Alloy error signature - alloy
I've to run an example of the book "Logic in computer Science", Michael Huth and Mark Ryan. The example is on section 2.7.3, and it's the next one:
module PDS
open std/ord -- opens specification template for linear order
sig Component {
name: Name,
main: option Service,
export: set Service,
import: set Service,
version: Number
}{ no import & export }
sig PDS {
components: set Component,
schedule: components -> Service ->? components,
requires: components -> components
}{ components.import in components.export }
fact SoundPDSs {
all P : PDS |
all c : components, s : Service | --1
let c' = c.schedule[s] {
(some c' iff s in c.import) && (some c' => s in c'.export)
}
all c : components | c.requieres = c.schedule[Service] --2
}
sig Name, Number, Service {}
fun AddComponent(P, P': PDS, c: Component) {
not c in P.components
P'.components = P.components + c
} run AddComponent for 3 but 2 PDS
fun RemoveComponent(P, P' : PDS, c: Component) {
c in P.components
P'.components = P.components - c
} run RemoveComponents for 3 but 2 PDS
fun HighestVersionPolicy(P: PDS) {
all s : Service, c : components, c' : c.schedule[s],
c'' : components - c' {
s in c''.export && c''.name = c'.name => c''.version in c'version.^(Ord[Number].prev)
}
} run HighestVersionPolicy for 3 but 1 PDS
fun AGuideSimulation(P, P', P'' : PDS, c1, c2 : Component) {
AddComponent(P, P', c1) RemoveComponent(P, P'', c2)
HighestVersionPolicy(P) HigjestVersionPolicy(P') HighestVersionPolicy(P'')
} run AGuideSimulation for 3
assert AddingIsFunctionalForPDSs {
all P, P', P'' : PDS, c : Component {
AddComponent(P, P', c) && AddComponent(P, P'', c) => P' = P''
}
}
check AddingIsFunctionalForPDSs for 3
I've to run it on the MIT's alloy analizer (http://alloy.mit.edu/alloy/), and when I execute this code I have the following error:
Syntax error at line 7 column 15:
There are 1 possible tokens that can appear here:
}
I 've searched in some reference books, forums... and I don't found something useful. If someone have been working with this tool and knows how to solve this problem I would be very grateful.
Thanks in advance.
Your primary problem is that the second edition of the Huth / Ryan book appears to have been published in 2004 and to use (unsurprisingly) the syntax accepted by the Alloy Analyzer at that time, which is (also unsurprisingly) not quite the same as the syntax accepted by current versions of the Alloy Analyzer.
So to run this in a current version of the Analyzer, you are going to have to understand (a) what they are trying to say (b) the then-current Alloy syntax in which they are trying to say it, and (c) the current Alloy syntax, well enough to translate the model into current syntax. (Or else find someone who has done this already.) Fortunately, Huth and Ryan explain the Alloy syntax they use in some detail, so it's not a difficult exercise for someone familiar with Alloy 4 to translate the model into the Alloy 4 syntax.
Good luck!
[Postscript] On the theory that the goal of your assignment is to let you get familiar with the Alloy Analyzer, and not to drop you in the deep end by requiring a translation from the old Alloy syntax to the new Alloy syntax, I append a rough translation of the Huth / Ryan PDS model into Alloy 4 syntax, with some interspersed comments. (I say 'rough' because I haven't spent a lot of time on it, and I may have missed some nuances, especially in the predicate HighestVersionPolicy, where the authors get a little tricky.) If the goal of your assignment is precisely to force you to fight your way through the thickets of syntax with only your native ingenuity to use as a machete, then I apologize for messing up that experience.
At the top of the module, the main change is to the way the ordering library module is invoked.
module PDS
open util/ordering[Number]
In Component, the keyword 'option' is replaced by the current keyword 'lone', and I've transcribed some of Huth and Ryan's comments, to try to help myself understand what is going on better.
sig Component {
name: Name, // name of the component
main: lone Service, // component may have a 'main' service
export: set Service, // services the component exports
import: set Service, // services the component imports
version: Number // version number of the component
}{
no import & export // imports and exports are disjoint
// sets of services
}
In the sig for PDS, the main change is again the change to cardinality syntax: ->? becomes -> lone.
// Package Dependency System
// components is the set of Component in this PDS
// schedule assigns to each component in the PDS
// and any of its import services
// a component in the PDS that provides that service
// (see SoundPDSs, below)
// requires expresses the component dependencies
// entailed by the schedule
sig PDS {
components: set Component,
schedule: components -> Service -> lone components,
// any component / Service pair maps to at most
// one component
requires: components -> components
}{
// for every component in the system,
// the services it imports are supplied (exported)
// by some (other) component in the system
components.import in components.export
}
In the fact SoundPDSs, the authors use a with P construct which I don't remember ever seeing in versions of Alloy I've used. So I took it out, and reformulated the expressions a bit for clarity, since the authors explain that clarity is their main motive for using the with P construct. It will be well worth your while to be sure you understand Alloy's box notation, and why P.schedule[c][s] is another way of writing c.(P.schedule)[s] or s.(c.(P.schedule)).
fact SoundPDSs {
all P : PDS | {
all c : P.components, s : Service |
let c' = P.schedule[c][s] {
(some c' iff s in c.import)
// c and s require c' only iff c imports s
&&
(some c' => s in c'.export)
// c and s require c' only if c' exports s
}
all c : P.components | P.requires[c]= P.schedule[c][Service]
// c requires precisely those components
// that schedule says c depends on for some service
}
}
sig Name, Number, Service {}
The big change from here on out is that Huth and Ryan use fun for their definitions of various properties, where Alloy 4 uses pred -- the keyword fun is still legal, but it means a function (an expression which when evaluated returns a value, not a Boolean) not a predicate.
pred AddComponent(P, P': PDS, c: Component) {
not c in P.components
P'.components = P.components + c
} run AddComponent for 3 but 2 PDS
pred RemoveComponent(P, P' : PDS, c: Component) {
c in P.components
P'.components = P.components - c
} run RemoveComponent for 3 but 2 PDS
In HighestVersionPolicy, I've again introduced box notation to try to make the expression clearer. Note that prev is not defined here -- it's one of the relations imported by the import instruction (open ...) at the top of the module, from the library module for ordering.
pred HighestVersionPolicy(P: PDS) {
all s : Service,
c : P.components,
c' : P.schedule[c][s],
c'' : P.components - c' {
s in c''.export && c''.name = c'.name
=>
c''.version in ^prev[c'.version]
}
} run HighestVersionPolicy for 3 but 1 PDS
pred AGuideSimulation(P, P', P'' : PDS, c1, c2 : Component) {
AddComponent[P, P', c1]
RemoveComponent[P, P'', c2]
HighestVersionPolicy[P]
HighestVersionPolicy[P']
HighestVersionPolicy[P'']
} run AGuideSimulation for 3
assert AddingIsFunctionalForPDSs {
all P, P', P'' : PDS, c : Component {
AddComponent[P, P', c] && AddComponent[P, P'', c]
=> P' = P''
}
}
check AddingIsFunctionalForPDSs for 3
The version of their model given by Huth and Ryan on the web doesn't include the StructurallyEqual predicate they describe in their text; I added it to help make sure my translation of the model worked.
pred StructurallyEqual(P, P' : PDS) {
P.components = P'.components
P.schedule = P'.schedule
P.requires = P'.requires
}
run StructurallyEqual for 2
And similarly, they don't include the fix to AddingIsStructurallyFunctional -- the intent is presumably for the student to do it dynamically, in Alloy.
assert AddingIsStructurallyFunctionalForPDSs {
all P, P', P'' : PDS, c : Component {
AddComponent[P, P', c] && AddComponent[P, P'', c]
=>
StructurallyEqual[P',P'']
}
}
check AddingIsStructurallyFunctionalForPDSs for 3
Related
Predicate not consistent
I have to realize an application which permits to reserve a seat in a store. There are no sintax error, but I don't understand why terminal reply me "predicate not consistent". Can u help me? This is my code: open util/integer sig Email{} sig CF{} sig Time{ hour: one Int, minute:one Int, second: one Int } abstract sig RegisteredUser{ email: one Email } sig User extends RegisteredUser{ cf: one CF } sig SM extends RegisteredUser{ cf: one CF, store: one Store } sig Location{} sig Date{} abstract sig Status {} //only one of this can be true one sig Waiting extends Status {} one sig Expired extends Status{} one sig Pending extends Status{} sig Ticket{ owner:one User, date: one Date, time: one Time, status : one Status, } sig Visit{ owner:one User, date: one Date, time: one Time, duration:one Time, status : one Status, products: some Product, category: some Category, } //tickets are assumed with a default duration time of 15 min and entrance one for time, so 4*8=32 visit per day sig TicketQueue { max_visit:one Int, ticket: some Ticket, manager: one SM } sig VisitQueue{ category: some Category, visit: some Visit, manager: one SM } sig Store{ max_simultaneous: one Int, location: one Location, visitqueue: one VisitQueue, ticketqueue: one TicketQueue, product_category: some Category } sig Category{ simultaneous_seats: one Int, } sig Product{ category: one Category } // Constraints // Registration data for the system are unique(Unique username and Fiscal Code) fact registrationDataUniqueness { no disjoint u1, u2: RegisteredUser | u1.email = u2.email no disjoint u1,u2: User | u1.cf = u2.cf no disjoint s1,s2: SM | s1.cf = s2.cf no disjoint s:SM, u:User | s.cf=u.cf } //Ticket and Visit can have only one of status' values defined before fact requestConsistency { all s: Status | (s = Waiting && s != Expired && s !=Pending ) || (s != Waiting && s = Expired && s != Pending) || (s !=Waiting && s != Expired && s = Pending) } //SM can manage only one Store fact StoreUniqueness{ no disjoint s1,s2: SM |s1.store=s2.store } // the same ticket or visit cannot be of two or more different user fact UserUniqueness{ no disjoint t1,t2: Ticket | t1.owner=t2.owner no disjoint v1,v2: Visit | v1.owner=v2.owner } //different products can not be of the same category fact CategoryUniqueness{ no disjoint p1,p2: Product | p1.category=p2.category } //different stores can't have the same ticket or visit queue fact QueueUniqueness{ no disjoint s1,s2: Store | s1.ticketqueue=s2.ticketqueue no disjoint s1,s2: Store | s1.visitqueue=s2.visitqueue } //different tickets cannot have the same time fact TimeUniqueness{ no disjoint t1,t2: Ticket | t1.time = t2.time } //for semplicity,in the visit/ticket queue, we consider "active" only visit/ticket with Waiting status fact StatusQueue{ all tq:TicketQueue | tq.ticket.status=Waiting all vq:VisitQueue | vq.visit.status=Waiting } //one ticket/visit can not belong to two or more different queue fact ReservationUniqueness{ no disjoint tq1,tq2:TicketQueue | tq1.ticket=tq2.ticket no disjoint vq1,vq2:VisitQueue | vq1.visit=vq2.visit } //SM is unique for a specific store, and its related ticket/visit queue fact SMUniqueness{ no disjoint s1,s2: Store | s1.ticketqueue.manager=s2.ticketqueue.manager and s1.visitqueue.manager=s2.visitqueue.manager and s1.ticketqueue.manager=s2.visitqueue.manager and s1.visitqueue.manager=s2.ticketqueue.manager } //different tickets/visits associated with the same user have different time fact UniqueTimeUser { all u: User, t1, t2: Ticket, v1,v2:Visit | ((u in t1.owner) and (u in t2.owner) and (u in v1.owner) and (u in v2.owner) and (t1 != t2) and (v1 !=v2)) implies (t1.time != t2.time) and (v1.time != v2.time) } //different ticket and visit associated with the same user have different time fact UniqueTimeUser2 { all u: User, t: Ticket, v:Visit | ((u in t.owner) and (u in v.owner) ) implies (v.time != t.time) } //Maximum number of visit with the same time for category fact MaxTime{ all v:Visit, c: Category |(( c in v.category)) implies #v.time< c.simultaneous_seats } //Considering meaningfull integer value fact PossibleValues{ all c: Category | c.simultaneous_seats>1 and c.simultaneous_seats<5 all s: Store | s.max_simultaneous >0 and s.max_simultaneous<50 all t: Ticket | t.time.hour>7 and t.time.hour<21 and ((t.time.minute=15) || (t.time.minute=30) || (t.time.minute=45)) and t.time.second=0 all v: Visit | v.time.hour>7 and v.time.hour<21 and ((v.time.minute=15) || (v.time.minute=30) || (v.time.minute=45)) and v.time.second=0 and v.duration.hour=0 and v.duration.minute>0 and v.duration.minute=<30 and v.duration.second=0 all tq: TicketQueue | tq.max_visit=32 } pred addTicket[ t :Ticket,ti,ti':Time, tq, tq':TicketQueue]{ //precondition ti' not in Ticket.time #tq.ticket< tq.max_visit //seats available //postconditions tq'.manager= tq.manager tq'.ticket= tq.ticket+t t in tq'.ticket #tq'.ticket< tq.max_visit all t': Ticket | t' in tq.ticket implies t' in tq'.ticket } pred show{ #User = 4 #Store = 2 #SM = 2 #Category = 3 #TicketQueue = 2 #VisitQueue= 2 #Category = 5 some v, v': Visit | v.time != v'.time #Ticket = 5 #Visit=5 } run show for 4 This is the complete response of Alloy terminal: Executing "Run show for 4" Solver=sat4j Bitwidth=4 MaxSeq=4 SkolemDepth=1 Symmetry=20 15098 vars. 840 primary vars. 17697 clauses. 28ms. No instance found. Predicate may be inconsistent. 1ms.
Have you run unsat core (using the MiniSAT with Unsat Core solver)? That might give you a hint. Another thought: I would simplify the model first and then only add features as you need them. I'm not sure that you really need to split the times into hours, minutes and seconds. That adds a lot of solver complexity, perhaps needlessly.
General observations: Some inconsistences in your show predicate: #Category = 3 #Category = 5 Your scope is definitely too small. You can't expect 5 Visit elements if you have a general scope of 4. I'd rewrite your show predicate and run command as follows: pred show{ some v, v': Visit | v.time != v'.time } run show for 10 but 7 Int, exactly 4 User, exactly 2 Store, exactly 2 SM, exactly 3 Category, exactly 2 TicketQueue, exactly 2 VisitQueue, exactly 5 Ticket, exactly 5 Visit Notice the 7 Int. It means that your model will contain int type atoms that represent all the integers you can express with a bitwidth of 7 (interval is [-64,63]). As Daniel wrote, i'd also advise to stay as abstract as possible when you model in Alloy and thus to prefer concepts over quantitative values.
I concur with the previous advice of simplifying and would add to use check statements to test as you go. I'm not an expert with Alloy, so I take it slow and test early and often. One thing that sticks out to me immediately is that your "show" predicate seems to be specifying multiplicities for some signatures that are greater than those allowed by the run statement ("for 4"). I've never specified multiplicity in a predicate that way, so I don't know how Alloy handles that. Offhand, those seem like contradictory constraints. Also, I figured this out the hard way, but Alloy counts instances (atoms) of extended signatures as instances (atoms) of the parent(s). So, be aware of that.
Modeling sequence of events in Alloy
The following model represents a sequence of actions given a certain pre-defined order. open util/ordering[Time] abstract sig Action {pre: set Action} one sig A, B, C, D extends Action {} fact{ pre = A -> B + D -> B + D -> C } sig Time { queue: Action -> lone State} abstract sig State {} one sig Acted, Ok, Nok extends State{} pred Queue [t, t': Time] { some a: Action-(t.queue).State | a.pre in (t.queue).Ok + (t.queue).Nok and t'.queue=t.queue+(a->Acted) } pred Reply [t, t': Time] { some a: (t.queue).Acted | some s: State-Acted | t'.queue=t.queue++(a->s) } fact { no first.queue last.queue=Action->Ok or last.queue = Action -> Nok all t:Time-last | Queue[t,t.next] or Reply[t,t.next] } run {last.queue=Action->Ok and some t:Time-last | t.queue = Action->Nok} for 9 With the run I would like to have a sequence where the last queueing action goes OK but some action failed before. However I don't get any instance. Can someone explain me what am I doing wrong? Regards, Andre.
The problem comes from the fact that once an action has, at a given time, a state which is Nok then it can't be changed back to another state in a future time(as suggested by the two quantifier in the Queue and Reply predicates). The analyzer thus can't find an instance where in the final Time, all the actions are in an Ok state and where at a given time an action is in a Nok State. (This is what you request in your run command) Hope it helps
Use topographical sort with alloy 4.2
I'm trying to use topological sort to find two different sequential schedules that follow their prereqs. When I execute the code no instances are found and I'm not sure why. Here's my code: open util/relation abstract sig Course { prereq: set Course, -- c->d in prereq if c is a prerequisite of d s1, s2: set Course -- two sequential course schedules } one sig cs1121, cs1122, cs1141, cs2311, cs2321, cs3000, cs3141, cs3311, cs3331, cs3411, cs3421, cs3425 extends Course { } fact { no prereq.cs1121 prereq.cs1122 = cs1121 prereq.cs1141 = cs1122 prereq.cs2311 = cs1121 prereq.cs2321 = cs1122 prereq.cs3000 = cs3141 prereq.cs3141 = cs2311 prereq.cs3141 = cs2321 prereq.cs3311 = cs2311 prereq.cs3331 = cs1141 prereq.cs3331 = cs2311 prereq.cs3331 = cs2321 prereq.cs3411 = cs1141 prereq.cs3411 = cs3421 prereq.cs3421 = cs1122 prereq.cs3425 = cs2311 prereq.cs3425 = cs2321 } -- is the given schedule a topological sort of the prereq relation? pred topoSort [schedule: Course->Course] { (all c: Course | lone c.schedule and lone schedule.c) -- no branching in the schedule and totalOrder[*schedule, Course] -- and it's a total order and prereq in ^schedule -- and it obeys the prerequisite graph } pred show { s1.irreflexive and s2.irreflexive -- no retaking courses! s1.topoSort and s2.topoSort -- both schedules are topological sorts of the prereq relation s1 != s2 -- the schedules are different } run show
Switch the solver (under the Options menu) to MiniSAT with Unsat Core, then look at the core. You'll see it highlights prereq.cs3141 = cs2311 prereq.cs3141 = cs2321 which contradicts your no branching rule.
Creating an object for each relation in Alloy
I have the following def. in Alloy: sig A {b : set B} sig B{} sig Q {s: A , t: B} I want to add a set of constraints such that for each relation b1:b there exists one and only one Q1:Q where Q1.s and Q1.t refers to the source and target of b1, respectively. For example, if I have an instance which contains A1 and B1 and b1 connects them (i.e., b1: A1->B1), then I also would like to have a Q1 where Q1.s=A1 and Q1.t=B1. Obviously number (cardinality) of Q is equal to number (cardinality) of b relation. I managed to write such a constraint as bellow: t in s.b all q1,q2:Q | q1.s=q2.s and q1.t=q2.t => q1=q2 all a1:A,b1:B | a1->b1 in b => some q:Q | q.s=a1 and q.t=b1 I am wondering if anyone has a bit more concise way to express my intentions in terms of an alloy fact. I am open to use Alloy util package if it makes life easier. Thanks
sig A { b : set B } sig B {} sig Q { ab : A -> B }{ one ab } fact { b = Q.ab and #Q = #b }
I would complete the #user1513683 answer by adding two relations s and t to make it the complete answer to the question: sig A { b : set B } sig B {} sig Q { ab : A -> B , s:A, t:B}{ one ab and t=ab[s]} fact { b = Q.ab and #Q = #b }
Using String Alloy
I have an Alloy module module WorkPlace sig String{} sig person{} sig Employee extends person{ name :String, boss: Employee,worker: set Employee} sig Employee1 extends person{ name :String, boss: Employee,worker: set Employee} fact Employee{ all e1:Employee, e2:Employee| (e1.name = e2 && e2.name = e1) =>e1 = e2} run{} when i triad to run this mode it give me this massage : "Syntax error at line 2 column 5: There are 3 possible tokens that can appear here: NAME seq this " I don't know what its mean? 2\ If I have 2 Alloy models ,each model has same element i.e mode1/name, model2/name. how can I create a fact or pred which can say mode1/name = model2/name? regards
As user1513683 already answered: "String" is a reserved word. Use "string" instead (or, better, "Name") You can open an existing module from another module, and then in that module you can use all sigs/relations present in any of the two modules. For example: module 1 (file m1.als): module m1 sig S1 {} module 2 (file m2.als): module m2 open m1 sig S2 {} run { #S1 = #S2 }