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.
Related
How can I write out a literal for a sig in Alloy? Consider the example below.
sig Foo { a: Int }
fact { #Foo = 1 }
If I execute this, I get
| this/Foo | a |
|----------|---|
| Foo⁰ | 7 |
In the evaluator, I know I can get a reference to the Foo instance with Foo$0 but how can I write a literal that represents the same value?
I've tried {a: 7}, but this is not equal to Foo$0. This is intentionally a trivial example, but I'm debugging a more complex model and I need to be able to write out literals of sigs with multiple fields.
Ah, this is one of the well hidden secrets! :-) Clearly in your model you cannot refer to atoms since the model is defining all possible values of those atoms. However, quite often you need your hands on some atom to reason about it. That is, you want to be able to name some objects.
The best way to get 'constants' is to create a predicate you call from a run clause. In this predicate, you define names for atoms you want to discuss. You only have to make sure this predicate is true.
pred collision[ car1, car2 : Car, road : Road ] {
// here you can reason about car1 and car2
}
run collision for 10
Another way is to create a quantification whenever you need to have some named objects:
run {
some car1, car2 : Car, road : Road {
// here you can reason about car1 and car2 and road
}
} for 10
There was a recent discussion to add these kinds of instances to the language so that Kodkod could take advantage of them. (It would allow faster solving and it is extremely useful for test cases of your model.) However, during a discussion this solution I presented came forward and it does not require any new syntax.
try to put a limitation for 'Integer' in the 'run' command. I mean :
sig Foo {a : Int}
fact{ #Foo = 1}
pred show {}
run show for 1 Foo, 2 Int
In the dining philosophers problem we have a table with Philosophers and Forks.
sig P {}
sig F {}
For this problem I want the following relation that represents the table:
P1 -> F1
F1 -> P2
P2 -> F2
F2 -> P3
P3 -> F3
F3 -> P1
I.e. each P would point to an F and each F to a P, and this would form a circle. I would like to call a function to get this relation:
fun table : (P+F) one -> one (P+F) { ... }
I've been trying hard to make this work but it feels like I am missing something fundamental that also is relevant for other problems I am having. Somehow I miss a 'constructor'.
Any pointers?
Additional
#Hovercouch gave an working solution with a helper sig. However, this required a non-natural extension to the P and F and introduced a new sig. This can also be solved by:
sig P, F {}
one sig Table {
setting : (P+F) one -> one (P+F)
} {
# P = # F
all p : P, f : F | P in p.^setting and F in f.^setting
}
run {} for 6
Which addresses the non-natural inheritance concerns.
However, it still seems very global and a lot of work for an imho very simple problem. Still keeping the question open to see if there are other solutions.
If you're willing to add a helper object, we can do this by making an abstract sig Thing and then making both P and F instances of Thing:
abstract sig Thing {
next: Thing
} {
Thing = this.^#next
}
sig F extends Thing {} {
next in P
}
sig P extends Thing {} {
next in F
}
fact SameNumberOfThings {
#P = #F
}
run {} for 6
There may be a design tradeoff involved here, between expressive power and tractability.
There is certainly an issue of what counts as clean or intuitive; you say that the 'next'-ness of P and F is "an aspect of the table setting" and not "an aspect of P or F". I think I understand your thinking, but I don't think you are likely to have any more success defining a principled way to distinguish between "aspects" of P and F and relations in whose domain or range they appear, any more than any of the philosophers who have tried, over the last couple thousand years, to distinguish reliably between essence and accidence.
And if we accept that the distinction is unreliable, but we nevertheless find it useful, then the question becomes "who made the rule that a relation defined as part of a signature must relate to an (intrinsic) aspect of the individuals involved, and not to an extrinsic relation which is not an aspect of the individuals?" The answer is: you did, not [the creators of] Alloy. If one insists too strongly on one's intuitions about the constructs one wants to use to express something, there is a certain risk of insisting not just that the thing should be expressible but that we should be able to express it using a particular construct. That kind of insistence can teach us a lot about a notation, but sometimes it's easier to accept that the designers of the notation also had intuitions.
This general topic is discussed in Daniel Jackson's Software Abstractions under the questions Does Alloy allow freestanding declarations? (in discussion following section 3.5.3 on higher-order quantification) and Must all relations be declared as fields? (in discussion following section 4.2.2 on basic field declarations). The nut of the discussion is "If you want to declare some relations that don't belong naturally to any existing signatures, you can simply declare them as fields of a singleton signature." Mutatis mutandis, the example given looks a lot the Table sig in your addendum.
TL;DR yes, you may find it a bit cumbersome, but the singleton sig to contain a relation you don't want to define on its first member really is as close to an established idiom as there is, for this sort of thing.
I am trying to learn about how ordering works in Alloy. I have a time signature which I have used to instantiate the ordering module. I want the predicate addPage to add a page to the book at time t' where t' = t.next. (Basically add a page to the Book on the next time) However it is not working as expected and instead Time2 has lesser number of pages than Time1. Can someone explain to me why this is happening? Thanks.
open util/ordering[Page] as P0
open util/ordering[Time] as T0
sig Page {}
sig Time {}
sig Book
{
pages: Page -> Time
}
pred addPage(b:Book, p:Page, t: Time)
{
t != T0/last implies
{
let t' = t.next |
b.pages.t' = b.pages.t + p
}
}
run addPage {} for 3
The problem are the extra curly braces in the run statement.
I think Alloy executes an empty predicate in this case.
Try:
run addPage for 3
instead. You will see a visualization where the selected instances for b, t and p are marked.
You're trying to change state which can only be simulated in constraint logic.
Please notice that the expression in addPage is basically ineffective /run your model without it/ and that there's only one Book atom in the solution.
Here's a model you can start with and gradually refine.
open util/ordering[Time]
sig Page {}
sig Time {}
sig Book {
pages : Page lone -> Time // each Time atom is mapped to at most one Page atom
}
pred addPage(b0, b1 : Book, pg : Page, t0, t1 : Time) {
one pg and // one page at a time (it's likely redundant)
not pg in b0.pages.Time and // it's a 'new' page
b0.pages + pg->t1 = b1.pages and // 'new state' of b0
t1 = t0.next // pg is 'added' with the next time stamp
}
run addPage for 3 but 2 Book
I used the optional 'and' operators, placed t1 = t0.next at the end of the constraint, positioned b1.pages /representing the 'new state'/ on the right and used quotes in the comments to emphasize that there's no real state change and sequence of operation in the sense imperative programming works.
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.
/*
sig a {
}
sig b {
}
*/
pred rel_test(r : univ -> univ) {
# r = 1
}
run {
some r : univ -> univ {
rel_test [r]
}
} for 2
Running this small test, $r contains one element in every generated instance. When sig a and sig b are uncommented, however, the first instance is this:
In my explanation, $r has 9 tuples here and still, the predicate which asks for a one tuple relation succeeds. Where am I wrong?
An auxiliary question: are these two declarations equivalent?
pred rel_test(r : univ -> univ)
pred rel_test(r : set univ -> univ)
The problem is that with the Forbid Overflow option set to No the integer semantics in Alloy is wrap around, and with the default scope of 3 (bits), then indeed 9=1, as you can confirm in the evaluator.
With the signatures a and b commented the biggest relation that can be generated with scope 2 has 4 tuples (since the max size of univ is 2), so the problem does not occur.
It also does not occur in the latest build because I believe it comes with the Forbid Overflow option set to Yes by default, and with that option the semantics of integers rules out instances where overflows occur, precisely the case when you compute the size of the relation with 9 tuples. More details about this alternative integer semantics can be found in the paper "Preventing arithmetic overflows in Alloy" by Aleksandar Milicevic and Daniel Jackson.
On the main question: what version of Alloy are you using? I'm unable to replicate the behavior you describe (using Alloy 4.2 of 22 Feb 2015 on OS X 10.6.8).
On the auxiliary question: it appears so. (The language reference is not quite as explicit as one might wish, but it begins one part of its discussion of multiplicities with "If the right-hand expression denotes a unary relation ..." and (in what I take to be the context so defined) "the default multiplicity is one"; the conditional would make no sense if the default multiplicity were always one.
On the other hand, the same interpretive logic would lead to the conclusion that the language reference believes that unary multiplicity keywords are only allowed before expressions denoting unary relations (which would appear to make r: set univ -> univ ungrammatical). But Alloy accepts the expression and parses it as set (univ -> univ). (The alternative parse, (set univ) -> univ, would be very hard to assign a meaning to.)