BWAPI
|
00001 // Copyright (c) 2008 Max-Planck-Institute Saarbruecken (Germany). 00002 // All rights reserved. 00003 // 00004 // This file is part of CGAL (www.cgal.org); you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public License as 00006 // published by the Free Software Foundation; version 2.1 of the License. 00007 // See the file LICENSE.LGPL distributed with CGAL. 00008 // 00009 // Licensees holding a valid commercial license may use this file in 00010 // accordance with the commercial license agreement provided with the software. 00011 // 00012 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 00013 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00014 // 00015 // $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.5-branch/Polynomial/include/CGAL/Polynomial/polynomial_gcd.h $ 00016 // $Id: polynomial_gcd.h 47254 2008-12-06 21:18:27Z afabri $ 00017 // 00018 // 00019 // Author(s) : Arno Eigenwillig <arno@mpi-inf.mpg.de> 00020 // Tobias Reithmann <treith@mpi-inf.mpg.de> 00021 // Michael Hemmer <hemmer@informatik.uni-mainz.de> 00022 // Michael Kerber <mkerber@mpi-inf.mpg.de> 00023 // Dominik Huelse <dominik.huelse@gmx.de> 00024 // ============================================================================ 00025 00030 #ifndef CGAL_POLYNOMIAL_GCD_H 00031 #define CGAL_POLYNOMIAL_GCD_H 00032 00033 #ifndef CGAL_USE_INTERNAL_MODULAR_GCD 00034 #define CGAL_USE_INTERNAL_MODULAR_GCD 1 00035 #endif 00036 00037 #include <CGAL/basic.h> 00038 #include <CGAL/Residue.h> 00039 #include <CGAL/Polynomial.h> 00040 #include <CGAL/Scalar_factor_traits.h> 00041 #include <CGAL/Real_timer.h> 00042 #include <CGAL/Polynomial/Polynomial_type.h> 00043 #include <CGAL/Polynomial/misc.h> 00044 #include <CGAL/Polynomial/polynomial_gcd_implementations.h> 00045 #include <CGAL/polynomial_utils.h> 00046 00047 //#undef LiS_HAVE_NTL 00048 #ifdef LiS_HAVE_NTL 00049 #include <CGAL/Polynomial/polynomial_gcd_ntl.h> 00050 #endif 00051 00052 #if CGAL_USE_INTERNAL_MODULAR_GCD 00053 #include <CGAL/Polynomial/modular_gcd.h> 00054 #endif 00055 00056 00057 // 1) gcd (basic form without cofactors) 00058 // uses three level of dispatch on tag types: 00059 // a) if the algebra type of the innermost coefficient is a field, 00060 // ask for decomposability. for UFDs compute the gcd directly 00061 // b) if NT supports integralization, the gcd is computed on 00062 // integralized polynomials 00063 // c) over a field (unless integralized), use the Euclidean algorithm; 00064 // over a UFD, use the subresultant algorithm 00065 // 00066 // NOTICE: For better performance, especially in AlciX, there exist special 00067 // modular implementations for the polynmials with coefficient type 00068 // leda::integer and the CORE::BigInt type which use, when the 00069 // NTL library is available. 00070 // see CGAL/Polynomial/polynomial_gcd_ntl.h 00071 00072 namespace CGAL { 00073 namespace CGALi { 00074 00075 template <class NT> 00076 inline 00077 Polynomial<NT> gcd_( 00078 const Polynomial<NT>& p1, 00079 const Polynomial<NT>& p2, 00080 Field_tag) 00081 { 00082 return CGAL::CGALi::gcd_utcf(p1,p2); 00083 } 00084 00085 template <class NT> 00086 inline 00087 Polynomial<NT> gcd_( 00088 const Polynomial<NT>& p1, 00089 const Polynomial<NT>& p2, 00090 Unique_factorization_domain_tag) 00091 { 00092 typedef Polynomial<NT> POLY; 00093 typedef Polynomial_traits_d<POLY> PT; 00094 typedef typename PT::Innermost_coefficient_type IC; 00095 00096 typename PT::Multivariate_content mcont; 00097 IC mcont_p1 = mcont(p1); 00098 IC mcont_p2 = mcont(p2); 00099 00100 typename CGAL::Coercion_traits<POLY,IC>::Cast ictp; 00101 POLY p1_ = CGAL::integral_division(p1,ictp(mcont_p1)); 00102 POLY p2_ = CGAL::integral_division(p2,ictp(mcont_p2)); 00103 00104 return CGAL::CGALi::gcd_utcf(p1_, p2_) * ictp(CGAL::gcd(mcont_p1, mcont_p2)); 00105 } 00106 00107 00108 00109 // name gcd() forwarded to the CGALi::gcd_() dispatch function 00116 template <class NT> 00117 inline 00118 Polynomial<NT> gcd(const Polynomial<NT>& p1, const Polynomial<NT>& p2) 00119 { 00120 typedef typename CGALi::Innermost_coefficient_type<Polynomial<NT> >::Type IC; 00121 typedef typename Algebraic_structure_traits<IC>::Algebraic_category Algebraic_category; 00122 00123 // Filter for zero-polynomials 00124 if( p1 == Polynomial<NT>(0) ) 00125 return p2; 00126 if( p2 == Polynomial<NT>(0) ) 00127 return p1; 00128 return CGALi::gcd_(p1,p2,Algebraic_category()); 00129 } 00130 00131 } // namespace CGALi 00132 00133 // 2) gcd_utcf computation 00134 // (gcd up to scalar factors, for non-UFD non-field coefficients) 00135 // a) first try to decompose the coefficients 00136 // b) second dispatch depends on the algebra type of NT 00137 00138 namespace CGALi { 00139 00140 template <class NT> Polynomial<NT> 00141 gcd_utcf_(const Polynomial<NT>&, const Polynomial<NT>&); 00142 00143 // is fraction ? 00144 template <class NT> Polynomial<NT> 00145 gcd_utcf_is_fraction_( const Polynomial<NT>&, const Polynomial<NT>&, 00146 ::CGAL::Tag_true); 00147 template <class NT> Polynomial<NT> 00148 gcd_utcf_is_fraction_( const Polynomial<NT>&, const Polynomial<NT>&, 00149 ::CGAL::Tag_false); 00150 00151 // is type modularizable 00152 template <class NT> Polynomial<NT> 00153 gcd_utcf_modularizable_algebra_( const Polynomial<NT>&, const Polynomial<NT>&, 00154 ::CGAL::Tag_false, Integral_domain_tag); 00155 template <class NT> Polynomial<NT> 00156 gcd_utcf_modularizable_algebra_( const Polynomial<NT>&, const Polynomial<NT>&, 00157 ::CGAL::Tag_false, Unique_factorization_domain_tag); 00158 template <class NT> Polynomial<NT> 00159 gcd_utcf_modularizable_algebra_( const Polynomial<NT>&, const Polynomial<NT>&, 00160 ::CGAL::Tag_false, Field_tag); 00161 00162 template <class NT> Polynomial<NT> 00163 gcd_utcf_modularizable_algebra_( const Polynomial<NT>&, const Polynomial<NT>&, 00164 ::CGAL::Tag_true, Integral_domain_tag); 00165 template <class NT> Polynomial<NT> 00166 gcd_utcf_modularizable_algebra_( const Polynomial<NT>&, const Polynomial<NT>&, 00167 ::CGAL::Tag_true, Unique_factorization_domain_tag); 00168 template <class NT> Polynomial<NT> 00169 gcd_utcf_modularizable_algebra_( const Polynomial<NT>&, const Polynomial<NT>&, 00170 ::CGAL::Tag_true, Field_tag); 00171 00172 00173 template <class NT> Polynomial<NT> inline 00174 gcd_utcf_(const Polynomial<NT>& p1, const Polynomial<NT>& p2){ 00175 typedef CGAL::Fraction_traits< Polynomial<NT> > FT; 00176 typedef typename FT::Is_fraction Is_fraction; 00177 return gcd_utcf_is_fraction_(p1, p2, Is_fraction()); 00178 } 00179 00180 // is fraction ? 00181 template <class NT> Polynomial<NT> inline 00182 gcd_utcf_is_fraction_( 00183 const Polynomial<NT>& p1, 00184 const Polynomial<NT>& p2, 00185 ::CGAL::Tag_true) 00186 { 00187 typedef Polynomial<NT> POLY; 00188 typedef Polynomial_traits_d<POLY> PT; 00189 typedef Fraction_traits<POLY> FT; 00190 00191 typename FT::Denominator_type dummy; 00192 typename FT::Numerator_type p1i, p2i; 00193 00194 typename FT::Decompose()(p1,p1i, dummy); 00195 typename FT::Decompose()(p2,p2i, dummy); 00196 00197 typename Coercion_traits<POLY,typename FT::Numerator_type>::Cast cast; 00198 return typename PT::Canonicalize()(cast(CGALi::gcd_utcf(p1i, p2i))); 00199 } 00200 00201 template <class NT> Polynomial<NT> inline 00202 gcd_utcf_is_fraction_( 00203 const Polynomial<NT>& p1, 00204 const Polynomial<NT>& p2, 00205 ::CGAL::Tag_false) 00206 { 00207 typedef Algebraic_structure_traits< Polynomial<NT> > NTT; 00208 typedef CGAL::Modular_traits<Polynomial<NT> > MT; 00209 00210 return gcd_utcf_modularizable_algebra_( 00211 p1,p2,typename MT::Is_modularizable(),typename NTT::Algebraic_category()); 00212 } 00213 00214 // is type modularizable 00215 template <class NT> Polynomial<NT> inline 00216 gcd_utcf_modularizable_algebra_( 00217 const Polynomial<NT>& p1, 00218 const Polynomial<NT>& p2, 00219 ::CGAL::Tag_false, 00220 Integral_domain_tag){ 00221 return CGALi::gcd_utcf_Integral_domain(p1, p2); 00222 } 00223 template <class NT> Polynomial<NT> inline 00224 gcd_utcf_modularizable_algebra_( 00225 const Polynomial<NT>& p1, 00226 const Polynomial<NT>& p2, 00227 ::CGAL::Tag_false, 00228 Unique_factorization_domain_tag){ 00229 return CGALi::gcd_utcf_UFD(p1, p2); 00230 } 00231 template <class NT> Polynomial<NT> inline 00232 gcd_utcf_modularizable_algebra_( 00233 const Polynomial<NT>& p1, 00234 const Polynomial<NT>& p2, 00235 ::CGAL::Tag_false, 00236 Euclidean_ring_tag){ 00237 return CGALi::gcd_Euclidean_ring(p1, p2); 00238 } 00239 00240 #if CGAL_USE_INTERNAL_MODULAR_GCD 00241 template <class NT> Polynomial<NT> inline 00242 gcd_utcf_modularizable_algebra_( 00243 const Polynomial<NT>& p1, 00244 const Polynomial<NT>& p2, 00245 ::CGAL::Tag_true, 00246 Integral_domain_tag tag){ 00247 return modular_gcd_utcf(p1, p2, tag); 00248 // return modular_gcd_utcf_with_wang(p1, p2); 00249 } 00250 template <class NT> Polynomial<NT> inline 00251 gcd_utcf_modularizable_algebra_( 00252 const Polynomial<NT>& p1, 00253 const Polynomial<NT>& p2, 00254 ::CGAL::Tag_true, 00255 Unique_factorization_domain_tag tag){ 00256 return modular_gcd_utcf(p1, p2, tag); 00257 // return modular_gcd_utcf_algorithm_M(p1, p2); 00258 } 00259 #else 00260 template <class NT> Polynomial<NT> inline 00261 gcd_utcf_modularizable_algebra_( 00262 const Polynomial<NT>& p1, 00263 const Polynomial<NT>& p2, 00264 ::CGAL::Tag_true, 00265 Integral_domain_tag){ 00266 return CGALi::gcd_utcf_Integral_domain(p1, p2); 00267 } 00268 template <class NT> Polynomial<NT> inline 00269 gcd_utcf_modularizable_algebra_( 00270 const Polynomial<NT>& p1, 00271 const Polynomial<NT>& p2, 00272 ::CGAL::Tag_true, 00273 Unique_factorization_domain_tag){ 00274 return CGALi::gcd_utcf_UFD(p1, p2); 00275 } 00276 #endif 00277 00278 template <class NT> Polynomial<NT> inline 00279 gcd_utcf_modularizable_algebra_( 00280 const Polynomial<NT>& p1, 00281 const Polynomial<NT>& p2, 00282 ::CGAL::Tag_true, 00283 Euclidean_ring_tag){ 00284 // No modular algorithm available 00285 return CGALi::gcd_Euclidean_ring(p1, p2); 00286 } 00287 00288 template <class NT> Polynomial<NT> inline 00289 gcd_utcf(const Polynomial<NT>& p1, const Polynomial<NT>& p2){ 00290 return CGALi::gcd_utcf_(p1,p2); 00291 } 00292 00293 } // namespace CGALi 00294 00295 00296 // 3) extended gcd computation (with cofactors) 00297 // with dispatch similar to gcd 00298 00299 namespace CGALi { 00300 00301 template <class NT> 00302 inline 00303 Polynomial<NT> gcdex_( 00304 Polynomial<NT> x, Polynomial<NT> y, 00305 Polynomial<NT>& xf, Polynomial<NT>& yf, 00306 ::CGAL::Tag_false 00307 ) { 00308 typedef typename Algebraic_structure_traits<NT>::Algebraic_category Algebraic_category; 00309 return gcdex_(x, y, xf, yf, Algebraic_category()); 00310 }; 00311 00312 template <class NT> 00313 inline 00314 Polynomial<NT> gcdex_( 00315 Polynomial<NT> x, Polynomial<NT> y, 00316 Polynomial<NT>& xf, Polynomial<NT>& yf, 00317 Field_tag 00318 ) { 00319 /* The extended Euclidean algorithm for univariate polynomials. 00320 * See [Cohen, 1993], algorithm 3.2.2 00321 */ 00322 typedef Polynomial<NT> POLY; 00323 typename Algebraic_structure_traits<NT>::Integral_div idiv; 00324 00325 // handle trivial cases 00326 if (x.is_zero()) { 00327 if (y.is_zero()) CGAL_error_msg("gcdex(0,0) is undefined"); 00328 xf = NT(0); yf = idiv(NT(1), y.unit_part()); 00329 return yf * y; 00330 } 00331 if (y.is_zero()) { 00332 yf = NT(0); xf = idiv(NT(1), x.unit_part()); 00333 return xf * x; 00334 } 00335 bool swapped = x.degree() < y.degree(); 00336 if (swapped) { POLY t = x; x = y; y = t; } 00337 00338 // main loop 00339 POLY u = x, v = y, q, r, m11(1), m21(0), m21old; 00340 for (;;) { 00341 /* invariant: (i) There exist m12 and m22 such that 00342 * u = m11*x + m12*y 00343 * v = m21*x + m22*y 00344 * (ii) and we have 00345 * gcd(u,v) == gcd(x,y) 00346 */ 00347 00348 // compute next element of remainder sequence 00349 POLY::euclidean_division(u, v, q, r); // u == qv + r 00350 if (r.is_zero()) break; 00351 00352 // update u and v while preserving invariant 00353 u = v; v = r; 00354 /* Since r = u - qv, this preserves invariant (part ii) 00355 * and corresponds to the matrix assignment 00356 * (u) = (0 1) (u) 00357 * (v) (1 -q) (v) 00358 */ 00359 m21old = m21; m21 = m11 - q*m21; m11 = m21old; 00360 /* This simulates the matching matrix assignment 00361 * (m11 m12) = (0 1) (m11 m12) 00362 * (m21 m22) (1 -q) (m21 m22) 00363 * which preserves the invariant (part i) 00364 */ 00365 if (r.degree() == 0) break; 00366 } 00367 /* postcondition: invariant holds and v divides u */ 00368 00369 // make gcd unit-normal 00370 m21 /= v.unit_part(); v /= v.unit_part(); 00371 00372 // obtain m22 such that v == m21*x + m22*y 00373 POLY m22; 00374 POLY::euclidean_division(v - m21*x, y, m22, r); 00375 CGAL_assertion(r.is_zero()); 00376 00377 // check computation 00378 CGAL_assertion(v == m21*x + m22*y); 00379 00380 // return results 00381 if (swapped) { 00382 xf = m22; yf = m21; 00383 } else { 00384 xf = m21; yf = m22; 00385 } 00386 return v; 00387 } 00388 00389 template <class NT> 00390 inline 00391 Polynomial<NT> gcdex_( 00392 Polynomial<NT> x, Polynomial<NT> y, 00393 Polynomial<NT>& xf, Polynomial<NT>& yf, 00394 ::CGAL::Tag_true 00395 ) { 00396 typedef Polynomial<NT> POLY; 00397 typedef typename CGAL::Fraction_traits<POLY>::Numerator_type INTPOLY; 00398 typedef typename CGAL::Fraction_traits<POLY>::Denominator_type DENOM; 00399 typedef typename INTPOLY::NT INTNT; 00400 00401 typename CGAL::Fraction_traits<POLY>::Decompose decompose; 00402 typename CGAL::Fraction_traits<POLY>::Compose compose; 00403 00404 00405 // rewrite x as xi/xd and y as yi/yd with integral polynomials xi, yi 00406 DENOM xd, yd; 00407 x.simplify_coefficients(); 00408 y.simplify_coefficients(); 00409 INTPOLY xi ,yi; 00410 decompose(x,xi,xd); 00411 decompose(y,yi,yd); 00412 00413 // compute the integral gcd with cofactors: 00414 // vi = gcd(xi, yi); vfi*vi == xfi*xi + yfi*yi 00415 INTPOLY xfi, yfi; INTNT vfi; 00416 INTPOLY vi = pseudo_gcdex(xi, yi, xfi, yfi, vfi); 00417 00418 // proceed to vfi*v == xfi*x + yfi*y with v = gcd(x,y) (unit-normal) 00419 POLY v = compose(vi, vi.lcoeff()); 00420 v.simplify_coefficients(); 00421 CGAL_assertion(v.unit_part() == NT(1)); 00422 vfi *= vi.lcoeff(); xfi *= xd; yfi *= yd; 00423 00424 // compute xf, yf such that gcd(x,y) == v == xf*x + yf*y 00425 xf = compose(xfi, vfi); 00426 yf = compose(yfi, vfi); 00427 xf.simplify_coefficients(); 00428 yf.simplify_coefficients(); 00429 return v; 00430 }; 00431 00432 } // namespace CGALi 00433 00455 template <class NT> 00456 inline 00457 Polynomial<NT> gcdex( 00458 Polynomial<NT> p1, Polynomial<NT> p2, 00459 Polynomial<NT>& f1, Polynomial<NT>& f2 00460 ) { 00461 typedef typename CGAL::Fraction_traits< Polynomial<NT> > 00462 ::Is_fraction Is_fraction; 00463 return CGALi::gcdex_(p1, p2, f1, f2, Is_fraction()); 00464 }; 00465 00466 00483 template <class NT> 00484 inline 00485 Polynomial<NT> pseudo_gcdex( 00486 #ifdef DOXYGEN_RUNNING 00487 Polynomial<NT> p1, Polynomial<NT> p2, 00488 Polynomial<NT>& f2, Polynomial<NT>& f2, NT& v 00489 #else 00490 Polynomial<NT> x, Polynomial<NT> y, 00491 Polynomial<NT>& xf, Polynomial<NT>& yf, NT& vf 00492 #endif // DOXYGEN_RUNNING 00493 ) { 00494 /* implemented using the extended subresultant algorithm 00495 * for gcd computation with Bezout factors 00496 * 00497 * To understand this, you need to understand the computation of 00498 * cofactors as in the basic extended Euclidean algorithm (see 00499 * the code above of gcdex_(..., Field_tag)), and the subresultant 00500 * gcd algorithm, see gcd_(..., Unique_factorization_domain_tag). 00501 * 00502 * The crucial point of the combination of both is the observation 00503 * that the subresultant factor (called rho here) divided out of the 00504 * new remainder in each step can also be divided out of the 00505 * cofactors. 00506 */ 00507 00508 typedef Polynomial<NT> POLY; 00509 typename Algebraic_structure_traits<NT>::Integral_division idiv; 00510 typename Algebraic_structure_traits<NT>::Gcd gcd; 00511 00512 // handle trivial cases 00513 if (x.is_zero()) { 00514 if (y.is_zero()) CGAL_error_msg("gcdex(0,0) is undefined"); 00515 xf = NT(0); yf = NT(1); vf = y.unit_part(); 00516 return y / vf; 00517 } 00518 if (y.is_zero()) { 00519 xf = NT(1); yf = NT(0); vf = x.unit_part(); 00520 return x / vf; 00521 } 00522 bool swapped = x.degree() < y.degree(); 00523 if (swapped) { POLY t = x; x = y; y = t; } 00524 00525 // compute gcd of content 00526 NT xcont = x.content(); NT ycont = y.content(); 00527 NT gcdcont = gcd(xcont, ycont); 00528 00529 // compute gcd of primitive parts 00530 POLY xprim = x / xcont; POLY yprim = y / ycont; 00531 POLY u = xprim, v = yprim, q, r; 00532 POLY m11(1), m21(0), m21old; 00533 NT g(1), h(1), d, rho; 00534 for (;;) { 00535 int delta = u.degree() - v.degree(); 00536 POLY::pseudo_division(u, v, q, r, d); 00537 CGAL_assertion(d == ipower(v.lcoeff(), delta+1)); 00538 if (r.is_zero()) break; 00539 rho = g * ipower(h, delta); 00540 u = v; v = r / rho; 00541 m21old = m21; m21 = (d*m11 - q*m21) / rho; m11 = m21old; 00542 /* The transition from (u, v) to (v, r/rho) corresponds 00543 * to multiplication with the matrix 00544 * __1__ (0 rho) 00545 * rho (d -q) 00546 * The comments and correctness arguments from 00547 * gcdex(..., Field_tag) apply analogously. 00548 */ 00549 g = u.lcoeff(); 00550 CGAL::CGALi::hgdelta_update(h, g, delta); 00551 if (r.degree() == 0) break; 00552 } 00553 00554 // obtain v == m21*xprim + m22*yprim 00555 // the correct m21 was already computed above 00556 POLY m22; 00557 POLY::euclidean_division(v - m21*xprim, yprim, m22, r); 00558 CGAL_assertion(r.is_zero()); 00559 00560 // now obtain gcd(x,y) == gcdcont * v/v.content() == (m21*x + m22*y)/denom 00561 NT vcont = v.content(), vup = v.unit_part(); 00562 v /= vup * vcont; v *= gcdcont; 00563 m21 *= ycont; m22 *= xcont; 00564 vf = idiv(xcont, gcdcont) * ycont * (vup * vcont); 00565 CGAL_assertion(vf * v == m21*x + m22*y); 00566 00567 // return results 00568 if (swapped) { 00569 xf = m22; yf = m21; 00570 } else { 00571 xf = m21; yf = m22; 00572 } 00573 return v; 00574 } 00575 00576 00577 00578 00579 00580 } // namespace CGAL 00581 00582 #endif // CGAL_POLYNOMIAL_GCD_H 00583 00584 // EOF