dust3d/thirdparty/cgal/CGAL-5.1/include/CGAL/Polynomial/Algebraic_structure_traits.h

347 lines
11 KiB
C++

// Copyright (c) 2008 Max-Planck-Institute Saarbruecken (Germany)
//
// This file is part of CGAL (www.cgal.org)
//
// $URL: https://github.com/CGAL/cgal/blob/v5.1/Polynomial/include/CGAL/Polynomial/Algebraic_structure_traits.h $
// $Id: Algebraic_structure_traits.h 0779373 2020-03-26T13:31:46+01:00 Sébastien Loriot
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s) : Arno Eigenwillig <arno@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.
#ifndef CGAL_POLYNOMIAL_ALGEBRAIC_STRUCTURE_TRAITS_H
#define CGAL_POLYNOMIAL_ALGEBRAIC_STRUCTURE_TRAITS_H
#include <CGAL/basic.h>
#include <CGAL/Coercion_traits.h>
#include <CGAL/Polynomial/modular_filter.h>
namespace CGAL {
// Extend to a UFDomain as coefficient range
// Forward declaration for <NiX/polynomial_gcd.h> for NT_traits<Poly...>::Gcd
namespace internal {
template <class NT> inline
Polynomial<NT> gcd_(const Polynomial<NT>&, const Polynomial<NT>&);
} // namespace internal
// Now we wrap up all of this in the actual NT_traits
// specialization for Polynomial<NT>
/*! \ingroup NiX_Polynomial
\brief \c NiX::NT_traits < \c NiX::Polynomial<NT> >
*
* If \c NT is a model of a number type concept, then so is
* \c Polynomial<NT>. A specialization of \c NiX::NT_traits
* is provided automatically by NiX/Polynomial.h.
*
* The number type concepts for the coefficient domain NT are
* mapped to those for the polynomials as follows:
* <PRE>
IntegralDomainWithoutDiv --> IntegralDomainWithoutDiv
IntegralDomain --> IntegralDomain
UFDomain --> UFDomain
EuclideanRing --> UFDomain
Field --> EuclideanRing
FieldWithSqrt --> EuclideanRing
</PRE>
*
* \c Polynomial<NT> is \c RealComparable iff \c NT is.
* The ordering is determined by the \c sign() of differences, see ibid.
*
* \c Polynomial<NT> offers a non-<TT>Null_tag</TT> \c To_double
* iff \c NT does. If non-<TT>Null_tag</TT>, it returns a coefficient-wise
* \c double approximation of the polynomial.
*/
// Algebraic structure traits
template< class POLY, class Algebraic_type >
class Polynomial_algebraic_structure_traits_base;
// The most basic suite of algebraic operations, suitable for the
// most basic kind of coefficient range, viz. a IntegralDomainWithoutDiv.
template< class POLY >
class Polynomial_algebraic_structure_traits_base< POLY,
Integral_domain_without_division_tag >
: public Algebraic_structure_traits_base< POLY,
Integral_domain_without_division_tag > {
public:
typedef Integral_domain_without_division_tag Algebraic_category;
class Simplify
: public CGAL::cpp98::unary_function< POLY&, void > {
public:
void operator()( POLY& p ) const {
p.simplify_coefficients();
}
};
class Unit_part
: public CGAL::cpp98::unary_function< POLY, POLY > {
public:
POLY operator()( const POLY& x ) const {
return POLY( x.unit_part() );
}
};
class Is_zero
: public CGAL::cpp98::unary_function< POLY, bool > {
public:
bool operator()( const POLY& x ) const {
return x.is_zero();
}
};
};
// Extend to the case that the coefficient range is a IntegralDomain (with div)
template< class POLY >
class Polynomial_algebraic_structure_traits_base< POLY, Integral_domain_tag >
: public Polynomial_algebraic_structure_traits_base< POLY,
Integral_domain_without_division_tag > {
public:
typedef Integral_domain_tag Algebraic_category;
class Integral_division
: public CGAL::cpp98::binary_function< POLY, POLY, POLY > {
public:
POLY operator()( const POLY& x, const POLY& y ) const {
return x / y;
}
CGAL_IMPLICIT_INTEROPERABLE_BINARY_OPERATOR( POLY )
};
private:
typedef typename POLY::NT COEFF;
typedef Algebraic_structure_traits<COEFF> AST_COEFF;
typedef typename AST_COEFF::Divides Divides_coeff;
typedef typename Divides_coeff::result_type BOOL;
public:
class Divides
: public CGAL::cpp98::binary_function<POLY,POLY,BOOL>{
public:
BOOL operator()( const POLY& p1, const POLY& p2) const {
POLY q;
return (*this)(p1,p2,q);
}
BOOL operator()( const POLY& p1, const POLY& p2, POLY& q) const {
Divides_coeff divides_coeff;
q=POLY(0);
COEFF q1;
BOOL result;
if (p2.is_zero()) {
q=POLY(0);
return true;
}
int d1 = p1.degree();
int d2 = p2.degree();
if ( d2 < d1 ) {
q = POLY(0);
return false;
}
typedef std::vector<COEFF> Vector;
Vector V_R, V_Q;
V_Q.reserve(d2);
if(d1==0){
for(int i=d2;i>=0;--i){
result=divides_coeff(p1[0],p2[i],q1);
if(!result) return false;
V_Q.push_back(q1);
}
V_R.push_back(COEFF(0));
}
else{
V_R.reserve(d2);
V_R=Vector(p2.begin(),p2.end());
Vector tmp1;
tmp1.reserve(d1);
for(int k=0; k<=d2-d1; ++k){
result=divides_coeff(p1[d1],V_R[d2-k],q1);
if(!result) return false;
V_Q.push_back(q1);
for(int j=0;j<d1;++j){
tmp1.push_back(p1[j]*V_Q[k]);
}
V_R[d2-k]=COEFF(0);
for(int i=d2-d1-k;i<=d2-k-1;++i){
V_R[i]=V_R[i]-tmp1[i-(d2-d1-k)];
}
tmp1.clear();
}
}
q = POLY(V_Q.rbegin(),V_Q.rend());
POLY r = POLY(V_R.begin(),V_R.end());
return (r == POLY(0));
}
CGAL_IMPLICIT_INTEROPERABLE_BINARY_OPERATOR_WITH_RT(POLY,BOOL)
};
};
template< class POLY >
class Polynomial_algebraic_structure_traits_base< POLY, Unique_factorization_domain_tag >
: public Polynomial_algebraic_structure_traits_base< POLY,
Integral_domain_tag > {
public:
typedef Unique_factorization_domain_tag Algebraic_category;
class Gcd
: public CGAL::cpp98::binary_function< POLY, POLY, POLY > {
typedef typename Polynomial_traits_d<POLY>::Multivariate_content Mcontent;
typedef typename Mcontent::result_type ICoeff;
ICoeff gcd_help(const ICoeff& , const ICoeff& , Field_tag) const {
return ICoeff(1);
}
ICoeff gcd_help(const ICoeff& x, const ICoeff& y,
Unique_factorization_domain_tag) const {
return CGAL::gcd(x,y);
}
public:
POLY operator()( const POLY& x, const POLY& y ) const {
if(x==y) return x;
typedef Algebraic_structure_traits<POLY> AST;
typename AST::Integral_division idiv;
typename AST::Unit_part upart;
// First: the extreme cases and negative sign corrections.
if (CGAL::is_zero(x)) {
if (CGAL::is_zero(y))
return POLY(0);
return idiv(y,upart(y));
}
if (CGAL::is_zero(y))
return idiv(x,upart(x));
if (internal::may_have_common_factor(x,y))
return CGAL::internal::gcd_(x,y);
else{
typename Algebraic_structure_traits<ICoeff>::Algebraic_category category;
return POLY(gcd_help(Mcontent()(x),Mcontent()(y), category));
}
}
CGAL_IMPLICIT_INTEROPERABLE_BINARY_OPERATOR( POLY )
};
};
// Clone this for a EuclideanRing
template< class POLY >
class Polynomial_algebraic_structure_traits_base< POLY, Euclidean_ring_tag >
: public Polynomial_algebraic_structure_traits_base< POLY,
Unique_factorization_domain_tag > {
// nothing new
};
// Extend to a field as coefficient range
template< class POLY >
class Polynomial_algebraic_structure_traits_base< POLY, Field_tag >
: public Polynomial_algebraic_structure_traits_base< POLY,
Unique_factorization_domain_tag > {
public:
typedef Euclidean_ring_tag Algebraic_category;
class Div_mod {
public:
typedef POLY first_argument_type;
typedef POLY second_argument_type;
typedef POLY& third_argument_type;
typedef POLY& fourth_argument_type;
typedef void result_type;
void operator()( const POLY& x, const POLY& y,
POLY& q, POLY& r ) const {
POLY::euclidean_division( x, y, q, r );
}
template < class NT1, class NT2 >
void operator()( const NT1& x, const NT2& y,
POLY& q, POLY& r ) const {
CGAL_static_assertion((::boost::is_same<
typename Coercion_traits< NT1, NT2 >::Type, POLY
>::value));
typename Coercion_traits< NT1, NT2 >::Cast cast;
operator()( cast(x), cast(y), q, r );
}
};
class Div
: public CGAL::cpp98::binary_function< POLY, POLY, POLY > {
public:
POLY operator()(const POLY& a, const POLY& b) const {
POLY q, r;
Div_mod()(a, b, q, r);
return q;
}
CGAL_IMPLICIT_INTEROPERABLE_BINARY_OPERATOR( POLY )
};
class Mod
: public CGAL::cpp98::binary_function< POLY, POLY, POLY > {
public:
POLY operator () (const POLY& a, const POLY& b) const {
POLY q, r;
Div_mod()(a, b, q, r);
return r;
}
CGAL_IMPLICIT_INTEROPERABLE_BINARY_OPERATOR( POLY )
};
};
// Clone this for a FieldWithSqrt
template< class POLY >
class Polynomial_algebraic_structure_traits_base< POLY, Field_with_sqrt_tag >
: public Polynomial_algebraic_structure_traits_base< POLY, Field_tag > {
// nothing new
};
// Clone this for a FieldWithKthRoot
template< class POLY >
class Polynomial_algebraic_structure_traits_base< POLY,
Field_with_kth_root_tag >
: public Polynomial_algebraic_structure_traits_base< POLY,
Field_with_sqrt_tag > {
// nothing new
};
// Clone this for a FieldWithRootOf
template< class POLY >
class Polynomial_algebraic_structure_traits_base< POLY,
Field_with_root_of_tag >
: public Polynomial_algebraic_structure_traits_base< POLY,
Field_with_kth_root_tag > {
// nothing new
};
// The actual algebraic structure traits class
template< class NT > class Algebraic_structure_traits< Polynomial< NT > >
: public Polynomial_algebraic_structure_traits_base< Polynomial< NT >,
typename Algebraic_structure_traits< NT >::Algebraic_category > {
public:
typedef Polynomial<NT> Algebraic_structure;
typedef typename Algebraic_structure_traits< NT >::Is_exact Is_exact;
};
} //namespace CGAL
#endif // CGAL_POLYNOMIAL_ALGEBRAIC_STRUCTURE_TRAITS_H