88#define DCOUT(str) cout << #str << endl
89#define DCOUTVAR(var) cout << #var << ": " << var << endl
90#define DCOUT2(str,var) cout << #str << ": " << var << endl
91ostream&
operator<<(ostream& o,
const vector<int>& v)
93 auto i = v.begin(), end = v.end();
100static ostream&
operator<<(ostream& o,
const vector<cl_I>& v)
102 auto i = v.begin(), end = v.end();
104 o << *i <<
"[" << i-v.begin() <<
"]" <<
" ";
109static ostream&
operator<<(ostream& o,
const vector<cl_MI>& v)
111 auto i = v.begin(), end = v.end();
113 o << *i <<
"[" << i-v.begin() <<
"]" <<
" ";
118ostream&
operator<<(ostream& o,
const vector<numeric>& v)
120 for (
size_t i=0; i<v.size(); ++i ) {
125ostream&
operator<<(ostream& o,
const vector<vector<cl_MI>>& v)
127 auto i = v.begin(), end = v.end();
129 o << i-v.begin() <<
": " << *i << endl;
137#define DCOUT2(str,var)
143typedef std::vector<cln::cl_MI> umodpoly;
144typedef std::vector<cln::cl_I> upoly;
145typedef vector<umodpoly> upvec;
151template<
typename T>
static int degree(
const T& p)
156template<
typename T>
static typename T::value_type lcoeff(
const T& p)
158 return p[p.size() - 1];
166static bool normalize_in_field(umodpoly& a)
170 if ( lcoeff(a) == a[0].ring()->
one() ) {
174 const cln::cl_MI lc_1 = recip(lcoeff(a));
175 for (std::size_t
k = a.size();
k-- != 0; )
185template<
typename T>
static void
186canonicalize(T& p,
const typename T::size_type hint = std::numeric_limits<typename T::size_type>::max())
188 std::size_t i = min(p.size(), hint);
190 while ( i-- && zerop(p[i]) ) { }
192 p.erase(p.begin() + i + 1, p.end());
197template<
typename T>
struct uvar_poly_p
202template<>
struct uvar_poly_p<upoly>
204 static const bool value =
true;
207template<>
struct uvar_poly_p<umodpoly>
209 static const bool value =
true;
214static typename enable_if<uvar_poly_p<T>::value, T>::type
222 for ( ; i<sb; ++i ) {
225 for ( ; i<sa; ++i ) {
234 for ( ; i<sa; ++i ) {
237 for ( ; i<sb; ++i ) {
249static typename enable_if<uvar_poly_p<T>::value, T>::type
257 for ( ; i<sb; ++i ) {
260 for ( ; i<sa; ++i ) {
269 for ( ; i<sa; ++i ) {
272 for ( ; i<sb; ++i ) {
280static upoly
operator*(
const upoly& a,
const upoly& b)
283 if ( a.empty() || b.empty() )
return c;
287 for (
int i=0 ; i<=
n; ++i ) {
288 for (
int j=0 ; j<=i; ++j ) {
290 c[i] =
c[i] + a[j] * b[i-j];
297static umodpoly
operator*(
const umodpoly& a,
const umodpoly& b)
300 if ( a.empty() || b.empty() )
return c;
303 c.resize(
n+1, a[0].ring()->zero());
304 for (
int i=0 ; i<=
n; ++i ) {
305 for (
int j=0 ; j<=i; ++j ) {
307 c[i] =
c[i] + a[j] * b[i-j];
314static upoly
operator*(
const upoly& a,
const cl_I&
x)
321 for (
size_t i=0; i<a.size(); ++i ) {
327static upoly
operator/(
const upoly& a,
const cl_I&
x)
334 for (
size_t i=0; i<a.size(); ++i ) {
335 r[i] = exquo(a[i],
x);
340static umodpoly
operator*(
const umodpoly& a,
const cl_MI&
x)
342 umodpoly
r(a.size());
343 for (
size_t i=0; i<a.size(); ++i ) {
350static void upoly_from_ex(upoly& up,
const ex& e,
const ex&
x)
353 int deg = e.degree(
x);
355 int ldeg = e.ldegree(
x);
356 for ( ; deg>=ldeg; --deg ) {
357 up[deg] = the<cl_I>(ex_to<numeric>(e.coeff(
x, deg)).to_cl_N());
359 for ( ; deg>=0; --deg ) {
365static void umodpoly_from_upoly(umodpoly& ump,
const upoly& e,
const cl_modint_ring&
R)
369 for ( ; deg>=0; --deg ) {
370 ump[deg] =
R->canonhom(e[deg]);
375static void umodpoly_from_ex(umodpoly& ump,
const ex& e,
const ex&
x,
const cl_modint_ring&
R)
378 int deg = e.degree(
x);
380 int ldeg = e.ldegree(
x);
381 for ( ; deg>=ldeg; --deg ) {
382 cl_I
coeff = the<cl_I>(ex_to<numeric>(e.coeff(
x, deg)).to_cl_N());
383 ump[deg] =
R->canonhom(
coeff);
385 for ( ; deg>=0; --deg ) {
386 ump[deg] =
R->zero();
392static void umodpoly_from_ex(umodpoly& ump,
const ex& e,
const ex&
x,
const cl_I&
modulus)
394 umodpoly_from_ex(ump, e,
x, find_modint_ring(
modulus));
398static ex upoly_to_ex(
const upoly& a,
const ex&
x)
400 if ( a.empty() )
return 0;
402 for (
int i=
degree(a); i>=0; --i ) {
403 e += numeric(a[i]) *
pow(
x, i);
408static ex umodpoly_to_ex(
const umodpoly& a,
const ex&
x)
410 if ( a.empty() )
return 0;
411 cl_modint_ring
R = a[0].ring();
412 cl_I
mod =
R->modulus;
413 cl_I halfmod = (
mod-1) >> 1;
415 for (
int i=
degree(a); i>=0; --i ) {
416 cl_I
n =
R->retract(a[i]);
420 e += numeric(
n) *
pow(
x, i);
426static upoly umodpoly_to_upoly(
const umodpoly& a)
429 if ( a.empty() )
return e;
430 cl_modint_ring
R = a[0].ring();
431 cl_I
mod =
R->modulus;
432 cl_I halfmod = (
mod-1) >> 1;
433 for (
int i=
degree(a); i>=0; --i ) {
434 cl_I
n =
R->retract(a[i]);
444static umodpoly umodpoly_to_umodpoly(
const umodpoly& a,
const cl_modint_ring&
R,
unsigned int m)
447 if ( a.empty() )
return e;
448 cl_modint_ring oldR = a[0].ring();
449 size_t sa = a.size();
450 e.resize(sa+
m,
R->zero());
451 for (
size_t i=0; i<sa; ++i ) {
452 e[i+
m] =
R->canonhom(oldR->retract(a[i]));
465static void reduce_coeff(umodpoly& a,
const cl_I&
x)
467 if ( a.empty() )
return;
469 cl_modint_ring
R = a[0].ring();
472 cl_I
c =
R->retract(i);
473 i = cl_MI(
R, exquopos(
c,
x));
484static void rem(
const umodpoly& a,
const umodpoly& b, umodpoly&
r)
493 cl_MI qk = div(
r[
n+
k], b[
n]);
495 for (
int i=0; i<
n; ++i ) {
496 unsigned int j =
n +
k - 1 - i;
497 r[j] =
r[j] - qk * b[j-
k];
502 fill(
r.begin()+
n,
r.end(), a[0].ring()->zero());
513static void div(
const umodpoly& a,
const umodpoly& b, umodpoly& q)
522 q.resize(
k+1, a[0].ring()->zero());
524 cl_MI qk = div(
r[
n+
k], b[
n]);
527 for (
int i=0; i<
n; ++i ) {
528 unsigned int j =
n +
k - 1 - i;
529 r[j] =
r[j] - qk * b[j-
k];
545static void remdiv(
const umodpoly& a,
const umodpoly& b, umodpoly&
r, umodpoly& q)
554 q.resize(
k+1, a[0].ring()->zero());
556 cl_MI qk = div(
r[
n+
k], b[
n]);
559 for (
int i=0; i<
n; ++i ) {
560 unsigned int j =
n +
k - 1 - i;
561 r[j] =
r[j] - qk * b[j-
k];
566 fill(
r.begin()+
n,
r.end(), a[0].ring()->zero());
577static void gcd(
const umodpoly& a,
const umodpoly& b, umodpoly&
c)
582 normalize_in_field(
c);
584 normalize_in_field(d);
586 while ( !d.empty() ) {
591 normalize_in_field(
c);
599static void deriv(
const umodpoly& a, umodpoly& d)
602 if ( a.size() <= 1 )
return;
604 d.insert(d.begin(), a.begin()+1, a.end());
606 for (
int i=1; i<max; ++i ) {
612static bool unequal_one(
const umodpoly& a)
614 return ( a.size() != 1 || a[0] != a[0].ring()->one() );
617static bool equal_one(
const umodpoly& a)
619 return ( a.size() == 1 && a[0] == a[0].ring()->one() );
627static bool squarefree(
const umodpoly& a)
647static void expt_pos_Q(
const umodpoly& w,
const umodpoly& a,
unsigned int q, umodpoly&
r)
649 if ( w.empty() )
return;
650 cl_MI zero = w[0].ring()->zero();
652 umodpoly buf(deg*q+1, zero);
653 for (
size_t i=0; i<=deg; ++i ) {
665typedef vector<cl_MI> mvec;
670 friend ostream&
operator<<(ostream& o,
const modular_matrix& m);
673 modular_matrix(
size_t r_,
size_t c_,
const cl_MI& init) :
r(r_),
c(c_)
677 size_t rowsize()
const {
return r; }
678 size_t colsize()
const {
return c; }
679 cl_MI& operator()(
size_t row,
size_t col) {
return m[row*
c + col]; }
680 cl_MI operator()(
size_t row,
size_t col)
const {
return m[row*
c + col]; }
681 void mul_col(
size_t col,
const cl_MI
x)
683 for (
size_t rc=0; rc<
r; ++rc ) {
684 std::size_t i =
c*rc + col;
688 void sub_col(
size_t col1,
size_t col2,
const cl_MI fac)
690 for (
size_t rc=0; rc<
r; ++rc ) {
691 std::size_t i1 = col1 +
c*rc;
692 std::size_t i2 = col2 +
c*rc;
693 m[i1] =
m[i1] -
m[i2]*fac;
696 void switch_col(
size_t col1,
size_t col2)
698 for (
size_t rc=0; rc<
r; ++rc ) {
699 std::size_t i1 = col1 + rc*
c;
700 std::size_t i2 = col2 + rc*
c;
704 void mul_row(
size_t row,
const cl_MI
x)
706 for (
size_t cc=0; cc<
c; ++cc ) {
707 std::size_t i = row*
c + cc;
711 void sub_row(
size_t row1,
size_t row2,
const cl_MI fac)
713 for (
size_t cc=0; cc<
c; ++cc ) {
714 std::size_t i1 = row1*
c + cc;
715 std::size_t i2 = row2*
c + cc;
716 m[i1] =
m[i1] -
m[i2]*fac;
719 void switch_row(
size_t row1,
size_t row2)
721 for (
size_t cc=0; cc<
c; ++cc ) {
722 std::size_t i1 = row1*
c + cc;
723 std::size_t i2 = row2*
c + cc;
727 bool is_col_zero(
size_t col)
const
729 for (
size_t rr=0; rr<
r; ++rr ) {
730 std::size_t i = col + rr*
c;
731 if ( !zerop(m[i]) ) {
737 bool is_row_zero(
size_t row)
const
739 for (
size_t cc=0; cc<
c; ++cc ) {
740 std::size_t i = row*
c + cc;
741 if ( !zerop(m[i]) ) {
747 void set_row(
size_t row,
const vector<cl_MI>& newrow)
749 for (std::size_t i2 = 0; i2 < newrow.size(); ++i2) {
750 std::size_t i1 = row*
c + i2;
754 mvec::const_iterator row_begin(
size_t row)
const {
return m.begin()+row*
c; }
755 mvec::const_iterator row_end(
size_t row)
const {
return m.begin()+row*
c+
r; }
762modular_matrix
operator*(
const modular_matrix& m1,
const modular_matrix& m2)
764 const unsigned int r = m1.rowsize();
765 const unsigned int c = m2.colsize();
766 modular_matrix o(
r,
c,m1(0,0));
768 for (
size_t i=0; i<
r; ++i ) {
769 for (
size_t j=0; j<
c; ++j ) {
771 buf = m1(i,0) * m2(0,j);
772 for (
size_t k=1;
k<
c; ++
k ) {
773 buf = buf + m1(i,
k)*m2(
k,j);
781ostream&
operator<<(ostream& o,
const modular_matrix&
m)
783 cl_modint_ring
R =
m(0,0).ring();
785 for (
size_t i=0; i<
m.rowsize(); ++i ) {
787 for (
size_t j=0; j<
m.colsize()-1; ++j ) {
788 o <<
R->retract(
m(i,j)) <<
",";
790 o <<
R->retract(
m(i,
m.colsize()-1)) <<
"}";
791 if ( i !=
m.rowsize()-1 ) {
810static void q_matrix(
const umodpoly& a_, modular_matrix& Q)
813 normalize_in_field(a);
816 unsigned int q = cl_I_to_uint(a[0].ring()->
modulus);
817 umodpoly
r(
n, a[0].ring()->zero());
818 r[0] = a[0].ring()->one();
820 unsigned int max = (
n-1) * q;
821 for (
size_t m=1;
m<=max; ++
m ) {
822 cl_MI rn_1 =
r.back();
823 for (
size_t i=
n-1; i>0; --i ) {
824 r[i] =
r[i-1] - (rn_1 * a[i]);
827 if ( (
m % q) == 0 ) {
838static void nullspace(modular_matrix& M, vector<mvec>& basis)
840 const size_t n = M.rowsize();
841 const cl_MI
one = M(0,0).ring()->one();
842 for (
size_t i=0; i<
n; ++i ) {
843 M(i,i) = M(i,i) -
one;
845 for (
size_t r=0;
r<
n; ++
r ) {
847 for ( ; cc<
n; ++cc ) {
848 if ( !zerop(M(
r,cc)) ) {
850 if ( !zerop(M(cc,cc)) ) {
862 M.mul_col(
r, recip(M(
r,
r)));
863 for ( cc=0; cc<
n; ++cc ) {
865 M.sub_col(cc,
r, M(
r,cc));
871 for (
size_t i=0; i<
n; ++i ) {
872 M(i,i) = M(i,i) -
one;
874 for (
size_t i=0; i<
n; ++i ) {
875 if ( !M.is_row_zero(i) ) {
876 mvec nu(M.row_begin(i), M.row_end(i));
890static void berlekamp(
const umodpoly& a, upvec& upv)
892 cl_modint_ring
R = a[0].ring();
893 umodpoly
one(1,
R->one());
901 const unsigned int k = nu.size();
908 unsigned int size = 1;
910 unsigned int q = cl_I_to_uint(
R->modulus);
912 list<umodpoly>::iterator u =
factors.begin();
916 for (
unsigned int s=0; s<q; ++s ) {
917 umodpoly nur = nu[
r];
918 nur[0] = nur[0] - cl_MI(
R, s);
922 if ( unequal_one(g) && g != *u ) {
925 if ( equal_one(uo) ) {
926 throw logic_error(
"berlekamp: unexpected divisor.");
961static void expt_1_over_p(
const umodpoly& a,
unsigned int prime, umodpoly& ap)
963 size_t newdeg =
degree(a)/prime;
966 for (
size_t i=1; i<=newdeg; ++i ) {
977static void modsqrfree(
const umodpoly& a, upvec&
factors, vector<int>& mult)
979 const unsigned int prime = cl_I_to_uint(a[0].ring()->
modulus);
988 while ( unequal_one(w) ) {
1001 if ( unequal_one(
c) ) {
1003 expt_1_over_p(
c, prime, cp);
1004 size_t previ = mult.size();
1005 modsqrfree(cp,
factors, mult);
1006 for (
size_t i=previ; i<mult.size(); ++i ) {
1012 expt_1_over_p(a, prime, ap);
1013 size_t previ = mult.size();
1014 modsqrfree(ap,
factors, mult);
1015 for (
size_t i=previ; i<mult.size(); ++i ) {
1033static void distinct_degree_factor(
const umodpoly& a_, vector<int>& degrees, upvec& ddfactors)
1037 cl_modint_ring
R = a[0].ring();
1038 int q = cl_I_to_int(
R->modulus);
1042 umodpoly w = {
R->zero(),
R->one()};
1045 while ( i <= nhalf ) {
1047 expt_pos_Q(w, a, q, buf);
1050 if ( unequal_one(buf) ) {
1051 degrees.push_back(i);
1052 ddfactors.push_back(buf);
1062 if ( unequal_one(a) ) {
1063 degrees.push_back(
degree(a));
1064 ddfactors.push_back(a);
1078static void same_degree_factor(
const umodpoly& a, upvec& upv)
1080 cl_modint_ring
R = a[0].ring();
1082 vector<int> degrees;
1084 distinct_degree_factor(a, degrees, ddfactors);
1086 for (
size_t i=0; i<degrees.size(); ++i ) {
1087 if ( degrees[i] ==
degree(ddfactors[i]) ) {
1088 upv.push_back(ddfactors[i]);
1090 berlekamp(ddfactors[i], upv);
1096#define USE_SAME_DEGREE_FACTOR
1108static void factor_modular(
const umodpoly& p, upvec& upv)
1110#ifdef USE_SAME_DEGREE_FACTOR
1111 same_degree_factor(p, upv);
1125static void exteuclid(
const umodpoly& a,
const umodpoly& b, umodpoly& s, umodpoly& t)
1128 exteuclid(b, a, t, s);
1132 umodpoly
one(1, a[0].ring()->
one());
1133 umodpoly
c = a; normalize_in_field(
c);
1134 umodpoly d = b; normalize_in_field(d);
1142 umodpoly
r =
c - q * d;
1143 umodpoly r1 = s - q * d1;
1144 umodpoly r2 = t - q * d2;
1148 if (
r.empty() )
break;
1153 cl_MI fac = recip(lcoeff(a) * lcoeff(
c));
1154 for (
auto & i : s) {
1158 fac = recip(lcoeff(b) * lcoeff(
c));
1159 for (
auto & i : t) {
1171static upoly replace_lc(
const upoly&
poly,
const cl_I& lc)
1182static inline cl_I calc_bound(
const ex& a,
const ex&
x)
1185 for (
int i=a.degree(
x); i>=a.ldegree(
x); --i ) {
1186 cl_I aa =
abs(the<cl_I>(ex_to<numeric>(a.coeff(
x, i)).to_cl_N()));
1187 radicand = radicand + square(aa);
1189 return ceiling1(the<cl_R>(cln::sqrt(radicand)));
1195static inline cl_I calc_bound(
const upoly& a)
1198 for (
int i=
degree(a); i>=0; --i ) {
1199 cl_I aa =
abs(a[i]);
1200 radicand = radicand + square(aa);
1202 return ceiling1(the<cl_R>(cln::sqrt(radicand)));
1217static void hensel_univar(
const upoly& a_,
unsigned int p,
const umodpoly& u1_,
const umodpoly& w1_, upoly& u, upoly& w)
1220 const cl_modint_ring&
R = u1_[0].ring();
1224 cl_I maxmodulus = ash(calc_bound(a), maxdeg+1);
1227 cl_I alpha = lcoeff(a);
1230 normalize_in_field(nu1);
1232 normalize_in_field(nw1);
1234 phi = umodpoly_to_upoly(nu1) * alpha;
1236 umodpoly_from_upoly(u1, phi,
R);
1237 phi = umodpoly_to_upoly(nw1) * alpha;
1239 umodpoly_from_upoly(w1, phi,
R);
1244 exteuclid(u1, w1, s, t);
1247 u = replace_lc(umodpoly_to_upoly(u1), alpha);
1248 w = replace_lc(umodpoly_to_upoly(w1), alpha);
1249 upoly e = a - u * w;
1253 while ( !e.empty() &&
modulus < maxmodulus ) {
1255 phi = umodpoly_to_upoly(s) *
c;
1256 umodpoly sigmatilde;
1257 umodpoly_from_upoly(sigmatilde, phi,
R);
1258 phi = umodpoly_to_upoly(t) *
c;
1260 umodpoly_from_upoly(tautilde, phi,
R);
1262 remdiv(sigmatilde, w1,
r, q);
1264 phi = umodpoly_to_upoly(tautilde) + umodpoly_to_upoly(q) * umodpoly_to_upoly(u1);
1266 umodpoly_from_upoly(tau, phi,
R);
1267 u = u + umodpoly_to_upoly(tau) *
modulus;
1268 w = w + umodpoly_to_upoly(sigma) *
modulus;
1276 for (
size_t i=1; i<u.size(); ++i ) {
1278 if ( g == 1 )
break;
1297static unsigned int next_prime(
unsigned int n)
1299 static vector<unsigned int> primes = {2, 3, 5, 7};
1300 unsigned int candidate = primes.back();
1301 while (primes.back() <=
n) {
1304 for (
size_t i=1; primes[i]*primes[i]<=candidate; ++i) {
1305 if (candidate % primes[i] == 0) {
1311 primes.push_back(candidate);
1313 for (
auto & it : primes) {
1318 throw logic_error(
"next_prime: should not reach this point!");
1323class factor_partition
1327 factor_partition(
const upvec& factors_) :
factors(factors_)
1333 one.resize(1,
factors.front()[0].ring()->one());
1338 int operator[](
size_t i)
const {
return k[i]; }
1339 size_t size()
const {
return n; }
1340 size_t size_left()
const {
return n-
len; }
1341 size_t size_right()
const {
return len; }
1346 if ( last == n-1 ) {
1356 while ( k[last] == 0 ) { --
last; }
1357 if ( last == 0 && n == 2*len )
return false;
1359 for (
size_t i=0; i<=
len-
rem; ++i ) {
1363 fill(
k.begin()+last,
k.end(), 0);
1370 if ( len > n/2 )
return false;
1371 fill(
k.begin(),
k.begin()+len, 1);
1372 fill(
k.begin()+len+1,
k.end(), 0);
1381 umodpoly& left() {
return lr[0]; }
1383 umodpoly& right() {
return lr[1]; }
1392 while ( i < n && k[i] == group ) { ++d; ++i; }
1394 if ( cache[pos].size() >= d ) {
1395 lr[group] =
lr[group] *
cache[pos][d-1];
1397 if ( cache[pos].size() == 0 ) {
1398 cache[pos].push_back(factors[pos] * factors[pos+1]);
1400 size_t j = pos +
cache[pos].size() + 1;
1401 d -=
cache[pos].size();
1404 cache[pos].push_back(buf);
1408 lr[group] =
lr[group] *
cache[pos].back();
1422 for (
size_t i=0; i<
n; ++i ) {
1457static ex factor_univariate(
const ex&
poly,
const ex&
x,
unsigned int& prime)
1462 upoly_from_ex(prim, prim_ex,
x);
1463 if (prim_ex.is_equal(1)) {
1469 unsigned int lastp = prime;
1471 unsigned int trials = 0;
1472 unsigned int minfactors = 0;
1474 const numeric& cont_n = ex_to<numeric>(
cont);
1476 if (cont_n.is_integer()) {
1477 i_cont = the<cl_I>(cont_n.to_cl_N());
1483 cl_I lc = lcoeff(prim)*i_cont;
1485 while ( trials < 2 ) {
1488 prime = next_prime(prime);
1489 if ( !zerop(
rem(lc, prime)) ) {
1490 R = find_modint_ring(prime);
1491 umodpoly_from_upoly(modpoly, prim,
R);
1492 if ( squarefree(modpoly) )
break;
1498 factor_modular(modpoly, trialfactors);
1499 if ( trialfactors.size() <= 1 ) {
1504 if ( minfactors == 0 || trialfactors.size() < minfactors ) {
1506 minfactors = trialfactors.size();
1514 R = find_modint_ring(prime);
1517 stack<ModFactors> tocheck;
1524 while ( tocheck.size() ) {
1525 const size_t n = tocheck.top().factors.size();
1526 factor_partition part(tocheck.top().factors);
1529 hensel_univar(tocheck.top().poly, prime, part.left(), part.right(), f1, f2);
1530 if ( !f1.empty() ) {
1532 if ( part.size_left() == 1 ) {
1533 if ( part.size_right() == 1 ) {
1534 result *= upoly_to_ex(f1,
x) * upoly_to_ex(f2,
x);
1538 result *= upoly_to_ex(f1,
x);
1539 tocheck.top().poly = f2;
1540 for (
size_t i=0; i<
n; ++i ) {
1541 if ( part[i] == 0 ) {
1542 tocheck.top().factors.erase(tocheck.top().factors.begin()+i);
1548 else if ( part.size_right() == 1 ) {
1549 if ( part.size_left() == 1 ) {
1550 result *= upoly_to_ex(f1,
x) * upoly_to_ex(f2,
x);
1554 result *= upoly_to_ex(f2,
x);
1555 tocheck.top().poly = f1;
1556 for (
size_t i=0; i<
n; ++i ) {
1557 if ( part[i] == 1 ) {
1558 tocheck.top().factors.erase(tocheck.top().factors.begin()+i);
1564 upvec newfactors1(part.size_left()), newfactors2(part.size_right());
1565 auto i1 = newfactors1.begin(), i2 = newfactors2.begin();
1566 for (
size_t i=0; i<
n; ++i ) {
1568 *i2++ = tocheck.top().factors[i];
1570 *i1++ = tocheck.top().factors[i];
1573 tocheck.top().factors = newfactors1;
1574 tocheck.top().poly = f1;
1576 mf.factors = newfactors2;
1583 if ( !part.next() ) {
1586 result *= upoly_to_ex(tocheck.top().poly,
x);
1600static inline ex factor_univariate(
const ex&
poly,
const ex&
x)
1603 return factor_univariate(
poly,
x, prime);
1615ostream&
operator<<(ostream& o,
const vector<EvalPoint>& v)
1617 for (
size_t i=0; i<v.size(); ++i ) {
1618 o <<
"(" << v[i].x <<
"==" << v[i].evalpoint <<
") ";
1625static 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);
1642static upvec multiterm_eea_lift(
const upvec& a,
const ex&
x,
unsigned int p,
unsigned int k)
1644 const size_t r = a.size();
1645 cl_modint_ring
R = find_modint_ring(expt_pos(cl_I(p),
k));
1648 for (
size_t j=
r-2; j>=1; --j ) {
1649 q[j-1] = a[j] * q[j];
1651 umodpoly beta(1,
R->one());
1653 for (
size_t j=1; j<
r; ++j ) {
1654 vector<ex> mdarg(2);
1655 mdarg[0] = umodpoly_to_ex(q[j-1],
x);
1656 mdarg[1] = umodpoly_to_ex(a[j-1],
x);
1657 vector<EvalPoint> empty;
1658 vector<ex> exsigma = multivar_diophant(mdarg,
x, umodpoly_to_ex(beta,
x), empty, 0, p,
k);
1660 umodpoly_from_ex(sigma1, exsigma[0],
x,
R);
1662 umodpoly_from_ex(sigma2, exsigma[1],
x,
R);
1664 s.push_back(sigma2);
1675static void change_modulus(
const cl_modint_ring&
R, umodpoly& a)
1677 if ( a.empty() )
return;
1678 cl_modint_ring oldR = a[0].ring();
1679 for (
auto & i : a) {
1680 i =
R->canonhom(oldR->retract(i));
1699static void eea_lift(
const umodpoly& a,
const umodpoly& b,
const ex&
x,
unsigned int p,
unsigned int k, umodpoly& s_, umodpoly& t_)
1701 cl_modint_ring
R = find_modint_ring(p);
1703 change_modulus(
R, amod);
1705 change_modulus(
R, bmod);
1709 exteuclid(amod, bmod,
smod, tmod);
1711 cl_modint_ring Rpk = find_modint_ring(expt_pos(cl_I(p),
k));
1713 change_modulus(Rpk, s);
1715 change_modulus(Rpk, t);
1718 umodpoly
one(1, Rpk->one());
1719 for (
size_t j=1; j<
k; ++j ) {
1720 umodpoly e =
one - a * s - b * t;
1723 change_modulus(
R,
c);
1724 umodpoly sigmabar =
smod *
c;
1725 umodpoly taubar = tmod *
c;
1727 remdiv(sigmabar, bmod, sigma, q);
1728 umodpoly tau = taubar + q * amod;
1729 umodpoly sadd = sigma;
1730 change_modulus(Rpk, sadd);
1731 cl_MI modmodulus(Rpk,
modulus);
1732 s = s + sadd * modmodulus;
1733 umodpoly tadd = tau;
1734 change_modulus(Rpk, tadd);
1735 t = t + tadd * modmodulus;
1757static upvec univar_diophant(
const upvec& a,
const ex&
x,
unsigned int m,
unsigned int p,
unsigned int k)
1759 cl_modint_ring
R = find_modint_ring(expt_pos(cl_I(p),
k));
1761 const size_t r = a.size();
1764 upvec s = multiterm_eea_lift(a,
x, p,
k);
1765 for (
size_t j=0; j<
r; ++j ) {
1766 umodpoly bmod = umodpoly_to_umodpoly(s[j],
R,
m);
1768 rem(bmod, a[j], buf);
1769 result.push_back(buf);
1773 eea_lift(a[1], a[0],
x, p,
k, s, t);
1774 umodpoly bmod = umodpoly_to_umodpoly(s,
R,
m);
1776 remdiv(bmod, a[0], buf, q);
1777 result.push_back(buf);
1778 umodpoly t1mod = umodpoly_to_umodpoly(t,
R,
m);
1779 buf = t1mod + q * a[1];
1780 result.push_back(buf);
1790struct make_modular_map :
public map_function {
1792 make_modular_map(
const cl_modint_ring& R_) :
R(R_) { }
1793 ex operator()(
const ex& e)
override
1795 if ( is_a<add>(e) || is_a<mul>(e) ) {
1796 return e.map(*
this);
1798 else if ( is_a<numeric>(e) ) {
1799 numeric
mod(
R->modulus);
1800 numeric halfmod = (
mod-1)/2;
1801 cl_MI emod =
R->canonhom(the<cl_I>(ex_to<numeric>(e).to_cl_N()));
1802 numeric
n(
R->retract(emod));
1803 if (
n > halfmod ) {
1820static ex make_modular(
const ex& e,
const cl_modint_ring&
R)
1822 make_modular_map map(
R);
1823 return map(e.expand());
1843static vector<ex> multivar_diophant(
const vector<ex>& a_,
const ex&
x,
const ex&
c,
const vector<EvalPoint>&
I,
1844 unsigned int d,
unsigned int p,
unsigned int k)
1848 const cl_I
modulus = expt_pos(cl_I(p),
k);
1849 const cl_modint_ring
R = find_modint_ring(
modulus);
1850 const size_t r = a.size();
1851 const size_t nu =
I.size() + 1;
1855 ex xnu =
I.back().x;
1856 int alphanu =
I.back().evalpoint;
1859 for (
size_t i=0; i<
r; ++i ) {
1863 for (
size_t i=0; i<
r; ++i ) {
1867 vector<ex> anew = a;
1868 for (
size_t i=0; i<
r; ++i ) {
1869 anew[i] = anew[i].subs(xnu == alphanu);
1871 ex cnew =
c.subs(xnu == alphanu);
1872 vector<EvalPoint> Inew =
I;
1874 sigma = multivar_diophant(anew,
x, cnew, Inew, d, p,
k);
1877 for (
size_t i=0; i<
r; ++i ) {
1878 buf -= sigma[i] * b[i];
1880 ex e = make_modular(buf,
R);
1883 for (
size_t m=1; !e.is_zero() && e.has(xnu) &&
m<=d; ++
m ) {
1884 monomial *= (xnu - alphanu);
1885 monomial =
expand(monomial);
1886 ex cm = e.diff(ex_to<symbol>(xnu),
m).subs(xnu==alphanu) /
factorial(
m);
1887 cm = make_modular(cm,
R);
1888 if ( !cm.is_zero() ) {
1889 vector<ex> delta_s = multivar_diophant(anew,
x, cm, Inew, d, p,
k);
1891 for (
size_t j=0; j<delta_s.size(); ++j ) {
1892 delta_s[j] *= monomial;
1893 sigma[j] += delta_s[j];
1894 buf -= delta_s[j] * b[j];
1896 e = make_modular(buf,
R);
1901 for (
size_t i=0; i<a.size(); ++i ) {
1903 umodpoly_from_ex(up, a[i],
x,
R);
1907 sigma.insert(sigma.begin(),
r, 0);
1910 if ( is_a<add>(
c) ) {
1917 for (
size_t i=0; i<nterms; ++i ) {
1918 int m = z.degree(
x);
1919 cl_I cm = the<cl_I>(ex_to<numeric>(z.lcoeff(
x)).to_cl_N());
1920 upvec delta_s = univar_diophant(amod,
x,
m, p,
k);
1922 cl_I poscm = plusp(cm) ? cm :
mod(cm,
modulus);
1923 modcm = cl_MI(
R, poscm);
1924 for (
size_t j=0; j<delta_s.size(); ++j ) {
1925 delta_s[j] = delta_s[j] * modcm;
1926 sigma[j] = sigma[j] + umodpoly_to_ex(delta_s[j],
x);
1928 if ( nterms > 1 && i+1 != nterms ) {
1934 for (
size_t i=0; i<sigma.size(); ++i ) {
1935 sigma[i] = make_modular(sigma[i],
R);
1957static ex hensel_multivar(
const ex& a,
const ex&
x,
const vector<EvalPoint>&
I,
1958 unsigned int p,
const cl_I& l,
const upvec& u,
const vector<ex>& lcU)
1960 const size_t nu =
I.size() + 1;
1961 const cl_modint_ring
R = find_modint_ring(expt_pos(cl_I(p),l));
1966 for (
size_t j=nu; j>=2; --j ) {
1968 int alpha =
I[j-2].evalpoint;
1969 A[j-2] = A[j-1].
subs(
x==alpha);
1970 A[j-2] = make_modular(A[j-2],
R);
1973 int maxdeg = a.degree(
I.front().x);
1974 for (
size_t i=1; i<
I.size(); ++i ) {
1975 int maxdeg2 = a.degree(
I[i].
x);
1976 if ( maxdeg2 > maxdeg ) maxdeg = maxdeg2;
1979 const size_t n = u.size();
1981 for (
size_t i=0; i<
n; ++i ) {
1982 U[i] = umodpoly_to_ex(u[i],
x);
1985 for (
size_t j=2; j<=nu; ++j ) {
1988 for (
size_t m=0;
m<
n; ++
m) {
1989 if ( lcU[
m] != 1 ) {
1991 for (
size_t i=j-1; i<nu-1; ++i ) {
1994 coef = make_modular(coef,
R);
1995 int deg = U[
m].degree(
x);
1996 U[
m] = U[
m] - U[
m].lcoeff(
x) *
pow(
x,deg) + coef *
pow(
x,deg);
2000 for (
size_t i=0; i<
n; ++i ) {
2003 ex e =
expand(A[j-1] - Uprod);
2005 vector<EvalPoint> newI;
2006 for (
size_t i=1; i<=j-2; ++i ) {
2007 newI.push_back(
I[i-1]);
2011 int alphaj =
I[j-2].evalpoint;
2012 size_t deg = A[j-1].
degree(xj);
2013 for (
size_t k=1;
k<=deg; ++
k ) {
2014 if ( !e.is_zero() ) {
2015 monomial *= (xj - alphaj);
2016 monomial =
expand(monomial);
2017 ex dif = e.diff(ex_to<symbol>(xj),
k);
2019 if ( !
c.is_zero() ) {
2020 vector<ex> deltaU = multivar_diophant(U1,
x,
c, newI, maxdeg, p, cl_I_to_uint(l));
2021 for (
size_t i=0; i<
n; ++i ) {
2022 deltaU[i] *= monomial;
2024 U[i] = make_modular(U[i],
R);
2027 for (
size_t i=0; i<
n; ++i ) {
2031 e = make_modular(e,
R);
2038 for (
size_t i=0; i<U.size(); ++i ) {
2042 return lst(U.begin(), U.end());
2052static exvector put_factors_into_vec(
const ex& e)
2055 if ( is_a<numeric>(e) ) {
2056 result.push_back(e);
2059 if ( is_a<power>(e) ) {
2060 result.push_back(1);
2061 result.push_back(e.op(0));
2064 if ( is_a<symbol>(e) || is_a<add>(e) ) {
2065 ex icont(e.integer_content());
2066 result.push_back(icont);
2067 result.push_back(e/icont);
2070 if ( is_a<mul>(e) ) {
2072 result.push_back(nfac);
2073 for (
size_t i=0; i<e.nops(); ++i ) {
2075 if ( is_a<numeric>(
op) ) {
2078 if ( is_a<power>(
op) ) {
2079 result.push_back(
op.
op(0));
2081 if ( is_a<symbol>(
op) || is_a<add>(
op) ) {
2082 result.push_back(
op);
2088 throw runtime_error(
"put_factors_into_vec: bad term.");
2097static bool checkdivisors(
const exvector& f)
2099 const int k = f.size();
2101 vector<numeric> d(
k);
2102 d[0] = ex_to<numeric>(
abs(f[0]));
2103 for (
int i=1; i<
k; ++i ) {
2104 q = ex_to<numeric>(
abs(f[i]));
2105 for (
int j=i-1; j>=0; --j ) {
2138 numeric&
modulus, ex& u0, vector<numeric>& a)
2147 for (
size_t i=0; i<a.size(); ++i ) {
2150 vnatry = vna.
subs(*s == a[i]);
2152 }
while ( vnatry == 0 );
2154 u0 = u0.
subs(*s == a[i]);
2158 ex g =
gcd(u0, u0.diff(ex_to<symbol>(
x)));
2159 if ( !is_a<numeric>(g) ) {
2162 if ( !is_a<numeric>(
vn) ) {
2165 fnum[0] = fnum[0] * u0.content(
x);
2166 for (
size_t i=1; i<fnum.size(); ++i ) {
2167 if ( !is_a<numeric>(fnum[i]) ) {
2169 for (
size_t j=0; j<a.size(); ++j, ++s ) {
2170 fnum[i] = fnum[i].subs(*s == a[j]);
2174 if ( checkdivisors(fnum) ) {
2184static ex factor_sqrfree(
const ex&
poly);
2188struct factorization_ctx {
2195 ex try_next_evaluation_homomorphism()
2197 constexpr unsigned maxtrials = 3;
2198 vector<numeric> a(
syms_wox.size(), 0);
2200 unsigned int trialcount = 0;
2202 int factor_count = 0;
2203 int min_factor_count = -1;
2209 while ( trialcount < maxtrials ) {
2214 ufac = factor_univariate(u,
x, prime);
2215 ufaclst = put_factors_into_vec(ufac);
2216 factor_count = ufaclst.size()-1;
2219 if ( factor_count <= 1 ) {
2223 if ( min_factor_count < 0 ) {
2225 min_factor_count = factor_count;
2227 else if ( min_factor_count == factor_count ) {
2231 else if ( min_factor_count > factor_count ) {
2233 min_factor_count = factor_count;
2239 vector<ex> C(factor_count);
2240 if ( is_a<numeric>(
vn) ) {
2242 for (
size_t i=1; i<ufaclst.size(); ++i ) {
2243 C[i-1] = ufaclst[i].lcoeff(
x);
2250 vector<numeric> ftilde(
vnlst.size()-1);
2251 for (
size_t i=0; i<ftilde.size(); ++i ) {
2254 for (
size_t j=0; j<a.size(); ++j ) {
2255 ft = ft.subs(*s == a[j]);
2258 ftilde[i] = ex_to<numeric>(ft);
2261 vector<bool> used_flag(ftilde.size(),
false);
2262 vector<ex> D(factor_count, 1);
2264 for (
int i=0; i<factor_count; ++i ) {
2265 numeric prefac = ex_to<numeric>(ufaclst[i+1].lcoeff(
x));
2266 for (
int j=ftilde.size()-1; j>=0; --j ) {
2269 while (
irem(prefac, ftilde[j], q) == 0 ) {
2274 used_flag[j] =
true;
2275 D[i] = D[i] *
pow(
vnlst[j+1], count);
2278 C[i] = D[i] * prefac;
2281 for (
int i=0; i<factor_count; ++i ) {
2282 numeric prefac = ex_to<numeric>(ufaclst[i+1].lcoeff(
x));
2283 for (
int j=ftilde.size()-1; j>=0; --j ) {
2286 while (
irem(prefac, ftilde[j], q) == 0 ) {
2290 while (
irem(ex_to<numeric>(delta)*prefac, ftilde[j]) == 0 ) {
2291 numeric g =
gcd(prefac, ex_to<numeric>(ftilde[j]));
2292 prefac =
iquo(prefac, g);
2293 delta = delta / (ftilde[j]/g);
2294 ufaclst[i+1] = ufaclst[i+1] * (ftilde[j]/g);
2298 used_flag[j] =
true;
2299 D[i] = D[i] *
pow(
vnlst[j+1], count);
2302 C[i] = D[i] * prefac;
2306 bool some_factor_unused =
false;
2307 for (
size_t i=0; i<used_flag.size(); ++i ) {
2308 if ( !used_flag[i] ) {
2309 some_factor_unused =
true;
2313 if ( some_factor_unused ) {
2321 C[0] = C[0] * delta;
2322 ufaclst[1] = ufaclst[1] * delta;
2326 vector<EvalPoint> epv;
2328 for (
size_t i=0; i<a.size(); ++i ) {
2329 epv.emplace_back(EvalPoint{*s++, a[i].to_int()});
2334 for (
int i=1; i<=factor_count; ++i ) {
2335 if ( ufaclst[i].
degree(
x) > maxdeg ) {
2336 maxdeg = ufaclst[i].degree(
x);
2339 cl_I B = ash(calc_bound(u,
x), maxdeg+1);
2348 cl_modint_ring
R = find_modint_ring(pl);
2349 upvec modfactors(ufaclst.size()-1);
2350 for (
size_t i=1; i<ufaclst.size(); ++i ) {
2351 umodpoly_from_ex(modfactors[i-1], ufaclst[i],
x,
R);
2355 return hensel_multivar(
pp,
x, epv, prime, l, modfactors, C);
2374static ex factor_multivariate(
const ex&
poly,
const exset&
syms)
2377 vector<factorization_ctx> ctx_in_x;
2378 for (
auto x :
syms) {
2387 if ( !is_a<numeric>(ctx.cont) ) {
2389 return ctx.unit * factor_sqrfree(ctx.cont) * factor_sqrfree(ctx.pp);
2393 ctx.vn = ctx.pp.collect(
x).lcoeff(
x);
2394 ctx.vnlst = put_factors_into_vec(
factor(ctx.vn));
2396 ctx.modulus = (ctx.vnlst.size() > 3) ? ctx.vnlst.size() : numeric(3);
2398 ctx_in_x.push_back(ctx);
2402 auto ctx = ctx_in_x.begin();
2405 ex res = ctx->try_next_evaluation_homomorphism();
2407 if ( res !=
lst{} ) {
2409 ex result = ctx->cont * ctx->unit;
2410 for (
size_t i=0; i<res.nops(); ++i ) {
2419 if (++ctx == ctx_in_x.end()) {
2420 ctx = ctx_in_x.
begin();
2427struct find_symbols_map :
public map_function {
2429 ex operator()(
const ex& e)
override
2431 if ( is_a<symbol>(e) ) {
2435 return e.map(*
this);
2442static ex factor_sqrfree(
const ex&
poly)
2445 find_symbols_map findsymbols;
2447 if ( findsymbols.syms.size() == 0 ) {
2451 if ( findsymbols.syms.size() == 1 ) {
2453 const ex&
x = *(findsymbols.syms.begin());
2458 return res *
pow(
x,ld);
2460 ex res = factor_univariate(
poly,
x);
2466 ex res = factor_multivariate(
poly, findsymbols.syms);
2473struct apply_factor_map :
public map_function {
2475 apply_factor_map(
unsigned options_) :
options(options_) { }
2476 ex operator()(
const ex& e)
override
2479 return factor(e, options);
2481 if ( is_a<add>(e) ) {
2483 for (
size_t i=0; i<e.nops(); ++i ) {
2490 return factor(s1, options) + s2.
map(*
this);
2492 return e.
map(*
this);
2502template <
typename F>
void
2503factor_iter(
const ex &e, F yield)
2506 for (
const auto &f : e) {
2507 if (is_a<power>(f)) {
2508 yield(f.op(0), f.op(1));
2514 if (is_a<power>(e)) {
2515 yield(e.op(0), e.op(1));
2530static ex factor1(
const ex&
poly,
unsigned options)
2535 options &= ~factor_options::all;
2536 apply_factor_map factor_map(
options);
2537 return factor_map(
poly);
2543 find_symbols_map findsymbols;
2545 if ( findsymbols.syms.size() == 0 ) {
2549 for (
auto & i : findsymbols.
syms ) {
2559 [&](
const ex &f,
const ex &
k) {
2560 if ( is_a<add>(f) ) {
2561 res *=
pow(factor_sqrfree(f),
k);
2579 [&](
const ex &f1,
const ex &k1) {
2580 factor_iter(factor1(f1,
options),
2581 [&](
const ex &f2,
const ex &k2) {
2582 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.