mirror of
https://github.com/Z3Prover/z3
synced 2025-04-15 05:18:44 +00:00
1924 lines
63 KiB
C++
1924 lines
63 KiB
C++
/*++
|
|
Copyright (c) 2017 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
<name>
|
|
|
|
Abstract:
|
|
|
|
<abstract>
|
|
|
|
Author:
|
|
Nikolaj Bjorner (nbjorner)
|
|
Lev Nachmanson (levnach)
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
#include "util/lp/nla_solver.h"
|
|
#include "util/map.h"
|
|
#include "util/lp/monomial.h"
|
|
#include "util/lp/lp_utils.h"
|
|
#include "util/lp/vars_equivalence.h"
|
|
#include "util/lp/factorization.h"
|
|
#include "util/lp/rooted_mons.h"
|
|
namespace nla {
|
|
struct solver::imp {
|
|
|
|
|
|
typedef lp::lar_base_constraint lpcon;
|
|
|
|
|
|
|
|
//fields
|
|
vars_equivalence m_vars_equivalence;
|
|
vector<monomial> m_monomials;
|
|
|
|
rooted_mon_table m_rm_table;
|
|
// this field is used for the push/pop operations
|
|
unsigned_vector m_monomials_counts;
|
|
lp::lar_solver& m_lar_solver;
|
|
std::unordered_map<lpvar, svector<lpvar>> m_monomials_containing_var;
|
|
|
|
// m_var_to_its_monomial[m_monomials[i].var()] = i
|
|
std::unordered_map<lpvar, unsigned> m_var_to_its_monomial;
|
|
lp::explanation * m_expl;
|
|
lemma * m_lemma;
|
|
imp(lp::lar_solver& s, reslimit& lim, params_ref const& p)
|
|
:
|
|
m_vars_equivalence([this](unsigned h){return vvr(h);}),
|
|
m_lar_solver(s)
|
|
// m_limit(lim),
|
|
// m_params(p)
|
|
{
|
|
}
|
|
|
|
|
|
rational vvr(lpvar j) const { return m_lar_solver.get_column_value_rational(j); }
|
|
|
|
lp::impq vv(lpvar j) const { return m_lar_solver.get_column_value(j); }
|
|
|
|
lpvar var(const rooted_mon& rm) const {return m_monomials[rm.m_orig.m_i].var(); }
|
|
|
|
rational vvr(const rooted_mon& rm) const { return vvr(m_monomials[rm.m_orig.m_i].var()) * rm.m_orig.m_sign; }
|
|
|
|
rational vvr(const factor& f) const { return f.is_var()? vvr(f.index()) : vvr(m_rm_table.vec()[f.index()]); }
|
|
|
|
lpvar var(const factor& f) const {
|
|
return f.is_var()?
|
|
f.index() : var(m_rm_table.vec()[f.index()]);
|
|
}
|
|
|
|
svector<lpvar> sorted_vars(const factor& f) const {
|
|
if (f.is_var()) {
|
|
svector<lpvar> r; r.push_back(f.index());
|
|
return r;
|
|
}
|
|
TRACE("nla_solver", tout << "nv";);
|
|
return m_rm_table.vec()[f.index()].vars();
|
|
}
|
|
|
|
// the value of the factor is equal to the value of the variable multiplied
|
|
// by the flip_sign
|
|
rational flip_sign(const factor& f) const {
|
|
return f.is_var()?
|
|
rational(1) : m_rm_table.vec()[f.index()].m_orig.sign();
|
|
}
|
|
|
|
// the value of the rooted monomias is equal to the value of the variable multiplied
|
|
// by the flip_sign
|
|
rational flip_sign(const rooted_mon& m) const {
|
|
return m.m_orig.sign();
|
|
}
|
|
|
|
// returns the monomial index
|
|
unsigned add(lpvar v, unsigned sz, lpvar const* vs) {
|
|
unsigned ret = m_var_to_its_monomial[v] = m_monomials.size();
|
|
m_monomials.push_back(monomial(v, sz, vs));
|
|
TRACE("nla_solver", print_monomial(m_monomials.back(), tout););
|
|
return ret;
|
|
}
|
|
|
|
void push() {
|
|
TRACE("nla_solver",);
|
|
m_monomials_counts.push_back(m_monomials.size());
|
|
}
|
|
|
|
|
|
void deregister_monomial_from_rooted_monomials (const monomial & m, unsigned i){
|
|
rational sign = rational(1);
|
|
svector<lpvar> vars = reduce_monomial_to_rooted(m.vars(), sign);
|
|
NOT_IMPLEMENTED_YET();
|
|
}
|
|
|
|
void deregister_monomial_from_tables(const monomial & m, unsigned i){
|
|
m_vars_equivalence.deregister_monomial_from_abs_vals(m, i);
|
|
deregister_monomial_from_rooted_monomials(m, i);
|
|
}
|
|
|
|
void pop(unsigned n) {
|
|
TRACE("nla_solver",);
|
|
if (n == 0) return;
|
|
unsigned new_size = m_monomials_counts[m_monomials_counts.size() - n];
|
|
for (unsigned i = m_monomials.size(); i-- > new_size; ){
|
|
deregister_monomial_from_tables(m_monomials[i], i);
|
|
}
|
|
m_monomials.shrink(new_size);
|
|
m_monomials_counts.shrink(m_monomials_counts.size() - n);
|
|
}
|
|
|
|
rational mon_value_by_vars(unsigned i) const {
|
|
return mon_value_by_vars(m_monomials[i]);
|
|
}
|
|
rational mon_value_by_vars(const monomial & m) const {
|
|
rational r(1);
|
|
for (auto j : m) {
|
|
r *= m_lar_solver.get_column_value_rational(j);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
// return true if the monomial value is equal to the product of the values of the factors
|
|
bool check_monomial(const monomial& m) {
|
|
SASSERT(m_lar_solver.get_column_value(m.var()).is_int());
|
|
return mon_value_by_vars(m) == m_lar_solver.get_column_value_rational(m.var());
|
|
}
|
|
|
|
/**
|
|
* \brief <here we have two monomials, i_mon and other_m, examined for "sign" equivalence>
|
|
*/
|
|
|
|
bool values_are_different(lpvar j, rational const& sign, lpvar k) const {
|
|
SASSERT(sign == 1 || sign == -1);
|
|
return sign * m_lar_solver.get_column_value(j) != m_lar_solver.get_column_value(k);
|
|
}
|
|
|
|
void explain(const rooted_mon& rm) {
|
|
expl_set e;
|
|
add_explanation_of_reducing_to_rooted_monomial_and_set_expl(rm, e);
|
|
}
|
|
|
|
void add_explanation_of_reducing_to_rooted_monomial(const monomial& m, expl_set & exp) const {
|
|
m_vars_equivalence.add_explanation_of_reducing_to_rooted_monomial(m, exp);
|
|
}
|
|
|
|
void add_explanation_of_reducing_to_rooted_monomial(lpvar j, expl_set & exp) const {
|
|
auto it = m_var_to_its_monomial.find(j);
|
|
if (it == m_var_to_its_monomial.end())
|
|
return; // j is not a var of a monomial
|
|
add_explanation_of_reducing_to_rooted_monomial(it->second, exp);
|
|
}
|
|
|
|
template <typename T>
|
|
std::ostream& print_product(const T & m, std::ostream& out) const {
|
|
for (unsigned k = 0; k < m.size(); k++) {
|
|
out << m_lar_solver.get_variable_name(m[k]);
|
|
if (k + 1 < m.size()) out << "*";
|
|
}
|
|
return out;
|
|
}
|
|
|
|
std::ostream & print_factor(const factor& f, std::ostream& out) const {
|
|
if (f.is_var()) {
|
|
print_var(f.index(), out);
|
|
} else {
|
|
print_product(m_rm_table.vec()[f.index()].vars(), out);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
std::ostream & print_factor_with_vars(const factor& f, std::ostream& out) const {
|
|
if (f.is_var()) {
|
|
print_var(f.index(), out);
|
|
} else {
|
|
print_product_with_vars(m_rm_table.vec()[f.index()].vars(), out);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
std::ostream& print_monomial(const monomial& m, std::ostream& out) const {
|
|
out << m_lar_solver.get_variable_name(m.var()) << " = ";
|
|
return print_product(m.vars(), out);
|
|
}
|
|
|
|
std::ostream& print_monomial(unsigned i, std::ostream& out) const {
|
|
return print_monomial(m_monomials[i], out);
|
|
}
|
|
|
|
std::ostream& print_monomial_with_vars(unsigned i, std::ostream& out) const {
|
|
return print_monomial_with_vars(m_monomials[i], tout);
|
|
}
|
|
|
|
template <typename T>
|
|
std::ostream& print_product_with_vars(const T& m, std::ostream& out) const {
|
|
print_product(m, out);
|
|
out << '\n';
|
|
for (unsigned k = 0; k < m.size(); k++) {
|
|
print_var(m[k], out);
|
|
}
|
|
return out;
|
|
|
|
}
|
|
|
|
std::ostream& print_monomial_with_vars(const monomial& m, std::ostream& out) const {
|
|
out << m_lar_solver.get_variable_name(m.var()) << " = ";
|
|
return print_product_with_vars(m, out);
|
|
}
|
|
|
|
std::ostream& print_rooted_monomial(const rooted_mon& rm, std::ostream& out) const {
|
|
out << "vars = ";
|
|
print_product(rm.vars(), out);
|
|
out << "\n orig = "; print_monomial(m_monomials[rm.orig_index()], out);
|
|
out << ", orig sign = " << rm.orig_sign() << "\n";
|
|
return out;
|
|
}
|
|
|
|
std::ostream& print_explanation(std::ostream& out) const {
|
|
for (auto &p : *m_expl) {
|
|
m_lar_solver.print_constraint(p.second, out);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
void mk_ineq(const rational& a, lpvar j, const rational& b, lpvar k, lp::lconstraint_kind cmp, const rational& rs) {
|
|
lp::lar_term t;
|
|
t.add_coeff_var(a, j);
|
|
t.add_coeff_var(b, k);
|
|
m_lemma->push_back(ineq(cmp, t, rs));
|
|
}
|
|
|
|
void mk_ineq(lpvar j, const rational& b, lpvar k, lp::lconstraint_kind cmp, const rational& rs) {
|
|
mk_ineq(rational(1), j, b, k, cmp, rs);
|
|
}
|
|
|
|
void mk_ineq(lpvar j, const rational& b, lpvar k, lp::lconstraint_kind cmp) {
|
|
mk_ineq(j, b, k, cmp, rational::zero());
|
|
}
|
|
|
|
void mk_ineq(const rational& a, lpvar j, const rational& b, lpvar k, lp::lconstraint_kind cmp) {
|
|
mk_ineq(a, j, b, k, cmp, rational::zero());
|
|
}
|
|
|
|
void mk_ineq(const rational& a ,lpvar j, lpvar k, lp::lconstraint_kind cmp, const rational& rs) {
|
|
mk_ineq(a, j, rational(1), k, cmp, rs);
|
|
}
|
|
|
|
void mk_ineq(lpvar j, lpvar k, lp::lconstraint_kind cmp, const rational& rs) {
|
|
mk_ineq(j, rational(1), k, cmp, rs);
|
|
}
|
|
|
|
void mk_ineq(lpvar j, lp::lconstraint_kind cmp, const rational& rs) {
|
|
lp::lar_term t;
|
|
t.add_coeff_var(j);
|
|
m_lemma->push_back(ineq(cmp, t, rs));
|
|
}
|
|
|
|
void mk_ineq(const rational& a, lpvar j, lp::lconstraint_kind cmp, const rational& rs) {
|
|
lp::lar_term t;
|
|
t.add_coeff_var(a, j);
|
|
m_lemma->push_back(ineq(cmp, t, rs));
|
|
}
|
|
|
|
void mk_ineq(const rational& a, lpvar j, lp::lconstraint_kind cmp) {
|
|
mk_ineq(a, j, cmp, rational::zero());
|
|
}
|
|
|
|
void mk_ineq(lpvar j, lpvar k, lp::lconstraint_kind cmp) {
|
|
mk_ineq(rational(1), j, rational(1), k, cmp, rational::zero());
|
|
}
|
|
|
|
void mk_ineq(lpvar j, lp::lconstraint_kind cmp) {
|
|
mk_ineq(j, cmp, rational::zero());
|
|
}
|
|
|
|
// the monomials should be equal by modulo sign but this is not so the model
|
|
void fill_explanation_and_lemma_sign(const monomial& a, const monomial & b, rational const& sign) {
|
|
expl_set expl;
|
|
SASSERT(sign == 1 || sign == -1);
|
|
add_explanation_of_reducing_to_rooted_monomial(a, expl);
|
|
add_explanation_of_reducing_to_rooted_monomial(b, expl);
|
|
m_expl->clear();
|
|
m_expl->add(expl);
|
|
TRACE("nla_solver",
|
|
tout << "used constraints: ";
|
|
for (auto &p : *m_expl)
|
|
m_lar_solver.print_constraint(p.second, tout); tout << "\n";
|
|
);
|
|
SASSERT(m_lemma->size() == 0);
|
|
mk_ineq(rational(1), a.var(), -sign, b.var(), lp::lconstraint_kind::EQ, rational::zero());
|
|
TRACE("nla_solver", print_lemma(tout););
|
|
}
|
|
|
|
// Replaces each variable index by the root in the tree and flips the sign if the var comes with a minus.
|
|
// Also sorts the result.
|
|
//
|
|
svector<lpvar> reduce_monomial_to_rooted(const svector<lpvar> & vars, rational & sign) const {
|
|
svector<lpvar> ret;
|
|
sign = 1;
|
|
for (lpvar v : vars) {
|
|
unsigned root = m_vars_equivalence.map_to_root(v, sign);
|
|
SASSERT(m_vars_equivalence.is_root(root));
|
|
ret.push_back(root);
|
|
}
|
|
std::sort(ret.begin(), ret.end());
|
|
return ret;
|
|
}
|
|
|
|
|
|
// Replaces definition m_v = v1* .. * vn by
|
|
// m_v = coeff * w1 * ... * wn, where w1, .., wn are canonical
|
|
// representatives, which are the roots of the equivalence tree, under current equations.
|
|
//
|
|
monomial_coeff canonize_monomial(monomial const& m) const {
|
|
rational sign = rational(1);
|
|
svector<lpvar> vars = reduce_monomial_to_rooted(m.vars(), sign);
|
|
return monomial_coeff(vars, sign);
|
|
}
|
|
|
|
// the value of the i-th monomial has to be equal to the value of the k-th monomial modulo sign
|
|
// but it is not the case in the model
|
|
void generate_sign_lemma(const vector<rational>& abs_vals, unsigned i, unsigned k, const rational& sign) {
|
|
SASSERT(sign == rational(1) || sign == rational(-1));
|
|
SASSERT(m_lemma->empty());
|
|
TRACE("nla_solver",
|
|
tout << "mon i=" << i << " = "; print_monomial_with_vars(m_monomials[i],tout);
|
|
tout << '\n';
|
|
tout << "mon k=" << k << " = "; print_monomial_with_vars(m_monomials[k],tout);
|
|
tout << '\n';
|
|
tout << "abs_vals="; print_vector(abs_vals, tout);
|
|
);
|
|
std::unordered_map<rational, vector<index_with_sign>> map;
|
|
for (const rational& v : abs_vals) {
|
|
map[v] = vector<index_with_sign>();
|
|
}
|
|
|
|
for (unsigned j : m_monomials[i]) {
|
|
rational v = vvr(j);
|
|
int s;
|
|
if (v.is_pos()) {
|
|
s = 1;
|
|
} else {
|
|
s = -1;
|
|
v = -v;
|
|
};
|
|
// v = abs(vvr(j))
|
|
auto it = map.find(v);
|
|
SASSERT(it != map.end());
|
|
it->second.push_back(index_with_sign(j, rational(s)));
|
|
}
|
|
|
|
for (unsigned j : m_monomials[k]) {
|
|
rational v = vvr(j);
|
|
rational s;
|
|
if (v.is_pos()) {
|
|
s = rational(1);
|
|
} else {
|
|
s = -rational(1);
|
|
v = -v;
|
|
};
|
|
// v = abs(vvr(j))
|
|
auto it = map.find(v);
|
|
SASSERT(it != map.end());
|
|
index_with_sign & ins = it->second.back();
|
|
if (j != ins.m_i) {
|
|
s *= ins.m_sign;
|
|
mk_ineq(j, -s, ins.m_i, lp::lconstraint_kind::NE);
|
|
}
|
|
it->second.pop_back();
|
|
}
|
|
|
|
mk_ineq(m_monomials[i].var(), -sign, m_monomials[k].var(), lp::lconstraint_kind::EQ);
|
|
TRACE("nla_solver", print_lemma(tout););
|
|
}
|
|
|
|
|
|
static int rat_sign(const rational& r) {
|
|
return r.is_pos()? 1 : ( r.is_neg()? -1 : 0);
|
|
}
|
|
|
|
int vars_sign(const svector<lpvar>& v) {
|
|
int sign = 1;
|
|
for (lpvar j : v) {
|
|
sign *= rat_sign(vvr(j));
|
|
if (sign == 0)
|
|
return 0;
|
|
}
|
|
return sign;
|
|
}
|
|
|
|
bool basic_sign_lemma_on_a_bucket_of_abs_vals(const vector<rational>& abs_vals, const unsigned_vector& list){
|
|
rational val = vvr(m_monomials[list[0]].var());
|
|
int sign = vars_sign(m_monomials[list[0]].vars());
|
|
if (sign == 0) {
|
|
return false;
|
|
}
|
|
|
|
for (unsigned i = 1; i < list.size(); i++) {
|
|
rational rsign = rational(vars_sign(m_monomials[list[i]].vars()) * sign);
|
|
SASSERT(!rsign.is_zero());
|
|
rational other_val = vvr(m_monomials[list[i]].var());
|
|
if (val * rsign != other_val) {
|
|
generate_sign_lemma(abs_vals, list[0], list[i], rsign);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* \brief <generate lemma by using the fact that -ab = (-a)b) and
|
|
-ab = a(-b)
|
|
*/
|
|
bool basic_sign_lemma() {
|
|
for (const auto & p : m_vars_equivalence.monomials_by_abs_values()){
|
|
if (basic_sign_lemma_on_a_bucket_of_abs_vals(p.first, p.second))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool var_is_fixed_to_zero(lpvar j) const {
|
|
return
|
|
m_lar_solver.column_has_upper_bound(j) &&
|
|
m_lar_solver.column_has_lower_bound(j) &&
|
|
m_lar_solver.get_upper_bound(j) == lp::zero_of_type<lp::impq>() &&
|
|
m_lar_solver.get_lower_bound(j) == lp::zero_of_type<lp::impq>();
|
|
}
|
|
|
|
std::ostream & print_ineq(const ineq & in, std::ostream & out) const {
|
|
m_lar_solver.print_term(in.m_term, out);
|
|
out << " " << lp::lconstraint_kind_string(in.m_cmp) << " " << in.m_rs;
|
|
return out;
|
|
}
|
|
|
|
std::ostream & print_var(lpvar j, std::ostream & out) const {
|
|
bool is_monomial = false;
|
|
for (const monomial & m : m_monomials) {
|
|
if (j == m.var()) {
|
|
is_monomial = true;
|
|
print_monomial(m, out);
|
|
out << " = " << vvr(j);;
|
|
break;
|
|
}
|
|
}
|
|
if (!is_monomial)
|
|
out << m_lar_solver.get_variable_name(j) << " = " << vvr(j);
|
|
out <<";";
|
|
return out;
|
|
}
|
|
|
|
std::ostream & print_lemma(std::ostream & out) const {
|
|
auto &l = *m_lemma;
|
|
out << "lemma: ";
|
|
for (unsigned i = 0; i < l.size(); i++) {
|
|
print_ineq(l[i], out);
|
|
if (i + 1 < l.size()) out << " or ";
|
|
}
|
|
out << std::endl;
|
|
std::unordered_set<lpvar> vars;
|
|
for (auto & in: l) {
|
|
for (const auto & p: in.m_term)
|
|
vars.insert(p.var());
|
|
}
|
|
for (lpvar j : vars) {
|
|
print_var(j, out);
|
|
}
|
|
out << "\n";
|
|
return out;
|
|
}
|
|
|
|
std::ostream & print_factorization(const factorization& f, std::ostream& out) const {
|
|
for (unsigned k = 0; k < f.size(); k++ ) {
|
|
if (f[k].is_var())
|
|
print_var(f[k].index(), out);
|
|
else {
|
|
print_product(m_rm_table.vec()[f[k].index()].vars(), out);
|
|
}
|
|
if (k < f.size() - 1)
|
|
out << "*";
|
|
}
|
|
return out;
|
|
}
|
|
|
|
struct factorization_factory_imp: factorization_factory {
|
|
const imp& m_imp;
|
|
|
|
factorization_factory_imp(const svector<lpvar>& m_vars, const imp& s) :
|
|
factorization_factory(m_vars),
|
|
m_imp(s) { }
|
|
|
|
bool find_monomial_of_vars(const svector<lpvar>& vars, unsigned & i) const {
|
|
SASSERT(m_imp.vars_are_roots(vars));
|
|
auto it = m_imp.m_rm_table.map().find(vars);
|
|
if (it == m_imp.m_rm_table.map().end()) {
|
|
return false;
|
|
}
|
|
|
|
i = it->second.m_mons.begin()->m_i;
|
|
return true;
|
|
}
|
|
};
|
|
|
|
// here we use the fact
|
|
// xy = 0 -> x = 0 or y = 0
|
|
bool basic_lemma_for_mon_zero(const rooted_mon& rm, const factorization& f) {
|
|
TRACE("nla_solver", trace_print_monomial_and_factorization(rm, f, tout););
|
|
SASSERT(vvr(rm).is_zero());
|
|
for (auto j : f) {
|
|
if (vvr(j).is_zero()) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
SASSERT(m_lemma->empty());
|
|
|
|
mk_ineq(var(rm), lp::lconstraint_kind::NE);
|
|
for (auto j : f) {
|
|
mk_ineq(var(j), lp::lconstraint_kind::EQ);
|
|
}
|
|
|
|
explain(rm);
|
|
TRACE("nla_solver", print_lemma(tout););
|
|
|
|
return true;
|
|
}
|
|
|
|
void add_explanation_of_reducing_to_rooted_monomial_and_set_expl(const rooted_mon& rm, expl_set& ex) {
|
|
add_explanation_of_reducing_to_rooted_monomial(m_monomials[rm.orig_index()], ex);
|
|
set_expl(ex);
|
|
}
|
|
|
|
void set_expl(const expl_set & e) {
|
|
m_expl->clear();
|
|
for (lpci ci : e)
|
|
m_expl->push_justification(ci);
|
|
}
|
|
|
|
void trace_print_monomial_and_factorization(const rooted_mon& rm, const factorization& f, std::ostream& out) const {
|
|
out << "rooted vars: ";
|
|
print_product(rm.m_vars, out);
|
|
out << "\n";
|
|
|
|
print_monomial(rm.orig_index(), out << "mon: ") << "\n";
|
|
out << "value: " << vvr(rm) << "\n";
|
|
print_factorization(f, out << "fact: ") << "\n";
|
|
}
|
|
|
|
// x = 0 or y = 0 -> xy = 0
|
|
bool basic_lemma_for_mon_non_zero(const rooted_mon& rm, const factorization& f) {
|
|
TRACE("nla_solver", trace_print_monomial_and_factorization(rm, f, tout););
|
|
SASSERT (!vvr(rm).is_zero());
|
|
int zero_j = -1;
|
|
for (auto j : f) {
|
|
if (vvr(j).is_zero()) {
|
|
zero_j = var(j);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (zero_j == -1) {
|
|
return false;
|
|
}
|
|
|
|
mk_ineq(zero_j, lp::lconstraint_kind::NE);
|
|
mk_ineq(var(rm), lp::lconstraint_kind::EQ);
|
|
|
|
explain(rm);
|
|
TRACE("nla_solver", print_lemma(tout););
|
|
return true;
|
|
}
|
|
|
|
// use the fact that
|
|
// |xabc| = |x| and x != 0 -> |a| = |b| = |c| = 1
|
|
bool basic_lemma_for_mon_neutral_monomial_to_factor(const rooted_mon& rm, const factorization& f) {
|
|
TRACE("nla_solver", trace_print_monomial_and_factorization(rm, f, tout););
|
|
|
|
lpvar mon_var = m_monomials[rm.orig_index()].var();
|
|
const auto & mv = vvr(mon_var);
|
|
const auto abs_mv = abs(mv);
|
|
|
|
if (abs_mv == rational::zero()) {
|
|
return false;
|
|
}
|
|
lpvar jl = -1;
|
|
for (auto j : f ) {
|
|
if (abs(vvr(j)) == abs_mv) {
|
|
jl = var(j);
|
|
break;
|
|
}
|
|
}
|
|
if (jl == static_cast<lpvar>(-1))
|
|
return false;
|
|
lpvar not_one_j = -1;
|
|
for (auto j : f ) {
|
|
if (var(j) == jl) {
|
|
continue;
|
|
}
|
|
if (abs(vvr(j)) != rational(1)) {
|
|
not_one_j = var(j);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (not_one_j == static_cast<lpvar>(-1)) {
|
|
return false;
|
|
}
|
|
|
|
SASSERT(m_lemma->empty());
|
|
// jl + mon_var != 0
|
|
mk_ineq(jl, mon_var, lp::lconstraint_kind::NE);
|
|
|
|
// jl - mon_var != 0
|
|
mk_ineq(jl, -rational(1), mon_var, lp::lconstraint_kind::NE);
|
|
|
|
// not_one_j = 1
|
|
mk_ineq(not_one_j, lp::lconstraint_kind::EQ, rational(1));
|
|
|
|
// not_one_j = -1
|
|
mk_ineq(not_one_j, lp::lconstraint_kind::EQ, -rational(1));
|
|
explain(rm);
|
|
TRACE("nla_solver", print_lemma(tout); );
|
|
return true;
|
|
}
|
|
|
|
// use the fact
|
|
// 1 * 1 ... * 1 * x * 1 ... * 1 = x
|
|
bool basic_lemma_for_mon_neutral_from_factors_to_monomial(const rooted_mon& rm, const factorization& f) {
|
|
rational sign = rm.m_orig.m_sign;
|
|
lpvar not_one = -1;
|
|
for (auto j : f){
|
|
if (vvr(j) == rational(1)) {
|
|
continue;
|
|
}
|
|
|
|
if (vvr(j) == -rational(1)) {
|
|
sign = - sign;
|
|
continue;
|
|
}
|
|
|
|
if (not_one == static_cast<lpvar>(-1)) {
|
|
not_one = var(j);
|
|
continue;
|
|
}
|
|
|
|
// if we are here then there are at least two factors with values different from one and minus one: cannot create the lemma
|
|
return false;
|
|
}
|
|
|
|
explain(rm);
|
|
|
|
for (auto j : f){
|
|
lpvar var_j = var(j);
|
|
if (not_one == var_j) continue;
|
|
mk_ineq(var_j, lp::lconstraint_kind::NE, j.is_var()? vvr(j) : flip_sign(j) * vvr(j) );
|
|
}
|
|
|
|
if (not_one == static_cast<lpvar>(-1)) {
|
|
mk_ineq(m_monomials[rm.orig_index()].var(), lp::lconstraint_kind::EQ, sign);
|
|
} else {
|
|
mk_ineq(m_monomials[rm.orig_index()].var(), -sign, not_one, lp::lconstraint_kind::EQ);
|
|
}
|
|
TRACE("nla_solver", print_lemma(tout););
|
|
return true;
|
|
}
|
|
|
|
bool basic_lemma_for_mon_neutral(const rooted_mon& rm, const factorization& factorization) {
|
|
return
|
|
basic_lemma_for_mon_neutral_monomial_to_factor(rm, factorization) ||
|
|
basic_lemma_for_mon_neutral_from_factors_to_monomial(rm, factorization);
|
|
return false;
|
|
}
|
|
|
|
// use basic multiplication properties to create a lemma
|
|
// for the given monomial
|
|
bool basic_lemma_for_mon(const rooted_mon& rm) {
|
|
if (vvr(rm).is_zero()) {
|
|
for (auto factorization : factorization_factory_imp(rm.m_vars, *this)) {
|
|
if (factorization.is_empty())
|
|
continue;
|
|
if (basic_lemma_for_mon_zero(rm, factorization) ||
|
|
basic_lemma_for_mon_neutral(rm, factorization))
|
|
return true;
|
|
}
|
|
} else {
|
|
for (auto factorization : factorization_factory_imp(rm.m_vars, *this)) {
|
|
if (factorization.is_empty())
|
|
continue;
|
|
if (basic_lemma_for_mon_non_zero(rm, factorization) ||
|
|
basic_lemma_for_mon_neutral(rm, factorization))
|
|
return true;
|
|
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// use basic multiplication properties to create a lemma
|
|
bool basic_lemma() {
|
|
if (basic_sign_lemma())
|
|
return true;
|
|
|
|
for (const rooted_mon& r : m_rm_table.vec()) {
|
|
if (check_monomial(m_monomials[r.orig_index()]))
|
|
continue;
|
|
if (basic_lemma_for_mon(r)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void map_monomial_vars_to_monomial_indices(unsigned i) {
|
|
const monomial& m = m_monomials[i];
|
|
for (lpvar j : m.vars()) {
|
|
auto it = m_monomials_containing_var.find(j);
|
|
if (it == m_monomials_containing_var.end()) {
|
|
unsigned_vector ms;
|
|
ms.push_back(i);
|
|
m_monomials_containing_var[j] = ms;
|
|
}
|
|
else {
|
|
it->second.push_back(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
void map_vars_to_monomials() {
|
|
for (unsigned i = 0; i < m_monomials.size(); i++)
|
|
map_monomial_vars_to_monomial_indices(i);
|
|
}
|
|
|
|
// we look for octagon constraints here, with a left part +-x +- y
|
|
void collect_equivs() {
|
|
const lp::lar_solver& s = m_lar_solver;
|
|
|
|
for (unsigned i = 0; i < s.terms().size(); i++) {
|
|
unsigned ti = i + s.terms_start_index();
|
|
if (!s.term_is_used_as_row(ti))
|
|
continue;
|
|
lpvar j = s.external2local(ti);
|
|
if (var_is_fixed_to_zero(j)) {
|
|
TRACE("nla_solver", tout << "term = "; s.print_term(*s.terms()[i], tout););
|
|
add_equivalence_maybe(s.terms()[i], s.get_column_upper_bound_witness(j), s.get_column_lower_bound_witness(j));
|
|
}
|
|
}
|
|
}
|
|
|
|
void add_equivalence_maybe(const lp::lar_term *t, lpci c0, lpci c1) {
|
|
if (t->size() != 2)
|
|
return;
|
|
bool seen_minus = false;
|
|
bool seen_plus = false;
|
|
lpvar i = -1, j;
|
|
for(const auto & p : *t) {
|
|
const auto & c = p.coeff();
|
|
if (c == 1) {
|
|
seen_plus = true;
|
|
} else if (c == - 1) {
|
|
seen_minus = true;
|
|
} else {
|
|
return;
|
|
}
|
|
if (i == static_cast<lpvar>(-1))
|
|
i = p.var();
|
|
else
|
|
j = p.var();
|
|
}
|
|
TRACE("nla_solver", tout << "adding equiv";);
|
|
rational sign((seen_minus && seen_plus)? 1 : -1);
|
|
m_vars_equivalence.add_equiv(i, j, sign, c0, c1);
|
|
}
|
|
|
|
// x is equivalent to y if x = +- y
|
|
void init_vars_equivalence() {
|
|
m_vars_equivalence.clear();
|
|
collect_equivs();
|
|
m_vars_equivalence.create_tree();
|
|
for (lpvar j = 0; j < m_lar_solver.number_of_vars(); j++) {
|
|
m_vars_equivalence.register_var(j, vvr(j));
|
|
}
|
|
}
|
|
|
|
bool var_is_a_root(lpvar j) const { return m_vars_equivalence.is_root(j); }
|
|
|
|
template <typename T>
|
|
bool vars_are_roots(const T& v) const {
|
|
for (lpvar j: v) {
|
|
if (!var_is_a_root(j))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
void register_monomial_in_tables(unsigned i_mon) {
|
|
m_vars_equivalence.register_monomial_in_abs_vals(i_mon, m_monomials[i_mon]);
|
|
monomial_coeff mc = canonize_monomial(m_monomials[i_mon]);
|
|
m_rm_table.register_key_mono_in_rooted_monomials(mc, i_mon);
|
|
}
|
|
|
|
template <typename T>
|
|
void trace_print_rms(const T& p, std::ostream& out) {
|
|
out << "p = {";
|
|
for (auto j : p) {
|
|
out << "\nj = " << j <<
|
|
", rm = ";
|
|
print_rooted_monomial(m_rm_table.vec()[j], out);
|
|
}
|
|
out << "\n}";
|
|
}
|
|
|
|
|
|
|
|
|
|
void register_monomials_in_tables() {
|
|
m_vars_equivalence.clear_monomials_by_abs_vals();
|
|
for (unsigned i = 0; i < m_monomials.size(); i++)
|
|
register_monomial_in_tables(i);
|
|
|
|
m_rm_table.fill_rooted_monomials_containing_var();
|
|
m_rm_table.fill_rooted_factor_to_product();
|
|
}
|
|
|
|
void init_search() {
|
|
map_vars_to_monomials();
|
|
init_vars_equivalence();
|
|
register_monomials_in_tables();
|
|
m_expl->clear();
|
|
m_lemma->clear();
|
|
}
|
|
|
|
|
|
bool divide(const rooted_mon& bc, const factor& c, factor & b) const {
|
|
svector<lpvar> c_vars = sorted_vars(c);
|
|
TRACE("nla_solver_div",
|
|
tout << "c_vars = ";
|
|
print_product(c_vars, tout);
|
|
tout << "\nbc_vars = ";
|
|
print_product(bc.vars(), tout););
|
|
if (!lp::is_proper_factor(c_vars, bc.vars()))
|
|
return false;
|
|
|
|
auto b_vars = lp::vector_div(bc.vars(), c_vars);
|
|
TRACE("nla_solver_div", tout << "b_vars = "; print_product(b_vars, tout););
|
|
SASSERT(b_vars.size() > 0);
|
|
if (b_vars.size() == 1) {
|
|
b = factor(b_vars[0]);
|
|
return true;
|
|
}
|
|
auto it = m_rm_table.map().find(b_vars);
|
|
if (it == m_rm_table.map().end()) {
|
|
TRACE("nla_solver_div", tout << "not in rooted";);
|
|
return false;
|
|
}
|
|
b = factor(it->second.m_i, factor_type::RM);
|
|
TRACE("nla_solver_div", tout << "success div:"; print_factor(b, tout););
|
|
return true;
|
|
}
|
|
|
|
void negate_factor_equality(const factor& c,
|
|
const factor& d) {
|
|
if (c == d)
|
|
return;
|
|
lpvar i = var(c);
|
|
lpvar j = var(d);
|
|
auto iv = vvr(i), jv = vvr(j);
|
|
SASSERT(abs(iv) == abs(jv));
|
|
if (iv == jv) {
|
|
mk_ineq(i, -rational(1), j, lp::lconstraint_kind::NE);
|
|
} else { // iv == -jv
|
|
mk_ineq(i, j, lp::lconstraint_kind::NE);
|
|
}
|
|
}
|
|
|
|
void negate_factor_relation(const rational& a_sign, const factor& a, const rational& b_sign, const factor& b) {
|
|
rational a_fs = flip_sign(a);
|
|
rational b_fs = flip_sign(b);
|
|
lp::lconstraint_kind cmp = a_sign*vvr(a) < b_sign*vvr(b)? lp::lconstraint_kind::GE : lp::lconstraint_kind::LE;
|
|
mk_ineq(a_fs*a_sign, var(a), - b_fs*b_sign, var(b), cmp);
|
|
}
|
|
|
|
void generate_ol(const rooted_mon& ac,
|
|
const factor& a,
|
|
int c_sign,
|
|
const factor& c,
|
|
const rooted_mon& bd,
|
|
const factor& b,
|
|
int d_sign,
|
|
const factor& d,
|
|
lp::lconstraint_kind ab_cmp) {
|
|
negate_factor_equality(c, d);
|
|
negate_factor_relation(rational(c_sign), a, rational(d_sign), b);
|
|
mk_ineq(flip_sign(ac), var(ac), -flip_sign(bd), var(bd), ab_cmp);
|
|
}
|
|
|
|
bool order_lemma_on_ac_and_bd_and_factors(const rooted_mon& ac,
|
|
const factor& a,
|
|
const factor& c,
|
|
const rooted_mon& bd,
|
|
const factor& b,
|
|
const factor& d) {
|
|
TRACE("nla_solver", tout << "a = "; print_factor(a, tout); tout << ", b = "; print_factor(b, tout););
|
|
SASSERT(abs(vvr(c)) == abs(vvr(d)));
|
|
auto av = vvr(a); auto bv = vvr(b);
|
|
auto cv = vvr(c); auto dv = vvr(d);
|
|
auto acv = vvr(ac); auto bdv = vvr(bd);
|
|
|
|
if (cv == dv) {
|
|
if (cv.is_pos()) {
|
|
if (av < bv){
|
|
if(!(acv < bdv)) {
|
|
generate_ol(ac, a, 1, c, bd, b, 1, d, lp::lconstraint_kind::LT);
|
|
return true;
|
|
}
|
|
return false;
|
|
} else if (av > bv){
|
|
if(!(acv > bdv)) {
|
|
generate_ol(ac, a, 1, c, bd, b, 1, d, lp::lconstraint_kind::GT);
|
|
return true;
|
|
}
|
|
return false;
|
|
} else {
|
|
SASSERT(av == bv);
|
|
// the sign lemma should take care of this case
|
|
}
|
|
} else {
|
|
SASSERT(cv.is_neg());
|
|
if (av < bv){
|
|
if(!(acv > bdv)) {
|
|
generate_ol(ac, a, 1, c, bd, b, 1, d, lp::lconstraint_kind::GT);
|
|
return true;
|
|
}
|
|
return false;
|
|
} else if (av > bv){
|
|
if(!(acv < bdv)) {
|
|
generate_ol(ac, a, 1, c, bd, b, 1, d, lp::lconstraint_kind::LT);
|
|
return true;
|
|
}
|
|
return false;
|
|
} else {
|
|
SASSERT(av == bv);
|
|
// the sign lemma should take care of this case
|
|
}
|
|
}
|
|
} else { // cv == -dv
|
|
if (cv.is_pos()) {
|
|
if (av < -bv){
|
|
if(!(acv < bdv)) {
|
|
generate_ol(ac, a, 1, c, bd, b, -1, d, lp::lconstraint_kind::LT);
|
|
return true;
|
|
}
|
|
return false;
|
|
} else if (av > -bv){
|
|
if(!(acv > bdv)) {
|
|
generate_ol(ac, a, 1, c, bd, b, -1, d, lp::lconstraint_kind::GT);
|
|
return true;
|
|
}
|
|
return false;
|
|
} else {
|
|
SASSERT(av == bv);
|
|
// the sign lemma should take care of this case
|
|
}
|
|
} else {
|
|
SASSERT(cv.is_neg());
|
|
if (-av < bv){
|
|
if(!(acv < bdv)) {
|
|
generate_ol(ac, a, -1, c, bd, b, 1, d, lp::lconstraint_kind::LT);
|
|
return true;
|
|
}
|
|
return false;
|
|
} else if (-av > bv){
|
|
if(!(acv > bdv)) {
|
|
generate_ol(ac, a, -1, c, bd, b, 1, d, lp::lconstraint_kind::GT);
|
|
return true;
|
|
}
|
|
return false;
|
|
} else {
|
|
SASSERT(av == bv);
|
|
// the sign lemma should take care of this case
|
|
}
|
|
}
|
|
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// a > b && c > 0 && d = c => ac > bd
|
|
// ac is a factorization of m_monomials[i_mon]
|
|
// ac[k] plays the role of c
|
|
bool order_lemma_on_ac_and_bd(const rooted_mon& rm_ac,
|
|
const factorization& ac_f,
|
|
unsigned k,
|
|
const rooted_mon& rm_bd,
|
|
const factor& d) {
|
|
TRACE("nla_solver", tout << "rm_ac = ";
|
|
print_rooted_monomial(rm_ac, tout);
|
|
tout << "\nrm_bd = ";
|
|
print_rooted_monomial(rm_bd, tout);
|
|
tout << ", d = "; print_factor(d, tout););
|
|
SASSERT(abs(vvr(ac_f[k])) == abs(vvr(d)));
|
|
factor b;
|
|
if (!divide(rm_bd, d, b)){
|
|
return false;
|
|
}
|
|
|
|
return order_lemma_on_ac_and_bd_and_factors(rm_ac, ac_f[(k + 1) % 2], ac_f[k], rm_bd, b, d);
|
|
}
|
|
|
|
// collect all vars and rooted monomials with the same absolute
|
|
// value as c and return them as factors
|
|
vector<factor> factors_with_the_same_abs_val(const factor& c) const {
|
|
vector<factor> r;
|
|
std::unordered_set<lpvar> found_vars;
|
|
std::unordered_set<unsigned> found_rm;
|
|
TRACE("nla_solver", tout << "c = "; print_factor_with_vars(c, tout););
|
|
for (lpvar i : m_vars_equivalence.get_vars_with_the_same_abs_val(vvr(c))) {
|
|
auto it = m_var_to_its_monomial.find(i);
|
|
if (it == m_var_to_its_monomial.end()) {
|
|
i = m_vars_equivalence.map_to_root(i);
|
|
if (!contains(found_vars, i)) {
|
|
found_vars.insert(i);
|
|
r.push_back(factor(i, factor_type::VAR));
|
|
}
|
|
} else {
|
|
const monomial& m = m_monomials[it->second];
|
|
monomial_coeff mc = canonize_monomial(m);
|
|
auto it = m_rm_table.map().find(mc.vars());
|
|
SASSERT(it != m_rm_table.map().end());
|
|
i = it->second.m_i;
|
|
if (!contains(found_rm, i)) {
|
|
found_rm.insert(i);
|
|
r.push_back(factor(i, factor_type::RM));
|
|
TRACE("nla_solver", tout << "insering factor = "; print_factor(factor(i, factor_type::RM), tout); );
|
|
}
|
|
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
|
|
// a > b && c > 0 => ac > bc
|
|
// ac is a factorization of m_monomials[i_mon]
|
|
// ac[k] plays the role of c
|
|
bool order_lemma_on_factor(const rooted_mon& rm, const factorization& ac, unsigned k) {
|
|
auto c = ac[k];
|
|
TRACE("nla_solver", tout << "k = " << k << ", c = "; print_factor(c, tout); );
|
|
|
|
for (const factor & d : factors_with_the_same_abs_val(c)) {
|
|
TRACE("nla_solver", tout << "d = "; print_factor(d, tout); );
|
|
if (d.is_var()) {
|
|
TRACE("nla_solver", tout << "var(d) = " << var(d););
|
|
for (unsigned rm_bd : m_rm_table.var_map()[d.index()]) {
|
|
TRACE("nla_solver", );
|
|
if (order_lemma_on_ac_and_bd(rm , ac, k, m_rm_table.vec()[rm_bd], d)) {
|
|
return true;
|
|
}
|
|
}
|
|
} else {
|
|
TRACE("nla_solver", tout << "not a var = " << m_rm_table.factor_to_product()[d.index()].size() ;);
|
|
for (unsigned rm_bd : m_rm_table.factor_to_product()[d.index()]) {
|
|
TRACE("nla_solver", );
|
|
if (order_lemma_on_ac_and_bd(rm , ac, k, m_rm_table.vec()[rm_bd], d)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// a > b && c == d => ac > bd
|
|
// ac is a factorization of m_monomials[i_mon]
|
|
bool order_lemma_on_factorization(const rooted_mon& rm, const factorization& ac) {
|
|
SASSERT(ac.size() == 2);
|
|
CTRACE("nla_solver",
|
|
rm.vars().size() == 4,
|
|
tout << "rm = "; print_rooted_monomial(rm, tout);
|
|
tout << ", factorization = "; print_factorization(ac, tout););
|
|
for (unsigned k = 0; k < ac.size(); k++) {
|
|
const rational & v = vvr(ac[k]);
|
|
if (v.is_zero())
|
|
continue;
|
|
|
|
if (order_lemma_on_factor(rm, ac, k)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// a > b && c > 0 => ac > bc
|
|
bool order_lemma_on_monomial(const rooted_mon& rm) {
|
|
TRACE("nla_solver",
|
|
tout << "rm = "; print_product(rm, tout);
|
|
tout << ", orig = "; print_monomial(m_monomials[rm.orig_index()], tout);
|
|
);
|
|
for (auto ac : factorization_factory_imp(rm.vars(), *this)) {
|
|
if (ac.size() != 2)
|
|
continue;
|
|
if (order_lemma_on_factorization(rm, ac))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool order_lemma() {
|
|
for (const auto& rm : m_rm_table.vec()) {
|
|
if (check_monomial(m_monomials[rm.orig_index()]))
|
|
continue;
|
|
if (order_lemma_on_monomial(rm)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool monotonicity_lemma_on_factorization(unsigned i_mon, const factorization& factorization) {
|
|
return false;
|
|
}
|
|
|
|
bool monotonicity_lemma_on_monomial() {
|
|
/*
|
|
for (auto factorization : factorization_factory_imp(i_mon, *this)) {
|
|
if (factorization.is_empty())
|
|
continue;
|
|
if (monotonicity_lemma_on_factorization(i_mon, factorization))
|
|
return true;
|
|
}*/
|
|
return false;
|
|
}
|
|
|
|
bool monotonicity_lemma() {
|
|
|
|
// for (unsigned i_mon : to_refine) {
|
|
// if (monotonicity_lemma_on_monomial(i_mon)) {
|
|
// return true;
|
|
// }
|
|
// }
|
|
|
|
return false;
|
|
}
|
|
|
|
bool tangent_lemma() {
|
|
return false;
|
|
}
|
|
|
|
lbool check(lp::explanation & exp, lemma& l) {
|
|
TRACE("nla_solver", tout << "check of nla";);
|
|
m_expl = &exp;
|
|
m_lemma = &l;
|
|
|
|
if (!(m_lar_solver.get_status() == lp::lp_status::OPTIMAL || m_lar_solver.get_status() == lp::lp_status::FEASIBLE )) {
|
|
TRACE("nla_solver", tout << "unknown because of the m_lar_solver.m_status = " << lp_status_to_string(m_lar_solver.get_status()) << "\n";);
|
|
return l_undef;
|
|
}
|
|
|
|
bool to_refine = false;
|
|
for (unsigned i = 0; i < m_monomials.size() && !to_refine; i++) {
|
|
if (!check_monomial(m_monomials[i]))
|
|
to_refine = true;
|
|
}
|
|
|
|
if (!to_refine) {
|
|
return l_true;
|
|
}
|
|
|
|
init_search();
|
|
for (int search_level = 0; search_level < 3; search_level++) {
|
|
if (search_level == 0) {
|
|
if (basic_lemma()) {
|
|
return l_false;
|
|
}
|
|
} else if (search_level == 1) {
|
|
if (order_lemma()) {
|
|
return l_false;
|
|
}
|
|
} else { // search_level == 3
|
|
if (monotonicity_lemma()) {
|
|
return l_false;
|
|
}
|
|
|
|
if (tangent_lemma()) {
|
|
return l_false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return l_undef;
|
|
}
|
|
|
|
void test_factorization(unsigned mon_index, unsigned number_of_factorizations) {
|
|
vector<ineq> lemma;
|
|
m_lemma = & lemma;
|
|
lp::explanation exp;
|
|
m_expl = & exp;
|
|
init_search();
|
|
|
|
factorization_factory_imp fc(m_monomials[mon_index].vars(), // 0 is the index of "abcde"
|
|
*this);
|
|
|
|
std::cout << "factorizations = of "; print_var(m_monomials[0].var(), std::cout) << "\n";
|
|
unsigned found_factorizations = 0;
|
|
for (auto f : fc) {
|
|
if (f.is_empty()) continue;
|
|
found_factorizations ++;
|
|
for (auto j : f) {
|
|
std::cout << "j = "; print_factor(j, std::cout);
|
|
}
|
|
std::cout << std::endl;
|
|
}
|
|
SASSERT(found_factorizations == number_of_factorizations);
|
|
}
|
|
|
|
lbool test_check(
|
|
vector<ineq>& lemma,
|
|
lp::explanation& exp )
|
|
{
|
|
m_lar_solver.set_status(lp::lp_status::OPTIMAL);
|
|
m_lemma = & lemma;
|
|
m_expl = & exp;
|
|
|
|
return check(exp, lemma);
|
|
}
|
|
}; // end of imp
|
|
|
|
// returns the monomial index
|
|
unsigned solver::add_monomial(lpvar v, unsigned sz, lpvar const* vs) {
|
|
return m_imp->add(v, sz, vs);
|
|
}
|
|
|
|
bool solver::need_check() { return true; }
|
|
|
|
lbool solver::check(lp::explanation & ex, lemma& l) {
|
|
return m_imp->check(ex, l);
|
|
}
|
|
|
|
void solver::push(){
|
|
m_imp->push();
|
|
}
|
|
|
|
void solver::pop(unsigned n) {
|
|
m_imp->pop(n);
|
|
}
|
|
|
|
solver::solver(lp::lar_solver& s, reslimit& lim, params_ref const& p) {
|
|
m_imp = alloc(imp, s, lim, p);
|
|
}
|
|
|
|
solver::~solver() {
|
|
dealloc(m_imp);
|
|
}
|
|
|
|
void create_abcde(solver & nla,
|
|
unsigned lp_a,
|
|
unsigned lp_b,
|
|
unsigned lp_c,
|
|
unsigned lp_d,
|
|
unsigned lp_e,
|
|
unsigned lp_abcde,
|
|
unsigned lp_ac,
|
|
unsigned lp_bde,
|
|
unsigned lp_acd,
|
|
unsigned lp_be) {
|
|
// create monomial abcde
|
|
vector<unsigned> vec;
|
|
vec.push_back(lp_a);
|
|
vec.push_back(lp_b);
|
|
vec.push_back(lp_c);
|
|
vec.push_back(lp_d);
|
|
vec.push_back(lp_e);
|
|
|
|
nla.add_monomial(lp_abcde, vec.size(), vec.begin());
|
|
|
|
// create monomial ac
|
|
vec.clear();
|
|
vec.push_back(lp_a);
|
|
vec.push_back(lp_c);
|
|
nla.add_monomial(lp_ac, vec.size(), vec.begin());
|
|
|
|
// create monomial bde
|
|
vec.clear();
|
|
vec.push_back(lp_b);
|
|
vec.push_back(lp_d);
|
|
vec.push_back(lp_e);
|
|
nla.add_monomial(lp_bde, vec.size(), vec.begin());
|
|
|
|
// create monomial acd
|
|
vec.clear();
|
|
vec.push_back(lp_a);
|
|
vec.push_back(lp_c);
|
|
vec.push_back(lp_d);
|
|
nla.add_monomial(lp_acd, vec.size(), vec.begin());
|
|
|
|
// create monomial be
|
|
vec.clear();
|
|
vec.push_back(lp_b);
|
|
vec.push_back(lp_e);
|
|
nla.add_monomial(lp_be, vec.size(), vec.begin());
|
|
}
|
|
|
|
void solver::test_factorization() {
|
|
lp::lar_solver s;
|
|
unsigned a = 0, b = 1, c = 2, d = 3, e = 4,
|
|
abcde = 5, ac = 6, bde = 7, acd = 8, be = 9;
|
|
lpvar lp_a = s.add_var(a, true);
|
|
lpvar lp_b = s.add_var(b, true);
|
|
lpvar lp_c = s.add_var(c, true);
|
|
lpvar lp_d = s.add_var(d, true);
|
|
lpvar lp_e = s.add_var(e, true);
|
|
lpvar lp_abcde = s.add_var(abcde, true);
|
|
lpvar lp_ac = s.add_var(ac, true);
|
|
lpvar lp_bde = s.add_var(bde, true);
|
|
lpvar lp_acd = s.add_var(acd, true);
|
|
lpvar lp_be = s.add_var(be, true);
|
|
|
|
reslimit l;
|
|
params_ref p;
|
|
solver nla(s, l, p);
|
|
|
|
create_abcde(nla,
|
|
lp_a,
|
|
lp_b,
|
|
lp_c,
|
|
lp_d,
|
|
lp_e,
|
|
lp_abcde,
|
|
lp_ac,
|
|
lp_bde,
|
|
lp_acd,
|
|
lp_be);
|
|
|
|
nla.m_imp->test_factorization(0, // 0 is the index of monomial abcde
|
|
3); // 3 is the number of expected factorizations
|
|
|
|
|
|
}
|
|
|
|
void solver::test_basic_lemma_for_mon_neutral_from_factors_to_monomial() {
|
|
test_basic_lemma_for_mon_neutral_from_factors_to_monomial_0();
|
|
test_basic_lemma_for_mon_neutral_from_factors_to_monomial_1();
|
|
}
|
|
|
|
void solver::test_basic_lemma_for_mon_neutral_from_factors_to_monomial_0() {
|
|
std::cout << "test_basic_lemma_for_mon_neutral_from_factors_to_monomial_0\n";
|
|
// enable_trace("nla_solver");
|
|
TRACE("nla_solver",);
|
|
lp::lar_solver s;
|
|
unsigned a = 0, b = 1, c = 2, d = 3, e = 4,
|
|
abcde = 5, ac = 6, bde = 7;
|
|
lpvar lp_a = s.add_var(a, true);
|
|
lpvar lp_b = s.add_var(b, true);
|
|
lpvar lp_c = s.add_var(c, true);
|
|
lpvar lp_d = s.add_var(d, true);
|
|
lpvar lp_e = s.add_var(e, true);
|
|
lpvar lp_abcde = s.add_var(abcde, true);
|
|
lpvar lp_ac = s.add_var(ac, true);
|
|
lpvar lp_bde = s.add_var(bde, true);
|
|
|
|
reslimit l;
|
|
params_ref p;
|
|
solver nla(s, l, p);
|
|
svector<lpvar> v; v.push_back(lp_b);v.push_back(lp_d);v.push_back(lp_e);
|
|
nla.add_monomial(lp_bde, v.size(), v.begin());
|
|
v.clear();
|
|
v.push_back(lp_a);v.push_back(lp_b);v.push_back(lp_c);v.push_back(lp_d);v.push_back(lp_e);
|
|
nla.add_monomial(lp_abcde, v.size(), v.begin());
|
|
v.clear();
|
|
v.push_back(lp_a);v.push_back(lp_c);
|
|
nla.add_monomial(lp_ac, v.size(), v.begin());
|
|
|
|
vector<ineq> lemma;
|
|
lp::explanation exp;
|
|
|
|
// set abcde = ac * bde
|
|
// ac = 1, bde = 3 -> abcde = bde, but we have abcde set to 2
|
|
s.set_column_value(lp_a, rational(4));
|
|
s.set_column_value(lp_b, rational(4));
|
|
s.set_column_value(lp_c, rational(4));
|
|
s.set_column_value(lp_d, rational(4));
|
|
s.set_column_value(lp_e, rational(4));
|
|
s.set_column_value(lp_abcde, rational(2));
|
|
s.set_column_value(lp_ac, rational(1));
|
|
s.set_column_value(lp_bde, rational(3));
|
|
|
|
|
|
SASSERT(nla.m_imp->test_check(lemma, exp) == l_false);
|
|
|
|
nla.m_imp->print_lemma(std::cout << "expl & lemma: ");
|
|
|
|
ineq i0(lp::lconstraint_kind::NE, lp::lar_term(), rational(1));
|
|
i0.m_term.add_coeff_var(lp_ac);
|
|
ineq i1(lp::lconstraint_kind::EQ, lp::lar_term(), rational(0));
|
|
i1.m_term.add_coeff_var(lp_bde);
|
|
i1.m_term.add_coeff_var(-rational(1), lp_abcde);
|
|
ineq i2(lp::lconstraint_kind::EQ, lp::lar_term(), rational(0));
|
|
i2.m_term.add_coeff_var(lp_abcde);
|
|
i2.m_term.add_coeff_var(-rational(1), lp_bde);
|
|
bool found0 = false;
|
|
bool found1 = false;
|
|
bool found2 = false;
|
|
for (const auto& k : lemma){
|
|
if (k == i0) {
|
|
found0 = true;
|
|
} else if (k == i1) {
|
|
found1 = true;
|
|
} else if (k == i2) {
|
|
found2 = true;
|
|
}
|
|
}
|
|
|
|
SASSERT(found0 && (found1 || found2));
|
|
|
|
|
|
}
|
|
|
|
void solver::test_basic_lemma_for_mon_neutral_from_factors_to_monomial_1() {
|
|
std::cout << "test_basic_lemma_for_mon_neutral_from_factors_to_monomial_1\n";
|
|
TRACE("nla_solver",);
|
|
lp::lar_solver s;
|
|
unsigned a = 0, b = 1, c = 2, d = 3, e = 4,
|
|
bde = 7;
|
|
lpvar lp_a = s.add_var(a, true);
|
|
lpvar lp_b = s.add_var(b, true);
|
|
lpvar lp_c = s.add_var(c, true);
|
|
lpvar lp_d = s.add_var(d, true);
|
|
lpvar lp_e = s.add_var(e, true);
|
|
lpvar lp_bde = s.add_var(bde, true);
|
|
|
|
reslimit l;
|
|
params_ref p;
|
|
solver nla(s, l, p);
|
|
svector<lpvar> v; v.push_back(lp_b);v.push_back(lp_d);v.push_back(lp_e);
|
|
nla.add_monomial(lp_bde, v.size(), v.begin());
|
|
|
|
vector<ineq> lemma;
|
|
lp::explanation exp;
|
|
|
|
s.set_column_value(lp_a, rational(1));
|
|
s.set_column_value(lp_b, rational(1));
|
|
s.set_column_value(lp_c, rational(1));
|
|
s.set_column_value(lp_d, rational(1));
|
|
s.set_column_value(lp_e, rational(1));
|
|
s.set_column_value(lp_bde, rational(3));
|
|
|
|
SASSERT(nla.m_imp->test_check(lemma, exp) == l_false);
|
|
SASSERT(lemma.size() == 4);
|
|
nla.m_imp->print_lemma(std::cout << "expl & lemma: ");
|
|
|
|
ineq i0(lp::lconstraint_kind::NE, lp::lar_term(), rational(1));
|
|
i0.m_term.add_coeff_var(lp_b);
|
|
ineq i1(lp::lconstraint_kind::NE, lp::lar_term(), rational(1));
|
|
i1.m_term.add_coeff_var(lp_d);
|
|
ineq i2(lp::lconstraint_kind::NE, lp::lar_term(), rational(1));
|
|
i2.m_term.add_coeff_var(lp_e);
|
|
ineq i3(lp::lconstraint_kind::EQ, lp::lar_term(), rational(1));
|
|
i3.m_term.add_coeff_var(lp_bde);
|
|
bool found0 = false;
|
|
bool found1 = false;
|
|
bool found2 = false;
|
|
bool found3 = false;
|
|
for (const auto& k : lemma){
|
|
if (k == i0) {
|
|
found0 = true;
|
|
} else if (k == i1) {
|
|
found1 = true;
|
|
} else if (k == i2) {
|
|
found2 = true;
|
|
} else if (k == i3) {
|
|
found3 = true;
|
|
}
|
|
|
|
}
|
|
|
|
SASSERT(found0 && found1 && found2 && found3);
|
|
|
|
}
|
|
|
|
void solver::test_basic_lemma_for_mon_zero_from_factors_to_monomial() {
|
|
std::cout << "test_basic_lemma_for_mon_zero_from_factors_to_monomial\n";
|
|
lp::lar_solver s;
|
|
unsigned a = 0, b = 1, c = 2, d = 3, e = 4,
|
|
abcde = 5, ac = 6, bde = 7, acd = 8, be = 9;
|
|
lpvar lp_a = s.add_var(a, true);
|
|
lpvar lp_b = s.add_var(b, true);
|
|
lpvar lp_c = s.add_var(c, true);
|
|
lpvar lp_d = s.add_var(d, true);
|
|
lpvar lp_e = s.add_var(e, true);
|
|
lpvar lp_abcde = s.add_var(abcde, true);
|
|
lpvar lp_ac = s.add_var(ac, true);
|
|
lpvar lp_bde = s.add_var(bde, true);
|
|
lpvar lp_acd = s.add_var(acd, true);
|
|
lpvar lp_be = s.add_var(be, true);
|
|
|
|
reslimit l;
|
|
params_ref p;
|
|
solver nla(s, l, p);
|
|
|
|
create_abcde(nla,
|
|
lp_a,
|
|
lp_b,
|
|
lp_c,
|
|
lp_d,
|
|
lp_e,
|
|
lp_abcde,
|
|
lp_ac,
|
|
lp_bde,
|
|
lp_acd,
|
|
lp_be);
|
|
vector<ineq> lemma;
|
|
lp::explanation exp;
|
|
|
|
|
|
// set vars
|
|
s.set_column_value(lp_a, rational(1));
|
|
s.set_column_value(lp_b, rational(0));
|
|
s.set_column_value(lp_c, rational(1));
|
|
s.set_column_value(lp_d, rational(1));
|
|
s.set_column_value(lp_e, rational(1));
|
|
s.set_column_value(lp_abcde, rational(0));
|
|
s.set_column_value(lp_ac, rational(1));
|
|
s.set_column_value(lp_bde, rational(0));
|
|
s.set_column_value(lp_acd, rational(1));
|
|
s.set_column_value(lp_be, rational(1));
|
|
|
|
SASSERT(nla.m_imp->test_check(lemma, exp) == l_false);
|
|
nla.m_imp->print_lemma(std::cout << "expl & lemma: ");
|
|
SASSERT(lemma.size() == 2);
|
|
ineq i0(lp::lconstraint_kind::NE, lp::lar_term(), rational(0));
|
|
i0.m_term.add_coeff_var(lp_b);
|
|
ineq i1(lp::lconstraint_kind::EQ, lp::lar_term(), rational(0));
|
|
i1.m_term.add_coeff_var(lp_be);
|
|
bool found0 = false;
|
|
bool found1 = false;
|
|
|
|
for (const auto& k : lemma){
|
|
if (k == i0) {
|
|
found0 = true;
|
|
} else if (k == i1) {
|
|
found1 = true;
|
|
}
|
|
}
|
|
|
|
SASSERT(found0 && found1);
|
|
}
|
|
|
|
void solver::test_basic_lemma_for_mon_zero_from_monomial_to_factors() {
|
|
std::cout << "test_basic_lemma_for_mon_zero_from_monomial_to_factors\n";
|
|
lp::lar_solver s;
|
|
unsigned a = 0, b = 1, c = 2, d = 3, e = 4,
|
|
abcde = 5, ac = 6, bde = 7, acd = 8, be = 9;
|
|
lpvar lp_a = s.add_var(a, true);
|
|
lpvar lp_b = s.add_var(b, true);
|
|
lpvar lp_c = s.add_var(c, true);
|
|
lpvar lp_d = s.add_var(d, true);
|
|
lpvar lp_e = s.add_var(e, true);
|
|
lpvar lp_abcde = s.add_var(abcde, true);
|
|
lpvar lp_ac = s.add_var(ac, true);
|
|
lpvar lp_bde = s.add_var(bde, true);
|
|
lpvar lp_acd = s.add_var(acd, true);
|
|
lpvar lp_be = s.add_var(be, true);
|
|
|
|
reslimit l;
|
|
params_ref p;
|
|
solver nla(s, l, p);
|
|
|
|
create_abcde(nla,
|
|
lp_a,
|
|
lp_b,
|
|
lp_c,
|
|
lp_d,
|
|
lp_e,
|
|
lp_abcde,
|
|
lp_ac,
|
|
lp_bde,
|
|
lp_acd,
|
|
lp_be);
|
|
vector<ineq> lemma;
|
|
lp::explanation exp;
|
|
|
|
|
|
s.set_column_value(lp_b, rational(1));
|
|
s.set_column_value(lp_d, rational(1));
|
|
s.set_column_value(lp_e, rational(1));
|
|
|
|
// set bde to zero
|
|
s.set_column_value(lp_bde, rational(0));
|
|
|
|
SASSERT(nla.m_imp->test_check(lemma, exp) == l_false);
|
|
|
|
nla.m_imp->print_lemma(std::cout << "expl & lemma: ");
|
|
|
|
ineq i0(lp::lconstraint_kind::EQ, lp::lar_term(), rational(0));
|
|
i0.m_term.add_coeff_var(lp_b);
|
|
ineq i1(lp::lconstraint_kind::EQ, lp::lar_term(), rational(0));
|
|
i1.m_term.add_coeff_var(lp_d);
|
|
ineq i2(lp::lconstraint_kind::EQ, lp::lar_term(), rational(0));
|
|
i2.m_term.add_coeff_var(lp_e);
|
|
bool found0 = false;
|
|
bool found1 = false;
|
|
bool found2 = false;
|
|
|
|
for (const auto& k : lemma){
|
|
if (k == i0) {
|
|
found0 = true;
|
|
} else if (k == i1) {
|
|
found1 = true;
|
|
} else if (k == i2){
|
|
found2 = true;
|
|
}
|
|
}
|
|
|
|
SASSERT(found0 && found1 && found2);
|
|
|
|
}
|
|
|
|
void solver::test_basic_lemma_for_mon_neutral_from_monomial_to_factors() {
|
|
std::cout << "test_basic_lemma_for_mon_neutral_from_monomial_to_factors\n";
|
|
lp::lar_solver s;
|
|
unsigned a = 0, b = 1, c = 2, d = 3, e = 4,
|
|
abcde = 5, ac = 6, bde = 7, acd = 8, be = 9;
|
|
lpvar lp_a = s.add_var(a, true);
|
|
lpvar lp_b = s.add_var(b, true);
|
|
lpvar lp_c = s.add_var(c, true);
|
|
lpvar lp_d = s.add_var(d, true);
|
|
lpvar lp_e = s.add_var(e, true);
|
|
lpvar lp_abcde = s.add_var(abcde, true);
|
|
lpvar lp_ac = s.add_var(ac, true);
|
|
lpvar lp_bde = s.add_var(bde, true);
|
|
lpvar lp_acd = s.add_var(acd, true);
|
|
lpvar lp_be = s.add_var(be, true);
|
|
|
|
reslimit l;
|
|
params_ref p;
|
|
solver nla(s, l, p);
|
|
|
|
create_abcde(nla,
|
|
lp_a,
|
|
lp_b,
|
|
lp_c,
|
|
lp_d,
|
|
lp_e,
|
|
lp_abcde,
|
|
lp_ac,
|
|
lp_bde,
|
|
lp_acd,
|
|
lp_be);
|
|
vector<ineq> lemma;
|
|
lp::explanation exp;
|
|
|
|
// set all vars to 1
|
|
s.set_column_value(lp_a, rational(1));
|
|
s.set_column_value(lp_b, rational(1));
|
|
s.set_column_value(lp_c, rational(1));
|
|
s.set_column_value(lp_d, rational(1));
|
|
s.set_column_value(lp_e, rational(1));
|
|
s.set_column_value(lp_abcde, rational(1));
|
|
s.set_column_value(lp_ac, rational(1));
|
|
s.set_column_value(lp_bde, rational(1));
|
|
s.set_column_value(lp_acd, rational(1));
|
|
s.set_column_value(lp_be, rational(1));
|
|
|
|
// set bde to 2, b to minus 2
|
|
s.set_column_value(lp_bde, rational(2));
|
|
s.set_column_value(lp_b, - rational(2));
|
|
// we have bde = -b, therefore d = +-1 and e = +-1
|
|
SASSERT(nla.m_imp->test_check(lemma, exp) == l_false);
|
|
|
|
nla.m_imp->print_lemma(std::cout << "expl & lemma: ");
|
|
ineq i0(lp::lconstraint_kind::EQ, lp::lar_term(), rational(1));
|
|
i0.m_term.add_coeff_var(lp_b);
|
|
ineq i1(lp::lconstraint_kind::EQ, lp::lar_term(), -rational(1));
|
|
i1.m_term.add_coeff_var(lp_b);
|
|
bool found0 = false;
|
|
bool found1 = false;
|
|
|
|
for (const auto& k : lemma){
|
|
if (k == i0) {
|
|
found0 = true;
|
|
} else if (k == i1) {
|
|
found1 = true;
|
|
}
|
|
}
|
|
|
|
SASSERT(found0 && found1);
|
|
}
|
|
|
|
void solver::test_basic_sign_lemma() {
|
|
lp::lar_solver s;
|
|
unsigned a = 0, b = 1, c = 2, d = 3, e = 4,
|
|
bde = 7, acd = 8;
|
|
lpvar lp_a = s.add_var(a, true);
|
|
lpvar lp_b = s.add_var(b, true);
|
|
lpvar lp_c = s.add_var(c, true);
|
|
lpvar lp_d = s.add_var(d, true);
|
|
lpvar lp_e = s.add_var(e, true);
|
|
lpvar lp_bde = s.add_var(bde, true);
|
|
lpvar lp_acd = s.add_var(acd, true);
|
|
|
|
reslimit l;
|
|
params_ref p;
|
|
solver nla(s, l, p);
|
|
// create monomial bde
|
|
vector<unsigned> vec;
|
|
|
|
vec.push_back(lp_b);
|
|
vec.push_back(lp_d);
|
|
vec.push_back(lp_e);
|
|
|
|
nla.add_monomial(lp_bde, vec.size(), vec.begin());
|
|
vec.clear();
|
|
|
|
vec.push_back(lp_a);
|
|
vec.push_back(lp_c);
|
|
vec.push_back(lp_d);
|
|
|
|
nla.add_monomial(lp_acd, vec.size(), vec.begin());
|
|
|
|
// set the values of the factors so it should be bde = -acd according to the model
|
|
|
|
// b = -a
|
|
s.set_column_value(lp_a, rational(7));
|
|
s.set_column_value(lp_b, rational(-7));
|
|
|
|
// e - c = 0
|
|
s.set_column_value(lp_e, rational(4));
|
|
s.set_column_value(lp_c, rational(4));
|
|
|
|
s.set_column_value(lp_d, rational(6));
|
|
|
|
// make bde != -acd according to the model
|
|
s.set_column_value(lp_bde, lp::impq(rational(5)));
|
|
s.set_column_value(lp_acd, lp::impq(rational(3)));
|
|
|
|
vector<ineq> lemma;
|
|
lp::explanation exp;
|
|
|
|
SASSERT(nla.m_imp->test_check(lemma, exp) == l_false);
|
|
|
|
lp::lar_term t;
|
|
t.add_coeff_var(lp_bde);
|
|
t.add_coeff_var(lp_acd);
|
|
ineq q(lp::lconstraint_kind::EQ, t, rational(0));
|
|
|
|
nla.m_imp->print_lemma(std::cout << "expl & lemma: ");
|
|
SASSERT(q == lemma.back());
|
|
ineq i0(lp::lconstraint_kind::EQ, lp::lar_term(), rational(0));
|
|
i0.m_term.add_coeff_var(lp_bde);
|
|
i0.m_term.add_coeff_var(rational(1), lp_acd);
|
|
bool found = false;
|
|
for (const auto& k : lemma){
|
|
if (k == i0) {
|
|
found = true;
|
|
}
|
|
}
|
|
|
|
SASSERT(found);
|
|
}
|
|
|
|
void solver::test_order_lemma_params(bool var_equiv, int sign) {
|
|
enable_trace("nla_solver");
|
|
lp::lar_solver s;
|
|
unsigned a = 0, b = 1, c = 2, d = 3, e = 4, f = 5,
|
|
i = 8, j = 9,
|
|
ab = 10, cd = 11, ef = 12, abef = 13, cdij = 16, ij = 17,
|
|
k = 18;
|
|
|
|
|
|
lpvar lp_a = s.add_named_var(a, true, "a");
|
|
lpvar lp_b = s.add_named_var(b, true, "b");
|
|
lpvar lp_c = s.add_named_var(c, true, "c");
|
|
lpvar lp_d = s.add_named_var(d, true, "d");
|
|
lpvar lp_e = s.add_named_var(e, true, "e");
|
|
lpvar lp_f = s.add_named_var(f, true, "f");
|
|
lpvar lp_i = s.add_named_var(i, true, "i");
|
|
lpvar lp_j = s.add_named_var(j, true, "j");
|
|
lpvar lp_k = s.add_named_var(k, true, "k");
|
|
lpvar lp_ab = s.add_named_var(ab, true, "ab");
|
|
lpvar lp_cd = s.add_named_var(cd, true, "cd");
|
|
lpvar lp_ef = s.add_named_var(ef, true, "ef");
|
|
lpvar lp_ij = s.add_named_var(ij, true, "ij");
|
|
lpvar lp_abef = s.add_named_var(abef, true, "abef");
|
|
lpvar lp_cdij = s.add_named_var(cdij, true, "cdij");
|
|
|
|
for (unsigned j = 0; j < s.number_of_vars(); j++) {
|
|
s.set_column_value(j, rational(j + 2));
|
|
}
|
|
|
|
reslimit l;
|
|
params_ref p;
|
|
solver nla(s, l, p);
|
|
// create monomial ab
|
|
vector<unsigned> vec;
|
|
vec.push_back(lp_a);
|
|
vec.push_back(lp_b);
|
|
int mon_ab = nla.add_monomial(lp_ab, vec.size(), vec.begin());
|
|
// create monomial cd
|
|
vec.clear();
|
|
vec.push_back(lp_c);
|
|
vec.push_back(lp_d);
|
|
int mon_cd = nla.add_monomial(lp_cd, vec.size(), vec.begin());
|
|
// create monomial ef
|
|
vec.clear();
|
|
vec.push_back(lp_e);
|
|
vec.push_back(lp_f);
|
|
int mon_ef = nla.add_monomial(lp_ef, vec.size(), vec.begin());
|
|
// create monomial ij
|
|
vec.clear();
|
|
vec.push_back(lp_i);
|
|
if (var_equiv)
|
|
vec.push_back(lp_k);
|
|
else
|
|
vec.push_back(lp_j);
|
|
int mon_ij = nla.add_monomial(lp_ij, vec.size(), vec.begin());
|
|
|
|
if (var_equiv) { // make k equivalent to j
|
|
lp::lar_term t;
|
|
t.add_coeff_var(lp_k);
|
|
t.add_coeff_var(-rational(1), lp_j);
|
|
lpvar kj = s.add_term(t.coeffs_as_vector());
|
|
s.add_var_bound(kj, lp::lconstraint_kind::LE, rational(0));
|
|
s.add_var_bound(kj, lp::lconstraint_kind::GE, rational(0));
|
|
}
|
|
|
|
//create monomial (ab)(ef)
|
|
vec.clear();
|
|
vec.push_back(lp_e);
|
|
vec.push_back(lp_a);
|
|
vec.push_back(lp_b);
|
|
vec.push_back(lp_f);
|
|
nla.add_monomial(lp_abef, vec.size(), vec.begin());
|
|
|
|
//create monomial (cd)(ij)
|
|
vec.clear();
|
|
vec.push_back(lp_i);
|
|
vec.push_back(lp_j);
|
|
vec.push_back(lp_c);
|
|
vec.push_back(lp_d);
|
|
auto mon_cdij = nla.add_monomial(lp_cdij, vec.size(), vec.begin());
|
|
|
|
// set i == e
|
|
s.set_column_value(lp_e, s.get_column_value(lp_i));
|
|
// set f == sign*j
|
|
s.set_column_value(lp_f, rational(sign) * s.get_column_value(lp_j));
|
|
if (var_equiv) {
|
|
s.set_column_value(lp_k, s.get_column_value(lp_j));
|
|
}
|
|
// set the values of ab, ef, cd, and ij correctly
|
|
s.set_column_value(lp_ab, nla.m_imp->mon_value_by_vars(mon_ab));
|
|
s.set_column_value(lp_ef, nla.m_imp->mon_value_by_vars(mon_ef));
|
|
s.set_column_value(lp_cd, nla.m_imp->mon_value_by_vars(mon_cd));
|
|
s.set_column_value(lp_ij, nla.m_imp->mon_value_by_vars(mon_ij));
|
|
|
|
// set abef = cdij, while it has to be abef < cdij
|
|
if (sign > 0) {
|
|
SASSERT(s.get_column_value(lp_ab) < s.get_column_value(lp_cd));
|
|
// we have ab < cd
|
|
|
|
// we need to have ab*ef < cd*ij, so let us make ab*ef > cd*ij
|
|
s.set_column_value(lp_cdij, nla.m_imp->mon_value_by_vars(mon_cdij));
|
|
s.set_column_value(lp_abef, nla.m_imp->mon_value_by_vars(mon_cdij)
|
|
+ rational(1));
|
|
|
|
}
|
|
else {
|
|
SASSERT(-s.get_column_value(lp_ab) < s.get_column_value(lp_cd));
|
|
// we need to have abef < cdij, so let us make abef < cdij
|
|
s.set_column_value(lp_cdij, nla.m_imp->mon_value_by_vars(mon_cdij));
|
|
s.set_column_value(lp_abef, nla.m_imp->mon_value_by_vars(mon_cdij)
|
|
+ rational(1));
|
|
}
|
|
vector<ineq> lemma;
|
|
lp::explanation exp;
|
|
|
|
SASSERT(nla.m_imp->test_check(lemma, exp) == l_false);
|
|
SASSERT(!var_equiv || !exp.empty());
|
|
// lp::lar_term t;
|
|
// t.add_coeff_var(lp_bde);
|
|
// t.add_coeff_var(lp_acd);
|
|
// ineq q(lp::lconstraint_kind::EQ, t, rational(0));
|
|
|
|
nla.m_imp->print_lemma(std::cout << "lemma: ");
|
|
// SASSERT(q == lemma.back());
|
|
// ineq i0(lp::lconstraint_kind::EQ, lp::lar_term(), rational(0));
|
|
// i0.m_term.add_coeff_var(lp_bde);
|
|
// i0.m_term.add_coeff_var(rational(1), lp_acd);
|
|
// bool found = false;
|
|
// for (const auto& k : lemma){
|
|
// if (k == i0) {
|
|
// found = true;
|
|
// }
|
|
// }
|
|
|
|
// SASSERT(found);
|
|
}
|
|
|
|
void solver::test_order_lemma() {
|
|
test_order_lemma_params(false, 1);
|
|
test_order_lemma_params(false, -1);
|
|
test_order_lemma_params(true, 1);
|
|
test_order_lemma_params(true, -1);
|
|
}
|
|
}
|