Technical instructions for exercise 2 from exercise sheet 6
On the website (next to this file) there is a .jar file containing a current version of SMTInterpol. There is also a solver file QuantifierEliminationTQ.java, too. This is the file you should edit. Furthermore there is a test-file with some (very) simple tests -- feel free to write more interesting ones.
To solve this exercise you only need to fill in code in three positions, which are labelled with "fill in here" as well as a description of where you are in the algorithm.
However, feel free to read the whole code, change it if you see room for improvement (there is..).
Having smtinterpol.jar, QuantifierEliminationTQ.java and tests.smt2 in the same directory you can compile it with:
javac -cp smtinterpol.jar QuantifierEliminationTQ.java
and run it with:
java -cp "smtinterpol.jar;." de.uni_freiburg.informatik.ultimate.smtinterpol.Main -script QuantifierEliminationTQ tests.smt2
(under Linux or similar systems you have to replace the semicolon after smtinterpol.jar with a colon (... -cp smtinterpol.jar:. ...))
However, you can also unzip the jar, copy the QuantifierElem.. file into some directory (set the package accordingly) and work with it from Eclipse for example. -- this might be more convenient but should not be necessary.
We implement Quantifier Elimination as a simplification step -- i.e. in the smtlib script you have a line "(simplify formula)" where formula may contain quantifiers. The result will be the formula with the innermost quantifiers eliminated -- it may be several, but when quantifiers are nested, only the innermost ones are eliminated. To eliminate all, we can then just simplify several times (we need to copy/paste the intermediate results, as simplify is a command, not a function..).
Use the logic "LRA" (Linear Real Arithmetic).
starting the smt2 file with (set-option :print-terms-cse false) usually leads to nicer output.
You have to work with the data structures of SMTInterpol, here are the important parts of the API:
(you can also look into the code, of course, it is in the jar, as already mentioned..)
--- Theory, Sorts, Numbers,... ---
A Theory object takes care of building terms, providing sorts and much more, it is referenced by m_theory in our file.
m_theory.term(m_theory.m_Or, Term t1, Term2)
m_theory.or(Term t1, Term2) -- convenience function for "or"
FunctionSymbols represent functions of all kinds (see ApplicationTerm..)
examples:
m_theory.m_Or, m_theory.TRUE, m_theory.Not,...
Sorts are the variable domains. We only use the "Boolean" and "Real" sort (in the SMT context people tend to use Reals and Rationals synonymously)
You can obtain Sort objects from the theory
m_theory.getRealSort()
m_theory.getBooleanSort()
We have a special class for rational (real) numbers called Rational
Constants are for instance Rational.ZERO, Rational.ONE, Rational.MONE (for -1)
--- Types of Terms: ---
for us, pretty much everything is a Term, formulas too, the most interesting ones for you are:
To print a term, use toString(), or - probably more convenient - toStringDirect(), which eliminates most of the lets.
ConstantTerm:
Term representing a number
ApplicationTerm:
Term representing any function application, this may be boolean functions like "or" (Bool, Bool -> Bool), as well as relations like ">" (Real, Real -> Bool), or arithmetic operations like "+" (Real, Real -> Real)
ApplicationTerm at = m_theory.term(String functionsymbol, Terms t...)
= m_theory.term(FunctionSymbol f, Terms t..)
at.getFunction() -- returns a FunctionSymbol
at.getFunction().getName() -- the FunctionSymbol as the String in the script, for example ">", "or", useful for checking which function it is
at.getParameters() -- returns a Term[]
TermVariable:
A variable that is a Term, used for quantification and let, also as placeholder for later substitution
m_theory.createFreshTermVariable("anyNamePrefix", Sort s)
QuantifiedFormula:
.. the name says it all
qf.getQuantifier() -- 0 for exists, 1 for forall
qf.getVariables() -- smtlib allows quantification over several variables at once, we don't use this, so there should be only one
qf.getSubformula() -- the inner formula
m_theory.exists(TermVariable[] ts, Term subformula)
SMTAffineTerm:
self-simplifying, non-nested, linear terms, they are basically a hashmap mapping each variable to its coefficient.
String output does not work when they are nested inside ">"-ApplicationTerms for instance, so convert them back, if you want to debug them
ways to obtain new SMTAffineTerms:
SMTAffineTerm s = SMTAffineTerm.create(Rational r, TermVariable t)
= SMTAffineTerm.create(Rational r, Sort s)
= SMTAffineTerm.create(ConstantTerm t)
s.add(Rational r)
s.add(SMTAffineTerm t)
s.mul(Rational r)
s.div(Rational r)
s.negated() -- returns (-s)
SMTAffineTerm.cleanup(Term t) -- converts all SMTAffineTerms back to normal ApplicationTerms inside t
s.getSummands() -- gives a HashMap from the variables to the coefficients of the SMTAffineTerm
s.isConstant() -- returns true iff the term does not contain any variables
s.getConstant() -- returns the constant summand as a Rational