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

vermaseren / form / 9364948935

04 Jun 2024 09:49AM UTC coverage: 49.979% (-0.02%) from 49.999%
9364948935

Pull #526

github

web-flow
Merge 7062bd769 into 83e3d4185
Pull Request #526: RFC: better debugging

52 of 415 new or added lines in 46 files covered. (12.53%)

32 existing lines in 2 files now uncovered.

41391 of 82816 relevant lines covered (49.98%)

878690.77 hits per line

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

90.43
/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):
8,307,040✔
54
        size_of_terms(AM.MaxTer/(LONG)sizeof(WORD)),
8,307,040✔
55
        modp(0),
56
        modn(1)
8,307,040✔
57
{
58
        POLY_STOREIDENTITY;
8,307,040✔
59
        
60
        terms = TermMalloc("poly::poly(int)");
8,307,040✔
61

62
        if (a == 0) {
8,307,040✔
63
                terms[0] = 1; // length
7,370,040✔
64
        }
65
        else {
66
                terms[0] = 4 + AN.poly_num_vars;                       // length
936,996✔
67
                terms[1] = 3 + AN.poly_num_vars;                       // length
936,996✔
68
                for (int i=0; i<AN.poly_num_vars; i++) terms[2+i] = 0; // powers
2,819,305✔
69
                terms[2+AN.poly_num_vars] = ABS(a);                    // coefficient
936,996✔
70
                terms[3+AN.poly_num_vars] = a>0 ? 1 : -1;              // length coefficient
1,017,647✔
71
        }
72

73
        if (modp!=-1) setmod(modp,modn);
8,307,040✔
74
}
8,307,040✔
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):
332,319✔
83
        size_of_terms(AM.MaxTer/(LONG)sizeof(WORD)),
332,319✔
84
        modp(0),
85
        modn(1)
332,319✔
86
{
87
        POLY_STOREIDENTITY;
332,319✔
88
        
89
        terms = TermMalloc("poly::poly(UWORD*,WORD)");
332,319✔
90

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

101
        if (modp!=-1) setmod(modp,modn);
332,319✔
102
}
332,319✔
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):
1,920,557✔
111
        size_of_terms(AM.MaxTer/(LONG)sizeof(WORD))        
1,920,557✔
112
{
113
        POLY_GETIDENTITY(a);
1,920,557✔
114
        POLY_STOREIDENTITY;
1,920,557✔
115
        
116
        terms = TermMalloc("poly::poly(poly&)");
1,920,557✔
117

118
        *this = a;
1,920,557✔
119

120
        if (modp!=-1) setmod(modp,modn);
1,920,557✔
121
}
1,920,557✔
122

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

128
// destructor
129
poly::~poly () {
21,119,830✔
130

131
        POLY_GETIDENTITY(*this);
10,559,910✔
132
        
133
        if (size_of_terms == AM.MaxTer/(LONG)sizeof(WORD))
10,559,910✔
134
                TermFree(terms, "poly::~poly");
10,559,840✔
135
        else
136
                M_free(terms, "poly::~poly");
72✔
137
}
10,559,910✔
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) {
136✔
146
        
147
        POLY_GETIDENTITY(*this);
136✔
148

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

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

165
        terms = newterms;
136✔
166
        size_of_terms = new_size_of_terms;
136✔
167
}
136✔
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) {
2,576,509✔
176

177
        POLY_GETIDENTITY(*this);
2,576,509✔
178
        
179
        if (_modp>0 && (_modp!=modp || _modn<modn)) {
2,576,509✔
180
                modp = _modp;
45,472✔
181
                modn = _modn;
45,472✔
182
        
183
                WORD nmodq=0;
45,472✔
184
                UWORD *modq=NULL;
45,472✔
185
                bool smallq;
45,472✔
186
                
187
                if (modn == 1) {
45,472✔
188
                        modq = (UWORD *)&modp;
40,530✔
189
                        nmodq = 1;
40,530✔
190
                        smallq = true;
40,530✔
191
                }
192
                else {
193
                        RaisPowCached(BHEAD modp,modn,&modq,&nmodq);
4,942✔
194
                        smallq = false;
195
                }
196
                
197
                coefficients_modulo(modq,nmodq,smallq);
45,472✔
198
        }
199
        else {
200
                modp = _modp;
2,531,037✔
201
                modn = _modn;
2,531,037✔
202
        }
203
}
2,576,509✔
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) {
170,566✔
212

213
        POLY_GETIDENTITY(*this);
170,566✔
214
        
215
        int j=1;
170,566✔
216
        for (int i=1, di; i<terms[0]; i+=di) {
1,876,784✔
217
                di = terms[i];
1,706,218✔
218
                
219
                if (i!=j)
1,706,218✔
220
                        for (int k=0; k<di; k++)
6,309,230✔
221
                                terms[j+k] = terms[i+k];
5,503,540✔
222
                
223
                WORD n = terms[j+terms[j]-1];
1,706,218✔
224

225
                if (ABS(n)==1 && small) {
1,706,218✔
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]);
944,368✔
228
                        if (terms[j+1+AN.poly_num_vars] == 0)
944,368✔
229
                                n=0;
9,684✔
230
                        else {
231
                                if (terms[j+1+AN.poly_num_vars] > +(WORD)a[0]/2) terms[j+1+AN.poly_num_vars]-=a[0];
934,684✔
232
                                if (terms[j+1+AN.poly_num_vars] < -(WORD)a[0]/2) terms[j+1+AN.poly_num_vars]+=a[0];
934,684✔
233
                                n = SGN(terms[j+1+AN.poly_num_vars]);
934,684✔
234
                                terms[j+1+AN.poly_num_vars] = ABS(terms[j+1+AN.poly_num_vars]);
934,684✔
235
                        }
236
                }
237
                else
238
                        TakeNormalModulus((UWORD *)&terms[j+1+AN.poly_num_vars], &n, a, na, NOUNPACK);
761,850✔
239
                        
240
                if (n!=0) {
1,706,218✔
241
                        terms[j] = 2+AN.poly_num_vars+ABS(n);
1,675,592✔
242
                        terms[j+terms[j]-1] = n;
1,675,592✔
243
                        j += terms[j];
1,675,592✔
244
                }
245
        }
246
        
247
        terms[0] = j;
170,566✔
248
}
170,566✔
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) {
94,246,500✔
347
        for (int i=0; i<AN.poly_num_vars; i++)
180,781,700✔
348
                if (a[i+1]!=b[i+1]) return a[i+1]-b[i+1];
146,095,800✔
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() {
123,161✔
359

360
        POLY_GETIDENTITY(*this);
123,161✔
361
 
362
        WORD nmodq=0;
123,161✔
363
        UWORD *modq=NULL;
123,161✔
364
        
365
        if (modp!=0) {
123,161✔
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;
123,161✔
379
    WantAddPointers((terms[0]/(AN.poly_num_vars+3)));
123,457✔
380
    AT.pWorkPointer += terms[0]/(AN.poly_num_vars+3);
123,161✔
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;
123,161✔
386
        for (int i=1; i<terms[0]; i+=terms[i])
1,057,923✔
387
                p[nterms++] = terms + i;
934,762✔
388

389
        sort(p, p + nterms, monomial_larger(BHEAD0));
123,161✔
390

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

403
        for (int i=0; i<nterms; i++) {
1,057,923✔
404
                if (i>0 && monomial_compare(BHEAD &tmp[j], p[i])==0) {
934,762✔
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;
934,762✔
417
                        j += tmp[j];
934,762✔
418
                        WCOPY(&tmp[j],p[i],p[i][0]);
7,007,960✔
419
                }
420

421
                if (modp!=0) {
934,762✔
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) {
934,762✔
432
                        tmp[j]=0;
×
433
                        j=prevj;
×
434
                }
435
        }
436

437
        j+=tmp[j];
123,161✔
438

439
        tmp[0] = j;
123,161✔
440
        WCOPY(terms,tmp,tmp[0]);
6,319,510✔
441

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

449
        AT.pWorkPointer = poffset;
123,161✔
450
        #undef p
451

452
        return *this;
123,161✔
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 {
621,144✔
462
        POLY_GETIDENTITY(*this);
621,144✔
463
        return terms[0] - ABS(terms[terms[0]-1]) - AN.poly_num_vars - 2;
621,144✔
464
}
465

466

467
// pointer to the last monomial (the constant term)
468
WORD * poly::last_monomial () const {
621,144✔
469
        return &terms[last_monomial_index()];
621,144✔
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) {
181,435✔
535

536
        POLY_GETIDENTITY(a);
181,435✔
537

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

558
        int ai=1,bi=1,ci=1;
181,435✔
559
        
560
        while (ai<a[0] || bi<b[0]) {
1,965,989✔
561

562
                c.check_memory(ci);
1,784,554✔
563
                
564
                int cmp = ai<a[0] && bi<b[0] ? monomial_compare(BHEAD &a[ai],&b[bi]) : 0;
1,784,554✔
565
                
566
                if (bi==b[0] || cmp>0) {
1,784,554✔
567
                        // insert term from a
568
                        c.termscopy(&a[ai],ci,a[ai]);
340,919✔
569
                        ci+=a[ai];
340,919✔
570
                        ai+=a[ai];
340,919✔
571
                }
572
                else if (ai==a[0] || cmp<0) {
1,443,635✔
573
                        // insert term from b
574
                        c.termscopy(&b[bi],ci,b[bi]);
49,303✔
575
                        ci+=b[bi];
49,303✔
576
                        bi+=b[bi];
49,303✔
577
                }
578
                else {
579
                        // insert term from a+b
580
                        c.termscopy(&a[ai],ci,MaX(a[ai],b[bi]));
1,394,332✔
581
                        WORD nc=0;
1,394,332✔
582
                        if (both_mod_small) {
1,394,332✔
583
                                c[ci+1+AN.poly_num_vars] = ((LONG)a[ai+1+AN.poly_num_vars]*a[ai+a[ai]-1]+
74✔
584
                                                                                                                                                (LONG)b[bi+1+AN.poly_num_vars]*b[bi+b[bi]-1]) % c.modp;
74✔
585
                                if ((WORD)c[ci+1+AN.poly_num_vars] > +c.modp/2) c[ci+1+AN.poly_num_vars] -= c.modp;
74✔
586
                                if ((WORD)c[ci+1+AN.poly_num_vars] < -c.modp/2) c[ci+1+AN.poly_num_vars] += c.modp;
74✔
587
                                nc = (c[ci+1+AN.poly_num_vars]==0 ? 0 : SGN((WORD)c[ci+1+AN.poly_num_vars]));
74✔
588
                                c[ci+1+AN.poly_num_vars] = ABS((WORD)c[ci+1+AN.poly_num_vars]);                                                                                                        
74✔
589
                        }
590
                        else {
591
                                AddLong((UWORD *)&a[ai+1+AN.poly_num_vars], a[ai+a[ai]-1],
1,394,258✔
592
                                                                (UWORD *)&b[bi+1+AN.poly_num_vars], b[bi+b[bi]-1],
1,394,258✔
593
                                                                (UWORD *)&c[ci+1+AN.poly_num_vars], &nc);
1,394,258✔
594
                                if (c.modp!=0) TakeNormalModulus((UWORD *)&c[ci+1+AN.poly_num_vars], &nc,
1,394,258✔
595
                                                                                                                                                                 modq, nmodq, NOUNPACK);
596
                        }
597
                                                        
598
                        if (nc!=0) {
1,394,332✔
599
                                c[ci] = 2+AN.poly_num_vars+ABS(nc);
1,334,260✔
600
                                c[ci+c[ci]-1] = nc;
1,334,260✔
601
                                ci += c[ci];
1,334,260✔
602
                        }
603
                        
604
                        ai+=a[ai];
1,394,332✔
605
                        bi+=b[bi];                        
1,394,332✔
606
                }                
607
        }
608

609
        c[0]=ci;
181,435✔
610
}
181,435✔
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) {
185,151✔
619

620
        POLY_GETIDENTITY(a);
185,151✔
621
        
622
  c.modp = a.modp;
185,151✔
623
  c.modn = a.modn;
185,151✔
624

625
        WORD nmodq=0;
185,151✔
626
        UWORD *modq=NULL;
185,151✔
627
        
628
        bool both_mod_small=false;
185,151✔
629
        
630
        if (c.modp!=0) {
185,151✔
631
                if (c.modn == 1) {
35,729✔
632
                        modq = (UWORD *)&c.modp;
35,045✔
633
                        nmodq = 1;
35,045✔
634
                        if (a.modp>0 && b.modp>0 && a.modn==1 && b.modn==1)
35,045✔
635
                                both_mod_small=true;
35,045✔
636
                }
637
                else {
638
                        RaisPowCached(BHEAD c.modp,c.modn,&modq,&nmodq);
684✔
639
                }
640
        }
641
        
642
        int ai=1,bi=1,ci=1;
185,151✔
643
        
644
        while (ai<a[0] || bi<b[0]) {
2,088,830✔
645

646
                c.check_memory(ci);
1,903,679✔
647
                
648
                int cmp = ai<a[0] && bi<b[0] ? monomial_compare(BHEAD &a[ai],&b[bi]) : 0;
1,903,679✔
649
                
650
                if (bi==b[0] || cmp>0) {
1,903,679✔
651
                        // insert term from a
652
                        c.termscopy(&a[ai],ci,a[ai]);
92,447✔
653
                        ci+=a[ai];
92,447✔
654
                        ai+=a[ai];
92,447✔
655
                }
656
                else if (ai==a[0] || cmp<0) {
1,811,232✔
657
                        // insert term from b
658
                        c.termscopy(&b[bi],ci,b[bi]);
200,173✔
659
                        ci+=b[bi];
200,173✔
660
                        bi+=b[bi];
200,173✔
661
                        c[ci-1]*=-1;
200,173✔
662
                }
663
                else {
664
                        // insert term from a+b
665
                        c.termscopy(&a[ai],ci,MaX(a[ai],b[bi]));
1,611,059✔
666
                        WORD nc=0;
1,611,059✔
667
                        if (both_mod_small) {
1,611,059✔
668
                                c[ci+1+AN.poly_num_vars] = ((LONG)a[ai+1+AN.poly_num_vars]*a[ai+a[ai]-1]-
712,471✔
669
                                                                                                                                                (LONG)b[bi+1+AN.poly_num_vars]*b[bi+b[bi]-1]) % c.modp;
712,471✔
670
                                if ((WORD)c[ci+1+AN.poly_num_vars] > +c.modp/2) c[ci+1+AN.poly_num_vars] -= c.modp;
712,471✔
671
                                if ((WORD)c[ci+1+AN.poly_num_vars] < -c.modp/2) c[ci+1+AN.poly_num_vars] += c.modp;
712,471✔
672
                                nc = (c[ci+1+AN.poly_num_vars]==0 ? 0 : SGN((WORD)c[ci+1+AN.poly_num_vars]));
712,471✔
673
                                c[ci+1+AN.poly_num_vars] = ABS((WORD)c[ci+1+AN.poly_num_vars]);                                                                                                        
712,471✔
674
                        }
675
                        else {
676
                                AddLong((UWORD *)&a[ai+1+AN.poly_num_vars], a[ai+a[ai]-1],
898,588✔
677
                                                                (UWORD *)&b[bi+1+AN.poly_num_vars],-b[bi+b[bi]-1], // -b[...] causes subtraction
898,588✔
678
                                                                (UWORD *)&c[ci+1+AN.poly_num_vars], &nc);
898,588✔
679
                                if (c.modp!=0) TakeNormalModulus((UWORD *)&c[ci+1+AN.poly_num_vars], &nc,
898,588✔
680
                                                                                                                                                                 modq, nmodq, NOUNPACK);
681
                        }
682

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

694
        c[0]=ci;
185,151✔
695
}
185,151✔
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) {
13,767,240✔
704

705
        WORD *old = heap[0];
13,767,240✔
706
        
707
        heap[0] = heap[--n];
13,767,240✔
708

709
        int i=0;
13,767,240✔
710
        while (2*i+2<n && (monomial_compare(BHEAD heap[2*i+1]+3, heap[i]+3)>0 ||
33,560,600✔
711
                                                                                 monomial_compare(BHEAD heap[2*i+2]+3, heap[i]+3)>0)) {
6,065,930✔
712
                
713
                if (monomial_compare(BHEAD heap[2*i+1]+3, heap[2*i+2]+3)>0) {
19,793,360✔
714
                        swap(heap[i], heap[2*i+1]);
10,502,100✔
715
                        i=2*i+1;
10,502,100✔
716
                }
717
                else {
718
                        swap(heap[i], heap[2*i+2]);
9,291,260✔
719
                        i=2*i+2;
9,291,260✔
720
                }
721
        }
722

723
        if (2*i+1<n && monomial_compare(BHEAD heap[2*i+1]+3, heap[i]+3)>0) 
13,767,240✔
724
                swap(heap[i], heap[2*i+1]);
890,931✔
725

726
        heap[n] = old;
13,767,240✔
727
}
13,767,240✔
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)  {
13,405,600✔
736

737
        int i=n-1;
13,405,600✔
738

739
        while (i>0 && monomial_compare(BHEAD heap[i]+3, heap[(i-1)/2]+3) > 0) {
17,483,800✔
740
                swap(heap[(i-1)/2], heap[i]);
4,078,200✔
741
                i=(i-1)/2;
4,078,200✔
742
        }
743
}
13,405,600✔
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) {
223,008✔
752

753
  POLY_GETIDENTITY(a);
223,008✔
754
        
755
  int ci=1;
223,008✔
756

757
        WORD nmodq=0;
223,008✔
758
        UWORD *modq=NULL;
223,008✔
759
        
760
        bool both_mod_small=false;
223,008✔
761
        
762
        if (c.modp!=0) {
223,008✔
763
                if (c.modn == 1) {
12,531✔
764
                        modq = (UWORD *)&c.modp;
3,551✔
765
                        nmodq = 1;
3,551✔
766
                        if (a.modp>0 && b.modp>0 && a.modn==1 && b.modn==1)
3,551✔
767
                                both_mod_small=true;
3,523✔
768
                }
769
                else {
770
                        RaisPowCached(BHEAD c.modp,c.modn,&modq,&nmodq);
8,980✔
771
                }
772
        }
773
        
774
  for (int ai=1; ai<a[0]; ai+=a[ai])
684,255✔
775
    for (int bi=1; bi<b[0]; bi+=b[bi]) {
1,559,177✔
776
                        
777
                        c.check_memory(ci);
1,097,930✔
778
                
779
      for (int i=0; i<AN.poly_num_vars; i++)
3,459,870✔
780
        c[ci+1+i] = a[ai+1+i] + b[bi+1+i];
2,361,940✔
781
      WORD nc;
1,097,930✔
782

783
                        // if both polynomials are modulo p^1, use integer calculus
784
                        if (both_mod_small) {
1,097,930✔
785
                                c[ci+1+AN.poly_num_vars] =
29,004✔
786
                                        ((LONG)a[ai+1+AN.poly_num_vars] * a[ai+2+AN.poly_num_vars] *
29,004✔
787
                                         b[bi+1+AN.poly_num_vars] * b[bi+2+AN.poly_num_vars]) % c.modp;
29,004✔
788
                                nc = (c[ci+1+AN.poly_num_vars]==0 ? 0 : 1);
29,004✔
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,068,926✔
793
                                                                (UWORD *)&b[bi+1+AN.poly_num_vars], b[bi+b[bi]-1],
1,068,926✔
794
                                                                (UWORD *)&c[ci+1+AN.poly_num_vars], &nc);
1,068,926✔
795
                                if (c.modp!=0) TakeNormalModulus((UWORD *)&c[ci+1+AN.poly_num_vars], &nc,
1,068,926✔
796
                                                                                                                                                                 modq, nmodq, NOUNPACK);
797
                        }
798

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

803
                                if (both_mod_small) {
1,097,930✔
804
                                        if (c[ci-2] > +c.modp/2) c[ci-2] -= c.modp;
29,004✔
805
                                        if (c[ci-2] < -c.modp/2) c[ci-2] += c.modp;
29,004✔
806
                                        c[ci-1] = SGN(c[ci-2]);
29,004✔
807
                                        c[ci-2] = ABS(c[ci-2]);
29,004✔
808
                                }
809
                                else {
810
                                        c[ci-1] = nc;
1,068,926✔
811
                                }
812
                        }
813
    }
814
        
815
  c[0]=ci;
223,008✔
816
}
223,008✔
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) {
283,862✔
826

827
        POLY_GETIDENTITY(a);
283,862✔
828

829
        WORD nmodq=0;
283,862✔
830
        UWORD *modq=NULL;
283,862✔
831

832
        bool both_mod_small=false;
283,862✔
833
        
834
        if (c.modp!=0) {
283,862✔
835
                if (c.modn == 1) {
54,159✔
836
                        modq = (UWORD *)&c.modp;
32,166✔
837
                        nmodq = 1;
32,166✔
838
                        if (a.modp>0 && b.modp>0 && a.modn==1 && b.modn==1)
32,166✔
839
                                both_mod_small=true;
32,160✔
840
                }
841
                else {
842
                        RaisPowCached(BHEAD c.modp,c.modn,&modq,&nmodq);
21,993✔
843
                }
844
        }
845
        
846
        poly t(BHEAD 0);
567,724✔
847
        WORD nt;
283,862✔
848
        
849
        int ci=1;
283,862✔
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];
283,862✔
853
        int maxpow = AN.poly_num_vars==0 ? 0 : a[2+var]+b[2+var];
283,862✔
854
        int afirst=1, blast=1;
855

856
        for (int pow=maxpow; pow>=minpow; pow--) {
4,034,360✔
857

858
                c.check_memory(ci);
3,750,494✔
859
                
860
                WORD nc=0;
3,750,494✔
861

862
                // adjust range in a or b
863
                if (a[afirst+1+var] + b[blast+1+var] > pow) {
3,750,494✔
864
                        if (blast+b[blast] < b[0])
3,058,102✔
865
                                blast+=b[blast];
3,750,494✔
866
                        else 
867
                                afirst+=a[afirst];
1,588,262✔
868
                }
869

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

877
                                // if both polynomials are modulo p^1, use integer calculus
878
                                if (both_mod_small) {
25,022,490✔
879
                                        c[ci+1+AN.poly_num_vars] =
41,450,400✔
880
                                                ((nc==0 ? 0 : (LONG)c[ci+1+AN.poly_num_vars] * nc) +
20,725,200✔
881
                                                (LONG)a[ai+1+AN.poly_num_vars] * a[ai+2+AN.poly_num_vars] *
20,725,200✔
882
                                                 b[bi+1+AN.poly_num_vars] * b[bi+2+AN.poly_num_vars]) % c.modp;
20,725,200✔
883
                                        nc = (c[ci+1+AN.poly_num_vars]==0 ? 0 : 1);
20,725,200✔
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],
4,297,270✔
889
                                                                        (UWORD *)&b[bi+1+AN.poly_num_vars], b[bi+b[bi]-1],
4,297,270✔
890
                                                                        (UWORD *)&t[0], &nt);
4,297,270✔
891
                                        
892
                                        AddLong ((UWORD *)&t[0], nt,
4,297,270✔
893
                                                                         (UWORD *)&c[ci+1+AN.poly_num_vars], nc,
4,297,270✔
894
                                                                         (UWORD *)&c[ci+1+AN.poly_num_vars], &nc);
4,297,270✔
895

896
                                        if (c.modp!=0) TakeNormalModulus((UWORD *)&c[ci+1+AN.poly_num_vars], &nc,
4,297,270✔
897
                                                                                                                                                                         modq, nmodq, NOUNPACK);
898
                                }
899
                                
900
                                ai += a[ai];
25,022,490✔
901
                                bi -= ABS(b[bi-1]) + 2 + AN.poly_num_vars;
25,022,490✔
902
                        }
903
                        else if (thispow > pow) 
5,443,300✔
904
                                ai += a[ai];
3,161,118✔
905
                        else 
906
                                bi -= ABS(b[bi-1]) + 2 + AN.poly_num_vars;
2,282,180✔
907
                }
908

909
                // add term to result
910
                if (nc != 0) {
3,750,494✔
911
                        for (int j=0; j<AN.poly_num_vars; j++)
9,643,790✔
912
                                c[ci+1+j] = 0;
6,214,610✔
913
                        if (AN.poly_num_vars > 0)
3,429,167✔
914
                                c[ci+1+var] = pow;
3,429,167✔
915
                        
916
                        c[ci] =        2+AN.poly_num_vars+ABS(nc);
3,429,167✔
917
                        ci += c[ci];
3,429,167✔
918

919
                        // if necessary, adjust to range [-p/2,p/2]
920
                        if (both_mod_small) {
3,429,167✔
921
                                if (c[ci-2] > +c.modp/2) c[ci-2] -= c.modp;
1,488,419✔
922
                                if (c[ci-2] < -c.modp/2) c[ci-2] += c.modp;
1,488,419✔
923
                                c[ci-1] = SGN(c[ci-2]);
1,488,419✔
924
                                c[ci-2] = ABS(c[ci-2]);
1,488,419✔
925
                        }
926
                        else {
927
                                c[ci-1] = nc;
1,940,748✔
928
                        }
929
                }
930
        }
931

932
        c[0] = ci;
283,862✔
933
}
283,862✔
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) {
41,943✔
958

959
        POLY_GETIDENTITY(a);
41,943✔
960

961
        WORD nmodq=0;
41,943✔
962
        UWORD *modq=NULL;
41,943✔
963
        
964
        bool both_mod_small=false;
41,943✔
965
        
966
        if (c.modp!=0) {
41,943✔
967
                if (c.modn == 1) {
37,433✔
968
                        modq = (UWORD *)&c.modp;
18,820✔
969
                        nmodq = 1;
18,820✔
970
                        if (a.modp>0 && b.modp>0 && a.modn==1 && b.modn==1)
18,820✔
971
                                both_mod_small=true;
18,820✔
972
                }
973
                else {
974
                        RaisPowCached(BHEAD c.modp,c.modn,&modq,&nmodq);
18,613✔
975
                }
976
        }
977

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

986
        for (int i=0; i<AN.poly_num_vars; i++)
129,994✔
987
                maxpowera[i] = maxpowerb[i] = 0;
88,051✔
988

989
        for (int ai=1; ai<a[0]; ai+=a[ai])
320,444✔
990
                for (int j=0; j<AN.poly_num_vars; j++)
848,062✔
991
                        maxpowera[j] = MaX(maxpowera[j], a[ai+1+j]);
569,561✔
992

993
        for (int bi=1; bi<b[0]; bi+=b[bi])
868,670✔
994
                for (int j=0; j<AN.poly_num_vars; j++)
2,497,088✔
995
                        maxpowerb[j] = MaX(maxpowerb[j], b[bi+1+j]);
1,670,361✔
996

997
        for (int i=0; i<AN.poly_num_vars; i++)
129,994✔
998
                maxpower[i] = maxpowera[i] + maxpowerb[i];
88,051✔
999

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

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

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

1016
        WantAddPointers(nheap+nhash);
42,145✔
1017
        WORD **heap = AT.pWorkSpace + AT.pWorkPointer;
41,943✔
1018

1019
        for (int ai=1, i=0; ai<a[0]; ai+=a[ai], i++) {
320,444✔
1020
                heap[i] = (WORD *) NumberMalloc("poly::mul_heap");
278,501✔
1021
                heap[i][0] = ai;
278,501✔
1022
                heap[i][1] = 1;
278,501✔
1023
                heap[i][2] = -1;
278,501✔
1024
                heap[i][3] = 0;
278,501✔
1025
                for (int j=0; j<AN.poly_num_vars; j++)
848,062✔
1026
                        heap[i][4+j] = MAXPOSITIVE;
569,561✔
1027
        }
1028
        
1029
        WORD **hash = AT.pWorkSpace + AT.pWorkPointer + nheap;
41,943✔
1030
        for (int i=0; i<nhash; i++)
3,806,934✔
1031
                hash[i] = NULL;
3,764,991✔
1032

1033
        int ci = 1;
1034

1035
        // multiply
1036
        while (nheap > 0) {
2,103,227✔
1037

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

1043
                // if non-zero
1044
                if (p[3] != 0) {
2,061,284✔
1045
                        if (use_hash) hash[p[2]] = NULL;
1,587,919✔
1046

1047
                        c[0] = ci;
1,587,919✔
1048

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

1061
                                // if both polynomials are modulo p^1, use integer calculus
1062
                                if (both_mod_small) {
×
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],
×
1076
                                                                         (UWORD *)&c[ci+AN.poly_num_vars+1], nc,
×
1077
                                                                         (UWORD *)&c[ci+AN.poly_num_vars+1],&nc);
×
1078
                                        
1079
                                        if (c.modp!=0) TakeNormalModulus((UWORD *)&c[ci+1+AN.poly_num_vars], &nc,
×
1080
                                                                                                                                                                         modq, nmodq, NOUNPACK);
1081
                                }
1082
                                
1083
                                if (nc!=0) {
×
1084
                                        c[ci] = 2 + AN.poly_num_vars + ABS(nc);
×
1085
                                        ci += c[ci];
×
1086
                                        c[ci-1] = nc;
×
1087
                                }
1088
                        }
1089
                }
1090

1091
                // add new term to the heap (ai, bi+1)
1092
                while (p[1] < b[0]) {
8,573,670✔
1093
                        
1094
                        for (int j=0; j<AN.poly_num_vars; j++)
25,084,890✔
1095
                                p[4+j] = a[p[0]+1+j] + b[p[1]+1+j];
16,789,710✔
1096

1097
                        // if both polynomials are modulo p^1, use integer calculus
1098
                        if (both_mod_small) {
8,295,170✔
1099
                                p[4+AN.poly_num_vars] = ((LONG)a[p[0]+1+AN.poly_num_vars]*a[p[0]+a[p[0]]-1]*
6,443,000✔
1100
                                                                                                                                 b[p[1]+1+AN.poly_num_vars]*b[p[1]+b[p[1]]-1]) % c.modp;
6,443,000✔
1101
                                if (p[4+AN.poly_num_vars]==0)
6,443,000✔
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;
6,443,000✔
1105
                                        if (p[4+AN.poly_num_vars] < -c.modp/2) p[4+AN.poly_num_vars] += c.modp;
6,443,000✔
1106
                                        p[3] = SGN(p[4+AN.poly_num_vars]);
6,443,000✔
1107
                                        p[4+AN.poly_num_vars] = ABS(p[4+AN.poly_num_vars]);
6,443,000✔
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,852,160✔
1113
                                                                (UWORD *)&b[p[1]+1+AN.poly_num_vars], b[p[1]+b[p[1]]-1],
1,852,160✔
1114
                                                                (UWORD *)&p[4+AN.poly_num_vars], &p[3]);
1,852,160✔
1115
                                
1116
                                if (c.modp!=0) TakeNormalModulus((UWORD *)&p[4+AN.poly_num_vars], &p[3],
1,852,160✔
1117
                                                                                                                                                                 modq, nmodq, NOUNPACK);                                
1118
                        }
1119
                        
1120
                        p[1] += b[p[1]];
8,295,170✔
1121

1122
                        if (use_hash) {
8,295,170✔
1123
                                int ID = 0;
1124
                                for (int i=0; i<AN.poly_num_vars; i++)
25,084,890✔
1125
                                        ID = (maxpower[i]+1)*ID + p[4+i];
16,789,710✔
1126

1127
                                // if hash and unused, push onto heap
1128
                                if (hash[ID] == NULL) {
8,295,170✔
1129
                                        p[2] = ID;
1,782,783✔
1130
                                        hash[ID] = p;
1,782,783✔
1131
                                        push_heap(BHEAD heap, ++nheap);
1,782,783✔
1132
                                        break;
1,782,783✔
1133
                                }
1134
                                else {
1135
                                        // if hash and used, add to heap element
1136
                                        WORD *h = hash[ID];
6,512,380✔
1137
                                        // if both polynomials are modulo p^1, use integer calculus
1138
                                        if (both_mod_small) {
6,512,380✔
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;
5,372,410✔
1140
                                                if (h[4+AN.poly_num_vars]==0) 
5,372,410✔
1141
                                                        h[3]=0;
383,156✔
1142
                                                else {
1143
                                                        if (h[4+AN.poly_num_vars] > +c.modp/2) h[4+AN.poly_num_vars] -= c.modp;
4,989,250✔
1144
                                                        if (h[4+AN.poly_num_vars] < -c.modp/2) h[4+AN.poly_num_vars] += c.modp;
4,989,250✔
1145
                                                        h[3] = SGN(h[4+AN.poly_num_vars]);
4,989,250✔
1146
                                                        h[4+AN.poly_num_vars] = ABS(h[4+AN.poly_num_vars]);
4,989,250✔
1147
                                                }
1148
                                        }
1149
                                        else {
1150
                                                // otherwise, use form long calculus
1151
                                                AddLong ((UWORD *)&p[4+AN.poly_num_vars],  p[3],
1,139,969✔
1152
                                                                                 (UWORD *)&h[4+AN.poly_num_vars],  h[3],
1153
                                                                                 (UWORD *)&h[4+AN.poly_num_vars], &h[3]);
1,139,969✔
1154

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

1169
        c[0] = ci;
41,943✔
1170
        
1171
        for (int ai=1, i=0; ai<a[0]; ai+=a[ai], i++)
320,444✔
1172
                NumberFree(heap[i],"poly::mul_heap");
278,501✔
1173
        AT.WorkPointer -= 3 * AN.poly_num_vars;
41,943✔
1174
}
41,943✔
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) {
1,253,229✔
1192

1193
  c.modp = a.modp;
1,253,229✔
1194
  c.modn = a.modn;
1,253,229✔
1195
        
1196
        if (a.is_zero() || b.is_zero()) { c[0]=1; return; }
1,253,229✔
1197
        if (a.is_one()) {
1,245,236✔
1198
                c.check_memory(b[0]);
573,210✔
1199
                c.termscopy(b.terms,0,b[0]);
573,210✔
1200
                // normalize if necessary
1201
                if (a.modp!=b.modp || a.modn!=b.modn) {
573,210✔
1202
                        c.modp=0;
507✔
1203
                        c.setmod(a.modp,a.modn);
507✔
1204
                }
1205
                return;
573,210✔
1206
        }
1207
        if (b.is_one()) {
672,026✔
1208
                c.check_memory(a[0]);
123,213✔
1209
                c.termscopy(a.terms,0,a[0]);                
123,213✔
1210
                return;
123,213✔
1211
        }
1212

1213
        int na=a.number_of_terms();
548,813✔
1214
        int nb=b.number_of_terms();
548,813✔
1215

1216
        if (na==1 || nb==1) {
548,813✔
1217
                mul_one_term(a,b,c);
223,008✔
1218
                return;
223,008✔
1219
        }
1220

1221
        int vara = a.is_dense_univariate();
325,805✔
1222
        int varb = b.is_dense_univariate();
325,805✔
1223

1224
        if (vara!=-2 && varb!=-2 && vara==varb) {
325,805✔
1225
                mul_univar(a,b,c,vara);
283,862✔
1226
                return;
283,862✔
1227
        }
1228

1229
        if (na < nb)
41,943✔
1230
                mul_heap(a,b,c);
16,550✔
1231
        else
1232
                mul_heap(b,a,c);
25,393✔
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) {
210,893✔
1242

1243
        POLY_GETIDENTITY(a);
210,893✔
1244

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

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

1268
                if (both_mod_small) {
5,162✔
1269
                        WORD ltb = b[b[1]]*b[2+AN.poly_num_vars];
5,108✔
1270
                        GetModInverses(ltb + (ltb<0?q.modp:0), q.modp, (WORD*)ltbinv, NULL);
8,044✔
1271
                        nltbinv = 1;
5,108✔
1272
                }
1273
                else
1274
                        GetLongModInverses(BHEAD (UWORD *)&b[2+AN.poly_num_vars], b[b[1]], modq, nmodq, ltbinv, &nltbinv, NULL, NULL);
54✔
1275
        }
1276
        
1277
        for (int ai=1; ai<a[0]; ai+=a[ai]) {
1,522,370✔
1278

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

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

1326
                // add terms to quotient/remainder
1327
                if (nq!=0) {
1,311,488✔
1328
                        q[qi] = 2+AN.poly_num_vars+ABS(nq);
1,310,371✔
1329
                        qi += q[qi];
1,310,371✔
1330
                        
1331
                        // if necessary, adjust to range [-p/2,p/2]
1332
                        if (both_mod_small) {
1,310,371✔
1333
                                if (q[qi-2] > +q.modp/2) q[qi-2] -= q.modp;
32,525✔
1334
                                if (q[qi-2] < -q.modp/2) q[qi-2] += q.modp;
32,525✔
1335
                                q[qi-1] = SGN(q[qi-2]);
32,525✔
1336
                                q[qi-2] = ABS(q[qi-2]);
32,525✔
1337
                        }
1338
                        else {
1339
                                q[qi-1] = nq;
1,277,846✔
1340
                        }
1341
                }
1342
                
1343
                if (nr != 0) {
1,311,488✔
1344
                        if (only_divides) { r = poly(BHEAD 1); ri=r[0]; break; }
2,851✔
1345
                        r[ri] = 2+AN.poly_num_vars+ABS(nr);
2,840✔
1346
                        ri += r[ri];
2,840✔
1347
                        r[ri-1] = nr;
2,840✔
1348
                }                
1349
        }
1350

1351
        q[0]=qi;
210,893✔
1352
        r[0]=ri;
210,893✔
1353
        
1354
        if (q.modp!=0 || ltbinv != NULL) NumberFree(ltbinv,"poly::div_one_term");
210,893✔
1355
}        
210,893✔
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) {
223,387✔
1373

1374
        POLY_GETIDENTITY(a);
223,387✔
1375
        
1376
        WORD nmodq=0;
223,387✔
1377
        UWORD *modq=NULL;
223,387✔
1378
        
1379
        WORD nltbinv=0;
223,387✔
1380
        UWORD *ltbinv=NULL;
223,387✔
1381
        
1382
        bool both_mod_small=false;
223,387✔
1383
        
1384
        if (q.modp!=0) {
223,387✔
1385
                if (q.modn == 1) {
21,560✔
1386
                        modq = (UWORD *)&q.modp;
20,114✔
1387
                        nmodq = 1;
20,114✔
1388
                        if (a.modp>0 && b.modp>0 && a.modn==1 && b.modn==1)
20,114✔
1389
                                both_mod_small=true;
17,575✔
1390
                }
1391
                else {
1392
                        RaisPowCached(BHEAD q.modp,q.modn,&modq,&nmodq);
1,446✔
1393
                }
1394
                ltbinv = NumberMalloc("poly::div_univar");
21,560✔
1395

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

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

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

1417
                q.check_memory(qi);
2,388,645✔
1418
                r.check_memory(ri);
2,388,645✔
1419
                
1420
                // look for the correct power in a
1421
                while (ai<a[0] && a[ai+1+var] > pow)
4,417,960✔
1422
                        ai+=a[ai];
2,029,319✔
1423

1424
                // first term of the r.h.s. of the above equation
1425
                if (ai<a[0] && a[ai+1+var] == pow) {
2,388,645✔
1426
                        ns = a[ai+a[ai]-1];
2,244,387✔
1427
                        WCOPY(s, &a[ai+1+AN.poly_num_vars], ABS(ns));
5,575,170✔
1428
                }
1429
                else {
1430
                        ns = 0;
144,258✔
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]) {
20,697,880✔
1437
                        
1438
                        qj -= 2 + AN.poly_num_vars + ABS(q[qj-1]);
18,309,230✔
1439
                        
1440
                        while (bi<b[0] && b[bi+1+var]+q[qj+1+var] > pow)
47,464,200✔
1441
                                bi += b[bi];
29,154,890✔
1442
                        
1443
                        if (bi<b[0] && b[bi+1+var]+q[qj+1+var] == pow) {
18,309,230✔
1444
                                // if both polynomials are modulo p^1, use integer calculus
1445

1446
                                if (both_mod_small) {
13,626,710✔
1447
                                        s[0] = ((WORD)s[0]*ns - (LONG)b[bi+1+AN.poly_num_vars] * b[bi+b[bi]-1] *
11,845,940✔
1448
                                                                        q[qj+1+AN.poly_num_vars] * q[qj+q[qj]-1]) % q.modp;
11,845,940✔
1449
                                        ns = (s[0]==0 ? 0 : 1);
11,845,940✔
1450
                                }
1451
                                else {
1452
                                        // otherwise, use form long calculus
1453
                                        MulLong((UWORD *)&b[bi+1+AN.poly_num_vars], b[bi+b[bi]-1],
1,780,770✔
1454
                                                                        (UWORD *)&q[qj+1+AN.poly_num_vars], q[qj+q[qj]-1],
1,780,770✔
1455
                                                                        t, &nt);
1456
                                        nt *= -1;
1,780,770✔
1457
                                        AddLong(t,nt,s,ns,s,&ns);
1,780,770✔
1458
                                        if (q.modp!=0) TakeNormalModulus((UWORD *)s,&ns,modq, nmodq, NOUNPACK);
1,780,770✔
1459
                                }
1460
                        }
1461
                }
1462

1463
                if (ns != 0) {
2,388,645✔
1464
                        // if necessary, adjust to range [-p/2,p/2]
1465
                        if (both_mod_small) {
1,818,813✔
1466
                                s[0]*=ns;
576,332✔
1467
                                if ((WORD)s[0] > +q.modp/2) s[0] -= q.modp;
576,332✔
1468
                                if ((WORD)s[0] < -q.modp/2) s[0] += q.modp;
576,332✔
1469
                                ns = SGN((WORD)s[0]);
576,332✔
1470
                                s[0] = ABS((WORD)s[0]);
576,332✔
1471
                        }
1472

1473
                        if (pow >= bpow) {
1,818,813✔
1474
                                // large power, so divide by b
1475
                                if (q.modp == 0) {
1,386,913✔
1476
                                        DivLong(s, ns,
907,268✔
1477
                                                                        (UWORD *)&b[2+AN.poly_num_vars],  b[b[1]],
907,268✔
1478
                                                                        (UWORD *)&q[qi+1+AN.poly_num_vars], &ns, t, &nt);
907,268✔
1479
                                }
1480
                                else {
1481
                                        if (both_mod_small) {
479,645✔
1482
                                                q[qi+1+AN.poly_num_vars] = ((LONG)s[0]*ns*ltbinv[0]*nltbinv) % q.modp;
321,333✔
1483
                                                if ((WORD)q[qi+1+AN.poly_num_vars] > +q.modp/2) q[qi+1+AN.poly_num_vars] -= q.modp;
321,333✔
1484
                                                if ((WORD)q[qi+1+AN.poly_num_vars] < -q.modp/2) q[qi+1+AN.poly_num_vars] += q.modp;
321,333✔
1485
                                                ns = (q[qi+1+AN.poly_num_vars]==0 ? 0 : SGN((WORD)q[qi+1+AN.poly_num_vars]));
321,333✔
1486
                                                q[qi+1+AN.poly_num_vars] = ABS((WORD)q[qi+1+AN.poly_num_vars]);                                                                        
321,333✔
1487
                                        }
1488
                                        else {
1489
                                                MulLong(s, ns, ltbinv, nltbinv,        (UWORD *)&q[qi+1+AN.poly_num_vars], &ns);
158,312✔
1490
                                                TakeNormalModulus((UWORD *)&q[qi+1+AN.poly_num_vars], &ns,
158,312✔
1491
                                                                                                                        modq,nmodq, NOUNPACK);
1492
                                        }
1493
                                        nt=0;
479,645✔
1494
                                }                                        
1495
                        }
1496
                        else {
1497
                                // small power, so remainder
1498
                                WCOPY(t,s,ABS(ns));
2,070,549✔
1499
                                nt = ns;
431,900✔
1500
                                ns = 0;
431,900✔
1501
                        }
1502

1503
                        // add terms to quotient/remainder
1504
                        if (ns!=0) {
1,818,813✔
1505
                                for (int i=0; i<AN.poly_num_vars; i++)
3,338,979✔
1506
                                        q[qi+1+i] = 0;
1,952,068✔
1507
                                q[qi+1+var] = pow-bpow;
1,386,911✔
1508
                                
1509
                                q[qi] = 2+AN.poly_num_vars+ABS(ns);
1,386,911✔
1510
                                qi += q[qi];
1,386,911✔
1511
                                q[qi-1] = ns;
1,386,911✔
1512
                        }
1513
                        
1514
                        if (nt != 0) {
1,818,813✔
1515
                                if (only_divides) { r=poly(BHEAD 1); ri=r[0]; break; }
431,934✔
1516
                                for (int i=0; i<AN.poly_num_vars; i++)
1,187,375✔
1517
                                        r[ri+1+i] = 0;
755,441✔
1518
                                r[ri+1+var] = pow;
431,934✔
1519

1520
                                for (int i=0; i<ABS(nt); i++)
2,070,617✔
1521
                                        r[ri+1+AN.poly_num_vars+i] = t[i];
1,638,683✔
1522
                                
1523
                                r[ri] = 2+AN.poly_num_vars+ABS(nt);
431,934✔
1524
                                ri += r[ri];
431,934✔
1525
                                r[ri-1] = nt;
431,934✔
1526
                        }
1527
                }
1528
        }
1529

1530
        q[0] = qi;
223,387✔
1531
        r[0] = ri;
223,387✔
1532

1533
        NumberFree(s,"poly::div_univar");
223,387✔
1534
        NumberFree(t,"poly::div_univar");
223,387✔
1535

1536
        if (q.modp!=0 || ltbinv!=NULL) NumberFree(ltbinv,"poly::div_univar");
223,387✔
1537
}
223,387✔
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) {
83,210✔
1576

1577
        POLY_GETIDENTITY(a);
83,210✔
1578

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

1603
                if (both_mod_small) {
29,851✔
1604
                        WORD ltb = b[b[1]]*b[2+AN.poly_num_vars];
28,368✔
1605
                        GetModInverses(ltb + (ltb<0?q.modp:0), q.modp, (WORD*)ltbinv, NULL);
28,432✔
1606
                        nltbinv = 1;
28,368✔
1607
                }
1608
                else
1609
                        GetLongModInverses(BHEAD (UWORD *)&b[2+AN.poly_num_vars], b[b[1]], modq, nmodq, ltbinv, &nltbinv, NULL, NULL);
1,483✔
1610
        }
1611
        
1612
        // allocate heap
1613
        int nb=b.number_of_terms();
83,210✔
1614
        WantAddPointers(nb);
83,210✔
1615
        WORD **heap = AT.pWorkSpace + AT.pWorkPointer;
83,210✔
1616
        AT.pWorkPointer += nb;
83,210✔
1617
        
1618
        for (int i=0; i<nb; i++) 
654,128✔
1619
                heap[i] = (WORD *) NumberMalloc("poly::div_heap-b");
570,918✔
1620
        int nheap = 1;
83,210✔
1621
        heap[0][0] = 1;
83,210✔
1622
        heap[0][1] = 0;
83,210✔
1623
        heap[0][2] = -1;
83,210✔
1624
        WCOPY(&heap[0][3], &a[1], a[1]);
636,427✔
1625
        heap[0][3] = a[a[1]];
83,210✔
1626
        
1627
        int qi=1, ri=1;
83,210✔
1628

1629
        int s = nb;
83,210✔
1630
        WORD *t = (WORD *) NumberMalloc("poly::div_heap-c");
83,210✔
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;
83,210✔
1635
        
1636
        while (insert.size()>0 || nheap>0) {
3,649,532✔
1637

1638
                q.check_memory(qi);
3,566,359✔
1639
                r.check_memory(ri);
3,566,359✔
1640
                
1641
                // collect a term t for the quotient/remainder
1642
                t[0] = -1;
3,566,359✔
1643
                
1644
                do {
12,558,560✔
1645

1646
                        WORD *p = heap[nheap];
12,558,560✔
1647
                        bool this_insert;
12,558,560✔
1648
                 
1649
                        if (insert.empty()) {
12,558,560✔
1650
                                // extract element from the heap and prepare adding new ones
1651
                                this_insert = false;
11,705,970✔
1652

1653
                                pop_heap(BHEAD heap, nheap--);
11,705,970✔
1654
                                p = heap[nheap];
11,705,970✔
1655
                                
1656
                                if (t[0] == -1) {
11,705,970✔
1657
                                        WCOPY(t, p, (5+ABS(p[3])+AN.poly_num_vars));
56,567,000✔
1658
                                }                                
1659
                                else {
1660
                                        // if both polynomials are modulo p^1, use integer calculus
1661
                                        if (both_mod_small) {
8,139,610✔
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;
7,510,200✔
1663
                                                if (t[4+AN.poly_num_vars]==0)
7,510,200✔
1664
                                                        t[3]=0;
757,648✔
1665
                                                else {
1666
                                                        if (t[4+AN.poly_num_vars] > +q.modp/2) t[4+AN.poly_num_vars] -= q.modp;
6,752,560✔
1667
                                                        if (t[4+AN.poly_num_vars] < -q.modp/2) t[4+AN.poly_num_vars] += q.modp;
6,752,560✔
1668
                                                        t[3] = SGN(t[4+AN.poly_num_vars]);
6,752,560✔
1669
                                                        t[4+AN.poly_num_vars] = ABS(t[4+AN.poly_num_vars]);
6,752,560✔
1670
                                                }
1671
                                        }
1672
                                        else {
1673
                                                // otherwise, use form long calculus
1674
                                                AddLong ((UWORD *)&p[4+AN.poly_num_vars],  p[3],
629,392✔
1675
                                                                                 (UWORD *)&t[4+AN.poly_num_vars],  t[3],
1676
                                                                                 (UWORD *)&t[4+AN.poly_num_vars], &t[3]);
629,392✔
1677
                                                if (q.modp!=0) TakeNormalModulus((UWORD *)&t[4+AN.poly_num_vars], &t[3],
629,392✔
1678
                                                                                                                                                                                 modq, nmodq, NOUNPACK);
1679
                                        }
1680
                                }
1681
                        }
1682
                        else {
1683
                                // prepare adding an element of insert to the heap
1684
                                this_insert = true;
852,602✔
1685

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

1691
                        // add elements to the heap
1692
                        while (true) {
12,558,560✔
1693
                                // prepare the element
1694
                                if (p[1]==0) {
12,558,560✔
1695
                                        p[0] += a[p[0]];
1,773,228✔
1696
                                        if (p[0]==a[0]) break;
1,773,228✔
1697
                                        WCOPY(&p[3], &a[p[0]], a[p[0]]);
11,941,890✔
1698
                                        p[3] = p[2+p[3]];
1,690,055✔
1699
                                }                        
1700
                                else {
1701
                                        if (!this_insert)
10,785,340✔
1702
                                                p[1] += q[p[1]];
9,932,740✔
1703
                                        this_insert = false;
10,785,340✔
1704
                                        
1705
                                        if (p[1]==qi) {        s++; break; }
10,785,340✔
1706

1707
                                        for (int i=0; i<AN.poly_num_vars; i++)
33,345,750✔
1708
                                                p[4+i] = b[p[0]+1+i] + q[p[1]+1+i];
23,413,000✔
1709
                                        
1710
                                        // if both polynomials are modulo p^1, use integer calculus
1711
                                        if (both_mod_small) {
9,932,760✔
1712
                                                p[4+AN.poly_num_vars] = ((LONG)b[p[0]+1+AN.poly_num_vars]*b[p[0]+b[p[0]]-1]*
7,672,320✔
1713
                                                                                                                                                 q[p[1]+1+AN.poly_num_vars]*q[p[1]+q[p[1]]-1]) % q.modp;
7,672,320✔
1714
                                                if (p[4+AN.poly_num_vars]==0)
7,672,320✔
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;
7,672,320✔
1718
                                                        if (p[4+AN.poly_num_vars] < -q.modp/2) p[4+AN.poly_num_vars] += q.modp;
7,672,320✔
1719
                                                        p[3] = SGN(p[4+AN.poly_num_vars]);
7,672,320✔
1720
                                                        p[4+AN.poly_num_vars] = ABS(p[4+AN.poly_num_vars]);
7,672,320✔
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],
2,260,439✔
1726
                                                                                (UWORD *)&q[p[1]+1+AN.poly_num_vars], q[p[1]+q[p[1]]-1],
2,260,439✔
1727
                                                                                (UWORD *)&p[4+AN.poly_num_vars], &p[3]);
2,260,439✔
1728
                                                if (q.modp!=0) TakeNormalModulus((UWORD *)&p[4+AN.poly_num_vars], &p[3],
2,260,439✔
1729
                                                                                                                                                                                 modq, nmodq, NOUNPACK);
1730
                                        }
1731
                                        
1732
                                        p[3] *= -1;
9,932,760✔
1733
                                }
1734

1735
                                // no hashing
1736
                                p[2] = -1;
11,622,820✔
1737

1738
                                // add it to a heap element
1739
                                swap (heap[nheap],p);
11,622,820✔
1740
                                push_heap(BHEAD heap, ++nheap);
11,622,820✔
1741
                                break;
11,622,820✔
1742
                        }
1743
                }
1744
                while (t[0]==-1 || (nheap>0 && monomial_compare(BHEAD heap[0]+3, t+3)==0));
12,558,560✔
1745

1746
                if (t[3] == 0) continue;
3,566,359✔
1747
                
1748
                // check divisibility 
1749
                bool div = true;
1750
                for (int i=0; i<AN.poly_num_vars; i++)
13,328,910✔
1751
                        if (t[4+i] < b[2+i]) div=false;
10,357,230✔
1752
                
1753
                if (!div) {
2,971,688✔
1754
                        // not divisible, so append it to the remainder
1755
                        if (only_divides) { r=poly(BHEAD 1); ri=r[0]; break; }
716,561✔
1756
                        t[4 + AN.poly_num_vars + ABS(t[3])] = t[3];
716,556✔
1757
                        t[3] = 2 + AN.poly_num_vars + ABS(t[3]);
716,556✔
1758
                        r.termscopy(&t[3], ri, t[3]);
716,556✔
1759
                        ri += t[3];
716,556✔
1760
                }
1761
                else {
1762
                        // divisible, so divide coefficient as well
1763
                        WORD nq, nr;
2,255,127✔
1764
        
1765
                        if (q.modp==0) {
2,255,127✔
1766
                                DivLong((UWORD *)&t[4+AN.poly_num_vars], t[3],
1,692,425✔
1767
                                                                (UWORD *)&b[2+AN.poly_num_vars], b[b[1]],
1,692,425✔
1768
                                                                (UWORD *)&q[qi+1+AN.poly_num_vars], &nq,
1,692,425✔
1769
                                                                (UWORD *)&r[ri+1+AN.poly_num_vars], &nr);
1,692,425✔
1770
                                if(check_div && nr != 0)
1,692,425✔
1771
                                {
1772
                                        // non-zero remainder from coefficient division => result not expressible in integers
1773
                                        div_fail = true;
32✔
1774
                                        break;
32✔
1775
                                }
1776
                        }
1777
                        else {
1778
                                // if both polynomials are modulo p^1, use integer calculus
1779
                                if (both_mod_small) {
562,702✔
1780
                                        q[qi+1+AN.poly_num_vars] = ((LONG)t[4+AN.poly_num_vars]*t[3]*ltbinv[0]*nltbinv) % q.modp;
482,664✔
1781
                                        if (q[qi+1+AN.poly_num_vars]==0)
482,664✔
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;
482,664✔
1785
                                                if (q[qi+1+AN.poly_num_vars] < -q.modp/2) q[qi+1+AN.poly_num_vars] += q.modp;
482,664✔
1786
                                                nq = SGN(q[qi+1+AN.poly_num_vars]);
482,664✔
1787
                                                q[qi+1+AN.poly_num_vars] = ABS(q[qi+1+AN.poly_num_vars]);
482,664✔
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);
80,038✔
1793
                                        TakeNormalModulus((UWORD *)&q[qi+1+AN.poly_num_vars], &nq, modq, nmodq, NOUNPACK);
80,038✔
1794
                                }
1795
                                
1796
                                nr=0;
562,702✔
1797
                        }
1798

1799
                        // add terms to quotient and remainder
1800
                        if (nq != 0) {
2,255,095✔
1801
                                int bi = 1;
1802
                                for (int j=1; j<s; j++) {
3,106,876✔
1803
                                        bi += b[bi];
852,602✔
1804
                                        insert.push_back(make_pair(bi,qi));
852,602✔
1805
                                }
1806
                                s=1;
2,254,274✔
1807
                                
1808
                                q[qi] = 2+AN.poly_num_vars+ABS(nq);
2,254,274✔
1809
                                for (int i=0; i<AN.poly_num_vars; i++)
10,213,330✔
1810
                                        q[qi+1+i] = t[4+i] - b[2+i];
7,959,040✔
1811
                                qi += q[qi];
2,254,274✔
1812
                                q[qi-1] = nq;
2,254,274✔
1813
                        }
1814

1815
                        if (nr != 0) {
2,255,095✔
1816
                                r[ri] = 2+AN.poly_num_vars+ABS(nr);
1,928✔
1817
                                for (int i=0; i<AN.poly_num_vars; i++)
9,606✔
1818
                                        r[ri+1+i] = t[4+i];
7,678✔
1819
                                ri += r[ri];
1,928✔
1820
                                r[ri-1] = nr;
1,928✔
1821
                        }
1822
                }
1823
        }
1824

1825
        q[0] = qi;
83,210✔
1826
        r[0] = ri;
83,210✔
1827

1828
        for (int i=0; i<nb; i++)
654,128✔
1829
                NumberFree(heap[i],"poly::div_heap-b");
570,918✔
1830

1831
        NumberFree(t,"poly::div_heap-c");
83,210✔
1832

1833
        if (q.modp!=0||ltbinv!=NULL) NumberFree(ltbinv,"poly::div_heap-a");
83,210✔
1834
        AT.pWorkPointer = oldpWorkPointer;
83,210✔
1835
}
83,210✔
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) {
1,502,206✔
1853

1854
        q.modp = r.modp = a.modp;
1,502,206✔
1855
        q.modn = r.modn = a.modn;
1,502,206✔
1856
        
1857
        if (a.is_zero()) {
1,502,206✔
1858
                q[0]=1;
101,625✔
1859
                r[0]=1;
101,625✔
1860
                return;
101,625✔
1861
        }
1862
        if (b.is_zero()) {
1,400,581✔
1863
                MLOCK(ErrorMessageLock);
×
1864
                MesPrint ((char*)"ERROR: division by zero polynomial");
×
1865
                MUNLOCK(ErrorMessageLock);
×
NEW
1866
                TERMINATE(1);
×
1867
        }
1868
        if (b.is_one()) {
1,400,581✔
1869
                q.check_memory(a[0]);
883,139✔
1870
                q.termscopy(a.terms,0,a[0]);
883,139✔
1871
                r[0]=1;
883,139✔
1872
                return;
883,139✔
1873
        }
1874
        
1875
        if (b.is_monomial()) {
517,442✔
1876
                divmod_one_term(a,b,q,r,only_divides);
210,893✔
1877
                return;
210,893✔
1878
        }
1879

1880
        int vara = a.is_dense_univariate();
306,549✔
1881
        int varb = b.is_dense_univariate();
306,549✔
1882

1883
        if (vara!=-2 && varb!=-2 && (vara==-1 || varb==-1 || vara==varb)) {
306,549✔
1884
                divmod_univar(a,b,q,r,MaX(vara,varb),only_divides);
446,774✔
1885
        }
1886
        else {
1887
                bool div_fail;
83,162✔
1888
                divmod_heap(a,b,q,r,only_divides,false,div_fail);
83,162✔
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) {
418✔
1899
        POLY_GETIDENTITY(a);
418✔
1900
        poly q(BHEAD 0), r(BHEAD 0);
836✔
1901
        divmod(b,a,q,r,true);
418✔
1902
        return r.is_zero();
836✔
1903
}
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) {
1,076,602✔
1912
        POLY_GETIDENTITY(a);
1,076,602✔
1913
        poly d(BHEAD 0);
2,153,204✔
1914
        divmod(a,b,c,d,false);
1,076,602✔
1915
}
1,076,602✔
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) {
425,186✔
1924
        POLY_GETIDENTITY(a);
425,186✔
1925
        poly d(BHEAD 0);
850,372✔
1926
        divmod(a,b,d,c,false);
425,186✔
1927
}
425,186✔
1928

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

1934
// copy operator
1935
poly & poly::operator= (const poly &a) {
4,496,480✔
1936

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

1944
        return *this;
4,496,480✔
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; }
181,435✔
1954
const poly poly::operator- (const poly &a) const { POLY_GETIDENTITY(a); poly b(BHEAD 0); sub(*this,a,b); return b; }
185,151✔
1955
const poly poly::operator* (const poly &a) const { POLY_GETIDENTITY(a); poly b(BHEAD 0); mul(*this,a,b); return b; }
1,253,229✔
1956
const poly poly::operator/ (const poly &a) const { POLY_GETIDENTITY(a); poly b(BHEAD 0); div(*this,a,b); return b; }
1,076,602✔
1957
const poly poly::operator% (const poly &a) const { POLY_GETIDENTITY(a); poly b(BHEAD 0); mod(*this,a,b); return b; }
425,186✔
1958

1959
// assignment operators for polynomial arithmetic
1960
poly& poly::operator+= (const poly &a) { return *this = *this + a; }
48,198✔
1961
poly& poly::operator-= (const poly &a) { return *this = *this - a; }
35,486✔
1962
poly& poly::operator*= (const poly &a) { return *this = *this * a; }
716,640✔
1963
poly& poly::operator/= (const poly &a) { return *this = *this / a; }
264,098✔
1964
poly& poly::operator%= (const poly &a) { return *this = *this % a; }
7,835✔
1965

1966
// comparison operators
1967
bool poly::operator== (const poly &a) const {
455,650✔
1968
        for (int i=0; i<terms[0]; i++)
2,381,593✔
1969
                if (terms[i] != a[i]) return 0;
2,321,609✔
1970
        return 1;
1971
}
1972

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

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

1980
int poly::number_of_terms () const {
1,278,947✔
1981

1982
        int res=0;
1,278,947✔
1983
        for (int i=1; i<terms[0]; i+=terms[i])
9,817,090✔
1984
                res++;
8,538,140✔
1985
        return res;        
1,278,947✔
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 {
4,335✔
1995
        
1996
        POLY_GETIDENTITY(*this);
4,335✔
1997
        
1998
        int var = AN.poly_num_vars;
4,335✔
1999
        for (int j=0; j<var; j++)
5,099✔
2000
                if (terms[2+j]>0) return j;
5,099✔
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 {
246,800✔
2011

2012
        POLY_GETIDENTITY(*this);
246,800✔
2013
        
2014
        vector<bool> used(AN.poly_num_vars, false);
246,800✔
2015
        
2016
        for (int i=1; i<terms[0]; i+=terms[i])
1,615,583✔
2017
                for (int j=0; j<AN.poly_num_vars; j++)
4,703,310✔
2018
                        if (terms[i+1+j]>0) used[j] = true;
3,334,524✔
2019

2020
        vector<int> vars;
246,800✔
2021
        for (int i=0; i<AN.poly_num_vars; i++)
770,322✔
2022
                if (used[i]) vars.push_back(i);
523,522✔
2023
        
2024
        return vars;
246,800✔
2025
}
2026

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

2032
// returns the sign of the leading coefficient
2033
int poly::sign () const {
1,946,915✔
2034
        if (terms[0]==1) return 0;
1,946,915✔
2035
        return terms[terms[1]] > 0 ? 1 : -1;
1,946,915✔
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 {
201,362✔
2045
        int deg = -1;
201,362✔
2046
        for (int i=1; i<terms[0]; i+=terms[i])
3,921,113✔
2047
                deg = MaX(deg, terms[i+1+x]);
7,194,220✔
2048
        return deg;
201,362✔
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 {
8,339✔
2078

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

2085
        res.termscopy(&terms[1],1,terms[1]);
8,339✔
2086
        res[0] = res[1] + 1; // length
8,339✔
2087
        for (int i=0; i<AN.poly_num_vars; i++)
28,122✔
2088
                res[2+i] = 0; // powers
19,783✔
2089
        
2090
        return res;
8,339✔
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 {
2,042✔
2100

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

2116
        return res;
2,042✔
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,936✔
2128
        return coefficient(x, degree(x));
1,936✔
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 {
124✔
2135

2136
        POLY_GETIDENTITY(*this);
124✔
2137

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

2140
        for (int i=1; i<terms[0]; i+=terms[i]) {
248✔
2141
                bool same_powers = true;
733✔
2142
                for (int j=0; j<AN.poly_num_vars; j++)
733✔
2143
                        if (j!=x && terms[i+1+j]!=terms[2+j]) {
609✔
2144
                                same_powers = false;
2145
                                break;
2146
                        }
2147
                if (!same_powers) break;
225✔
2148
                
2149
                res.check_memory(res[0]+terms[i]);
124✔
2150
                res.termscopy(&terms[i],res[0],terms[i]);
124✔
2151
                for (int k=0; k<AN.poly_num_vars; k++)
632✔
2152
                        if (k!=x) res[res[0]+1+k]=0;
508✔
2153
                
2154
                res[0] += terms[i];
124✔
2155
        }
2156
        
2157
        return res;        
124✔
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 {
2,245✔
2167

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

2173
        for (int i=1; i<terms[0]; i+=terms[i]) {
10,380✔
2174
                
2175
                int power = terms[i+1+x];
8,135✔
2176

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

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

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

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

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

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

2212
// returns whether the polynomial is one
2213
bool poly::is_one () const {
3,493,246✔
2214
        
2215
        POLY_GETIDENTITY(*this);
3,493,246✔
2216
        
2217
        if (terms[0] != 4+AN.poly_num_vars) return false;
3,493,246✔
2218
        if (terms[1] != 3+AN.poly_num_vars) return false;
2,279,541✔
2219
        for (int i=0; i<AN.poly_num_vars; i++)
6,380,580✔
2220
                if (terms[2+i] != 0) return false;
4,218,210✔
2221
        if (terms[2+AN.poly_num_vars]!=1) return false;
2,162,369✔
2222
        if (terms[3+AN.poly_num_vars]!=1) return false;
1,764,990✔
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 {
851,745✔
2234

2235
        POLY_GETIDENTITY(*this);
851,745✔
2236

2237
        if (terms[0] == 1) return true;
851,745✔
2238
        if (terms[0] != terms[1]+1)        return false;
851,745✔
2239
        
2240
        for (int j=0; j<AN.poly_num_vars; j++)
1,158,841✔
2241
                if (terms[2+j] != 0)
869,057✔
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 {
731,800✔
2254
        return terms[0]>1 && terms[0]==terms[1]+1;
731,800✔
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 {
1,266,110✔
2279

2280
        POLY_GETIDENTITY(*this);
1,266,110✔
2281
        
2282
        int num_terms=0, res=-1;
1,266,110✔
2283

2284
        // test univariate
2285
        for (int i=1; i<terms[0]; i+=terms[i]) {
10,901,890✔
2286
                for (int j=0; j<AN.poly_num_vars; j++)
27,429,820✔
2287
                        if (terms[i+1+j] > 0) {
17,794,020✔
2288
                                if (res == -1) res = j;
8,578,890✔
2289
                                if (res != j) return -2;
8,578,890✔
2290
                        }
2291

2292
                num_terms++;
9,635,780✔
2293
        }
2294

2295
        // constant polynomial
2296
        if (res == -1) return -1;
1,196,305✔
2297

2298
        // test density
2299
        int deg = terms[2+res];
1,194,248✔
2300
        if (2*num_terms < deg+1) return -2;
1,194,248✔
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) {
7,765✔
2312
        
2313
        poly tmp(BHEAD 0,p,n);
15,530✔
2314
        
2315
        int idx=1;
7,765✔
2316
        tmp[idx++] = 3 + AN.poly_num_vars;                        // length
7,765✔
2317
        for (int i=0; i<AN.poly_num_vars; i++)
50,110✔
2318
                tmp[idx++] = i==x ? 1 : 0;                              // powers
76,925✔
2319
        tmp[idx++] = 1;                                           // coefficient
7,765✔
2320
        tmp[idx++] = 1;                                           // length coefficient
7,765✔
2321

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

2331
        if (b == 1) return tmp;
7,765✔
2332
        
2333
        poly res(BHEAD 1,p,n);
676✔
2334
        
2335
        while (b!=0) {
1,158✔
2336
                if (b&1) res*=tmp;
820✔
2337
                tmp*=tmp;
820✔
2338
                b>>=1;
820✔
2339
        }
2340

2341
        return res;
338✔
2342
}
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) {
195,600✔
2351

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

2357
        tmp[idx++] = 3 + AN.poly_num_vars;                                // length
195,600✔
2358
        for (int i=0; i<AN.poly_num_vars; i++)
549,284✔
2359
                tmp[idx++] = i==x ? 1 : 0;                                      // powers
511,768✔
2360
        tmp[idx++] = 1;                                                   // coefficient
195,600✔
2361
        tmp[idx++] = 1;                                                   // length coefficient
195,600✔
2362

2363
        if (!a.is_zero()) {
195,600✔
2364
                tmp[idx++] = 2 + AN.poly_num_vars + ABS(a[a[0]-1]); // length
195,600✔
2365
                for (int i=0; i<AN.poly_num_vars; i++) tmp[idx++] = 0;          // powers
549,284✔
2366
                for (int i=0; i<ABS(a[a[0]-1]); i++)
561,304✔
2367
                        tmp[idx++] = a[2 + AN.poly_num_vars + i];                     // coefficient
365,704✔
2368
                tmp[idx++] = -a[a[0]-1];                                        // length coefficient
195,600✔
2369
        }
2370
        
2371
        tmp[0] = idx;                                                     // length
195,600✔
2372

2373
        while (b!=0) {
391,200✔
2374
                if (b&1) res*=tmp;
195,600✔
2375
                tmp*=tmp;
195,600✔
2376
                b>>=1;
195,600✔
2377
        }
2378
        
2379
        return res;
195,600✔
2380
}
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) {
56,705✔
2390

2391
        AN.poly_num_vars = 0;
56,705✔
2392

2393
        vector<int> vars;
56,705✔
2394
        vector<int> degrees;
56,702✔
2395
        map<int,int> var_to_idx;
113,407✔
2396
        
2397
        // extract all variables
2398
        for (int ei=0; ei<(int)es.size(); ei++) {
298,966✔
2399
                WORD *e = es[ei];
242,264✔
2400

2401
                // fast notation
2402
                if (*e == -SNUMBER) {
242,264✔
2403
                }
2404
                else if (*e == -SYMBOL) {
182,812✔
2405
                        if (!var_to_idx.count(e[1])) {
44,712✔
2406
                                vars.push_back(e[1]);
18,000✔
2407
                                var_to_idx[e[1]] = AN.poly_num_vars++;
18,000✔
2408
                                degrees.push_back(1);
18,000✔
2409
                        }
2410
                }
2411
                else {                
2412
                        for (int i=with_arghead ? ARGHEAD : 0; with_arghead ? i<e[0] : e[i]!=0; i+=e[i]) {
1,605,590✔
2413
                                if (i+1<i+e[i]-ABS(e[i+e[i]-1]) && e[i+1]!=SYMBOL) {
1,302,681✔
2414
                                        MLOCK(ErrorMessageLock);
3✔
2415
                                        MesPrint ((char*)"ERROR: polynomials and polyratfuns must contain symbols only");
3✔
2416
                                        MUNLOCK(ErrorMessageLock);
3✔
2417
                                        TERMINATE(1);
3✔
2418
                                }
2419
                                
2420
                                for (int j=i+3; j<i+e[i]-ABS(e[i+e[i]-1]); j+=2) 
3,582,206✔
2421
                                        if (!var_to_idx.count(e[j])) {
2,279,528✔
2422
                                                vars.push_back(e[j]);
107,642✔
2423
                                                var_to_idx[e[j]] = AN.poly_num_vars++;
107,642✔
2424
                                                degrees.push_back(e[j+1]);
107,642✔
2425
                                        }
2426
                                        else {
2427
                                                degrees[var_to_idx[e[j]]] = MaX(degrees[var_to_idx[e[j]]], e[j+1]);
2,171,886✔
2428
                                        }
2429
                        }
2430
                }
2431
        }
2432
                                 
2433
        // make sure an eventual FACTORSYMBOL appear as last
2434
        if (var_to_idx.count(FACTORSYMBOL)) {
113,396✔
2435
                int i = var_to_idx[FACTORSYMBOL];
8✔
2436
                while (i+1<AN.poly_num_vars) {
16✔
2437
                        swap(vars[i], vars[i+1]);
8✔
2438
                        swap(degrees[i], degrees[i+1]);
8✔
2439
                        i++;
8✔
2440
                }
2441
                degrees[i] = -1; // makes sure it stays last
8✔
2442
        }
2443

2444
        // AN.poly_vars will be deleted in calling functions from polywrap.c
2445
        // For that we use the function poly_free_poly_vars
2446
        // We add one to the allocation to avoid copying in poly_divmod
2447

2448
        if ( (AN.poly_num_vars+1)*sizeof(WORD) > (size_t)(AM.MaxTer) ) {
56,702✔
2449
                // This can happen only in expressions with excessively many variables.
2450
                AN.poly_vars = (WORD *)Malloc1((AN.poly_num_vars+1)*sizeof(WORD), "AN.poly_vars");
×
2451
                AN.poly_vars_type = 1;
×
2452
        }
2453
        else {
2454
                AN.poly_vars = TermMalloc("AN.poly_vars");
56,702✔
2455
                AN.poly_vars_type = 0;
56,702✔
2456
        }
2457

2458
        for (int i=0; i<AN.poly_num_vars; i++)
182,344✔
2459
                AN.poly_vars[i] = vars[i];
125,642✔
2460

2461
        if (sort_vars) {
56,702✔
2462
                // bubble sort variables in decreasing order of degree
2463
                // (this seems better for factorization)
2464
                for (int i=0; i<AN.poly_num_vars; i++)
182,196✔
2465
                        for (int j=0; j+1<AN.poly_num_vars; j++)
473,581✔
2466
                                if (degrees[j] < degrees[j+1]) {
348,036✔
2467
                                        swap(degrees[j], degrees[j+1]);
48,648✔
2468
                                        swap(AN.poly_vars[j], AN.poly_vars[j+1]);
522,229✔
2469
                                }
2470
        }
2471
        else {
2472
                // sort lexicographically                
2473
                sort(AN.poly_vars, AN.poly_vars+AN.poly_num_vars - var_to_idx.count(FACTORSYMBOL));
102✔
2474
        }
2475
}
56,702✔
2476

2477
/*
2478
          #] get_variables : 
2479
          #[ argument_to_poly :
2480
*/
2481

2482
// converts a form expression to a polynomial class "poly"
2483
const poly poly::argument_to_poly (PHEAD WORD *e, bool with_arghead, bool sort_univar, poly *denpoly) {
242,261✔
2484

2485
        map<int,int> var_to_idx;
484,522✔
2486
        for (int i=0; i<AN.poly_num_vars; i++)
759,904✔
2487
                var_to_idx[AN.poly_vars[i]] = i;
517,643✔
2488
        
2489
        poly res(BHEAD 0);
242,261✔
2490

2491
         // fast notation
2492
        if (*e == -SNUMBER) {
242,261✔
2493
                if (denpoly!=NULL) *denpoly = poly(BHEAD 1);
59,452✔
2494
                
2495
                if (e[1] == 0) {
59,452✔
2496
                        res[0] = 1;
×
2497
                        return res;
×
2498
                }
2499
                else {
2500
                        res[0] = 4 + AN.poly_num_vars;
59,452✔
2501
                        res[1] = 3 + AN.poly_num_vars;
59,452✔
2502
                        for (int i=0; i<AN.poly_num_vars; i++)
180,480✔
2503
                                res[2+i] = 0;
121,028✔
2504
                        res[2+AN.poly_num_vars] = ABS(e[1]);
59,452✔
2505
                        res[3+AN.poly_num_vars] = SGN(e[1]);
59,452✔
2506

2507
                        return res;
59,452✔
2508
                }
2509
        }
2510

2511
        if (*e == -SYMBOL) {
182,809✔
2512
                if (denpoly!=NULL) *denpoly = poly(BHEAD 1);
31,356✔
2513
                
2514
                res[0] = 4 + AN.poly_num_vars;
31,356✔
2515
                res[1] = 3 + AN.poly_num_vars;
31,356✔
2516
                for (int i=0; i<AN.poly_num_vars; i++)
101,796✔
2517
                        res[2+i] = 0;
70,440✔
2518
                res[2+var_to_idx.find(e[1])->second] = 1;
31,356✔
2519
                res[2+AN.poly_num_vars] = 1;
31,356✔
2520
                res[3+AN.poly_num_vars] = 1;
31,356✔
2521
                return res;
31,356✔
2522
        }
2523

2524
        // find LCM of denominators of all terms
2525
        WORD nden=1, npro=0, ngcd=0, ndum=0;
151,453✔
2526
        UWORD *den = NumberMalloc("poly::argument_to_poly");
151,453✔
2527
        UWORD *pro = NumberMalloc("poly::argument_to_poly");
151,453✔
2528
        UWORD *gcd = NumberMalloc("poly::argument_to_poly");
151,453✔
2529
        UWORD *dum = NumberMalloc("poly::argument_to_poly");
151,453✔
2530
        den[0]=1;
151,453✔
2531
        
2532
         for (int i=with_arghead ? ARGHEAD : 0; with_arghead ? i<e[0] : e[i]!=0; i+=e[i]) {
1,454,412✔
2533
                int ncoe = ABS(e[i+e[i]-1]/2);
1,302,678✔
2534
                UWORD *coe = (UWORD *)&e[i+e[i]-ncoe-1];
1,302,678✔
2535
                while (ncoe>0 && coe[ncoe-1]==0) ncoe--;
2,348,998✔
2536
                MulLong(den,nden,coe,ncoe,pro,&npro);
1,302,678✔
2537
                GcdLong(BHEAD den,nden,coe,ncoe,gcd,&ngcd);
1,302,678✔
2538
                DivLong(pro,npro,gcd,ngcd,den,&nden,dum,&ndum);
1,302,678✔
2539
        }
2540

2541
        if (denpoly!=NULL) *denpoly = poly(BHEAD den, nden);
151,453✔
2542
        
2543
        int ri=1;
2544
        
2545
        // ordinary notation
2546
        for (int i=with_arghead ? ARGHEAD : 0; with_arghead ? i<e[0] : e[i]!=0; i+=e[i]) {
1,454,131✔
2547
                res.check_memory(ri);
1,302,678✔
2548
                WORD nc = e[i+e[i]-1];                                                 // length coefficient
1,302,678✔
2549
                for (int j=0; j<AN.poly_num_vars; j++)
4,332,130✔
2550
                        res[ri+1+j]=0;                                                     // powers=0
3,029,450✔
2551
                WCOPY(dum, &e[i+e[i]-ABS(nc)], ABS(nc));                               // coefficient to dummy
7,304,360✔
2552
                nc /= 2;                                                               // remove denominator
1,302,678✔
2553
                Mully(BHEAD dum, &nc, den, nden);                                      // multiply with overall den
1,302,678✔
2554
                res.termscopy((WORD *)dum, ri+1+AN.poly_num_vars, ABS(nc));            // coefficient to res
1,302,678✔
2555
                res[ri] = ABS(nc) + AN.poly_num_vars + 2;                              // length
1,302,678✔
2556
                res[ri+res[ri]-1] = nc;                                                // length coefficient
1,302,678✔
2557
                for (int j=i+3; j<i+e[i]-ABS(e[i+e[i]-1]); j+=2) 
3,582,206✔
2558
                        res[ri+1+var_to_idx.find(e[j])->second] = e[j+1];                  // powers
2,279,528✔
2559
                ri += res[ri];                                                         // length
1,302,678✔
2560
        }
2561

2562
        res[0] = ri;
151,453✔
2563

2564
        // JD: For univariate cases, check whether the ordering is correct or not.
2565
        // There are various ways to arrive here, but with an incorrect ordering, such
2566
        // as interactions with collect, moving a polyratfun out of another function
2567
        // argument, etc.
2568
        // If the ordering is not correct, make sure we normalize. In multivariate cases,
2569
        // always normalize as before.
2570
        if (sort_univar == false && AN.poly_num_vars == 1) {
151,453✔
2571
                if (res.number_of_terms() >= 2) {
54,872✔
2572
                        if(res[2] < res.last_monomial()[2]) {
53,420✔
2573
                                sort_univar = true;
2574
                        }
2575
                }
2576
        }
2577

2578
        if (sort_univar || AN.poly_num_vars>1) {
124,873✔
2579
                res.normalize();
123,161✔
2580
        }
2581

2582
        NumberFree(den,"poly::argument_to_poly");
151,453✔
2583
        NumberFree(pro,"poly::argument_to_poly");
151,453✔
2584
        NumberFree(gcd,"poly::argument_to_poly");
151,453✔
2585
        NumberFree(dum,"poly::argument_to_poly");
151,453✔
2586
        
2587
        return res;
151,453✔
2588
}
2589

2590
/*
2591
          #] argument_to_poly : 
2592
          #[ poly_to_argument :
2593
*/
2594

2595
// converts a polynomial class "poly" to a form expression
2596
void poly::poly_to_argument (const poly &a, WORD *res, bool with_arghead) {
113,273✔
2597

2598
        POLY_GETIDENTITY(a);
113,273✔
2599

2600
        // special case: a=0
2601
        if (a[0]==1) {
113,273✔
2602
                if (with_arghead) {
3,284✔
2603
                        res[0] = -SNUMBER;
3,284✔
2604
                        res[1] = 0;
3,284✔
2605
                }
2606
                else {
2607
                        res[0] = 0;
×
2608
                }
2609
                return;
3,284✔
2610
        }
2611

2612
        if (with_arghead) {
109,989✔
2613
                res[1] = AN.poly_num_vars>1 ? DIRTYFLAG : 0; // dirty flag
109,568✔
2614
                for (int i=2; i<ARGHEAD; i++)
109,568✔
2615
                        res[i] = 0;                                // remainder of arghead        
2616
        }
2617

2618
        int L = with_arghead ? ARGHEAD : 0;
109,989✔
2619
        
2620
        for (int i=1; i!=a[0]; i+=a[i]) {
1,041,102✔
2621
                
2622
                res[L]=1; // length
931,113✔
2623

2624
                bool first=true;
931,113✔
2625
                
2626
                for (int j=0; j<AN.poly_num_vars; j++)
3,135,934✔
2627
                        if (a[i+1+j] > 0) {
2,204,821✔
2628
                                if (first) {
1,646,462✔
2629
                                        first=false;
876,090✔
2630
                                        res[L+1] = 1; // symbols
876,090✔
2631
                                        res[L+2] = 2; // length
876,090✔
2632
                                }
2633
                                res[L+1+res[L+2]++] = AN.poly_vars[j]; // symbol
1,646,462✔
2634
                                res[L+1+res[L+2]++] = a[i+1+j];  // power
1,646,462✔
2635
                        }
2636

2637
                if (!first)        res[L] += res[L+2]; // fix length
931,113✔
2638

2639
                WORD nc = a[i+a[i]-1];
931,113✔
2640
                WCOPY(&res[L+res[L]], &a[i+a[i]-1-ABS(nc)], ABS(nc)); // numerator
2,628,206✔
2641

2642
                res[L] += ABS(nc);                                     // fix length
931,113✔
2643
                memset(&res[L+res[L]], 0, ABS(nc)*sizeof(WORD)); // denominator one
931,113✔
2644
                res[L+res[L]] = 1;                               // denominator one
931,113✔
2645
                res[L] += ABS(nc);                               // fix length
931,113✔
2646
                res[L+res[L]] = SGN(nc) * (2*ABS(nc)+1);         // length of coefficient
931,113✔
2647
                res[L]++;                                        // fix length
931,113✔
2648
                L += res[L];                                     // fix length
931,113✔
2649
        }
2650

2651
        if (with_arghead) {
109,989✔
2652
                res[0] = L;
109,568✔
2653
                // convert to fast notation if possible
2654
                ToFast(res,res);
109,568✔
2655
        }
2656
        else {
2657
                res[L] = 0;
421✔
2658
        }
2659
}
2660

2661
/*
2662
          #] poly_to_argument : 
2663
          #[ poly_to_argument_with_den :
2664
*/
2665

2666
// converts a polynomial class "poly" divided by a number (nden, den) to a form expression
2667
// cf. poly::poly_to_argument()
2668
void poly::poly_to_argument_with_den (const poly &a, WORD nden, const UWORD *den, WORD *res, bool with_arghead) {
12✔
2669

2670
        POLY_GETIDENTITY(a);
12✔
2671

2672
        // special case: a=0
2673
        if (a[0]==1) {
12✔
2674
                if (with_arghead) {
×
2675
                        res[0] = -SNUMBER;
×
2676
                        res[1] = 0;
×
2677
                }
2678
                else {
2679
                        res[0] = 0;
×
2680
                }
2681
                return;
×
2682
        }
2683

2684
        if (with_arghead) {
12✔
2685
                res[1] = AN.poly_num_vars>1 ? DIRTYFLAG : 0; // dirty flag
×
2686
                for (int i=2; i<ARGHEAD; i++)
×
2687
                        res[i] = 0;                                // remainder of arghead
2688
        }
2689

2690
        WORD nden1;
12✔
2691
        UWORD *den1 = (UWORD *)NumberMalloc("poly_to_argument_with_den");
12✔
2692

2693
        int L = with_arghead ? ARGHEAD : 0;
12✔
2694

2695
        for (int i=1; i!=a[0]; i+=a[i]) {
10,992✔
2696

2697
                res[L]=1; // length
10,980✔
2698

2699
                bool first=true;
10,980✔
2700

2701
                for (int j=0; j<AN.poly_num_vars; j++)
54,848✔
2702
                        if (a[i+1+j] > 0) {
43,868✔
2703
                                if (first) {
36,588✔
2704
                                        first=false;
10,968✔
2705
                                        res[L+1] = 1; // symbols
10,968✔
2706
                                        res[L+2] = 2; // length
10,968✔
2707
                                }
2708
                                res[L+1+res[L+2]++] = AN.poly_vars[j]; // symbol
36,588✔
2709
                                res[L+1+res[L+2]++] = a[i+1+j];  // power
36,588✔
2710
                        }
2711

2712
                if (!first)        res[L] += res[L+2]; // fix length
10,980✔
2713

2714
                // numerator
2715
                WORD nc = a[i+a[i]-1];
10,980✔
2716
                WCOPY(&res[L+res[L]], &a[i+a[i]-1-ABS(nc)], ABS(nc));
103,852✔
2717

2718
                // denominator
2719
                nden1 = nden;
10,980✔
2720
                WCOPY(den1, den, ABS(nden));
98,708✔
2721

2722
                if (nden != 1 || den[0] != 1) {
10,980✔
2723
                        // remove gcd(num,den)
2724
                        Simplify(BHEAD (UWORD *)&res[L+res[L]], &nc, den1, &nden1);
10,980✔
2725
                }
2726

2727
                Pack((UWORD *)&res[L+res[L]], &nc, den1, nden1);  // format
10,980✔
2728
                res[L] += 2*ABS(nc)+1;                            // fix length
10,980✔
2729
                res[L+res[L]-1] = SGN(nc)*(2*ABS(nc)+1);          // length of coefficient
10,980✔
2730
                L += res[L];                                      // fix length
10,980✔
2731
        }
2732

2733
        NumberFree(den1, "poly_to_argument_with_den");
12✔
2734

2735
        if (with_arghead) {
12✔
2736
                res[0] = L;
×
2737
                // convert to fast notation if possible
2738
                ToFast(res,res);
×
2739
        }
2740
        else {
2741
                res[L] = 0;
12✔
2742
        }
2743
}
2744

2745
/*
2746
          #] poly_to_argument_with_den : 
2747
          #[ size_of_form_notation :
2748
*/
2749

2750
// the size of the polynomial in form notation (without argheads and fast notation)
2751
int poly::size_of_form_notation () const {
113,288✔
2752
        
2753
        POLY_GETIDENTITY(*this);
113,288✔
2754

2755
        // special case: a=0
2756
        if (terms[0]==1) return 0;
113,288✔
2757

2758
        int len = 0;
2759
        
2760
        for (int i=1; i!=terms[0]; i+=terms[i]) {
1,041,435✔
2761
                len++;
931,431✔
2762
                int npow = 0;
931,431✔
2763
                for (int j=0; j<AN.poly_num_vars; j++)
3,137,368✔
2764
                        if (terms[i+1+j] > 0) npow++;
2,205,937✔
2765
                if (npow > 0) len += 2*npow + 2;
931,431✔
2766
                len += 2 * ABS(terms[i+terms[i]-1]) + 1;
931,431✔
2767
        }
2768

2769
        return len;
2770
}
2771

2772
/*
2773
          #] size_of_form_notation : 
2774
          #[ size_of_form_notation_with_den :
2775
*/
2776

2777
// the size of the polynomial divided by a number (its size is given by nden)
2778
// in form notation (without argheads and fast notation)
2779
// cf. poly::size_of_form_notation()
2780
int poly::size_of_form_notation_with_den (WORD nden) const {
12✔
2781

2782
        POLY_GETIDENTITY(*this);
12✔
2783

2784
        // special case: a=0
2785
        if (terms[0]==1) return 0;
12✔
2786

2787
        nden = ABS(nden);
12✔
2788
        int len = 0;
12✔
2789

2790
        for (int i=1; i!=terms[0]; i+=terms[i]) {
10,992✔
2791
                len++;
10,980✔
2792
                int npow = 0;
10,980✔
2793
                for (int j=0; j<AN.poly_num_vars; j++)
54,848✔
2794
                        if (terms[i+1+j] > 0) npow++;
43,868✔
2795
                if (npow > 0) len += 2*npow + 2;
10,980✔
2796
                len += 2 * MaX(ABS(terms[i+terms[i]-1]), nden) + 1;
10,980✔
2797
        }
2798

2799
        return len;
2800
}
2801

2802
/*
2803
          #] size_of_form_notation_with_den : 
2804
          #[ to_coefficient_list :
2805
*/
2806

2807
// returns the coefficient list of a univariate polynomial
2808
const vector<WORD> poly::to_coefficient_list (const poly &a) {
1,627✔
2809

2810
        POLY_GETIDENTITY(a);
1,627✔
2811
        
2812
        if (a.is_zero()) return vector<WORD>();
1,627✔
2813
                        
2814
        int x = a.first_variable();
1,627✔
2815
        if (x == AN.poly_num_vars) x=0;
1,627✔
2816
                
2817
        vector<WORD> res(1+a[2+x],0);
1,627✔
2818
        
2819
        for (int i=1; i<a[0]; i+=a[i]) 
10,765✔
2820
                res[a[i+1+x]] = (a[i+a[i]-1] * a[i+a[i]-2]) % a.modp;
9,138✔
2821

2822
        return res;
1,627✔
2823
}
2824

2825
/*
2826
          #] to_coefficient_list : 
2827
          #[ coefficient_list_divmod :
2828
*/
2829

2830
// divides two polynomials represented by coefficient lists
2831
const vector<WORD> poly::coefficient_list_divmod (const vector<WORD> &a, const vector<WORD> &b, WORD p, int divmod) {
27,028✔
2832

2833
        int bsize = (int)b.size();
27,028✔
2834
        while (b[bsize-1]==0) bsize--;
195,377✔
2835
        
2836
        WORD inv;
27,028✔
2837
        GetModInverses(b[bsize-1] + (b[bsize-1]<0?p:0), p, &inv, NULL);
48,084✔
2838
                                                                                
2839
        vector<WORD> q(a.size(),0);
54,056✔
2840
        vector<WORD> r(a);
54,056✔
2841
                
2842
        while ((int)r.size() >= bsize) {
172,072✔
2843
                LONG mul = ((LONG)inv * r.back()) % p;
145,044✔
2844
                int off = r.size()-bsize;
145,044✔
2845
                q[off] = mul;
145,044✔
2846
                for (int i=0; i<bsize; i++)
796,318✔
2847
                        r[off+i] = (r[off+i] - mul*b[i]) % p;
651,274✔
2848
                while (r.size()>0 && r.back()==0)
555,508✔
2849
                        r.pop_back();
564,290✔
2850
        }
2851

2852
        if (divmod==0) {
27,028✔
2853
                while (q.size()>0 && q.back()==0)
1,243✔
2854
                        q.pop_back();
1,243✔
2855
                return q;
291✔
2856
        }
2857
        else {
2858
                while (r.size()>0 && r.back()==0)
18,246✔
2859
                        r.pop_back();
26,737✔
2860
                return r;
27,028✔
2861
        }
2862
}
2863

2864
/*
2865
          #] coefficient_list_divmod : 
2866
          #[ from_coefficient_list :
2867
*/
2868

2869
// converts a coefficient list to a "poly"
2870
const poly poly::from_coefficient_list (PHEAD const vector<WORD> &a, int x, WORD p) {
1,377✔
2871

2872
        poly res(BHEAD 0);
1,377✔
2873
        int ri=1;
1,377✔
2874
        
2875
        for (int i=(int)a.size()-1; i>=0; i--)
4,298✔
2876
                if (a[i] != 0) {
2,921✔
2877
                        res.check_memory(ri);
2,676✔
2878
                        res[ri] = AN.poly_num_vars+3;                // length
2,676✔
2879
                        for (int j=0; j<AN.poly_num_vars; j++)
13,058✔
2880
                                res[ri+1+j]=0;                             // powers
10,382✔
2881
                        res[ri+1+x] = i;                             // power of x
2,676✔
2882
                        res[ri+1+AN.poly_num_vars] = ABS(a[i]);      // coefficient
2,676✔
2883
                        res[ri+1+AN.poly_num_vars+1] = SGN(a[i]);    // sign
2,676✔
2884
                        ri += res[ri];
2,676✔
2885
                }
2886
        
2887
        res[0]=ri;                                       // total length
1,377✔
2888
        res.setmod(p,1);
1,377✔
2889
        
2890
        return res;
1,377✔
2891
}
2892

2893
/*
2894
          #] from_coefficient_list : 
2895
*/
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

© 2025 Coveralls, Inc