├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── algorithms ├── discovery │ ├── INSLabel.als │ └── ins.als ├── distributed-hashtable │ ├── chord.als │ ├── chord2.als │ └── chordbugmodel.als ├── echo │ ├── echo.md │ ├── echo.thm │ ├── echo_reif.md │ ├── echo_reif.thm │ ├── echo_var.md │ ├── echo_var.thm │ └── readme.md ├── election │ ├── ringlead.als │ ├── s_ringlead.als │ └── stable_ringlead.als ├── gc │ └── marksweepgc.als ├── mapping │ └── view-backing.als ├── multicasting │ └── iolus.als ├── mutex │ ├── dijkstra-2-process.als │ ├── dijkstra-K-state.als │ └── peterson.als ├── ring-orientation │ └── stable-orient-ring.als ├── spanning-tree │ └── opt_spantree.als └── synchronisation │ ├── sync.als │ └── syncimpl.als ├── ietf-rfcs └── rfc7617-BasicAuth │ └── basic-auth.als ├── logic └── syllogism │ └── syllogism.als ├── models ├── file-system │ └── file_system.als ├── firewire │ └── firewire.als ├── java │ ├── java-map.als │ ├── javatypes.als │ └── javatypes_soundness.als ├── logic │ └── philosophers.als ├── microsoft-com │ └── com.als ├── transport │ └── railway.als ├── typography │ └── paragraph-numbering.als └── webattack │ └── webattack.md ├── paper-examples └── jackson-cacm-2019 │ ├── origin-tracking-meta.thm │ ├── origin-tracking.als │ └── origin-tracking.thm ├── puzzles ├── 8-queens │ └── queens.als ├── coloring │ └── color-australia.als ├── einstein │ └── einstein-wikipedia.als ├── farmer-chicken-fox │ └── farmer.als ├── halmos-handshake │ └── handshake.als ├── money.als ├── prisoner-room-visit │ ├── README.md │ └── prisoner.als └── tower-hanoi │ └── hanoi.als ├── simple-models ├── 4-bit-adder │ └── 4-bit-adder.als ├── books │ └── birthday.als ├── games │ └── life.als ├── genealogy │ ├── genealogy.als │ └── grandpa.als ├── lists │ └── lists.als ├── no-solution │ └── trivial.als └── state-machine │ ├── flip-flop.als │ └── reset-flipflop-with-enable.als ├── software-abstractions-book ├── appendixA │ ├── addressBook1.als │ ├── addressBook2.als │ ├── barbers.als │ ├── closure.als │ ├── distribution.als │ ├── phones.als │ ├── prison.als │ ├── properties.als │ ├── ring.als │ ├── spanning.als │ ├── tree.als │ ├── tube.als │ └── undirected.als ├── appendixE │ ├── hotel.thm │ ├── p300-hotel.als │ ├── p303-hotel.als │ └── p306-hotel.als ├── chapter2 │ ├── addressBook1a.als │ ├── addressBook1b.als │ ├── addressBook1c.als │ ├── addressBook1d.als │ ├── addressBook1e.als │ ├── addressBook1f.als │ ├── addressBook1g.als │ ├── addressBook1h.als │ ├── addressBook2a.als │ ├── addressBook2b.als │ ├── addressBook2c.als │ ├── addressBook2d.als │ ├── addressBook2e.als │ ├── addressBook3a.als │ ├── addressBook3b.als │ ├── addressBook3c.als │ ├── addressBook3d.als │ └── theme.thm ├── chapter4 │ ├── filesystem.als │ ├── grandpa1.als │ ├── grandpa2.als │ ├── grandpa3.als │ └── lights.als ├── chapter5 │ ├── addressBook.als │ ├── lists.als │ ├── sets1.als │ └── sets2.als └── chapter6 │ ├── hotel.thm │ ├── hotel1.als │ ├── hotel2.als │ ├── hotel3.als │ ├── hotel4.als │ ├── mediaAssets.als │ ├── memory │ ├── abstractMemory.als │ ├── cacheMemory.als │ ├── checkCache.als │ ├── checkFixedSize.als │ ├── fixedSizeMemory.als │ └── fixedSizeMemory_H.als │ ├── ringElection.thm │ ├── ringElection1.als │ └── ringElection2.als └── utilities ├── messaging └── messaging.als ├── time └── overlapping-ranges.als ├── trace └── trace.als └── types ├── boolean.als ├── graph.als ├── integer.als ├── natural.als ├── ordering.als ├── relation.als ├── seqrel.als ├── sequence.als ├── sequniv.als ├── ternary.als └── time.als /README.md: -------------------------------------------------------------------------------- 1 | # Alloy Models 2 | A public repository to host Alloy models. 3 | 4 | This repository holds public models to be used as entertainment, examples, tutorials, utilities, and proofs. All models are free to use and expand under the Apache 2 License. 5 | 6 | We are actively seeking contributions and improvements. Just submit a PR, see the [CONTRIBUTING](CONTRIBUTING.md) for the rules. 7 | 8 | If you're not familiar with Github you can read [how to add a file to another repository](https://help.github.com/articles/editing-files-in-another-user-s-repository/) to find out how to add a _Pull Request_ (PR). (This is simpler than you think.) 9 | 10 | You can also look at this [short video](https://www.youtube.com/watch?v=4vya039Ku64) that shows how to propose a new model. 11 | 12 | [![Watch the video](https://user-images.githubusercontent.com/200494/45866577-9bf8ba00-bd81-11e8-8349-07820551e7ad.png)](https://www.youtube.com/watch?v=4vya039Ku64) 13 | 14 | To propose a change to an existing model, just click the file you want to change and edit it by clicking on the pen in the top right corner. 15 | 16 | alt text 17 | -------------------------------------------------------------------------------- /algorithms/discovery/INSLabel.als: -------------------------------------------------------------------------------- 1 | /* 2 | * Models an Intentional Naming System (INS), a scheme for 3 | * dynamic resource discovery in a dynamic environment. 4 | * 5 | * S. Khurshid. Exploring the Design of an Intentional Naming Scheme with an 6 | * Automatic Constraint Analyzer. S.M. Thesis. Laboratory for Computer Science, 7 | * M.I.T. Cambridge, MA. May 2000. 8 | * 9 | * author: Sarfraz Khurshid 10 | */ 11 | 12 | sig Record {} 13 | 14 | sig Label {} 15 | 16 | sig Node { 17 | label: Label 18 | } 19 | 20 | sig LabelTree { 21 | root: Node, 22 | nodes: set Node, 23 | children: nodes one -> (nodes - root) 24 | } 25 | { // connected 26 | nodes = root.*children 27 | some root.children 28 | } 29 | 30 | pred Get[db: DB, r: Record, a:Advertisement] { 31 | root[a] = root[db] 32 | nodes[a] = 33 | nodes[db] & r.~(db.recs).*(~(db.children)) 34 | anodes[a] = 35 | anodes[db] & r.~(db.recs).*(~(db.children)) 36 | vnodes[a] = 37 | vnodes[db] & r.~(db.recs).*(~(db.children)) 38 | all n: a.nodes | 39 | n.~(a.children) = n.~(db.children) 40 | } 41 | 42 | sig Attribute extends Label {} 43 | 44 | sig Value extends Label {} 45 | 46 | one sig Wildcard, Null extends Value {} 47 | 48 | sig AVTree extends LabelTree { 49 | vnodes, anodes: set nodes 50 | } 51 | { 52 | root in vnodes 53 | root.label = Null 54 | Null !in (vnodes - root).label + anodes.label 55 | anodes.label in Attribute 56 | vnodes.label in Value 57 | all n: nodes | all /* disj */ c,c": n.children | 58 | c.label != c".label 59 | all a: anodes | a.children in vnodes && some a.children 60 | all v: vnodes | v.children in anodes 61 | no Wildcard.~label.children 62 | } 63 | 64 | one sig Query extends AVTree {} 65 | { 66 | all a: anodes | one a.children 67 | } 68 | 69 | one sig Advertisement extends AVTree {} 70 | { 71 | Wildcard !in vnodes.label 72 | } 73 | 74 | one sig DB extends AVTree { 75 | records: set Record, 76 | recs: (vnodes - root) some -> records 77 | } 78 | { 79 | Wildcard !in vnodes.label 80 | all a: anodes | no a.recs 81 | all v: vnodes { 82 | no v.children => some v.recs 83 | no v.recs & v.^(~children).recs } 84 | all a: anodes | all disj v,v": a.children | 85 | (no v.*children.recs & v".*children.recs) 86 | } 87 | 88 | one sig State { 89 | conforms: Query -> Advertisement -> Node -> Node, 90 | lookup: DB -> Query -> Node -> Node -> Record 91 | } 92 | 93 | fact ConformsFixPoint { 94 | all q: Query | all a: Advertisement | 95 | all nq: Node | all na: Node | 96 | q.ConformsAux[a,nq,na] <=> 97 | { 98 | nq.label in Wildcard + na.label 99 | all nq": q.children[nq] | some na": a.children[na] | 100 | q.ConformsAux[a,nq",na"] 101 | } 102 | } 103 | 104 | pred Query.ConformsAux[a: Advertisement, nq: Node, na: Node] { 105 | na in State.conforms[this][a][nq] 106 | } 107 | 108 | pred Conforms[q: Query, a:Advertisement] { 109 | q.ConformsAux[a, q.root, a.root] 110 | } 111 | 112 | fact LookupFixPoint { 113 | all db: DB, q: Query, T: Node, n: Node, r: Record | 114 | r in db.LookupAux[q,T,n] <=> // record r is in the result if and only if 115 | { 116 | all na: n.(q.children) | all nv: na.(q.children) | // for all child av-pairs (na,nv) of av-pair n in q 117 | some Ta: T.(db.children) { 118 | Ta.label = na.label // Ta is a child node with attribute na 119 | nv.label = Wildcard => // wildcard matching 120 | r in Ta.^(db.children).(db.recs) else // r is a record of any child of Ta 121 | (some Tv: Ta.(db.children) { // normal matching 122 | Tv.label = nv.label // Tv is a child of Ta with value nv 123 | no nv.(q.children) => // if Tv is a leaf-node 124 | r in Tv.*(db.children).(db.recs) else // r is a record of Tv or of v 125 | r in db.LookupAux[q,Tv,nv] }) } // else r is a record of the recursive call at Tv 126 | } 127 | } 128 | 129 | fun DB.LookupAux[q: Query, vd: Node, vq: Node]: set Record { // helper function for Lookup 130 | State.lookup[this][q][vd][vq] 131 | } 132 | 133 | fun Lookup[db: DB, q: Query]: set Record { // models Lookup-Name algorithm invocation 134 | db.LookupAux[q, db.root, q.root] 135 | } 136 | 137 | assert LookupConforms2 { //soundness and completeness 138 | all q: Query | all db: DB | all r: Record | all a: Advertisement | 139 | Get[db,r,a] => // all n: a.nodes | n.~(db.children) 140 | {r in db.Lookup[q] <=> q.Conforms[a]} 141 | } 142 | 143 | // < 10 sec 144 | check LookupConforms2 for 4 but 1 State, 3 LabelTree, 2 Record expect 0 145 | // ~ 25 min 146 | //check LookupConforms2 for 6 but 1 State, 3 LabelTree, 2 Record 147 | //check LookupConforms2 for 6 but 1 State, 3 LabelTree, 3 Record 148 | run Lookup for 3 expect 0 149 | -------------------------------------------------------------------------------- /algorithms/discovery/ins.als: -------------------------------------------------------------------------------- 1 | /* 2 | * Models an Intentional Naming System (INS), a scheme for 3 | * dynamic resource discovery in a dynamic environment. 4 | * 5 | * S. Khurshid. Exploring the Design of an Intentional Naming Scheme with an 6 | * Automatic Constraint Analyzer. S.M. Thesis. Laboratory for Computer Science, 7 | * M.I.T. Cambridge, MA. May 2000. 8 | * 9 | * author: Sarfraz Khurshid 10 | */ 11 | 12 | open util/relation as rel 13 | 14 | sig Attribute {} 15 | sig Value {} 16 | sig Record {} 17 | 18 | one sig Wildcard extends Value {} 19 | 20 | sig AVTree { 21 | values: set Value, 22 | attributes: set Attribute, 23 | root: values - Wildcard, 24 | av: attributes one -> some (values - root), 25 | va: (values - Wildcard) one -> attributes 26 | }{ 27 | // values (and attributes) of tree are those reachable from root 28 | values = root.*(va.av) 29 | } 30 | 31 | sig Query extends AVTree {} {all a:attributes | one a.av} 32 | 33 | sig DB extends AVTree { 34 | records : set Record, 35 | recs: (values - root) some -> records, 36 | lookup : Query -> (values -> records) 37 | }{ 38 | Wildcard !in values 39 | } 40 | 41 | fact AddInvariants { 42 | all db: DB { 43 | all v: db.values | no v.(db.recs) & v.^(~(db.av).~(db.va)).(db.recs) 44 | all a: db.attributes | all disj v1, v2: a.(db.av) | 45 | (some rr: *((db.va).(db.av)).(db.recs) | no v1.rr & v2.rr) 46 | } 47 | } 48 | 49 | pred Get [db: DB, r: Record, q: Query] { 50 | q.values = r.~(db.recs).*(~(db.av).~(db.va)) 51 | q.attributes = q.values.~(db.av) 52 | q.root = db.root 53 | all a : attributes| a.~(q.va) = a.~(db.va) 54 | all v : values | v.~(q.av) = v.~(db.av) 55 | } 56 | 57 | pred Conforms [db: DB, q: Query, r: Record] { 58 | some p: Query { 59 | db.Get[r, p] 60 | q.va in p.va 61 | (q.av - Attribute -> Wildcard) in p.av 62 | } 63 | } 64 | 65 | pred indSubset[db : DB, q: Query, r: set Record, v: Value] { 66 | all a : v.(q.va) | 67 | (a.(q.av) in a.(db.av) => r in (a.(q.av)).(q.(db.lookup))) && 68 | (a.(q.av) = Wildcard => r in a.(db.av).*((db.va).(db.av)).(db.recs)) 69 | } 70 | 71 | pred Lookup[db: DB, q: Query, found: set Record] { 72 | all v: Value | not v.(q.va) in v.(db.va) => no v.(q.(db.lookup)) 73 | all v: Value | all a : v.(q.va) | 74 | a.(q.av) != Wildcard && not a.(q.av) in a.(db.av) => no v.(q.(db.lookup)) 75 | all v: Value - Wildcard | 76 | no v.(q.va) => v.(q.(db.lookup)) = v.*((db.va).(db.av)).(db.recs) 77 | all v: Value | 78 | some v.(q.va) => indSubset[db, q, v.(q.(db.lookup)), v] && 79 | (no r: Record - v.(q.(db.lookup)) | indSubset[db, q, v.(q.(db.lookup)) + r, v]) 80 | found = db.root.(q.(db.lookup)) 81 | } 82 | 83 | assert CorrectLookup { 84 | all db: DB | all q : Query | all r : Record | 85 | Conforms [db,q,r] <=> db.Lookup[q, r] 86 | } 87 | 88 | pred Add [me: DB, adv: Query, r: Record, db: DB] { 89 | // restricted version - only advertisements with fresh attributes and values added 90 | no me.attributes & adv.attributes 91 | me.values & adv.values = me.root 92 | me.root = adv.root 93 | Wildcard !in adv.values 94 | r !in me.records 95 | db.values = me.values + adv.values 96 | db.attributes = me.attributes + adv.attributes 97 | db.root = me.root 98 | db.av = me.av + adv.av 99 | db.va = me.va + adv.va 100 | db.recs = me.recs + ((db.values - dom[db.va]) -> r) 101 | } 102 | 103 | pred RemoveWildCard[me: Query, q: Query] { 104 | q.values = me.values - Wildcard 105 | q.attributes = me.attributes - Wildcard.~(me.av) 106 | q.root = me.root 107 | q.av = me.av - Attribute -> Wildcard 108 | q.va = me.va - Value -> Wildcard.~(me.av) 109 | } 110 | 111 | assert MissingAttributeAsWildcard { 112 | all db : DB, q, q" : Query, found: set Record | 113 | db.Lookup[q, found] && q.RemoveWildCard[q"] => db.Lookup[q", found] 114 | } 115 | -------------------------------------------------------------------------------- /algorithms/echo/echo.thm: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /algorithms/echo/echo_reif.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Echo algorithm with reification of transition predicates 3 | author: Burkhardt Renz 4 | date: February 2022 5 | --- 6 | 7 | ## The echo algorithm with reification of transition predicates 8 | 9 | The visualisation of the echo algorithm in `echo.md` does not show which 10 | transition predicates is responsible for a state transition. 11 | Using the _event reification idiom_ 12 | (see [An idiom to depict events](https://haslab.github.io/formal-software-design/modeling-tips/index.html#an-idiom-to-depict-events)) it is possible to improve the 13 | visualisation. 14 | 15 | To observe the effects of the new entities that represent transition 16 | predicates in the _instance window_ of the Alloy Analyzer, you should 17 | load _theme_ `echo_reif.thm`. 18 | 19 | The following part of the specification is the same as in `echo.als`: 20 | 21 | ```alloy 22 | open util/graph[Node] 23 | 24 | let unchanged[r] { (r)' = (r) } 25 | 26 | enum Color {Red, Green} 27 | 28 | abstract sig Node { 29 | neighbors: set Node, 30 | var parent: lone Node, 31 | var inbox: set Node, 32 | var color: Color 33 | } 34 | 35 | one sig INode extends Node{} 36 | sig PNode extends Node{} 37 | 38 | fact { 39 | noSelfLoops[neighbors] 40 | undirected[neighbors] 41 | rootedAt[neighbors, INode] 42 | } 43 | 44 | pred init { 45 | no parent 46 | no inbox 47 | color = Node->Red 48 | } 49 | 50 | pred stutter { 51 | unchanged[parent] 52 | unchanged[inbox] 53 | unchanged[color] 54 | } 55 | 56 | pred broadcast[n, fp: Node] { 57 | all q: n.neighbors - fp | q.inbox' = q.inbox + n 58 | all u: (Node - n.neighbors) + fp | unchanged[u.inbox] 59 | } 60 | 61 | pred initiate { 62 | init 63 | broadcast[INode, INode] 64 | unchanged[parent] 65 | unchanged[color] 66 | } 67 | 68 | pred forward [n: Node, msg: Node] { 69 | (not n = INode) and no n.parent and msg in n.inbox 70 | parent' = parent + n->msg 71 | broadcast[n, msg] 72 | unchanged[color] 73 | } 74 | 75 | pred echo [n: Node] { 76 | (n = INode or one n.parent) and n.inbox = n.neighbors and n.color = Red 77 | unchanged[parent] 78 | inbox' = inbox ++ n.parent->(n.parent.inbox + n) 79 | color' = color ++ (n->Green) 80 | } 81 | ``` 82 | 83 | The first step is the definition of an enumeration of atoms that 84 | represent the transition predicates in the visualisation. 85 | 86 | ```alloy 87 | enum TransPred { Initiate, Forward, Echo, Stutter } 88 | ``` 89 | 90 | In the second step we make sure that these singletons are coupled with 91 | the state transitions using functions in Alloy. At first 92 | glance the definition of the functions look self-referential: In the 93 | definition of `initiate` e.g. `initiate` itself occurs. However, in one 94 | case it is the _function_ and in the other case the _predicate_. In 95 | Alloy functions and predicates can be overloaded. 96 | 97 | ```alloy 98 | fun initiate: TransPred { 99 | { tp: Initiate | initiate } 100 | } 101 | fun forward: TransPred -> Node -> Node { 102 | { tp: Forward, n, msg: Node | forward[n, msg] } 103 | } 104 | fun echo: TransPred -> Node { 105 | { tp: Echo, n: Node | echo[n] } 106 | } 107 | fun stutter: TransPred { 108 | { tp: Stutter | stutter} 109 | } 110 | fun transPreds: set TransPred { 111 | initiate + forward.Node.Node + echo.Node + stutter 112 | } 113 | ``` 114 | 115 | Since `transPreds` is the set of the names of the transition predicates, 116 | we can use these names in the definition of the transition system: 117 | 118 | ```alloy 119 | fact trans { 120 | init 121 | always some transPreds 122 | } 123 | ``` 124 | 125 | Finally we define a function that gives us the green nodes of the graphs. 126 | We can use this function to show the color in the visualisation. 127 | 128 | ```alloy 129 | fun finished: set Node { 130 | { n: Node | n.color = Green } 131 | } 132 | ``` 133 | 134 | The predicates and assertions for the verification remain unchanged. 135 | 136 | ```alloy 137 | pred fairness { 138 | all n, msg: Node { 139 | (eventually always init) 140 | implies (always eventually initiate) 141 | (eventually always (not n = INode and no n.parent and msg in n.inbox)) 142 | implies (always eventually forward[n, msg]) 143 | (eventually always ((n = INode or one n.parent) and n.inbox = n.neighbors and n.color = Red)) 144 | implies (always eventually echo[n]) 145 | } 146 | } 147 | 148 | run examples {} 149 | 150 | run withProgress {fairness} for exactly 4 Node 151 | 152 | assert EchoComesBack { 153 | fairness implies eventually INode.color = Green 154 | } 155 | check EchoComesBack 156 | 157 | assert SpanningTree { 158 | always (INode.color = Green 159 | implies (tree[~parent] and rootedAt[~parent, INode])) 160 | } 161 | check SpanningTree 162 | ``` 163 | 164 | To get a nice visualisation you have to customize the _theme_. An 165 | example how to do this is found in `echo_reif.thm`. 166 | 167 | -------------------------------------------------------------------------------- /algorithms/echo/echo_reif.thm: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /algorithms/echo/echo_var.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Echo algorithm - variant 3 | author: Burkhardt Renz 4 | date: February 2022 5 | --- 6 | ## The echo algorithm - variant 7 | 8 | So far we specified graphs with a dedicated node that initiates 9 | the echo algorithm. In this variant of the specification we let the 10 | Alloy model finder choose the initiating node. 11 | 12 | ```alloy 13 | open util/graph[Node] 14 | 15 | let unchanged[r] { (r)' = (r) } 16 | 17 | enum Color {Red, Green} 18 | 19 | sig Node { 20 | neighbors: set Node, 21 | var parent: lone Node, 22 | var inbox: set Node, 23 | var color: Color 24 | } 25 | ``` 26 | 27 | Since we do not have a dedicated initiator, we have to ensure the 28 | connectivity of the graph by the predicate `stronglyConnected` from 29 | `util/graph`. 30 | 31 | ```alloy 32 | fact { 33 | noSelfLoops[neighbors] 34 | undirected[neighbors] 35 | stronglyConnected[neighbors] 36 | } 37 | ``` 38 | 39 | The definition of the transition predicates has a small modification: 40 | The initiating node marks itself as its parent. 41 | 42 | ```alloy 43 | pred stutter { 44 | unchanged[parent] 45 | unchanged[inbox] 46 | unchanged[color] 47 | } 48 | 49 | pred broadcast[n, fp: Node] { 50 | all q: n.neighbors - fp | q.inbox' = q.inbox + n 51 | all u: Node - n.neighbors + fp | u.inbox' = u.inbox 52 | } 53 | 54 | pred initiate[n: Node] { 55 | parent = n -> n 56 | no inbox 57 | color = Node -> Red 58 | unchanged[parent] 59 | #Node = 1 implies { 60 | color' = n -> Green 61 | unchanged[inbox] 62 | } else { 63 | broadcast[n, n] 64 | unchanged[color] 65 | } 66 | } 67 | 68 | pred forward [n: Node, msg: Node] { 69 | no n.parent and msg in n.inbox 70 | parent' = parent + n->msg 71 | broadcast[n, msg] 72 | unchanged[color] 73 | } 74 | 75 | pred echo [n: Node] { 76 | one n.parent and n.inbox = n.neighbors and n.color = Red 77 | unchanged[parent] 78 | inbox' = inbox ++ n.parent->(n.parent.inbox + n) 79 | color' = color ++ (n->Green) 80 | } 81 | ``` 82 | 83 | In the definition of the transition system, we perform as first step 84 | `initiate` for some node chosen by the model finder. Thus, the other 85 | possible steps are only possible in the next step `after` the first 86 | one: 87 | 88 | ```alloy 89 | fact trans { 90 | some n: Node | initiate[n] 91 | after always { 92 | some n, msg: Node | forward[n, msg] or 93 | some n: Node | echo[n] or 94 | stutter 95 | } 96 | } 97 | 98 | pred fairness { 99 | all n, msg: Node { 100 | (eventually always (no n.parent and msg in n.inbox)) 101 | implies (always eventually forward[n, msg]) 102 | (eventually always (one n.parent and n.inbox = n.neighbors and n.color = Red)) 103 | implies (always eventually echo[n]) 104 | } 105 | } 106 | 107 | run examples {} 108 | 109 | run makeProgress {fairness} 110 | 111 | assert echoComesBack { 112 | fairness implies (eventually all n:Node | n.color = Green) 113 | } 114 | check echoComesBack 115 | ``` 116 | 117 | Since we defined a self loop at the initiating node, we must modify 118 | the check whether we got a spanning tree as result of the algorithm: 119 | ```alloy 120 | assert SpanningTree { 121 | #{ n: Node | n = n.parent} = 1 122 | always (color = Node->Green implies tree[~(parent-iden)]) 123 | } 124 | 125 | check SpanningTree 126 | ``` 127 | -------------------------------------------------------------------------------- /algorithms/echo/echo_var.thm: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /algorithms/echo/readme.md: -------------------------------------------------------------------------------- 1 | #### Content of the folder 2 | `echo.md, echo.thm` 3 | echo algorithm constructing a spanning tree, spec and theme 4 | 5 | `echo_reif.md, echo_reif.thm` 6 | variant with reification of transition predicates 7 | 8 | `echo_var.md, echo_var.thm` 9 | variant without dedicated initiator -------------------------------------------------------------------------------- /algorithms/election/ringlead.als: -------------------------------------------------------------------------------- 1 | /* 2 | * Model of leader election on a ring 3 | * 4 | * Each process has a unique ID, IDs are ordered. 5 | * The algorithm elects the process with the highest 6 | * ID the leader, as follows. First, each process 7 | * sends its own ID to its right neighbor. 8 | * Then, whenever a process receives an ID, if the 9 | * ID is greater than the process' own ID it forwards 10 | * the ID to its right neighbor, otherwise does nothing. 11 | * When a process receives its own ID that process 12 | * is the leader. 13 | */ 14 | 15 | open util/boolean as bool 16 | open examples/algorithms/messaging as msg 17 | open util/ordering[msg/Node] as nodeOrd 18 | open util/ordering[msg/Tick] as tickOrd 19 | 20 | sig RingLeadNode extends msg/Node { 21 | rightNeighbor: msg/Node 22 | } 23 | 24 | fact DefineRing { 25 | (one msg/Node || (no n: msg/Node | n = n.rightNeighbor)) 26 | all n: msg/Node | msg/Node in n.^rightNeighbor 27 | } 28 | 29 | sig RingLeadMsgState extends msg/MsgState { 30 | id: msg/Node 31 | } 32 | 33 | sig MsgViz extends msg/Msg { 34 | vFrom: msg/Node, 35 | vTo: set msg/Node, 36 | vId: msg/Node 37 | } 38 | 39 | fact { 40 | MsgViz = msg/Msg 41 | vFrom = state.from 42 | vTo = state.to 43 | vId = state.id 44 | } 45 | 46 | 47 | sig RingLeadNodeState extends msg/NodeState { 48 | leader: Bool 49 | } 50 | 51 | 52 | pred RingLeadFirstTrans [self: msg/Node, pre, post: msg/NodeState, 53 | sees, reads, sends, needsToSend: set msg/Msg] { 54 | one sends 55 | # needsToSend = 1 56 | sends.state.to = self.rightNeighbor 57 | sends.state.id = self 58 | post.leader = False 59 | } 60 | 61 | fact InitRingLeadState { 62 | all n: msg/Node | 63 | tickOrd/first.state[n].leader = False 64 | } 65 | 66 | pred RingLeadRestTrans [self: msg/Node, pre, post: msg/NodeState, 67 | sees, reads, sends, needsToSend: set msg/Msg] { 68 | RingLeadTransHelper[self, sees, reads, sends, needsToSend] 69 | post.leader = True iff (pre.leader = True || 70 | self in reads.state.id) 71 | } 72 | 73 | /** 74 | * we take any messages whose node ids are higher than ours, 75 | * and we forward them to the right neighbor. we drop 76 | * all other messages. if we get a message with our own 77 | * id, we're the leader. 78 | */ 79 | pred RingLeadTransHelper[self: msg/Node, sees, reads, sends, needsToSend: set msg/Msg] { 80 | reads = sees 81 | 82 | all received: reads | 83 | (received.state.id in nodeOrd/nexts[self]) => 84 | (one weSend: sends | (weSend.state.id = received.state.id && weSend.state.to = self.rightNeighbor)) 85 | 86 | all weSend: sends | { 87 | let mID = weSend.state.id | { 88 | mID in nodeOrd/nexts[self] 89 | mID in reads.state.id 90 | weSend.state.to = self.rightNeighbor 91 | } 92 | //weSend.sentBecauseOf = { received : reads | received.id = weSend.id } 93 | //all otherWeSend: sends - weSend | otherWeSend.id != weSend.id 94 | } 95 | 96 | # needsToSend = # { m: reads | m.state.id in nodeOrd/nexts[self] } 97 | } 98 | fact RingLeadTransitions { 99 | all n: msg/Node { 100 | all t: msg/Tick - tickOrd/last | { 101 | t = tickOrd/first => 102 | RingLeadFirstTrans[n, t.state[n], tickOrd/next[t].state[n], t.visible[n], t.read[n], t.sent[n], t.needsToSend[n]] 103 | else 104 | RingLeadRestTrans[n, t.state[n], tickOrd/next[t].state[n], t.visible[n], t.read[n], t.sent[n], t.needsToSend[n]] 105 | } 106 | // also constrain last tick 107 | RingLeadTransHelper[n, tickOrd/last.visible[n], tickOrd/last.read[n], tickOrd/last.sent[n], tickOrd/last.needsToSend[n]] 108 | } 109 | } 110 | 111 | assert OneLeader { 112 | all t: msg/Tick | 113 | lone n: msg/Node | 114 | t.state[n].leader = True 115 | } 116 | 117 | fact CleanupViz { 118 | RingLeadNode = msg/Node 119 | RingLeadMsgState = msg/MsgState 120 | RingLeadNodeState = msg/NodeState 121 | } 122 | 123 | pred SomeLeaderAtTick[t: msg/Tick] { 124 | some n: msg/Node | t.state[n].leader = True 125 | } 126 | 127 | pred NeverFindLeader { 128 | msg/Loop 129 | all t: msg/Tick | ! SomeLeaderAtTick[t] 130 | } 131 | 132 | assert Liveness { 133 | (msg/NoLostMessages && msg/NoMessageShortage) => ! NeverFindLeader 134 | } 135 | 136 | pred SomeLeader { some t: msg/Tick | SomeLeaderAtTick[t] } 137 | 138 | assert LeaderHighest { 139 | all t: msg/Tick, n: msg/Node | 140 | t.state[n].leader = True => n = nodeOrd/last 141 | } 142 | 143 | run NeverFindLeader for 1 but 3 msg/Tick, 2 Bool, 2 msg/NodeState expect 1 144 | check Liveness for 3 but 6 msg/Msg, 2 Bool, 2 msg/NodeState expect 0 145 | check OneLeader for 5 but 2 Bool, 2 msg/NodeState expect 0 146 | run SomeLeader for 2 but 3 msg/Node, 5 msg/Msg, 5 msg/Tick, 5 msg/MsgState expect 1 147 | check LeaderHighest for 3 but 2 msg/NodeState, 5 msg/Msg, 5 msg/MsgState, 5 msg/Tick expect 0 148 | 149 | -------------------------------------------------------------------------------- /algorithms/election/s_ringlead.als: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Model of leader election on a ring. 4 | * 5 | * Each process has a unique ID, IDs are ordered. The algorithm 6 | * elects the process with the highest ID the leader, as follows. 7 | * First, each process sends its own ID to its right neighbor. 8 | * Then, whenever a process receives an ID, if the ID is greater 9 | * than the process' own ID it forwards the ID to its right 10 | * neighbor, otherwise does nothing. When a process receives its 11 | * own ID that process is the leader. 12 | * 13 | * Note: This file needs higher order quantifiers turned on. 14 | */ 15 | 16 | open util/ordering[State] as so 17 | open util/ordering[Process] as po 18 | open util/graph[Process] as graph 19 | 20 | sig Process { 21 | rightNeighbor: Process 22 | } 23 | 24 | sig State { 25 | // buffer which the right neighbor can read from 26 | buffer: Process -> Process, 27 | //sends, reads: Process -> Process, 28 | runs: set Process, 29 | leader: set Process 30 | } 31 | 32 | fact DefineRing { 33 | graph/ring[rightNeighbor] 34 | } 35 | 36 | fact InitialState { 37 | no so/first.buffer 38 | no so/first.leader 39 | Process in so/first.runs 40 | } 41 | 42 | 43 | fact CleanupLast { 44 | let ls = so/last | 45 | no ls.runs 46 | } 47 | 48 | pred ValidTrans2[s, s": State] { 49 | all p : s.runs | VT2Helper[p,s,s"] 50 | all p : Process - s.runs | NOP2[p,s,s"] 51 | NoMagicMsg[s,s"] 52 | 53 | } 54 | 55 | pred NoMagicMsg[s, s" : State] { 56 | // no magically appearing messages 57 | all p : Process, m : s".buffer[p] | 58 | m in s.buffer[p] || (!NOP2[p,s,s"] && 59 | ((s = so/first && m = p) || 60 | (s != so/first && m in s.buffer[p.~rightNeighbor] 61 | && m !in s".buffer[p.~rightNeighbor] && po/gt[m,p]))) 62 | } 63 | 64 | pred PossTrans[s, s" : State] { 65 | all p : Process | VT2Helper[p,s,s"] || NOP2[p,s,s"] 66 | NoMagicMsg[s,s"] 67 | } 68 | 69 | pred VT2Helper[p : Process, s, s" : State] { 70 | ( 71 | let readable=s.buffer[p.~rightNeighbor] | 72 | (s = so/first) => { 73 | p = s".buffer[p] 74 | readable in s".buffer[p.~rightNeighbor] 75 | p !in s".leader 76 | } else { 77 | (some readable) => { 78 | some m : set readable | { 79 | m !in s".buffer[p.~rightNeighbor] 80 | // nothing else gets deleted 81 | readable - m in s".buffer[p.~rightNeighbor] 82 | { m": m | po/gt[m",p] } /*m & nexts(p)*/ in s".buffer[p] 83 | p in s".leader iff (p in s.leader || p in m) 84 | } 85 | } else NOP2[p,s,s"] 86 | } 87 | ) 88 | } 89 | 90 | pred NOP2[p : Process, s,s": State] { 91 | p in s".leader iff p in s.leader 92 | // no reads 93 | s.buffer[p.~rightNeighbor] in s".buffer[p.~rightNeighbor] 94 | // no sends 95 | s".buffer[p] in s.buffer[p] 96 | } 97 | 98 | pred Preconds[p : Process, s : State] { 99 | s = so/first || some s.buffer[p.~rightNeighbor] 100 | } 101 | 102 | fact TransIfPossible { 103 | all s : State - so/last | 104 | (all p : Process | NOP2[p, s, so/next[s]]) => 105 | (all p : Process | !Preconds[p,s]) 106 | } 107 | 108 | fact LegalTrans { 109 | all s : State - so/last | 110 | let s" = so/next[s] | 111 | ValidTrans2[s,s"] 112 | } 113 | 114 | pred EquivStates[s, s": State] { 115 | s.buffer = s".buffer 116 | s.leader = s".leader 117 | } 118 | 119 | assert Safety { 120 | all s : State | lone s.leader 121 | } 122 | 123 | pred Legit[s : State] { 124 | one s.leader 125 | } 126 | 127 | pred BadLivenessTrace { 128 | all s : State | !Legit[s] 129 | let ls = so/last | 130 | some s : State - ls | { 131 | EquivStates[s, ls] 132 | Process in (so/nexts[s] + s).runs 133 | } 134 | } 135 | 136 | pred TraceWithoutLoop { 137 | all t1, t2 : State | t1!=t2 => !EquivStates[t1,t2] 138 | all s, s" : State | (s" in (so/nexts[s] - so/next[s])) => !PossTrans[s,s"] 139 | all s : State | !Legit[s] 140 | } 141 | 142 | pred AltTrans { 143 | SomeLeader 144 | } 145 | 146 | pred SomeLeader { some State.leader } 147 | 148 | run BadLivenessTrace for 3 but 8 State expect 0 149 | run SomeLeader for 4 but 6 State expect 1 150 | check Safety for 7 expect 0 151 | // run TraceWithoutLoop for 5 but 13 State expect 1 152 | run AltTrans for 5 but 8 State expect 1 153 | -------------------------------------------------------------------------------- /algorithms/election/stable_ringlead.als: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Huang's self-stabilizing leader-election algorithm 4 | * for rings. 5 | */ 6 | 7 | open util/ordering[Process] as po 8 | open util/ordering[Val] as vo 9 | open util/ordering[State] as so 10 | open util/graph[Process] as graph 11 | 12 | sig Process { 13 | rightNeighbor: Process 14 | } 15 | 16 | sig Val { 17 | nextVal : Val 18 | } 19 | 20 | fact { 21 | graph/ring[rightNeighbor] 22 | vo/next + (vo/last -> vo/first) = nextVal 23 | # Val = # Process 24 | } 25 | 26 | sig State { 27 | val : Process -> one Val, 28 | running : set Process 29 | // for visualization 30 | //leader : set Process 31 | } { 32 | //leader = { p : Process | LeaderAtState(p, this) } 33 | } 34 | 35 | fact { 36 | no so/last.running 37 | } 38 | 39 | fun LeadersAtState[t : State] : set Process { 40 | { p : Process | LeaderAtState[p,t] } 41 | } 42 | 43 | pred LeaderAtState[p : Process, t : State] { ValAtState[p,t] = vo/first } 44 | 45 | fun ValAtState[p : Process, t : State] : Val { t.val[p] } 46 | 47 | fun LeftValAtState[p : Process, t : State] : Val { t.val[p.~rightNeighbor] } 48 | 49 | fun RightValAtState[p : Process, t : State] : Val { t.val[p.rightNeighbor] } 50 | 51 | fun XAtState[p : Process, t : State] : Int { 52 | g[LeftValAtState[p,t],ValAtState[p,t]] 53 | } 54 | 55 | fun YAtState[p : Process, t : State] : Int { 56 | g[ValAtState[p,t],RightValAtState[p,t]] 57 | } 58 | 59 | fun g[a, b : Val] : Int { 60 | (a = b) => Int[# Val] else minus[b,a] 61 | } 62 | 63 | fun minus[v1, v2 : Val] : Int { 64 | Int[ (v1 = v2) => 0 65 | else vo/gt[v1, v2] => (# (vo/nexts[v2] & vo/prevs[v1] + v1)) 66 | else (# (Val - (vo/nexts[v1] & vo/prevs[v2] + v1))) 67 | ] 68 | } 69 | 70 | fun Trans[oldVal : Val, x, y : Int] : Val { 71 | ((int x = int y && int y = # Val) || (int x < int y)) => oldVal.nextVal else oldVal 72 | } 73 | 74 | pred OneAtATimeTrans { 75 | all tp: State - so/last | 76 | let tn = so/next[tp] | 77 | some p : Process | { 78 | tp.running = p 79 | TransHelper[p,tp,tn] 80 | all other : Process - p | 81 | ValAtState[other,tn] = ValAtState[other,tp] 82 | } 83 | } 84 | 85 | pred DDaemonTrans { 86 | all tp: State - so/last | 87 | let tn = so/next[tp] | { 88 | some tp.running 89 | all p : tp.running | TransHelper[p,tp,tn] 90 | all other : Process - tp.running | 91 | ValAtState[other,tn] = ValAtState[other,tp] 92 | } 93 | } 94 | 95 | pred TransHelper[p : Process, tp, tn : State] { 96 | let oldVal = ValAtState[p, tp], 97 | newVal = ValAtState[p, tn], 98 | x = XAtState[p, tp], 99 | y = YAtState[p,tp] | 100 | newVal = Trans[oldVal, x, y] 101 | 102 | } 103 | 104 | pred StateTrans[s, s" : State] { 105 | all p : Process | 106 | TransHelper[p, s, s"] || ValAtState[p,s] = ValAtState[p,s"] 107 | } 108 | 109 | 110 | 111 | pred CBadLivenessTrace { 112 | OneAtATimeTrans 113 | BadLivenessHelper 114 | } 115 | 116 | pred DBadLivenessTrace { 117 | DDaemonTrans 118 | BadLivenessHelper 119 | } 120 | 121 | pred BadLivenessHelper { 122 | let ls = so/last | 123 | some s : State - ls | { 124 | s.val = ls.val 125 | // fair 126 | Process in (so/nexts[s] + s - ls).running 127 | } 128 | all s : State | ! Legit[s] 129 | } 130 | 131 | pred CTraceWithoutLoop { 132 | OneAtATimeTrans 133 | all t, t" : State | t!=t" => t.val != t".val 134 | } 135 | 136 | pred DTraceWithoutLoop { 137 | DDaemonTrans 138 | all t, t" : State | t!=t" => { 139 | t.val != t".val 140 | (t" in so/nexts[t] && t" != so/next[t]) => !StateTrans[t,t"] 141 | } 142 | all t : State | !Legit[t] 143 | } 144 | 145 | pred ConvergingRun { 146 | OneAtATimeTrans 147 | !Legit[so/first] 148 | some t : State | Legit[t] 149 | } 150 | 151 | pred OnlyFairLoops { 152 | OneAtATimeTrans 153 | all s, s" : State | 154 | (s" in so/nexts[s] && s".val = s.val) => 155 | (let loopStates = (so/nexts[s] & so/prevs[s"]) + s + s" | Process in loopStates.running) 156 | } 157 | 158 | assert CMustConverge { 159 | OnlyFairLoops => (some s : State | Legit[s]) 160 | } 161 | 162 | pred Legit [s : State] { 163 | one LeadersAtState[s] 164 | all p : Process | { 165 | int XAtState[p,s] < # Val 166 | int YAtState[p,s] < # Val 167 | } 168 | all p, p" : Process | { 169 | int XAtState[p,s] = int XAtState[p",s] 170 | int YAtState[p,s] = int YAtState[p",s] 171 | } 172 | } 173 | 174 | run ConvergingRun for 3 but 4 State expect 1 175 | run DTraceWithoutLoop for 3 but 4 State expect 1 176 | run DBadLivenessTrace for 3 but 4 State expect 1 177 | run CTraceWithoutLoop for 3 but 5 State expect 0 178 | run CBadLivenessTrace for 4 but 5 State expect 1 179 | check CMustConverge for 3 but 4 State expect 0 180 | -------------------------------------------------------------------------------- /algorithms/gc/marksweepgc.als: -------------------------------------------------------------------------------- 1 | /* 2 | * Model of mark and sweep garbage collection. 3 | */ 4 | 5 | // a node in the heap 6 | sig Node {} 7 | 8 | sig HeapState { 9 | left, right : Node -> lone Node, 10 | marked : set Node, 11 | freeList : lone Node 12 | } 13 | 14 | pred clearMarks[hs, hs" : HeapState] { 15 | // clear marked set 16 | no hs".marked 17 | // left and right fields are unchanged 18 | hs".left = hs.left 19 | hs".right = hs.right 20 | } 21 | 22 | /** 23 | * simulate the recursion of the mark() function using transitive closure 24 | */ 25 | fun reachable[hs: HeapState, n: Node] : set Node { 26 | n + n.^(hs.left + hs.right) 27 | } 28 | 29 | pred mark[hs: HeapState, from : Node, hs": HeapState] { 30 | hs".marked = hs.reachable[from] 31 | hs".left = hs.left 32 | hs".right = hs.right 33 | } 34 | 35 | /** 36 | * complete hack to simulate behavior of code to set freeList 37 | */ 38 | pred setFreeList[hs, hs": HeapState] { 39 | // especially hackish 40 | hs".freeList.*(hs".left) in (Node - hs.marked) 41 | all n: Node | 42 | (n !in hs.marked) => { 43 | no hs".right[n] 44 | hs".left[n] in (hs".freeList.*(hs".left)) 45 | n in hs".freeList.*(hs".left) 46 | } else { 47 | hs".left[n] = hs.left[n] 48 | hs".right[n] = hs.right[n] 49 | } 50 | hs".marked = hs.marked 51 | } 52 | 53 | pred GC[hs: HeapState, root : Node, hs": HeapState] { 54 | some hs1, hs2: HeapState | 55 | hs.clearMarks[hs1] && hs1.mark[root, hs2] && hs2.setFreeList[hs"] 56 | } 57 | 58 | assert Soundness1 { 59 | all h, h" : HeapState, root : Node | 60 | h.GC[root, h"] => 61 | (all live : h.reachable[root] | { 62 | h".left[live] = h.left[live] 63 | h".right[live] = h.right[live] 64 | }) 65 | } 66 | 67 | assert Soundness2 { 68 | all h, h" : HeapState, root : Node | 69 | h.GC[root, h"] => 70 | no h".reachable[root] & h".reachable[h".freeList] 71 | } 72 | 73 | assert Completeness { 74 | all h, h" : HeapState, root : Node | 75 | h.GC[root, h"] => 76 | (Node - h".reachable[root]) in h".reachable[h".freeList] 77 | } 78 | 79 | check Soundness1 for 3 expect 0 80 | check Soundness2 for 3 expect 0 81 | check Completeness for 3 expect 0 82 | -------------------------------------------------------------------------------- /algorithms/mutex/dijkstra-2-process.als: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Models how mutexes are grabbed and released by processes, and 4 | * how Dijkstra's mutex ordering criterion can prevent deadlocks. 5 | * 6 | * For a detailed description, see: 7 | * E. W. Dijkstra, Cooperating sequential processes. Technological 8 | * University, Eindhoven, The Netherlands, September 1965. 9 | * Reprinted in Programming Languages, F. Genuys, Ed., Academic 10 | * Press, New York, 1968, 43-112. 11 | * 12 | * Acknowledgements to Ulrich Geilmann for finding and fixing a bug 13 | * in the GrabMutex predicate. 14 | * 15 | */ 16 | 17 | open util/ordering [State] as so 18 | open util/ordering [Mutex] as mo 19 | 20 | sig Process {} 21 | sig Mutex {} 22 | 23 | sig State { holds, waits: Process -> Mutex } 24 | 25 | 26 | pred Initial [s: State] { no s.holds + s.waits } 27 | 28 | pred IsFree [s: State, m: Mutex] { 29 | // no process holds this mutex 30 | no m.~(s.holds) 31 | // all p: Process | m !in p.(this.holds) 32 | } 33 | 34 | pred IsStalled [s: State, p: Process] { some p.(s.waits) } 35 | 36 | pred GrabMutex [s: State, p: Process, m: Mutex, s": State] { 37 | // a process can only act if it is not 38 | // waiting for a mutex 39 | !s.IsStalled[p] 40 | // can only grab a mutex we do not yet hold 41 | m !in p.(s.holds) 42 | // mutexes are grabbed in order 43 | all m": p.(s.holds) | mo/lt[m",m] 44 | s.IsFree[m] => { 45 | // if the mutex is free, we now hold it, 46 | // and do not become stalled 47 | p.(s".holds) = p.(s.holds) + m 48 | no p.(s".waits) 49 | } else { 50 | // if the mutex was not free, 51 | // we still hold the same mutexes we held, 52 | // and are now waiting on the mutex 53 | // that we tried to grab. 54 | p.(s".holds) = p.(s.holds) 55 | p.(s".waits) = m 56 | } 57 | all otherProc: Process - p | { 58 | otherProc.(s".holds) = otherProc.(s.holds) 59 | otherProc.(s".waits) = otherProc.(s.waits) 60 | } 61 | } 62 | 63 | pred ReleaseMutex [s: State, p: Process, m: Mutex, s": State] { 64 | !s.IsStalled[p] 65 | m in p.(s.holds) 66 | p.(s".holds) = p.(s.holds) - m 67 | no p.(s".waits) 68 | no m.~(s.waits) => { 69 | no m.~(s".holds) 70 | no m.~(s".waits) 71 | } else { 72 | some lucky: m.~(s.waits) | { 73 | m.~(s".waits) = m.~(s.waits) - lucky 74 | m.~(s".holds) = lucky 75 | } 76 | } 77 | all mu: Mutex - m { 78 | mu.~(s".waits) = mu.~(s.waits) 79 | mu.~(s".holds)= mu.~(s.holds) 80 | } 81 | } 82 | 83 | /** 84 | * for every adjacent (pre,post) pair of States, 85 | * one action happens: either some process grabs a mutex, 86 | * or some process releases a mutex, 87 | * or nothing happens (have to allow this to show deadlocks) 88 | */ 89 | pred GrabOrRelease { 90 | Initial[so/first] && 91 | ( 92 | all pre: State - so/last | let post = so/next [pre] | 93 | (post.holds = pre.holds && post.waits = pre.waits) 94 | || 95 | (some p: Process, m: Mutex | pre.GrabMutex [p, m, post]) 96 | || 97 | (some p: Process, m: Mutex | pre.ReleaseMutex [p, m, post]) 98 | 99 | ) 100 | } 101 | 102 | pred Deadlock { 103 | some Process 104 | some s: State | all p: Process | some p.(s.waits) 105 | } 106 | 107 | assert DijkstraPreventsDeadlocks { 108 | GrabOrRelease => ! Deadlock 109 | } 110 | 111 | 112 | pred ShowDijkstra { 113 | GrabOrRelease && Deadlock 114 | some waits 115 | } 116 | 117 | run Deadlock for 3 expect 1 118 | run ShowDijkstra for 5 State, 2 Process, 2 Mutex expect 1 119 | check DijkstraPreventsDeadlocks for 5 State, 5 Process, 4 Mutex expect 0 120 | -------------------------------------------------------------------------------- /algorithms/mutex/peterson.als: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Model of Peterson's algorithm for mutual exclusion of n 4 | * processes. The names kept similar to Murphi specification 5 | * to make correspondence clear. 6 | */ 7 | 8 | open util/ordering[priority] as po 9 | open util/ordering[State] as so 10 | 11 | sig pid { 12 | } 13 | 14 | sig priority { 15 | } 16 | 17 | fact { 18 | # priority = # pid + 1 19 | } 20 | 21 | abstract sig label_t {} 22 | 23 | // here subtyping would help 24 | one sig L0, L1, L2, L3, L4 extends label_t {} 25 | 26 | sig State { 27 | P: pid -> label_t, 28 | Q: pid -> priority, 29 | turn: priority -> pid, 30 | localj: pid -> priority 31 | } 32 | 33 | pred NOPTrans[i: pid, pre, post : State] { 34 | post.P[i] = pre.P[i] 35 | post.Q[i] = pre.Q[i] 36 | post.localj[i] = pre.localj[i] 37 | } 38 | 39 | pred L0TransPre[i : pid, pre : State] { 40 | // precondition 41 | pre.P[i] = L0 42 | } 43 | 44 | pred L0Trans[i: pid, pre, post : State] { 45 | L0TransPre[i, pre] 46 | // localj[i] := 1 47 | post.localj[i] = po/next[po/first] 48 | post.P[i] = L1 49 | post.Q[i] = pre.Q[i] 50 | // something for turn? 51 | post.turn = pre.turn 52 | } 53 | 54 | pred L1TransPre[i : pid, pre : State] { 55 | // precondition 56 | pre.P[i] = L1 57 | } 58 | 59 | pred L1Trans[i : pid, pre, post : State] { 60 | L1TransPre[i, pre] 61 | post.localj[i] = pre.localj[i] 62 | post.Q[i] = pre.localj[i] 63 | post.P[i] = L2 64 | // something for turn? 65 | post.turn = pre.turn 66 | } 67 | 68 | pred L2TransPre[i : pid, pre : State] { 69 | // precondition 70 | pre.P[i] = L2 71 | } 72 | 73 | pred L2Trans[i : pid, pre, post : State] { 74 | L2TransPre[i, pre] 75 | post.localj[i] = pre.localj[i] 76 | post.Q[i] = pre.Q[i] 77 | post.P[i] = L3 78 | post.turn[post.localj[i]] = i 79 | all j : priority - post.localj[i] | 80 | post.turn[j] = pre.turn[j] 81 | } 82 | 83 | pred L3TransPre[i : pid, pre : State] { 84 | // precondition 85 | pre.P[i] = L3 86 | 87 | all k : pid - i | 88 | po/lt[pre.Q[k], pre.localj[i]] || 89 | pre.turn[pre.localj[i]] != i 90 | } 91 | 92 | pred L3Trans[i : pid, pre, post : State] { 93 | L3TransPre[i, pre] 94 | post.localj[i] = po/next[pre.localj[i]] 95 | po/lt[post.localj[i], po/last] => 96 | post.P[i] = L1 97 | else 98 | post.P[i] = L4 99 | post.Q[i] = pre.Q[i] 100 | post.turn = pre.turn 101 | } 102 | 103 | pred L4TransPre[i : pid, pre : State] { 104 | // precondition 105 | pre.P[i] = L4 106 | } 107 | 108 | pred L4Trans[i : pid, pre, post : State] { 109 | L4TransPre[i, pre] 110 | 111 | post.P[i] = L0 112 | post.Q[i] = po/first 113 | post.localj[i] = pre.localj[i] 114 | post.turn = pre.turn 115 | } 116 | 117 | pred RealTrans[i : pid, pre, post : State] { 118 | L0Trans[i,pre,post] || 119 | L1Trans[i,pre,post] || 120 | L2Trans[i,pre,post] || 121 | L3Trans[i,pre,post] || 122 | L4Trans[i,pre,post] 123 | } 124 | 125 | pred SomePre[i : pid, pre : State] { 126 | L0TransPre[i, pre] || 127 | L1TransPre[i, pre] || 128 | L2TransPre[i, pre] || 129 | L3TransPre[i, pre] || 130 | L4TransPre[i, pre] 131 | } 132 | 133 | fact Init { 134 | let firstState = so/first | { 135 | all i : pid | { 136 | firstState.P[i] = L0 137 | firstState.Q[i] = po/first 138 | } 139 | no firstState.turn 140 | no firstState.localj 141 | } 142 | } 143 | 144 | fact LegalTrans { 145 | all pre : State - so/last | 146 | let post = so/next[pre] | { 147 | /*some i : pid | { 148 | // HACK: 149 | // need to specify that if some node 150 | // can make a non-NOP transition, it 151 | // does, but i can't figure out how 152 | // right now 153 | Trans(i,pre,post) && !NOPTrans(i,pre,post) 154 | all j : pid - i | 155 | NOPTrans(j,pre,post) 156 | }*/ 157 | all i : pid | 158 | RealTrans[i,pre,post] || NOPTrans[i,pre,post] 159 | (all i : pid | NOPTrans[i,pre,post]) => { 160 | all i : pid | !SomePre[i,pre] 161 | post.turn = pre.turn 162 | } 163 | } 164 | } 165 | 166 | assert Safety { 167 | all i1, i2 : pid, s : State | i1!=i2 => not (s.P[i1] = L4 && s.P[i2] = L4) 168 | } 169 | 170 | assert NotStuck { 171 | all pre : State - so/last | 172 | let post = so/next[pre] | 173 | some i : pid | 174 | RealTrans[i, pre, post] && !NOPTrans[i,pre,post] 175 | } 176 | 177 | pred TwoRun { 178 | some s1, s2: State, i1, i2: pid | { 179 | s1!=s2 180 | i1!=i2 181 | s1.P[i1] = L4 182 | s2.P[i2] = L4 183 | } 184 | } 185 | 186 | pred ThreeRun { 187 | some disj s1, s2, s3: State, disj i1, i2, i3: pid | { 188 | s1.P[i1] = L4 189 | s2.P[i2] = L4 190 | s3.P[i3] = L4 191 | } 192 | } 193 | 194 | // 2 pids requires 8 states 195 | // 3 pids requires 16 states 196 | run TwoRun for 13 but 3 pid, 4 priority, 5 label_t expect 1 197 | 198 | // haven't run this one successfully yet 199 | run ThreeRun for 19 but 3 pid,4 priority,5 label_t expect 1 200 | 201 | // how many states do we need for this to match murphi? 202 | check Safety for 10 but 2 pid, 3 priority, 5 label_t expect 0 203 | 204 | // this assertion is trivial because of the hack described above 205 | check NotStuck for 10 but 2 pid, 3 priority, 5 label_t expect 0 206 | -------------------------------------------------------------------------------- /algorithms/ring-orientation/stable-orient-ring.als: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * A self-stabilizing algorithm for orienting uniform rings. 4 | * Communication model is the state-reading model. 5 | */ 6 | 7 | open util/boolean as bool 8 | open util/ordering[Tick] as ord 9 | open util/graph[Process] as graph 10 | 11 | sig Process { 12 | rightNeighbor: Process, 13 | AP1, AP2: Process 14 | } 15 | 16 | fun leftNeighbor[p: Process]: Process { 17 | p.~(rightNeighbor) 18 | } 19 | 20 | fact { 21 | all p: Process { 22 | (p.AP1=p.rightNeighbor && p.AP2=leftNeighbor[p]) || 23 | (p.AP2=p.rightNeighbor && p.AP1=leftNeighbor[p]) 24 | } 25 | } 26 | 27 | fact DefineRing { 28 | graph/ring[rightNeighbor] 29 | } 30 | 31 | sig Tick { 32 | runs: set Process, 33 | dir, S, T: Process -> one Bool, 34 | ring_: Process -> Process 35 | } 36 | { 37 | all p: Process | p.ring_ = (p.dir=True => p.AP1 else p.AP2) 38 | } 39 | 40 | pred Eq3[b1,b2,b3: Bool] { b1 = b2 && b2 = b3 } 41 | pred Eq4[b1,b2,b3,b4: Bool] { Eq3[b1,b2,b3] && b3=b4 } 42 | 43 | fact Transitions { 44 | all tp: Tick - ord/last | let tn = ord/next[tp] | 45 | all p: Process | 46 | let p1 = p.AP1, p2 = p.AP2, pS = tp.S, pT=tp.T, nS=tn.S, nT=tn.T | 47 | let S1p=p1.pS, S2p=p2.pS, 48 | T1p=p1.pT, T2p=p2.pT, 49 | Sp = p.pS, Sn=p.nS, 50 | Tp = p.pT, Tn=p.nT, 51 | dirp = p.(tp.dir), dirn = p.(tn.dir) | { 52 | p !in tp.runs => ( Sn = Sp && Tn = Tp && dirn = dirp ) else ( 53 | S1p = S2p => ( Sn = Not[S1p] && Tn = True && dirn=dirp) else ( 54 | (Eq3[S1p, Sp, Not[S2p]] && 55 | Eq4[Not[T1p],Tp,T2p,True]) => 56 | (Sn = Not[Sp] && Tn = False && dirn = True) 57 | else ( 58 | (Eq3[Not[S1p],Sp,S2p] && Eq4[T1p,Tp,Not[T2p],True]) => 59 | (Sn = Not[Sp] && Tn = False && dirn = False) else ( 60 | ((Eq3[S1p,Sp,Not[S2p]] && T1p=Tp) || 61 | (Eq3[Not[S1p],Sp,S2p] && Tp=T2p)) => 62 | (Tn = Not[Tp] && Sn=Sp && dirn=dirp) else ( 63 | Sn=Sp && Tn=Tp && dirn=dirp 64 | ) 65 | ) 66 | ) 67 | ) 68 | ) 69 | } 70 | } 71 | 72 | pred RingAtTick[t: Tick] { 73 | let rng = t.ring_ | 74 | graph/ring[rng] || graph/ring[~rng] 75 | } 76 | 77 | assert Closure { 78 | // if the ring is properly oriented 79 | all t: Tick - ord/last | 80 | RingAtTick[t] => RingAtTick[ord/next[t]] 81 | } 82 | 83 | pred SomeState { 84 | !graph/ring[ord/first.ring_] 85 | some t: Tick | graph/ring[t.ring_] 86 | } 87 | 88 | run SomeState for 1 but 2 Tick, 2 Bool, 3 Process expect 1 89 | check Closure for 1 but 2 Tick, 2 Bool, 3 Process expect 1 90 | -------------------------------------------------------------------------------- /algorithms/synchronisation/sync.als: -------------------------------------------------------------------------------- 1 | /* 2 | * Model of a generic file synchronizer. 3 | * 4 | * Adapted from: 5 | * Reference: S. Balasubramaniam and Benjamin C. Pierce, 6 | * "What is a File Synchronizer", Indiana University CSCI 7 | * Technical Report #507, April 22, 1998 8 | * 9 | * author: Tina Nolte 10 | */ 11 | 12 | private open util/graph[Name] as graph 13 | 14 | /** 15 | * The Name atom represents the hierarchy of all name sequences 16 | * used in the model. A Name atom represents the name, and the path 17 | * in the sequence of names to the root excluding the RootName. 18 | */ 19 | sig Name { 20 | children: set Name 21 | } 22 | 23 | fact { graph/tree[children] } 24 | 25 | one sig RootName extends Name { } 26 | 27 | fact { Name in RootName.*children } 28 | 29 | // We assume that the empty path always 30 | 31 | sig FileContents { } 32 | one sig Dir extends FileContents { } 33 | 34 | pred IsValidFS[fs: Name -> lone FileContents] { 35 | all n: Name - RootName | { 36 | // files don't have children 37 | n.fs != Dir => no (n.^children).fs 38 | // if a path maps to something non-nil, all prefixes do also 39 | some n.fs => some (n.~children).fs 40 | } 41 | // the root of a file system must be a directory 42 | RootName.fs = Dir 43 | } 44 | 45 | pred IsValidDirty[dirty: set Name] { 46 | all n: dirty | n.~children in dirty 47 | RootName in dirty => some dirty - RootName 48 | } 49 | 50 | pred DirtiesValid[A, B: Name -> lone FileContents, Adirty, Bdirty: set Name] { 51 | some O: Name -> lone FileContents | { 52 | IsValidFS[O] 53 | { n: Name | n.O != n.A } in Adirty 54 | { n: Name | n.O != n.B } in Bdirty 55 | } 56 | } 57 | 58 | fun RestrictFS[fs: Name -> lone FileContents, p: Name]: Name -> lone FileContents { 59 | fs & (p.*children -> FileContents) 60 | } 61 | 62 | fun RestrictFSComplement[fs: Name -> lone FileContents, p: Name]: Name -> lone FileContents { 63 | fs & ((Name - p.*children) -> FileContents) 64 | } 65 | 66 | /** 67 | * The following function test whether a particular synchronizer 68 | * operation satisfies the "reasonableness" conditions. 69 | * The arguments are: 70 | * O - the original filesystem. 71 | * A,B - separately modified copies 72 | * Adirty, Bdirty - sets of paths modified in A and B, respectively, from O. 73 | * 74 | * A",B" - results of synchronizer operation 75 | */ 76 | pred SyncSpec[A, B, A", B": Name -> lone FileContents, Adirty, Bdirty: set Name] { 77 | { 78 | IsValidFS[A] 79 | IsValidFS[B] 80 | IsValidDirty[Adirty] 81 | IsValidDirty[Bdirty] 82 | } => { 83 | { 84 | all p: Name | IsRelevantPath[p, A, B] => { 85 | SyncSpecForPath[p, A, B, A", B", Adirty, Bdirty] 86 | } 87 | } 88 | IsValidFS[A"] 89 | IsValidFS[B"] 90 | } 91 | } 92 | 93 | pred SyncSpecForPath[p: Name, A, B, A", B": Name -> lone FileContents, Adirty, Bdirty: set Name] { 94 | (p.A = p.B => (p.A" = p.A && p.B" = p.B)) 95 | (p !in Adirty => (RestrictFS[A", p] = RestrictFS[B, p] && RestrictFS[B", p] = RestrictFS[B, p])) 96 | (p !in Bdirty => (RestrictFS[B", p] = RestrictFS[A, p] && RestrictFS[A", p] = RestrictFS[A, p])) 97 | ((p in Adirty && p in Bdirty && p.A != p.B) => (RestrictFS[A",p] = RestrictFS[A,p] && RestrictFS[B",p] = RestrictFS[B,p])) 98 | } 99 | 100 | pred IsRelevantPath[p: Name, A, B: Name -> lone FileContents] { 101 | p = RootName || { 102 | (p.~children).A = Dir 103 | (p.~children).B = Dir 104 | } 105 | } 106 | 107 | pred SyncSpecExample[A, B, A", B": Name -> lone FileContents, Adirty, Bdirty: set Name] { 108 | IsValidFS[A] 109 | IsValidFS[B] 110 | IsValidDirty[Adirty] 111 | IsValidDirty[Bdirty] 112 | SyncSpec[A, B, A", B", Adirty, Bdirty] 113 | A != A" 114 | } 115 | 116 | //run SyncSpecExample for 3 117 | 118 | pred SyncSpecNotUnique { 119 | some A, B, A1", B1", A2", B2": Name -> lone FileContents, Adirty, Bdirty: set Name | { 120 | IsValidFS[A] && IsValidFS[B] 121 | IsValidDirty[Adirty] && IsValidDirty[Bdirty] 122 | //DirtiesValid(A, B, Adirty, Bdirty) 123 | (A1" != A2" || B1" != B2") 124 | SyncSpec[A, B, A1", B1", Adirty, Bdirty] 125 | SyncSpec[A, B, A2", B2", Adirty, Bdirty] 126 | } 127 | } 128 | 129 | run SyncSpecNotUnique for 5 expect 0 130 | -------------------------------------------------------------------------------- /algorithms/synchronisation/syncimpl.als: -------------------------------------------------------------------------------- 1 | /* 2 | * Model of a file synchronizer reconciliation algorithm. 3 | * 4 | * Adapted from: 5 | * Reference: S. Balasubramaniam and Benjamin C. Pierce, 6 | * "What is a File Synchronizer", Indiana University CSCI 7 | * Technical Report #507, April 22, 1998 8 | * 9 | * author: Tina Nolte 10 | */ 11 | 12 | open sync as sync 13 | open util/ordering[sync/Name] as ord 14 | open util/relation as rel 15 | 16 | // Model the reconciliation algorithm 17 | 18 | sig ReconName extends Name { 19 | Ain, Bin, Aout, Bout: Name->FileContents, 20 | p_children: set Name, 21 | first_p_child, last_p_child: lone Name, 22 | prev_p_child: (p_children - first_p_child) -> p_children 23 | } 24 | 25 | fact { 26 | all x: ReconName { 27 | x.p_children = ChildrenAB[x.Ain, x.Bin, x] 28 | x.first_p_child = { pc: x.p_children | x.p_children in (pc + nexts[pc]) } 29 | x.last_p_child = { pc: x.p_children | x.p_children in (pc + prevs[pc]) } 30 | all p_child: x.p_children - x.first_p_child | { 31 | let earlierChildren = prevs[p_child] & x.p_children | 32 | p_child . (x.prev_p_child) = { earlierChild: earlierChildren | earlierChildren in (earlierChild + @prevs[earlierChild]) } 33 | } 34 | } 35 | } 36 | 37 | fact { ReconName = Name } 38 | 39 | fun ChildrenAB[A, B: Name -> lone FileContents, p: Name]: set Name { 40 | p.children & (dom[A] + dom[B]) 41 | } 42 | 43 | pred reconHelper[Adirty, Bdirty: set Name] { 44 | all p: Name { 45 | let A = p.Ain, B = p.Bin, A" = p.Aout, B" = p.Bout | { 46 | some p.(A+B) => { 47 | (p !in Adirty && p !in Bdirty) => (A" = A && B" = B) else { 48 | (p.A = Dir && p.B = Dir) => { 49 | no p_children => { 50 | p.Aout = p.Ain 51 | p.Bout = p.Bin 52 | } else { 53 | p.first_p_child.Ain = p.Ain 54 | p.first_p_child.Bin = p.Bin 55 | p.Aout = p.last_p_child.Aout 56 | p.Bout = p.last_p_child.Bout 57 | all pchild: p.p_children - p.first_p_child | { 58 | pchild.Ain = (pchild.(p.prev_p_child)).Aout 59 | pchild.Bin = (pchild.(p.prev_p_child)).Bout 60 | } 61 | } // some p_children 62 | } else { // !(p.A = Dir && p.B = Dir) 63 | p !in Adirty => { 64 | A" = RestrictFS[B, p] + RestrictFSComplement[A, p] 65 | B" = B 66 | } else { 67 | p !in Bdirty => { 68 | A" = A 69 | B" = RestrictFS[A, p] + RestrictFSComplement[B, p] 70 | } else { 71 | A" = A 72 | B" = B 73 | } 74 | } // not "p !in Adirty" 75 | } // not case 2 i.e. not both are dirs 76 | } // not both clean 77 | } // some p.(A+B) 78 | } // let A =, B=, A"=, B"= 79 | } // all p: Name 80 | } // reconHelper() 81 | 82 | pred recon[A, B, A", B": Name -> lone FileContents, Adirty, Bdirty: set Name] { 83 | A = ReconName.Ain 84 | B = ReconName.Bin 85 | A" = ReconName.Aout 86 | B" = ReconName.Bout 87 | reconHelper[Adirty, Bdirty] 88 | } 89 | 90 | assert Correctness { 91 | all A, B, A", B": Name -> lone FileContents, Adirty, Bdirty: set Name | { 92 | { 93 | DirtiesValid[A, B, Adirty, Bdirty] 94 | recon[A, B, A", B", Adirty, Bdirty] 95 | //no Adirty + Bdirty 96 | } 97 | => 98 | SyncSpec[A, B, A", B", Adirty, Bdirty] 99 | } 100 | } 101 | 102 | check Correctness for 4 but 2 FileContents expect 0 103 | -------------------------------------------------------------------------------- /ietf-rfcs/rfc7617-BasicAuth/basic-auth.als: -------------------------------------------------------------------------------- 1 | 2 | // https://tools.ietf.org/html/rfc7617 Basic Authentication 3 | 4 | 5 | sig BasicChallenge extends Challenge { 6 | realm : Realm, 7 | charset : lone Charset 8 | } { 9 | name = "Basic" 10 | (RealmParameter & parameters).realm = Realm 11 | one charset implies (CharsetParameter & parameters).charset = charset 12 | } 13 | 14 | 15 | sig BasicCredentials extends Credentials { 16 | user_id : String, 17 | password : String, 18 | charset : lone Charset 19 | } { 20 | name = "Basic" 21 | let s = user_id.cat[":"].cat[password], 22 | c = one charset implies charset else OTHER_CHARSET, 23 | p = (Token68Parameter & parameters ){ 24 | 25 | p.value = c.binary[s] 26 | 27 | } 28 | } 29 | 30 | fun String.cat[ other : String ] : String { 31 | other // wrong! but cannot concatenate 32 | } 33 | 34 | // https://tools.ietf.org/html/rfc7235 Authentication 35 | 36 | one sig SC_UNAUTHORIZED_401 extends ResponseCode {} 37 | 38 | 39 | sig AuthorizationServer extends Server { 40 | protectionSpaces : set Realm 41 | } 42 | 43 | abstract sig Challenge extends AuthScheme {} 44 | abstract sig Credentials extends AuthScheme {} 45 | 46 | 47 | sig WWWAuthenticate extends Header { 48 | challenges : seq Challenge 49 | } { 50 | name = "WWW-Authenticate" 51 | some challenges 52 | } 53 | 54 | sig Authorization extends Header { 55 | credentials : Credentials 56 | } { 57 | name = "Authorization" 58 | } 59 | 60 | abstract sig AuthScheme { 61 | name : String, 62 | parameters : set Parameter 63 | } { 64 | some (Token68Parameter & parameters) implies one parameters 65 | } 66 | 67 | abstract sig Parameter { 68 | } 69 | 70 | sig Binary { 71 | } 72 | 73 | abstract sig Token68Parameter extends Parameter { 74 | value : Binary 75 | } 76 | 77 | abstract sig AuthParam extends Parameter { 78 | name : String 79 | } 80 | 81 | sig Realm {} 82 | 83 | sig RealmParameter extends AuthParam { 84 | realm : Realm 85 | } { 86 | name = "realm" 87 | } 88 | 89 | abstract sig Charset { 90 | maps : String -> Binary 91 | } 92 | 93 | fun Charset.binary[ s : String ] : Binary { 94 | this.maps[s] 95 | } 96 | 97 | 98 | 99 | one sig ASCII extends Charset {} 100 | one sig ISO8859 extends Charset {} 101 | one sig UTF16 extends Charset {} 102 | one sig UTF8 extends Charset {} 103 | one sig OTHER_CHARSET extends Charset {} 104 | 105 | sig CharsetParameter extends AuthParam { 106 | charset : Charset 107 | } { 108 | name = "charset" 109 | } 110 | 111 | 112 | fact WWWAuthenticateChallengeResponse { 113 | all r : HttpResponse | 114 | r.response = SC_UNAUTHORIZED_401 implies some (r.headers.elems & WWWAuthenticate ) 115 | } 116 | 117 | 118 | // https://tools.ietf.org/html/rfc7230 (HTTP 1.1) and further 119 | 120 | sig Server {} 121 | 122 | 123 | sig Path {} 124 | one sig EmptyPath extends Path { 125 | } 126 | 127 | sig URI { 128 | host : Server, 129 | path : Path 130 | } 131 | 132 | enum Method { GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD } 133 | 134 | enum ResponseCode { 135 | SC_OK_200, SC_NOT_FOUND_404, SC_TEMP_REDIRECT_302 136 | } 137 | 138 | abstract sig Body {} 139 | 140 | 141 | sig HttpRequest { 142 | method : Method, 143 | url : URI, 144 | headers : seq Header, 145 | body : lone Body 146 | } 147 | 148 | sig HttpResponse { 149 | response : ResponseCode, 150 | headers : seq Header, 151 | payload : lone Body, 152 | } 153 | 154 | 155 | abstract sig Header { 156 | name : String 157 | } 158 | 159 | 160 | fact fixup { 161 | all a : Authorization | a in HttpRequest.headers.elems 162 | all a : WWWAuthenticate | a in HttpResponse.headers.elems 163 | all b : Credentials | b in Authorization.credentials 164 | all b : Challenge | b in WWWAuthenticate.challenges.elems 165 | all b : Body | lone r : HttpRequest | r.body = b 166 | } 167 | 168 | run {} for 3 169 | -------------------------------------------------------------------------------- /logic/syllogism/syllogism.als: -------------------------------------------------------------------------------- 1 | /** 2 | * Syllogism (Greek: συλλογισμός syllogismos, 3 | * "conclusion, inference") is a kind of logical argument 4 | * that applies deductive reasoning to arrive at a 5 | * conclusion based on two or more propositions that 6 | * are asserted or assumed to be true. 7 | * 8 | * In its earliest form, defined by Aristotle, from the 9 | * combination of a general statement (the major premise) 10 | * and a specific statement (the minor premise), a conclusion 11 | * is deduced. 12 | * 13 | * For example, knowing that all men are mortal (major premise) 14 | * and that Socrates is a man (minor premise), we may validly 15 | * conclude that Socrates is mortal. Syllogistic arguments 16 | * are usually represented in a three-line form: 17 | * 18 | * All men are mortal. 19 | * Socrates is a man. 20 | * Therefore Socrates is mortal. 21 | */ 22 | 23 | sig Men{} 24 | one sig Socrates {} 25 | 26 | check { 27 | 28 | all mortal, men : some Men + Socrates { 29 | 30 | men in mortal 31 | and 32 | Socrates in men 33 | => Socrates in mortal 34 | 35 | } 36 | } for 5 Men 37 | 38 | /** 39 | * This is very error prone since the following is not correct: 40 | * 41 | * All men are mortal. 42 | * Socrates is a mortal. 43 | * Therefore Socrates is a man. 44 | * 45 | * Running the following example will therefore fail 46 | */ 47 | 48 | check { 49 | 50 | all mortal, men : some Men + Socrates { 51 | 52 | men in mortal 53 | and 54 | Socrates in mortal 55 | => Socrates in men 56 | 57 | } 58 | } for 5 Men 59 | -------------------------------------------------------------------------------- /models/file-system/file_system.als: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Model of a generic file system. 4 | */ 5 | 6 | abstract sig Object {} 7 | 8 | sig Name {} 9 | 10 | sig File extends Object {} { some d: Dir | this in d.entries.contents } 11 | 12 | sig Dir extends Object { 13 | entries: set DirEntry, 14 | parent: lone Dir 15 | } { 16 | parent = this.~@contents.~@entries 17 | all e1, e2 : entries | e1.name = e2.name => e1 = e2 18 | this !in this.^@parent 19 | this != Root => Root in this.^@parent 20 | } 21 | 22 | one sig Root extends Dir {} { no parent } 23 | 24 | lone sig Cur extends Dir {} 25 | 26 | sig DirEntry { 27 | name: Name, 28 | contents: Object 29 | } { 30 | one this.~entries 31 | } 32 | 33 | 34 | /** 35 | * all directories besides root have one parent 36 | */ 37 | pred OneParent_buggyVersion { 38 | all d: Dir - Root | one d.parent 39 | } 40 | 41 | /** 42 | * all directories besides root have one parent 43 | */ 44 | pred OneParent_correctVersion { 45 | all d: Dir - Root | (one d.parent && one contents.d) 46 | } 47 | 48 | /** 49 | * Only files may be linked (that is, have more than one entry) 50 | * That is, all directories are the contents of at most one directory entry 51 | */ 52 | pred NoDirAliases { 53 | all o: Dir | lone o.~contents 54 | } 55 | 56 | check { OneParent_buggyVersion => NoDirAliases } for 5 expect 1 57 | 58 | check { OneParent_correctVersion => NoDirAliases } for 5 expect 0 59 | -------------------------------------------------------------------------------- /models/java/java-map.als: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | A partial formal definition of a Map in Java 4 | 5 | See http://aqute.biz/2017/07/15/Alloy.html 6 | */ 7 | 8 | 9 | sig Object {} 10 | one sig null extends Object {} 11 | enum boolean { true, false } 12 | 13 | sig Map { 14 | entries : Object -> lone Object 15 | } 16 | 17 | fun Map.size : Int { 18 | # this.entries 19 | } 20 | 21 | pred Map.isEmpty { 22 | no entries 23 | } 24 | 25 | pred Map.containsKey( k : Object ) { 26 | one this.entries[k] 27 | } 28 | 29 | 30 | pred Map.containsValue( v : Object ) { 31 | one this.entries.v 32 | } 33 | 34 | fun Map.get( k : Object ) : Object { 35 | let v = this.entries[k] | one v implies v else null 36 | } 37 | 38 | pred Map.put( m" : Map, k, v, r : Object ) { 39 | this.get[k] = r 40 | m".entries = this.entries ++ k -> v 41 | } 42 | 43 | pred Map.remove( m" : Map, k, r: Object ) { 44 | this.containsKey[k] 45 | implies { 46 | m".entries = this.entries - k->Object 47 | and this.get[k] = r 48 | } else { 49 | r = null 50 | m".entries = this.entries 51 | } 52 | } 53 | 54 | pred Map.putAll( m", other : Map ) { 55 | m".entries = this.entries ++ other.entries 56 | } 57 | 58 | fun Map.keySet : set Object { 59 | this.entries.Object 60 | } 61 | 62 | fun Map.values : set Object { 63 | this.entries[Object] 64 | } 65 | 66 | pred Map.clear( m" : Map ) { 67 | m".isEmpty 68 | } 69 | 70 | fun Map.entrySet : Object -> Object { 71 | this.entries 72 | } 73 | 74 | pred equals( a,b : Map ) { 75 | a.keySet = b.keySet 76 | all k : a.keySet | a.get[k] = b.get[k] 77 | } 78 | 79 | pred Map.putIfAbsent( m" : Map, k, initial, r : Object ) { 80 | this.containsKey[k] 81 | implies r = this.get[k] 82 | else ( r=null and this.put[m",k,initial,null]) 83 | } 84 | 85 | pred Map.remove( m" : Map, k, v : Object, r : boolean ) { 86 | k -> v in this.entries 87 | implies ( m".entries = this.entries - k -> v 88 | and r = true ) 89 | else r=false 90 | } 91 | 92 | pred Map.replace( m" : Map, k, oldValue, newValue : Object, r : boolean ) { 93 | this.put[m",k,newValue,oldValue] implies r = true else r = false 94 | } 95 | 96 | /* 97 | * Replaces the entry for the specified key only if it is 98 | * currently mapped to some value. 99 | */ 100 | 101 | pred Map.replace( m" : Map, k, v, r : Object ) { 102 | this.containsKey[k] implies this.put[m",k,v,r] else r = null 103 | } 104 | 105 | 106 | 107 | // Verifications 108 | 109 | pred Map.put"(m" : Map, k, v, r : Object ) { 110 | 111 | m".containsKey[k] 112 | m".get[k] = v 113 | this.get[k] = r 114 | 115 | this.containsKey[k] 116 | implies { 117 | this.size = m".size 118 | 119 | r = null or r != null 120 | } else { 121 | this.size.plus[1] = m".size 122 | r = null 123 | } 124 | } 125 | 126 | pred Map.clear"[ m" : Map ] { 127 | m".size = 0 128 | all k : Object | { 129 | m".get[k] = null 130 | not m".containsKey[k] 131 | } 132 | } 133 | 134 | pred Map.remove"( m" : Map, k, r : Object) { 135 | not m".containsKey[k] 136 | 137 | this.containsKey[k] implies { 138 | this.get[k] = r 139 | this.size.minus[1] = m".size 140 | } else { 141 | r = null 142 | this.size = m".size 143 | } 144 | } 145 | 146 | pred Map.putAll"( m", other : Map ) { 147 | 148 | this.keySet + other.keySet = m".keySet 149 | 150 | all k : this.keySet + other.keySet | { 151 | let v = k in other.keySet 152 | implies other.get[k] 153 | else this.get[k] | { 154 | m".get[k] = v 155 | } 156 | } 157 | } 158 | 159 | assert verify { 160 | 161 | all m, m", other : Map, k, v, r : Object | { 162 | m.put[m", k, v, r ] implies m.put"[m",k,v,r] 163 | m.clear[m"] implies m.clear"[m"] 164 | m.remove[m",k, r] implies m.remove"[m",k,r] 165 | m.putAll[m",other] implies m.putAll"[m",other] 166 | } 167 | 168 | } 169 | 170 | check verify for 4 but 2 Map 171 | 172 | 173 | 174 | fact { 175 | # Map > 0 176 | } 177 | -------------------------------------------------------------------------------- /models/java/javatypes.als: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * A simple model of typing in Java. 5 | * 6 | * This model describes the basic notions of typing in Java. 7 | * It ignores primitive types and null references. Each type has 8 | * some set of subtypes. Types are partitioned into class and 9 | * interface types. Object is a particular class. 10 | * 11 | * The fact TypeHierarchy says that every type is a direct or 12 | * indirect subtype of Object; that no type is a direct or indirect 13 | * of itself; and every type is a subtype of at most one class. 14 | * 15 | * An object instance has a type (its creation type) that is a class. 16 | * A variable may hold an instance, and has a declared type. The 17 | * fact TypeSoundness says that all instances held by a variable 18 | * have types that are direct or indirect subtypes of the variable's 19 | * declared type. 20 | * 21 | * The function Show specifies a case in which there is a class 22 | * distinct from Object; there is some interface; and some variable 23 | * has a declared type that is an interface. 24 | * 25 | * author: Daniel Jackson, 11/13/01 26 | */ 27 | 28 | abstract sig Type {subtypes: set Type} 29 | sig Class, Interface extends Type {} 30 | one sig Object extends Class {} 31 | fact TypeHierarchy { 32 | Type in Object.*subtypes 33 | no t: Type | t in t.^subtypes 34 | all t: Type | lone t.~subtypes & Class 35 | } 36 | sig Instance {type: Class} 37 | sig Variable {holds: lone Instance, type: Type} 38 | fact TypeSoundness { 39 | all v: Variable | v.holds.type in v.type.*subtypes 40 | } 41 | pred Show { 42 | some Class - Object 43 | some Interface 44 | some Variable.type & Interface 45 | } 46 | run Show for 3 expect 1 47 | -------------------------------------------------------------------------------- /models/java/javatypes_soundness.als: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Model of the Java type system. The TypeSoundness assertion 4 | * claims that if a Java program type checks successfully, 5 | * then a field will cannot be assigned an incorrect type. 6 | * 7 | * author: Daniel Jackson 8 | */ 9 | 10 | open util/graph[Type] as graph 11 | 12 | abstract sig Type { 13 | xtends: set Type 14 | } 15 | sig Interface extends Type {} 16 | { xtends in Interface } 17 | sig Class extends Type { 18 | implements: set Interface, 19 | fields: set Field 20 | } { lone xtends && xtends in Class } 21 | -- optional: best omitted to allow private etc 22 | -- {xtends.@fields in fields} 23 | sig Field { 24 | declType: Type 25 | } 26 | 27 | fact { 28 | graph/dag[xtends] 29 | } 30 | 31 | abstract sig Value {} 32 | one sig Null extends Value {} 33 | sig Object extends Value { 34 | type: Class, 35 | slot: Field lone -> lone Slot 36 | } {slot.Slot = type.fields} 37 | sig Slot {} 38 | 39 | abstract sig Statement {} 40 | sig Assignment extends Statement { 41 | v: Variable, 42 | expr: Expr 43 | } 44 | sig Setter extends Statement { 45 | field: Field, 46 | lexpr, rexpr: Expr 47 | } 48 | 49 | abstract sig Expr { 50 | type: Type, 51 | subexprs: set Expr 52 | } {subexprs = this + this.^@expr} 53 | sig Variable extends Expr { 54 | declType: Type 55 | } {type = declType} 56 | sig Constructor extends Expr { 57 | class: Class 58 | } 59 | sig Getter extends Expr { 60 | field: Field, 61 | expr: Expr 62 | } {type = field.declType} 63 | 64 | sig State { 65 | objects: set Object, 66 | reaches: Object -> Object, 67 | vars: set Variable, 68 | holds: (Slot + Variable) -> lone Value, 69 | val: Expr -> lone Value 70 | } { 71 | all o: Object | o.reaches = holds[o.slot[Field]] & Object 72 | holds.Value & Variable = vars 73 | objects = holds[vars].^reaches 74 | all e: Expr | let v = val[e] { 75 | e in Variable => v = holds[e] 76 | e in Getter => v = holds[(val[e.expr]).slot[e.field]] 77 | e in Constructor => v in Object and v.type = e.type } 78 | } 79 | 80 | pred RuntimeTypesOK [s: State] { 81 | all o: s.objects, f: o.type.fields | 82 | let v = s.holds [o.slot [f]] | HasType [v, f.declType] 83 | all v: s.vars | 84 | let v = s.holds [v] | HasType [v, v.declType] 85 | } 86 | 87 | pred HasType [v: Value, t: Type] { 88 | v in Null or Subtype [v.type, t] 89 | } 90 | 91 | pred Subtype [t, t": Type] { 92 | t in Class => 93 | (let supers = (t & Class).*(Class<:xtends) | 94 | t" in (supers + supers.implements.*(Interface<:xtends))) 95 | t in Interface => t" in (t & Interface).*(Interface<:xtends) 96 | } 97 | 98 | pred TypeChecksSetter [stmt: Setter] { 99 | all g: Getter & stmt.(lexpr+rexpr).subexprs | g.field in g.expr.type.fields 100 | stmt.field in stmt.lexpr.type.fields 101 | Subtype [stmt.rexpr.type, stmt.field.declType] 102 | } 103 | 104 | pred ExecuteSetter [s, s": State, stmt: Setter] { 105 | stmt.(rexpr+lexpr).subexprs & Variable in s.vars 106 | s".objects = s.objects and s".vars = s.vars 107 | let rval = s.val [stmt.rexpr], lval = s.val [stmt.lexpr] { 108 | no lval & Null 109 | s".holds = s.holds ++ (lval.slot[stmt.field] -> rval) 110 | } 111 | } 112 | 113 | assert TypeSoundness { 114 | all s, s": State, stmt: Setter | 115 | {RuntimeTypesOK[s] 116 | ExecuteSetter [s, s", stmt] 117 | TypeChecksSetter[stmt] 118 | } => RuntimeTypesOK[s"] 119 | } 120 | 121 | fact {all o, o": Object | some o.slot[Field] & o".slot[Field] => o = o"} 122 | fact {all g: Getter | no g & g.^subexprs} 123 | 124 | fact ScopeFact { 125 | #Assignment =< 1 126 | #Class =< 5 127 | #Interface =< 5 128 | } 129 | 130 | check TypeSoundness for 3 expect 0 131 | 132 | check TypeSoundness for 2 State, 1 Assignment, 133 | 1 Statement, 5 Interface, 5 Class, 1 Null, 134 | 7 Object, 12 Expr, 3 Field, 3 Slot expect 0 135 | 136 | // very slow 137 | // check TypeSoundness for 2 State, 1 Statement, 138 | // 10 Type, 8 Value, 12 Expr, 139 | // 3 Field, 3 Slot expect 0 140 | -------------------------------------------------------------------------------- /models/logic/philosophers.als: -------------------------------------------------------------------------------- 1 | 2 | open util/ordering[Table] 3 | 4 | sig Table { 5 | setting : P -> Fork 6 | } 7 | 8 | 9 | sig Fork {} 10 | 11 | sig P { 12 | next : P, 13 | left, right : Fork 14 | } { 15 | right = next.@left 16 | } 17 | 18 | let update[table",settings"] = no table" or table".setting=settings" 19 | 20 | let take[ philosopher, fork, table, table"] { 21 | no table.setting.fork 22 | table".update[ table.setting + philosopher -> fork ] 23 | } 24 | 25 | let eat[ philosopher, table, table" ] { 26 | let forks = table.setting[philosopher] { 27 | # forks = 2 28 | table".update[ table.setting - philosopher->forks ] 29 | } 30 | } 31 | 32 | let wait[p,table,tableOrNone"] = { 33 | one tableOrNone" 34 | tableOrNone".setting = table.setting 35 | } 36 | 37 | pred step[ philosopher : P, table : Table, table" : lone Table ] { 38 | philosopher.take[ philosopher.left, table, table" ] 39 | or philosopher.take[ philosopher.right, table, table" ] 40 | or philosopher.eat[ table, table" ] 41 | or philosopher.wait[ table, table" ] 42 | 43 | } 44 | 45 | fact trace { 46 | ring[P] 47 | bijective[left] and bijective[right] 48 | 49 | no first.setting 50 | 51 | all table : Table - last | 52 | some p : P | p.step[ table, table.next ] 53 | } 54 | 55 | assert Liveliness { 56 | no table : Table | no philosopher : P | philosopher.step[table,none] 57 | } 58 | 59 | 60 | run { #P = 4 } for 4 61 | 62 | check Liveliness for 15 but exactly 4 P, 4 Fork, 4 int 63 | 64 | // macros 65 | 66 | let ring[group] = all member : group | member.^next = group 67 | let bijective[relation] = ( all d,r : univ | d.relation = r <=> relation.r = d ) 68 | let domain[ relation ] = relation.univ 69 | let range[ relation ] = univ.relation 70 | 71 | -------------------------------------------------------------------------------- /models/microsoft-com/com.als: -------------------------------------------------------------------------------- 1 | /* 2 | * Model of Microsoft Component Object Model (COM) query 3 | * interface and aggregation mechanism. 4 | * 5 | * For a detailed description, see: 6 | * "COM revisited: tool-assisted modelling of an architectural framework" 7 | * -- Daniel Jackson, Kevin Sullivan 8 | * 9 | * author: Daniel Jackson 10 | */ 11 | 12 | open util/relation as rel 13 | 14 | sig IID {} 15 | 16 | sig Interface { 17 | qi : IID -> lone Interface, 18 | iids : set IID, 19 | // next two lines should use domain() or range() functions 20 | iidsKnown : IID, 21 | reaches : Interface 22 | }{ 23 | iidsKnown = dom[qi] 24 | reaches = ran[qi] 25 | } 26 | 27 | sig Component { 28 | interfaces : set Interface, 29 | iids : set IID, // can't do iids = interfaces.Interface$iids 30 | first, identity : interfaces, 31 | eqs: set Component, 32 | aggregates : set Component 33 | } 34 | 35 | fact defineEqs { 36 | all c1, c2: Component | 37 | c1->c2 in eqs <=> c1.identity = c2.identity 38 | } 39 | 40 | fact IdentityAxiom { 41 | some unknown : IID | all c : Component | 42 | all i : c.interfaces | unknown.(i.qi) = c.identity 43 | } 44 | 45 | fact ComponentProps { 46 | all c : Component { 47 | c.iids = c.interfaces.iids 48 | all i : c.interfaces | all x : IID | x.(i.qi) in c.interfaces 49 | } 50 | } 51 | 52 | sig LegalInterface extends Interface { } 53 | fact { all i : LegalInterface | all x : i.iidsKnown | x in x.(i.qi).iids} 54 | 55 | sig LegalComponent extends Component { } 56 | fact { LegalComponent.interfaces in LegalInterface } 57 | 58 | fact Reflexivity { all i : LegalInterface | i.iids in i.iidsKnown } 59 | fact Symmetry { all i, j : LegalInterface | j in i.reaches => i.iids in j.iidsKnown } 60 | fact Transitivity { all i, j : LegalInterface | j in i.reaches => j.iidsKnown in i.iidsKnown } 61 | 62 | fact Aggregation { 63 | no c : Component | c in c.^aggregates 64 | all outer : Component | all inner : outer.aggregates | 65 | (some inner.interfaces & outer.interfaces) 66 | && (some o: outer.interfaces | all i: inner.interfaces - inner.first | all x: Component | (x.iids).(i.qi) = (x.iids).(o.qi)) 67 | } 68 | 69 | assert Theorem1 { 70 | all c: LegalComponent | all i: c.interfaces | i.iidsKnown = c.iids 71 | } 72 | 73 | assert Theorem2 { 74 | all outer: Component | all inner : outer.aggregates | 75 | inner in LegalComponent => inner.iids in outer.iids 76 | } 77 | 78 | assert Theorem3 { 79 | all outer: Component | all inner : outer.aggregates | inner in outer.eqs 80 | } 81 | 82 | assert Theorem4a { 83 | all c1: Component, c2: LegalComponent | 84 | some (c1.interfaces & c2.interfaces) => c2.iids in c1.iids 85 | } 86 | 87 | assert Theorem4b { 88 | all c1, c2: Component | some (c1.interfaces & c2.interfaces) => c1 in c2.eqs 89 | } 90 | 91 | check Theorem1 for 3 expect 0 92 | check Theorem2 for 3 expect 0 93 | check Theorem3 for 3 expect 0 94 | check Theorem4a for 3 expect 0 95 | check Theorem4b for 3 expect 0 96 | -------------------------------------------------------------------------------- /models/transport/railway.als: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * A simple model of a railway system. Trains sit on segments of tracks 4 | * and segments overlap one another. It shows a that simple gate policy 5 | * does not ensure train safety. 6 | * 7 | * author: Daniel Jackson 8 | */ 9 | 10 | sig Seg {next, overlaps: set Seg} 11 | fact {all s: Seg | s in s.overlaps} 12 | fact {all s1, s2: Seg | s1 in s2.overlaps => s2 in s1.overlaps} 13 | 14 | sig Train {} 15 | sig GateState {closed: set Seg} 16 | sig TrainState {on: Train -> lone Seg, occupied: set Seg} 17 | fact {all x: TrainState | 18 | x.occupied = {s: Seg | some t: Train | t.(x.on) = s} 19 | } 20 | 21 | pred Safe [x: TrainState] {all s: Seg | lone s.overlaps.~(x.on)} 22 | 23 | pred MayMove [g: GateState, x: TrainState, ts: set Train] { 24 | no ts.(x.on) & g.closed 25 | } 26 | 27 | pred TrainsMove [x, x": TrainState, ts: set Train] { 28 | all t: ts | t.(x".on) in t.(x.on).next 29 | all t: Train - ts | t.(x".on) = t.(x.on) 30 | } 31 | 32 | pred GatePolicy [g: GateState, x: TrainState] { 33 | x.occupied.overlaps.~next in g.closed 34 | all s1, s2: Seg | some s1.next.overlaps & s2.next => lone (s1+s2) - g.closed 35 | } 36 | 37 | assert PolicyWorks { 38 | all x, x": TrainState, g: GateState, ts: set Train | 39 | {MayMove [g, x, ts] 40 | TrainsMove [x, x", ts] 41 | Safe [x] 42 | GatePolicy [g, x] 43 | } => Safe [x"] 44 | } 45 | 46 | -- has counterexample in scope of 4 47 | check PolicyWorks for 2 Train, 1 GateState, 2 TrainState, 4 Seg expect 1 48 | 49 | pred TrainsMoveLegal [x, x": TrainState, g: GateState, ts: set Train] { 50 | TrainsMove [x, x", ts] 51 | MayMove [g, x, ts] 52 | GatePolicy [g, x] 53 | } 54 | run TrainsMoveLegal for 3 expect 1 55 | 56 | 57 | 58 | // DEFINED VARIABLES 59 | // Defined variables are uncalled, no-argument functions. 60 | // They are helpful for getting good visualization. 61 | fun contains [] : TrainState -> Seg -> Train { 62 | {state: TrainState, seg: Seg, train: Train | seg = train.(state.on)} 63 | } 64 | -------------------------------------------------------------------------------- /models/typography/paragraph-numbering.als: -------------------------------------------------------------------------------- 1 | /* 2 | * Alloy model of paragraph numbering 3 | * 4 | * This model addresses some issues that arose in the design of a text tagging tool. The 5 | * tool receives as input a text stream in which paragraphs are tagged with style names, 6 | * along with a style sheet that indicates how paragraphs of a given style are to be numbered. 7 | * In practice, the style sheet includes such details as what symbols to use for numbering (eg, 8 | * roman numericals, letters of the alphabet, etc), but these details are uninteresting. 9 | * 10 | * In the simplest case, the styles are organized into chains. For example, there may be a 11 | * single chain, chapter-section-subsection, so that chapters are numbered 1, 2, 3, etc, 12 | * sections are numbered 1.1, 1.2, 1.3, etc, and subsections are numbered 1.1.1, 1.1.2, 13 | * etc, each paragraph being numbered according to a number associated with its own 14 | * style, and a number for each ancestor. 15 | * 16 | * Some styles, however, should be numbered independently of one another, but still 17 | * according to the same ancestors. For example, we might also have a figure style 18 | * that is numbered, like section, according to its chapter, with figures and sections in 19 | * some arbitrary interleaving, the numbering of one not affecting the other. 20 | * 21 | * So in our style hierarchy, a style can have more than one "child". A more tricky complication 22 | * allows multiple parents. We might want to have an appendix style, for example, with a 23 | * different numbering from the chapter style, but would want section and subsection to work 24 | * within appendix exactly as they would work within chapter. So the first section in an 25 | * appendix numbered A might be numbered A.1, but if placed in a chapter numbered 1, 26 | * it would be numbered 1.1 instead. 27 | * 28 | * To account for this, styles are organized into replacement classes. Chapter and appendix, 29 | * for example, are replacements of one another. When a chapter style is encountered, it 30 | * is as if the style hierarchy contains only chapter, with children section, figure and so on; 31 | * when appendix is encountered subsequently, chapter is replaced, and figure and section 32 | * become children of appendix. We'll call the set of styles active in the tree at a given time 33 | * the "context". 34 | * 35 | * The first part focuses on the replacement mechanism. It characterizes a well-formed 36 | * style sheet (with the fact StyleSheet), and a well-formed state (with the fact Forest). An 37 | * operation addStyleToContext describes how the context is altered, and includes a 38 | * precondition requiring that, for example, a child is not encountered before its parents 39 | * (a document can't start with subsection, eg). The assertion PreservesForest checks that the 40 | * operation preserves the well-formedness of the state; it was analyzing this that helped 41 | * determine an appropriate precondition and the appropriate constraints in the invariant. 42 | * 43 | * The second part adds the numbering of styles. Note the idiom of declaring a subsignature 44 | * and then equating it to the supersignature, thus essentially retrofitting the new fields to the 45 | * old signature. A second operation describes how numbers are assigned; the conjunction of the 46 | * two operations is what happens when a style is encountered. The assertion AddNeverReduces 47 | * checks that when a style is encountered the number associated with each style in the context is 48 | * not decreased. The first assertion is valid; the second isn't. 49 | * 50 | * author: Daniel Jackson, 11/15/01 51 | */ 52 | 53 | open util/relation as rel 54 | 55 | sig Style { 56 | replaces, parents: set Style 57 | } 58 | 59 | fact StyleSheet { 60 | equivalence [replaces, Style] 61 | acyclic [parents, Style] 62 | all x: Style { 63 | x.replaces.parents.replaces = x.parents 64 | all y,z: x.parents | y in z.replaces 65 | } 66 | } 67 | 68 | sig State { 69 | context: set Style, 70 | ancestors: Style -> Style 71 | } 72 | 73 | fact DefineAncestors { 74 | all s: State, x: Style | s.ancestors [x] = x.*parents & s.context 75 | } 76 | 77 | pred Forest [s: State] { 78 | all x: s.context | 79 | some root: s.ancestors[x] { 80 | no root.parents 81 | all y: s.ancestors[x] - root | one y.parents & s.context 82 | } 83 | all x: Style | lone x.replaces & s.context 84 | } 85 | 86 | pred AddStyleToContext [s, s": State, style: Style] { 87 | all x: style.^parents | some x.replaces & s.context 88 | s".context = s.context - style.replaces + style 89 | } 90 | 91 | assert PreserveForest { 92 | all s,s": State, z: Style | 93 | Forest[s] && AddStyleToContext [s,s",z] => Forest[s"] 94 | } 95 | 96 | check PreserveForest for 4 expect 0 97 | 98 | sig Value {next: Value} 99 | sig NumberedStyle extends Style { 100 | initial: Value 101 | } 102 | sig NumberedState extends State { 103 | value: Style -> one Value 104 | } 105 | fact {Style = NumberedStyle} 106 | fact {State = NumberedState} 107 | 108 | pred AddStyleToNumbering [s, s": State, style: Style] { 109 | s".value[style] = (style in s.context => s.value[style].next else style.initial) 110 | s".context = s.context - style.replaces + style 111 | all x: Style - style | 112 | s".value[x] = (style in x.^parents => x.initial else s.value[x]) 113 | } 114 | 115 | pred AddStyle [s, s": State, style: Style] { 116 | AddStyleToContext [s,s",style] 117 | AddStyleToNumbering [s,s",style] 118 | } 119 | 120 | assert AddNeverReduces { 121 | all s,s": State, z: Style | 122 | Forest[s] && AddStyle [s,s",z] => 123 | (all y: s".context | s".value[y] in s.value[y].*next) 124 | } 125 | 126 | check AddNeverReduces for 5 expect 1 127 | 128 | -------------------------------------------------------------------------------- /paper-examples/jackson-cacm-2019/origin-tracking-meta.thm: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /paper-examples/jackson-cacm-2019/origin-tracking.als: -------------------------------------------------------------------------------- 1 | // Example from CACM 2019 paper by Jackson 2 | // Alloy: A Language and Tool for Exploring Software Designs 3 | // An exploration of an origin tracking mechanism to counter CSRF 4 | 5 | abstract sig EndPoint { } 6 | 7 | sig Server extends EndPoint { 8 | causes: set HTTPEvent 9 | } 10 | 11 | sig Client extends EndPoint { } 12 | 13 | abstract sig HTTPEvent { 14 | from, to, origin: EndPoint 15 | } 16 | 17 | sig Request extends HTTPEvent { 18 | response: lone Response 19 | } 20 | 21 | sig Response extends HTTPEvent { 22 | embeds: set Request 23 | } 24 | 25 | sig Redirect extends Response { 26 | } 27 | 28 | run {some response} 29 | 30 | fact Directions { 31 | Request.from + Response.to in Client 32 | Request.to + Response.from in Server 33 | } 34 | 35 | fact Causality { 36 | -- s causes e if 37 | -- e is (a response) from s, or 38 | -- e is (a request) embedded in r and s causes r 39 | all e: HTTPEvent, s: Server | 40 | e in s.causes iff e.from = s or some r: Response | e in r.embeds and r in s.causes 41 | } 42 | 43 | fact RequestResponse { 44 | -- time order of requests 45 | all r: Request | r not in r.^(response.embeds) 46 | -- every response comes from a single request 47 | all r: Response | one response.r 48 | 49 | all r: Response | r.to = response.r.from and r.from = response.r.to 50 | } 51 | 52 | fact Origin { 53 | // for a redirect, origin is same as request, else server 54 | all r: Response | r.origin = (r in Redirect implies response.r.origin else r.from) 55 | // embedded requests have the same origin as the response 56 | all r: Response, e: r.embeds | e.origin = r.origin 57 | // requests that are not embedded come from the client 58 | all r: Request | no embeds.r implies r.origin in r.from 59 | } 60 | 61 | pred obeysOrigins (s: Server) { 62 | // request is only accepted if origin is itself or sender 63 | all r: Request | r.to =s implies r.origin = r.to or r.origin = r.from 64 | } 65 | 66 | check { 67 | no good, bad: Server { 68 | no r: Request | r.to = bad and r.origin in Client 69 | good.obeysOrigins 70 | some r: Request | r.to = good and r in bad.causes 71 | } 72 | } for 5 73 | -------------------------------------------------------------------------------- /paper-examples/jackson-cacm-2019/origin-tracking.thm: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /puzzles/8-queens/queens.als: -------------------------------------------------------------------------------- 1 | // Queens are placed on boards. 2 | some sig Queen { } 3 | // The coordinates on the board. 4 | let positions = { i: Int, j: Int | 0 <= i && i <= 7 && 0 <= j && j <= 7 } 5 | // Each position can have at most one queen occupying it and each queen 6 | // has exactly one position assigned. 7 | one sig Board { queens: positions one -> lone Queen } 8 | // one sig Board { queens: Queen lone -> one positions } 9 | // Absolute value difference for comparing diagonal attack positions. 10 | fun absDifference(m: Int, n: Int): Int { 11 | let difference = minus[m, n] { 12 | difference > 0 => difference else minus[0, difference] 13 | } 14 | } 15 | // Attack relationship in terms of coordinates. 16 | pred attacks(q1: (Int -> Int), q2: (Int -> Int)) { 17 | let q1row = q1.univ, q1col = univ.q1, 18 | q2row = q2.univ, q2col = univ.q2, 19 | rowDifference = absDifference[q1row, q2row], 20 | colDifference = absDifference[q1col, q2col] { 21 | // Same row attacks 22 | rowDifference = 0 || 23 | // Same column attacks 24 | colDifference = 0 || 25 | // Diagonal attacks 26 | rowDifference = colDifference 27 | } 28 | } 29 | // Make sure no two queens attack each other. 30 | fact notAttacking { 31 | all q1, q2: Queen | q1 != q2 => !attacks[Board.queens.q1, Board.queens.q2] 32 | } 33 | // Make sure every queen is assigned a position on the board. I think this is 34 | // redundant and follows from Board signature 35 | // assert assignedPosition { all q: Queen | one Board.queens.q } 36 | // Run 37 | run { } for 1 Board, exactly 8 Queen 38 | -------------------------------------------------------------------------------- /puzzles/coloring/color-australia.als: -------------------------------------------------------------------------------- 1 | /** 2 | * Example constraint solving with Alloy 3 | * Solves the coloring problem for coloring Australia's states with 4 | * different colors. This problem was defined in miniZinc but I 5 | * think it looks better in Alloy 6 | */ 7 | 8 | 9 | sig Color {} 10 | enum State { wa, nt, q, sa, nsw, v, t } 11 | 12 | let adjacent = 13 | wa -> nt 14 | + wa -> sa 15 | + nt->sa 16 | + nt->q 17 | + sa->q 18 | + sa->nsw 19 | + sa-> v 20 | + q->nsw 21 | + nsw->v 22 | 23 | pred colors[ coloring : State -> one Color ] { 24 | all s : State, a : adjacent[s] | coloring[s] != coloring[a] 25 | } 26 | 27 | run colors for 1 but exactly 3 Color 28 | -------------------------------------------------------------------------------- /puzzles/einstein/einstein-wikipedia.als: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * See https://en.wikipedia.org/wiki/Zebra_Puzzle 4 | */ 5 | 6 | open util/ordering[House] 7 | 8 | 9 | enum Color { yellow, blue, red, ivory, green} 10 | enum Nationality {Norwegian, Ukrainian, Englishman, Spaniard, Japanese } 11 | enum Drink {water, tea,milk,juice,coffee} 12 | enum Smoke {Kools,Chesterfield,OldGold,LuckyStrike,Parliament} 13 | enum Pet {fox,horse,snails,dog,zebra} 14 | 15 | sig House { 16 | house : one Color, 17 | home : one Nationality, 18 | drunk : one Drink, 19 | smoker : one Smoke, 20 | owns : one Pet 21 | } 22 | 23 | 24 | fact disjunct { 25 | all disj h1, h2 : House | 26 | h1.house != h2.house and 27 | h1.home != h2.home and 28 | h1.drunk != h2.drunk and 29 | h1.smoker != h2.smoker and 30 | h1.owns != h2.owns 31 | } 32 | 33 | pred House.nextTo[ other : House ] { 34 | other in this.(prev+next) 35 | } 36 | 37 | let centerHouse = first.next.next 38 | 39 | fact { 40 | 41 | 42 | // There are five houses. 43 | 44 | # House = 5 45 | 46 | // The Englishman lives in the red house. 47 | Englishman.~home = red.~house 48 | 49 | // The Spaniard owns the dog. 50 | Spaniard.~home = owns.dog 51 | 52 | // Coffee is drunk in the green house. 53 | coffee.~drunk = green.~house 54 | 55 | // The Ukrainian drinks tea. 56 | Ukrainian.~home = drunk.tea 57 | 58 | // The green house is immediately to the right of the ivory house. 59 | green.~house = ivory.~house.next 60 | 61 | // The Old Gold smoker owns snails. 62 | OldGold.~smoker = owns.snails 63 | 64 | // Kools are smoked in the yellow house. 65 | Kools.~smoker = yellow.~house 66 | 67 | // Milk is drunk in the middle house. 68 | milk.~drunk = centerHouse 69 | 70 | // The Norwegian lives in the first house. 71 | Norwegian.~home = first 72 | 73 | // The man who smokes Chesterfields lives in the house next to the man with the fox. 74 | Chesterfield.~smoker.nextTo[ owns.fox ] 75 | 76 | // Kools are smoked in the house next to the house where the horse is kept. 77 | Kools.~smoker.nextTo[ owns.horse ] 78 | 79 | // The Lucky Strike smoker drinks orange juice. 80 | LuckyStrike.~smoker = drunk.juice 81 | 82 | // The Japanese smokes Parliaments. 83 | Japanese.~home = smoker.Parliament 84 | 85 | // The Norwegian lives next to the blue house. 86 | Norwegian.~home.nextTo[ blue.~house ] 87 | } 88 | 89 | run { one drunk.water and one owns.zebra } for 5 90 | 91 | 92 | -------------------------------------------------------------------------------- /puzzles/farmer-chicken-fox/farmer.als: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * The classic river crossing puzzle. A farmer is carrying a fox, a 4 | * chicken, and a sack of grain. He must cross a river using a boat 5 | * that can only hold the farmer and at most one other thing. If the 6 | * farmer leaves the fox alone with the chicken, the fox will eat the 7 | * chicken; and if he leaves the chicken alone with the grain, the 8 | * chicken will eat the grain. How can the farmer bring everything 9 | * to the far side of the river intact? 10 | * 11 | * authors: Greg Dennis, Rob Seater 12 | * 13 | * Acknowledgements to Derek Rayside and his students for finding and 14 | * fixing a bug in the "crossRiver" predicate. 15 | */ 16 | 17 | open util/ordering[State] as ord 18 | 19 | /** 20 | * The farmer and all his possessions will be represented as Objects. 21 | * Some objects eat other objects when the Farmer's not around. 22 | */ 23 | abstract sig Object { eats: set Object } 24 | one sig Farmer, Fox, Chicken, Grain extends Object {} 25 | 26 | /** 27 | * Define what eats what when the Farmer' not around. 28 | * Fox eats the chicken and the chicken eats the grain. 29 | */ 30 | fact eating { eats = Fox->Chicken + Chicken->Grain } 31 | 32 | /** 33 | * The near and far relations contain the objects held on each 34 | * side of the river in a given state, respectively. 35 | */ 36 | sig State { 37 | near: set Object, 38 | far: set Object 39 | } 40 | 41 | /** 42 | * In the initial state, all objects are on the near side. 43 | */ 44 | fact initialState { 45 | let s0 = ord/first | 46 | s0.near = Object && no s0.far 47 | } 48 | 49 | /** 50 | * Constrains at most one item to move from 'from' to 'to'. 51 | * Also constrains which objects get eaten. 52 | */ 53 | pred crossRiver [from, from", to, to": set Object] { 54 | // either the Farmer takes no items 55 | (from" = from - Farmer - from".eats and 56 | to" = to + Farmer) or 57 | // or the Farmer takes one item 58 | (one x : from - Farmer | { 59 | from" = from - Farmer - x - from".eats 60 | to" = to + Farmer + x }) 61 | } 62 | 63 | /** 64 | * crossRiver transitions between states 65 | */ 66 | fact stateTransition { 67 | all s: State, s": ord/next[s] { 68 | Farmer in s.near => 69 | crossRiver[s.near, s".near, s.far, s".far] else 70 | crossRiver[s.far, s".far, s.near, s".near] 71 | } 72 | } 73 | 74 | /** 75 | * the farmer moves everything to the far side of the river. 76 | */ 77 | pred solvePuzzle { 78 | ord/last.far = Object 79 | } 80 | 81 | run solvePuzzle for 8 State expect 1 82 | 83 | /** 84 | * no Object can be in two places at once 85 | * this is implied by both definitions of crossRiver 86 | */ 87 | assert NoQuantumObjects { 88 | no s : State | some x : Object | x in s.near and x in s.far 89 | } 90 | 91 | check NoQuantumObjects for 8 State expect 0 92 | -------------------------------------------------------------------------------- /puzzles/halmos-handshake/handshake.als: -------------------------------------------------------------------------------- 1 | /* 2 | * Alloy model of the Halmos handshake problem 3 | * 4 | * Hilary and Jocelyn are married. They invite four couples who are friends for dinner. When 5 | * they arrive, they shake hands with each other. Nobody shakes hands with him or herself 6 | * or with his or her spouse. After there has been some handshaking, Jocelyn jumps up on 7 | * a chair and says "Stop shaking hands!", and then asks how many hands each person has 8 | * shaken. All the answers are different. How many hands has Hilary shaken? 9 | * 10 | * The Alloy model represents the problem as a set of constraints. Properties of the spouse 11 | * relationship and of handshaking in general are given as facts. The particular situation 12 | * is cast as a function. 13 | * 14 | * There are 9 people answering, and all answers are different. Nobody can shake more than 15 | * 8 hands. So answers must be 0..8. The one (p8 say) who answered 8 has shaken everybody's 16 | * hand except for his or her own, and his or her spouse's. Now consider the person who shook 17 | * 0 hands (p0 say). The persons p0 and p8 are distinct. If they are not married, then p8 cannot 18 | * have shaken 8 hands, because he or she did not shake the hand of p0 or of his or her spouse. 19 | * So p8's spouse to p0. Now imagine Jocelyn asking the question again, with p0 and p8 out of 20 | * the room, and excluding hand shakes with them. Since p8 shook hands with everyone else 21 | * except p0 and p8, everyone gives an answer one smaller than they did before, giving 0..6. 22 | * The argument now applies recursively. So Hilary is left alone, having shaken 4 hands. 23 | * 24 | * author: Daniel Jackson, 11/15/01 25 | */ 26 | 27 | sig Person {spouse: Person, shaken: set Person} 28 | one sig Jocelyn, Hilary extends Person {} 29 | 30 | fact ShakingProtocol { 31 | // nobody shakes own or spouse's hand 32 | all p: Person | no (p + p.spouse) & p.shaken 33 | // if p shakes q, q shakes p 34 | all p, q: Person | p in q.shaken => q in p.shaken 35 | } 36 | 37 | fact Spouses { 38 | all p, q: Person | p!=q => { 39 | // if q is p's spouse, p is q's spouse 40 | p.spouse = q => q.spouse = p 41 | // no spouse sharing 42 | p.spouse != q.spouse 43 | } 44 | all p: Person { 45 | // a person is his or her spouse's spouse 46 | p.spouse.spouse = p 47 | // nobody is his or her own spouse 48 | p != p.spouse 49 | } 50 | } 51 | 52 | pred Puzzle { 53 | // everyone but Jocelyn has shaken a different number of hands 54 | all p,q: Person - Jocelyn | p!=q => #p.shaken != #q.shaken 55 | // Hilary's spouse is Jocelyn 56 | Hilary.spouse = Jocelyn 57 | } 58 | 59 | P10: run Puzzle for exactly 10 Person, 5 int expect 1 60 | P12: run Puzzle for exactly 12 Person, 5 int expect 1 61 | P14: run Puzzle for exactly 14 Person, 5 int expect 1 62 | P16: run Puzzle for exactly 16 Person, 6 int expect 1 63 | -------------------------------------------------------------------------------- /puzzles/money.als: -------------------------------------------------------------------------------- 1 | /* 2 | * Famous puzzle "SEND + MORE = MONEY" 3 | * Substitute each letter in the equation with a single integer 0-9 4 | * (no duplicates) such that the addition is correct. 5 | * 6 | */ 7 | 8 | // Non-negative numbers 9 | abstract sig Num { val: Int } { val >= 0 && val <= 9 } 10 | 11 | // Digits 12 | one sig S, E, N, D, M, O, R, Y extends Num { } 13 | 14 | // Digits must all be different and in 0..9 15 | fact { 16 | all m, n : Num | m !=n => n.val != m.val 17 | } 18 | 19 | // Function for computing the sum and the carry at the same time 20 | fun sumCarry(a: Num, b: Num): (Int -> Int) { 21 | let s = a.val + b.val | 22 | s -> (s > 9 => 1 else 0) 23 | } 24 | 25 | fun fst(t: (Int -> Int)): Int { 26 | t.univ 27 | } 28 | 29 | fun snd(t: (Int -> Int)): Int { 30 | univ.t 31 | } 32 | 33 | fun val(a: (Int -> Int), b: (Int -> Int)): Int { 34 | rem[plus[fst[a], snd[b]], 10] 35 | } 36 | 37 | // Constraints for SEND + MORE = MONEY 38 | fact { 39 | M.val > 0 40 | S.val > 0 41 | let YSumCarry = sumCarry[D, E], 42 | ESumCarry = sumCarry[N, R], 43 | NSumCarry = sumCarry[E, O], 44 | OSumCarry = sumCarry[S, M] | 45 | Y.val = rem[fst[YSumCarry], 10] && 46 | E.val = val[ESumCarry, YSumCarry] && 47 | N.val = val[NSumCarry, ESumCarry] && 48 | O.val = val[OSumCarry, NSumCarry] && 49 | M.val = snd[OSumCarry] 50 | } 51 | 52 | run { } for 5 Int 53 | -------------------------------------------------------------------------------- /puzzles/prisoner-room-visit/README.md: -------------------------------------------------------------------------------- 1 | # Prisoners-Puzzle 2 | This is an Alloy module for the prisoners puzzle 3 | 4 | The warden of a prison gives his prisoners the following problem. 5 | There is a room in the prison with two switches, labeled A and B. 6 | Every so often, the warden will select a prisoner at random and take him into the room, where 7 | he must flip (change the position of) exactly one of the switches. 8 | The only guarantee he makes is that every prisoner will eventually 9 | be brought into the room multiple times. 10 | 11 | At any time, any prisoner may declare that all the prisoners have 12 | been in the room at least once. If that prisoner is right, then 13 | all the prisoners go free. If he is wrong, all the prisoners are 14 | immediately executed. 15 | 16 | The prisoners are allowed to decide upon a strategy, after which 17 | they will not be allowed to communicate with one another. And, of 18 | course, they cannot see the room or who is being brought into it. 19 | 20 | What do they do? 21 | 22 | The solution presented by the Car Guys and checked in Alloy by Shiran Zada 23 | -------------------------------------------------------------------------------- /simple-models/4-bit-adder/4-bit-adder.als: -------------------------------------------------------------------------------- 1 | // Example of how to create basic boolean logic circuits. Starting with the 2 | // definition of basic boolean operations we build a half-adder and then 3 | // a 4-bit full adder using 4 registers: 2 summands, 1 sum, 1 carry 4 | 5 | // 0 or 1 6 | let bits = { i: Int | 0 <= i && i <= 1 } 7 | 8 | // Or 9 | let bitOrTable = { i: bits, j: bits, k: sum[i + j] } 10 | 11 | // And 12 | let bitAndTable = { i: bits, j: bits, k: mul[i, j] } 13 | 14 | // Not 15 | let bitNotTable = { i: bits, j: minus[1, i] } 16 | 17 | // Xor: https://en.wikipedia.org/wiki/Exclusive_or 18 | let bitXorTable = { 19 | i: bits, 20 | j: bits, 21 | k: bitAndTable[bitOrTable[i, j], bitNotTable[bitAndTable[i, j]]] 22 | } 23 | 24 | // Half adder: https://en.wikipedia.org/wiki/Adder_(electronics)#Half_adder 25 | pred halfAdder(m: Int, n: Int, s: Int, c: Int) { 26 | s = bitXorTable[m, n] 27 | c = bitAndTable[m, n] 28 | } 29 | 30 | // https://en.wikipedia.org/wiki/Adder_(electronics)#/media/File:Full-adder_logic_diagram.svg 31 | pred fullAdder(m: Int, n: Int, c: Int, s: Int, carry: Int) { 32 | let xor = bitXorTable[m, n] { 33 | s = bitXorTable[xor, c] 34 | carry = bitOrTable[bitAndTable[m, n], bitAndTable[xor, c]] 35 | } 36 | } 37 | 38 | // BitVector consists of 4 bits 39 | abstract sig BitVector { 40 | values: (0 + 1 + 2 + 3) -> one bits 41 | } 42 | 43 | // We want 4 vectors to perform a computation: 2 summands, sum, and carry 44 | one sig A, B, C, S extends BitVector { } 45 | 46 | // 4 bit adder with overflow 47 | pred bitAddition(a: BitVector, b: BitVector, c: BitVector, s: BitVector) { 48 | fullAdder[a.values[0], b.values[0], 0, s.values[0], c.values[0]] 49 | fullAdder[a.values[1], b.values[1], c.values[0], s.values[1], c.values[1]] 50 | fullAdder[a.values[2], b.values[2], c.values[1], s.values[2], c.values[2]] 51 | fullAdder[a.values[3], b.values[3], c.values[2], s.values[3], c.values[3]] 52 | } 53 | 54 | // Run it to verify 55 | run { 56 | bitAddition[A, B, C, S] 57 | } 58 | -------------------------------------------------------------------------------- /simple-models/books/birthday.als: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * Birthday Book 5 | * 6 | * A classic Z example to explain the basic form of an Alloy model. For the original, 7 | * see J.M. Spivey, The Z Notation, Second Edition, Prentice Hall, 1992. 8 | * 9 | * A birthday book has two fields: known, a set of names (of persons whose birthdays are known), 10 | * and date, a function from known names to dates. The operation AddBirthday adds an association 11 | * between a name and a date; it uses the relational override operator (++), so any existing 12 | * mapping from the name to a date is replaced. DelBirthday removes the entry for a given name. 13 | * FindBirthday obtains the date d for a name n. The argument d is declared to be optional (that is, 14 | * a singleton or empty set), so if there is no entry for n, d will be empty. Remind gives the set 15 | * of names whose birthdays fall on a particular day. 16 | * 17 | * The assertion AddWorks says that if you add an entry, then look it up, you get back what you 18 | * just entered. DelIsUndo says that doing DelBirthday after AddBirthday undoes it, as if the add 19 | * had never happened. The first of these assertions is valid; the second isn't. 20 | * 21 | * The function BusyDay shows a case in which Remind produces more than one card. 22 | * 23 | * author: Daniel Jackson, 11/14/01 24 | */ 25 | 26 | sig Name {} 27 | sig Date {} 28 | sig BirthdayBook {known: set Name, date: known -> one Date} 29 | 30 | pred AddBirthday [bb, bb": BirthdayBook, n: Name, d: Date] { 31 | bb".date = bb.date ++ (n->d) 32 | } 33 | 34 | pred DelBirthday [bb, bb": BirthdayBook, n: Name] { 35 | bb".date = bb.date - (n->Date) 36 | } 37 | 38 | pred FindBirthday [bb: BirthdayBook, n: Name, d: lone Date] { 39 | d = bb.date[n] 40 | } 41 | 42 | pred Remind [bb: BirthdayBook, today: Date, cards: set Name] { 43 | cards = (bb.date).today 44 | } 45 | 46 | pred InitBirthdayBook [bb: BirthdayBook] { 47 | no bb.known 48 | } 49 | 50 | assert AddWorks { 51 | all bb, bb": BirthdayBook, n: Name, d: Date, d": lone Date | 52 | AddBirthday [bb,bb",n,d] && FindBirthday [bb",n,d"] => d = d" 53 | } 54 | 55 | assert DelIsUndo { 56 | all bb1,bb2,bb3: BirthdayBook, n: Name, d: Date| 57 | AddBirthday [bb1,bb2,n,d] && DelBirthday [bb2,bb3,n] 58 | => bb1.date = bb3.date 59 | } 60 | 61 | check AddWorks for 3 but 2 BirthdayBook expect 0 62 | check DelIsUndo for 3 but 2 BirthdayBook expect 1 63 | 64 | pred BusyDay [bb: BirthdayBook, d: Date]{ 65 | some cards: set Name | Remind [bb,d,cards] && !lone cards 66 | } 67 | 68 | run BusyDay for 3 but 1 BirthdayBook expect 1 69 | -------------------------------------------------------------------------------- /simple-models/games/life.als: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * John Conway's Game of Life 5 | * 6 | * For a detailed description, see: 7 | * http://www.math.com/students/wonders/life/life.html 8 | * 9 | * authors: Bill Thies, Manu Sridharan 10 | */ 11 | 12 | open util/ordering[State] as ord 13 | 14 | sig Point { 15 | right: lone Point, 16 | below: lone Point 17 | } 18 | 19 | fact Acyclic { 20 | all p: Point | p !in p.^(right + below) 21 | } 22 | 23 | one sig Root extends Point {} 24 | 25 | fact InnerSquaresCommute { 26 | all p: Point { 27 | p.below.right = p.right.below 28 | some p.below && some p.right => some p.below.right 29 | } 30 | } 31 | 32 | fact TopRow { 33 | all p: Point - Root | no p.~below => # p.*below = # Root.*below 34 | } 35 | 36 | fact Connected { 37 | Root.*(right + below) = Point 38 | } 39 | 40 | pred Square { 41 | # Root.*right = # Root.*below 42 | } 43 | 44 | run Square for 6 Point, 3 State expect 1 45 | 46 | pred Rectangle {} 47 | 48 | sig State { 49 | live : set Point 50 | } 51 | 52 | fun Neighbors[p : Point] : set Point { 53 | p.right + p.right.below + p.below 54 | + p.below.~right + p.~right 55 | + p.~right.~below + p.~below + 56 | p.~below.right 57 | } 58 | 59 | fun LiveNeighborsInState[p : Point, s : State] : set Point { 60 | Neighbors[p] & s.live 61 | } 62 | 63 | pred Trans[pre, post: State, p : Point] { 64 | let preLive = LiveNeighborsInState[p,pre] | 65 | // dead cell w/ 3 live neighbors becomes live 66 | (p !in pre.live && # preLive = 3) => 67 | p in post.live 68 | else ( 69 | // live cell w/ 2 or 3 live neighbors stays alive 70 | (p in pre.live && (# preLive = 2 || # preLive = 3)) => 71 | p in post.live else p !in post.live 72 | ) 73 | } 74 | 75 | fact ValidTrans { 76 | all pre : State - ord/last | 77 | let post = ord/next[pre] | 78 | all p : Point | 79 | Trans[pre,post,p] 80 | } 81 | 82 | pred Show {} 83 | 84 | // slow 85 | run Show for exactly 12 Point, 3 State expect 1 86 | 87 | // a small but interesting example 88 | pred interesting { 89 | some State.live 90 | some Point - State.live 91 | some right 92 | some below 93 | } 94 | run interesting for exactly 6 Point, 3 State expect 1 95 | -------------------------------------------------------------------------------- /simple-models/genealogy/genealogy.als: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * Toy model of genealogical relationships 5 | * 6 | * The purpose of this model is to introduce basic concepts in Alloy. 7 | * The signature Person introduces a set of persons; this is paritioned into 8 | * two subsets, Man and Woman. The subsignature Adam declares a set of men 9 | * with one element -- that is, a scalar. Similarly, Eve declares a single 10 | * woman. 11 | * 12 | * The Person signature declares two fields: a person has one or zero spouses 13 | * and a set of parents. 14 | * 15 | * The facts should be self-explanatory. Note that the constraint that 16 | * spouse is a symmetric relation (that is, p is a spouse of q if q is a spouse 17 | * of p) is written by equating the field, viewed as a relation, to its 18 | * transpose. Since signatures have their own namespaces, and the same field 19 | * name can refer to different fields in different relations, it is necessary 20 | * to indicate which signature the field belongs to. This is not necessary when 21 | * dereferencing a field, because the appropriate field is automatically 22 | * determined by the type of the referencing expression. 23 | * 24 | * The command has no solutions. Given only 5 persons, it's not possible 25 | * to have a couple distinct from Adam and Eve without incest. To understand 26 | * the model, try weakening the constraints by commenting lines out (just 27 | * put two hyphens at the start of a line) and rerunning the command. 28 | * 29 | * author: Daniel Jackson, 11/13/01 30 | */ 31 | 32 | abstract sig Person {spouse: lone Person, parents: set Person} 33 | sig Man, Woman extends Person {} 34 | one sig Eve extends Woman {} 35 | one sig Adam extends Man {} 36 | 37 | fact Biology { 38 | -- nobody is his or her own ancestor 39 | no p: Person | p in p.^parents 40 | } 41 | 42 | fact Bible { 43 | -- every person except Adam and Eve has a mother and father 44 | all p: Person - (Adam + Eve) | one mother: Woman, father: Man | 45 | p.parents = mother + father 46 | -- Adam and Eve have no parents 47 | no (Adam + Eve).parents 48 | -- Adam's spouse is Eve 49 | Adam.spouse = Eve 50 | } 51 | 52 | fact SocialNorms { 53 | -- nobody is his or her own spouse 54 | no p: Person | p.spouse = p 55 | -- spouse is symmetric 56 | spouse = ~spouse 57 | -- a man's spouse is a woman and vice versa 58 | Man.spouse in Woman && Woman.spouse in Man 59 | } 60 | 61 | fact NoIncest { 62 | -- can't marry a sibling 63 | no p: Person | some p.spouse.parents & p.parents 64 | -- can't marry a parent 65 | no p: Person | some p.spouse & p.parents 66 | } 67 | 68 | pred Show { 69 | some p: Person - (Adam + Eve) | some p.spouse 70 | } 71 | run Show for 6 expect 1 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /simple-models/genealogy/grandpa.als: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * An Alloy model of the song "I Am My Own Grandpa" 5 | * by Dwight B. Latham and Moe Jaffe 6 | * 7 | * The challenge is to produce a man who is his own grandfather 8 | * without resorting to incest or time travel. Executing the predicate 9 | * "ownGrandpa" will demonstrate how such a thing can occur. 10 | * 11 | * The full song lyrics, which describe an isomorophic solution, 12 | * are included at the end of this file. 13 | * 14 | * model author: Daniel Jackson 15 | */ 16 | 17 | abstract sig Person { 18 | father: lone Man, 19 | mother: lone Woman 20 | } 21 | 22 | sig Man extends Person { wife: lone Woman } 23 | 24 | sig Woman extends Person { husband: lone Man } 25 | 26 | fact Biology { no p: Person | p in p.^(mother+father) } 27 | 28 | fact Terminology { wife = ~husband } 29 | 30 | fact SocialConvention { 31 | no wife & *(mother+father).mother 32 | no husband & *(mother+father).father 33 | } 34 | 35 | fun grandpas [p: Person]: set Person { 36 | let parent = mother + father + father.wife + mother.husband | 37 | p.parent.parent & Man 38 | } 39 | 40 | pred ownGrandpa [m: Man] { m in grandpas[m] } 41 | 42 | run ownGrandpa for 4 Person expect 1 43 | 44 | /* defined variables: 45 | * 46 | * spouse = husband+wife 47 | */ 48 | 49 | /* 50 | I Am My Own Grandpa 51 | by Dwight B. Latham and Moe Jaffe 52 | 53 | Many many years ago, when I was twenty-three, 54 | I was married to a widow as pretty as can be, 55 | This widow had a grown-up daughter who had hair of red, 56 | My father fell in love with her and soon the two were wed. 57 | 58 | I'm my own grandpa, I'm my own grandpa. 59 | It sounds funny, I know, but it really is so— 60 | I'm my own grandpa. 61 | 62 | This made my dad my son-in-law and changed my very life, 63 | For my daughter was my mother, for she was my father's wife. 64 | To complicate the matter, even though it brought me joy, 65 | I soon became the father of a bouncing baby boy. 66 | 67 | My little baby thus became a brother-in-law to dad, 68 | And so became my uncle, though it made me very sad, 69 | For if he was my uncle then that also made him brother 70 | To the widow's grown-up daughter, who of course was my step-mother. 71 | 72 | Father's wife then had a son who kept them on the run. 73 | And he became my grandchild for he was my daughter's son. 74 | My wife is now my mother's mother and it makes me blue, 75 | Because although she is my wife, she's my grandmother, too. 76 | 77 | Oh, if my wife's my grandmother then I am her grandchild. 78 | And every time I think of it, it nearly drives me wild. 79 | For now I have become the strangest case you ever saw— 80 | As the husband of my grandmother, I am my own grandpa. 81 | 82 | I'm my own grandpa, I'm my own grandpa. 83 | It sounds funny, I know, but it really is so— 84 | I'm my own grandpa. 85 | I'm my own grandpa, I'm my own grandpa. 86 | It sounds funny, I know, but it really is so— 87 | I'm my own grandpa. 88 | */ 89 | -------------------------------------------------------------------------------- /simple-models/lists/lists.als: -------------------------------------------------------------------------------- 1 | /* 2 | * a simple list module 3 | * which demonstrates how to create predicates and fields that mirror each other 4 | * thus allowing recursive constraints (even though recursive predicates are not 5 | * currently supported by Alloy) 6 | * author: Robert Seater 7 | */ 8 | 9 | sig Thing {} 10 | fact NoStrayThings {Thing in List.car} 11 | 12 | abstract sig List { 13 | equivTo: set List, 14 | prefixes: set List 15 | } 16 | sig NonEmptyList extends List { 17 | car: one Thing, 18 | cdr: one List 19 | } 20 | sig EmptyList extends List {} 21 | 22 | pred isFinite [L:List] {some e: EmptyList | e in L.*cdr} 23 | fact finite {all L: List | isFinite[L]} 24 | 25 | fact Equivalence { 26 | all a,b: List | (a in b.equivTo) <=> ((a.car = b.car and b.cdr in a.cdr.equivTo) and (#a.*cdr = #b.*cdr)) 27 | } 28 | assert reflexive {all L: List | L in L.equivTo} 29 | check reflexive for 6 expect 0 30 | assert symmetric {all a,b: List | a in b.equivTo <=> b in a.equivTo} 31 | check symmetric for 6 expect 0 32 | assert empties {all a,b: EmptyList | a in b.equivTo} 33 | check empties for 6 expect 0 34 | 35 | fact prefix { //a is a prefix of b 36 | all e: EmptyList, L:List | e in L.prefixes 37 | all a,b: NonEmptyList | (a in b.prefixes) <=> (a.car = b.car 38 | and a.cdr in b.cdr.prefixes 39 | and #a.*cdr < #b.*cdr) 40 | } 41 | 42 | pred show { 43 | some a, b: NonEmptyList | a!=b && b in a.prefixes 44 | } 45 | run show for 4 expect 1 46 | 47 | -------------------------------------------------------------------------------- /simple-models/no-solution/trivial.als: -------------------------------------------------------------------------------- 1 | //a trivial model whose command has no solution 2 | 3 | 4 | sig S {} 5 | 6 | fact { 1=2 } 7 | 8 | run {some S} expect 0 9 | -------------------------------------------------------------------------------- /simple-models/state-machine/flip-flop.als: -------------------------------------------------------------------------------- 1 | // 2 | // A simple model of a flipflop state machine that 3 | // flips on every clock event. 4 | // 5 | // This is probably the simplest possible time based example 6 | // for Alloy but shows how to make a trace. 7 | // 8 | 9 | open util/ordering[Trace] 10 | 11 | enum Event { C } 12 | enum State { On, Off } 13 | 14 | fun transitions : State -> Event -> State { 15 | On -> C -> Off 16 | + Off -> C -> On 17 | } 18 | 19 | sig Trace { 20 | state : State, 21 | event : lone Event 22 | } 23 | 24 | fact { 25 | first.state = On 26 | no last.event 27 | 28 | all t : Trace - last, t" : t.next { 29 | some e : Event { 30 | t.event = e 31 | t".state = transitions[t.state][t.event] 32 | } 33 | } 34 | } 35 | 36 | pred show( t : set Trace ) { } 37 | 38 | run show for 10 39 | -------------------------------------------------------------------------------- /simple-models/state-machine/reset-flipflop-with-enable.als: -------------------------------------------------------------------------------- 1 | 2 | open util/ordering[Trace] 3 | 4 | enum Event { C, X } 5 | enum State { On, Off } 6 | 7 | fun transitions : State -> Event -> State { 8 | On -> C -> Off 9 | + On -> X -> On 10 | + Off -> C -> On 11 | + Off -> X -> Off 12 | } 13 | 14 | sig Trace { 15 | state : State, 16 | event : lone Event 17 | } 18 | 19 | fact { 20 | first.state = On 21 | no last.event 22 | 23 | all t" : Trace - first, t : t".prev { 24 | some e : Event | 25 | t.event = e 26 | and t".state = transitions[t.state][t.event] 27 | } 28 | } 29 | 30 | pred show( ) { 31 | some t : Trace | all s : t.^next | s.state = Off 32 | 33 | } 34 | 35 | run show for 10 36 | -------------------------------------------------------------------------------- /software-abstractions-book/appendixA/addressBook1.als: -------------------------------------------------------------------------------- 1 | module appendixA/addressBook1 2 | 3 | abstract sig Name { 4 | address: set Addr+Name 5 | } 6 | 7 | sig Alias, Group extends Name { } 8 | 9 | sig Addr { } 10 | 11 | fact { 12 | // the invariants should go here 13 | } 14 | 15 | pred show { 16 | // simulation constraints should go here 17 | } 18 | 19 | run show for 3 20 | -------------------------------------------------------------------------------- /software-abstractions-book/appendixA/addressBook2.als: -------------------------------------------------------------------------------- 1 | module appendixA/addressBook2 2 | 3 | sig Addr, Name { } 4 | 5 | sig Book { 6 | addr: Name -> (Name + Addr) 7 | } 8 | 9 | pred inv [b: Book] { 10 | let addr = b.addr | 11 | all n: Name { 12 | n not in n.^addr 13 | some addr.n => some n.^addr & Addr 14 | } 15 | } 16 | 17 | pred add [b, b": Book, n: Name, t: Name+Addr] { 18 | b".addr = b.addr + n->t 19 | } 20 | 21 | pred del [b, b": Book, n: Name, t: Name+Addr] { 22 | b".addr = b.addr - n->t 23 | } 24 | 25 | fun lookup [b: Book, n: Name] : set Addr { 26 | n.^(b.addr) & Addr 27 | } 28 | -------------------------------------------------------------------------------- /software-abstractions-book/appendixA/barbers.als: -------------------------------------------------------------------------------- 1 | module appendixA/barbers 2 | 3 | sig Man { shaves: set Man } 4 | 5 | one sig Barber extends Man { } 6 | 7 | fact { 8 | Barber.shaves = { m: Man | m not in m.shaves } 9 | } 10 | -------------------------------------------------------------------------------- /software-abstractions-book/appendixA/closure.als: -------------------------------------------------------------------------------- 1 | module appendixA/closure 2 | 3 | pred transCover [R, r: univ->univ] { 4 | // You have to fill in the appropriate formula here 5 | } 6 | 7 | pred transClosure [R, r: univ->univ] { 8 | transCover [R, r] 9 | // You have to fill in the appropriate formula here 10 | } 11 | 12 | assert Equivalence { 13 | all R, r: univ->univ | transClosure [R,r] iff R = ^r 14 | } 15 | 16 | check Equivalence for 3 17 | -------------------------------------------------------------------------------- /software-abstractions-book/appendixA/distribution.als: -------------------------------------------------------------------------------- 1 | module appendixA/distribution 2 | 3 | assert union { 4 | all s: set univ, p, q: univ->univ | s.(p+q) = s.p + s.q 5 | } 6 | 7 | check union for 4 8 | -------------------------------------------------------------------------------- /software-abstractions-book/appendixA/phones.als: -------------------------------------------------------------------------------- 1 | module appendixA/phones 2 | 3 | sig Phone { 4 | requests: set Phone, 5 | connects: lone Phone 6 | } 7 | -------------------------------------------------------------------------------- /software-abstractions-book/appendixA/prison.als: -------------------------------------------------------------------------------- 1 | module appendixA/prison 2 | 3 | sig Gang { members: set Inmate } 4 | 5 | sig Inmate { room: Cell } 6 | 7 | sig Cell { } 8 | 9 | pred safe { 10 | // your constraints should go here 11 | } 12 | 13 | pred show { 14 | // your constraints should go here 15 | } 16 | 17 | run show 18 | -------------------------------------------------------------------------------- /software-abstractions-book/appendixA/properties.als: -------------------------------------------------------------------------------- 1 | module appendixA/properties 2 | 3 | pred show { 4 | some r: univ->univ { 5 | some r -- nonempty 6 | r.r in r -- transitive 7 | no iden & r -- irreflexive 8 | ~r in r -- symmetric 9 | ~r.r in iden -- functional 10 | r.~r in iden -- injective 11 | univ in r.univ -- total 12 | univ in univ.r -- onto 13 | } 14 | } 15 | 16 | run show for 4 17 | 18 | assert ReformulateNonEmptinessOK { 19 | all r: univ->univ | 20 | some r iff (some x, y: univ | x->y in r) 21 | } 22 | 23 | check ReformulateNonEmptinessOK 24 | -------------------------------------------------------------------------------- /software-abstractions-book/appendixA/ring.als: -------------------------------------------------------------------------------- 1 | module appendixA/ring 2 | 3 | sig Node { next: set Node } 4 | 5 | pred isRing { 6 | // You have to fill in the appropriate formula here 7 | } 8 | 9 | run isRing for exactly 4 Node 10 | -------------------------------------------------------------------------------- /software-abstractions-book/appendixA/spanning.als: -------------------------------------------------------------------------------- 1 | module appendixA/spanning 2 | 3 | pred isTree [r: univ->univ] { 4 | // You have to fill in the appropriate formula here 5 | } 6 | 7 | pred spans [r1, r2: univ->univ] { 8 | // You have to fill in the appropriate formula here 9 | } 10 | 11 | pred show [r, t1, t2: univ->univ] { 12 | spans [t1,r] and isTree [t1] 13 | spans [t2,r] and isTree [t2] 14 | t1 != t2 15 | } 16 | 17 | run show for 3 18 | -------------------------------------------------------------------------------- /software-abstractions-book/appendixA/tree.als: -------------------------------------------------------------------------------- 1 | module appendixA/tree 2 | 3 | pred isTree [r:univ->univ] { 4 | // You have to fill in the appropriate formula here 5 | } 6 | 7 | run isTree for 4 8 | -------------------------------------------------------------------------------- /software-abstractions-book/appendixA/tube.als: -------------------------------------------------------------------------------- 1 | module appendixA/tube 2 | 3 | abstract sig Station { 4 | jubilee, central, circle: set Station 5 | } 6 | 7 | sig Jubilee, Central, Circle in Station {} 8 | 9 | one sig 10 | Stanmore, BakerStreet, BondStreet, Westminster, Waterloo, 11 | WestRuislip, EalingBroadway, NorthActon, NottingHillGate, 12 | LiverpoolStreet, Epping 13 | extends Station {} 14 | 15 | fact { 16 | // the constraints should go here 17 | } 18 | 19 | pred show {} 20 | 21 | run show 22 | -------------------------------------------------------------------------------- /software-abstractions-book/appendixA/undirected.als: -------------------------------------------------------------------------------- 1 | module appendixA/undirected 2 | 3 | sig Node { adjs: set Node } 4 | 5 | pred acyclic { 6 | adjs = ~adjs 7 | // You have to fill in additional formula here 8 | } 9 | 10 | run acyclic for 4 11 | 12 | -------------------------------------------------------------------------------- /software-abstractions-book/appendixE/hotel.thm: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /software-abstractions-book/appendixE/p300-hotel.als: -------------------------------------------------------------------------------- 1 | module hotel 2 | 3 | open util/ordering [Time] as timeOrder 4 | 5 | sig Key, Time {} 6 | 7 | sig Card { 8 | fst, snd: Key 9 | } 10 | 11 | sig Room { 12 | key: Key one->Time 13 | } 14 | 15 | one sig Desk { 16 | issued: Key->Time, 17 | prev: (Room->lone Key)->Time 18 | } 19 | 20 | sig Guest { 21 | cards: Card->Time 22 | } 23 | 24 | pred init [t: Time] { 25 | Desk.prev.t = key.t 26 | no issued.t and no cards.t ------ bug! (see page 303) 27 | } 28 | 29 | pred checkin [t,t": Time, r: Room, g: Guest] { 30 | some c: Card { 31 | c.fst = r.(Desk.prev.t) 32 | c.snd not in Desk.issued.t 33 | cards.t" = cards.t + g->c ------------- bug! (see page 306) 34 | Desk.issued.t" = Desk.issued.t + c.snd 35 | Desk.prev.t" = Desk.prev.t ++ r->c.snd 36 | } 37 | key.t = key.t" 38 | } 39 | 40 | pred enter [t,t": Time, r: Room, g: Guest] { 41 | some c: g.cards.t | 42 | let k = r.key.t { 43 | c.snd = k and key.t" = key.t 44 | or c.fst = k and key.t" = key.t ++ r->c.snd 45 | } 46 | issued.t = issued.t" and (Desk<:prev).t = prev.t" 47 | cards.t = cards.t" 48 | } 49 | 50 | fact Traces { 51 | init [first] 52 | all t: Time - last | some g: Guest, r: Room | 53 | checkin [t, t.next, r, g] or enter[t, t.next, r, g] 54 | } 55 | 56 | assert NoIntruder { 57 | no t1: Time, g: Guest, g": Guest-g, r: Room | 58 | let t2=t1.next, t3=t2.next, t4=t3.next { 59 | enter [t1, t2, r, g] 60 | enter [t2, t3, r, g"] 61 | enter [t3, t4, r, g] 62 | } 63 | } 64 | 65 | -- This check reveals a bug (similar to Fig E.3) in which the initial key was issued twice. 66 | check NoIntruder for 3 but 6 Time, 1 Room, 2 Guest 67 | -------------------------------------------------------------------------------- /software-abstractions-book/appendixE/p303-hotel.als: -------------------------------------------------------------------------------- 1 | module hotel 2 | 3 | open util/ordering [Time] as timeOrder 4 | 5 | sig Key, Time {} 6 | 7 | sig Card { 8 | fst, snd: Key 9 | } 10 | 11 | sig Room { 12 | key: Key one->Time 13 | } 14 | 15 | one sig Desk { 16 | issued: Key->Time, 17 | prev: (Room->lone Key)->Time 18 | } 19 | 20 | sig Guest { 21 | cards: Card->Time 22 | } 23 | 24 | pred init [t: Time] { 25 | Desk.prev.t = key.t 26 | Desk.issued.t = Room.key.t and no cards.t 27 | } 28 | 29 | pred checkin [t,t": Time, r: Room, g: Guest] { 30 | some c: Card { 31 | c.fst = r.(Desk.prev.t) 32 | c.snd not in Desk.issued.t 33 | cards.t" = cards.t + g->c ------------- bug! (see page 306) 34 | Desk.issued.t" = Desk.issued.t + c.snd 35 | Desk.prev.t" = Desk.prev.t ++ r->c.snd 36 | } 37 | key.t = key.t" 38 | } 39 | 40 | pred enter [t,t": Time, r: Room, g: Guest] { 41 | some c: g.cards.t | 42 | let k = r.key.t { 43 | c.snd = k and key.t" = key.t 44 | or c.fst = k and key.t" = key.t ++ r->c.snd 45 | } 46 | issued.t = issued.t" and (Desk<:prev).t = prev.t" 47 | cards.t = cards.t" 48 | } 49 | 50 | fact Traces { 51 | init [first] 52 | all t: Time - last | some g: Guest, r: Room | 53 | checkin [t, t.next, r, g] or enter[t, t.next, r, g] 54 | } 55 | 56 | assert NoIntruder { 57 | no t1: Time, g: Guest, g": Guest-g, r: Room | 58 | let t2=t1.next, t3=t2.next, t4=t3.next { 59 | enter [t1, t2, r, g] 60 | enter [t2, t3, r, g"] 61 | enter [t3, t4, r, g] 62 | } 63 | } 64 | 65 | -- This check now succeeds without finding any counterexample. 66 | check NoIntruder for 3 but 6 Time, 1 Room, 2 Guest 67 | 68 | -- To increase our confidence, we can increase the scope. 69 | -- This time, it finds a counterexample. 70 | check NoIntruder for 4 but 7 Time, 1 Room, 2 Guest 71 | -------------------------------------------------------------------------------- /software-abstractions-book/appendixE/p306-hotel.als: -------------------------------------------------------------------------------- 1 | module hotel 2 | 3 | open util/ordering [Time] as timeOrder 4 | 5 | sig Key, Time {} 6 | 7 | sig Card { 8 | fst, snd: Key 9 | } 10 | 11 | sig Room { 12 | key: Key one->Time 13 | } 14 | 15 | one sig Desk { 16 | issued: Key->Time, 17 | prev: (Room->lone Key)->Time 18 | } 19 | 20 | sig Guest { 21 | cards: Card->Time 22 | } 23 | 24 | pred init [t: Time] { 25 | Desk.prev.t = key.t 26 | Desk.issued.t = Room.key.t and no cards.t 27 | } 28 | 29 | pred checkin [t,t": Time, r: Room, g: Guest] { 30 | some c: Card { 31 | c.fst = r.(Desk.prev.t) 32 | c.snd not in Desk.issued.t 33 | cards.t" = cards.t ++ g->c 34 | Desk.issued.t" = Desk.issued.t + c.snd 35 | Desk.prev.t" = Desk.prev.t ++ r->c.snd 36 | } 37 | key.t = key.t" 38 | } 39 | 40 | pred enter [t,t": Time, r: Room, g: Guest] { 41 | some c: g.cards.t | 42 | let k = r.key.t { 43 | c.snd = k and key.t" = key.t 44 | or c.fst = k and key.t" = key.t ++ r->c.snd 45 | } 46 | issued.t = issued.t" and (Desk<:prev).t = prev.t" 47 | cards.t = cards.t" 48 | } 49 | 50 | fact Traces { 51 | init [first] 52 | all t: Time - last | some g: Guest, r: Room | 53 | checkin [t, t.next, r, g] or enter[t, t.next, r, g] 54 | } 55 | 56 | assert NoIntruder { 57 | no t1: Time, g: Guest, g": Guest-g, r: Room | 58 | let t2=t1.next, t3=t2.next, t4=t3.next { 59 | enter [t1, t2, r, g] 60 | enter [t2, t3, r, g"] 61 | enter [t3, t4, r, g] 62 | } 63 | } 64 | 65 | -- This check now succeeds without finding any counterexample. 66 | check NoIntruder for 3 but 6 Time, 1 Room, 2 Guest 67 | 68 | -- This check now succeeds without finding any counterexample. 69 | check NoIntruder for 4 but 7 Time, 1 Room, 2 Guest 70 | 71 | -- We can try to increase the scope further. 72 | -- This check also succeeds without finding any counterexample. 73 | check NoIntruder for 6 but 12 Time, 3 Room, 3 Guest 74 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter2/addressBook1a.als: -------------------------------------------------------------------------------- 1 | module tour/addressBook1a ----- Page 6 2 | 3 | sig Name, Addr { } 4 | 5 | sig Book { 6 | addr: Name -> lone Addr 7 | } 8 | 9 | pred show { } 10 | 11 | // This command generates an instance similar to Fig 2.1 12 | run show for 3 but 1 Book 13 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter2/addressBook1b.als: -------------------------------------------------------------------------------- 1 | module tour/addressBook1b ----- Page 8 2 | 3 | sig Name, Addr { } 4 | 5 | sig Book { 6 | addr: Name -> lone Addr 7 | } 8 | 9 | pred show [b: Book] { 10 | #b.addr > 1 11 | } 12 | 13 | // This command generates an instance similar to Fig 2.2 14 | run show for 3 but 1 Book 15 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter2/addressBook1c.als: -------------------------------------------------------------------------------- 1 | module tour/addressBook1c ----- Page 8 2 | 3 | sig Name, Addr { } 4 | 5 | sig Book { 6 | addr: Name -> lone Addr 7 | } 8 | 9 | pred show [b: Book] { 10 | #b.addr > 1 11 | some n: Name | #n.(b.addr) > 1 12 | } 13 | 14 | // This command should not find any instance. 15 | run show for 3 but 1 Book 16 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter2/addressBook1d.als: -------------------------------------------------------------------------------- 1 | module tour/addressBook1d ----- Page 9 2 | 3 | sig Name, Addr { } 4 | 5 | sig Book { 6 | addr: Name -> lone Addr 7 | } 8 | 9 | pred show [b: Book] { 10 | #b.addr > 1 11 | #Name.(b.addr) > 1 12 | } 13 | 14 | // This command generates an instance similar to Fig 2.3 15 | run show for 3 but 1 Book 16 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter2/addressBook1e.als: -------------------------------------------------------------------------------- 1 | module tour/addressBook1e ----- Page 11 2 | 3 | sig Name, Addr { } 4 | 5 | sig Book { 6 | addr: Name -> lone Addr 7 | } 8 | 9 | pred add [b, b": Book, n: Name, a: Addr] { 10 | b".addr = b.addr + n->a 11 | } 12 | 13 | // This command generates an instance similar to Fig 2.4 14 | run add for 3 but 2 Book 15 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter2/addressBook1f.als: -------------------------------------------------------------------------------- 1 | module tour/addressBook1f ----- Page 12 2 | 3 | sig Name, Addr { } 4 | 5 | sig Book { 6 | addr: Name -> lone Addr 7 | } 8 | 9 | pred add [b, b": Book, n: Name, a: Addr] { 10 | b".addr = b.addr + n->a 11 | } 12 | 13 | pred showAdd [b, b": Book, n: Name, a: Addr] { 14 | add [b, b", n, a] 15 | #Name.(b".addr) > 1 16 | } 17 | 18 | // This command generates an instance similar to Fig 2.5 19 | run showAdd for 3 but 2 Book 20 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter2/addressBook1g.als: -------------------------------------------------------------------------------- 1 | module tour/addressBook1g ----- Page 14 2 | 3 | sig Name, Addr { } 4 | 5 | sig Book { 6 | addr: Name -> lone Addr 7 | } 8 | 9 | pred add [b, b": Book, n: Name, a: Addr] { 10 | b".addr = b.addr + n->a 11 | } 12 | 13 | pred del [b, b": Book, n: Name] { 14 | b".addr = b.addr - n->Addr 15 | } 16 | 17 | fun lookup [b: Book, n: Name] : set Addr { 18 | n.(b.addr) 19 | } 20 | 21 | assert delUndoesAdd { 22 | all b, b", b"": Book, n: Name, a: Addr | 23 | add [b, b", n, a] and del [b", b"", n] 24 | implies 25 | b.addr = b"".addr 26 | } 27 | 28 | // This command generates an instance similar to Fig 2.6 29 | check delUndoesAdd for 3 30 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter2/addressBook1h.als: -------------------------------------------------------------------------------- 1 | module tour/addressBook1h ------- Page 14..16 2 | 3 | sig Name, Addr { } 4 | 5 | sig Book { 6 | addr: Name -> lone Addr 7 | } 8 | 9 | pred show [b: Book] { 10 | #b.addr > 1 11 | #Name.(b.addr) > 1 12 | } 13 | run show for 3 but 1 Book 14 | 15 | pred add [b, b": Book, n: Name, a: Addr] { 16 | b".addr = b.addr + n->a 17 | } 18 | 19 | pred del [b, b": Book, n: Name] { 20 | b".addr = b.addr - n->Addr 21 | } 22 | 23 | fun lookup [b: Book, n: Name] : set Addr { 24 | n.(b.addr) 25 | } 26 | 27 | pred showAdd [b, b": Book, n: Name, a: Addr] { 28 | add [b, b", n, a] 29 | #Name.(b".addr) > 1 30 | } 31 | run showAdd for 3 but 2 Book 32 | 33 | assert delUndoesAdd { 34 | all b, b", b"": Book, n: Name, a: Addr | 35 | no n.(b.addr) and add [b, b", n, a] and del [b", b"", n] 36 | implies 37 | b.addr = b"".addr 38 | } 39 | 40 | assert addIdempotent { 41 | all b, b", b"": Book, n: Name, a: Addr | 42 | add [b, b", n, a] and add [b", b"", n, a] 43 | implies 44 | b".addr = b"".addr 45 | } 46 | 47 | assert addLocal { 48 | all b, b": Book, n, n": Name, a: Addr | 49 | add [b, b", n, a] and n != n" 50 | implies 51 | lookup [b, n"] = lookup [b", n"] 52 | } 53 | 54 | // This command should not find any counterexample. 55 | check delUndoesAdd for 3 56 | 57 | // This command should not find any counterexample. 58 | check delUndoesAdd for 10 but 3 Book 59 | 60 | // This command should not find any counterexample. 61 | check addIdempotent for 3 62 | 63 | // This command should not find any counterexample. 64 | check addLocal for 3 but 2 Book 65 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter2/addressBook2a.als: -------------------------------------------------------------------------------- 1 | module tour/addressBook2a ----- Page 18 2 | 3 | abstract sig Target { } 4 | sig Addr extends Target { } 5 | abstract sig Name extends Target { } 6 | 7 | sig Alias, Group extends Name { } 8 | 9 | sig Book { 10 | addr: Name->Target 11 | } 12 | 13 | pred show [b:Book] { some b.addr } 14 | 15 | // This command generates an instance similar to Fig 2.9 16 | run show for 3 but 1 Book 17 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter2/addressBook2b.als: -------------------------------------------------------------------------------- 1 | module tour/addressBook2b ----- Page 19 2 | 3 | abstract sig Target { } 4 | sig Addr extends Target { } 5 | abstract sig Name extends Target { } 6 | 7 | sig Alias, Group extends Name { } 8 | 9 | sig Book { 10 | addr: Name->Target 11 | } { 12 | no n: Name | n in n.^addr 13 | } 14 | 15 | pred show [b:Book] { some b.addr } 16 | 17 | // This command generates an instance similar to Fig 2.10 18 | run show for 3 but 1 Book 19 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter2/addressBook2c.als: -------------------------------------------------------------------------------- 1 | module tour/addressBook2c ----- Page 20 2 | 3 | abstract sig Target { } 4 | sig Addr extends Target { } 5 | abstract sig Name extends Target { } 6 | 7 | sig Alias, Group extends Name { } 8 | 9 | sig Book { 10 | addr: Name->Target 11 | } { 12 | no n: Name | n in n.^addr 13 | } 14 | 15 | pred show [b:Book] { some Alias.(b.addr) } 16 | 17 | // This command generates an instance similar to Fig 2.11 18 | run show for 3 but 1 Book 19 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter2/addressBook2d.als: -------------------------------------------------------------------------------- 1 | module tour/addressBook2d ----- Page 21 2 | 3 | abstract sig Target { } 4 | sig Addr extends Target { } 5 | abstract sig Name extends Target { } 6 | 7 | sig Alias, Group extends Name { } 8 | 9 | sig Book { 10 | addr: Name->Target 11 | } { 12 | no n: Name | n in n.^addr 13 | all a: Alias | lone a.addr 14 | } 15 | 16 | pred show [b:Book] { some Alias.(b.addr) } 17 | 18 | // This command generates an instance similar to Fig 2.12 19 | run show for 3 but 1 Book 20 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter2/addressBook2e.als: -------------------------------------------------------------------------------- 1 | module tour/addressBook2e --- this is the final model in Fig 2.14 2 | 3 | abstract sig Target { } 4 | sig Addr extends Target { } 5 | abstract sig Name extends Target { } 6 | 7 | sig Alias, Group extends Name { } 8 | 9 | sig Book { 10 | names: set Name, 11 | addr: names->some Target 12 | } { 13 | no n: Name | n in n.^addr 14 | all a: Alias | lone a.addr 15 | } 16 | 17 | pred add [b, b": Book, n: Name, t: Target] { b".addr = b.addr + n->t } 18 | pred del [b, b": Book, n: Name, t: Target] { b".addr = b.addr - n->t } 19 | fun lookup [b: Book, n: Name] : set Addr { n.^(b.addr) & Addr } 20 | 21 | assert delUndoesAdd { 22 | all b, b", b"": Book, n: Name, t: Target | 23 | no n.(b.addr) and add [b, b", n, t] and del [b", b"", n, t] 24 | implies 25 | b.addr = b"".addr 26 | } 27 | 28 | // This should not find any counterexample. 29 | check delUndoesAdd for 3 30 | 31 | assert addIdempotent { 32 | all b, b", b"": Book, n: Name, t: Target | 33 | add [b, b", n, t] and add [b", b"", n, t] 34 | implies 35 | b".addr = b"".addr 36 | } 37 | 38 | // This should not find any counterexample. 39 | check addIdempotent for 3 40 | 41 | assert addLocal { 42 | all b, b": Book, n, n": Name, t: Target | 43 | add [b, b", n, t] and n != n" 44 | implies 45 | lookup [b, n"] = lookup [b", n"] 46 | } 47 | 48 | // This shows a counterexample similar to Fig 2.13 49 | check addLocal for 3 but 2 Book 50 | 51 | assert lookupYields { 52 | all b: Book, n: b.names | some lookup [b,n] 53 | } 54 | 55 | // This shows a counterexample similar to Fig 2.12 56 | check lookupYields for 4 but 1 Book 57 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter2/addressBook3a.als: -------------------------------------------------------------------------------- 1 | module tour/addressBook3a ----- Page 25 2 | 3 | open util/ordering [Book] as BookOrder 4 | 5 | abstract sig Target { } 6 | sig Addr extends Target { } 7 | abstract sig Name extends Target { } 8 | 9 | sig Alias, Group extends Name { } 10 | 11 | sig Book { 12 | names: set Name, 13 | addr: names->some Target 14 | } { 15 | no n: Name | n in n.^addr 16 | all a: Alias | lone a.addr 17 | } 18 | 19 | pred add [b, b": Book, n: Name, t: Target] { b".addr = b.addr + n->t } 20 | pred del [b, b": Book, n: Name, t: Target] { b".addr = b.addr - n->t } 21 | fun lookup [b: Book, n: Name] : set Addr { n.^(b.addr) & Addr } 22 | 23 | pred init [b: Book] { no b.addr } 24 | 25 | fact traces { 26 | init [first] 27 | all b: Book-last | 28 | let b" = b.next | 29 | some n: Name, t: Target | 30 | add [b, b", n, t] or del [b, b", n, t] 31 | } 32 | 33 | ------------------------------------------------------ 34 | 35 | pred show { } 36 | 37 | // This command generates an instance similar to Fig 2.15 38 | run show for 4 39 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter2/addressBook3b.als: -------------------------------------------------------------------------------- 1 | module tour/addressBook3b ----- Page 26 2 | 3 | open util/ordering [Book] as BookOrder 4 | 5 | abstract sig Target { } 6 | sig Addr extends Target { } 7 | abstract sig Name extends Target { } 8 | 9 | sig Alias, Group extends Name { } 10 | 11 | sig Book { 12 | names: set Name, 13 | addr: names->some Target 14 | } { 15 | no n: Name | n in n.^addr 16 | all a: Alias | lone a.addr 17 | } 18 | 19 | pred add [b, b": Book, n: Name, t: Target] { b".addr = b.addr + n->t } 20 | pred del [b, b": Book, n: Name, t: Target] { b".addr = b.addr - n->t } 21 | fun lookup [b: Book, n: Name] : set Addr { n.^(b.addr) & Addr } 22 | 23 | pred init [b: Book] { no b.addr } 24 | 25 | fact traces { 26 | init [first] 27 | all b: Book-last | 28 | let b" = b.next | 29 | some n: Name, t: Target | 30 | add [b, b", n, t] or del [b, b", n, t] 31 | } 32 | 33 | ------------------------------------------------------ 34 | 35 | assert delUndoesAdd { 36 | all b, b", b"": Book, n: Name, t: Target | 37 | no n.(b.addr) and add [b, b", n, t] and del [b", b"", n, t] 38 | implies 39 | b.addr = b"".addr 40 | } 41 | 42 | // This should not find any counterexample. 43 | check delUndoesAdd for 3 44 | 45 | ------------------------------------------------------ 46 | 47 | assert addIdempotent { 48 | all b, b", b"": Book, n: Name, t: Target | 49 | add [b, b", n, t] and add [b", b"", n, t] 50 | implies 51 | b".addr = b"".addr 52 | } 53 | 54 | // This should not find any counterexample. 55 | check addIdempotent for 3 56 | 57 | ------------------------------------------------------ 58 | 59 | assert addLocal { 60 | all b, b": Book, n, n": Name, t: Target | 61 | add [b, b", n, t] and n != n" 62 | implies 63 | lookup [b, n"] = lookup [b", n"] 64 | } 65 | 66 | // This should not find any counterexample. 67 | check addLocal for 3 but 2 Book 68 | 69 | ------------------------------------------------------ 70 | 71 | assert lookupYields { 72 | all b: Book, n: b.names | some lookup [b,n] 73 | } 74 | 75 | // This shows a counterexample similar to Fig 2.16 76 | check lookupYields for 3 but 4 Book 77 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter2/addressBook3c.als: -------------------------------------------------------------------------------- 1 | module tour/addressBook3c ----- Page 27 2 | 3 | open util/ordering [Book] as BookOrder 4 | 5 | abstract sig Target { } 6 | sig Addr extends Target { } 7 | abstract sig Name extends Target { } 8 | 9 | sig Alias, Group extends Name { } 10 | 11 | sig Book { 12 | names: set Name, 13 | addr: names->some Target 14 | } { 15 | no n: Name | n in n.^addr 16 | all a: Alias | lone a.addr 17 | } 18 | 19 | pred add [b, b": Book, n: Name, t: Target] { 20 | t in Addr or some lookup [b, Name&t] 21 | b".addr = b.addr + n->t 22 | } 23 | 24 | pred del [b, b": Book, n: Name, t: Target] { b".addr = b.addr - n->t } 25 | 26 | fun lookup [b: Book, n: Name] : set Addr { n.^(b.addr) & Addr } 27 | 28 | pred init [b: Book] { no b.addr } 29 | 30 | fact traces { 31 | init [first] 32 | all b: Book-last | 33 | let b" = b.next | 34 | some n: Name, t: Target | 35 | add [b, b", n, t] or del [b, b", n, t] 36 | } 37 | 38 | ------------------------------------------------------ 39 | 40 | assert delUndoesAdd { 41 | all b, b", b"": Book, n: Name, t: Target | 42 | no n.(b.addr) and add [b, b", n, t] and del [b", b"", n, t] 43 | implies 44 | b.addr = b"".addr 45 | } 46 | 47 | // This should not find any counterexample. 48 | check delUndoesAdd for 3 49 | 50 | ------------------------------------------------------ 51 | 52 | assert addIdempotent { 53 | all b, b", b"": Book, n: Name, t: Target | 54 | add [b, b", n, t] and add [b", b"", n, t] 55 | implies 56 | b".addr = b"".addr 57 | } 58 | 59 | // This should not find any counterexample. 60 | check addIdempotent for 3 61 | 62 | ------------------------------------------------------ 63 | 64 | assert addLocal { 65 | all b, b": Book, n, n": Name, t: Target | 66 | add [b, b", n, t] and n != n" 67 | implies 68 | lookup [b, n"] = lookup [b", n"] 69 | } 70 | 71 | // This should not find any counterexample. 72 | check addLocal for 3 but 2 Book 73 | 74 | ------------------------------------------------------ 75 | 76 | assert lookupYields { 77 | all b: Book, n: b.names | some lookup [b,n] 78 | } 79 | 80 | // This shows a counterexample similar to Fig 2.17 81 | check lookupYields for 3 but 4 Book 82 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter2/addressBook3d.als: -------------------------------------------------------------------------------- 1 | module tour/addressBook3d ----- this is the final model in fig 2.18 2 | 3 | open util/ordering [Book] as BookOrder 4 | 5 | abstract sig Target { } 6 | sig Addr extends Target { } 7 | abstract sig Name extends Target { } 8 | 9 | sig Alias, Group extends Name { } 10 | 11 | sig Book { 12 | names: set Name, 13 | addr: names->some Target 14 | } { 15 | no n: Name | n in n.^addr 16 | all a: Alias | lone a.addr 17 | } 18 | 19 | pred add [b, b": Book, n: Name, t: Target] { 20 | t in Addr or some lookup [b, Name&t] 21 | b".addr = b.addr + n->t 22 | } 23 | 24 | pred del [b, b": Book, n: Name, t: Target] { 25 | no b.addr.n or some n.(b.addr) - t 26 | b".addr = b.addr - n->t 27 | } 28 | 29 | fun lookup [b: Book, n: Name] : set Addr { n.^(b.addr) & Addr } 30 | 31 | pred init [b: Book] { no b.addr } 32 | 33 | fact traces { 34 | init [first] 35 | all b: Book-last | 36 | let b" = b.next | 37 | some n: Name, t: Target | 38 | add [b, b", n, t] or del [b, b", n, t] 39 | } 40 | 41 | ------------------------------------------------------ 42 | 43 | assert delUndoesAdd { 44 | all b, b", b"": Book, n: Name, t: Target | 45 | no n.(b.addr) and add [b, b", n, t] and del [b", b"", n, t] 46 | implies 47 | b.addr = b"".addr 48 | } 49 | 50 | // This should not find any counterexample. 51 | check delUndoesAdd for 3 52 | 53 | ------------------------------------------------------ 54 | 55 | assert addIdempotent { 56 | all b, b", b"": Book, n: Name, t: Target | 57 | add [b, b", n, t] and add [b", b"", n, t] 58 | implies 59 | b".addr = b"".addr 60 | } 61 | 62 | // This should not find any counterexample. 63 | check addIdempotent for 3 64 | 65 | ------------------------------------------------------ 66 | 67 | assert addLocal { 68 | all b, b": Book, n, n": Name, t: Target | 69 | add [b, b", n, t] and n != n" 70 | implies 71 | lookup [b, n"] = lookup [b", n"] 72 | } 73 | 74 | // This should not find any counterexample. 75 | check addLocal for 3 but 2 Book 76 | 77 | ------------------------------------------------------ 78 | 79 | assert lookupYields { 80 | all b: Book, n: b.names | some lookup [b,n] 81 | } 82 | 83 | // This should not find any counterexample. 84 | check lookupYields for 3 but 4 Book 85 | 86 | // This should not find any counterexample. 87 | check lookupYields for 6 88 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter2/theme.thm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter4/filesystem.als: -------------------------------------------------------------------------------- 1 | module chapter4/filesystem ----- The model from page 125 2 | 3 | abstract sig Object {} 4 | 5 | sig Dir extends Object {contents: set Object} 6 | 7 | one sig Root extends Dir { } 8 | 9 | sig File extends Object {} 10 | 11 | fact { 12 | Object in Root.*contents 13 | } 14 | 15 | assert SomeDir { 16 | all o: Object - Root | some contents.o 17 | } 18 | check SomeDir // This assertion is valid 19 | 20 | assert RootTop { 21 | no o: Object | Root in o.contents 22 | } 23 | check RootTop // This assertion should produce a counterexample 24 | 25 | assert FileInDir { 26 | all f: File | some contents.f 27 | } 28 | check FileInDir // This assertion is valid 29 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter4/grandpa1.als: -------------------------------------------------------------------------------- 1 | module language/grandpa1 ---- Page 84, 85 2 | 3 | abstract sig Person { 4 | father: lone Man, 5 | mother: lone Woman 6 | } 7 | 8 | sig Man extends Person { 9 | wife: lone Woman 10 | } 11 | 12 | sig Woman extends Person { 13 | husband: lone Man 14 | } 15 | 16 | fact { 17 | no p: Person | p in p.^(mother+father) 18 | wife = ~husband 19 | } 20 | 21 | assert NoSelfFather { 22 | no m: Man | m = m.father 23 | } 24 | 25 | // This should not find any counterexample. 26 | check NoSelfFather 27 | 28 | fun grandpas [p: Person] : set Person { 29 | p.(mother+father).father 30 | } 31 | 32 | pred ownGrandpa [p: Person] { 33 | p in p.grandpas 34 | } 35 | 36 | // This should not find any instance. 37 | run ownGrandpa for 4 Person 38 | 39 | assert NoSelfGrandpa { 40 | no p: Person | p in p.grandpas 41 | } 42 | 43 | // This should not find any counterexample 44 | check NoSelfGrandpa for 4 Person 45 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter4/grandpa2.als: -------------------------------------------------------------------------------- 1 | module language/grandpa2 ---- Page 86 2 | 3 | abstract sig Person { 4 | father: lone Man, 5 | mother: lone Woman 6 | } 7 | 8 | sig Man extends Person { 9 | wife: lone Woman 10 | } 11 | 12 | sig Woman extends Person { 13 | husband: lone Man 14 | } 15 | 16 | fact { 17 | no p: Person | p in p.^(mother+father) 18 | wife = ~husband 19 | } 20 | 21 | assert NoSelfFather { 22 | no m: Man | m = m.father 23 | } 24 | 25 | // This should not find any counterexample. 26 | check NoSelfFather 27 | 28 | fun grandpas [p: Person] : set Person { 29 | let parent = mother + father + father.wife + mother.husband | 30 | p.parent.parent & Man 31 | } 32 | 33 | pred ownGrandpa [p: Person] { 34 | p in p.grandpas 35 | } 36 | 37 | // This generates an instance similar to Fig 4.2 38 | run ownGrandpa for 4 Person 39 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter4/grandpa3.als: -------------------------------------------------------------------------------- 1 | module language/grandpa3 ---- the final model in fig 4.4 2 | 3 | abstract sig Person { 4 | father: lone Man, 5 | mother: lone Woman 6 | } 7 | 8 | sig Man extends Person { 9 | wife: lone Woman 10 | } 11 | 12 | sig Woman extends Person { 13 | husband: lone Man 14 | } 15 | 16 | fact Biology { 17 | no p: Person | p in p.^(mother+father) 18 | } 19 | 20 | fact Terminology { 21 | wife = ~husband 22 | } 23 | 24 | fact SocialConvention { 25 | no (wife+husband) & ^(mother+father) 26 | } 27 | 28 | ------------------------------------------ 29 | 30 | assert NoSelfFather { 31 | no m: Man | m = m.father 32 | } 33 | 34 | // This should not find any counterexample. 35 | check NoSelfFather 36 | 37 | ------------------------------------------ 38 | 39 | fun grandpas [p: Person] : set Person { 40 | let parent = mother + father + father.wife + mother.husband | 41 | p.parent.parent & Man 42 | } 43 | 44 | pred ownGrandpa [p: Person] { 45 | p in p.grandpas 46 | } 47 | 48 | // This generates an instance similar to Fig 4.3 49 | run ownGrandpa for 4 Person 50 | 51 | ------------------------------------------ 52 | 53 | pred SocialConvention1 { 54 | no (wife + husband) & ^(mother + father) 55 | } 56 | 57 | pred SocialConvention2 { 58 | let parent = mother + father { 59 | no m: Man | some m.wife and m.wife in m.*parent.mother 60 | no w: Woman | some w.husband and w.husband in w.*parent.father 61 | } 62 | } 63 | 64 | // This assertion was described on page 90. 65 | assert Same { 66 | SocialConvention1 iff SocialConvention2 67 | } 68 | 69 | // This should not find any counterexample 70 | check Same 71 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter4/lights.als: -------------------------------------------------------------------------------- 1 | module chapter4/lights ----- The model from page 127 2 | 3 | abstract sig Color {} 4 | 5 | one sig Red, Yellow, Green extends Color {} 6 | 7 | fun colorSequence: Color -> Color { 8 | Color <: iden + Red->Green + Green->Yellow + Yellow->Red 9 | } 10 | 11 | sig Light {} 12 | sig LightState {color: Light -> one Color} 13 | sig Junction {lights: set Light} 14 | 15 | fun redLights [s: LightState]: set Light { s.color.Red } 16 | 17 | pred mostlyRed [s: LightState, j: Junction] { 18 | lone j.lights - redLights[s] 19 | } 20 | 21 | pred trans [s, s": LightState, j: Junction] { 22 | lone x: j.lights | s.color[x] != s".color[x] 23 | all x: j.lights | 24 | let step = s.color[x] -> s".color[x] { 25 | step in colorSequence 26 | step in Red->(Color-Red) => j.lights in redLights[s] 27 | } 28 | } 29 | 30 | assert Safe { 31 | all s, s": LightState, j: Junction | 32 | mostlyRed [s, j] and trans [s, s", j] => mostlyRed [s", j] 33 | } 34 | 35 | check Safe for 3 but 1 Junction 36 | 37 | //assert ColorSequenceDeterministic { 38 | // all c: Color | lone c.colorSequence 39 | // } 40 | // 41 | //check ColorSequenceDeterministic 42 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter5/addressBook.als: -------------------------------------------------------------------------------- 1 | module chapter5/addressBook --- the model in fig 5.1 2 | 3 | abstract sig Target {} 4 | 5 | sig Addr extends Target {} 6 | sig Name extends Target {} 7 | sig Book {addr: Name -> Target} 8 | 9 | fact Acyclic {all b: Book | no n: Name | n in n.^(b.addr)} 10 | 11 | pred add [b, b": Book, n: Name, t: Target] { 12 | b".addr = b.addr + n -> t 13 | } 14 | 15 | // This command should produce an instance similar to Fig 5.2 16 | run add for 3 but 2 Book 17 | 18 | fun lookup [b: Book, n: Name]: set Addr {n.^(b.addr) & Addr} 19 | 20 | assert addLocal { 21 | all b,b": Book, n,n": Name, t: Target | 22 | add [b,b",n,t] and n != n" => lookup [b,n"] = lookup [b",n"] 23 | } 24 | 25 | // This command should produce a counterexample similar to Fig 5.3 26 | check addLocal for 3 but 2 Book 27 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter5/lists.als: -------------------------------------------------------------------------------- 1 | module chapter5/lists ---- page 157 2 | 3 | some sig Element {} 4 | 5 | abstract sig List {} 6 | one sig EmptyList extends List {} 7 | sig NonEmptyList extends List { 8 | element: Element, 9 | rest: List 10 | } 11 | 12 | fact ListGenerator { 13 | all list: List, e: Element | 14 | some list": List | list".rest = list and list".element = e 15 | } 16 | 17 | assert FalseAssertion { 18 | all list: List | list != list 19 | } 20 | 21 | // This check finds no counterexample since 22 | // the only possible counterexamples are infinite. 23 | check FalseAssertion 24 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter5/sets1.als: -------------------------------------------------------------------------------- 1 | module chapter5/sets1 ----- page 156 2 | 3 | sig Set { 4 | elements: set Element 5 | } 6 | 7 | sig Element {} 8 | 9 | assert Closed { 10 | all s0, s1: Set | 11 | some s2: Set | 12 | s2.elements = s0.elements + s1.elements 13 | } 14 | 15 | // This check should produce a counterexample 16 | check Closed 17 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter5/sets2.als: -------------------------------------------------------------------------------- 1 | module chapter5/sets2 ----- page 157 2 | 3 | sig Set { 4 | elements: set Element 5 | } 6 | 7 | sig Element {} 8 | 9 | assert Closed { 10 | all s0, s1: Set | 11 | some s2: Set | 12 | s2.elements = s0.elements + s1.elements 13 | } 14 | 15 | fact SetGenerator { 16 | some s: Set | no s.elements 17 | all s: Set, e: Element | some s": Set | s".elements = s.elements + e 18 | } 19 | 20 | // This check should not produce a counterexample 21 | check Closed for 4 Element, 16 Set 22 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter6/hotel.thm: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter6/hotel1.als: -------------------------------------------------------------------------------- 1 | module chapter6/hotel1 --- the model up to the top of page 191 2 | 3 | open util/ordering[Time] as to 4 | open util/ordering[Key] as ko 5 | 6 | sig Key {} 7 | sig Time {} 8 | 9 | sig Room { 10 | keys: set Key, 11 | currentKey: keys one -> Time 12 | } 13 | 14 | fact DisjointKeySets { 15 | -- each key belongs to at most one room 16 | Room<:keys in Room lone-> Key 17 | } 18 | 19 | one sig FrontDesk { 20 | lastKey: (Room -> lone Key) -> Time, 21 | occupant: (Room -> Guest) -> Time 22 | } 23 | 24 | sig Guest { 25 | keys: Key -> Time 26 | } 27 | 28 | fun nextKey [k: Key, ks: set Key]: set Key { 29 | min [k.nexts & ks] 30 | } 31 | 32 | pred init [t: Time] { 33 | no Guest.keys.t 34 | no FrontDesk.occupant.t 35 | all r: Room | FrontDesk.lastKey.t [r] = r.currentKey.t 36 | } 37 | 38 | pred entry [t, t": Time, g: Guest, r: Room, k: Key] { 39 | k in g.keys.t 40 | let ck = r.currentKey | 41 | (k = ck.t and ck.t" = ck.t) or 42 | (k = nextKey[ck.t, r.keys] and ck.t" = k) 43 | noRoomChangeExcept [t, t", r] 44 | noGuestChangeExcept [t, t", none] 45 | noFrontDeskChange [t, t"] 46 | } 47 | 48 | pred noFrontDeskChange [t, t": Time] { 49 | FrontDesk.lastKey.t = FrontDesk.lastKey.t" 50 | FrontDesk.occupant.t = FrontDesk.occupant.t" 51 | } 52 | 53 | pred noRoomChangeExcept [t, t": Time, rs: set Room] { 54 | all r: Room - rs | r.currentKey.t = r.currentKey.t" 55 | } 56 | 57 | pred noGuestChangeExcept [t, t": Time, gs: set Guest] { 58 | all g: Guest - gs | g.keys.t = g.keys.t" 59 | } 60 | 61 | pred checkout [t, t": Time, g: Guest] { 62 | let occ = FrontDesk.occupant { 63 | some occ.t.g 64 | occ.t" = occ.t - Room ->g 65 | } 66 | FrontDesk.lastKey.t = FrontDesk.lastKey.t" 67 | noRoomChangeExcept [t, t", none] 68 | noGuestChangeExcept [t, t", none] 69 | } 70 | 71 | pred checkin [t, t": Time, g: Guest, r: Room, k: Key] { 72 | g.keys.t" = g.keys.t + k 73 | let occ = FrontDesk.occupant { 74 | no occ.t [r] 75 | occ.t" = occ.t + r -> g 76 | } 77 | let lk = FrontDesk.lastKey { 78 | lk.t" = lk.t ++ r -> k 79 | k = nextKey [lk.t [r], r.keys] 80 | } 81 | noRoomChangeExcept [t, t", none] 82 | noGuestChangeExcept [t, t", g] 83 | } 84 | 85 | fact traces { 86 | init [first] 87 | all t: Time-last | let t" = t.next | 88 | some g: Guest, r: Room, k: Key | 89 | entry [t, t", g, r, k] 90 | or checkin [t, t", g, r, k] 91 | or checkout [t, t", g] 92 | } 93 | 94 | assert NoBadEntry { 95 | all t: Time, r: Room, g: Guest, k: Key | 96 | let t" = t.next, o = FrontDesk.occupant.t[r] | 97 | entry [t, t", g, r, k] and some o => g in o 98 | } 99 | 100 | // This generates a counterexample similar to Fig 6.6 101 | check NoBadEntry for 3 but 2 Room, 2 Guest, 5 Time 102 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter6/hotel2.als: -------------------------------------------------------------------------------- 1 | module chapter6/hotel2 --- the final model in Fig 6.7 2 | 3 | open util/ordering[Time] as to 4 | open util/ordering[Key] as ko 5 | 6 | sig Key {} 7 | sig Time {} 8 | 9 | sig Room { 10 | keys: set Key, 11 | currentKey: keys one -> Time 12 | } 13 | 14 | fact DisjointKeySets { 15 | -- each key belongs to at most one room 16 | Room<:keys in Room lone-> Key 17 | } 18 | 19 | one sig FrontDesk { 20 | lastKey: (Room -> lone Key) -> Time, 21 | occupant: (Room -> Guest) -> Time 22 | } 23 | 24 | sig Guest { 25 | keys: Key -> Time 26 | } 27 | 28 | fun nextKey [k: Key, ks: set Key]: set Key { 29 | min [k.nexts & ks] 30 | } 31 | 32 | pred init [t: Time] { 33 | no Guest.keys.t 34 | no FrontDesk.occupant.t 35 | all r: Room | FrontDesk.lastKey.t [r] = r.currentKey.t 36 | } 37 | 38 | pred entry [t, t": Time, g: Guest, r: Room, k: Key] { 39 | k in g.keys.t 40 | let ck = r.currentKey | 41 | (k = ck.t and ck.t" = ck.t) or 42 | (k = nextKey[ck.t, r.keys] and ck.t" = k) 43 | noRoomChangeExcept [t, t", r] 44 | noGuestChangeExcept [t, t", none] 45 | noFrontDeskChange [t, t"] 46 | } 47 | 48 | pred noFrontDeskChange [t, t": Time] { 49 | FrontDesk.lastKey.t = FrontDesk.lastKey.t" 50 | FrontDesk.occupant.t = FrontDesk.occupant.t" 51 | } 52 | 53 | pred noRoomChangeExcept [t, t": Time, rs: set Room] { 54 | all r: Room - rs | r.currentKey.t = r.currentKey.t" 55 | } 56 | 57 | pred noGuestChangeExcept [t, t": Time, gs: set Guest] { 58 | all g: Guest - gs | g.keys.t = g.keys.t" 59 | } 60 | 61 | pred checkout [t, t": Time, g: Guest] { 62 | let occ = FrontDesk.occupant { 63 | some occ.t.g 64 | occ.t" = occ.t - Room ->g 65 | } 66 | FrontDesk.lastKey.t = FrontDesk.lastKey.t" 67 | noRoomChangeExcept [t, t", none] 68 | noGuestChangeExcept [t, t", none] 69 | } 70 | 71 | pred checkin [t, t": Time, g: Guest, r: Room, k: Key] { 72 | g.keys.t" = g.keys.t + k 73 | let occ = FrontDesk.occupant { 74 | no occ.t [r] 75 | occ.t" = occ.t + r -> g 76 | } 77 | let lk = FrontDesk.lastKey { 78 | lk.t" = lk.t ++ r -> k 79 | k = nextKey [lk.t [r], r.keys] 80 | } 81 | noRoomChangeExcept [t, t", none] 82 | noGuestChangeExcept [t, t", g] 83 | } 84 | 85 | fact traces { 86 | init [first] 87 | all t: Time-last | let t" = t.next | 88 | some g: Guest, r: Room, k: Key | 89 | entry [t, t", g, r, k] 90 | or checkin [t, t", g, r, k] 91 | or checkout [t, t", g] 92 | } 93 | 94 | fact NoIntervening { 95 | all t: Time-last | let t" = t.next, t" = t".next | 96 | all g: Guest, r: Room, k: Key | 97 | checkin [t, t", g, r, k] => (entry [t", t", g, r, k] or no t") 98 | } 99 | 100 | assert NoBadEntry { 101 | all t: Time, r: Room, g: Guest, k: Key | 102 | let t" = t.next, o = FrontDesk.occupant.t[r] | 103 | entry [t, t", g, r, k] and some o => g in o 104 | } 105 | 106 | // After adding the NoIntervening fact, 107 | // these commands no longer generate counterexamples 108 | check NoBadEntry for 3 but 2 Room, 2 Guest, 5 Time 109 | check NoBadEntry for 3 but 3 Room, 3 Guest, 7 Time 110 | check NoBadEntry for 5 but 3 Room, 3 Guest, 9 Time 111 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter6/hotel3.als: -------------------------------------------------------------------------------- 1 | module chapter6/hotel3 --- model in Fig 6.10 without the NonIntervening fact 2 | 3 | open util/ordering[Time] as to 4 | open util/ordering[Key] as ko 5 | 6 | sig Key, Time {} 7 | 8 | sig Room { 9 | keys: set Key, 10 | currentKey: keys one -> Time 11 | } 12 | 13 | fact { 14 | Room <: keys in Room lone -> Key 15 | } 16 | 17 | one sig FrontDesk { 18 | lastKey: (Room -> lone Key) -> Time, 19 | occupant: (Room -> Guest) -> Time 20 | } 21 | 22 | sig Guest { 23 | keys: Key -> Time 24 | } 25 | 26 | fun nextKey [k: Key, ks: set Key]: set Key { 27 | min [k.nexts & ks] 28 | } 29 | 30 | pred init [t: Time] { 31 | no Guest.keys.t 32 | no FrontDesk.occupant.t 33 | all r: Room | FrontDesk.lastKey.t [r] = r.currentKey.t 34 | } 35 | 36 | abstract sig Event { 37 | pre, post: Time, 38 | guest: Guest 39 | } 40 | 41 | abstract sig RoomKeyEvent extends Event { 42 | room: Room, 43 | key: Key 44 | } 45 | 46 | sig Entry extends RoomKeyEvent { } { 47 | key in guest.keys.pre 48 | let ck = room.currentKey | 49 | (key = ck.pre and ck.post = ck.pre) or 50 | (key = nextKey[ck.pre, room.keys] and ck.post = key) 51 | currentKey.post = currentKey.pre ++ room->key 52 | } 53 | 54 | sig Checkin extends RoomKeyEvent { } { 55 | keys.post = keys.pre + guest -> key 56 | let occ = FrontDesk.occupant { 57 | no occ.pre [room] 58 | occ.post = occ.pre + room -> guest 59 | } 60 | let lk = FrontDesk.lastKey { 61 | lk.post = lk.pre ++ room -> key 62 | key = nextKey [lk.pre [room], room.keys] 63 | } 64 | } 65 | 66 | sig Checkout extends Event { } { 67 | let occ = FrontDesk.occupant { 68 | some occ.pre.guest 69 | occ.post = occ.pre - Room -> guest 70 | } 71 | } 72 | 73 | fact Traces { 74 | init [first] 75 | all t: Time-last | 76 | let t" = t.next | 77 | some e: Event { 78 | e.pre = t and e.post = t" 79 | currentKey.t != currentKey.t" => e in Entry 80 | occupant.t != occupant.t" => e in Checkin + Checkout 81 | (lastKey.t != lastKey.t" or keys.t != keys.t") => e in Checkin 82 | } 83 | } 84 | 85 | assert NoBadEntry { 86 | all e: Entry | 87 | let o=FrontDesk.occupant.(e.pre) [e.room] | 88 | some o => e.guest in o 89 | } 90 | 91 | // This generates a counterexample similar to Fig 6.13 92 | check NoBadEntry for 5 but 3 Room, 3 Guest, 5 Time, 4 Event 93 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter6/hotel4.als: -------------------------------------------------------------------------------- 1 | module chapter6/hotel4 --- model in Fig 6.10 with the NonIntervening fact 2 | 3 | open util/ordering[Time] as to 4 | open util/ordering[Key] as ko 5 | 6 | sig Key, Time {} 7 | 8 | sig Room { 9 | keys: set Key, 10 | currentKey: keys one -> Time 11 | } 12 | 13 | fact { 14 | Room <: keys in Room lone -> Key 15 | } 16 | 17 | one sig FrontDesk { 18 | lastKey: (Room -> lone Key) -> Time, 19 | occupant: (Room -> Guest) -> Time 20 | } 21 | 22 | sig Guest { 23 | keys: Key -> Time 24 | } 25 | 26 | fun nextKey [k: Key, ks: set Key]: set Key { 27 | min [k.nexts & ks] 28 | } 29 | 30 | pred init [t: Time] { 31 | no Guest.keys.t 32 | no FrontDesk.occupant.t 33 | all r: Room | FrontDesk.lastKey.t [r] = r.currentKey.t 34 | } 35 | 36 | abstract sig Event { 37 | pre, post: Time, 38 | guest: Guest 39 | } 40 | 41 | abstract sig RoomKeyEvent extends Event { 42 | room: Room, 43 | key: Key 44 | } 45 | 46 | sig Entry extends RoomKeyEvent { } { 47 | key in guest.keys.pre 48 | let ck = room.currentKey | 49 | (key = ck.pre and ck.post = ck.pre) or 50 | (key = nextKey[ck.pre, room.keys] and ck.post = key) 51 | currentKey.post = currentKey.pre ++ room->key 52 | } 53 | 54 | sig Checkin extends RoomKeyEvent { } { 55 | keys.post = keys.pre + guest -> key 56 | let occ = FrontDesk.occupant { 57 | no occ.pre [room] 58 | occ.post = occ.pre + room -> guest 59 | } 60 | let lk = FrontDesk.lastKey { 61 | lk.post = lk.pre ++ room -> key 62 | key = nextKey [lk.pre [room], room.keys] 63 | } 64 | } 65 | 66 | sig Checkout extends Event { } { 67 | let occ = FrontDesk.occupant { 68 | some occ.pre.guest 69 | occ.post = occ.pre - Room -> guest 70 | } 71 | } 72 | 73 | fact Traces { 74 | init [first] 75 | all t: Time-last | 76 | let t" = t.next | 77 | some e: Event { 78 | e.pre = t and e.post = t" 79 | currentKey.t != currentKey.t" => e in Entry 80 | occupant.t != occupant.t" => e in Checkin + Checkout 81 | (lastKey.t != lastKey.t" or keys.t != keys.t") => e in Checkin 82 | } 83 | } 84 | 85 | assert NoBadEntry { 86 | all e: Entry | 87 | let o=FrontDesk.occupant.(e.pre) [e.room] | 88 | some o => e.guest in o 89 | } 90 | 91 | fact NoIntervening { 92 | all c: Checkin | 93 | c.post = last 94 | or some e: Entry { 95 | e.pre = c.post 96 | e.room = c.room 97 | e.guest = c.guest 98 | } 99 | } 100 | 101 | // After adding the NoIntervening fact, 102 | // this command no longer generates a counterexample 103 | check NoBadEntry for 5 but 3 Room, 3 Guest, 9 Time, 8 Event 104 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter6/mediaAssets.als: -------------------------------------------------------------------------------- 1 | module chapter6/mediaAssets 2 | 3 | sig ApplicationState { 4 | catalogs: set Catalog, 5 | catalogState: catalogs -> one CatalogState, 6 | currentCatalog: catalogs, 7 | buffer: set Asset 8 | } 9 | 10 | sig Catalog, Asset {} 11 | 12 | sig CatalogState { 13 | assets: set Asset, 14 | disj hidden, showing: set assets, 15 | selection: set assets + Undefined 16 | } { 17 | hidden+showing = assets 18 | } 19 | 20 | one sig Undefined {} 21 | 22 | pred catalogInv [cs: CatalogState] { 23 | cs.selection = Undefined or (some cs.selection and cs.selection in cs.showing) 24 | } 25 | 26 | pred appInv [xs: ApplicationState] { 27 | all cs: xs.catalogs | catalogInv [xs.catalogState[cs]] 28 | } 29 | 30 | pred showSelected [cs, cs": CatalogState] { 31 | cs.selection != Undefined 32 | cs".showing = cs.selection 33 | cs".selection = cs.selection 34 | cs".assets = cs.assets 35 | } 36 | 37 | pred hideSelected [cs, cs": CatalogState] { 38 | cs.selection != Undefined 39 | cs".hidden = cs.hidden + cs.selection 40 | cs".selection = Undefined 41 | cs".assets = cs.assets 42 | } 43 | 44 | pred cut [xs, xs": ApplicationState] { 45 | let cs = xs.currentCatalog.(xs.catalogState), sel = cs.selection { 46 | sel != Undefined 47 | xs".buffer = sel 48 | some cs": CatalogState { 49 | cs".assets = cs.assets - sel 50 | cs".showing = cs.showing - sel 51 | cs".selection = Undefined 52 | xs".catalogState = xs.catalogState ++ xs.currentCatalog -> cs" 53 | } 54 | } 55 | xs".catalogs = xs.catalogs 56 | xs".currentCatalog = xs.currentCatalog 57 | } 58 | 59 | pred paste [xs, xs": ApplicationState] { 60 | let cs = xs.currentCatalog.(xs.catalogState), buf = xs.buffer { 61 | xs".buffer = buf 62 | some cs": CatalogState { 63 | cs".assets = cs.assets + buf 64 | cs".showing = cs.showing + (buf - cs.assets) 65 | cs".selection = buf - cs.assets 66 | xs".catalogState = xs.catalogState ++ xs.currentCatalog -> cs" 67 | } 68 | } 69 | xs".catalogs = xs.catalogs 70 | xs".currentCatalog = xs.currentCatalog 71 | } 72 | 73 | assert HidePreservesInv { 74 | all cs, cs": CatalogState | 75 | catalogInv [cs] and hideSelected [cs, cs"] => catalogInv [cs"] 76 | } 77 | 78 | // This check should not find any counterexample 79 | check HidePreservesInv 80 | 81 | pred sameApplicationState [xs, xs": ApplicationState] { 82 | xs".catalogs = xs.catalogs 83 | all c: xs.catalogs | sameCatalogState [c.(xs.catalogState), c.(xs".catalogState)] 84 | xs".currentCatalog = xs.currentCatalog 85 | xs".buffer = xs.buffer 86 | } 87 | 88 | pred sameCatalogState [cs, cs": CatalogState] { 89 | cs".assets = cs.assets 90 | cs".showing = cs.showing 91 | cs".selection = cs.selection 92 | } 93 | 94 | assert CutPaste { 95 | all xs, xs", xs"": ApplicationState | 96 | (appInv [xs] and cut [xs, xs"] and paste [xs", xs""]) => sameApplicationState [xs, xs""] 97 | } 98 | 99 | // This check should find a counterexample 100 | check CutPaste 101 | 102 | assert PasteCut { 103 | all xs, xs", xs"": ApplicationState | 104 | (appInv [xs] and paste [xs, xs"] and cut [xs", xs""]) => sameApplicationState [xs, xs""] 105 | } 106 | 107 | // This check should find a counterexample 108 | check PasteCut 109 | 110 | assert PasteNotAffectHidden { 111 | all xs, xs": ApplicationState | 112 | (appInv [xs] and paste [xs, xs"]) => 113 | let c = xs.currentCatalog | xs".catalogState[c].hidden = xs.catalogState[c].hidden 114 | } 115 | 116 | // This check should not find any counterexample 117 | check PasteNotAffectHidden 118 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter6/memory/abstractMemory.als: -------------------------------------------------------------------------------- 1 | module chapter6/memory/abstractMemory [Addr, Data] ----- the model from page 217 2 | 3 | sig Memory { 4 | data: Addr -> lone Data 5 | } 6 | 7 | pred init [m: Memory] { 8 | no m.data 9 | } 10 | 11 | pred write [m, m": Memory, a: Addr, d: Data] { 12 | m".data = m.data ++ a -> d 13 | } 14 | 15 | pred read [m: Memory, a: Addr, d: Data] { 16 | let d" = m.data [a] | some d" implies d = d" 17 | } 18 | 19 | fact Canonicalize { 20 | no disj m, m": Memory | m.data = m".data 21 | } 22 | 23 | // This command should not find any counterexample 24 | WriteRead: check { 25 | all m, m": Memory, a: Addr, d1, d2: Data | 26 | write [m, m", a, d1] and read [m", a, d2] => d1 = d2 27 | } 28 | 29 | // This command should not find any counterexample 30 | WriteIdempotent: check { 31 | all m, m", m"": Memory, a: Addr, d: Data | 32 | write [m, m", a, d] and write [m", m"", a, d] => m" = m"" 33 | } 34 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter6/memory/cacheMemory.als: -------------------------------------------------------------------------------- 1 | module chapter6/memory/cacheMemory [Addr, Data] ----- the model from page 219 2 | 3 | sig CacheSystem { 4 | main, cache: Addr -> lone Data 5 | } 6 | 7 | pred init [c: CacheSystem] { 8 | no c.main + c.cache 9 | } 10 | 11 | pred write [c, c": CacheSystem, a: Addr, d: Data] { 12 | c".main = c.main 13 | c".cache = c.cache ++ a -> d 14 | } 15 | 16 | pred read [c: CacheSystem, a: Addr, d: Data] { 17 | some d 18 | d = c.cache [a] 19 | } 20 | 21 | pred load [c, c": CacheSystem] { 22 | some addrs: set c.main.Data - c.cache.Data | 23 | c".cache = c.cache ++ addrs <: c.main 24 | c".main = c.main 25 | } 26 | 27 | pred flush [c, c": CacheSystem] { 28 | some addrs: some c.cache.Data { 29 | c".main = c.main ++ addrs <: c.cache 30 | c".cache = c.cache - addrs -> Data 31 | } 32 | } 33 | 34 | // This command should not find any counterexample 35 | LoadNotObservable: check { 36 | all c, c", c"": CacheSystem, a1, a2: Addr, d1, d2, d3: Data | 37 | { 38 | read [c, a2, d2] 39 | write [c, c", a1, d1] 40 | load [c", c"] 41 | read [c"", a2, d3] 42 | } implies d3 = (a1=a2 => d1 else d2) 43 | } 44 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter6/memory/checkCache.als: -------------------------------------------------------------------------------- 1 | module chapter6/memory/checkCache [Addr, Data] 2 | 3 | open chapter6/memory/cacheMemory [Addr, Data] as cache 4 | open chapter6/memory/abstractMemory [Addr, Data] as amemory 5 | 6 | fun alpha [c: CacheSystem]: Memory { 7 | {m: Memory | m.data = c.main ++ c.cache} 8 | } 9 | 10 | // This check should not produce a counterexample 11 | ReadOK: check { 12 | // introduction of m, m" ensures that they exist, and gives witnesses if counterexample 13 | all c: CacheSystem, a: Addr, d: Data, m: Memory | 14 | cache/read [c, a, d] and m = alpha [c] => amemory/read [m, a, d] 15 | } 16 | 17 | // This check should not produce a counterexample 18 | WriteOK: check { 19 | all c, c": CacheSystem, a: Addr, d: Data, m, m": Memory | 20 | cache/write [c, c", a, d] and m = alpha [c] and m" = alpha [c"] 21 | => amemory/write [m, m", a, d] 22 | } 23 | 24 | // This check should not produce a counterexample 25 | LoadOK: check { 26 | all c, c": CacheSystem, m, m": Memory | 27 | cache/load [c, c"] and m = alpha [c] and m" = alpha [c"] => m = m" 28 | } 29 | 30 | // This check should not produce a counterexample 31 | FlushOK: check { 32 | all c, c": CacheSystem, m, m": Memory | 33 | cache/flush [c, c"] and m = alpha [c] and m" = alpha [c"] => m = m" 34 | } 35 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter6/memory/checkFixedSize.als: -------------------------------------------------------------------------------- 1 | module chapter6/memory/checkFixedSize [Addr, Data] 2 | 3 | open chapter6/memory/fixedSizeMemory_H [Addr, Data] as fmemory 4 | open chapter6/memory/abstractMemory [Addr, Data] as amemory 5 | 6 | // define abstraction function from history-extended concrete state to abstract state 7 | pred alpha [fm: fmemory/Memory_H, am: amemory/Memory] { 8 | am.data = fm.data - (fm.unwritten -> Data) 9 | } 10 | 11 | // This check should not find a counterexample 12 | initOk: check { 13 | all fm: fmemory/Memory_H, am: amemory/Memory | 14 | fmemory/init [fm] and alpha [fm, am] => amemory/init [am] 15 | } 16 | 17 | // This check should not find a counterexample 18 | readOk: check { 19 | all fm: fmemory/Memory_H, a: Addr, d: Data, am: amemory/Memory | 20 | fmemory/read [fm, a, d] and alpha [fm, am] => amemory/read [am, a, d] 21 | } 22 | 23 | // This check should not find a counterexample 24 | writeOk: check { 25 | all fm, fm": fmemory/Memory_H, a: Addr, d: Data, am, am": amemory/Memory | 26 | fmemory/write [fm, fm", a, d] and alpha [fm, am] and alpha [fm", am"] 27 | implies amemory/write [am, am", a, d] 28 | } 29 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter6/memory/fixedSizeMemory.als: -------------------------------------------------------------------------------- 1 | module chapter6/memory/fixedSizeMemory [Addr, Data] 2 | 3 | sig Memory { 4 | data: Addr -> one Data 5 | } 6 | 7 | pred init [m: Memory] { 8 | // This predicate is empty in order to allow non-deterministic initialization 9 | } 10 | 11 | pred write [m, m": Memory, a: Addr, d: Data] { 12 | m".data = m.data ++ a -> d 13 | } 14 | 15 | pred read [m: Memory, a: Addr, d: Data] { 16 | d = m.data [a] 17 | } 18 | 19 | fact Canonicalize { 20 | no disj m, m": Memory | m.data = m".data 21 | } 22 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter6/memory/fixedSizeMemory_H.als: -------------------------------------------------------------------------------- 1 | module chapter6/memory/fixedSizeMemory_H [Addr, Data] 2 | 3 | open chapter6/memory/fixedSizeMemory [Addr, Data] as memory 4 | 5 | sig Memory_H extends memory/Memory { 6 | unwritten: set Addr 7 | } 8 | 9 | pred init [m: Memory_H] { 10 | memory/init [m] 11 | m.unwritten = Addr 12 | } 13 | 14 | pred read [m: Memory_H, a: Addr, d: Data] { 15 | memory/read [m, a, d] 16 | } 17 | 18 | pred write [m, m": Memory_H, a: Addr, d: Data] { 19 | memory/write [m, m", a, d] 20 | m".unwritten = m.unwritten - a 21 | } 22 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter6/ringElection.thm: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter6/ringElection1.als: -------------------------------------------------------------------------------- 1 | module chapter6/ringElection1 --- the version up to the top of page 181 2 | 3 | open util/ordering[Time] as TO 4 | open util/ordering[Process] as PO 5 | 6 | sig Time {} 7 | 8 | sig Process { 9 | succ: Process, 10 | toSend: Process -> Time, 11 | elected: set Time 12 | } 13 | 14 | fact ring { 15 | all p: Process | Process in p.^succ 16 | } 17 | 18 | pred init [t: Time] { 19 | all p: Process | p.toSend.t = p 20 | } 21 | 22 | pred step [t, t": Time, p: Process] { 23 | let from = p.toSend, to = p.succ.toSend | 24 | some id: from.t { 25 | from.t" = from.t - id 26 | to.t" = to.t + (id - p.succ.prevs) 27 | } 28 | } 29 | 30 | fact defineElected { 31 | no elected.first 32 | all t: Time-first | elected.t = {p: Process | p in p.toSend.t - p.toSend.(t.prev)} 33 | } 34 | 35 | fact traces { 36 | init [first] 37 | all t: Time-last | 38 | let t" = t.next | 39 | all p: Process | 40 | step [t, t", p] or step [t, t", succ.p] or skip [t, t", p] 41 | } 42 | 43 | pred skip [t, t": Time, p: Process] { 44 | p.toSend.t = p.toSend.t" 45 | } 46 | 47 | pred show { some elected } 48 | run show for 3 Process, 4 Time 49 | // This generates an instance similar to Fig 6.4 50 | 51 | assert AtMostOneElected { lone elected.Time } 52 | check AtMostOneElected for 3 Process, 7 Time 53 | // This should not find any counterexample 54 | 55 | assert AtLeastOneElected { some t: Time | some elected.t } 56 | check AtLeastOneElected for 3 Process, 7 Time 57 | // This generates a counterexample in which nothing happens 58 | -------------------------------------------------------------------------------- /software-abstractions-book/chapter6/ringElection2.als: -------------------------------------------------------------------------------- 1 | module chapter6/ringElection2 --- the final version (as depicted in Fig 6.1) 2 | 3 | open util/ordering[Time] as TO 4 | open util/ordering[Process] as PO 5 | 6 | sig Time {} 7 | 8 | sig Process { 9 | succ: Process, 10 | toSend: Process -> Time, 11 | elected: set Time 12 | } 13 | 14 | fact ring { 15 | all p: Process | Process in p.^succ 16 | } 17 | 18 | pred init [t: Time] { 19 | all p: Process | p.toSend.t = p 20 | } 21 | 22 | pred step [t, t": Time, p: Process] { 23 | let from = p.toSend, to = p.succ.toSend | 24 | some id: from.t { 25 | from.t" = from.t - id 26 | to.t" = to.t + (id - p.succ.prevs) 27 | } 28 | } 29 | 30 | fact defineElected { 31 | no elected.first 32 | all t: Time-first | elected.t = {p: Process | p in p.toSend.t - p.toSend.(t.prev)} 33 | } 34 | 35 | fact traces { 36 | init [first] 37 | all t: Time-last | 38 | let t" = t.next | 39 | all p: Process | 40 | step [t, t", p] or step [t, t", succ.p] or skip [t, t", p] 41 | } 42 | 43 | pred skip [t, t": Time, p: Process] { 44 | p.toSend.t = p.toSend.t" 45 | } 46 | 47 | pred show { some elected } 48 | run show for 3 Process, 4 Time 49 | // This generates an instance similar to Fig 6.4 50 | 51 | assert AtMostOneElected { lone elected.Time } 52 | check AtMostOneElected for 3 Process, 7 Time 53 | // This should not find any counterexample 54 | 55 | pred progress { 56 | all t: Time - TO/last | 57 | let t" = TO/next [t] | 58 | some Process.toSend.t => some p: Process | not skip [t, t", p] 59 | } 60 | 61 | assert AtLeastOneElected { progress => some elected.Time } 62 | check AtLeastOneElected for 3 Process, 7 Time 63 | // This should not find any counterexample 64 | 65 | pred looplessPath { no disj t, t": Time | toSend.t = toSend.t" } 66 | 67 | // This produces an instance 68 | run looplessPath for 3 Process, 12 Time 69 | 70 | // This does not produce an instance 71 | run looplessPath for 3 Process, 13 Time 72 | 73 | // Therefore, we can conclude that a scope of 12 for Time is 74 | // sufficient to reach all states of the protocol for a three-node ring. 75 | -------------------------------------------------------------------------------- /utilities/time/overlapping-ranges.als: -------------------------------------------------------------------------------- 1 | open util/ordering[Time] 2 | 3 | sig Time {} 4 | 5 | 6 | let range[s,e] = (s + s.nexts) - e.nexts // inclusive bounds i.e. [s,e] 7 | let overlap[s1,e1,s2,e2] = some (range[s1,e1] & range[s2,e2]) 8 | 9 | check { 10 | 11 | 12 | // [t0,t0] ∩ [t0,tn] 13 | overlap[ first, first, first, last ] 14 | 15 | // [t0,t1] ∩ [t1,tn] 16 | overlap[ first, first.next, first.next, last ] 17 | 18 | // [t0,t1] ∩ [t0,tn] 19 | overlap[ first, first.next, first, last ] 20 | 21 | // [t0,t1] ∩ [t0,t1] 22 | overlap[ first, first.next, first, first.next ] 23 | 24 | // not ( [t1,t0] ∩ [t0,t1] ) 25 | not overlap[ first.next, first, first, last ] 26 | 27 | // not ( [t0,t1] ∩ [t2,tn] ) 28 | not overlap[ first, first.next, first.next.next, last ] 29 | 30 | // reflexive 31 | all t1, t2, t3, t4 : Time | overlap[t1,t2,t3,t4] <=> overlap[t3,t4,t1,t2] 32 | } for 10 33 | -------------------------------------------------------------------------------- /utilities/trace/trace.als: -------------------------------------------------------------------------------- 1 | module trace[exactly elem] 2 | 3 | private one sig Ord { 4 | First: set elem, 5 | Next: elem -> elem 6 | } { 7 | pred/totalOrder[elem,First,Next] 8 | } 9 | 10 | lone sig back in elem {} 11 | 12 | fun loop : elem -> elem { 13 | last -> back 14 | } 15 | 16 | fun first: one elem { Ord.First } 17 | 18 | fun last: one elem { elem - ((Ord.Next).elem) } 19 | 20 | fun next : elem->elem { Ord.Next + loop } 21 | 22 | fun prev : elem->elem { ~this/next } 23 | 24 | fun past : elem->elem { ^(~this/next) } 25 | 26 | fun future : elem -> elem { elem <: *this/next } 27 | 28 | fun upto[s,s" : elem] : set elem { 29 | (s" in s.*(Ord.Next) or finite) implies s.future & ^(Ord.Next).s" else s.*(Ord.Next) + (^(Ord.Next).s" & back.*(Ord.Next)) 30 | } 31 | 32 | 33 | pred finite { 34 | no loop 35 | } 36 | 37 | pred infinite { 38 | some loop 39 | } 40 | 41 | check total { 42 | finite implies pred/totalOrder[elem,first,next] 43 | } 44 | -------------------------------------------------------------------------------- /utilities/types/boolean.als: -------------------------------------------------------------------------------- 1 | module util/boolean 2 | 3 | /* 4 | * Creates a Bool type with two singleton subtypes: True 5 | * and False. Provides common boolean operations. 6 | * 7 | * author: Greg Dennis 8 | */ 9 | 10 | abstract sig Bool {} 11 | one sig True, False extends Bool {} 12 | 13 | pred isTrue[b: Bool] { b in True } 14 | 15 | pred isFalse[b: Bool] { b in False } 16 | 17 | fun Not[b: Bool] : Bool { 18 | Bool - b 19 | } 20 | 21 | fun And[b1, b2: Bool] : Bool { 22 | subset_[b1 + b2, True] 23 | } 24 | 25 | fun Or[b1, b2: Bool] : Bool { 26 | subset_[True, b1 + b2] 27 | } 28 | 29 | fun Xor[b1, b2: Bool] : Bool { 30 | subset_[Bool, b1 + b2] 31 | } 32 | 33 | fun Nand[b1, b2: Bool] : Bool { 34 | subset_[False, b1 + b2] 35 | } 36 | 37 | fun Nor[b1, b2: Bool] : Bool { 38 | subset_[b1 + b2, False] 39 | } 40 | 41 | fun subset_[s1, s2: set Bool] : Bool { 42 | (s1 in s2) => True else False 43 | } 44 | -------------------------------------------------------------------------------- /utilities/types/graph.als: -------------------------------------------------------------------------------- 1 | module util/graph[node] 2 | 3 | /* 4 | * Utilities for some common operations and constraints 5 | * on graphs. 6 | * 7 | * author: Greg Dennis 8 | */ 9 | 10 | open util/relation as rel 11 | 12 | /** graph in undirected */ 13 | pred undirected [r: node->node] { 14 | symmetric[r] 15 | } 16 | 17 | /** graph has no self-loops */ 18 | pred noSelfLoops[r: node->node] { 19 | irreflexive[r] 20 | } 21 | 22 | /** graph is weakly connected */ 23 | pred weaklyConnected[r: node->node] { 24 | all n1, n2: node | n1 in n2.*(r + ~r) // Changed from ^ to * to permit singleton 25 | } 26 | 27 | /** graph is strongly connected */ 28 | pred stronglyConnected[r: node->node] { 29 | all n1, n2: node | n1 in n2.*r // Changed from ^ to * to permit singleton 30 | } 31 | 32 | /** graph is rooted at root */ 33 | pred rootedAt[r: node->node, root: node] { 34 | node in root.*r 35 | } 36 | 37 | /** graph is a ring */ 38 | pred ring [r: node->node] { 39 | all n: node | one n.r && rootedAt[r, n] 40 | } 41 | 42 | /** graph is a dag */ 43 | pred dag [r: node->node] { 44 | acyclic[r, node] 45 | } 46 | 47 | /** graph is a forest */ 48 | pred forest [r: node->node] { 49 | dag[r] 50 | all n: node | lone r.n 51 | } 52 | 53 | /** graph is a tree */ 54 | pred tree [r: node->node] { 55 | forest[r] 56 | lone root: node | no r.root 57 | } 58 | 59 | /** graph is a tree rooted at root */ 60 | pred treeRootedAt[r: node->node, root: node] { 61 | forest[r] 62 | rootedAt[r, root] 63 | } 64 | 65 | /** returns the roots of the graph */ 66 | fun roots [r: node->node] : set node { 67 | node - node.^r 68 | } 69 | 70 | /** returns the leaves of the graph */ 71 | fun leaves [r: node->node] : set node { 72 | node - node.^~r 73 | } 74 | 75 | /** returns the inner nodes (non-leaves) of the graph */ 76 | fun innerNodes [r: node->node] : set node { 77 | node - leaves[r] 78 | } 79 | -------------------------------------------------------------------------------- /utilities/types/integer.als: -------------------------------------------------------------------------------- 1 | module util/integer 2 | 3 | /* 4 | * A collection of utility functions for using Integers in Alloy. 5 | * Note that integer overflows are silently truncated to the current bitwidth 6 | * using the 2's complement arithmetic, unless the "forbid overfows" option is 7 | * turned on, in which case only models that don't have any overflows are 8 | * analyzed. 9 | */ 10 | 11 | fun add [n1, n2: Int] : Int { this/plus[n1, n2] } 12 | fun plus [n1, n2: Int] : Int { n1 fun/add n2 } 13 | 14 | fun sub [n1, n2: Int] : Int { this/minus[n1, n2] } 15 | fun minus [n1, n2: Int] : Int { n1 fun/sub n2 } 16 | 17 | fun mul [n1, n2: Int] : Int { n1 fun/mul n2 } 18 | 19 | /** 20 | * Performs the division with "round to zero" semantics, except the following 3 cases 21 | * 1) if a is 0, then it returns 0 22 | * 2) else if b is 0, then it returns 1 if a is negative and -1 if a is positive 23 | * 3) else if a is the smallest negative integer, and b is -1, then it returns a 24 | */ 25 | fun div [n1, n2: Int] : Int { n1 fun/div n2 } 26 | 27 | /** answer is defined to be the unique integer that satisfies "a = ((a/b)*b) + remainder" */ 28 | fun rem [n1, n2: Int] : Int { n1 fun/rem n2 } 29 | 30 | /** negate */ 31 | fun negate [n: Int] : Int { 0 fun/sub n } 32 | 33 | /** equal to */ 34 | pred eq [n1, n2: Int] { int[n1] = int[n2] } 35 | 36 | /** greater than */ 37 | pred gt [n1, n2: Int] { n1 > n2 } 38 | 39 | /** less then */ 40 | pred lt [n1, n2: Int] { n1 < n2 } 41 | 42 | /** greater than or equal */ 43 | pred gte [n1, n2: Int] { n1 >= n2 } 44 | 45 | /** less than or equal */ 46 | pred lte [n1, n2: Int] { n1 <= n2 } 47 | 48 | /** integer is zero */ 49 | pred zero [n: Int] { n = 0 } 50 | 51 | /** positive */ 52 | pred pos [n: Int] { n > 0 } 53 | 54 | /** negative */ 55 | pred neg [n: Int] { n < 0 } 56 | 57 | /** non-positive */ 58 | pred nonpos [n: Int] { n <= 0 } 59 | 60 | /** non-negative */ 61 | pred nonneg [n: Int] { n >= 0 } 62 | 63 | /** signum (aka sign or sgn) */ 64 | fun signum [n: Int] : Int { n<0 => (0 fun/sub 1) else (n>0 => 1 else 0) } 65 | 66 | /** 67 | * returns the ith element (zero-based) from the set s 68 | * in the ordering of 'next', which is a linear ordering 69 | * relation like that provided by util/ordering 70 | */ 71 | fun int2elem[i: Int, next: univ->univ, s: set univ] : lone s { 72 | {e: s | #^next.e = int i } 73 | } 74 | 75 | /** 76 | * returns the index of the element (zero-based) in the 77 | * ordering of next, which is a linear ordering relation 78 | * like that provided by util/ordering 79 | */ 80 | fun elem2int[e: univ, next: univ->univ] : lone Int { 81 | Int[#^next.e] 82 | } 83 | 84 | /** returns the largest integer in the current bitwidth */ 85 | fun max:one Int { fun/max } 86 | 87 | /** returns the smallest integer in the current bitwidth */ 88 | fun min:one Int { fun/min } 89 | 90 | /** maps each integer (except max) to the integer after it */ 91 | fun next:Int->Int { fun/next } 92 | 93 | /** maps each integer (except min) to the integer before it */ 94 | fun prev:Int->Int { ~next } 95 | 96 | /** given a set of integers, return the largest element */ 97 | fun max [es: set Int]: lone Int { es - es.^prev } 98 | 99 | /** given a set of integers, return the smallest element */ 100 | fun min [es: set Int]: lone Int { es - es.^next } 101 | 102 | /** given an integer, return all integers prior to it */ 103 | fun prevs [e: Int]: set Int { e.^prev } 104 | 105 | /** given an integer, return all integers following it */ 106 | fun nexts [e: Int]: set Int { e.^next } 107 | 108 | /** returns the larger of the two integers */ 109 | fun larger [e1, e2: Int]: Int { let a=int[e1], b=int[e2] | (a b else a) } 110 | 111 | /** returns the smaller of the two integers */ 112 | fun smaller [e1, e2: Int]: Int { let a=int[e1], b=int[e2] | (a a else b) } 113 | -------------------------------------------------------------------------------- /utilities/types/natural.als: -------------------------------------------------------------------------------- 1 | module util/natural 2 | 3 | /* 4 | * Utility function and predicates for using the set of 5 | * nonnegative integers (0, 1, 2, . . .). The number of 6 | * naturals present in an analysis will be equal to the 7 | * scope on Natural. Specifically, if the scope on Natural 8 | * is N, then the naturals 0 through N-1 will be present. 9 | * 10 | * Note that the functions that return Naturals, such as 11 | * 'add' and 'div', may return an empty set if no such 12 | * Natural exists for that integer value. 13 | * 14 | * To write an Alloy model that makes use of negative 15 | * integers, use the util/integer module instead. 16 | * 17 | * @author Greg Dennis 18 | */ 19 | 20 | private open util/ordering[Natural] as ord 21 | private open util/integer as integer 22 | 23 | sig Natural {} 24 | 25 | /** the integer zero */ 26 | one sig Zero in Natural {} 27 | 28 | /** the integer one will be the empty set if the scope on Natural is less than two */ 29 | lone sig One in Natural {} 30 | 31 | fact { 32 | first in Zero 33 | next[first] in One 34 | } 35 | 36 | /** returns n + 1 */ 37 | fun inc [n: Natural] : lone Natural { ord/next[n] } 38 | 39 | /** returns n - 1 */ 40 | fun dec [n: Natural] : lone Natural { ord/prev[n] } 41 | 42 | /** returns n1 + n2 */ 43 | fun add [n1, n2: Natural] : lone Natural { 44 | {n: Natural | #ord/prevs[n] = plus[#ord/prevs[n1], #ord/prevs[n2]]} 45 | } 46 | 47 | /** returns n1 - n2 */ 48 | fun sub [n1, n2: Natural] : lone Natural { 49 | {n: Natural | #ord/prevs[n1] = plus[#ord/prevs[n2], #ord/prevs[n]]} 50 | } 51 | 52 | /** returns n1 * n2 */ 53 | fun mul [n1, n2: Natural] : lone Natural { 54 | {n: Natural | #ord/prevs[n] = #(ord/prevs[n1]->ord/prevs[n2])} 55 | } 56 | 57 | /** returns n1 / n2 */ 58 | fun div [n1, n2: Natural] : lone Natural { 59 | {n: Natural | #ord/prevs[n1] = #(ord/prevs[n2]->ord/prevs[n])} 60 | } 61 | 62 | /** returns true iff n1 is greater than n2 */ 63 | pred gt [n1, n2: Natural] { ord/gt [n1, n2] } 64 | 65 | /** returns true iff n1 is less than n2 */ 66 | pred lt [n1, n2: Natural] { ord/lt [n1, n2] } 67 | 68 | /** returns true iff n1 is greater than or equal to n2 */ 69 | pred gte [n1, n2: Natural] { ord/gte[n1, n2] } 70 | 71 | /** returns true iff n1 is less than or equal to n2 */ 72 | pred lte [n1, n2: Natural] { ord/lte[n1, n2] } 73 | 74 | /** returns the maximum integer in ns */ 75 | fun max [ns: set Natural] : lone Natural { ord/max[ns] } 76 | 77 | /** returns the minimum integer in ns */ 78 | fun min [ns: set Natural] : lone Natural { ord/min[ns] } 79 | -------------------------------------------------------------------------------- /utilities/types/ordering.als: -------------------------------------------------------------------------------- 1 | module util/ordering[exactly elem] 2 | 3 | /* 4 | * Creates a single linear ordering over the atoms in elem. It also constrains all 5 | * the atoms to exist that are permitted by the scope on elem. That is, if the scope 6 | * on a signature S is 5, opening util/ordering[S] will force S to have 5 elements 7 | * and create a linear ordering over those five elements. The predicates and 8 | * functions below provide access to properties of the linear ordering, such as 9 | * which element is first in the ordering, or whether a given element precedes 10 | * another. You cannotcreate multiple linear orderings over the same signature with 11 | * this model. If you that functionality, try using the util/sequence module instead. 12 | * 13 | * Technical comment: 14 | * An important constraint: elem must contain all atoms permitted by the scope. 15 | * This is to let the analyzer optimize the analysis by setting all fields of each 16 | * instantiation of Ord to predefined values: e.g. by setting 'last' to the highest 17 | * atom of elem and by setting 'next' to {,,...}, where n is 18 | * the scope of elem. Without this constraint, it might not be true that Ord.last is 19 | * a subset of elem, and that the domain and range of Ord.next lie inside elem. 20 | * 21 | * author: Ilya Shlyakhter 22 | * revisions: Daniel jackson 23 | */ 24 | 25 | private one sig Ord { 26 | First: set elem, 27 | Next: elem -> elem 28 | } { 29 | pred/totalOrder[elem,First,Next] 30 | } 31 | 32 | /** first */ 33 | fun first: one elem { Ord.First } 34 | 35 | /** last */ 36 | fun last: one elem { elem - (next.elem) } 37 | 38 | /** return a mapping from each element to its predecessor */ 39 | fun prev : elem->elem { ~(Ord.Next) } 40 | 41 | /** return a mapping from each element to its successor */ 42 | fun next : elem->elem { Ord.Next } 43 | 44 | /** return elements prior to e in the ordering */ 45 | fun prevs [e: elem]: set elem { e.^(~(Ord.Next)) } 46 | 47 | /** return elements following e in the ordering */ 48 | fun nexts [e: elem]: set elem { e.^(Ord.Next) } 49 | 50 | /** e1 is less than e2 in the ordering */ 51 | pred lt [e1, e2: elem] { e1 in prevs[e2] } 52 | 53 | /** e1 is greater than e2 in the ordering */ 54 | pred gt [e1, e2: elem] { e1 in nexts[e2] } 55 | 56 | /** e1 is less than or equal to e2 in the ordering */ 57 | pred lte [e1, e2: elem] { e1=e2 || lt [e1,e2] } 58 | 59 | /** e1 is greater than or equal to e2 in the ordering */ 60 | pred gte [e1, e2: elem] { e1=e2 || gt [e1,e2] } 61 | 62 | /** returns the larger of the two elements in the ordering */ 63 | fun larger [e1, e2: elem]: elem { lt[e1,e2] => e2 else e1 } 64 | 65 | /** returns the smaller of the two elements in the ordering */ 66 | fun smaller [e1, e2: elem]: elem { lt[e1,e2] => e1 else e2 } 67 | 68 | /** 69 | * returns the largest element in es 70 | * or the empty set if es is empty 71 | */ 72 | fun max [es: set elem]: lone elem { es - es.^(~(Ord.Next)) } 73 | 74 | /** 75 | * returns the smallest element in es 76 | * or the empty set if es is empty 77 | */ 78 | fun min [es: set elem]: lone elem { es - es.^(Ord.Next) } 79 | 80 | assert correct { 81 | let mynext = Ord.Next | 82 | let myprev = ~mynext | { 83 | ( all b:elem | (lone b.next) && (lone b.prev) && (b !in b.^mynext) ) 84 | ( (no first.prev) && (no last.next) ) 85 | ( all b:elem | (b!=first && b!=last) => (one b.prev && one b.next) ) 86 | ( !one elem => (one first && one last && first!=last && one first.next && one last.prev) ) 87 | ( one elem => (first=elem && last=elem && no myprev && no mynext) ) 88 | ( myprev=~mynext ) 89 | ( elem = first.*mynext ) 90 | (all disj a,b:elem | a in b.^mynext or a in b.^myprev) 91 | (no disj a,b:elem | a in b.^mynext and a in b.^myprev) 92 | (all disj a,b,c:elem | (b in a.^mynext and c in b.^mynext) =>(c in a.^mynext)) 93 | (all disj a,b,c:elem | (b in a.^myprev and c in b.^myprev) =>(c in a.^myprev)) 94 | } 95 | } 96 | run {} for exactly 0 elem expect 0 97 | run {} for exactly 1 elem expect 1 98 | run {} for exactly 2 elem expect 1 99 | run {} for exactly 3 elem expect 1 100 | run {} for exactly 4 elem expect 1 101 | check correct for exactly 0 elem 102 | check correct for exactly 1 elem 103 | check correct for exactly 2 elem 104 | check correct for exactly 3 elem 105 | check correct for exactly 4 elem 106 | check correct for exactly 5 elem 107 | -------------------------------------------------------------------------------- /utilities/types/relation.als: -------------------------------------------------------------------------------- 1 | module util/relation 2 | 3 | /* 4 | * Utilities for some common operations and constraints 5 | * on binary relations. The keyword 'univ' represents the 6 | * top-level type, which all other types implicitly extend. 7 | * Therefore, all the functions and predicates in this model 8 | * may be applied to binary relations of any type. 9 | * 10 | * author: Greg Dennis 11 | */ 12 | 13 | /** returns the domain of a binary relation */ 14 | fun dom [r: univ->univ] : set (r.univ) { r.univ } 15 | 16 | /** returns the range of a binary relation */ 17 | fun ran [r: univ->univ] : set (univ.r) { univ.r } 18 | 19 | /** r is total over the domain s */ 20 | pred total [r: univ->univ, s: set univ] { 21 | all x: s | some x.r 22 | } 23 | 24 | /** r is a partial function over the domain s */ 25 | pred functional [r: univ->univ, s: set univ] { 26 | all x: s | lone x.r 27 | } 28 | 29 | /** r is a total function over the domain s */ 30 | pred function [r: univ->univ, s: set univ] { 31 | all x: s | one x.r 32 | } 33 | 34 | /** r is surjective over the codomain s */ 35 | pred surjective [r: univ->univ, s: set univ] { 36 | all x: s | some r.x 37 | } 38 | 39 | /** r is injective */ 40 | pred injective [r: univ->univ, s: set univ] { 41 | all x: s | lone r.x 42 | } 43 | 44 | /** r is bijective over the codomain s */ 45 | pred bijective[r: univ->univ, s: set univ] { 46 | all x: s | one r.x 47 | } 48 | 49 | /** r is a bijection over the domain d and the codomain c */ 50 | pred bijection[r: univ->univ, d, c: set univ] { 51 | function[r, d] && bijective[r, c] 52 | } 53 | 54 | /** r is reflexive over the set s */ 55 | pred reflexive [r: univ -> univ, s: set univ] {s<:iden in r} 56 | 57 | /** r is irreflexive */ 58 | pred irreflexive [r: univ -> univ] {no iden & r} 59 | 60 | /** r is symmetric */ 61 | pred symmetric [r: univ -> univ] {~r in r} 62 | 63 | /** r is anti-symmetric */ 64 | pred antisymmetric [r: univ -> univ] {~r & r in iden} 65 | 66 | /** r is transitive */ 67 | pred transitive [r: univ -> univ] {r.r in r} 68 | 69 | /** r is acyclic over the set s */ 70 | pred acyclic[r: univ->univ, s: set univ] { 71 | all x: s | x !in x.^r 72 | } 73 | 74 | /** r is complete over the set s */ 75 | pred complete[r: univ->univ, s: univ] { 76 | all x,y:s | (x!=y => x->y in (r + ~r)) 77 | } 78 | 79 | /** r is a preorder (or a quasi-order) over the set s */ 80 | pred preorder [r: univ -> univ, s: set univ] { 81 | reflexive[r, s] 82 | transitive[r] 83 | } 84 | 85 | /** r is an equivalence relation over the set s */ 86 | pred equivalence [r: univ->univ, s: set univ] { 87 | preorder[r, s] 88 | symmetric[r] 89 | } 90 | 91 | /** r is a partial order over the set s */ 92 | pred partialOrder [r: univ -> univ, s: set univ] { 93 | preorder[r, s] 94 | antisymmetric[r] 95 | } 96 | 97 | /** r is a total order over the set s */ 98 | pred totalOrder [r: univ -> univ, s: set univ] { 99 | partialOrder[r, s] 100 | complete[r, s] 101 | } 102 | -------------------------------------------------------------------------------- /utilities/types/seqrel.als: -------------------------------------------------------------------------------- 1 | module util/seqrel[elem] 2 | 3 | /* 4 | * A sequence utility for modeling sequences as just a 5 | * relation as opposed to reifying them into sequence 6 | * atoms like the util/sequence module does. 7 | * 8 | * @author Greg Dennis 9 | */ 10 | 11 | open util/integer 12 | open util/ordering[SeqIdx] as ord 13 | 14 | sig SeqIdx {} 15 | 16 | /** sequence covers a prefix of SeqIdx */ 17 | pred isSeq[s: SeqIdx -> elem] { 18 | s in SeqIdx -> lone elem 19 | s.inds - ord/next[s.inds] in ord/first 20 | } 21 | 22 | /** returns all the elements in this sequence */ 23 | fun elems [s: SeqIdx -> elem]: set elem { SeqIdx.s } 24 | 25 | /** returns the first element in the sequence */ 26 | fun first [s: SeqIdx -> elem]: lone elem { s[ord/first] } 27 | 28 | /** returns the last element in the sequence */ 29 | fun last [s: SeqIdx -> elem]: lone elem { s[lastIdx[s]] } 30 | 31 | /** returns the cdr of the sequence */ 32 | fun rest [s: SeqIdx -> elem] : SeqIdx -> elem { 33 | (ord/next).s 34 | } 35 | 36 | /** returns all but the last element of the sequence */ 37 | fun butlast [s: SeqIdx -> elem] : SeqIdx -> elem { 38 | (SeqIdx - lastIdx[s]) <: s 39 | } 40 | 41 | /** true if the sequence is empty */ 42 | pred isEmpty [s: SeqIdx -> elem] { no s } 43 | 44 | /** true if this sequence has duplicates */ 45 | pred hasDups [s: SeqIdx -> elem] { # elems[s] < # inds[s] } 46 | 47 | /** returns all the indices occupied by this sequence */ 48 | fun inds [s: SeqIdx -> elem]: set SeqIdx { s.elem } 49 | 50 | /** returns last index occupied by this sequence */ 51 | fun lastIdx [s: SeqIdx -> elem]: lone SeqIdx { ord/max[inds[s]] } 52 | 53 | /** 54 | * returns the index after the last index 55 | * if this sequence is empty, returns the first index, 56 | * if this sequence is full, returns empty set 57 | */ 58 | fun afterLastIdx [s: SeqIdx -> elem] : lone SeqIdx { 59 | ord/min[SeqIdx - inds[s]] 60 | } 61 | 62 | /** returns first index at which given element appears or the empty set if it doesn't */ 63 | fun idxOf [s: SeqIdx -> elem, e: elem] : lone SeqIdx { ord/min[indsOf[s, e]] } 64 | 65 | /** returns last index at which given element appears or the empty set if it doesn't */ 66 | fun lastIdxOf [s: SeqIdx -> elem, e: elem] : lone SeqIdx { ord/max[indsOf[s, e]] } 67 | 68 | /** returns set of indices at which given element appears or the empty set if it doesn't */ 69 | fun indsOf [s: SeqIdx -> elem, e: elem] : set SeqIdx { s.e } 70 | 71 | /** 72 | * return the result of appending e to the end of s 73 | * just returns s if s exhausted SeqIdx 74 | */ 75 | fun add [s: SeqIdx -> elem, e: elem] : SeqIdx -> elem { 76 | setAt[s, afterLastIdx[s], e] 77 | } 78 | 79 | /** returns the result of setting the value at index i in sequence to e */ 80 | fun setAt [s: SeqIdx -> elem, i: SeqIdx, e: elem] : SeqIdx -> elem { 81 | s ++ i -> e 82 | } 83 | 84 | /** returns the result of inserting value e at index i */ 85 | fun insert [s: SeqIdx -> elem, i: SeqIdx, e: elem] : SeqIdx -> elem { 86 | (ord/prevs[i] <: s) + (i->e) + (~(ord/next)).((ord/nexts[i] + i) <: s) 87 | } 88 | 89 | /** returns the result of deleting the value at index i */ 90 | fun delete[s: SeqIdx -> elem, i: SeqIdx] : SeqIdx -> elem { 91 | (ord/prevs[i] <: s) + (ord/next).(ord/nexts[i] <: s) 92 | } 93 | 94 | /** appended is the result of appending s2 to s1 */ 95 | fun append [s1, s2: SeqIdx -> elem] : SeqIdx -> elem { 96 | let shift = {i", i: SeqIdx | #ord/prevs[i"] = add[#ord/prevs[i], add[#ord/prevs[lastIdx[s1]], 1]] } | 97 | s1 + shift.s2 98 | } 99 | 100 | /** returns the subsequence of s between from and to, inclusive */ 101 | fun subseq [s: SeqIdx -> elem, from, to: SeqIdx] : SeqIdx -> elem { 102 | let shift = {i", i: SeqIdx | #ord/prevs[i"] = sub[#ord/prevs[i], #ord/prevs[from]] } | 103 | shift.((SeqIdx - ord/nexts[to]) <: s) 104 | } 105 | 106 | fun firstIdx: SeqIdx { ord/first } 107 | 108 | fun finalIdx: SeqIdx { ord/last } -------------------------------------------------------------------------------- /utilities/types/sequniv.als: -------------------------------------------------------------------------------- 1 | module util/sequniv 2 | 3 | open util/integer as ui 4 | 5 | /* 6 | * NOTE: Do not include this module manually. 7 | * Instead, use the "seq" keyword which will automatically 8 | * import this module with the correct additional constraints as needed. 9 | */ 10 | 11 | /* 12 | * A sequence utility for modeling sequences as just a 13 | * relation as opposed to reifying them into sequence 14 | * atoms like the util/sequence module does. 15 | * 16 | * Precondition: each input sequence must range over a prefix 17 | * of seq/Int. 18 | * 19 | * Postcondition: we guarantee the returned sequence 20 | * also ranges over a prefix of seq/Int. 21 | * 22 | * @author Greg Dennis 23 | */ 24 | 25 | /** sequence covers a prefix of seq/Int */ 26 | pred isSeq[s: Int -> univ] { 27 | s in seq/Int -> lone univ 28 | s.inds - ui/next[s.inds] in 0 29 | } 30 | 31 | /** returns all the elements in this sequence */ 32 | fun elems [s: Int -> univ]: set (Int.s) { seq/Int . s } 33 | 34 | /** 35 | * returns the first element in the sequence 36 | * (Returns the empty set if the sequence is empty) 37 | */ 38 | fun first [s: Int -> univ]: lone (Int.s) { s[0] } 39 | 40 | /** 41 | * returns the last element in the sequence 42 | * (Returns the empty set if the sequence is empty) 43 | */ 44 | fun last [s: Int -> univ]: lone (Int.s) { s[lastIdx[s]] } 45 | 46 | /** 47 | * returns the cdr of the sequence 48 | * (Returns the empty sequence if the sequence has 1 or fewer element) 49 | */ 50 | fun rest [s: Int -> univ] : s { seq/Int <: ((ui/next).s) } 51 | 52 | /** returns all but the last element of the sequence */ 53 | fun butlast [s: Int -> univ] : s { 54 | (seq/Int - lastIdx[s]) <: s 55 | } 56 | 57 | /** true if the sequence is empty */ 58 | pred isEmpty [s: Int -> univ] { no s } 59 | 60 | /** true if this sequence has duplicates */ 61 | pred hasDups [s: Int -> univ] { # elems[s] < # inds[s] } 62 | 63 | /** returns all the indices occupied by this sequence */ 64 | fun inds [s: Int -> univ]: set Int { s.univ } 65 | 66 | /** 67 | * returns last index occupied by this sequence 68 | * (Returns the empty set if the sequence is empty) 69 | */ 70 | fun lastIdx [s: Int -> univ]: lone Int { ui/max[inds[s]] } 71 | 72 | /** 73 | * returns the index after the last index 74 | * if this sequence is empty, returns 0 75 | * if this sequence is full, returns empty set 76 | */ 77 | fun afterLastIdx [s: Int -> univ] : lone Int { ui/min[seq/Int - inds[s]] } 78 | 79 | /** returns first index at which given element appears or the empty set if it doesn't */ 80 | fun idxOf [s: Int -> univ, e: univ] : lone Int { ui/min[indsOf[s, e]] } 81 | 82 | /** returns last index at which given element appears or the empty set if it doesn't */ 83 | fun lastIdxOf [s: Int -> univ, e: univ] : lone Int { ui/max[indsOf[s, e]] } 84 | 85 | /** returns set of indices at which given element appears or the empty set if it doesn't */ 86 | fun indsOf [s: Int -> univ, e: univ] : set Int { s.e } 87 | 88 | /** 89 | * return the result of appending e to the end of s 90 | * (returns s if s exhausted seq/Int) 91 | */ 92 | fun add [s: Int -> univ, e: univ] : s + (seq/Int->e) { 93 | setAt[s, afterLastIdx[s], e] 94 | } 95 | 96 | /** 97 | * returns the result of setting the value at index i in sequence to e 98 | * Precondition: 0 <= i < #s 99 | */ 100 | fun setAt [s: Int -> univ, i: Int, e: univ] : s + (seq/Int->e) { 101 | s ++ i -> e 102 | } 103 | 104 | /** 105 | * returns the result of inserting value e at index i 106 | * (if sequence was full, the original last element will be removed first) 107 | * Precondition: 0 <= i <= #s 108 | */ 109 | fun insert [s: Int -> univ, i: Int, e: univ] : s + (seq/Int->e) { 110 | seq/Int <: ((ui/prevs[i] <: s) + (i->e) + ui/prev.((ui/nexts[i] + i) <: s)) 111 | } 112 | 113 | /** 114 | * returns the result of deleting the value at index i 115 | * Precondition: 0 <= i < #s 116 | */ 117 | fun delete[s: Int -> univ, i: Int] : s { 118 | (ui/prevs[i] <: s) + (ui/next).(ui/nexts[i] <: s) 119 | } 120 | 121 | /** 122 | * appended is the result of appending s2 to s1 123 | * (If the resulting sequence is too long, it will be truncated) 124 | */ 125 | fun append [s1, s2: Int -> univ] : s1+s2 { 126 | let shift = {i", i: seq/Int | int[i"] = ui/add[int[i], ui/add[int[lastIdx[s1]], 1]] } | 127 | no s1 => s2 else (s1 + shift.s2) 128 | } 129 | 130 | /** 131 | * returns the subsequence of s between from and to, inclusive 132 | * Precondition: 0 <= from <= to < #s 133 | */ 134 | fun subseq [s: Int -> univ, from, to: Int] : s { 135 | let shift = {i", i: seq/Int | int[i"] = ui/sub[int[i], int[from]] } | 136 | shift.((seq/Int - ui/nexts[to]) <: s) 137 | } 138 | -------------------------------------------------------------------------------- /utilities/types/ternary.als: -------------------------------------------------------------------------------- 1 | module util/ternary 2 | 3 | /* 4 | * Utilities for some common operations and constraints 5 | * on ternary relations. The keyword 'univ' represents the 6 | * top-level type, which all other types implicitly extend. 7 | * Therefore, all the functions and predicates in this model 8 | * may be applied to ternary relations of any type. 9 | * 10 | * author: Greg Dennis 11 | */ 12 | 13 | /** returns the domain of a ternary relation */ 14 | fun dom [r: univ->univ->univ] : set ((r.univ).univ) { (r.univ).univ } 15 | 16 | /** returns the range of a ternary relation */ 17 | fun ran [r: univ->univ->univ] : set (univ.(univ.r)) { univ.(univ.r) } 18 | 19 | /** returns the "middle range" of a ternary relation */ 20 | fun mid [r: univ->univ->univ] : set (univ.(r.univ)) { univ.(r.univ) } 21 | 22 | /** returns the first two columns of a ternary relation */ 23 | fun select12 [r: univ->univ->univ] : r.univ { 24 | r.univ 25 | } 26 | 27 | /** returns the first and last columns of a ternary relation */ 28 | fun select13 [r: univ->univ->univ] : ((r.univ).univ) -> (univ.(univ.r)) { 29 | {x: (r.univ).univ, z: univ.(univ.r) | some (x.r).z} 30 | } 31 | 32 | /** returns the last two columns of a ternary relation */ 33 | fun select23 [r: univ->univ->univ] : univ.r { 34 | univ.r 35 | } 36 | 37 | /** flips the first two columns of a ternary relation */ 38 | fun flip12 [r: univ->univ->univ] : (univ.(r.univ))->((r.univ).univ)->(univ.(univ.r)) { 39 | {x: univ.(r.univ), y: (r.univ).univ, z: univ.(univ.r) | y->x->z in r} 40 | } 41 | 42 | /** flips the first and last columns of a ternary relation */ 43 | fun flip13 [r: univ->univ->univ] : (univ.(univ.r))->(univ.(r.univ))->((r.univ).univ) { 44 | {x: univ.(univ.r), y: univ.(r.univ), z: (r.univ).univ | z->y->x in r} 45 | } 46 | 47 | /** flips the last two columns of a ternary relation */ 48 | fun flip23 [r: univ->univ->univ] : ((r.univ).univ)->(univ.(univ.r))->(univ.(r.univ)) { 49 | {x: (r.univ).univ, y: univ.(univ.r), z: univ.(r.univ) | x->z->y in r} 50 | } 51 | -------------------------------------------------------------------------------- /utilities/types/time.als: -------------------------------------------------------------------------------- 1 | open util/ordering[Time] 2 | 3 | sig Time { } 4 | 5 | let dynamic[x] = x one-> Time 6 | 7 | let dynamicSet[x] = x -> Time 8 | 9 | let then [a, b, t, t"] { 10 | some x:Time | a[t,x] && b[x,t"] 11 | } 12 | 13 | let while = while3 14 | 15 | let while9 [cond, body, t, t"] { 16 | some x:Time | (cond[t] => body[t,x] else t=x) && while8[cond,body,x,t"] 17 | } 18 | 19 | let while8 [cond, body, t, t"] { 20 | some x:Time | (cond[t] => body[t,x] else t=x) && while7[cond,body,x,t"] 21 | } 22 | 23 | let while7 [cond, body, t, t"] { 24 | some x:Time | (cond[t] => body[t,x] else t=x) && while6[cond,body,x,t"] 25 | } 26 | 27 | let while6 [cond, body, t, t"] { 28 | some x:Time | (cond[t] => body[t,x] else t=x) && while5[cond,body,x,t"] 29 | } 30 | 31 | let while5 [cond, body, t, t"] { 32 | some x:Time | (cond[t] => body[t,x] else t=x) && while4[cond,body,x,t"] 33 | } 34 | 35 | let while4 [cond, body, t, t"] { 36 | some x:Time | (cond[t] => body[t,x] else t=x) && while3[cond,body,x,t"] 37 | } 38 | 39 | let while3 [cond, body, t, t"] { 40 | some x:Time | (cond[t] => body[t,x] else t=x) && while2[cond,body,x,t"] 41 | } 42 | 43 | let while2 [cond, body, t, t"] { 44 | some x:Time | (cond[t] => body[t,x] else t=x) && while1[cond,body,x,t"] 45 | } 46 | 47 | let while1 [cond, body, t, t"] { 48 | some x:Time | (cond[t] => body[t,x] else t=x) && while0[cond,body,x,t"] 49 | } 50 | 51 | let while0 [cond, body, t, t"] { 52 | !cond[t] && t=t" 53 | } 54 | --------------------------------------------------------------------------------