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"
66 #define DCOUT(str) cout << #str << endl
67 #define DCOUTVAR(var) cout << #var << ": " << var << endl
68 #define DCOUT2(str,var) cout << #str << ": " << var << endl
72 #define DCOUT2(str,var)
75 // forward declaration
76 ex factor(const ex& poly, unsigned options);
78 // anonymous namespace to hide all utility functions
81 typedef vector<cl_MI> mvec;
84 ostream& operator<<(ostream& o, const mvec& v)
86 mvec::const_iterator i = v.begin(), end = v.end();
92 #endif // def DEBUGFACTOR
95 ostream& operator<<(ostream& o, const vector<mvec>& v)
97 vector<mvec>::const_iterator i = v.begin(), end = v.end();
103 #endif // def DEBUGFACTOR
105 ////////////////////////////////////////////////////////////////////////////////
106 // modular univariate polynomial code
108 typedef cl_UP_MI umod;
109 typedef vector<umod> umodvec;
111 #define COPY(to,from) from.ring()->create(degree(from)); \
112 for ( int II=0; II<=degree(from); ++II ) to.set_coeff(II, coeff(from, II)); \
116 ostream& operator<<(ostream& o, const umodvec& v)
118 umodvec::const_iterator i = v.begin(), end = v.end();
120 o << *i++ << " , " << endl;
124 #endif // def DEBUGFACTOR
126 static umod umod_from_ex(const ex& e, const ex& x, const cl_univpoly_modint_ring& UPR)
128 // assert: e is in Z[x]
129 int deg = e.degree(x);
130 umod p = UPR->create(deg);
131 int ldeg = e.ldegree(x);
132 for ( ; deg>=ldeg; --deg ) {
133 cl_I coeff = the<cl_I>(ex_to<numeric>(e.coeff(x, deg)).to_cl_N());
134 p.set_coeff(deg, UPR->basering()->canonhom(coeff));
136 for ( ; deg>=0; --deg ) {
137 p.set_coeff(deg, UPR->basering()->zero());
143 static umod umod_from_ex(const ex& e, const ex& x, const cl_modint_ring& R)
145 return umod_from_ex(e, x, find_univpoly_ring(R));
148 static umod umod_from_ex(const ex& e, const ex& x, const cl_I& modulus)
150 return umod_from_ex(e, x, find_modint_ring(modulus));
153 static umod umod_from_modvec(const mvec& mv)
155 size_t n = mv.size(); // assert: n>0
156 while ( n && zerop(mv[n-1]) ) --n;
157 cl_univpoly_modint_ring UPR = find_univpoly_ring(mv.front().ring());
159 umod p = UPR->create(-1);
163 umod p = UPR->create(n-1);
164 for ( size_t i=0; i<n; ++i ) {
165 p.set_coeff(i, mv[i]);
171 static umod divide(const umod& a, const cl_I& x)
175 cl_univpoly_modint_ring UPR = a.ring();
176 cl_modint_ring R = UPR->basering();
178 umod newa = UPR->create(deg);
179 for ( int i=0; i<=deg; ++i ) {
180 cl_I c = R->retract(coeff(a, i));
181 newa.set_coeff(i, cl_MI(R, the<cl_I>(c / x)));
188 static ex umod_to_ex(const umod& a, const ex& x)
191 cl_modint_ring R = a.ring()->basering();
192 cl_I mod = R->modulus;
193 cl_I halfmod = (mod-1) >> 1;
194 for ( int i=degree(a); i>=0; --i ) {
195 cl_I n = R->retract(coeff(a, i));
197 e += numeric(n-mod) * pow(x, i);
199 e += numeric(n) * pow(x, i);
205 static void unit_normal(umod& a)
209 cl_MI lc = coeff(a, deg);
210 cl_MI one = a.ring()->basering()->one();
212 umod newa = a.ring()->create(deg);
213 newa.set_coeff(deg, one);
214 for ( --deg; deg>=0; --deg ) {
215 cl_MI nc = div(coeff(a, deg), lc);
216 newa.set_coeff(deg, nc);
224 static umod rem(const umod& a, const umod& b)
236 cl_MI qk = div(coeff(c, n+k), coeff(b, n));
239 for ( int i=0; i<n; ++i ) {
241 c.set_coeff(j, coeff(c, j) - qk * coeff(b, j-k));
246 cl_MI zero = a.ring()->basering()->zero();
247 for ( int i=degree(a); i>=n; --i ) {
248 c.set_coeff(i, zero);
255 static umod div(const umod& a, const umod& b)
261 umod q = a.ring()->create(-1);
267 umod q = a.ring()->create(k);
269 cl_MI qk = div(coeff(c, n+k), coeff(b, n));
273 for ( int i=0; i<n; ++i ) {
275 c.set_coeff(j, coeff(c, j) - qk * coeff(b, j-k));
284 static umod remdiv(const umod& a, const umod& b, umod& q)
290 q = a.ring()->create(-1);
297 q = a.ring()->create(k);
299 cl_MI qk = div(coeff(c, n+k), coeff(b, n));
303 for ( int i=0; i<n; ++i ) {
305 c.set_coeff(j, coeff(c, j) - qk * coeff(b, j-k));
310 cl_MI zero = a.ring()->basering()->zero();
311 for ( int i=degree(a); i>=n; --i ) {
312 c.set_coeff(i, zero);
320 static umod gcd(const umod& a, const umod& b)
322 if ( degree(a) < degree(b) ) return gcd(b, a);
328 while ( !zerop(d) ) {
337 static bool squarefree(const umod& a)
343 umod one = a.ring()->one();
348 // END modular univariate polynomial code
349 ////////////////////////////////////////////////////////////////////////////////
351 ////////////////////////////////////////////////////////////////////////////////
356 friend ostream& operator<<(ostream& o, const modular_matrix& m);
358 modular_matrix(size_t r_, size_t c_, const cl_MI& init) : r(r_), c(c_)
362 size_t rowsize() const { return r; }
363 size_t colsize() const { return c; }
364 cl_MI& operator()(size_t row, size_t col) { return m[row*c + col]; }
365 cl_MI operator()(size_t row, size_t col) const { return m[row*c + col]; }
366 void mul_col(size_t col, const cl_MI x)
368 mvec::iterator i = m.begin() + col;
369 for ( size_t rc=0; rc<r; ++rc ) {
374 void sub_col(size_t col1, size_t col2, const cl_MI fac)
376 mvec::iterator i1 = m.begin() + col1;
377 mvec::iterator i2 = m.begin() + col2;
378 for ( size_t rc=0; rc<r; ++rc ) {
379 *i1 = *i1 - *i2 * fac;
384 void switch_col(size_t col1, size_t col2)
387 mvec::iterator i1 = m.begin() + col1;
388 mvec::iterator i2 = m.begin() + col2;
389 for ( size_t rc=0; rc<r; ++rc ) {
390 buf = *i1; *i1 = *i2; *i2 = buf;
395 void mul_row(size_t row, const cl_MI x)
397 vector<cl_MI>::iterator i = m.begin() + row*c;
398 for ( size_t cc=0; cc<c; ++cc ) {
403 void sub_row(size_t row1, size_t row2, const cl_MI fac)
405 vector<cl_MI>::iterator i1 = m.begin() + row1*c;
406 vector<cl_MI>::iterator i2 = m.begin() + row2*c;
407 for ( size_t cc=0; cc<c; ++cc ) {
408 *i1 = *i1 - *i2 * fac;
413 void switch_row(size_t row1, size_t row2)
416 vector<cl_MI>::iterator i1 = m.begin() + row1*c;
417 vector<cl_MI>::iterator i2 = m.begin() + row2*c;
418 for ( size_t cc=0; cc<c; ++cc ) {
419 buf = *i1; *i1 = *i2; *i2 = buf;
424 bool is_col_zero(size_t col) const
426 mvec::const_iterator i = m.begin() + col;
427 for ( size_t rr=0; rr<r; ++rr ) {
435 bool is_row_zero(size_t row) const
437 mvec::const_iterator i = m.begin() + row*c;
438 for ( size_t cc=0; cc<c; ++cc ) {
446 void set_row(size_t row, const vector<cl_MI>& newrow)
448 mvec::iterator i1 = m.begin() + row*c;
449 mvec::const_iterator i2 = newrow.begin(), end = newrow.end();
450 for ( ; i2 != end; ++i1, ++i2 ) {
454 mvec::const_iterator row_begin(size_t row) const { return m.begin()+row*c; }
455 mvec::const_iterator row_end(size_t row) const { return m.begin()+row*c+r; }
462 modular_matrix operator*(const modular_matrix& m1, const modular_matrix& m2)
464 const unsigned int r = m1.rowsize();
465 const unsigned int c = m2.colsize();
466 modular_matrix o(r,c,m1(0,0));
468 for ( size_t i=0; i<r; ++i ) {
469 for ( size_t j=0; j<c; ++j ) {
471 buf = m1(i,0) * m2(0,j);
472 for ( size_t k=1; k<c; ++k ) {
473 buf = buf + m1(i,k)*m2(k,j);
481 ostream& operator<<(ostream& o, const modular_matrix& m)
483 vector<cl_MI>::const_iterator i = m.m.begin(), end = m.m.end();
485 for ( ; i != end; ++i ) {
487 if ( !(wrap++ % m.c) ) {
494 #endif // def DEBUGFACTOR
496 // END modular matrix
497 ////////////////////////////////////////////////////////////////////////////////
499 static void q_matrix(const umod& a, modular_matrix& Q)
502 unsigned int q = cl_I_to_uint(a.ring()->basering()->modulus);
504 // vector<cl_MI> r(n, a.R->zero());
505 // r[0] = a.R->one();
507 // unsigned int max = (n-1) * q;
508 // for ( size_t m=1; m<=max; ++m ) {
509 // cl_MI rn_1 = r.back();
510 // for ( size_t i=n-1; i>0; --i ) {
511 // r[i] = r[i-1] - rn_1 * a[i];
513 // r[0] = -rn_1 * a[0];
514 // if ( (m % q) == 0 ) {
515 // Q.set_row(m/q, r);
518 // slow and (hopefully) correct
519 cl_MI one = a.ring()->basering()->one();
520 for ( int i=0; i<n; ++i ) {
521 umod qk = a.ring()->create(i*q);
522 qk.set_coeff(i*q, one);
526 for ( int j=0; j<n; ++j ) {
527 rvec.push_back(coeff(r, j));
533 static void nullspace(modular_matrix& M, vector<mvec>& basis)
535 const size_t n = M.rowsize();
536 const cl_MI one = M(0,0).ring()->one();
537 for ( size_t i=0; i<n; ++i ) {
538 M(i,i) = M(i,i) - one;
540 for ( size_t r=0; r<n; ++r ) {
542 for ( ; cc<n; ++cc ) {
543 if ( !zerop(M(r,cc)) ) {
545 if ( !zerop(M(cc,cc)) ) {
557 M.mul_col(r, recip(M(r,r)));
558 for ( cc=0; cc<n; ++cc ) {
560 M.sub_col(cc, r, M(r,cc));
566 for ( size_t i=0; i<n; ++i ) {
567 M(i,i) = M(i,i) - one;
569 for ( size_t i=0; i<n; ++i ) {
570 if ( !M.is_row_zero(i) ) {
571 mvec nu(M.row_begin(i), M.row_end(i));
577 static void berlekamp(const umod& a, umodvec& upv)
579 cl_modint_ring R = a.ring()->basering();
580 const umod one = a.ring()->one();
582 modular_matrix Q(degree(a), degree(a), R->zero());
586 const unsigned int k = nu.size();
592 factors.push_back(a);
593 unsigned int size = 1;
595 unsigned int q = cl_I_to_uint(R->modulus);
597 list<umod>::iterator u = factors.begin();
600 for ( unsigned int s=0; s<q; ++s ) {
601 umod nur = umod_from_modvec(nu[r]);
602 cl_MI buf = coeff(nur, 0) - cl_MI(R, s);
603 nur.set_coeff(0, buf);
605 umod g = gcd(nur, *u);
606 if ( g != one && g != *u ) {
607 umod uo = div(*u, g);
609 throw logic_error("berlekamp: unexpected divisor.");
614 factors.push_back(g);
616 list<umod>::const_iterator i = factors.begin(), end = factors.end();
618 if ( degree(*i) ) ++size;
622 list<umod>::const_iterator i = factors.begin(), end = factors.end();
637 static void factor_modular(const umod& p, umodvec& upv)
643 static void exteuclid(const umod& a, const umod& b, umod& g, umod& s, umod& t)
645 if ( degree(a) < degree(b) ) {
646 exteuclid(b, a, g, t, s);
649 umod c = COPY(c, a); unit_normal(c);
650 umod d = COPY(d, b); unit_normal(d);
651 umod c1 = a.ring()->one();
652 umod c2 = a.ring()->create(-1);
653 umod d1 = a.ring()->create(-1);
654 umod d2 = a.ring()->one();
655 while ( !zerop(d) ) {
658 umod r1 = c1 - q * d1;
659 umod r2 = c2 - q * d2;
667 g = COPY(g, c); unit_normal(g);
669 for ( int i=0; i<=degree(s); ++i ) {
670 s.set_coeff(i, coeff(s, i) * recip(coeff(a, degree(a)) * coeff(c, degree(c))));
674 for ( int i=0; i<=degree(t); ++i ) {
675 t.set_coeff(i, coeff(t, i) * recip(coeff(b, degree(b)) * coeff(c, degree(c))));
680 static ex replace_lc(const ex& poly, const ex& x, const ex& lc)
682 ex r = expand(poly + (lc - poly.lcoeff(x)) * pow(x, poly.degree(x)));
686 static ex hensel_univar(const ex& a_, const ex& x, unsigned int p, const umod& u1_, const umod& w1_, const ex& gamma_ = 0)
689 const cl_univpoly_modint_ring& UPR = u1_.ring();
690 const cl_modint_ring& R = UPR->basering();
694 for ( int i=a.degree(x); i>=a.ldegree(x); --i ) {
695 maxcoeff += pow(abs(a.coeff(x, i)),2);
697 cl_I normmc = ceiling1(the<cl_R>(cln::sqrt(ex_to<numeric>(maxcoeff).to_cl_N())));
698 cl_I maxdegree = (degree(u1_) > degree(w1_)) ? degree(u1_) : degree(w1_);
699 cl_I B = normmc * expt_pos(cl_I(2), maxdegree);
702 ex alpha = a.lcoeff(x);
707 numeric gamma_ui = ex_to<numeric>(abs(gamma));
709 umod nu1 = COPY(nu1, u1_);
711 umod nw1 = COPY(nw1, w1_);
714 phi = gamma * umod_to_ex(nu1, x);
715 umod u1 = umod_from_ex(phi, x, R);
716 phi = alpha * umod_to_ex(nw1, x);
717 umod w1 = umod_from_ex(phi, x, R);
720 umod g = UPR->create(-1);
721 umod s = UPR->create(-1);
722 umod t = UPR->create(-1);
723 exteuclid(u1, w1, g, s, t);
726 ex u = replace_lc(umod_to_ex(u1, x), x, gamma);
727 ex w = replace_lc(umod_to_ex(w1, x), x, alpha);
728 ex e = expand(a - u * w);
730 const numeric maxmodulus = 2*numeric(B)*gamma_ui;
733 while ( !e.is_zero() && modulus < maxmodulus ) {
735 phi = expand(umod_to_ex(s, x) * c);
736 umod sigmatilde = umod_from_ex(phi, x, R);
737 phi = expand(umod_to_ex(t, x) * c);
738 umod tautilde = umod_from_ex(phi, x, R);
739 umod q = div(sigmatilde, w1);
740 umod r = rem(sigmatilde, w1);
741 umod sigma = COPY(sigma, r);
742 phi = expand(umod_to_ex(tautilde, x) + umod_to_ex(q, x) * umod_to_ex(u1, x));
743 umod tau = umod_from_ex(phi, x, R);
744 u = expand(u + umod_to_ex(tau, x) * modulus);
745 w = expand(w + umod_to_ex(sigma, x) * modulus);
746 e = expand(a - u * w);
747 modulus = modulus * p;
752 ex delta = u.content(x);
754 w = w / gamma * delta;
762 static unsigned int next_prime(unsigned int p)
764 static vector<unsigned int> primes;
765 if ( primes.size() == 0 ) {
766 primes.push_back(3); primes.push_back(5); primes.push_back(7);
768 vector<unsigned int>::const_iterator it = primes.begin();
769 if ( p >= primes.back() ) {
770 unsigned int candidate = primes.back() + 2;
772 size_t n = primes.size()/2;
773 for ( size_t i=0; i<n; ++i ) {
774 if ( candidate % primes[i] ) continue;
778 primes.push_back(candidate);
779 if ( candidate > p ) break;
783 vector<unsigned int>::const_iterator end = primes.end();
784 for ( ; it!=end; ++it ) {
789 throw logic_error("next_prime: should not reach this point!");
795 Partition(size_t n_) : n(n_)
801 int operator[](size_t i) const { return k[i]; }
802 size_t size() const { return n; }
803 size_t size_first() const { return n-sum; }
804 size_t size_second() const { return sum; }
808 for ( size_t i=0; i<k.size(); ++i ) {
816 for ( size_t i=n-1; i>=1; --i ) {
832 static void split(const umodvec& factors, const Partition& part, umod& a, umod& b)
834 a = factors.front().ring()->one();
835 b = factors.front().ring()->one();
836 for ( size_t i=0; i<part.size(); ++i ) {
852 static ex factor_univariate(const ex& poly, const ex& x)
855 poly.unitcontprim(x, unit, cont, prim);
857 // determine proper prime and minimize number of modular factors
858 unsigned int p = 3, lastp;
860 unsigned int trials = 0;
861 unsigned int minfactors = 0;
862 numeric lcoeff = ex_to<numeric>(prim.lcoeff(x));
864 while ( trials < 2 ) {
867 if ( irem(lcoeff, p) != 0 ) {
868 R = find_modint_ring(p);
869 umod modpoly = umod_from_ex(prim, x, R);
870 if ( squarefree(modpoly) ) break;
874 // do modular factorization
875 umod modpoly = umod_from_ex(prim, x, R);
876 umodvec trialfactors;
877 factor_modular(modpoly, trialfactors);
878 if ( trialfactors.size() <= 1 ) {
879 // irreducible for sure
883 if ( minfactors == 0 || trialfactors.size() < minfactors ) {
884 factors = trialfactors;
885 minfactors = factors.size();
894 R = find_modint_ring(p);
895 cl_univpoly_modint_ring UPR = find_univpoly_ring(R);
897 // lift all factor combinations
898 stack<ModFactors> tocheck;
901 mf.factors = factors;
904 while ( tocheck.size() ) {
905 const size_t n = tocheck.top().factors.size();
908 umod a = UPR->create(-1);
909 umod b = UPR->create(-1);
910 split(tocheck.top().factors, part, a, b);
912 ex answer = hensel_univar(tocheck.top().poly, x, p, a, b);
913 if ( answer != lst() ) {
914 if ( part.size_first() == 1 ) {
915 if ( part.size_second() == 1 ) {
916 result *= answer.op(0) * answer.op(1);
920 result *= answer.op(0);
921 tocheck.top().poly = answer.op(1);
922 for ( size_t i=0; i<n; ++i ) {
923 if ( part[i] == 0 ) {
924 tocheck.top().factors.erase(tocheck.top().factors.begin()+i);
930 else if ( part.size_second() == 1 ) {
931 if ( part.size_first() == 1 ) {
932 result *= answer.op(0) * answer.op(1);
936 result *= answer.op(1);
937 tocheck.top().poly = answer.op(0);
938 for ( size_t i=0; i<n; ++i ) {
939 if ( part[i] == 1 ) {
940 tocheck.top().factors.erase(tocheck.top().factors.begin()+i);
947 umodvec newfactors1(part.size_first(), UPR->create(-1)), newfactors2(part.size_second(), UPR->create(-1));
948 umodvec::iterator i1 = newfactors1.begin(), i2 = newfactors2.begin();
949 for ( size_t i=0; i<n; ++i ) {
951 *i2++ = tocheck.top().factors[i];
954 *i1++ = tocheck.top().factors[i];
957 tocheck.top().factors = newfactors1;
958 tocheck.top().poly = answer.op(0);
960 mf.factors = newfactors2;
961 mf.poly = answer.op(1);
967 if ( !part.next() ) {
968 result *= tocheck.top().poly;
976 return unit * cont * result;
987 // forward declaration
988 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);
990 umodvec multiterm_eea_lift(const umodvec& a, const ex& x, unsigned int p, unsigned int k)
992 DCOUT(multiterm_eea_lift);
997 const size_t r = a.size();
999 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1000 cl_univpoly_modint_ring UPR = find_univpoly_ring(R);
1001 umodvec q(r-1, UPR->create(-1));
1003 for ( size_t j=r-2; j>=1; --j ) {
1004 q[j-1] = a[j] * q[j];
1007 umod beta = UPR->one();
1009 for ( size_t j=1; j<r; ++j ) {
1012 vector<ex> mdarg(2);
1013 mdarg[0] = umod_to_ex(q[j-1], x);
1014 mdarg[1] = umod_to_ex(a[j-1], x);
1015 vector<EvalPoint> empty;
1016 vector<ex> exsigma = multivar_diophant(mdarg, x, umod_to_ex(beta, x), empty, 0, p, k);
1017 umod sigma1 = umod_from_ex(exsigma[0], x, R);
1018 umod sigma2 = umod_from_ex(exsigma[1], x, R);
1019 beta = COPY(beta, sigma1);
1020 s.push_back(sigma2);
1025 DCOUT(END multiterm_eea_lift);
1029 void change_modulus(umod& out, const umod& in)
1031 // ASSERT: out and in have same degree
1032 if ( out.ring() == in.ring() ) {
1033 out = COPY(out, in);
1036 for ( int i=0; i<=degree(in); ++i ) {
1037 out.set_coeff(i, out.ring()->basering()->canonhom(in.ring()->basering()->retract(coeff(in, i))));
1043 void eea_lift(const umod& a, const umod& b, const ex& x, unsigned int p, unsigned int k, umod& s_, umod& t_)
1052 cl_modint_ring R = find_modint_ring(p);
1053 cl_univpoly_modint_ring UPR = find_univpoly_ring(R);
1054 umod amod = UPR->create(degree(a));
1056 change_modulus(amod, a);
1057 umod bmod = UPR->create(degree(b));
1058 change_modulus(bmod, b);
1062 umod g = UPR->create(-1);
1063 umod smod = UPR->create(-1);
1064 umod tmod = UPR->create(-1);
1065 exteuclid(amod, bmod, g, smod, tmod);
1072 cl_modint_ring Rpk = find_modint_ring(expt_pos(cl_I(p),k));
1073 cl_univpoly_modint_ring UPRpk = find_univpoly_ring(Rpk);
1074 umod s = UPRpk->create(degree(smod));
1075 change_modulus(s, smod);
1076 umod t = UPRpk->create(degree(tmod));
1077 change_modulus(t, tmod);
1084 umod one = UPRpk->one();
1085 for ( size_t j=1; j<k; ++j ) {
1087 umod e = one - a * s - b * t;
1092 e = divide(e, modulus);
1093 umod c = UPR->create(degree(e));
1094 change_modulus(c, e);
1095 umod sigmabar = smod * c;
1096 umod taubar = tmod * c;
1097 umod q = div(sigmabar, bmod);
1098 umod sigma = rem(sigmabar, bmod);
1099 umod tau = taubar + q * amod;
1100 umod sadd = UPRpk->create(degree(sigma));
1101 change_modulus(sadd, sigma);
1102 cl_MI modmodulus(Rpk, modulus);
1103 s = s + sadd * modmodulus;
1104 umod tadd = UPRpk->create(degree(tau));
1105 change_modulus(tadd, tau);
1106 t = t + tadd * modmodulus;
1107 modulus = modulus * p;
1114 DCOUT2(check, a*s + b*t);
1115 DCOUT(END eea_lift);
1118 umodvec univar_diophant(const umodvec& a, const ex& x, unsigned int m, unsigned int p, unsigned int k)
1120 DCOUT(univar_diophant);
1127 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1128 cl_univpoly_modint_ring UPR = find_univpoly_ring(R);
1130 const size_t r = a.size();
1133 umodvec s = multiterm_eea_lift(a, x, p, k);
1134 for ( size_t j=0; j<r; ++j ) {
1135 ex phi = expand(pow(x,m) * umod_to_ex(s[j], x));
1136 umod bmod = umod_from_ex(phi, x, R);
1137 umod buf = rem(bmod, a[j]);
1138 result.push_back(buf);
1142 umod s = UPR->create(-1);
1143 umod t = UPR->create(-1);
1144 eea_lift(a[1], a[0], x, p, k, s, t);
1145 ex phi = expand(pow(x,m) * umod_to_ex(s, x));
1146 umod bmod = umod_from_ex(phi, x, R);
1147 umod buf = rem(bmod, a[0]);
1148 result.push_back(buf);
1149 umod q = div(bmod, a[0]);
1150 phi = expand(pow(x,m) * umod_to_ex(t, x));
1151 umod t1mod = umod_from_ex(phi, x, R);
1152 umod buf2 = t1mod + q * a[1];
1153 result.push_back(buf2);
1157 DCOUT(END univar_diophant);
1161 struct make_modular_map : public map_function {
1163 make_modular_map(const cl_modint_ring& R_) : R(R_) { }
1164 ex operator()(const ex& e)
1166 if ( is_a<add>(e) || is_a<mul>(e) ) {
1167 return e.map(*this);
1169 else if ( is_a<numeric>(e) ) {
1170 numeric mod(R->modulus);
1171 numeric halfmod = (mod-1)/2;
1172 cl_MI emod = R->canonhom(the<cl_I>(ex_to<numeric>(e).to_cl_N()));
1173 numeric n(R->retract(emod));
1174 if ( n > halfmod ) {
1185 static ex make_modular(const ex& e, const cl_modint_ring& R)
1187 make_modular_map map(R);
1191 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)
1195 DCOUT(multivar_diophant);
1198 for ( size_t i=0; i<a.size(); ++i ) {
1199 cout << a[i] << " ";
1207 for ( size_t i=0; i<I.size(); ++i ) {
1208 cout << I[i].x << "=" << I[i].evalpoint << " ";
1216 const cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1217 const size_t r = a.size();
1218 const size_t nu = I.size() + 1;
1224 ex xnu = I.back().x;
1225 int alphanu = I.back().evalpoint;
1228 for ( size_t i=0; i<r; ++i ) {
1232 for ( size_t i=0; i<r; ++i ) {
1233 b[i] = normal(A / a[i]);
1236 vector<ex> anew = a;
1237 for ( size_t i=0; i<r; ++i ) {
1238 anew[i] = anew[i].subs(xnu == alphanu);
1240 ex cnew = c.subs(xnu == alphanu);
1241 vector<EvalPoint> Inew = I;
1243 sigma = multivar_diophant(anew, x, cnew, Inew, d, p, k);
1247 for ( size_t i=0; i<r; ++i ) {
1248 buf -= sigma[i] * b[i];
1251 e = make_modular(e, R);
1257 for ( size_t m=1; m<=d; ++m ) {
1259 while ( !e.is_zero() && e.has(xnu) ) {
1260 monomial *= (xnu - alphanu);
1261 monomial = expand(monomial);
1264 ex cm = e.diff(ex_to<symbol>(xnu), m).subs(xnu==alphanu) / factorial(m);
1266 if ( !cm.is_zero() ) {
1267 vector<ex> delta_s = multivar_diophant(anew, x, cm, Inew, d, p, k);
1270 for ( size_t j=0; j<delta_s.size(); ++j ) {
1271 delta_s[j] *= monomial;
1272 sigma[j] += delta_s[j];
1273 buf -= delta_s[j] * b[j];
1276 e = make_modular(e, R);
1282 DCOUT(uniterm left);
1284 for ( size_t i=0; i<a.size(); ++i ) {
1285 umod up = umod_from_ex(a[i], x, R);
1289 sigma.insert(sigma.begin(), r, 0);
1292 if ( is_a<add>(c) ) {
1301 for ( size_t i=0; i<nterms; ++i ) {
1303 int m = z.degree(x);
1305 cl_I cm = the<cl_I>(ex_to<numeric>(z.lcoeff(x)).to_cl_N());
1307 umodvec delta_s = univar_diophant(amod, x, m, p, k);
1310 while ( poscm < 0 ) {
1311 poscm = poscm + expt_pos(cl_I(p),k);
1313 modcm = cl_MI(R, poscm);
1315 for ( size_t j=0; j<delta_s.size(); ++j ) {
1316 delta_s[j] = delta_s[j] * modcm;
1317 sigma[j] = sigma[j] + umod_to_ex(delta_s[j], x);
1321 cout << "STEP " << i << " sigma ";
1322 for ( size_t p=0; p<sigma.size(); ++p ) {
1323 cout << sigma[p] << " ";
1334 for ( size_t i=0; i<sigma.size(); ++i ) {
1335 cout << sigma[i] << " ";
1340 for ( size_t i=0; i<sigma.size(); ++i ) {
1341 sigma[i] = make_modular(sigma[i], R);
1346 for ( size_t i=0; i<sigma.size(); ++i ) {
1347 cout << sigma[i] << " ";
1351 DCOUT(END multivar_diophant);
1356 ostream& operator<<(ostream& o, const vector<EvalPoint>& v)
1358 for ( size_t i=0; i<v.size(); ++i ) {
1359 o << "(" << v[i].x << "==" << v[i].evalpoint << ") ";
1363 #endif // def DEBUGFACTOR
1366 ex hensel_multivar(const ex& a, const ex& x, const vector<EvalPoint>& I, unsigned int p, const cl_I& l, const umodvec& u, const vector<ex>& lcU)
1368 DCOUT(hensel_multivar);
1376 const size_t nu = I.size() + 1;
1377 const cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),l));
1384 for ( size_t j=nu; j>=2; --j ) {
1386 int alpha = I[j-2].evalpoint;
1387 A[j-2] = A[j-1].subs(x==alpha);
1388 A[j-2] = make_modular(A[j-2], R);
1393 for ( size_t i=0; i<A.size(); ++i) cout << A[i] << " ";
1397 int maxdeg = a.degree(I.front().x);
1398 for ( size_t i=1; i<I.size(); ++i ) {
1399 int maxdeg2 = a.degree(I[i].x);
1400 if ( maxdeg2 > maxdeg ) maxdeg = maxdeg2;
1404 const size_t n = u.size();
1407 for ( size_t i=0; i<n; ++i ) {
1408 U[i] = umod_to_ex(u[i], x);
1412 for ( size_t i=0; i<U.size(); ++i) cout << U[i] << " ";
1416 for ( size_t j=2; j<=nu; ++j ) {
1421 for ( size_t m=0; m<n; ++m) {
1422 if ( lcU[m] != 1 ) {
1424 for ( size_t i=j-1; i<nu-1; ++i ) {
1425 coef = coef.subs(I[i].x == I[i].evalpoint);
1427 coef = expand(coef);
1428 coef = make_modular(coef, R);
1429 int deg = U[m].degree(x);
1430 U[m] = U[m] - U[m].lcoeff(x) * pow(x,deg) + coef * pow(x,deg);
1435 for ( size_t i=0; i<n; ++i ) {
1438 ex e = expand(A[j-1] - Uprod);
1441 vector<EvalPoint> newI;
1442 for ( size_t i=1; i<=j-2; ++i ) {
1443 newI.push_back(I[i-1]);
1448 int alphaj = I[j-2].evalpoint;
1449 size_t deg = A[j-1].degree(xj);
1451 for ( size_t k=1; k<=deg; ++k ) {
1453 if ( !e.is_zero() ) {
1456 monomial *= (xj - alphaj);
1457 monomial = expand(monomial);
1459 ex dif = e.diff(ex_to<symbol>(xj), k);
1461 ex c = dif.subs(xj==alphaj) / factorial(k);
1463 if ( !c.is_zero() ) {
1464 vector<ex> deltaU = multivar_diophant(U1, x, c, newI, maxdeg, p, cl_I_to_uint(l));
1465 for ( size_t i=0; i<n; ++i ) {
1467 DCOUTVAR(deltaU[i]);
1468 deltaU[i] *= monomial;
1470 U[i] = make_modular(U[i], R);
1471 U[i] = U[i].expand();
1475 for ( size_t i=0; i<n; ++i ) {
1478 DCOUTVAR(Uprod.expand());
1480 e = expand(A[j-1] - Uprod);
1481 e = make_modular(e, R);
1492 for ( size_t i=0; i<U.size(); ++i ) {
1496 if ( expand(a-acand).is_zero() ) {
1498 for ( size_t i=0; i<U.size(); ++i ) {
1502 DCOUT(END hensel_multivar);
1508 DCOUT(END hensel_multivar);
1513 static ex put_factors_into_lst(const ex& e)
1515 DCOUT(put_factors_into_lst);
1520 if ( is_a<numeric>(e) ) {
1522 DCOUT(END put_factors_into_lst);
1526 if ( is_a<power>(e) ) {
1528 result.append(e.op(0));
1529 result.append(e.op(1));
1530 DCOUT(END put_factors_into_lst);
1534 if ( is_a<symbol>(e) || is_a<add>(e) ) {
1538 DCOUT(END put_factors_into_lst);
1542 if ( is_a<mul>(e) ) {
1544 for ( size_t i=0; i<e.nops(); ++i ) {
1546 if ( is_a<numeric>(op) ) {
1549 if ( is_a<power>(op) ) {
1550 result.append(op.op(0));
1551 result.append(op.op(1));
1553 if ( is_a<symbol>(op) || is_a<add>(op) ) {
1558 result.prepend(nfac);
1559 DCOUT(END put_factors_into_lst);
1563 throw runtime_error("put_factors_into_lst: bad term.");
1567 ostream& operator<<(ostream& o, const vector<numeric>& v)
1569 for ( size_t i=0; i<v.size(); ++i ) {
1574 #endif // def DEBUGFACTOR
1576 static bool checkdivisors(const lst& f, vector<numeric>& d)
1578 DCOUT(checkdivisors);
1579 const int k = f.nops()-2;
1583 d[0] = ex_to<numeric>(f.op(0) * f.op(f.nops()-1));
1584 if ( d[0] == 1 && k == 1 && abs(f.op(1)) != 1 ) {
1586 DCOUT(END checkdivisors);
1590 for ( int i=1; i<=k; ++i ) {
1592 DCOUTVAR(abs(f.op(i)));
1593 q = ex_to<numeric>(abs(f.op(i)));
1595 for ( int j=i-1; j>=0; --j ) {
1606 DCOUT(END checkdivisors);
1613 DCOUT(END checkdivisors);
1617 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)
1619 // computation of d is actually not necessary
1620 DCOUT(generate_set);
1625 const ex& x = *syms.begin();
1631 exset::const_iterator s = syms.begin();
1633 for ( size_t i=0; i<a.size(); ++i ) {
1636 a[i] = mod(numeric(rand()), 2*modulus) - modulus;
1637 vnatry = vna.subs(*s == a[i]);
1638 } while ( vnatry == 0 );
1640 u0 = u0.subs(*s == a[i]);
1645 if ( gcd(u0,u0.diff(ex_to<symbol>(x))) != 1 ) {
1648 if ( is_a<numeric>(vn) ) {
1652 DCOUT(do substitution);
1654 lst::const_iterator i = ex_to<lst>(f).begin();
1656 bool problem = false;
1657 while ( i!=ex_to<lst>(f).end() ) {
1659 if ( !is_a<numeric>(fs) ) {
1662 for ( size_t j=0; j<a.size(); ++j ) {
1663 fs = fs.subs(*s == a[j]);
1666 if ( abs(fs) == 1 ) {
1677 ex con = u0.content(x);
1680 trying = checkdivisors(fnum, d);
1683 DCOUT(END generate_set);
1687 static ex factor_multivariate(const ex& poly, const exset& syms)
1689 DCOUT(factor_multivariate);
1692 exset::const_iterator s;
1693 const ex& x = *syms.begin();
1696 /* make polynomial primitive */
1697 ex p = poly.expand().collect(x);
1699 ex cont = p.lcoeff(x);
1700 for ( numeric i=p.degree(x)-1; i>=p.ldegree(x); --i ) {
1701 cont = gcd(cont, p.coeff(x,ex_to<numeric>(i).to_int()));
1702 if ( cont == 1 ) break;
1705 ex pp = expand(normal(p / cont));
1707 if ( !is_a<numeric>(cont) ) {
1709 return ::factor(cont) * ::factor(pp);
1711 return factor(cont) * factor(pp);
1715 /* factor leading coefficient */
1717 ex vn = pp.lcoeff(x);
1720 if ( is_a<numeric>(vn) ) {
1725 ex vnfactors = ::factor(vn);
1727 ex vnfactors = factor(vn);
1729 vnlst = put_factors_into_lst(vnfactors);
1733 const numeric maxtrials = 3;
1734 numeric modulus = (vnlst.nops()-1 > 3) ? vnlst.nops()-1 : 3;
1736 numeric minimalr = -1;
1737 vector<numeric> a(syms.size()-1, 0);
1738 vector<numeric> d((vnlst.nops()-1)/2+1, 0);
1741 numeric trialcount = 0;
1744 size_t factor_count;
1747 while ( trialcount < maxtrials ) {
1748 bool problem = generate_set(pp, vn, syms, vnlst, modulus, a, d);
1759 for ( size_t i=0; i<a.size(); ++i ) {
1760 u = u.subs(*s == a[i]);
1763 delta = u.content(x);
1766 // determine proper prime
1769 cl_modint_ring R = find_modint_ring(prime);
1770 DCOUTVAR(u.lcoeff(x));
1772 if ( irem(ex_to<numeric>(u.lcoeff(x)), prime) != 0 ) {
1773 umod modpoly = umod_from_ex(u, x, R);
1774 if ( squarefree(modpoly) ) break;
1776 prime = next_prime(prime);
1778 R = find_modint_ring(prime);
1787 ufaclst = put_factors_into_lst(ufac);
1789 factor_count = (ufaclst.nops()-1)/2;
1790 DCOUTVAR(factor_count);
1792 if ( factor_count <= 1 ) {
1794 DCOUT(END factor_multivariate);
1798 if ( minimalr < 0 ) {
1799 minimalr = factor_count;
1801 else if ( minimalr == factor_count ) {
1805 else if ( minimalr > factor_count ) {
1806 minimalr = factor_count;
1809 DCOUTVAR(trialcount);
1811 if ( minimalr <= 1 ) {
1813 DCOUT(END factor_multivariate);
1818 vector<numeric> ftilde((vnlst.nops()-1)/2+1);
1819 ftilde[0] = ex_to<numeric>(vnlst.op(0));
1820 for ( size_t i=1; i<ftilde.size(); ++i ) {
1821 ex ft = vnlst.op((i-1)*2+1);
1824 for ( size_t j=0; j<a.size(); ++j ) {
1825 ft = ft.subs(*s == a[j]);
1828 ftilde[i] = ex_to<numeric>(ft);
1832 vector<bool> used_flag((vnlst.nops()-1)/2+1, false);
1833 vector<ex> D(factor_count, 1);
1834 for ( size_t i=0; i<=factor_count; ++i ) {
1838 prefac = ex_to<numeric>(ufaclst.op(0));
1839 ftilde[0] = ftilde[0] / prefac;
1840 vnlst.let_op(0) = vnlst.op(0) / prefac;
1844 prefac = ex_to<numeric>(ufaclst.op(2*(i-1)+1).lcoeff(x));
1847 for ( size_t j=(vnlst.nops()-1)/2+1; j>0; --j ) {
1850 DCOUTVAR(ftilde[j-1]);
1851 if ( abs(ftilde[j-1]) == 1 ) {
1852 used_flag[j-1] = true;
1855 numeric g = gcd(prefac, ftilde[j-1]);
1858 DCOUT(has_common_prime);
1859 prefac = prefac / g;
1860 numeric count = abs(iquo(g, ftilde[j-1]));
1862 used_flag[j-1] = true;
1865 D[i-1] = D[i-1] * pow(vnlst.op(0), count);
1868 D[i-1] = D[i-1] * pow(vnlst.op(2*(j-2)+1), count);
1872 ftilde[j-1] = ftilde[j-1] / prefac;
1874 DCOUTVAR(ftilde[j-1]);
1883 bool some_factor_unused = false;
1884 for ( size_t i=0; i<used_flag.size(); ++i ) {
1885 if ( !used_flag[i] ) {
1886 some_factor_unused = true;
1890 if ( some_factor_unused ) {
1891 DCOUT(some factor unused!);
1895 vector<ex> C(factor_count);
1899 for ( size_t i=0; i<D.size(); ++i ) {
1903 for ( size_t j=0; j<a.size(); ++j ) {
1904 Dtilde = Dtilde.subs(*s == a[j]);
1908 C[i] = D[i] * (ufaclst.op(2*i+1).lcoeff(x) / Dtilde);
1912 for ( size_t i=0; i<D.size(); ++i ) {
1916 for ( size_t j=0; j<a.size(); ++j ) {
1917 Dtilde = Dtilde.subs(*s == a[j]);
1925 ui = ufaclst.op(2*(i-1)+1);
1928 ex d = gcd(ui.lcoeff(x), Dtilde);
1929 C[i] = D[i] * ( ui.lcoeff(x) / d );
1930 ui = ui * ( Dtilde[i] / d );
1931 delta = delta / ( Dtilde[i] / d );
1932 if ( delta == 1 ) break;
1934 C[i] = delta * C[i];
1935 pp = pp * pow(delta, D.size()-1);
1942 vector<EvalPoint> epv;
1945 for ( size_t i=0; i<a.size(); ++i ) {
1947 ep.evalpoint = a[i].to_int();
1954 for ( int i=u.degree(x); i>=u.ldegree(x); --i ) {
1955 maxcoeff += pow(abs(u.coeff(x, i)),2);
1957 cl_I normmc = ceiling1(the<cl_R>(cln::sqrt(ex_to<numeric>(maxcoeff).to_cl_N())));
1958 unsigned int maxdegree = 0;
1959 for ( size_t i=0; i<factor_count; ++i ) {
1960 if ( ufaclst[2*i+1].degree(x) > (int)maxdegree ) {
1961 maxdegree = ufaclst[2*i+1].degree(x);
1964 cl_I B = normmc * expt_pos(cl_I(2), maxdegree);
1973 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(prime),l));
1974 for ( size_t i=0; i<(ufaclst.nops()-1)/2; ++i ) {
1975 umod newu = umod_from_ex(ufaclst.op(i*2+1), x, R);
1976 uvec.push_back(newu);
1980 ex res = hensel_multivar(ufaclst.op(0)*pp, x, epv, prime, l, uvec, C);
1981 if ( res != lst() ) {
1982 ex result = cont * ufaclst.op(0);
1983 for ( size_t i=0; i<res.nops(); ++i ) {
1984 result *= res.op(i).content(x) * res.op(i).unit(x);
1985 result *= res.op(i).primpart(x);
1988 DCOUT(END factor_multivariate);
1994 struct find_symbols_map : public map_function {
1996 ex operator()(const ex& e)
1998 if ( is_a<symbol>(e) ) {
2002 return e.map(*this);
2006 static ex factor_sqrfree(const ex& poly)
2008 // determine all symbols in poly
2009 find_symbols_map findsymbols;
2011 if ( findsymbols.syms.size() == 0 ) {
2015 if ( findsymbols.syms.size() == 1 ) {
2017 const ex& x = *(findsymbols.syms.begin());
2018 if ( poly.ldegree(x) > 0 ) {
2019 int ld = poly.ldegree(x);
2020 ex res = factor_univariate(expand(poly/pow(x, ld)), x);
2021 return res * pow(x,ld);
2024 ex res = factor_univariate(poly, x);
2029 // multivariate case
2030 ex res = factor_multivariate(poly, findsymbols.syms);
2034 struct apply_factor_map : public map_function {
2036 apply_factor_map(unsigned options_) : options(options_) { }
2037 ex operator()(const ex& e)
2039 if ( e.info(info_flags::polynomial) ) {
2041 return ::factor(e, options);
2043 return factor(e, options);
2046 if ( is_a<add>(e) ) {
2048 for ( size_t i=0; i<e.nops(); ++i ) {
2049 if ( e.op(i).info(info_flags::polynomial) ) {
2059 return ::factor(s1, options) + s2.map(*this);
2061 return factor(s1, options) + s2.map(*this);
2064 return e.map(*this);
2068 } // anonymous namespace
2071 ex factor(const ex& poly, unsigned options = 0)
2073 ex factor(const ex& poly, unsigned options)
2077 if ( !poly.info(info_flags::polynomial) ) {
2078 if ( options & factor_options::all ) {
2079 options &= ~factor_options::all;
2080 apply_factor_map factor_map(options);
2081 return factor_map(poly);
2086 // determine all symbols in poly
2087 find_symbols_map findsymbols;
2089 if ( findsymbols.syms.size() == 0 ) {
2093 exset::const_iterator i=findsymbols.syms.begin(), end=findsymbols.syms.end();
2094 for ( ; i!=end; ++i ) {
2098 // make poly square free
2099 ex sfpoly = sqrfree(poly, syms);
2101 // factorize the square free components
2102 if ( is_a<power>(sfpoly) ) {
2103 // case: (polynomial)^exponent
2104 const ex& base = sfpoly.op(0);
2105 if ( !is_a<add>(base) ) {
2106 // simple case: (monomial)^exponent
2109 ex f = factor_sqrfree(base);
2110 return pow(f, sfpoly.op(1));
2112 if ( is_a<mul>(sfpoly) ) {
2113 // case: multiple factors
2115 for ( size_t i=0; i<sfpoly.nops(); ++i ) {
2116 const ex& t = sfpoly.op(i);
2117 if ( is_a<power>(t) ) {
2118 const ex& base = t.op(0);
2119 if ( !is_a<add>(base) ) {
2123 ex f = factor_sqrfree(base);
2124 res *= pow(f, t.op(1));
2127 else if ( is_a<add>(t) ) {
2128 ex f = factor_sqrfree(t);
2137 if ( is_a<symbol>(sfpoly) ) {
2140 // case: (polynomial)
2141 ex f = factor_sqrfree(sfpoly);
2145 } // namespace GiNaC