Copyright (c) 2015 Microsoft Corporation
--*/
#include<vector>
#include"z3++.h"
using namespace z3;
Demonstration of how Z3 can be used to prove validity of
De Morgan's Duality Law: {e not(x and y) <-> (not x) or ( not y) }
*/
void demorgan() {
std::cout << "de-Morgan example\n";
context c;
expr x = c.bool_const("x");
expr y = c.bool_const("y");
expr conjecture = (!(x && y)) == (!x || !y);
solver s(c);
s.add(!conjecture);
std::cout << s << "\n";
std::cout << s.to_smt2() << "\n";
switch (s.check()) {
case unsat: std::cout << "de-Morgan is valid\n"; break;
case sat: std::cout << "de-Morgan is not valid\n"; break;
case unknown: std::cout << "unknown\n"; break;
}
}
\brief Find a model for <tt>x >= 1 and y < x + 3</tt>.
*/
void find_model_example1() {
std::cout << "find_model_example1\n";
context c;
expr x = c.int_const("x");
expr y = c.int_const("y");
solver s(c);
s.add(x >= 1);
s.add(y < x + 3);
std::cout << s.check() << "\n";
model m = s.get_model();
std::cout << m << "\n";
for (unsigned i = 0; i < m.size(); i++) {
func_decl v = m[i];
assert(v.arity() == 0);
std::cout << v.name() << " = " << m.get_const_interp(v) << "\n";
}
std::cout << "x + y + 1 = " << m.eval(x + y + 1) << "\n";
}
\brief Prove <tt>x = y implies g(x) = g(y)</tt>, and
disprove <tt>x = y implies g(g(x)) = g(y)</tt>.
This function demonstrates how to create uninterpreted types and
functions.
*/
void prove_example1() {
std::cout << "prove_example1\n";
context c;
expr x = c.int_const("x");
expr y = c.int_const("y");
sort I = c.int_sort();
func_decl g = function("g", I, I);
solver s(c);
expr conjecture1 = implies(x == y, g(x) == g(y));
std::cout << "conjecture 1\n" << conjecture1 << "\n";
s.add(!conjecture1);
if (s.check() == unsat)
std::cout << "proved" << "\n";
else
std::cout << "failed to prove" << "\n";
s.reset();
expr conjecture2 = implies(x == y, g(g(x)) == g(y));
std::cout << "conjecture 2\n" << conjecture2 << "\n";
s.add(!conjecture2);
if (s.check() == unsat) {
std::cout << "proved" << "\n";
}
else {
std::cout << "failed to prove" << "\n";
model m = s.get_model();
std::cout << "counterexample:\n" << m << "\n";
std::cout << "g(g(x)) = " << m.eval(g(g(x))) << "\n";
std::cout << "g(y) = " << m.eval(g(y)) << "\n";
}
}
\brief Prove <tt>not(g(g(x) - g(y)) = g(z)), x + z <= y <= x implies z < 0 </tt>.
Then, show that <tt>z < -1</tt> is not implied.
This example demonstrates how to combine uninterpreted functions and arithmetic.
*/
void prove_example2() {
std::cout << "prove_example1\n";
context c;
expr x = c.int_const("x");
expr y = c.int_const("y");
expr z = c.int_const("z");
sort I = c.int_sort();
func_decl g = function("g", I, I);
expr conjecture1 = implies(g(g(x) - g(y)) != g(z) && x + z <= y && y <= x,
z < 0);
solver s(c);
s.add(!conjecture1);
std::cout << "conjecture 1:\n" << conjecture1 << "\n";
if (s.check() == unsat)
std::cout << "proved" << "\n";
else
std::cout << "failed to prove" << "\n";
expr conjecture2 = implies(g(g(x) - g(y)) != g(z) && x + z <= y && y <= x,
z < -1);
s.reset();
s.add(!conjecture2);
std::cout << "conjecture 2:\n" << conjecture2 << "\n";
if (s.check() == unsat) {
std::cout << "proved" << "\n";
}
else {
std::cout << "failed to prove" << "\n";
std::cout << "counterexample:\n" << s.get_model() << "\n";
}
}
\brief Nonlinear arithmetic example 1
*/
void nonlinear_example1() {
std::cout << "nonlinear example 1\n";
config cfg;
cfg.set("auto_config", true);
context c(cfg);
expr x = c.real_const("x");
expr y = c.real_const("y");
expr z = c.real_const("z");
solver s(c);
s.add(x*x + y*y == 1);
s.add(x*x*x + z*z*z < c.real_val("1/2"));
s.add(z != 0);
std::cout << s.check() << "\n";
model m = s.get_model();
std::cout << m << "\n";
set_param("pp.decimal", true);
std::cout << "model in decimal notation\n";
std::cout << m << "\n";
set_param("pp.decimal-precision", 50);
std::cout << "model using 50 decimal places\n";
std::cout << m << "\n";
set_param("pp.decimal", false);
}
\brief Simple function that tries to prove the given conjecture using the following steps:
1- create a solver
2- assert the negation of the conjecture
3- checks if the result is unsat.
*/
void prove(expr conjecture) {
context & c = conjecture.ctx();
solver s(c);
s.add(!conjecture);
std::cout << "conjecture:\n" << conjecture << "\n";
if (s.check() == unsat) {
std::cout << "proved" << "\n";
}
else {
std::cout << "failed to prove" << "\n";
std::cout << "counterexample:\n" << s.get_model() << "\n";
}
}
\brief Simple bit-vector example. This example disproves that x - 10 <= 0 IFF x <= 10 for (32-bit) machine integers
*/
void bitvector_example1() {
std::cout << "bitvector example 1\n";
context c;
expr x = c.bv_const("x", 32);
prove((x - 10 <= 0) == (x <= 10));
prove(ule(x - 10, 0) == ule(x, 10));
expr y = c.bv_const("y", 32);
prove(implies(concat(x, y) == concat(y, x), x == y));
}
\brief Find x and y such that: x ^ y - 103 == x * y
*/
void bitvector_example2() {
std::cout << "bitvector example 2\n";
context c;
expr x = c.bv_const("x", 32);
expr y = c.bv_const("y", 32);
solver s(c);
s.add((x ^ y) - 103 == x * y);
std::cout << s << "\n";
std::cout << s.check() << "\n";
std::cout << s.get_model() << "\n";
}
\brief Mixing C and C++ APIs.
*/
void capi_example() {
std::cout << "capi example\n";
context c;
expr x = c.bv_const("x", 32);
expr y = c.bv_const("y", 32);
expr r = to_expr(c, Z3_mk_bvsrem(c, x, y));
std::cout << "r: " << r << "\n";
}
\brief Demonstrate how to evaluate expressions in a model.
*/
void eval_example1() {
std::cout << "eval example 1\n";
context c;
expr x = c.int_const("x");
expr y = c.int_const("y");
solver s(c);
s.add(x < y);
s.add(x > 2);
std::cout << s.check() << "\n";
model m = s.get_model();
std::cout << "Model:\n" << m << "\n";
std::cout << "x+y = " << m.eval(x+y) << "\n";
}
\brief Several contexts can be used simultaneously.
*/
void two_contexts_example1() {
std::cout << "two contexts example 1\n";
context c1, c2;
expr x = c1.int_const("x");
expr n = x + 1;
expr n1 = to_expr(c2, Z3_translate(c1, n, c2));
std::cout << n1 << "\n";
}
\brief Demonstrates how to catch API usage errors.
*/
void error_example() {
std::cout << "error example\n";
context c;
expr x = c.bool_const("x");
if (Z3_get_error_code(c) != Z3_OK) {
std::cout << "last call failed.\n";
}
try {
expr n = x + 1;
}
catch (exception ex) {
std::cout << "failed: " << ex << "\n";
}
try {
expr arg = to_expr(c, Z3_get_app_arg(c, x, 0));
}
catch (exception ex) {
std::cout << "failed: " << ex << "\n";
}
}
\brief Demonstrate different ways of creating rational numbers: decimal and fractional representations.
*/
void numeral_example() {
std::cout << "numeral example\n";
context c;
expr n1 = c.real_val("1/2");
expr n2 = c.real_val("0.5");
expr n3 = c.real_val(1, 2);
std::cout << n1 << " " << n2 << " " << n3 << "\n";
prove(n1 == n2 && n1 == n3);
n1 = c.real_val("-1/3");
n2 = c.real_val("-0.3333333333333333333333333333333333");
std::cout << n1 << " " << n2 << "\n";
prove(n1 != n2);
}
\brief Test ite-term (if-then-else terms).
*/
void ite_example() {
std::cout << "if-then-else example\n";
context c;
expr f = c.bool_val(false);
expr one = c.int_val(1);
expr zero = c.int_val(0);
expr ite = to_expr(c, Z3_mk_ite(c, f, one, zero));
std::cout << "term: " << ite << "\n";
}
void ite_example2() {
std::cout << "if-then-else example2\n";
context c;
expr b = c.bool_const("b");
expr x = c.int_const("x");
expr y = c.int_const("y");
std::cout << (ite(b, x, y) > 0) << "\n";
}
\brief Small example using quantifiers.
*/
void quantifier_example() {
std::cout << "quantifier example\n";
context c;
expr x = c.int_const("x");
expr y = c.int_const("y");
sort I = c.int_sort();
func_decl f = function("f", I, I, I);
solver s(c);
params p(c);
p.set("mbqi", true);
s.set(p);
s.add(forall(x, y, f(x, y) >= 0));
expr a = c.int_const("a");
s.add(f(a, a) < a);
std::cout << s << "\n";
std::cout << s.check() << "\n";
std::cout << s.get_model() << "\n";
s.add(a < 0);
std::cout << s.check() << "\n";
}
\brief Unsat core example
*/
void unsat_core_example1() {
std::cout << "unsat core example1\n";
context c;
expr p1 = c.bool_const("p1");
expr p2 = c.bool_const("p2");
expr p3 = c.bool_const("p3");
expr x = c.int_const("x");
expr y = c.int_const("y");
solver s(c);
s.add(implies(p1, x > 10));
s.add(implies(p1, y > x));
s.add(implies(p2, y < 5));
s.add(implies(p3, y > 0));
expr assumptions[3] = { p1, p2, p3 };
std::cout << s.check(3, assumptions) << "\n";
expr_vector core = s.unsat_core();
std::cout << core << "\n";
std::cout << "size: " << core.size() << "\n";
for (unsigned i = 0; i < core.size(); i++) {
std::cout << core[i] << "\n";
}
expr assumptions2[2] = { p1, p3 };
std::cout << s.check(2, assumptions2) << "\n";
}
\brief Unsat core example 2
*/
void unsat_core_example2() {
std::cout << "unsat core example 2\n";
context c;
expr p1 = c.bool_const("p1");
expr x = c.int_const("x");
expr y = c.int_const("y");
solver s(c);
expr F = x > 10 && y > x && y < 5 && y > 0;
s.add(implies(p1, F));
expr assumptions[1] = { p1 };
std::cout << s.check(1, assumptions) << "\n";
expr_vector core = s.unsat_core();
std::cout << core << "\n";
std::cout << "size: " << core.size() << "\n";
for (unsigned i = 0; i < core.size(); i++) {
std::cout << core[i] << "\n";
}
std::vector<expr> qs;
assert(F.is_app());
if (F.decl().decl_kind() == Z3_OP_AND) {
std::cout << "F num. args (before simplify): " << F.num_args() << "\n";
F = F.simplify();
std::cout << "F num. args (after simplify): " << F.num_args() << "\n";
for (unsigned i = 0; i < F.num_args(); i++) {
std::cout << "Creating answer literal q" << i << " for " << F.arg(i) << "\n";
std::stringstream qname; qname << "q" << i;
expr qi = c.bool_const(qname.str().c_str());
s.add(implies(qi, F.arg(i)));
qs.push_back(qi);
}
}
qs.push_back(!p1);
std::cout << s.check(static_cast<unsigned>(qs.size()), &qs[0]) << "\n";
expr_vector core2 = s.unsat_core();
std::cout << core2 << "\n";
std::cout << "size: " << core2.size() << "\n";
for (unsigned i = 0; i < core2.size(); i++) {
std::cout << core2[i] << "\n";
}
}
\brief Unsat core example 3
*/
void unsat_core_example3() {
std::cout << "unsat core example 3\n";
context c;
expr x = c.int_const("x");
expr y = c.int_const("y");
solver s(c);
params p(c);
p.set("unsat_core", true);
s.set(p);
s.add(x > 0);
s.add(y > 0, "p1");
s.add(x < 10, "p2");
s.add(y < 0, "p3");
std::cout << s.check() << "\n";
std::cout << s.unsat_core() << "\n";
}
void tactic_example1() {
Z3 implements a methodology for orchestrating reasoning engines where "big" symbolic
reasoning steps are represented as functions known as tactics, and tactics are composed
using combinators known as tacticals. Tactics process sets of formulas called Goals.
When a tactic is applied to some goal G, four different outcomes are possible. The tactic succeeds
in showing G to be satisfiable (i.e., feasible); succeeds in showing G to be unsatisfiable (i.e., infeasible);
produces a sequence of subgoals; or fails. When reducing a goal G to a sequence of subgoals G1, ..., Gn,
we face the problem of model conversion. A model converter construct a model for G using a model for some subgoal Gi.
In this example, we create a goal g consisting of three formulas, and a tactic t composed of two built-in tactics:
simplify and solve-eqs. The tactic simplify apply transformations equivalent to the ones found in the command simplify.
The tactic solver-eqs eliminate variables using Gaussian elimination. Actually, solve-eqs is not restricted
only to linear arithmetic. It can also eliminate arbitrary variables.
Then, sequential composition combinator & applies simplify to the input goal and solve-eqs to each subgoal produced by simplify.
In this example, only one subgoal is produced.
*/
std::cout << "tactic example 1\n";
context c;
expr x = c.real_const("x");
expr y = c.real_const("y");
goal g(c);
g.add(x > 0);
g.add(y > 0);
g.add(x == y + 2);
std::cout << g << "\n";
tactic t1(c, "simplify");
tactic t2(c, "solve-eqs");
tactic t = t1 & t2;
apply_result r = t(g);
std::cout << r << "\n";
}
void tactic_example2() {
In Z3, we say a clause is any constraint of the form (f_1 || ... || f_n).
The tactic split-clause will select a clause in the input goal, and split it n subgoals.
One for each subformula f_i.
*/
std::cout << "tactic example 2\n";
context c;
expr x = c.real_const("x");
expr y = c.real_const("y");
goal g(c);
g.add(x < 0 || x > 0);
g.add(x == y + 1);
g.add(y < 0);
tactic t(c, "split-clause");
apply_result r = t(g);
for (unsigned i = 0; i < r.size(); i++) {
std::cout << "subgoal " << i << "\n" << r[i] << "\n";
}
}
void tactic_example3() {
- The choice combinator t | s first applies t to the given goal, if it fails then returns the result of s applied to the given goal.
- repeat(t) Keep applying the given tactic until no subgoal is modified by it.
- repeat(t, n) Keep applying the given tactic until no subgoal is modified by it, or the number of iterations is greater than n.
- try_for(t, ms) Apply tactic t to the input goal, if it does not return in ms milliseconds, it fails.
- with(t, params) Apply the given tactic using the given parameters.
*/
std::cout << "tactic example 3\n";
context c;
expr x = c.real_const("x");
expr y = c.real_const("y");
expr z = c.real_const("z");
goal g(c);
g.add(x == 0 || x == 1);
g.add(y == 0 || y == 1);
g.add(z == 0 || z == 1);
g.add(x + y + z > 2);
tactic split_all = repeat(tactic(c, "split-clause") | tactic(c, "skip"));
std::cout << split_all(g) << "\n";
tactic split_at_most_2 = repeat(tactic(c, "split-clause") | tactic(c, "skip"), 1);
std::cout << split_at_most_2(g) << "\n";
tactic split_solve = split_all & tactic(c, "solve-eqs");
std::cout << split_solve(g) << "\n";
}
void tactic_example4() {
A tactic can be converted into a solver object using the method mk_solver().
If the tactic produces the empty goal, then the associated solver returns sat.
If the tactic produces a single goal containing False, then the solver returns unsat.
Otherwise, it returns unknown.
In this example, the tactic t implements a basic bit-vector solver using equation solving,
bit-blasting, and a propositional SAT solver.
We use the combinator `with` to configure our little solver.
We also include the tactic `aig` which tries to compress Boolean formulas using And-Inverted Graphs.
*/
std::cout << "tactic example 4\n";
context c;
params p(c);
p.set("mul2concat", true);
tactic t =
with(tactic(c, "simplify"), p) &
tactic(c, "solve-eqs") &
tactic(c, "bit-blast") &
tactic(c, "aig") &
tactic(c, "sat");
solver s = t.mk_solver();
expr x = c.bv_const("x", 16);
expr y = c.bv_const("y", 16);
s.add(x*32 + y == 13);
s.add((x & y) < 10);
s.add(y > -100);
std::cout << s.check() << "\n";
model m = s.get_model();
std::cout << m << "\n";
std::cout << "x*32 + y = " << m.eval(x*32 + y) << "\n";
std::cout << "x & y = " << m.eval(x & y) << "\n";
}
void tactic_example5() {
The tactic smt wraps the main solver in Z3 as a tactic.
*/
std::cout << "tactic example 5\n";
context c;
expr x = c.int_const("x");
expr y = c.int_const("y");
solver s = tactic(c, "smt").mk_solver();
s.add(x > y + 1);
std::cout << s.check() << "\n";
std::cout << s.get_model() << "\n";
}
void tactic_example6() {
In this example, we show how to implement a solver for integer arithmetic using SAT.
The solver is complete only for problems where every variable has a lower and upper bound.
*/
std::cout << "tactic example 6\n";
context c;
params p(c);
p.set("arith_lhs", true);
p.set("som", true);
solver s =
(with(tactic(c, "simplify"), p) &
tactic(c, "normalize-bounds") &
tactic(c, "lia2pb") &
tactic(c, "pb2bv") &
tactic(c, "bit-blast") &
tactic(c, "sat")).mk_solver();
expr x = c.int_const("x");
expr y = c.int_const("y");
expr z = c.int_const("z");
s.add(x > 0 && x < 10);
s.add(y > 0 && y < 10);
s.add(z > 0 && z < 10);
s.add(3*y + 2*x == z);
std::cout << s.check() << "\n";
std::cout << s.get_model() << "\n";
s.reset();
s.add(3*y + 2*x == z);
std::cout << s.check() << "\n";
}
void tactic_example7() {
Tactics can be combined with solvers.
For example, we can apply a tactic to a goal, produced a set of subgoals,
then select one of the subgoals and solve it using a solver.
This example demonstrates how to do that, and
how to use model converters to convert a model for a subgoal into a model for the original goal.
*/
std::cout << "tactic example 7\n";
context c;
tactic t =
tactic(c, "simplify") &
tactic(c, "normalize-bounds") &
tactic(c, "solve-eqs");
expr x = c.int_const("x");
expr y = c.int_const("y");
expr z = c.int_const("z");
goal g(c);
g.add(x > 10);
g.add(y == x + 3);
g.add(z > y);
apply_result r = t(g);
std::cout << r << "\n";
solver s(c);
goal subgoal = r[0];
for (unsigned i = 0; i < subgoal.size(); i++) {
s.add(subgoal[i]);
}
std::cout << s.check() << "\n";
model m = s.get_model();
std::cout << "model for subgoal:\n" << m << "\n";
std::cout << "model for original goal:\n" << subgoal.convert_model(m) << "\n";
}
void tactic_example8() {
Probes (aka formula measures) are evaluated over goals.
Boolean expressions over them can be built using relational operators and Boolean connectives.
The tactic fail_if(cond) fails if the given goal does not satisfy the condition cond.
Many numeric and Boolean measures are available in Z3.
In this example, we build a simple tactic using fail_if.
It also shows that a probe can be applied directly to a goal.
*/
std::cout << "tactic example 8\n";
context c;
expr x = c.int_const("x");
expr y = c.int_const("y");
expr z = c.int_const("z");
goal g(c);
g.add(x + y + z > 0);
probe p(c, "num-consts");
std::cout << "num-consts: " << p(g) << "\n";
tactic t = fail_if(p > 2);
try {
t(g);
}
catch (exception) {
std::cout << "tactic failed...\n";
}
std::cout << "trying again...\n";
g.reset();
g.add(x + y > 0);
std::cout << t(g) << "\n";
}
void tactic_example9() {
The combinator (tactical) cond(p, t1, t2) is a shorthand for:
(fail_if(p) & t1) | t2
The combinator when(p, t) is a shorthand for:
cond(p, t, tactic(c, "skip"))
The tactic skip just returns the input goal.
This example demonstrates how to use the cond combinator.
*/
std::cout << "tactic example 9\n";
context c;
expr x = c.int_const("x");
expr y = c.int_const("y");
expr z = c.int_const("z");
goal g(c);
g.add(x*x - y*y >= 0);
probe p(c, "num-consts");
tactic t = cond(p > 2, tactic(c, "simplify"), tactic(c, "factor"));
std::cout << t(g) << "\n";
g.reset();
g.add(x + x + y + z >= 0);
g.add(x*x - y*y >= 0);
std::cout << t(g) << "\n";
}
void tactic_qe() {
std::cout << "tactic example using quantifier elimination\n";
context c;
solver s =
(tactic(c, "qe") &
tactic(c, "smt")).mk_solver();
expr a = c.int_const("a");
expr b = c.int_const("b");
expr x = c.int_const("x");
expr f = implies(x <= a, x < b);
expr qf = forall(x, f);
std::cout << qf << "\n";
s.add(qf);
std::cout << s.check() << "\n";
std::cout << s.get_model() << "\n";
}
void visit(std::vector<bool>& visited, expr const & e) {
if (visited.size() <= e.id()) {
visited.resize(e.id()+1, false);
}
if (visited[e.id()]) {
return;
}
visited[e.id()] = true;
if (e.is_app()) {
unsigned num = e.num_args();
for (unsigned i = 0; i < num; i++) {
visit(visited, e.arg(i));
}
func_decl f = e.decl();
std::cout << "application of " << f.name() << ": " << e << "\n";
}
else if (e.is_quantifier()) {
visit(visited, e.body());
}
else {
assert(e.is_var());
}
}
void tst_visit() {
std::cout << "visit example\n";
context c;
expr x = c.int_const("x");
expr y = c.int_const("y");
expr z = c.int_const("z");
expr f = x*x + x*x - y*y >= 0;
std::vector<bool> visited;
visit(visited, f);
}
void tst_numeral() {
std::cout << "numeral example\n";
context c;
expr x = c.real_val("1/3");
double d = 0;
if (!x.is_numeral(d)) {
std::cout << x << " is not recognized as a numeral\n";
return;
}
std::cout << x << " is " << d << "\n";
}
void incremental_example1() {
std::cout << "incremental example1\n";
context c;
expr x = c.int_const("x");
solver s(c);
s.add(x > 0);
std::cout << s.check() << "\n";
s.add(x < 0);
std::cout << s.check() << "\n";
}
void incremental_example2() {
std::cout << "incremental example2\n";
context c;
expr x = c.int_const("x");
solver s(c);
s.add(x > 0);
std::cout << s.check() << "\n";
s.push();
s.add(x < 0);
std::cout << s.check() << "\n";
s.pop();
std::cout << s.check() << "\n";
std::cout << s << "\n";
}
void incremental_example3() {
std::cout << "incremental example3\n";
context c;
expr x = c.int_const("x");
solver s(c);
s.add(x > 0);
std::cout << s.check() << "\n";
expr b = c.bool_const("b");
s.add(implies(b, x < 0));
expr_vector a1(c);
a1.push_back(b);
std::cout << s.check(a1) << "\n";
std::cout << s.check() << "\n";
expr_vector a2(c);
a2.push_back(!b);
std::cout << s.check(a2) << "\n";
}
void enum_sort_example() {
std::cout << "enumeration sort example\n";
context ctx;
const char * enum_names[] = { "a", "b", "c" };
func_decl_vector enum_consts(ctx);
func_decl_vector enum_testers(ctx);
sort s = ctx.enumeration_sort("enumT", 3, enum_names, enum_consts, enum_testers);
expr a = enum_consts[0]();
expr b = enum_consts[1]();
expr x = ctx.constant("x", s);
expr test = (x==a) && (x==b);
std::cout << "1: " << test << std::endl;
tactic qe(ctx, "ctx-solver-simplify");
goal g(ctx);
g.add(test);
expr res(ctx);
apply_result result_of_elimination = qe.apply(g);
goal result_goal = result_of_elimination[0];
std::cout << "2: " << result_goal.as_expr() << std::endl;
}
void tuple_example() {
std::cout << "tuple example\n";
context ctx;
const char * names[] = { "first", "second" };
sort sorts[2] = { ctx.int_sort(), ctx.bool_sort() };
func_decl_vector projs(ctx);
func_decl pair = ctx.tuple_sort("pair", 2, names, sorts, projs);
sorts[1] = pair.range();
func_decl pair2 = ctx.tuple_sort("pair2", 2, names, sorts, projs);
std::cout << pair2 << "\n";
}
void expr_vector_example() {
std::cout << "expr_vector example\n";
context c;
const unsigned N = 10;
expr_vector x(c);
for (unsigned i = 0; i < N; i++) {
std::stringstream x_name;
x_name << "x_" << i;
x.push_back(c.int_const(x_name.str().c_str()));
}
solver s(c);
for (unsigned i = 0; i < N; i++) {
s.add(x[i] >= 1);
}
std::cout << s << "\n" << "solving...\n" << s.check() << "\n";
model m = s.get_model();
std::cout << "solution\n" << m;
}
void exists_expr_vector_example() {
std::cout << "exists expr_vector example\n";
context c;
const unsigned N = 10;
expr_vector xs(c);
expr x(c);
expr b(c);
b = c.bool_val(true);
for (unsigned i = 0; i < N; i++) {
std::stringstream x_name;
x_name << "x_" << i;
x = c.int_const(x_name.str().c_str());
xs.push_back(x);
b = b && x >= 0;
}
expr ex(c);
ex = exists(xs, b);
std::cout << ex << std::endl;
}
void substitute_example() {
std::cout << "substitute example\n";
context c;
expr x(c);
x = c.int_const("x");
expr f(c);
f = (x == 2) || (x == 1);
std::cout << f << std::endl;
expr two(c), three(c);
two = c.int_val(2);
three = c.int_val(3);
Z3_ast from[] = { two };
Z3_ast to[] = { three };
expr new_f(c);
new_f = to_expr(c, Z3_substitute(c, f, 1, from, to));
std::cout << new_f << std::endl;
}
void opt_example() {
context c;
optimize opt(c);
params p(c);
p.set("priority",c.str_symbol("pareto"));
opt.set(p);
expr x = c.int_const("x");
expr y = c.int_const("y");
opt.add(10 >= x && x >= 0);
opt.add(10 >= y && y >= 0);
opt.add(x + y <= 11);
optimize::handle h1 = opt.maximize(x);
optimize::handle h2 = opt.maximize(y);
while (true) {
if (sat == opt.check()) {
std::cout << x << ": " << opt.lower(h1) << " " << y << ": " << opt.lower(h2) << "\n";
}
else {
break;
}
}
}
* translate from one optimization context to another.
*/
void opt_translate_example() {
context c1, c2;
optimize o1(c1);
expr x = c1.int_const("x");
expr y = c1.int_const("y");
o1.add(10 >= x && x >= 0);
o1.add(10 >= y && y >= 0);
o1.add(x + y <= 11);
optimize::handle h1 = o1.maximize(x);
optimize::handle h2 = o1.maximize(y);
(void)h1;
(void)h2;
optimize o2(c2, o1);
expr z = c2.int_const("z");
expr x2 = c2.int_const("x");
o2.add(x2 + z == 2);
o2.minimize(z);
std::cout << o2 << "\n";
}
void extract_example() {
std::cout << "extract example\n";
context c;
expr x(c);
x = c.constant("x", c.bv_sort(32));
expr y = x.extract(21, 10);
std::cout << y << " " << y.hi() << " " << y.lo() << "\n";
}
void sudoku_example() {
std::cout << "sudoku example\n";
context c;
expr_vector x(c);
for (unsigned i = 0; i < 9; ++i)
for (unsigned j = 0; j < 9; ++j) {
std::stringstream x_name;
x_name << "x_" << i << '_' << j;
x.push_back(c.int_const(x_name.str().c_str()));
}
solver s(c);
for (unsigned i = 0; i < 9; ++i)
for (unsigned j = 0; j < 9; ++j) {
s.add(x[i * 9 + j] >= 1 && x[i * 9 + j] <= 9);
}
for (unsigned i = 0; i < 9; ++i) {
expr_vector t(c);
for (unsigned j = 0; j < 9; ++j)
t.push_back(x[i * 9 + j]);
s.add(distinct(t));
}
for (unsigned j = 0; j < 9; ++j) {
expr_vector t(c);
for (unsigned i = 0; i < 9; ++i)
t.push_back(x[i * 9 + j]);
s.add(distinct(t));
}
for (unsigned i0 = 0; i0 < 3; i0++) {
for (unsigned j0 = 0; j0 < 3; j0++) {
expr_vector t(c);
for (unsigned i = 0; i < 3; i++)
for (unsigned j = 0; j < 3; j++)
t.push_back(x[(i0 * 3 + i) * 9 + j0 * 3 + j]);
s.add(distinct(t));
}
}
int instance[9][9] = {{0,0,0,0,9,4,0,3,0},
{0,0,0,5,1,0,0,0,7},
{0,8,9,0,0,0,0,4,0},
{0,0,0,0,0,0,2,0,8},
{0,6,0,2,0,1,0,5,0},
{1,0,2,0,0,0,0,0,0},
{0,7,0,0,0,0,5,2,0},
{9,0,0,0,6,5,0,0,0},
{0,4,0,9,7,0,0,0,0}};
for (unsigned i = 0; i < 9; i++)
for (unsigned j = 0; j < 9; j++)
if (instance[i][j] != 0)
s.add(x[i * 9 + j] == instance[i][j]);
std::cout << s.check() << std::endl;
std::cout << s << std::endl;
model m = s.get_model();
for (unsigned i = 0; i < 9; ++i) {
for (unsigned j = 0; j < 9; ++j)
std::cout << m.eval(x[i * 9 + j]);
std::cout << '\n';
}
}
void param_descrs_example() {
std::cout << "parameter description example\n";
context c;
param_descrs p = param_descrs::simplify_param_descrs(c);
std::cout << p << "\n";
unsigned sz = p.size();
for (unsigned i = 0; i < sz; ++i) {
symbol nm = p.name(i);
char const* kind = "other";
Z3_param_kind k = p.kind(nm);
if (k == Z3_PK_UINT) kind = "uint";
if (k == Z3_PK_BOOL) kind = "bool";
std::cout << nm << ": " << p.documentation(nm) << " kind: " << kind << "\n";
}
}
void consequence_example() {
std::cout << "consequence example\n";
context c;
expr A = c.bool_const("a");
expr B = c.bool_const("b");
expr C = c.bool_const("c");
solver s(c);
s.add(implies(A, B));
s.add(implies(B, C));
expr_vector assumptions(c), vars(c), consequences(c);
assumptions.push_back(!C);
vars.push_back(A);
vars.push_back(B);
vars.push_back(C);
std::cout << s.consequences(assumptions, vars, consequences) << "\n";
std::cout << consequences << "\n";
}
static void parse_example() {
std::cout << "parse example\n";
context c;
sort_vector sorts(c);
func_decl_vector decls(c);
sort B = c.bool_sort();
decls.push_back(c.function("a", 0, 0, B));
expr_vector a = c.parse_string("(assert a)", sorts, decls);
std::cout << a << "\n";
}
static void parse_string() {
std::cout << "parse string\n";
z3::context c;
z3::solver s(c);
s.from_string("(declare-const x Int)(assert (> x 10))");
std::cout << s.check() << "\n";
}
void mk_model_example() {
context c;
model m(c);
expr a = c.int_const("a");
expr b = c.int_const("b");
func_decl a_decl = a.decl();
func_decl b_decl = b.decl();
expr zero_numeral = c.int_val(0);
expr one_numeral = c.int_val(1);
m.add_const_interp(a_decl, zero_numeral);
m.add_const_interp(b_decl, one_numeral);
std::cout << m.eval(a + b < 2)<< std::endl;
}
void recfun_example() {
std::cout << "recfun example\n";
context c;
expr x = c.int_const("x");
expr y = c.int_const("y");
expr b = c.bool_const("b");
sort I = c.int_sort();
sort B = c.bool_sort();
func_decl f = recfun("f", I, B, I);
expr_vector args(c);
args.push_back(x); args.push_back(b);
c.recdef(f, args, ite(b, x, f(x + 1, !b)));
prove(f(x,c.bool_val(false)) > x);
}
static void string_values() {
context c;
expr s = c.string_val("abc\n\n\0\0", 7);
std::cout << s << "\n";
std::string s1 = s.get_string();
std::cout << s1 << "\n";
}
expr MakeStringConstant(context* context, std::string value) {
return context->string_val(value.c_str());
}
expr MakeStringFunction(context* c, std::string s) {
sort sort = c->string_sort();
symbol name = c->str_symbol(s.c_str());
return c->constant(name, sort);
}
static void string_issue_2298() {
context c;
solver s(c);
s.push();
expr func1 = MakeStringFunction(&c, "func1");
expr func2 = MakeStringFunction(&c, "func2");
expr abc = MakeStringConstant(&c, "abc");
expr cde = MakeStringConstant(&c, "cde");
expr length = func1.length();
expr five = c.int_val(5);
s.add(func2 == abc || func1 == cde);
s.add(func2 == abc || func2 == cde);
s.add(length <= five);
s.check();
s.pop();
}
int main() {
try {
demorgan(); std::cout << "\n";
find_model_example1(); std::cout << "\n";
prove_example1(); std::cout << "\n";
prove_example2(); std::cout << "\n";
nonlinear_example1(); std::cout << "\n";
bitvector_example1(); std::cout << "\n";
bitvector_example2(); std::cout << "\n";
capi_example(); std::cout << "\n";
eval_example1(); std::cout << "\n";
two_contexts_example1(); std::cout << "\n";
error_example(); std::cout << "\n";
numeral_example(); std::cout << "\n";
ite_example(); std::cout << "\n";
ite_example2(); std::cout << "\n";
quantifier_example(); std::cout << "\n";
unsat_core_example1(); std::cout << "\n";
unsat_core_example2(); std::cout << "\n";
unsat_core_example3(); std::cout << "\n";
tactic_example1(); std::cout << "\n";
tactic_example2(); std::cout << "\n";
tactic_example3(); std::cout << "\n";
tactic_example4(); std::cout << "\n";
tactic_example5(); std::cout << "\n";
tactic_example6(); std::cout << "\n";
tactic_example7(); std::cout << "\n";
tactic_example8(); std::cout << "\n";
tactic_example9(); std::cout << "\n";
tactic_qe(); std::cout << "\n";
tst_visit(); std::cout << "\n";
tst_numeral(); std::cout << "\n";
incremental_example1(); std::cout << "\n";
incremental_example2(); std::cout << "\n";
incremental_example3(); std::cout << "\n";
enum_sort_example(); std::cout << "\n";
tuple_example(); std::cout << "\n";
expr_vector_example(); std::cout << "\n";
exists_expr_vector_example(); std::cout << "\n";
substitute_example(); std::cout << "\n";
opt_example(); std::cout << "\n";
opt_translate_example(); std::cout << "\n";
extract_example(); std::cout << "\n";
param_descrs_example(); std::cout << "\n";
sudoku_example(); std::cout << "\n";
consequence_example(); std::cout << "\n";
parse_example(); std::cout << "\n";
parse_string(); std::cout << "\n";
mk_model_example(); std::cout << "\n";
recfun_example(); std::cout << "\n";
string_values(); std::cout << "\n";
string_issue_2298(); std::cout << "\n";
std::cout << "done\n";
}
catch (exception & ex) {
std::cout << "unexpected error: " << ex << "\n";
}
Z3_finalize_memory();
return 0;
}