HepLib
AsyMB.cpp
Go to the documentation of this file.
1 
6 #include "SD.h"
7 #include <math.h>
8 #include <cmath>
9 
10 namespace HepLib::SD {
11 
17  int SecDec::PRank(matrix m) {
18  int nr = m.rows();
19  int nc = m.cols();
20  int pr = 0;
21  if(nr>1) {
22  matrix pr_mat(nr, nc);
23  for(int ic=0; ic<nc; ic++) {
24  for(int ir=0; ir<nr; ir++) {
25  pr_mat(ir,ic) = m(ir,ic)-m(0,ic);
26  }
27  }
28  pr = pr_mat.rank();
29  }
30  return pr;
31  }
32 
39  ex SecDec::PExpand(ex xpol, bool delta) {
40  lst nlst;
41  ex pol = collect_common_factors(xpol.expand());
42  if(is_a<mul>(pol)) {
43  ex tmp = 1;
44  for(int i=0; i<pol.nops(); i++) {
45  if(is_a<numeric>(pol.op(i))) continue;
46  if(pol.op(i).match(x(w))) continue;
47  if(pol.op(i).match(pow(x(w1),w2))) continue;
48  if(pol.op(i).match(pow(y(w1),w2))) continue;
49  if(pol.op(i).match(pow(vs,w))) continue;
50  tmp *= pol.op(i);
51  }
52  pol = tmp;
53  }
54  pol = pol.expand();
55  auto xs = get_xy_from(pol);
56  int nx = xs.size();
57  int id = delta ? nx-1 : nx;
58 
59  lst lxs;
60  for(auto item : xs) lxs.append(item);
61  lxs.append(vs);
62  pol = pol.expand().collect(lxs, true);
63  int np = is_a<add>(pol) ? pol.nops() : 1;
64  matrix rs_mat(np, nx+1);
65 
66  for(int n=0; n<np; n++) {
67  ex tmp = pol.op(n);
68  rs_mat(n,0) = tmp.degree(vs);
69  for(int ix=0; ix<nx; ix++) {
70  rs_mat(n, ix+1) = collect_ex(tmp, xs[ix]).degree(xs[ix]);
71  }
72  }
73 
74  int pr = PRank(rs_mat);
75  if(pr-1 != id) return nlst;
76 
77  matrix rp_mat(np, id+1);
78  for(int n=0; n<np; n++) {
79  for(int ix=0; ix<id+1; ix++) {
80  rp_mat(n,ix) = rs_mat(n,ix);
81  }
82  }
83  int rp = PRank(rp_mat);
84 
85  if(pr != rp) {
86  cout << "pr=" << pr << ", rp=" << rp << endl;
87  throw Error("PExpand: projection method does not work.");
88  }
89 
90  auto fs = SecDecG::RunQHull(rp_mat);
91  lst vs, ret;
92  for(int i=0; i<id+1; i++) {
93  symbol v;
94  vs.append(v);
95  }
96  auto vv = vs.op(id);
97  for(auto fi : fs) {
98  lst eqns;
99  for(auto pi : fi) {
100  ex eqn = rs_mat(pi,0);
101  for(int i=0; i<id; i++) {
102  eqn += vs.op(i) * rs_mat(pi,i+1);
103  }
104  eqns.append(eqn==vv);
105  }
106  auto lss = lsolve(eqns, vs);
107  if(lss.nops()>1) {
108  bool bf = true;
109  auto vs2 = subs(vs,lss);
110  for(int r=0; r<np; r++) {
111  ex eqn = rs_mat(r,0);
112  for(int i=0; i<id; i++) {
113  eqn += vs2.op(i) * rs_mat(r,i+1);
114  }
115  ex chk = eqn-vs2.op(id);
116  if(!is_a<numeric>(chk)) {
117  cerr << ErrColor << "chk is NOT a number: " << chk << RESET << endl;
118  throw Error("PExpand: chk is NOT a number.");
119  }
120  if(chk<0) {
121  bf = false;
122  break;
123  }
124  }
125  if(bf) {
126  vs2.let_op(id) = 0;
127  ex min = vs2.op(0);
128  for(auto vsi : vs2) {
129  if(vsi<min) min = vsi;
130  }
131  for(int i=0; i<vs2.nops(); i++) vs2.let_op(i) = vs2.op(i)-min;
132  ret.append(vs2);
133  }
134  }
135  }
136 
137  lst lxs2;
138  for(auto item : xs) lxs2.append(item);
139  ret.prepend(lxs2);
140  return ret;
141  }
142 
146  void SecDec::DoAsy() {
147 
148  while(true) {
149  exvector funexp;
150  for(auto fe : FunExp) {
151  funexp.push_back(fe);
152  }
153  FunExp.clear();
154  FunExp.shrink_to_fit();
155 
156  bool ret = false;
157  for(auto fe : funexp) {
158  if(fe.nops()<=2) {
159  cerr << ErrColor << "needs 3 elements: " << fe << RESET << endl;
160  throw Error("DoAsy: we needs 3 elements.");
161  }
162  ex ft = fe.op(0).op(1).subs(vs==0);
163  ex eqn;
164  bool ok2 = true;
165  auto xs = get_x_from(ft);
166  for(int i=0; i<xs.size(); i++) { // keep only 2 xi's
167  for(int j=i+1; j<xs.size(); j++) { // keep only 2 xi's
168  bool delta_ij = false;
169  for(int di=0; di<fe.op(2).nops(); di++) {
170  if(fe.op(2).op(di).has(xs[i]) && fe.op(2).op(di).has(xs[j])) {
171  delta_ij = true;
172  break;
173  }
174  }
175  if(!delta_ij) continue;
176 
177  symbol xi("xi"), xj("xj");
178  auto ftt = ft.subs(lst{xs[i]==xi, xs[j]==xj});
179  ftt = Factor(ftt);
180  lst fts2;
181  if(is_a<mul>(ftt)) {
182  for(auto item : ftt) fts2.append(item);
183  } else {
184  fts2.append(ftt);
185  }
186  lst tmp_lst;
187  for(auto item : fts2) {
188  auto tmp = Factor(item.subs(x(w)==0));
189  if(is_a<mul>(tmp)) {
190  for(auto it : tmp) tmp_lst.append(it);
191  } else {
192  tmp_lst.append(tmp);
193  }
194  }
195  fts2 = tmp_lst;
196 
197  for(auto item : fts2) {
198  auto tmp = item;
199  if(item.match(pow(w1,w2))) tmp = item.op(0);
200  if(tmp.degree(xi)==1 && tmp.degree(xj)==1) {
201  ex ci = tmp.coeff(xi);
202  ex cj = tmp.coeff(xj);
203  if((ci*xi+cj*xj-tmp).is_zero() && is_a<numeric>(ci*cj) && (ci*cj)<0) {
204  eqn = tmp.subs(lst{xi==xs[i], xj==xs[j]});
205  ok2 = false;
206  goto OK2;
207  }
208  }
209  }
210  }
211  }
212 
213  OK2:
214  if(!ok2) {
215  auto xij = get_x_from(eqn);
216  ex xi = xij[0];
217  ex xj = xij[1];
218 
219  ex ci = eqn.coeff(xi);
220  ex cj = eqn.coeff(xj);
221 
222  // handle eqn==ci xi - cj xj
223  ret = true;
224  ci = abs(ci);
225  cj = abs(cj);
226  symbol yi,yj;
227  // Part I: ci xi-cj xj>0, i.e., xi>cj/ci xj
228  auto f1 = ex_to<lst>(fe.op(0));
229  auto e1 = ex_to<lst>(fe.op(1));
230  ex c1 = cj/ci;
231  for(int i=0; i<f1.nops(); i++) {
232  f1.let_op(i) = f1.op(i).subs(lst{xi==c1*yj/(1+c1)+yi,xj==yj/(1+c1)}).subs(lst{yi==xi,yj==xj});
233  }
234  if(e1.op(0)==1) f1.let_op(0) = f1.op(0)/(1+c1); // Jaccobi
235  else if(e1.op(1)==1) f1.let_op(1) = f1.op(1)/(1+c1);
236  else {
237  f1.append(1/(1+c1));
238  e1.append(1);
239  }
240 
241  FunExp.push_back(lst{f1,e1,fe.op(2)});
242  // Part II: ci xi-cj xj<0, i.e., i.e., xj>ci/cj xi
243  auto f2 = ex_to<lst>(fe.op(0));
244  auto e2 = ex_to<lst>(fe.op(1));
245  ex c2 = ci/cj;
246  for(int i=0; i<f2.nops(); i++) {
247  f2.let_op(i) = f2.op(i).subs(lst{xj==c2*yi/(1+c2)+yj,xi==yi/(1+c2)}).subs(lst{yi==xi,yj==xj});
248  }
249  if(e2.op(0)==1) f2.let_op(0) = f2.op(0)/(1+c2); // Jaccobi
250  else if(e2.op(1)==1) f2.let_op(1) = f2.op(1)/(1+c2);
251  else {
252  f2.append(1/(1+c2));
253  e2.append(1);
254  }
255  FunExp.push_back(lst{f2,e2,fe.op(2)});
256  } else {
257  FunExp.push_back(fe);
258  }
259  }
260  if(!ret) break;
261  }
262 
263 
264  for(auto fe : FunExp) {
265  ex expn = 0;
266  symbol s;
267  for(int i=0; i<fe.op(0).nops(); i++) {
268  auto item = fe.op(0).op(i).subs(x(w)==s*y(w)).subs(y(w)==x(w));
269  if(!item.has(s)) continue;
270  item = collect_ex(item, s);
271  if(item.ldegree(s)!=item.degree(s)) {
272  cerr << ErrColor << "Not Homogeneous: " << s << RESET << endl;
273  throw Error("DoAsy: Not Homogeneous");
274  }
275  expn += item.degree(s) * fe.op(1).op(i);
276  }
277  auto xsize = get_x_from(fe.op(0)).size();
278  if(!normal(expn+xsize).is_zero()) {
279  cout << ErrColor << "expn=" << expn << ", xsize=" << xsize << RESET << endl;
280  throw Error("DoAsy: expn + xsize != 0.");
281  }
282  }
283 
284 
285  auto fes = FunExp;
286  FunExp.clear();
287  FunExp.shrink_to_fit();
288 
289  for(auto fe : fes) {
290  ex xpol = 1;
291  lst uf;
292  for(int i=0; i<fe.op(0).nops(); i++) {
293  if(fe.op(1).op(i).info(info_flags::nonnegint)) continue;
294  uf.append(fe.op(0).op(i));
295  }
296  uf.sort();
297  uf.unique();
298  //sort_lst(uf);
299  for(auto item : uf) xpol *= item;
300  if(!xpol.has(vs)) {
301  FunExp.push_back(fe);
302  continue;
303  }
304 
305  bool has_delta = true;
306  auto rs = PExpand(xpol, has_delta);
307  if(rs.nops()<1) {
308  throw Error("PExpand returned with nothing, even without hard region!");
309  }
310  if(Verbose>10) {
311  cout << PRE << "\\--Asy Regions:" << (rs.nops()-1) << endl;
312  if(rs.nops()>1) {
313  for(auto ri : rs) cout << " " << ri << endl;
314  }
315  }
316 
317  auto r0 = rs.op(0);
318  auto r0y = subs(r0,x(w)==y(w));
319  for(int i=1; i<rs.nops(); i++) {
320  lst srepl;
321  auto ri = rs.op(i);
322  ex vs_pow = 0;
323  for(int j=0; j<r0.nops(); j++) {
324  srepl.append(r0.op(j)==r0y.op(j) * pow(vs, ri.op(j)));
325  vs_pow += ri.op(j);
326  }
327 
328  auto fs = subs(fe.op(0), srepl);
329  fs = subs(fs, y(w)==x(w));
330  auto es = fe.op(1);
331  ex fpre = fs.op(0);
332  if(!(es.op(0)-1).is_zero()) {
333  cerr << ErrColor << "op(0) is Not 1: " << es << RESET << endl;
334  throw Error("DoAsy: op(0) is Not 1");
335  }
336 
337  lst fs2, es2;
338  for(int j=1; j<fs.nops(); j++) {
339  auto fj = fs.op(j);
340  auto tmp = fj.expand();
341  auto vsp = 0;
342  try {
343  vsp = tmp.ldegree(vs);
344  } catch(exception &e) {
345  cout << e.what() << endl;
346  throw Error("DoAsy: non-integer exponent.");
347  }
348  vs_pow += vsp * es.op(j);
349  tmp = collect_common_factors(tmp)/pow(vs,vsp);
350  fs2.append(tmp);
351  es2.append(es.op(j));
352  }
353  exmap eps_map;
354  for(auto epi : eps_lst) eps_map[epi.op(0)] = 0;
355 
356  auto vsn0 = vsRank(fpre); // maybe need to expand ep/eps first
357  auto vsn = vsn0 + vs_pow.subs(eps_map);
358  int di=0;
359  lst fss, ess;
360  fss.append(fs2);
361  ess.append(es2);
362  while(di<=vsN-vsn) { // fss, ess will get updated
363  lst fss2, ess2;
364  for(int ife=0; ife<fss.nops(); ife++) {
365  lst fs3 = ex_to<lst>(fss.op(ife));
366  lst es3 = ex_to<lst>(ess.op(ife));
367  if(di<vsN-vsn) {
368  for(int ii=0; ii<fs3.nops(); ii++) {
369  lst fs4 = fs3;
370  lst es4 = es3;
371  auto dit = diff_ex(fs4.op(ii),vs);
372  if(!dit.is_zero()) {
373  if((es4.op(ii)-1).is_zero()) {
374  fs4.let_op(ii) = dit;
375  } else {
376  fs4.append(es4.op(ii)*dit);
377  es4.let_op(ii) = es4.op(ii)-1;
378  es4.append(1);
379  }
380  fss2.append(fs4);
381  ess2.append(es4);
382  }
383  }
384  }
385  fs3 = ex_to<lst>(subs(fs3,vs==0));
386  fs3.prepend(fpre/factorial(di) * pow(vs,di+vs_pow));
387  es3.prepend(1);
388  FunExp.push_back(lst{fs3,es3,fe.op(2)});
389  }
390  fss = fss2;
391  ess = ess2;
392  di++;
393  }
394  }
395  }
396  }
397 
401  void SecDec::MB() {
402  for(auto &fe : FunExp) {
403  if(fe.has(vz) || !fe.has(vs)) continue; // 2nd entrance
404 
405  // check epz
406  if(fe.has(epz)) {
407  cout << ErrColor << "MB: epz found at fe = " << fe << RESET << endl;
408  throw Error("MB: epz found at fe.");
409  }
410 
411  exmap eps_map;
412  ex epn = ex(1)/111;
413  for(auto epi : eps_lst) {
414  eps_map[epi.op(0)] = epn;
415  epn = epn / 13;
416  }
417 
418  // check variables besides x or PL
419  // CV should only appear at kv.op(0).op(0), i.e., the prefactor
420  for(int i=2; i<fe.op(0).nops(); i++) {
421  // make sure only Constant/F terms can contain small variable: vs
422  if(i!=1 && fe.op(0).op(i).has(vz)) {
423  cout << "vz Found @ " << i << " of " << fe.op(0) << endl;
424  throw Error("MB: vz Found.");
425  }
426 
427  auto tmp = fe.op(0).op(i).subs(lst{WRA(w)==0,x(w)==1,PL(w)==1}).subs(eps_map);
428  if(!is_a<numeric>(NN(tmp,20))) {
429  cout << ErrColor << tmp << RESET << endl;
430  cout << fe.op(0) << endl;
431  throw Error("MB: Extra Variable(^[ep,eps,PL,x]) Found.");
432  }
433  }
434 
435  ex ft = fe.op(0).op(1);
436  if(ft.has(vs)) {
437  ft = collect_ex(ft, vs);
438  if(!ft.is_polynomial(vs) || (ft.degree(vs)-1)!=0) {
439  cout << ErrColor << "Not supported F-term with s: " << ft << RESET << endl;
440  throw Error("MB: Not supported F-term with s.");
441  }
442  ex expn = ex(0)-fe.op(1).op(1);
443  // (2*Pi*I) dropped out, since we will take residue later.
444  fe.let_op(0).let_op(0) = fe.op(0).op(0) * tgamma(expn+vz)*tgamma(ex(0)-vz)/tgamma(expn)*pow(vs,vz);
445  ex w1 = ft.coeff(vs);
446  ex w2 = ft.subs(vs==0);
447  if(!w2.is_zero()) {
448  if(xPositive(w1)) {
449  let_op_append(fe, 0, w1);
450  let_op_append(fe, 1, vz);
451  fe.let_op(0).let_op(1) = w2;
452  fe.let_op(1).let_op(1) = fe.op(1).op(1)-vz-epz;
453  } else if(xPositive(w2)) {
454  let_op_append(fe, 0, w2);
455  let_op_append(fe, 1, fe.op(1).op(1)-vz-epz);
456  fe.let_op(0).let_op(1) = w1;
457  fe.let_op(1).let_op(1) = vz;
458  } else if(xPositive(ex(0)-w1)) {
459  let_op_append(fe, 0, ex(0)-w1);
460  let_op_append(fe, 1, vz);
461  let_op_append(fe, 0, exp(-I*Pi*vz));
462  let_op_append(fe, 1, 1);
463  fe.let_op(0).let_op(1) = w2;
464  fe.let_op(1).let_op(1) = fe.op(1).op(1)-vz-epz;
465  } else if(xPositive(ex(0)-w2)) {
466  let_op_append(fe, 0, ex(0)-w2);
467  let_op_append(fe, 1, fe.op(1).op(1)-vz-epz);
468  let_op_append(fe, 0, exp(-I*Pi*(fe.op(1).op(1)-vz-epz)));
469  let_op_append(fe, 1, 1);
470  fe.let_op(0).let_op(1) = w1;
471  fe.let_op(1).let_op(1) = vz;
472  } else {
473  cout << "w1=" << w1 << endl;
474  cout << "w2=" << w2 << endl;
475  throw Error("MB: Neither w1 nor w2 is xPositive.");
476  }
477  }
478  }
479  }
480  }
481 
482 
483 }
#define RESET
Definition: BASIC.h:79
SecDec header file.
class used to wrap error message
Definition: BASIC.h:242
static vector< vector< int > > RunQHull(const matrix &pts)
Definition: SecDecG.cpp:176
static ex PExpand(ex xpol, bool delta=true)
PExpand from asy2.1.1.m.
Definition: AsyMB.cpp:39
static int PRank(matrix m)
PRank from FIESTA.
Definition: AsyMB.cpp:17
void MB()
MB.
Definition: AsyMB.cpp:401
exvector FunExp
Definition: SD.h:426
namespace for Numerical integration with Sector Decomposition method
Definition: AsyMB.cpp:10
exvector get_xy_from(ex pol)
Definition: Helpers.cpp:14
int vsRank(ex expr_in)
Definition: Helpers.cpp:211
exvector get_x_from(ex pol)
Definition: Helpers.cpp:29
ex Factor(const ex expr_in)
Definition: Helpers.cpp:244
bool xPositive(ex const expr)
check the expr is xPositive, i.e., each x-monomial item is postive
Definition: BASIC.cpp:1290
ex NN(ex expr, int digits)
the nuerical evaluation
Definition: BASIC.cpp:1278
const char * ErrColor
Definition: BASIC.cpp:246
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
ex w
Definition: Init.cpp:90
const Symbol vs
const Symbol epz
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 let_op_append(ex &ex_in, const ex item)
append item into expression
Definition: BASIC.cpp:1324
ex w1
Definition: BASIC.h:499
ex w2
Definition: BASIC.h:499
const Symbol vz
string PRE
Definition: Init.cpp:140
ex subs(const ex &e, init_list sl)
Definition: BASIC.h:51