X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=blobdiff_plain;f=ginac%2Ffactor.cpp;h=204010be3750294640434dc28da698f9f452db69;hp=222e05fd55760cfd155c36ca0056060af5e1940e;hb=edc92b7a463993da62357fb4afad053e8c6d0771;hpb=e989719ca767691eb75b34785baaaed716ea2624 diff --git a/ginac/factor.cpp b/ginac/factor.cpp index 222e05fd..204010be 100644 --- a/ginac/factor.cpp +++ b/ginac/factor.cpp @@ -29,11 +29,6 @@ //#define DEBUGFACTOR -#ifdef DEBUGFACTOR -#include -#include -using namespace GiNaC; -#else #include "factor.h" #include "ex.h" @@ -46,22 +41,21 @@ using namespace GiNaC; #include "mul.h" #include "normal.h" #include "add.h" -#endif #include #include +#include #include #include +#ifdef DEBUGFACTOR +#include +#endif using namespace std; #include using namespace cln; -#ifdef DEBUGFACTOR -namespace Factor { -#else namespace GiNaC { -#endif #ifdef DEBUGFACTOR #define DCOUT(str) cout << #str << endl @@ -73,127 +67,328 @@ namespace GiNaC { #define DCOUT2(str,var) #endif -// forward declaration -ex factor(const ex& poly, unsigned options); - // anonymous namespace to hide all utility functions namespace { typedef vector mvec; - #ifdef DEBUGFACTOR -ostream& operator<<(ostream& o, const mvec& v) +ostream& operator<<(ostream& o, const vector& v) { - mvec::const_iterator i = v.begin(), end = v.end(); + vector::const_iterator i = v.begin(), end = v.end(); while ( i != end ) { o << *i++ << " "; } return o; } -#endif // def DEBUGFACTOR - -#ifdef DEBUGFACTOR -ostream& operator<<(ostream& o, const vector& v) +ostream& operator<<(ostream& o, const vector& v) { - vector::const_iterator i = v.begin(), end = v.end(); + vector::const_iterator i = v.begin(), end = v.end(); while ( i != end ) { - o << *i++ << endl; + o << *i << "[" << i-v.begin() << "]" << " "; + ++i; } return o; } -#endif // def DEBUGFACTOR +ostream& operator<<(ostream& o, const vector& v) +{ + vector::const_iterator i = v.begin(), end = v.end(); + while ( i != end ) { + o << *i << "[" << i-v.begin() << "]" << " "; + ++i; + } + return o; +} +ostream& operator<<(ostream& o, const vector< vector >& v) +{ + vector< vector >::const_iterator i = v.begin(), end = v.end(); + while ( i != end ) { + o << i-v.begin() << ": " << *i << endl; + ++i; + } + return o; +} +#endif //////////////////////////////////////////////////////////////////////////////// // modular univariate polynomial code -typedef cl_UP_MI umod; -typedef vector umodvec; +typedef std::vector umodpoly; +typedef std::vector upoly; +typedef vector upvec; -#define COPY(to,from) from.ring()->create(degree(from)); \ - for ( int II=0; II<=degree(from); ++II ) to.set_coeff(II, coeff(from, II)); \ - to.finalize() +// COPY FROM UPOLY.HPP -#ifdef DEBUGFACTOR -ostream& operator<<(ostream& o, const umodvec& v) +// CHANGED size_t -> int !!! +template static int degree(const T& p) { - umodvec::const_iterator i = v.begin(), end = v.end(); - while ( i != end ) { - o << *i++ << " , " << endl; + return p.size() - 1; +} + +template static typename T::value_type lcoeff(const T& p) +{ + return p[p.size() - 1]; +} + +static bool normalize_in_field(umodpoly& a) +{ + if (a.size() == 0) + return true; + if ( lcoeff(a) == a[0].ring()->one() ) { + return true; } - return o; + + const cln::cl_MI lc_1 = recip(lcoeff(a)); + for (std::size_t k = a.size(); k-- != 0; ) + a[k] = a[k]*lc_1; + return false; } -#endif // def DEBUGFACTOR -static umod umod_from_ex(const ex& e, const ex& x, const cl_univpoly_modint_ring& UPR) +template static void +canonicalize(T& p, const typename T::size_type hint = std::numeric_limits::max()) +{ + if (p.empty()) + return; + + std::size_t i = p.size() - 1; + // Be fast if the polynomial is already canonicalized + if (!zerop(p[i])) + return; + + if (hint < p.size()) + i = hint; + + bool is_zero = false; + do { + if (!zerop(p[i])) { + ++i; + break; + } + if (i == 0) { + is_zero = true; + break; + } + --i; + } while (true); + + if (is_zero) { + p.clear(); + return; + } + + p.erase(p.begin() + i, p.end()); +} + +// END COPY FROM UPOLY.HPP + +static void expt_pos(umodpoly& a, unsigned int q) +{ + if ( a.empty() ) return; + cl_MI zero = a[0].ring()->zero(); + int deg = degree(a); + a.resize(degree(a)*q+1, zero); + for ( int i=deg; i>0; --i ) { + a[i*q] = a[i]; + a[i] = zero; + } +} + +template +static T operator+(const T& a, const T& b) +{ + int sa = a.size(); + int sb = b.size(); + if ( sa >= sb ) { + T r(sa); + int i = 0; + for ( ; i +static T operator-(const T& a, const T& b) +{ + int sa = a.size(); + int sb = b.size(); + if ( sa >= sb ) { + T r(sa); + int i = 0; + for ( ; i degree(a) || (i-j) > degree(b) ) continue; + c[i] = c[i] + a[j] * b[i-j]; + } + } + canonicalize(c); + return c; +} + +static umodpoly operator*(const umodpoly& a, const umodpoly& b) +{ + umodpoly c; + if ( a.empty() || b.empty() ) return c; + + int n = degree(a) + degree(b); + c.resize(n+1, a[0].ring()->zero()); + for ( int i=0 ; i<=n; ++i ) { + for ( int j=0 ; j<=i; ++j ) { + if ( j > degree(a) || (i-j) > degree(b) ) continue; + c[i] = c[i] + a[j] * b[i-j]; + } + } + canonicalize(c); + return c; +} + +static upoly operator*(const upoly& a, const cl_I& x) +{ + if ( zerop(x) ) { + upoly r; + return r; + } + upoly r(a.size()); + for ( size_t i=0; icreate(deg); + up.resize(deg+1); int ldeg = e.ldegree(x); for ( ; deg>=ldeg; --deg ) { - cl_I coeff = the(ex_to(e.coeff(x, deg)).to_cl_N()); - p.set_coeff(deg, UPR->basering()->canonhom(coeff)); + up[deg] = the(ex_to(e.coeff(x, deg)).to_cl_N()); } for ( ; deg>=0; --deg ) { - p.set_coeff(deg, UPR->basering()->zero()); + up[deg] = 0; } - p.finalize(); - return p; + canonicalize(up); } -static umod umod_from_ex(const ex& e, const ex& x, const cl_modint_ring& R) +static void umodpoly_from_upoly(umodpoly& ump, const upoly& e, const cl_modint_ring& R) { - return umod_from_ex(e, x, find_univpoly_ring(R)); -} - -static umod umod_from_ex(const ex& e, const ex& x, const cl_I& modulus) -{ - return umod_from_ex(e, x, find_modint_ring(modulus)); + int deg = degree(e); + ump.resize(deg+1); + for ( ; deg>=0; --deg ) { + ump[deg] = R->canonhom(e[deg]); + } + canonicalize(ump); } -static umod umod_from_modvec(const mvec& mv) +static void umodpoly_from_ex(umodpoly& ump, const ex& e, const ex& x, const cl_modint_ring& R) { - size_t n = mv.size(); // assert: n>0 - while ( n && zerop(mv[n-1]) ) --n; - cl_univpoly_modint_ring UPR = find_univpoly_ring(mv.front().ring()); - if ( n == 0 ) { - umod p = UPR->create(-1); - p.finalize(); - return p; + // assert: e is in Z[x] + int deg = e.degree(x); + ump.resize(deg+1); + int ldeg = e.ldegree(x); + for ( ; deg>=ldeg; --deg ) { + cl_I coeff = the(ex_to(e.coeff(x, deg)).to_cl_N()); + ump[deg] = R->canonhom(coeff); } - umod p = UPR->create(n-1); - for ( size_t i=0; i=0; --deg ) { + ump[deg] = R->zero(); } - p.finalize(); - return p; + canonicalize(ump); } -static umod divide(const umod& a, const cl_I& x) +static void umodpoly_from_ex(umodpoly& ump, const ex& e, const ex& x, const cl_I& modulus) { - DCOUT(divide); - DCOUTVAR(a); - cl_univpoly_modint_ring UPR = a.ring(); - cl_modint_ring R = UPR->basering(); - int deg = degree(a); - umod newa = UPR->create(deg); - for ( int i=0; i<=deg; ++i ) { - cl_I c = R->retract(coeff(a, i)); - newa.set_coeff(i, cl_MI(R, the(c / x))); - } - newa.finalize(); - DCOUT(END divide); - return newa; + umodpoly_from_ex(ump, e, x, find_modint_ring(modulus)); } -static ex umod_to_ex(const umod& a, const ex& x) +static ex upoly_to_ex(const upoly& a, const ex& x) { + if ( a.empty() ) return 0; ex e; - cl_modint_ring R = a.ring()->basering(); + for ( int i=degree(a); i>=0; --i ) { + e += numeric(a[i]) * pow(x, i); + } + return e; +} + +static ex umodpoly_to_ex(const umodpoly& a, const ex& x) +{ + if ( a.empty() ) return 0; + cl_modint_ring R = a[0].ring(); cl_I mod = R->modulus; cl_I halfmod = (mod-1) >> 1; + ex e; for ( int i=degree(a); i>=0; --i ) { - cl_I n = R->retract(coeff(a, i)); + cl_I n = R->retract(a[i]); if ( n > halfmod ) { e += numeric(n-mod) * pow(x, i); } else { @@ -203,147 +398,219 @@ static ex umod_to_ex(const umod& a, const ex& x) return e; } -static void unit_normal(umod& a) +static upoly umodpoly_to_upoly(const umodpoly& a) { - int deg = degree(a); - if ( deg >= 0 ) { - cl_MI lc = coeff(a, deg); - cl_MI one = a.ring()->basering()->one(); - if ( lc != one ) { - umod newa = a.ring()->create(deg); - newa.set_coeff(deg, one); - for ( --deg; deg>=0; --deg ) { - cl_MI nc = div(coeff(a, deg), lc); - newa.set_coeff(deg, nc); - } - newa.finalize(); - a = newa; + upoly e(a.size()); + if ( a.empty() ) return e; + cl_modint_ring R = a[0].ring(); + cl_I mod = R->modulus; + cl_I halfmod = (mod-1) >> 1; + for ( int i=degree(a); i>=0; --i ) { + cl_I n = R->retract(a[i]); + if ( n > halfmod ) { + e[i] = n-mod; + } else { + e[i] = n; } } + return e; +} + +static umodpoly umodpoly_to_umodpoly(const umodpoly& a, const cl_modint_ring& R, unsigned int m) +{ + umodpoly e; + if ( a.empty() ) return e; + cl_modint_ring oldR = a[0].ring(); + size_t sa = a.size(); + e.resize(sa+m, R->zero()); + for ( int i=0; icanonhom(oldR->retract(a[i])); + } + canonicalize(e); + return e; +} + +/** Divides all coefficients of the polynomial a by the integer x. + * All coefficients are supposed to be divisible by x. If they are not, the + * the cast will raise an exception. + * + * @param[in,out] a polynomial of which the coefficients will be reduced by x + * @param[in] x integer that divides the coefficients + */ +static void reduce_coeff(umodpoly& a, const cl_I& x) +{ + if ( a.empty() ) return; + + cl_modint_ring R = a[0].ring(); + umodpoly::iterator i = a.begin(), end = a.end(); + for ( ; i!=end; ++i ) { + // cln cannot perform this division in the modular field + cl_I c = R->retract(*i); + *i = cl_MI(R, the(c / x)); + } } -static umod rem(const umod& a, const umod& b) +/** Calculates remainder of a/b. + * Assertion: a and b not empty. + * + * @param[in] a polynomial dividend + * @param[in] b polynomial divisor + * @param[out] r polynomial remainder + */ +static void rem(const umodpoly& a, const umodpoly& b, umodpoly& r) { int k, n; n = degree(b); k = degree(a) - n; - if ( k < 0 ) { - umod c = COPY(c, a); - return c; - } + r = a; + if ( k < 0 ) return; - umod c = COPY(c, a); do { - cl_MI qk = div(coeff(c, n+k), coeff(b, n)); + cl_MI qk = div(r[n+k], b[n]); if ( !zerop(qk) ) { - unsigned int j; for ( int i=0; ibasering()->zero(); - for ( int i=degree(a); i>=n; --i ) { - c.set_coeff(i, zero); - } - - c.finalize(); - return c; + fill(r.begin()+n, r.end(), a[0].ring()->zero()); + canonicalize(r); } -static umod div(const umod& a, const umod& b) +/** Calculates quotient of a/b. + * Assertion: a and b not empty. + * + * @param[in] a polynomial dividend + * @param[in] b polynomial divisor + * @param[out] q polynomial quotient + */ +static void div(const umodpoly& a, const umodpoly& b, umodpoly& q) { int k, n; n = degree(b); k = degree(a) - n; - if ( k < 0 ) { - umod q = a.ring()->create(-1); - q.finalize(); - return q; - } + q.clear(); + if ( k < 0 ) return; - umod c = COPY(c, a); - umod q = a.ring()->create(k); + umodpoly r = a; + q.resize(k+1, a[0].ring()->zero()); do { - cl_MI qk = div(coeff(c, n+k), coeff(b, n)); + cl_MI qk = div(r[n+k], b[n]); if ( !zerop(qk) ) { - q.set_coeff(k, qk); - unsigned int j; + q[k] = qk; for ( int i=0; icreate(-1); - q.finalize(); - umod c = COPY(c, a); - return c; - } + q.clear(); + r = a; + if ( k < 0 ) return; - umod c = COPY(c, a); - q = a.ring()->create(k); + q.resize(k+1, a[0].ring()->zero()); do { - cl_MI qk = div(coeff(c, n+k), coeff(b, n)); + cl_MI qk = div(r[n+k], b[n]); if ( !zerop(qk) ) { - q.set_coeff(k, qk); - unsigned int j; + q[k] = qk; for ( int i=0; ibasering()->zero(); - for ( int i=degree(a); i>=n; --i ) { - c.set_coeff(i, zero); - } + fill(r.begin()+n, r.end(), a[0].ring()->zero()); + canonicalize(r); + canonicalize(q); +} - q.finalize(); - c.finalize(); - return c; +/** Calculates the GCD of polynomial a and b. + * + * @param[in] a polynomial + * @param[in] b polynomial + * @param[out] c GCD + */ +static void gcd(const umodpoly& a, const umodpoly& b, umodpoly& c) +{ + if ( degree(a) < degree(b) ) return gcd(b, a, c); + + c = a; + normalize_in_field(c); + umodpoly d = b; + normalize_in_field(d); + umodpoly r; + while ( !d.empty() ) { + rem(c, d, r); + c = d; + d = r; + } + normalize_in_field(c); } -static umod gcd(const umod& a, const umod& b) +/** Calculates the derivative of the polynomial a. + * + * @param[in] a polynomial of which to take the derivative + * @param[out] d result/derivative + */ +static void deriv(const umodpoly& a, umodpoly& d) { - if ( degree(a) < degree(b) ) return gcd(b, a); + d.clear(); + if ( a.size() <= 1 ) return; - umod c = COPY(c, a); - unit_normal(c); - umod d = COPY(d, b); - unit_normal(d); - while ( !zerop(d) ) { - umod r = rem(c, d); - c = COPY(c, d); - d = COPY(d, r); + d.insert(d.begin(), a.begin()+1, a.end()); + int max = d.size(); + for ( int i=1; ione() ); +} + +static bool equal_one(const umodpoly& a) +{ + return ( a.size() == 1 && a[0] == a[0].ring()->one() ); +} + +/** Returns true if polynomial a is square free. + * + * @param[in] a polynomial to check + * @return true if polynomial is square free, false otherwise + */ +static bool squarefree(const umodpoly& a) +{ + umodpoly b; + deriv(a, b); + if ( b.empty() ) { + return true; } - umod one = a.ring()->one(); - umod c = gcd(a, b); - return c == one; + umodpoly c; + gcd(a, b, c); + return equal_one(c); } // END modular univariate polynomial code @@ -481,15 +748,19 @@ modular_matrix operator*(const modular_matrix& m1, const modular_matrix& m2) ostream& operator<<(ostream& o, const modular_matrix& m) { - vector::const_iterator i = m.m.begin(), end = m.m.end(); - size_t wrap = 1; - for ( ; i != end; ++i ) { - o << *i << " "; - if ( !(wrap++ % m.c) ) { - o << endl; + cl_modint_ring R = m(0,0).ring(); + o << "{"; + for ( size_t i=0; iretract(m(i,j)) << ","; + } + o << R->retract(m(i,m.colsize()-1)) << "}"; + if ( i != m.rowsize()-1 ) { + o << ","; } } - o << endl; + o << "}"; return o; } #endif // def DEBUGFACTOR @@ -497,37 +768,26 @@ ostream& operator<<(ostream& o, const modular_matrix& m) // END modular matrix //////////////////////////////////////////////////////////////////////////////// -static void q_matrix(const umod& a, modular_matrix& Q) +static void q_matrix(const umodpoly& a_, modular_matrix& Q) { + umodpoly a = a_; + normalize_in_field(a); + int n = degree(a); - unsigned int q = cl_I_to_uint(a.ring()->basering()->modulus); -// fast and buggy -// vector r(n, a.R->zero()); -// r[0] = a.R->one(); -// Q.set_row(0, r); -// unsigned int max = (n-1) * q; -// for ( size_t m=1; m<=max; ++m ) { -// cl_MI rn_1 = r.back(); -// for ( size_t i=n-1; i>0; --i ) { -// r[i] = r[i-1] - rn_1 * a[i]; -// } -// r[0] = -rn_1 * a[0]; -// if ( (m % q) == 0 ) { -// Q.set_row(m/q, r); -// } -// } -// slow and (hopefully) correct - cl_MI one = a.ring()->basering()->one(); - for ( int i=0; icreate(i*q); - qk.set_coeff(i*q, one); - qk.finalize(); - umod r = rem(qk, a); - mvec rvec; - for ( int j=0; jmodulus); + umodpoly r(n, a[0].ring()->zero()); + r[0] = a[0].ring()->one(); + Q.set_row(0, r); + unsigned int max = (n-1) * q; + for ( size_t m=1; m<=max; ++m ) { + cl_MI rn_1 = r.back(); + for ( size_t i=n-1; i>0; --i ) { + r[i] = r[i-1] - (rn_1 * a[i]); + } + r[0] = -rn_1 * a[0]; + if ( (m % q) == 0 ) { + Q.set_row(m/q, r); + } } } @@ -575,52 +835,54 @@ static void nullspace(modular_matrix& M, vector& basis) } } -static void berlekamp(const umod& a, umodvec& upv) +static void berlekamp(const umodpoly& a, upvec& upv) { - cl_modint_ring R = a.ring()->basering(); - const umod one = a.ring()->one(); + cl_modint_ring R = a[0].ring(); + umodpoly one(1, R->one()); modular_matrix Q(degree(a), degree(a), R->zero()); q_matrix(a, Q); vector nu; nullspace(Q, nu); + const unsigned int k = nu.size(); if ( k == 1 ) { return; } - list factors; + list factors; factors.push_back(a); unsigned int size = 1; unsigned int r = 1; unsigned int q = cl_I_to_uint(R->modulus); - list::iterator u = factors.begin(); + list::iterator u = factors.begin(); while ( true ) { for ( unsigned int s=0; s::const_iterator i = factors.begin(), end = factors.end(); + list::const_iterator i = factors.begin(), end = factors.end(); while ( i != end ) { if ( degree(*i) ) ++size; ++i; } if ( size == k ) { - list::const_iterator i = factors.begin(), end = factors.end(); + list::const_iterator i = factors.begin(), end = factors.end(); while ( i != end ) { upv.push_back(*i++); } @@ -635,326 +897,299 @@ static void berlekamp(const umod& a, umodvec& upv) } } -static umod rem_xq(int q, const umod& b) +static void expt_1_over_p(const umodpoly& a, unsigned int prime, umodpoly& ap) { - cl_univpoly_modint_ring UPR = b.ring(); - cl_modint_ring R = UPR->basering(); - - int n = degree(b); - if ( n > q ) { - umod c = UPR->create(q); - c.set_coeff(q, R->one()); - c.finalize(); - return c; + size_t newdeg = degree(a)/prime; + ap.resize(newdeg+1); + ap[0] = a[0]; + for ( size_t i=1; i<=newdeg; ++i ) { + ap[i] = a[i*prime]; } +} - mvec c(n+1, R->zero()); - int k = q-n; - c[n] = R->one(); - DCOUTVAR(k); - - int ofs = 0; - do { - cl_MI qk = div(c[n-ofs], coeff(b, n)); - if ( !zerop(qk) ) { - for ( int i=1; i<=n; ++i ) { - c[n-i+ofs] = c[n-i] - qk * coeff(b, n-i); +static void modsqrfree(const umodpoly& a, upvec& factors, vector& mult) +{ + const unsigned int prime = cl_I_to_uint(a[0].ring()->modulus); + int i = 1; + umodpoly b; + deriv(a, b); + if ( b.size() ) { + umodpoly c; + gcd(a, b, c); + umodpoly w; + div(a, c, w); + while ( unequal_one(w) ) { + umodpoly y; + gcd(w, c, y); + umodpoly z; + div(w, y, z); + factors.push_back(z); + mult.push_back(i); + ++i; + w = y; + umodpoly buf; + div(c, y, buf); + c = buf; + } + if ( unequal_one(c) ) { + umodpoly cp; + expt_1_over_p(c, prime, cp); + size_t previ = mult.size(); + modsqrfree(cp, factors, mult); + for ( size_t i=previ; i& degrees, upvec& ddfactors) { - umod a = COPY(a, a_); + umodpoly a = a_; - DCOUT(distinct_degree_factor); - DCOUTVAR(a); - - cl_univpoly_modint_ring UPR = a.ring(); - cl_modint_ring R = UPR->basering(); + cl_modint_ring R = a[0].ring(); int q = cl_I_to_int(R->modulus); - int n = degree(a); - size_t nhalf = n/2; + int nhalf = degree(a)/2; + int i = 1; + umodpoly w(2); + w[0] = R->zero(); + w[1] = R->one(); + umodpoly x = w; - size_t i = 1; - umod w = UPR->create(1); - w.set_coeff(1, R->one()); - w.finalize(); - umod x = COPY(x, w); - - umodvec ai; - + bool nontrivial = false; while ( i <= nhalf ) { - w = expt_pos(w, q); - w = rem(w, a); - - ai.push_back(gcd(a, w-x)); - - if ( ai.back() != UPR->one() ) { - a = div(a, ai.back()); - w = rem(w, a); + expt_pos(w, q); + umodpoly buf; + rem(w, a, buf); + w = buf; + umodpoly wx = w - x; + gcd(a, wx, buf); + if ( unequal_one(buf) ) { + degrees.push_back(i); + ddfactors.push_back(buf); + } + if ( unequal_one(buf) ) { + umodpoly buf2; + div(a, buf, buf2); + a = buf2; + nhalf = degree(a)/2; + rem(w, a, buf); + w = buf; } - ++i; } - - result = ai; - DCOUTVAR(result); - DCOUT(END distinct_degree_factor); + if ( unequal_one(a) ) { + degrees.push_back(degree(a)); + ddfactors.push_back(a); + } } -static void same_degree_factor(const umod& a, umodvec& result) +static void same_degree_factor(const umodpoly& a, upvec& upv) { - DCOUT(same_degree_factor); - - cl_univpoly_modint_ring UPR = a.ring(); - cl_modint_ring R = UPR->basering(); + cl_modint_ring R = a[0].ring(); int deg = degree(a); - umodvec buf; - distinct_degree_factor(a, buf); - int degsum = 0; - - for ( size_t i=0; ione() ) { - degsum += degree(buf[i]); - umodvec upv; - berlekamp(buf[i], upv); - for ( size_t j=0; j degrees; + upvec ddfactors; + distinct_degree_factor(a, degrees, ddfactors); - if ( degsum < deg ) { - result.push_back(a); + for ( size_t i=0; ibasering(); - int q = cl_I_to_int(R->modulus); - int n = degree(a); - - cl_N pm = 0.3; - int l = cl_I_to_int(ceiling1(the(expt(n, pm)))); - DCOUTVAR(l); - umodvec h(l+1, UPR->create(-1)); - umod qk = UPR->create(1); - qk.set_coeff(1, R->one()); - qk.finalize(); - h[0] = qk; - DCOUTVAR(h[0]); - for ( int i=1; i<=l; ++i ) { - qk = expt_pos(h[i-1], q); - h[i] = rem(qk, a); - DCOUTVAR(i); - DCOUTVAR(h[i]); - } - - int m = std::ceil(((double)n)/2/l); - DCOUTVAR(m); - umodvec H(m, UPR->create(-1)); - int ql = std::pow(q, l); - H[0] = COPY(H[0], h[l]); - DCOUTVAR(H[0]); - for ( int i=1; icreate(-1)); - for ( int i=0; ione(); - for ( int j=0; jone()); - umod f = COPY(f, a); - for ( int i=0; ione() ) continue; - F[i] = g; - f = div(f, g); - DCOUTVAR(F[i]); - } - - result.resize(n, UPR->one()); - if ( f != UPR->one() ) { - result[n] = f; - } - for ( int i=0; i=0; --j ) { - umod g = gcd(f, H[i]-h[j]); - result[l*(i+1)-j-1] = g; - f = div(f, g); - } - } - - DCOUTVAR(result); - DCOUT(END distinct_degree_factor_BSGS); } -static void cantor_zassenhaus(const umod& a, umodvec& result) +static void factor_modular(const umodpoly& p, upvec& upv) { -} + upvec factors; + vector mult; + modsqrfree(p, factors, mult); -static void factor_modular(const umod& p, umodvec& upv) -{ - //same_degree_factor(p, upv); - berlekamp(p, upv); - return; +#define USE_SAME_DEGREE_FACTOR +#ifdef USE_SAME_DEGREE_FACTOR + for ( size_t i=0; i0; --j ) { + upv.insert(upv.end(), upvbuf.begin(), upvbuf.end()); + } + } +#else + for ( size_t i=0; i0; --j ) { + upv.push_back(factors[i]); + } + } + } +#endif } -static void exteuclid(const umod& a, const umod& b, umod& g, umod& s, umod& t) +/** Calculates polynomials s and t such that a*s+b*t==1. + * Assertion: a and b are relatively prime and not zero. + * + * @param[in] a polynomial + * @param[in] b polynomial + * @param[out] s polynomial + * @param[out] t polynomial + */ +static void exteuclid(const umodpoly& a, const umodpoly& b, umodpoly& s, umodpoly& t) { if ( degree(a) < degree(b) ) { - exteuclid(b, a, g, t, s); + exteuclid(b, a, t, s); return; } - umod c = COPY(c, a); unit_normal(c); - umod d = COPY(d, b); unit_normal(d); - umod c1 = a.ring()->one(); - umod c2 = a.ring()->create(-1); - umod d1 = a.ring()->create(-1); - umod d2 = a.ring()->one(); - while ( !zerop(d) ) { - umod q = div(c, d); - umod r = c - q * d; - umod r1 = c1 - q * d1; - umod r2 = c2 - q * d2; - c = COPY(c, d); - c1 = COPY(c1, d1); - c2 = COPY(c2, d2); - d = COPY(d, r); - d1 = COPY(d1, r1); - d2 = COPY(d2, r2); - } - g = COPY(g, c); unit_normal(g); - s = COPY(s, c1); - for ( int i=0; i<=degree(s); ++i ) { - s.set_coeff(i, coeff(s, i) * recip(coeff(a, degree(a)) * coeff(c, degree(c)))); - } - s.finalize(); - t = COPY(t, c2); - for ( int i=0; i<=degree(t); ++i ) { - t.set_coeff(i, coeff(t, i) * recip(coeff(b, degree(b)) * coeff(c, degree(c)))); - } - t.finalize(); + + umodpoly one(1, a[0].ring()->one()); + umodpoly c = a; normalize_in_field(c); + umodpoly d = b; normalize_in_field(d); + s = one; + t.clear(); + umodpoly d1; + umodpoly d2 = one; + umodpoly q; + while ( true ) { + div(c, d, q); + umodpoly r = c - q * d; + umodpoly r1 = s - q * d1; + umodpoly r2 = t - q * d2; + c = d; + s = d1; + t = d2; + if ( r.empty() ) break; + d = r; + d1 = r1; + d2 = r2; + } + cl_MI fac = recip(lcoeff(a) * lcoeff(c)); + umodpoly::iterator i = s.begin(), end = s.end(); + for ( ; i!=end; ++i ) { + *i = *i * fac; + } + canonicalize(s); + fac = recip(lcoeff(b) * lcoeff(c)); + i = t.begin(), end = t.end(); + for ( ; i!=end; ++i ) { + *i = *i * fac; + } + canonicalize(t); } -static ex replace_lc(const ex& poly, const ex& x, const ex& lc) +static upoly replace_lc(const upoly& poly, const cl_I& lc) { - ex r = expand(poly + (lc - poly.lcoeff(x)) * pow(x, poly.degree(x))); + if ( poly.empty() ) return poly; + upoly r = poly; + r.back() = lc; return r; } -static ex hensel_univar(const ex& a_, const ex& x, unsigned int p, const umod& u1_, const umod& w1_, const ex& gamma_ = 0) +static void hensel_univar(const upoly& a_, unsigned int p, const umodpoly& u1_, const umodpoly& w1_, upoly& u, upoly& w) { - ex a = a_; - const cl_univpoly_modint_ring& UPR = u1_.ring(); - const cl_modint_ring& R = UPR->basering(); + upoly a = a_; + const cl_modint_ring& R = u1_[0].ring(); // calc bound B - ex maxcoeff; - for ( int i=a.degree(x); i>=a.ldegree(x); --i ) { - maxcoeff += pow(abs(a.coeff(x, i)),2); + cl_R maxcoeff = 0; + for ( int i=degree(a); i>=0; --i ) { + maxcoeff = maxcoeff + square(abs(a[i])); } - cl_I normmc = ceiling1(the(cln::sqrt(ex_to(maxcoeff).to_cl_N()))); + cl_I normmc = ceiling1(the(cln::sqrt(maxcoeff))); cl_I maxdegree = (degree(u1_) > degree(w1_)) ? degree(u1_) : degree(w1_); cl_I B = normmc * expt_pos(cl_I(2), maxdegree); // step 1 - ex alpha = a.lcoeff(x); - ex gamma = gamma_; - if ( gamma == 0 ) { - gamma = alpha; - } - numeric gamma_ui = ex_to(abs(gamma)); - a = a * gamma; - umod nu1 = COPY(nu1, u1_); - unit_normal(nu1); - umod nw1 = COPY(nw1, w1_); - unit_normal(nw1); - ex phi; - phi = gamma * umod_to_ex(nu1, x); - umod u1 = umod_from_ex(phi, x, R); - phi = alpha * umod_to_ex(nw1, x); - umod w1 = umod_from_ex(phi, x, R); + cl_I alpha = lcoeff(a); + a = a * alpha; + umodpoly nu1 = u1_; + normalize_in_field(nu1); + umodpoly nw1 = w1_; + normalize_in_field(nw1); + upoly phi; + phi = umodpoly_to_upoly(nu1) * alpha; + umodpoly u1; + umodpoly_from_upoly(u1, phi, R); + phi = umodpoly_to_upoly(nw1) * alpha; + umodpoly w1; + umodpoly_from_upoly(w1, phi, R); // step 2 - umod g = UPR->create(-1); - umod s = UPR->create(-1); - umod t = UPR->create(-1); - exteuclid(u1, w1, g, s, t); + umodpoly s; + umodpoly t; + exteuclid(u1, w1, s, t); // step 3 - ex u = replace_lc(umod_to_ex(u1, x), x, gamma); - ex w = replace_lc(umod_to_ex(w1, x), x, alpha); - ex e = expand(a - u * w); - numeric modulus = p; - const numeric maxmodulus = 2*numeric(B)*gamma_ui; + u = replace_lc(umodpoly_to_upoly(u1), alpha); + w = replace_lc(umodpoly_to_upoly(w1), alpha); + upoly e = a - u * w; + cl_I modulus = p; + const cl_I maxmodulus = 2*B*abs(alpha); // step 4 - while ( !e.is_zero() && modulus < maxmodulus ) { - ex c = e / modulus; - phi = expand(umod_to_ex(s, x) * c); - umod sigmatilde = umod_from_ex(phi, x, R); - phi = expand(umod_to_ex(t, x) * c); - umod tautilde = umod_from_ex(phi, x, R); - umod q = UPR->create(-1); - umod r = remdiv(sigmatilde, w1, q); - umod sigma = COPY(sigma, r); - phi = expand(umod_to_ex(tautilde, x) + umod_to_ex(q, x) * umod_to_ex(u1, x)); - umod tau = umod_from_ex(phi, x, R); - u = expand(u + umod_to_ex(tau, x) * modulus); - w = expand(w + umod_to_ex(sigma, x) * modulus); - e = expand(a - u * w); + while ( !e.empty() && modulus < maxmodulus ) { + // ad-hoc divisablity check + for ( size_t k=0; kone()); + split(); } int operator[](size_t i) const { return k[i]; } size_t size() const { return n; } size_t size_first() const { return n-sum; } size_t size_second() const { return sum; } #ifdef DEBUGFACTOR - void get() const - { - for ( size_t i=0; i 0; + if ( sum > 0 ) { + split(); + return true; + } + else { + return false; + } } ++k[i]; ++sum; } return false; } + void split() + { + left = one; + right = one; + for ( size_t i=0; i k; }; -static void split(const umodvec& factors, const Partition& part, umod& a, umod& b) -{ - a = factors.front().ring()->one(); - b = factors.front().ring()->one(); - for ( size_t i=0; i(prim.lcoeff(x)); - umodvec factors; + cl_I lc = lcoeff(prim); + upvec factors; while ( trials < 2 ) { + umodpoly modpoly; while ( true ) { p = next_prime(p); - if ( irem(lcoeff, p) != 0 ) { + if ( !zerop(rem(lc, p)) ) { R = find_modint_ring(p); - umod modpoly = umod_from_ex(prim, x, R); + umodpoly_from_upoly(modpoly, prim, R); if ( squarefree(modpoly) ) break; } } // do modular factorization - umod modpoly = umod_from_ex(prim, x, R); - umodvec trialfactors; + upvec trialfactors; factor_modular(modpoly, trialfactors); if ( trialfactors.size() <= 1 ) { // irreducible for sure @@ -1094,7 +1334,6 @@ static ex factor_univariate(const ex& poly, const ex& x) } p = lastp; R = find_modint_ring(p); - cl_univpoly_modint_ring UPR = find_univpoly_ring(R); // lift all factor combinations stack tocheck; @@ -1102,25 +1341,22 @@ static ex factor_univariate(const ex& poly, const ex& x) mf.poly = prim; mf.factors = factors; tocheck.push(mf); + upoly f1, f2; ex result = 1; while ( tocheck.size() ) { const size_t n = tocheck.top().factors.size(); - Partition part(n); + factor_partition part(tocheck.top().factors); while ( true ) { - umod a = UPR->create(-1); - umod b = UPR->create(-1); - split(tocheck.top().factors, part, a, b); - - ex answer = hensel_univar(tocheck.top().poly, x, p, a, b); - if ( answer != lst() ) { + hensel_univar(tocheck.top().poly, p, part.left, part.right, f1, f2); + if ( !f1.empty() ) { if ( part.size_first() == 1 ) { if ( part.size_second() == 1 ) { - result *= answer.op(0) * answer.op(1); + result *= upoly_to_ex(f1, x) * upoly_to_ex(f2, x); tocheck.pop(); break; } - result *= answer.op(0); - tocheck.top().poly = answer.op(1); + result *= upoly_to_ex(f1, x); + tocheck.top().poly = f2; for ( size_t i=0; icreate(-1)), newfactors2(part.size_second(), UPR->create(-1)); - umodvec::iterator i1 = newfactors1.begin(), i2 = newfactors2.begin(); + upvec newfactors1(part.size_first()), newfactors2(part.size_second()); + upvec::iterator i1 = newfactors1.begin(), i2 = newfactors2.begin(); for ( size_t i=0; i multivar_diophant(const vector& a_, const ex& x, const ex& c, const vector& I, unsigned int d, unsigned int p, unsigned int k); -umodvec multiterm_eea_lift(const umodvec& a, const ex& x, unsigned int p, unsigned int k) +upvec multiterm_eea_lift(const upvec& a, const ex& x, unsigned int p, unsigned int k) { - DCOUT(multiterm_eea_lift); - DCOUTVAR(a); - DCOUTVAR(p); - DCOUTVAR(k); - const size_t r = a.size(); - DCOUTVAR(r); cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k)); - cl_univpoly_modint_ring UPR = find_univpoly_ring(R); - umodvec q(r-1, UPR->create(-1)); + upvec q(r-1); q[r-2] = a[r-1]; for ( size_t j=r-2; j>=1; --j ) { q[j-1] = a[j] * q[j]; } - DCOUTVAR(q); - umod beta = UPR->one(); - umodvec s; + umodpoly beta(1, R->one()); + upvec s; for ( size_t j=1; j mdarg(2); - mdarg[0] = umod_to_ex(q[j-1], x); - mdarg[1] = umod_to_ex(a[j-1], x); + mdarg[0] = umodpoly_to_ex(q[j-1], x); + mdarg[1] = umodpoly_to_ex(a[j-1], x); vector empty; - vector exsigma = multivar_diophant(mdarg, x, umod_to_ex(beta, x), empty, 0, p, k); - umod sigma1 = umod_from_ex(exsigma[0], x, R); - umod sigma2 = umod_from_ex(exsigma[1], x, R); - beta = COPY(beta, sigma1); + vector exsigma = multivar_diophant(mdarg, x, umodpoly_to_ex(beta, x), empty, 0, p, k); + umodpoly sigma1; + umodpoly_from_ex(sigma1, exsigma[0], x, R); + umodpoly sigma2; + umodpoly_from_ex(sigma2, exsigma[1], x, R); + beta = sigma1; s.push_back(sigma2); } s.push_back(beta); - - DCOUTVAR(s); - DCOUT(END multiterm_eea_lift); return s; } -void change_modulus(umod& out, const umod& in) +/** + * Assert: a not empty. + */ +void change_modulus(const cl_modint_ring& R, umodpoly& a) { - // ASSERT: out and in have same degree - if ( out.ring() == in.ring() ) { - out = COPY(out, in); - } - else { - for ( int i=0; i<=degree(in); ++i ) { - out.set_coeff(i, out.ring()->basering()->canonhom(in.ring()->basering()->retract(coeff(in, i)))); - } - out.finalize(); + if ( a.empty() ) return; + cl_modint_ring oldR = a[0].ring(); + umodpoly::iterator i = a.begin(), end = a.end(); + for ( ; i!=end; ++i ) { + *i = R->canonhom(oldR->retract(*i)); } + canonicalize(a); } -void eea_lift(const umod& a, const umod& b, const ex& x, unsigned int p, unsigned int k, umod& s_, umod& t_) +void eea_lift(const umodpoly& a, const umodpoly& b, const ex& x, unsigned int p, unsigned int k, umodpoly& s_, umodpoly& t_) { - DCOUT(eea_lift); - cl_modint_ring R = find_modint_ring(p); - cl_univpoly_modint_ring UPR = find_univpoly_ring(R); - umod amod = UPR->create(degree(a)); - change_modulus(amod, a); - umod bmod = UPR->create(degree(b)); - change_modulus(bmod, b); - - umod g = UPR->create(-1); - umod smod = UPR->create(-1); - umod tmod = UPR->create(-1); - exteuclid(amod, bmod, g, smod, tmod); - + umodpoly amod = a; + change_modulus(R, amod); + umodpoly bmod = b; + change_modulus(R, bmod); + + umodpoly smod; + umodpoly tmod; + exteuclid(amod, bmod, smod, tmod); + cl_modint_ring Rpk = find_modint_ring(expt_pos(cl_I(p),k)); - cl_univpoly_modint_ring UPRpk = find_univpoly_ring(Rpk); - umod s = UPRpk->create(degree(smod)); - change_modulus(s, smod); - umod t = UPRpk->create(degree(tmod)); - change_modulus(t, tmod); + umodpoly s = smod; + change_modulus(Rpk, s); + umodpoly t = tmod; + change_modulus(Rpk, t); cl_I modulus(p); - umod one = UPRpk->one(); + umodpoly one(1, Rpk->one()); for ( size_t j=1; jcreate(degree(e)); - change_modulus(c, e); - umod sigmabar = smod * c; - umod taubar = tmod * c; - umod q = UPR->create(-1); - umod sigma = remdiv(sigmabar, bmod, q); - umod tau = taubar + q * amod; - umod sadd = UPRpk->create(degree(sigma)); - change_modulus(sadd, sigma); + umodpoly e = one - a * s - b * t; + reduce_coeff(e, modulus); + umodpoly c = e; + change_modulus(R, c); + umodpoly sigmabar = smod * c; + umodpoly taubar = tmod * c; + umodpoly sigma, q; + remdiv(sigmabar, bmod, sigma, q); + umodpoly tau = taubar + q * amod; + umodpoly sadd = sigma; + change_modulus(Rpk, sadd); cl_MI modmodulus(Rpk, modulus); s = s + sadd * modmodulus; - umod tadd = UPRpk->create(degree(tau)); - change_modulus(tadd, tau); + umodpoly tadd = tau; + change_modulus(Rpk, tadd); t = t + tadd * modmodulus; modulus = modulus * p; } s_ = s; t_ = t; - - DCOUT2(check, a*s + b*t); - DCOUT(END eea_lift); } -umodvec univar_diophant(const umodvec& a, const ex& x, unsigned int m, unsigned int p, unsigned int k) +upvec univar_diophant(const upvec& a, const ex& x, unsigned int m, unsigned int p, unsigned int k) { - DCOUT(univar_diophant); - DCOUTVAR(a); - DCOUTVAR(x); - DCOUTVAR(m); - DCOUTVAR(p); - DCOUTVAR(k); - cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k)); - cl_univpoly_modint_ring UPR = find_univpoly_ring(R); const size_t r = a.size(); - umodvec result; + upvec result; if ( r > 2 ) { - umodvec s = multiterm_eea_lift(a, x, p, k); + upvec s = multiterm_eea_lift(a, x, p, k); for ( size_t j=0; jcreate(-1); - umod t = UPR->create(-1); + umodpoly s, t; eea_lift(a[1], a[0], x, p, k, s, t); - ex phi = expand(pow(x,m) * umod_to_ex(s, x)); - umod bmod = umod_from_ex(phi, x, R); - umod q = UPR->create(-1); - umod buf = remdiv(bmod, a[0], q); + umodpoly bmod = umodpoly_to_umodpoly(s, R, m); + umodpoly buf, q; + remdiv(bmod, a[0], buf, q); + result.push_back(buf); + umodpoly t1mod = umodpoly_to_umodpoly(t, R, m); + buf = t1mod + q * a[1]; result.push_back(buf); - phi = expand(pow(x,m) * umod_to_ex(t, x)); - umod t1mod = umod_from_ex(phi, x, R); - umod buf2 = t1mod + q * a[1]; - result.push_back(buf2); } - DCOUTVAR(result); - DCOUT(END univar_diophant); return result; } @@ -1371,32 +1572,9 @@ vector multivar_diophant(const vector& a_, const ex& x, const ex& c, con { vector a = a_; - DCOUT(multivar_diophant); -#ifdef DEBUGFACTOR - cout << "a "; - for ( size_t i=0; i sigma; if ( nu > 1 ) { @@ -1420,7 +1598,6 @@ vector multivar_diophant(const vector& a_, const ex& x, const ex& c, con vector Inew = I; Inew.pop_back(); sigma = multivar_diophant(anew, x, cnew, Inew, d, p, k); - DCOUTVAR(sigma); ex buf = c; for ( size_t i=0; i multivar_diophant(const vector& a_, const ex& x, const ex& c, con } ex e = make_modular(buf, R); - DCOUTVAR(e); - DCOUTVAR(d); ex monomial = 1; for ( size_t m=1; m<=d; ++m ) { - DCOUTVAR(m); while ( !e.is_zero() && e.has(xnu) ) { monomial *= (xnu - alphanu); monomial = expand(monomial); - DCOUTVAR(monomial); - DCOUTVAR(xnu); - DCOUTVAR(alphanu); ex cm = e.diff(ex_to(xnu), m).subs(xnu==alphanu) / factorial(m); cm = make_modular(cm, R); - DCOUTVAR(cm); if ( !cm.is_zero() ) { vector delta_s = multivar_diophant(anew, x, cm, Inew, d, p, k); - DCOUTVAR(delta_s); ex buf = e; for ( size_t j=0; j multivar_diophant(const vector& a_, const ex& x, const ex& c, con buf -= delta_s[j] * b[j]; } e = make_modular(buf, R); - DCOUTVAR(e); } } } } else { - DCOUT(uniterm left); - umodvec amod; + upvec amod; for ( size_t i=0; i multivar_diophant(const vector& a_, const ex& x, const ex& c, con nterms = 1; z = c; } - DCOUTVAR(nterms); for ( size_t i=0; i(ex_to(z.lcoeff(x)).to_cl_N()); - DCOUTVAR(cm); - umodvec delta_s = univar_diophant(amod, x, m, p, k); + upvec delta_s = univar_diophant(amod, x, m, p, k); cl_MI modcm; cl_I poscm = cm; while ( poscm < 0 ) { poscm = poscm + expt_pos(cl_I(p),k); } modcm = cl_MI(R, poscm); - DCOUTVAR(modcm); for ( size_t j=0; j 1 ) { z = c.op(i+1); } } } -#ifdef DEBUGFACTOR - cout << "sigma "; - for ( size_t i=0; i& v) } #endif // def DEBUGFACTOR - -ex hensel_multivar(const ex& a, const ex& x, const vector& I, unsigned int p, const cl_I& l, const umodvec& u, const vector& lcU) +ex hensel_multivar(const ex& a, const ex& x, const vector& I, unsigned int p, const cl_I& l, const upvec& u, const vector& lcU) { - DCOUT(hensel_multivar); - DCOUTVAR(a); - DCOUTVAR(x); - DCOUTVAR(I); - DCOUTVAR(p); - DCOUTVAR(l); - DCOUTVAR(u); - DCOUTVAR(lcU); const size_t nu = I.size() + 1; const cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),l)); - DCOUTVAR(nu); - vector A(nu); A[nu-1] = a; @@ -1567,36 +1696,21 @@ ex hensel_multivar(const ex& a, const ex& x, const vector& I, unsigne A[j-2] = make_modular(A[j-2], R); } -#ifdef DEBUGFACTOR - cout << "A "; - for ( size_t i=0; i maxdeg ) maxdeg = maxdeg2; } - DCOUTVAR(maxdeg); const size_t n = u.size(); - DCOUTVAR(n); vector U(n); for ( size_t i=0; i U1 = U; ex monomial = 1; - DCOUTVAR(U); for ( size_t m=0; m& I, unsigne U[m] = U[m] - U[m].lcoeff(x) * pow(x,deg) + coef * pow(x,deg); } } - DCOUTVAR(U); ex Uprod = 1; for ( size_t i=0; i newI; for ( size_t i=1; i<=j-2; ++i ) { newI.push_back(I[i-1]); } - DCOUTVAR(newI); ex xj = I[j-2].x; int alphaj = I[j-2].evalpoint; size_t deg = A[j-1].degree(xj); - DCOUTVAR(deg); for ( size_t k=1; k<=deg; ++k ) { - DCOUTVAR(k); if ( !e.is_zero() ) { - DCOUTVAR(xj); - DCOUTVAR(alphaj); monomial *= (xj - alphaj); monomial = expand(monomial); - DCOUTVAR(monomial); ex dif = e.diff(ex_to(xj), k); - DCOUTVAR(dif); ex c = dif.subs(xj==alphaj) / factorial(k); - DCOUTVAR(c); if ( !c.is_zero() ) { vector deltaU = multivar_diophant(U1, x, c, newI, maxdeg, p, cl_I_to_uint(l)); for ( size_t i=0; i& I, unsigne for ( size_t i=0; i(e) ) { result.append(e); - DCOUT(END put_factors_into_lst); - DCOUTVAR(result); return result; } if ( is_a(e) ) { result.append(1); result.append(e.op(0)); result.append(e.op(1)); - DCOUT(END put_factors_into_lst); - DCOUTVAR(result); return result; } if ( is_a(e) || is_a(e) ) { result.append(1); result.append(e); result.append(1); - DCOUT(END put_factors_into_lst); - DCOUTVAR(result); return result; } if ( is_a(e) ) { @@ -1730,8 +1814,6 @@ static ex put_factors_into_lst(const ex& e) } } result.prepend(nfac); - DCOUT(END put_factors_into_lst); - DCOUTVAR(result); return result; } throw runtime_error("put_factors_into_lst: bad term."); @@ -1749,53 +1831,32 @@ ostream& operator<<(ostream& o, const vector& v) static bool checkdivisors(const lst& f, vector& d) { - DCOUT(checkdivisors); const int k = f.nops()-2; - DCOUTVAR(k); - DCOUTVAR(d.size()); numeric q, r; d[0] = ex_to(f.op(0) * f.op(f.nops()-1)); if ( d[0] == 1 && k == 1 && abs(f.op(1)) != 1 ) { - DCOUT(false); - DCOUT(END checkdivisors); return false; } - DCOUTVAR(d[0]); for ( int i=1; i<=k; ++i ) { - DCOUTVAR(i); - DCOUTVAR(abs(f.op(i))); q = ex_to(abs(f.op(i))); - DCOUTVAR(q); for ( int j=i-1; j>=0; --j ) { r = d[j]; - DCOUTVAR(r); do { r = gcd(r, q); - DCOUTVAR(r); q = q/r; - DCOUTVAR(q); } while ( r != 1 ); if ( q == 1 ) { - DCOUT(true); - DCOUT(END checkdivisors); return true; } } d[i] = q; } - DCOUT(false); - DCOUT(END checkdivisors); return false; } static bool generate_set(const ex& u, const ex& vn, const exset& syms, const ex& f, const numeric& modulus, vector& a, vector& d) { // computation of d is actually not necessary - DCOUT(generate_set); - DCOUTVAR(u); - DCOUTVAR(vn); - DCOUTVAR(f); - DCOUTVAR(modulus); const ex& x = *syms.begin(); bool trying = true; do { @@ -1805,7 +1866,6 @@ static bool generate_set(const ex& u, const ex& vn, const exset& syms, const ex& exset::const_iterator s = syms.begin(); ++s; for ( size_t i=0; i(x))) != 1 ) { continue; } @@ -1823,7 +1881,6 @@ static bool generate_set(const ex& u, const ex& vn, const exset& syms, const ex& trying = false; } else { - DCOUT(do substitution); lst fnum; lst::const_iterator i = ex_to(f).begin(); fnum.append(*i++); @@ -1850,40 +1907,27 @@ static bool generate_set(const ex& u, const ex& vn, const exset& syms, const ex& } ex con = u0.content(x); fnum.append(con); - DCOUTVAR(fnum); trying = checkdivisors(fnum, d); } } while ( trying ); - DCOUT(END generate_set); return false; } static ex factor_multivariate(const ex& poly, const exset& syms) { - DCOUT(factor_multivariate); - DCOUTVAR(poly); - exset::const_iterator s; const ex& x = *syms.begin(); - DCOUTVAR(x); /* make polynomial primitive */ ex p = poly.expand().collect(x); - DCOUTVAR(p); ex cont = p.lcoeff(x); for ( numeric i=p.degree(x)-1; i>=p.ldegree(x); --i ) { cont = gcd(cont, p.coeff(x,ex_to(i).to_int())); if ( cont == 1 ) break; } - DCOUTVAR(cont); ex pp = expand(normal(p / cont)); - DCOUTVAR(pp); if ( !is_a(cont) ) { -#ifdef DEBUGFACTOR - return ::factor(cont) * ::factor(pp); -#else return factor(cont) * factor(pp); -#endif } /* factor leading coefficient */ @@ -1895,18 +1939,12 @@ static ex factor_multivariate(const ex& poly, const exset& syms) vnlst = lst(vn); } else { -#ifdef DEBUGFACTOR - ex vnfactors = ::factor(vn); -#else ex vnfactors = factor(vn); -#endif vnlst = put_factors_into_lst(vnfactors); } - DCOUTVAR(vnlst); const numeric maxtrials = 3; numeric modulus = (vnlst.nops()-1 > 3) ? vnlst.nops()-1 : 3; - DCOUTVAR(modulus); numeric minimalr = -1; vector a(syms.size()-1, 0); vector d((vnlst.nops()-1)/2+1, 0); @@ -1920,13 +1958,10 @@ static ex factor_multivariate(const ex& poly, const exset& syms) ex ufaclst; while ( trialcount < maxtrials ) { bool problem = generate_set(pp, vn, syms, vnlst, modulus, a, d); - DCOUTVAR(problem); if ( problem ) { ++modulus; continue; } - DCOUTVAR(a); - DCOUTVAR(d); u = pp; s = syms.begin(); ++s; @@ -1935,37 +1970,48 @@ static ex factor_multivariate(const ex& poly, const exset& syms) ++s; } delta = u.content(x); - DCOUTVAR(u); // determine proper prime prime = 3; - DCOUTVAR(prime); cl_modint_ring R = find_modint_ring(prime); - DCOUTVAR(u.lcoeff(x)); while ( true ) { if ( irem(ex_to(u.lcoeff(x)), prime) != 0 ) { - umod modpoly = umod_from_ex(u, x, R); + umodpoly modpoly; + umodpoly_from_ex(modpoly, u, x, R); if ( squarefree(modpoly) ) break; } prime = next_prime(prime); - DCOUTVAR(prime); R = find_modint_ring(prime); } -#ifdef DEBUGFACTOR - ufac = ::factor(u); -#else ufac = factor(u); -#endif - DCOUTVAR(ufac); ufaclst = put_factors_into_lst(ufac); - DCOUTVAR(ufaclst); factor_count = (ufaclst.nops()-1)/2; - DCOUTVAR(factor_count); + + // veto factorization for which gcd(u_i, u_j) != 1 for all i,j + upvec tryu; + for ( size_t i=0; i<(ufaclst.nops()-1)/2; ++i ) { + umodpoly newu; + umodpoly_from_ex(newu, ufaclst.op(i*2+1), x, R); + tryu.push_back(newu); + } + bool veto = false; + for ( size_t i=0; i(ft); } - DCOUTVAR(ftilde); vector used_flag((vnlst.nops()-1)/2+1, false); vector D(factor_count, 1); for ( size_t i=0; i<=factor_count; ++i ) { - DCOUTVAR(i); numeric prefac; if ( i == 0 ) { prefac = ex_to(ufaclst.op(0)); @@ -2017,22 +2057,15 @@ static ex factor_multivariate(const ex& poly, const exset& syms) else { prefac = ex_to(ufaclst.op(2*(i-1)+1).lcoeff(x)); } - DCOUTVAR(prefac); for ( size_t j=(vnlst.nops()-1)/2+1; j>0; --j ) { - DCOUTVAR(j); - DCOUTVAR(prefac); - DCOUTVAR(ftilde[j-1]); if ( abs(ftilde[j-1]) == 1 ) { used_flag[j-1] = true; continue; } numeric g = gcd(prefac, ftilde[j-1]); - DCOUTVAR(g); if ( g != 1 ) { - DCOUT(has_common_prime); prefac = prefac / g; numeric count = abs(iquo(g, ftilde[j-1])); - DCOUTVAR(count); used_flag[j-1] = true; if ( i > 0 ) { if ( j == 1 ) { @@ -2044,15 +2077,12 @@ static ex factor_multivariate(const ex& poly, const exset& syms) } else { ftilde[j-1] = ftilde[j-1] / prefac; - DCOUT(BREAK); - DCOUTVAR(ftilde[j-1]); break; } ++j; } } } - DCOUTVAR(D); bool some_factor_unused = false; for ( size_t i=0; i C(factor_count); - DCOUTVAR(C); - DCOUTVAR(delta); if ( delta == 1 ) { for ( size_t i=0; i epv; @@ -2121,7 +2146,6 @@ static ex factor_multivariate(const ex& poly, const exset& syms) ep.evalpoint = a[i].to_int(); epv.push_back(ep); } - DCOUTVAR(epv); // calc bound B ex maxcoeff; @@ -2143,13 +2167,13 @@ static ex factor_multivariate(const ex& poly, const exset& syms) pl = pl * prime; } - umodvec uvec; + upvec uvec; cl_modint_ring R = find_modint_ring(expt_pos(cl_I(prime),l)); for ( size_t i=0; i<(ufaclst.nops()-1)/2; ++i ) { - umod newu = umod_from_ex(ufaclst.op(i*2+1), x, R); + umodpoly newu; + umodpoly_from_ex(newu, ufaclst.op(i*2+1), x, R); uvec.push_back(newu); } - DCOUTVAR(uvec); ex res = hensel_multivar(ufaclst.op(0)*pp, x, epv, prime, l, uvec, C); if ( res != lst() ) { @@ -2158,8 +2182,6 @@ static ex factor_multivariate(const ex& poly, const exset& syms) result *= res.op(i).content(x) * res.op(i).unit(x); result *= res.op(i).primpart(x); } - DCOUTVAR(result); - DCOUT(END factor_multivariate); return result; } } @@ -2179,13 +2201,10 @@ struct find_symbols_map : public map_function { static ex factor_sqrfree(const ex& poly) { - DCOUT(factor_sqrfree); - // determine all symbols in poly find_symbols_map findsymbols; findsymbols(poly); if ( findsymbols.syms.size() == 0 ) { - DCOUT(END factor_sqrfree); return poly; } @@ -2195,19 +2214,16 @@ static ex factor_sqrfree(const ex& poly) if ( poly.ldegree(x) > 0 ) { int ld = poly.ldegree(x); ex res = factor_univariate(expand(poly/pow(x, ld)), x); - DCOUT(END factor_sqrfree); return res * pow(x,ld); } else { ex res = factor_univariate(poly, x); - DCOUT(END factor_sqrfree); return res; } } // multivariate case ex res = factor_multivariate(poly, findsymbols.syms); - DCOUT(END factor_sqrfree); return res; } @@ -2217,11 +2233,7 @@ struct apply_factor_map : public map_function { ex operator()(const ex& e) { if ( e.info(info_flags::polynomial) ) { -#ifdef DEBUGFACTOR - return ::factor(e, options); -#else return factor(e, options); -#endif } if ( is_a(e) ) { ex s1, s2; @@ -2235,11 +2247,7 @@ struct apply_factor_map : public map_function { } s1 = s1.eval(); s2 = s2.eval(); -#ifdef DEBUGFACTOR - return ::factor(s1, options) + s2.map(*this); -#else return factor(s1, options) + s2.map(*this); -#endif } return e.map(*this); } @@ -2247,11 +2255,7 @@ struct apply_factor_map : public map_function { } // anonymous namespace -#ifdef DEBUGFACTOR -ex factor(const ex& poly, unsigned options = 0) -#else ex factor(const ex& poly, unsigned options) -#endif { // check arguments if ( !poly.info(info_flags::polynomial) ) { @@ -2323,3 +2327,7 @@ ex factor(const ex& poly, unsigned options) } } // namespace GiNaC + +#ifdef DEBUGFACTOR +#include "test.h" +#endif