Basic error using solver in Z3-Python: it is returning [] as a model - z3

Maybe I have slept bad today, but I am really struggling with this simple query to Z3-Python:
from z3 import *
a = Bool('a')
b = Bool('b')
sss = Solver()
sss.add(Exists([a,b], True))
print(sss.check())
print(sss.model())
The check prints out sat, but the model is []. However, it should be printing some (anyone) concrete assignment, such as a=True, b=True.
The same is happening if I change the formula to, say: sss.add(Exists([a,b], Not(And(a,b)))). Also tested sss.add(True). Thus, I am missing something really basic, so sorry for the basic nature of this question.
Other codes are working normally (even with optimizers instead of solvers), so it is not a problem of my environment (Collab)
Any help?

Note that there's a big difference between:
a = Bool('a')
b = Bool('b')
sss.add(Exists([a, b], True))
and
a = Bool('a')
b = Bool('b')
sss.add(True) # redundant, but to illustrate
In the first case, you're checking if the statement Exists a. Exists b. True is satisfiable; which trivially is; but there is no model to display: The variables a and b are inside quantification; and they don't play any role in model construction.
In the second case, a and b are part of the model, and hence will be displayed.
What's confusing is why do you need to declare the a and b in the first case. That is, why can't we just say:
sss.add(Exists([a, b], True))
without any a or b in the environment? After all, they are irrelevant as far as the problem is concerned. This is merely a peculiarity of the Python API; there's really no good reason other than this is how it is implemented.
You can see the generated SMTLib by adding a statement of the form:
print(sss.sexpr())
and if you do that for the above segments, you'll see the first one doesn't even declare the variables at all.
So, long story short, the formula exists a, b. True has no "model" variables and thus there's nothing to display. The only reason you declare them in z3py is because of an implementation trick that they use (so they can figure out the type of the variable), nothing more than that.
Here're some specific comments about your questions:
An SMT solver will only construct model-values for top-level declared variables. If you create "local" variables via exists/forall, they are not going to be displayed in models constructed. Note that you could have two totally separate assertions that talk about the "same" existentially quantified variable: It wouldn't even have a way of referring to that item. Rule-of-thumb: If you want to see the value in a model, it has to be declared at the top-level.
Yes, this is the reason for the trick. So they can figure out what type those variables are. (And other bookkeeping.) There's just no syntax afforded by z3py to let you say something like Exists([Int(a), Int(b)], True) or some such. Note that this doesn't mean something like this cannot be implemented. They just didn't. (And is probably not worth it.)
No you understood correctly. The reason you get [] is because there are absolutely no constraints on those a and b, and z3's model constructor will not assign any values because they are irrelevant. You can recover their values via model_completion parameter. But the best way to experiment with this is to add some extra constraints at the top level. (It might be easier to play around if you make a and b Ints. At the top level, assert that a = 5, b = 12. At the "existential" level assert something else. You'll see that your model will only satisfy the top-level constraints. Interestingly, if you assert something that's unsatisfiable in your existential query, the whole thing will become unsat; which is another sign of how they are treated.
I said trivially true because your formula is Exists a. Exists b. True. There're no constraints, so any assignment to a and b satisfy it. It's trivial in this sense. (And all SMTLib logics work over non-empty domains, so you can always assign values freely.)
Quantified variables can always be alpha-renamed without changing the semantics. So, whenever there's collision between quantified names and top-level names, imagine renaming them to be unique. I think you'll be able to answer your own question if you think of it this way.
Extended discussions over comments is really not productive. Feel free to ask new questions if anything isn't clear.

Related

How do I change a pre-defined variable in a table in Luau?

In a Roblox game I'm programming, I want to have a table of boolean values to iterate over ensuring that they're all false before making another one true, e.g.;
local bool1 = true
local bool2 = false
local bool3 = false
local bool4 = false
local tbl1 = {}
table.insert(tbl1,boolX) -- where "X" is the number above, did this in interest of shortening
for i,v in pairs(tbl1) do
if v then v = not v end
end
However, as stated in the penultimate paragraph of section 2.1 of the 5.3 manual (knowing, albeit, that Luau uses 5.1 as its base);
Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, only references to them. Assignment, parameter passing, and function returns always manipulate references to such values; these operations do not imply any kind of copy.
That in mind, that means that I'm not actually shoving bool1 through bool4 into the table, just their values; the table would look like {true, false, false, false}. This means that I can't simply write a loop to iterate through the table and invert any trues I find;
local bool1 = true
local tbl1 = {}
table.insert(tbl1,bool1)
tbl1[1] = false
print(bool1)
print(tbl[1])
--output:
-- true
-- false
I should point out that I very well could just shove all my variables into one giant if/else and call it a night, but that is a lot of variables to check, a lot of typing, and I can't think of any other more elgant and less tedious way other than finding a form of iteration over them all.
I want to be able to have an actual reference, in some form, to the actual variables so that I can modify them from within the table and make them iterable.
I've attempted to follow the examples given in the best answer to this question, with no successes. I would need to be able to, and cannot with these examples, substitute for any given variable at any given time, rather than just having one or two I want declated and thus returned as shown. I've attempted wrapping them in a function to provide my table and variable as arguments, but that doesn't seem to have any effect; it either outputs nothing, or nil.
The following answer after has one example that seems like it could work, but overall is pointless for what I'm trying to achieve; I don't want to re-declare or re-assign the variables I already have, I just want to return the specific value.
I've attempted using a key/value pair, making the key the potential variable name and making it equal the variable's value, but I've no way to make that key return a variable of the same name. I even attempted merging this method and the setmetatable method mentioned in the first set of examples to see if I couldn't substitute from there, to no avail.
I should point out that, while I'm not a complete newbie to Lua or Luau, I'm also not an expert in the field by any meaning of the word; I'll catch on quick, but where possible, explain like I'm 10.
The only way to iterate over local variables that are not referenced by table fields, is to use debug.getlocal in a loop.
Opinionated:
But this is a very bad approach to your problem.
You should refactor the code. If you need to update a list of variables have them in a list from the start. Don't be afraid of refactoring. Improving things usually pays off on the long term.
If your codebase is so bad that you are afraid of putting a few variables into a table you should really think over the design.
There is no way to do this in Roblox Luau.
Any potential way to do so in standard Lua is impossible to do in Luau due to how heavily sandboxed the latter is compared to the former.
Possible solutions that were recommended via comments include: making the variables needed available in _G as globals, then using them there; or using a pointer value in the table equivalent to the one you want, even though it won't technically change the value you want itself.
Another answer recommends the use of debug.getlocal() for standard Lua, but doesn't work in Luau; keep this in mind when attempting to use it, as you will get an attempt to call a nil value error.
The recommended way to do this is not to do it at all, and instead have your variables and/or values in your table from the start.
Not only does this provide ease-of-access in many cases, but it will allow you to iterate through them significantly easier than trying to shove them into tables and the like. Refactoring, if you need to do something similar to this, is highly recommended across the board.

SAT queries are slowing down in Z3-Python: what about incremental SAT?

In Z3 (Python) my SAT queries inside a loop are slowing down, can I use incremental SAT to overcome this problem?
The problem is the following: I am performing a concrete SAT search inside a loop. On each iteration, I get a model (of course, I store the negation of the model in order not to explore the same model again). And also, if that model satisfies a certain property, then I also add a subquery of it and add other restrictions to the formula. And iterate again, until UNSAT (i.e. "no more models") is obtained.
I offer an orientative snapshot of the code:
...
s = Solver()
s.add(True)
while s.check() == sat:
s.check()
m = s.model()
phi = add_modelNegation(m)
s.add(phi) #in order not to explore the same model again
if holds_property(m): #if the model holds a property
s = add_moreConstraints(s,m) #add other constrains to the formula
...
The question is that, as the formula that s has to solve gets greater, Z3 is starting to have more trouble to find those models. That is okay: this should happen, since finding a model is now more difficult because of the added restrictions. However, in my case, it is happening too much: the computation speed has been even halved; i.e. the time that the solver needs to find a new model is the double after some iterations.
Thus, I would like to implement some kind of incremental solving and wondered whether there are native methods in Z3 to do so.
I have been reading about this in many pages (see, for instance, How incremental solving works in Z3?), but only found this response in How to use incremental solving with z3py interesting:
The Python API is automatically "incremental". This simply means the ability to call the command check() multiple times, without the solver forgetting what it has seen before (i.e., call check(), assert more facts, call check() again; the second check() will take into account all the assertions from the very beginning).
I am not sure I understand, thus I make a simple question: that the response mean that the incremental SAT is indeed used in Z3's SAT? The point I think I am looking for another incrementality; for example: if in the SAT iteration number 230 it is inevitable that a variable (say b1) is true, then that is a fact that will not change afterwards, you can set it to 1, simplify the formula and not re-reason anything to do with b1, because all models if any will have b1. Is this incremental SAT of Z3 considering these kind of cases?
In case not, how could I implement this?
I know there are some implementations in PySat or in MiniSat, but I would like to do it in Z3.
As with anything related to performance of z3 solving, there's no one size fits all. Each specific problem can benefit from different ideas.
Incremental Solving The term "incremental solving" has a very specific meaning in the SAT/SMT context. It means that you can continue to add assertions to the system after a call to check, without it forgetting the assertions you added before hand. This is what makes it incremental. Additionally, you can set jump-points; i.e., you can tell the solver to "forget" the assertions you put in after a certain point in your program, essentially moving through a stack of assertions. For details, see Section 3.9 of https://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.6-r2021-05-12.pdf, specifically the part where it talks about the "Assertion Stack."
And, as noted before, you don't have to do anything specific for z3 to be incremental. It is incremental by default, i.e., you can simply add new assertions after calling check, or use push/pop calls etc. (Compare this to, for instance, CVC4; which is by default not incremental. If you want to use CVC4 in incremental mode, you have to pass a specific command line argument.) The main reason for this is that incremental mode requires extra bookkeeping, which CVC4 isn't willing to pay for unless you explicitly ask it to do so. For z3, the developers decided to always make it incremental without any command line switches.
Regarding your particular question about what happens if b1 is true: Well, if you somehow determined b1 is always true, simply assert it. And the solver will automatically take advantage of this; nothing special needs to be done. Note that z3 learns a ton of lemmas as it works through your program such as these and adds them to its internal database anyhow. But if you have some external mechanism that lets you deduce a particular constraint, just go ahead and add it. (Of course, the soundness of this will be on you, not on z3; but that's a different question.)
One specific "trick" in speeding up enumerating "find me all-solutions" loops like you are doing is to do a divide-and-conquer approach, instead of the "add the negation of the previous model and iterate." In practice this can make a significant difference in performance. I think you should try this idea. It's explained here: https://theory.stanford.edu/~nikolaj/programmingz3.html#sec-blocking-evaluations As you can see, the all_smt function defined at the end of that section takes specific advantage of incrementality (note the calls to push/pop) to speed up the model-search process, by carefully dividing the search space into disjoint segments, instead of doing a random-walk. Using this might give you the speed-up you need. But, again, as with anything performance specific, you'll need to tell us more about exactly what problem you are solving: None of these methods can avoid performance problems caused by modeling issues. (For instance, using integers to model booleans is one common pitfall.) See this answer for some generic advice: https://stackoverflow.com/a/57661441/936310

Difference between multiset(a[..a.Length]) and multiset(a[..]) in Dafny

I'm trying to figure something out in dafny.
Given 2 arrays a and b, my assertions, invariants, post conditions, etc in the form of:
multiset(a[..]) == multiset(b[..]);
fails but
multiset(a[..a.Length]) == multiset(b[..b.Length])
succeeds.
I'm very confused by this because I assumed a[..] and a[..a.Length] would be the exact same thing. However, I found something interesting. If I add at the end of my method:
assert a[..a.Length] == a[..];
assert b[..b.Length] == b[..];
then I can get the invariants, post conditions, assertions involving my first example to work.
This suggests to me that a[..] and a[..a.Length] are actually different.
Could someone please explain why this is the case and what is happening here?
You are correct that a[..] and [..a.Length] (and, for that matter, also a[0..] and a[0..a.Length]) are the same thing. However, it may be that verifier treats these slightly differently. This makes a difference because the lack of (caution: technical word coming up) extensionality in Dafny.
Extensionality means that, if you know two things have the same elements, then they are the same thing. In your example, extensionality would mean that, if you know a[..] and a[..a.Length] to have the same elements, then a[..] and a[..a.Length] are the same thing.
The lack of extensionality in Dafny means that the verifier sometimes knows that two things have the same elements, but it still doesn't draw the conclusion that the two things are the same. This tends to be noticeable when the two things are passed to a function. In your example, that function is multiset(...), which converts a sequence into a multiset.
While Dafny does not support extensionality automatically, it does offer a simple technique to "remind" the verifier about extensionality. The technique is to assert the equality between the two things. In particular, when you write assert A == B; for two sequences A and B, then the verifier will first prove that A and B have the same elements, and then it will draw the conclusion that A is in fact equal to B. In other words, when the verifier is explicitly asked to verify the equality of two sequence-valued expressions like A and B, then it instead just proves that they are element-wise equal, after which it concludes A == B.
So, your remedy above is exactly the right thing to do. When you assert the equality between a[..a.Length] and a[..], the verifier proves that they have the same elements. After that, it "remembers" that this also means that a[..a.Length] and a[..] are equal. Once it has realized the two sequences are the same, it immediately also knows that functions of them, like multiset(a[..a.Length]) and multiset(a[..]), are the same.
More generally, extensionality is relevant for not just sequences, but also for sets, multisets, and maps. So, if you're working with any of those collection types, you may need to write assertions about sequence equality, set equality, etc., to "remind" the verifier about extensionality.
More generally, there are many things that are true and that the verifier doesn't immediately verify. To home in on what may be missing, the common technique is to start breaking down the proof obligations yourself, like you did in the assert statements. By breaking down more complicated proof obligations into simpler ones (which is usually done with assert statements or calc statements), you essentially provide hints to the verifier about how to prove the more complicated things.

DLV Rule is not safe

I am starting to work with DLV (Disjunctive Datalog) and I have a rule that is reporting a "Rule is not safe" error, when running the code. The rule is the following:
foo(R, 1) :- not foo(R, _)
I have read the manual and seen that "cyclic dependencies are disallowed". I guess this is why I am being reported the error, but I am not sure how this statement is so problematic to DLV. The final goal is to have some kind of initialization in case that the predicate has not been defined.
More precisely, if there is no occurrence of 'foo' with the parameter R (and anything else), then define it with parameters R and 1. Once it is defined, the rule shouldn't be triggered again. So, this is not a real recursion in my opinion.
Any comments on how to solve this issue are welcomed!
I have realised that I probably need another predicate to match the parameter R in the body of the rule. Something like this:
foo(R, 1) :- not foo(R, _), bar(R)
Since, otherwise there would be no way to know whether there are no occurrences of foo(R, _). I don't know whether I made myself clear.
Anyway, this doesn't work either :(
To the particular "Rule is not safe" error: First of all this has nothing to do with cyclic or acyclic dependencies. The same error message shows up for the non-cyclic program:
foo2(R, 1) :- not foo(R,_), bar(R).
The problem is that the program is actually not safe (http://www.dlvsystem.com/html/DLV_User_Manual.html#SAFETY). As mentioned in the section on negative rules (anchor #AEN375, I am only allowed to use 2 links in my answer):
Variables, which occur in a negated literal, must also occur in a
positive literal in the body.
Observe that the _ is an anonymous variable. I.e., the program
foo(R,1) :- not foo(R,_), bar(R).
can be equivalently written as (and is equivalent to)
foo(R,1) :- not foo(R,X), bar(R).
Anonymous variables (DLV manual, anchor #AEN264 - at the end of the section) just allow us to avoid inventing names for variables that will only occur once within the rule (i.e. for variables that only express "there is some value, I absolutely do not care about it), but they are variables nevertheless. And since negation with not is "negation" and not "true negation" (or "strong negation" as it is also often called), none of the three safety conditions is satisfied by the rule.
A very rough and high-level intuition for safety is that it guarantees that every variable in the program can be assigned to some finite domain - as it is now the case with R by adding bar(R). However, the same also must be the case for the anonymous variable _ .
To the actual problem of defining default values:
As pointed out by lambda.xy.x, the problem here is the Answer Set (or stable model) semantics of DLV: Trying to do it in one rule does not give any solution:
In order to get a safe program, we could replace the above problems e.g. by
foo(1,2). bar(1). bar(2).
tmp(R) :- foo(R,_).
foo(R,1) :- not tmp(R), bar(R).
This has no stable model:
Assume the answer is, as intended,
{foo(1,2), bar(1), bar(2), foo(2,1)}
However, this is not a valid model, since tmp(R) :- foo(R,_) would require it to contain tmp(2). But then, "not tmp(2)" is no longer true, and therefore having foo(2,1) in the model violates the required minimality of the model. (This is not exactly what is going on, more a rough intuition. More technical details could be found in any article on answer set programming, a quick Google search gave me this paper as one of the first results: http://www.kr.tuwien.ac.at/staff/tkren/pub/2009/rw2009-asp.pdf)
In order to solve the problem, it is therefore somehow necessary to "break the cycle". One possibility would be:
foo(1,2). bar(1). bar(2). bar(3).
tmp(R) :- foo(R,X), X!=1.
foo(R,1) :- bar(R), not tmp(R).
I.e., by explicitly stating that we want to add R into the intermediate atom only if the value is different from 1, having foo(2,1) in the model does not contradict tmp(2) not being part of the model as well. Of course, this no longer allows to distinguish whether foo(R,1) is there as default value or by input, but if this is not required ...
Another possibility would be to not use foo for the computation, but some foo1 instead. I.e. having
foo1(R,X) :- foo(R,X).
tmp(R) :- foo(R,_).
foo1(R,1) :- bar(R), not tmp(R).
and then just use foo1 instead of foo.

Elixir: rationale behind allowing rebinding of variables

What is the rationale behind allowing rebinding of variables in Elixir, when Erlang doesn't allow that?
Most functional languages don't allow rebinding of variables in the same scope. So Elixir allowing this does definitely give it an non-functional, imperative feel. Erlang's problem is rather lack of scope, or to be more precise that there is only one scope in a whole function clause. We did have serious discussions whether to introduce scope but in the end we decided against it as it was backwards incompatible with the existing system. And developers hate backwards inconsistent changes.
The Erlang way has one serious benefit: when you get it wrong you generally get an error so you can SEE the mistake. This compared just getting strange behaviour when a variable doesn't have the value you expect it to have which is MUCH harder to detect and correct.
Personally I think that the problem of new variable names, for example using the number scheme, is greatly overblown. Compared to the time it takes me to work out WHAT I am going to do changing variable names is trivial. And after a while you just see it without reflecting about it. Honestly.
EDIT:
Also when chaining data through a sequence of functions the actual meaning of the data changes so reusing the same variable name can be very misleading. It can end up just meaning a generic "data I am passing from one function to another".
Here's the rationale straight from the horse's mouth:
http://blog.plataformatec.com.br/2016/01/comparing-elixir-and-erlang-variables/
Because it's simpler.
Take a look at this question posted to the Erlang mailing list in 2009. Specifically this part:
I like pattern matching in the majority of cases, but I find I write
enough code where I need to incrementally update a data structure, and
maintaining that code is a pain when I have code like:
X = foo(),
X1 = bar(X),
X2 = xyzzy(X1),
blah(X2).
and later want to change it to:
X = foo(),
X1 = whee(X),
X2 = bar(X1),
X3 = xyzzy(X2),
blah(X3).
Editor's note--this is the reply to that question.
This goes through IRC a lot. This is a result of poor variable naming
practice, and there is no need to introduce rebinding to "fix" it;
just stop using single letters and counters as variable names.
If for example that was written
FooStateX = foo(),
PostBarX = bar(FooStateX),
OnceXyzziedX = xyzzy(PostBarX),
blah(OnceXyzziedX).
The code demonstrated there isn't all that uncommon in Erlang (note the remark "this goes through IRC a lot"). Elixir's ability to simply rebind names saves us from having to generate new dummy names for things all the time. That's all. It's wise to bear in mind that the original creators of Erlang weren't trying to build a functional language. They were simply pragmatic developers who had a problem to solve. Elixir's approach is simple pragmatism.

Resources