├── .gitignore ├── Blinker.pdf ├── Blinker.tla ├── Chameneos.pdf ├── Chameneos.tla ├── CheckRequirements.pdf ├── CheckRequirements.tla ├── CigaretteSmokers.pdf ├── CigaretteSmokers.tla ├── GameOfLife.pdf ├── GameOfLife.tla ├── README.md ├── Requirements.pdf ├── Requirements.tla ├── Scheduler.cfg ├── Scheduler.dvi ├── Scheduler.tla ├── SlidingPuzzles.pdf ├── SlidingPuzzles.tla ├── Watchdog.cfg ├── Watchdog.dvi ├── Watchdog.tla ├── images ├── Blinker.png ├── Chameneos.png ├── CheckRequirements.png ├── CigaretteSmokers.png ├── GameOfLife.png ├── Requirements.png ├── Scheduler.png ├── SlidingPuzzles.png ├── Watchdog.png ├── blinker.png ├── chameneos_n2.png ├── chameneos_n2_m4.png ├── chameneos_n4.png ├── conflicting.png ├── fig1.png ├── gameoflife_3x3.png ├── gameoflife_4x4.png ├── gameoflife_4x4c.png ├── gameoflife_4x4cz1.png ├── gameoflife_4x4cz2.png ├── gameoflife_5x5_sym.png ├── klotski.png ├── mas.png ├── pennant.png ├── scheduler.png ├── scheduler_trace.png └── watchdog_n3_t3.png └── to_images.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.toolbox/ 2 | -------------------------------------------------------------------------------- /Blinker.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/Blinker.pdf -------------------------------------------------------------------------------- /Blinker.tla: -------------------------------------------------------------------------------- 1 | ------------------------------ MODULE Blinker ------------------------------ 2 | EXTENDS Integers, Sequences 3 | 4 | (***************************************************************************) 5 | (* BC is a sequence of blinker configurations - in this case just *) 6 | (* a natural number signifying the blink period in some time unit *) 7 | (***************************************************************************) 8 | CONSTANT BC 9 | VARIABLES bState 10 | 11 | ASSUME /\ BC \in Seq(Nat) 12 | 13 | vars == bState 14 | 15 | States == {"Active_Off", "Active_On"} 16 | Blinker == [timer : Nat, state : States] 17 | 18 | TypeOK == /\ bState \in [DOMAIN BC -> Blinker] 19 | 20 | Init == 21 | /\ bState \in {[n \in DOMAIN BC |-> [timer |-> BC[n], 22 | state |-> "Active_Off"] 23 | ]} 24 | 25 | Transition(n) == /\ bState[n].timer = 0 26 | /\ bState[n].state = "Active_Off" 27 | /\ bState' = [bState EXCEPT ![n].timer = BC[n], 28 | ![n].state = "Active_On"] 29 | \/ 30 | /\ bState[n].timer = 0 31 | /\ bState[n].state = "Active_On" 32 | /\ bState' = [bState EXCEPT ![n].timer = BC[n], 33 | ![n].state = "Active_Off"] 34 | 35 | Tick == /\ \A n \in DOMAIN BC : bState[n].timer > 0 36 | /\ bState' = [n \in DOMAIN BC |-> [timer |-> bState[n].timer - 1, 37 | state |-> bState[n].state]] 38 | 39 | Next == Tick \/ \E n \in DOMAIN BC : Transition(n) 40 | 41 | Spec == Init /\ [][Next]_vars 42 | FairSpec == Spec /\ WF_vars(Next) 43 | 44 | LEDsWillTurnOn == 45 | \A n \in DOMAIN BC : 46 | (bState[n].state = "Active_Off") ~> (bState[n].state = "Active_On") 47 | 48 | LEDsWillTurnOff == 49 | \A n \in DOMAIN BC : 50 | (bState[n].state = "Active_On") ~> (bState[n].state = "Active_Off") 51 | 52 | ============================================================================= 53 | -------------------------------------------------------------------------------- /Chameneos.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/Chameneos.pdf -------------------------------------------------------------------------------- /Chameneos.tla: -------------------------------------------------------------------------------- 1 | ----------------------------- MODULE Chameneos ----------------------------- 2 | (***************************************************************************) 3 | (* A specification of a 'concurrency game' requiring concurrent *) 4 | (* and symmetrical cooperation - https://cedric.cnam.fr/fichiers/RC474.pdf *) 5 | (***************************************************************************) 6 | 7 | EXTENDS Integers 8 | 9 | \* N - number of total meeting after which chameneoses fade 10 | \* M - number of chameneoses 11 | CONSTANT N, M 12 | ASSUME N \in (Nat \ {0}) /\ M \in (Nat \ {0}) 13 | 14 | VARIABLE chameneoses, meetingPlace, numMeetings 15 | 16 | vars == <> 17 | 18 | Color == {"blue", "red", "yellow"} 19 | Faded == CHOOSE c : c \notin Color 20 | 21 | ChameneosID == 1 .. M 22 | MeetingPlaceEmpty == CHOOSE e : e \notin ChameneosID 23 | 24 | RECURSIVE Sum(_, _) 25 | Sum(f, S) == IF S = {} THEN 0 26 | ELSE LET x == CHOOSE x \in S : TRUE 27 | IN f[x] + Sum(f, S \ {x}) 28 | 29 | TypeOK == /\ chameneoses \in [ ChameneosID -> (Color \cup {Faded}) \X (0 .. N) ] 30 | /\ meetingPlace \in ChameneosID \cup {MeetingPlaceEmpty} 31 | 32 | Complement(c1, c2) == IF c1 = c2 33 | THEN c1 34 | ELSE CHOOSE cid \in Color \ {c1, c2} : TRUE 35 | 36 | Meet(cid) == IF meetingPlace = MeetingPlaceEmpty 37 | THEN IF numMeetings < N 38 | \* chameneos enters meeting empty meeting place 39 | THEN /\ meetingPlace' = cid 40 | /\ UNCHANGED <> 41 | \* chameneos takes on faded color 42 | ELSE /\ chameneoses' = [chameneoses EXCEPT ![cid] = <>] 43 | /\ UNCHANGED <> 44 | \* meeting place is not empty - two chameneoses mutate 45 | ELSE /\ meetingPlace /= cid 46 | /\ meetingPlace' = MeetingPlaceEmpty 47 | /\ chameneoses' = 48 | LET newColor == Complement(chameneoses[cid][1], 49 | chameneoses[meetingPlace][1]) 50 | IN [chameneoses EXCEPT ![cid] = <>, 51 | ![meetingPlace] = <>] 52 | /\ numMeetings' = numMeetings + 1 53 | 54 | Init == /\ chameneoses \in [ChameneosID -> Color \X {0}] 55 | /\ meetingPlace = MeetingPlaceEmpty 56 | /\ numMeetings = 0 57 | 58 | \* repeatedly try to enter meeting place for chameneoses that are not faded yet 59 | Next == /\ \E c \in { x \in ChameneosID : chameneoses[x][1] /= Faded} : Meet(c) 60 | 61 | Spec == Init /\ [][Next]_vars 62 | 63 | SumMet == numMeetings = N => LET f[c \in ChameneosID] == chameneoses[c][2] 64 | IN Sum(f, ChameneosID) = 2 * N 65 | 66 | ============================================================================= 67 | -------------------------------------------------------------------------------- /CheckRequirements.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/CheckRequirements.pdf -------------------------------------------------------------------------------- /CheckRequirements.tla: -------------------------------------------------------------------------------- 1 | -------------------------- MODULE CheckRequirements ------------------------- 2 | VARIABLES inputs1, output1 3 | VARIABLES inputs2, output2 4 | 5 | vars1 == <> 6 | vars2 == <> 7 | 8 | Requirements1 == INSTANCE Requirements 9 | WITH inputs <- inputs1, 10 | output <- output1 11 | 12 | Requirements2 == INSTANCE Requirements 13 | WITH inputs <- inputs2, 14 | output <- output2 15 | 16 | Init == Requirements1!Init /\ Requirements2!Init 17 | Next == Requirements1!Next /\ Requirements2!Next 18 | 19 | RequirementsNotConflicting == inputs1 = inputs2 => output1 = output2 20 | EndsInSteadyState == <>[][output1 = output2]_<> 21 | 22 | ============================================================================= 23 | -------------------------------------------------------------------------------- /CigaretteSmokers.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/CigaretteSmokers.pdf -------------------------------------------------------------------------------- /CigaretteSmokers.tla: -------------------------------------------------------------------------------- 1 | -------------------------- MODULE CigaretteSmokers -------------------------- 2 | (***************************************************************************) 3 | (* A specification of the cigarette smokers problem, originally *) 4 | (* described in 1971 by Suhas Patil. *) 5 | (* https://en.wikipedia.org/wiki/Cigarette_smokers_problem *) 6 | (***************************************************************************) 7 | EXTENDS Integers, FiniteSets 8 | 9 | CONSTANT Ingredients 10 | VARIABLE smokers, dealer 11 | 12 | (***************************************************************************) 13 | (* 'Ingredients' is a set of ingredients, originally *) 14 | (* {matches, paper, tobacco}. 'Offers' is a subset of subsets of *) 15 | (* ingredients, each missing just one ingriedent *) 16 | (***************************************************************************) 17 | Offers == {i \in SUBSET Ingredients : 18 | Cardinality(i) = Cardinality(Ingredients) - 1} 19 | 20 | (***************************************************************************) 21 | (* 'smokers' is a function from the ingredient the smoker has *) 22 | (* infinite supply of, to a BOOLEAN flag signifying smoker's state *) 23 | (* (smoking/not smoking) *) 24 | (* 'dealer' is an element of 'Offers', or an empty set *) 25 | (***************************************************************************) 26 | TypeOK == /\ smokers \in [Ingredients -> [smoking: BOOLEAN]] 27 | /\ dealer \in Offers \/ dealer = {} 28 | 29 | vars == <> 30 | 31 | Init == /\ smokers = [r \in Ingredients |-> [smoking |-> FALSE]] 32 | /\ dealer \in Offers 33 | 34 | startSmoking == /\ dealer /= {} 35 | /\ smokers' = [r \in Ingredients |-> [smoking |-> {r} \cup 36 | dealer = Ingredients]] 37 | /\ dealer' = {} 38 | 39 | stopSmoking == /\ dealer = {} 40 | /\ smokers' = [r \in Ingredients |-> [smoking |-> FALSE]] 41 | /\ dealer' \in Offers 42 | 43 | Next == startSmoking \/ stopSmoking 44 | 45 | Spec == Init /\ [][Next]_vars 46 | FairSpec == Spec /\ WF_vars(Next) 47 | 48 | (***************************************************************************) 49 | (* An invariant checking that at most one smoker smokes at any particular *) 50 | (* moment *) 51 | (***************************************************************************) 52 | AtMostOne == Cardinality({r \in Ingredients : smokers[r].smoking}) <= 1 53 | ============================================================================= 54 | -------------------------------------------------------------------------------- /GameOfLife.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/GameOfLife.pdf -------------------------------------------------------------------------------- /GameOfLife.tla: -------------------------------------------------------------------------------- 1 | ----------------------------- MODULE GameOfLife ----------------------------- 2 | EXTENDS Integers 3 | 4 | CONSTANT N 5 | VARIABLE grid 6 | 7 | ASSUME N \in Nat 8 | 9 | vars == grid 10 | 11 | RECURSIVE Sum(_, _) 12 | Sum(f, S) == IF S = {} THEN 0 13 | ELSE LET x == CHOOSE x \in S : TRUE 14 | IN f[x] + Sum(f, S \ {x}) 15 | 16 | Pos == {<> : x, y \in 1..N} 17 | TypeOK == grid \in [Pos -> BOOLEAN] 18 | 19 | sc[<> \in (0 .. N + 1) \X 20 | (0 .. N + 1)] == CASE \/ x = 0 \/ y = 0 21 | \/ x > N \/ y > N 22 | \/ ~grid[<>] -> 0 23 | [] OTHER -> 1 24 | 25 | score(p) == LET nbrs == {x \in {-1, 0, 1} \X 26 | {-1, 0, 1} : x /= <<0, 0>>} 27 | points == {<> : <> \in nbrs} 28 | IN Sum(sc, points) 29 | 30 | Init == grid \in [Pos -> BOOLEAN] 31 | Next == grid' = [p \in Pos |-> IF \/ (grid[p] /\ score(p) \in {2, 3}) 32 | \/ (~grid[p] /\ score(p) = 3) 33 | THEN TRUE 34 | ELSE FALSE] 35 | 36 | Spec == Init /\ [][Next]_vars 37 | 38 | ============================================================================= 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Different TLA+ specifications, mostly for learning purposes 2 | =========================================================== 3 | 4 | CigaretteSmokers.tla 5 | -------------------- 6 | 7 | A specification of the [Cigarette smokers problem](https://en.wikipedia.org/wiki/Cigarette_smokers_problem). 8 | The generated state graph is very small: 9 | 10 | ![spec1](images/CigaretteSmokers.png) 11 | 12 | ![fig1](images/fig1.png) 13 | 14 | Blinker.tla 15 | ----------- 16 | 17 | Simple spec simulating, more or less, [this](https://github.com/mryndzionek/esm/blob/master/apps/blink/src/blink.c) application. 18 | Three state machines controlling three LEDs. With 100ms resolution (model run with `BC <- <<3, 5, 7>>`) model checker 19 | finds 384 distinct states: 20 | 21 | ![spec2](images/Blinker.png) 22 | 23 | ![fig2](images/blinker.png) 24 | 25 | Just a humble reminder to never underestimate even the simplest concurrent programs, I guess :smiley: 26 | 27 | GameOfLife.tla 28 | -------------- 29 | 30 | [Conway's Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) 31 | 32 | ![spec3](images/GameOfLife.png) 33 | 34 | All the 'attractors' for a 3x3 grid 35 | 36 | ![fig3](images/gameoflife_3x3.png) 37 | 38 | State space for a 4x4 grid - original image generated by Graphviz is around 300MB :smiley:: 39 | 40 | ![fig4](images/gameoflife_4x4.png) 41 | 42 | The same with some colors based on number of occupied cells: 43 | 44 | ![fig5](images/gameoflife_4x4c.png) 45 | 46 | Zoom on two of the smaller clusters: 47 | 48 | ![fig6](images/gameoflife_4x4cz1.png) 49 | 50 | ![fig7](images/gameoflife_4x4cz2.png) 51 | 52 | Under 'symmetry group of the square' (D4) view in TLC the state space shrinks to ... 27 states. 53 | Under this view it's even possible to run TLC on 5x5 grid and get 486 states (reduction from 33554432): 54 | 55 | ![fig8](images/gameoflife_5x5_sym.png) 56 | 57 | Base Graphviz parameters: 58 | 59 | ```sh 60 | dot -Tpng -Nstyle=filled -Npenwidth=5 -Epenwidth=8 -Ksfdp -Goverlap=prism -Goverlap_scaling=-10 61 | ``` 62 | 63 | Requirements.tla 64 | ---------------- 65 | 66 | Experimental specification aimed at mechanising verification of written requirements documents. 67 | 68 | ![spec4](images/Requirements.png) 69 | 70 | ![spec5](images/CheckRequirements.png) 71 | 72 | Checking `CheckRequirements` spec produces: 73 | 74 | ![fig9](images/conflicting.png) 75 | 76 | 77 | SlidingPuzzles.tla 78 | ------------------ 79 | 80 | Solution to a variation of [sliding block puzzle](https://en.wikipedia.org/wiki/Sliding_puzzle) 81 | most commonly known as [Klotski](https://en.wikipedia.org/wiki/Klotski). 82 | 83 | ![spec6](images/SlidingPuzzles.png) 84 | 85 | TLC finds 25955 distinct states. Green node is the starting position. 86 | Red nodes are the goal nodes - with the biggest piece in center-bottom position. 87 | 88 | ![fig10](images/klotski.png) 89 | 90 | The Pennant variation has significantly smaller state space of 'only' 1398 states. 91 | Raymond Hettinger talked about this puzzle and the state graph [here](https://youtu.be/_GP9OpZPUYc?t=742). 92 | 93 | ```tla 94 | W == 4 H == 5 95 | 96 | Pennant == {{<<0, 0>>, <<0, 1>>, <<1, 0>>, <<1, 1>>}, 97 | {<<2, 0>>, <<3, 0>>}, {<<2, 1>>, <<3, 1>>}, 98 | {<<0, 2>>}, {<<1, 2>>}, 99 | {<<0, 3>>, <<0, 4>>}, {<<1, 3>>, <<1, 4>>}, 100 | {<<2, 3>>, <<3, 3>>}, {<<2, 4>>, <<3, 4>>}} 101 | 102 | PennantGoal == {<<0, 3>>, <<0, 4>>, <<1, 3>>, <<1, 4>>} \in board 103 | ``` 104 | 105 | ![fig11](images/pennant.png) 106 | 107 | Ma's Puzzle has 110804 distinct states. 108 | 109 | ```tla 110 | W == 5 H == 5 111 | 112 | Mas == {{<<0, 0>>, <<1, 0>>, <<2, 0>>}, 113 | {<<3, 0>>, <<4, 0>>,<<4, 1>>}, 114 | {<<0, 1>>, <<1, 1>>}, {<<2, 1>>, <<3, 1>>}, 115 | {<<0, 2>>, <<0, 3>>, <<1, 3>>}, 116 | {<<1, 2>>, <<2, 2>>}, {<<3, 2>>, <<4, 2>>}, 117 | {<<2, 3>>, <<3, 3>>, <<4, 3>>}, 118 | {<<2, 4>>}} 119 | 120 | MasGoal == {{<<3, 0>>, <<4, 0>>,<<4, 1>>}, {<<3, 1>>, <<3, 2>>, <<4, 2>>}} \subseteq board 121 | ``` 122 | 123 | ![fig12](images/mas.png) 124 | 125 | Chameneos.tla 126 | ------------- 127 | 128 | A specification of a 'concurrency game' requiring concurrent and symmetrical cooperation - [link](https://cedric.cnam.fr/fichiers/RC474.pdf) 129 | 130 | ![fig13](images/Chameneos.png) 131 | 132 | For N=3 there are 522 distinct states: 133 | 134 | ![fig14](images/chameneos_n2.png) 135 | 136 | The lattices at the edges are due to the possible orders in which the chameneoses fade. 137 | 138 | For N=4 there are 6652 distinct states: 139 | 140 | ![fig15](images/chameneos_n4.png) 141 | 142 | All the above graphs are for single initial permutation of chameneoses. 143 | Here is a full graph for N=2, M=4 (4843 distinct states). 144 | 145 | ![fig16](images/chameneos_n2_m4.png) 146 | 147 | Watchdog.tla 148 | ------------ 149 | 150 | ![fig17](images/Watchdog.png) 151 | 152 | ![fig18](images/watchdog_n3_t3.png) 153 | 154 | Scheduler.tla 155 | ------------- 156 | 157 | ![fig19](images/Scheduler.png) 158 | 159 | State diagram for 3-task configuration: 160 | 161 | ![fig20](images/scheduler.png) 162 | 163 | Sample trace rendered graphically. Can you spot when the sequence starts repeating? 164 | 165 | ![fig21](images/scheduler_trace.png) 166 | 167 | -------------------------------------------------------------------------------- /Requirements.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/Requirements.pdf -------------------------------------------------------------------------------- /Requirements.tla: -------------------------------------------------------------------------------- 1 | ---------------------------- MODULE Requirements ---------------------------- 2 | EXTENDS Integers 3 | 4 | VARIABLES inputs, output 5 | 6 | (***************************************************************************) 7 | (* We have two buttons - A and B - and an indicator light. Spec like this *) 8 | (* can help with disambiguating written requirements in situations where *) 9 | (* multiple requirements concern same resource. In this case requirements *) 10 | (* say only what needs to be done if one of the button is pressed, or not *) 11 | (* totally ignoring the situation where both are pressed *) 12 | (***************************************************************************) 13 | Inputs == SUBSET {"a_button_pressed", "b_button_pressed"} 14 | Output == {"off", "red", "green", "yellow"} 15 | 16 | TypeOK == /\ inputs \in Inputs 17 | /\ output \in Output 18 | 19 | (***************************************************************************) 20 | (* Initially indicator light is off and buttons can be pushed or not *) 21 | (***************************************************************************) 22 | Init == /\ inputs \in Inputs 23 | /\ output = "off" 24 | 25 | (***************************************************************************) 26 | (* First requirement says that we signal with green light the fact that *) 27 | (* button A is pushed. If it's not then the light should be yellow *) 28 | (***************************************************************************) 29 | Requirement1 == /\ IF "a_button_pressed" \in inputs THEN output' = "green" 30 | ELSE output' = "yellow" 31 | /\ UNCHANGED <> 32 | 33 | (***************************************************************************) 34 | (* Second requirement says that we signal with red light the fact that *) 35 | (* button B is pushed. If it's not then the light should be yellow *) 36 | (***************************************************************************) 37 | Requirement2 == /\ IF "b_button_pressed" \in inputs THEN output' = "green" 38 | ELSE output' = "yellow" 39 | /\ UNCHANGED <> 40 | 41 | (***************************************************************************) 42 | (* We want to check all requirements *) 43 | (***************************************************************************) 44 | Next == Requirement1 \/ Requirement2 45 | 46 | ============================================================================= 47 | -------------------------------------------------------------------------------- /Scheduler.cfg: -------------------------------------------------------------------------------- 1 | SPECIFICATION Spec 2 | 3 | CONSTANTS 4 | NoTask = NoTask 5 | 6 | INVARIANT TypeOK 7 | NoMissingDeadlines 8 | -------------------------------------------------------------------------------- /Scheduler.dvi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/Scheduler.dvi -------------------------------------------------------------------------------- /Scheduler.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE Scheduler ---- 2 | (***************************************************************************) 3 | (* A specification of a simple rate-monotonic scheduler *) 4 | (***************************************************************************) 5 | 6 | EXTENDS Integers, FiniteSets, Sequences 7 | 8 | VARIABLE tasks, scheduler 9 | 10 | vars == <> 11 | 12 | TasksCfg == <<[prio |-> 2, p |-> 17, et |-> 3], 13 | [prio |-> 1, p |-> 21, et |-> 5], 14 | [prio |-> 3, p |-> 9, et |-> 2]>> 15 | 16 | N == Len(TasksCfg) 17 | NoTask == CHOOSE v : v \notin 1..N 18 | 19 | ASSUME DOMAIN TasksCfg = 1..N 20 | 21 | TypeOK == /\ tasks \in [1..N -> [s : {"idle", "running", "pending"}, 22 | tmr : Int, 23 | tmR : Int, 24 | hasRun : BOOLEAN]] 25 | /\ scheduler \in [uid : 1..N \cup {NoTask}] 26 | 27 | Init == /\ tasks = [uid \in 1..N |-> [s |-> "pending", 28 | tmr |-> TasksCfg[uid].et - 1, 29 | tmR |-> 0, hasRun |-> TRUE]] 30 | /\ scheduler = [uid |-> NoTask] 31 | 32 | Update(uid) == /\ ~tasks[uid].hasRun 33 | /\ \/ /\ tasks[uid].s = "idle" 34 | /\ \/ /\ tasks[uid].tmr = 0 35 | /\ tasks' = [tasks EXCEPT ![uid].s = "pending", 36 | ![uid].tmR = 0, 37 | ![uid].tmr = TasksCfg[uid].et - 1, 38 | ![uid].hasRun = TRUE] 39 | \/ /\ tasks[uid].tmr > 0 40 | /\ tasks' = [tasks EXCEPT ![uid].tmr = @ - 1, 41 | ![uid].hasRun = TRUE] 42 | \/ /\ tasks[uid].s = "running" 43 | /\ \/ /\ tasks[uid].tmr = 0 44 | /\ tasks' = [tasks EXCEPT ![uid].s = "idle", 45 | ![uid].tmR = 0, 46 | ![uid].tmr = TasksCfg[uid].p - 47 | tasks[uid].tmR - 2, 48 | ![uid].hasRun = TRUE] 49 | \/ /\ tasks[uid].tmr > 0 50 | /\ tasks' = [tasks EXCEPT ![uid].tmr = @ - 1, 51 | ![uid].tmR = @ + 1, 52 | ![uid].hasRun = TRUE] 53 | \/ /\ tasks[uid].s = "pending" 54 | /\ tasks' = [tasks EXCEPT ![uid].tmR = @ + 1, 55 | ![uid].hasRun = TRUE] 56 | /\ UNCHANGED scheduler 57 | 58 | MaxPendingUID == LET Max(S) == CHOOSE x \in S : \A y \in S : TasksCfg[x].prio >= TasksCfg[y].prio 59 | C == {uid \in 1..N : tasks[uid].s = "pending"} 60 | MaxP == Max(C) 61 | IN IF C = {} THEN NoTask ELSE MaxP 62 | 63 | SetMaxPendingAsRunning == tasks' = [uid \in 1..N |-> 64 | [tasks[uid] EXCEPT 65 | !.hasRun = FALSE, 66 | !.s = IF uid = MaxPendingUID THEN "running" 67 | ELSE IF /\ uid = scheduler.uid 68 | /\ tasks[uid].s = "running" 69 | THEN "pending" 70 | ELSE tasks[uid].s]] 71 | 72 | Tick == /\ \A uid \in 1..N : tasks[uid].hasRun 73 | /\ LET CurrUID == IF scheduler.uid = NoTask THEN NoTask 74 | ELSE IF tasks[scheduler.uid].s = "idle" THEN NoTask 75 | ELSE scheduler.uid 76 | IN IF CurrUID = NoTask 77 | THEN IF MaxPendingUID = NoTask 78 | THEN /\ tasks' = [uid \in 1..N |-> [tasks[uid] EXCEPT !.hasRun = FALSE]] 79 | /\ scheduler' = [uid |-> NoTask] 80 | ELSE /\ SetMaxPendingAsRunning 81 | /\ scheduler' = [uid |-> MaxPendingUID] 82 | ELSE IF MaxPendingUID = NoTask 83 | THEN /\ tasks' = [uid \in 1..N |-> [tasks[uid] EXCEPT !.hasRun = FALSE]] 84 | /\ scheduler' = [uid |-> CurrUID] 85 | ELSE IF TasksCfg[MaxPendingUID].prio > TasksCfg[CurrUID].prio 86 | THEN /\ SetMaxPendingAsRunning 87 | /\ scheduler' = [uid |-> MaxPendingUID] 88 | ELSE /\ tasks' = [uid \in 1..N |-> [tasks[uid] EXCEPT !.hasRun = FALSE]] 89 | /\ scheduler' = [uid |-> CurrUID] 90 | 91 | 92 | Next == \E uid \in 1..N : Update(uid) \/ Tick 93 | 94 | Spec == Init /\ [][Next]_vars 95 | 96 | NoMissingDeadlines == \A uid \in 1..N : tasks[uid].tmR + 2 < TasksCfg[uid].p 97 | 98 | ==== 99 | -------------------------------------------------------------------------------- /SlidingPuzzles.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/SlidingPuzzles.pdf -------------------------------------------------------------------------------- /SlidingPuzzles.tla: -------------------------------------------------------------------------------- 1 | --------------------------- MODULE SlidingPuzzles --------------------------- 2 | EXTENDS Integers 3 | 4 | VARIABLE board 5 | 6 | W == 4 H == 5 7 | Pos == (0 .. W - 1) \X (0 .. H - 1) 8 | Piece == SUBSET Pos 9 | 10 | Klotski == {{<<0, 0>>, <<0, 1>>}, 11 | {<<1, 0>>, <<2, 0>>, <<1, 1>>, <<2, 1>>}, 12 | {<<3, 0>>, <<3, 1>>},{<<0, 2>>, <<0, 3>>}, 13 | {<<1, 2>>, <<2, 2>>},{<<3, 2>>, <<3, 3>>}, 14 | {<<1, 3>>}, {<<2, 3>>}, {<<0, 4>>}, {<<3, 4>>}} 15 | 16 | KlotskiGoal == {<<1, 3>>, <<1, 4>>, <<2, 3>>, <<2, 4>>} \in board 17 | 18 | ChooseOne(S, P(_)) == CHOOSE x \in S : P(x) /\ \A y \in S : P(y) => y = x 19 | 20 | TypeOK == board \in SUBSET Piece 21 | 22 | (***************************************************************************) 23 | (* Given a position and a set of empty positions return a set of *) 24 | (* appropriately filtered von Neumann neighborhood points *) 25 | (***************************************************************************) 26 | dir(p, es) == LET dir == {<<1, 0>>, <<0, 1>>, <<-1, 0>>, <<0, -1>>} 27 | IN {d \in dir : /\ <> \in Pos 28 | /\ <> \notin es} 29 | 30 | (***************************************************************************) 31 | (* Given a position and a unit translation vector return a pair of *) 32 | (* pieces, before and after translation in opposite this vector direction *) 33 | (***************************************************************************) 34 | move(p, d) == LET s == <> 35 | pc == ChooseOne(board, LAMBDA pc : s \in pc) 36 | IN <> : q \in pc}>> 37 | 38 | (***************************************************************************) 39 | (* Given specific free position and a set of all free positions return *) 40 | (* a set of boards updated by moving appropriate pieces to that *) 41 | (* free position *) 42 | (***************************************************************************) 43 | update(e, es) == LET dirs == dir(e, es) 44 | moved == {move(e, d) : d \in dirs} 45 | free == {<> \in moved : 46 | /\ m \cap (UNION (board \ {pc})) = {} 47 | /\ \A p \in m : p \in Pos} 48 | IN {(board \ {pc}) \cup {m} : <> \in free} 49 | 50 | Init == board = Klotski 51 | 52 | Next == LET empty == Pos \ UNION board 53 | IN \E e \in empty : board' \in update(e, empty) 54 | 55 | ============================================================================= -------------------------------------------------------------------------------- /Watchdog.cfg: -------------------------------------------------------------------------------- 1 | SPECIFICATION FairSpec 2 | 3 | CONSTANTS 4 | N = 3 5 | T = 3 6 | 7 | INVARIANT TypeOK 8 | 9 | PROPERTIES AlwaysReset 10 | -------------------------------------------------------------------------------- /Watchdog.dvi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/Watchdog.dvi -------------------------------------------------------------------------------- /Watchdog.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE Watchdog ---- 2 | (***************************************************************************) 3 | (* A specification of a simple software watchdog multiplexing system. *) 4 | (* *) 5 | (* On many (most) MCUs a hardware watchdog has only one time interval. *) 6 | (* However in most cases there are multiple software tasks/components *) 7 | (* with different timing constraints. Solution to this is a separate *) 8 | (* software component mediating between the hardware watchdog and the *) 9 | (* other software components. The software watchdog maintains a set of its *) 10 | (* own software timers. Each software component periodically feeds the *) 11 | (* software watchdog which results in the appropriate timer being reset. *) 12 | (* The software watchdog feeds the hardware watchdog with its own software *) 13 | (* timer-set update rate. This results in an optimal reaction to any *) 14 | (* software failure. *) 15 | (***************************************************************************) 16 | EXTENDS Integers, FiniteSets 17 | 18 | CONSTANTS N, T 19 | VARIABLE components, watchdog 20 | 21 | vars == <> 22 | 23 | (***************************************************************************) 24 | (* A software component is modeled as a periodic state machine driven by *) 25 | (* a timer and can crash and halt at any time. The 'ready' flag is used to *) 26 | (* model synchronicity between the component and the software watchdog. *) 27 | (***************************************************************************) 28 | TypeOK == /\ components \in [1..N -> [timer : 0..T, 29 | timeout : 0..T, 30 | ready : BOOLEAN, 31 | crashed : BOOLEAN]] 32 | /\ watchdog \in [1..N -> [timer : 0..T + 1]] 33 | 34 | Init == /\ components \in [1..N -> {[timer |-> x, 35 | timeout |-> x, 36 | ready |-> TRUE, 37 | crashed |-> FALSE] : x \in {T}}] 38 | /\ watchdog = [uid \in 1..N |-> [timer |-> components[uid].timeout + 1]] 39 | 40 | RunOne(c) == IF c.timer > 0 41 | THEN [c EXCEPT !.timer = @ - 1] 42 | ELSE [c EXCEPT !.timer = c.timeout] 43 | 44 | WatchdogUpdate(uid) == IF watchdog[uid].timer > 0 45 | THEN watchdog[uid].timer - 1 46 | ELSE 0 47 | 48 | WatchdogFeed(uid) == IF components[uid].timer = 0 49 | THEN components[uid].timeout + 1 50 | ELSE WatchdogUpdate(uid) 51 | 52 | Run(uid) == 53 | /\ \A id \in 1..N : watchdog[id].timer > 0 54 | /\ components[uid].ready 55 | /\ IF components[uid].crashed 56 | THEN /\ components' = [components EXCEPT ![uid].ready = FALSE] 57 | /\ watchdog' = [watchdog EXCEPT ![uid].timer = WatchdogUpdate(uid)] 58 | ELSE /\ components' = [components EXCEPT ![uid] = RunOne(components[uid]), 59 | ![uid].ready = FALSE] 60 | /\ watchdog' = [watchdog EXCEPT ![uid].timer = WatchdogFeed(uid)] 61 | 62 | Crash(uid) == /\ ~components[uid].crashed 63 | /\ components[uid].ready 64 | /\ components' = [components EXCEPT ![uid].crashed = TRUE] 65 | /\ UNCHANGED watchdog 66 | 67 | Reset == /\ \E uid \in 1..N : watchdog[uid].timer = 0 68 | /\ watchdog' = [uid \in 1..N |-> [timer |-> components[uid].timeout + 1]] 69 | /\ components' = [uid \in 1..N |-> [timer |-> components[uid].timeout, 70 | timeout |-> components[uid].timeout, 71 | ready |-> TRUE, 72 | crashed |-> FALSE]] 73 | 74 | Tick == /\ \A uid \in 1..N : ~components[uid].ready 75 | /\ UNCHANGED watchdog 76 | /\ components' = [uid \in 1..N |-> [components[uid] EXCEPT !.ready = TRUE]] 77 | 78 | Next == (\E uid \in 1..N : Run(uid) \/ Crash(uid)) \/ Tick \/ Reset 79 | 80 | Spec == Init /\ [][Next]_vars 81 | FairSpec == Spec /\ WF_vars(Next) 82 | 83 | (***************************************************************************) 84 | (* Make sure a crashed component leads to a global system reset *) 85 | (***************************************************************************) 86 | AlwaysReset == (\E uid \in 1..N: components[uid].crashed) ~> 87 | <>(\A uid \in 1..N: ~components[uid].crashed) 88 | 89 | ==== -------------------------------------------------------------------------------- /images/Blinker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/Blinker.png -------------------------------------------------------------------------------- /images/Chameneos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/Chameneos.png -------------------------------------------------------------------------------- /images/CheckRequirements.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/CheckRequirements.png -------------------------------------------------------------------------------- /images/CigaretteSmokers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/CigaretteSmokers.png -------------------------------------------------------------------------------- /images/GameOfLife.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/GameOfLife.png -------------------------------------------------------------------------------- /images/Requirements.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/Requirements.png -------------------------------------------------------------------------------- /images/Scheduler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/Scheduler.png -------------------------------------------------------------------------------- /images/SlidingPuzzles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/SlidingPuzzles.png -------------------------------------------------------------------------------- /images/Watchdog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/Watchdog.png -------------------------------------------------------------------------------- /images/blinker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/blinker.png -------------------------------------------------------------------------------- /images/chameneos_n2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/chameneos_n2.png -------------------------------------------------------------------------------- /images/chameneos_n2_m4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/chameneos_n2_m4.png -------------------------------------------------------------------------------- /images/chameneos_n4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/chameneos_n4.png -------------------------------------------------------------------------------- /images/conflicting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/conflicting.png -------------------------------------------------------------------------------- /images/fig1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/fig1.png -------------------------------------------------------------------------------- /images/gameoflife_3x3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/gameoflife_3x3.png -------------------------------------------------------------------------------- /images/gameoflife_4x4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/gameoflife_4x4.png -------------------------------------------------------------------------------- /images/gameoflife_4x4c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/gameoflife_4x4c.png -------------------------------------------------------------------------------- /images/gameoflife_4x4cz1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/gameoflife_4x4cz1.png -------------------------------------------------------------------------------- /images/gameoflife_4x4cz2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/gameoflife_4x4cz2.png -------------------------------------------------------------------------------- /images/gameoflife_5x5_sym.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/gameoflife_5x5_sym.png -------------------------------------------------------------------------------- /images/klotski.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/klotski.png -------------------------------------------------------------------------------- /images/mas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/mas.png -------------------------------------------------------------------------------- /images/pennant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/pennant.png -------------------------------------------------------------------------------- /images/scheduler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/scheduler.png -------------------------------------------------------------------------------- /images/scheduler_trace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/scheduler_trace.png -------------------------------------------------------------------------------- /images/watchdog_n3_t3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mryndzionek/tlaplus_specs/4984ba698693b169a9ecf797f28ef4c8c3e628ab/images/watchdog_n3_t3.png -------------------------------------------------------------------------------- /to_images.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | OPTS="-background white -alpha remove -alpha off -quality 90" 4 | 5 | convert -density 300 -append CigaretteSmokers.pdf $OPTS -crop 1570x1860+520+520 images/CigaretteSmokers.png 6 | convert -density 300 -append Blinker.pdf $OPTS -crop 1570x2240+520+520 images/Blinker.png 7 | convert images/Blinker.png -crop 1570x2360+520+520 images/Blinker.png 8 | convert -density 300 -append GameOfLife.pdf $OPTS -crop 1570x1860+520+520 images/GameOfLife.png 9 | convert -density 300 -append Requirements.pdf $OPTS -crop 1570x1660+520+520 images/Requirements.png 10 | convert -density 300 -append CheckRequirements.pdf $OPTS -crop 1570x1000+520+520 images/CheckRequirements.png 11 | convert -density 300 -append SlidingPuzzles.pdf $OPTS -crop 1570x2250+520+520 images/SlidingPuzzles.png 12 | convert -density 300 -append Chameneos.pdf $OPTS -crop 1770x2260+520+520 images/Chameneos.png 13 | convert images/Chameneos.png -crop 1770x2960+520+520 images/Chameneos.png 14 | # DIV generated with -textwidth 420 15 | convert -density 300 -append Watchdog.dvi $OPTS -crop 1870x2260+520+520 images/Watchdog.png 16 | convert images/Watchdog.png -crop 1870x3660+520+520 images/Watchdog.png 17 | # DIV generated with -textwidth 460 18 | convert -density 300 -append Scheduler.dvi $OPTS -crop 2000x2260+520+520 images/Scheduler.png 19 | convert images/Scheduler.png -crop 2000x4660+520+520 images/Scheduler.png 20 | --------------------------------------------------------------------------------