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 apart_cache;
651 if(using_cache && cache_limit>0 && apart_cache.size() > cache_limit) apart_cache.clear();
652 ex ckey = lst{expr_in, vars_in};
653 auto itr = apart_cache.find(ckey);
654 if(itr!=apart_cache.end()) return itr->second;
655
656 exmap map1, map2;
657 lst vars;
658 for(int i=0; i<vars_in.nops(); i++) {
659 auto v = vars_in.op(i);
660 Symbol s("_apX"+to_string(i));
661 map1[v]=s;
662 map2[s]=v;
663 vars.append(s);
664 }
665 exmap sgnmap;
666 for(auto kv : smap) sgnmap[kv.first.subs(map1,nopat)] = kv.second.subs(map1,nopat);
667
668 ex expr = expr_in.subs(map1,nopat);
669 if(!is_a<mul>(expr)) expr = lst{expr};
670
671 // check only, try normal_fermat if faild
672 bool ok = true;
673 for(auto item : expr) {
674 bool has_var=false;
675 for(auto v : vars) {
676 if(item.has(v)) {
677 has_var=true;
678 break;
679 }
680 }
681 if(has_var) {
682 if(!isOK(item,vars)) {
683 ok = false;
684 break;
685 }
686 }
687 }
688 if(!ok) {
689 expr = expr_in.subs(map1,nopat);
690 expr = exnormal(expr,o_flintfD); // need option factor=true, factor denominator
691 if(!is_a<mul>(expr)) expr = lst{expr};
692 }
693
694 lst pnlst;
695 ex pref = 1;
696 map<ex,int,ex_is_less> count_ip;
697 exmap ie_map;
698 for(auto item : expr) {
699 bool has_var=false;
700 for(auto v : vars) {
701 if(item.has(v)) {
702 has_var=true;
703 break;
704 }
705 }
706 if(has_var) {
707 if(!isOK(item,vars)) {
708 cout << expr_in << endl;
709 cout << item << endl;
710 throw Error("Apart: item is not linear wrt vars.");
711 }
712
713 ex pc, nc;
714 if(is_a<power>(item)) {
715 pc = item.op(0);
716 nc = item.op(1);
717 } else {
718 pc = item;
719 nc = 1;
720 }
721
722 // consider sign
723 bool has_sgn = false;
724 // iEpsilon
725 if(pc.has(iEpsilon)) { // iEpsilon first
726 ex si = 1; // default
727 auto itr = sgnmap.find(iEpsilon);
728 if(itr != sgnmap.end() && !is_zero(itr->second)) si = itr->second;
729 ex sign = si/pc.coeff(iEpsilon);
730 pref /= pow(sign, nc);
731 pc *= sign;
732 has_sgn = true;
733 }
734 // v from sgnmap
735 if(!has_sgn) {
736 for(auto v : vars) {
737 auto cc = pc.coeff(v);
738 if(is_zero(cc) || !key_exists(sgnmap,v) || is_zero(sgnmap[v])) continue;
739 ex sign = sgnmap[v]/cc;
740 pref /= pow(sign, nc);
741 pc *= sign;
742 has_sgn = true;
743 break;
744 }
745 }
746 // v from vars
747 if(!has_sgn) {
748 for(auto v : vars) {
749 if(key_exists(sgnmap,v)) continue; // already handled by sgnmap
750 auto cc = pc.coeff(v);
751 if(is_zero(cc) || !is_a<numeric>(cc)) continue;
752 ex sign = 1/cc;
753 pref /= pow(sign, nc);
754 pc *= sign;
755 break;
756 }
757 }
758
759 ex key = expand(pc.subs(iEpsilon==0,nopat));
760 if(pc.has(iEpsilon)) {
761 if(ie_map.find(-key) != ie_map.end()) {
762 cout << expr_ino << endl;
763 cout << "Item 1: " << ie_map[-key].subs(map2,nopat) << endl;
764 cout << "Item 2: " << pc.subs(map2,nopat) << endl;
765 throw Error("iEpsilon Error: maybe pinch singularity?");
766 }
767 ie_map[key] = pc;
768 }
769
770 auto itr = count_ip.find(key);
771 if(itr==count_ip.end()) itr = count_ip.find(-key);
772 if(itr==count_ip.end()) count_ip[key] = 1;
773 else itr->second++;
774
775 pnlst.append(lst{ pc, nc });
776 } else pref *= item;
777 }
778 // check whether needs to combine again
779 bool needs_again = false;
780 for(auto kv : count_ip) {
781 if(kv.second>1) { needs_again = true; break; }
782 }
783 if(needs_again) {
784 exmap imap;
785 for(auto pn : pnlst) {
786 auto key = pn.op(0);
787 if(key.has(iEpsilon)) {
788 auto k = key.subs(iEpsilon==0,nopat);
789 if(imap.find(-k) != imap.end()) {
790 cout << "Item 1: " << imap[k] << endl;
791 cout << "Item 2: " << key << endl;
792 throw Error("iEpsilon Error: maybe pinch singularity?");
793 }
794 if(imap.find(k)==imap.end()) imap[k] = key;
795 }
796 }
797 exmap p2n;
798 for(auto pn : pnlst) {
799 auto key = pn.op(0);
800 auto itr = imap.find(key);
801 if(itr!=imap.end()) key = itr->second;
802 else {
803 itr = imap.find(-key);
804 if(itr!=imap.end()) {
805 key = itr->second;
806 pref *= pow(-1, pn.op(1));
807 }
808 }
809 p2n[key] = p2n[key] + pn.op(1);
810 }
811 pnlst.remove_all();
812 for(auto kv : p2n) {
813 if(is_zero(kv.second)) continue;
814 auto k = kv.first;
815 auto v = kv.second;
816 if(is_a<numeric>(v) && ex_to<numeric>(v)>0) {
817 k = k.subs(iEpsilon==0,nopat);
818 }
819 pnlst.append(lst{k, v});
820 }
821 }
822 sort_lst(pnlst); // need sort_lst
823
824 if(pnlst.nops()==0) return apart_cache[ckey] = pref * ApartIR(1,vars_in);
825
826 int nrow=vars.nops(), ncol=pnlst.nops();
827 exmap vars0;
828 for(auto v : vars) vars0[v]=0;
829 matrix mat(nrow+2, ncol);
830 for(int c=0; c<ncol; c++) {
831 ex pn = pnlst.op(c);
832 if(pn.op(0).is_zero() && pn.op(1).is_zero()) throw Error("Apart: 0^0 Found!");
833 mat(nrow+1,c) = normal(pn.op(1));
834 auto tmp = pn.op(0);
835 for(int r=0; r<nrow; r++) {
836 mat(r,c) = exnormal(tmp.coeff(vars.op(r)));
837 }
838 mat(nrow,c) = exnormal(tmp.subs(vars0,nopat));
839 }
840
841 ex ret = Apart(mat);
842
843 auto cv_lst = collect_lst(ret,ApartIR(w));
844 ret = 0;
845 for(auto cv : cv_lst) {
846 ret += pref * cv.op(0) * ApartIR(cv.op(1).op(0), vars).subs(map2,nopat);
847 }
848
849 return apart_cache[ckey] = ret;
850 }
851
860 ex Apart(const ex &expr_ino, const lst &loops, const lst & extps, exmap smap) {
861 auto expr_in = expr_ino.subs(SP_map,nopat);
862 auto expr = expr_in;
863
864 lst sps;
865 for(auto li : loops) {
866 for(auto li2: loops) {
867 auto item = SP(li, li2).subs(SP_map,nopat);
868 if(is_a<Pair>(item)) sps.append(item);
869 }
870 for(auto ei: extps) {
871 auto item = SP(li, ei).subs(SP_map,nopat);
872 if(is_a<Pair>(item)) sps.append(item);
873 }
874 }
875 sps.sort();
876 sps.unique();
877
878 auto cv_lst = collect_lst(expr, loops);
879 ex res = 0;
880 for(auto item : cv_lst) {
881 res += item.op(0) * Apart(lst{item.op(1)}, sps, smap);
882 }
883
884 res = collect_ex(res, ApartIR(w1,w2));
885
886 // random check
887 lst nlst;
888 for(const_preorder_iterator i = res.preorder_begin(); i != res.preorder_end(); ++i) {
889 auto e = (*i);
890 if(is_a<symbol>(e) || is_a<Pair>(e)) nlst.append(e);
891 }
892 nlst.sort();
893 nlst.unique();
894 exmap nrepl;
895 auto pi = nextprime(3);
896 for(auto ni : nlst) {
897 pi = nextprime(pi+1);
898 nrepl[ni] = 1/pi;
899 }
900 nrepl[iEpsilon]=0;
901 ex chk = ApartIR2ex(subs(res,nrepl))-subs(expr_in,nrepl);
902 chk = normal(chk);
903 if(!is_zero(chk)) {
904 throw Error("Apart@2 random check Failed.");
905 }
906
907 return res;
908 }
909
915 ex ApartIRC(const ex & expr_in) {
916 exmap cache;
917 MapFunction map([&cache](const ex & e, MapFunction &self)->ex {
918 if(!e.has(ApartIR(w1,w2))) return e;
919 else if(e.match(ApartIR(w1,w2))) {
920 auto i = cache.find(e);
921 if(i!=cache.end()) return i->second;
922 int n = e.op(1).nops();
923 if((e.op(0)).is_equal(1)) {
924 matrix mat(n+2,n);
925 for(int r=0; r<n+2; r++) {
926 for(int c=0; c<n; c++) mat(r,c) = 0;
927 }
928 for(int i=0; i<n; i++) mat(i,i) = 1;
929 return cache[e] = ApartIR(mat, e.op(1));
930 }
931 if(!is_a<matrix>(e.op(0))) throw Error("ApartIRC: Not matrix : " + ex2str(e.op(0)));
932 auto mat0 = ex_to<matrix>(e.op(0));
933 matrix mat(n+2,n);
934 int cc = mat0.cols();
935 if(cc==n) mat=mat0;
936 else {
937 // zero each element
938 for(int r=0; r<n+2; r++) {
939 for(int c=0; c<cc; c++) mat(r,c) = 0;
940 }
941 // n-row from mat0 to mat, note the last 2 rows still 0
942 for(int r=0; r<n; r++) {
943 for(int c=0; c<cc; c++) mat(r,c) = mat0(r,c);
944 }
945 for(int i=0; i<n; i++) {
946 mat(i,cc) = 1;
947 auto r = mat.rank();
948 if(r==n) break;
949 if(r==cc+1) cc++;
950 else mat(i,cc) = 0;
951 }
952 if(mat.rank()!=n) throw Error("ApartIRC failed, NOT full rank.");
953 // last 2 rows from mat0 to mat
954 for(int r=n; r<n+2; r++) {
955 for(int c=0; c<mat0.cols(); c++) mat(r,c) = mat0(r,c);
956 }
957 }
958 return cache[e] = ApartIR(mat, e.op(1));
959 } else return e.map(self);
960 });
961 return map(expr_in);
962 }
963
964
965}
966
967
#define CHECK
HEP header file.
int pn
Definition Others.cpp:25
class used to wrap error message
Definition BASIC.h:242
interface to communicate with Fermat program
Definition BASIC.h:840
string Execute(string)
Definition Process.cpp:102
class to wrap map_function of GiNaC
Definition BASIC.h:675
class to parse for string or file, helpful with Symbol class
Definition BASIC.h:688
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:184
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:915
ex collect_ex(ex const &expr_in, std::function< bool(const ex &)> has_func, int opt)
the collect function like Mathematica
Definition BASIC.cpp:1204
bool Apart_using_fermat
Definition Init.cpp:212
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:1608
ex exnormal(const ex &expr, int opt)
normalize a expression
Definition BASIC.cpp:1918
const int o_flintfD
Definition Init.cpp:115
ex nextprime(const ex &n)
Definition BASIC.cpp:2286
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:1224
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:717
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