mirror of
https://github.com/Z3Prover/z3
synced 2025-10-08 00:41:56 +00:00
wip
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
69a9d9f0b0
commit
c3281f08ef
3 changed files with 246 additions and 98 deletions
|
@ -40,8 +40,8 @@ inline std::string lconstraint_kind_string(lconstraint_kind t) {
|
||||||
class lar_base_constraint {
|
class lar_base_constraint {
|
||||||
lconstraint_kind m_kind;
|
lconstraint_kind m_kind;
|
||||||
mpq m_right_side;
|
mpq m_right_side;
|
||||||
bool m_active;
|
bool m_active = false;
|
||||||
bool m_is_auxiliary;
|
bool m_is_auxiliary = false;
|
||||||
unsigned m_j;
|
unsigned m_j;
|
||||||
u_dependency* m_dep;
|
u_dependency* m_dep;
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ public:
|
||||||
|
|
||||||
virtual vector<std::pair<mpq, lpvar>> coeffs() const = 0;
|
virtual vector<std::pair<mpq, lpvar>> coeffs() const = 0;
|
||||||
lar_base_constraint(unsigned j, lconstraint_kind kind, u_dependency* dep, const mpq& right_side) :
|
lar_base_constraint(unsigned j, lconstraint_kind kind, u_dependency* dep, const mpq& right_side) :
|
||||||
m_kind(kind), m_right_side(right_side), m_active(false), m_is_auxiliary(false), m_j(j), m_dep(dep) {}
|
m_kind(kind), m_right_side(right_side), m_j(j), m_dep(dep) {}
|
||||||
virtual ~lar_base_constraint() = default;
|
virtual ~lar_base_constraint() = default;
|
||||||
|
|
||||||
lconstraint_kind kind() const { return m_kind; }
|
lconstraint_kind kind() const { return m_kind; }
|
||||||
|
@ -66,9 +66,13 @@ public:
|
||||||
|
|
||||||
virtual unsigned size() const = 0;
|
virtual unsigned size() const = 0;
|
||||||
virtual mpq get_free_coeff_of_left_side() const { return zero_of_type<mpq>();}
|
virtual mpq get_free_coeff_of_left_side() const { return zero_of_type<mpq>();}
|
||||||
|
virtual lar_term const &lhs() const = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class lar_var_constraint: public lar_base_constraint {
|
class lar_var_constraint: public lar_base_constraint {
|
||||||
|
mutable lar_term * m_lhs = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
lar_var_constraint(unsigned j, lconstraint_kind kind, u_dependency* dep, const mpq& right_side) :
|
lar_var_constraint(unsigned j, lconstraint_kind kind, u_dependency* dep, const mpq& right_side) :
|
||||||
lar_base_constraint(j, kind, dep, right_side) {}
|
lar_base_constraint(j, kind, dep, right_side) {}
|
||||||
|
@ -79,6 +83,11 @@ public:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
unsigned size() const override { return 1;}
|
unsigned size() const override { return 1;}
|
||||||
|
lar_term const &lhs() const override {
|
||||||
|
if (!m_lhs)
|
||||||
|
m_lhs = alloc(lar_term, rational::one(), column());
|
||||||
|
return *m_lhs;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -90,13 +99,14 @@ public:
|
||||||
|
|
||||||
vector<std::pair<mpq, lpvar>> coeffs() const override { return m_term->coeffs_as_vector(); }
|
vector<std::pair<mpq, lpvar>> coeffs() const override { return m_term->coeffs_as_vector(); }
|
||||||
unsigned size() const override { return m_term->size();}
|
unsigned size() const override { return m_term->size();}
|
||||||
|
lar_term const &lhs() const override { return *m_term; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class constraint_set {
|
class constraint_set {
|
||||||
region m_region;
|
region m_region;
|
||||||
column_namer& m_namer;
|
column_namer& m_namer;
|
||||||
u_dependency_manager& m_dep_manager;
|
u_dependency_manager& m_dep_manager;
|
||||||
vector<lar_base_constraint*> m_constraints;
|
ptr_vector<lar_base_constraint> m_constraints;
|
||||||
stacked_value<unsigned> m_constraint_count;
|
stacked_value<unsigned> m_constraint_count;
|
||||||
unsigned_vector m_active;
|
unsigned_vector m_active;
|
||||||
stacked_value<unsigned> m_active_lim;
|
stacked_value<unsigned> m_active_lim;
|
||||||
|
|
|
@ -92,9 +92,9 @@ namespace nla {
|
||||||
m_mon2vars.reset();
|
m_mon2vars.reset();
|
||||||
m_values.reset();
|
m_values.reset();
|
||||||
m_resolvents.reset();
|
m_resolvents.reset();
|
||||||
m_old_constraints.reset();
|
m_assumptions.reset();
|
||||||
m_new_bounds.reset();
|
m_monomials_to_refine.reset();
|
||||||
m_to_refine.reset();
|
m_false_constraints.reset();
|
||||||
m_factored_constraints.reset();
|
m_factored_constraints.reset();
|
||||||
m_max_monomial_degree = 0;
|
m_max_monomial_degree = 0;
|
||||||
m_coi.init();
|
m_coi.init();
|
||||||
|
@ -131,7 +131,7 @@ namespace nla {
|
||||||
auto rhs = lo_bound.x;
|
auto rhs = lo_bound.x;
|
||||||
auto dep = src.get_column_lower_bound_witness(v);
|
auto dep = src.get_column_lower_bound_witness(v);
|
||||||
auto ci = dst.add_var_bound(v, k, rhs);
|
auto ci = dst.add_var_bound(v, k, rhs);
|
||||||
m_ci2dep.setx(ci, dep, nullptr);
|
m_assumptions.insert(ci, assumptions{dep});
|
||||||
}
|
}
|
||||||
if (src.column_has_upper_bound(v)) {
|
if (src.column_has_upper_bound(v)) {
|
||||||
auto hi_bound = src.get_upper_bound(v);
|
auto hi_bound = src.get_upper_bound(v);
|
||||||
|
@ -140,7 +140,7 @@ namespace nla {
|
||||||
auto rhs = hi_bound.x;
|
auto rhs = hi_bound.x;
|
||||||
auto dep = src.get_column_upper_bound_witness(v);
|
auto dep = src.get_column_upper_bound_witness(v);
|
||||||
auto ci = dst.add_var_bound(v, k, rhs);
|
auto ci = dst.add_var_bound(v, k, rhs);
|
||||||
m_ci2dep.setx(ci, dep, nullptr);
|
m_assumptions.insert(ci, assumptions{dep});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto const &[v, vars] : m_mon2vars)
|
for (auto const &[v, vars] : m_mon2vars)
|
||||||
|
@ -163,6 +163,7 @@ namespace nla {
|
||||||
// 2. bounds assumptions are added as assumptions to the lemma.
|
// 2. bounds assumptions are added as assumptions to the lemma.
|
||||||
//
|
//
|
||||||
void stellensatz::add_lemma(lp::explanation const& ex1, vector<ineq> const& ineqs) {
|
void stellensatz::add_lemma(lp::explanation const& ex1, vector<ineq> const& ineqs) {
|
||||||
|
TRACE(arith, display(tout));
|
||||||
auto& lra = c().lra_solver();
|
auto& lra = c().lra_solver();
|
||||||
lp::explanation ex2;
|
lp::explanation ex2;
|
||||||
lemma_builder new_lemma(c(), "stellensatz");
|
lemma_builder new_lemma(c(), "stellensatz");
|
||||||
|
@ -185,19 +186,18 @@ namespace nla {
|
||||||
if (m_constraints_in_conflict.contains(ci))
|
if (m_constraints_in_conflict.contains(ci))
|
||||||
return;
|
return;
|
||||||
m_constraints_in_conflict.insert(ci);
|
m_constraints_in_conflict.insert(ci);
|
||||||
auto dep = m_ci2dep[ci];
|
if (!m_assumptions.contains(ci))
|
||||||
m_solver.lra().push_explanation(dep, ex);
|
|
||||||
lp::constraint_index old_ci;
|
|
||||||
if (m_old_constraints.find(ci, old_ci))
|
|
||||||
explain_constraint(new_lemma, old_ci, ex);
|
|
||||||
if (!m_new_bounds.contains(ci))
|
|
||||||
return;
|
return;
|
||||||
auto const &bounds = m_new_bounds[ci];
|
auto const &bounds = m_assumptions[ci];
|
||||||
for (auto const &b : bounds) {
|
for (auto const &b : bounds) {
|
||||||
if (std::holds_alternative<u_dependency *>(b)) {
|
if (std::holds_alternative<u_dependency *>(b)) {
|
||||||
auto dep = *std::get_if<u_dependency *>(&b);
|
auto dep = *std::get_if<u_dependency *>(&b);
|
||||||
m_solver.lra().push_explanation(dep, ex);
|
m_solver.lra().push_explanation(dep, ex);
|
||||||
}
|
}
|
||||||
|
else if (std::holds_alternative<lp::constraint_index>(b)) {
|
||||||
|
auto c = *std::get_if<lp::constraint_index>(&b);
|
||||||
|
explain_constraint(new_lemma, c, ex);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
//
|
//
|
||||||
// the inequality was posted as an assumption
|
// the inequality was posted as an assumption
|
||||||
|
@ -268,19 +268,19 @@ namespace nla {
|
||||||
void stellensatz::saturate_signs(lpvar j, rational const& val_j, svector<lpvar> const& vars,
|
void stellensatz::saturate_signs(lpvar j, rational const& val_j, svector<lpvar> const& vars,
|
||||||
rational const& val_vars) {
|
rational const& val_vars) {
|
||||||
if (val_vars == 0 && val_j != 0) {
|
if (val_vars == 0 && val_j != 0) {
|
||||||
bound_justifications bounds;
|
assumptions bounds;
|
||||||
lbool sign = add_bounds(vars, bounds);
|
lbool sign = add_bounds(vars, bounds);
|
||||||
VERIFY(sign == l_undef);
|
VERIFY(sign == l_undef);
|
||||||
add_ineq("signs = 0", bounds, j, lp::lconstraint_kind::EQ, rational(0));
|
add_ineq("signs = 0", bounds, j, lp::lconstraint_kind::EQ, rational(0));
|
||||||
}
|
}
|
||||||
else if (val_j <= 0 && 0 < val_vars) {
|
else if (val_j <= 0 && 0 < val_vars) {
|
||||||
bound_justifications bounds;
|
assumptions bounds;
|
||||||
lbool sign = add_bounds(vars, bounds);
|
lbool sign = add_bounds(vars, bounds);
|
||||||
VERIFY(sign == l_false);
|
VERIFY(sign == l_false);
|
||||||
add_ineq("signs > 0", bounds, j, lp::lconstraint_kind::GT, rational(0));
|
add_ineq("signs > 0", bounds, j, lp::lconstraint_kind::GT, rational(0));
|
||||||
}
|
}
|
||||||
else if (val_j >= 0 && 0 > val_vars) {
|
else if (val_j >= 0 && 0 > val_vars) {
|
||||||
bound_justifications bounds;
|
assumptions bounds;
|
||||||
lbool sign = add_bounds(vars, bounds);
|
lbool sign = add_bounds(vars, bounds);
|
||||||
VERIFY(sign == l_true);
|
VERIFY(sign == l_true);
|
||||||
add_ineq("signs < 0", bounds, j, lp::lconstraint_kind::LT, rational(0));
|
add_ineq("signs < 0", bounds, j, lp::lconstraint_kind::LT, rational(0));
|
||||||
|
@ -294,19 +294,19 @@ namespace nla {
|
||||||
//
|
//
|
||||||
void stellensatz::saturate_units(lpvar j, svector<lpvar> const &vars) {
|
void stellensatz::saturate_units(lpvar j, svector<lpvar> const &vars) {
|
||||||
lpvar non_unit = lp::null_lpvar;
|
lpvar non_unit = lp::null_lpvar;
|
||||||
bool sign = false;
|
int sign = 1;
|
||||||
for (auto v : vars) {
|
for (auto v : vars) {
|
||||||
if (m_values[v] == 1)
|
if (m_values[v] == 1)
|
||||||
continue;
|
continue;
|
||||||
if (m_values[v] == -1) {
|
if (m_values[v] == -1) {
|
||||||
sign = !sign;
|
sign = -sign;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (non_unit != lp::null_lpvar)
|
if (non_unit != lp::null_lpvar)
|
||||||
return;
|
return;
|
||||||
non_unit = v;
|
non_unit = v;
|
||||||
}
|
}
|
||||||
bound_justifications bounds;
|
assumptions bounds;
|
||||||
for (auto v : vars) {
|
for (auto v : vars) {
|
||||||
if (m_values[v] == 1 || m_values[v] == -1) {
|
if (m_values[v] == 1 || m_values[v] == -1) {
|
||||||
bound b(v, lp::lconstraint_kind::EQ, m_values[v]);
|
bound b(v, lp::lconstraint_kind::EQ, m_values[v]);
|
||||||
|
@ -316,8 +316,12 @@ namespace nla {
|
||||||
// assert j = +/- non_unit
|
// assert j = +/- non_unit
|
||||||
lp::lar_term lhs;
|
lp::lar_term lhs;
|
||||||
lhs.add_monomial(rational(1), j);
|
lhs.add_monomial(rational(1), j);
|
||||||
lhs.add_monomial(rational(sign ? 1 : -1), non_unit);
|
if (non_unit != lp::null_lpvar) {
|
||||||
add_ineq("unit mul", bounds, lhs, lp::lconstraint_kind::EQ, rational(0));
|
lhs.add_monomial(rational(-sign), non_unit);
|
||||||
|
add_ineq("unit mul", bounds, lhs, lp::lconstraint_kind::EQ, rational(0));
|
||||||
|
} else {
|
||||||
|
add_ineq("unit mul", bounds, lhs, lp::lconstraint_kind::EQ, rational(sign));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Monotonicity axioms:
|
// Monotonicity axioms:
|
||||||
|
@ -355,7 +359,7 @@ namespace nla {
|
||||||
// x > 1, y > 0 => xy > y
|
// x > 1, y > 0 => xy > y
|
||||||
// x > 1, y < 1 => -xy > -y
|
// x > 1, y < 1 => -xy > -y
|
||||||
void stellensatz::saturate_monotonicity(lpvar j, rational const& val_j, lpvar x, int sign_x, lpvar y, int sign_y) {
|
void stellensatz::saturate_monotonicity(lpvar j, rational const& val_j, lpvar x, int sign_x, lpvar y, int sign_y) {
|
||||||
bound_justifications bounds;
|
assumptions bounds;
|
||||||
bound b1(x, sign_x < 0 ? lp::lconstraint_kind::LT : lp::lconstraint_kind::GT, rational(sign_x));
|
bound b1(x, sign_x < 0 ? lp::lconstraint_kind::LT : lp::lconstraint_kind::GT, rational(sign_x));
|
||||||
bound b2(y, sign_y < 0 ? lp::lconstraint_kind::LT : lp::lconstraint_kind::GT, rational(0));
|
bound b2(y, sign_y < 0 ? lp::lconstraint_kind::LT : lp::lconstraint_kind::GT, rational(0));
|
||||||
bounds.push_back(b1);
|
bounds.push_back(b1);
|
||||||
|
@ -376,7 +380,7 @@ namespace nla {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// it is a square.
|
// it is a square.
|
||||||
bound_justifications bounds;
|
assumptions bounds;
|
||||||
add_ineq("squares", bounds, j, lp::lconstraint_kind::GE, rational(0));
|
add_ineq("squares", bounds, j, lp::lconstraint_kind::GE, rational(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,7 +399,7 @@ namespace nla {
|
||||||
}
|
}
|
||||||
|
|
||||||
lp::constraint_index stellensatz::add_ineq(char const* rule,
|
lp::constraint_index stellensatz::add_ineq(char const* rule,
|
||||||
bound_justifications const& bounds,
|
assumptions const& bounds,
|
||||||
lp::lar_term const& t, lp::lconstraint_kind k,
|
lp::lar_term const& t, lp::lconstraint_kind k,
|
||||||
rational const& rhs) {
|
rational const& rhs) {
|
||||||
SASSERT(!t.coeffs_as_vector().empty());
|
SASSERT(!t.coeffs_as_vector().empty());
|
||||||
|
@ -406,17 +410,15 @@ namespace nla {
|
||||||
display_constraint(tout << rule << ": ", new_ci) << "\n";
|
display_constraint(tout << rule << ": ", new_ci) << "\n";
|
||||||
if (!bounds.empty()) display(tout << "\t <- ", bounds) << "\n";);
|
if (!bounds.empty()) display(tout << "\t <- ", bounds) << "\n";);
|
||||||
SASSERT(m_values.size() - 1 == ti);
|
SASSERT(m_values.size() - 1 == ti);
|
||||||
m_new_bounds.insert(new_ci, bounds);
|
m_assumptions.insert(new_ci, bounds);
|
||||||
m_ci2dep.setx(new_ci, nullptr, nullptr);
|
|
||||||
init_occurs(new_ci);
|
init_occurs(new_ci);
|
||||||
return new_ci;
|
return new_ci;
|
||||||
}
|
}
|
||||||
|
|
||||||
lp::constraint_index stellensatz::add_ineq(char const* rule, bound_justifications const& bounds, lpvar j, lp::lconstraint_kind k,
|
lp::constraint_index stellensatz::add_ineq(char const* rule, assumptions const& bounds, lpvar j, lp::lconstraint_kind k,
|
||||||
rational const& rhs) {
|
rational const& rhs) {
|
||||||
auto new_ci = m_solver.lra().add_var_bound(j, k, rhs);
|
auto new_ci = m_solver.lra().add_var_bound(j, k, rhs);
|
||||||
m_new_bounds.insert(new_ci, bounds);
|
m_assumptions.insert(new_ci, bounds);
|
||||||
m_ci2dep.setx(new_ci, nullptr, nullptr);
|
|
||||||
init_occurs(new_ci);
|
init_occurs(new_ci);
|
||||||
return new_ci;
|
return new_ci;
|
||||||
}
|
}
|
||||||
|
@ -429,8 +431,9 @@ namespace nla {
|
||||||
|
|
||||||
void stellensatz::init_occurs(lp::constraint_index ci) {
|
void stellensatz::init_occurs(lp::constraint_index ci) {
|
||||||
auto const &con = m_solver.lra().constraints()[ci];
|
auto const &con = m_solver.lra().constraints()[ci];
|
||||||
for (auto [coeff, v] : con.coeffs()) {
|
for (auto cv : con.lhs()) {
|
||||||
if (m_mon2vars.contains(v)) {
|
auto v = cv.j();
|
||||||
|
if (is_mon_var(v)) {
|
||||||
for (auto w : m_mon2vars[v]) {
|
for (auto w : m_mon2vars[v]) {
|
||||||
if (w >= m_occurs.size())
|
if (w >= m_occurs.size())
|
||||||
m_occurs.resize(w + 1);
|
m_occurs.resize(w + 1);
|
||||||
|
@ -464,9 +467,43 @@ namespace nla {
|
||||||
return i == a.size();
|
return i == a.size();
|
||||||
};
|
};
|
||||||
|
|
||||||
for (unsigned it = 0; it < m_to_refine.size(); ++it) {
|
unsigned initial_false_constraints = m_false_constraints.size();
|
||||||
auto j = m_to_refine[it];
|
for (unsigned it = 0; it < m_false_constraints.size(); ++it) {
|
||||||
|
if (it > 5*initial_false_constraints)
|
||||||
|
break;
|
||||||
|
auto ci1 = m_false_constraints[it];
|
||||||
|
auto const &con = m_solver.lra().constraints()[ci1];
|
||||||
|
for (auto const &cv1 : con.lhs()) {
|
||||||
|
auto j = cv1.j();
|
||||||
|
if (!is_mon_var(j))
|
||||||
|
continue;
|
||||||
|
auto vars = m_mon2vars[j];
|
||||||
|
if (vars.size() > m_max_monomial_degree)
|
||||||
|
continue;
|
||||||
|
for (auto v : vars) {
|
||||||
|
if (v >= m_occurs.size())
|
||||||
|
continue;
|
||||||
|
svector<lpvar> _vars;
|
||||||
|
_vars.push_back(v);
|
||||||
|
for (unsigned cidx = 0; cidx < m_occurs[v].size(); ++cidx) {
|
||||||
|
auto ci2 = m_occurs[v][cidx];
|
||||||
|
for (auto const & cv2 : m_solver.lra().constraints()[ci2].lhs()) {
|
||||||
|
auto u = cv2.j();
|
||||||
|
if (u == v && is_resolvable(ci1, cv1.coeff(), ci2, cv2.coeff()))
|
||||||
|
resolve(j, ci1, saturate_constraint(ci2, j, _vars));
|
||||||
|
else if (is_mon_var(u) && is_subset(m_mon2vars[u], vars) &&
|
||||||
|
is_resolvable(ci1, cv1.coeff(), ci2, cv2.coeff()))
|
||||||
|
resolve(j, ci1, saturate_constraint(ci2, j, m_mon2vars[u]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
for (unsigned it = 0; it < m_monomials_to_refine.size(); ++it) {
|
||||||
|
auto j = m_monomials_to_refine[it];
|
||||||
auto vars = m_mon2vars[j];
|
auto vars = m_mon2vars[j];
|
||||||
|
TRACE(arith, tout << "j" << j << " " << vars << "\n");
|
||||||
for (auto v : vars) {
|
for (auto v : vars) {
|
||||||
if (v >= m_occurs.size())
|
if (v >= m_occurs.size())
|
||||||
continue;
|
continue;
|
||||||
|
@ -474,34 +511,115 @@ namespace nla {
|
||||||
_vars.push_back(v);
|
_vars.push_back(v);
|
||||||
for (unsigned cidx = 0; cidx < m_occurs[v].size(); ++cidx) {
|
for (unsigned cidx = 0; cidx < m_occurs[v].size(); ++cidx) {
|
||||||
auto ci = m_occurs[v][cidx];
|
auto ci = m_occurs[v][cidx];
|
||||||
for (unsigned uidx = 0; uidx < m_solver.lra().constraints()[ci].coeffs().size(); ++uidx) {
|
for (auto const &cv1 : m_solver.lra().constraints()[ci].lhs()) {
|
||||||
auto const &[coeff, u] = m_solver.lra().constraints()[ci].coeffs()[uidx];
|
auto u = cv1.j();
|
||||||
if (u == v)
|
if (u == v)
|
||||||
saturate_constraint(ci, j, _vars);
|
saturate_constraint(ci, j, _vars);
|
||||||
else if (m_mon2vars.contains(u) && is_subset(m_mon2vars[u], vars))
|
else if (is_mon_var(u) && is_subset(m_mon2vars[u], vars))
|
||||||
saturate_constraint(ci, j, m_mon2vars[u]);
|
saturate_constraint(ci, j, m_mon2vars[u]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
IF_VERBOSE(5,
|
IF_VERBOSE(5,
|
||||||
c().lra_solver().display(verbose_stream() << "original\n");
|
c().lra_solver().display(verbose_stream() << "original\n");
|
||||||
c().display(verbose_stream());
|
c().display(verbose_stream());
|
||||||
display(verbose_stream() << "saturated\n"));
|
display(verbose_stream() << "saturated\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool stellensatz::is_resolvable(lp::constraint_index ci1, rational const& c1, lp::constraint_index ci2,
|
||||||
|
rational const& c2) const {
|
||||||
|
SASSERT(c1 != 0);
|
||||||
|
SASSERT(c2 != 0);
|
||||||
|
auto const &con1 = m_solver.lra().constraints()[ci1];
|
||||||
|
auto const &con2 = m_solver.lra().constraints()[ci2];
|
||||||
|
auto k1 = con1.kind();
|
||||||
|
auto k2 = con2.kind();
|
||||||
|
for (auto const& cv : con1.lhs())
|
||||||
|
if (is_mon_var(cv.j()) && m_mon2vars[cv.j()].size() > m_max_monomial_degree)
|
||||||
|
return false;
|
||||||
|
for (auto const &cv : con2.lhs())
|
||||||
|
if (is_mon_var(cv.j()) && m_mon2vars[cv.j()].size() > m_max_monomial_degree)
|
||||||
|
return false;
|
||||||
|
bool same_sign = (c1.is_pos() == c2.is_pos());
|
||||||
|
if (k1 == lp::lconstraint_kind::EQ)
|
||||||
|
return true;
|
||||||
|
if (k2 == lp::lconstraint_kind::EQ)
|
||||||
|
return true;
|
||||||
|
bool is_le1 = (k1 == lp::lconstraint_kind::LE || k1 == lp::lconstraint_kind::LT);
|
||||||
|
bool is_le2 = (k2 == lp::lconstraint_kind::LE || k2 == lp::lconstraint_kind::LT);
|
||||||
|
if ((is_le1 == is_le2) && !same_sign)
|
||||||
|
return true;
|
||||||
|
if ((is_le1 != is_le2) && same_sign)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stellensatz::resolve(lpvar j, lp::constraint_index ci1, lp::constraint_index ci2) {
|
||||||
|
// resolut of saturate_constraint could swap inequality,
|
||||||
|
// so the premise of is_resolveable may not hold.
|
||||||
|
return;
|
||||||
|
auto const &constraints = m_solver.lra().constraints();
|
||||||
|
if (!constraints.valid_index(ci1))
|
||||||
|
return;
|
||||||
|
if (!constraints.valid_index(ci2))
|
||||||
|
return;
|
||||||
|
auto const &con1 = constraints[ci1];
|
||||||
|
auto const &con2 = constraints[ci2];
|
||||||
|
auto k1 = con1.kind();
|
||||||
|
auto k2 = con2.kind();
|
||||||
|
auto const & lhs1 = con1.lhs();
|
||||||
|
auto const & lhs2 = con2.lhs();
|
||||||
|
auto const& c1 = lhs1.get_coeff(j);
|
||||||
|
auto const& c2 = lhs2.get_coeff(j);
|
||||||
|
verbose_stream() << "resolve on " << m_mon2vars[j] << " c1: " << c1 << " c2: " << c2 << "\n";
|
||||||
|
display_constraint(verbose_stream(), ci1) << "\n";
|
||||||
|
display_constraint(verbose_stream(), ci2) << "\n";
|
||||||
|
rational mul1, mul2;
|
||||||
|
bool is_le1 = (k1 == lp::lconstraint_kind::LE || k1 == lp::lconstraint_kind::LT);
|
||||||
|
bool is_le2 = (k2 == lp::lconstraint_kind::LE || k2 == lp::lconstraint_kind::LT);
|
||||||
|
bool is_strict = (k1 == lp::lconstraint_kind::LT || k2 == lp::lconstraint_kind::LT);
|
||||||
|
if (k1 == lp::lconstraint_kind::EQ) {
|
||||||
|
mul1 = (c1 > 0 ? -1 : 1) * c2;
|
||||||
|
mul2 = (c1 > 0 ? c1 : -c1);
|
||||||
|
}
|
||||||
|
else if (k2 == lp::lconstraint_kind::EQ) {
|
||||||
|
mul1 = (c2 > 0 ? c2 : -c2);
|
||||||
|
mul2 = (c2 > 0 ? -1 : 1) * c1;
|
||||||
|
}
|
||||||
|
else if (is_le1 == is_le2) {
|
||||||
|
SASSERT(c1.is_pos() != c2.is_pos());
|
||||||
|
mul1 = abs(c2);
|
||||||
|
mul2 = abs(c1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SASSERT(c1.is_pos() == c2.is_pos());
|
||||||
|
mul1 = abs(c2);
|
||||||
|
mul2 = -abs(c1);
|
||||||
|
}
|
||||||
|
auto lhs = mul1 * lhs1 + mul2 * lhs2;
|
||||||
|
auto rhs = mul1 * con1.rhs() + mul2 * con2.rhs();
|
||||||
|
assumptions bounds;
|
||||||
|
bounds.push_back(ci1);
|
||||||
|
bounds.push_back(ci2);
|
||||||
|
auto new_ci = add_ineq("resolve", bounds, lhs, k1, rhs);
|
||||||
|
insert_monomials_from_constraint(new_ci);
|
||||||
|
display_constraint(verbose_stream(), new_ci) << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
// multiply by remaining vars
|
// multiply by remaining vars
|
||||||
void stellensatz::saturate_constraint(lp::constraint_index old_ci, lpvar mi, svector<lpvar> const& xs) {
|
lp::constraint_index stellensatz::saturate_constraint(lp::constraint_index old_ci, lpvar mi, svector<lpvar> const& xs) {
|
||||||
resolvent r = {old_ci, mi, xs};
|
resolvent r = {old_ci, mi, xs};
|
||||||
if (m_resolvents.contains(r))
|
if (m_resolvents.contains(r))
|
||||||
return;
|
return lp::null_ci;
|
||||||
m_resolvents.insert(r);
|
m_resolvents.insert(r);
|
||||||
lp::lar_base_constraint const& con = m_solver.lra().constraints()[old_ci];
|
lp::lar_base_constraint const& con = m_solver.lra().constraints()[old_ci];
|
||||||
auto const& lhs = con.coeffs();
|
auto const& lhs = con.lhs();
|
||||||
auto const& rhs = con.rhs();
|
auto const& rhs = con.rhs();
|
||||||
auto k = con.kind();
|
auto k = con.kind();
|
||||||
if (k == lp::lconstraint_kind::NE || k == lp::lconstraint_kind::EQ)
|
if (k == lp::lconstraint_kind::NE || k == lp::lconstraint_kind::EQ)
|
||||||
return; // not supported
|
return lp::null_ci; // not supported
|
||||||
|
|
||||||
|
|
||||||
// xs is a proper subset of vars in mi
|
// xs is a proper subset of vars in mi
|
||||||
|
@ -514,19 +632,19 @@ namespace nla {
|
||||||
SASSERT(!vars.empty());
|
SASSERT(!vars.empty());
|
||||||
SASSERT(vars.size() + xs.size() == m_mon2vars[mi].size());
|
SASSERT(vars.size() + xs.size() == m_mon2vars[mi].size());
|
||||||
|
|
||||||
bound_justifications bounds;
|
assumptions bounds;
|
||||||
// compute bounds constraints and sign of vars
|
// compute bounds constraints and sign of vars
|
||||||
lbool sign = add_bounds(vars, bounds);
|
lbool sign = add_bounds(vars, bounds);
|
||||||
lp::lar_term new_lhs;
|
lp::lar_term new_lhs;
|
||||||
rational new_rhs(rhs);
|
rational new_rhs(rhs);
|
||||||
for (auto const & [coeff, v] : lhs) {
|
for (auto const & cv : lhs) {
|
||||||
unsigned old_sz = vars.size();
|
unsigned old_sz = vars.size();
|
||||||
if (m_mon2vars.contains(v))
|
if (is_mon_var(cv.j()))
|
||||||
vars.append(m_mon2vars[v]);
|
vars.append(m_mon2vars[cv.j()]);
|
||||||
else
|
else
|
||||||
vars.push_back(v);
|
vars.push_back(cv.j());
|
||||||
lpvar new_monic_var = add_monomial(vars);
|
lpvar new_monic_var = add_monomial(vars);
|
||||||
new_lhs.add_monomial(coeff, new_monic_var);
|
new_lhs.add_monomial(cv.coeff(), new_monic_var);
|
||||||
vars.shrink(old_sz);
|
vars.shrink(old_sz);
|
||||||
}
|
}
|
||||||
if (rhs != 0) {
|
if (rhs != 0) {
|
||||||
|
@ -550,12 +668,13 @@ namespace nla {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bounds.push_back(old_ci);
|
||||||
auto new_ci = add_ineq("superpose", bounds, new_lhs, k, new_rhs);
|
auto new_ci = add_ineq("superpose", bounds, new_lhs, k, new_rhs);
|
||||||
IF_VERBOSE(4, display_constraint(verbose_stream(), old_ci) << " -> ";
|
IF_VERBOSE(4, display_constraint(verbose_stream(), old_ci) << " -> ";
|
||||||
display_constraint(verbose_stream(), new_lhs.coeffs_as_vector(), k, new_rhs) << "\n");
|
display_constraint(verbose_stream(), new_lhs.coeffs_as_vector(), k, new_rhs) << "\n");
|
||||||
insert_monomials_from_constraint(new_ci);
|
insert_monomials_from_constraint(new_ci);
|
||||||
m_old_constraints.insert(new_ci, old_ci);
|
|
||||||
m_factored_constraints.insert(new_ci); // don't bother to factor this because it comes from factors already
|
m_factored_constraints.insert(new_ci); // don't bother to factor this because it comes from factors already
|
||||||
|
return new_ci;
|
||||||
}
|
}
|
||||||
|
|
||||||
// call polynomial factorization using the polynomial manager
|
// call polynomial factorization using the polynomial manager
|
||||||
|
@ -588,7 +707,7 @@ namespace nla {
|
||||||
auto v = kv.j();
|
auto v = kv.j();
|
||||||
while (v >= m_pm.num_vars())
|
while (v >= m_pm.num_vars())
|
||||||
m_pm.mk_var();
|
m_pm.mk_var();
|
||||||
if (m_mon2vars.contains(v)) {
|
if (is_mon_var(v)) {
|
||||||
auto const &vars = m_mon2vars[v];
|
auto const &vars = m_mon2vars[v];
|
||||||
ms.push_back(m_pm.mk_monomial(vars.size(), vars.data()));
|
ms.push_back(m_pm.mk_monomial(vars.size(), vars.data()));
|
||||||
}
|
}
|
||||||
|
@ -624,6 +743,7 @@ namespace nla {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool stellensatz::saturate_factors(lp::explanation &ex, vector<ineq> &ineqs) {
|
bool stellensatz::saturate_factors(lp::explanation &ex, vector<ineq> &ineqs) {
|
||||||
|
return true;
|
||||||
auto indices = m_solver.lra().constraints().indices();
|
auto indices = m_solver.lra().constraints().indices();
|
||||||
return all_of(indices, [&](auto ci) { return saturate_factors(ci, ex, ineqs); });
|
return all_of(indices, [&](auto ci) { return saturate_factors(ci, ex, ineqs); });
|
||||||
}
|
}
|
||||||
|
@ -633,12 +753,12 @@ namespace nla {
|
||||||
return true;
|
return true;
|
||||||
m_factored_constraints.insert(ci);
|
m_factored_constraints.insert(ci);
|
||||||
auto const &con = m_solver.lra().constraints()[ci];
|
auto const &con = m_solver.lra().constraints()[ci];
|
||||||
if (all_of(con.coeffs(), [&](auto const& cv) { return !m_mon2vars.contains(cv.second); }))
|
if (all_of(con.lhs(), [&](auto const& cv) { return !is_mon_var(cv.j()); }))
|
||||||
return true;
|
return true;
|
||||||
term_offset t;
|
term_offset t;
|
||||||
// ignore nested terms and nested polynomials..
|
// ignore nested terms and nested polynomials..
|
||||||
for (auto const& [coeff, v] : con.coeffs())
|
for (auto const& cv : con.lhs())
|
||||||
t.first.add_monomial(coeff, v);
|
t.first.add_monomial(cv.coeff(), cv.j());
|
||||||
t.second = -con.rhs();
|
t.second = -con.rhs();
|
||||||
|
|
||||||
vector<std::pair<term_offset, unsigned>> factors;
|
vector<std::pair<term_offset, unsigned>> factors;
|
||||||
|
@ -657,7 +777,7 @@ namespace nla {
|
||||||
bool is_square = all_of(factors, [&](auto const &f) { return f.second % 2 == 0; });
|
bool is_square = all_of(factors, [&](auto const &f) { return f.second % 2 == 0; });
|
||||||
if (is_square) {
|
if (is_square) {
|
||||||
auto v = add_term(t);
|
auto v = add_term(t);
|
||||||
bound_justifications bounds;
|
assumptions bounds;
|
||||||
add_ineq("squares", bounds, v, lp::lconstraint_kind::GE, rational(0));
|
add_ineq("squares", bounds, v, lp::lconstraint_kind::GE, rational(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -691,7 +811,7 @@ namespace nla {
|
||||||
SASSERT(k < factors.size());
|
SASSERT(k < factors.size());
|
||||||
|
|
||||||
auto v = add_term(factors[k].first);
|
auto v = add_term(factors[k].first);
|
||||||
bound_justifications bounds;
|
assumptions bounds;
|
||||||
bound b(v, lp::lconstraint_kind::EQ, rational(0));
|
bound b(v, lp::lconstraint_kind::EQ, rational(0));
|
||||||
bounds.push_back(b);
|
bounds.push_back(b);
|
||||||
add_ineq("factor = 0", bounds, v, lp::lconstraint_kind::EQ, rational(0));
|
add_ineq("factor = 0", bounds, v, lp::lconstraint_kind::EQ, rational(0));
|
||||||
|
@ -704,7 +824,7 @@ namespace nla {
|
||||||
for (auto & f : factors) {
|
for (auto & f : factors) {
|
||||||
if (f.second % 2 == 0)
|
if (f.second % 2 == 0)
|
||||||
continue;
|
continue;
|
||||||
bound_justifications bounds;
|
assumptions bounds;
|
||||||
auto v = add_term(f.first);
|
auto v = add_term(f.first);
|
||||||
auto k = m_values[v] > 0 ? lp::lconstraint_kind::GE : lp::lconstraint_kind::LE;
|
auto k = m_values[v] > 0 ? lp::lconstraint_kind::GE : lp::lconstraint_kind::LE;
|
||||||
bounds.push_back(bound(v, k, rational(0)));
|
bounds.push_back(bound(v, k, rational(0)));
|
||||||
|
@ -714,7 +834,9 @@ namespace nla {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((prod > 0 && k == lp::lconstraint_kind::LE) || (prod < 0 && k == lp::lconstraint_kind::GE)) {
|
if ((prod > 0 && k == lp::lconstraint_kind::LE) || (prod < 0 && k == lp::lconstraint_kind::GE)) {
|
||||||
|
return true;
|
||||||
// this is a conflict with the current evaluation. Produce a lemma that blocks
|
// this is a conflict with the current evaluation. Produce a lemma that blocks
|
||||||
|
// TODO, need to check if variables use fresh monomials
|
||||||
ex.push_back(ci);
|
ex.push_back(ci);
|
||||||
for (auto &f : factors) {
|
for (auto &f : factors) {
|
||||||
auto [t, offset] = f.first;
|
auto [t, offset] = f.first;
|
||||||
|
@ -736,7 +858,7 @@ namespace nla {
|
||||||
// add bound assumptions from vars
|
// add bound assumptions from vars
|
||||||
// return the sign of the product of vars under the current interpretation.
|
// return the sign of the product of vars under the current interpretation.
|
||||||
//
|
//
|
||||||
lbool stellensatz::add_bounds(svector<lpvar> const& vars, bound_justifications& bounds) {
|
lbool stellensatz::add_bounds(svector<lpvar> const& vars, assumptions& bounds) {
|
||||||
bool sign = false;
|
bool sign = false;
|
||||||
auto &src = c().lra_solver();
|
auto &src = c().lra_solver();
|
||||||
auto &dst = m_solver.lra();
|
auto &dst = m_solver.lra();
|
||||||
|
@ -827,19 +949,20 @@ namespace nla {
|
||||||
// other approach: use a lex ordering on monomials and insert the lex leading monomial.
|
// other approach: use a lex ordering on monomials and insert the lex leading monomial.
|
||||||
// to avoid blowup, only insert monomials up to a certain degree.
|
// to avoid blowup, only insert monomials up to a certain degree.
|
||||||
void stellensatz::insert_monomials_from_constraint(lp::constraint_index ci) {
|
void stellensatz::insert_monomials_from_constraint(lp::constraint_index ci) {
|
||||||
if (constraint_is_true(ci))
|
if (/*false && */ constraint_is_true(ci))
|
||||||
return;
|
return;
|
||||||
|
m_false_constraints.insert(ci);
|
||||||
auto const& con = m_solver.lra().constraints()[ci];
|
auto const& con = m_solver.lra().constraints()[ci];
|
||||||
for (auto [coeff, v] : con.coeffs())
|
for (auto cv : con.lhs())
|
||||||
if (m_mon2vars.contains(v) && m_mon2vars[v].size() <= m_max_monomial_degree)
|
if (is_mon_var(cv.j()) && m_mon2vars[cv.j()].size() <= m_max_monomial_degree)
|
||||||
m_to_refine.insert(v);
|
m_monomials_to_refine.insert(cv.j());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool stellensatz::constraint_is_true(lp::constraint_index ci) {
|
bool stellensatz::constraint_is_true(lp::constraint_index ci) const {
|
||||||
auto const& con = m_solver.lra().constraints()[ci];
|
auto const& con = m_solver.lra().constraints()[ci];
|
||||||
auto lhs = -con.rhs();
|
auto lhs = -con.rhs();
|
||||||
for (auto const& [coeff, v] : con.coeffs())
|
for (auto const& cv : con.lhs())
|
||||||
lhs += coeff * m_values[v];
|
lhs += cv.coeff() * m_values[cv.j()];
|
||||||
switch (con.kind()) {
|
switch (con.kind()) {
|
||||||
case lp::lconstraint_kind::GT:
|
case lp::lconstraint_kind::GT:
|
||||||
return lhs > 0;
|
return lhs > 0;
|
||||||
|
@ -867,22 +990,20 @@ namespace nla {
|
||||||
out << "\n";
|
out << "\n";
|
||||||
}
|
}
|
||||||
for (auto ci : m_solver.lra().constraints().indices()) {
|
for (auto ci : m_solver.lra().constraints().indices()) {
|
||||||
lp::constraint_index old_ci;
|
|
||||||
out << "(" << ci << ") ";
|
out << "(" << ci << ") ";
|
||||||
display_constraint(out, ci);
|
display_constraint(out, ci);
|
||||||
if (m_old_constraints.find(ci, old_ci))
|
bool is_true = constraint_is_true(ci);
|
||||||
out << " [parent (" << old_ci << ")] ";
|
out << (is_true ? " [true]" : " [false]") << "\n";
|
||||||
out << "\n";
|
if (!m_assumptions.contains(ci))
|
||||||
if (!m_new_bounds.contains(ci))
|
|
||||||
continue;
|
continue;
|
||||||
out << "\t<- ";
|
out << "\t<- ";
|
||||||
display(out, m_new_bounds[ci]);
|
display(out, m_assumptions[ci]);
|
||||||
out << "\n";
|
out << "\n";
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& stellensatz::display(std::ostream& out, bound_justifications const& bounds) const {
|
std::ostream& stellensatz::display(std::ostream& out, assumptions const& bounds) const {
|
||||||
for (auto b : bounds) {
|
for (auto b : bounds) {
|
||||||
if (std::holds_alternative<u_dependency *>(b)) {
|
if (std::holds_alternative<u_dependency *>(b)) {
|
||||||
auto dep = *std::get_if<u_dependency *>(&b);
|
auto dep = *std::get_if<u_dependency *>(&b);
|
||||||
|
@ -890,7 +1011,12 @@ namespace nla {
|
||||||
c().lra_solver().dep_manager().linearize(dep, cs);
|
c().lra_solver().dep_manager().linearize(dep, cs);
|
||||||
for (auto c : cs)
|
for (auto c : cs)
|
||||||
out << "[o " << c << "] "; // constraint index from c().lra_solver.
|
out << "[o " << c << "] "; // constraint index from c().lra_solver.
|
||||||
} else {
|
}
|
||||||
|
else if (std::holds_alternative<lp::constraint_index>(b)) {
|
||||||
|
auto ci = *std::get_if<lp::constraint_index>(&b);
|
||||||
|
out << "(" << ci << ") "; // constraint index from this solver.
|
||||||
|
}
|
||||||
|
else {
|
||||||
auto [v, k, rhs] = *std::get_if<bound>(&b);
|
auto [v, k, rhs] = *std::get_if<bound>(&b);
|
||||||
out << "[j" << v << " " << k << " " << rhs << "] ";
|
out << "[j" << v << " " << k << " " << rhs << "] ";
|
||||||
}
|
}
|
||||||
|
@ -915,7 +1041,7 @@ namespace nla {
|
||||||
for (auto [v, coeff] : t.first) {
|
for (auto [v, coeff] : t.first) {
|
||||||
c().display_coeff(out, first, coeff);
|
c().display_coeff(out, first, coeff);
|
||||||
first = false;
|
first = false;
|
||||||
if (m_mon2vars.contains(v))
|
if (is_mon_var(v))
|
||||||
display_product(out, m_mon2vars[v]);
|
display_product(out, m_mon2vars[v]);
|
||||||
else
|
else
|
||||||
out << "j" << v;
|
out << "j" << v;
|
||||||
|
@ -927,17 +1053,18 @@ namespace nla {
|
||||||
|
|
||||||
std::ostream& stellensatz::display_constraint(std::ostream& out, lp::constraint_index ci) const {
|
std::ostream& stellensatz::display_constraint(std::ostream& out, lp::constraint_index ci) const {
|
||||||
auto const& con = m_solver.lra().constraints()[ci];
|
auto const& con = m_solver.lra().constraints()[ci];
|
||||||
return display_constraint(out, con.coeffs(), con.kind(), con.rhs());
|
return display_constraint(out, con.lhs(), con.kind(), con.rhs());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& stellensatz::display_constraint(std::ostream& out,
|
std::ostream& stellensatz::display_constraint(std::ostream& out,
|
||||||
vector<std::pair<rational, lpvar>> const& lhs,
|
lp::lar_term const& lhs,
|
||||||
lp::lconstraint_kind k, rational const& rhs) const {
|
lp::lconstraint_kind k, rational const& rhs) const {
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (auto [coeff, v] : lhs) {
|
for (auto cv : lhs) {
|
||||||
c().display_coeff(out, first, coeff);
|
auto v = cv.j();
|
||||||
|
c().display_coeff(out, first, cv.coeff());
|
||||||
first = false;
|
first = false;
|
||||||
if (m_mon2vars.contains(v))
|
if (is_mon_var(v))
|
||||||
display_product(out, m_mon2vars[v]);
|
display_product(out, m_mon2vars[v]);
|
||||||
else
|
else
|
||||||
out << "j" << v;
|
out << "j" << v;
|
||||||
|
@ -971,6 +1098,12 @@ namespace nla {
|
||||||
if (update_values())
|
if (update_values())
|
||||||
return l_true;
|
return l_true;
|
||||||
|
|
||||||
|
return l_undef;
|
||||||
|
// At this point it is not sound to use value assumptions
|
||||||
|
// because the model changed from the outer LRA solver.
|
||||||
|
// Also value assumptions made in a previous iteration may no longer be valid.
|
||||||
|
// this can be fixed by asserting the value assumptions as bounds directly and
|
||||||
|
// making them depend on themselves.
|
||||||
TRACE(arith, s.display(tout));
|
TRACE(arith, s.display(tout));
|
||||||
if (!s.saturate_factors(ex, ineqs))
|
if (!s.saturate_factors(ex, ineqs))
|
||||||
return l_false;
|
return l_false;
|
||||||
|
@ -1014,7 +1147,7 @@ namespace nla {
|
||||||
auto const &value = values[i];
|
auto const &value = values[i];
|
||||||
bool is_int = lra_solver->var_is_int(i);
|
bool is_int = lra_solver->var_is_int(i);
|
||||||
SASSERT(!is_int || value.is_int());
|
SASSERT(!is_int || value.is_int());
|
||||||
if (s.m_mon2vars.contains(i))
|
if (s.is_mon_var(i))
|
||||||
s.m_values[i] = s.value(s.m_mon2vars[i]);
|
s.m_values[i] = s.value(s.m_mon2vars[i]);
|
||||||
else
|
else
|
||||||
s.m_values[i] = value;
|
s.m_values[i] = value;
|
||||||
|
@ -1022,18 +1155,19 @@ namespace nla {
|
||||||
auto indices = lra_solver->constraints().indices();
|
auto indices = lra_solver->constraints().indices();
|
||||||
bool satisfies_products = all_of(indices, [&](auto ci) {
|
bool satisfies_products = all_of(indices, [&](auto ci) {
|
||||||
return s.constraint_is_true(ci);});
|
return s.constraint_is_true(ci);});
|
||||||
s.m_to_refine.reset();
|
s.m_monomials_to_refine.reset();
|
||||||
|
s.m_false_constraints.reset();
|
||||||
// check if all constraints are satisfied
|
// check if all constraints are satisfied
|
||||||
// if they are, then update the model of parent lra solver.
|
// if they are, then update the model of parent lra solver.
|
||||||
for (auto ci : indices)
|
for (auto ci : indices)
|
||||||
s.insert_monomials_from_constraint(ci);
|
s.insert_monomials_from_constraint(ci);
|
||||||
SASSERT(satisfies_products == s.m_to_refine.empty());
|
SASSERT(satisfies_products == s.m_monomials_to_refine.empty());
|
||||||
if (satisfies_products) {
|
if (satisfies_products) {
|
||||||
TRACE(arith, tout << "found satisfying model\n");
|
TRACE(arith, tout << "found satisfying model\n");
|
||||||
for (auto v : s.m_coi.vars())
|
for (auto v : s.m_coi.vars())
|
||||||
s.c().lra_solver().set_column_value(v, lp::impq(s.m_values[v], rational(0)));
|
s.c().lra_solver().set_column_value(v, lp::impq(s.m_values[v], rational(0)));
|
||||||
}
|
}
|
||||||
for (auto j : s.m_to_refine) {
|
for (auto j : s.m_monomials_to_refine) {
|
||||||
auto val_j = values[j];
|
auto val_j = values[j];
|
||||||
auto const &vars = s.m_mon2vars[j];
|
auto const &vars = s.m_mon2vars[j];
|
||||||
auto val_vars = s.m_values[j];
|
auto val_vars = s.m_values[j];
|
||||||
|
|
|
@ -39,14 +39,13 @@ namespace nla {
|
||||||
lp::lconstraint_kind k;
|
lp::lconstraint_kind k;
|
||||||
rational rhs;
|
rational rhs;
|
||||||
};
|
};
|
||||||
using bound_justification = std::variant<u_dependency*, bound>;
|
using assumption = std::variant<u_dependency*, bound, lp::constraint_index>;
|
||||||
using bound_justifications = vector<bound_justification>;
|
using assumptions = vector<assumption>;
|
||||||
|
|
||||||
coi m_coi;
|
coi m_coi;
|
||||||
u_map<bound_justifications> m_new_bounds;
|
u_map<assumptions> m_assumptions; // map from constraint to set of assumptions
|
||||||
u_map<lp::constraint_index> m_old_constraints;
|
indexed_uint_set m_monomials_to_refine;
|
||||||
indexed_uint_set m_to_refine;
|
indexed_uint_set m_false_constraints; // constraints that are false in the current model
|
||||||
ptr_vector<u_dependency> m_ci2dep;
|
|
||||||
vector<rational> m_values;
|
vector<rational> m_values;
|
||||||
struct eq {
|
struct eq {
|
||||||
bool operator()(unsigned_vector const& a, unsigned_vector const& b) const {
|
bool operator()(unsigned_vector const& a, unsigned_vector const& b) const {
|
||||||
|
@ -55,6 +54,8 @@ namespace nla {
|
||||||
};
|
};
|
||||||
map<unsigned_vector, unsigned, svector_hash<unsigned_hash>, eq> m_vars2mon;
|
map<unsigned_vector, unsigned, svector_hash<unsigned_hash>, eq> m_vars2mon;
|
||||||
u_map<unsigned_vector> m_mon2vars;
|
u_map<unsigned_vector> m_mon2vars;
|
||||||
|
bool is_mon_var(lpvar v) const { return m_mon2vars.contains(v); }
|
||||||
|
|
||||||
unsigned m_max_monomial_degree = 0;
|
unsigned m_max_monomial_degree = 0;
|
||||||
|
|
||||||
vector<svector<lp::constraint_index>> m_occurs; // map from variable to constraints they occur.
|
vector<svector<lp::constraint_index>> m_occurs; // map from variable to constraints they occur.
|
||||||
|
@ -88,24 +89,27 @@ namespace nla {
|
||||||
void init_occurs();
|
void init_occurs();
|
||||||
void init_occurs(lp::constraint_index ci);
|
void init_occurs(lp::constraint_index ci);
|
||||||
|
|
||||||
bool constraint_is_true(lp::constraint_index ci);
|
bool constraint_is_true(lp::constraint_index ci) const;
|
||||||
void insert_monomials_from_constraint(lp::constraint_index ci);
|
void insert_monomials_from_constraint(lp::constraint_index ci);
|
||||||
|
|
||||||
// additional variables and monomials and constraints
|
// additional variables and monomials and constraints
|
||||||
using term_offset = std::pair<lp::lar_term, rational>; // term and its offset
|
using term_offset = std::pair<lp::lar_term, rational>; // term and its offset
|
||||||
lpvar add_monomial(svector<lp::lpvar> const& vars);
|
lpvar add_monomial(svector<lp::lpvar> const& vars);
|
||||||
lpvar add_term(term_offset &t);
|
lpvar add_term(term_offset &t);
|
||||||
lp::constraint_index add_ineq(char const* rule, bound_justifications const& bounds, lp::lar_term const &t, lp::lconstraint_kind k, rational const &rhs);
|
lp::constraint_index add_ineq(char const* rule, assumptions const& bounds, lp::lar_term const &t, lp::lconstraint_kind k, rational const &rhs);
|
||||||
lp::constraint_index add_ineq(char const* rule, bound_justifications const &bounds, lpvar j, lp::lconstraint_kind k,
|
lp::constraint_index add_ineq(char const* rule, assumptions const &bounds, lpvar j, lp::lconstraint_kind k,
|
||||||
rational const &rhs);
|
rational const &rhs);
|
||||||
|
|
||||||
bool is_int(svector<lp::lpvar> const& vars) const;
|
bool is_int(svector<lp::lpvar> const& vars) const;
|
||||||
rational value(lp::lar_term const &t) const;
|
rational value(lp::lar_term const &t) const;
|
||||||
rational value(svector<lpvar> const &prod) const;
|
rational value(svector<lpvar> const &prod) const;
|
||||||
lpvar add_var(bool is_int);
|
lpvar add_var(bool is_int);
|
||||||
lbool add_bounds(svector<lpvar> const &vars, bound_justifications &bounds);
|
lbool add_bounds(svector<lpvar> const &vars, assumptions &bounds);
|
||||||
void saturate_constraints();
|
void saturate_constraints();
|
||||||
void saturate_constraint(lp::constraint_index con_id, lp::lpvar mi, svector<lpvar> const & xs);
|
lp::constraint_index saturate_constraint(lp::constraint_index con_id, lp::lpvar mi, svector<lpvar> const & xs);
|
||||||
|
bool is_resolvable(lp::constraint_index ci1, rational const& c1, lp::constraint_index ci2, rational const& c2) const;
|
||||||
|
|
||||||
|
void resolve(lpvar j, lp::constraint_index ci1, lp::constraint_index ci2);
|
||||||
void saturate_basic_linearize();
|
void saturate_basic_linearize();
|
||||||
void saturate_basic_linearize(lpvar j, rational const &val_j, svector<lpvar> const &vars,
|
void saturate_basic_linearize(lpvar j, rational const &val_j, svector<lpvar> const &vars,
|
||||||
rational const &val_vars);
|
rational const &val_vars);
|
||||||
|
@ -132,10 +136,10 @@ namespace nla {
|
||||||
std::ostream& display(std::ostream& out) const;
|
std::ostream& display(std::ostream& out) const;
|
||||||
std::ostream& display_product(std::ostream& out, svector<lpvar> const& vars) const;
|
std::ostream& display_product(std::ostream& out, svector<lpvar> const& vars) const;
|
||||||
std::ostream& display_constraint(std::ostream& out, lp::constraint_index ci) const;
|
std::ostream& display_constraint(std::ostream& out, lp::constraint_index ci) const;
|
||||||
std::ostream& display_constraint(std::ostream& out, vector<std::pair<rational, lpvar>> const& lhs,
|
std::ostream& display_constraint(std::ostream& out, lp::lar_term const& lhs,
|
||||||
lp::lconstraint_kind k, rational const& rhs) const;
|
lp::lconstraint_kind k, rational const& rhs) const;
|
||||||
std::ostream& display(std::ostream &out, term_offset const &t) const;
|
std::ostream& display(std::ostream &out, term_offset const &t) const;
|
||||||
std::ostream& display(std::ostream &out, bound_justifications const &bounds) const;
|
std::ostream& display(std::ostream &out, assumptions const &bounds) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
stellensatz(core* core);
|
stellensatz(core* core);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue