|
GiNaC
1.6.2
|
00001 00035 /* 00036 * GiNaC Copyright (C) 1999-2011 Johannes Gutenberg University Mainz, Germany 00037 * 00038 * This program is free software; you can redistribute it and/or modify 00039 * it under the terms of the GNU General Public License as published by 00040 * the Free Software Foundation; either version 2 of the License, or 00041 * (at your option) any later version. 00042 * 00043 * This program is distributed in the hope that it will be useful, 00044 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00045 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00046 * GNU General Public License for more details. 00047 * 00048 * You should have received a copy of the GNU General Public License 00049 * along with this program; if not, write to the Free Software 00050 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00051 */ 00052 00053 //#define DEBUGFACTOR 00054 00055 #include "factor.h" 00056 00057 #include "ex.h" 00058 #include "numeric.h" 00059 #include "operators.h" 00060 #include "inifcns.h" 00061 #include "symbol.h" 00062 #include "relational.h" 00063 #include "power.h" 00064 #include "mul.h" 00065 #include "normal.h" 00066 #include "add.h" 00067 00068 #include <algorithm> 00069 #include <cmath> 00070 #include <limits> 00071 #include <list> 00072 #include <vector> 00073 #ifdef DEBUGFACTOR 00074 #include <ostream> 00075 #endif 00076 using namespace std; 00077 00078 #include <cln/cln.h> 00079 using namespace cln; 00080 00081 namespace GiNaC { 00082 00083 #ifdef DEBUGFACTOR 00084 #define DCOUT(str) cout << #str << endl 00085 #define DCOUTVAR(var) cout << #var << ": " << var << endl 00086 #define DCOUT2(str,var) cout << #str << ": " << var << endl 00087 ostream& operator<<(ostream& o, const vector<int>& v) 00088 { 00089 vector<int>::const_iterator i = v.begin(), end = v.end(); 00090 while ( i != end ) { 00091 o << *i++ << " "; 00092 } 00093 return o; 00094 } 00095 static ostream& operator<<(ostream& o, const vector<cl_I>& v) 00096 { 00097 vector<cl_I>::const_iterator i = v.begin(), end = v.end(); 00098 while ( i != end ) { 00099 o << *i << "[" << i-v.begin() << "]" << " "; 00100 ++i; 00101 } 00102 return o; 00103 } 00104 static ostream& operator<<(ostream& o, const vector<cl_MI>& v) 00105 { 00106 vector<cl_MI>::const_iterator i = v.begin(), end = v.end(); 00107 while ( i != end ) { 00108 o << *i << "[" << i-v.begin() << "]" << " "; 00109 ++i; 00110 } 00111 return o; 00112 } 00113 ostream& operator<<(ostream& o, const vector<numeric>& v) 00114 { 00115 for ( size_t i=0; i<v.size(); ++i ) { 00116 o << v[i] << " "; 00117 } 00118 return o; 00119 } 00120 ostream& operator<<(ostream& o, const vector< vector<cl_MI> >& v) 00121 { 00122 vector< vector<cl_MI> >::const_iterator i = v.begin(), end = v.end(); 00123 while ( i != end ) { 00124 o << i-v.begin() << ": " << *i << endl; 00125 ++i; 00126 } 00127 return o; 00128 } 00129 #else 00130 #define DCOUT(str) 00131 #define DCOUTVAR(var) 00132 #define DCOUT2(str,var) 00133 #endif // def DEBUGFACTOR 00134 00135 // anonymous namespace to hide all utility functions 00136 namespace { 00137 00139 // modular univariate polynomial code 00140 00141 typedef std::vector<cln::cl_MI> umodpoly; 00142 typedef std::vector<cln::cl_I> upoly; 00143 typedef vector<umodpoly> upvec; 00144 00145 // COPY FROM UPOLY.HPP 00146 00147 // CHANGED size_t -> int !!! 00148 template<typename T> static int degree(const T& p) 00149 { 00150 return p.size() - 1; 00151 } 00152 00153 template<typename T> static typename T::value_type lcoeff(const T& p) 00154 { 00155 return p[p.size() - 1]; 00156 } 00157 00158 static bool normalize_in_field(umodpoly& a) 00159 { 00160 if (a.size() == 0) 00161 return true; 00162 if ( lcoeff(a) == a[0].ring()->one() ) { 00163 return true; 00164 } 00165 00166 const cln::cl_MI lc_1 = recip(lcoeff(a)); 00167 for (std::size_t k = a.size(); k-- != 0; ) 00168 a[k] = a[k]*lc_1; 00169 return false; 00170 } 00171 00172 template<typename T> static void 00173 canonicalize(T& p, const typename T::size_type hint = std::numeric_limits<typename T::size_type>::max()) 00174 { 00175 if (p.empty()) 00176 return; 00177 00178 std::size_t i = p.size() - 1; 00179 // Be fast if the polynomial is already canonicalized 00180 if (!zerop(p[i])) 00181 return; 00182 00183 if (hint < p.size()) 00184 i = hint; 00185 00186 bool is_zero = false; 00187 do { 00188 if (!zerop(p[i])) { 00189 ++i; 00190 break; 00191 } 00192 if (i == 0) { 00193 is_zero = true; 00194 break; 00195 } 00196 --i; 00197 } while (true); 00198 00199 if (is_zero) { 00200 p.clear(); 00201 return; 00202 } 00203 00204 p.erase(p.begin() + i, p.end()); 00205 } 00206 00207 // END COPY FROM UPOLY.HPP 00208 00209 static void expt_pos(umodpoly& a, unsigned int q) 00210 { 00211 if ( a.empty() ) return; 00212 cl_MI zero = a[0].ring()->zero(); 00213 int deg = degree(a); 00214 a.resize(degree(a)*q+1, zero); 00215 for ( int i=deg; i>0; --i ) { 00216 a[i*q] = a[i]; 00217 a[i] = zero; 00218 } 00219 } 00220 00221 template<bool COND, typename T = void> struct enable_if 00222 { 00223 typedef T type; 00224 }; 00225 00226 template<typename T> struct enable_if<false, T> { /* empty */ }; 00227 00228 template<typename T> struct uvar_poly_p 00229 { 00230 static const bool value = false; 00231 }; 00232 00233 template<> struct uvar_poly_p<upoly> 00234 { 00235 static const bool value = true; 00236 }; 00237 00238 template<> struct uvar_poly_p<umodpoly> 00239 { 00240 static const bool value = true; 00241 }; 00242 00243 template<typename T> 00244 // Don't define this for anything but univariate polynomials. 00245 static typename enable_if<uvar_poly_p<T>::value, T>::type 00246 operator+(const T& a, const T& b) 00247 { 00248 int sa = a.size(); 00249 int sb = b.size(); 00250 if ( sa >= sb ) { 00251 T r(sa); 00252 int i = 0; 00253 for ( ; i<sb; ++i ) { 00254 r[i] = a[i] + b[i]; 00255 } 00256 for ( ; i<sa; ++i ) { 00257 r[i] = a[i]; 00258 } 00259 canonicalize(r); 00260 return r; 00261 } 00262 else { 00263 T r(sb); 00264 int i = 0; 00265 for ( ; i<sa; ++i ) { 00266 r[i] = a[i] + b[i]; 00267 } 00268 for ( ; i<sb; ++i ) { 00269 r[i] = b[i]; 00270 } 00271 canonicalize(r); 00272 return r; 00273 } 00274 } 00275 00276 template<typename T> 00277 // Don't define this for anything but univariate polynomials. Otherwise 00278 // overload resolution might fail (this actually happens when compiling 00279 // GiNaC with g++ 3.4). 00280 static typename enable_if<uvar_poly_p<T>::value, T>::type 00281 operator-(const T& a, const T& b) 00282 { 00283 int sa = a.size(); 00284 int sb = b.size(); 00285 if ( sa >= sb ) { 00286 T r(sa); 00287 int i = 0; 00288 for ( ; i<sb; ++i ) { 00289 r[i] = a[i] - b[i]; 00290 } 00291 for ( ; i<sa; ++i ) { 00292 r[i] = a[i]; 00293 } 00294 canonicalize(r); 00295 return r; 00296 } 00297 else { 00298 T r(sb); 00299 int i = 0; 00300 for ( ; i<sa; ++i ) { 00301 r[i] = a[i] - b[i]; 00302 } 00303 for ( ; i<sb; ++i ) { 00304 r[i] = -b[i]; 00305 } 00306 canonicalize(r); 00307 return r; 00308 } 00309 } 00310 00311 static upoly operator*(const upoly& a, const upoly& b) 00312 { 00313 upoly c; 00314 if ( a.empty() || b.empty() ) return c; 00315 00316 int n = degree(a) + degree(b); 00317 c.resize(n+1, 0); 00318 for ( int i=0 ; i<=n; ++i ) { 00319 for ( int j=0 ; j<=i; ++j ) { 00320 if ( j > degree(a) || (i-j) > degree(b) ) continue; 00321 c[i] = c[i] + a[j] * b[i-j]; 00322 } 00323 } 00324 canonicalize(c); 00325 return c; 00326 } 00327 00328 static umodpoly operator*(const umodpoly& a, const umodpoly& b) 00329 { 00330 umodpoly c; 00331 if ( a.empty() || b.empty() ) return c; 00332 00333 int n = degree(a) + degree(b); 00334 c.resize(n+1, a[0].ring()->zero()); 00335 for ( int i=0 ; i<=n; ++i ) { 00336 for ( int j=0 ; j<=i; ++j ) { 00337 if ( j > degree(a) || (i-j) > degree(b) ) continue; 00338 c[i] = c[i] + a[j] * b[i-j]; 00339 } 00340 } 00341 canonicalize(c); 00342 return c; 00343 } 00344 00345 static upoly operator*(const upoly& a, const cl_I& x) 00346 { 00347 if ( zerop(x) ) { 00348 upoly r; 00349 return r; 00350 } 00351 upoly r(a.size()); 00352 for ( size_t i=0; i<a.size(); ++i ) { 00353 r[i] = a[i] * x; 00354 } 00355 return r; 00356 } 00357 00358 static upoly operator/(const upoly& a, const cl_I& x) 00359 { 00360 if ( zerop(x) ) { 00361 upoly r; 00362 return r; 00363 } 00364 upoly r(a.size()); 00365 for ( size_t i=0; i<a.size(); ++i ) { 00366 r[i] = exquo(a[i],x); 00367 } 00368 return r; 00369 } 00370 00371 static umodpoly operator*(const umodpoly& a, const cl_MI& x) 00372 { 00373 umodpoly r(a.size()); 00374 for ( size_t i=0; i<a.size(); ++i ) { 00375 r[i] = a[i] * x; 00376 } 00377 canonicalize(r); 00378 return r; 00379 } 00380 00381 static void upoly_from_ex(upoly& up, const ex& e, const ex& x) 00382 { 00383 // assert: e is in Z[x] 00384 int deg = e.degree(x); 00385 up.resize(deg+1); 00386 int ldeg = e.ldegree(x); 00387 for ( ; deg>=ldeg; --deg ) { 00388 up[deg] = the<cl_I>(ex_to<numeric>(e.coeff(x, deg)).to_cl_N()); 00389 } 00390 for ( ; deg>=0; --deg ) { 00391 up[deg] = 0; 00392 } 00393 canonicalize(up); 00394 } 00395 00396 static void umodpoly_from_upoly(umodpoly& ump, const upoly& e, const cl_modint_ring& R) 00397 { 00398 int deg = degree(e); 00399 ump.resize(deg+1); 00400 for ( ; deg>=0; --deg ) { 00401 ump[deg] = R->canonhom(e[deg]); 00402 } 00403 canonicalize(ump); 00404 } 00405 00406 static void umodpoly_from_ex(umodpoly& ump, const ex& e, const ex& x, const cl_modint_ring& R) 00407 { 00408 // assert: e is in Z[x] 00409 int deg = e.degree(x); 00410 ump.resize(deg+1); 00411 int ldeg = e.ldegree(x); 00412 for ( ; deg>=ldeg; --deg ) { 00413 cl_I coeff = the<cl_I>(ex_to<numeric>(e.coeff(x, deg)).to_cl_N()); 00414 ump[deg] = R->canonhom(coeff); 00415 } 00416 for ( ; deg>=0; --deg ) { 00417 ump[deg] = R->zero(); 00418 } 00419 canonicalize(ump); 00420 } 00421 00422 #ifdef DEBUGFACTOR 00423 static void umodpoly_from_ex(umodpoly& ump, const ex& e, const ex& x, const cl_I& modulus) 00424 { 00425 umodpoly_from_ex(ump, e, x, find_modint_ring(modulus)); 00426 } 00427 #endif 00428 00429 static ex upoly_to_ex(const upoly& a, const ex& x) 00430 { 00431 if ( a.empty() ) return 0; 00432 ex e; 00433 for ( int i=degree(a); i>=0; --i ) { 00434 e += numeric(a[i]) * pow(x, i); 00435 } 00436 return e; 00437 } 00438 00439 static ex umodpoly_to_ex(const umodpoly& a, const ex& x) 00440 { 00441 if ( a.empty() ) return 0; 00442 cl_modint_ring R = a[0].ring(); 00443 cl_I mod = R->modulus; 00444 cl_I halfmod = (mod-1) >> 1; 00445 ex e; 00446 for ( int i=degree(a); i>=0; --i ) { 00447 cl_I n = R->retract(a[i]); 00448 if ( n > halfmod ) { 00449 e += numeric(n-mod) * pow(x, i); 00450 } else { 00451 e += numeric(n) * pow(x, i); 00452 } 00453 } 00454 return e; 00455 } 00456 00457 static upoly umodpoly_to_upoly(const umodpoly& a) 00458 { 00459 upoly e(a.size()); 00460 if ( a.empty() ) return e; 00461 cl_modint_ring R = a[0].ring(); 00462 cl_I mod = R->modulus; 00463 cl_I halfmod = (mod-1) >> 1; 00464 for ( int i=degree(a); i>=0; --i ) { 00465 cl_I n = R->retract(a[i]); 00466 if ( n > halfmod ) { 00467 e[i] = n-mod; 00468 } else { 00469 e[i] = n; 00470 } 00471 } 00472 return e; 00473 } 00474 00475 static umodpoly umodpoly_to_umodpoly(const umodpoly& a, const cl_modint_ring& R, unsigned int m) 00476 { 00477 umodpoly e; 00478 if ( a.empty() ) return e; 00479 cl_modint_ring oldR = a[0].ring(); 00480 size_t sa = a.size(); 00481 e.resize(sa+m, R->zero()); 00482 for ( size_t i=0; i<sa; ++i ) { 00483 e[i+m] = R->canonhom(oldR->retract(a[i])); 00484 } 00485 canonicalize(e); 00486 return e; 00487 } 00488 00496 static void reduce_coeff(umodpoly& a, const cl_I& x) 00497 { 00498 if ( a.empty() ) return; 00499 00500 cl_modint_ring R = a[0].ring(); 00501 umodpoly::iterator i = a.begin(), end = a.end(); 00502 for ( ; i!=end; ++i ) { 00503 // cln cannot perform this division in the modular field 00504 cl_I c = R->retract(*i); 00505 *i = cl_MI(R, the<cl_I>(c / x)); 00506 } 00507 } 00508 00516 static void rem(const umodpoly& a, const umodpoly& b, umodpoly& r) 00517 { 00518 int k, n; 00519 n = degree(b); 00520 k = degree(a) - n; 00521 r = a; 00522 if ( k < 0 ) return; 00523 00524 do { 00525 cl_MI qk = div(r[n+k], b[n]); 00526 if ( !zerop(qk) ) { 00527 for ( int i=0; i<n; ++i ) { 00528 unsigned int j = n + k - 1 - i; 00529 r[j] = r[j] - qk * b[j-k]; 00530 } 00531 } 00532 } while ( k-- ); 00533 00534 fill(r.begin()+n, r.end(), a[0].ring()->zero()); 00535 canonicalize(r); 00536 } 00537 00545 static void div(const umodpoly& a, const umodpoly& b, umodpoly& q) 00546 { 00547 int k, n; 00548 n = degree(b); 00549 k = degree(a) - n; 00550 q.clear(); 00551 if ( k < 0 ) return; 00552 00553 umodpoly r = a; 00554 q.resize(k+1, a[0].ring()->zero()); 00555 do { 00556 cl_MI qk = div(r[n+k], b[n]); 00557 if ( !zerop(qk) ) { 00558 q[k] = qk; 00559 for ( int i=0; i<n; ++i ) { 00560 unsigned int j = n + k - 1 - i; 00561 r[j] = r[j] - qk * b[j-k]; 00562 } 00563 } 00564 } while ( k-- ); 00565 00566 canonicalize(q); 00567 } 00568 00577 static void remdiv(const umodpoly& a, const umodpoly& b, umodpoly& r, umodpoly& q) 00578 { 00579 int k, n; 00580 n = degree(b); 00581 k = degree(a) - n; 00582 q.clear(); 00583 r = a; 00584 if ( k < 0 ) return; 00585 00586 q.resize(k+1, a[0].ring()->zero()); 00587 do { 00588 cl_MI qk = div(r[n+k], b[n]); 00589 if ( !zerop(qk) ) { 00590 q[k] = qk; 00591 for ( int i=0; i<n; ++i ) { 00592 unsigned int j = n + k - 1 - i; 00593 r[j] = r[j] - qk * b[j-k]; 00594 } 00595 } 00596 } while ( k-- ); 00597 00598 fill(r.begin()+n, r.end(), a[0].ring()->zero()); 00599 canonicalize(r); 00600 canonicalize(q); 00601 } 00602 00609 static void gcd(const umodpoly& a, const umodpoly& b, umodpoly& c) 00610 { 00611 if ( degree(a) < degree(b) ) return gcd(b, a, c); 00612 00613 c = a; 00614 normalize_in_field(c); 00615 umodpoly d = b; 00616 normalize_in_field(d); 00617 umodpoly r; 00618 while ( !d.empty() ) { 00619 rem(c, d, r); 00620 c = d; 00621 d = r; 00622 } 00623 normalize_in_field(c); 00624 } 00625 00631 static void deriv(const umodpoly& a, umodpoly& d) 00632 { 00633 d.clear(); 00634 if ( a.size() <= 1 ) return; 00635 00636 d.insert(d.begin(), a.begin()+1, a.end()); 00637 int max = d.size(); 00638 for ( int i=1; i<max; ++i ) { 00639 d[i] = d[i] * (i+1); 00640 } 00641 canonicalize(d); 00642 } 00643 00644 static bool unequal_one(const umodpoly& a) 00645 { 00646 if ( a.empty() ) return true; 00647 return ( a.size() != 1 || a[0] != a[0].ring()->one() ); 00648 } 00649 00650 static bool equal_one(const umodpoly& a) 00651 { 00652 return ( a.size() == 1 && a[0] == a[0].ring()->one() ); 00653 } 00654 00660 static bool squarefree(const umodpoly& a) 00661 { 00662 umodpoly b; 00663 deriv(a, b); 00664 if ( b.empty() ) { 00665 return false; 00666 } 00667 umodpoly c; 00668 gcd(a, b, c); 00669 return equal_one(c); 00670 } 00671 00672 // END modular univariate polynomial code 00674 00676 // modular matrix 00677 00678 typedef vector<cl_MI> mvec; 00679 00680 class modular_matrix 00681 { 00682 friend ostream& operator<<(ostream& o, const modular_matrix& m); 00683 public: 00684 modular_matrix(size_t r_, size_t c_, const cl_MI& init) : r(r_), c(c_) 00685 { 00686 m.resize(c*r, init); 00687 } 00688 size_t rowsize() const { return r; } 00689 size_t colsize() const { return c; } 00690 cl_MI& operator()(size_t row, size_t col) { return m[row*c + col]; } 00691 cl_MI operator()(size_t row, size_t col) const { return m[row*c + col]; } 00692 void mul_col(size_t col, const cl_MI x) 00693 { 00694 for ( size_t rc=0; rc<r; ++rc ) { 00695 std::size_t i = c*rc + col; 00696 m[i] = m[i] * x; 00697 } 00698 } 00699 void sub_col(size_t col1, size_t col2, const cl_MI fac) 00700 { 00701 for ( size_t rc=0; rc<r; ++rc ) { 00702 std::size_t i1 = col1 + c*rc; 00703 std::size_t i2 = col2 + c*rc; 00704 m[i1] = m[i1] - m[i2]*fac; 00705 } 00706 } 00707 void switch_col(size_t col1, size_t col2) 00708 { 00709 for ( size_t rc=0; rc<r; ++rc ) { 00710 std::size_t i1 = col1 + rc*c; 00711 std::size_t i2 = col2 + rc*c; 00712 std::swap(m[i1], m[i2]); 00713 } 00714 } 00715 void mul_row(size_t row, const cl_MI x) 00716 { 00717 for ( size_t cc=0; cc<c; ++cc ) { 00718 std::size_t i = row*c + cc; 00719 m[i] = m[i] * x; 00720 } 00721 } 00722 void sub_row(size_t row1, size_t row2, const cl_MI fac) 00723 { 00724 for ( size_t cc=0; cc<c; ++cc ) { 00725 std::size_t i1 = row1*c + cc; 00726 std::size_t i2 = row2*c + cc; 00727 m[i1] = m[i1] - m[i2]*fac; 00728 } 00729 } 00730 void switch_row(size_t row1, size_t row2) 00731 { 00732 for ( size_t cc=0; cc<c; ++cc ) { 00733 std::size_t i1 = row1*c + cc; 00734 std::size_t i2 = row2*c + cc; 00735 std::swap(m[i1], m[i2]); 00736 } 00737 } 00738 bool is_col_zero(size_t col) const 00739 { 00740 for ( size_t rr=0; rr<r; ++rr ) { 00741 std::size_t i = col + rr*c; 00742 if ( !zerop(m[i]) ) { 00743 return false; 00744 } 00745 } 00746 return true; 00747 } 00748 bool is_row_zero(size_t row) const 00749 { 00750 for ( size_t cc=0; cc<c; ++cc ) { 00751 std::size_t i = row*c + cc; 00752 if ( !zerop(m[i]) ) { 00753 return false; 00754 } 00755 } 00756 return true; 00757 } 00758 void set_row(size_t row, const vector<cl_MI>& newrow) 00759 { 00760 for (std::size_t i2 = 0; i2 < newrow.size(); ++i2) { 00761 std::size_t i1 = row*c + i2; 00762 m[i1] = newrow[i2]; 00763 } 00764 } 00765 mvec::const_iterator row_begin(size_t row) const { return m.begin()+row*c; } 00766 mvec::const_iterator row_end(size_t row) const { return m.begin()+row*c+r; } 00767 private: 00768 size_t r, c; 00769 mvec m; 00770 }; 00771 00772 #ifdef DEBUGFACTOR 00773 modular_matrix operator*(const modular_matrix& m1, const modular_matrix& m2) 00774 { 00775 const unsigned int r = m1.rowsize(); 00776 const unsigned int c = m2.colsize(); 00777 modular_matrix o(r,c,m1(0,0)); 00778 00779 for ( size_t i=0; i<r; ++i ) { 00780 for ( size_t j=0; j<c; ++j ) { 00781 cl_MI buf; 00782 buf = m1(i,0) * m2(0,j); 00783 for ( size_t k=1; k<c; ++k ) { 00784 buf = buf + m1(i,k)*m2(k,j); 00785 } 00786 o(i,j) = buf; 00787 } 00788 } 00789 return o; 00790 } 00791 00792 ostream& operator<<(ostream& o, const modular_matrix& m) 00793 { 00794 cl_modint_ring R = m(0,0).ring(); 00795 o << "{"; 00796 for ( size_t i=0; i<m.rowsize(); ++i ) { 00797 o << "{"; 00798 for ( size_t j=0; j<m.colsize()-1; ++j ) { 00799 o << R->retract(m(i,j)) << ","; 00800 } 00801 o << R->retract(m(i,m.colsize()-1)) << "}"; 00802 if ( i != m.rowsize()-1 ) { 00803 o << ","; 00804 } 00805 } 00806 o << "}"; 00807 return o; 00808 } 00809 #endif // def DEBUGFACTOR 00810 00811 // END modular matrix 00813 00819 static void q_matrix(const umodpoly& a_, modular_matrix& Q) 00820 { 00821 umodpoly a = a_; 00822 normalize_in_field(a); 00823 00824 int n = degree(a); 00825 unsigned int q = cl_I_to_uint(a[0].ring()->modulus); 00826 umodpoly r(n, a[0].ring()->zero()); 00827 r[0] = a[0].ring()->one(); 00828 Q.set_row(0, r); 00829 unsigned int max = (n-1) * q; 00830 for ( size_t m=1; m<=max; ++m ) { 00831 cl_MI rn_1 = r.back(); 00832 for ( size_t i=n-1; i>0; --i ) { 00833 r[i] = r[i-1] - (rn_1 * a[i]); 00834 } 00835 r[0] = -rn_1 * a[0]; 00836 if ( (m % q) == 0 ) { 00837 Q.set_row(m/q, r); 00838 } 00839 } 00840 } 00841 00847 static void nullspace(modular_matrix& M, vector<mvec>& basis) 00848 { 00849 const size_t n = M.rowsize(); 00850 const cl_MI one = M(0,0).ring()->one(); 00851 for ( size_t i=0; i<n; ++i ) { 00852 M(i,i) = M(i,i) - one; 00853 } 00854 for ( size_t r=0; r<n; ++r ) { 00855 size_t cc = 0; 00856 for ( ; cc<n; ++cc ) { 00857 if ( !zerop(M(r,cc)) ) { 00858 if ( cc < r ) { 00859 if ( !zerop(M(cc,cc)) ) { 00860 continue; 00861 } 00862 M.switch_col(cc, r); 00863 } 00864 else if ( cc > r ) { 00865 M.switch_col(cc, r); 00866 } 00867 break; 00868 } 00869 } 00870 if ( cc < n ) { 00871 M.mul_col(r, recip(M(r,r))); 00872 for ( cc=0; cc<n; ++cc ) { 00873 if ( cc != r ) { 00874 M.sub_col(cc, r, M(r,cc)); 00875 } 00876 } 00877 } 00878 } 00879 00880 for ( size_t i=0; i<n; ++i ) { 00881 M(i,i) = M(i,i) - one; 00882 } 00883 for ( size_t i=0; i<n; ++i ) { 00884 if ( !M.is_row_zero(i) ) { 00885 mvec nu(M.row_begin(i), M.row_end(i)); 00886 basis.push_back(nu); 00887 } 00888 } 00889 } 00890 00899 static void berlekamp(const umodpoly& a, upvec& upv) 00900 { 00901 cl_modint_ring R = a[0].ring(); 00902 umodpoly one(1, R->one()); 00903 00904 // find nullspace of Q matrix 00905 modular_matrix Q(degree(a), degree(a), R->zero()); 00906 q_matrix(a, Q); 00907 vector<mvec> nu; 00908 nullspace(Q, nu); 00909 00910 const unsigned int k = nu.size(); 00911 if ( k == 1 ) { 00912 // irreducible 00913 return; 00914 } 00915 00916 list<umodpoly> factors; 00917 factors.push_back(a); 00918 unsigned int size = 1; 00919 unsigned int r = 1; 00920 unsigned int q = cl_I_to_uint(R->modulus); 00921 00922 list<umodpoly>::iterator u = factors.begin(); 00923 00924 // calculate all gcd's 00925 while ( true ) { 00926 for ( unsigned int s=0; s<q; ++s ) { 00927 umodpoly nur = nu[r]; 00928 nur[0] = nur[0] - cl_MI(R, s); 00929 canonicalize(nur); 00930 umodpoly g; 00931 gcd(nur, *u, g); 00932 if ( unequal_one(g) && g != *u ) { 00933 umodpoly uo; 00934 div(*u, g, uo); 00935 if ( equal_one(uo) ) { 00936 throw logic_error("berlekamp: unexpected divisor."); 00937 } 00938 else { 00939 *u = uo; 00940 } 00941 factors.push_back(g); 00942 size = 0; 00943 list<umodpoly>::const_iterator i = factors.begin(), end = factors.end(); 00944 while ( i != end ) { 00945 if ( degree(*i) ) ++size; 00946 ++i; 00947 } 00948 if ( size == k ) { 00949 list<umodpoly>::const_iterator i = factors.begin(), end = factors.end(); 00950 while ( i != end ) { 00951 upv.push_back(*i++); 00952 } 00953 return; 00954 } 00955 } 00956 } 00957 if ( ++r == k ) { 00958 r = 1; 00959 ++u; 00960 } 00961 } 00962 } 00963 00964 // modular square free factorization is not used at the moment so we deactivate 00965 // the code 00966 #if 0 00967 00974 static void expt_1_over_p(const umodpoly& a, unsigned int prime, umodpoly& ap) 00975 { 00976 size_t newdeg = degree(a)/prime; 00977 ap.resize(newdeg+1); 00978 ap[0] = a[0]; 00979 for ( size_t i=1; i<=newdeg; ++i ) { 00980 ap[i] = a[i*prime]; 00981 } 00982 } 00983 00990 static void modsqrfree(const umodpoly& a, upvec& factors, vector<int>& mult) 00991 { 00992 const unsigned int prime = cl_I_to_uint(a[0].ring()->modulus); 00993 int i = 1; 00994 umodpoly b; 00995 deriv(a, b); 00996 if ( b.size() ) { 00997 umodpoly c; 00998 gcd(a, b, c); 00999 umodpoly w; 01000 div(a, c, w); 01001 while ( unequal_one(w) ) { 01002 umodpoly y; 01003 gcd(w, c, y); 01004 umodpoly z; 01005 div(w, y, z); 01006 factors.push_back(z); 01007 mult.push_back(i); 01008 ++i; 01009 w = y; 01010 umodpoly buf; 01011 div(c, y, buf); 01012 c = buf; 01013 } 01014 if ( unequal_one(c) ) { 01015 umodpoly cp; 01016 expt_1_over_p(c, prime, cp); 01017 size_t previ = mult.size(); 01018 modsqrfree(cp, factors, mult); 01019 for ( size_t i=previ; i<mult.size(); ++i ) { 01020 mult[i] *= prime; 01021 } 01022 } 01023 } 01024 else { 01025 umodpoly ap; 01026 expt_1_over_p(a, prime, ap); 01027 size_t previ = mult.size(); 01028 modsqrfree(ap, factors, mult); 01029 for ( size_t i=previ; i<mult.size(); ++i ) { 01030 mult[i] *= prime; 01031 } 01032 } 01033 } 01034 01035 #endif // deactivation of square free factorization 01036 01047 static void distinct_degree_factor(const umodpoly& a_, vector<int>& degrees, upvec& ddfactors) 01048 { 01049 umodpoly a = a_; 01050 01051 cl_modint_ring R = a[0].ring(); 01052 int q = cl_I_to_int(R->modulus); 01053 int nhalf = degree(a)/2; 01054 01055 int i = 1; 01056 umodpoly w(2); 01057 w[0] = R->zero(); 01058 w[1] = R->one(); 01059 umodpoly x = w; 01060 01061 while ( i <= nhalf ) { 01062 expt_pos(w, q); 01063 umodpoly buf; 01064 rem(w, a, buf); 01065 w = buf; 01066 umodpoly wx = w - x; 01067 gcd(a, wx, buf); 01068 if ( unequal_one(buf) ) { 01069 degrees.push_back(i); 01070 ddfactors.push_back(buf); 01071 } 01072 if ( unequal_one(buf) ) { 01073 umodpoly buf2; 01074 div(a, buf, buf2); 01075 a = buf2; 01076 nhalf = degree(a)/2; 01077 rem(w, a, buf); 01078 w = buf; 01079 } 01080 ++i; 01081 } 01082 if ( unequal_one(a) ) { 01083 degrees.push_back(degree(a)); 01084 ddfactors.push_back(a); 01085 } 01086 } 01087 01098 static void same_degree_factor(const umodpoly& a, upvec& upv) 01099 { 01100 cl_modint_ring R = a[0].ring(); 01101 01102 vector<int> degrees; 01103 upvec ddfactors; 01104 distinct_degree_factor(a, degrees, ddfactors); 01105 01106 for ( size_t i=0; i<degrees.size(); ++i ) { 01107 if ( degrees[i] == degree(ddfactors[i]) ) { 01108 upv.push_back(ddfactors[i]); 01109 } 01110 else { 01111 berlekamp(ddfactors[i], upv); 01112 } 01113 } 01114 } 01115 01116 // Yes, we can (choose). 01117 #define USE_SAME_DEGREE_FACTOR 01118 01129 static void factor_modular(const umodpoly& p, upvec& upv) 01130 { 01131 #ifdef USE_SAME_DEGREE_FACTOR 01132 same_degree_factor(p, upv); 01133 #else 01134 berlekamp(p, upv); 01135 #endif 01136 } 01137 01146 static void exteuclid(const umodpoly& a, const umodpoly& b, umodpoly& s, umodpoly& t) 01147 { 01148 if ( degree(a) < degree(b) ) { 01149 exteuclid(b, a, t, s); 01150 return; 01151 } 01152 01153 umodpoly one(1, a[0].ring()->one()); 01154 umodpoly c = a; normalize_in_field(c); 01155 umodpoly d = b; normalize_in_field(d); 01156 s = one; 01157 t.clear(); 01158 umodpoly d1; 01159 umodpoly d2 = one; 01160 umodpoly q; 01161 while ( true ) { 01162 div(c, d, q); 01163 umodpoly r = c - q * d; 01164 umodpoly r1 = s - q * d1; 01165 umodpoly r2 = t - q * d2; 01166 c = d; 01167 s = d1; 01168 t = d2; 01169 if ( r.empty() ) break; 01170 d = r; 01171 d1 = r1; 01172 d2 = r2; 01173 } 01174 cl_MI fac = recip(lcoeff(a) * lcoeff(c)); 01175 umodpoly::iterator i = s.begin(), end = s.end(); 01176 for ( ; i!=end; ++i ) { 01177 *i = *i * fac; 01178 } 01179 canonicalize(s); 01180 fac = recip(lcoeff(b) * lcoeff(c)); 01181 i = t.begin(), end = t.end(); 01182 for ( ; i!=end; ++i ) { 01183 *i = *i * fac; 01184 } 01185 canonicalize(t); 01186 } 01187 01194 static upoly replace_lc(const upoly& poly, const cl_I& lc) 01195 { 01196 if ( poly.empty() ) return poly; 01197 upoly r = poly; 01198 r.back() = lc; 01199 return r; 01200 } 01201 01205 static inline cl_I calc_bound(const ex& a, const ex& x, int maxdeg) 01206 { 01207 cl_I maxcoeff = 0; 01208 cl_R coeff = 0; 01209 for ( int i=a.degree(x); i>=a.ldegree(x); --i ) { 01210 cl_I aa = abs(the<cl_I>(ex_to<numeric>(a.coeff(x, i)).to_cl_N())); 01211 if ( aa > maxcoeff ) maxcoeff = aa; 01212 coeff = coeff + square(aa); 01213 } 01214 cl_I coeffnorm = ceiling1(the<cl_R>(cln::sqrt(coeff))); 01215 cl_I B = coeffnorm * expt_pos(cl_I(2), cl_I(maxdeg)); 01216 return ( B > maxcoeff ) ? B : maxcoeff; 01217 } 01218 01222 static inline cl_I calc_bound(const upoly& a, int maxdeg) 01223 { 01224 cl_I maxcoeff = 0; 01225 cl_R coeff = 0; 01226 for ( int i=degree(a); i>=0; --i ) { 01227 cl_I aa = abs(a[i]); 01228 if ( aa > maxcoeff ) maxcoeff = aa; 01229 coeff = coeff + square(aa); 01230 } 01231 cl_I coeffnorm = ceiling1(the<cl_R>(cln::sqrt(coeff))); 01232 cl_I B = coeffnorm * expt_pos(cl_I(2), cl_I(maxdeg)); 01233 return ( B > maxcoeff ) ? B : maxcoeff; 01234 } 01235 01248 static void hensel_univar(const upoly& a_, unsigned int p, const umodpoly& u1_, const umodpoly& w1_, upoly& u, upoly& w) 01249 { 01250 upoly a = a_; 01251 const cl_modint_ring& R = u1_[0].ring(); 01252 01253 // calc bound B 01254 int maxdeg = (degree(u1_) > degree(w1_)) ? degree(u1_) : degree(w1_); 01255 cl_I maxmodulus = 2*calc_bound(a, maxdeg); 01256 01257 // step 1 01258 cl_I alpha = lcoeff(a); 01259 a = a * alpha; 01260 umodpoly nu1 = u1_; 01261 normalize_in_field(nu1); 01262 umodpoly nw1 = w1_; 01263 normalize_in_field(nw1); 01264 upoly phi; 01265 phi = umodpoly_to_upoly(nu1) * alpha; 01266 umodpoly u1; 01267 umodpoly_from_upoly(u1, phi, R); 01268 phi = umodpoly_to_upoly(nw1) * alpha; 01269 umodpoly w1; 01270 umodpoly_from_upoly(w1, phi, R); 01271 01272 // step 2 01273 umodpoly s; 01274 umodpoly t; 01275 exteuclid(u1, w1, s, t); 01276 01277 // step 3 01278 u = replace_lc(umodpoly_to_upoly(u1), alpha); 01279 w = replace_lc(umodpoly_to_upoly(w1), alpha); 01280 upoly e = a - u * w; 01281 cl_I modulus = p; 01282 01283 // step 4 01284 while ( !e.empty() && modulus < maxmodulus ) { 01285 upoly c = e / modulus; 01286 phi = umodpoly_to_upoly(s) * c; 01287 umodpoly sigmatilde; 01288 umodpoly_from_upoly(sigmatilde, phi, R); 01289 phi = umodpoly_to_upoly(t) * c; 01290 umodpoly tautilde; 01291 umodpoly_from_upoly(tautilde, phi, R); 01292 umodpoly r, q; 01293 remdiv(sigmatilde, w1, r, q); 01294 umodpoly sigma = r; 01295 phi = umodpoly_to_upoly(tautilde) + umodpoly_to_upoly(q) * umodpoly_to_upoly(u1); 01296 umodpoly tau; 01297 umodpoly_from_upoly(tau, phi, R); 01298 u = u + umodpoly_to_upoly(tau) * modulus; 01299 w = w + umodpoly_to_upoly(sigma) * modulus; 01300 e = a - u * w; 01301 modulus = modulus * p; 01302 } 01303 01304 // step 5 01305 if ( e.empty() ) { 01306 cl_I g = u[0]; 01307 for ( size_t i=1; i<u.size(); ++i ) { 01308 g = gcd(g, u[i]); 01309 if ( g == 1 ) break; 01310 } 01311 if ( g != 1 ) { 01312 u = u / g; 01313 w = w * g; 01314 } 01315 if ( alpha != 1 ) { 01316 w = w / alpha; 01317 } 01318 } 01319 else { 01320 u.clear(); 01321 } 01322 } 01323 01329 static unsigned int next_prime(unsigned int p) 01330 { 01331 static vector<unsigned int> primes; 01332 if ( primes.size() == 0 ) { 01333 primes.push_back(3); primes.push_back(5); primes.push_back(7); 01334 } 01335 vector<unsigned int>::const_iterator it = primes.begin(); 01336 if ( p >= primes.back() ) { 01337 unsigned int candidate = primes.back() + 2; 01338 while ( true ) { 01339 size_t n = primes.size()/2; 01340 for ( size_t i=0; i<n; ++i ) { 01341 if ( candidate % primes[i] ) continue; 01342 candidate += 2; 01343 i=-1; 01344 } 01345 primes.push_back(candidate); 01346 if ( candidate > p ) break; 01347 } 01348 return candidate; 01349 } 01350 vector<unsigned int>::const_iterator end = primes.end(); 01351 for ( ; it!=end; ++it ) { 01352 if ( *it > p ) { 01353 return *it; 01354 } 01355 } 01356 throw logic_error("next_prime: should not reach this point!"); 01357 } 01358 01361 class factor_partition 01362 { 01363 public: 01365 factor_partition(const upvec& factors_) : factors(factors_) 01366 { 01367 n = factors.size(); 01368 k.resize(n, 0); 01369 k[0] = 1; 01370 cache.resize(n-1); 01371 one.resize(1, factors.front()[0].ring()->one()); 01372 len = 1; 01373 last = 0; 01374 split(); 01375 } 01376 int operator[](size_t i) const { return k[i]; } 01377 size_t size() const { return n; } 01378 size_t size_left() const { return n-len; } 01379 size_t size_right() const { return len; } 01382 bool next() 01383 { 01384 if ( last == n-1 ) { 01385 int rem = len - 1; 01386 int p = last - 1; 01387 while ( rem ) { 01388 if ( k[p] ) { 01389 --rem; 01390 --p; 01391 continue; 01392 } 01393 last = p - 1; 01394 while ( k[last] == 0 ) { --last; } 01395 if ( last == 0 && n == 2*len ) return false; 01396 k[last++] = 0; 01397 for ( size_t i=0; i<=len-rem; ++i ) { 01398 k[last] = 1; 01399 ++last; 01400 } 01401 fill(k.begin()+last, k.end(), 0); 01402 --last; 01403 split(); 01404 return true; 01405 } 01406 last = len; 01407 ++len; 01408 if ( len > n/2 ) return false; 01409 fill(k.begin(), k.begin()+len, 1); 01410 fill(k.begin()+len+1, k.end(), 0); 01411 } 01412 else { 01413 k[last++] = 0; 01414 k[last] = 1; 01415 } 01416 split(); 01417 return true; 01418 } 01420 umodpoly& left() { return lr[0]; } 01422 umodpoly& right() { return lr[1]; } 01423 private: 01424 void split_cached() 01425 { 01426 size_t i = 0; 01427 do { 01428 size_t pos = i; 01429 int group = k[i++]; 01430 size_t d = 0; 01431 while ( i < n && k[i] == group ) { ++d; ++i; } 01432 if ( d ) { 01433 if ( cache[pos].size() >= d ) { 01434 lr[group] = lr[group] * cache[pos][d-1]; 01435 } 01436 else { 01437 if ( cache[pos].size() == 0 ) { 01438 cache[pos].push_back(factors[pos] * factors[pos+1]); 01439 } 01440 size_t j = pos + cache[pos].size() + 1; 01441 d -= cache[pos].size(); 01442 while ( d ) { 01443 umodpoly buf = cache[pos].back() * factors[j]; 01444 cache[pos].push_back(buf); 01445 --d; 01446 ++j; 01447 } 01448 lr[group] = lr[group] * cache[pos].back(); 01449 } 01450 } 01451 else { 01452 lr[group] = lr[group] * factors[pos]; 01453 } 01454 } while ( i < n ); 01455 } 01456 void split() 01457 { 01458 lr[0] = one; 01459 lr[1] = one; 01460 if ( n > 6 ) { 01461 split_cached(); 01462 } 01463 else { 01464 for ( size_t i=0; i<n; ++i ) { 01465 lr[k[i]] = lr[k[i]] * factors[i]; 01466 } 01467 } 01468 } 01469 private: 01470 umodpoly lr[2]; 01471 vector< vector<umodpoly> > cache; 01472 upvec factors; 01473 umodpoly one; 01474 size_t n; 01475 size_t len; 01476 size_t last; 01477 vector<int> k; 01478 }; 01479 01483 struct ModFactors 01484 { 01485 upoly poly; 01486 upvec factors; 01487 }; 01488 01499 static ex factor_univariate(const ex& poly, const ex& x, unsigned int& prime) 01500 { 01501 ex unit, cont, prim_ex; 01502 poly.unitcontprim(x, unit, cont, prim_ex); 01503 upoly prim; 01504 upoly_from_ex(prim, prim_ex, x); 01505 01506 // determine proper prime and minimize number of modular factors 01507 prime = 3; 01508 unsigned int lastp = prime; 01509 cl_modint_ring R; 01510 unsigned int trials = 0; 01511 unsigned int minfactors = 0; 01512 cl_I lc = lcoeff(prim) * the<cl_I>(ex_to<numeric>(cont).to_cl_N()); 01513 upvec factors; 01514 while ( trials < 2 ) { 01515 umodpoly modpoly; 01516 while ( true ) { 01517 prime = next_prime(prime); 01518 if ( !zerop(rem(lc, prime)) ) { 01519 R = find_modint_ring(prime); 01520 umodpoly_from_upoly(modpoly, prim, R); 01521 if ( squarefree(modpoly) ) break; 01522 } 01523 } 01524 01525 // do modular factorization 01526 upvec trialfactors; 01527 factor_modular(modpoly, trialfactors); 01528 if ( trialfactors.size() <= 1 ) { 01529 // irreducible for sure 01530 return poly; 01531 } 01532 01533 if ( minfactors == 0 || trialfactors.size() < minfactors ) { 01534 factors = trialfactors; 01535 minfactors = trialfactors.size(); 01536 lastp = prime; 01537 trials = 1; 01538 } 01539 else { 01540 ++trials; 01541 } 01542 } 01543 prime = lastp; 01544 R = find_modint_ring(prime); 01545 01546 // lift all factor combinations 01547 stack<ModFactors> tocheck; 01548 ModFactors mf; 01549 mf.poly = prim; 01550 mf.factors = factors; 01551 tocheck.push(mf); 01552 upoly f1, f2; 01553 ex result = 1; 01554 while ( tocheck.size() ) { 01555 const size_t n = tocheck.top().factors.size(); 01556 factor_partition part(tocheck.top().factors); 01557 while ( true ) { 01558 // call Hensel lifting 01559 hensel_univar(tocheck.top().poly, prime, part.left(), part.right(), f1, f2); 01560 if ( !f1.empty() ) { 01561 // successful, update the stack and the result 01562 if ( part.size_left() == 1 ) { 01563 if ( part.size_right() == 1 ) { 01564 result *= upoly_to_ex(f1, x) * upoly_to_ex(f2, x); 01565 tocheck.pop(); 01566 break; 01567 } 01568 result *= upoly_to_ex(f1, x); 01569 tocheck.top().poly = f2; 01570 for ( size_t i=0; i<n; ++i ) { 01571 if ( part[i] == 0 ) { 01572 tocheck.top().factors.erase(tocheck.top().factors.begin()+i); 01573 break; 01574 } 01575 } 01576 break; 01577 } 01578 else if ( part.size_right() == 1 ) { 01579 if ( part.size_left() == 1 ) { 01580 result *= upoly_to_ex(f1, x) * upoly_to_ex(f2, x); 01581 tocheck.pop(); 01582 break; 01583 } 01584 result *= upoly_to_ex(f2, x); 01585 tocheck.top().poly = f1; 01586 for ( size_t i=0; i<n; ++i ) { 01587 if ( part[i] == 1 ) { 01588 tocheck.top().factors.erase(tocheck.top().factors.begin()+i); 01589 break; 01590 } 01591 } 01592 break; 01593 } 01594 else { 01595 upvec newfactors1(part.size_left()), newfactors2(part.size_right()); 01596 upvec::iterator i1 = newfactors1.begin(), i2 = newfactors2.begin(); 01597 for ( size_t i=0; i<n; ++i ) { 01598 if ( part[i] ) { 01599 *i2++ = tocheck.top().factors[i]; 01600 } 01601 else { 01602 *i1++ = tocheck.top().factors[i]; 01603 } 01604 } 01605 tocheck.top().factors = newfactors1; 01606 tocheck.top().poly = f1; 01607 ModFactors mf; 01608 mf.factors = newfactors2; 01609 mf.poly = f2; 01610 tocheck.push(mf); 01611 break; 01612 } 01613 } 01614 else { 01615 // not successful 01616 if ( !part.next() ) { 01617 // if no more combinations left, return polynomial as 01618 // irreducible 01619 result *= upoly_to_ex(tocheck.top().poly, x); 01620 tocheck.pop(); 01621 break; 01622 } 01623 } 01624 } 01625 } 01626 01627 return unit * cont * result; 01628 } 01629 01633 static inline ex factor_univariate(const ex& poly, const ex& x) 01634 { 01635 unsigned int prime; 01636 return factor_univariate(poly, x, prime); 01637 } 01638 01641 struct EvalPoint 01642 { 01643 ex x; 01644 int evalpoint; 01645 }; 01646 01647 #ifdef DEBUGFACTOR 01648 ostream& operator<<(ostream& o, const vector<EvalPoint>& v) 01649 { 01650 for ( size_t i=0; i<v.size(); ++i ) { 01651 o << "(" << v[i].x << "==" << v[i].evalpoint << ") "; 01652 } 01653 return o; 01654 } 01655 #endif // def DEBUGFACTOR 01656 01657 // forward declaration 01658 static vector<ex> multivar_diophant(const vector<ex>& a_, const ex& x, const ex& c, const vector<EvalPoint>& I, unsigned int d, unsigned int p, unsigned int k); 01659 01675 static upvec multiterm_eea_lift(const upvec& a, const ex& x, unsigned int p, unsigned int k) 01676 { 01677 const size_t r = a.size(); 01678 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k)); 01679 upvec q(r-1); 01680 q[r-2] = a[r-1]; 01681 for ( size_t j=r-2; j>=1; --j ) { 01682 q[j-1] = a[j] * q[j]; 01683 } 01684 umodpoly beta(1, R->one()); 01685 upvec s; 01686 for ( size_t j=1; j<r; ++j ) { 01687 vector<ex> mdarg(2); 01688 mdarg[0] = umodpoly_to_ex(q[j-1], x); 01689 mdarg[1] = umodpoly_to_ex(a[j-1], x); 01690 vector<EvalPoint> empty; 01691 vector<ex> exsigma = multivar_diophant(mdarg, x, umodpoly_to_ex(beta, x), empty, 0, p, k); 01692 umodpoly sigma1; 01693 umodpoly_from_ex(sigma1, exsigma[0], x, R); 01694 umodpoly sigma2; 01695 umodpoly_from_ex(sigma2, exsigma[1], x, R); 01696 beta = sigma1; 01697 s.push_back(sigma2); 01698 } 01699 s.push_back(beta); 01700 return s; 01701 } 01702 01708 static void change_modulus(const cl_modint_ring& R, umodpoly& a) 01709 { 01710 if ( a.empty() ) return; 01711 cl_modint_ring oldR = a[0].ring(); 01712 umodpoly::iterator i = a.begin(), end = a.end(); 01713 for ( ; i!=end; ++i ) { 01714 *i = R->canonhom(oldR->retract(*i)); 01715 } 01716 canonicalize(a); 01717 } 01718 01733 static void eea_lift(const umodpoly& a, const umodpoly& b, const ex& x, unsigned int p, unsigned int k, umodpoly& s_, umodpoly& t_) 01734 { 01735 cl_modint_ring R = find_modint_ring(p); 01736 umodpoly amod = a; 01737 change_modulus(R, amod); 01738 umodpoly bmod = b; 01739 change_modulus(R, bmod); 01740 01741 umodpoly smod; 01742 umodpoly tmod; 01743 exteuclid(amod, bmod, smod, tmod); 01744 01745 cl_modint_ring Rpk = find_modint_ring(expt_pos(cl_I(p),k)); 01746 umodpoly s = smod; 01747 change_modulus(Rpk, s); 01748 umodpoly t = tmod; 01749 change_modulus(Rpk, t); 01750 01751 cl_I modulus(p); 01752 umodpoly one(1, Rpk->one()); 01753 for ( size_t j=1; j<k; ++j ) { 01754 umodpoly e = one - a * s - b * t; 01755 reduce_coeff(e, modulus); 01756 umodpoly c = e; 01757 change_modulus(R, c); 01758 umodpoly sigmabar = smod * c; 01759 umodpoly taubar = tmod * c; 01760 umodpoly sigma, q; 01761 remdiv(sigmabar, bmod, sigma, q); 01762 umodpoly tau = taubar + q * amod; 01763 umodpoly sadd = sigma; 01764 change_modulus(Rpk, sadd); 01765 cl_MI modmodulus(Rpk, modulus); 01766 s = s + sadd * modmodulus; 01767 umodpoly tadd = tau; 01768 change_modulus(Rpk, tadd); 01769 t = t + tadd * modmodulus; 01770 modulus = modulus * p; 01771 } 01772 01773 s_ = s; t_ = t; 01774 } 01775 01791 static upvec univar_diophant(const upvec& a, const ex& x, unsigned int m, unsigned int p, unsigned int k) 01792 { 01793 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k)); 01794 01795 const size_t r = a.size(); 01796 upvec result; 01797 if ( r > 2 ) { 01798 upvec s = multiterm_eea_lift(a, x, p, k); 01799 for ( size_t j=0; j<r; ++j ) { 01800 umodpoly bmod = umodpoly_to_umodpoly(s[j], R, m); 01801 umodpoly buf; 01802 rem(bmod, a[j], buf); 01803 result.push_back(buf); 01804 } 01805 } 01806 else { 01807 umodpoly s, t; 01808 eea_lift(a[1], a[0], x, p, k, s, t); 01809 umodpoly bmod = umodpoly_to_umodpoly(s, R, m); 01810 umodpoly buf, q; 01811 remdiv(bmod, a[0], buf, q); 01812 result.push_back(buf); 01813 umodpoly t1mod = umodpoly_to_umodpoly(t, R, m); 01814 buf = t1mod + q * a[1]; 01815 result.push_back(buf); 01816 } 01817 01818 return result; 01819 } 01820 01825 struct make_modular_map : public map_function { 01826 cl_modint_ring R; 01827 make_modular_map(const cl_modint_ring& R_) : R(R_) { } 01828 ex operator()(const ex& e) 01829 { 01830 if ( is_a<add>(e) || is_a<mul>(e) ) { 01831 return e.map(*this); 01832 } 01833 else if ( is_a<numeric>(e) ) { 01834 numeric mod(R->modulus); 01835 numeric halfmod = (mod-1)/2; 01836 cl_MI emod = R->canonhom(the<cl_I>(ex_to<numeric>(e).to_cl_N())); 01837 numeric n(R->retract(emod)); 01838 if ( n > halfmod ) { 01839 return n-mod; 01840 } 01841 else { 01842 return n; 01843 } 01844 } 01845 return e; 01846 } 01847 }; 01848 01856 static ex make_modular(const ex& e, const cl_modint_ring& R) 01857 { 01858 make_modular_map map(R); 01859 return map(e.expand()); 01860 } 01861 01879 static vector<ex> multivar_diophant(const vector<ex>& a_, const ex& x, const ex& c, const vector<EvalPoint>& I, 01880 unsigned int d, unsigned int p, unsigned int k) 01881 { 01882 vector<ex> a = a_; 01883 01884 const cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k)); 01885 const size_t r = a.size(); 01886 const size_t nu = I.size() + 1; 01887 01888 vector<ex> sigma; 01889 if ( nu > 1 ) { 01890 ex xnu = I.back().x; 01891 int alphanu = I.back().evalpoint; 01892 01893 ex A = 1; 01894 for ( size_t i=0; i<r; ++i ) { 01895 A *= a[i]; 01896 } 01897 vector<ex> b(r); 01898 for ( size_t i=0; i<r; ++i ) { 01899 b[i] = normal(A / a[i]); 01900 } 01901 01902 vector<ex> anew = a; 01903 for ( size_t i=0; i<r; ++i ) { 01904 anew[i] = anew[i].subs(xnu == alphanu); 01905 } 01906 ex cnew = c.subs(xnu == alphanu); 01907 vector<EvalPoint> Inew = I; 01908 Inew.pop_back(); 01909 sigma = multivar_diophant(anew, x, cnew, Inew, d, p, k); 01910 01911 ex buf = c; 01912 for ( size_t i=0; i<r; ++i ) { 01913 buf -= sigma[i] * b[i]; 01914 } 01915 ex e = make_modular(buf, R); 01916 01917 ex monomial = 1; 01918 for ( size_t m=1; !e.is_zero() && e.has(xnu) && m<=d; ++m ) { 01919 monomial *= (xnu - alphanu); 01920 monomial = expand(monomial); 01921 ex cm = e.diff(ex_to<symbol>(xnu), m).subs(xnu==alphanu) / factorial(m); 01922 cm = make_modular(cm, R); 01923 if ( !cm.is_zero() ) { 01924 vector<ex> delta_s = multivar_diophant(anew, x, cm, Inew, d, p, k); 01925 ex buf = e; 01926 for ( size_t j=0; j<delta_s.size(); ++j ) { 01927 delta_s[j] *= monomial; 01928 sigma[j] += delta_s[j]; 01929 buf -= delta_s[j] * b[j]; 01930 } 01931 e = make_modular(buf, R); 01932 } 01933 } 01934 } 01935 else { 01936 upvec amod; 01937 for ( size_t i=0; i<a.size(); ++i ) { 01938 umodpoly up; 01939 umodpoly_from_ex(up, a[i], x, R); 01940 amod.push_back(up); 01941 } 01942 01943 sigma.insert(sigma.begin(), r, 0); 01944 size_t nterms; 01945 ex z; 01946 if ( is_a<add>(c) ) { 01947 nterms = c.nops(); 01948 z = c.op(0); 01949 } 01950 else { 01951 nterms = 1; 01952 z = c; 01953 } 01954 for ( size_t i=0; i<nterms; ++i ) { 01955 int m = z.degree(x); 01956 cl_I cm = the<cl_I>(ex_to<numeric>(z.lcoeff(x)).to_cl_N()); 01957 upvec delta_s = univar_diophant(amod, x, m, p, k); 01958 cl_MI modcm; 01959 cl_I poscm = cm; 01960 while ( poscm < 0 ) { 01961 poscm = poscm + expt_pos(cl_I(p),k); 01962 } 01963 modcm = cl_MI(R, poscm); 01964 for ( size_t j=0; j<delta_s.size(); ++j ) { 01965 delta_s[j] = delta_s[j] * modcm; 01966 sigma[j] = sigma[j] + umodpoly_to_ex(delta_s[j], x); 01967 } 01968 if ( nterms > 1 ) { 01969 z = c.op(i+1); 01970 } 01971 } 01972 } 01973 01974 for ( size_t i=0; i<sigma.size(); ++i ) { 01975 sigma[i] = make_modular(sigma[i], R); 01976 } 01977 01978 return sigma; 01979 } 01980 01997 static ex hensel_multivar(const ex& a, const ex& x, const vector<EvalPoint>& I, 01998 unsigned int p, const cl_I& l, const upvec& u, const vector<ex>& lcU) 01999 { 02000 const size_t nu = I.size() + 1; 02001 const cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),l)); 02002 02003 vector<ex> A(nu); 02004 A[nu-1] = a; 02005 02006 for ( size_t j=nu; j>=2; --j ) { 02007 ex x = I[j-2].x; 02008 int alpha = I[j-2].evalpoint; 02009 A[j-2] = A[j-1].subs(x==alpha); 02010 A[j-2] = make_modular(A[j-2], R); 02011 } 02012 02013 int maxdeg = a.degree(I.front().x); 02014 for ( size_t i=1; i<I.size(); ++i ) { 02015 int maxdeg2 = a.degree(I[i].x); 02016 if ( maxdeg2 > maxdeg ) maxdeg = maxdeg2; 02017 } 02018 02019 const size_t n = u.size(); 02020 vector<ex> U(n); 02021 for ( size_t i=0; i<n; ++i ) { 02022 U[i] = umodpoly_to_ex(u[i], x); 02023 } 02024 02025 for ( size_t j=2; j<=nu; ++j ) { 02026 vector<ex> U1 = U; 02027 ex monomial = 1; 02028 for ( size_t m=0; m<n; ++m) { 02029 if ( lcU[m] != 1 ) { 02030 ex coef = lcU[m]; 02031 for ( size_t i=j-1; i<nu-1; ++i ) { 02032 coef = coef.subs(I[i].x == I[i].evalpoint); 02033 } 02034 coef = make_modular(coef, R); 02035 int deg = U[m].degree(x); 02036 U[m] = U[m] - U[m].lcoeff(x) * pow(x,deg) + coef * pow(x,deg); 02037 } 02038 } 02039 ex Uprod = 1; 02040 for ( size_t i=0; i<n; ++i ) { 02041 Uprod *= U[i]; 02042 } 02043 ex e = expand(A[j-1] - Uprod); 02044 02045 vector<EvalPoint> newI; 02046 for ( size_t i=1; i<=j-2; ++i ) { 02047 newI.push_back(I[i-1]); 02048 } 02049 02050 ex xj = I[j-2].x; 02051 int alphaj = I[j-2].evalpoint; 02052 size_t deg = A[j-1].degree(xj); 02053 for ( size_t k=1; k<=deg; ++k ) { 02054 if ( !e.is_zero() ) { 02055 monomial *= (xj - alphaj); 02056 monomial = expand(monomial); 02057 ex dif = e.diff(ex_to<symbol>(xj), k); 02058 ex c = dif.subs(xj==alphaj) / factorial(k); 02059 if ( !c.is_zero() ) { 02060 vector<ex> deltaU = multivar_diophant(U1, x, c, newI, maxdeg, p, cl_I_to_uint(l)); 02061 for ( size_t i=0; i<n; ++i ) { 02062 deltaU[i] *= monomial; 02063 U[i] += deltaU[i]; 02064 U[i] = make_modular(U[i], R); 02065 } 02066 ex Uprod = 1; 02067 for ( size_t i=0; i<n; ++i ) { 02068 Uprod *= U[i]; 02069 } 02070 e = A[j-1] - Uprod; 02071 e = make_modular(e, R); 02072 } 02073 } 02074 } 02075 } 02076 02077 ex acand = 1; 02078 for ( size_t i=0; i<U.size(); ++i ) { 02079 acand *= U[i]; 02080 } 02081 if ( expand(a-acand).is_zero() ) { 02082 lst res; 02083 for ( size_t i=0; i<U.size(); ++i ) { 02084 res.append(U[i]); 02085 } 02086 return res; 02087 } 02088 else { 02089 lst res; 02090 return lst(); 02091 } 02092 } 02093 02098 static ex put_factors_into_lst(const ex& e) 02099 { 02100 lst result; 02101 if ( is_a<numeric>(e) ) { 02102 result.append(e); 02103 return result; 02104 } 02105 if ( is_a<power>(e) ) { 02106 result.append(1); 02107 result.append(e.op(0)); 02108 return result; 02109 } 02110 if ( is_a<symbol>(e) || is_a<add>(e) ) { 02111 result.append(1); 02112 result.append(e); 02113 return result; 02114 } 02115 if ( is_a<mul>(e) ) { 02116 ex nfac = 1; 02117 for ( size_t i=0; i<e.nops(); ++i ) { 02118 ex op = e.op(i); 02119 if ( is_a<numeric>(op) ) { 02120 nfac = op; 02121 } 02122 if ( is_a<power>(op) ) { 02123 result.append(op.op(0)); 02124 } 02125 if ( is_a<symbol>(op) || is_a<add>(op) ) { 02126 result.append(op); 02127 } 02128 } 02129 result.prepend(nfac); 02130 return result; 02131 } 02132 throw runtime_error("put_factors_into_lst: bad term."); 02133 } 02134 02141 static bool checkdivisors(const lst& f) 02142 { 02143 const int k = f.nops(); 02144 numeric q, r; 02145 vector<numeric> d(k); 02146 d[0] = ex_to<numeric>(abs(f.op(0))); 02147 for ( int i=1; i<k; ++i ) { 02148 q = ex_to<numeric>(abs(f.op(i))); 02149 for ( int j=i-1; j>=0; --j ) { 02150 r = d[j]; 02151 do { 02152 r = gcd(r, q); 02153 q = q/r; 02154 } while ( r != 1 ); 02155 if ( q == 1 ) { 02156 return true; 02157 } 02158 } 02159 d[i] = q; 02160 } 02161 return false; 02162 } 02163 02180 static void generate_set(const ex& u, const ex& vn, const exset& syms, const lst& f, 02181 numeric& modulus, ex& u0, vector<numeric>& a) 02182 { 02183 const ex& x = *syms.begin(); 02184 while ( true ) { 02185 ++modulus; 02186 // generate a set of integers ... 02187 u0 = u; 02188 ex vna = vn; 02189 ex vnatry; 02190 exset::const_iterator s = syms.begin(); 02191 ++s; 02192 for ( size_t i=0; i<a.size(); ++i ) { 02193 do { 02194 a[i] = mod(numeric(rand()), 2*modulus) - modulus; 02195 vnatry = vna.subs(*s == a[i]); 02196 // ... for which the leading coefficient doesn't vanish ... 02197 } while ( vnatry == 0 ); 02198 vna = vnatry; 02199 u0 = u0.subs(*s == a[i]); 02200 ++s; 02201 } 02202 // ... for which u0 is square free ... 02203 ex g = gcd(u0, u0.diff(ex_to<symbol>(x))); 02204 if ( !is_a<numeric>(g) ) { 02205 continue; 02206 } 02207 if ( !is_a<numeric>(vn) ) { 02208 // ... and for which the evaluated factors have each an unique prime factor 02209 lst fnum = f; 02210 fnum.let_op(0) = fnum.op(0) * u0.content(x); 02211 for ( size_t i=1; i<fnum.nops(); ++i ) { 02212 if ( !is_a<numeric>(fnum.op(i)) ) { 02213 s = syms.begin(); 02214 ++s; 02215 for ( size_t j=0; j<a.size(); ++j, ++s ) { 02216 fnum.let_op(i) = fnum.op(i).subs(*s == a[j]); 02217 } 02218 } 02219 } 02220 if ( checkdivisors(fnum) ) { 02221 continue; 02222 } 02223 } 02224 // ok, we have a valid set now 02225 return; 02226 } 02227 } 02228 02229 // forward declaration 02230 static ex factor_sqrfree(const ex& poly); 02231 02247 static ex factor_multivariate(const ex& poly, const exset& syms) 02248 { 02249 exset::const_iterator s; 02250 const ex& x = *syms.begin(); 02251 02252 // make polynomial primitive 02253 ex unit, cont, pp; 02254 poly.unitcontprim(x, unit, cont, pp); 02255 if ( !is_a<numeric>(cont) ) { 02256 return factor_sqrfree(cont) * factor_sqrfree(pp); 02257 } 02258 02259 // factor leading coefficient 02260 ex vn = pp.collect(x).lcoeff(x); 02261 ex vnlst; 02262 if ( is_a<numeric>(vn) ) { 02263 vnlst = lst(vn); 02264 } 02265 else { 02266 ex vnfactors = factor(vn); 02267 vnlst = put_factors_into_lst(vnfactors); 02268 } 02269 02270 const unsigned int maxtrials = 3; 02271 numeric modulus = (vnlst.nops() > 3) ? vnlst.nops() : 3; 02272 vector<numeric> a(syms.size()-1, 0); 02273 02274 // try now to factorize until we are successful 02275 while ( true ) { 02276 02277 unsigned int trialcount = 0; 02278 unsigned int prime; 02279 int factor_count = 0; 02280 int min_factor_count = -1; 02281 ex u, delta; 02282 ex ufac, ufaclst; 02283 02284 // try several evaluation points to reduce the number of factors 02285 while ( trialcount < maxtrials ) { 02286 02287 // generate a set of valid evaluation points 02288 generate_set(pp, vn, syms, ex_to<lst>(vnlst), modulus, u, a); 02289 02290 ufac = factor_univariate(u, x, prime); 02291 ufaclst = put_factors_into_lst(ufac); 02292 factor_count = ufaclst.nops()-1; 02293 delta = ufaclst.op(0); 02294 02295 if ( factor_count <= 1 ) { 02296 // irreducible 02297 return poly; 02298 } 02299 if ( min_factor_count < 0 ) { 02300 // first time here 02301 min_factor_count = factor_count; 02302 } 02303 else if ( min_factor_count == factor_count ) { 02304 // one less to try 02305 ++trialcount; 02306 } 02307 else if ( min_factor_count > factor_count ) { 02308 // new minimum, reset trial counter 02309 min_factor_count = factor_count; 02310 trialcount = 0; 02311 } 02312 } 02313 02314 // determine true leading coefficients for the Hensel lifting 02315 vector<ex> C(factor_count); 02316 if ( is_a<numeric>(vn) ) { 02317 // easy case 02318 for ( size_t i=1; i<ufaclst.nops(); ++i ) { 02319 C[i-1] = ufaclst.op(i).lcoeff(x); 02320 } 02321 } 02322 else { 02323 // difficult case. 02324 // we use the property of the ftilde having a unique prime factor. 02325 // details can be found in [Wan]. 02326 // calculate ftilde 02327 vector<numeric> ftilde(vnlst.nops()-1); 02328 for ( size_t i=0; i<ftilde.size(); ++i ) { 02329 ex ft = vnlst.op(i+1); 02330 s = syms.begin(); 02331 ++s; 02332 for ( size_t j=0; j<a.size(); ++j ) { 02333 ft = ft.subs(*s == a[j]); 02334 ++s; 02335 } 02336 ftilde[i] = ex_to<numeric>(ft); 02337 } 02338 // calculate D and C 02339 vector<bool> used_flag(ftilde.size(), false); 02340 vector<ex> D(factor_count, 1); 02341 if ( delta == 1 ) { 02342 for ( int i=0; i<factor_count; ++i ) { 02343 numeric prefac = ex_to<numeric>(ufaclst.op(i+1).lcoeff(x)); 02344 for ( int j=ftilde.size()-1; j>=0; --j ) { 02345 int count = 0; 02346 while ( irem(prefac, ftilde[j]) == 0 ) { 02347 prefac = iquo(prefac, ftilde[j]); 02348 ++count; 02349 } 02350 if ( count ) { 02351 used_flag[j] = true; 02352 D[i] = D[i] * pow(vnlst.op(j+1), count); 02353 } 02354 } 02355 C[i] = D[i] * prefac; 02356 } 02357 } 02358 else { 02359 for ( int i=0; i<factor_count; ++i ) { 02360 numeric prefac = ex_to<numeric>(ufaclst.op(i+1).lcoeff(x)); 02361 for ( int j=ftilde.size()-1; j>=0; --j ) { 02362 int count = 0; 02363 while ( irem(prefac, ftilde[j]) == 0 ) { 02364 prefac = iquo(prefac, ftilde[j]); 02365 ++count; 02366 } 02367 while ( irem(ex_to<numeric>(delta)*prefac, ftilde[j]) == 0 ) { 02368 numeric g = gcd(prefac, ex_to<numeric>(ftilde[j])); 02369 prefac = iquo(prefac, g); 02370 delta = delta / (ftilde[j]/g); 02371 ufaclst.let_op(i+1) = ufaclst.op(i+1) * (ftilde[j]/g); 02372 ++count; 02373 } 02374 if ( count ) { 02375 used_flag[j] = true; 02376 D[i] = D[i] * pow(vnlst.op(j+1), count); 02377 } 02378 } 02379 C[i] = D[i] * prefac; 02380 } 02381 } 02382 // check if something went wrong 02383 bool some_factor_unused = false; 02384 for ( size_t i=0; i<used_flag.size(); ++i ) { 02385 if ( !used_flag[i] ) { 02386 some_factor_unused = true; 02387 break; 02388 } 02389 } 02390 if ( some_factor_unused ) { 02391 continue; 02392 } 02393 } 02394 02395 // multiply the remaining content of the univariate polynomial into the 02396 // first factor 02397 if ( delta != 1 ) { 02398 C[0] = C[0] * delta; 02399 ufaclst.let_op(1) = ufaclst.op(1) * delta; 02400 } 02401 02402 // set up evaluation points 02403 EvalPoint ep; 02404 vector<EvalPoint> epv; 02405 s = syms.begin(); 02406 ++s; 02407 for ( size_t i=0; i<a.size(); ++i ) { 02408 ep.x = *s++; 02409 ep.evalpoint = a[i].to_int(); 02410 epv.push_back(ep); 02411 } 02412 02413 // calc bound p^l 02414 int maxdeg = 0; 02415 for ( int i=1; i<=factor_count; ++i ) { 02416 if ( ufaclst.op(i).degree(x) > maxdeg ) { 02417 maxdeg = ufaclst[i].degree(x); 02418 } 02419 } 02420 cl_I B = 2*calc_bound(u, x, maxdeg); 02421 cl_I l = 1; 02422 cl_I pl = prime; 02423 while ( pl < B ) { 02424 l = l + 1; 02425 pl = pl * prime; 02426 } 02427 02428 // set up modular factors (mod p^l) 02429 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(prime),l)); 02430 upvec modfactors(ufaclst.nops()-1); 02431 for ( size_t i=1; i<ufaclst.nops(); ++i ) { 02432 umodpoly_from_ex(modfactors[i-1], ufaclst.op(i), x, R); 02433 } 02434 02435 // try Hensel lifting 02436 ex res = hensel_multivar(pp, x, epv, prime, l, modfactors, C); 02437 if ( res != lst() ) { 02438 ex result = cont * unit; 02439 for ( size_t i=0; i<res.nops(); ++i ) { 02440 result *= res.op(i).content(x) * res.op(i).unit(x); 02441 result *= res.op(i).primpart(x); 02442 } 02443 return result; 02444 } 02445 } 02446 } 02447 02450 struct find_symbols_map : public map_function { 02451 exset syms; 02452 ex operator()(const ex& e) 02453 { 02454 if ( is_a<symbol>(e) ) { 02455 syms.insert(e); 02456 return e; 02457 } 02458 return e.map(*this); 02459 } 02460 }; 02461 02465 static ex factor_sqrfree(const ex& poly) 02466 { 02467 // determine all symbols in poly 02468 find_symbols_map findsymbols; 02469 findsymbols(poly); 02470 if ( findsymbols.syms.size() == 0 ) { 02471 return poly; 02472 } 02473 02474 if ( findsymbols.syms.size() == 1 ) { 02475 // univariate case 02476 const ex& x = *(findsymbols.syms.begin()); 02477 if ( poly.ldegree(x) > 0 ) { 02478 // pull out direct factors 02479 int ld = poly.ldegree(x); 02480 ex res = factor_univariate(expand(poly/pow(x, ld)), x); 02481 return res * pow(x,ld); 02482 } 02483 else { 02484 ex res = factor_univariate(poly, x); 02485 return res; 02486 } 02487 } 02488 02489 // multivariate case 02490 ex res = factor_multivariate(poly, findsymbols.syms); 02491 return res; 02492 } 02493 02497 struct apply_factor_map : public map_function { 02498 unsigned options; 02499 apply_factor_map(unsigned options_) : options(options_) { } 02500 ex operator()(const ex& e) 02501 { 02502 if ( e.info(info_flags::polynomial) ) { 02503 return factor(e, options); 02504 } 02505 if ( is_a<add>(e) ) { 02506 ex s1, s2; 02507 for ( size_t i=0; i<e.nops(); ++i ) { 02508 if ( e.op(i).info(info_flags::polynomial) ) { 02509 s1 += e.op(i); 02510 } 02511 else { 02512 s2 += e.op(i); 02513 } 02514 } 02515 s1 = s1.eval(); 02516 s2 = s2.eval(); 02517 return factor(s1, options) + s2.map(*this); 02518 } 02519 return e.map(*this); 02520 } 02521 }; 02522 02523 } // anonymous namespace 02524 02529 ex factor(const ex& poly, unsigned options) 02530 { 02531 // check arguments 02532 if ( !poly.info(info_flags::polynomial) ) { 02533 if ( options & factor_options::all ) { 02534 options &= ~factor_options::all; 02535 apply_factor_map factor_map(options); 02536 return factor_map(poly); 02537 } 02538 return poly; 02539 } 02540 02541 // determine all symbols in poly 02542 find_symbols_map findsymbols; 02543 findsymbols(poly); 02544 if ( findsymbols.syms.size() == 0 ) { 02545 return poly; 02546 } 02547 lst syms; 02548 exset::const_iterator i=findsymbols.syms.begin(), end=findsymbols.syms.end(); 02549 for ( ; i!=end; ++i ) { 02550 syms.append(*i); 02551 } 02552 02553 // make poly square free 02554 ex sfpoly = sqrfree(poly.expand(), syms); 02555 02556 // factorize the square free components 02557 if ( is_a<power>(sfpoly) ) { 02558 // case: (polynomial)^exponent 02559 const ex& base = sfpoly.op(0); 02560 if ( !is_a<add>(base) ) { 02561 // simple case: (monomial)^exponent 02562 return sfpoly; 02563 } 02564 ex f = factor_sqrfree(base); 02565 return pow(f, sfpoly.op(1)); 02566 } 02567 if ( is_a<mul>(sfpoly) ) { 02568 // case: multiple factors 02569 ex res = 1; 02570 for ( size_t i=0; i<sfpoly.nops(); ++i ) { 02571 const ex& t = sfpoly.op(i); 02572 if ( is_a<power>(t) ) { 02573 const ex& base = t.op(0); 02574 if ( !is_a<add>(base) ) { 02575 res *= t; 02576 } 02577 else { 02578 ex f = factor_sqrfree(base); 02579 res *= pow(f, t.op(1)); 02580 } 02581 } 02582 else if ( is_a<add>(t) ) { 02583 ex f = factor_sqrfree(t); 02584 res *= f; 02585 } 02586 else { 02587 res *= t; 02588 } 02589 } 02590 return res; 02591 } 02592 if ( is_a<symbol>(sfpoly) ) { 02593 return poly; 02594 } 02595 // case: (polynomial) 02596 ex f = factor_sqrfree(sfpoly); 02597 return f; 02598 } 02599 02600 } // namespace GiNaC 02601 02602 #ifdef DEBUGFACTOR 02603 #include "test.h" 02604 #endif