The introductory example from Software Abstractions:
sig Name, Addr{}
sig Book {
addr: Name -> lone Addr
}
pred show(b:Book) {
#b.addr > 1
#Name.(b.addr) > 1
}
Would #Addr > 1 be semantically equivalent with #Name.(b.addr) > 1?
It confuses me Name is a general set reference while b refers to particular books and they appear in an expression together. Furthermore, what does the bracketed (b.addr) expression exactly refer to?
b.addr is the mapping for address book b, from names to addresses. So Name.(b.addr) is the image of the set of all names under that mapping: it's the set of addresses in b. Thus #Name.(b.addr) > 1 says that address book b contains more than one address. In contrast, #Addr > 1 says that there exists more than one address -- which would be satisfied by having addresses that don't belong to any book at all.
Related
I tried my first steps in modelling with Alloy and have come across a problem I cannot get my head around. I have the following spec:
module tour/AddressBook1
sig Name, Addr{}
sig Book {
addr: Name->lone Addr
}
// operation: adds a (name, address) to the Book b, resulting in b'
pred add (b, b' : Book, n:Name, a:Addr) {
b'.addr = b.addr + n->a
}
run add for 3 but 2 Book
So far nothing special. It is literally the example of the book 'Software abstraction' by Daniel Jackson.
It essentially models books, that have (name,address)-pairs associated with it. The add-predicate is supposed to grab a Book-instance b and create another Book-instance b' from it by adding (a potentially already existing) (name,address)-pair to it.
The first few examples found are easy and convincing but clicking through with the Next-button I end up with the following example (full view above, equivalent projection over books below)
I see two books, the starting book Book0 with two pairs (Name0, Addr2) and (Name1, Addr1). From the annotions we can also see that the add operation is going to add the new duo (Name1, Addr2). When I now look at the result book Book1 I have
{(Name0, Addr0),(Name1, Addr2)} instead of
{(Name0, Addr2),(Name1, Addr1),(Name1, Addr2)}
Why is this considered a legal instance?
(Alloy Analyzer 4.2, Build date 2012-09-25 15:54 EDT)
There are two confusing things here:
Book0 does not take part in the operation. Instead Book1 has the role of both b0 and b1.
Adding n->a to a book does not assert that this is a new address. In the instance, Book1 has this address before and after add.
This is because the operation
b'.addr = b.addr + n->a
uses set union. Broken down to a simpler example:
{1, 2} = {1} + {2}
is true. But
{1, 2} = {1, 2} + {2}
is also true. So in the original example, there is nothing that excludes n->a from already being a part of b.addr. And the Alloy Analyzer simply generates all instances that are consistent with the given constraints.
You can improve this example by adding an assertion in add:
b.addr[n] != a
Below is an Alloy model of an email address book. Each name in an address book maps to either a name or an address.
I want each name to eventually map to an address, e.g., Family -> Tom -> Tom_addr. I created a fact to implement this. To check that my fact is correct, I created an assert.
I puzzled for a long time on what to place in the assert. Oddly, the expression that I placed in the "fact" section seems like the right expression to place in assert. But then the assert would be just repeating the fact, which is not helpful. So I created something else to place in assert.
I'm not entirely convinced that what I placed in the "assert" section actually checks that every name eventually maps to an address.
Questions:
In the "fact" section, have I correctly expressed the constraint that each name eventually maps to an address?
In the "assert" section, is there a better way to assert that every name eventually maps to an address?
sig Addr {}
sig Name {
address: some Addr + Name
}
fact {
// No cycles.
no n: Name | n in n.^address
// All names eventually map to an Addr.
// Here's how I implemented the constraint:
// There is no name n that is mapped-to (i.e., m -> n),
// which does not map-to something (i.e., n -> p).
no n: Name {
n in univ.address
n not in address.univ
}
}
assert All_names_eventually_map_to_an_Addr {
all n: Name | some n.^address & Addr
}
check All_names_eventually_map_to_an_Addr
Assertion that repeats the fact is something that you probably don't want to have as it is indeed useful. (Think of checking/proving a property under an assumption -- an implication of the form (Q and P) implies P clearly holds for any P and Q.)
Having that said, the property:
every name eventually maps to an address
should be correctly expressed, as given in your code snippet. (The closure can map only to one element of Address, since the relation address is not defined for instances of Address.)
Below I create three sets: Name, Address, and Host. The addr field maps Name to Address. The host field maps Address to Host.
sig Name {
addr: Address
}
sig Address {
host: Host
}
sig Host {}
Here I ask the Alloy Analyzer to create an instance for the join of two relations: addr and host.
run {one addr.host} for 1
This is the graphic that is generated:
Next, I ask the Alloy Analyzer to create an instance for the join of three relations: addr, a ternary relation of identical atoms in each tuple, and host.
run {one addr.{a, b, c: univ | a = b and b = c}.host} for 1
Surprisingly, the graphic generated is identical to the one shown above. Why is this?
The visualizer shows an instance by giving values for each of the named relations and sets. Your second example still has only two named relations in it. If you want to see the value of a relation that is given just as an expression, you'll need to name it, eg like this:
run {some r: univ -> univ -> univ |
r = {a, b, c: univ | a = b and b = c} and
one addr.r.host} for 1
Here are the signatures
one sig Library {
books: set Book,
patrons: set Patron,
circulation: Patron lone -> some Book
}
sig Book { }
sig Patron {
curbooks: set Book
}
Question ->What I want to do is : write a fact that the books currently with a patron are accounted in the library's circulation relation
fact curPatronBooksConsistent {
lone l : Library | all b : l.patrons.curbooks | b in l.circulation
}
Now I understand the nature of the error: in can be used only between 2 expressions of the same arity.
Left type = this/Book
Right type = this/Patron->this/Book
However I do not know how to nor can I find any examples of returning only a "set" of books that are associated with the library.circulation. I realize this is not a set but a relationship so how do I express that in Alloy?
all the books belonging to the patrons e.g. all p.curbooks are mapped in the l.circulation?
Thank you all in advance.
Welcome to Stack Overflow. You say
However I do not know how to nor can I find any examples of returning only a "set" of books that are associated with the library.circulation.
Look again at discussions of the dot (join) operator; you should find plenty of examples. The relation circulation is a ternary relation Library -> Patron -> Book. Your expression l.circulation performs a join and reduces the arity, producing a relation Patron -> Book.
How do you get a relation of the form Patron -> Book down to a set of books?
One obvious way is to join it to a set of Patrons with an expression like Patron.(l.circulation). That's probably not what you want -- you probably want to say that every book shown as in some patron's curbooks is checked out not just to some patron but to that particular patron.
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