X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=blobdiff_plain;f=ginac%2Ffactor.cpp;h=204010be3750294640434dc28da698f9f452db69;hp=ce845e4ef58c8e92df8db79859bcaea9f8fb9d6a;hb=edc92b7a463993da62357fb4afad053e8c6d0771;hpb=1b735625b2759c1627046f9cb1baf834f4d26f5d diff --git a/ginac/factor.cpp b/ginac/factor.cpp index ce845e4e..204010be 100644 --- a/ginac/factor.cpp +++ b/ginac/factor.cpp @@ -1,6 +1,6 @@ /** @file factor.cpp * - * Polynomial factorization code (Implementation). + * Polynomial factorization code (implementation). * * Algorithms used can be found in * [W1] An Improved Multivariate Polynomial Factoring Algorithm, @@ -29,11 +29,6 @@ //#define DEBUGFACTOR -#ifdef DEBUGFACTOR -#include -#include -using namespace GiNaC; -#else #include "factor.h" #include "ex.h" @@ -46,21 +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 @@ -72,661 +67,563 @@ 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 Vec; -typedef vector VecVec; - +typedef vector mvec; #ifdef DEBUGFACTOR -ostream& operator<<(ostream& o, const Vec& v) +ostream& operator<<(ostream& o, const vector& v) { - Vec::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 VecVec& v) +ostream& operator<<(ostream& o, const vector& v) { - VecVec::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 - -struct Term -{ - cl_MI c; // coefficient - unsigned int exp; // exponent >=0 -}; - -#ifdef DEBUGFACTOR -ostream& operator<<(ostream& o, const Term& t) +ostream& operator<<(ostream& o, const vector& v) { - if ( t.exp ) { - o << "(" << t.c << ")x^" << t.exp; + vector::const_iterator i = v.begin(), end = v.end(); + while ( i != end ) { + o << *i << "[" << i-v.begin() << "]" << " "; + ++i; } - else { - o << "(" << t.c << ")"; + 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 // def DEBUGFACTOR +#endif + +//////////////////////////////////////////////////////////////////////////////// +// modular univariate polynomial code -struct UniPoly +typedef std::vector umodpoly; +typedef std::vector upoly; +typedef vector upvec; + +// COPY FROM UPOLY.HPP + +// CHANGED size_t -> int !!! +template static int degree(const T& p) { - cl_modint_ring R; - list terms; // highest exponent first - - UniPoly(const cl_modint_ring& ring) : R(ring) { } - UniPoly(const cl_modint_ring& ring, const ex& poly, const ex& x) : R(ring) - { - // assert: poly is in Z[x] - Term t; - for ( int i=poly.degree(x); i>=poly.ldegree(x); --i ) { - cl_I coeff = the(ex_to(poly.coeff(x,i)).to_cl_N()); - if ( !zerop(coeff) ) { - t.c = R->canonhom(coeff); - if ( !zerop(t.c) ) { - t.exp = i; - terms.push_back(t); - } - } - } - } - UniPoly(const cl_modint_ring& ring, const UniPoly& poly) : R(ring) - { - if ( R->modulus == poly.R->modulus ) { - terms = poly.terms; - } - else { - list::const_iterator i=poly.terms.begin(), end=poly.terms.end(); - for ( ; i!=end; ++i ) { - terms.push_back(*i); - terms.back().c = R->canonhom(poly.R->retract(i->c)); - if ( zerop(terms.back().c) ) { - terms.pop_back(); - } - } - } - } - UniPoly(const cl_modint_ring& ring, const Vec& v) : R(ring) - { - Term t; - for ( unsigned int i=0; i::const_iterator i = terms.begin(), end = terms.end(); - for ( ; i != end; ++i ) { - if ( i->exp == deg ) { - return i->c; - } - if ( i->exp < deg ) { - break; - } - } - return R->zero(); + 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; } - void set(unsigned int deg, const cl_MI& c) - { - list::iterator i = terms.begin(), end = terms.end(); - while ( i != end ) { - if ( i->exp == deg ) { - if ( !zerop(c) ) { - i->c = c; - } - else { - terms.erase(i); - } - return; - } - if ( i->exp < deg ) { - break; - } + + 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; +} + +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 ( !zerop(c) ) { - Term t; - t.c = c; - t.exp = deg; - terms.insert(i, t); - } - } - ex to_ex(const ex& x, bool symmetric = true) const - { - ex r; - list::const_iterator i = terms.begin(), end = terms.end(); - if ( symmetric ) { - numeric mod(R->modulus); - numeric halfmod = (mod-1)/2; - for ( ; i != end; ++i ) { - numeric n(R->retract(i->c)); - if ( n > halfmod ) { - r += pow(x, i->exp) * (n-mod); - } - else { - r += pow(x, i->exp) * n; - } - } - } - else { - for ( ; i != end; ++i ) { - r += pow(x, i->exp) * numeric(R->retract(i->c)); - } - } - return r; - } - void unit_normal() - { - if ( terms.size() ) { - if ( terms.front().c != R->one() ) { - list::iterator i = terms.begin(), end = terms.end(); - cl_MI cont = i->c; - i->c = R->one(); - while ( ++i != end ) { - i->c = div(i->c, cont); - if ( zerop(i->c) ) { - terms.erase(i); - } - } - } + if (i == 0) { + is_zero = true; + break; } + --i; + } while (true); + + if (is_zero) { + p.clear(); + return; } - cl_MI unit() const - { - return terms.front().c; - } - void divide(const cl_MI& x) - { - list::iterator i = terms.begin(), end = terms.end(); - for ( ; i != end; ++i ) { - i->c = div(i->c, x); - if ( zerop(i->c) ) { - terms.erase(i); - } - } + + 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; } - void divide(const cl_I& x) - { - list::iterator i = terms.begin(), end = terms.end(); - for ( ; i != end; ++i ) { - i->c = cl_MI(R, the(R->retract(i->c) / x)); - } +} + +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::iterator i = terms.begin(), end = terms.end(); - while ( i != end ) { - if ( i->exp > 0 ) { - // assert: i->exp is multiple of prime - i->exp /= prime; - } - ++i; + else { + T r(sb); + int i = 0; + for ( ; i::const_iterator i = terms.begin(), end = terms.end(); - while ( i != end ) { - if ( i->exp ) { - cl_MI newc = i->c * i->exp; - if ( !zerop(newc) ) { - Term t; - t.c = newc; - t.exp = i->exp-1; - d.terms.push_back(t); - } - } - ++i; + for ( ; i::const_iterator i1 = terms.begin(), end = terms.end(); - list::const_iterator i2 = o.terms.begin(); - while ( i1 != end ) { - if ( i1->exp != i2->exp ) { - return i1->exp < i2->exp; - } - if ( i1->c != i2->c ) { - return R->retract(i1->c) < R->retract(i2->c); - } - ++i1; ++i2; - } - return true; +} + +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::const_iterator i1 = terms.begin(), end = terms.end(); - list::const_iterator i2 = o.terms.begin(); - while ( i1 != end ) { - if ( i1->exp != i2->exp ) { - return false; - } - if ( i1->c != i2->c ) { - return false; - } - ++i1; ++i2; + for ( ; izero(); - for ( unsigned int j=0 ; j<=i; ++j ) { - t.c = t.c + a[j] * b[i-j]; - } - if ( !zerop(t.c) ) { - t.exp = i; - c.terms.push_front(t); + upoly c; + if ( a.empty() || b.empty() ) return c; + + int n = degree(a) + degree(b); + c.resize(n+1, 0); + 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 UniPoly operator-(const UniPoly& a, const UniPoly& b) +static umodpoly operator*(const umodpoly& a, const umodpoly& b) { - list::const_iterator ia = a.terms.begin(), aend = a.terms.end(); - list::const_iterator ib = b.terms.begin(), bend = b.terms.end(); - UniPoly c(a.R); - while ( ia != aend && ib != bend ) { - if ( ia->exp > ib->exp ) { - c.terms.push_back(*ia); - ++ia; - } - else if ( ia->exp < ib->exp ) { - c.terms.push_back(*ib); - c.terms.back().c = -c.terms.back().c; - ++ib; - } - else { - Term t; - t.exp = ia->exp; - t.c = ia->c - ib->c; - if ( !zerop(t.c) ) { - c.terms.push_back(t); - } - ++ia; ++ib; + 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]; } } - while ( ia != aend ) { - c.terms.push_back(*ia); - ++ia; - } - while ( ib != bend ) { - c.terms.push_back(*ib); - c.terms.back().c = -c.terms.back().c; - ++ib; - } + canonicalize(c); return c; } -static UniPoly operator*(const UniPoly& a, const cl_MI& fac) +static upoly operator*(const upoly& a, const cl_I& x) { - unsigned int n = a.degree(); - UniPoly c(a.R); - Term t; - for ( unsigned int i=0 ; i<=n; ++i ) { - t.c = a[i] * fac; - if ( !zerop(t.c) ) { - t.exp = i; - c.terms.push_front(t); - } + if ( zerop(x) ) { + upoly r; + return r; } - return c; + upoly r(a.size()); + for ( size_t i=0; i::const_iterator ia = a.terms.begin(), aend = a.terms.end(); - list::const_iterator ib = b.terms.begin(), bend = b.terms.end(); - UniPoly c(a.R); - while ( ia != aend && ib != bend ) { - if ( ia->exp > ib->exp ) { - c.terms.push_back(*ia); - ++ia; - } - else if ( ia->exp < ib->exp ) { - c.terms.push_back(*ib); - ++ib; - } - else { - Term t; - t.exp = ia->exp; - t.c = ia->c + ib->c; - if ( !zerop(t.c) ) { - c.terms.push_back(t); - } - ++ia; ++ib; - } - } - while ( ia != aend ) { - c.terms.push_back(*ia); - ++ia; + if ( zerop(x) ) { + upoly r; + return r; } - while ( ib != bend ) { - c.terms.push_back(*ib); - ++ib; + upoly r(a.size()); + for ( size_t i=0; i::const_iterator ia = a.terms.begin(), aend = a.terms.end(); -// UniPoly c(a.R); -// while ( ia != aend ) { -// c.terms.push_back(*ia); -// c.terms.back().c = -c.terms.back().c; -// ++ia; -// } -// return c; -// } +static umodpoly operator*(const umodpoly& a, const cl_MI& x) +{ + umodpoly r(a.size()); + for ( size_t i=0; i::const_iterator i = t.terms.begin(), end = t.terms.end(); - if ( i == end ) { - o << "0"; - return o; + // assert: e is in Z[x] + int deg = e.degree(x); + up.resize(deg+1); + int ldeg = e.ldegree(x); + for ( ; deg>=ldeg; --deg ) { + up[deg] = the(ex_to(e.coeff(x, deg)).to_cl_N()); } - for ( ; i != end; ) { - o << *i++; - if ( i != end ) { - o << " + "; - } + for ( ; deg>=0; --deg ) { + up[deg] = 0; } - return o; + canonicalize(up); } -#endif // def DEBUGFACTOR -#ifdef DEBUGFACTOR -ostream& operator<<(ostream& o, const list& t) +static void umodpoly_from_upoly(umodpoly& ump, const upoly& e, const cl_modint_ring& R) { - list::const_iterator i = t.begin(), end = t.end(); - o << "{" << endl; - for ( ; i != end; ) { - o << *i++ << endl; + int deg = degree(e); + ump.resize(deg+1); + for ( ; deg>=0; --deg ) { + ump[deg] = R->canonhom(e[deg]); } - o << "}" << endl; - return o; + canonicalize(ump); } -#endif // def DEBUGFACTOR - -typedef vector UniPolyVec; -#ifdef DEBUGFACTOR -ostream& operator<<(ostream& o, const UniPolyVec& v) +static void umodpoly_from_ex(umodpoly& ump, const ex& e, const ex& x, const cl_modint_ring& R) { - UniPolyVec::const_iterator i = v.begin(), end = v.end(); - while ( i != end ) { - o << *i++ << " , " << endl; - } - return o; + // 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); + } + for ( ; deg>=0; --deg ) { + ump[deg] = R->zero(); + } + canonicalize(ump); } -#endif // def DEBUGFACTOR -struct UniFactor +static void umodpoly_from_ex(umodpoly& ump, const ex& e, const ex& x, const cl_I& modulus) { - UniPoly p; - unsigned int exp; + umodpoly_from_ex(ump, e, x, find_modint_ring(modulus)); +} - UniFactor(const cl_modint_ring& ring) : p(ring) { } - UniFactor(const UniPoly& p_, unsigned int exp_) : p(p_), exp(exp_) { } - bool operator<(const UniFactor& o) const - { - return p < o.p; +static ex upoly_to_ex(const upoly& a, const ex& x) +{ + if ( a.empty() ) return 0; + ex e; + for ( int i=degree(a); i>=0; --i ) { + e += numeric(a[i]) * pow(x, i); } -}; + return e; +} -struct UniFactorVec +static ex umodpoly_to_ex(const umodpoly& a, const ex& x) { - vector factors; - - void unique() - { - sort(factors.begin(), factors.end()); - if ( factors.size() > 1 ) { - vector::iterator i = factors.begin(); - vector::const_iterator cmp = factors.begin()+1; - vector::iterator end = factors.end(); - while ( cmp != end ) { - if ( i->p != cmp->p ) { - ++i; - ++cmp; - } - else { - i->exp += cmp->exp; - ++cmp; - } - } - if ( i != end-1 ) { - factors.erase(i+1, end); - } - } - } -}; + 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(a[i]); + if ( n > halfmod ) { + e += numeric(n-mod) * pow(x, i); + } else { + e += numeric(n) * pow(x, i); + } + } + return e; +} -#ifdef DEBUGFACTOR -ostream& operator<<(ostream& o, const UniFactorVec& ufv) +static upoly umodpoly_to_upoly(const umodpoly& a) { - for ( size_t i=0; imodulus; + 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; } -#endif // def DEBUGFACTOR -static void rem(const UniPoly& a_, const UniPoly& b, UniPoly& c) +static umodpoly umodpoly_to_umodpoly(const umodpoly& a, const cl_modint_ring& R, unsigned int m) { - if ( a_.degree() < b.degree() ) { - c = a_; - return; - } + 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; +} - unsigned int k, n; - n = b.degree(); - k = a_.degree() - n; +/** 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; - if ( n == 0 ) { - c.terms.clear(); - 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)); } +} - c = a_; - Term termbuf; +/** 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; + r = a; + if ( k < 0 ) return; - while ( true ) { - cl_MI qk = div(c[n+k], b[n]); + do { + cl_MI qk = div(r[n+k], b[n]); if ( !zerop(qk) ) { - unsigned int j; - for ( unsigned int i=0; i::iterator i = c.terms.begin(), end = c.terms.end(); - while ( i != end ) { - if ( i->exp <= n-1 ) { - break; - } - ++i; - } - c.terms.erase(c.terms.begin(), i); + } while ( k-- ); + + fill(r.begin()+n, r.end(), a[0].ring()->zero()); + canonicalize(r); } -static void div(const UniPoly& a_, const UniPoly& b, UniPoly& q) +/** 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) { - if ( a_.degree() < b.degree() ) { - q.terms.clear(); - return; - } - - unsigned int k, n; - n = b.degree(); - k = a_.degree() - n; + int k, n; + n = degree(b); + k = degree(a) - n; + q.clear(); + if ( k < 0 ) return; + + umodpoly r = a; + q.resize(k+1, a[0].ring()->zero()); + do { + cl_MI qk = div(r[n+k], b[n]); + if ( !zerop(qk) ) { + q[k] = qk; + for ( int i=0; izero()); + do { + cl_MI qk = div(r[n+k], b[n]); if ( !zerop(qk) ) { - Term t; - t.c = qk; - t.exp = k; - q.terms.push_back(t); - unsigned int j; - for ( unsigned int i=0; izero()); + canonicalize(r); + canonicalize(q); } -static void gcd(const UniPoly& a, const UniPoly& b, UniPoly& 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) { - c = a; - c.unit_normal(); - UniPoly d = b; - d.unit_normal(); - - if ( c.degree() < d.degree() ) { - gcd(b, a, c); - return; - } + if ( degree(a) < degree(b) ) return gcd(b, a, c); - while ( !d.zero() ) { - UniPoly r(a.R); + 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; } - c.unit_normal(); + normalize_in_field(c); } -static bool is_one(const UniPoly& w) +/** 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 ( w.terms.size() == 1 && w[0] == w.R->one() ) { - return true; + d.clear(); + if ( a.size() <= 1 ) return; + + d.insert(d.begin(), a.begin()+1, a.end()); + int max = d.size(); + for ( int i=1; imodulus); - c.reduce_exponents(prime); - unsigned int pos = fvec.factors.size(); - sqrfree_main(c, fvec); - for ( unsigned int p=pos; pmodulus); - UniPoly amod = a; - amod.reduce_exponents(prime); - unsigned int pos = fvec.factors.size(); - sqrfree_main(amod, fvec); - for ( unsigned int p=pos; pone() ); } -static void squarefree(const UniPoly& a, UniFactorVec& fvec) +static bool equal_one(const umodpoly& a) { - sqrfree_main(a, fvec); - fvec.unique(); + return ( a.size() == 1 && a[0] == a[0].ring()->one() ); } -class Matrix +/** 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) { - friend ostream& operator<<(ostream& o, const Matrix& m); + umodpoly b; + deriv(a, b); + if ( b.empty() ) { + return true; + } + umodpoly c; + gcd(a, b, c); + return equal_one(c); +} + +// END modular univariate polynomial code +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// modular matrix + +class modular_matrix +{ + friend ostream& operator<<(ostream& o, const modular_matrix& m); public: - Matrix(size_t r_, size_t c_, const cl_MI& init) : r(r_), c(c_) + modular_matrix(size_t r_, size_t c_, const cl_MI& init) : r(r_), c(c_) { m.resize(c*r, init); } @@ -736,7 +633,7 @@ public: cl_MI operator()(size_t row, size_t col) const { return m[row*c + col]; } void mul_col(size_t col, const cl_MI x) { - Vec::iterator i = m.begin() + col; + mvec::iterator i = m.begin() + col; for ( size_t rc=0; rc& newrow) { - Vec::iterator i1 = m.begin() + row*c; - Vec::const_iterator i2 = newrow.begin(), end = newrow.end(); + mvec::iterator i1 = m.begin() + row*c; + mvec::const_iterator i2 = newrow.begin(), end = newrow.end(); for ( ; i2 != end; ++i1, ++i2 ) { *i1 = *i2; } } - Vec::const_iterator row_begin(size_t row) const { return m.begin()+row*c; } - Vec::const_iterator row_end(size_t row) const { return m.begin()+row*c+r; } + mvec::const_iterator row_begin(size_t row) const { return m.begin()+row*c; } + mvec::const_iterator row_end(size_t row) const { return m.begin()+row*c+r; } private: size_t r, c; - Vec m; + mvec m; }; #ifdef DEBUGFACTOR -Matrix operator*(const Matrix& m1, const Matrix& m2) +modular_matrix operator*(const modular_matrix& m1, const modular_matrix& m2) { const unsigned int r = m1.rowsize(); const unsigned int c = m2.colsize(); - Matrix o(r,c,m1(0,0)); + modular_matrix o(r,c,m1(0,0)); for ( size_t i=0; i::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 -static void q_matrix(const UniPoly& a, Matrix& Q) -{ - unsigned int n = a.degree(); - unsigned int q = cl_I_to_uint(a.R->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 - for ( size_t i=0; ione()); - UniPoly r(a.R); - rem(qk, a, r); - Vec rvec; - for ( size_t 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); } - Q.set_row(i, rvec); } } -static void nullspace(Matrix& M, vector& basis) +static void nullspace(modular_matrix& M, vector& basis) { const size_t n = M.rowsize(); const cl_MI one = M(0,0).ring()->one(); @@ -935,41 +829,46 @@ static void nullspace(Matrix& M, vector& basis) } for ( size_t i=0; izero()); + 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); - VecVec nu; + 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(a.R->modulus); + 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 ( i->degree() ) ++size; + 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++); } return; } -// if ( u->degree() < nur.degree() ) { -// break; -// } } } if ( ++r == k ) { @@ -1001,122 +897,299 @@ static void berlekamp(const UniPoly& a, UniPolyVec& upv) } } -static void factor_modular(const UniPoly& p, UniPolyVec& upv) +static void expt_1_over_p(const umodpoly& a, unsigned int prime, umodpoly& ap) +{ + 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]; + } +} + +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) { - berlekamp(p, upv); - return; + umodpoly a = a_; + + cl_modint_ring R = a[0].ring(); + int q = cl_I_to_int(R->modulus); + int nhalf = degree(a)/2; + + int i = 1; + umodpoly w(2); + w[0] = R->zero(); + w[1] = R->one(); + umodpoly x = w; + + bool nontrivial = false; + while ( i <= nhalf ) { + 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; + } + if ( unequal_one(a) ) { + degrees.push_back(degree(a)); + ddfactors.push_back(a); + } +} + +static void same_degree_factor(const umodpoly& a, upvec& upv) +{ + cl_modint_ring R = a[0].ring(); + int deg = degree(a); + + vector degrees; + upvec ddfactors; + distinct_degree_factor(a, degrees, ddfactors); + + for ( size_t i=0; i mult; + modsqrfree(p, factors, mult); + +#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 UniPoly& a, const UniPoly& b, UniPoly& g, UniPoly& s, UniPoly& 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 ( a.degree() < b.degree() ) { - exteuclid(b, a, g, t, s); + if ( degree(a) < degree(b) ) { + exteuclid(b, a, t, s); return; } - UniPoly c1(a.R), c2(a.R), d1(a.R), d2(a.R), q(a.R), r(a.R), r1(a.R), r2(a.R); - UniPoly c = a; c.unit_normal(); - UniPoly d = b; d.unit_normal(); - c1.set(0, a.R->one()); - d2.set(0, a.R->one()); - while ( !d.zero() ) { - q.terms.clear(); + + 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); - r = c - q * d; - r1 = c1 - q * d1; - r2 = c2 - q * d2; + umodpoly r = c - q * d; + umodpoly r1 = s - q * d1; + umodpoly r2 = t - q * d2; c = d; - c1 = d1; - c2 = d2; + s = d1; + t = d2; + if ( r.empty() ) break; d = r; d1 = r1; d2 = r2; } - g = c; g.unit_normal(); - s = c1; - s.divide(a.unit()); - s.divide(c.unit()); - t = c2; - t.divide(b.unit()); - t.divide(c.unit()); + 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 UniPoly& u1_, const UniPoly& 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_modint_ring& R = u1_.R; + 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 maxdegree = (u1_.degree() > w1_.degree()) ? u1_.degree() : w1_.degree(); + 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; - UniPoly nu1 = u1_; - nu1.unit_normal(); - UniPoly nw1 = w1_; - nw1.unit_normal(); - ex phi; - phi = expand(gamma * nu1.to_ex(x)); - UniPoly u1(R, phi, x); - phi = expand(alpha * nw1.to_ex(x)); - UniPoly w1(R, phi, x); + 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 - UniPoly s(R), t(R), g(R); - exteuclid(u1, w1, g, s, t); + umodpoly s; + umodpoly t; + exteuclid(u1, w1, s, t); // step 3 - ex u = replace_lc(u1.to_ex(x), x, gamma); - ex w = replace_lc(w1.to_ex(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(s.to_ex(x)*c); - UniPoly sigmatilde(R, phi, x); - phi = expand(t.to_ex(x)*c); - UniPoly tautilde(R, phi, x); - UniPoly q(R), r(R); - div(sigmatilde, w1, q); - rem(sigmatilde, w1, r); - UniPoly sigma = r; - phi = expand(tautilde.to_ex(x) + q.to_ex(x) * u1.to_ex(x)); - UniPoly tau(R, phi, x); - u = expand(u + tau.to_ex(x) * modulus); - w = expand(w + sigma.to_ex(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 UniPolyVec& factors, const Partition& part, UniPoly& a, UniPoly& b) -{ - a.set(0, a.R->one()); - b.set(0, a.R->one()); - for ( size_t i=0; i(prim.lcoeff(x)), p) != 0 ) { - UniPoly modpoly(R, prim, x); - UniFactorVec sqrfree_ufv; - squarefree(modpoly, sqrfree_ufv); - if ( sqrfree_ufv.factors.size() == 1 && sqrfree_ufv.factors.front().exp == 1 ) break; - } - p = next_prime(p); - R = find_modint_ring(p); - } - - // do modular factorization - UniPoly modpoly(R, prim, x); - UniPolyVec factors; - factor_modular(modpoly, factors); - if ( factors.size() <= 1 ) { - // irreducible for sure - return poly; + // determine proper prime and minimize number of modular factors + unsigned int p = 3, lastp = 3; + cl_modint_ring R; + unsigned int trials = 0; + unsigned int minfactors = 0; + cl_I lc = lcoeff(prim); + upvec factors; + while ( trials < 2 ) { + umodpoly modpoly; + while ( true ) { + p = next_prime(p); + if ( !zerop(rem(lc, p)) ) { + R = find_modint_ring(p); + umodpoly_from_upoly(modpoly, prim, R); + if ( squarefree(modpoly) ) break; + } + } + + // do modular factorization + upvec trialfactors; + factor_modular(modpoly, trialfactors); + if ( trialfactors.size() <= 1 ) { + // irreducible for sure + return poly; + } + + if ( minfactors == 0 || trialfactors.size() < minfactors ) { + factors = trialfactors; + minfactors = factors.size(); + lastp = p; + trials = 1; + } + else { + ++trials; + } } + p = lastp; + R = find_modint_ring(p); // lift all factor combinations stack tocheck; @@ -1244,24 +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 ) { - UniPoly a(R), b(R); - 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; i multivar_diophant(const vector& a_, const ex& x, const ex& c, const vector& I, unsigned int d, unsigned int p, unsigned int k); -UniPolyVec multiterm_eea_lift(const UniPolyVec& 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)); - UniPoly fill(R); - UniPolyVec q(r-1, fill); + 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); - UniPoly beta(R); - beta.set(0, R->one()); - UniPolyVec s; + umodpoly beta(1, R->one()); + upvec s; for ( size_t j=1; j mdarg(2); - mdarg[0] = q[j-1].to_ex(x); - mdarg[1] = a[j-1].to_ex(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, beta.to_ex(x), empty, 0, p, k); - UniPoly sigma1(R, exsigma[0], x); - UniPoly sigma2(R, exsigma[1], x); + 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 eea_lift(const UniPoly& a, const UniPoly& b, const ex& x, unsigned int p, unsigned int k, UniPoly& s_, UniPoly& t_) +/** + * Assert: a not empty. + */ +void change_modulus(const cl_modint_ring& R, umodpoly& a) { - DCOUT(eea_lift); - DCOUTVAR(a); - DCOUTVAR(b); - DCOUTVAR(x); - DCOUTVAR(p); - DCOUTVAR(k); + 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 umodpoly& a, const umodpoly& b, const ex& x, unsigned int p, unsigned int k, umodpoly& s_, umodpoly& t_) +{ cl_modint_ring R = find_modint_ring(p); - UniPoly amod(R, a); - UniPoly bmod(R, b); - DCOUTVAR(amod); - DCOUTVAR(bmod); - - UniPoly smod(R), tmod(R), g(R); - exteuclid(amod, bmod, g, smod, tmod); - - DCOUTVAR(smod); - DCOUTVAR(tmod); - DCOUTVAR(g); + 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)); - UniPoly s(Rpk, smod); - UniPoly t(Rpk, tmod); - DCOUTVAR(s); - DCOUTVAR(t); + umodpoly s = smod; + change_modulus(Rpk, s); + umodpoly t = tmod; + change_modulus(Rpk, t); cl_I modulus(p); - - UniPoly one(Rpk); - one.set(0, Rpk->one()); + umodpoly one(1, Rpk->one()); for ( size_t j=1; j 2 ) { - UniPolyVec s = multiterm_eea_lift(a, x, p, k); + upvec s = multiterm_eea_lift(a, x, p, k); for ( size_t j=0; j multivar_diophant(const vector& a_, const ex& x, const ex& c, const vector& I, unsigned int d, unsigned int p, unsigned int k) { vector a = a_; - DCOUT(multivar_diophant); -#ifdef DEBUGFACTOR - cout << "a "; - for ( size_t i=0; i sigma; if ( nu > 1 ) { @@ -1557,48 +1598,38 @@ 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(xnu), m).subs(xnu==alphanu) / factorial(m); - DCOUTVAR(cm); + cm = make_modular(cm, R); 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 nterms = 1; z = c; } - DCOUTVAR(nterms); for ( size_t i=0; i(ex_to(z.lcoeff(x)).to_cl_N()); - DCOUTVAR(cm); - UniPolyVec 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 UniPolyVec& 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; @@ -1704,101 +1696,65 @@ 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 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) ) { @@ -1872,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."); @@ -1891,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 { @@ -1947,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; } @@ -1965,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++); @@ -1992,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 */ @@ -2037,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); @@ -2056,19 +1952,16 @@ static ex factor_multivariate(const ex& poly, const exset& syms) while ( true ) { numeric trialcount = 0; ex u, delta; - unsigned int prime; - size_t factor_count; + unsigned int prime = 3; + size_t factor_count = 0; ex ufac; 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; @@ -2077,40 +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 ) { - UniPoly modpoly(R, u, x); - UniFactorVec sqrfree_ufv; - squarefree(modpoly, sqrfree_ufv); - DCOUTVAR(sqrfree_ufv); - if ( sqrfree_ufv.factors.size() == 1 && sqrfree_ufv.factors.front().exp == 1 ) break; + 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)); @@ -2162,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 ) { @@ -2189,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; @@ -2266,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; @@ -2288,13 +2167,13 @@ static ex factor_multivariate(const ex& poly, const exset& syms) pl = pl * prime; } - UniPolyVec 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 ) { - UniPoly newu(R, ufaclst.op(i*2+1), x); + 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() ) { @@ -2303,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; } } @@ -2356,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; @@ -2374,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); } @@ -2386,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) ) { @@ -2462,3 +2327,7 @@ ex factor(const ex& poly, unsigned options) } } // namespace GiNaC + +#ifdef DEBUGFACTOR +#include "test.h" +#endif