├── 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 | [](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 |
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 |
--------------------------------------------------------------------------------