/*++ Copyright (c) 2011 Microsoft Corporation Module Name: polynomial.h Abstract: Goodies for creating and handling polynomials. Author: Leonardo (leonardo) 2011-11-15 Notes: --*/ #ifndef _POLYNOMIAL_H_ #define _POLYNOMIAL_H_ #include"mpz.h" #include"rational.h" #include"obj_ref.h" #include"ref_vector.h" #include"z3_exception.h" #include"scoped_numeral.h" #include"scoped_numeral_vector.h" #include"params.h" #include"mpbqi.h" class small_object_allocator; namespace algebraic_numbers { class anum; class manager; }; namespace polynomial { typedef unsigned var; const var null_var = UINT_MAX; typedef svector var_vector; class monomial; int lex_compare(monomial const * m1, monomial const * m2); int lex_compare2(monomial const * m1, monomial const * m2, var min_var); int graded_lex_compare(monomial const * m1, monomial const * m2); int rev_lex_compare(monomial const * m1, monomial const * m2); int graded_rev_lex_compare(monomial const * m1, monomial const * m2); // It is used only for signing cancellation. class polynomial_exception : public default_exception { public: polynomial_exception(char const * msg):default_exception(msg) {} }; /** \brief A mapping from variables to degree */ class var2degree { unsigned_vector m_var2degree; public: void set_degree(var x, unsigned d) { m_var2degree.setx(x, d, 0); } unsigned degree(var x) const { return m_var2degree.get(x, 0); } void display(std::ostream & out) const; friend std::ostream & operator<<(std::ostream & out, var2degree const & ideal) { ideal.display(out); return out; } }; template class var2value { public: virtual ValManager & m() const = 0; virtual bool contains(var x) const = 0; virtual Value const & operator()(var x) const = 0; }; typedef var2value var2mpq; typedef var2value var2mpbqi; typedef var2value var2anum; class monomial_manager; /** \brief Parameters for polynomial factorization. */ struct factor_params { unsigned m_max_p; //!< factor in GF_p using primes p <= m_max_p (default UINT_MAX) unsigned m_p_trials; //!< Number of different finite factorizations: G_p1 ... G_pk, where k < m_p_trials unsigned m_max_search_size; //!< Threshold on the search space. factor_params(); factor_params(unsigned max_p, unsigned p_trials, unsigned max_search_size); void updt_params(params_ref const & p); static void get_param_descrs(param_descrs & r); }; struct display_var_proc { virtual void operator()(std::ostream & out, var x) const { out << "x" << x; } }; class polynomial; class manager; typedef obj_ref monomial_ref; typedef obj_ref polynomial_ref; typedef ref_vector polynomial_ref_vector; typedef ptr_vector polynomial_vector; class manager { public: typedef unsynch_mpz_manager numeral_manager; typedef numeral_manager::numeral numeral; typedef svector numeral_vector; typedef _scoped_numeral scoped_numeral; typedef _scoped_numeral_vector scoped_numeral_vector; /** \brief Contains a factorization of a polynomial of the form c * (f_1)^k_1 * ... (f_n)^k_n */ class factors { vector m_factors; svector m_degrees; manager & m_manager; numeral m_constant; unsigned m_total_factors; public: factors(manager & m); ~factors(); /** \brief Numer of distinct factors (not counting multiplicities). */ unsigned distinct_factors() const { return m_factors.size(); } /** \brief Numer of distinct factors (counting multiplicities). */ unsigned total_factors() const { return m_total_factors; } /** \brief Returns the factor at given position. */ polynomial_ref operator[](unsigned i) const; /** \brief Returns the constant (c above). */ numeral const & get_constant() const { return m_constant; } /** \brief Sets the constant. */ void set_constant(numeral const & constant); /** \brief Returns the degree of a factor (k_i above). */ unsigned get_degree(unsigned i) const { return m_degrees[i]; } /** \brief Sets the degree of a factor. */ void set_degree(unsigned i, unsigned degree); /** \brief Adds a polynomial to the factorization. */ void push_back(polynomial * p, unsigned degree); /** \brief Returns the polynomial that this factorization represents. */ void multiply(polynomial_ref & out) const; manager & m() const { return m_manager; } manager & pm() const { return m_manager; } void display(std::ostream& out) const; void reset(); friend std::ostream & operator<<(std::ostream & out, factors const & f) { f.display(out); return out; } }; struct imp; private: imp * m_imp; public: manager(numeral_manager & m, monomial_manager * mm = 0); manager(numeral_manager & m, small_object_allocator * a); ~manager(); numeral_manager & m() const; monomial_manager & mm() const; small_object_allocator & allocator() const; /** \brief Return true if Z_p[X1, ..., Xn] */ bool modular() const; /** \brief Return p in Z_p[X1, ..., Xn] \pre modular */ numeral const & p() const; /** \brief Set manager as Z[X1, ..., Xn] */ void set_z(); /** \brief Set manager as Z_p[X1, ..., Xn] */ void set_zp(numeral const & p); void set_zp(uint64 p); void set_cancel(bool f); /** \brief Abstract event handler. */ class del_eh { friend class manager; del_eh * m_next; public: del_eh():m_next(0) {} virtual void operator()(polynomial * p) = 0; }; /** \brief Install a "delete polynomial" event handler. The even hanlder is not owned by the polynomial manager. If eh = 0, then it uninstall the event handler. */ void add_del_eh(del_eh * eh); void remove_del_eh(del_eh * eh); /** \brief Create a new variable. */ var mk_var(); /** \brief Return the number of variables in the manager. */ unsigned num_vars() const; /** \brief Return true if x is a valid variable in this manager. */ bool is_valid(var x) const { return x < num_vars(); } /** \brief Increment reference counter. */ void inc_ref(polynomial * p); void inc_ref(monomial * m); /** \brief Decrement reference counter. */ void dec_ref(polynomial * p); void dec_ref(monomial * m); /** \brief Return an unique id associated with \c m. This id can be used to implement efficient mappings from monomial to data. */ static unsigned id(monomial const * m); /** \brief Return an unique id associated with \c m. This id can be used to implement efficient mappings from polynomial to data. */ static unsigned id(polynomial const * p); /** \brief Return true if \c m is the unit monomial. */ static bool is_unit(monomial const * m); /** \brief Return true if \c p is the zero polynomial. */ static bool is_zero(polynomial const * p); /** \brief Return true if \c p is the constant polynomial. */ static bool is_const(polynomial const * p); /** \brief Return true if \c m is univariate. */ static bool is_univariate(monomial const * m); /** \brief Return true if \c p is an univariate polynomial. */ static bool is_univariate(polynomial const * p); /** \brief Return true if m is linear (i.e., it is of the form 1 or x). */ static bool is_linear(monomial const * m); /** \brief Return true if all monomials in p are linear. */ static bool is_linear(polynomial const * p); /** \brief Return the degree of variable x in p. */ static unsigned degree(polynomial const * p, var x); /** \brief Return the polynomial total degree. That is, the degree of the monomial of maximal degree in p. */ static unsigned total_degree(polynomial const * p); /** \brief Return the number of monomials in p. */ static unsigned size(polynomial const * p); /** \brief Return the maximal variable occurring in p. Return null_var if p is a constant polynomial. */ static var max_var(polynomial const * p); /** \brief Return the coefficient of the i-th monomial in p. \pre i < size(p) */ static numeral const & coeff(polynomial const * p, unsigned i); /** \brief Given an univariate polynomial, return the coefficient of x_k */ static numeral const & univ_coeff(polynomial const * p, unsigned k); /** \brief Return a polynomial h that is the coefficient of x^k in p. if p does not contain any monomial containing x^k, then return 0. */ polynomial * coeff(polynomial const * p, var x, unsigned k); polynomial * coeff(polynomial const * p, var x, unsigned k, polynomial_ref & reduct); /** \brief Return true if the coefficient of x^k in p is an integer != 0. */ bool nonzero_const_coeff(polynomial const * p, var x, unsigned k); /** \brief Return true if the coefficient of x^k in p is an integer, and store it in c. */ bool const_coeff(polynomial const * p, var x, unsigned k, numeral & c); /** \brief Store in c the integer content of p. */ void int_content(polynomial const * p, numeral & c); /** \brief Returns sum of the absolute value of the coefficients. */ void abs_norm(polynomial const * p, numeral & norm); /** \brief Return the leading integer coefficient (among the loeding power of x, one is picked arbitrary). */ numeral const & numeral_lc(polynomial const * p, var x); /** \brief Return the trailing integer coefficient (i.e. the constant term). */ numeral const & numeral_tc(polynomial const * p); /** \brief Return the content i*c of p with respect to variable x. If p is a polynomial in Z[y_1, ..., y_k, x], then c is a polynomial in Z[y_1, ..., y_k] */ void content(polynomial const * p, var x, numeral & i, polynomial_ref & c); void content(polynomial const * p, var x, polynomial_ref & c); /** \brief Return the primitive polynomial of p with respect to variable x. If p is a polynomial in Z[y_1, ..., y_k, x], then pp is a polynomial in Z[y_1, ..., y_k, x] */ void primitive(polynomial const * p, var x, polynomial_ref & pp); /** \brief Return the integer content, content, and primitive polynomials of p with respect to x. i*c*pp = p If p is a polynomial in Z[y_1, ..., y_k, x], then c is a polynomial in Z[y_1, ..., y_k] pp is a polynomial in Z[y_1, ..., y_k, x] */ void icpp(polynomial const * p, var x, numeral & i, polynomial_ref & c, polynomial_ref & pp); polynomial * flip_sign_if_lm_neg(polynomial const * p); /** \breif Return the gcd g of p and q. */ void gcd(polynomial const * p, polynomial const * q, polynomial_ref & g); /** \brief Return the i-th monomial of p. */ static monomial * get_monomial(polynomial const * p, unsigned i); /** \brief Return the total degree of the given monomial. */ static unsigned total_degree(monomial const * m); /** \brief Return the size (number of variables) of the given monomial. */ static unsigned size(monomial const * m); /** \brief Convert a monomial created in a different manager. */ monomial * convert(monomial const * m); /** \brief Return the i-th variable in the given monomial. \pre i < size(m) */ static var get_var(monomial const * m, unsigned i); /** \brief Return the degree of the i-th variable in the given monomial. \pre i < size(m) */ static unsigned degree(monomial const * m, unsigned i); /** \brief Return the degree of x in the given monomial. */ static unsigned degree_of(monomial const * m, var x); /** \brief Return hash code for the given monomial. */ static unsigned hash(monomial const * m); /** \brief Return hash code for the given polynomial. */ unsigned hash(polynomial const * p); /** \brief Create the unit monomial. That is, the monomial of size zero. */ monomial * mk_unit(); /** \brief Create the zero polynomial. That is, the polynomial of size zero. */ polynomial * mk_zero(); /** \brief Create the constant polynomial \c r. \warning r is a number managed by the numeral_manager in the polynomial manager \warning r is reset. */ polynomial * mk_const(numeral & r); /** \brief Create the constant polynomial \c r. \pre r must be an integer */ polynomial * mk_const(rational const & r); /** \brief Create an univariate monomial. */ monomial * mk_monomial(var x); /** \brief Create an univariate monomial. */ monomial * mk_monomial(var x, unsigned k); /** \brief Create the monomial xs[0]*...*xs[sz-1] Remark: xs may contain duplicate variables. \warning The elements of xs will be reordered. */ monomial * mk_monomial(unsigned sz, var * xs); /** \brief Create the polynomial x^k */ polynomial * mk_polynomial(var x, unsigned k = 1); /** \brief Create the polynomial as[0]*ms[0] + ... + as[sz-1]*ms[sz - 1] \pre as's must be integers */ polynomial * mk_polynomial(unsigned sz, rational const * as, monomial * const * ms); /** \brief Create the polynomial as[0]*ms[0] + ... + as[sz-1]*ms[sz - 1] \warning as's are numbers managed by mpq_manager in the polynomial manager \warning the numerals in as are reset. */ polynomial * mk_polynomial(unsigned sz, numeral * as, monomial * const * ms); /** \brief Create the linear polynomial as[0]*xs[0] + ... + as[sz-1]*xs[sz-1] + c \pre as's must be integers */ polynomial * mk_linear(unsigned sz, rational const * as, var const * xs, rational const & c); /** \brief Create the linear polynomial as[0]*xs[0] + ... + as[sz-1]*xs[sz-1] + c \warning as's are numbers managed by mpq_manager in the polynomial manager \warning the numerals in as are reset. */ polynomial * mk_linear(unsigned sz, numeral * as, var const * xs, numeral & c); /** \brief Create an univariate polynomial of degree n as[0] + as[1]*x + as[2]*x^2 + ... + as[n]*x^n \warning \c as must contain n+1 elements. */ polynomial * mk_univariate(var x, unsigned n, numeral * as); /** \brief Return -p */ polynomial * neg(polynomial const * p); /** \brief Return p1 + p2 */ polynomial * add(polynomial const * p1, polynomial const * p2); /** \brief Return p1 - p2 */ polynomial * sub(polynomial const * p1, polynomial const * p2); /** \brief Return a1*m1*p1 + a2*m2*p2 */ polynomial * addmul(numeral const & a1, monomial const * m1, polynomial const * p1, numeral const & a2, monomial const * m2, polynomial const * p2); /** \brief Return p1 + a2*m2*p2 */ polynomial * addmul(polynomial const * p1, numeral const & a2, monomial const * m2, polynomial const * p2); /** \brief Return p1 + a2*p2 */ polynomial * addmul(polynomial const * p1, numeral const & a2, polynomial const * p2); /** \brief Return a * p */ polynomial * mul(numeral const & a, polynomial const * p); polynomial * mul(rational const & a, polynomial const * p); /** \brief Return p1 * p2 */ polynomial * mul(polynomial const * p1, polynomial const * p2); /** \brief Return m1 * m2 */ monomial * mul(monomial const * m1, monomial const * m2); /** \brief Return a * m * p */ polynomial * mul(numeral const & a, monomial const * m, polynomial const * p); /** \brief Return m * p */ polynomial * mul(monomial const * m, polynomial const * p); /** \brief Return true if m2 divides m1 */ bool div(monomial const * m1, monomial const * m2); /** \brief Return true if m2 divides m1, and store the result in r. */ bool div(monomial const * m1, monomial const * m2, monomial * & r); /** \brief Newton interpolation algorithm for multivariate polynomials. */ void newton_interpolation(var x, unsigned d, numeral const * inputs, polynomial * const * outputs, polynomial_ref & r); /** \brief Return the GCD of m1 and m2. Store in q1 and q2 monomials s.t. m1 = gcd * q1 m2 = gcd * q2 */ monomial * gcd(monomial const * m1, monomial const * m2, monomial * & q1, monomial * & q2); /** \brief Return true if the gcd of m1 and m2 is not 1. In that case, store in q1 and q2 monomials s.t. m1 = gcd * q1 m2 = gcd * q2 */ bool unify(monomial const * m1, monomial const * m2, monomial * & q1, monomial * & q2); /** \brief Return m^k */ monomial * pw(monomial const * m, unsigned k); /** \brief Return the polynomial p^k */ void pw(polynomial const * p, unsigned k, polynomial_ref & r); /** \brief Return dp/dx */ polynomial * derivative(polynomial const * p, var x); /** \brief r := square free part of p with respect to x */ void square_free(polynomial const * p, var x, polynomial_ref & r); /** \brief Return true if p is square free with respect to x */ bool is_square_free(polynomial const * p, var x); /** \brief r := square free part of p */ void square_free(polynomial const * p, polynomial_ref & r); /** \brief Return true if p is square free */ bool is_square_free(polynomial const * p); /** \brief Return true if p1 == p2. */ bool eq(polynomial const * p1, polynomial const * p2); /** \brief Rename variables using the given permutation. sz must be num_vars() */ void rename(unsigned sz, var const * xs); /** \brief Given an univariate polynomial p(x), return the polynomial x^n * p(1/x), where n = degree(p) If u is a nonzero root of p, then 1/u is a root the resultant polynomial. */ polynomial * compose_1_div_x(polynomial const * p); /** \brief Given an univariate polynomial p(x), return the polynomial y^n * p(x/y), where n = degree(p) */ polynomial * compose_x_div_y(polynomial const * p, var y); /** \brief Given an univariate polynomial p(x), return p(-x) */ polynomial * compose_minus_x(polynomial const * p); /** \brief Given an univariate polynomial p(x) and a polynomial q(y_1, ..., y_n), return a polynomial r(y_1, ..., y_n) = p(q(y_1, ..., y_n)). */ void compose(polynomial const * p, polynomial const * q, polynomial_ref & r); /** \brief Given an univariate polynomial p(x), return the polynomial r(y) = p(y) */ polynomial * compose_y(polynomial const * p, var y); /** \brief Given an univariate polynomial p(x), return the polynomial r(x, y) = p(x - y). The result is stored in r. */ void compose_x_minus_y(polynomial const * p, var y, polynomial_ref & r); /** \brief Given an univariate polynomial p(x), return the polynomial r(x, y) = p(x + y). The result is stored in r. */ void compose_x_plus_y(polynomial const * p, var y, polynomial_ref & r); /** \brief Given an univariate polynomial p(x), return the polynomial r(x) = p(x - c). The result is stored in r. */ void compose_x_minus_c(polynomial const * p, numeral const & c, polynomial_ref & r); /** \brief Return the exact pseudo remainder of p by q, assuming x is the maximal variable. See comments at pseudo_division_core at polynomial.cpp for a description of exact pseudo division. */ void exact_pseudo_remainder(polynomial const * p, polynomial const * q, var x, polynomial_ref & R); void exact_pseudo_remainder(polynomial const * p, polynomial const * q, polynomial_ref & R) { exact_pseudo_remainder(p, q, max_var(q), R); } /** \brief Return the pseudo remainder of p by q, assuming x is the maximal variable. See comments at pseudo_division_core at polynomial.cpp for a description of exact pseudo division. */ void pseudo_remainder(polynomial const * p, polynomial const * q, var x, unsigned & d, polynomial_ref & R); void pseudo_remainder(polynomial const * p, polynomial const * q, unsigned & d, polynomial_ref & R) { pseudo_remainder(p, q, max_var(q), d, R); } /** \brief Return the exact pseudo division quotient and remainder. See comments at pseudo_division_core at polynomial.cpp for a description of exact pseudo division. */ void exact_pseudo_division(polynomial const * p, polynomial const * q, var x, polynomial_ref & Q, polynomial_ref & R); void exact_pseudo_division(polynomial const * p, polynomial const * q, polynomial_ref & Q, polynomial_ref & R) { exact_pseudo_division(p, q, max_var(q), Q, R); } /** \brief Return the pseudo division quotient and remainder. See comments at pseudo_division_core at polynomial.cpp for a description of exact pseudo division. */ void pseudo_division(polynomial const * p, polynomial const * q, var x, unsigned & d, polynomial_ref & Q, polynomial_ref & R); void pseudo_division(polynomial const * p, polynomial const * q, unsigned & d, polynomial_ref & Q, polynomial_ref & R) { pseudo_division(p, q, max_var(q), d, Q, R); } /** \brief Return p/q if q divides p. \pre q divides p. \remark p and q may be multivariate polynomials. */ polynomial * exact_div(polynomial const * p, polynomial const * q); /** \brief Return true if q divides p. */ bool divides(polynomial const * q, polynomial const * p); /** \brief Return p/c if c divides p. \pre c divides p. \remark p may be multivariate polynomial. */ polynomial * exact_div(polynomial const * p, numeral const & c); /** \brief Store in r the quasi-resultant of p and q with respect to variable x. Assume p and q are polynomials in Q[y_1, ..., y_n, x]. Then r is a polynomial in Q[y_1, ..., y_n]. Moreover, Forall a_1, ..., a_n, b, if p(a_1, ..., a_n, b) = q(a_1, ..., a_n, b) = 0 then r(a_1, ..., a_n) = 0 \pre p and q must contain x. \remark if r is the zero polynomial, then for any complex numbers a_1, ..., a_n, the univariate polynomials p(a_1, ..., a_n, x) and q(a_1, ..., a_n, x) in C[x] have a common root. C is the field of the complex numbers. */ void quasi_resultant(polynomial const * p, polynomial const * q, var x, polynomial_ref & r); /** \brief Store in r the resultant of p and q with respect to variable x. See comments in polynomial.cpp for more details */ void resultant(polynomial const * p, polynomial const * q, var x, polynomial_ref & r); /** \brief Stroe in r the discriminant of p with respect to variable x. discriminant(p, x, r) == resultant(p, derivative(p, x), x, r) */ void discriminant(polynomial const * p, var x, polynomial_ref & r); /** \brief Store in S the principal subresultant coefficients for p and q. */ void psc_chain(polynomial const * p, polynomial const * q, var x, polynomial_ref_vector & S); /** \brief Make sure the GCD of the coefficients is one. Make sure that the polynomial is a member of the polynomial ring of this manager. If manager is Z_p[X1, ..., Xn], and polynomial is in Z[X1, ..., Xn] return a new one where all coefficients are in Z_p */ polynomial * normalize(polynomial const * p); /** \brief Return true if p is a square, and store its square root in r. */ bool sqrt(polynomial const * p, polynomial_ref & r); /** \brief Return true if p is always positive for any assignment of its variables. This is an incomplete check. This method just check if all monomials are powers of two, and the coefficients are positive. */ bool is_pos(polynomial const * p); /** \brief Return true if p is always negative for any assignment of its variables. This is an incomplete check. */ bool is_neg(polynomial const * p); /** \brief Return true if p is always non-positive for any assignment of its variables. This is an incomplete check. */ bool is_nonpos(polynomial const * p); /** \brief Return true if p is always non-negative for any assignment of its variables. This is an incomplete check. */ bool is_nonneg(polynomial const * p); /** \brief Make sure the monomials in p are sorted using lexicographical order. Remark: the maximal monomial is at position 0. */ void lex_sort(polynomial * p); /** \brief Collect variables that occur in p into xs */ void vars(polynomial const * p, var_vector & xs); /** \brief Evaluate polynomial p using the assignment [x_1 -> v_1, ..., x_n -> v_n]. The result is store in r. All variables occurring in p must be in xs. */ void eval(polynomial const * p, var2mpbqi const & x2v, mpbqi & r); void eval(polynomial const * p, var2mpq const & x2v, mpq & r); void eval(polynomial const * p, var2anum const & x2v, algebraic_numbers::anum & r); /** \brief Apply substitution [x_1 -> v_1, ..., x_n -> v_n]. That is, given p \in Z[x_1, ..., x_n, y_1, ..., y_m] return a polynomial r \in Z[y_1, ..., y_m]. Moreover forall a_1, ..., a_m in Q sign(r(a_1, ..., a_m)) == sign(p(v_1, ..., v_n, a_1, ..., a_m)) */ polynomial * substitute(polynomial const * p, var2mpq const & x2v); polynomial * substitute(polynomial const * p, unsigned xs_sz, var const * xs, mpq const * vs); /** \brief Apply substitution [x_1 -> v_1, ..., x_n -> v_n]. That is, given p \in Z[x_1, ..., x_n, y_1, ..., y_m] return polynomial r(y_1, ..., y_m) = p(v_1, ..., v_n, y_1, ..., y_m) in Z[y_1, ..., y_m]. */ polynomial * substitute(polynomial const * p, unsigned xs_sz, var const * xs, numeral const * vs); /** \brief Apply substitution [x -> v]. That is, given p \in Z[x, y_1, ..., y_m] return polynomial r(y_1, ..., y_m) = p(v, y_1, ..., y_m) in Z[y_1, ..., y_m]. */ polynomial * substitute(polynomial const * p, var x, numeral const & v) { return substitute(p, 1, &x, &v); } /** \brief Factorize the given polynomial p and store its factors in r. */ void factor(polynomial const * p, factors & r, factor_params const & params = factor_params()); /** \brief Dense univariate polynomial to sparse polynomial. */ polynomial * to_polynomial(unsigned sz, numeral const * p, var x); polynomial * to_polynomial(numeral_vector const & p, var x) { return to_polynomial(p.size(), p.c_ptr(), x); } /** \brief Make the leading monomial (with respect to graded lexicographical order) monic. \pre numeral_manager must be a field. */ polynomial * mk_glex_monic(polynomial const * p); /** \brief Return p'(y_1, ..., y_n, x) = p(y_1, ..., y_n, x + v) */ polynomial * translate(polynomial const * p, var x, numeral const & v); /** \brief Store p'(y_1, ..., y_n, x_1, ..., x_m) = p(y_1, ..., y_n, x_1 + v_1, ..., x_m + v_m) into r. */ void translate(polynomial const * p, unsigned xs_sz, var const * xs, numeral const * vs, polynomial_ref & r); void translate(polynomial const * p, var_vector const & xs, numeral_vector const & vs, polynomial_ref & r) { SASSERT(xs.size() == vs.size()); translate(p, xs.size(), xs.c_ptr(), vs.c_ptr(), r); } /** \brief Remove monomials m if it contains x^k and x2d[x] >= k */ polynomial * mod_d(polynomial const * p, var2degree const & x2d); /** \brief (exact) Pseudo division modulo var->degree mapping. */ void exact_pseudo_division_mod_d(polynomial const * p, polynomial const * q, var x, var2degree const & x2d, polynomial_ref & Q, polynomial_ref & R); void display(std::ostream & out, monomial const * m, display_var_proc const & proc = display_var_proc(), bool use_star = true) const; void display(std::ostream & out, polynomial const * p, display_var_proc const & proc = display_var_proc(), bool use_star = false) const; void display_smt2(std::ostream & out, polynomial const * p, display_var_proc const & proc = display_var_proc()) const; friend std::ostream & operator<<(std::ostream & out, polynomial_ref const & p) { p.m().display(out, p); return out; } }; typedef manager::factors factors; typedef manager::numeral numeral; typedef manager::numeral_manager numeral_manager; typedef manager::scoped_numeral scoped_numeral; typedef manager::scoped_numeral_vector scoped_numeral_vector; class scoped_set_z { manager & m; bool m_modular; scoped_numeral m_p; public: scoped_set_z(manager & _m):m(_m), m_modular(m.modular()), m_p(m.m()) { m_p = m.p(); m.set_z(); } ~scoped_set_z() { if (m_modular) m.set_zp(m_p); } }; class scoped_set_zp { manager & m; bool m_modular; scoped_numeral m_p; public: scoped_set_zp(manager & _m, numeral const & p):m(_m), m_modular(m.modular()), m_p(m.m()) { m_p = m.p(); m.set_zp(p); } scoped_set_zp(manager & _m, uint64 p):m(_m), m_modular(m.modular()), m_p(m.m()) { m_p = m.p(); m.set_zp(p); } ~scoped_set_zp() { if (m_modular) m.set_zp(m_p); else m.set_z(); } }; }; typedef polynomial::polynomial_ref polynomial_ref; typedef polynomial::polynomial_ref_vector polynomial_ref_vector; polynomial::polynomial * convert(polynomial::manager & sm, polynomial::polynomial * p, polynomial::manager & tm, polynomial::var x = polynomial::null_var, unsigned max_d = UINT_MAX); inline polynomial::polynomial * convert(polynomial::manager & sm, polynomial_ref const & p, polynomial::manager & tm) { SASSERT(&sm == &(p.m())); return convert(sm, p.get(), tm); } inline polynomial_ref neg(polynomial_ref const & p) { polynomial::manager & m = p.m(); return polynomial_ref(m.neg(p), m); } inline polynomial_ref operator-(polynomial_ref const & p) { polynomial::manager & m = p.m(); return polynomial_ref(m.neg(p), m); } inline polynomial_ref operator+(polynomial_ref const & p1, polynomial_ref const & p2) { polynomial::manager & m = p1.m(); return polynomial_ref(m.add(p1, p2), m); } inline polynomial_ref operator+(polynomial_ref const & p1, int n) { polynomial::manager & m = p1.m(); polynomial_ref tmp(m.mk_const(rational(n)), m); return p1 + tmp; } inline polynomial_ref operator+(polynomial_ref const & p1, rational const & n) { polynomial::manager & m = p1.m(); polynomial_ref tmp(m.mk_const(n), m); return p1 + tmp; } inline polynomial_ref operator+(polynomial::numeral const & n, polynomial_ref const & p) { polynomial::manager & m = p.m(); polynomial_ref tmp(m.mk_const(n), m); return p + tmp; } inline polynomial_ref operator+(polynomial_ref const & p, polynomial::numeral const & n) { return operator+(n, p); } inline polynomial_ref operator-(polynomial_ref const & p1, polynomial_ref const & p2) { polynomial::manager & m = p1.m(); return polynomial_ref(m.sub(p1, p2), m); } inline polynomial_ref operator-(polynomial_ref const & p1, int n) { polynomial::manager & m = p1.m(); polynomial_ref tmp(m.mk_const(rational(n)), m); return p1 - tmp; } inline polynomial_ref operator-(polynomial_ref const & p1, rational const & n) { polynomial::manager & m = p1.m(); polynomial_ref tmp(m.mk_const(n), m); return p1 - tmp; } inline polynomial_ref operator-(polynomial::numeral const & n, polynomial_ref const & p) { polynomial::manager & m = p.m(); polynomial_ref tmp(m.mk_const(n), m); return p - tmp; } inline polynomial_ref operator-(polynomial_ref const & p, polynomial::numeral const & n) { return operator-(n, p); } inline polynomial_ref operator*(polynomial_ref const & p1, polynomial_ref const & p2) { polynomial::manager & m = p1.m(); return polynomial_ref(m.mul(p1, p2), m); } inline polynomial_ref operator*(rational const & n, polynomial_ref const & p) { polynomial::manager & m = p.m(); return polynomial_ref(m.mul(n, p), m); } inline polynomial_ref operator*(int n, polynomial_ref const & p) { polynomial::manager & m = p.m(); return polynomial_ref(m.mul(rational(n), p), m); } inline polynomial_ref operator*(polynomial::numeral const & n, polynomial_ref const & p) { polynomial::manager & m = p.m(); return polynomial_ref(m.mul(n, p), m); } inline polynomial_ref operator*(polynomial_ref const & p, polynomial::numeral const & n) { return operator*(n, p); } inline bool eq(polynomial_ref const & p1, polynomial_ref const & p2) { polynomial::manager & m = p1.m(); return m.eq(p1, p2); } inline polynomial_ref operator^(polynomial_ref const & p, int k) { SASSERT(k > 0); polynomial::manager & m = p.m(); polynomial_ref r(m); m.pw(p, k, r); return polynomial_ref(r); } inline polynomial_ref operator^(polynomial_ref const & p, unsigned k) { return operator^(p, static_cast(k)); } inline polynomial_ref derivative(polynomial_ref const & p, polynomial::var x) { polynomial::manager & m = p.m(); return polynomial_ref(m.derivative(p, x), m); } inline bool is_zero(polynomial_ref const & p) { return p.m().is_zero(p); } inline bool is_const(polynomial_ref const & p) { return p.m().is_const(p); } inline bool is_linear(polynomial_ref const & p) { return p.m().is_linear(p); } inline bool is_univariate(polynomial_ref const & p) { return p.m().is_univariate(p); } inline unsigned total_degree(polynomial_ref const & p) { return p.m().total_degree(p); } inline polynomial::var max_var(polynomial_ref const & p) { return p.m().max_var(p); } inline unsigned degree(polynomial_ref const & p, polynomial::var x) { return p.m().degree(p, x); } inline unsigned size(polynomial_ref const & p) { return p.m().size(p); } inline polynomial_ref coeff(polynomial_ref const & p, polynomial::var x, unsigned k) { polynomial::manager & m = p.m(); return polynomial_ref(m.coeff(p, x, k), m); } inline polynomial_ref lc(polynomial_ref const & p, polynomial::var x) { polynomial::manager & m = p.m(); return polynomial_ref(m.coeff(p, x, degree(p, x)), m); } inline polynomial::numeral const & univ_coeff(polynomial_ref const & p, unsigned k) { return p.m().univ_coeff(p, k); } inline polynomial_ref content(polynomial_ref const & p, polynomial::var x) { polynomial::manager & m = p.m(); polynomial_ref r(m); m.content(p, x, r); return r; } inline polynomial_ref primitive(polynomial_ref const & p, polynomial::var x) { polynomial::manager & m = p.m(); polynomial_ref r(m); m.primitive(p, x, r); return r; } inline polynomial_ref gcd(polynomial_ref const & p, polynomial_ref const & q) { polynomial::manager & m = p.m(); polynomial_ref r(m); m.gcd(p, q, r); return r; } inline bool is_square_free(polynomial_ref const & p, polynomial::var x) { return p.m().is_square_free(p, x); } inline polynomial_ref square_free(polynomial_ref const & p, polynomial::var x) { polynomial::manager & m = p.m(); polynomial_ref r(m); m.square_free(p, x, r); return r; } inline bool is_square_free(polynomial_ref const & p) { return p.m().is_square_free(p); } inline polynomial_ref square_free(polynomial_ref const & p) { polynomial::manager & m = p.m(); polynomial_ref r(m); m.square_free(p, r); return r; } inline polynomial_ref compose_y(polynomial_ref const & p, polynomial::var y) { polynomial::manager & m = p.m(); return polynomial_ref(m.compose_y(p, y), m); } inline polynomial_ref compose_1_div_x(polynomial_ref const & p) { polynomial::manager & m = p.m(); return polynomial_ref(m.compose_1_div_x(p), m); } inline polynomial_ref compose_x_div_y(polynomial_ref const & p, polynomial::var y) { polynomial::manager & m = p.m(); return polynomial_ref(m.compose_x_div_y(p, y), m); } inline polynomial_ref compose_minus_x(polynomial_ref const & p) { polynomial::manager & m = p.m(); return polynomial_ref(m.compose_minus_x(p), m); } inline polynomial_ref compose(polynomial_ref const & p, polynomial_ref const & g) { polynomial::manager & m = p.m(); polynomial_ref r(m); m.compose(p, g, r); return polynomial_ref(r); } inline polynomial_ref compose_x_minus_y(polynomial_ref const & p, polynomial::var y) { polynomial::manager & m = p.m(); polynomial_ref r(m); m.compose_x_minus_y(p, y, r); return polynomial_ref(r); } inline polynomial_ref compose_x_plus_y(polynomial_ref const & p, polynomial::var y) { polynomial::manager & m = p.m(); polynomial_ref r(m); m.compose_x_plus_y(p, y, r); return polynomial_ref(r); } inline polynomial_ref compose_x_minus_c(polynomial_ref const & p, polynomial::numeral const & c) { polynomial::manager & m = p.m(); polynomial_ref r(m); m.compose_x_minus_c(p, c, r); return polynomial_ref(r); } inline polynomial_ref exact_div(polynomial_ref const & p, polynomial_ref const & q) { polynomial::manager & m = p.m(); return polynomial_ref(m.exact_div(p, q), m); } inline polynomial_ref normalize(polynomial_ref const & p) { polynomial::manager & m = p.m(); return polynomial_ref(m.normalize(p), m); } inline bool sqrt(polynomial_ref const & p, polynomial_ref & r) { return p.m().sqrt(p, r); } inline polynomial_ref exact_pseudo_remainder(polynomial_ref const & p, polynomial_ref const & q, polynomial::var x) { polynomial::manager & m = p.m(); polynomial_ref r(m); m.exact_pseudo_remainder(p, q, x, r); return polynomial_ref(r); } inline polynomial_ref exact_pseudo_remainder(polynomial_ref const & p, polynomial_ref const & q) { return exact_pseudo_remainder(p, q, max_var(q)); } inline polynomial_ref pseudo_remainder(polynomial_ref const & p, polynomial_ref const & q, polynomial::var x, unsigned & d) { polynomial::manager & m = p.m(); polynomial_ref r(m); m.pseudo_remainder(p, q, x, d, r); return polynomial_ref(r); } inline polynomial_ref pseudo_remainder(polynomial_ref const & p, polynomial_ref const & q, unsigned & d) { return pseudo_remainder(p, q, max_var(q), d); } inline polynomial_ref exact_pseudo_division(polynomial_ref const & p, polynomial_ref const & q, polynomial::var x, polynomial_ref & R) { polynomial::manager & m = p.m(); polynomial_ref Q(m); m.exact_pseudo_division(p, q, x, Q, R); return polynomial_ref(Q); } inline polynomial_ref exact_pseudo_division(polynomial_ref const & p, polynomial_ref const & q, polynomial_ref & R) { return exact_pseudo_division(p, q, max_var(q), R); } inline polynomial_ref pseudo_division(polynomial_ref const & p, polynomial_ref const & q, polynomial::var x, unsigned & d, polynomial_ref & R) { polynomial::manager & m = p.m(); polynomial_ref Q(m); m.pseudo_division(p, q, x, d, Q, R); return polynomial_ref(Q); } inline polynomial_ref pseudo_division(polynomial_ref const & p, polynomial_ref const & q, unsigned & d, polynomial_ref & R) { return pseudo_division(p, q, max_var(q), d, R); } inline polynomial_ref quasi_resultant(polynomial_ref const & p, polynomial_ref const & q, unsigned x) { polynomial::manager & m = p.m(); polynomial_ref r(m); m.quasi_resultant(p, q, x, r); return polynomial_ref(r); } inline polynomial_ref resultant(polynomial_ref const & p, polynomial_ref const & q, unsigned x) { polynomial::manager & m = p.m(); polynomial_ref r(m); m.resultant(p, q, x, r); return polynomial_ref(r); } inline polynomial_ref discriminant(polynomial_ref const & p, unsigned x) { polynomial::manager & m = p.m(); polynomial_ref r(m); m.discriminant(p, x, r); return polynomial_ref(r); } inline bool is_pos(polynomial_ref const & p) { return p.m().is_pos(p); } inline bool is_neg(polynomial_ref const & p) { return p.m().is_neg(p); } inline bool is_nonpos(polynomial_ref const & p) { return p.m().is_nonpos(p); } inline bool is_nonneg(polynomial_ref const & p) { return p.m().is_nonneg(p); } inline void factor(polynomial_ref const & p, polynomial::factors & r, polynomial::factor_params const & params = polynomial::factor_params()) { p.m().factor(p, r, params); } std::ostream & operator<<(std::ostream & out, polynomial_ref_vector const & seq); #endif