GiNaC 1.8.10
factor.cpp
Go to the documentation of this file.
1
35/*
36 * GiNaC Copyright (C) 1999-2026 Johannes Gutenberg University Mainz, Germany
37 *
38 * This program is free software; you can redistribute it and/or modify
39 * it under the terms of the GNU General Public License as published by
40 * the Free Software Foundation; either version 2 of the License, or
41 * (at your option) any later version.
42 *
43 * This program is distributed in the hope that it will be useful,
44 * but WITHOUT ANY WARRANTY; without even the implied warranty of
45 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46 * GNU General Public License for more details.
47 *
48 * You should have received a copy of the GNU General Public License
49 * along with this program. If not, see <https://www.gnu.org/licenses/>.
50 */
51
52//#define DEBUGFACTOR
53
54#include "factor.h"
55
56#include "ex.h"
57#include "numeric.h"
58#include "operators.h"
59#include "inifcns.h"
60#include "symbol.h"
61#include "relational.h"
62#include "power.h"
63#include "mul.h"
64#include "normal.h"
65#include "add.h"
66
67#include <type_traits>
68#include <algorithm>
69#include <limits>
70#include <list>
71#include <vector>
72#include <stack>
73#ifdef DEBUGFACTOR
74#include <ostream>
75#endif
76using namespace std;
77
78#include <cln/cln.h>
79using namespace cln;
80
81namespace GiNaC {
82
83// anonymous namespace to hide all utility functions
84namespace {
85
86#ifdef DEBUGFACTOR
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)
91{
92 auto i = v.begin(), end = v.end();
93 while ( i != end ) {
94 o << *i << " ";
95 ++i;
96 }
97 return o;
98}
99static ostream& operator<<(ostream& o, const vector<cl_I>& v)
100{
101 auto i = v.begin(), end = v.end();
102 while ( i != end ) {
103 o << *i << "[" << i-v.begin() << "]" << " ";
104 ++i;
105 }
106 return o;
107}
108static ostream& operator<<(ostream& o, const vector<cl_MI>& v)
109{
110 auto i = v.begin(), end = v.end();
111 while ( i != end ) {
112 o << *i << "[" << i-v.begin() << "]" << " ";
113 ++i;
114 }
115 return o;
116}
117ostream& operator<<(ostream& o, const vector<numeric>& v)
118{
119 for ( size_t i=0; i<v.size(); ++i ) {
120 o << v[i] << " ";
121 }
122 return o;
123}
124ostream& operator<<(ostream& o, const vector<vector<cl_MI>>& v)
125{
126 auto i = v.begin(), end = v.end();
127 while ( i != end ) {
128 o << i-v.begin() << ": " << *i << endl;
129 ++i;
130 }
131 return o;
132}
133#else
134#define DCOUT(str)
135#define DCOUTVAR(var)
136#define DCOUT2(str,var)
137#endif // def DEBUGFACTOR
138
140// modular univariate polynomial code
141
142typedef std::vector<cln::cl_MI> umodpoly;
143typedef std::vector<cln::cl_I> upoly;
144typedef vector<umodpoly> upvec;
145
146
147// COPY FROM UPOLY.H
148
149// CHANGED size_t -> int !!!
150template<typename T> static int degree(const T& p)
151{
152 return p.size() - 1;
153}
154
155template<typename T> static typename T::value_type lcoeff(const T& p)
156{
157 return p[p.size() - 1];
158}
159
165static bool normalize_in_field(umodpoly& a)
166{
167 if (a.size() == 0)
168 return true;
169 if ( lcoeff(a) == a[0].ring()->one() ) {
170 return true;
171 }
172
173 const cln::cl_MI lc_1 = recip(lcoeff(a));
174 for (std::size_t k = a.size(); k-- != 0; )
175 a[k] = a[k]*lc_1;
176 return false;
177}
178
184template<typename T> static void
185canonicalize(T& p, const typename T::size_type hint = std::numeric_limits<typename T::size_type>::max())
186{
187 std::size_t i = min(p.size(), hint);
188
189 while ( i-- && zerop(p[i]) ) { }
190
191 p.erase(p.begin() + i + 1, p.end());
192}
193
194// END COPY FROM UPOLY.H
195
196template<typename T> struct uvar_poly_p
197{
198 static const bool value = false;
199};
200
201template<> struct uvar_poly_p<upoly>
202{
203 static const bool value = true;
204};
205
206template<> struct uvar_poly_p<umodpoly>
207{
208 static const bool value = true;
209};
210
211template<typename T>
212// Don't define this for anything but univariate polynomials.
213static typename enable_if<uvar_poly_p<T>::value, T>::type
214operator+(const T& a, const T& b)
215{
216 int sa = a.size();
217 int sb = b.size();
218 if ( sa >= sb ) {
219 T r(sa);
220 int i = 0;
221 for ( ; i<sb; ++i ) {
222 r[i] = a[i] + b[i];
223 }
224 for ( ; i<sa; ++i ) {
225 r[i] = a[i];
226 }
228 return r;
229 }
230 else {
231 T r(sb);
232 int i = 0;
233 for ( ; i<sa; ++i ) {
234 r[i] = a[i] + b[i];
235 }
236 for ( ; i<sb; ++i ) {
237 r[i] = b[i];
238 }
240 return r;
241 }
242}
243
244template<typename T>
245// Don't define this for anything but univariate polynomials. Otherwise
246// overload resolution might fail (this actually happens when compiling
247// GiNaC with g++ 3.4).
248static typename enable_if<uvar_poly_p<T>::value, T>::type
249operator-(const T& a, const T& b)
250{
251 int sa = a.size();
252 int sb = b.size();
253 if ( sa >= sb ) {
254 T r(sa);
255 int i = 0;
256 for ( ; i<sb; ++i ) {
257 r[i] = a[i] - b[i];
258 }
259 for ( ; i<sa; ++i ) {
260 r[i] = a[i];
261 }
263 return r;
264 }
265 else {
266 T r(sb);
267 int i = 0;
268 for ( ; i<sa; ++i ) {
269 r[i] = a[i] - b[i];
270 }
271 for ( ; i<sb; ++i ) {
272 r[i] = -b[i];
273 }
275 return r;
276 }
277}
278
279static upoly operator*(const upoly& a, const upoly& b)
280{
281 upoly c;
282 if ( a.empty() || b.empty() ) return c;
283
284 int n = degree(a) + degree(b);
285 c.resize(n+1, 0);
286 for ( int i=0 ; i<=n; ++i ) {
287 for ( int j=0 ; j<=i; ++j ) {
288 if ( j > degree(a) || (i-j) > degree(b) ) continue;
289 c[i] = c[i] + a[j] * b[i-j];
290 }
291 }
293 return c;
294}
295
296static umodpoly operator*(const umodpoly& a, const umodpoly& b)
297{
298 umodpoly c;
299 if ( a.empty() || b.empty() ) return c;
300
301 int n = degree(a) + degree(b);
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 ) {
305 if ( j > degree(a) || (i-j) > degree(b) ) continue;
306 c[i] = c[i] + a[j] * b[i-j];
307 }
308 }
310 return c;
311}
312
313static upoly operator*(const upoly& a, const cl_I& x)
314{
315 if ( zerop(x) ) {
316 upoly r;
317 return r;
318 }
319 upoly r(a.size());
320 for ( size_t i=0; i<a.size(); ++i ) {
321 r[i] = a[i] * x;
322 }
323 return r;
324}
325
326static upoly operator/(const upoly& a, const cl_I& x)
327{
328 if ( zerop(x) ) {
329 upoly r;
330 return r;
331 }
332 upoly r(a.size());
333 for ( size_t i=0; i<a.size(); ++i ) {
334 r[i] = exquo(a[i],x);
335 }
336 return r;
337}
338
339static umodpoly operator*(const umodpoly& a, const cl_MI& x)
340{
341 umodpoly r(a.size());
342 for ( size_t i=0; i<a.size(); ++i ) {
343 r[i] = a[i] * x;
344 }
346 return r;
347}
348
349static void upoly_from_ex(upoly& up, const ex& e, const ex& x)
350{
351 // assert: e is in Z[x]
352 int deg = e.degree(x);
353 up.resize(deg+1);
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());
357 }
358 for ( ; deg>=0; --deg ) {
359 up[deg] = 0;
360 }
361 canonicalize(up);
362}
363
364static void umodpoly_from_upoly(umodpoly& ump, const upoly& e, const cl_modint_ring& R)
365{
366 int deg = degree(e);
367 ump.resize(deg+1);
368 for ( ; deg>=0; --deg ) {
369 ump[deg] = R->canonhom(e[deg]);
370 }
371 canonicalize(ump);
372}
373
374static void umodpoly_from_ex(umodpoly& ump, const ex& e, const ex& x, const cl_modint_ring& R)
375{
376 // assert: e is in Z[x]
377 int deg = e.degree(x);
378 ump.resize(deg+1);
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);
383 }
384 for ( ; deg>=0; --deg ) {
385 ump[deg] = R->zero();
386 }
387 canonicalize(ump);
388}
389
390#ifdef DEBUGFACTOR
391static void umodpoly_from_ex(umodpoly& ump, const ex& e, const ex& x, const cl_I& modulus)
392{
393 umodpoly_from_ex(ump, e, x, find_modint_ring(modulus));
394}
395#endif
396
397static ex upoly_to_ex(const upoly& a, const ex& x)
398{
399 if ( a.empty() ) return 0;
400 ex e;
401 for ( int i=degree(a); i>=0; --i ) {
402 e += numeric(a[i]) * pow(x, i);
403 }
404 return e;
405}
406
407static ex umodpoly_to_ex(const umodpoly& a, const ex& x)
408{
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;
413 ex e;
414 for ( int i=degree(a); i>=0; --i ) {
415 cl_I n = R->retract(a[i]);
416 if ( n > halfmod ) {
417 e += numeric(n-mod) * pow(x, i);
418 } else {
419 e += numeric(n) * pow(x, i);
420 }
421 }
422 return e;
423}
424
425static upoly umodpoly_to_upoly(const umodpoly& a)
426{
427 upoly e(a.size());
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]);
434 if ( n > halfmod ) {
435 e[i] = n-mod;
436 } else {
437 e[i] = n;
438 }
439 }
440 return e;
441}
442
443static umodpoly umodpoly_to_umodpoly(const umodpoly& a, const cl_modint_ring& R, unsigned int m)
444{
445 umodpoly e;
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]));
452 }
453 canonicalize(e);
454 return e;
455}
456
464static void reduce_coeff(umodpoly& a, const cl_I& x)
465{
466 if ( a.empty() ) return;
467
468 cl_modint_ring R = a[0].ring();
469 for (auto & i : a) {
470 // cln cannot perform this division in the modular field
471 cl_I c = R->retract(i);
472 i = cl_MI(R, exquopos(c, x));
473 }
474}
475
483static void rem(const umodpoly& a, const umodpoly& b, umodpoly& r)
484{
485 int k, n;
486 n = degree(b);
487 k = degree(a) - n;
488 r = a;
489 if ( k < 0 ) return;
490
491 do {
492 cl_MI qk = div(r[n+k], b[n]);
493 if ( !zerop(qk) ) {
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];
497 }
498 }
499 } while ( k-- );
500
501 fill(r.begin()+n, r.end(), a[0].ring()->zero());
502 canonicalize(r, n);
503}
504
512static void div(const umodpoly& a, const umodpoly& b, umodpoly& q)
513{
514 int k, n;
515 n = degree(b);
516 k = degree(a) - n;
517 q.clear();
518 if ( k < 0 ) return;
519
520 umodpoly r = a;
521 q.resize(k+1, a[0].ring()->zero());
522 do {
523 cl_MI qk = div(r[n+k], b[n]);
524 if ( !zerop(qk) ) {
525 q[k] = qk;
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];
529 }
530 }
531 } while ( k-- );
532
533 canonicalize(q);
534}
535
544static void remdiv(const umodpoly& a, const umodpoly& b, umodpoly& r, umodpoly& q)
545{
546 int k, n;
547 n = degree(b);
548 k = degree(a) - n;
549 q.clear();
550 r = a;
551 if ( k < 0 ) return;
552
553 q.resize(k+1, a[0].ring()->zero());
554 do {
555 cl_MI qk = div(r[n+k], b[n]);
556 if ( !zerop(qk) ) {
557 q[k] = qk;
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];
561 }
562 }
563 } while ( k-- );
564
565 fill(r.begin()+n, r.end(), a[0].ring()->zero());
567 canonicalize(q);
568}
569
576static void gcd(const umodpoly& a, const umodpoly& b, umodpoly& c)
577{
578 if ( degree(a) < degree(b) ) return gcd(b, a, c);
579
580 c = a;
581 normalize_in_field(c);
582 umodpoly d = b;
583 normalize_in_field(d);
584 umodpoly r;
585 while ( !d.empty() ) {
586 rem(c, d, r);
587 c = d;
588 d = r;
589 }
590 normalize_in_field(c);
591}
592
598static void deriv(const umodpoly& a, umodpoly& d)
599{
600 d.clear();
601 if ( a.size() <= 1 ) return;
602
603 d.insert(d.begin(), a.begin()+1, a.end());
604 int max = d.size();
605 for ( int i=1; i<max; ++i ) {
606 d[i] = d[i] * (i+1);
607 }
608 canonicalize(d);
609}
610
611static bool unequal_one(const umodpoly& a)
612{
613 return ( a.size() != 1 || a[0] != a[0].ring()->one() );
614}
615
616static bool equal_one(const umodpoly& a)
617{
618 return ( a.size() == 1 && a[0] == a[0].ring()->one() );
619}
620
626static bool squarefree(const umodpoly& a)
627{
628 umodpoly b;
629 deriv(a, b);
630 if ( b.empty() ) {
631 return false;
632 }
633 umodpoly c;
634 gcd(a, b, c);
635 return equal_one(c);
636}
637
646static void expt_pos_Q(const umodpoly& w, const umodpoly& a, unsigned int q, umodpoly& r)
647{
648 if ( w.empty() ) return;
649 cl_MI zero = w[0].ring()->zero();
650 int deg = degree(w);
651 umodpoly buf(deg*q+1, zero);
652 for ( size_t i=0; i<=deg; ++i ) {
653 buf[i*q] = w[i];
654 }
655 rem(buf, a, r);
656}
657
658// END modular univariate polynomial code
660
662// modular matrix
663
664typedef vector<cl_MI> mvec;
665
666class modular_matrix
667{
668#ifdef DEBUGFACTOR
669 friend ostream& operator<<(ostream& o, const modular_matrix& m);
670#endif
671public:
672 modular_matrix(size_t r_, size_t c_, const cl_MI& init) : r(r_), c(c_)
673 {
674 m.resize(c*r, init);
675 }
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)
681 {
682 for ( size_t rc=0; rc<r; ++rc ) {
683 std::size_t i = c*rc + col;
684 m[i] = m[i] * x;
685 }
686 }
687 void sub_col(size_t col1, size_t col2, const cl_MI fac)
688 {
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;
693 }
694 }
695 void switch_col(size_t col1, size_t col2)
696 {
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;
700 std::swap(m[i1], m[i2]);
701 }
702 }
703 void mul_row(size_t row, const cl_MI x)
704 {
705 for ( size_t cc=0; cc<c; ++cc ) {
706 std::size_t i = row*c + cc;
707 m[i] = m[i] * x;
708 }
709 }
710 void sub_row(size_t row1, size_t row2, const cl_MI fac)
711 {
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;
716 }
717 }
718 void switch_row(size_t row1, size_t row2)
719 {
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;
723 std::swap(m[i1], m[i2]);
724 }
725 }
726 bool is_col_zero(size_t col) const
727 {
728 for ( size_t rr=0; rr<r; ++rr ) {
729 std::size_t i = col + rr*c;
730 if ( !zerop(m[i]) ) {
731 return false;
732 }
733 }
734 return true;
735 }
736 bool is_row_zero(size_t row) const
737 {
738 for ( size_t cc=0; cc<c; ++cc ) {
739 std::size_t i = row*c + cc;
740 if ( !zerop(m[i]) ) {
741 return false;
742 }
743 }
744 return true;
745 }
746 void set_row(size_t row, const vector<cl_MI>& newrow)
747 {
748 for (std::size_t i2 = 0; i2 < newrow.size(); ++i2) {
749 std::size_t i1 = row*c + i2;
750 m[i1] = newrow[i2];
751 }
752 }
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; }
755private:
756 size_t r, c;
757 mvec m;
758};
759
760#ifdef DEBUGFACTOR
761modular_matrix operator*(const modular_matrix& m1, const modular_matrix& m2)
762{
763 const unsigned int r = m1.rowsize();
764 const unsigned int c = m2.colsize();
765 modular_matrix o(r,c,m1(0,0));
766
767 for ( size_t i=0; i<r; ++i ) {
768 for ( size_t j=0; j<c; ++j ) {
769 cl_MI buf;
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);
773 }
774 o(i,j) = buf;
775 }
776 }
777 return o;
778}
779
780ostream& operator<<(ostream& o, const modular_matrix& m)
781{
782 cl_modint_ring R = m(0,0).ring();
783 o << "{";
784 for ( size_t i=0; i<m.rowsize(); ++i ) {
785 o << "{";
786 for ( size_t j=0; j<m.colsize()-1; ++j ) {
787 o << R->retract(m(i,j)) << ",";
788 }
789 o << R->retract(m(i,m.colsize()-1)) << "}";
790 if ( i != m.rowsize()-1 ) {
791 o << ",";
792 }
793 }
794 o << "}";
795 return o;
796}
797#endif // def DEBUGFACTOR
798
799// END modular matrix
801
809static void q_matrix(const umodpoly& a_, modular_matrix& Q)
810{
811 umodpoly a = a_;
812 normalize_in_field(a);
813
814 int n = degree(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();
818 Q.set_row(0, r);
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]);
824 }
825 r[0] = -rn_1 * a[0];
826 if ( (m % q) == 0 ) {
827 Q.set_row(m/q, r);
828 }
829 }
830}
831
837static void nullspace(modular_matrix& M, vector<mvec>& basis)
838{
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;
843 }
844 for ( size_t r=0; r<n; ++r ) {
845 size_t cc = 0;
846 for ( ; cc<n; ++cc ) {
847 if ( !zerop(M(r,cc)) ) {
848 if ( cc < r ) {
849 if ( !zerop(M(cc,cc)) ) {
850 continue;
851 }
852 M.switch_col(cc, r);
853 }
854 else if ( cc > r ) {
855 M.switch_col(cc, r);
856 }
857 break;
858 }
859 }
860 if ( cc < n ) {
861 M.mul_col(r, recip(M(r,r)));
862 for ( cc=0; cc<n; ++cc ) {
863 if ( cc != r ) {
864 M.sub_col(cc, r, M(r,cc));
865 }
866 }
867 }
868 }
869
870 for ( size_t i=0; i<n; ++i ) {
871 M(i,i) = M(i,i) - one;
872 }
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));
876 basis.push_back(nu);
877 }
878 }
879}
880
889static void berlekamp(const umodpoly& a, upvec& upv)
890{
891 cl_modint_ring R = a[0].ring();
892 umodpoly one(1, R->one());
893
894 // find nullspace of Q matrix
895 modular_matrix Q(degree(a), degree(a), R->zero());
896 q_matrix(a, Q);
897 vector<mvec> nu;
898 nullspace(Q, nu);
899
900 const unsigned int k = nu.size();
901 if ( k == 1 ) {
902 // irreducible
903 return;
904 }
905
906 list<umodpoly> factors = {a};
907 unsigned int size = 1;
908 unsigned int r = 1;
909 unsigned int q = cl_I_to_uint(R->modulus);
910
911 list<umodpoly>::iterator u = factors.begin();
912
913 // calculate all gcd's
914 while ( true ) {
915 for ( unsigned int s=0; s<q; ++s ) {
916 umodpoly nur = nu[r];
917 nur[0] = nur[0] - cl_MI(R, s);
918 canonicalize(nur);
919 umodpoly g;
920 gcd(nur, *u, g);
921 if ( unequal_one(g) && g != *u ) {
922 umodpoly uo;
923 div(*u, g, uo);
924 if ( equal_one(uo) ) {
925 throw logic_error("berlekamp: unexpected divisor.");
926 } else {
927 *u = uo;
928 }
929 factors.push_back(g);
930 size = 0;
931 for (auto & i : factors) {
932 if (degree(i))
933 ++size;
934 }
935 if ( size == k ) {
936 for (auto & i : factors) {
937 upv.push_back(i);
938 }
939 return;
940 }
941 }
942 }
943 if ( ++r == k ) {
944 r = 1;
945 ++u;
946 }
947 }
948}
949
950// modular square free factorization is not used at the moment so we deactivate
951// the code
952#if 0
953
960static void expt_1_over_p(const umodpoly& a, unsigned int prime, umodpoly& ap)
961{
962 size_t newdeg = degree(a)/prime;
963 ap.resize(newdeg+1);
964 ap[0] = a[0];
965 for ( size_t i=1; i<=newdeg; ++i ) {
966 ap[i] = a[i*prime];
967 }
968}
969
976static void modsqrfree(const umodpoly& a, upvec& factors, vector<int>& mult)
977{
978 const unsigned int prime = cl_I_to_uint(a[0].ring()->modulus);
979 int i = 1;
980 umodpoly b;
981 deriv(a, b);
982 if ( b.size() ) {
983 umodpoly c;
984 gcd(a, b, c);
985 umodpoly w;
986 div(a, c, w);
987 while ( unequal_one(w) ) {
988 umodpoly y;
989 gcd(w, c, y);
990 umodpoly z;
991 div(w, y, z);
992 factors.push_back(z);
993 mult.push_back(i);
994 ++i;
995 w = y;
996 umodpoly buf;
997 div(c, y, buf);
998 c = buf;
999 }
1000 if ( unequal_one(c) ) {
1001 umodpoly cp;
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 ) {
1006 mult[i] *= prime;
1007 }
1008 }
1009 } else {
1010 umodpoly ap;
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 ) {
1015 mult[i] *= prime;
1016 }
1017 }
1018}
1019
1020#endif // deactivation of square free factorization
1021
1032static void distinct_degree_factor(const umodpoly& a_, vector<int>& degrees, upvec& ddfactors)
1033{
1034 umodpoly a = a_;
1035
1036 cl_modint_ring R = a[0].ring();
1037 int q = cl_I_to_int(R->modulus);
1038 int nhalf = degree(a)/2;
1039
1040 int i = 1;
1041 umodpoly w = {R->zero(), R->one()};
1042 umodpoly x = w;
1043
1044 while ( i <= nhalf ) {
1045 umodpoly buf;
1046 expt_pos_Q(w, a, q, buf);
1047 w = buf;
1048 gcd(a, w - x, buf);
1049 if ( unequal_one(buf) ) {
1050 degrees.push_back(i);
1051 ddfactors.push_back(buf);
1052 umodpoly buf2;
1053 div(a, buf, buf2);
1054 a = buf2;
1055 nhalf = degree(a)/2;
1056 rem(w, a, buf);
1057 w = buf;
1058 }
1059 ++i;
1060 }
1061 if ( unequal_one(a) ) {
1062 degrees.push_back(degree(a));
1063 ddfactors.push_back(a);
1064 }
1065}
1066
1077static void same_degree_factor(const umodpoly& a, upvec& upv)
1078{
1079 cl_modint_ring R = a[0].ring();
1080
1081 vector<int> degrees;
1082 upvec ddfactors;
1083 distinct_degree_factor(a, degrees, ddfactors);
1084
1085 for ( size_t i=0; i<degrees.size(); ++i ) {
1086 if ( degrees[i] == degree(ddfactors[i]) ) {
1087 upv.push_back(ddfactors[i]);
1088 } else {
1089 berlekamp(ddfactors[i], upv);
1090 }
1091 }
1092}
1093
1094// Yes, we can (choose).
1095#define USE_SAME_DEGREE_FACTOR
1096
1107static void factor_modular(const umodpoly& p, upvec& upv)
1108{
1109#ifdef USE_SAME_DEGREE_FACTOR
1110 same_degree_factor(p, upv);
1111#else
1112 berlekamp(p, upv);
1113#endif
1114}
1115
1124static void exteuclid(const umodpoly& a, const umodpoly& b, umodpoly& s, umodpoly& t)
1125{
1126 if ( degree(a) < degree(b) ) {
1127 exteuclid(b, a, t, s);
1128 return;
1129 }
1130
1131 umodpoly one(1, a[0].ring()->one());
1132 umodpoly c = a; normalize_in_field(c);
1133 umodpoly d = b; normalize_in_field(d);
1134 s = one;
1135 t.clear();
1136 umodpoly d1;
1137 umodpoly d2 = one;
1138 umodpoly q;
1139 while ( true ) {
1140 div(c, d, q);
1141 umodpoly r = c - q * d;
1142 umodpoly r1 = s - q * d1;
1143 umodpoly r2 = t - q * d2;
1144 c = d;
1145 s = d1;
1146 t = d2;
1147 if ( r.empty() ) break;
1148 d = r;
1149 d1 = r1;
1150 d2 = r2;
1151 }
1152 cl_MI fac = recip(lcoeff(a) * lcoeff(c));
1153 for (auto & i : s) {
1154 i = i * fac;
1155 }
1156 canonicalize(s);
1157 fac = recip(lcoeff(b) * lcoeff(c));
1158 for (auto & i : t) {
1159 i = i * fac;
1160 }
1161 canonicalize(t);
1162}
1163
1170static upoly replace_lc(const upoly& poly, const cl_I& lc)
1171{
1172 if ( poly.empty() ) return poly;
1173 upoly r = poly;
1174 r.back() = lc;
1175 return r;
1176}
1177
1181static inline cl_I calc_bound(const ex& a, const ex& x)
1182{
1183 cl_R radicand = 0;
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);
1187 }
1188 return ceiling1(the<cl_R>(cln::sqrt(radicand)));
1189}
1190
1194static inline cl_I calc_bound(const upoly& a)
1195{
1196 cl_R radicand = 0;
1197 for ( int i=degree(a); i>=0; --i ) {
1198 cl_I aa = abs(a[i]);
1199 radicand = radicand + square(aa);
1200 }
1201 return ceiling1(the<cl_R>(cln::sqrt(radicand)));
1202}
1203
1216static void hensel_univar(const upoly& a_, unsigned int p, const umodpoly& u1_, const umodpoly& w1_, upoly& u, upoly& w)
1217{
1218 upoly a = a_;
1219 const cl_modint_ring& R = u1_[0].ring();
1220
1221 // calc bound B
1222 int maxdeg = (degree(u1_) > degree(w1_)) ? degree(u1_) : degree(w1_);
1223 cl_I maxmodulus = ash(calc_bound(a), maxdeg+1); // = 2 * calc_bound(a) * 2^maxdeg
1224
1225 // step 1
1226 cl_I alpha = lcoeff(a);
1227 a = a * alpha;
1228 umodpoly nu1 = u1_;
1229 normalize_in_field(nu1);
1230 umodpoly nw1 = w1_;
1231 normalize_in_field(nw1);
1232 upoly phi;
1233 phi = umodpoly_to_upoly(nu1) * alpha;
1234 umodpoly u1;
1235 umodpoly_from_upoly(u1, phi, R);
1236 phi = umodpoly_to_upoly(nw1) * alpha;
1237 umodpoly w1;
1238 umodpoly_from_upoly(w1, phi, R);
1239
1240 // step 2
1241 umodpoly s;
1242 umodpoly t;
1243 exteuclid(u1, w1, s, t);
1244
1245 // step 3
1246 u = replace_lc(umodpoly_to_upoly(u1), alpha);
1247 w = replace_lc(umodpoly_to_upoly(w1), alpha);
1248 upoly e = a - u * w;
1249 cl_I modulus = p;
1250
1251 // step 4
1252 while ( !e.empty() && modulus < maxmodulus ) {
1253 upoly c = e / modulus;
1254 phi = umodpoly_to_upoly(s) * c;
1255 umodpoly sigmatilde;
1256 umodpoly_from_upoly(sigmatilde, phi, R);
1257 phi = umodpoly_to_upoly(t) * c;
1258 umodpoly tautilde;
1259 umodpoly_from_upoly(tautilde, phi, R);
1260 umodpoly r, q;
1261 remdiv(sigmatilde, w1, r, q);
1262 umodpoly sigma = r;
1263 phi = umodpoly_to_upoly(tautilde) + umodpoly_to_upoly(q) * umodpoly_to_upoly(u1);
1264 umodpoly tau;
1265 umodpoly_from_upoly(tau, phi, R);
1266 u = u + umodpoly_to_upoly(tau) * modulus;
1267 w = w + umodpoly_to_upoly(sigma) * modulus;
1268 e = a - u * w;
1269 modulus = modulus * p;
1270 }
1271
1272 // step 5
1273 if ( e.empty() ) {
1274 cl_I g = u[0];
1275 for ( size_t i=1; i<u.size(); ++i ) {
1276 g = gcd(g, u[i]);
1277 if ( g == 1 ) break;
1278 }
1279 if ( g != 1 ) {
1280 u = u / g;
1281 w = w * g;
1282 }
1283 if ( alpha != 1 ) {
1284 w = w / alpha;
1285 }
1286 } else {
1287 u.clear();
1288 }
1289}
1290
1296static unsigned int next_prime(unsigned int n)
1297{
1298 static vector<unsigned int> primes = {2, 3, 5, 7};
1299 unsigned int candidate = primes.back();
1300 while (primes.back() <= n) {
1301 candidate += 2;
1302 bool is_prime = true;
1303 for (size_t i=1; primes[i]*primes[i]<=candidate; ++i) {
1304 if (candidate % primes[i] == 0) {
1305 is_prime = false;
1306 break;
1307 }
1308 }
1309 if (is_prime)
1310 primes.push_back(candidate);
1311 }
1312 for (auto & it : primes) {
1313 if ( it > n ) {
1314 return it;
1315 }
1316 }
1317 throw logic_error("next_prime: should not reach this point!");
1318}
1319
1322class factor_partition
1323{
1324public:
1326 factor_partition(const upvec& factors_) : factors(factors_)
1327 {
1328 n = factors.size();
1329 k.resize(n, 0);
1330 k[0] = 1;
1331 cache.resize(n-1);
1332 one.resize(1, factors.front()[0].ring()->one());
1333 len = 1;
1334 last = 0;
1335 split();
1336 }
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; }
1343 bool next()
1344 {
1345 if ( last == n-1 ) {
1346 int rem = len - 1;
1347 int p = last - 1;
1348 while ( rem ) {
1349 if ( k[p] ) {
1350 --rem;
1351 --p;
1352 continue;
1353 }
1354 last = p - 1;
1355 while ( k[last] == 0 ) { --last; }
1356 if ( last == 0 && n == 2*len ) return false;
1357 k[last++] = 0;
1358 for ( size_t i=0; i<=len-rem; ++i ) {
1359 k[last] = 1;
1360 ++last;
1361 }
1362 fill(k.begin()+last, k.end(), 0);
1363 --last;
1364 split();
1365 return true;
1366 }
1367 last = len;
1368 ++len;
1369 if ( len > n/2 ) return false;
1370 fill(k.begin(), k.begin()+len, 1);
1371 fill(k.begin()+len+1, k.end(), 0);
1372 } else {
1373 k[last++] = 0;
1374 k[last] = 1;
1375 }
1376 split();
1377 return true;
1378 }
1380 umodpoly& left() { return lr[0]; }
1382 umodpoly& right() { return lr[1]; }
1383private:
1384 void split_cached()
1385 {
1386 size_t i = 0;
1387 do {
1388 size_t pos = i;
1389 int group = k[i++];
1390 size_t d = 0;
1391 while ( i < n && k[i] == group ) { ++d; ++i; }
1392 if ( d ) {
1393 if ( cache[pos].size() >= d ) {
1394 lr[group] = lr[group] * cache[pos][d-1];
1395 } else {
1396 if ( cache[pos].size() == 0 ) {
1397 cache[pos].push_back(factors[pos] * factors[pos+1]);
1398 }
1399 size_t j = pos + cache[pos].size() + 1;
1400 d -= cache[pos].size();
1401 while ( d ) {
1402 umodpoly buf = cache[pos].back() * factors[j];
1403 cache[pos].push_back(buf);
1404 --d;
1405 ++j;
1406 }
1407 lr[group] = lr[group] * cache[pos].back();
1408 }
1409 } else {
1410 lr[group] = lr[group] * factors[pos];
1411 }
1412 } while ( i < n );
1413 }
1414 void split()
1415 {
1416 lr[0] = one;
1417 lr[1] = one;
1418 if ( n > 6 ) {
1419 split_cached();
1420 } else {
1421 for ( size_t i=0; i<n; ++i ) {
1422 lr[k[i]] = lr[k[i]] * factors[i];
1423 }
1424 }
1425 }
1426private:
1427 umodpoly lr[2];
1428 vector<vector<umodpoly>> cache;
1429 upvec factors;
1430 umodpoly one;
1431 size_t n;
1432 size_t len;
1433 size_t last;
1434 vector<int> k;
1435};
1436
1440struct ModFactors
1441{
1442 upoly poly;
1443 upvec factors;
1444};
1445
1456static ex factor_univariate(const ex& poly, const ex& x, unsigned int& prime)
1457{
1458 ex unit, cont, prim_ex;
1459 poly.unitcontprim(x, unit, cont, prim_ex);
1460 upoly prim;
1461 upoly_from_ex(prim, prim_ex, x);
1462 if (prim_ex.is_equal(1)) {
1463 return poly;
1464 }
1465
1466 // determine proper prime and minimize number of modular factors
1467 prime = 3;
1468 unsigned int lastp = prime;
1469 cl_modint_ring R;
1470 unsigned int trials = 0;
1471 unsigned int minfactors = 0;
1472
1473 const numeric& cont_n = ex_to<numeric>(cont);
1474 cl_I i_cont;
1475 if (cont_n.is_integer()) {
1476 i_cont = the<cl_I>(cont_n.to_cl_N());
1477 } else {
1478 // poly \in Q[x] => poly = q ipoly, ipoly \in Z[x], q \in Q
1479 // factor(poly) \equiv q factor(ipoly)
1480 i_cont = cl_I(1);
1481 }
1482 cl_I lc = lcoeff(prim)*i_cont;
1483 upvec factors;
1484 while ( trials < 2 ) {
1485 umodpoly modpoly;
1486 while ( true ) {
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;
1492 }
1493 }
1494
1495 // do modular factorization
1496 upvec trialfactors;
1497 factor_modular(modpoly, trialfactors);
1498 if ( trialfactors.size() <= 1 ) {
1499 // irreducible for sure
1500 return poly;
1501 }
1502
1503 if ( minfactors == 0 || trialfactors.size() < minfactors ) {
1504 factors = trialfactors;
1505 minfactors = trialfactors.size();
1506 lastp = prime;
1507 trials = 1;
1508 } else {
1509 ++trials;
1510 }
1511 }
1512 prime = lastp;
1513 R = find_modint_ring(prime);
1514
1515 // lift all factor combinations
1516 stack<ModFactors> tocheck;
1517 ModFactors mf;
1518 mf.poly = prim;
1519 mf.factors = factors;
1520 tocheck.push(mf);
1521 upoly f1, f2;
1522 ex result = 1;
1523 while ( tocheck.size() ) {
1524 const size_t n = tocheck.top().factors.size();
1525 factor_partition part(tocheck.top().factors);
1526 while ( true ) {
1527 // call Hensel lifting
1528 hensel_univar(tocheck.top().poly, prime, part.left(), part.right(), f1, f2);
1529 if ( !f1.empty() ) {
1530 // successful, update the stack and the result
1531 if ( part.size_left() == 1 ) {
1532 if ( part.size_right() == 1 ) {
1533 result *= upoly_to_ex(f1, x) * upoly_to_ex(f2, x);
1534 tocheck.pop();
1535 break;
1536 }
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);
1542 break;
1543 }
1544 }
1545 break;
1546 }
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);
1550 tocheck.pop();
1551 break;
1552 }
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);
1558 break;
1559 }
1560 }
1561 break;
1562 } else {
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 ) {
1566 if ( part[i] ) {
1567 *i2++ = tocheck.top().factors[i];
1568 } else {
1569 *i1++ = tocheck.top().factors[i];
1570 }
1571 }
1572 tocheck.top().factors = newfactors1;
1573 tocheck.top().poly = f1;
1574 ModFactors mf;
1575 mf.factors = newfactors2;
1576 mf.poly = f2;
1577 tocheck.push(mf);
1578 break;
1579 }
1580 } else {
1581 // not successful
1582 if ( !part.next() ) {
1583 // if no more combinations left, return polynomial as
1584 // irreducible
1585 result *= upoly_to_ex(tocheck.top().poly, x);
1586 tocheck.pop();
1587 break;
1588 }
1589 }
1590 }
1591 }
1592
1593 return unit * cont * result;
1594}
1595
1599static inline ex factor_univariate(const ex& poly, const ex& x)
1600{
1601 unsigned int prime;
1602 return factor_univariate(poly, x, prime);
1603}
1604
1607struct EvalPoint
1608{
1609 ex x;
1611};
1612
1613#ifdef DEBUGFACTOR
1614ostream& operator<<(ostream& o, const vector<EvalPoint>& v)
1615{
1616 for ( size_t i=0; i<v.size(); ++i ) {
1617 o << "(" << v[i].x << "==" << v[i].evalpoint << ") ";
1618 }
1619 return o;
1620}
1621#endif // def DEBUGFACTOR
1622
1623// forward declaration
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);
1625
1641static upvec multiterm_eea_lift(const upvec& a, const ex& x, unsigned int p, unsigned int k)
1642{
1643 const size_t r = a.size();
1644 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1645 upvec q(r-1);
1646 q[r-2] = a[r-1];
1647 for ( size_t j=r-2; j>=1; --j ) {
1648 q[j-1] = a[j] * q[j];
1649 }
1650 umodpoly beta(1, R->one());
1651 upvec s;
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);
1658 umodpoly sigma1;
1659 umodpoly_from_ex(sigma1, exsigma[0], x, R);
1660 umodpoly sigma2;
1661 umodpoly_from_ex(sigma2, exsigma[1], x, R);
1662 beta = sigma1;
1663 s.push_back(sigma2);
1664 }
1665 s.push_back(beta);
1666 return s;
1667}
1668
1674static void change_modulus(const cl_modint_ring& R, umodpoly& a)
1675{
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));
1680 }
1681 canonicalize(a);
1682}
1683
1698static void eea_lift(const umodpoly& a, const umodpoly& b, const ex& x, unsigned int p, unsigned int k, umodpoly& s_, umodpoly& t_)
1699{
1700 cl_modint_ring R = find_modint_ring(p);
1701 umodpoly amod = a;
1702 change_modulus(R, amod);
1703 umodpoly bmod = b;
1704 change_modulus(R, bmod);
1705
1706 umodpoly smod;
1707 umodpoly tmod;
1708 exteuclid(amod, bmod, smod, tmod);
1709
1710 cl_modint_ring Rpk = find_modint_ring(expt_pos(cl_I(p),k));
1711 umodpoly s = smod;
1712 change_modulus(Rpk, s);
1713 umodpoly t = tmod;
1714 change_modulus(Rpk, t);
1715
1716 cl_I modulus(p);
1717 umodpoly one(1, Rpk->one());
1718 for ( size_t j=1; j<k; ++j ) {
1719 umodpoly e = one - a * s - b * t;
1720 reduce_coeff(e, modulus);
1721 umodpoly c = e;
1722 change_modulus(R, c);
1723 umodpoly sigmabar = smod * c;
1724 umodpoly taubar = tmod * c;
1725 umodpoly sigma, q;
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;
1735 modulus = modulus * p;
1736 }
1737
1738 s_ = s; t_ = t;
1739}
1740
1756static upvec univar_diophant(const upvec& a, const ex& x, unsigned int m, unsigned int p, unsigned int k)
1757{
1758 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1759
1760 const size_t r = a.size();
1761 upvec result;
1762 if ( r > 2 ) {
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);
1766 umodpoly buf;
1767 rem(bmod, a[j], buf);
1768 result.push_back(buf);
1769 }
1770 } else {
1771 umodpoly s, t;
1772 eea_lift(a[1], a[0], x, p, k, s, t);
1773 umodpoly bmod = umodpoly_to_umodpoly(s, R, m);
1774 umodpoly buf, q;
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);
1780 }
1781
1782 return result;
1783}
1784
1789struct make_modular_map : public map_function {
1790 cl_modint_ring R;
1791 make_modular_map(const cl_modint_ring& R_) : R(R_) { }
1792 ex operator()(const ex& e) override
1793 {
1794 if ( is_a<add>(e) || is_a<mul>(e) ) {
1795 return e.map(*this);
1796 }
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 ) {
1803 return n-mod;
1804 } else {
1805 return n;
1806 }
1807 }
1808 return e;
1809 }
1810};
1811
1819static ex make_modular(const ex& e, const cl_modint_ring& R)
1820{
1821 make_modular_map map(R);
1822 return map(e.expand());
1823}
1824
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)
1844{
1845 vector<ex> a = a_;
1846
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;
1851
1852 vector<ex> sigma;
1853 if ( nu > 1 ) {
1854 ex xnu = I.back().x;
1855 int alphanu = I.back().evalpoint;
1856
1857 ex A = 1;
1858 for ( size_t i=0; i<r; ++i ) {
1859 A *= a[i];
1860 }
1861 vector<ex> b(r);
1862 for ( size_t i=0; i<r; ++i ) {
1863 b[i] = normal(A / a[i]);
1864 }
1865
1866 vector<ex> anew = a;
1867 for ( size_t i=0; i<r; ++i ) {
1868 anew[i] = anew[i].subs(xnu == alphanu);
1869 }
1870 ex cnew = c.subs(xnu == alphanu);
1871 vector<EvalPoint> Inew = I;
1872 Inew.pop_back();
1873 sigma = multivar_diophant(anew, x, cnew, Inew, d, p, k);
1874
1875 ex buf = c;
1876 for ( size_t i=0; i<r; ++i ) {
1877 buf -= sigma[i] * b[i];
1878 }
1879 ex e = make_modular(buf, R);
1880
1881 ex monomial = 1;
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);
1889 ex buf = e;
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];
1894 }
1895 e = make_modular(buf, R);
1896 }
1897 }
1898 } else {
1899 upvec amod;
1900 for ( size_t i=0; i<a.size(); ++i ) {
1901 umodpoly up;
1902 umodpoly_from_ex(up, a[i], x, R);
1903 amod.push_back(up);
1904 }
1905
1906 sigma.insert(sigma.begin(), r, 0);
1907 size_t nterms;
1908 ex z;
1909 if ( is_a<add>(c) ) {
1910 nterms = c.nops();
1911 z = c.op(0);
1912 } else {
1913 nterms = 1;
1914 z = c;
1915 }
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);
1920 cl_MI modcm;
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);
1926 }
1927 if ( nterms > 1 && i+1 != nterms ) {
1928 z = c.op(i+1);
1929 }
1930 }
1931 }
1932
1933 for ( size_t i=0; i<sigma.size(); ++i ) {
1934 sigma[i] = make_modular(sigma[i], R);
1935 }
1936
1937 return sigma;
1938}
1939
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)
1958{
1959 const size_t nu = I.size() + 1;
1960 const cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),l));
1961
1962 vector<ex> A(nu);
1963 A[nu-1] = a;
1964
1965 for ( size_t j=nu; j>=2; --j ) {
1966 ex x = I[j-2].x;
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);
1970 }
1971
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;
1976 }
1977
1978 const size_t n = u.size();
1979 vector<ex> U(n);
1980 for ( size_t i=0; i<n; ++i ) {
1981 U[i] = umodpoly_to_ex(u[i], x);
1982 }
1983
1984 for ( size_t j=2; j<=nu; ++j ) {
1985 vector<ex> U1 = U;
1986 ex monomial = 1;
1987 for ( size_t m=0; m<n; ++m) {
1988 if ( lcU[m] != 1 ) {
1989 ex coef = lcU[m];
1990 for ( size_t i=j-1; i<nu-1; ++i ) {
1991 coef = coef.subs(I[i].x == I[i].evalpoint);
1992 }
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);
1996 }
1997 }
1998 ex Uprod = 1;
1999 for ( size_t i=0; i<n; ++i ) {
2000 Uprod *= U[i];
2001 }
2002 ex e = expand(A[j-1] - Uprod);
2003
2004 vector<EvalPoint> newI;
2005 for ( size_t i=1; i<=j-2; ++i ) {
2006 newI.push_back(I[i-1]);
2007 }
2008
2009 ex xj = I[j-2].x;
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);
2017 ex c = dif.subs(xj==alphaj) / factorial(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;
2022 U[i] += deltaU[i];
2023 U[i] = make_modular(U[i], R);
2024 }
2025 ex Uprod = 1;
2026 for ( size_t i=0; i<n; ++i ) {
2027 Uprod *= U[i];
2028 }
2029 e = A[j-1] - Uprod;
2030 e = make_modular(e, R);
2031 }
2032 }
2033 }
2034 }
2035
2036 ex acand = 1;
2037 for ( size_t i=0; i<U.size(); ++i ) {
2038 acand *= U[i];
2039 }
2040 if ( expand(a-acand).is_zero() ) {
2041 return lst(U.begin(), U.end());
2042 } else {
2043 return lst{};
2044 }
2045}
2046
2051static exvector put_factors_into_vec(const ex& e)
2052{
2053 exvector result;
2054 if ( is_a<numeric>(e) ) {
2055 result.push_back(e);
2056 return result;
2057 }
2058 if ( is_a<power>(e) ) {
2059 result.push_back(1);
2060 result.push_back(e.op(0));
2061 return result;
2062 }
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);
2067 return result;
2068 }
2069 if ( is_a<mul>(e) ) {
2070 ex nfac = 1;
2071 result.push_back(nfac);
2072 for ( size_t i=0; i<e.nops(); ++i ) {
2073 ex op = e.op(i);
2074 if ( is_a<numeric>(op) ) {
2075 nfac = op;
2076 }
2077 if ( is_a<power>(op) ) {
2078 result.push_back(op.op(0));
2079 }
2080 if ( is_a<symbol>(op) || is_a<add>(op) ) {
2081 result.push_back(op);
2082 }
2083 }
2084 result[0] = nfac;
2085 return result;
2086 }
2087 throw runtime_error("put_factors_into_vec: bad term.");
2088}
2089
2096static bool checkdivisors(const exvector& f)
2097{
2098 const int k = f.size();
2099 numeric q, r;
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 ) {
2105 r = d[j];
2106 do {
2107 r = gcd(r, q);
2108 q = q/r;
2109 } while ( r != 1 );
2110 if ( q == 1 ) {
2111 return true;
2112 }
2113 }
2114 d[i] = q;
2115 }
2116 return false;
2117}
2118
2136static void generate_set(const ex& u, const ex& vn, const ex& x, const exset& syms_wox, const exvector& f,
2137 numeric& modulus, ex& u0, vector<numeric>& a)
2138{
2139 while ( true ) {
2140 ++modulus;
2141 // generate a set of integers ...
2142 u0 = u;
2143 ex vna = vn;
2144 ex vnatry;
2145 auto s = syms_wox.begin();
2146 for ( size_t i=0; i<a.size(); ++i ) {
2147 do {
2148 a[i] = mod(numeric(rand()), 2*modulus) - modulus;
2149 vnatry = vna.subs(*s == a[i]);
2150 // ... for which the leading coefficient doesn't vanish ...
2151 } while ( vnatry == 0 );
2152 vna = vnatry;
2153 u0 = u0.subs(*s == a[i]);
2154 ++s;
2155 }
2156 // ... for which u0 is square free ...
2157 ex g = gcd(u0, u0.diff(ex_to<symbol>(x)));
2158 if ( !is_a<numeric>(g) ) {
2159 continue;
2160 }
2161 if ( !is_a<numeric>(vn) ) {
2162 // ... and for which the evaluated factors have each an unique prime factor
2163 exvector fnum = f;
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]) ) {
2167 s = syms_wox.begin();
2168 for ( size_t j=0; j<a.size(); ++j, ++s ) {
2169 fnum[i] = fnum[i].subs(*s == a[j]);
2170 }
2171 }
2172 }
2173 if ( checkdivisors(fnum) ) {
2174 continue;
2175 }
2176 }
2177 // ok, we have a valid set now
2178 return;
2179 }
2180}
2181
2182// forward declaration
2183static ex factor_sqrfree(const ex& poly);
2184
2187struct factorization_ctx {
2188 const ex poly, x; // polynomial, first symbol x...
2189 const exset syms_wox; // ...remaining symbols w/o x
2190 ex unit, cont, pp; // unit * cont * pp == poly
2191 ex vn; exvector vnlst; // leading coeff, factors of leading coeff
2192 numeric modulus; // incremented each time we try
2194 ex try_next_evaluation_homomorphism()
2195 {
2196 constexpr unsigned maxtrials = 3;
2197 vector<numeric> a(syms_wox.size(), 0);
2198
2199 unsigned int trialcount = 0;
2200 unsigned int prime;
2201 int factor_count = 0;
2202 int min_factor_count = -1;
2203 ex u, delta;
2204 ex ufac;
2205 exvector ufaclst;
2206
2207 // try several evaluation points to reduce the number of factors
2208 while ( trialcount < maxtrials ) {
2209
2210 // generate a set of valid evaluation points
2211 generate_set(pp, vn, x, syms_wox, vnlst, modulus, u, a);
2212
2213 ufac = factor_univariate(u, x, prime);
2214 ufaclst = put_factors_into_vec(ufac);
2215 factor_count = ufaclst.size()-1;
2216 delta = ufaclst[0];
2217
2218 if ( factor_count <= 1 ) {
2219 // irreducible
2220 return lst{pp};
2221 }
2222 if ( min_factor_count < 0 ) {
2223 // first time here
2224 min_factor_count = factor_count;
2225 }
2226 else if ( min_factor_count == factor_count ) {
2227 // one less to try
2228 ++trialcount;
2229 }
2230 else if ( min_factor_count > factor_count ) {
2231 // new minimum, reset trial counter
2232 min_factor_count = factor_count;
2233 trialcount = 0;
2234 }
2235 }
2236
2237 // determine true leading coefficients for the Hensel lifting
2238 vector<ex> C(factor_count);
2239 if ( is_a<numeric>(vn) ) {
2240 // easy case
2241 for ( size_t i=1; i<ufaclst.size(); ++i ) {
2242 C[i-1] = ufaclst[i].lcoeff(x);
2243 }
2244 } else {
2245 // difficult case.
2246 // we use the property of the ftilde having a unique prime factor.
2247 // details can be found in [Wan].
2248 // calculate ftilde
2249 vector<numeric> ftilde(vnlst.size()-1);
2250 for ( size_t i=0; i<ftilde.size(); ++i ) {
2251 ex ft = vnlst[i+1];
2252 auto s = syms_wox.begin();
2253 for ( size_t j=0; j<a.size(); ++j ) {
2254 ft = ft.subs(*s == a[j]);
2255 ++s;
2256 }
2257 ftilde[i] = ex_to<numeric>(ft);
2258 }
2259 // calculate D and C
2260 vector<bool> used_flag(ftilde.size(), false);
2261 vector<ex> D(factor_count, 1);
2262 if ( delta == 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 ) {
2266 int count = 0;
2267 numeric q;
2268 while ( irem(prefac, ftilde[j], q) == 0 ) {
2269 prefac = q;
2270 ++count;
2271 }
2272 if ( count ) {
2273 used_flag[j] = true;
2274 D[i] = D[i] * pow(vnlst[j+1], count);
2275 }
2276 }
2277 C[i] = D[i] * prefac;
2278 }
2279 } else {
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 ) {
2283 int count = 0;
2284 numeric q;
2285 while ( irem(prefac, ftilde[j], q) == 0 ) {
2286 prefac = q;
2287 ++count;
2288 }
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);
2294 ++count;
2295 }
2296 if ( count ) {
2297 used_flag[j] = true;
2298 D[i] = D[i] * pow(vnlst[j+1], count);
2299 }
2300 }
2301 C[i] = D[i] * prefac;
2302 }
2303 }
2304 // check if something went wrong
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;
2309 break;
2310 }
2311 }
2312 if ( some_factor_unused ) {
2313 return lst{}; // next try
2314 }
2315 }
2316
2317 // multiply the remaining content of the univariate polynomial into the
2318 // first factor
2319 if ( delta != 1 ) {
2320 C[0] = C[0] * delta;
2321 ufaclst[1] = ufaclst[1] * delta;
2322 }
2323
2324 // set up evaluation points
2325 vector<EvalPoint> epv;
2326 auto s = syms_wox.begin();
2327 for ( size_t i=0; i<a.size(); ++i ) {
2328 epv.emplace_back(EvalPoint{*s++, a[i].to_int()});
2329 }
2330
2331 // calc bound p^l
2332 int maxdeg = 0;
2333 for ( int i=1; i<=factor_count; ++i ) {
2334 if ( ufaclst[i].degree(x) > maxdeg ) {
2335 maxdeg = ufaclst[i].degree(x);
2336 }
2337 }
2338 cl_I B = ash(calc_bound(u, x), maxdeg+1); // = 2 * calc_bound(u,x) * 2^maxdeg
2339 cl_I l = 1;
2340 cl_I pl = prime;
2341 while ( pl < B ) {
2342 l = l + 1;
2343 pl = pl * prime;
2344 }
2345
2346 // set up modular factors (mod p^l)
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);
2351 }
2352
2353 // try Hensel lifting
2354 return hensel_multivar(pp, x, epv, prime, l, modfactors, C);
2355 }
2356};
2357
2373static ex factor_multivariate(const ex& poly, const exset& syms)
2374{
2375 // set up one factorization context for each symbol
2376 vector<factorization_ctx> ctx_in_x;
2377 for (auto x : syms) {
2378 exset syms_wox; // remaining syms w/o x
2379 copy_if(syms.begin(), syms.end(),
2380 inserter(syms_wox, syms_wox.end()), [x](const ex& y){ return y != x; });
2381
2382 factorization_ctx ctx{poly, x, syms_wox};
2383
2384 // make polynomial primitive
2385 poly.unitcontprim(x, ctx.unit, ctx.cont, ctx.pp);
2386 if ( !is_a<numeric>(ctx.cont) ) {
2387 // content is a polynomial in one or more of remaining syms, let's start over
2388 return ctx.unit * factor_sqrfree(ctx.cont) * factor_sqrfree(ctx.pp);
2389 }
2390
2391 // find factors of leading coefficient
2392 ctx.vn = ctx.pp.collect(x).lcoeff(x);
2393 ctx.vnlst = put_factors_into_vec(factor(ctx.vn));
2394
2395 ctx.modulus = (ctx.vnlst.size() > 3) ? ctx.vnlst.size() : numeric(3);
2396
2397 ctx_in_x.push_back(ctx);
2398 }
2399
2400 // try an evaluation homomorphism for each context in round-robin
2401 auto ctx = ctx_in_x.begin();
2402 while ( true ) {
2403
2404 ex res = ctx->try_next_evaluation_homomorphism();
2405
2406 if ( res != lst{} ) {
2407 // found the factors
2408 ex result = ctx->cont * ctx->unit;
2409 for ( size_t i=0; i<res.nops(); ++i ) {
2410 ex unit, cont, pp;
2411 res.op(i).unitcontprim(ctx->x, unit, cont, pp);
2412 result *= unit * cont * pp;
2413 }
2414 return result;
2415 }
2416
2417 // switch context for next symbol
2418 if (++ctx == ctx_in_x.end()) {
2419 ctx = ctx_in_x.begin();
2420 }
2421 }
2422}
2423
2426struct find_symbols_map : public map_function {
2428 ex operator()(const ex& e) override
2429 {
2430 if ( is_a<symbol>(e) ) {
2431 syms.insert(e);
2432 return e;
2433 }
2434 return e.map(*this);
2435 }
2436};
2437
2441static ex factor_sqrfree(const ex& poly)
2442{
2443 // determine all symbols in poly
2444 find_symbols_map findsymbols;
2445 findsymbols(poly);
2446 if ( findsymbols.syms.size() == 0 ) {
2447 return poly;
2448 }
2449
2450 if ( findsymbols.syms.size() == 1 ) {
2451 // univariate case
2452 const ex& x = *(findsymbols.syms.begin());
2453 int ld = poly.ldegree(x);
2454 if ( ld > 0 ) {
2455 // pull out direct factors
2456 ex res = factor_univariate(expand(poly/pow(x, ld)), x);
2457 return res * pow(x,ld);
2458 } else {
2459 ex res = factor_univariate(poly, x);
2460 return res;
2461 }
2462 }
2463
2464 // multivariate case
2465 ex res = factor_multivariate(poly, findsymbols.syms);
2466 return res;
2467}
2468
2472struct apply_factor_map : public map_function {
2473 unsigned options;
2474 apply_factor_map(unsigned options_) : options(options_) { }
2475 ex operator()(const ex& e) override
2476 {
2477 if ( e.info(info_flags::polynomial) ) {
2478 return factor(e, options);
2479 }
2480 if ( is_a<add>(e) ) {
2481 ex s1, s2;
2482 for ( size_t i=0; i<e.nops(); ++i ) {
2483 if ( e.op(i).info(info_flags::polynomial) ) {
2484 s1 += e.op(i);
2485 } else {
2486 s2 += e.op(i);
2487 }
2488 }
2489 return factor(s1, options) + s2.map(*this);
2490 }
2491 return e.map(*this);
2492 }
2493};
2494
2501template <typename F> void
2502factor_iter(const ex &e, F yield)
2503{
2504 if (is_a<mul>(e)) {
2505 for (const auto &f : e) {
2506 if (is_a<power>(f)) {
2507 yield(f.op(0), f.op(1));
2508 } else {
2509 yield(f, ex(1));
2510 }
2511 }
2512 } else {
2513 if (is_a<power>(e)) {
2514 yield(e.op(0), e.op(1));
2515 } else {
2516 yield(e, ex(1));
2517 }
2518 }
2519}
2520
2529static ex factor1(const ex& poly, unsigned options)
2530{
2531 // check arguments
2532 if ( !poly.info(info_flags::polynomial) ) {
2533 if ( options & factor_options::all ) {
2534 options &= ~factor_options::all;
2535 apply_factor_map factor_map(options);
2536 return factor_map(poly);
2537 }
2538 return poly;
2539 }
2540
2541 // determine all symbols in poly
2542 find_symbols_map findsymbols;
2543 findsymbols(poly);
2544 if ( findsymbols.syms.size() == 0 ) {
2545 return poly;
2546 }
2547 lst syms;
2548 for (auto & i : findsymbols.syms ) {
2549 syms.append(i);
2550 }
2551
2552 // make poly square free
2553 ex sfpoly = sqrfree(poly.expand(), syms);
2554
2555 // factorize the square free components
2556 ex res = 1;
2557 factor_iter(sfpoly,
2558 [&](const ex &f, const ex &k) {
2559 if ( is_a<add>(f) ) {
2560 res *= pow(factor_sqrfree(f), k);
2561 } else {
2562 // simple case: (monomial)^exponent
2563 res *= pow(f, k);
2564 }
2565 });
2566 return res;
2567}
2568
2569} // anonymous namespace
2570
2574ex factor(const ex& poly, unsigned options)
2575{
2576 ex result = 1;
2577 factor_iter(poly,
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);
2582 });
2583 });
2584 return result;
2585}
2586
2587} // namespace GiNaC
Interface to GiNaC's sums of expressions.
Lightweight wrapper for GiNaC's symbolic objects.
Definition ex.h:72
ex unit(const ex &x) const
Compute unit part (= sign of leading coefficient) of a multivariate polynomial in Q[x].
Definition normal.cpp:922
ex map(map_function &f) const
Definition ex.h:162
const_iterator begin() const noexcept
Definition ex.h:662
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].
Definition normal.cpp:1021
ex subs(const exmap &m, unsigned options=0) const
Definition ex.h:841
ex op(size_t i) const
Definition ex.h:136
int ldegree(const ex &s) const
Definition ex.h:174
@ all
factor all polynomial subexpressions
Definition flags.h:302
ex subs(const exmap &m, unsigned options=0) const override
Substitute a set of objects by arbitrary expressions.
Definition numeric.h:109
int degree(const ex &s) const override
Return degree of highest power in object s.
Definition numeric.cpp:732
Interface to GiNaC's light-weight expression handles.
vector< vector< umodpoly > > cache
Definition factor.cpp:1428
static const bool value
Definition factor.cpp:198
ex unit
Definition factor.cpp:2190
upvec factors
Definition factor.cpp:1429
exvector vnlst
Definition factor.cpp:2191
int evalpoint
Definition factor.cpp:1610
numeric modulus
Definition factor.cpp:2192
ex vn
Definition factor.cpp:2191
unsigned options
Definition factor.cpp:2473
vector< int > k
Definition factor.cpp:1434
size_t n
Definition factor.cpp:1431
ex pp
Definition factor.cpp:2190
size_t len
Definition factor.cpp:1432
size_t c
Definition factor.cpp:756
ex x
Definition factor.cpp:1609
size_t r
Definition factor.cpp:756
exset syms
Definition factor.cpp:2427
const exset syms_wox
Definition factor.cpp:2189
umodpoly one
Definition factor.cpp:1430
umodpoly lr[2]
Definition factor.cpp:1427
cl_modint_ring R
Definition factor.cpp:1790
mvec m
Definition factor.cpp:757
size_t last
Definition factor.cpp:1433
ex cont
Definition factor.cpp:2190
upoly poly
Definition factor.cpp:1442
Polynomial factorization.
Interface to GiNaC's initially known functions.
Interface to GiNaC's products of expressions.
Definition add.cpp:35
bool is_zero(const ex &thisex)
Definition ex.h:835
const numeric I
Imaginary unit.
Definition numeric.cpp:1432
std::ostream & operator<<(std::ostream &os, const archive_node &n)
Write archive_node to binary data stream.
Definition archive.cpp:198
const numeric pow(const numeric &x, const numeric &y)
Definition numeric.h:250
container< std::list > lst
Definition lst.h:31
ex sqrfree(const ex &a, const lst &l)
Compute a square-free factorization of a multivariate polynomial in Q[X].
Definition normal.cpp:1888
std::set< ex, ex_is_less > exset
Definition basic.h:48
const numeric mod(const numeric &a, const numeric &b)
Modulus (in positive representation).
Definition numeric.cpp:2332
const ex operator/(const ex &lh, const ex &rh)
Definition operators.cpp:77
const numeric abs(const numeric &x)
Absolute value.
Definition numeric.cpp:2319
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].
Definition normal.cpp:1432
const numeric irem(const numeric &a, const numeric &b)
Numeric integer remainder.
Definition numeric.cpp:2367
const ex operator+(const ex &lh, const ex &rh)
Definition operators.cpp:62
const ex operator*(const ex &lh, const ex &rh)
Definition operators.cpp:72
const numeric factorial(const numeric &n)
Factorial combinatorial function.
Definition numeric.cpp:2112
const numeric smod(const numeric &a_, const numeric &b_)
Modulus (in symmetric representation).
Definition numeric.cpp:2345
int degree(const ex &thisex, const ex &s)
Definition ex.h:751
const numeric iquo(const numeric &a, const numeric &b)
Numeric integer quotient.
Definition numeric.cpp:2408
ex normal(const ex &thisex)
Definition ex.h:769
ex op(const ex &thisex, size_t i)
Definition ex.h:826
ex coeff(const ex &thisex, const ex &s, int n=1)
Definition ex.h:757
ex factor(const ex &poly, unsigned options)
Interface function to the outside world.
Definition factor.cpp:2574
bool is_prime(const numeric &x)
Definition numeric.h:286
int canonicalize(exvector::iterator v, const symmetry &symm)
Canonicalize the order of elements of an expression vector, according to the symmetry properties defi...
Definition symmetry.cpp:436
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].
Definition normal.cpp:422
std::vector< ex > exvector
Definition basic.h:47
const ex operator-(const ex &lh, const ex &rh)
Definition operators.cpp:67
ex expand(const ex &thisex, unsigned options=0)
Definition ex.h:730
Definition ex.h:987
void swap(GiNaC::ex &a, GiNaC::ex &b)
Specialization of std::swap() for ex objects.
Definition ex.h:991
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.

This page is part of the GiNaC developer's reference. It was generated automatically by doxygen. For an introduction, see the tutorial.