-
Notifications
You must be signed in to change notification settings - Fork 199
/
SimKnuthYao.tla
96 lines (79 loc) · 3.71 KB
/
SimKnuthYao.tla
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
----------------------------------------- MODULE SimKnuthYao -----------------------------------------
EXTENDS KnuthYao, Integers, Functions, CSV, TLC, TLCExt, IOUtils, Statistics
StatelessCrookedCoin ==
\* 3/8 tails, 5/8 heads.
/\ IF RandomElement(1..8) \in 1..3
THEN /\ flip' = "T"
\* Multiplying these probabilities quickly overflows TLC's dyadic rationals.
\* /\ p' = Reduce([ num |-> p.num * 3, den |-> p.den * 8 ])
ELSE /\ flip' = "H"
\* /\ p' = Reduce([ num |-> p.num * 5, den |-> p.den * 8 ])
\* Statistically, modeling the crooked coin with a disjunct is the same,
\* but the generator won't extend the behavior if both disjuncts evaluate
\* to false. Confirm by running the generator with a fixed number of traces
\* and see how PostCondition is violated.
\* /\ \/ /\ RandomElement(1..10) \in 4..10
\* /\ flip' = "H"
\* \/ /\ RandomElement(1..10) \in 1..3
\* /\ flip' = "T"
----------------------------------------------------------------------------------------------------
StatefulCrookedCoin ==
\* Crooked coin: Decreasing chance of a tail over time.
/\ IF RandomElement(1..p.den) = 1
THEN flip' = "T"
ELSE flip' = "H"
----------------------------------------------------------------------------------------------------
SimInit ==
/\ state = "init"
/\ p = One
/\ flip \in Flip
SimNext ==
\* Need an artificial initial state to be able to model a crooked coin. Otherwise,
\* the first flip will always be fair.
\/ /\ state = "init"
/\ state' = "s0"
/\ UNCHANGED p
/\ TossCoin
\/ /\ state # "init"
/\ state \notin Done
/\ state' = Transition[state][flip]
/\ p' = Half(p)
/\ TossCoin
IsDyadic ==
\* This is expensive to evaluate with TLC.
IsDyadicRational(p)
----------------------------------------------------------------------------------------------------
ASSUME
\* The data collection below only works with TLC running in generation mode.
/\ TLCGet("config").mode = "generate"
\* Do not artificially restrict the length of behaviors.
/\ TLCGet("config").depth >= 15 \/ TLCGet("config").depth = -1
\* The algorithm terminates. Thus, do not check for deadlocks.
/\ TLCGet("config").deadlock = FALSE
\* Require a recent versions of TLC with support for the operators appearing here.
/\ TLCGet("revision").timestamp >= 1663720820
CSVFile ==
"SimKnuthYao.csv"
ASSUME
\* Initialize the CSV file with a header.
/\ CSVRecords(CSVFile) = 0 => CSVWrite("side,p,flip", <<>>, CSVFile)
\* Initialize TLC's registers 1 to 6 with zero.
/\ \A i \in Done: TLCSet(atoi(i), 0)
Stats ==
\* Cfg: CONSTRAINT Stats
/\ state \in Done =>
/\ CSVWrite("%1$s,%2$s,%3$s", <<state, p.den, flip>>, CSVFile)
/\ TLCSet(atoi(state), TLCGet(atoi(state)) + 1)
\* Update KnuthYao.svg every 100 samples.
/\ TLCGet("stats").traces % 250 = 0 =>
/\ IOExec(<<"/usr/bin/env", "Rscript", "SimKnuthYao.R", CSVFile>>).exitValue = 0
----------------------------------------------------------------------------------------------------
PostCondition ==
\* Cfg: POSTCONDITION PostCondition
LET uniform == [ i \in 1..6 |-> 6 ]
samples == [ i \in Done |-> TLCGet(atoi(i)) ]
sum == FoldFunctionOnSet(+, 0, samples, Done)
IN /\ Assert(TLCGet("config").traces = sum, <<"Fewer samples than expected:", sum>>)
/\ Assert(ChiSquare(uniform, samples, "0.2"), <<"ChiSquare test failed:", samples>>)
====================================================================================================
$ rm *.csv ; tlc SimKnuthYao -note -generate -depth -1