#pragma once
#include "util/rational.h"
#include "util/mpq.h"
#include "math/polynomial/polynomial.h"
#include "util/z3_exception.h"
#include "util/scoped_numeral.h"
#include "util/scoped_numeral_vector.h"
#include "util/tptr.h"
#include "util/statistics.h"
#include "util/params.h"
#include "util/rlimit.h"
class small_object_allocator;
class mpbq_manager;
class mpbq;
namespace algebraic_numbers {
class anum;
class manager;
class algebraic_exception : public default_exception {
public:
algebraic_exception(char const * msg):default_exception(msg) {}
};
class manager {
public:
struct imp;
private:
imp * m_imp;
small_object_allocator * m_allocator;
bool m_own_allocator;
public:
static bool precise() { return true; }
static bool field() { return true; }
typedef anum numeral;
typedef svector<numeral> numeral_vector;
typedef _scoped_numeral<manager> scoped_numeral;
typedef _scoped_numeral_vector<manager> scoped_numeral_vector;
manager(reslimit& rl, unsynch_mpq_manager & m, params_ref const & p = params_ref(), small_object_allocator * a = nullptr);
~manager();
static void get_param_descrs(param_descrs & r);
static void collect_param_descrs(param_descrs & r) { get_param_descrs(r); }
void updt_params(params_ref const & p);
unsynch_mpq_manager & qm() const;
mpbq_manager & bqm() const;
void del(numeral & a);
void reset(numeral & a);
bool is_zero(numeral const & a);
bool is_pos(numeral const & a);
bool is_neg(numeral const & a);
bool is_rational(numeral const & a);
bool is_int(numeral const & a);
unsigned degree(numeral const & a);
void to_rational(numeral const & a, mpq & r);
void to_rational(numeral const & a, rational & r);
void set(numeral & a, int n);
void set(numeral & a, mpz const & n);
void set(numeral & a, mpq const & n);
void set(numeral & a, numeral const & n);
void swap(numeral & a, numeral & b) noexcept;
void int_lt(numeral const & a, numeral & b);
void int_gt(numeral const & a, numeral & b);
void select(numeral const & prev, numeral const & curr, numeral & result);
void isolate_roots(polynomial_ref const & p, numeral_vector & roots);
void isolate_roots(polynomial_ref const & p, polynomial::var2anum const & x2v, numeral_vector & roots);
void isolate_roots(polynomial_ref const & p, polynomial::var2anum const & x2v, numeral_vector & roots, svector<sign> & signs);
void mk_root(polynomial_ref const & p, unsigned i, numeral & r);
void mk_root(sexpr const * p, unsigned i, numeral & r);
void root(numeral const & a, unsigned k, numeral & b);
void power(numeral const & a, unsigned k, numeral & b);
void add(numeral const & a, numeral const & b, numeral & c);
void add(numeral const & a, mpz const & b, numeral & c);
void sub(numeral const & a, numeral const & b, numeral & c);
void mul(numeral const & a, numeral const & b, numeral & c);
void neg(numeral & a);
void inv(numeral & a);
void div(numeral const & a, numeral const & b, numeral & c);
sign compare(numeral const & a, numeral const & b);
bool eq(numeral const & a, numeral const & b);
bool eq(numeral const & a, mpq const & b);
bool eq(numeral const & a, mpz const & b);
bool neq(numeral const & a, numeral const & b) { return !eq(a, b); }
bool neq(numeral const & a, mpq const & b) { return !eq(a, b); }
bool neq(numeral const & a, mpz const & b) { return !eq(a, b); }
bool lt(numeral const & a, numeral const & b);
bool lt(numeral const & a, mpq const & b);
bool lt(numeral const & a, mpz const & b);
bool gt(numeral const & a, numeral const & b) { return lt(b, a); }
bool gt(numeral const & a, mpq const & b);
bool gt(numeral const & a, mpz const & b);
bool le(numeral const & a, numeral const & b) { return !gt(a, b); }
bool le(numeral const & a, mpq const & b) { return !gt(a, b); }
bool le(numeral const & a, mpz const & b) { return !gt(a, b); }
bool ge(numeral const & a, numeral const & b) { return !lt(a, b); }
bool ge(numeral const & a, mpq const & b) { return !lt(a, b); }
bool ge(numeral const & a, mpz const & b) { return !lt(a, b); }
sign eval_sign_at(polynomial_ref const & p, polynomial::var2anum const & x2v);
void get_polynomial(numeral const & a, svector<mpz> & r);
unsigned get_i(numeral const & a);
void get_lower(numeral const & a, mpbq & l);
void get_lower(numeral const & a, mpq & l);
void get_lower(numeral const & a, rational & l);
void get_lower(numeral const & a, mpq & l, unsigned precision);
void get_lower(numeral const & a, rational & l, unsigned precision);
void get_upper(numeral const & a, mpbq & u);
void get_upper(numeral const & a, mpq & u);
void get_upper(numeral const & a, rational & u);
void get_upper(numeral const & a, mpq & l, unsigned precision);
void get_upper(numeral const & a, rational & l, unsigned precision);
std::ostream& display_interval(std::ostream & out, numeral const & a) const;
std::ostream& display_decimal(std::ostream & out, numeral const & a, unsigned precision = 10) const;
std::ostream& display_root(std::ostream & out, numeral const & a) const;
std::ostream& display_root_smt2(std::ostream & out, numeral const & a) const;
std::ostream& display_mathematica(std::ostream & out, numeral const & a) const;
std::ostream& display(std::ostream & out, numeral const & a) { return display_decimal(out, a); }
void reset_statistics();
void collect_statistics(statistics & st) const;
};
struct basic_cell;
struct algebraic_cell;
class anum {
enum anum_kind { BASIC = 0, ROOT };
void* m_cell;
public:
anum() :m_cell(nullptr) {}
anum(basic_cell* cell) :m_cell(TAG(void*, cell, BASIC)) { }
anum(algebraic_cell * cell):m_cell(TAG(void*, cell, ROOT)) { }
bool is_basic() const { return GET_TAG(m_cell) == BASIC; }
basic_cell * to_basic() const { SASSERT(is_basic()); return UNTAG(basic_cell*, m_cell); }
algebraic_cell * to_algebraic() const { SASSERT(!is_basic()); return UNTAG(algebraic_cell*, m_cell); }
bool is_null() const { return m_cell == nullptr; }
void clear() { m_cell = nullptr; }
void swap(anum & other) { std::swap(m_cell, other.m_cell); }
anum& operator=(basic_cell* cell) { SASSERT(is_null()); m_cell = TAG(void*, cell, BASIC); return *this; }
anum& operator=(algebraic_cell* cell) { SASSERT(is_null()); m_cell = TAG(void*, cell, ROOT); return *this; }
};
};
typedef algebraic_numbers::manager anum_manager;
typedef algebraic_numbers::manager::numeral anum;
typedef algebraic_numbers::manager::numeral_vector anum_vector;
typedef algebraic_numbers::manager::scoped_numeral scoped_anum;
typedef algebraic_numbers::manager::scoped_numeral_vector scoped_anum_vector;
#define AN_MK_COMPARISON_CORE(EXTERNAL, INTERNAL, TYPE) \
inline bool EXTERNAL(scoped_anum const & a, TYPE const & b) { \
anum_manager & m = a.m(); \
scoped_anum _b(m); \
m.set(_b, b); \
return m.INTERNAL(a, _b); \
}
#define AN_MK_COMPARISON(EXTERNAL, INTERNAL) \
AN_MK_COMPARISON_CORE(EXTERNAL, INTERNAL, int) \
AN_MK_COMPARISON_CORE(EXTERNAL, INTERNAL, mpz) \
AN_MK_COMPARISON_CORE(EXTERNAL, INTERNAL, mpq)
AN_MK_COMPARISON(operator==, eq);
AN_MK_COMPARISON(operator!=, neq);
AN_MK_COMPARISON(operator<, lt);
AN_MK_COMPARISON(operator<=, le);
AN_MK_COMPARISON(operator>, gt);
AN_MK_COMPARISON(operator>=, ge);
#undef AN_MK_COMPARISON
#undef AN_MK_COMPARISON_CORE
#define AN_MK_BINARY_CORE(EXTERNAL, INTERNAL, TYPE) \
inline scoped_anum EXTERNAL(scoped_anum const & a, TYPE const & b) { \
anum_manager & m = a.m(); \
scoped_anum _b(m); \
m.set(_b, b); \
scoped_anum r(m); \
m.INTERNAL(a, _b, r); \
return r; \
}
#define AN_MK_BINARY(EXTERNAL, INTERNAL) \
AN_MK_BINARY_CORE(EXTERNAL, INTERNAL, int) \
AN_MK_BINARY_CORE(EXTERNAL, INTERNAL, mpz) \
AN_MK_BINARY_CORE(EXTERNAL, INTERNAL, mpq)
AN_MK_BINARY(operator+, add)
AN_MK_BINARY(operator-, sub)
AN_MK_BINARY(operator*, mul)
AN_MK_BINARY(operator/, div)
#undef AN_MK_BINARY
#undef AN_MK_BINARY_CORE
inline scoped_anum root(scoped_anum const & a, unsigned k) {
scoped_anum r(a.m());
a.m().root(a, k, r);
return r;
}
inline scoped_anum power(scoped_anum const & a, unsigned k) {
scoped_anum r(a.m());
a.m().power(a, k, r);
return r;
}
inline scoped_anum operator^(scoped_anum const & a, unsigned k) {
return power(a, k);
}
inline bool is_int(scoped_anum const & a) {
return a.m().is_int(a);
}
inline bool is_rational(scoped_anum const & a) {
return a.m().is_rational(a);
}
struct root_obj_pp {
anum_manager & m;
anum const & n;
root_obj_pp(anum_manager & _m, anum const & _n):m(_m), n(_n) {}
root_obj_pp(scoped_anum const & _n):m(_n.m()), n(_n.get()) {}
};
inline std::ostream & operator<<(std::ostream & out, root_obj_pp const & n) {
n.m.display_root(out, n.n);
return out;
}
struct decimal_pp {
anum_manager & m;
anum const & n;
unsigned prec;
decimal_pp(anum_manager & _m, anum const & _n, unsigned p):m(_m), n(_n), prec(p) {}
decimal_pp(scoped_anum const & _n, unsigned p):m(_n.m()), n(_n.get()), prec(p) {}
};
inline std::ostream & operator<<(std::ostream & out, decimal_pp const & n) {
n.m.display_decimal(out, n.n, n.prec);
return out;
}
struct interval_pp {
anum_manager & m;
anum const & n;
interval_pp(anum_manager & _m, anum const & _n):m(_m), n(_n) {}
interval_pp(scoped_anum const & _n):m(_n.m()), n(_n.get()) {}
};
inline std::ostream & operator<<(std::ostream & out, interval_pp const & n) {
n.m.display_interval(out, n.n);
return out;
}