3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-23 00:55:31 +00:00

moving remaining qsat functionality over

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2016-03-19 15:35:26 -07:00
parent 296addf246
commit 20bbdfe31a
23 changed files with 3876 additions and 225 deletions

921
src/qe/nlqsat.cpp Normal file
View file

@ -0,0 +1,921 @@
/*++
Copyright (c) 2015 Microsoft Corporation
Module Name:
nlqsat.cpp
Abstract:
Quantifier Satisfiability Solver for nlsat
Author:
Nikolaj Bjorner (nbjorner) 2015-10-17
Revision History:
--*/
#include "nlqsat.h"
#include "nlsat_solver.h"
#include "nlsat_explain.h"
#include "nlsat_assignment.h"
#include "qsat.h"
#include "quant_hoist.h"
#include "goal2nlsat.h"
#include "expr2var.h"
#include "uint_set.h"
#include "ast_util.h"
#include "tseitin_cnf_tactic.h"
#include "expr_safe_replace.h"
namespace qe {
enum qsat_mode_t {
qsat_t,
elim_t,
interp_t
};
class nlqsat : public tactic {
typedef unsigned_vector assumption_vector;
typedef nlsat::scoped_literal_vector clause;
struct stats {
unsigned m_num_rounds;
stats() { reset(); }
void reset() { memset(this, 0, sizeof(*this)); }
};
ast_manager& m;
qsat_mode_t m_mode;
params_ref m_params;
nlsat::solver m_solver;
tactic_ref m_nftactic;
nlsat::literal_vector m_asms;
nlsat::literal_vector m_cached_asms;
unsigned_vector m_cached_asms_lim;
nlsat::literal m_is_true;
nlsat::assignment m_rmodel;
svector<lbool> m_bmodel;
nlsat::assignment m_rmodel0;
svector<lbool> m_bmodel0;
bool m_valid_model;
vector<nlsat::var_vector> m_bound_rvars;
vector<svector<nlsat::bool_var> > m_bound_bvars;
vector<nlsat::scoped_literal_vector> m_preds;
svector<max_level> m_rvar2level;
u_map<max_level> m_bvar2level;
expr2var m_a2b, m_t2x;
u_map<expr*> m_b2a, m_x2t;
volatile bool m_cancel;
stats m_stats;
statistics m_st;
obj_hashtable<expr> m_free_vars;
expr_ref_vector m_answer;
expr_safe_replace m_answer_simplify;
nlsat::literal_vector m_assumptions;
u_map<expr*> m_asm2fml;
expr_ref_vector m_trail;
lbool check_sat() {
while (true) {
++m_stats.m_num_rounds;
check_cancel();
init_assumptions();
lbool res = m_solver.check(m_asms);
switch (res) {
case l_true:
TRACE("qe", display(tout); );
save_model();
push();
break;
case l_false:
if (0 == level()) return l_false;
if (1 == level() && m_mode == qsat_t) return l_true;
project();
break;
case l_undef:
return res;
}
}
return l_undef;
}
void init_assumptions() {
unsigned lvl = level();
m_asms.reset();
m_asms.push_back(is_exists()?m_is_true:~m_is_true);
m_asms.append(m_assumptions);
TRACE("qe", tout << "model valid: " << m_valid_model << " level: " << lvl << " ";
display_assumptions(tout);
m_solver.display(tout););
if (!m_valid_model) {
m_asms.append(m_cached_asms);
return;
}
unsave_model();
if (lvl == 0) {
SASSERT(m_cached_asms.empty());
return;
}
if (lvl <= m_preds.size()) {
for (unsigned j = 0; j < m_preds[lvl - 1].size(); ++j) {
add_literal(m_cached_asms, m_preds[lvl - 1][j]);
}
}
m_asms.append(m_cached_asms);
for (unsigned i = lvl + 1; i < m_preds.size(); i += 2) {
for (unsigned j = 0; j < m_preds[i].size(); ++j) {
nlsat::literal l = m_preds[i][j];
max_level lv = m_bvar2level.find(l.var());
bool use =
(lv.m_fa == i && (lv.m_ex == UINT_MAX || lv.m_ex < lvl)) ||
(lv.m_ex == i && (lv.m_fa == UINT_MAX || lv.m_fa < lvl));
if (use) {
add_literal(m_asms, l);
}
}
}
TRACE("qe", display(tout);
for (unsigned i = 0; i < m_asms.size(); ++i) {
m_solver.display(tout, m_asms[i]); tout << "\n";
});
save_model();
}
void add_literal(nlsat::literal_vector& lits, nlsat::literal l) {
lbool r = m_solver.value(l);
switch (r) {
case l_true:
lits.push_back(l);
break;
case l_false:
lits.push_back(~l);
break;
default:
UNREACHABLE();
break;
}
}
template<class S, class T>
void insert_set(S& set, T const& vec) {
for (unsigned i = 0; i < vec.size(); ++i) {
set.insert(vec[i]);
}
}
void mbp(unsigned level, nlsat::scoped_literal_vector& result) {
nlsat::var_vector vars;
uint_set fvars;
extract_vars(level, vars, fvars);
mbp(vars, fvars, result);
}
void extract_vars(unsigned level, nlsat::var_vector& vars, uint_set& fvars) {
for (unsigned i = 0; i < m_bound_rvars.size(); ++i) {
if (i < level) {
insert_set(fvars, m_bound_bvars[i]);
}
else {
vars.append(m_bound_rvars[i]);
}
}
}
void mbp(nlsat::var_vector const& vars, uint_set const& fvars, clause& result) {
//
// Also project auxiliary variables from clausification.
//
unsave_model();
nlsat::explain& ex = m_solver.get_explain();
nlsat::scoped_literal_vector new_result(m_solver);
result.reset();
// project quantified Boolean variables.
for (unsigned i = 0; i < m_asms.size(); ++i) {
nlsat::literal lit = m_asms[i];
if (!m_b2a.contains(lit.var()) || fvars.contains(lit.var())) {
result.push_back(lit);
}
}
TRACE("qe", m_solver.display(tout, result.size(), result.c_ptr()); tout << "\n";);
// project quantified real variables.
// They are sorted by size, so we project the largest variables first to avoid
// renaming variables.
for (unsigned i = vars.size(); i > 0;) {
--i;
new_result.reset();
ex.project(vars[i], result.size(), result.c_ptr(), new_result);
result.swap(new_result);
TRACE("qe", m_solver.display(tout, result.size(), result.c_ptr()); tout << "\n";);
}
negate_clause(result);
}
void negate_clause(clause& result) {
for (unsigned i = 0; i < result.size(); ++i) {
result.set(i, ~result[i]);
}
}
void save_model() {
m_solver.get_rvalues(m_rmodel);
m_solver.get_bvalues(m_bmodel);
m_valid_model = true;
if (is_exists(level())) {
m_rmodel0.copy(m_rmodel);
m_bmodel0.reset();
m_bmodel0.append(m_bmodel);
}
}
void unsave_model() {
SASSERT(m_valid_model);
m_solver.set_rvalues(m_rmodel);
m_solver.set_bvalues(m_bmodel);
}
void clear_model() {
m_valid_model = false;
m_rmodel.reset();
m_bmodel.reset();
m_solver.set_rvalues(m_rmodel);
}
unsigned level() const {
return m_cached_asms_lim.size();
}
void enforce_parity(clause& cl) {
cl.push_back(is_exists()?~m_is_true:m_is_true);
}
void add_clause(clause& cl) {
if (cl.empty()) {
cl.push_back(~m_solver.mk_true());
}
SASSERT(!cl.empty());
nlsat::literal_vector lits(cl.size(), cl.c_ptr());
m_solver.mk_clause(lits.size(), lits.c_ptr());
}
max_level get_level(clause const& cl) {
return get_level(cl.size(), cl.c_ptr());
}
max_level get_level(unsigned n, nlsat::literal const* ls) {
max_level level;
for (unsigned i = 0; i < n; ++i) {
level.merge(get_level(ls[i]));
}
return level;
}
max_level get_level(nlsat::literal l) {
max_level level;
if (m_bvar2level.find(l.var(), level)) {
return level;
}
nlsat::var_vector vs;
m_solver.vars(l, vs);
for (unsigned i = 0; i < vs.size(); ++i) {
level.merge(m_rvar2level[vs[i]]);
}
set_level(l.var(), level);
return level;
}
void set_level(nlsat::bool_var v, max_level const& level) {
unsigned k = level.max();
while (m_preds.size() <= k) {
m_preds.push_back(nlsat::scoped_literal_vector(m_solver));
}
nlsat::literal l(v, false);
m_preds[k].push_back(l);
m_bvar2level.insert(v, level);
TRACE("qe", m_solver.display(tout, l); tout << ": " << level << "\n";);
}
void project() {
TRACE("qe", display_assumptions(tout););
if (!m_valid_model) {
pop(1);
return;
}
if (m_mode == elim_t) {
project_qe();
return;
}
SASSERT(level() >= 2);
unsigned num_scopes;
clause cl(m_solver);
mbp(level()-1, cl);
max_level clevel = get_level(cl);
enforce_parity(cl);
add_clause(cl);
if (clevel.max() == UINT_MAX) {
num_scopes = 2*(level()/2);
}
else {
SASSERT(clevel.max() + 2 <= level());
num_scopes = level() - clevel.max();
if ((num_scopes % 2) != 0) {
--num_scopes;
}
SASSERT(num_scopes >= 2);
}
TRACE("qe", tout << "backtrack: " << num_scopes << "\n";);
pop(num_scopes);
}
void project_qe() {
SASSERT(level() >= 1 && m_mode == elim_t && m_valid_model);
clause cl(m_solver);
mbp(std::max(1u, level()-1), cl);
expr_ref fml = clause2fml(cl);
TRACE("qe", tout << level() << ": " << fml << "\n";);
max_level clevel = get_level(cl);
if (level() == 1 || clevel.max() == 0) {
add_assumption_literal(cl, fml);
}
else {
enforce_parity(cl);
}
add_clause(cl);
if (level() == 1) { // is_forall() && clevel.max() == 0
add_to_answer(fml);
}
if (level() == 1) {
pop(1);
}
else {
pop(2);
}
}
void add_to_answer(expr_ref& fml) {
m_answer_simplify(fml);
expr* e;
if (m.is_not(fml, e)) {
m_answer_simplify.insert(e, m.mk_false());
}
else {
m_answer_simplify.insert(fml, m.mk_true());
}
m_answer.push_back(fml);
}
expr_ref clause2fml(nlsat::scoped_literal_vector const& clause) {
expr_ref_vector fmls(m);
expr_ref fml(m);
expr* t;
nlsat2goal n2g(m);
for (unsigned i = 0; i < clause.size(); ++i) {
nlsat::literal l = clause[i];
if (m_asm2fml.find(l.var(), t)) {
fml = t;
if (l.sign()) {
fml = push_not(fml);
}
SASSERT(l.sign());
fmls.push_back(fml);
}
else {
fmls.push_back(n2g(m_solver, m_b2a, m_x2t, l));
}
}
fml = mk_or(fmls);
return fml;
}
void add_assumption_literal(clause& clause, expr* fml) {
nlsat::bool_var b = m_solver.mk_bool_var();
clause.push_back(nlsat::literal(b, true));
m_assumptions.push_back(nlsat::literal(b, false));
m_asm2fml.insert(b, fml);
m_trail.push_back(fml);
m_bvar2level.insert(b, max_level());
}
bool is_exists() const { return is_exists(level()); }
bool is_forall() const { return is_forall(level()); }
bool is_exists(unsigned level) const { return (level % 2) == 0; }
bool is_forall(unsigned level) const { return is_exists(level+1); }
void check_cancel() {
if (m_cancel) {
throw tactic_exception(TACTIC_CANCELED_MSG);
}
}
void reset() {
//m_solver.reset();
m_asms.reset();
m_cached_asms.reset();
m_cached_asms_lim.reset();
m_is_true = nlsat::null_literal;
m_rmodel.reset();
m_valid_model = false;
m_bound_rvars.reset();
m_bound_bvars.reset();
m_preds.reset();
m_rvar2level.reset();
m_bvar2level.reset();
m_t2x.reset();
m_a2b.reset();
m_b2a.reset();
m_x2t.reset();
m_cancel = false;
m_st.reset();
m_solver.collect_statistics(m_st);
m_free_vars.reset();
m_answer.reset();
m_answer_simplify.reset();
m_assumptions.reset();
m_asm2fml.reset();
m_trail.reset();
}
void push() {
m_cached_asms_lim.push_back(m_cached_asms.size());
}
void pop(unsigned num_scopes) {
clear_model();
unsigned new_level = level() - num_scopes;
m_cached_asms.shrink(m_cached_asms_lim[new_level]);
m_cached_asms_lim.shrink(new_level);
}
void display(std::ostream& out) {
display_preds(out);
display_assumptions(out);
m_solver.display(out << "solver:\n");
}
void display_assumptions(std::ostream& out) {
m_solver.display(out << "assumptions: ", m_asms.size(), m_asms.c_ptr());
out << "\n";
}
void display_preds(std::ostream& out) {
for (unsigned i = 0; i < m_preds.size(); ++i) {
m_solver.display(out << i << ": ", m_preds[i].size(), m_preds[i].c_ptr());
out << "\n";
}
}
// expr -> nlsat::solver
void hoist(expr_ref& fml) {
quantifier_hoister hoist(m);
vector<app_ref_vector> qvars;
app_ref_vector vars(m);
bool is_forall = false;
pred_abs abs(m);
abs.get_free_vars(fml, vars);
insert_set(m_free_vars, vars);
qvars.push_back(vars);
vars.reset();
if (m_mode == elim_t) {
is_forall = true;
hoist.pull_quantifier(is_forall, fml, vars);
qvars.push_back(vars);
}
else {
hoist.pull_quantifier(is_forall, fml, vars);
qvars.back().append(vars);
}
do {
is_forall = !is_forall;
vars.reset();
hoist.pull_quantifier(is_forall, fml, vars);
qvars.push_back(vars);
}
while (!vars.empty());
SASSERT(qvars.back().empty());
init_expr2var(qvars);
goal2nlsat g2s;
expr_ref is_true(m), fml1(m), fml2(m);
is_true = m.mk_fresh_const("is_true", m.mk_bool_sort());
fml = m.mk_iff(is_true, fml);
goal_ref g = alloc(goal, m);
g->assert_expr(fml);
proof_converter_ref pc;
expr_dependency_ref core(m);
model_converter_ref mc;
goal_ref_buffer result;
(*m_nftactic)(g, result, mc, pc, core);
SASSERT(result.size() == 1);
TRACE("qe", result[0]->display(tout););
g2s(*result[0], m_params, m_solver, m_a2b, m_t2x);
// insert variables and their levels.
for (unsigned i = 0; i < qvars.size(); ++i) {
m_bound_bvars.push_back(svector<nlsat::bool_var>());
m_bound_rvars.push_back(nlsat::var_vector());
max_level lvl;
if (is_exists(i)) lvl.m_ex = i; else lvl.m_fa = i;
for (unsigned j = 0; j < qvars[i].size(); ++j) {
app* v = qvars[i][j].get();
if (m_a2b.is_var(v)) {
SASSERT(m.is_bool(v));
nlsat::bool_var b = m_a2b.to_var(v);
m_bound_bvars.back().push_back(b);
set_level(b, lvl);
}
else if (m_t2x.is_var(v)) {
nlsat::var w = m_t2x.to_var(v);
m_bound_rvars.back().push_back(w);
m_rvar2level.setx(w, lvl, max_level());
}
}
}
init_var2expr();
m_is_true = nlsat::literal(m_a2b.to_var(is_true), false);
// insert literals from arithmetical sub-formulas
nlsat::atom_vector const& atoms = m_solver.get_atoms();
for (unsigned i = 0; i < atoms.size(); ++i) {
if (atoms[i]) {
get_level(nlsat::literal(i, false));
}
}
TRACE("qe", tout << fml << "\n";);
}
void init_expr2var(vector<app_ref_vector> const& qvars) {
for (unsigned i = 0; i < qvars.size(); ++i) {
init_expr2var(qvars[i]);
}
}
void init_expr2var(app_ref_vector const& qvars) {
for (unsigned i = 0; i < qvars.size(); ++i) {
app* v = qvars[i];
if (m.is_bool(v)) {
m_a2b.insert(v, m_solver.mk_bool_var());
}
else {
// TODO: assert it is of type Real.
m_t2x.insert(v, m_solver.mk_var(false));
}
}
}
void init_var2expr() {
expr2var::iterator it = m_t2x.begin(), end = m_t2x.end();
for (; it != end; ++it) {
m_x2t.insert(it->m_value, it->m_key);
}
it = m_a2b.begin(), end = m_a2b.end();
for (; it != end; ++it) {
m_b2a.insert(it->m_value, it->m_key);
}
}
// Return false if nlsat assigned noninteger value to an integer variable.
// [copied from nlsat_tactic.cpp]
bool mk_model(model_converter_ref & mc) {
bool ok = true;
model_ref md = alloc(model, m);
arith_util util(m);
expr2var::iterator it = m_t2x.begin(), end = m_t2x.end();
for (; it != end; ++it) {
nlsat::var x = it->m_value;
expr * t = it->m_key;
if (!is_uninterp_const(t) || !m_free_vars.contains(t))
continue;
expr * v;
try {
v = util.mk_numeral(m_rmodel0.value(x), util.is_int(t));
}
catch (z3_error & ex) {
throw ex;
}
catch (z3_exception &) {
v = util.mk_to_int(util.mk_numeral(m_rmodel0.value(x), false));
ok = false;
}
md->register_decl(to_app(t)->get_decl(), v);
}
it = m_a2b.begin(), end = m_a2b.end();
for (; it != end; ++it) {
expr * a = it->m_key;
nlsat::bool_var b = it->m_value;
if (a == 0 || !is_uninterp_const(a) || b == m_is_true.var() || !m_free_vars.contains(a))
continue;
lbool val = m_bmodel0.get(b, l_undef);
if (val == l_undef)
continue; // don't care
md->register_decl(to_app(a)->get_decl(), val == l_true ? m.mk_true() : m.mk_false());
}
mc = model2model_converter(md.get());
return ok;
}
public:
nlqsat(ast_manager& m, qsat_mode_t mode, params_ref const& p):
m(m),
m_mode(mode),
m_params(p),
m_solver(m.limit(), p),
m_nftactic(0),
m_rmodel(m_solver.am()),
m_rmodel0(m_solver.am()),
m_valid_model(false),
m_a2b(m),
m_t2x(m),
m_cancel(false),
m_answer(m),
m_answer_simplify(m),
m_trail(m)
{
m_solver.get_explain().set_signed_project(true);
m_nftactic = mk_tseitin_cnf_tactic(m);
}
virtual ~nlqsat() {
}
void updt_params(params_ref const & p) {
params_ref p2(p);
p2.set_bool("factor", false);
m_solver.updt_params(p2);
}
void collect_param_descrs(param_descrs & r) {
}
void operator()(/* in */ goal_ref const & in,
/* out */ goal_ref_buffer & result,
/* out */ model_converter_ref & mc,
/* out */ proof_converter_ref & pc,
/* out */ expr_dependency_ref & core) {
tactic_report report("nlqsat-tactic", *in);
ptr_vector<expr> fmls;
expr_ref fml(m);
mc = 0; pc = 0; core = 0;
in->get_formulas(fmls);
fml = mk_and(m, fmls.size(), fmls.c_ptr());
if (m_mode == elim_t) {
fml = m.mk_not(fml);
}
reset();
TRACE("qe", tout << fml << "\n";);
hoist(fml);
TRACE("qe", tout << "ex: " << fml << "\n";);
lbool is_sat = check_sat();
switch (is_sat) {
case l_false:
in->reset();
in->inc_depth();
if (m_mode == elim_t) {
fml = mk_and(m_answer);
}
else {
fml = m.mk_false();
}
in->assert_expr(fml);
result.push_back(in.get());
break;
case l_true:
SASSERT(m_mode == qsat_t);
in->reset();
in->inc_depth();
result.push_back(in.get());
if (in->models_enabled()) {
VERIFY(mk_model(mc));
}
break;
case l_undef:
result.push_back(in.get());
std::string s = "search failed";
throw tactic_exception(s.c_str());
}
}
void collect_statistics(statistics & st) const {
st.copy(m_st);
st.update("qsat num rounds", m_stats.m_num_rounds);
}
void reset_statistics() {
m_stats.reset();
m_solver.reset_statistics();
}
void cleanup() {
reset();
}
void set_logic(symbol const & l) {
}
void set_progress_callback(progress_callback * callback) {
}
tactic * translate(ast_manager & m) {
return alloc(nlqsat, m, m_mode, m_params);
}
#if 0
/**
Algorithm:
I := true
while there is M, such that M |= ~B & I:
find P, such that M => P => exists y . ~B & I
; forall y B => ~P
C := core of P with respect to A
; A => ~ C => ~ P
I := I & ~C
Alternative Algorithm:
R := false
while there is M, such that M |= A & ~R:
find I, such that M => I => forall y . B
R := R | I
*/
lbool interpolate(expr* a, expr* b, expr_ref& result) {
SASSERT(m_mode == interp_t);
reset();
app_ref enableA(m), enableB(m);
expr_ref A(m), B(m), fml(m);
expr_ref_vector fmls(m), answer(m);
// varsB are private to B.
nlsat::var_vector vars;
uint_set fvars;
private_vars(a, b, vars, fvars);
enableA = m.mk_const(symbol("#A"), m.mk_bool_sort());
enableB = m.mk_not(enableA);
A = m.mk_implies(enableA, a);
B = m.mk_implies(enableB, m.mk_not(b));
fml = m.mk_and(A, B);
hoist(fml);
nlsat::literal _enableB = nlsat::literal(m_a2b.to_var(enableB), false);
nlsat::literal _enableA = ~_enableB;
while (true) {
m_mode = qsat_t;
// enable B
m_assumptions.reset();
m_assumptions.push_back(_enableB);
lbool is_sat = check_sat();
switch (is_sat) {
case l_undef:
return l_undef;
case l_true:
break;
case l_false:
result = mk_and(answer);
return l_true;
}
// disable B, enable A
m_assumptions.reset();
m_assumptions.push_back(_enableA);
// add blocking clause to solver.
nlsat::scoped_literal_vector core(m_solver);
m_mode = elim_t;
mbp(vars, fvars, core);
// minimize core.
nlsat::literal_vector _core(core.size(), core.c_ptr());
_core.push_back(_enableA);
is_sat = m_solver.check(_core); // TBD: only for quantifier-free A. Generalize output of elim_t to be a core.
switch (is_sat) {
case l_undef:
return l_undef;
case l_true:
UNREACHABLE();
case l_false:
core.reset();
core.append(_core.size(), _core.c_ptr());
break;
}
negate_clause(core);
// keep polarity of enableA, such that clause is only
// used when checking satisfiability of B.
for (unsigned i = 0; i < core.size(); ++i) {
if (core[i].var() == _enableA.var()) core.set(i, ~core[i]);
}
add_clause(core); // Invariant is added as assumption for B.
answer.push_back(clause2fml(core)); // TBD: remove answer literal.
}
}
/**
\brief extract variables that are private to a (not used in b).
vars cover the real variables, and fvars cover the Boolean variables.
TBD: We want fvars to be the complement such that returned core contains
Shared boolean variables, but not the ones private to B.
*/
void private_vars(expr* a, expr* b, nlsat::var_vector& vars, uint_set& fvars) {
app_ref_vector varsA(m), varsB(m);
obj_hashtable<expr> varsAS;
pred_abs abs(m);
abs.get_free_vars(a, varsA);
abs.get_free_vars(b, varsB);
insert_set(varsAS, varsA);
for (unsigned i = 0; i < varsB.size(); ++i) {
if (varsAS.contains(varsB[i].get())) {
varsB[i] = varsB.back();
varsB.pop_back();
--i;
}
}
for (unsigned j = 0; j < varsB.size(); ++j) {
app* v = varsB[j].get();
if (m_a2b.is_var(v)) {
fvars.insert(m_a2b.to_var(v));
}
else if (m_t2x.is_var(v)) {
vars.push_back(m_t2x.to_var(v));
}
}
}
lbool maximize(app* _x, expr* _fml, scoped_anum& result, bool& unbounded) {
expr_ref fml(_fml, m);
reset();
hoist(fml);
nlsat::literal_vector lits;
lbool is_sat = l_true;
nlsat::var x = m_t2x.to_var(_x);
m_mode = qsat_t;
while (is_sat == l_true) {
is_sat = check_sat();
if (is_sat == l_true) {
// m_asms is minimized set of literals that satisfy formula.
nlsat::explain& ex = m_solver.get_explain();
polynomial::manager& pm = m_solver.pm();
anum_manager& am = m_solver.am();
ex.maximize(x, m_asms.size(), m_asms.c_ptr(), result, unbounded);
if (unbounded) {
break;
}
// TBD: assert the new bound on x using the result.
bool is_even = false;
polynomial::polynomial_ref pr(pm);
pr = pm.mk_polynomial(x);
rational r;
am.get_upper(result, r);
// result is algebraic numeral, but polynomials are not defined over extension field.
polynomial::polynomial* p = pr;
nlsat::bool_var b = m_solver.mk_ineq_atom(nlsat::atom::GT, 1, &p, &is_even);
nlsat::literal bound(b, false);
m_solver.mk_clause(1, &bound);
}
}
return is_sat;
}
#endif
};
};
tactic * mk_nlqsat_tactic(ast_manager & m, params_ref const& p) {
return alloc(qe::nlqsat, m, qe::qsat_t, p);
}
tactic * mk_nlqe_tactic(ast_manager & m, params_ref const& p) {
return alloc(qe::nlqsat, m, qe::elim_t, p);
}

38
src/qe/nlqsat.h Normal file
View file

@ -0,0 +1,38 @@
/*++
Copyright (c) 2015 Microsoft Corporation
Module Name:
nlqsat.h
Abstract:
Quantifier Satisfiability Solver for nlsat
Author:
Nikolaj Bjorner (nbjorner) 2015-10-17
Revision History:
--*/
#ifndef QE_NLQSAT_H__
#define QE_NLQSAT_H__
#include "tactic.h"
tactic * mk_nlqsat_tactic(ast_manager & m, params_ref const& p = params_ref());
tactic * mk_nlqe_tactic(ast_manager & m, params_ref const& p = params_ref());
/*
ADD_TACTIC("nlqsat", "apply a NL-QSAT solver.", "mk_nlqsat_tactic(m, p)")
*/
// TBD_TACTIC("nlqe", "apply a NL-QE solver.", "mk_nlqe_tactic(m, p)")
#endif

View file

@ -1,26 +0,0 @@
/*++
Copyright (c) 2015 Microsoft Corporation
--*/
#include "qe_util.h"
#include "bool_rewriter.h"
namespace qe {
expr_ref mk_and(expr_ref_vector const& fmls) {
ast_manager& m = fmls.get_manager();
expr_ref result(m);
bool_rewriter(m).mk_and(fmls.size(), fmls.c_ptr(), result);
return result;
}
expr_ref mk_or(expr_ref_vector const& fmls) {
ast_manager& m = fmls.get_manager();
expr_ref result(m);
bool_rewriter(m).mk_or(fmls.size(), fmls.c_ptr(), result);
return result;
}
}

View file

@ -1,31 +0,0 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
qe_util.h
Abstract:
Utilities for quantifiers.
Author:
Nikolaj Bjorner (nbjorner) 2013-08-28
Revision History:
--*/
#ifndef QE_UTIL_H_
#define QE_UTIL_H_
#include "ast.h"
namespace qe {
expr_ref mk_and(expr_ref_vector const& fmls);
expr_ref mk_or(expr_ref_vector const& fmls);
}
#endif

1176
src/qe/qsat.cpp Normal file

File diff suppressed because it is too large Load diff

135
src/qe/qsat.h Normal file
View file

@ -0,0 +1,135 @@
/*++
Copyright (c) 2015 Microsoft Corporation
Module Name:
qsat.h
Abstract:
Quantifier Satisfiability Solver.
Author:
Nikolaj Bjorner (nbjorner) 2015-5-28
Revision History:
--*/
#ifndef QE_QSAT_H__
#define QE_QSAT_H__
#include "tactic.h"
#include "filter_model_converter.h"
namespace qe {
struct max_level {
unsigned m_ex, m_fa;
max_level(): m_ex(UINT_MAX), m_fa(UINT_MAX) {}
void merge(max_level const& other) {
merge(m_ex, other.m_ex);
merge(m_fa, other.m_fa);
}
static unsigned max(unsigned a, unsigned b) {
if (a == UINT_MAX) return b;
if (b == UINT_MAX) return a;
return std::max(a, b);
}
unsigned max() const {
return max(m_ex, m_fa);
}
void merge(unsigned& lvl, unsigned other) {
lvl = max(lvl, other);
}
std::ostream& display(std::ostream& out) const {
if (m_ex != UINT_MAX) out << "e" << m_ex << " ";
if (m_fa != UINT_MAX) out << "a" << m_fa << " ";
return out;
}
bool operator==(max_level const& other) const {
return
m_ex == other.m_ex &&
m_fa == other.m_fa;
}
};
inline std::ostream& operator<<(std::ostream& out, max_level const& lvl) {
return lvl.display(out);
}
class pred_abs {
ast_manager& m;
vector<app_ref_vector> m_preds;
expr_ref_vector m_asms;
unsigned_vector m_asms_lim;
obj_map<expr, expr*> m_pred2lit; // maintain definitions of predicates.
obj_map<expr, app*> m_lit2pred; // maintain reverse mapping to predicates
obj_map<expr, app*> m_asm2pred; // maintain map from assumptions to predicates
obj_map<expr, expr*> m_pred2asm; // predicates |-> assumptions
expr_ref_vector m_trail;
filter_model_converter_ref m_fmc;
ptr_vector<expr> todo;
obj_map<expr, max_level> m_elevel;
obj_map<func_decl, max_level> m_flevel;
template <typename T>
void dec_keys(obj_map<expr, T*>& map) {
typename obj_map<expr, T*>::iterator it = map.begin(), end = map.end();
for (; it != end; ++it) {
m.dec_ref(it->m_key);
}
}
void add_lit(app* p, app* lit);
void add_asm(app* p, expr* lit);
bool is_predicate(app* a, unsigned l);
void mk_concrete(expr_ref_vector& fmls, obj_map<expr, expr*> const& map);
public:
pred_abs(ast_manager& m);
filter_model_converter* fmc();
void reset();
max_level compute_level(app* e);
void push();
void pop(unsigned num_scopes);
void insert(app* a, max_level const& lvl);
void get_assumptions(model* mdl, expr_ref_vector& asms);
void set_expr_level(app* v, max_level const& lvl);
void set_decl_level(func_decl* v, max_level const& lvl);
void abstract_atoms(expr* fml, max_level& level, expr_ref_vector& defs);
void abstract_atoms(expr* fml, expr_ref_vector& defs);
expr_ref mk_abstract(expr* fml);
void pred2lit(expr_ref_vector& fmls);
expr_ref pred2asm(expr* fml);
void get_free_vars(expr* fml, app_ref_vector& vars);
expr_ref mk_assumption_literal(expr* a, model* mdl, max_level const& lvl, expr_ref_vector& defs);
void add_pred(app* p, app* lit);
app_ref fresh_bool(char const* name);
void display(std::ostream& out) const;
void display(std::ostream& out, expr_ref_vector const& asms) const;
void collect_statistics(statistics& st) const;
};
}
tactic * mk_qsat_tactic(ast_manager & m, params_ref const& p = params_ref());
tactic * mk_qe2_tactic(ast_manager & m, params_ref const& p = params_ref());
tactic * mk_qe_rec_tactic(ast_manager & m, params_ref const& p = params_ref());
/*
ADD_TACTIC("qsat", "apply a QSAT solver.", "mk_qsat_tactic(m, p)")
ADD_TACTIC("qe2", "apply a QSAT based quantifier elimination.", "mk_qe2_tactic(m, p)")
ADD_TACTIC("qe_rec", "apply a QSAT based quantifier elimination recursively.", "mk_qe_rec_tactic(m, p)")
*/
#endif