ce845e4ef58c8e92df8db79859bcaea9f8fb9d6a
[ginac.git] / ginac / factor.cpp
1 /** @file factor.cpp
2  *
3  *  Polynomial factorization code (Implementation).
4  *
5  *  Algorithms used can be found in
6  *    [W1]  An Improved Multivariate Polynomial Factoring Algorithm,
7  *          P.S.Wang, Mathematics of Computation, Vol. 32, No. 144 (1978) 1215--1231.
8  *    [GCL] Algorithms for Computer Algebra,
9  *          K.O.Geddes, S.R.Czapor, G.Labahn, Springer Verlag, 1992.
10  */
11
12 /*
13  *  GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany
14  *
15  *  This program is free software; you can redistribute it and/or modify
16  *  it under the terms of the GNU General Public License as published by
17  *  the Free Software Foundation; either version 2 of the License, or
18  *  (at your option) any later version.
19  *
20  *  This program is distributed in the hope that it will be useful,
21  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  *  GNU General Public License for more details.
24  *
25  *  You should have received a copy of the GNU General Public License
26  *  along with this program; if not, write to the Free Software
27  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
28  */
29
30 //#define DEBUGFACTOR
31
32 #ifdef DEBUGFACTOR
33 #include <ostream>
34 #include <ginac/ginac.h>
35 using namespace GiNaC;
36 #else
37 #include "factor.h"
38
39 #include "ex.h"
40 #include "numeric.h"
41 #include "operators.h"
42 #include "inifcns.h"
43 #include "symbol.h"
44 #include "relational.h"
45 #include "power.h"
46 #include "mul.h"
47 #include "normal.h"
48 #include "add.h"
49 #endif
50
51 #include <algorithm>
52 #include <list>
53 #include <vector>
54 using namespace std;
55
56 #include <cln/cln.h>
57 using namespace cln;
58
59 #ifdef DEBUGFACTOR
60 namespace Factor {
61 #else
62 namespace GiNaC {
63 #endif
64
65 #ifdef DEBUGFACTOR
66 #define DCOUT(str) cout << #str << endl
67 #define DCOUTVAR(var) cout << #var << ": " << var << endl
68 #define DCOUT2(str,var) cout << #str << ": " << var << endl
69 #else
70 #define DCOUT(str)
71 #define DCOUTVAR(var)
72 #define DCOUT2(str,var)
73 #endif
74
75 // forward declaration
76 ex factor(const ex& poly, unsigned options);
77
78 // anonymous namespace to hide all utility functions
79 namespace {
80
81 typedef vector<cl_MI> Vec;
82 typedef vector<Vec> VecVec;
83
84 #ifdef DEBUGFACTOR
85 ostream& operator<<(ostream& o, const Vec& v)
86 {
87         Vec::const_iterator i = v.begin(), end = v.end();
88         while ( i != end ) {
89                 o << *i++ << " ";
90         }
91         return o;
92 }
93 #endif // def DEBUGFACTOR
94
95 #ifdef DEBUGFACTOR
96 ostream& operator<<(ostream& o, const VecVec& v)
97 {
98         VecVec::const_iterator i = v.begin(), end = v.end();
99         while ( i != end ) {
100                 o << *i++ << endl;
101         }
102         return o;
103 }
104 #endif // def DEBUGFACTOR
105
106 struct Term
107 {
108         cl_MI c;          // coefficient
109         unsigned int exp; // exponent >=0
110 };
111
112 #ifdef DEBUGFACTOR
113 ostream& operator<<(ostream& o, const Term& t)
114 {
115         if ( t.exp ) {
116                 o << "(" << t.c << ")x^" << t.exp;
117         }
118         else {
119                 o << "(" << t.c << ")";
120         }
121         return o;
122 }
123 #endif // def DEBUGFACTOR
124
125 struct UniPoly
126 {
127         cl_modint_ring R;
128         list<Term> terms;  // highest exponent first
129
130         UniPoly(const cl_modint_ring& ring) : R(ring) { }
131         UniPoly(const cl_modint_ring& ring, const ex& poly, const ex& x) : R(ring)
132         { 
133                 // assert: poly is in Z[x]
134                 Term t;
135                 for ( int i=poly.degree(x); i>=poly.ldegree(x); --i ) {
136                         cl_I coeff = the<cl_I>(ex_to<numeric>(poly.coeff(x,i)).to_cl_N());
137                         if ( !zerop(coeff) ) {
138                                 t.c = R->canonhom(coeff);
139                                 if ( !zerop(t.c) ) {
140                                         t.exp = i;
141                                         terms.push_back(t);
142                                 }
143                         }
144                 }
145         }
146         UniPoly(const cl_modint_ring& ring, const UniPoly& poly) : R(ring)
147         { 
148                 if ( R->modulus == poly.R->modulus ) {
149                         terms = poly.terms;
150                 }
151                 else {
152                         list<Term>::const_iterator i=poly.terms.begin(), end=poly.terms.end();
153                         for ( ; i!=end; ++i ) {
154                                 terms.push_back(*i);
155                                 terms.back().c = R->canonhom(poly.R->retract(i->c));
156                                 if ( zerop(terms.back().c) ) {
157                                         terms.pop_back();
158                                 }
159                         }
160                 }
161         }
162         UniPoly(const cl_modint_ring& ring, const Vec& v) : R(ring)
163         {
164                 Term t;
165                 for ( unsigned int i=0; i<v.size(); ++i ) {
166                         if ( !zerop(v[i]) ) {
167                                 t.c = v[i];
168                                 t.exp = i;
169                                 terms.push_front(t);
170                         }
171                 }
172         }
173         unsigned int degree() const
174         {
175                 if ( terms.size() ) {
176                         return terms.front().exp;
177                 }
178                 else {
179                         return 0;
180                 }
181         }
182         bool zero() const { return (terms.size() == 0); }
183         const cl_MI operator[](unsigned int deg) const
184         {
185                 list<Term>::const_iterator i = terms.begin(), end = terms.end();
186                 for ( ; i != end; ++i ) {
187                         if ( i->exp == deg ) {
188                                 return i->c;
189                         }
190                         if ( i->exp < deg ) {
191                                 break;
192                         }
193                 }
194                 return R->zero();
195         }
196         void set(unsigned int deg, const cl_MI& c)
197         {
198                 list<Term>::iterator i = terms.begin(), end = terms.end();
199                 while ( i != end ) {
200                         if ( i->exp == deg ) {
201                                 if ( !zerop(c) ) {
202                                         i->c = c;
203                                 }
204                                 else {
205                                         terms.erase(i);
206                                 }
207                                 return;
208                         }
209                         if ( i->exp < deg ) {
210                                 break;
211                         }
212                         ++i;
213                 }
214                 if ( !zerop(c) ) {
215                         Term t;
216                         t.c = c;
217                         t.exp = deg;
218                         terms.insert(i, t);
219                 }
220         }
221         ex to_ex(const ex& x, bool symmetric = true) const
222         {
223                 ex r;
224                 list<Term>::const_iterator i = terms.begin(), end = terms.end();
225                 if ( symmetric ) {
226                         numeric mod(R->modulus);
227                         numeric halfmod = (mod-1)/2;
228                         for ( ; i != end; ++i ) {
229                                 numeric n(R->retract(i->c));
230                                 if ( n > halfmod ) {
231                                         r += pow(x, i->exp) * (n-mod);
232                                 }
233                                 else {
234                                         r += pow(x, i->exp) * n;
235                                 }
236                         }
237                 }
238                 else {
239                         for ( ; i != end; ++i ) {
240                                 r += pow(x, i->exp) * numeric(R->retract(i->c));
241                         }
242                 }
243                 return r;
244         }
245         void unit_normal()
246         {
247                 if ( terms.size() ) {
248                         if ( terms.front().c != R->one() ) {
249                                 list<Term>::iterator i = terms.begin(), end = terms.end();
250                                 cl_MI cont = i->c;
251                                 i->c = R->one();
252                                 while ( ++i != end ) {
253                                         i->c = div(i->c, cont);
254                                         if ( zerop(i->c) ) {
255                                                 terms.erase(i);
256                                         }
257                                 }
258                         }
259                 }
260         }
261         cl_MI unit() const
262         {
263                 return terms.front().c;
264         }
265         void divide(const cl_MI& x)
266         {
267                 list<Term>::iterator i = terms.begin(), end = terms.end();
268                 for ( ; i != end; ++i ) {
269                         i->c = div(i->c, x);
270                         if ( zerop(i->c) ) {
271                                 terms.erase(i);
272                         }
273                 }
274         }
275         void divide(const cl_I& x)
276         {
277                 list<Term>::iterator i = terms.begin(), end = terms.end();
278                 for ( ; i != end; ++i ) {
279                         i->c = cl_MI(R, the<cl_I>(R->retract(i->c) / x));
280                 }
281         }
282         void reduce_exponents(unsigned int prime)
283         {
284                 list<Term>::iterator i = terms.begin(), end = terms.end();
285                 while ( i != end ) {
286                         if ( i->exp > 0 ) {
287                                 // assert: i->exp is multiple of prime
288                                 i->exp /= prime;
289                         }
290                         ++i;
291                 }
292         }
293         void deriv(UniPoly& d) const
294         {
295                 list<Term>::const_iterator i = terms.begin(), end = terms.end();
296                 while ( i != end ) {
297                         if ( i->exp ) {
298                                 cl_MI newc = i->c * i->exp;
299                                 if ( !zerop(newc) ) {
300                                         Term t;
301                                         t.c = newc;
302                                         t.exp = i->exp-1;
303                                         d.terms.push_back(t);
304                                 }
305                         }
306                         ++i;
307                 }
308         }
309         bool operator<(const UniPoly& o) const
310         {
311                 if ( terms.size() != o.terms.size() ) {
312                         return terms.size() < o.terms.size();
313                 }
314                 list<Term>::const_iterator i1 = terms.begin(), end = terms.end();
315                 list<Term>::const_iterator i2 = o.terms.begin();
316                 while ( i1 != end ) {
317                         if ( i1->exp != i2->exp ) {
318                                 return i1->exp < i2->exp;
319                         }
320                         if ( i1->c != i2->c ) {
321                                 return R->retract(i1->c) < R->retract(i2->c);
322                         }
323                         ++i1; ++i2;
324                 }
325                 return true;
326         }
327         bool operator==(const UniPoly& o) const
328         {
329                 if ( terms.size() != o.terms.size() ) {
330                         return false;
331                 }
332                 list<Term>::const_iterator i1 = terms.begin(), end = terms.end();
333                 list<Term>::const_iterator i2 = o.terms.begin();
334                 while ( i1 != end ) {
335                         if ( i1->exp != i2->exp ) {
336                                 return false;
337                         }
338                         if ( i1->c != i2->c ) {
339                                 return false;
340                         }
341                         ++i1; ++i2;
342                 }
343                 return true;
344         }
345         bool operator!=(const UniPoly& o) const
346         {
347                 bool res = !(*this == o);
348                 return res;
349         }
350 };
351
352 static UniPoly operator*(const UniPoly& a, const UniPoly& b)
353 {
354         unsigned int n = a.degree()+b.degree();
355         UniPoly c(a.R);
356         Term t;
357         for ( unsigned int i=0 ; i<=n; ++i ) {
358                 t.c = a.R->zero();
359                 for ( unsigned int j=0 ; j<=i; ++j ) {
360                         t.c = t.c + a[j] * b[i-j];
361                 }
362                 if ( !zerop(t.c) ) {
363                         t.exp = i;
364                         c.terms.push_front(t);
365                 }
366         }
367         return c;
368 }
369
370 static UniPoly operator-(const UniPoly& a, const UniPoly& b)
371 {
372         list<Term>::const_iterator ia = a.terms.begin(), aend = a.terms.end();
373         list<Term>::const_iterator ib = b.terms.begin(), bend = b.terms.end();
374         UniPoly c(a.R);
375         while ( ia != aend && ib != bend ) {
376                 if ( ia->exp > ib->exp ) {
377                         c.terms.push_back(*ia);
378                         ++ia;
379                 }
380                 else if ( ia->exp < ib->exp ) {
381                         c.terms.push_back(*ib);
382                         c.terms.back().c = -c.terms.back().c;
383                         ++ib;
384                 }
385                 else {
386                         Term t;
387                         t.exp = ia->exp;
388                         t.c = ia->c - ib->c;
389                         if ( !zerop(t.c) ) {
390                                 c.terms.push_back(t);
391                         }
392                         ++ia; ++ib;
393                 }
394         }
395         while ( ia != aend ) {
396                 c.terms.push_back(*ia);
397                 ++ia;
398         }
399         while ( ib != bend ) {
400                 c.terms.push_back(*ib);
401                 c.terms.back().c = -c.terms.back().c;
402                 ++ib;
403         }
404         return c;
405 }
406
407 static UniPoly operator*(const UniPoly& a, const cl_MI& fac)
408 {
409         unsigned int n = a.degree();
410         UniPoly c(a.R);
411         Term t;
412         for ( unsigned int i=0 ; i<=n; ++i ) {
413                 t.c = a[i] * fac;
414                 if ( !zerop(t.c) ) {
415                         t.exp = i;
416                         c.terms.push_front(t);
417                 }
418         }
419         return c;
420 }
421
422 static UniPoly operator+(const UniPoly& a, const UniPoly& b)
423 {
424         list<Term>::const_iterator ia = a.terms.begin(), aend = a.terms.end();
425         list<Term>::const_iterator ib = b.terms.begin(), bend = b.terms.end();
426         UniPoly c(a.R);
427         while ( ia != aend && ib != bend ) {
428                 if ( ia->exp > ib->exp ) {
429                         c.terms.push_back(*ia);
430                         ++ia;
431                 }
432                 else if ( ia->exp < ib->exp ) {
433                         c.terms.push_back(*ib);
434                         ++ib;
435                 }
436                 else {
437                         Term t;
438                         t.exp = ia->exp;
439                         t.c = ia->c + ib->c;
440                         if ( !zerop(t.c) ) {
441                                 c.terms.push_back(t);
442                         }
443                         ++ia; ++ib;
444                 }
445         }
446         while ( ia != aend ) {
447                 c.terms.push_back(*ia);
448                 ++ia;
449         }
450         while ( ib != bend ) {
451                 c.terms.push_back(*ib);
452                 ++ib;
453         }
454         return c;
455 }
456
457 // static UniPoly operator-(const UniPoly& a)
458 // {
459 //      list<Term>::const_iterator ia = a.terms.begin(), aend = a.terms.end();
460 //      UniPoly c(a.R);
461 //      while ( ia != aend ) {
462 //              c.terms.push_back(*ia);
463 //              c.terms.back().c = -c.terms.back().c;
464 //              ++ia;
465 //      }
466 //      return c;
467 // }
468
469 #ifdef DEBUGFACTOR
470 ostream& operator<<(ostream& o, const UniPoly& t)
471 {
472         list<Term>::const_iterator i = t.terms.begin(), end = t.terms.end();
473         if ( i == end ) {
474                 o << "0";
475                 return o;
476         }
477         for ( ; i != end; ) {
478                 o << *i++;
479                 if ( i != end ) {
480                         o << " + ";
481                 }
482         }
483         return o;
484 }
485 #endif // def DEBUGFACTOR
486
487 #ifdef DEBUGFACTOR
488 ostream& operator<<(ostream& o, const list<UniPoly>& t)
489 {
490         list<UniPoly>::const_iterator i = t.begin(), end = t.end();
491         o << "{" << endl;
492         for ( ; i != end; ) {
493                 o << *i++ << endl;
494         }
495         o << "}" << endl;
496         return o;
497 }
498 #endif // def DEBUGFACTOR
499
500 typedef vector<UniPoly> UniPolyVec;
501
502 #ifdef DEBUGFACTOR
503 ostream& operator<<(ostream& o, const UniPolyVec& v)
504 {
505         UniPolyVec::const_iterator i = v.begin(), end = v.end();
506         while ( i != end ) {
507                 o << *i++ << " , " << endl;
508         }
509         return o;
510 }
511 #endif // def DEBUGFACTOR
512
513 struct UniFactor
514 {
515         UniPoly p;
516         unsigned int exp;
517
518         UniFactor(const cl_modint_ring& ring) : p(ring) { }
519         UniFactor(const UniPoly& p_, unsigned int exp_) : p(p_), exp(exp_) { }
520         bool operator<(const UniFactor& o) const
521         {
522                 return p < o.p;
523         }
524 };
525
526 struct UniFactorVec
527 {
528         vector<UniFactor> factors;
529
530         void unique()
531         {
532                 sort(factors.begin(), factors.end());
533                 if ( factors.size() > 1 ) {
534                         vector<UniFactor>::iterator i = factors.begin();
535                         vector<UniFactor>::const_iterator cmp = factors.begin()+1;
536                         vector<UniFactor>::iterator end = factors.end();
537                         while ( cmp != end ) {
538                                 if ( i->p != cmp->p ) {
539                                         ++i;
540                                         ++cmp;
541                                 }
542                                 else {
543                                         i->exp += cmp->exp;
544                                         ++cmp;
545                                 }
546                         }
547                         if ( i != end-1 ) {
548                                 factors.erase(i+1, end);
549                         }
550                 }
551         }
552 };
553
554 #ifdef DEBUGFACTOR
555 ostream& operator<<(ostream& o, const UniFactorVec& ufv)
556 {
557         for ( size_t i=0; i<ufv.factors.size(); ++i ) {
558                 if ( i != ufv.factors.size()-1 ) {
559                         o << "*";
560                 }
561                 else {
562                         o << " ";
563                 }
564                 o << "[ " << ufv.factors[i].p << " ]^" << ufv.factors[i].exp << endl;
565         }
566         return o;
567 }
568 #endif // def DEBUGFACTOR
569
570 static void rem(const UniPoly& a_, const UniPoly& b, UniPoly& c)
571 {
572         if ( a_.degree() < b.degree() ) {
573                 c = a_;
574                 return;
575         }
576
577         unsigned int k, n;
578         n = b.degree();
579         k = a_.degree() - n;
580
581         if ( n == 0 ) {
582                 c.terms.clear();
583                 return;
584         }
585
586         c = a_;
587         Term termbuf;
588
589         while ( true ) {
590                 cl_MI qk = div(c[n+k], b[n]);
591                 if ( !zerop(qk) ) {
592                         unsigned int j;
593                         for ( unsigned int i=0; i<n; ++i ) {
594                                 j = n + k - 1 - i;
595                                 c.set(j, c[j] - qk*b[j-k]);
596                         }
597                 }
598                 if ( k == 0 ) break;
599                 --k;
600         }
601         list<Term>::iterator i = c.terms.begin(), end = c.terms.end();
602         while ( i != end ) {
603                 if ( i->exp <= n-1 ) {
604                         break;
605                 }
606                 ++i;
607         }
608         c.terms.erase(c.terms.begin(), i);
609 }
610
611 static void div(const UniPoly& a_, const UniPoly& b, UniPoly& q)
612 {
613         if ( a_.degree() < b.degree() ) {
614                 q.terms.clear();
615                 return;
616         }
617
618         unsigned int k, n;
619         n = b.degree();
620         k = a_.degree() - n;
621
622         UniPoly c = a_;
623         Term termbuf;
624
625         while ( true ) {
626                 cl_MI qk = div(c[n+k], b[n]);
627                 if ( !zerop(qk) ) {
628                         Term t;
629                         t.c = qk;
630                         t.exp = k;
631                         q.terms.push_back(t);
632                         unsigned int j;
633                         for ( unsigned int i=0; i<n; ++i ) {
634                                 j = n + k - 1 - i;
635                                 c.set(j, c[j] - qk*b[j-k]);
636                         }
637                 }
638                 if ( k == 0 ) break;
639                 --k;
640         }
641 }
642
643 static void gcd(const UniPoly& a, const UniPoly& b, UniPoly& c)
644 {
645         c = a;
646         c.unit_normal();
647         UniPoly d = b;
648         d.unit_normal();
649
650         if ( c.degree() < d.degree() ) {
651                 gcd(b, a, c);
652                 return;
653         }
654
655         while ( !d.zero() ) {
656                 UniPoly r(a.R);
657                 rem(c, d, r);
658                 c = d;
659                 d = r;
660         }
661         c.unit_normal();
662 }
663
664 static bool is_one(const UniPoly& w)
665 {
666         if ( w.terms.size() == 1 && w[0] == w.R->one() ) {
667                 return true;
668         }
669         return false;
670 }
671
672 static void sqrfree_main(const UniPoly& a, UniFactorVec& fvec)
673 {
674         unsigned int i = 1;
675         UniPoly b(a.R);
676         a.deriv(b);
677         if ( !b.zero() ) {
678                 UniPoly c(a.R), w(a.R);
679                 gcd(a, b, c);
680                 div(a, c, w);
681                 while ( !is_one(w) ) {
682                         UniPoly y(a.R), z(a.R);
683                         gcd(w, c, y);
684                         div(w, y, z);
685                         if ( !is_one(z) ) {
686                                 UniFactor uf(z, i);
687                                 fvec.factors.push_back(uf);
688                         }
689                         ++i;
690                         w = y;
691                         UniPoly cbuf(a.R);
692                         div(c, y, cbuf);
693                         c = cbuf;
694                 }
695                 if ( !is_one(c) ) {
696                         unsigned int prime = cl_I_to_uint(c.R->modulus);
697                         c.reduce_exponents(prime);
698                         unsigned int pos = fvec.factors.size();
699                         sqrfree_main(c, fvec);
700                         for ( unsigned int p=pos; p<fvec.factors.size(); ++p ) {
701                                 fvec.factors[p].exp *= prime;
702                         }
703                         return;
704                 }
705         }
706         else {
707                 unsigned int prime = cl_I_to_uint(a.R->modulus);
708                 UniPoly amod = a;
709                 amod.reduce_exponents(prime);
710                 unsigned int pos = fvec.factors.size();
711                 sqrfree_main(amod, fvec);
712                 for ( unsigned int p=pos; p<fvec.factors.size(); ++p ) {
713                         fvec.factors[p].exp *= prime;
714                 }
715                 return;
716         }
717 }
718
719 static void squarefree(const UniPoly& a, UniFactorVec& fvec)
720 {
721         sqrfree_main(a, fvec);
722         fvec.unique();
723 }
724
725 class Matrix
726 {
727         friend ostream& operator<<(ostream& o, const Matrix& m);
728 public:
729         Matrix(size_t r_, size_t c_, const cl_MI& init) : r(r_), c(c_)
730         {
731                 m.resize(c*r, init);
732         }
733         size_t rowsize() const { return r; }
734         size_t colsize() const { return c; }
735         cl_MI& operator()(size_t row, size_t col) { return m[row*c + col]; }
736         cl_MI operator()(size_t row, size_t col) const { return m[row*c + col]; }
737         void mul_col(size_t col, const cl_MI x)
738         {
739                 Vec::iterator i = m.begin() + col;
740                 for ( size_t rc=0; rc<r; ++rc ) {
741                         *i = *i * x;
742                         i += c;
743                 }
744         }
745         void sub_col(size_t col1, size_t col2, const cl_MI fac)
746         {
747                 Vec::iterator i1 = m.begin() + col1;
748                 Vec::iterator i2 = m.begin() + col2;
749                 for ( size_t rc=0; rc<r; ++rc ) {
750                         *i1 = *i1 - *i2 * fac;
751                         i1 += c;
752                         i2 += c;
753                 }
754         }
755         void switch_col(size_t col1, size_t col2)
756         {
757                 cl_MI buf;
758                 Vec::iterator i1 = m.begin() + col1;
759                 Vec::iterator i2 = m.begin() + col2;
760                 for ( size_t rc=0; rc<r; ++rc ) {
761                         buf = *i1; *i1 = *i2; *i2 = buf;
762                         i1 += c;
763                         i2 += c;
764                 }
765         }
766         void mul_row(size_t row, const cl_MI x)
767         {
768                 vector<cl_MI>::iterator i = m.begin() + row*c;
769                 for ( size_t cc=0; cc<c; ++cc ) {
770                         *i = *i * x;
771                         ++i;
772                 }
773         }
774         void sub_row(size_t row1, size_t row2, const cl_MI fac)
775         {
776                 vector<cl_MI>::iterator i1 = m.begin() + row1*c;
777                 vector<cl_MI>::iterator i2 = m.begin() + row2*c;
778                 for ( size_t cc=0; cc<c; ++cc ) {
779                         *i1 = *i1 - *i2 * fac;
780                         ++i1;
781                         ++i2;
782                 }
783         }
784         void switch_row(size_t row1, size_t row2)
785         {
786                 cl_MI buf;
787                 vector<cl_MI>::iterator i1 = m.begin() + row1*c;
788                 vector<cl_MI>::iterator i2 = m.begin() + row2*c;
789                 for ( size_t cc=0; cc<c; ++cc ) {
790                         buf = *i1; *i1 = *i2; *i2 = buf;
791                         ++i1;
792                         ++i2;
793                 }
794         }
795         bool is_col_zero(size_t col) const
796         {
797                 Vec::const_iterator i = m.begin() + col;
798                 for ( size_t rr=0; rr<r; ++rr ) {
799                         if ( !zerop(*i) ) {
800                                 return false;
801                         }
802                         i += c;
803                 }
804                 return true;
805         }
806         bool is_row_zero(size_t row) const
807         {
808                 Vec::const_iterator i = m.begin() + row*c;
809                 for ( size_t cc=0; cc<c; ++cc ) {
810                         if ( !zerop(*i) ) {
811                                 return false;
812                         }
813                         ++i;
814                 }
815                 return true;
816         }
817         void set_row(size_t row, const vector<cl_MI>& newrow)
818         {
819                 Vec::iterator i1 = m.begin() + row*c;
820                 Vec::const_iterator i2 = newrow.begin(), end = newrow.end();
821                 for ( ; i2 != end; ++i1, ++i2 ) {
822                         *i1 = *i2;
823                 }
824         }
825         Vec::const_iterator row_begin(size_t row) const { return m.begin()+row*c; }
826         Vec::const_iterator row_end(size_t row) const { return m.begin()+row*c+r; }
827 private:
828         size_t r, c;
829         Vec m;
830 };
831
832 #ifdef DEBUGFACTOR
833 Matrix operator*(const Matrix& m1, const Matrix& m2)
834 {
835         const unsigned int r = m1.rowsize();
836         const unsigned int c = m2.colsize();
837         Matrix o(r,c,m1(0,0));
838
839         for ( size_t i=0; i<r; ++i ) {
840                 for ( size_t j=0; j<c; ++j ) {
841                         cl_MI buf;
842                         buf = m1(i,0) * m2(0,j);
843                         for ( size_t k=1; k<c; ++k ) {
844                                 buf = buf + m1(i,k)*m2(k,j);
845                         }
846                         o(i,j) = buf;
847                 }
848         }
849         return o;
850 }
851
852 ostream& operator<<(ostream& o, const Matrix& m)
853 {
854         vector<cl_MI>::const_iterator i = m.m.begin(), end = m.m.end();
855         size_t wrap = 1;
856         for ( ; i != end; ++i ) {
857                 o << *i << " ";
858                 if ( !(wrap++ % m.c) ) {
859                         o << endl;
860                 }
861         }
862         o << endl;
863         return o;
864 }
865 #endif // def DEBUGFACTOR
866
867 static void q_matrix(const UniPoly& a, Matrix& Q)
868 {
869         unsigned int n = a.degree();
870         unsigned int q = cl_I_to_uint(a.R->modulus);
871 // fast and buggy
872 //      vector<cl_MI> r(n, a.R->zero());
873 //      r[0] = a.R->one();
874 //      Q.set_row(0, r);
875 //      unsigned int max = (n-1) * q;
876 //      for ( size_t m=1; m<=max; ++m ) {
877 //              cl_MI rn_1 = r.back();
878 //              for ( size_t i=n-1; i>0; --i ) {
879 //                      r[i] = r[i-1] - rn_1 * a[i];
880 //              }
881 //              r[0] = -rn_1 * a[0];
882 //              if ( (m % q) == 0 ) {
883 //                      Q.set_row(m/q, r);
884 //              }
885 //      }
886 // slow and (hopefully) correct
887         for ( size_t i=0; i<n; ++i ) {
888                 UniPoly qk(a.R);
889                 qk.set(i*q, a.R->one());
890                 UniPoly r(a.R);
891                 rem(qk, a, r);
892                 Vec rvec;
893                 for ( size_t j=0; j<n; ++j ) {
894                         rvec.push_back(r[j]);
895                 }
896                 Q.set_row(i, rvec);
897         }
898 }
899
900 static void nullspace(Matrix& M, vector<Vec>& basis)
901 {
902         const size_t n = M.rowsize();
903         const cl_MI one = M(0,0).ring()->one();
904         for ( size_t i=0; i<n; ++i ) {
905                 M(i,i) = M(i,i) - one;
906         }
907         for ( size_t r=0; r<n; ++r ) {
908                 size_t cc = 0;
909                 for ( ; cc<n; ++cc ) {
910                         if ( !zerop(M(r,cc)) ) {
911                                 if ( cc < r ) {
912                                         if ( !zerop(M(cc,cc)) ) {
913                                                 continue;
914                                         }
915                                         M.switch_col(cc, r);
916                                 }
917                                 else if ( cc > r ) {
918                                         M.switch_col(cc, r);
919                                 }
920                                 break;
921                         }
922                 }
923                 if ( cc < n ) {
924                         M.mul_col(r, recip(M(r,r)));
925                         for ( cc=0; cc<n; ++cc ) {
926                                 if ( cc != r ) {
927                                         M.sub_col(cc, r, M(r,cc));
928                                 }
929                         }
930                 }
931         }
932
933         for ( size_t i=0; i<n; ++i ) {
934                 M(i,i) = M(i,i) - one;
935         }
936         for ( size_t i=0; i<n; ++i ) {
937                 if ( !M.is_row_zero(i) ) {
938                         Vec nu(M.row_begin(i), M.row_end(i));
939                         basis.push_back(nu);
940                 }
941         }
942 }
943
944 static void berlekamp(const UniPoly& a, UniPolyVec& upv)
945 {
946         Matrix Q(a.degree(), a.degree(), a.R->zero());
947         q_matrix(a, Q);
948         VecVec nu;
949         nullspace(Q, nu);
950         const unsigned int k = nu.size();
951         if ( k == 1 ) {
952                 return;
953         }
954
955         list<UniPoly> factors;
956         factors.push_back(a);
957         unsigned int size = 1;
958         unsigned int r = 1;
959         unsigned int q = cl_I_to_uint(a.R->modulus);
960
961         list<UniPoly>::iterator u = factors.begin();
962
963         while ( true ) {
964                 for ( unsigned int s=0; s<q; ++s ) {
965                         UniPoly g(a.R);
966                         UniPoly nur(a.R, nu[r]);
967                         nur.set(0, nur[0] - cl_MI(a.R, s));
968                         gcd(nur, *u, g);
969                         if ( !is_one(g) && g != *u ) {
970                                 UniPoly uo(a.R);
971                                 div(*u, g, uo);
972                                 if ( is_one(uo) ) {
973                                         throw logic_error("berlekamp: unexpected divisor.");
974                                 }
975                                 else {
976                                         *u = uo;
977                                 }
978                                 factors.push_back(g);
979                                 size = 0;
980                                 list<UniPoly>::const_iterator i = factors.begin(), end = factors.end();
981                                 while ( i != end ) {
982                                         if ( i->degree() ) ++size; 
983                                         ++i;
984                                 }
985                                 if ( size == k ) {
986                                         list<UniPoly>::const_iterator i = factors.begin(), end = factors.end();
987                                         while ( i != end ) {
988                                                 upv.push_back(*i++);
989                                         }
990                                         return;
991                                 }
992 //                              if ( u->degree() < nur.degree() ) {
993 //                                      break;
994 //                              }
995                         }
996                 }
997                 if ( ++r == k ) {
998                         r = 1;
999                         ++u;
1000                 }
1001         }
1002 }
1003
1004 static void factor_modular(const UniPoly& p, UniPolyVec& upv)
1005 {
1006         berlekamp(p, upv);
1007         return;
1008 }
1009
1010 static void exteuclid(const UniPoly& a, const UniPoly& b, UniPoly& g, UniPoly& s, UniPoly& t)
1011 {
1012         if ( a.degree() < b.degree() ) {
1013                 exteuclid(b, a, g, t, s);
1014                 return;
1015         }
1016         UniPoly c1(a.R), c2(a.R), d1(a.R), d2(a.R), q(a.R), r(a.R), r1(a.R), r2(a.R);
1017         UniPoly c = a; c.unit_normal();
1018         UniPoly d = b; d.unit_normal();
1019         c1.set(0, a.R->one());
1020         d2.set(0, a.R->one());
1021         while ( !d.zero() ) {
1022                 q.terms.clear();
1023                 div(c, d, q);
1024                 r = c - q * d;
1025                 r1 = c1 - q * d1;
1026                 r2 = c2 - q * d2;
1027                 c = d;
1028                 c1 = d1;
1029                 c2 = d2;
1030                 d = r;
1031                 d1 = r1;
1032                 d2 = r2;
1033         }
1034         g = c; g.unit_normal();
1035         s = c1;
1036         s.divide(a.unit());
1037         s.divide(c.unit());
1038         t = c2;
1039         t.divide(b.unit());
1040         t.divide(c.unit());
1041 }
1042
1043 static ex replace_lc(const ex& poly, const ex& x, const ex& lc)
1044 {
1045         ex r = expand(poly + (lc - poly.lcoeff(x)) * pow(x, poly.degree(x)));
1046         return r;
1047 }
1048
1049 static ex hensel_univar(const ex& a_, const ex& x, unsigned int p, const UniPoly& u1_, const UniPoly& w1_, const ex& gamma_ = 0)
1050 {
1051         ex a = a_;
1052         const cl_modint_ring& R = u1_.R;
1053
1054         // calc bound B
1055         ex maxcoeff;
1056         for ( int i=a.degree(x); i>=a.ldegree(x); --i ) {
1057                 maxcoeff += pow(abs(a.coeff(x, i)),2);
1058         }
1059         cl_I normmc = ceiling1(the<cl_R>(cln::sqrt(ex_to<numeric>(maxcoeff).to_cl_N())));
1060         cl_I maxdegree = (u1_.degree() > w1_.degree()) ? u1_.degree() : w1_.degree();
1061         cl_I B = normmc * expt_pos(cl_I(2), maxdegree);
1062
1063         // step 1
1064         ex alpha = a.lcoeff(x);
1065         ex gamma = gamma_;
1066         if ( gamma == 0 ) {
1067                 gamma = alpha;
1068         }
1069         numeric gamma_ui = ex_to<numeric>(abs(gamma));
1070         a = a * gamma;
1071         UniPoly nu1 = u1_;
1072         nu1.unit_normal();
1073         UniPoly nw1 = w1_;
1074         nw1.unit_normal();
1075         ex phi;
1076         phi = expand(gamma * nu1.to_ex(x));
1077         UniPoly u1(R, phi, x);
1078         phi = expand(alpha * nw1.to_ex(x));
1079         UniPoly w1(R, phi, x);
1080
1081         // step 2
1082         UniPoly s(R), t(R), g(R);
1083         exteuclid(u1, w1, g, s, t);
1084
1085         // step 3
1086         ex u = replace_lc(u1.to_ex(x), x, gamma);
1087         ex w = replace_lc(w1.to_ex(x), x, alpha);
1088         ex e = expand(a - u * w);
1089         numeric modulus = p;
1090         const numeric maxmodulus = 2*numeric(B)*gamma_ui;
1091
1092         // step 4
1093         while ( !e.is_zero() && modulus < maxmodulus ) {
1094                 ex c = e / modulus;
1095                 phi = expand(s.to_ex(x)*c);
1096                 UniPoly sigmatilde(R, phi, x);
1097                 phi = expand(t.to_ex(x)*c);
1098                 UniPoly tautilde(R, phi, x);
1099                 UniPoly q(R), r(R);
1100                 div(sigmatilde, w1, q);
1101                 rem(sigmatilde, w1, r);
1102                 UniPoly sigma = r;
1103                 phi = expand(tautilde.to_ex(x) + q.to_ex(x) * u1.to_ex(x));
1104                 UniPoly tau(R, phi, x);
1105                 u = expand(u + tau.to_ex(x) * modulus);
1106                 w = expand(w + sigma.to_ex(x) * modulus);
1107                 e = expand(a - u * w);
1108                 modulus = modulus * p;
1109         }
1110
1111         // step 5
1112         if ( e.is_zero() ) {
1113                 ex delta = u.content(x);
1114                 u = u / delta;
1115                 w = w / gamma * delta;
1116                 return lst(u, w);
1117         }
1118         else {
1119                 return lst();
1120         }
1121 }
1122
1123 static unsigned int next_prime(unsigned int p)
1124 {
1125         static vector<unsigned int> primes;
1126         if ( primes.size() == 0 ) {
1127                 primes.push_back(3); primes.push_back(5); primes.push_back(7);
1128         }
1129         vector<unsigned int>::const_iterator it = primes.begin();
1130         if ( p >= primes.back() ) {
1131                 unsigned int candidate = primes.back() + 2;
1132                 while ( true ) {
1133                         size_t n = primes.size()/2;
1134                         for ( size_t i=0; i<n; ++i ) {
1135                                 if ( candidate % primes[i] ) continue;
1136                                 candidate += 2;
1137                                 i=-1;
1138                         }
1139                         primes.push_back(candidate);
1140                         if ( candidate > p ) break;
1141                 }
1142                 return candidate;
1143         }
1144         vector<unsigned int>::const_iterator end = primes.end();
1145         for ( ; it!=end; ++it ) {
1146                 if ( *it > p ) {
1147                         return *it;
1148                 }
1149         }
1150         throw logic_error("next_prime: should not reach this point!");
1151 }
1152
1153 class Partition
1154 {
1155 public:
1156         Partition(size_t n_) : n(n_)
1157         {
1158                 k.resize(n, 1);
1159                 k[0] = 0;
1160                 sum = n-1;
1161         }
1162         int operator[](size_t i) const { return k[i]; }
1163         size_t size() const { return n; }
1164         size_t size_first() const { return n-sum; }
1165         size_t size_second() const { return sum; }
1166 #ifdef DEBUGFACTOR
1167         void get() const
1168         {
1169                 for ( size_t i=0; i<k.size(); ++i ) {
1170                         cout << k[i] << " ";
1171                 }
1172                 cout << endl;
1173         }
1174 #endif
1175         bool next()
1176         {
1177                 for ( size_t i=n-1; i>=1; --i ) {
1178                         if ( k[i] ) {
1179                                 --k[i];
1180                                 --sum;
1181                                 return sum > 0;
1182                         }
1183                         ++k[i];
1184                         ++sum;
1185                 }
1186                 return false;
1187         }
1188 private:
1189         size_t n, sum;
1190         vector<int> k;
1191 };
1192
1193 static void split(const UniPolyVec& factors, const Partition& part, UniPoly& a, UniPoly& b)
1194 {
1195         a.set(0, a.R->one());
1196         b.set(0, a.R->one());
1197         for ( size_t i=0; i<part.size(); ++i ) {
1198                 if ( part[i] ) {
1199                         b = b * factors[i];
1200                 }
1201                 else {
1202                         a = a * factors[i];
1203                 }
1204         }
1205 }
1206
1207 struct ModFactors
1208 {
1209         ex poly;
1210         UniPolyVec factors;
1211 };
1212
1213 static ex factor_univariate(const ex& poly, const ex& x)
1214 {
1215         ex unit, cont, prim;
1216         poly.unitcontprim(x, unit, cont, prim);
1217
1218         // determine proper prime
1219         unsigned int p = 3;
1220         cl_modint_ring R = find_modint_ring(p);
1221         while ( true ) {
1222                 if ( irem(ex_to<numeric>(prim.lcoeff(x)), p) != 0 ) {
1223                         UniPoly modpoly(R, prim, x);
1224                         UniFactorVec sqrfree_ufv;
1225                         squarefree(modpoly, sqrfree_ufv);
1226                         if ( sqrfree_ufv.factors.size() == 1 && sqrfree_ufv.factors.front().exp == 1 ) break;
1227                 }
1228                 p = next_prime(p);
1229                 R = find_modint_ring(p);
1230         }
1231
1232         // do modular factorization
1233         UniPoly modpoly(R, prim, x);
1234         UniPolyVec factors;
1235         factor_modular(modpoly, factors);
1236         if ( factors.size() <= 1 ) {
1237                 // irreducible for sure
1238                 return poly;
1239         }
1240
1241         // lift all factor combinations
1242         stack<ModFactors> tocheck;
1243         ModFactors mf;
1244         mf.poly = prim;
1245         mf.factors = factors;
1246         tocheck.push(mf);
1247         ex result = 1;
1248         while ( tocheck.size() ) {
1249                 const size_t n = tocheck.top().factors.size();
1250                 Partition part(n);
1251                 while ( true ) {
1252                         UniPoly a(R), b(R);
1253                         split(tocheck.top().factors, part, a, b);
1254
1255                         ex answer = hensel_univar(tocheck.top().poly, x, p, a, b);
1256                         if ( answer != lst() ) {
1257                                 if ( part.size_first() == 1 ) {
1258                                         if ( part.size_second() == 1 ) {
1259                                                 result *= answer.op(0) * answer.op(1);
1260                                                 tocheck.pop();
1261                                                 break;
1262                                         }
1263                                         result *= answer.op(0);
1264                                         tocheck.top().poly = answer.op(1);
1265                                         for ( size_t i=0; i<n; ++i ) {
1266                                                 if ( part[i] == 0 ) {
1267                                                         tocheck.top().factors.erase(tocheck.top().factors.begin()+i);
1268                                                         break;
1269                                                 }
1270                                         }
1271                                         break;
1272                                 }
1273                                 else if ( part.size_second() == 1 ) {
1274                                         if ( part.size_first() == 1 ) {
1275                                                 result *= answer.op(0) * answer.op(1);
1276                                                 tocheck.pop();
1277                                                 break;
1278                                         }
1279                                         result *= answer.op(1);
1280                                         tocheck.top().poly = answer.op(0);
1281                                         for ( size_t i=0; i<n; ++i ) {
1282                                                 if ( part[i] == 1 ) {
1283                                                         tocheck.top().factors.erase(tocheck.top().factors.begin()+i);
1284                                                         break;
1285                                                 }
1286                                         }
1287                                         break;
1288                                 }
1289                                 else {
1290                                         UniPolyVec newfactors1(part.size_first(), R), newfactors2(part.size_second(), R);
1291                                         UniPolyVec::iterator i1 = newfactors1.begin(), i2 = newfactors2.begin();
1292                                         for ( size_t i=0; i<n; ++i ) {
1293                                                 if ( part[i] ) {
1294                                                         *i2++ = tocheck.top().factors[i];
1295                                                 }
1296                                                 else {
1297                                                         *i1++ = tocheck.top().factors[i];
1298                                                 }
1299                                         }
1300                                         tocheck.top().factors = newfactors1;
1301                                         tocheck.top().poly = answer.op(0);
1302                                         ModFactors mf;
1303                                         mf.factors = newfactors2;
1304                                         mf.poly = answer.op(1);
1305                                         tocheck.push(mf);
1306                                         break;
1307                                 }
1308                         }
1309                         else {
1310                                 if ( !part.next() ) {
1311                                         result *= tocheck.top().poly;
1312                                         tocheck.pop();
1313                                         break;
1314                                 }
1315                         }
1316                 }
1317         }
1318
1319         return unit * cont * result;
1320 }
1321
1322 struct EvalPoint
1323 {
1324         ex x;
1325         int evalpoint;
1326 };
1327
1328 // forward declaration
1329 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);
1330
1331 UniPolyVec multiterm_eea_lift(const UniPolyVec& a, const ex& x, unsigned int p, unsigned int k)
1332 {
1333         DCOUT(multiterm_eea_lift);
1334         DCOUTVAR(a);
1335         DCOUTVAR(p);
1336         DCOUTVAR(k);
1337
1338         const size_t r = a.size();
1339         DCOUTVAR(r);
1340         cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1341         UniPoly fill(R);
1342         UniPolyVec q(r-1, fill);
1343         q[r-2] = a[r-1];
1344         for ( size_t j=r-2; j>=1; --j ) {
1345                 q[j-1] = a[j] * q[j];
1346         }
1347         DCOUTVAR(q);
1348         UniPoly beta(R);
1349         beta.set(0, R->one());
1350         UniPolyVec s;
1351         for ( size_t j=1; j<r; ++j ) {
1352                 DCOUTVAR(j);
1353                 DCOUTVAR(beta);
1354                 vector<ex> mdarg(2);
1355                 mdarg[0] = q[j-1].to_ex(x);
1356                 mdarg[1] = a[j-1].to_ex(x);
1357                 vector<EvalPoint> empty;
1358                 vector<ex> exsigma = multivar_diophant(mdarg, x, beta.to_ex(x), empty, 0, p, k);
1359                 UniPoly sigma1(R, exsigma[0], x);
1360                 UniPoly sigma2(R, exsigma[1], x);
1361                 beta = sigma1;
1362                 s.push_back(sigma2);
1363         }
1364         s.push_back(beta);
1365
1366         DCOUTVAR(s);
1367         DCOUT(END multiterm_eea_lift);
1368         return s;
1369 }
1370
1371 void eea_lift(const UniPoly& a, const UniPoly& b, const ex& x, unsigned int p, unsigned int k, UniPoly& s_, UniPoly& t_)
1372 {
1373         DCOUT(eea_lift);
1374         DCOUTVAR(a);
1375         DCOUTVAR(b);
1376         DCOUTVAR(x);
1377         DCOUTVAR(p);
1378         DCOUTVAR(k);
1379
1380         cl_modint_ring R = find_modint_ring(p);
1381         UniPoly amod(R, a);
1382         UniPoly bmod(R, b);
1383         DCOUTVAR(amod);
1384         DCOUTVAR(bmod);
1385
1386         UniPoly smod(R), tmod(R), g(R);
1387         exteuclid(amod, bmod, g, smod, tmod);
1388         
1389         DCOUTVAR(smod);
1390         DCOUTVAR(tmod);
1391         DCOUTVAR(g);
1392
1393         cl_modint_ring Rpk = find_modint_ring(expt_pos(cl_I(p),k));
1394         UniPoly s(Rpk, smod);
1395         UniPoly t(Rpk, tmod);
1396         DCOUTVAR(s);
1397         DCOUTVAR(t);
1398
1399         cl_I modulus(p);
1400
1401         UniPoly one(Rpk);
1402         one.set(0, Rpk->one());
1403         for ( size_t j=1; j<k; ++j ) {
1404                 UniPoly e = one - a * s - b * t;
1405                 e.divide(modulus);
1406                 UniPoly c(R, e);
1407                 UniPoly sigmabar(R);
1408                 sigmabar = smod * c;
1409                 UniPoly taubar(R);
1410                 taubar = tmod * c;
1411                 UniPoly q(R);
1412                 div(sigmabar, bmod, q);
1413                 UniPoly sigma(R);
1414                 rem(sigmabar, bmod, sigma);
1415                 UniPoly tau(R);
1416                 tau = taubar + q * amod;
1417                 UniPoly sadd(Rpk, sigma);
1418                 cl_MI modmodulus(Rpk, modulus);
1419                 s = s + sadd * modmodulus;
1420                 UniPoly tadd(Rpk, tau);
1421                 t = t + tadd * modmodulus;
1422                 modulus = modulus * p;
1423         }
1424
1425         s_ = s; t_ = t;
1426
1427         DCOUTVAR(s);
1428         DCOUTVAR(t);
1429         DCOUT2(check, a*s + b*t);
1430         DCOUT(END eea_lift);
1431 }
1432
1433 UniPolyVec univar_diophant(const UniPolyVec& a, const ex& x, unsigned int m, unsigned int p, unsigned int k)
1434 {
1435         DCOUT(univar_diophant);
1436         DCOUTVAR(a);
1437         DCOUTVAR(x);
1438         DCOUTVAR(m);
1439         DCOUTVAR(p);
1440         DCOUTVAR(k);
1441
1442         cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1443
1444         const size_t r = a.size();
1445         UniPolyVec result;
1446         if ( r > 2 ) {
1447                 UniPolyVec s = multiterm_eea_lift(a, x, p, k);
1448                 for ( size_t j=0; j<r; ++j ) {
1449                         ex phi = expand(pow(x,m)*s[j].to_ex(x));
1450                         UniPoly bmod(R, phi, x);
1451                         UniPoly buf(R);
1452                         rem(bmod, a[j], buf);
1453                         result.push_back(buf);
1454                 }
1455         }
1456         else {
1457                 UniPoly s(R), t(R);
1458                 eea_lift(a[1], a[0], x, p, k, s, t);
1459                 ex phi = expand(pow(x,m)*s.to_ex(x));
1460                 UniPoly bmod(R, phi, x);
1461                 UniPoly buf(R);
1462                 rem(bmod, a[0], buf);
1463                 result.push_back(buf);
1464                 UniPoly q(R);
1465                 div(bmod, a[0], q);
1466                 phi = expand(pow(x,m)*t.to_ex(x));
1467                 UniPoly t1mod(R, phi, x);
1468                 buf = t1mod + q * a[1];
1469                 result.push_back(buf);
1470         }
1471
1472         DCOUTVAR(result);
1473         DCOUT(END univar_diophant);
1474         return result;
1475 }
1476
1477 struct make_modular_map : public map_function {
1478         cl_modint_ring R;
1479         make_modular_map(const cl_modint_ring& R_) : R(R_) { }
1480         ex operator()(const ex& e)
1481         {
1482                 if ( is_a<add>(e) || is_a<mul>(e) ) {
1483                         return e.map(*this);
1484                 }
1485                 else if ( is_a<numeric>(e) ) {
1486                         numeric mod(R->modulus);
1487                         numeric halfmod = (mod-1)/2;
1488                         cl_MI emod = R->canonhom(the<cl_I>(ex_to<numeric>(e).to_cl_N()));
1489                         numeric n(R->retract(emod));
1490                         if ( n > halfmod ) {
1491                                 return n-mod;
1492                         }
1493                         else {
1494                                 return n;
1495                         }
1496                 }
1497                 return e;
1498         }
1499 };
1500
1501 static ex make_modular(const ex& e, const cl_modint_ring& R)
1502 {
1503         make_modular_map map(R);
1504         return map(e);
1505 }
1506
1507 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)
1508 {
1509         vector<ex> a = a_;
1510
1511         DCOUT(multivar_diophant);
1512 #ifdef DEBUGFACTOR
1513         cout << "a ";
1514         for ( size_t i=0; i<a.size(); ++i ) {
1515                 cout << a[i] << " ";
1516         }
1517         cout << endl;
1518 #endif
1519         DCOUTVAR(x);
1520         DCOUTVAR(c);
1521 #ifdef DEBUGFACTOR
1522         cout << "I ";
1523         for ( size_t i=0; i<I.size(); ++i ) {
1524                 cout << I[i].x << "=" << I[i].evalpoint << " ";
1525         }
1526         cout << endl;
1527 #endif
1528         DCOUTVAR(d);
1529         DCOUTVAR(p);
1530         DCOUTVAR(k);
1531
1532         const cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),k));
1533         const size_t r = a.size();
1534         const size_t nu = I.size() + 1;
1535         DCOUTVAR(r);
1536         DCOUTVAR(nu);
1537
1538         vector<ex> sigma;
1539         if ( nu > 1 ) {
1540                 ex xnu = I.back().x;
1541                 int alphanu = I.back().evalpoint;
1542
1543                 ex A = 1;
1544                 for ( size_t i=0; i<r; ++i ) {
1545                         A *= a[i];
1546                 }
1547                 vector<ex> b(r);
1548                 for ( size_t i=0; i<r; ++i ) {
1549                         b[i] = normal(A / a[i]);
1550                 }
1551
1552                 vector<ex> anew = a;
1553                 for ( size_t i=0; i<r; ++i ) {
1554                         anew[i] = anew[i].subs(xnu == alphanu);
1555                 }
1556                 ex cnew = c.subs(xnu == alphanu);
1557                 vector<EvalPoint> Inew = I;
1558                 Inew.pop_back();
1559                 sigma = multivar_diophant(anew, x, cnew, Inew, d, p, k);
1560                 DCOUTVAR(sigma);
1561
1562                 ex buf = c;
1563                 for ( size_t i=0; i<r; ++i ) {
1564                         buf -= sigma[i] * b[i];
1565                 }
1566                 ex e = buf;
1567                 e = make_modular(e, R);
1568
1569                 e = e.expand();
1570                 DCOUTVAR(e);
1571                 DCOUTVAR(d);
1572                 ex monomial = 1;
1573                 for ( size_t m=1; m<=d; ++m ) {
1574                         DCOUTVAR(m);
1575                         while ( !e.is_zero() && e.has(xnu) ) {
1576                                 monomial *= (xnu - alphanu);
1577                                 monomial = expand(monomial);
1578                                 DCOUTVAR(xnu);
1579                                 DCOUTVAR(alphanu);
1580                                 ex cm = e.diff(ex_to<symbol>(xnu), m).subs(xnu==alphanu) / factorial(m);
1581                                 DCOUTVAR(cm);
1582                                 if ( !cm.is_zero() ) {
1583                                         vector<ex> delta_s = multivar_diophant(anew, x, cm, Inew, d, p, k);
1584                                         DCOUTVAR(delta_s);
1585                                         ex buf = e;
1586                                         for ( size_t j=0; j<delta_s.size(); ++j ) {
1587                                                 delta_s[j] *= monomial;
1588                                                 sigma[j] += delta_s[j];
1589                                                 buf -= delta_s[j] * b[j];
1590                                         }
1591                                         e = buf.expand();
1592                                         e = make_modular(e, R);
1593                                 }
1594                         }
1595                 }
1596         }
1597         else {
1598                 DCOUT(uniterm left);
1599                 UniPolyVec amod;
1600                 for ( size_t i=0; i<a.size(); ++i ) {
1601                         UniPoly up(R, a[i], x);
1602                         amod.push_back(up);
1603                 }
1604
1605                 sigma.insert(sigma.begin(), r, 0);
1606                 size_t nterms;
1607                 ex z;
1608                 if ( is_a<add>(c) ) {
1609                         nterms = c.nops();
1610                         z = c.op(0);
1611                 }
1612                 else {
1613                         nterms = 1;
1614                         z = c;
1615                 }
1616                 DCOUTVAR(nterms);
1617                 for ( size_t i=0; i<nterms; ++i ) {
1618                         DCOUTVAR(z);
1619                         int m = z.degree(x);
1620                         DCOUTVAR(m);
1621                         cl_I cm = the<cl_I>(ex_to<numeric>(z.lcoeff(x)).to_cl_N());
1622                         DCOUTVAR(cm);
1623                         UniPolyVec delta_s = univar_diophant(amod, x, m, p, k);
1624                         cl_MI modcm;
1625                         cl_I poscm = cm;
1626                         while ( poscm < 0 ) {
1627                                 poscm = poscm + expt_pos(cl_I(p),k);
1628                         }
1629                         modcm = cl_MI(R, poscm);
1630                         DCOUTVAR(modcm);
1631                         for ( size_t j=0; j<delta_s.size(); ++j ) {
1632                                 delta_s[j] = delta_s[j] * modcm;
1633                                 sigma[j] = sigma[j] + delta_s[j].to_ex(x);
1634                         }
1635                         DCOUTVAR(delta_s);
1636 #ifdef DEBUGFACTOR
1637                         cout << "STEP " << i << " sigma ";
1638                         for ( size_t p=0; p<sigma.size(); ++p ) {
1639                                 cout << sigma[p] << " ";
1640                         }
1641                         cout << endl;
1642 #endif
1643                         if ( nterms > 1 ) {
1644                                 z = c.op(i+1);
1645                         }
1646                 }
1647         }
1648 #ifdef DEBUGFACTOR
1649         cout << "sigma ";
1650         for ( size_t i=0; i<sigma.size(); ++i ) {
1651                 cout << sigma[i] << " ";
1652         }
1653         cout << endl;
1654 #endif
1655
1656         for ( size_t i=0; i<sigma.size(); ++i ) {
1657                 sigma[i] = make_modular(sigma[i], R);
1658         }
1659
1660 #ifdef DEBUGFACTOR
1661         cout << "sigma ";
1662         for ( size_t i=0; i<sigma.size(); ++i ) {
1663                 cout << sigma[i] << " ";
1664         }
1665         cout << endl;
1666 #endif
1667         DCOUT(END multivar_diophant);
1668         return sigma;
1669 }
1670
1671 #ifdef DEBUGFACTOR
1672 ostream& operator<<(ostream& o, const vector<EvalPoint>& v)
1673 {
1674         for ( size_t i=0; i<v.size(); ++i ) {
1675                 o << "(" << v[i].x << "==" << v[i].evalpoint << ") ";
1676         }
1677         return o;
1678 }
1679 #endif // def DEBUGFACTOR
1680
1681
1682 ex hensel_multivar(const ex& a, const ex& x, const vector<EvalPoint>& I, unsigned int p, const cl_I& l, const UniPolyVec& u, const vector<ex>& lcU)
1683 {
1684         DCOUT(hensel_multivar);
1685         DCOUTVAR(a);
1686         DCOUTVAR(x);
1687         DCOUTVAR(I);
1688         DCOUTVAR(p);
1689         DCOUTVAR(l);
1690         DCOUTVAR(u);
1691         DCOUTVAR(lcU);
1692         const size_t nu = I.size() + 1;
1693         const cl_modint_ring R = find_modint_ring(expt_pos(cl_I(p),l));
1694
1695         DCOUTVAR(nu);
1696         
1697         vector<ex> A(nu);
1698         A[nu-1] = a;
1699
1700         for ( size_t j=nu; j>=2; --j ) {
1701                 ex x = I[j-2].x;
1702                 int alpha = I[j-2].evalpoint;
1703                 A[j-2] = A[j-1].subs(x==alpha);
1704                 A[j-2] = make_modular(A[j-2], R);
1705         }
1706
1707 #ifdef DEBUGFACTOR
1708         cout << "A ";
1709         for ( size_t i=0; i<A.size(); ++i) cout << A[i] << " ";
1710         cout << endl;
1711 #endif
1712
1713         int maxdeg = a.degree(I.front().x);
1714         for ( size_t i=1; i<I.size(); ++i ) {
1715                 int maxdeg2 = a.degree(I[i].x);
1716                 if ( maxdeg2 > maxdeg ) maxdeg = maxdeg2;
1717         }
1718         DCOUTVAR(maxdeg);
1719
1720         const size_t n = u.size();
1721         DCOUTVAR(n);
1722         vector<ex> U(n);
1723         for ( size_t i=0; i<n; ++i ) {
1724                 U[i] = u[i].to_ex(x);
1725         }
1726 #ifdef DEBUGFACTOR
1727         cout << "U ";
1728         for ( size_t i=0; i<U.size(); ++i) cout << U[i] << " ";
1729         cout << endl;
1730 #endif
1731
1732         for ( size_t j=2; j<=nu; ++j ) {
1733                 DCOUTVAR(j);
1734                 vector<ex> U1 = U;
1735                 ex monomial = 1;
1736                 DCOUTVAR(U);
1737                 for ( size_t m=0; m<n; ++m) {
1738                         if ( lcU[m] != 1 ) {
1739                                 ex coef = lcU[m];
1740                                 for ( size_t i=j-1; i<nu-1; ++i ) {
1741                                         coef = coef.subs(I[i].x == I[i].evalpoint);
1742                                 }
1743                                 coef = expand(coef);
1744                                 coef = make_modular(coef, R);
1745                                 int deg = U[m].degree(x);
1746                                 U[m] = U[m] - U[m].lcoeff(x) * pow(x,deg) + coef * pow(x,deg);
1747                         }
1748                 }
1749                 DCOUTVAR(U);
1750                 ex Uprod = 1;
1751                 for ( size_t i=0; i<n; ++i ) {
1752                         Uprod *= U[i];
1753                 }
1754                 ex e = expand(A[j-1] - Uprod);
1755                 DCOUTVAR(e);
1756
1757                 vector<EvalPoint> newI;
1758                 for ( size_t i=1; i<=j-2; ++i ) {
1759                         newI.push_back(I[i-1]);
1760                 }
1761                 DCOUTVAR(newI);
1762
1763                 ex xj = I[j-2].x;
1764                 int alphaj = I[j-2].evalpoint;
1765                 size_t deg = A[j-1].degree(xj);
1766                 DCOUTVAR(deg);
1767                 for ( size_t k=1; k<=deg; ++k ) {
1768                         DCOUTVAR(k);
1769                         if ( !e.is_zero() ) {
1770                                 DCOUTVAR(xj);
1771                                 DCOUTVAR(alphaj);
1772                                 monomial *= (xj - alphaj);
1773                                 monomial = expand(monomial);
1774                                 DCOUTVAR(monomial);
1775                                 ex dif = e.diff(ex_to<symbol>(xj), k);
1776                                 DCOUTVAR(dif);
1777                                 ex c = dif.subs(xj==alphaj) / factorial(k);
1778                                 DCOUTVAR(c);
1779                                 if ( !c.is_zero() ) {
1780                                         vector<ex> deltaU = multivar_diophant(U1, x, c, newI, maxdeg, p, cl_I_to_uint(l));
1781                                         for ( size_t i=0; i<n; ++i ) {
1782                                                 DCOUTVAR(i);
1783                                                 DCOUTVAR(deltaU[i]);
1784                                                 deltaU[i] *= monomial;
1785                                                 U[i] += deltaU[i];
1786                                                 U[i] = make_modular(U[i], R);
1787                                                 U[i] = U[i].expand();
1788                                                 DCOUTVAR(U[i]);
1789                                         }
1790                                         ex Uprod = 1;
1791                                         for ( size_t i=0; i<n; ++i ) {
1792                                                 Uprod *= U[i];
1793                                         }
1794                                         DCOUTVAR(Uprod.expand());
1795                                         DCOUTVAR(A[j-1]);
1796                                         e = expand(A[j-1] - Uprod);
1797                                         e = make_modular(e, R);
1798                                         DCOUTVAR(e);
1799                                 }
1800                                 else {
1801                                         break;
1802                                 }
1803                         }
1804                 }
1805         }
1806
1807         ex acand = 1;
1808         for ( size_t i=0; i<U.size(); ++i ) {
1809                 acand *= U[i];
1810         }
1811         DCOUTVAR(acand);
1812         if ( expand(a-acand).is_zero() ) {
1813                 lst res;
1814                 for ( size_t i=0; i<U.size(); ++i ) {
1815                         res.append(U[i]);
1816                 }
1817                 DCOUTVAR(res);
1818                 DCOUT(END hensel_multivar);
1819                 return res;
1820         }
1821         else {
1822                 lst res;
1823                 DCOUTVAR(res);
1824                 DCOUT(END hensel_multivar);
1825                 return lst();
1826         }
1827 }
1828
1829 static ex put_factors_into_lst(const ex& e)
1830 {
1831         DCOUT(put_factors_into_lst);
1832         DCOUTVAR(e);
1833
1834         lst result;
1835
1836         if ( is_a<numeric>(e) ) {
1837                 result.append(e);
1838                 DCOUT(END put_factors_into_lst);
1839                 DCOUTVAR(result);
1840                 return result;
1841         }
1842         if ( is_a<power>(e) ) {
1843                 result.append(1);
1844                 result.append(e.op(0));
1845                 result.append(e.op(1));
1846                 DCOUT(END put_factors_into_lst);
1847                 DCOUTVAR(result);
1848                 return result;
1849         }
1850         if ( is_a<symbol>(e) || is_a<add>(e) ) {
1851                 result.append(1);
1852                 result.append(e);
1853                 result.append(1);
1854                 DCOUT(END put_factors_into_lst);
1855                 DCOUTVAR(result);
1856                 return result;
1857         }
1858         if ( is_a<mul>(e) ) {
1859                 ex nfac = 1;
1860                 for ( size_t i=0; i<e.nops(); ++i ) {
1861                         ex op = e.op(i);
1862                         if ( is_a<numeric>(op) ) {
1863                                 nfac = op;
1864                         }
1865                         if ( is_a<power>(op) ) {
1866                                 result.append(op.op(0));
1867                                 result.append(op.op(1));
1868                         }
1869                         if ( is_a<symbol>(op) || is_a<add>(op) ) {
1870                                 result.append(op);
1871                                 result.append(1);
1872                         }
1873                 }
1874                 result.prepend(nfac);
1875                 DCOUT(END put_factors_into_lst);
1876                 DCOUTVAR(result);
1877                 return result;
1878         }
1879         throw runtime_error("put_factors_into_lst: bad term.");
1880 }
1881
1882 #ifdef DEBUGFACTOR
1883 ostream& operator<<(ostream& o, const vector<numeric>& v)
1884 {
1885         for ( size_t i=0; i<v.size(); ++i ) {
1886                 o << v[i] << " ";
1887         }
1888         return o;
1889 }
1890 #endif // def DEBUGFACTOR
1891
1892 static bool checkdivisors(const lst& f, vector<numeric>& d)
1893 {
1894         DCOUT(checkdivisors);
1895         const int k = f.nops()-2;
1896         DCOUTVAR(k);
1897         DCOUTVAR(d.size());
1898         numeric q, r;
1899         d[0] = ex_to<numeric>(f.op(0) * f.op(f.nops()-1));
1900         if ( d[0] == 1 && k == 1 && abs(f.op(1)) != 1 ) {
1901                 DCOUT(false);
1902                 DCOUT(END checkdivisors);
1903                 return false;
1904         }
1905         DCOUTVAR(d[0]);
1906         for ( int i=1; i<=k; ++i ) {
1907                 DCOUTVAR(i);
1908                 DCOUTVAR(abs(f.op(i)));
1909                 q = ex_to<numeric>(abs(f.op(i)));
1910                 DCOUTVAR(q);
1911                 for ( int j=i-1; j>=0; --j ) {
1912                         r = d[j];
1913                         DCOUTVAR(r);
1914                         do {
1915                                 r = gcd(r, q);
1916                                 DCOUTVAR(r);
1917                                 q = q/r;
1918                                 DCOUTVAR(q);
1919                         } while ( r != 1 );
1920                         if ( q == 1 ) {
1921                                 DCOUT(true);
1922                                 DCOUT(END checkdivisors);
1923                                 return true;
1924                         }
1925                 }
1926                 d[i] = q;
1927         }
1928         DCOUT(false);
1929         DCOUT(END checkdivisors);
1930         return false;
1931 }
1932
1933 static bool generate_set(const ex& u, const ex& vn, const exset& syms, const ex& f, const numeric& modulus, vector<numeric>& a, vector<numeric>& d)
1934 {
1935         // computation of d is actually not necessary
1936         DCOUT(generate_set);
1937         DCOUTVAR(u);
1938         DCOUTVAR(vn);
1939         DCOUTVAR(f);
1940         DCOUTVAR(modulus);
1941         const ex& x = *syms.begin();
1942         bool trying = true;
1943         do {
1944                 ex u0 = u;
1945                 ex vna = vn;
1946                 ex vnatry;
1947                 exset::const_iterator s = syms.begin();
1948                 ++s;
1949                 for ( size_t i=0; i<a.size(); ++i ) {
1950                         DCOUTVAR(*s);
1951                         do {
1952                                 a[i] = mod(numeric(rand()), 2*modulus) - modulus;
1953                                 vnatry = vna.subs(*s == a[i]);
1954                         } while ( vnatry == 0 );
1955                         vna = vnatry;
1956                         u0 = u0.subs(*s == a[i]);
1957                         ++s;
1958                 }
1959                 DCOUTVAR(a);
1960                 DCOUTVAR(u0);
1961                 if ( gcd(u0,u0.diff(ex_to<symbol>(x))) != 1 ) {
1962                         continue;
1963                 }
1964                 if ( is_a<numeric>(vn) ) {
1965                         trying = false;
1966                 }
1967                 else {
1968                         DCOUT(do substitution);
1969                         lst fnum;
1970                         lst::const_iterator i = ex_to<lst>(f).begin();
1971                         fnum.append(*i++);
1972                         bool problem = false;
1973                         while ( i!=ex_to<lst>(f).end() ) {
1974                                 ex fs = *i;
1975                                 if ( !is_a<numeric>(fs) ) {
1976                                         s = syms.begin();
1977                                         ++s;
1978                                         for ( size_t j=0; j<a.size(); ++j ) {
1979                                                 fs = fs.subs(*s == a[j]);
1980                                                 ++s;
1981                                         }
1982                                         if ( abs(fs) == 1 ) {
1983                                                 problem = true;
1984                                                 break;
1985                                         }
1986                                 }
1987                                 fnum.append(fs);
1988                                 ++i; ++i;
1989                         }
1990                         if ( problem ) {
1991                                 return true;
1992                         }
1993                         ex con = u0.content(x);
1994                         fnum.append(con);
1995                         DCOUTVAR(fnum);
1996                         trying = checkdivisors(fnum, d);
1997                 }
1998         } while ( trying );
1999         DCOUT(END generate_set);
2000         return false;
2001 }
2002
2003 static ex factor_multivariate(const ex& poly, const exset& syms)
2004 {
2005         DCOUT(factor_multivariate);
2006         DCOUTVAR(poly);
2007
2008         exset::const_iterator s;
2009         const ex& x = *syms.begin();
2010         DCOUTVAR(x);
2011
2012         /* make polynomial primitive */
2013         ex p = poly.expand().collect(x);
2014         DCOUTVAR(p);
2015         ex cont = p.lcoeff(x);
2016         for ( numeric i=p.degree(x)-1; i>=p.ldegree(x); --i ) {
2017                 cont = gcd(cont, p.coeff(x,ex_to<numeric>(i).to_int()));
2018                 if ( cont == 1 ) break;
2019         }
2020         DCOUTVAR(cont);
2021         ex pp = expand(normal(p / cont));
2022         DCOUTVAR(pp);
2023         if ( !is_a<numeric>(cont) ) {
2024 #ifdef DEBUGFACTOR
2025                 return ::factor(cont) * ::factor(pp);
2026 #else
2027                 return factor(cont) * factor(pp);
2028 #endif
2029         }
2030
2031         /* factor leading coefficient */
2032         pp = pp.collect(x);
2033         ex vn = pp.lcoeff(x);
2034         pp = pp.expand();
2035         ex vnlst;
2036         if ( is_a<numeric>(vn) ) {
2037                 vnlst = lst(vn);
2038         }
2039         else {
2040 #ifdef DEBUGFACTOR
2041                 ex vnfactors = ::factor(vn);
2042 #else
2043                 ex vnfactors = factor(vn);
2044 #endif
2045                 vnlst = put_factors_into_lst(vnfactors);
2046         }
2047         DCOUTVAR(vnlst);
2048
2049         const numeric maxtrials = 3;
2050         numeric modulus = (vnlst.nops()-1 > 3) ? vnlst.nops()-1 : 3;
2051         DCOUTVAR(modulus);
2052         numeric minimalr = -1;
2053         vector<numeric> a(syms.size()-1, 0);
2054         vector<numeric> d((vnlst.nops()-1)/2+1, 0);
2055
2056         while ( true ) {
2057                 numeric trialcount = 0;
2058                 ex u, delta;
2059                 unsigned int prime;
2060                 size_t factor_count;
2061                 ex ufac;
2062                 ex ufaclst;
2063                 while ( trialcount < maxtrials ) {
2064                         bool problem = generate_set(pp, vn, syms, vnlst, modulus, a, d);
2065                         DCOUTVAR(problem);
2066                         if ( problem ) {
2067                                 ++modulus;
2068                                 continue;
2069                         }
2070                         DCOUTVAR(a);
2071                         DCOUTVAR(d);
2072                         u = pp;
2073                         s = syms.begin();
2074                         ++s;
2075                         for ( size_t i=0; i<a.size(); ++i ) {
2076                                 u = u.subs(*s == a[i]);
2077                                 ++s;
2078                         }
2079                         delta = u.content(x);
2080                         DCOUTVAR(u);
2081
2082                         // determine proper prime
2083                         prime = 3;
2084                         DCOUTVAR(prime);
2085                         cl_modint_ring R = find_modint_ring(prime);
2086                         DCOUTVAR(u.lcoeff(x));
2087                         while ( true ) {
2088                                 if ( irem(ex_to<numeric>(u.lcoeff(x)), prime) != 0 ) {
2089                                         UniPoly modpoly(R, u, x);
2090                                         UniFactorVec sqrfree_ufv;
2091                                         squarefree(modpoly, sqrfree_ufv);
2092                                         DCOUTVAR(sqrfree_ufv);
2093                                         if ( sqrfree_ufv.factors.size() == 1 && sqrfree_ufv.factors.front().exp == 1 ) break;
2094                                 }
2095                                 prime = next_prime(prime);
2096                                 DCOUTVAR(prime);
2097                                 R = find_modint_ring(prime);
2098                         }
2099
2100 #ifdef DEBUGFACTOR
2101                         ufac = ::factor(u);
2102 #else
2103                         ufac = factor(u);
2104 #endif
2105                         DCOUTVAR(ufac);
2106                         ufaclst = put_factors_into_lst(ufac);
2107                         DCOUTVAR(ufaclst);
2108                         factor_count = (ufaclst.nops()-1)/2;
2109                         DCOUTVAR(factor_count);
2110
2111                         if ( factor_count <= 1 ) {
2112                                 DCOUTVAR(poly);
2113                                 DCOUT(END factor_multivariate);
2114                                 return poly;
2115                         }
2116
2117                         if ( minimalr < 0 ) {
2118                                 minimalr = factor_count;
2119                         }
2120                         else if ( minimalr == factor_count ) {
2121                                 ++trialcount;
2122                                 ++modulus;
2123                         }
2124                         else if ( minimalr > factor_count ) {
2125                                 minimalr = factor_count;
2126                                 trialcount = 0;
2127                         }
2128                         DCOUTVAR(trialcount);
2129                         DCOUTVAR(minimalr);
2130                         if ( minimalr <= 1 ) {
2131                                 DCOUTVAR(poly);
2132                                 DCOUT(END factor_multivariate);
2133                                 return poly;
2134                         }
2135                 }
2136
2137                 vector<numeric> ftilde((vnlst.nops()-1)/2+1);
2138                 ftilde[0] = ex_to<numeric>(vnlst.op(0));
2139                 for ( size_t i=1; i<ftilde.size(); ++i ) {
2140                         ex ft = vnlst.op((i-1)*2+1);
2141                         s = syms.begin();
2142                         ++s;
2143                         for ( size_t j=0; j<a.size(); ++j ) {
2144                                 ft = ft.subs(*s == a[j]);
2145                                 ++s;
2146                         }
2147                         ftilde[i] = ex_to<numeric>(ft);
2148                 }
2149                 DCOUTVAR(ftilde);
2150
2151                 vector<bool> used_flag((vnlst.nops()-1)/2+1, false);
2152                 vector<ex> D(factor_count, 1);
2153                 for ( size_t i=0; i<=factor_count; ++i ) {
2154                         DCOUTVAR(i);
2155                         numeric prefac;
2156                         if ( i == 0 ) {
2157                                 prefac = ex_to<numeric>(ufaclst.op(0));
2158                                 ftilde[0] = ftilde[0] / prefac;
2159                                 vnlst.let_op(0) = vnlst.op(0) / prefac;
2160                                 continue;
2161                         }
2162                         else {
2163                                 prefac = ex_to<numeric>(ufaclst.op(2*(i-1)+1).lcoeff(x));
2164                         }
2165                         DCOUTVAR(prefac);
2166                         for ( size_t j=(vnlst.nops()-1)/2+1; j>0; --j ) {
2167                                 DCOUTVAR(j);
2168                                 DCOUTVAR(prefac);
2169                                 DCOUTVAR(ftilde[j-1]);
2170                                 if ( abs(ftilde[j-1]) == 1 ) {
2171                                         used_flag[j-1] = true;
2172                                         continue;
2173                                 }
2174                                 numeric g = gcd(prefac, ftilde[j-1]);
2175                                 DCOUTVAR(g);
2176                                 if ( g != 1 ) {
2177                                         DCOUT(has_common_prime);
2178                                         prefac = prefac / g;
2179                                         numeric count = abs(iquo(g, ftilde[j-1]));
2180                                         DCOUTVAR(count);
2181                                         used_flag[j-1] = true;
2182                                         if ( i > 0 ) {
2183                                                 if ( j == 1 ) {
2184                                                         D[i-1] = D[i-1] * pow(vnlst.op(0), count);
2185                                                 }
2186                                                 else {
2187                                                         D[i-1] = D[i-1] * pow(vnlst.op(2*(j-2)+1), count);
2188                                                 }
2189                                         }
2190                                         else {
2191                                                 ftilde[j-1] = ftilde[j-1] / prefac;
2192                                                 DCOUT(BREAK);
2193                                                 DCOUTVAR(ftilde[j-1]);
2194                                                 break;
2195                                         }
2196                                         ++j;
2197                                 }
2198                         }
2199                 }
2200                 DCOUTVAR(D);
2201
2202                 bool some_factor_unused = false;
2203                 for ( size_t i=0; i<used_flag.size(); ++i ) {
2204                         if ( !used_flag[i] ) {
2205                                 some_factor_unused = true;
2206                                 break;
2207                         }
2208                 }
2209                 if ( some_factor_unused ) {
2210                         DCOUT(some factor unused!);
2211                         continue;
2212                 }
2213
2214                 vector<ex> C(factor_count);
2215                 DCOUTVAR(C);
2216                 DCOUTVAR(delta);
2217                 if ( delta == 1 ) {
2218                         for ( size_t i=0; i<D.size(); ++i ) {
2219                                 ex Dtilde = D[i];
2220                                 s = syms.begin();
2221                                 ++s;
2222                                 for ( size_t j=0; j<a.size(); ++j ) {
2223                                         Dtilde = Dtilde.subs(*s == a[j]);
2224                                         ++s;
2225                                 }
2226                                 DCOUTVAR(Dtilde);
2227                                 C[i] = D[i] * (ufaclst.op(2*i+1).lcoeff(x) / Dtilde);
2228                         }
2229                 }
2230                 else {
2231                         for ( size_t i=0; i<D.size(); ++i ) {
2232                                 ex Dtilde = D[i];
2233                                 s = syms.begin();
2234                                 ++s;
2235                                 for ( size_t j=0; j<a.size(); ++j ) {
2236                                         Dtilde = Dtilde.subs(*s == a[j]);
2237                                         ++s;
2238                                 }
2239                                 ex ui;
2240                                 if ( i == 0 ) {
2241                                         ui = ufaclst.op(0);
2242                                 }
2243                                 else {
2244                                         ui = ufaclst.op(2*(i-1)+1);
2245                                 }
2246                                 while ( true ) {
2247                                         ex d = gcd(ui.lcoeff(x), Dtilde);
2248                                         C[i] = D[i] * ( ui.lcoeff(x) / d );
2249                                         ui = ui * ( Dtilde[i] / d );
2250                                         delta = delta / ( Dtilde[i] / d );
2251                                         if ( delta == 1 ) break;
2252                                         ui = delta * ui;
2253                                         C[i] = delta * C[i];
2254                                         pp = pp * pow(delta, D.size()-1);
2255                                 }
2256                         }
2257                 }
2258                 DCOUTVAR(C);
2259
2260                 EvalPoint ep;
2261                 vector<EvalPoint> epv;
2262                 s = syms.begin();
2263                 ++s;
2264                 for ( size_t i=0; i<a.size(); ++i ) {
2265                         ep.x = *s++;
2266                         ep.evalpoint = a[i].to_int();
2267                         epv.push_back(ep);
2268                 }
2269                 DCOUTVAR(epv);
2270
2271                 // calc bound B
2272                 ex maxcoeff;
2273                 for ( int i=u.degree(x); i>=u.ldegree(x); --i ) {
2274                         maxcoeff += pow(abs(u.coeff(x, i)),2);
2275                 }
2276                 cl_I normmc = ceiling1(the<cl_R>(cln::sqrt(ex_to<numeric>(maxcoeff).to_cl_N())));
2277                 unsigned int maxdegree = 0;
2278                 for ( size_t i=0; i<factor_count; ++i ) {
2279                         if ( ufaclst[2*i+1].degree(x) > (int)maxdegree ) {
2280                                 maxdegree = ufaclst[2*i+1].degree(x);
2281                         }
2282                 }
2283                 cl_I B = normmc * expt_pos(cl_I(2), maxdegree);
2284                 cl_I l = 1;
2285                 cl_I pl = prime;
2286                 while ( pl < B ) {
2287                         l = l + 1;
2288                         pl = pl * prime;
2289                 }
2290
2291                 UniPolyVec uvec;
2292                 cl_modint_ring R = find_modint_ring(expt_pos(cl_I(prime),l));
2293                 for ( size_t i=0; i<(ufaclst.nops()-1)/2; ++i ) {
2294                         UniPoly newu(R, ufaclst.op(i*2+1), x);
2295                         uvec.push_back(newu);
2296                 }
2297                 DCOUTVAR(uvec);
2298
2299                 ex res = hensel_multivar(ufaclst.op(0)*pp, x, epv, prime, l, uvec, C);
2300                 if ( res != lst() ) {
2301                         ex result = cont * ufaclst.op(0);
2302                         for ( size_t i=0; i<res.nops(); ++i ) {
2303                                 result *= res.op(i).content(x) * res.op(i).unit(x);
2304                                 result *= res.op(i).primpart(x);
2305                         }
2306                         DCOUTVAR(result);
2307                         DCOUT(END factor_multivariate);
2308                         return result;
2309                 }
2310         }
2311 }
2312
2313 struct find_symbols_map : public map_function {
2314         exset syms;
2315         ex operator()(const ex& e)
2316         {
2317                 if ( is_a<symbol>(e) ) {
2318                         syms.insert(e);
2319                         return e;
2320                 }
2321                 return e.map(*this);
2322         }
2323 };
2324
2325 static ex factor_sqrfree(const ex& poly)
2326 {
2327         // determine all symbols in poly
2328         find_symbols_map findsymbols;
2329         findsymbols(poly);
2330         if ( findsymbols.syms.size() == 0 ) {
2331                 return poly;
2332         }
2333
2334         if ( findsymbols.syms.size() == 1 ) {
2335                 // univariate case
2336                 const ex& x = *(findsymbols.syms.begin());
2337                 if ( poly.ldegree(x) > 0 ) {
2338                         int ld = poly.ldegree(x);
2339                         ex res = factor_univariate(expand(poly/pow(x, ld)), x);
2340                         return res * pow(x,ld);
2341                 }
2342                 else {
2343                         ex res = factor_univariate(poly, x);
2344                         return res;
2345                 }
2346         }
2347
2348         // multivariate case
2349         ex res = factor_multivariate(poly, findsymbols.syms);
2350         return res;
2351 }
2352
2353 struct apply_factor_map : public map_function {
2354         unsigned options;
2355         apply_factor_map(unsigned options_) : options(options_) { }
2356         ex operator()(const ex& e)
2357         {
2358                 if ( e.info(info_flags::polynomial) ) {
2359 #ifdef DEBUGFACTOR
2360                         return ::factor(e, options);
2361 #else
2362                         return factor(e, options);
2363 #endif
2364                 }
2365                 if ( is_a<add>(e) ) {
2366                         ex s1, s2;
2367                         for ( size_t i=0; i<e.nops(); ++i ) {
2368                                 if ( e.op(i).info(info_flags::polynomial) ) {
2369                                         s1 += e.op(i);
2370                                 }
2371                                 else {
2372                                         s2 += e.op(i);
2373                                 }
2374                         }
2375                         s1 = s1.eval();
2376                         s2 = s2.eval();
2377 #ifdef DEBUGFACTOR
2378                         return ::factor(s1, options) + s2.map(*this);
2379 #else
2380                         return factor(s1, options) + s2.map(*this);
2381 #endif
2382                 }
2383                 return e.map(*this);
2384         }
2385 };
2386
2387 } // anonymous namespace
2388
2389 #ifdef DEBUGFACTOR
2390 ex factor(const ex& poly, unsigned options = 0)
2391 #else
2392 ex factor(const ex& poly, unsigned options)
2393 #endif
2394 {
2395         // check arguments
2396         if ( !poly.info(info_flags::polynomial) ) {
2397                 if ( options & factor_options::all ) {
2398                         options &= ~factor_options::all;
2399                         apply_factor_map factor_map(options);
2400                         return factor_map(poly);
2401                 }
2402                 return poly;
2403         }
2404
2405         // determine all symbols in poly
2406         find_symbols_map findsymbols;
2407         findsymbols(poly);
2408         if ( findsymbols.syms.size() == 0 ) {
2409                 return poly;
2410         }
2411         lst syms;
2412         exset::const_iterator i=findsymbols.syms.begin(), end=findsymbols.syms.end();
2413         for ( ; i!=end; ++i ) {
2414                 syms.append(*i);
2415         }
2416
2417         // make poly square free
2418         ex sfpoly = sqrfree(poly, syms);
2419
2420         // factorize the square free components
2421         if ( is_a<power>(sfpoly) ) {
2422                 // case: (polynomial)^exponent
2423                 const ex& base = sfpoly.op(0);
2424                 if ( !is_a<add>(base) ) {
2425                         // simple case: (monomial)^exponent
2426                         return sfpoly;
2427                 }
2428                 ex f = factor_sqrfree(base);
2429                 return pow(f, sfpoly.op(1));
2430         }
2431         if ( is_a<mul>(sfpoly) ) {
2432                 // case: multiple factors
2433                 ex res = 1;
2434                 for ( size_t i=0; i<sfpoly.nops(); ++i ) {
2435                         const ex& t = sfpoly.op(i);
2436                         if ( is_a<power>(t) ) {
2437                                 const ex& base = t.op(0);
2438                                 if ( !is_a<add>(base) ) {
2439                                         res *= t;
2440                                 }
2441                                 else {
2442                                         ex f = factor_sqrfree(base);
2443                                         res *= pow(f, t.op(1));
2444                                 }
2445                         }
2446                         else if ( is_a<add>(t) ) {
2447                                 ex f = factor_sqrfree(t);
2448                                 res *= f;
2449                         }
2450                         else {
2451                                 res *= t;
2452                         }
2453                 }
2454                 return res;
2455         }
2456         if ( is_a<symbol>(sfpoly) ) {
2457                 return poly;
2458         }
2459         // case: (polynomial)
2460         ex f = factor_sqrfree(sfpoly);
2461         return f;
2462 }
2463
2464 } // namespace GiNaC