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 ( int 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 bool nontrivial = false;
970 while ( i <= nhalf ) {
977 if ( unequal_one(buf) ) {
978 degrees.push_back(i);
979 ddfactors.push_back(buf);
981 if ( unequal_one(buf) ) {
991 if ( unequal_one(a) ) {
992 degrees.push_back(degree(a));
993 ddfactors.push_back(a);
997 static void same_degree_factor(const umodpoly& a, upvec& upv)
999 cl_modint_ring R = a[0].ring();
1000 int deg = degree(a);
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 static void factor_modular(const umodpoly& p, upvec& upv)
1020 modsqrfree(p, factors, mult);
1022 #define USE_SAME_DEGREE_FACTOR
1023 #ifdef USE_SAME_DEGREE_FACTOR
1024 for ( size_t i=0; i<factors.size(); ++i ) {
1026 same_degree_factor(factors[i], upvbuf);
1027 for ( int j=mult[i]; j>0; --j ) {
1028 upv.insert(upv.end(), upvbuf.begin(), upvbuf.end());
1032 for ( size_t i=0; i<factors.size(); ++i ) {
1034 berlekamp(factors[i], upvbuf);
1035 if ( upvbuf.size() ) {
1036 for ( size_t j=0; j<upvbuf.size(); ++j ) {
1037 upv.insert(upv.end(), mult[i], upvbuf[j]);
1041 for ( int j=mult[i]; j>0; --j ) {
1042 upv.push_back(factors[i]);
1049 /** Calculates polynomials s and t such that a*s+b*t==1.
1050 * Assertion: a and b are relatively prime and not zero.
1052 * @param[in] a polynomial
1053 * @param[in] b polynomial
1054 * @param[out] s polynomial
1055 * @param[out] t polynomial
1057 static void exteuclid(const umodpoly& a, const umodpoly& b, umodpoly& s, umodpoly& t)
1059 if ( degree(a) < degree(b) ) {
1060 exteuclid(b, a, t, s);
1064 umodpoly one(1, a[0].ring()->one());
1065 umodpoly c = a; normalize_in_field(c);
1066 umodpoly d = b; normalize_in_field(d);
1074 umodpoly r = c - q * d;
1075 umodpoly r1 = s - q * d1;
1076 umodpoly r2 = t - q * d2;
1080 if ( r.empty() ) break;
1085 cl_MI fac = recip(lcoeff(a) * lcoeff(c));
1086 umodpoly::iterator i = s.begin(), end = s.end();
1087 for ( ; i!=end; ++i ) {
1091 fac = recip(lcoeff(b) * lcoeff(c));
1092 i = t.begin(), end = t.end();
1093 for ( ; i!=end; ++i ) {
1099 static upoly replace_lc(const upoly& poly, const cl_I& lc)
1101 if ( poly.empty() ) return poly;
1107 static void hensel_univar(const upoly& a_, unsigned int p, const umodpoly& u1_, const umodpoly& w1_, upoly& u, upoly& w)
1110 const cl_modint_ring& R = u1_[0].ring();
1114 for ( int i=degree(a); i>=0; --i ) {
1115 maxcoeff = maxcoeff + square(abs(a[i]));
1117 cl_I normmc = ceiling1(the<cl_R>(cln::sqrt(maxcoeff)));
1118 cl_I maxdegree = (degree(u1_) > degree(w1_)) ? degree(u1_) : degree(w1_);
1119 cl_I B = normmc * expt_pos(cl_I(2), maxdegree);
1122 cl_I alpha = lcoeff(a);
1125 normalize_in_field(nu1);
1127 normalize_in_field(nw1);
1129 phi = umodpoly_to_upoly(nu1) * alpha;
1131 umodpoly_from_upoly(u1, phi, R);
1132 phi = umodpoly_to_upoly(nw1) * alpha;
1134 umodpoly_from_upoly(w1, phi, R);
1139 exteuclid(u1, w1, s, t);
1142 u = replace_lc(umodpoly_to_upoly(u1), alpha);
1143 w = replace_lc(umodpoly_to_upoly(w1), alpha);
1144 upoly e = a - u * w;
1146 const cl_I maxmodulus = 2*B*abs(alpha);
1149 while ( !e.empty() && modulus < maxmodulus ) {
1150 // ad-hoc divisablity check
1151 for ( size_t k=0; k<e.size(); ++k ) {
1152 if ( !zerop(mod(e[k], modulus)) ) {
1156 upoly c = e / modulus;
1157 phi = umodpoly_to_upoly(s) * c;
1158 umodpoly sigmatilde;
1159 umodpoly_from_upoly(sigmatilde, phi, R);
1160 phi = umodpoly_to_upoly(t) * c;
1162 umodpoly_from_upoly(tautilde, phi, R);
1164 remdiv(sigmatilde, w1, r, q);
1166 phi = umodpoly_to_upoly(tautilde) + umodpoly_to_upoly(q) * umodpoly_to_upoly(u1);
1168 umodpoly_from_upoly(tau, phi, R);
1169 u = u + umodpoly_to_upoly(tau) * modulus;
1170 w = w + umodpoly_to_upoly(sigma) * modulus;
1172 modulus = modulus * p;
1179 for ( size_t i=1; i<u.size(); ++i ) {
1181 if ( g == 1 ) break;
1196 static unsigned int next_prime(unsigned int p)
1198 static vector<unsigned int> primes;
1199 if ( primes.size() == 0 ) {
1200 primes.push_back(3); primes.push_back(5); primes.push_back(7);
1202 vector<unsigned int>::const_iterator it = primes.begin();
1203 if ( p >= primes.back() ) {
1204 unsigned int candidate = primes.back() + 2;
1206 size_t n = primes.size()/2;
1207 for ( size_t i=0; i<n; ++i ) {
1208 if ( candidate % primes[i] ) continue;
1212 primes.push_back(candidate);
1213 if ( candidate > p ) break;
1217 vector<unsigned int>::const_iterator end = primes.end();
1218 for ( ; it!=end; ++it ) {
1223 throw logic_error("next_prime: should not reach this point!");
1226 class factor_partition
1229 factor_partition(const upvec& factors_) : factors(factors_)
1235 one.resize(1, factors.front()[0].ring()->one());
1238 int operator[](size_t i) const { return k[i]; }
1239 size_t size() const { return n; }
1240 size_t size_first() const { return n-sum; }
1241 size_t size_second() const { return sum; }
1243 void get() const { DCOUTVAR(k); }
1247 for ( size_t i=n-1; i>=1; --i ) {
1268 for ( size_t i=0; i<n; ++i ) {
1270 right = right * factors[i];
1273 left = left * factors[i];
1278 umodpoly left, right;
1292 static ex factor_univariate(const ex& poly, const ex& x)
1294 ex unit, cont, prim_ex;
1295 poly.unitcontprim(x, unit, cont, prim_ex);
1297 upoly_from_ex(prim, prim_ex, x);
1299 // determine proper prime and minimize number of modular factors
1300 unsigned int p = 3, lastp = 3;
1302 unsigned int trials = 0;
1303 unsigned int minfactors = 0;
1304 cl_I lc = lcoeff(prim);
1306 while ( trials < 2 ) {
1310 if ( !zerop(rem(lc, p)) ) {
1311 R = find_modint_ring(p);
1312 umodpoly_from_upoly(modpoly, prim, R);
1313 if ( squarefree(modpoly) ) break;
1317 // do modular factorization
1319 factor_modular(modpoly, trialfactors);
1320 if ( trialfactors.size() <= 1 ) {
1321 // irreducible for sure
1325 if ( minfactors == 0 || trialfactors.size() < minfactors ) {
1326 factors = trialfactors;
1327 minfactors = factors.size();
1336 R = find_modint_ring(p);
1338 // lift all factor combinations
1339 stack<ModFactors> tocheck;
1342 mf.factors = factors;
1346 while ( tocheck.size() ) {
1347 const size_t n = tocheck.top().factors.size();
1348 factor_partition part(tocheck.top().factors);
1350 hensel_univar(tocheck.top().poly, p, part.left, part.right, f1, f2);
1351 if ( !f1.empty() ) {
1352 if ( part.size_first() == 1 ) {
1353 if ( part.size_second() == 1 ) {
1354 result *= upoly_to_ex(f1, x) * upoly_to_ex(f2, x);
1358 result *= upoly_to_ex(f1, x);
1359 tocheck.top().poly = f2;
1360 for ( size_t i=0; i<n; ++i ) {
1361 if ( part[i] == 0 ) {
1362 tocheck.top().factors.erase(tocheck.top().factors.begin()+i);
1368 else if ( part.size_second() == 1 ) {
1369 if ( part.size_first() == 1 ) {
1370 result *= upoly_to_ex(f1, x) * upoly_to_ex(f2, x);
1374 result *= upoly_to_ex(f2, x);
1375 tocheck.top().poly = f1;
1376 for ( size_t i=0; i<n; ++i ) {
1377 if ( part[i] == 1 ) {
1378 tocheck.top().factors.erase(tocheck.top().factors.begin()+i);
1385 upvec newfactors1(part.size_first()), newfactors2(part.size_second());
1386 upvec::iterator i1 = newfactors1.begin(), i2 = newfactors2.begin();
1387 for ( size_t i=0; i<n; ++i ) {
1389 *i2++ = tocheck.top().factors[i];
1392 *i1++ = tocheck.top().factors[i];
1395 tocheck.top().factors = newfactors1;
1396 tocheck.top().poly = f1;
1398 mf.factors = newfactors2;
1405 if ( !part.next() ) {
1406 result *= upoly_to_ex(tocheck.top().poly, x);
1414 return unit * cont * result;
1423 // forward declaration
1424 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);
1426 upvec multiterm_eea_lift(const upvec& a, const ex& x, unsigned int p, unsigned int k)
1428 const size_t r = a.size();
1429 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1432 for ( size_t j=r-2; j>=1; --j ) {
1433 q[j-1] = a[j] * q[j];
1435 umodpoly beta(1, R->one());
1437 for ( size_t j=1; j<r; ++j ) {
1438 vector<ex> mdarg(2);
1439 mdarg[0] = umodpoly_to_ex(q[j-1], x);
1440 mdarg[1] = umodpoly_to_ex(a[j-1], x);
1441 vector<EvalPoint> empty;
1442 vector<ex> exsigma = multivar_diophant(mdarg, x, umodpoly_to_ex(beta, x), empty, 0, p, k);
1444 umodpoly_from_ex(sigma1, exsigma[0], x, R);
1446 umodpoly_from_ex(sigma2, exsigma[1], x, R);
1448 s.push_back(sigma2);
1455 * Assert: a not empty.
1457 void change_modulus(const cl_modint_ring& R, umodpoly& a)
1459 if ( a.empty() ) return;
1460 cl_modint_ring oldR = a[0].ring();
1461 umodpoly::iterator i = a.begin(), end = a.end();
1462 for ( ; i!=end; ++i ) {
1463 *i = R->canonhom(oldR->retract(*i));
1468 void eea_lift(const umodpoly& a, const umodpoly& b, const ex& x, unsigned int p, unsigned int k, umodpoly& s_, umodpoly& t_)
1470 cl_modint_ring R = find_modint_ring(p);
1472 change_modulus(R, amod);
1474 change_modulus(R, bmod);
1478 exteuclid(amod, bmod, smod, tmod);
1480 cl_modint_ring Rpk = find_modint_ring(expt_pos(cl_I(p),k));
1482 change_modulus(Rpk, s);
1484 change_modulus(Rpk, t);
1487 umodpoly one(1, Rpk->one());
1488 for ( size_t j=1; j<k; ++j ) {
1489 umodpoly e = one - a * s - b * t;
1490 reduce_coeff(e, modulus);
1492 change_modulus(R, c);
1493 umodpoly sigmabar = smod * c;
1494 umodpoly taubar = tmod * c;
1496 remdiv(sigmabar, bmod, sigma, q);
1497 umodpoly tau = taubar + q * amod;
1498 umodpoly sadd = sigma;
1499 change_modulus(Rpk, sadd);
1500 cl_MI modmodulus(Rpk, modulus);
1501 s = s + sadd * modmodulus;
1502 umodpoly tadd = tau;
1503 change_modulus(Rpk, tadd);
1504 t = t + tadd * modmodulus;
1505 modulus = modulus * p;
1511 upvec univar_diophant(const upvec& a, const ex& x, unsigned int m, unsigned int p, unsigned int k)
1513 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1515 const size_t r = a.size();
1518 upvec s = multiterm_eea_lift(a, x, p, k);
1519 for ( size_t j=0; j<r; ++j ) {
1520 umodpoly bmod = umodpoly_to_umodpoly(s[j], R, m);
1522 rem(bmod, a[j], buf);
1523 result.push_back(buf);
1528 eea_lift(a[1], a[0], x, p, k, s, t);
1529 umodpoly bmod = umodpoly_to_umodpoly(s, R, m);
1531 remdiv(bmod, a[0], buf, q);
1532 result.push_back(buf);
1533 umodpoly t1mod = umodpoly_to_umodpoly(t, R, m);
1534 buf = t1mod + q * a[1];
1535 result.push_back(buf);
1541 struct make_modular_map : public map_function {
1543 make_modular_map(const cl_modint_ring& R_) : R(R_) { }
1544 ex operator()(const ex& e)
1546 if ( is_a<add>(e) || is_a<mul>(e) ) {
1547 return e.map(*this);
1549 else if ( is_a<numeric>(e) ) {
1550 numeric mod(R->modulus);
1551 numeric halfmod = (mod-1)/2;
1552 cl_MI emod = R->canonhom(the<cl_I>(ex_to<numeric>(e).to_cl_N()));
1553 numeric n(R->retract(emod));
1554 if ( n > halfmod ) {
1565 static ex make_modular(const ex& e, const cl_modint_ring& R)
1567 make_modular_map map(R);
1568 return map(e.expand());
1571 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)
1575 const cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1576 const size_t r = a.size();
1577 const size_t nu = I.size() + 1;
1581 ex xnu = I.back().x;
1582 int alphanu = I.back().evalpoint;
1585 for ( size_t i=0; i<r; ++i ) {
1589 for ( size_t i=0; i<r; ++i ) {
1590 b[i] = normal(A / a[i]);
1593 vector<ex> anew = a;
1594 for ( size_t i=0; i<r; ++i ) {
1595 anew[i] = anew[i].subs(xnu == alphanu);
1597 ex cnew = c.subs(xnu == alphanu);
1598 vector<EvalPoint> Inew = I;
1600 sigma = multivar_diophant(anew, x, cnew, Inew, d, p, k);
1603 for ( size_t i=0; i<r; ++i ) {
1604 buf -= sigma[i] * b[i];
1606 ex e = make_modular(buf, R);
1609 for ( size_t m=1; m<=d; ++m ) {
1610 while ( !e.is_zero() && e.has(xnu) ) {
1611 monomial *= (xnu - alphanu);
1612 monomial = expand(monomial);
1613 ex cm = e.diff(ex_to<symbol>(xnu), m).subs(xnu==alphanu) / factorial(m);
1614 cm = make_modular(cm, R);
1615 if ( !cm.is_zero() ) {
1616 vector<ex> delta_s = multivar_diophant(anew, x, cm, Inew, d, p, k);
1618 for ( size_t j=0; j<delta_s.size(); ++j ) {
1619 delta_s[j] *= monomial;
1620 sigma[j] += delta_s[j];
1621 buf -= delta_s[j] * b[j];
1623 e = make_modular(buf, R);
1630 for ( size_t i=0; i<a.size(); ++i ) {
1632 umodpoly_from_ex(up, a[i], x, R);
1636 sigma.insert(sigma.begin(), r, 0);
1639 if ( is_a<add>(c) ) {
1647 for ( size_t i=0; i<nterms; ++i ) {
1648 int m = z.degree(x);
1649 cl_I cm = the<cl_I>(ex_to<numeric>(z.lcoeff(x)).to_cl_N());
1650 upvec delta_s = univar_diophant(amod, x, m, p, k);
1653 while ( poscm < 0 ) {
1654 poscm = poscm + expt_pos(cl_I(p),k);
1656 modcm = cl_MI(R, poscm);
1657 for ( size_t j=0; j<delta_s.size(); ++j ) {
1658 delta_s[j] = delta_s[j] * modcm;
1659 sigma[j] = sigma[j] + umodpoly_to_ex(delta_s[j], x);
1667 for ( size_t i=0; i<sigma.size(); ++i ) {
1668 sigma[i] = make_modular(sigma[i], R);
1675 ostream& operator<<(ostream& o, const vector<EvalPoint>& v)
1677 for ( size_t i=0; i<v.size(); ++i ) {
1678 o << "(" << v[i].x << "==" << v[i].evalpoint << ") ";
1682 #endif // def DEBUGFACTOR
1684 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)
1686 const size_t nu = I.size() + 1;
1687 const cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),l));
1692 for ( size_t j=nu; j>=2; --j ) {
1694 int alpha = I[j-2].evalpoint;
1695 A[j-2] = A[j-1].subs(x==alpha);
1696 A[j-2] = make_modular(A[j-2], R);
1699 int maxdeg = a.degree(I.front().x);
1700 for ( size_t i=1; i<I.size(); ++i ) {
1701 int maxdeg2 = a.degree(I[i].x);
1702 if ( maxdeg2 > maxdeg ) maxdeg = maxdeg2;
1705 const size_t n = u.size();
1707 for ( size_t i=0; i<n; ++i ) {
1708 U[i] = umodpoly_to_ex(u[i], x);
1711 for ( size_t j=2; j<=nu; ++j ) {
1714 for ( size_t m=0; m<n; ++m) {
1715 if ( lcU[m] != 1 ) {
1717 for ( size_t i=j-1; i<nu-1; ++i ) {
1718 coef = coef.subs(I[i].x == I[i].evalpoint);
1720 coef = make_modular(coef, R);
1721 int deg = U[m].degree(x);
1722 U[m] = U[m] - U[m].lcoeff(x) * pow(x,deg) + coef * pow(x,deg);
1726 for ( size_t i=0; i<n; ++i ) {
1729 ex e = expand(A[j-1] - Uprod);
1731 vector<EvalPoint> newI;
1732 for ( size_t i=1; i<=j-2; ++i ) {
1733 newI.push_back(I[i-1]);
1737 int alphaj = I[j-2].evalpoint;
1738 size_t deg = A[j-1].degree(xj);
1739 for ( size_t k=1; k<=deg; ++k ) {
1740 if ( !e.is_zero() ) {
1741 monomial *= (xj - alphaj);
1742 monomial = expand(monomial);
1743 ex dif = e.diff(ex_to<symbol>(xj), k);
1744 ex c = dif.subs(xj==alphaj) / factorial(k);
1745 if ( !c.is_zero() ) {
1746 vector<ex> deltaU = multivar_diophant(U1, x, c, newI, maxdeg, p, cl_I_to_uint(l));
1747 for ( size_t i=0; i<n; ++i ) {
1748 deltaU[i] *= monomial;
1750 U[i] = make_modular(U[i], R);
1753 for ( size_t i=0; i<n; ++i ) {
1757 e = make_modular(e, R);
1764 for ( size_t i=0; i<U.size(); ++i ) {
1767 if ( expand(a-acand).is_zero() ) {
1769 for ( size_t i=0; i<U.size(); ++i ) {
1780 static ex put_factors_into_lst(const ex& e)
1784 if ( is_a<numeric>(e) ) {
1788 if ( is_a<power>(e) ) {
1790 result.append(e.op(0));
1791 result.append(e.op(1));
1794 if ( is_a<symbol>(e) || is_a<add>(e) ) {
1800 if ( is_a<mul>(e) ) {
1802 for ( size_t i=0; i<e.nops(); ++i ) {
1804 if ( is_a<numeric>(op) ) {
1807 if ( is_a<power>(op) ) {
1808 result.append(op.op(0));
1809 result.append(op.op(1));
1811 if ( is_a<symbol>(op) || is_a<add>(op) ) {
1816 result.prepend(nfac);
1819 throw runtime_error("put_factors_into_lst: bad term.");
1823 ostream& operator<<(ostream& o, const vector<numeric>& v)
1825 for ( size_t i=0; i<v.size(); ++i ) {
1830 #endif // def DEBUGFACTOR
1832 static bool checkdivisors(const lst& f, vector<numeric>& d)
1834 const int k = f.nops()-2;
1836 d[0] = ex_to<numeric>(f.op(0) * f.op(f.nops()-1));
1837 if ( d[0] == 1 && k == 1 && abs(f.op(1)) != 1 ) {
1840 for ( int i=1; i<=k; ++i ) {
1841 q = ex_to<numeric>(abs(f.op(i)));
1842 for ( int j=i-1; j>=0; --j ) {
1857 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)
1859 // computation of d is actually not necessary
1860 const ex& x = *syms.begin();
1866 exset::const_iterator s = syms.begin();
1868 for ( size_t i=0; i<a.size(); ++i ) {
1870 a[i] = mod(numeric(rand()), 2*modulus) - modulus;
1871 vnatry = vna.subs(*s == a[i]);
1872 } while ( vnatry == 0 );
1874 u0 = u0.subs(*s == a[i]);
1877 if ( gcd(u0,u0.diff(ex_to<symbol>(x))) != 1 ) {
1880 if ( is_a<numeric>(vn) ) {
1885 lst::const_iterator i = ex_to<lst>(f).begin();
1887 bool problem = false;
1888 while ( i!=ex_to<lst>(f).end() ) {
1890 if ( !is_a<numeric>(fs) ) {
1893 for ( size_t j=0; j<a.size(); ++j ) {
1894 fs = fs.subs(*s == a[j]);
1897 if ( abs(fs) == 1 ) {
1908 ex con = u0.content(x);
1910 trying = checkdivisors(fnum, d);
1916 static ex factor_multivariate(const ex& poly, const exset& syms)
1918 exset::const_iterator s;
1919 const ex& x = *syms.begin();
1921 /* make polynomial primitive */
1922 ex p = poly.expand().collect(x);
1923 ex cont = p.lcoeff(x);
1924 for ( numeric i=p.degree(x)-1; i>=p.ldegree(x); --i ) {
1925 cont = gcd(cont, p.coeff(x,ex_to<numeric>(i).to_int()));
1926 if ( cont == 1 ) break;
1928 ex pp = expand(normal(p / cont));
1929 if ( !is_a<numeric>(cont) ) {
1930 return factor(cont) * factor(pp);
1933 /* factor leading coefficient */
1935 ex vn = pp.lcoeff(x);
1938 if ( is_a<numeric>(vn) ) {
1942 ex vnfactors = factor(vn);
1943 vnlst = put_factors_into_lst(vnfactors);
1946 const numeric maxtrials = 3;
1947 numeric modulus = (vnlst.nops()-1 > 3) ? vnlst.nops()-1 : 3;
1948 numeric minimalr = -1;
1949 vector<numeric> a(syms.size()-1, 0);
1950 vector<numeric> d((vnlst.nops()-1)/2+1, 0);
1953 numeric trialcount = 0;
1955 unsigned int prime = 3;
1956 size_t factor_count = 0;
1959 while ( trialcount < maxtrials ) {
1960 bool problem = generate_set(pp, vn, syms, vnlst, modulus, a, d);
1968 for ( size_t i=0; i<a.size(); ++i ) {
1969 u = u.subs(*s == a[i]);
1972 delta = u.content(x);
1974 // determine proper prime
1976 cl_modint_ring R = find_modint_ring(prime);
1978 if ( irem(ex_to<numeric>(u.lcoeff(x)), prime) != 0 ) {
1980 umodpoly_from_ex(modpoly, u, x, R);
1981 if ( squarefree(modpoly) ) break;
1983 prime = next_prime(prime);
1984 R = find_modint_ring(prime);
1988 ufaclst = put_factors_into_lst(ufac);
1989 factor_count = (ufaclst.nops()-1)/2;
1991 // veto factorization for which gcd(u_i, u_j) != 1 for all i,j
1993 for ( size_t i=0; i<(ufaclst.nops()-1)/2; ++i ) {
1995 umodpoly_from_ex(newu, ufaclst.op(i*2+1), x, R);
1996 tryu.push_back(newu);
1999 for ( size_t i=0; i<tryu.size()-1; ++i ) {
2000 for ( size_t j=i+1; j<tryu.size(); ++j ) {
2002 gcd(tryu[i], tryu[j], tryg);
2003 if ( unequal_one(tryg) ) {
2005 goto escape_quickly;
2014 if ( factor_count <= 1 ) {
2018 if ( minimalr < 0 ) {
2019 minimalr = factor_count;
2021 else if ( minimalr == factor_count ) {
2025 else if ( minimalr > factor_count ) {
2026 minimalr = factor_count;
2029 if ( minimalr <= 1 ) {
2034 vector<numeric> ftilde((vnlst.nops()-1)/2+1);
2035 ftilde[0] = ex_to<numeric>(vnlst.op(0));
2036 for ( size_t i=1; i<ftilde.size(); ++i ) {
2037 ex ft = vnlst.op((i-1)*2+1);
2040 for ( size_t j=0; j<a.size(); ++j ) {
2041 ft = ft.subs(*s == a[j]);
2044 ftilde[i] = ex_to<numeric>(ft);
2047 vector<bool> used_flag((vnlst.nops()-1)/2+1, false);
2048 vector<ex> D(factor_count, 1);
2049 for ( size_t i=0; i<=factor_count; ++i ) {
2052 prefac = ex_to<numeric>(ufaclst.op(0));
2053 ftilde[0] = ftilde[0] / prefac;
2054 vnlst.let_op(0) = vnlst.op(0) / prefac;
2058 prefac = ex_to<numeric>(ufaclst.op(2*(i-1)+1).lcoeff(x));
2060 for ( size_t j=(vnlst.nops()-1)/2+1; j>0; --j ) {
2061 if ( abs(ftilde[j-1]) == 1 ) {
2062 used_flag[j-1] = true;
2065 numeric g = gcd(prefac, ftilde[j-1]);
2067 prefac = prefac / g;
2068 numeric count = abs(iquo(g, ftilde[j-1]));
2069 used_flag[j-1] = true;
2072 D[i-1] = D[i-1] * pow(vnlst.op(0), count);
2075 D[i-1] = D[i-1] * pow(vnlst.op(2*(j-2)+1), count);
2079 ftilde[j-1] = ftilde[j-1] / prefac;
2087 bool some_factor_unused = false;
2088 for ( size_t i=0; i<used_flag.size(); ++i ) {
2089 if ( !used_flag[i] ) {
2090 some_factor_unused = true;
2094 if ( some_factor_unused ) {
2098 vector<ex> C(factor_count);
2100 for ( size_t i=0; i<D.size(); ++i ) {
2104 for ( size_t j=0; j<a.size(); ++j ) {
2105 Dtilde = Dtilde.subs(*s == a[j]);
2108 C[i] = D[i] * (ufaclst.op(2*i+1).lcoeff(x) / Dtilde);
2112 for ( size_t i=0; i<D.size(); ++i ) {
2116 for ( size_t j=0; j<a.size(); ++j ) {
2117 Dtilde = Dtilde.subs(*s == a[j]);
2125 ui = ufaclst.op(2*(i-1)+1);
2128 ex d = gcd(ui.lcoeff(x), Dtilde);
2129 C[i] = D[i] * ( ui.lcoeff(x) / d );
2130 ui = ui * ( Dtilde[i] / d );
2131 delta = delta / ( Dtilde[i] / d );
2132 if ( delta == 1 ) break;
2134 C[i] = delta * C[i];
2135 pp = pp * pow(delta, D.size()-1);
2141 vector<EvalPoint> epv;
2144 for ( size_t i=0; i<a.size(); ++i ) {
2146 ep.evalpoint = a[i].to_int();
2152 for ( int i=u.degree(x); i>=u.ldegree(x); --i ) {
2153 maxcoeff += pow(abs(u.coeff(x, i)),2);
2155 cl_I normmc = ceiling1(the<cl_R>(cln::sqrt(ex_to<numeric>(maxcoeff).to_cl_N())));
2156 unsigned int maxdegree = 0;
2157 for ( size_t i=0; i<factor_count; ++i ) {
2158 if ( ufaclst[2*i+1].degree(x) > (int)maxdegree ) {
2159 maxdegree = ufaclst[2*i+1].degree(x);
2162 cl_I B = normmc * expt_pos(cl_I(2), maxdegree);
2171 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(prime),l));
2172 for ( size_t i=0; i<(ufaclst.nops()-1)/2; ++i ) {
2174 umodpoly_from_ex(newu, ufaclst.op(i*2+1), x, R);
2175 uvec.push_back(newu);
2178 ex res = hensel_multivar(ufaclst.op(0)*pp, x, epv, prime, l, uvec, C);
2179 if ( res != lst() ) {
2180 ex result = cont * ufaclst.op(0);
2181 for ( size_t i=0; i<res.nops(); ++i ) {
2182 result *= res.op(i).content(x) * res.op(i).unit(x);
2183 result *= res.op(i).primpart(x);
2190 struct find_symbols_map : public map_function {
2192 ex operator()(const ex& e)
2194 if ( is_a<symbol>(e) ) {
2198 return e.map(*this);
2202 static ex factor_sqrfree(const ex& poly)
2204 // determine all symbols in poly
2205 find_symbols_map findsymbols;
2207 if ( findsymbols.syms.size() == 0 ) {
2211 if ( findsymbols.syms.size() == 1 ) {
2213 const ex& x = *(findsymbols.syms.begin());
2214 if ( poly.ldegree(x) > 0 ) {
2215 int ld = poly.ldegree(x);
2216 ex res = factor_univariate(expand(poly/pow(x, ld)), x);
2217 return res * pow(x,ld);
2220 ex res = factor_univariate(poly, x);
2225 // multivariate case
2226 ex res = factor_multivariate(poly, findsymbols.syms);
2230 struct apply_factor_map : public map_function {
2232 apply_factor_map(unsigned options_) : options(options_) { }
2233 ex operator()(const ex& e)
2235 if ( e.info(info_flags::polynomial) ) {
2236 return factor(e, options);
2238 if ( is_a<add>(e) ) {
2240 for ( size_t i=0; i<e.nops(); ++i ) {
2241 if ( e.op(i).info(info_flags::polynomial) ) {
2250 return factor(s1, options) + s2.map(*this);
2252 return e.map(*this);
2256 } // anonymous namespace
2258 ex factor(const ex& poly, unsigned options)
2261 if ( !poly.info(info_flags::polynomial) ) {
2262 if ( options & factor_options::all ) {
2263 options &= ~factor_options::all;
2264 apply_factor_map factor_map(options);
2265 return factor_map(poly);
2270 // determine all symbols in poly
2271 find_symbols_map findsymbols;
2273 if ( findsymbols.syms.size() == 0 ) {
2277 exset::const_iterator i=findsymbols.syms.begin(), end=findsymbols.syms.end();
2278 for ( ; i!=end; ++i ) {
2282 // make poly square free
2283 ex sfpoly = sqrfree(poly, syms);
2285 // factorize the square free components
2286 if ( is_a<power>(sfpoly) ) {
2287 // case: (polynomial)^exponent
2288 const ex& base = sfpoly.op(0);
2289 if ( !is_a<add>(base) ) {
2290 // simple case: (monomial)^exponent
2293 ex f = factor_sqrfree(base);
2294 return pow(f, sfpoly.op(1));
2296 if ( is_a<mul>(sfpoly) ) {
2297 // case: multiple factors
2299 for ( size_t i=0; i<sfpoly.nops(); ++i ) {
2300 const ex& t = sfpoly.op(i);
2301 if ( is_a<power>(t) ) {
2302 const ex& base = t.op(0);
2303 if ( !is_a<add>(base) ) {
2307 ex f = factor_sqrfree(base);
2308 res *= pow(f, t.op(1));
2311 else if ( is_a<add>(t) ) {
2312 ex f = factor_sqrfree(t);
2321 if ( is_a<symbol>(sfpoly) ) {
2324 // case: (polynomial)
2325 ex f = factor_sqrfree(sfpoly);
2329 } // namespace GiNaC