4: Language
4.1 An Example: Self-Grandpas
· Some assertions, labeled by the keyword assert, that record properties that are expected to hold.
· Some commands, labeled by the keywords run and check, which are instructions to the analyzer to perform particular analyses.
The signature declarations set up a classification hierarchy. The declara-tions of Man and Woman say that they extend the signature Person. This means that they represent disjoint subsets of the set Person: no person is both a man and a woman. Marking Person as abstract says that it has no elements of its own that do not belong to its extensions; if omitted, the declarations would allow a person that is neither a man nor a woman.
1 module language/grandpa1
2 abstract sig Person {
3 father: lone Man,
4 mother: lone Woman
5 }
6 sig Man extends Person {
7 wife: lone Woman
8 }
9 sig Woman extends Person {
10 husband: lone Man
11 }
12 fact {
13 no p: Person | p in p.^(mother + father)
14 wife = ~husband
15 }
16 assert NoSelfFather {
17 no m: Man | m = m.father
18 }
19 check NoSelfFather
20 fun grandpas (p: Person): set Person {
21 p.(mother + father).father
22 }
23 pred ownGrandpa (p: Person) {
24 p in grandpas (p)
25 }
26 run ownGrandpa for 4 Person
fig. 4.1 A first Alloy model: Can you be your own grandpa?
language 5 The fields of a signature declare relations whose domain is a subset of the signature. So the field father declared within Person, for example, re-lates persons to men. The keyword lone says that a person has at most one father. Similarly, wife, for example, relates men to women.
A fact records a constraint that is assumed always to hold. The fact start-ing on line 12 says that you can’t be your own ancestor (13) and that if someone is your husband, you are his wife, and vice versa (14).
An assertion, marked by the keyword assert, introduces a constraint that is intended to follow from the facts of the model. The command, marked check, tells the analyzer to find a counterexample to the asser-tion: that is, an instance that makes it false. In this case, the assertion NoSelfFather, which says that nobody is his own father, is valid, and no counterexamples are found.
A function defines a reusable expression. Having written the function grandpas (20), we can now use grandpas (p) to refer to p’s grandpas, rath-er than the more cumbrath-ersome expression p.(mother + father).father. A predicate defines a reusable constraint. Having written the predicate
ownGrandpa (23), we can now use ownGrandpa (p) to say that p is his own grandpa, rather than the constraint p in grandpas (p).
Finally, we come to the real action. The command run ownGrandpa for 4 (26) instructs the analyzer to attempt to find a solution to the constraint ownGrandpa. The phrase for 4 is a scope setting: it limits the search to a universe in which each top-level set (in this case, just Person) contains at most four elements. When the scope setting is omitted, as in the check for NoSelfFather, a default scope of 3 is used.
In fact, there is no action. The analyzer finds no solution within this scope. This could mean that there is a solution in a larger scope, so we might increase the scope, by replacing 4 with 10 in the run command, for example. Again, no solution is found, and if we increase the scope further, we’ll soon reach the point at which the analyzer is no longer able to exhaust the space of possibilities within a reasonable time.
Under these circumstances, we might have instead cast the predicate as an assertion:
assert NoSelfGrandpa {
no p: Person | p in grandpas (p) }
check NoSelfGrandpa for 4 Person
When the analyzer finds no counterexample to an assertion, as here, it reports success (as opposed to failure when a predicate is found to have no instances).
Clearly, if it is possible to be your own grandpa, something must give:
either our definition of grandpa, or the constraint that you can’t be your own ancestor. The first seems more plausible. Suppose we extend the grandpa notion beyond biological grandpas to include grandpas by marriage. Here’s our new definition of grandpa:
fun grandpas (p: Person): set Person {
let parent = mother + father + father.wife +mother.husband | p.parent.parent & Man
}
The let binds parent to the relation that maps a person to his or her mother, father, father’s wife, and mother’s husband. The definition as a whole says that your grandpa is any man who is your parent’s parent, where “parent” now includes stepparents.
Running ownGrandpa, we now get a solution, shown in fig. 4.2. There are two persons, Woman_0 and Man_0, who are mother and son, and also wife and husband. This is not a solution appropriate for a popular song.
We can rule out incest by adding another fact:
no (wife + husband) & ^(mother + father)
I’ve written this constraint relationally. The expression mother + father relates children to parents; its closure relates persons to their ancestors.
Finally, no p & q says that the relations p and q share no tuples, so the constraint as a whole says that no person has a spouse who is also an ancestor.
Now running ownGrandpa again, we get a more socially acceptable solu-tion, shown in fig. 4.3. There are two couples, in which the wife in each is the mother of the husband in the other. The person who is his own grandpa, p, achieved this by having his stepson marry his mother.
The final version of the model, incorporating the new definition of grandpa, and with the constraints ruling out incest, is given in fig. 4.4.
I’ve split the facts into separate paragraphs to show that it’s usually a good idea to group constraints according to their role or origin, and to give them suggestive names.
language
fig. 4.2 An inappropriate solution to ownGrandpa.
fig. 4.3 Another solution to ownGrandpa.
module language/grandpa2 abstract sig Person { father: lone Man, mother: lone Woman }
sig Man extends Person { wife: lone Woman }
sig Woman extends Person { husband: lone Man }
fact Biology {
no p: Person | p in p.^(mother + father) }
fact Terminology { wife = ~husband }
fact SocialConvention {
no (wife + husband) & ^(mother + father) }
assert NoSelfFather { no m: Man | m = m.father }
check NoSelfFather
fun grandpas (p: Person): set Person {
let parent = mother + father + father.wife +mother.husband | p.parent.parent & Man
}
pred ownGrandpa (p: Man) { p in grandpas (p)
}
run ownGrandpa for 4 Person
fig. 4.4 Self-grandpas revisited.
language Discussion
Where does the song “I’m My Own Grandpa” come from?
It was originally a skit written by Dwight Latham and Moe Jaffe for their radio show in the 1930’s. Dwight Latham credited the idea to a book of anecdotes by Mark Twain. They later expanded it into a song, which was recorded in 1948 by “Lonzo and Oscar” (Ken Marvin and Rollin Sullivan), and became a hit. You can find the text of the song, in Lonzo and Oscar’s 1948 version, along with a recording of it being sung, at http://www.wwco.com/gean/grandpa. The song’s scenario is not identical to the one Alloy found, by the way: instead of having his stepson marry his mother, the self-grandpa has his stepdaughter marry his father.
How do you construct relational formulas?
To the novice, the relational style can be hard to grasp. But it becomes quite natural when you’re comfortable with it. I find it helpful to think about sets of arrows rather than atoms and their relationships. For ex-ample, to construct a formula such as
no (wife + husband) & ^(mother + father)
from the SocialConvention fact of 4.4, my thinking would go as follows.
The constraint to be expressed is that no person should marry a parent, grandparent, and so on. This says that certain relationships are prohibit-ed—some arrows should not exist—so the constraint will have the form no e for some expression e. The prohibited relationship involves being both a spouse and a parent or grandparent, and so on. This conjunction suggests taking the intersection of two relations: there should not be an arrow belonging to both. Now we need to express the two relations.
Being a spouse means being a wife or a husband; that tells us to take the union of the relations wife and husband. The “so on” in “being a parent or grandparent, and so on” suggests applying transitive closure to the par-ent relation. A parpar-ent is a mother or a father, indicating another union.
Putting all this together gives the desired formula.
To increase your confidence that a constraint has the meaning you in-tended, you can check an assertion that it is equivalent to a different formulation. In this case, for example, you might compare the relational formulation to one in a navigational style:
pred SocialConvention () {
no (wife + husband) & ^(mother + father) }
pred SocialConvention’ () { let parent = mother + father {
no m: Man | some m.wife and m.wife in m.*parent.mother no w: Woman |
some w.husband and w.husband in w.*parent.father }
}
assert Same {
SocialConvention () iff SocialConvention’() }
check Same
If the two formulations are not equivalent (within the scope), a coun-terexample will be generated showing a family that satisfies one and not the other.
Is there really a difference between running a predicate and checking an assertion?
From an analysis perspective, there’s no fundamental difference between assertions and predicates. Running a predicate involves searching for an instance of its constraint; checking an assertion involves searching for an instance of the negation of its constraint. So, checking an asser-tion with a constraint C is equivalent to running a predicate with the constraint not C.
But this blurs a vital methodological distinction, and in the design of Al-loy I thought it was important to be able to factor out those properties conjectured to follow from the rest. This idea of recording redundan-cies explicitly in a model, and marking them as such, is due to John Gut-tag and Jim Horning and was part of the Larch language [22].
If the Alloy Analyzer finds no counterexample to an assertion, does that mean it is valid?
Not necessarily. It’s possible that there’s a counterexample in a larger scope. But, in practice, as you increase the scope, the chance that a counterexample remains does decrease. So you get some assurance, but not in any absolute sense.
language 1