When Alloy says 'No instance found.' How can I look for some more detail to know why the outcome is not as expected?
I am using Alloy Analyzer 6.1.0
My code is,
sig State, Node {}
sig List {
header: Node ->one State
}
pred test( l: List, n: Node ){
#l.header = 1 and #n.(l.header) = 1
}
run test for exactly 2 List, exactly 2 State, exactly 2 Node
My expect is,
But Alloy's output is,
Executing "Run run$1 for exactly 2 List, exactly 2 State, exactly 2 Node" Solver=sat4j Bitwidth=4 MaxSeq=4 SkolemDepth=1 Symmetry=20 Mode=batch 106 vars. 8 primary vars. 195 clauses. 124ms. No instance found. Predicate may be inconsistent. 3ms.
I looked the Parse Tree, but still having no idea why no instance found.
However, if I change the exactly 2 Node to exactly 1 Node, then Alloy says, Instance found. Like this,

I do not understand how to explain this difference.

There are mainly two approaches to "debugging" in Alloy.
I'm going with the most important one first, which is like being a detective: you must look by yourself for constraints that are sufficient to make your model inconsistent:
For instance, your model can be rewritten as follows:
Then you may realize that
one l.header[n]isn't useful as the type ofheaderalready says that there's exactly one state for every pair of list and node. So you can remove it and see that it is still UNSAT.Now, you have essentially 3 constraints:
onein the type ofheader,oneintestand the scope specification. The type ofheadersays that every combination of list and node is mapped to a unique state. Due to the scope, it meansheadershould be equal to, up to permutations,{ l1->n1->?, l1->n2->?, l2->n1->?, l2->n2->? }(with?beings1ors2for every tuple). Then, intest, you're saying thatl(be itl1orl2) is associated to a single pair of node and state. Bang!So we see the issue comes from a combination of 3 constraints.
If indeed you consider only one node instead, then
headerwill only contain tuples of the shape{ l1->n1->?, l2->n1->? }, which will -this time- satisfytest.But another way to solve the issue would be to remove
test! Or to removeonein the type ofheader! There are often several ways to solve an inconsistency. It's your knowledge of the domain that will make you favor one solution over another.For completeness, there is a second approach which complements the former and is automated, but it's sometimes difficult to interpret. The idea is to ask Alloy to produce a so-called UNSAT core, that is a set of constraints that is sufficient to lead to inconsistency. To do so, you must rely on a SAT solver that can produce such cores, e.g. "Minisat with Unsat Cores" in the Options menu. Then, you run the analysis and, if it's inconsistent as in your example, a
Coreclickable text will appear that will highlight "suspicious" parts in your model. Depending on options, the computation of the core will be more or less fast and the scope of highlighting will be more or less large.In your example, if I use
Slow minimizationand granularityExpand quantifiers, then Alloy will only highlightone l.header. And indeed, you may relax or remove this constraint to make the model satisfiable. But as you can see from the above discussion, other modifications might work too, and UNSAT core extraction with these options doesn't show them. At the very least, using this technique should by no means prevent you to rely on your own analysis of the situation!