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<int>& v)
77 vector<int>::const_iterator i = v.begin(), end = v.end();
83 ostream& operator<<(ostream& o, const vector<cl_I>& v)
85 vector<cl_I>::const_iterator i = v.begin(), end = v.end();
87 o << *i << "[" << i-v.begin() << "]" << " ";
92 ostream& operator<<(ostream& o, const vector<cl_MI>& v)
94 vector<cl_MI>::const_iterator i = v.begin(), end = v.end();
96 o << *i << "[" << i-v.begin() << "]" << " ";
101 ostream& operator<<(ostream& o, const vector< vector<cl_MI> >& v)
103 vector< vector<cl_MI> >::const_iterator i = v.begin(), end = v.end();
105 o << i-v.begin() << ": " << *i << endl;
112 ////////////////////////////////////////////////////////////////////////////////
113 // modular univariate polynomial code
115 typedef std::vector<cln::cl_MI> umodpoly;
116 typedef std::vector<cln::cl_I> upoly;
117 typedef vector<umodpoly> upvec;
119 // COPY FROM UPOLY.HPP
121 // CHANGED size_t -> int !!!
122 template<typename T> static int degree(const T& p)
127 template<typename T> static typename T::value_type lcoeff(const T& p)
129 return p[p.size() - 1];
132 static bool normalize_in_field(umodpoly& a)
136 if ( lcoeff(a) == a[0].ring()->one() ) {
140 const cln::cl_MI lc_1 = recip(lcoeff(a));
141 for (std::size_t k = a.size(); k-- != 0; )
146 template<typename T> static void
147 canonicalize(T& p, const typename T::size_type hint = std::numeric_limits<typename T::size_type>::max())
152 std::size_t i = p.size() - 1;
153 // Be fast if the polynomial is already canonicalized
160 bool is_zero = false;
178 p.erase(p.begin() + i, p.end());
181 // END COPY FROM UPOLY.HPP
183 static void expt_pos(umodpoly& a, unsigned int q)
185 if ( a.empty() ) return;
186 cl_MI zero = a[0].ring()->zero();
188 a.resize(degree(a)*q+1, zero);
189 for ( int i=deg; i>0; --i ) {
196 static T operator+(const T& a, const T& b)
203 for ( ; i<sb; ++i ) {
206 for ( ; i<sa; ++i ) {
215 for ( ; i<sa; ++i ) {
218 for ( ; i<sb; ++i ) {
227 static T operator-(const T& a, const T& b)
234 for ( ; i<sb; ++i ) {
237 for ( ; i<sa; ++i ) {
246 for ( ; i<sa; ++i ) {
249 for ( ; i<sb; ++i ) {
257 static upoly operator*(const upoly& a, const upoly& b)
260 if ( a.empty() || b.empty() ) return c;
262 int n = degree(a) + degree(b);
264 for ( int i=0 ; i<=n; ++i ) {
265 for ( int j=0 ; j<=i; ++j ) {
266 if ( j > degree(a) || (i-j) > degree(b) ) continue;
267 c[i] = c[i] + a[j] * b[i-j];
274 static umodpoly operator*(const umodpoly& a, const umodpoly& b)
277 if ( a.empty() || b.empty() ) return c;
279 int n = degree(a) + degree(b);
280 c.resize(n+1, a[0].ring()->zero());
281 for ( int i=0 ; i<=n; ++i ) {
282 for ( int j=0 ; j<=i; ++j ) {
283 if ( j > degree(a) || (i-j) > degree(b) ) continue;
284 c[i] = c[i] + a[j] * b[i-j];
291 static upoly operator*(const upoly& a, const cl_I& x)
298 for ( size_t i=0; i<a.size(); ++i ) {
304 static upoly operator/(const upoly& a, const cl_I& x)
311 for ( size_t i=0; i<a.size(); ++i ) {
312 r[i] = exquo(a[i],x);
317 static umodpoly operator*(const umodpoly& a, const cl_MI& x)
319 umodpoly r(a.size());
320 for ( size_t i=0; i<a.size(); ++i ) {
327 static void upoly_from_ex(upoly& up, const ex& e, const ex& x)
329 // assert: e is in Z[x]
330 int deg = e.degree(x);
332 int ldeg = e.ldegree(x);
333 for ( ; deg>=ldeg; --deg ) {
334 up[deg] = the<cl_I>(ex_to<numeric>(e.coeff(x, deg)).to_cl_N());
336 for ( ; deg>=0; --deg ) {
342 static void umodpoly_from_upoly(umodpoly& ump, const upoly& e, const cl_modint_ring& R)
346 for ( ; deg>=0; --deg ) {
347 ump[deg] = R->canonhom(e[deg]);
352 static void umodpoly_from_ex(umodpoly& ump, const ex& e, const ex& x, const cl_modint_ring& R)
354 // assert: e is in Z[x]
355 int deg = e.degree(x);
357 int ldeg = e.ldegree(x);
358 for ( ; deg>=ldeg; --deg ) {
359 cl_I coeff = the<cl_I>(ex_to<numeric>(e.coeff(x, deg)).to_cl_N());
360 ump[deg] = R->canonhom(coeff);
362 for ( ; deg>=0; --deg ) {
363 ump[deg] = R->zero();
368 static void umodpoly_from_ex(umodpoly& ump, const ex& e, const ex& x, const cl_I& modulus)
370 umodpoly_from_ex(ump, e, x, find_modint_ring(modulus));
373 static ex upoly_to_ex(const upoly& a, const ex& x)
375 if ( a.empty() ) return 0;
377 for ( int i=degree(a); i>=0; --i ) {
378 e += numeric(a[i]) * pow(x, i);
383 static ex umodpoly_to_ex(const umodpoly& a, const ex& x)
385 if ( a.empty() ) return 0;
386 cl_modint_ring R = a[0].ring();
387 cl_I mod = R->modulus;
388 cl_I halfmod = (mod-1) >> 1;
390 for ( int i=degree(a); i>=0; --i ) {
391 cl_I n = R->retract(a[i]);
393 e += numeric(n-mod) * pow(x, i);
395 e += numeric(n) * pow(x, i);
401 static upoly umodpoly_to_upoly(const umodpoly& a)
404 if ( a.empty() ) return e;
405 cl_modint_ring R = a[0].ring();
406 cl_I mod = R->modulus;
407 cl_I halfmod = (mod-1) >> 1;
408 for ( int i=degree(a); i>=0; --i ) {
409 cl_I n = R->retract(a[i]);
419 static umodpoly umodpoly_to_umodpoly(const umodpoly& a, const cl_modint_ring& R, unsigned int m)
422 if ( a.empty() ) return e;
423 cl_modint_ring oldR = a[0].ring();
424 size_t sa = a.size();
425 e.resize(sa+m, R->zero());
426 for ( size_t i=0; i<sa; ++i ) {
427 e[i+m] = R->canonhom(oldR->retract(a[i]));
433 /** Divides all coefficients of the polynomial a by the integer x.
434 * All coefficients are supposed to be divisible by x. If they are not, the
435 * the<cl_I> cast will raise an exception.
437 * @param[in,out] a polynomial of which the coefficients will be reduced by x
438 * @param[in] x integer that divides the coefficients
440 static void reduce_coeff(umodpoly& a, const cl_I& x)
442 if ( a.empty() ) return;
444 cl_modint_ring R = a[0].ring();
445 umodpoly::iterator i = a.begin(), end = a.end();
446 for ( ; i!=end; ++i ) {
447 // cln cannot perform this division in the modular field
448 cl_I c = R->retract(*i);
449 *i = cl_MI(R, the<cl_I>(c / x));
453 /** Calculates remainder of a/b.
454 * Assertion: a and b not empty.
456 * @param[in] a polynomial dividend
457 * @param[in] b polynomial divisor
458 * @param[out] r polynomial remainder
460 static void rem(const umodpoly& a, const umodpoly& b, umodpoly& r)
469 cl_MI qk = div(r[n+k], b[n]);
471 for ( int i=0; i<n; ++i ) {
472 unsigned int j = n + k - 1 - i;
473 r[j] = r[j] - qk * b[j-k];
478 fill(r.begin()+n, r.end(), a[0].ring()->zero());
482 /** Calculates quotient of a/b.
483 * Assertion: a and b not empty.
485 * @param[in] a polynomial dividend
486 * @param[in] b polynomial divisor
487 * @param[out] q polynomial quotient
489 static void div(const umodpoly& a, const umodpoly& b, umodpoly& q)
498 q.resize(k+1, a[0].ring()->zero());
500 cl_MI qk = div(r[n+k], b[n]);
503 for ( int i=0; i<n; ++i ) {
504 unsigned int j = n + k - 1 - i;
505 r[j] = r[j] - qk * b[j-k];
513 /** Calculates quotient and remainder of a/b.
514 * Assertion: a and b not empty.
516 * @param[in] a polynomial dividend
517 * @param[in] b polynomial divisor
518 * @param[out] r polynomial remainder
519 * @param[out] q polynomial quotient
521 static void remdiv(const umodpoly& a, const umodpoly& b, umodpoly& r, umodpoly& q)
530 q.resize(k+1, a[0].ring()->zero());
532 cl_MI qk = div(r[n+k], b[n]);
535 for ( int i=0; i<n; ++i ) {
536 unsigned int j = n + k - 1 - i;
537 r[j] = r[j] - qk * b[j-k];
542 fill(r.begin()+n, r.end(), a[0].ring()->zero());
547 /** Calculates the GCD of polynomial a and b.
549 * @param[in] a polynomial
550 * @param[in] b polynomial
553 static void gcd(const umodpoly& a, const umodpoly& b, umodpoly& c)
555 if ( degree(a) < degree(b) ) return gcd(b, a, c);
558 normalize_in_field(c);
560 normalize_in_field(d);
562 while ( !d.empty() ) {
567 normalize_in_field(c);
570 /** Calculates the derivative of the polynomial a.
572 * @param[in] a polynomial of which to take the derivative
573 * @param[out] d result/derivative
575 static void deriv(const umodpoly& a, umodpoly& d)
578 if ( a.size() <= 1 ) return;
580 d.insert(d.begin(), a.begin()+1, a.end());
582 for ( int i=1; i<max; ++i ) {
588 static bool unequal_one(const umodpoly& a)
590 if ( a.empty() ) return true;
591 return ( a.size() != 1 || a[0] != a[0].ring()->one() );
594 static bool equal_one(const umodpoly& a)
596 return ( a.size() == 1 && a[0] == a[0].ring()->one() );
599 /** Returns true if polynomial a is square free.
601 * @param[in] a polynomial to check
602 * @return true if polynomial is square free, false otherwise
604 static bool squarefree(const umodpoly& a)
616 // END modular univariate polynomial code
617 ////////////////////////////////////////////////////////////////////////////////
619 ////////////////////////////////////////////////////////////////////////////////
624 friend ostream& operator<<(ostream& o, const modular_matrix& m);
626 modular_matrix(size_t r_, size_t c_, const cl_MI& init) : r(r_), c(c_)
630 size_t rowsize() const { return r; }
631 size_t colsize() const { return c; }
632 cl_MI& operator()(size_t row, size_t col) { return m[row*c + col]; }
633 cl_MI operator()(size_t row, size_t col) const { return m[row*c + col]; }
634 void mul_col(size_t col, const cl_MI x)
636 mvec::iterator i = m.begin() + col;
637 for ( size_t rc=0; rc<r; ++rc ) {
642 void sub_col(size_t col1, size_t col2, const cl_MI fac)
644 mvec::iterator i1 = m.begin() + col1;
645 mvec::iterator i2 = m.begin() + col2;
646 for ( size_t rc=0; rc<r; ++rc ) {
647 *i1 = *i1 - *i2 * fac;
652 void switch_col(size_t col1, size_t col2)
655 mvec::iterator i1 = m.begin() + col1;
656 mvec::iterator i2 = m.begin() + col2;
657 for ( size_t rc=0; rc<r; ++rc ) {
658 buf = *i1; *i1 = *i2; *i2 = buf;
663 void mul_row(size_t row, const cl_MI x)
665 vector<cl_MI>::iterator i = m.begin() + row*c;
666 for ( size_t cc=0; cc<c; ++cc ) {
671 void sub_row(size_t row1, size_t row2, const cl_MI fac)
673 vector<cl_MI>::iterator i1 = m.begin() + row1*c;
674 vector<cl_MI>::iterator i2 = m.begin() + row2*c;
675 for ( size_t cc=0; cc<c; ++cc ) {
676 *i1 = *i1 - *i2 * fac;
681 void switch_row(size_t row1, size_t row2)
684 vector<cl_MI>::iterator i1 = m.begin() + row1*c;
685 vector<cl_MI>::iterator i2 = m.begin() + row2*c;
686 for ( size_t cc=0; cc<c; ++cc ) {
687 buf = *i1; *i1 = *i2; *i2 = buf;
692 bool is_col_zero(size_t col) const
694 mvec::const_iterator i = m.begin() + col;
695 for ( size_t rr=0; rr<r; ++rr ) {
703 bool is_row_zero(size_t row) const
705 mvec::const_iterator i = m.begin() + row*c;
706 for ( size_t cc=0; cc<c; ++cc ) {
714 void set_row(size_t row, const vector<cl_MI>& newrow)
716 mvec::iterator i1 = m.begin() + row*c;
717 mvec::const_iterator i2 = newrow.begin(), end = newrow.end();
718 for ( ; i2 != end; ++i1, ++i2 ) {
722 mvec::const_iterator row_begin(size_t row) const { return m.begin()+row*c; }
723 mvec::const_iterator row_end(size_t row) const { return m.begin()+row*c+r; }
730 modular_matrix operator*(const modular_matrix& m1, const modular_matrix& m2)
732 const unsigned int r = m1.rowsize();
733 const unsigned int c = m2.colsize();
734 modular_matrix o(r,c,m1(0,0));
736 for ( size_t i=0; i<r; ++i ) {
737 for ( size_t j=0; j<c; ++j ) {
739 buf = m1(i,0) * m2(0,j);
740 for ( size_t k=1; k<c; ++k ) {
741 buf = buf + m1(i,k)*m2(k,j);
749 ostream& operator<<(ostream& o, const modular_matrix& m)
751 cl_modint_ring R = m(0,0).ring();
753 for ( size_t i=0; i<m.rowsize(); ++i ) {
755 for ( size_t j=0; j<m.colsize()-1; ++j ) {
756 o << R->retract(m(i,j)) << ",";
758 o << R->retract(m(i,m.colsize()-1)) << "}";
759 if ( i != m.rowsize()-1 ) {
766 #endif // def DEBUGFACTOR
768 // END modular matrix
769 ////////////////////////////////////////////////////////////////////////////////
771 static void q_matrix(const umodpoly& a_, modular_matrix& Q)
774 normalize_in_field(a);
777 unsigned int q = cl_I_to_uint(a[0].ring()->modulus);
778 umodpoly r(n, a[0].ring()->zero());
779 r[0] = a[0].ring()->one();
781 unsigned int max = (n-1) * q;
782 for ( size_t m=1; m<=max; ++m ) {
783 cl_MI rn_1 = r.back();
784 for ( size_t i=n-1; i>0; --i ) {
785 r[i] = r[i-1] - (rn_1 * a[i]);
788 if ( (m % q) == 0 ) {
794 static void nullspace(modular_matrix& M, vector<mvec>& basis)
796 const size_t n = M.rowsize();
797 const cl_MI one = M(0,0).ring()->one();
798 for ( size_t i=0; i<n; ++i ) {
799 M(i,i) = M(i,i) - one;
801 for ( size_t r=0; r<n; ++r ) {
803 for ( ; cc<n; ++cc ) {
804 if ( !zerop(M(r,cc)) ) {
806 if ( !zerop(M(cc,cc)) ) {
818 M.mul_col(r, recip(M(r,r)));
819 for ( cc=0; cc<n; ++cc ) {
821 M.sub_col(cc, r, M(r,cc));
827 for ( size_t i=0; i<n; ++i ) {
828 M(i,i) = M(i,i) - one;
830 for ( size_t i=0; i<n; ++i ) {
831 if ( !M.is_row_zero(i) ) {
832 mvec nu(M.row_begin(i), M.row_end(i));
838 static void berlekamp(const umodpoly& a, upvec& upv)
840 cl_modint_ring R = a[0].ring();
841 umodpoly one(1, R->one());
843 modular_matrix Q(degree(a), degree(a), R->zero());
848 const unsigned int k = nu.size();
853 list<umodpoly> factors;
854 factors.push_back(a);
855 unsigned int size = 1;
857 unsigned int q = cl_I_to_uint(R->modulus);
859 list<umodpoly>::iterator u = factors.begin();
862 for ( unsigned int s=0; s<q; ++s ) {
863 umodpoly nur = nu[r];
864 nur[0] = nur[0] - cl_MI(R, s);
868 if ( unequal_one(g) && g != *u ) {
871 if ( equal_one(uo) ) {
872 throw logic_error("berlekamp: unexpected divisor.");
877 factors.push_back(g);
879 list<umodpoly>::const_iterator i = factors.begin(), end = factors.end();
881 if ( degree(*i) ) ++size;
885 list<umodpoly>::const_iterator i = factors.begin(), end = factors.end();
900 static void expt_1_over_p(const umodpoly& a, unsigned int prime, umodpoly& ap)
902 size_t newdeg = degree(a)/prime;
905 for ( size_t i=1; i<=newdeg; ++i ) {
910 static void modsqrfree(const umodpoly& a, upvec& factors, vector<int>& mult)
912 const unsigned int prime = cl_I_to_uint(a[0].ring()->modulus);
921 while ( unequal_one(w) ) {
926 factors.push_back(z);
934 if ( unequal_one(c) ) {
936 expt_1_over_p(c, prime, cp);
937 size_t previ = mult.size();
938 modsqrfree(cp, factors, mult);
939 for ( size_t i=previ; i<mult.size(); ++i ) {
946 expt_1_over_p(a, prime, ap);
947 size_t previ = mult.size();
948 modsqrfree(ap, factors, mult);
949 for ( size_t i=previ; i<mult.size(); ++i ) {
955 static void distinct_degree_factor(const umodpoly& a_, vector<int>& degrees, upvec& ddfactors)
959 cl_modint_ring R = a[0].ring();
960 int q = cl_I_to_int(R->modulus);
961 int nhalf = degree(a)/2;
969 while ( i <= nhalf ) {
976 if ( unequal_one(buf) ) {
977 degrees.push_back(i);
978 ddfactors.push_back(buf);
980 if ( unequal_one(buf) ) {
990 if ( unequal_one(a) ) {
991 degrees.push_back(degree(a));
992 ddfactors.push_back(a);
996 static void same_degree_factor(const umodpoly& a, upvec& upv)
998 cl_modint_ring R = a[0].ring();
1000 vector<int> degrees;
1002 distinct_degree_factor(a, degrees, ddfactors);
1004 for ( size_t i=0; i<degrees.size(); ++i ) {
1005 if ( degrees[i] == degree(ddfactors[i]) ) {
1006 upv.push_back(ddfactors[i]);
1009 berlekamp(ddfactors[i], upv);
1014 #define USE_SAME_DEGREE_FACTOR
1016 static void factor_modular(const umodpoly& p, upvec& upv)
1018 #ifdef USE_SAME_DEGREE_FACTOR
1019 same_degree_factor(p, upv);
1025 /** Calculates polynomials s and t such that a*s+b*t==1.
1026 * Assertion: a and b are relatively prime and not zero.
1028 * @param[in] a polynomial
1029 * @param[in] b polynomial
1030 * @param[out] s polynomial
1031 * @param[out] t polynomial
1033 static void exteuclid(const umodpoly& a, const umodpoly& b, umodpoly& s, umodpoly& t)
1035 if ( degree(a) < degree(b) ) {
1036 exteuclid(b, a, t, s);
1040 umodpoly one(1, a[0].ring()->one());
1041 umodpoly c = a; normalize_in_field(c);
1042 umodpoly d = b; normalize_in_field(d);
1050 umodpoly r = c - q * d;
1051 umodpoly r1 = s - q * d1;
1052 umodpoly r2 = t - q * d2;
1056 if ( r.empty() ) break;
1061 cl_MI fac = recip(lcoeff(a) * lcoeff(c));
1062 umodpoly::iterator i = s.begin(), end = s.end();
1063 for ( ; i!=end; ++i ) {
1067 fac = recip(lcoeff(b) * lcoeff(c));
1068 i = t.begin(), end = t.end();
1069 for ( ; i!=end; ++i ) {
1075 static upoly replace_lc(const upoly& poly, const cl_I& lc)
1077 if ( poly.empty() ) return poly;
1083 static inline cl_I calc_bound(const ex& a, const ex& x, int maxdeg)
1087 for ( int i=a.degree(x); i>=a.ldegree(x); --i ) {
1088 cl_I aa = abs(the<cl_I>(ex_to<numeric>(a.coeff(x, i)).to_cl_N()));
1089 if ( aa > maxcoeff ) maxcoeff = aa;
1090 coeff = coeff + square(aa);
1092 cl_I coeffnorm = ceiling1(the<cl_R>(cln::sqrt(coeff)));
1093 cl_I B = coeffnorm * expt_pos(cl_I(2), cl_I(maxdeg));
1094 return ( B > maxcoeff ) ? B : maxcoeff;
1097 static inline cl_I calc_bound(const upoly& a, int maxdeg)
1101 for ( int i=degree(a); i>=0; --i ) {
1102 cl_I aa = abs(a[i]);
1103 if ( aa > maxcoeff ) maxcoeff = aa;
1104 coeff = coeff + square(aa);
1106 cl_I coeffnorm = ceiling1(the<cl_R>(cln::sqrt(coeff)));
1107 cl_I B = coeffnorm * expt_pos(cl_I(2), cl_I(maxdeg));
1108 return ( B > maxcoeff ) ? B : maxcoeff;
1111 static void hensel_univar(const upoly& a_, unsigned int p, const umodpoly& u1_, const umodpoly& w1_, upoly& u, upoly& w)
1114 const cl_modint_ring& R = u1_[0].ring();
1117 int maxdeg = (degree(u1_) > degree(w1_)) ? degree(u1_) : degree(w1_);
1118 cl_I maxmodulus = 2*calc_bound(a, maxdeg);
1121 cl_I alpha = lcoeff(a);
1124 normalize_in_field(nu1);
1126 normalize_in_field(nw1);
1128 phi = umodpoly_to_upoly(nu1) * alpha;
1130 umodpoly_from_upoly(u1, phi, R);
1131 phi = umodpoly_to_upoly(nw1) * alpha;
1133 umodpoly_from_upoly(w1, phi, R);
1138 exteuclid(u1, w1, s, t);
1141 u = replace_lc(umodpoly_to_upoly(u1), alpha);
1142 w = replace_lc(umodpoly_to_upoly(w1), alpha);
1143 upoly e = a - u * w;
1147 while ( !e.empty() && modulus < maxmodulus ) {
1148 upoly c = e / modulus;
1149 phi = umodpoly_to_upoly(s) * c;
1150 umodpoly sigmatilde;
1151 umodpoly_from_upoly(sigmatilde, phi, R);
1152 phi = umodpoly_to_upoly(t) * c;
1154 umodpoly_from_upoly(tautilde, phi, R);
1156 remdiv(sigmatilde, w1, r, q);
1158 phi = umodpoly_to_upoly(tautilde) + umodpoly_to_upoly(q) * umodpoly_to_upoly(u1);
1160 umodpoly_from_upoly(tau, phi, R);
1161 u = u + umodpoly_to_upoly(tau) * modulus;
1162 w = w + umodpoly_to_upoly(sigma) * modulus;
1164 modulus = modulus * p;
1170 for ( size_t i=1; i<u.size(); ++i ) {
1172 if ( g == 1 ) break;
1187 static unsigned int next_prime(unsigned int p)
1189 static vector<unsigned int> primes;
1190 if ( primes.size() == 0 ) {
1191 primes.push_back(3); primes.push_back(5); primes.push_back(7);
1193 vector<unsigned int>::const_iterator it = primes.begin();
1194 if ( p >= primes.back() ) {
1195 unsigned int candidate = primes.back() + 2;
1197 size_t n = primes.size()/2;
1198 for ( size_t i=0; i<n; ++i ) {
1199 if ( candidate % primes[i] ) continue;
1203 primes.push_back(candidate);
1204 if ( candidate > p ) break;
1208 vector<unsigned int>::const_iterator end = primes.end();
1209 for ( ; it!=end; ++it ) {
1214 throw logic_error("next_prime: should not reach this point!");
1217 class factor_partition
1220 factor_partition(const upvec& factors_) : factors(factors_)
1226 one.resize(1, factors.front()[0].ring()->one());
1231 int operator[](size_t i) const { return k[i]; }
1232 size_t size() const { return n; }
1233 size_t size_left() const { return n-len; }
1234 size_t size_right() const { return len; }
1236 void get() const { DCOUTVAR(k); }
1240 if ( last == n-1 ) {
1250 while ( k[last] == 0 ) { --last; }
1251 if ( last == 0 && n == 2*len ) return false;
1253 for ( size_t i=0; i<=len-rem; ++i ) {
1257 fill(k.begin()+last, k.end(), 0);
1264 if ( len > n/2 ) return false;
1265 fill(k.begin(), k.begin()+len, 1);
1266 fill(k.begin()+len+1, k.end(), 0);
1275 umodpoly& left() { return lr[0]; }
1276 umodpoly& right() { return lr[1]; }
1285 while ( i < n && k[i] == group ) { ++d; ++i; }
1287 if ( cache[pos].size() >= d ) {
1288 lr[group] = lr[group] * cache[pos][d-1];
1291 if ( cache[pos].size() == 0 ) {
1292 cache[pos].push_back(factors[pos] * factors[pos+1]);
1294 size_t j = pos + cache[pos].size() + 1;
1295 d -= cache[pos].size();
1297 umodpoly buf = cache[pos].back() * factors[j];
1298 cache[pos].push_back(buf);
1302 lr[group] = lr[group] * cache[pos].back();
1306 lr[group] = lr[group] * factors[pos];
1318 for ( size_t i=0; i<n; ++i ) {
1319 lr[k[i]] = lr[k[i]] * factors[i];
1325 vector< vector<umodpoly> > cache;
1340 static ex factor_univariate(const ex& poly, const ex& x)
1342 ex unit, cont, prim_ex;
1343 poly.unitcontprim(x, unit, cont, prim_ex);
1345 upoly_from_ex(prim, prim_ex, x);
1347 // determine proper prime and minimize number of modular factors
1348 unsigned int p = 3, lastp = 3;
1350 unsigned int trials = 0;
1351 unsigned int minfactors = 0;
1352 cl_I lc = lcoeff(prim);
1354 while ( trials < 2 ) {
1358 if ( !zerop(rem(lc, p)) ) {
1359 R = find_modint_ring(p);
1360 umodpoly_from_upoly(modpoly, prim, R);
1361 if ( squarefree(modpoly) ) break;
1365 // do modular factorization
1367 factor_modular(modpoly, trialfactors);
1368 if ( trialfactors.size() <= 1 ) {
1369 // irreducible for sure
1373 if ( minfactors == 0 || trialfactors.size() < minfactors ) {
1374 factors = trialfactors;
1375 minfactors = trialfactors.size();
1384 R = find_modint_ring(p);
1386 // lift all factor combinations
1387 stack<ModFactors> tocheck;
1390 mf.factors = factors;
1394 while ( tocheck.size() ) {
1395 const size_t n = tocheck.top().factors.size();
1396 factor_partition part(tocheck.top().factors);
1398 hensel_univar(tocheck.top().poly, p, part.left(), part.right(), f1, f2);
1399 if ( !f1.empty() ) {
1400 if ( part.size_left() == 1 ) {
1401 if ( part.size_right() == 1 ) {
1402 result *= upoly_to_ex(f1, x) * upoly_to_ex(f2, x);
1406 result *= upoly_to_ex(f1, x);
1407 tocheck.top().poly = f2;
1408 for ( size_t i=0; i<n; ++i ) {
1409 if ( part[i] == 0 ) {
1410 tocheck.top().factors.erase(tocheck.top().factors.begin()+i);
1416 else if ( part.size_right() == 1 ) {
1417 if ( part.size_left() == 1 ) {
1418 result *= upoly_to_ex(f1, x) * upoly_to_ex(f2, x);
1422 result *= upoly_to_ex(f2, x);
1423 tocheck.top().poly = f1;
1424 for ( size_t i=0; i<n; ++i ) {
1425 if ( part[i] == 1 ) {
1426 tocheck.top().factors.erase(tocheck.top().factors.begin()+i);
1433 upvec newfactors1(part.size_left()), newfactors2(part.size_right());
1434 upvec::iterator i1 = newfactors1.begin(), i2 = newfactors2.begin();
1435 for ( size_t i=0; i<n; ++i ) {
1437 *i2++ = tocheck.top().factors[i];
1440 *i1++ = tocheck.top().factors[i];
1443 tocheck.top().factors = newfactors1;
1444 tocheck.top().poly = f1;
1446 mf.factors = newfactors2;
1453 if ( !part.next() ) {
1454 result *= upoly_to_ex(tocheck.top().poly, x);
1462 return unit * cont * result;
1471 // forward declaration
1472 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 upvec multiterm_eea_lift(const upvec& a, const ex& x, unsigned int p, unsigned int k)
1476 const size_t r = a.size();
1477 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1480 for ( size_t j=r-2; j>=1; --j ) {
1481 q[j-1] = a[j] * q[j];
1483 umodpoly beta(1, R->one());
1485 for ( size_t j=1; j<r; ++j ) {
1486 vector<ex> mdarg(2);
1487 mdarg[0] = umodpoly_to_ex(q[j-1], x);
1488 mdarg[1] = umodpoly_to_ex(a[j-1], x);
1489 vector<EvalPoint> empty;
1490 vector<ex> exsigma = multivar_diophant(mdarg, x, umodpoly_to_ex(beta, x), empty, 0, p, k);
1492 umodpoly_from_ex(sigma1, exsigma[0], x, R);
1494 umodpoly_from_ex(sigma2, exsigma[1], x, R);
1496 s.push_back(sigma2);
1503 * Assert: a not empty.
1505 void change_modulus(const cl_modint_ring& R, umodpoly& a)
1507 if ( a.empty() ) return;
1508 cl_modint_ring oldR = a[0].ring();
1509 umodpoly::iterator i = a.begin(), end = a.end();
1510 for ( ; i!=end; ++i ) {
1511 *i = R->canonhom(oldR->retract(*i));
1516 void eea_lift(const umodpoly& a, const umodpoly& b, const ex& x, unsigned int p, unsigned int k, umodpoly& s_, umodpoly& t_)
1518 cl_modint_ring R = find_modint_ring(p);
1520 change_modulus(R, amod);
1522 change_modulus(R, bmod);
1526 exteuclid(amod, bmod, smod, tmod);
1528 cl_modint_ring Rpk = find_modint_ring(expt_pos(cl_I(p),k));
1530 change_modulus(Rpk, s);
1532 change_modulus(Rpk, t);
1535 umodpoly one(1, Rpk->one());
1536 for ( size_t j=1; j<k; ++j ) {
1537 umodpoly e = one - a * s - b * t;
1538 reduce_coeff(e, modulus);
1540 change_modulus(R, c);
1541 umodpoly sigmabar = smod * c;
1542 umodpoly taubar = tmod * c;
1544 remdiv(sigmabar, bmod, sigma, q);
1545 umodpoly tau = taubar + q * amod;
1546 umodpoly sadd = sigma;
1547 change_modulus(Rpk, sadd);
1548 cl_MI modmodulus(Rpk, modulus);
1549 s = s + sadd * modmodulus;
1550 umodpoly tadd = tau;
1551 change_modulus(Rpk, tadd);
1552 t = t + tadd * modmodulus;
1553 modulus = modulus * p;
1559 upvec univar_diophant(const upvec& a, const ex& x, unsigned int m, unsigned int p, unsigned int k)
1561 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1563 const size_t r = a.size();
1566 upvec s = multiterm_eea_lift(a, x, p, k);
1567 for ( size_t j=0; j<r; ++j ) {
1568 umodpoly bmod = umodpoly_to_umodpoly(s[j], R, m);
1570 rem(bmod, a[j], buf);
1571 result.push_back(buf);
1576 eea_lift(a[1], a[0], x, p, k, s, t);
1577 umodpoly bmod = umodpoly_to_umodpoly(s, R, m);
1579 remdiv(bmod, a[0], buf, q);
1580 result.push_back(buf);
1581 umodpoly t1mod = umodpoly_to_umodpoly(t, R, m);
1582 buf = t1mod + q * a[1];
1583 result.push_back(buf);
1589 struct make_modular_map : public map_function {
1591 make_modular_map(const cl_modint_ring& R_) : R(R_) { }
1592 ex operator()(const ex& e)
1594 if ( is_a<add>(e) || is_a<mul>(e) ) {
1595 return e.map(*this);
1597 else if ( is_a<numeric>(e) ) {
1598 numeric mod(R->modulus);
1599 numeric halfmod = (mod-1)/2;
1600 cl_MI emod = R->canonhom(the<cl_I>(ex_to<numeric>(e).to_cl_N()));
1601 numeric n(R->retract(emod));
1602 if ( n > halfmod ) {
1613 static ex make_modular(const ex& e, const cl_modint_ring& R)
1615 make_modular_map map(R);
1616 return map(e.expand());
1619 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)
1623 const cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1624 const size_t r = a.size();
1625 const size_t nu = I.size() + 1;
1629 ex xnu = I.back().x;
1630 int alphanu = I.back().evalpoint;
1633 for ( size_t i=0; i<r; ++i ) {
1637 for ( size_t i=0; i<r; ++i ) {
1638 b[i] = normal(A / a[i]);
1641 vector<ex> anew = a;
1642 for ( size_t i=0; i<r; ++i ) {
1643 anew[i] = anew[i].subs(xnu == alphanu);
1645 ex cnew = c.subs(xnu == alphanu);
1646 vector<EvalPoint> Inew = I;
1648 sigma = multivar_diophant(anew, x, cnew, Inew, d, p, k);
1651 for ( size_t i=0; i<r; ++i ) {
1652 buf -= sigma[i] * b[i];
1654 ex e = make_modular(buf, R);
1657 for ( size_t m=1; !e.is_zero() && e.has(xnu) && m<=d; ++m ) {
1658 monomial *= (xnu - alphanu);
1659 monomial = expand(monomial);
1660 ex cm = e.diff(ex_to<symbol>(xnu), m).subs(xnu==alphanu) / factorial(m);
1661 cm = make_modular(cm, R);
1662 if ( !cm.is_zero() ) {
1663 vector<ex> delta_s = multivar_diophant(anew, x, cm, Inew, d, p, k);
1665 for ( size_t j=0; j<delta_s.size(); ++j ) {
1666 delta_s[j] *= monomial;
1667 sigma[j] += delta_s[j];
1668 buf -= delta_s[j] * b[j];
1670 e = make_modular(buf, R);
1676 for ( size_t i=0; i<a.size(); ++i ) {
1678 umodpoly_from_ex(up, a[i], x, R);
1682 sigma.insert(sigma.begin(), r, 0);
1685 if ( is_a<add>(c) ) {
1693 for ( size_t i=0; i<nterms; ++i ) {
1694 int m = z.degree(x);
1695 cl_I cm = the<cl_I>(ex_to<numeric>(z.lcoeff(x)).to_cl_N());
1696 upvec delta_s = univar_diophant(amod, x, m, p, k);
1699 while ( poscm < 0 ) {
1700 poscm = poscm + expt_pos(cl_I(p),k);
1702 modcm = cl_MI(R, poscm);
1703 for ( size_t j=0; j<delta_s.size(); ++j ) {
1704 delta_s[j] = delta_s[j] * modcm;
1705 sigma[j] = sigma[j] + umodpoly_to_ex(delta_s[j], x);
1713 for ( size_t i=0; i<sigma.size(); ++i ) {
1714 sigma[i] = make_modular(sigma[i], R);
1721 ostream& operator<<(ostream& o, const vector<EvalPoint>& v)
1723 for ( size_t i=0; i<v.size(); ++i ) {
1724 o << "(" << v[i].x << "==" << v[i].evalpoint << ") ";
1728 #endif // def DEBUGFACTOR
1730 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)
1732 const size_t nu = I.size() + 1;
1733 const cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),l));
1738 for ( size_t j=nu; j>=2; --j ) {
1740 int alpha = I[j-2].evalpoint;
1741 A[j-2] = A[j-1].subs(x==alpha);
1742 A[j-2] = make_modular(A[j-2], R);
1745 int maxdeg = a.degree(I.front().x);
1746 for ( size_t i=1; i<I.size(); ++i ) {
1747 int maxdeg2 = a.degree(I[i].x);
1748 if ( maxdeg2 > maxdeg ) maxdeg = maxdeg2;
1751 const size_t n = u.size();
1753 for ( size_t i=0; i<n; ++i ) {
1754 U[i] = umodpoly_to_ex(u[i], x);
1757 for ( size_t j=2; j<=nu; ++j ) {
1760 for ( size_t m=0; m<n; ++m) {
1761 if ( lcU[m] != 1 ) {
1763 for ( size_t i=j-1; i<nu-1; ++i ) {
1764 coef = coef.subs(I[i].x == I[i].evalpoint);
1766 coef = make_modular(coef, R);
1767 int deg = U[m].degree(x);
1768 U[m] = U[m] - U[m].lcoeff(x) * pow(x,deg) + coef * pow(x,deg);
1772 for ( size_t i=0; i<n; ++i ) {
1775 ex e = expand(A[j-1] - Uprod);
1777 vector<EvalPoint> newI;
1778 for ( size_t i=1; i<=j-2; ++i ) {
1779 newI.push_back(I[i-1]);
1783 int alphaj = I[j-2].evalpoint;
1784 size_t deg = A[j-1].degree(xj);
1785 for ( size_t k=1; k<=deg; ++k ) {
1786 if ( !e.is_zero() ) {
1787 monomial *= (xj - alphaj);
1788 monomial = expand(monomial);
1789 ex dif = e.diff(ex_to<symbol>(xj), k);
1790 ex c = dif.subs(xj==alphaj) / factorial(k);
1791 if ( !c.is_zero() ) {
1792 vector<ex> deltaU = multivar_diophant(U1, x, c, newI, maxdeg, p, cl_I_to_uint(l));
1793 for ( size_t i=0; i<n; ++i ) {
1794 deltaU[i] *= monomial;
1796 U[i] = make_modular(U[i], R);
1799 for ( size_t i=0; i<n; ++i ) {
1803 e = make_modular(e, R);
1810 for ( size_t i=0; i<U.size(); ++i ) {
1813 if ( expand(a-acand).is_zero() ) {
1815 for ( size_t i=0; i<U.size(); ++i ) {
1826 static ex put_factors_into_lst(const ex& e)
1830 if ( is_a<numeric>(e) ) {
1834 if ( is_a<power>(e) ) {
1836 result.append(e.op(0));
1837 result.append(e.op(1));
1840 if ( is_a<symbol>(e) || is_a<add>(e) ) {
1846 if ( is_a<mul>(e) ) {
1848 for ( size_t i=0; i<e.nops(); ++i ) {
1850 if ( is_a<numeric>(op) ) {
1853 if ( is_a<power>(op) ) {
1854 result.append(op.op(0));
1855 result.append(op.op(1));
1857 if ( is_a<symbol>(op) || is_a<add>(op) ) {
1862 result.prepend(nfac);
1865 throw runtime_error("put_factors_into_lst: bad term.");
1869 ostream& operator<<(ostream& o, const vector<numeric>& v)
1871 for ( size_t i=0; i<v.size(); ++i ) {
1876 #endif // def DEBUGFACTOR
1878 static bool checkdivisors(const lst& f, vector<numeric>& d)
1880 const int k = f.nops()-2;
1882 d[0] = ex_to<numeric>(f.op(0) * f.op(f.nops()-1));
1883 if ( d[0] == 1 && k == 1 && abs(f.op(1)) != 1 ) {
1886 for ( int i=1; i<=k; ++i ) {
1887 q = ex_to<numeric>(abs(f.op(i)));
1888 for ( int j=i-1; j>=0; --j ) {
1903 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)
1905 // computation of d is actually not necessary
1906 const ex& x = *syms.begin();
1912 exset::const_iterator s = syms.begin();
1914 for ( size_t i=0; i<a.size(); ++i ) {
1916 a[i] = mod(numeric(rand()), 2*modulus) - modulus;
1917 vnatry = vna.subs(*s == a[i]);
1918 } while ( vnatry == 0 );
1920 u0 = u0.subs(*s == a[i]);
1923 if ( gcd(u0,u0.diff(ex_to<symbol>(x))) != 1 ) {
1926 if ( is_a<numeric>(vn) ) {
1931 lst::const_iterator i = ex_to<lst>(f).begin();
1933 bool problem = false;
1934 while ( i!=ex_to<lst>(f).end() ) {
1936 if ( !is_a<numeric>(fs) ) {
1939 for ( size_t j=0; j<a.size(); ++j ) {
1940 fs = fs.subs(*s == a[j]);
1943 if ( abs(fs) == 1 ) {
1954 ex con = u0.content(x);
1956 trying = checkdivisors(fnum, d);
1962 static ex factor_multivariate(const ex& poly, const exset& syms)
1964 exset::const_iterator s;
1965 const ex& x = *syms.begin();
1967 /* make polynomial primitive */
1968 ex p = poly.expand().collect(x);
1969 ex cont = p.lcoeff(x);
1970 for ( numeric i=p.degree(x)-1; i>=p.ldegree(x); --i ) {
1971 cont = gcd(cont, p.coeff(x,ex_to<numeric>(i).to_int()));
1972 if ( cont == 1 ) break;
1974 ex pp = expand(normal(p / cont));
1975 if ( !is_a<numeric>(cont) ) {
1976 return factor(cont) * factor(pp);
1979 /* factor leading coefficient */
1981 ex vn = pp.lcoeff(x);
1984 if ( is_a<numeric>(vn) ) {
1988 ex vnfactors = factor(vn);
1989 vnlst = put_factors_into_lst(vnfactors);
1992 const numeric maxtrials = 3;
1993 numeric modulus = (vnlst.nops()-1 > 3) ? vnlst.nops()-1 : 3;
1994 numeric minimalr = -1;
1995 vector<numeric> a(syms.size()-1, 0);
1996 vector<numeric> d((vnlst.nops()-1)/2+1, 0);
1999 numeric trialcount = 0;
2001 unsigned int prime = 3;
2002 size_t factor_count = 0;
2005 while ( trialcount < maxtrials ) {
2006 bool problem = generate_set(pp, vn, syms, vnlst, modulus, a, d);
2014 for ( size_t i=0; i<a.size(); ++i ) {
2015 u = u.subs(*s == a[i]);
2018 delta = u.content(x);
2020 // determine proper prime
2022 cl_modint_ring R = find_modint_ring(prime);
2024 if ( irem(ex_to<numeric>(u.lcoeff(x)), prime) != 0 ) {
2026 umodpoly_from_ex(modpoly, u, x, R);
2027 if ( squarefree(modpoly) ) break;
2029 prime = next_prime(prime);
2030 R = find_modint_ring(prime);
2034 ufaclst = put_factors_into_lst(ufac);
2035 factor_count = (ufaclst.nops()-1)/2;
2037 // veto factorization for which gcd(u_i, u_j) != 1 for all i,j
2039 for ( size_t i=0; i<(ufaclst.nops()-1)/2; ++i ) {
2041 umodpoly_from_ex(newu, ufaclst.op(i*2+1), x, R);
2042 tryu.push_back(newu);
2045 for ( size_t i=0; i<tryu.size()-1; ++i ) {
2046 for ( size_t j=i+1; j<tryu.size(); ++j ) {
2048 gcd(tryu[i], tryu[j], tryg);
2049 if ( unequal_one(tryg) ) {
2051 goto escape_quickly;
2060 if ( factor_count <= 1 ) {
2064 if ( minimalr < 0 ) {
2065 minimalr = factor_count;
2067 else if ( minimalr == factor_count ) {
2071 else if ( minimalr > factor_count ) {
2072 minimalr = factor_count;
2075 if ( minimalr <= 1 ) {
2080 vector<numeric> ftilde((vnlst.nops()-1)/2+1);
2081 ftilde[0] = ex_to<numeric>(vnlst.op(0));
2082 for ( size_t i=1; i<ftilde.size(); ++i ) {
2083 ex ft = vnlst.op((i-1)*2+1);
2086 for ( size_t j=0; j<a.size(); ++j ) {
2087 ft = ft.subs(*s == a[j]);
2090 ftilde[i] = ex_to<numeric>(ft);
2093 vector<bool> used_flag((vnlst.nops()-1)/2+1, false);
2094 vector<ex> D(factor_count, 1);
2095 for ( size_t i=0; i<=factor_count; ++i ) {
2098 prefac = ex_to<numeric>(ufaclst.op(0));
2099 ftilde[0] = ftilde[0] / prefac;
2100 vnlst.let_op(0) = vnlst.op(0) / prefac;
2104 prefac = ex_to<numeric>(ufaclst.op(2*(i-1)+1).lcoeff(x));
2106 for ( size_t j=(vnlst.nops()-1)/2+1; j>0; --j ) {
2107 if ( abs(ftilde[j-1]) == 1 ) {
2108 used_flag[j-1] = true;
2111 numeric g = gcd(prefac, ftilde[j-1]);
2113 prefac = prefac / g;
2114 numeric count = abs(iquo(g, ftilde[j-1]));
2115 used_flag[j-1] = true;
2118 D[i-1] = D[i-1] * pow(vnlst.op(0), count);
2121 D[i-1] = D[i-1] * pow(vnlst.op(2*(j-2)+1), count);
2125 ftilde[j-1] = ftilde[j-1] / prefac;
2133 bool some_factor_unused = false;
2134 for ( size_t i=0; i<used_flag.size(); ++i ) {
2135 if ( !used_flag[i] ) {
2136 some_factor_unused = true;
2140 if ( some_factor_unused ) {
2144 vector<ex> C(factor_count);
2146 for ( size_t i=0; i<D.size(); ++i ) {
2150 for ( size_t j=0; j<a.size(); ++j ) {
2151 Dtilde = Dtilde.subs(*s == a[j]);
2154 C[i] = D[i] * (ufaclst.op(2*i+1).lcoeff(x) / Dtilde);
2158 for ( size_t i=0; i<D.size(); ++i ) {
2162 for ( size_t j=0; j<a.size(); ++j ) {
2163 Dtilde = Dtilde.subs(*s == a[j]);
2171 ui = ufaclst.op(2*(i-1)+1);
2174 ex d = gcd(ui.lcoeff(x), Dtilde);
2175 C[i] = D[i] * ( ui.lcoeff(x) / d );
2176 ui = ui * ( Dtilde[i] / d );
2177 delta = delta / ( Dtilde[i] / d );
2178 if ( delta == 1 ) break;
2180 C[i] = delta * C[i];
2181 pp = pp * pow(delta, D.size()-1);
2187 vector<EvalPoint> epv;
2190 for ( size_t i=0; i<a.size(); ++i ) {
2192 ep.evalpoint = a[i].to_int();
2198 for ( size_t i=0; i<factor_count; ++i ) {
2199 if ( ufaclst[2*i+1].degree(x) > maxdeg ) {
2200 maxdeg = ufaclst[2*i+1].degree(x);
2203 cl_I B = 2*calc_bound(u, x, maxdeg);
2212 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(prime),l));
2213 for ( size_t i=0; i<(ufaclst.nops()-1)/2; ++i ) {
2215 umodpoly_from_ex(newu, ufaclst.op(i*2+1), x, R);
2216 uvec.push_back(newu);
2219 ex res = hensel_multivar(ufaclst.op(0)*pp, x, epv, prime, l, uvec, C);
2220 if ( res != lst() ) {
2221 ex result = cont * ufaclst.op(0);
2222 for ( size_t i=0; i<res.nops(); ++i ) {
2223 result *= res.op(i).content(x) * res.op(i).unit(x);
2224 result *= res.op(i).primpart(x);
2231 struct find_symbols_map : public map_function {
2233 ex operator()(const ex& e)
2235 if ( is_a<symbol>(e) ) {
2239 return e.map(*this);
2243 static ex factor_sqrfree(const ex& poly)
2245 // determine all symbols in poly
2246 find_symbols_map findsymbols;
2248 if ( findsymbols.syms.size() == 0 ) {
2252 if ( findsymbols.syms.size() == 1 ) {
2254 const ex& x = *(findsymbols.syms.begin());
2255 if ( poly.ldegree(x) > 0 ) {
2256 int ld = poly.ldegree(x);
2257 ex res = factor_univariate(expand(poly/pow(x, ld)), x);
2258 return res * pow(x,ld);
2261 ex res = factor_univariate(poly, x);
2266 // multivariate case
2267 ex res = factor_multivariate(poly, findsymbols.syms);
2271 struct apply_factor_map : public map_function {
2273 apply_factor_map(unsigned options_) : options(options_) { }
2274 ex operator()(const ex& e)
2276 if ( e.info(info_flags::polynomial) ) {
2277 return factor(e, options);
2279 if ( is_a<add>(e) ) {
2281 for ( size_t i=0; i<e.nops(); ++i ) {
2282 if ( e.op(i).info(info_flags::polynomial) ) {
2291 return factor(s1, options) + s2.map(*this);
2293 return e.map(*this);
2297 } // anonymous namespace
2299 ex factor(const ex& poly, unsigned options)
2302 if ( !poly.info(info_flags::polynomial) ) {
2303 if ( options & factor_options::all ) {
2304 options &= ~factor_options::all;
2305 apply_factor_map factor_map(options);
2306 return factor_map(poly);
2311 // determine all symbols in poly
2312 find_symbols_map findsymbols;
2314 if ( findsymbols.syms.size() == 0 ) {
2318 exset::const_iterator i=findsymbols.syms.begin(), end=findsymbols.syms.end();
2319 for ( ; i!=end; ++i ) {
2323 // make poly square free
2324 ex sfpoly = sqrfree(poly, syms);
2326 // factorize the square free components
2327 if ( is_a<power>(sfpoly) ) {
2328 // case: (polynomial)^exponent
2329 const ex& base = sfpoly.op(0);
2330 if ( !is_a<add>(base) ) {
2331 // simple case: (monomial)^exponent
2334 ex f = factor_sqrfree(base);
2335 return pow(f, sfpoly.op(1));
2337 if ( is_a<mul>(sfpoly) ) {
2338 // case: multiple factors
2340 for ( size_t i=0; i<sfpoly.nops(); ++i ) {
2341 const ex& t = sfpoly.op(i);
2342 if ( is_a<power>(t) ) {
2343 const ex& base = t.op(0);
2344 if ( !is_a<add>(base) ) {
2348 ex f = factor_sqrfree(base);
2349 res *= pow(f, t.op(1));
2352 else if ( is_a<add>(t) ) {
2353 ex f = factor_sqrfree(t);
2362 if ( is_a<symbol>(sfpoly) ) {
2365 // case: (polynomial)
2366 ex f = factor_sqrfree(sfpoly);
2370 } // namespace GiNaC