cgal/Polynomial/include/CGAL/Polynomial.h

1082 lines
34 KiB
C++

// 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 <arno@mpi-inf.mpg.de>
// Michael Seel <seel@mpi-inf.mpg.de>
// Michael Hemmer <hemmer@informatik.uni-mainz.de>
//
// ============================================================================
// 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 <cstdarg>
#include <cctype>
#include <vector>
#include <iostream>
#include <CGAL/basic.h>
#include <CGAL/Handle_with_policy.h>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/mpl/if.hpp>
#include <CGAL/Flattening_iterator.h>
//#include <NiX/Modular.h>
#include <CGAL/Exponent_vector.h>
#include <boost/static_assert.hpp>
#ifdef CGAL_USE_LEDA
#include <LEDA/array.h>
#endif // CGAL_USE_LEDA
#include <CGAL/Polynomial/Polynomial_type.h>
#include <CGAL/Polynomial/Algebraic_structure_traits.h>
#include <CGAL/Polynomial/Real_embeddable_traits.h>
#include <CGAL/Polynomial/Fraction_traits.h>
#include <CGAL/Polynomial/Scalar_factor_traits.h>
// #include <CGAL/Polynomial/Modular_traits.h>
CGAL_BEGIN_NAMESPACE
// TODO: copied from EXACUS/NumeriX/include/NiX/number_type_utils.h
template <typename NT>
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<<msb;
while (b >>= 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 <typename Polynomial_d> class Polynomial_traits_d;
namespace INTERN_POLYNOMIAL {
template <class NT>
Polynomial<NT> canonicalize_polynomial_(Polynomial<NT> p, CGAL::Tag_true)
{
typedef Polynomial<NT> POLY;
typedef typename Polynomial_traits_d<POLY>::Innermost_coefficient IC;
typename Polynomial_traits_d<POLY>::Innermost_leading_coefficient ilcoeff;
typename Algebraic_extension_traits<IC>::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 <class NT>
Polynomial<NT> canonicalize_polynomial_(Polynomial<NT> 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 <class NT> inline
Polynomial<NT> canonicalize_polynomial(const Polynomial<NT>& p)
{
typedef Polynomial<NT> POLY;
typedef typename Polynomial_traits_d<POLY>::Innermost_coefficient IC;
typedef typename Algebraic_extension_traits<IC>::Is_extended Is_extended;
if (p.is_zero()) return p;
return canonicalize_polynomial_(p, Is_extended());
};
namespace INTERN_POLYNOMIAL {
// Polynomial<NT> / Polynomial<NT> - coefficient type is extended
template <class NT>
Polynomial<NT> div_utcf_(
Polynomial<NT> f, const Polynomial<NT>& g, bool, CGAL::Tag_true)
{
typedef Polynomial<NT> POLY;
typedef typename Polynomial_traits_d<POLY>::Innermost_coefficient IC;
typename Polynomial_traits_d<POLY>::Innermost_leading_coefficient ilcoeff;
typename Polynomial_traits_d<POLY>::Innermost_coefficient_to_polynomial ictp;
typename Polynomial_traits_d<POLY>::Innermost_coefficient_begin begin;
typename Polynomial_traits_d<POLY>::Innermost_coefficient_end end;
typename Algebraic_extension_traits<IC>::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> / Polynomial<NT> - coefficient type is NOT extended
template <class NT>
Polynomial<NT> div_utcf_(
Polynomial<NT> f, const Polynomial<NT>& g, bool is_canonicalized, CGAL::Tag_false)
{
typedef Polynomial<NT> POLY;
typedef typename Polynomial_traits_d<POLY>::Innermost_coefficient IC;
typename Polynomial_traits_d<POLY>::Innermost_leading_coefficient ilcoeff;
typename Polynomial_traits_d<POLY>::Innermost_coefficient_to_polynomial ictp;
if (!is_canonicalized) {
IC lcoeff = ilcoeff(g);
f *= ictp(lcoeff);
}
return canonicalize_polynomial(f / g);
}
// Polynomial<NT> / NT - NT is already the coefficient type and is extended
template <class NT>
Polynomial<NT> div_utcf_NT_is_IC(
Polynomial<NT> f, const NT& g, CGAL::Tag_false)
{
return canonicalize_polynomial(f);
}
// Polynomial<NT> / NT - NT is again a polynomial - coefficient type is extended
template <class NT, class Is_nested>
Polynomial<NT> div_utcf_NT_is_IC(
Polynomial<NT> f, const NT& g, Is_nested)
{
typedef Polynomial<NT> POLY;
typedef typename Polynomial_traits_d<POLY>::Innermost_coefficient IC;
typename Polynomial_traits_d<POLY>::Innermost_leading_coefficient ilcoeff;
typename Polynomial_traits_d<POLY>::Innermost_coefficient_to_polynomial ictp;
typename Polynomial_traits_d<NT>::Innermost_coefficient_begin begin;
typename Polynomial_traits_d<NT>::Innermost_coefficient_end end;
typename Algebraic_extension_traits<IC>::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> / NT - coefficient type is extended
template <class NT> inline
Polynomial<NT> div_utcf_(
const Polynomial<NT>& f, const NT& g, bool, CGAL::Tag_true)
{
typedef CGAL::Boolean_tag< (Polynomial_traits_d<NT>::d >= 2) > Is_nested;
return div_utcf_NT_is_IC(f, g, Is_nested() );
}
// Polynomial<NT> / NT - coefficient type is NOT extended
template <class NT>
Polynomial<NT> div_utcf_(
Polynomial<NT> f, const NT& g, bool is_canonicalized, CGAL::Tag_false)
{
typedef Polynomial<NT> POLY;
typedef typename Polynomial_traits_d<POLY>::Innermost_coefficient IC;
typename Polynomial_traits_d<POLY>::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 <class NT> inline
Polynomial<NT> div_utcf(
const Polynomial<NT>& f, const Polynomial<NT>& g, bool is_canonicalized = false)
{
typedef Polynomial<NT> POLY;
typedef typename Polynomial_traits_d<POLY>::Innermost_coefficient IC;
typedef typename Algebraic_extension_traits<IC>::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 <class NT> inline
Polynomial<NT> div_utcf(
const Polynomial<NT>& f, const NT& g, bool is_canonicalized = false)
{
typedef Polynomial<NT> POLY;
typedef typename Polynomial_traits_d<POLY>::Innermost_coefficient IC;
typedef typename Algebraic_extension_traits<IC>::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 <class NT> inline
Polynomial<NT> operator + (const Polynomial<NT>& p) {
CGAL_precondition(p.degree() >= 0);
return p;
}
template <class NT> inline
Polynomial<NT> operator - (const Polynomial<NT>& p) {
CGAL_precondition(p.degree()>=0);
Polynomial<NT> res(p.coeffs().begin(),p.coeffs().end());
typename Polynomial<NT>::iterator it, ite=res.coeffs().end();
for(it=res.coeffs().begin(); it!=ite; ++it) *it = -*it;
return res;
}
template <class NT> inline
Polynomial<NT> operator + (const Polynomial<NT>& p1,
const Polynomial<NT>& p2)
{
typedef typename Polynomial<NT>::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<NT> 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 <class NT> inline
Polynomial<NT> operator - (const Polynomial<NT>& p1,
const Polynomial<NT>& p2)
{
typedef typename Polynomial<NT>::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<NT> 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 <class NT> inline
Polynomial<NT> operator * (const Polynomial<NT>& p1,
const Polynomial<NT>& p2)
{
typedef typename Polynomial<NT>::size_type size_type;
CGAL_precondition(p1.degree()>=0 && p2.degree()>=0);
INTERN_POLYNOMIAL::Creation_tag TAG;
Polynomial<NT> 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 <class NT> inline
Polynomial<NT> operator / (const Polynomial<NT>& p1,
const Polynomial<NT>& p2)
{
typedef Algebraic_structure_traits< Polynomial<NT> > 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<NT> q, r;
Polynomial<NT>::euclidean_division(p1, p2, q, r);
// TODO: Replace by correct Makro
CGAL_postcondition( !AST::Is_exact::value || p2 * q == p1);
return q;
}
#else
template <class NT> inline
Polynomial<NT> operator / (const Polynomial<NT>& p1,
const Polynomial<NT>& p2)
{
typedef typename Algebraic_structure_traits<NT>::Algebric_structure_tag Algebra_type;
return division(p1, p2, Algebra_type());
}
template <class NT> inline
Polynomial<NT> division(const Polynomial<NT>& p1,
const Polynomial<NT>& p2,
Field_tag)
{
typedef Algebraic_structure_traits<NT> AST;
CGAL_precondition(!p2.is_zero());
if (p1.is_zero()) return p1;
Polynomial<NT> q,r;
Polynomial<NT>::euclidean_division(p1,p2,q,r);
CGAL_postcondition( !AST::Is_exact::value || p2 * q == p1);
return q;
}
template <class NT> inline
Polynomial<NT> division(const Polynomial<NT>& p1,
const Polynomial<NT>& p2,
Integral_domain_tag)
{
typedef Algebraic_structure_traits<NT> AST;
CGAL_precondition(!p2.is_zero());
if ( p1.is_zero() ) return p1;
Polynomial<NT> q,r; NT D;
Polynomial<NT>::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 <class NT> inline
Polynomial<NT> operator + (const NT& num, Polynomial<NT> p2)
{ p2 += num; return p2; }
template <class NT> inline
Polynomial<NT> operator - (const NT& num, Polynomial<NT> p2)
{ p2 -= num; return -p2; }
template <class NT> inline
Polynomial<NT> operator * (const NT& num, Polynomial<NT> p2)
{ p2 *= num; return p2; }
template <class NT> inline
Polynomial<NT> operator / (const NT& num, const Polynomial<NT>& p2) {
CGAL_precondition(p2.degree() == 0);
CGAL_precondition(p2[0] != NT(0));
typename Algebraic_structure_traits<NT>::Integral_division idiv;
return Polynomial<NT>(idiv(num, p2[0]));
}
// righthand side
template <class NT> inline
Polynomial<NT> operator + (Polynomial<NT> p1, const NT& num)
{ p1 += num; return p1; }
template <class NT> inline
Polynomial<NT> operator - (Polynomial<NT> p1, const NT& num)
{ p1 -= num; return p1; }
template <class NT> inline
Polynomial<NT> operator * (Polynomial<NT> p1, const NT& num)
{ p1 *= num; return p1; }
template <class NT> inline
Polynomial<NT> operator / (Polynomial<NT> p1, const NT& num)
{ p1 /= num; return p1; }
//
// Comparison Operators
//
// polynomials only
template <class NT> inline
bool operator == (const Polynomial<NT>& p1, const Polynomial<NT>& 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 <class NT> inline
bool operator != (const Polynomial<NT>& p1, const Polynomial<NT>& p2)
{ return !(p1 == p2); }
template <class NT> inline
bool operator < (const Polynomial<NT>& p1, const Polynomial<NT>& p2)
{ return ( p1.compare(p2) < 0 ); }
template <class NT> inline
bool operator <= (const Polynomial<NT>& p1, const Polynomial<NT>& p2)
{ return ( p1.compare(p2) <= 0 ); }
template <class NT> inline
bool operator > (const Polynomial<NT>& p1, const Polynomial<NT>& p2)
{ return ( p1.compare(p2) > 0 ); }
template <class NT> inline
bool operator >= (const Polynomial<NT>& p1, const Polynomial<NT>& p2)
{ return ( p1.compare(p2) >= 0 ); }
// mixed-mode, lefthand side
template <class NT> inline
bool operator == (const NT& num, const Polynomial<NT>& p) {
CGAL_precondition(p.degree() >= 0);
return p.degree() == 0 && p[0] == num;
}
template <class NT> inline
bool operator != (const NT& num, const Polynomial<NT>& p)
{ return !(num == p);}
template <class NT> inline
bool operator < (const NT& num, const Polynomial<NT>& p)
{ return ( p.compare(num) > 0 );}
template <class NT> inline
bool operator <= (const NT& num, const Polynomial<NT>& p)
{ return ( p.compare(num) >= 0 );}
template <class NT> inline
bool operator > (const NT& num, const Polynomial<NT>& p)
{ return ( p.compare(num) < 0 );}
template <class NT> inline
bool operator >= (const NT& num, const Polynomial<NT>& p)
{ return ( p.compare(num) <= 0 );}
// mixed-mode, righthand side
template <class NT> inline
bool operator == (const Polynomial<NT>& p, const NT& num)
{ return num == p; }
template <class NT> inline
bool operator != (const Polynomial<NT>& p, const NT& num)
{ return !(num == p); }
template <class NT> inline
bool operator < (const Polynomial<NT>& p, const NT& num)
{ return ( p.compare(num) < 0 );}
template <class NT> inline
bool operator <= (const Polynomial<NT>& p, const NT& num)
{ return ( p.compare(num) <= 0 );}
template <class NT> inline
bool operator > (const Polynomial<NT>& p, const NT& num)
{ return ( p.compare(num) > 0 );}
template <class NT> inline
bool operator >= (const Polynomial<NT>& 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 <class NT>
std::ostream& operator << (std::ostream& os, const Polynomial<NT>& 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 <class NT>
std::istream& operator >> (std::istream& is, Polynomial<NT>& p) {
CGAL_precondition(!CGAL::is_pretty(is));
p = Polynomial<NT>::input_ascii(is);
return is;
}
template <class NT> 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 <class NT>
void Polynomial<NT>::output_maple(std::ostream& os) const {
const Polynomial<NT>& p = *this;
const char *varname;
char vnbuf[42];
// use variable names x, y, z, w1, w2, w3, ...
if (Polynomial_traits_d<NT>::d < 3) {
static const char *varnames[] = { "x", "y", "z" };
varname = varnames[Polynomial_traits_d<NT>::d];
} else {
sprintf(vnbuf, "w%d", Polynomial_traits_d<NT>::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 <class NT>
void Polynomial<NT>::output_ascii(std::ostream &os) const {
const Polynomial<NT> &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 <class NT>
void Polynomial<NT>::output_benchmark(std::ostream &os) const {
const Polynomial<NT> &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 <class NT>
Polynomial<NT> Polynomial<NT>::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<NT> 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 <class NT>
NT weak_upper_root_bound(const Polynomial<NT>& P) {
// code comes from Kurt Mehlhorn
// see [Mignotte, 1992], p.144 for a proof
CGAL_precondition(Polynomial_traits_d<NT>::d == 0);
typename Real_embeddable_traits<NT>::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 <class NT>
int sign_variations(const Polynomial<NT>& P) {
typename Real_embeddable_traits<NT>::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 <class NT>
void Polynomial<NT>::euclidean_division(
const Polynomial<NT>& f, const Polynomial<NT>& g,
Polynomial<NT>& q, Polynomial<NT>& r)
{
typedef Algebraic_structure_traits<NT> AST;
typename AST::Integral_division idiv;
int fd = f.degree(), gd = g.degree();
if ( fd < gd ) {
q = Polynomial<NT>(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<NT>(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 <class NT>
void Polynomial<NT>::pseudo_division(
const Polynomial<NT>& A, const Polynomial<NT>& B,
Polynomial<NT>& Q, Polynomial<NT>& R, NT& D)
{
typedef Algebraic_structure_traits<NT> 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>(NT(0)); R = A; D = NT(1);
CGAL_postcondition( !AST::Is_exact::value || Polynomial<NT>(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<NT>(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<NT>(D)*A == Q*B + R);
}
#else
template <class NT>
void Polynomial<NT>::pseudo_division(
const Polynomial<NT>& f, const Polynomial<NT>& g,
Polynomial<NT>& q, Polynomial<NT>& r, NT& D)
{
typedef Algebraic_structure_traits<NT> AST;
// pseudo-division with one big multiplication with lcoeff(g)^{...}
typename Algebraic_structure_traits<NT>::Integral_division idiv;
int fd=f.degree(), gd=g.degree();
if ( fd < gd ) {
q = Polynomial<NT>(NT(0)); r = f; D = NT(1);
CGAL_postcondition( !AST::Is_exact::value || Polynomial<NT>(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<NT>(TAG, delta );
NT G = g[gd]; // highest order coeff of g
D = ipower(G, delta);
Polynomial<NT> 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<NT>(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
// <NiX/polynomial_gcd.h> (items 2,3,5) and <NiX/prs_resultant.h> (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 <class NT> inline
void hgdelta_update(NT& h, const NT& g, int delta) {
typename Algebraic_structure_traits<NT>::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 <CGAL/polynomial_gcd.h> // used above for NT_traits<Poly...>::Gcd
#include <CGAL/prs_resultant.h> // for compatibility
CGAL_BEGIN_NAMESPACE
// Cofraction_traits added by Michael Hemmer
/*namespace NiX{
namespace Intern{
template <class NT, class TAG> class Cofraction_traits_base;
template <class NT_, class TAG>
class Cofraction_traits_base<NiX::Polynomial<NT_>, TAG > {
typedef NT_ NT;
public:
typedef Polynomial<NT_> 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 NT_>
class Cofraction_traits_base<NiX::Polynomial<NT_>, LiS::True_tag > {
typedef NT_ NT;
typedef NiX::Cofraction_traits<NT_> CFT_NT;
public:
typedef Polynomial<NT> Numerator_type;
typedef ::LiS::True_tag Is_composable;
typedef typename CFT_NT::Denominator_type Denominator_type;
typedef Polynomial<typename CFT_NT::Type> 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<NT>.
*/
//template<class NT>
/*class Cofraction_traits<Polynomial<NT> > :
public Intern::Cofraction_traits_base<
Polynomial<NT>,
typename Cofraction_traits<NT>::Is_composable>{
//nothing new
};*/
template <class COEFF>
struct Needs_parens_as_product<Polynomial<COEFF> >{
typedef Polynomial<COEFF> 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 A,class B>
class Coercion_traits_for_level<Polynomial<A>, Polynomial<B>, CTL_POLYNOMIAL >{
typedef Coercion_traits<A,B> CT;
public:
typedef CGAL::Tag_true Are_explicit_interoperable;
typedef CGAL::Tag_false Are_implicit_interoperable;
typedef Polynomial<typename CT::Type> Type;
struct Cast{
typedef Type result_type;
Type operator()(const Polynomial<A>& 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<B>& poly) const {
typename CT::Cast cast;
return Type(::boost::make_transform_iterator(poly.begin(),cast),
::boost::make_transform_iterator(poly.end() ,cast));
}
};
};
template <class A,class B>
class Coercion_traits_for_level<Polynomial<A>,B ,CTL_POLYNOMIAL >{
typedef Coercion_traits<A,B> CT;
public:
typedef CGAL::Tag_true Are_explicit_interoperable;
typedef CGAL::Tag_false Are_implicit_interoperable;
typedef Polynomial<typename CT::Type> Type;
struct Cast{
typedef Type result_type;
Type operator()(const Polynomial<A>& 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 A,class B>
class Coercion_traits_for_level<B,Polynomial<A>,CTL_POLYNOMIAL >
:public Coercion_traits_for_level<Polynomial<A>,B,CTL_POLYNOMIAL >
{};
// COERCION_TRAITS END
CGAL_END_NAMESPACE
#include <CGAL/Polynomial_traits_d.h>
#include <CGAL/polynomial_utils.h>
//
// 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