CS195Y Lecture 9

2/17/16

Announcement: Alloy 2 deadline is extended to Friday, 2/19 at 11:59pm. You may still use your late pass to Saturday, 2/20 at 11:59pm.
Note about the homework: Make sure to check Piazza for a common bug for the Goats and Wolves problem.
Note about efficiency: if your model is buggy and thus unintentionally unsatisfiable, it will take much longer to run in general.

Q: Is it a good idea to put the bounds way up so there are more potential solutions? A: No, because raising the bounds exponentially increases the solutions Alloy needs to consider.

Hint for the homework, Problem 2: Goats and Wolves - the smallest solution Tim knows of is 11 crossing events (12 states). Also, util/ordering may be significantly more efficient than seq for some models, which was something we did not anticipate. If your model is taking an unreasonable time to run (more than a few minutes), try switching to util/ordering on States.


River Crossing Puzzles Continued

Farmer, Fox, Chicken, Grain

fact eating { eats = Fox->Chicken + Chicken->Grain }

Two ways of looking at eats:

  1. The field of a given object. That objects eats some other object(s).
  2. The set of all “eating pairs”. object1 -> object2 in eats means that object1 eats object2.
Digression on until/ordering

For the purpose of experimentation, let’s order all the objects using util/ordering.

open util/ordering[Object]

In the evaluator, we can now use this ordering. For example, entering

first 

outputs

{Chicken$0}

What happens if we enter:

first.next.next.next.next.next

If this were a programming language, we would probably get an error, because this field doesn’t exist. But since this is Alloy, where it isn’t true field access but instead relational joins, this evaluates to:

{}

Also,

ordering/next

is a binary relation that gives you all the “edges” of the ordering.

Q: What would we do if we wanted to only order farmers? A: We could pass farmer instead of object. Q: What if we wanted to order all Animal objects (ruling out the grain)? A: We can add a level to the subtyping: Animal extends Object, etc.

Should we make Animal abstract? What’s the problem about talking about things that aren’t in a subtype of the abstract sig? Q: What makes abstract different? A: There can’t be direct instances of it. Q: What can you say about the union of the subtypes? A: The union of the subtypes is exactly the abstract sig.

Back to the Puzzle

We need to specify initial and ending states in order to get meaningful instances. The built in Alloy solution does this slightly differently than we did in previous classes.

Q: Why is it ord/first instead of just first? A: If you’re using multiple modules, this specifies which module’s definitions you intend to use.

Q: What does let do? A: It allows you to bind an identifier to a certain expression, to avoid repeating that expression in the body of the let statement. (Note: this is a common construct in languages without mutation).

Q: Why is the ending condition a predicate? A: Design decision, if the ending condition is a predicate we can run that predicate to obtain a solution.

If this looks odd to you, Tim suggests opening up this example in Alloy and spending some time looking at the instances it produces.

Let’s look at the fact that models that state transitions are valid. This is different than how we modeled transitions previously, so what’s going on here?

Q: What is the meaning of the expression ord/next[s]? A: This expression is the next state after s (of which there is exactly one), or nothing. This is equivalent to s.(ord/next). Because there is either one thing or nothing, we could also use a let statement. We don’t need to do “all states but the last one” here, because we are quantifying both s and s'. If there is no next state, there will be no s', so it won’t trigger the body.

fact stateTransition {
  all s: State, s': ord/next[s] {
    Farmer in s.near =>
      crossRiver[s.near, s'.near, s.far, s'.far] else
      crossRiver[s.far, s'.far, s.near, s'.near]
  }
}

Note on syntax: => here is not implies, because of the else on the next line. The combination of the two is an if-then-else block. In Alloy, => is an overloaded syntax that can serve either function.

Let’s run the sample instance and check out the evaluator. We used predicates for transitions, so there are no explicit events.

Pros of using util/ordering instead of seq: The instances are often easier to read, because atoms are numbered nicely. Projecting over the ordered sig is also much more pleasant.

If something looks fishy/wrong in the evaluator or the tree, use the evaluator to check! In this case: where did the chicken go in this intermediate state?!? It got eaten :(

Q: Why didn’t the chicken simultaneously eat the grain? Who’s to say the fox eats first? A: Interesting, we aren’t sure! Alloy is not imperative, so it’s not that one thing happens first and changes the outcome of the second - is it arbitrarily choosing one? Tim will look into it for Friday!