• 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

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

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

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

45
//#define DEBUG
46
//#define DEBUGALL
47

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

52
using namespace std;
53

54
/*
55
          #] include : 
56
          #[ ostream operator :
57
*/
58

59
#ifdef DEBUG
60
// ostream operator for outputting vector<T>s        for debugging purposes
61
template<class T> ostream& operator<< (ostream &out, const vector<T> &x) {
62
        out<<"{";
63
        for (int i=0; i<(int)x.size(); i++) {
64
                if (i>0) out<<",";
65
                out<<x[i];
66
        }
67
        out<<"}";
68
        return out;
69
}
70
#endif
71

72
/*
73
          #] ostream operator : 
74
          #[ integer_gcd :
75
*/
76

77
/**  Integer gcd calculation
78
 *
79
 *   Description
80
 *   ===========
81
 *   Calculates the greatest common divisor of two integers a and b.
82
 *
83
 *   Notes
84
 *   =====
85
 *   - The input and output integers are represented as polynomials.
86
 *     These polynomials must consist of one term with all powers
87
 *     equal to zero.
88
 *   - The result is always positive.
89
 *   - Over ZZ/p^n, the gcd is defined as 1.
90
 */
91
const poly polygcd::integer_gcd (const poly &a, const poly &b) {
3,730,317✔
92

93
#ifdef DEBUGALL
94
        cout << "*** [" << thetime() << "]  CALL: integer_gcd(" << a << "," << b << ")" << endl;
95
#endif
96

97
        POLY_GETIDENTITY(a);
3,730,317✔
98
        
99
        if (a.is_zero()) return b;
3,730,317✔
100
        if (b.is_zero()) return a;
3,730,317✔
101

102
        poly c(BHEAD 0, a.modp, a.modn);
3,730,317✔
103
        WORD nc;
3,730,317✔
104
        
105
        GcdLong(BHEAD
3,730,317✔
106
                                        (UWORD *)&a[AN.poly_num_vars+2],a[a[0]-1],
3,730,317✔
107
                                        (UWORD *)&b[AN.poly_num_vars+2],b[b[0]-1],
3,730,317✔
108
                                        (UWORD *)&c[AN.poly_num_vars+2],&nc);
3,730,317✔
109

110
        WORD x = 2 + AN.poly_num_vars + ABS(nc);
3,730,317✔
111
        c[1] = x;     // term length
3,730,317✔
112
        c[0] = x+1;   // total length
3,730,317✔
113
        c[x] = nc;    // coefficient length
3,730,317✔
114

115
        for (int i=0; i<AN.poly_num_vars; i++)
7,572,062✔
116
                c[2+i] = 0; // powers
3,841,745✔
117

118
#ifdef DEBUGALL
119
        cout << "*** [" << thetime() << "]  RES : integer_gcd(" << a << "," << b << ") = " << c << endl;
120
#endif
121

122
        return c;
3,730,317✔
123
}
3,730,317✔
124

125
/*
126
          #] integer_gcd : 
127
          #[ integer_content :
128
*/
129

130
/**  Integer content of a polynomial
131
 *
132
 *   Description
133
 *   ===========
134
 *   Calculates the integer content of a polynomial. This is the
135
 *   greatest common divisor of the coefficients.
136
 *
137
 *   Notes
138
 *   =====
139
 *   - The result has the sign of lcoeff(a).
140
 *   - Over ZZ/p^n, the integer content is defined as the leading
141
 *     coefficient of the polynomial.
142
 */
143
const poly polygcd::integer_content (const poly &a) {
8,717,673✔
144

145
#ifdef DEBUGALL
146
        cout << "*** [" << thetime() << "]  CALL: integer_content(" << a << ")" << endl;
147
#endif
148

149
        POLY_GETIDENTITY(a);
8,717,673✔
150

151
        if (a.modp>0) return a.integer_lcoeff();        
8,717,673✔
152

153
        poly c(BHEAD 0, 0, 1);
8,717,673✔
154
        WORD *d = (WORD *)NumberMalloc("polygcd::integer_content");
8,717,673✔
155
        WORD nc=0;
8,717,673✔
156

157
        for (int i=0; i<AN.poly_num_vars; i++)
17,735,277✔
158
                c[2+i] = 0;
9,017,604✔
159

160
        for (int i=1; i<a[0]; i+=a[i]) {
26,963,955✔
161

162
                WCOPY(d,&c[2+AN.poly_num_vars],nc);
27,860,232✔
163
                
164
                GcdLong(BHEAD (UWORD *)d, nc,
18,246,282✔
165
                                                (UWORD *)&a[i+1+AN.poly_num_vars], a[i+a[i]-1],
18,246,282✔
166
                                                (UWORD *)&c[2+AN.poly_num_vars], &nc);
18,246,282✔
167

168
                WORD x = 2 + AN.poly_num_vars + ABS(nc);
18,246,282✔
169
                c[1] = x;   // term length
18,246,282✔
170
                c[0] = x+1; // total length
18,246,282✔
171
                c[x] = nc;  // coefficient length
18,246,282✔
172
        }        
173

174
        if (a.sign() != c.sign()) c *= poly(BHEAD -1);
8,717,673✔
175
        
176
        NumberFree(d,"polygcd::integer_content");
8,717,673✔
177
        
178
#ifdef DEBUGALL
179
        cout << "*** [" << thetime() << "]  RES : integer_content(" << a << ") = " << c << endl;
180
#endif
181
        
182
        return c;
8,717,673✔
183
}
8,717,673✔
184

185
/*
186
          #] integer_content : 
187
          #[ content_univar :
188
*/
189

190
/**  Content of a univariate polynomial
191
 *
192
 *   Description
193
 *   ===========
194
 *   Calculates the content of a polynomial, regarded as a univariate
195
 *   polynomial in x. The content is the greatest common divisor of
196
 *   the polynomial coefficients in front of the powers of x. The
197
 *   result, therefore, is a polynomial in the variables except x.
198
 *
199
 *   Notes
200
 *   =====
201
 *   - The result has the sign of lcoeff(a).
202
 *   - Over ZZ/p, the leading coefficient of the content is defined as
203
 *     the leading coefficient of the polynomial.
204
 */
205
const poly polygcd::content_univar (const poly &a, int x) {
26,899✔
206
        
207
#ifdef DEBUG
208
        cout << "*** [" << thetime() << "]  CALL: content_univar(" << a << "," << string(1,'a'+x) << ")" << endl;
209
#endif
210
        
211
        POLY_GETIDENTITY(a);
26,899✔
212
        
213
        poly res(BHEAD 0, a.modp, a.modn);
26,899✔
214

215
        for (int i=1; i<a[0];) {
61,548✔
216
                poly b(BHEAD 0, a.modp, a.modn);
49,712✔
217
                int deg = a[i+1+x];
49,712✔
218
                
219
                for (; i<a[0] && a[i+1+x]==deg; i+=a[i]) {
128,817✔
220
                        b.check_memory(b[0]+a[i]);
79,105✔
221
                        b.termscopy(&a[i],b[0],a[i]);
79,105✔
222
                        b[b[0]+1+x] = 0;
79,105✔
223
                        b[0] += a[i];
79,105✔
224
                }                        
225
                
226
                res = gcd(res, b);
49,712✔
227

228
                if (res.is_integer()) {
49,712✔
229
                        res = integer_content(a);
15,063✔
230
                        break;
15,063✔
231
                }
232
        }        
49,712✔
233

234
        if (a.sign() != res.sign()) res *= poly(BHEAD -1);
26,899✔
235
        
236
#ifdef DEBUG
237
        cout << "*** [" << thetime() << "]  RES : content_univar(" << a << "," << string(1,'a'+x) << ") = " << res << endl;
238
#endif
239

240
        return res;
26,899✔
241
}
×
242

243
/*
244
          #] content_univar : 
245
                 #[ content_multivar :
246
*/
247

248
/**  Content of a multivariate polynomial
249
 *
250
 *   Description
251
 *   ===========
252
 *   Calculates the content of a polynomial, regarded as a
253
 *   multivariate polynomial in all variables except x (so with
254
 *   coefficients in ZZ[x]). The content is the greatest common
255
 *   divisor of the ZZ[x] coefficients in front of the powers of the
256
 *   remaining variables. The result, therefore, is a polynomial in x.
257
 *
258
 *   Notes
259
 *   =====
260
 *   - The result has the sign of lcoeff(a).
261
 *   - Over ZZ/p^n, the leading coefficient of the content is defined as +/-1
262
 */
263
const poly polygcd::content_multivar (const poly &a, int x) {
196✔
264
        
265
#ifdef DEBUGALL
266
        cout << "*** [" << thetime() << "]  CALL: content_multivar(" << a << "," << string(1,'a'+x) << ")" << endl;
267
#endif
268

269
        POLY_GETIDENTITY(a);
196✔
270

271
        poly res(BHEAD 0, a.modp, a.modn);
196✔
272

273
        for (int i=1,j; i<a[0]; i=j) {
216✔
274
                poly b(BHEAD 0, a.modp, a.modn);
199✔
275

276
                for (j=i; j<a[0]; j+=a[j]) {
404✔
277
                        bool same_powers = true;
1,177✔
278
                        for (int k=0; k<AN.poly_num_vars; k++)
1,177✔
279
                                if (k!=x && a[i+1+k]!=a[j+1+k]) {
972✔
280
                                        same_powers = false;
281
                                        break;
282
                                }
283
                        if (!same_powers) break;
332✔
284
                        
285
                        b.check_memory(b[0]+a[j]);
205✔
286
                        b.termscopy(&a[j],b[0],a[j]);
205✔
287
                        for (int k=0; k<AN.poly_num_vars; k++)
1,050✔
288
                                if (k!=x) b[b[0]+1+k]=0;
845✔
289
                        
290
                        b[0] += a[j];
205✔
291
                }                        
292

293
                res = gcd_Euclidean(res, b);
199✔
294
                
295
                if (res.is_integer()) {
199✔
296
                        res = poly(BHEAD a.sign(),a.modp,a.modn); 
179✔
297
                        break;
179✔
298
                }
299
        }        
199✔
300
        
301
#ifdef DEBUGALL
302
        cout << "*** [" << thetime() << "]  RES : content_multivar(" << a << "," << string(1,'a'+x) << ") = " << res << endl;
303
#endif
304

305
        return res;
196✔
306
}
×
307

308
/*
309
          #] content_multivar : 
310
                 #[ coefficient_list_gcd :
311
*/
312

313
/**  Euclidean algorithm for coefficient lists
314
 *
315
 *   Description
316
 *   ===========
317
 *   Calculates the greatest common divisor modulo a prime of two
318
 *   univariate polynomials represented by coefficient lists. The
319
 *   Euclidean algorithm is used to calculate it.
320
 *
321
 *   Notes
322
 *   =====
323
 *   - The result is normalized and has leading coefficient 1.
324
 */
325
const vector<WORD> polygcd::coefficient_list_gcd (const vector<WORD> &_a, const vector<WORD> &_b, WORD p) {
9,121✔
326

327
#ifdef DEBUGALL
328
        cout << "*** [" << thetime() << "]  CALL: coefficient_list_gcd("<<_a<<","<<_b<<","<<p<<")"<<endl;
329
#endif
330
        
331
        vector<WORD> a(_a), b(_b);
9,121✔
332
        
333
        while (b.size() != 0) {
154,669✔
334
          a = poly::coefficient_list_divmod(a,b,p,1);
145,548✔
335
                swap(a,b);
145,548✔
336
        }
337

338
        while (a.back()==0) a.pop_back();
9,271✔
339
        
340
        WORD inv;
9,121✔
341
        GetModInverses(a.back() + (a.back()<0?p:0), p, &inv, NULL);
15,083✔
342
        
343
        for (int i=0; i<(int)a.size(); i++)
20,304✔
344
                a[i] = (LONG)inv*a[i] % p;
11,183✔
345

346
#ifdef DEBUGALL
347
        cout << "*** [" << thetime() << "]  RES : coefficient_list_gcd("<<_a<<","<<_b<<","<<p<<") = "<<a<<endl;
348
#endif
349
        
350
        return a;
9,121✔
351
}
9,121✔
352

353
/*                
354
                 #] coefficient_list_gcd : 
355
          #[ gcd_Euclidean :
356
*/
357

358
/**  Euclidean Algorithm
359
 *
360
 *   Description
361
 *   ===========
362
 *   Returns the greatest common divisor of two univariate polynomials
363
 *   a(x) and b(x) with coefficients modulo a prime. If the
364
 *   polynomials are dense, they are converted to coefficient lists
365
 *   for efficiency.
366
 *
367
 *   Notes
368
 *   =====
369
 *   - Doesn't work over the integers or prime powers.
370
 *   - The result is normalized and has leading coefficient 1.
371
 *
372
 *   [for details, see "Algorithms for Computer Algebra", pp. 32-35]
373
 */
374
const poly polygcd::gcd_Euclidean (const poly &a, const poly &b) {
4,019✔
375

376
#ifdef DEBUG
377
        cout << "*** [" << thetime() << "]  CALL: gcd_Euclidean("<<a<<","<<b<<")"<<endl;
378
#endif
379

380
        POLY_GETIDENTITY(a);
4,019✔
381
        
382
        if (a.is_zero()) return b;
4,019✔
383
        if (b.is_zero()) return a;
3,823✔
384
        if (a.is_integer() || b.is_integer())        return integer_gcd(a,b);
3,823✔
385

386
        poly res(BHEAD 0);
3,622✔
387
        
388
        if (a.is_dense_univariate()>=-1 && b.is_dense_univariate()>=-1) {
3,622✔
389
                vector<WORD> coeff = coefficient_list_gcd(poly::to_coefficient_list(a),
6,806✔
390
                                                                                                                                                                                        poly::to_coefficient_list(b), a.modp);
10,209✔
391
                res = poly::from_coefficient_list(BHEAD coeff, a.first_variable(), a.modp);
3,403✔
392
        }
3,403✔
393
        else {
394
                res = a;
219✔
395
                poly rem(b);
219✔
396
                while (!rem.is_zero()) 
657✔
397
                        swap(res%=rem, rem);
438✔
398
                res /= res.integer_lcoeff();
219✔
399
        }
219✔
400

401
#ifdef DEBUG
402
        cout << "*** [" << thetime() << "]  RES : gcd_Euclidean("<<a<<","<<b<<") = "<<res<<endl;
403
#endif
404

405
        return res;
3,622✔
406
}
3,622✔
407

408
/*
409
          #] gcd_Euclidean : 
410
                 #[ chinese_remainder :
411
*/
412

413
/**  Chinese Remainder Algorithm
414
 *
415
 *   Description
416
 *   ===========
417
 *   Returns the unique number a mod (m1*m2) such that a = ai (mod mi)
418
 *   (i=1,2). The number is calculated with the Chinese Remainder Algorithm.
419
 *
420
 *   Notes
421
 *   =====
422
 *   - m1 and m2 must be relatively prime.
423
 *
424
 *   [for details, see "Algorithms for Computer Algebra", pp. 174-183]
425
 */
426
const poly polygcd::chinese_remainder (const poly &a1, const poly &m1, const poly &a2, const poly &m2) {
×
427

428
#ifdef DEBUGALL
429
        cout << "*** [" << thetime() << "]  CALL: chinese_remainder(" << a1 << "," << m1 << "," << a2 << "," << m2 << ")" << endl;
430
#endif
431

432
        POLY_GETIDENTITY(a1);
×
433
        
434
        WORD nx,ny,nz;
×
435
        UWORD *x = (UWORD *)NumberMalloc("polygcd::chinese_remainder");
×
436
        UWORD *y = (UWORD *)NumberMalloc("polygcd::chinese_remainder");
×
437
        UWORD *z = (UWORD *)NumberMalloc("polygcd::chinese_remainder");
×
438

439
        GetLongModInverses(BHEAD (UWORD *)&m1[2+AN.poly_num_vars], m1[m1[1]],
×
440
                                                                                 (UWORD *)&m2[2+AN.poly_num_vars], m2[m2[1]],
×
441
                                                                                 (UWORD *)x, &nx, NULL, NULL);
442
        
443
        AddLong((UWORD *)&a2[2+AN.poly_num_vars], a2.is_zero() ? 0 :  a2[a2[1]],
×
444
                                        (UWORD *)&a1[2+AN.poly_num_vars], a1.is_zero() ? 0 : -a1[a1[1]],
×
445
                                        y, &ny);
446

447
        MulLong (x,nx,y,ny,z,&nz);
×
448
        MulLong (z,nz,(UWORD *)&m1[2+AN.poly_num_vars],m1[m1[1]],x,&nx);
×
449

450
        AddLong (x,nx,(UWORD *)&a1[2+AN.poly_num_vars], a1.is_zero() ? 0 : a1[a1[1]],y,&ny);
×
451
        
452
        MulLong ((UWORD *)&m1[2+AN.poly_num_vars], m1[m1[1]],
×
453
                                         (UWORD *)&m2[2+AN.poly_num_vars], m2[m2[1]],
×
454
                                         (UWORD *)z,&nz);
455

456
        TakeNormalModulus (y,&ny,(UWORD *)z,nz,NOUNPACK);
×
457
        
458
        poly res(BHEAD y,ny);
×
459

460
        NumberFree(x,"polygcd::chinese_remainder");
×
461
        NumberFree(y,"polygcd::chinese_remainder");
×
462
        NumberFree(z,"polygcd::chinese_remainder");
×
463

464
#ifdef DEBUGALL
465
        cout << "*** [" << thetime() << "]  RES : chinese_remainder(" << a1 << "," << m1 << "," << a2 << "," << m2 << ") = " << res << endl;
466
#endif
467

468
        return res;
×
469
}
470

471
/*
472
          #] chinese_remainder : 
473
                 #[ substitute :
474
*/
475

476
/**  Substitute a variable of a polynomial with a number.
477
 *
478
 *   Description
479
 *   ===========
480
 *   Returns the polynomial that is obtained by substituting the
481
 *   variable x in the polynomial a by the constant c
482
 *
483
 *   Notes
484
 *   =====
485
 *   - if x is not the last variable (in lexicographical order) of the
486
 *     polynomial, the polynomial has to be normalised after.
487
 */
488
const poly polygcd::substitute(const poly &a, int x, int c) {
576✔
489

490
        POLY_GETIDENTITY(a);
576✔
491

492
        poly b(BHEAD 0);
576✔
493

494
        if (a.is_zero()) {
576✔
495
                return b;
496
        }
497

498
        bool zero=true;
576✔
499
        int bi=1;
576✔
500

501
        // cache size is bounded by the degree in x, twice the number of terms of
502
        // the polynomial and a constant
503
        vector<WORD> cache(min(a.degree(x)+1,min(2*a.number_of_terms(),
672✔
504
                                                                                                                                                                         POLYGCD_RAISPOWMOD_CACHE_SIZE)), 0);
1,152✔
505

506
        for (int ai=1; ai<=a[0]; ai+=a[ai]) {
548,722✔
507
                // last term or different power, then add term to b iff non-zero
508
                if (!zero) {
548,722✔
509
                        bool add=false;
548,146✔
510
                        if (ai==a[0])
548,146✔
511
                                add=true;
512
                        else {
513
                                for (int i=0; i<AN.poly_num_vars; i++)
2,110,462✔
514
                                        if (i!=x && a[ai+1+i]!=b[bi+1+i]) {
1,849,942✔
515
                                                zero=true;
516
                                                add=true;
517
                                                break;
518
                                        }
519
                        }
520

521
                        if (add) {
547,570✔
522
                                if (b[bi+AN.poly_num_vars+1] < 0)
287,626✔
523
                                        b[bi+AN.poly_num_vars+1] += a.modp;
148,338✔
524
                                bi+=b[bi];
287,626✔
525
                        }
526

527
                        if (ai==a[0]) break;
548,146✔
528
                }
529
                
530
                b.check_memory(bi);
548,146✔
531

532
                // create new term in b
533
                if (zero) {
548,146✔
534
                        b[bi] = 3+AN.poly_num_vars;
287,626✔
535
                        for (int i=0; i<AN.poly_num_vars; i++)
1,438,212✔
536
                                b[bi+1+i] = a[ai+1+i];
1,150,586✔
537
                        b[bi+1+x] = 0;
287,626✔
538
                        b[bi+AN.poly_num_vars+1] = 0;
287,626✔
539
                        b[bi+AN.poly_num_vars+2] = 1;
287,626✔
540
                }
541

542
                // add term of a to the current term in b
543
                LONG coeff = a[ai+1+AN.poly_num_vars] * a[ai+2+AN.poly_num_vars];
548,146✔
544
                int pow = a[ai+1+x];
548,146✔
545
                
546
                if (pow<(int)cache.size()) {
548,146✔
547
                        if (cache[pow]==0) 
548,140✔
548
                                cache[pow] = RaisPowMod(c, pow, a.modp);
4,992✔
549
                        coeff = (coeff * cache[pow]) % a.modp;
548,140✔
550
                }
551
                else {
552
                        coeff = (coeff * RaisPowMod(c, pow, a.modp)) % a.modp;
6✔
553
                }
554
                
555
                b[bi+AN.poly_num_vars+1] = (coeff + b[bi+AN.poly_num_vars+1]) % a.modp;
548,146✔
556
                if (b[bi+AN.poly_num_vars+1] != 0) zero=false;
548,146✔
557
        }
558

559
        b[0]=bi;
576✔
560
        b.setmod(a.modp);
576✔
561

562
        return b;        
576✔
563
}
576✔
564

565
/*
566
                 #] substitute : 
567
                 #[ sparse_interpolation helper functions :
568
*/
569

570
// Returns a list of size #terms(a) with entries PROD(ci^powi, i=2..n)
571
const vector<int> polygcd::sparse_interpolation_get_mul_list (const poly &a, const vector<int> &x, const vector<int> &c) {
104✔
572
        // cache size for variable x is bounded by the degree in x, twice
573
        // the number of terms of the polynomial and a constant
574
        vector<vector<WORD> > cache(c.size());
104✔
575
        int max_cache_size = min(2*a.number_of_terms(),POLYGCD_RAISPOWMOD_CACHE_SIZE);
104✔
576
        for (int i=0; i<(int)c.size(); i++)
256✔
577
                cache[i] = vector<WORD>(min(a.degree(x[i+1])+1,max_cache_size), 0);
154✔
578
        
579
        vector<int> res;
104✔
580
        for (int i=1; i<a[0]; i+=a[i]) {
143,010✔
581
                LONG coeff=1;
582
                for (int j=0; j<(int)c.size(); j++) {
416,780✔
583
                        int pow = a[i+1+x[j+1]];
273,874✔
584
                        if (pow<(int)cache[j].size()) {
273,874✔
585
                                if (cache[j][pow]==0) 
273,872✔
586
                                        cache[j][pow] = RaisPowMod(c[j], pow, a.modp);
2,312✔
587
                                coeff = (coeff * cache[j][pow]) % a.modp;
273,872✔
588
                        }
589
                        else {
590
                                coeff = (coeff * RaisPowMod(c[j], pow, a.modp)) % a.modp;
2✔
591
                        }
592
                }
593
                res.push_back(coeff);
142,906✔
594
        }
595
        return res;
104✔
596
}
104✔
597

598
// Multiplies the coefficients of a with the entries of mul
599
void polygcd::sparse_interpolation_mul_poly (poly &a, const vector<int> &mul) {
104✔
600
        for (int i=1,j=0; i<a[0]; i+=a[i],j++) 
143,010✔
601
                a[i+a[i]-2] = ((LONG)a[i+a[i]-2]*mul[j]) % a.modp;
142,906✔
602
}
104✔
603

604
// Sets all coefficients to the range 0..modp-1 and the powers of x2...xn to 0
605
const poly polygcd::sparse_interpolation_reduce_poly (const poly &a, const vector<int> &x) {
104✔
606
        poly res(a);
104✔
607
        for (int i=1; i<a[0]; i+=a[i]) {
143,010✔
608
                for (int j=1; j<(int)x.size(); j++)
416,780✔
609
                        res[i+1+x[j]]=0;
273,874✔
610
                if (res[i+a[i]-1]==-1) {
142,906✔
611
                        res[i+a[i]-1]=1;
69,760✔
612
                        res[i+a[i]-2]=a.modp-res[i+a[i]-2];
69,760✔
613
                }
614
        }
615
        return res;
104✔
616
}
617

618
// Collects entries with equal powers, so that the result is a proper polynomial
619
const poly polygcd::sparse_interpolation_fix_poly (const poly &a, int x) {
78✔
620
        
621
        POLY_GETIDENTITY(a);
78✔
622
        poly res(BHEAD 0,a.modp,1);
78✔
623

624
        int j=1;
78✔
625
        bool newterm=true;
78✔
626
                
627
        for (int i=1; i<a[0]; i+=a[i]) {
142,958✔
628
                if (newterm)
142,880✔
629
                        res.termscopy(&a[i], j, a[i]);
1,520✔
630
                else 
631
                        res[j+res[j]-2] = ((LONG)res[j+res[j]-2] + a[i+a[i]-2]) % a.modp;
141,360✔
632
                
633
                newterm = i+a[i] == a[0] || res[j+1+x] != a[i+a[i]+1+x];
142,880✔
634
                if (newterm && res[j+res[j]-2]!=0) j += res[j];
1,520✔
635
        }
636

637
        res[0]=j;
78✔
638
        return res;
78✔
639
}
640

641
/*
642
                 #] sparse_interpolation helper functions : 
643
                 #[ gcd_modular_sparse_interpolation :
644
*/
645

646
/**  Sparse interpolation for the modular gcd algorithm
647
 *
648
 *   Description
649
 *   ===========
650
 *   Assuming that it is known which terms of the gcd are non-zero
651
 *   (this is determined by dense interpolation), this method
652
 *   generates linear equations for the coefficients by substituting
653
 *   numbers. These equations are then solved by Gaussian elimination
654
 *   to give the correct coefficients of the gcd.
655
 *
656
 *   The first set of substitutions is randomly generated. The next
657
 *   set is obtained by squaring these numbers and so on. This results
658
 *   in matrix of equations which is solved by Gaussian elimination.
659
 *
660
 *   Notes
661
 *   =====
662
 *   - The method returns 0 upon failure. This is probably because the
663
 *     shape is wrong because of unlucky primes or substitutions.
664
 *   - The obtained matrix is a Vandermonde matrix, which can be
665
 *     inverted faster than with Gaussian elimination, see
666
 *     e.g. "Computing the Greatest Common Divisor of Multivariate
667
 *     Polynomials over Finite Fields" by Suling Yang. [TODO]
668
 *   - For calculation modulo small prime numbers, such a Vandermonde
669
 *     matrix does not exist, because there are not enough different
670
 *     numbers. In that case, we should resort to random equations of
671
 *     which enough exist. [TODO]
672
 *   - Non-monic cases are handled inefficiently. Implement LINZIP? [TODO]
673
 * 
674
 *   [for details, see "Algorithms for Computer Algebra", pp. 311-313; and
675
 *    R.E. Zippel, "Probabilistic Algorithms for Sparse Polynomials", PhD thesis]
676
 */
677
const poly polygcd::gcd_modular_sparse_interpolation (const poly &origa, const poly &origb, const vector<int> &x, const poly &s) {
26✔
678

679
#ifdef DEBUG
680
        cout << "*** [" << thetime() << "]  CALL: gcd_modular_sparse_interpolation("
681
                         << origa << "," << origb << "," << x << "," << "," << s <<")" << endl;
682
#endif
683

684
        POLY_GETIDENTITY(origa);
26✔
685

686
        // strip multivariate content
687
        poly conta(content_multivar(origa,x.back()));
26✔
688
        poly contb(content_multivar(origb,x.back()));
26✔
689
        poly gcdconts(gcd_Euclidean(conta,contb));
26✔
690
        const poly& a = conta.is_one() ? origa : origa/conta;
26✔
691
        const poly& b = contb.is_one() ? origb : origb/contb;
26✔
692

693
        // for non-monic cases, we need to normalize with the gcd of the lcoeffs of a poly in x[0]
694
        // or else the shape fitting does not work.
695
        // FIXME: the current implementation still rejects some valid shapes.
696
        poly lcgcd(BHEAD 1, a.modp);
26✔
697
        if (!s.lcoeff_univar(x[0]).is_integer()) {
26✔
698
                lcgcd = gcd_modular_dense_interpolation(a.lcoeff_univar(x[0]), b.lcoeff_univar(x[0]), x, poly(BHEAD 0));
1✔
699
        }
700

701
        // reduce polynomials
702
        poly ared(sparse_interpolation_reduce_poly(a,x));
26✔
703
        poly bred(sparse_interpolation_reduce_poly(b,x));
26✔
704
        poly sred(sparse_interpolation_reduce_poly(s,x));
26✔
705
        poly lred(sparse_interpolation_reduce_poly(lcgcd,x));
26✔
706

707
        // set all coefficients to 1
708
        for (int i=1; i<sred[0]; i+=sred[i]) {
52✔
709
                sred[i+sred[i]-2] = sred[i+sred[i]-1] = 1;
26✔
710
        }
711
        
712
        // generate random numbers and check there this set doesn't result
713
        // in a singular matrix
714
        vector<int> c(x.size()-1);
26✔
715
        vector<int> smul;
26✔
716

717
        bool duplicates;
26✔
718
        do {
26✔
719
                for (int i=0; i<(int)c.size(); i++)
64✔
720
                        c[i] = 1 + wranf(BHEAD0) % (a.modp-1);
38✔
721
                smul = sparse_interpolation_get_mul_list(s,x,c);
26✔
722

723
                duplicates = false;
26✔
724

725
                int fr=0,to=0;
26✔
726
                for (int i=1; i<s[0];) {
52✔
727
                        int pow = s[i+1+x[0]];
26✔
728
                        while (i<s[0] && s[i+1+x[0]]==pow) i+=s[i], to++;
52✔
729
                        for (int j=fr; j<to; j++)
52✔
730
                                for (int k=fr; k<j; k++)
26✔
731
                                        if (smul[j] == smul[k]) 
×
732
                                                duplicates = true;
×
733
                        fr=to;
734
                }                
735
        }
736
        while (duplicates);
737

738
        // get the lists to multiply the polynomials with every iteration
739
        vector<int> amul(sparse_interpolation_get_mul_list(a,x,c));
26✔
740
        vector<int> bmul(sparse_interpolation_get_mul_list(b,x,c));
26✔
741
        vector<int> lmul(sparse_interpolation_get_mul_list(lcgcd,x,c));
26✔
742

743
        vector<vector<vector<LONG> > > M;
26✔
744
        vector<vector<LONG> > V;
26✔
745

746
        int maxMsize=0;
26✔
747
        
748
        // create (empty) matrices
749
        for (int i=1; i<s[0]; i+=s[i]) {
52✔
750
                if (i==1 || s[i+1+x[0]]!=s[i+1+x[0]-s[i]]) {
26✔
751
                        M.push_back(vector<vector<LONG> >());
26✔
752
                        V.push_back(vector<LONG>());
26✔
753
                }
754
                M.back().push_back(vector<LONG>());
26✔
755
                V.back().push_back(0);
26✔
756
                maxMsize = max(maxMsize, (int)M.back().size());
52✔
757
        }
758

759
        // generate linear equations
760
        for (int numg=0; numg<maxMsize; numg++) {
52✔
761

762
                poly amodI(sparse_interpolation_fix_poly(ared,x[0]));
26✔
763
                poly bmodI(sparse_interpolation_fix_poly(bred,x[0]));
26✔
764
                poly lmodI(sparse_interpolation_fix_poly(lred,x[0]));
26✔
765

766
                // A fix for non-monic gcds. This could be slow if lmodI has many terms,
767
                // since it overfits the gcd now. Another gcd has to be run to remove the
768
                // extra terms.
769
                poly gcd(lmodI * gcd_Euclidean(amodI,bmodI));
26✔
770

771
                // if correct gcd
772
                if (!gcd.is_zero() && gcd[2+x[0]]==sred[2+x[0]]) {
26✔
773

774
                        // for each power in the gcd, generate an equation if needed
775
                        int gi=1, midx=0;
776
                        
777
                        for (int si=1; si<s[0];) {
52✔
778
                                // if the term exists, set Vi=coeff, otherwise Vi remains 0
779
                                if (gi<gcd[0] && gcd[gi+1+x[0]]==sred[si+1+x[0]]) {
26✔
780
                                        if (numg < (int)V[midx].size()) 
26✔
781
                                                V[midx][numg] = gcd[gi+gcd[gi]-1]*gcd[gi+gcd[gi]-2];
26✔
782
                                        gi += gcd[gi];
26✔
783
                                }
784

785
                                // add the coefficients of s to the matrix M
786
                                for (int i=0; i<(int)M[midx].size(); i++) {
52✔
787
                                        if (numg < (int)M[midx].size())
26✔
788
                                                M[midx][numg].push_back(sred[si+1+AN.poly_num_vars]);
26✔
789
                                        si += s[si];
26✔
790
                                }
791
                                
792
                                midx++;
26✔
793
                        }
794
                }
795
                else {
796
                        // incorrect gcd
797
                        if (!gcd.is_zero() && gcd[2+x[0]]<sred[2+x[0]])
×
798
                                return poly(BHEAD 0);
×
799
                        numg--;
×
800
                }
801
                
802
                // multiply polynomials by the lists to obtain new ones
803
                sparse_interpolation_mul_poly(ared,amul);
26✔
804
                sparse_interpolation_mul_poly(bred,bmul);
26✔
805
                sparse_interpolation_mul_poly(sred,smul);
26✔
806
                sparse_interpolation_mul_poly(lred,lmul);
26✔
807
        }
26✔
808

809
        // solve the linear equations
810
        for (int i=0; i<(int)M.size(); i++) {
52✔
811
                int n = M[i].size();
26✔
812

813
                // Gaussian elimination
814
                for (int j=0; j<n; j++) {
52✔
815
                        for (int k=0; k<j; k++) {
26✔
816
                                LONG x = M[i][j][k];
×
817
                                for (int l=k; l<n; l++) 
×
818
                                        M[i][j][l] = (M[i][j][l] - M[i][k][l]*x) % a.modp;
×
819
                                V[i][j] = (V[i][j] - V[i][k]*x) % a.modp;
×
820
                        }
821
                        
822
                        // normalize row
823
                        WORD x = M[i][j][j]; // WORD for GetModInverses
26✔
824
                        GetModInverses(x + (x<0?a.modp:0), a.modp, &x, NULL);
26✔
825
                        for (int k=0; k<n; k++) 
52✔
826
                                M[i][j][k] = (M[i][j][k]*x) % a.modp;
26✔
827
                        V[i][j] = (V[i][j]*x) % a.modp;
26✔
828
                }
829

830
                // solve
831
                for (int j=n-1; j>=0; j--)
52✔
832
                        for (int k=j+1; k<n; k++) 
26✔
833
                                V[i][j] = (V[i][j] - M[i][j][k]*V[i][k]) % a.modp;
×
834
        }
835

836
        // create coefficient list
837
        vector<LONG> coeff;
26✔
838
        for (int i=0; i<(int)V.size(); i++)
52✔
839
                for (int j=0; j<(int)V[i].size(); j++) 
52✔
840
                        coeff.push_back(V[i][j]);
26✔
841
        
842
        // create resulting polynomial
843
        poly res(BHEAD 0);
26✔
844
        int ri=1, i=0;
845
        for (int si=1; si<s[0]; si+=s[si]) {
52✔
846
                res.check_memory(ri);
26✔
847
                res[ri] = 3 + AN.poly_num_vars;             // term length
26✔
848
                for (int j=0; j<AN.poly_num_vars; j++) 
132✔
849
                        res[ri+1+j] = s[si+1+j];                  // powers
106✔
850
                res[ri+1+AN.poly_num_vars] = ABS(coeff[i]); // coefficient
26✔
851
                res[ri+2+AN.poly_num_vars] = SGN(coeff[i]); // coefficient length
26✔
852
                i++;
26✔
853
                ri += res[ri];
26✔
854
        }
855
        res[0]=ri;                                    // total length
26✔
856
        res.setmod(a.modp,1);
26✔
857

858
        if (!poly::divides(res, lcgcd * a) || !poly::divides(res, lcgcd * b)) {
51✔
859
                return poly(BHEAD 0); // bad shape
1✔
860
        } else {
861
                // refine gcd
862
                if (!poly::divides(res, a))
25✔
863
                        res = gcd_modular_dense_interpolation(res, a, x, poly(BHEAD 0));
×
864
                if (!poly::divides(res, b))
25✔
865
                        res = gcd_modular_dense_interpolation(res, b, x, poly(BHEAD 0));
×
866
        }
867

868
#ifdef DEBUG
869
        cout << "*** [" << thetime() << "]  RES : gcd_modular_sparse_interpolation("
870
                         << a << "," << b << "," << x << "," << "," << s <<") = " << res << endl;
871
#endif
872
        
873
        return gcdconts * res;
25✔
874
}
26✔
875

876
/*
877
          #] gcd_modular_sparse_interpolation : 
878
                 #[ gcd_modular_dense_interpolation :
879
*/
880

881
/**  Dense interpolation for the modular gcd algorithm
882
 *
883
 *   Description
884
 *   ===========
885
 *   This method determines the gcd by substituting multiple random
886
 *   values for the variables, calculating the univariate gcd with the
887
 *   Euclidean algorithm and interpolating a multivariate polynomial
888
 *   with Newton interpolation. Once a correct shape is known, sparse
889
 *   interpolation is used for efficiency.
890
 *
891
 *   Notes
892
 *   =====
893
 *   - The method returns 0 upon failure. This is probably because the
894
 *     shape is wrong because of unlucky primes or substitutions.
895
 *
896
 *   [for details, see "Algorithms for Computer Algebra", pp. 300-311]
897
 */
898

899
const poly polygcd::gcd_modular_dense_interpolation (const poly &a, const poly &b, const vector<int> &x, const poly &s) {
3,393✔
900
        
901
#ifdef DEBUG
902
        cout << "*** [" << thetime() << "]  CALL: gcd_modular_dense_interpolation(" << a << "," << b << "," << x << "," << s <<")" << endl;
903
#endif
904

905
        POLY_GETIDENTITY(a);
3,393✔
906

907
        // if univariate, then use Euclidean algorithm
908
        if (x.size() == 1) {
3,393✔
909
                return gcd_Euclidean(a,b);
3,320✔
910
        }
911

912
        // if shape is known, use sparse interpolation
913
        if (!s.is_zero()) {
73✔
914
                poly res = gcd_modular_sparse_interpolation (a,b,x,s);
26✔
915
                if (!res.is_zero()) return res;
26✔
916
                // apparently the shape was not correct. continue.
917
        }
26✔
918

919
        // divide out multivariate content in last variable
920
        int X = x.back();
48✔
921

922
        poly conta(content_multivar(a,X));
48✔
923
        poly contb(content_multivar(b,X));
48✔
924
        poly gcdconts(gcd_Euclidean(conta,contb));
48✔
925
        const poly& ppa = conta.is_one() ? a : poly(a/conta);
48✔
926
        const poly& ppb = contb.is_one() ? b : poly(b/contb);
48✔
927

928
        // gcd of leading coefficients
929
        poly lcoeffa(ppa.lcoeff_multivar(X));
48✔
930
        poly lcoeffb(ppb.lcoeff_multivar(X));
48✔
931
        poly gcdlcoeffs(gcd_Euclidean(lcoeffa,lcoeffb));
48✔
932

933
        // calculate the degree bound for each variable
934
        int m = MiN(ppa.degree(x[x.size() - 2]),ppb.degree(x[x.size() - 2]));
48✔
935

936
        poly res(BHEAD 0);
48✔
937
        poly oldres(BHEAD 0);
48✔
938
        poly newshape(BHEAD 0);
48✔
939
        poly modpoly(BHEAD 1,a.modp);
48✔
940
        
941
        while (true) {
96✔
942
                // generate random constants and substitute it
943
                int c = 1 + wranf(BHEAD0) % (a.modp-1);
96✔
944
                if (substitute(gcdlcoeffs,X,c).is_zero()) continue;
96✔
945
                if (substitute(modpoly,X,c).is_zero()) continue;
96✔
946
                
947
                poly amodc(substitute(ppa,X,c));
96✔
948
                poly bmodc(substitute(ppb,X,c));
96✔
949

950
                // calculate gcd recursively
951
                poly gcdmodc(gcd_modular_dense_interpolation(amodc,bmodc,vector<int>(x.begin(),x.end()-1), newshape));
96✔
952
                int n = gcdmodc.degree(x[x.size() - 2]);
96✔
953

954
                // normalize
955
                gcdmodc = (gcdmodc * substitute(gcdlcoeffs,X,c)) / gcdmodc.integer_lcoeff();
96✔
956
                poly simple(poly::simple_poly(BHEAD X,c,1,a.modp)); // (X-c) mod p
96✔
957

958
                // if power is smaller, the old one was wrong
959
                if ((res.is_zero() && n == m) || n < m) {
96✔
960
                        m = n;
48✔
961
                        res = gcdmodc;
48✔
962
                        newshape = gcdmodc; // set a new shape (interpolation does not change it)
48✔
963
                        modpoly = simple;
48✔
964
                }
965
                else if (n == m) {
48✔
966
                        oldres = res;
48✔
967
                        // equal powers, so interpolate results
968
                        poly coeff_poly(substitute(modpoly,X,c));
48✔
969
                        WORD coeff_word = coeff_poly[2+AN.poly_num_vars] * coeff_poly[3+AN.poly_num_vars];
48✔
970
                        if (coeff_word < 0) coeff_word += a.modp;
48✔
971

972
                        GetModInverses(coeff_word, a.modp, &coeff_word, NULL);
48✔
973
                        
974
                        res.setmod(a.modp); // make sure the mod is set before substituting
48✔
975
                        res += poly(BHEAD coeff_word, a.modp, 1) * modpoly * (gcdmodc - substitute(res,X,c));
48✔
976
                        modpoly *= simple;
48✔
977
                }
48✔
978

979
                // check whether this is the complete gcd
980
                if (!res.is_zero() && res == oldres) {
96✔
981
                        poly nres = res / content_multivar(res, X);
48✔
982
                        if (poly::divides(nres,ppa) && poly::divides(nres,ppb)) {
48✔
983
#ifdef DEBUG
984
                                cout << "*** [" << thetime() << "]  RES : gcd_modular_dense_interpolation(" << a << "," << b << ","
985
                                                 << x << "," << "," << s <<") = " << gcdconts * nres << endl;
986
#endif
987
                                return gcdconts * nres;
48✔
988
                        }
989

990
                        // At this point, the gcd may be too large due to bad luck
991
                        // TODO: create an efficient fail state that tries to find a smaller
992
                        // polynomial without interpolating bad ones?
993
                        newshape = poly(BHEAD 0); // reset the shape, important!
×
994
                }
48✔
995
        }
96✔
996
}
48✔
997

998
/*
999
          #] gcd_modular_dense_interpolation : : 
1000
                 #[ gcd_modular :
1001
*/
1002

1003
/**  Zippel's Modular GCD Algorithm
1004
 *
1005
 *   Description
1006
 *   ===========
1007
 *   This method choose a prime number and calls the method
1008
 *   "gcd_modular_dense_interpolation" to calculate the gcd modulo
1009
 *   this prime. It continues choosing more primes and constructs a
1010
 *   final result with the Chinese Remainder Algorithm.
1011
 *
1012
 *   Notes
1013
 *   =====
1014
 *   - Necessary condition: icont(a) = icont(b) = 0
1015
 *   - More efficient methods for the leading coefficient problem
1016
 *     exist, such as Linzip (see: "Algorithms for the Non-monic case
1017
 *     of the Sparse Modular GCD Algorithm" by De Kleine et al) [TODO]
1018
 */
1019
const poly polygcd::gcd_modular (const poly &origa, const poly &origb, const vector<int> &x) {
3,296✔
1020

1021
#ifdef DEBUG
1022
        cout << "*** [" << thetime() << "]  CALL: gcd_modular(" << origa << "," << origb << "," << x << ")" << endl;
1023
#endif
1024

1025
        POLY_GETIDENTITY(origa);
3,296✔
1026

1027
        if (origa.is_zero()) return origa.modp==0 ? origb : origb / origb.integer_lcoeff();
3,296✔
1028
        if (origb.is_zero()) return origa.modp==0 ? origa : origa / origa.integer_lcoeff();
3,296✔
1029
        if (origa==origb) return origa.modp==0 ? origa : origa / origa.integer_lcoeff();
3,296✔
1030

1031
        poly ac = integer_content(origa);
3,296✔
1032
        poly bc = integer_content(origb);
3,296✔
1033
        const poly& a = ac.is_one() ? origa : poly(origa/ac);
3,296✔
1034
        const poly& b = bc.is_one() ? origb : poly(origb/bc);
3,296✔
1035
        poly ic = integer_gcd(ac, bc);
3,296✔
1036
        poly g = integer_gcd(a.integer_lcoeff(), b.integer_lcoeff());
3,296✔
1037

1038
        int pnum=0;
3,296✔
1039
         
1040
        poly d(BHEAD 0);
3,296✔
1041
        poly m1(BHEAD 1);
3,296✔
1042
        int mindeg=MAXPOSITIVE;
1043

1044
        while (true) {
3,296✔
1045
                // choose a prime and solve modulo the prime
1046
                WORD p = NextPrime(BHEAD pnum++);
3,296✔
1047
                if (poly(a.integer_lcoeff(),p).is_zero()) continue;
3,296✔
1048
                if (poly(b.integer_lcoeff(),p).is_zero()) continue;
3,296✔
1049

1050
                poly c(gcd_modular_dense_interpolation(poly(a,p),poly(b,p),x,poly(d,p)));
3,296✔
1051
                c = (c * poly(g,p)) / c.integer_lcoeff(); // normalize so that lcoeff(c) = g mod p
3,296✔
1052

1053
                if (c.is_zero()) {
3,296✔
1054
                        // unlucky choices somewhere, so start all over again
1055
                        d = poly(BHEAD 0);
×
1056
                        m1 = poly(BHEAD 1);
×
1057
                        mindeg = MAXPOSITIVE;
×
1058
                        continue;
×
1059
                }
1060
                
1061
                if (!(poly(a,p)%c).is_zero()) continue;
3,296✔
1062
                if (!(poly(b,p)%c).is_zero()) continue;
3,296✔
1063

1064
                int deg = c.degree(x[0]);
3,296✔
1065

1066
                if (deg < mindeg) {
3,296✔
1067
                        // small degree, so the old one is wrong
1068
                        d=c;
3,296✔
1069
                        d.modp=a.modp;
3,296✔
1070
                        d.modn=a.modn;
3,296✔
1071
                        m1 = poly(BHEAD p);
3,296✔
1072
                        mindeg=deg;
3,296✔
1073
                }
1074
                else if (deg == mindeg) {
×
1075
                        // same degree, so use Chinese Remainder Algorithm
1076
                        poly newd(BHEAD 0);
×
1077
                        
1078
                        for (int ci=1,di=1; ci<c[0]||di<d[0]; ) {
×
1079
                                int comp = ci==c[0] ? -1 : di==d[0] ? +1 : poly::monomial_compare(BHEAD &c[ci],&d[di]);
×
1080
                                poly a1(BHEAD 0),a2(BHEAD 0);
×
1081
                                
1082
                                newd.check_memory(newd[0]);
×
1083
                                
1084
                                if (comp <= 0) {
×
1085
                                        newd.termscopy(&d[di],newd[0],1+AN.poly_num_vars);
×
1086
                                        a1 = poly(BHEAD (UWORD *)&d[di+1+AN.poly_num_vars],d[di+d[di]-1]);
×
1087
                                        di+=d[di];
×
1088
                                }
1089
                                if (comp >= 0) {
×
1090
                                        newd.termscopy(&c[ci],newd[0],1+AN.poly_num_vars);
×
1091
                                        a2 = poly(BHEAD (UWORD *)&c[ci+1+AN.poly_num_vars],c[ci+c[ci]-1]);
×
1092
                                        ci+=c[ci];
×
1093
                                }
1094

1095
                                poly e(chinese_remainder(a1,m1,a2,poly(BHEAD p)));
×
1096
                                newd.termscopy(&e[2+AN.poly_num_vars], newd[0]+1+AN.poly_num_vars, ABS(e[e[1]])+1);
×
1097
                                newd[newd[0]] = 2 + AN.poly_num_vars + ABS(e[e[1]]);
×
1098
                                newd[0] += newd[newd[0]];
×
1099
                        }
×
1100

1101
                        m1 *= poly(BHEAD p);
×
1102
                        d=newd;
×
1103
                }
×
1104

1105
                // divide out spurious integer content
1106
                poly ppd(d / integer_content(d));
3,296✔
1107

1108
                // check whether this is the complete gcd
1109
                if (poly::divides(ppd,a) && poly::divides(ppd,b)) {
3,296✔
1110
#ifdef DEBUG
1111
                        cout << "*** [" << thetime() << "]  RES : gcd_modular(" << origa << "," << origb << "," << x << ") = "
1112
                                         << ic * ppd << endl;
1113
#endif
1114
                        return ic * ppd;
3,296✔
1115
                }
1116
#ifdef DEBUG
1117
                cout << "*** [" << thetime() << "] Retrying modular_gcd with new prime" << endl;
1118
#endif
1119
        }
3,296✔
1120
}
3,296✔
1121

1122
/*
1123
          #] gcd_modular : 
1124
          #[ gcd_heuristic_possible :
1125
*/
1126

1127
/**  Heuristic greatest common divisor of multivariate polynomials
1128
 *
1129
 *   Description
1130
 *   ===========
1131
 *   Checks whether the heuristic seems possible by estimating
1132
 *
1133
 *      MAX_{terms} (coeff ^ PROD_{i=1..#vars} (pow_i+1))
1134
 *
1135
 *   and comparing this with GCD_HEURISTIC_MAX_DIGITS.
1136
 *
1137
 *   Notes
1138
 *   =====
1139
 *   - For small polynomials, this consumes time and never triggers.
1140
 */
1141

1142
bool gcd_heuristic_possible (const poly &a) {
2,475,460✔
1143

1144
        POLY_GETIDENTITY(a);
2,475,460✔
1145
        
1146
        double prod_deg = 1;
2,475,460✔
1147
        for (int j=0; j<AN.poly_num_vars; j++)
4,992,518✔
1148
                prod_deg *= a[2+j]+1;
2,517,058✔
1149

1150
        double digits = ABS(a[1+a[1]-1]);
2,475,460✔
1151
  double lead = a[1+1+AN.poly_num_vars];
2,475,460✔
1152
                
1153
        return prod_deg*(digits-1+log(2*ABS(lead))/log(2.0)/(BITSINWORD/2)) < POLYGCD_HEURISTIC_MAX_DIGITS;
2,475,460✔
1154
}
1155

1156
/*
1157
          #] gcd_heuristic_possible : 
1158
          #[ gcd_heuristic :
1159
*/
1160

1161

1162
/**  Heuristic greatest common divisor of multivariate polynomials
1163
 *
1164
 *   Description
1165
 *   ===========
1166
 *   The heuristic method for calculating the greatest common divisors
1167
 *   of a and b consists of the following steps:
1168
 *
1169
 *   - substite constants for the variables (each constant being
1170
 *     larger than the coefficients of the polynomial so far)
1171
 *   - calculate the integer gcd
1172
 *   - reconstruct the polynomial gcd from this by expanding it in
1173
 *     power of the constants
1174
 *
1175
 *   For low degree polynomials with small coefficients, this method is
1176
 *   very efficient. The method is aborted if the coefficients grow
1177
 *   too large.
1178
 *
1179
 *   Notes
1180
 *   =====
1181
 *   - a and b should be primitive
1182
 *   - result = c * gcd(a,b), with c an integer. This constant should
1183
 *     be divided out by the called method (it's the igcd).
1184
 *
1185
 *   [for details, see "Algorithms for Computer Algebra", pp. 320-331]
1186
 */
1187

1188
const poly polygcd::gcd_heuristic (const poly &a, const poly &b, const vector<int> &x, int max_tries) {
2,489,465✔
1189

1190
#ifdef DEBUG
1191
        cout << "*** [" << thetime() << "]  CALL: gcd_heuristic("<<a<<","<<b<<","<<x<<")\n";
1192
#endif
1193

1194
        if (a.is_integer())        return integer_gcd(a,integer_content(b));
2,489,465✔
1195
        if (b.is_integer())        return integer_gcd(integer_content(a),b);
1,250,919✔
1196

1197
        POLY_GETIDENTITY(a);
837,566✔
1198

1199
        // Calculate xi = 2*min(max(coefficients a),max(coefficients b))+2
1200

1201
        UWORD *pxi=NULL;
837,566✔
1202
        WORD nxi=0;
837,566✔
1203

1204
        for (int i=1; i<a[0]; i+=a[i]) {
5,066,537✔
1205
                WORD na = ABS(a[i+a[i]-1]);
3,818,960✔
1206
                if (BigLong((UWORD *)&a[i+a[i]-1-na], na, pxi, nxi) > 0) {
3,818,960✔
1207
                        pxi = (UWORD *)&a[i+a[i]-1-na];
3,601,855✔
1208
                        nxi = na;
3,601,855✔
1209
                }
1210
        }
1211
        
1212
        for (int i=1; i<b[0]; i+=b[i]) {                
5,221,591✔
1213
                WORD nb = ABS(b[i+b[i]-1]);
3,974,014✔
1214
                if (BigLong((UWORD *)&b[i+b[i]-1-nb], nb, pxi, nxi) > 0) {
3,974,014✔
1215
                        pxi = (UWORD *)&b[i+b[i]-1-nb];
935,003✔
1216
                        nxi = nb;
935,003✔
1217
                }
1218
        }
1219

1220
        poly xi(BHEAD pxi,nxi);
1,247,577✔
1221
        
1222
        // Addition of another random factor gives better performance
1223
        xi = xi*poly(BHEAD 2) + poly(BHEAD 2 + wranf(BHEAD0)%POLYGCD_HEURISTIC_MAX_ADD_RANDOM);
1,247,577✔
1224

1225
        // If degree*digits(xi) is too large, throw exception
1226
        if (max(a.degree(x[0]),b.degree(x[0])) * xi[xi[1]] >= MiN(AM.MaxTal, POLYGCD_HEURISTIC_MAX_DIGITS)) {
1,404,155✔
1227
#ifdef DEBUG
1228
                cout << "*** [" << thetime() << "]  RES : gcd_heuristic("<<a<<","<<b<<","<<x<<") = overflow\n";
1229
#endif
1230
                throw(gcd_heuristic_failed());
3,322✔
1231
        }
1232

1233
        for (int times=0; times<max_tries; times++) {
1,251,827✔
1234

1235
                // Recursively calculate the gcd
1236

1237
                poly gamma(gcd_heuristic(a % poly::simple_poly(BHEAD x[0],xi),
3,755,230✔
1238
                                                                                                                 b % poly::simple_poly(BHEAD x[0],xi),
2,503,495✔
1239
                                                                                                                 vector<int>(x.begin()+1,x.end()),1));
3,755,205✔
1240
                                                                                                                                         
1241
                // If a gcd is found, reconstruct the powers of x
1242
                if (!gamma.is_zero()) {
1,251,710✔
1243
                        // res is construct is reverse order. idx/len are for reversing
1244
                        // it in the correct order
1245
                        poly res(BHEAD 0), c(BHEAD 0);
1,251,618✔
1246
                        vector<int> idx, len;
1,251,618✔
1247
                        
1248
                        for (int power=0; !gamma.is_zero(); power++) {
2,528,029✔
1249

1250
                                // calculate c = gamma % xi (c and gamma are polynomials, xi is integer)
1251
                                c = gamma;
1,276,411✔
1252
                                c.coefficients_modulo((UWORD *)&xi[2+AN.poly_num_vars], xi[xi[0]-1], false);
1,276,411✔
1253
                                
1254
                                // Add the terms c * x^power to res
1255
                                res.check_memory(res[0]+c[0]);
1,276,411✔
1256
                                res.termscopy(&c[1],res[0],c[0]-1);
1,276,411✔
1257
                                for (int i=1; i<c[0]; i+=c[i])
2,555,172✔
1258
                                        res[res[0]-1+i+1+x[0]] = power;
1,278,761✔
1259

1260
                                // Store idx/len for reversing
1261
                                if (!c.is_zero()) {
1,276,411✔
1262
                                        idx.push_back(res[0]);
1,274,881✔
1263
                                        len.push_back(c[0]-1);
1,274,881✔
1264
                                }
1265
                                
1266
                                res[0] += c[0]-1;
1,276,411✔
1267

1268
                                // Divide gamma by xi
1269
                                gamma = (gamma - c) / xi;
1,276,411✔
1270
                        }
1271
                        
1272
                        // Reverse the resulting polynomial
1273
                        poly rev(BHEAD 0);
1,251,618✔
1274
                        rev.check_memory(res[0]);
1,251,618✔
1275
                        
1276
                        rev[0] = 1;
1,251,618✔
1277
                        for (int i=idx.size()-1; i>=0; i--) {
2,526,499✔
1278
                                rev.termscopy(&res[idx[i]], rev[0], len[i]);
1,274,881✔
1279
                                rev[0] += len[i];
1,274,881✔
1280
                        }
1281
                        res = rev;
1,251,618✔
1282

1283
                        poly ppres = res / integer_content(res);
1,251,618✔
1284

1285
                        if ((a%ppres).is_zero() && (b%ppres).is_zero()) {
2,495,756✔
1286
#ifdef DEBUG
1287
                                cout << "*** [" << thetime() << "]  RES : gcd_heuristic("<<a<<","<<b<<","<<x<<") = "<<res<<"\n";
1288
#endif
1289
                                return res;
1,244,138✔
1290
                        }
1291
                }
1,251,618✔
1292

1293
                // Next xi by multiplying with the golden ratio to avoid correlated errors
1294
                xi = xi * poly(BHEAD 28657) / poly(BHEAD 17711) + poly(BHEAD wranf(BHEAD0) % POLYGCD_HEURISTIC_MAX_ADD_RANDOM);
7,572✔
1295
        }
1,251,710✔
1296
        
1297
#ifdef DEBUG
1298
        cout << "*** [" << thetime() << "]  RES : gcd_heuristic("<<a<<","<<b<<","<<x<<") = failed\n";
1299
#endif
1300

1301
        return poly(BHEAD 0);
92✔
1302
}
1,247,577✔
1303

1304
/*
1305
          #] gcd_heuristic : 
1306
          #[ bracket :
1307
*/
1308

1309
const map<vector<int>,poly> polygcd::full_bracket(const poly &a, const vector<int>& filter) {
50✔
1310
        POLY_GETIDENTITY(a);
50✔
1311

1312
        map<vector<int>,poly> bracket;
50✔
1313
        for (int ai=1; ai<a[0]; ai+=a[ai]) {
169✔
1314
                vector<int> varpattern(AN.poly_num_vars);
119✔
1315
                for (int i=0; i<AN.poly_num_vars; i++)
432✔
1316
                        if (filter[i] == 1 && a[ai + i + 1] > 0)
313✔
1317
                                varpattern[i] = a[ai + i + 1];
58✔
1318

1319
                // create monomial
1320
                poly mon(BHEAD 1);
119✔
1321
                mon.setmod(a.modp);
119✔
1322
                mon[0] = a[ai] + 1;
119✔
1323
                for (int i=0; i<a[ai]; i++)
789✔
1324
                        if (i > 0 && i <= AN.poly_num_vars && varpattern[i - 1])
670✔
1325
                                mon[1+i] = 0;
58✔
1326
                        else
1327
                                mon[1+i] = a[ai+i];
612✔
1328

1329
                map<vector<int>,poly>::iterator i = bracket.find(varpattern);
119✔
1330
                if (i == bracket.end()) {
119✔
1331
                        bracket.insert(std::make_pair(varpattern, mon));
184✔
1332
                } else {
1333
                        i->second += mon;
27✔
1334
                }
1335
        }
119✔
1336

1337
        return bracket;
50✔
1338
}
×
1339

1340
const poly polygcd::bracket(const poly &a, const vector<int>& pattern, const vector<int>& filter) {
×
1341
        POLY_GETIDENTITY(a);
×
1342

1343
        poly bracket(BHEAD 0);
×
1344
        for (int ai=1; ai<a[0]; ai+=a[ai]) {
×
1345
                bool ispat = true;
×
1346
                for (int i=0; i<AN.poly_num_vars; i++)
×
1347
                        if (filter[i] == 1 && pattern[i] != a[ai + i + 1]) {
×
1348
                                ispat = false;
1349
                                break;
1350
                        }
1351

1352
                if (ispat) {
×
1353
                        poly mon(BHEAD 1);
×
1354
                        mon.setmod(a.modp);
×
1355
                        mon[0] = a[ai] + 1;
×
1356
                        for (int i=0; i<a[ai]; i++)
×
1357
                                if (i > 0 && i <= AN.poly_num_vars && pattern[i - 1])
×
1358
                                        mon[1+i] = 0;
×
1359
                                else
1360
                                        mon[1+i] = a[ai+i];
×
1361
                        bracket += mon;
×
1362
                }
×
1363
        }
1364

1365
        return bracket;
×
1366
}
×
1367

1368
const map<vector<int>,int> polygcd::bracket_count(const poly &a, const vector<int>& filter) {
×
1369
        POLY_GETIDENTITY(a);
×
1370

1371
        map<vector<int>,int> bracket;
×
1372
        for (int ai=1; ai<a[0]; ai+=a[ai]) {
×
1373
                vector<int> varpattern(AN.poly_num_vars);
×
1374
                for (int i=0; i<AN.poly_num_vars; i++)
×
1375
                        if (filter[i] == 1 && a[ai + i + 1] > 0)
×
1376
                                varpattern[i] = a[ai + i + 1];
×
1377

1378
                map<vector<int>,int>::iterator i = bracket.find(varpattern);
×
1379
                if (i == bracket.end()) {
×
1380
                        bracket.insert(std::make_pair(varpattern, 0));
×
1381
                } else {
1382
                        i->second++;
×
1383
                }
1384
        }
×
1385

1386
        return bracket;
×
1387
}
×
1388

1389
struct BracketInfo {
×
1390
        std::vector<int> pattern;
1391
        int num_terms, dummy = 0;
1392
        const poly* p;
1393

1394
        BracketInfo(const std::vector<int>& pattern, int num_terms, const poly* p) : pattern(pattern), num_terms(num_terms), p(p) {}
×
1395
        bool operator<(const BracketInfo& rhs) const { return num_terms > rhs.num_terms; } // biggest should be first!
×
1396
};
1397

1398
/*
1399
          #] bracket : 
1400
          #[ gcd_linear:
1401
*/
1402

1403
const poly gcd_linear_helper (const poly &a, const poly &b) {
6,665✔
1404
        POLY_GETIDENTITY(a);
6,665✔
1405

1406
        for (int i = 0; i < AN.poly_num_vars; i++)
13,468✔
1407
                if (a.degree(i) == 1) {
6,853✔
1408
                        vector<int> filter(AN.poly_num_vars);
50✔
1409
                        filter[i] = 1;
50✔
1410

1411
                        // bracket the linear variable
1412
                        map<vector<int>,poly> ba = polygcd::full_bracket(a, filter);
50✔
1413

1414
                        poly subgcd(BHEAD 1);
50✔
1415
                        if (ba.size() == 2)
50✔
1416
                                subgcd = polygcd::gcd_linear(ba.begin()->second, (++ba.begin())->second);
42✔
1417
                        else
1418
                                subgcd = ba.begin()->second;
8✔
1419

1420
                        poly linfac = a / subgcd;
50✔
1421
                        if (poly::divides(linfac,b))
50✔
1422
                                return linfac * polygcd::gcd_linear(subgcd, b / linfac);
8✔
1423

1424
                        return polygcd::gcd_linear(subgcd, b);
42✔
1425
                }
50✔
1426

1427
        return poly(BHEAD 0);
6,615✔
1428
}
1429

1430
/**
1431
        Performs a faster, recursive gcd algorithm if one of the variables in one of the
1432
        polynomials is linear. If no terms are linear, fall back to Zippel's method.
1433
*/
1434
const poly polygcd::gcd_linear (const poly &a, const poly &b) {
3,414✔
1435
#ifdef DEBUG
1436
        cout << "*** [" << thetime() << "]  CALL: gcd_linear("<<a<<","<<b<<")\n";
1437
#endif
1438

1439
        POLY_GETIDENTITY(a);
3,414✔
1440

1441
        if (a.is_zero()) return a.modp==0 ? b : b / b.integer_lcoeff();
3,414✔
1442
        if (b.is_zero()) return a.modp==0 ? a : a / a.integer_lcoeff();
3,414✔
1443
        if (a==b) return a.modp==0 ? a : a / a.integer_lcoeff();
3,414✔
1444

1445
        if (a.is_integer() || b.is_integer()) {
3,400✔
1446
                if (a.modp > 0) return poly(BHEAD 1,a.modp,a.modn);
54✔
1447
                return poly(integer_gcd(integer_content(a),integer_content(b)),0,1);
54✔
1448
        }
1449

1450
        poly h = gcd_linear_helper(a, b);
3,346✔
1451
        if (!h.is_zero()) return h;
3,346✔
1452

1453
        h = gcd_linear_helper(b, a);
3,319✔
1454
        if (!h.is_zero()) return h;
3,319✔
1455

1456
        vector<int> xa = a.all_variables();
3,296✔
1457
        vector<int> xb = b.all_variables();
3,296✔
1458

1459
        vector<int> used(AN.poly_num_vars,0);
3,296✔
1460
        for (int i=0; i<(int)xa.size(); i++) used[xa[i]]++;
6,632✔
1461
        for (int i=0; i<(int)xb.size(); i++) used[xb[i]]++;
6,630✔
1462
        vector<int> x;
3,296✔
1463
        for (int i=0; i<AN.poly_num_vars; i++)
6,654✔
1464
                if (used[i]) x.push_back(i);
3,358✔
1465

1466
        return gcd_modular(a,b,x);
3,296✔
1467
}
3,346✔
1468

1469
/*
1470
          #] gcd_linear: 
1471
          #[ gcd :
1472
*/
1473

1474
/**  Greatest common divisor (gcd) of multivariate polynomials
1475
 *   with coefficients in ZZ or ZZ/p
1476
 *
1477
 *   Description
1478
 *   ===========
1479
 *   Method calculates the gcd of multivariate polynomials with
1480
 *   integer coefficients, eventually modulo a prime number.
1481
 *
1482
 *   It consist of the following steps:
1483
 *   - Calculate the contents of a and b; now the following holds:
1484
 *     gcd(a,b) = gcd(cont(a),cont(b)) * gcd(pp(a),pp(b));
1485
 *   - Recursively calculate gcd(cont(a),cont(b)), which has one
1486
 *     variable less;
1487
 *   - If the coefficients are integers, try the heuristic gcd
1488
 *     method;
1489
 *   - If this method fails call the Zippel's method to calculate
1490
 *     the gcd of the two primitive polynomials pp(a) and pp(b).
1491
 *
1492
 *   [for details, see "Algorithms for Computer Algebra", pp. 314-320]
1493
 */
1494
const poly polygcd::gcd (const poly &a, const poly &b) {
2,550,832✔
1495

1496
#ifdef DEBUG
1497
        cout << "*** [" << thetime() << "]  CALL: gcd("<<a<<","<<b<<")\n";
1498
#endif
1499

1500
        POLY_GETIDENTITY(a);
2,550,832✔
1501
        
1502
        if (a.is_zero()) return a.modp==0 ? b : b / b.integer_lcoeff();
2,550,832✔
1503
        if (b.is_zero()) return a.modp==0 ? a : a / a.integer_lcoeff();
2,520,714✔
1504
         if (a==b) return a.modp==0 ? a : a / a.integer_lcoeff();
2,520,714✔
1505

1506
        if (a.is_integer() || b.is_integer()) {
2,494,796✔
1507
                if (a.modp > 0) return poly(BHEAD 1,a.modp,a.modn);
1,237,802✔
1508
                return poly(integer_gcd(integer_content(a),integer_content(b)),0,1);
1,237,802✔
1509
        }
1510

1511
        // Generate a list of variables of a and b
1512
        vector<int> xa = a.all_variables();
1,256,994✔
1513
        vector<int> xb = b.all_variables();
1,256,994✔
1514

1515
        vector<int> used(AN.poly_num_vars,0);
1,256,994✔
1516
        for (int i=0; i<(int)xa.size(); i++) used[xa[i]]++;
2,531,953✔
1517
        for (int i=0; i<(int)xb.size(); i++) used[xb[i]]++;
2,539,632✔
1518
        vector<int> x;
1,256,994✔
1519
        for (int i=0; i<AN.poly_num_vars; i++)
2,566,440✔
1520
                if (used[i]) x.push_back(i);
1,309,446✔
1521

1522
        if (a.is_monomial() || b.is_monomial()) {
1,256,994✔
1523

1524
                poly res(BHEAD 1,a.modp,a.modn);
18,029✔
1525
                if (a.modp == 0) res = integer_gcd(integer_content(a),integer_content(b));
18,029✔
1526
                
1527
                for (int i=0; i<(int)x.size(); i++)
46,190✔
1528
                        res[2+x[i]] = 1<<(BITSINWORD-2);
28,161✔
1529

1530
                for (int i=1; i<a[0]; i+=a[i]) 
43,027✔
1531
                        for (int j=0; j<(int)x.size(); j++) 
63,867✔
1532
                                res[2+x[j]] = MiN(res[2+x[j]], a[i+1+x[j]]);
38,869✔
1533
                
1534
                for (int i=1; i<b[0]; i+=b[i]) 
53,628✔
1535
                        for (int j=0; j<(int)x.size(); j++) 
104,434✔
1536
                                res[2+x[j]] = MiN(res[2+x[j]], b[i+1+x[j]]);
68,835✔
1537

1538
                return res;
18,029✔
1539
        }
18,029✔
1540

1541
        // Calculate the contents, their gcd and the primitive parts
1542
        poly conta(x.size()==1 ? integer_content(a) : content_univar(a,x[0]));
1,238,965✔
1543
        poly contb(x.size()==1 ? integer_content(b) : content_univar(b,x[0]));
1,238,965✔
1544
        poly gcdconts(x.size()==1 ? integer_gcd(conta,contb) : gcd(conta,contb));
1,238,965✔
1545
        const poly& ppa = conta.is_one() ? a : poly(a/conta);
1,238,965✔
1546
        const poly& ppb = contb.is_one() ? b : poly(b/contb);
1,238,965✔
1547
        
1548
        if (ppa == ppb) 
1,238,965✔
1549
                return ppa * gcdconts;
1,235✔
1550

1551
        poly res(BHEAD 0);
1,237,730✔
1552
        
1553
#ifdef POLYGCD_USE_HEURISTIC
1554
        // Try the heuristic gcd algorithm
1555
        if (a.modp==0 && gcd_heuristic_possible(a) && gcd_heuristic_possible(b)) {
1,237,730✔
1556
                try {
1,237,730✔
1557
                        res = gcd_heuristic(ppa,ppb,x);
1,237,730✔
1558
                        if (!res.is_zero()) res /= integer_content(res);
1,234,408✔
1559
                }
1560
                catch (gcd_heuristic_failed) {}
3,322✔
1561
        }
1562
#endif
1563
        
1564
        // If gcd==0, the heuristic algorithm failed, so we do more extensive checks.
1565
        // First, we filter out variables that appear in only one of the expressions.
1566
        if (res.is_zero()) {
1,237,730✔
1567
                bool unusedVars = false;
6,693✔
1568
                for (unsigned int i = 0; i < used.size(); i++) {
6,693✔
1569
                        if (used[i] == 1) {
3,371✔
1570
                                unusedVars = true;
1571
                                break;
1572
                        }
1573
                }
1574

1575
                // if there are no unused variables, go to the linear routine directly
1576
                if (!unusedVars) {
3,322✔
1577
                        res = gcd_linear(ppa,ppb);
3,322✔
1578
#ifdef DEBUG
1579
                        cout << "New GCD attempt (unused vars): " << res << endl;
1580
#endif
1581
                }
1582

1583
                // if res is not the gcd, it is 0 or larger than the gcd.
1584
                // we bracket the expression in all the variables that appear only in one expr.
1585
                // and we refine the gcd.
1586
                bool diva = !res.is_zero() && poly::divides(res,ppa);
3,322✔
1587
                bool divb = !res.is_zero() && poly::divides(res,ppb);
3,322✔
1588
                if (!diva || !divb) {
3,322✔
1589
                        vector<BracketInfo> bracketinfo;
×
1590

1591
                        if (!diva) {
×
1592
                                map<vector<int>,int> ba = bracket_count(ppa, used);
×
1593
                                for(map<vector<int>,int>::iterator it = ba.begin(); it != ba.end(); it++)
×
1594
                                        bracketinfo.push_back(BracketInfo(it->first, it->second, &ppa));
×
1595
                        }
×
1596

1597
                        if (!divb) {
×
1598
                                map<vector<int>,int> bb = bracket_count(ppb, used);
×
1599
                                for(map<vector<int>,int>::iterator it = bb.begin(); it != bb.end(); it++)
×
1600
                                        bracketinfo.push_back(BracketInfo(it->first, it->second, &ppb));
×
1601
                        }
×
1602

1603
                        // sort so that the smallest bracket will be last
1604
                        sort(bracketinfo.begin(), bracketinfo.end());
×
1605

1606
                        if (res.is_zero()) {
×
1607
                                res = bracket(*bracketinfo.back().p, bracketinfo.back().pattern, used);
×
1608
                                bracketinfo.pop_back();
×
1609
                        }
1610

1611
                        while (bracketinfo.size() > 0) {
×
1612
                                poly subpoly(bracket(*bracketinfo.back().p, bracketinfo.back().pattern, used));
×
1613
                                if (!poly::divides(res,subpoly)) {
×
1614
                                        // if we can filter out more variables, call gcd again
1615
                                        if (res.all_variables() != subpoly.all_variables())
×
1616
                                                res = gcd(subpoly,res);
×
1617
                                        else
1618
                                                res = gcd_linear(subpoly,res);
×
1619
                                }
1620

1621
                                bracketinfo.pop_back();
×
1622
                        }
×
1623
                }
×
1624

1625
                if (res.is_zero() || !poly::divides(res,ppa) || !poly::divides(res,ppb)) {
3,322✔
1626
                        MesPrint("Bad gcd found.");
×
1627
                        std::cout << "Bad gcd:" << res << " for " << ppa << " " << ppb << std::endl;
×
1628
                        Terminate(1);
×
1629
                }
1630
        }
1631

1632
        res *= gcdconts * poly(BHEAD res.sign());
1,237,730✔
1633

1634
#ifdef DEBUG
1635
        cout << "*** [" << thetime() << "]  RES : gcd("<<a<<","<<b<<") = "<<res<<endl;
1636
#endif
1637

1638
        return res;
1,237,730✔
1639
}
1,256,994✔
1640

1641
/*
1642
          #] gcd : 
1643
*/
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