dust3d/thirdparty/cgal/CGAL-5.1/include/CGAL/Polynomial/polynomial_gcd_implementati...

225 lines
6.0 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/polynomial_gcd_implementations.h $
// $Id: polynomial_gcd_implementations.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@informatik.uni-mainz.de>
#ifndef CGAL_POLYNOMIAL_GCD_IMPLEMENTATIONS_H
#define CGAL_POLYNOMIAL_GCD_IMPLEMENTATIONS_H
#include <CGAL/basic.h>
#include <CGAL/Polynomial.h>
#include <CGAL/Real_timer.h>
#include <CGAL/polynomial_utils.h>
#include <CGAL/Polynomial/hgdelta_update.h>
#include <CGAL/Polynomial/polynomial_gcd.h>
namespace CGAL {
namespace internal {
template <class NT>
inline
Polynomial<NT> gcd_utcf_UFD(
Polynomial<NT> p1, Polynomial<NT> 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>(NT(1));
else {
return CGAL::canonicalize(p2);
}
}
if (p2.is_zero()){
return CGAL::canonicalize(p1);
}
if (p2.degree() > p1.degree()) {
Polynomial<NT> 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<NT> q, r;
NT g = NT(1), h = NT(1);
for (;;) {
Polynomial<NT>::pseudo_division(p1, p2, q, r, dummy);
if (r.is_zero()) { break; }
if (r.degree() == 0) {
return CGAL::canonicalize(Polynomial<NT>(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 <class NT>
inline
Polynomial<NT> gcd_Euclidean_ring(
Polynomial<NT> p1, Polynomial<NT> p2
) {
// std::cout<<" gcd_Field"<<std::endl;
// handle trivial cases
if (p1.is_zero()){
if (p2.is_zero()) return Polynomial<NT>(NT(1));
else return p2 / p2.unit_part();
}
if (p2.is_zero())
return p1 / p1.unit_part();
if (p2.degree() > p1.degree()) {
Polynomial<NT> p3 = p1; p1 = p2; p2 = p3;
}
Polynomial<NT> q, r;
while (!p2.is_zero()) {
Polynomial<NT>::euclidean_division(p1, p2, q, r);
p1 = p2; p2 = r;
}
p1 /= p1.lcoeff();
p1.simplify_coefficients();
return p1;
}
template <class NT>
inline
NT content_utcf_(const Polynomial<NT>& p)
{
typename Algebraic_structure_traits<NT>::Integral_division idiv;
typename Algebraic_structure_traits<NT>::Unit_part upart;
typedef typename Polynomial<NT>::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 <class NT>
inline
Polynomial<NT> gcd_utcf_Integral_domain( Polynomial<NT> p1, Polynomial<NT> p2){
// std::cout<<" gcd_utcf_Integral_domain"<<std::endl;
typedef Polynomial<NT> POLY;
// handle trivial cases
if (p1.is_zero()){
if (p2.is_zero()){
return Polynomial<NT>(NT(1));
}else{
return CGAL::canonicalize(p2);
}
}
if (p2.is_zero()){
return CGAL::canonicalize(p1);
}
if (p2.degree() > p1.degree()) {
Polynomial<NT> 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<NT> q, r;
// TODO measure preformance of both methodes with respect to
// univariat polynomials on Integeres
// univariat polynomials on Sqrt_extension<Integer,Integer>
// 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<NT>::pseudo_division(p1, p2, q, r, dummy);
if (r.is_zero()) { break; }
if (r.degree() == 0) { return Polynomial<NT>(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<NT>::pseudo_division(p1, p2, q, r, dummy);
if (r.is_zero()) { break; }
if (r.degree() == 0) { return Polynomial<NT>(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<NT> result;
// make poly unique
result = CGAL::canonicalize(p2);
return result;
}
} // namespace internal
} // namespace CGAL
#endif //CGAL_POLYNOMIAL_GCD_IMPLEMENTATIONS_H