Ways to model the farmer, goat, cabbage, wolf puzzle? - alloy

I am cataloging various ways of modeling the farmer, goat, cabbage, wolf problem.
Below are two ways to model the problem. Are there other, reasonable, ways to model it?
One model defines a set of River objects. Each River object represents a snapshot of the River and its two sides after the farmer has done a ferry.
sig River {
side1: set Item,
side2: set Item
}
Another model has one River object. The items on the two sides of the River vary over time.
one sig River {
side1: Item -> Time,
side2: Item -> Time
}
What are other, reasonable, ways to model the farmer, goat, cabbage, wolf problem?

Let's imagine the puzzle as an ordered series of situations where a situation contains location-item pairs.
open util/ordering[Situation]
abstract sig Location {}
one sig SideA, SideB extends Location {}
abstract sig Item {}
one sig Goat, Cabbage, Wolf, Farmer extends Item {}
sig Situation {
l_i: Location -> Item
}
Puzzle rules are easy to form then:
// in the initial situation everyone is on SideA
one s: Situation & first | all i: Item | s.l_i.i = SideA
// in the final situation everyone is on SideB
one s: Situation & last | all i: Item | s.l_i.i = SideB
// in all other situations the locations of the goat/wolf and the cabbage/goat must be diffent, except when the farmer is also there
all s: Situation - first - last | (s.l_i.Goat != s.l_i.Cabbage) or s.l_i.Goat = s.l_i.Farmer
all s: Situation - first - last | (s.l_i.Goat != s.l_i.Wolf) or s.l_i.Goat = s.l_i.Farmer
// further puzzle constraints ...
I'm curious if there's a more compact way to refer to the first item in an ordering than
one s: Situation & first

Related

Ordering predicate is unsatisfiable

There seems to be something I don't understand about the first branch of the ordering predicate in ff_next of this alloy model.
open util/ordering[Exposure]
open util/ordering[Tile]
open util/ordering[Point]
sig Exposure {}
sig Tile {}
sig Point {
ex: one Exposure,
tl: one Tile
} fact {
// Uncommenting the line below makes the model unsatisfiable
// Point.ex = Exposure
Point.tl = Tile
}
pred ff_next[p, p': Point] {
(p.tl = last) => (p'.ex = next[p.ex] and p'.tl = first)
else (p'.ex = p.ex and p'.tl = next[p.tl])
}
fact ff_ordering {
first.ex = first
first.tl = first
all p: Point - last | ff_next[p, next[p]]
}
run {}
The intuition here is that I have a number of exposures, each of which I want to perform at a number of tile positions. Think doing panorama images and then stitching them together, but doing this multiple times with different camera settings.
With the noted line commented out the first instance I get is this:
This is equivalent to one pass over the panorama with exposure one, and then dropping the other exposures on the floor.
The issue seems to be the first branch after the => in ff_next but I don't understand what's wrong. That branch is never satisfied, which would move to the next exposure and the start of the panorama. If I uncomment the line Point.ex = Exposure the model becomes unsatisfiable, because it requires that branch.
Any help on why that branch is not satisfiable?
It looks like you're trying to express "every tile must correspond to point with the current exposure before we move to the next exposure." The problem is a major pitfall with ordering: It forces the signature to be exact. If you write
run {} for 6 but 3 Tile, 2 Exposure
Then that works as expected. There are only models when #Point = #Exposure * #Tile. You can write your own reduced version of ordering if this is an issue for you.

Grouping of people multiple times, where all the members meet each other in the same group at least once

I want to group people into smaller subgroups, and after shuffling groups multiple times for successive sessions, make all the people meet each other at least once.
In every session, people are divided into a constant number of groups. Everyone has to join one group in every session.
The group size should be closest to (the number of people)/(# of groups). There should not be a groups of too few people or too many people.
The sessions are continued until every pair of people meets each other at least once.
Preferably, the number of times the same pair meet each other should be minimized.
The following is the answer for this problem for 11 people (numbered 0-10) and 3 groups (3 columns). It requires 5 sessions.
Session 1: 3,6,8,10 0,1,7,9 2,4,5
Session 2: 3,5,7,8 0,1,2,10 4,6,9
Session 3: 0,1,6,8 2,3,4,9 5,7,10
Session 4: 0,3,5,9 1,4,8,10 2,6,7
Session 5: 1,3,5,6 2,8,9,10 0,4,7
Members of two groups of different size must meet each other (1v1, once)
The question above is similar, but I want rather make the people meet just in a group of a larger group, not 1-on-1.
The following is my approach that uses Alloy. This works for a small number of people (~15) and groups (~2), but it quickly causes computation time explosion when the size is increased. I need to calculate it for ~25 people and ~5 groups.
module Teaming
sig Person { groups: some Group }
sig Group { people: some Person }
sig Session { groups: some Group }
one sig Sessions { sessions: some Session }
sig GroupPerSession {}
-- Tree structures
fact {
all s: Session | s in Sessions.sessions
all g: Group | g in Session.groups
all s: Session | all p:Person | p in s.groups.people
people =~ groups
}
-- The total number of people
fact {
all s: Session | #s.groups.people = #Person
}
-- The number of groups per session
fact {
all s: Session | #s.groups = #GroupPerSession
}
-- The number of people in a group
fact {
all g: Group | (#g.people) >= div[#(Person), #(GroupPerSession)] and (#g.people) <= add[div[#Person,#GroupPerSession],1]
}
-- Mutually exclusive grouping in a session
fact separate {
all s: Session | all disj a,b: s.groups | no p: Person | p in a.people and p in b.people
}
-- Every pair of people meets somewhere
pred sameGroup {
all disj a,b: Person | some g: Group | a in g.people and b in g.people
}
-- The same people should not meet too many times
fact sameGroupNotTooMuch {
all disj a,b: Person | #{a.groups & b.groups} <= 3
}
run sameGroup for 6 Int, 5 Session, 15 Group, exactly 3 GroupPerSession, exactly 16 Person
run sameGroup for 6 Int, 6 Session, 24 Group, exactly 4 GroupPerSession, exactly 18 Person
run sameGroup for 6 Int, 7 Session, 35 Group, exactly 5 GroupPerSession, exactly 18 Person
I guess dynamic programming should work, though I cannot find anything specific. Any pointer for the improvement in Alloy code or other algorithms would be great.
Here's my quick shot at solving this problem.
Overall, the generation of instance seems faster, but still have difficulty to complete when trying to assign >20 people into >4 groups.
module Teaming
one sig Settings{
maxEncounter:Int,
minGroupSize:Int,
maxGroupSize:Int
}{
// Manually filling values there helps (1)reducing the integer bit-width needed (2) decrease the complexity (in terms of clauses)
maxEncounter=4
//minGroupSize=5
//maxGroupSize=5
minGroupSize=div[#Person, #Group]
maxGroupSize=add[minGroupSize,1]
}
sig Session{}{
Group.people[this]=Person // all person are assigned in group during a session
no disj g1,g2 :Group| g1.people[this] & g2.people [this] !=none // a person can't be in two disjoint groups of a same session
}
sig Group {
people: Session some -> some Person
}{
all s:Session| #people[s]<= Settings.maxGroupSize and #people[s]>=Settings.minGroupSize
}
sig Person {}
pred allMeet {
all disj a,b: Person | people. a & people.b != none->none
}
pred allMeetAndMinEncounter {
all disj a,b: Person | let x= (people. a & people.b) {
#x <=Settings.maxEncounter
x != none ->none
}
}
run allMeet for 6 Int, 9 Session, exactly 4 Group, exactly 20 Person
Highlight of the changes brought:
Removed quantifications when possible
Removed redundant constraints
Replaced the two binary relations groups and people by a ternary relation. This comes with several advantages:
It reduces the number of group atoms present in an instance to the total of group per session.
It enables the use of instance projection in the instance viewer. You'll now be able e.g. to view group assignment for each session separately.
I do not think Alloy is the right tool for optimisation. It is a specification tool that focuses on finding counter examples. However, it can of course be found to find solutions to puzzles like this. (I think there is a group that developed an extension to Alloy that minimises the found solutions.)
I took a stab though I am a beginner. Surprisingly I found a solution with 4 sessions 11 people and 3 groups.
s0 {2,9,10}, {5,6,7,8}, {0,1,3,4},
s1 {2,4,7,8}, {1,3,6,10}, {0,5,9},
s2 {1,2,3,5}, {0,7,8,10}, {4,6,9},
s3 {0,2,6}, {4,5,10}, {1,3,7,8,9}
Since Alloy is not an optimiser I used the binary way to find the minimum number of sessions, I found that you needed at least 7 sessions for 25/5.
This is my full model:
sig P, Group {}
sig Session {
participants : Group -> P
}
fact {
// tuning goes here (max sure <= scope )
# Group = 5
# P = 25
# Session = 7
// In every session, people are divided into a constant number
// of groups.
all s : Session | s.participants.P = Group
// The sessions are continued until every pair of people
// meets each other at least once.
// Preferably, the number of times the same pair meet
// each other should be minimized.
all disj a,b : P | some participants.a & participants.b
// Everyone has to join one group in every session.
all p : P, s : Session | one s.participants.p
// The group size should be closest to (the number
// of people)/(# of groups).
// There should not be a
// groups of too few people or too many people.
all g : Group, s : Session | (# s.participants[g]) >= 3
}
run {} for 5 Group, 25 P, 24 Session, 6 int
Specifying the int width for these number is crucial.
Finding a series of 8 sessions took 5 seconds, finding the 7 sessions took much longer, 34 seconds. Forcing a more equal group size by increasing the minimum is still running :-)
I think the tool does exactly what it is supposed to do: finding a solution. It is not that good in finding an optimal solution.

How to implement order in a set of sets?

When an aircraft approaches an airport to land, the aircraft's approach procedure is divided up into transitions. Each transition consists of a set of legs.
sig Transition {
legs: set Leg
}
sig Leg {}
The set of legs within a transition is ordered. For each transition, I want to be able to access the first leg in the transition, the last leg in the transition, and I want to navigate from leg to leg in the transition. Thus, I want a first, last, and next function.
What's the simplest way to implement this? I have an implementation working but I wonder if there's something simpler. My implementation associates each Leg to a sequence number:
open util/ordering [SequenceNumber]
sig SequenceNumber {}
sig Transition {
legs: Leg one -> one SequenceNumber
}
Then I created my own utility functions:
fun First (t: Transition): Leg {
t.legs.(min [Leg.(t.legs)])
}
fun Last (t: Transition): Leg {
t.legs.(max [Leg.(t.legs)])
}
fun Next (t: Transition, leg: Leg): Leg {
t.legs.(next [leg.(t.legs)])
}
I am hoping you can show me a simpler solution.
Why not use seq Leg and the inbuilt sequence predicates & functions?

Modelling the Chinese Go game

For an university project I'm trying to write the chinese game of Go (http://en.wikipedia.org/wiki/Go_%28game%29) in Alloy. (i'm using the 4.2 version)
I managed to write the base structure. Go's played on a board 9 x 9 wide, but i'm using a smaller set of 3 x 3 for checking it faster.
The board is made of crosses which can either be empty or occupied by black or white stones.
abstract sig Colour {}
one sig White, Black, Empty extends Colour {}
abstract sig Cross {
Status: one Colour,
near: some Cross,
group: lone Group
}
one sig C11, C12, C13,
C21, C22, C23,
C31, C32, C33 extends Cross {}
sig Group {
stones : some Cross,
freedom : some Cross
}
pred closeStones {
near=
C11->C12 + C11->C21 +
C12->C11 + C12->C13 + C12->C22 +
C13->C12 + C13->C23 +
C21->C22 + C21->C11 + C21->C31 +
C22->C21 + C22->C23 + C22->C12 + C22->C32 +
C23->C22 + C23->C13 + C23->C33 +
C31->C32 + C31->C21 +
C32->C31 + C32->C33 + C32->C22 +
C33->C32 + C33->C23
}
fact stones2 {
all g : Group |
all c : Cross |
(c.group=g) iff c in g.stones
}
fact noGroup{
all c : Cross | (c.Status=Empty) iff c.group=none
}
fact groupNearStones {
all disj c,d : Cross |
((d in c.near) and c.Status=d.Status)
iff
d.group=c.group
}
The problem is: following Go rules, every stones must be considered as part of a group. This group is made of all the adiacent stones with the same colour.
My fact "groupNearStones" should be sufficient to describe that condition, but this way I can't get groups made of more of 3 stones.
I've tried rewriting it in different ways, but either the analizer says it found "0 variables" or it groups up all the stones with the same status, regardless of wheter they're near each other or not.
If you could give me any insight I will be grateful, since i'm breaking my head on this simple matter for days.
Ask yourself two questions.
First: in Go, what constitutes a group? You say yourself: it is a set of adjacent stones with the same color. Not that every stone in the group must be adjacent to every other; it suffices for every stone to be adjacent to another stone in the group.
So from a formal point of view: given a stone S, the set of stones in the group as S is the transitive closure of the stones reachable through the relation same_color_and_adjacent, or S.*same_color_and_adjacent.
Second: what constitutes being the same color and adjacent? I think you can define this easily, with what you have.
On a side issue; you may find it easier to scale the model to arbitrary sizes of boards if you reify the notion of rows and columns.
I hope this helps.
[Addendum:] Apparently it doesn't help enough. I'll try to be a bit more explicit, but I want the full solution to come from you and not from me.
Note that the point of defining a relation like same_color_and_adjacent is not to eliminate the formulation of facts or predicates in your model, but to make them easier to write and to write correctly. It's not magic.
Consider first a reformulation of your fact groupNearStones in terms of a single relation that holds for pairs of stones which are adjacent and have the same color. The relation can be defined by modifying your declaration for Cross:
abstract sig Cross {
Status: one Colour,
near: some Cross,
group: lone Group,
near_and_similar : some Cross
}{
near_and_similar = near & { c : Cross | c.#Status = Status}
}
Now your existing fact can be written as:
fact groupNearStones2 {
all disj c,d : Cross |
d in c.near_and_similar
iff
d.group=c.group
}
Actually, I would write both versions of groupNearStones as predicates, not facts. That would allow you to check that the new formulation is really equivalent to the old one by running a check like:
pred GNS_equal_GNS2 {
groupNearStones iff groupNearStones2
}
(I have not run such a check; I'm being a little lazy.)
Now, let us consider the problems you mention:
You never get groups containing more than three stones. Actually, given the formulation of groupNearStones, I'm surprised you get groups with more than two. Consider what groupNearStones says: any two stones in a group are adjacent and have the same color. Draw a board on a piece of paper and draw a group of five stones. Now ask whether such a group satisfies the fact groupNearStones. Say the group is C11, C12, C13, C21, C22. What does groupNearStones say about the pair C21, C13?
Do you see the problem? Are the relations near and 'close enough to be in the same group' really the same? If they are not the same, are they related?
Hint: think about transitive closure.
You never get groups containing a single stone.
How surprising is this, given that groupNearStones says that c.group = d.group only if c and d are disjoint? If you never get single-stone groups, then every stone that should be a single-stone group is not classed as being in any group at all, since such a stone must not satisfy the expression s.group = s.group.
Do you see the problem?
Hint: think about reflexive transitive closure.

Understanding predicates in alloy

Can someone please help me understand predicates using the following example:
sig Light{}
sig LightState { color: Light -> one Color}
sig Junction {lights: set Light}
fun redLigths(s:LightState) : set Light{ s.color.Red}
pred mostlyRed(s:LightState, j:Junction){
lone j.lights - redLigths(s)
}
I have the below questions about the above code:
1) What happens if the above predicate is true?
2) What happends if it is false?
3) Can someone show me a bit of alloy code that uses the above code and clarifies the meaning of predicates through the code.
I am just trying to understand how do we use the above predicate.
Nothing "happens" until you place a call to a predicate or a function in a command to find an example or counterexample.
First, use the right terminology, nothing 'happens' when a predicate is true; it's the more like the other way around, an instance (an allocation of atoms to sets) satisfies (or doesn't) some condition, making the predicate true (or false).
Also, your model is incomplete, because there is no sig declaration for Color (which should include an attribute called Red).
I assume you want to model a world with crossroads containing traffic lights, if so I would use the following model:
abstract sig Color {}
one sig Red,Yellow,Green extends Color {}
sig Light {
color: Color
}
sig Junction {
lights : set Light
}
// This is just for realism, make sure each light belongs to exactly one junction
fact {
Light = Junction.lights
no x,y:Junction | x!=y and some x.lights & y.lights
}
fun count[j:Junction, c:Color] : Int {
#{x:Light | x in j.lights and x.color=c}
}
pred mostly[j:Junction, c:Color] {
no cc:Color | cc!=c and count[j,cc]>=count[j,c]
}
run{
some j:Junction | mostly[j,Red]
} for 10 Light, 2 Junction, 10 int
Looking at the above, i'm using the # operator to count the number of atoms in a set, and I'm specifying a bitwidth of 10 to integers just so that I don't stumble into an overflow when using the # operator for large sets.
When you execute this, you will get an instance with at least one junction that has mostly red lights, it will be marked as $j in the visualizer.
Hope this helps.
sig Light{}
sig LightState { color: Light -> one Color}
sig Junction {lights: set Light}
fun redLigths(s:LightState) : set Light{ s.color.Red}
pred mostlyRed(s:LightState, j:Junction){
lone j.lights - redLigths(s)
}
What the predicate simply means in the example you gave is;
The difference between the set A, in this case the relation (j.lights) and another set say B, returned from the function redligths, of which the Predicate will always constraint the constraint analyser to return only red light when you run the Predicate "mostlyRed".
And note that the multiplicity "lone" you added to the predicate's body only evaluate after the difference between the set A and B (as I assumed) has been evaluated, to make sure that at most one atom of red is returned. I hope my explanation was helpful. I will welcome positive criticism. Thanks

Resources