• 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

77.87
/sources/polywrap.cc
1
/** @file polywrap.cc
2
 *
3
 *   Contains methods to call the polynomial methods (written in C++)
4
 *   from the rest of Form (written in C). These include polynomial
5
 *   gcd computation, factorization and polyratfuns.
6
 */
7

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

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

39
#include <iostream>
40
#include <vector>
41
#include <map>
42
#include <climits>
43
#include <cassert>
44

45
//#define DEBUG
46

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

51
// denompower is increased by this factor when divmod_heap fails
52
const int POLYWRAP_DENOMPOWER_INCREASE_FACTOR = 2;
53

54
using namespace std;
55

56
/*
57
          #[ poly_determine_modulus :
58
*/
59

60
/**  Modulus for polynomial algebra
61
 *
62
 *   Description
63
 *   ===========
64
 *   This method determines whether polynomial algebra is done with a
65
 *   modulus or not. This depends on AC.ncmod. If only_funargs is set
66
 *   it also depends on (AC.modmode & ALSOFUNARGS).
67
 *
68
 *   The program terminates if the feature is not
69
 *   implemented. Polynomial algebra modulo M > WORDSIZE in not
70
 *   implemented. If multi_error is set, multivariate algebra mod M is
71
 *   not implemented.
72
 
73
 *   Notes
74
 *   =====
75
 *   - If AC.ncmod>0 and only_funargs=true and
76
 *     AC.modmode&ALSOFUNARGS=false, AN.ncmod is set to zero, for
77
 *     otherwise RaisPow calculates mod M.
78
 */
79
WORD poly_determine_modulus (PHEAD bool multi_error, bool is_fun_arg, string message) {
56,702✔
80
        
81
        if (AC.ncmod==0) return 0;
56,702✔
82

83
        if (!is_fun_arg || (AC.modmode & ALSOFUNARGS)) {
×
84
                
85
                if (ABS(AC.ncmod)>1) {
×
86
                        MLOCK(ErrorMessageLock);
×
87
                        MesPrint ((char*)"ERROR: %s with modulus > WORDSIZE not implemented",message.c_str());
×
88
                        MUNLOCK(ErrorMessageLock);
×
NEW
89
                        TERMINATE(-1);
×
90
                }
91
                        
92
                if (multi_error && AN.poly_num_vars>1) {
×
93
                        MLOCK(ErrorMessageLock);
×
94
                        MesPrint ((char*)"ERROR: multivariate %s with modulus not implemented",message.c_str());
×
95
                        MUNLOCK(ErrorMessageLock);
×
NEW
96
                        TERMINATE(-1);
×
97
                }
98
                        
99
                return *AC.cmod;
×
100
        }
101

102
        AN.ncmod = 0;
×
103
        return 0;
×
104
}
105

106
/*
107
          #] poly_determine_modulus : 
108
          #[ poly_gcd :
109
*/
110

111
/**  Polynomial gcd
112
 *
113
 *   Description
114
 *   ===========
115
 *   This method calculates the greatest common divisor of two
116
 *   polynomials, given by two zero-terminated Form-style term lists.
117
 *
118
 *   Notes
119
 *   =====
120
 *   - The result is written at newly allocated memory
121
 *   - Called from ratio.c
122
 *   - Calls polygcd::gcd
123
 */
124
WORD *poly_gcd(PHEAD WORD *a, WORD *b, WORD fit) {
40✔
125

126
#ifdef DEBUG
127
        cout << "*** [" << thetime() << "]  CALL : poly_gcd" << endl;
128
#endif
129

130
//
131
//MesPrint("Calling poly_gcd with:");
132
//{
133
//        WORD *at = a;
134
//        MesPrint("      a:");
135
//        while ( *at ) {
136
//                MesPrint("   %a",*at,at);
137
//                at += *at;
138
//        }
139
//        MesPrint("      b:");
140
//        at = b;
141
//        while ( *at ) {
142
//                MesPrint("   %a",*at,at);
143
//                at += *at;
144
//        }
145
//}
146
        
147
        // Extract variables
148
        vector<WORD *> e;
40✔
149
        e.push_back(a);
40✔
150
        e.push_back(b);
40✔
151
        poly::get_variables(BHEAD e, false, true);
40✔
152

153
        // Check for modulus calculus
154
        WORD modp=poly_determine_modulus(BHEAD true, true, "polynomial GCD");
40✔
155

156
        // Convert to polynomials
157
        poly pa(poly::argument_to_poly(BHEAD a, false, true), modp, 1);
80✔
158
        poly pb(poly::argument_to_poly(BHEAD b, false, true), modp, 1);
80✔
159

160
        // Calculate gcd
161
        poly gcd(polygcd::gcd(pa,pb));
40✔
162
        
163
        // Allocate new memory and convert to Form notation
164
        int newsize = (gcd.size_of_form_notation()+1);
40✔
165
        WORD *res;
40✔
166
        if ( fit ) {
40✔
167
                if ( newsize*sizeof(WORD) >= (size_t)(AM.MaxTer) ) {
×
168
                        MLOCK(ErrorMessageLock);
×
169
                        MesPrint("poly_gcd: Term too complex. Maybe increasing MaxTermSize can help");
×
170
                        MUNLOCK(ErrorMessageLock);
×
NEW
171
                        TERMINATE(-1);
×
172
                }
173
                res = TermMalloc("poly_gcd");
×
174
        }
175
        else {
176
                res = (WORD *)Malloc1(newsize*sizeof(WORD), "poly_gcd");
40✔
177
        }
178
        poly::poly_to_argument(gcd, res, false);
40✔
179

180
        poly_free_poly_vars(BHEAD "AN.poly_vars_qcd");
40✔
181

182
        // reset modulo calculation
183
        AN.ncmod = AC.ncmod;
40✔
184
        return res;
80✔
185
}
186

187
/*
188
          #] poly_gcd : 
189
          #[ poly_divmod :
190

191
        if fit == 1 the answer must fit inside a term.
192
*/
193

194
WORD *poly_divmod(PHEAD WORD *a, WORD *b, int divmod, WORD fit) {
32✔
195

196
#ifdef DEBUG
197
        cout << "*** [" << thetime() << "]  CALL : poly_divmod" << endl;
198
#endif
199

200
        // check for modulus calculus
201
        WORD modp=poly_determine_modulus(BHEAD false, true, "polynomial division");
32✔
202

203
        // get variables
204
        vector<WORD *> e;
32✔
205
        e.push_back(a);
32✔
206
        e.push_back(b);
32✔
207
        poly::get_variables(BHEAD e, false, false);
32✔
208

209
        // add extra variables to keep track of denominators
210
        const int DENOMSYMBOL = MAXPOSITIVE;
32✔
211
        
212
//        WORD *new_poly_vars = (WORD *)Malloc1((AN.poly_num_vars+1)*sizeof(WORD), "AN.poly_vars");
213
//        WCOPY(new_poly_vars, AN.poly_vars, AN.poly_num_vars);
214
//        new_poly_vars[AN.poly_num_vars] = DENOMSYMBOL;
215
//        if (AN.poly_num_vars > 0)
216
//                M_free(AN.poly_vars, "AN.poly_vars");
217
//        AN.poly_num_vars++;
218
//        AN.poly_vars = new_poly_vars;
219
        AN.poly_vars[AN.poly_num_vars++] = DENOMSYMBOL;
32✔
220
        
221
        // convert to polynomials
222
        poly dena(BHEAD 0);
64✔
223
        poly denb(BHEAD 0);
64✔
224
        poly pa(poly::argument_to_poly(BHEAD a, false, true, &dena), modp, 1);
64✔
225
        poly pb(poly::argument_to_poly(BHEAD b, false, true, &denb), modp, 1);
64✔
226
        
227
        // remove contents
228
        poly numres(polygcd::integer_content(pa));
64✔
229
        poly denres(polygcd::integer_content(pb));
64✔
230
        pa /= numres;
32✔
231
        pb /= denres;
32✔
232

233
        if (divmod==0) {
32✔
234
                numres *= denb;
16✔
235
                denres *= dena;
16✔
236
        }
237
        else {
238
                denres = dena;
16✔
239
        }
240

241
        poly gcdres(polygcd::integer_gcd(numres,denres));
64✔
242
        numres /= gcdres;
32✔
243
        denres /= gcdres;                                                        
32✔
244

245
        // determine lcoeff(b)
246
        poly lcoeffb(pb.integer_lcoeff());
64✔
247

248
        poly pres(BHEAD 0);
32✔
249

250
        if (!lcoeffb.is_one()) {
32✔
251

252
                if (AN.poly_num_vars > 2) {
24✔
253
                        // the original polynomial is multivariate (one dummy variable has
254
                        // been added), so it is not trivial to determine which power of
255
                        // lcoeff(b) can be in the answer
256

257
                        int denompower = 0, prevdenompower = 0;
16✔
258
                        poly pq(BHEAD 0);
32✔
259
                        poly pr(BHEAD 0);
32✔
260

261
                        // try denompower = 0, if this fails increase denompower until division succeeds
262
                        bool div_fail = true;
16✔
263
                        do
48✔
264
                        {
265
                                if(denompower < prevdenompower)
48✔
266
                                {
267
                                        // denompower increased beyond INT_MAX
268
                                        MLOCK(ErrorMessageLock);
×
269
                                        MesPrint ((char*)"ERROR: pseudo-division failed in poly_divmod (denompower > INT_MAX)");
×
270
                                        MUNLOCK(ErrorMessageLock);
×
NEW
271
                                        TERMINATE(1);
×
272
                                }
273

274
                                if(denompower != 0)
48✔
275
                                {
276
                                        // multiply a by lcoeffb^(denompower-prevdenompower)
277
                                        WORD n = lcoeffb[lcoeffb[1]];
32✔
278
                                        RaisPow(BHEAD (UWORD *)&lcoeffb[2+AN.poly_num_vars], &n, denompower-prevdenompower);
32✔
279
                                        lcoeffb[1] = 2 + AN.poly_num_vars + ABS(n);
32✔
280
                                        lcoeffb[0] = 1 + lcoeffb[1];
32✔
281
                                        lcoeffb[lcoeffb[1]] = n;
32✔
282

283
                                        pa *= lcoeffb;
32✔
284
                                        denres *= lcoeffb;
32✔
285
                                }
286

287
                                // try division
288
                                poly ppow(BHEAD 0);
48✔
289
                                poly::divmod_heap(pa,pb,pq,pr,false,true,div_fail); // sets div_fail
48✔
290

291
                                // increase denompower for next iteration
292
                                prevdenompower = denompower;
48✔
293
                                denompower = (denompower==0 ? 1 : denompower*POLYWRAP_DENOMPOWER_INCREASE_FACTOR+1 ); // generates 2^n-1 when POLYWRAP_DENOMPOWER_INCREASE_FACTOR = 2
48✔
294
                        }
295
                        while(div_fail);
296

297
                        pres = (divmod==0 ? pq : pr);
24✔
298

299
                }
300
                else {
301
                        // one variable, so the power is the difference of the degrees
302

303
                        int denompower = MaX(0, pa.degree(0) - pb.degree(0) + 1);
8✔
304

305
                        // multiply a by that power
306
                        WORD n = lcoeffb[lcoeffb[1]];
8✔
307
                        RaisPow(BHEAD (UWORD *)&lcoeffb[2+AN.poly_num_vars], &n, denompower);
8✔
308
                        lcoeffb[1] = 2 + AN.poly_num_vars + ABS(n);
8✔
309
                        lcoeffb[0] = 1 + lcoeffb[1];
8✔
310
                        lcoeffb[lcoeffb[1]] = n;
8✔
311

312
                        pa *= lcoeffb;
8✔
313
                        denres *= lcoeffb;
8✔
314

315
                        pres = (divmod==0 ? pa/pb : pa%pb);
8✔
316

317
                }
318

319
        }
320
        else {
321

322
                pres = (divmod==0 ? pa/pb : pa%pb);
8✔
323

324
        }
325

326
        // convert to Form notation
327
        // NOTE: this part can be rewritten with poly::size_of_form_notation_with_den()
328
        // and poly::poly_to_argument_with_den().
329
        WORD *res;
32✔
330

331
        // special case: a=0
332
        if (pres[0]==1) {
32✔
333
                if ( fit ) {
8✔
334
                        res = TermMalloc("poly_divmod");
×
335
                }
336
                else {
337
                        res = (WORD *)Malloc1(sizeof(WORD), "poly_divmod");
8✔
338
                }
339
                res[0] = 0;
8✔
340
        }
341
        else {
342
                pres *= numres;
24✔
343
                
344
                WORD nden;
24✔
345
                UWORD *den = (UWORD *)NumberMalloc("poly_divmod");
24✔
346

347
                // allocate the memory; note that this overestimates the size,
348
                // since the estimated denominators are too large
349
                int ressize = pres.size_of_form_notation() + pres.number_of_terms()*2*ABS(denres[denres[1]]) + 1;
24✔
350

351
                if ( fit ) {
24✔
352
                        if ( ressize*sizeof(WORD) > (size_t)(AM.MaxTer) ) {
×
353
                                MLOCK(ErrorMessageLock);
×
354
                                MesPrint("poly_divmod: Term too complex. Maybe increasing MaxTermSize can help");
×
355
                                MUNLOCK(ErrorMessageLock);
×
NEW
356
                                TERMINATE(-1);
×
357
                        }
358
                        res = TermMalloc("poly_divmod");
×
359
                }
360
                else {
361
                        res = (WORD *)Malloc1(ressize*sizeof(WORD), "poly_divmod");
24✔
362
                }
363
                int L=0;
24✔
364

365
                for (int i=1; i!=pres[0]; i+=pres[i]) {
360✔
366

367
                        res[L]=1; // length
336✔
368
                        bool first = true;
336✔
369
                        
370
                        for (int j=0; j<AN.poly_num_vars; j++)
1,632✔
371
                                if (pres[i+1+j] > 0) {
1,296✔
372
                                        if (first) {
784✔
373
                                                first = false;
324✔
374
                                                res[L+1] = 1; // symbols
324✔
375
                                                res[L+2] = 2; // length
324✔
376
                                        }
377
                                        res[L+1+res[L+2]++] = AN.poly_vars[j]; // symbol
784✔
378
                                        res[L+1+res[L+2]++] = pres[i+1+j];     // power
784✔
379
                                }
380
                        
381
                        if (!first)        res[L] += res[L+2]; // fix length
336✔
382

383
                        // numerator                        
384
                        WORD nnum = pres[i+pres[i]-1];
336✔
385
                        WCOPY(&res[L+res[L]], &pres[i+pres[i]-1-ABS(nnum)], ABS(nnum));
2,268✔
386

387
                        // calculate denominator
388
                        nden = denres[denres[1]];
336✔
389
                        WCOPY(den, &denres[2+AN.poly_num_vars], ABS(nden));
2,520✔
390

391
                        if (nden!=1 || den[0]!=1)
336✔
392
                                Simplify(BHEAD (UWORD *)&res[L+res[L]], &nnum, den, &nden); // gcd(num,den)
320✔
393
                        Pack((UWORD *)&res[L+res[L]], &nnum, den, nden);              // format
336✔
394
                        res[L] += 2*ABS(nnum)+1;                                      // fix length
336✔
395
                        res[L+res[L]-1] = SGN(nnum)*(2*ABS(nnum)+1);                  // length of coefficient
336✔
396
                        L += res[L];                                                  // fix length
336✔
397
                }
398
                
399
                res[L] = 0;
24✔
400
                
401
                NumberFree(den,"poly_divmod");        
24✔
402
        }
403

404
        // clean up
405
        poly_free_poly_vars(BHEAD "AN.poly_vars_divmod");
32✔
406

407
        // reset modulo calculation
408
        AN.ncmod = AC.ncmod;
32✔
409

410
        return res;
64✔
411
}
412

413
/*
414
          #] poly_divmod : 
415
          #[ poly_div :
416

417
        Routine divides the expression in arg1 by the expression in arg2.
418
        We did not take out special cases.
419
        The arguments are zero terminated sequences of term(s).
420
        The action is to divide arg1 by arg2: [arg1/arg2].
421
        The answer should be a buffer (allocated by Malloc1) with a zero
422
        terminated sequence of terms (or just zero).
423
*/
424
WORD *poly_div(PHEAD WORD *a, WORD *b, WORD fit) {
16✔
425

426
#ifdef DEBUG
427
        cout << "*** [" << thetime() << "]  CALL : poly_div" << endl;
428
#endif
429
        
430
        return poly_divmod(BHEAD a, b, 0, fit);
16✔
431
}
432

433
/*
434
          #] poly_div : 
435
          #[ poly_rem :
436

437
        Routine divides the expression in arg1 by the expression in arg2
438
        and takes the remainder.
439
        We did not take out special cases.
440
        The arguments are zero terminated sequences of term(s).
441
        The action is to divide arg1 by arg2 and take the remainder: [arg1%arg2].
442
        The answer should be a buffer (allocated by Malloc1) with a zero
443
        terminated sequence of terms (or just zero).
444
*/
445
WORD *poly_rem(PHEAD WORD *a, WORD *b, WORD fit) {
16✔
446

447
#ifdef DEBUG
448
        cout << "*** [" << thetime() << "]  CALL : poly_rem" << endl;
449
#endif
450

451
        return poly_divmod(BHEAD a, b, 1, fit);
16✔
452
}
453

454
/*
455
          #] poly_rem : 
456
          #[ poly_ratfun_read :
457
*/
458

459
/**  Read a PolyRatFun
460
 *
461
 *   Description
462
 *   ===========
463
 *   This method reads a polyratfun starting at the pointer a. The
464
 *   resulting numerator and denominator are written in num and
465
 *   den. If MUSTCLEANPRF, the result is normalized.
466
 *
467
 *   Notes
468
 *   =====
469
 *   - Calls polygcd::gcd
470
 */
471
void poly_ratfun_read (WORD *a, poly &num, poly &den) {
120,888✔
472

473
#ifdef DEBUG
474
        cout << "*** [" << thetime() << "]  CALL : poly_ratfun_read" << endl;
475
#endif
476

477
        POLY_GETIDENTITY(num);
120,888✔
478

479
        int modp = num.modp;
120,888✔
480
        
481
        WORD *astop = a+a[1];
120,888✔
482

483
        bool clean = (a[2] & MUSTCLEANPRF) == 0;
120,888✔
484

485
        a += FUNHEAD;
120,888✔
486
        if (a >= astop) {
120,888✔
487
                MLOCK(ErrorMessageLock);
×
488
                MesPrint ((char*)"ERROR: PolyRatFun cannot have zero arguments");
×
489
                MUNLOCK(ErrorMessageLock);
×
NEW
490
                TERMINATE(-1);
×
491
        }
492

493
        poly den_num(BHEAD 1),den_den(BHEAD 1);
241,776✔
494
        
495
        num = poly::argument_to_poly(BHEAD a, true, !clean, &den_num);
120,888✔
496
        num.setmod(modp,1);
120,888✔
497
        NEXTARG(a);
120,888✔
498
        
499
        if (a < astop) {
120,888✔
500
                den = poly::argument_to_poly(BHEAD a, true, !clean, &den_den);
120,888✔
501
                den.setmod(modp,1);
120,888✔
502
                NEXTARG(a);
120,888✔
503
        }
504
        else {
505
                den = poly(BHEAD 1, modp, 1);
×
506
        }
507

508
        if (a < astop) {
120,888✔
509
                MLOCK(ErrorMessageLock);
×
510
                MesPrint ((char*)"ERROR: PolyRatFun cannot have more than two arguments");
×
511
                MUNLOCK(ErrorMessageLock);
×
NEW
512
                TERMINATE(-1);
×
513
        }
514

515
        // JD: At this point, num and den are certainly sorted into the correct order by
516
        // poly::argument_to_poly, but we can't rely on the clean flag to know if there
517
        // are any negative powers. Check for them, and set clean = false if there are any.
518
        vector<WORD> minpower(AN.poly_num_vars, MAXPOSITIVE);
241,776✔
519

520
        for (int i=1; i<num[0]; i+=num[i]) {
780,890✔
521
                for (int j=0; j<AN.poly_num_vars; j++) {
2,169,484✔
522
                        minpower[j] = MiN(minpower[j], num[i+1+j]);
1,509,482✔
523
                }
524
        }
525
        for (int i=1; i<den[0]; i+=den[i]) {
848,879✔
526
                for (int j=0; j<AN.poly_num_vars; j++) {
2,404,571✔
527
                        minpower[j] = MiN(minpower[j], den[i+1+j]);
1,676,580✔
528
                        if ( minpower[j] < 0 ) clean = false;
1,676,580✔
529
                }
530
        }
531

532
        if (!clean) {
120,888✔
533
                for (int i=1; i<num[0]; i+=num[i])
219,368✔
534
                        for (int j=0; j<AN.poly_num_vars; j++)
614,220✔
535
                                num[i+1+j] -= minpower[j];
455,824✔
536
                for (int i=1; i<den[0]; i+=den[i])
208,356✔
537
                        for (int j=0; j<AN.poly_num_vars; j++)
524,872✔
538
                                den[i+1+j] -= minpower[j];
377,488✔
539

540
                num *= den_den;
60,972✔
541
                den *= den_num;
60,972✔
542

543
                poly gcd = polygcd::gcd(num,den);
121,944✔
544
                num /= gcd;
60,972✔
545
                den /= gcd;
60,972✔
546
        }
547
}
120,888✔
548

549
/*
550
          #] poly_ratfun_read : 
551
          #[ poly_sort :
552
*/
553

554
/**  Sort the polynomial terms
555
 *
556
 *   Description
557
 *   ===========
558
 *   Sorts the terms of a polynomial in Form poly(rat)fun order,
559
 *   i.e. lexicographical order with highest degree first.
560
 *
561
 *   Notes
562
 *   =====
563
 *   - Uses Form sort routines with custom compare
564
 */
565
void poly_sort(PHEAD WORD *a) {
45,800✔
566

567
#ifdef DEBUG
568
        cout << "*** [" << thetime() << "]  CALL : poly_sort" << endl;
569
#endif
570
        if (NewSort(BHEAD0)) { TERMINATE(-1); }
45,800✔
571
        AR.CompareRoutine = (COMPAREDUMMY)(&CompareSymbols);
45,800✔
572
        
573
        for (int i=ARGHEAD; i<a[0]; i+=a[i]) {
412,357✔
574
                if (SymbolNormalize(a+i)<0 || StoreTerm(BHEAD a+i)) {
366,557✔
575
                        AR.CompareRoutine = (COMPAREDUMMY)(&Compare1);
×
576
                        LowerSortLevel();
×
NEW
577
                        TERMINATE(-1);
×
578
                }
579
        }
580
        
581
        if (EndSort(BHEAD a+ARGHEAD,1) < 0) {
45,800✔
582
                AR.CompareRoutine = (COMPAREDUMMY)(&Compare1);
×
NEW
583
                TERMINATE(-1);
×
584
        }
585
        
586
        AR.CompareRoutine = (COMPAREDUMMY)(&Compare1);
45,800✔
587
        a[1] = 0; // set dirty flag to zero
45,800✔
588
}
45,800✔
589

590
/*
591
          #] poly_sort : 
592
          #[ poly_ratfun_add :
593
*/
594

595
/**  Addition of PolyRatFuns
596
 *
597
 *   Description
598
 *   ===========
599
 *   This method gets two pointers to polyratfuns with up to two
600
 *   arguments each and calculates the sum.
601
 *
602
 *   Notes
603
 *   =====
604
 *   - The result is written at the workpointer
605
 *   - Called from sort.c and threads.c
606
 *   - Calls poly::operators and polygcd::gcd
607
 */
608
WORD *poly_ratfun_add (PHEAD WORD *t1, WORD *t2) {
13,916✔
609
 
610
        if ( AR.PolyFunExp == 1 ) return PolyRatFunSpecial(BHEAD t1, t2);
13,916✔
611

612
#ifdef DEBUG
613
        cout << "*** [" << thetime() << "]  CALL : poly_ratfun_add" << endl;
614
#endif
615

616
        WORD *oldworkpointer = AT.WorkPointer;
13,916✔
617
        
618
        // Extract variables
619
        vector<WORD *> e;
27,832✔
620
        
621
        for (WORD *t=t1+FUNHEAD; t<t1+t1[1];) {
41,748✔
622
                e.push_back(t);
27,832✔
623
                NEXTARG(t);
27,832✔
624
        }
625
        for (WORD *t=t2+FUNHEAD; t<t2+t2[1];) {
41,748✔
626
                e.push_back(t);
27,832✔
627
                NEXTARG(t);
27,832✔
628
        }
629

630
        poly::get_variables(BHEAD e, true, true);
13,916✔
631
        
632
        // Check for modulus calculus
633
        WORD modp=poly_determine_modulus(BHEAD true, true, "PolyRatFun");
13,916✔
634
        
635
        // Find numerators / denominators
636
        poly num1(BHEAD 0,modp,1), den1(BHEAD 0,modp,1), num2(BHEAD 0,modp,1), den2(BHEAD 0,modp,1);
27,832✔
637

638
        poly_ratfun_read(t1, num1, den1);
13,916✔
639
        poly_ratfun_read(t2, num2, den2);
13,916✔
640

641
        poly num(BHEAD 0),den(BHEAD 0),gcd(BHEAD 0);
27,832✔
642

643
        // Calculate result
644
        if (den1 != den2) {
13,916✔
645
                gcd = polygcd::gcd(den1,den2);
3,941✔
646
#ifdef OLDADDITION
647
                num = num1*(den2/gcd) + num2*(den1/gcd);
648
                den = (den1/gcd)*den2;
649
                gcd = polygcd::gcd(num,den);
650
#else
651
                den = den1/gcd;
3,941✔
652
                num = num1*(den2/gcd) + num2*den;
3,941✔
653
                den = den*den2;
3,941✔
654
                gcd = polygcd::gcd(num,gcd);
3,941✔
655
#endif
656
        }
657
        else {
658
                num = num1 + num2;
9,975✔
659
                den = den1;
9,975✔
660
                gcd = polygcd::gcd(num,den);
9,975✔
661
        }
662

663
        num /= gcd;
13,916✔
664
        den /= gcd;
13,916✔
665
        
666
        // Fix sign
667
        if (den.sign() == -1) { num*=poly(BHEAD -1); den*=poly(BHEAD -1); }
13,916✔
668

669
        // Check size
670
        if (num.size_of_form_notation() + den.size_of_form_notation() + 3 >= AM.MaxTer/(int)sizeof(WORD)) {
13,916✔
671
                MLOCK(ErrorMessageLock);
×
672
                MesPrint ("ERROR: PolyRatFun doesn't fit in a term");
×
673
                MesPrint ("(1) num size = %d, den size = %d,  MaxTer = %d",num.size_of_form_notation(),
×
674
                                den.size_of_form_notation(),AM.MaxTer);
675
                MUNLOCK(ErrorMessageLock);
×
NEW
676
                TERMINATE(-1);
×
677
        }
678

679
        // Format result in Form notation
680
        WORD *t = oldworkpointer;
13,916✔
681

682
        *t++ = AR.PolyFun;                   // function 
13,916✔
683
        *t++ = 0;                            // length (to be determined)
13,916✔
684
//        *t++ &= ~MUSTCLEANPRF;               // clean polyratfun
685
        *t++ = 0;
13,916✔
686
        FILLFUN3(t);                         // header
13,916✔
687
        poly::poly_to_argument(num,t, true); // argument 1 (numerator)
13,916✔
688
        if (*t>0 && t[1]==DIRTYFLAG)          // to Form order
13,916✔
689
                poly_sort(BHEAD t);        
3,780✔
690
        t += (*t>0 ? *t : 2);
13,916✔
691
        poly::poly_to_argument(den,t, true); // argument 2 (denominator)
13,916✔
692
        if (*t>0 && t[1]==DIRTYFLAG)          // to Form order
13,916✔
693
                poly_sort(BHEAD t);        
3,604✔
694
        t += (*t>0 ? *t : 2);
13,916✔
695

696
        oldworkpointer[1] = t - oldworkpointer; // length
13,916✔
697
        AT.WorkPointer = t;
13,916✔
698

699
        poly_free_poly_vars(BHEAD "AN.poly_vars_ratfun_add");
13,916✔
700

701
        // reset modulo calculation
702
        AN.ncmod = AC.ncmod;
13,916✔
703
        
704
        return oldworkpointer;
13,916✔
705
}
706

707
/*
708
          #] poly_ratfun_add : 
709
          #[ poly_ratfun_normalize :
710
*/
711

712
/**  Multiplication/normalization of PolyRatFuns
713
 *
714
 *   Description
715
 *   ===========
716
 *   This method searches a term for multiple polyratfuns and
717
 *   multiplies their contents. The result is properly
718
 *   normalized. Normalization also works for terms with a single
719
 *   polyratfun.
720
 *
721
 *   Notes
722
 *   =====
723
 *   - The result overwrites the original term
724
 *   - Called from proces.c
725
 *   - Calls poly::operators and polygcd::gcd
726
 */
727
int poly_ratfun_normalize (PHEAD WORD *term) {
603,943✔
728

729
#ifdef DEBUG
730
        cout << "*** [" << thetime() << "]  CALL : poly_ratfun_normalize" << endl;
731
#endif
732
        
733
        // Strip coefficient
734
        WORD *tstop = term + *term;
603,943✔
735
        int ncoeff = tstop[-1];
603,943✔
736
        tstop -= ABS(ncoeff);
603,943✔
737

738
        // if only one clean polyratfun, return immediately
739
        int num_polyratfun = 0;
603,943✔
740

741
        for (WORD *t=term+1; t<tstop; t+=t[1]) 
1,009,142✔
742
                if (*t == AR.PolyFun) {
447,594✔
743
                        num_polyratfun++;
90,179✔
744
                        if ((t[2] & MUSTCLEANPRF) != 0)
90,179✔
745
                                num_polyratfun = INT_MAX;
746
                        if (num_polyratfun > 1) break;
51,796✔
747
                }
748
                
749
        if (num_polyratfun <= 1) return 0;
603,943✔
750

751
        WORD oldsorttype = AR.SortType;
42,395✔
752
        AR.SortType = SORTHIGHFIRST;
42,395✔
753

754
/*
755
        When there are polyratfun's with only one variable: rename them
756
        temporarily to TMPPOLYFUN.
757
*/
758
        for (WORD *t=term+1; t<tstop; t+=t[1]) {
182,226✔
759
                if (*t == AR.PolyFun && (t[1] == FUNHEAD+t[FUNHEAD]
139,831✔
760
                        || t[1] == FUNHEAD+2 ) ) { *t = TMPPOLYFUN; }
93,071✔
761
        }
762

763
        
764
        // Extract all variables in the polyfuns
765
        vector<WORD *> e;
646,335✔
766
        
767
        for (WORD *t=term+1; t<tstop; t+=t[1]) {
182,226✔
768
                if (*t == AR.PolyFun) 
139,831✔
769
                        for (WORD *t2 = t+FUNHEAD; t2<t+t[1];) {
279,177✔
770
                                e.push_back(t2);
186,118✔
771
                                NEXTARG(t2);
186,118✔
772
                        }                
773
        }
774
        poly::get_variables(BHEAD e, true, true);
42,395✔
775

776
        // Check for modulus calculus
777
        WORD modp=poly_determine_modulus(BHEAD true, true, "PolyRatFun");
42,392✔
778
        
779
        // Accumulate total denominator/numerator and copy the remaining terms
780
        // We start with 'trivial' polynomials
781
        poly num1(BHEAD (UWORD *)tstop, ncoeff/2, modp, 1);
84,784✔
782
        poly den1(BHEAD (UWORD *)tstop+ABS(ncoeff/2), ABS(ncoeff)/2, modp, 1);
42,392✔
783

784
        WORD *s = term+1;
785

786
        for (WORD *t=term+1; t<tstop;) 
182,220✔
787
                if (*t == AR.PolyFun) {
139,828✔
788

789
                        poly num2(BHEAD 0,modp,1);
186,112✔
790
                        poly den2(BHEAD 0,modp,1);
186,112✔
791
                        poly_ratfun_read(t,num2,den2);
93,056✔
792

793
                        if ((t[2] & MUSTCLEANPRF) != 0) { // first normalize
93,056✔
794
                                poly gcd1(polygcd::gcd(num2,den2));
57,996✔
795
                                num2 = num2/gcd1;
57,996✔
796
                                den2 = den2/gcd1;
57,996✔
797
                        }
798
                        t += t[1];
93,056✔
799
                        poly gcd1(polygcd::gcd(num1,den2));
186,112✔
800
                        poly gcd2(polygcd::gcd(num2,den1));
93,056✔
801

802
                        num1 = (num1 / gcd1) * (num2 / gcd2);
93,056✔
803
                        den1 = (den1 / gcd2) * (den2 / gcd1);
93,056✔
804
                }
805
                else {
806
                        int i = t[1];
46,772✔
807
                        if ( s != t ) {        NCOPY(s,t,i) }
378,020✔
808
                        else { t += i; s += i; }
16,024✔
809
                }                        
810

811
        // Fix sign
812
        if (den1.sign() == -1) { num1*=poly(BHEAD -1); den1*=poly(BHEAD -1); }
42,392✔
813

814
        // Check size
815
        if (num1.size_of_form_notation() + den1.size_of_form_notation() + 3 >= AM.MaxTer/(int)sizeof(WORD)) {
42,392✔
816
                MLOCK(ErrorMessageLock);
×
817
                MesPrint ("ERROR: PolyRatFun doesn't fit in a term");
×
818
                MesPrint ("(2) num size = %d, den size = %d,  MaxTer = %d",num1.size_of_form_notation(),
×
819
                                den1.size_of_form_notation(),AM.MaxTer);
820
                MUNLOCK(ErrorMessageLock);
×
NEW
821
                TERMINATE(-1);
×
822
        }
823

824
        // Format result in Form notation
825
        WORD *t = s;
42,392✔
826
        *t++ = AR.PolyFun;                   // function
42,392✔
827
        *t++ = 0;                            // size (to be determined)
42,392✔
828
        *t++ &= ~MUSTCLEANPRF;                   // clean polyratfun
42,392✔
829
        FILLFUN3(t);                         // header
42,392✔
830
        poly::poly_to_argument(num1,t,true); // argument 1 (numerator)
42,392✔
831
        if (*t>0 && t[1]==DIRTYFLAG)         // to Form order
42,392✔
832
                poly_sort(BHEAD t);
18,120✔
833
        t += (*t>0 ? *t : 2);
42,392✔
834
        poly::poly_to_argument(den1,t,true); // argument 2 (denominator)
42,392✔
835
        if (*t>0 && t[1]==DIRTYFLAG)         // to Form order
42,392✔
836
                poly_sort(BHEAD t);        
20,296✔
837
        t += (*t>0 ? *t : 2);
42,392✔
838

839
        s[1] = t - s;                        // function length
42,392✔
840

841
        *t++ = 1;                            // term coefficient
42,392✔
842
        *t++ = 1;
42,392✔
843
        *t++ = 3;
42,392✔
844
        
845
        term[0] = t-term;                    // term length
42,392✔
846

847
        poly_free_poly_vars(BHEAD "AN.poly_vars_ratfun_normalize");
42,392✔
848

849
        // reset modulo calculation
850
        AN.ncmod = AC.ncmod;
42,392✔
851

852
        tstop = term + *term; tstop -= ABS(tstop[-1]);
42,392✔
853
        for (WORD *t=term+1; t<tstop; t+=t[1]) {
131,556✔
854
                if (*t == TMPPOLYFUN ) *t = AR.PolyFun;
89,164✔
855
        }
856

857
        AR.SortType = oldsorttype;
42,392✔
858
        return 0;
42,392✔
859
}
860

861
/*
862
          #] poly_ratfun_normalize : 
863
          #[ poly_fix_minus_signs :
864
*/
865

866
void poly_fix_minus_signs (factorized_poly &a) {
363✔
867

868
        if ( a.factor.empty() ) return;
363✔
869

870
        POLY_GETIDENTITY(a.factor[0]);
191✔
871
        
872
        int overall_sign = +1;
191✔
873

874
        // find term with maximum power of highest symbol
875
        for (int i=0; i<(int)a.factor.size(); i++) {
1,017✔
876

877
                int maxvar = -1;
658✔
878
                int maxpow = -1;
658✔
879
                int sign = +1;
658✔
880

881
                WORD *tstop = a.factor[i].terms; tstop += *tstop;
658✔
882
                for (WORD *t=a.factor[i].terms+1; t<tstop; t+=*t) 
2,958✔
883
                        for (int j=0; j<AN.poly_num_vars; j++) {
13,268✔
884
                                int var = AN.poly_vars[j];
10,968✔
885
                                int pow = t[1+j];
10,968✔
886
                                if (pow>0 && (var>maxvar || (var==maxvar && pow>maxpow))) {
10,968✔
887
                                        maxvar = var;
925✔
888
                                        maxpow = pow;
925✔
889
                                        sign = SGN(*(t+*t-1));
925✔
890
                                }
891
                        }
892

893
                // if negative coefficient, multiply by -1
894
                if (sign==-1) {
658✔
895
                        a.factor[i] *= poly(BHEAD sign);
60✔
896
                        if (a.power[i] % 2 == 1) overall_sign*=-1;
60✔
897
                }
898
        }
899

900
        // if overall minus sign
901
        if (overall_sign == -1) {
359✔
902
                // look at constant factor and multiply by -1
903
                for (int i=0; i<(int)a.factor.size(); i++)
182✔
904
                        if (a.factor[i].is_integer()) {
131✔
905
                                a.factor[i] *= poly(BHEAD -1);
9✔
906
                                return;
9✔
907
                        }
908

909
                // otherwise, add a factor of -1
910
                a.add_factor(poly(BHEAD -1), 1);
51✔
911
        }
912
}
913

914
/*
915
          #] poly_fix_minus_signs : 
916
          #[ poly_factorize :
917
*/
918

919
/**  Factorization of function arguments / dollars
920
 *
921
 *   Description
922
 *   ===========
923
 *   This method factorizes a Form style argument or zero-terminated
924
 *   term list.
925
 *
926
 *   Notes
927
 *   =====
928
 *   - Called from poly_factorize_{argument,dollar}
929
 *   - Calls polyfact::factorize
930
 */
931
WORD *poly_factorize (PHEAD WORD *argin, WORD *argout, bool with_arghead, bool is_fun_arg) {
267✔
932

933
#ifdef DEBUG
934
        cout << "*** [" << thetime() << "]  CALL : poly_factorize" << endl;
935
#endif
936
        
937
        poly::get_variables(BHEAD vector<WORD*>(1,argin), with_arghead, true);
267✔
938
        poly den(BHEAD 0);
534✔
939
         poly a(poly::argument_to_poly(BHEAD argin, with_arghead, true, &den));
534✔
940

941
        // check for modulus calculus
942
        WORD modp=poly_determine_modulus(BHEAD true, is_fun_arg, "polynomial factorization");
267✔
943
        a.setmod(modp,1);
267✔
944

945
        // factorize
946
        factorized_poly f(polyfact::factorize(a));
534✔
947
        poly_fix_minus_signs(f);
267✔
948

949
        poly num(BHEAD 1);
267✔
950
        for (int i=0; i<(int)f.factor.size(); i++)
704✔
951
                if (f.factor[i].is_integer())
437✔
952
                        num = f.factor[i];        
60✔
953
        
954
        // determine size
955
        int len = with_arghead ? ARGHEAD : 0;
267✔
956

957
        if (!num.is_one() || !den.is_one()) {
267✔
958
                len++;
51✔
959
                len += MaX(ABS(num[num[1]]), den[den[1]])*2+1;
51✔
960
                len += with_arghead ? ARGHEAD : 1;
94✔
961
        }
962
        
963
        for (int i=0; i<(int)f.factor.size(); i++) {
704✔
964
                if (!f.factor[i].is_integer()) {
437✔
965
                        len += f.power[i] * f.factor[i].size_of_form_notation();
377✔
966
                        len += f.power[i] * (with_arghead ? ARGHEAD : 1);
521✔
967
                }
968
        }
969
        
970
        len++;
267✔
971
        
972
        if (argout != NULL) {
267✔
973
                // check size
974
                if (len >= AM.MaxTer) {
204✔
975
                        MLOCK(ErrorMessageLock);
×
976
                        MesPrint ("ERROR: factorization doesn't fit in a term");
×
977
                        MUNLOCK(ErrorMessageLock);
×
NEW
978
                        TERMINATE(-1);
×
979
                }
980
        }
981
        else {
982
                // allocate size
983
                argout = (WORD*) Malloc1(len*sizeof(WORD), "poly_factorize");
63✔
984
        }
985

986
        WORD *old_argout = argout;
267✔
987

988
        // constant factor
989
        if (!num.is_one() || !den.is_one()) {
267✔
990
                int n = max(ABS(num[num[1]]), ABS(den[den[1]]));
51✔
991

992
                if (with_arghead) {
51✔
993
                        *argout++ = ARGHEAD + 2 + 2*n;
8✔
994
                        for (int i=1; i<ARGHEAD; i++)
16✔
995
                                *argout++ = 0;
8✔
996
                }
997
                
998
                *argout++ = 2 + 2*n;
51✔
999
                
1000
                for (int i=0; i<n; i++) 
102✔
1001
                        *argout++ = i<ABS(num[num[1]]) ? num[2+AN.poly_num_vars+i] : 0;
51✔
1002
                for (int i=0; i<n; i++) 
102✔
1003
                        *argout++ = i<ABS(den[den[1]]) ? den[2+AN.poly_num_vars+i] : 0;
51✔
1004

1005
                *argout++ = SGN(num[num[1]]) * (2*n+1);
51✔
1006

1007
                if (!with_arghead)
51✔
1008
                        *argout++ = 0;
43✔
1009
                else {
1010
                        if (ToFast(old_argout, old_argout))
8✔
1011
                                argout = old_argout+2;
8✔
1012
                }
1013
        }
1014

1015
        // non-constant factors
1016
        for (int i=0; i<(int)f.factor.size(); i++)
704✔
1017
                if (!f.factor[i].is_integer()) 
437✔
1018
                        for (int j=0; j<f.power[i]; j++) {                        
763✔
1019
                                poly::poly_to_argument(f.factor[i],argout,with_arghead);
386✔
1020
                                
1021
                                if (with_arghead)
386✔
1022
                                        argout += *argout > 0 ? *argout : 2;
236✔
1023
                                else {
1024
                                        while (*argout!=0) argout+=*argout;
792✔
1025
                                        argout++;
150✔
1026
                                }
1027
                        }
1028
        
1029
        *argout=0;
267✔
1030

1031
        poly_free_poly_vars(BHEAD "AN.poly_vars_factorize");
267✔
1032

1033
        // reset modulo calculation
1034
        AN.ncmod = AC.ncmod;
267✔
1035
        
1036
        return old_argout;
534✔
1037
}
1038

1039
/*
1040
          #] poly_factorize : 
1041
          #[ poly_factorize_argument :
1042
*/
1043
 
1044
/**  Factorization of function arguments
1045
 *
1046
 *   Description
1047
 *   ===========
1048
 *   This method factorizes the Form-style argument argin.
1049
 *
1050
 *   Notes
1051
 *   =====
1052
 *   - The result is written at argout
1053
 *   - Called from argument.c
1054
 *   - Calls poly_factorize
1055
 */
1056
int poly_factorize_argument(PHEAD WORD *argin, WORD *argout) {
204✔
1057

1058
#ifdef DEBUG
1059
        cout << "*** [" << thetime() << "]  CALL : poly_factorize_argument" << endl;
1060
#endif
1061

1062
        poly_factorize(BHEAD argin,argout,true,true);
204✔
1063
        return 0;
204✔
1064
}
1065

1066
/*
1067
          #] poly_factorize_argument : 
1068
          #[ poly_factorize_dollar :
1069
*/
1070

1071
/**  Factorization of dollar variables
1072
 *
1073
 *   Description
1074
 *   ===========
1075
 *   This method factorizes a dollar variable.
1076
 *
1077
 *   Notes
1078
 *   =====
1079
 *   - The result is written at newly allocated memory.
1080
 *   - Called from dollar.c
1081
 *   - Calls poly_factorize
1082
 */
1083
WORD *poly_factorize_dollar (PHEAD WORD *argin) {
63✔
1084

1085
#ifdef DEBUG
1086
        cout << "*** [" << thetime() << "]  CALL : poly_factorize_dollar" << endl;
1087
#endif
1088

1089
        return poly_factorize(BHEAD argin,NULL,false,false);
63✔
1090
}
1091

1092
/*
1093
          #] poly_factorize_dollar : 
1094
          #[ poly_factorize_expression :
1095
*/
1096

1097
/**  Factorization of expressions
1098
 *
1099
 *   Description
1100
 *   ===========
1101
 *   This method factorizes an expression.
1102
 *
1103
 *   Notes
1104
 *   =====
1105
 *   - The result overwrites the input expression
1106
 *   - Called from proces.c
1107
 *   - Calls polyfact::factorize
1108
 */
1109
int poly_factorize_expression(EXPRESSIONS expr) {
36✔
1110

1111
#ifdef DEBUG
1112
        cout << "*** [" << thetime() << "]  CALL : poly_factorize_expression" << endl;
1113
#endif
1114

1115
        GETIDENTITY;
36✔
1116

1117
        if (AT.WorkPointer + AM.MaxTer > AT.WorkTop ) {
36✔
1118
                MLOCK(ErrorMessageLock);
×
1119
                MesWork();
×
1120
                MUNLOCK(ErrorMessageLock);
×
NEW
1121
                TERMINATE(-1);
×
1122
        }
1123
        
1124
        WORD *term = AT.WorkPointer;
36✔
1125
        WORD startebuf = cbuf[AT.ebufnum].numrhs;
36✔
1126
        FILEHANDLE *file;
36✔
1127
        POSITION pos;
36✔
1128

1129
        FILEHANDLE *oldinfile = AR.infile;
36✔
1130
        FILEHANDLE *oldoutfile = AR.outfile;
36✔
1131
        WORD oldBracketOn = AR.BracketOn;
36✔
1132
        WORD *oldBrackBuf = AT.BrackBuf;
36✔
1133
        WORD oldbracketindexflag = AT.bracketindexflag;
36✔
1134
        char oldCommercial[COMMERCIALSIZE+2];
36✔
1135

1136
        strcpy(oldCommercial, (char*)AC.Commercial);
36✔
1137
        strcpy((char*)AC.Commercial, "factorize");
36✔
1138

1139
        // locate is the input        
1140
        if (expr->status == HIDDENGEXPRESSION || expr->status == HIDDENLEXPRESSION ||
36✔
1141
                        expr->status == INTOHIDEGEXPRESSION || expr->status == INTOHIDELEXPRESSION) {
36✔
1142
                AR.InHiBuf = 0; file = AR.hidefile; AR.GetFile = 2;
×
1143
        }
1144
        else {
1145
                AR.InInBuf = 0; file = AR.outfile; AR.GetFile = 0;
36✔
1146
        }
1147

1148
        // read and write to expression file
1149
        AR.infile = AR.outfile = file;
36✔
1150
        
1151
        // dummy indices are not allowed
1152
        if (expr->numdummies > 0) {
36✔
1153
                MesPrint("ERROR: factorization with dummy indices not implemented");
×
NEW
1154
                TERMINATE(-1);
×
1155
        }
1156

1157
        // determine whether the expression in on file or in memory
1158
        if (file->handle >= 0) {
36✔
1159
                pos = expr->onfile;
×
1160
                SeekFile(file->handle,&pos,SEEK_SET);
×
1161
                if (ISNOTEQUALPOS(pos,expr->onfile)) {
×
1162
                        MesPrint("ERROR: something wrong in scratch file [poly_factorize_expression]");
×
NEW
1163
                        TERMINATE(-1);
×
1164
                }
1165
                file->POposition = expr->onfile;
×
1166
                file->POfull = file->PObuffer;
×
1167
                if (expr->status == HIDDENGEXPRESSION)
×
1168
                        AR.InHiBuf = 0;
×
1169
                else
1170
                        AR.InInBuf = 0;
×
1171
        }
1172
        else {
1173
                file->POfill = (WORD *)((UBYTE *)(file->PObuffer)+BASEPOSITION(expr->onfile));
36✔
1174
        }
1175
         
1176
        SetScratch(AR.infile, &(expr->onfile));
36✔
1177

1178
        // read the first header term
1179
        WORD size = GetTerm(BHEAD term);
36✔
1180
        if (size <= 0) {
36✔
1181
                MesPrint ("ERROR: something wrong with expression [poly_factorize_expression]");
×
NEW
1182
                TERMINATE(-1);
×
1183
        }
1184

1185
        // store position: this is where the output will go
1186
        pos = expr->onfile;
36✔
1187
        ADDPOS(pos, size*sizeof(WORD));
36✔
1188
        
1189
        // use polynomial as buffer, because it is easy to extend
1190
        poly buffer(BHEAD 0);
72✔
1191
        int bufpos = 0;
1192
        int sumcommu = 0;
1193

1194
        // read all terms
1195
        while (GetTerm(BHEAD term)) {
248✔
1196
                // substitute non-symbols by extra symbols
1197
                sumcommu += DoesCommu(term);
212✔
1198
                if ( sumcommu > 1 ) {
212✔
1199
                        MesPrint("ERROR: Cannot factorize an expression with more than one noncommuting object");
×
NEW
1200
                        TERMINATE(-1);
×
1201
                }
1202
                buffer.check_memory(bufpos);                
212✔
1203
                if (LocalConvertToPoly(BHEAD term, buffer.terms + bufpos, startebuf,0) < 0) {
212✔
1204
                        MesPrint("ERROR: in LocalConvertToPoly [factorize_expression]");
×
NEW
1205
                        TERMINATE(-1);
×
1206
                }
1207
                bufpos += *(buffer.terms + bufpos);
212✔
1208
        }
1209
        buffer[bufpos] = 0;
36✔
1210

1211
        // parse the polynomial
1212
                         
1213
        AN.poly_num_vars = 0;
36✔
1214
        poly::get_variables(BHEAD vector<WORD*>(1,buffer.terms), false, true);
36✔
1215
        poly den(BHEAD 0);
72✔
1216
        poly a(poly::argument_to_poly(BHEAD buffer.terms, false, true, &den));
72✔
1217

1218
        // check for modulus calculus
1219
         WORD modp=poly_determine_modulus(BHEAD true, false, "polynomial factorization");
36✔
1220
        a.setmod(modp,1);
36✔
1221

1222
        // create output
1223
        SetScratch(file, &pos);
36✔
1224
        NewSort(BHEAD0);        
36✔
1225
        
1226
        CBUF *C = cbuf+AC.cbufnum;
36✔
1227
        CBUF *CC = cbuf+AT.ebufnum;
36✔
1228
        
1229
        // turn brackets on. We force the existence of a bracket index.
1230
        WORD nexpr = expr - Expressions;
36✔
1231
        AR.BracketOn = 1;
36✔
1232
        AT.BrackBuf = AM.BracketFactors;
36✔
1233
        AT.bracketindexflag = 1;
36✔
1234
        ClearBracketIndex(-nexpr-2); // Clears the index made during primary generation
36✔
1235
        OpenBracketIndex(nexpr);     // Set up a new index
36✔
1236
                
1237
        if (a.is_zero()) {
36✔
1238
                expr->numfactors = 1;
4✔
1239
        }
1240
        else if (a.is_one() && den.is_one()) {
32✔
1241
                expr->numfactors = 1;
4✔
1242
                
1243
                term[0] = 8;
4✔
1244
                term[1] = SYMBOL;
4✔
1245
                term[2] = 4;
4✔
1246
                term[3] = FACTORSYMBOL;
4✔
1247
                term[4] = 1;
4✔
1248
                term[5] = 1;
4✔
1249
                term[6] = 1;
4✔
1250
                term[7] = 3;
4✔
1251

1252
                AT.WorkPointer += *term;
4✔
1253
                Generator(BHEAD term, C->numlhs);
4✔
1254
                AT.WorkPointer = term;
4✔
1255
        }
1256
        else {
1257
                factorized_poly fac;
56✔
1258
                bool iszero = false;
28✔
1259
                
1260
                if (!(expr->vflags & ISFACTORIZED)) {
28✔
1261
                        // factorize the polynomial
1262
                        fac = polyfact::factorize(a);
40✔
1263
                        poly_fix_minus_signs(fac);
20✔
1264
                }
1265
                else {
1266
                        int factorsymbol=-1;
1267
                        for (int i=0; i<AN.poly_num_vars; i++)
24✔
1268
                                if (AN.poly_vars[i] == FACTORSYMBOL)
16✔
1269
                                        factorsymbol = i;
8✔
1270

1271
                        poly denpow(BHEAD 1);
16✔
1272
                        
1273
                        // already factorized, so factorize the factors
1274
                        for (int i=1; i<=expr->numfactors; i++) {
92✔
1275
                                poly origfac(a.coefficient(factorsymbol, i));
168✔
1276
                                factorized_poly fac2;
168✔
1277
                                if (origfac.is_zero())
84✔
1278
                                        iszero=true;
1279
                                else {
1280
                                        fac2 = polyfact::factorize(origfac);
152✔
1281
                                        poly_fix_minus_signs(fac2);
76✔
1282
                                        denpow *= den;
76✔
1283
                                }
1284
                                for (int j=0; j<(int)fac2.power.size(); j++)
212✔
1285
                                        fac.add_factor(fac2.factor[j], fac2.power[j]);
128✔
1286
                        }
1287

1288
                        // update denominator, since each factor was scaled
1289
                        den=denpow;
8✔
1290
                }
1291

1292
                expr->numfactors = 0;
28✔
1293
                
1294
                // coefficient
1295
                poly num(BHEAD 1);                
56✔
1296
                for (int i=0; i<(int)fac.factor.size(); i++) 
300✔
1297
                        if (fac.factor[i].is_integer())
272✔
1298
                                num *= fac.factor[i];
48✔
1299

1300
                poly gcd(polygcd::integer_gcd(num,den));
56✔
1301
                den/=gcd;
28✔
1302
                num/=gcd;
28✔
1303

1304
                if (iszero) 
28✔
1305
                        expr->numfactors++;
4✔
1306

1307
                if (!iszero || (expr->vflags & KEEPZERO)) {
28✔
1308
                        if (!num.is_one() || !den.is_one()) {
28✔
1309
                                expr->numfactors++;
16✔
1310
                                
1311
                                int n = max(ABS(num[num[1]]), ABS(den[den[1]]));
16✔
1312
                                
1313
                                term[0] = 6 + 2*n;
16✔
1314
                                term[1] = SYMBOL;
16✔
1315
                                term[2] = 4;
16✔
1316
                                term[3] = FACTORSYMBOL;
16✔
1317
                                term[4] = expr->numfactors;
16✔
1318
                                for (int i=0; i<n; i++) {
32✔
1319
                                        term[5+i]   = i<ABS(num[num[1]]) ? num[2+AN.poly_num_vars+i] : 0;
16✔
1320
                                        term[5+n+i] = i<ABS(den[den[1]]) ? den[2+AN.poly_num_vars+i] : 0;
16✔
1321
                                }
1322
                                term[5+2*n] = SGN(num[num[1]]) * (2*n+1);
16✔
1323
                                AT.WorkPointer += *term;
16✔
1324
                                Generator(BHEAD term, C->numlhs);
16✔
1325
                                AT.WorkPointer = term;
16✔
1326
                        }
1327

1328
                        vector<poly> fac_arg(fac.factor.size(), poly(BHEAD 0));
56✔
1329
                        
1330
                        // convert the non-constant factors to Form-style arguments
1331
                        for (int i=0; i<(int)fac.factor.size(); i++)
300✔
1332
                                if (!fac.factor[i].is_integer()) {
272✔
1333
                                        buffer.check_memory(fac.factor[i].size_of_form_notation()+1);                
224✔
1334
                                        poly::poly_to_argument(fac.factor[i], buffer.terms, false);
224✔
1335
                                        NewSort(BHEAD0);
224✔
1336
                                        
1337
                                        for (WORD *t=buffer.terms; *t!=0; t+=*t) {
888✔
1338
                                                // substitute extra symbols
1339
                                                if (ConvertFromPoly(BHEAD t, term, numxsymbol, CC->numrhs-startebuf+numxsymbol,
664✔
1340
                                                                                                                                startebuf-numxsymbol, 1) <= 0 ) {
664✔
1341
                                                        MesPrint("ERROR: in ConvertFromPoly [factorize_expression]");
×
NEW
1342
                                                        TERMINATE(-1);
×
1343
                                                        return(-1);
×
1344
                                                }
1345
                                                
1346
                                                // store term
1347
                                                AT.WorkPointer += *term;
664✔
1348
                                                Generator(BHEAD term, C->numlhs);
664✔
1349
                                                AT.WorkPointer = term;
664✔
1350
                                        }
1351

1352
                                        // sort and store in buffer
1353
                                        WORD *buffer;
224✔
1354
                                        if (EndSort(BHEAD (WORD *)((VOID *)(&buffer)),2) < 0) return -1;
224✔
1355
                                        
1356
                                        LONG bufsize=0;
224✔
1357
                                        for (WORD *t=buffer; *t!=0; t+=*t)
888✔
1358
                                                bufsize+=*t;
664✔
1359
                                        
1360
                                        fac_arg[i].check_memory(bufsize+ARGHEAD+1);
224✔
1361

1362
                                        for (int j=0; j<ARGHEAD; j++)
672✔
1363
                                                fac_arg[i].terms[j] = 0;
448✔
1364
                                        fac_arg[i].terms[0] = ARGHEAD + bufsize;
224✔
1365
                                        WCOPY(fac_arg[i].terms+ARGHEAD, buffer, bufsize);
5,192✔
1366
                                        M_free(buffer, "polynomial factorization");
224✔
1367
                                }
1368
                
1369
                        // compare and sort the factors in Form notation
1370
                        vector<int> order;
56✔
1371
                        vector<vector<int> > comp(fac.factor.size(), vector<int>(fac.factor.size(), 0));
56✔
1372
                        
1373
                        for (int i=0; i<(int)fac.factor.size(); i++)
300✔
1374
                                if (!fac.factor[i].is_integer()) {
272✔
1375
                                        order.push_back(i);
224✔
1376
                                        
1377
                                        for (int j=i+1; j<(int)fac.factor.size(); j++)
1,652✔
1378
                                                if (!fac.factor[j].is_integer()) {                                                
1,428✔
1379
                                                        comp[i][j] = CompArg(fac_arg[j].terms, fac_arg[i].terms);
1,272✔
1380
                                                        comp[j][i] = -comp[i][j];
1,272✔
1381
                                                }
1382
                                }
1383
                        
1384
                        for (int i=0; i<(int)order.size(); i++) 
252✔
1385
                                for (int j=0; j+1<(int)order.size(); j++)
2,768✔
1386
                                        if (comp[order[i]][order[j]] == 1)
2,544✔
1387
                                                swap(order[i],order[j]);                
3,072✔
1388
                        
1389
                        // create the final expression
1390
                        for (int i=0; i<(int)order.size(); i++)
252✔
1391
                                for (int j=0; j<fac.power[order[i]]; j++) {
448✔
1392
                                        
1393
                                        expr->numfactors++;
224✔
1394
                                        
1395
                                        WORD *tstop = fac_arg[order[i]].terms + *fac_arg[order[i]].terms;
224✔
1396
                                        for (WORD *t=fac_arg[order[i]].terms+ARGHEAD; t<tstop; t+=*t) {
888✔
1397
                                                
1398
                                                WCOPY(term+4, t, *t);
5,632✔
1399
                                                
1400
                                                // add special symbol "factor_"
1401
                                                *term = *(term+4) + 4;
664✔
1402
                                                *(term+1) = SYMBOL;
664✔
1403
                                                *(term+2) = 4;
664✔
1404
                                                *(term+3) = FACTORSYMBOL;
664✔
1405
                                                *(term+4) =        expr->numfactors;
664✔
1406
                                                
1407
                                                // store term
1408
                                                AT.WorkPointer += *term;
664✔
1409
                                                Generator(BHEAD term, C->numlhs);
664✔
1410
                                                AT.WorkPointer = term;
664✔
1411
                                        }                                
1412
                                }
1413
                }
1414
        }
1415
        
1416
        // final sorting
1417
        if (EndSort(BHEAD NULL,0) < 0) {
36✔
1418
                LowerSortLevel();
×
NEW
1419
                TERMINATE(-1);
×
1420
        }
1421

1422
        // set factorized flag
1423
        if (expr->numfactors > 0) 
36✔
1424
                expr->vflags |= ISFACTORIZED;
36✔
1425

1426
        // clean up
1427
        AR.infile = oldinfile;
36✔
1428
        AR.outfile = oldoutfile;
36✔
1429
        AR.BracketOn = oldBracketOn;
36✔
1430
        AT.BrackBuf = oldBrackBuf;
36✔
1431
        AT.bracketindexflag = oldbracketindexflag;
36✔
1432
        strcpy((char*)AC.Commercial, oldCommercial);
36✔
1433
        
1434
        poly_free_poly_vars(BHEAD "AN.poly_vars_factorize_expression");
36✔
1435

1436
        return 0;
1437
}
1438

1439
/*
1440
          #] poly_factorize_expression : 
1441
          #[ poly_unfactorize_expression :
1442
*/
1443

1444
/**  Unfactorization of expressions
1445
 *
1446
 *   Description
1447
 *   ===========
1448
 *   This method expands a factorized expression.
1449
 *
1450
 *   Notes
1451
 *   =====
1452
 *   - The result overwrites the input expression
1453
 *   - Called from proces.c
1454
 */
1455

1456
#if ( SUBEXPSIZE == 5 )
1457
static WORD genericterm[] = {38,1,4,FACTORSYMBOL,0
1458
        ,EXPRESSION,15,0,1,0,13,10,8,1,4,FACTORSYMBOL,0,1,1,3
1459
        ,EXPRESSION,15,0,1,0,13,10,8,1,4,FACTORSYMBOL,0,1,1,3
1460
        ,1,1,3,0};
1461
static WORD genericterm2[] = {23,1,4,FACTORSYMBOL,0
1462
        ,EXPRESSION,15,0,1,0,13,10,8,1,4,FACTORSYMBOL,0,1,1,3
1463
        ,1,1,3,0};
1464
#endif
1465

1466
int poly_unfactorize_expression(EXPRESSIONS expr)
4✔
1467
{
1468
        GETIDENTITY;
4✔
1469
        int i, j, nfac = expr->numfactors, nfacp, nexpr = expr - Expressions;
4✔
1470
        int expriszero = 0;
4✔
1471
 
1472
        FILEHANDLE *oldinfile = AR.infile;
4✔
1473
        FILEHANDLE *oldoutfile = AR.outfile;
4✔
1474
        char oldCommercial[COMMERCIALSIZE+2];
4✔
1475

1476
        WORD *oldworkpointer = AT.WorkPointer;        
4✔
1477
        WORD *term = AT.WorkPointer, *t, *w, size;
4✔
1478
        
1479
        FILEHANDLE *file;
4✔
1480
        POSITION pos, oldpos;
4✔
1481

1482
        WORD oldBracketOn = AR.BracketOn;
4✔
1483
        WORD *oldBrackBuf = AT.BrackBuf;
4✔
1484
        CBUF *C = cbuf+AC.cbufnum;
4✔
1485

1486
        if ( ( expr->vflags & ISFACTORIZED ) == 0 ) return(0);
4✔
1487

1488
        if ( AT.WorkPointer + AM.MaxTer > AT.WorkTop ) {
4✔
1489
                MLOCK(ErrorMessageLock);
×
1490
                MesWork();
×
1491
                MUNLOCK(ErrorMessageLock);
×
NEW
1492
                TERMINATE(-1);
×
1493
        }
1494

1495
        oldpos = AS.OldOnFile[nexpr];
4✔
1496
        AS.OldOnFile[nexpr] = expr->onfile;
4✔
1497

1498
        strcpy(oldCommercial, (char*)AC.Commercial);
4✔
1499
        strcpy((char*)AC.Commercial, "unfactorize");
4✔
1500
/*
1501
        locate the input        
1502
*/
1503
        if ( expr->status == HIDDENGEXPRESSION || expr->status == HIDDENLEXPRESSION ||
4✔
1504
                        expr->status == INTOHIDEGEXPRESSION || expr->status == INTOHIDELEXPRESSION ) {
4✔
1505
                AR.InHiBuf = 0; file = AR.hidefile; AR.GetFile = 2;
×
1506
        }
1507
        else {
1508
                AR.InInBuf = 0; file = AR.outfile; AR.GetFile = 0;
4✔
1509
        }
1510
/*
1511
        read and write to expression file
1512
*/
1513
        AR.infile = AR.outfile = file;
4✔
1514
/*
1515
        set the input file to the correct position        
1516
*/
1517
        if ( file->handle >= 0 ) {
4✔
1518
                pos = expr->onfile;
×
1519
                SeekFile(file->handle,&pos,SEEK_SET);
×
1520
                if (ISNOTEQUALPOS(pos,expr->onfile)) {
×
1521
                        MesPrint("ERROR: something wrong in scratch file unfactorize_expression");
×
NEW
1522
                        TERMINATE(-1);
×
1523
                }
1524
                file->POposition = expr->onfile;
×
1525
                file->POfull = file->PObuffer;
×
1526
                if ( expr->status == HIDDENGEXPRESSION )
×
1527
                        AR.InHiBuf = 0;
×
1528
                else
1529
                        AR.InInBuf = 0;
×
1530
        }
1531
        else {
1532
                file->POfill = (WORD *)((UBYTE *)(file->PObuffer)+BASEPOSITION(expr->onfile));
4✔
1533
        }
1534
        SetScratch(AR.infile, &(expr->onfile));
4✔
1535
/*
1536
        Test for whether the first factor is zero.
1537
*/
1538
        if ( GetFirstBracket(term,nexpr) < 0 ) TERMINATE(-1);
4✔
1539
        if ( term[4] != 1 || *term != 8 || term[1] != SYMBOL || term[3] != FACTORSYMBOL || term[4] != 1 ) {
4✔
1540
                expriszero = 1;
×
1541
        }
1542
        SetScratch(AR.infile, &(expr->onfile));
4✔
1543
/*
1544
        Read the prototype. After this we have the file ready for the output at pos.
1545
*/
1546
        size = GetTerm(BHEAD term);
4✔
1547
        if ( size <= 0 ) {
4✔
1548
                MesPrint ("ERROR: something wrong with expression unfactorize_expression");
×
NEW
1549
                TERMINATE(-1);
×
1550
        }
1551
        pos = expr->onfile;
4✔
1552
        ADDPOS(pos, size*sizeof(WORD));
4✔
1553
/*
1554
        Set the brackets straight
1555
*/
1556
        AR.BracketOn = 1;
4✔
1557
        AT.BrackBuf = AM.BracketFactors;
4✔
1558
        AT.bracketinfo = 0;
4✔
1559
        while ( nfac > 2 ) {
8✔
1560
                nfacp = nfac - nfac%2;
4✔
1561
/*
1562
                Prepare the bracket index. We have:
1563
                        e->bracketinfo:    the old input bracket index
1564
                        e->newbracketinfo: the bracket index made for our current input
1565
                We need to keep e->bracketinfo in case other workers need it (InParallel)
1566
                Hence we work with AT.bracketinfo which takes priority.
1567
                Note that in Processor we forced a newbracketinfo to be made.
1568
*/
1569
                if ( AT.bracketinfo != 0 ) ClearBracketIndex(-1);
4✔
1570
                AT.bracketinfo = expr->newbracketinfo;
4✔
1571
                OpenBracketIndex(nexpr);
4✔
1572
/*
1573
                Now emulate the terms:
1574
                        sum_(i,0,nfacp,2,factor_^(i/2+1)*F[factor_^(i+1)]*F[factor_^(i+2)])
1575
                        +factor_^(nfacp/2+1)*F[factor_^nfac]
1576
*/
1577
                NewSort(BHEAD0);
4✔
1578
                if ( expriszero == 0 ) {
4✔
1579
                        for ( i = 0; i < nfacp; i += 2 ) {
8✔
1580
                                t = genericterm; w = term = oldworkpointer;
4✔
1581
                                j = *t; NCOPY(w,t,j);
156✔
1582
                                term[4] = i/2+1;
4✔
1583
                                term[7] = nexpr;
4✔
1584
                                term[16] = i+1;
4✔
1585
                                term[22] = nexpr;
4✔
1586
                                term[31] = i+2;
4✔
1587
                                AT.WorkPointer = term + *term;
4✔
1588
                                Generator(BHEAD term, C->numlhs);
4✔
1589
                        }
1590
                        if ( nfac > nfacp ) {
4✔
1591
                                t = genericterm2; w = term = oldworkpointer;
4✔
1592
                                j = *t; NCOPY(w,t,j);
96✔
1593
                                term[4] = i/2+1;
4✔
1594
                                term[7] = nexpr;
4✔
1595
                                term[16] = nfac;
4✔
1596
                                AT.WorkPointer = term + *term;
4✔
1597
                                Generator(BHEAD term, C->numlhs);
4✔
1598
                        }
1599
                }
1600
                if ( EndSort(BHEAD AM.S0->sBuffer,0) < 0 ) {
4✔
1601
                        LowerSortLevel();
×
NEW
1602
                        TERMINATE(-1);
×
1603
                }
1604
/*
1605
                Set the file back into reading position
1606
*/
1607
                SetScratch(file, &pos);
4✔
1608
                nfac = (nfac+1)/2;
4✔
1609
                if ( expriszero ) { nfac = 1; }
4✔
1610
        }
1611
        if ( AT.bracketinfo != 0 ) ClearBracketIndex(-1);
4✔
1612
        AT.bracketinfo = expr->newbracketinfo;
4✔
1613
        expr->newbracketinfo = 0;
4✔
1614
/*
1615
        Reset the brackets to make them ready for the final pass
1616
*/
1617
        AR.BracketOn = oldBracketOn;
4✔
1618
        AT.BrackBuf = oldBrackBuf;
4✔
1619
        if ( AR.BracketOn ) OpenBracketIndex(nexpr);
4✔
1620
/*
1621
        We distinguish two cases: nfac == 2 and nfac == 1
1622
        After preparing the term we skip the factor_ part.
1623
*/
1624
        NewSort(BHEAD0);
4✔
1625
        if ( expriszero == 0 ) {
4✔
1626
                if ( nfac == 1 ) {
4✔
1627
                        t = genericterm2; w = term = oldworkpointer;
×
1628
                        j = *t; NCOPY(w,t,j);
×
1629
                        term[7] = nexpr;
×
1630
                        term[16] = nfac;
×
1631
                }
1632
                else if ( nfac == 2 ) {
4✔
1633
                        t = genericterm; w = term = oldworkpointer;
4✔
1634
                        j = *t; NCOPY(w,t,j);
156✔
1635
                        term[7] = nexpr;
4✔
1636
                        term[16] = 1;
4✔
1637
                        term[22] = nexpr;
4✔
1638
                        term[31] = 2;
4✔
1639
                }
1640
                else {
1641
                        AS.OldOnFile[nexpr] = oldpos;
×
1642
                        return(-1);
×
1643
                }
1644
                term[4] = term[0]-4;
4✔
1645
                term += 4;
4✔
1646
                AT.WorkPointer = term + *term;
4✔
1647
                Generator(BHEAD term, C->numlhs);
4✔
1648
        }
1649
        if ( EndSort(BHEAD AM.S0->sBuffer,0) < 0 ) {
4✔
1650
                LowerSortLevel();
×
NEW
1651
                TERMINATE(-1);
×
1652
        }
1653
/*
1654
        Final Cleanup
1655
*/
1656
        expr->numfactors = 0;
4✔
1657
        expr->vflags &= ~ISFACTORIZED;
4✔
1658
        if ( AT.bracketinfo != 0 ) ClearBracketIndex(-1);
4✔
1659

1660
        AR.infile = oldinfile;
4✔
1661
        AR.outfile = oldoutfile;
4✔
1662
        strcpy((char*)AC.Commercial, oldCommercial);
4✔
1663
        AT.WorkPointer = oldworkpointer;
4✔
1664
        AS.OldOnFile[nexpr] = oldpos;
4✔
1665
        
1666
        return(0);
4✔
1667
}
1668

1669
/*
1670
          #] poly_unfactorize_expression : 
1671
          #[ poly_inverse : 
1672
*/
1673

1674
WORD *poly_inverse(PHEAD WORD *arga, WORD *argb) {
×
1675

1676
#ifdef DEBUG
1677
        cout << "*** [" << thetime() << "]  CALL : poly_inverse" << endl;
1678
#endif
1679
        
1680
        // Extract variables
1681
        vector<WORD *> e;
×
1682
        e.push_back(arga);
×
1683
        e.push_back(argb);
×
1684
        poly::get_variables(BHEAD e, false, true);
×
1685

1686
        if (AN.poly_num_vars > 1) {
×
1687
                MLOCK(ErrorMessageLock);
×
1688
                MesPrint ((char*)"ERROR: multivariate polynomial inverse is generally impossible");
×
1689
                MUNLOCK(ErrorMessageLock);
×
NEW
1690
                TERMINATE(-1);
×
1691
        }
1692
        
1693
        // Convert to polynomials
1694
        poly a(poly::argument_to_poly(BHEAD arga, false, true));
×
1695
        poly b(poly::argument_to_poly(BHEAD argb, false, true));
×
1696

1697
        // Check for modulus calculus
1698
        WORD modp=poly_determine_modulus(BHEAD true, true, "polynomial inverse");
×
1699
        a.setmod(modp,1);
×
1700
        b.setmod(modp,1);
×
1701
        
1702
        if (modp == 0) {
×
1703
                vector<int> x(1,0);
×
1704
                modp = polyfact::choose_prime(a.integer_lcoeff()*b.integer_lcoeff(), x);
×
1705
        }
1706

1707
        poly amodp(a,modp,1);
×
1708
        poly bmodp(b,modp,1);        
×
1709

1710
        // Calculate gcd
1711
        vector<poly> xgcd(polyfact::extended_gcd_Euclidean_lifted(amodp,bmodp));
×
1712
        poly invamodp(xgcd[0]);
×
1713
        poly invbmodp(xgcd[1]);
×
1714
        
1715
        if (!((invamodp * amodp) % bmodp).is_one()) {
×
1716
                MLOCK(ErrorMessageLock);
×
1717
                MesPrint ((char*)"ERROR: polynomial inverse does not exist");
×
1718
                MUNLOCK(ErrorMessageLock);
×
NEW
1719
                TERMINATE(-1);                
×
1720
        }
1721

1722
        // estimate of the size of the Form notation; might be extended later
1723
        int ressize = invamodp.size_of_form_notation()+1;
×
1724
        WORD *res = (WORD *)Malloc1(ressize*sizeof(WORD), "poly_inverse");
×
1725

1726
        // initialize polynomials to store the result
1727
        poly primepower(BHEAD modp);
×
1728
        poly inva(invamodp,modp,1);
×
1729
        poly invb(invbmodp,modp,1);
×
1730

1731
        while (true) {
×
1732
                // convert to Form notation 
1733
                int j=0;
×
1734
                WORD n=0;                
×
1735
                for (int i=1; i<inva[0]; i+=inva[i]) {
×
1736

1737
                        // check whether res should be extended
1738
                        while (ressize < j + 2*ABS(inva[i+inva[i]-1]) + (inva[i+1]>0?4:0) + 3) {
×
1739
                                int newressize = 2*ressize;
×
1740
                                
1741
                                WORD *newres = (WORD *)Malloc1(newressize*sizeof(WORD), "poly_inverse");
×
1742
                                WCOPY(newres, res, ressize);
×
1743
                                M_free(res, "poly_inverse");
×
1744
                                res = newres;
1745
                                ressize = newressize;
1746
                        }
1747
                        
1748
                        res[j] = 1;
×
1749
                        if (inva[i+1]>0) {
×
1750
                                res[j+res[j]++] = SYMBOL;
×
1751
                                res[j+res[j]++] = 4;
×
1752
                                res[j+res[j]++] = AN.poly_vars[0];
×
1753
                                res[j+res[j]++] = inva[i+1];
×
1754
                        }
1755
                        MakeLongRational(BHEAD (UWORD *)&inva[i+2], inva[i+inva[i]-1],
×
1756
                                                                                         (UWORD*)&primepower.terms[3], primepower.terms[primepower.terms[1]],
×
1757
                                                                                         (UWORD *)&res[j+res[j]], &n);
×
1758
                        res[j] += 2*ABS(n);
×
1759
                        res[j+res[j]++] = SGN(n)*(2*ABS(n)+1);
×
1760
                        j += res[j];
×
1761
                }
1762
                res[j]=0;
×
1763

1764
                // if modulus calculus is set, this is the answer
1765
                if (a.modp != 0) break;
×
1766

1767
                // otherwise check over integers
1768
                poly den(BHEAD 0);
×
1769
                poly check(poly::argument_to_poly(BHEAD res, false, true, &den));
×
1770
                if (poly::divides(b.integer_lcoeff(), check.integer_lcoeff())) {
×
1771
                        check = check*a - den;
×
1772
                        if (poly::divides(b, check)) break;
×
1773
                }
1774
                
1775
                // if incorrect, lift with quadratic p-adic Newton's iteration.
1776
                poly error((poly(BHEAD 1) - a*inva - b*invb) / primepower);
×
1777
                poly errormodpp(error, modp, inva.modn);
×
1778

1779
                inva.modn *= 2;
×
1780
                invb.modn *= 2;
×
1781
                
1782
                poly dinva((inva * errormodpp) % b);
×
1783
                poly dinvb((invb * errormodpp) % a);
×
1784

1785
                inva += dinva * primepower;
×
1786
                invb += dinvb * primepower;
×
1787
                
1788
                primepower *= primepower;
×
1789
        }
1790

1791
        // clean up and reset modulo calculation
1792
        poly_free_poly_vars(BHEAD "AN.poly_vars_inverse");
×
1793
        
1794
        AN.ncmod = AC.ncmod;
×
1795
        return res;
×
1796
}
1797

1798
/*
1799
          #] poly_inverse : 
1800
          #[ poly_mul :
1801
*/
1802

1803
WORD *poly_mul(PHEAD WORD *a, WORD *b) {
19✔
1804

1805
#ifdef DEBUG
1806
        cout << "*** [" << thetime() << "]  CALL : poly_mul" << endl;
1807
#endif
1808

1809
        // Extract variables
1810
        vector<WORD *> e;
19✔
1811
        e.push_back(a);
19✔
1812
        e.push_back(b);
19✔
1813
        poly::get_variables(BHEAD e, false, false);  // TODO: any performance effect by sort_vars=true?
19✔
1814

1815
        // Convert to polynomials
1816
        poly dena(BHEAD 0);
38✔
1817
        poly denb(BHEAD 0);
38✔
1818
        poly pa(poly::argument_to_poly(BHEAD a, false, true, &dena));
38✔
1819
        poly pb(poly::argument_to_poly(BHEAD b, false, true, &denb));
19✔
1820

1821
        // Check for modulus calculus
1822
        WORD modp = poly_determine_modulus(BHEAD true, true, "polynomial multiplication");
19✔
1823
        pa.setmod(modp, 1);
19✔
1824

1825
        // NOTE: mul_ is currently implemented by translating negative powers of
1826
        // symbols to extra symbols. For future improvement, it may be better to
1827
        // compute
1828
        //   (content(a) * content(b)) * (a/content(a)) * (b/content(b))
1829
        // to avoid introducing extra symbols for "mixed" cases, e.g.,
1830
        // (1+x) * (1/x) -> (1+x) * (1+Z1_).
1831
        assert(dena.is_integer());
19✔
1832
        assert(denb.is_integer());
19✔
1833
        assert(modp == 0 || dena.is_one());
19✔
1834
        assert(modp == 0 || denb.is_one());
19✔
1835

1836
        // multiplication
1837
        pa *= pb;
19✔
1838

1839
        // convert to Form notation
1840
        WORD *res;
19✔
1841
        if (dena.is_one() && denb.is_one()) {
19✔
1842
                res = (WORD *)Malloc1((pa.size_of_form_notation() + 1) * sizeof(WORD), "poly_mul");
7✔
1843
                poly::poly_to_argument(pa, res, false);
7✔
1844
        } else {
1845
                dena *= denb;
12✔
1846
                res = (WORD *)Malloc1((pa.size_of_form_notation_with_den(dena[dena[1]]) + 1) * sizeof(WORD), "poly_mul");
12✔
1847
                poly::poly_to_argument_with_den(pa, dena[dena[1]], (const UWORD *)&dena[2+AN.poly_num_vars], res, false);
12✔
1848
        }
1849

1850
        // clean up and reset modulo calculation
1851
        poly_free_poly_vars(BHEAD "AN.poly_vars_mul");
19✔
1852
        AN.ncmod = AC.ncmod;
19✔
1853

1854
        return res;
38✔
1855
}
1856

1857
/*
1858
          #] poly_mul : 
1859
          #[ poly_free_poly_vars :
1860
*/
1861

1862
void poly_free_poly_vars(PHEAD const char *text)
56,702✔
1863
{
1864
        if ( AN.poly_vars_type == 0 ) {
56,702✔
1865
                TermFree(AN.poly_vars, text);
56,702✔
1866
        }
1867
        else {
1868
                M_free(AN.poly_vars, text);
×
1869
        }
1870
        AN.poly_num_vars = 0;
56,702✔
1871
        AN.poly_vars = 0;
56,702✔
1872
}
56,702✔
1873

1874
/*
1875
          #] poly_free_poly_vars : 
1876
*/
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