// 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 #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 #include #include #include #include #include #include #include #include #include #include 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 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 inline Coeff resultant_interpolate( const CGAL::Polynomial&, const CGAL::Polynomial& ); template inline Coeff resultant_modularize( const CGAL::Polynomial&, const CGAL::Polynomial&, CGAL::Tag_true); template inline Coeff resultant_modularize( const CGAL::Polynomial&, const CGAL::Polynomial&, CGAL::Tag_false); template inline Coeff resultant_decompose( const CGAL::Polynomial&, const CGAL::Polynomial&, CGAL::Tag_true); template inline Coeff resultant_decompose( const CGAL::Polynomial&, const CGAL::Polynomial&, CGAL::Tag_false); template inline Coeff resultant_( const CGAL::Polynomial&, const CGAL::Polynomial&); template inline Coeff resultant_univariate( const CGAL::Polynomial& A, const CGAL::Polynomial& B, CGAL::Integral_domain_without_division_tag){ return hybrid_bezout_subresultant(A,B,0); } template inline Coeff resultant_univariate( const CGAL::Polynomial& A, const CGAL::Polynomial& B, CGAL::Integral_domain_tag){ // this seems to help for for large polynomials return prs_resultant_integral_domain(A,B); } template inline Coeff resultant_univariate( const CGAL::Polynomial& A, const CGAL::Polynomial& B, CGAL::Unique_factorization_domain_tag){ return prs_resultant_ufd(A,B); } template inline Coeff resultant_univariate( const CGAL::Polynomial& A, const CGAL::Polynomial& B, CGAL::Field_tag){ return prs_resultant_field(A,B); } } // namespace internal namespace internal{ template inline IC resultant_interpolate( const CGAL::Polynomial& F, const CGAL::Polynomial& G){ CGAL_precondition(CGAL::Polynomial_traits_d >::d == 1); typedef CGAL::Algebraic_structure_traits AST_IC; typedef typename AST_IC::Algebraic_category Algebraic_category; return internal::resultant_univariate(F,G,Algebraic_category()); } template inline CGAL::Polynomial resultant_interpolate( const CGAL::Polynomial >& F, const CGAL::Polynomial >& G){ typedef CGAL::Polynomial Coeff_1; typedef CGAL::Polynomial POLY; typedef CGAL::Polynomial_traits_d 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 Point; std::vector points; // interpolation points typename CGAL::Polynomial_traits_d::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::Degree()(res_at_i) << std::endl ; } } // timer3.start(); CGAL::internal::Interpolator 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 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 inline Coeff resultant_modularize( const CGAL::Polynomial& F, const CGAL::Polynomial& G, CGAL::Tag_false){ return resultant_interpolate(F,G); } template inline Coeff resultant_modularize( const CGAL::Polynomial& F, const CGAL::Polynomial& G, CGAL::Tag_true){ // Enforce IEEE double precision and to nearest before using modular arithmetic CGAL::Protect_FPU_rounding pfr(CGAL_FE_TONEAREST); typedef Polynomial_traits_d > PT; typedef typename PT::Polynomial_d Polynomial; typedef Chinese_remainder_traits CRT; typedef typename CRT::Scalar_type Scalar; typedef typename CGAL::Modular_traits::Residue_type MPolynomial; typedef typename CGAL::Modular_traits::Residue_type MCoeff; typename CRT::Chinese_remainder chinese_remainder; typename CGAL::Modular_traits::Modular_image_representative inv_map; typename PT::Degree_vector degree_vector; typename CGAL::Polynomial_traits_d::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"< 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 inline Coeff resultant_decompose( const CGAL::Polynomial& F, const CGAL::Polynomial& G, CGAL::Tag_false){ #if CGAL_RESULTANT_USE_MODULAR_ARITHMETIC typedef CGAL::Polynomial Polynomial; typedef typename Modular_traits::Is_modularizable Is_modularizable; return resultant_modularize(F,G,Is_modularizable()); #else return resultant_modularize(F,G,CGAL::Tag_false()); #endif } template inline Coeff resultant_decompose( const CGAL::Polynomial& F, const CGAL::Polynomial& G, CGAL::Tag_true){ typedef Polynomial POLY; typedef typename Fraction_traits::Numerator_type Numerator; typedef typename Fraction_traits::Denominator_type Denominator; typename Fraction_traits::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::Compose comp_frac; Coeff res = comp_frac(res0, c); typename Algebraic_structure_traits::Simplify simplify; simplify(res); return res; } template inline Coeff resultant_( const CGAL::Polynomial& F, const CGAL::Polynomial& G){ #if CGAL_RESULTANT_USE_DECOMPOSE typedef CGAL::Fraction_traits > 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 inline Coeff resultant( const CGAL::Polynomial& F_, const CGAL::Polynomial& G_){ // make the variable to be elimnated the innermost one. typedef CGAL::Polynomial_traits_d > PT; CGAL::Polynomial F = typename PT::Move()(F_, PT::d-1, 0); CGAL::Polynomial G = typename PT::Move()(G_, PT::d-1, 0); return internal::resultant_(F,G); } } // namespace internal } //namespace CGAL #endif // CGAL_POLYNOMIAL_RESULTANT_H