// Copyright (c) 2008 Max-Planck-Institute Saarbruecken (Germany). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 3 of the License, // or (at your option) any later version. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // 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$ // SPDX-License-Identifier: LGPL-3.0+ // // Author(s) : Michael Kerber // // ============================================================================ #ifndef CGAL_POLYNOMIAL_SUBRESULTANTS_H #define CGAL_POLYNOMIAL_SUBRESULTANTS_H #include #include #include namespace CGAL { namespace internal { // Intern function needed for Ducos algorithm template void lazard_optimization (typename Polynomial_traits_d::Coefficient_type y, double n, typename Polynomial_traits_d::Polynomial_d B, typename Polynomial_traits_d::Polynomial_d& C) { typedef typename Polynomial_traits_d::Coefficient_type NT; typename CGAL::Algebraic_structure_traits::Integral_division idiv; CGAL_precondition(n>0); NT x = typename Polynomial_traits_d::Leading_coefficient() (B); double a = pow(2.,std::floor(log(n)/log(2.))); NT c = x; n -= a; while(a!=1) { a/=2; c=idiv(c*c,y); if(n>=a) { c=idiv(c*x,y); n-=a; } } C=c*B/y; } template void lickteig_roy_optimization (typename Polynomial_traits_d::Polynomial_d A, typename Polynomial_traits_d::Polynomial_d B, typename Polynomial_traits_d::Polynomial_d C, typename Polynomial_traits_d::Coefficient_type s, typename Polynomial_traits_d::Polynomial_d& D) { typedef typename Polynomial_traits_d::Polynomial_d Poly; typedef typename Polynomial_traits_d::Coefficient_type NT; typename Polynomial_traits_d::Degree degree; typename Polynomial_traits_d::Leading_coefficient lcoeff; typename Polynomial_traits_d::Construct_polynomial construct; typename Polynomial_traits_d::Get_coefficient coeff; int d = degree(A), e = degree(B); CGAL_precondition(d>=e); std::vector H(d+1); std::list initial; initial.push_front(lcoeff(C)); for(int i=0;i=e ? coeff(H[i],e) : NT(0); H[i]-=(h_i_e*B)/lcoeff(B); initial.clear(); std::copy(H[i].begin(),H[i].end(),std::back_inserter(initial)); initial.push_front(NT(0)); } H[d]=construct(initial.begin(),initial.end()); D=construct(0); for(int i=0;i=e ? coeff(H[d],e) : NT(0); D=(lcoeff(B)*(H[d]+D)-Hde*B)/s; if((d-e)%2==0) { D=-D; } return; } template typename Polynomial_traits_d::Coefficient_type resultant_for_constant_polynomial (typename Polynomial_traits_d::Polynomial_d P, typename Polynomial_traits_d::Polynomial_d Q) { typedef typename Polynomial_traits_d::Polynomial_d Polynomial; typedef typename Polynomial_traits_d::Coefficient_type NT; typename Polynomial_traits_d::Leading_coefficient lcoeff; typename Polynomial_traits_d::Degree degree; typename CGAL::Algebraic_structure_traits::Is_zero is_zero; CGAL_assertion(degree(P) < 1 || degree(Q) < 1); if(is_zero(P) || is_zero(Q) ) { return NT(0); } if(degree(P)==0) { return CGAL::ipower(lcoeff(P),degree(Q)); } else { return CGAL::ipower(lcoeff(Q),degree(P)); } } /*! * \brief Compute the sequence of subresultants with pseudo-division * * This is an implementation of Ducos' algorithm. It improves on the * classical methods for subresultant computation by reducing the * swell-up of intermediate results. For all details, see * L.Ducos: Optimazations of the Subresultant algorithm. Journal of Pure * and Applied Algebra 145 (2000) 149--163 */ template inline OutputIterator prs_polynomial_subresultants (typename Polynomial_traits_d::Polynomial_d P, typename Polynomial_traits_d::Polynomial_d Q, OutputIterator out) { typedef typename Polynomial_traits_d::Polynomial_d Polynomial; typedef typename Polynomial_traits_d::Coefficient_type NT; typename Polynomial_traits_d::Leading_coefficient lcoeff; typename Polynomial_traits_d::Degree degree; typename Polynomial_traits_d::Construct_polynomial construct; typename CGAL::Algebraic_structure_traits::Is_zero is_zero; if(degree(P) < 1 || degree(Q) < 1) { *out++ = Polynomial(CGAL::internal::resultant_for_constant_polynomial (P,Q)); return out; } bool poly_swapped = (degree(P) < degree(Q)); if(poly_swapped) { std::swap(P,Q); } Polynomial zero_pol = construct(NT(0)); std::vector sres; int deg_diff=degree(P)-degree(Q); if(deg_diff==0) { sres.push_back(Q); } else { sres.push_back(CGAL::ipower(lcoeff(Q),deg_diff-1)*Q); } Polynomial A,B,C,D,dummy_pol; NT s,dummy_nt; int delta,d,e; A=Q; s=CGAL::ipower(lcoeff(Q),deg_diff); typename Polynomial_traits_d::Pseudo_division() (P, -Q, dummy_pol, B, dummy_nt); while(true) { d=degree(A); e=degree(B); if(is_zero(B)) { for(int i=0;i1) { CGAL::internal::lazard_optimization (s,double(delta-1),B,C); //C=CGAL::ipower(CGAL::integral_division(lcoeff(B),s),delta-1)*B; for(int i=0;i(A,B,C,s,D); B=D; //typename Polynomial_traits_d::Pseudo_division() // (A, -B, dummy_pol, D, dummy_nt); //B= D / (CGAL::ipower(s,delta)*lcoeff(A)); A=C; s=lcoeff(A); } CGAL_assertion(static_cast(sres.size()) == degree(Q)+1); // If P and Q were swapped, correct the signs if(poly_swapped) { int p = degree(P); int q = degree(Q); for(int i=0;i<=q;i++) { if((p-i)*(q-i) % 2 == 1) { sres[q-i]=-sres[q-i]; } } } // Now, reverse the entries return std::copy(sres.rbegin(),sres.rend(),out); } /*! * \brief Computes the polynomial subresultants * as minors of the Bezout matrix */ template inline OutputIterator bezout_polynomial_subresultants (typename Polynomial_traits_d::Polynomial_d P, typename Polynomial_traits_d::Polynomial_d Q, OutputIterator out) { typedef typename Polynomial_traits_d::Polynomial_d Polynomial; typedef typename Polynomial_traits_d::Coefficient_type NT; typename Polynomial_traits_d::Leading_coefficient lcoeff; typename Polynomial_traits_d::Degree degree; typename Polynomial_traits_d::Construct_polynomial construct; if(degree(P) < 1 || degree(Q) < 1) { *out++ = Polynomial(CGAL::internal::resultant_for_constant_polynomial (P,Q)); return out; } typedef CGAL::internal::Simple_matrix Matrix; Matrix M = CGAL::internal::polynomial_subresultant_matrix (P,Q); int r = static_cast(M.row_dimension()); for(int i = 0;i < r; i++) { std::vector curr_row; std::copy(M[r-1-i].begin(), M[r-1-i].end(), std::back_inserter(curr_row)); //std::reverse(curr_row.begin(),curr_row.end()); *out++ = construct(curr_row.rbegin(),curr_row.rend()); } int deg_diff=degree(P)-degree(Q); if(deg_diff==0) { *out++=Q; } else if(deg_diff>0) { *out++=CGAL::ipower(lcoeff(Q),deg_diff-1)*Q; } else { *out++=CGAL::ipower(lcoeff(P),-deg_diff-1)*P; } return out; } /*! * \brief Compute the sequence of principal subresultants * with pseudo-division * * Uses Ducos algorithm for the polynomial subresultant, and * returns the formal leading coefficients. */ template inline OutputIterator prs_principal_subresultants (typename Polynomial_traits_d::Polynomial_d P, typename Polynomial_traits_d::Polynomial_d Q, OutputIterator out) { typedef typename Polynomial_traits_d::Polynomial_d Polynomial; typedef typename Polynomial_traits_d::Coefficient_type NT; typename Polynomial_traits_d::Degree degree; typename Polynomial_traits_d::Get_coefficient coeff; std::vector sres; int q = (std::min)(degree(Q),degree(P)); CGAL::internal::prs_polynomial_subresultants (P,Q,std::back_inserter(sres)); CGAL_assertion(static_cast(sres.size()) == q+1); for(int i=0; i <= q; i++) { int d = degree(sres[i]); CGAL_assertion(d<=i); if(d inline OutputIterator bezout_principal_subresultants (typename Polynomial_traits_d::Polynomial_d P, typename Polynomial_traits_d::Polynomial_d Q, OutputIterator out) { typedef typename Polynomial_traits_d::Coefficient_type NT; typename Polynomial_traits_d::Leading_coefficient lcoeff; typename Polynomial_traits_d::Degree degree; if(degree(P) < 1 || degree(Q) < 1) { *out++ = CGAL::internal::resultant_for_constant_polynomial (P,Q); return out; } typedef CGAL::internal::Simple_matrix Matrix; Matrix M = CGAL::internal::polynomial_subresultant_matrix (P,Q,1); int r = static_cast(M.row_dimension()); for(int i = r - 1;i >=0; i--) { *out++=M[i][i]; } int deg_diff=degree(P)-degree(Q); if(deg_diff==0) { *out++=NT(1); } else if(deg_diff>0) { *out++=CGAL::ipower(lcoeff(Q),deg_diff); } else { *out++=CGAL::ipower(lcoeff(P),-deg_diff); } return out; } /*! * \brief Computes the subresultants together with the according cofactors * * For details, see S.Basu, R.Pollack, M.-F.Roy: Algorithms in Real * Algebraic Geometry, Second edition, Alg.8.22 */ template OutputIterator1 prs_subresultants_with_cofactors (typename Polynomial_traits_d::Polynomial_d P, typename Polynomial_traits_d::Polynomial_d Q, OutputIterator1 sres_out, OutputIterator2 coP_out, OutputIterator3 coQ_out) { typedef typename Polynomial_traits_d::Polynomial_d Polynomial; typedef typename Polynomial_traits_d::Coefficient_type NT; typename Polynomial_traits_d::Leading_coefficient lcoeff; typename Polynomial_traits_d::Degree degree; typename Polynomial_traits_d::Construct_polynomial construct; if(degree(P) < 1 || degree(Q) < 1) { *sres_out++ = Polynomial(CGAL::internal::resultant_for_constant_polynomial (P,Q)); *coP_out++ = Polynomial(lcoeff(Q)); *coQ_out++ = Polynomial(lcoeff(P)); return sres_out; } bool poly_swapped = (degree(P) < degree(Q)); if(poly_swapped) { std::swap(P,Q); } Polynomial zero_pol = construct(NT(0)); std::vector sres, coP, coQ; #if 0 // old algorithm, there is some problem when deg_diff>1 int deg_diff=degree(P)-degree(Q); if(deg_diff==0) { sres.push_back(Q); } else { sres.push_back(CGAL::ipower(lcoeff(Q),deg_diff-1)*Q); } Polynomial A,B,C,D,Quo, coPA, coPB, coQA, coQB, coPC, coQC; NT s,m; int delta,d,e; coPA = construct(NT(0)); if(deg_diff==0) { coQA = construct(NT(1)); } else { coQA = construct(CGAL::ipower(lcoeff(Q),deg_diff-1)); } coP.push_back(coPA); coQ.push_back(coQA); A=Q; s=CGAL::ipower(lcoeff(Q),deg_diff); //s=CGAL::ipower(lcoeff(Q),1); typename Polynomial_traits_d::Pseudo_division() (P, -Q, Quo, B, m); coPB = construct(m); coQB = Quo; //CGAL_assertion(m*P+Quo*Q==B); //CGAL_assertion(CGAL::degree(B)1) { C=CGAL::ipower(lcoeff(B),delta-1)*B / CGAL::ipower(s,delta-1); coPC = CGAL::ipower(lcoeff(B),delta-1)*coPB / CGAL::ipower(s,delta-1); coQC = CGAL::ipower(lcoeff(B),delta-1)*coQB / CGAL::ipower(s,delta-1); for(int i=0;i sResP,sResU,sResV,C; std::vector s,t; for(int i=0;i1) { NT eps_p_minus_1 = ((p-q)%4==0 || (p-q)%4==1) ? NT(1) : NT(-1); sResP[q]=eps_p_minus_1*CGAL::ipower(lcoeff(Q),p-q-1)*Q; s[q]=eps_p_minus_1*CGAL::ipower(lcoeff(Q),p-q); sResU[q]=construct(NT(0)); sResV[q]=construct(eps_p_minus_1*CGAL::ipower(lcoeff(Q),p-q-1)); for(int i=q+1;i<=p-2;i++) { sResP[i]=sResU[i]=sResV[i]=construct(NT(0)); s[i]=NT(0); } } int i = p+1; int j = p; int k = 0; while(!CGAL::is_zero(sResP[j-1])) { k=degree(sResP[j-1]); if(k>=j-1) { if(k==0) { break; } s[j-1]=t[j-1]; NT prefac=CGAL::ipower(s[j-1],2); NT denom=s[j]*t[i-1]; Polynomial Quo,Rem; NT D; CGAL::pseudo_division(prefac*sResP[i-1],sResP[j-1],Quo,Rem,D); C[k-1]=CGAL::integral_division(Quo,D); sResP[k-1]=CGAL::integral_division (-prefac*sResP[i-1]+C[k-1]*sResP[j-1], denom); sResU[k-1]=CGAL::integral_division (-prefac*sResU[i-1]+C[k-1]*sResU[j-1], denom); sResV[k-1]=CGAL::integral_division (-prefac*sResV[i-1]+C[k-1]*sResV[j-1], denom); } else { // k < j-1 s[j-1]=NT(0); for(int delta=1;delta<=j-k-1;delta++) { t[j-delta-1]=CGAL::ipower(NT(-1),delta)*CGAL::integral_division (t[j-1]*t[j-delta],s[j]); } s[k]=t[k]; sResP[k]=CGAL::integral_division(s[k]*sResP[j-1],t[j-1]); sResU[k]=CGAL::integral_division(s[k]*sResU[j-1],t[j-1]); sResV[k]=CGAL::integral_division(s[k]*sResV[j-1],t[j-1]); for(int ell=k+1;ell<=j-2;ell++) { sResP[ell]=sResU[ell]=sResV[ell]=construct(NT(0)); s[ell]=NT(0); } if(k==0) { break; } Polynomial Quo,Rem; NT D; NT prefac=s[k]*t[j-1]; CGAL::pseudo_division(prefac*sResP[i-1],sResP[j-1],Quo,Rem,D); C[k-1]=CGAL::integral_division(Quo,D); NT denom = s[j]*t[i-1]; sResP[k-1]=CGAL::integral_division (-prefac*sResP[i-1]+C[k-1]*sResP[j-1],denom); sResU[k-1]=CGAL::integral_division (-prefac*sResU[i-1]+C[k-1]*sResU[j-1],denom); sResV[k-1]=CGAL::integral_division (-prefac*sResV[i-1]+C[k-1]*sResV[j-1],denom); } t[k-1]=lcoeff(sResP[k-1]); i=j; j=k; } if(k>0) { for(int ell=0;ell<=j-2;ell++) { sResP[ell]=sResU[ell]=sResV[ell]=construct(NT(0)); s[ell]=NT(0); } } // Correct factors for same degree (hack) if(same_degree) { for(int i = q-1;i>=0;i--) { NT d = lcoeff(Q); CGAL_assertion(CGAL::divides(d,sResP[i])); sResP[i]=CGAL::integral_division(sResP[i],d); CGAL_assertion(CGAL::divides(d,sResU[i])); sResU[i]=CGAL::integral_division(sResU[i],d); CGAL_assertion(CGAL::divides(d,sResV[i])); sResV[i]=CGAL::integral_division(sResV[i],d); } } // Correct the signs (the algorithm computes the signed subresultants) if(degree(P)==degree(Q)) { p--; CGAL_assertion(p==q); } for(int i = q;i>=0;i--) { if((p-i)%4==0 || (p-i)%4==1) { sres.push_back(sResP[i]); coP.push_back(sResU[i]); coQ.push_back(sResV[i]); } else { sres.push_back(-sResP[i]); coP.push_back(-sResU[i]); coQ.push_back(-sResV[i]); } } CGAL_assertion(static_cast(sres.size()) == degree(Q)+1); // If P and Q were swapped, correct the signs if(poly_swapped) { int p = degree(P); int q = degree(Q); for(int i=0;i<=q;i++) { if((p-i)*(q-i) % 2 == 1) { sres[q-i] = -sres[q-i]; coP[q-i] = -coP[q-i]; coQ[q-i] = -coQ[q-i]; } } for(int i=0;i<=q;i++) { // Swap coP and coQ: Polynomial help = coP[i]; coP[i] = coQ[i]; coQ[i] = help; } } // Now, reverse the entries std::copy(coP.rbegin(),coP.rend(),coP_out); std::copy(coQ.rbegin(),coQ.rend(),coQ_out); return std::copy(sres.rbegin(),sres.rend(),sres_out); } // the general function for CGAL::Integral_domain_without_division_tag template inline OutputIterator polynomial_subresultants_(typename Polynomial_traits_d::Polynomial_d A, typename Polynomial_traits_d::Polynomial_d B, OutputIterator out, CGAL::Integral_domain_without_division_tag){ return bezout_polynomial_subresultants(A,B,out); } // the specialization for CGAL::Integral_domain_tag template inline OutputIterator polynomial_subresultants_(typename Polynomial_traits_d::Polynomial_d A, typename Polynomial_traits_d::Polynomial_d B, OutputIterator out, CGAL::Integral_domain_tag){ return prs_polynomial_subresultants(A,B,out); } template inline OutputIterator polynomial_subresultants_ (typename Polynomial_traits_d::Polynomial_d A, typename Polynomial_traits_d::Polynomial_d B, OutputIterator out) { typedef typename Polynomial_traits_d::Coefficient_type NT; typedef typename CGAL::Algebraic_structure_traits::Algebraic_category Algebraic_category; return polynomial_subresultants_ (A,B,out,Algebraic_category()); } // the general function for CGAL::Integral_domain_without_division_tag template inline OutputIterator principal_subresultants_(typename Polynomial_traits_d::Polynomial_d A, typename Polynomial_traits_d::Polynomial_d B, OutputIterator out, CGAL::Integral_domain_without_division_tag){ return bezout_principal_subresultants(A,B,out); } // the specialization for CGAL::Integral_domain_tag template inline OutputIterator principal_subresultants_(typename Polynomial_traits_d::Polynomial_d A, typename Polynomial_traits_d::Polynomial_d B, OutputIterator out, CGAL::Integral_domain_tag){ return prs_principal_subresultants(A,B,out); } template inline OutputIterator principal_subresultants_ (typename Polynomial_traits_d::Polynomial_d A, typename Polynomial_traits_d::Polynomial_d B, OutputIterator out) { typedef typename Polynomial_traits_d::Coefficient_type NT; typedef typename CGAL::Algebraic_structure_traits::Algebraic_category Algebraic_category; return principal_subresultants_ (A,B,out,Algebraic_category()); } template OutputIterator1 polynomial_subresultants_with_cofactors_ (typename Polynomial_traits_d::Polynomial_d P, typename Polynomial_traits_d::Polynomial_d Q, OutputIterator1 sres_out, OutputIterator2 coP_out, OutputIterator3 coQ_out, CGAL::Integral_domain_tag) { return prs_subresultants_with_cofactors (P,Q,sres_out,coP_out,coQ_out); } template OutputIterator1 polynomial_subresultants_with_cofactors_ (typename Polynomial_traits_d::Polynomial_d /* P */, typename Polynomial_traits_d::Polynomial_d /* Q */, OutputIterator1 sres_out, OutputIterator2 /* coP_out */, OutputIterator3 /* coQ_out */, CGAL::Integral_domain_without_division_tag) { // polynomial_subresultants_with_cofactors requires // a model of IntegralDomain as coefficient type; CGAL_static_assertion(sizeof(Polynomial_traits_d)==0); return sres_out; } template OutputIterator1 polynomial_subresultants_with_cofactors_ (typename Polynomial_traits_d::Polynomial_d P, typename Polynomial_traits_d::Polynomial_d Q, OutputIterator1 sres_out, OutputIterator2 coP_out, OutputIterator3 coQ_out) { typedef typename Polynomial_traits_d::Coefficient_type NT; typedef typename CGAL::Algebraic_structure_traits::Algebraic_category Algebraic_category; return polynomial_subresultants_with_cofactors_ (P,Q,sres_out,coP_out,coQ_out,Algebraic_category()); } /*! \relates CGAL::Polynomial * \brief compute the polynomial subresultants of the polynomials * \c A and \c B * * If \c n and \c m are the degrees of p and q, * the routine returns a sequence * of length min(n,m)+1, the (polynomial) subresultants of \c p and \c q. * It starts with the resultant of \c p and \c q. * The ith polynomial has degree at most i. * * The way the subresultants are computed depends on the Algebra_type. * In general the subresultant will be computed by the function * CGAL::bezout_polynomial_subresultants, but if possible the function * CGAL::prs_polynomial_subresultants is used. */ template inline OutputIterator polynomial_subresultants (typename Polynomial_traits_d::Polynomial_d p, typename Polynomial_traits_d::Polynomial_d q, OutputIterator out) { return CGAL::internal::polynomial_subresultants_ (p, q, out); } /*! \relates CGAL::Polynomial * \brief compute the principal subresultants of the polynomials * \c p and \c q * * If \c n and \c m are the degrees of A and B, * the routine returns a sequence * of length min(n,m)+1, the (principal) subresultants of \c p and \c q, * which starts with the resultant of \c p and \c q. * * The way the subresultants are computed depends on the Algebra_type. * In general the subresultant will be computed by the function * CGAL::bezout_principal_subresultants, but if possible the function * CGAL::prs_principal_subresultants is used. */ template inline OutputIterator principal_subresultants (typename Polynomial_traits_d::Polynomial_d p, typename Polynomial_traits_d::Polynomial_d q, OutputIterator out) { return CGAL::internal::principal_subresultants_ (p, q, out); } template OutputIterator1 polynomial_subresultants_with_cofactors (typename Polynomial_traits_d::Polynomial_d p, typename Polynomial_traits_d::Polynomial_d q, OutputIterator1 sres_out, OutputIterator2 coP_out, OutputIterator3 coQ_out) { return CGAL::internal::polynomial_subresultants_with_cofactors_ (p,q,sres_out,coP_out,coQ_out); } } // namespace internal } //namespace CGAL #endif// CGAL_POLYNOMIAL_SUBRESULTANTS_H