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
- customizing the theme
- exporting examples
- evaluator
(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.