Refactoring Alloy models - alloy

In a model I started to sketch in Alloy the other day, I get the following message when I attempt to find an instance of a particular predicate:
Translation capacity exceeded.
In this scope, universe contains 34 atoms
and relations of arity 12 cannot be represented.
Visit http://alloy.mit.edu/ for advice on refactoring.
Any suggestions of where on the site alloy.mit.edu to look? I'm not finding anything with an obvious label like "Refactoring models that exceed translation capacity".
That's the essential question.
[Postscript: the cause of my problem appears to have been a bad initial formulation of the quantified variable declarations I was using in a predicate; the problem went away once I got the syntax of the declarations right. The full details are not instructive enough to be worth keeping on record, so I'm dropping the original description of the specifics. The short version is: to elicit the instantiation of a particular concrete example, I initially wrote a predicate of the form
pred m {
one t1 : table,
r1, r2, r3 : row,
c1, c2 : column,
c11, c21 : headingcell,
c12, c22, c13, c23 : datacell | {
... // description of the example here
}
}
The one scopes all twelve variables, and is [I am told on good authority] translated internally into a set comprehension defined by a relation of arity 12. What I wanted to say was something more like the following, which does not raise the translation-capacity issue:
pred m {
some t1 : table |
some disj r1, r2, r3 : row |
some disj c1, c2 : column |
some disj c11, c21 : headingcell |
some disj c12, c22, c13, c23 : datacell | {
...
}
}
So: one way to fix some models which elicit the translation-capacity error message is to clean up the quantification of variables.
The basic question, however, retains its interest: when a model elicits the translation-capcity error message and the quantifiers are already clean and correct, is there a document to read?]

The kind of refactoring needed in this case is unlikely to be a simple syntactic one. Rather, it here means restructuring the model so that it doesn't use a relation of that high arity. In your example above, I can't really see which relation has arity 12. If you post (or send me) a self-contained model, I can look at it, identify the problematic relation, and maybe even suggest how to avoid it.

Related

Comparing predicates

A poster asked how to compare functions in Alloy. While testing a small example (comparing predicates instead of functions) to answer the question with, I've noticed the following behavior, which puzzles me.
The analyzer finds no counterexamples whenever the boundary of the check command is higher than 3 and the fact 'f1' is active. Inactivating the fact, the analyzer works as expected. Why does the redundant fact 'f1' modify the analyzer's operation so and why just in the case the boundary is higher than 3?
open util/ordering [V]
sig V {}
fact f1 {
# V > 0
}
pred p1 [x: V] {
x = last
}
pred p2 [x: V] {
x = first
}
assert a1 {
all x: V | p1[x] <=> p2[x]
}
check a1 for 3
It appears that whenever the check boundary is 4 or higher and 'f1' is active the analyzer reports '0 vars. 0 primary vars. 0 clauses.'
I am unable at the moment to look into the details, but it seems likely that you're seeing overflow behavior, based in part on the fact that Alloy's integers are very narrow (4 bits by default, I believe?) twos-complement integers, so overflow happens regularly.
Several changes might be instructive, separately or together, to see if they affect the behavior.
replace fact f1 with some V
turn on the "Forbid Overflow" option
provide an explicit bit width for Int using the scope command (for other signatures, the scope number specifies a maximum number of instances; for Int it specifies a bit width)
As Loïc Gammaitoni has put it in another question here "You should always be careful when playing with numbers in Alloy".

Search Game in Prolog

I was wondering if someone can help me, I have done a lot of work on the 8 Piece puzzle program, and now I want to stretch this out, however I am struggling.
So here is the board.
The idea of this is to try and get a piece for instance P1 which is currently residing at a1 to end up at b1. There can be anywhere up to 5 other pieces on the board and each piece can only occupy and move 1 space at a time.
What I want to be able to do is calculate the moves that are needed to get, for example P1 at position B1, to P1 at position A3 (Or any finishing position to be honest) if it can only move 1 space at a time. No two pieces can occupy the same space, and no pieces can cross over to the other side if their is a piece in the t zone. How can I code it so that when I input something like
?- pmove([at(a1,p3),at(b1,p1),at(b3,p2)],
[at(a1,p1),at(b1,p3),at(b3,p2)],M).
which inputs the starting states of all the positions and where they should all end up It will output something along the lines of:
M = [move(p3,a1,t),move(p1,b1,b2),move(p3,t,b1),
move(p1,b2,t),move(p1,t,a1)]
Showing all of the moves it took to get the piece from start to finish, as well as the moves the other pieces had to take to get to their positions. I believe it would be best to use Breadth First Search for this, but I am not all too sure where to go from there.
This is an excellent problem and working through it will be an excellent way to improve at Prolog! So I commend your choice of problem.
This answer is a sketch, not a complete solution, and I hope that is sufficient for your needs.
What you want to do next is to write a predicate that expresses a single valid move from one state to another, something that looks like this:
singlemove(StartBoardState, Move, NextBoardState) :- ...
So we're going to regard lists of at(Place, Piece) as a board state, and structures like move(Piece,From,To) as a move; the former will unify with StartBoardState and NextBoardState and the latter with Move.
The rules of your game should be encoded in singlemove/3. You could think of it as the relationship between a given board state, every valid move and the resultant states.
I think once you have this, at least one inefficient way to solve your problem will become apparent to you, using a brute-force search. Once you have that working (slowly, possibly only for two-move games), you can begin to see how to improve the performance by making the search more intelligent.
How to Implement singlemove/3
From the question, the rules of this game are:
...it can only move 1 space at a time. No two pieces can occupy the same space, and no pieces can cross over to the other side if their is a piece in the t zone.
So first, let's state some facts about the board. What are the spaces called?
boardspace(b1).
boardspace(b2).
boardspace(b3).
boardspace(t).
boardspace(a1).
boardspace(a2).
boardspace(a3).
Now we need some positional information.
:- op(300, xfx, left_of).
:- op(300, xfx, right_of).
b1 left_of b2.
b2 left_of b3.
a1 left_of a2.
a2 left_of a3.
row(b1, upper).
row(b2, upper).
row(b3, upper).
row(a1, lower).
row(a2, lower).
row(a3, lower).
X right_of Y :- Y left_of X.
adjacent(X, Y) :- X left_of Y.
adjacent(X, Y) :- X right_of Y.
adjacent(t, X) :- boardspace(X), X \= t.
adjacent(X, t) :- boardspace(X), X \= t.
I'm not sure yet if I'm going to need all of this, but this seems like a plausible start. Now let's address the rules.
There are thus three rules to the game:
Only one piece may move per turn.
A piece can only move one space per turn.
No two pieces can occupy the same space.
No pieces can "cross over to the other side" if there is a piece in the t-zone.
I feel like #1 is handled adequately by having a predicate singlemove/3 at all. We call it once, we get one move.
For #2, we can construct the list of nearby spaces based on what is adjacent to the piece right now. Assuming p1 is to move and I have a board as defined above, member(at(StartLocation, p1), Board), adjacent(StartLocation, EndLocation) will unify EndLocation with places that p1 can move. Let's try it:
?- Board = [at(a1,p3),at(b1,p1),at(b3,p2)],
member(at(StartLocation, p1), Board),
adjacent(StartLocation, EndLocation).
Board = [at(a1, p3), at(b1, p1), at(b3, p2)],
StartLocation = b1,
EndLocation = b2 ;
Board = [at(a1, p3), at(b1, p1), at(b3, p2)],
StartLocation = b1,
EndLocation = t ;
false.
So this seems correct; the adjacent locations to b1 are b2 and t.
Now let's codify the next rule, no two pieces can occupy the same space.
unoccupied(Board, Location) :-
\+ member(at(Location, _), Board).
Now we can combine these two things into a good start at singlemove/3:
singlemove(Board,
move(Piece,StartLocation,EndLocation),
[at(EndLocation,Piece)|RemainingLocations]) :-
select(at(StartLocation,Piece), Board, RemainingLocations),
adjacent(StartLocation, EndLocation),
unoccupied(Board, EndLocation).
Let's try it:
?- Board = [at(a1,p3),at(a2,p1),at(a3,p2)],
singlemove(Board, Move, NextBoard).
Board = [at(a1, p3), at(a2, p1), at(a3, p2)],
Move = move(p3, a1, t),
NextBoard = [at(t, p3), at(a2, p1), at(a3, p2)] ;
Board = [at(a1, p3), at(a2, p1), at(a3, p2)],
Move = move(p1, a2, t),
NextBoard = [at(t, p1), at(a1, p3), at(a3, p2)] ;
Board = [at(a1, p3), at(a2, p1), at(a3, p2)],
Move = move(p2, a3, t),
NextBoard = [at(t, p2), at(a1, p3), at(a2, p1)] ;
false.
So what's interesting about this? I'm using select/3 to chop the list into candidates and remainders. I'm building the results in the head of the clause. But otherwise, I'm really just taking your rules, translating them into Prolog, and listing them. So you can see you just need one more predicate to implement your fourth rule and it will go right after unoccupied/2, to further filter out invalid moves.
Hopefully, you get the gist of the process. My data model may be too much, but then again, you may find you need more of it than it seemed at first. And the search strategy is weak. But this is the underpinning of the overall solution, the base case. The inductive case will be interesting—I again suggest you try it with the built-in depth-first strategy and see how horrible it is before resorting to BFS. You will probably want to use trace/0 and see when you get stuck in a trap and how you can circumvent it with better explicit reasoning. But I think this is a good start and I hope it's helpful to you.

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.

alloy model for hydrocarbons

i need to model hydrocarbon structure using alloy
basically i need to design alkane, alkene and alkyne groups
i have created following signatures(alkene example)
sig Hydrogen{}
sig Carbon{}
sig alkenegrp{
c:one Carbon,
h:set Hydrogen,
doublebond:lone alkenegrp
}
sig alkene{
unit : set alkenegrp
}
fact{
all a:alkenegrp|a not in a.doublebond.*doublebond
all a:alkenegrp|#a.h=mul[#(a.c),2]
}
pred show_alkene{
#alkene>1
}
run show_alkene
this works from alkene but when ever i try to design the same for alkane or alkyne by changing the fact like all a:alkynegrp|#a.h=minus[mul[#(a.c),2],2] it doesnt work.
Can anyone suggest how do i implement it?
My problem statement is
In Organic chemistry saturated hydrocarbons are organic compound composed entirely of single
bonds and are saturated with hydrogen. The general formula for saturated hydrocarbons is
CnH2n+2(assuming non-cyclic structures). Also called as alkanes. Unsaturated hydrocarbons
have one or more double or triple bonds between carbon atoms. Those with double bond are
called alkenes. Those with one double bond have the formula CnH2n (assuming non-cyclic
structures). Those containing triple bonds are called alkynes, with general formula CnH2n-2.
Model hydrocarbons and give predicates to generate instances of alkane, alkene and alkyne.
We have tried as:
sig Hydrogen{}
sig Carbon{}
sig alkane{
c:one Carbon,
h:set Hydrogen,
n:lone alkane
}
fact{
//(#h)=add [mul[(#c),2],2]
//all a:alkane|a not in a.*n
all a:alkane|#a.h=mul[#(a.c),2]
}
pred show_alkane(){}
run show_alkan
e
General formula for alkane is CnH2n+2,for multiplication we can use mul inbuilt function but we can not write for addtion as we have to do CnH2n+2.What should we write so that it can work for alkane
I understand alkanes, alkenes, and alkynes a little better now, but I still don't understand why you think your Alloy model doesn't work.
To express the CnH2n-2 constraint, you can certainly write what you suggested
all a:alkynegrp |
#a.h = minus[mul[#(a.c), 2], 2]
The problem is only that in your alkane sig declaration you said c: one Carbon, which is going to fix the number of carbon atoms to exactly 1, so minus[mul[#(a.c), 2], 2] is always going to evaluate to exactly 0. I assume you want to alloy for any number of carbons (since Cn) so you should change it from c: one Carbon to c: set Carbon. If you then run the show_alkane predicate, you should get some instances where the number of carbons is greater than 1 and thus, the number of hydrogens is greater than 0.
Also, for the alkane formula
all a:alkynegrp |
#a.h = plus[mul[#(a.c), 2], 2]
the default scope of 3 will not suffice, because you will need at least 4 atoms of hydrogen when a.c is non-empty, but you can fix that by explicitly giving a scope
run show_alkane for 8
If this wasn't the problem you were talking about, please be more specific about why you think "it doesn't work", i.e., what is it that you expect Alloy to do and what is it that Alloy actually does.

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