CS195Y Lecture 10

2/19/16

Announcement: there will be some shuffling of the course calendar, you can check the website for an updated schedule.

River Crossing Puzzle Continued

The question from Wednesday’s lecture: the Chicken disappeared. Why didn’t the chicken simultaneously eat the grain?

When you write an Alloy model, you give a set of constraints, where many instances might satisfy the constraints.

In the farmer model, consider the constraint:

from' = from - Farmer - from'.eats

Note that this is a recursive definition: from' appears on both the left and right hand sides.

Q: Does the above constrain allow both the chicken and the grain to be simultaneously eaten?
A: If the Chicken gets eaten, it must be in from'.eats, so Chicken cannot be in from' (because of the set subtraction on the right hand side). So, the Grain cannot also be eaten, because Chicken not in from' implies that Grain is not in from'.eats.

expect Keyword

run solvePuzzle for 8 State expect 1

expect is a keyword in Alloy (that is unfortunately absent in the documentation). It can be used in a run statement to signify that you expect there to be at least one satisfying instance.

Transitive Closure

The following models a simple graph:
sig Node { edges : set Node }

run { _ edges & iden }

What should we fill in the blank to eliminate self-loops from the instance?

run { no edges & iden }

The constraint no edges & iden eliminates the possibility of self-loops from the graph. What if we wanted to eliminate all loops?

To eliminate length 2 loops from the graph, we could use:

no edges.edges & iden

To eliminate length 3 loops from the graph, we could use:

no edges.edges.edges & iden

This is tedious! Fortunately, Alloy has a built-in operator that represents repeated joins of a relation and itself.

The “transitive closure” of a 2-column relation is the smallest relation that encompasses the relation and satisfies transitivity. It can be thought of as repeatedly joining the relation with itself. In Alloy, the ^ operator gives the transitive closure.

The transitive closure is useful to express the “reachability” of a graph. If we wanted to eliminate all loops from our graph in this example, we could then use:

no ^edges & iden

Which constraints the instance such that no node is “reachable” from itself.

Symmetry Breaking and Isomorphism

If we keep clicking next when running the above model, the following message will pop up:

There are no more satisfying instances. Note: due to symmetry breaking and other optimizations, some equivalent solutions may have been omitted.

Alloy, by default, tries to not show instances that are “isomorphic” to one another. Isomorphic, informally, refers to things that are the same up to renaming. For example, graphs are isomorphic to one another if one’s vertices can be relabeled to create the other.

Q: Is it a Good Thing that Alloy rules out isomorphic examples?
A: It depends!

In general, this is a useful feature of Alloy, because it allows you to see more useful instances more quickly.

When isn’t symmetry breaking useful?

If we wanted to count the number of instances, it prevents us from doing so.

If our instances correspond to real-world things, like routes between cities, we wouldn’t want Alloy to assume all cities are the same. We can get around this by explicitly naming sigs:

sig Providence extends Node
sig Denver extends Node

Alloy would then generate graphs that are the same up to naming, because we’ve given the names significance.

Q: Why does naming the nodes decrease the number of variables and clauses?
A: Tim isn’t sure! To help us find out: in Options, you can turn “message verbosity” to high, and Alloy will give you more information about how it’s generating instances. The answer is likely related to the fact that we’re specifying the scope of Providence and Denver to both be one.

Other downside to turning off symmetry breaking: it can slow down finding instances.

Back to our earlier point: if we expect 1, Alloy will turn off symmetry breaking by default. If we expect 0, Alloy will turn it off by default.

Note that we’ll spend more time later in the semester on how Alloy works under the hood to generate instances.

The takeaway from this: when browsing built in Alloy examples, you may see the expect keyword. In general, it’s a good idea to keep symmetry breaking on.