• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tueda / form / 15241916852

25 May 2025 08:59PM UTC coverage: 47.908% (-2.8%) from 50.743%
15241916852

push

github

tueda
ci: build arm64-windows binaries

39009 of 81425 relevant lines covered (47.91%)

1079780.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

79.18
/sources/polyfact.cc
1
/** @file polyfact.cc
2
 *
3
 *   Contains the routines for factorizing multivariate polynomials
4
 */
5
/* #[ License : */
6
/*
7
 *   Copyright (C) 1984-2023 J.A.M. Vermaseren
8
 *   When using this file you are requested to refer to the publication
9
 *   J.A.M.Vermaseren "New features of FORM" math-ph/0010025
10
 *   This is considered a matter of courtesy as the development was paid
11
 *   for by FOM the Dutch physics granting agency and we would like to
12
 *   be able to track its scientific use to convince FOM of its value
13
 *   for the community.
14
 *
15
 *   This file is part of FORM.
16
 *
17
 *   FORM is free software: you can redistribute it and/or modify it under the
18
 *   terms of the GNU General Public License as published by the Free Software
19
 *   Foundation, either version 3 of the License, or (at your option) any later
20
 *   version.
21
 *
22
 *   FORM is distributed in the hope that it will be useful, but WITHOUT ANY
23
 *   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
24
 *   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
25
 *   details.
26
 *
27
 *   You should have received a copy of the GNU General Public License along
28
 *   with FORM.  If not, see <http://www.gnu.org/licenses/>.
29
 */
30
/* #] License : */ 
31
/*
32
          #[ include :
33
*/
34

35
#include "poly.h"
36
#include "polygcd.h"
37
#include "polyfact.h"
38

39
#include <cmath>
40
#include <vector>
41
#include <iostream>
42
#include <algorithm>
43
#include <climits>
44

45
//#define DEBUG
46

47
#ifdef DEBUG
48
#include "mytime.h"
49
#endif
50

51
using namespace std;
52

53
/*
54
          #] include : 
55
          #[ tostring :
56
*/
57

58
// Turns a factorized_poly into a readable string
59
const string factorized_poly::tostring () const {
×
60
        
61
        // empty
62
        if (factor.size()==0) 
×
63
                return "no_factors";
×
64

65
        string res;
×
66
        
67
        // polynomial
68
        for (int i=0; i<(int)factor.size(); i++) {
×
69
                if (i>0) res += "*";
×
70
                res += "(";
×
71
                res += poly(factor[i],0,1).to_string();
×
72
                res += ")";
×
73
                if (power[i]>1) {
×
74
                        res += "^";
×
75
                        char tmp[100];
×
76
                        snprintf (tmp,100,"%i",power[i]);
×
77
                        res += tmp;
×
78
                }
79
        }
80

81
        // modulo p^n
82
        if (factor[0].modp>0) {
×
83
                res += " (mod ";
×
84
                char tmp[12];
×
85
                snprintf (tmp,12,"%i",factor[0].modp);
×
86
                res += tmp;
×
87
                if (factor[0].modn > 1) {
×
88
                        snprintf (tmp,12,"%i",factor[0].modn);
×
89
                        res += "^";
×
90
                        res += tmp;
×
91
                }
92
                res += ")";
×
93
        }                        
94
        
95
        return res;
×
96
}
×
97

98
/*
99
          #] tostring : 
100
          #[ ostream operator :
101
*/
102

103
// ostream operator for outputting a factorized_poly
104
ostream& operator<< (ostream &out, const factorized_poly &a) {
×
105
        return out << a.tostring();
×
106
}
107

108
// ostream operator for outputting a vector<T>
109
template<class T> ostream& operator<< (ostream &out, const vector<T> &v) {
110
        out<<"{";
111
        for (int i=0; i<(int)v.size(); i++) {
112
                if (i>0) out<<",";
113
                out<<v[i];
114
        }
115
        out<<"}";
116
        return out;                        
117
}
118

119
/*
120
          #] ostream operator : 
121
          #[ add_factor :
122
*/
123

124
// adds a factor f^p to a factorization
125
void factorized_poly::add_factor(const poly &f, int p) {
303✔
126
        factor.push_back(f);
303✔
127
        power.push_back(p);
303✔
128
}
303✔
129

130
/*
131
          #] add_factor : 
132
          #[ extended_gcd_Euclidean_lifted :
133
*/
134

135
/**  Lifted Extended Euclidean Algorithm
136
 *
137
 *   Description
138
 *   ===========
139
 *   Returns s(x) and t(x) such that
140
 *
141
 *     s(x)*a(x) + t(x)*b(x) = 1 (mod p^n),
142
 *
143
 *   with a(x) and b(x) univariate polynomials.
144
 *
145
 *   Notes
146
 *   =====
147
 *   - The lifting part works only when a and b are relative prime;
148
 *     otherwise the method might crash/hang.
149
 *
150
 *   [for details, see "Algorithms for Computer Algebra", pp. 32-37, 205-225]
151
 */
152
const vector<poly> polyfact::extended_gcd_Euclidean_lifted (const poly &a, const poly &b) {
1,035✔
153

154
#ifdef DEBUGALL
155
        cout << "*** [" << thetime() << "]  CALL: extended_Euclidean_lifted("<<a<<","<<b<<")"<<endl;
156
#endif
157

158
        POLY_GETIDENTITY(a);
1,035✔
159
        
160
        // Calculate s,t,gcd (mod p) with the Extended Euclidean Algorithm.
161
        poly s(a,a.modp,1);
1,035✔
162
        poly t(b,b.modp,1);
1,035✔
163
        poly sa(BHEAD 1,a.modp,1);
1,035✔
164
        poly sb(BHEAD 0,b.modp,1);
1,035✔
165
        poly ta(BHEAD 0,a.modp,1);
1,035✔
166
        poly tb(BHEAD 1,b.modp,1);
1,035✔
167
        
168
        while (!t.is_zero()) {
4,695✔
169
                poly x(s/t);
3,660✔
170
                swap(s -=x*t , t);
3,660✔
171
                swap(sa-=x*ta, ta);
3,660✔
172
                swap(sb-=x*tb, tb);
3,660✔
173
        }
3,660✔
174

175
        // Normalize the result.
176
        sa /= s.integer_lcoeff();
1,035✔
177
        sb /= s.integer_lcoeff();
1,035✔
178

179
        // Lift the result to modulo p^n with p-adic Newton's iteration.
180
        poly samodp(sa);
1,035✔
181
        poly sbmodp(sb);
1,035✔
182
        poly term(BHEAD 1);
1,035✔
183

184
        sa.setmod(0,1);
1,035✔
185
        sb.setmod(0,1);
1,035✔
186

187
        poly amodp(a,a.modp,1);
1,035✔
188
        poly bmodp(b,a.modp,1);        
1,035✔
189
        poly error(poly(BHEAD 1) - sa*a - sb*b);
1,035✔
190
        poly p(BHEAD a.modp);
1,035✔
191
        
192
        for (int n=1; n<a.modn && !error.is_zero(); n++) {
17,459✔
193
                error /= p;
16,424✔
194
                term *= p;
16,424✔
195
                poly errormodp(error,a.modp,1);
16,424✔
196
                poly dsa((samodp * errormodp) % bmodp);
16,424✔
197
                // equivalent, but faster than the symmetric
198
                // poly dsb((sbmodp * errormodp) % amodp);
199
                poly dsb((errormodp - dsa*amodp) / bmodp);
16,424✔
200
                sa += term * dsa;
16,424✔
201
                sb += term * dsb;
16,424✔
202
                error -= a*dsa + b*dsb;
16,424✔
203
        }
16,424✔
204

205
        sa.setmod(a.modp,a.modn);
1,035✔
206
        sb.setmod(a.modp,a.modn);
1,035✔
207
        
208
        // Output the result
209
        vector<poly> res;
1,035✔
210
        res.push_back(sa);
1,035✔
211
        res.push_back(sb);
1,035✔
212

213
#ifdef DEBUGALL
214
        cout << "*** [" << thetime() << "]  RES : extended_Euclidean_lifted("<<a<<","<<b<<") = "<<res<<endl;
215
#endif
216

217
        return res;
1,035✔
218
}
1,035✔
219

220
/*
221
          #] extended_gcd_Euclidean_lifted : 
222
          #[ solve_Diophantine_univariate :
223
*/
224

225
/**  Univariate Diophantine equation solver modulo a prime power
226
 *
227
 *   Description
228
 *   ===========
229
 *   Method for solving the Diophantine equation
230
 *
231
 *     s1*A1 + ... + sk*Ak = b (mod p^n)
232
 *
233
 *   The input a1,...,ak and b consists of univariate polynomials
234
 *   and Ai = product(aj|j!=i). The solution si consists therefore of
235
 *   univariate polynomials as well.
236
 *
237
 *   When deg(c) < sum(deg(ai)), the result is the unique result with
238
 *   deg(si) < deg(ai) for all i. This is necessary for the Hensel
239
 *   construction.
240
 *
241
 *   The equation is solved by iteratively solving the following
242
 *   two-term equations with the Extended Euclidean Algorithm:
243
 *
244
 *     B0(x) = 1
245
 *     Bj(x) * aj(x) + sj(x) * product(ai(x) | i=j+1,...,r) = B{j-1}(x)
246
 *     sk(x) = B{k-1}(x)
247
 *
248
 *   Substitution proves that this solution is indeed correct.
249
 *
250
 *   Notes
251
 *   =====
252
 *   - The ai must be pairwise relatively prime modulo p.
253
 *
254
 *   [for details, see "Algorithms for Computer Algebra", pp. 266-273]
255
 */
256
const vector<poly> polyfact::solve_Diophantine_univariate (const vector<poly> &a, const poly &b) {
351✔
257

258
#ifdef DEBUGALL
259
        cout << "*** [" << thetime() << "]  CALL: solve_Diophantine_univariate(" <<a<<","<<b<<")"<<endl;
260
#endif
261

262
        POLY_GETIDENTITY(b);
351✔
263
        
264
        vector<poly> s(1,b);
351✔
265
        
266
        for (int i=0; i+1<(int)a.size(); i++) {
1,386✔
267
                poly A(BHEAD 1,b.modp,b.modn);
1,035✔
268
                for (int j=i+1; j<(int)a.size(); j++) A *= a[j];
5,745✔
269
                
270
                vector<poly> t(extended_gcd_Euclidean_lifted(a[i],A));
1,035✔
271
                poly prev(s.back());
1,035✔
272
                s.back() = t[1] * prev % a[i];
1,035✔
273
                s.push_back(t[0] * prev % A);
1,035✔
274
        }
1,035✔
275

276
#ifdef DEBUGALL
277
        cout << "*** [" << thetime() << "]  RES : solve_Diophantine_univariate(" <<a<<","<<b<<") = "<<s<<endl;
278
#endif
279
        
280
        return s;
351✔
281
}
×
282

283
/*
284
          #] solve_Diophantine_univariate : 
285
          #[ solve_Diophantine_multivariate :
286
*/
287

288
/**  Multivariate Diophantine equation solver modulo a prime power
289
 *
290
 *   Description
291
 *   ===========
292
 *   Method for solving the Diophantine equation
293
 *
294
 *     s1*A1 + ... + sk*Ak = b
295
 *
296
 *   modulo <p^n,I^d>, with the ideal I=<x2-c1,...,xm-c{m-1}>. The
297
 *   input a1,...,ak and b consists of multivariate polynomials and
298
 *   Ai = product(aj|j!=i). The solution si consists therefore of
299
 *   multivariate polynomials as well.
300
 *
301
 *   When deg(c,x1) < sum(deg(ai,x1)), the result is the unique result
302
 *   with deg(si,x1) < deg(ai,x1) for all i. This is necessary for the
303
 *   Hensel construction.
304
 *
305
 *   The equation is solved in the following way:
306
 *   - reduce with the homomorphism <xm-c{m-1}>
307
 *   - solve the equation in one less variable
308
 *   - use ideal-adic Newton's iteration to add the xm-terms.
309
 *
310
 *   Notes
311
 *   =====
312
 *   - The ai must be pairwise relatively prime modulo <I,p>.
313
 *   - The method returns an empty vector<poly>() iff the
314
 *     Diophantine equation has no solution (typically happens in
315
 *     gcd calculations with unlucky reductions).
316
 *
317
 *   [for details, see "Algorithms for Computer Algebra", pp. 264-273]
318
 */
319
const vector<poly> polyfact::solve_Diophantine_multivariate (const vector<poly> &a, const poly &b, const vector<int> &x, const vector<int> &c, int d) {
6,345✔
320
        
321
#ifdef DEBUGALL
322
        cout << "*** [" << thetime() << "]  CALL: solve_Diophantine_multivariate(" <<a<<","<<b<<","<<x<<","<<c<<","<<d<<")"<<endl;
323
#endif
324
        
325
        POLY_GETIDENTITY(b);
6,345✔
326
        
327
        if (b.is_zero()) return vector<poly>(a.size(),poly(BHEAD 0));
6,345✔
328

329
        if (x.size() == 1) return solve_Diophantine_univariate(a,b);
6,345✔
330

331
        // Reduce the polynomial with the homomorphism <xm-c{m-1}>
332
        poly simple(poly::simple_poly(BHEAD x.back(),c.back()));
6,048✔
333
        
334
        vector<poly> ared (a);
6,048✔
335
        for (int i=0; i<(int)ared.size(); i++)
18,144✔
336
                ared[i] %= simple;
12,096✔
337
                
338
        poly bred(b % simple);
6,048✔
339
        vector<int> xred(x.begin(),x.end()-1);
6,048✔
340
        vector<int> cred(c.begin(),c.end()-1);
6,048✔
341

342
        // Solve the equation in one less variable
343
        vector<poly> s(solve_Diophantine_multivariate(ared,bred,xred,cred,d));
6,048✔
344
        if (s == vector<poly>()) return vector<poly>();
6,048✔
345

346
        // Cache the Ai = product(aj | j!=i).
347
        vector<poly> A(a.size(), poly(BHEAD 1,b.modp,b.modn));
6,048✔
348
        for (int i=0; i<(int)a.size(); i++) 
18,144✔
349
                for (int j=0; j<(int)a.size(); j++)
36,288✔
350
                        if (i!=j) A[i] *= a[j];
24,192✔
351

352
        // Add the powers (xm-c{m-1})^k with ideal-adic Newton iteration.
353
        poly term(BHEAD 1,b.modp,b.modn);
6,048✔
354

355
        poly error(b);
6,048✔
356
        for (int i=0; i<(int)A.size(); i++)
18,144✔
357
                error -= s[i] * A[i];
12,096✔
358

359
        for (int deg=1; deg<=d; deg++) {
6,048✔
360

361
                if (error.is_zero()) break;
6,048✔
362
                
363
                error /= simple;
×
364
                term *= simple;
×
365

366
                vector<poly> ds(solve_Diophantine_multivariate(ared, error%simple, xred, cred, d));
×
367
                if (ds == vector<poly>()) return vector<poly>();
×
368
                
369
                for (int i=0; i<(int)s.size(); i++) {
×
370
                        s[i] += ds[i] * term;
×
371
                        error -= ds[i] * A[i];
×
372
                }
373
        }
×
374

375
        if (!error.is_zero()) return vector<poly>();
6,048✔
376
        
377
#ifdef DEBUGALL
378
        cout << "*** [" << thetime() << "]  RES : solve_Diophantine_multivariate(" <<a<<","<<b<<","<<x<<","<<c<<","<<d<<") = "<<s<<endl;
379
#endif
380
        
381
        return s;
6,048✔
382
}
6,048✔
383

384
/*
385
          #] solve_Diophantine_multivariate : 
386
          #[ lift_coefficients :
387
*/
388
                                                                                                                                                                                                                                                                                                                                                                                                 
389
/**  Univariate Hensel lifting of coefficients
390
 *
391
 *   Description
392
 *   ===========
393
 *   Given a primitive univariate polynomial A and a list of
394
 *   univariate polynomials a1(x),...,ak(x), such that
395
 *
396
 *   - N(A(x)) = N(a1(x))*...*N(ak(x)) mod p
397
 *   - gcd(ai,aj) = 1 (for i!=j),
398
 *
399
 *   where N(A(x)) means make A monic modulo p, i.e., divide by its
400
 *   leading coefficient, the method returns a list of univariate
401
 *   polynomials A1(x),...,Ak(x), such that
402
 *
403
 *     A(x) = A1(x)*...*Ak(x) mod p^n
404
 *
405
 *   with
406
 *
407
 *     N(Ai(x)) = N(ai(x)) mod p.
408
 *
409
 *   If there exists a factorization of A over the integers, it is the
410
 *   one returned by the method if p^n is large enough.
411
 *
412
 *   Notes
413
 *   =====
414
 *   - The polynomial A must be primitive.
415
 *   - If there exists no factorization over the integers, the
416
 *     coefficients of the factors modulo p^n typically become large,
417
 *     like 1/2 mod p^n.
418
 *
419
 *   [for details, see "Algorithms for Computer Algebra", pp. 232-250]
420
 */
421
const vector<poly> polyfact::lift_coefficients (const poly &_A, const vector<poly> &_a) {
54✔
422
        
423
#ifdef DEBUG
424
        cout << "*** [" << thetime() << "]  CALL: lift_coefficients("<<_A<<","<<_a<<")"<<endl;
425
#endif
426

427
        POLY_GETIDENTITY(_A);
54✔
428
        
429
        poly A(_A);
54✔
430
        vector<poly> a(_a);
54✔
431
        poly term(BHEAD 1);
54✔
432
        
433
        int x = A.first_variable();
54✔
434

435
        // Replace the leading term of all factors with lterm(A) mod p
436
        poly lead(A.integer_lcoeff());
54✔
437
        for (int i=0; i<(int)a.size(); i++) {
306✔
438
                a[i] *= lead / a[i].integer_lcoeff();
252✔
439
                if (i>0) A*=lead;
252✔
440
        }
441

442
        // Solve Diophantine equation
443
        vector<poly> s(solve_Diophantine_univariate(a,poly(BHEAD 1,A.modp,1)));
54✔
444
        
445
        // Replace the leading term of all factors with lterm(A) mod p^n
446
        for (int i=0; i<(int)a.size(); i++) {
306✔
447
                a[i].setmod(A.modp,A.modn);
252✔
448
                a[i] += (lead - a[i].integer_lcoeff()) * poly::simple_poly(BHEAD x,0,a[i].degree(x));
252✔
449
        }
450

451
        // Calculate the error, express it in terms of ai and add corrections.
452
        for (int k=2; k<=A.modn; k++) {
174✔
453
                term *= poly(BHEAD A.modp);
165✔
454

455
                poly error(BHEAD -1);
165✔
456
                for (int i=0; i<(int)a.size(); i++) error *= a[i];
2,526✔
457
                error += A;
165✔
458
                if (error.is_zero()) break;
165✔
459

460
                error /= term;
120✔
461
                error.setmod(A.modp,1);
120✔
462

463
                for (int i=0; i<(int)a.size(); i++) 
2,349✔
464
                        a[i] += term * (error * s[i] % a[i]);
2,229✔
465
        }
165✔
466
        
467
        // Fix leading coefficients by dividing out integer contents.
468
        for (int i=0; i<(int)a.size(); i++) 
306✔
469
                a[i] /= polygcd::integer_content(poly(a[i],0,1));        
252✔
470

471
#ifdef DEBUG
472
        cout << "*** [" << thetime() << "]  RES : lift_coefficients("<<_A<<","<<_a<<") = "<<a<<endl;
473
#endif
474

475
        return a;
54✔
476
}
54✔
477

478
/*
479
          #] lift_coefficients : 
480
                 #[ predetermine :
481
*/
482

483
/**  Predetermine coefficients
484
 *
485
 *   Description
486
 *   ===========
487
 *   Helper function for multivariate Hensel lifting to predetermine
488
 *   coefficients. The function creates all products of terms of the
489
 *   polynomials a1,...,an and stores them according to degree in x1.
490
 *
491
 *   All terms with equal power in x1 result in an equation that might
492
 *   be solved to predetermine a coefficient.
493
 *
494
 *   For details, see Wang, "An Improved Polynomial Factoring
495
 *   Algorithm", Math. Comput. 32 (1978) pp. 1215-1231]
496
 */
497
void polyfact::predetermine (int dep, const vector<vector<int> > &state, vector<vector<vector<int> > > &terms, vector<int> &term, int sumdeg) {
567✔
498
        // store the term
499
        if (dep == (int)state.size()) {
567✔
500
                terms[sumdeg].push_back(term);
324✔
501
                return;
324✔
502
        }
503

504
        // recursively create new terms
505
        term.push_back(0);
243✔
506
        
507
        for (int deg=0; sumdeg+deg<(int)state[dep].size(); deg++)
1,275✔
508
                if (state[dep][deg] > 0) {
1,032✔
509
                        term.back() = deg;
534✔
510
                        predetermine(dep+1, state, terms, term, sumdeg+deg);
534✔
511
                }
512

513
        term.pop_back();
243✔
514
}
515

516
/*
517
                 #] predetermine : 
518
          #[ lift_variables :
519
*/
520

521
/**  Multivariate Hensel lifting of variables
522
 *
523
 *   Description
524
 *   ===========
525
 *   Given a multivariate polynomial A modulo a prime power p^n and
526
 *   a list of univariate polynomials a1(x1),...,am(x1), such that
527
 *
528
 *   - A(x1,...,xm) = a1(x1)*...*ak(x1) mod <p^n,I>,
529
 *   - gcd(ai,aj) = 1 (for i!=j),
530
 *
531
 *   with the ideal I=<x2-c1,...,xm-c{m-1}>, the method returns a
532
 *   list of multivariate polynomials A1(x1,...xm),...,Ak(x1,...,xm),
533
 *   such that
534
 *
535
 *     A(x1,...,xm) = A1(x1,...,xm)*...*Ak(x1,...,xm) mod p^n
536
 *
537
 *   with
538
 *
539
 *     Ai(x1,...,xm) = ai(x1) mod <p^n,I>.
540
 *
541
 *   The correct multivariate leading coefficients should be given in
542
 *   the parameter lc.
543
 *
544
 *   [for details, see "Algorithms for Computer Algebra", pp. 250-273]
545
 *
546
 *   Before Hensel lifting, predetermination of coefficients is used
547
 *   for efficiency.
548
 
549
 *   [for details, see Wang, "An Improved Polynomial Factoring
550
 *   Algorithm", Math. Comput. 32 (1978) pp. 1215-1231]
551
 *  
552
 *   Notes
553
 *   =====
554
 *   - The polynomial A must be primitive.
555
 *   - Returns empty vector<poly>() if lifting is impossible.
556
 */
557

558
const vector<poly> polyfact::lift_variables (const poly &A, const vector<poly> &_a, const vector<int> &x, const vector<int> &c, const vector<poly> &lc) {
36✔
559
        
560
#ifdef DEBUG
561
        cout << "*** [" << thetime() << "]  CALL: lift_variables("<<A<<","<<_a<<","<<x<<","<<c<<","<<lc<<")\n";
562
#endif
563

564
        // If univariate, don't lift
565
        if (x.size()<=1) return _a;
36✔
566

567
        POLY_GETIDENTITY(A);
36✔
568
        
569
        vector<poly> a(_a);
36✔
570

571
        // First method: predetermine coefficients
572

573
        // check feasibility, otherwise it tries too many possibilities
574
        int cnt = POLYFACT_MAX_PREDETERMINATION;
575
        for (int i=0; i<(int)a.size(); i++) {
168✔
576
                if (a[i].number_of_terms() == 0) return vector<poly>();
132✔
577
                cnt /= a[i].number_of_terms();
132✔
578
        }
579

580
        if (cnt>0) {
36✔
581
                // state[n][d]: coefficient of x^d in a[n] is
582
                // 0: non-existent, 1: undetermined, 2: determined
583
                int D = A.degree(x[0]);
33✔
584
                vector<vector<int> > state(a.size(), vector<int>(D+1, 0));
33✔
585
                
586
                for (int i=0; i<(int)a.size(); i++)
129✔
587
                        for (int j=1; j<a[i][0]; j+=a[i][j]) 
294✔
588
                                state[i][a[i][j+1+x[0]]] = j==1 ? 2 : 1;
300✔
589
        
590
                // collect all products of terms
591
                vector<vector<vector<int> > > terms(D+1);
33✔
592
                vector<int> term;
33✔
593
                predetermine(0,state,terms,term);
33✔
594

595
                // count the number of undetermined coefficients
596
                vector<int> num_undet(terms.size(),0);
33✔
597
                for (int i=0; i<(int)terms.size(); i++) 
192✔
598
                        for (int j=0; j<(int)terms[i].size(); j++)
483✔
599
                                for (int k=0; k<(int)terms[i][j].size(); k++)
1,380✔
600
                                        if (state[k][terms[i][j][k]] == 1) num_undet[i]++;
1,056✔
601

602
                // replace the current leading coefficients by the correct ones
603
                for (int i=0; i<(int)a.size(); i++) 
129✔
604
                        a[i] += (lc[i] - a[i].lcoeff_univar(x[0])) * poly::simple_poly(BHEAD x[0],0,a[i].degree(x[0]));
96✔
605
        
606
                bool changed;
33✔
607
                do {
33✔
608
                        changed = false;
33✔
609

610
                        for (int i=0; i<(int)terms.size(); i++) {
192✔
611
                                // is only one coefficient in a equation is undetermined, solve
612
                                // the equation to determine this coefficient
613
                                if (num_undet[i] == 1) {
159✔
614
                                        // generate equation
615
                                        poly lhs(BHEAD 0), rhs(A.coefficient(x[0],i), A.modp, A.modn);
×
616
                                        int which_idx=-1, which_deg=-1;
×
617
                                        for (int j=0; j<(int)terms[i].size(); j++) {
×
618
                                                poly coeff(BHEAD 1, A.modp, A.modn);
×
619
                                                bool undet=false;
620
                                                for (int k=0; k<(int)terms[i][j].size(); k++) {
×
621
                                                        if (state[k][terms[i][j][k]] == 1) {
×
622
                                                                undet = true;
623
                                                                which_idx=k;
624
                                                                which_deg=terms[i][j][k];
625
                                                        }
626
                                                        else 
627
                                                                coeff *= a[k].coefficient(x[0], terms[i][j][k]);
×
628
                                                }
629
                                                if (undet) 
×
630
                                                        lhs = coeff;
×
631
                                                else
632
                                                        rhs -= coeff;
×
633
                                        }
×
634
                                        // solve equation
635
                                        if (A.modn > 1) rhs.setmod(0,1);
×
636
                                        if (lhs.is_zero() || !(rhs%lhs).is_zero()) return vector<poly>();
×
637
                                        a[which_idx] += (rhs / lhs - a[which_idx].coefficient(x[0],which_deg)) * poly::simple_poly(BHEAD x[0],0,which_deg);
×
638
                                        state[which_idx][which_deg] = 2;
×
639

640
                                        // update number of undetermined coefficients
641
                                        for (int j=0; j<(int)terms.size(); j++)
×
642
                                                for (int k=0; k<(int)terms[j].size(); k++)
×
643
                                                        if (terms[j][k][which_idx] == which_deg)
×
644
                                                                num_undet[j]--;
×
645

646
                                        changed = true;
×
647
                                }
×
648
                        }
649
                }
650
                while (changed);
651

652
                // if this is the complete result, skip lifting
653
                poly check(BHEAD 1, A.modn>1?0:A.modp, 1);
33✔
654
                for (int i=0; i<(int)a.size(); i++)
129✔
655
                        check *= a[i];
96✔
656

657
                if (check == A) return a;
33✔
658
        }
33✔
659

660
        // Second method: Hensel lifting
661
        
662
        // Calculate A and lc's modulo Ii = <xi-c{i-1],...,xm-c{m-1}> (for i=2,...,m)
663
        vector<poly> simple(x.size(), poly(BHEAD 0));
36✔
664
        for (int i=(int)x.size()-2; i>=0; i--) 
261✔
665
                simple[i] = poly::simple_poly(BHEAD x[i+1],c[i],1);
225✔
666

667
        // Calculate the maximum degree of A in x2,...,xm
668
        int maxdegA=0;
669
        for (int i=1; i<(int)x.size(); i++)
261✔
670
                maxdegA = MaX(maxdegA, A.degree(x[i]));
225✔
671

672
        // Iteratively add the variables x2,...,xm
673
        for (int xi=1; xi<(int)x.size(); xi++) {
261✔
674
                // replace the current leading coefficients by the correct ones
675
                for (int i=0; i<(int)a.size(); i++)
735✔
676
                        a[i] += (lc[i] - a[i].lcoeff_univar(x[0])) * poly::simple_poly(BHEAD x[0],0,a[i].degree(x[0]));
510✔
677

678
                vector<poly> anew(a);
225✔
679
                for (int i=0; i<(int)anew.size(); i++)
735✔
680
                        for (int j=xi-1; j<(int)c.size(); j++)
13,116✔
681
                                anew[i] %= simple[j];
12,606✔
682

683
                vector<int> xnew(x.begin(), x.begin()+xi);
225✔
684
                vector<int> cnew(c.begin(), c.begin()+xi-1);
225✔
685
                poly term(BHEAD 1,A.modp,A.modn);
225✔
686

687
                // Iteratively add the powers xi^k
688
                for (int deg=1, maxdeg=A.degree(x[xi]); deg<=maxdeg; deg++) {
747✔
689

690
                        term *= simple[xi-1];
333✔
691

692
                        // Calculate the error, express it in terms of ai and add corrections.
693
                        poly error(BHEAD -1,A.modp,A.modn);
333✔
694
                        for (int i=0; i<(int)a.size(); i++) error *= a[i];
1,599✔
695
                        error += A;
333✔
696
                        for (int i=xi; i<(int)c.size(); i++) error %= simple[i];
6,570✔
697

698
                        if (error.is_zero()) break;
333✔
699
                                
700
                        error /= term;
297✔
701
                        error %= simple[xi-1];
297✔
702
                        
703
                        vector<poly> s(solve_Diophantine_multivariate(anew,error,xnew,cnew,maxdegA));
297✔
704
                        if (s == vector<poly>()) return vector<poly>();
297✔
705

706
                        for (int i=0; i<(int)a.size(); i++)
1,431✔
707
                                a[i] += s[i] * term;
1,134✔
708
                }
333✔
709
                
710
                // check whether PRODUCT(a[i]) = A mod <xi-c{i-1},...,xm-c{m-1]> over the integers or ZZ/p
711
                poly check(BHEAD -1, A.modn>1?0:A.modp, 1);
225✔
712
                for (int i=0; i<(int)a.size(); i++)        check *= a[i];
735✔
713
                check += A;
225✔
714
                for (int i=xi; i<(int)c.size(); i++) check %= simple[i];
6,273✔
715
                if (!check.is_zero()) return vector<poly>();
225✔
716
        }
225✔
717

718
#ifdef DEBUG
719
        cout << "*** [" << thetime() << "]  RES : lift_variables("<<A<<","<<_a<<","<<x<<","<<c<<","<<lc<<") = " << a << endl;
720
#endif
721

722
        return a;
36✔
723
}
36✔
724

725
/*
726
          #] lift_variables : 
727
          #[ choose_prime :
728
*/
729

730
/**  Choose a good prime number
731
 *
732
 *   Description
733
 *   ===========
734
 *   Choose a prime number, such that lcoeff(a) != 0 (mod p) (which
735
 *   is equivalent to icont(lcoeff(a)) != 0 (mod p))
736
 *
737
 *   Notes
738
 *   =====
739
 *   If a prime p is provided, it returns the next prime that is good.
740
 */
741
WORD polyfact::choose_prime (const poly &a, const vector<int> &x, WORD p) {
351✔
742

743
#ifdef DEBUG
744
        cout << "*** [" << thetime() << "]  CALL: choose_prime("<<a<<","<<x<<","<<p<<")"<<endl;
745
#endif
746

747
        POLY_GETIDENTITY(a);
351✔
748
        
749
        poly icont_lcoeff(polygcd::integer_content(a.lcoeff_univar(x[0])));
351✔
750

751
        if (p==0) p = POLYFACT_FIRST_PRIME;
351✔
752

753
        poly icont_lcoeff_modp(BHEAD 0);
351✔
754
        
755
        do {
613✔
756

757
                bool is_prime;
613✔
758
                
759
                do {
613✔
760
                        p += 2;
613✔
761
                        is_prime = true;
613✔
762
                        for (int d=2; d*d<=p; d++)
2,456✔
763
                                if (p%d==0) { is_prime=false; break; }
2,105✔
764
                }
765
                while (!is_prime);                        
613✔
766
                
767
                icont_lcoeff_modp = icont_lcoeff;
351✔
768
                icont_lcoeff_modp.setmod(p,1);
351✔
769
        }
770
        while (icont_lcoeff_modp.is_zero());
351✔
771

772
#ifdef DEBUG
773
        cout << "*** [" << thetime() << "]  RES : choose_prime("<<a<<","<<x<<",?) = "<<p<<endl;
774
#endif
775
        
776
        return p;
351✔
777
}
351✔
778

779
/*
780
          #] choose_prime : 
781
          #[ choose_prime_power :
782
*/
783

784
/**  Choose a good prime power
785
 *
786
 *   Description
787
 *   ===========
788
 *   Choose a power n such that p^n is larger than the coefficients of
789
 *   any factorization of a. These coefficients are bounded by:
790
 *
791
 *      goldenratio^degree * |f|
792
 *
793
 *   with the norm |f| = (SUM coeff^2)^1/2
794
 *
795
 *   [for details, see "Bounding the Coefficients of a Divisor of a
796
 *   Given Polynomial" by Andrew Granville]
797
 */
798
WORD polyfact::choose_prime_power (const poly &a, WORD p) {
352✔
799

800
#ifdef DEBUG
801
        cout << "*** [" << thetime() << "]  CALL: choose_prime_power("<<a<<","<<p<<")"<<endl;
802
#endif
803
        
804
        POLY_GETIDENTITY(a);
352✔
805

806
        // analyse the polynomial for calculating the bound
807
        double maxdegree=0, maxlogcoeff=0, numterms=0;
352✔
808
                        
809
        for (int i=1; i<a[0]; i+=a[i]) {
2,475✔
810
                 for (int j=0; j<AN.poly_num_vars; j++)
40,011✔
811
                        maxdegree = MaX(maxdegree, a[i+1+j]);
37,888✔
812

813
                maxlogcoeff = MaX(maxlogcoeff,
2,123✔
814
                                                                                        log(1.0+(UWORD)a[i+a[i]-2]) +            // most significant digit + 1
815
                                                                                        BITSINWORD*log(2.0)*(ABS(a[i+a[i]-1])-1)); // number of digits
816
                numterms++;
2,123✔
817
        }
818

819
        WORD res = (WORD)ceil((log((sqrt(5.0)+1)/2)*maxdegree + maxlogcoeff + 0.5*log(numterms)) / log((double)p));
352✔
820
        
821
#ifdef DEBUG
822
        cout << "*** [" << thetime() << "]  CALL: choose_prime_power("<<a<<","<<p<<") = "<<res<<endl;
823
#endif
824

825
        return res;
352✔
826
}
827

828
/*
829
          #] choose_prime_power : 
830
          #[ choose_ideal :
831
*/
832

833
/**  Choose a good ideal
834
 *
835
 *   Description
836
 *   ===========
837
 *   Choose an ideal I=<x2-c1,...,xm-c{m-1}) such that the following
838
 *   properties hold:
839
 *
840
 *   - The leading coefficient of a, regarded as polynomial in x1,
841
 *     does not vanish mod I;
842
 *   - a mod I is squarefree;
843
 *   - Each factor of lcoeff(a) mod I (i.e., parameter lc) has a
844
 *     unique prime number factor that is not contained in one of the
845
 *     other factors. (This can be used to "identification" later.)
846
 *
847
 *   This last condition is not fulfilled when calculating over ZZ/p.
848
 *
849
 *   Notes
850
 *   =====
851
 *   - If a step fails, an empty vector<int> is returned. This is
852
 *     necessary, e.g., in the case of a non-squarefree input
853
 *     polynomial
854
 *
855
 *   [for details, see:
856
 *   - "Algorithms for Computer Algebra", pp. 337-343,
857
 *   -  Wang, "An Improved Polynomial Factoring Algorithm",
858
 *      Math. Comput. 32 (1978) pp. 1215-1231]
859
 */
860
const vector<int> polyfact::choose_ideal (const poly &a, int p, const factorized_poly &lc, const vector<int> &x) {
217✔
861

862
#ifdef DEBUG
863
        cout << "*** [" << thetime() << "]  CALL: polyfact::choose_ideal("
864
                         <<a<<","<<p<<","<<lc<<","<<x<<")"<<endl;
865
#endif
866

867
        if (x.size()==1) return vector<int>();
217✔
868

869
        POLY_GETIDENTITY(a);
217✔
870
        
871
        vector<int> c(x.size()-1);
217✔
872
        
873
        int dega = a.degree(x[0]);
217✔
874
        poly amodI(a);
217✔
875

876
        // choose random c
877
        for (int i=0; i<(int)c.size(); i++) {
1,201✔
878
                c[i] = 1 + wranf(BHEAD0) % ((p-1) / POLYFACT_IDEAL_FRACTION);
984✔
879
                amodI %= poly::simple_poly(BHEAD x[i+1],c[i],1);
984✔
880
        }
881
        
882
        poly amodIp(amodI);
217✔
883
        amodIp.setmod(p,1);
217✔
884
        
885
        // check if leading coefficient is non-zero [equivalent to degree=old_degree]
886
        if (amodIp.degree(x[0]) != dega) 
217✔
887
                return c = vector<int>();
×
888
        
889
        // check if leading coefficient is squarefree [equivalent to gcd(a,a')==const]        
890
        if (!polygcd::gcd_Euclidean(amodIp, amodIp.derivative(x[0])).is_integer()) 
217✔
891
                return c = vector<int>();
1✔
892

893
        if (a.modp>0 && a.modn==1) return c;
216✔
894
        
895
        // check for unique prime factors in each factor lc[i] of the leading coefficient
896
        vector<poly> d(1, polygcd::integer_content(amodI));
216✔
897
        
898
        for (int i=0; i<(int)lc.factor.size(); i++) {
231✔
899
                // constant factor
900
                if (i==0 && lc.factor[i].is_integer()) {
15✔
901
                        d[0] *= lc.factor[i];
15✔
902
                        continue;
15✔
903
                }
904

905
                // factor modulo I
906
                poly q(lc.factor[i]);
×
907
                for (int j=0; j<(int)c.size(); j++)
×
908
                        q %= poly::simple_poly(BHEAD x[j+1],c[j]);
×
909
                if (q.sign() == -1) q *= poly(BHEAD -1);
×
910

911
                // divide out common factors
912
                for (int j=(int)d.size()-1; j>=0; j--) {
×
913
                        poly r(d[j]);
×
914
                        while (!r.is_one()) {
×
915
                                r = polygcd::integer_gcd(r,q); 
×
916
                                q /= r;
×
917
                        }
918
                }
×
919

920
                // check whether there is some factor left
921
                if (q.is_one()) return vector<int>();
×
922
                d.push_back(q);
×
923
        }
×
924
        
925
#ifdef DEBUG
926
        cout << "*** [" << thetime() << "]  RES : polyfact::choose_ideal("
927
                         <<a<<","<<p<<","<<lc<<","<<x<<") = "<<c<<endl;
928
#endif
929

930
        return c;
216✔
931
}
217✔
932

933
/*
934
          #] choose_ideal : 
935
          #[ squarefree_factors_Yun :
936
*/
937

938
/**  Yun's squarefree factorization of a primitive polynomial
939
 *
940
 *   Description
941
 *   ===========
942
 *   See description "squarefree_factors".
943
 */
944
const factorized_poly polyfact::squarefree_factors_Yun (const poly &_a) {
117✔
945

946
        factorized_poly res;
117✔
947
        poly a(_a);
117✔
948
        
949
        int pow = 1;
117✔
950
        int x = a.first_variable();
117✔
951

952
        poly b(a.derivative(x));
117✔
953
        poly c(polygcd::gcd(a,b));
117✔
954

955
        while (true) {
135✔
956
                a /= c;
126✔
957
                b /= c;
126✔
958
                b -= a.derivative(x);
126✔
959
                if (b.is_zero()) break;
126✔
960
                c = polygcd::gcd(a,b);
9✔
961
                if (!c.is_one()) res.add_factor(c,pow);
9✔
962
                pow++;
9✔
963
        }
964
        
965
        if (!a.is_one()) res.add_factor(a,pow);
117✔
966
        return res;
117✔
967
}        
117✔
968

969
/*
970
          #] squarefree_factors_Yun : 
971
          #[ squarefree_factors_modp :
972
*/
973

974
/**  Squarefree factorization of a primitive polynomial modulo a prime
975
 *
976
 *   Description
977
 *   ===========
978
 *   See description "squarefree_factors".
979
 */
980
const factorized_poly polyfact::squarefree_factors_modp (const poly &_a) {
×
981

982
        factorized_poly res;
×
983
        poly a(_a);
×
984
        
985
        int pow = 1;
×
986
        int x = a.first_variable();
×
987
        poly b(a.derivative(x));
×
988

989
        // poly contains terms of the form c(x)^n (n!=c*p)
990
        if (!b.is_zero()) {
×
991
                poly c(polygcd::gcd(a,b));
×
992
                a /= c;
×
993
                
994
                while (!a.is_one()) {
×
995
                        b = polygcd::gcd(a,c);
×
996
                        a /= b;
×
997
                        if (!a.is_one()) res.add_factor(a,pow);
×
998
                        pow++;
×
999
                        a = b;
×
1000
                        c /= a;                        
×
1001
                }
1002

1003
                a = c;
×
1004
        }
×
1005

1006
        // polynomial contains terms of the form c(x)^p
1007
        if (!a.is_one()) {
×
1008
                for (int i=1; i<a[1]; i+=a[i])
×
1009
                        a[i+1+x] /= a.modp;
×
1010
                factorized_poly res2(squarefree_factors(a));
×
1011
                for (int i=0; i<(int)res2.factor.size(); i++) {
×
1012
                        res.factor.push_back(res2.factor[i]);
×
1013
                        res.power.push_back(a.modp*res2.power[i]);
×
1014
                }
1015
        }
×
1016

1017
        return res;
×
1018
}
×
1019

1020
/*
1021
          #] squarefree_factors_modp : 
1022
          #[ squarefree_factors :
1023
*/
1024

1025
/**  Squarefree factorization of a primitive polynomial
1026
 *
1027
 *   Description
1028
 *   ===========
1029
 *   Calculates a squarefree factorization of a multivariate
1030
 *   polynomial, i.e., a factorization of the form
1031
 *
1032
 *     a = PRODUCT(ai^i | i=1,...,k),
1033
 *
1034
 *   with ai squarefree polynomials that are relatively prime. A
1035
 *   polynomial is squarefree iff it is not divisable by b^2 for all b
1036
 *   with degree greater than zero.
1037
 *
1038
 *   Notes
1039
 *   ===== 
1040
 *   - For modp==0, Yun's efficient method is used
1041
 *   - For modp!=0, a simple method is used
1042
 *
1043
 *   [for details, see "Algorithms for Computer Algebra", pp. 337-343]
1044
 */
1045
const factorized_poly polyfact::squarefree_factors (const poly &a) {
117✔
1046

1047
#ifdef DEBUG
1048
        cout << "*** [" << thetime() << "]  CALL: squarefree_factors("<<a<<")\n";
1049
#endif
1050

1051
        if (a.is_one()) return factorized_poly();
117✔
1052

1053
        factorized_poly res;
117✔
1054
        
1055
        if (a.modp==0)
117✔
1056
                res = squarefree_factors_Yun(a);
234✔
1057
        else
1058
                res = squarefree_factors_modp(a);
×
1059

1060
#ifdef DEBUG
1061
        cout << "*** [" << thetime() << "]  RES : squarefree_factors("<<a<<") = "<<res<<"\n";
1062
#endif
1063

1064
        return res;
117✔
1065
}
117✔
1066

1067
/*
1068
          #] squarefree_factors : 
1069
          #[ Berlekamp_Qmatrix :
1070
*/
1071

1072
/**  Berlekamp Q-matrix
1073
 *
1074
 *   Description
1075
 *   ===========
1076
 *   This method determines a basis for the eigenspace with eigenvalue
1077
 *   1 of the matrix Q required by Berlekamp's factorization
1078
 *   algorithm. The matrix Q is defined by
1079
 *
1080
 *     Qij = coefficient( x^j in x^(i*p) mod a(x) ),
1081
 *
1082
 *   with i,j = 0,1,...,deg(a)-1. The eigenspace is determined with
1083
 *   Gaussian elimination on Q-I. 
1084
 * 
1085
 *   Notes
1086
 *   =====
1087
 *   - The polynomial a must be univariate.
1088
 *   - The polynomial a must be squarefree.
1089
 *   - The polynomial a must have coefficients in Z/p.
1090
 *   - For efficiency, dense representations of polynomials are used.
1091
 *
1092
 *   [for details, see "Algorithms for Computer Algebra", pp. 346-359]
1093
 */
1094
const vector<vector<WORD> > polyfact::Berlekamp_Qmatrix (const poly &_a) {
351✔
1095

1096
#ifdef DEBUG
1097
        cout << "*** [" << thetime() << "]  CALL: Berlekamp_Qmatrix("<<_a<<")\n";
1098
#endif
1099

1100
        if (_a.all_variables() == vector<int>())
351✔
1101
                return vector<vector<WORD> >(0);
×
1102

1103
        POLY_GETIDENTITY(_a);
351✔
1104
        
1105
        poly a(_a);
351✔
1106
        int x = a.first_variable();
351✔
1107
        int n = a.degree(x);
351✔
1108
        int p = a.modp;
351✔
1109
        
1110
        poly lc(a.integer_lcoeff());
351✔
1111
        a /= lc;
351✔
1112

1113
        vector<vector<WORD> > Q(n, vector<WORD>(n));
351✔
1114

1115
        // c is the vector of coefficients of the polynomial a
1116
        vector<WORD> c(n+1,0);
351✔
1117
        for (int j=1; j<a[0]; j+=a[j])
1,165✔
1118
                c[a[j+1+x]] = a[j+1+AN.poly_num_vars] * a[j+2+AN.poly_num_vars];
814✔
1119

1120
        // d is the vector of coefficients of x^i mod a, starting with i=0
1121
        vector<WORD> d(n,0);
351✔
1122
        d[0]=1;
351✔
1123

1124
        for (int i=0; i<=(n-1)*p; i++) {
302,268✔
1125
                // store the coefficients of x^(i*p) mod a
1126
                if (i%p==0) Q[i/p] = d;
301,917✔
1127

1128
                // transform d=x^i mod a into d=x^(i+1) mod a
1129
                vector<WORD> e(n);
301,917✔
1130
                for (int j=0; j<n; j++) {
17,693,712✔
1131
                        e[j] = (-(LONG)d[n-1]*c[j] + (j>0?d[j-1]:0)) % p;
17,391,795✔
1132
                        if (e[j]<0) e[j]+=p;
17,391,795✔
1133
                }
1134

1135
                d=e;
301,917✔
1136
        }
301,917✔
1137

1138
        // Q = Q - I
1139
        for (int i=0; i<n; i++)
6,858✔
1140
                Q[i][i] = (Q[i][i] - 1 + p) % p;
6,507✔
1141

1142
        // Gaussian elimination
1143
        for (int i=0; i<n; i++) {
6,858✔
1144
                // Find pivot
1145
                int ii=i; while (ii<n && Q[i][ii]==0) ii++;
70,398✔
1146
                if (ii==n) continue;
6,507✔
1147
                
1148
                for (int k=0; k<n; k++)
177,657✔
1149
                        swap(Q[k][ii],Q[k][i]);
174,654✔
1150
                
1151
                // normalize row i, which becomes the pivot
1152
                WORD mul;
3,003✔
1153
                GetModInverses (Q[i][i], p, &mul, NULL);
3,003✔
1154
                vector<int> idx;
3,003✔
1155
                
1156
                for (int k=0; k<n; k++) if (Q[k][i] != 0) {
177,657✔
1157
                        // store indices of non-zero elements for sparse matrices
1158
                        idx.push_back(k); 
5,997✔
1159
                        Q[k][i] = ((LONG)Q[k][i] * mul) % p;
5,997✔
1160
                }
1161

1162
                // reduce
1163
                for (int j=0; j<n; j++)
177,657✔
1164
                        if (j!=i && Q[i][j]!=0) {
174,654✔
1165
                                LONG mul = Q[i][j];
3,831✔
1166
                                for (int k=0; k<(int)idx.size(); k++) {
11,484✔
1167
                                        Q[idx[k]][j] = (Q[idx[k]][j] - mul*Q[idx[k]][i]) % p;
7,653✔
1168
                                        if (Q[idx[k]][j] < 0) Q[idx[k]][j]+=p;
7,653✔
1169
                                }
1170
                        }
1171
        }
3,003✔
1172

1173
        for (int i=0; i<n; i++) {
6,858✔
1174
                // Q = Q - I
1175
                Q[i][i] = Q[i][i]-1;
6,507✔
1176

1177
                // reduce all coefficients in the range 0,1,...,p-1
1178
                for (int j=0; j<n; j++) {
354,882✔
1179
                        Q[i][j] = -Q[i][j]%p;
348,375✔
1180
                        if (Q[i][j]<0) Q[i][j]+=p;
348,375✔
1181
                }                                
1182
        }
1183

1184
#ifdef DEBUG
1185
        cout << "*** [" << thetime() << "]  RES : Berlekamp_Qmatrix("<<_a<<") = "<<Q<<"\n";
1186
#endif
1187
        
1188
        return Q;
351✔
1189
}
351✔
1190

1191
/*
1192
          #] Berlekamp_Qmatrix : 
1193
          #[ Berlekamp_find_factors :
1194
*/
1195

1196
/**  Berlekamp find factors
1197
 *
1198
 *   Description
1199
 *   ===========
1200
 *   This method determines the factors of the polynomial, after a
1201
 *   suitable prime number and ideal are selected, and the
1202
 *   corresponding Q-matrix is calculated,
1203
 *
1204
 *   This is done by trying each factor of the form 
1205
 *
1206
 *     gcd( a(x), q(x) + const ),
1207
 *
1208
 *   with q(x) a polynomial, that is represented by a row of Q and
1209
 *   const=0,1,...,p-1. These factors can be proven to form a exhaustive
1210
 *   set of candidate factors.
1211
 *
1212
 *   Notes
1213
 *   =====
1214
 *   a must be squarefree, and therefore a vector<poly> is suitable
1215
 *   for returning the factors.
1216
 *
1217
 *   [for details, see "Algorithms for Computer Algebra", pp. 346-359]
1218
 */
1219
const vector<poly> polyfact::Berlekamp_find_factors (const poly &_a, const vector<vector<WORD> > &_q) {
126✔
1220

1221
#ifdef DEBUG
1222
        cout << "*** [" << thetime() << "]  CALL: Berlekamp_find_factors("<<_a<<","<<_q<<")\n";
1223
#endif
1224

1225
        if (_a.all_variables() == vector<int>()) return vector<poly>(1,_a);
126✔
1226

1227
        POLY_GETIDENTITY(_a);
126✔
1228

1229
        vector<vector<WORD> > q=_q;
126✔
1230

1231
        int rank=0;
1232
        for (int i=0; i<(int)q.size(); i++)
735✔
1233
                if (q[i]!=vector<WORD>(q[i].size(),0)) rank++;
609✔
1234
        
1235
        poly a(_a);
126✔
1236
        int x = a.first_variable();
126✔
1237
        int n = a.degree(x);
126✔
1238
        int p = a.modp;
126✔
1239
        
1240
        a /= a.integer_lcoeff();
126✔
1241

1242
        // Vector of factors, represented as dense polynomials mod p
1243
        vector<vector<WORD> > fac(1, vector<WORD>(n+1,0));
126✔
1244

1245
        fac[0] = poly::to_coefficient_list(a);
126✔
1246
        bool finished=false;
126✔
1247
        
1248
        // Loop over the columns of q + constant, i.e., an exhaustive list of possible factors        
1249
        for (int i=1; i<n && !finished; i++) {
450✔
1250
                if (q[i] == vector<WORD>(n,0)) continue;
324✔
1251

1252
                for (int s=0; s<p && !finished; s++) {
1,300✔
1253
                        for (int j=0; j<(int)fac.size() && !finished; j++) {
6,919✔
1254
                                vector<WORD> c = polygcd::coefficient_list_gcd(fac[j], q[i], p);
5,718✔
1255
                                
1256
                                // If a non-trivial factor is found, add it to the list
1257
                                if (c.size()!=1 && c.size()!=fac[j].size()) {
5,718✔
1258
                                        fac.push_back(c);
198✔
1259
                                        fac[j] = poly::coefficient_list_divmod(fac[j], c, p, 0);
198✔
1260
                                        if ((int)fac.size() == rank) finished=true;
198✔
1261
                                }
1262
                        }
5,718✔
1263

1264
                        // Increase the constant term by one
1265
                        q[i][0] = (q[i][0]+1) % p;
1,201✔
1266
                }
1267
        }
1268

1269
        // Convert the densely represented polynomials to sparse ones
1270
        vector<poly> res(fac.size(),poly(BHEAD 0, p));
126✔
1271
        for (int i=0; i<(int)fac.size(); i++)
450✔
1272
                res[i] = poly::from_coefficient_list(BHEAD fac[i],x,p);
324✔
1273
        
1274
#ifdef DEBUG
1275
        cout << "*** [" << thetime() << "]  RES : Berlekamp_find_factors("<<_a<<","<<_q<<") = "<<res<<"\n";
1276
#endif
1277

1278
        return res;
126✔
1279
}
126✔
1280

1281
/*
1282
          #] Berlekamp_find_factors : 
1283
          #[ combine_factors :
1284
*/
1285

1286
/**  Combine incorrect factors
1287
 *
1288
 *   Description
1289
 *   ===========
1290
 *   Occasionally, a polynomial is split into more factors (modulo
1291
 *   <p,I>) than is possible over the integers. This might be caused
1292
 *   by a unlucky choice of p or I, but might also happen for choices.
1293
 *
1294
 *   When this happens, the coefficients of the factors are large
1295
 *   after Hensel lifting, and therefore the factor does not divide
1296
 *   the polynomial viewed as polynomial over the integers.
1297
 *
1298
 *   This method combines those incorrect factors into correct ones.
1299
 *
1300
 *   Notes
1301
 *   =====
1302
 *   Theoretically, this method takes exponential time (for ugly,
1303
 *   constructed cases), but in practice it is fast. This can be fixed
1304
 *   by implementing Van Hoeij's knapsack method (see: "Factoring
1305
 *   polynomials and the knapsack problem" by M. van Hoeij). [TODO]
1306
 */
1307
const vector<poly> polyfact::combine_factors (const poly &a, const vector<poly> &f) {
54✔
1308

1309
#ifdef DEBUG
1310
        cout << "*** [" << thetime() << "]  CALL: combine_factors("<<a<<","<<f<<")\n";
1311
#endif
1312

1313
        POLY_GETIDENTITY(a);
54✔
1314
        
1315
        poly a0(a,0,1);
54✔
1316
        vector<poly> res;
54✔
1317

1318
        int num_used = 0;
54✔
1319
        vector<bool> used(f.size(), false);
54✔
1320

1321
        // Loop over all bitmasks with num=1,2,...,size(factors)/2 bits
1322
        // set, that contain only unused factors
1323
        for (int num=1; num<=(int)(f.size() - num_used)/2; num++) {
222✔
1324
                vector<int> next(f.size() - num_used, 0);
168✔
1325
                for (int i=0; i<num; i++) next[next.size()-1-i] = 1;
366✔
1326

1327
                do {
801✔
1328
                        poly fac(BHEAD 1,a.modp,a.modn);
801✔
1329
                        for (int i=0, j=0; i<(int)f.size(); i++)
14,592✔
1330
                                if (!used[i] && next[j++]) fac *= f[i];
13,791✔
1331
                        fac /= fac.integer_lcoeff();
801✔
1332
                        fac *= a.integer_lcoeff();
801✔
1333
                        fac /= polygcd::integer_content(poly(fac,0,1));
801✔
1334

1335
                        if ((a0 % fac).is_zero()) {
801✔
1336
                                res.push_back(fac);
156✔
1337
                                for (int i=0, j=0; i<(int)f.size(); i++)
1,692✔
1338
                                        if (!used[i]) used[i] = next[j++];
1,536✔
1339
                                num_used += num;
156✔
1340
                                num--;
156✔
1341
                                break;
156✔
1342
                        }
1343
                }
801✔
1344
                while (next_permutation(next.begin(), next.end()));
645✔
1345
        }
168✔
1346
                        
1347
        // All unused factors together form one more factor
1348
        if (num_used != (int)f.size()) {
54✔
1349
                poly fac(BHEAD 1,a.modp,a.modn);
54✔
1350
                for (int i=0; i<(int)f.size(); i++)
306✔
1351
                        if (!used[i]) fac *= f[i];
252✔
1352
                fac /= fac.integer_lcoeff();
54✔
1353
                fac *= a.integer_lcoeff();
54✔
1354
                fac /= polygcd::integer_content(poly(fac,0,1));
54✔
1355
                res.push_back(fac);
54✔
1356
        }
54✔
1357

1358
#ifdef DEBUG
1359
        cout << "*** [" << thetime() << "]  RES : combine_factors("<<a<<","<<f<<") = "<<res<<"\n";
1360
#endif
1361

1362
        return res;
108✔
1363
}
54✔
1364

1365
/*
1366
          #] combine_factors : 
1367
          #[ factorize_squarefree :
1368
*/
1369

1370
/**  Factorization of a squarefree polynomial  
1371
 *
1372
 *   Description
1373
 *   ===========
1374
 *   This method find the factors of a primitive squarefree
1375
 *   polynomial. It proceeds with the following steps:
1376
 *
1377
 *   - Try a number a primes p and ideals I
1378
 *   - Determine the rank (=number of factors) of the Q-matrix
1379
 *   - Select the best (i.e., least number of factors) and find the
1380
 *     actual factors mod <p,I>
1381
 *   - Use Hensel lifting and factor combination to find the correct
1382
 *     factors over the integers
1383
 *
1384
 *   Notes
1385
 *   ===== 
1386
 *   The polynomial must be primitive and squarefree
1387
 */
1388
const vector<poly> polyfact::factorize_squarefree (const poly &a, const vector<int> &x) {
126✔
1389
        
1390
#ifdef DEBUG
1391
        cout << "*** [" << thetime() << "]  CALL: factorize_squarefree("<<a<<")\n";
1392
#endif
1393

1394
        POLY_GETIDENTITY(a);
126✔
1395
        
1396
        WORD p=a.modp, n=a.modn;
126✔
1397
        
1398
 try_again:
126✔
1399
        
1400
        int bestp=0;
126✔
1401
        int min_factors = INT_MAX;
126✔
1402
        poly amodI(BHEAD 0), bestamodI(BHEAD 0);
126✔
1403
        vector<int> c,d,bestc,bestd;
126✔
1404
        vector<vector<WORD> > q,bestq;
×
1405

1406
        // Factorize leading coefficient
1407
        factorized_poly lc(factorize(a.lcoeff_univar(x[0])));
126✔
1408

1409
        // Try a number of primes
1410
        int prime_tries = 0;
126✔
1411
        
1412
        while (prime_tries<POLYFACT_NUM_CONFIRMATIONS && min_factors>1) {
477✔
1413
                if (a.modp == 0) {
351✔
1414
                        p = choose_prime(a,x,p);
351✔
1415
                        n = 0;
351✔
1416
                        if (a.degree(x[0]) % p == 0) continue;
351✔
1417
                        
1418
                        // Univariate case: check whether the polynomial mod p is squarefree
1419
                        // Multivariate case: this check is done after choosing I (for efficiency)
1420
                        if (x.size()==1) {
351✔
1421
                                poly amodp(a,p,1);
135✔
1422
                                if (polygcd::gcd_Euclidean(amodp, amodp.derivative(x[0])).degree(x[0]) != 0)
135✔
1423
                                        continue;
×
1424
                        }
135✔
1425
                }
1426

1427
                // Try a number of ideals
1428
                if (x.size()>1) 
351✔
1429
                        for (int ideal_tries=0; ideal_tries<POLYFACT_MAX_IDEAL_TRIES; ideal_tries++) {
217✔
1430
                                c = choose_ideal(a,p,lc,x);
217✔
1431
                                if (c.size()>0) break;
217✔
1432
                        }
1433
                
1434
                if (x.size()==1 || c.size()>0) {
351✔
1435
                        amodI = a;
351✔
1436
                        for (int i=0; i<(int)c.size(); i++) 
1,326✔
1437
                                amodI %= poly::simple_poly(BHEAD x[i+1],c[i]);
975✔
1438

1439
                        // Determine Q-matrix and its rank. Smaller rank is better.
1440
                        q = Berlekamp_Qmatrix(poly(amodI,p,1));
351✔
1441
                        int rank=0;
351✔
1442
                        for (int i=0; i<(int)q.size(); i++)
6,858✔
1443
                                if (q[i]!=vector<WORD>(q[i].size(),0)) rank++;
6,507✔
1444

1445
                        if (rank<min_factors) {
351✔
1446
                                bestp=p;
140✔
1447
                                bestc=c;
140✔
1448
                                bestq=q;
140✔
1449
                                bestamodI=amodI;
140✔
1450
                                min_factors = rank;
1451
                                prime_tries = 0;
1452
                        }
1453

1454
                        if (rank==min_factors)
351✔
1455
                                prime_tries++;
249✔
1456

1457
#ifdef DEBUG
1458
        cout << "*** [" << thetime() << "]  (A) : factorize_squarefree("<<a<<
1459
                ") try p=" << p << " #factors=" << rank << " (min="<<min_factors<<"x"<<prime_tries<<")" << endl;
1460
#endif                        
1461
                }
1462
        }
1463

1464
        p=bestp;
126✔
1465
        c=bestc;
126✔
1466
        q=bestq;
126✔
1467
        amodI=bestamodI;
126✔
1468

1469
        // Determine to which power of p to lift
1470
        if (n==0) {
126✔
1471
                n = choose_prime_power(amodI,p);
126✔
1472
                n = MaX(n, choose_prime_power(a,p));
126✔
1473
        }
1474

1475
        amodI.setmod(p,n);
126✔
1476

1477
#ifdef DEBUG
1478
        cout << "*** [" << thetime() << "]  (B) : factorize_squarefree("<<a<<
1479
                ") chosen c = " << c << ", p^n = "<<p<<"^"<<n<<endl;
1480
        cout << "*** [" << thetime() << "]  (C) : factorize_squarefree("<<a<<
1481
                ") #factors = " << min_factors << endl;
1482
#endif
1483

1484
        // Find factors
1485
        vector<poly> f(Berlekamp_find_factors(poly(amodI,p,1),q));
126✔
1486

1487
        // Lift coefficients
1488
        if (f.size() > 1) {
126✔
1489
                f = lift_coefficients(amodI,f);
54✔
1490
                if (f==vector<poly>()) {
54✔
1491
#ifdef DEBUG
1492
                        cout << "factor_squarefree failed (lift_coeff step) : " << endl;
1493
#endif
1494
                        goto try_again;
×
1495
                }
1496

1497
                // Combine factors
1498
                if (a.modp==0) f = combine_factors(amodI,f);
54✔
1499
        }
1500

1501
        // Lift variables
1502
        if (f.size() == 1)
126✔
1503
                f = vector<poly>(1, a);
144✔
1504
        
1505
        if (x.size() > 1 && f.size() > 1) {
126✔
1506

1507
                // The correct leading coefficients of the factors can be
1508
                // reconstructed from prime number factors of the leading
1509
                // coefficients modulo I. This is possible since all factors of
1510
                // the leading coefficient have unique prime factors for the ideal
1511
                // I is chosen as such.
1512
                
1513
                poly amodI(a);
36✔
1514
                for (int i=0; i<(int)c.size(); i++)
261✔
1515
                        amodI %= poly::simple_poly(BHEAD x[i+1],c[i]);
225✔
1516
                poly delta(polygcd::integer_content(amodI));
36✔
1517
                
1518
                vector<poly> lcmodI(lc.factor.size(), poly(BHEAD 0));
36✔
1519
                for (int i=0; i<(int)lc.factor.size(); i++) {
36✔
1520
                        lcmodI[i] = lc.factor[i];
×
1521
                        for (int j=0; j<(int)c.size(); j++)
×
1522
                                lcmodI[i] %= poly::simple_poly(BHEAD x[j+1],c[j]);
×
1523
                }
1524
                
1525
                vector<poly> correct_lc(f.size(), poly(BHEAD 1,p,n));
36✔
1526
                
1527
                for (int j=0; j<(int)f.size(); j++) {
168✔
1528
                        poly lc_f(f[j].integer_lcoeff() * delta);
132✔
1529
                        WORD nlc_f = lc_f[lc_f[1]];
132✔
1530
                        poly quo(BHEAD 0),rem(BHEAD 0);
132✔
1531
                        WORD nquo,nrem;
132✔
1532
                        
1533
                        for (int i=(int)lcmodI.size()-1; i>=0; i--) {
132✔
1534
                                
1535
                                if (i==0 && lc.factor[i].is_integer()) continue;
×
1536
                                
1537
                                do {
×
1538
                                        DivLong((UWORD *)&lc_f[2+AN.poly_num_vars], nlc_f,
×
1539
                                                                        (UWORD *)&lcmodI[i][2+AN.poly_num_vars], lcmodI[i][lcmodI[i][1]],
×
1540
                                                                        (UWORD *)&quo[0], &nquo,
×
1541
                                                                        (UWORD *)&rem[0], &nrem);
×
1542
                                        
1543
                                        if (nrem == 0) {
×
1544
                                                correct_lc[j] *= lc.factor[i];
×
1545
                                                lc_f.termscopy(&quo[0], 2+AN.poly_num_vars, ABS(nquo));
×
1546
                                                nlc_f = nquo;
×
1547
                                        }
1548
                                }
1549
                                while (nrem == 0);
×
1550
                        }
1551
                }
132✔
1552
                
1553
                for (int i=0; i<(int)correct_lc.size(); i++) {
168✔
1554
                        poly correct_modI(correct_lc[i]);
132✔
1555
                        for (int j=0; j<(int)c.size(); j++)
642✔
1556
                                correct_modI %= poly::simple_poly(BHEAD x[j+1],c[j]);
510✔
1557
                        
1558
                        poly d(polygcd::integer_gcd(correct_modI, f[i].integer_lcoeff()));
132✔
1559
                        correct_lc[i] *= f[i].integer_lcoeff() / d;
132✔
1560
                        delta /= correct_modI / d;
132✔
1561
                        f[i] *= correct_modI / d;
132✔
1562
                }
132✔
1563
                
1564
                // increase n, because of multiplying with delta
1565
                if (!delta.is_one()) {
36✔
1566
                        poly deltapow(BHEAD 1);
×
1567
                        for (int i=1; i<(int)correct_lc.size(); i++)
×
1568
                                        deltapow *= delta;
×
1569
                        while (!deltapow.is_zero()) {
×
1570
                                deltapow /= poly(BHEAD p);
×
1571
                                n++;
×
1572
                        }
1573
                        
1574
                        for (int i=0; i<(int)f.size(); i++) {
×
1575
                                f[i].modn = n;
×
1576
                                correct_lc[i].modn = n;
×
1577
                        }
1578
                }
×
1579
                
1580
                poly aa(a,p,n);
36✔
1581
                        
1582
                for (int i=0; i<(int)correct_lc.size(); i++) {
168✔
1583
                        correct_lc[i] *= delta;
132✔
1584
                        f[i] *= delta;
132✔
1585
                        if (i>0) aa *= delta;
132✔
1586
                }                
1587

1588
                f = lift_variables(aa,f,x,c,correct_lc);
36✔
1589
                
1590
                for (int i=0; i<(int)f.size(); i++)
168✔
1591
                        if (a.modp == 0)
132✔
1592
                                f[i] /= polygcd::integer_content(poly(f[i],0,1));
132✔
1593
                        else
1594
                                f[i] /= polygcd::content_univar(f[i], x[0]);
×
1595
                
1596
                if (f==vector<poly>()) {
36✔
1597
#ifdef DEBUG
1598
                        cout << "factor_squarefree failed (lift_var step)" << endl;
1599
#endif
1600
                        goto try_again;
×
1601
                }
1602
        }
36✔
1603
        
1604
        // set modulus of the factors correctly
1605
        if (a.modp==0) 
126✔
1606
                for (int i=0; i<(int)f.size(); i++)
408✔
1607
                        f[i].setmod(0,1);
282✔
1608
        
1609
        // Final check (not sure if this is necessary, but it doesn't hurt)
1610
        poly check(BHEAD 1,a.modp,a.modn);
126✔
1611
        for (int i=0; i<(int)f.size(); i++)
408✔
1612
                check *= f[i];
282✔
1613
        
1614
        if (check != a) {
126✔
1615
#ifdef DEBUG
1616
                cout << "factor_squarefree failed (final check) : " << f << endl;
1617
#endif
1618
                goto try_again;
×
1619
        }
1620
        
1621
#ifdef DEBUG
1622
        cout << "*** [" << thetime() << "]  RES : factorize_squarefree("<<a<<","<<x<<","<<c<<") = "<<f<<"\n";
1623
#endif
1624
        
1625
        return f;
252✔
1626
}
1627

1628
/*
1629
          #] factorize_squarefree : 
1630
          #[ factorize :
1631
*/
1632

1633
/**  Factorization of polynomials
1634
 *
1635
 *   Description
1636
 *   ===========
1637
 *   This method removes the content of a polynomial, splits it into
1638
 *   squarefree factors and calls "factorize_squarefree" for each of
1639
 *   these factors.
1640
 */
1641
const factorized_poly polyfact::factorize (const poly &a) {
360✔
1642

1643
#ifdef DEBUG
1644
        cout << "*** [" << thetime() << "]  CALL: factorize("<<a<<")\n";
1645
#endif
1646
        vector<int> x = a.all_variables();
360✔
1647

1648
        // No variables, so just one factor
1649
        if (x.size() == 0) {
360✔
1650
                factorized_poly res;
243✔
1651
                if (a.is_one()) return res;
243✔
1652
                res.add_factor(a,1);
54✔
1653
                return res;
54✔
1654
        }
243✔
1655

1656
        // Remove content
1657
        poly conta(polygcd::content_univar(a,x[0]));
117✔
1658
        
1659
        factorized_poly faca(factorize(conta));
117✔
1660
        
1661
        poly ppa(a / conta);
117✔
1662

1663
        // Find a squarefree factorization
1664
        factorized_poly b(squarefree_factors(ppa));
117✔
1665
        
1666
#ifdef DEBUG
1667
        cout << "*** [" << thetime() << "]  ... : factorize("<<a<<") : SFF = "<<b<<"\n";
1668
#endif
1669
        
1670
        // Factorize each squarefree factor and build the "factorized_poly"
1671
        for (int i=0; i<(int)b.factor.size(); i++) {
243✔
1672
                
1673
                vector<poly> c(factorize_squarefree(b.factor[i], x));
126✔
1674

1675
                for (int j=0; j<(int)c.size(); j++) {
408✔
1676
                        faca.factor.push_back(c[j]);
282✔
1677
                        faca.power.push_back(b.power[i]);
282✔
1678
                }
1679
        }                
126✔
1680

1681
#ifdef DEBUG
1682
        cout << "*** [" << thetime() << "]  RES : factorize("<<a<<") = "<<faca<<"\n";
1683
#endif
1684
        
1685
        return faca;
117✔
1686
}
477✔
1687

1688
/*
1689
          #] factorize : 
1690
*/
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc