higher-order quantification that cannot be skolemized - alloy

I'm learning Alloy and experimenting with creating predicates for relations being injective and surjective. I tried this in Alloy using the following model:
sig A {}
sig B {}
pred injective(r: A -> B) {
all disj a, a': r.B | no (a.r & a'.r)
}
pred inj {
no r: A -> B | injective[r]
}
run inj for 8
However, I get this error on no r:
Analysis cannot be performed since it requires higher-order
quantification that could not be skolemized.
I've read the portions of Software Abstractions about skolemization and some other SO questions but it's not clear to me what the issue is here. Can I fix this by rephrasing or have I hit a fundamental limitation?
EDIT:
After some experimenting the issue seems to be associated with the negation. Asking for some r: A -> B | injective[r] immediately produces an injective example. This makes conceptual sense as a generally harder problem, but they seem like more or less isomorphic questions in a small scope.
EDIT2:
I've found using the following model that Alloy gives me examples which also satisfy the commented predicate that gives me the error.
sig A {}
sig B {}
pred injective(r: A -> B) {
all disj a, a': r.B | no (a.r & a'.r)
}
pred surjective(r: A -> B) {
B = A.r
}
pred function(f: A -> B) {
all a: f.B | one a.f
}
pred inj {
some s: A -> B | function[s] && surjective[s]
// no r: A -> B | function[r] && injective[r]
}
run inj for 8

Think of it like this: every Alloy analysis involves model finding, in which the solution is a model (called an instance in Alloy) that maps names to relations. To show that no model exists at all for a formula, you can run it and if Alloy finds no solution, then there is no model (in that scope). So if you run
some s: A -> B | function[s] && surjective[s]
and you get no solution, you know there is no surjective function in that scope.
But if you ask Alloy to find a model such that no relation exists with respect to that model, that's a very different question, and requires a higher order analysis, because the solver can't just find a solution: it needs to show that there is no extension of that solution satisfying the negated constraint. Your initial example is like that.
So, yes, it's a fundamental limitation in the sense that higher order logic is fundamentally less tractable. But whether that's a limitation for you in practice is another matter. What analysis do you actually need?
One compelling use of higher order formulas is synthesis. A typical synthesis problem takes the form "find me a program structure P such that there is no counterexample to the specification S". This requires higher order analysis, and is the kind of problem that Alloy* was designed to solve.
But there's generally no reason to use Alloy* for standard verification/simulation problems.

Related

How do relation multiplicities work?

I'm using this simple model and the evaluator to study relation multiplicities. The evaluator dialogue demonstrates a situation that I find puzzling.
sig A {}
sig B {}
pred show {}
run show
Evaluator dialogue:
univ
{A$0, A$1, B$0, B$1, B$2}
B->A
{B$0->A$0, B$0->A$1, B$1->A$0, B$1->A$1, B$2->A$0, B$2->A$1}
B lone -> A
{B$0->A$0, B$0->A$1, B$1->A$0, B$1->A$1, B$2->A$0, B$2->A$1}
// Although the two relations seem to be identical,
B->A in B->A
true
// but
B->A in B lone -> A
false
What makes the two products different in answering 'B->A in B->A' and 'B->A in B lone -> A'?

Simple Alloy constraint doesn't work as expected

The following model produces instances with exactly 2 address relations when the number of Books is limited to 1, however, if more Books are allowed it will create instances with 0-3 address relations. My misunderstanding of how Alloy works?
sig Name{}
sig Addr{}
sig Book { addr: Name -> lone Addr }
pred show(b:Book) { #b.addr = 2 }
// nr. of address relations in every Book should be 2
run show for 3 but 2 Book
// works as expected with 1 Book
Each instance of show should include one Book, labeled as being the b of show, which has two address pairs. But show does not say that every book must have two address pairs, only that at least one must have two address pairs.
[Postscript]
When you ask Alloy to show you an instance of a predicate, for example by the command run show, then Alloy should show you an instance: that is (quoting section 5.2.1 of Software abstractions, which you already have open) "an assignment of values to the variables of the constraint for which the constraint evaluates to true." In any given universe, there may be many other possible assignments of values to the variables for which the constraint evaluates to false; the existence of such possible non-suitable assignments is unavoidable in any universe with more than one atom.
Informally, we can think of a run command for a predicate P with arguments X, Y, Z as requesting that Alloy show us universes which satisfy the expression
some X, Y, Z : univ | P[X, Y, Z]
The run command does not amount to the expression
all X, Y, Z : univ | P[X, Y, Z]
If you want to see only universes in which every book has two pairs in its addr relation, then say so:
pred all_books_have_2 { all b : Book | #b.addr = 2 }
I think it's better that run have implicit existential quantification, rather than implicit universal quantification. One way to see why is to imagine a model that defines trees, such as:
sig Node { parent : lone Node }
fact parent_acyclic { no n : Node | n in n.^parent }
Suppose we get tired of seeing universes in which every tree is trivial and contains a single node. I'd like to be able to define a predicate that guarantees at least one tree with depth greater than 1, by writing
pred nontrivial[n : Node]{ some n.parent }
Given the constraint that trees be acyclic, there can never be a non-empty universe in which the predicate nontrivial holds for all nodes. So if run and pred had the semantics you have been supposing, we could not use nontrivial to find universes containing non-trivial trees.
I hope this helps.

Alloy - set difference leading to vars and clauses, set union does not

I'm curious as to when evaluation sets in, apparently certain operators are rather transformed into clauses than evaluated:
abstract sig Element {}
one sig A,B,C extend Element {}
one sig Test {
test: set Element
}
pred Test1 { Test.test = A+B }
pred Test2 { Test.test = Element-C }
and run it for Test1 and Test2 respectively will give different number of vars/clauses, specifically:
Test1: 0 vars, 0 primary vars, 0 clauses
Test2: 5 vars, 3 primary vars, 4 clauses
So although Element is abstract and all its members and their cardinalities are known, the difference seems not to be computed in advance, while the sum is. I don't want to make any assumptions, so I'm interested in why that is. Is the + operator special?
To give some context, I tried to limit the domain of a relation and found, that using only + seems to be more efficient, even when the sets are completely known in advance.
To give some context, I tried to limit the domain of a relation and found, that using only + seems to be more efficient, even when the sets are completely known in advance.
That is pretty much the right conclusion. The reason is the fact that the Alloy Analyzer tries to infer relation bounds from certain Alloy idioms. It uses a conservative approximation that is always sound for set union and product, but not for set difference. That's why for Test1 in the example above the Alloy Analyzer infers a fixed bound for the test relation (this/Test.test: [[[A$0], [B$0]]]) so no solver needs to be invoked; for Test2, the bound for the test relation cannot be shrunk so is set to be the most permissive (this/Test.test: [[], [[A$0], [B$0], [C$0]]]), thus a solver needs to be invoked to find a solution satisfying the constraints given the bounds.

Solving maximizing problems in Alloy (or other optimization problems)

I've bought and read the Software Abstractions book (great book actually) a couple of months if not 1.5 years ago. I've read online tutorials and slides on Alloy, etc. Of course, I've also done exercises and a few models of my own. I've even preached for Alloy in some confs. Congrats for Alloy btw!
Now, I am wondering if one can model and solve maximizing problems over integers in Alloy. I don't see how it could be done but I thought asking real experts could give me a more definitive answer.
For instance, say you have a model similar to this:
open util/ordering[State] as states
sig State {
i, j, k: Int
}{
i >= 0
j >= 0
k >= 0
}
pred subi (s, s': State) {
s'.i = minus[s.i, 2]
s'.j = s.j
s'.k = s.k
}
pred subj (s, s': State) {
s'.i = s.i
s'.j = minus[s.j, 1]
s'.k = s.k
}
pred subk (s, s': State) {
s'.i = s.i
s'.j = s.j
s'.k = minus[s.k, 3]
}
pred init (s: State) {
// one example
s.i = 10
s.j = 8
s.k = 17
}
fact traces {
init[states/first]
all s: State - states/last | let s' = states/next[s] |
subi[s, s'] or subj[s, s'] or subk[s, s']
let s = states/last | (s.i > 0 => (s.j = 0 and s.k = 0)) and
(s.j > 0 => (s.i = 0 and s.k = 0)) and
(s.k > 0 => (s.i = 0 and s.j = 0))
}
run {} for 14 State, 6 Int
I could have used Naturals but let's forget it. What if I want the trace which leads to the maximal i, j or k in the last state? Can I constrain it?
Some intuition is telling me I could do it by trial and error, i.e., find one solution and then manually add a constraint in the model for the variable to be stricly greater than the one value I just found, until it is unsatisfiable. But can it be done more elegantly and efficiently?
Thanks!
Fred
EDIT: I realize that for this particular problem, the maximum is easy to find, of course. Keep the maximal value in the initial state as-is and only decrease the other two and you're good. But my point was to illustrate one simple problem to optimize so that it can be applied to harder problems.
Your intuition is right: trial and error is certainly a possible approach, and I use it regularly in similar situations (e.g. to find minimal sets of axioms that entail the properties I want).
Whether it can be done more directly and elegantly depends, I think, on whether a solution to the problem can be represented by an atom or must be a set or other non-atomic object. Given a problem whose solutions will all be atoms of type T, a predicate Solution which is true of atomic solutions to a problem, and a comparison relation gt which holds over atoms of the appropriate type(s), then you can certainly write
pred Maximum[ a : T ] {
Solution[a]
and
all s : T | Solution[s] implies
(gt[a,s] or a = s)
}
run Maximum for 5
Since Alloy is resolutely first-order, you cannot write the equivalent predicate for solutions which involve sets, relations, functions, paths through a graph, etc. (Or rather, you can write them, but the Analyzer cannot analyze them.)
But of course one can also introduce signatures called MySet, MyRelation, etc., so that one has one atom for each set, relation, etc., that one needs in a problem. This sometimes works, but it does run into the difficulty that such problems sometimes need all possible sets, relations, functions, etc., to exist (as in set theory they do), while Alloy will not, in general, create an atom of type MySet for every possible set of objects in univ. Jackson discusses this technique in sections 3.2.3 (see "Is there a loss of expressive power in the restriction to flat relations?"), 5.2.2 "Skolemization", and 5.3 "Unbounded universal quantifiers" of his book, and the discussion has thus far repaid repeated rereadings. (I have penciled in an additional index entry in my copy of the book pointing to these sections, under the heading 'Second-order logic, faking it', so I can find them again when I need them.)
All of that said, however: in section 4.8 of his book, Jackson writes "Integers are not actually very useful. If you think you need them, think again; ... Of course, if you have a heavily numerical problem, you're likely to need integers (and more), but then Alloy is probably not suitable anyway."

Getting Alloy to find the largest answer for particular sets

I'm trying to see if I can get Alloy to return the largest possible answer for a particular set. So, in this example, I would like the answers x={}, x=A, and x=B to not be generated by the model finder.
abstract sig X{}
one sig A extends X{}
one sig B extends X{}
pred(x: set X) {
x in A + B
}
I have tried something along the lines of:
pred(x: set X) {
x in A + B and
no y : set X |
y in A + B and #(y) > #(x)
}
but I get an error that analysis is not possible since it requires higher-order quantification.
I was wondering if there is a possible (or simpler) way to do this?
Alloy does not currently have any built-in functionality to produce maximal or minimal solutions. And yes, you're right that specifying that a solution is maximal generally requires higher order quantification. However, you can ensure that the solution is at least locally maximal with a first order quantification:
pred p (x: set X) {...}
pred locally_maximal_p (x: set X) {
p(x)
no e: X - x | p(x + e)
}

Resources