// 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 Hemmer #ifndef CGAL_POLYNOMIAL_GCD_IMPLEMENTATIONS_H #define CGAL_POLYNOMIAL_GCD_IMPLEMENTATIONS_H #include #include #include #include #include #include namespace CGAL { namespace internal { template inline Polynomial gcd_utcf_UFD( Polynomial p1, Polynomial p2 ) { // implemented using the subresultant algorithm for gcd computation // see [Cohen, 1993], algorithm 3.3.1 // handle trivial cases if (p1.is_zero()){ if (p2.is_zero()) return Polynomial(NT(1)); else { return CGAL::canonicalize(p2); } } if (p2.is_zero()){ return CGAL::canonicalize(p1); } if (p2.degree() > p1.degree()) { Polynomial p3 = p1; p1 = p2; p2 = p3; } // compute gcd of content NT p1c = p1.content(), p2c = p2.content(); NT gcdcont = CGAL::gcd(p1c,p2c); // compute gcd of primitive parts p1 /= p1c; p2 /= p2c; NT dummy; Polynomial q, r; NT g = NT(1), h = NT(1); for (;;) { Polynomial::pseudo_division(p1, p2, q, r, dummy); if (r.is_zero()) { break; } if (r.degree() == 0) { return CGAL::canonicalize(Polynomial(gcdcont)); } int delta = p1.degree() - p2.degree(); p1 = p2; p2 = r / (g * ipower(h, delta)); g = p1.lcoeff(); // h = h^(1-delta) * g^delta CGAL::internal::hgdelta_update(h, g, delta); } p2 /= p2.content() * p2.unit_part(); // combine both parts to proper gcd p2 *= gcdcont; return CGAL::canonicalize(p2); } template inline Polynomial gcd_Euclidean_ring( Polynomial p1, Polynomial p2 ) { // std::cout<<" gcd_Field"<(NT(1)); else return p2 / p2.unit_part(); } if (p2.is_zero()) return p1 / p1.unit_part(); if (p2.degree() > p1.degree()) { Polynomial p3 = p1; p1 = p2; p2 = p3; } Polynomial q, r; while (!p2.is_zero()) { Polynomial::euclidean_division(p1, p2, q, r); p1 = p2; p2 = r; } p1 /= p1.lcoeff(); p1.simplify_coefficients(); return p1; } template inline NT content_utcf_(const Polynomial& p) { typename Algebraic_structure_traits::Integral_division idiv; typename Algebraic_structure_traits::Unit_part upart; typedef typename Polynomial::const_iterator const_iterator; const_iterator it = p.begin(), ite = p.end(); while (*it == NT(0)) it++; NT cont = idiv(*it, upart(*it)); for( ; it != ite; it++) { if (cont == NT(1)) break; if (*it != NT(0)) cont = internal::gcd_utcf_(cont, *it); } return cont; } template inline Polynomial gcd_utcf_Integral_domain( Polynomial p1, Polynomial p2){ // std::cout<<" gcd_utcf_Integral_domain"< POLY; // handle trivial cases if (p1.is_zero()){ if (p2.is_zero()){ return Polynomial(NT(1)); }else{ return CGAL::canonicalize(p2); } } if (p2.is_zero()){ return CGAL::canonicalize(p1); } if (p2.degree() > p1.degree()) { Polynomial p3 = p1; p1 = p2; p2 = p3; } // remove redundant scalar factors p1=CGAL::canonicalize(p1); p2=CGAL::canonicalize(p2); // compute content of p1 and p2 NT p1c = internal::content_utcf_(p1); NT p2c = internal::content_utcf_(p2); // compute gcd of content NT gcdcont = internal::gcd_utcf_(p1c, p2c); // compute gcd of primitive parts p1 = integral_division_up_to_constant_factor(p1, POLY(p1c)); p2 = integral_division_up_to_constant_factor(p2, POLY(p2c)); Polynomial q, r; // TODO measure preformance of both methodes with respect to // univariat polynomials on Integeres // univariat polynomials on Sqrt_extension // multivariat polynomials // May write specializations for different cases #if 0 // implemented using the subresultant algorithm for gcd computation // with respect to constant scalar factors // see [Cohen, 1993], algorithm 3.3.1 NT g = NT(1), h = NT(1), dummy; for (;;) { Polynomial::pseudo_division(p1, p2, q, r, dummy); if (r.is_zero()) { break; } if (r.degree() == 0) { return Polynomial(gcdcont); } int delta = p1.degree() - p2.degree(); p1 = p2; p2 = r / (g * ipower(h, delta)); g = p1.lcoeff(); // h = h^(1-delta) * g^delta CGAL::internal::hgdelta_update(h, g, delta); } #else // implentaion using just the 'naive' methode // but performed much better as the one by Cohen // (for univariat polynomials with Sqrt_extension coeffs ) NT dummy; for (;;) { Polynomial::pseudo_division(p1, p2, q, r, dummy); if (r.is_zero()) { break; } if (r.degree() == 0) { return Polynomial(gcdcont); } p1 = p2; p2 = r ; p2=CGAL::canonicalize(p2); } #endif p2 = integral_division_up_to_constant_factor(p2, POLY(content_utcf_(p2))); // combine both parts to proper gcd p2 *= gcdcont; Polynomial result; // make poly unique result = CGAL::canonicalize(p2); return result; } } // namespace internal } // namespace CGAL #endif //CGAL_POLYNOMIAL_GCD_IMPLEMENTATIONS_H