3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-01-21 09:34:43 +00:00

add option to propagation quotients

for equations x*y + z = 0,
with x, y, z integer, enforce that x divides z
It is (currently) enabled within Grobner completion
and applied partially to x a variable, z linear, and
only when |z| < |x|.
This commit is contained in:
Nikolaj Bjorner 2025-08-31 14:41:23 -07:00
parent 91b4873b79
commit e91e432496
10 changed files with 516 additions and 258 deletions

319
src/math/lp/nla_pp.cpp Normal file
View file

@ -0,0 +1,319 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
nla_core.cpp
Author:
Lev Nachmanson (levnach)
Nikolaj Bjorner (nbjorner)
--*/
#include "math/lp/nla_core.h"
using namespace nla;
template <typename T>
std::ostream& core::print_product(const T& m, std::ostream& out) const {
bool first = true;
for (lpvar v : m) {
if (!first)
out << "*";
else
first = false;
if (lp_settings().print_external_var_name())
out << "(" << lra.get_variable_name(v) << "=" << val(v) << ")";
else
out << "(j" << v << " = " << val(v) << ")";
}
return out;
}
template <typename T>
std::string core::product_indices_str(const T& m) const {
std::stringstream out;
bool first = true;
for (lpvar v : m) {
if (!first)
out << "*";
else
first = false;
out << "j" << v;
;
}
return out.str();
}
std::ostream& core::print_factor(const factor& f, std::ostream& out) const {
if (f.sign())
out << "- ";
if (f.is_var()) {
out << "VAR, " << pp(f.var());
} else {
out << "MON, v" << m_emons[f.var()] << " = ";
print_product(m_emons[f.var()].rvars(), out);
}
out << "\n";
return out;
}
std::ostream& core::print_factor_with_vars(const factor& f, std::ostream& out) const {
if (f.is_var()) {
out << pp(f.var());
} else {
out << " MON = " << pp_mon_with_vars(*this, m_emons[f.var()]);
}
return out;
}
std::ostream& core::print_monic(const monic& m, std::ostream& out) const {
if (lp_settings().print_external_var_name())
out << "([" << m.var() << "] = " << lra.get_variable_name(m.var()) << " = " << val(m.var()) << " = ";
else
out << "(j" << m.var() << " = " << val(m.var()) << " = ";
print_product(m.vars(), out) << ")\n";
return out;
}
std::ostream& core::print_bfc(const factorization& m, std::ostream& out) const {
SASSERT(m.size() == 2);
out << "( x = " << pp(m[0]) << "* y = " << pp(m[1]) << ")";
return out;
}
std::ostream& core::print_monic_with_vars(lpvar v, std::ostream& out) const {
return print_monic_with_vars(m_emons[v], out);
}
template <typename T>
std::ostream& core::print_product_with_vars(const T& m, std::ostream& out) const {
print_product(m, out) << "\n";
for (unsigned k = 0; k < m.size(); k++) {
print_var(m[k], out);
}
return out;
}
std::ostream& core::print_monic_with_vars(const monic& m, std::ostream& out) const {
out << "[" << pp(m.var()) << "]\n";
out << "vars:";
print_product_with_vars(m.vars(), out) << "\n";
if (m.vars() == m.rvars())
out << "same rvars, and m.rsign = " << m.rsign() << " of course\n";
else {
out << "rvars:";
print_product_with_vars(m.rvars(), out) << "\n";
out << "rsign:" << m.rsign() << "\n";
}
return out;
}
std::ostream& core::print_explanation(const lp::explanation& exp, std::ostream& out) const {
out << "expl: ";
unsigned i = 0;
for (auto p : exp) {
out << "(" << p.ci() << ")";
lra.constraints().display(out, [this](lpvar j) { return var_str(j); }, p.ci());
if (++i < exp.size())
out << " ";
}
return out;
}
std::ostream& core::print_ineq(const ineq& in, std::ostream& out) const {
lra.print_term_as_indices(in.term(), out);
return out << " " << lconstraint_kind_string(in.cmp()) << " " << in.rs();
}
std::ostream& core::print_var(lpvar j, std::ostream& out) const {
if (is_monic_var(j))
print_monic(m_emons[j], out);
lra.print_column_info(j, out);
signed_var jr = m_evars.find(j);
out << "root=";
if (jr.sign()) {
out << "-";
}
out << lra.get_variable_name(jr.var()) << "\n";
return out;
}
std::ostream& core::print_monics(std::ostream& out) const {
for (auto& m : m_emons) {
print_monic_with_vars(m, out);
}
return out;
}
std::ostream& core::print_ineqs(const lemma& l, std::ostream& out) const {
std::unordered_set<lpvar> vars;
out << "ineqs: ";
if (l.ineqs().size() == 0) {
out << "conflict\n";
} else {
for (unsigned i = 0; i < l.ineqs().size(); i++) {
auto& in = l.ineqs()[i];
print_ineq(in, out);
if (i + 1 < l.ineqs().size()) out << " or ";
for (lp::lar_term::ival p : in.term())
vars.insert(p.j());
}
out << std::endl;
for (lpvar j : vars) {
print_var(j, out);
}
out << "\n";
}
return out;
}
std::ostream& core::print_factorization(const factorization& f, std::ostream& out) const {
if (f.is_mon()) {
out << "is_mon " << pp_mon(*this, f.mon());
} else {
for (unsigned k = 0; k < f.size(); k++) {
out << "(" << pp(f[k]) << ")";
if (k < f.size() - 1)
out << "*";
}
}
return out;
}
void core::trace_print_monic_and_factorization(const monic& rm, const factorization& f, std::ostream& out) const {
out << "rooted vars: ";
print_product(rm.rvars(), out) << "\n";
out << "mon: " << pp_mon(*this, rm.var()) << "\n";
out << "value: " << var_val(rm) << "\n";
print_factorization(f, out << "fact: ") << "\n";
}
template <typename T>
void core::trace_print_rms(const T& p, std::ostream& out) {
out << "p = {\n";
for (auto j : p) {
out << "j = " << j << ", rm = " << m_emons[j] << "\n";
}
out << "}";
}
void core::print_monic_stats(const monic& m, std::ostream& out) {
if (m.size() == 2) return;
monic_coeff mc = canonize_monic(m);
for (unsigned i = 0; i < mc.vars().size(); i++) {
if (abs(val(mc.vars()[i])) == rational(1)) {
auto vv = mc.vars();
vv.erase(vv.begin() + i);
monic const* sv = m_emons.find_canonical(vv);
if (!sv) {
out << "nf length" << vv.size() << "\n";
;
}
}
}
}
void core::print_stats(std::ostream& out) {
}
std::ostream& core::print_terms(std::ostream& out) const {
for (const auto* t : lra.terms()) {
out << "term:";
print_term(*t, out) << std::endl;
print_var(t->j(), out);
}
return out;
}
std::ostream& core::print_term(const lp::lar_term& t, std::ostream& out) const {
return lp::print_linear_combination_customized(
t.coeffs_as_vector(),
[this](lpvar j) { return var_str(j); },
out);
}
std::string core::var_str(lpvar j) const {
std::string result;
if (is_monic_var(j))
result += product_indices_str(m_emons[j].vars()) + (check_monic(m_emons[j]) ? "" : "_");
else
result += std::string("j") + lp::T_to_string(j);
// result += ":w" + lp::T_to_string(get_var_weight(j));
return result;
}
std::ostream& core::display_row(std::ostream& out, lp::row_strip<lp::mpq> const& row) const {
auto display_coeff = [&](bool first, lp::mpq const& p) {
if (first && p == 1)
return;
if (first && p > 0)
out << p;
else if (p == 1)
out << " + ";
else if (p > 0)
out << " + " << p << " * ";
else if (p == -1)
out << " - ";
else if (first)
out << p << " * ";
else
out << " - " << -p << " * ";
};
auto display_var = [&](bool first, lp::mpq p, lp::lpvar v) {
if (is_monic_var(v)) {
for (auto w : m_emons[v].vars())
p *= m_evars.find(w).rsign();
}
else
p *= m_evars.find(v).rsign();
display_coeff(first, p);
if (is_monic_var(v)) {
bool first = true;
for (auto w : m_emons[v].vars())
out << (first ? (first = false, "") : " * ") << "j" << m_evars.find(w).var();
}
else
out << "j" << m_evars.find(v).var();
};
bool first = true;
for (auto const& ri : row) {
auto v = ri.var();
if (lra.column_is_fixed(v)) {
auto q = lra.get_column_value(v).x;
if (q == 0)
continue;
q = q * ri.coeff();
if (first)
out << q;
else if (q > 0)
out << " + " << q;
else if (q < 0)
out << " - " << -q;
}
else if (lra.column_has_term(v)) {
auto const& t = lra.get_term(v);
for (lp::lar_term::ival p : t) {
display_var(first, p.coeff() * ri.coeff(), p.j());
first = false;
}
}
else {
display_var(first, ri.coeff(), ri.var());
}
first = false;
}
out << " = 0\n";
return out;
}
std::ostream& core::display(std::ostream& out) {
print_monics(out);
for (unsigned i = 0; i < lra.row_count(); ++i)
display_row(out, lra.get_row(i));
return out;
}