3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-13 20:38:43 +00:00

port to emonomials (#90)

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2019-04-18 13:17:24 -07:00 committed by Lev Nachmanson
parent b52e79b648
commit e28e83a25e
20 changed files with 666 additions and 683 deletions

View file

@ -24,15 +24,6 @@
namespace nla {
void emonomials::inc_canonical() {
++m_canonical;
if (m_canonical == 0) {
for (auto& svt : m_canonized) {
svt.m_canonical = 0;
}
++m_canonical;
}
}
void emonomials::inc_visited() const {
++m_visited;
@ -55,11 +46,12 @@ namespace nla {
unsigned old_sz = m_lim[m_lim.size() - n];
for (unsigned i = m_monomials.size(); i-- > old_sz; ) {
monomial const& m = m_monomials[i];
remove_cg(i, m);
m_var2index[m.var()] = UINT_MAX;
lpvar last_var = UINT_MAX;
for (lpvar v : m.vars()) {
if (v != last_var) {
remove_var2monomials(v, i);
remove_cell(m_use_lists[v], i);
last_var = v;
}
}
@ -70,9 +62,9 @@ namespace nla {
m_lim.shrink(m_lim.size() - n);
}
void emonomials::remove_var2monomials(lpvar v, unsigned mIndex) {
cell*& cur_head = m_use_lists[v].m_head;
cell*& cur_tail = m_use_lists[v].m_tail;
void emonomials::remove_cell(head_tail& v, unsigned mIndex) {
cell*& cur_head = v.m_head;
cell*& cur_tail = v.m_tail;
cell* old_head = cur_head->m_next;
if (old_head == cur_head) {
cur_head = nullptr;
@ -84,23 +76,21 @@ namespace nla {
}
}
void emonomials::insert_var2monomials(lpvar v, unsigned mIndex) {
m_use_lists.reserve(v + 1);
cell*& cur_head = m_use_lists[v].m_head;
cell*& cur_tail = m_use_lists[v].m_tail;
void emonomials::insert_cell(head_tail& v, unsigned mIndex) {
cell*& cur_head = v.m_head;
cell*& cur_tail = v.m_tail;
cell* new_head = new (m_region) cell(mIndex, cur_head);
cur_head = new_head;
if (!cur_tail) cur_tail = new_head;
cur_tail->m_next = new_head;
}
void emonomials::merge_var2monomials(lpvar root, lpvar other) {
if (root == other) return;
m_use_lists.reserve(std::max(root, other) + 1);
cell*& root_head = m_use_lists[root].m_head;
cell*& root_tail = m_use_lists[root].m_tail;
cell* other_head = m_use_lists[other].m_head;
cell* other_tail = m_use_lists[other].m_tail;
void emonomials::merge_cells(head_tail& root, head_tail& other) {
if (&root == &other) return;
cell*& root_head = root.m_head;
cell*& root_tail = root.m_tail;
cell* other_head = other.m_head;
cell* other_tail = other.m_tail;
if (root_head == nullptr) {
root_head = other_head;
root_tail = other_tail;
@ -116,12 +106,12 @@ namespace nla {
}
}
void emonomials::unmerge_var2monomials(lpvar root, lpvar other) {
if (root == other) return;
cell*& root_head = m_use_lists[root].m_head;
cell*& root_tail = m_use_lists[root].m_tail;
cell* other_head = m_use_lists[other].m_head;
cell* other_tail = m_use_lists[other].m_tail;
void emonomials::unmerge_cells(head_tail& root, head_tail& other) {
if (&root == &other) return;
cell*& root_head = root.m_head;
cell*& root_tail = root.m_tail;
cell* other_head = other.m_head;
cell* other_tail = other.m_tail;
if (other_head == nullptr) {
// no-op
}
@ -142,6 +132,112 @@ namespace nla {
return m_use_lists[v].m_head;
}
signed_vars const* emonomials::find_canonical(svector<lpvar> const& vars) const {
// find a unique key for dummy monomial
lpvar v = m_var2index.size();
for (unsigned i = 0; i < m_var2index.size(); ++i) {
if (m_var2index[i] == UINT_MAX) {
v = i;
break;
}
}
unsigned idx = m_monomials.size();
m_monomials.push_back(monomial(v, vars.size(), vars.c_ptr()));
m_canonized.push_back(signed_vars_ts(v, idx));
m_var2index.setx(v, idx, UINT_MAX);
do_canonize(m_monomials[idx]);
signed_vars const* result = nullptr;
lpvar w;
if (m_cg_table.find(v, w)) {
SASSERT(w != v);
result = &m_canonized[m_var2index[w]];
}
m_var2index[v] = UINT_MAX;
m_monomials.pop_back();
m_canonized.pop_back(); // NB. relies on the pointer m_canonized not to change.
return result;
}
void emonomials::remove_cg(lpvar v) {
cell* c = m_use_lists[v].m_head;
cell* first = c;
inc_visited();
do {
unsigned idx = c->m_index;
c = c->m_next;
monomial const& m = m_monomials[idx];
if (!is_visited(m)) {
set_visited(m);
remove_cg(idx, m);
}
}
while (c != first);
}
void emonomials::remove_cg(unsigned idx, monomial const& m) {
signed_vars_ts& sv = m_canonized[idx];
unsigned next = sv.m_next;
unsigned prev = sv.m_prev;
lpvar u = m.var(), w;
// equivalence class of u:
if (m_cg_table.find(u, w) && w == u) {
m_cg_table.erase(u);
// insert other representative:
if (prev != idx) {
m_cg_table.insert(m_monomials[prev].var());
}
}
if (prev != idx) {
m_canonized[next].m_prev = prev;
m_canonized[prev].m_next = next;
sv.m_next = idx;
sv.m_prev = idx;
}
}
/**
\brief insert canonized monomials using v into a congruence table.
Prior to insertion, the monomials are canonized according to the current
variable equivalences. The canonized monomials (signed_vars) are considered
in the same equivalence class if they have the same set of representative
variables. Their signs may differ.
*/
void emonomials::insert_cg(lpvar v) {
cell* c = m_use_lists[v].m_head;
cell* first = c;
inc_visited();
do {
unsigned idx = c->m_index;
c = c->m_next;
monomial const& m = m_monomials[idx];
if (!is_visited(m)) {
set_visited(m);
insert_cg(idx, m);
}
}
while (c != first);
}
void emonomials::insert_cg(unsigned idx, monomial const& m) {
canonize(m);
lpvar v = m.var(), w;
if (m_cg_table.find(v, w)) {
SASSERT(w != v);
unsigned idxr = m_var2index[w];
// Insert idx to the right of idxr
m_canonized[idx].m_prev = idxr;
m_canonized[idx].m_next = m_canonized[idxr].m_next;
m_canonized[idxr].m_next = idx;
}
else {
m_cg_table.insert(v);
SASSERT(m_canonized[idx].m_next == idx);
SASSERT(m_canonized[idx].m_prev == idx);
}
}
void emonomials::set_visited(monomial const& m) const {
m_canonized[m_var2index[m.var()]].m_visited = m_visited;
}
@ -150,48 +246,40 @@ namespace nla {
return m_visited == m_canonized[m_var2index[m.var()]].m_visited;
}
/**
\brief insert a new monomial.
Assume that the variables are canonical, that is, not equal in current
context so another variable. To support equal in current context we
could track sign information in monomials, or ensure that insert_var2monomials
works on the equivalence class roots.
context so another variable. The monomial is inserted into a congruence
class of equal up-to var_eqs monomials.
*/
void emonomials::add(lpvar v, unsigned sz, lpvar const* vs) {
unsigned idx = m_monomials.size();
m_monomials.push_back(monomial(v, sz, vs));
m_canonized.push_back(signed_vars_ts());
m_canonized.push_back(signed_vars_ts(v, idx));
lpvar last_var = UINT_MAX;
for (unsigned i = 0; i < sz; ++i) {
lpvar w = vs[i];
SASSERT(m_ve.is_root(w));
if (w != last_var) {
insert_var2monomials(w, idx);
m_use_lists.reserve(w + 1);
insert_cell(m_use_lists[w], idx);
last_var = w;
}
}
SASSERT(m_ve.is_root(v));
m_var2index.setx(v, idx, UINT_MAX);
insert_cg(idx, m_monomials[idx]);
}
signed_vars const& emonomials::canonize(monomial const& mon) const {
void emonomials::do_canonize(monomial const& mon) const {
unsigned index = m_var2index[mon.var()];
if (m_canonized[index].m_canonical != m_canonical) {
m_vars.reset();
bool sign = false;
for (lpvar v : mon) {
signed_var sv = m_ve.find(v);
m_vars.push_back(sv.var());
sign ^= sv.sign();
}
m_canonized[index].set_vars(m_vars.size(), m_vars.c_ptr());
m_canonized[index].set_sign(sign);
m_canonized[index].set_var(mon.var());
m_canonized[index].m_canonical = m_canonical;
signed_vars& svs = m_canonized[index];
svs.reset();
for (lpvar v : mon) {
svs.push_var(m_ve.find(v));
}
return m_canonized[index];
svs.done_push();
}
bool emonomials::canonize_divides(monomial const& m1, monomial const& m2) const {
@ -242,21 +330,22 @@ namespace nla {
}
void emonomials::merge_eh(signed_var r2, signed_var r1, signed_var v2, signed_var v1) {
if (!r2.sign() && m_ve.find(~r2) != m_ve.find(r1)) {
merge_var2monomials(r2.var(), r1.var());
}
inc_canonical();
// no-op
}
void emonomials::after_merge_eh(signed_var r2, signed_var r1, signed_var v2, signed_var v1) {
// skip
if (!r2.sign() && m_ve.find(~r2) != m_ve.find(r1)) {
m_use_lists.reserve(std::max(r2.var(), r1.var()) + 1);
rehash_cg(r1.var());
merge_cells(m_use_lists[r2.var()], m_use_lists[r1.var()]);
}
}
void emonomials::unmerge_eh(signed_var r2, signed_var r1) {
if (!r2.sign() && m_ve.find(~r2) != m_ve.find(r1)) {
unmerge_var2monomials(r2.var(), r1.var());
unmerge_cells(m_use_lists[r2.var()], m_use_lists[r1.var()]);
rehash_cg(r1.var());
}
inc_canonical();
}
std::ostream& emonomials::display(std::ostream& out) const {

View file

@ -36,17 +36,18 @@ namespace nla {
svector<lpvar> m_vars;
bool m_sign;
public:
signed_vars() : m_sign(false) {}
signed_vars(lpvar v) : m_var(v), m_sign(false) {}
lpvar var() const { return m_var; }
svector<lpvar> const& vars() const { return m_vars; }
svector<lp::var_index>::const_iterator begin() const { return vars().begin(); }
svector<lp::var_index>::const_iterator end() const { return vars().end(); }
unsigned size() const { return m_vars.size(); }
lpvar operator[](unsigned i) const { return m_vars[i]; }
bool sign() const { return m_sign; }
void set_sign(bool s) { m_sign = s; }
void set_var(lpvar v) { m_var = v; }
void set_vars(unsigned n, lpvar const* vars) {
m_vars.reset();
m_vars.append(n, vars);
rational rsign() const { return rational(m_sign ? -1 : 1); }
void reset() { m_sign = false; m_vars.reset(); }
void push_var(signed_var sv) { m_sign ^= sv.sign(); m_vars.push_back(sv.var()); }
void done_push() {
std::sort(m_vars.begin(), m_vars.end());
}
std::ostream& display(std::ostream& out) const {
@ -61,15 +62,6 @@ namespace nla {
class emonomials : public var_eqs_merge_handler {
/**
\brief private fields used by emonomials for maintaining state of canonized monomials.
*/
class signed_vars_ts : public signed_vars {
public:
signed_vars_ts(): m_canonical(0), m_visited(0) {}
unsigned m_canonical;
unsigned m_visited;
};
/**
\brief singly-lined cyclic list of monomial indices where variable occurs.
@ -90,24 +82,64 @@ namespace nla {
cell* m_tail;
};
var_eqs& m_ve;
vector<monomial> m_monomials; // set of monomials
unsigned_vector m_lim; // backtracking point
unsigned_vector m_var2index; // var_mIndex -> mIndex
unsigned m_canonical; // timestamp of last merge
mutable unsigned m_visited; // timestamp of visited monomials during pf_iterator
region m_region; // region for allocating linked lists
mutable vector<signed_vars_ts> m_canonized; // canonized versions of signed variables
mutable svector<lpvar> m_vars; // temporary vector of variables
mutable svector<head_tail> m_use_lists; // use list of monomials where variables occur.
void inc_canonical();
/**
\brief private fields used by emonomials for maintaining state of canonized monomials.
*/
class signed_vars_ts : public signed_vars {
public:
signed_vars_ts(lpvar v, unsigned idx): signed_vars(v), m_next(idx), m_prev(idx), m_visited(0) {}
unsigned m_next; // next congruent node.
unsigned m_prev; // previous congruent node
mutable unsigned m_visited;
};
struct hash_canonical {
emonomials& em;
hash_canonical(emonomials& em): em(em) {}
unsigned operator()(lpvar v) const {
auto const& vec = em.m_canonized[em.m_var2index[v]].vars();
return string_hash(reinterpret_cast<char const*>(vec.c_ptr()), sizeof(lpvar)*vec.size(), 10);
}
};
struct eq_canonical {
emonomials& em;
eq_canonical(emonomials& em): em(em) {}
bool operator()(lpvar u, lpvar v) const {
auto const& uvec = em.m_canonized[em.m_var2index[u]].vars();
auto const& vvec = em.m_canonized[em.m_var2index[v]].vars();
return uvec == vvec;
}
};
var_eqs& m_ve;
mutable vector<monomial> m_monomials; // set of monomials
mutable unsigned_vector m_var2index; // var_mIndex -> mIndex
unsigned_vector m_lim; // backtracking point
mutable unsigned m_visited; // timestamp of visited monomials during pf_iterator
region m_region; // region for allocating linked lists
mutable vector<signed_vars_ts> m_canonized; // canonized versions of signed variables
mutable svector<head_tail> m_use_lists; // use list of monomials where variables occur.
hash_canonical m_cg_hash;
eq_canonical m_cg_eq;
hashtable<lpvar, hash_canonical, eq_canonical> m_cg_table; // congruence (canonical) table.
void inc_visited() const;
void remove_var2monomials(lpvar v, unsigned mIndex);
void insert_var2monomials(lpvar v, unsigned mIndex);
void merge_var2monomials(lpvar root, lpvar other);
void unmerge_var2monomials(lpvar root, lpvar other);
void remove_cell(head_tail& v, unsigned mIndex);
void insert_cell(head_tail& v, unsigned mIndex);
void merge_cells(head_tail& root, head_tail& other);
void unmerge_cells(head_tail& root, head_tail& other);
void remove_cg(lpvar v);
void insert_cg(lpvar v);
void insert_cg(unsigned idx, monomial const& m);
void remove_cg(unsigned idx, monomial const& m);
void rehash_cg(lpvar v) { remove_cg(v); insert_cg(v); }
void do_canonize(monomial const& m) const;
cell* head(lpvar v) const;
void set_visited(monomial const& m) const;
@ -119,7 +151,15 @@ namespace nla {
push and pop on emonomials calls push/pop on var_eqs, so no
other calls to push/pop to the var_eqs should take place.
*/
emonomials(var_eqs& ve): m_ve(ve), m_canonical(1), m_visited(0) { m_ve.set_merge_handler(this); }
emonomials(var_eqs& ve):
m_ve(ve),
m_visited(0),
m_cg_hash(*this),
m_cg_eq(*this),
m_cg_table(DEFAULT_HASHTABLE_INITIAL_CAPACITY, m_cg_hash, m_cg_eq),
canonical(*this) {
m_ve.set_merge_handler(this);
}
/**
\brief push/pop scopes.
@ -140,13 +180,42 @@ namespace nla {
/**
\brief retrieve monomial corresponding to variable v from definition v := vs
*/
monomial const* var2monomial(lpvar v) const { unsigned idx = m_var2index.get(v, UINT_MAX); return idx == UINT_MAX ? nullptr : &m_monomials[idx]; }
monomial const& var2monomial(lpvar v) const { SASSERT(is_monomial_var(v)); return m_monomials[m_var2index[v]]; }
monomial const& operator[](lpvar v) const { return var2monomial(v); }
bool is_monomial_var(lpvar v) const { return m_var2index.get(v, UINT_MAX) != UINT_MAX; }
/**
\brief retrieve canonized monomial corresponding to variable v from definition v := vs
*/
signed_vars const& var2canonical(lpvar v) const { return canonize(var2monomial(v)); }
class canonical {
emonomials& m;
public:
canonical(emonomials& m): m(m) {}
signed_vars const& operator[](lpvar v) const { return m.var2canonical(v); }
signed_vars const& operator[](monomial const& mon) const { return m.var2canonical(mon.var()); }
};
canonical canonical;
/**
\brief obtain a canonized signed monomial
corresponding to current equivalence class.
*/
signed_vars const& canonize(monomial const& m) const;
signed_vars const& canonize(monomial const& m) const { return m_canonized[m_var2index[m.var()]]; }
/**
\brief obtain the representative canonized monomial up to sign.
*/
signed_vars const& rep(signed_vars const& sv) const { return m_canonized[m_var2index[m_cg_table[sv.var()]]]; }
/**
\brief the original sign is defined as a sign of the equivalence class representative.
*/
rational orig_sign(signed_vars const& sv) const { return rep(sv).rsign(); }
/**
\brief determine if m1 divides m2 over the canonization obtained from merged variables.
@ -192,7 +261,6 @@ namespace nla {
use_list get_use_list(lpvar v) const { return use_list(*this, v); }
/**
\brief retrieve monomials m' where m is a proper factor of modulo current equalities.
*/
@ -222,7 +290,49 @@ namespace nla {
};
factors_of get_factors_of(monomial const& m) const { inc_visited(); return factors_of(*this, m); }
factors_of get_factors_of(lpvar v) const { return get_factors_of(var2monomial(v)); }
signed_vars const* find_canonical(svector<lpvar> const& vars) const;
/**
\brief iterator over sign equivalent monomials.
These are monomials that are equivalent modulo m_var_eqs amd modulo signs.
*/
class sign_equiv_monomials_it {
emonomials const& m;
unsigned m_index;
bool m_touched;
public:
sign_equiv_monomials_it(emonomials const& m, unsigned idx, bool at_end): m(m), m_index(idx), m_touched(at_end) {}
monomial const& operator*() { return m.m_monomials[m_index]; }
sign_equiv_monomials_it& operator++() {
m_touched = true;
m_index = m.m_canonized[m_index].m_next;
return *this;
}
sign_equiv_monomials_it operator++(int) { sign_equiv_monomials_it tmp = *this; ++*this; return tmp; }
bool operator==(sign_equiv_monomials_it const& other) const {
return m_index == other.m_index && m_touched == other.m_touched;
}
bool operator!=(sign_equiv_monomials_it const& other) const {
return m_index != other.m_index || m_touched != other.m_touched;
}
};
class sign_equiv_monomials {
emonomials& em;
monomial const& m;
unsigned index() const { return em.m_var2index[m.var()]; }
public:
sign_equiv_monomials(emonomials & em, monomial const& m): em(em), m(m) {}
sign_equiv_monomials_it begin() { return sign_equiv_monomials_it(em, index(), false); }
sign_equiv_monomials_it end() { return sign_equiv_monomials_it(em, index(), true); }
};
sign_equiv_monomials enum_sign_equiv_monomials(monomial const& m) { return sign_equiv_monomials(*this, m); }
sign_equiv_monomials enum_sign_equiv_monomials(lpvar v) { return enum_sign_equiv_monomials((*this)[v]); }
sign_equiv_monomials enum_sign_equiv_monomials(signed_vars const& sv) { return enum_sign_equiv_monomials(sv.var()); }
/**
\brief display state of emonomials
*/

View file

@ -24,26 +24,26 @@ bool const_iterator_mon::get_factors(factor& k, factor& j, rational& sign) const
std::sort(j_vars.begin(), j_vars.end());
if (k_vars.size() == 1) {
k.index() = k_vars[0];
k.var() = k_vars[0];
k.type() = factor_type::VAR;
} else {
unsigned i;
if (!m_ff->find_rm_monomial_of_vars(k_vars, i)) {
return false;
}
k.index() = i;
k.var() = i;
k.type() = factor_type::RM;
}
if (j_vars.size() == 1) {
j.index() = j_vars[0];
j.var() = j_vars[0];
j.type() = factor_type::VAR;
} else {
unsigned i;
if (!m_ff->find_rm_monomial_of_vars(j_vars, i)) {
return false;
}
j.index() = i;
j.var() = i;
j.type() = factor_type::RM;
}
return true;

View file

@ -30,22 +30,22 @@ typedef unsigned lpvar;
enum class factor_type { VAR, RM }; // RM stands for rooted monomial
class factor {
unsigned m_index;
unsigned m_var;
factor_type m_type;
public:
factor() {}
explicit factor(unsigned j) : factor(j, factor_type::VAR) {}
factor(unsigned i, factor_type t) : m_index(i), m_type(t) {}
unsigned index() const { return m_index; }
unsigned& index() { return m_index; }
factor(unsigned i, factor_type t) : m_var(i), m_type(t) {}
unsigned var() const { return m_var; }
unsigned& var() { return m_var; }
factor_type type() const { return m_type; }
factor_type& type() { return m_type; }
bool is_var() const { return m_type == factor_type::VAR; }
bool operator==(factor const& other) const {
return m_index == other.index() && m_type == other.type();
return m_var == other.var() && m_type == other.type();
}
bool operator!=(factor const& other) const {
return m_index != other.index() || m_type != other.type();
return m_var != other.var() || m_type != other.type();
}
};

View file

@ -21,12 +21,12 @@
#include "util/lp/nla_core.h"
namespace nla {
factorization_factory_imp::factorization_factory_imp(const rooted_mon& rm, const core& s) :
factorization_factory(rm.m_vars, &s.m_monomials[rm.orig_index()]),
m_core(s), m_mon(& s.m_monomials[rm.orig_index()]), m_rm(rm) { }
factorization_factory_imp::factorization_factory_imp(const signed_vars& rm, const core& s) :
factorization_factory(rm.vars(), &s.m_emons[rm.var()]),
m_core(s), m_mon(s.m_emons[rm.var()]), m_rm(rm) { }
bool factorization_factory_imp::find_rm_monomial_of_vars(const svector<lpvar>& vars, unsigned & i) const {
return m_core.find_rm_monomial_of_vars(vars, i);
return m_core.find_rm_monomial_of_vars(vars, i);
}
const monomial* factorization_factory_imp::find_monomial_of_vars(const svector<lpvar>& vars) const {
return m_core.find_monomial_of_vars(vars);

View file

@ -20,15 +20,16 @@
#pragma once
#include "util/lp/factorization.h"
namespace nla {
struct core;
struct rooted_mon;
struct factorization_factory_imp: factorization_factory {
const core& m_core;
const monomial *m_mon;
const rooted_mon& m_rm;
class core;
class signed_vars;
struct factorization_factory_imp: factorization_factory {
const core& m_core;
const monomial & m_mon;
const signed_vars& m_rm;
factorization_factory_imp(const rooted_mon& rm, const core& s);
bool find_rm_monomial_of_vars(const svector<lpvar>& vars, unsigned & i) const;
const monomial* find_monomial_of_vars(const svector<lpvar>& vars) const;
};
factorization_factory_imp(const signed_vars& rm, const core& s);
bool find_rm_monomial_of_vars(const svector<lpvar>& vars, unsigned & i) const;
const monomial* find_monomial_of_vars(const svector<lpvar>& vars) const;
};
}

View file

@ -23,12 +23,13 @@
namespace nla {
basics::basics(core * c) : common(c) {}
// Monomials m and n vars have the same values, up to "sign"
// Generate a lemma if values of m.var() and n.var() are not the same up to sign
bool basics::basic_sign_lemma_on_two_monomials(const monomial& m, const monomial& n, const rational& sign) {
if (vvr(m) == vvr(n) *sign)
if (vvr(m) == vvr(n) * sign)
return false;
TRACE("nla_solver", tout << "sign contradiction:\nm = "; c().print_monomial_with_vars(m, tout); tout << "n= "; c().print_monomial_with_vars(n, tout); tout << "sign: " << sign << "\n";);
TRACE("nla_solver", tout << "sign contradiction:\nm = " << m << "n= " << n << "sign: " << sign << "\n";);
generate_sign_lemma(m, n, sign);
return true;
}
@ -40,17 +41,18 @@ void basics::generate_zero_lemmas(const monomial& m) {
lpvar zero_j = find_best_zero(m, fixed_zeros);
SASSERT(is_set(zero_j));
unsigned zero_power = 0;
for (unsigned j : m){
for (lpvar j : m){
if (j == zero_j) {
zero_power++;
continue;
}
get_non_strict_sign(j, sign);
if(sign == 0)
if (sign == 0)
break;
}
if (sign && is_even(zero_power))
if (sign && is_even(zero_power)) {
sign = 0;
}
TRACE("nla_solver_details", tout << "zero_j = " << zero_j << ", sign = " << sign << "\n";);
if (sign == 0) { // have to generate a non-convex lemma
add_trival_zero_lemma(zero_j, m);
@ -98,10 +100,10 @@ void basics::basic_sign_lemma_model_based_one_mon(const monomial& m, int product
}
bool basics::basic_sign_lemma_model_based() {
unsigned i = c().random() % c().m_to_refine.size();
unsigned ii = i;
do {
const monomial& m = c().m_monomials[c().m_to_refine[i]];
unsigned start = c().random();
unsigned sz = c().m_to_refine.size();
for (unsigned i = sz; i-- > 0; ) {
monomial const& m = c().m_emons[c().m_to_refine[(start + i) % sz]];
int mon_sign = nla::rat_sign(vvr(m));
int product_sign = c().rat_sign(m);
if (mon_sign != product_sign) {
@ -109,47 +111,26 @@ bool basics::basic_sign_lemma_model_based() {
if (c().done())
return true;
}
i++;
if (i == c().m_to_refine.size())
i = 0;
} while (i != ii);
}
return c().m_lemma_vec->size() > 0;
}
bool basics::basic_sign_lemma_on_mon(unsigned i, std::unordered_set<unsigned> & explored){
const monomial& m = c().m_monomials[i];
TRACE("nla_solver_details", tout << "i = " << i << ", mon = "; c().print_monomial_with_vars(m, tout););
const index_with_sign& rm_i_s = c().m_rm_table.get_rooted_mon(i);
unsigned k = rm_i_s.index();
if (!try_insert(k, explored))
bool basics::basic_sign_lemma_on_mon(lpvar v, std::unordered_set<unsigned> & explored){
if (!try_insert(v, explored)) {
return false;
const auto& mons_to_explore = c().m_rm_table.rms()[k].m_mons;
TRACE("nla_solver", tout << "rm = "; c().print_rooted_monomial_with_vars(c().m_rm_table.rms()[k], tout) << "\n";);
for (index_with_sign i_s : mons_to_explore) {
TRACE("nla_solver", tout << "i_s = (" << i_s.index() << "," << i_s.sign() << ")\n";
c().print_monomial_with_vars(c().m_monomials[i_s.index()], tout << "m = ") << "\n";
{
for (lpvar j : c().m_monomials[i_s.index()] ) {
lpvar rj = c().m_evars.find(j).var();
if (j == rj)
tout << "rj = j =" << j << "\n";
else {
lp::explanation e;
c().m_evars.explain(j, e);
tout << "j = " << j << ", e = "; c().print_explanation(e, tout) << "\n";
}
}
}
);
unsigned n = i_s.index();
if (n == i) continue;
if (basic_sign_lemma_on_two_monomials(m, c().m_monomials[n], rm_i_s.sign()*i_s.sign()))
if(done())
return true;
}
const monomial& m_v = c().m_emons[v];
signed_vars const& sv_v = c().m_emons.canonical[v];
TRACE("nla_solver_details", tout << "mon = " << m_v;);
for (auto const& m_w : c().m_emons.enum_sign_equiv_monomials(v)) {
signed_vars const& sv_w = c().m_emons.canonical[m_w];
if (m_v.var() != m_w.var() && basic_sign_lemma_on_two_monomials(m_v, m_w, sv_v.rsign() * sv_w.rsign()) && done())
return true;
}
TRACE("nla_solver_details", tout << "return false\n";);
return false;
}
@ -163,7 +144,7 @@ bool basics::basic_sign_lemma(bool derived) {
return basic_sign_lemma_model_based();
std::unordered_set<unsigned> explored;
for (unsigned i : c().m_to_refine){
for (lpvar i : c().m_to_refine){
if (basic_sign_lemma_on_mon(i, explored))
return true;
}
@ -241,7 +222,10 @@ void basics::negate_strict_sign(lpvar j) {
// here we use the fact
// xy = 0 -> x = 0 or y = 0
bool basics::basic_lemma_for_mon_zero(const rooted_mon& rm, const factorization& f) {
bool basics::basic_lemma_for_mon_zero(const signed_vars& rm, const factorization& f) {
NOT_IMPLEMENTED_YET();
return true;
#if 0
TRACE("nla_solver", c().trace_print_monomial_and_factorization(rm, f, tout););
add_empty_lemma();
c().explain_fixed_var(var(rm));
@ -253,6 +237,7 @@ bool basics::basic_lemma_for_mon_zero(const rooted_mon& rm, const factorization&
explain(rm);
TRACE("nla_solver", c().print_lemma(tout););
return true;
#endif
}
// use basic multiplication properties to create a lemma
bool basics::basic_lemma(bool derived) {
@ -261,31 +246,27 @@ bool basics::basic_lemma(bool derived) {
if (derived)
return false;
c().init_rm_to_refine();
const auto& rm_ref = c().m_rm_table.to_refine();
const auto& rm_ref = c().m_to_refine;
TRACE("nla_solver", tout << "rm_ref = "; print_vector(rm_ref, tout););
unsigned start = c().random() % rm_ref.size();
unsigned i = start;
do {
const rooted_mon& r = c().m_rm_table.rms()[rm_ref[i]];
SASSERT (!c().check_monomial(c().m_monomials[r.orig_index()]));
unsigned start = c().random();
for (unsigned j = rm_ref.size(); j-- > 0; ) {
const signed_vars& r = c().m_emons.canonical[(j + start) % rm_ref.size()];
SASSERT (!c().check_monomial(c().m_emons[r.var()]));
basic_lemma_for_mon(r, derived);
if (++i == rm_ref.size()) {
i = 0;
}
} while(i != start && !done());
}
return false;
}
// Use basic multiplication properties to create a lemma
// for the given monomial.
// "derived" means derived from constraints - the alternative is model based
void basics::basic_lemma_for_mon(const rooted_mon& rm, bool derived) {
void basics::basic_lemma_for_mon(const signed_vars& rm, bool derived) {
if (derived)
basic_lemma_for_mon_derived(rm);
else
basic_lemma_for_mon_model_based(rm);
}
bool basics::basic_lemma_for_mon_derived(const rooted_mon& rm) {
bool basics::basic_lemma_for_mon_derived(const signed_vars& rm) {
if (c().var_is_fixed_to_zero(var(rm))) {
for (auto factorization : factorization_factory_imp(rm, c())) {
if (factorization.is_empty())
@ -311,7 +292,7 @@ bool basics::basic_lemma_for_mon_derived(const rooted_mon& rm) {
return false;
}
// x = 0 or y = 0 -> xy = 0
bool basics::basic_lemma_for_mon_non_zero_derived(const rooted_mon& rm, const factorization& f) {
bool basics::basic_lemma_for_mon_non_zero_derived(const signed_vars& rm, const factorization& f) {
TRACE("nla_solver", c().trace_print_monomial_and_factorization(rm, f, tout););
if (! c().var_is_separated_from_zero(var(rm)))
return false;
@ -335,10 +316,10 @@ bool basics::basic_lemma_for_mon_non_zero_derived(const rooted_mon& rm, const fa
}
// use the fact that
// |xabc| = |x| and x != 0 -> |a| = |b| = |c| = 1
bool basics::basic_lemma_for_mon_neutral_monomial_to_factor_derived(const rooted_mon& rm, const factorization& f) {
bool basics::basic_lemma_for_mon_neutral_monomial_to_factor_derived(const signed_vars& rm, const factorization& f) {
TRACE("nla_solver", c().trace_print_monomial_and_factorization(rm, f, tout););
lpvar mon_var = c().m_monomials[rm.orig_index()].var();
lpvar mon_var = c().m_emons[rm.var()].var();
TRACE("nla_solver", c().trace_print_monomial_and_factorization(rm, f, tout); tout << "\nmon_var = " << mon_var << "\n";);
const auto & mv = vvr(mon_var);
@ -395,9 +376,9 @@ bool basics::basic_lemma_for_mon_neutral_monomial_to_factor_derived(const rooted
}
// use the fact
// 1 * 1 ... * 1 * x * 1 ... * 1 = x
bool basics::basic_lemma_for_mon_neutral_from_factors_to_monomial_derived(const rooted_mon& rm, const factorization& f) {
bool basics::basic_lemma_for_mon_neutral_from_factors_to_monomial_derived(const signed_vars& rm, const factorization& f) {
return false;
rational sign = rm.orig().m_sign;
rational sign = c().m_emons.orig_sign(rm);
lpvar not_one = -1;
TRACE("nla_solver", tout << "f = "; c().print_factorization(f, tout););
@ -432,17 +413,17 @@ bool basics::basic_lemma_for_mon_neutral_from_factors_to_monomial_derived(const
}
if (not_one == static_cast<lpvar>(-1)) {
c().mk_ineq( c().m_monomials[rm.orig_index()].var(), llc::EQ, sign);
c().mk_ineq( c().m_emons[rm.var()].var(), llc::EQ, sign);
} else {
c().mk_ineq( c().m_monomials[rm.orig_index()].var(), -sign, not_one, llc::EQ);
c().mk_ineq( c().m_emons[rm.var()].var(), -sign, not_one, llc::EQ);
}
TRACE("nla_solver",
tout << "rm = "; c().print_rooted_monomial_with_vars(rm, tout);
c().print_lemma(tout););
tout << "rm = " << rm;
c().print_lemma(tout););
return true;
}
bool basics::basic_lemma_for_mon_neutral_derived(const rooted_mon& rm, const factorization& factorization) {
bool basics::basic_lemma_for_mon_neutral_derived(const signed_vars& rm, const factorization& factorization) {
return
basic_lemma_for_mon_neutral_monomial_to_factor_derived(rm, factorization) ||
basic_lemma_for_mon_neutral_from_factors_to_monomial_derived(rm, factorization);
@ -450,7 +431,7 @@ bool basics::basic_lemma_for_mon_neutral_derived(const rooted_mon& rm, const fac
}
// x != 0 or y = 0 => |xy| >= |y|
void basics::proportion_lemma_model_based(const rooted_mon& rm, const factorization& factorization) {
void basics::proportion_lemma_model_based(const signed_vars& rm, const factorization& factorization) {
rational rmv = abs(vvr(rm));
if (rmv.is_zero()) {
SASSERT(c().has_zero_factor(factorization));
@ -466,7 +447,7 @@ void basics::proportion_lemma_model_based(const rooted_mon& rm, const factorizat
}
}
// x != 0 or y = 0 => |xy| >= |y|
bool basics::proportion_lemma_derived(const rooted_mon& rm, const factorization& factorization) {
bool basics::proportion_lemma_derived(const signed_vars& rm, const factorization& factorization) {
return false;
rational rmv = abs(vvr(rm));
if (rmv.is_zero()) {
@ -507,11 +488,11 @@ void basics::generate_pl_on_mon(const monomial& m, unsigned factor_index) {
// none of the factors is zero and the product is not zero
// -> |fc[factor_index]| <= |rm|
void basics::generate_pl(const rooted_mon& rm, const factorization& fc, int factor_index) {
void basics::generate_pl(const signed_vars& rm, const factorization& fc, int factor_index) {
TRACE("nla_solver", tout << "factor_index = " << factor_index << ", rm = ";
c().print_rooted_monomial_with_vars(rm, tout);
tout << rm;
tout << "fc = "; c().print_factorization(fc, tout);
tout << "orig mon = "; c().print_monomial(c().m_monomials[rm.orig_index()], tout););
tout << "orig mon = "; c().print_monomial(c().m_emons[rm.var()], tout););
if (fc.is_mon()) {
generate_pl_on_mon(*fc.mon(), factor_index);
return;
@ -541,7 +522,7 @@ void basics::generate_pl(const rooted_mon& rm, const factorization& fc, int fact
TRACE("nla_solver", c().print_lemma(tout); );
}
// here we use the fact xy = 0 -> x = 0 or y = 0
void basics::basic_lemma_for_mon_zero_model_based(const rooted_mon& rm, const factorization& f) {
void basics::basic_lemma_for_mon_zero_model_based(const signed_vars& rm, const factorization& f) {
TRACE("nla_solver", c().trace_print_monomial_and_factorization(rm, f, tout););
SASSERT(vvr(rm).is_zero()&& ! c().rm_check(rm));
add_empty_lemma();
@ -562,8 +543,8 @@ void basics::basic_lemma_for_mon_zero_model_based(const rooted_mon& rm, const fa
TRACE("nla_solver", c().print_lemma(tout););
}
void basics::basic_lemma_for_mon_model_based(const rooted_mon& rm) {
TRACE("nla_solver_bl", tout << "rm = "; c().print_rooted_monomial(rm, tout););
void basics::basic_lemma_for_mon_model_based(const signed_vars& rm) {
TRACE("nla_solver_bl", tout << "rm = " << rm;);
if (vvr(rm).is_zero()) {
for (auto factorization : factorization_factory_imp(rm, c())) {
if (factorization.is_empty())
@ -682,10 +663,10 @@ bool basics::basic_lemma_for_mon_neutral_from_factors_to_monomial_model_based_fm
// use the fact that
// |xabc| = |x| and x != 0 -> |a| = |b| = |c| = 1
bool basics::basic_lemma_for_mon_neutral_monomial_to_factor_model_based(const rooted_mon& rm, const factorization& f) {
bool basics::basic_lemma_for_mon_neutral_monomial_to_factor_model_based(const signed_vars& rm, const factorization& f) {
TRACE("nla_solver_bl", c().trace_print_monomial_and_factorization(rm, f, tout););
lpvar mon_var = c().m_monomials[rm.orig_index()].var();
lpvar mon_var = c().m_emons[rm.var()].var();
TRACE("nla_solver_bl", c().trace_print_monomial_and_factorization(rm, f, tout); tout << "\nmon_var = " << mon_var << "\n";);
const auto & mv = vvr(mon_var);
@ -740,7 +721,7 @@ bool basics::basic_lemma_for_mon_neutral_monomial_to_factor_model_based(const ro
return true;
}
void basics::basic_lemma_for_mon_neutral_model_based(const rooted_mon& rm, const factorization& f) {
void basics::basic_lemma_for_mon_neutral_model_based(const signed_vars& rm, const factorization& f) {
if (f.is_mon()) {
basic_lemma_for_mon_neutral_monomial_to_factor_model_based_fm(*f.mon());
basic_lemma_for_mon_neutral_from_factors_to_monomial_model_based_fm(*f.mon());
@ -752,8 +733,8 @@ void basics::basic_lemma_for_mon_neutral_model_based(const rooted_mon& rm, const
}
// use the fact
// 1 * 1 ... * 1 * x * 1 ... * 1 = x
bool basics::basic_lemma_for_mon_neutral_from_factors_to_monomial_model_based(const rooted_mon& rm, const factorization& f) {
rational sign = rm.orig_sign();
bool basics::basic_lemma_for_mon_neutral_from_factors_to_monomial_model_based(const signed_vars& rm, const factorization& f) {
rational sign = c().m_emons.orig_sign(rm);
TRACE("nla_solver_bl", tout << "f = "; c().print_factorization(f, tout); tout << ", sign = " << sign << '\n'; );
lpvar not_one = -1;
for (auto j : f){
@ -801,15 +782,15 @@ bool basics::basic_lemma_for_mon_neutral_from_factors_to_monomial_model_based(co
}
if (not_one == static_cast<lpvar>(-1)) {
c().mk_ineq(c().m_monomials[rm.orig_index()].var(), llc::EQ, sign);
c().mk_ineq(rm.var(), llc::EQ, sign);
} else {
c().mk_ineq(c().m_monomials[rm.orig_index()].var(), -sign, not_one, llc::EQ);
c().mk_ineq(rm.var(), -sign, not_one, llc::EQ);
}
explain(rm);
explain(f);
TRACE("nla_solver",
c().print_lemma(tout);
tout << "rm = "; c().print_rooted_monomial_with_vars(rm, tout);
tout << "rm = " << rm;
);
return true;
}
@ -833,7 +814,7 @@ void basics::basic_lemma_for_mon_non_zero_model_based_mf(const factorization& f)
}
// x = 0 or y = 0 -> xy = 0
void basics::basic_lemma_for_mon_non_zero_model_based(const rooted_mon& rm, const factorization& f) {
void basics::basic_lemma_for_mon_non_zero_model_based(const signed_vars& rm, const factorization& f) {
TRACE("nla_solver_bl", c().trace_print_monomial_and_factorization(rm, f, tout););
if (f.is_mon())
basic_lemma_for_mon_non_zero_model_based_mf(f);

View file

@ -25,7 +25,7 @@
namespace nla {
struct core;
class core;
struct basics: common {
basics(core *core);
bool basic_sign_lemma_on_two_monomials(const monomial& m, const monomial& n, const rational& sign);
@ -40,47 +40,47 @@ struct basics: common {
-ab = a(-b)
*/
bool basic_sign_lemma(bool derived);
bool basic_lemma_for_mon_zero(const rooted_mon& rm, const factorization& f);
bool basic_lemma_for_mon_zero(const signed_vars& rm, const factorization& f);
void basic_lemma_for_mon_zero_model_based(const rooted_mon& rm, const factorization& f);
void basic_lemma_for_mon_zero_model_based(const signed_vars& rm, const factorization& f);
void basic_lemma_for_mon_non_zero_model_based(const rooted_mon& rm, const factorization& f);
void basic_lemma_for_mon_non_zero_model_based(const signed_vars& rm, const factorization& f);
// x = 0 or y = 0 -> xy = 0
void basic_lemma_for_mon_non_zero_model_based_rm(const rooted_mon& rm, const factorization& f);
void basic_lemma_for_mon_non_zero_model_based_rm(const signed_vars& rm, const factorization& f);
void basic_lemma_for_mon_non_zero_model_based_mf(const factorization& f);
// x = 0 or y = 0 -> xy = 0
bool basic_lemma_for_mon_non_zero_derived(const rooted_mon& rm, const factorization& f);
bool basic_lemma_for_mon_non_zero_derived(const signed_vars& rm, const factorization& f);
// use the fact that
// |xabc| = |x| and x != 0 -> |a| = |b| = |c| = 1
bool basic_lemma_for_mon_neutral_monomial_to_factor_model_based(const rooted_mon& rm, const factorization& f);
bool basic_lemma_for_mon_neutral_monomial_to_factor_model_based(const signed_vars& rm, const factorization& f);
// use the fact that
// |xabc| = |x| and x != 0 -> |a| = |b| = |c| = 1
bool basic_lemma_for_mon_neutral_monomial_to_factor_model_based_fm(const monomial& m);
bool basic_lemma_for_mon_neutral_monomial_to_factor_derived(const rooted_mon& rm, const factorization& f);
bool basic_lemma_for_mon_neutral_monomial_to_factor_derived(const signed_vars& rm, const factorization& f);
// use the fact
// 1 * 1 ... * 1 * x * 1 ... * 1 = x
bool basic_lemma_for_mon_neutral_from_factors_to_monomial_model_based(const rooted_mon& rm, const factorization& f);
bool basic_lemma_for_mon_neutral_from_factors_to_monomial_model_based(const signed_vars& rm, const factorization& f);
// use the fact
// 1 * 1 ... * 1 * x * 1 ... * 1 = x
bool basic_lemma_for_mon_neutral_from_factors_to_monomial_model_based_fm(const monomial& m);
// use the fact
// 1 * 1 ... * 1 * x * 1 ... * 1 = x
bool basic_lemma_for_mon_neutral_from_factors_to_monomial_derived(const rooted_mon& rm, const factorization& f);
void basic_lemma_for_mon_neutral_model_based(const rooted_mon& rm, const factorization& f);
bool basic_lemma_for_mon_neutral_from_factors_to_monomial_derived(const signed_vars& rm, const factorization& f);
void basic_lemma_for_mon_neutral_model_based(const signed_vars& rm, const factorization& f);
bool basic_lemma_for_mon_neutral_derived(const rooted_mon& rm, const factorization& factorization);
bool basic_lemma_for_mon_neutral_derived(const signed_vars& rm, const factorization& factorization);
void basic_lemma_for_mon_model_based(const rooted_mon& rm);
void basic_lemma_for_mon_model_based(const signed_vars& rm);
bool basic_lemma_for_mon_derived(const rooted_mon& rm);
bool basic_lemma_for_mon_derived(const signed_vars& rm);
// Use basic multiplication properties to create a lemma
// for the given monomial.
// "derived" means derived from constraints - the alternative is model based
void basic_lemma_for_mon(const rooted_mon& rm, bool derived);
void basic_lemma_for_mon(const signed_vars& rm, bool derived);
// use basic multiplication properties to create a lemma
bool basic_lemma(bool derived);
void generate_sign_lemma(const monomial& m, const monomial& n, const rational& sign);
@ -94,14 +94,14 @@ struct basics: common {
void add_fixed_zero_lemma(const monomial& m, lpvar j);
void negate_strict_sign(lpvar j);
// x != 0 or y = 0 => |xy| >= |y|
void proportion_lemma_model_based(const rooted_mon& rm, const factorization& factorization);
void proportion_lemma_model_based(const signed_vars& rm, const factorization& factorization);
// x != 0 or y = 0 => |xy| >= |y|
bool proportion_lemma_derived(const rooted_mon& rm, const factorization& factorization);
bool proportion_lemma_derived(const signed_vars& rm, const factorization& factorization);
// if there are no zero factors then |m| >= |m[factor_index]|
void generate_pl_on_mon(const monomial& m, unsigned factor_index);
// none of the factors is zero and the product is not zero
// -> |fc[factor_index]| <= |rm|
void generate_pl(const rooted_mon& rm, const factorization& fc, int factor_index);
void generate_pl(const signed_vars& rm, const factorization& fc, int factor_index);
};
}

View file

@ -21,31 +21,31 @@
#include "util/lp/nla_core.h"
namespace nla {
bool common::done() const { return m_core->done(); }
bool common::done() const { return c().done(); }
template <typename T> void common::explain(const T& t) {
c().explain(t, c().current_expl());
}
template void common::explain<monomial>(const monomial& t);
template void common::explain<factor>(const factor& t);
template void common::explain<rooted_mon>(const rooted_mon& t);
template void common::explain<signed_vars>(const signed_vars& t);
template void common::explain<factorization>(const factorization& t);
void common::explain(lpvar j) { c().explain(j, c().current_expl()); }
template <typename T> rational common::vvr(T const& t) const { return m_core->vvr(t); }
template <typename T> rational common::vvr(T const& t) const { return c().vvr(t); }
template rational common::vvr<monomial>(monomial const& t) const;
template rational common::vvr<rooted_mon>(rooted_mon const& t) const;
template rational common::vvr<signed_vars>(signed_vars const& t) const;
template rational common::vvr<factor>(factor const& t) const;
rational common::vvr(lpvar t) const { return m_core->vvr(t); }
template <typename T> lpvar common::var(T const& t) const { return m_core->var(t); }
rational common::vvr(lpvar t) const { return c().vvr(t); }
template <typename T> lpvar common::var(T const& t) const { return c().var(t); }
template lpvar common::var<factor>(factor const& t) const;
template lpvar common::var<rooted_mon>(rooted_mon const& t) const;
template lpvar common::var<signed_vars>(signed_vars const& t) const;
void common::add_empty_lemma() { c().add_empty_lemma(); }
template <typename T> rational common::canonize_sign(const T& t) const {
return c().canonize_sign(t);
}
template rational common::canonize_sign<rooted_mon>(const rooted_mon& t) const;
template rational common::canonize_sign<signed_vars>(const signed_vars& t) const;
template rational common::canonize_sign<factor>(const factor& t) const;
rational common::canonize_sign(lpvar j) const {
return c().canonize_sign_of_var(j);
@ -99,18 +99,19 @@ std::ostream& common::print_product(const T & m, std::ostream& out) const {
template
std::ostream& common::print_product<monomial>(const monomial & m, std::ostream& out) const;
template std::ostream& common::print_product<rooted_mon>(const rooted_mon & m, std::ostream& out) const;
template std::ostream& common::print_product<signed_vars>(const signed_vars & m, std::ostream& out) const;
std::ostream& common::print_monomial(const monomial & m, std::ostream& out) const {
return c().print_monomial(m, out);
}
std::ostream& common::print_rooted_monomial(const rooted_mon& rm, std::ostream& out) const {
return c().print_rooted_monomial(rm, out);
}
std::ostream& common::print_rooted_monomial_with_vars(const rooted_mon& rm, std::ostream& out) const {
return c().print_rooted_monomial_with_vars(rm, out);
}
//std::ostream& common::print_rooted_monomial(const signed_vars& rm, std::ostream& out) const {
// return c().print_rooted_monomial(rm, out);
//}
//std::ostream& common::print_rooted_monomial_with_vars(const signed_vars& rm, std::ostream& out) const {
// return c().print_rooted_monomial_with_vars(rm, out);
//}
std::ostream& common::print_factor(const factor & f, std::ostream& out) const {
return c().print_factor(f, out);
}

View file

@ -22,9 +22,11 @@
#include "util/lp/nla_defs.h"
#include "util/lp/lar_term.h"
#include "util/lp/monomial.h"
#include "util/lp/emonomials.h"
#include "util/lp/factorization.h"
#include "util/lp/rooted_mons.h"
namespace nla {
inline llc negate(llc cmp) {
switch(cmp) {
case llc::LE: return llc::GT;
@ -38,7 +40,7 @@ inline llc negate(llc cmp) {
return cmp; // not reachable
}
struct core;
class core;
struct common {
core* m_core;
common(core* c): m_core(c) {}
@ -82,8 +84,8 @@ struct common {
std::ostream& print_var(lpvar, std::ostream& out) const;
std::ostream& print_monomial(const monomial & m, std::ostream& out) const;
std::ostream& print_rooted_monomial(const rooted_mon &, std::ostream& out) const;
std::ostream& print_rooted_monomial_with_vars(const rooted_mon&, std::ostream& out) const;
std::ostream& print_rooted_monomial(const signed_vars &, std::ostream& out) const;
std::ostream& print_rooted_monomial_with_vars(const signed_vars&, std::ostream& out) const;
bool check_monomial(const monomial&) const;
unsigned random();
};

View file

@ -79,75 +79,46 @@ bool core::lemma_holds(const lemma& l) const {
svector<lpvar> core::sorted_vars(const factor& f) const {
if (f.is_var()) {
svector<lpvar> r; r.push_back(f.index());
svector<lpvar> r; r.push_back(f.var());
return r;
}
TRACE("nla_solver", tout << "nv";);
return m_rm_table.rms()[f.index()].vars();
return m_emons.canonical[f.var()].vars();
}
// the value of the factor is equal to the value of the variable multiplied
// by the canonize_sign
rational core::canonize_sign(const factor& f) const {
return f.is_var()?
canonize_sign_of_var(f.index()) : m_rm_table.rms()[f.index()].orig_sign();
canonize_sign_of_var(f.var()) : m_emons.canonical[f.var()].rsign();
}
rational core::canonize_sign_of_var(lpvar j) const {
return m_evars.find(j).rsign();
}
// the value of the rooted monomias is equal to the value of the variable multiplied
// by the canonize_sign
rational core::canonize_sign(const rooted_mon& m) const {
return m.orig().sign();
rational core::canonize_sign(const signed_vars& m) const {
NOT_IMPLEMENTED_YET();
return rational::one();
}
// returns the monomial index
unsigned core::add(lpvar v, unsigned sz, lpvar const* vs) {
m_monomials.push_back(monomial(v, sz, vs));
TRACE("nla_solver", print_monomial(m_monomials.back(), tout););
const auto & m = m_monomials.back();
SASSERT(m_mkeys.find(m.vars()) == m_mkeys.end());
return m_mkeys[m.vars()] = m_monomials.size() - 1;
void core::add(lpvar v, unsigned sz, lpvar const* vs) {
m_emons.add(v, sz, vs);
}
void core::push() {
TRACE("nla_solver",);
m_monomials_counts.push_back(m_monomials.size());
m_evars.push();
m_emons.push();
}
void core::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 core::deregister_monomial_from_tables(const monomial & m, unsigned i){
TRACE("nla_solver", tout << "m = "; print_monomial(m, tout););
m_mkeys.erase(m.vars());
deregister_monomial_from_rooted_monomials(m, i);
}
void core::pop(unsigned n) {
TRACE("nla_solver", tout << "n = " << n <<
" , m_monomials_counts.size() = " << m_monomials_counts.size() << ", m_monomials.size() = " << m_monomials.size() << "\n"; );
if (n == 0) return;
unsigned new_size = m_monomials_counts[m_monomials_counts.size() - n];
TRACE("nla_solver", tout << "new_size = " << new_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);
m_evars.pop(n);
TRACE("nla_solver", tout << "n = " << n << "\n";);
m_emons.pop(n);
}
rational core::mon_value_by_vars(unsigned i) const {
return product_value(m_monomials[i]);
}
template <typename T>
rational core::product_value(const T & m) const {
rational r(1);
@ -168,16 +139,15 @@ void core::explain(const monomial& m, lp::explanation& exp) const {
explain(j, exp);
}
void core::explain(const rooted_mon& rm, lp::explanation& exp) const {
auto & m = m_monomials[rm.orig_index()];
explain(m, exp);
void core::explain(const signed_vars& rm, lp::explanation& exp) const {
explain(m_emons[rm.var()], exp);
}
void core::explain(const factor& f, lp::explanation& exp) const {
if (f.type() == factor_type::VAR) {
explain(f.index(), exp);
explain(f.var(), exp);
} else {
explain(m_monomials[m_rm_table.rms()[f.index()].orig_index()], exp);
explain(m_emons[f.var()], exp);
}
}
@ -187,22 +157,23 @@ void core::explain(lpvar j, lp::explanation& exp) const {
template <typename T>
std::ostream& core::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]) << "=" << vvr(m[k]) << ")";
if (k + 1 < m.size()) out << "*";
bool first = true;
for (lpvar v : m) {
if (!first) out << "*"; else first = false;
out << "(" << m_lar_solver.get_variable_name(v) << "=" << vvr(v) << ")";
}
return out;
}
template std::ostream& core::print_product<monomial>(const monomial & m, std::ostream& out) const;
template std::ostream& core::print_product<rooted_mon>(const rooted_mon & m, std::ostream& out) const;
template std::ostream& core::print_product<signed_vars>(const signed_vars & m, std::ostream& out) const;
std::ostream & core::print_factor(const factor& f, std::ostream& out) const {
if (f.is_var()) {
out << "VAR, ";
print_var(f.index(), out);
print_var(f.var(), out);
} else {
out << "PROD, ";
print_product(m_rm_table.rms()[f.index()].vars(), out);
print_product(m_emons.canonical[f.var()].vars(), out);
}
out << "\n";
return out;
@ -210,10 +181,10 @@ std::ostream & core::print_factor(const factor& f, std::ostream& out) const {
std::ostream & core::print_factor_with_vars(const factor& f, std::ostream& out) const {
if (f.is_var()) {
print_var(f.index(), out);
print_var(f.var(), out);
} else {
out << " RM = "; print_rooted_monomial_with_vars(m_rm_table.rms()[f.index()], out);
out << "\n orig mon = "; print_monomial_with_vars(m_monomials[m_rm_table.rms()[f.index()].orig_index()], out);
out << " RM = " << m_emons.canonical[f.var()];
out << "\n orig mon = " << m_emons[f.var()];
}
return out;
}
@ -241,11 +212,11 @@ std::ostream& core::print_bfc(const bfc& m, std::ostream& out) const {
}
std::ostream& core::print_monomial(unsigned i, std::ostream& out) const {
return print_monomial(m_monomials[i], out);
return print_monomial(m_emons[i], out);
}
std::ostream& core::print_monomial_with_vars(unsigned i, std::ostream& out) const {
return print_monomial_with_vars(m_monomials[i], out);
std::ostream& core::print_monomial_with_vars(lpvar v, std::ostream& out) const {
return print_monomial_with_vars(m_emons[v], out);
}
template <typename T>
@ -260,30 +231,12 @@ std::ostream& core::print_product_with_vars(const T& m, std::ostream& out) const
std::ostream& core::print_monomial_with_vars(const monomial& m, std::ostream& out) const {
out << "["; print_var(m.var(), out) << "]\n";
for(lpvar j: m)
for (lpvar j: m)
print_var(j, out);
out << ")\n";
return out;
}
std::ostream& core::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& core::print_rooted_monomial_with_vars(const rooted_mon& rm, std::ostream& out) const {
out << "vars = ";
print_product(rm.vars(), out);
out << "\n orig = "; print_monomial_with_vars(m_monomials[rm.orig_index()], out);
out << ", orig sign = " << rm.orig_sign() << "\n";
out << ", vvr(rm) = " << vvr(rm) << "\n";
return out;
}
std::ostream& core::print_explanation(const lp::explanation& exp, std::ostream& out) const {
out << "expl: ";
for (auto &p : exp) {
@ -400,13 +353,12 @@ bool core:: explain_ineq(const lp::lar_term& t, llc cmp, const rational& rs) {
(rs.is_zero() && explain_by_equiv(t, exp));
break;
case llc::NE:
r = explain_lower_bound(t, rs + rational(1), exp) || explain_upper_bound(t, rs - rational(1), exp);
// TBD - NB: does this work for Reals?
r = explain_lower_bound(t, rs + rational(1), exp) || explain_upper_bound(t, rs - rational(1), exp);
break;
default:
SASSERT(false);
r = false;
UNREACHABLE();
return false;
}
if (r) {
current_expl().add(exp);
@ -426,10 +378,10 @@ bool core:: explain_by_equiv(const lp::lar_term& t, lp::explanation& e) {
bool sign;
if (!is_octagon_term(t, sign, i, j))
return false;
if (m_evars.find(signed_var(i,false)) != m_evars.find(signed_var(j, sign)))
if (m_evars.find(signed_var(i, false)) != m_evars.find(signed_var(j, sign)))
return false;
m_evars.explain(signed_var(i,false), signed_var(j, sign), e);
m_evars.explain(signed_var(i, false), signed_var(j, sign), e);
TRACE("nla_solver", tout << "explained :"; m_lar_solver.print_term(t, tout););
return true;
@ -437,13 +389,12 @@ bool core:: explain_by_equiv(const lp::lar_term& t, lp::explanation& e) {
void core::mk_ineq(lp::lar_term& t, llc cmp, const rational& rs) {
TRACE("nla_solver_details", m_lar_solver.print_term(t, tout << "t = "););
if (explain_ineq(t, cmp, rs)) {
return;
if (!explain_ineq(t, cmp, rs)) {
m_lar_solver.subs_term_columns(t);
current_lemma().push_back(ineq(cmp, t, rs));
CTRACE("nla_solver", ineq_holds(ineq(cmp, t, rs)), print_ineq(ineq(cmp, t, rs), tout) << "\n";);
SASSERT(!ineq_holds(ineq(cmp, t, rs)));
}
m_lar_solver.subs_term_columns(t);
current_lemma().push_back(ineq(cmp, t, rs));
CTRACE("nla_solver", ineq_holds(ineq(cmp, t, rs)), print_ineq(ineq(cmp, t, rs), tout) << "\n";);
SASSERT(!ineq_holds(ineq(cmp, t, rs)));
}
void core::mk_ineq(const rational& a, lpvar j, const rational& b, lpvar k, llc cmp, const rational& rs) {
@ -781,9 +732,8 @@ std::ostream & core::print_ineq(const ineq & in, std::ostream & out) const {
}
std::ostream & core::print_var(lpvar j, std::ostream & out) const {
auto it = m_var_to_its_monomial.find(j);
if (it != m_var_to_its_monomial.end()) {
print_monomial(m_monomials[it->second], out);
if (m_emons.is_monomial_var(j)) {
print_monomial(m_emons[j], out);
out << " = " << vvr(j);;
}
@ -792,7 +742,7 @@ std::ostream & core::print_var(lpvar j, std::ostream & out) const {
}
std::ostream & core::print_monomials(std::ostream & out) const {
for (auto &m : m_monomials) {
for (auto &m : m_emons) {
print_monomial_with_vars(m, out);
}
return out;
@ -835,23 +785,13 @@ std::ostream & core::print_factorization(const factorization& f, std::ostream& o
bool core:: find_rm_monomial_of_vars(const svector<lpvar>& vars, unsigned & i) const {
SASSERT(vars_are_roots(vars));
auto it = m_rm_table.vars_key_to_rm_index().find(vars);
if (it == m_rm_table.vars_key_to_rm_index().end()) {
return false;
}
i = it->second;
TRACE("nla_solver",);
SASSERT(lp::vectors_are_equal_(vars, m_rm_table.rms()[i].vars()));
return true;
signed_vars const* sv = m_emons.find_canonical(vars);
return sv && (i = sv->var(), true);
}
const monomial* core::find_monomial_of_vars(const svector<lpvar>& vars) const {
unsigned i;
if (!find_rm_monomial_of_vars(vars, i))
return nullptr;
return &m_monomials[m_rm_table.rms()[i].orig_index()];
signed_vars const* sv = m_emons.find_canonical(vars);
return sv ? &m_emons[sv->var()] : nullptr;
}
@ -873,8 +813,8 @@ void core::explain_separation_from_zero(lpvar j) {
explain_existing_upper_bound(j);
}
int core::get_derived_sign(const rooted_mon& rm, const factorization& f) const {
rational sign = rm.orig_sign(); // this is the flip sign of the variable var(rm)
int core::get_derived_sign(const signed_vars& rm, const factorization& f) const {
rational sign = rm.rsign(); // this is the flip sign of the variable var(rm)
SASSERT(!sign.is_zero());
for (const factor& fc: f) {
lpvar j = var(fc);
@ -885,12 +825,12 @@ int core::get_derived_sign(const rooted_mon& rm, const factorization& f) const {
}
return nla::rat_sign(sign);
}
void core::trace_print_monomial_and_factorization(const rooted_mon& rm, const factorization& f, std::ostream& out) const {
void core::trace_print_monomial_and_factorization(const signed_vars& rm, const factorization& f, std::ostream& out) const {
out << "rooted vars: ";
print_product(rm.m_vars, out);
print_product(rm.vars(), out);
out << "\n";
print_monomial(rm.orig_index(), out << "mon: ") << "\n";
print_monomial(rm.var(), out << "mon: ") << "\n";
out << "value: " << vvr(rm) << "\n";
print_factorization(f, out << "fact: ") << "\n";
}
@ -1338,13 +1278,6 @@ bool core:: mon_has_zero(const T& product) const {
template bool core::mon_has_zero<monomial>(const monomial& product) const;
void core::init_rm_to_refine() {
if (!m_rm_table.to_refine().empty())
return;
std::unordered_set<unsigned> ref;
ref.insert(m_to_refine.begin(), m_to_refine.end());
m_rm_table.init_to_refine(ref);
}
lp::lp_settings& core::settings() {
return m_lar_solver.settings();
@ -1352,53 +1285,6 @@ lp::lp_settings& core::settings() {
unsigned core::random() { return settings().random_next(); }
// use basic multiplication properties to create a lemma
bool core:: basic_lemma(bool derived) {
if (basic_sign_lemma(derived))
return true;
if (derived)
return false;
init_rm_to_refine();
const auto& rm_ref = m_rm_table.to_refine();
TRACE("nla_solver", tout << "rm_ref = "; print_vector(rm_ref, tout););
unsigned start = random() % rm_ref.size();
unsigned i = start;
do {
const rooted_mon& r = m_rm_table.rms()[rm_ref[i]];
SASSERT (!check_monomial(m_monomials[r.orig_index()]));
basic_lemma_for_mon(r, derived);
if (++i == rm_ref.size()) {
i = 0;
}
} while(i != start && !done());
return false;
}
void core::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 core::map_vars_to_monomials() {
for (unsigned i = 0; i < m_monomials.size(); i++) {
const monomial& m = m_monomials[i];
lpvar v = m.var();
SASSERT(m_var_to_its_monomial.find(v) == m_var_to_its_monomial.end());
m_var_to_its_monomial[v] = i;
map_monomial_vars_to_monomial_indices(i);
}
}
// we look for octagon constraints here, with a left part +-x +- y
void core::collect_equivs() {
@ -1494,38 +1380,6 @@ void core::init_vars_equivalence() {
SASSERT((settings().random_next() % 100) || tables_are_ok());
}
bool core:: vars_table_is_ok() const {
for (lpvar j = 0; j < m_lar_solver.number_of_vars(); j++) {
auto it = m_var_to_its_monomial.find(j);
if (it != m_var_to_its_monomial.end()
&& m_monomials[it->second].var() != j) {
TRACE("nla_solver", tout << "j = ";
print_var(j, tout););
return false;
}
}
for (unsigned i = 0; i < m_monomials.size(); i++){
const monomial& m = m_monomials[i];
lpvar j = m.var();
if (m_var_to_its_monomial.find(j) == m_var_to_its_monomial.end()){
return false;
}
}
return true;
}
bool core:: rm_table_is_ok() const {
for (const auto & rm : m_rm_table.rms()) {
for (lpvar j : rm.vars()) {
if (!m_evars.is_root(j)){
TRACE("nla_solver", print_var(j, tout););
return false;
}
}
}
return true;
}
bool core:: tables_are_ok() const {
return vars_table_is_ok() && rm_table_is_ok();
@ -1543,26 +1397,14 @@ bool core:: vars_are_roots(const T& v) const {
}
void core::register_monomial_in_tables(unsigned i_mon) {
const monomial& m = m_monomials[i_mon];
monomial_coeff mc = canonize_monomial(m);
TRACE("nla_solver_rm", tout << "i_mon = " << i_mon << ", mon = ";
print_monomial(m_monomials[i_mon], tout);
tout << "\nmc = ";
print_product(mc.vars(), tout);
);
m_rm_table.register_key_mono_in_rooted_monomials(mc, i_mon);
}
template <typename T>
void core::trace_print_rms(const T& p, std::ostream& out) {
out << "p = {";
out << "p = {\n";
for (auto j : p) {
out << "\nj = " << j <<
", rm = ";
print_rooted_monomial(m_rm_table.rms()[j], out);
out << "j = " << j << ", rm = " << m_emons.canonical[j] << "\n";
}
out << "\n}";
out << "}";
}
void core::print_monomial_stats(const monomial& m, std::ostream& out) {
@ -1572,8 +1414,8 @@ void core::print_monomial_stats(const monomial& m, std::ostream& out) {
if (abs(vvr(mc.vars()[i])) == rational(1)) {
auto vv = mc.vars();
vv.erase(vv.begin()+i);
auto it = m_rm_table.vars_key_to_rm_index().find(vv);
if (it == m_rm_table.vars_key_to_rm_index().end()) {
signed_vars const* sv = m_emons.find_canonical(vv);
if (!sv) {
out << "nf length" << vv.size() << "\n"; ;
}
}
@ -1581,32 +1423,16 @@ void core::print_monomial_stats(const monomial& m, std::ostream& out) {
}
void core::print_stats(std::ostream& out) {
// for (const auto& m : m_monomials)
// print_monomial_stats(m, out);
m_rm_table.print_stats(out);
}
void core::register_monomials_in_tables() {
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_proper_multiples();
TRACE("nla_solver_rm", print_stats(tout););
}
void core::clear() {
m_var_to_its_monomial.clear();
m_rm_table.clear();
m_monomials_containing_var.clear();
m_lemma_vec->clear();
}
void core::init_search() {
clear();
map_vars_to_monomials();
init_vars_equivalence();
register_monomials_in_tables();
}
void core::init_to_refine() {
@ -1617,15 +1443,16 @@ void core::init_to_refine() {
TRACE("nla_solver",
tout << m_to_refine.size() << " mons to refine:\n";
for (unsigned v : m_to_refine) tout << m_emons.var2monomial(v) << "\n";);
for (lpvar v : m_to_refine) tout << m_emons[v] << "\n";);
}
std::unordered_set<lpvar> core::collect_vars(const lemma& l) const {
std::unordered_set<lpvar> vars;
auto insert_j = [&](lpvar j) {
vars.insert(j);
auto const* m = m_emons.var2monomial(j);
if (m) for (lpvar k : *m) vars.insert(k);
if (m_emons.is_monomial_var(j)) {
for (lpvar k : m_emons[j]) vars.insert(k);
}
};
for (const auto& i : current_lemma().ineqs()) {
@ -1642,7 +1469,7 @@ std::unordered_set<lpvar> core::collect_vars(const lemma& l) const {
return vars;
}
bool core:: divide(const rooted_mon& bc, const factor& c, factor & b) const {
bool core::divide(const signed_vars& bc, const factor& c, factor & b) const {
svector<lpvar> c_vars = sorted_vars(c);
TRACE("nla_solver_div",
tout << "c_vars = ";
@ -1659,12 +1486,12 @@ bool core:: divide(const rooted_mon& bc, const factor& c, factor & b) const {
b = factor(b_vars[0]);
return true;
}
auto it = m_rm_table.vars_key_to_rm_index().find(b_vars);
if (it == m_rm_table.vars_key_to_rm_index().end()) {
signed_vars const* sv = m_emons.find_canonical(b_vars);
if (!sv) {
TRACE("nla_solver_div", tout << "not in rooted";);
return false;
}
b = factor(it->second, factor_type::RM);
b = factor(sv->var(), factor_type::RM);
TRACE("nla_solver_div", tout << "success div:"; print_factor(b, tout););
return true;
}
@ -1709,17 +1536,15 @@ void core::print_specific_lemma(const lemma& l, std::ostream& out) const {
}
void core::trace_print_ol(const rooted_mon& ac,
void core::trace_print_ol(const signed_vars& ac,
const factor& a,
const factor& c,
const rooted_mon& bc,
const signed_vars& bc,
const factor& b,
std::ostream& out) {
out << "ac = ";
print_rooted_monomial_with_vars(ac, out);
out << "\nbc = ";
print_rooted_monomial_with_vars(bc, out);
out << "\na = ";
out << "ac = " << ac << "\n";
out << "bc = " << bc << "\n";
out << "a = ";
print_factor_with_vars(a, out);
out << ", \nb = ";
print_factor_with_vars(b, out);
@ -1733,20 +1558,15 @@ void core::maybe_add_a_factor(lpvar i,
std::unordered_set<unsigned>& found_rm,
vector<factor> & r) const {
SASSERT(abs(vvr(i)) == abs(vvr(c)));
auto it = m_var_to_its_monomial.find(i);
if (it == m_var_to_its_monomial.end()) {
if (!m_emons.is_monomial_var(i)) {
i = m_evars.find(i).var();
if (try_insert(i, found_vars)) {
r.push_back(factor(i, factor_type::VAR));
}
} else {
SASSERT(m_monomials[it->second].var() == i && abs(vvr(m_monomials[it->second])) == abs(vvr(c)));
const index_with_sign & i_s = m_rm_table.get_rooted_mon(it->second);
unsigned rm_i = i_s.index();
// SASSERT(abs(vvr(m_rm_table.rms()[i])) == abs(vvr(c)));
if (try_insert(rm_i, found_rm)) {
r.push_back(factor(rm_i, factor_type::RM));
TRACE("nla_solver", tout << "inserting factor = "; print_factor_with_vars(factor(rm_i, factor_type::RM), tout); );
if (try_insert(i, found_rm)) {
r.push_back(factor(i, factor_type::RM));
TRACE("nla_solver", tout << "inserting factor = "; print_factor_with_vars(factor(i, factor_type::RM), tout); );
}
}
}
@ -1755,21 +1575,21 @@ void core::maybe_add_a_factor(lpvar i,
// Returns rooted monomials by arity
std::unordered_map<unsigned, unsigned_vector> core::get_rm_by_arity() {
std::unordered_map<unsigned, unsigned_vector> m;
for (unsigned i = 0; i < m_rm_table.rms().size(); i++ ) {
unsigned arity = m_rm_table.rms()[i].vars().size();
for (auto const& mon : m_emons) {
unsigned arity = mon.vars().size();
auto it = m.find(arity);
if (it == m.end()) {
it = m.insert(it, std::make_pair(arity, unsigned_vector()));
}
it->second.push_back(i);
it->second.push_back(mon.var());
}
return m;
}
bool core:: rm_check(const rooted_mon& rm) const {
return check_monomial(m_monomials[rm.orig_index()]);
bool core::rm_check(const signed_vars& rm) const {
return check_monomial(m_emons[rm.var()]);
}
@ -1817,6 +1637,7 @@ void core::add_abs_bound(lpvar v, llc cmp, rational const& bound) {
mk_ineq(t, cmp, abs(bound));
}
// NB - move this comment to monotonicity or appropriate.
/** \brief enforce the inequality |m| <= product |m[i]| .
by enforcing lemma:
/\_i |m[i]| <= |vvr(m[i])| => |m| <= |product_i vvr(m[i])|
@ -1825,7 +1646,7 @@ void core::add_abs_bound(lpvar v, llc cmp, rational const& bound) {
*/
bool core:: find_bfc_to_refine_on_rmonomial(const rooted_mon& rm, bfc & bf) {
bool core::find_bfc_to_refine_on_rmonomial(const signed_vars& rm, bfc & bf) {
for (auto factorization : factorization_factory_imp(rm, *this)) {
if (factorization.size() == 2) {
auto a = factorization[0];
@ -1839,13 +1660,14 @@ bool core:: find_bfc_to_refine_on_rmonomial(const rooted_mon& rm, bfc & bf) {
return false;
}
bool core:: find_bfc_to_refine(bfc& bf, lpvar &j, rational& sign, const rooted_mon*& rm_found){
for (unsigned i: m_rm_table.to_refine()) {
const auto& rm = m_rm_table.rms()[i];
SASSERT (!check_monomial(m_monomials[rm.orig_index()]));
bool core::find_bfc_to_refine(bfc& bf, lpvar &j, rational& sign, const signed_vars*& rm_found){
rm_found = nullptr;
for (unsigned i: m_to_refine) {
const auto& rm = m_emons.canonical[i];
SASSERT (!check_monomial(m_emons[rm.var()]));
if (rm.size() == 2) {
sign = rational(1);
const monomial & m = m_monomials[rm.orig_index()];
const monomial & m = m_emons[rm.var()];
j = m.var();
rm_found = nullptr;
bf.m_x = factor(m[0]);
@ -1855,10 +1677,10 @@ bool core:: find_bfc_to_refine(bfc& bf, lpvar &j, rational& sign, const rooted_m
rm_found = &rm;
if (find_bfc_to_refine_on_rmonomial(rm, bf)) {
j = m_monomials[rm.orig_index()].var();
sign = rm.orig_sign();
j = rm.var();
sign = rm.rsign();
TRACE("nla_solver", tout << "found bf";
tout << ":rm:"; print_rooted_monomial(rm, tout) << "\n";
tout << ":rm:" << rm << "\n";
tout << "bf:"; print_bfc(bf, tout);
tout << ", product = " << vvr(rm) << ", but should be =" << vvr(bf.m_x)*vvr(bf.m_y);
tout << ", j == "; print_var(j, tout) << "\n";);
@ -2159,3 +1981,10 @@ lbool core::test_check(
template rational core::product_value<monomial>(const monomial & m) const;
} // end of nla
#if 0
rational core::mon_value_by_vars(unsigned i) const {
return product_value(m_monomials[i]);
}
#endif

View file

@ -21,7 +21,6 @@
#include "util/lp/factorization.h"
#include "util/lp/lp_types.h"
#include "util/lp/var_eqs.h"
#include "util/lp/rooted_mons.h"
#include "util/lp/nla_tangent_lemmas.h"
#include "util/lp/nla_basics_lemmas.h"
#include "util/lp/nla_order_lemmas.h"
@ -38,8 +37,8 @@ bool try_insert(const A& elem, B& collection) {
return true;
}
typedef lp::constraint_index lpci;
typedef lp::lconstraint_kind llc;
typedef lp::constraint_index lpci;
typedef lp::lconstraint_kind llc;
typedef lp::constraint_index lpci;
typedef lp::explanation expl_set;
typedef lp::var_index lpvar;
@ -75,29 +74,20 @@ public:
};
struct core {
//fields
var_eqs m_evars;
vector<monomial> m_monomials;
class core {
public:
var_eqs m_evars;
emonomials m_emons;
lp::lar_solver m_lar_solver;
vector<lemma> * m_lemma_vec;
svector<lpvar> m_to_refine;
tangents m_tangents;
basics m_basics;
order m_order;
monotone m_monotone;
// 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;
vector<lemma> * m_lemma_vec;
unsigned_vector m_to_refine;
std::unordered_map<unsigned_vector, unsigned, hash_svector> m_mkeys; // the key is the sorted vars of a monomial
tangents m_tangents;
basics m_basics;
order m_order;
monotone m_monotone;
emonomials m_emons;
// methods
core(lp::lar_solver& s);
bool compare_holds(const rational& ls, llc cmp, const rational& rs) const;
rational value(const lp::lar_term& r) const;
@ -112,13 +102,13 @@ struct core {
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.orig_index()].var(); }
lpvar var(signed_vars const& sv) const { return sv.var(); }
rational vvr(const rooted_mon& rm) const { return vvr(m_monomials[rm.orig_index()].var()) * rm.orig_sign(); }
rational vvr(const signed_vars& rm) const { return vvr(m_emons[rm.var()]); } // NB: removed multiplication with sign.
rational vvr(const factor& f) const { return f.is_var()? vvr(f.index()) : vvr(m_rm_table.rms()[f.index()]); }
rational vvr(const factor& f) const { return f.is_var()? vvr(f.var()) : vvr(m_emons[f.var()]); }
lpvar var(const factor& f) const { return f.is_var()? f.index() : var(m_rm_table.rms()[f.index()]); }
lpvar var(const factor& f) const { return f.var(); }
svector<lpvar> sorted_vars(const factor& f) const;
bool done() const;
@ -132,17 +122,16 @@ struct core {
// the value of the rooted monomias is equal to the value of the variable multiplied
// by the canonize_sign
rational canonize_sign(const rooted_mon& m) const;
rational canonize_sign(const signed_vars& m) const;
// returns the monomial index
unsigned add(lpvar v, unsigned sz, lpvar const* vs);
void push();
void deregister_monomial_from_rooted_monomials (const monomial & m, unsigned i);
void deregister_monomial_from_signed_varsomials (const monomial & m, unsigned i);
void deregister_monomial_from_tables(const monomial & m, unsigned i);
// returns the monomial index
void add(lpvar v, unsigned sz, lpvar const* vs);
void push();
void pop(unsigned n);
rational mon_value_by_vars(unsigned i) const;
@ -153,7 +142,7 @@ struct core {
bool check_monomial(const monomial& m) const;
void explain(const monomial& m, lp::explanation& exp) const;
void explain(const rooted_mon& rm, lp::explanation& exp) const;
void explain(const signed_vars& rm, lp::explanation& exp) const;
void explain(const factor& f, lp::explanation& exp) const;
void explain(lpvar j, lp::explanation& exp) const;
void explain_existing_lower_bound(lpvar j);
@ -179,12 +168,10 @@ struct core {
template <typename T>
std::ostream& print_product_with_vars(const T& m, std::ostream& out) const;
std::ostream& print_monomial_with_vars(const monomial& m, std::ostream& out) const;
std::ostream& print_rooted_monomial(const rooted_mon& rm, std::ostream& out) const;
std::ostream& print_rooted_monomial_with_vars(const rooted_mon& rm, std::ostream& out) const;
std::ostream& print_explanation(const lp::explanation& exp, std::ostream& out) const;
template <typename T>
void trace_print_rms(const T& p, std::ostream& out);
void trace_print_monomial_and_factorization(const rooted_mon& rm, const factorization& f, std::ostream& out) const;
void trace_print_monomial_and_factorization(const signed_vars& rm, const factorization& f, std::ostream& out) const;
void print_monomial_stats(const monomial& m, std::ostream& out);
void print_stats(std::ostream& out);
std::ostream& print_lemma(std::ostream& out) const;
@ -192,10 +179,10 @@ struct core {
void print_specific_lemma(const lemma& l, std::ostream& out) const;
void trace_print_ol(const rooted_mon& ac,
void trace_print_ol(const signed_vars& ac,
const factor& a,
const factor& c,
const rooted_mon& bc,
const signed_vars& bc,
const factor& b,
std::ostream& out);
@ -258,7 +245,7 @@ struct core {
const monomial* find_monomial_of_vars(const svector<lpvar>& vars) const;
int get_derived_sign(const rooted_mon& rm, const factorization& f) const;
int get_derived_sign(const signed_vars& rm, const factorization& f) const;
bool var_has_positive_lower_bound(lpvar j) const;
@ -289,7 +276,7 @@ struct core {
template <typename T>
bool mon_has_zero(const T& product) const;
void init_rm_to_refine();
void init_rm_to_refine() { NOT_IMPLEMENTED_YET(); }
lp::lp_settings& settings();
unsigned random();
void map_monomial_vars_to_monomial_indices(unsigned i);
@ -328,7 +315,7 @@ struct core {
void init_to_refine();
bool divide(const rooted_mon& bc, const factor& c, factor & b) const;
bool divide(const signed_vars& bc, const factor& c, factor & b) const;
void negate_factor_equality(const factor& c, const factor& d);
@ -336,15 +323,15 @@ struct core {
std::unordered_set<lpvar> collect_vars(const lemma& l) const;
bool rm_check(const rooted_mon&) const;
bool rm_check(const signed_vars&) const;
std::unordered_map<unsigned, unsigned_vector> get_rm_by_arity();
void add_abs_bound(lpvar v, llc cmp);
void add_abs_bound(lpvar v, llc cmp, rational const& bound);
bool find_bfc_to_refine_on_rmonomial(const rooted_mon& rm, bfc & bf);
bool find_bfc_to_refine_on_rmonomial(const signed_vars& rm, bfc & bf);
bool find_bfc_to_refine(bfc& bf, lpvar &j, rational& sign, const rooted_mon*& rm_found);
bool find_bfc_to_refine(bfc& bf, lpvar &j, rational& sign, const signed_vars*& rm_found);
void generate_simple_sign_lemma(const rational& sign, const monomial& m);
void negate_relation(unsigned j, const rational& a);

View file

@ -19,7 +19,7 @@
--*/
#include "util/lp/nla_basics_lemmas.h"
#include "util/lp/nla_core.h"
#include "util/lp/factorization_factory_imp.h"
// #include "util/lp/factorization_factory_imp.h"
namespace nla {
monotone::monotone(core * c) : common(c) {}
@ -33,18 +33,15 @@ void monotone::print_monotone_array(const vector<std::pair<std::vector<rational>
}
out << "}";
}
bool monotone::monotonicity_lemma_on_lex_sorted_rm_upper(const vector<std::pair<std::vector<rational>, unsigned>>& lex_sorted, unsigned i, const rooted_mon& rm) {
bool monotone::monotonicity_lemma_on_lex_sorted_rm_upper(const vector<std::pair<std::vector<rational>, unsigned>>& lex_sorted, unsigned i, const signed_vars& rm) {
const rational v = abs(vvr(rm));
const auto& key = lex_sorted[i].first;
TRACE("nla_solver", tout << "rm = ";
print_rooted_monomial_with_vars(rm, tout); tout << "i = " << i << std::endl;);
TRACE("nla_solver", tout << "rm = " << rm << "i = " << i << std::endl;);
for (unsigned k = i + 1; k < lex_sorted.size(); k++) {
const auto& p = lex_sorted[k];
const rooted_mon& rmk = c().m_rm_table.rms()[p.second];
const signed_vars& rmk = c().m_emons.canonical[p.second];
const rational vk = abs(vvr(rmk));
TRACE("nla_solver", tout << "rmk = ";
print_rooted_monomial_with_vars(rmk, tout);
tout << "\n";
TRACE("nla_solver", tout << "rmk = " << rmk << "\n";
tout << "vk = " << vk << std::endl;);
if (vk > v) continue;
unsigned strict;
@ -64,19 +61,16 @@ bool monotone::monotonicity_lemma_on_lex_sorted_rm_upper(const vector<std::pair<
return false;
}
bool monotone::monotonicity_lemma_on_lex_sorted_rm_lower(const vector<std::pair<std::vector<rational>, unsigned>>& lex_sorted, unsigned i, const rooted_mon& rm) {
bool monotone::monotonicity_lemma_on_lex_sorted_rm_lower(const vector<std::pair<std::vector<rational>, unsigned>>& lex_sorted, unsigned i, const signed_vars& rm) {
const rational v = abs(vvr(rm));
const auto& key = lex_sorted[i].first;
TRACE("nla_solver", tout << "rm = ";
print_rooted_monomial_with_vars(rm, tout); tout << "i = " << i << std::endl;);
TRACE("nla_solver", tout << "rm = " << rm << "i = " << i << std::endl;);
for (unsigned k = i; k-- > 0;) {
const auto& p = lex_sorted[k];
const rooted_mon& rmk = c().m_rm_table.rms()[p.second];
const signed_vars& rmk = c().m_emons.canonical[p.second];
const rational vk = abs(vvr(rmk));
TRACE("nla_solver", tout << "rmk = ";
print_rooted_monomial_with_vars(rmk, tout);
tout << "\n";
TRACE("nla_solver", tout << "rmk = " << rmk << "\n";
tout << "vk = " << vk << std::endl;);
if (vk < v) continue;
unsigned strict;
@ -98,22 +92,22 @@ bool monotone::monotonicity_lemma_on_lex_sorted_rm_lower(const vector<std::pair<
return false;
}
bool monotone::monotonicity_lemma_on_lex_sorted_rm(const vector<std::pair<std::vector<rational>, unsigned>>& lex_sorted, unsigned i, const rooted_mon& rm) {
bool monotone::monotonicity_lemma_on_lex_sorted_rm(const vector<std::pair<std::vector<rational>, unsigned>>& lex_sorted, unsigned i, const signed_vars& rm) {
return monotonicity_lemma_on_lex_sorted_rm_upper(lex_sorted, i, rm)
|| monotonicity_lemma_on_lex_sorted_rm_lower(lex_sorted, i, rm);
}
bool monotone::monotonicity_lemma_on_lex_sorted(const vector<std::pair<std::vector<rational>, unsigned>>& lex_sorted) {
for (unsigned i = 0; i < lex_sorted.size(); i++) {
unsigned rmi = lex_sorted[i].second;
const rooted_mon& rm = c().m_rm_table.rms()[rmi];
TRACE("nla_solver", print_rooted_monomial(rm, tout); tout << "\n, rm_check = " << c().rm_check(rm); tout << std::endl;);
const signed_vars& rm = c().m_emons.canonical[rmi];
TRACE("nla_solver", tout << rm << "\n, rm_check = " << c().rm_check(rm); tout << std::endl;);
if ((!c().rm_check(rm)) && monotonicity_lemma_on_lex_sorted_rm(lex_sorted, i, rm))
return true;
}
return false;
}
vector<std::pair<rational, lpvar>> monotone::get_sorted_key_with_vars(const rooted_mon& a) const {
vector<std::pair<rational, lpvar>> monotone::get_sorted_key_with_vars(const signed_vars& a) const {
vector<std::pair<rational, lpvar>> r;
for (lpvar j : a.vars()) {
r.push_back(std::make_pair(abs(vvr(j)), j));
@ -143,8 +137,8 @@ void monotone::negate_abs_a_le_abs_b(lpvar a, lpvar b, bool strict) {
}
// strict version
void monotone::generate_monl_strict(const rooted_mon& a,
const rooted_mon& b,
void monotone::generate_monl_strict(const signed_vars& a,
const signed_vars& b,
unsigned strict) {
add_empty_lemma();
auto akey = get_sorted_key_with_vars(a);
@ -165,8 +159,8 @@ void monotone::generate_monl_strict(const rooted_mon& a,
}
void monotone::assert_abs_val_a_le_abs_var_b(
const rooted_mon& a,
const rooted_mon& b,
const signed_vars& a,
const signed_vars& b,
bool strict) {
lpvar aj = var(a);
lpvar bj = var(b);
@ -194,11 +188,11 @@ void monotone::negate_abs_a_lt_abs_b(lpvar a, lpvar b) {
// not a strict version
void monotone::generate_monl(const rooted_mon& a,
const rooted_mon& b) {
TRACE("nla_solver", tout <<
"a = "; print_rooted_monomial_with_vars(a, tout) << "\n:";
tout << "b = "; print_rooted_monomial_with_vars(a, tout) << "\n:";);
void monotone::generate_monl(const signed_vars& a,
const signed_vars& b) {
TRACE("nla_solver",
tout << "a = " << a << "\n:";
tout << "b = " << b << "\n:";);
add_empty_lemma();
auto akey = get_sorted_key_with_vars(a);
auto bkey = get_sorted_key_with_vars(b);
@ -212,7 +206,7 @@ void monotone::generate_monl(const rooted_mon& a,
TRACE("nla_solver", print_lemma(tout););
}
std::vector<rational> monotone::get_sorted_key(const rooted_mon& rm) const {
std::vector<rational> monotone::get_sorted_key(const signed_vars& rm) const {
std::vector<rational> r;
for (unsigned j : rm.vars()) {
r.push_back(abs(vvr(j)));
@ -224,7 +218,7 @@ std::vector<rational> monotone::get_sorted_key(const rooted_mon& rm) const {
bool monotone::monotonicity_lemma_on_rms_of_same_arity(const unsigned_vector& rms) {
vector<std::pair<std::vector<rational>, unsigned>> lex_sorted;
for (unsigned i : rms) {
lex_sorted.push_back(std::make_pair(get_sorted_key(c().m_rm_table.rms()[i]), i));
lex_sorted.push_back(std::make_pair(get_sorted_key(c().m_emons.canonical[i]), i));
}
std::sort(lex_sorted.begin(), lex_sorted.end(),
[](const std::pair<std::vector<rational>, unsigned> &a,
@ -237,10 +231,10 @@ bool monotone::monotonicity_lemma_on_rms_of_same_arity(const unsigned_vector& rm
void monotone::monotonicity_lemma() {
unsigned shift = random();
unsigned size = c().m_rm_table.m_to_refine.size();
unsigned size = c().m_to_refine.size();
for(unsigned i = 0; i < size && !done(); i++) {
unsigned rm_i = c().m_rm_table.m_to_refine[(i + shift)% size];
monotonicity_lemma(c().m_rm_table.rms()[rm_i].orig_index());
lpvar v = c().m_to_refine[(i + shift) % size];
monotonicity_lemma(c().m_emons[v]);
}
}
@ -257,8 +251,7 @@ void monotone::monotonicity_lemma() {
#endif
void monotone::monotonicity_lemma(unsigned i_mon) {
const monomial & m = c().m_monomials[i_mon];
void monotone::monotonicity_lemma(monomial const& m) {
SASSERT(!check_monomial(m));
if (c().mon_has_zero(m))
return;

View file

@ -19,26 +19,26 @@
--*/
#pragma once
namespace nla {
struct core;
class core;
struct monotone: common {
monotone(core *core);
void print_monotone_array(const vector<std::pair<std::vector<rational>, unsigned>>& lex_sorted,
std::ostream& out) const;
bool monotonicity_lemma_on_lex_sorted_rm_upper(const vector<std::pair<std::vector<rational>, unsigned>>& lex_sorted, unsigned i, const rooted_mon& rm);
bool monotonicity_lemma_on_lex_sorted_rm_lower(const vector<std::pair<std::vector<rational>, unsigned>>& lex_sorted, unsigned i, const rooted_mon& rm);
bool monotonicity_lemma_on_lex_sorted_rm(const vector<std::pair<std::vector<rational>, unsigned>>& lex_sorted, unsigned i, const rooted_mon& rm);
bool monotonicity_lemma_on_lex_sorted_rm_upper(const vector<std::pair<std::vector<rational>, unsigned>>& lex_sorted, unsigned i, const signed_vars& rm);
bool monotonicity_lemma_on_lex_sorted_rm_lower(const vector<std::pair<std::vector<rational>, unsigned>>& lex_sorted, unsigned i, const signed_vars& rm);
bool monotonicity_lemma_on_lex_sorted_rm(const vector<std::pair<std::vector<rational>, unsigned>>& lex_sorted, unsigned i, const signed_vars& rm);
bool monotonicity_lemma_on_lex_sorted(const vector<std::pair<std::vector<rational>, unsigned>>& lex_sorted);
bool monotonicity_lemma_on_rms_of_same_arity(const unsigned_vector& rms);
void monotonicity_lemma();
void monotonicity_lemma(unsigned i_mon);
void monotonicity_lemma(monomial const& m);
void monotonicity_lemma_gt(const monomial& m, const rational& prod_val);
void monotonicity_lemma_lt(const monomial& m, const rational& prod_val);
void generate_monl_strict(const rooted_mon& a, const rooted_mon& b, unsigned strict);
void generate_monl(const rooted_mon& a, const rooted_mon& b);
std::vector<rational> get_sorted_key(const rooted_mon& rm) const;
vector<std::pair<rational, lpvar>> get_sorted_key_with_vars(const rooted_mon& a) const;
void generate_monl_strict(const signed_vars& a, const signed_vars& b, unsigned strict);
void generate_monl(const signed_vars& a, const signed_vars& b);
std::vector<rational> get_sorted_key(const signed_vars& rm) const;
vector<std::pair<rational, lpvar>> get_sorted_key_with_vars(const signed_vars& a) const;
void negate_abs_a_le_abs_b(lpvar a, lpvar b, bool strict);
void negate_abs_a_lt_abs_b(lpvar a, lpvar b);
void assert_abs_val_a_le_abs_var_b(const rooted_mon& a, const rooted_mon& b, bool strict);
void assert_abs_val_a_le_abs_var_b(const signed_vars& a, const signed_vars& b, bool strict);
};
}

View file

@ -29,38 +29,35 @@ namespace nla {
// a >< b && c < 0 => ac <> bc
// ac[k] plays the role of c
bool order::order_lemma_on_ac_and_bc(const rooted_mon& rm_ac,
bool order::order_lemma_on_ac_and_bc(const signed_vars& rm_ac,
const factorization& ac_f,
unsigned k,
const rooted_mon& rm_bd) {
TRACE("nla_solver", tout << "rm_ac = ";
c().print_rooted_monomial(rm_ac, tout);
tout << "\nrm_bd = ";
c().print_rooted_monomial(rm_bd, tout);
tout << "\nac_f[k] = ";
const signed_vars& rm_bd) {
TRACE("nla_solver",
tout << "rm_ac = " << rm_ac << "\n";
tout << "rm_bd = " << rm_bd << "\n";
tout << "ac_f[k] = ";
c().print_factor_with_vars(ac_f[k], tout););
factor b;
if (!c().divide(rm_bd, ac_f[k], b)){
return false;
}
return order_lemma_on_ac_and_bc_and_factors(rm_ac, ac_f[(k + 1) % 2], ac_f[k], rm_bd, b);
return
c().divide(rm_bd, ac_f[k], b) &&
order_lemma_on_ac_and_bc_and_factors(rm_ac, ac_f[(k + 1) % 2], ac_f[k], rm_bd, b);
}
bool order::order_lemma_on_ac_explore(const rooted_mon& rm, const factorization& ac, unsigned k) {
bool order::order_lemma_on_ac_explore(const signed_vars& rm, const factorization& ac, unsigned k) {
const factor c = ac[k];
TRACE("nla_solver", tout << "c = "; _().print_factor_with_vars(c, tout); );
if (c.is_var()) {
TRACE("nla_solver", tout << "var(c) = " << var(c););
for (unsigned rm_bc : _().m_rm_table.var_map()[c.index()]) {
TRACE("nla_solver", );
if (order_lemma_on_ac_and_bc(rm ,ac, k, _().m_rm_table.rms()[rm_bc])) {
for (monomial const& bc : _().m_emons.get_use_list(c.var())) {
if (order_lemma_on_ac_and_bc(rm ,ac, k, _().m_emons.canonical[bc])) {
return true;
}
}
} else {
for (unsigned rm_bc : _().m_rm_table.proper_multiples()[c.index()]) {
if (order_lemma_on_ac_and_bc(rm , ac, k, _().m_rm_table.rms()[rm_bc])) {
}
else {
for (monomial const& bc : _().m_emons.get_factors_of(c.var())) {
if (order_lemma_on_ac_and_bc(rm , ac, k, _().m_emons.canonical[bc])) {
return true;
}
}
@ -68,11 +65,11 @@ bool order::order_lemma_on_ac_explore(const rooted_mon& rm, const factorization&
return false;
}
void order::order_lemma_on_factorization(const rooted_mon& rm, const factorization& ab) {
const monomial& m = _().m_monomials[rm.orig_index()];
TRACE("nla_solver", tout << "orig_sign = " << rm.orig_sign() << "\n";);
rational sign = rm.orig_sign();
for(factor f: ab)
void order::order_lemma_on_factorization(const signed_vars& rm, const factorization& ab) {
const monomial& m = _().m_emons[rm.var()];
TRACE("nla_solver", tout << "orig_sign = " << _().m_emons.orig_sign(rm) << "\n";);
rational sign = _().m_emons.orig_sign(rm);
for (factor f: ab)
sign *= _().canonize_sign(f);
const rational & fv = vvr(ab[0]) * vvr(ab[1]);
const rational mv = sign * vvr(m);
@ -93,11 +90,11 @@ void order::order_lemma_on_factorization(const rooted_mon& rm, const factorizati
}
// |c_sign| = 1, and c*c_sign > 0
// ac > bc => ac/|c| > bc/|c| => a*c_sign > b*c_sign
void order::generate_ol(const rooted_mon& ac,
void order::generate_ol(const signed_vars& ac,
const factor& a,
int c_sign,
const factor& c,
const rooted_mon& bc,
const signed_vars& bc,
const factor& b,
llc ab_cmp) {
add_empty_lemma();
@ -117,7 +114,7 @@ void order::generate_mon_ol(const monomial& ac,
lpvar a,
const rational& c_sign,
lpvar c,
const rooted_mon& bd,
const signed_vars& bd,
const factor& b,
const rational& d_sign,
lpvar d,
@ -142,22 +139,19 @@ void order::negate_var_factor_relation(const rational& a_sign, lpvar a, const ra
void order::order_lemma() {
TRACE("nla_solver", );
c().init_rm_to_refine();
const auto& rm_ref = c().m_rm_table.to_refine();
unsigned start = random() % rm_ref.size();
unsigned i = start;
do {
const rooted_mon& rm = c().m_rm_table.rms()[rm_ref[i]];
const auto& rm_ref = c().m_to_refine;
unsigned start = random();
unsigned sz = rm_ref.size();
for (unsigned i = sz; i-- > 0 && !done(); ) {
const signed_vars& rm = c().m_emons.canonical[rm_ref[(i + start) % sz]];
order_lemma_on_rmonomial(rm);
if (++i == rm_ref.size()) {
i = 0;
}
} while(i != start && !done());
}
}
bool order::order_lemma_on_ac_and_bc_and_factors(const rooted_mon& ac,
bool order::order_lemma_on_ac_and_bc_and_factors(const signed_vars& ac,
const factor& a,
const factor& c,
const rooted_mon& bc,
const signed_vars& bc,
const factor& b) {
auto cv = vvr(c);
int c_sign = nla::rat_sign(cv);
@ -239,10 +233,10 @@ void order::order_lemma_on_ab(const monomial& m, const rational& sign, lpvar a,
order_lemma_on_ab_lt(m, sign, a, b);
}
// a > b && c > 0 => ac > bc
void order::order_lemma_on_rmonomial(const rooted_mon& rm) {
void order::order_lemma_on_rmonomial(const signed_vars& rm) {
TRACE("nla_solver_details",
tout << "rm = "; print_product(rm, tout);
tout << ", orig = "; print_monomial(c().m_monomials[rm.orig_index()], tout);
tout << ", orig = " << c().m_emons[rm.var()] << "\n";
);
for (auto ac : factorization_factory_imp(rm, c())) {
if (ac.size() != 2)
@ -273,17 +267,18 @@ void order::order_lemma_on_binomial_sign(const monomial& ac, lpvar x, lpvar y, i
mk_ineq(ac.var(), - vvr(x), y, sign == 1?llc::LE:llc::GE);
TRACE("nla_solver", print_lemma(tout););
}
void order::order_lemma_on_factor_binomial_rm(const monomial& ac, unsigned k, const rooted_mon& rm_bd) {
void order::order_lemma_on_factor_binomial_rm(const monomial& ac, unsigned k, const monomial& bd) {
signed_vars const& rm_bd = _().m_emons.canonical[bd];
factor d(_().m_evars.find(ac[k]).var(), factor_type::VAR);
factor b;
if (!_().divide(rm_bd, d, b))
return;
order_lemma_on_binomial_ac_bd(ac, k, rm_bd, b, d.index());
if (_().divide(rm_bd, d, b)) {
order_lemma_on_binomial_ac_bd(ac, k, rm_bd, b, d.var());
}
}
void order::order_lemma_on_binomial_ac_bd(const monomial& ac, unsigned k, const rooted_mon& bd, const factor& b, lpvar d) {
void order::order_lemma_on_binomial_ac_bd(const monomial& ac, unsigned k, const signed_vars& bd, const factor& b, lpvar d) {
TRACE("nla_solver", print_monomial(ac, tout << "ac=");
print_rooted_monomial(bd, tout << "\nrm=");
tout << "\nrm=" << bd;
print_factor(b, tout << ", b="); print_var(d, tout << ", d=") << "\n";);
int p = (k + 1) % 2;
lpvar a = ac[p];
@ -309,14 +304,12 @@ void order::order_lemma_on_binomial_ac_bd(const monomial& ac, unsigned k, const
void order::order_lemma_on_factor_binomial_explore(const monomial& m, unsigned k) {
SASSERT(m.size() == 2);
lpvar c = m[k];
lpvar d = _().m_evars.find(c).var();
auto it = _().m_rm_table.var_map().find(d);
SASSERT(it != _().m_rm_table.var_map().end());
for (unsigned bd_i : it->second) {
order_lemma_on_factor_binomial_rm(m, k, _().m_rm_table.rms()[bd_i]);
if (done())
for (monomial const& m2 : _().m_emons.get_factors_of(c)) {
order_lemma_on_factor_binomial_rm(m, k, m2);
if (done()) {
break;
}
}
}
}
void order::order_lemma_on_binomial(const monomial& ac) {

View file

@ -23,29 +23,29 @@
#include "util/lp/nla_common.h"
namespace nla {
struct core;
class core;
struct order: common {
core& _() { return *m_core; }
const core& _() const { return *m_core; }
//constructor
order(core *c) : common(c) {}
bool order_lemma_on_ac_and_bc_and_factors(const rooted_mon& ac,
bool order_lemma_on_ac_and_bc_and_factors(const signed_vars& ac,
const factor& a,
const factor& c,
const rooted_mon& bc,
const signed_vars& bc,
const factor& b);
// a >< b && c > 0 => ac >< bc
// a >< b && c < 0 => ac <> bc
// ac[k] plays the role of c
bool order_lemma_on_ac_and_bc(const rooted_mon& rm_ac,
bool order_lemma_on_ac_and_bc(const signed_vars& rm_ac,
const factorization& ac_f,
unsigned k,
const rooted_mon& rm_bd);
const signed_vars& rm_bd);
bool order_lemma_on_ac_explore(const rooted_mon& rm, const factorization& ac, unsigned k);
bool order_lemma_on_ac_explore(const signed_vars& rm, const factorization& ac, unsigned k);
void order_lemma_on_factorization(const rooted_mon& rm, const factorization& ab);
void order_lemma_on_factorization(const signed_vars& rm, const factorization& ab);
/**
\brief Add lemma:
@ -62,20 +62,20 @@ struct order: common {
void order_lemma_on_ab_lt(const monomial& m, const rational& sign, lpvar a, lpvar b);
void order_lemma_on_ab(const monomial& m, const rational& sign, lpvar a, lpvar b, bool gt);
void order_lemma_on_factor_binomial_explore(const monomial& m, unsigned k);
void order_lemma_on_factor_binomial_rm(const monomial& ac, unsigned k, const rooted_mon& rm_bd);
void order_lemma_on_binomial_ac_bd(const monomial& ac, unsigned k, const rooted_mon& bd, const factor& b, lpvar d);
void order_lemma_on_factor_binomial_rm(const monomial& ac, unsigned k, const monomial& bd);
void order_lemma_on_binomial_ac_bd(const monomial& ac, unsigned k, const signed_vars& bd, const factor& b, lpvar d);
void order_lemma_on_binomial_k(const monomial& m, lpvar k, bool gt);
void order_lemma_on_binomial_sign(const monomial& ac, lpvar x, lpvar y, int sign);
void order_lemma_on_binomial(const monomial& ac);
void order_lemma_on_rmonomial(const rooted_mon& rm);
void order_lemma_on_rmonomial(const signed_vars& rm);
void order_lemma();
// |c_sign| = 1, and c*c_sign > 0
// ac > bc => ac/|c| > bc/|c| => a*c_sign > b*c_sign
void generate_ol(const rooted_mon& ac,
void generate_ol(const signed_vars& ac,
const factor& a,
int c_sign,
const factor& c,
const rooted_mon& bc,
const signed_vars& bc,
const factor& b,
llc ab_cmp);
@ -83,7 +83,7 @@ struct order: common {
lpvar a,
const rational& c_sign,
lpvar c,
const rooted_mon& bd,
const signed_vars& bd,
const factor& b,
const rational& d_sign,
lpvar d,

View file

@ -28,8 +28,8 @@
namespace nla {
// returns the monomial index
unsigned solver::add_monomial(lpvar v, unsigned sz, lpvar const* vs) {
return m_core->add(v, sz, vs);
void solver::add_monomial(lpvar v, unsigned sz, lpvar const* vs) {
m_core->add(v, sz, vs);
}
bool solver::need_check() { return true; }

View file

@ -32,8 +32,7 @@ namespace nla {
class solver {
core* m_core;
public:
// returns the monomial index
unsigned add_monomial(lp::var_index v, unsigned sz, lp::var_index const* vs);
void add_monomial(lp::var_index v, unsigned sz, lp::var_index const* vs);
solver(lp::lar_solver& s, reslimit& lim, params_ref const& p);
~solver();

View file

@ -22,7 +22,6 @@
namespace nla {
template <typename T> rational tangents::vvr(T const& t) const { return m_core->vvr(t); }
template <typename T> lpvar tangents::var(T const& t) const { return m_core->var(t); }
tangents::tangents(core * c) : common(c) {}
std::ostream& tangents::print_point(const point &a, std::ostream& out) const {
@ -34,13 +33,12 @@ std::ostream& tangents::print_tangent_domain(const point &a, const point &b, std
out << "("; print_point(a, out); out << ", "; print_point(b, out); out << ")";
return out;
}
void tangents::generate_simple_tangent_lemma(const rooted_mon* rm) {
void tangents::generate_simple_tangent_lemma(const signed_vars* rm) {
if (rm->size() != 2)
return;
TRACE("nla_solver", tout << "rm:"; m_core->print_rooted_monomial_with_vars(*rm, tout) << std::endl;);
TRACE("nla_solver", tout << "rm:" << *rm << std::endl;);
m_core->add_empty_lemma();
unsigned i_mon = rm->orig_index();
const monomial & m = c().m_monomials[i_mon];
const monomial & m = c().m_emons[rm->var()];
const rational v = c().product_value(m);
const rational& mv = vvr(m);
SASSERT(mv != v);
@ -58,7 +56,7 @@ void tangents::generate_simple_tangent_lemma(const rooted_mon* rm) {
c().mk_ineq(js, j, llc::LT);
c().mk_ineq(js, j, llc::GT, jv);
}
c().mk_ineq(sign, i_mon, llc::LE, std::max(v, rational(-1)));
c().mk_ineq(sign, rm->var(), llc::LE, std::max(v, rational(-1)));
} else {
for (lpvar j : m) {
const rational & jv = vvr(j);
@ -75,7 +73,7 @@ void tangents::tangent_lemma() {
bfc bf;
lpvar j;
rational sign;
const rooted_mon* rm = nullptr;
const signed_vars* rm = nullptr;
if (c().find_bfc_to_refine(bf, j, sign, rm)) {
tangent_lemma_bf(bf, j, sign, rm);
@ -86,7 +84,7 @@ void tangents::tangent_lemma() {
}
}
void tangents::generate_explanations_of_tang_lemma(const rooted_mon& rm, const bfc& bf, lp::explanation& exp) {
void tangents::generate_explanations_of_tang_lemma(const signed_vars& rm, const bfc& bf, lp::explanation& exp) {
// here we repeat the same explanation for each lemma
c().explain(rm, exp);
c().explain(bf.m_x, exp);
@ -114,7 +112,7 @@ void tangents::generate_tang_plane(const rational & a, const rational& b, const
t.add_coeff_var( j_sign, j);
c().mk_ineq(t, sbelow? llc::GT : llc::LT, - a*b);
}
void tangents::tangent_lemma_bf(const bfc& bf, lpvar j, const rational& sign, const rooted_mon* rm){
void tangents::tangent_lemma_bf(const bfc& bf, lpvar j, const rational& sign, const signed_vars* rm){
point a, b;
point xy (vvr(bf.m_x), vvr(bf.m_y));
rational correct_mult_val = xy.x * xy.y;

View file

@ -24,7 +24,7 @@
#include "util/lp/nla_common.h"
namespace nla {
struct core;
class core;
struct tangents: common {
struct point {
rational x;
@ -47,13 +47,13 @@ struct tangents: common {
tangents(core *core);
void generate_simple_tangent_lemma(const rooted_mon* rm);
void generate_simple_tangent_lemma(const signed_vars* rm);
void tangent_lemma();
void generate_explanations_of_tang_lemma(const rooted_mon& rm, const bfc& bf, lp::explanation& exp);
void generate_explanations_of_tang_lemma(const signed_vars& rm, const bfc& bf, lp::explanation& exp);
void tangent_lemma_bf(const bfc& bf, lpvar j, const rational& sign, const rooted_mon* rm);
void tangent_lemma_bf(const bfc& bf, lpvar j, const rational& sign, const signed_vars* rm);
void generate_tang_plane(const rational & a, const rational& b, const factor& x, const factor& y, bool below, lpvar j, const rational& j_sign);
void generate_two_tang_lines(const bfc & bf, const point& xy, const rational& sign, lpvar j);
@ -76,6 +76,6 @@ struct tangents: common {
const rational & val,
bool below) const;
template <typename T> rational vvr(T const& t) const;
template <typename T> lpvar var(T const& t) const;
template <typename T> lpvar var(T const& t) const { return t.var(); }
}; // end of tangents
}