• 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

90.78
/sources/poly.cc
1
/* @file poly.cc
2
 *
3
 *  Contains the class for representing sparse multivariate
4
 *  polynomials with integer coefficients
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
          #[ includes :
34
*/
35

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

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

45
using namespace std;
46

47
/*
48
          #] includes : 
49
          #[ constructor (small constant polynomial) :
50
*/
51

52
// constructor for a small constant polynomial
53
poly::poly (PHEAD int a, WORD modp, WORD modn):
81,069,831✔
54
        size_of_terms(AM.MaxTer/(LONG)sizeof(WORD)),
81,069,831✔
55
        modp(0),
81,069,831✔
56
        modn(1)
81,069,831✔
57
{
58
        POLY_STOREIDENTITY;
81,069,831✔
59
        
60
        terms = TermMalloc("poly::poly(int)");
81,069,831✔
61

62
        if (a == 0) {
81,069,831✔
63
                terms[0] = 1; // length
72,316,392✔
64
        }
65
        else {
66
                terms[0] = 4 + AN.poly_num_vars;                       // length
8,753,439✔
67
                terms[1] = 3 + AN.poly_num_vars;                       // length
8,753,439✔
68
                for (int i=0; i<AN.poly_num_vars; i++) terms[2+i] = 0; // powers
18,833,977✔
69
                terms[2+AN.poly_num_vars] = ABS(a);                    // coefficient
8,753,439✔
70
                terms[3+AN.poly_num_vars] = a>0 ? 1 : -1;              // length coefficient
8,809,405✔
71
        }
72

73
        if (modp!=-1) setmod(modp,modn);
81,069,831✔
74
}
81,069,831✔
75

76
/*
77
          #] constructor (small constant polynomial) : 
78
          #[ constructor (large constant polynomial) :
79
*/
80

81
// constructor for a large constant polynomial
82
poly::poly (PHEAD const UWORD *a, WORD na, WORD modp, WORD modn):
4,459,127✔
83
        size_of_terms(AM.MaxTer/(LONG)sizeof(WORD)),
4,459,127✔
84
        modp(0),
4,459,127✔
85
        modn(1)
4,459,127✔
86
{
87
        POLY_STOREIDENTITY;
4,459,127✔
88
        
89
        terms = TermMalloc("poly::poly(UWORD*,WORD)");
4,459,127✔
90

91
        // remove leading zeros
92
        while (*(a+ABS(na)-1)==0)
4,459,127✔
93
                na -= SGN(na);
×
94
                
95
        terms[0] = 3 + AN.poly_num_vars + ABS(na);               // length
4,459,127✔
96
        terms[1] = terms[0] - 1;                                 // length
4,459,127✔
97
        for (int i=0; i<AN.poly_num_vars; i++) terms[2+i] = 0;   // powers
9,058,042✔
98
        termscopy((WORD *)a, 2+AN.poly_num_vars, ABS(na));       // coefficient
4,459,127✔
99
        terms[2+AN.poly_num_vars+ABS(na)] = na;                         // length coefficient
4,459,127✔
100

101
        if (modp!=-1) setmod(modp,modn);
4,459,127✔
102
}
4,459,127✔
103

104
/*
105
          #] constructor (large constant polynomial) : 
106
          #[ constructor (deep copy polynomial) :
107
*/
108

109
// copy constructor: makes a deep copy of a polynomial
110
poly::poly (const poly &a, WORD modp, WORD modn):
18,792,623✔
111
        size_of_terms(AM.MaxTer/(LONG)sizeof(WORD))        
18,792,623✔
112
{
113
        POLY_GETIDENTITY(a);
18,792,623✔
114
        POLY_STOREIDENTITY;
18,792,623✔
115
        
116
        terms = TermMalloc("poly::poly(poly&)");
18,792,623✔
117

118
        *this = a;
18,792,623✔
119

120
        if (modp!=-1) setmod(modp,modn);
18,792,623✔
121
}
18,792,623✔
122

123
/*
124
          #] constructor (deep copy polynomial) : 
125
          #[ destructor :
126
*/
127

128
// destructor
129
poly::~poly () {
104,321,581✔
130

131
        POLY_GETIDENTITY(*this);
104,321,581✔
132
        
133
        if (size_of_terms == AM.MaxTer/(LONG)sizeof(WORD))
104,321,581✔
134
                TermFree(terms, "poly::~poly");
104,321,024✔
135
        else
136
                M_free(terms, "poly::~poly");
557✔
137
}
104,321,581✔
138

139
/*
140
          #] destructor : 
141
          #[ expand_memory :
142
*/
143

144
// expands the memory allocated for terms to at least twice its size
145
void poly::expand_memory (int i) {
605✔
146
        
147
        POLY_GETIDENTITY(*this);
605✔
148

149
        LONG new_size_of_terms = MaX(2*size_of_terms, i);
605✔
150
        if (new_size_of_terms > MAXPOSITIVE) {
605✔
151
                MLOCK(ErrorMessageLock);
×
152
                MesPrint ((char*)"ERROR: polynomials too large (> WORDSIZE)");
×
153
                MUNLOCK(ErrorMessageLock);
×
154
                Terminate(1);
×
155
        }
156
        
157
        WORD *newterms = (WORD *)Malloc1(new_size_of_terms * sizeof(WORD), "poly::expand_memory");
605✔
158
        WCOPY(newterms, terms, size_of_terms);
58,760,605✔
159

160
        if (size_of_terms == AM.MaxTer/(LONG)sizeof(WORD))
605✔
161
                TermFree(terms, "poly::expand_memory");
557✔
162
        else
163
                M_free(terms, "poly::expand_memory");
48✔
164

165
        terms = newterms;
605✔
166
        size_of_terms = new_size_of_terms;
605✔
167
}
605✔
168

169
/*
170
          #] expand_memory : 
171
          #[ setmod :
172
*/
173

174
// sets the coefficient space to ZZ/p^n
175
void poly::setmod(WORD _modp, WORD _modn) {
24,483,153✔
176

177
        POLY_GETIDENTITY(*this);
24,483,153✔
178
        
179
        if (_modp>0 && (_modp!=modp || _modn<modn)) {
24,483,153✔
180
                modp = _modp;
74,969✔
181
                modn = _modn;
74,969✔
182
        
183
                WORD nmodq=0;
74,969✔
184
                UWORD *modq=NULL;
74,969✔
185
                bool smallq;
74,969✔
186
                
187
                if (modn == 1) {
74,969✔
188
                        modq = (UWORD *)&modp;
58,247✔
189
                        nmodq = 1;
58,247✔
190
                        smallq = true;
58,247✔
191
                }
192
                else {
193
                        RaisPowCached(BHEAD modp,modn,&modq,&nmodq);
16,722✔
194
                        smallq = false;
195
                }
196
                
197
                coefficients_modulo(modq,nmodq,smallq);
74,969✔
198
        }
74,969✔
199
        else {
200
                modp = _modp;
24,408,184✔
201
                modn = _modn;
24,408,184✔
202
        }
203
}
24,483,153✔
204

205
/*
206
          #] setmod : 
207
          #[ coefficients_modulo :
208
*/
209

210
// reduces all coefficients of the polynomial modulo a
211
void poly::coefficients_modulo (UWORD *a, WORD na, bool small) {
1,351,380✔
212

213
        POLY_GETIDENTITY(*this);
1,351,380✔
214
        
215
        int j=1;
1,351,380✔
216
        for (int i=1, di; i<terms[0]; i+=di) {
4,773,606✔
217
                di = terms[i];
3,422,226✔
218
                
219
                if (i!=j)
3,422,226✔
220
                        for (int k=0; k<di; k++)
18,578,502✔
221
                                terms[j+k] = terms[i+k];
17,095,027✔
222
                
223
                WORD n = terms[j+terms[j]-1];
3,422,226✔
224

225
                if (ABS(n)==1 && small) {
3,422,226✔
226
                        // small number modulo small number
227
                        terms[j+1+AN.poly_num_vars] = n*((UWORD)terms[j+1+AN.poly_num_vars] % a[0]);
764,090✔
228
                        if (terms[j+1+AN.poly_num_vars] == 0)
764,090✔
229
                                n=0;
7,331✔
230
                        else {
231
                                if (terms[j+1+AN.poly_num_vars] > +(WORD)a[0]/2) terms[j+1+AN.poly_num_vars]-=a[0];
756,759✔
232
                                if (terms[j+1+AN.poly_num_vars] < -(WORD)a[0]/2) terms[j+1+AN.poly_num_vars]+=a[0];
756,759✔
233
                                n = SGN(terms[j+1+AN.poly_num_vars]);
756,759✔
234
                                terms[j+1+AN.poly_num_vars] = ABS(terms[j+1+AN.poly_num_vars]);
756,759✔
235
                        }
236
                }
237
                else
238
                        TakeNormalModulus((UWORD *)&terms[j+1+AN.poly_num_vars], &n, a, na, NOUNPACK);
2,658,136✔
239
                        
240
                if (n!=0) {
3,422,226✔
241
                        terms[j] = 2+AN.poly_num_vars+ABS(n);
3,401,444✔
242
                        terms[j+terms[j]-1] = n;
3,401,444✔
243
                        j += terms[j];
3,401,444✔
244
                }
245
        }
246
        
247
        terms[0] = j;
1,351,380✔
248
}
1,351,380✔
249

250
/*
251
          #] coefficients_modulo : 
252
          #[ to_string :
253
*/
254

255
// converts an integer to a string
256
const string int_to_string (WORD x) {
×
257
        char res[41];
×
258
        snprintf (res, 41, "%i",x);
×
259
        return res;
×
260
}
261

262
// converts a polynomial to a string
263
const string poly::to_string() const {
×
264
        
265
        POLY_GETIDENTITY(*this);
×
266
        
267
        string res;
×
268
        
269
        int printtimes;
×
270
        UBYTE *scoeff = (UBYTE *)NumberMalloc("poly::to_string");
×
271

272
        if (terms[0]==1)
×
273
                // zero
274
                res = "0";
×
275
        else {
276
                for (int i=1; i<terms[0]; i+=terms[i]) {
×
277

278
                        // sign
279
                        WORD ncoeff = terms[i+terms[i]-1];
×
280
                        if (ncoeff < 0) {
×
281
                                ncoeff*=-1;
×
282
                                res += "-";
×
283
                        }
284
                        else {
285
                                if (i>1) res += "+";
×
286
                        }
287

288
                        if (ncoeff==1 && terms[i+terms[i]-1-ncoeff]==1) {
×
289
                                // coeff=1, so don't print coefficient and '*'
290
                                printtimes = 0;
291
                        }                        
292
                        else {
293
                                // print coefficient
294
                                PrtLong((UWORD*)&terms[i+terms[i]-1-ncoeff], ncoeff, scoeff);
×
295
                                res += string((char *)scoeff);
×
296
                                printtimes=1;
×
297
                        }
298

299
                        // print variables
300
                        for (int j=0; j<AN.poly_num_vars; j++) {
×
301
                                if (terms[i+1+j] > 0) {
×
302
                                        if (printtimes) res += "*";
×
303
                                        res += string(1,'a'+j);
×
304
                                        if (terms[i+1+j] > 1) res += "^" + int_to_string(terms[i+1+j]);
×
305
                                        printtimes = 1;
306
                                }
307
                        }
308

309
                        // iff coeff=1 and all power=0, print '1' after all
310
                        if (!printtimes) res += "1";
×
311
                }
312
        }
313

314
        // eventual modulo
315
        if (modp>0) {
×
316
                res += " (mod ";
×
317
                res += int_to_string(modp);
×
318
                if (modn>1) {
×
319
                        res += "^";
×
320
                        res += int_to_string(modn);
×
321
                }
322
                res += ")";
×
323
        }
324

325
        NumberFree(scoeff,"poly::to_string");
×
326
        
327
        return res;
×
328
}
×
329

330
/*
331
          #] to_string : 
332
          #[ ostream operator :
333
*/
334

335
// output stream operator
336
ostream& operator<< (ostream &out, const poly &a) {
×
337
        return out << a.to_string();
×
338
}
339

340
/*
341
          #] ostream operator : 
342
          #[ monomial_compare :
343
*/
344

345
// compares two monomials (0:equal, <0:a smaller, >0:b smaller)
346
int poly::monomial_compare (PHEAD const WORD *a, const WORD *b) {
89,425,343✔
347
        for (int i=0; i<AN.poly_num_vars; i++)
232,663,630✔
348
                if (a[i+1]!=b[i+1]) return a[i+1]-b[i+1];
201,026,372✔
349
        return 0;
350
}
351

352
/*
353
          #] monomial_compare : 
354
          #[ normalize :
355
*/
356

357
// brings a polynomial to normal form
358
const poly & poly::normalize() {
2,221,782✔
359

360
        POLY_GETIDENTITY(*this);
2,221,782✔
361
 
362
        WORD nmodq=0;
2,221,782✔
363
        UWORD *modq=NULL;
2,221,782✔
364
        
365
        if (modp!=0) {
2,221,782✔
366
                if (modn == 1) {
×
367
                        modq = (UWORD *)&modp;
×
368
                        nmodq = 1;
×
369
                }
370
                else {
371
                        RaisPowCached(BHEAD modp,modn,&modq,&nmodq);
×
372
                }
373
        }
374

375
        // find and sort all monomials
376
        // terms[0]/num_vars+3 is an upper bound for number of terms in a
377

378
    LONG poffset = AT.pWorkPointer;
2,221,782✔
379
    WantAddPointers((terms[0]/(AN.poly_num_vars+3)));
2,222,015✔
380
    AT.pWorkPointer += terms[0]/(AN.poly_num_vars+3);
2,221,782✔
381
    #define p (&(AT.pWorkSpace[poffset]))
382

383
//        WORD **p = (WORD **)Malloc1(terms[0]/(AN.poly_num_vars+3) * sizeof(WORD*), "poly::normalize");
384
        
385
        int nterms = 0;
2,221,782✔
386
        for (int i=1; i<terms[0]; i+=terms[i])
8,787,384✔
387
                p[nterms++] = terms + i;
6,565,602✔
388

389
        sort(p, p + nterms, monomial_larger(BHEAD0));
2,221,782✔
390

391
        WORD *tmp;
2,221,782✔
392
        if (size_of_terms == AM.MaxTer/(LONG)sizeof(WORD)) {
2,221,782✔
393
                tmp = (WORD *)TermMalloc("poly::normalize");
2,221,782✔
394
        }
395
        else {
396
                tmp = (WORD *)Malloc1(size_of_terms * sizeof(WORD), "poly::normalize");
×
397
        }
398
        int j=1;
2,221,782✔
399
        int prevj=0;
2,221,782✔
400
        tmp[0]=0;
2,221,782✔
401
        tmp[1]=0;
2,221,782✔
402

403
        for (int i=0; i<nterms; i++) {
8,787,384✔
404
                if (i>0 && monomial_compare(BHEAD &tmp[j], p[i])==0) {
6,565,602✔
405
                        // duplicate term, so add coefficients
406
                        WORD ncoeff = tmp[j+tmp[j]-1];
×
407
                        AddLong((UWORD *)&tmp[j+1+AN.poly_num_vars], ncoeff,
×
408
                                                        (UWORD *)&p[i][1+AN.poly_num_vars], p[i][p[i][0]-1],
×
409
                                                        (UWORD *)&tmp[j+1+AN.poly_num_vars], &ncoeff);
×
410
                        
411
                        tmp[j+1+AN.poly_num_vars+ABS(ncoeff)] = ncoeff;
×
412
                        tmp[j] = 2+AN.poly_num_vars+ABS(ncoeff);
×
413
                }
414
                else {
415
                        // new term
416
                        prevj = j;
6,565,602✔
417
                        j += tmp[j];
6,565,602✔
418
                        WCOPY(&tmp[j],p[i],p[i][0]);
35,650,822✔
419
                }
420

421
                if (modp!=0) {
6,565,602✔
422
                        // bring coefficient to normal form mod p^n
423
                        WORD ntmp = tmp[j+tmp[j]-1];
×
424
                        TakeNormalModulus((UWORD *)&tmp[j+1+AN.poly_num_vars], &ntmp,          
×
425
                                                                                                modq,nmodq, NOUNPACK);
426
                        tmp[j] = 2+AN.poly_num_vars+ABS(ntmp);
×
427
                        tmp[j+tmp[j]-1] = ntmp;
×
428
                }                
429

430
                // add terms to polynomial
431
                if (tmp[j+tmp[j]-1]==0) {
6,565,602✔
432
                        tmp[j]=0;
×
433
                        j=prevj;
×
434
                }
435
        }
436

437
        j+=tmp[j];
2,221,782✔
438

439
        tmp[0] = j;
2,221,782✔
440
        WCOPY(terms,tmp,tmp[0]);
33,528,784✔
441

442
//        M_free(p, "poly::normalize");
443
        
444
        if (size_of_terms == AM.MaxTer/(LONG)sizeof(WORD))
2,221,782✔
445
                TermFree(tmp, "poly::normalize");
2,221,782✔
446
        else
447
                M_free(tmp, "poly::normalize");
×
448

449
        AT.pWorkPointer = poffset;
2,221,782✔
450
        #undef p
451

452
        return *this;
2,221,782✔
453
}
454

455
/*
456
          #] normalize : 
457
          #[ last_monomial_index :
458
*/
459

460
// index of the last monomial, i.e., the constant term
461
WORD poly::last_monomial_index () const {
8,812,091✔
462
        POLY_GETIDENTITY(*this);
8,812,091✔
463
        return terms[0] - ABS(terms[terms[0]-1]) - AN.poly_num_vars - 2;
8,812,091✔
464
}
465

466

467
// pointer to the last monomial (the constant term)
468
WORD * poly::last_monomial () const {
8,811,809✔
469
        return &terms[last_monomial_index()];
8,811,809✔
470
}
471

472
/*
473
          #] last_monomial_index : 
474
          #[ compare_degree_vector :
475
*/
476

477
int poly::compare_degree_vector(const poly & b) const {
×
478
        POLY_GETIDENTITY(*this);
×
479

480
        // special cases if one or both are 0
481
        if (terms[0] == 1 &&  b[0] == 1) return 0;
×
482
        if (terms[0] == 1) return -1;
×
483
        if (b[0] == 1) return 1;
×
484

485
        for (int i = 0; i < AN.poly_num_vars; i++) {
×
486
                int d1 = degree(i);
×
487
                int d2 = b.degree(i);
×
488
                if (d1 != d2) return d1 - d2;
×
489
        }
490

491
        return 0;
492
}
493

494
/*
495
          #] compare_degree_vector : 
496
          #[ degree_vector :
497
*/
498

499
std::vector<int> poly::degree_vector() const {
×
500
        POLY_GETIDENTITY(*this);
×
501

502
        std::vector<int> degrees(AN.poly_num_vars);
×
503
        for (int i = 0; i < AN.poly_num_vars; i++) {
×
504
                degrees[i] = degree(i);
×
505
        }
506

507
        return degrees;
×
508
}
509

510
/*
511
          #] degree_vector : 
512
          #[ compare_degree_vector :
513
*/
514

515
int poly::compare_degree_vector(const vector<int> & b) const {
×
516
        POLY_GETIDENTITY(*this);
×
517

518
        if (terms[0] == 1) return -1;
×
519

520
        for (int i = 0; i < AN.poly_num_vars; i++) {
×
521
                int d1 = degree(i);
×
522
                if (d1 != b[i]) return d1 - b[i];
×
523
        }
524

525
        return 0;
526
}
527

528
/*
529
          #] compare_degree_vector : 
530
          #[ add :
531
*/
532

533
// addition of polynomials by merging
534
void poly::add (const poly &a, const poly &b, poly &c) {
1,678,703✔
535

536
        POLY_GETIDENTITY(a);
1,678,703✔
537

538
  c.modp = a.modp;
1,678,703✔
539
  c.modn = a.modn;
1,678,703✔
540
        
541
        WORD nmodq=0;
1,678,703✔
542
        UWORD *modq=NULL;
1,678,703✔
543
        
544
        bool both_mod_small=false;
1,678,703✔
545
        
546
        if (c.modp!=0) {
1,678,703✔
547
                if (c.modn == 1) {
21,029✔
548
                        modq = (UWORD *)&c.modp;
81✔
549
                        nmodq = 1;
81✔
550
                        if (a.modp>0 && b.modp>0 && a.modn==1 && b.modn==1)
81✔
551
                                both_mod_small=true;
81✔
552
                }
553
                else {
554
                        RaisPowCached(BHEAD c.modp,c.modn,&modq,&nmodq);
20,948✔
555
                }
556
        }
557

558
        int ai=1,bi=1,ci=1;
1,678,703✔
559
        
560
        while (ai<a[0] || bi<b[0]) {
7,408,540✔
561

562
                c.check_memory(ci);
5,729,837✔
563
                
564
                int cmp = ai<a[0] && bi<b[0] ? monomial_compare(BHEAD &a[ai],&b[bi]) : 0;
5,729,090✔
565
                
566
                if (bi==b[0] || cmp>0) {
5,729,837✔
567
                        // insert term from a
568
                        c.termscopy(&a[ai],ci,a[ai]);
262,105✔
569
                        ci+=a[ai];
262,105✔
570
                        ai+=a[ai];
262,105✔
571
                }
572
                else if (ai==a[0] || cmp<0) {
5,467,732✔
573
                        // insert term from b
574
                        c.termscopy(&b[bi],ci,b[bi]);
56,579✔
575
                        ci+=b[bi];
56,579✔
576
                        bi+=b[bi];
56,579✔
577
                }
578
                else {
579
                        // insert term from a+b
580
                        c.termscopy(&a[ai],ci,MaX(a[ai],b[bi]));
5,411,153✔
581
                        WORD nc=0;
5,411,153✔
582
                        if (both_mod_small) {
5,411,153✔
583
                                c[ci+1+AN.poly_num_vars] = ((LONG)a[ai+1+AN.poly_num_vars]*a[ai+a[ai]-1]+
39✔
584
                                                                                                                                                (LONG)b[bi+1+AN.poly_num_vars]*b[bi+b[bi]-1]) % c.modp;
39✔
585
                                if ((WORD)c[ci+1+AN.poly_num_vars] > +c.modp/2) c[ci+1+AN.poly_num_vars] -= c.modp;
39✔
586
                                if ((WORD)c[ci+1+AN.poly_num_vars] < -c.modp/2) c[ci+1+AN.poly_num_vars] += c.modp;
39✔
587
                                nc = (c[ci+1+AN.poly_num_vars]==0 ? 0 : SGN((WORD)c[ci+1+AN.poly_num_vars]));
39✔
588
                                c[ci+1+AN.poly_num_vars] = ABS((WORD)c[ci+1+AN.poly_num_vars]);                                                                                                        
39✔
589
                        }
590
                        else {
591
                                AddLong((UWORD *)&a[ai+1+AN.poly_num_vars], a[ai+a[ai]-1],
5,411,114✔
592
                                                                (UWORD *)&b[bi+1+AN.poly_num_vars], b[bi+b[bi]-1],
5,411,114✔
593
                                                                (UWORD *)&c[ci+1+AN.poly_num_vars], &nc);
5,411,114✔
594
                                if (c.modp!=0) TakeNormalModulus((UWORD *)&c[ci+1+AN.poly_num_vars], &nc,
5,411,114✔
595
                                                                                                                                                                 modq, nmodq, NOUNPACK);
596
                        }
597
                                                        
598
                        if (nc!=0) {
5,411,153✔
599
                                c[ci] = 2+AN.poly_num_vars+ABS(nc);
5,115,708✔
600
                                c[ci+c[ci]-1] = nc;
5,115,708✔
601
                                ci += c[ci];
5,115,708✔
602
                        }
603
                        
604
                        ai+=a[ai];
5,411,153✔
605
                        bi+=b[bi];                        
5,411,153✔
606
                }                
607
        }
608

609
        c[0]=ci;
1,678,703✔
610
}
1,678,703✔
611

612
/*
613
          #] add : 
614
          #[ sub :
615
*/
616

617
// subtraction of polynomials by merging
618
void poly::sub (const poly &a, const poly &b, poly &c) {
1,335,437✔
619

620
        POLY_GETIDENTITY(a);
1,335,437✔
621
        
622
  c.modp = a.modp;
1,335,437✔
623
  c.modn = a.modn;
1,335,437✔
624

625
        WORD nmodq=0;
1,335,437✔
626
        UWORD *modq=NULL;
1,335,437✔
627
        
628
        bool both_mod_small=false;
1,335,437✔
629
        
630
        if (c.modp!=0) {
1,335,437✔
631
                if (c.modn == 1) {
40,406✔
632
                        modq = (UWORD *)&c.modp;
27,470✔
633
                        nmodq = 1;
27,470✔
634
                        if (a.modp>0 && b.modp>0 && a.modn==1 && b.modn==1)
27,470✔
635
                                both_mod_small=true;
27,470✔
636
                }
637
                else {
638
                        RaisPowCached(BHEAD c.modp,c.modn,&modq,&nmodq);
12,936✔
639
                }
640
        }
641
        
642
        int ai=1,bi=1,ci=1;
1,335,437✔
643
        
644
        while (ai<a[0] || bi<b[0]) {
3,970,557✔
645

646
                c.check_memory(ci);
2,635,120✔
647
                
648
                int cmp = ai<a[0] && bi<b[0] ? monomial_compare(BHEAD &a[ai],&b[bi]) : 0;
2,611,954✔
649
                
650
                if (bi==b[0] || cmp>0) {
2,635,120✔
651
                        // insert term from a
652
                        c.termscopy(&a[ai],ci,a[ai]);
79,311✔
653
                        ci+=a[ai];
79,311✔
654
                        ai+=a[ai];
79,311✔
655
                }
656
                else if (ai==a[0] || cmp<0) {
2,555,809✔
657
                        // insert term from b
658
                        c.termscopy(&b[bi],ci,b[bi]);
150,986✔
659
                        ci+=b[bi];
150,986✔
660
                        bi+=b[bi];
150,986✔
661
                        c[ci-1]*=-1;
150,986✔
662
                }
663
                else {
664
                        // insert term from a+b
665
                        c.termscopy(&a[ai],ci,MaX(a[ai],b[bi]));
2,404,823✔
666
                        WORD nc=0;
2,404,823✔
667
                        if (both_mod_small) {
2,404,823✔
668
                                c[ci+1+AN.poly_num_vars] = ((LONG)a[ai+1+AN.poly_num_vars]*a[ai+a[ai]-1]-
535,308✔
669
                                                                                                                                                (LONG)b[bi+1+AN.poly_num_vars]*b[bi+b[bi]-1]) % c.modp;
535,308✔
670
                                if ((WORD)c[ci+1+AN.poly_num_vars] > +c.modp/2) c[ci+1+AN.poly_num_vars] -= c.modp;
535,308✔
671
                                if ((WORD)c[ci+1+AN.poly_num_vars] < -c.modp/2) c[ci+1+AN.poly_num_vars] += c.modp;
535,308✔
672
                                nc = (c[ci+1+AN.poly_num_vars]==0 ? 0 : SGN((WORD)c[ci+1+AN.poly_num_vars]));
535,308✔
673
                                c[ci+1+AN.poly_num_vars] = ABS((WORD)c[ci+1+AN.poly_num_vars]);                                                                                                        
535,308✔
674
                        }
675
                        else {
676
                                AddLong((UWORD *)&a[ai+1+AN.poly_num_vars], a[ai+a[ai]-1],
1,869,515✔
677
                                                                (UWORD *)&b[bi+1+AN.poly_num_vars],-b[bi+b[bi]-1], // -b[...] causes subtraction
1,869,515✔
678
                                                                (UWORD *)&c[ci+1+AN.poly_num_vars], &nc);
1,869,515✔
679
                                if (c.modp!=0) TakeNormalModulus((UWORD *)&c[ci+1+AN.poly_num_vars], &nc,
1,869,515✔
680
                                                                                                                                                                 modq, nmodq, NOUNPACK);
681
                        }
682

683
                        if (nc!=0) {
2,404,823✔
684
                                c[ci] = 2+AN.poly_num_vars+ABS(nc);
893,432✔
685
                                c[ci+c[ci]-1] = nc;
893,432✔
686
                                ci += c[ci];
893,432✔
687
                        }
688
                        
689
                        ai+=a[ai];
2,404,823✔
690
                        bi+=b[bi];                        
2,404,823✔
691
                }                
692
        }
693

694
        c[0]=ci;
1,335,437✔
695
}
1,335,437✔
696

697
/*
698
          #] sub : 
699
          #[ pop_heap :
700
*/
701

702
// pops the largest monomial from the heap and stores it in heap[n]
703
void poly::pop_heap (PHEAD WORD **heap, int n) {
11,357,126✔
704

705
        WORD *old = heap[0];
11,357,126✔
706
        
707
        heap[0] = heap[--n];
11,357,126✔
708

709
        int i=0;
11,357,126✔
710
        while (2*i+2<n && (monomial_compare(BHEAD heap[2*i+1]+3, heap[i]+3)>0 ||
26,203,757✔
711
                                                                                 monomial_compare(BHEAD heap[2*i+2]+3, heap[i]+3)>0)) {
4,548,267✔
712
                
713
                if (monomial_compare(BHEAD heap[2*i+1]+3, heap[2*i+2]+3)>0) {
14,846,631✔
714
                        swap(heap[i], heap[2*i+1]);
7,877,641✔
715
                        i=2*i+1;
7,877,641✔
716
                }
717
                else {
718
                        swap(heap[i], heap[2*i+2]);
6,968,990✔
719
                        i=2*i+2;
6,968,990✔
720
                }
721
        }
722

723
        if (2*i+1<n && monomial_compare(BHEAD heap[2*i+1]+3, heap[i]+3)>0) 
11,357,126✔
724
                swap(heap[i], heap[2*i+1]);
666,494✔
725

726
        heap[n] = old;
11,357,126✔
727
}
11,357,126✔
728

729
/*
730
          #] pop_heap : 
731
          #[ push_heap :
732
*/
733

734
// pushes the monomial in heap[n] onto the heap
735
void poly::push_heap (PHEAD WORD **heap, int n)  {
11,044,773✔
736

737
        int i=n-1;
11,044,773✔
738

739
        while (i>0 && monomial_compare(BHEAD heap[i]+3, heap[(i-1)/2]+3) > 0) {
14,689,562✔
740
                swap(heap[(i-1)/2], heap[i]);
3,644,789✔
741
                i=(i-1)/2;
3,644,789✔
742
        }
743
}
11,044,773✔
744

745
/*
746
          #] push_heap : 
747
          #[ mul_one_term :
748
*/
749

750
// multiplies a polynomial with a monomial
751
void poly::mul_one_term (const poly &a, const poly &b, poly &c) {
1,321,155✔
752

753
  POLY_GETIDENTITY(a);
1,321,155✔
754
        
755
  int ci=1;
1,321,155✔
756

757
        WORD nmodq=0;
1,321,155✔
758
        UWORD *modq=NULL;
1,321,155✔
759
        
760
        bool both_mod_small=false;
1,321,155✔
761
        
762
        if (c.modp!=0) {
1,321,155✔
763
                if (c.modn == 1) {
11,404✔
764
                        modq = (UWORD *)&c.modp;
3,571✔
765
                        nmodq = 1;
3,571✔
766
                        if (a.modp>0 && b.modp>0 && a.modn==1 && b.modn==1)
3,571✔
767
                                both_mod_small=true;
3,571✔
768
                }
769
                else {
770
                        RaisPowCached(BHEAD c.modp,c.modn,&modq,&nmodq);
7,833✔
771
                }
772
        }
773
        
774
  for (int ai=1; ai<a[0]; ai+=a[ai])
2,819,701✔
775
    for (int bi=1; bi<b[0]; bi+=b[bi]) {
3,474,263✔
776
                        
777
                        c.check_memory(ci);
1,975,717✔
778
                
779
      for (int i=0; i<AN.poly_num_vars; i++)
5,199,165✔
780
        c[ci+1+i] = a[ai+1+i] + b[bi+1+i];
3,223,448✔
781
      WORD nc;
1,975,717✔
782

783
                        // if both polynomials are modulo p^1, use integer calculus
784
                        if (both_mod_small) {
1,975,717✔
785
                                c[ci+1+AN.poly_num_vars] =
23,280✔
786
                                        ((LONG)a[ai+1+AN.poly_num_vars] * a[ai+2+AN.poly_num_vars] *
23,280✔
787
                                         b[bi+1+AN.poly_num_vars] * b[bi+2+AN.poly_num_vars]) % c.modp;
23,280✔
788
                                nc = (c[ci+1+AN.poly_num_vars]==0 ? 0 : 1);
23,280✔
789
                        }
790
                        else {
791
                                // otherwise, use form long calculus
792
                                MulLong((UWORD *)&a[ai+1+AN.poly_num_vars], a[ai+a[ai]-1],
1,952,437✔
793
                                                                (UWORD *)&b[bi+1+AN.poly_num_vars], b[bi+b[bi]-1],
1,952,437✔
794
                                                                (UWORD *)&c[ci+1+AN.poly_num_vars], &nc);
1,952,437✔
795
                                if (c.modp!=0) TakeNormalModulus((UWORD *)&c[ci+1+AN.poly_num_vars], &nc,
1,952,437✔
796
                                                                                                                                                                 modq, nmodq, NOUNPACK);
797
                        }
798

799
                        if (nc!=0) {
1,975,717✔
800
                                c[ci] = 2+AN.poly_num_vars+ABS(nc);
1,975,717✔
801
                                ci += c[ci];
1,975,717✔
802

803
                                if (both_mod_small) {
1,975,717✔
804
                                        if (c[ci-2] > +c.modp/2) c[ci-2] -= c.modp;
23,280✔
805
                                        if (c[ci-2] < -c.modp/2) c[ci-2] += c.modp;
23,280✔
806
                                        c[ci-1] = SGN(c[ci-2]);
23,280✔
807
                                        c[ci-2] = ABS(c[ci-2]);
23,280✔
808
                                }
809
                                else {
810
                                        c[ci-1] = nc;
1,952,437✔
811
                                }
812
                        }
813
    }
814
        
815
  c[0]=ci;
1,321,155✔
816
}
1,321,155✔
817

818
/*
819
          #] mul_one_term : 
820
          #[ mul_univar :
821
*/
822

823
// dense univariate multiplication, i.e., for each power find all
824
// pairs of monomials that result in that power
825
void poly::mul_univar (const poly &a, const poly &b, poly &c, int var) {
3,651,651✔
826

827
        POLY_GETIDENTITY(a);
3,651,651✔
828

829
        WORD nmodq=0;
3,651,651✔
830
        UWORD *modq=NULL;
3,651,651✔
831

832
        bool both_mod_small=false;
3,651,651✔
833
        
834
        if (c.modp!=0) {
3,651,651✔
835
                if (c.modn == 1) {
40,417✔
836
                        modq = (UWORD *)&c.modp;
23,996✔
837
                        nmodq = 1;
23,996✔
838
                        if (a.modp>0 && b.modp>0 && a.modn==1 && b.modn==1)
23,996✔
839
                                both_mod_small=true;
23,993✔
840
                }
841
                else {
842
                        RaisPowCached(BHEAD c.modp,c.modn,&modq,&nmodq);
16,421✔
843
                }
844
        }
845
        
846
        poly t(BHEAD 0);
3,651,651✔
847
        WORD nt;
3,651,651✔
848
        
849
        int ci=1;
3,651,651✔
850

851
        // bounds on the powers in a*b
852
        int minpow = AN.poly_num_vars==0 ? 0 : a.last_monomial()[1+var] + b.last_monomial()[1+var];
3,651,651✔
853
        int maxpow = AN.poly_num_vars==0 ? 0 : a[2+var]+b[2+var];
3,651,651✔
854
        int afirst=1, blast=1;
855

856
        for (int pow=maxpow; pow>=minpow; pow--) {
23,007,394✔
857

858
                c.check_memory(ci);
19,355,743✔
859
                
860
                WORD nc=0;
19,355,743✔
861

862
                // adjust range in a or b
863
                if (a[afirst+1+var] + b[blast+1+var] > pow) {
19,355,743✔
864
                        if (blast+b[blast] < b[0])
15,176,392✔
865
                                blast+=b[blast];
866
                        else 
867
                                afirst+=a[afirst];
7,453,758✔
868
                }
869

870
                // find terms that result in the correct power
871
                for (int ai=afirst, bi=blast; ai<a[0] && bi>=1;) {
139,539,075✔
872
                        
873
                        int thispow = AN.poly_num_vars==0 ? 0 : a[ai+1+var] + b[bi+1+var];
120,183,332✔
874
                        
875
                        if (thispow == pow) {
120,183,332✔
876

877
                                // if both polynomials are modulo p^1, use integer calculus
878
                                if (both_mod_small) {
114,752,688✔
879
                                        c[ci+1+AN.poly_num_vars] =
31,086,222✔
880
                                                ((nc==0 ? 0 : (LONG)c[ci+1+AN.poly_num_vars] * nc) +
15,543,111✔
881
                                                (LONG)a[ai+1+AN.poly_num_vars] * a[ai+2+AN.poly_num_vars] *
15,543,111✔
882
                                                 b[bi+1+AN.poly_num_vars] * b[bi+2+AN.poly_num_vars]) % c.modp;
15,543,111✔
883
                                        nc = (c[ci+1+AN.poly_num_vars]==0 ? 0 : 1);
15,543,111✔
884
                                }
885
                                else {
886
                                        // otherwise, use form long calculus
887

888
                                        MulLong((UWORD *)&a[ai+1+AN.poly_num_vars], a[ai+a[ai]-1],
99,209,577✔
889
                                                                        (UWORD *)&b[bi+1+AN.poly_num_vars], b[bi+b[bi]-1],
99,209,577✔
890
                                                                        (UWORD *)&t[0], &nt);
99,209,577✔
891
                                        
892
                                        AddLong ((UWORD *)&t[0], nt,
99,209,577✔
893
                                                                         (UWORD *)&c[ci+1+AN.poly_num_vars], nc,
99,209,577✔
894
                                                                         (UWORD *)&c[ci+1+AN.poly_num_vars], &nc);
99,209,577✔
895

896
                                        if (c.modp!=0) TakeNormalModulus((UWORD *)&c[ci+1+AN.poly_num_vars], &nc,
99,209,577✔
897
                                                                                                                                                                         modq, nmodq, NOUNPACK);
898
                                }
899
                                
900
                                ai += a[ai];
114,752,688✔
901
                                bi -= ABS(b[bi-1]) + 2 + AN.poly_num_vars;
114,752,688✔
902
                        }
903
                        else if (thispow > pow) 
5,430,644✔
904
                                ai += a[ai];
2,370,780✔
905
                        else 
906
                                bi -= ABS(b[bi-1]) + 2 + AN.poly_num_vars;
3,059,864✔
907
                }
908

909
                // add term to result
910
                if (nc != 0) {
19,355,743✔
911
                        for (int j=0; j<AN.poly_num_vars; j++)
40,304,850✔
912
                                c[ci+1+j] = 0;
21,189,988✔
913
                        if (AN.poly_num_vars > 0)
19,114,862✔
914
                                c[ci+1+var] = pow;
19,114,862✔
915
                        
916
                        c[ci] =        2+AN.poly_num_vars+ABS(nc);
19,114,862✔
917
                        ci += c[ci];
19,114,862✔
918

919
                        // if necessary, adjust to range [-p/2,p/2]
920
                        if (both_mod_small) {
19,114,862✔
921
                                if (c[ci-2] > +c.modp/2) c[ci-2] -= c.modp;
1,115,847✔
922
                                if (c[ci-2] < -c.modp/2) c[ci-2] += c.modp;
1,115,847✔
923
                                c[ci-1] = SGN(c[ci-2]);
1,115,847✔
924
                                c[ci-2] = ABS(c[ci-2]);
1,115,847✔
925
                        }
926
                        else {
927
                                c[ci-1] = nc;
17,999,015✔
928
                        }
929
                }
930
        }
931

932
        c[0] = ci;
3,651,651✔
933
}
3,651,651✔
934

935
/*
936
          #] mul_univar : 
937
          #[ mul_heap :
938
*/
939

940
/**  Multiplication of polynomials with a heap
941
 *
942
 *   Description
943
 *   ===========
944
 *   Multiplies two multivariate polynomials. The next element of the
945
 *   product is efficiently determined by using a heap. If the product
946
 *   of the maximum power in all variables is small, a hash table is
947
 *   used to add equal terms for extra speed.
948
 *
949
 *   A heap element h is formatted as follows:
950
 *   - h[0] = index in a
951
 *   - h[1] = index in b
952
 *   - h[2] = hash code (-1 if no hash is used)
953
 *   - h[3] = length of coefficient with sign
954
 *   - h[4...4+AN.poly_num_vars-1] = powers 
955
 *   - h[4+AN.poly_num_vars...4+h[3]-1] = coefficient
956
 */
957
void poly::mul_heap (const poly &a, const poly &b, poly &c) {
29,440✔
958

959
        POLY_GETIDENTITY(a);
29,440✔
960

961
        WORD nmodq=0;
29,440✔
962
        UWORD *modq=NULL;
29,440✔
963
        
964
        bool both_mod_small=false;
29,440✔
965
        
966
        if (c.modp!=0) {
29,440✔
967
                if (c.modn == 1) {
28,245✔
968
                        modq = (UWORD *)&c.modp;
14,112✔
969
                        nmodq = 1;
14,112✔
970
                        if (a.modp>0 && b.modp>0 && a.modn==1 && b.modn==1)
14,112✔
971
                                both_mod_small=true;
14,112✔
972
                }
973
                else {
974
                        RaisPowCached(BHEAD c.modp,c.modn,&modq,&nmodq);
14,133✔
975
                }
976
        }
977

978
        // find maximum powers in different variables
979
        WORD *maxpower  = AT.WorkPointer;
29,440✔
980
        AT.WorkPointer += AN.poly_num_vars;
29,440✔
981
        WORD *maxpowera = AT.WorkPointer;
29,440✔
982
        AT.WorkPointer += AN.poly_num_vars;
29,440✔
983
        WORD *maxpowerb = AT.WorkPointer;
29,440✔
984
        AT.WorkPointer += AN.poly_num_vars;
29,440✔
985

986
        for (int i=0; i<AN.poly_num_vars; i++)
113,042✔
987
                maxpowera[i] = maxpowerb[i] = 0;
83,602✔
988

989
        for (int ai=1; ai<a[0]; ai+=a[ai])
234,021✔
990
                for (int j=0; j<AN.poly_num_vars; j++)
665,233✔
991
                        maxpowera[j] = MaX(maxpowera[j], a[ai+1+j]);
460,652✔
992

993
        for (int bi=1; bi<b[0]; bi+=b[bi])
654,478✔
994
                for (int j=0; j<AN.poly_num_vars; j++)
2,709,201✔
995
                        maxpowerb[j] = MaX(maxpowerb[j], b[bi+1+j]);
2,084,163✔
996

997
        for (int i=0; i<AN.poly_num_vars; i++)
113,042✔
998
                maxpower[i] = maxpowera[i] + maxpowerb[i];
83,602✔
999

1000
        // if PROD(maxpower) small, use hash array
1001
        bool use_hash = true;
99,788✔
1002
        int nhash = 1;
1003

1004
        for (int i=0; i<AN.poly_num_vars; i++) {
99,788✔
1005
                if (nhash > POLY_MAX_HASH_SIZE / (maxpower[i]+1)) {
70,630✔
1006
                        nhash = 1;
1007
                        use_hash = false;
1008
                        break;
1009
                }
1010
                nhash *= maxpower[i]+1;
70,348✔
1011
        }
1012

1013
        // allocate heap and hash
1014
        int nheap=a.number_of_terms();
29,440✔
1015

1016
        WantAddPointers(nheap+nhash);
29,575✔
1017
        WORD **heap = AT.pWorkSpace + AT.pWorkPointer;
29,440✔
1018

1019
        for (int ai=1, i=0; ai<a[0]; ai+=a[ai], i++) {
234,021✔
1020
                heap[i] = (WORD *) NumberMalloc("poly::mul_heap");
204,581✔
1021
                heap[i][0] = ai;
204,581✔
1022
                heap[i][1] = 1;
204,581✔
1023
                heap[i][2] = -1;
204,581✔
1024
                heap[i][3] = 0;
204,581✔
1025
                for (int j=0; j<AN.poly_num_vars; j++)
665,233✔
1026
                        heap[i][4+j] = MAXPOSITIVE;
460,652✔
1027
        }
1028
        
1029
        WORD **hash = AT.pWorkSpace + AT.pWorkPointer + nheap;
29,440✔
1030
        for (int i=0; i<nhash; i++)
9,579,070✔
1031
                hash[i] = NULL;
9,549,630✔
1032

1033
        int ci = 1;
1034

1035
        // multiply
1036
        while (nheap > 0) {
1,585,662✔
1037

1038
                c.check_memory(ci);
1,556,222✔
1039
                
1040
                pop_heap(BHEAD heap, nheap--);
1,556,222✔
1041
                WORD *p = heap[nheap];
1,556,222✔
1042

1043
                // if non-zero
1044
                if (p[3] != 0) {
1,556,222✔
1045
                        if (use_hash) hash[p[2]] = NULL;
1,205,560✔
1046

1047
                        c[0] = ci;
1,205,560✔
1048

1049
                        // append this term to the result
1050
                        if (use_hash || ci==1 || monomial_compare(BHEAD p+3, c.last_monomial())!=0) {
1,205,560✔
1051
                                p[4 + AN.poly_num_vars + ABS(p[3])] = p[3];
1,205,278✔
1052
                                p[3] = 2 + AN.poly_num_vars + ABS(p[3]);
1,205,278✔
1053
                                c.termscopy(&p[3],ci,p[3]);
1,205,278✔
1054
                                ci += c[ci];
1,205,278✔
1055
                        }
1056
                        else {
1057
                                // add this term to the last term of the result
1058
                                ci = c.last_monomial_index();
282✔
1059
                                WORD nc = c[ci+c[ci]-1];
282✔
1060

1061
                                // if both polynomials are modulo p^1, use integer calculus
1062
                                if (both_mod_small) {
282✔
1063
                                        c[ci+AN.poly_num_vars+1] = ((LONG)c[ci+AN.poly_num_vars+1]*nc + p[4+AN.poly_num_vars]*p[3]) % c.modp;
×
1064
                                        if (c[ci+1+AN.poly_num_vars]==0)
×
1065
                                                nc = 0;
×
1066
                                        else {
1067
                                                if (c[ci+1+AN.poly_num_vars] > +c.modp/2) c[ci+1+AN.poly_num_vars] -= c.modp;
×
1068
                                                if (c[ci+1+AN.poly_num_vars] < -c.modp/2) c[ci+1+AN.poly_num_vars] += c.modp;
×
1069
                                                nc = SGN(c[ci+1+AN.poly_num_vars]);
×
1070
                                                c[ci+1+AN.poly_num_vars] = ABS(c[ci+1+AN.poly_num_vars]);
×
1071
                                        }
1072
                                }
1073
                                else {
1074
                                        // otherwise, use form long calculus
1075
                                        AddLong ((UWORD *)&p[4+AN.poly_num_vars], p[3],
282✔
1076
                                                                         (UWORD *)&c[ci+AN.poly_num_vars+1], nc,
282✔
1077
                                                                         (UWORD *)&c[ci+AN.poly_num_vars+1],&nc);
282✔
1078
                                        
1079
                                        if (c.modp!=0) TakeNormalModulus((UWORD *)&c[ci+1+AN.poly_num_vars], &nc,
282✔
1080
                                                                                                                                                                         modq, nmodq, NOUNPACK);
1081
                                }
1082
                                
1083
                                if (nc!=0) {
282✔
1084
                                        c[ci] = 2 + AN.poly_num_vars + ABS(nc);
282✔
1085
                                        ci += c[ci];
282✔
1086
                                        c[ci-1] = nc;
282✔
1087
                                }
1088
                        }
1089
                }
1090

1091
                // add new term to the heap (ai, bi+1)
1092
                while (p[1] < b[0]) {
6,432,547✔
1093
                        
1094
                        for (int j=0; j<AN.poly_num_vars; j++)
20,469,064✔
1095
                                p[4+j] = a[p[0]+1+j] + b[p[1]+1+j];
14,241,098✔
1096

1097
                        // if both polynomials are modulo p^1, use integer calculus
1098
                        if (both_mod_small) {
6,227,966✔
1099
                                p[4+AN.poly_num_vars] = ((LONG)a[p[0]+1+AN.poly_num_vars]*a[p[0]+a[p[0]]-1]*
4,832,229✔
1100
                                                                                                                                 b[p[1]+1+AN.poly_num_vars]*b[p[1]+b[p[1]]-1]) % c.modp;
4,832,229✔
1101
                                if (p[4+AN.poly_num_vars]==0)
4,832,229✔
1102
                                        p[3]=0;
×
1103
                                else {
1104
                                        if (p[4+AN.poly_num_vars] > +c.modp/2) p[4+AN.poly_num_vars] -= c.modp;
4,832,229✔
1105
                                        if (p[4+AN.poly_num_vars] < -c.modp/2) p[4+AN.poly_num_vars] += c.modp;
4,832,229✔
1106
                                        p[3] = SGN(p[4+AN.poly_num_vars]);
4,832,229✔
1107
                                        p[4+AN.poly_num_vars] = ABS(p[4+AN.poly_num_vars]);
4,832,229✔
1108
                                }
1109
                        }
1110
                        else {
1111
                                // otherwise, use form long calculus
1112
                                MulLong((UWORD *)&a[p[0]+1+AN.poly_num_vars], a[p[0]+a[p[0]]-1],
1,395,737✔
1113
                                                                (UWORD *)&b[p[1]+1+AN.poly_num_vars], b[p[1]+b[p[1]]-1],
1,395,737✔
1114
                                                                (UWORD *)&p[4+AN.poly_num_vars], &p[3]);
1,395,737✔
1115
                                
1116
                                if (c.modp!=0) TakeNormalModulus((UWORD *)&p[4+AN.poly_num_vars], &p[3],
1,395,737✔
1117
                                                                                                                                                                 modq, nmodq, NOUNPACK);                                
1118
                        }
1119
                        
1120
                        p[1] += b[p[1]];
6,227,966✔
1121

1122
                        if (use_hash) {
6,227,966✔
1123
                                int ID = 0;
1124
                                for (int i=0; i<AN.poly_num_vars; i++)
18,869,224✔
1125
                                        ID = (maxpower[i]+1)*ID + p[4+i];
12,665,498✔
1126

1127
                                // if hash and unused, push onto heap
1128
                                if (hash[ID] == NULL) {
6,203,726✔
1129
                                        p[2] = ID;
1,327,401✔
1130
                                        hash[ID] = p;
1,327,401✔
1131
                                        push_heap(BHEAD heap, ++nheap);
1,327,401✔
1132
                                        break;
1,327,401✔
1133
                                }
1134
                                else {
1135
                                        // if hash and used, add to heap element
1136
                                        WORD *h = hash[ID];
4,876,325✔
1137
                                        // if both polynomials are modulo p^1, use integer calculus
1138
                                        if (both_mod_small) {
4,876,325✔
1139
                                                h[4+AN.poly_num_vars] = ((LONG)p[4+AN.poly_num_vars]*p[3] + h[4+AN.poly_num_vars]*h[3]) % c.modp;
4,029,303✔
1140
                                                if (h[4+AN.poly_num_vars]==0) 
4,029,303✔
1141
                                                        h[3]=0;
287,361✔
1142
                                                else {
1143
                                                        if (h[4+AN.poly_num_vars] > +c.modp/2) h[4+AN.poly_num_vars] -= c.modp;
3,741,942✔
1144
                                                        if (h[4+AN.poly_num_vars] < -c.modp/2) h[4+AN.poly_num_vars] += c.modp;
3,741,942✔
1145
                                                        h[3] = SGN(h[4+AN.poly_num_vars]);
3,741,942✔
1146
                                                        h[4+AN.poly_num_vars] = ABS(h[4+AN.poly_num_vars]);
3,741,942✔
1147
                                                }
1148
                                        }
1149
                                        else {
1150
                                                // otherwise, use form long calculus
1151
                                                AddLong ((UWORD *)&p[4+AN.poly_num_vars],  p[3],
847,022✔
1152
                                                                                 (UWORD *)&h[4+AN.poly_num_vars],  h[3],
1153
                                                                                 (UWORD *)&h[4+AN.poly_num_vars], &h[3]);
847,022✔
1154

1155
                                                if (c.modp!=0) TakeNormalModulus((UWORD *)&h[4+AN.poly_num_vars], &h[3],
847,022✔
1156
                                                                                                                                                                                 modq, nmodq, NOUNPACK);
1157
                                        }
1158
                                }
1159
                        }
1160
                        else {
1161
                                // if no hash, push onto heap
1162
                                p[2] = -1;
24,240✔
1163
                                push_heap(BHEAD heap, ++nheap);
24,240✔
1164
                                break;
24,240✔
1165
                        }
1166
                }
1167
        }
1168

1169
        c[0] = ci;
29,440✔
1170
        
1171
        for (int ai=1, i=0; ai<a[0]; ai+=a[ai], i++)
234,021✔
1172
                NumberFree(heap[i],"poly::mul_heap");
204,581✔
1173
        AT.WorkPointer -= 3 * AN.poly_num_vars;
29,440✔
1174
}
29,440✔
1175

1176
/*
1177
          #] mul_heap : 
1178
          #[ mul :
1179
*/
1180

1181
/**  Polynomial multiplication
1182
 *
1183
 *   Description
1184
 *   ===========
1185
 *   This routine determines which multiplication routine to use for
1186
 *   multiplying two polynomials. The logic is as follows:
1187
 *   - If a or b consists of only one term, call mul_one_term;
1188
 *   - Otherwise, if both are univariate and dense, call mul_univar;
1189
 *   - Otherwise, call mul_heap.
1190
 */
1191
void poly::mul (const poly &a, const poly &b, poly &c) {
11,821,254✔
1192

1193
  c.modp = a.modp;
11,821,254✔
1194
  c.modn = a.modn;
11,821,254✔
1195
        
1196
        if (a.is_zero() || b.is_zero()) { c[0]=1; return; }
11,821,254✔
1197
        if (a.is_one()) {
11,808,232✔
1198
                c.check_memory(b[0]);
5,933,466✔
1199
                c.termscopy(b.terms,0,b[0]);
5,933,466✔
1200
                // normalize if necessary
1201
                if (a.modp!=b.modp || a.modn!=b.modn) {
5,933,466✔
1202
                        c.modp=0;
534✔
1203
                        c.setmod(a.modp,a.modn);
534✔
1204
                }
1205
                return;
5,933,466✔
1206
        }
1207
        if (b.is_one()) {
5,874,766✔
1208
                c.check_memory(a[0]);
872,520✔
1209
                c.termscopy(a.terms,0,a[0]);                
872,520✔
1210
                return;
872,520✔
1211
        }
1212

1213
        int na=a.number_of_terms();
5,002,246✔
1214
        int nb=b.number_of_terms();
5,002,246✔
1215

1216
        if (na==1 || nb==1) {
5,002,246✔
1217
                mul_one_term(a,b,c);
1,321,155✔
1218
                return;
1,321,155✔
1219
        }
1220

1221
        int vara = a.is_dense_univariate();
3,681,091✔
1222
        int varb = b.is_dense_univariate();
3,681,091✔
1223

1224
        if (vara!=-2 && varb!=-2 && vara==varb) {
3,681,091✔
1225
                mul_univar(a,b,c,vara);
3,651,651✔
1226
                return;
3,651,651✔
1227
        }
1228

1229
        if (na < nb)
29,440✔
1230
                mul_heap(a,b,c);
12,587✔
1231
        else
1232
                mul_heap(b,a,c);
16,853✔
1233
}
1234

1235
/*
1236
          #] mul : 
1237
          #[ divmod_one_term : :
1238
*/
1239

1240
// divides a polynomial by a monomial
1241
void poly::divmod_one_term (const poly &a, const poly &b, poly &q, poly &r, bool only_divides) {
1,456,982✔
1242

1243
        POLY_GETIDENTITY(a);
1,456,982✔
1244

1245
        int qi=1, ri=1;
1,456,982✔
1246
        
1247
        WORD nmodq=0;
1,456,982✔
1248
        UWORD *modq=NULL;
1,456,982✔
1249
        
1250
        WORD nltbinv=0;
1,456,982✔
1251
        UWORD *ltbinv=NULL;
1,456,982✔
1252

1253
        bool both_mod_small=false;
1,456,982✔
1254
        
1255
        if (q.modp!=0) {
1,456,982✔
1256
                if (q.modn == 1) {
3,883✔
1257
                        modq = (UWORD *)&q.modp;
3,883✔
1258
                        nmodq = 1;
3,883✔
1259
                        if (a.modp>0 && b.modp>0 && a.modn==1 && b.modn==1)
3,883✔
1260
                                both_mod_small=true;
3,883✔
1261
                }
1262
                else {
1263
                        RaisPowCached(BHEAD q.modp,q.modn,&modq,&nmodq);
×
1264
                }
1265
                
1266
                ltbinv = NumberMalloc("poly::div_one_term");
3,883✔
1267

1268
                if (both_mod_small) {
3,883✔
1269
                        WORD ltb = b[b[1]]*b[2+AN.poly_num_vars];
3,883✔
1270
                        GetModInverses(ltb + (ltb<0?q.modp:0), q.modp, (WORD*)ltbinv, NULL);
6,372✔
1271
                        nltbinv = 1;
3,883✔
1272
                }
1273
                else
1274
                        GetLongModInverses(BHEAD (UWORD *)&b[2+AN.poly_num_vars], b[b[1]], modq, nmodq, ltbinv, &nltbinv, NULL, NULL);
×
1275
        }
1276
        
1277
        for (int ai=1; ai<a[0]; ai+=a[ai]) {
3,742,026✔
1278

1279
                q.check_memory(qi);
2,285,053✔
1280
                r.check_memory(ri);
2,285,053✔
1281
                
1282
                // check divisibility of powers
1283
                bool div=true;
1284
                for (int j=0; j<AN.poly_num_vars; j++) {
5,453,287✔
1285
                        q[qi+1+j] = a[ai+1+j]-b[2+j];
3,168,234✔
1286
                        r[ri+1+j] = a[ai+1+j];
3,168,234✔
1287
                        if (q[qi+1+j] < 0) div=false;
3,168,234✔
1288
                }
1289

1290
                WORD nq,nr;
2,285,053✔
1291
         
1292
                if (div) {
2,285,053✔
1293
                        // if variables are divisible, divide coefficient
1294
                        if (q.modp==0) {                                
2,283,941✔
1295
                                DivLong((UWORD *)&a[ai+1+AN.poly_num_vars], a[ai+a[ai]-1],
2,260,581✔
1296
                                                                (UWORD *)&b[2+AN.poly_num_vars], b[b[1]],
2,260,581✔
1297
                                                                (UWORD *)&q[qi+1+AN.poly_num_vars], &nq,
2,260,581✔
1298
                                                                (UWORD *)&r[ri+1+AN.poly_num_vars], &nr);
2,260,581✔
1299
                        }
1300
                        else {
1301
                                // if both polynomials are modulo p^1, use integer calculus
1302
                                if (both_mod_small) {
23,360✔
1303
                                        q[qi+1+AN.poly_num_vars] =
23,360✔
1304
                                                ((LONG)a[ai+1+AN.poly_num_vars] * a[ai+a[ai]-1] * ltbinv[0] * nltbinv) % q.modp;
23,360✔
1305
                                        nq = (q[qi+1+AN.poly_num_vars]==0 ? 0 : 1);
23,360✔
1306
                                }
1307
                                else {
1308
                                        // otherwise, use form long calculus
1309
                                        MulLong((UWORD *)&a[ai+1+AN.poly_num_vars], a[ai+a[ai]-1],
×
1310
                                                                        ltbinv, nltbinv,
1311
                                                                        (UWORD *)&q[qi+1+AN.poly_num_vars], &nq);
×
1312
                                        TakeNormalModulus((UWORD *)&q[qi+1+AN.poly_num_vars], &nq,
×
1313
                                                                                                                modq,nmodq, NOUNPACK);
1314
                                }
1315
                                
1316
                                nr=0;                                
23,360✔
1317
                        }
1318
                }
1319
                else {
1320
                        // if not, term becomes part of the remainder
1321
                        nq=0;
1,112✔
1322
                        nr=a[ai+a[ai]-1];
1,112✔
1323
                        r.termscopy(&a[ai+1+AN.poly_num_vars], ri+1+AN.poly_num_vars, ABS(nr));
1,112✔
1324
                }
1325

1326
                // add terms to quotient/remainder
1327
                if (nq!=0) {
2,285,053✔
1328
                        q[qi] = 2+AN.poly_num_vars+ABS(nq);
2,283,941✔
1329
                        qi += q[qi];
2,283,941✔
1330
                        
1331
                        // if necessary, adjust to range [-p/2,p/2]
1332
                        if (both_mod_small) {
2,283,941✔
1333
                                if (q[qi-2] > +q.modp/2) q[qi-2] -= q.modp;
23,360✔
1334
                                if (q[qi-2] < -q.modp/2) q[qi-2] += q.modp;
23,360✔
1335
                                q[qi-1] = SGN(q[qi-2]);
23,360✔
1336
                                q[qi-2] = ABS(q[qi-2]);
23,360✔
1337
                        }
1338
                        else {
1339
                                q[qi-1] = nq;
2,260,581✔
1340
                        }
1341
                }
1342
                
1343
                if (nr != 0) {
2,285,053✔
1344
                        if (only_divides) { r = poly(BHEAD 1); ri=r[0]; break; }
8,684✔
1345
                        r[ri] = 2+AN.poly_num_vars+ABS(nr);
8,675✔
1346
                        ri += r[ri];
8,675✔
1347
                        r[ri-1] = nr;
8,675✔
1348
                }                
1349
        }
1350

1351
        q[0]=qi;
1,456,982✔
1352
        r[0]=ri;
1,456,982✔
1353
        
1354
        if (q.modp!=0 || ltbinv != NULL) NumberFree(ltbinv,"poly::div_one_term");
1,456,982✔
1355
}        
1,456,982✔
1356

1357
/*
1358
          #] divmod_one_term : 
1359
          #[ divmod_univar : :
1360
*/
1361

1362
/**  Division of dense univariate polynomials.
1363
 *
1364
 *   Description
1365
 *   ===========
1366
 *   Divides two dense univariate polynomials. For each power, the
1367
 *   method collects all terms that result in that power.
1368
 *
1369
 *   Relevant formula [Q=A/B, P=SUM(p_i*x^i), n=deg(A), m=deg(B)]:
1370
 *   q_k = [ a_{m+k} - SUM(i=k+1...n-m, b_{m+k-i}*q_i) ] / b_m
1371
 */
1372
void poly::divmod_univar (const poly &a, const poly &b, poly &q, poly &r, int var, bool only_divides) {
2,531,924✔
1373

1374
        POLY_GETIDENTITY(a);
2,531,924✔
1375
        
1376
        WORD nmodq=0;
2,531,924✔
1377
        UWORD *modq=NULL;
2,531,924✔
1378
        
1379
        WORD nltbinv=0;
2,531,924✔
1380
        UWORD *ltbinv=NULL;
2,531,924✔
1381
        
1382
        bool both_mod_small=false;
2,531,924✔
1383
        
1384
        if (q.modp!=0) {
2,531,924✔
1385
                if (q.modn == 1) {
17,513✔
1386
                        modq = (UWORD *)&q.modp;
15,740✔
1387
                        nmodq = 1;
15,740✔
1388
                        if (a.modp>0 && b.modp>0 && a.modn==1 && b.modn==1)
15,740✔
1389
                                both_mod_small=true;
13,853✔
1390
                }
1391
                else {
1392
                        RaisPowCached(BHEAD q.modp,q.modn,&modq,&nmodq);
1,773✔
1393
                }
1394
                ltbinv = NumberMalloc("poly::div_univar");
17,513✔
1395

1396
                if (both_mod_small) {
17,513✔
1397
                        WORD ltb = b[b[1]]*b[2+AN.poly_num_vars];
13,853✔
1398
                        GetModInverses(ltb + (ltb<0?q.modp:0), q.modp, (WORD*)ltbinv, NULL);
14,210✔
1399
                        nltbinv = 1;
13,853✔
1400
                }
1401
                else
1402
                        GetLongModInverses(BHEAD (UWORD *)&b[2+AN.poly_num_vars], b[b[1]], modq, nmodq, ltbinv, &nltbinv, NULL, NULL);
3,660✔
1403
        }
1404

1405
        WORD ns=0;
2,531,924✔
1406
        WORD nt;
2,531,924✔
1407
        UWORD *s = NumberMalloc("poly::div_univar");
2,531,924✔
1408
        UWORD *t = NumberMalloc("poly::div_univar");
2,531,924✔
1409
        s[0]=0;
2,531,924✔
1410
        
1411
        int bpow = b[2+var];
2,531,924✔
1412
                
1413
        int ai=1, qi=1, ri=1;
2,531,924✔
1414

1415
        for (int pow=a[2+var]; pow>=0; pow--) {
10,673,830✔
1416

1417
                q.check_memory(qi);
8,141,936✔
1418
                r.check_memory(ri);
8,141,936✔
1419
                
1420
                // look for the correct power in a
1421
                while (ai<a[0] && a[ai+1+var] > pow)
13,647,248✔
1422
                        ai+=a[ai];
5,505,312✔
1423

1424
                // first term of the r.h.s. of the above equation
1425
                if (ai<a[0] && a[ai+1+var] == pow) {
8,141,936✔
1426
                        ns = a[ai+a[ai]-1];
8,029,109✔
1427
                        WCOPY(s, &a[ai+1+AN.poly_num_vars], ABS(ns));
19,787,875✔
1428
                }
1429
                else {
1430
                        ns = 0;
112,827✔
1431
                }
1432

1433
                int bi=1, qj=qi;
1434

1435
                // second term(s) of the r.h.s. of the above equation
1436
                while (qj>1 && bi<b[0]) {
27,480,818✔
1437
                        
1438
                        qj -= 2 + AN.poly_num_vars + ABS(q[qj-1]);
19,338,882✔
1439
                        
1440
                        while (bi<b[0] && b[bi+1+var]+q[qj+1+var] > pow)
46,809,249✔
1441
                                bi += b[bi];
27,470,367✔
1442
                        
1443
                        if (bi<b[0] && b[bi+1+var]+q[qj+1+var] == pow) {
19,338,882✔
1444
                                // if both polynomials are modulo p^1, use integer calculus
1445

1446
                                if (both_mod_small) {
14,204,396✔
1447
                                        s[0] = ((WORD)s[0]*ns - (LONG)b[bi+1+AN.poly_num_vars] * b[bi+b[bi]-1] *
8,884,668✔
1448
                                                                        q[qj+1+AN.poly_num_vars] * q[qj+q[qj]-1]) % q.modp;
8,884,668✔
1449
                                        ns = (s[0]==0 ? 0 : 1);
8,884,668✔
1450
                                }
1451
                                else {
1452
                                        // otherwise, use form long calculus
1453
                                        MulLong((UWORD *)&b[bi+1+AN.poly_num_vars], b[bi+b[bi]-1],
5,319,728✔
1454
                                                                        (UWORD *)&q[qj+1+AN.poly_num_vars], q[qj+q[qj]-1],
5,319,728✔
1455
                                                                        t, &nt);
1456
                                        nt *= -1;
5,319,728✔
1457
                                        AddLong(t,nt,s,ns,s,&ns);
5,319,728✔
1458
                                        if (q.modp!=0) TakeNormalModulus((UWORD *)s,&ns,modq, nmodq, NOUNPACK);
5,319,728✔
1459
                                }
1460
                        }
1461
                }
1462

1463
                if (ns != 0) {
8,141,936✔
1464
                        // if necessary, adjust to range [-p/2,p/2]
1465
                        if (both_mod_small) {
7,709,347✔
1466
                                s[0]*=ns;
432,852✔
1467
                                if ((WORD)s[0] > +q.modp/2) s[0] -= q.modp;
432,852✔
1468
                                if ((WORD)s[0] < -q.modp/2) s[0] += q.modp;
432,852✔
1469
                                ns = SGN((WORD)s[0]);
432,852✔
1470
                                s[0] = ABS((WORD)s[0]);
432,852✔
1471
                        }
1472

1473
                        if (pow >= bpow) {
7,709,347✔
1474
                                // large power, so divide by b
1475
                                if (q.modp == 0) {
5,027,269✔
1476
                                        DivLong(s, ns,
4,666,948✔
1477
                                                                        (UWORD *)&b[2+AN.poly_num_vars],  b[b[1]],
4,666,948✔
1478
                                                                        (UWORD *)&q[qi+1+AN.poly_num_vars], &ns, t, &nt);
4,666,948✔
1479
                                }
1480
                                else {
1481
                                        if (both_mod_small) {
360,321✔
1482
                                                q[qi+1+AN.poly_num_vars] = ((LONG)s[0]*ns*ltbinv[0]*nltbinv) % q.modp;
241,308✔
1483
                                                if ((WORD)q[qi+1+AN.poly_num_vars] > +q.modp/2) q[qi+1+AN.poly_num_vars] -= q.modp;
241,308✔
1484
                                                if ((WORD)q[qi+1+AN.poly_num_vars] < -q.modp/2) q[qi+1+AN.poly_num_vars] += q.modp;
241,308✔
1485
                                                ns = (q[qi+1+AN.poly_num_vars]==0 ? 0 : SGN((WORD)q[qi+1+AN.poly_num_vars]));
241,308✔
1486
                                                q[qi+1+AN.poly_num_vars] = ABS((WORD)q[qi+1+AN.poly_num_vars]);                                                                        
241,308✔
1487
                                        }
1488
                                        else {
1489
                                                MulLong(s, ns, ltbinv, nltbinv,        (UWORD *)&q[qi+1+AN.poly_num_vars], &ns);
119,013✔
1490
                                                TakeNormalModulus((UWORD *)&q[qi+1+AN.poly_num_vars], &ns,
119,013✔
1491
                                                                                                                        modq,nmodq, NOUNPACK);
1492
                                        }
1493
                                        nt=0;
360,321✔
1494
                                }                                        
1495
                        }
1496
                        else {
1497
                                // small power, so remainder
1498
                                WCOPY(t,s,ABS(ns));
12,644,630✔
1499
                                nt = ns;
2,682,078✔
1500
                                ns = 0;
2,682,078✔
1501
                        }
1502

1503
                        // add terms to quotient/remainder
1504
                        if (ns!=0) {
7,709,347✔
1505
                                for (int i=0; i<AN.poly_num_vars; i++)
10,505,698✔
1506
                                        q[qi+1+i] = 0;
5,478,431✔
1507
                                q[qi+1+var] = pow-bpow;
5,027,267✔
1508
                                
1509
                                q[qi] = 2+AN.poly_num_vars+ABS(ns);
5,027,267✔
1510
                                qi += q[qi];
5,027,267✔
1511
                                q[qi-1] = ns;
5,027,267✔
1512
                        }
1513
                        
1514
                        if (nt != 0) {
7,709,347✔
1515
                                if (only_divides) { r=poly(BHEAD 1); ri=r[0]; break; }
2,682,089✔
1516
                                for (int i=0; i<AN.poly_num_vars; i++)
5,664,664✔
1517
                                        r[ri+1+i] = 0;
2,982,605✔
1518
                                r[ri+1+var] = pow;
2,682,059✔
1519

1520
                                for (int i=0; i<ABS(nt); i++)
12,643,960✔
1521
                                        r[ri+1+AN.poly_num_vars+i] = t[i];
9,961,901✔
1522
                                
1523
                                r[ri] = 2+AN.poly_num_vars+ABS(nt);
2,682,059✔
1524
                                ri += r[ri];
2,682,059✔
1525
                                r[ri-1] = nt;
2,682,059✔
1526
                        }
1527
                }
1528
        }
1529

1530
        q[0] = qi;
2,531,924✔
1531
        r[0] = ri;
2,531,924✔
1532

1533
        NumberFree(s,"poly::div_univar");
2,531,924✔
1534
        NumberFree(t,"poly::div_univar");
2,531,924✔
1535

1536
        if (q.modp!=0 || ltbinv!=NULL) NumberFree(ltbinv,"poly::div_univar");
2,531,924✔
1537
}
2,531,924✔
1538

1539
/*
1540
          #] divmod_univar : 
1541
          #[ divmod_heap :
1542
*/
1543

1544
/**  Division of polynomials with a heap
1545
 *
1546
 *   Description
1547
 *   ===========
1548
 *   Divides two multivariate polynomials. The next element of the
1549
 *   quotient/remainder is efficiently determined by using a heap. If
1550
 *   the product of the maximum power in all variables is small, a
1551
 *   hash table is used to add equal terms for extra speed.
1552
 *
1553
 *   If the input flag check_div is set then if the result of any
1554
 *   coefficient division results in a non-zero remainder (indicating
1555
 *   that division has failed over the integers) the output flag div_fail
1556
 *   will be set and the division will be terminated early (q, r
1557
 *   will be incorrect). If check_div is not set then non-zero remainders
1558
 *   from coefficient division will be written into r.
1559
 *
1560
 *   A heap element h is formatted as follows:
1561
 *   - h[0] = index in a
1562
 *   - h[1] = index in b
1563
 *   - h[2] = -1 (no hash is used)
1564
 *   - h[3] = length of coefficient with sign
1565
 *   - h[4...4+AN.poly_num_vars-1] = powers 
1566
 *   - h[4+AN.poly_num_vars...4+h[3]-1] = coefficient
1567
 *
1568
 *   Note: the hashing trick as in multiplication cannot be used
1569
 *   easily, since there is no tight upperbound on the exponents in
1570
 *   the answer.
1571

1572
 *   For details, see M. Monagan, "Polynomial Division using Dynamic
1573
 *   Array, Heaps, and Packed Exponent Vectors"
1574
 */
1575
void poly::divmod_heap (const poly &a, const poly &b, poly &q, poly &r, bool only_divides, bool check_div, bool &div_fail) {
107,818✔
1576

1577
        POLY_GETIDENTITY(a);
107,818✔
1578

1579
        div_fail = false;
107,818✔
1580
        q[0] = r[0] = 1;
107,818✔
1581
        
1582
        WORD nmodq=0;
107,818✔
1583
        UWORD *modq=NULL;
107,818✔
1584
        
1585
        WORD nltbinv=0;
107,818✔
1586
        UWORD *ltbinv=NULL;
107,818✔
1587
        LONG oldpWorkPointer = AT.pWorkPointer;
107,818✔
1588
        
1589
        bool both_mod_small=false;
107,818✔
1590
        
1591
        if (q.modp!=0) {
107,818✔
1592
                if (q.modn == 1) {
59,601✔
1593
                        modq = (UWORD *)&q.modp;
21,633✔
1594
                        nmodq = 1;
21,633✔
1595
                        if (a.modp>0 && b.modp>0 && a.modn==1 && b.modn==1)
21,633✔
1596
                                both_mod_small=true;
21,276✔
1597
                }
1598
                else {
1599
                        RaisPowCached(BHEAD q.modp,q.modn,&modq,&nmodq);
37,968✔
1600
                }
1601
                ltbinv = NumberMalloc("poly::div_heap-a");
59,601✔
1602

1603
                if (both_mod_small) {
59,601✔
1604
                        WORD ltb = b[b[1]]*b[2+AN.poly_num_vars];
21,276✔
1605
                        GetModInverses(ltb + (ltb<0?q.modp:0), q.modp, (WORD*)ltbinv, NULL);
21,324✔
1606
                        nltbinv = 1;
21,276✔
1607
                }
1608
                else
1609
                        GetLongModInverses(BHEAD (UWORD *)&b[2+AN.poly_num_vars], b[b[1]], modq, nmodq, ltbinv, &nltbinv, NULL, NULL);
38,325✔
1610
        }
1611
        
1612
        // allocate heap
1613
        int nb=b.number_of_terms();
107,818✔
1614
        WantAddPointers(nb);
107,818✔
1615
        WORD **heap = AT.pWorkSpace + AT.pWorkPointer;
107,818✔
1616
        AT.pWorkPointer += nb;
107,818✔
1617
        
1618
        for (int i=0; i<nb; i++) 
625,299✔
1619
                heap[i] = (WORD *) NumberMalloc("poly::div_heap-b");
517,481✔
1620
        int nheap = 1;
107,818✔
1621
        heap[0][0] = 1;
107,818✔
1622
        heap[0][1] = 0;
107,818✔
1623
        heap[0][2] = -1;
107,818✔
1624
        WCOPY(&heap[0][3], &a[1], a[1]);
3,539,150✔
1625
        heap[0][3] = a[a[1]];
107,818✔
1626
        
1627
        int qi=1, ri=1;
107,818✔
1628

1629
        int s = nb;
107,818✔
1630
        WORD *t = (WORD *) NumberMalloc("poly::div_heap-c");
107,818✔
1631

1632
        // insert contains element that still have to be inserted to the heap
1633
        // (exists to avoid code duplication).
1634
        vector<pair<int,int> > insert;
107,818✔
1635
        
1636
        while (insert.size()>0 || nheap>0) {
3,771,293✔
1637

1638
                q.check_memory(qi);
3,663,503✔
1639
                r.check_memory(ri);
3,663,503✔
1640
                
1641
                // collect a term t for the quotient/remainder
1642
                t[0] = -1;
3,663,503✔
1643
                
1644
                do {
10,475,856✔
1645

1646
                        WORD *p = heap[nheap];
10,475,856✔
1647
                        bool this_insert;
10,475,856✔
1648
                 
1649
                        if (insert.empty()) {
10,475,856✔
1650
                                // extract element from the heap and prepare adding new ones
1651
                                this_insert = false;
9,800,904✔
1652

1653
                                pop_heap(BHEAD heap, nheap--);
9,800,904✔
1654
                                p = heap[nheap];
9,800,904✔
1655
                                
1656
                                if (t[0] == -1) {
9,800,904✔
1657
                                        WCOPY(t, p, (5+ABS(p[3])+AN.poly_num_vars));
114,222,275✔
1658
                                }                                
1659
                                else {
1660
                                        // if both polynomials are modulo p^1, use integer calculus
1661
                                        if (both_mod_small) {
6,137,401✔
1662
                                                t[4+AN.poly_num_vars] = ((LONG)t[4+AN.poly_num_vars]*t[3] + p[4+AN.poly_num_vars]*p[3]) % q.modp;
5,632,659✔
1663
                                                if (t[4+AN.poly_num_vars]==0)
5,632,659✔
1664
                                                        t[3]=0;
568,236✔
1665
                                                else {
1666
                                                        if (t[4+AN.poly_num_vars] > +q.modp/2) t[4+AN.poly_num_vars] -= q.modp;
5,064,423✔
1667
                                                        if (t[4+AN.poly_num_vars] < -q.modp/2) t[4+AN.poly_num_vars] += q.modp;
5,064,423✔
1668
                                                        t[3] = SGN(t[4+AN.poly_num_vars]);
5,064,423✔
1669
                                                        t[4+AN.poly_num_vars] = ABS(t[4+AN.poly_num_vars]);
5,064,423✔
1670
                                                }
1671
                                        }
1672
                                        else {
1673
                                                // otherwise, use form long calculus
1674
                                                AddLong ((UWORD *)&p[4+AN.poly_num_vars],  p[3],
504,742✔
1675
                                                                                 (UWORD *)&t[4+AN.poly_num_vars],  t[3],
1676
                                                                                 (UWORD *)&t[4+AN.poly_num_vars], &t[3]);
504,742✔
1677
                                                if (q.modp!=0) TakeNormalModulus((UWORD *)&t[4+AN.poly_num_vars], &t[3],
504,742✔
1678
                                                                                                                                                                                 modq, nmodq, NOUNPACK);
1679
                                        }
1680
                                }
1681
                        }
1682
                        else {
1683
                                // prepare adding an element of insert to the heap
1684
                                this_insert = true;
674,952✔
1685

1686
                                p[0] = insert.back().first;
674,952✔
1687
                                p[1] = insert.back().second;
674,952✔
1688
                                insert.pop_back();
674,952✔
1689
                        }
1690

1691
                        // add elements to the heap
1692
                        while (true) {
10,475,856✔
1693
                                // prepare the element
1694
                                if (p[1]==0) {
10,475,856✔
1695
                                        p[0] += a[p[0]];
2,316,864✔
1696
                                        if (p[0]==a[0]) break;
2,316,864✔
1697
                                        WCOPY(&p[3], &a[p[0]], a[p[0]]);
74,753,964✔
1698
                                        p[3] = p[2+p[3]];
2,209,074✔
1699
                                }                        
1700
                                else {
1701
                                        if (!this_insert)
8,158,992✔
1702
                                                p[1] += q[p[1]];
7,484,040✔
1703
                                        this_insert = false;
8,158,992✔
1704
                                        
1705
                                        if (p[1]==qi) {        s++; break; }
8,158,992✔
1706

1707
                                        for (int i=0; i<AN.poly_num_vars; i++)
27,176,063✔
1708
                                                p[4+i] = b[p[0]+1+i] + q[p[1]+1+i];
19,692,005✔
1709
                                        
1710
                                        // if both polynomials are modulo p^1, use integer calculus
1711
                                        if (both_mod_small) {
7,484,058✔
1712
                                                p[4+AN.poly_num_vars] = ((LONG)b[p[0]+1+AN.poly_num_vars]*b[p[0]+b[p[0]]-1]*
5,754,240✔
1713
                                                                                                                                                 q[p[1]+1+AN.poly_num_vars]*q[p[1]+q[p[1]]-1]) % q.modp;
5,754,240✔
1714
                                                if (p[4+AN.poly_num_vars]==0)
5,754,240✔
1715
                                                        p[3]=0;
×
1716
                                                else {
1717
                                                        if (p[4+AN.poly_num_vars] > +q.modp/2) p[4+AN.poly_num_vars] -= q.modp;
5,754,240✔
1718
                                                        if (p[4+AN.poly_num_vars] < -q.modp/2) p[4+AN.poly_num_vars] += q.modp;
5,754,240✔
1719
                                                        p[3] = SGN(p[4+AN.poly_num_vars]);
5,754,240✔
1720
                                                        p[4+AN.poly_num_vars] = ABS(p[4+AN.poly_num_vars]);
5,754,240✔
1721
                                                }
1722
                                        }
1723
                                        else {
1724
                                                // otherwise, use form long calculus
1725
                                                MulLong((UWORD *)&b[p[0]+1+AN.poly_num_vars], b[p[0]+b[p[0]]-1],
1,729,818✔
1726
                                                                                (UWORD *)&q[p[1]+1+AN.poly_num_vars], q[p[1]+q[p[1]]-1],
1,729,818✔
1727
                                                                                (UWORD *)&p[4+AN.poly_num_vars], &p[3]);
1,729,818✔
1728
                                                if (q.modp!=0) TakeNormalModulus((UWORD *)&p[4+AN.poly_num_vars], &p[3],
1,729,818✔
1729
                                                                                                                                                                                 modq, nmodq, NOUNPACK);
1730
                                        }
1731
                                        
1732
                                        p[3] *= -1;
7,484,058✔
1733
                                }
1734

1735
                                // no hashing
1736
                                p[2] = -1;
9,693,132✔
1737

1738
                                // add it to a heap element
1739
                                swap (heap[nheap],p);
9,693,132✔
1740
                                push_heap(BHEAD heap, ++nheap);
9,693,132✔
1741
                                break;
9,693,132✔
1742
                        }
1743
                }
1744
                while (t[0]==-1 || (nheap>0 && monomial_compare(BHEAD heap[0]+3, t+3)==0));
16,613,257✔
1745

1746
                if (t[3] == 0) continue;
3,663,503✔
1747
                
1748
                // check divisibility 
1749
                bool div = true;
1750
                for (int i=0; i<AN.poly_num_vars; i++)
75,803,242✔
1751
                        if (t[4+i] < b[2+i]) div=false;
72,585,813✔
1752
                
1753
                if (!div) {
3,217,429✔
1754
                        // not divisible, so append it to the remainder
1755
                        if (only_divides) { r=poly(BHEAD 1); ri=r[0]; break; }
1,487,795✔
1756
                        t[4 + AN.poly_num_vars + ABS(t[3])] = t[3];
1,487,791✔
1757
                        t[3] = 2 + AN.poly_num_vars + ABS(t[3]);
1,487,791✔
1758
                        r.termscopy(&t[3], ri, t[3]);
1,487,791✔
1759
                        ri += t[3];
1,487,791✔
1760
                }
1761
                else {
1762
                        // divisible, so divide coefficient as well
1763
                        WORD nq, nr;
1,729,634✔
1764
        
1765
                        if (q.modp==0) {
1,729,634✔
1766
                                DivLong((UWORD *)&t[4+AN.poly_num_vars], t[3],
1,288,355✔
1767
                                                                (UWORD *)&b[2+AN.poly_num_vars], b[b[1]],
1,288,355✔
1768
                                                                (UWORD *)&q[qi+1+AN.poly_num_vars], &nq,
1,288,355✔
1769
                                                                (UWORD *)&r[ri+1+AN.poly_num_vars], &nr);
1,288,355✔
1770
                                if(check_div && nr != 0)
1,288,355✔
1771
                                {
1772
                                        // non-zero remainder from coefficient division => result not expressible in integers
1773
                                        div_fail = true;
24✔
1774
                                        break;
24✔
1775
                                }
1776
                        }
1777
                        else {
1778
                                // if both polynomials are modulo p^1, use integer calculus
1779
                                if (both_mod_small) {
441,279✔
1780
                                        q[qi+1+AN.poly_num_vars] = ((LONG)t[4+AN.poly_num_vars]*t[3]*ltbinv[0]*nltbinv) % q.modp;
361,998✔
1781
                                        if (q[qi+1+AN.poly_num_vars]==0)
361,998✔
1782
                                                nq=0;
×
1783
                                        else {
1784
                                                if (q[qi+1+AN.poly_num_vars] > +q.modp/2) q[qi+1+AN.poly_num_vars] -= q.modp;
361,998✔
1785
                                                if (q[qi+1+AN.poly_num_vars] < -q.modp/2) q[qi+1+AN.poly_num_vars] += q.modp;
361,998✔
1786
                                                nq = SGN(q[qi+1+AN.poly_num_vars]);
361,998✔
1787
                                                q[qi+1+AN.poly_num_vars] = ABS(q[qi+1+AN.poly_num_vars]);
361,998✔
1788
                                        }
1789
                                }
1790
                                else {
1791
                                        // otherwise, use form long calculus
1792
                                        MulLong((UWORD *)&t[4+AN.poly_num_vars], t[3], ltbinv, nltbinv,        (UWORD *)&q[qi+1+AN.poly_num_vars], &nq);
79,281✔
1793
                                        TakeNormalModulus((UWORD *)&q[qi+1+AN.poly_num_vars], &nq, modq, nmodq, NOUNPACK);
79,281✔
1794
                                }
1795
                                
1796
                                nr=0;
441,279✔
1797
                        }
1798

1799
                        // add terms to quotient and remainder
1800
                        if (nq != 0) {
1,729,610✔
1801
                                int bi = 1;
1802
                                for (int j=1; j<s; j++) {
2,403,627✔
1803
                                        bi += b[bi];
674,952✔
1804
                                        insert.push_back(make_pair(bi,qi));
674,952✔
1805
                                }
1806
                                s=1;
1,728,675✔
1807
                                
1808
                                q[qi] = 2+AN.poly_num_vars+ABS(nq);
1,728,675✔
1809
                                for (int i=0; i<AN.poly_num_vars; i++)
9,854,409✔
1810
                                        q[qi+1+i] = t[4+i] - b[2+i];
8,125,734✔
1811
                                qi += q[qi];
1,728,675✔
1812
                                q[qi-1] = nq;
1,728,675✔
1813
                        }
1814

1815
                        if (nr != 0) {
1,729,610✔
1816
                                r[ri] = 2+AN.poly_num_vars+ABS(nr);
1,799✔
1817
                                for (int i=0; i<AN.poly_num_vars; i++)
8,339✔
1818
                                        r[ri+1+i] = t[4+i];
6,540✔
1819
                                ri += r[ri];
1,799✔
1820
                                r[ri-1] = nr;
1,799✔
1821
                        }
1822
                }
1823
        }
1824

1825
        q[0] = qi;
107,818✔
1826
        r[0] = ri;
107,818✔
1827

1828
        for (int i=0; i<nb; i++)
625,299✔
1829
                NumberFree(heap[i],"poly::div_heap-b");
517,481✔
1830

1831
        NumberFree(t,"poly::div_heap-c");
107,818✔
1832

1833
        if (q.modp!=0||ltbinv!=NULL) NumberFree(ltbinv,"poly::div_heap-a");
107,818✔
1834
        AT.pWorkPointer = oldpWorkPointer;
107,818✔
1835
}
107,818✔
1836

1837
/*
1838
          #] divmod_heap : 
1839
          #[ divmod :
1840
*/
1841

1842
/**  Polynomial division
1843
 *
1844
 *   Description
1845
 *   ===========
1846
 *   This routine determines which division routine to use for
1847
 *   dividing two polynomials. The logic is as follows:
1848
 *   - If b consists of only one term, call divmod_one_term;
1849
 *   - Otherwise, if both are univariate and dense, call divmod_univar;
1850
 *   - Otherwise, call divmod_heap.
1851
 */
1852
void poly::divmod (const poly &a, const poly &b, poly &q, poly &r, bool only_divides) {
13,947,609✔
1853

1854
        q.modp = r.modp = a.modp;
13,947,609✔
1855
        q.modn = r.modn = a.modn;
13,947,609✔
1856
        
1857
        if (a.is_zero()) {
13,947,609✔
1858
                q[0]=1;
1,255,451✔
1859
                r[0]=1;
1,255,451✔
1860
                return;
1,255,451✔
1861
        }
1862
        if (b.is_zero()) {
12,692,158✔
1863
                MLOCK(ErrorMessageLock);
×
1864
                MesPrint ((char*)"ERROR: division by zero polynomial");
×
1865
                MUNLOCK(ErrorMessageLock);
×
1866
                Terminate(1);
×
1867
        }
1868
        if (b.is_one()) {
12,692,158✔
1869
                q.check_memory(a[0]);
8,595,470✔
1870
                q.termscopy(a.terms,0,a[0]);
8,595,470✔
1871
                r[0]=1;
8,595,470✔
1872
                return;
8,595,470✔
1873
        }
1874
        
1875
        if (b.is_monomial()) {
4,096,688✔
1876
                divmod_one_term(a,b,q,r,only_divides);
1,456,982✔
1877
                return;
1,456,982✔
1878
        }
1879

1880
        int vara = a.is_dense_univariate();
2,639,706✔
1881
        int varb = b.is_dense_univariate();
2,639,706✔
1882

1883
        if (vara!=-2 && varb!=-2 && (vara==-1 || varb==-1 || vara==varb)) {
2,639,706✔
1884
                divmod_univar(a,b,q,r,MaX(vara,varb),only_divides);
5,063,848✔
1885
        }
1886
        else {
1887
                bool div_fail;
107,782✔
1888
                divmod_heap(a,b,q,r,only_divides,false,div_fail);
107,782✔
1889
        }
1890
}
1891

1892
/*
1893
          #] divmod : 
1894
          #[ divides :
1895
*/
1896

1897
// returns whether a exactly divides b 
1898
bool poly::divides (const poly &a, const poly &b) {
20,127✔
1899
        POLY_GETIDENTITY(a);
20,127✔
1900
        poly q(BHEAD 0), r(BHEAD 0);
20,127✔
1901
        divmod(b,a,q,r,true);
20,127✔
1902
        return r.is_zero();
20,127✔
1903
}
20,127✔
1904

1905
/*
1906
          #] divides : 
1907
          #[ div :
1908
*/
1909

1910
// the quotient of two polynomials
1911
void poly::div (const poly &a, const poly &b, poly &c) {
8,847,926✔
1912
        POLY_GETIDENTITY(a);
8,847,926✔
1913
        poly d(BHEAD 0);
8,847,926✔
1914
        divmod(a,b,c,d,false);
8,847,926✔
1915
}
8,847,926✔
1916

1917
/*
1918
          #] div : 
1919
          #[ mod :
1920
*/
1921

1922
// the remainder of division of two polynomials
1923
void poly::mod (const poly &a, const poly &b, poly &c) {
5,079,556✔
1924
        POLY_GETIDENTITY(a);
5,079,556✔
1925
        poly d(BHEAD 0);
5,079,556✔
1926
        divmod(a,b,d,c,false);
5,079,556✔
1927
}
5,079,556✔
1928

1929
/*
1930
          #] mod : 
1931
          #[ copy operator :
1932
*/
1933

1934
// copy operator
1935
poly & poly::operator= (const poly &a) {
43,731,633✔
1936

1937
        if (&a != this) {
43,731,633✔
1938
                modp = a.modp;
43,731,633✔
1939
                modn = a.modn;
43,731,633✔
1940
                check_memory(a[0]);
43,731,633✔
1941
                termscopy(a.terms,0,a[0]);
43,731,633✔
1942
        }
1943

1944
        return *this;
43,731,633✔
1945
}
1946

1947
/*
1948
          #] copy operator : 
1949
          #[ operator overloads :
1950
*/
1951

1952
// binary operators for polynomial arithmetic
1953
const poly poly::operator+ (const poly &a) const { POLY_GETIDENTITY(a); poly b(BHEAD 0); add(*this,a,b); return b; }
1,678,703✔
1954
const poly poly::operator- (const poly &a) const { POLY_GETIDENTITY(a); poly b(BHEAD 0); sub(*this,a,b); return b; }
1,335,437✔
1955
const poly poly::operator* (const poly &a) const { POLY_GETIDENTITY(a); poly b(BHEAD 0); mul(*this,a,b); return b; }
11,821,254✔
1956
const poly poly::operator/ (const poly &a) const { POLY_GETIDENTITY(a); poly b(BHEAD 0); div(*this,a,b); return b; }
8,847,926✔
1957
const poly poly::operator% (const poly &a) const { POLY_GETIDENTITY(a); poly b(BHEAD 0); mod(*this,a,b); return b; }
5,079,556✔
1958

1959
// assignment operators for polynomial arithmetic
1960
poly& poly::operator+= (const poly &a) { return *this = *this + a; }
37,867✔
1961
poly& poly::operator-= (const poly &a) { return *this = *this - a; }
39,626✔
1962
poly& poly::operator*= (const poly &a) { return *this = *this * a; }
7,206,080✔
1963
poly& poly::operator/= (const poly &a) { return *this = *this / a; }
2,858,911✔
1964
poly& poly::operator%= (const poly &a) { return *this = *this % a; }
40,416✔
1965

1966
// comparison operators
1967
bool poly::operator== (const poly &a) const {
4,135,907✔
1968
        for (int i=0; i<terms[0]; i++)
22,680,306✔
1969
                if (terms[i] != a[i]) return 0;
22,645,152✔
1970
        return 1;
1971
}
1972

1973
bool poly::operator!= (const poly &a) const {        return !(*this == a); }
369,389✔
1974

1975
/*
1976
          #] operator overloads : 
1977
          #[ num_terms :
1978
*/
1979

1980
int poly::number_of_terms () const {
11,627,873✔
1981

1982
        int res=0;
11,627,873✔
1983
        for (int i=1; i<terms[0]; i+=terms[i])
47,002,449✔
1984
                res++;
35,374,576✔
1985
        return res;        
11,627,873✔
1986
}
1987

1988
/*
1989
          #] num_terms : 
1990
          #[ first_variable :
1991
*/
1992

1993
// returns the lexicographically first variable of a polynomial
1994
int poly::first_variable () const {
10,983✔
1995
        
1996
        POLY_GETIDENTITY(*this);
10,983✔
1997
        
1998
        int var = AN.poly_num_vars;
10,983✔
1999
        for (int j=0; j<var; j++)
11,043✔
2000
                if (terms[2+j]>0) return j;
11,043✔
2001
        return var;
2002
}
2003

2004
/*
2005
          #] first_variable : 
2006
          #[ all_variables :
2007
*/
2008

2009
// returns a list of all variables of a polynomial
2010
const vector<int> poly::all_variables () const {
2,521,417✔
2011

2012
        POLY_GETIDENTITY(*this);
2,521,417✔
2013
        
2014
        vector<bool> used(AN.poly_num_vars, false);
2,521,417✔
2015
        
2016
        for (int i=1; i<terms[0]; i+=terms[i])
10,755,109✔
2017
                for (int j=0; j<AN.poly_num_vars; j++)
17,697,881✔
2018
                        if (terms[i+1+j]>0) used[j] = true;
9,464,189✔
2019

2020
        vector<int> vars;
2,521,417✔
2021
        for (int i=0; i<AN.poly_num_vars; i++)
5,150,874✔
2022
                if (used[i]) vars.push_back(i);
2,629,457✔
2023
        
2024
        return vars;
2,521,417✔
2025
}
2,521,417✔
2026

2027
/*
2028
          #] all_variables : 
2029
          #[ sign :
2030
*/
2031

2032
// returns the sign of the leading coefficient
2033
int poly::sign () const {
19,524,464✔
2034
        if (terms[0]==1) return 0;
19,524,464✔
2035
        return terms[terms[1]] > 0 ? 1 : -1;
19,524,464✔
2036
}
2037

2038
/*
2039
          #] sign : 
2040
          #[ degree :
2041
*/
2042

2043
// returns the degree of x of a polynomial (deg=-1 iff a=0)
2044
int poly::degree (int x) const {
2,510,180✔
2045
        int deg = -1;
2,510,180✔
2046
        for (int i=1; i<terms[0]; i+=terms[i])
12,612,296✔
2047
                deg = MaX(deg, terms[i+1+x]);
12,659,320✔
2048
        return deg;
2,510,180✔
2049
}
2050

2051
/*
2052
          #] degree : 
2053
          #[ total_degree :
2054
*/
2055

2056
// returns the total degree of a polynomial (deg=-1 iff a=0)
2057
int poly::total_degree () const {
×
2058

2059
        POLY_GETIDENTITY(*this);
×
2060
        
2061
        int tot_deg = -1;
×
2062
        for (int i=1; i<terms[0]; i+=terms[i]) {
×
2063
                int deg=0;
2064
                for (int j=0; j<AN.poly_num_vars; j++)
×
2065
                        deg += terms[i+1+j];
×
2066
                tot_deg = MaX(deg, tot_deg);
×
2067
        }
2068
        return tot_deg;
×
2069
}
2070

2071
/*
2072
          #] total_degree : 
2073
          #[ integer_lcoeff :
2074
*/
2075

2076
// returns the integer coefficient of the leading monomial
2077
const poly poly::integer_lcoeff () const {
22,030✔
2078

2079
        POLY_GETIDENTITY(*this);
22,030✔
2080
        
2081
        poly res(BHEAD 0);
22,030✔
2082
        res.modp = modp;
22,030✔
2083
        res.modn = modn;
22,030✔
2084

2085
        res.termscopy(&terms[1],1,terms[1]);
22,030✔
2086
        res[0] = res[1] + 1; // length
22,030✔
2087
        for (int i=0; i<AN.poly_num_vars; i++)
77,655✔
2088
                res[2+i] = 0; // powers
55,625✔
2089
        
2090
        return res;
22,030✔
2091
}
2092

2093
/*
2094
          #] integer_lcoeff : 
2095
          #[ coefficient :
2096
*/
2097

2098
// returns the polynomial coefficient of x^n
2099
const poly poly::coefficient (int x, int n) const {
1,174✔
2100

2101
        POLY_GETIDENTITY(*this);
1,174✔
2102
        
2103
        poly res(BHEAD 0);
1,174✔
2104
        res.modp = modp;
1,174✔
2105
        res.modn = modn;
1,174✔
2106
        res[0] = 1;
1,174✔
2107
        
2108
        for (int i=1; i<terms[0]; i+=terms[i]) 
13,890✔
2109
                if (terms[i+1+x] == n) {
12,716✔
2110
                        res.check_memory(res[0]+terms[i]);                
1,237✔
2111
                        res.termscopy(&terms[i], res[0], terms[i]);
1,237✔
2112
                        res[res[0]+1+x] -= n;  // power of x
1,237✔
2113
                        res[0] += res[res[0]]; // length
1,237✔
2114
                }
2115

2116
        return res;
1,174✔
2117
}
×
2118

2119
/*
2120
          #] coefficient : 
2121
          #[ lcoeff_multivar :
2122
*/
2123

2124
// returns the leading coefficient with the polynomial viewed as a
2125
// polynomial in x, so that the result is a polynomial in the
2126
// remaining variables
2127
const poly poly::lcoeff_univar (int x) const {
1,111✔
2128
        return coefficient(x, degree(x));
1,111✔
2129
}
2130

2131
// returns the leading coefficient with the polynomial viewed as a
2132
// polynomial with coefficients in ZZ[x], so that the result
2133
// polynomial is in ZZ[x] too
2134
const poly poly::lcoeff_multivar (int x) const {
96✔
2135

2136
        POLY_GETIDENTITY(*this);
96✔
2137

2138
        poly res(BHEAD 0,modp,modn);
96✔
2139

2140
        for (int i=1; i<terms[0]; i+=terms[i]) {
192✔
2141
                bool same_powers = true;
569✔
2142
                for (int j=0; j<AN.poly_num_vars; j++)
569✔
2143
                        if (j!=x && terms[i+1+j]!=terms[2+j]) {
473✔
2144
                                same_powers = false;
2145
                                break;
2146
                        }
2147
                if (!same_powers) break;
173✔
2148
                
2149
                res.check_memory(res[0]+terms[i]);
96✔
2150
                res.termscopy(&terms[i],res[0],terms[i]);
96✔
2151
                for (int k=0; k<AN.poly_num_vars; k++)
492✔
2152
                        if (k!=x) res[res[0]+1+k]=0;
396✔
2153
                
2154
                res[0] += terms[i];
96✔
2155
        }
2156
        
2157
        return res;        
96✔
2158
}
×
2159

2160
/*
2161
          #] lcoeff_multivar : 
2162
          #[ derivative :
2163
*/
2164

2165
// returns the derivative with respect to x
2166
const poly poly::derivative (int x) const {
595✔
2167

2168
        POLY_GETIDENTITY(*this);
595✔
2169
        
2170
        poly b(BHEAD 0);
595✔
2171
        int bi=1;
595✔
2172

2173
        for (int i=1; i<terms[0]; i+=terms[i]) {
4,862✔
2174
                
2175
                int power = terms[i+1+x];
4,267✔
2176

2177
                if (power > 0) {
4,267✔
2178
                        b.check_memory(bi);
2,504✔
2179
                        b.termscopy(&terms[i], bi, terms[i]);
2,504✔
2180
                        b[bi+1+x]--;
2,504✔
2181
                        
2182
                        WORD nb = b[bi+b[bi]-1];
2,504✔
2183
                        Product((UWORD *)&b[bi+1+AN.poly_num_vars], &nb, power);
2,504✔
2184

2185
                        b[bi] = 2 + AN.poly_num_vars + ABS(nb);
2,504✔
2186
                        b[bi+b[bi]-1] = nb;
2,504✔
2187
                        
2188
                        bi += b[bi];
2,504✔
2189
                }
2190
        }
2191

2192
        b[0] = bi;
595✔
2193
        b.setmod(modp, modn);
595✔
2194
        return b;        
595✔
2195
}
×
2196

2197
/*
2198
          #] derivative : 
2199
          #[ is_zero :
2200
*/
2201

2202
// returns whether the polynomial is zero
2203
bool poly::is_zero () const {
75,462,731✔
2204
        return terms[0] == 1;
75,462,731✔
2205
}
2206

2207
/*
2208
          #] is_zero : 
2209
          #[ is_one :
2210
*/
2211

2212
// returns whether the polynomial is one
2213
bool poly::is_one () const {
32,860,570✔
2214
        
2215
        POLY_GETIDENTITY(*this);
32,860,570✔
2216
        
2217
        if (terms[0] != 4+AN.poly_num_vars) return false;
32,860,570✔
2218
        if (terms[1] != 3+AN.poly_num_vars) return false;
21,759,690✔
2219
        for (int i=0; i<AN.poly_num_vars; i++)
46,027,497✔
2220
                if (terms[2+i] != 0) return false;
24,299,730✔
2221
        if (terms[2+AN.poly_num_vars]!=1) return false;
21,727,767✔
2222
        if (terms[3+AN.poly_num_vars]!=1) return false;
17,885,314✔
2223
        
2224
        return true;        
2225
}
2226

2227
/*
2228
          #] is_one : 
2229
          #[ is_integer :
2230
*/
2231

2232
// returns whether the polynomial is an integer
2233
bool poly::is_integer () const {
8,357,649✔
2234

2235
        POLY_GETIDENTITY(*this);
8,357,649✔
2236

2237
        if (terms[0] == 1) return true;
8,357,649✔
2238
        if (terms[0] != terms[1]+1)        return false;
8,357,649✔
2239
        
2240
        for (int j=0; j<AN.poly_num_vars; j++)
5,217,859✔
2241
                if (terms[2+j] != 0)
2,722,050✔
2242
                        return false;
2243

2244
        return true;
2245
}
2246

2247
/*
2248
          #] is_integer : 
2249
          #[ is_monomial :
2250
*/
2251

2252
// returns whether the polynomial consist of one term
2253
bool poly::is_monomial () const {
6,598,125✔
2254
        return terms[0]>1 && terms[0]==terms[1]+1;
6,598,125✔
2255
}
2256

2257
/*
2258
          #] is_monomial : 
2259
          #[ is_dense_univariate :
2260
*/
2261

2262
/**  Dense univariate detection
2263
 *
2264
 *   Description
2265
 *   ===========
2266
 *   This method returns whether the polynomial is dense and
2267
 *   univariate. The possible return values are:
2268
 *
2269
 *   -2 is not dense univariate
2270
 *   -1 is no variables
2271
 *   n>=0 is univariate in n
2272
 *
2273
 *   Notes
2274
 *   =====
2275
 *   A univariate polynomial is considered dense iff more than half of
2276
 *   the coefficients a_0...a_deg are non-zero.
2277
 */
2278
int poly::is_dense_univariate () const {
12,648,625✔
2279

2280
        POLY_GETIDENTITY(*this);
12,648,625✔
2281
        
2282
        int num_terms=0, res=-1;
12,648,625✔
2283

2284
        // test univariate
2285
        for (int i=1; i<terms[0]; i+=terms[i]) {
51,293,373✔
2286
                for (int j=0; j<AN.poly_num_vars; j++)
91,927,485✔
2287
                        if (terms[i+1+j] > 0) {
53,282,737✔
2288
                                if (res == -1) res = j;
26,246,361✔
2289
                                if (res != j) return -2;
26,246,361✔
2290
                        }
2291

2292
                num_terms++;
38,644,748✔
2293
        }
2294

2295
        // constant polynomial
2296
        if (res == -1) return -1;
12,557,110✔
2297

2298
        // test density
2299
        int deg = terms[2+res];
12,556,092✔
2300
        if (2*num_terms < deg+1) return -2;
12,556,092✔
2301
        
2302
        return res;
2303
}
2304

2305
/*
2306
          #] is_dense_univariate : 
2307
          #[ simple_poly (small) :
2308
*/
2309

2310
// returns the polynomial (x-a)^b mod p^n with a small
2311
const poly poly::simple_poly (PHEAD int x, int a, int b, int p, int n) {
9,921✔
2312
        
2313
        poly tmp(BHEAD 0,p,n);
9,921✔
2314
        
2315
        int idx=1;
9,921✔
2316
        tmp[idx++] = 3 + AN.poly_num_vars;                        // length
9,921✔
2317
        for (int i=0; i<AN.poly_num_vars; i++)
560,370✔
2318
                tmp[idx++] = i==x ? 1 : 0;                              // powers
1,090,977✔
2319
        tmp[idx++] = 1;                                           // coefficient
9,921✔
2320
        tmp[idx++] = 1;                                           // length coefficient
9,921✔
2321

2322
        if (a != 0) {
9,921✔
2323
                tmp[idx++] = 3 + AN.poly_num_vars;                      // length
9,063✔
2324
                for (int i=0; i<AN.poly_num_vars; i++) tmp[idx++] = 0;  // powers
532,905✔
2325
                tmp[idx++] = ABS(a);                                    // coefficient
9,063✔
2326
                tmp[idx++] = -SGN(a);                                   // length coefficient
9,063✔
2327
        }
2328
        
2329
        tmp[0] = idx;                                             // length
9,921✔
2330

2331
        if (b == 1) return tmp;
9,921✔
2332
        
2333
        poly res(BHEAD 1,p,n);
222✔
2334
        
2335
        while (b!=0) {
774✔
2336
                if (b&1) res*=tmp;
552✔
2337
                tmp*=tmp;
552✔
2338
                b>>=1;
552✔
2339
        }
2340

2341
        return res;
222✔
2342
}
9,921✔
2343

2344
/*
2345
          #] simple_poly (small) : 
2346
          #[ simple_poly (large) :
2347
*/
2348

2349
// returns the polynomial (x-a)^b mod p^n with a large
2350
const poly poly::simple_poly (PHEAD int x, const poly &a, int b, int p, int n) {
2,503,470✔
2351

2352
        poly res(BHEAD 1,p,n);
2,503,470✔
2353
        poly tmp(BHEAD 0,p,n);
2,503,470✔
2354
        
2355
        int idx=1;
2,503,470✔
2356

2357
        tmp[idx++] = 3 + AN.poly_num_vars;                                // length
2,503,470✔
2358
        for (int i=0; i<AN.poly_num_vars; i++)
5,120,818✔
2359
                tmp[idx++] = i==x ? 1 : 0;                                      // powers
2,731,226✔
2360
        tmp[idx++] = 1;                                                   // coefficient
2,503,470✔
2361
        tmp[idx++] = 1;                                                   // length coefficient
2,503,470✔
2362

2363
        if (!a.is_zero()) {
2,503,470✔
2364
                tmp[idx++] = 2 + AN.poly_num_vars + ABS(a[a[0]-1]); // length
2,503,470✔
2365
                for (int i=0; i<AN.poly_num_vars; i++) tmp[idx++] = 0;          // powers
5,120,818✔
2366
                for (int i=0; i<ABS(a[a[0]-1]); i++)
5,376,808✔
2367
                        tmp[idx++] = a[2 + AN.poly_num_vars + i];                     // coefficient
2,873,338✔
2368
                tmp[idx++] = -a[a[0]-1];                                        // length coefficient
2,503,470✔
2369
        }
2370
        
2371
        tmp[0] = idx;                                                     // length
2,503,470✔
2372

2373
        while (b!=0) {
5,006,940✔
2374
                if (b&1) res*=tmp;
2,503,470✔
2375
                tmp*=tmp;
2,503,470✔
2376
                b>>=1;
2,503,470✔
2377
        }
2378
        
2379
        return res;
2,503,470✔
2380
}
2,503,470✔
2381

2382
/*
2383
          #] simple_poly (large) : 
2384
          #[ get_variables :
2385
*/
2386

2387
// gets all variables in the expressions and stores them in AN.poly_vars
2388
// (it is assumed that AN.poly_vars=NULL)
2389
void poly::get_variables (PHEAD vector<WORD *> es, bool with_arghead, bool sort_vars) {
797,576✔
2390

2391
        AN.poly_num_vars = 0;
797,576✔
2392

2393
        vector<int> vars;
797,576✔
2394
        vector<int> degrees;
797,576✔
2395
        map<int,int> var_to_idx;
797,576✔
2396
        
2397
        // extract all variables
2398
        for (int ei=0; ei<(int)es.size(); ei++) {
3,172,258✔
2399
                WORD *e = es[ei];
2,374,709✔
2400

2401
                // fast notation
2402
                if (*e == -SNUMBER) {
2,374,709✔
2403
                }
2404
                else if (*e == -SYMBOL) {
2,356,037✔
2405
                        if (!var_to_idx.count(e[1])) {
696✔
2406
                                vars.push_back(e[1]);
252✔
2407
                                var_to_idx[e[1]] = AN.poly_num_vars++;
252✔
2408
                                degrees.push_back(1);
252✔
2409
                        }
2410
                }
2411
                // JD: Here we need to check for non-symbol/number terms in fast notation.
2412
                else if (*e < 0) {
2,355,341✔
2413
                        MLOCK(ErrorMessageLock);
24✔
2414
                        MesPrint ((char*)"ERROR: polynomials and polyratfuns must contain symbols only");
24✔
2415
                        MUNLOCK(ErrorMessageLock);
24✔
2416
                        Terminate(1);
24✔
2417
                }
2418
                else {
2419
                        for (int i=with_arghead ? ARGHEAD : 0; with_arghead ? i<e[0] : e[i]!=0; i+=e[i]) {
14,097,377✔
2420
                                if (i+1<i+e[i]-ABS(e[i+e[i]-1]) && e[i+1]!=SYMBOL) {
9,386,746✔
2421
                                        MLOCK(ErrorMessageLock);
3✔
2422
                                        MesPrint ((char*)"ERROR: polynomials and polyratfuns must contain symbols only");
3✔
2423
                                        MUNLOCK(ErrorMessageLock);
3✔
2424
                                        Terminate(1);
3✔
2425
                                }
2426
                                
2427
                                for (int j=i+3; j<i+e[i]-ABS(e[i+e[i]-1]); j+=2) {
17,180,226✔
2428
                                        if (!var_to_idx.count(e[j])) {
7,793,483✔
2429
                                                vars.push_back(e[j]);
818,741✔
2430
                                                var_to_idx[e[j]] = AN.poly_num_vars++;
818,741✔
2431
                                                degrees.push_back(e[j+1]);
818,741✔
2432
                                        }
2433
                                        else {
2434
                                                degrees[var_to_idx[e[j]]] = MaX(degrees[var_to_idx[e[j]]], e[j+1]);
6,974,742✔
2435
                                        }
2436
                                }
2437
                        }
2438
                }
2439
        }
2440

2441
        // make sure an eventual FACTORSYMBOL appear as last
2442
        if (var_to_idx.count(FACTORSYMBOL)) {
797,549✔
2443
                int i = var_to_idx[FACTORSYMBOL];
6✔
2444
                while (i+1<AN.poly_num_vars) {
12✔
2445
                        swap(vars[i], vars[i+1]);
6✔
2446
                        swap(degrees[i], degrees[i+1]);
6✔
2447
                        i++;
6✔
2448
                }
2449
                degrees[i] = -1; // makes sure it stays last
6✔
2450
        }
2451

2452
        // AN.poly_vars will be deleted in calling functions from polywrap.c
2453
        // For that we use the function poly_free_poly_vars
2454
        // We add one to the allocation to avoid copying in poly_divmod
2455

2456
        if ( (AN.poly_num_vars+1)*sizeof(WORD) > (size_t)(AM.MaxTer) ) {
797,549✔
2457
                // This can happen only in expressions with excessively many variables.
2458
                AN.poly_vars = (WORD *)Malloc1((AN.poly_num_vars+1)*sizeof(WORD), "AN.poly_vars");
×
2459
                AN.poly_vars_type = 1;
×
2460
        }
2461
        else {
2462
                AN.poly_vars = TermMalloc("AN.poly_vars");
797,549✔
2463
                AN.poly_vars_type = 0;
797,549✔
2464
        }
2465

2466
        for (int i=0; i<AN.poly_num_vars; i++)
1,616,542✔
2467
                AN.poly_vars[i] = vars[i];
818,993✔
2468

2469
        if (sort_vars) {
797,549✔
2470
                // bubble sort variables in decreasing order of degree
2471
                // (this seems better for factorization)
2472
                for (int i=0; i<AN.poly_num_vars; i++)
1,616,440✔
2473
                        for (int j=0; j+1<AN.poly_num_vars; j++)
900,653✔
2474
                                if (degrees[j] < degrees[j+1]) {
81,726✔
2475
                                        swap(degrees[j], degrees[j+1]);
11,954✔
2476
                                        swap(AN.poly_vars[j], AN.poly_vars[j+1]);
11,954✔
2477
                                }
2478
        }
2479
        else {
2480
                // sort lexicographically                
2481
                sort(AN.poly_vars, AN.poly_vars+AN.poly_num_vars - var_to_idx.count(FACTORSYMBOL));
36✔
2482
        }
2483
}
797,549✔
2484

2485
/*
2486
          #] get_variables : 
2487
          #[ argument_to_poly :
2488
*/
2489

2490
// converts a form expression to a polynomial class "poly"
2491
const poly poly::argument_to_poly (PHEAD WORD *e, bool with_arghead, bool sort_univar, poly *denpoly) {
2,374,682✔
2492

2493
        map<int,int> var_to_idx;
2,374,682✔
2494
        for (int i=0; i<AN.poly_num_vars; i++)
4,823,320✔
2495
                var_to_idx[AN.poly_vars[i]] = i;
2,448,638✔
2496
        
2497
        poly res(BHEAD 0);
2,374,682✔
2498

2499
        // fast notation
2500
        if (*e == -SNUMBER) {
2,374,682✔
2501
                if (denpoly!=NULL) *denpoly = poly(BHEAD 1);
18,672✔
2502
                
2503
                if (e[1] == 0) {
18,672✔
2504
                        res[0] = 1;
×
2505
                        return res;
×
2506
                }
2507
                else {
2508
                        res[0] = 4 + AN.poly_num_vars;
18,672✔
2509
                        res[1] = 3 + AN.poly_num_vars;
18,672✔
2510
                        for (int i=0; i<AN.poly_num_vars; i++)
61,083✔
2511
                                res[2+i] = 0;
42,411✔
2512
                        res[2+AN.poly_num_vars] = ABS(e[1]);
18,672✔
2513
                        res[3+AN.poly_num_vars] = SGN(e[1]);
18,672✔
2514

2515
                        return res;
18,672✔
2516
                }
2517
        }
2518

2519
        if (*e == -SYMBOL) {
2,356,010✔
2520
                if (denpoly!=NULL) *denpoly = poly(BHEAD 1);
696✔
2521
                
2522
                res[0] = 4 + AN.poly_num_vars;
696✔
2523
                res[1] = 3 + AN.poly_num_vars;
696✔
2524
                for (int i=0; i<AN.poly_num_vars; i++)
1,851✔
2525
                        res[2+i] = 0;
1,155✔
2526
                res[2+var_to_idx.find(e[1])->second] = 1;
696✔
2527
                res[2+AN.poly_num_vars] = 1;
696✔
2528
                res[3+AN.poly_num_vars] = 1;
696✔
2529
                return res;
696✔
2530
        }
2531

2532
        // find LCM of denominators of all terms
2533
        WORD nden=1, npro=0, ngcd=0, ndum=0;
2,355,314✔
2534
        UWORD *den = NumberMalloc("poly::argument_to_poly");
2,355,314✔
2535
        UWORD *pro = NumberMalloc("poly::argument_to_poly");
2,355,314✔
2536
        UWORD *gcd = NumberMalloc("poly::argument_to_poly");
2,355,314✔
2537
        UWORD *dum = NumberMalloc("poly::argument_to_poly");
2,355,314✔
2538
        den[0]=1;
2,355,314✔
2539
        
2540
        for (int i=with_arghead ? ARGHEAD : 0; with_arghead ? i<e[0] : e[i]!=0; i+=e[i]) {
11,742,249✔
2541
                int ncoe = ABS(e[i+e[i]-1]/2);
9,386,743✔
2542
                UWORD *coe = (UWORD *)&e[i+e[i]-ncoe-1];
9,386,743✔
2543
                while (ncoe>0 && coe[ncoe-1]==0) ncoe--;
25,570,374✔
2544
                MulLong(den,nden,coe,ncoe,pro,&npro);
9,386,743✔
2545
                GcdLong(BHEAD den,nden,coe,ncoe,gcd,&ngcd);
9,386,743✔
2546
                DivLong(pro,npro,gcd,ngcd,den,&nden,dum,&ndum);
9,386,743✔
2547
        }
2548

2549
        if (denpoly!=NULL) *denpoly = poly(BHEAD den, nden);
2,355,314✔
2550
        
2551
        int ri=1;
2552
        
2553
        // ordinary notation
2554
        for (int i=with_arghead ? ARGHEAD : 0; with_arghead ? i<e[0] : e[i]!=0; i+=e[i]) {
11,742,057✔
2555
                res.check_memory(ri);
9,386,743✔
2556
                WORD nc = e[i+e[i]-1];                                                 // length coefficient
9,386,743✔
2557
                for (int j=0; j<AN.poly_num_vars; j++)
19,795,239✔
2558
                        res[ri+1+j]=0;                                                     // powers=0
10,408,496✔
2559
                WCOPY(dum, &e[i+e[i]-ABS(nc)], ABS(nc));                               // coefficient to dummy
69,914,984✔
2560
                nc /= 2;                                                               // remove denominator
9,386,743✔
2561
                Mully(BHEAD dum, &nc, den, nden);                                      // multiply with overall den
9,386,743✔
2562
                res.termscopy((WORD *)dum, ri+1+AN.poly_num_vars, ABS(nc));            // coefficient to res
9,386,743✔
2563
                res[ri] = ABS(nc) + AN.poly_num_vars + 2;                              // length
9,386,743✔
2564
                res[ri+res[ri]-1] = nc;                                                // length coefficient
9,386,743✔
2565
                for (int j=i+3; j<i+e[i]-ABS(e[i+e[i]-1]); j+=2) 
17,180,226✔
2566
                        res[ri+1+var_to_idx.find(e[j])->second] = e[j+1];                  // powers
7,793,483✔
2567
                ri += res[ri];                                                         // length
9,386,743✔
2568
        }
2569

2570
        res[0] = ri;
2,355,314✔
2571

2572
        // JD: For univariate cases, check whether the ordering is correct or not.
2573
        // There are various ways to arrive here, but with an incorrect ordering, such
2574
        // as interactions with collect, moving a polyratfun out of another function
2575
        // argument, etc.
2576
        // If the ordering is not correct, make sure we normalize. In multivariate cases,
2577
        // always normalize as before.
2578
        if (sort_univar == false && AN.poly_num_vars == 1) {
2,355,314✔
2579
                if (res.number_of_terms() >= 2) {
1,485,161✔
2580
                        if(res[2] < res.last_monomial()[2]) {
1,484,549✔
2581
                                sort_univar = true;
2582
                        }
2583
                }
2584
        }
2585

2586
        if (sort_univar || AN.poly_num_vars>1) {
155,933✔
2587
                res.normalize();
2,221,782✔
2588
        }
2589

2590
        NumberFree(den,"poly::argument_to_poly");
2,355,314✔
2591
        NumberFree(pro,"poly::argument_to_poly");
2,355,314✔
2592
        NumberFree(gcd,"poly::argument_to_poly");
2,355,314✔
2593
        NumberFree(dum,"poly::argument_to_poly");
2,355,314✔
2594
        
2595
        return res;
2,355,314✔
2596
}
2,374,682✔
2597

2598
/*
2599
          #] argument_to_poly : 
2600
          #[ poly_to_argument :
2601
*/
2602

2603
// converts a polynomial class "poly" to a form expression
2604
void poly::poly_to_argument (const poly &a, WORD *res, bool with_arghead) {
1,595,146✔
2605

2606
        POLY_GETIDENTITY(a);
1,595,146✔
2607

2608
        // special case: a=0
2609
        if (a[0]==1) {
1,595,146✔
2610
                if (with_arghead) {
3,219✔
2611
                        res[0] = -SNUMBER;
3,219✔
2612
                        res[1] = 0;
3,219✔
2613
                }
2614
                else {
2615
                        res[0] = 0;
×
2616
                }
2617
                return;
3,219✔
2618
        }
2619

2620
        if (with_arghead) {
1,591,927✔
2621
                res[1] = AN.poly_num_vars>1 ? DIRTYFLAG : 0; // dirty flag
1,591,639✔
2622
                for (int i=2; i<ARGHEAD; i++)
1,591,639✔
2623
                        res[i] = 0;                                // remainder of arghead        
2624
        }
2625

2626
        int L = with_arghead ? ARGHEAD : 0;
1,591,639✔
2627
        
2628
        for (int i=1; i!=a[0]; i+=a[i]) {
9,960,168✔
2629
                
2630
                res[L]=1; // length
8,368,241✔
2631

2632
                bool first=true;
8,368,241✔
2633
                
2634
                for (int j=0; j<AN.poly_num_vars; j++)
17,455,820✔
2635
                        if (a[i+1+j] > 0) {
9,087,579✔
2636
                                if (first) {
7,312,912✔
2637
                                        first=false;
6,798,997✔
2638
                                        res[L+1] = 1; // symbols
6,798,997✔
2639
                                        res[L+2] = 2; // length
6,798,997✔
2640
                                }
2641
                                res[L+1+res[L+2]++] = AN.poly_vars[j]; // symbol
7,312,912✔
2642
                                res[L+1+res[L+2]++] = a[i+1+j];  // power
7,312,912✔
2643
                        }
2644

2645
                if (!first)        res[L] += res[L+2]; // fix length
8,368,241✔
2646

2647
                WORD nc = a[i+a[i]-1];
8,368,241✔
2648
                WCOPY(&res[L+res[L]], &a[i+a[i]-1-ABS(nc)], ABS(nc)); // numerator
44,628,210✔
2649

2650
                res[L] += ABS(nc);                                     // fix length
8,368,241✔
2651
                memset(&res[L+res[L]], 0, ABS(nc)*sizeof(WORD)); // denominator one
8,368,241✔
2652
                res[L+res[L]] = 1;                               // denominator one
8,368,241✔
2653
                res[L] += ABS(nc);                               // fix length
8,368,241✔
2654
                res[L+res[L]] = SGN(nc) * (2*ABS(nc)+1);         // length of coefficient
8,368,241✔
2655
                res[L]++;                                        // fix length
8,368,241✔
2656
                L += res[L];                                     // fix length
8,368,241✔
2657
        }
2658

2659
        if (with_arghead) {
1,591,927✔
2660
                res[0] = L;
1,591,639✔
2661
                // convert to fast notation if possible
2662
                ToFast(res,res);
1,591,639✔
2663
        }
2664
        else {
2665
                res[L] = 0;
288✔
2666
        }
2667
}
2668

2669
/*
2670
          #] poly_to_argument : 
2671
          #[ poly_to_argument_with_den :
2672
*/
2673

2674
// converts a polynomial class "poly" divided by a number (nden, den) to a form expression
2675
// cf. poly::poly_to_argument()
2676
void poly::poly_to_argument_with_den (const poly &a, WORD nden, const UWORD *den, WORD *res, bool with_arghead) {
9✔
2677

2678
        POLY_GETIDENTITY(a);
9✔
2679

2680
        // special case: a=0
2681
        if (a[0]==1) {
9✔
2682
                if (with_arghead) {
×
2683
                        res[0] = -SNUMBER;
×
2684
                        res[1] = 0;
×
2685
                }
2686
                else {
2687
                        res[0] = 0;
×
2688
                }
2689
                return;
×
2690
        }
2691

2692
        if (with_arghead) {
9✔
2693
                res[1] = AN.poly_num_vars>1 ? DIRTYFLAG : 0; // dirty flag
×
2694
                for (int i=2; i<ARGHEAD; i++)
×
2695
                        res[i] = 0;                                // remainder of arghead
2696
        }
2697

2698
        WORD nden1;
9✔
2699
        UWORD *den1 = (UWORD *)NumberMalloc("poly_to_argument_with_den");
9✔
2700

2701
        int L = with_arghead ? ARGHEAD : 0;
9✔
2702

2703
        for (int i=1; i!=a[0]; i+=a[i]) {
8,244✔
2704

2705
                res[L]=1; // length
8,235✔
2706

2707
                bool first=true;
8,235✔
2708

2709
                for (int j=0; j<AN.poly_num_vars; j++)
41,136✔
2710
                        if (a[i+1+j] > 0) {
32,901✔
2711
                                if (first) {
27,441✔
2712
                                        first=false;
8,226✔
2713
                                        res[L+1] = 1; // symbols
8,226✔
2714
                                        res[L+2] = 2; // length
8,226✔
2715
                                }
2716
                                res[L+1+res[L+2]++] = AN.poly_vars[j]; // symbol
27,441✔
2717
                                res[L+1+res[L+2]++] = a[i+1+j];  // power
27,441✔
2718
                        }
2719

2720
                if (!first)        res[L] += res[L+2]; // fix length
8,235✔
2721

2722
                // numerator
2723
                WORD nc = a[i+a[i]-1];
8,235✔
2724
                WCOPY(&res[L+res[L]], &a[i+a[i]-1-ABS(nc)], ABS(nc));
77,889✔
2725

2726
                // denominator
2727
                nden1 = nden;
8,235✔
2728
                WCOPY(den1, den, ABS(nden));
74,031✔
2729

2730
                if (nden != 1 || den[0] != 1) {
8,235✔
2731
                        // remove gcd(num,den)
2732
                        Simplify(BHEAD (UWORD *)&res[L+res[L]], &nc, den1, &nden1);
8,235✔
2733
                }
2734

2735
                Pack((UWORD *)&res[L+res[L]], &nc, den1, nden1);  // format
8,235✔
2736
                res[L] += 2*ABS(nc)+1;                            // fix length
8,235✔
2737
                res[L+res[L]-1] = SGN(nc)*(2*ABS(nc)+1);          // length of coefficient
8,235✔
2738
                L += res[L];                                      // fix length
8,235✔
2739
        }
2740

2741
        NumberFree(den1, "poly_to_argument_with_den");
9✔
2742

2743
        if (with_arghead) {
9✔
2744
                res[0] = L;
×
2745
                // convert to fast notation if possible
2746
                ToFast(res,res);
×
2747
        }
2748
        else {
2749
                res[L] = 0;
9✔
2750
        }
2751
}
2752

2753
/*
2754
          #] poly_to_argument_with_den : 
2755
          #[ size_of_form_notation :
2756
*/
2757

2758
// the size of the polynomial in form notation (without argheads and fast notation)
2759
int poly::size_of_form_notation () const {
1,595,155✔
2760
        
2761
        POLY_GETIDENTITY(*this);
1,595,155✔
2762

2763
        // special case: a=0
2764
        if (terms[0]==1) return 0;
1,595,155✔
2765

2766
        int len = 0;
2767
        
2768
        for (int i=1; i!=terms[0]; i+=terms[i]) {
9,960,411✔
2769
                len++;
8,368,475✔
2770
                int npow = 0;
8,368,475✔
2771
                for (int j=0; j<AN.poly_num_vars; j++)
17,456,846✔
2772
                        if (terms[i+1+j] > 0) npow++;
9,088,371✔
2773
                if (npow > 0) len += 2*npow + 2;
8,368,475✔
2774
                len += 2 * ABS(terms[i+terms[i]-1]) + 1;
8,368,475✔
2775
        }
2776

2777
        return len;
2778
}
2779

2780
/*
2781
          #] size_of_form_notation : 
2782
          #[ size_of_form_notation_with_den :
2783
*/
2784

2785
// the size of the polynomial divided by a number (its size is given by nden)
2786
// in form notation (without argheads and fast notation)
2787
// cf. poly::size_of_form_notation()
2788
int poly::size_of_form_notation_with_den (WORD nden) const {
9✔
2789

2790
        POLY_GETIDENTITY(*this);
9✔
2791

2792
        // special case: a=0
2793
        if (terms[0]==1) return 0;
9✔
2794

2795
        nden = ABS(nden);
9✔
2796
        int len = 0;
9✔
2797

2798
        for (int i=1; i!=terms[0]; i+=terms[i]) {
8,244✔
2799
                len++;
8,235✔
2800
                int npow = 0;
8,235✔
2801
                for (int j=0; j<AN.poly_num_vars; j++)
41,136✔
2802
                        if (terms[i+1+j] > 0) npow++;
32,901✔
2803
                if (npow > 0) len += 2*npow + 2;
8,235✔
2804
                len += 2 * MaX(ABS(terms[i+terms[i]-1]), nden) + 1;
8,235✔
2805
        }
2806

2807
        return len;
2808
}
2809

2810
/*
2811
          #] size_of_form_notation_with_den : 
2812
          #[ to_coefficient_list :
2813
*/
2814

2815
// returns the coefficient list of a univariate polynomial
2816
const vector<WORD> poly::to_coefficient_list (const poly &a) {
6,932✔
2817

2818
        POLY_GETIDENTITY(a);
6,932✔
2819
        
2820
        if (a.is_zero()) return vector<WORD>();
6,932✔
2821
                        
2822
        int x = a.first_variable();
6,932✔
2823
        if (x == AN.poly_num_vars) x=0;
6,932✔
2824
                
2825
        vector<WORD> res(1+a[2+x],0);
6,932✔
2826
        
2827
        for (int i=1; i<a[0]; i+=a[i]) 
480,819✔
2828
                res[a[i+1+x]] = (a[i+a[i]-1] * a[i+a[i]-2]) % a.modp;
473,887✔
2829

2830
        return res;
6,932✔
2831
}
6,932✔
2832

2833
/*
2834
          #] to_coefficient_list : 
2835
          #[ coefficient_list_divmod :
2836
*/
2837

2838
// divides two polynomials represented by coefficient lists
2839
const vector<WORD> poly::coefficient_list_divmod (const vector<WORD> &a, const vector<WORD> &b, WORD p, int divmod) {
145,746✔
2840

2841
        int bsize = (int)b.size();
145,746✔
2842
        while (b[bsize-1]==0) bsize--;
271,838✔
2843
        
2844
        WORD inv;
145,746✔
2845
        GetModInverses(b[bsize-1] + (b[bsize-1]<0?p:0), p, &inv, NULL);
232,399✔
2846
                                                                                
2847
        vector<WORD> q(a.size(),0);
145,746✔
2848
        vector<WORD> r(a);
145,746✔
2849
                
2850
        while ((int)r.size() >= bsize) {
718,096✔
2851
                LONG mul = ((LONG)inv * r.back()) % p;
572,350✔
2852
                int off = r.size()-bsize;
572,350✔
2853
                q[off] = mul;
572,350✔
2854
                for (int i=0; i<bsize; i++)
13,340,937✔
2855
                        r[off+i] = (r[off+i] - mul*b[i]) % p;
12,768,587✔
2856
                while (r.size()>0 && r.back()==0)
1,349,783✔
2857
                        r.pop_back();
777,433✔
2858
        }
2859

2860
        if (divmod==0) {
145,746✔
2861
                while (q.size()>0 && q.back()==0)
873✔
2862
                        q.pop_back();
675✔
2863
                return q;
198✔
2864
        }
2865
        else {
2866
                while (r.size()>0 && r.back()==0)
145,548✔
2867
                        r.pop_back();
×
2868
                return r;
145,548✔
2869
        }
2870
}
145,746✔
2871

2872
/*
2873
          #] coefficient_list_divmod : 
2874
          #[ from_coefficient_list :
2875
*/
2876

2877
// converts a coefficient list to a "poly"
2878
const poly poly::from_coefficient_list (PHEAD const vector<WORD> &a, int x, WORD p) {
3,727✔
2879

2880
        poly res(BHEAD 0);
3,727✔
2881
        int ri=1;
3,727✔
2882
        
2883
        for (int i=(int)a.size()-1; i>=0; i--)
8,064✔
2884
                if (a[i] != 0) {
4,337✔
2885
                        res.check_memory(ri);
4,283✔
2886
                        res[ri] = AN.poly_num_vars+3;                // length
4,283✔
2887
                        for (int j=0; j<AN.poly_num_vars; j++)
11,410✔
2888
                                res[ri+1+j]=0;                             // powers
7,127✔
2889
                        res[ri+1+x] = i;                             // power of x
4,283✔
2890
                        res[ri+1+AN.poly_num_vars] = ABS(a[i]);      // coefficient
4,283✔
2891
                        res[ri+1+AN.poly_num_vars+1] = SGN(a[i]);    // sign
4,283✔
2892
                        ri += res[ri];
4,283✔
2893
                }
2894
        
2895
        res[0]=ri;                                       // total length
3,727✔
2896
        res.setmod(p,1);
3,727✔
2897
        
2898
        return res;
3,727✔
2899
}
×
2900

2901
/*
2902
          #] from_coefficient_list : 
2903
*/
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