// TODO: Add licence // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // // // Author(s) : Arno Eigenwillig // Michael Seel // Michael Hemmer // // ============================================================================ // TODO: The comments are all original EXACUS comments and aren't adapted. So // they may be wrong now. /*! \file NiX/Polynomial.h * \brief Defines class NiX::Polynomial. * * Polynomials in one variable (or more, by recursion) */ #ifndef CGAL_POLYNOMIAL_H #define CGAL_POLYNOMIAL_H #include #include #include #include #include #include #include #include #include //#include #include #include #ifdef CGAL_USE_LEDA #include #endif // CGAL_USE_LEDA #include #include #include #include #include // #include CGAL_BEGIN_NAMESPACE // TODO: copied from EXACUS/NumeriX/include/NiX/number_type_utils.h template inline NT ipower(const NT& base, int expn) { // compute base^expn using square-and-multiply CGAL_precondition(expn >= 0); // handle trivial cases efficiently if (expn == 0) return NT(1); if (expn == 1) return base; // find the most significant non-zero bit of expn int e = expn, msb = 0; while (e >>= 1) msb++; // computing base^expn by square-and-multiply NT res = base; int b = 1<>= 1) { // is there another bit right of what we saw so far? res *= res; if (expn & b) res *= base; } return res; } // TODO: END included from number_type_utils.h // Internally, Polynomials also need this: //! used internally for data exchanged between nesting levels of polynomials // this traits-class provides // a) poly_nesting_depth: a counter for identifying a polynomials nesting level // b) Innermost_coefficient: a type which defines the numbertype of the // innermost nesting level, which is not a polynomial itself // c) Innermost_lcoeff: returns the leading coefficient of the polynomial in its // common sense // d) Innermost_coefficient_to_polynomial: transforms an innermost // numbertype into a polynomial like a typecast // fwd Polynomial_traits_d template class Polynomial_traits_d; namespace INTERN_POLYNOMIAL { template Polynomial canonicalize_polynomial_(Polynomial p, CGAL::Tag_true) { typedef Polynomial POLY; typedef typename Polynomial_traits_d::Innermost_coefficient IC; typename Polynomial_traits_d::Innermost_leading_coefficient ilcoeff; typename Algebraic_extension_traits::Normalization_factor nfac; IC tmp = nfac(ilcoeff(p)); if(tmp != IC(1)){ p *= POLY(tmp); } remove_scalar_factor(p); p /= p.unit_part(); p.simplify_coefficients(); CGAL_postcondition(nfac(ilcoeff(p)) == IC(1)); return p; }; template Polynomial canonicalize_polynomial_(Polynomial p, CGAL::Tag_false) { remove_scalar_factor(p); p /= p.unit_part(); p.simplify_coefficients(); return p; }; } // namespace INTERN_POLYNOMIAL /*! \ingroup NiX_Polynomial * \relates NiX::Polynomial * * \brief divide a polynomial \c p by its Scalar_factor and Unit_part * * ...making it a canonical representative of all its constant multiples. * Depending on the number type of the innermost coefficient, this * function does * a) dividing \c p by the leading coefficient in fields * b) dividing \c p by the gcd of all coefficients in UFDomains * c) extending the leading coefficient in Sqrt_extensions, so it * becomes integral, and dividing \c p by the gcd of all scalars * \see NiX/Sqrt_extension.h * The result is uniquely determined by setting the leading coefficient * to the minimal integral rational. */ template inline Polynomial canonicalize_polynomial(const Polynomial& p) { typedef Polynomial POLY; typedef typename Polynomial_traits_d::Innermost_coefficient IC; typedef typename Algebraic_extension_traits::Is_extended Is_extended; if (p.is_zero()) return p; return canonicalize_polynomial_(p, Is_extended()); }; namespace INTERN_POLYNOMIAL { // Polynomial / Polynomial - coefficient type is extended template Polynomial div_utcf_( Polynomial f, const Polynomial& g, bool, CGAL::Tag_true) { typedef Polynomial POLY; typedef typename Polynomial_traits_d::Innermost_coefficient IC; typename Polynomial_traits_d::Innermost_leading_coefficient ilcoeff; typename Polynomial_traits_d::Innermost_coefficient_to_polynomial ictp; typename Polynomial_traits_d::Innermost_coefficient_begin begin; typename Polynomial_traits_d::Innermost_coefficient_end end; typename Algebraic_extension_traits::Denominator_for_algebraic_integers dfai; IC tmp = ilcoeff(g); tmp *= dfai(begin(g), end(g)); f *= ictp(tmp); return canonicalize_polynomial(f / g); } // Polynomial / Polynomial - coefficient type is NOT extended template Polynomial div_utcf_( Polynomial f, const Polynomial& g, bool is_canonicalized, CGAL::Tag_false) { typedef Polynomial POLY; typedef typename Polynomial_traits_d::Innermost_coefficient IC; typename Polynomial_traits_d::Innermost_leading_coefficient ilcoeff; typename Polynomial_traits_d::Innermost_coefficient_to_polynomial ictp; if (!is_canonicalized) { IC lcoeff = ilcoeff(g); f *= ictp(lcoeff); } return canonicalize_polynomial(f / g); } // Polynomial / NT - NT is already the coefficient type and is extended template Polynomial div_utcf_NT_is_IC( Polynomial f, const NT& g, CGAL::Tag_false) { return canonicalize_polynomial(f); } // Polynomial / NT - NT is again a polynomial - coefficient type is extended template Polynomial div_utcf_NT_is_IC( Polynomial f, const NT& g, Is_nested) { typedef Polynomial POLY; typedef typename Polynomial_traits_d::Innermost_coefficient IC; typename Polynomial_traits_d::Innermost_leading_coefficient ilcoeff; typename Polynomial_traits_d::Innermost_coefficient_to_polynomial ictp; typename Polynomial_traits_d::Innermost_coefficient_begin begin; typename Polynomial_traits_d::Innermost_coefficient_end end; typename Algebraic_extension_traits::Denominator_for_algebraic_integers dfai; IC tmp = ilcoeff(g); tmp *= dfai(begin(g), end(g)); f *= ictp(tmp); return canonicalize_polynomial(f / g); } // Polynomial / NT - coefficient type is extended template inline Polynomial div_utcf_( const Polynomial& f, const NT& g, bool, CGAL::Tag_true) { typedef CGAL::Boolean_tag< (Polynomial_traits_d::d >= 2) > Is_nested; return div_utcf_NT_is_IC(f, g, Is_nested() ); } // Polynomial / NT - coefficient type is NOT extended template Polynomial div_utcf_( Polynomial f, const NT& g, bool is_canonicalized, CGAL::Tag_false) { typedef Polynomial POLY; typedef typename Polynomial_traits_d::Innermost_coefficient IC; typename Polynomial_traits_d::Innermost_leading_coefficient ilcoeff; if (!is_canonicalized) { IC lcoeff = ilcoeff(g); f *= POLY(lcoeff); } return canonicalize_polynomial(f / g); } } // namespace INTERN_POLYNOMIAL //! divide \c f by \c g with respect to constant factors /*! This function provides a division of two polynomials, which takes * no care of constant factors of the innermost scalar type. * The boolean parameter decides whether the divisor has already been * canonicalized due to running time optimisation. * The result is made unique by canonicalizing it. */ template inline Polynomial div_utcf( const Polynomial& f, const Polynomial& g, bool is_canonicalized = false) { typedef Polynomial POLY; typedef typename Polynomial_traits_d::Innermost_coefficient IC; typedef typename Algebraic_extension_traits::Is_extended Is_extended; return div_utcf_(f, g, is_canonicalized, Is_extended()); } //! overloaded version for divisors with a by one lower nesting level template inline Polynomial div_utcf( const Polynomial& f, const NT& g, bool is_canonicalized = false) { typedef Polynomial POLY; typedef typename Polynomial_traits_d::Innermost_coefficient IC; typedef typename Algebraic_extension_traits::Is_extended Is_extended; return div_utcf_(f, g, is_canonicalized, Is_extended()); } // // Arithmetic Operators, Part III: // implementation of unary operators and three-address arithmetic // by friend functions // template inline Polynomial operator + (const Polynomial& p) { CGAL_precondition(p.degree() >= 0); return p; } template inline Polynomial operator - (const Polynomial& p) { CGAL_precondition(p.degree()>=0); Polynomial res(p.coeffs().begin(),p.coeffs().end()); typename Polynomial::iterator it, ite=res.coeffs().end(); for(it=res.coeffs().begin(); it!=ite; ++it) *it = -*it; return res; } template inline Polynomial operator + (const Polynomial& p1, const Polynomial& p2) { typedef typename Polynomial::size_type size_type; CGAL_precondition(p1.degree()>=0 && p2.degree()>=0); bool p1d_smaller_p2d = p1.degree() < p2.degree(); int min,max,i; if (p1d_smaller_p2d) { min = p1.degree(); max = p2.degree(); } else { max = p1.degree(); min = p2.degree(); } INTERN_POLYNOMIAL::Creation_tag TAG; Polynomial p(TAG, size_type(max + 1)); for (i = 0; i <= min; ++i ) p.coeff(i) = p1[i]+p2[i]; if (p1d_smaller_p2d) for (; i <= max; ++i ) p.coeff(i)=p2[i]; else /* p1d >= p2d */ for (; i <= max; ++i ) p.coeff(i)=p1[i]; p.reduce(); return p; } template inline Polynomial operator - (const Polynomial& p1, const Polynomial& p2) { typedef typename Polynomial::size_type size_type; CGAL_precondition(p1.degree()>=0 && p2.degree()>=0); bool p1d_smaller_p2d = p1.degree() < p2.degree(); int min,max,i; if (p1d_smaller_p2d) { min = p1.degree(); max = p2.degree(); } else { max = p1.degree(); min = p2.degree(); } INTERN_POLYNOMIAL::Creation_tag TAG; Polynomial p(TAG, size_type(max + 1)); for (i = 0; i <= min; ++i ) p.coeff(i)=p1[i]-p2[i]; if (p1d_smaller_p2d) for (; i <= max; ++i ) p.coeff(i)= -p2[i]; else /* p1d >= p2d */ for (; i <= max; ++i ) p.coeff(i)= p1[i]; p.reduce(); return p; } template inline Polynomial operator * (const Polynomial& p1, const Polynomial& p2) { typedef typename Polynomial::size_type size_type; CGAL_precondition(p1.degree()>=0 && p2.degree()>=0); INTERN_POLYNOMIAL::Creation_tag TAG; Polynomial p(TAG, size_type(p1.degree()+p2.degree()+1) ); // initialized with zeros for (int i=0; i <= p1.degree(); ++i) for (int j=0; j <= p2.degree(); ++j) p.coeff(i+j) += (p1[i]*p2[j]); p.reduce(); return p; } #ifndef NiX_POLY_USE_SLOW_DIVISION template inline Polynomial operator / (const Polynomial& p1, const Polynomial& p2) { typedef Algebraic_structure_traits< Polynomial > AST; // Precondition: q with p1 == p2 * q must exist within NT[x]. // If this holds, we can perform Euclidean division even over a ring NT // Proof: The quotients of each division that occurs are precisely // the terms of q and hence in NT. CGAL_precondition(!p2.is_zero()); if (p1.is_zero()) return p1; Polynomial q, r; Polynomial::euclidean_division(p1, p2, q, r); // TODO: Replace by correct Makro CGAL_postcondition( !AST::Is_exact::value || p2 * q == p1); return q; } #else template inline Polynomial operator / (const Polynomial& p1, const Polynomial& p2) { typedef typename Algebraic_structure_traits::Algebric_structure_tag Algebra_type; return division(p1, p2, Algebra_type()); } template inline Polynomial division(const Polynomial& p1, const Polynomial& p2, Field_tag) { typedef Algebraic_structure_traits AST; CGAL_precondition(!p2.is_zero()); if (p1.is_zero()) return p1; Polynomial q,r; Polynomial::euclidean_division(p1,p2,q,r); CGAL_postcondition( !AST::Is_exact::value || p2 * q == p1); return q; } template inline Polynomial division(const Polynomial& p1, const Polynomial& p2, Integral_domain_tag) { typedef Algebraic_structure_traits AST; CGAL_precondition(!p2.is_zero()); if ( p1.is_zero() ) return p1; Polynomial q,r; NT D; Polynomial::pseudo_division(p1,p2,q,r,D); q/=D; CGAL_postcondition( !AST::Is_exact::value || p2 * q == p1); return q; } #endif // NiX_POLY_USE_SLOW_DIVISION // // Arithmetic Operators, Part IV: // Mixed-mode three-address arithmetic on top of two-address operators // // lefthand side template inline Polynomial operator + (const NT& num, Polynomial p2) { p2 += num; return p2; } template inline Polynomial operator - (const NT& num, Polynomial p2) { p2 -= num; return -p2; } template inline Polynomial operator * (const NT& num, Polynomial p2) { p2 *= num; return p2; } template inline Polynomial operator / (const NT& num, const Polynomial& p2) { CGAL_precondition(p2.degree() == 0); CGAL_precondition(p2[0] != NT(0)); typename Algebraic_structure_traits::Integral_division idiv; return Polynomial(idiv(num, p2[0])); } // righthand side template inline Polynomial operator + (Polynomial p1, const NT& num) { p1 += num; return p1; } template inline Polynomial operator - (Polynomial p1, const NT& num) { p1 -= num; return p1; } template inline Polynomial operator * (Polynomial p1, const NT& num) { p1 *= num; return p1; } template inline Polynomial operator / (Polynomial p1, const NT& num) { p1 /= num; return p1; } // // Comparison Operators // // polynomials only template inline bool operator == (const Polynomial& p1, const Polynomial& p2) { CGAL_precondition(p1.degree() >= 0); CGAL_precondition(p2.degree() >= 0); if (p1.is_identical(p2)) return true; if (p1.degree() != p2.degree()) return false; for (int i = p1.degree(); i >= 0; i--) if (p1[i] != p2[i]) return false; return true; } template inline bool operator != (const Polynomial& p1, const Polynomial& p2) { return !(p1 == p2); } template inline bool operator < (const Polynomial& p1, const Polynomial& p2) { return ( p1.compare(p2) < 0 ); } template inline bool operator <= (const Polynomial& p1, const Polynomial& p2) { return ( p1.compare(p2) <= 0 ); } template inline bool operator > (const Polynomial& p1, const Polynomial& p2) { return ( p1.compare(p2) > 0 ); } template inline bool operator >= (const Polynomial& p1, const Polynomial& p2) { return ( p1.compare(p2) >= 0 ); } // mixed-mode, lefthand side template inline bool operator == (const NT& num, const Polynomial& p) { CGAL_precondition(p.degree() >= 0); return p.degree() == 0 && p[0] == num; } template inline bool operator != (const NT& num, const Polynomial& p) { return !(num == p);} template inline bool operator < (const NT& num, const Polynomial& p) { return ( p.compare(num) > 0 );} template inline bool operator <= (const NT& num, const Polynomial& p) { return ( p.compare(num) >= 0 );} template inline bool operator > (const NT& num, const Polynomial& p) { return ( p.compare(num) < 0 );} template inline bool operator >= (const NT& num, const Polynomial& p) { return ( p.compare(num) <= 0 );} // mixed-mode, righthand side template inline bool operator == (const Polynomial& p, const NT& num) { return num == p; } template inline bool operator != (const Polynomial& p, const NT& num) { return !(num == p); } template inline bool operator < (const Polynomial& p, const NT& num) { return ( p.compare(num) < 0 );} template inline bool operator <= (const Polynomial& p, const NT& num) { return ( p.compare(num) <= 0 );} template inline bool operator > (const Polynomial& p, const NT& num) { return ( p.compare(num) > 0 );} template inline bool operator >= (const Polynomial& p, const NT& num) { return ( p.compare(num) >= 0 );} // // I/O Operations // /*! \ingroup NiX_Polynomial * \relates NiX::Polynomial * \brief output \c p to \c os * * Output \c p in a format as specified by * \c LiS::get_mode(os), see \link LiS_io LiS I/O Support \endlink. * Currently, the output for \c LiS::IO::BINARY happens to be * identical to \c LiS::IO::ASCII. */ template std::ostream& operator << (std::ostream& os, const Polynomial& p) { switch(CGAL::get_mode(os)) { case CGAL::IO::PRETTY: p.output_maple(os); break; default: p.output_ascii(os); break; } return os; } /*! \ingroup NiX_Polynomial * \relates NiX::Polynomial * \brief try to read a polynomial from \c is into \c p * * \c is must be in a mode that supports input of polynomials * (\c LiS::IO::ASCII or \c LiS::IO::BINARY) and the input from * \c is must have the format of output to a stream of the same mode. */ template std::istream& operator >> (std::istream& is, Polynomial& p) { CGAL_precondition(!CGAL::is_pretty(is)); p = Polynomial::input_ascii(is); return is; } template inline void print_maple_monomial(std::ostream& os, const NT& coeff, const char *var, int expn) { if (expn == 0 || coeff != NT(1)) { os << CGAL::oformat(coeff, Parens_as_product_tag()); if (expn >= 1) os << "*"; } if (expn >= 1) { os << var; if (expn > 1) os << "^" << CGAL::oformat(expn); } } template void Polynomial::output_maple(std::ostream& os) const { const Polynomial& p = *this; const char *varname; char vnbuf[42]; // use variable names x, y, z, w1, w2, w3, ... if (Polynomial_traits_d::d < 3) { static const char *varnames[] = { "x", "y", "z" }; varname = varnames[Polynomial_traits_d::d]; } else { sprintf(vnbuf, "w%d", Polynomial_traits_d::d - 2); varname = vnbuf; } int i = p.degree(); print_maple_monomial(os, p[i], varname, i); while (--i >= 0) { if (p[i] != NT(0)) { os << " + "; print_maple_monomial(os, p[i], varname, i); } } } template void Polynomial::output_ascii(std::ostream &os) const { const Polynomial &p = *this; if (p.is_zero()) { os << "P[0 (0," << oformat(NT(0)) << ")]"; return; } os << "P[" << oformat(p.degree()); for (int i = 0; i <= p.degree(); i++) { if (p[i] != NT(0)) os << "(" << CGAL::oformat(i) << "," << CGAL::oformat(p[i]) << ")"; } os << "]"; } template void Polynomial::output_benchmark(std::ostream &os) const { const Polynomial &p = *this; if (p.is_zero()) { os << "Polynomial_1(0)"; return; } os << "Polynomial_1("; for (int i = 0; i <= p.degree(); i++) { os << CGAL::oformat(p[i]); if (i != p.degree()) { os << ","; } } os << ")"; } // Moved to internal namespace because of name clashes // TODO: Is this OK? namespace INTERN_POLYNOMIAL { inline static void swallow(std::istream &is, char d) { char c; do c = is.get(); while (isspace(c)); if (c != d) CGAL_assertion_msg( false, "input error: unexpected character in polynomial"); } } // namespace INTERN_POLYNOMIAL template Polynomial Polynomial::input_ascii(std::istream &is) { char c; int degr = -1, i; INTERN_POLYNOMIAL::swallow(is, 'P'); INTERN_POLYNOMIAL::swallow(is, '['); is >> CGAL::iformat(degr); if (degr < 0) { CGAL_assertion_msg( false, "input error: negative degree of polynomial specified"); } INTERN_POLYNOMIAL::Creation_tag TAG; Polynomial p(TAG, degr+1); do c = is.get(); while (isspace(c)); do { if (c != '(') CGAL_assertion_msg( false, "input error: ( expected"); is >> CGAL::iformat(i); if (!(i >= 0 && i <= degr && p[i] == NT(0))) { CGAL_assertion_msg( false, "input error: invalid exponent in polynomial"); }; INTERN_POLYNOMIAL::swallow(is, ','); is >> CGAL::iformat(p.coeff(i)); INTERN_POLYNOMIAL::swallow(is, ')'); do c = is.get(); while (isspace(c)); } while (c != ']'); p.reduce(); p.simplify_coefficients(); return p; } // // Non-Member Functions // //! return an upper bound on the absolute value of all real roots of \c P. /*! The upper bound is a power of two. Only works for univariate polynomials. * \pre \c NT must be \c RealComparable. * \relates NiX::Polynomial */ template NT weak_upper_root_bound(const Polynomial& P) { // code comes from Kurt Mehlhorn // see [Mignotte, 1992], p.144 for a proof CGAL_precondition(Polynomial_traits_d::d == 0); typename Real_embeddable_traits::Abs abs; const int n = P.degree(); NT x(1); NT val; for (;;) { val = -abs(P[n]); for (int i = n-1; i >= 0; i--) { val = val*x + abs(P[i]); } if (val < NT(0)) return x; x *= NT(2); } } //! return the number of sign variations in the coefficient sequence of \c P. /*! This is the number of sign changes (+ to - or - to +) in the * coefficient sequence of the polynomial, ignoring zeroes. * Only meaningful for univariate polynomials. * \pre \c NT must be \c RealComparable. * \relates NiX::Polynomial */ template int sign_variations(const Polynomial& P) { typename Real_embeddable_traits::Sign sign; const int n = P.degree(); int variations = 0; int old_sign = sign(P[n]); // never zero unless P is zero for (int i = n-1; i >= 0; i--) { int s = sign(P[i]); if (s == 0) continue; if (old_sign != s) { old_sign = s; variations++; } } return variations; } // // Algebraically non-trivial operations // // 1) Euclidean and pseudo-division of polynomials // (implementation of static member functions) template void Polynomial::euclidean_division( const Polynomial& f, const Polynomial& g, Polynomial& q, Polynomial& r) { typedef Algebraic_structure_traits AST; typename AST::Integral_division idiv; int fd = f.degree(), gd = g.degree(); if ( fd < gd ) { q = Polynomial(NT(0)); r = f; CGAL_postcondition( !AST::Is_exact::value || f == q*g + r); return; } // now we know fd >= gd int qd = fd-gd, delta = qd+1, rd = fd; INTERN_POLYNOMIAL::Creation_tag TAG; q = Polynomial(TAG, delta ); r = f; r.copy_on_write(); while ( qd >= 0 ) { NT Q = idiv(r[rd], g[gd]); q.coeff(qd) += Q; r.minus_offsetmult(g,Q,qd); r.simplify_coefficients(); if (r.is_zero()) break; rd = r.degree(); qd = rd - gd; } q.simplify_coefficients(); CGAL_postcondition( !AST::Is_exact::value || f == q*g + r); } #ifndef NiX_POLY_USE_OLD_PSEUDODIV template void Polynomial::pseudo_division( const Polynomial& A, const Polynomial& B, Polynomial& Q, Polynomial& R, NT& D) { typedef Algebraic_structure_traits AST; // pseudo-division with incremental multiplication by lcoeff(B) // see [Cohen, 1993], algorithm 3.1.2 CGAL_precondition(!B.is_zero()); int delta = A.degree() - B.degree(); if (delta < 0 || A.is_zero()) { Q = Polynomial(NT(0)); R = A; D = NT(1); CGAL_postcondition( !AST::Is_exact::value || Polynomial(D)*A == Q*B + R); return; } const NT d = B.lcoeff(); int e = delta + 1; D = ipower(d, e); INTERN_POLYNOMIAL::Creation_tag TAG; Q = Polynomial(TAG, e); R = A; R.copy_on_write(); R.simplify_coefficients(); // invariant: d^(deg(A)-deg(B)+1 - e) * A == Q*B + R do { // here we have delta == R.degree() - B.degree() >= 0 && R != 0 NT lR = R.lcoeff(); for (int i = delta+1; i <= Q.degree(); i++) Q.coeff(i) *= d; Q.coeff(delta) = lR; // Q = d*Q + lR * X^delta for (int i = 0; i <= R.degree(); i++) R.coeff(i) *= d; R.minus_offsetmult(B, lR, delta); // R = d*R - lR * X^delta * B R.simplify_coefficients(); e--; delta = R.degree() - B.degree(); } while (delta > 0 || delta == 0 && !R.is_zero()); // funny termination condition because deg(0) = 0, not -\infty NT q = ipower(d, e); Q *= q; Q.simplify_coefficients(); R *= q; R.simplify_coefficients(); CGAL_postcondition( !AST::Is_exact::value || Polynomial(D)*A == Q*B + R); } #else template void Polynomial::pseudo_division( const Polynomial& f, const Polynomial& g, Polynomial& q, Polynomial& r, NT& D) { typedef Algebraic_structure_traits AST; // pseudo-division with one big multiplication with lcoeff(g)^{...} typename Algebraic_structure_traits::Integral_division idiv; int fd=f.degree(), gd=g.degree(); if ( fd < gd ) { q = Polynomial(NT(0)); r = f; D = NT(1); CGAL_postcondition( !AST::Is_exact::value || Polynomial(D)*f==q*g+r); return; } // now we know rd >= gd int qd = fd-gd, delta = qd+1, rd = fd; INTERN_POLYNOMIAL::Creation_tag TAG; q = Polynomial(TAG, delta ); NT G = g[gd]; // highest order coeff of g D = ipower(G, delta); Polynomial res = D*f; res.simplify_coefficients(); while ( qd >= 0 ) { NT F = res[rd]; // highest order coeff of res NT t = idiv(F, G); // sure to be integral by multiplication of D q.coeff(qd) = t; // store q coeff res.minus_offsetmult(g,t,qd); res.simplify_coefficients(); if (res.is_zero()) break; rd = res.degree(); qd = rd - gd; } r = res; // already simplified q.simplify_coefficients(); CGAL_postcondition( !AST::Is_exact::value || Polynomial(D)*f==q*g+r); } #endif // NiX_POLY_USE_OLD_PSEUDODIV // The following former parts of Polynomial.h have been moved to the new files // (items 2,3,5) and (item 4): // // 2) gcd (basic form without cofactors) // 3) extended gcd computation (with cofactors) // 4) resultant computation from polynomial remainder sequences (PRS) // 5) square-free factorization // This subroutine has been retained here for use in both new files. namespace INTERN_POLYNOMIAL { template inline void hgdelta_update(NT& h, const NT& g, int delta) { typename Algebraic_structure_traits::Integral_division idiv; // compute h = h^(1-delta) * g^delta switch (delta) { case 0: // h = h; break; case 1: h = g; break; default: h = idiv(ipower(g, delta), ipower(h, delta-1)); break; } } } // namespace INTERN_POLYNOMIAL // } // namespace NiX CGAL_END_NAMESPACE #include // used above for NT_traits::Gcd #include // for compatibility CGAL_BEGIN_NAMESPACE // Cofraction_traits added by Michael Hemmer /*namespace NiX{ namespace Intern{ template class Cofraction_traits_base; template class Cofraction_traits_base, TAG > { typedef NT_ NT; public: typedef Polynomial Numerator_type; typedef ::LiS::False_tag Is_composable; typedef ::LiS::Null_tag Denominator_type; typedef ::LiS::Null_tag Type; typedef ::LiS::Null_tag Compose; }; template class Cofraction_traits_base, LiS::True_tag > { typedef NT_ NT; typedef NiX::Cofraction_traits CFT_NT; public: typedef Polynomial Numerator_type; typedef ::LiS::True_tag Is_composable; typedef typename CFT_NT::Denominator_type Denominator_type; typedef Polynomial Type; class Compose { public: //! first argument type typedef Numerator_type first_argument_type; //! second argument type typedef Denominator_type second_argument_type; //! result type typedef Type result_type; //! Compose fraction Type operator() (Numerator_type num, Denominator_type den = Denominator_type(1)){ Type tmp1; NiX::convert_to(num,tmp1); Type tmp2; NiX::convert_to(den,tmp2); return tmp1/tmp2; } }; }; } //namespace Intern */ /*! \ingroup NiX_Cofraction_traits_specs * \brief Specialization of Cofraction_traits for NiX::Polynomial. */ //template /*class Cofraction_traits > : public Intern::Cofraction_traits_base< Polynomial, typename Cofraction_traits::Is_composable>{ //nothing new };*/ template struct Needs_parens_as_product >{ typedef Polynomial Poly; bool operator()(const Poly& x){ return (x.degree() > 0); } }; // COERCION_TRAITS BEGIN //Coercion_traits_polynomial----------------------------------- // If there is a Polynomial_traits, valid for more than one Polynomial // class this part should be adapted, using a Polynomial_traits // and the nesting_depth template class Coercion_traits_for_level, Polynomial, CTL_POLYNOMIAL >{ typedef Coercion_traits CT; public: typedef CGAL::Tag_true Are_explicit_interoperable; typedef CGAL::Tag_false Are_implicit_interoperable; typedef Polynomial Type; struct Cast{ typedef Type result_type; Type operator()(const Polynomial& poly) const { typename CT::Cast cast; return Type(::boost::make_transform_iterator(poly.begin(),cast), ::boost::make_transform_iterator(poly.end() ,cast)); } Type operator()(const Polynomial& poly) const { typename CT::Cast cast; return Type(::boost::make_transform_iterator(poly.begin(),cast), ::boost::make_transform_iterator(poly.end() ,cast)); } }; }; template class Coercion_traits_for_level,B ,CTL_POLYNOMIAL >{ typedef Coercion_traits CT; public: typedef CGAL::Tag_true Are_explicit_interoperable; typedef CGAL::Tag_false Are_implicit_interoperable; typedef Polynomial Type; struct Cast{ typedef Type result_type; Type operator()(const Polynomial& poly) const { typename CT::Cast cast; return Type(::boost::make_transform_iterator(poly.begin(),cast), ::boost::make_transform_iterator(poly.end() ,cast)); } Type operator()(const B& x) const { typename CT::Cast cast; return Type(cast(x)); } }; }; template class Coercion_traits_for_level,CTL_POLYNOMIAL > :public Coercion_traits_for_level,B,CTL_POLYNOMIAL > {}; // COERCION_TRAITS END CGAL_END_NAMESPACE #include #include // // trailing documentation // // Literature reference // // [Akritas, 1989] // Alkiviadis G. Akritas // Elements of Computer Algebra With Applications // Wiley, New York, 1989. // // [Cohen, 1993] // Cohen, Henri // A Course in Computational Algebraic Number Theory // Springer GTM 138, 1993 // // [Cox et al, 1997] // David Cox; John Little; Donal O'Shea // Ideals, Varieties, and Algorithms // 2nd ed., Springer UTM, 1997 // // [Geddes et al, 1992] // Geddes, Keith O. and Czapor, Stephen R. and Labahn, George // Algorithms for Computer Algebra // Kluwer, 1992 // // [Mignotte, 1992] // Mignotte, Maurice // Mathematics for Computer Algebra // Springer, 1992 // // [PARI] // (a computer algebra system by Henri Cohen and collaborators) // http://www.parigp-home.de/ #endif // NiX_POLYNOMIAL_H // EOF