mirror of
https://github.com/Z3Prover/z3
synced 2025-12-03 10:39:07 +00:00
turn on 3rd gen saturation
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
5438d5ad89
commit
5381cb338f
4 changed files with 196 additions and 188 deletions
|
|
@ -1786,6 +1786,7 @@ namespace dd {
|
|||
}
|
||||
|
||||
bool pdd_manager::well_formed() {
|
||||
return true;
|
||||
bool ok = true;
|
||||
for (unsigned n : m_free_nodes) {
|
||||
ok &= (lo(n) == 0 && hi(n) == 0 && m_nodes[n].m_refcount == 0);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,43 @@
|
|||
/*++
|
||||
Copyright (c) 2025 Microsoft Corporation
|
||||
|
||||
|
||||
vanishing(v, p) = (q, r) with q = 0, r >= 0 if p := q*v + r, M(q) = 0
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "util/heap.h"
|
||||
#include "params/smt_params_helper.hpp"
|
||||
#include "math/dd/pdd_eval.h"
|
||||
#include "math/lp/nla_core.h"
|
||||
#include "math/lp/nla_coi.h"
|
||||
#include "math/lp/nla_stellensatz.h"
|
||||
#include <algorithm>
|
||||
#include <ostream>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <math/dd/dd_pdd.h>
|
||||
#include "explanation.h"
|
||||
#include "int_solver.h"
|
||||
#include "lar_solver.h"
|
||||
#include "lia_move.h"
|
||||
#include "lp_settings.h"
|
||||
#include "lp_types.h"
|
||||
#include "nla_common.h"
|
||||
#include "nla_defs.h"
|
||||
#include "nla_types.h"
|
||||
#include <util/debug.h>
|
||||
#include <util/dependency.h>
|
||||
#include <util/lbool.h>
|
||||
#include <util/memory_manager.h>
|
||||
#include <util/params.h>
|
||||
#include <util/rational.h>
|
||||
#include <util/trace.h>
|
||||
#include <util/trail.h>
|
||||
#include <util/uint_set.h>
|
||||
#include <util/util.h>
|
||||
#include <util/vector.h>
|
||||
|
||||
namespace nla {
|
||||
|
||||
|
|
@ -98,7 +127,7 @@ namespace nla {
|
|||
start_saturate:
|
||||
num_constraints = m_constraints.size();
|
||||
lbool r;
|
||||
if (m_config.strategy == 0)
|
||||
if (m_config.strategy == 1)
|
||||
r = conflict_saturation();
|
||||
else
|
||||
r = model_repair();
|
||||
|
|
@ -302,6 +331,10 @@ namespace nla {
|
|||
void stellensatz::add_active(lp::constraint_index ci, uint_set const &tabu) {
|
||||
if (m_active.contains(ci))
|
||||
return;
|
||||
if (m_constraints[ci].p.degree() > m_config.max_degree)
|
||||
return;
|
||||
verbose_stream() << "(nla.stellensatz :add-active " << ci << " :degree " << m_constraints[ci].p.degree()
|
||||
<< ")\n";
|
||||
m_active.insert(ci);
|
||||
m_tabu[ci] = tabu;
|
||||
}
|
||||
|
|
@ -330,11 +363,10 @@ namespace nla {
|
|||
|
||||
TRACE(arith, display_constraint(tout << "process (" << ci << ") ", ci) << " " << m_tabu[ci] << "\n");
|
||||
|
||||
switch (factor(ci)) {
|
||||
case l_undef: break;
|
||||
case l_false: return l_false;
|
||||
case l_true: continue;
|
||||
}
|
||||
ci = factor(ci);
|
||||
|
||||
if (constraint_is_conflict(ci))
|
||||
return l_false;
|
||||
|
||||
auto x = select_variable_to_eliminate(ci);
|
||||
if (x == lp::null_lpvar)
|
||||
|
|
@ -350,7 +382,8 @@ namespace nla {
|
|||
TRACE(arith, tout << "factor " << m_constraints[ci].p << " -> j" << x << "^" << f.degree << " * " << f.p
|
||||
<< " + " << f.q << "\n");
|
||||
auto p_value = value(f.p);
|
||||
if (vanishing(x, f, ci))
|
||||
auto q_ge_0 = vanishing(x, f, ci);
|
||||
if (q_ge_0 != lp::null_ci)
|
||||
return true;
|
||||
if (p_value == 0)
|
||||
return true;
|
||||
|
|
@ -365,24 +398,25 @@ namespace nla {
|
|||
auto other_ci = m_occurs[x][cx];
|
||||
if (m_tabu[other_ci].contains(x))
|
||||
continue;
|
||||
if (!resolve_variable(x, ci, other_ci, p_value, f, _m1, _f_p))
|
||||
auto resolved_ci = resolve_variable(x, ci, other_ci, p_value, f, _m1, _f_p);
|
||||
if (conflict(resolved_ci))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool stellensatz::resolve_variable(lpvar x, lp::constraint_index ci, lp::constraint_index other_ci,
|
||||
lp::constraint_index stellensatz::resolve_variable(lpvar x, lp::constraint_index ci, lp::constraint_index other_ci,
|
||||
rational const &p_value, factorization const &f, unsigned_vector const &_m1,
|
||||
dd::pdd _f_p) {
|
||||
if (ci == other_ci)
|
||||
return true;
|
||||
return lp::null_ci;
|
||||
if (f.degree != 1)
|
||||
return true; // future - could handle this
|
||||
return lp::null_ci; // future - could handle this
|
||||
auto const &[other_p, other_k, other_j] = m_constraints[other_ci];
|
||||
auto const &[p, k, j] = m_constraints[ci];
|
||||
auto g = factor(x, other_ci);
|
||||
if (g.degree != 1)
|
||||
return true; // not handling degree > 1
|
||||
return lp::null_ci; // not handling degree > 1
|
||||
auto p_value2 = value(g.p);
|
||||
//
|
||||
// check that p_value and p_value2 have different signs
|
||||
|
|
@ -394,13 +428,13 @@ namespace nla {
|
|||
SASSERT(g.degree > 0);
|
||||
SASSERT(p_value != 0);
|
||||
if (g.degree > f.degree) // future: could handle this too by considering tabu to be a map into degrees.
|
||||
return true;
|
||||
return lp::null_ci;
|
||||
if (p_value > 0 && p_value2 > 0)
|
||||
return true;
|
||||
return lp::null_ci;
|
||||
if (p_value < 0 && p_value2 < 0)
|
||||
return true;
|
||||
return lp::null_ci;
|
||||
if (any_of(other_p.free_vars(), [&](unsigned j) { return m_tabu[ci].contains(j); }))
|
||||
return true;
|
||||
return lp::null_ci;
|
||||
|
||||
TRACE(arith, tout << "factor (" << other_ci << ") " << other_p << " -> j" << x << "^" << g.degree << " * "
|
||||
<< g.p << " + " << g.q << "\n");
|
||||
|
|
@ -426,35 +460,29 @@ namespace nla {
|
|||
// m1m2 * g_p + g.q >= 0
|
||||
//
|
||||
lp::constraint_index ci_a, ci_b;
|
||||
auto aj = assumption_justification();
|
||||
|
||||
bool g_strict = other_k == lp::lconstraint_kind::GT;
|
||||
bool f_strict = k == lp::lconstraint_kind::LT;
|
||||
bool f_strict = k == lp::lconstraint_kind::GT;
|
||||
if (g_p.is_val())
|
||||
ci_a = multiply(ci, pddm.mk_val(g_p.val()));
|
||||
else if (!sign_f)
|
||||
ci_a =
|
||||
multiply(ci, add_constraint(g_p, f_strict ? lp::lconstraint_kind::LT : lp::lconstraint_kind::LE, aj));
|
||||
ci_a = multiply(ci, assume(g_p, f_strict ? lp::lconstraint_kind::LT : lp::lconstraint_kind::LE));
|
||||
else
|
||||
ci_a =
|
||||
multiply(ci, add_constraint(g_p, f_strict ? lp::lconstraint_kind::GT : lp::lconstraint_kind::GE, aj));
|
||||
ci_a = multiply(ci, assume(g_p, f_strict ? lp::lconstraint_kind::GT : lp::lconstraint_kind::GE));
|
||||
|
||||
if (f_p.is_val())
|
||||
ci_b = multiply(other_ci, pddm.mk_val(f_p.val()));
|
||||
else if (sign_f)
|
||||
ci_b = multiply(other_ci,
|
||||
add_constraint(f_p, g_strict ? lp::lconstraint_kind::LT : lp::lconstraint_kind::LE, aj));
|
||||
ci_b = multiply(other_ci, assume(f_p, g_strict ? lp::lconstraint_kind::LT : lp::lconstraint_kind::LE));
|
||||
else
|
||||
ci_b = multiply(other_ci,
|
||||
add_constraint(f_p, g_strict ? lp::lconstraint_kind::GT : lp::lconstraint_kind::GE, aj));
|
||||
ci_b = multiply(other_ci, assume(f_p, g_strict ? lp::lconstraint_kind::GT : lp::lconstraint_kind::GE));
|
||||
|
||||
auto new_ci = add(ci_a, ci_b);
|
||||
CTRACE(arith, !is_new_constraint(new_ci), display_constraint(tout << "not new ", new_ci) << "\n");
|
||||
++c().lp_settings().stats().m_stellensatz.m_num_resolutions;
|
||||
if (!is_new_constraint(new_ci))
|
||||
return true;
|
||||
if (m_constraints[new_ci].p.degree() <= m_config.max_degree)
|
||||
init_occurs(new_ci);
|
||||
return new_ci;
|
||||
|
||||
TRACE(arith, tout << "eliminate j" << x << ":\n";
|
||||
display_constraint(tout << "ci: ", ci) << "\n";
|
||||
display_constraint(tout << "other_ci: ", other_ci) << "\n";
|
||||
|
|
@ -462,23 +490,27 @@ namespace nla {
|
|||
display_constraint(tout << "ci_b: ", ci_b) << "\n";
|
||||
display_constraint(tout << "new_ci: ", new_ci) << "\n");
|
||||
|
||||
if (conflict(new_ci))
|
||||
return false;
|
||||
if (constraint_is_conflict(new_ci))
|
||||
return new_ci;
|
||||
|
||||
new_ci = factor(new_ci);
|
||||
|
||||
if (m_constraints[new_ci].p.degree() > m_config.max_degree)
|
||||
return new_ci;
|
||||
|
||||
init_occurs(new_ci);
|
||||
uint_set new_tabu(m_tabu[ci]);
|
||||
new_tabu.insert(x);
|
||||
add_active(new_ci, new_tabu);
|
||||
return factor(new_ci) != l_false;
|
||||
add_active(new_ci, new_tabu);
|
||||
return new_ci;
|
||||
}
|
||||
|
||||
bool stellensatz::conflict(lp::constraint_index ci) {
|
||||
auto const &[new_p, new_k, new_j] = m_constraints[ci];
|
||||
if (new_p.is_val() && ((new_p.val() < 0 && new_k == lp::lconstraint_kind::GE) || (new_p.val() <= 0 && new_k == lp::lconstraint_kind::GT))) {
|
||||
m_core.reset();
|
||||
m_core.push_back(ci);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (!constraint_is_conflict(ci))
|
||||
return false;
|
||||
m_core.reset();
|
||||
m_core.push_back(ci);
|
||||
return true;
|
||||
}
|
||||
|
||||
void stellensatz::conflict(svector<lp::constraint_index> const& core) {
|
||||
|
|
@ -496,127 +528,90 @@ namespace nla {
|
|||
lbool stellensatz::model_repair() {
|
||||
for (lp::constraint_index ci = 0; ci < m_constraints.size(); ++ci)
|
||||
m_active.insert(ci);
|
||||
svector<lpvar> vars;
|
||||
m_level2var.reset();
|
||||
m_var2level.reset();
|
||||
for (unsigned v = 0; v < m_values.size(); ++v)
|
||||
vars.push_back(v);
|
||||
m_level2var.push_back(v);
|
||||
random_gen rand(c().random());
|
||||
shuffle(vars.size(), vars.begin(), rand);
|
||||
for (auto v : vars)
|
||||
if (!model_repair(v))
|
||||
return l_false;
|
||||
for (unsigned i = vars.size(); i-- > 0;)
|
||||
set_value(vars[i]);
|
||||
return all_of(m_constraints, [&](constraint const& c) { return constraint_is_true(c); }) ? l_true : l_undef;
|
||||
shuffle(m_level2var.size(), m_level2var.begin(), rand);
|
||||
m_var2level.resize(m_values.size(), m_level2var.size());
|
||||
for (unsigned i = 0; i < m_level2var.size(); ++i)
|
||||
m_var2level[m_level2var[i]] = i;
|
||||
return model_repair_loop();
|
||||
}
|
||||
|
||||
bool stellensatz::model_repair(lp::lpvar v) {
|
||||
m_sup_inf.reserve(v + 1);
|
||||
auto bounds = find_bounds(v);
|
||||
auto const &[lo, inf, infs] = bounds.first;
|
||||
auto const &[hi, sup, sups] = bounds.second;
|
||||
auto has_false = any_of(infs, [&](lp::constraint_index ci) { return !constraint_is_true(ci); }) ||
|
||||
any_of(sups, [&](lp::constraint_index ci) { return !constraint_is_true(ci); });
|
||||
TRACE(arith, tout << "j" << v << " " << infs.size() << " " << sups.size() << "\n");
|
||||
if (!has_false)
|
||||
return true;
|
||||
m_sup_inf[v] = {inf, sup};
|
||||
SASSERT(!infs.empty() || !sups.empty());
|
||||
if (infs.empty()) {
|
||||
SASSERT(!sups.empty());
|
||||
lbool stellensatz::model_repair_loop() {
|
||||
unsigned level = 0;
|
||||
while (true) {
|
||||
if (level >= m_level2var.size())
|
||||
break;
|
||||
auto ci = model_repair(m_level2var[level]);
|
||||
if (ci == lp::null_ci)
|
||||
++level;
|
||||
else if (conflict(ci))
|
||||
return l_false;
|
||||
else if (constraint_is_true(ci))
|
||||
++level;
|
||||
else
|
||||
level = max_level(m_constraints[ci]);
|
||||
}
|
||||
return all_of(m_constraints, [&](constraint const &c) { return constraint_is_true(c); }) ? l_true : l_undef;
|
||||
}
|
||||
|
||||
unsigned stellensatz::max_level(constraint const &c) const {
|
||||
unsigned level = 0;
|
||||
auto const &vars = c.p.free_vars();
|
||||
for (auto v : vars)
|
||||
level = std::max(level, m_var2level[v]);
|
||||
return level;
|
||||
}
|
||||
|
||||
lp::constraint_index stellensatz::model_repair(lp::lpvar v) {
|
||||
auto [lo, hi, inf, sup, vanishing] = find_bounds(v);
|
||||
|
||||
|
||||
if (vanishing != lp::null_ci)
|
||||
return vanishing;
|
||||
|
||||
if (inf == lp::null_ci && sup == lp::null_ci)
|
||||
return lp::null_ci;
|
||||
if (constraint_is_true(inf) && constraint_is_true(sup))
|
||||
return lp::null_ci;
|
||||
if (inf == lp::null_ci) {
|
||||
SASSERT(sup != lp::null_ci);
|
||||
// repair v by setting it below sup
|
||||
auto f = factor(v, sup);
|
||||
m_values[v] = floor(-value(f.q) / value(f.p));
|
||||
return true;
|
||||
return lp::null_ci;
|
||||
}
|
||||
if (sups.empty()) {
|
||||
SASSERT(!infs.empty());
|
||||
if (sup == lp::null_ci) {
|
||||
SASSERT(inf != lp::null_ci);
|
||||
// repair v by setting it above inf
|
||||
auto f = factor(v, inf);
|
||||
m_values[v] = ceil(-value(f.q) / value(f.p));
|
||||
return true;
|
||||
return lp::null_ci;
|
||||
}
|
||||
if (lo <= hi && (!is_int(v) || ceil(lo) <= floor(hi))) {
|
||||
|
||||
if (lo <= hi && (!is_int(v) || ceil(lo) <= floor(hi))) {
|
||||
// repair v by setting it between lo and hi assuming it is integral when v is integer
|
||||
m_values[v] = is_int(v) ? ceil(lo) : lo;
|
||||
return true;
|
||||
return lp::null_ci;
|
||||
}
|
||||
|
||||
auto resolve = [&](unsigned inf, unsigned_vector const &sups) {
|
||||
auto f = factor(v, inf);
|
||||
SASSERT(f.degree == 1);
|
||||
auto p_value = value(f.p);
|
||||
f.p *= pddm.mk_var(v);
|
||||
auto [m, f_p] = f.p.var_factors();
|
||||
return all_of(sups, [&](auto s) { return resolve_variable(v, inf, s, p_value, f, m, f_p); });
|
||||
};
|
||||
// lo > hi - pick a side and assume inf or sup and enforce order between sup and inf.
|
||||
// maybe just add constraints that are false and skip the rest?
|
||||
// remove sups and infs from active because we computed resolvents
|
||||
if (infs.size() <= 3 && sups.size() <= 3 && (infs.size() <= 2 || sups.size() <= 2)) {
|
||||
for (auto inf : infs)
|
||||
if (!resolve(inf, sups))
|
||||
return false;
|
||||
}
|
||||
else if (infs.size() < sups.size()) {
|
||||
if (!resolve(inf, sups))
|
||||
return false;
|
||||
for (auto i : infs)
|
||||
if (!assume_ge(v, i, inf))
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if (!resolve(sup, infs))
|
||||
return false;
|
||||
for (auto s : sups)
|
||||
if (!assume_ge(v, sup, s))
|
||||
return false;
|
||||
}
|
||||
for (auto ci : infs)
|
||||
if (m_active.contains(ci))
|
||||
m_active.remove(ci);
|
||||
for (auto ci : sups)
|
||||
if (m_active.contains(ci))
|
||||
m_active.remove(ci);
|
||||
return true;
|
||||
}
|
||||
TRACE(arith, tout << "v" << v << "@ " << m_var2level[v] << "\n");
|
||||
|
||||
void stellensatz::set_value(lp::lpvar v) {
|
||||
auto [inf, sup] = m_sup_inf[v];
|
||||
if (inf == lp::null_ci && sup == lp::null_ci)
|
||||
return;
|
||||
else if (inf != lp::null_ci) {
|
||||
auto f = factor(v, inf);
|
||||
SASSERT(f.degree == 1);
|
||||
auto quot = -value(f.q) / value(f.p);
|
||||
bool is_strict = m_constraints[inf].k == lp::lconstraint_kind::GT;
|
||||
if (is_strict) {
|
||||
if (sup != lp::null_ci) {
|
||||
auto g = factor(v, sup);
|
||||
SASSERT(g.degree == 1);
|
||||
auto quot2 = -value(g.q) / value(g.p);
|
||||
quot = (quot + quot2) / rational(2);
|
||||
}
|
||||
else {
|
||||
quot += rational(1);
|
||||
}
|
||||
}
|
||||
m_values[v] = is_int(v) ? ceil(quot) : quot;
|
||||
}
|
||||
else if (sup != lp::null_ci) {
|
||||
auto f = factor(v, sup);
|
||||
SASSERT(f.degree == 1);
|
||||
auto quot = -value(f.q) / value(f.p);
|
||||
bool is_strict = m_constraints[sup].k == lp::lconstraint_kind::GT;
|
||||
if (is_strict)
|
||||
quot -= rational(1);
|
||||
m_values[v] = is_int(v) ? floor(quot) : quot;
|
||||
}
|
||||
auto f = factor(v, inf);
|
||||
SASSERT(f.degree == 1);
|
||||
auto p_value = value(f.p);
|
||||
f.p *= pddm.mk_var(v);
|
||||
auto [m, f_p] = f.p.var_factors();
|
||||
return resolve_variable(v, inf, sup, p_value, f, m, f_p);
|
||||
}
|
||||
|
||||
// lo <= hi
|
||||
bool stellensatz::assume_ge(lpvar v, lp::constraint_index lo, lp::constraint_index hi) {
|
||||
void stellensatz::assume_ge(lpvar v, lp::constraint_index lo, lp::constraint_index hi) {
|
||||
if (lo == hi)
|
||||
return true;
|
||||
return;
|
||||
auto const &[plo, klo, jlo] = m_constraints[lo];
|
||||
auto const &[phi, khi, jhi] = m_constraints[hi];
|
||||
auto f = factor(v, lo);
|
||||
|
|
@ -645,58 +640,65 @@ namespace nla {
|
|||
SASSERT(value(r) >= 0);
|
||||
auto new_ci = assume(r, join(klo, khi));
|
||||
m_active.insert(new_ci);
|
||||
return factor(new_ci) != l_false;
|
||||
factor(new_ci);
|
||||
}
|
||||
|
||||
std::pair<stellensatz::bound_info, stellensatz::bound_info> stellensatz::find_bounds(lpvar v) {
|
||||
std::pair<bound_info, bound_info> result;
|
||||
auto &[lo, inf, infs] = result.first;
|
||||
auto &[hi, sup, sups] = result.second;
|
||||
stellensatz::bound_info stellensatz::find_bounds(lpvar v) {
|
||||
bound_info result;
|
||||
auto &[lo, hi, inf, sup, van] = result;
|
||||
for (auto ci : m_occurs[v]) {
|
||||
if (!m_active.contains(ci))
|
||||
continue;
|
||||
// consider only constraints where v is maximal
|
||||
auto const &vars = m_constraints[ci].p.free_vars();
|
||||
if (any_of(vars, [&](unsigned j) { return m_var2level[j] > m_var2level[v]; }))
|
||||
continue;
|
||||
auto f = factor(v, ci);
|
||||
if (vanishing(v, f, ci))
|
||||
auto q_ge_0 = vanishing(v, f, ci);
|
||||
if (q_ge_0 != lp::null_ci) {
|
||||
if (is_new_constraint(q_ge_0) && !constraint_is_true(q_ge_0)) {
|
||||
van = q_ge_0;
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
|
||||
}
|
||||
if (f.degree > 1)
|
||||
continue;
|
||||
SASSERT(f.degree == 1);
|
||||
auto p_value = value(f.p);
|
||||
auto q_value = value(f.q);
|
||||
SASSERT(f.degree == 1);
|
||||
SASSERT(p_value != 0);
|
||||
auto quot = -q_value / p_value;
|
||||
if (p_value < 0) {
|
||||
// p*x + q >= 0 => x <= -q / p if p < 0
|
||||
if (sups.empty() || hi > quot) {
|
||||
if (sup == lp::null_ci || hi > quot) {
|
||||
hi = quot;
|
||||
sup = ci;
|
||||
}
|
||||
else if (hi == quot && m_constraints[ci].k == lp::lconstraint_kind::GT) {
|
||||
sup = ci;
|
||||
}
|
||||
sups.push_back(ci);
|
||||
}
|
||||
else {
|
||||
// p*x + q >= 0 => x >= -q / p if p > 0
|
||||
if (infs.empty() || lo < quot) {
|
||||
if (inf == lp::null_ci || lo < quot) {
|
||||
lo = quot;
|
||||
inf = ci;
|
||||
}
|
||||
else if (lo == quot && m_constraints[ci].k == lp::lconstraint_kind::GT) {
|
||||
inf = ci;
|
||||
}
|
||||
infs.push_back(ci);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool stellensatz::vanishing(lpvar x, factorization const &f, lp::constraint_index ci) {
|
||||
lp::constraint_index stellensatz::vanishing(lpvar x, factorization const &f, lp::constraint_index ci) {
|
||||
if (f.p.is_zero())
|
||||
return false;
|
||||
return lp::null_ci;
|
||||
auto p_value = value(f.p);
|
||||
if (p_value != 0)
|
||||
return false;
|
||||
return lp::null_ci;
|
||||
|
||||
// add p = 0 as assumption and reduce to q.
|
||||
auto p_is_0 = assume(f.p, lp::lconstraint_kind::EQ);
|
||||
|
|
@ -714,30 +716,20 @@ namespace nla {
|
|||
add_active(new_ci, new_tabu);
|
||||
}
|
||||
++c().lp_settings().stats().m_stellensatz.m_num_vanishings;
|
||||
return true;
|
||||
return new_ci;
|
||||
}
|
||||
|
||||
lbool stellensatz::factor(lp::constraint_index ci) {
|
||||
lp::constraint_index stellensatz::factor(lp::constraint_index ci) {
|
||||
auto const &[p, k, j] = m_constraints[ci];
|
||||
auto [vars, q] = p.var_factors(); // p = vars * q
|
||||
|
||||
auto add_new = [&](lp::constraint_index new_ci) {
|
||||
TRACE(arith, display_constraint(tout << "factor ", new_ci) << "\n");
|
||||
if (conflict(new_ci))
|
||||
return l_false;
|
||||
init_occurs(new_ci);
|
||||
auto new_tabu(m_tabu[ci]);
|
||||
add_active(new_ci, new_tabu);
|
||||
return l_true;
|
||||
};
|
||||
|
||||
TRACE(arith, tout << "factor (" << ci << ") " << p << " q: " << q << " vars: " << vars << "\n");
|
||||
if (vars.empty())
|
||||
return l_undef;
|
||||
for (auto v : vars) {
|
||||
return ci;
|
||||
for (auto v : vars)
|
||||
if (value(v) == 0)
|
||||
return l_undef;
|
||||
}
|
||||
return ci;
|
||||
|
||||
vector<dd::pdd> muls;
|
||||
muls.push_back(q);
|
||||
for (auto v : vars)
|
||||
|
|
@ -751,7 +743,8 @@ namespace nla {
|
|||
}
|
||||
if (m_active.contains(ci))
|
||||
m_active.remove(ci);
|
||||
return add_new(new_ci);
|
||||
TRACE(arith, display_constraint(tout << "factor ", new_ci) << "\n");
|
||||
return new_ci;
|
||||
}
|
||||
|
||||
bool stellensatz::is_new_constraint(lp::constraint_index ci) const {
|
||||
|
|
@ -779,7 +772,6 @@ namespace nla {
|
|||
return {degree, lc, rest};
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// check if core depends on an assumption
|
||||
// identify the maximal assumption
|
||||
|
|
@ -1076,7 +1068,7 @@ namespace nla {
|
|||
}
|
||||
|
||||
bool stellensatz::constraint_is_true(lp::constraint_index ci) const {
|
||||
return constraint_is_true(m_constraints[ci]);
|
||||
return ci != lp::null_ci && constraint_is_true(m_constraints[ci]);
|
||||
}
|
||||
|
||||
bool stellensatz::constraint_is_true(constraint const &c) const {
|
||||
|
|
@ -1093,6 +1085,17 @@ namespace nla {
|
|||
}
|
||||
}
|
||||
|
||||
bool stellensatz::constraint_is_conflict(lp::constraint_index ci) const {
|
||||
return ci != lp::null_ci && constraint_is_conflict(m_constraints[ci]);
|
||||
}
|
||||
|
||||
bool stellensatz::constraint_is_conflict(constraint const& c) const {
|
||||
auto const &[p, k, j] = c;
|
||||
return p.is_val() &&
|
||||
((p.val() < 0 && k == lp::lconstraint_kind::GE)
|
||||
|| (p.val() <= 0 && k == lp::lconstraint_kind::GT));
|
||||
}
|
||||
|
||||
std::ostream& stellensatz::display(std::ostream& out) const {
|
||||
#if 0
|
||||
// m_solver.lra().display(out);
|
||||
|
|
|
|||
|
|
@ -146,6 +146,8 @@ namespace nla {
|
|||
vector<svector<lp::constraint_index>> m_occurs; // map from variable to constraints they occur.
|
||||
bool_vector m_has_occurs;
|
||||
|
||||
unsigned_vector m_var2level, m_level2var;
|
||||
|
||||
struct constraint_key {
|
||||
unsigned pdd;
|
||||
lp::lconstraint_kind k;
|
||||
|
|
@ -183,30 +185,32 @@ namespace nla {
|
|||
void remove_occurs(lp::constraint_index ci);
|
||||
|
||||
lbool conflict_saturation();
|
||||
lbool factor(lp::constraint_index ci);
|
||||
lp::constraint_index factor(lp::constraint_index ci);
|
||||
bool conflict(lp::constraint_index ci);
|
||||
void conflict(svector<lp::constraint_index> const& core);
|
||||
bool vanishing(lpvar x, factorization const& f, lp::constraint_index ci);
|
||||
lp::constraint_index vanishing(lpvar x, factorization const& f, lp::constraint_index ci);
|
||||
lp::lpvar select_variable_to_eliminate(lp::constraint_index ci);
|
||||
unsigned degree_of_var_in_constraint(lpvar v, lp::constraint_index ci) const;
|
||||
factorization factor(lpvar v, lp::constraint_index ci);
|
||||
bool resolve_variable(lpvar x, lp::constraint_index ci);
|
||||
bool resolve_variable(lpvar x, lp::constraint_index ci, lp::constraint_index other_ci, rational const& p_value,
|
||||
lp::constraint_index resolve_variable(lpvar x, lp::constraint_index ci, lp::constraint_index other_ci, rational const& p_value,
|
||||
factorization const& f, unsigned_vector const& m1, dd::pdd _f_p);
|
||||
|
||||
svector<std::pair<lp::constraint_index, lp::constraint_index>> m_sup_inf;
|
||||
lbool model_repair();
|
||||
bool model_repair(lp::lpvar v);
|
||||
lbool model_repair_loop();
|
||||
lp::constraint_index model_repair(lp::lpvar v);
|
||||
struct bound_info {
|
||||
rational value;
|
||||
lp::constraint_index bound = lp::null_ci;
|
||||
svector<lp::constraint_index> bounds;
|
||||
rational lo_value, hi_value;
|
||||
lp::constraint_index lo = lp::null_ci, hi = lp::null_ci, vanishing = lp::null_ci;
|
||||
};
|
||||
std::pair<bound_info, bound_info> find_bounds(lpvar v);
|
||||
bool assume_ge(lpvar v, lp::constraint_index lo, lp::constraint_index hi);
|
||||
bound_info find_bounds(lpvar v);
|
||||
unsigned max_level(constraint const &c) const;
|
||||
void assume_ge(lpvar v, lp::constraint_index lo, lp::constraint_index hi);
|
||||
|
||||
bool constraint_is_true(lp::constraint_index ci) const;
|
||||
bool constraint_is_true(constraint const &c) const;
|
||||
bool constraint_is_conflict(lp::constraint_index ci) const;
|
||||
bool constraint_is_conflict(constraint const &c) const;
|
||||
bool is_new_constraint(lp::constraint_index ci) const;
|
||||
|
||||
lp::constraint_index gcd_normalize(lp::constraint_index ci);
|
||||
|
|
@ -222,7 +226,6 @@ namespace nla {
|
|||
rational value(dd::pdd const& p) const;
|
||||
rational value(lp::lpvar v) const { return m_values[v]; }
|
||||
bool set_model();
|
||||
void set_value(lp::lpvar v);
|
||||
|
||||
void add_active(lp::constraint_index ci, uint_set const &tabu);
|
||||
|
||||
|
|
|
|||
|
|
@ -4417,8 +4417,9 @@ namespace nlsat {
|
|||
}
|
||||
|
||||
anum const & solver::value(var x) const {
|
||||
if (m_imp->m_assignment.is_assigned(x))
|
||||
return m_imp->m_assignment.value(x);
|
||||
auto y = m_imp->m_inv_perm[x];
|
||||
if (m_imp->m_assignment.is_assigned(y))
|
||||
return m_imp->m_assignment.value(y);
|
||||
return m_imp->m_zero;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue