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