How to compare two LTLs? - automata

How can I compare two LTLs to see if one can contradict each other? I ask this because I have a hierarchical state machine and LTLs describing the behavior in each state. I need to know if a local LTL can contradict a global LTL. I saw in the Article 'Feature Specification and Automated Conflict Detection' that two LTLs properties f and g are inconsistent iff L(f) intersection L(g) is empty. And this is exactly the model checking question with f as the program and ¬g as the property. Can anyone help me with this? How can I transform an LTL f into a program in SPIN/Promela??
Thanks.

The following works for me. (Warning: I've not seen this in official documentation. This could mean that there are other, better ways to do this. Or that I didn't look hard enough.)
We want to check whether [] <> p && [] <> q implies <> (p && q). (It does not.)
Write a trivial process P that can do all transitions, and write the claim as an LTL property A.
bool p; bool q;
active proctype P () {
do :: d_step { p = false; q = false }
:: d_step { p = false; q = true }
:: d_step { p = true; q = false }
:: d_step { p = true; q = true }
od
}
ltl A { (([] <> p) && ([] <> q)) -> <> (p && q) }
(EDIT 1-Nov-2016: this may be incorrect because we might be missing some transitions because of a hidden initial state, see how to make a non-initialised variable in Spin? )
Then put this in a file check.pml, and
spin -a check.pml
cc pan.c -o pan
./pan -a -n
./pan -r check.pml.trail -v
shows a model of the negation of the claim (an ultimately periodic trail where p and q are true infinitely often, but p && q is never).
Double-check: change the conclusion in the claim to <> (p || q), then there is no counter-examle, proving that the implication is valid.
In your case, the claim is ! (f && g) (they should never be true at the same time).
There probably is some clever way to make the code for the trivial process smaller.
Also, the third command is actually ./pan -a -i -n (the -i to find a shortest example) but it gives a warning. And it does find a shorter cycle.

Related

Using sets and SetHasSize on intersections in z3

I've been trying to enumerate solutions to the following problem. I've started with simple approach first.
Below I have two sets of size k, intersection between them is of size 1 and I want to see how sets A and B look:
Els, elems = EnumSort('Els',['a1', 'a2', 'a3'])
A, B = Consts('A B', SetSort(Els))
k, c = Ints('k c')
s = Solver()
s.add(SetHasSize(A, k))
s.add(SetHasSize(B, k))
s.add(k == 2, c == 1)
s.add(SetHasSize(SetIntersect(A, B), c))
s.check()
s.model()
Here, the solution should be A == ['a1', 'a2'] and B == ['a2', 'a3'] but satisfiability was not reached.
Even a simple task like one below results in never ending execution:
V, _ = EnumSort('Els',['a1', 'a2', 'a3'])
A = Const('A', SetSort(V))
k = Int('k')
s = SimpleSolver()
s.add(SetHasSize(A, k))
s.add(k == IntVal(2))
s.check()
s.model()
Changing k == IntVal(2) to k <= IntVal(2) makes the problem satisfiable and returns [A = ∃k!0 : k!0 = a1 ∨ k!0 = a2, k = 2] as a model of the set. I'm not sure if there is a faster approach.
If I run your program, I get:
WARNING: correct handling of finite domains is TBD
WARNING: correct handling of finite domains is TBD
WARNING: correct handling of finite domains is TBD
before it starts looping. This is a known issue in the implementation: Z3 cannot really deal with sets that have a finite domain.
Alas, replacing it with an infinite domain doesn't help either. Making this change:
A, B = Consts('A B', SetSort(IntSort()))
You get:
unsat
which is clearly bogus. I strongly suspect this is related to the following issue: https://github.com/Z3Prover/z3/issues/3854 (In short, the SMTLib frontend does not support set-has-size. For whatever reason, they left it in the Python and C/C++ interfaces, but clearly it's not really functional.)
So, strictly speaking, this is a bug. But more realistic answer is that set-has-size is no longer supported by z3. You should file an issue at https://github.com/Z3Prover/z3/issues so the authors are aware of this problem and perhaps remove it from the API completely if it won't ever be supported.
UPDATE:
As of this commit, z3 no longer accepts the set-has-size predicate; it is no longer supported.

How do I write a clean function in Dafny to get the minimum of a set?

I am trying to write a function to get the minimum of a non-empty set.
Here is what I came up with:
method minimum(s: set<int>) returns (out: int)
requires |s| >= 1
ensures forall t : int :: t in s ==> out <= t
{
var y :| y in s;
if (|s| > 1) {
var m := minimum(s - {y});
out := (if y < m then y else m);
assert forall t : int :: t in (s - {y}) ==> out <= t;
assert out <= y;
} else {
assert |s| == 1;
assert y in s;
assert |s - {y}| == 0;
assert s - {y} == {};
assert s == {y};
return y;
}
}
This is suboptimal for two reasons:
Dafny gives a "No terms found to trigger on." warning for the line,
assert forall t : int :: t in (s - {y}) ==> out <= t;
However, removing this line causes the code to fail to verify. My understanding is that the trigger warning isn't really bad, it's just a warning that Dafny might have trouble with the line. (Even though it actually seems to help.) So it makes me feel like I'm doing something suboptimal or non-idiomatic.
This is pretty inefficient. (It constructs a new set each time, so it would be O(n^2).) But I don't see any other way to iterate through a set. Is there a faster way to do this? Are sets really intended for programming "real" non-ghost code in Dafny?
So my question (in addition to the above) is: is there a better way to write the minimum function?
In this case, I recommend ignoring the trigger warning, since it seems to work fine despite the warning. (Dafny's trigger inference is a little bit overly conservative when it comes to the set theoretic operators, and Z3 is able to infer a good trigger at the low level.) If you really want to fix it, here is one way. Replace the "then" branch of your code with
var s' := (s - {y});
var m := minimum(s');
out := (if y < m then y else m);
assert forall t :: t in s ==> t == y || t in s';
assert forall t : int :: t in s' ==> out <= t;
assert out <= y;
The second problem (about efficiency) is somewhat fundamental. (See Rustan's paper "Compiling Hilbert's Epsilon Operator" where it is mentioned that compiling let-such-that statements results in quadratic performance.) I prefer to think of Dafny's set as a mathematical construct that should not be compiled. (The fact that it can be compiled is a convenience for toy programs, not for real systems, where one would expect a standard library implementation of sets based on a data structure.)

Using :| in functional code -- recursion on sets

How might one recurse over a set, S, in Dafny when writing pure functional code? I can use :| in imperative code, having checked for non-emptiness, to select an element, s, then recurse on S - {s}. Not quite sure how to make :| deterministic and use it in functional code.
Good question! (I wish downvoters would have the courage to leave a comment...)
This is addressed in depth in Rustan's paper "Compiling Hilbert's Epsilon Operator".
In particular, see section 3.2, which describes how to write a deterministic function by recursion over sets. For reasons not entirely clear to me, the paper's Dafny code proving lemma ThereIsASmallest doesn't work for me in modern Dafny. Here is a version that works (but is ugly):
lemma ThereIsASmallest(S: set<int>)
requires S != {}
ensures exists x :: x in S && forall y | y in S :: x <= y
{
var y :| y in S;
if S != {y} {
var S' := S - {y};
assert forall z | z in S :: z in S' || z == y;
ThereIsASmallest(S');
var x' :| x' in S' && forall y | y in S' :: x' <= y;
var x := min2(y, x');
assert x in S;
}
}
Finally, as an aside, note that the technique of section 3.2 relies on having a total order on the type. If you are trying to do something fully polymorphic, then as far as I know it isn't possible.

Is my rec function tail recursive?

Is this function tail-recursive ?
let rec rec_algo1 step J =
if step = dSs then J
else
let a = Array.init (Array2D.length1 M) (fun i -> minby1J i M J)
let argmin = a|> Array.minBy snd |> fst
rec_algo1 (step+1) (argmin::J)
In general, is there a way to formally check it ?
Thanks.
This function is tail-recursive; I can tell by eyeballing it.
In general it is not always easy to tell. Perhaps the most reliable/pragmatic thing is just to check it on a large input (and make sure you are compiling in 'Release' mode, as 'Debug' mode turns off tail calls for better debugging).
Yes, you can formally prove that a function is tail-recursive. Every expression reduction has a tail-position, and if all recursions are in tail-positions then the function is tail-recursive. It's possible for a function to be tail-recursive in one place, but not in another.
In the expression let pat = exprA in exprB only exprB is in tail-position. That is, while you can go evaluate exprA, you still have to come back to evaluate exprB with exprA in mind. For every expression in the language, there's a reduction rule that tells you where the tail position is. In ExprA; ExprB it's ExprB again. In if ExprA then ExprB else ExprC it's both ExprB and ExprC and so on.
The compiler of course knows this as it goes. However the many expressions available in F# and the many internal optimizations carried out by the compiler as it goes, e.g. during pattern match compiling, computation expressions like seq{} or async{} can make knowing which expressions are in tail-position non-obvious.
Practically speaking, with some practice it's easy for small functions to determine a tail call by just looking at your nested expressions and checking the slots which are NOT in tail positions for function calls. (Remember that a tail call may be to another function!)
You asked how we can formally check this so I'll have a stab. We first have to define what it means for a function to be tail-recursive. A recursive function definition of the form
let rec f x_1 ... x_n = e
is tail recursive if all calls of f inside e are tail calls - ie. occur in a tail context. A tail context C is defined inductively as a term with a hole []:
C ::= []
| e
| let p = e in C
| e; C
| match e with p_1 -> C | ... | p_n -> C
| if e then C else C
where e is an F# expression, x is a variable and p is a pattern. We ought to expand this to mutually recursive function definitions but I'll leave that as an exercise.
Lets now apply this to your example. The only call to rec_algo1 in the body of the function is in this context:
if step = dSs then J
else
let a = Array.init (Array2D.length1 M) (fun i -> minby1J i M J)
let argmin = a|> Array.minBy snd |> fst
[]
And since this is a tail context, the function is tail-recursive. This is how functional programmers eyeball it - scan the body of the definition for recursive calls and then verify that each occurs in a tail context. A more intuitive definition of a tail call is when nothing else is done with the result of the call apart from returning it.

List comprehension stop generating certain lists if sublist fails on check

I have a code, which generates all the possible variation (with the legnth of N) with repetition.
variation(1, L) ->
[ [H] || H <- L ];
variation(N, L) ->
[[H | T] || H <- L, T <- variation(N - 1, L)].
For variation(3, [1,2,3,4]) it will generate:
[[1,1,1,1],[1,1,1,2],[1,1,1,3],[1,1,1,4],[1,1,2,1],...]
I would like to check a condition during the generation of the lists. If a sublist fails, it should stop generating lists, that begins with the certain sublist.
For example if [1,1] sublist fails that condition (check), than it should not generate [1,1,1,1], [1,1,1,2] etc (all of those that begin with [1,1]).
I don't know if its possible with 1 list comprehension.
So far, I have this code:
variation(1, L) ->
[ [H] || H <- L ];
variation(N, L) ->
[[H | T] || H <- L, T <- variation(N - 1, L), check([H|T]) ].
This solution will only return those lists, that doesn't fail the condition (it works, but really slow for big input).
If [1,1] fails, it will try to generate [1,1,1,2], but those will fail the check as well. I would need a solution, which doesn't try to generate lists that begin with [1,1,...] (or with a previously failing sublist).
One small detail first: According to your question, variations(3, [1,2,3]). should generate [[1,1,1,1], [1,1,1,2], …] but it actually generates [[1,1,1], [1,1,2], …]. I will assume the code was right and you meant to say that variations(4, [1,2,3]). should generate [[1,1,1,1], [1,1,1,2], …]
I wrote an alternative version of your function that, using a different order on the right side of the LC, avoids generating list when their prefix is already false when checked with check/1:
variation(1, L) ->
[ [Elem] || Elem <- L ];
variation(N, L) ->
[ Init ++ [Last] || Init <- variation(N-1, L), check(Init), Last <- L].
As you can see, since check(Init) happens before Last <- L, Last is only generated if check(Init) == true.
That will likely have the effect you were looking for.
But… be careful. I'm using ++ in the left side of the LC. You should definitely benchmark your code and see if that has an impact on performance or not.
If it does, and only if it does, you might want to consider using something like this:
variation3(1, L) ->
[ [Elem] || Elem <- L ];
variation3(N, L) ->
[ lists:reverse([Last|lists:reverse(Init)]) || Init <- variation2(N-1, L), check(Init), Last <- L].
Maybe worth it, maybe not… you will need to benchmark your stuff to figure that out.

Resources