Click to see the file
Is this file compliant with the SMT2.0 standard? At least, z3 can accpet it. By the way, what's the difference between 'declare-const' and 'declare-fun'? For example, in order to declare a Bool variable I can write declare-const a Bool or declare-fun a() Bool.
I am unable to locate the file you mention in the post, but to answer your question about declare-const:
(declare-const a Bool)
means the same as
(declare-fun a () Bool)
declare-const is not part of standard SMT-LIB2.
It is a command added to Z3 for the convenience of
entering SMT-LIB2 benchmarks manually. You can
always use declare-fun instead to be compatible
across solvers.
While Z3 can process SMT-LIB2 compliant files.
On the other hand, there are several other extensions in Z3's input format
that are not part of SMT-LIB2 standard.
To mention some:
declare-datatypes. Declaration of algebraic datatypes is a Z3 specific extension.
tactics and solvers. Creation, composition and application of tactics is specific to Z3.
declare-rel, declare-var, rule, query. These commands are used by the fixedpoint solver for the convenience of entering benchmarks as Horn formulas.
Related
I would like to model the behaviour of generic datatypes in SMT v2.6. I am using Z3 as constraint solver. I modelled, based on the official example, a generic list as parameterised datatype in the following way:
(declare-datatypes (T) ((MyList nelem (cons (hd T) (tl MyList)))))
I would like the list to be generic with respect to the datatype. Later on, I would like to declare constants the following way:
(declare-const x (MyList Int))
(declare-const y (MyList Real))
However, now I would like to define functions on the generic datatype MyList (e.g., a length operation, empty operation, ...) so that they are re-usable for all T's. Do you have an idea how I could achieve this? I did try something like:
(declare-sort K)
(define-fun isEmpty ((in (MyList K))) Bool
(= in nelem)
)
but this gives me an error message; for this example to work Z3 would need to do some type-inference, I suppose.
Would be great if you could could give me a hint.
SMT-Lib does not allow polymorphic user-defined functions. Section 4.1.5 of http://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.6-r2017-07-18.pdf states:
Well-sortedness checks, required for commands that use sorts or terms,
are always done with respect to the current signature. It is an error
to declare or define a symbol that is already in the current
signature. This implies in particular that, contrary to theory
function symbols, user-defined function symbols cannot be overloaded.
Which is further expanded in Footnote-29:
The motivation for not overloading user-defined symbols is to simplify
their processing by a solver. This restriction is significant only for
users who want to extend the signature of the theory used by a script
with a new polymorphic function symbol—i.e., one whose rank would
contain parametric sorts if it was a theory symbol. For instance,
users who want to declare a “reverse” function on arbitrary lists,
must define a different reverse function symbol for each (concrete)
list sort used in the script. This restriction might be removed in
future versions.
So, as you suspected, you cannot define "polymorphic" functions at the user level. But as the footnote indicates, this restriction might be removed in the future, something that will most likely happen as SMT-solvers are more widely deployed. Exactly when that might happen, however, is anyone's guess.
Using Z3's Horn clause solver:
If the answer is SAT, one can get a satisfying assignment to the unknown predicates (which, in most applications, correspond to inductive invariants of some kind of transition system or procedure call system).
If the answer is unsat, then this means the exists an unfolding of the Horn clauses and an assignment to the universally quantified variables in the Horn clauses such that at least one of the safety conditions (the clauses with a false head) is violated. This constitutes a concrete witness why the system had no solution.
I suspect that if Z3 can conclude unsat, then it has some form of such witness internally (and this anyway is the case in PDR, if I remember well). Is there a way to print it out?
Maybe I badly read the documentation, but I can't find a way. (get-proof) prints something unreadable, and, besides, (set-option :produce-proofs true) makes some problems intractable.
The refutation that Z3 produces for HORN logic problems is in the form of a tree of unit-resulting resolution steps. The counterexample you're looking for is hiding in the conclusions of the unit-resolution steps. These conclusions (the last arguments of the rules) are ground facts that correspond to program states (or procedure summaries or whatever) in the counterexample. The variable bindings that produce these facts can be found in "quant-inst" rules.
Obviously, this is not human readable, and actually is pretty hard to read by machine. For Boogie I implemented a more regular format, but it is currently only available with the duality engine and only for the fixedpoint format using "rule" and "query". You can get this using the following command.
(query :engine duality :print-certificate true)
I have precise and validated descriptions of the behaviors of many X86 instructions in terms amenable to encoding in QF_ABV and solving directly with the standard solver (using no special solving strategies). I wrote an SMT-LIB script whose interface matches my ultimate goal perfectly:
X86State, a record sort describing x86 machine state (registers and flags as bitvectors, and memory as an array).
X86Instr, a record sort describing x86 instructions (enumerated mnemonics, operands as an ML-like discriminated union describing registers, memory expressions, etc.)
A function x86-translate taking an X86State and an X86Instr, and returning a new X86State. It decodes the X86Instr and produces a new X86State in terms of the symbolic effects of the given X86Instr on the input X86State.
It's great for prototyping: the user can write x86 easily and directly. After simplifying a formula built using the library, all functions and extraneous data types are eliminated, leaving a QF_ABV expression. I hoped that users could simply (set-logic QF_ABV) and #include my script (alas, neither the SMT-LIB standard nor Z3 support #include).
Unfortunately, by defining functions and types, the script requires theories such as uninterpreted functions, thus requiring a logic other than QF_ABV (or even QF_AUFBV due to the types). My experience with SMT solvers dictates that the lowest acceptable logic should be specified for best solving time. Also, it is unclear whether I can reuse my SMT-LIB script in a programmatic context (e.g. OCaml, Python, C) as I desire. Finally, the script is a bit verbose given the lack of higher-order functions, and my lack of access to par leading to code duplication.
Thus, despite having accomplished my technical goals, I think that SMT-LIB might be the wrong approach. Is there a more natural avenue for interacting with Z3 to implement my x86 instruction description / QF_ABV translation scheme? Is the SMT-LIB script re-usable at all in these avenues? For example, you can build "custom OCaml top-levels", i.e. interpreters with scripts "burned into them". Something like that could be nice. Or do I have to re-implement the functionality in another language, in a program that interacts with Z3 via a theory extension (C DLL)? What's the best option here?
Well, I don't think that people write .smt2 files by hand. These are usually generated automatically by some program.
I find the Z3 Python interface quite nice, so I guess you could give it a try. But you can always write a simple .smt2 dumper from any language.
BTW, do you plan releasing the specification you wrote for X86? I would be really interested!
In z3 is it possible to declare a function that takes another function as an argument? For instance, this
(declare-fun foo ( ((Int) Bool) ) Int)
doesn't quite seem to work. Thanks.
As Leonardo mentioned, SMT-Lib does not allow higher-order functions. This is not merely a syntactic restriction: Reasoning with higher-order functions is (generally) beyond what SMT solvers can deal with. (Although uninterpreted functions can be used in some special cases.)
If you do need to reason with higher-order functions, then interactive theorem provers are the main weapon of choice: Isabelle, HOL, Coq being some of the examples.
However, sometimes you want the higher-order functions not to reason about them, but rather merely to simplify programming tasks. SMT-Lib input language is not suitable for high-level programming that end-users typically need in practical situations. If that is your use case, then I'd recommend not using SMT-Lib directly, but rather working with a programming language that gives you access to Z3 (or other SMT solvers). There are several choices, depending on what host language is most suitable for your use case:
If you are a Python user, Z3Py that just shipped with Z3 4.0 is the way to go,
If you are a Scala user, then look into Scala^Z3.
If Haskell is your preferred language, then take a look at SBV.
Each binding has its own feature set, Z3Py probably being the most versatile since it's directly supported by the Z3 folks. (It also provides access to Z3 internals that remain inaccessible for the other choices, at least for the time being.)
No, this is not possible. However, you can define a function that takes an array as an argument.
(declare-fun foo ((Array Int Bool)) Int)
You can use this trick to simulate high-order functions like the one in your question.
Here is an example: http://rise4fun.com/Z3/qsED
The Z3 guide contains more information about Z3 and SMT.
I am currently experimenting with Z3 as bounded engine for specifications written in Alloy (a relational logic/language). I am using the UFBV as target language.
I detect a problem using the Z3 option (set-option :pull-nested-quantifiers true).
For two semantically identical SMT specifications Spec1 and Spec2, Z3 times out (200 sec) for proving Spec1 but proves Spec2.
The only different between Spec1 and Spec2 is that they have different function identifiers (because I use java hash names). Can this be related to a bug?
The second observation I would like to share and discuss, is the "iff" operator in the context of UFBV. This operator is not supported, if (set-logic UFBV) is set. My solution was to use "=" instead but this do not work well if the operands contains deeply nested quantifiers and the "pull-nested-quantifiers" is set. The other saver solution is to use double implication.
Now the question:
Is there any other better solution for model "iff" in UFBV, because I think, that using double implication will in general loose maybe useable semantic information for improvement/simplifications.
http://i12www.ira.uka.de/~elghazi/tmp/
you can find: spec1 and spec2 the tow (I think) semantically identical SMT specifications, and spec3 an SMT specification using "=" to model "iff", for which z3 times out.
The default strategy for the UFBV logic is not effective for your problems. Actually, the default strategy solves all of them in less than 1 sec. To force Z3 to use the default strategy, you just need to comment the following lines in your script.
; (set-logic UFBV)
; (set-option :pull-nested-quantifiers true)
; (set-option :macro-finder true)
If the warning messages are bothering you, you can add:
(set-option :print-warning false)
That being said, I will try to address the issues you raised.
Does identifier names affect the behavior of Z3? Yes, they do.
Starting at version 3.0, we started using a total order on Z3 expressions for performing operations such as: sorting the arguments of associative-commutative operators.
This total order is based on the identifier names.
Ironically, this modification was motivated by user feedback. In previous versions, we used an internal ID for performing operations such as sorting, and breaking ties in many different heuristics. However, these IDs are based on the order Z3 creates/deletes expressions, which is based on the order users declare symbols. So, Z3 2.x behavior would be affected by trivial modifications such as removing unused declarations.
Regarding iff, it is not part of SMT-LIB 2.0 standard. In SMT-LIB 2.0, = is used for formulas and terms. To make sure Z3 is fully compliant with the SMT-LIB 2.0 standard, whenever users specify a SMT-LIB supported logic (or soon to be supported such as UFBV), Z3 only "loads" the symbols defined in it. When, a logic is not specified, Z3 assumes the user is using the "Z3 logic" that contains all supported theories in Z3, and many extra aliases such as: iff for Boolean =, if for ite, etc.