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();
369 static void umodpoly_from_ex(umodpoly& ump, const ex& e, const ex& x, const cl_I& modulus)
371 umodpoly_from_ex(ump, e, x, find_modint_ring(modulus));
375 static ex upoly_to_ex(const upoly& a, const ex& x)
377 if ( a.empty() ) return 0;
379 for ( int i=degree(a); i>=0; --i ) {
380 e += numeric(a[i]) * pow(x, i);
385 static ex umodpoly_to_ex(const umodpoly& a, const ex& x)
387 if ( a.empty() ) return 0;
388 cl_modint_ring R = a[0].ring();
389 cl_I mod = R->modulus;
390 cl_I halfmod = (mod-1) >> 1;
392 for ( int i=degree(a); i>=0; --i ) {
393 cl_I n = R->retract(a[i]);
395 e += numeric(n-mod) * pow(x, i);
397 e += numeric(n) * pow(x, i);
403 static upoly umodpoly_to_upoly(const umodpoly& a)
406 if ( a.empty() ) return e;
407 cl_modint_ring R = a[0].ring();
408 cl_I mod = R->modulus;
409 cl_I halfmod = (mod-1) >> 1;
410 for ( int i=degree(a); i>=0; --i ) {
411 cl_I n = R->retract(a[i]);
421 static umodpoly umodpoly_to_umodpoly(const umodpoly& a, const cl_modint_ring& R, unsigned int m)
424 if ( a.empty() ) return e;
425 cl_modint_ring oldR = a[0].ring();
426 size_t sa = a.size();
427 e.resize(sa+m, R->zero());
428 for ( size_t i=0; i<sa; ++i ) {
429 e[i+m] = R->canonhom(oldR->retract(a[i]));
435 /** Divides all coefficients of the polynomial a by the integer x.
436 * All coefficients are supposed to be divisible by x. If they are not, the
437 * the<cl_I> cast will raise an exception.
439 * @param[in,out] a polynomial of which the coefficients will be reduced by x
440 * @param[in] x integer that divides the coefficients
442 static void reduce_coeff(umodpoly& a, const cl_I& x)
444 if ( a.empty() ) return;
446 cl_modint_ring R = a[0].ring();
447 umodpoly::iterator i = a.begin(), end = a.end();
448 for ( ; i!=end; ++i ) {
449 // cln cannot perform this division in the modular field
450 cl_I c = R->retract(*i);
451 *i = cl_MI(R, the<cl_I>(c / x));
455 /** Calculates remainder of a/b.
456 * Assertion: a and b not empty.
458 * @param[in] a polynomial dividend
459 * @param[in] b polynomial divisor
460 * @param[out] r polynomial remainder
462 static void rem(const umodpoly& a, const umodpoly& b, umodpoly& r)
471 cl_MI qk = div(r[n+k], b[n]);
473 for ( int i=0; i<n; ++i ) {
474 unsigned int j = n + k - 1 - i;
475 r[j] = r[j] - qk * b[j-k];
480 fill(r.begin()+n, r.end(), a[0].ring()->zero());
484 /** Calculates quotient of a/b.
485 * Assertion: a and b not empty.
487 * @param[in] a polynomial dividend
488 * @param[in] b polynomial divisor
489 * @param[out] q polynomial quotient
491 static void div(const umodpoly& a, const umodpoly& b, umodpoly& q)
500 q.resize(k+1, a[0].ring()->zero());
502 cl_MI qk = div(r[n+k], b[n]);
505 for ( int i=0; i<n; ++i ) {
506 unsigned int j = n + k - 1 - i;
507 r[j] = r[j] - qk * b[j-k];
515 /** Calculates quotient and remainder of a/b.
516 * Assertion: a and b not empty.
518 * @param[in] a polynomial dividend
519 * @param[in] b polynomial divisor
520 * @param[out] r polynomial remainder
521 * @param[out] q polynomial quotient
523 static void remdiv(const umodpoly& a, const umodpoly& b, umodpoly& r, umodpoly& q)
532 q.resize(k+1, a[0].ring()->zero());
534 cl_MI qk = div(r[n+k], b[n]);
537 for ( int i=0; i<n; ++i ) {
538 unsigned int j = n + k - 1 - i;
539 r[j] = r[j] - qk * b[j-k];
544 fill(r.begin()+n, r.end(), a[0].ring()->zero());
549 /** Calculates the GCD of polynomial a and b.
551 * @param[in] a polynomial
552 * @param[in] b polynomial
555 static void gcd(const umodpoly& a, const umodpoly& b, umodpoly& c)
557 if ( degree(a) < degree(b) ) return gcd(b, a, c);
560 normalize_in_field(c);
562 normalize_in_field(d);
564 while ( !d.empty() ) {
569 normalize_in_field(c);
572 /** Calculates the derivative of the polynomial a.
574 * @param[in] a polynomial of which to take the derivative
575 * @param[out] d result/derivative
577 static void deriv(const umodpoly& a, umodpoly& d)
580 if ( a.size() <= 1 ) return;
582 d.insert(d.begin(), a.begin()+1, a.end());
584 for ( int i=1; i<max; ++i ) {
590 static bool unequal_one(const umodpoly& a)
592 if ( a.empty() ) return true;
593 return ( a.size() != 1 || a[0] != a[0].ring()->one() );
596 static bool equal_one(const umodpoly& a)
598 return ( a.size() == 1 && a[0] == a[0].ring()->one() );
601 /** Returns true if polynomial a is square free.
603 * @param[in] a polynomial to check
604 * @return true if polynomial is square free, false otherwise
606 static bool squarefree(const umodpoly& a)
618 // END modular univariate polynomial code
619 ////////////////////////////////////////////////////////////////////////////////
621 ////////////////////////////////////////////////////////////////////////////////
626 friend ostream& operator<<(ostream& o, const modular_matrix& m);
628 modular_matrix(size_t r_, size_t c_, const cl_MI& init) : r(r_), c(c_)
632 size_t rowsize() const { return r; }
633 size_t colsize() const { return c; }
634 cl_MI& operator()(size_t row, size_t col) { return m[row*c + col]; }
635 cl_MI operator()(size_t row, size_t col) const { return m[row*c + col]; }
636 void mul_col(size_t col, const cl_MI x)
638 mvec::iterator i = m.begin() + col;
639 for ( size_t rc=0; rc<r; ++rc ) {
644 void sub_col(size_t col1, size_t col2, const cl_MI fac)
646 mvec::iterator i1 = m.begin() + col1;
647 mvec::iterator i2 = m.begin() + col2;
648 for ( size_t rc=0; rc<r; ++rc ) {
649 *i1 = *i1 - *i2 * fac;
654 void switch_col(size_t col1, size_t col2)
657 mvec::iterator i1 = m.begin() + col1;
658 mvec::iterator i2 = m.begin() + col2;
659 for ( size_t rc=0; rc<r; ++rc ) {
660 buf = *i1; *i1 = *i2; *i2 = buf;
665 void mul_row(size_t row, const cl_MI x)
667 vector<cl_MI>::iterator i = m.begin() + row*c;
668 for ( size_t cc=0; cc<c; ++cc ) {
673 void sub_row(size_t row1, size_t row2, const cl_MI fac)
675 vector<cl_MI>::iterator i1 = m.begin() + row1*c;
676 vector<cl_MI>::iterator i2 = m.begin() + row2*c;
677 for ( size_t cc=0; cc<c; ++cc ) {
678 *i1 = *i1 - *i2 * fac;
683 void switch_row(size_t row1, size_t row2)
686 vector<cl_MI>::iterator i1 = m.begin() + row1*c;
687 vector<cl_MI>::iterator i2 = m.begin() + row2*c;
688 for ( size_t cc=0; cc<c; ++cc ) {
689 buf = *i1; *i1 = *i2; *i2 = buf;
694 bool is_col_zero(size_t col) const
696 mvec::const_iterator i = m.begin() + col;
697 for ( size_t rr=0; rr<r; ++rr ) {
705 bool is_row_zero(size_t row) const
707 mvec::const_iterator i = m.begin() + row*c;
708 for ( size_t cc=0; cc<c; ++cc ) {
716 void set_row(size_t row, const vector<cl_MI>& newrow)
718 mvec::iterator i1 = m.begin() + row*c;
719 mvec::const_iterator i2 = newrow.begin(), end = newrow.end();
720 for ( ; i2 != end; ++i1, ++i2 ) {
724 mvec::const_iterator row_begin(size_t row) const { return m.begin()+row*c; }
725 mvec::const_iterator row_end(size_t row) const { return m.begin()+row*c+r; }
732 modular_matrix operator*(const modular_matrix& m1, const modular_matrix& m2)
734 const unsigned int r = m1.rowsize();
735 const unsigned int c = m2.colsize();
736 modular_matrix o(r,c,m1(0,0));
738 for ( size_t i=0; i<r; ++i ) {
739 for ( size_t j=0; j<c; ++j ) {
741 buf = m1(i,0) * m2(0,j);
742 for ( size_t k=1; k<c; ++k ) {
743 buf = buf + m1(i,k)*m2(k,j);
751 ostream& operator<<(ostream& o, const modular_matrix& m)
753 cl_modint_ring R = m(0,0).ring();
755 for ( size_t i=0; i<m.rowsize(); ++i ) {
757 for ( size_t j=0; j<m.colsize()-1; ++j ) {
758 o << R->retract(m(i,j)) << ",";
760 o << R->retract(m(i,m.colsize()-1)) << "}";
761 if ( i != m.rowsize()-1 ) {
768 #endif // def DEBUGFACTOR
770 // END modular matrix
771 ////////////////////////////////////////////////////////////////////////////////
773 static void q_matrix(const umodpoly& a_, modular_matrix& Q)
776 normalize_in_field(a);
779 unsigned int q = cl_I_to_uint(a[0].ring()->modulus);
780 umodpoly r(n, a[0].ring()->zero());
781 r[0] = a[0].ring()->one();
783 unsigned int max = (n-1) * q;
784 for ( size_t m=1; m<=max; ++m ) {
785 cl_MI rn_1 = r.back();
786 for ( size_t i=n-1; i>0; --i ) {
787 r[i] = r[i-1] - (rn_1 * a[i]);
790 if ( (m % q) == 0 ) {
796 static void nullspace(modular_matrix& M, vector<mvec>& basis)
798 const size_t n = M.rowsize();
799 const cl_MI one = M(0,0).ring()->one();
800 for ( size_t i=0; i<n; ++i ) {
801 M(i,i) = M(i,i) - one;
803 for ( size_t r=0; r<n; ++r ) {
805 for ( ; cc<n; ++cc ) {
806 if ( !zerop(M(r,cc)) ) {
808 if ( !zerop(M(cc,cc)) ) {
820 M.mul_col(r, recip(M(r,r)));
821 for ( cc=0; cc<n; ++cc ) {
823 M.sub_col(cc, r, M(r,cc));
829 for ( size_t i=0; i<n; ++i ) {
830 M(i,i) = M(i,i) - one;
832 for ( size_t i=0; i<n; ++i ) {
833 if ( !M.is_row_zero(i) ) {
834 mvec nu(M.row_begin(i), M.row_end(i));
840 static void berlekamp(const umodpoly& a, upvec& upv)
842 cl_modint_ring R = a[0].ring();
843 umodpoly one(1, R->one());
845 modular_matrix Q(degree(a), degree(a), R->zero());
850 const unsigned int k = nu.size();
855 list<umodpoly> factors;
856 factors.push_back(a);
857 unsigned int size = 1;
859 unsigned int q = cl_I_to_uint(R->modulus);
861 list<umodpoly>::iterator u = factors.begin();
864 for ( unsigned int s=0; s<q; ++s ) {
865 umodpoly nur = nu[r];
866 nur[0] = nur[0] - cl_MI(R, s);
870 if ( unequal_one(g) && g != *u ) {
873 if ( equal_one(uo) ) {
874 throw logic_error("berlekamp: unexpected divisor.");
879 factors.push_back(g);
881 list<umodpoly>::const_iterator i = factors.begin(), end = factors.end();
883 if ( degree(*i) ) ++size;
887 list<umodpoly>::const_iterator i = factors.begin(), end = factors.end();
902 static void expt_1_over_p(const umodpoly& a, unsigned int prime, umodpoly& ap)
904 size_t newdeg = degree(a)/prime;
907 for ( size_t i=1; i<=newdeg; ++i ) {
912 static void modsqrfree(const umodpoly& a, upvec& factors, vector<int>& mult)
914 const unsigned int prime = cl_I_to_uint(a[0].ring()->modulus);
923 while ( unequal_one(w) ) {
928 factors.push_back(z);
936 if ( unequal_one(c) ) {
938 expt_1_over_p(c, prime, cp);
939 size_t previ = mult.size();
940 modsqrfree(cp, factors, mult);
941 for ( size_t i=previ; i<mult.size(); ++i ) {
948 expt_1_over_p(a, prime, ap);
949 size_t previ = mult.size();
950 modsqrfree(ap, factors, mult);
951 for ( size_t i=previ; i<mult.size(); ++i ) {
957 static void distinct_degree_factor(const umodpoly& a_, vector<int>& degrees, upvec& ddfactors)
961 cl_modint_ring R = a[0].ring();
962 int q = cl_I_to_int(R->modulus);
963 int nhalf = degree(a)/2;
971 while ( i <= nhalf ) {
978 if ( unequal_one(buf) ) {
979 degrees.push_back(i);
980 ddfactors.push_back(buf);
982 if ( unequal_one(buf) ) {
992 if ( unequal_one(a) ) {
993 degrees.push_back(degree(a));
994 ddfactors.push_back(a);
998 static void same_degree_factor(const umodpoly& a, upvec& upv)
1000 cl_modint_ring R = a[0].ring();
1002 vector<int> degrees;
1004 distinct_degree_factor(a, degrees, ddfactors);
1006 for ( size_t i=0; i<degrees.size(); ++i ) {
1007 if ( degrees[i] == degree(ddfactors[i]) ) {
1008 upv.push_back(ddfactors[i]);
1011 berlekamp(ddfactors[i], upv);
1016 #define USE_SAME_DEGREE_FACTOR
1018 static void factor_modular(const umodpoly& p, upvec& upv)
1020 #ifdef USE_SAME_DEGREE_FACTOR
1021 same_degree_factor(p, upv);
1027 /** Calculates polynomials s and t such that a*s+b*t==1.
1028 * Assertion: a and b are relatively prime and not zero.
1030 * @param[in] a polynomial
1031 * @param[in] b polynomial
1032 * @param[out] s polynomial
1033 * @param[out] t polynomial
1035 static void exteuclid(const umodpoly& a, const umodpoly& b, umodpoly& s, umodpoly& t)
1037 if ( degree(a) < degree(b) ) {
1038 exteuclid(b, a, t, s);
1042 umodpoly one(1, a[0].ring()->one());
1043 umodpoly c = a; normalize_in_field(c);
1044 umodpoly d = b; normalize_in_field(d);
1052 umodpoly r = c - q * d;
1053 umodpoly r1 = s - q * d1;
1054 umodpoly r2 = t - q * d2;
1058 if ( r.empty() ) break;
1063 cl_MI fac = recip(lcoeff(a) * lcoeff(c));
1064 umodpoly::iterator i = s.begin(), end = s.end();
1065 for ( ; i!=end; ++i ) {
1069 fac = recip(lcoeff(b) * lcoeff(c));
1070 i = t.begin(), end = t.end();
1071 for ( ; i!=end; ++i ) {
1077 static upoly replace_lc(const upoly& poly, const cl_I& lc)
1079 if ( poly.empty() ) return poly;
1085 static inline cl_I calc_bound(const ex& a, const ex& x, int maxdeg)
1089 for ( int i=a.degree(x); i>=a.ldegree(x); --i ) {
1090 cl_I aa = abs(the<cl_I>(ex_to<numeric>(a.coeff(x, i)).to_cl_N()));
1091 if ( aa > maxcoeff ) maxcoeff = aa;
1092 coeff = coeff + square(aa);
1094 cl_I coeffnorm = ceiling1(the<cl_R>(cln::sqrt(coeff)));
1095 cl_I B = coeffnorm * expt_pos(cl_I(2), cl_I(maxdeg));
1096 return ( B > maxcoeff ) ? B : maxcoeff;
1099 static inline cl_I calc_bound(const upoly& a, int maxdeg)
1103 for ( int i=degree(a); i>=0; --i ) {
1104 cl_I aa = abs(a[i]);
1105 if ( aa > maxcoeff ) maxcoeff = aa;
1106 coeff = coeff + square(aa);
1108 cl_I coeffnorm = ceiling1(the<cl_R>(cln::sqrt(coeff)));
1109 cl_I B = coeffnorm * expt_pos(cl_I(2), cl_I(maxdeg));
1110 return ( B > maxcoeff ) ? B : maxcoeff;
1113 static void hensel_univar(const upoly& a_, unsigned int p, const umodpoly& u1_, const umodpoly& w1_, upoly& u, upoly& w)
1116 const cl_modint_ring& R = u1_[0].ring();
1119 int maxdeg = (degree(u1_) > degree(w1_)) ? degree(u1_) : degree(w1_);
1120 cl_I maxmodulus = 2*calc_bound(a, maxdeg);
1123 cl_I alpha = lcoeff(a);
1126 normalize_in_field(nu1);
1128 normalize_in_field(nw1);
1130 phi = umodpoly_to_upoly(nu1) * alpha;
1132 umodpoly_from_upoly(u1, phi, R);
1133 phi = umodpoly_to_upoly(nw1) * alpha;
1135 umodpoly_from_upoly(w1, phi, R);
1140 exteuclid(u1, w1, s, t);
1143 u = replace_lc(umodpoly_to_upoly(u1), alpha);
1144 w = replace_lc(umodpoly_to_upoly(w1), alpha);
1145 upoly e = a - u * w;
1149 while ( !e.empty() && modulus < maxmodulus ) {
1150 upoly c = e / modulus;
1151 phi = umodpoly_to_upoly(s) * c;
1152 umodpoly sigmatilde;
1153 umodpoly_from_upoly(sigmatilde, phi, R);
1154 phi = umodpoly_to_upoly(t) * c;
1156 umodpoly_from_upoly(tautilde, phi, R);
1158 remdiv(sigmatilde, w1, r, q);
1160 phi = umodpoly_to_upoly(tautilde) + umodpoly_to_upoly(q) * umodpoly_to_upoly(u1);
1162 umodpoly_from_upoly(tau, phi, R);
1163 u = u + umodpoly_to_upoly(tau) * modulus;
1164 w = w + umodpoly_to_upoly(sigma) * modulus;
1166 modulus = modulus * p;
1172 for ( size_t i=1; i<u.size(); ++i ) {
1174 if ( g == 1 ) break;
1189 static unsigned int next_prime(unsigned int p)
1191 static vector<unsigned int> primes;
1192 if ( primes.size() == 0 ) {
1193 primes.push_back(3); primes.push_back(5); primes.push_back(7);
1195 vector<unsigned int>::const_iterator it = primes.begin();
1196 if ( p >= primes.back() ) {
1197 unsigned int candidate = primes.back() + 2;
1199 size_t n = primes.size()/2;
1200 for ( size_t i=0; i<n; ++i ) {
1201 if ( candidate % primes[i] ) continue;
1205 primes.push_back(candidate);
1206 if ( candidate > p ) break;
1210 vector<unsigned int>::const_iterator end = primes.end();
1211 for ( ; it!=end; ++it ) {
1216 throw logic_error("next_prime: should not reach this point!");
1219 class factor_partition
1222 factor_partition(const upvec& factors_) : factors(factors_)
1228 one.resize(1, factors.front()[0].ring()->one());
1233 int operator[](size_t i) const { return k[i]; }
1234 size_t size() const { return n; }
1235 size_t size_left() const { return n-len; }
1236 size_t size_right() const { return len; }
1238 void get() const { DCOUTVAR(k); }
1242 if ( last == n-1 ) {
1252 while ( k[last] == 0 ) { --last; }
1253 if ( last == 0 && n == 2*len ) return false;
1255 for ( size_t i=0; i<=len-rem; ++i ) {
1259 fill(k.begin()+last, k.end(), 0);
1266 if ( len > n/2 ) return false;
1267 fill(k.begin(), k.begin()+len, 1);
1268 fill(k.begin()+len+1, k.end(), 0);
1277 umodpoly& left() { return lr[0]; }
1278 umodpoly& right() { return lr[1]; }
1287 while ( i < n && k[i] == group ) { ++d; ++i; }
1289 if ( cache[pos].size() >= d ) {
1290 lr[group] = lr[group] * cache[pos][d-1];
1293 if ( cache[pos].size() == 0 ) {
1294 cache[pos].push_back(factors[pos] * factors[pos+1]);
1296 size_t j = pos + cache[pos].size() + 1;
1297 d -= cache[pos].size();
1299 umodpoly buf = cache[pos].back() * factors[j];
1300 cache[pos].push_back(buf);
1304 lr[group] = lr[group] * cache[pos].back();
1308 lr[group] = lr[group] * factors[pos];
1320 for ( size_t i=0; i<n; ++i ) {
1321 lr[k[i]] = lr[k[i]] * factors[i];
1327 vector< vector<umodpoly> > cache;
1342 static ex factor_univariate(const ex& poly, const ex& x, unsigned int& prime)
1344 ex unit, cont, prim_ex;
1345 poly.unitcontprim(x, unit, cont, prim_ex);
1347 upoly_from_ex(prim, prim_ex, x);
1349 // determine proper prime and minimize number of modular factors
1351 unsigned int lastp = prime;
1353 unsigned int trials = 0;
1354 unsigned int minfactors = 0;
1355 cl_I lc = lcoeff(prim) * the<cl_I>(ex_to<numeric>(cont).to_cl_N());
1357 while ( trials < 2 ) {
1360 prime = next_prime(prime);
1361 if ( !zerop(rem(lc, prime)) ) {
1362 R = find_modint_ring(prime);
1363 umodpoly_from_upoly(modpoly, prim, R);
1364 if ( squarefree(modpoly) ) break;
1368 // do modular factorization
1370 factor_modular(modpoly, trialfactors);
1371 if ( trialfactors.size() <= 1 ) {
1372 // irreducible for sure
1376 if ( minfactors == 0 || trialfactors.size() < minfactors ) {
1377 factors = trialfactors;
1378 minfactors = trialfactors.size();
1387 R = find_modint_ring(prime);
1389 // lift all factor combinations
1390 stack<ModFactors> tocheck;
1393 mf.factors = factors;
1397 while ( tocheck.size() ) {
1398 const size_t n = tocheck.top().factors.size();
1399 factor_partition part(tocheck.top().factors);
1401 hensel_univar(tocheck.top().poly, prime, part.left(), part.right(), f1, f2);
1402 if ( !f1.empty() ) {
1403 if ( part.size_left() == 1 ) {
1404 if ( part.size_right() == 1 ) {
1405 result *= upoly_to_ex(f1, x) * upoly_to_ex(f2, x);
1409 result *= upoly_to_ex(f1, x);
1410 tocheck.top().poly = f2;
1411 for ( size_t i=0; i<n; ++i ) {
1412 if ( part[i] == 0 ) {
1413 tocheck.top().factors.erase(tocheck.top().factors.begin()+i);
1419 else if ( part.size_right() == 1 ) {
1420 if ( part.size_left() == 1 ) {
1421 result *= upoly_to_ex(f1, x) * upoly_to_ex(f2, x);
1425 result *= upoly_to_ex(f2, x);
1426 tocheck.top().poly = f1;
1427 for ( size_t i=0; i<n; ++i ) {
1428 if ( part[i] == 1 ) {
1429 tocheck.top().factors.erase(tocheck.top().factors.begin()+i);
1436 upvec newfactors1(part.size_left()), newfactors2(part.size_right());
1437 upvec::iterator i1 = newfactors1.begin(), i2 = newfactors2.begin();
1438 for ( size_t i=0; i<n; ++i ) {
1440 *i2++ = tocheck.top().factors[i];
1443 *i1++ = tocheck.top().factors[i];
1446 tocheck.top().factors = newfactors1;
1447 tocheck.top().poly = f1;
1449 mf.factors = newfactors2;
1456 if ( !part.next() ) {
1457 result *= upoly_to_ex(tocheck.top().poly, x);
1465 return unit * cont * result;
1468 static inline ex factor_univariate(const ex& poly, const ex& x)
1471 return factor_univariate(poly, x, prime);
1480 // forward declaration
1481 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);
1483 static upvec multiterm_eea_lift(const upvec& a, const ex& x, unsigned int p, unsigned int k)
1485 const size_t r = a.size();
1486 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1489 for ( size_t j=r-2; j>=1; --j ) {
1490 q[j-1] = a[j] * q[j];
1492 umodpoly beta(1, R->one());
1494 for ( size_t j=1; j<r; ++j ) {
1495 vector<ex> mdarg(2);
1496 mdarg[0] = umodpoly_to_ex(q[j-1], x);
1497 mdarg[1] = umodpoly_to_ex(a[j-1], x);
1498 vector<EvalPoint> empty;
1499 vector<ex> exsigma = multivar_diophant(mdarg, x, umodpoly_to_ex(beta, x), empty, 0, p, k);
1501 umodpoly_from_ex(sigma1, exsigma[0], x, R);
1503 umodpoly_from_ex(sigma2, exsigma[1], x, R);
1505 s.push_back(sigma2);
1512 * Assert: a not empty.
1514 static void change_modulus(const cl_modint_ring& R, umodpoly& a)
1516 if ( a.empty() ) return;
1517 cl_modint_ring oldR = a[0].ring();
1518 umodpoly::iterator i = a.begin(), end = a.end();
1519 for ( ; i!=end; ++i ) {
1520 *i = R->canonhom(oldR->retract(*i));
1525 static void eea_lift(const umodpoly& a, const umodpoly& b, const ex& x, unsigned int p, unsigned int k, umodpoly& s_, umodpoly& t_)
1527 cl_modint_ring R = find_modint_ring(p);
1529 change_modulus(R, amod);
1531 change_modulus(R, bmod);
1535 exteuclid(amod, bmod, smod, tmod);
1537 cl_modint_ring Rpk = find_modint_ring(expt_pos(cl_I(p),k));
1539 change_modulus(Rpk, s);
1541 change_modulus(Rpk, t);
1544 umodpoly one(1, Rpk->one());
1545 for ( size_t j=1; j<k; ++j ) {
1546 umodpoly e = one - a * s - b * t;
1547 reduce_coeff(e, modulus);
1549 change_modulus(R, c);
1550 umodpoly sigmabar = smod * c;
1551 umodpoly taubar = tmod * c;
1553 remdiv(sigmabar, bmod, sigma, q);
1554 umodpoly tau = taubar + q * amod;
1555 umodpoly sadd = sigma;
1556 change_modulus(Rpk, sadd);
1557 cl_MI modmodulus(Rpk, modulus);
1558 s = s + sadd * modmodulus;
1559 umodpoly tadd = tau;
1560 change_modulus(Rpk, tadd);
1561 t = t + tadd * modmodulus;
1562 modulus = modulus * p;
1568 static upvec univar_diophant(const upvec& a, const ex& x, unsigned int m, unsigned int p, unsigned int k)
1570 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1572 const size_t r = a.size();
1575 upvec s = multiterm_eea_lift(a, x, p, k);
1576 for ( size_t j=0; j<r; ++j ) {
1577 umodpoly bmod = umodpoly_to_umodpoly(s[j], R, m);
1579 rem(bmod, a[j], buf);
1580 result.push_back(buf);
1585 eea_lift(a[1], a[0], x, p, k, s, t);
1586 umodpoly bmod = umodpoly_to_umodpoly(s, R, m);
1588 remdiv(bmod, a[0], buf, q);
1589 result.push_back(buf);
1590 umodpoly t1mod = umodpoly_to_umodpoly(t, R, m);
1591 buf = t1mod + q * a[1];
1592 result.push_back(buf);
1598 struct make_modular_map : public map_function {
1600 make_modular_map(const cl_modint_ring& R_) : R(R_) { }
1601 ex operator()(const ex& e)
1603 if ( is_a<add>(e) || is_a<mul>(e) ) {
1604 return e.map(*this);
1606 else if ( is_a<numeric>(e) ) {
1607 numeric mod(R->modulus);
1608 numeric halfmod = (mod-1)/2;
1609 cl_MI emod = R->canonhom(the<cl_I>(ex_to<numeric>(e).to_cl_N()));
1610 numeric n(R->retract(emod));
1611 if ( n > halfmod ) {
1622 static ex make_modular(const ex& e, const cl_modint_ring& R)
1624 make_modular_map map(R);
1625 return map(e.expand());
1628 static vector<ex> multivar_diophant(const vector<ex>& a_, const ex& x, const ex& c, const vector<EvalPoint>& I,
1629 unsigned int d, unsigned int p, unsigned int k)
1633 const cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1634 const size_t r = a.size();
1635 const size_t nu = I.size() + 1;
1639 ex xnu = I.back().x;
1640 int alphanu = I.back().evalpoint;
1643 for ( size_t i=0; i<r; ++i ) {
1647 for ( size_t i=0; i<r; ++i ) {
1648 b[i] = normal(A / a[i]);
1651 vector<ex> anew = a;
1652 for ( size_t i=0; i<r; ++i ) {
1653 anew[i] = anew[i].subs(xnu == alphanu);
1655 ex cnew = c.subs(xnu == alphanu);
1656 vector<EvalPoint> Inew = I;
1658 sigma = multivar_diophant(anew, x, cnew, Inew, d, p, k);
1661 for ( size_t i=0; i<r; ++i ) {
1662 buf -= sigma[i] * b[i];
1664 ex e = make_modular(buf, R);
1667 for ( size_t m=1; !e.is_zero() && e.has(xnu) && m<=d; ++m ) {
1668 monomial *= (xnu - alphanu);
1669 monomial = expand(monomial);
1670 ex cm = e.diff(ex_to<symbol>(xnu), m).subs(xnu==alphanu) / factorial(m);
1671 cm = make_modular(cm, R);
1672 if ( !cm.is_zero() ) {
1673 vector<ex> delta_s = multivar_diophant(anew, x, cm, Inew, d, p, k);
1675 for ( size_t j=0; j<delta_s.size(); ++j ) {
1676 delta_s[j] *= monomial;
1677 sigma[j] += delta_s[j];
1678 buf -= delta_s[j] * b[j];
1680 e = make_modular(buf, R);
1686 for ( size_t i=0; i<a.size(); ++i ) {
1688 umodpoly_from_ex(up, a[i], x, R);
1692 sigma.insert(sigma.begin(), r, 0);
1695 if ( is_a<add>(c) ) {
1703 for ( size_t i=0; i<nterms; ++i ) {
1704 int m = z.degree(x);
1705 cl_I cm = the<cl_I>(ex_to<numeric>(z.lcoeff(x)).to_cl_N());
1706 upvec delta_s = univar_diophant(amod, x, m, p, k);
1709 while ( poscm < 0 ) {
1710 poscm = poscm + expt_pos(cl_I(p),k);
1712 modcm = cl_MI(R, poscm);
1713 for ( size_t j=0; j<delta_s.size(); ++j ) {
1714 delta_s[j] = delta_s[j] * modcm;
1715 sigma[j] = sigma[j] + umodpoly_to_ex(delta_s[j], x);
1723 for ( size_t i=0; i<sigma.size(); ++i ) {
1724 sigma[i] = make_modular(sigma[i], R);
1731 ostream& operator<<(ostream& o, const vector<EvalPoint>& v)
1733 for ( size_t i=0; i<v.size(); ++i ) {
1734 o << "(" << v[i].x << "==" << v[i].evalpoint << ") ";
1738 #endif // def DEBUGFACTOR
1740 static 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)
1742 const size_t nu = I.size() + 1;
1743 const cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),l));
1748 for ( size_t j=nu; j>=2; --j ) {
1750 int alpha = I[j-2].evalpoint;
1751 A[j-2] = A[j-1].subs(x==alpha);
1752 A[j-2] = make_modular(A[j-2], R);
1755 int maxdeg = a.degree(I.front().x);
1756 for ( size_t i=1; i<I.size(); ++i ) {
1757 int maxdeg2 = a.degree(I[i].x);
1758 if ( maxdeg2 > maxdeg ) maxdeg = maxdeg2;
1761 const size_t n = u.size();
1763 for ( size_t i=0; i<n; ++i ) {
1764 U[i] = umodpoly_to_ex(u[i], x);
1767 for ( size_t j=2; j<=nu; ++j ) {
1770 for ( size_t m=0; m<n; ++m) {
1771 if ( lcU[m] != 1 ) {
1773 for ( size_t i=j-1; i<nu-1; ++i ) {
1774 coef = coef.subs(I[i].x == I[i].evalpoint);
1776 coef = make_modular(coef, R);
1777 int deg = U[m].degree(x);
1778 U[m] = U[m] - U[m].lcoeff(x) * pow(x,deg) + coef * pow(x,deg);
1782 for ( size_t i=0; i<n; ++i ) {
1785 ex e = expand(A[j-1] - Uprod);
1787 vector<EvalPoint> newI;
1788 for ( size_t i=1; i<=j-2; ++i ) {
1789 newI.push_back(I[i-1]);
1793 int alphaj = I[j-2].evalpoint;
1794 size_t deg = A[j-1].degree(xj);
1795 for ( size_t k=1; k<=deg; ++k ) {
1796 if ( !e.is_zero() ) {
1797 monomial *= (xj - alphaj);
1798 monomial = expand(monomial);
1799 ex dif = e.diff(ex_to<symbol>(xj), k);
1800 ex c = dif.subs(xj==alphaj) / factorial(k);
1801 if ( !c.is_zero() ) {
1802 vector<ex> deltaU = multivar_diophant(U1, x, c, newI, maxdeg, p, cl_I_to_uint(l));
1803 for ( size_t i=0; i<n; ++i ) {
1804 deltaU[i] *= monomial;
1806 U[i] = make_modular(U[i], R);
1809 for ( size_t i=0; i<n; ++i ) {
1813 e = make_modular(e, R);
1820 for ( size_t i=0; i<U.size(); ++i ) {
1823 if ( expand(a-acand).is_zero() ) {
1825 for ( size_t i=0; i<U.size(); ++i ) {
1836 static ex put_factors_into_lst(const ex& e)
1840 if ( is_a<numeric>(e) ) {
1844 if ( is_a<power>(e) ) {
1846 result.append(e.op(0));
1849 if ( is_a<symbol>(e) || is_a<add>(e) ) {
1854 if ( is_a<mul>(e) ) {
1856 for ( size_t i=0; i<e.nops(); ++i ) {
1858 if ( is_a<numeric>(op) ) {
1861 if ( is_a<power>(op) ) {
1862 result.append(op.op(0));
1864 if ( is_a<symbol>(op) || is_a<add>(op) ) {
1868 result.prepend(nfac);
1871 throw runtime_error("put_factors_into_lst: bad term.");
1875 ostream& operator<<(ostream& o, const vector<numeric>& v)
1877 for ( size_t i=0; i<v.size(); ++i ) {
1882 #endif // def DEBUGFACTOR
1884 /** Checks whether in a set of numbers each has a unique prime factor.
1886 * @param[in] f list of numbers to check
1887 * @return true: if number set is bad, false: otherwise
1889 static bool checkdivisors(const lst& f)
1891 const int k = f.nops();
1893 vector<numeric> d(k);
1894 d[0] = ex_to<numeric>(abs(f.op(0)));
1895 for ( int i=1; i<k; ++i ) {
1896 q = ex_to<numeric>(abs(f.op(i)));
1897 for ( int j=i-1; j>=0; --j ) {
1912 /** Generates a set of evaluation points for a multivariate polynomial.
1913 * The set fulfills the following conditions:
1914 * 1. lcoeff(evaluated_polynomial) does not vanish
1915 * 2. factors of lcoeff(evaluated_polynomial) have each a unique prime factor
1916 * 3. evaluated_polynomial is square free
1917 * See [W1] for more details.
1919 * @param[in] u multivariate polynomial to be factored
1920 * @param[in] vn leading coefficient of u in x (x==first symbol in syms)
1921 * @param[in] syms set of symbols that appear in u
1922 * @param[in] f lst containing the factors of the leading coefficient vn
1923 * @param[in,out] modulus integer modulus for random number generation (i.e. |a_i| < modulus)
1924 * @param[out] u0 returns the evaluated (univariate) polynomial
1925 * @param[out] a returns the valid evaluation points. must have initial size equal
1926 * number of symbols-1 before calling generate_set
1928 static void generate_set(const ex& u, const ex& vn, const exset& syms, const lst& f,
1929 numeric& modulus, ex& u0, vector<numeric>& a)
1931 const ex& x = *syms.begin();
1934 /* generate a set of integers ... */
1938 exset::const_iterator s = syms.begin();
1940 for ( size_t i=0; i<a.size(); ++i ) {
1942 a[i] = mod(numeric(rand()), 2*modulus) - modulus;
1943 vnatry = vna.subs(*s == a[i]);
1944 /* ... for which the leading coefficient doesn't vanish ... */
1945 } while ( vnatry == 0 );
1947 u0 = u0.subs(*s == a[i]);
1950 /* ... for which u0 is square free ... */
1951 ex g = gcd(u0, u0.diff(ex_to<symbol>(x)));
1952 if ( !is_a<numeric>(g) ) {
1955 if ( !is_a<numeric>(vn) ) {
1956 /* ... and for which the evaluated factors have each an unique prime factor */
1958 fnum.let_op(0) = fnum.op(0) * u0.content(x);
1959 for ( size_t i=1; i<fnum.nops(); ++i ) {
1960 if ( !is_a<numeric>(fnum.op(i)) ) {
1963 for ( size_t j=0; j<a.size(); ++j, ++s ) {
1964 fnum.let_op(i) = fnum.op(i).subs(*s == a[j]);
1968 if ( checkdivisors(fnum) ) {
1972 /* ok, we have a valid set now */
1977 // forward declaration
1978 static ex factor_sqrfree(const ex& poly);
1981 * ASSERT: poly is expanded
1983 static ex factor_multivariate(const ex& poly, const exset& syms)
1985 exset::const_iterator s;
1986 const ex& x = *syms.begin();
1988 /* make polynomial primitive */
1989 ex p = poly.collect(x);
1990 ex cont = p.lcoeff(x);
1991 for ( int i=p.degree(x)-1; i>=p.ldegree(x); --i ) {
1992 cont = gcd(cont, p.coeff(x,i));
1993 if ( cont == 1 ) break;
1995 ex pp = expand(normal(p / cont));
1996 if ( !is_a<numeric>(cont) ) {
1997 return factor_sqrfree(cont) * factor_sqrfree(pp);
2000 /* factor leading coefficient */
2001 ex vn = pp.collect(x).lcoeff(x);
2003 if ( is_a<numeric>(vn) ) {
2007 ex vnfactors = factor(vn);
2008 vnlst = put_factors_into_lst(vnfactors);
2011 const unsigned int maxtrials = 3;
2012 numeric modulus = (vnlst.nops() > 3) ? vnlst.nops() : 3;
2013 vector<numeric> a(syms.size()-1, 0);
2015 /* try now to factorize until we are successful */
2018 unsigned int trialcount = 0;
2020 int factor_count = 0;
2021 int min_factor_count = -1;
2025 /* try several evaluation points to reduce the number of modular factors */
2026 while ( trialcount < maxtrials ) {
2028 /* generate a set of valid evaluation points */
2029 generate_set(pp, vn, syms, ex_to<lst>(vnlst), modulus, u, a);
2031 ufac = factor_univariate(u, x, prime);
2032 ufaclst = put_factors_into_lst(ufac);
2033 factor_count = ufaclst.nops()-1;
2034 delta = ufaclst.op(0);
2036 if ( factor_count <= 1 ) {
2040 if ( min_factor_count < 0 ) {
2041 /* first time here */
2042 min_factor_count = factor_count;
2044 else if ( min_factor_count == factor_count ) {
2045 /* one less to try */
2048 else if ( min_factor_count > factor_count ) {
2049 /* new minimum, reset trial counter */
2050 min_factor_count = factor_count;
2055 // determine true leading coefficients for the Hensel lifting
2056 vector<ex> C(factor_count);
2057 if ( is_a<numeric>(vn) ) {
2058 for ( size_t i=1; i<ufaclst.nops(); ++i ) {
2059 C[i-1] = ufaclst.op(i).lcoeff(x);
2063 vector<numeric> ftilde(vnlst.nops()-1);
2064 for ( size_t i=0; i<ftilde.size(); ++i ) {
2065 ex ft = vnlst.op(i+1);
2068 for ( size_t j=0; j<a.size(); ++j ) {
2069 ft = ft.subs(*s == a[j]);
2072 ftilde[i] = ex_to<numeric>(ft);
2075 vector<bool> used_flag(ftilde.size(), false);
2076 vector<ex> D(factor_count, 1);
2078 for ( int i=0; i<factor_count; ++i ) {
2079 numeric prefac = ex_to<numeric>(ufaclst.op(i+1).lcoeff(x));
2080 for ( int j=ftilde.size()-1; j>=0; --j ) {
2082 while ( irem(prefac, ftilde[j]) == 0 ) {
2083 prefac = iquo(prefac, ftilde[j]);
2087 used_flag[j] = true;
2088 D[i] = D[i] * pow(vnlst.op(j+1), count);
2091 C[i] = D[i] * prefac;
2095 for ( int i=0; i<factor_count; ++i ) {
2096 numeric prefac = ex_to<numeric>(ufaclst.op(i+1).lcoeff(x));
2097 for ( int j=ftilde.size()-1; j>=0; --j ) {
2099 while ( irem(prefac, ftilde[j]) == 0 ) {
2100 prefac = iquo(prefac, ftilde[j]);
2103 while ( irem(ex_to<numeric>(delta)*prefac, ftilde[j]) == 0 ) {
2104 numeric g = gcd(prefac, ex_to<numeric>(ftilde[j]));
2105 prefac = iquo(prefac, g);
2106 delta = delta / (ftilde[j]/g);
2107 ufaclst.let_op(i+1) = ufaclst.op(i+1) * (ftilde[j]/g);
2111 used_flag[j] = true;
2112 D[i] = D[i] * pow(vnlst.op(j+1), count);
2115 C[i] = D[i] * prefac;
2119 bool some_factor_unused = false;
2120 for ( size_t i=0; i<used_flag.size(); ++i ) {
2121 if ( !used_flag[i] ) {
2122 some_factor_unused = true;
2126 if ( some_factor_unused ) {
2132 C[0] = C[0] * delta;
2133 ufaclst.let_op(1) = ufaclst.op(1) * delta;
2137 vector<EvalPoint> epv;
2140 for ( size_t i=0; i<a.size(); ++i ) {
2142 ep.evalpoint = a[i].to_int();
2148 for ( int i=1; i<=factor_count; ++i ) {
2149 if ( ufaclst.op(i).degree(x) > maxdeg ) {
2150 maxdeg = ufaclst[i].degree(x);
2153 cl_I B = 2*calc_bound(u, x, maxdeg);
2160 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(prime),l));
2161 upvec modfactors(ufaclst.nops()-1);
2162 for ( size_t i=1; i<ufaclst.nops(); ++i ) {
2163 umodpoly_from_ex(modfactors[i-1], ufaclst.op(i), x, R);
2166 ex res = hensel_multivar(pp, x, epv, prime, l, modfactors, C);
2167 if ( res != lst() ) {
2169 for ( size_t i=0; i<res.nops(); ++i ) {
2170 result *= res.op(i).content(x) * res.op(i).unit(x);
2171 result *= res.op(i).primpart(x);
2178 struct find_symbols_map : public map_function {
2180 ex operator()(const ex& e)
2182 if ( is_a<symbol>(e) ) {
2186 return e.map(*this);
2190 static ex factor_sqrfree(const ex& poly)
2192 // determine all symbols in poly
2193 find_symbols_map findsymbols;
2195 if ( findsymbols.syms.size() == 0 ) {
2199 if ( findsymbols.syms.size() == 1 ) {
2201 const ex& x = *(findsymbols.syms.begin());
2202 if ( poly.ldegree(x) > 0 ) {
2203 int ld = poly.ldegree(x);
2204 ex res = factor_univariate(expand(poly/pow(x, ld)), x);
2205 return res * pow(x,ld);
2208 ex res = factor_univariate(poly, x);
2213 // multivariate case
2214 ex res = factor_multivariate(poly, findsymbols.syms);
2218 struct apply_factor_map : public map_function {
2220 apply_factor_map(unsigned options_) : options(options_) { }
2221 ex operator()(const ex& e)
2223 if ( e.info(info_flags::polynomial) ) {
2224 return factor(e, options);
2226 if ( is_a<add>(e) ) {
2228 for ( size_t i=0; i<e.nops(); ++i ) {
2229 if ( e.op(i).info(info_flags::polynomial) ) {
2238 return factor(s1, options) + s2.map(*this);
2240 return e.map(*this);
2244 } // anonymous namespace
2246 ex factor(const ex& poly, unsigned options)
2249 if ( !poly.info(info_flags::polynomial) ) {
2250 if ( options & factor_options::all ) {
2251 options &= ~factor_options::all;
2252 apply_factor_map factor_map(options);
2253 return factor_map(poly);
2258 // determine all symbols in poly
2259 find_symbols_map findsymbols;
2261 if ( findsymbols.syms.size() == 0 ) {
2265 exset::const_iterator i=findsymbols.syms.begin(), end=findsymbols.syms.end();
2266 for ( ; i!=end; ++i ) {
2270 // make poly square free
2271 ex sfpoly = sqrfree(poly.expand(), syms);
2273 // factorize the square free components
2274 if ( is_a<power>(sfpoly) ) {
2275 // case: (polynomial)^exponent
2276 const ex& base = sfpoly.op(0);
2277 if ( !is_a<add>(base) ) {
2278 // simple case: (monomial)^exponent
2281 ex f = factor_sqrfree(base);
2282 return pow(f, sfpoly.op(1));
2284 if ( is_a<mul>(sfpoly) ) {
2285 // case: multiple factors
2287 for ( size_t i=0; i<sfpoly.nops(); ++i ) {
2288 const ex& t = sfpoly.op(i);
2289 if ( is_a<power>(t) ) {
2290 const ex& base = t.op(0);
2291 if ( !is_a<add>(base) ) {
2295 ex f = factor_sqrfree(base);
2296 res *= pow(f, t.op(1));
2299 else if ( is_a<add>(t) ) {
2300 ex f = factor_sqrfree(t);
2309 if ( is_a<symbol>(sfpoly) ) {
2312 // case: (polynomial)
2313 ex f = factor_sqrfree(sfpoly);
2317 } // namespace GiNaC