3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-10-10 01:41:57 +00:00
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2012-12-10 14:07:59 -08:00
commit 265bdbe757
76 changed files with 3991 additions and 1422 deletions

422
src/api/api_algebraic.cpp Normal file
View file

@ -0,0 +1,422 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
api_algebraic.cpp
Abstract:
Additional APIs for handling Z3 algebraic numbers encoded as
Z3_ASTs
Author:
Leonardo de Moura (leonardo) 2012-12-07
Notes:
--*/
#include<iostream>
#include"z3.h"
#include"api_log_macros.h"
#include"api_context.h"
#include"api_ast_vector.h"
#include"algebraic_numbers.h"
#include"expr2polynomial.h"
#include"cancel_eh.h"
#include"scoped_timer.h"
#define CHECK_IS_ALGEBRAIC(ARG, RET) { \
if (!Z3_algebraic_is_value_core(c, ARG)) { \
SET_ERROR_CODE(Z3_INVALID_ARG); \
return RET; \
} \
}
#define CHECK_IS_ALGEBRAIC_X(ARG, RET) { \
if (!Z3_algebraic_is_value_core(c, ARG)) { \
SET_ERROR_CODE(Z3_INVALID_ARG); \
RETURN_Z3(RET); \
} \
}
static arith_util & au(Z3_context c) {
return mk_c(c)->autil();
}
static algebraic_numbers::manager & am(Z3_context c) {
return au(c).am();
}
static bool is_rational(Z3_context c, Z3_ast a) {
return au(c).is_numeral(to_expr(a));
}
static bool is_irrational(Z3_context c, Z3_ast a) {
return au(c).is_irrational_algebraic_numeral(to_expr(a));
}
static rational get_rational(Z3_context c, Z3_ast a) {
SASSERT(is_rational(c, a));
rational r;
VERIFY(au(c).is_numeral(to_expr(a), r));
return r;
}
static algebraic_numbers::anum const & get_irrational(Z3_context c, Z3_ast a) {
SASSERT(is_irrational(c, a));
return au(c).to_irrational_algebraic_numeral(to_expr(a));
}
extern "C" {
bool Z3_algebraic_is_value_core(Z3_context c, Z3_ast a) {
api::context * _c = mk_c(c);
return
is_expr(a) &&
(_c->autil().is_numeral(to_expr(a)) ||
_c->autil().is_irrational_algebraic_numeral(to_expr(a)));
}
Z3_bool Z3_API Z3_algebraic_is_value(Z3_context c, Z3_ast a) {
Z3_TRY;
LOG_Z3_algebraic_is_value(c, a);
RESET_ERROR_CODE();
return Z3_algebraic_is_value_core(c, a) ? Z3_TRUE : Z3_FALSE;
Z3_CATCH_RETURN(Z3_FALSE);
}
Z3_bool Z3_API Z3_algebraic_is_pos(Z3_context c, Z3_ast a) {
return Z3_algebraic_sign(c, a) > 0;
}
Z3_bool Z3_API Z3_algebraic_is_neg(Z3_context c, Z3_ast a) {
return Z3_algebraic_sign(c, a) < 0;
}
Z3_bool Z3_API Z3_algebraic_is_zero(Z3_context c, Z3_ast a) {
return Z3_algebraic_sign(c, a) == 0;
}
int Z3_API Z3_algebraic_sign(Z3_context c, Z3_ast a) {
Z3_TRY;
LOG_Z3_algebraic_sign(c, a);
RESET_ERROR_CODE();
CHECK_IS_ALGEBRAIC(a, 0);
if (is_rational(c, a)) {
rational v = get_rational(c, a);
if (v.is_pos()) return 1;
else if (v.is_neg()) return -1;
else return 0;
}
else {
algebraic_numbers::anum const & v = get_irrational(c, a);
if (am(c).is_pos(v)) return 1;
else if (am(c).is_neg(v)) return -1;
else return 0;
}
Z3_CATCH_RETURN(0);
}
#define BIN_OP(RAT_OP, IRAT_OP) \
algebraic_numbers::manager & _am = am(c); \
ast * r = 0; \
if (is_rational(c, a)) { \
rational av = get_rational(c, a); \
if (is_rational(c, b)) { \
rational bv = get_rational(c, b); \
r = au(c).mk_numeral(av RAT_OP bv, false); \
} \
else { \
algebraic_numbers::anum const & bv = get_irrational(c, b); \
scoped_anum _av(_am); \
_am.set(_av, av.to_mpq()); \
scoped_anum _r(_am); \
_am.IRAT_OP(_av, bv, _r); \
r = au(c).mk_numeral(_r, false); \
} \
} \
else { \
algebraic_numbers::anum const & av = get_irrational(c, a); \
if (is_rational(c, b)) { \
rational bv = get_rational(c, b); \
scoped_anum _bv(_am); \
_am.set(_bv, bv.to_mpq()); \
scoped_anum _r(_am); \
_am.IRAT_OP(av, _bv, _r); \
r = au(c).mk_numeral(_r, false); \
} \
else { \
algebraic_numbers::anum const & bv = get_irrational(c, b); \
scoped_anum _r(_am); \
_am.IRAT_OP(av, bv, _r); \
r = au(c).mk_numeral(_r, false); \
} \
} \
mk_c(c)->save_ast_trail(r); \
RETURN_Z3(of_ast(r));
Z3_ast Z3_API Z3_algebraic_add(Z3_context c, Z3_ast a, Z3_ast b) {
Z3_TRY;
LOG_Z3_algebraic_add(c, a, b);
RESET_ERROR_CODE();
CHECK_IS_ALGEBRAIC_X(a, 0);
CHECK_IS_ALGEBRAIC_X(b, 0);
BIN_OP(+,add);
Z3_CATCH_RETURN(0);
}
Z3_ast Z3_API Z3_algebraic_sub(Z3_context c, Z3_ast a, Z3_ast b) {
Z3_TRY;
LOG_Z3_algebraic_sub(c, a, b);
RESET_ERROR_CODE();
CHECK_IS_ALGEBRAIC_X(a, 0);
CHECK_IS_ALGEBRAIC_X(b, 0);
BIN_OP(-,sub);
Z3_CATCH_RETURN(0);
}
Z3_ast Z3_API Z3_algebraic_mul(Z3_context c, Z3_ast a, Z3_ast b) {
Z3_TRY;
LOG_Z3_algebraic_mul(c, a, b);
RESET_ERROR_CODE();
CHECK_IS_ALGEBRAIC_X(a, 0);
CHECK_IS_ALGEBRAIC_X(b, 0);
BIN_OP(*,mul);
Z3_CATCH_RETURN(0);
}
Z3_ast Z3_API Z3_algebraic_div(Z3_context c, Z3_ast a, Z3_ast b) {
Z3_TRY;
LOG_Z3_algebraic_div(c, a, b);
RESET_ERROR_CODE();
CHECK_IS_ALGEBRAIC_X(a, 0);
CHECK_IS_ALGEBRAIC_X(b, 0);
if ((is_rational(c, b) && get_rational(c, b).is_zero()) ||
(!is_rational(c, b) && am(c).is_zero(get_irrational(c, b)))) {
SET_ERROR_CODE(Z3_INVALID_ARG);
RETURN_Z3(0);
}
BIN_OP(/,div);
Z3_CATCH_RETURN(0);
}
Z3_ast Z3_API Z3_algebraic_root(Z3_context c, Z3_ast a, unsigned k) {
Z3_TRY;
LOG_Z3_algebraic_root(c, a, k);
RESET_ERROR_CODE();
CHECK_IS_ALGEBRAIC_X(a, 0);
if (k % 2 == 0) {
if ((is_rational(c, a) && get_rational(c, a).is_neg()) ||
(!is_rational(c, a) && am(c).is_neg(get_irrational(c, a)))) {
SET_ERROR_CODE(Z3_INVALID_ARG);
RETURN_Z3(0);
}
}
algebraic_numbers::manager & _am = am(c);
scoped_anum _r(_am);
if (is_rational(c, a)) {
scoped_anum av(_am);
_am.set(av, get_rational(c, a).to_mpq());
_am.root(av, k, _r);
}
else {
algebraic_numbers::anum const & av = get_irrational(c, a);
_am.root(av, k, _r);
}
expr * r = au(c).mk_numeral(_r, false);
mk_c(c)->save_ast_trail(r);
RETURN_Z3(of_ast(r));
Z3_CATCH_RETURN(0);
}
Z3_ast Z3_API Z3_algebraic_power(Z3_context c, Z3_ast a, unsigned k) {
Z3_TRY;
LOG_Z3_algebraic_power(c, a, k);
RESET_ERROR_CODE();
CHECK_IS_ALGEBRAIC_X(a, 0);
algebraic_numbers::manager & _am = am(c);
scoped_anum _r(_am);
if (is_rational(c, a)) {
scoped_anum av(_am);
_am.set(av, get_rational(c, a).to_mpq());
_am.power(av, k, _r);
}
else {
algebraic_numbers::anum const & av = get_irrational(c, a);
_am.power(av, k, _r);
}
expr * r = au(c).mk_numeral(_r, false);
mk_c(c)->save_ast_trail(r);
RETURN_Z3(of_ast(r));
Z3_CATCH_RETURN(0);
}
#define BIN_PRED(RAT_PRED, IRAT_PRED) \
algebraic_numbers::manager & _am = am(c); \
bool r; \
if (is_rational(c, a)) { \
rational av = get_rational(c, a); \
if (is_rational(c, b)) { \
rational bv = get_rational(c, b); \
r = av RAT_PRED bv; \
} \
else { \
algebraic_numbers::anum const & bv = get_irrational(c, b); \
scoped_anum _av(_am); \
_am.set(_av, av.to_mpq()); \
r = _am.IRAT_PRED(_av, bv); \
} \
} \
else { \
algebraic_numbers::anum const & av = get_irrational(c, a); \
if (is_rational(c, b)) { \
rational bv = get_rational(c, b); \
scoped_anum _bv(_am); \
_am.set(_bv, bv.to_mpq()); \
r = _am.IRAT_PRED(av, _bv); \
} \
else { \
algebraic_numbers::anum const & bv = get_irrational(c, b); \
r = _am.IRAT_PRED(av, bv); \
} \
} \
return r ? Z3_TRUE : Z3_FALSE;
Z3_bool Z3_API Z3_algebraic_lt(Z3_context c, Z3_ast a, Z3_ast b) {
Z3_TRY;
LOG_Z3_algebraic_lt(c, a, b);
RESET_ERROR_CODE();
CHECK_IS_ALGEBRAIC(a, 0);
CHECK_IS_ALGEBRAIC(b, 0);
BIN_PRED(<,lt);
Z3_CATCH_RETURN(Z3_FALSE);
}
Z3_bool Z3_API Z3_algebraic_gt(Z3_context c, Z3_ast a, Z3_ast b) {
return Z3_algebraic_lt(c, b, a);
}
Z3_bool Z3_API Z3_algebraic_le(Z3_context c, Z3_ast a, Z3_ast b) {
return !Z3_algebraic_lt(c, b, a);
}
Z3_bool Z3_API Z3_algebraic_ge(Z3_context c, Z3_ast a, Z3_ast b) {
return !Z3_algebraic_lt(c, a, b);
}
Z3_bool Z3_API Z3_algebraic_eq(Z3_context c, Z3_ast a, Z3_ast b) {
Z3_TRY;
LOG_Z3_algebraic_eq(c, a, b);
RESET_ERROR_CODE();
CHECK_IS_ALGEBRAIC(a, 0);
CHECK_IS_ALGEBRAIC(b, 0);
BIN_PRED(==,eq);
Z3_CATCH_RETURN(0);
}
Z3_bool Z3_API Z3_algebraic_neq(Z3_context c, Z3_ast a, Z3_ast b) {
return !Z3_algebraic_eq(c, a, b);
}
static bool to_anum_vector(Z3_context c, unsigned n, Z3_ast a[], scoped_anum_vector & as) {
algebraic_numbers::manager & _am = am(c);
scoped_anum tmp(_am);
for (unsigned i = 0; i < n; i++) {
if (is_rational(c, a[i])) {
_am.set(tmp, get_rational(c, a[i]).to_mpq());
as.push_back(tmp);
}
else if (is_irrational(c, a[i])) {
as.push_back(get_irrational(c, a[i]));
}
else {
return false;
}
}
return true;
}
class vector_var2anum : public polynomial::var2anum {
scoped_anum_vector const & m_as;
public:
vector_var2anum(scoped_anum_vector & as):m_as(as) {}
virtual ~vector_var2anum() {}
virtual algebraic_numbers::manager & m() const { return m_as.m(); }
virtual bool contains(polynomial::var x) const { return static_cast<unsigned>(x) < m_as.size(); }
virtual algebraic_numbers::anum const & operator()(polynomial::var x) const { return m_as.get(x); }
};
Z3_ast_vector Z3_API Z3_algebraic_roots(Z3_context c, Z3_ast p, unsigned n, Z3_ast a[]) {
Z3_TRY;
LOG_Z3_algebraic_roots(c, p, n, a);
RESET_ERROR_CODE();
polynomial::manager & pm = mk_c(c)->pm();
polynomial_ref _p(pm);
polynomial::scoped_numeral d(pm.m());
expr2polynomial converter(mk_c(c)->m(), pm, 0, true);
if (!converter.to_polynomial(to_expr(p), _p, d) ||
static_cast<unsigned>(max_var(_p)) >= n + 1) {
SET_ERROR_CODE(Z3_INVALID_ARG);
return 0;
}
algebraic_numbers::manager & _am = am(c);
scoped_anum_vector as(_am);
if (!to_anum_vector(c, n, a, as)) {
SET_ERROR_CODE(Z3_INVALID_ARG);
return 0;
}
scoped_anum_vector roots(_am);
{
cancel_eh<algebraic_numbers::manager> eh(_am);
api::context::set_interruptable(*(mk_c(c)), eh);
scoped_timer timer(mk_c(c)->params().m_timeout, &eh);
vector_var2anum v2a(as);
_am.isolate_roots(_p, v2a, roots);
}
Z3_ast_vector_ref* result = alloc(Z3_ast_vector_ref, mk_c(c)->m());
mk_c(c)->save_object(result);
for (unsigned i = 0; i < roots.size(); i++) {
result->m_ast_vector.push_back(au(c).mk_numeral(roots.get(i), false));
}
RETURN_Z3(of_ast_vector(result));
Z3_CATCH_RETURN(0);
}
int Z3_API Z3_algebraic_eval(Z3_context c, Z3_ast p, unsigned n, Z3_ast a[]) {
Z3_TRY;
LOG_Z3_algebraic_eval(c, p, n, a);
RESET_ERROR_CODE();
polynomial::manager & pm = mk_c(c)->pm();
polynomial_ref _p(pm);
polynomial::scoped_numeral d(pm.m());
expr2polynomial converter(mk_c(c)->m(), pm, 0, true);
if (!converter.to_polynomial(to_expr(p), _p, d) ||
static_cast<unsigned>(max_var(_p)) >= n) {
SET_ERROR_CODE(Z3_INVALID_ARG);
return 0;
}
algebraic_numbers::manager & _am = am(c);
scoped_anum_vector as(_am);
if (!to_anum_vector(c, n, a, as)) {
SET_ERROR_CODE(Z3_INVALID_ARG);
return 0;
}
{
cancel_eh<algebraic_numbers::manager> eh(_am);
api::context::set_interruptable(*(mk_c(c)), eh);
scoped_timer timer(mk_c(c)->params().m_timeout, &eh);
vector_var2anum v2a(as);
int r = _am.eval_sign_at(_p, v2a);
if (r > 0) return 1;
else if (r < 0) return -1;
else return 0;
}
Z3_CATCH_RETURN(0);
}
};

View file

@ -324,7 +324,8 @@ extern "C" {
switch (_a->get_kind()) {
case AST_APP: {
expr * e = to_expr(_a);
if (is_numeral_sort(c, of_sort(mk_c(c)->m().get_sort(e))) && mk_c(c)->m().is_value(e))
// Real algebraic numbers are not considered Z3_NUMERAL_AST
if (is_numeral_sort(c, of_sort(mk_c(c)->m().get_sort(e))) && mk_c(c)->m().is_unique_value(e))
return Z3_NUMERAL_AST;
return Z3_APP_AST;
}

View file

@ -82,13 +82,13 @@ namespace api {
context::context(context_params * p, bool user_ref_count):
m_params(p != 0 ? *p : context_params()),
m_user_ref_count(user_ref_count),
m_manager(m_params.m_proof ? PGM_FINE : PGM_DISABLED, m_params.m_trace ? m_params.m_trace_file_name.c_str() : 0),
m_plugins(m_manager),
m_arith_util(m_manager),
m_bv_util(m_manager),
m_datalog_util(m_manager),
m_last_result(m_manager),
m_ast_trail(m_manager),
m_manager(m_params.mk_ast_manager()),
m_plugins(m()),
m_arith_util(m()),
m_bv_util(m()),
m_datalog_util(m()),
m_last_result(m()),
m_ast_trail(m()),
m_replay_stack() {
m_solver = 0;
@ -102,22 +102,16 @@ namespace api {
m_smtlib_parser_has_decls = false;
z3_bound_num_procs();
//
// Configuration parameter settings.
//
if (m_params.m_debug_ref_count) {
m_manager.debug_ref_count();
}
m_error_handler = &default_error_handler;
m_basic_fid = m_manager.get_basic_family_id();
m_arith_fid = m_manager.get_family_id("arith");
m_bv_fid = m_manager.get_family_id("bv");
m_array_fid = m_manager.get_family_id("array");
m_dt_fid = m_manager.get_family_id("datatype");
m_datalog_fid = m_manager.get_family_id("datalog_relation");
m_dt_plugin = static_cast<datatype_decl_plugin*>(m_manager.get_plugin(m_dt_fid));
m_basic_fid = m().get_basic_family_id();
m_arith_fid = m().get_family_id("arith");
m_bv_fid = m().get_family_id("bv");
m_array_fid = m().get_family_id("array");
m_dt_fid = m().get_family_id("datatype");
m_datalog_fid = m().get_family_id("datalog_relation");
m_dt_plugin = static_cast<datatype_decl_plugin*>(m().get_plugin(m_dt_fid));
if (!m_user_ref_count) {
m_replay_stack.push_back(0);
@ -143,6 +137,7 @@ namespace api {
{
if (m_interruptable)
(*m_interruptable)();
m().set_cancel(true);
}
}
@ -195,12 +190,12 @@ namespace api {
expr * context::mk_and(unsigned num_exprs, expr * const * exprs) {
switch(num_exprs) {
case 0:
return m_manager.mk_true();
return m().mk_true();
case 1:
save_ast_trail(exprs[0]);
return exprs[0];
default: {
expr * a = m_manager.mk_and(num_exprs, exprs);
expr * a = m().mk_and(num_exprs, exprs);
save_ast_trail(a);
return a;
} }
@ -216,7 +211,7 @@ namespace api {
SASSERT(m_replay_stack.size() > num_scopes);
unsigned j = m_replay_stack.size() - num_scopes - 1;
if (!m_replay_stack[j]) {
m_replay_stack[j] = alloc(ast_ref_vector, m_manager);
m_replay_stack[j] = alloc(ast_ref_vector, m());
}
m_replay_stack[j]->push_back(n);
}
@ -324,7 +319,7 @@ namespace api {
smt::kernel & context::get_smt_kernel() {
if (!m_solver) {
m_fparams.updt_params(m_params);
m_solver = alloc(smt::kernel, m_manager, m_fparams);
m_solver = alloc(smt::kernel, m(), m_fparams);
}
return *m_solver;
}

View file

@ -32,6 +32,7 @@ Revision History:
#include"event_handler.h"
#include"tactic_manager.h"
#include"context_params.h"
#include"api_polynomial.h"
namespace smtlib {
class parser;
@ -45,7 +46,7 @@ namespace api {
struct add_plugins { add_plugins(ast_manager & m); };
context_params m_params;
bool m_user_ref_count; //!< if true, the user is responsible for managing referenc counters.
ast_manager m_manager;
scoped_ptr<ast_manager> m_manager;
add_plugins m_plugins;
arith_util m_arith_util;
@ -81,6 +82,8 @@ namespace api {
Z3_ast_print_mode m_print_mode;
event_handler * m_interruptable; // Reference to an object that can be interrupted by Z3_interrupt
pmanager m_pmanager;
public:
// Scoped obj for setting m_interruptable
class set_interruptable {
@ -98,10 +101,10 @@ namespace api {
context(context_params * p, bool user_ref_count = false);
~context();
ast_manager & m() { return m_manager; }
ast_manager & m() const { return *(m_manager.get()); }
context_params & params() { return m_params; }
bool produce_proofs() const { return m_manager.proofs_enabled(); }
bool produce_proofs() const { return m().proofs_enabled(); }
bool produce_models() const { return m_params.m_model; }
bool produce_unsat_cores() const { return m_params.m_unsat_core; }
bool use_auto_config() const { return m_params.m_auto_config; }
@ -167,6 +170,13 @@ namespace api {
void check_sorts(ast * n);
// ------------------------
//
// Polynomial manager & caches
//
// -----------------------
polynomial::manager & pm() { return m_pmanager.pm(); }
// ------------------------
//
// Solver interface for backward compatibility

View file

@ -0,0 +1,84 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
api_polynomial.cpp
Abstract:
Polynomial manager and caches for the external API.
Author:
Leonardo de Moura (leonardo) 2012-12-08
Notes:
--*/
#include<iostream>
#include"z3.h"
#include"api_log_macros.h"
#include"api_context.h"
#include"api_polynomial.h"
#include"api_ast_vector.h"
#include"expr2polynomial.h"
#include"cancel_eh.h"
#include"scoped_timer.h"
#include"expr2var.h"
namespace api {
pmanager::pmanager():
m_pm(m_nm) {
}
pmanager::~pmanager() {
}
void pmanager::set_cancel(bool f) {
m_pm.set_cancel(f);
}
};
extern "C" {
Z3_ast_vector Z3_API Z3_polynomial_subresultants(Z3_context c, Z3_ast p, Z3_ast q, Z3_ast x) {
Z3_TRY;
LOG_Z3_polynomial_subresultants(c, p, q, x);
RESET_ERROR_CODE();
polynomial::manager & pm = mk_c(c)->pm();
polynomial_ref _p(pm), _q(pm);
polynomial::scoped_numeral d(pm.m());
default_expr2polynomial converter(mk_c(c)->m(), pm);
if (!converter.to_polynomial(to_expr(p), _p, d) ||
!converter.to_polynomial(to_expr(q), _q, d)) {
SET_ERROR_CODE(Z3_INVALID_ARG);
return 0;
}
Z3_ast_vector_ref* result = alloc(Z3_ast_vector_ref, mk_c(c)->m());
mk_c(c)->save_object(result);
if (converter.is_var(to_expr(x))) {
expr2var const & mapping = converter.get_mapping();
unsigned v_x = mapping.to_var(to_expr(x));
polynomial_ref_vector rs(pm);
polynomial_ref r(pm);
expr_ref _r(mk_c(c)->m());
{
cancel_eh<polynomial::manager> eh(pm);
api::context::set_interruptable(*(mk_c(c)), eh);
scoped_timer timer(mk_c(c)->params().m_timeout, &eh);
pm.psc_chain(_p, _q, v_x, rs);
}
for (unsigned i = 0; i < rs.size(); i++) {
r = rs.get(i);
converter.to_expr(r, true, _r);
result->m_ast_vector.push_back(_r);
}
}
RETURN_Z3(of_ast_vector(result));
Z3_CATCH_RETURN(0);
}
};

39
src/api/api_polynomial.h Normal file
View file

@ -0,0 +1,39 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
api_polynomial.h
Abstract:
Polynomial manager and caches for the external API.
Author:
Leonardo de Moura (leonardo) 2012-12-08
Notes:
--*/
#ifndef _API_POLYNOMIAL_H_
#define _API_POLYNOMIAL_H_
#include"polynomial.h"
namespace api {
class pmanager {
unsynch_mpz_manager m_nm;
polynomial::manager m_pm;
// TODO: add support for caching expressions -> polynomial and back
public:
pmanager();
virtual ~pmanager();
polynomial::manager & pm() { return m_pm; }
void set_cancel(bool f);
};
};
#endif

View file

@ -36,17 +36,7 @@ extern "C" {
static void init_solver_core(Z3_context c, Z3_solver _s) {
ast_manager & m = mk_c(c)->m();
Z3_solver_ref * s = to_solver(_s);
s->m_solver->set_produce_proofs(mk_c(c)->produce_proofs());
s->m_solver->set_produce_unsat_cores(s->m_params.get_bool("unsat_core", mk_c(c)->produce_unsat_cores()));
s->m_solver->set_produce_models(s->m_params.get_bool("model", mk_c(c)->produce_models()));
if (!mk_c(c)->use_auto_config()) {
params_ref p = s->m_params;
p.set_bool("auto_config", false);
s->m_solver->updt_params(p);
}
else {
s->m_solver->updt_params(s->m_params);
}
mk_c(c)->params().init_solver_params(mk_c(c)->m(), *(s->m_solver), s->m_params);
s->m_solver->init(m, s->m_logic);
s->m_initialized = true;
}

View file

@ -1,4 +1,3 @@
Java bindings
-------------
This is currently "working in progress".

View file

@ -1126,6 +1126,27 @@ def Var(idx, s):
_z3_assert(is_sort(s), "Z3 sort expected")
return _to_expr_ref(Z3_mk_bound(s.ctx_ref(), idx, s.ast), s.ctx)
def RealVar(idx, ctx=None):
"""
Create a real free variable. Free variables are used to create quantified formulas.
They are also used to create polynomials.
>>> RealVar(0)
Var(0)
"""
return Var(idx, RealSort(ctx))
def RealVarVector(n, ctx=None):
"""
Create a list of Real free variables.
The variables have ids: 0, 1, ..., n-1
>>> x0, x1, x2, x3 = RealVarVector(4)
>>> x2
Var(2)
"""
return [ RealVar(i, ctx) for i in range(n) ]
#########################################
#
# Booleans

564
src/api/python/z3num.py Normal file
View file

@ -0,0 +1,564 @@
############################################
# Copyright (c) 2012 Microsoft Corporation
#
# Z3 Python interface for Z3 numerals
#
# Author: Leonardo de Moura (leonardo)
############################################
from z3 import *
from z3core import *
from z3printer import *
def _to_numeral(num, ctx=None):
if isinstance(num, Numeral):
return num
else:
return Numeral(num, ctx)
class Numeral:
"""
A Z3 numeral can be used to perform computations over arbitrary
precision integers, rationals and real algebraic numbers.
It also automatically converts python numeric values.
>>> Numeral(2)
2
>>> Numeral("3/2") + 1
5/2
>>> Numeral(Sqrt(2))
1.4142135623?
>>> Numeral(Sqrt(2)) + 2
3.4142135623?
>>> Numeral(Sqrt(2)) + Numeral(Sqrt(3))
3.1462643699?
Z3 numerals can be used to perform computations with
values in a Z3 model.
>>> s = Solver()
>>> x = Real('x')
>>> s.add(x*x == 2)
>>> s.add(x > 0)
>>> s.check()
sat
>>> m = s.model()
>>> m[x]
1.4142135623?
>>> m[x] + 1
1.4142135623? + 1
The previous result is a Z3 expression.
>>> (m[x] + 1).sexpr()
'(+ (root-obj (+ (^ x 2) (- 2)) 2) 1.0)'
>>> Numeral(m[x]) + 1
2.4142135623?
>>> Numeral(m[x]).is_pos()
True
>>> Numeral(m[x])**2
2
We can also isolate the roots of polynomials.
>>> x0, x1, x2 = RealVarVector(3)
>>> r0 = isolate_roots(x0**5 - x0 - 1)
>>> r0
[1.1673039782?]
In the following example, we are isolating the roots
of a univariate polynomial (on x1) obtained after substituting
x0 -> r0[0]
>>> r1 = isolate_roots(x1**2 - x0 + 1, [ r0[0] ])
>>> r1
[-0.4090280898?, 0.4090280898?]
Similarly, in the next example we isolate the roots of
a univariate polynomial (on x2) obtained after substituting
x0 -> r0[0] and x1 -> r1[0]
>>> isolate_roots(x1*x2 + x0, [ r0[0], r1[0] ])
[2.8538479564?]
"""
def __init__(self, num, ctx=None):
if isinstance(num, Ast):
self.ast = num
self.ctx = z3._get_ctx(ctx)
elif isinstance(num, RatNumRef) or isinstance(num, AlgebraicNumRef):
self.ast = num.ast
self.ctx = num.ctx
elif isinstance(num, ArithRef):
r = simplify(num)
self.ast = r.ast
self.ctx = r.ctx
else:
v = RealVal(num, ctx)
self.ast = v.ast
self.ctx = v.ctx
Z3_inc_ref(self.ctx_ref(), self.as_ast())
assert Z3_algebraic_is_value(self.ctx_ref(), self.ast)
def __del__(self):
Z3_dec_ref(self.ctx_ref(), self.as_ast())
def is_integer(self):
""" Return True if the numeral is integer.
>>> Numeral(2).is_integer()
True
>>> (Numeral(Sqrt(2)) * Numeral(Sqrt(2))).is_integer()
True
>>> Numeral(Sqrt(2)).is_integer()
False
>>> Numeral("2/3").is_integer()
False
"""
return self.is_rational() and self.denominator() == 1
def is_rational(self):
""" Return True if the numeral is rational.
>>> Numeral(2).is_rational()
True
>>> Numeral("2/3").is_rational()
True
>>> Numeral(Sqrt(2)).is_rational()
False
"""
return Z3_get_ast_kind(self.ctx_ref(), self.as_ast()) == Z3_NUMERAL_AST
def denominator(self):
""" Return the denominator if `self` is rational.
>>> Numeral("2/3").denominator()
3
"""
assert(self.is_rational())
return Numeral(Z3_get_denominator(self.ctx_ref(), self.as_ast()), self.ctx)
def numerator(self):
""" Return the numerator if `self` is rational.
>>> Numeral("2/3").numerator()
2
"""
assert(self.is_rational())
return Numeral(Z3_get_numerator(self.ctx_ref(), self.as_ast()), self.ctx)
def is_irrational(self):
""" Return True if the numeral is irrational.
>>> Numeral(2).is_irrational()
False
>>> Numeral("2/3").is_irrational()
False
>>> Numeral(Sqrt(2)).is_irrational()
True
"""
return not self.is_rational()
def as_long(self):
""" Return a numeral (that is an integer) as a Python long.
>>> (Numeral(10)**20).as_long()
100000000000000000000L
"""
assert(self.is_integer())
return long(Z3_get_numeral_string(self.ctx_ref(), self.as_ast()))
def approx(self, precision=10):
"""Return a numeral that approximates the numeral `self`.
The result `r` is such that |r - self| <= 1/10^precision
If `self` is rational, then the result is `self`.
>>> x = Numeral(2).root(2)
>>> x.approx(20)
6838717160008073720548335/4835703278458516698824704
>>> x.approx(5)
2965821/2097152
>>> Numeral(2).approx(10)
2
"""
return self.upper(precision)
def upper(self, precision=10):
"""Return a upper bound that approximates the numeral `self`.
The result `r` is such that r - self <= 1/10^precision
If `self` is rational, then the result is `self`.
>>> x = Numeral(2).root(2)
>>> x.upper(20)
6838717160008073720548335/4835703278458516698824704
>>> x.upper(5)
2965821/2097152
>>> Numeral(2).upper(10)
2
"""
if self.is_rational():
return self
else:
return Numeral(Z3_get_algebraic_number_upper(self.ctx_ref(), self.as_ast(), precision), self.ctx)
def lower(self, precision=10):
"""Return a lower bound that approximates the numeral `self`.
The result `r` is such that self - r <= 1/10^precision
If `self` is rational, then the result is `self`.
>>> x = Numeral(2).root(2)
>>> x.lower(20)
1709679290002018430137083/1208925819614629174706176
>>> Numeral("2/3").lower(10)
2/3
"""
if self.is_rational():
return self
else:
return Numeral(Z3_get_algebraic_number_lower(self.ctx_ref(), self.as_ast(), precision), self.ctx)
def sign(self):
""" Return the sign of the numeral.
>>> Numeral(2).sign()
1
>>> Numeral(-3).sign()
-1
>>> Numeral(0).sign()
0
"""
return Z3_algebraic_sign(self.ctx_ref(), self.ast)
def is_pos(self):
""" Return True if the numeral is positive.
>>> Numeral(2).is_pos()
True
>>> Numeral(-3).is_pos()
False
>>> Numeral(0).is_pos()
False
"""
return Z3_algebraic_is_pos(self.ctx_ref(), self.ast)
def is_neg(self):
""" Return True if the numeral is negative.
>>> Numeral(2).is_neg()
False
>>> Numeral(-3).is_neg()
True
>>> Numeral(0).is_neg()
False
"""
return Z3_algebraic_is_neg(self.ctx_ref(), self.ast)
def is_zero(self):
""" Return True if the numeral is zero.
>>> Numeral(2).is_zero()
False
>>> Numeral(-3).is_zero()
False
>>> Numeral(0).is_zero()
True
>>> sqrt2 = Numeral(2).root(2)
>>> sqrt2.is_zero()
False
>>> (sqrt2 - sqrt2).is_zero()
True
"""
return Z3_algebraic_is_zero(self.ctx_ref(), self.ast)
def __add__(self, other):
""" Return the numeral `self + other`.
>>> Numeral(2) + 3
5
>>> Numeral(2) + Numeral(4)
6
>>> Numeral("2/3") + 1
5/3
"""
return Numeral(Z3_algebraic_add(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast), self.ctx)
def __radd__(self, other):
""" Return the numeral `other + self`.
>>> 3 + Numeral(2)
5
"""
return Numeral(Z3_algebraic_add(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast), self.ctx)
def __sub__(self, other):
""" Return the numeral `self - other`.
>>> Numeral(2) - 3
-1
"""
return Numeral(Z3_algebraic_sub(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast), self.ctx)
def __rsub__(self, other):
""" Return the numeral `other - self`.
>>> 3 - Numeral(2)
1
"""
return Numeral(Z3_algebraic_sub(self.ctx_ref(), _to_numeral(other, self.ctx).ast, self.ast), self.ctx)
def __mul__(self, other):
""" Return the numeral `self * other`.
>>> Numeral(2) * 3
6
"""
return Numeral(Z3_algebraic_mul(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast), self.ctx)
def __rmul__(self, other):
""" Return the numeral `other * mul`.
>>> 3 * Numeral(2)
6
"""
return Numeral(Z3_algebraic_mul(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast), self.ctx)
def __div__(self, other):
""" Return the numeral `self / other`.
>>> Numeral(2) / 3
2/3
>>> Numeral(2).root(2) / 3
0.4714045207?
>>> Numeral(Sqrt(2)) / Numeral(Sqrt(3))
0.8164965809?
"""
return Numeral(Z3_algebraic_div(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast), self.ctx)
def __rdiv__(self, other):
""" Return the numeral `other / self`.
>>> 3 / Numeral(2)
3/2
>>> 3 / Numeral(2).root(2)
2.1213203435?
"""
return Numeral(Z3_algebraic_div(self.ctx_ref(), _to_numeral(other, self.ctx).ast, self.ast), self.ctx)
def root(self, k):
""" Return the numeral `self^(1/k)`.
>>> sqrt2 = Numeral(2).root(2)
>>> sqrt2
1.4142135623?
>>> sqrt2 * sqrt2
2
>>> sqrt2 * 2 + 1
3.8284271247?
>>> (sqrt2 * 2 + 1).sexpr()
'(root-obj (+ (^ x 2) (* (- 2) x) (- 7)) 2)'
"""
return Numeral(Z3_algebraic_root(self.ctx_ref(), self.ast, k), self.ctx)
def power(self, k):
""" Return the numeral `self^k`.
>>> sqrt3 = Numeral(3).root(2)
>>> sqrt3
1.7320508075?
>>> sqrt3.power(2)
3
"""
return Numeral(Z3_algebraic_power(self.ctx_ref(), self.ast, k), self.ctx)
def __pow__(self, k):
""" Return the numeral `self^k`.
>>> sqrt3 = Numeral(3).root(2)
>>> sqrt3
1.7320508075?
>>> sqrt3**2
3
"""
return self.power(k)
def __lt__(self, other):
""" Return True if `self < other`.
>>> Numeral(Sqrt(2)) < 2
True
>>> Numeral(Sqrt(3)) < Numeral(Sqrt(2))
False
>>> Numeral(Sqrt(2)) < Numeral(Sqrt(2))
False
"""
return Z3_algebraic_lt(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast)
def __rlt__(self, other):
""" Return True if `other < self`.
>>> 2 < Numeral(Sqrt(2))
False
"""
return self > other
def __gt__(self, other):
""" Return True if `self > other`.
>>> Numeral(Sqrt(2)) > 2
False
>>> Numeral(Sqrt(3)) > Numeral(Sqrt(2))
True
>>> Numeral(Sqrt(2)) > Numeral(Sqrt(2))
False
"""
return Z3_algebraic_gt(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast)
def __rgt__(self, other):
""" Return True if `other > self`.
>>> 2 > Numeral(Sqrt(2))
True
"""
return self < other
def __le__(self, other):
""" Return True if `self <= other`.
>>> Numeral(Sqrt(2)) <= 2
True
>>> Numeral(Sqrt(3)) <= Numeral(Sqrt(2))
False
>>> Numeral(Sqrt(2)) <= Numeral(Sqrt(2))
True
"""
return Z3_algebraic_le(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast)
def __rle__(self, other):
""" Return True if `other <= self`.
>>> 2 <= Numeral(Sqrt(2))
False
"""
return self >= other
def __ge__(self, other):
""" Return True if `self >= other`.
>>> Numeral(Sqrt(2)) >= 2
False
>>> Numeral(Sqrt(3)) >= Numeral(Sqrt(2))
True
>>> Numeral(Sqrt(2)) >= Numeral(Sqrt(2))
True
"""
return Z3_algebraic_ge(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast)
def __rge__(self, other):
""" Return True if `other >= self`.
>>> 2 >= Numeral(Sqrt(2))
True
"""
return self <= other
def __eq__(self, other):
""" Return True if `self == other`.
>>> Numeral(Sqrt(2)) == 2
False
>>> Numeral(Sqrt(3)) == Numeral(Sqrt(2))
False
>>> Numeral(Sqrt(2)) == Numeral(Sqrt(2))
True
"""
return Z3_algebraic_eq(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast)
def __ne__(self, other):
""" Return True if `self != other`.
>>> Numeral(Sqrt(2)) != 2
True
>>> Numeral(Sqrt(3)) != Numeral(Sqrt(2))
True
>>> Numeral(Sqrt(2)) != Numeral(Sqrt(2))
False
"""
return Z3_algebraic_neq(self.ctx_ref(), self.ast, _to_numeral(other, self.ctx).ast)
def __str__(self):
if Z3_is_numeral_ast(self.ctx_ref(), self.ast):
return str(RatNumRef(self.ast, self.ctx))
else:
return str(AlgebraicNumRef(self.ast, self.ctx))
def __repr__(self):
return self.__str__()
def sexpr(self):
return Z3_ast_to_string(self.ctx_ref(), self.as_ast())
def as_ast(self):
return self.ast
def ctx_ref(self):
return self.ctx.ref()
def eval_sign_at(p, vs):
"""
Evaluate the sign of the polynomial `p` at `vs`. `p` is a Z3
Expression containing arithmetic operators: +, -, *, ^k where k is
an integer; and free variables x that is_var(x) is True. Moreover,
all variables must be real.
The result is 1 if the polynomial is positive at the given point,
-1 if negative, and 0 if zero.
>>> x0, x1, x2 = RealVarVector(3)
>>> eval_sign_at(x0**2 + x1*x2 + 1, (Numeral(0), Numeral(1), Numeral(2)))
1
>>> eval_sign_at(x0**2 - 2, [ Numeral(Sqrt(2)) ])
0
>>> eval_sign_at((x0 + x1)*(x0 + x2), (Numeral(0), Numeral(Sqrt(2)), Numeral(Sqrt(3))))
1
"""
num = len(vs)
_vs = (Ast * num)()
for i in range(num):
_vs[i] = vs[i].ast
return Z3_algebraic_eval(p.ctx_ref(), p.as_ast(), num, _vs)
def isolate_roots(p, vs=[]):
"""
Given a multivariate polynomial p(x_0, ..., x_{n-1}, x_n), returns the
roots of the univariate polynomial p(vs[0], ..., vs[len(vs)-1], x_n).
Remarks:
* p is a Z3 expression that contains only arithmetic terms and free variables.
* forall i in [0, n) vs is a numeral.
The result is a list of numerals
>>> x0 = RealVar(0)
>>> isolate_roots(x0**5 - x0 - 1)
[1.1673039782?]
>>> x1 = RealVar(1)
>>> isolate_roots(x0**2 - x1**4 - 1, [ Numeral(Sqrt(3)) ])
[-1.1892071150?, 1.1892071150?]
>>> x2 = RealVar(2)
>>> isolate_roots(x2**2 + x0 - x1, [ Numeral(Sqrt(3)), Numeral(Sqrt(2)) ])
[]
"""
num = len(vs)
_vs = (Ast * num)()
for i in range(num):
_vs[i] = vs[i].ast
_roots = AstVector(Z3_algebraic_roots(p.ctx_ref(), p.as_ast(), num, _vs), p.ctx)
return [ Numeral(r) for r in _roots ]
if __name__ == "__main__":
import doctest
if doctest.testmod().failed:
exit(1)

37
src/api/python/z3poly.py Normal file
View file

@ -0,0 +1,37 @@
############################################
# Copyright (c) 2012 Microsoft Corporation
#
# Z3 Python interface for Z3 polynomials
#
# Author: Leonardo de Moura (leonardo)
############################################
from z3 import *
def subresultants(p, q, x):
"""
Return the non-constant subresultants of 'p' and 'q' with respect to the "variable" 'x'.
'p', 'q' and 'x' are Z3 expressions where 'p' and 'q' are arithmetic terms.
Note that, any subterm that cannot be viewed as a polynomial is assumed to be a variable.
Example: f(a) is a considered to be a variable b in the polynomial
f(a)*f(a) + 2*f(a) + 1
>>> x, y = Reals('x y')
>>> subresultants(2*x + y, 3*x - 2*y + 2, x)
[-7*y + 4]
>>> r = subresultants(3*y*x**2 + y**3 + 1, 2*x**3 + y + 3, x)
>>> r[0]
4*y**9 + 12*y**6 + 27*y**5 + 162*y**4 + 255*y**3 + 4
>>> r[1]
-6*y**4 + -6*y
"""
return AstVector(Z3_polynomial_subresultants(p.ctx_ref(), p.as_ast(), q.as_ast(), x.as_ast()), p.ctx)
if __name__ == "__main__":
import doctest
if doctest.testmod().failed:
exit(1)

View file

@ -24,6 +24,8 @@ Notes:
#include<stdio.h>
#include"z3_macros.h"
#include"z3_api.h"
#include"z3_algebraic.h"
#include"z3_polynomial.h"
#undef __in
#undef __out

226
src/api/z3_algebraic.h Normal file
View file

@ -0,0 +1,226 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
z3_algebraic.h
Abstract:
Additional APIs for handling Z3 algebraic numbers encoded as
Z3_ASTs
Author:
Leonardo de Moura (leonardo) 2012-12-07
Notes:
--*/
#ifndef _Z3_ALGEBRAIC_H_
#define _Z3_ALGEBRAIC_H_
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/**
\brief Return Z3_TRUE if \c can be used as value in the Z3 real algebraic
number package.
def_API('Z3_algebraic_is_value', BOOL, (_in(CONTEXT), _in(AST)))
*/
Z3_bool Z3_API Z3_algebraic_is_value(__in Z3_context c, __in Z3_ast a);
/**
\brief Return the Z3_TRUE if \c a is positive, and Z3_FALSE otherwise.
\pre Z3_algebraic_is_value(c, a)
def_API('Z3_algebraic_is_pos', BOOL, (_in(CONTEXT), _in(AST)))
*/
Z3_bool Z3_API Z3_algebraic_is_pos(__in Z3_context c, __in Z3_ast a);
/**
\brief Return the Z3_TRUE if \c a is negative, and Z3_FALSE otherwise.
\pre Z3_algebraic_is_value(c, a)
def_API('Z3_algebraic_is_neg', BOOL, (_in(CONTEXT), _in(AST)))
*/
Z3_bool Z3_API Z3_algebraic_is_neg(__in Z3_context c, __in Z3_ast a);
/**
\brief Return the Z3_TRUE if \c a is zero, and Z3_FALSE otherwise.
\pre Z3_algebraic_is_value(c, a)
def_API('Z3_algebraic_is_zero', BOOL, (_in(CONTEXT), _in(AST)))
*/
Z3_bool Z3_API Z3_algebraic_is_zero(__in Z3_context c, __in Z3_ast a);
/**
\brief Return 1 if \c a is positive, 0 if \c a is zero, and -1 if \c a is negative.
\pre Z3_algebraic_is_value(c, a)
def_API('Z3_algebraic_sign', INT, (_in(CONTEXT), _in(AST)))
*/
int Z3_API Z3_algebraic_sign(__in Z3_context c, __in Z3_ast a);
/**
\brief Return the value a + b.
\pre Z3_algebraic_is_value(c, a)
\pre Z3_algebraic_is_value(c, b)
\post Z3_algebraic_is_value(c, result)
def_API('Z3_algebraic_add', AST, (_in(CONTEXT), _in(AST), _in(AST)))
*/
Z3_ast Z3_API Z3_algebraic_add(__in Z3_context c, __in Z3_ast a, __in Z3_ast b);
/**
\brief Return the value a - b.
\pre Z3_algebraic_is_value(c, a)
\pre Z3_algebraic_is_value(c, b)
\post Z3_algebraic_is_value(c, result)
def_API('Z3_algebraic_sub', AST, (_in(CONTEXT), _in(AST), _in(AST)))
*/
Z3_ast Z3_API Z3_algebraic_sub(__in Z3_context c, __in Z3_ast a, __in Z3_ast b);
/**
\brief Return the value a * b.
\pre Z3_algebraic_is_value(c, a)
\pre Z3_algebraic_is_value(c, b)
\post Z3_algebraic_is_value(c, result)
def_API('Z3_algebraic_mul', AST, (_in(CONTEXT), _in(AST), _in(AST)))
*/
Z3_ast Z3_API Z3_algebraic_mul(__in Z3_context c, __in Z3_ast a, __in Z3_ast b);
/**
\brief Return the value a / b.
\pre Z3_algebraic_is_value(c, a)
\pre Z3_algebraic_is_value(c, b)
\pre !Z3_algebraic_is_zero(c, b)
\post Z3_algebraic_is_value(c, result)
def_API('Z3_algebraic_div', AST, (_in(CONTEXT), _in(AST), _in(AST)))
*/
Z3_ast Z3_API Z3_algebraic_div(__in Z3_context c, __in Z3_ast a, __in Z3_ast b);
/**
\brief Return the a^(1/k)
\pre Z3_algebraic_is_value(c, a)
\pre k is even => !Z3_algebraic_is_neg(c, a)
\post Z3_algebraic_is_value(c, result)
def_API('Z3_algebraic_root', AST, (_in(CONTEXT), _in(AST), _in(UINT)))
*/
Z3_ast Z3_API Z3_algebraic_root(__in Z3_context c, __in Z3_ast a, __in unsigned k);
/**
\brief Return the a^k
\pre Z3_algebraic_is_value(c, a)
\post Z3_algebraic_is_value(c, result)
def_API('Z3_algebraic_power', AST, (_in(CONTEXT), _in(AST), _in(UINT)))
*/
Z3_ast Z3_API Z3_algebraic_power(__in Z3_context c, __in Z3_ast a, __in unsigned k);
/**
\brief Return Z3_TRUE if a < b, and Z3_FALSE otherwise.
\pre Z3_algebraic_is_value(c, a)
\pre Z3_algebraic_is_value(c, b)
def_API('Z3_algebraic_lt', BOOL, (_in(CONTEXT), _in(AST), _in(AST)))
*/
Z3_bool Z3_API Z3_algebraic_lt(__in Z3_context c, __in Z3_ast a, __in Z3_ast b);
/**
\brief Return Z3_TRUE if a > b, and Z3_FALSE otherwise.
\pre Z3_algebraic_is_value(c, a)
\pre Z3_algebraic_is_value(c, b)
def_API('Z3_algebraic_gt', BOOL, (_in(CONTEXT), _in(AST), _in(AST)))
*/
Z3_bool Z3_API Z3_algebraic_gt(__in Z3_context c, __in Z3_ast a, __in Z3_ast b);
/**
\brief Return Z3_TRUE if a <= b, and Z3_FALSE otherwise.
\pre Z3_algebraic_is_value(c, a)
\pre Z3_algebraic_is_value(c, b)
def_API('Z3_algebraic_le', BOOL, (_in(CONTEXT), _in(AST), _in(AST)))
*/
Z3_bool Z3_API Z3_algebraic_le(__in Z3_context c, __in Z3_ast a, __in Z3_ast b);
/**
\brief Return Z3_TRUE if a >= b, and Z3_FALSE otherwise.
\pre Z3_algebraic_is_value(c, a)
\pre Z3_algebraic_is_value(c, b)
def_API('Z3_algebraic_ge', BOOL, (_in(CONTEXT), _in(AST), _in(AST)))
*/
Z3_bool Z3_API Z3_algebraic_ge(__in Z3_context c, __in Z3_ast a, __in Z3_ast b);
/**
\brief Return Z3_TRUE if a == b, and Z3_FALSE otherwise.
\pre Z3_algebraic_is_value(c, a)
\pre Z3_algebraic_is_value(c, b)
def_API('Z3_algebraic_eq', BOOL, (_in(CONTEXT), _in(AST), _in(AST)))
*/
Z3_bool Z3_API Z3_algebraic_eq(__in Z3_context c, __in Z3_ast a, __in Z3_ast b);
/**
\brief Return Z3_TRUE if a != b, and Z3_FALSE otherwise.
\pre Z3_algebraic_is_value(c, a)
\pre Z3_algebraic_is_value(c, b)
def_API('Z3_algebraic_neq', BOOL, (_in(CONTEXT), _in(AST), _in(AST)))
*/
Z3_bool Z3_API Z3_algebraic_neq(__in Z3_context c, __in Z3_ast a, __in Z3_ast b);
/**
\brief Given a multivariate polynomial p(x_0, ..., x_{n-1}, x_n), returns the
roots of the univariate polynomial p(a[0], ..., a[n-1], x_n).
\pre p is a Z3 expression that contains only arithmetic terms and free variables.
\pre forall i in [0, n) Z3_algebraic_is_value(c, a[i])
\post forall r in result Z3_algebraic_is_value(c, result)
def_API('Z3_algebraic_roots', AST_VECTOR, (_in(CONTEXT), _in(AST), _in(UINT), _in_array(2, AST)))
*/
Z3_ast_vector Z3_API Z3_algebraic_roots(__in Z3_context c, __in Z3_ast p, __in unsigned n, __in Z3_ast a[]);
/**
\brief Given a multivariate polynomial p(x_0, ..., x_{n-1}), return the
sign of p(a[0], ..., a[n-1]).
\pre p is a Z3 expression that contains only arithmetic terms and free variables.
\pre forall i in [0, n) Z3_algebraic_is_value(c, a[i])
def_API('Z3_algebraic_eval', INT, (_in(CONTEXT), _in(AST), _in(UINT), _in_array(2, AST)))
*/
int Z3_API Z3_algebraic_eval(__in Z3_context c, __in Z3_ast p, __in unsigned n, __in Z3_ast a[]);
#ifdef __cplusplus
};
#endif // __cplusplus
#endif

45
src/api/z3_polynomial.h Normal file
View file

@ -0,0 +1,45 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
z3_polynomial.h
Abstract:
Additional APIs for polynomials.
Author:
Leonardo de Moura (leonardo) 2012-12-09
Notes:
--*/
#ifndef _Z3_POLYNOMIAL_H_
#define _Z3_POLYNOMIAL_H_
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/**
\brief Return the nonzero subresultants of \c p and \c q with respect to the "variable" \c x.
\pre \c p, \c q and \c x are Z3 expressions where \c p and \c q are arithmetic terms.
Note that, any subterm that cannot be viewed as a polynomial is assumed to be a variable.
Example: f(a) is a considered to be a variable in the polynomial
f(a)*f(a) + 2*f(a) + 1
def_API('Z3_polynomial_subresultants', AST_VECTOR, (_in(CONTEXT), _in(AST), _in(AST), _in(AST)))
*/
Z3_ast_vector Z3_API Z3_polynomial_subresultants(__in Z3_context c, __in Z3_ast p, __in Z3_ast q, __in Z3_ast x);
#ifdef __cplusplus
};
#endif // __cplusplus
#endif

View file

@ -38,13 +38,6 @@ struct arith_decl_plugin::algebraic_numbers_wrapper {
unsigned mk_id(algebraic_numbers::anum const & val) {
SASSERT(!m_amanager.is_rational(val));
// TODO: avoid linear scan. Use hashtable based on the floor of val
unsigned sz = m_nums.size();
for (unsigned i = 0; i < sz; i++) {
algebraic_numbers::anum const & other = m_nums.get(i);
if (m_amanager.eq(val, other))
return i;
}
unsigned new_id = m_id_gen.mk();
m_nums.reserve(new_id+1);
m_amanager.set(m_nums[new_id], val);
@ -71,13 +64,13 @@ struct arith_decl_plugin::algebraic_numbers_wrapper {
};
arith_decl_plugin::algebraic_numbers_wrapper & arith_decl_plugin::aw() {
arith_decl_plugin::algebraic_numbers_wrapper & arith_decl_plugin::aw() const {
if (m_aw == 0)
m_aw = alloc(algebraic_numbers_wrapper);
const_cast<arith_decl_plugin*>(this)->m_aw = alloc(algebraic_numbers_wrapper);
return *m_aw;
}
algebraic_numbers::manager & arith_decl_plugin::am() {
algebraic_numbers::manager & arith_decl_plugin::am() const {
return aw().m_amanager;
}
@ -509,16 +502,43 @@ void arith_decl_plugin::get_op_names(svector<builtin_name>& op_names, symbol con
}
}
bool arith_decl_plugin::is_value(app* e) const {
return is_app_of(e, m_family_id, OP_NUM);
bool arith_decl_plugin::is_value(app * e) const {
return
is_app_of(e, m_family_id, OP_NUM) ||
is_app_of(e, m_family_id, OP_IRRATIONAL_ALGEBRAIC_NUM) ||
is_app_of(e, m_family_id, OP_PI) ||
is_app_of(e, m_family_id, OP_E);
}
bool arith_decl_plugin::are_distinct(app* a, app* b) const {
bool arith_decl_plugin::is_unique_value(app * e) const {
return
is_app_of(e, m_family_id, OP_NUM) ||
is_app_of(e, m_family_id, OP_PI) ||
is_app_of(e, m_family_id, OP_E);
}
bool arith_decl_plugin::are_equal(app * a, app * b) const {
if (decl_plugin::are_equal(a, b)) {
return true;
}
if (is_app_of(a, m_family_id, OP_IRRATIONAL_ALGEBRAIC_NUM) && is_app_of(b, m_family_id, OP_IRRATIONAL_ALGEBRAIC_NUM)) {
return am().eq(aw().to_anum(a->get_decl()), aw().to_anum(b->get_decl()));
}
return false;
}
bool arith_decl_plugin::are_distinct(app * a, app * b) const {
TRACE("are_distinct_bug", tout << mk_ismt2_pp(a, *m_manager) << "\n" << mk_ismt2_pp(b, *m_manager) << "\n";);
if (decl_plugin::are_distinct(a,b)) {
return true;
}
if (is_app_of(a, m_family_id, OP_IRRATIONAL_ALGEBRAIC_NUM) && is_app_of(b, m_family_id, OP_IRRATIONAL_ALGEBRAIC_NUM)) {
return am().neq(aw().to_anum(a->get_decl()), aw().to_anum(b->get_decl()));
}
#define is_non_zero(e) is_app_of(e,m_family_id, OP_NUM) && !to_app(e)->get_decl()->get_parameter(0).get_rational().is_zero()
if (is_app_of(a, m_family_id, OP_ADD) &&

View file

@ -141,8 +141,8 @@ public:
virtual ~arith_decl_plugin();
virtual void finalize();
algebraic_numbers::manager & am();
algebraic_numbers_wrapper & aw();
algebraic_numbers::manager & am() const;
algebraic_numbers_wrapper & aw() const;
virtual void del(parameter const & p);
virtual parameter translate(parameter const & p, decl_plugin & target);
@ -159,9 +159,13 @@ public:
virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned num_args, expr * const * args, sort * range);
virtual bool is_value(app* e) const;
virtual bool is_value(app * e) const;
virtual bool are_distinct(app* a, app* b) const;
virtual bool is_unique_value(app * e) const;
virtual bool are_equal(app * a, app * b) const;
virtual bool are_distinct(app * a, app * b) const;
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
@ -180,7 +184,7 @@ public:
virtual expr * get_some_value(sort * s);
void set_cancel(bool f);
virtual void set_cancel(bool f);
};
class arith_util {

View file

@ -872,6 +872,10 @@ bool basic_decl_plugin::is_value(app* a) const {
return a->get_decl() == m_true_decl || a->get_decl() == m_false_decl;
}
bool basic_decl_plugin::is_unique_value(app* a) const {
return is_value(a);
}
void basic_decl_plugin::finalize() {
#define DEC_REF(FIELD) if (FIELD) { m_manager->dec_ref(FIELD); }
#define DEC_ARRAY_REF(FIELD) m_manager->dec_array_ref(FIELD.size(), FIELD.begin())
@ -1151,6 +1155,10 @@ bool model_value_decl_plugin::is_value(app* n) const {
return is_app_of(n, m_family_id, OP_MODEL_VALUE);
}
bool model_value_decl_plugin::is_unique_value(app* n) const {
return is_value(n);
}
// -----------------------------------
//
// user_sort_plugin
@ -1328,6 +1336,12 @@ ast_manager::~ast_manager() {
}
}
void ast_manager::set_cancel(bool f) {
for (unsigned i = 0; i < m_plugins.size(); i++) {
m_plugins[i]->set_cancel(f);
}
}
void ast_manager::compact_memory() {
m_alloc.consolidate();
unsigned capacity = m_ast_table.capacity();
@ -1442,6 +1456,27 @@ bool ast_manager::is_value(expr* e) const {
return false;
}
bool ast_manager::is_unique_value(expr* e) const {
decl_plugin const * p = 0;
if (is_app(e)) {
p = get_plugin(to_app(e)->get_family_id());
return p && p->is_unique_value(to_app(e));
}
return false;
}
bool ast_manager::are_equal(expr * a, expr * b) const {
if (is_app(a) && is_app(b)) {
app* ap = to_app(a), *bp = to_app(b);
decl_plugin const * p = get_plugin(ap->get_family_id());
if (!p) {
p = get_plugin(bp->get_family_id());
}
return p && p->are_equal(ap, bp);
}
return false;
}
bool ast_manager::are_distinct(expr* a, expr* b) const {
if (is_app(a) && is_app(b)) {
app* ap = to_app(a), *bp = to_app(b);

View file

@ -921,6 +921,8 @@ public:
virtual ~decl_plugin() {}
virtual void finalize() {}
virtual void set_cancel(bool f) {}
virtual decl_plugin * mk_fresh() = 0;
family_id get_family_id() const { return m_family_id; }
@ -933,9 +935,39 @@ public:
virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const* parameters,
unsigned num_args, expr * const * args, sort * range);
virtual bool is_value(app*) const { return false; }
/**
\brief Return true if the plugin can decide whether two
interpreted constants are equal or not.
For all a, b:
If is_value(a) and is_value(b)
Then,
are_equal(a, b) != are_distinct(a, b)
The may be much more expensive than checking a pointer.
virtual bool are_distinct(app* a, app* b) const { return a != b && is_value(a) && is_value(b); }
We need this because some plugin values are too expensive too canonize.
*/
virtual bool is_value(app * a) const { return false; }
/**
\brief Return true if \c a is a unique plugin value.
The following property should hold for unique theory values:
For all a, b:
If is_unique_value(a) and is_unique_value(b)
Then,
a == b (pointer equality)
IFF
the interpretations of these theory terms are equal.
\remark This is a stronger version of is_value.
*/
virtual bool is_unique_value(app * a) const { return false; }
virtual bool are_equal(app * a, app * b) const { return a == b && is_unique_value(a) && is_unique_value(b); }
virtual bool are_distinct(app * a, app * b) const { return a != b && is_unique_value(a) && is_unique_value(b); }
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic = symbol()) {}
@ -1080,6 +1112,8 @@ public:
virtual void get_sort_names(svector<builtin_name> & sort_names, symbol const & logic);
virtual bool is_value(app* a) const;
virtual bool is_unique_value(app* a) const;
sort * mk_bool_sort() const { return m_bool_sort; }
sort * mk_proof_sort() const { return m_proof_sort; }
@ -1116,7 +1150,6 @@ public:
virtual decl_plugin * mk_fresh() { return alloc(label_decl_plugin); }
virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters);
/**
@ -1198,6 +1231,8 @@ public:
unsigned arity, sort * const * domain, sort * range);
virtual bool is_value(app* n) const;
virtual bool is_unique_value(app* a) const;
};
// -----------------------------------
@ -1367,6 +1402,9 @@ public:
ast_manager(ast_manager const & src, bool disable_proofs = false);
~ast_manager();
// propagate cancellation signal to decl_plugins
void set_cancel(bool f);
bool has_trace_stream() const { return m_trace_stream != 0; }
std::ostream & trace_stream() { SASSERT(has_trace_stream()); return *m_trace_stream; }
@ -1442,9 +1480,13 @@ public:
*/
void set_next_expr_id(unsigned id);
bool is_value(expr* e) const;
bool is_value(expr * e) const;
bool is_unique_value(expr * e) const;
bool are_distinct(expr* a, expr* b) const;
bool are_equal(expr * a, expr * b) const;
bool are_distinct(expr * a, expr * b) const;
bool contains(ast * a) const { return m_ast_table.contains(a); }

View file

@ -260,8 +260,10 @@ public:
virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned num_args, expr * const * args, sort * range);
virtual bool is_value(app* e) const;
virtual bool is_value(app * e) const;
virtual bool is_unique_value(app * e) const { return is_value(e); }
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
virtual void get_sort_names(svector<builtin_name> & sort_names, symbol const & logic);

View file

@ -146,6 +146,9 @@ public:
virtual bool is_fully_interp(sort const * s) const;
virtual bool is_value(app* e) const;
virtual bool is_unique_value(app * e) const { return is_value(e); }
private:
bool is_value_visit(expr * arg, ptr_buffer<app> & todo) const;
};

View file

@ -130,7 +130,8 @@ namespace datalog {
virtual void get_sort_names(svector<builtin_name> & sort_names, symbol const & logic);
virtual bool is_value(app* e) const { return is_app_of(e, m_family_id, OP_DL_CONSTANT); }
virtual bool is_value(app * e) const { return is_app_of(e, m_family_id, OP_DL_CONSTANT); }
virtual bool is_unique_value(app * e) const { return is_value(e); }
};

View file

@ -49,21 +49,24 @@ struct expr2polynomial::imp {
polynomial::polynomial_ref_vector m_presult_stack;
polynomial::scoped_numeral_vector m_dresult_stack;
bool m_use_var_idxs;
volatile bool m_cancel;
imp(expr2polynomial & w, ast_manager & am, polynomial::manager & pm, expr2var * e2v):
imp(expr2polynomial & w, ast_manager & am, polynomial::manager & pm, expr2var * e2v, bool use_var_idxs):
m_wrapper(w),
m_am(am),
m_autil(am),
m_pm(pm),
m_expr2var(e2v == 0 ? alloc(expr2var, am) : e2v),
m_expr2var_owner(e2v == 0),
m_expr2var(e2v == 0 && !use_var_idxs ? alloc(expr2var, am) : e2v),
m_expr2var_owner(e2v == 0 && !use_var_idxs),
m_var2expr(am),
m_cached_domain(am),
m_cached_polynomials(pm),
m_cached_denominators(pm.m()),
m_presult_stack(pm),
m_dresult_stack(pm.m()),
m_use_var_idxs(use_var_idxs),
m_cancel(false) {
}
@ -95,6 +98,14 @@ struct expr2polynomial::imp {
cooperate("expr2polynomial");
}
void throw_not_polynomial() {
throw default_exception("the given expression is not a polynomial");
}
void throw_no_int_var() {
throw default_exception("integer variables are not allowed in the given polynomial");
}
void push_frame(app * t) {
m_frame_stack.push_back(frame(t));
}
@ -127,14 +138,26 @@ struct expr2polynomial::imp {
}
void store_var_poly(expr * t) {
polynomial::var x = m_expr2var->to_var(t);
if (x == UINT_MAX) {
bool is_int = m_autil.is_int(t);
x = m_wrapper.mk_var(is_int);
m_expr2var->insert(t, x);
if (x >= m_var2expr.size())
m_var2expr.resize(x+1, 0);
m_var2expr.set(x, t);
polynomial::var x;
if (m_use_var_idxs) {
SASSERT(::is_var(t));
if (m_autil.is_int(t))
throw_no_int_var();
unsigned idx = to_var(t)->get_idx();
while (idx >= m_pm.num_vars())
m_pm.mk_var();
x = static_cast<polynomial::var>(idx);
}
else {
x = m_expr2var->to_var(t);
if (x == UINT_MAX) {
bool is_int = m_autil.is_int(t);
x = m_wrapper.mk_var(is_int);
m_expr2var->insert(t, x);
if (x >= m_var2expr.size())
m_var2expr.resize(x+1, 0);
m_var2expr.set(x, t);
}
}
polynomial::numeral one(1);
store_result(t, pm().mk_polynomial(x), one);
@ -160,7 +183,10 @@ struct expr2polynomial::imp {
rational k;
SASSERT(t->get_num_args() == 2);
if (!m_autil.is_numeral(t->get_arg(1), k) || !k.is_int() || !k.is_unsigned()) {
store_var_poly(t);
if (m_use_var_idxs)
throw_not_polynomial();
else
store_var_poly(t);
return true;
}
push_frame(t);
@ -168,6 +194,8 @@ struct expr2polynomial::imp {
}
default:
// can't handle operator
if (m_use_var_idxs)
throw_not_polynomial();
store_var_poly(t);
return true;
}
@ -190,6 +218,8 @@ struct expr2polynomial::imp {
SASSERT(is_app(t));
if (!m_autil.is_arith_expr(t)) {
if (m_use_var_idxs)
throw_not_polynomial();
store_var_poly(t);
return true;
}
@ -378,19 +408,25 @@ struct expr2polynomial::imp {
for (unsigned i = 0; i < sz; i++) {
margs.reset();
polynomial::monomial * m = pm().get_monomial(p, i);
polynomial::monomial * _m = pm().get_monomial(p, i);
polynomial::numeral const & a = pm().coeff(p, i);
if (!nm().is_one(a)) {
margs.push_back(m_autil.mk_numeral(rational(a), is_int));
}
unsigned msz = pm().size(m);
unsigned msz = pm().size(_m);
for (unsigned j = 0; j < msz; j++) {
polynomial::var x = pm().get_var(m, j);
expr * t = m_var2expr.get(x);
if (m_wrapper.is_int(x) && !is_int) {
t = m_autil.mk_to_real(t);
polynomial::var x = pm().get_var(_m, j);
expr * t;
if (m_use_var_idxs) {
t = m().mk_var(x, m_autil.mk_real());
}
unsigned d = pm().degree(m, j);
else {
t = m_var2expr.get(x);
if (m_wrapper.is_int(x) && !is_int) {
t = m_autil.mk_to_real(t);
}
}
unsigned d = pm().degree(_m, j);
if (use_power && d > 1) {
margs.push_back(m_autil.mk_power(t, m_autil.mk_numeral(rational(d), is_int)));
}
@ -426,8 +462,8 @@ struct expr2polynomial::imp {
}
};
expr2polynomial::expr2polynomial(ast_manager & am, polynomial::manager & pm, expr2var * e2v) {
m_imp = alloc(imp, *this, am, pm, e2v);
expr2polynomial::expr2polynomial(ast_manager & am, polynomial::manager & pm, expr2var * e2v, bool use_var_idxs) {
m_imp = alloc(imp, *this, am, pm, e2v, use_var_idxs);
}
expr2polynomial::~expr2polynomial() {
@ -451,10 +487,12 @@ void expr2polynomial::to_expr(polynomial::polynomial_ref const & p, bool use_pow
}
bool expr2polynomial::is_var(expr * t) const {
SASSERT(!m_imp->m_use_var_idxs);
return m_imp->m_expr2var->is_var(t);
}
expr2var const & expr2polynomial::get_mapping() const {
SASSERT(!m_imp->m_use_var_idxs);
return *(m_imp->m_expr2var);
}

View file

@ -29,7 +29,24 @@ class expr2polynomial {
struct imp;
imp * m_imp;
public:
expr2polynomial(ast_manager & am, polynomial::manager & pm, expr2var * e2v);
expr2polynomial(ast_manager & am,
polynomial::manager & pm,
expr2var * e2v,
/*
If true, the expressions converted into
polynomials should only contain Z3 free variables.
A Z3 variable x, with idx i, is converted into
the variable i of the polynomial manager pm.
An exception is thrown if there is a mismatch between
the sorts x and the variable in the polynomial manager.
The argument e2v is ignored when use_var_idxs is true.
Moreover, only real variables are allowed.
*/
bool use_var_idxs = false
);
virtual ~expr2polynomial();
ast_manager & m() const;
@ -63,6 +80,8 @@ public:
/**
\brief Return the mapping from expressions to variables
\pre the object was created using use_var_idxs = false.
*/
expr2var const & get_mapping() const;
@ -74,10 +93,10 @@ public:
/**
\brief Return true if the variable is associated with an expression of integer sort.
*/
virtual bool is_int(polynomial::var x) const = 0;
virtual bool is_int(polynomial::var x) const { UNREACHABLE(); return false; }
protected:
virtual polynomial::var mk_var(bool is_int) = 0;
virtual polynomial::var mk_var(bool is_int) { UNREACHABLE(); return polynomial::null_var; }
};
class default_expr2polynomial : public expr2polynomial {

View file

@ -141,6 +141,7 @@ public:
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
virtual void get_sort_names(svector<builtin_name> & sort_names, symbol const & logic);
virtual bool is_value(app* e) const;
virtual bool is_unique_value(app* e) const { return is_value(e); }
mpf_manager & fm() { return m_fm; }
func_decl * mk_value_decl(mpf const & v);

View file

@ -5,7 +5,7 @@ def_module_params(class_name='pattern_inference_params_helper',
params=(('max_multi_patterns', UINT, 0, 'when patterns are not provided, the prover uses a heuristic to infer them, this option sets the threshold on the number of extra multi-patterns that can be created; by default, the prover creates at most one multi-pattern when there is no unary pattern'),
('block_loop_patterns', BOOL, True, 'block looping patterns during pattern inference'),
('arith', UINT, 1, '0 - do not infer patterns with arithmetic terms, 1 - use patterns with arithmetic terms if there is no other pattern, 2 - always use patterns with arithmetic terms'),
('use_database', BOOL, True, 'use pattern database'),
('use_database', BOOL, False, 'use pattern database'),
('arith_weight', UINT, 5, 'default weight for quantifiers where the only available pattern has nested arithmetic terms'),
('non_nested_arith_weight', UINT, 10, 'default weight for quantifiers where the only available pattern has non nested arithmetic terms'),
('pull_quantifiers', BOOL, True, 'pull nested quantifiers, if no pattern was found'),

View file

@ -732,7 +732,7 @@ br_status bool_rewriter::mk_distinct_core(unsigned num_args, expr * const * args
return BR_DONE;
}
visited.mark(arg);
if (!m().is_value(arg))
if (!m().is_unique_value(arg))
all_value = false;
}
if (all_value) {

View file

@ -200,7 +200,12 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
expr * mk_eq_value(expr * lhs, expr * value) {
SASSERT(m().is_value(value));
if (m().is_value(lhs)) {
return lhs == value ? m().mk_true() : m().mk_false();
if (m().are_equal(lhs, value)) {
return m().mk_true();
}
else if (m().are_distinct(lhs, value)) {
return m().mk_false();
}
}
return m().mk_eq(lhs, value);
}

View file

@ -112,7 +112,10 @@ public:
virtual void get_sort_names(svector<builtin_name> & sort_names, symbol const & logic);
virtual bool is_value(app* e) const;
virtual bool is_value(app * e) const;
virtual bool is_unique_value(app * e) const { return is_value(e); }
};

View file

@ -293,7 +293,7 @@ bool array_simplifier_plugin::all_const_array(unsigned num_args, expr* const* ar
bool array_simplifier_plugin::all_values(unsigned num_args, expr* const* args) const {
for (unsigned i = 0; i < num_args; ++i) {
if (!m_manager.is_value(args[i])) {
if (!m_manager.is_unique_value(args[i])) {
return false;
}
}
@ -331,7 +331,7 @@ lbool array_simplifier_plugin::eq_default(expr* def, unsigned arity, unsigned nu
if (st[i][arity] == def) {
continue;
}
if (m_manager.is_value(st[i][arity]) && m_manager.is_value(def)) {
if (m_manager.is_unique_value(st[i][arity]) && m_manager.is_unique_value(def)) {
return l_false;
}
return l_undef;
@ -342,7 +342,7 @@ lbool array_simplifier_plugin::eq_default(expr* def, unsigned arity, unsigned nu
bool array_simplifier_plugin::insert_table(expr* def, unsigned arity, unsigned num_st, expr*const* const* st, arg_table& table) {
for (unsigned i = 0; i < num_st; ++i ) {
for (unsigned j = 0; j < arity; ++j) {
if (!m_manager.is_value(st[i][j])) {
if (!m_manager.is_unique_value(st[i][j])) {
return false;
}
}
@ -380,12 +380,12 @@ lbool array_simplifier_plugin::eq_stores(expr* def, unsigned arity, unsigned num
table2.erase(e1);
continue;
}
if (m_manager.is_value(v1) && m_manager.is_value(v2)) {
if (m_manager.is_unique_value(v1) && m_manager.is_unique_value(v2)) {
return l_false;
}
return l_undef;
}
else if (m_manager.is_value(v1) && m_manager.is_value(def) && v1 != def) {
else if (m_manager.is_unique_value(v1) && m_manager.is_unique_value(def) && v1 != def) {
return l_false;
}
}
@ -394,7 +394,7 @@ lbool array_simplifier_plugin::eq_stores(expr* def, unsigned arity, unsigned num
for (; it != end; ++it) {
args_entry const & e = *it;
expr* v = e.m_args[arity];
if (m_manager.is_value(v) && m_manager.is_value(def) && v != def) {
if (m_manager.is_unique_value(v) && m_manager.is_unique_value(def) && v != def) {
return l_false;
}
}
@ -431,7 +431,7 @@ bool array_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & resul
return false;
}
}
else if (m_manager.is_value(c1) && m_manager.is_value(c2)) {
else if (m_manager.is_unique_value(c1) && m_manager.is_unique_value(c2)) {
result = m_manager.mk_false();
return true;
}
@ -464,7 +464,7 @@ array_simplifier_plugin::mk_select_const(expr* m, app* index, expr_ref& result)
//
// Unfold and cache the store while searching for value of index.
//
while (is_store(a) && m_manager.is_value(to_app(a)->get_arg(1))) {
while (is_store(a) && m_manager.is_unique_value(to_app(a)->get_arg(1))) {
app* b = to_app(a);
app* c = to_app(b->get_arg(1));
@ -728,7 +728,7 @@ void array_simplifier_plugin::mk_select(unsigned num_args, expr * const * args,
return;
}
bool is_const_select = num_args == 2 && m_manager.is_value(args[1]);
bool is_const_select = num_args == 2 && m_manager.is_unique_value(args[1]);
app* const_index = is_const_select?to_app(args[1]):0;
unsigned num_const_stores = 0;
expr_ref tmp(m_manager);
@ -766,7 +766,7 @@ void array_simplifier_plugin::mk_select(unsigned num_args, expr * const * args,
expr * else_branch = 0;
entry[0] = nested_array;
if (is_const_select) {
if (m_manager.is_value(to_app(m)->get_arg(1))) {
if (m_manager.is_unique_value(to_app(m)->get_arg(1))) {
app* const_index2 = to_app(to_app(m)->get_arg(1));
//
// we found the value, all other stores are different.

View file

@ -37,6 +37,7 @@ Notes:
#include"well_sorted.h"
#include"model_evaluator.h"
#include"for_each_expr.h"
#include"scoped_timer.h"
func_decls::func_decls(ast_manager & m, func_decl * f):
m_decls(TAG(func_decl*, f, 0)) {
@ -591,14 +592,9 @@ void cmd_context::init_manager() {
SASSERT(m_manager == 0);
SASSERT(m_pmanager == 0);
m_check_sat_result = 0;
m_manager = alloc(ast_manager,
produce_proofs() ? PGM_FINE : PGM_DISABLED,
m_params.m_trace ? m_params.m_trace_file_name.c_str() : 0);
m_manager = m_params.mk_ast_manager();
m_pmanager = alloc(pdecl_manager, *m_manager);
init_manager_core(true);
// PARAM-TODO
// if (params().m_smtlib2_compliant)
// m_manager->enable_int_real_coercions(false);
}
void cmd_context::init_external_manager() {
@ -1304,9 +1300,11 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions
if (m_solver) {
m_check_sat_result = m_solver.get(); // solver itself stores the result.
m_solver->set_progress_callback(this);
unsigned timeout = m_params.m_timeout;
scoped_watch sw(*this);
cancel_eh<solver> eh(*m_solver);
scoped_ctrl_c ctrlc(eh);
scoped_timer timer(timeout, &eh);
lbool r;
try {
r = m_solver->check_sat(num_assumptions, assumptions);
@ -1444,15 +1442,9 @@ void cmd_context::validate_model() {
}
void cmd_context::init_solver_options(solver * s) {
m_solver->set_produce_unsat_cores(produce_unsat_cores());
m_solver->set_produce_models(produce_models());
m_solver->set_produce_proofs(produce_proofs());
params_ref p;
m_params.init_solver_params(m(), *m_solver, p);
m_solver->init(m(), m_logic);
if (!m_params.m_auto_config) {
params_ref p;
p.set_bool("auto_config", false);
m_solver->updt_params(p);
}
}
void cmd_context::set_solver(solver * s) {

View file

@ -20,6 +20,8 @@ Notes:
#include"context_params.h"
#include"gparams.h"
#include"params.h"
#include"ast.h"
#include"solver.h"
context_params::context_params() {
updt_params();
@ -39,7 +41,7 @@ void context_params::set_bool(bool & opt, char const * param, char const * value
void context_params::set(char const * param, char const * value) {
std::string p = param;
unsigned n = p.size();
unsigned n = static_cast<unsigned>(p.size());
for (unsigned i = 0; i < n; i++) {
if (p[i] >= 'A' && p[i] <= 'Z')
p[i] = p[i] - 'A' + 'a';
@ -77,6 +79,9 @@ void context_params::set(char const * param, char const * value) {
else if (p == "debug_ref_count") {
set_bool(m_debug_ref_count, param, value);
}
else if (p == "smtlib2_compliant") {
set_bool(m_smtlib2_compliant, param, value);
}
else {
throw default_exception("unknown parameter '%s'", p.c_str());
}
@ -97,6 +102,7 @@ void context_params::updt_params(params_ref const & p) {
m_trace_file_name = p.get_str("trace_file_name", "z3.log");
m_unsat_core = p.get_bool("unsat_core", false);
m_debug_ref_count = p.get_bool("debug_ref_count", false);
m_smtlib2_compliant = p.get_bool("smtlib2_compliant", false);
}
void context_params::collect_param_descrs(param_descrs & d) {
@ -111,4 +117,36 @@ void context_params::collect_param_descrs(param_descrs & d) {
d.insert("trace_file_name", CPK_STRING, "trace out file name (see option 'trace')", "z3.log");
d.insert("unsat_core", CPK_BOOL, "unsat-core generation for solvers, this parameter can be overwritten when creating a solver, not every solver in Z3 supports unsat core generation", "false");
d.insert("debug_ref_count", CPK_BOOL, "debug support for AST reference counting", "false");
d.insert("smtlib2_compliant", CPK_BOOL, "enable/disable SMT-LIB 2.0 compliance", "false");
}
params_ref context_params::merge_default_params(params_ref const & p) {
if (!m_auto_config && !p.contains("auto_config")) {
params_ref new_p = p;
new_p.set_bool("auto_config", false);
return new_p;
}
else {
return p;
}
}
void context_params::init_solver_params(ast_manager & m, solver & s, params_ref const & p) {
s.set_produce_proofs(m.proofs_enabled() && m_proof);
s.set_produce_models(p.get_bool("model", m_model));
s.set_produce_unsat_cores(p.get_bool("unsat_core", m_unsat_core));
s.updt_params(merge_default_params(p));
}
ast_manager * context_params::mk_ast_manager() {
ast_manager * r = alloc(ast_manager,
m_proof ? PGM_FINE : PGM_DISABLED,
m_trace ? m_trace_file_name.c_str() : 0);
if (m_smtlib2_compliant)
r->enable_int_real_coercions(false);
if (m_debug_ref_count)
r->debug_ref_count();
return r;
}

View file

@ -21,6 +21,8 @@ Notes:
#define _CONTEXT_PARAMS_H_
#include"params.h"
class ast_manager;
class solver;
class context_params {
void set_bool(bool & opt, char const * param, char const * value);
@ -35,6 +37,7 @@ public:
bool m_model;
bool m_model_validate;
bool m_unsat_core;
bool m_smtlib2_compliant; // it must be here because it enable/disable the use of coercions in the ast_manager.
unsigned m_timeout;
context_params();
@ -45,6 +48,27 @@ public:
/*
REG_PARAMS('context_params::collect_param_descrs')
*/
/**
\brief Goodie for updating the solver params
based on the configuration of the context_params object.
This method is used when creating solvers from the
cmd_context and API.
*/
void init_solver_params(ast_manager & m, solver & s, params_ref const & p);
/**
\brief Include in p parameters derived from this context_params.
These are parameters that are meaningful for tactics and solvers.
Example: auto_config
*/
params_ref merge_default_params(params_ref const & p);
/**
\brief Create an AST manager using this configuration.
*/
ast_manager * mk_ast_manager();
};

View file

@ -36,7 +36,7 @@ tactic_cmd::~tactic_cmd() {
dealloc(m_factory);
}
tactic * tactic_cmd::mk(ast_manager & m) {
tactic * tactic_cmd::mk(ast_manager & m) {
return (*m_factory)(m, params_ref());
}
@ -185,7 +185,7 @@ public:
}
virtual void execute(cmd_context & ctx) {
params_ref p = ps();
params_ref p = ctx.params().merge_default_params(ps());
tactic_ref tref = using_params(sexpr2tactic(ctx, m_tactic), p);
tref->set_logic(ctx.get_logic());
ast_manager & m = ctx.m();
@ -295,7 +295,7 @@ public:
}
virtual void execute(cmd_context & ctx) {
params_ref p = ps();
params_ref p = ctx.params().merge_default_params(ps());
tactic_ref tref = using_params(sexpr2tactic(ctx, m_tactic), p);
{
tactic & t = *(tref.get());

View file

@ -64,6 +64,8 @@ namespace algebraic_numbers {
static void collect_param_descrs(param_descrs & r) { get_param_descrs(r); }
void set_cancel(bool f);
void cancel() { set_cancel(true); }
void updt_params(params_ref const & p);

View file

@ -219,6 +219,7 @@ namespace polynomial {
void set_zp(uint64 p);
void set_cancel(bool f);
void cancel() { set_cancel(true); }
/**
\brief Abstract event handler.

View file

@ -49,10 +49,10 @@ void func_entry::set_result(ast_manager & m, expr * r) {
m_result = r;
}
bool func_entry::eq_args(unsigned arity, expr * const * args) const {
bool func_entry::eq_args(ast_manager & m, unsigned arity, expr * const * args) const {
unsigned i = 0;
for (; i < arity; i++) {
if (m_args[i] != args[i])
if (!m.are_equal(m_args[i], args[i]))
return false;
}
return true;
@ -131,7 +131,7 @@ bool func_interp::is_constant() const {
}
/**
\brief Return a func_entry e such that e.m_args[i] == args[i] for all i in [0, m_arity).
\brief Return a func_entry e such that m().are_equal(e.m_args[i], args[i]) for all i in [0, m_arity).
If such entry does not exist then return 0, and store set
args_are_values to true if for all entries e e.args_are_values() is true.
*/
@ -140,7 +140,7 @@ func_entry * func_interp::get_entry(expr * const * args) const {
ptr_vector<func_entry>::const_iterator end = m_entries.end();
for (; it != end; ++it) {
func_entry * curr = *it;
if (curr->eq_args(m_arity, args))
if (curr->eq_args(m(), m_arity, args))
return curr;
}
return 0;

View file

@ -58,9 +58,9 @@ public:
expr * get_arg(unsigned idx) const { return m_args[idx]; }
expr * const * get_args() const { return m_args; }
/**
\brief Return true if m_args[i] == args[i] for all i in [0, arity)
\brief Return true if m.are_equal(m_args[i], args[i]) for all i in [0, arity)
*/
bool eq_args(unsigned arity, expr * const * args) const;
bool eq_args(ast_manager & m, unsigned arity, expr * const * args) const;
};
class func_interp {

File diff suppressed because it is too large Load diff

View file

@ -35,83 +35,23 @@ namespace datalog {
ast_manager& m;
smt_params m_fparams;
smt::kernel m_solver;
obj_map<func_decl, sort*> m_pred2sort;
obj_map<sort, func_decl*> m_sort2pred;
obj_map<func_decl, func_decl*> m_pred2newpred;
obj_map<func_decl, ptr_vector<func_decl> > m_pred2args;
ast_ref_vector m_pinned;
rule_set m_rules;
func_decl_ref m_query_pred;
expr_ref m_answer;
volatile bool m_cancel;
proof_converter_ref m_pc;
sort_ref m_path_sort;
bv_util m_bv;
unsigned m_bit_width;
lbool check_query();
proof_ref get_proof(model_ref& md, app* trace, app* path);
void checkpoint();
void declare_datatypes();
void compile_nonlinear();
void mk_rule_vars_nonlinear(rule& r, unsigned rule_id, expr* trace_arg, expr* path_arg, expr_ref_vector& sub);
expr_ref mk_var_nonlinear(func_decl* pred, sort* s, unsigned idx, expr* path_arg, expr* trace_arg);
expr_ref mk_arg_nonlinear(func_decl* pred, unsigned idx, expr* path_arg, expr* trace_arg);
void mk_subst(rule& r, expr* path, app* trace, expr_ref_vector& sub);
class nonlinear_dt;
class nonlinear;
class qlinear;
class linear;
bool is_linear() const;
lbool check_nonlinear();
void setup_nonlinear();
bool check_model_nonlinear(model_ref& md, expr* trace);
void mk_answer_nonlinear(model_ref& md, expr_ref& trace, expr_ref& path);
func_decl_ref mk_predicate(func_decl* p);
func_decl_ref mk_rule(func_decl* p, unsigned rule_idx);
// linear check
lbool check_linear();
lbool check_linear(unsigned level);
void compile_linear();
void compile_linear(unsigned level);
void compile_linear(rule& r, unsigned level);
expr_ref mk_level_predicate(symbol const& name, unsigned level);
expr_ref mk_level_predicate(func_decl* p, unsigned level);
expr_ref mk_level_arg(func_decl* pred, unsigned idx, unsigned level);
expr_ref mk_level_rule(func_decl* p, unsigned rule_idx, unsigned level);
expr_ref mk_level_var(func_decl* pred, sort* s, unsigned rule_id, unsigned idx, unsigned level);
void get_model_linear(unsigned level);
void setup_linear();
void assert_expr(expr* e);
void mk_rule_vars(rule& r, unsigned level, unsigned rule_id, expr_ref_vector& sub);
// quantified linear check
void compile_qlinear();
void setup_qlinear();
lbool check_qlinear();
lbool get_model_qlinear();
sort_ref mk_index_sort();
var_ref mk_index_var();
void mk_qrule_vars(datalog::rule const& r, unsigned i, expr_ref_vector& sub);
expr_ref mk_q_var(func_decl* pred, sort* s, unsigned rule_id, unsigned idx);
expr_ref mk_q_arg(func_decl* pred, unsigned idx, bool is_current);
expr_ref mk_q_one();
expr_ref mk_q_num(unsigned i);
expr_ref eval_q(model_ref& model, expr* t, unsigned i);
expr_ref eval_q(model_ref& model, func_decl* f, unsigned i);
func_decl_ref mk_q_rule(func_decl* f, unsigned rule_id);
func_decl_ref mk_q_func_decl(func_decl* f);
public:
bmc(context& ctx);
@ -131,6 +71,10 @@ namespace datalog {
void reset_statistics();
expr_ref get_answer();
// direct access to (new) non-linear compiler.
void compile(rule_set const& rules, expr_ref_vector& fmls, unsigned level);
expr_ref compile_query(func_decl* query_pred, unsigned level);
};
};

View file

@ -715,6 +715,8 @@ namespace datalog {
check_positive_predicates(r);
break;
case BMC_ENGINE:
check_positive_predicates(r);
break;
case QBMC_ENGINE:
check_existential_tail(r);
check_positive_predicates(r);

View file

@ -18,7 +18,8 @@ Revision History:
--*/
#include "dl_mk_array_blast.h"
#include "expr_replacer.h"
#include "expr_safe_replace.h"
namespace datalog {
@ -54,9 +55,10 @@ namespace datalog {
unsigned tsz = r.get_tail_size();
expr_ref_vector conjs(m), new_conjs(m);
expr_ref tmp(m);
expr_substitution sub(m);
expr_safe_replace sub(m);
uint_set lhs_vars, rhs_vars;
bool change = false;
bool inserted = false;
for (unsigned i = 0; i < utsz; ++i) {
new_conjs.push_back(r.get_tail(i));
@ -81,6 +83,7 @@ namespace datalog {
}
else {
sub.insert(x, y);
inserted = true;
}
}
else {
@ -89,7 +92,7 @@ namespace datalog {
new_conjs.push_back(tmp);
}
}
if (sub.empty() && !change) {
if (!inserted && !change) {
rules.add_rule(&r);
return false;
}
@ -99,11 +102,9 @@ namespace datalog {
r.to_formula(fml1);
body = m.mk_and(new_conjs.size(), new_conjs.c_ptr());
head = r.get_head();
scoped_ptr<expr_replacer> replace = mk_default_expr_replacer(m);
replace->set_substitution(&sub);
(*replace)(body);
sub(body);
m_rewriter(body);
(*replace)(head);
sub(head);
m_rewriter(head);
fml2 = m.mk_implies(body, head);
rm.mk_rule(fml2, new_rules, r.name());

View file

@ -60,7 +60,7 @@ namespace datalog {
obj_map<expr, unsigned> indices;
bool_rewriter bwr(m);
rule_ref r(const_cast<rule*>(&rl), rm);
sort_ref_vector sorts(m);
ptr_vector<sort> sorts;
expr_ref_vector revsub(m), conjs(m);
rl.get_vars(sorts);
revsub.resize(sorts.size());
@ -72,8 +72,8 @@ namespace datalog {
if (is_var(e)) {
unsigned v = to_var(e)->get_idx();
SASSERT(v < valid.size());
if (sorts[v].get()) {
SASSERT(s == sorts[v].get());
if (sorts[v]) {
SASSERT(s == sorts[v]);
if (valid[v]) {
revsub[v] = w;
valid[v] = false;
@ -92,8 +92,8 @@ namespace datalog {
}
}
for (unsigned i = 0; i < sorts.size(); ++i) {
if (valid[i] && sorts[i].get() && !revsub[i].get()) {
revsub[i] = m.mk_var(m_idx++, sorts[i].get());
if (valid[i] && sorts[i] && !revsub[i].get()) {
revsub[i] = m.mk_var(m_idx++, sorts[i]);
}
}
var_subst vs(m, false);
@ -112,7 +112,7 @@ namespace datalog {
app_ref pred(m), head(m);
expr_ref fml1(m), fml2(m), fml(m);
app_ref_vector tail(m);
sort_ref_vector sorts1(m), sorts2(m);
ptr_vector<sort> sorts1, sorts2;
expr_ref_vector conjs1(m), conjs(m);
rule_ref res(rm);
bool_rewriter bwr(m);

View file

@ -0,0 +1,366 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
dl_mk_extract_quantifiers2.cpp
Abstract:
Remove universal quantifiers over interpreted predicates in the body.
Author:
Nikolaj Bjorner (nbjorner) 2012-11-21
Revision History:
--*/
#include"dl_mk_extract_quantifiers2.h"
#include"ast_pp.h"
#include"dl_bmc_engine.h"
#include"smt_quantifier.h"
#include"smt_context.h"
namespace datalog {
mk_extract_quantifiers2::mk_extract_quantifiers2(context & ctx) :
rule_transformer::plugin(101, false),
m_ctx(ctx),
m(ctx.get_manager()),
rm(ctx.get_rule_manager()),
m_query_pred(m),
m_quantifiers(m),
m_refs(m)
{}
mk_extract_quantifiers2::~mk_extract_quantifiers2() {
reset();
}
void mk_extract_quantifiers2::set_query(func_decl* q) {
m_query_pred = q;
}
bool mk_extract_quantifiers2::matches_signature(func_decl* head, expr_ref_vector const& binding) {
unsigned sz = head->get_arity();
if (sz != binding.size()) {
return false;
}
for (unsigned i = 0; i < sz; ++i) {
if (head->get_domain(i) != m.get_sort(binding[sz-i-1])) {
return false;
}
}
return true;
}
bool mk_extract_quantifiers2::matches_quantifier(quantifier* q, expr_ref_vector const& binding) {
unsigned sz = q->get_num_decls();
if (sz != binding.size()) {
return false;
}
for (unsigned i = 0; i < sz; ++i) {
if (q->get_decl_sort(i) != m.get_sort(binding[sz-i-1])) {
return false;
}
}
return true;
}
bool mk_extract_quantifiers2::mk_abstract_expr(expr_ref& term) {
if (!is_app(term)) {
return false;
}
expr* r;
if (m_map.find(term, r)) {
term = r;
return true;
}
if (to_app(term)->get_family_id() == null_family_id) {
return false;
}
expr_ref_vector args(m);
expr_ref tmp(m);
for (unsigned i = 0; i < to_app(term)->get_num_args(); ++i) {
tmp = to_app(term)->get_arg(i);
if (!mk_abstract_expr(tmp)) {
return false;
}
args.push_back(tmp);
}
tmp = m.mk_app(to_app(term)->get_decl(), args.size(), args.c_ptr());
m_refs.push_back(tmp);
m_map.insert(term, tmp);
term = tmp;
return true;
}
bool mk_extract_quantifiers2::mk_abstract_binding(expr_ref_vector const& binding, expr_ref_vector& result) {
for (unsigned i = 0; i < binding.size(); ++i) {
expr_ref tmp(m);
tmp = binding[i];
if (!mk_abstract_expr(tmp)) {
return false;
}
result.push_back(tmp);
}
return true;
}
void mk_extract_quantifiers2::mk_abstraction_map(rule& r, expr_ref_vector const& binding) {
m_map.reset();
unsigned sz = binding.size();
SASSERT(sz == r.get_decl()->get_arity());
for (unsigned i = 0; i < sz; ++i) {
m_map.insert(binding[sz-i-1], r.get_head()->get_arg(i));
SASSERT(m.get_sort(binding[sz-i-1]) == m.get_sort(r.get_head()->get_arg(i)));
}
// todo: also make bindings for variables in rule body.
}
void mk_extract_quantifiers2::match_bindings(unsigned i, unsigned j, unsigned k) {
expr_ref_vector resb(m);
rule* r = m_qrules[i];
quantifier* q = m_quantifiers[i].get();
expr_ref_vector const& ruleb = m_rule_bindings[i][j];
expr_ref_vector const& quantb = m_quantifier_bindings[i][k];
mk_abstraction_map(*r, ruleb);
if (!mk_abstract_binding(quantb, resb)) {
return;
}
expr_ref inst(m), tmp(m);
var_shifter shift(m);
for (unsigned l = 0; l < resb.size(); ++l) {
tmp = resb[l].get();
shift(tmp, q->get_num_decls(), tmp);
resb[l] = tmp;
}
instantiate(m, q, resb.c_ptr(), inst);
if (!m_seen.contains(r)) {
m_seen.insert(r, alloc(obj_hashtable<expr>));
}
obj_hashtable<expr>& seen = *m_seen.find(r);
if (seen.contains(inst)) {
return;
}
seen.insert(inst);
m_refs.push_back(inst);
if (!m_quantifier_instantiations.contains(r, q)) {
m_quantifier_instantiations.insert(r, q, alloc(expr_ref_vector, m));
}
expr_ref_vector* vec = 0;
VERIFY(m_quantifier_instantiations.find(r, q, vec));
vec->push_back(inst);
TRACE("dl", tout << "matched: " << mk_pp(q, m) << "\n" << mk_pp(inst, m) << "\n";);
}
app_ref mk_extract_quantifiers2::ensure_app(expr* e) {
if (is_app(e)) {
return app_ref(to_app(e), m);
}
else {
return app_ref(m.mk_eq(e, m.mk_true()), m);
}
}
void mk_extract_quantifiers2::extract(rule& r, rule_set& new_rules) {
unsigned utsz = r.get_uninterpreted_tail_size();
unsigned tsz = r.get_tail_size();
bool has_quantifier = false;
expr_ref_vector conjs(m);
for (unsigned i = utsz; i < tsz; ++i) {
conjs.push_back(r.get_tail(i));
}
datalog::flatten_and(conjs);
for (unsigned j = 0; j < conjs.size(); ++j) {
expr* e = conjs[j].get();
quantifier* q;
if (rule_manager::is_forall(m, e, q)) {
m_quantifiers.push_back(q);
m_qrules.push_back(&r);
m_rule_bindings.push_back(vector<expr_ref_vector>());
m_quantifier_bindings.push_back(vector<expr_ref_vector>());
has_quantifier = true;
}
}
if (!has_quantifier) {
new_rules.add_rule(&r);
}
}
void mk_extract_quantifiers2::apply(rule& r, rule_set& new_rules) {
expr_ref_vector tail(m), conjs(m);
expr_ref fml(m);
unsigned utsz = r.get_uninterpreted_tail_size();
unsigned tsz = r.get_tail_size();
for (unsigned i = 0; i < utsz; ++i) {
SASSERT(!r.is_neg_tail(i));
tail.push_back(r.get_tail(i));
}
bool has_quantifier = false;
for (unsigned i = utsz; i < tsz; ++i) {
conjs.push_back(r.get_tail(i));
}
datalog::flatten_and(conjs);
for (unsigned j = 0; j < conjs.size(); ++j) {
expr* e = conjs[j].get();
quantifier* q;
if (rule_manager::is_forall(m, e, q)) {
expr_ref_vector* ls;
if (m_quantifier_instantiations.find(&r,q,ls)) {
tail.append(*ls);
}
has_quantifier = true;
}
else {
tail.push_back(e);
}
}
if (has_quantifier) {
fml = m.mk_implies(m.mk_and(tail.size(), tail.c_ptr()), r.get_head());
rule_ref_vector rules(rm);
rm.mk_rule(fml, rules, r.name());
for (unsigned i = 0; i < rules.size(); ++i) {
new_rules.add_rule(rules[i].get());
}
}
}
#if 0
class mk_extract_quantifiers2::instance_plugin : public smt::quantifier_instance_plugin {
mk_extract_quantifiers2& ex;
ast_manager& m;
expr_ref_vector m_refs;
obj_hashtable<expr> m_bindings;
public:
instance_plugin(mk_extract_quantifiers2& ex): ex(ex), m(ex.m), m_refs(m) {}
virtual void operator()(quantifier* q, unsigned num_bindings, smt::enode*const* bindings) {
expr_ref_vector binding(m);
ptr_vector<sort> sorts;
for (unsigned i = 0; i < num_bindings; ++i) {
binding.push_back(bindings[i]->get_owner());
sorts.push_back(m.get_sort(binding[i].get()));
}
func_decl* f = m.mk_func_decl(symbol("T"), sorts.size(), sorts.c_ptr(), m.mk_bool_sort());
expr_ref tup(m);
tup = m.mk_app(f, binding.size(), binding.c_ptr());
if (!m_bindings.contains(tup)) {
m_bindings.insert(tup);
m_refs.push_back(tup);
ex.m_bindings.push_back(binding);
TRACE("dl", tout << "insert\n" << mk_pp(q, m) << "\n" << mk_pp(tup, m) << "\n";);
}
}
};
#endif
void mk_extract_quantifiers2::reset() {
{
obj_pair_map<rule,quantifier, expr_ref_vector*>::iterator
it = m_quantifier_instantiations.begin(),
end = m_quantifier_instantiations.end();
for (; it != end; ++it) {
dealloc(it->get_value());
}
}
{
obj_map<rule,obj_hashtable<expr>*>::iterator
it = m_seen.begin(),
end = m_seen.end();
for (; it != end; ++it) {
dealloc(it->m_value);
}
}
m_quantifier_instantiations.reset();
m_seen.reset();
m_has_quantifiers = false;
m_quantifiers.reset();
m_qrules.reset();
m_bindings.reset();
m_rule_bindings.reset();
m_quantifier_bindings.reset();
m_refs.reset();
}
rule_set * mk_extract_quantifiers2::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) {
reset();
rule_set::iterator it = source.begin(), end = source.end();
for (; !m_has_quantifiers && it != end; ++it) {
m_has_quantifiers = (*it)->has_quantifiers();
}
if (!m_has_quantifiers) {
return 0;
}
rule_set* rules = alloc(rule_set, m_ctx);
it = source.begin();
for (; it != end; ++it) {
extract(**it, *rules);
}
bmc bmc(m_ctx);
expr_ref_vector fmls(m);
bmc.compile(source, fmls, 0); // TBD: use cancel_eh to terminate without base-case.
bmc.compile(source, fmls, 1);
bmc.compile(source, fmls, 2);
// bmc.compile(source, fmls, 3);
expr_ref query = bmc.compile_query(m_query_pred, 2);
fmls.push_back(query);
smt_params fparams;
fparams.m_relevancy_lvl = 0;
fparams.m_model = true;
fparams.m_model_compact = true;
fparams.m_mbqi = true;
smt::kernel solver(m, fparams);
TRACE("dl",
for (unsigned i = 0; i < fmls.size(); ++i) {
tout << mk_pp(fmls[i].get(), m) << "\n";
});
for (unsigned i = 0; i < fmls.size(); ++i) {
solver.assert_expr(fmls[i].get());
}
#if 0
smt::context& ctx = solver.get_context();
smt::quantifier_manager* qm = ctx.get_quantifier_manager();
qm->get_plugin()->set_instance_plugin(alloc(instance_plugin, *this));
#endif
lbool res = solver.check();
for (unsigned i = 0; i < m_bindings.size(); ++i) {
expr_ref_vector& binding = m_bindings[i];
for (unsigned j = 0; j < m_qrules.size(); ++j) {
rule* r = m_qrules[j];
if (matches_signature(r->get_decl(), binding)) {
m_rule_bindings[j].push_back(binding);
}
else if (matches_quantifier(m_quantifiers[j].get(), binding)) {
m_quantifier_bindings[j].push_back(binding);
}
}
}
for (unsigned i = 0; i < m_qrules.size(); ++i) {
for (unsigned j = 0; j < m_rule_bindings[i].size(); ++j) {
for (unsigned k = 0; k < m_quantifier_bindings[i].size(); ++k) {
match_bindings(i, j, k);
}
}
}
it = source.begin();
for (; it != end; ++it) {
apply(**it, *rules);
}
return rules;
}
};

View file

@ -0,0 +1,91 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
dl_mk_extract_quantifiers2.h
Abstract:
Replace universal quantifiers over interpreted predicates in the body
by instantiations mined using bounded model checking search.
Author:
Nikolaj Bjorner (nbjorner) 2012-11-21
Revision History:
--*/
#ifndef _DL_MK_EXTRACT_QUANTIFIERS2_H_
#define _DL_MK_EXTRACT_QUANTIFIERS2_H_
#include"dl_context.h"
#include"dl_rule_set.h"
#include"dl_rule_transformer.h"
#include"obj_pair_hashtable.h"
namespace datalog {
/**
\brief Extract universal quantifiers from rules.
*/
class mk_extract_quantifiers2 : public rule_transformer::plugin {
context& m_ctx;
ast_manager& m;
rule_manager& rm;
func_decl_ref m_query_pred;
quantifier_ref_vector m_quantifiers;
ptr_vector<rule> m_qrules;
vector<expr_ref_vector>m_bindings;
vector<vector<expr_ref_vector> > m_rule_bindings;
vector<vector<expr_ref_vector> > m_quantifier_bindings;
obj_pair_map<rule,quantifier, expr_ref_vector*> m_quantifier_instantiations;
obj_map<rule, obj_hashtable<expr>*> m_seen;
bool m_has_quantifiers;
obj_map<expr,expr*> m_map;
expr_ref_vector m_refs;
class instance_plugin;
void reset();
void extract(rule& r, rule_set& new_rules);
void apply(rule& r, rule_set& new_rules);
app_ref ensure_app(expr* e);
bool matches_signature(func_decl* head, expr_ref_vector const& binding);
bool matches_quantifier(quantifier* q, expr_ref_vector const& binding);
void match_bindings(unsigned i, unsigned j, unsigned k);
bool mk_abstract_expr(expr_ref& term);
bool mk_abstract_binding(expr_ref_vector const& binding, expr_ref_vector& result);
void mk_abstraction_map(rule& r, expr_ref_vector const& binding);
public:
/**
\brief Create rule transformer that extracts universal quantifiers (over recursive predicates).
*/
mk_extract_quantifiers2(context & ctx);
virtual ~mk_extract_quantifiers2();
void set_query(func_decl* q);
rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc);
bool has_quantifiers() { return m_has_quantifiers; }
};
};
#endif /* _DL_MK_EXTRACT_QUANTIFIERS2_H_ */

View file

@ -136,14 +136,14 @@ namespace datalog {
expr_ref_vector rule_unifier::get_rule_subst(const rule& r, bool is_tgt) {
SASSERT(m_ready);
expr_ref_vector result(m);
sort_ref_vector sorts(m);
ptr_vector<sort> sorts;
expr_ref v(m), w(m);
r.get_vars(sorts);
for (unsigned i = 0; i < sorts.size(); ++i) {
if (!sorts[i].get()) {
if (!sorts[i]) {
sorts[i] = m.mk_bool_sort();
}
v = m.mk_var(i, sorts[i].get());
v = m.mk_var(i, sorts[i]);
m_subst.apply(2, m_deltas, expr_offset(v, is_tgt?0:1), w);
result.push_back(w);
}

View file

@ -41,6 +41,7 @@ Revision History:
#include"expr_replacer.h"
#include"bool_rewriter.h"
#include"qe_lite.h"
#include"expr_safe_replace.h"
namespace datalog {
@ -130,17 +131,15 @@ namespace datalog {
return index;
}
// replace vars by de-bruijn indices
expr_substitution sub(m);
expr_safe_replace rep(m);
for (unsigned i = 0; i < vars.size(); ++i) {
app* v = vars[i].get();
if (names) {
names->push_back(v->get_decl()->get_name());
}
sub.insert(v, m.mk_var(index++,m.get_sort(v)));
rep.insert(v, m.mk_var(index++,m.get_sort(v)));
}
scoped_ptr<expr_replacer> rep = mk_default_expr_replacer(m);
rep->set_substitution(&sub);
(*rep)(fml);
rep(fml);
return index;
}
@ -936,7 +935,7 @@ namespace datalog {
}
}
void rule::get_vars(sort_ref_vector& sorts) const {
void rule::get_vars(ptr_vector<sort>& sorts) const {
sorts.reset();
used_vars used;
get_used_vars(used);

View file

@ -244,7 +244,7 @@ namespace datalog {
void norm_vars(rule_manager & rm);
void get_vars(sort_ref_vector& sorts) const;
void get_vars(ptr_vector<sort>& sorts) const;
void to_formula(expr_ref& result) const;

View file

@ -440,7 +440,7 @@ namespace pdr {
unsigned ut_size = r.get_uninterpreted_tail_size();
unsigned t_size = r.get_tail_size();
var_subst vs(m, false);
sort_ref_vector vars(m);
ptr_vector<sort> vars;
uint_set empty_index_set;
qe_lite qe(m);

View file

@ -2365,7 +2365,7 @@ namespace smt2 {
parser(cmd_context & ctx, std::istream & is, bool interactive, params_ref const & p):
m_ctx(ctx),
m_params(p),
m_scanner(ctx, is, interactive, p),
m_scanner(ctx, is, interactive),
m_curr(scanner::NULL_TOKEN),
m_curr_cmd(0),
m_num_bindings(0),

View file

@ -242,7 +242,7 @@ namespace smt2 {
}
}
scanner::scanner(cmd_context & ctx, std::istream& stream, bool interactive, params_ref const & _p):
scanner::scanner(cmd_context & ctx, std::istream& stream, bool interactive):
m_ctx(ctx),
m_interactive(interactive),
m_spos(0),
@ -254,9 +254,8 @@ namespace smt2 {
m_bend(0),
m_stream(stream),
m_cache_input(false) {
parser_params p(_p);
m_smtlib2_compliant = p.smt2_compliant();
m_smtlib2_compliant = ctx.params().m_smtlib2_compliant;
for (int i = 0; i < 256; ++i) {
m_normalized[i] = (char) i;

View file

@ -76,7 +76,7 @@ namespace smt2 {
EOF_TOKEN
};
scanner(cmd_context & ctx, std::istream& stream, bool interactive = false, params_ref const & p = params_ref());
scanner(cmd_context & ctx, std::istream& stream, bool interactive = false);
~scanner() {}

View file

@ -3,4 +3,4 @@ def_module_params('parser',
params=(('ignore_user_patterns', BOOL, False, 'ignore patterns provided by the user'),
('ignore_bad_patterns', BOOL, True, 'ignore malformed patterns'),
('error_for_visual_studio', BOOL, False, 'display error messages in Visual Studio format'),
('smt2_compliant', BOOL, False, 'enable/disable SMT-LIB 2.0 compliance')))
))

View file

@ -142,6 +142,14 @@ namespace smt {
}
};
struct initn : public instruction {
// We need that because starting at Z3 3.0, some associative
// operators (e.g., + and *) are represented using n-ary
// applications.
// We do not need the extra field for INIT1, ..., INIT6.
unsigned m_num_args;
};
struct compare : public instruction {
unsigned m_reg1;
unsigned m_reg2;
@ -608,7 +616,18 @@ namespace smt {
instruction * mk_init(unsigned n) {
SASSERT(n >= 1);
opcode op = n <= 6 ? static_cast<opcode>(INIT1 + n - 1) : INITN;
return mk_instr<instruction>(op, sizeof(instruction));
if (op == INITN) {
// We store the actual number of arguments for INITN.
// Starting at Z3 3.0, some associative operators
// (e.g., + and *) are represented using n-ary
// applications.
initn * r = mk_instr<initn>(op, sizeof(initn));
r->m_num_args = n;
return r;
}
else {
return mk_instr<instruction>(op, sizeof(instruction));
}
}
public:
@ -2345,6 +2364,8 @@ namespace smt {
case INITN:
m_app = m_registers[0];
m_num_args = m_app->get_num_args();
if (m_num_args != static_cast<const initn *>(m_pc)->m_num_args)
goto backtrack;
for (unsigned i = 0; i < m_num_args; i++)
m_registers[i+1] = m_app->get_arg(i);
m_pc = m_pc->m_next;
@ -3982,3 +4003,8 @@ namespace smt {
}
};
#ifdef Z3DEBUG
void pp(smt::code_tree * c) {
c->display(std::cout);
}
#endif

View file

@ -32,6 +32,7 @@ void smt_params::updt_local_params(params_ref const & _p) {
m_delay_units = p.delay_units();
m_delay_units_threshold = p.delay_units_threshold();
m_preprocess = _p.get_bool("preprocess", true); // hidden parameter
m_soft_timeout = p.soft_timeout();
if (_p.get_bool("arith.greatest_error_pivot", false))
m_arith_pivot_strategy = ARITH_PIVOT_GREATEST_ERROR;
else if (_p.get_bool("arith.least_error_pivot", false))
@ -48,7 +49,6 @@ void smt_params::updt_params(params_ref const & p) {
void smt_params::updt_params(context_params const & p) {
m_auto_config = p.m_auto_config;
m_soft_timeout = p.m_timeout;
m_model = p.m_model;
m_model_validate = p.m_model_validate;
}

View file

@ -7,13 +7,14 @@ def_module_params(module_name='smt',
('relevancy', UINT, 2, 'relevancy propagation heuristic: 0 - disabled, 1 - relevancy is tracked by only affects quantifier instantiation, 2 - relevancy is tracked, and an atom is only asserted if it is relevant'),
('macro_finder', BOOL, False, 'try to find universally quantified formulas that can be viewed as macros'),
('ematching', BOOL, True, 'E-Matching based quantifier instantiation'),
('phase_selection', UINT, 4, 'phase selection heuristic: 0 - always false, 1 - always true, 2 - phase caching, 3 - phase caching conservative, 4 - phase caching conservative 2, 5 - random, 6 - number of occurrences'),
('phase_selection', UINT, 3, 'phase selection heuristic: 0 - always false, 1 - always true, 2 - phase caching, 3 - phase caching conservative, 4 - phase caching conservative 2, 5 - random, 6 - number of occurrences'),
('restart_strategy', UINT, 1, '0 - geometric, 1 - inner-outer-geometric, 2 - luby, 3 - fixed, 4 - arithmetic'),
('restart_factor', DOUBLE, 1.1, 'when using geometric (or inner-outer-geometric) progression of restarts, it specifies the constant used to multiply the currect restart threshold'),
('case_split', UINT, 1, '0 - case split based on variable activity, 1 - similar to 0, but delay case splits created during the search, 2 - similar to 0, but cache the relevancy, 3 - case split based on relevancy (structural splitting), 4 - case split on relevancy and activity, 5 - case split on relevancy and current goal'),
('delay_units', BOOL, False, 'if true then z3 will not restart when a unit clause is learned'),
('delay_units_threshold', UINT, 32, 'maximum number of learned unit clauses before restarting, ingored if delay_units is false'),
('pull_nested_quantifiers', BOOL, False, 'pull nested quantifiers'),
('soft_timeout', UINT, 0, 'soft timeout (0 means no timeout)'),
('mbqi', BOOL, True, 'model based quantifier instantiation (MBQI)'),
('mbqi.max_cexs', UINT, 1, 'initial maximal number of counterexamples used in MBQI, each counterexample generates a quantifier instantiation'),
('mbqi.max_cexs_incr', UINT, 0, 'increment for MBQI_MAX_CEXS, the increment is performed after each round of MBQI'),

View file

@ -155,7 +155,7 @@ bool eval(func_interp & fi, simplifier & s, expr * const * args, expr_ref & resu
basic_simplifier_plugin * bs = static_cast<basic_simplifier_plugin*>(s.get_plugin(fi.m().get_basic_family_id()));
for (unsigned k = 0; k < fi.num_entries(); k++) {
func_entry const * curr = fi.get_entry(k);
SASSERT(!curr->eq_args(fi.get_arity(), args));
SASSERT(!curr->eq_args(fi.m(), fi.get_arity(), args));
if (!actuals_are_values || !curr->args_are_values()) {
expr_ref_buffer eqs(fi.m());
unsigned i = fi.get_arity();

View file

@ -907,7 +907,7 @@ namespace smt {
}
enode * e = enode::mk(m_manager, m_region, m_app2enode, n, generation, suppress_args, merge_tf, m_scope_lvl, cgc_enabled, true);
TRACE("mk_enode_detail", tout << "e.get_num_args() = " << e->get_num_args() << "\n";);
if (n->get_num_args() == 0 && m_manager.is_value(n))
if (n->get_num_args() == 0 && m_manager.is_unique_value(n))
e->mark_as_interpreted();
TRACE("mk_var_bug", tout << "mk_enode: " << id << "\n";);
TRACE("generation", tout << "mk_enode: " << id << " " << generation << "\n";);

View file

@ -139,6 +139,7 @@ public:
ast_manager & m = in->m();
TRACE("smt_tactic", tout << this << "\nAUTO_CONFIG: " << fparams().m_auto_config << " HIDIV0: " << fparams().m_hi_div0 << " "
<< " PREPROCESS: " << fparams().m_preprocess << "\n";
tout << "RELEVANCY: " << fparams().m_relevancy_lvl << "\n";
tout << "fail-if-inconclusive: " << m_fail_if_inconclusive << "\n";
tout << "params_ref: " << m_params_ref << "\n";);
TRACE("smt_tactic_detail", in->display(tout););

View file

@ -49,6 +49,8 @@ public:
virtual bool is_value(app*) const;
virtual bool is_unique_value(app * a) const { return is_value(a); }
bool is_value(func_decl *) const;
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic);

View file

@ -355,12 +355,12 @@ struct cofactor_elim_term_ite::imp {
expr * lhs;
expr * rhs;
if (m.is_eq(t, lhs, rhs)) {
if (m.is_value(lhs)) {
if (m.is_unique_value(lhs)) {
m_term = rhs;
m_value = to_app(lhs);
TRACE("set_cofactor_atom", tout << "term:\n" << mk_ismt2_pp(m_term, m) << "\nvalue: " << mk_ismt2_pp(m_value, m) << "\n";);
}
else if (m.is_value(rhs)) {
else if (m.is_unique_value(rhs)) {
m_term = lhs;
m_value = to_app(rhs);
TRACE("set_cofactor_atom", tout << "term:\n" << mk_ismt2_pp(m_term, m) << "\nvalue: " << mk_ismt2_pp(m_value, m) << "\n";);

View file

@ -128,7 +128,7 @@ struct reduce_args_tactic::imp {
unsigned j = n->get_num_args();
while (j > 0) {
--j;
if (m_manager.is_value(n->get_arg(j)))
if (m_manager.is_unique_value(n->get_arg(j)))
return;
}
m_non_cadidates.insert(d);
@ -185,13 +185,13 @@ struct reduce_args_tactic::imp {
it->m_value.reserve(j);
while (j > 0) {
--j;
it->m_value.set(j, m_manager.is_value(n->get_arg(j)));
it->m_value.set(j, m_manager.is_unique_value(n->get_arg(j)));
}
} else {
SASSERT(j == it->m_value.size());
while (j > 0) {
--j;
it->m_value.set(j, it->m_value.get(j) && m_manager.is_value(n->get_arg(j)));
it->m_value.set(j, it->m_value.get(j) && m_manager.is_unique_value(n->get_arg(j)));
}
}
}

View file

@ -559,10 +559,10 @@ public:
ts.push_back(m_ts.get(i)->translate(*new_m));
}
unsigned finished_id = UINT_MAX;
par_exception_kind ex_kind;
unsigned finished_id = UINT_MAX;
par_exception_kind ex_kind = DEFAULT_EX;
std::string ex_msg;
unsigned error_code;
unsigned error_code = 0;
#pragma omp parallel for
for (int i = 0; i < static_cast<int>(sz); i++) {
@ -734,8 +734,8 @@ public:
bool found_solution = false;
bool failed = false;
par_exception_kind ex_kind;
unsigned error_code;
par_exception_kind ex_kind = DEFAULT_EX;
unsigned error_code = 0;
std::string ex_msg;
#pragma omp parallel for
@ -1242,8 +1242,7 @@ public:
virtual void updt_params(params_ref const & p) {
TRACE("using_params",
tout << "before p: " << p << "\n";
tout << "m_params: " << m_params << "\n";
;);
tout << "m_params: " << m_params << "\n";);
params_ref new_p = p;
new_p.append(m_params);

View file

@ -62,9 +62,8 @@ tactic * mk_ufbv_preprocessor_tactic(ast_manager & m, params_ref const & p) {
tactic * mk_ufbv_tactic(ast_manager & m, params_ref const & p) {
params_ref main_p(p);
main_p.set_bool("mbqi", true);
main_p.set_uint("mbqi_max_iterations", -1);
main_p.set_uint("mbqi.max_iterations", UINT_MAX);
main_p.set_bool("elim_and", true);
main_p.set_bool("solver", true);
tactic * t = and_then(repeat(mk_ufbv_preprocessor_tactic(m, main_p), 2),
mk_smt_tactic_using(false, main_p));

View file

@ -260,8 +260,8 @@ public:
\brief c <- a - b
*/
void sub(interval const & a, interval const & b, interval & c) {
m().sub(a.m_lower, b.m_lower, c.m_lower);
m().sub(a.m_upper, b.m_upper, c.m_upper);
m().sub(a.m_lower, b.m_upper, c.m_lower);
m().sub(a.m_upper, b.m_lower, c.m_upper);
}
private:

View file

@ -165,7 +165,7 @@ public:
if (*name == ':')
name++;
std::string tmp = name;
unsigned n = tmp.size();
unsigned n = static_cast<unsigned>(tmp.size());
for (unsigned i = 0; i < n; i++) {
if (tmp[i] >= 'A' && tmp[i] <= 'Z')
tmp[i] = tmp[i] - 'A' + 'a';

View file

@ -21,13 +21,15 @@ Notes:
#include"symbol.h"
#include"dictionary.h"
params_ref params_ref::g_empty_params_ref;
std::string norm_param_name(char const * n) {
if (n == 0)
return "_";
if (*n == ':')
n++;
std::string r = n;
unsigned sz = r.size();
unsigned sz = static_cast<unsigned>(r.size());
if (sz == 0)
return "_";
for (unsigned i = 0; i < sz; i++) {
@ -133,7 +135,7 @@ struct param_descrs::imp {
if (smt2_style)
out << ':';
char const * s = it2->bare_str();
unsigned n = strlen(s);
unsigned n = static_cast<unsigned>(strlen(s));
for (unsigned i = 0; i < n; i++) {
if (smt2_style && s[i] == '_')
out << '-';

View file

@ -31,6 +31,8 @@ class params;
class param_descrs;
class params_ref {
static params_ref g_empty_params_ref;
params * m_params;
void init();
void copy_core(params const * p);
@ -38,7 +40,9 @@ public:
params_ref():m_params(0) {}
params_ref(params_ref const & p);
~params_ref();
static params_ref const & get_empty() { return g_empty_params_ref; }
params_ref & operator=(params_ref const & p);
// copy params from src

View file

@ -43,7 +43,7 @@ Revision History:
#define CLOCKID CLOCK_PROCESS_CPUTIME_ID
#else
// FreeBSD does not support CLOCK_PROCESS_CPUTIME_ID
#define CLOCKID CLOCK_PROF
#define CLOCKID CLOCK_MONOTONIC
#endif
#define SIG SIGRTMIN
// ---------