CS1950Y Lecture 7: Multiplicities and Quantifiers
2/7/18


Multiplicities and Quantifiers

Review

Back to relational operators with our city example from last time.

sig City {roads: set City}
run {} for exactly 6 City

Alloy has multiplicities:

pred multiplicityPratice {
	some roads
	one roads
	lone roads
	no roads
}

What do all of these quantifiers mean?

Which of these can coexist? run multiplicityPractice for exactly 6 City is unsatisfiable as expected. But if we comment out the no roads, Alloy can satisfy this model with one road. Let's try to rule out self loops just using the relational operators and multiplicities.

Question: what do you mean specifically by relational operators?
Answer: Some of the multiplicities shown and operators like join, union, set difference, and some other builtin operators.

fact roadsGoSomewhere {
	no iden & roads
}

What does this actually mean? What is their intersection? This gives us all of the self-loops in roads (e.g. City0 -> City0), and then we assert that there are none of them. Frequently in the text you'll see predicates building up relations and using multiplicities. So you want to get used to reading and understanding predicates written this way. They typically run faster than a predicate using quantifiers, which can be good if your model is running slowly.

Question: How do you know when to use 'fact' and when to use 'pred'?
Answer 1: A fact will hold no matter what. Alloy has to satisfy this constraint. Predicates are helpers. Alloy can ignore the predicate unless we reference it to give it some say.
Answer 2: Tim likes to start off with predicates. Because facts are held to always be true, they can cause subtle, hard-to-find bugs. Try to use as few facts as possible. Rather than have facts A, B, C, you can make them all predicates and run them in the combination you need at the time.

Let's look at quantifiers:

pred someAll {
	some c: City | all c2: City-c | c2 in c.roads
}

pred allSome {
	all c: City | some c2: City-c | c2 in c.roads
}

check { allSome iff someAll } for exactly 4 City

Exercise: What's the difference between these two predicates? Are they the same? Why?
The order in which we nest all and some matters. The first says that there exists some 'Golden city' that has a road to every other city. The second one says that every city has an escape route (or an outgoing road). Alloy confirms that these two predicates are different when we execute the check statement.

Question: Can we make a pred for some city that has all roads leading into it?
Answer: Let's model that.

pred romeExists {
	-- "All roads lead to Rome"
	some rome: City | all other: City-rome |
		rome in other.roads -- or other in roads.rome
}
run romeExists for exactly 4 City

Question: This checks for just direct, single step routes?
Answer: Yes

Question: Can there be more than one 'Rome'?
Answer: Sure. Consider the complete graph - every city is a Rome. Let's try

pred allConnected {
	all c1, c2: City | c1-> c2 in edges
}

run {romeExists and allConnected} for exaclty 4 City

This won't work as we expect it to. Why?
We've declared a fact that says no self loops, but in the universal quantifier, c1 can be the same as c2. We can use some nice shorthand from alloy disj that means disjoint and add it after all. Now when we run, Alloy shows us only examples of complete graphs, and we can see four distinct instances where the example picked for 'Rome' varies.

Question: 'some' means at least one. Why does Alloy never identify more than one 'Rome' in an instance?
Answer: Alloy won't identify more than one unless we ask it to. That would require us asserting the existence of some set of 'Romes' and then asking for that set.

Now we're going to construct a predicate that takes in a set of Cities, and if a cycle exists through all cities using only edges between the cities in the set. This predicate should return true. We're going to produce a series of potential implementations of this predicate and debug them along the way.

pred isCycle[cities: set City] {
	...
}

First try:

pred isCycle1[cities: set City] {
	cities in cities.^roads
}

run isCycle1

We get an instance of City0 ---> City1. Alloy can choose the set cities, so here it might be making it the empty set to make this a satisfying instance. We'll update our run statement:

 run {some cities: set City | isCycle1[cities] and some cities}

This predicate is what we call 'underconstrained' - we're getting behavior we don't want. Let's try another implementation. We take the cross product of cities and intersect it with roads to get the localRoads. Then we say that each city can reach itself in the transitive closure. That sounds like a cycle!

pred isCycle2[cities: set City] {
	let localRoads = cities->cities & roads |
		all c: cities | c in c.^localRoads
}

run {some cities: set City | isCycle1[cities] and some cities} 

Spoiler: This won't work the way we want it to because each city in cities must be in a cycle, but not necessarily in a cycle encompassing all cities. We create a test predicate that constructs an invalid instance and see if it reconciles with the isCycle2 predicate.

-- Test predicate!
run test_isCycle2_discon {
	some disj a, b, c, d: City | {
		roads = a -> b + b -> a + c -> d + d -> c
		isCycle2[a+b+c+d]
	}
} for exactly 4 City -- expect false

Alloy finds an instance, so we are still underconstrained.
Note: This is an incredibly useful technique for when hitting the next button in the visualizer is not giving us interesting/good instances. We can construct our own test cases and check if they correctly or incorrectly satisfy our Alloy model!

-- Test predicate #2!
run test_isCycle2_4cycle {
	some disj a, b, c, d: City | {
		roads = a -> b + b -> c + c -> d + d -> a
		isCycle2[a+b+c+d]
	}
} for exactly 4 City -- expect true

Can we do better in isCycle3? Now we want to say that from every city, we can reach every other city. This should help us get our test_isCycle2_discon to fail as expected.

pred isCycle3[cities: set City] {
	let localRoads = cities->cities & roads |
		all c: cities | all c2: cities-c | c2 in c.^localRoads
}

But this still doesn't work! A hub with two-way spokes out to the rest of the cities would pass this predicate.

We'll finish this example on Friday, where it will lead into our next topic: Skolemization.