87#define DCOUT(str) cout << #str << endl
88#define DCOUTVAR(var) cout << #var << ": " << var << endl
89#define DCOUT2(str,var) cout << #str << ": " << var << endl
90ostream&
operator<<(ostream& o,
const vector<int>& v)
92 auto i = v.begin(), end = v.end();
99static ostream&
operator<<(ostream& o,
const vector<cl_I>& v)
101 auto i = v.begin(), end = v.end();
103 o << *i <<
"[" << i-v.begin() <<
"]" <<
" ";
108static ostream&
operator<<(ostream& o,
const vector<cl_MI>& v)
110 auto i = v.begin(), end = v.end();
112 o << *i <<
"[" << i-v.begin() <<
"]" <<
" ";
117ostream&
operator<<(ostream& o,
const vector<numeric>& v)
119 for (
size_t i=0; i<v.size(); ++i ) {
124ostream&
operator<<(ostream& o,
const vector<vector<cl_MI>>& v)
126 auto i = v.begin(), end = v.end();
128 o << i-v.begin() <<
": " << *i << endl;
136#define DCOUT2(str,var)
142typedef std::vector<cln::cl_MI> umodpoly;
143typedef std::vector<cln::cl_I> upoly;
144typedef vector<umodpoly> upvec;
150template<
typename T>
static int degree(
const T& p)
155template<
typename T>
static typename T::value_type lcoeff(
const T& p)
157 return p[p.size() - 1];
165static bool normalize_in_field(umodpoly& a)
169 if ( lcoeff(a) == a[0].ring()->
one() ) {
173 const cln::cl_MI lc_1 = recip(lcoeff(a));
174 for (std::size_t
k = a.size();
k-- != 0; )
184template<
typename T>
static void
185canonicalize(T& p,
const typename T::size_type hint = std::numeric_limits<typename T::size_type>::max())
187 std::size_t i = min(p.size(), hint);
189 while ( i-- && zerop(p[i]) ) { }
191 p.erase(p.begin() + i + 1, p.end());
196template<
typename T>
struct uvar_poly_p
201template<>
struct uvar_poly_p<upoly>
203 static const bool value =
true;
206template<>
struct uvar_poly_p<umodpoly>
208 static const bool value =
true;
213static typename enable_if<uvar_poly_p<T>::value, T>::type
221 for ( ; i<sb; ++i ) {
224 for ( ; i<sa; ++i ) {
233 for ( ; i<sa; ++i ) {
236 for ( ; i<sb; ++i ) {
248static typename enable_if<uvar_poly_p<T>::value, T>::type
256 for ( ; i<sb; ++i ) {
259 for ( ; i<sa; ++i ) {
268 for ( ; i<sa; ++i ) {
271 for ( ; i<sb; ++i ) {
279static upoly
operator*(
const upoly& a,
const upoly& b)
282 if ( a.empty() || b.empty() )
return c;
286 for (
int i=0 ; i<=
n; ++i ) {
287 for (
int j=0 ; j<=i; ++j ) {
289 c[i] =
c[i] + a[j] * b[i-j];
296static umodpoly
operator*(
const umodpoly& a,
const umodpoly& b)
299 if ( a.empty() || b.empty() )
return c;
302 c.resize(
n+1, a[0].ring()->zero());
303 for (
int i=0 ; i<=
n; ++i ) {
304 for (
int j=0 ; j<=i; ++j ) {
306 c[i] =
c[i] + a[j] * b[i-j];
313static upoly
operator*(
const upoly& a,
const cl_I&
x)
320 for (
size_t i=0; i<a.size(); ++i ) {
326static upoly
operator/(
const upoly& a,
const cl_I&
x)
333 for (
size_t i=0; i<a.size(); ++i ) {
334 r[i] = exquo(a[i],
x);
339static umodpoly
operator*(
const umodpoly& a,
const cl_MI&
x)
341 umodpoly
r(a.size());
342 for (
size_t i=0; i<a.size(); ++i ) {
349static void upoly_from_ex(upoly& up,
const ex& e,
const ex&
x)
352 int deg = e.degree(
x);
354 int ldeg = e.ldegree(
x);
355 for ( ; deg>=ldeg; --deg ) {
356 up[deg] = the<cl_I>(ex_to<numeric>(e.coeff(
x, deg)).to_cl_N());
358 for ( ; deg>=0; --deg ) {
364static void umodpoly_from_upoly(umodpoly& ump,
const upoly& e,
const cl_modint_ring&
R)
368 for ( ; deg>=0; --deg ) {
369 ump[deg] =
R->canonhom(e[deg]);
374static void umodpoly_from_ex(umodpoly& ump,
const ex& e,
const ex&
x,
const cl_modint_ring&
R)
377 int deg = e.degree(
x);
379 int ldeg = e.ldegree(
x);
380 for ( ; deg>=ldeg; --deg ) {
381 cl_I
coeff = the<cl_I>(ex_to<numeric>(e.coeff(
x, deg)).to_cl_N());
382 ump[deg] =
R->canonhom(
coeff);
384 for ( ; deg>=0; --deg ) {
385 ump[deg] =
R->zero();
391static void umodpoly_from_ex(umodpoly& ump,
const ex& e,
const ex&
x,
const cl_I&
modulus)
393 umodpoly_from_ex(ump, e,
x, find_modint_ring(
modulus));
397static ex upoly_to_ex(
const upoly& a,
const ex&
x)
399 if ( a.empty() )
return 0;
401 for (
int i=
degree(a); i>=0; --i ) {
402 e += numeric(a[i]) *
pow(
x, i);
407static ex umodpoly_to_ex(
const umodpoly& a,
const ex&
x)
409 if ( a.empty() )
return 0;
410 cl_modint_ring
R = a[0].ring();
411 cl_I
mod =
R->modulus;
412 cl_I halfmod = (
mod-1) >> 1;
414 for (
int i=
degree(a); i>=0; --i ) {
415 cl_I
n =
R->retract(a[i]);
419 e += numeric(
n) *
pow(
x, i);
425static upoly umodpoly_to_upoly(
const umodpoly& a)
428 if ( a.empty() )
return e;
429 cl_modint_ring
R = a[0].ring();
430 cl_I
mod =
R->modulus;
431 cl_I halfmod = (
mod-1) >> 1;
432 for (
int i=
degree(a); i>=0; --i ) {
433 cl_I
n =
R->retract(a[i]);
443static umodpoly umodpoly_to_umodpoly(
const umodpoly& a,
const cl_modint_ring&
R,
unsigned int m)
446 if ( a.empty() )
return e;
447 cl_modint_ring oldR = a[0].ring();
448 size_t sa = a.size();
449 e.resize(sa+
m,
R->zero());
450 for (
size_t i=0; i<sa; ++i ) {
451 e[i+
m] =
R->canonhom(oldR->retract(a[i]));
464static void reduce_coeff(umodpoly& a,
const cl_I&
x)
466 if ( a.empty() )
return;
468 cl_modint_ring
R = a[0].ring();
471 cl_I
c =
R->retract(i);
472 i = cl_MI(
R, exquopos(
c,
x));
483static void rem(
const umodpoly& a,
const umodpoly& b, umodpoly&
r)
492 cl_MI qk = div(
r[
n+
k], b[
n]);
494 for (
int i=0; i<
n; ++i ) {
495 unsigned int j =
n +
k - 1 - i;
496 r[j] =
r[j] - qk * b[j-
k];
501 fill(
r.begin()+
n,
r.end(), a[0].ring()->zero());
512static void div(
const umodpoly& a,
const umodpoly& b, umodpoly& q)
521 q.resize(
k+1, a[0].ring()->zero());
523 cl_MI qk = div(
r[
n+
k], b[
n]);
526 for (
int i=0; i<
n; ++i ) {
527 unsigned int j =
n +
k - 1 - i;
528 r[j] =
r[j] - qk * b[j-
k];
544static void remdiv(
const umodpoly& a,
const umodpoly& b, umodpoly&
r, umodpoly& q)
553 q.resize(
k+1, a[0].ring()->zero());
555 cl_MI qk = div(
r[
n+
k], b[
n]);
558 for (
int i=0; i<
n; ++i ) {
559 unsigned int j =
n +
k - 1 - i;
560 r[j] =
r[j] - qk * b[j-
k];
565 fill(
r.begin()+
n,
r.end(), a[0].ring()->zero());
576static void gcd(
const umodpoly& a,
const umodpoly& b, umodpoly&
c)
581 normalize_in_field(
c);
583 normalize_in_field(d);
585 while ( !d.empty() ) {
590 normalize_in_field(
c);
598static void deriv(
const umodpoly& a, umodpoly& d)
601 if ( a.size() <= 1 )
return;
603 d.insert(d.begin(), a.begin()+1, a.end());
605 for (
int i=1; i<max; ++i ) {
611static bool unequal_one(
const umodpoly& a)
613 return ( a.size() != 1 || a[0] != a[0].ring()->one() );
616static bool equal_one(
const umodpoly& a)
618 return ( a.size() == 1 && a[0] == a[0].ring()->one() );
626static bool squarefree(
const umodpoly& a)
646static void expt_pos_Q(
const umodpoly& w,
const umodpoly& a,
unsigned int q, umodpoly&
r)
648 if ( w.empty() )
return;
649 cl_MI zero = w[0].ring()->zero();
651 umodpoly buf(deg*q+1, zero);
652 for (
size_t i=0; i<=deg; ++i ) {
664typedef vector<cl_MI> mvec;
669 friend ostream&
operator<<(ostream& o,
const modular_matrix& m);
672 modular_matrix(
size_t r_,
size_t c_,
const cl_MI& init) :
r(r_),
c(c_)
676 size_t rowsize()
const {
return r; }
677 size_t colsize()
const {
return c; }
678 cl_MI& operator()(
size_t row,
size_t col) {
return m[row*
c + col]; }
679 cl_MI operator()(
size_t row,
size_t col)
const {
return m[row*
c + col]; }
680 void mul_col(
size_t col,
const cl_MI
x)
682 for (
size_t rc=0; rc<
r; ++rc ) {
683 std::size_t i =
c*rc + col;
687 void sub_col(
size_t col1,
size_t col2,
const cl_MI fac)
689 for (
size_t rc=0; rc<
r; ++rc ) {
690 std::size_t i1 = col1 +
c*rc;
691 std::size_t i2 = col2 +
c*rc;
692 m[i1] =
m[i1] -
m[i2]*fac;
695 void switch_col(
size_t col1,
size_t col2)
697 for (
size_t rc=0; rc<
r; ++rc ) {
698 std::size_t i1 = col1 + rc*
c;
699 std::size_t i2 = col2 + rc*
c;
703 void mul_row(
size_t row,
const cl_MI
x)
705 for (
size_t cc=0; cc<
c; ++cc ) {
706 std::size_t i = row*
c + cc;
710 void sub_row(
size_t row1,
size_t row2,
const cl_MI fac)
712 for (
size_t cc=0; cc<
c; ++cc ) {
713 std::size_t i1 = row1*
c + cc;
714 std::size_t i2 = row2*
c + cc;
715 m[i1] =
m[i1] -
m[i2]*fac;
718 void switch_row(
size_t row1,
size_t row2)
720 for (
size_t cc=0; cc<
c; ++cc ) {
721 std::size_t i1 = row1*
c + cc;
722 std::size_t i2 = row2*
c + cc;
726 bool is_col_zero(
size_t col)
const
728 for (
size_t rr=0; rr<
r; ++rr ) {
729 std::size_t i = col + rr*
c;
730 if ( !zerop(m[i]) ) {
736 bool is_row_zero(
size_t row)
const
738 for (
size_t cc=0; cc<
c; ++cc ) {
739 std::size_t i = row*
c + cc;
740 if ( !zerop(m[i]) ) {
746 void set_row(
size_t row,
const vector<cl_MI>& newrow)
748 for (std::size_t i2 = 0; i2 < newrow.size(); ++i2) {
749 std::size_t i1 = row*
c + i2;
753 mvec::const_iterator row_begin(
size_t row)
const {
return m.begin()+row*
c; }
754 mvec::const_iterator row_end(
size_t row)
const {
return m.begin()+row*
c+
r; }
761modular_matrix
operator*(
const modular_matrix& m1,
const modular_matrix& m2)
763 const unsigned int r = m1.rowsize();
764 const unsigned int c = m2.colsize();
765 modular_matrix o(
r,
c,m1(0,0));
767 for (
size_t i=0; i<
r; ++i ) {
768 for (
size_t j=0; j<
c; ++j ) {
770 buf = m1(i,0) * m2(0,j);
771 for (
size_t k=1;
k<
c; ++
k ) {
772 buf = buf + m1(i,
k)*m2(
k,j);
780ostream&
operator<<(ostream& o,
const modular_matrix&
m)
782 cl_modint_ring
R =
m(0,0).ring();
784 for (
size_t i=0; i<
m.rowsize(); ++i ) {
786 for (
size_t j=0; j<
m.colsize()-1; ++j ) {
787 o <<
R->retract(
m(i,j)) <<
",";
789 o <<
R->retract(
m(i,
m.colsize()-1)) <<
"}";
790 if ( i !=
m.rowsize()-1 ) {
809static void q_matrix(
const umodpoly& a_, modular_matrix& Q)
812 normalize_in_field(a);
815 unsigned int q = cl_I_to_uint(a[0].ring()->
modulus);
816 umodpoly
r(
n, a[0].ring()->zero());
817 r[0] = a[0].ring()->one();
819 unsigned int max = (
n-1) * q;
820 for (
size_t m=1;
m<=max; ++
m ) {
821 cl_MI rn_1 =
r.back();
822 for (
size_t i=
n-1; i>0; --i ) {
823 r[i] =
r[i-1] - (rn_1 * a[i]);
826 if ( (
m % q) == 0 ) {
837static void nullspace(modular_matrix& M, vector<mvec>& basis)
839 const size_t n = M.rowsize();
840 const cl_MI
one = M(0,0).ring()->one();
841 for (
size_t i=0; i<
n; ++i ) {
842 M(i,i) = M(i,i) -
one;
844 for (
size_t r=0;
r<
n; ++
r ) {
846 for ( ; cc<
n; ++cc ) {
847 if ( !zerop(M(
r,cc)) ) {
849 if ( !zerop(M(cc,cc)) ) {
861 M.mul_col(
r, recip(M(
r,
r)));
862 for ( cc=0; cc<
n; ++cc ) {
864 M.sub_col(cc,
r, M(
r,cc));
870 for (
size_t i=0; i<
n; ++i ) {
871 M(i,i) = M(i,i) -
one;
873 for (
size_t i=0; i<
n; ++i ) {
874 if ( !M.is_row_zero(i) ) {
875 mvec nu(M.row_begin(i), M.row_end(i));
889static void berlekamp(
const umodpoly& a, upvec& upv)
891 cl_modint_ring
R = a[0].ring();
892 umodpoly
one(1,
R->one());
900 const unsigned int k = nu.size();
907 unsigned int size = 1;
909 unsigned int q = cl_I_to_uint(
R->modulus);
911 list<umodpoly>::iterator u =
factors.begin();
915 for (
unsigned int s=0; s<q; ++s ) {
916 umodpoly nur = nu[
r];
917 nur[0] = nur[0] - cl_MI(
R, s);
921 if ( unequal_one(g) && g != *u ) {
924 if ( equal_one(uo) ) {
925 throw logic_error(
"berlekamp: unexpected divisor.");
960static void expt_1_over_p(
const umodpoly& a,
unsigned int prime, umodpoly& ap)
962 size_t newdeg =
degree(a)/prime;
965 for (
size_t i=1; i<=newdeg; ++i ) {
976static void modsqrfree(
const umodpoly& a, upvec&
factors, vector<int>& mult)
978 const unsigned int prime = cl_I_to_uint(a[0].ring()->
modulus);
987 while ( unequal_one(w) ) {
1000 if ( unequal_one(
c) ) {
1002 expt_1_over_p(
c, prime, cp);
1003 size_t previ = mult.size();
1004 modsqrfree(cp,
factors, mult);
1005 for (
size_t i=previ; i<mult.size(); ++i ) {
1011 expt_1_over_p(a, prime, ap);
1012 size_t previ = mult.size();
1013 modsqrfree(ap,
factors, mult);
1014 for (
size_t i=previ; i<mult.size(); ++i ) {
1032static void distinct_degree_factor(
const umodpoly& a_, vector<int>& degrees, upvec& ddfactors)
1036 cl_modint_ring
R = a[0].ring();
1037 int q = cl_I_to_int(
R->modulus);
1041 umodpoly w = {
R->zero(),
R->one()};
1044 while ( i <= nhalf ) {
1046 expt_pos_Q(w, a, q, buf);
1049 if ( unequal_one(buf) ) {
1050 degrees.push_back(i);
1051 ddfactors.push_back(buf);
1061 if ( unequal_one(a) ) {
1062 degrees.push_back(
degree(a));
1063 ddfactors.push_back(a);
1077static void same_degree_factor(
const umodpoly& a, upvec& upv)
1079 cl_modint_ring
R = a[0].ring();
1081 vector<int> degrees;
1083 distinct_degree_factor(a, degrees, ddfactors);
1085 for (
size_t i=0; i<degrees.size(); ++i ) {
1086 if ( degrees[i] ==
degree(ddfactors[i]) ) {
1087 upv.push_back(ddfactors[i]);
1089 berlekamp(ddfactors[i], upv);
1095#define USE_SAME_DEGREE_FACTOR
1107static void factor_modular(
const umodpoly& p, upvec& upv)
1109#ifdef USE_SAME_DEGREE_FACTOR
1110 same_degree_factor(p, upv);
1124static void exteuclid(
const umodpoly& a,
const umodpoly& b, umodpoly& s, umodpoly& t)
1127 exteuclid(b, a, t, s);
1131 umodpoly
one(1, a[0].ring()->
one());
1132 umodpoly
c = a; normalize_in_field(
c);
1133 umodpoly d = b; normalize_in_field(d);
1141 umodpoly
r =
c - q * d;
1142 umodpoly r1 = s - q * d1;
1143 umodpoly r2 = t - q * d2;
1147 if (
r.empty() )
break;
1152 cl_MI fac = recip(lcoeff(a) * lcoeff(
c));
1153 for (
auto & i : s) {
1157 fac = recip(lcoeff(b) * lcoeff(
c));
1158 for (
auto & i : t) {
1170static upoly replace_lc(
const upoly&
poly,
const cl_I& lc)
1181static inline cl_I calc_bound(
const ex& a,
const ex&
x)
1184 for (
int i=a.degree(
x); i>=a.ldegree(
x); --i ) {
1185 cl_I aa =
abs(the<cl_I>(ex_to<numeric>(a.coeff(
x, i)).to_cl_N()));
1186 radicand = radicand + square(aa);
1188 return ceiling1(the<cl_R>(cln::sqrt(radicand)));
1194static inline cl_I calc_bound(
const upoly& a)
1197 for (
int i=
degree(a); i>=0; --i ) {
1198 cl_I aa =
abs(a[i]);
1199 radicand = radicand + square(aa);
1201 return ceiling1(the<cl_R>(cln::sqrt(radicand)));
1216static void hensel_univar(
const upoly& a_,
unsigned int p,
const umodpoly& u1_,
const umodpoly& w1_, upoly& u, upoly& w)
1219 const cl_modint_ring&
R = u1_[0].ring();
1223 cl_I maxmodulus = ash(calc_bound(a), maxdeg+1);
1226 cl_I alpha = lcoeff(a);
1229 normalize_in_field(nu1);
1231 normalize_in_field(nw1);
1233 phi = umodpoly_to_upoly(nu1) * alpha;
1235 umodpoly_from_upoly(u1, phi,
R);
1236 phi = umodpoly_to_upoly(nw1) * alpha;
1238 umodpoly_from_upoly(w1, phi,
R);
1243 exteuclid(u1, w1, s, t);
1246 u = replace_lc(umodpoly_to_upoly(u1), alpha);
1247 w = replace_lc(umodpoly_to_upoly(w1), alpha);
1248 upoly e = a - u * w;
1252 while ( !e.empty() &&
modulus < maxmodulus ) {
1254 phi = umodpoly_to_upoly(s) *
c;
1255 umodpoly sigmatilde;
1256 umodpoly_from_upoly(sigmatilde, phi,
R);
1257 phi = umodpoly_to_upoly(t) *
c;
1259 umodpoly_from_upoly(tautilde, phi,
R);
1261 remdiv(sigmatilde, w1,
r, q);
1263 phi = umodpoly_to_upoly(tautilde) + umodpoly_to_upoly(q) * umodpoly_to_upoly(u1);
1265 umodpoly_from_upoly(tau, phi,
R);
1266 u = u + umodpoly_to_upoly(tau) *
modulus;
1267 w = w + umodpoly_to_upoly(sigma) *
modulus;
1275 for (
size_t i=1; i<u.size(); ++i ) {
1277 if ( g == 1 )
break;
1296static unsigned int next_prime(
unsigned int n)
1298 static vector<unsigned int> primes = {2, 3, 5, 7};
1299 unsigned int candidate = primes.back();
1300 while (primes.back() <=
n) {
1303 for (
size_t i=1; primes[i]*primes[i]<=candidate; ++i) {
1304 if (candidate % primes[i] == 0) {
1310 primes.push_back(candidate);
1312 for (
auto & it : primes) {
1317 throw logic_error(
"next_prime: should not reach this point!");
1322class factor_partition
1326 factor_partition(
const upvec& factors_) :
factors(factors_)
1332 one.resize(1,
factors.front()[0].ring()->one());
1337 int operator[](
size_t i)
const {
return k[i]; }
1338 size_t size()
const {
return n; }
1339 size_t size_left()
const {
return n-
len; }
1340 size_t size_right()
const {
return len; }
1345 if ( last == n-1 ) {
1355 while ( k[last] == 0 ) { --
last; }
1356 if ( last == 0 && n == 2*len )
return false;
1358 for (
size_t i=0; i<=
len-
rem; ++i ) {
1362 fill(
k.begin()+last,
k.end(), 0);
1369 if ( len > n/2 )
return false;
1370 fill(
k.begin(),
k.begin()+len, 1);
1371 fill(
k.begin()+len+1,
k.end(), 0);
1380 umodpoly& left() {
return lr[0]; }
1382 umodpoly& right() {
return lr[1]; }
1391 while ( i < n && k[i] == group ) { ++d; ++i; }
1393 if ( cache[pos].size() >= d ) {
1394 lr[group] =
lr[group] *
cache[pos][d-1];
1396 if ( cache[pos].size() == 0 ) {
1397 cache[pos].push_back(factors[pos] * factors[pos+1]);
1399 size_t j = pos +
cache[pos].size() + 1;
1400 d -=
cache[pos].size();
1403 cache[pos].push_back(buf);
1407 lr[group] =
lr[group] *
cache[pos].back();
1421 for (
size_t i=0; i<
n; ++i ) {
1456static ex factor_univariate(
const ex&
poly,
const ex&
x,
unsigned int& prime)
1461 upoly_from_ex(prim, prim_ex,
x);
1462 if (prim_ex.is_equal(1)) {
1468 unsigned int lastp = prime;
1470 unsigned int trials = 0;
1471 unsigned int minfactors = 0;
1473 const numeric& cont_n = ex_to<numeric>(
cont);
1475 if (cont_n.is_integer()) {
1476 i_cont = the<cl_I>(cont_n.to_cl_N());
1482 cl_I lc = lcoeff(prim)*i_cont;
1484 while ( trials < 2 ) {
1487 prime = next_prime(prime);
1488 if ( !zerop(
rem(lc, prime)) ) {
1489 R = find_modint_ring(prime);
1490 umodpoly_from_upoly(modpoly, prim,
R);
1491 if ( squarefree(modpoly) )
break;
1497 factor_modular(modpoly, trialfactors);
1498 if ( trialfactors.size() <= 1 ) {
1503 if ( minfactors == 0 || trialfactors.size() < minfactors ) {
1505 minfactors = trialfactors.size();
1513 R = find_modint_ring(prime);
1516 stack<ModFactors> tocheck;
1523 while ( tocheck.size() ) {
1524 const size_t n = tocheck.top().factors.size();
1525 factor_partition part(tocheck.top().factors);
1528 hensel_univar(tocheck.top().poly, prime, part.left(), part.right(), f1, f2);
1529 if ( !f1.empty() ) {
1531 if ( part.size_left() == 1 ) {
1532 if ( part.size_right() == 1 ) {
1533 result *= upoly_to_ex(f1,
x) * upoly_to_ex(f2,
x);
1537 result *= upoly_to_ex(f1,
x);
1538 tocheck.top().poly = f2;
1539 for (
size_t i=0; i<
n; ++i ) {
1540 if ( part[i] == 0 ) {
1541 tocheck.top().factors.erase(tocheck.top().factors.begin()+i);
1547 else if ( part.size_right() == 1 ) {
1548 if ( part.size_left() == 1 ) {
1549 result *= upoly_to_ex(f1,
x) * upoly_to_ex(f2,
x);
1553 result *= upoly_to_ex(f2,
x);
1554 tocheck.top().poly = f1;
1555 for (
size_t i=0; i<
n; ++i ) {
1556 if ( part[i] == 1 ) {
1557 tocheck.top().factors.erase(tocheck.top().factors.begin()+i);
1563 upvec newfactors1(part.size_left()), newfactors2(part.size_right());
1564 auto i1 = newfactors1.begin(), i2 = newfactors2.begin();
1565 for (
size_t i=0; i<
n; ++i ) {
1567 *i2++ = tocheck.top().factors[i];
1569 *i1++ = tocheck.top().factors[i];
1572 tocheck.top().factors = newfactors1;
1573 tocheck.top().poly = f1;
1575 mf.factors = newfactors2;
1582 if ( !part.next() ) {
1585 result *= upoly_to_ex(tocheck.top().poly,
x);
1599static inline ex factor_univariate(
const ex&
poly,
const ex&
x)
1602 return factor_univariate(
poly,
x, prime);
1614ostream&
operator<<(ostream& o,
const vector<EvalPoint>& v)
1616 for (
size_t i=0; i<v.size(); ++i ) {
1617 o <<
"(" << v[i].x <<
"==" << v[i].evalpoint <<
") ";
1624static vector<ex> multivar_diophant(
const vector<ex>& a_,
const ex&
x,
const ex&
c,
const vector<EvalPoint>&
I,
unsigned int d,
unsigned int p,
unsigned int k);
1641static upvec multiterm_eea_lift(
const upvec& a,
const ex&
x,
unsigned int p,
unsigned int k)
1643 const size_t r = a.size();
1644 cl_modint_ring
R = find_modint_ring(expt_pos(cl_I(p),
k));
1647 for (
size_t j=
r-2; j>=1; --j ) {
1648 q[j-1] = a[j] * q[j];
1650 umodpoly beta(1,
R->one());
1652 for (
size_t j=1; j<
r; ++j ) {
1653 vector<ex> mdarg(2);
1654 mdarg[0] = umodpoly_to_ex(q[j-1],
x);
1655 mdarg[1] = umodpoly_to_ex(a[j-1],
x);
1656 vector<EvalPoint> empty;
1657 vector<ex> exsigma = multivar_diophant(mdarg,
x, umodpoly_to_ex(beta,
x), empty, 0, p,
k);
1659 umodpoly_from_ex(sigma1, exsigma[0],
x,
R);
1661 umodpoly_from_ex(sigma2, exsigma[1],
x,
R);
1663 s.push_back(sigma2);
1674static void change_modulus(
const cl_modint_ring&
R, umodpoly& a)
1676 if ( a.empty() )
return;
1677 cl_modint_ring oldR = a[0].ring();
1678 for (
auto & i : a) {
1679 i =
R->canonhom(oldR->retract(i));
1698static void eea_lift(
const umodpoly& a,
const umodpoly& b,
const ex&
x,
unsigned int p,
unsigned int k, umodpoly& s_, umodpoly& t_)
1700 cl_modint_ring
R = find_modint_ring(p);
1702 change_modulus(
R, amod);
1704 change_modulus(
R, bmod);
1708 exteuclid(amod, bmod,
smod, tmod);
1710 cl_modint_ring Rpk = find_modint_ring(expt_pos(cl_I(p),
k));
1712 change_modulus(Rpk, s);
1714 change_modulus(Rpk, t);
1717 umodpoly
one(1, Rpk->one());
1718 for (
size_t j=1; j<
k; ++j ) {
1719 umodpoly e =
one - a * s - b * t;
1722 change_modulus(
R,
c);
1723 umodpoly sigmabar =
smod *
c;
1724 umodpoly taubar = tmod *
c;
1726 remdiv(sigmabar, bmod, sigma, q);
1727 umodpoly tau = taubar + q * amod;
1728 umodpoly sadd = sigma;
1729 change_modulus(Rpk, sadd);
1730 cl_MI modmodulus(Rpk,
modulus);
1731 s = s + sadd * modmodulus;
1732 umodpoly tadd = tau;
1733 change_modulus(Rpk, tadd);
1734 t = t + tadd * modmodulus;
1756static upvec univar_diophant(
const upvec& a,
const ex&
x,
unsigned int m,
unsigned int p,
unsigned int k)
1758 cl_modint_ring
R = find_modint_ring(expt_pos(cl_I(p),
k));
1760 const size_t r = a.size();
1763 upvec s = multiterm_eea_lift(a,
x, p,
k);
1764 for (
size_t j=0; j<
r; ++j ) {
1765 umodpoly bmod = umodpoly_to_umodpoly(s[j],
R,
m);
1767 rem(bmod, a[j], buf);
1768 result.push_back(buf);
1772 eea_lift(a[1], a[0],
x, p,
k, s, t);
1773 umodpoly bmod = umodpoly_to_umodpoly(s,
R,
m);
1775 remdiv(bmod, a[0], buf, q);
1776 result.push_back(buf);
1777 umodpoly t1mod = umodpoly_to_umodpoly(t,
R,
m);
1778 buf = t1mod + q * a[1];
1779 result.push_back(buf);
1789struct make_modular_map :
public map_function {
1791 make_modular_map(
const cl_modint_ring& R_) :
R(R_) { }
1792 ex operator()(
const ex& e)
override
1794 if ( is_a<add>(e) || is_a<mul>(e) ) {
1795 return e.map(*
this);
1797 else if ( is_a<numeric>(e) ) {
1798 numeric
mod(
R->modulus);
1799 numeric halfmod = (
mod-1)/2;
1800 cl_MI emod =
R->canonhom(the<cl_I>(ex_to<numeric>(e).to_cl_N()));
1801 numeric
n(
R->retract(emod));
1802 if (
n > halfmod ) {
1819static ex make_modular(
const ex& e,
const cl_modint_ring&
R)
1821 make_modular_map map(
R);
1822 return map(e.expand());
1842static vector<ex> multivar_diophant(
const vector<ex>& a_,
const ex&
x,
const ex&
c,
const vector<EvalPoint>&
I,
1843 unsigned int d,
unsigned int p,
unsigned int k)
1847 const cl_I
modulus = expt_pos(cl_I(p),
k);
1848 const cl_modint_ring
R = find_modint_ring(
modulus);
1849 const size_t r = a.size();
1850 const size_t nu =
I.size() + 1;
1854 ex xnu =
I.back().x;
1855 int alphanu =
I.back().evalpoint;
1858 for (
size_t i=0; i<
r; ++i ) {
1862 for (
size_t i=0; i<
r; ++i ) {
1866 vector<ex> anew = a;
1867 for (
size_t i=0; i<
r; ++i ) {
1868 anew[i] = anew[i].subs(xnu == alphanu);
1870 ex cnew =
c.subs(xnu == alphanu);
1871 vector<EvalPoint> Inew =
I;
1873 sigma = multivar_diophant(anew,
x, cnew, Inew, d, p,
k);
1876 for (
size_t i=0; i<
r; ++i ) {
1877 buf -= sigma[i] * b[i];
1879 ex e = make_modular(buf,
R);
1882 for (
size_t m=1; !e.is_zero() && e.has(xnu) &&
m<=d; ++
m ) {
1883 monomial *= (xnu - alphanu);
1884 monomial =
expand(monomial);
1885 ex cm = e.diff(ex_to<symbol>(xnu),
m).subs(xnu==alphanu) /
factorial(
m);
1886 cm = make_modular(cm,
R);
1887 if ( !cm.is_zero() ) {
1888 vector<ex> delta_s = multivar_diophant(anew,
x, cm, Inew, d, p,
k);
1890 for (
size_t j=0; j<delta_s.size(); ++j ) {
1891 delta_s[j] *= monomial;
1892 sigma[j] += delta_s[j];
1893 buf -= delta_s[j] * b[j];
1895 e = make_modular(buf,
R);
1900 for (
size_t i=0; i<a.size(); ++i ) {
1902 umodpoly_from_ex(up, a[i],
x,
R);
1906 sigma.insert(sigma.begin(),
r, 0);
1909 if ( is_a<add>(
c) ) {
1916 for (
size_t i=0; i<nterms; ++i ) {
1917 int m = z.degree(
x);
1918 cl_I cm = the<cl_I>(ex_to<numeric>(z.lcoeff(
x)).to_cl_N());
1919 upvec delta_s = univar_diophant(amod,
x,
m, p,
k);
1921 cl_I poscm = plusp(cm) ? cm :
mod(cm,
modulus);
1922 modcm = cl_MI(
R, poscm);
1923 for (
size_t j=0; j<delta_s.size(); ++j ) {
1924 delta_s[j] = delta_s[j] * modcm;
1925 sigma[j] = sigma[j] + umodpoly_to_ex(delta_s[j],
x);
1927 if ( nterms > 1 && i+1 != nterms ) {
1933 for (
size_t i=0; i<sigma.size(); ++i ) {
1934 sigma[i] = make_modular(sigma[i],
R);
1956static ex hensel_multivar(
const ex& a,
const ex&
x,
const vector<EvalPoint>&
I,
1957 unsigned int p,
const cl_I& l,
const upvec& u,
const vector<ex>& lcU)
1959 const size_t nu =
I.size() + 1;
1960 const cl_modint_ring
R = find_modint_ring(expt_pos(cl_I(p),l));
1965 for (
size_t j=nu; j>=2; --j ) {
1967 int alpha =
I[j-2].evalpoint;
1968 A[j-2] = A[j-1].
subs(
x==alpha);
1969 A[j-2] = make_modular(A[j-2],
R);
1972 int maxdeg = a.degree(
I.front().x);
1973 for (
size_t i=1; i<
I.size(); ++i ) {
1974 int maxdeg2 = a.degree(
I[i].
x);
1975 if ( maxdeg2 > maxdeg ) maxdeg = maxdeg2;
1978 const size_t n = u.size();
1980 for (
size_t i=0; i<
n; ++i ) {
1981 U[i] = umodpoly_to_ex(u[i],
x);
1984 for (
size_t j=2; j<=nu; ++j ) {
1987 for (
size_t m=0;
m<
n; ++
m) {
1988 if ( lcU[
m] != 1 ) {
1990 for (
size_t i=j-1; i<nu-1; ++i ) {
1993 coef = make_modular(coef,
R);
1994 int deg = U[
m].degree(
x);
1995 U[
m] = U[
m] - U[
m].lcoeff(
x) *
pow(
x,deg) + coef *
pow(
x,deg);
1999 for (
size_t i=0; i<
n; ++i ) {
2002 ex e =
expand(A[j-1] - Uprod);
2004 vector<EvalPoint> newI;
2005 for (
size_t i=1; i<=j-2; ++i ) {
2006 newI.push_back(
I[i-1]);
2010 int alphaj =
I[j-2].evalpoint;
2011 size_t deg = A[j-1].
degree(xj);
2012 for (
size_t k=1;
k<=deg; ++
k ) {
2013 if ( !e.is_zero() ) {
2014 monomial *= (xj - alphaj);
2015 monomial =
expand(monomial);
2016 ex dif = e.diff(ex_to<symbol>(xj),
k);
2018 if ( !
c.is_zero() ) {
2019 vector<ex> deltaU = multivar_diophant(U1,
x,
c, newI, maxdeg, p, cl_I_to_uint(l));
2020 for (
size_t i=0; i<
n; ++i ) {
2021 deltaU[i] *= monomial;
2023 U[i] = make_modular(U[i],
R);
2026 for (
size_t i=0; i<
n; ++i ) {
2030 e = make_modular(e,
R);
2037 for (
size_t i=0; i<U.size(); ++i ) {
2041 return lst(U.begin(), U.end());
2051static exvector put_factors_into_vec(
const ex& e)
2054 if ( is_a<numeric>(e) ) {
2055 result.push_back(e);
2058 if ( is_a<power>(e) ) {
2059 result.push_back(1);
2060 result.push_back(e.op(0));
2063 if ( is_a<symbol>(e) || is_a<add>(e) ) {
2064 ex icont(e.integer_content());
2065 result.push_back(icont);
2066 result.push_back(e/icont);
2069 if ( is_a<mul>(e) ) {
2071 result.push_back(nfac);
2072 for (
size_t i=0; i<e.nops(); ++i ) {
2074 if ( is_a<numeric>(
op) ) {
2077 if ( is_a<power>(
op) ) {
2078 result.push_back(
op.
op(0));
2080 if ( is_a<symbol>(
op) || is_a<add>(
op) ) {
2081 result.push_back(
op);
2087 throw runtime_error(
"put_factors_into_vec: bad term.");
2096static bool checkdivisors(
const exvector& f)
2098 const int k = f.size();
2100 vector<numeric> d(
k);
2101 d[0] = ex_to<numeric>(
abs(f[0]));
2102 for (
int i=1; i<
k; ++i ) {
2103 q = ex_to<numeric>(
abs(f[i]));
2104 for (
int j=i-1; j>=0; --j ) {
2137 numeric&
modulus, ex& u0, vector<numeric>& a)
2146 for (
size_t i=0; i<a.size(); ++i ) {
2149 vnatry = vna.
subs(*s == a[i]);
2151 }
while ( vnatry == 0 );
2153 u0 = u0.
subs(*s == a[i]);
2157 ex g =
gcd(u0, u0.diff(ex_to<symbol>(
x)));
2158 if ( !is_a<numeric>(g) ) {
2161 if ( !is_a<numeric>(
vn) ) {
2164 fnum[0] = fnum[0] * u0.content(
x);
2165 for (
size_t i=1; i<fnum.size(); ++i ) {
2166 if ( !is_a<numeric>(fnum[i]) ) {
2168 for (
size_t j=0; j<a.size(); ++j, ++s ) {
2169 fnum[i] = fnum[i].subs(*s == a[j]);
2173 if ( checkdivisors(fnum) ) {
2183static ex factor_sqrfree(
const ex&
poly);
2187struct factorization_ctx {
2194 ex try_next_evaluation_homomorphism()
2196 constexpr unsigned maxtrials = 3;
2197 vector<numeric> a(
syms_wox.size(), 0);
2199 unsigned int trialcount = 0;
2201 int factor_count = 0;
2202 int min_factor_count = -1;
2208 while ( trialcount < maxtrials ) {
2213 ufac = factor_univariate(u,
x, prime);
2214 ufaclst = put_factors_into_vec(ufac);
2215 factor_count = ufaclst.size()-1;
2218 if ( factor_count <= 1 ) {
2222 if ( min_factor_count < 0 ) {
2224 min_factor_count = factor_count;
2226 else if ( min_factor_count == factor_count ) {
2230 else if ( min_factor_count > factor_count ) {
2232 min_factor_count = factor_count;
2238 vector<ex> C(factor_count);
2239 if ( is_a<numeric>(
vn) ) {
2241 for (
size_t i=1; i<ufaclst.size(); ++i ) {
2242 C[i-1] = ufaclst[i].lcoeff(
x);
2249 vector<numeric> ftilde(
vnlst.size()-1);
2250 for (
size_t i=0; i<ftilde.size(); ++i ) {
2253 for (
size_t j=0; j<a.size(); ++j ) {
2254 ft = ft.subs(*s == a[j]);
2257 ftilde[i] = ex_to<numeric>(ft);
2260 vector<bool> used_flag(ftilde.size(),
false);
2261 vector<ex> D(factor_count, 1);
2263 for (
int i=0; i<factor_count; ++i ) {
2264 numeric prefac = ex_to<numeric>(ufaclst[i+1].lcoeff(
x));
2265 for (
int j=ftilde.size()-1; j>=0; --j ) {
2268 while (
irem(prefac, ftilde[j], q) == 0 ) {
2273 used_flag[j] =
true;
2274 D[i] = D[i] *
pow(
vnlst[j+1], count);
2277 C[i] = D[i] * prefac;
2280 for (
int i=0; i<factor_count; ++i ) {
2281 numeric prefac = ex_to<numeric>(ufaclst[i+1].lcoeff(
x));
2282 for (
int j=ftilde.size()-1; j>=0; --j ) {
2285 while (
irem(prefac, ftilde[j], q) == 0 ) {
2289 while (
irem(ex_to<numeric>(delta)*prefac, ftilde[j]) == 0 ) {
2290 numeric g =
gcd(prefac, ex_to<numeric>(ftilde[j]));
2291 prefac =
iquo(prefac, g);
2292 delta = delta / (ftilde[j]/g);
2293 ufaclst[i+1] = ufaclst[i+1] * (ftilde[j]/g);
2297 used_flag[j] =
true;
2298 D[i] = D[i] *
pow(
vnlst[j+1], count);
2301 C[i] = D[i] * prefac;
2305 bool some_factor_unused =
false;
2306 for (
size_t i=0; i<used_flag.size(); ++i ) {
2307 if ( !used_flag[i] ) {
2308 some_factor_unused =
true;
2312 if ( some_factor_unused ) {
2320 C[0] = C[0] * delta;
2321 ufaclst[1] = ufaclst[1] * delta;
2325 vector<EvalPoint> epv;
2327 for (
size_t i=0; i<a.size(); ++i ) {
2328 epv.emplace_back(EvalPoint{*s++, a[i].to_int()});
2333 for (
int i=1; i<=factor_count; ++i ) {
2334 if ( ufaclst[i].
degree(
x) > maxdeg ) {
2335 maxdeg = ufaclst[i].degree(
x);
2338 cl_I B = ash(calc_bound(u,
x), maxdeg+1);
2347 cl_modint_ring
R = find_modint_ring(pl);
2348 upvec modfactors(ufaclst.size()-1);
2349 for (
size_t i=1; i<ufaclst.size(); ++i ) {
2350 umodpoly_from_ex(modfactors[i-1], ufaclst[i],
x,
R);
2354 return hensel_multivar(
pp,
x, epv, prime, l, modfactors, C);
2373static ex factor_multivariate(
const ex&
poly,
const exset&
syms)
2376 vector<factorization_ctx> ctx_in_x;
2377 for (
auto x :
syms) {
2386 if ( !is_a<numeric>(ctx.cont) ) {
2388 return ctx.unit * factor_sqrfree(ctx.cont) * factor_sqrfree(ctx.pp);
2392 ctx.vn = ctx.pp.collect(
x).lcoeff(
x);
2393 ctx.vnlst = put_factors_into_vec(
factor(ctx.vn));
2395 ctx.modulus = (ctx.vnlst.size() > 3) ? ctx.vnlst.size() : numeric(3);
2397 ctx_in_x.push_back(ctx);
2401 auto ctx = ctx_in_x.begin();
2404 ex res = ctx->try_next_evaluation_homomorphism();
2406 if ( res !=
lst{} ) {
2408 ex result = ctx->cont * ctx->unit;
2409 for (
size_t i=0; i<res.nops(); ++i ) {
2418 if (++ctx == ctx_in_x.end()) {
2419 ctx = ctx_in_x.
begin();
2426struct find_symbols_map :
public map_function {
2428 ex operator()(
const ex& e)
override
2430 if ( is_a<symbol>(e) ) {
2434 return e.map(*
this);
2441static ex factor_sqrfree(
const ex&
poly)
2444 find_symbols_map findsymbols;
2446 if ( findsymbols.syms.size() == 0 ) {
2450 if ( findsymbols.syms.size() == 1 ) {
2452 const ex&
x = *(findsymbols.syms.begin());
2457 return res *
pow(
x,ld);
2459 ex res = factor_univariate(
poly,
x);
2465 ex res = factor_multivariate(
poly, findsymbols.syms);
2472struct apply_factor_map :
public map_function {
2474 apply_factor_map(
unsigned options_) :
options(options_) { }
2475 ex operator()(
const ex& e)
override
2478 return factor(e, options);
2480 if ( is_a<add>(e) ) {
2482 for (
size_t i=0; i<e.nops(); ++i ) {
2489 return factor(s1, options) + s2.
map(*
this);
2491 return e.
map(*
this);
2501template <
typename F>
void
2502factor_iter(
const ex &e, F yield)
2505 for (
const auto &f : e) {
2506 if (is_a<power>(f)) {
2507 yield(f.op(0), f.op(1));
2513 if (is_a<power>(e)) {
2514 yield(e.op(0), e.op(1));
2529static ex factor1(
const ex&
poly,
unsigned options)
2534 options &= ~factor_options::all;
2535 apply_factor_map factor_map(
options);
2536 return factor_map(
poly);
2542 find_symbols_map findsymbols;
2544 if ( findsymbols.syms.size() == 0 ) {
2548 for (
auto & i : findsymbols.
syms ) {
2558 [&](
const ex &f,
const ex &
k) {
2559 if ( is_a<add>(f) ) {
2560 res *=
pow(factor_sqrfree(f),
k);
2578 [&](
const ex &f1,
const ex &k1) {
2579 factor_iter(factor1(f1,
options),
2580 [&](
const ex &f2,
const ex &k2) {
2581 result *=
pow(f2, k1*k2);
Interface to GiNaC's sums of expressions.
Lightweight wrapper for GiNaC's symbolic objects.
ex unit(const ex &x) const
Compute unit part (= sign of leading coefficient) of a multivariate polynomial in Q[x].
ex map(map_function &f) const
const_iterator begin() const noexcept
void unitcontprim(const ex &x, ex &u, ex &c, ex &p) const
Compute unit part, content part, and primitive part of a multivariate polynomial in Q[x].
ex subs(const exmap &m, unsigned options=0) const
int ldegree(const ex &s) const
@ all
factor all polynomial subexpressions
ex subs(const exmap &m, unsigned options=0) const override
Substitute a set of objects by arbitrary expressions.
int degree(const ex &s) const override
Return degree of highest power in object s.
Interface to GiNaC's light-weight expression handles.
vector< vector< umodpoly > > cache
Polynomial factorization.
Interface to GiNaC's initially known functions.
Interface to GiNaC's products of expressions.
bool is_zero(const ex &thisex)
const numeric I
Imaginary unit.
std::ostream & operator<<(std::ostream &os, const archive_node &n)
Write archive_node to binary data stream.
const numeric pow(const numeric &x, const numeric &y)
container< std::list > lst
ex sqrfree(const ex &a, const lst &l)
Compute a square-free factorization of a multivariate polynomial in Q[X].
std::set< ex, ex_is_less > exset
const numeric mod(const numeric &a, const numeric &b)
Modulus (in positive representation).
const ex operator/(const ex &lh, const ex &rh)
const numeric abs(const numeric &x)
Absolute value.
ex gcd(const ex &a, const ex &b, ex *ca, ex *cb, bool check_args, unsigned options)
Compute GCD (Greatest Common Divisor) of multivariate polynomials a(X) and b(X) in Z[X].
const numeric irem(const numeric &a, const numeric &b)
Numeric integer remainder.
const ex operator+(const ex &lh, const ex &rh)
const ex operator*(const ex &lh, const ex &rh)
const numeric factorial(const numeric &n)
Factorial combinatorial function.
const numeric smod(const numeric &a_, const numeric &b_)
Modulus (in symmetric representation).
int degree(const ex &thisex, const ex &s)
const numeric iquo(const numeric &a, const numeric &b)
Numeric integer quotient.
ex normal(const ex &thisex)
ex op(const ex &thisex, size_t i)
ex coeff(const ex &thisex, const ex &s, int n=1)
ex factor(const ex &poly, unsigned options)
Interface function to the outside world.
bool is_prime(const numeric &x)
int canonicalize(exvector::iterator v, const symmetry &symm)
Canonicalize the order of elements of an expression vector, according to the symmetry properties defi...
ex rem(const ex &a, const ex &b, const ex &x, bool check_args)
Remainder r(x) of polynomials a(x) and b(x) in Q[x].
std::vector< ex > exvector
const ex operator-(const ex &lh, const ex &rh)
ex expand(const ex &thisex, unsigned options=0)
void swap(GiNaC::ex &a, GiNaC::ex &b)
Specialization of std::swap() for ex objects.
This file defines several functions that work on univariate and multivariate polynomials and rational...
Makes the interface to the underlying bignum package available.
Interface to GiNaC's overloaded operators.
Interface to GiNaC's symbolic exponentiation (basis^exponent).
Interface to relations between expressions.
Interface to GiNaC's symbolic objects.