I am reading an article that uses Alloy to model some safety and security requirements for aircraft avionics. I am struggling to understand one of the "fact constraints" shown in the article.
Data flows into systems. Data is consumed by the systems. The model declares a set of Data, a set of System, and a consumedBy relation (Data is consumed by System):
sig Data {
consumedBy: some System
}
sig System {}
The model then declares a set of "criticality values." A relation maps criticality to data. Another relation maps criticality to system:
sig Criticality {
concernedData: one Data,
concernedSystem: one System
}
Next, the model expresses two facts. It's the second fact that I am struggling with.
The first fact says that each system consumes at least one datum:
all s: System | some consumedBy.s
The article has this comment about the second fact:
// for any system which consumes a given datum,
// the said datum and system should belong to
// a same unique criticality
I think the comment is saying this: If a system consumes a datum, then the datum and the system must have the same criticality. For example, if datum D1 is consumed by system S1 and datum D1 has criticality C1, then system S1 must also have criticality C1. Do you agree with that interpretation of the comment?
Now, here is how the fact is expressed in Alloy:
all d: Data | all s: System | one c: Criticality |
c.concernedData = d and c.concernedSystem = s
My understanding of how to read that fact is this:
The following constraint holds for exactly one c in Criticality:
For every d in Data and every s in System:
c.concernedData = d and c.concernedSystem = s
Is that a correct understanding of the fact? If so, I don't think the fact is expressing the same thing as the description in the comment.
So my questions are these:
One: the comment says this:
// for any system which consumes a given datum,
// the said datum and system should belong to
// a same unique criticality
Does the following Alloy fact express the same thing as the comment?
all d: Data | all s: System | one c: Criticality |
c.concernedData = d and c.concernedSystem = s
Two: if the comment and the Alloy fact are not the same, then what is the correct way to express the comment in Alloy?
Here is an Alloy model that compares the paper's version of the fact to what I believe captures what you want to express:
sig Data {consumedBy: some System}
sig Criticality {
concernedData: one Data,
concernedSystem: one System
}
sig System {}
// the paper's statement:
// for any system which consumes a given datum,
// there is one criticality that has that data and system
// as its concernedData and concernedSystem
pred Paper {
all d: Data | all s: d.consumedBy | one c: Criticality |
c.concernedData = d and c.concernedSystem = s
}
// your interpretation:
// If a system consumes a datum, then the datum and the system
// must have the same (single) criticality
pred You {
all d: Data | all s: d.consumedBy |
concernedData.d = concernedSystem.s and one concernedSystem.s
}
check {Paper implies You} for 2
If you execute this, you get the following counterexample that shows the difference between the two:
In short, the paper version says there is only one criticality shared by both; your version says that the datum and system are each associated with one criticality, and it's the same one (which is stronger).
I don't know which is right in this case.
The "one" quantifier, while having a very simple semantics ("one x: S | P" means P is true for one x in the set S) can be confusing because of how we're tempted to read quantifiers in natural language. There's a half page discussion of an example of this in the FAQ of Chapter 3 of Software Abstractions, on p.73.
Related
I am modeling a Google Docs-like inline commenting system in Alloy. Specifically, I'm modeling the UI interactions that the user can do. The constraints, in English, are that:
users can have any number of comments
users can have any number of comments composing at once
comments can be either composing or editing, not both
(eventually) users can expand one comment at a time to view it—text is truncated otherwise.
so far I have only modeled adding a new comment—or so I think! When I run the model below, I expect to see that Alloy cannot find any counterexamples, but it finds one where a comment is in both the composed and composing relations at a single time.
I think there may be something off in my mental model of how Alloy works in this case. I can't see how a comment would possibly be added to the composed relation here: I think init would set all the drafts to have empty relations there, and that the actions in Traces would preclude a comment ever being added to composed. BUT! I'm clearly wrong, since Alloy finds an example where composed is non-empty. Does anyone know what's actually happening here?
module inlineComments
open util/ordering [Time] as TimeOrdering
sig Time {}
sig Draft {
composing: set Comment -> Time,
composed: set Comment -> Time,
-- expanded: lone Comment -> Time,
}
sig Comment {}
-- What can we do with these?
pred newComment (t, t': Time, c: Comment, d: Draft) {
-- comment is not already known to us
c not in d.composing.t
c not in d.composed.t
-- start composing the comment
d.composing.t' = d.composing.t + c
}
pred init (t: Time) {
all d: Draft, c: Comment | c not in d.composing.t
all d: Draft, c: Comment | c not in d.composed.t
}
fact Traces {
init[TimeOrdering/first]
all t: Time - TimeOrdering/last |
let t' = TimeOrdering/next[t] |
some d: Draft, c: Comment |
newComment [t, t', c, d]
}
-- Is the world how we expect it to be?
assert validState {
-- comments cannot be composing and composed at the same time
all t: Time, d: Draft | d.composing.t & d.composed.t = none
}
check validState for 3 but 1 Draft
This is known as the "frame problem": you've specified that new comments can be put into composing, but not that nothing else happens! You have to make it explicit that the only way the system may change is via newComment. Here's one way you could do that:
fact Traces {
init[TimeOrdering/first]
all t: Time - TimeOrdering/last |
let t' = TimeOrdering/next[t] |
some d: Draft, c: Comment {
newComment [t, t', c, d]
d.composed.t = d.composed.t' -- d.composed doesn't change
}
}
Note this only works because you've exlicitly scoped to a maximum of 1 draft. If you test with two drafts, you also have to show that none of the drafts change in any way. If that will always be the case that there's only one Draft, you can write one sig Draft to enforce that.
Good afternoon,
I've been experiencing an issue with Alloy when dealing with unbounded universal quantifiers. As explained in Daniel Jackson's book 'Software Abstractions' (Section 5.3 'Unbounded Universal Quantifiers'), Alloy has a subtle limitation regarding universal quantifiers and assertion checking. Alloy produces spurious counterexamples in some cases, such as the next one to check that sets are closed under union (shown in the aforementioned book):
sig Set {
elements: set Element
}
sig Element {}
assert Closed {
all s0, s1: Set | some s2: Set |
s2.elements = s0.elements + s1.elements
}
check Closed for 3
Producing a counterexample such as:
Set = {(S0),(S1)}
Element = {(E0),(E1)}
s0 = {(S0)}
s1 = {(S1)}
elements = {(S0,E0), (S1,E1)}
where the analyser didn't populate Set with enough values (a missing Set atom, S2, containing the union of S0 and S1).
Two solutions to this general problem are suggested then in the book:
1) Declaring a generator axiom to force Alloy to generate all possible instances.
For example:
fact SetGenerator{
some s: Set | no s.elements
all s: Set, e: Element |
some s': Set | s'.elements = s.elements + e
}
This solution, however, produces a scope explosion and may also lead to inconsistencies.
2) Omitting the generator axiom and using the bounded-universal form for constraints. That is, quantified variable's bounding expression doesn't mention the names of generated signatures. However, not every assertion can be expressed in such a form.
My question is: is there any specific rule to choose any of these solutions? It isn't clear to me from the book.
Thanks.
No, there's no specific rule (or at least none that I've come up with). In practice, this doesn't arise very often, so I would deal with each case as it comes up. Do you have a particular example in mind?
Also, bear in mind that sometimes you can formulate your problem with a higher order quantifier (ie a quantifier over a set or relation) and in that case you can use Alloy*, an extension of Alloy that supports higher order analysis.
I've got an Alloy model which contains the following :
abstract sig person{}
one sig john,Steve extends person {Gender: man}
sig man{}
fact {
all name: person, Gender: man |
name.Gender = name.Gender => person =person}
How can I make equality between two signatures?
It's not clear from your question what you want to do, and from your sample Alloy code it looks as if you may be suffering from some confusions.
First, the model you show uses the name Gender in two different ways, which is not illegal in itself but seems to suggest some confusion. (It certainly confuses the willies out of this reader.)
In the declaration for the two singleton signatures john and Steve, Gender denotes two binary relations, one holding between the signature john and the signature man, the other holding between Steve and man. To say the same thing in symbolic form, Gender denotes (a) some subset of john -> man, and (b) some subset of Steve -> man.
In the anonymous fact, however, Gender denotes a variable of type man.
Your model will be easier to understand if you find a way to rename one or the other of these. Since variable names in a quantified expression are arbitrary, your fact will mean the same thing if you reformulate it as
fact { all P : person, M : man | P.M = P.M => person = person }
If that's not what you meant to say, then you may have meant to say something like
fact { all P : person, M : man |
P.Gender = P.Gender => person = person
}
Renaming the variable forces you to choose one meaning or the other. This is a good thing. (It is an unfortunate fact that neither formulation is actually satisfactory in Alloy. But let's deal with one problem at a time; getting rid of the double use of the name Gender is the first step.)
A second issue is that whichever formulation of the fact you meant, it almost certainly doesn't mean what you wanted it to mean. Ignoring the specifics of the model for a moment, your fact takes the form
fact { all V1 : sig1, V2 : sig2 |
Expression = Expression => sig1 = sig1
}
where Expression is either V1.V2 or V1.Relation, for some Relation defined in the model. There are several things wrong here:
V1.V2 is meaningless where V1 and V2 are both names of signatures or variables ranging over given signatures: the dot operator is meaningful only if one of its arguments is the name of a relation.
If any expression E is meaningful at all, then a Boolean expression of the form E = E (for example, person.Gender = person.Gender) is true regardless of what E means. Anything denoted by E is naturally going to be equal to itself. So the conditional might as well be written
1 = 1 => person = person
For the same reason, person = person will always be true, regardless of the model: for any model instance the set of persons in the instance will be identical to the set of persons in the instance. So the conditional will always be true, and the fact won't actually impose any constraint on instances of the model.
It's not clear how best to help you move forward. Perhaps one way to start would be to ask yourself which of the following statements you are trying to capture in your model.
There is a set of persons.
Some persons are males (have gender = 'man'). Others are not males.
John is a male individual.
Steve is a male individual.
John and Steve are distinct individuals.
If x and y are individuals with the same gender, then x and y are the same individual. I.e. no two individuals have the same gender.
Note that these statements cannot all be true at the same time. (If that's not obvious, you might do worse than try to figure out why. Alloy can be helpful in that effort.)
Good luck.
Consider the following simple variant of the Address Book example
sig Name, Addr {}
sig Book { addr : Name -> Addr } // no lone on Addr
pred show(b:Book) { some n : Name | #addr[b,n] > 1 }
run show for exactly 2 Book, exactly 2 Addr, exactly 2 Name
In some model instances, I can get the following results in the evaluator
all b:Book | show[b]
--> yields false
some b:Book | show[b]
--> yields true
show[Book]
--> yields true
If show was a relation, then one might expect to get an answer like: { true, false }. Given that it is a predicate, a single Boolean value is returned. I would have expected show[Book] to be a shorthand for the universally quantified expression above it. Instead, it seems to be using existential quantification to fold the results. Anyone know what might be the rational for this, or have another explanation for the meaning of show[Book]?
(I'm not sure I have the correct words for this, so bear with me if this seems fuzzy.)
Bear in mind that all expressions in Alloy that denote individuals denote sets of individuals, and that there is no distinction available in the language between 'individual X' and 'the singleton set whose member is the individual X'. ([Later addendum:] In the terms more usually used: the general rule in Alloy's logic is that all values are relations. Binary relations are sets of pairs, n-ary relations sets of n-tuples, sets are unary relations, and scalars are singleton sets. See the discussion in sec. 3.2.2 of Software Abstractions, or the slide "Everything's a relation" in the Alloy Analyzer 4 tutorial by Greg Dennis and Rob Seater.)
Given the declaration you give of the 'show' predicate, it's easy to expect that the argument of 'show' should be a single Book -- or more correctly, a singleton set of Book --, and then to expect further that if the argument is not actually a singleton set (as in the expression show[Book] here) then the system will coerce it to being a singleton set, or interpret it with some sort of implicit existential or universal quantification. But in the declaration pred show(b:Book) ..., the expression b:Book just names an object b which will be a set of objects in the signature Book. (To require that b be a singleton set, write pred show(one b: Book) ....) The expression which constitutes the body of show is evaluated for b = Book just as readily as for b = Book$0.
The appearance of existential quantification is a consequence of the way the dot operator at the heart of the expression addr[b,n] (or equivalently n.(b.addr) is defined. Actually, if you experiment you'll find that show[Book] is true whenever there is any name for which the set of all books contains a mapping to two different addresses, even in cases where an existential interpretation would fail. Try adding this to your model, for example:
pred hmmmm { show[Book] and no b: Book | show[b] }
run hmmmm for exactly 2 Book, exactly 2 Addr, exactly 2 Name
This is homework and I'm having a lot of trouble with it. I am using Alloy to model a library. Here are the definitions of the objects:
sig Library {
patrons : set Person,
on_shelves : set Book,
}
sig Book {
authors : set Person,
loaned_to : set Person,
}
sig Person{}
Then we need to have to have a fact that states, every book is either on the shelf, or taken out by a patron. However, they cannot be in both places.
// Every book must either be loaned to a patron or
// on the shelves.
fact AllBooksLoanedOrOnShelves {}
I have tried this...
fact AllBooksLoanedOrOnShelves {
some b : Book {
one b.loaned_to =>
no (b & Library.on_shelves)
else
b in Library.on_shelves
}
}
But it's not working... the books always are on the shelves. want to say, "For every book, if it is not being loaned, it is on the shelf. Otherwise, it's out."
Corrections, examples, and hints are greatly appreciated.
If every book must be either on loan to someone or on the shelves, then (a) no book will be both on loan and on the shelves (assuming you mean that "or" as exclusive), so the intersection of the onloan set and the onshelf set will be empty, and (b) the set of books will be equal to the union of the onloan and onshelf sets.
The set of books on loan at any time is the domain of the loaned_to relation. The set of books on the shelf in a given library L is the value of L.onshelves; the set of books on the shelves in all known libraries is Library.onshelves.
So you might say
fact in_or_out_not_both {
no Library.onshelves & loaned_to.Person
}
fact all_books_in_or_out {
Book = Library.onshelves + loaned_to.Person
}
Or you might need to say slightly different things, depending on just what you mean. Note that these constraints don't say that a book on loan must be on loan to a single borrower.
Your fact is wrong. You want to say something for all books (not "some"). And that something is basically an XOR.
Here's one that works:
fact AllBooksLoanedOrOnShelves{
all b : Book|
(b in Library.on_shelves and no p:Person | p in b.loaned_to)
or
(not b in Library.on_shelves and one p:Person | p in b.loaned_to)
}
Ok correct me if I'm wrong, but I believe this is the fact you're after:
fact {
disj[Library.on_shelves, Person.~loaned_to]
}
And a little explanation. Library.on_shelves is the set of books on the right side of the on_shelves relation, i.e. all the books that are on the shelves. ~loaned_to is the reverse relation of type Person -> Book and Person.~loaned_to is the set of books loaned to any person.
The disj predicate declares that the two sets have no common atoms (disjoint sets).
I am not very familiar with Alloy.
But I think this or something similar would work.
Every book is either on the shelves or is loaned to a a patron.
fact AllBooksLoanedOrOnShelves {
all b: Book | b in Library.on_shelves || b.loaned_to in Library.patrons
}
This question is 6 years old now, but I'm learning Alloy, and I wanted to offer my take on a solution.
fact AllBooksLoanedOrOnShelves {
no (Library.on_shelves & loaned_to.Person)
}
This can be read as "the intersection of the set of books that are on shelves and the set of books that are loaned out, is empty".