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 std::vector<cln::cl_MI> umodpoly;
97 typedef std::vector<cln::cl_I> upoly;
98 typedef vector<umodpoly> upvec;
100 // COPY FROM UPOLY.HPP
102 // CHANGED size_t -> int !!!
103 template<typename T> static int degree(const T& p)
108 template<typename T> static typename T::value_type lcoeff(const T& p)
110 return p[p.size() - 1];
113 static bool normalize_in_field(umodpoly& a)
117 if ( lcoeff(a) == a[0].ring()->one() ) {
121 const cln::cl_MI lc_1 = recip(lcoeff(a));
122 for (std::size_t k = a.size(); k-- != 0; )
127 template<typename T> static void
128 canonicalize(T& p, const typename T::size_type hint = std::numeric_limits<typename T::size_type>::max())
133 std::size_t i = p.size() - 1;
134 // Be fast if the polynomial is already canonicalized
141 bool is_zero = false;
159 p.erase(p.begin() + i, p.end());
162 // END COPY FROM UPOLY.HPP
164 static void expt_pos(const umodpoly& a, unsigned int q, umodpoly& b)
166 throw runtime_error("expt_pos: not implemented!");
167 // code below is not correct!
169 // if ( a.empty() ) return;
170 // b.resize(degree(a)*q+1, a[0].ring()->zero());
171 // cl_MI norm = recip(a[0]);
173 // for ( size_t i=0; i<an.size(); ++i ) {
174 // an[i] = an[i] * norm;
176 // b[0] = a[0].ring()->one();
177 // for ( size_t i=1; i<b.size(); ++i ) {
178 // for ( size_t j=1; j<i; ++j ) {
179 // b[i] = b[i] + ((i-j+1)*q-i-1) * a[i-j] * b[j-1];
183 // cl_MI corr = expt_pos(a[0], q);
184 // for ( size_t i=0; i<b.size(); ++i ) {
185 // b[i] = b[i] * corr;
190 static T operator+(const T& a, const T& b)
197 for ( ; i<sb; ++i ) {
200 for ( ; i<sa; ++i ) {
209 for ( ; i<sa; ++i ) {
212 for ( ; i<sb; ++i ) {
221 static T operator-(const T& a, const T& b)
228 for ( ; i<sb; ++i ) {
231 for ( ; i<sa; ++i ) {
240 for ( ; i<sa; ++i ) {
243 for ( ; i<sb; ++i ) {
251 static upoly operator*(const upoly& a, const upoly& b)
254 if ( a.empty() || b.empty() ) return c;
256 int n = degree(a) + degree(b);
258 for ( int i=0 ; i<=n; ++i ) {
259 for ( int j=0 ; j<=i; ++j ) {
260 if ( j > degree(a) || (i-j) > degree(b) ) continue;
261 c[i] = c[i] + a[j] * b[i-j];
268 static umodpoly operator*(const umodpoly& a, const umodpoly& b)
271 if ( a.empty() || b.empty() ) return c;
273 int n = degree(a) + degree(b);
274 c.resize(n+1, a[0].ring()->zero());
275 for ( int i=0 ; i<=n; ++i ) {
276 for ( int j=0 ; j<=i; ++j ) {
277 if ( j > degree(a) || (i-j) > degree(b) ) continue;
278 c[i] = c[i] + a[j] * b[i-j];
285 static upoly operator*(const upoly& a, const cl_I& x)
292 for ( size_t i=0; i<a.size(); ++i ) {
298 static upoly operator/(const upoly& a, const cl_I& x)
305 for ( size_t i=0; i<a.size(); ++i ) {
306 r[i] = exquo(a[i],x);
311 static umodpoly operator*(const umodpoly& a, const cl_MI& x)
313 umodpoly r(a.size());
314 for ( size_t i=0; i<a.size(); ++i ) {
321 static void upoly_from_ex(upoly& up, const ex& e, const ex& x)
323 // assert: e is in Z[x]
324 int deg = e.degree(x);
326 int ldeg = e.ldegree(x);
327 for ( ; deg>=ldeg; --deg ) {
328 up[deg] = the<cl_I>(ex_to<numeric>(e.coeff(x, deg)).to_cl_N());
330 for ( ; deg>=0; --deg ) {
336 static void umodpoly_from_upoly(umodpoly& ump, const upoly& e, const cl_modint_ring& R)
340 for ( ; deg>=0; --deg ) {
341 ump[deg] = R->canonhom(e[deg]);
346 static void umodpoly_from_ex(umodpoly& ump, const ex& e, const ex& x, const cl_modint_ring& R)
348 // assert: e is in Z[x]
349 int deg = e.degree(x);
351 int ldeg = e.ldegree(x);
352 for ( ; deg>=ldeg; --deg ) {
353 cl_I coeff = the<cl_I>(ex_to<numeric>(e.coeff(x, deg)).to_cl_N());
354 ump[deg] = R->canonhom(coeff);
356 for ( ; deg>=0; --deg ) {
357 ump[deg] = R->zero();
362 static void umodpoly_from_ex(umodpoly& ump, const ex& e, const ex& x, const cl_I& modulus)
364 umodpoly_from_ex(ump, e, x, find_modint_ring(modulus));
367 static ex upoly_to_ex(const upoly& a, const ex& x)
369 if ( a.empty() ) return 0;
371 for ( int i=degree(a); i>=0; --i ) {
372 e += numeric(a[i]) * pow(x, i);
377 static ex umodpoly_to_ex(const umodpoly& a, const ex& x)
379 if ( a.empty() ) return 0;
380 cl_modint_ring R = a[0].ring();
381 cl_I mod = R->modulus;
382 cl_I halfmod = (mod-1) >> 1;
384 for ( int i=degree(a); i>=0; --i ) {
385 cl_I n = R->retract(a[i]);
387 e += numeric(n-mod) * pow(x, i);
389 e += numeric(n) * pow(x, i);
395 static upoly umodpoly_to_upoly(const umodpoly& a)
398 if ( a.empty() ) return e;
399 cl_modint_ring R = a[0].ring();
400 cl_I mod = R->modulus;
401 cl_I halfmod = (mod-1) >> 1;
402 for ( int i=degree(a); i>=0; --i ) {
403 cl_I n = R->retract(a[i]);
413 /** Divides all coefficients of the polynomial a by the integer x.
414 * All coefficients are supposed to be divisible by x. If they are not, the
415 * the<cl_I> cast will raise an exception.
417 * @param[in,out] a polynomial of which the coefficients will be reduced by x
418 * @param[in] x integer that divides the coefficients
420 static void reduce_coeff(umodpoly& a, const cl_I& x)
422 if ( a.empty() ) return;
424 cl_modint_ring R = a[0].ring();
425 umodpoly::iterator i = a.begin(), end = a.end();
426 for ( ; i!=end; ++i ) {
427 // cln cannot perform this division in the modular field
428 cl_I c = R->retract(*i);
429 *i = cl_MI(R, the<cl_I>(c / x));
433 /** Calculates remainder of a/b.
434 * Assertion: a and b not empty.
436 * @param[in] a polynomial dividend
437 * @param[in] b polynomial divisor
438 * @param[out] r polynomial remainder
440 static void rem(const umodpoly& a, const umodpoly& b, umodpoly& r)
449 cl_MI qk = div(r[n+k], b[n]);
451 for ( int i=0; i<n; ++i ) {
452 unsigned int j = n + k - 1 - i;
453 r[j] = r[j] - qk * b[j-k];
458 fill(r.begin()+n, r.end(), a[0].ring()->zero());
462 /** Calculates quotient of a/b.
463 * Assertion: a and b not empty.
465 * @param[in] a polynomial dividend
466 * @param[in] b polynomial divisor
467 * @param[out] q polynomial quotient
469 static void div(const umodpoly& a, const umodpoly& b, umodpoly& q)
478 q.resize(k+1, a[0].ring()->zero());
480 cl_MI qk = div(r[n+k], b[n]);
483 for ( int i=0; i<n; ++i ) {
484 unsigned int j = n + k - 1 - i;
485 r[j] = r[j] - qk * b[j-k];
493 /** Calculates quotient and remainder of a/b.
494 * Assertion: a and b not empty.
496 * @param[in] a polynomial dividend
497 * @param[in] b polynomial divisor
498 * @param[out] r polynomial remainder
499 * @param[out] q polynomial quotient
501 static void remdiv(const umodpoly& a, const umodpoly& b, umodpoly& r, umodpoly& q)
510 q.resize(k+1, a[0].ring()->zero());
512 cl_MI qk = div(r[n+k], b[n]);
515 for ( int i=0; i<n; ++i ) {
516 unsigned int j = n + k - 1 - i;
517 r[j] = r[j] - qk * b[j-k];
522 fill(r.begin()+n, r.end(), a[0].ring()->zero());
527 /** Calculates the GCD of polynomial a and b.
529 * @param[in] a polynomial
530 * @param[in] b polynomial
533 static void gcd(const umodpoly& a, const umodpoly& b, umodpoly& c)
535 if ( degree(a) < degree(b) ) return gcd(b, a, c);
538 normalize_in_field(c);
540 normalize_in_field(d);
542 while ( !d.empty() ) {
547 normalize_in_field(c);
550 /** Calculates the derivative of the polynomial a.
552 * @param[in] a polynomial of which to take the derivative
553 * @param[out] d result/derivative
555 static void deriv(const umodpoly& a, umodpoly& d)
558 if ( a.size() <= 1 ) return;
560 d.insert(d.begin(), a.begin()+1, a.end());
562 for ( int i=1; i<max; ++i ) {
568 static bool unequal_one(const umodpoly& a)
570 if ( a.empty() ) return true;
571 return ( a.size() != 1 || a[0] != a[0].ring()->one() );
574 static bool equal_one(const umodpoly& a)
576 return ( a.size() == 1 && a[0] == a[0].ring()->one() );
579 /** Returns true if polynomial a is square free.
581 * @param[in] a polynomial to check
582 * @return true if polynomial is square free, false otherwise
584 static bool squarefree(const umodpoly& a)
596 // END modular univariate polynomial code
597 ////////////////////////////////////////////////////////////////////////////////
599 ////////////////////////////////////////////////////////////////////////////////
604 friend ostream& operator<<(ostream& o, const modular_matrix& m);
606 modular_matrix(size_t r_, size_t c_, const cl_MI& init) : r(r_), c(c_)
610 size_t rowsize() const { return r; }
611 size_t colsize() const { return c; }
612 cl_MI& operator()(size_t row, size_t col) { return m[row*c + col]; }
613 cl_MI operator()(size_t row, size_t col) const { return m[row*c + col]; }
614 void mul_col(size_t col, const cl_MI x)
616 mvec::iterator i = m.begin() + col;
617 for ( size_t rc=0; rc<r; ++rc ) {
622 void sub_col(size_t col1, size_t col2, const cl_MI fac)
624 mvec::iterator i1 = m.begin() + col1;
625 mvec::iterator i2 = m.begin() + col2;
626 for ( size_t rc=0; rc<r; ++rc ) {
627 *i1 = *i1 - *i2 * fac;
632 void switch_col(size_t col1, size_t col2)
635 mvec::iterator i1 = m.begin() + col1;
636 mvec::iterator i2 = m.begin() + col2;
637 for ( size_t rc=0; rc<r; ++rc ) {
638 buf = *i1; *i1 = *i2; *i2 = buf;
643 void mul_row(size_t row, const cl_MI x)
645 vector<cl_MI>::iterator i = m.begin() + row*c;
646 for ( size_t cc=0; cc<c; ++cc ) {
651 void sub_row(size_t row1, size_t row2, const cl_MI fac)
653 vector<cl_MI>::iterator i1 = m.begin() + row1*c;
654 vector<cl_MI>::iterator i2 = m.begin() + row2*c;
655 for ( size_t cc=0; cc<c; ++cc ) {
656 *i1 = *i1 - *i2 * fac;
661 void switch_row(size_t row1, size_t row2)
664 vector<cl_MI>::iterator i1 = m.begin() + row1*c;
665 vector<cl_MI>::iterator i2 = m.begin() + row2*c;
666 for ( size_t cc=0; cc<c; ++cc ) {
667 buf = *i1; *i1 = *i2; *i2 = buf;
672 bool is_col_zero(size_t col) const
674 mvec::const_iterator i = m.begin() + col;
675 for ( size_t rr=0; rr<r; ++rr ) {
683 bool is_row_zero(size_t row) const
685 mvec::const_iterator i = m.begin() + row*c;
686 for ( size_t cc=0; cc<c; ++cc ) {
694 void set_row(size_t row, const vector<cl_MI>& newrow)
696 mvec::iterator i1 = m.begin() + row*c;
697 mvec::const_iterator i2 = newrow.begin(), end = newrow.end();
698 for ( ; i2 != end; ++i1, ++i2 ) {
702 mvec::const_iterator row_begin(size_t row) const { return m.begin()+row*c; }
703 mvec::const_iterator row_end(size_t row) const { return m.begin()+row*c+r; }
710 modular_matrix operator*(const modular_matrix& m1, const modular_matrix& m2)
712 const unsigned int r = m1.rowsize();
713 const unsigned int c = m2.colsize();
714 modular_matrix o(r,c,m1(0,0));
716 for ( size_t i=0; i<r; ++i ) {
717 for ( size_t j=0; j<c; ++j ) {
719 buf = m1(i,0) * m2(0,j);
720 for ( size_t k=1; k<c; ++k ) {
721 buf = buf + m1(i,k)*m2(k,j);
729 ostream& operator<<(ostream& o, const modular_matrix& m)
731 cl_modint_ring R = m(0,0).ring();
733 for ( size_t i=0; i<m.rowsize(); ++i ) {
735 for ( size_t j=0; j<m.colsize()-1; ++j ) {
736 o << R->retract(m(i,j)) << ",";
738 o << R->retract(m(i,m.colsize()-1)) << "}";
739 if ( i != m.rowsize()-1 ) {
746 #endif // def DEBUGFACTOR
748 // END modular matrix
749 ////////////////////////////////////////////////////////////////////////////////
751 static void q_matrix(const umodpoly& a_, modular_matrix& Q)
754 normalize_in_field(a);
757 unsigned int q = cl_I_to_uint(a[0].ring()->modulus);
758 umodpoly r(n, a[0].ring()->zero());
759 r[0] = a[0].ring()->one();
761 unsigned int max = (n-1) * q;
762 for ( size_t m=1; m<=max; ++m ) {
763 cl_MI rn_1 = r.back();
764 for ( size_t i=n-1; i>0; --i ) {
765 r[i] = r[i-1] - (rn_1 * a[i]);
768 if ( (m % q) == 0 ) {
774 static void nullspace(modular_matrix& M, vector<mvec>& basis)
776 const size_t n = M.rowsize();
777 const cl_MI one = M(0,0).ring()->one();
778 for ( size_t i=0; i<n; ++i ) {
779 M(i,i) = M(i,i) - one;
781 for ( size_t r=0; r<n; ++r ) {
783 for ( ; cc<n; ++cc ) {
784 if ( !zerop(M(r,cc)) ) {
786 if ( !zerop(M(cc,cc)) ) {
798 M.mul_col(r, recip(M(r,r)));
799 for ( cc=0; cc<n; ++cc ) {
801 M.sub_col(cc, r, M(r,cc));
807 for ( size_t i=0; i<n; ++i ) {
808 M(i,i) = M(i,i) - one;
810 for ( size_t i=0; i<n; ++i ) {
811 if ( !M.is_row_zero(i) ) {
812 mvec nu(M.row_begin(i), M.row_end(i));
818 static void berlekamp(const umodpoly& a, upvec& upv)
820 cl_modint_ring R = a[0].ring();
821 umodpoly one(1, R->one());
823 modular_matrix Q(degree(a), degree(a), R->zero());
828 const unsigned int k = nu.size();
833 list<umodpoly> factors;
834 factors.push_back(a);
835 unsigned int size = 1;
837 unsigned int q = cl_I_to_uint(R->modulus);
839 list<umodpoly>::iterator u = factors.begin();
842 for ( unsigned int s=0; s<q; ++s ) {
843 umodpoly nur = nu[r];
844 nur[0] = nur[0] - cl_MI(R, s);
848 if ( unequal_one(g) && g != *u ) {
851 if ( equal_one(uo) ) {
852 throw logic_error("berlekamp: unexpected divisor.");
857 factors.push_back(g);
859 list<umodpoly>::const_iterator i = factors.begin(), end = factors.end();
861 if ( degree(*i) ) ++size;
865 list<umodpoly>::const_iterator i = factors.begin(), end = factors.end();
880 static void rem_xq(int q, const umodpoly& b, umodpoly& c)
882 cl_modint_ring R = b[0].ring();
886 c.resize(q+1, R->zero());
892 c.resize(n+1, R->zero());
898 cl_MI qk = div(c[n-ofs], b[n]);
900 for ( int i=1; i<=n; ++i ) {
901 c[n-i+ofs] = c[n-i] - qk * b[n-i];
916 static void distinct_degree_factor(const umodpoly& a_, upvec& result)
920 cl_modint_ring R = a[0].ring();
921 int q = cl_I_to_int(R->modulus);
926 umodpoly w(1, R->one());
931 while ( i <= nhalf ) {
939 if ( unequal_one(ai.back()) ) {
940 div(a, ai.back(), a);
950 static void same_degree_factor(const umodpoly& a, upvec& result)
952 cl_modint_ring R = a[0].ring();
956 distinct_degree_factor(a, buf);
959 for ( size_t i=0; i<buf.size(); ++i ) {
960 if ( unequal_one(buf[i]) ) {
961 degsum += degree(buf[i]);
963 berlekamp(buf[i], upv);
964 for ( size_t j=0; j<upv.size(); ++j ) {
965 result.push_back(upv[j]);
970 if ( degsum < deg ) {
975 static void distinct_degree_factor_BSGS(const umodpoly& a, upvec& result)
977 cl_modint_ring R = a[0].ring();
978 int q = cl_I_to_int(R->modulus);
982 int l = cl_I_to_int(ceiling1(the<cl_F>(expt(n, pm))));
984 umodpoly qk(1, R->one());
986 for ( int i=1; i<=l; ++i ) {
987 expt_pos(h[i-1], q, qk);
991 int m = std::ceil(((double)n)/2/l);
993 int ql = std::pow(q, l);
995 for ( int i=1; i<m; ++i ) {
996 expt_pos(H[i-1], ql, qk);
1001 umodpoly one(1, R->one());
1002 for ( int i=0; i<m; ++i ) {
1004 for ( int j=0; j<l; ++j ) {
1005 I[i] = I[i] * (H[i] - h[j]);
1012 for ( int i=0; i<m; ++i ) {
1015 if ( g == one ) continue;
1020 result.resize(n, one);
1021 if ( unequal_one(f) ) {
1024 for ( int i=0; i<m; ++i ) {
1026 for ( int j=l-1; j>=0; --j ) {
1028 gcd(f, H[i]-h[j], g);
1029 result[l*(i+1)-j-1] = g;
1035 static void cantor_zassenhaus(const umodpoly& a, upvec& result)
1039 static void factor_modular(const umodpoly& p, upvec& upv)
1041 //same_degree_factor(p, upv);
1046 /** Calculates polynomials s and t such that a*s+b*t==1.
1047 * Assertion: a and b are relatively prime and not zero.
1049 * @param[in] a polynomial
1050 * @param[in] b polynomial
1051 * @param[out] s polynomial
1052 * @param[out] t polynomial
1054 static void exteuclid(const umodpoly& a, const umodpoly& b, umodpoly& s, umodpoly& t)
1056 if ( degree(a) < degree(b) ) {
1057 exteuclid(b, a, t, s);
1061 umodpoly one(1, a[0].ring()->one());
1062 umodpoly c = a; normalize_in_field(c);
1063 umodpoly d = b; normalize_in_field(d);
1071 umodpoly r = c - q * d;
1072 umodpoly r1 = s - q * d1;
1073 umodpoly r2 = t - q * d2;
1077 if ( r.empty() ) break;
1082 cl_MI fac = recip(lcoeff(a) * lcoeff(c));
1083 umodpoly::iterator i = s.begin(), end = s.end();
1084 for ( ; i!=end; ++i ) {
1088 fac = recip(lcoeff(b) * lcoeff(c));
1089 i = t.begin(), end = t.end();
1090 for ( ; i!=end; ++i ) {
1096 static upoly replace_lc(const upoly& poly, const cl_I& lc)
1098 if ( poly.empty() ) return poly;
1104 static ex hensel_univar(const ex& a_, const ex& x, unsigned int p, const umodpoly& u1_, const umodpoly& w1_, const ex& gamma_ = 0)
1107 upoly_from_ex(a, a_, x);
1108 const cl_modint_ring& R = u1_[0].ring();
1112 for ( int i=degree(a); i>=0; --i ) {
1113 maxcoeff = maxcoeff + square(abs(a[i]));
1115 cl_I normmc = ceiling1(the<cl_R>(cln::sqrt(maxcoeff)));
1116 cl_I maxdegree = (degree(u1_) > degree(w1_)) ? degree(u1_) : degree(w1_);
1117 cl_I B = normmc * expt_pos(cl_I(2), maxdegree);
1120 cl_I alpha = lcoeff(a);
1121 cl_I gamma = the<cl_I>(ex_to<numeric>(gamma_).to_cl_N());
1125 cl_I gamma_ui = abs(gamma);
1128 normalize_in_field(nu1);
1130 normalize_in_field(nw1);
1132 phi = umodpoly_to_upoly(nu1) * gamma;
1134 umodpoly_from_upoly(u1, phi, R);
1135 phi = umodpoly_to_upoly(nw1) * alpha;
1137 umodpoly_from_upoly(w1, phi, R);
1142 exteuclid(u1, w1, s, t);
1145 upoly u = replace_lc(umodpoly_to_upoly(u1), gamma);
1146 upoly w = replace_lc(umodpoly_to_upoly(w1), alpha);
1147 upoly e = a - u * w;
1149 const cl_I maxmodulus = 2*B*gamma_ui;
1152 while ( !e.empty() && modulus < maxmodulus ) {
1153 upoly c = e / modulus;
1154 phi = umodpoly_to_upoly(s) * c;
1155 umodpoly sigmatilde;
1156 umodpoly_from_upoly(sigmatilde, phi, R);
1157 phi = umodpoly_to_upoly(t) * c;
1159 umodpoly_from_upoly(tautilde, phi, R);
1161 remdiv(sigmatilde, w1, r, q);
1163 phi = umodpoly_to_upoly(tautilde) + umodpoly_to_upoly(q) * umodpoly_to_upoly(u1);
1165 umodpoly_from_upoly(tau, phi, R);
1166 u = u + umodpoly_to_upoly(tau) * modulus;
1167 w = w + umodpoly_to_upoly(sigma) * modulus;
1169 modulus = modulus * p;
1174 ex ue = upoly_to_ex(u, x);
1175 ex we = upoly_to_ex(w, x);
1176 ex delta = ue.content(x);
1178 we = we / numeric(gamma) * delta;
1186 static unsigned int next_prime(unsigned int p)
1188 static vector<unsigned int> primes;
1189 if ( primes.size() == 0 ) {
1190 primes.push_back(3); primes.push_back(5); primes.push_back(7);
1192 vector<unsigned int>::const_iterator it = primes.begin();
1193 if ( p >= primes.back() ) {
1194 unsigned int candidate = primes.back() + 2;
1196 size_t n = primes.size()/2;
1197 for ( size_t i=0; i<n; ++i ) {
1198 if ( candidate % primes[i] ) continue;
1202 primes.push_back(candidate);
1203 if ( candidate > p ) break;
1207 vector<unsigned int>::const_iterator end = primes.end();
1208 for ( ; it!=end; ++it ) {
1213 throw logic_error("next_prime: should not reach this point!");
1219 Partition(size_t n_) : n(n_)
1225 int operator[](size_t i) const { return k[i]; }
1226 size_t size() const { return n; }
1227 size_t size_first() const { return n-sum; }
1228 size_t size_second() const { return sum; }
1232 for ( size_t i=0; i<k.size(); ++i ) {
1233 cout << k[i] << " ";
1240 for ( size_t i=n-1; i>=1; --i ) {
1256 static void split(const upvec& factors, const Partition& part, umodpoly& a, umodpoly& b)
1258 umodpoly one(1, factors.front()[0].ring()->one());
1261 for ( size_t i=0; i<part.size(); ++i ) {
1277 static ex factor_univariate(const ex& poly, const ex& x)
1279 ex unit, cont, prim;
1280 poly.unitcontprim(x, unit, cont, prim);
1282 // determine proper prime and minimize number of modular factors
1283 unsigned int p = 3, lastp = 3;
1285 unsigned int trials = 0;
1286 unsigned int minfactors = 0;
1287 numeric lcoeff = ex_to<numeric>(prim.lcoeff(x));
1289 while ( trials < 2 ) {
1292 if ( irem(lcoeff, p) != 0 ) {
1293 R = find_modint_ring(p);
1295 umodpoly_from_ex(modpoly, prim, x, R);
1296 if ( squarefree(modpoly) ) break;
1300 // do modular factorization
1302 umodpoly_from_ex(modpoly, prim, x, R);
1304 factor_modular(modpoly, trialfactors);
1305 if ( trialfactors.size() <= 1 ) {
1306 // irreducible for sure
1310 if ( minfactors == 0 || trialfactors.size() < minfactors ) {
1311 factors = trialfactors;
1312 minfactors = factors.size();
1321 R = find_modint_ring(p);
1322 cl_univpoly_modint_ring UPR = find_univpoly_ring(R);
1324 // lift all factor combinations
1325 stack<ModFactors> tocheck;
1328 mf.factors = factors;
1331 while ( tocheck.size() ) {
1332 const size_t n = tocheck.top().factors.size();
1336 split(tocheck.top().factors, part, a, b);
1338 ex answer = hensel_univar(tocheck.top().poly, x, p, a, b);
1339 if ( answer != lst() ) {
1340 if ( part.size_first() == 1 ) {
1341 if ( part.size_second() == 1 ) {
1342 result *= answer.op(0) * answer.op(1);
1346 result *= answer.op(0);
1347 tocheck.top().poly = answer.op(1);
1348 for ( size_t i=0; i<n; ++i ) {
1349 if ( part[i] == 0 ) {
1350 tocheck.top().factors.erase(tocheck.top().factors.begin()+i);
1356 else if ( part.size_second() == 1 ) {
1357 if ( part.size_first() == 1 ) {
1358 result *= answer.op(0) * answer.op(1);
1362 result *= answer.op(1);
1363 tocheck.top().poly = answer.op(0);
1364 for ( size_t i=0; i<n; ++i ) {
1365 if ( part[i] == 1 ) {
1366 tocheck.top().factors.erase(tocheck.top().factors.begin()+i);
1373 upvec newfactors1(part.size_first()), newfactors2(part.size_second());
1374 upvec::iterator i1 = newfactors1.begin(), i2 = newfactors2.begin();
1375 for ( size_t i=0; i<n; ++i ) {
1377 *i2++ = tocheck.top().factors[i];
1380 *i1++ = tocheck.top().factors[i];
1383 tocheck.top().factors = newfactors1;
1384 tocheck.top().poly = answer.op(0);
1386 mf.factors = newfactors2;
1387 mf.poly = answer.op(1);
1393 if ( !part.next() ) {
1394 result *= tocheck.top().poly;
1402 return unit * cont * result;
1411 // forward declaration
1412 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);
1414 upvec multiterm_eea_lift(const upvec& a, const ex& x, unsigned int p, unsigned int k)
1416 const size_t r = a.size();
1417 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1420 for ( size_t j=r-2; j>=1; --j ) {
1421 q[j-1] = a[j] * q[j];
1423 umodpoly beta(1, R->one());
1425 for ( size_t j=1; j<r; ++j ) {
1426 vector<ex> mdarg(2);
1427 mdarg[0] = umodpoly_to_ex(q[j-1], x);
1428 mdarg[1] = umodpoly_to_ex(a[j-1], x);
1429 vector<EvalPoint> empty;
1430 vector<ex> exsigma = multivar_diophant(mdarg, x, umodpoly_to_ex(beta, x), empty, 0, p, k);
1432 umodpoly_from_ex(sigma1, exsigma[0], x, R);
1434 umodpoly_from_ex(sigma2, exsigma[1], x, R);
1436 s.push_back(sigma2);
1443 * Assert: a not empty.
1445 void change_modulus(const cl_modint_ring& R, umodpoly& a)
1447 if ( a.empty() ) return;
1448 cl_modint_ring oldR = a[0].ring();
1449 umodpoly::iterator i = a.begin(), end = a.end();
1450 for ( ; i!=end; ++i ) {
1451 *i = R->canonhom(oldR->retract(*i));
1456 void eea_lift(const umodpoly& a, const umodpoly& b, const ex& x, unsigned int p, unsigned int k, umodpoly& s_, umodpoly& t_)
1458 cl_modint_ring R = find_modint_ring(p);
1460 change_modulus(R, amod);
1462 change_modulus(R, bmod);
1466 exteuclid(amod, bmod, smod, tmod);
1468 cl_modint_ring Rpk = find_modint_ring(expt_pos(cl_I(p),k));
1470 change_modulus(Rpk, s);
1472 change_modulus(Rpk, t);
1475 umodpoly one(1, Rpk->one());
1476 for ( size_t j=1; j<k; ++j ) {
1477 umodpoly e = one - a * s - b * t;
1478 reduce_coeff(e, modulus);
1480 change_modulus(R, c);
1481 umodpoly sigmabar = smod * c;
1482 umodpoly taubar = tmod * c;
1484 remdiv(sigmabar, bmod, sigma, q);
1485 umodpoly tau = taubar + q * amod;
1486 umodpoly sadd = sigma;
1487 change_modulus(Rpk, sadd);
1488 cl_MI modmodulus(Rpk, modulus);
1489 s = s + sadd * modmodulus;
1490 umodpoly tadd = tau;
1491 change_modulus(Rpk, tadd);
1492 t = t + tadd * modmodulus;
1493 modulus = modulus * p;
1499 upvec univar_diophant(const upvec& a, const ex& x, unsigned int m, unsigned int p, unsigned int k)
1501 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1503 const size_t r = a.size();
1506 upvec s = multiterm_eea_lift(a, x, p, k);
1507 for ( size_t j=0; j<r; ++j ) {
1508 ex phi = expand(pow(x,m) * umodpoly_to_ex(s[j], x));
1510 umodpoly_from_ex(bmod, phi, x, R);
1512 rem(bmod, a[j], buf);
1513 result.push_back(buf);
1519 eea_lift(a[1], a[0], x, p, k, s, t);
1520 ex phi = expand(pow(x,m) * umodpoly_to_ex(s, x));
1522 umodpoly_from_ex(bmod, phi, x, R);
1524 remdiv(bmod, a[0], buf, q);
1525 result.push_back(buf);
1526 phi = expand(pow(x,m) * umodpoly_to_ex(t, x));
1528 umodpoly_from_ex(t1mod, phi, x, R);
1529 umodpoly buf2 = t1mod + q * a[1];
1530 result.push_back(buf2);
1536 struct make_modular_map : public map_function {
1538 make_modular_map(const cl_modint_ring& R_) : R(R_) { }
1539 ex operator()(const ex& e)
1541 if ( is_a<add>(e) || is_a<mul>(e) ) {
1542 return e.map(*this);
1544 else if ( is_a<numeric>(e) ) {
1545 numeric mod(R->modulus);
1546 numeric halfmod = (mod-1)/2;
1547 cl_MI emod = R->canonhom(the<cl_I>(ex_to<numeric>(e).to_cl_N()));
1548 numeric n(R->retract(emod));
1549 if ( n > halfmod ) {
1560 static ex make_modular(const ex& e, const cl_modint_ring& R)
1562 make_modular_map map(R);
1563 return map(e.expand());
1566 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)
1570 const cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1571 const size_t r = a.size();
1572 const size_t nu = I.size() + 1;
1576 ex xnu = I.back().x;
1577 int alphanu = I.back().evalpoint;
1580 for ( size_t i=0; i<r; ++i ) {
1584 for ( size_t i=0; i<r; ++i ) {
1585 b[i] = normal(A / a[i]);
1588 vector<ex> anew = a;
1589 for ( size_t i=0; i<r; ++i ) {
1590 anew[i] = anew[i].subs(xnu == alphanu);
1592 ex cnew = c.subs(xnu == alphanu);
1593 vector<EvalPoint> Inew = I;
1595 sigma = multivar_diophant(anew, x, cnew, Inew, d, p, k);
1598 for ( size_t i=0; i<r; ++i ) {
1599 buf -= sigma[i] * b[i];
1601 ex e = make_modular(buf, R);
1604 for ( size_t m=1; m<=d; ++m ) {
1605 while ( !e.is_zero() && e.has(xnu) ) {
1606 monomial *= (xnu - alphanu);
1607 monomial = expand(monomial);
1608 ex cm = e.diff(ex_to<symbol>(xnu), m).subs(xnu==alphanu) / factorial(m);
1609 cm = make_modular(cm, R);
1610 if ( !cm.is_zero() ) {
1611 vector<ex> delta_s = multivar_diophant(anew, x, cm, Inew, d, p, k);
1613 for ( size_t j=0; j<delta_s.size(); ++j ) {
1614 delta_s[j] *= monomial;
1615 sigma[j] += delta_s[j];
1616 buf -= delta_s[j] * b[j];
1618 e = make_modular(buf, R);
1625 for ( size_t i=0; i<a.size(); ++i ) {
1627 umodpoly_from_ex(up, a[i], x, R);
1631 sigma.insert(sigma.begin(), r, 0);
1634 if ( is_a<add>(c) ) {
1642 for ( size_t i=0; i<nterms; ++i ) {
1643 int m = z.degree(x);
1644 cl_I cm = the<cl_I>(ex_to<numeric>(z.lcoeff(x)).to_cl_N());
1645 upvec delta_s = univar_diophant(amod, x, m, p, k);
1648 while ( poscm < 0 ) {
1649 poscm = poscm + expt_pos(cl_I(p),k);
1651 modcm = cl_MI(R, poscm);
1652 for ( size_t j=0; j<delta_s.size(); ++j ) {
1653 delta_s[j] = delta_s[j] * modcm;
1654 sigma[j] = sigma[j] + umodpoly_to_ex(delta_s[j], x);
1662 for ( size_t i=0; i<sigma.size(); ++i ) {
1663 sigma[i] = make_modular(sigma[i], R);
1670 ostream& operator<<(ostream& o, const vector<EvalPoint>& v)
1672 for ( size_t i=0; i<v.size(); ++i ) {
1673 o << "(" << v[i].x << "==" << v[i].evalpoint << ") ";
1677 #endif // def DEBUGFACTOR
1679 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)
1681 const size_t nu = I.size() + 1;
1682 const cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),l));
1687 for ( size_t j=nu; j>=2; --j ) {
1689 int alpha = I[j-2].evalpoint;
1690 A[j-2] = A[j-1].subs(x==alpha);
1691 A[j-2] = make_modular(A[j-2], R);
1694 int maxdeg = a.degree(I.front().x);
1695 for ( size_t i=1; i<I.size(); ++i ) {
1696 int maxdeg2 = a.degree(I[i].x);
1697 if ( maxdeg2 > maxdeg ) maxdeg = maxdeg2;
1700 const size_t n = u.size();
1702 for ( size_t i=0; i<n; ++i ) {
1703 U[i] = umodpoly_to_ex(u[i], x);
1706 for ( size_t j=2; j<=nu; ++j ) {
1709 for ( size_t m=0; m<n; ++m) {
1710 if ( lcU[m] != 1 ) {
1712 for ( size_t i=j-1; i<nu-1; ++i ) {
1713 coef = coef.subs(I[i].x == I[i].evalpoint);
1715 coef = make_modular(coef, R);
1716 int deg = U[m].degree(x);
1717 U[m] = U[m] - U[m].lcoeff(x) * pow(x,deg) + coef * pow(x,deg);
1721 for ( size_t i=0; i<n; ++i ) {
1724 ex e = expand(A[j-1] - Uprod);
1726 vector<EvalPoint> newI;
1727 for ( size_t i=1; i<=j-2; ++i ) {
1728 newI.push_back(I[i-1]);
1732 int alphaj = I[j-2].evalpoint;
1733 size_t deg = A[j-1].degree(xj);
1734 for ( size_t k=1; k<=deg; ++k ) {
1735 if ( !e.is_zero() ) {
1736 monomial *= (xj - alphaj);
1737 monomial = expand(monomial);
1738 ex dif = e.diff(ex_to<symbol>(xj), k);
1739 ex c = dif.subs(xj==alphaj) / factorial(k);
1740 if ( !c.is_zero() ) {
1741 vector<ex> deltaU = multivar_diophant(U1, x, c, newI, maxdeg, p, cl_I_to_uint(l));
1742 for ( size_t i=0; i<n; ++i ) {
1743 deltaU[i] *= monomial;
1745 U[i] = make_modular(U[i], R);
1748 for ( size_t i=0; i<n; ++i ) {
1752 e = make_modular(e, R);
1759 for ( size_t i=0; i<U.size(); ++i ) {
1762 if ( expand(a-acand).is_zero() ) {
1764 for ( size_t i=0; i<U.size(); ++i ) {
1775 static ex put_factors_into_lst(const ex& e)
1779 if ( is_a<numeric>(e) ) {
1783 if ( is_a<power>(e) ) {
1785 result.append(e.op(0));
1786 result.append(e.op(1));
1789 if ( is_a<symbol>(e) || is_a<add>(e) ) {
1795 if ( is_a<mul>(e) ) {
1797 for ( size_t i=0; i<e.nops(); ++i ) {
1799 if ( is_a<numeric>(op) ) {
1802 if ( is_a<power>(op) ) {
1803 result.append(op.op(0));
1804 result.append(op.op(1));
1806 if ( is_a<symbol>(op) || is_a<add>(op) ) {
1811 result.prepend(nfac);
1814 throw runtime_error("put_factors_into_lst: bad term.");
1818 ostream& operator<<(ostream& o, const vector<numeric>& v)
1820 for ( size_t i=0; i<v.size(); ++i ) {
1825 #endif // def DEBUGFACTOR
1827 static bool checkdivisors(const lst& f, vector<numeric>& d)
1829 const int k = f.nops()-2;
1831 d[0] = ex_to<numeric>(f.op(0) * f.op(f.nops()-1));
1832 if ( d[0] == 1 && k == 1 && abs(f.op(1)) != 1 ) {
1835 for ( int i=1; i<=k; ++i ) {
1836 q = ex_to<numeric>(abs(f.op(i)));
1837 for ( int j=i-1; j>=0; --j ) {
1852 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)
1854 // computation of d is actually not necessary
1855 const ex& x = *syms.begin();
1861 exset::const_iterator s = syms.begin();
1863 for ( size_t i=0; i<a.size(); ++i ) {
1865 a[i] = mod(numeric(rand()), 2*modulus) - modulus;
1866 vnatry = vna.subs(*s == a[i]);
1867 } while ( vnatry == 0 );
1869 u0 = u0.subs(*s == a[i]);
1872 if ( gcd(u0,u0.diff(ex_to<symbol>(x))) != 1 ) {
1875 if ( is_a<numeric>(vn) ) {
1880 lst::const_iterator i = ex_to<lst>(f).begin();
1882 bool problem = false;
1883 while ( i!=ex_to<lst>(f).end() ) {
1885 if ( !is_a<numeric>(fs) ) {
1888 for ( size_t j=0; j<a.size(); ++j ) {
1889 fs = fs.subs(*s == a[j]);
1892 if ( abs(fs) == 1 ) {
1903 ex con = u0.content(x);
1905 trying = checkdivisors(fnum, d);
1911 static ex factor_multivariate(const ex& poly, const exset& syms)
1913 exset::const_iterator s;
1914 const ex& x = *syms.begin();
1916 /* make polynomial primitive */
1917 ex p = poly.expand().collect(x);
1918 ex cont = p.lcoeff(x);
1919 for ( numeric i=p.degree(x)-1; i>=p.ldegree(x); --i ) {
1920 cont = gcd(cont, p.coeff(x,ex_to<numeric>(i).to_int()));
1921 if ( cont == 1 ) break;
1923 ex pp = expand(normal(p / cont));
1924 if ( !is_a<numeric>(cont) ) {
1925 return factor(cont) * factor(pp);
1928 /* factor leading coefficient */
1930 ex vn = pp.lcoeff(x);
1933 if ( is_a<numeric>(vn) ) {
1937 ex vnfactors = factor(vn);
1938 vnlst = put_factors_into_lst(vnfactors);
1941 const numeric maxtrials = 3;
1942 numeric modulus = (vnlst.nops()-1 > 3) ? vnlst.nops()-1 : 3;
1943 numeric minimalr = -1;
1944 vector<numeric> a(syms.size()-1, 0);
1945 vector<numeric> d((vnlst.nops()-1)/2+1, 0);
1948 numeric trialcount = 0;
1950 unsigned int prime = 3;
1951 size_t factor_count = 0;
1954 while ( trialcount < maxtrials ) {
1955 bool problem = generate_set(pp, vn, syms, vnlst, modulus, a, d);
1963 for ( size_t i=0; i<a.size(); ++i ) {
1964 u = u.subs(*s == a[i]);
1967 delta = u.content(x);
1969 // determine proper prime
1971 cl_modint_ring R = find_modint_ring(prime);
1973 if ( irem(ex_to<numeric>(u.lcoeff(x)), prime) != 0 ) {
1975 umodpoly_from_ex(modpoly, u, x, R);
1976 if ( squarefree(modpoly) ) break;
1978 prime = next_prime(prime);
1979 R = find_modint_ring(prime);
1983 ufaclst = put_factors_into_lst(ufac);
1984 factor_count = (ufaclst.nops()-1)/2;
1986 // veto factorization for which gcd(u_i, u_j) != 1 for all i,j
1988 for ( size_t i=0; i<(ufaclst.nops()-1)/2; ++i ) {
1990 umodpoly_from_ex(newu, ufaclst.op(i*2+1), x, R);
1991 tryu.push_back(newu);
1994 for ( size_t i=0; i<tryu.size()-1; ++i ) {
1995 for ( size_t j=i+1; j<tryu.size(); ++j ) {
1997 gcd(tryu[i], tryu[j], tryg);
1998 if ( unequal_one(tryg) ) {
2000 goto escape_quickly;
2009 if ( factor_count <= 1 ) {
2013 if ( minimalr < 0 ) {
2014 minimalr = factor_count;
2016 else if ( minimalr == factor_count ) {
2020 else if ( minimalr > factor_count ) {
2021 minimalr = factor_count;
2024 if ( minimalr <= 1 ) {
2029 vector<numeric> ftilde((vnlst.nops()-1)/2+1);
2030 ftilde[0] = ex_to<numeric>(vnlst.op(0));
2031 for ( size_t i=1; i<ftilde.size(); ++i ) {
2032 ex ft = vnlst.op((i-1)*2+1);
2035 for ( size_t j=0; j<a.size(); ++j ) {
2036 ft = ft.subs(*s == a[j]);
2039 ftilde[i] = ex_to<numeric>(ft);
2042 vector<bool> used_flag((vnlst.nops()-1)/2+1, false);
2043 vector<ex> D(factor_count, 1);
2044 for ( size_t i=0; i<=factor_count; ++i ) {
2047 prefac = ex_to<numeric>(ufaclst.op(0));
2048 ftilde[0] = ftilde[0] / prefac;
2049 vnlst.let_op(0) = vnlst.op(0) / prefac;
2053 prefac = ex_to<numeric>(ufaclst.op(2*(i-1)+1).lcoeff(x));
2055 for ( size_t j=(vnlst.nops()-1)/2+1; j>0; --j ) {
2056 if ( abs(ftilde[j-1]) == 1 ) {
2057 used_flag[j-1] = true;
2060 numeric g = gcd(prefac, ftilde[j-1]);
2062 prefac = prefac / g;
2063 numeric count = abs(iquo(g, ftilde[j-1]));
2064 used_flag[j-1] = true;
2067 D[i-1] = D[i-1] * pow(vnlst.op(0), count);
2070 D[i-1] = D[i-1] * pow(vnlst.op(2*(j-2)+1), count);
2074 ftilde[j-1] = ftilde[j-1] / prefac;
2082 bool some_factor_unused = false;
2083 for ( size_t i=0; i<used_flag.size(); ++i ) {
2084 if ( !used_flag[i] ) {
2085 some_factor_unused = true;
2089 if ( some_factor_unused ) {
2093 vector<ex> C(factor_count);
2095 for ( size_t i=0; i<D.size(); ++i ) {
2099 for ( size_t j=0; j<a.size(); ++j ) {
2100 Dtilde = Dtilde.subs(*s == a[j]);
2103 C[i] = D[i] * (ufaclst.op(2*i+1).lcoeff(x) / Dtilde);
2107 for ( size_t i=0; i<D.size(); ++i ) {
2111 for ( size_t j=0; j<a.size(); ++j ) {
2112 Dtilde = Dtilde.subs(*s == a[j]);
2120 ui = ufaclst.op(2*(i-1)+1);
2123 ex d = gcd(ui.lcoeff(x), Dtilde);
2124 C[i] = D[i] * ( ui.lcoeff(x) / d );
2125 ui = ui * ( Dtilde[i] / d );
2126 delta = delta / ( Dtilde[i] / d );
2127 if ( delta == 1 ) break;
2129 C[i] = delta * C[i];
2130 pp = pp * pow(delta, D.size()-1);
2136 vector<EvalPoint> epv;
2139 for ( size_t i=0; i<a.size(); ++i ) {
2141 ep.evalpoint = a[i].to_int();
2147 for ( int i=u.degree(x); i>=u.ldegree(x); --i ) {
2148 maxcoeff += pow(abs(u.coeff(x, i)),2);
2150 cl_I normmc = ceiling1(the<cl_R>(cln::sqrt(ex_to<numeric>(maxcoeff).to_cl_N())));
2151 unsigned int maxdegree = 0;
2152 for ( size_t i=0; i<factor_count; ++i ) {
2153 if ( ufaclst[2*i+1].degree(x) > (int)maxdegree ) {
2154 maxdegree = ufaclst[2*i+1].degree(x);
2157 cl_I B = normmc * expt_pos(cl_I(2), maxdegree);
2166 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(prime),l));
2167 for ( size_t i=0; i<(ufaclst.nops()-1)/2; ++i ) {
2169 umodpoly_from_ex(newu, ufaclst.op(i*2+1), x, R);
2170 uvec.push_back(newu);
2173 ex res = hensel_multivar(ufaclst.op(0)*pp, x, epv, prime, l, uvec, C);
2174 if ( res != lst() ) {
2175 ex result = cont * ufaclst.op(0);
2176 for ( size_t i=0; i<res.nops(); ++i ) {
2177 result *= res.op(i).content(x) * res.op(i).unit(x);
2178 result *= res.op(i).primpart(x);
2185 struct find_symbols_map : public map_function {
2187 ex operator()(const ex& e)
2189 if ( is_a<symbol>(e) ) {
2193 return e.map(*this);
2197 static ex factor_sqrfree(const ex& poly)
2199 // determine all symbols in poly
2200 find_symbols_map findsymbols;
2202 if ( findsymbols.syms.size() == 0 ) {
2206 if ( findsymbols.syms.size() == 1 ) {
2208 const ex& x = *(findsymbols.syms.begin());
2209 if ( poly.ldegree(x) > 0 ) {
2210 int ld = poly.ldegree(x);
2211 ex res = factor_univariate(expand(poly/pow(x, ld)), x);
2212 return res * pow(x,ld);
2215 ex res = factor_univariate(poly, x);
2220 // multivariate case
2221 ex res = factor_multivariate(poly, findsymbols.syms);
2225 struct apply_factor_map : public map_function {
2227 apply_factor_map(unsigned options_) : options(options_) { }
2228 ex operator()(const ex& e)
2230 if ( e.info(info_flags::polynomial) ) {
2231 return factor(e, options);
2233 if ( is_a<add>(e) ) {
2235 for ( size_t i=0; i<e.nops(); ++i ) {
2236 if ( e.op(i).info(info_flags::polynomial) ) {
2245 return factor(s1, options) + s2.map(*this);
2247 return e.map(*this);
2251 } // anonymous namespace
2253 ex factor(const ex& poly, unsigned options)
2256 if ( !poly.info(info_flags::polynomial) ) {
2257 if ( options & factor_options::all ) {
2258 options &= ~factor_options::all;
2259 apply_factor_map factor_map(options);
2260 return factor_map(poly);
2265 // determine all symbols in poly
2266 find_symbols_map findsymbols;
2268 if ( findsymbols.syms.size() == 0 ) {
2272 exset::const_iterator i=findsymbols.syms.begin(), end=findsymbols.syms.end();
2273 for ( ; i!=end; ++i ) {
2277 // make poly square free
2278 ex sfpoly = sqrfree(poly, syms);
2280 // factorize the square free components
2281 if ( is_a<power>(sfpoly) ) {
2282 // case: (polynomial)^exponent
2283 const ex& base = sfpoly.op(0);
2284 if ( !is_a<add>(base) ) {
2285 // simple case: (monomial)^exponent
2288 ex f = factor_sqrfree(base);
2289 return pow(f, sfpoly.op(1));
2291 if ( is_a<mul>(sfpoly) ) {
2292 // case: multiple factors
2294 for ( size_t i=0; i<sfpoly.nops(); ++i ) {
2295 const ex& t = sfpoly.op(i);
2296 if ( is_a<power>(t) ) {
2297 const ex& base = t.op(0);
2298 if ( !is_a<add>(base) ) {
2302 ex f = factor_sqrfree(base);
2303 res *= pow(f, t.op(1));
2306 else if ( is_a<add>(t) ) {
2307 ex f = factor_sqrfree(t);
2316 if ( is_a<symbol>(sfpoly) ) {
2319 // case: (polynomial)
2320 ex f = factor_sqrfree(sfpoly);
2324 } // namespace GiNaC