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

406 lines
13 KiB
C++

// Copyright (c) 2008 Max-Planck-Institute Saarbruecken (Germany).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL: https://github.com/CGAL/cgal/blob/v5.1/Polynomial/include/CGAL/Polynomial/resultant.h $
// $Id: resultant.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) : Michael Hemmer <hemmer@mpi-inf.mpg.de>
#ifndef CGAL_POLYNOMIAL_RESULTANT_H
#define CGAL_POLYNOMIAL_RESULTANT_H
// Modular arithmetic is slower, hence the default is 0
#ifndef CGAL_RESULTANT_USE_MODULAR_ARITHMETIC
#define CGAL_RESULTANT_USE_MODULAR_ARITHMETIC 0
#endif
#ifndef CGAL_RESULTANT_USE_DECOMPOSE
#define CGAL_RESULTANT_USE_DECOMPOSE 1
#endif
#include <CGAL/basic.h>
#include <CGAL/Polynomial.h>
#include <CGAL/Polynomial_traits_d.h>
#include <CGAL/Polynomial/Interpolator.h>
#include <CGAL/Polynomial/prs_resultant.h>
#include <CGAL/Polynomial/bezout_matrix.h>
#include <CGAL/Residue.h>
#include <CGAL/Modular_traits.h>
#include <CGAL/Chinese_remainder_traits.h>
#include <CGAL/primes.h>
#include <CGAL/Polynomial/Cached_extended_euclidean_algorithm.h>
namespace CGAL {
// The main function provided within this file is CGAL::internal::resultant(F,G),
// all other functions are used for dispatching.
// The implementation uses interpolatation for multivariate polynomials
// Due to the recursive structuture of CGAL::Polynomial<Coeff> it is better
// to write the function such that the inner most variabel is eliminated.
// However, CGAL::internal::resultant(F,G) eliminates the outer most variabel.
// This is due to backward compatibility issues with code base on EXACUS.
// In turn CGAL::internal::resultant_(F,G) eliminates the innermost variable.
// Dispatching
// CGAL::internal::resultant_decompose applies if Coeff is a Fraction
// CGAL::internal::resultant_modularize applies if Coeff is Modularizable
// CGAL::internal::resultant_interpolate applies for multivairate polynomials
// CGAL::internal::resultant_univariate selects the proper algorithm for IC
// CGAL_RESULTANT_USE_DECOMPOSE ( default = 1 )
// CGAL_RESULTANT_USE_MODULAR_ARITHMETIC (default = 0 )
namespace internal{
template <class Coeff>
inline Coeff resultant_interpolate(
const CGAL::Polynomial<Coeff>&, const CGAL::Polynomial<Coeff>& );
template <class Coeff>
inline Coeff resultant_modularize(
const CGAL::Polynomial<Coeff>&,
const CGAL::Polynomial<Coeff>&, CGAL::Tag_true);
template <class Coeff>
inline Coeff resultant_modularize(
const CGAL::Polynomial<Coeff>&,
const CGAL::Polynomial<Coeff>&, CGAL::Tag_false);
template <class Coeff>
inline Coeff resultant_decompose(
const CGAL::Polynomial<Coeff>&,
const CGAL::Polynomial<Coeff>&, CGAL::Tag_true);
template <class Coeff>
inline Coeff resultant_decompose(
const CGAL::Polynomial<Coeff>&,
const CGAL::Polynomial<Coeff>&, CGAL::Tag_false);
template <class Coeff>
inline Coeff resultant_(
const CGAL::Polynomial<Coeff>&, const CGAL::Polynomial<Coeff>&);
template <class Coeff>
inline Coeff resultant_univariate(
const CGAL::Polynomial<Coeff>& A,
const CGAL::Polynomial<Coeff>& B,
CGAL::Integral_domain_without_division_tag){
return hybrid_bezout_subresultant(A,B,0);
}
template <class Coeff>
inline Coeff resultant_univariate(
const CGAL::Polynomial<Coeff>& A,
const CGAL::Polynomial<Coeff>& B, CGAL::Integral_domain_tag){
// this seems to help for for large polynomials
return prs_resultant_integral_domain(A,B);
}
template <class Coeff>
inline Coeff resultant_univariate(
const CGAL::Polynomial<Coeff>& A,
const CGAL::Polynomial<Coeff>& B, CGAL::Unique_factorization_domain_tag){
return prs_resultant_ufd(A,B);
}
template <class Coeff>
inline Coeff resultant_univariate(
const CGAL::Polynomial<Coeff>& A,
const CGAL::Polynomial<Coeff>& B, CGAL::Field_tag){
return prs_resultant_field(A,B);
}
} // namespace internal
namespace internal{
template <class IC>
inline IC
resultant_interpolate(
const CGAL::Polynomial<IC>& F,
const CGAL::Polynomial<IC>& G){
CGAL_precondition(CGAL::Polynomial_traits_d<CGAL::Polynomial<IC> >::d == 1);
typedef CGAL::Algebraic_structure_traits<IC> AST_IC;
typedef typename AST_IC::Algebraic_category Algebraic_category;
return internal::resultant_univariate(F,G,Algebraic_category());
}
template <class Coeff_2>
inline
CGAL::Polynomial<Coeff_2> resultant_interpolate(
const CGAL::Polynomial<CGAL::Polynomial<Coeff_2> >& F,
const CGAL::Polynomial<CGAL::Polynomial<Coeff_2> >& G){
typedef CGAL::Polynomial<Coeff_2> Coeff_1;
typedef CGAL::Polynomial<Coeff_1> POLY;
typedef CGAL::Polynomial_traits_d<POLY> PT;
typedef typename PT::Innermost_coefficient_type IC;
CGAL_precondition(PT::d >= 2);
typename PT::Degree degree;
int maxdegree = degree(F,0)*degree(G,PT::d-1) + degree(F,PT::d-1)*degree(G,0);
typedef std::pair<IC,Coeff_2> Point;
std::vector<Point> points; // interpolation points
typename CGAL::Polynomial_traits_d<Coeff_1>::Degree coeff_degree;
int i(-maxdegree/2);
int deg_f(0);
int deg_g(0);
while((int) points.size() <= maxdegree + 1){
i++;
// timer1.start();
Coeff_1 c_i(i);
Coeff_1 Fat_i(typename PT::Evaluate()(F,c_i));
Coeff_1 Gat_i(typename PT::Evaluate()(G,c_i));
// timer1.stop();
int deg_f_at_i = coeff_degree(Fat_i,0);
int deg_g_at_i = coeff_degree(Gat_i,0);
// std::cout << F << std::endl;
// std::cout << Fat_i << std::endl;
// std::cout << deg_f_at_i << " vs. " << deg_f << std::endl;
if(deg_f_at_i > deg_f ){
points.clear();
deg_f = deg_f_at_i;
CGAL_postcondition(points.size() == 0);
}
if(deg_g_at_i > deg_g){
points.clear();
deg_g = deg_g_at_i;
CGAL_postcondition(points.size() == 0);
}
if(deg_f_at_i == deg_f && deg_g_at_i == deg_g){
// timer2.start();
Coeff_2 res_at_i = resultant_interpolate(Fat_i, Gat_i);
// timer2.stop();
points.push_back(Point(IC(i),res_at_i));
// std::cout << typename Polynomial_traits_d<Coeff_2>::Degree()(res_at_i) << std::endl ;
}
}
// timer3.start();
CGAL::internal::Interpolator<Coeff_1> interpolator(points.begin(),points.end());
Coeff_1 result = interpolator.get_interpolant();
// timer3.stop();
#ifndef CGAL_NDEBUG
while((int) points.size() <= maxdegree + 3){
i++;
Coeff_1 c_i(i);
Coeff_1 Fat_i(typename PT::Evaluate()(F,c_i));
Coeff_1 Gat_i(typename PT::Evaluate()(G,c_i));
CGAL_assertion(coeff_degree(Fat_i,0) <= deg_f);
CGAL_assertion(coeff_degree(Gat_i,0) <= deg_g);
if(coeff_degree( Fat_i , 0) == deg_f && coeff_degree( Gat_i , 0 ) == deg_g){
Coeff_2 res_at_i = resultant_interpolate(Fat_i, Gat_i);
points.push_back(Point(IC(i), res_at_i));
}
}
CGAL::internal::Interpolator<Coeff_1>
interpolator_(points.begin(),points.end());
Coeff_1 result_= interpolator_.get_interpolant();
// the interpolate polynomial has to be stable !
CGAL_assertion(result_ == result);
#endif
return result;
}
template <class Coeff>
inline
Coeff resultant_modularize(
const CGAL::Polynomial<Coeff>& F,
const CGAL::Polynomial<Coeff>& G,
CGAL::Tag_false){
return resultant_interpolate(F,G);
}
template <class Coeff>
inline
Coeff resultant_modularize(
const CGAL::Polynomial<Coeff>& F,
const CGAL::Polynomial<Coeff>& G,
CGAL::Tag_true){
// Enforce IEEE double precision and to nearest before using modular arithmetic
CGAL::Protect_FPU_rounding<true> pfr(CGAL_FE_TONEAREST);
typedef Polynomial_traits_d<CGAL::Polynomial<Coeff> > PT;
typedef typename PT::Polynomial_d Polynomial;
typedef Chinese_remainder_traits<Coeff> CRT;
typedef typename CRT::Scalar_type Scalar;
typedef typename CGAL::Modular_traits<Polynomial>::Residue_type MPolynomial;
typedef typename CGAL::Modular_traits<Coeff>::Residue_type MCoeff;
typename CRT::Chinese_remainder chinese_remainder;
typename CGAL::Modular_traits<Coeff>::Modular_image_representative inv_map;
typename PT::Degree_vector degree_vector;
typename CGAL::Polynomial_traits_d<MPolynomial>::Degree_vector mdegree_vector;
bool solved = false;
int prime_index = 0;
int n = 0;
Scalar p,q,pq,s,t;
Coeff R, R_old;
// CGAL::Timer timer_evaluate, timer_resultant, timer_cr;
do{
MPolynomial mF, mG;
MCoeff mR;
//timer_evaluate.start();
do{
// select a prime number
int current_prime = -1;
prime_index++;
if(prime_index >= 2000){
std::cerr<<"primes in the array exhausted"<<std::endl;
CGAL_assertion(false);
current_prime = internal::get_next_lower_prime(current_prime);
} else{
current_prime = internal::primes[prime_index];
}
CGAL::Residue::set_current_prime(current_prime);
mF = CGAL::modular_image(F);
mG = CGAL::modular_image(G);
}while( degree_vector(F) != mdegree_vector(mF) ||
degree_vector(G) != mdegree_vector(mG));
//timer_evaluate.stop();
//timer_resultant.start();
n++;
mR = resultant_interpolate(mF,mG);
//timer_resultant.stop();
//timer_cr.start();
if(n == 1){
// init chinese remainder
q = CGAL::Residue::get_current_prime(); // implicit !
R = inv_map(mR);
}else{
// continue chinese remainder
p = CGAL::Residue::get_current_prime(); // implicit!
R_old = R ;
// chinese_remainder(q,Gs ,p,inv_map(mG_),pq,Gs);
// cached_extended_euclidean_algorithm(q,p,s,t);
internal::Cached_extended_euclidean_algorithm
<typename CRT::Scalar_type> ceea;
ceea(q,p,s,t);
pq =p*q;
chinese_remainder(q,p,pq,s,t,R_old,inv_map(mR),R);
q=pq;
}
solved = (R==R_old);
//timer_cr.stop();
} while(!solved);
//std::cout << "Time Evaluate : " << timer_evaluate.time() << std::endl;
//std::cout << "Time Resultant : " << timer_resultant.time() << std::endl;
//std::cout << "Time Chinese R : " << timer_cr.time() << std::endl;
// CGAL_postcondition(R == resultant_interpolate(F,G));
return R;
// return resultant_interpolate(F,G);
}
template <class Coeff>
inline
Coeff resultant_decompose(
const CGAL::Polynomial<Coeff>& F,
const CGAL::Polynomial<Coeff>& G,
CGAL::Tag_false){
#if CGAL_RESULTANT_USE_MODULAR_ARITHMETIC
typedef CGAL::Polynomial<Coeff> Polynomial;
typedef typename Modular_traits<Polynomial>::Is_modularizable Is_modularizable;
return resultant_modularize(F,G,Is_modularizable());
#else
return resultant_modularize(F,G,CGAL::Tag_false());
#endif
}
template <class Coeff>
inline
Coeff resultant_decompose(
const CGAL::Polynomial<Coeff>& F,
const CGAL::Polynomial<Coeff>& G,
CGAL::Tag_true){
typedef Polynomial<Coeff> POLY;
typedef typename Fraction_traits<POLY>::Numerator_type Numerator;
typedef typename Fraction_traits<POLY>::Denominator_type Denominator;
typename Fraction_traits<POLY>::Decompose decompose;
typedef typename Numerator::NT RES;
Denominator a, b;
// F.simplify_coefficients(); not const
// G.simplify_coefficients(); not const
Numerator F0; decompose(F,F0,a);
Numerator G0; decompose(G,G0,b);
Denominator c = CGAL::ipower(a, G.degree()) * CGAL::ipower(b, F.degree());
RES res0 = CGAL::internal::resultant_(F0, G0);
typename Fraction_traits<Coeff>::Compose comp_frac;
Coeff res = comp_frac(res0, c);
typename Algebraic_structure_traits<Coeff>::Simplify simplify;
simplify(res);
return res;
}
template <class Coeff>
inline
Coeff resultant_(
const CGAL::Polynomial<Coeff>& F,
const CGAL::Polynomial<Coeff>& G){
#if CGAL_RESULTANT_USE_DECOMPOSE
typedef CGAL::Fraction_traits<Polynomial<Coeff > > FT;
typedef typename FT::Is_fraction Is_fraction;
return resultant_decompose(F,G,Is_fraction());
#else
return resultant_decompose(F,G,CGAL::Tag_false());
#endif
}
template <class Coeff>
inline
Coeff resultant(
const CGAL::Polynomial<Coeff>& F_,
const CGAL::Polynomial<Coeff>& G_){
// make the variable to be elimnated the innermost one.
typedef CGAL::Polynomial_traits_d<CGAL::Polynomial<Coeff> > PT;
CGAL::Polynomial<Coeff> F = typename PT::Move()(F_, PT::d-1, 0);
CGAL::Polynomial<Coeff> G = typename PT::Move()(G_, PT::d-1, 0);
return internal::resultant_(F,G);
}
} // namespace internal
} //namespace CGAL
#endif // CGAL_POLYNOMIAL_RESULTANT_H