GiNaC  1.6.2
factor.cpp
Go to the documentation of this file.
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

This page is part of the GiNaC developer's reference. It was generated automatically by doxygen. For an introduction, see the tutorial.