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
34 #include <ginac/ginac.h>
35 using namespace GiNaC;
41 #include "operators.h"
44 #include "relational.h"
68 #define DCOUT(str) cout << #str << endl
69 #define DCOUTVAR(var) cout << #var << ": " << var << endl
70 #define DCOUT2(str,var) cout << #str << ": " << var << endl
74 #define DCOUT2(str,var)
77 // forward declaration
78 ex factor(const ex& poly, unsigned options);
80 // anonymous namespace to hide all utility functions
83 typedef vector<cl_MI> mvec;
86 ostream& operator<<(ostream& o, const mvec& v)
88 mvec::const_iterator i = v.begin(), end = v.end();
94 #endif // def DEBUGFACTOR
97 ostream& operator<<(ostream& o, const vector<mvec>& v)
99 vector<mvec>::const_iterator i = v.begin(), end = v.end();
105 #endif // def DEBUGFACTOR
107 ////////////////////////////////////////////////////////////////////////////////
108 // modular univariate polynomial code
110 //typedef cl_UP_MI umod;
111 typedef std::vector<cln::cl_MI> umodpoly;
112 //typedef vector<umod> umodvec;
113 typedef vector<umodpoly> upvec;
115 // COPY FROM UPOLY.HPP
117 // CHANGED size_t -> int !!!
118 template<typename T> static int degree(const T& p)
123 template<typename T> static typename T::value_type lcoeff(const T& p)
125 return p[p.size() - 1];
128 static bool normalize_in_field(umodpoly& a)
132 if ( lcoeff(a) == a[0].ring()->one() ) {
136 const cln::cl_MI lc_1 = recip(lcoeff(a));
137 for (std::size_t k = a.size(); k-- != 0; )
142 template<typename T> static void
143 canonicalize(T& p, const typename T::size_type hint = std::numeric_limits<typename T::size_type>::max())
148 std::size_t i = p.size() - 1;
149 // Be fast if the polynomial is already canonicalized
156 bool is_zero = false;
174 p.erase(p.begin() + i, p.end());
177 // END COPY FROM UPOLY.HPP
179 static void expt_pos(const umodpoly& a, unsigned int q, umodpoly& b)
181 throw runtime_error("expt_pos: not implemented!");
182 // code below is not correct!
184 // if ( a.empty() ) return;
185 // b.resize(degree(a)*q+1, a[0].ring()->zero());
186 // cl_MI norm = recip(a[0]);
188 // for ( size_t i=0; i<an.size(); ++i ) {
189 // an[i] = an[i] * norm;
191 // b[0] = a[0].ring()->one();
192 // for ( size_t i=1; i<b.size(); ++i ) {
193 // for ( size_t j=1; j<i; ++j ) {
194 // b[i] = b[i] + ((i-j+1)*q-i-1) * a[i-j] * b[j-1];
198 // cl_MI corr = expt_pos(a[0], q);
199 // for ( size_t i=0; i<b.size(); ++i ) {
200 // b[i] = b[i] * corr;
204 static umodpoly operator+(const umodpoly& a, const umodpoly& b)
211 for ( ; i<sb; ++i ) {
214 for ( ; i<sa; ++i ) {
223 for ( ; i<sa; ++i ) {
226 for ( ; i<sb; ++i ) {
234 static umodpoly operator-(const umodpoly& a, const umodpoly& b)
241 for ( ; i<sb; ++i ) {
244 for ( ; i<sa; ++i ) {
253 for ( ; i<sa; ++i ) {
256 for ( ; i<sb; ++i ) {
264 static umodpoly operator*(const umodpoly& a, const umodpoly& b)
267 if ( a.empty() || b.empty() ) return c;
269 int n = degree(a) + degree(b);
270 c.resize(n+1, a[0].ring()->zero());
271 for ( int i=0 ; i<=n; ++i ) {
272 for ( int j=0 ; j<=i; ++j ) {
273 if ( j > degree(a) || (i-j) > degree(b) ) continue; // TODO optimize!
274 c[i] = c[i] + a[j] * b[i-j];
281 static umodpoly operator*(const umodpoly& a, const cl_MI& x)
283 umodpoly r(a.size());
284 for ( size_t i=0; i<a.size(); ++i ) {
291 static void umodpoly_from_ex(umodpoly& ump, const ex& e, const ex& x, const cl_modint_ring& R)
293 // assert: e is in Z[x]
294 int deg = e.degree(x);
296 int ldeg = e.ldegree(x);
297 for ( ; deg>=ldeg; --deg ) {
298 cl_I coeff = the<cl_I>(ex_to<numeric>(e.coeff(x, deg)).to_cl_N());
299 ump[deg] = R->canonhom(coeff);
301 for ( ; deg>=0; --deg ) {
302 ump[deg] = R->zero();
307 static void umodpoly_from_ex(umodpoly& ump, const ex& e, const ex& x, const cl_I& modulus)
309 umodpoly_from_ex(ump, e, x, find_modint_ring(modulus));
312 static ex umod_to_ex(const umodpoly& a, const ex& x)
314 if ( a.empty() ) return 0;
315 cl_modint_ring R = a[0].ring();
316 cl_I mod = R->modulus;
317 cl_I halfmod = (mod-1) >> 1;
319 for ( int i=degree(a); i>=0; --i ) {
320 cl_I n = R->retract(a[i]);
322 e += numeric(n-mod) * pow(x, i);
324 e += numeric(n) * pow(x, i);
330 /** Divides all coefficients of the polynomial a by the integer x.
331 * All coefficients are supposed to be divisible by x. If they are not, the
332 * the<cl_I> cast will raise an exception.
334 * @param[in,out] a polynomial of which the coefficients will be reduced by x
335 * @param[in] x integer that divides the coefficients
337 static void reduce_coeff(umodpoly& a, const cl_I& x)
339 if ( a.empty() ) return;
341 cl_modint_ring R = a[0].ring();
342 umodpoly::iterator i = a.begin(), end = a.end();
343 for ( ; i!=end; ++i ) {
344 // cln cannot perform this division in the modular field
345 cl_I c = R->retract(*i);
346 *i = cl_MI(R, the<cl_I>(c / x));
350 /** Calculates remainder of a/b.
351 * Assertion: a and b not empty.
353 * @param[in] a polynomial dividend
354 * @param[in] b polynomial divisor
355 * @param[out] r polynomial remainder
357 static void rem(const umodpoly& a, const umodpoly& b, umodpoly& r)
366 cl_MI qk = div(r[n+k], b[n]);
368 for ( int i=0; i<n; ++i ) {
369 unsigned int j = n + k - 1 - i;
370 r[j] = r[j] - qk * b[j-k];
375 fill(r.begin()+n, r.end(), a[0].ring()->zero());
379 /** Calculates quotient of a/b.
380 * Assertion: a and b not empty.
382 * @param[in] a polynomial dividend
383 * @param[in] b polynomial divisor
384 * @param[out] q polynomial quotient
386 static void div(const umodpoly& a, const umodpoly& b, umodpoly& q)
395 q.resize(k+1, a[0].ring()->zero());
397 cl_MI qk = div(r[n+k], b[n]);
400 for ( int i=0; i<n; ++i ) {
401 unsigned int j = n + k - 1 - i;
402 r[j] = r[j] - qk * b[j-k];
410 /** Calculates quotient and remainder of a/b.
411 * Assertion: a and b not empty.
413 * @param[in] a polynomial dividend
414 * @param[in] b polynomial divisor
415 * @param[out] r polynomial remainder
416 * @param[out] q polynomial quotient
418 static void remdiv(const umodpoly& a, const umodpoly& b, umodpoly& r, umodpoly& q)
427 q.resize(k+1, a[0].ring()->zero());
429 cl_MI qk = div(r[n+k], b[n]);
432 for ( int i=0; i<n; ++i ) {
433 unsigned int j = n + k - 1 - i;
434 r[j] = r[j] - qk * b[j-k];
439 fill(r.begin()+n, r.end(), a[0].ring()->zero());
444 /** Calculates the GCD of polynomial a and b.
446 * @param[in] a polynomial
447 * @param[in] b polynomial
450 static void gcd(const umodpoly& a, const umodpoly& b, umodpoly& c)
452 if ( degree(a) < degree(b) ) return gcd(b, a, c);
455 normalize_in_field(c);
457 normalize_in_field(d);
459 while ( !d.empty() ) {
464 normalize_in_field(c);
467 /** Calculates the derivative of the polynomial a.
469 * @param[in] a polynomial of which to take the derivative
470 * @param[out] d result/derivative
472 static void deriv(const umodpoly& a, umodpoly& d)
475 if ( a.size() <= 1 ) return;
477 d.insert(d.begin(), a.begin()+1, a.end());
479 for ( int i=1; i<max; ++i ) {
485 static bool unequal_one(const umodpoly& a)
487 if ( a.empty() ) return true;
488 return ( a.size() != 1 || a[0] != a[0].ring()->one() );
491 static bool equal_one(const umodpoly& a)
493 return ( a.size() == 1 && a[0] == a[0].ring()->one() );
496 /** Returns true if polynomial a is square free.
498 * @param[in] a polynomial to check
499 * @return true if polynomial is square free, false otherwise
501 static bool squarefree(const umodpoly& a)
513 // END modular univariate polynomial code
514 ////////////////////////////////////////////////////////////////////////////////
516 ////////////////////////////////////////////////////////////////////////////////
521 friend ostream& operator<<(ostream& o, const modular_matrix& m);
523 modular_matrix(size_t r_, size_t c_, const cl_MI& init) : r(r_), c(c_)
527 size_t rowsize() const { return r; }
528 size_t colsize() const { return c; }
529 cl_MI& operator()(size_t row, size_t col) { return m[row*c + col]; }
530 cl_MI operator()(size_t row, size_t col) const { return m[row*c + col]; }
531 void mul_col(size_t col, const cl_MI x)
533 mvec::iterator i = m.begin() + col;
534 for ( size_t rc=0; rc<r; ++rc ) {
539 void sub_col(size_t col1, size_t col2, const cl_MI fac)
541 mvec::iterator i1 = m.begin() + col1;
542 mvec::iterator i2 = m.begin() + col2;
543 for ( size_t rc=0; rc<r; ++rc ) {
544 *i1 = *i1 - *i2 * fac;
549 void switch_col(size_t col1, size_t col2)
552 mvec::iterator i1 = m.begin() + col1;
553 mvec::iterator i2 = m.begin() + col2;
554 for ( size_t rc=0; rc<r; ++rc ) {
555 buf = *i1; *i1 = *i2; *i2 = buf;
560 void mul_row(size_t row, const cl_MI x)
562 vector<cl_MI>::iterator i = m.begin() + row*c;
563 for ( size_t cc=0; cc<c; ++cc ) {
568 void sub_row(size_t row1, size_t row2, const cl_MI fac)
570 vector<cl_MI>::iterator i1 = m.begin() + row1*c;
571 vector<cl_MI>::iterator i2 = m.begin() + row2*c;
572 for ( size_t cc=0; cc<c; ++cc ) {
573 *i1 = *i1 - *i2 * fac;
578 void switch_row(size_t row1, size_t row2)
581 vector<cl_MI>::iterator i1 = m.begin() + row1*c;
582 vector<cl_MI>::iterator i2 = m.begin() + row2*c;
583 for ( size_t cc=0; cc<c; ++cc ) {
584 buf = *i1; *i1 = *i2; *i2 = buf;
589 bool is_col_zero(size_t col) const
591 mvec::const_iterator i = m.begin() + col;
592 for ( size_t rr=0; rr<r; ++rr ) {
600 bool is_row_zero(size_t row) const
602 mvec::const_iterator i = m.begin() + row*c;
603 for ( size_t cc=0; cc<c; ++cc ) {
611 void set_row(size_t row, const vector<cl_MI>& newrow)
613 mvec::iterator i1 = m.begin() + row*c;
614 mvec::const_iterator i2 = newrow.begin(), end = newrow.end();
615 for ( ; i2 != end; ++i1, ++i2 ) {
619 mvec::const_iterator row_begin(size_t row) const { return m.begin()+row*c; }
620 mvec::const_iterator row_end(size_t row) const { return m.begin()+row*c+r; }
627 modular_matrix operator*(const modular_matrix& m1, const modular_matrix& m2)
629 const unsigned int r = m1.rowsize();
630 const unsigned int c = m2.colsize();
631 modular_matrix o(r,c,m1(0,0));
633 for ( size_t i=0; i<r; ++i ) {
634 for ( size_t j=0; j<c; ++j ) {
636 buf = m1(i,0) * m2(0,j);
637 for ( size_t k=1; k<c; ++k ) {
638 buf = buf + m1(i,k)*m2(k,j);
646 ostream& operator<<(ostream& o, const modular_matrix& m)
648 vector<cl_MI>::const_iterator i = m.m.begin(), end = m.m.end();
650 for ( ; i != end; ++i ) {
652 if ( !(wrap++ % m.c) ) {
659 #endif // def DEBUGFACTOR
661 // END modular matrix
662 ////////////////////////////////////////////////////////////////////////////////
664 static void q_matrix(const umodpoly& a, modular_matrix& Q)
667 unsigned int q = cl_I_to_uint(a[0].ring()->modulus);
669 // vector<cl_MI> r(n, a.R->zero());
670 // r[0] = a.R->one();
672 // unsigned int max = (n-1) * q;
673 // for ( size_t m=1; m<=max; ++m ) {
674 // cl_MI rn_1 = r.back();
675 // for ( size_t i=n-1; i>0; --i ) {
676 // r[i] = r[i-1] - rn_1 * a[i];
678 // r[0] = -rn_1 * a[0];
679 // if ( (m % q) == 0 ) {
680 // Q.set_row(m/q, r);
683 // slow and (hopefully) correct
684 cl_MI one = a[0].ring()->one();
685 cl_MI zero = a[0].ring()->zero();
686 for ( int i=0; i<n; ++i ) {
687 umodpoly qk(i*q+1, zero);
692 for ( int j=0; j<=degree(r); ++j ) {
699 static void nullspace(modular_matrix& M, vector<mvec>& basis)
701 const size_t n = M.rowsize();
702 const cl_MI one = M(0,0).ring()->one();
703 for ( size_t i=0; i<n; ++i ) {
704 M(i,i) = M(i,i) - one;
706 for ( size_t r=0; r<n; ++r ) {
708 for ( ; cc<n; ++cc ) {
709 if ( !zerop(M(r,cc)) ) {
711 if ( !zerop(M(cc,cc)) ) {
723 M.mul_col(r, recip(M(r,r)));
724 for ( cc=0; cc<n; ++cc ) {
726 M.sub_col(cc, r, M(r,cc));
732 for ( size_t i=0; i<n; ++i ) {
733 M(i,i) = M(i,i) - one;
735 for ( size_t i=0; i<n; ++i ) {
736 if ( !M.is_row_zero(i) ) {
737 mvec nu(M.row_begin(i), M.row_end(i));
743 static void berlekamp(const umodpoly& a, upvec& upv)
745 cl_modint_ring R = a[0].ring();
746 umodpoly one(1, R->one());
748 modular_matrix Q(degree(a), degree(a), R->zero());
752 const unsigned int k = nu.size();
757 list<umodpoly> factors;
758 factors.push_back(a);
759 unsigned int size = 1;
761 unsigned int q = cl_I_to_uint(R->modulus);
763 list<umodpoly>::iterator u = factors.begin();
766 for ( unsigned int s=0; s<q; ++s ) {
767 umodpoly nur = nu[r];
768 nur[0] = nur[0] - cl_MI(R, s);
772 if ( unequal_one(g) && g != *u ) {
775 if ( equal_one(uo) ) {
776 throw logic_error("berlekamp: unexpected divisor.");
781 factors.push_back(g);
783 list<umodpoly>::const_iterator i = factors.begin(), end = factors.end();
785 if ( degree(*i) ) ++size;
789 list<umodpoly>::const_iterator i = factors.begin(), end = factors.end();
804 static void rem_xq(int q, const umodpoly& b, umodpoly& c)
806 cl_modint_ring R = b[0].ring();
810 c.resize(q+1, R->zero());
816 c.resize(n+1, R->zero());
822 cl_MI qk = div(c[n-ofs], b[n]);
824 for ( int i=1; i<=n; ++i ) {
825 c[n-i+ofs] = c[n-i] - qk * b[n-i];
840 static void distinct_degree_factor(const umodpoly& a_, upvec& result)
844 cl_modint_ring R = a[0].ring();
845 int q = cl_I_to_int(R->modulus);
850 umodpoly w(1, R->one());
855 while ( i <= nhalf ) {
863 if ( unequal_one(ai.back()) ) {
864 div(a, ai.back(), a);
874 static void same_degree_factor(const umodpoly& a, upvec& result)
876 cl_modint_ring R = a[0].ring();
880 distinct_degree_factor(a, buf);
883 for ( size_t i=0; i<buf.size(); ++i ) {
884 if ( unequal_one(buf[i]) ) {
885 degsum += degree(buf[i]);
887 berlekamp(buf[i], upv);
888 for ( size_t j=0; j<upv.size(); ++j ) {
889 result.push_back(upv[j]);
894 if ( degsum < deg ) {
899 static void distinct_degree_factor_BSGS(const umodpoly& a, upvec& result)
901 cl_modint_ring R = a[0].ring();
902 int q = cl_I_to_int(R->modulus);
906 int l = cl_I_to_int(ceiling1(the<cl_F>(expt(n, pm))));
908 umodpoly qk(1, R->one());
910 for ( int i=1; i<=l; ++i ) {
911 expt_pos(h[i-1], q, qk);
915 int m = std::ceil(((double)n)/2/l);
917 int ql = std::pow(q, l);
919 for ( int i=1; i<m; ++i ) {
920 expt_pos(H[i-1], ql, qk);
925 umodpoly one(1, R->one());
926 for ( int i=0; i<m; ++i ) {
928 for ( int j=0; j<l; ++j ) {
929 I[i] = I[i] * (H[i] - h[j]);
936 for ( int i=0; i<m; ++i ) {
939 if ( g == one ) continue;
944 result.resize(n, one);
945 if ( unequal_one(f) ) {
948 for ( int i=0; i<m; ++i ) {
950 for ( int j=l-1; j>=0; --j ) {
952 gcd(f, H[i]-h[j], g);
953 result[l*(i+1)-j-1] = g;
959 static void cantor_zassenhaus(const umodpoly& a, upvec& result)
963 static void factor_modular(const umodpoly& p, upvec& upv)
965 //same_degree_factor(p, upv);
970 static void exteuclid(const umodpoly& a, const umodpoly& b, umodpoly& g, umodpoly& s, umodpoly& t)
972 if ( degree(a) < degree(b) ) {
973 exteuclid(b, a, g, t, s);
976 umodpoly one(1, a[0].ring()->one());
977 umodpoly c = a; normalize_in_field(c);
978 umodpoly d = b; normalize_in_field(d);
983 while ( !d.empty() ) {
986 umodpoly r = c - q * d;
987 umodpoly r1 = c1 - q * d1;
988 umodpoly r2 = c2 - q * d2;
996 g = c; normalize_in_field(g);
998 for ( int i=0; i<=degree(s); ++i ) {
999 s[i] = s[i] * recip(a[degree(a)] * c[degree(c)]);
1004 for ( int i=0; i<=degree(t); ++i ) {
1005 t[i] = t[i] * recip(b[degree(b)] * c[degree(c)]);
1011 static ex replace_lc(const ex& poly, const ex& x, const ex& lc)
1013 ex r = expand(poly + (lc - poly.lcoeff(x)) * pow(x, poly.degree(x)));
1017 static ex hensel_univar(const ex& a_, const ex& x, unsigned int p, const umodpoly& u1_, const umodpoly& w1_, const ex& gamma_ = 0)
1020 const cl_modint_ring& R = u1_[0].ring();
1024 for ( int i=a.degree(x); i>=a.ldegree(x); --i ) {
1025 maxcoeff += pow(abs(a.coeff(x, i)),2);
1027 cl_I normmc = ceiling1(the<cl_R>(cln::sqrt(ex_to<numeric>(maxcoeff).to_cl_N())));
1028 cl_I maxdegree = (degree(u1_) > degree(w1_)) ? degree(u1_) : degree(w1_);
1029 cl_I B = normmc * expt_pos(cl_I(2), maxdegree);
1032 ex alpha = a.lcoeff(x);
1037 numeric gamma_ui = ex_to<numeric>(abs(gamma));
1040 normalize_in_field(nu1);
1042 normalize_in_field(nw1);
1044 phi = gamma * umod_to_ex(nu1, x);
1046 umodpoly_from_ex(u1, phi, x, R);
1047 phi = alpha * umod_to_ex(nw1, x);
1049 umodpoly_from_ex(w1, phi, x, R);
1055 exteuclid(u1, w1, g, s, t);
1056 if ( unequal_one(g) ) {
1057 throw logic_error("gcd(u1,w1) != 1");
1061 ex u = replace_lc(umod_to_ex(u1, x), x, gamma);
1062 ex w = replace_lc(umod_to_ex(w1, x), x, alpha);
1063 ex e = expand(a - u * w);
1064 numeric modulus = p;
1065 const numeric maxmodulus = 2*numeric(B)*gamma_ui;
1068 while ( !e.is_zero() && modulus < maxmodulus ) {
1070 phi = expand(umod_to_ex(s, x) * c);
1071 umodpoly sigmatilde;
1072 umodpoly_from_ex(sigmatilde, phi, x, R);
1073 phi = expand(umod_to_ex(t, x) * c);
1075 umodpoly_from_ex(tautilde, phi, x, R);
1077 remdiv(sigmatilde, w1, r, q);
1079 phi = expand(umod_to_ex(tautilde, x) + umod_to_ex(q, x) * umod_to_ex(u1, x));
1081 umodpoly_from_ex(tau, phi, x, R);
1082 u = expand(u + umod_to_ex(tau, x) * modulus);
1083 w = expand(w + umod_to_ex(sigma, x) * modulus);
1084 e = expand(a - u * w);
1085 modulus = modulus * p;
1089 if ( e.is_zero() ) {
1090 ex delta = u.content(x);
1092 w = w / gamma * delta;
1100 static unsigned int next_prime(unsigned int p)
1102 static vector<unsigned int> primes;
1103 if ( primes.size() == 0 ) {
1104 primes.push_back(3); primes.push_back(5); primes.push_back(7);
1106 vector<unsigned int>::const_iterator it = primes.begin();
1107 if ( p >= primes.back() ) {
1108 unsigned int candidate = primes.back() + 2;
1110 size_t n = primes.size()/2;
1111 for ( size_t i=0; i<n; ++i ) {
1112 if ( candidate % primes[i] ) continue;
1116 primes.push_back(candidate);
1117 if ( candidate > p ) break;
1121 vector<unsigned int>::const_iterator end = primes.end();
1122 for ( ; it!=end; ++it ) {
1127 throw logic_error("next_prime: should not reach this point!");
1133 Partition(size_t n_) : n(n_)
1139 int operator[](size_t i) const { return k[i]; }
1140 size_t size() const { return n; }
1141 size_t size_first() const { return n-sum; }
1142 size_t size_second() const { return sum; }
1146 for ( size_t i=0; i<k.size(); ++i ) {
1147 cout << k[i] << " ";
1154 for ( size_t i=n-1; i>=1; --i ) {
1170 static void split(const upvec& factors, const Partition& part, umodpoly& a, umodpoly& b)
1172 umodpoly one(1, factors.front()[0].ring()->one());
1175 for ( size_t i=0; i<part.size(); ++i ) {
1191 static ex factor_univariate(const ex& poly, const ex& x)
1193 ex unit, cont, prim;
1194 poly.unitcontprim(x, unit, cont, prim);
1196 // determine proper prime and minimize number of modular factors
1197 unsigned int p = 3, lastp = 3;
1199 unsigned int trials = 0;
1200 unsigned int minfactors = 0;
1201 numeric lcoeff = ex_to<numeric>(prim.lcoeff(x));
1203 while ( trials < 2 ) {
1206 if ( irem(lcoeff, p) != 0 ) {
1207 R = find_modint_ring(p);
1209 umodpoly_from_ex(modpoly, prim, x, R);
1210 if ( squarefree(modpoly) ) break;
1214 // do modular factorization
1216 umodpoly_from_ex(modpoly, prim, x, R);
1218 factor_modular(modpoly, trialfactors);
1219 if ( trialfactors.size() <= 1 ) {
1220 // irreducible for sure
1224 if ( minfactors == 0 || trialfactors.size() < minfactors ) {
1225 factors = trialfactors;
1226 minfactors = factors.size();
1235 R = find_modint_ring(p);
1236 cl_univpoly_modint_ring UPR = find_univpoly_ring(R);
1238 // lift all factor combinations
1239 stack<ModFactors> tocheck;
1242 mf.factors = factors;
1245 while ( tocheck.size() ) {
1246 const size_t n = tocheck.top().factors.size();
1250 split(tocheck.top().factors, part, a, b);
1252 ex answer = hensel_univar(tocheck.top().poly, x, p, a, b);
1253 if ( answer != lst() ) {
1254 if ( part.size_first() == 1 ) {
1255 if ( part.size_second() == 1 ) {
1256 result *= answer.op(0) * answer.op(1);
1260 result *= answer.op(0);
1261 tocheck.top().poly = answer.op(1);
1262 for ( size_t i=0; i<n; ++i ) {
1263 if ( part[i] == 0 ) {
1264 tocheck.top().factors.erase(tocheck.top().factors.begin()+i);
1270 else if ( part.size_second() == 1 ) {
1271 if ( part.size_first() == 1 ) {
1272 result *= answer.op(0) * answer.op(1);
1276 result *= answer.op(1);
1277 tocheck.top().poly = answer.op(0);
1278 for ( size_t i=0; i<n; ++i ) {
1279 if ( part[i] == 1 ) {
1280 tocheck.top().factors.erase(tocheck.top().factors.begin()+i);
1287 upvec newfactors1(part.size_first()), newfactors2(part.size_second());
1288 upvec::iterator i1 = newfactors1.begin(), i2 = newfactors2.begin();
1289 for ( size_t i=0; i<n; ++i ) {
1291 *i2++ = tocheck.top().factors[i];
1294 *i1++ = tocheck.top().factors[i];
1297 tocheck.top().factors = newfactors1;
1298 tocheck.top().poly = answer.op(0);
1300 mf.factors = newfactors2;
1301 mf.poly = answer.op(1);
1307 if ( !part.next() ) {
1308 result *= tocheck.top().poly;
1316 return unit * cont * result;
1325 // forward declaration
1326 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);
1328 upvec multiterm_eea_lift(const upvec& a, const ex& x, unsigned int p, unsigned int k)
1330 const size_t r = a.size();
1331 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1334 for ( size_t j=r-2; j>=1; --j ) {
1335 q[j-1] = a[j] * q[j];
1337 umodpoly beta(1, R->one());
1339 for ( size_t j=1; j<r; ++j ) {
1340 vector<ex> mdarg(2);
1341 mdarg[0] = umod_to_ex(q[j-1], x);
1342 mdarg[1] = umod_to_ex(a[j-1], x);
1343 vector<EvalPoint> empty;
1344 vector<ex> exsigma = multivar_diophant(mdarg, x, umod_to_ex(beta, x), empty, 0, p, k);
1346 umodpoly_from_ex(sigma1, exsigma[0], x, R);
1348 umodpoly_from_ex(sigma2, exsigma[1], x, R);
1350 s.push_back(sigma2);
1357 * Assert: a not empty.
1359 void change_modulus(const cl_modint_ring& R, umodpoly& a)
1361 if ( a.empty() ) return;
1362 cl_modint_ring oldR = a[0].ring();
1363 umodpoly::iterator i = a.begin(), end = a.end();
1364 for ( ; i!=end; ++i ) {
1365 *i = R->canonhom(oldR->retract(*i));
1370 void eea_lift(const umodpoly& a, const umodpoly& b, const ex& x, unsigned int p, unsigned int k, umodpoly& s_, umodpoly& t_)
1372 cl_modint_ring R = find_modint_ring(p);
1374 change_modulus(R, amod);
1376 change_modulus(R, bmod);
1381 exteuclid(amod, bmod, g, smod, tmod);
1382 if ( unequal_one(g) ) {
1383 throw logic_error("gcd(amod,bmod) != 1");
1386 cl_modint_ring Rpk = find_modint_ring(expt_pos(cl_I(p),k));
1388 change_modulus(Rpk, s);
1390 change_modulus(Rpk, t);
1393 umodpoly one(1, Rpk->one());
1394 for ( size_t j=1; j<k; ++j ) {
1395 umodpoly e = one - a * s - b * t;
1396 reduce_coeff(e, modulus);
1398 change_modulus(R, c);
1399 umodpoly sigmabar = smod * c;
1400 umodpoly taubar = tmod * c;
1402 remdiv(sigmabar, bmod, sigma, q);
1403 umodpoly tau = taubar + q * amod;
1404 umodpoly sadd = sigma;
1405 change_modulus(Rpk, sadd);
1406 cl_MI modmodulus(Rpk, modulus);
1407 s = s + sadd * modmodulus;
1408 umodpoly tadd = tau;
1409 change_modulus(Rpk, tadd);
1410 t = t + tadd * modmodulus;
1411 modulus = modulus * p;
1417 upvec univar_diophant(const upvec& a, const ex& x, unsigned int m, unsigned int p, unsigned int k)
1419 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1421 const size_t r = a.size();
1424 upvec s = multiterm_eea_lift(a, x, p, k);
1425 for ( size_t j=0; j<r; ++j ) {
1426 ex phi = expand(pow(x,m) * umod_to_ex(s[j], x));
1428 umodpoly_from_ex(bmod, phi, x, R);
1430 rem(bmod, a[j], buf);
1431 result.push_back(buf);
1437 eea_lift(a[1], a[0], x, p, k, s, t);
1438 ex phi = expand(pow(x,m) * umod_to_ex(s, x));
1440 umodpoly_from_ex(bmod, phi, x, R);
1442 remdiv(bmod, a[0], buf, q);
1443 result.push_back(buf);
1444 phi = expand(pow(x,m) * umod_to_ex(t, x));
1446 umodpoly_from_ex(t1mod, phi, x, R);
1447 umodpoly buf2 = t1mod + q * a[1];
1448 result.push_back(buf2);
1454 struct make_modular_map : public map_function {
1456 make_modular_map(const cl_modint_ring& R_) : R(R_) { }
1457 ex operator()(const ex& e)
1459 if ( is_a<add>(e) || is_a<mul>(e) ) {
1460 return e.map(*this);
1462 else if ( is_a<numeric>(e) ) {
1463 numeric mod(R->modulus);
1464 numeric halfmod = (mod-1)/2;
1465 cl_MI emod = R->canonhom(the<cl_I>(ex_to<numeric>(e).to_cl_N()));
1466 numeric n(R->retract(emod));
1467 if ( n > halfmod ) {
1478 static ex make_modular(const ex& e, const cl_modint_ring& R)
1480 make_modular_map map(R);
1481 return map(e.expand());
1484 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)
1488 const cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1489 const size_t r = a.size();
1490 const size_t nu = I.size() + 1;
1494 ex xnu = I.back().x;
1495 int alphanu = I.back().evalpoint;
1498 for ( size_t i=0; i<r; ++i ) {
1502 for ( size_t i=0; i<r; ++i ) {
1503 b[i] = normal(A / a[i]);
1506 vector<ex> anew = a;
1507 for ( size_t i=0; i<r; ++i ) {
1508 anew[i] = anew[i].subs(xnu == alphanu);
1510 ex cnew = c.subs(xnu == alphanu);
1511 vector<EvalPoint> Inew = I;
1513 sigma = multivar_diophant(anew, x, cnew, Inew, d, p, k);
1516 for ( size_t i=0; i<r; ++i ) {
1517 buf -= sigma[i] * b[i];
1519 ex e = make_modular(buf, R);
1522 for ( size_t m=1; m<=d; ++m ) {
1523 while ( !e.is_zero() && e.has(xnu) ) {
1524 monomial *= (xnu - alphanu);
1525 monomial = expand(monomial);
1526 ex cm = e.diff(ex_to<symbol>(xnu), m).subs(xnu==alphanu) / factorial(m);
1527 cm = make_modular(cm, R);
1528 if ( !cm.is_zero() ) {
1529 vector<ex> delta_s = multivar_diophant(anew, x, cm, Inew, d, p, k);
1531 for ( size_t j=0; j<delta_s.size(); ++j ) {
1532 delta_s[j] *= monomial;
1533 sigma[j] += delta_s[j];
1534 buf -= delta_s[j] * b[j];
1536 e = make_modular(buf, R);
1543 for ( size_t i=0; i<a.size(); ++i ) {
1545 umodpoly_from_ex(up, a[i], x, R);
1549 sigma.insert(sigma.begin(), r, 0);
1552 if ( is_a<add>(c) ) {
1560 for ( size_t i=0; i<nterms; ++i ) {
1561 int m = z.degree(x);
1562 cl_I cm = the<cl_I>(ex_to<numeric>(z.lcoeff(x)).to_cl_N());
1563 upvec delta_s = univar_diophant(amod, x, m, p, k);
1566 while ( poscm < 0 ) {
1567 poscm = poscm + expt_pos(cl_I(p),k);
1569 modcm = cl_MI(R, poscm);
1570 for ( size_t j=0; j<delta_s.size(); ++j ) {
1571 delta_s[j] = delta_s[j] * modcm;
1572 sigma[j] = sigma[j] + umod_to_ex(delta_s[j], x);
1580 for ( size_t i=0; i<sigma.size(); ++i ) {
1581 sigma[i] = make_modular(sigma[i], R);
1588 ostream& operator<<(ostream& o, const vector<EvalPoint>& v)
1590 for ( size_t i=0; i<v.size(); ++i ) {
1591 o << "(" << v[i].x << "==" << v[i].evalpoint << ") ";
1595 #endif // def DEBUGFACTOR
1598 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)
1600 const size_t nu = I.size() + 1;
1601 const cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),l));
1606 for ( size_t j=nu; j>=2; --j ) {
1608 int alpha = I[j-2].evalpoint;
1609 A[j-2] = A[j-1].subs(x==alpha);
1610 A[j-2] = make_modular(A[j-2], R);
1613 int maxdeg = a.degree(I.front().x);
1614 for ( size_t i=1; i<I.size(); ++i ) {
1615 int maxdeg2 = a.degree(I[i].x);
1616 if ( maxdeg2 > maxdeg ) maxdeg = maxdeg2;
1619 const size_t n = u.size();
1621 for ( size_t i=0; i<n; ++i ) {
1622 U[i] = umod_to_ex(u[i], x);
1625 for ( size_t j=2; j<=nu; ++j ) {
1628 for ( size_t m=0; m<n; ++m) {
1629 if ( lcU[m] != 1 ) {
1631 for ( size_t i=j-1; i<nu-1; ++i ) {
1632 coef = coef.subs(I[i].x == I[i].evalpoint);
1634 coef = make_modular(coef, R);
1635 int deg = U[m].degree(x);
1636 U[m] = U[m] - U[m].lcoeff(x) * pow(x,deg) + coef * pow(x,deg);
1640 for ( size_t i=0; i<n; ++i ) {
1643 ex e = expand(A[j-1] - Uprod);
1645 vector<EvalPoint> newI;
1646 for ( size_t i=1; i<=j-2; ++i ) {
1647 newI.push_back(I[i-1]);
1651 int alphaj = I[j-2].evalpoint;
1652 size_t deg = A[j-1].degree(xj);
1653 for ( size_t k=1; k<=deg; ++k ) {
1654 if ( !e.is_zero() ) {
1655 monomial *= (xj - alphaj);
1656 monomial = expand(monomial);
1657 ex dif = e.diff(ex_to<symbol>(xj), k);
1658 ex c = dif.subs(xj==alphaj) / factorial(k);
1659 if ( !c.is_zero() ) {
1660 vector<ex> deltaU = multivar_diophant(U1, x, c, newI, maxdeg, p, cl_I_to_uint(l));
1661 for ( size_t i=0; i<n; ++i ) {
1662 deltaU[i] *= monomial;
1664 U[i] = make_modular(U[i], R);
1667 for ( size_t i=0; i<n; ++i ) {
1671 e = make_modular(e, R);
1678 for ( size_t i=0; i<U.size(); ++i ) {
1681 if ( expand(a-acand).is_zero() ) {
1683 for ( size_t i=0; i<U.size(); ++i ) {
1694 static ex put_factors_into_lst(const ex& e)
1698 if ( is_a<numeric>(e) ) {
1702 if ( is_a<power>(e) ) {
1704 result.append(e.op(0));
1705 result.append(e.op(1));
1708 if ( is_a<symbol>(e) || is_a<add>(e) ) {
1714 if ( is_a<mul>(e) ) {
1716 for ( size_t i=0; i<e.nops(); ++i ) {
1718 if ( is_a<numeric>(op) ) {
1721 if ( is_a<power>(op) ) {
1722 result.append(op.op(0));
1723 result.append(op.op(1));
1725 if ( is_a<symbol>(op) || is_a<add>(op) ) {
1730 result.prepend(nfac);
1733 throw runtime_error("put_factors_into_lst: bad term.");
1737 ostream& operator<<(ostream& o, const vector<numeric>& v)
1739 for ( size_t i=0; i<v.size(); ++i ) {
1744 #endif // def DEBUGFACTOR
1746 static bool checkdivisors(const lst& f, vector<numeric>& d)
1748 const int k = f.nops()-2;
1750 d[0] = ex_to<numeric>(f.op(0) * f.op(f.nops()-1));
1751 if ( d[0] == 1 && k == 1 && abs(f.op(1)) != 1 ) {
1754 for ( int i=1; i<=k; ++i ) {
1755 q = ex_to<numeric>(abs(f.op(i)));
1756 for ( int j=i-1; j>=0; --j ) {
1771 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)
1773 // computation of d is actually not necessary
1774 const ex& x = *syms.begin();
1780 exset::const_iterator s = syms.begin();
1782 for ( size_t i=0; i<a.size(); ++i ) {
1784 a[i] = mod(numeric(rand()), 2*modulus) - modulus;
1785 vnatry = vna.subs(*s == a[i]);
1786 } while ( vnatry == 0 );
1788 u0 = u0.subs(*s == a[i]);
1791 if ( gcd(u0,u0.diff(ex_to<symbol>(x))) != 1 ) {
1794 if ( is_a<numeric>(vn) ) {
1799 lst::const_iterator i = ex_to<lst>(f).begin();
1801 bool problem = false;
1802 while ( i!=ex_to<lst>(f).end() ) {
1804 if ( !is_a<numeric>(fs) ) {
1807 for ( size_t j=0; j<a.size(); ++j ) {
1808 fs = fs.subs(*s == a[j]);
1811 if ( abs(fs) == 1 ) {
1822 ex con = u0.content(x);
1824 trying = checkdivisors(fnum, d);
1830 static ex factor_multivariate(const ex& poly, const exset& syms)
1832 exset::const_iterator s;
1833 const ex& x = *syms.begin();
1835 /* make polynomial primitive */
1836 ex p = poly.expand().collect(x);
1837 ex cont = p.lcoeff(x);
1838 for ( numeric i=p.degree(x)-1; i>=p.ldegree(x); --i ) {
1839 cont = gcd(cont, p.coeff(x,ex_to<numeric>(i).to_int()));
1840 if ( cont == 1 ) break;
1842 ex pp = expand(normal(p / cont));
1843 if ( !is_a<numeric>(cont) ) {
1845 return ::factor(cont) * ::factor(pp);
1847 return factor(cont) * factor(pp);
1851 /* factor leading coefficient */
1853 ex vn = pp.lcoeff(x);
1856 if ( is_a<numeric>(vn) ) {
1861 ex vnfactors = ::factor(vn);
1863 ex vnfactors = factor(vn);
1865 vnlst = put_factors_into_lst(vnfactors);
1868 const numeric maxtrials = 3;
1869 numeric modulus = (vnlst.nops()-1 > 3) ? vnlst.nops()-1 : 3;
1870 numeric minimalr = -1;
1871 vector<numeric> a(syms.size()-1, 0);
1872 vector<numeric> d((vnlst.nops()-1)/2+1, 0);
1875 numeric trialcount = 0;
1877 unsigned int prime = 3;
1878 size_t factor_count = 0;
1881 while ( trialcount < maxtrials ) {
1882 bool problem = generate_set(pp, vn, syms, vnlst, modulus, a, d);
1890 for ( size_t i=0; i<a.size(); ++i ) {
1891 u = u.subs(*s == a[i]);
1894 delta = u.content(x);
1896 // determine proper prime
1898 cl_modint_ring R = find_modint_ring(prime);
1900 if ( irem(ex_to<numeric>(u.lcoeff(x)), prime) != 0 ) {
1902 umodpoly_from_ex(modpoly, u, x, R);
1903 if ( squarefree(modpoly) ) break;
1905 prime = next_prime(prime);
1906 R = find_modint_ring(prime);
1914 ufaclst = put_factors_into_lst(ufac);
1915 factor_count = (ufaclst.nops()-1)/2;
1917 // veto factorization for which gcd(u_i, u_j) != 1 for all i,j
1919 for ( size_t i=0; i<(ufaclst.nops()-1)/2; ++i ) {
1921 umodpoly_from_ex(newu, ufaclst.op(i*2+1), x, R);
1922 tryu.push_back(newu);
1925 for ( size_t i=0; i<tryu.size()-1; ++i ) {
1926 for ( size_t j=i+1; j<tryu.size(); ++j ) {
1928 gcd(tryu[i], tryu[j], tryg);
1929 if ( unequal_one(tryg) ) {
1931 goto escape_quickly;
1940 if ( factor_count <= 1 ) {
1944 if ( minimalr < 0 ) {
1945 minimalr = factor_count;
1947 else if ( minimalr == factor_count ) {
1951 else if ( minimalr > factor_count ) {
1952 minimalr = factor_count;
1955 if ( minimalr <= 1 ) {
1960 vector<numeric> ftilde((vnlst.nops()-1)/2+1);
1961 ftilde[0] = ex_to<numeric>(vnlst.op(0));
1962 for ( size_t i=1; i<ftilde.size(); ++i ) {
1963 ex ft = vnlst.op((i-1)*2+1);
1966 for ( size_t j=0; j<a.size(); ++j ) {
1967 ft = ft.subs(*s == a[j]);
1970 ftilde[i] = ex_to<numeric>(ft);
1973 vector<bool> used_flag((vnlst.nops()-1)/2+1, false);
1974 vector<ex> D(factor_count, 1);
1975 for ( size_t i=0; i<=factor_count; ++i ) {
1978 prefac = ex_to<numeric>(ufaclst.op(0));
1979 ftilde[0] = ftilde[0] / prefac;
1980 vnlst.let_op(0) = vnlst.op(0) / prefac;
1984 prefac = ex_to<numeric>(ufaclst.op(2*(i-1)+1).lcoeff(x));
1986 for ( size_t j=(vnlst.nops()-1)/2+1; j>0; --j ) {
1987 if ( abs(ftilde[j-1]) == 1 ) {
1988 used_flag[j-1] = true;
1991 numeric g = gcd(prefac, ftilde[j-1]);
1993 prefac = prefac / g;
1994 numeric count = abs(iquo(g, ftilde[j-1]));
1995 used_flag[j-1] = true;
1998 D[i-1] = D[i-1] * pow(vnlst.op(0), count);
2001 D[i-1] = D[i-1] * pow(vnlst.op(2*(j-2)+1), count);
2005 ftilde[j-1] = ftilde[j-1] / prefac;
2013 bool some_factor_unused = false;
2014 for ( size_t i=0; i<used_flag.size(); ++i ) {
2015 if ( !used_flag[i] ) {
2016 some_factor_unused = true;
2020 if ( some_factor_unused ) {
2024 vector<ex> C(factor_count);
2026 for ( size_t i=0; i<D.size(); ++i ) {
2030 for ( size_t j=0; j<a.size(); ++j ) {
2031 Dtilde = Dtilde.subs(*s == a[j]);
2034 C[i] = D[i] * (ufaclst.op(2*i+1).lcoeff(x) / Dtilde);
2038 for ( size_t i=0; i<D.size(); ++i ) {
2042 for ( size_t j=0; j<a.size(); ++j ) {
2043 Dtilde = Dtilde.subs(*s == a[j]);
2051 ui = ufaclst.op(2*(i-1)+1);
2054 ex d = gcd(ui.lcoeff(x), Dtilde);
2055 C[i] = D[i] * ( ui.lcoeff(x) / d );
2056 ui = ui * ( Dtilde[i] / d );
2057 delta = delta / ( Dtilde[i] / d );
2058 if ( delta == 1 ) break;
2060 C[i] = delta * C[i];
2061 pp = pp * pow(delta, D.size()-1);
2067 vector<EvalPoint> epv;
2070 for ( size_t i=0; i<a.size(); ++i ) {
2072 ep.evalpoint = a[i].to_int();
2078 for ( int i=u.degree(x); i>=u.ldegree(x); --i ) {
2079 maxcoeff += pow(abs(u.coeff(x, i)),2);
2081 cl_I normmc = ceiling1(the<cl_R>(cln::sqrt(ex_to<numeric>(maxcoeff).to_cl_N())));
2082 unsigned int maxdegree = 0;
2083 for ( size_t i=0; i<factor_count; ++i ) {
2084 if ( ufaclst[2*i+1].degree(x) > (int)maxdegree ) {
2085 maxdegree = ufaclst[2*i+1].degree(x);
2088 cl_I B = normmc * expt_pos(cl_I(2), maxdegree);
2097 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(prime),l));
2098 for ( size_t i=0; i<(ufaclst.nops()-1)/2; ++i ) {
2100 umodpoly_from_ex(newu, ufaclst.op(i*2+1), x, R);
2101 uvec.push_back(newu);
2104 ex res = hensel_multivar(ufaclst.op(0)*pp, x, epv, prime, l, uvec, C);
2105 if ( res != lst() ) {
2106 ex result = cont * ufaclst.op(0);
2107 for ( size_t i=0; i<res.nops(); ++i ) {
2108 result *= res.op(i).content(x) * res.op(i).unit(x);
2109 result *= res.op(i).primpart(x);
2116 struct find_symbols_map : public map_function {
2118 ex operator()(const ex& e)
2120 if ( is_a<symbol>(e) ) {
2124 return e.map(*this);
2128 static ex factor_sqrfree(const ex& poly)
2130 // determine all symbols in poly
2131 find_symbols_map findsymbols;
2133 if ( findsymbols.syms.size() == 0 ) {
2137 if ( findsymbols.syms.size() == 1 ) {
2139 const ex& x = *(findsymbols.syms.begin());
2140 if ( poly.ldegree(x) > 0 ) {
2141 int ld = poly.ldegree(x);
2142 ex res = factor_univariate(expand(poly/pow(x, ld)), x);
2143 return res * pow(x,ld);
2146 ex res = factor_univariate(poly, x);
2151 // multivariate case
2152 ex res = factor_multivariate(poly, findsymbols.syms);
2156 struct apply_factor_map : public map_function {
2158 apply_factor_map(unsigned options_) : options(options_) { }
2159 ex operator()(const ex& e)
2161 if ( e.info(info_flags::polynomial) ) {
2163 return ::factor(e, options);
2165 return factor(e, options);
2168 if ( is_a<add>(e) ) {
2170 for ( size_t i=0; i<e.nops(); ++i ) {
2171 if ( e.op(i).info(info_flags::polynomial) ) {
2181 return ::factor(s1, options) + s2.map(*this);
2183 return factor(s1, options) + s2.map(*this);
2186 return e.map(*this);
2190 } // anonymous namespace
2193 ex factor(const ex& poly, unsigned options = 0)
2195 ex factor(const ex& poly, unsigned options)
2199 if ( !poly.info(info_flags::polynomial) ) {
2200 if ( options & factor_options::all ) {
2201 options &= ~factor_options::all;
2202 apply_factor_map factor_map(options);
2203 return factor_map(poly);
2208 // determine all symbols in poly
2209 find_symbols_map findsymbols;
2211 if ( findsymbols.syms.size() == 0 ) {
2215 exset::const_iterator i=findsymbols.syms.begin(), end=findsymbols.syms.end();
2216 for ( ; i!=end; ++i ) {
2220 // make poly square free
2221 ex sfpoly = sqrfree(poly, syms);
2223 // factorize the square free components
2224 if ( is_a<power>(sfpoly) ) {
2225 // case: (polynomial)^exponent
2226 const ex& base = sfpoly.op(0);
2227 if ( !is_a<add>(base) ) {
2228 // simple case: (monomial)^exponent
2231 ex f = factor_sqrfree(base);
2232 return pow(f, sfpoly.op(1));
2234 if ( is_a<mul>(sfpoly) ) {
2235 // case: multiple factors
2237 for ( size_t i=0; i<sfpoly.nops(); ++i ) {
2238 const ex& t = sfpoly.op(i);
2239 if ( is_a<power>(t) ) {
2240 const ex& base = t.op(0);
2241 if ( !is_a<add>(base) ) {
2245 ex f = factor_sqrfree(base);
2246 res *= pow(f, t.op(1));
2249 else if ( is_a<add>(t) ) {
2250 ex f = factor_sqrfree(t);
2259 if ( is_a<symbol>(sfpoly) ) {
2262 // case: (polynomial)
2263 ex f = factor_sqrfree(sfpoly);
2267 } // namespace GiNaC