1 | //////////////////////////////////////////////////////////////////// |
---|
2 | version="version pfd.lib 4.1.3.2 Aug_2020 "; |
---|
3 | category="??"; |
---|
4 | info=" |
---|
5 | LIBRARY: pfd.lib Multivariate Partial Fraction Decomposition |
---|
6 | |
---|
7 | AUTHOR: Marcel Wittmann, e-mail: mwittman@rhrk.uni-kl.de |
---|
8 | |
---|
9 | OVERVIEW: |
---|
10 | This Library implements an algorithm based on the work of E. K. Leinartas to |
---|
11 | write rational functions in mutiple variables as a sum of functions with |
---|
12 | \"smaller\" numerators and denominators. |
---|
13 | This can be used to shorten the IBP reduction coeffcients of multi-loop Feynman |
---|
14 | integrals as shown in [J. Böhm, M. Wittmann, Z. Wu, Y. Xu, Y. Zhang: 'IBP |
---|
15 | reduction coefficients made simple'] (preprint 2020). For this application, |
---|
16 | we also provide a procedure that applies the algorithm to all entries of a |
---|
17 | matrix of rational functions given as one (possibly very big) txt-file. |
---|
18 | |
---|
19 | KEYWORDS: partial fraction; decomposition; Leinartas |
---|
20 | |
---|
21 | PROCEDURES: |
---|
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 | |
---|
42 | LIB "random.lib"; |
---|
43 | LIB "ring.lib"; |
---|
44 | LIB "parallel.lib"; |
---|
45 | LIB "elim.lib"; |
---|
46 | LIB "poly.lib"; |
---|
47 | |
---|
48 | ///////////////////////////////////////////////////////////////////////////// |
---|
49 | |
---|
50 | static 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 | |
---|
63 | proc 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 |
---|
67 | RETURN: 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. |
---|
87 | NOTE: The result depends on the monomial ordering. For \"small\" results |
---|
88 | use dp. |
---|
89 | EXAMPLE: example pfd; shows an example |
---|
90 | SEE 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 | } |
---|
340 | example |
---|
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 | |
---|
418 | static 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 | |
---|
459 | static 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 | |
---|
530 | static 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 | |
---|
620 | static 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 | |
---|
685 | static 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 | |
---|
738 | static 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 | |
---|
757 | proc checkpfd(list fraction, list dec, list #) |
---|
758 | "USAGE: checkpfd(list(f,g),dec[,N,C]); f,g poly, dec list, N,C int |
---|
759 | RETURN: 0 or 1 |
---|
760 | PURPOSE: 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. |
---|
772 | SEE ALSO: pfd |
---|
773 | EXAMPLE: 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 | } |
---|
908 | example |
---|
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 | |
---|
932 | proc evaluatepfd(list dec, ideal values, list #) |
---|
933 | "USAGE: evaluatepfd(dec, values[, mode]); dec list, values ideal, mode int |
---|
934 | RETURN: 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. |
---|
940 | SEE ALSO: pfd |
---|
941 | EXAMPLE: 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 | } |
---|
968 | example |
---|
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 | |
---|
985 | static 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 | |
---|
995 | proc displaypfd(list dec) |
---|
996 | "USAGE: displaypfd(dec); dec list |
---|
997 | PURPOSE: 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}. |
---|
999 | SEE ALSO: pfd, displaypfd_long, getStringpfd, getStringpfd_indexed |
---|
1000 | EXAMPLE: 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 | } |
---|
1036 | example |
---|
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 | |
---|
1049 | proc displaypfd_long(list dec) |
---|
1050 | "USAGE: displaypfd_long(dec); dec list |
---|
1051 | PURPOSE: like @ref{displaypfd}, but denominators are written out, not indexed. |
---|
1052 | SEE ALSO: pfd, displaypfd, getStringpfd, getStringpfd_indexed |
---|
1053 | EXAMPLE: 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 | } |
---|
1064 | example |
---|
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 | |
---|
1077 | proc getStringpfd(list dec) |
---|
1078 | "USAGE: getStringpfd(dec); dec list |
---|
1079 | PURPOSE: 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}. |
---|
1081 | SEE ALSO: pfd, getStringpfd_indexed, displaypfd, displaypfd_long |
---|
1082 | EXAMPLE: 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 | } |
---|
1093 | example |
---|
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 | |
---|
1107 | proc getStringpfd_indexed(list dec) |
---|
1108 | "USAGE: getStringpfd_indexed(dec); dec list |
---|
1109 | PURPOSE: 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}. |
---|
1112 | SEE ALSO: pfd, getStringpfd, displaypfd, displaypfd_long |
---|
1113 | EXAMPLE: 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 | } |
---|
1123 | example |
---|
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 | |
---|
1137 | static 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 | |
---|
1156 | static 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 | |
---|
1175 | proc readInputTXT(def file__, list #) |
---|
1176 | "USAGE: readInputTXT(file[, mode]), file string, mode int |
---|
1177 | readInputTXT(filelist[, mode]), filelist list, mode int |
---|
1178 | PURPOSE: 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 |
---|
1194 | SEE 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 | |
---|
1432 | static 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 | |
---|
1463 | static 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 | |
---|
1477 | static 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 | |
---|
1487 | proc pfdMat(def infile, list #) |
---|
1488 | "USAGE: pfdMat(file[, dotest, ignore_nonlin, output_mode, parallelize]); |
---|
1489 | file string, dotest,ignore_nonlin,output_mode,parallelize int |
---|
1490 | PURPOSE: 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}) |
---|
1536 | SEE 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 | |
---|
1778 | static 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 | |
---|
1892 | static 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 | |
---|
1933 | static 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 | |
---|
1974 | static 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 | |
---|
2028 | proc 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 |
---|
2033 | PURPOSE: 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. |
---|
2053 | SEE 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 | |
---|
2152 | static 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 | |
---|
2288 | static 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 | } |
---|