z3-z3-4.13.0.src.ast.simplifiers.linear_equation.cpp Maven / Gradle / Ivy
The newest version!
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
linear_equation.cpp
Abstract:
Basic infrastructure for managing linear equations of the form:
a_1 * x_1 + ... + a_n * x_n = 0
Author:
Leonardo de Moura (leonardo) 2011-06-28
Revision History:
--*/
#include "ast/simplifiers/linear_equation.h"
/**
\brief Return the position of variable x_i in the linear equation.
Return UINT_MAX, if the variable is not in the linear_equation.
*/
unsigned linear_equation::pos(unsigned x_i) const {
int low = 0;
int high = m_size - 1;
while (true) {
int mid = low + ((high - low) / 2);
var x_mid = m_xs[mid];
if (x_i > x_mid) {
low = mid + 1;
if (low > high)
return UINT_MAX;
}
else if (x_i < x_mid) {
high = mid - 1;
if (low > high)
return UINT_MAX;
}
else {
return mid;
}
}
}
void linear_equation_manager::display(std::ostream & out, linear_equation const & eq) const {
unsigned sz = eq.m_size;
for (unsigned i = 0; i < sz; i++) {
if (i > 0)
out << " + ";
out << m.to_string(eq.m_as[i]) << "*x" << eq.m_xs[i];
}
out << " = 0";
}
linear_equation * linear_equation_manager::mk(unsigned sz, mpq * as, var * xs, bool normalized) {
SASSERT(sz > 1);
// compute lcm of the denominators
mpz l;
mpz r;
m.set(l, as[0].denominator());
for (unsigned i = 1; i < sz; i++) {
m.set(r, as[i].denominator());
m.lcm(r, l, l);
}
TRACE("linear_equation_mk", tout << "lcm: " << m.to_string(l) << "\n";);
// copy l * as to m_int_buffer.
m_int_buffer.reset();
for (unsigned i = 0; i < sz; i++) {
TRACE("linear_equation_mk", tout << "before as[" << i << "]: " << m.to_string(as[i]) << "\n";);
m.mul(l, as[i], as[i]);
TRACE("linear_equation_mk", tout << "after as[" << i << "]: " << m.to_string(as[i]) << "\n";);
SASSERT(m.is_int(as[i]));
m_int_buffer.push_back(as[i].numerator());
}
linear_equation * new_eq = mk(sz, m_int_buffer.data(), xs, normalized);
m.del(r);
m.del(l);
return new_eq;
}
linear_equation * linear_equation_manager::mk_core(unsigned sz, mpz * as, var * xs) {
SASSERT(sz > 0);
DEBUG_CODE({
for (unsigned i = 1; i < sz; i++) {
SASSERT(xs[i-1] < xs[i]);
}
});
TRACE("linear_equation_bug", for (unsigned i = 0; i < sz; i++) tout << m.to_string(as[i]) << "*x" << xs[i] << " "; tout << "\n";);
mpz g;
m.set(g, as[0]);
for (unsigned i = 1; i < sz; i++) {
if (m.is_one(g))
break;
if (m.is_neg(as[i])) {
m.neg(as[i]);
m.gcd(g, as[i], g);
m.neg(as[i]);
}
else {
m.gcd(g, as[i], g);
}
}
if (!m.is_one(g)) {
for (unsigned i = 0; i < sz; i++) {
m.div(as[i], g, as[i]);
}
}
TRACE("linear_equation_bug",
tout << "g: " << m.to_string(g) << "\n";
for (unsigned i = 0; i < sz; i++) tout << m.to_string(as[i]) << "*x" << xs[i] << " "; tout << "\n";);
m.del(g);
unsigned obj_sz = linear_equation::get_obj_size(sz);
void * mem = m_allocator.allocate(obj_sz);
linear_equation * new_eq = new (mem) linear_equation();
mpz * new_as = reinterpret_cast(reinterpret_cast(new_eq) + sizeof(linear_equation));
double * new_app_as = reinterpret_cast(reinterpret_cast(new_as) + sz * sizeof(mpz));
var * new_xs = reinterpret_cast(reinterpret_cast(new_app_as) + sz * sizeof(double));
for (unsigned i = 0; i < sz; i++) {
new (new_as + i) mpz();
m.set(new_as[i], as[i]);
new_app_as[i] = m.get_double(as[i]);
var x_i = xs[i];
new_xs[i] = x_i;
}
new_eq->m_size = sz;
new_eq->m_as = new_as;
new_eq->m_approx_as = new_app_as;
new_eq->m_xs = new_xs;
return new_eq;
}
linear_equation * linear_equation_manager::mk(unsigned sz, mpz * as, var * xs, bool normalized) {
if (!normalized) {
for (unsigned i = 0; i < sz; i++) {
var x = xs[i];
m_mark.reserve(x+1, false);
m_val_buffer.reserve(x+1);
if (m_mark[x]) {
m.add(m_val_buffer[x], as[i], m_val_buffer[x]);
}
else {
m.set(m_val_buffer[x], as[i]);
m_mark[x] = true;
}
}
unsigned j = 0;
for (unsigned i = 0; i < sz; i++) {
var x = xs[i];
if (m_mark[x]) {
if (!m.is_zero(m_val_buffer[x])) {
xs[j] = xs[i];
m.set(as[j], m_val_buffer[x]);
j++;
}
m_mark[x] = false;
}
}
sz = j;
if (sz <= 1)
return nullptr;
}
else {
DEBUG_CODE({
for (unsigned i = 0; i < sz; i++) {
var x = xs[i];
m_mark.reserve(x+1, false);
SASSERT(!m_mark[x]);
m_mark[x] = true;
}
for (unsigned i = 0; i < sz; i++) {
var x = xs[i];
m_mark[x] = false;
}
});
}
for (unsigned i = 0; i < sz; i++) {
var x = xs[i];
m_val_buffer.reserve(x+1);
m.swap(m_val_buffer[x], as[i]);
}
std::sort(xs, xs+sz);
for (unsigned i = 0; i < sz; i++) {
var x = xs[i];
m.swap(as[i], m_val_buffer[x]);
}
return mk_core(sz, as, xs);
}
linear_equation * linear_equation_manager::mk(mpz const & b1, linear_equation const & eq1, mpz const & b2, linear_equation const & eq2) {
SASSERT(!m.is_zero(b1));
SASSERT(!m.is_zero(b2));
mpz tmp, new_a;
m_int_buffer.reset();
m_var_buffer.reset();
unsigned sz1 = eq1.size();
unsigned sz2 = eq2.size();
unsigned i1 = 0;
unsigned i2 = 0;
while (true) {
if (i1 == sz1) {
// copy remaining entries from eq2
while (i2 < sz2) {
m_int_buffer.push_back(eq2.a(i2));
m.mul(m_int_buffer.back(), b2, m_int_buffer.back());
m_var_buffer.push_back(eq2.x(i2));
i2++;
}
break;
}
if (i2 == sz2) {
// copy remaining entries from eq1
while (i1 < sz1) {
m_int_buffer.push_back(eq1.a(i1));
m.mul(m_int_buffer.back(), b1, m_int_buffer.back());
m_var_buffer.push_back(eq1.x(i1));
i1++;
}
break;
}
var x1 = eq1.x(i1);
var x2 = eq2.x(i2);
if (x1 < x2) {
m_int_buffer.push_back(eq1.a(i1));
m.mul(m_int_buffer.back(), b1, m_int_buffer.back());
m_var_buffer.push_back(eq1.x(i1));
i1++;
}
else if (x1 > x2) {
m_int_buffer.push_back(eq2.a(i2));
m.mul(m_int_buffer.back(), b2, m_int_buffer.back());
m_var_buffer.push_back(eq2.x(i2));
i2++;
}
else {
m.mul(eq1.a(i1), b1, tmp);
m.addmul(tmp, b2, eq2.a(i2), new_a);
if (!m.is_zero(new_a)) {
m_int_buffer.push_back(new_a);
m_var_buffer.push_back(eq1.x(i1));
}
i1++;
i2++;
}
}
m.del(tmp);
m.del(new_a);
SASSERT(m_int_buffer.size() == m_var_buffer.size());
if (m_int_buffer.empty())
return nullptr;
return mk_core(m_int_buffer.size(), m_int_buffer.data(), m_var_buffer.data());
}
void linear_equation_manager::del(linear_equation * eq) {
for (unsigned i = 0; i < eq->m_size; i++) {
m.del(eq->m_as[i]);
}
unsigned obj_sz = linear_equation::get_obj_size(eq->m_size);
m_allocator.deallocate(obj_sz, eq);
}