3 * Polynomial factorization code (implementation).
5 * Algorithms used can be found in
6 * [W1] An Improved Multivariate Polynomial Factoring Algorithm,
7 * P.S.Wang, Mathematics of Computation, Vol. 32, No. 144 (1978) 1215--1231.
8 * [GCL] Algorithms for Computer Algebra,
9 * K.O.Geddes, S.R.Czapor, G.Labahn, Springer Verlag, 1992.
13 * GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
36 #include "operators.h"
39 #include "relational.h"
61 #define DCOUT(str) cout << #str << endl
62 #define DCOUTVAR(var) cout << #var << ": " << var << endl
63 #define DCOUT2(str,var) cout << #str << ": " << var << endl
67 #define DCOUT2(str,var)
70 // anonymous namespace to hide all utility functions
73 typedef vector<cl_MI> mvec;
75 ostream& operator<<(ostream& o, const vector<cl_MI>& v)
77 vector<cl_MI>::const_iterator i = v.begin(), end = v.end();
83 ostream& operator<<(ostream& o, const vector< vector<cl_MI> >& v)
85 vector< vector<cl_MI> >::const_iterator i = v.begin(), end = v.end();
93 ////////////////////////////////////////////////////////////////////////////////
94 // modular univariate polynomial code
96 //typedef cl_UP_MI umod;
97 typedef std::vector<cln::cl_MI> umodpoly;
98 //typedef vector<umod> umodvec;
99 typedef vector<umodpoly> upvec;
101 // COPY FROM UPOLY.HPP
103 // CHANGED size_t -> int !!!
104 template<typename T> static int degree(const T& p)
109 template<typename T> static typename T::value_type lcoeff(const T& p)
111 return p[p.size() - 1];
114 static bool normalize_in_field(umodpoly& a)
118 if ( lcoeff(a) == a[0].ring()->one() ) {
122 const cln::cl_MI lc_1 = recip(lcoeff(a));
123 for (std::size_t k = a.size(); k-- != 0; )
128 template<typename T> static void
129 canonicalize(T& p, const typename T::size_type hint = std::numeric_limits<typename T::size_type>::max())
134 std::size_t i = p.size() - 1;
135 // Be fast if the polynomial is already canonicalized
142 bool is_zero = false;
160 p.erase(p.begin() + i, p.end());
163 // END COPY FROM UPOLY.HPP
165 static void expt_pos(const umodpoly& a, unsigned int q, umodpoly& b)
167 throw runtime_error("expt_pos: not implemented!");
168 // code below is not correct!
170 // if ( a.empty() ) return;
171 // b.resize(degree(a)*q+1, a[0].ring()->zero());
172 // cl_MI norm = recip(a[0]);
174 // for ( size_t i=0; i<an.size(); ++i ) {
175 // an[i] = an[i] * norm;
177 // b[0] = a[0].ring()->one();
178 // for ( size_t i=1; i<b.size(); ++i ) {
179 // for ( size_t j=1; j<i; ++j ) {
180 // b[i] = b[i] + ((i-j+1)*q-i-1) * a[i-j] * b[j-1];
184 // cl_MI corr = expt_pos(a[0], q);
185 // for ( size_t i=0; i<b.size(); ++i ) {
186 // b[i] = b[i] * corr;
190 static umodpoly operator+(const umodpoly& a, const umodpoly& b)
197 for ( ; i<sb; ++i ) {
200 for ( ; i<sa; ++i ) {
209 for ( ; i<sa; ++i ) {
212 for ( ; i<sb; ++i ) {
220 static umodpoly operator-(const umodpoly& a, const umodpoly& b)
227 for ( ; i<sb; ++i ) {
230 for ( ; i<sa; ++i ) {
239 for ( ; i<sa; ++i ) {
242 for ( ; i<sb; ++i ) {
250 static umodpoly operator*(const umodpoly& a, const umodpoly& b)
253 if ( a.empty() || b.empty() ) return c;
255 int n = degree(a) + degree(b);
256 c.resize(n+1, a[0].ring()->zero());
257 for ( int i=0 ; i<=n; ++i ) {
258 for ( int j=0 ; j<=i; ++j ) {
259 if ( j > degree(a) || (i-j) > degree(b) ) continue; // TODO optimize!
260 c[i] = c[i] + a[j] * b[i-j];
267 static umodpoly operator*(const umodpoly& a, const cl_MI& x)
269 umodpoly r(a.size());
270 for ( size_t i=0; i<a.size(); ++i ) {
277 static void umodpoly_from_ex(umodpoly& ump, const ex& e, const ex& x, const cl_modint_ring& R)
279 // assert: e is in Z[x]
280 int deg = e.degree(x);
282 int ldeg = e.ldegree(x);
283 for ( ; deg>=ldeg; --deg ) {
284 cl_I coeff = the<cl_I>(ex_to<numeric>(e.coeff(x, deg)).to_cl_N());
285 ump[deg] = R->canonhom(coeff);
287 for ( ; deg>=0; --deg ) {
288 ump[deg] = R->zero();
293 static void umodpoly_from_ex(umodpoly& ump, const ex& e, const ex& x, const cl_I& modulus)
295 umodpoly_from_ex(ump, e, x, find_modint_ring(modulus));
298 static ex umod_to_ex(const umodpoly& a, const ex& x)
300 if ( a.empty() ) return 0;
301 cl_modint_ring R = a[0].ring();
302 cl_I mod = R->modulus;
303 cl_I halfmod = (mod-1) >> 1;
305 for ( int i=degree(a); i>=0; --i ) {
306 cl_I n = R->retract(a[i]);
308 e += numeric(n-mod) * pow(x, i);
310 e += numeric(n) * pow(x, i);
316 /** Divides all coefficients of the polynomial a by the integer x.
317 * All coefficients are supposed to be divisible by x. If they are not, the
318 * the<cl_I> cast will raise an exception.
320 * @param[in,out] a polynomial of which the coefficients will be reduced by x
321 * @param[in] x integer that divides the coefficients
323 static void reduce_coeff(umodpoly& a, const cl_I& x)
325 if ( a.empty() ) return;
327 cl_modint_ring R = a[0].ring();
328 umodpoly::iterator i = a.begin(), end = a.end();
329 for ( ; i!=end; ++i ) {
330 // cln cannot perform this division in the modular field
331 cl_I c = R->retract(*i);
332 *i = cl_MI(R, the<cl_I>(c / x));
336 /** Calculates remainder of a/b.
337 * Assertion: a and b not empty.
339 * @param[in] a polynomial dividend
340 * @param[in] b polynomial divisor
341 * @param[out] r polynomial remainder
343 static void rem(const umodpoly& a, const umodpoly& b, umodpoly& r)
352 cl_MI qk = div(r[n+k], b[n]);
354 for ( int i=0; i<n; ++i ) {
355 unsigned int j = n + k - 1 - i;
356 r[j] = r[j] - qk * b[j-k];
361 fill(r.begin()+n, r.end(), a[0].ring()->zero());
365 /** Calculates quotient of a/b.
366 * Assertion: a and b not empty.
368 * @param[in] a polynomial dividend
369 * @param[in] b polynomial divisor
370 * @param[out] q polynomial quotient
372 static void div(const umodpoly& a, const umodpoly& b, umodpoly& q)
381 q.resize(k+1, a[0].ring()->zero());
383 cl_MI qk = div(r[n+k], b[n]);
386 for ( int i=0; i<n; ++i ) {
387 unsigned int j = n + k - 1 - i;
388 r[j] = r[j] - qk * b[j-k];
396 /** Calculates quotient and remainder of a/b.
397 * Assertion: a and b not empty.
399 * @param[in] a polynomial dividend
400 * @param[in] b polynomial divisor
401 * @param[out] r polynomial remainder
402 * @param[out] q polynomial quotient
404 static void remdiv(const umodpoly& a, const umodpoly& b, umodpoly& r, umodpoly& q)
413 q.resize(k+1, a[0].ring()->zero());
415 cl_MI qk = div(r[n+k], b[n]);
418 for ( int i=0; i<n; ++i ) {
419 unsigned int j = n + k - 1 - i;
420 r[j] = r[j] - qk * b[j-k];
425 fill(r.begin()+n, r.end(), a[0].ring()->zero());
430 /** Calculates the GCD of polynomial a and b.
432 * @param[in] a polynomial
433 * @param[in] b polynomial
436 static void gcd(const umodpoly& a, const umodpoly& b, umodpoly& c)
438 if ( degree(a) < degree(b) ) return gcd(b, a, c);
441 normalize_in_field(c);
443 normalize_in_field(d);
445 while ( !d.empty() ) {
450 normalize_in_field(c);
453 /** Calculates the derivative of the polynomial a.
455 * @param[in] a polynomial of which to take the derivative
456 * @param[out] d result/derivative
458 static void deriv(const umodpoly& a, umodpoly& d)
461 if ( a.size() <= 1 ) return;
463 d.insert(d.begin(), a.begin()+1, a.end());
465 for ( int i=1; i<max; ++i ) {
471 static bool unequal_one(const umodpoly& a)
473 if ( a.empty() ) return true;
474 return ( a.size() != 1 || a[0] != a[0].ring()->one() );
477 static bool equal_one(const umodpoly& a)
479 return ( a.size() == 1 && a[0] == a[0].ring()->one() );
482 /** Returns true if polynomial a is square free.
484 * @param[in] a polynomial to check
485 * @return true if polynomial is square free, false otherwise
487 static bool squarefree(const umodpoly& a)
499 // END modular univariate polynomial code
500 ////////////////////////////////////////////////////////////////////////////////
502 ////////////////////////////////////////////////////////////////////////////////
507 friend ostream& operator<<(ostream& o, const modular_matrix& m);
509 modular_matrix(size_t r_, size_t c_, const cl_MI& init) : r(r_), c(c_)
513 size_t rowsize() const { return r; }
514 size_t colsize() const { return c; }
515 cl_MI& operator()(size_t row, size_t col) { return m[row*c + col]; }
516 cl_MI operator()(size_t row, size_t col) const { return m[row*c + col]; }
517 void mul_col(size_t col, const cl_MI x)
519 mvec::iterator i = m.begin() + col;
520 for ( size_t rc=0; rc<r; ++rc ) {
525 void sub_col(size_t col1, size_t col2, const cl_MI fac)
527 mvec::iterator i1 = m.begin() + col1;
528 mvec::iterator i2 = m.begin() + col2;
529 for ( size_t rc=0; rc<r; ++rc ) {
530 *i1 = *i1 - *i2 * fac;
535 void switch_col(size_t col1, size_t col2)
538 mvec::iterator i1 = m.begin() + col1;
539 mvec::iterator i2 = m.begin() + col2;
540 for ( size_t rc=0; rc<r; ++rc ) {
541 buf = *i1; *i1 = *i2; *i2 = buf;
546 void mul_row(size_t row, const cl_MI x)
548 vector<cl_MI>::iterator i = m.begin() + row*c;
549 for ( size_t cc=0; cc<c; ++cc ) {
554 void sub_row(size_t row1, size_t row2, const cl_MI fac)
556 vector<cl_MI>::iterator i1 = m.begin() + row1*c;
557 vector<cl_MI>::iterator i2 = m.begin() + row2*c;
558 for ( size_t cc=0; cc<c; ++cc ) {
559 *i1 = *i1 - *i2 * fac;
564 void switch_row(size_t row1, size_t row2)
567 vector<cl_MI>::iterator i1 = m.begin() + row1*c;
568 vector<cl_MI>::iterator i2 = m.begin() + row2*c;
569 for ( size_t cc=0; cc<c; ++cc ) {
570 buf = *i1; *i1 = *i2; *i2 = buf;
575 bool is_col_zero(size_t col) const
577 mvec::const_iterator i = m.begin() + col;
578 for ( size_t rr=0; rr<r; ++rr ) {
586 bool is_row_zero(size_t row) const
588 mvec::const_iterator i = m.begin() + row*c;
589 for ( size_t cc=0; cc<c; ++cc ) {
597 void set_row(size_t row, const vector<cl_MI>& newrow)
599 mvec::iterator i1 = m.begin() + row*c;
600 mvec::const_iterator i2 = newrow.begin(), end = newrow.end();
601 for ( ; i2 != end; ++i1, ++i2 ) {
605 mvec::const_iterator row_begin(size_t row) const { return m.begin()+row*c; }
606 mvec::const_iterator row_end(size_t row) const { return m.begin()+row*c+r; }
613 modular_matrix operator*(const modular_matrix& m1, const modular_matrix& m2)
615 const unsigned int r = m1.rowsize();
616 const unsigned int c = m2.colsize();
617 modular_matrix o(r,c,m1(0,0));
619 for ( size_t i=0; i<r; ++i ) {
620 for ( size_t j=0; j<c; ++j ) {
622 buf = m1(i,0) * m2(0,j);
623 for ( size_t k=1; k<c; ++k ) {
624 buf = buf + m1(i,k)*m2(k,j);
632 ostream& operator<<(ostream& o, const modular_matrix& m)
634 vector<cl_MI>::const_iterator i = m.m.begin(), end = m.m.end();
636 for ( ; i != end; ++i ) {
638 if ( !(wrap++ % m.c) ) {
645 #endif // def DEBUGFACTOR
647 // END modular matrix
648 ////////////////////////////////////////////////////////////////////////////////
650 static void q_matrix(const umodpoly& a, modular_matrix& Q)
653 unsigned int q = cl_I_to_uint(a[0].ring()->modulus);
655 // vector<cl_MI> r(n, a.R->zero());
656 // r[0] = a.R->one();
658 // unsigned int max = (n-1) * q;
659 // for ( size_t m=1; m<=max; ++m ) {
660 // cl_MI rn_1 = r.back();
661 // for ( size_t i=n-1; i>0; --i ) {
662 // r[i] = r[i-1] - rn_1 * a[i];
664 // r[0] = -rn_1 * a[0];
665 // if ( (m % q) == 0 ) {
666 // Q.set_row(m/q, r);
669 // slow and (hopefully) correct
670 cl_MI one = a[0].ring()->one();
671 cl_MI zero = a[0].ring()->zero();
672 for ( int i=0; i<n; ++i ) {
673 umodpoly qk(i*q+1, zero);
678 for ( int j=0; j<=degree(r); ++j ) {
685 static void nullspace(modular_matrix& M, vector<mvec>& basis)
687 const size_t n = M.rowsize();
688 const cl_MI one = M(0,0).ring()->one();
689 for ( size_t i=0; i<n; ++i ) {
690 M(i,i) = M(i,i) - one;
692 for ( size_t r=0; r<n; ++r ) {
694 for ( ; cc<n; ++cc ) {
695 if ( !zerop(M(r,cc)) ) {
697 if ( !zerop(M(cc,cc)) ) {
709 M.mul_col(r, recip(M(r,r)));
710 for ( cc=0; cc<n; ++cc ) {
712 M.sub_col(cc, r, M(r,cc));
718 for ( size_t i=0; i<n; ++i ) {
719 M(i,i) = M(i,i) - one;
721 for ( size_t i=0; i<n; ++i ) {
722 if ( !M.is_row_zero(i) ) {
723 mvec nu(M.row_begin(i), M.row_end(i));
729 static void berlekamp(const umodpoly& a, upvec& upv)
731 cl_modint_ring R = a[0].ring();
732 umodpoly one(1, R->one());
734 modular_matrix Q(degree(a), degree(a), R->zero());
738 const unsigned int k = nu.size();
743 list<umodpoly> factors;
744 factors.push_back(a);
745 unsigned int size = 1;
747 unsigned int q = cl_I_to_uint(R->modulus);
749 list<umodpoly>::iterator u = factors.begin();
752 for ( unsigned int s=0; s<q; ++s ) {
753 umodpoly nur = nu[r];
754 nur[0] = nur[0] - cl_MI(R, s);
758 if ( unequal_one(g) && g != *u ) {
761 if ( equal_one(uo) ) {
762 throw logic_error("berlekamp: unexpected divisor.");
767 factors.push_back(g);
769 list<umodpoly>::const_iterator i = factors.begin(), end = factors.end();
771 if ( degree(*i) ) ++size;
775 list<umodpoly>::const_iterator i = factors.begin(), end = factors.end();
790 static void rem_xq(int q, const umodpoly& b, umodpoly& c)
792 cl_modint_ring R = b[0].ring();
796 c.resize(q+1, R->zero());
802 c.resize(n+1, R->zero());
808 cl_MI qk = div(c[n-ofs], b[n]);
810 for ( int i=1; i<=n; ++i ) {
811 c[n-i+ofs] = c[n-i] - qk * b[n-i];
826 static void distinct_degree_factor(const umodpoly& a_, upvec& result)
830 cl_modint_ring R = a[0].ring();
831 int q = cl_I_to_int(R->modulus);
836 umodpoly w(1, R->one());
841 while ( i <= nhalf ) {
849 if ( unequal_one(ai.back()) ) {
850 div(a, ai.back(), a);
860 static void same_degree_factor(const umodpoly& a, upvec& result)
862 cl_modint_ring R = a[0].ring();
866 distinct_degree_factor(a, buf);
869 for ( size_t i=0; i<buf.size(); ++i ) {
870 if ( unequal_one(buf[i]) ) {
871 degsum += degree(buf[i]);
873 berlekamp(buf[i], upv);
874 for ( size_t j=0; j<upv.size(); ++j ) {
875 result.push_back(upv[j]);
880 if ( degsum < deg ) {
885 static void distinct_degree_factor_BSGS(const umodpoly& a, upvec& result)
887 cl_modint_ring R = a[0].ring();
888 int q = cl_I_to_int(R->modulus);
892 int l = cl_I_to_int(ceiling1(the<cl_F>(expt(n, pm))));
894 umodpoly qk(1, R->one());
896 for ( int i=1; i<=l; ++i ) {
897 expt_pos(h[i-1], q, qk);
901 int m = std::ceil(((double)n)/2/l);
903 int ql = std::pow(q, l);
905 for ( int i=1; i<m; ++i ) {
906 expt_pos(H[i-1], ql, qk);
911 umodpoly one(1, R->one());
912 for ( int i=0; i<m; ++i ) {
914 for ( int j=0; j<l; ++j ) {
915 I[i] = I[i] * (H[i] - h[j]);
922 for ( int i=0; i<m; ++i ) {
925 if ( g == one ) continue;
930 result.resize(n, one);
931 if ( unequal_one(f) ) {
934 for ( int i=0; i<m; ++i ) {
936 for ( int j=l-1; j>=0; --j ) {
938 gcd(f, H[i]-h[j], g);
939 result[l*(i+1)-j-1] = g;
945 static void cantor_zassenhaus(const umodpoly& a, upvec& result)
949 static void factor_modular(const umodpoly& p, upvec& upv)
951 //same_degree_factor(p, upv);
956 static void exteuclid(const umodpoly& a, const umodpoly& b, umodpoly& g, umodpoly& s, umodpoly& t)
958 if ( degree(a) < degree(b) ) {
959 exteuclid(b, a, g, t, s);
962 umodpoly one(1, a[0].ring()->one());
963 umodpoly c = a; normalize_in_field(c);
964 umodpoly d = b; normalize_in_field(d);
969 while ( !d.empty() ) {
972 umodpoly r = c - q * d;
973 umodpoly r1 = c1 - q * d1;
974 umodpoly r2 = c2 - q * d2;
982 g = c; normalize_in_field(g);
984 for ( int i=0; i<=degree(s); ++i ) {
985 s[i] = s[i] * recip(a[degree(a)] * c[degree(c)]);
990 for ( int i=0; i<=degree(t); ++i ) {
991 t[i] = t[i] * recip(b[degree(b)] * c[degree(c)]);
997 static ex replace_lc(const ex& poly, const ex& x, const ex& lc)
999 ex r = expand(poly + (lc - poly.lcoeff(x)) * pow(x, poly.degree(x)));
1003 static ex hensel_univar(const ex& a_, const ex& x, unsigned int p, const umodpoly& u1_, const umodpoly& w1_, const ex& gamma_ = 0)
1006 const cl_modint_ring& R = u1_[0].ring();
1010 for ( int i=a.degree(x); i>=a.ldegree(x); --i ) {
1011 maxcoeff += pow(abs(a.coeff(x, i)),2);
1013 cl_I normmc = ceiling1(the<cl_R>(cln::sqrt(ex_to<numeric>(maxcoeff).to_cl_N())));
1014 cl_I maxdegree = (degree(u1_) > degree(w1_)) ? degree(u1_) : degree(w1_);
1015 cl_I B = normmc * expt_pos(cl_I(2), maxdegree);
1018 ex alpha = a.lcoeff(x);
1023 numeric gamma_ui = ex_to<numeric>(abs(gamma));
1026 normalize_in_field(nu1);
1028 normalize_in_field(nw1);
1030 phi = gamma * umod_to_ex(nu1, x);
1032 umodpoly_from_ex(u1, phi, x, R);
1033 phi = alpha * umod_to_ex(nw1, x);
1035 umodpoly_from_ex(w1, phi, x, R);
1041 exteuclid(u1, w1, g, s, t);
1042 if ( unequal_one(g) ) {
1043 throw logic_error("gcd(u1,w1) != 1");
1047 ex u = replace_lc(umod_to_ex(u1, x), x, gamma);
1048 ex w = replace_lc(umod_to_ex(w1, x), x, alpha);
1049 ex e = expand(a - u * w);
1050 numeric modulus = p;
1051 const numeric maxmodulus = 2*numeric(B)*gamma_ui;
1054 while ( !e.is_zero() && modulus < maxmodulus ) {
1056 phi = expand(umod_to_ex(s, x) * c);
1057 umodpoly sigmatilde;
1058 umodpoly_from_ex(sigmatilde, phi, x, R);
1059 phi = expand(umod_to_ex(t, x) * c);
1061 umodpoly_from_ex(tautilde, phi, x, R);
1063 remdiv(sigmatilde, w1, r, q);
1065 phi = expand(umod_to_ex(tautilde, x) + umod_to_ex(q, x) * umod_to_ex(u1, x));
1067 umodpoly_from_ex(tau, phi, x, R);
1068 u = expand(u + umod_to_ex(tau, x) * modulus);
1069 w = expand(w + umod_to_ex(sigma, x) * modulus);
1070 e = expand(a - u * w);
1071 modulus = modulus * p;
1075 if ( e.is_zero() ) {
1076 ex delta = u.content(x);
1078 w = w / gamma * delta;
1086 static unsigned int next_prime(unsigned int p)
1088 static vector<unsigned int> primes;
1089 if ( primes.size() == 0 ) {
1090 primes.push_back(3); primes.push_back(5); primes.push_back(7);
1092 vector<unsigned int>::const_iterator it = primes.begin();
1093 if ( p >= primes.back() ) {
1094 unsigned int candidate = primes.back() + 2;
1096 size_t n = primes.size()/2;
1097 for ( size_t i=0; i<n; ++i ) {
1098 if ( candidate % primes[i] ) continue;
1102 primes.push_back(candidate);
1103 if ( candidate > p ) break;
1107 vector<unsigned int>::const_iterator end = primes.end();
1108 for ( ; it!=end; ++it ) {
1113 throw logic_error("next_prime: should not reach this point!");
1119 Partition(size_t n_) : n(n_)
1125 int operator[](size_t i) const { return k[i]; }
1126 size_t size() const { return n; }
1127 size_t size_first() const { return n-sum; }
1128 size_t size_second() const { return sum; }
1132 for ( size_t i=0; i<k.size(); ++i ) {
1133 cout << k[i] << " ";
1140 for ( size_t i=n-1; i>=1; --i ) {
1156 static void split(const upvec& factors, const Partition& part, umodpoly& a, umodpoly& b)
1158 umodpoly one(1, factors.front()[0].ring()->one());
1161 for ( size_t i=0; i<part.size(); ++i ) {
1177 static ex factor_univariate(const ex& poly, const ex& x)
1179 ex unit, cont, prim;
1180 poly.unitcontprim(x, unit, cont, prim);
1182 // determine proper prime and minimize number of modular factors
1183 unsigned int p = 3, lastp = 3;
1185 unsigned int trials = 0;
1186 unsigned int minfactors = 0;
1187 numeric lcoeff = ex_to<numeric>(prim.lcoeff(x));
1189 while ( trials < 2 ) {
1192 if ( irem(lcoeff, p) != 0 ) {
1193 R = find_modint_ring(p);
1195 umodpoly_from_ex(modpoly, prim, x, R);
1196 if ( squarefree(modpoly) ) break;
1200 // do modular factorization
1202 umodpoly_from_ex(modpoly, prim, x, R);
1204 factor_modular(modpoly, trialfactors);
1205 if ( trialfactors.size() <= 1 ) {
1206 // irreducible for sure
1210 if ( minfactors == 0 || trialfactors.size() < minfactors ) {
1211 factors = trialfactors;
1212 minfactors = factors.size();
1221 R = find_modint_ring(p);
1222 cl_univpoly_modint_ring UPR = find_univpoly_ring(R);
1224 // lift all factor combinations
1225 stack<ModFactors> tocheck;
1228 mf.factors = factors;
1231 while ( tocheck.size() ) {
1232 const size_t n = tocheck.top().factors.size();
1236 split(tocheck.top().factors, part, a, b);
1238 ex answer = hensel_univar(tocheck.top().poly, x, p, a, b);
1239 if ( answer != lst() ) {
1240 if ( part.size_first() == 1 ) {
1241 if ( part.size_second() == 1 ) {
1242 result *= answer.op(0) * answer.op(1);
1246 result *= answer.op(0);
1247 tocheck.top().poly = answer.op(1);
1248 for ( size_t i=0; i<n; ++i ) {
1249 if ( part[i] == 0 ) {
1250 tocheck.top().factors.erase(tocheck.top().factors.begin()+i);
1256 else if ( part.size_second() == 1 ) {
1257 if ( part.size_first() == 1 ) {
1258 result *= answer.op(0) * answer.op(1);
1262 result *= answer.op(1);
1263 tocheck.top().poly = answer.op(0);
1264 for ( size_t i=0; i<n; ++i ) {
1265 if ( part[i] == 1 ) {
1266 tocheck.top().factors.erase(tocheck.top().factors.begin()+i);
1273 upvec newfactors1(part.size_first()), newfactors2(part.size_second());
1274 upvec::iterator i1 = newfactors1.begin(), i2 = newfactors2.begin();
1275 for ( size_t i=0; i<n; ++i ) {
1277 *i2++ = tocheck.top().factors[i];
1280 *i1++ = tocheck.top().factors[i];
1283 tocheck.top().factors = newfactors1;
1284 tocheck.top().poly = answer.op(0);
1286 mf.factors = newfactors2;
1287 mf.poly = answer.op(1);
1293 if ( !part.next() ) {
1294 result *= tocheck.top().poly;
1302 return unit * cont * result;
1311 // forward declaration
1312 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);
1314 upvec multiterm_eea_lift(const upvec& a, const ex& x, unsigned int p, unsigned int k)
1316 const size_t r = a.size();
1317 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1320 for ( size_t j=r-2; j>=1; --j ) {
1321 q[j-1] = a[j] * q[j];
1323 umodpoly beta(1, R->one());
1325 for ( size_t j=1; j<r; ++j ) {
1326 vector<ex> mdarg(2);
1327 mdarg[0] = umod_to_ex(q[j-1], x);
1328 mdarg[1] = umod_to_ex(a[j-1], x);
1329 vector<EvalPoint> empty;
1330 vector<ex> exsigma = multivar_diophant(mdarg, x, umod_to_ex(beta, x), empty, 0, p, k);
1332 umodpoly_from_ex(sigma1, exsigma[0], x, R);
1334 umodpoly_from_ex(sigma2, exsigma[1], x, R);
1336 s.push_back(sigma2);
1343 * Assert: a not empty.
1345 void change_modulus(const cl_modint_ring& R, umodpoly& a)
1347 if ( a.empty() ) return;
1348 cl_modint_ring oldR = a[0].ring();
1349 umodpoly::iterator i = a.begin(), end = a.end();
1350 for ( ; i!=end; ++i ) {
1351 *i = R->canonhom(oldR->retract(*i));
1356 void eea_lift(const umodpoly& a, const umodpoly& b, const ex& x, unsigned int p, unsigned int k, umodpoly& s_, umodpoly& t_)
1358 cl_modint_ring R = find_modint_ring(p);
1360 change_modulus(R, amod);
1362 change_modulus(R, bmod);
1367 exteuclid(amod, bmod, g, smod, tmod);
1368 if ( unequal_one(g) ) {
1369 throw logic_error("gcd(amod,bmod) != 1");
1372 cl_modint_ring Rpk = find_modint_ring(expt_pos(cl_I(p),k));
1374 change_modulus(Rpk, s);
1376 change_modulus(Rpk, t);
1379 umodpoly one(1, Rpk->one());
1380 for ( size_t j=1; j<k; ++j ) {
1381 umodpoly e = one - a * s - b * t;
1382 reduce_coeff(e, modulus);
1384 change_modulus(R, c);
1385 umodpoly sigmabar = smod * c;
1386 umodpoly taubar = tmod * c;
1388 remdiv(sigmabar, bmod, sigma, q);
1389 umodpoly tau = taubar + q * amod;
1390 umodpoly sadd = sigma;
1391 change_modulus(Rpk, sadd);
1392 cl_MI modmodulus(Rpk, modulus);
1393 s = s + sadd * modmodulus;
1394 umodpoly tadd = tau;
1395 change_modulus(Rpk, tadd);
1396 t = t + tadd * modmodulus;
1397 modulus = modulus * p;
1403 upvec univar_diophant(const upvec& a, const ex& x, unsigned int m, unsigned int p, unsigned int k)
1405 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1407 const size_t r = a.size();
1410 upvec s = multiterm_eea_lift(a, x, p, k);
1411 for ( size_t j=0; j<r; ++j ) {
1412 ex phi = expand(pow(x,m) * umod_to_ex(s[j], x));
1414 umodpoly_from_ex(bmod, phi, x, R);
1416 rem(bmod, a[j], buf);
1417 result.push_back(buf);
1423 eea_lift(a[1], a[0], x, p, k, s, t);
1424 ex phi = expand(pow(x,m) * umod_to_ex(s, x));
1426 umodpoly_from_ex(bmod, phi, x, R);
1428 remdiv(bmod, a[0], buf, q);
1429 result.push_back(buf);
1430 phi = expand(pow(x,m) * umod_to_ex(t, x));
1432 umodpoly_from_ex(t1mod, phi, x, R);
1433 umodpoly buf2 = t1mod + q * a[1];
1434 result.push_back(buf2);
1440 struct make_modular_map : public map_function {
1442 make_modular_map(const cl_modint_ring& R_) : R(R_) { }
1443 ex operator()(const ex& e)
1445 if ( is_a<add>(e) || is_a<mul>(e) ) {
1446 return e.map(*this);
1448 else if ( is_a<numeric>(e) ) {
1449 numeric mod(R->modulus);
1450 numeric halfmod = (mod-1)/2;
1451 cl_MI emod = R->canonhom(the<cl_I>(ex_to<numeric>(e).to_cl_N()));
1452 numeric n(R->retract(emod));
1453 if ( n > halfmod ) {
1464 static ex make_modular(const ex& e, const cl_modint_ring& R)
1466 make_modular_map map(R);
1467 return map(e.expand());
1470 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)
1474 const cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1475 const size_t r = a.size();
1476 const size_t nu = I.size() + 1;
1480 ex xnu = I.back().x;
1481 int alphanu = I.back().evalpoint;
1484 for ( size_t i=0; i<r; ++i ) {
1488 for ( size_t i=0; i<r; ++i ) {
1489 b[i] = normal(A / a[i]);
1492 vector<ex> anew = a;
1493 for ( size_t i=0; i<r; ++i ) {
1494 anew[i] = anew[i].subs(xnu == alphanu);
1496 ex cnew = c.subs(xnu == alphanu);
1497 vector<EvalPoint> Inew = I;
1499 sigma = multivar_diophant(anew, x, cnew, Inew, d, p, k);
1502 for ( size_t i=0; i<r; ++i ) {
1503 buf -= sigma[i] * b[i];
1505 ex e = make_modular(buf, R);
1508 for ( size_t m=1; m<=d; ++m ) {
1509 while ( !e.is_zero() && e.has(xnu) ) {
1510 monomial *= (xnu - alphanu);
1511 monomial = expand(monomial);
1512 ex cm = e.diff(ex_to<symbol>(xnu), m).subs(xnu==alphanu) / factorial(m);
1513 cm = make_modular(cm, R);
1514 if ( !cm.is_zero() ) {
1515 vector<ex> delta_s = multivar_diophant(anew, x, cm, Inew, d, p, k);
1517 for ( size_t j=0; j<delta_s.size(); ++j ) {
1518 delta_s[j] *= monomial;
1519 sigma[j] += delta_s[j];
1520 buf -= delta_s[j] * b[j];
1522 e = make_modular(buf, R);
1529 for ( size_t i=0; i<a.size(); ++i ) {
1531 umodpoly_from_ex(up, a[i], x, R);
1535 sigma.insert(sigma.begin(), r, 0);
1538 if ( is_a<add>(c) ) {
1546 for ( size_t i=0; i<nterms; ++i ) {
1547 int m = z.degree(x);
1548 cl_I cm = the<cl_I>(ex_to<numeric>(z.lcoeff(x)).to_cl_N());
1549 upvec delta_s = univar_diophant(amod, x, m, p, k);
1552 while ( poscm < 0 ) {
1553 poscm = poscm + expt_pos(cl_I(p),k);
1555 modcm = cl_MI(R, poscm);
1556 for ( size_t j=0; j<delta_s.size(); ++j ) {
1557 delta_s[j] = delta_s[j] * modcm;
1558 sigma[j] = sigma[j] + umod_to_ex(delta_s[j], x);
1566 for ( size_t i=0; i<sigma.size(); ++i ) {
1567 sigma[i] = make_modular(sigma[i], R);
1574 ostream& operator<<(ostream& o, const vector<EvalPoint>& v)
1576 for ( size_t i=0; i<v.size(); ++i ) {
1577 o << "(" << v[i].x << "==" << v[i].evalpoint << ") ";
1581 #endif // def DEBUGFACTOR
1583 ex hensel_multivar(const ex& a, const ex& x, const vector<EvalPoint>& I, unsigned int p, const cl_I& l, const upvec& u, const vector<ex>& lcU)
1585 const size_t nu = I.size() + 1;
1586 const cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),l));
1591 for ( size_t j=nu; j>=2; --j ) {
1593 int alpha = I[j-2].evalpoint;
1594 A[j-2] = A[j-1].subs(x==alpha);
1595 A[j-2] = make_modular(A[j-2], R);
1598 int maxdeg = a.degree(I.front().x);
1599 for ( size_t i=1; i<I.size(); ++i ) {
1600 int maxdeg2 = a.degree(I[i].x);
1601 if ( maxdeg2 > maxdeg ) maxdeg = maxdeg2;
1604 const size_t n = u.size();
1606 for ( size_t i=0; i<n; ++i ) {
1607 U[i] = umod_to_ex(u[i], x);
1610 for ( size_t j=2; j<=nu; ++j ) {
1613 for ( size_t m=0; m<n; ++m) {
1614 if ( lcU[m] != 1 ) {
1616 for ( size_t i=j-1; i<nu-1; ++i ) {
1617 coef = coef.subs(I[i].x == I[i].evalpoint);
1619 coef = make_modular(coef, R);
1620 int deg = U[m].degree(x);
1621 U[m] = U[m] - U[m].lcoeff(x) * pow(x,deg) + coef * pow(x,deg);
1625 for ( size_t i=0; i<n; ++i ) {
1628 ex e = expand(A[j-1] - Uprod);
1630 vector<EvalPoint> newI;
1631 for ( size_t i=1; i<=j-2; ++i ) {
1632 newI.push_back(I[i-1]);
1636 int alphaj = I[j-2].evalpoint;
1637 size_t deg = A[j-1].degree(xj);
1638 for ( size_t k=1; k<=deg; ++k ) {
1639 if ( !e.is_zero() ) {
1640 monomial *= (xj - alphaj);
1641 monomial = expand(monomial);
1642 ex dif = e.diff(ex_to<symbol>(xj), k);
1643 ex c = dif.subs(xj==alphaj) / factorial(k);
1644 if ( !c.is_zero() ) {
1645 vector<ex> deltaU = multivar_diophant(U1, x, c, newI, maxdeg, p, cl_I_to_uint(l));
1646 for ( size_t i=0; i<n; ++i ) {
1647 deltaU[i] *= monomial;
1649 U[i] = make_modular(U[i], R);
1652 for ( size_t i=0; i<n; ++i ) {
1656 e = make_modular(e, R);
1663 for ( size_t i=0; i<U.size(); ++i ) {
1666 if ( expand(a-acand).is_zero() ) {
1668 for ( size_t i=0; i<U.size(); ++i ) {
1679 static ex put_factors_into_lst(const ex& e)
1683 if ( is_a<numeric>(e) ) {
1687 if ( is_a<power>(e) ) {
1689 result.append(e.op(0));
1690 result.append(e.op(1));
1693 if ( is_a<symbol>(e) || is_a<add>(e) ) {
1699 if ( is_a<mul>(e) ) {
1701 for ( size_t i=0; i<e.nops(); ++i ) {
1703 if ( is_a<numeric>(op) ) {
1706 if ( is_a<power>(op) ) {
1707 result.append(op.op(0));
1708 result.append(op.op(1));
1710 if ( is_a<symbol>(op) || is_a<add>(op) ) {
1715 result.prepend(nfac);
1718 throw runtime_error("put_factors_into_lst: bad term.");
1722 ostream& operator<<(ostream& o, const vector<numeric>& v)
1724 for ( size_t i=0; i<v.size(); ++i ) {
1729 #endif // def DEBUGFACTOR
1731 static bool checkdivisors(const lst& f, vector<numeric>& d)
1733 const int k = f.nops()-2;
1735 d[0] = ex_to<numeric>(f.op(0) * f.op(f.nops()-1));
1736 if ( d[0] == 1 && k == 1 && abs(f.op(1)) != 1 ) {
1739 for ( int i=1; i<=k; ++i ) {
1740 q = ex_to<numeric>(abs(f.op(i)));
1741 for ( int j=i-1; j>=0; --j ) {
1756 static bool generate_set(const ex& u, const ex& vn, const exset& syms, const ex& f, const numeric& modulus, vector<numeric>& a, vector<numeric>& d)
1758 // computation of d is actually not necessary
1759 const ex& x = *syms.begin();
1765 exset::const_iterator s = syms.begin();
1767 for ( size_t i=0; i<a.size(); ++i ) {
1769 a[i] = mod(numeric(rand()), 2*modulus) - modulus;
1770 vnatry = vna.subs(*s == a[i]);
1771 } while ( vnatry == 0 );
1773 u0 = u0.subs(*s == a[i]);
1776 if ( gcd(u0,u0.diff(ex_to<symbol>(x))) != 1 ) {
1779 if ( is_a<numeric>(vn) ) {
1784 lst::const_iterator i = ex_to<lst>(f).begin();
1786 bool problem = false;
1787 while ( i!=ex_to<lst>(f).end() ) {
1789 if ( !is_a<numeric>(fs) ) {
1792 for ( size_t j=0; j<a.size(); ++j ) {
1793 fs = fs.subs(*s == a[j]);
1796 if ( abs(fs) == 1 ) {
1807 ex con = u0.content(x);
1809 trying = checkdivisors(fnum, d);
1815 static ex factor_multivariate(const ex& poly, const exset& syms)
1817 exset::const_iterator s;
1818 const ex& x = *syms.begin();
1820 /* make polynomial primitive */
1821 ex p = poly.expand().collect(x);
1822 ex cont = p.lcoeff(x);
1823 for ( numeric i=p.degree(x)-1; i>=p.ldegree(x); --i ) {
1824 cont = gcd(cont, p.coeff(x,ex_to<numeric>(i).to_int()));
1825 if ( cont == 1 ) break;
1827 ex pp = expand(normal(p / cont));
1828 if ( !is_a<numeric>(cont) ) {
1829 return factor(cont) * factor(pp);
1832 /* factor leading coefficient */
1834 ex vn = pp.lcoeff(x);
1837 if ( is_a<numeric>(vn) ) {
1841 ex vnfactors = factor(vn);
1842 vnlst = put_factors_into_lst(vnfactors);
1845 const numeric maxtrials = 3;
1846 numeric modulus = (vnlst.nops()-1 > 3) ? vnlst.nops()-1 : 3;
1847 numeric minimalr = -1;
1848 vector<numeric> a(syms.size()-1, 0);
1849 vector<numeric> d((vnlst.nops()-1)/2+1, 0);
1852 numeric trialcount = 0;
1854 unsigned int prime = 3;
1855 size_t factor_count = 0;
1858 while ( trialcount < maxtrials ) {
1859 bool problem = generate_set(pp, vn, syms, vnlst, modulus, a, d);
1867 for ( size_t i=0; i<a.size(); ++i ) {
1868 u = u.subs(*s == a[i]);
1871 delta = u.content(x);
1873 // determine proper prime
1875 cl_modint_ring R = find_modint_ring(prime);
1877 if ( irem(ex_to<numeric>(u.lcoeff(x)), prime) != 0 ) {
1879 umodpoly_from_ex(modpoly, u, x, R);
1880 if ( squarefree(modpoly) ) break;
1882 prime = next_prime(prime);
1883 R = find_modint_ring(prime);
1887 ufaclst = put_factors_into_lst(ufac);
1888 factor_count = (ufaclst.nops()-1)/2;
1890 // veto factorization for which gcd(u_i, u_j) != 1 for all i,j
1892 for ( size_t i=0; i<(ufaclst.nops()-1)/2; ++i ) {
1894 umodpoly_from_ex(newu, ufaclst.op(i*2+1), x, R);
1895 tryu.push_back(newu);
1898 for ( size_t i=0; i<tryu.size()-1; ++i ) {
1899 for ( size_t j=i+1; j<tryu.size(); ++j ) {
1901 gcd(tryu[i], tryu[j], tryg);
1902 if ( unequal_one(tryg) ) {
1904 goto escape_quickly;
1913 if ( factor_count <= 1 ) {
1917 if ( minimalr < 0 ) {
1918 minimalr = factor_count;
1920 else if ( minimalr == factor_count ) {
1924 else if ( minimalr > factor_count ) {
1925 minimalr = factor_count;
1928 if ( minimalr <= 1 ) {
1933 vector<numeric> ftilde((vnlst.nops()-1)/2+1);
1934 ftilde[0] = ex_to<numeric>(vnlst.op(0));
1935 for ( size_t i=1; i<ftilde.size(); ++i ) {
1936 ex ft = vnlst.op((i-1)*2+1);
1939 for ( size_t j=0; j<a.size(); ++j ) {
1940 ft = ft.subs(*s == a[j]);
1943 ftilde[i] = ex_to<numeric>(ft);
1946 vector<bool> used_flag((vnlst.nops()-1)/2+1, false);
1947 vector<ex> D(factor_count, 1);
1948 for ( size_t i=0; i<=factor_count; ++i ) {
1951 prefac = ex_to<numeric>(ufaclst.op(0));
1952 ftilde[0] = ftilde[0] / prefac;
1953 vnlst.let_op(0) = vnlst.op(0) / prefac;
1957 prefac = ex_to<numeric>(ufaclst.op(2*(i-1)+1).lcoeff(x));
1959 for ( size_t j=(vnlst.nops()-1)/2+1; j>0; --j ) {
1960 if ( abs(ftilde[j-1]) == 1 ) {
1961 used_flag[j-1] = true;
1964 numeric g = gcd(prefac, ftilde[j-1]);
1966 prefac = prefac / g;
1967 numeric count = abs(iquo(g, ftilde[j-1]));
1968 used_flag[j-1] = true;
1971 D[i-1] = D[i-1] * pow(vnlst.op(0), count);
1974 D[i-1] = D[i-1] * pow(vnlst.op(2*(j-2)+1), count);
1978 ftilde[j-1] = ftilde[j-1] / prefac;
1986 bool some_factor_unused = false;
1987 for ( size_t i=0; i<used_flag.size(); ++i ) {
1988 if ( !used_flag[i] ) {
1989 some_factor_unused = true;
1993 if ( some_factor_unused ) {
1997 vector<ex> C(factor_count);
1999 for ( size_t i=0; i<D.size(); ++i ) {
2003 for ( size_t j=0; j<a.size(); ++j ) {
2004 Dtilde = Dtilde.subs(*s == a[j]);
2007 C[i] = D[i] * (ufaclst.op(2*i+1).lcoeff(x) / Dtilde);
2011 for ( size_t i=0; i<D.size(); ++i ) {
2015 for ( size_t j=0; j<a.size(); ++j ) {
2016 Dtilde = Dtilde.subs(*s == a[j]);
2024 ui = ufaclst.op(2*(i-1)+1);
2027 ex d = gcd(ui.lcoeff(x), Dtilde);
2028 C[i] = D[i] * ( ui.lcoeff(x) / d );
2029 ui = ui * ( Dtilde[i] / d );
2030 delta = delta / ( Dtilde[i] / d );
2031 if ( delta == 1 ) break;
2033 C[i] = delta * C[i];
2034 pp = pp * pow(delta, D.size()-1);
2040 vector<EvalPoint> epv;
2043 for ( size_t i=0; i<a.size(); ++i ) {
2045 ep.evalpoint = a[i].to_int();
2051 for ( int i=u.degree(x); i>=u.ldegree(x); --i ) {
2052 maxcoeff += pow(abs(u.coeff(x, i)),2);
2054 cl_I normmc = ceiling1(the<cl_R>(cln::sqrt(ex_to<numeric>(maxcoeff).to_cl_N())));
2055 unsigned int maxdegree = 0;
2056 for ( size_t i=0; i<factor_count; ++i ) {
2057 if ( ufaclst[2*i+1].degree(x) > (int)maxdegree ) {
2058 maxdegree = ufaclst[2*i+1].degree(x);
2061 cl_I B = normmc * expt_pos(cl_I(2), maxdegree);
2070 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(prime),l));
2071 for ( size_t i=0; i<(ufaclst.nops()-1)/2; ++i ) {
2073 umodpoly_from_ex(newu, ufaclst.op(i*2+1), x, R);
2074 uvec.push_back(newu);
2077 ex res = hensel_multivar(ufaclst.op(0)*pp, x, epv, prime, l, uvec, C);
2078 if ( res != lst() ) {
2079 ex result = cont * ufaclst.op(0);
2080 for ( size_t i=0; i<res.nops(); ++i ) {
2081 result *= res.op(i).content(x) * res.op(i).unit(x);
2082 result *= res.op(i).primpart(x);
2089 struct find_symbols_map : public map_function {
2091 ex operator()(const ex& e)
2093 if ( is_a<symbol>(e) ) {
2097 return e.map(*this);
2101 static ex factor_sqrfree(const ex& poly)
2103 // determine all symbols in poly
2104 find_symbols_map findsymbols;
2106 if ( findsymbols.syms.size() == 0 ) {
2110 if ( findsymbols.syms.size() == 1 ) {
2112 const ex& x = *(findsymbols.syms.begin());
2113 if ( poly.ldegree(x) > 0 ) {
2114 int ld = poly.ldegree(x);
2115 ex res = factor_univariate(expand(poly/pow(x, ld)), x);
2116 return res * pow(x,ld);
2119 ex res = factor_univariate(poly, x);
2124 // multivariate case
2125 ex res = factor_multivariate(poly, findsymbols.syms);
2129 struct apply_factor_map : public map_function {
2131 apply_factor_map(unsigned options_) : options(options_) { }
2132 ex operator()(const ex& e)
2134 if ( e.info(info_flags::polynomial) ) {
2135 return factor(e, options);
2137 if ( is_a<add>(e) ) {
2139 for ( size_t i=0; i<e.nops(); ++i ) {
2140 if ( e.op(i).info(info_flags::polynomial) ) {
2149 return factor(s1, options) + s2.map(*this);
2151 return e.map(*this);
2155 } // anonymous namespace
2157 ex factor(const ex& poly, unsigned options)
2160 if ( !poly.info(info_flags::polynomial) ) {
2161 if ( options & factor_options::all ) {
2162 options &= ~factor_options::all;
2163 apply_factor_map factor_map(options);
2164 return factor_map(poly);
2169 // determine all symbols in poly
2170 find_symbols_map findsymbols;
2172 if ( findsymbols.syms.size() == 0 ) {
2176 exset::const_iterator i=findsymbols.syms.begin(), end=findsymbols.syms.end();
2177 for ( ; i!=end; ++i ) {
2181 // make poly square free
2182 ex sfpoly = sqrfree(poly, syms);
2184 // factorize the square free components
2185 if ( is_a<power>(sfpoly) ) {
2186 // case: (polynomial)^exponent
2187 const ex& base = sfpoly.op(0);
2188 if ( !is_a<add>(base) ) {
2189 // simple case: (monomial)^exponent
2192 ex f = factor_sqrfree(base);
2193 return pow(f, sfpoly.op(1));
2195 if ( is_a<mul>(sfpoly) ) {
2196 // case: multiple factors
2198 for ( size_t i=0; i<sfpoly.nops(); ++i ) {
2199 const ex& t = sfpoly.op(i);
2200 if ( is_a<power>(t) ) {
2201 const ex& base = t.op(0);
2202 if ( !is_a<add>(base) ) {
2206 ex f = factor_sqrfree(base);
2207 res *= pow(f, t.op(1));
2210 else if ( is_a<add>(t) ) {
2211 ex f = factor_sqrfree(t);
2220 if ( is_a<symbol>(sfpoly) ) {
2223 // case: (polynomial)
2224 ex f = factor_sqrfree(sfpoly);
2228 } // namespace GiNaC