FORM v5.0.0-35-g6318119
polywrap.cc
Go to the documentation of this file.
1
8/* #[ License : */
9/*
10 * Copyright (C) 1984-2026 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
52const int POLYWRAP_DENOMPOWER_INCREASE_FACTOR = 2;
53
54using namespace std;
55
56/*
57 #[ poly_determine_modulus :
58*/
59
79WORD poly_determine_modulus (PHEAD bool multi_error, bool is_fun_arg, string message) {
80
81 if (AC.ncmod==0) return 0;
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);
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);
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
124WORD *poly_gcd(PHEAD WORD *a, WORD *b, WORD fit) {
125
126#ifdef WITHFLINT
127 if ( AC.FlintPolyFlag && AC.ncmod==0 ) {
128 WORD *ret = flint_gcd(BHEAD a, b, fit);
129 return ret;
130 }
131#endif
132
133#ifdef DEBUG
134 cout << "*** [" << thetime() << "] CALL : poly_gcd" << endl;
135#endif
136
137//
138//MesPrint("Calling poly_gcd with:");
139//{
140// WORD *at = a;
141// MesPrint(" a:");
142// while ( *at ) {
143// MesPrint(" %a",*at,at);
144// at += *at;
145// }
146// MesPrint(" b:");
147// at = b;
148// while ( *at ) {
149// MesPrint(" %a",*at,at);
150// at += *at;
151// }
152//}
153
154 // Extract variables
155 vector<WORD *> e;
156 e.reserve(2);
157 e.push_back(a);
158 e.push_back(b);
159 poly::get_variables(BHEAD e, false, true);
160
161 // Check for modulus calculus
162 WORD modp=poly_determine_modulus(BHEAD true, true, "polynomial GCD");
163
164 // Convert to polynomials
165 poly pa(poly::argument_to_poly(BHEAD a, false, true), modp, 1);
166 poly pb(poly::argument_to_poly(BHEAD b, false, true), modp, 1);
167
168 // Calculate gcd
169 poly gcd(polygcd::gcd(pa,pb));
170
171 // Allocate new memory and convert to Form notation
172 int newsize = (gcd.size_of_form_notation()+1);
173 WORD *res;
174 if ( fit ) {
175 if ( newsize*sizeof(WORD) >= (size_t)(AM.MaxTer) ) {
176 MLOCK(ErrorMessageLock);
177 MesPrint("poly_gcd: Term too complex (%d words). Maybe increasing MaxTermSize (%d words) can help",
178 newsize, AM.MaxTer/sizeof(WORD));
179 MUNLOCK(ErrorMessageLock);
180 Terminate(-1);
181 }
182 res = TermMalloc("poly_gcd");
183 }
184 else {
185 res = (WORD *)Malloc1(newsize*sizeof(WORD), "poly_gcd");
186 }
187 poly::poly_to_argument(gcd, res, false);
188
189 poly_free_poly_vars(BHEAD "AN.poly_vars_qcd");
190
191 // reset modulo calculation
192 AN.ncmod = AC.ncmod;
193 return res;
194}
195
196/*
197 #] poly_gcd :
198 #[ poly_divmod :
199
200 if fit == 1 the answer must fit inside a term.
201*/
202
203WORD *poly_divmod(PHEAD WORD *a, WORD *b, int divmod, WORD fit) {
204
205#ifdef DEBUG
206 cout << "*** [" << thetime() << "] CALL : poly_divmod" << endl;
207#endif
208
209 // check for modulus calculus
210 WORD modp=poly_determine_modulus(BHEAD false, true, "polynomial division");
211
212 // get variables
213 vector<WORD *> e;
214 e.reserve(2);
215 e.push_back(a);
216 e.push_back(b);
217 poly::get_variables(BHEAD e, false, false);
218
219 // add extra variables to keep track of denominators
220 const int DENOMSYMBOL = MAXPOSITIVE;
221
222// WORD *new_poly_vars = (WORD *)Malloc1((AN.poly_num_vars+1)*sizeof(WORD), "AN.poly_vars");
223// WCOPY(new_poly_vars, AN.poly_vars, AN.poly_num_vars);
224// new_poly_vars[AN.poly_num_vars] = DENOMSYMBOL;
225// if (AN.poly_num_vars > 0)
226// M_free(AN.poly_vars, "AN.poly_vars");
227// AN.poly_num_vars++;
228// AN.poly_vars = new_poly_vars;
229 AN.poly_vars[AN.poly_num_vars++] = DENOMSYMBOL;
230
231 // convert to polynomials
232 poly dena(BHEAD 0);
233 poly denb(BHEAD 0);
234 poly pa(poly::argument_to_poly(BHEAD a, false, true, &dena), modp, 1);
235 poly pb(poly::argument_to_poly(BHEAD b, false, true, &denb), modp, 1);
236
237 // remove contents
238 poly numres(polygcd::integer_content(pa));
239 poly denres(polygcd::integer_content(pb));
240 pa /= numres;
241 pb /= denres;
242
243 if (divmod==0) {
244 numres *= denb;
245 denres *= dena;
246 }
247 else {
248 denres = dena;
249 }
250
251 poly gcdres(polygcd::integer_gcd(numres,denres));
252 numres /= gcdres;
253 denres /= gcdres;
254
255 // determine lcoeff(b)
256 poly lcoeffb(pb.integer_lcoeff());
257
258 poly pres(BHEAD 0);
259
260 if (!lcoeffb.is_one()) {
261
262 if (AN.poly_num_vars > 2) {
263 // the original polynomial is multivariate (one dummy variable has
264 // been added), so it is not trivial to determine which power of
265 // lcoeff(b) can be in the answer
266
267 int denompower = 0, prevdenompower = 0;
268 poly pq(BHEAD 0);
269 poly pr(BHEAD 0);
270
271 // try denompower = 0, if this fails increase denompower until division succeeds
272 bool div_fail = true;
273 do
274 {
275 if(denompower < prevdenompower)
276 {
277 // denompower increased beyond INT_MAX
278 MLOCK(ErrorMessageLock);
279 MesPrint ((char*)"ERROR: pseudo-division failed in poly_divmod (denompower > INT_MAX)");
280 MUNLOCK(ErrorMessageLock);
281 Terminate(1);
282 }
283
284 if(denompower != 0)
285 {
286 // multiply a by lcoeffb^(denompower-prevdenompower)
287 WORD n = lcoeffb[lcoeffb[1]];
288 RaisPow(BHEAD (UWORD *)&lcoeffb[2+AN.poly_num_vars], &n, denompower-prevdenompower);
289 lcoeffb[1] = 2 + AN.poly_num_vars + ABS(n);
290 lcoeffb[0] = 1 + lcoeffb[1];
291 lcoeffb[lcoeffb[1]] = n;
292
293 pa *= lcoeffb;
294 denres *= lcoeffb;
295 }
296
297 // try division
298 poly ppow(BHEAD 0);
299 poly::divmod_heap(pa,pb,pq,pr,false,true,div_fail); // sets div_fail
300
301 // increase denompower for next iteration
302 prevdenompower = denompower;
303 denompower = (denompower==0 ? 1 : denompower*POLYWRAP_DENOMPOWER_INCREASE_FACTOR+1 ); // generates 2^n-1 when POLYWRAP_DENOMPOWER_INCREASE_FACTOR = 2
304 }
305 while(div_fail);
306
307 pres = (divmod==0 ? pq : pr);
308
309 }
310 else {
311 // one variable, so the power is the difference of the degrees
312
313 int denompower = MaX(0, pa.degree(0) - pb.degree(0) + 1);
314
315 // multiply a by that power
316 WORD n = lcoeffb[lcoeffb[1]];
317 RaisPow(BHEAD (UWORD *)&lcoeffb[2+AN.poly_num_vars], &n, denompower);
318 lcoeffb[1] = 2 + AN.poly_num_vars + ABS(n);
319 lcoeffb[0] = 1 + lcoeffb[1];
320 lcoeffb[lcoeffb[1]] = n;
321
322 pa *= lcoeffb;
323 denres *= lcoeffb;
324
325 pres = (divmod==0 ? pa/pb : pa%pb);
326
327 }
328
329 }
330 else {
331
332 pres = (divmod==0 ? pa/pb : pa%pb);
333
334 }
335
336 // convert to Form notation
337 // NOTE: this part can be rewritten with poly::size_of_form_notation_with_den()
338 // and poly::poly_to_argument_with_den().
339 WORD *res;
340
341 // special case: a=0
342 if (pres[0]==1) {
343 if ( fit ) {
344 res = TermMalloc("poly_divmod");
345 }
346 else {
347 res = (WORD *)Malloc1(sizeof(WORD), "poly_divmod");
348 }
349 res[0] = 0;
350 }
351 else {
352 pres *= numres;
353
354 WORD nden;
355 UWORD *den = (UWORD *)NumberMalloc("poly_divmod");
356
357 // allocate the memory; note that this overestimates the size,
358 // since the estimated denominators are too large
359 int ressize = pres.size_of_form_notation() + pres.number_of_terms()*2*ABS(denres[denres[1]]) + 1;
360
361 if ( fit ) {
362 if ( ressize*sizeof(WORD) > (size_t)(AM.MaxTer) ) {
363 MLOCK(ErrorMessageLock);
364 MesPrint("poly_divmod: Term too complex (%d words). Maybe increasing MaxTermSize (%d words) can help",
365 ressize, AM.MaxTer/sizeof(WORD));
366 MUNLOCK(ErrorMessageLock);
367 Terminate(-1);
368 }
369 res = TermMalloc("poly_divmod");
370 }
371 else {
372 res = (WORD *)Malloc1(ressize*sizeof(WORD), "poly_divmod");
373 }
374 int L=0;
375
376 for (int i=1; i!=pres[0]; i+=pres[i]) {
377
378 res[L]=1; // length
379 bool first = true;
380
381 for (int j=0; j<AN.poly_num_vars; j++)
382 if (pres[i+1+j] > 0) {
383 if (first) {
384 first = false;
385 res[L+1] = 1; // symbols
386 res[L+2] = 2; // length
387 }
388 res[L+1+res[L+2]++] = AN.poly_vars[j]; // symbol
389 res[L+1+res[L+2]++] = pres[i+1+j]; // power
390 }
391
392 if (!first) res[L] += res[L+2]; // fix length
393
394 // numerator
395 WORD nnum = pres[i+pres[i]-1];
396 WCOPY(&res[L+res[L]], &pres[i+pres[i]-1-ABS(nnum)], ABS(nnum));
397
398 // calculate denominator
399 nden = denres[denres[1]];
400 WCOPY(den, &denres[2+AN.poly_num_vars], ABS(nden));
401
402 if (nden!=1 || den[0]!=1)
403 Simplify(BHEAD (UWORD *)&res[L+res[L]], &nnum, den, &nden); // gcd(num,den)
404 Pack((UWORD *)&res[L+res[L]], &nnum, den, nden); // format
405 res[L] += 2*ABS(nnum)+1; // fix length
406 res[L+res[L]-1] = SGN(nnum)*(2*ABS(nnum)+1); // length of coefficient
407 L += res[L]; // fix length
408 }
409
410 res[L] = 0;
411
412 NumberFree(den,"poly_divmod");
413 }
414
415 // clean up
416 poly_free_poly_vars(BHEAD "AN.poly_vars_divmod");
417
418 // reset modulo calculation
419 AN.ncmod = AC.ncmod;
420
421 return res;
422}
423
424/*
425 #] poly_divmod :
426 #[ poly_div :
427
428 Routine divides the expression in arg1 by the expression in arg2.
429 We did not take out special cases.
430 The arguments are zero terminated sequences of term(s).
431 The action is to divide arg1 by arg2: [arg1/arg2].
432 The answer should be a buffer (allocated by Malloc1) with a zero
433 terminated sequence of terms (or just zero).
434*/
435WORD *poly_div(PHEAD WORD *a, WORD *b, WORD fit) {
436
437#ifdef WITHFLINT
438 if ( AC.FlintPolyFlag && AC.ncmod==0 ) {
439 WORD *ret = flint_div(BHEAD a, b, fit);
440 return ret;
441 }
442#endif
443
444#ifdef DEBUG
445 cout << "*** [" << thetime() << "] CALL : poly_div" << endl;
446#endif
447
448 return poly_divmod(BHEAD a, b, 0, fit);
449}
450
451/*
452 #] poly_div :
453 #[ poly_rem :
454
455 Routine divides the expression in arg1 by the expression in arg2
456 and takes the remainder.
457 We did not take out special cases.
458 The arguments are zero terminated sequences of term(s).
459 The action is to divide arg1 by arg2 and take the remainder: [arg1%arg2].
460 The answer should be a buffer (allocated by Malloc1) with a zero
461 terminated sequence of terms (or just zero).
462*/
463WORD *poly_rem(PHEAD WORD *a, WORD *b, WORD fit) {
464
465#ifdef WITHFLINT
466 if ( AC.FlintPolyFlag && AC.ncmod==0 ) {
467 WORD *ret = flint_rem(BHEAD a, b, fit);
468 return ret;
469 }
470#endif
471
472#ifdef DEBUG
473 cout << "*** [" << thetime() << "] CALL : poly_rem" << endl;
474#endif
475
476 return poly_divmod(BHEAD a, b, 1, fit);
477}
478
479/*
480 #] poly_rem :
481 #[ poly_ratfun_read :
482*/
483
496void poly_ratfun_read (WORD *a, poly &num, poly &den) {
497
498#ifdef DEBUG
499 cout << "*** [" << thetime() << "] CALL : poly_ratfun_read" << endl;
500#endif
501
502 POLY_GETIDENTITY(num);
503
504 int modp = num.modp;
505
506 WORD *astop = a+a[1];
507
508 bool clean = (a[2] & MUSTCLEANPRF) == 0;
509
510 a += FUNHEAD;
511 if (a >= astop) {
512 MLOCK(ErrorMessageLock);
513 MesPrint ((char*)"ERROR: PolyRatFun cannot have zero arguments");
514 MUNLOCK(ErrorMessageLock);
515 Terminate(-1);
516 }
517
518 poly den_num(BHEAD 1),den_den(BHEAD 1);
519
520 num = poly::argument_to_poly(BHEAD a, true, !clean, &den_num);
521 num.setmod(modp,1);
522 NEXTARG(a);
523
524 if (a < astop) {
525 den = poly::argument_to_poly(BHEAD a, true, !clean, &den_den);
526 den.setmod(modp,1);
527 NEXTARG(a);
528 }
529 else {
530 den = poly(BHEAD 1, modp, 1);
531 }
532
533 if (a < astop) {
534 MLOCK(ErrorMessageLock);
535 MesPrint ((char*)"ERROR: PolyRatFun cannot have more than two arguments");
536 MUNLOCK(ErrorMessageLock);
537 Terminate(-1);
538 }
539
540 // JD: At this point, num and den are certainly sorted into the correct order by
541 // poly::argument_to_poly, but we can't rely on the clean flag to know if there
542 // are any negative powers. Check for them, and set clean = false if there are any.
543 vector<WORD> minpower(AN.poly_num_vars, MAXPOSITIVE);
544
545 for (int i=1; i<num[0]; i+=num[i]) {
546 for (int j=0; j<AN.poly_num_vars; j++) {
547 minpower[j] = MiN(minpower[j], num[i+1+j]);
548 }
549 }
550 for (int i=1; i<den[0]; i+=den[i]) {
551 for (int j=0; j<AN.poly_num_vars; j++) {
552 minpower[j] = MiN(minpower[j], den[i+1+j]);
553 if ( minpower[j] < 0 ) clean = false;
554 }
555 }
556
557 if (!clean) {
558 for (int i=1; i<num[0]; i+=num[i])
559 for (int j=0; j<AN.poly_num_vars; j++)
560 num[i+1+j] -= minpower[j];
561 for (int i=1; i<den[0]; i+=den[i])
562 for (int j=0; j<AN.poly_num_vars; j++)
563 den[i+1+j] -= minpower[j];
564
565 num *= den_den;
566 den *= den_num;
567
568 poly gcd = polygcd::gcd(num,den);
569 num /= gcd;
570 den /= gcd;
571 }
572}
573
574/*
575 #] poly_ratfun_read :
576 #[ poly_sort :
577*/
578
590void poly_sort(PHEAD WORD *a) {
591
592#ifdef DEBUG
593 cout << "*** [" << thetime() << "] CALL : poly_sort" << endl;
594#endif
595 if (NewSort(BHEAD0)) { Terminate(-1); }
596 AR.CompareRoutine = (COMPAREDUMMY)(&CompareSymbols);
597
598 for (int i=ARGHEAD; i<a[0]; i+=a[i]) {
599 if (SymbolNormalize(a+i)<0 || StoreTerm(BHEAD a+i)) {
600 AR.CompareRoutine = (COMPAREDUMMY)(&Compare1);
602 Terminate(-1);
603 }
604 }
605
606 if (EndSort(BHEAD a+ARGHEAD,1) < 0) {
607 AR.CompareRoutine = (COMPAREDUMMY)(&Compare1);
608 Terminate(-1);
609 }
610
611 AR.CompareRoutine = (COMPAREDUMMY)(&Compare1);
612 a[1] = 0; // set dirty flag to zero
613}
614
615/*
616 #] poly_sort :
617 #[ poly_ratfun_add :
618*/
619
633WORD *poly_ratfun_add (PHEAD WORD *t1, WORD *t2) {
634
635#ifdef WITHFLINT
636 if ( AC.FlintPolyFlag && AC.ncmod==0 ) {
637 WORD *ret = flint_ratfun_add(BHEAD t1, t2);
638 return ret;
639 }
640#endif
641
642 if ( AR.PolyFunExp == 1 ) return PolyRatFunSpecial(BHEAD t1, t2);
643
644#ifdef DEBUG
645 cout << "*** [" << thetime() << "] CALL : poly_ratfun_add" << endl;
646#endif
647
648 WORD *oldworkpointer = AT.WorkPointer;
649
650 // Extract variables
651 vector<WORD *> e;
652 e.reserve(4);
653
654 for (WORD *t=t1+FUNHEAD; t<t1+t1[1];) {
655 e.push_back(t);
656 NEXTARG(t);
657 }
658 for (WORD *t=t2+FUNHEAD; t<t2+t2[1];) {
659 e.push_back(t);
660 NEXTARG(t);
661 }
662
663 assert(e.size() == 4);
664
665 poly::get_variables(BHEAD e, true, true);
666
667 // Check for modulus calculus
668 WORD modp=poly_determine_modulus(BHEAD true, true, "PolyRatFun");
669
670 // Find numerators / denominators
671 poly num1(BHEAD 0,modp,1), den1(BHEAD 0,modp,1), num2(BHEAD 0,modp,1), den2(BHEAD 0,modp,1);
672
673 poly_ratfun_read(t1, num1, den1);
674 poly_ratfun_read(t2, num2, den2);
675
676 poly num(BHEAD 0),den(BHEAD 0),gcd(BHEAD 0);
677
678 // Calculate result
679 if (den1 != den2) {
680 gcd = polygcd::gcd(den1,den2);
681#ifdef OLDADDITION
682 num = num1*(den2/gcd) + num2*(den1/gcd);
683 den = (den1/gcd)*den2;
684 gcd = polygcd::gcd(num,den);
685#else
686 den = den1/gcd;
687 num = num1*(den2/gcd) + num2*den;
688 den = den*den2;
689 gcd = polygcd::gcd(num,gcd);
690#endif
691 }
692 else {
693 num = num1 + num2;
694 den = den1;
695 gcd = polygcd::gcd(num,den);
696 }
697
698 num /= gcd;
699 den /= gcd;
700
701 // Fix sign
702 if (den.sign() == -1) { num*=poly(BHEAD -1); den*=poly(BHEAD -1); }
703
704 // Check size: include FUNHEAD for the prf itself, an ARGHEAD each for num and den,
705 // and 3 for the final coeff "1/1". We don't know here what the rest of the term looks like,
706 // but it certainly has at least its total size (so +1):
707 if ((num.size_of_form_notation() + den.size_of_form_notation() + FUNHEAD + 2*ARGHEAD + 3 + 1)
708 > AM.MaxTer/(int)sizeof(WORD)) {
709
710 MLOCK(ErrorMessageLock);
711 MesPrint ("ERROR: PolyRatFun doesn't fit in a term");
712 MesPrint ("(1) num size = %d, den size = %d, rest = %d, MaxTermSize = %d words",
713 num.size_of_form_notation()+ARGHEAD,
714 den.size_of_form_notation()+ARGHEAD,
715 FUNHEAD + 3 + 1,
716 AM.MaxTer/sizeof(WORD));
717 MUNLOCK(ErrorMessageLock);
718 Terminate(-1);
719 }
720
721 // Format result in Form notation
722 WORD *t = oldworkpointer;
723
724 *t++ = AR.PolyFun; // function
725 *t++ = 0; // length (to be determined)
726// *t++ &= ~MUSTCLEANPRF; // clean polyratfun
727 *t++ = 0;
728 FILLFUN3(t); // header
729 poly::poly_to_argument(num,t, true); // argument 1 (numerator)
730 if (*t>0 && t[1]==DIRTYFLAG) // to Form order
731 poly_sort(BHEAD t);
732 t += (*t>0 ? *t : 2);
733 poly::poly_to_argument(den,t, true); // argument 2 (denominator)
734 if (*t>0 && t[1]==DIRTYFLAG) // to Form order
735 poly_sort(BHEAD t);
736 t += (*t>0 ? *t : 2);
737
738 oldworkpointer[1] = t - oldworkpointer; // length
739 AT.WorkPointer = t;
740
741 poly_free_poly_vars(BHEAD "AN.poly_vars_ratfun_add");
742
743 // reset modulo calculation
744 AN.ncmod = AC.ncmod;
745
746 return oldworkpointer;
747}
748
749/*
750 #] poly_ratfun_add :
751 #[ poly_ratfun_normalize :
752*/
753
769int poly_ratfun_normalize (PHEAD WORD *term) {
770
771#ifdef WITHFLINT
772 if ( AC.FlintPolyFlag && AC.ncmod==0 ) {
773 flint_ratfun_normalize(BHEAD term);
774 return 0;
775 }
776#endif
777
778#ifdef DEBUG
779 cout << "*** [" << thetime() << "] CALL : poly_ratfun_normalize" << endl;
780#endif
781
782 // Strip coefficient
783 WORD *tstop = term + *term;
784 int ncoeff = tstop[-1];
785 tstop -= ABS(ncoeff);
786
787 // if only one clean polyratfun, return immediately
788 int num_polyratfun = 0;
789
790 for (WORD *t=term+1; t<tstop; t+=t[1])
791 if (*t == AR.PolyFun) {
792 num_polyratfun++;
793 if ((t[2] & MUSTCLEANPRF) != 0)
794 num_polyratfun = INT_MAX;
795 if (num_polyratfun > 1) break;
796 }
797
798 if (num_polyratfun <= 1) return 0;
799
800 WORD oldsorttype = AR.SortType;
801 AR.SortType = SORTHIGHFIRST;
802
803/*
804 When there are polyratfun's with only one variable: rename them
805 temporarily to TMPPOLYFUN.
806*/
807 for (WORD *t=term+1; t<tstop; t+=t[1]) {
808 if (*t == AR.PolyFun && (t[1] == FUNHEAD+t[FUNHEAD]
809 || t[1] == FUNHEAD+2 ) ) { *t = TMPPOLYFUN; }
810 }
811
812
813 // Extract all variables in the polyfuns
814 vector<WORD *> e;
815
816 for (WORD *t=term+1; t<tstop; t+=t[1]) {
817 if (*t == AR.PolyFun)
818 for (WORD *t2 = t+FUNHEAD; t2<t+t[1];) {
819 e.push_back(t2);
820 NEXTARG(t2);
821 }
822 }
823 poly::get_variables(BHEAD e, true, true);
824
825 // Check for modulus calculus
826 WORD modp=poly_determine_modulus(BHEAD true, true, "PolyRatFun");
827
828 // Accumulate total denominator/numerator and copy the remaining terms
829 // We start with 'trivial' polynomials
830 poly num1(BHEAD (UWORD *)tstop, ncoeff/2, modp, 1);
831 poly den1(BHEAD (UWORD *)tstop+ABS(ncoeff/2), ABS(ncoeff)/2, modp, 1);
832
833 WORD *s = term+1;
834
835 for (WORD *t=term+1; t<tstop;)
836 if (*t == AR.PolyFun) {
837
838 poly num2(BHEAD 0,modp,1);
839 poly den2(BHEAD 0,modp,1);
840 poly_ratfun_read(t,num2,den2);
841
842 if ((t[2] & MUSTCLEANPRF) != 0) { // first normalize
843 poly gcd1(polygcd::gcd(num2,den2));
844 num2 = num2/gcd1;
845 den2 = den2/gcd1;
846 }
847 t += t[1];
848 poly gcd1(polygcd::gcd(num1,den2));
849 poly gcd2(polygcd::gcd(num2,den1));
850
851 num1 = (num1 / gcd1) * (num2 / gcd2);
852 den1 = (den1 / gcd2) * (den2 / gcd1);
853 }
854 else {
855 int i = t[1];
856 if ( s != t ) { NCOPY(s,t,i) }
857 else { t += i; s += i; }
858 }
859
860 // Fix sign
861 if (den1.sign() == -1) { num1*=poly(BHEAD -1); den1*=poly(BHEAD -1); }
862
863 // Check size: include FUNHEAD for the prf itself, an ARGHEAD each for num and den,
864 // s-term for the copied term so far, and 3 for final coeff "1/1"
865 if ((num1.size_of_form_notation() + den1.size_of_form_notation() + FUNHEAD + 2*ARGHEAD
866 + s-term + 3) > AM.MaxTer/(int)sizeof(WORD)) {
867
868 MLOCK(ErrorMessageLock);
869 MesPrint ("ERROR: PolyRatFun doesn't fit in a term");
870 MesPrint ("(2) num size = %d, den size = %d, rest = %d, MaxTermSize = %d words",
871 num1.size_of_form_notation()+ARGHEAD,
872 den1.size_of_form_notation()+ARGHEAD,
873 FUNHEAD + s-term + 3,
874 AM.MaxTer/sizeof(WORD));
875 MUNLOCK(ErrorMessageLock);
876 Terminate(-1);
877 }
878
879 // Format result in Form notation
880 WORD *t = s;
881 *t++ = AR.PolyFun; // function
882 *t++ = 0; // size (to be determined)
883 *t++ &= ~MUSTCLEANPRF; // clean polyratfun
884 FILLFUN3(t); // header
885 poly::poly_to_argument(num1,t,true); // argument 1 (numerator)
886 if (*t>0 && t[1]==DIRTYFLAG) // to Form order
887 poly_sort(BHEAD t);
888 t += (*t>0 ? *t : 2);
889 poly::poly_to_argument(den1,t,true); // argument 2 (denominator)
890 if (*t>0 && t[1]==DIRTYFLAG) // to Form order
891 poly_sort(BHEAD t);
892 t += (*t>0 ? *t : 2);
893
894 s[1] = t - s; // function length
895
896 *t++ = 1; // term coefficient
897 *t++ = 1;
898 *t++ = 3;
899
900 term[0] = t-term; // term length
901
902 poly_free_poly_vars(BHEAD "AN.poly_vars_ratfun_normalize");
903
904 // reset modulo calculation
905 AN.ncmod = AC.ncmod;
906
907 tstop = term + *term; tstop -= ABS(tstop[-1]);
908 for (WORD *t=term+1; t<tstop; t+=t[1]) {
909 if (*t == TMPPOLYFUN ) *t = AR.PolyFun;
910 }
911
912 AR.SortType = oldsorttype;
913 return 0;
914}
915
916/*
917 #] poly_ratfun_normalize :
918 #[ poly_fix_minus_signs :
919*/
920
921void poly_fix_minus_signs (factorized_poly &a) {
922
923 if ( a.factor.empty() ) return;
924
925 POLY_GETIDENTITY(a.factor[0]);
926
927 int overall_sign = +1;
928
929 // find term with maximum power of highest symbol
930 for (int i=0; i<(int)a.factor.size(); i++) {
931
932 int maxvar = -1;
933 int maxpow = -1;
934 int sign = +1;
935
936 WORD *tstop = a.factor[i].terms; tstop += *tstop;
937 for (WORD *t=a.factor[i].terms+1; t<tstop; t+=*t)
938 for (int j=0; j<AN.poly_num_vars; j++) {
939 int var = AN.poly_vars[j];
940 int pow = t[1+j];
941 if (pow>0 && (var>maxvar || (var==maxvar && pow>maxpow))) {
942 maxvar = var;
943 maxpow = pow;
944 sign = SGN(*(t+*t-1));
945 }
946 }
947
948 // if negative coefficient, multiply by -1
949 if (sign==-1) {
950 a.factor[i] *= poly(BHEAD sign);
951 if (a.power[i] % 2 == 1) overall_sign*=-1;
952 }
953 }
954
955 // if overall minus sign
956 if (overall_sign == -1) {
957 // look at constant factor and multiply by -1
958 for (int i=0; i<(int)a.factor.size(); i++)
959 if (a.factor[i].is_integer()) {
960 a.factor[i] *= poly(BHEAD -1);
961 return;
962 }
963
964 // otherwise, add a factor of -1
965 a.add_factor(poly(BHEAD -1), 1);
966 }
967}
968
969/*
970 #] poly_fix_minus_signs :
971 #[ poly_factorize :
972*/
973
986WORD *poly_factorize (PHEAD WORD *argin, WORD *argout, bool with_arghead, bool is_fun_arg) {
987
988#ifdef DEBUG
989 cout << "*** [" << thetime() << "] CALL : poly_factorize" << endl;
990#endif
991
992 poly::get_variables(BHEAD vector<WORD*>(1,argin), with_arghead, true);
993 poly den(BHEAD 0);
994 poly a(poly::argument_to_poly(BHEAD argin, with_arghead, true, &den));
995
996 // check for modulus calculus
997 WORD modp=poly_determine_modulus(BHEAD true, is_fun_arg, "polynomial factorization");
998 a.setmod(modp,1);
999
1000 // factorize
1001 factorized_poly f(polyfact::factorize(a));
1002 poly_fix_minus_signs(f);
1003
1004 poly num(BHEAD 1);
1005 for (int i=0; i<(int)f.factor.size(); i++)
1006 if (f.factor[i].is_integer())
1007 num = f.factor[i];
1008
1009 // determine size
1010 int len = with_arghead ? ARGHEAD : 0;
1011
1012 if (!num.is_one() || !den.is_one()) {
1013 len++;
1014 len += MaX(ABS(num[num[1]]), den[den[1]])*2+1;
1015 len += with_arghead ? ARGHEAD : 1;
1016 }
1017
1018 for (int i=0; i<(int)f.factor.size(); i++) {
1019 if (!f.factor[i].is_integer()) {
1020 len += f.power[i] * f.factor[i].size_of_form_notation();
1021 len += f.power[i] * (with_arghead ? ARGHEAD : 1);
1022 }
1023 }
1024
1025 len++;
1026
1027 if (argout != NULL) {
1028 // check size
1029 if (len >= AM.MaxTer) {
1030 MLOCK(ErrorMessageLock);
1031 MesPrint ("ERROR: factorization doesn't fit in a term (len = %d, MaxTermSize = %d words)",
1032 len/sizeof(WORD), AM.MaxTer/sizeof(WORD));
1033 MUNLOCK(ErrorMessageLock);
1034 Terminate(-1);
1035 }
1036 }
1037 else {
1038 // allocate size
1039 argout = (WORD*) Malloc1(len*sizeof(WORD), "poly_factorize");
1040 }
1041
1042 WORD *old_argout = argout;
1043
1044 // constant factor
1045 if (!num.is_one() || !den.is_one()) {
1046 int n = max(ABS(num[num[1]]), ABS(den[den[1]]));
1047
1048 if (with_arghead) {
1049 *argout++ = ARGHEAD + 2 + 2*n;
1050 for (int i=1; i<ARGHEAD; i++)
1051 *argout++ = 0;
1052 }
1053
1054 *argout++ = 2 + 2*n;
1055
1056 for (int i=0; i<n; i++)
1057 *argout++ = i<ABS(num[num[1]]) ? num[2+AN.poly_num_vars+i] : 0;
1058 for (int i=0; i<n; i++)
1059 *argout++ = i<ABS(den[den[1]]) ? den[2+AN.poly_num_vars+i] : 0;
1060
1061 *argout++ = SGN(num[num[1]]) * (2*n+1);
1062
1063 if (!with_arghead)
1064 *argout++ = 0;
1065 else {
1066 if (ToFast(old_argout, old_argout))
1067 argout = old_argout+2;
1068 }
1069 }
1070
1071 // non-constant factors
1072 for (int i=0; i<(int)f.factor.size(); i++)
1073 if (!f.factor[i].is_integer())
1074 for (int j=0; j<f.power[i]; j++) {
1075 poly::poly_to_argument(f.factor[i],argout,with_arghead);
1076
1077 if (with_arghead)
1078 argout += *argout > 0 ? *argout : 2;
1079 else {
1080 while (*argout!=0) argout+=*argout;
1081 argout++;
1082 }
1083 }
1084
1085 *argout=0;
1086
1087 poly_free_poly_vars(BHEAD "AN.poly_vars_factorize");
1088
1089 // reset modulo calculation
1090 AN.ncmod = AC.ncmod;
1091
1092 return old_argout;
1093}
1094
1095/*
1096 #] poly_factorize :
1097 #[ poly_factorize_argument :
1098*/
1099
1112int poly_factorize_argument(PHEAD WORD *argin, WORD *argout) {
1113
1114#ifdef DEBUG
1115 cout << "*** [" << thetime() << "] CALL : poly_factorize_argument" << endl;
1116#endif
1117
1118#ifdef WITHFLINT
1119 if ( AC.FlintPolyFlag && AC.ncmod==0 ) {
1120 flint_factorize_argument(BHEAD argin, argout);
1121 return 0;
1122 }
1123#endif
1124
1125 poly_factorize(BHEAD argin,argout,true,true);
1126 return 0;
1127}
1128
1129/*
1130 #] poly_factorize_argument :
1131 #[ poly_factorize_dollar :
1132*/
1133
1146WORD *poly_factorize_dollar (PHEAD WORD *argin) {
1147
1148#ifdef DEBUG
1149 cout << "*** [" << thetime() << "] CALL : poly_factorize_dollar" << endl;
1150#endif
1151
1152#ifdef WITHFLINT
1153 if ( AC.FlintPolyFlag && AC.ncmod==0 ) {
1154 return flint_factorize_dollar(BHEAD argin);
1155 }
1156#endif
1157
1158 return poly_factorize(BHEAD argin,NULL,false,false);
1159}
1160
1161/*
1162 #] poly_factorize_dollar :
1163 #[ poly_factorize_expression :
1164*/
1165
1179
1180#ifdef DEBUG
1181 cout << "*** [" << thetime() << "] CALL : poly_factorize_expression" << endl;
1182#endif
1183
1184 GETIDENTITY;
1185
1186 if (AT.WorkPointer + AM.MaxTer > AT.WorkTop ) {
1187 MLOCK(ErrorMessageLock);
1188 MesWork();
1189 MUNLOCK(ErrorMessageLock);
1190 Terminate(-1);
1191 }
1192
1193 WORD *term = AT.WorkPointer;
1194 WORD startebuf = cbuf[AT.ebufnum].numrhs;
1195 FILEHANDLE *file;
1196 POSITION pos;
1197
1198 FILEHANDLE *oldinfile = AR.infile;
1199 FILEHANDLE *oldoutfile = AR.outfile;
1200 WORD oldBracketOn = AR.BracketOn;
1201 WORD *oldBrackBuf = AT.BrackBuf;
1202 WORD oldbracketindexflag = AT.bracketindexflag;
1203 char oldCommercial[COMMERCIALSIZE+2];
1204
1205 strcpy(oldCommercial, (char*)AC.Commercial);
1206 strcpy((char*)AC.Commercial, "factorize");
1207
1208 // locate is the input
1209 if (expr->status == HIDDENGEXPRESSION || expr->status == HIDDENLEXPRESSION ||
1210 expr->status == INTOHIDEGEXPRESSION || expr->status == INTOHIDELEXPRESSION) {
1211 AR.InHiBuf = 0; file = AR.hidefile; AR.GetFile = 2;
1212 }
1213 else {
1214 AR.InInBuf = 0; file = AR.outfile; AR.GetFile = 0;
1215 }
1216
1217 // read and write to expression file
1218 AR.infile = AR.outfile = file;
1219
1220 // dummy indices are not allowed
1221 if (expr->numdummies > 0) {
1222 MesPrint("ERROR: factorization with dummy indices not implemented");
1223 Terminate(-1);
1224 }
1225
1226 // determine whether the expression in on file or in memory
1227 if (file->handle >= 0) {
1228 pos = expr->onfile;
1229 SeekFile(file->handle,&pos,SEEK_SET);
1230 if (ISNOTEQUALPOS(pos,expr->onfile)) {
1231 MesPrint("ERROR: something wrong in scratch file [poly_factorize_expression]");
1232 Terminate(-1);
1233 }
1234 file->POposition = expr->onfile;
1235 file->POfull = file->PObuffer;
1236 if (expr->status == HIDDENGEXPRESSION)
1237 AR.InHiBuf = 0;
1238 else
1239 AR.InInBuf = 0;
1240 }
1241 else {
1242 file->POfill = (WORD *)((UBYTE *)(file->PObuffer)+BASEPOSITION(expr->onfile));
1243 }
1244
1245 SetScratch(AR.infile, &(expr->onfile));
1246
1247 // read the first header term
1248 WORD size = GetTerm(BHEAD term);
1249 if (size <= 0) {
1250 MesPrint ("ERROR: something wrong with expression [poly_factorize_expression]");
1251 Terminate(-1);
1252 }
1253
1254 // store position: this is where the output will go
1255 pos = expr->onfile;
1256 ADDPOS(pos, size*sizeof(WORD));
1257
1258 // use polynomial as buffer, because it is easy to extend
1259 poly buffer(BHEAD 0);
1260 int bufpos = 0;
1261 int sumcommu = 0;
1262
1263 // read all terms
1264 while (GetTerm(BHEAD term)) {
1265 // substitute non-symbols by extra symbols
1266 sumcommu += DoesCommu(term);
1267 if ( sumcommu > 1 ) {
1268 MesPrint("ERROR: Cannot factorize an expression with more than one noncommuting object");
1269 Terminate(-1);
1270 }
1271 buffer.check_memory(bufpos);
1272 if (LocalConvertToPoly(BHEAD term, buffer.terms + bufpos, startebuf,0) < 0) {
1273 MesPrint("ERROR: in LocalConvertToPoly [factorize_expression]");
1274 Terminate(-1);
1275 }
1276 bufpos += *(buffer.terms + bufpos);
1277 }
1278 buffer[bufpos] = 0;
1279
1280 // parse the polynomial
1281
1282 AN.poly_num_vars = 0;
1283 poly::get_variables(BHEAD vector<WORD*>(1,buffer.terms), false, true);
1284 poly den(BHEAD 0);
1285 poly a(poly::argument_to_poly(BHEAD buffer.terms, false, true, &den));
1286
1287 // check for modulus calculus
1288 WORD modp=poly_determine_modulus(BHEAD true, false, "polynomial factorization");
1289 a.setmod(modp,1);
1290
1291 // create output
1292 SetScratch(file, &pos);
1293 NewSort(BHEAD0);
1294
1295 CBUF *C = cbuf+AC.cbufnum;
1296 CBUF *CC = cbuf+AT.ebufnum;
1297
1298 // turn brackets on. We force the existence of a bracket index.
1299 WORD nexpr = expr - Expressions;
1300 AR.BracketOn = 1;
1301 AT.BrackBuf = AM.BracketFactors;
1302 AT.bracketindexflag = 1;
1303 ClearBracketIndex(-nexpr-2); // Clears the index made during primary generation
1304 OpenBracketIndex(nexpr); // Set up a new index
1305
1306 if (a.is_zero()) {
1307 expr->numfactors = 1;
1308 }
1309 else if (a.is_one() && den.is_one()) {
1310 expr->numfactors = 1;
1311
1312 term[0] = 8;
1313 term[1] = SYMBOL;
1314 term[2] = 4;
1315 term[3] = FACTORSYMBOL;
1316 term[4] = 1;
1317 term[5] = 1;
1318 term[6] = 1;
1319 term[7] = 3;
1320
1321 AT.WorkPointer += *term;
1322 Generator(BHEAD term, C->numlhs);
1323 AT.WorkPointer = term;
1324 }
1325 else {
1326 factorized_poly fac;
1327 bool iszero = false;
1328
1329 if (!(expr->vflags & ISFACTORIZED)) {
1330 // factorize the polynomial
1331 fac = polyfact::factorize(a);
1332 poly_fix_minus_signs(fac);
1333 }
1334 else {
1335 int factorsymbol=-1;
1336 for (int i=0; i<AN.poly_num_vars; i++)
1337 if (AN.poly_vars[i] == FACTORSYMBOL)
1338 factorsymbol = i;
1339
1340 poly denpow(BHEAD 1);
1341
1342 // already factorized, so factorize the factors
1343 for (int i=1; i<=expr->numfactors; i++) {
1344 poly origfac(a.coefficient(factorsymbol, i));
1345 factorized_poly fac2;
1346 if (origfac.is_zero())
1347 iszero=true;
1348 else {
1349 fac2 = polyfact::factorize(origfac);
1350 poly_fix_minus_signs(fac2);
1351 denpow *= den;
1352 }
1353 for (int j=0; j<(int)fac2.power.size(); j++)
1354 fac.add_factor(fac2.factor[j], fac2.power[j]);
1355 }
1356
1357 // update denominator, since each factor was scaled
1358 den=denpow;
1359 }
1360
1361 expr->numfactors = 0;
1362
1363 // coefficient
1364 poly num(BHEAD 1);
1365 for (int i=0; i<(int)fac.factor.size(); i++)
1366 if (fac.factor[i].is_integer())
1367 num *= fac.factor[i];
1368
1369 poly gcd(polygcd::integer_gcd(num,den));
1370 den/=gcd;
1371 num/=gcd;
1372
1373 if (iszero)
1374 expr->numfactors++;
1375
1376 if (!iszero || (expr->vflags & KEEPZERO)) {
1377 if (!num.is_one() || !den.is_one()) {
1378 expr->numfactors++;
1379
1380 int n = max(ABS(num[num[1]]), ABS(den[den[1]]));
1381
1382 term[0] = 6 + 2*n;
1383 term[1] = SYMBOL;
1384 term[2] = 4;
1385 term[3] = FACTORSYMBOL;
1386 term[4] = expr->numfactors;
1387 for (int i=0; i<n; i++) {
1388 term[5+i] = i<ABS(num[num[1]]) ? num[2+AN.poly_num_vars+i] : 0;
1389 term[5+n+i] = i<ABS(den[den[1]]) ? den[2+AN.poly_num_vars+i] : 0;
1390 }
1391 term[5+2*n] = SGN(num[num[1]]) * (2*n+1);
1392 AT.WorkPointer += *term;
1393 Generator(BHEAD term, C->numlhs);
1394 AT.WorkPointer = term;
1395 }
1396
1397 vector<poly> fac_arg(fac.factor.size(), poly(BHEAD 0));
1398
1399 // convert the non-constant factors to Form-style arguments
1400 for (int i=0; i<(int)fac.factor.size(); i++)
1401 if (!fac.factor[i].is_integer()) {
1402 buffer.check_memory(fac.factor[i].size_of_form_notation()+1);
1403 poly::poly_to_argument(fac.factor[i], buffer.terms, false);
1404 NewSort(BHEAD0);
1405
1406 for (WORD *t=buffer.terms; *t!=0; t+=*t) {
1407 // substitute extra symbols
1408 if (ConvertFromPoly(BHEAD t, term, numxsymbol, CC->numrhs-startebuf+numxsymbol,
1409 startebuf-numxsymbol, 1) <= 0 ) {
1410 MesPrint("ERROR: in ConvertFromPoly [factorize_expression]");
1411 Terminate(-1);
1412 return(-1);
1413 }
1414
1415 // store term
1416 AT.WorkPointer += *term;
1417 Generator(BHEAD term, C->numlhs);
1418 AT.WorkPointer = term;
1419 }
1420
1421 // sort and store in buffer
1422 WORD *buffer;
1423 if (EndSort(BHEAD (WORD *)((void *)(&buffer)),2) < 0) return -1;
1424
1425 LONG bufsize=0;
1426 for (WORD *t=buffer; *t!=0; t+=*t)
1427 bufsize+=*t;
1428
1429 fac_arg[i].check_memory(bufsize+ARGHEAD+1);
1430
1431 for (int j=0; j<ARGHEAD; j++)
1432 fac_arg[i].terms[j] = 0;
1433 fac_arg[i].terms[0] = ARGHEAD + bufsize;
1434 WCOPY(fac_arg[i].terms+ARGHEAD, buffer, bufsize);
1435 M_free(buffer, "polynomial factorization");
1436 }
1437
1438 // compare and sort the factors in Form notation
1439 vector<int> order;
1440 vector<vector<int> > comp(fac.factor.size(), vector<int>(fac.factor.size(), 0));
1441
1442 for (int i=0; i<(int)fac.factor.size(); i++)
1443 if (!fac.factor[i].is_integer()) {
1444 order.push_back(i);
1445
1446 for (int j=i+1; j<(int)fac.factor.size(); j++)
1447 if (!fac.factor[j].is_integer()) {
1448 comp[i][j] = CompArg(fac_arg[j].terms, fac_arg[i].terms);
1449 comp[j][i] = -comp[i][j];
1450 }
1451 }
1452
1453 for (int i=0; i<(int)order.size(); i++)
1454 for (int j=0; j+1<(int)order.size(); j++)
1455 if (comp[order[i]][order[j]] == 1)
1456 swap(order[i],order[j]);
1457
1458 // create the final expression
1459 for (int i=0; i<(int)order.size(); i++)
1460 for (int j=0; j<fac.power[order[i]]; j++) {
1461
1462 expr->numfactors++;
1463
1464 WORD *tstop = fac_arg[order[i]].terms + *fac_arg[order[i]].terms;
1465 for (WORD *t=fac_arg[order[i]].terms+ARGHEAD; t<tstop; t+=*t) {
1466
1467 WCOPY(term+4, t, *t);
1468
1469 // add special symbol "factor_"
1470 *term = *(term+4) + 4;
1471 *(term+1) = SYMBOL;
1472 *(term+2) = 4;
1473 *(term+3) = FACTORSYMBOL;
1474 *(term+4) = expr->numfactors;
1475
1476 // store term
1477 AT.WorkPointer += *term;
1478 Generator(BHEAD term, C->numlhs);
1479 AT.WorkPointer = term;
1480 }
1481 }
1482 }
1483 }
1484
1485 // final sorting
1486 if (EndSort(BHEAD NULL,0) < 0) {
1488 Terminate(-1);
1489 }
1490
1491 // set factorized flag
1492 if (expr->numfactors > 0)
1493 expr->vflags |= ISFACTORIZED;
1494
1495 // clean up
1496 AR.infile = oldinfile;
1497 AR.outfile = oldoutfile;
1498 AR.BracketOn = oldBracketOn;
1499 AT.BrackBuf = oldBrackBuf;
1500 AT.bracketindexflag = oldbracketindexflag;
1501 strcpy((char*)AC.Commercial, oldCommercial);
1502
1503 poly_free_poly_vars(BHEAD "AN.poly_vars_factorize_expression");
1504
1505 return 0;
1506}
1507
1508/*
1509 #] poly_factorize_expression :
1510 #[ poly_unfactorize_expression :
1511*/
1512
1525#if ( SUBEXPSIZE == 5 )
1526static WORD genericterm[] = {38,1,4,FACTORSYMBOL,0
1527 ,EXPRESSION,15,0,1,0,13,10,8,1,4,FACTORSYMBOL,0,1,1,3
1528 ,EXPRESSION,15,0,1,0,13,10,8,1,4,FACTORSYMBOL,0,1,1,3
1529 ,1,1,3,0};
1530static WORD genericterm2[] = {23,1,4,FACTORSYMBOL,0
1531 ,EXPRESSION,15,0,1,0,13,10,8,1,4,FACTORSYMBOL,0,1,1,3
1532 ,1,1,3,0};
1533#endif
1534
1536{
1537 GETIDENTITY;
1538 int i, j, nfac = expr->numfactors, nfacp, nexpr = expr - Expressions;
1539 int expriszero = 0;
1540
1541 FILEHANDLE *oldinfile = AR.infile;
1542 FILEHANDLE *oldoutfile = AR.outfile;
1543 char oldCommercial[COMMERCIALSIZE+2];
1544
1545 WORD *oldworkpointer = AT.WorkPointer;
1546 WORD *term = AT.WorkPointer, *t, *w, size;
1547
1548 FILEHANDLE *file;
1549 POSITION pos, oldpos;
1550
1551 WORD oldBracketOn = AR.BracketOn;
1552 WORD *oldBrackBuf = AT.BrackBuf;
1553 CBUF *C = cbuf+AC.cbufnum;
1554
1555 if ( ( expr->vflags & ISFACTORIZED ) == 0 ) return(0);
1556
1557 if ( AT.WorkPointer + AM.MaxTer > AT.WorkTop ) {
1558 MLOCK(ErrorMessageLock);
1559 MesWork();
1560 MUNLOCK(ErrorMessageLock);
1561 Terminate(-1);
1562 }
1563
1564 oldpos = AS.OldOnFile[nexpr];
1565 AS.OldOnFile[nexpr] = expr->onfile;
1566
1567 strcpy(oldCommercial, (char*)AC.Commercial);
1568 strcpy((char*)AC.Commercial, "unfactorize");
1569/*
1570 locate the input
1571*/
1572 if ( expr->status == HIDDENGEXPRESSION || expr->status == HIDDENLEXPRESSION ||
1573 expr->status == INTOHIDEGEXPRESSION || expr->status == INTOHIDELEXPRESSION ) {
1574 AR.InHiBuf = 0; file = AR.hidefile; AR.GetFile = 2;
1575 }
1576 else {
1577 AR.InInBuf = 0; file = AR.outfile; AR.GetFile = 0;
1578 }
1579/*
1580 read and write to expression file
1581*/
1582 AR.infile = AR.outfile = file;
1583/*
1584 set the input file to the correct position
1585*/
1586 if ( file->handle >= 0 ) {
1587 pos = expr->onfile;
1588 SeekFile(file->handle,&pos,SEEK_SET);
1589 if (ISNOTEQUALPOS(pos,expr->onfile)) {
1590 MesPrint("ERROR: something wrong in scratch file unfactorize_expression");
1591 Terminate(-1);
1592 }
1593 file->POposition = expr->onfile;
1594 file->POfull = file->PObuffer;
1595 if ( expr->status == HIDDENGEXPRESSION )
1596 AR.InHiBuf = 0;
1597 else
1598 AR.InInBuf = 0;
1599 }
1600 else {
1601 file->POfill = (WORD *)((UBYTE *)(file->PObuffer)+BASEPOSITION(expr->onfile));
1602 }
1603 SetScratch(AR.infile, &(expr->onfile));
1604/*
1605 Test for whether the first factor is zero.
1606*/
1607 if ( GetFirstBracket(term,nexpr) < 0 ) Terminate(-1);
1608 if ( term[4] != 1 || *term != 8 || term[1] != SYMBOL || term[3] != FACTORSYMBOL || term[4] != 1 ) {
1609 expriszero = 1;
1610 }
1611 SetScratch(AR.infile, &(expr->onfile));
1612/*
1613 Read the prototype. After this we have the file ready for the output at pos.
1614*/
1615 size = GetTerm(BHEAD term);
1616 if ( size <= 0 ) {
1617 MesPrint ("ERROR: something wrong with expression unfactorize_expression");
1618 Terminate(-1);
1619 }
1620 pos = expr->onfile;
1621 ADDPOS(pos, size*sizeof(WORD));
1622/*
1623 Set the brackets straight
1624*/
1625 AR.BracketOn = 1;
1626 AT.BrackBuf = AM.BracketFactors;
1627 AT.bracketinfo = 0;
1628 while ( nfac > 2 ) {
1629 nfacp = nfac - nfac%2;
1630/*
1631 Prepare the bracket index. We have:
1632 e->bracketinfo: the old input bracket index
1633 e->newbracketinfo: the bracket index made for our current input
1634 We need to keep e->bracketinfo in case other workers need it (InParallel)
1635 Hence we work with AT.bracketinfo which takes priority.
1636 Note that in Processor we forced a newbracketinfo to be made.
1637*/
1638 if ( AT.bracketinfo != 0 ) ClearBracketIndex(-1);
1639 AT.bracketinfo = expr->newbracketinfo;
1640 OpenBracketIndex(nexpr);
1641/*
1642 Now emulate the terms:
1643 sum_(i,0,nfacp,2,factor_^(i/2+1)*F[factor_^(i+1)]*F[factor_^(i+2)])
1644 +factor_^(nfacp/2+1)*F[factor_^nfac]
1645*/
1646 NewSort(BHEAD0);
1647 if ( expriszero == 0 ) {
1648 for ( i = 0; i < nfacp; i += 2 ) {
1649 t = genericterm; w = term = oldworkpointer;
1650 j = *t; NCOPY(w,t,j);
1651 term[4] = i/2+1;
1652 term[7] = nexpr;
1653 term[16] = i+1;
1654 term[22] = nexpr;
1655 term[31] = i+2;
1656 AT.WorkPointer = term + *term;
1657 Generator(BHEAD term, C->numlhs);
1658 }
1659 if ( nfac > nfacp ) {
1660 t = genericterm2; w = term = oldworkpointer;
1661 j = *t; NCOPY(w,t,j);
1662 term[4] = i/2+1;
1663 term[7] = nexpr;
1664 term[16] = nfac;
1665 AT.WorkPointer = term + *term;
1666 Generator(BHEAD term, C->numlhs);
1667 }
1668 }
1669 if ( EndSort(BHEAD AM.S0->sBuffer,0) < 0 ) {
1671 Terminate(-1);
1672 }
1673/*
1674 Set the file back into reading position
1675*/
1676 SetScratch(file, &pos);
1677 nfac = (nfac+1)/2;
1678 if ( expriszero ) { nfac = 1; }
1679 }
1680 if ( AT.bracketinfo != 0 ) ClearBracketIndex(-1);
1681 AT.bracketinfo = expr->newbracketinfo;
1682 expr->newbracketinfo = 0;
1683/*
1684 Reset the brackets to make them ready for the final pass
1685*/
1686 AR.BracketOn = oldBracketOn;
1687 AT.BrackBuf = oldBrackBuf;
1688 if ( AR.BracketOn ) OpenBracketIndex(nexpr);
1689/*
1690 We distinguish two cases: nfac == 2 and nfac == 1
1691 After preparing the term we skip the factor_ part.
1692*/
1693 NewSort(BHEAD0);
1694 if ( expriszero == 0 ) {
1695 if ( nfac == 1 ) {
1696 t = genericterm2; w = term = oldworkpointer;
1697 j = *t; NCOPY(w,t,j);
1698 term[7] = nexpr;
1699 term[16] = nfac;
1700 }
1701 else if ( nfac == 2 ) {
1702 t = genericterm; w = term = oldworkpointer;
1703 j = *t; NCOPY(w,t,j);
1704 term[7] = nexpr;
1705 term[16] = 1;
1706 term[22] = nexpr;
1707 term[31] = 2;
1708 }
1709 else {
1710 AS.OldOnFile[nexpr] = oldpos;
1711 return(-1);
1712 }
1713 term[4] = term[0]-4;
1714 term += 4;
1715 AT.WorkPointer = term + *term;
1716 Generator(BHEAD term, C->numlhs);
1717 }
1718 if ( EndSort(BHEAD AM.S0->sBuffer,0) < 0 ) {
1720 Terminate(-1);
1721 }
1722/*
1723 Final Cleanup
1724*/
1725 expr->numfactors = 0;
1726 expr->vflags &= ~ISFACTORIZED;
1727 if ( AT.bracketinfo != 0 ) ClearBracketIndex(-1);
1728
1729 AR.infile = oldinfile;
1730 AR.outfile = oldoutfile;
1731 strcpy((char*)AC.Commercial, oldCommercial);
1732 AT.WorkPointer = oldworkpointer;
1733 AS.OldOnFile[nexpr] = oldpos;
1734
1735 return(0);
1736}
1737
1738/*
1739 #] poly_unfactorize_expression :
1740 #[ poly_inverse :
1741*/
1742
1743WORD *poly_inverse(PHEAD WORD *arga, WORD *argb) {
1744
1745#ifdef WITHFLINT
1746 if ( AC.FlintPolyFlag && AC.ncmod==0 ) {
1747 return flint_inverse(BHEAD arga, argb);
1748 }
1749#endif
1750
1751#ifdef DEBUG
1752 cout << "*** [" << thetime() << "] CALL : poly_inverse" << endl;
1753#endif
1754
1755 // Extract variables
1756 vector<WORD *> e;
1757 e.reserve(2);
1758 e.push_back(arga);
1759 e.push_back(argb);
1760 poly::get_variables(BHEAD e, false, true);
1761
1762 if (AN.poly_num_vars > 1) {
1763 MLOCK(ErrorMessageLock);
1764 MesPrint ((char*)"ERROR: multivariate polynomial inverse is generally impossible");
1765 MUNLOCK(ErrorMessageLock);
1766 Terminate(-1);
1767 }
1768
1769 poly finalden(BHEAD 1), finalres(BHEAD 1);
1770 int ressize = 0;
1771 WORD *res = NULL;
1772
1773 // Convert to polynomials
1774 poly dena(BHEAD 0); // We need to keep the overall denominator of arga, to multiply the result
1775 poly a(poly::argument_to_poly(BHEAD arga, false, true, &dena));
1776 poly b(poly::argument_to_poly(BHEAD argb, false, true));
1777
1778 // Divide out the integer content, FORM has not already done this.
1779 poly content_a(BHEAD 0), content_b(BHEAD 0);
1780 content_a = polygcd::integer_content(a);
1781 content_b = polygcd::integer_content(b);
1782 a /= content_a;
1783 b /= content_b;
1784
1785 poly invamodp(BHEAD 0), invbmodp(BHEAD 0);
1786 WORD modp = 0;
1787
1788 // Special cases:
1789 // Possibly strange that we give 1 for inverse_(x1,1) but here we take MMA's convention.
1790 if ((a.is_one() && b.is_one()) || a.is_one()) {
1791 finalres = poly(BHEAD 1);
1792 }
1793 else if (b.is_one()) {
1794 finalres = poly(BHEAD 0);
1795 }
1796 else {
1797 // Check for modulus calculus
1798 modp=poly_determine_modulus(BHEAD true, true, "polynomial inverse");
1799 const bool mod_calc = modp==0 ? false : true;
1800 a.setmod(modp,1);
1801 b.setmod(modp,1);
1802
1803 // Check the gcd of a,b: if it is != 1, the inverse does not exist.
1804 poly gcd(polygcd::gcd(a,b));
1805 if (!gcd.is_one()) {
1806 MLOCK(ErrorMessageLock);
1807 if (mod_calc) {
1808 MesPrint ((char*)"ERROR: polynomial inverse does not exist (mod %d)", modp);
1809 }
1810 else {
1811 MesPrint ((char*)"ERROR: polynomial inverse does not exist");
1812 }
1813 MUNLOCK(ErrorMessageLock);
1814 Terminate(-1);
1815 }
1816
1817 bool inv_exists = true;
1818 do {
1819 // If we are not using modulus calculus, find a suitable prime for xgcd:
1820 if (!mod_calc) {
1821 vector<int> x(1,0);
1822 modp = polyfact::choose_prime(a.integer_lcoeff()*b.integer_lcoeff(), x, modp);
1823 }
1824
1825 poly amodp(a,modp,1);
1826 poly bmodp(b,modp,1);
1827
1828 // Calculate gcd
1829 vector<poly> xgcd(polyfact::extended_gcd_Euclidean_lifted(amodp,bmodp));
1830 invamodp = poly(xgcd[0]);
1831 invbmodp = poly(xgcd[1]);
1832
1833 inv_exists = ((invamodp * amodp) % bmodp).is_one();
1834 if (!inv_exists && mod_calc) {
1835 // Control should not reach here!
1836 MLOCK(ErrorMessageLock);
1837 MesPrint ((char*)"ERROR: polynomial inverse does not exist (mod %d) B", modp);
1838 MUNLOCK(ErrorMessageLock);
1839 Terminate(-1);
1840 }
1841
1842 // If the inverse does not exist and we are not working in modulus calculus,
1843 // choose a new prime and try again. This loop should always terminate, as
1844 // we have already checked that gcd(a,b) == 1.
1845 } while (!inv_exists);
1846
1847 // estimate of the size of the Form notation; might be extended later
1848 ressize = invamodp.size_of_form_notation()+1;
1849 res = (WORD *)Malloc1(ressize*sizeof(WORD), "poly_inverse");
1850
1851 // initialize polynomials to store the result
1852 poly primepower(BHEAD modp);
1853 poly inva(invamodp,modp,1);
1854 poly invb(invbmodp,modp,1);
1855
1856 while (true) {
1857 // convert to Form notation
1858 int j=0;
1859 WORD n=0;
1860 for (int i=1; i<inva[0]; i+=inva[i]) {
1861
1862 // check whether res should be extended
1863 while (ressize < j + 2*ABS(inva[i+inva[i]-1]) + (inva[i+1]>0?4:0) + 3) {
1864 int newressize = 2*ressize;
1865
1866 WORD *newres = (WORD *)Malloc1(newressize*sizeof(WORD), "poly_inverse");
1867 WCOPY(newres, res, ressize);
1868 M_free(res, "poly_inverse");
1869 res = newres;
1870 ressize = newressize;
1871 }
1872
1873 res[j] = 1;
1874 if (inva[i+1]>0) {
1875 res[j+res[j]++] = SYMBOL;
1876 res[j+res[j]++] = 4;
1877 res[j+res[j]++] = AN.poly_vars[0];
1878 res[j+res[j]++] = inva[i+1];
1879 }
1880 MakeLongRational(BHEAD (UWORD *)&inva[i+2], inva[i+inva[i]-1],
1881 (UWORD*)&primepower.terms[3], primepower.terms[primepower.terms[1]],
1882 (UWORD *)&res[j+res[j]], &n);
1883 res[j] += 2*ABS(n);
1884 res[j+res[j]++] = SGN(n)*(2*ABS(n)+1);
1885 j += res[j];
1886 }
1887 res[j]=0;
1888
1889 // if modulus calculus is set, this is the answer
1890 if (a.modp != 0) break;
1891
1892 // otherwise check over integers
1893 poly den(BHEAD 0);
1894 poly check(poly::argument_to_poly(BHEAD res, false, true, &den));
1895 // Shortcut: if b's lcoeff doesn't divide the lcoeff of check*a,
1896 // b certainly doesn't divide check*a:
1897 if (poly::divides(b.integer_lcoeff(), check.integer_lcoeff()*a.integer_lcoeff())) {
1898 check = check*a - den;
1899 if (poly::divides(b, check)) break;
1900 }
1901
1902 // if incorrect, lift with quadratic p-adic Newton's iteration.
1903 poly error((poly(BHEAD 1) - a*inva - b*invb) / primepower);
1904 poly errormodpp(error, modp, inva.modn);
1905
1906 inva.modn *= 2;
1907 invb.modn *= 2;
1908
1909 poly dinva((inva * errormodpp) % b);
1910 poly dinvb((invb * errormodpp) % a);
1911
1912 inva += dinva * primepower;
1913 invb += dinvb * primepower;
1914
1915 primepower *= primepower;
1916 }
1917
1918 // One more round trip from form -> poly -> form, to multiply by dena in an easy way
1919 finalres = poly(poly::argument_to_poly(BHEAD res, false, true, &finalden));
1920 }
1921
1922 finalres *= dena;
1923 // The overall denominator additionally needs to be multiplied by content_a:
1924 finalden *= content_a;
1925 const WORD finalden_size = finalden.terms[finalden.terms[1]];
1926 const int finalsize = finalres.size_of_form_notation_with_den(finalden_size)+1;
1927 if (ressize < finalsize) {
1928 if (res != NULL) {
1929 M_free(res, "poly_inverse");
1930 }
1931 res = (WORD *)Malloc1(finalsize*sizeof(WORD), "poly_inverse");
1932 }
1933 poly::poly_to_argument_with_den(finalres, finalden_size,
1934 (UWORD*)&(finalden.terms[finalden.terms[1] - ABS(finalden_size)]), res, false);
1935
1936 // clean up and reset modulo calculation
1937 poly_free_poly_vars(BHEAD "AN.poly_vars_inverse");
1938
1939 AN.ncmod = AC.ncmod;
1940 return res;
1941}
1942
1943/*
1944 #] poly_inverse :
1945 #[ poly_mul :
1946*/
1947
1948WORD *poly_mul(PHEAD WORD *a, WORD *b) {
1949
1950#ifdef DEBUG
1951 cout << "*** [" << thetime() << "] CALL : poly_mul" << endl;
1952#endif
1953
1954#ifdef WITHFLINT
1955 if ( AC.FlintPolyFlag && AC.ncmod==0 ) {
1956 return flint_mul(BHEAD a, b);
1957 }
1958#endif
1959
1960 // Extract variables
1961 vector<WORD *> e;
1962 e.reserve(2);
1963 e.push_back(a);
1964 e.push_back(b);
1965 poly::get_variables(BHEAD e, false, false); // TODO: any performance effect by sort_vars=true?
1966
1967 // Convert to polynomials
1968 poly dena(BHEAD 0);
1969 poly denb(BHEAD 0);
1970 poly pa(poly::argument_to_poly(BHEAD a, false, true, &dena));
1971 poly pb(poly::argument_to_poly(BHEAD b, false, true, &denb));
1972
1973 // Check for modulus calculus
1974 WORD modp = poly_determine_modulus(BHEAD true, true, "polynomial multiplication");
1975 pa.setmod(modp, 1);
1976
1977 // NOTE: mul_ is currently implemented by translating negative powers of
1978 // symbols to extra symbols. For future improvement, it may be better to
1979 // compute
1980 // (content(a) * content(b)) * (a/content(a)) * (b/content(b))
1981 // to avoid introducing extra symbols for "mixed" cases, e.g.,
1982 // (1+x) * (1/x) -> (1+x) * (1+Z1_).
1983 assert(dena.is_integer());
1984 assert(denb.is_integer());
1985 assert(modp == 0 || dena.is_one());
1986 assert(modp == 0 || denb.is_one());
1987
1988 // multiplication
1989 pa *= pb;
1990
1991 // convert to Form notation
1992 WORD *res;
1993 if (dena.is_one() && denb.is_one()) {
1994 res = (WORD *)Malloc1((pa.size_of_form_notation() + 1) * sizeof(WORD), "poly_mul");
1995 poly::poly_to_argument(pa, res, false);
1996 } else {
1997 dena *= denb;
1998 res = (WORD *)Malloc1((pa.size_of_form_notation_with_den(dena[dena[1]]) + 1) * sizeof(WORD), "poly_mul");
1999 poly::poly_to_argument_with_den(pa, dena[dena[1]], (const UWORD *)&dena[2+AN.poly_num_vars], res, false);
2000 }
2001
2002 // clean up and reset modulo calculation
2003 poly_free_poly_vars(BHEAD "AN.poly_vars_mul");
2004 AN.ncmod = AC.ncmod;
2005
2006 return res;
2007}
2008
2009/*
2010 #] poly_mul :
2011 #[ poly_free_poly_vars :
2012*/
2013
2014void poly_free_poly_vars(PHEAD const char *text)
2015{
2016 if ( AN.poly_vars_type == 0 ) {
2017 TermFree(AN.poly_vars, text);
2018 }
2019 else {
2020 M_free(AN.poly_vars, text);
2021 }
2022 AN.poly_num_vars = 0;
2023 AN.poly_vars = 0;
2024}
2025
2026/*
2027 #] poly_free_poly_vars :
2028*/
Definition poly.h:53
static void divmod_heap(const poly &, const poly &, poly &, poly &, bool, bool, bool &)
Definition poly.cc:1579
int LocalConvertToPoly(PHEAD WORD *, WORD *, WORD, WORD)
Definition notation.c:510
LONG EndSort(PHEAD WORD *, int)
Definition sort.c:454
int Generator(PHEAD WORD *, WORD)
Definition proces.c:3249
void LowerSortLevel(void)
Definition sort.c:4661
int StoreTerm(PHEAD WORD *)
Definition sort.c:4244
int NewSort(PHEAD0)
Definition sort.c:359
WORD Compare1(PHEAD WORD *, WORD *, WORD)
Definition sort.c:2341
WORD CompareSymbols(PHEAD WORD *, WORD *, WORD)
Definition sort.c:2804
int SymbolNormalize(WORD *)
Definition normal.c:5195
int poly_factorize_expression(EXPRESSIONS expr)
Definition polywrap.cc:1178
WORD poly_determine_modulus(PHEAD bool multi_error, bool is_fun_arg, string message)
Definition polywrap.cc:79
WORD * poly_ratfun_add(PHEAD WORD *t1, WORD *t2)
Definition polywrap.cc:633
void poly_ratfun_read(WORD *a, poly &num, poly &den)
Definition polywrap.cc:496
void poly_sort(PHEAD WORD *a)
Definition polywrap.cc:590
WORD * poly_gcd(PHEAD WORD *a, WORD *b, WORD fit)
Definition polywrap.cc:124
int poly_ratfun_normalize(PHEAD WORD *term)
Definition polywrap.cc:769
WORD * poly_factorize(PHEAD WORD *argin, WORD *argout, bool with_arghead, bool is_fun_arg)
Definition polywrap.cc:986
int poly_unfactorize_expression(EXPRESSIONS expr)
Definition polywrap.cc:1535
int poly_factorize_argument(PHEAD WORD *argin, WORD *argout)
Definition polywrap.cc:1112
WORD * poly_factorize_dollar(PHEAD WORD *argin)
Definition polywrap.cc:1146
int handle
Definition structs.h:709