mirror of
https://github.com/Z3Prover/z3
synced 2025-04-10 11:17:07 +00:00
801 lines
27 KiB
C++
801 lines
27 KiB
C++
/*++
|
|
Copyright (c) 2012 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
rpolynomial.cpp
|
|
|
|
Abstract:
|
|
|
|
Goodies for creating and handling polynomials in dense recursive representation.
|
|
|
|
Author:
|
|
|
|
Leonardo (leonardo) 2012-06-11
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
#include"rpolynomial.h"
|
|
#include"tptr.h"
|
|
#include"buffer.h"
|
|
|
|
namespace rpolynomial {
|
|
|
|
typedef void poly_or_num;
|
|
|
|
inline bool is_poly(poly_or_num * p) { return GET_TAG(p) == 0; }
|
|
inline bool is_num(poly_or_num * p) { return GET_TAG(p) == 1; }
|
|
polynomial * to_poly(poly_or_num * p) { SASSERT(is_poly(p)); return UNTAG(polynomial*, p); }
|
|
manager::numeral * to_num_ptr(poly_or_num * p) { SASSERT(is_num(p)); return (UNTAG(manager::numeral *, p)); }
|
|
manager::numeral & to_num(poly_or_num * p) { return *to_num_ptr(p); }
|
|
poly_or_num * to_poly_or_num(polynomial * p) { return TAG(poly_or_num*, p, 0); }
|
|
poly_or_num * to_poly_or_num(manager::numeral * n) { return TAG(poly_or_num*, n, 1); }
|
|
|
|
class polynomial {
|
|
friend class manager;
|
|
friend struct manager::imp;
|
|
|
|
unsigned m_ref_count;
|
|
var m_var;
|
|
unsigned m_size;
|
|
poly_or_num * m_args[0];
|
|
|
|
public:
|
|
unsigned ref_count() const { return m_ref_count; }
|
|
void inc_ref() { m_ref_count++; }
|
|
void dec_ref() { SASSERT(m_ref_count > 0); m_ref_count--; }
|
|
|
|
static unsigned get_obj_size(unsigned n) { return sizeof(polynomial) + n*sizeof(void*); }
|
|
|
|
var max_var() const { return m_var; }
|
|
unsigned size() const { return m_size; }
|
|
poly_or_num * arg(unsigned i) const { SASSERT(i < size()); return m_args[i]; }
|
|
};
|
|
|
|
struct manager::imp {
|
|
manager & m_wrapper;
|
|
numeral_manager & m_manager;
|
|
small_object_allocator * m_allocator;
|
|
bool m_own_allocator;
|
|
volatile bool m_cancel;
|
|
|
|
imp(manager & w, numeral_manager & m, small_object_allocator * a):
|
|
m_wrapper(w),
|
|
m_manager(m),
|
|
m_allocator(a),
|
|
m_own_allocator(a == 0) {
|
|
if (a == 0)
|
|
m_allocator = alloc(small_object_allocator, "rpolynomial");
|
|
m_cancel = false;
|
|
}
|
|
|
|
~imp() {
|
|
if (m_own_allocator)
|
|
dealloc(m_allocator);
|
|
}
|
|
|
|
// Remark: recursive calls should be fine since I do not expect to have polynomials with more than 100 variables.
|
|
|
|
manager & pm() const { return m_wrapper; }
|
|
|
|
numeral * mk_numeral() {
|
|
void * mem = m_allocator->allocate(sizeof(numeral));
|
|
return new (mem) numeral();
|
|
}
|
|
|
|
void del_numeral(numeral * n) {
|
|
m_manager.del(*n);
|
|
m_allocator->deallocate(sizeof(numeral), n);
|
|
}
|
|
|
|
static void inc_ref(polynomial * p) {
|
|
if (p)
|
|
p->inc_ref();
|
|
}
|
|
|
|
static void inc_ref(poly_or_num * p) {
|
|
if (p && is_poly(p))
|
|
inc_ref(to_poly(p));
|
|
}
|
|
|
|
void del_poly(polynomial * p) {
|
|
SASSERT(p != 0);
|
|
ptr_buffer<polynomial> todo;
|
|
todo.push_back(p);
|
|
while (!todo.empty()) {
|
|
p = todo.back();
|
|
todo.pop_back();
|
|
unsigned sz = p->size();
|
|
for (unsigned i = 0; i < sz; i++) {
|
|
poly_or_num * pn = p->arg(i);
|
|
if (pn == 0)
|
|
continue;
|
|
if (is_num(pn)) {
|
|
del_numeral(to_num_ptr(pn));
|
|
}
|
|
else {
|
|
SASSERT(is_poly(p));
|
|
polynomial * p_arg = to_poly(p);
|
|
p_arg->dec_ref();
|
|
if (p_arg->ref_count() == 0) {
|
|
todo.push_back(p_arg);
|
|
}
|
|
}
|
|
}
|
|
unsigned obj_sz = polynomial::get_obj_size(sz);
|
|
m_allocator->deallocate(obj_sz, p);
|
|
}
|
|
}
|
|
|
|
void dec_ref(polynomial * p) {
|
|
if (p) {
|
|
p->dec_ref();
|
|
if (p->ref_count() == 0)
|
|
del_poly(p);
|
|
}
|
|
}
|
|
|
|
void dec_ref(poly_or_num * p) {
|
|
if (p && is_poly(p))
|
|
dec_ref(to_poly(p));
|
|
}
|
|
|
|
static bool is_const(polynomial const * p) {
|
|
SASSERT(p == 0 || (p->max_var() == null_var) == (p->size() == 1 && p->arg(0) != 0 && is_num(p->arg(0))));
|
|
return p == 0 || p->max_var() == null_var;
|
|
}
|
|
|
|
bool is_zero(polynomial const * p) {
|
|
return p == 0;
|
|
}
|
|
|
|
static bool is_univariate(polynomial const * p) {
|
|
if (is_const(p))
|
|
return false;
|
|
unsigned sz = p->size();
|
|
for (unsigned i = 0; i < sz; i++) {
|
|
poly_or_num * pn = p->arg(i);
|
|
if (pn == 0)
|
|
continue;
|
|
if (is_poly(pn))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool is_monomial(polynomial const * p) {
|
|
if (is_const(p))
|
|
return true;
|
|
unsigned sz = p->size();
|
|
SASSERT(sz > 0);
|
|
SASSERT(p->arg(sz - 1) != 0);
|
|
for (unsigned i = 0; i < sz - 1; i++) {
|
|
if (p->arg(i) != 0)
|
|
return false;
|
|
}
|
|
SASSERT(is_poly(p->arg(sz - 1)));
|
|
return is_monomial(to_poly(p->arg(sz-1)));
|
|
}
|
|
|
|
unsigned degree(polynomial const * p) {
|
|
SASSERT(p != 0);
|
|
SASSERT(p->size() > 0);
|
|
return p == 0 ? 0 : p->size() - 1;
|
|
}
|
|
|
|
bool eq(polynomial const * p1, polynomial const * p2) {
|
|
if (p1 == p2)
|
|
return true;
|
|
if (p1 == 0 || p2 == 0)
|
|
return false;
|
|
if (p1->size() != p2->size())
|
|
return false;
|
|
if (p1->max_var() != p2->max_var())
|
|
return false;
|
|
unsigned sz = p1->size();
|
|
for (unsigned i = 0; i < sz; i++) {
|
|
poly_or_num * pn1 = p1->arg(i);
|
|
poly_or_num * pn2 = p2->arg(i);
|
|
if (pn1 == 0 && pn2 == 0)
|
|
continue;
|
|
if (pn1 == 0 || pn2 == 0)
|
|
return false;
|
|
if (is_num(pn1) && is_num(pn2)) {
|
|
if (!m_manager.eq(to_num(pn1), to_num(pn2)))
|
|
return false;
|
|
}
|
|
else if (is_poly(pn1) && is_poly(pn2)) {
|
|
if (!eq(to_poly(pn1), to_poly(pn2)))
|
|
return false;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void inc_ref_args(unsigned sz, poly_or_num * const * args) {
|
|
for (unsigned i = 0; i < sz; i++) {
|
|
poly_or_num * pn = args[i];
|
|
if (pn == 0 || is_num(pn))
|
|
continue;
|
|
inc_ref(to_poly(pn));
|
|
}
|
|
}
|
|
|
|
void dec_ref_args(unsigned sz, poly_or_num * const * args) {
|
|
for (unsigned i = 0; i < sz; i++) {
|
|
poly_or_num * pn = args[i];
|
|
if (pn == 0 || is_num(pn))
|
|
continue;
|
|
dec_ref(to_poly(pn));
|
|
}
|
|
}
|
|
|
|
unsigned trim(unsigned sz, poly_or_num * const * args) {
|
|
while (sz > 0) {
|
|
if (args[sz - 1] != 0)
|
|
return sz;
|
|
sz--;
|
|
}
|
|
UNREACHABLE();
|
|
return UINT_MAX;
|
|
}
|
|
|
|
polynomial * allocate_poly(unsigned sz, poly_or_num * const * args, var max_var) {
|
|
SASSERT(sz > 0);
|
|
SASSERT((max_var == null_var) == (sz == 1 && is_num(args[0])));
|
|
unsigned obj_sz = polynomial::get_obj_size(sz);
|
|
void * mem = m_allocator->allocate(obj_sz);
|
|
polynomial * new_pol = new (mem) polynomial();
|
|
new_pol->m_ref_count = 0;
|
|
new_pol->m_var = max_var;
|
|
new_pol->m_size = sz;
|
|
for (unsigned i = 0; i < sz; i++) {
|
|
poly_or_num * pn = args[i];
|
|
if (is_poly(pn)) {
|
|
inc_ref(to_poly(pn));
|
|
new_pol->m_args[i] = pn;
|
|
SASSERT(max_var == null_var || to_poly(pn)->max_var() < max_var);
|
|
}
|
|
else {
|
|
SASSERT(!m_manager.is_zero(to_num(pn)));
|
|
new_pol->m_args[i] = pn;
|
|
}
|
|
}
|
|
return new_pol;
|
|
}
|
|
|
|
poly_or_num * mk_poly_core(unsigned sz, poly_or_num * const * args, var max_var) {
|
|
sz = trim(sz, args);
|
|
SASSERT(sz > 0);
|
|
if (sz == 1) {
|
|
poly_or_num * pn0 = args[0];
|
|
SASSERT(!is_num(pn0) || !m_manager.is_zero(to_num(pn0)));
|
|
return pn0;
|
|
}
|
|
SASSERT((max_var == null_var) == (sz == 1 && is_num(args[0])));
|
|
SASSERT(sz > 1);
|
|
return to_poly_or_num(allocate_poly(sz, args, max_var));
|
|
}
|
|
|
|
polynomial * mk_poly(unsigned sz, poly_or_num * const * args, var max_var) {
|
|
poly_or_num * _p = mk_poly_core(sz, args, max_var);
|
|
if (_p == 0)
|
|
return 0;
|
|
else if (is_num(_p))
|
|
return allocate_poly(1, &_p, null_var);
|
|
else
|
|
return to_poly(_p);
|
|
}
|
|
|
|
polynomial * mk_const(numeral const & n) {
|
|
if (m_manager.is_zero(n))
|
|
return 0;
|
|
numeral * a = mk_numeral();
|
|
m_manager.set(*a, n);
|
|
poly_or_num * _a = to_poly_or_num(a);
|
|
return allocate_poly(1, &_a, null_var);
|
|
}
|
|
|
|
polynomial * mk_const(rational const & a) {
|
|
SASSERT(a.is_int());
|
|
scoped_numeral tmp(m_manager);
|
|
m_manager.set(tmp, a.to_mpq().numerator());
|
|
return mk_const(tmp);
|
|
}
|
|
|
|
polynomial * mk_polynomial(var x, unsigned k) {
|
|
SASSERT(x != null_var);
|
|
if (k == 0) {
|
|
numeral one;
|
|
m_manager.set(one, 1);
|
|
return mk_const(one);
|
|
}
|
|
ptr_buffer<poly_or_num> new_args;
|
|
for (unsigned i = 0; i < k; i++)
|
|
new_args.push_back(0);
|
|
numeral * new_arg = mk_numeral();
|
|
m_manager.set(*new_arg, 1);
|
|
new_args.push_back(to_poly_or_num(new_arg));
|
|
return mk_poly(new_args.size(), new_args.c_ptr(), x);
|
|
}
|
|
|
|
poly_or_num * unpack(polynomial const * p) {
|
|
if (p == 0) {
|
|
return 0;
|
|
}
|
|
else if (is_const(p)) {
|
|
SASSERT(p->size() == 1);
|
|
SASSERT(p->max_var() == null_var);
|
|
return p->arg(0);
|
|
}
|
|
else {
|
|
return to_poly_or_num(const_cast<polynomial*>(p));
|
|
}
|
|
}
|
|
|
|
polynomial * pack(poly_or_num * p) {
|
|
if (p == 0)
|
|
return 0;
|
|
else if (is_num(p))
|
|
return mk_poly(1, &p, null_var);
|
|
else
|
|
return to_poly(p);
|
|
}
|
|
|
|
poly_or_num * mul_core(numeral const & c, poly_or_num * p) {
|
|
if (m_manager.is_zero(c) || p == 0) {
|
|
return 0;
|
|
}
|
|
else if (is_num(p)) {
|
|
numeral * r = mk_numeral();
|
|
m_manager.mul(c, to_num(p), *r);
|
|
return to_poly_or_num(r);
|
|
}
|
|
else {
|
|
polynomial * _p = to_poly(p);
|
|
unsigned sz = _p->size();
|
|
SASSERT(sz > 1);
|
|
ptr_buffer<poly_or_num> new_args;
|
|
for (unsigned i = 0; i < sz; i++) {
|
|
new_args.push_back(mul_core(c, _p->arg(i)));
|
|
}
|
|
return mk_poly_core(new_args.size(), new_args.c_ptr(), _p->max_var());
|
|
}
|
|
}
|
|
|
|
polynomial * mul(numeral const & c, polynomial const * p) {
|
|
return pack(mul_core(c, unpack(p)));
|
|
}
|
|
|
|
polynomial * neg(polynomial const * p) {
|
|
numeral minus_one;
|
|
m_manager.set(minus_one, -1);
|
|
return pack(mul_core(minus_one, unpack(p)));
|
|
}
|
|
|
|
poly_or_num * add_core(numeral const & c, poly_or_num * p) {
|
|
if (m_manager.is_zero(c)) {
|
|
return p;
|
|
}
|
|
else if (p == 0) {
|
|
numeral * r = mk_numeral();
|
|
m_manager.set(*r, c);
|
|
return to_poly_or_num(r);
|
|
}
|
|
else if (is_num(p)) {
|
|
numeral a;
|
|
m_manager.add(c, to_num(p), a);
|
|
if (m_manager.is_zero(a))
|
|
return 0;
|
|
numeral * new_arg = mk_numeral();
|
|
m_manager.swap(*new_arg, a);
|
|
return to_poly_or_num(new_arg);
|
|
}
|
|
else {
|
|
polynomial * _p = to_poly(p);
|
|
unsigned sz = _p->size();
|
|
SASSERT(sz > 1);
|
|
ptr_buffer<poly_or_num> new_args;
|
|
new_args.push_back(add_core(c, _p->arg(0)));
|
|
for (unsigned i = 1; i < sz; i++)
|
|
new_args.push_back(_p->arg(1));
|
|
return mk_poly_core(new_args.size(), new_args.c_ptr(), _p->max_var());
|
|
}
|
|
}
|
|
|
|
polynomial * add(numeral const & c, polynomial const * p) {
|
|
return pack(add_core(c, unpack(p)));
|
|
}
|
|
|
|
#if 0
|
|
polynomial * add_lt(polynomial const * p1, polynomial const * p2) {
|
|
// Add non-constant polynomials p1 and p2 when max_var(p1) < max_var(p2)
|
|
SASSERT(p1->max_var() != null_var);
|
|
SASSERT(p2->max_var() != null_var);
|
|
SASSERT(p1->max_var() < p2->max_var());
|
|
|
|
unsigned sz = p2->size();
|
|
ptr_buffer<poly_or_num> new_args;
|
|
poly_or_num * pn0 = p2->arg(0);
|
|
if (pn0 == 0) {
|
|
new_args.push_back(to_poly_or_num(const_cast<polynomial*>(p1)));
|
|
}
|
|
else if (is_num(pn0)) {
|
|
SASSERT(!is_const(p1));
|
|
polynomial * new_arg = add(to_num(pn0), p1);
|
|
SASSERT(!is_zero(new_arg));
|
|
SASSERT(!is_const(new_arg));
|
|
new_args.push_back(to_poly_or_num(new_arg));
|
|
}
|
|
else {
|
|
SASSERT(is_poly(pn0));
|
|
polynomial * new_arg = add(p1, to_poly(pn0));
|
|
new_args.push_back(to_poly_or_num(new_arg));
|
|
}
|
|
for (unsigned i = 1; i < sz; i++)
|
|
new_args.push_back(p2->arg(i));
|
|
return mk_poly(sz, new_args.c_ptr(), p2->max_var());
|
|
}
|
|
|
|
polynomial * add(polynomial const * p1, polynomial const * p2) {
|
|
if (is_zero(p1))
|
|
return const_cast<polynomial*>(p2);
|
|
if (is_zero(p2))
|
|
return const_cast<polynomial*>(p1);
|
|
var x1 = p1->max_var();
|
|
var x2 = p2->max_var();
|
|
if (x1 == null_var) {
|
|
SASSERT(is_const(p1));
|
|
return add(to_num(p1->arg(0)), p2);
|
|
}
|
|
if (x2 == null_var) {
|
|
SASSERT(is_const(p2));
|
|
return add(to_num(p2->arg(0)), p1);
|
|
}
|
|
if (x1 < x2)
|
|
return add_lt(p1, p2);
|
|
if (x2 < x1)
|
|
return add_lt(p2, p1);
|
|
SASSERT(x1 == x2);
|
|
unsigned sz1 = p1->size();
|
|
unsigned sz2 = p2->size();
|
|
unsigned msz = std::min(sz1, sz2);
|
|
ptr_buffer<poly_or_num> new_args;
|
|
for (unsigned i = 0; i < msz; i++) {
|
|
poly_or_num * pn1 = p1->arg(i);
|
|
poly_or_num * pn2 = p2->arg(i);
|
|
if (pn1 == 0) {
|
|
new_args.push_back(pn2);
|
|
continue;
|
|
}
|
|
if (pn2 == 0) {
|
|
new_args.push_back(pn1);
|
|
continue;
|
|
}
|
|
SASSERT(pn1 != 0 && pn2 != 0);
|
|
if (is_num(pn1)) {
|
|
if (is_num(pn2)) {
|
|
SASSERT(is_num(pn1) && is_num(pn2));
|
|
numeral a;
|
|
m_manager.add(to_num(pn1), to_num(pn2), a);
|
|
if (m_manager.is_zero(a)) {
|
|
new_args.push_back(0);
|
|
}
|
|
else {
|
|
numeral * new_arg = mk_numeral();
|
|
m_manager.swap(*new_arg, a);
|
|
new_args.push_back(to_poly_or_num(new_arg));
|
|
}
|
|
}
|
|
else {
|
|
SASSERT(is_num(pn1) && is_poly(pn2));
|
|
new_args.push_back(to_poly_or_num(add(to_num(pn1), to_poly(pn2))));
|
|
}
|
|
}
|
|
else {
|
|
if (is_num(pn2)) {
|
|
SASSERT(is_poly(pn1) && is_num(pn2));
|
|
new_args.push_back(to_poly_or_num(add(to_num(pn2), to_poly(pn1))));
|
|
}
|
|
else {
|
|
SASSERT(is_poly(pn1) && is_poly(pn2));
|
|
new_args.push_back(to_poly_or_num(add(to_poly(pn1), to_poly(pn2))));
|
|
}
|
|
}
|
|
}
|
|
SASSERT(new_args.size() == sz1 || new_args.size() == sz2);
|
|
for (unsigned i = msz; i < sz1; i++) {
|
|
new_args.push_back(p1->arg(i));
|
|
}
|
|
for (unsigned i = msz; i < sz2; i++) {
|
|
new_args.push_back(p2->arg(i));
|
|
}
|
|
SASSERT(new_args.size() == std::max(sz1, sz2));
|
|
return mk_poly(new_args.size(), new_args.c_ptr(), x1);
|
|
}
|
|
|
|
class resetter_mul_buffer;
|
|
friend class resetter_mul_buffer;
|
|
class resetter_mul_buffer {
|
|
imp & m_owner;
|
|
ptr_buffer<poly_or_num> m_buffer;
|
|
public:
|
|
resetter_mul_buffer(imp & o, ptr_buffer<poly_or_num> & b):m_owner(o), m_buffer(b) {}
|
|
~resetter_mul_buffer() {
|
|
m_owner.dec_ref_args(m_buffer.size(), m_buffer.c_ptr());
|
|
m_buffer.reset();
|
|
}
|
|
};
|
|
|
|
void acc_mul_xk(ptr_buffer<poly_or_num> & mul_buffer, unsigned k, polynomial * p) {
|
|
if (mul_buffer[k] == 0) {
|
|
mul_buffer[k] = to_poly_or_num(p);
|
|
inc_ref(p);
|
|
}
|
|
else {
|
|
polynomial * new_p;
|
|
if (is_num(mul_buffer[k]))
|
|
new_p = add(to_num(mul_buffer.get(k)), p);
|
|
else
|
|
new_p = add(p, to_poly(mul_buffer.get(k)));
|
|
if (is_zero(new_p)) {
|
|
dec_ref(mul_buffer[k]);
|
|
mul_buffer[k] = 0;
|
|
}
|
|
else {
|
|
inc_ref(new_p);
|
|
dec_ref(mul_buffer[k]);
|
|
mul_buffer[k] = to_poly_or_num(new_p);
|
|
}
|
|
}
|
|
}
|
|
|
|
void acc_mul_xk(ptr_buffer<poly_or_num> & mul_buffer, unsigned k, numeral & a) {
|
|
if (mul_buffer.get(k) == 0) {
|
|
numeral * new_arg = mk_numeral();
|
|
m_manager.swap(*new_arg, a);
|
|
mul_buffer[k] = to_poly_or_num(new_arg);
|
|
}
|
|
else {
|
|
if (is_num(mul_buffer[k])) {
|
|
m_manager.add(to_num(mul_buffer[k]), a, to_num(mul_buffer[k]));
|
|
if (m_manager.is_zero(to_num(mul_buffer[k]))) {
|
|
del_numeral(to_num_ptr(mul_buffer[k]));
|
|
mul_buffer[k] = 0;
|
|
}
|
|
}
|
|
else {
|
|
polynomial * new_p = add(a, to_poly(mul_buffer.get(k)));
|
|
if (is_zero(new_p)) {
|
|
dec_ref(mul_buffer[k]);
|
|
mul_buffer[k] = 0;
|
|
}
|
|
else {
|
|
inc_ref(new_p);
|
|
dec_ref(mul_buffer[k]);
|
|
mul_buffer[k] = to_poly_or_num(new_p);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
polynomial * mul_lt(polynomial const * p1, polynomial const * p2) {
|
|
unsigned sz2 = p2->size();
|
|
|
|
// TODO
|
|
return 0;
|
|
}
|
|
|
|
polynomial * mul(polynomial const * p1, polynomial const * p2) {
|
|
var x1 = p1->max_var();
|
|
var x2 = p2->max_var();
|
|
if (x1 == null_var) {
|
|
SASSERT(is_const(p1));
|
|
return mul(to_num(p1->arg(0)), p2);
|
|
}
|
|
if (x2 == null_var) {
|
|
SASSERT(is_const(p2));
|
|
return mul(to_num(p2->arg(0)), p1);
|
|
}
|
|
if (x1 < x2)
|
|
return mul_lt(p1, p2);
|
|
if (x2 < x1)
|
|
return mul_lt(p2, p1);
|
|
SASSERT(x1 == x2);
|
|
if (degree(p1) < degree(p2))
|
|
std::swap(p1, p2);
|
|
unsigned sz = degree(p1) * degree(p2) + 1;
|
|
ptr_buffer<poly_or_num> mul_buffer;
|
|
resetter_mul_buffer resetter(*this, mul_buffer);
|
|
mul_buffer.resize(sz);
|
|
unsigned sz1 = p1->size();
|
|
unsigned sz2 = p2->size();
|
|
for (unsigned i1 = 0; i1 < sz1; i1++) {
|
|
poly_or_num * pn1 = p1->arg(i1);
|
|
if (pn1 == 0)
|
|
continue;
|
|
for (unsigned i2 = 0; i2 < sz2; i2++) {
|
|
poly_or_num * pn2 = p2->arg(i2);
|
|
if (pn2 == 0)
|
|
continue;
|
|
unsigned i = i1+i2;
|
|
if (is_num(pn1)) {
|
|
if (is_num(pn2)) {
|
|
SASSERT(is_num(pn1) && is_num(pn2));
|
|
scoped_numeral a(m_manager);
|
|
m_manager.mul(to_num(pn1), to_num(pn2), a);
|
|
acc_mul_xk(mul_buffer, i, a);
|
|
}
|
|
else {
|
|
SASSERT(is_num(pn1) && is_poly(pn2));
|
|
polynomial_ref p(pm());
|
|
p = mul(to_num(pn1), to_poly(pn2));
|
|
acc_mul_xk(mul_buffer, i, p);
|
|
}
|
|
}
|
|
else {
|
|
if (is_num(pn2)) {
|
|
SASSERT(is_poly(pn1) && is_num(pn2));
|
|
polynomial_ref p(pm());
|
|
p = mul(to_num(pn2), to_poly(pn1));
|
|
acc_mul_xk(mul_buffer, i, p);
|
|
}
|
|
else {
|
|
SASSERT(is_poly(pn1) && is_poly(pn2));
|
|
polynomial_ref p(pm());
|
|
p = mul(to_poly(pn2), to_poly(pn1));
|
|
acc_mul_xk(mul_buffer, i, p);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return mk_poly(mul_buffer.size(), mul_buffer.c_ptr(), x1);
|
|
}
|
|
#endif
|
|
|
|
void display(std::ostream & out, polynomial const * p, display_var_proc const & proc, bool use_star) {
|
|
var x = p->max_var();
|
|
bool first = true;
|
|
unsigned i = p->size();
|
|
while (i > 0) {
|
|
--i;
|
|
poly_or_num * pn = p->arg(i);
|
|
if (pn == 0)
|
|
continue;
|
|
if (first)
|
|
first = false;
|
|
else
|
|
out << " + ";
|
|
if (is_num(pn)) {
|
|
numeral & a = to_num(pn);
|
|
if (i == 0) {
|
|
m_manager.display(out, a);
|
|
}
|
|
else {
|
|
if (m_manager.is_one(a)) {
|
|
proc(out, x);
|
|
if (i > 1)
|
|
out << "^" << i;
|
|
}
|
|
else {
|
|
m_manager.display(out, a);
|
|
if (use_star)
|
|
out << "*";
|
|
else
|
|
out << " ";
|
|
proc(out, x);
|
|
if (i > 1)
|
|
out << "^" << i;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
SASSERT(is_poly(pn));
|
|
if (i == 0) {
|
|
display(out, to_poly(pn), proc, use_star);
|
|
}
|
|
else {
|
|
bool add_paren = false;
|
|
if (i > 0)
|
|
add_paren = !is_monomial(to_poly(pn));
|
|
if (add_paren)
|
|
out << "(";
|
|
display(out, to_poly(pn), proc, use_star);
|
|
if (add_paren)
|
|
out << ")";
|
|
if (i > 0) {
|
|
if (use_star)
|
|
out << "*";
|
|
else
|
|
out << " ";
|
|
proc(out, x);
|
|
if (i > 1)
|
|
out << "^" << i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
manager:: manager(numeral_manager & m, small_object_allocator * a) {
|
|
m_imp = alloc(imp, *this, m, a);
|
|
}
|
|
|
|
manager::~manager() {
|
|
dealloc(m_imp);
|
|
}
|
|
|
|
bool manager::is_zero(polynomial const * p) {
|
|
return p == 0;
|
|
}
|
|
|
|
#if 0
|
|
bool manager::is_const(polynomial const * p) {
|
|
return imp::is_const(p);
|
|
}
|
|
|
|
bool manager::is_univariate(polynomial const * p) {
|
|
return imp::is_univariate(p);
|
|
}
|
|
|
|
bool manager::is_monomial(polynomial const * p) const {
|
|
return m_imp->is_monomial(p);
|
|
}
|
|
|
|
bool manager::eq(polynomial const * p1, polynomial const * p2) {
|
|
return m_imp->eq(p1, p2);
|
|
}
|
|
|
|
polynomial * manager::mk_zero() {
|
|
return m_imp->mk_zero();
|
|
}
|
|
|
|
polynomial * manager::mk_const(numeral const & r) {
|
|
return m_imp->mk_const(r);
|
|
}
|
|
|
|
polynomial * manager::mk_const(rational const & a) {
|
|
return m_imp->mk_const(a);
|
|
}
|
|
|
|
polynomial * manager::mk_polynomial(var x, unsigned k) {
|
|
return m_imp->mk_polynomial(x, k);
|
|
}
|
|
|
|
polynomial * manager::mul(numeral const & r, polynomial const * p) {
|
|
return m_imp->mul(r, p);
|
|
}
|
|
|
|
polynomial * manager::neg(polynomial const * p) {
|
|
return m_imp->neg(p);
|
|
}
|
|
|
|
polynomial * manager::add(numeral const & r, polynomial const * p) {
|
|
return m_imp->add(r, p);
|
|
}
|
|
|
|
polynomial * manager::add(polynomial const * p1, polynomial const * p2) {
|
|
return m_imp->add(p1, p2);
|
|
}
|
|
|
|
var manager::max_var(polynomial const * p) {
|
|
return p->max_var();
|
|
}
|
|
|
|
unsigned manager::size(polynomial const * p) {
|
|
return p->size();
|
|
}
|
|
|
|
void manager::display(std::ostream & out, polynomial const * p, display_var_proc const & proc, bool use_star) const {
|
|
return m_imp->display(out, p, proc, use_star);
|
|
}
|
|
#endif
|
|
|
|
};
|