Introduction to Alloy

Topic 3: Quantification and relations

13 July 2013

In which we discuss more advanced parts of Alloy's logic.

1 Quantification

  • syntax
  • the quantifiers
  • exercises, examples

1.1 Quantification (syntax)

General form: Q x : E | F
Alloy has more quantifiers than some logics: Q
  • all (F holds for every x in E — cf. ∀)
  • some (F holds for some x in E — cf. ∃)
  • no (F holds for no x in E)
  • lone (F holds for at most one x in E)
  • one (F holds for exactly one x in E — cf. ∃1)

1.2 Existential quantification

Conventional FOPC writes “(∃ x)(Px)”.
Alloy writes: some x | P[x]

1.3 Generator axioms

Alloy atoms have object identity, not mathematical identity.
They don't always exist when you might want them to.
sig Element {}
sig Set { elements : set Element }
assert Closed {
  all s0, s1 : Set | some s2 : Set |
    s2.elements = s0.elements + s1.elements
}
check Closed
What happens? Is there a workaround?
Yes; see Jackson's discussion of “generator axioms” and the “bounded-universal rule”.

1.4 Universal quantification

Conventional FOPC writes “(∀ x)(Px)”.
Alloy writes: all x | P[x]

1.5 Definite descriptions

How do we translate “the present king of France is bald”?
Russell proposed:

(∃ x)(king-of-france(x)
∧ (∀ y)(king-of-france(y) ⇒ x = y)
∧ bald(x))

1.6 Definite descriptions (2)

Others propose:

(∃1 x)(king-of-france(x) ∧ bald(x))

or

(℩ x)(king-of-france(x) ∧ bald(x))

1.7 Alloy's definite descriptions

Alloy writes:
one x | king-of-france[x] and bald[x]
The no and lone quantifiers are also provided.
They are not present in most conventional logic, but could be defined. They do not need to be primitives.

1.8 Exercises

See handout.

2 Operations on relations

Alloy offers several relational operators:
  • product: x -> y
  • dot-join: x . y
  • box-join: y[x]
  • transpose: ~x
  • transitive closure: ^x, *x
  • domain/range restriction: <:x, x:>
  • override: x ++ y

2.1 Product: x -> y

The arrow operator gives the Cartesian product of its arguments.
For sets x, y, x -> y is a binary relation.
For single tuples x, y, x -> y is a tuple concatenating them.
For scalar x, y, x -> y is the pair (x, y).

2.2 Dot-join: x . y

For a single tuple: If
  • x = s1 -> s2 -> ... -> sn
  • y = t1 -> t2 -> ... -> tn
and sn = t1, then
  • x . y = s1 -> s2 -> ... -> sn - 1 -> t2 -> ... -> tn
else
  • x . y = none (i.e. the empty set)
Informally: if the end of x matches the beginning of y, concatenate the tuples, dropping the matching atoms sn and t1.

2.3 Dot-join: r . s

For relations r and s:
  • For each pair x -> y | x in r and y in s,
  • include x . y if it exists.
I.e.
  • r . s = { z | some x : r, some y : s | z = x . y }
For binary relations r, s, r . s is their standard relational composition (r ; s).
Cf. relational natural join. Differences:
  • Dot-join is position, natural join works by name.
  • Dot-join drops the matching atoms, natural join keeps one.
Cf. also object.member navigation in C, Pascal, Java, etc.

2.4 Box-join: y[x]

Syntactic sugar: y[x] ≡ x . y
Mixtures are possible: x.y.z[w] = w.(x.y.z).

2.5 Transpose: ~x

For binary relation R:
  • ~R = {x, y | y -> x in R}
  • i.e. ~R = inverse of R (often written R-1)

2.6 Notes on transpose

For any binary relation R and any set S:
  • S.~R = R.S (image of set S, back through R)
  • (x -> y) ∈ R.~R iff ∃ z | x -> z + y -> z in R
  • So child_parent . ~child_parent = sibling relation
  • R.~R in iden: R is injective*
  • ~R.R in iden: R is a function*
Pause and meditate on these. Work examples as needed.

2.7 Transitive relations

Definition: R is transitive iff
all x, y, z : univ | 
    ( (x -> y in R)
      and (y -> z in R))
    implies
    (x -> z in R)
Cf. arithmetic < relation.

2.8 Transitive closure: ^x

Definition: transitive closure of R is:
the smallest relation
that contains R
and is transitive.
In Alloy, we write ^R.
So
^R = R + R.R + R.R.R + R.R.R.R + ...

2.9 Transitive closure (example)

E.g.
ancestor = ^parent
descendant = ^child

2.10 Reflexive relations

Definition: R is reflexive iff:
all a : univ | a -> a in R
Or, put another way:
iden in R

2.11 Reflexive transitive closure

Definition: reflexive transitive closure of R (written *R) is
smallest relation
that contains R
and is transitive
and is reflexive
Or, put another way:
*R = ^R + iden
or
*R = iden + R + R.R + R.R.R + ...
N.B. iden includes ‘irrelevant’ atoms, too. Seldom a problem.*

2.12 Domain/range restriction: <:x, x:>

For any set S and any relation R:
  • S <: R = tuples in R beginning with a member of S
  • R :> S = tuples in R ending with a member of S
So domain[R] <: *R is reflexive transitive closure of R without ‘irrelevant’ pairs.

2.13 Override: x ++ y

R ++ S = the override of relations R, S. It contains:
  • every member of R that does not match a member of S
  • every member of S
Two tuples match if they begin with same atom.

2.14 Override example

Suppose homephone and workphone map Name to PhoneNumber.
Suppose we prefer a work number to a home number.
Then preferredphone = homephone ++ workphone. Contains:
  • work number, if we have it
  • home number, if we have no work number

2.15 Exercises

See handout.

3 Set comprehensions, let expressions

3.1 Set comprehensions

Set comprehensions use predicates to define sets:
single = {p : Person | no p.spouse}
childless = {p : Person | no p.children}
descendants = { a, d : Person | d in a.^children }

3.2 let-expressions

A recurring expression can be factored out with let.
sig Person {
  mother : lone Person,
  father : lone Person
}
fun children [p : Person] : set Person {
  let parent = mother + father | parent.p
}
fun descendants[p : Person] : set Person {
 let parent = mother + father | ^parent.p
}
fun descendants2[p : Person] : set Person {
 let ch = {p, ch : Person | ch in children[p]} | 
     p.^ch
}
assert desc_equiv { all p : Person | 
  descendants[p] = descendants2[p]
}

4 More about the Analyzer

(Viva voce work.)

5 Facts, predicates, assertions

5.1 Facts

We can make axiomatic pronouncements using fact:
abstract sig person {}
sig Man, Woman extends Person {
  mother : lone Woman,
  father : lone Man
}
fact biology {
  all p : Person | 
    { (some p.mother iff some p.father)
      (some p.(mother + father) 
       implies
       p.mother != p.father)
}
fact ancestry {
  no p : Person | p in p.^(mother + father)
}
fact adam_eve {
  one adam : Man | no adam.mother and no adam.father
  one eve : Woman | no eve.mother and no eve.father
}

5.2 Signature facts

Facts about a given signature can be given in the signature:
abstract sig person {}
sig Man, Woman extends Person {
  mother : lone Woman,
  father : lone Man
}{
  (some mother iff some father)
  (some (mother + father) 
   implies
   mother != father)
   not (p in ^(@mother + @father)
}
fact adam_eve {
 one adam : Man | no adam.mother and no adam.father
 one eve : Woman | no eve.mother and no eve.father
}

5.3 Signature facts 2

In general, for some formula F
sig A { ... } { F }
is equivalent to
sig A { ... }
fact { all this : A | F′ }
where
  • F′ is just like F except:
  • each field f declared in A or a subtype is expanded to “this.f
  • unless it is written @f

5.4 Predicates

To explore what happens both when some property holds and when it doesn't, use predicates:
sig person {
  mother : lone Woman,
  father : lone Man
}
pred fatherless [ p : person ] {
  no p.father
}

5.5 Finding instances of predicates

To find a model instance satisfying the predicate, use the run command, specifying a scope:
pred fatherless [ p : person ] {
  no p.father
}
run fatherless for 3
run fatherless for 10

5.6 Assertions

Assertions reflect properties we believe are guaranteed for all instances of the model.
sig Person {
  mother : lone Person,
  children : set Person
}{
  not (this in this.^@mother)
}
// Check that that signature fact means what we think:
assert no_self_ancestor {
  no p : Person | p in p.^mother
}
check no_self_ancestor for 10
Alloy checks an assertion by seeking a counter-example.

5.7 More assertions

fact mother_and_child {
  all m, c : Person | c in m.children iff m in c.mother
}
// That means that 'mother' = 'children' ** -1
assert mother_child_inverse {
  mother = ~children
  children = ~mother
}
assert no_self_descendant {
  no p : Person | p in p.^children
}
check mother_child_inverse for 10
check no_self_descendant for 10

5.8 Assertions as a self-test tool

Handy way to check our understanding
sig element {
  r, s : set element
}
assert transpose { r = ~s iff s = ~r }
check transpose for 10
(So checking both mother = ~child and child = ~mother was overkill.)

5.9 Functions

Functions are named expressions, with
  • arguments
  • a bounding expression for result
  • an expression to evaluate

5.10 Functions, example

sig Person {
  mother : lone Person,
  father : lone Person
}

fun children [p : Person] : set Person {
  mother.p + father.p
}
assert children_alternatives {
  all p : Person | children[p] = (mother + father).p
  all p : Person | children[p] = p.~(mother + father)
}
check children_alternatives for 10
fun descendants[p : Person] : set Person {
  ^(mother + father).p
}

5.11 Exercises

See handout.

6 Three styles of expression

Expressing “The address relation maps each name to at most one address”:
  • predicate calculus style:
    all n : Name, d, d' : Address |
      n -> d in address and n -> d' in address
      implies 
      d = d'
  • navigational style:
    all n : Name | lone n.address
  • relational style:
    no ~address.address - iden

6.1 Predicate-calculus style

Only two kinds of expressions:
  • relation names (used as predicates)
  • tuples from quantified variables
all n : Name, d, d' : Address |
  n -> d i address and n -> d' in address
  implies 
  d = d'
Often verbose.

6.2 Navigational style

Expressions denote sets; sets are formed by navigating from quantified variables along relations.
all n : Name | lone n.address

6.3 Relational style

Expressions denote relations. No quantifiers; who needs 'em?
no ~address.address - iden
Sometimes cryptic.

6.4 And yet another ...

Multiplicity keywords allow another formulation:
address in Name -> lone Address
Or just declare it that way:
sig AddressBook {
  address : Name -> lone Address
}

6.5 Exercises

See handout.