HepLib
IBP.cpp
Go to the documentation of this file.
1 
6 #include "IBP.h"
7 #include "exFlint.h"
8 #include <cmath>
9 
10 namespace HepLib {
11 
12  namespace {
13  ex_is_less less;
14  }
15 
16  static void a_print(const ex & ex_in, const print_context & c) {
17  c.s << "a[" << ex_in << "]";
18  }
19 
20  REGISTER_FUNCTION(a, do_not_evalf_params().print_func<print_dflt>(a_print))
21 
22  void IBP::Reduce() {
23  Export();
24  Run();
25  Import();
26  }
27 
28  void IBP::garExport(string garfn) {
29  archive ar;
30  ar.archive_ex(Internal, "Internal");
31  ar.archive_ex(External, "External");
32  ar.archive_ex(Replacement, "Replacement");
33  ar.archive_ex(Propagator, "Propagator");
34  ar.archive_ex(Cut, "Cut");
35  ar.archive_ex(DSP, "DSP");
36  ar.archive_ex(ISP, "ISP");
37  ar.archive_ex(SECTOR, "SECTOR");
38 
39  ar.archive_ex(Shift.size(), "NShift");
40  int i = 0;
41  for(auto kv : Shift) {
42  ar.archive_ex(kv.first, ("ShiftK-"+to_string(i)).c_str());
43  ar.archive_ex(kv.second, ("ShiftV-"+to_string(i)).c_str());
44  i++;
45  }
46 
47  ar.archive_ex(reCut, "reCut"); // bool
48  ar.archive_ex(ProblemNumber, "ProblemNumber"); // int
49  ar.archive_ex(Symbol(WorkingDir), "WorkingDir"); // string
50  ar.archive_ex(PIntegral, "PIntegral");
51  ar.archive_ex(MIntegral, "MIntegral");
52  ar.archive_ex(Rules, "Rules");
53  ar.archive_ex(IsAlwaysZero, "IsAlwaysZero"); // bool
54 
55  ofstream out(garfn);
56  out << ar;
57  out.close();
58  }
59 
60  ex IBP::TO() {
61  lst shift;
62  for(auto kv : Shift) shift.append(lst{kv.first, kv.second});
63 
65  }
66 
67  void IBP::garImport(string garfn) {
68  archive ar;
69  ifstream in(garfn);
70  in >> ar;
71  in.close();
72 
73  Internal = ex_to<lst>(ar.unarchive_ex("Internal"));
74  External = ex_to<lst>(ar.unarchive_ex("External"));
75  Replacement = ex_to<lst>(ar.unarchive_ex("Replacement"));
76  Propagator = ex_to<lst>(ar.unarchive_ex("Propagator"));
77  Cut = ex_to<lst>(ar.unarchive_ex("Cut"));
78  DSP = ex_to<lst>(ar.unarchive_ex("DSP"));
79  ISP = ex_to<lst>(ar.unarchive_ex("ISP"));
80  SECTOR = ex_to<lst>(ar.unarchive_ex("SECTOR"));
81 
82  int n = ex_to<numeric>(ar.unarchive_ex("NShift")).to_int();
83  for(int i=0; i<n; i++) {
84  int key = ex_to<numeric>(ar.unarchive_ex(("ShiftK-"+to_string(i)).c_str())).to_int();
85  ex val = ar.unarchive_ex(("ShiftV-"+to_string(i)).c_str());
86  Shift[key] = val;
87  }
88 
89  reCut = !(ar.unarchive_ex("reCut").is_zero()); // bool
90  ProblemNumber = ex_to<numeric>(ar.unarchive_ex("ProblemNumber")).to_int(); // int
91  WorkingDir = ex_to<Symbol>(ar.unarchive_ex("WorkingDir")).get_name();
92  PIntegral = ex_to<lst>(ar.unarchive_ex("PIntegral"));
93  MIntegral = ex_to<lst>(ar.unarchive_ex("MIntegral"));
94  Rules = ex_to<lst>(ar.unarchive_ex("Rules"));
95  IsAlwaysZero = !(ar.unarchive_ex("IsAlwaysZero").is_zero()); // bool
96  }
97 
98  void IBP::FROM(ex s) {
99  int i = 0;
100  Internal = ex_to<lst>(s.op(i++));
101  External = ex_to<lst>(s.op(i++));
102  Replacement = ex_to<lst>(s.op(i++));
103  Propagator = ex_to<lst>(s.op(i++));
104  Cut = ex_to<lst>(s.op(i++));
105  DSP = ex_to<lst>(s.op(i++));
106  ISP = ex_to<lst>(s.op(i++));
107  if(s.nops()>15) SECTOR = ex_to<lst>(s.op(i++)); // if to work with old version
108  lst shift = ex_to<lst>(s.op(i++));
109  reCut = s.op(i++).is_equal(1);
110  ProblemNumber = ex_to<numeric>(s.op(i++)).to_int();
111  WorkingDir = ex_to<Symbol>(s.op(i++)).get_name();
112  PIntegral = ex_to<lst>(s.op(i++));
113  MIntegral = ex_to<lst>(s.op(i++));
114  Rules = ex_to<lst>(s.op(i++));
115  IsAlwaysZero = s.op(i++).is_equal(1);
116  for(auto item : shift) Shift[ex_to<numeric>(item.op(0)).to_int()] = item.op(1);
117  }
118 
119  void IBP::ReShare(const vector<IBP*> & fs) {
120  string garfn = to_string(getpid())+".ReShare.gar";
121  if(true) {
122  archive ar;
123  for(int i=0; i<fs.size(); i++) {
124  string si = to_string(i);
125  ar.archive_ex(fs[i]->Internal, (si+"-1").c_str());
126  ar.archive_ex(fs[i]->External, (si+"-2").c_str());
127  ar.archive_ex(fs[i]->Replacement, (si+"-3").c_str());
128  ar.archive_ex(fs[i]->Propagator, (si+"-4").c_str());
129  ar.archive_ex(fs[i]->DSP, (si+"-5").c_str());
130  ar.archive_ex(fs[i]->ISP, (si+"-6").c_str());
131  ar.archive_ex(fs[i]->SECTOR,(si+"-7").c_str());
132  ar.archive_ex(fs[i]->PIntegral, (si+"-8").c_str());
133  ar.archive_ex(fs[i]->MIntegral, (si+"-9").c_str());
134  ar.archive_ex(fs[i]->Rules, (si+"-10").c_str());
135  }
136  ofstream out(garfn);
137  out << ar;
138  out.close();
139  }
140  if(true) {
141  archive ar;
142  ifstream in(garfn);
143  in >> ar;
144  in.close();
145 
146  map<string, ex> dict;
147  for(int i=0; i<ar.num_expressions(); i++) {
148  string name;
149  ex res = ar.unarchive_ex(name, i);
150  dict[name] = res;
151  }
152 
153  for(int i=0; i<fs.size(); i++) {
154  string si = to_string(i);
155  fs[i]->Internal = ex_to<lst>(dict[si+"-1"]);
156  fs[i]->External = ex_to<lst>(dict[si+"-2"]);
157  fs[i]->Replacement = ex_to<lst>(dict[si+"-3"]);
158  fs[i]->Propagator = ex_to<lst>(dict[si+"-4"]);
159  fs[i]->DSP = ex_to<lst>(dict[si+"-5"]);
160  fs[i]->ISP = ex_to<lst>(dict[si+"-6"]);
161  fs[i]->SECTOR = ex_to<lst>(dict[si+"-7"]);
162  fs[i]->PIntegral = ex_to<lst>(dict[si+"-8"]);
163  fs[i]->MIntegral = ex_to<lst>(dict[si+"-9"]);
164  fs[i]->Rules = ex_to<lst>(dict[si+"-10"]);
165  }
166  }
167  }
168 
169  pair<exmap,lst> IBP::FindRules(bool is_mi) {
170  vector<IBP*> ibps;
171  ibps.push_back(this);
172  auto rs_mis = HepLib::FindRules(ibps, is_mi);
173  if(is_mi && rs_mis.first.size()>0) {
174  auto nr = Rules.nops();
175  for(int i=0; i<nr; i++) {
176  auto ri = Rules.op(i);
177  Rules.let_op(i) = (ri.op(0) == ri.op(1).subs(rs_mis.first, nopat));
178  }
179  for(auto mi : MIntegral) {
180  auto mi2 = mi.subs(rs_mis.first, nopat);
181  if(mi==mi2) continue;
182  Rules.append(mi==mi2);
183  }
184  MIntegral = rs_mis.second;
186  }
187  return rs_mis;
188  }
189 
196  exmap SortPermutation(const ex & in_expr, const lst & xs) {
197  auto expr = in_expr;
198  bool isPoly = true;
199  exmap xmap; // note that we need xmap.size == xs.nops()
200 
201  map<ex,vector<int>,ex_is_less> pgrp;
202  if(!expr.is_polynomial(xs)) {
203  if(Verbose>2) cout << "SortPermutation: NOT a polynomials, try ALL permutations!" << endl;
204  expr = expr.numer_denom();
205  if(true || !expr.op(0).is_polynomial(xs) || !expr.op(1).is_polynomial(xs)) {
206  isPoly = false;
207  for(int i=0; i<xs.nops(); i++) {
208  pgrp[-1].push_back(i); // all permuations
209  xmap[xs.op(i)] = xs.op(i);
210  }
211  } else {
212  expr = expr.op(0) * expr.op(1);
213  }
214  }
215 
216  if(isPoly) { // only for polynomials
217  auto cv_lst = collect_lst(expr, xs);
218  exvector cvs;
219  for(auto item : cv_lst) cvs.push_back(item);
220  sort_vec(cvs); // first sort by coefficient
221 
222  int nxi = xs.nops();
223  bool first = true;
224  lst xkey[nxi];
225  lst subkey[nxi];
226  ex clast;
227  for(auto cv : cvs) {
228  ex cc = cv.op(0);
229  ex vv = cv.op(1);
230  if(is_zero(cc)) continue;
231  if(!first && !is_zero(cc-clast)) { // equal coefficient to the same key
232  for(int i=0; i<nxi; i++) {
233  sort_lst(subkey[i]);
234  for(auto item : subkey[i]) xkey[i].append(item);
235  subkey[i].remove_all();
236  }
237  }
238  first = false;
239  clast = cc;
240  for(int i=0; i<nxi; i++) subkey[i].append(vv.degree(xs.op(i)));
241  }
242 
243  for(int i=0; i<nxi; i++) { // add last subkey
244  sort_lst(subkey[i]); // need sort due to equal coefficient
245  for(auto item : subkey[i]) xkey[i].append(item);
246  subkey[i].remove_all();
247  }
248 
249  exvector key_xi;
250  for(int i=0; i<nxi; i++) key_xi.push_back(lst{xkey[i], xs.op(i)});
251  sort_vec(key_xi); // first sort by key
252 
253  for(int i=0; i<nxi; i++) {
254  auto xi = key_xi[i].op(1);
255  auto xki = key_xi[i].op(0);
256  xmap[xi] = xs.op(i); // initial x-replacement
257  pgrp[xki].push_back(i);
258  }
259  expr = expr.subs(xmap, nopat); // need to update expr before permutations
260  expr = collect_ex(expr, xs); // need collect here
261  }
262 
263  // pgrp - needs to permuation explicitly
264  ex expr_min = expr;
265  exmap xmap_min;
266  long long npt = 1;
267  for(auto pi : pgrp) {
268  int nvi = pi.second.size();
269  for(int i=1; i<=nvi; i++) npt *= i; // nvi!
270  }
271  for(long long np=0; np<npt; np++) {
272  long long npc = np;
273  exmap xmap_tmp;
274  for(auto pi : pgrp) {
275  auto vi = pi.second;
276  int nvi = vi.size();
277  if(nvi<2) continue;
278  long long npti = 1;
279  for(int i=1; i<=nvi; i++) npti *= i; // nvi!
280  int ck = npc % npti; // kth permutation
281  npc = npc / npti;
282 
283  // https://stackoverflow.com/questions/1995328/are-there-any-better-methods-to-do-permutation-of-string
284  auto vip = vi;
285  int k = ck;
286  for(int j=1; j<nvi; ++j) { // startoverflow: j starts from 1
287  std::swap(vip[k%(j+1)], vip[j]);
288  k=k/(j+1);
289  }
290 
291  for(int j=0; j<nvi; j++) xmap_tmp[xs.op(vi[j])] = xs.op(vip[j]);
292  }
293  ex expr_tmp = expr.subs(xmap_tmp,nopat);
294  if(ex_less(expr_tmp, expr_min)) {
295  expr_min = expr_tmp;
296  xmap_min = xmap_tmp;
297  }
298  }
299 
300  for(auto & kv : xmap) kv.second = kv.second.subs(xmap_min,nopat);
301  return xmap;
302  }
303 
310  lst LoopUF(const IBP & ibp, const ex & idx) {
311 
312  auto props = ibp.Propagator;
313 
314  // handle sign
315  ex sign = 1;
316  for(int i=0; i<props.nops(); i++) {
317  auto ipr = expand_ex(props.op(i), ibp.Internal);
318 
319  if(ipr.has(iEpsilon)) {
320  auto cc = ipr.coeff(iEpsilon);
321  if(is_a<numeric>(cc)) {
322  if(cc<0) { // using +iEpsilon
323  sign *= pow(-1, idx.op(i));
324  props.let_op(i) = ex(0)-props.op(i);
325  }
326  props.let_op(i) = props.op(i).subs(iEpsilon==0,nopat);
327  goto sign_done;
328  } else {
329  cout << endl << ipr << endl;
330  throw Error("LoopUF: sign of iEpsilon NOT determined.");
331  }
332  }
333 
334  for(auto lp : ibp.Internal) {
335  if(ipr.degree(lp)==2) {
336  auto cc = ipr.coeff(lp,2);
337  if(is_a<numeric>(cc)) {
338  if(cc<0) { // using +l^2
339  sign *= pow(-1, idx.op(i));
340  props.let_op(i) = ex(0)-props.op(i);
341  }
342  goto sign_done;
343  }
344  }
345  }
346 
347  sign_done: ;
348  }
349 
350  ex ut, ft, uf;
351  lst key;
352  lst xs;
353  exmap x2ax;
354  int nxi=0;
355  int nps = props.nops();
356  ft = 0;
357  for(int i=0; i<nps; i++) {
358  if(is_zero(idx.op(i))) {
359  key.append(0);
360  continue;
361  }
362  key.append(1);
363  if(!is_zero(idx.op(i)-1)) x2ax[x(nxi)] = a(idx.op(i)) * x(nxi);
364  xs.append(x(nxi));
365  ft -= x(nxi) * props.op(i); // only used when no cache item
366  nxi++;
367  }
368 
369  static map<ex,exmap,ex_is_less> cache_by_prop;
370  if(using_cache && cache_limit>0 && cache_by_prop.size() > cache_limit/10) cache_by_prop.clear();
371  exmap & cache = cache_by_prop[lst{props,ibp.Internal}];
372  if(!using_cache || cache.find(key)==cache.end()) { // no cache item
373  ut = 1;
374  ft = expand_ex(ft);
375  ft = subs(ft, ibp.Replacement);
376  for(int i=0; i<ibp.Internal.nops(); i++) {
377  auto t2 = ft.coeff(ibp.Internal.op(i),2);
378  auto t1 = ft.coeff(ibp.Internal.op(i),1);
379  auto t0 = ft.subs(ibp.Internal.op(i)==0,nopat);
380  ut *= t2;
381  if(is_zero(t2)) return lst{0,0,1};
382  ft = normal_flint(t0-t1*t1/(4*t2));
383  //ft = expand_ex(ft);
384  ft = subs(ft, ibp.Replacement);
385  }
386  ft = normal_flint(ut*ft);
387  ft = normal_flint(subs(ft, ibp.Replacement));
388  ut = normal_flint(subs(ut, ibp.Replacement));
389  uf = normal_flint(ut+ft); // ut*ft, replay with ut+ft
390 
391  if(using_cache) cache[key] = lst{ut,ft,uf};
392  } else {
393  auto cc = cache[key];
394  ut = cc.op(0);
395  ft = cc.op(1);
396  uf = cc.op(2);
397  }
398 
399  ut = ut.subs(x2ax,nopat);
400  ft = ft.subs(x2ax,nopat);
401  uf = uf.subs(x2ax,nopat);
402 
403  uf = uf.subs(MapPreSP);
404  auto xmap = SortPermutation(uf,xs);
405  ut = (ut.subs(xmap,nopat));
406  ft = (ft.subs(xmap,nopat));
407  return lst{ut, ft, sign};
408  }
409 
420  lst UF(const ex & props, const ex & ns, const ex & loops, const ex & tloops, const ex & lsubs, const ex & tsubs) {
421  auto ps = props;
422 
423  // handle sign
424  ex sign = 1;
425  for(int i=0; i<ps.nops(); i++) {
426  auto ipr = expand_ex(ps.op(i), loops);
427 
428  if(ipr.has(iEpsilon)) {
429  auto cc = ipr.coeff(iEpsilon);
430  if(is_a<numeric>(cc)) {
431  if(cc<0) { // using +iEpsilon
432  sign *= pow(-1, ns.op(i));
433  ps.let_op(i) = ex(0)-ps.op(i);
434  }
435  ps.let_op(i) = ps.op(i).subs(iEpsilon==0,nopat);
436  goto sign_done;
437  } else throw Error("UF: sign of iEpsilon NOT determined.");
438  }
439 
440  for(auto lp : loops) {
441  if(ipr.degree(lp)==2) {
442  auto cc = ipr.coeff(lp,2);
443  if(is_a<numeric>(cc)) {
444  if(cc<0) { // using +l^2
445  sign *= pow(-1, ns.op(i));
446  ps.let_op(i) = ex(0)-ps.op(i);
447  }
448  goto sign_done;
449  }
450  }
451  }
452 
453  ipr = expand(ipr).subs(lsubs).subs(tsubs);
454  for(auto lp : tloops) {
455  if(ipr.degree(lp)==2) {
456  auto cc = ipr.coeff(lp,2);
457  if(is_a<numeric>(cc)) {
458  if(cc<0) { // using +l^2
459  sign *= pow(-1, ns.op(i));
460  ps.let_op(i) = ex(0)-ps.op(i);
461  }
462  goto sign_done;
463  }
464  }
465  }
466 
467  sign_done: ;
468  }
469 
470  ex ut1, ut2, ft, uf;
471  lst key;
472  lst xs;
473  exmap x2ax;
474  int nxi=0;
475  int nps = ps.nops();
476  ft = 0;
477  for(int i=0; i<nps; i++) {
478  if(is_zero(ns.op(i))) {
479  key.append(0);
480  continue;
481  }
482  key.append(1);
483  if(!is_zero(ns.op(i)-1)) x2ax[x(nxi)] = a(ns.op(i)) * x(nxi);
484  xs.append(x(nxi));
485  ft -= x(nxi) * ps.op(i); // only used when no cache item
486  nxi++;
487  }
488 
489  static map<ex,exmap,ex_is_less> cache_by_prop;
490  exmap & cache = cache_by_prop[lst{ps,loops,tloops}];
491  if(!using_cache || cache.find(key)==cache.end()) { // no cache item
492  ut1 = 1;
493  ft = expand(ft);
494  ft = subs(ft, lsubs);
495  for(int i=0; i<loops.nops(); i++) {
496  auto t2 = ft.coeff(loops.op(i),2);
497  auto t1 = ft.coeff(loops.op(i),1);
498  auto t0 = ft.subs(loops.op(i)==0,nopat);
499  ut1 *= t2;
500  if(is_zero(t2)) return lst{0,0,0,1};
501  ft = exnormal(t0-t1*t1/(4*t2));
502  ft = expand(ft);
503  ft = subs(ft, lsubs);
504  }
505  ft = exnormal(ut1*ft);
506  ft = exnormal(subs(ft, lsubs));
507  ut1 = exnormal(subs(ut1, lsubs));
508 
509  ut2 = 1;
510  ft = expand(ft);
511  ft = subs(ft, tsubs);
512  for(int i=0; i<tloops.nops(); i++) {
513  auto t2 = ft.coeff(tloops.op(i),2);
514  auto t1 = ft.coeff(tloops.op(i),1);
515  auto t0 = ft.subs(tloops.op(i)==0,nopat);
516  ut2 *= t2;
517  if(is_zero(t2)) return lst{0,0,0,1};
518  ft = exnormal(t0-t1*t1/(4*t2));
519  ft = expand(ft);
520  ft = subs(ft, tsubs);
521  }
522  ft = exnormal(ut2*ft);
523  ft = exnormal(subs(ft, tsubs));
524  ut2 = exnormal(subs(ut2, tsubs));
525 
526  uf = exnormal(ut1*ut2*ft);
527  if(using_cache) cache[key] = lst{ut1,ut2,ft,uf};
528  } else {
529  auto cc = cache[key];
530  ut1 = cc.op(0);
531  ut2 = cc.op(1);
532  ft = cc.op(2);
533  uf = cc.op(3);
534  }
535  ut1 = ut1.subs(x2ax,nopat);
536  ut2 = ut2.subs(x2ax,nopat);
537  ft = ft.subs(x2ax,nopat);
538  uf = uf.subs(x2ax,nopat);
539 
540  uf = uf.subs(MapPreSP);
541  auto xmap = SortPermutation(uf,xs);
542  uf = uf.subs(xmap,nopat);
543 
544  // z Permuatations
545  if(tloops.nops()>1) {
546  lst zs;
547  auto nzi = tloops.nops();
548  for(int i=0; i<nzi; i++) zs.append(z(i+1));
549  auto zmap = SortPermutation(uf,zs);
550  for(auto kv : zmap) xmap[kv.first] = kv.second; // add to xmap
551  }
552 
553  ut1 = (ut1.subs(xmap,nopat));
554  ut2 = (ut2.subs(xmap,nopat));
555  ft = (ft.subs(xmap,nopat));
556  return lst{ut1, ut2, ft, sign};
557  }
558 
566  pair<exmap,lst> FindRules(vector<IBP*> fs, bool mi, std::function<lst(const IBP &, const ex &)> uf) {
567  vector<pair<IBP*,ex>> ibp_idx_vec;
568  if(mi) for(auto fi : fs) for(auto item : fi->MIntegral) ibp_idx_vec.push_back(make_pair(fi, item));
569  else for(auto fi : fs) for(auto item : fi->Integral) ibp_idx_vec.push_back(make_pair(fi, F(fi->ProblemNumber,item)));
570 
571  exvector uf_smi_vec = GiNaC_Parallel(ibp_idx_vec.size(), [&ibp_idx_vec,&uf](int idx)->ex {
572  auto p = ibp_idx_vec[idx];
573  const IBP & fi = (*p.first);
574  auto mi = p.second;
575  auto ks = uf(fi,mi.subs(F(w1,w2)==w2));
576  int nk = ks.nops()-1;
577  lst key;
578  for(int i=0; i<nk; i++) key.append(expand(ks.op(i)));
579  lst pi = fi.Propagator;
580  return lst{ key, lst{ pi, ks.op(nk), mi } }; // ks.op(nk) -> the sign
581  }, "FR");
582 
583  map<ex,lst,ex_is_less> group;
584  int ntotal = uf_smi_vec.size();
585  int nLimit = 10000;
586 
587  for(auto item : uf_smi_vec) {
588  group[item.op(0)].append(item.op(1));
589  }
590 
591  exmap rules;
592  lst int_lst;
593  exset pis;
594  if(true) { // single element case
595  exset ks, vs;
596  for(auto g : group) {
597  if(g.second.nops()==1) {
598  ks.insert(g.first);
599  vs.insert(g.second.op(0));
600  }
601  }
602  for(auto vi : vs) {
603  pis.insert(vi.op(0));
604  int_lst.append(vi.op(2));
605  }
606  for(auto ki : ks) group.erase(ki);
607  }
608 
609  while(!group.empty()) {
610  if(pis.size()>0) {
611  exset ks;
612  for(auto g : group) {
613  ex c0, v0;
614  for(auto gi : g.second) {
615  auto itr = pis.find(gi.op(0));
616  if(itr!=pis.end()) {
617  ks.insert(g.first);
618  c0 = gi.op(1);
619  v0 = gi.op(2);
620  goto found;
621  }
622  }
623  continue; // if not found pi
624  found: ;
625  int_lst.append(v0);
626  for(auto gi : g.second) {
627  auto ci = gi.op(1);
628  auto vi = gi.op(2);
629  if(v0.is_equal(vi)) continue;
630  rules[vi] = v0 * c0 / ci;
631  }
632  }
633  for(auto ki : ks) group.erase(ki);
634  if(group.empty()) break;
635  }
636  pis.clear();
637 
638  int cur = 0;
639  for(auto g : group) {
640  cur++;
641  if(cur>10) break;
642  pis.insert(g.second.op(0).op(0));
643  }
644  }
645 
646  if(!In_GiNaC_Parallel && Verbose>2) cout << PRE << "\\--FindRules: " << WHITE << ntotal << " :> " << int_lst.nops() << RESET << " @ " << now(false) << endl;
647  return make_pair(rules,int_lst);
648  }
649 
650  static matrix Redrowech(const matrix & mat) {
651  Fermat &fermat = Fermat::get();
652  int &v_max = fermat.vmax;
653 
654  lst rep_vs;
655  ex tree = mat;
656  for(const_preorder_iterator i = tree.preorder_begin(); i != tree.preorder_end(); ++i) {
657  auto e = (*i);
658  if(is_a<symbol>(e) || e.match(a(w))) rep_vs.append(e);
659  }
660  rep_vs.sort();
661  rep_vs.unique();
662  sort_lst(rep_vs);
663 
664  exmap v2f;
665  symtab st;
666  int fvi = 0;
667  for(auto vi : rep_vs) {
668  auto name = "v" + to_string(fvi);
669  v2f[vi] = Symbol(name);
670  st[name] = vi;
671  fvi++;
672  }
673 
674  stringstream ss;
675  if(fvi>111) {
676  cout << rep_vs << endl;
677  throw Error("Fermat: Too many variables.");
678  }
679  if(fvi>v_max) {
680  for(int i=v_max; i<fvi; i++) ss << "&(J=v" << i << ");" << endl;
681  fermat.Execute(ss.str());
682  ss.clear();
683  ss.str("");
684  v_max = fvi;
685  }
686 
687  int nrow = mat.rows();
688  int ncol = mat.cols();
689 
690  ss << "Array m[" << nrow << "," << ncol << "];" << endl;
691  fermat.Execute(ss.str());
692  ss.clear();
693  ss.str("");
694 
695  ss << "[m]:=[(";
696  for(int c=0; c<ncol; c++) {
697  for(int r=0; r<nrow; r++) {
698  ss << mat(r,c).subs(iEpsilon==0,nopat).subs(v2f,nopat) << ",";
699  }
700  }
701  ss << ")];" << endl;
702  ss << "Redrowech([m]);" << endl;
703  auto tmp = ss.str();
704  string_replace_all(tmp,",)]",")]");
705  fermat.Execute(tmp);
706  ss.clear();
707  ss.str("");
708 
709  ss << "&(U=1);" << endl; // ugly printing, the whitespace matters
710  ss << "![m" << endl;
711  auto ostr = fermat.Execute(ss.str());
712  ss.clear();
713  ss.str("");
714  //fermat.Exit();
715 
716  // note the order, before exfactor (normal_fermat will be called again here)
717  ss << "&(U=0);" << endl; // disable ugly printing
718  ss << "@([m]);" << endl;
719  ss << "&_G;" << endl;
720  fermat.Execute(ss.str());
721  ss.clear();
722  ss.str("");
723 
724  // make sure last char is 0
725  if(ostr[ostr.length()-1]!='0') throw Error("Direc::Export, last char is NOT 0.");
726  ostr = ostr.substr(0, ostr.length()-1);
727  string_trim(ostr);
728 
729  ostr.erase(0, ostr.find(":=")+2);
730  string_replace_all(ostr, "[", "{");
731  string_replace_all(ostr, "]", "}");
732  Parser fp(st);
733  matrix mr(nrow, ncol);
734  auto res = fp.Read(ostr);
735  for(int r=0; r<nrow; r++) {
736  auto cur = res.op(r);
737  for(int c=0; c<ncol; c++) mr(r,c) = cur.op(c);
738  }
739  return mr;
740  }
741 
742  bool IBP::IsZero(ex sector) {
743  auto props = Propagator;
744  lst xs;
745  int nxi=0;
746  int nps = props.nops();
747  ex ft = 0;
748  for(int i=0; i<nps; i++) {
749  if(is_zero(sector.op(i))) continue;
750  xs.append(x(nxi));
751  ft -= x(nxi) * props.op(i);
752  nxi++;
753  }
754 
755  ex ut = 1;
756  ft = normal_flint(ft);
757  ft = subs(ft, Replacement);
758  for(int i=0; i<Internal.nops(); i++) {
759  auto t2 = ft.coeff(Internal.op(i),2);
760  auto t1 = ft.coeff(Internal.op(i),1);
761  auto t0 = ft.subs(Internal.op(i)==0,nopat);
762  ut *= t2;
763  if(is_zero(t2)) return true;
764  ft = normal_flint(t0-t1*t1/(4*t2));
765  //ft = expand(ft);
766  ft = subs(ft, Replacement);
767  }
768  ut = normal_flint(subs(ut, Replacement));
769  ft = normal_flint(ut*ft);
770  ft = normal_flint(subs(ft, Replacement));
771 
772  ex G = ut + ft;
773  ex sum = 0;
774  lst ks;
775  exmap ks20;
776  for(auto xi : xs) {
777  symbol ki;
778  ks.append(ki);
779  ks20[ki] = 0;
780  sum += ki * xi * diff_ex(G,xi);
781  }
782  sum -= G;
783  auto cvs = collect_lst(sum,x(w));
784  int rn = cvs.nops();
785  int cn = ks.nops();
786  matrix mat(rn,cn+1);
787  int ri = 0;
788  for(auto cv : cvs) {
789  int ci = 0;
790  for(auto ki : ks) {
791  mat(ri,ci) = cv.op(0).coeff(ki);
792  ci++;
793  }
794  mat(ri,cn) = cv.op(0).subs(ks20,nopat);
795  ri++;
796  }
797  auto mat2 = Redrowech(mat);
798  for(int ri=rn-1; ri>=0; ri--) {
799  for(int ci=0; ci<cn; ci++) {
800  if(!is_zero(mat2(ri,ci))) return true;
801  }
802  if(!is_zero(mat2(ri,cn))) return false;
803  }
804  return true;
805  }
806 
807  exmap IBP::SP2Pn() { // sp -> {c0,c1,c2,...,cn} coefficient of each propagator, c0 is remaining constant
808  lst InExternal;
809  for(auto ii : Internal) InExternal.append(ii);
810  for(auto ii : External) InExternal.append(ii);
811 
812  if(ISP.nops()<1) {
813  for(auto it : Internal) {
814  for(auto ii : InExternal) ISP.append(it*ii);
815  }
816  ISP.sort();
817  ISP.unique();
818  }
819 
820  int pdim = Propagator.nops();
821  if(ISP.nops() > pdim) {
822  cout << "ISP = " << ISP << endl;
823  cout << "Propagator = " << Propagator << endl;
824  throw Error("IBP::SP2Pn: #(ISP) > #(Propagator).");
825  }
826 
827  lst sp2s, s2sp, ss;
828  int _pic=0;
829  for(auto item : ISP) {
830  _pic++;
831  symbol si("sp"+to_string(_pic));
832  ss.append(si);
833  sp2s.append(w*item==w*si);
834  sp2s.append(item==si);
835  s2sp.append(si==item);
836  }
837 
838  lst eqns;
839  for(int i=0; i<ISP.nops(); i++) { // note NOT pdim
840  auto eq = expand(Propagator.op(i)).subs(iEpsilon==0); // drop iEpsilon
841  eq = eq.subs(sp2s);
842  eq = eq.subs(Replacement);
843  if(eq.has(iWF(w))) throw Error("IBP::SP2Pn, iWF used in eq.");
844  eqns.append(eq == iWF(i));
845  }
846  auto s2p = lsolve(eqns, ss);
847  if(s2p.nops() != ISP.nops()) {
848  cout << ISP << endl << s2p << endl << eqns << endl;
849  throw Error("IBP::SP2Pn: lsolve failed.");
850  }
851 
852  exmap smap;
853  for(auto r : s2p) {
854  ex k = r.op(0).subs(s2sp, nopat);
855  ex v = r.op(1);
856  ex chk = v.subs(iWF(w)==0);
857  lst res;
858  res.append(chk);
859  for(int i=0; i<ISP.nops(); i++) {
860  ex t = v.coeff(iWF(i));
861  res.append(t);
862  chk += t*iWF(i);
863  }
864  if(!normal(chk-v).is_zero()) throw Error("IBP::SP2Pn check failed.");
865  smap[k] = res;
866  }
867  return smap;
868  }
869 
870  exmap IBP::Dinv(const lst & ns) {
871  lst InExternal;
872  for(auto ii : Internal) InExternal.append(ii);
873  for(auto ii : External) InExternal.append(ii);
874  auto & es = External;
875  int eN = es.nops();
876  int pN = Propagator.nops();
877  matrix G(eN, eN);
878  for(int r=0; r<eN; r++) for(int c=0; c<eN; c++) G(r,c) = (es.op(r)*es.op(c)).subs(Replacement);
879  matrix Gi = G.inverse(solve_algo::gauss);
880  // partial J/partial pi^2
881  exmap spmap;
882  auto sp2pn = SP2Pn();
883  for(int p1i=0; p1i<eN; p1i++) {
884  for(int p2i=p1i; p2i<eN; p2i++) {
885  ex p1 = es.op(p1i);
886  ex p2 = es.op(p2i);
887  ex pf = 1;
888  if(p1i==p2i) pf = 1/ex(2);
889  ex res = 0;
890  for(int pi=0; pi<pN; pi++) {
891  lst ns2 = ns;
892  ns2.let_op(pi) = ns.op(pi)+1;
893  ex dpi = -ns.op(pi)*diff_ex(Propagator.op(pi), p1);
894  for(int i=0; i<eN; i++) {
895  ex idpi = expand_ex(dpi*es.op(i)).subs(Replacement);
896  auto cvs = collect_lst(idpi, InExternal);
897  for(auto cv : cvs) {
898  if(is_zero(cv.op(1)-1)) res += cv.op(0)*pf*Gi(i,p2i)*F(ProblemNumber, ns2);
899  else {
900  auto f = sp2pn.find(cv.op(1));
901  if(f==sp2pn.end()) throw Error("IBP::DExt, Not found.");
902  auto cps = f->second;
903  res += cv.op(0)*pf*Gi(i,p2i)*cps.op(0)*F(ProblemNumber, ns2);
904  for(int j=1; j<pN+1; j++) {
905  if(is_zero(cps.op(j))) continue;
906  lst ns3 = ns2;
907  ns3.let_op(j-1) = ns2.op(j-1)-1;
908  res += cv.op(0)*pf*Gi(i,p2i)*cps.op(j)*F(ProblemNumber, ns3);
909  }
910  }
911  }
912  }
913  }
914  spmap[p1*p2] = collect_ex(res,F(w1,w2));
915  }}
916  return spmap;
917  }
918 
919  ex IBP::D(const ex & x, const lst & ns) {
920  lst InExternal;
921  for(auto ii : Internal) InExternal.append(ii);
922  for(auto ii : External) InExternal.append(ii);
923  int pN = Propagator.nops();
924  auto sp2pn = SP2Pn();
925 
926  ex res = 0;
927  for(int pi=0; pi<pN; pi++) { // Direct Diff for each Propagator
928  lst ns2 = ns;
929  ns2.let_op(pi) = ns.op(pi)+1;
930  ex Pi = Propagator.op(pi);
931  Pi = Pi.subs(Replacement);
932  ex dpi = -ns.op(pi)*diff_ex(Pi, x);
933  auto cvs = collect_lst(dpi, InExternal);
934  for(auto cv : cvs) {
935  if(is_zero(cv.op(1)-1)) res += cv.op(0)*F(ProblemNumber, ns2);
936  else {
937  auto f = sp2pn.find(cv.op(1));
938  if(f==sp2pn.end()) throw Error("IBP::DExt, Not found.");
939  auto cps = f->second;
940  res += cv.op(0)*cps.op(0)*F(ProblemNumber, ns2);
941  for(int j=1; j<pN+1; j++) {
942  if(is_zero(cps.op(j))) continue;
943  lst ns3 = ns2;
944  ns3.let_op(j-1) = ns2.op(j-1)-1;
945  res += cv.op(0)*cps.op(j)*F(ProblemNumber, ns3);
946  }
947  }
948  }
949  }
950 
951  // InDirect Diff from external SP
952  auto dsp = Dinv(ns);
953  auto eN = External.nops();
954  for(int i=0; i<eN; i++) {
955  for(int j=i; j<eN; j++) {
956  ex sp = External.op(i) * External.op(j);
957  auto f = dsp.find(sp);
958  if(f==dsp.end()) throw Error("DESS::InitDE, sp NOT found.");
959  auto rsp = sp.subs(Replacement);
960  if(sp==rsp) throw Error("DESS::InitDE, sp==rsp, Replacement NOT work.");
961  res += f->second * diff_ex(rsp, x);
962  }}
963 
964  return res;
965  }
966 
967  void IBP::RM(bool keep_start_config) {
968  string spn = to_string(ProblemNumber);
969  if(!keep_start_config) {
970  file_remove(WorkingDir+"/"+spn+".start");
971  file_remove(WorkingDir+"/"+spn+".config");
972  }
973  file_remove(WorkingDir+"/"+spn+".intg");
974  file_remove(WorkingDir+"/"+spn+".tables");
975  }
976 
977  void IBP::rm(const string & pat) {
978  string spn = to_string(ProblemNumber);
979  string fn = WorkingDir+"/"+spn+pat;
980  if(file_exists(fn)) file_remove(fn);
981  }
982 
983 
984  ex GPolynomial(const IBP & ibp) {
985 
986  auto props = ibp.Propagator;
987  ex ut, ft, uf;
988  lst key;
989  lst xs;
990  exmap x2ax;
991  int nxi=0;
992  int nps = props.nops();
993  ft = 0;
994  for(int i=0; i<nps; i++) {
995  xs.append(x(nxi));
996  ft -= x(nxi) * props.op(i); // only used when no cache item
997  nxi++;
998  }
999 
1000  ut = 1;
1001  ft = expand_ex(ft);
1002  ft = subs(ft, ibp.Replacement);
1003  for(int i=0; i<ibp.Internal.nops(); i++) {
1004  auto t2 = ft.coeff(ibp.Internal.op(i),2);
1005  auto t1 = ft.coeff(ibp.Internal.op(i),1);
1006  auto t0 = ft.subs(ibp.Internal.op(i)==0,nopat);
1007  ut *= t2;
1008  if(is_zero(t2)) return lst{0,0,1};
1009  ft = exnormal(t0-t1*t1/(4*t2));
1010  ft = expand_ex(ft);
1011  ft = subs(ft, ibp.Replacement);
1012  }
1013  ft = exnormal(ut*ft);
1014  ft = exnormal(subs(ft, ibp.Replacement));
1015  ut = exnormal(subs(ut, ibp.Replacement));
1016  uf = exnormal(ut+ft); // ut*ft, replay with ut+ft
1017 
1018  uf = uf.subs(MapPreSP);
1019  return uf;
1020  }
1021 
1022  void GPermutation(const ex & uf, const lst & xs) {
1023  auto expr = collect_ex(uf, xs);
1024  map<ex,vector<ex>,ex_is_less> pgrp;
1025 
1026  if(true) { // only for polynomials
1027  auto cv_lst = collect_lst(expr, xs);
1028  exvector cvs;
1029  for(auto item : cv_lst) cvs.push_back(item);
1030  sort_vec(cvs); // first sort by coefficient
1031 
1032  int nxi = xs.nops();
1033  bool first = true;
1034  lst xkey[nxi];
1035  lst subkey[nxi];
1036  ex clast;
1037  for(auto cv : cvs) {
1038  ex cc = cv.op(0);
1039  ex vv = cv.op(1);
1040  if(is_zero(cc)) continue;
1041  if(!first && !is_zero(cc-clast)) { // equal coefficient to the same key
1042  for(int i=0; i<nxi; i++) {
1043  sort_lst(subkey[i]);
1044  for(auto item : subkey[i]) xkey[i].append(item);
1045  subkey[i].remove_all();
1046  }
1047  }
1048  first = false;
1049  clast = cc;
1050  for(int i=0; i<nxi; i++) subkey[i].append(vv.degree(xs.op(i)));
1051  }
1052 
1053  for(int i=0; i<nxi; i++) { // add last subkey
1054  sort_lst(subkey[i]); // need sort due to equal coefficient
1055  for(auto item : subkey[i]) xkey[i].append(item);
1056  subkey[i].remove_all();
1057  }
1058 
1059  exvector key_xi;
1060  for(int i=0; i<nxi; i++) key_xi.push_back(lst{xkey[i], xs.op(i)});
1061  sort_vec(key_xi); // first sort by key
1062 
1063  for(int i=0; i<nxi; i++) {
1064  auto xi = key_xi[i].op(1);
1065  auto xki = key_xi[i].op(0);
1066  pgrp[xki].push_back(xi);
1067  }
1068  }
1069 
1070  // pgrp - needs to permuation explicitly
1071  long long npt = 1;
1072  for(auto pi : pgrp) {
1073  int nvi = pi.second.size();
1074  for(int i=1; i<=nvi; i++) npt *= i; // nvi!
1075  }
1076  for(long long np=0; np<npt; np++) {
1077  long long npc = np;
1078  exmap xmap_tmp;
1079  for(auto pi : pgrp) {
1080  auto vi = pi.second;
1081  int nvi = vi.size();
1082  if(nvi<2) continue;
1083  long long npti = 1;
1084  for(int i=1; i<=nvi; i++) npti *= i; // nvi!
1085  int ck = npc % npti; // kth permutation
1086  npc = npc / npti;
1087 
1088  // https://stackoverflow.com/questions/1995328/are-there-any-better-methods-to-do-permutation-of-string
1089  auto vip = vi;
1090  int k = ck;
1091  for(int j=1; j<nvi; ++j) { // startoverflow: j starts from 1
1092  std::swap(vip[k%(j+1)], vip[j]);
1093  k=k/(j+1);
1094  }
1095 
1096  for(int j=0; j<nvi; j++) if(vi[j]!=vip[j]) xmap_tmp[vi[j]] = vip[j];
1097  }
1098  if(xmap_tmp.size()>0) {
1099  ex expr_tmp = expr.subs(xmap_tmp,nopat);
1100  if(is_zero(expr-expr_tmp)) {
1101  auto xs_tmp = xs.subs(xmap_tmp,nopat);
1102  cout << xs_tmp << endl;
1103  }
1104  }
1105  }
1106 
1107  }
1108 
1109 }
int * a
Definition: Functions.cpp:234
#define WHITE
Definition: BASIC.h:87
#define RESET
Definition: BASIC.h:79
IBP header file.
bool file_exists(const char *fn)
Definition: Process.cpp:9
class used to wrap error message
Definition: BASIC.h:242
IBP base class for IBP reduction.
Definition: IBP.h:24
lst Internal
Definition: IBP.h:27
lst MIntegral
Definition: IBP.h:42
map< int, ex > Shift
Definition: IBP.h:36
lst PIntegral
Definition: IBP.h:40
lst ISP
Definition: IBP.h:34
lst Replacement
Definition: IBP.h:29
virtual void Export()
Definition: IBP.h:46
void Reduce()
ex TO()
Definition: IBP.cpp:60
lst DSP
Definition: IBP.h:33
bool reCut
Definition: IBP.h:37
void garImport(string garfn)
Definition: IBP.cpp:67
void FROM(ex s)
Definition: IBP.cpp:98
lst Cut
Definition: IBP.h:32
pair< exmap, lst > FindRules(bool mi=true)
Definition: IBP.cpp:169
lst External
Definition: IBP.h:28
lst Propagator
Definition: IBP.h:30
bool IsAlwaysZero
Definition: IBP.h:44
int ProblemNumber
Definition: IBP.h:39
virtual void Import()
Definition: IBP.h:48
void garExport(string garfn)
Definition: IBP.cpp:28
string WorkingDir
Definition: IBP.h:38
virtual void Run()
Definition: IBP.h:47
static void ReShare(const vector< IBP * > &fs)
Definition: IBP.cpp:119
lst Rules
Definition: IBP.h:43
lst SECTOR
Definition: IBP.h:35
class extended to GiNaC symbol class, represent a positive symbol
Definition: BASIC.h:113
do_not_evalf_params().expl_derivative_func(zd1D).derivative_func(zp1D)) REGISTER_FUNCTION(FTX
HepLib namespace.
Definition: BASIC.cpp:17
ex expand_ex(ex const &expr_in, std::function< bool(const ex &)> has_func)
the expand like Mathematica
Definition: BASIC.cpp:1188
bool ex_less(const ex &a, const ex &b)
Definition: Sort.cpp:10
const iSymbol iEpsilon
ex sp(const ex &a, const ex &b)
translated the vector dot a.b to a*b, useful in SecDec
Definition: Pair.cpp:237
void GPermutation(const ex &uf, const lst &xs)
Definition: IBP.cpp:1022
ex GPolynomial(const IBP &ibp)
Definition: IBP.cpp:984
exmap MapPreSP
Definition: Init.cpp:335
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
lst LoopUF(const IBP &ibp, const ex &idx)
UF function.
Definition: IBP.cpp:310
pair< exmap, lst > FindRules(vector< IBP * > fs, bool mi, std::function< lst(const IBP &, const ex &)> uf)
Find Rules for Integral or Master Integral.
Definition: IBP.cpp:566
lst UF(const ex &props, const ex &ns, const ex &loops, const ex &tloops, const ex &lsubs, const ex &tsubs)
UF function, from FIRE.m.
Definition: IBP.cpp:420
REGISTER_FUNCTION(Matrix, do_not_evalf_params().print_func< FCFormat >(&Matrix_fc_print).conjugate_func(mat_conj).set_return_type(return_types::commutative)) bool IsZero(const ex &e)
Definition: Basic.cpp:715
bool using_cache
Definition: Init.cpp:153
string now(bool use_date)
date/time string
Definition: BASIC.cpp:525
ex w
Definition: Init.cpp:90
const Symbol vs
exmap SortPermutation(const ex &in_expr, const lst &xs)
Sort for all permuations, and return xs w.r.t. 1st permutation.
Definition: IBP.cpp:196
ex exnormal(const ex &expr, int opt)
normalize a expression
Definition: BASIC.cpp:1906
ex normal_flint(const ex &expr, int opt=o_flint)
bool In_GiNaC_Parallel
Definition: Init.cpp:142
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
void sort_vec(exvector &ivec, bool less=true)
sort the list in less order, or the reverse
Definition: Sort.cpp:54
ex diff_ex(ex const expr, ex const xp, unsigned nth, bool expand)
the differential like Mathematica
Definition: BASIC.cpp:1063
int Verbose
Definition: Init.cpp:139
void sort_lst(lst &ilst, bool less=true)
sort the list in less order, or the reverse
Definition: Sort.cpp:79
bool file_remove(string fn)
Definition: BASIC.h:285
void string_replace_all(string &str, const string &from, const string &to)
Definition: Functions.cpp:148
bool IsZero(const ex &e)
long long cache_limit
Definition: Init.cpp:154
ex w1
Definition: BASIC.h:499
unsigned nopat
Definition: Init.cpp:88
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)
Definition: Functions.cpp:156
string PRE
Definition: Init.cpp:140
ex subs(const ex &e, init_list sl)
Definition: BASIC.h:51