HepLib
Loading...
Searching...
No Matches
Apart.cpp
Go to the documentation of this file.
1
6#include "HEP.h"
7
8namespace HepLib {
9
10 #ifndef DOXYGEN_SKIP
11
12 unsigned ApartIR1_SERIAL::serial = GiNaC::function::register_new(function_options("ApartIR",1).do_not_evalf_params().overloaded(2));
13 unsigned ApartIR2_SERIAL::serial = GiNaC::function::register_new(function_options("ApartIR",2).do_not_evalf_params().overloaded(2));
14
15 #endif
16
17 namespace {
18 inline bool isOK(const ex &expr_in, const lst &vars) {
19 ex item = expr_in;
20 if(is_a<power>(item)) {
21 if(!is_a<numeric>(item.op(1)) || !ex_to<numeric>(item.op(1)).is_integer()) return false;
22 item = item.op(0);
23 }
24 exmap vs; symbol s;
25 for(auto v : vars) vs[v] = s*v;
26 return item.subs(vs,nopat).degree(s)<=1;
27 }
28 }
29
35 ex ApartIR2ex(const ex & expr_in) {
36 ex ret = expr_in;
37 ret = MapFunction([](const ex & e, MapFunction &self)->ex{
38 if(e.match(ApartIR(1)) || e.match(ApartIR(1,w))) return 1;
39 else if(!e.has(ApartIR(w1,w2))) return e;
40 else if(e.match(ApartIR(w1, w2))) {
41 ex vars = e.op(1);
42 ex ret=1;
43 matrix mat = ex_to<matrix>(e.op(0));
44 for(int c=0; c<mat.cols(); c++) {
45 ex sum=0;
46 for(int r=0; r<mat.rows()-2; r++) sum += mat(r,c) * vars.op(r);
47 sum += mat(mat.rows()-2,c);
48 ret *= pow(sum, mat(mat.rows()-1,c));
49 }
50 return ret;
51 } else return e.map(self);
52 })(ret);
53 return ret;
54 }
55
61 ex ApartIR2F(const ex & expr_in) {
62 ex ret = expr_in;
63 ret = MapFunction([](const ex & e, MapFunction &self)->ex{
64 if(e.match(ApartIR(1)) || e.match(ApartIR(1,w))) return 1;
65 else if(!e.has(ApartIR(w1,w2))) return e;
66 else if(e.match(ApartIR(w1, w2))) {
67 ex vars = e.op(1);
68 matrix mat = ex_to<matrix>(e.op(0));
69 lst pns;
70 for(int c=0; c<mat.cols(); c++) {
71 ex sum=0;
72 for(int r=0; r<mat.rows()-2; r++) sum += mat(r,c) * vars.op(r);
73 sum += mat(mat.rows()-2,c);
74 if(is_zero(mat(mat.rows()-1,c))) continue;
75 pns.append(lst{ sum, ex(0)-mat(mat.rows()-1,c) });
76 }
77 sort_lst(pns); // need sort_lst
78 lst ps, ns;
79 for(auto item : pns) {
80 ps.append(item.op(0));
81 ns.append(item.op(1));
82 }
83 return F(ps, ns);
84 } else return e.map(self);
85 })(ret);
86 return ret;
87 }
88
89 inline ex air2pn(ex air) {
90 matrix mat = ex_to<matrix>(air.op(0));
91 auto vars = air.op(1);
92 lst pns;
93 for(int c=0; c<mat.cols(); c++) {
94 ex sum=0;
95 for(int r=0; r<mat.rows()-2; r++) sum += mat(r,c) * vars.op(r);
96 sum += mat(mat.rows()-2,c);
97 if(is_zero(mat(mat.rows()-1,c))) continue;
98 pns.append(lst{ sum, mat(mat.rows()-1,c) });
99 }
100 sort_lst(pns); // need sort_lst
101 lst ps, ns;
102 for(auto item : pns) {
103 ps.append(item.op(0));
104 ns.append(item.op(1));
105 }
106 return lst{ps, ns};
107 }
108
109 inline ex pn2mat(ex ps, ex ns, ex vars) { // no need to use normal and removed
110 lst pnlst;
111 for(int i=0; i<ps.nops(); i++) pnlst.append(lst{ ps.op(i), ns.op(i) });
112 sort_lst(pnlst); // need sort_lst
113 int nrow=vars.nops(), ncol=pnlst.nops();
114 exmap vars0;
115 for(auto v : vars) vars0[v]=0;
116 matrix mat(nrow+2, ncol);
117 for(int c=0; c<ncol; c++) {
118 ex pn = pnlst.op(c);
119 mat(nrow+1,c) = normal(pn.op(1));
120 auto tmp = pn.op(0);
121 for(int r=0; r<nrow; r++) {
122 mat(r,c) = (tmp.coeff(vars.op(r))); // remove exnormal
123 }
124 mat(nrow,c) = (tmp.subs(vars0,nopat)); // remove exnormal
125 }
126 return mat;
127 }
128
129 // e1, e2 are sorted list, check if e1 is a subset of e2 or not.
130 inline bool is_subset(const ex & e1, const ex & e2) {
131 int i1=0, i2=0;
132 int t1 = e1.nops();
133 int t2 = e2.nops();
134 if(t1>t2) return false;
135 while(i1<t1) {
136 if(t1-i1>t2-i2) return false;
137 if(e1.op(i1).is_equal(e2.op(i2))) {
138 i1++; i2++; continue;
139 }
140 i2++;
141 }
142 return true;
143 }
144
145 inline ex pn2p(ex pn) {
146 lst l;
147 auto p = pn.op(0);
148 auto n = pn.op(1);
149 for(int i=0; i<n.nops(); i++) {
150 if(n.op(i).is_zero()) continue;
151 l.append(p.op(i));
152 }
153 return l;
154 }
155
156 exmap ApartRules(const exvector &airs, bool irc) { // irc=true to include ApartIRC
157 exmap rules;
158 if(airs.size()<1) return rules;
159 #define CHECK false
160 int nlimit = 50;
161 vector<exset> nps_set(airs[0].op(1).nops());
162 for(auto air : airs) {
163 auto pn = air2pn(air);
164 auto l = pn2p(pn);
165 nps_set[l.nops()-1].insert(l);
166 }
167 vector<exvector> nps(nps_set.size());
168 for(int i=0; i<nps_set.size(); i++) nps[i] = exvector(nps_set[i].begin(), nps_set[i].end());
169 nps_set.clear();
170
171 exmap s2s;
172 for(int i=0; i<nps.size()-1; i++) {
173 auto psi = nps[i];
174 if(psi.size()<1) continue;
175 if(psi.size()<nlimit) {
176 for(auto si : psi) {
177 for(int j=nps.size()-1; j>i; j--) {
178 auto psj = nps[j];
179 for(auto sj : psj) {
180 if(is_subset(si,sj)) { s2s[si] = sj; goto nextsi; }
181 }
182 }
183 nextsi: ;
184 }
185 } else {
186 exvector psi_vec(psi.begin(), psi.end());
187 auto ret = GiNaC_Parallel(psi_vec.size(), [&psi_vec,&nps,i](int idx)->ex{
188 auto si = psi_vec[idx];
189 for(int j=nps.size()-1; j>i; j--) {
190 auto psj = nps[j];
191 for(int jj=0; jj<psj.size(); jj++) {
192 //if(is_subset(si,sj)) return lst{si, sj};
193 auto sj = psj[jj];
194 if(is_subset(si,sj)) return lst{idx, j, jj};
195 }
196 }
197 return lst{ };
198 }, "AR-"+to_string(nps.size()-1)+"-"+to_string(i+1));
199 for(auto item : ret) if(item.nops()>1) {
200 int idx = ex_to<numeric>(item.op(0)).to_int();
201 int j = ex_to<numeric>(item.op(1)).to_int();
202 int jj = ex_to<numeric>(item.op(2)).to_int();
203 s2s[psi_vec[idx]] = nps[j][jj];
204 }
205 }
206 }
207
208 if(airs.size()<nlimit) {
209 for(int k=0; k<airs.size(); k++) {
210 auto pn = air2pn(airs[k]);
211 auto p = pn.op(0);
212 auto n = pn.op(1);
213 exmap p2n;
214 for(int i=0; i<p.nops(); i++) if(!is_zero(n.op(i))) p2n[p.op(i)] = n.op(i);
215 auto pk = pn2p(pn);
216 auto fi = s2s.find(pk);
217 if(fi!=s2s.end()) {
218 auto pp = fi->second;
219 lst nn;
220 for(int i=0; i<pp.nops(); i++) nn.append(p2n[pp.op(i)]);
221 ex air = ApartIR(pn2mat(pp,nn,airs[k].op(1)),airs[k].op(1));
222 if(CHECK) { // check
223 ex eL=1, eR=1;
224 for(int i=0; i<p.nops(); i++) if(!n.op(i).is_zero()) eL *= pow(WF(p.op(i)), n.op(i));
225 for(int i=0; i<pp.nops(); i++) if(!nn.op(i).is_zero()) eR *= pow(WF(pp.op(i)), nn.op(i));
226 ex chk = normal(eL-eR);
227 if(!chk.is_zero()) {
228 cout << p << ", " << n << endl;
229 cout << pp << ", " << nn << endl;
230 throw Error("ApartRules: check failed!");
231 }
232 }
233 if(irc) air = ApartIRC(air);
234 rules[airs[k]] = air;
235 } else if(irc) rules[airs[k]] = ApartIRC(airs[k]);
236 }
237 } else {
238 auto ret = GiNaC_Parallel(airs.size(), [&airs,&s2s,irc](int k)->ex{
239 auto pn = air2pn(airs[k]);
240 auto p = pn.op(0);
241 auto n = pn.op(1);
242 exmap p2n;
243 for(int i=0; i<p.nops(); i++) if(!is_zero(n.op(i))) p2n[p.op(i)] = n.op(i);
244 auto pk = pn2p(pn);
245 auto fi = s2s.find(pk);
246 if(fi!=s2s.end()) {
247 auto pp = fi->second;
248 lst nn;
249 for(int i=0; i<pp.nops(); i++) nn.append(p2n[pp.op(i)]);
250 ex air = ApartIR(pn2mat(pp,nn,airs[k].op(1)),airs[k].op(1));
251 air = ApartIRC(air);
252 if(CHECK) { // check
253 ex eL=1, eR=1;
254 for(int i=0; i<p.nops(); i++) if(!n.op(i).is_zero()) eL *= pow(WF(p.op(i)), n.op(i));
255 for(int i=0; i<pp.nops(); i++) if(!nn.op(i).is_zero()) eR *= pow(WF(pp.op(i)), nn.op(i));
256 ex chk = normal(eL-eR);
257 if(!chk.is_zero()) {
258 cout << p << ", " << n << endl;
259 cout << pp << ", " << nn << endl;
260 throw Error("ApartRules: check failed!");
261 }
262 }
263 if(irc) air = ApartIRC(air);
264 return lst{ airs[k], air };
265 } else if(irc) return lst{ airs[k], ApartIRC(airs[k]) };
266 else return lst{ };
267 }, "AR");
268 //ReShare(ret,airs);
269 for(auto lr : ret) if(lr.nops()>1) rules[lr.op(0)] = lr.op(1);
270 }
271 return rules;
272
273 }
274
280 ex Apart(const matrix & mat) {
281 static exmap mat_cache;
282 if(using_cache && cache_limit>0 && mat_cache.size() > cache_limit) mat_cache.clear();
283 auto mat_itr = mat_cache.find(mat);
284 if(mat_itr!=mat_cache.end()) return mat_itr->second;
285
286 int nrow = mat.rows()-2;
287 int ncol = mat.cols();
288 lst null_vec;
289
290 // null vector
291 static exmap null_cache;
292 if(cache_limit>0 && null_cache.size() > cache_limit) null_cache.clear();
293 ex key = sub_matrix(mat,0,nrow,0,ncol);
294 auto null_itr = null_cache.find(key);
295 if(null_itr==null_cache.end()) {
297 Fermat &fermat = Fermat::get();
298 int &v_max = fermat.vmax;
299
300 lst rep_vs;
301 ex tree = mat;
302 for(const_preorder_iterator i = tree.preorder_begin(); i != tree.preorder_end(); ++i) {
303 auto e = (*i);
304 if(is_a<symbol>(e) || is_a<Pair>(e) || is_a<Eps>(e)) {
305 rep_vs.append(e);
306 }
307 }
308 rep_vs.sort();
309 rep_vs.unique();
310
311 exmap v2f;
312 symtab st;
313 int fvi = 0;
314 for(auto vi : rep_vs) {
315 auto name = "v" + to_string(fvi);
316 v2f[vi] = Symbol(name);
317 st[name] = vi;
318 fvi++;
319 }
320
321 stringstream ss;
322 if(fvi>111) {
323 cout << rep_vs << endl;
324 throw Error("Fermat: Too many variables.");
325 }
326 if(fvi>v_max) {
327 for(int i=v_max; i<fvi; i++) ss << "&(J=v" << i << ");" << endl;
328 fermat.Execute(ss.str());
329 ss.clear();
330 ss.str("");
331 v_max = fvi;
332 }
333
334 ss << "Array m[" << nrow << "," << ncol+1 << "];" << endl;
335 fermat.Execute(ss.str());
336 ss.clear();
337 ss.str("");
338
339 ss << "[m]:=[(";
340 for(int c=0; c<ncol; c++) {
341 for(int r=0; r<nrow; r++) {
342 ss << mat(r,c).subs(iEpsilon==0,nopat).subs(v2f,nopat) << ",";
343 }
344 }
345 for(int r=0; r<nrow; r++) ss << "0,";
346 ss << ")];" << endl;
347 ss << "Redrowech([m]);" << endl;
348 auto tmp = ss.str();
349 string_replace_all(tmp,",)]",")]");
350 fermat.Execute(tmp);
351 ss.clear();
352 ss.str("");
353
354 ss << "&(U=1);" << endl; // ugly printing, the whitespace matters
355 ss << "![m" << endl;
356 auto ostr = fermat.Execute(ss.str());
357 ss.clear();
358 ss.str("");
359 //fermat.Exit();
360
361 // note the order, before exfactor (normal_fermat will be called again here)
362 ss << "&(U=0);" << endl; // disable ugly printing
363 ss << "@([m]);" << endl;
364 ss << "&_G;" << endl;
365 fermat.Execute(ss.str());
366 ss.clear();
367 ss.str("");
368
369 // make sure last char is 0
370 if(ostr[ostr.length()-1]!='0') throw Error("Apart: last char is NOT 0.");
371 ostr = ostr.substr(0, ostr.length()-1);
372 string_trim(ostr);
373
374 ostr.erase(0, ostr.find(":=")+2);
375 string_replace_all(ostr, "[", "{");
376 string_replace_all(ostr, "]", "}");
377 Parser fp(st);
378 auto mat2 = fp.Read(ostr);
379
380 exmap xs;
381 for(int c=0; c<ncol; c++) xs[c] = iWF(c);
382 for(int r=nrow-1; r>=0; r--) {
383 ex xadd = 0;
384 int pi=-1;
385 for(int c=0; c<ncol; c++) {
386 if(!is_zero(get_op(mat2,r,c)) && pi<0) pi = c;
387 else xadd -= get_op(mat2,r,c)*xs[c];
388 }
389 xs[pi] = xadd;
390 }
391 for(int c=0; c<ncol; c++) null_vec.append(xs[c]);
392 } else {
393 matrix v(ncol, 1);
394 exmap sRepl;
395 for (int c=0; c<ncol; c++) {
396 symbol t;
397 v(c,0) = t;
398 sRepl[t]=iWF(c);
399 }
400 // Solve M*V = 0
401 matrix zero(nrow, 1);
402 matrix s = ex_to<matrix>(key.subs(iEpsilon==0,nopat)).solve(v,zero);
403 for(int r=0; r<ncol; r++) null_vec.append(s(r,0).subs(sRepl,nopat));
404 }
405 null_cache.insert({key,null_vec});
406 } else {
407 null_vec = ex_to<lst>(null_itr->second);
408 }
409
410 // check null & return ApartIR
411 bool is_null = true;
412 for(int c=0; c<ncol; c++) {
413 if(!is_zero(null_vec.op(c))) {
414 is_null = false;
415 break;
416 }
417 }
418 if(is_null) {
419 ex res = ApartIR(mat);
420 if(using_cache) mat_cache.insert({mat,res});
421 return res;
422 }
423
424 // handle numerator
425 int ni=-1;
426 for(int c=0; c<ncol; c++) {
427 if(mat(nrow+1,c)>0 && !is_zero(null_vec.op(c))) {
428 ni = c;
429 break;
430 }
431 }
432
433 if(ni!=-1) {
434 ex nvec;
435 if(true) {
436 exset wfs;
437 find(null_vec.op(ni),iWF(w),wfs);
438 if(wfs.size()<1) throw Error("Apart: something is wrong!");
439 symbol s;
440
441 int max = -1;
442 for(auto wf : wfs) {
443 auto n1 = subs(null_vec, wf==s);
444 n1 = subs(n1, iWF(w)==0);
445 for(int i=0; i<3; i++) {
446 auto n2 = subs(n1, s==i);
447 if(!is_zero(n2.op(ni))) {
448 int nt = 0;
449 for(auto ii : n2) if(ii.is_zero()) nt++;
450 if(nt>max && nt!=ncol) { nvec = n2; max = nt; }
451 break;
452 }
453 }
454 }
455 if(nvec.has(iWF(w)) || is_zero(nvec.op(ni))) throw Error("Apart: iWF to int failed with "+ex2str(null_vec.op(ni)));
456 }
457
458 ex sol = 0;
459 for(int c=0; c<ncol; c++) {
460 if(c==ni) continue;
461 sol -= nvec.op(c) * (iWF(c)-mat(nrow,c)); // iWF(c) refer to c-th column, and minus the const term
462 }
463 sol = sol/nvec.op(ni) + mat(nrow,ni); // last one: const term
464 sol = collect_ex(pow(sol.subs(iEpsilon==0,nopat), mat(nrow+1,ni)), iWF(w)); // expand the numerator with power
465
466 if(!is_a<add>(sol)) sol = lst{ sol };
467 ex res = 0;
468 for(auto item : sol) {
469 int nzero = 0;
470 matrix mat2(nrow+2, ncol-1);
471 for(int c=0; c<ncol; c++) {
472 if(c==ni) continue;
473 int c2 = (c<ni ? c : c-1);
474 for(int r=0; r<nrow+1; r++) {
475 mat2(r,c2) = mat(r,c);
476 }
477 auto expn = mat(nrow+1,c) + item.degree(iWF(c));
478 if(is_zero(expn)) nzero++;
479 mat2(nrow+1,c2) = expn;
480 }
481 if(nzero>0) {
482 if((ncol-1-nzero)==0) {
483 res += ApartIR(1) * item.subs(iWF(w)==1);
484 } else {
485 matrix mat3(nrow+2, ncol-1-nzero);
486 int cc=0;
487 for(int c=0; c<ncol-1; c++) {
488 if(is_zero(mat2(nrow+1,c))) continue;
489 for(int r=0; r<nrow+2; r++) {
490 mat3(r,cc) = mat2(r,c);
491 }
492 cc++;
493 }
494 res += Apart(mat3) * item.subs(iWF(w)==1);
495 }
496 } else {
497 res += Apart(mat2) * item.subs(iWF(w)==1);
498 }
499 }
500 res = collect_ex(res,ApartIR(w));
501 if(using_cache) mat_cache.insert({mat,res});
502 return res;
503 }
504
505 // handle all denominators
506 ex cres0 = 0;
507 for(int c=0; c<ncol; c++) cres0 += mat(nrow,c)*null_vec.op(c);
508 cres0 = cres0.subs(iEpsilon==0,nopat);
509
510 ex nvec,cres;
511 if(true) {
512 exset wfs;
513 find(lst{cres0, null_vec},iWF(w),wfs);
514 if(wfs.size()<1) {
515 cres = cres0;
516 nvec = null_vec;
517 } else {
518 symbol s;
519 int max = -1;
520 bool c0 = true;
521 for(auto wf : wfs) {
522 auto c1 = subs(cres0, wf==s);
523 auto n1 = subs(null_vec, wf==s);
524 c1 = subs(c1, iWF(w)==0);
525 n1 = subs(n1, iWF(w)==0);
526 for(int i=0; i<5; i++) {
527 auto c2 = subs(c1, s==i).normal();
528 auto n2 = subs(n1, s==i);
529 if(!c0 && c2.is_zero()) continue;
530 if(c0 && !c2.is_zero()) {
531 c0 = false;
532 nvec = n2; cres = c2;
533 } else {
534 int nt = 0;
535 for(auto ii : n2) if(ii.is_zero()) nt++;
536 if(nt>max && nt!=ncol) { nvec = n2; cres = c2; max = nt; }
537 }
538 }
539 }
540 }
541 } // end if(true)
542
543 if(nvec.has(iWF(w)) || cres.has(iWF(w))) {
544 cout << cres0 << ", " << null_vec << endl;
545 throw Error("Apart: iWF still left.");
546 }
547
548 // handle const is NOT zero
549 if(!IsZero(cres)) {
550 ex res=0;
551 for(int c=0; c<ncol; c++) {
552 if(is_zero(nvec.op(c))) continue;
553 if(is_zero(mat(nrow+1,c)+1)) {
554 matrix mat2(nrow+2,ncol-1);
555 int ccc = 0;
556 for(int cc=0; cc<ncol; cc++) {
557 if(cc==c) continue;
558 for(int r=0; r<nrow+2; r++) mat2(r,ccc)=mat(r,cc);
559 ccc++;
560 }
561 res += Apart(mat2) * nvec.op(c);
562 } else {
563 matrix mat2(mat);
564 mat2(nrow+1,c) = mat2(nrow+1,c)+1;
565 res += Apart(mat2) * nvec.op(c);
566 }
567 }
568 res = res/cres;
569 res = collect_ex(res,ApartIR(w));
570 if(using_cache) mat_cache.insert({mat,res});
571 return res;
572 } else {
573 int ni=-1;
574 for(int c=0; c<ncol; c++) {
575 if(!is_zero(nvec.op(c))) {
576 ni = c;
577 break;
578 }
579 }
580
581 ex res=0;
582 for(int c=0; c<ncol; c++) {
583 if(is_zero(nvec.op(c)) || c==ni) continue;
584 if(is_zero(mat(nrow+1,c)+1)) {
585 matrix mat2(nrow+2,ncol-1);
586 int ccc = 0;
587 for(int cc=0; cc<ncol; cc++) {
588 if(cc==c) continue;
589 for(int r=0; r<nrow+2; r++) mat2(r,ccc)=mat(r,cc);
590 ccc++;
591 }
592 int ni2 = ni>c ? ni-1 : ni;
593 mat2(nrow+1,ni2) = mat2(nrow+1,ni2)-1;
594 res -= Apart(mat2) * nvec.op(c);
595 } else {
596 matrix mat2(mat);
597 mat2(nrow+1,c) = mat2(nrow+1,c)+1;
598 mat2(nrow+1,ni) = mat2(nrow+1,ni)-1;
599 res -= Apart(mat2) * nvec.op(c);
600 }
601 }
602 res = res/nvec.op(ni);
603 res = collect_ex(res,ApartIR(w));
604 if(using_cache) mat_cache.insert({mat,res});
605 return res;
606 }
607 }
608
616 ex Apart(const ex &expr_ino, const lst &vars_in, exmap smap) {
617 // Apart on rational terms
618 if(!is_a<lst>(expr_ino)) {
619 auto cv_lst = collect_lst(expr_ino, vars_in);
620 ex res = 0;
621 for(auto item : cv_lst) res += item.op(0) * Apart(lst{item.op(1)}, vars_in, smap);
622 res = collect_ex(res, ApartIR(w1,w2));
623
624 // random check
625 lst nlst;
626 for(const_preorder_iterator i = res.preorder_begin(); i != res.preorder_end(); ++i) {
627 auto e = (*i);
628 if(is_a<symbol>(e) || is_a<Pair>(e)) nlst.append(e);
629 }
630 for(auto var : vars_in) nlst.append(var);
631 nlst.sort();
632 nlst.unique();
633 exmap nrepl;
634 auto pi = nextprime(3);
635 for(auto ni : nlst) {
636 pi = nextprime(pi+1);
637 nrepl[ni] = ex(1)/pi;
638 }
639 nrepl[iEpsilon]=0;
640 ex chk = ApartIR2ex(subs(res,nrepl))-subs(expr_ino,nrepl);
641 chk = exnormal(chk);
642 if(!is_zero(chk)) throw Error("Apart@1 random check Failed.");
643 return res;
644 }
645
646 // Apart on monomial term
647 if(expr_ino.nops()!=1) throw Error("Apart: wrong convention found!");
648 ex expr_in = expr_ino.op(0);
649
650 static exmap cache;
651 if(using_cache && cache_limit>0 && cache.size() > cache_limit) cache.clear();
652 auto itr = cache.find(expr_in);
653 if(itr!=cache.end()) return itr->second;
654
655 exmap map1, map2;
656 lst vars;
657 for(int i=0; i<vars_in.nops(); i++) {
658 auto v = vars_in.op(i);
659 Symbol s("_apX"+to_string(i));
660 map1[v]=s;
661 map2[s]=v;
662 vars.append(s);
663 }
664 exmap sgnmap;
665 for(auto kv : smap) sgnmap[kv.first.subs(map1,nopat)] = kv.second.subs(map1,nopat);
666
667 ex expr = expr_in.subs(map1,nopat);
668 if(!is_a<mul>(expr)) expr = lst{expr};
669
670 // check only, try normal_fermat if faild
671 bool ok = true;
672 for(auto item : expr) {
673 bool has_var=false;
674 for(auto v : vars) {
675 if(item.has(v)) {
676 has_var=true;
677 break;
678 }
679 }
680 if(has_var) {
681 if(!isOK(item,vars)) {
682 ok = false;
683 break;
684 }
685 }
686 }
687 if(!ok) {
688 expr = expr_in.subs(map1,nopat);
689 expr = exnormal(expr,o_flintfD); // need option factor=true, factor denominator
690 if(!is_a<mul>(expr)) expr = lst{expr};
691 }
692
693 lst pnlst;
694 ex pref = 1;
695 map<ex,int,ex_is_less> count_ip;
696 exmap ie_map;
697 for(auto item : expr) {
698 bool has_var=false;
699 for(auto v : vars) {
700 if(item.has(v)) {
701 has_var=true;
702 break;
703 }
704 }
705 if(has_var) {
706 if(!isOK(item,vars)) {
707 cout << expr_in << endl;
708 cout << item << endl;
709 throw Error("Apart: item is not linear wrt vars.");
710 }
711
712 ex pc, nc;
713 if(is_a<power>(item)) {
714 pc = item.op(0);
715 nc = item.op(1);
716 } else {
717 pc = item;
718 nc = 1;
719 }
720
721 // consider sign
722 bool has_sgn = false;
723 // iEpsilon
724 if(pc.has(iEpsilon)) { // iEpsilon first
725 ex si = 1; // default
726 auto itr = sgnmap.find(iEpsilon);
727 if(itr != sgnmap.end() && !is_zero(itr->second)) si = itr->second;
728 ex sign = si/pc.coeff(iEpsilon);
729 pref /= pow(sign, nc);
730 pc *= sign;
731 has_sgn = true;
732 }
733 // v from sgnmap
734 if(!has_sgn) {
735 for(auto v : vars) {
736 auto cc = pc.coeff(v);
737 if(is_zero(cc) || !key_exists(sgnmap,v) || is_zero(sgnmap[v])) continue;
738 ex sign = sgnmap[v]/cc;
739 pref /= pow(sign, nc);
740 pc *= sign;
741 has_sgn = true;
742 break;
743 }
744 }
745 // v from vars
746 if(!has_sgn) {
747 for(auto v : vars) {
748 if(key_exists(sgnmap,v)) continue; // already handled by sgnmap
749 auto cc = pc.coeff(v);
750 if(is_zero(cc) || !is_a<numeric>(cc)) continue;
751 ex sign = 1/cc;
752 pref /= pow(sign, nc);
753 pc *= sign;
754 break;
755 }
756 }
757
758 ex key = expand(pc.subs(iEpsilon==0,nopat));
759 if(pc.has(iEpsilon)) {
760 if(ie_map.find(-key) != ie_map.end()) {
761 cout << expr_ino << endl;
762 cout << "Item 1: " << ie_map[-key].subs(map2,nopat) << endl;
763 cout << "Item 2: " << pc.subs(map2,nopat) << endl;
764 throw Error("iEpsilon Error: maybe pinch singularity?");
765 }
766 ie_map[key] = pc;
767 }
768
769 auto itr = count_ip.find(key);
770 if(itr==count_ip.end()) itr = count_ip.find(-key);
771 if(itr==count_ip.end()) count_ip[key] = 1;
772 else itr->second++;
773
774 pnlst.append(lst{ pc, nc });
775 } else pref *= item;
776 }
777 // check whether needs to combine again
778 bool needs_again = false;
779 for(auto kv : count_ip) {
780 if(kv.second>1) { needs_again = true; break; }
781 }
782 if(needs_again) {
783 exmap imap;
784 for(auto pn : pnlst) {
785 auto key = pn.op(0);
786 if(key.has(iEpsilon)) {
787 auto k = key.subs(iEpsilon==0,nopat);
788 if(imap.find(-k) != imap.end()) {
789 cout << "Item 1: " << imap[k] << endl;
790 cout << "Item 2: " << key << endl;
791 throw Error("iEpsilon Error: maybe pinch singularity?");
792 }
793 if(imap.find(k)==imap.end()) imap[k] = key;
794 }
795 }
796 exmap p2n;
797 for(auto pn : pnlst) {
798 auto key = pn.op(0);
799 auto itr = imap.find(key);
800 if(itr!=imap.end()) key = itr->second;
801 else {
802 itr = imap.find(-key);
803 if(itr!=imap.end()) {
804 key = itr->second;
805 pref *= pow(-1, pn.op(1));
806 }
807 }
808 p2n[key] = p2n[key] + pn.op(1);
809 }
810 pnlst.remove_all();
811 for(auto kv : p2n) {
812 if(is_zero(kv.second)) continue;
813 auto k = kv.first;
814 auto v = kv.second;
815 if(is_a<numeric>(v) && ex_to<numeric>(v)>0) {
816 k = k.subs(iEpsilon==0,nopat);
817 }
818 pnlst.append(lst{k, v});
819 }
820 }
821 sort_lst(pnlst); // need sort_lst
822
823 if(pnlst.nops()==0) return cache[expr_in] = pref * ApartIR(1,vars_in);
824
825 int nrow=vars.nops(), ncol=pnlst.nops();
826 exmap vars0;
827 for(auto v : vars) vars0[v]=0;
828 matrix mat(nrow+2, ncol);
829 for(int c=0; c<ncol; c++) {
830 ex pn = pnlst.op(c);
831 if(pn.op(0).is_zero() && pn.op(1).is_zero()) throw Error("Apart: 0^0 is found!");
832 mat(nrow+1,c) = normal(pn.op(1));
833 auto tmp = pn.op(0);
834 for(int r=0; r<nrow; r++) {
835 mat(r,c) = exnormal(tmp.coeff(vars.op(r)));
836 }
837 mat(nrow,c) = exnormal(tmp.subs(vars0,nopat));
838 }
839
840 ex ret = Apart(mat);
841
842 auto cv_lst = collect_lst(ret,ApartIR(w));
843 ret = 0;
844 for(auto cv : cv_lst) {
845 ret += pref * cv.op(0) * ApartIR(cv.op(1).op(0), vars).subs(map2,nopat);
846 }
847
848 return cache[expr_in] = ret;
849 }
850
859 ex Apart(const ex &expr_ino, const lst &loops, const lst & extps, exmap smap) {
860 auto expr_in = expr_ino.subs(SP_map,nopat);
861 auto expr = expr_in;
862
863 lst sps;
864 for(auto li : loops) {
865 for(auto li2: loops) {
866 auto item = SP(li, li2).subs(SP_map,nopat);
867 if(is_a<Pair>(item)) sps.append(item);
868 }
869 for(auto ei: extps) {
870 auto item = SP(li, ei).subs(SP_map,nopat);
871 if(is_a<Pair>(item)) sps.append(item);
872 }
873 }
874 sps.sort();
875 sps.unique();
876
877 auto cv_lst = collect_lst(expr, loops);
878 ex res = 0;
879 for(auto item : cv_lst) {
880 res += item.op(0) * Apart(lst{item.op(1)}, sps, smap);
881 }
882
883 res = collect_ex(res, ApartIR(w1,w2));
884
885 // random check
886 lst nlst;
887 for(const_preorder_iterator i = res.preorder_begin(); i != res.preorder_end(); ++i) {
888 auto e = (*i);
889 if(is_a<symbol>(e) || is_a<Pair>(e)) nlst.append(e);
890 }
891 nlst.sort();
892 nlst.unique();
893 exmap nrepl;
894 auto pi = nextprime(3);
895 for(auto ni : nlst) {
896 pi = nextprime(pi+1);
897 nrepl[ni] = 1/pi;
898 }
899 nrepl[iEpsilon]=0;
900 ex chk = ApartIR2ex(subs(res,nrepl))-subs(expr_in,nrepl);
901 chk = normal(chk);
902 if(!is_zero(chk)) {
903 throw Error("Apart@2 random check Failed.");
904 }
905
906 return res;
907 }
908
914 ex ApartIRC(const ex & expr_in) {
915 exmap cache;
916 MapFunction map([&cache](const ex & e, MapFunction &self)->ex {
917 if(!e.has(ApartIR(w1,w2))) return e;
918 else if(e.match(ApartIR(w1,w2))) {
919 auto i = cache.find(e);
920 if(i!=cache.end()) return i->second;
921 int n = e.op(1).nops();
922 if((e.op(0)).is_equal(1)) {
923 matrix mat(n+2,n);
924 for(int r=0; r<n+2; r++) {
925 for(int c=0; c<n; c++) mat(r,c) = 0;
926 }
927 for(int i=0; i<n; i++) mat(i,i) = 1;
928 return cache[e] = ApartIR(mat, e.op(1));
929 }
930 if(!is_a<matrix>(e.op(0))) throw Error("ApartIRC: Not matrix : " + ex2str(e.op(0)));
931 auto mat0 = ex_to<matrix>(e.op(0));
932 matrix mat(n+2,n);
933 int cc = mat0.cols();
934 if(cc==n) mat=mat0;
935 else {
936 // zero each element
937 for(int r=0; r<n+2; r++) {
938 for(int c=0; c<cc; c++) mat(r,c) = 0;
939 }
940 // n-row from mat0 to mat, note the last 2 rows still 0
941 for(int r=0; r<n; r++) {
942 for(int c=0; c<cc; c++) mat(r,c) = mat0(r,c);
943 }
944 for(int i=0; i<n; i++) {
945 mat(i,cc) = 1;
946 auto r = mat.rank();
947 if(r==n) break;
948 if(r==cc+1) cc++;
949 else mat(i,cc) = 0;
950 }
951 if(mat.rank()!=n) throw Error("ApartIRC failed, NOT full rank.");
952 // last 2 rows from mat0 to mat
953 for(int r=n; r<n+2; r++) {
954 for(int c=0; c<mat0.cols(); c++) mat(r,c) = mat0(r,c);
955 }
956 }
957 return cache[e] = ApartIR(mat, e.op(1));
958 } else return e.map(self);
959 });
960 return map(expr_in);
961 }
962
963
964}
965
966
#define CHECK
HEP header file.
class used to wrap error message
Definition BASIC.h:242
interface to communicate with Fermat program
Definition BASIC.h:797
string Execute(string)
Definition Process.cpp:102
class to wrap map_function of GiNaC
Definition BASIC.h:632
class to parse for string or file, helpful with Symbol class
Definition BASIC.h:645
ex Read(const string &instr, bool s2S=true)
class extended to GiNaC symbol class, represent a positive symbol
Definition BASIC.h:113
ex subs(const exmap &m, unsigned options=0) const override
Definition BASIC.h:145
do_not_evalf_params().expl_derivative_func(zd2D).derivative_func(zp2D)) REGISTER_FUNCTION(CT
HepLib namespace.
Definition BASIC.cpp:17
const iSymbol iEpsilon
ex pn2p(ex pn)
Definition Apart.cpp:145
ex pn2mat(ex ps, ex ns, ex vars)
Definition Apart.cpp:109
exmap SP_map
Definition Init.cpp:182
ex ApartIR2F(const ex &expr_in)
convert ApartIR to F(ps, ns), ns is like FIRE convention
Definition Apart.cpp:61
ex ApartIRC(const ex &expr_in)
complete the ApartIR elements
Definition Apart.cpp:914
ex collect_ex(ex const &expr_in, std::function< bool(const ex &)> has_func, int opt)
the collect function like Mathematica
Definition BASIC.cpp:1202
bool Apart_using_fermat
Definition Init.cpp:210
ex ApartIR2ex(const ex &expr_in)
convert ApartIR to ex
Definition Apart.cpp:35
bool key_exists(const exmap &map, const ex &key)
Definition BASIC.h:293
bool using_cache
Definition Init.cpp:156
ex air2pn(ex air)
Definition Apart.cpp:89
ex w
Definition Init.cpp:93
const Symbol vs
ex get_op(const ex ex_in, int index1, int index2)
return index1-th.index2-th of expression
Definition BASIC.cpp:1606
ex exnormal(const ex &expr, int opt)
normalize a expression
Definition BASIC.cpp:1916
const int o_flintfD
Definition Init.cpp:115
ex nextprime(const ex &n)
Definition BASIC.cpp:2284
lst collect_lst(ex const &expr_in, std::function< bool(const ex &)> has_func, int opt)
the collect function like Mathematica, reture the lst { {c1,v1}, {c2,v2}, ... }
Definition BASIC.cpp:1222
exmap ApartRules(const exvector &airs, bool irc)
Definition Apart.cpp:156
void sort_lst(lst &ilst, bool less=true)
sort the list in less order, or the reverse
Definition Sort.cpp:79
void string_replace_all(string &str, const string &from, const string &to)
bool is_subset(const ex &e1, const ex &e2)
Definition Apart.cpp:130
string ex2str(const ex &expr)
convert ex to output string, the defalut printer format will be used
Definition BASIC.cpp:715
bool IsZero(const ex &e)
ex Apart(const matrix &mat)
Apart on matrix.
Definition Apart.cpp:280
long long cache_limit
Definition Init.cpp:157
ex w1
Definition BASIC.h:499
unsigned nopat
Definition Init.cpp:91
exvector GiNaC_Parallel(int ntotal, std::function< ex(int)> f, const string &key)
GiNaC Parallel Evaluation using fork.
Definition BASIC.cpp:260
ex w2
Definition BASIC.h:499
void string_trim(string &str)
ex SP(const ex &a, bool use_map=false)
Definition Pair.cpp:166
ex subs(const ex &e, init_list sl)
Definition BASIC.h:51