How to assert a given state leads to a another state with variables in TLA+? - tla+

Sorry the title is a bit cryptic. I have a TLA+ spec that defines two sets:
variables Requests = {}, Outcomes = {};
I have one set of workers adding requests, and another set or workers fulfilling them and writing to Outcomes. Each request has a unique Id, which the matching Outcome entry will then also contain.
I want to guarantee that any request added to the Requests set is eventually matched by a structure with the same Id in the Outcomes set. I've been trying to do this using the "leads to", ~>, operator, but can't figure out how to resolve the Id matching portion.
I've naively tried something like:
RequestsAreFulfilled == \E req \in Requests: TRUE
~> \E outcome \in Outcomes : outcome.id = req.id
But this obviously breaks since req is not defined in the second expression. I've considered something along the lines of the second express being "Then there is a state where all Request items are matched by Outcome items", but that doesn't work since the system never terminates - there may very well always be more requests in the Requests set, since Outcomes is always playing catch-up.
What is a way for me to assert that a request is eventually matched with an outcome with the same id?

TLC has some trouble proving liveness properties with nonconstant sets. Let's start with the fixed case, where you have a finite, fixed set of ids. Then we can specify the relation as
\A id \in Ids: (\E r \in req: r.id = id) ~> (\E o \in out: o.id = id)
In this case, though, we're better off using structures, as they're easier to understand and express shared relationships better.
requested = [i \in Ids |-> FALSE];
processed = [i \in Ids |-> FALSE];
\A id \in Ids: requested[i] ~> processed[i]
or
messages = [i \in Ids |-> [requested |-> FALSE, processed |-> FALSE]]
\A id \in Ids:
LET m == messages[i]
IN m.requested ~> m.processed
If you want an infinite number of messages, one way to get TLC to handle liveness checks is to use a fixed set of ids then add logic to "recycle" finished messages - set both requested and processed to FALSE. Then we can use the always-eventually operator, []<>, to express this:
\A id \in Ids: []<>(requested[i] => processed[i])

Related

How can I generate a graph by constraining it to be subisomorphic to a given graph, while not subisomorphic to another?

TL;DR: How can I generate a graph while constraining it to be subisomorph to every graph in a positive list while being non-subisomorph to every graph in a negative list?
I have a list of directed heterogeneous attributed graphs labeled as positive or negative. I would like to find the smallest list of patterns(graphs with special values) such that:
Every input graph has a pattern that matches(= 'P is subisomorphic to G, and the mapped nodes have the same attribute values')
A positive pattern can only match a positive graph
A positive pattern does not match any negative graph
A negative pattern can only match a negative graph
A negative pattern does not match any negative graph
Exemple:
Input g1(+),g2(-),g3(+),g4(+),g5(-),g6(+)
Acceptable solution: p1(+),p2(+),p3(-) where p1(+) matches g1(+) and g4(+); p2(+) matches g3(+) and g6(+); and p3(-) matches g2(-) and g5(-)
Non acceptable solution: p1(+),p2(-) where p1(+) matches g1(+),g2(-),g3(+); p2(-) matches g4(+),g5(-),g6(+)
Currently, I'm able to generate graphs matching every graph in a list, but I can't manage to enforce the constraint 'A positive pattern does not match any negative graph'. I made a predicate 'matches', which takes as input a pattern and a graph, and uses a local array of variables 'mapping' to try and map nodes together. But when I try to use that predicate in a negative context, the following error is returned: MiniZinc: flattening error: free variable in non-positive context.
How can I bypass that limitation? I tried to code the opposite predicate 'not_matches' but I've not yet found how to specify 'for all node mapping, the isomorphism is invalid'. I also can't define the mapping outside the predicate, because a pattern can match a graph more than once and i need to be able to get all mappings.
Here is a reproductible exemple:
include "globals.mzn";
predicate p(array [1..5] of var 0..10:arr1, array [1..5] of 1..10:arr2)=
let{array [1..5] of var 1..5: mapping; constraint all_different(mapping)} in (forall(i in 1..5)(arr1[i]=0\/arr1[i]=arr2[mapping[i]]));
array [1..5] of var 0..10:arr;
constraint p(arr,[1,2,3,4,5]);
constraint p(arr,[1,2,3,4,6]);
constraint not p(arr,[1,2,3,5,6]);
solve satisfy;
For that exemple, the decision variable is an array and the predicate p is true if a mapping exists such that the values of the array are mapped together. One or more elements of the array can also be 0, used here as a wildcard.
[1,2,3,4,0] is an acceptable solution
[0,0,0,0,0] is not acceptable, it matches anything. And the solution should not match [1,2,3,5,6]
[1,2,3,4,7] is not acceptable, it doesn't match anything(as there is no 7 in the parameter arrays)
Thanks by advance! =)
Edit: Added non-acceptable solutions
It is probably good to note that MiniZinc's limitation is not coincidental. When the creation of a free variable is negated, rather then finding a valid assignment for the variable, instead the model would have to prove that no such valid assignment exists. This is a much harder problem that would bring MiniZinc into the field of quantified constraint programming. The only general solution (to still receive the same flattened constraint model) would be to iterate over all possible values for each variable and enforce the negated constraints. Since the number of possibilities quickly explodes and the chance of getting a good model is small, MiniZinc does not do this automatically and throws this error instead.
This technique would work in your case as well. In the not_matches version of your predicate, you can iterate over all possible permutations (the possible mappings) and enforce that they not correct (partial) mappings. This would be a correct way to enforce the constraint, but would quickly explode. I believe, however, that there is a different way to enforce this constraint that will work better.
My idea stems from the fact that, although the most natural way to describe a permutation from one array to the another is to actually create the assignment from the first to the second, when dealing with discrete variables, you can instead enforce that each has the exact same number of each possible value. As such a predicate that enforces X is a permutation of Y might be written as:
predicate is_perm(array[int] of var $$E: X, array[int] of var $$E: Y) =
let {
array[int] of int: vals = [i | i in (dom_array(X) union dom_array(Y))]
} in global_cardinality(X, vals) = global_cardinality(Y, vals);
Notably this predicate can be negated because it doesn't contain any free variables. All new variables (the resulting values of global_cardinality) are functionally defined. When negated, only the relation = has to be changed to !=.
In your model, we are not just considering full permutations, but rather partial permutations, and we use a dummy value otherwise. As such, the p predicate might also be written:
predicate p(array [int] of var 0..10: X, array [int] of var 1..10: Y) =
let {
set of int: vals = lb_array(Y)..ub_array(Y); % must not include dummy value
array[vals] of var int: countY = global_cardinality(Y, [i | i in vals]);
array[vals] of var int: countX = global_cardinality(X, [i | i in vals]);
} in forall(i in vals) (countX[i] <= countY[i]);
Again this predicate does not contain any free variables, and can be negated. In this case, the forall can be changed into a exist with a negated body.
There are a few things that we can still do to optimise p for this use case. First, it seems that global_cardinality is only defined for variables, but since Y is guaranteed par, we can rewrite it and have the correct counts during MiniZinc's compilation. Second, it can be seen that lb_array(Y)..ub_array(Y) gives the tighest possible set. In your example, this means that only slightly different versions of the global cardinality function are evaluated, that could have been
predicate p(array [1..5] of var 0..10: X, array [1..5] of 1..10: Y) =
let {
% CHANGE: Use declared values of Y to ensure CSE will reuse `global_cardinality` result values.
set of int: vals = 1..10; % do not include dummy value
% CHANGE: parameter evaluation of global_cardinality
array[vals] of int: countY = [count(j in index_set(Y)) (i = Y[j]) | i in vals];
array[vals] of var int: countX = global_cardinality(X, [i | i in 1..10]);
} in forall(i in vals) (countX[i] <= countY[i]);
Regarding the example. One approach might be to rewrite the not p(...) constraint to a specific not_p(...) constraint. But I'm how sure how that be formulated.
Here's an example but it's probably not correct:
predicate not_p(array [1..5] of var 0..10:arr1, array [1..5] of 1..10:arr2)=
let{
array [1..5] of var 1..5: mapping;
constraint all_different(mapping)
} in
exists(i in 1..5)(
arr1[i] != 0
/\
arr1[i] != arr2[mapping[i]]
);
This give 500 solutions such as
arr = [1, 0, 0, 0, 0];
----------
arr = [2, 0, 0, 0, 0];
----------
arr = [3, 0, 0, 0, 0];
...
----------
arr = [2, 0, 0, 3, 4];
----------
arr = [2, 0, 1, 3, 4];
----------
arr = [2, 1, 0, 3, 4];
Update
I added not before the exists loop.

\in works, while \subseteq gives a "identifier undefined" error

I have the following spec:
------------------------------ MODULE Group ------------------------------
CONSTANTS People
VARIABLES members
Init == members \subseteq People
Next == members' = members
Group == Init /\ [][Next]_members
=============================================================================
(I simplified this spec to the point where it's not doing anything useful.)
When I try to run it through TLC, I get the following error:
In evaluation, the identifier members is either undefined or not an operator.
The error points to the Init line.
When I change the Init line to:
Init == members \in People
it validates fine.
I want the former functionality because I mean for members to be a collection of People, not a single person.
According to section 16.1.6 of Leslie Lamport's Specifying Systems, "TLA+ provides the following operators on sets:" and lists both \in and \subseteq.
Why is TLA+ not letting me use \subseteq?
While that is a valid TLA+ expression, TLC can only assign next-state values to a variable x by the statements x' = e or x' \in S. See section 14.2.6 for details. This holds for the initial assignment, too. In your case, you probably want members \in SUBSET People.

AQL to validate path to node

We're required to have some AQL that validates a specific path to an entity. The current solution performs very poorly, due to needing to scan whole collections.
e.g. here we have 3 entity 'types': a, b, c (though they are all in a single collection) and specific edge collections between them and we want to establish whether or not there is a connection between _key "123" and _key "234" that goes exactly through a -> b -> c.
FOR a IN entities FILTER e._key == "123"
FOR b IN 1..1 OUTBOUND e edges_a_to_b
FOR c IN 1..1 INBOUND e_1 edges_c_to_b
FILTER e_2._key == "234"
...
This can fan out very quickly!
We have another solution, where we use SHORTEST PATH and specify the appropriate DIRECTION and edge collections which is much faster (>100times). But worry that this approach does not satisfy quite our general case... the order of the edges is not enforced, and we may have to go through the same edge collection more than once, which we cannot do with that syntax.
Is there another way, possibly involving paths in the traversal?
Thanks!
Dan.
If i understand correctly you always know the exact path that is required between your two vertices.
So to take your example a -> b -> c, a valid result will have:
path.vertices == [a, b, c]
So we can use this path to filter on it, which only works if you use a single traversal step instead of multiple ones.
So what we try to du is the following pattern:
FOR c,e, path IN <pathlength> <direction> <start> <edge-collections>
FILTER path.vertices[0] == a // This needs to be formulated correctly
FILTER path.vertices[1] == b // This needs to be formulated correctly
FILTER path.vertices[2] == c // This needs to be formulated correctly
LIMIT 1 // We only net exactly one path, so limit 1 is enough
[...]
So with this hint is it possible to write the query in the following way:
FOR a IN entities
FILTER a._key == "123"
FOR c, e, path IN 2 OUTBOUND a edges_a_to_b, INBOUND edges_b_to_c
FILTER path.vertices[1] == /* whatever identifies b e.g. vertices[1].type == "b" */
FILTER path.vertices[2]._key == "234"
LIMIT 1 /* This will stop as soon as the first match is found, so very important! */
/* [...] */
This will allow the optimizer to apply the filter conditions as early as possible, und will (almost) use the same algorithm as the shortest path implementation.
The trick is to use one traversal instead of multiples to save internal overhead and allow for better optimization.
Also take into account that it might be better to search in the opposite direction:
e.g. instead of a -> b -> c check for c <- b <- a which might be faster.
This depends on the amount of edges per each node.
I assume a doctor has many surgeries, but a single patient most likely has only a small amount of surgeries so it is better to start at the patient and check backwards instead of starting at the doctor and check forwards.
Please let me know it this helps already, otherwise we can talk about more details and see if we can find some further optimizations.
Disclaimer: I am part of the Core-Dev team at ArangoDB

Comparing elements of sequence and set in TLA+

Given a sequence S = <<1,2,3,4>> and a set S' = {1,2,3,4,5,6}. How do we check if both of them contain the same values in TLA+?
Define Range(f) == {f[x]: x \in DOMAIN f}. Since all sequences are functions, Range(S) will give us the values of sequence S. Then we check both have the same elements with Range(S) = S_prime.
(We can't call it S' because that means "The next state value of S".)

specifying properties of relations in alloy

I am trying to express certain mathematical properties of relations in Alloy, but I am not sure if I have the right approach yet, as I am just a beginner. Would appreciate any insights from the community of experts out there!
Specifying the fact that domain of a relation as singleton. e.g. Is the following a reasonable and correct way to do that?
pred SingletonDomain(r: univ->univ) {
one ~r
}
sig S2 {}
sig S1 {
child: set S2
}
fact {
SingletonDomain [child]
}
or should it be something like the following
pred SingletonDomain (r: univ->univ) {
#S2.~r = 1
}
This is not very modular since the use of S2 is very specific to the particular signature.
Specifying the fact that a relation is a total order. At the moment I am using the following, basically I am simulating xor
pred total[r: univ->univ] {
all disj e, e': Event | (e.r = e' and e'.r != e) or (e.r != e' and e'.r = e)
}
Thanks
To specify the fact that the domain of a given relation is a singleton, your first attempt is really close to do the trick. The only problem is that one ~r enforces the inverse of the r relation (and thus the r relation itself) to be composed of a single tuple. This is not what you want to express.
What you want to express is that all elements in the range of the r relation have the same (so only one) image through its inverse relation '.
You should thus write the following predicate :
pred SingletonDomain(r: univ->univ) {
one univ.~r
}
For your second question, your predicate doesn't handle cases were e -> e' -> e '' -> e. To handle those, you can use transitive closure.

Resources