source: git/Singular/LIB/pfd.lib @ 48c4ba

fieker-DuValspielwiese
Last change on this file since 48c4ba was aec1d5, checked in by Hans Schoenemann <hannes@…>, 4 years ago
pfd.lib: test results
  • Property mode set to 100644
File size: 70.2 KB
Line 
1////////////////////////////////////////////////////////////////////
2version="version pfd.lib 4.1.3.2 Aug_2020 ";
3category="??";
4info="
5LIBRARY: pfd.lib Multivariate Partial Fraction Decomposition
6
7AUTHOR: Marcel Wittmann, e-mail: mwittman@rhrk.uni-kl.de
8
9OVERVIEW:
10This Library implements an algorithm based on the work of E. K. Leinartas to
11write rational functions in mutiple variables as a sum of functions with
12\"smaller\" numerators and denominators.
13This can be used to shorten the IBP reduction coeffcients of multi-loop Feynman
14integrals as shown in [J. Böhm, M. Wittmann, Z. Wu, Y. Xu, Y. Zhang: 'IBP
15reduction coefficients made simple'] (preprint 2020). For this application,
16we also provide a procedure that applies the algorithm to all entries of a
17matrix of rational functions given as one (possibly very big) txt-file.
18
19KEYWORDS: partial fraction; decomposition; Leinartas
20
21PROCEDURES:
22  pfd();                  calculate a partial fraction decomposition
23                          of a rational function
24  checkpfd();             test if a decomposition is equal to a rational
25                          function given by numerator/denominator polynomials
26  evaluatepfd();          substitute values in a partial fraction
27                          decomposition gotten from @code{pfd}
28  displaypfd();           print a decomposition gotten as output of @code{pfd}
29  displaypfd_long();      like @code{display}, but denominators are written out
30  getStringpfd();         turn a decomposition gotten from @code{pfd} into one
31                          string
32  getStringpfd_indexed(); like @code{getStringpfd}, but writing the denominator
33                          factors just as @code{q1},@code{q2},...
34  readInputTXT();         read a matrix of rational functions from a txt-file
35  pfdMat();               apply @code{pfd} to a matrix of rational functions
36                          in parallel (using @ref{parallel_lib}) and save result
37                          as easy-to-read txt-files.
38  checkpfdMat();          test output files of @code{pfdMat} for correctness
39";
40/////////////////////////////////////////////////////////////////////////////
41
42LIB "random.lib";
43LIB "ring.lib";
44LIB "parallel.lib";
45LIB "elim.lib";
46LIB "poly.lib";
47
48/////////////////////////////////////////////////////////////////////////////
49
50static proc mod_init()
51{
52  if (!defined(Tasks)) {LIB "tasks.lib";}
53  // export some static functions so they can be run in parallel using parallelWaitAll
54  exportto(Tasks,pfdWrap);
55  importfrom(Tasks,pfdWrap);
56  exportto(Pfd,pfdWrap);
57
58  exportto(Tasks,testEntry);
59  importfrom(Tasks,testEntry);
60  exportto(Pfd,testEntry);
61}
62
63proc pfd(list #)
64"USAGE:   pfd(f,g[,debug]);   f,g poly, debug int
65          pfd(f,g[,debug]);   f poly, g list, debug int
66          pfd(arguments[, parallelize]);     arguments list, parallelize int
67RETURN:   a partial fraction decomposition of f/g as a list @code{l} where
68          @code{l[1]} is an ideal generate by irreducible polynomials and
69          @code{l[2]} is a list of fractions.
70          Each fraction is represented by a list of
71       @* 1) the numerator polynomial
72       @* 2) an intvec giving the indices @code{i} for which @code{l[1][i]}
73             occurs as a factor in the denominator
74       @* 3) an intvec containing the exponents of those irreducible factors.
75       @* Setting debug to a positive integer measures runtimes and
76          creates a log file (default: debug=0).
77       @* The denominator g can also be given in factorized form as a list of
78          an ideal of irreducible non constant polynomials and an intvec of
79          exponents. This can save time since the first step in the algorithm is
80          to factorize g. (g=list(ideal(0),intvec(0:0)) represents a denominator
81          of 1.)
82       @* If instead of f and g, the input is a single list (or even a list of
83          lists) containing elements of the form list(f,g[,debug]) (f,g[,debug]
84          as above), the algorithm is applied to all entries in parallel (using
85          @ref{parallel_lib}), if @code{parallelize=1} (default) and in sequence
86          if @code{parallelize=0}. A list of the results is returned.
87NOTE:     The result depends on the monomial ordering. For \"small\" results
88          use dp.
89EXAMPLE:  example pfd; shows an example
90SEE ALSO: checkpfd, evaluatepfd, displaypfd, displaypfd_long, pfdMat"
91{
92  short = 0;
93  int i;
94  if(typeof(#[1])=="list")
95  {
96    if(size(#)>1)
97    {
98      if(typeof(#[2])=="list")
99        {list arguments = #;    int parallelize = 1;}
100      else{if(typeof(#[2])=="int")
101        {list arguments = #[1]; int parallelize = #[2];}
102      else {ERROR("wrong type for second argument, expected int");}}
103    }
104    if(parallelize)
105    {
106      for(i=1; i<=size(arguments); i++)
107      {
108        if(typeof(arguments[i][1])=="list") //input is list of lists
109          {arguments[i] = list(arguments[i],1);}
110      }
111      return(parallelWaitAll("pfd",arguments));
112    }
113    else
114    {
115      list results;
116      for(i=1; i<=size(arguments); i++)
117      {
118        if(typeof(arguments[i][1])=="list") //input is list of lists
119          {results[i] = pfd(arguments[i],0);}
120        else
121        {
122          if(size(arguments[i])==2)
123            {results[i] = pfd(arguments[i][1],arguments[i][2]);}
124          else{if(size(arguments[i])==3)
125            {results[i] = pfd(arguments[i][1],arguments[i][2],arguments[i][3]);}
126          else {ERROR("wrong number of arguments, expected 2 or 3");}}
127        }
128      }
129      return(results);
130    }
131  }
132  poly f = #[1];
133  if(typeof(#[2])=="list")
134  {
135    list g=#[2];
136  }
137  else
138  {
139    poly g=#[2];
140  }
141
142  int debug=0; link l=":w ";
143  if(size(#)>2)
144  {
145    debug=#[3];
146    l=":a "+string(debug)+"_log_"+datetime()+".txt";
147    system("--ticks-per-sec",1000);
148  }
149  if(debug)
150  {
151    fprintf(l,"debug: %s", debug);
152    fprintf(l,"size(string(f)) = %s, size(string(g)) = %s %n",
153               size(string(f)), size(string(g)), 0);
154    int counter,tt,ttt;
155  }
156
157  if(f==0)
158  {
159    list dec = list(ideal(),list(list(poly(0),intvec(0:0),intvec(0:0))));
160    if(debug)
161      {fprintf(l,"%ntotal: 0 ms (numerator was 0)",0); close(l);}
162    if(voice<3)
163      {displaypfd(dec);}
164    return(dec);
165  }
166  if(typeof(g)=="poly")
167  {
168    if(deg(g)==0)
169    {
170      list dec = list(ideal(),list(list(f/g,intvec(0:0),intvec(0:0))));
171      if(debug)
172        {fprintf(l,"%ntotal: 0 ms (denominator was constant)",0); close(l);}
173      if(voice<3)
174        {displaypfd(dec);}
175      return(dec);
176    }
177
178    // (1) factorization of the denominator:
179    if(debug) {int t1 = rtimer; write(l,"factorizing ");}
180    list factor = factorize(g);
181    number lcoeff;
182    for(i=2; i<=size(factor[1]); i++) // making polynomials unique
183    {
184      lcoeff = leadcoef(factor[1][i]);
185      factor[1][i] = factor[1][i]/lcoeff;
186      factor[1][1] = factor[1][1]*(lcoeff^factor[2][i]); // polynomial is monic (thus unique)
187      lcoeff = content(factor[1][i]);
188      factor[1][i] = factor[1][i]/lcoeff;
189      factor[1][1] = factor[1][1]*(lcoeff^factor[2][i]); // polynomial has nice coefficients
190    }
191    ideal q = factor[1];
192    f = f/q[1];
193    q=delete(q,1);
194    intvec e = factor[2]; e=delete(e,1);
195    int m = size(q);
196    if(debug) {t1 = rtimer-t1; fprintf(l,"done! (%s ms)", t1);}
197  }
198  else{if(typeof(g)=="list")
199  {
200    if(size(g[1])==0)
201    {
202      list dec = list(ideal(),list(list(f,intvec(0:0),intvec(0:0))));
203      if(debug)
204        {fprintf(l,"%ntotal: 0 ms (denominator was constant)",0); close(l);}
205      if(voice<3)
206        {displaypfd(dec);}
207      return(dec);
208    }
209
210    // denominator is already factorized
211    for(i=1;i<=size(g[1]);i++)
212    {
213      if(size(factorize(g[1][i])[1])>2)
214        {ERROR("factors should be irreducible");}
215    }
216
217    ideal q = g[1];
218    intvec e = g[2];
219    int m = size(q);
220    if(debug) {int t1=0;}
221  }
222  else
223    {ERROR("wrong type for second argument, expected poly or list(ideal,intvec)");}}
224
225  // (2) Nullstellensatz decomposition
226  if(debug)
227    {int t2 = rtimer; write(l,"Nullstellensatz decomposition ");}
228  list terms = list(list(poly(f),1..m,e));
229  list dec,newterms,result;
230  int imax;
231  while(size(terms)>0)
232  {
233    if(debug) {ttt = rtimer; counter++;}
234    imax = size(terms);
235    newterms = list();
236    for(i=1; i<=imax; i++)
237    {
238      result = NSSdecompStep(terms[i],q);
239      if(size(result)>1) {newterms = mergepfd(newterms, result);}
240      else                    {dec = mergepfd(dec,      result);}
241    }
242    terms = newterms;
243    if(debug)
244      {fprintf(l,"  %s: %s ms, %s terms, %s unfinished",
245       counter, rtimer-ttt, size(terms)+size(dec), size(terms));}
246  }
247  if(debug)
248    {t2 = rtimer-t2; fprintf(l,"done! (%s ms, %s terms)", t2, size(dec));}
249
250  // (3) short numerator decomposition
251  if(debug)
252    {int t3 = rtimer; write(l,"short numerator decompositions "); counter=0;}
253  terms = dec;
254  dec = list();
255  while(size(terms)>0)
256  {
257    if(debug) {tt = rtimer; counter++;}
258    imax = size(terms);
259    newterms = list();
260    for(i=1; i<=imax; i++)
261    {
262      result = shortNumeratorDecompStep(terms[i],q,debug,l);
263
264      if(debug) {ttt = rtimer;}
265      newterms = mergepfd(newterms, result[1]);
266      dec = mergepfd(dec, result[2]);
267      if(debug)
268        {fprintf(l,"      merging: %s ms, %s new terms",
269         rtimer-ttt, size(result[1]));}
270    }
271    terms = newterms;
272    if(debug)
273      {fprintf(l,"  %s: %s ms, %s terms, %s unfinished",
274       counter, rtimer-tt, size(terms)+size(dec), size(terms));}
275  }
276  if(debug)
277    {t3 = rtimer-t3; fprintf(l,"done! (%s ms, %s terms)", t3, size(dec));}
278
279  // (4) algebraic dependence decomposition
280  if(debug)
281    {int t4 = rtimer; write(l,"algebraic dependence decomposition "); counter=0;}
282  terms = dec;
283  dec = list();
284  while(size(terms)>0)
285  {
286    if(debug) {tt = rtimer; counter++;}
287    imax = size(terms);
288    newterms = list();
289    for(i=1; i<=imax; i++)
290    {
291      result = algDependDecompStep(terms[i],q,debug,l);
292
293      if(debug) {ttt = rtimer;}
294      if(size(result)>1) {newterms = mergepfd(newterms, result);}
295      else                    {dec = mergepfd(dec,      result);}
296      if(debug)
297        {fprintf(l,"      merging: %s ms, %s new terms", rtimer-ttt, size(result));}
298    }
299    terms = newterms;
300    if(debug)
301      {fprintf(l,"  %s: %s ms, %s terms, %s unfinished",
302       counter, rtimer-tt, size(terms)+size(dec),size(terms));}
303  }
304  if(debug)
305    {t4 = rtimer-t4; fprintf(l,"done! (%s ms, %s terms)", t4, size(dec));}
306
307  // (5) numerator decomposition
308  if(debug)
309    {int t5 = rtimer; write(l,"numerator decompositions "); counter=0;}
310  terms = dec;
311  dec = list();
312  while(size(terms)>0)
313  {
314    if(debug) {tt = rtimer; counter++;}
315    imax = size(terms);
316    newterms = list();
317    for(i=1; i<=imax; i++)
318    {
319      result = numeratorDecompStep(terms[i],q,debug,l);
320
321      if(debug) {ttt = rtimer;}
322      newterms = mergepfd(newterms, result[1]);
323      dec = mergepfd(dec, result[2]);
324      if(debug)
325        {fprintf(l,"      merging: %s ms, %s new terms", rtimer-ttt, size(result[1]));}
326    }
327    terms = newterms;
328    if(debug)
329      {fprintf(l,"  %s: %s ms, %s terms, %s unfinished",
330       counter, rtimer-tt, size(terms)+size(dec), size(terms));}
331  }
332  if(debug)
333    {t5 = rtimer-t5; fprintf(l,"done! (%s ms, %s terms)", t5, size(dec));}
334
335  dec = list(q,dec);
336  if(debug) {fprintf(l,"%ntotal: %s ms", t1+t2+t3+t4+t5); close(l);}
337  if(voice<3) {displaypfd(dec);}
338  return(dec);
339}
340example
341{
342  "EXAMPLE:";
343  echo=voice;
344  ring R = 0,(x,y),dp;
345  poly f = x^3+3*x^2*y+2*y^2-x^2+4*x*y;
346  poly g = x^2*y*(x-1)*(x-y)^2;
347
348  list dec = pfd(f,g);
349
350  displaypfd_long(dec);   // display result
351  checkpfd(list(f,g),dec);   // check for equality to f/g
352
353  // calculate decompositions of a 2x2 matrix of rational functions at once:
354  list arguments = list(list(f, g),          list(1, f)     ),
355                        list(list(x*y, y+1), list(1, x^2-y^2));
356
357  dec = pfd(arguments);
358
359  // the result has the same shape as the
360  // input (2x2 matrix as list of lists):
361  displaypfd_long(dec[1][1]);
362  displaypfd_long(dec[1][2]);
363  displaypfd_long(dec[2][1]);
364  displaypfd_long(dec[2][2]);
365
366  // a more complicated example
367  ring S = 0,(s12,s15,s23,s34,s45),dp;
368  poly f = (7*s12^4*s15^2 + 11*s12^3*s15^3 + 4*s12^2*s15^4 - 10*s12^4*s15*s23
369    - 14*s12^3*s15^2*s23 - 4*s12^2*s15^3*s23 + 3*s12^4*s23^2 + 3*s12^3*s15*s23^2
370    + 13*s12^4*s15*s34 + 12*s12^3*s15^2*s34 + 2*s12^2*s15^3*s34
371    - 5*s12^4*s23*s34 + 33*s12^3*s15*s23*s34 + 49*s12^2*s15^2*s23*s34
372    + 17*s12*s15^3*s23*s34 - 17*s12^3*s23^2*s34 - 19*s12^2*s15*s23^2*s34
373    - 5*s12*s15^2*s23^2*s34 - 24*s12^3*s15*s34^2 - 15*s12^2*s15^2*s34^2
374    + 2*s12*s15^3*s34^2 + 15*s12^3*s23*s34^2 - 34*s12^2*s15*s23*s34^2
375    - 31*s12*s15^2*s23*s34^2 + 2*s15^3*s23*s34^2 + 33*s12^2*s23^2*s34^2
376    + 29*s12*s15*s23^2*s34^2 + 5*s15^2*s23^2*s34^2 + 9*s12^2*s15*s34^3
377    - 4*s12*s15^2*s34^3 - 15*s12^2*s23*s34^3 + 9*s12*s15*s23*s34^3
378    - 4*s15^2*s23*s34^3 - 27*s12*s23^2*s34^3 - 13*s15*s23^2*s34^3
379    + 2*s12*s15*s34^4 + 5*s12*s23*s34^4 + 2*s15*s23*s34^4 + 8*s23^2*s34^4
380    - 6*s12^3*s15^2*s45 - 9*s12^2*s15^3*s45 - 2*s12*s15^4*s45
381    + 30*s12^3*s15*s23*s45 + 56*s12^2*s15^2*s23*s45 + 24*s12*s15^3*s23*s45
382    - 12*s12^3*s23^2*s45 - 23*s12^2*s15*s23^2*s45 - 10*s12*s15^2*s23^2*s45
383    - 30*s12^3*s15*s34*s45 - 32*s12^2*s15^2*s34*s45 - 6*s12*s15^3*s34*s45
384    + 7*s12^3*s23*s34*s45 - 86*s12^2*s15*s23*s34*s45 - 104*s12*s15^2*s23*s34*s45
385    - 15*s15^3*s23*s34*s45 + 41*s12^2*s23^2*s34*s45 + 51*s12*s15*s23^2*s34*s45
386    + 10*s15^2*s23^2*s34*s45 - 5*s12^3*s34^2*s45 + 33*s12^2*s15*s34^2*s45
387    + 14*s12*s15^2*s34^2*s45 - 2*s15^3*s34^2*s45 - 21*s12^2*s23*s34^2*s45
388    + 62*s12*s15*s23*s34^2*s45 + 28*s15^2*s23*s34^2*s45 - 46*s12*s23^2*s34^2*s45
389    - 28*s15*s23^2*s34^2*s45 + 10*s12^2*s34^3*s45 - s12*s15*s34^3*s45
390    + 4*s15^2*s34^3*s45 + 21*s12*s23*s34^3*s45 - 6*s15*s23*s34^3*s45
391    + 17*s23^2*s34^3*s45 - 5*s12*s34^4*s45 - 2*s15*s34^4*s45 - 7*s23*s34^4*s45
392    - 6*s12^2*s15^2*s45^2 - 5*s12*s15^3*s45^2 - 2*s15^4*s45^2
393    - 28*s12^2*s15*s23*s45^2 - 42*s12*s15^2*s23*s45^2 - 10*s15^3*s23*s45^2
394    + 9*s12^2*s23^2*s45^2 + 10*s12*s15*s23^2*s45^2 + 24*s12^2*s15*s34*s45^2
395    + 36*s12*s15^2*s34*s45^2 + 10*s15^3*s34*s45^2 - 11*s12^2*s23*s34*s45^2
396    + 31*s12*s15*s23*s34*s45^2 + 25*s15^2*s23*s34*s45^2
397    - 18*s12*s23^2*s34*s45^2 - 10*s15*s23^2*s34*s45^2 + 4*s12^2*s34^2*s45^2
398    - 29*s12*s15*s34^2*s45^2 - 17*s15^2*s34^2*s45^2 + 27*s12*s23*s34^2*s45^2
399    + 2*s15*s23*s34^2*s45^2 + 9*s23^2*s34^2*s45^2 - 3*s12*s34^3*s45^2
400    + 10*s15*s34^3*s45^2 - 16*s23*s34^3*s45^2 - s34^4*s45^2 + 6*s12*s15^2*s45^3
401    + 3*s15^3*s45^3 + 8*s12*s15*s23*s45^3 + 10*s15^2*s23*s45^3
402    - 8*s12*s15*s34*s45^3 - 10*s15^2*s34*s45^3 + 9*s12*s23*s34*s45^3
403    + s12*s34^2*s45^3 + 8*s15*s34^2*s45^3 - 9*s23*s34^2*s45^3 - s34^3*s45^3
404    - s15^2*s45^4 + s15*s34*s45^4);
405  poly g = 4*s12*s15*(s12 + s15 - s34)*(s15 - s23 - s34)*(s12 + s23 - s45)
406                                 *(s12 - s34 - s45)*(s12 + s15 - s34 - s45)*s45;
407
408  list dec = pfd(f,g);
409
410  displaypfd(dec);
411  checkpfd(list(f,g),dec);
412
413  // size comparison:
414  size(string(f)) + size(string(g));
415  size(getStringpfd(dec));
416}
417
418static proc NSSdecompStep(list l, ideal q)
419{
420  poly f=l[1];
421  intvec indices=l[2];
422  intvec e=l[3];
423  int m = size(indices);
424
425  if(m==0) // denominator is 1
426  {
427    return(list(l)); //do nothing, return input
428  }
429
430  ideal qe = q[indices];
431  for(int i=1; i<=m; i++)
432  {
433    qe[i] = qe[i]^e[i];
434  }
435  matrix T;
436  ideal qe_std = liftstd(qe,T);
437
438  if(deg(qe_std) == 0)
439  {
440    T = T/qe_std[1]; // now 1 = T[1,1]*qe[1] + ... + T[m,1]*qe[m] is a Nullstellensatz certificate
441    list dec;
442    poly h;
443    for(i=1; i<=m; i++)
444    {
445      h = T[i,1];
446      if(h != 0)
447      {
448        dec[size(dec)+1] = list(f*h,delete(indices,i),delete(e,i));
449      }
450    }
451    return(dec);
452  }
453  else
454  {
455    return(list(l)); //do nothing, return input
456  }
457}
458
459static proc shortNumeratorDecompStep(list l, ideal q, list #)
460{
461  int debug=0;
462  if(size(#)>0) {debug=#[1]; link ll=#[2];}
463  if(debug) {system("--ticks-per-sec",1000); int tt=rtimer;}
464
465  poly f=l[1];
466  intvec indices=l[2];
467  intvec e=l[3];
468  int m = size(indices);
469
470  if(m==0) // denominator is 1
471  {
472    if(debug)
473      {fprintf(ll,"      shortNumeratorDecompStep: %s ms (m=%s, e=%s) "
474                  +"--> constant denominator", rtimer-tt, m, e);}
475    return(list(list(),list(l))); //do nothing, return input
476  }
477
478  ideal q_denom = q[indices]; //factors in the denominator
479  matrix T;
480  ideal q_std = liftstd(q_denom,T);
481  list divrem = division(f,q_std);
482  poly r = divrem[2][1]/divrem[3][1,1];
483
484  if(r!=0)
485  {
486    if(debug)
487      {fprintf(ll,"      shortNumeratorDecompStep: %s ms (m=%s, e=%s) "
488                  +"--> remainder is nonzero", rtimer-tt, m, e);}
489    return(list(list(),list(l))); // if there is a rest, decomposing further would
490                                  // not help in the next step (alg. depend. decomposition)
491  }
492
493  matrix a = divrem[1]/divrem[3][1,1]; // now f = r + a[1,1]*q_std[1] + ... +a[m,1]*q_std[m]
494  a = T*a; // lift coefficients     ==>    now f = r + a[1,1]*q[1]     + ... +a[m,1]*q[m]
495
496  // reduce w.r.t. groebner basis of syz(q) to make the numerators "smaller":
497  vector v;
498  for(int i=1; i<=m; i++) {v = v + gen(i)*a[i,1];}
499  v = reduce(v, std(syz(q_denom)));
500
501  list fraction,dec;
502  for(i=1; i<=m; i++)
503  {
504    if(v[i] == 0)
505    {
506      i++;
507      continue;
508    }
509    fraction[1] = v[i];
510    if(e[i]==1)
511      {
512        fraction[2] = delete(indices,i);
513        fraction[3] = delete(e,i);
514      }
515    else
516    {
517      fraction[2] = indices;
518      fraction[3] = e;
519      fraction[3][i] = fraction[3][i] - 1;
520    }
521    dec[size(dec)+1] = fraction;
522    }
523
524  if(debug)
525    {fprintf(ll,"      shortNumeratorDecompStep: %s ms (m=%s, e=%s, deg(v)=%s, size(v)=%s)",
526     rtimer-tt, m, e, deg(v), size(v));}
527  return(list(dec,list()));
528}
529
530static proc algDependDecompStep(list l, ideal q, list #)
531{
532  int debug=0;
533  if(size(#)>0) {debug=#[1]; link ll=#[2];}
534  if(debug) {system("--ticks-per-sec",1000); int tt=rtimer;}
535  def br = basering;
536  int d = nvars(br);
537  intvec indices=l[2];
538  int m = size(indices);
539  intvec e=l[3];
540  int i;
541
542  if(m==0) // denominator is 1
543  {
544    if(debug)
545      {fprintf(ll,"      algDependDecompStep: %s ms (m=%s, e=%s)", rtimer-tt, m, e);}
546    return(list(l)); //do nothing, return input
547  }
548
549  if(m<=d)
550  {
551    if(size(syz(module(transpose(jacob(ideal(q[indices]))))))==0) //jacobian criterion
552    {
553      if(debug)
554        {fprintf(ll,"      algDependDecompStep: %s ms (m=%s, e=%s) "
555                    +"--> alg. indep.", rtimer-tt, m, e);}
556      return(list(l)); //do nothing, return input
557    }
558  }
559
560  def R = changeord(list(list("dp",m+d)),extendring(m, "y(", "dp", 1, changevar("x()",br)));
561  setring(R);
562
563  list l = fetch(br,l);
564  ideal q = fetch(br,q);
565  poly f=l[1];
566
567  ideal I;
568  for(i=1; i<=m; i++)
569  {
570    I[i] = y(i)-q[indices[i]];//^e[i];
571  }
572
573  ideal annihilatingPolys = eliminate(I,intvec(1..d));
574
575  poly g = annihilatingPolys[1];
576
577  poly tail = g[size(g)]; // term of lowest dp-order (thus lowest degree)
578  number tcoeff = leadcoef(tail);
579  intvec texpon = leadexp(tail);
580  texpon = texpon[(d+1)..(d+m)];
581  g = g-tail;
582  poly term;
583  number coeff;
584  intvec expon;
585  list fraction,dec;
586  int pow;
587  int jmax = size(g);
588  for(int j=1; j<=jmax; j++)
589  {
590    term = g[j];
591    coeff = leadcoef(term);
592    expon = leadexp(term);
593    expon = expon[(d+1)..(d+m)];
594    fraction[1] = -f*coeff/tcoeff;
595    fraction[2] = intvec(0:0);
596    fraction[3] = intvec(0:0);
597    for(i=1; i<=m; i++)
598    {
599      //pow = e[i]*(expon[i]-texpon[i]-1);
600      pow = expon[i]-texpon[i]-e[i];
601      if(pow>=0)
602      {
603        fraction[1] = fraction[1]*q[indices[i]]^pow;
604      }
605      else
606      {
607        fraction[2][size(fraction[2])+1] = indices[i];
608        fraction[3][size(fraction[3])+1] = -pow;
609      }
610    }
611    dec[size(dec)+1] = fraction;
612  }
613  setring(br);
614  list dec = fetch(R,dec);
615  if(debug)
616    {fprintf(ll,"      algDependDecompStep: %s ms (m=%s, e=%s)", rtimer-tt, m, e);}
617  return(dec);
618}
619
620static proc numeratorDecompStep(list l, ideal q, list #)
621{
622  int debug=0;
623  if(size(#)>0) {debug=#[1]; link ll=#[2];}
624  if(debug) {system("--ticks-per-sec",1000); int tt=rtimer;}
625
626  poly f=l[1];
627  intvec indices=l[2];
628  intvec e=l[3];
629  int m = size(indices);
630
631  if(m==0) // denominator is 1
632  {
633    if(debug)
634      {fprintf(ll,"      numeratorDecompStep: %s ms (m=%s, e=%s) "
635                  +"--> constant denominator", rtimer-tt, m, e);}
636    return(list(list(),list(l))); //do nothing, return input
637  }
638
639  ideal q_denom = q[indices]; //factors in the denominator
640  matrix T;
641  ideal q_std = liftstd(q_denom,T);
642  list divrem = division(f,q_std);
643  matrix a = divrem[1]/divrem[3][1,1];
644  poly r = divrem[2][1]/divrem[3][1,1]; // now f = r + a[1,1]*q_std[1] + ... +a[m,1]*q_std[m]
645  a = T*a; // lift coefficients     ==>    now f = r + a[1,1]*q[1]     + ... +a[m,1]*q[m]
646
647  // reduce w.r.t. groebner basis of syz(q) to make the numerators "smaller"
648  vector v;
649  for(int i=1; i<=m; i++) {v = v + gen(i)*a[i,1];}
650  v = reduce(v, std(syz(q_denom)));
651
652  list fraction,dec,rest;
653  if(r!=0)
654  {
655    rest[1] = list(r,indices,e);
656  }
657  for(i=1; i<=m; i++)
658  {
659    if(v[i] == 0)
660    {
661      i++;
662      continue;
663    }
664    fraction[1] = v[i];
665    if(e[i]==1)
666      {
667        fraction[2] = delete(indices,i);
668        fraction[3] = delete(e,i);
669      }
670    else
671    {
672      fraction[2] = indices;
673      fraction[3] = e;
674      fraction[3][i] = fraction[3][i] - 1;
675    }
676    dec[size(dec)+1] = fraction;
677  }
678
679  if(debug)
680    {fprintf(ll,"      numeratorDecompStep: %s ms (m=%s, e=%s, deg(v)=%s, size(v)=%s)",
681     rtimer-tt, m, e, deg(v), size(v));}
682  return(list(dec,rest));
683}
684
685static proc mergepfd(list dec1, list dec2)
686// assumes dec1 is already sorted w.r.t. dp in the denominator exponents
687{
688  int n1=size(dec1);
689  int n2=size(dec2);
690  if(n2==0) {return(dec1);}
691  int i;
692  int a,b,m;
693  list entry;
694  for(i=1; i<=n2; i++)
695  {
696    entry = dec2[i];
697    if(n1==0)
698    {
699      dec1=list(entry); n1++;
700      i++; continue;
701    }
702
703    a=1;
704    b=n1;
705    m = (a+b) div 2;
706    while(b>a)
707    {
708      if(is_dp_smaller(dec1[m][2], dec1[m][3], entry[2], entry[3]))
709      {
710        a=m+1;
711      }
712      else
713      {
714        b=m;
715      }
716      m = (a+b) div 2;
717    }
718    if(is_dp_smaller(dec1[a][2], dec1[a][3], entry[2], entry[3]))
719    {         // numerator exponent vector of dec1[a] is dp-smaller than entry
720      dec1=insert(dec1,entry,a); n1++;
721    }
722    else{if(entry[2]==dec1[a][2] && entry[3]==dec1[a][3])
723    {
724      dec1[a][1] = dec1[a][1] + entry[1]; //same denominator: add numerators
725      if(dec1[a][1]==0)
726      {
727        dec1 = delete(dec1,a); n1--;
728      }
729    }
730    else
731    {
732      dec1=insert(dec1,entry,a-1); n1++;
733    }}
734  }
735  return(dec1);
736}
737
738static proc is_dp_smaller(intvec indices1, intvec e1, intvec indices2, intvec e2)
739{
740  if(size(e2)==0) {return(0);}
741  if(size(e1)==0) {return(1);}
742  int s1,s2 = sum(e1),sum(e2);
743  if(s1<s2) {return(1);}
744  if(s1>s2) {return(0);}
745  int n1,n2 = size(indices1),size(indices2);
746  int imax = min(n1,n2);
747  for(int i=0; i<imax; i++)
748  {
749    if(indices1[n1-i]>indices2[n2-i]) {return(1);}
750    if(indices1[n1-i]<indices2[n2-i]) {return(0);}
751    if(e1[n1-i]>e2[n2-i]) {return(1);}
752    if(e1[n1-i]<e2[n2-i]) {return(0);}
753  }
754  return(0);
755}
756
757proc checkpfd(list fraction, list dec, list #)
758"USAGE:   checkpfd(list(f,g),dec[,N,C]);   f,g poly, dec list, N,C int
759RETURN:   0 or 1
760PURPOSE:  tests for (mathematical) equality of f/g and a partial fraction
761          decomposition dec. The list dec has to have the same structure as the
762          output of @ref{pfd}.
763       @* The denominator g can also be given in factorized form as a list of
764          an ideal of irreducible non constant polynomials and an intvec of
765          exponents. (g=list(ideal(0),intvec(0:0)) represents a denominator
766          of 1.)
767       @* By default the test is done (exactly) by bringing all terms of the
768          decomposition on the same denominator and comparing to f/g.
769       @* If additional parameters N [, C] are given and if N>0, a probabilistic
770          method is chosen: evaluation at N random points with coordinates
771          between -C and C. This may be faster for big polynomials.
772SEE ALSO: pfd
773EXAMPLE:  example checkpfd; shows an example"
774{
775  poly f=fraction[1];
776  def g=fraction[2];
777  if(size(#)>0)
778  {
779    if(#[1]>0)
780    {
781      int N = #[1]; // number of random tests
782      int max_val=16;
783      if(size(#)>1) {max_val = #[2];}
784      ideal values;
785      ideal vars = maxideal(1);
786      int d=nvars(basering);
787      number val1,val2;
788      int div_by_0;
789      int i,j;
790      for(i=1; i<=N; i++)
791      {
792        values = ideal(random(max_val,1,d));
793
794        if(typeof(g)=="poly")
795        {
796          val1 = number(substitute(g,vars,values));
797        }
798        else{if(typeof(g)=="list") //denominator given in factorized form
799        {
800          val1 = number(1);
801          for(j=1; j<=size(g[1]); j++)
802          {
803            val1 = val1 * number(substitute(g[1][j]^g[2][j],vars,values));
804          }
805        }
806        else {ERROR("wrong type for second argument, expected poly or list");}}
807
808        if(val1==0) {continue;}
809        val1 = number(substitute(f,vars,values))/val1;
810        val2, div_by_0 = evaluatepfd(dec,values,2);
811        if(div_by_0) {continue;}
812        if(val1 != val2)
813        {
814          return(0);
815        }
816      }
817      return(1);
818    }
819  }
820  ideal q = dec[1];
821  dec = dec[2];
822
823  int m = size(q);
824  int jmax,j,ind,k;
825  intvec e_max; e_max[m]=0;
826  int imax = size(dec);
827  for(int i=1; i<=imax; i++)
828  {
829    jmax = size(dec[i][2]);
830    for(j=1; j<=jmax; j++)
831    {
832      ind = dec[i][2][j];
833      e_max[ind] = max(e_max[ind],dec[i][3][j]);
834    }
835  }
836  poly num;
837  poly sum_of_numerators = 0;
838  intvec e;
839  for(i=1; i<=imax; i++)
840  {
841    e = e_max;
842    jmax = size(dec[i][2]);
843    for(j=1; j<=jmax; j++)
844    {
845      ind = dec[i][2][j];
846      e[ind] = e[ind]-dec[i][3][j];
847    }
848    num = dec[i][1];
849    for(j=1; j<=m; j++)
850    {
851      num = num * q[j]^(e[j]);
852    }
853    sum_of_numerators = sum_of_numerators + num;
854  }
855
856  // the decomposition is now equal to sum_of_numerators/product(q[i]^e_max[i]) (i from 1 to imax)
857  // now: check if this equals f/g:
858
859  if(typeof(g)=="poly")
860  {
861    list fact = factorize(g);
862    ideal q_g = delete(fact[1],1);
863    intvec e_g = delete(fact[2],1);
864    num = f/fact[1][1];
865  }
866  else{if(typeof(g)=="list") //denominator given in factorized form
867  {
868    ideal q_g = g[1];
869    intvec e_g = g[2];
870    num = f;
871  }
872  else {ERROR("wrong type for second argument, expected poly or list");}}
873
874  int m_g = size(q_g);
875  int expon;
876  number c;
877  for(i=1; i<=m_g; i++)
878  {
879
880    j=0;
881    for(k=1; k<=m; k++)
882    {
883      c = leadcoef(q[k])/leadcoef(q_g[i]);
884      if(c*q_g[i]==q[k]) {j=k; break;}
885    }
886
887    if(j==0)
888    {
889      sum_of_numerators = sum_of_numerators*q_g[i]^e_g[i];
890    }
891    else
892    {
893      num = num*(c^e_g[i]); //fix lead coefficient
894
895      expon = e_g[i]-e_max[j];
896      if(expon>0)
897      {
898        sum_of_numerators = sum_of_numerators*q[j]^expon;
899      }
900      else{if(expon<0)
901      {
902        num = num*q[j]^(-expon);
903      }}
904    }
905  }
906  return(sum_of_numerators==num);
907}
908example
909{
910  "EXAMPLE:";
911  echo=voice;
912  ring R = 0,(x,y),dp;
913  poly f = x^3+3*x^2*y+2*y^2-x^2+4*x*y;
914  poly g = x^2*y*(x-1)*(x-y)^2;
915
916  // partial fraction decomposition of f/g:
917  list dec = pfd(f,g);
918  // some other decomposition (not equal to f/g):
919  list wrong_dec = pfd(f+1,g);
920
921  displaypfd_long(dec);
922  list fraction = f,g;
923
924  // exact test:
925  checkpfd(fraction,dec);
926  checkpfd(fraction,wrong_dec);
927  // probabilistic test (evaluation at 10 random points):
928  checkpfd(fraction,dec,10);
929  checkpfd(fraction,wrong_dec,10);
930}
931
932proc evaluatepfd(list dec, ideal values, list #)
933"USAGE:   evaluatepfd(dec, values[, mode]);   dec list, values ideal, mode int
934RETURN:   the number gotten by substituting the numbers generating the ideal
935          values for the variables in the partial fraction decomposition dec.
936          The list dec has to have the same structure as the output of @ref{pfd}.
937       @* mode = 1: raise Error in case of division by 0 (default)
938       @* mode = 2: return a second integer which is 1 if the denominator
939          becomes 0, and 0 otherwise.
940SEE ALSO: pfd
941EXAMPLE:  example evaluatepfd; shows an example"
942{
943  int mode = 1;
944  if(size(#)>0) {mode = #[1];}
945
946  ideal vars = maxideal(1); // ideal generate by ring variables
947  number val=0;
948  number denom;
949  int m,i,j;
950  for(i=1; i<=size(dec[2]); i++)
951  {
952    denom = 1;
953    m = size(dec[2][i][2]);
954    for(j=1; j<=m; j++)
955    {
956      denom = denom * (number(substitute(dec[1][dec[2][i][2][j]],vars,values)))^dec[2][i][3][j];
957      if(denom == 0)
958      {
959        if(mode==1) {ERROR("division by 0");}
960        else {return(0,1);}
961      }
962    }
963    val = val + number(substitute(dec[2][i][1],vars,values))/denom;
964  }
965  if(mode==1) {return(val);}
966  else {return(val,0);}
967}
968example
969{
970  "EXAMPLE:";
971  echo=voice;
972  ring R = 0,(x,y),dp;
973  poly f = x+2*y;
974  poly g = x^2-y^2;
975
976  // partial fraction decomposition of f/g:
977  list dec = pfd(f,g);
978
979  displaypfd_long(dec);
980  ideal values = 2,1;
981  evaluate(dec,values);
982  // compare: f(2,1)/g(2,1) = (2+2*1)/(2^2-1^1) = 4/7
983}
984
985static proc find_entry(def l, def entry)
986{
987  int n=size(l);
988  for(int i=1; i<=n; i++)
989  {
990    if(entry==l[i]) {return(i);}
991  }
992  return(0);
993}
994
995proc displaypfd(list dec)
996"USAGE:   displaypfd(dec);   dec list
997PURPOSE:  print a partial fraction decomposition dec in a readable way.
998          The list dec has to have the same structure as the output of @ref{pfd}.
999SEE ALSO: pfd, displaypfd_long, getStringpfd, getStringpfd_indexed
1000EXAMPLE:  example displaypfd; shows an example"
1001{
1002  ideal q = dec[1];
1003  dec = dec[2];
1004  int imax=size(dec);
1005  int jmax,j;
1006  string s1,s2;
1007  for(int i=1; i<=imax; i++)
1008  {
1009    s1 = "(" + string(dec[i][1]);
1010    if(i>1) {s1 = "+ " + s1;}
1011    else {s1 = "  " + s1;}
1012    if(size(dec[i][2])>0)
1013    {
1014      s2 = ") / (";
1015      jmax = size(dec[i][2]);
1016      for(j=1; j<=jmax; j++)
1017      {
1018        s2 = s2 + "q" + string(dec[i][2][j]);
1019        if(dec[i][3][j] != 1) {s2 = s2 + "^" + string(dec[i][3][j]);}
1020        if(j<jmax) {s2 = s2 + "*";}
1021      }
1022      s2 = s2 + ")";
1023    }
1024    else {s2 = ")";}
1025
1026    if(size(s1)+size(s2)>192) {s1=s1[1..(192-size(s2))]; s1 = s1 + "... ";}
1027    print(s1+s2);
1028  }
1029  print("where");
1030  for(i=1; i<=size(q); i++)
1031  {
1032    printf("q%s = %s",i,q[i]);
1033  }
1034  printf("(%s terms)%n", size(dec), 0);
1035}
1036example
1037{
1038  "EXAMPLE:";
1039  echo=voice;
1040  ring R = 0,(x,y),dp;
1041  poly f = x^3+3*x^2*y+2*y^2-x^2+4*x*y;
1042  poly g = x^2*y*(x-1)*(x-y)^2;
1043
1044  list dec = pfd(f,g);
1045
1046  displaypfd(dec);
1047}
1048
1049proc displaypfd_long(list dec)
1050"USAGE:   displaypfd_long(dec);   dec list
1051PURPOSE:  like @ref{displaypfd}, but denominators are written out, not indexed.
1052SEE ALSO: pfd, displaypfd, getStringpfd, getStringpfd_indexed
1053EXAMPLE:  example displaypfd_long; shows an example"
1054{
1055  ideal q = dec[1];
1056  dec = dec[2];
1057  print("  "+getStringFraction(dec[1],q));
1058  for(int i=2; i<=size(dec); i++)
1059  {
1060    print("+ "+getStringFraction(dec[i],q));
1061  }
1062  printf("(%s terms)%n", size(dec), 0);
1063}
1064example
1065{
1066  "EXAMPLE:";
1067  echo=voice;
1068  ring R = 0,(x,y),dp;
1069  poly f = x^3+3*x^2*y+2*y^2-x^2+4*x*y;
1070  poly g = x^2*y*(x-1)*(x-y)^2;
1071
1072  list dec = pfd(f,g);
1073
1074  displaypfd_long(dec);
1075}
1076
1077proc getStringpfd(list dec)
1078"USAGE:   getStringpfd(dec);   dec list
1079PURPOSE:  turn a partial fraction decomposition dec into one string. The list
1080          dec has to have the same structure as the output of @ref{pfd}.
1081SEE ALSO: pfd, getStringpfd_indexed, displaypfd, displaypfd_long
1082EXAMPLE:  example getStringpfd; shows an example"
1083{
1084  ideal q = dec[1];
1085  dec = dec[2];
1086  string s = getStringFraction(dec[1],q);
1087  for(int i=2; i<=size(dec); i++)
1088  {
1089    s = s+" + "+getStringFraction(dec[i],q);
1090  }
1091  return(s);
1092}
1093example
1094{
1095  "EXAMPLE:";
1096  echo=voice;
1097  ring R = 0,(x,y),dp;
1098  poly f = x^3+3*x^2*y+2*y^2-x^2+4*x*y;
1099  poly g = x^2*y*(x-1)*(x-y)^2;
1100
1101  list dec = pfd(f,g);
1102
1103  displaypfd_long(dec);
1104  getStringpfd(dec);
1105}
1106
1107proc getStringpfd_indexed(list dec)
1108"USAGE:   getStringpfd_indexed(dec);   dec list
1109PURPOSE:  turn a partial fraction decomposition dec into one string, writing the
1110          denominator factors just as q1,q2,... . The list dec has to have the
1111          same structure as the output of @ref{pfd}.
1112SEE ALSO: pfd, getStringpfd, displaypfd, displaypfd_long
1113EXAMPLE:  example getStringpfd_indexed; shows an example"
1114{
1115  if(typeof(dec[1])=="ideal") {dec = dec[2];}
1116  string s = getStringFraction_indexed(dec[1]);
1117  for(int i=2; i<=size(dec); i++)
1118  {
1119    s = s+" + "+getStringFraction_indexed(dec[i]);
1120  }
1121  return(s);
1122}
1123example
1124{
1125  "EXAMPLE:";
1126  echo=voice;
1127  ring R = 0,(x,y),dp;
1128  poly f = x^3+3*x^2*y+2*y^2-x^2+4*x*y;
1129  poly g = x^2*y*(x-1)*(x-y)^2;
1130
1131  list dec = pfd(f,g);
1132
1133  displaypfd(dec);
1134  getStringpfd_indexed(dec);
1135}
1136
1137static proc getStringFraction(list fraction, ideal q)
1138{
1139  int jmax,j;
1140  string s = "(" + string(fraction[1]);
1141  if(size(fraction[2])>0)
1142  {
1143    s = s + ")/(";
1144    jmax = size(fraction[2]);
1145    for(j=1; j<=jmax; j++)
1146    {
1147      s = s + "(" + string(q[fraction[2][j]]) + ")";
1148      if(fraction[3][j] != 1) {s = s + "^" + string(fraction[3][j]);}
1149      if(j<jmax) {s = s + "*";}
1150    }
1151  }
1152  s = s + ")";
1153  return(s);
1154}
1155
1156static proc getStringFraction_indexed(list fraction)
1157{
1158  int jmax,j;
1159  string s = "(" + string(fraction[1]);
1160  if(size(fraction[2])>0)
1161  {
1162    s = s + ")/(";
1163    jmax = size(fraction[2]);
1164    for(j=1; j<=jmax; j++)
1165    {
1166      s = s + "q" + string(fraction[2][j]);
1167      if(fraction[3][j] != 1) {s = s + "^" + string(fraction[3][j]);}
1168      if(j<jmax) {s = s + "*";}
1169    }
1170  }
1171  s = s + ")";
1172  return(s);
1173}
1174
1175proc readInputTXT(def file__, list #)
1176"USAGE:   readInputTXT(file[, mode]), file string, mode int
1177          readInputTXT(filelist[, mode]), filelist list, mode int
1178PURPOSE:  read matrix of rational functions from a txt-file and turn it into a
1179          matrix (i.e. a list of lists) of pairs of polynomials (numerators and
1180          denominators). The string file is the [directory +] name of the file,
1181          r is the ring chosen for the numerator/denominator polynomials.
1182       @* The input file should be a list of lists using the brackets \"{\",
1183          \"}\" and \",\" as seperation, e.g.
1184       @* \"{{(x+y)/(x^2-x*y), -(x^2*y+1)/(y), x^2}, {(x+1)/y, y/x, 0}}\".
1185       @* The file should contain less than 2^31 characters (filesize < 2 GB).
1186          For bigger files the matrix should be split row-wise in multiple
1187          matrices and saved in different files. A list of the filenames
1188          (in the right order) can then be given as first argument instead.
1189       @* Also the basering has to match the variable names used in the
1190          input file(s).
1191       @* mode = 1: save result to an ssi file of the same name (default)
1192       @* mode = 2: return result
1193       @* mode = 3: both save to ssi file and return result
1194SEE ALSO: pfdMat"
1195{
1196  system("--ticks-per-sec",1000);
1197  short = 0;
1198  if(!defined(basering))
1199    {ERROR("no basering defined!");}
1200  int left__,right__,pos1__,pos2__,tmp__,i__,j__,t__,tt__;
1201  int mode__=1;
1202  if(size(#)>0) {mode__=#[1];}
1203  if(typeof(file__)=="list") // list of filenames given --> apply function to each
1204  {                          // file and concatenate the resulting matrices
1205    int n = size(file__);
1206    list mat__ = list();
1207    for(i__=1;i__<=n;i__++)
1208    {
1209      printf("  file %s of %s:",i__,n);
1210      if(find(file__[i__],".txt")==0) {ERROR("wrong file type, expected txt");}
1211      mat__ = mat__ + readInputTXT(file__[i__],2);
1212    }
1213
1214    if(mode__==2) {return(mat__);}
1215
1216    string filename__ = file__[1][1,find(file__[1],".txt")-1];
1217    print("  saving to file "+filename__+".ssi "); t__ = rtimer;
1218    write("ssi:w "+filename__+".ssi", mat__);
1219    printf("  done! (%s ms)", rtimer-t__);
1220
1221    if(mode__==3) {return(mat__);}
1222  }
1223  if(typeof(file__)!="string")
1224    {ERROR("wrong type for first argument (expected string or list)");}
1225  if(find(file__,".txt")==0) {ERROR("wrong file type, expected txt");}
1226
1227  print("  reading file "); t__=rtimer;
1228  string data__ = read(":r "+file__);
1229  printf("  done! (%s ms)", rtimer-t__);
1230
1231
1232  print("  processing input "); t__ = rtimer;
1233  left__ = find(data__,"{");
1234  right__ = find(data__,"}");
1235  tmp__ = find(data__,"{",left__+1);
1236  if(left__<tmp__ && tmp__<right__) {left__ = tmp__;}
1237
1238  int finished__;
1239  poly p__,q__;
1240  list row__,mat__;
1241  i__=0;
1242  while(1)
1243  {
1244    i__++;
1245    tt__ = rtimer;
1246    row__ = list();
1247    pos2__ = left__;
1248    finished__ = 0;
1249    j__=0;
1250    while(not finished__)
1251    {
1252      j__++;
1253
1254      pos1__ = pos2__+1;
1255      pos2__ = find(data__,"/",pos1__);
1256      tmp__ = find(data__,",",pos1__);
1257      if(pos2__==0 || pos2__>right__) //no denominator
1258      {
1259        if(tmp__==0 || tmp__>right__) {pos2__ = right__; finished__ = 1;}
1260        else {pos2__ = tmp__;}
1261        execute("p__=" + fixBrackets(data__[pos1__,pos2__-pos1__]));
1262        q__=1;
1263      }
1264      else{if(tmp__>0 && tmp__<pos2__) // no denominator
1265      {
1266        pos2__ = tmp__;
1267        execute("p__=" + fixBrackets(data__[pos1__,pos2__-pos1__]));
1268        q__=1;
1269      }
1270      else
1271      {
1272        execute("p__=" + fixBrackets(data__[pos1__,pos2__-pos1__]));
1273
1274        pos1__ = pos2__+1;
1275        pos2__ = tmp__;
1276        if(pos2__==0 || pos2__>right__)
1277        {
1278          pos2__=right__;
1279          finished__=1;
1280        }
1281        execute("q__=" + fixBrackets(data__[pos1__,pos2__-pos1__]));
1282      }}
1283
1284      row__[j__] = list(p__,q__);
1285    }
1286
1287    mat__[i__] = row__; // append row to matrix
1288    printf("    row %s done! (%s ms)",i__,rtimer-tt__);
1289
1290    left__ = find(data__,"{",right__);
1291    if(left__==0) {break;}
1292    right__ = find(data__,"}",left__);
1293  }
1294  printf("  done! (%s ms)", rtimer-t__);
1295
1296  if(mode__==2) {return(mat__);}
1297
1298  string filename__ = file__[1,find(file__,".txt")-1];
1299  print("  saving to file "+filename__+".ssi "); t__ = rtimer;
1300  write("ssi:w "+filename__+".ssi", mat__);
1301  printf("  done! (%s ms)", rtimer-t__);
1302
1303  if(mode__==3) {return(mat__);}
1304}
1305/* new version:
1306{
1307  system("--ticks-per-sec",1000);
1308  if(!defined(basering))
1309    {ERROR("no basering defined!");}
1310  int left__,right__,pos1__,pos2__,tmp__,i__,j__,k__,d__,t__,tt__;
1311  int mode__=1;
1312  if(size(#)>0) {mode__=#[1];}
1313  if(typeof(file__)=="list") // list of filenames given --> apply function to each
1314  {                          // file and concatenate the resulting matrices
1315    int n = size(file__);
1316    list mat__ = list();
1317    for(i__=1;i__<=n;i__++)
1318    {
1319      printf("  file %s of %s:",i__,n);
1320      if(find(file__[i__],".txt")==0) {ERROR("wrong file type, expected txt");}
1321      mat__ = mat__ + readInputTXT(file__[i__],2);
1322    }
1323
1324    if(mode__==2) {return(mat__);}
1325
1326    string filename__ = file__[1][1,find(file__[1],".txt")-1];
1327    print("  saving to "+filename__+".ssi "); t__ = rtimer;
1328    write("ssi:w "+filename__+".ssi", mat__);
1329    printf("  done! (%s ms)", rtimer-t__);
1330
1331    if(mode__==3) {return(mat__);}
1332  }
1333  if(typeof(file__)!="string")
1334    {ERROR("wrong type for first argument (expected string or list)");}
1335  if(find(file__,".txt")==0) {ERROR("wrong file type, expected txt");}
1336
1337  print("  reading input matrix as string from "+file__); t__=rtimer;
1338  string data__ = read(":r "+file__);
1339  printf("  done! (%s ms)", rtimer-t__);
1340
1341
1342  print("  processing input "); t__ = rtimer;
1343  left__ = find(data__,"{");
1344  right__ = find(data__,"}");
1345  tmp__ = find(data__,"{",left__+1);
1346  if(left__<tmp__ && tmp__<right__) {left__ = tmp__;}
1347
1348  int finished__;
1349  poly p__,q__;
1350  int depth__;
1351  list mat__;
1352  string s__,s1__,s2__;
1353  for(i__=1;1;i__++)
1354  {
1355    tt__ = rtimer;
1356    mat__[i__] = list();
1357    pos2__ = left__;
1358    finished__ = 0;
1359    for(j__=1; not finished__; j__++)
1360    {
1361      pos1__ = pos2__+1;
1362      pos2__ = find(data__,",",pos1__);
1363      if(pos2__==0 || pos2__>right__) {finished__=1; pos2__=right__;}
1364      s__ = data__[pos1__,pos2__-pos1__];
1365      for(k__=1; s__[k__]==" "; k__++) {}
1366      s__ = s__[k__,size(s__)-k__+1]; // remove spaces
1367
1368      tmp__=find(s__,"/");
1369      //printf("s: %s",s__);
1370      if(tmp__>0)
1371      {
1372        depth__=0;
1373        d__=0;
1374        for(k__=tmp__+1;k__<=size(s__);k__++)
1375        {
1376          if(s__[k__]=="(") {depth__++; k__++; continue;}
1377          if(s__[k__]==")") {depth__--; k__++; continue;}
1378          if(s__[k__]=="/" && depth__<=d__) {tmp__=k__; d__=depth__;}
1379        }
1380        s1__ = s__[1,tmp__-1];
1381        s2__ = s__[tmp__+1,size(s__)-tmp__];
1382        depth__=0;
1383        for(k__=size(s1__); k__>1; k__--)
1384        {
1385          if(s1__[k__]==")") {depth__++; k__--; continue;}
1386          if(s1__[k__]=="(") {depth__--; k__--; continue;}
1387          if(depth__==0 && (s1__[k__]=="+" || s1__[k__]=="-")) {tmp__=0; break}
1388        }
1389        depth__=0;
1390        for(k__=1; k__<=size(s2__); k__++)
1391        {
1392          if(s2__[k__]=="(") {depth__++; k__++; continue;}
1393          if(s2__[k__]==")") {depth__--; k__++; continue;}
1394          if(depth__==0 && (s2__[k__]=="+" || s2__[k__]=="-" || s2__[k__]=="*")) {tmp__=0; break}
1395        }
1396        //printf("s1: %s,%ns2: %s",s1__,s2__);
1397      }
1398      if(tmp__==0) // no denominator
1399      {
1400        execute("p__=" + s__);
1401        q__=1;
1402      }
1403      else // s1__ = numerator, s2__ = denominator
1404      {
1405        execute("p__=" + fixBrackets(s1__));
1406        execute("q__=" + fixBrackets(s2__));
1407        if(deg(q__)==0) {p__=p__/q__; q__=1;}
1408      }
1409      ;
1410
1411      mat__[i__][j__] = list(p__,q__);
1412    }
1413    printf("    row %s done! (%s ms)",i__,rtimer-tt__);
1414
1415    left__ = find(data__,"{",right__);
1416    if(left__==0) {break;}
1417    right__ = find(data__,"}",left__);
1418  }
1419  printf("  done! (%s ms)", rtimer-t__);
1420
1421  if(mode__==2) {return(mat__);}
1422
1423  string filename__ = file__[1,find(file__,".txt")-1];
1424  print("  saving to "+filename__+".ssi "); t__ = rtimer;
1425  write("ssi:w "+filename__+".ssi", mat__);
1426  printf("  done! (%s ms)", rtimer-t__);
1427
1428  if(mode__==3) {return(mat__);}
1429} */
1430
1431
1432static proc fixBrackets(string data)
1433{
1434  int pos=0;
1435  int left_brackets =0;
1436  int right_brackets=0;
1437  int n=size(data);
1438  while(pos<n)
1439  {
1440    pos = find(data,"(",pos+1);
1441    if(pos==0) {break;}
1442    left_brackets++;
1443  }
1444  pos=0;
1445  while(pos<n)
1446  {
1447    pos = find(data,")",pos+1);
1448    if(pos==0) {break;}
1449    right_brackets++;
1450  }
1451  int difference = left_brackets-right_brackets;
1452  if(difference>0)
1453  {
1454    for(int i=1; i<=difference; i++) {data = data+")";}
1455  }
1456  if(difference<0)
1457  {
1458    for(int i=1; i<=-difference; i++) {data = "("+data;}
1459  }
1460  return(data);
1461}
1462
1463static proc pfdWrap(poly f, def g, int i, int j, link logfile, int output_mode)
1464{
1465  system("--ticks-per-sec",1000);
1466  if(output_mode>3)
1467    {write("ssi:w pfd_results_"+string(i)+"_"+string(j)
1468           +".ssi","task started, but not finished yet");}
1469  int t0 = rtimer;
1470  list result = pfd(f,g);
1471  fprintf(logfile,"_[%s,%s]: %s ms",i,j,rtimer-t0);
1472  if(output_mode>3)
1473    {write("ssi:w pfd_results_"+string(i)+"_"+string(j)+".ssi",result);}
1474  return(result);
1475}
1476
1477static proc testEntry(int i, int j, list fraction, list dec, link logfile, int N);
1478{
1479  int t=rtimer;
1480  system("--ticks-per-sec",1000);
1481  int result = checkpfd(fraction,dec,N);
1482  if(result==1) {fprintf(logfile, " _[%s,%s]: correct (%s ms)",i,j,rtimer-t);}
1483  else          {fprintf(logfile, " _[%s,%s]: WRONG! (%s ms)", i,j,rtimer-t);}
1484  return(result);
1485}
1486
1487proc pfdMat(def infile, list #)
1488"USAGE:   pfdMat(file[, dotest, ignore_nonlin, output_mode, parallelize]);
1489          file string, dotest,ignore_nonlin,output_mode,parallelize int
1490PURPOSE:  apply @code{pfd} to all entries of a matrix of rational functions
1491          saved in a file. The string file is the [directory +] name of the
1492          file.
1493       @* The input file can either be a txt-file or an ssi-file created with
1494          @code{readInputTXT}. In case of a txt-file, the base ring has to match
1495          and the matrix has to be in the same format specified in
1496          @ref{readInputTXT}.
1497          Also, txt-files that are bigger than 2 GB should be split as described
1498          for @code{readInputTXT} and a list of the filenames can be given as
1499          first argument instead.
1500       @* The result is written in two txt-files: once with the denominators
1501          written out and once with indexed denominator factors q1,q2,... .
1502          The polynomials q1,q2,... are saved in a separate txt-file.
1503       @* Also a logfile is created, which protocols the memory used and the
1504          runtimes of for each matrix entry in real-time.
1505
1506       @* There are also 4 optional arguments:
1507       @* If @code{dotest} is nonzero, test the results with checkpfd:
1508            dotest<0: exact test (may be slow),
1509            dotest>0: do this amount of probabilistic tests for each entry
1510                      (see @ref{checkpfd}).
1511       @* (default: @code{dotest=-1})
1512       @* If @code{ignore_nonlin} is nonzero, for each denominator, the
1513          nonlinear denominator factors are saved into a seperate file and
1514          removed before applying @code{pfd}. The nonlinear factors thus do not
1515          appear in the output files. (So the input matrix is equal to the
1516          output matrix divided element-wise by the matrix containing the
1517          nonlinear factors.)
1518          (default: @code{ignore_nonlin=1})
1519       @* If @code{output_mode} is nonzero, the input and result are also
1520          saved to ssi-files containing matrices (as list of lists) of the input
1521          rational functions (as lists of numerator and denominator poly) and
1522          decompositions respectively. For the ssi-file containing the result,
1523          the first entry is an ideal @code{q} of denominator factors and the
1524          second entry is a matrix (as list of lists) containing the
1525          decompositions, each of which is a list of terms, where a term is
1526          represented as in the result of @ref{pfd} by a list @code{l} containing
1527       @*   1) the numerator polynomial
1528       @*   2) an intvec giving the indices @code{i} for which @code{q[i]}
1529               occurs as a factor in the denominator
1530       @*   3) an intvec containing the exponents of those irreducible factors.
1531       @* Also, the results of @code{pfd} will be saved directly in ssi-files
1532          named pfd_results_i_j where i,j are the matrix indices in the current
1533          directory. (default: @code{output_mode=0})
1534       @* If @code{parallelize} is nonzero, the decompositions are calculated in
1535          parallel using @ref{parallel_lib}. (default: @code{parallelize=1})
1536SEE ALSO: readInputTXT, pfd, checkpfd, checkpfdMat"
1537{
1538  system("--ticks-per-sec",1000);
1539  short = 0;
1540  int dotest,ignore_nonlin,output_mode,parallelize = -1,1,0,1;
1541  if(size(#)>0) {dotest = #[1];}
1542  if(size(#)>1) {ignore_nonlin = #[2];}
1543  if(size(#)>2) {output_mode = #[3];}
1544  if(size(#)>3) {parallelize = #[4];}
1545
1546  int i,j,k,l,ind;
1547  list arguments,results;
1548
1549  print(newline+"reading data "); int t0=rtimer;
1550
1551  if(typeof(infile)=="list")
1552  {
1553    if(output_mode>2) {list mat = readInputTXT(infile,3);}
1554    else {list mat = readInputTXT(infile,2);}
1555    int pos=find(infile[1],".txt");
1556    string filename = infile[1][1,pos-1];
1557  }
1558  else
1559  {
1560    int pos=find(infile,".txt");
1561    if(pos!=0)
1562    {
1563      if(output_mode>2) {list mat = readInputTXT(infile,3);}
1564      else {list mat = readInputTXT(infile,2);}
1565    }
1566    else
1567    {
1568      pos=find(infile,".ssi");
1569      if(pos!=0)
1570      {
1571        list mat = read("ssi:r "+infile);
1572      }
1573      else {ERROR("invalid file type, expected ssi or txt");}
1574    }
1575    string filename = infile[1,pos-1];
1576  }
1577
1578  link qfile = ":w "+filename+"_denominator_factors.txt";
1579  int n = size(mat);
1580  int m = size(mat[1]);
1581  printf("done! (%s ms)",rtimer-t0);
1582
1583  if(typeof(mat[1][1][2])!="list") // denominators are not yet factorized
1584  {
1585    print("factorizing the denominators "); t0=rtimer;
1586    mat = FactDenom(mat);
1587    if(output_mode>2)
1588      {write("ssi:w "+filename+"_factorized_denominators.ssi",mat);}
1589    printf("done! (%s ms)",rtimer-t0);
1590  }
1591
1592  if(ignore_nonlin)
1593  {
1594    print("removing nonlinear denominator factors before pfd is applied");
1595    //       +" (%s_non_linear_factors[_indexed].txt):", filename);
1596    list denom_factors;
1597    ideal p;
1598    mat, denom_factors, p = removeNonlinearFactors(mat, filename);
1599    if(output_mode>2)
1600    {
1601      print("saving nonlinear factors to "+filename+"_non_linear_factors.ssi "); t0 = rtimer;
1602      write("ssi:w "+filename+"_non_linear_factors.ssi", denom_factors);
1603      printf("done! (%s ms)",rtimer-t0);
1604      print("saving input matrix without the nonlinear factors to "+filename+"_linear_part.ssi "); t0 = rtimer;
1605      write("ssi:w "+filename+"_linear_part.ssi", mat);
1606      printf("done! (%s ms)",rtimer-t0);
1607    }
1608    //ideal p = saveNonlinearFactorsTXT(denom_factors, filename);
1609    //filename = filename + "_linear_part";
1610  }
1611
1612  if(parallelize)
1613  {
1614    print("creating tasks "); t0=rtimer;
1615    write(":w "+filename+"_pfdMat_logfile.txt","finished matrix entries with runtimes "
1616          +"(calculated in parallel on "+string(getcores())+" cores):");
1617    link logfile = ":a "+filename+"_pfdMat_logfile.txt";
1618    for(i=1; i<=n; i++)
1619    {
1620      for(j=1; j<=m; j++)
1621      {
1622        ind = m*(i-1)+j;
1623        arguments[ind] = list(mat[i][j][1],mat[i][j][2],i,j,logfile,output_mode);
1624      }
1625    }
1626    printf("done! (%s ms)",rtimer-t0);
1627
1628    print("applying pfd to each matrix entry "); t0 = rtimer;
1629    results = parallelWaitAll("pfdWrap",arguments);
1630    arguments = list();
1631    printf("done! (%s ms)",rtimer-t0);
1632
1633    write(logfile,"decomposition: "+string(rtimer-t0)+" ms and "+string(memory(2))
1634                   +" Byte Memory max. (after calling pfd on each matrix entry)");
1635
1636    print("writing results in matrix shape "); t0 = rtimer;
1637    list dec_mat;
1638    for(i=1; i<=n; i++)
1639    {
1640      dec_mat[i] = list();
1641      for(j=1; j<=m; j++)
1642      {
1643        ind = m*(i-1)+j;
1644        dec_mat[i][j] = results[ind];
1645      }
1646    }
1647    results = list();
1648    printf("done! (%s ms)",rtimer-t0);
1649  }
1650  else
1651  {
1652    print("applying pfd to each matrix entry "); t0=rtimer;
1653    write(":w "+filename+"_pfdMat_logfile.txt",
1654          "finished matrix entries with runtimes (no parallelization):");
1655    link logfile = ":a "+filename+"_pfdMat_logfile.txt";
1656    list dec_mat;
1657    for(i=1; i<=n; i++)
1658    {
1659      dec_mat[i] = list();
1660      for(j=1; j<=m; j++)
1661      {
1662        dec_mat[i][j] = pfdWrap(mat[i][j][1],mat[i][j][2],i,j,logfile,output_mode);
1663      }
1664    }
1665    printf("done! (%s ms)",rtimer-t0);
1666    write(logfile,"decomposition: "+string(rtimer-t0)+" ms and "+string(memory(2))
1667          +" Byte Memory max. (after calling pfd on each matrix entry)");
1668 }
1669
1670  print("making one single list of denominator factors "); t0 = rtimer;
1671  ideal q,new_q;
1672  intvec dict;
1673  for(i=1; i<=n; i++)
1674  {
1675    for(j=1; j<=m; j++)
1676    {
1677      new_q = dec_mat[i][j][1];
1678      dec_mat[i][j] = dec_mat[i][j][2];
1679      dict = 0:0;
1680      for(k=1; k<=size(new_q); k++)
1681      {
1682        ind = find_entry(q,new_q[k]);
1683        if(ind==0)
1684        {
1685          ind = size(q)+1;
1686          q[ind] = new_q[k];
1687        }
1688        dict[k] = ind;
1689      }
1690      for(k=1; k<=size(dec_mat[i][j]); k++)
1691      {
1692        if(size(dec_mat[i][j][k][2])>0)
1693        {
1694          dec_mat[i][j][k][2] = intvec(dict[dec_mat[i][j][k][2]]);
1695        }
1696      }
1697    }
1698    printf("  row %s complete!",i);
1699  }
1700  printf("done! (%s ms)",rtimer-t0);
1701
1702  if(output_mode>2)
1703  {
1704    print("saving result to "+filename+"_pfd_only_linear_factors.ssi "); t0 = rtimer;
1705    write("ssi:w "+filename+"_pfd_only_linear_factors.ssi", list(q,dec_mat));
1706    printf("done! (%s ms)",rtimer-t0);
1707  }
1708
1709  if(ignore_nonlin)
1710  {
1711    ind = size(q);
1712    for(i=1; i<=size(p); i++) {q[ind+i]=p[i];} // add nonlin. polynomials to q
1713    for(i=1; i<=n; i++)
1714    {
1715      for(j=1; j<=m; j++)
1716        {
1717          denom_factors[i][j][1] = denom_factors[i][j][1]+ind; // adjust indices
1718        }
1719    }
1720  }
1721
1722  if(ignore_nonlin)
1723    {printf("creating readable .txt-files (including the nonlinear factors again)");}
1724  else
1725    {printf("creating readable .txt-files ");}
1726  t0 = rtimer;
1727  print(" indexed ("+filename+"_pfd_indexed.txt):");
1728  if(ignore_nonlin)
1729    {saveResultTXT_indexed(dec_mat, filename+"_pfd_indexed", denom_factors);}
1730  else {saveResultTXT_indexed(dec_mat, filename+"_pfd_indexed");}
1731  for(i=1; i<=size(q); i++) {fprintf(qfile, "q%s = %s;", i, q[i]);}
1732  if(output_mode>1)
1733  {
1734    print(" denominators written out ("+filename+"_pfd.txt):");
1735    if(ignore_nonlin)
1736      {saveResultTXT(dec_mat, q, filename+"_pfd", denom_factors);}
1737    else {saveResultTXT(dec_mat, q, filename+"_pfd");}
1738  }
1739  printf("done! (%s ms)",rtimer-t0);
1740
1741  if(dotest)
1742  {
1743    if(dotest<0)
1744      {print("checking for correctness (exact test) ");}
1745    else
1746      {printf("checking for correctness (%s random evaluations per entry) ",dotest);}
1747    t0 = rtimer;
1748    if(parallelize)
1749    {
1750      for(i=1; i<=n; i++)
1751      {
1752        for(j=1; j<=m; j++)
1753        {
1754          arguments[m*(i-1)+j]=list(i,j,mat[i][j],list(q,dec_mat[i][j]),logfile,dotest);
1755        }
1756      }
1757      results = parallelWaitAll("testEntry",arguments);
1758    }
1759    else
1760    {
1761      for(i=1; i<=n; i++)
1762      {
1763        for(j=1; j<=m; j++)
1764        {
1765          results[m*(i-1)+j]=testEntry(i,j,mat[i][j],list(q,dec_mat[i][j]),logfile,dotest);
1766        }
1767      }
1768    }
1769
1770    printf("%s out of %s = %sx%s decompositions are correct! (%s ms)%n",
1771            sum(results),n*m,n,m,rtimer-t0,0);
1772    write(logfile,"checking for correctness: "+string(rtimer-t0)+" ms and "
1773          +string(memory(2))+" Byte Memory max. (at the end of pfdMat), "
1774          +string(sum(results))+" correct out of "+string(n*m));
1775  }
1776}
1777
1778static proc FactDenom(list mat)
1779{
1780  system("--ticks-per-sec",1000);
1781  int i,j,k,ind,t,counter;
1782  int n = size(mat);
1783  int m = size(mat[1]);
1784  list denom = list();
1785  for(i=1; i<=n; i++)
1786  {
1787    denom[i] = list();
1788    for(j=1; j<=m; j++)
1789    {
1790      denom[i][j] = mat[i][j][2];
1791      mat[i][j][2] = list(ideal(),intvec(0:0));
1792    }
1793  }
1794  int expon;
1795  list fact;
1796  number lcoeff;
1797  int timeout = 60000;
1798  int finished = 0;
1799  list arguments,results;
1800  ideal q;
1801  while(!finished)
1802  {
1803    t = rtimer;
1804    for(i=1; i<=n; i++) // create argument list
1805    {
1806      for(j=1; j<=m; j++)
1807      {
1808        arguments[m*(i-1)+j] = list(denom[i][j]);
1809      }
1810    }
1811
1812    results = parallelWaitAll("factorize",arguments,timeout);
1813    arguments = list();
1814
1815    for(i=1; i<=n; i++) // update q, mat, denom
1816    {
1817      for(j=1; j<=m; j++)
1818      {
1819        ind = m*(i-1)+j;
1820        if(typeof(results[ind]) != "none")
1821        {
1822          fact = results[ind];
1823          for(k=2; k<=size(fact[1]); k++)
1824          {
1825            lcoeff = leadcoef(fact[1][k]);
1826            fact[1][k] = fact[1][k]/lcoeff;
1827            fact[1][1] = fact[1][1]*(lcoeff^fact[2][k]); // polynomial is monic (thus unique)
1828            lcoeff = content(fact[1][k]);
1829            fact[1][k] = fact[1][k]/lcoeff;
1830            fact[1][1] = fact[1][1]*(lcoeff^fact[2][k]); // polynomial has nice coefficients
1831
1832            // add a new factor to q:
1833            ind = find_entry(q,fact[1][k]);
1834            if(ind==0) {q[size(q)+1] = fact[1][k];}
1835            // complete the factorization of the i,j-th denominator:
1836            ind = find_entry(mat[i][j][2][1],fact[1][k]);
1837            if(ind==0)
1838            {
1839              ind = size(mat[i][j][2][1])+1;
1840              mat[i][j][2][1][ind] = fact[1][k];
1841              mat[i][j][2][2][ind] = fact[2][k];
1842            }
1843            else
1844            {
1845              mat[i][j][2][2][ind] = mat[i][j][2][2][ind] + fact[2][k];
1846            }
1847          }
1848          mat[i][j][1] = mat[i][j][1]/fact[1][1];
1849          denom[i][j] = 1;
1850        }
1851      }
1852    }
1853    results = list();
1854
1855    finished = 1;
1856    counter = n*m;
1857    for(i=1; i<=n; i++) // factorize by any known factors (from q)
1858    {
1859      for(j=1; j<=m; j++)
1860      {
1861        for(k=1; k<=size(q); k++)
1862        {
1863          expon=0;
1864          while(reduce(denom[i][j],q[k])==0)
1865          {
1866            denom[i][j] = denom[i][j]/q[k];
1867            expon++;
1868          }
1869          if(expon>0)
1870          {
1871            ind = size(mat[i][j][2][1])+1;
1872            mat[i][j][2][1][ind] = q[k];
1873            mat[i][j][2][2][ind] = expon;
1874          }
1875        }
1876        if(deg(denom[i][j])==0)
1877        {
1878          mat[i][j][1] = mat[i][j][1]/denom[i][j];
1879          denom[i][j] = poly(1);
1880        }
1881        if(denom[i][j]!=poly(1)) {finished = 0; counter--;}
1882      }
1883    }
1884
1885    timeout = timeout*2;
1886
1887    printf("  %s out of %s denominators factorized completely (%s ms)",counter,n*m,rtimer-t);
1888  }
1889  return(mat);
1890}
1891
1892static proc saveResultTXT_indexed(list dec, string filename, list #)
1893{
1894  // expect dec = list(list(dec11, dec12, ...), list(dec21, dec22, ...), ...),
1895  // where dec11, dec12, ... are decompositions of form list(list(poly, intvec, intvec), ...)
1896  system("--ticks-per-sec",1000);
1897  list nonlinFactors = list();
1898  if(size(#)>0) {nonlinFactors = #;}
1899  link file = ":w "+filename+".txt";
1900
1901  int i,j;
1902  int t;
1903  string s="{";
1904  int n=size(dec);
1905  int m=size(dec[1]);
1906  int k;
1907  for(i=1; i<=n; i++)
1908  {
1909    t = rtimer;
1910    s = s+"{";
1911    for(j=1; j<=m; j++)
1912    {
1913      if(size(nonlinFactors)>0)
1914      {
1915        if(size(nonlinFactors[i][j][1])>0)
1916        {
1917          s = s + getStringFraction_indexed(list(poly(1))+nonlinFactors[i][j])
1918                + " * (" + getStringpfd_indexed(dec[i][j]) + "), ";
1919          j++; continue;
1920        }
1921      }
1922      s = s + getStringpfd_indexed(dec[i][j]) + ", ";
1923    }
1924    k = size(s);
1925    s[k-1] = "}"; s[k] = ","; s = s+" ";
1926    printf("  row %s done! (%s ms)",i,rtimer-t);
1927  }
1928  k = size(s);
1929  s[k-1] = "}"; s[k] = " ";
1930  write(file,s);
1931}
1932
1933static proc saveResultTXT(list dec, ideal q, string filename, list #)
1934{
1935  // expect dec = list(list(dec11, dec12, ...), list(dec21, dec22, ...), ...),
1936  // where dec11, dec12, ... are decompositions of form list(list(poly, intvec, intvec), ...)
1937  system("--ticks-per-sec",1000);
1938  list nonlinFactors = list();
1939  if(size(#)>0) {nonlinFactors = #;}
1940  link file = ":w "+filename+".txt";
1941
1942  int i,j;
1943  int t;
1944  string s="{";
1945  int n=size(dec);
1946  int m=size(dec[1]);
1947  int k;
1948  for(i=1; i<=n; i++)
1949  {
1950    t = rtimer;
1951    s = s+"{";
1952    for(j=1; j<=m; j++)
1953    {
1954      if(size(nonlinFactors)>0)
1955      {
1956        if(size(nonlinFactors[i][j][1])>0)
1957        {
1958          s = s + getStringFraction(list(poly(1))+nonlinFactors[i][j],q)
1959                + " * (" + getStringpfd(list(q,dec[i][j])) + "), ";
1960          j++; continue;
1961        }
1962      }
1963      s = s + getStringpfd(list(q,dec[i][j])) + ", ";
1964    }
1965    k = size(s);
1966    s[k-1] = "}"; s[k] = ","; s = s+" ";
1967    printf("  row %s done! (%s ms)",i,rtimer-t);
1968  }
1969  k = size(s);
1970  s[k-1] = "}"; s[k] = " ";
1971  write(file,s);
1972}
1973
1974static proc removeNonlinearFactors(list fractions, string filename)
1975{
1976  int n=size(fractions);
1977  int m=size(fractions[1]);
1978  int i,j,k,t0,ind;
1979  ideal p;
1980  list denom_factors;
1981  intvec factors,exponents;
1982  list fac;
1983  for(i=1; i<=n; i++)
1984  {
1985    t0 = rtimer;
1986    denom_factors[i] = list();
1987    for(j=1; j<=m; j++)
1988    {
1989      fac = fractions[i][j][2];
1990      factors = 0:0;
1991      exponents = 0:0;
1992      for(k=1; k<=size(fac[1]); k++)
1993      {
1994        if(deg(poly(fac[1][k]))>1)
1995        {
1996          // add the nonlin. factor fac[1][k] to p if necessary:
1997          if(size(p)==0) {ind = 1; p[ind]=fac[1][k];}
1998          else
1999          {
2000            for(ind=1;1;ind++)
2001            {
2002              //print("   "+string(ind));
2003              if(p[ind]==fac[1][k]) {break;}
2004              if(ind==size(p))
2005              {
2006                ind++;
2007                p[ind]=fac[1][k];
2008                break;
2009              }
2010            }
2011          }
2012          factors[size(factors)+1] = ind;
2013          exponents[size(exponents)+1] = fac[2][k];
2014          fac[1] = delete(fac[1],k);
2015          fac[2] = delete(fac[2],k);
2016          continue;
2017        }
2018      }
2019      fractions[i][j][2] = fac;
2020
2021      denom_factors[i][j] = list(factors,exponents);
2022    }
2023    printf("  row %s done! (%s ms)",i,rtimer-t0);
2024  }
2025  return(fractions, denom_factors, p);
2026}
2027
2028proc checkpfdMat(def input, string output, string qfile, list #)
2029"USAGE:   checkpfdMat(input, output, denomFactors[, N, parallelize]);
2030          input,output,denomFactors string, N,parallelize int
2031          checkpfdMat(input, output, denomFactors, nonlinFactors[, N, parallelize]);
2032          input,output,denomFactors,nonlinFactors string, N,parallelize int
2033PURPOSE:  test the output files of @code{pfdMat} for correctness. Input and
2034          output (indexed) txt-file names are given as strings. If nonlinear
2035          denominator factors were ignored in the calculation (as described in
2036          @ref{pfdMat}), the txt-file containing the nonlinear factors must be
2037          given as fourth argument @code{nonlinFactors}. The output and
2038          nonlinear Factors should be indexed and @code{denomFactors} is the
2039          file containing the denominator factors @code{q1},@code{q2},... .
2040       @* As for @code{readInputTXT} and @code{pfdMat}, the basering has to
2041          match the variable names used in the input file, which has to be in
2042          the same format specified in @ref{readInputTXT}. Also, files bigger
2043          than 2 GB have to be split as described for @code{readInputTXT} and a
2044          list of filenames can be given as first argument instead.
2045       @* If an integer N is given, the test is done probabilistically by N
2046          random substitutions for each entry of the matrix. If N is omitted,
2047          the fractions in the decomposition will be expanded symbolically and
2048          compared to the input (may be slower).
2049       @* If @code{parallelize} is nonzero, the tests are run in parallel using
2050          @ref{parallel_lib}. (default: @code{parallelize=1})
2051       @* The result is printed and as in @code{pfdMat} a logfile is created
2052          showing the results for each matrix entry.
2053SEE ALSO: readInputTXT, pfd, checkpfd, pfdMat"
2054{
2055  system("--ticks-per-sec",1000);
2056  short = 0;
2057  int t0;
2058  int N=0;
2059  int parallelize=1;
2060  if(size(#)==1)
2061  {
2062    if(typeof(#[1])=="int") {N=#[1];}
2063    else {ERROR("invalid argument type: "+typeof(#[1]));}
2064  }
2065  if(size(#)==2)
2066  {
2067    if(typeof(#[1])=="int" && typeof(#[2])=="int")
2068      {N=#[1]; parallelize=#[2];}
2069    else {ERROR("invalid argument types: "+typeof(#[1])+", "+typeof(#[2]));}
2070  }
2071  if(size(#)>2) {ERROR("too many arguments");}
2072
2073  print(newline+"reading input file:");
2074  list frac = readInputTXT(input,2);
2075  if(typeof(input)=="string") {string filename=input;}
2076  if(typeof(input)=="list")   {string filename=input[1];}
2077  filename = filename[1,find(filename,".txt")-1];
2078
2079  print("factorizing the denominators "); t0=rtimer;
2080  frac = FactDenom(frac);
2081  printf("done! (%s ms)",rtimer-t0);
2082
2083  print("reading output files:"); t0=rtimer;
2084  print(" reading list of denominator factors from "+qfile);
2085  ideal q;
2086  q = readQfileTXT(qfile);
2087  //printf("denominator factors: %s",q);
2088  print(" done!");
2089
2090  print(" reading (indexed) output decompositions ");
2091  list dec,nonlin;
2092  dec,nonlin = readOutputTXT(output);
2093
2094  if(parallelize)
2095    {printf("done! (%s ms)%n%ncreating tasks",rtimer-t0,0); t0=rtimer;}
2096  else
2097  {
2098    printf("done! (%s ms)%n%n",rtimer-t0,0);
2099    if(N<=0)
2100      {print("checking for correctness (exact test) ");}
2101    else
2102      {printf("checking for correctness (%s random evaluations per entry) ",N);}
2103    t0=rtimer;
2104  }
2105
2106  fprintf(":w "+filename+"_checkpfd_logfile.txt","Input file (matrix of rational functions): %s"
2107          +"%nOutput file (decompositions): %s%nlist of all denominator factors: %s"
2108          +"%n%nResults of checkpfdMat:",input,output,qfile,0);
2109  link logfile = ":a "+filename+"_checkpfd_logfile.txt";
2110
2111  int n=size(frac);
2112  int m=size(frac[1]);
2113  int i,j,k,ind;
2114  list arguments;
2115  for(i=1;i<=n;i++)
2116  {
2117    for(j=1;j<=m;j++)
2118    {
2119      for(k=1;k<=size(nonlin[i][j][1]);k++)
2120      {
2121        ind = find_entry(frac[i][j][2][1],q[nonlin[i][j][1][k]]);
2122        if(ind==0) {ERROR("nonlinear factors are wrong");}
2123        if(frac[i][j][2][2][ind]!=nonlin[i][j][2][k])
2124          {ERROR("nonlinear factors are wrong");}
2125        frac[i][j][2][1] = delete(frac[i][j][2][1],ind);
2126        frac[i][j][2][2] = delete(frac[i][j][2][2],ind);
2127      }
2128      if(parallelize)
2129        {arguments[(i-1)*m+j] = list(i,j,frac[i][j],list(q,dec[i][j]),logfile,N);}
2130      else
2131        {results[(i-1)*m+j] = testEntry(i,j,frac[i][j],list(q,dec[i][j]),logfile,N);}
2132    }
2133  }
2134
2135  if(parallelize)
2136  {
2137    printf("done! (%s ms)%n%n",rtimer-t0,0);
2138    if(N<=0)
2139      {print("checking for correctness (exact test) ");}
2140    else
2141      {printf("checking for correctness (%s random evaluations per entry) ",N);}
2142    t0=rtimer;
2143    list results = parallelWaitAll("testEntry",arguments);
2144  }
2145  else {printf("done! (%s ms)",rtimer-t0);}
2146  printf("%s out of %s = %sx%s decompositions are correct! (%s ms)%n",
2147          sum(results),n*m,n,m,rtimer-t0,0);
2148  fprintf(logfile,"%s out of %s = %sx%s decompositions are correct! (%s ms)%n",
2149          sum(results),n*m,n,m,rtimer-t0,0);
2150}
2151
2152static proc readOutputTXT(string filename__)
2153{
2154  system("--ticks-per-sec",1000);
2155  print("  reading matrix of decompositions from file "+filename__);
2156  int t__=rtimer;
2157  int tt__;
2158  string data__ = read(":r "+filename__);
2159  printf("  done! (%s ms)", rtimer-t__);
2160
2161  print("  processing input "); t__ = rtimer;
2162  list mat__;
2163  list nonlin__=list();
2164  int nonlin_factors_seperated__=0;
2165  if(find(data__," * ")>0) {nonlin_factors_seperated__=1;}
2166  int left__,right__=0,0;
2167  left__ = find(data__,"{");
2168  int pos1__,pos2__=0,0;
2169  int p1__,p2__;
2170  int tmp__,tmp2__,depth__;
2171  int i__,j__,k__,l__,max__;
2172  intvec factors__,exponents__;
2173  poly numerator__;
2174  string s__,ss__;
2175  for(i__=1;1;i__++)
2176  {
2177    tt__ = rtimer;
2178    left__ = find(data__,"{",left__+1);
2179    if(left__==0) {break;}
2180    right__ = find(data__,"}",left__);
2181    mat__[i__]=list();
2182    nonlin__[i__]=list();
2183    pos2__=left__;
2184    for(j__=1;pos2__<right__&&pos2__>0;j__++)
2185    {
2186      pos1__ = pos2__+1;
2187      pos2__ = find(data__,",",pos1__);
2188      if(pos2__==0||pos2__>right__) {s__ = data__[pos1__,right__-pos1__];}
2189      else {s__ = data__[pos1__,pos2__-pos1__];}
2190      mat__[i__][j__] = list();
2191
2192
2193      factors__ = intvec(0:0);
2194      exponents__ = intvec(0:0);
2195      l__ = find(s__," * ");
2196      if(l__>0)
2197      {
2198        ss__ = s__[1,l__-1];  //ss__ contains the nonlinear factors
2199        s__ = s__[l__+3,size(s__)-l__-2];
2200        for(p1__=1;s__[p1__]!="(";p1__++) {}
2201        for(p2__=size(s__);s__[p2__]!=")";p2__--) {}
2202        s__ = s__[p1__+1,p2__-p1__-1];
2203        l__ = find(ss__,"q");
2204        ss__ = ss__[l__,find(ss__,")",l__)-l__];
2205        ss__ = ss__+"*";
2206        p1__=0;
2207        for(l__=1;1;l__++)
2208        {
2209          p1__ = find(ss__,"q",p1__+1);
2210          if(p1__==0) {break;}
2211          p1__++;
2212          p2__ = find(ss__,"^",p1__);
2213          tmp__ = find(ss__,"*",p1__);
2214          if((p2__>tmp__ && tmp__>0) || (p2__==0)) //exponent is 1
2215          {
2216            execute("factors__[l__]="+ss__[p1__,tmp__-p1__]);
2217            exponents__[l__] = 1;
2218          }
2219          else
2220          {
2221            execute("factors__[l__]="+ss__[p1__,p2__-p1__]);
2222            execute("exponents__[l__]="+ss__[p2__+1,tmp__-p2__-1]);
2223          }
2224        }
2225      }
2226      nonlin__[i__][j__] = list(factors__,exponents__);
2227
2228      depth__ = 0;
2229      s__=s__+" ";
2230      max__ = size(s__);
2231      tmp__ = 1;
2232      tmp2__ = 0;
2233      for(k__=1;k__<=max__;k__++)
2234      {
2235        if(s__[k__]=="(") {depth__++;k__++;continue;}
2236        if(s__[k__]==")") {depth__--;k__++;continue;}
2237        if(s__[k__]=="/" && depth__==0) {tmp2__ = k__;}
2238        if((s__[k__]=="+" && depth__==0) || k__==max__)
2239        {
2240          if(tmp2__==0) // no denominator
2241          {
2242            execute("numerator__="+s__[tmp__,k__-tmp__]);
2243            mat__[i__][j__][size(mat__[i__][j__])+1] = list(numerator__,intvec(0:0),intvec(0:0));
2244            tmp__ = k__+1;
2245            k__++; continue;
2246          }
2247          execute("numerator__="+s__[tmp__,tmp2__-tmp__]);
2248          ss__ = s__[tmp2__+1,k__-tmp2__-1];
2249          p1__ = find(ss__,"(");
2250          p2__ = find(ss__,")");
2251          ss__ = ss__[p1__+1,p2__-p1__-1]; // now ss__ is only the denominator
2252
2253          ss__ = ss__+"*";
2254          factors__ = intvec(0:0);
2255          exponents__ = intvec(0:0);
2256          p1__=0;
2257          for(l__=1;1;l__++)
2258          {
2259            p1__ = find(ss__,"q",p1__+1);
2260            if(p1__==0) {break;}
2261            p1__++;
2262            p2__ = find(ss__,"^",p1__);
2263            tmp__ = find(ss__,"*",p1__);
2264            if((p2__>tmp__ && tmp__>0) || (p2__==0)) //exponent is 1
2265            {
2266              execute("factors__[l__]="+ss__[p1__,tmp__-p1__]);
2267              exponents__[l__] = 1;
2268            }
2269            else
2270            {
2271              execute("factors__[l__]="+ss__[p1__,p2__-p1__]);
2272              execute("exponents__[l__]="+ss__[p2__+1,tmp__-p2__-1]);
2273            }
2274          }
2275          mat__[i__][j__][size(mat__[i__][j__])+1] = list(numerator__,factors__,exponents__);
2276          tmp__ = k__+1;
2277          tmp2__ = 0;
2278        }
2279      }
2280    }
2281    printf("    row %s done! (%s ms)",i__,rtimer-tt__);
2282  }
2283  printf("  done! (%s ms)", rtimer-t__);
2284
2285  return(mat__,nonlin__);
2286}
2287
2288static proc readQfileTXT(string filename__)
2289{
2290  string data__ = read(":r "+filename__);
2291  ideal q__;
2292  int pos1__,pos2__=1,1;
2293
2294  while(1)
2295  {
2296    pos1__=find(data__,"=",pos2__);
2297    if(pos1__==0) {break;}
2298    pos1__++;
2299    pos2__=find(data__,";",pos1__);
2300    execute("q__[size(q__)+1]="+data__[pos1__,pos2__-pos1__]);
2301  }
2302  return(q__);
2303}
Note: See TracBrowser for help on using the repository browser.