HepLib
Loading...
Searching...
No Matches
SecDec.cpp
Go to the documentation of this file.
1
6#include "SD.h"
7#include <math.h>
8#include <cmath>
9#include<algorithm>
10
11namespace HepLib::SD {
12
18 ex SecDecBase::XMonomials(const ex & expr_in) {
19 auto expr = expr_in;
20 auto xs = get_x_from(expr);
21 auto nx = xs.size();
22 if(nx<1) return expr;
23 if(!is_polynomial(expr, vec2lst(xs))) return expr;
24 auto cvs = collect_lst(expr,x(w));
25 vector<exvector> degs_vec;
26 for(auto cv : cvs) {
27 if(is_zero(cv.op(0))) continue;
28 exvector degs;
29 for(auto xi : xs) degs.push_back(cv.op(1).degree(xi));
30 degs_vec.push_back(degs);
31 }
32
33 map<int,bool> flag;
34 auto nn = degs_vec.size();
35
36 for(int i=0; i<nn; i++) flag[i] = true;
37 try {
38 matrix mat(nn,nx);
39 for(int ri=0; ri<nn; ri++) for(int ci=0; ci<nx; ci++) mat(ri,ci) = degs_vec[ri][ci];
40 auto vvi = SecDecG::RunQHull(mat);
41 for(auto vi : vvi) for(auto ii : vi) flag[ii] = false;
42 } catch(...) {
43 for(int i=0; i<nn; i++) flag[i] = false;
44 }
45
46 for(int i=0; i<nn; i++) {
47 if(flag[i]) continue;
48 exvector & ti = degs_vec[i];
49 for(int j=i+1; j<nn; j++) {
50 if(flag[j]) continue;
51 exvector & tj = degs_vec[j];
52 int comp = 0;
53 for(int c=0; c<nx; c++) {
54 if(ti[c]<tj[c]) {
55 if(comp>0) { comp=0; break; }
56 comp = -1;
57 } else if(ti[c]>tj[c]) {
58 if(comp<0) { comp=0; break; }
59 comp = 1;
60 }
61 }
62 if(comp>0) {
63 flag[i]=true;
64 break;
65 } else if(comp<0) {
66 flag[j]=true;
67 }
68 }
69 }
70
71 ex ret = 0;
72 for(int i=0; i<nn; i++) {
73 if(flag[i]) continue;
74 ex res = 1;
75 for(int c=0; c<nx; c++) res *= pow(xs[c],degs_vec[i][c]);
76 ret += res;
77 }
78
79 return ret;
80 }
81
88 bool SecDecBase::VerifySD(vector<exmap> map_vec, bool quick) {
89 lst xs;
90 exmap nxs;
91 for(auto kv : map_vec[0]) {
92 auto xi = kv.first;
93 if(is_zero(xi-x(-1))) continue;
94 xs.append(xi);
95 if(quick) nxs[xi] = xi.subs(x(w)==ex(w+1)/ex(w+13));
96 else nxs[xi];
97 }
98 ex chk_total = 1;
99 for(auto xi : xs) chk_total *= 1/(nxs[xi]+1);
100
101 ex int_total = 0;
102 for(auto imap : map_vec) {
103 ex intg = 1;
104 for(auto kv : imap) {
105 auto xi = kv.first;
106 auto nxi = kv.first.subs(x(w)==(13+w));
107 if(is_zero(xi-x(-1))) intg *= kv.second;
108 else intg *= pow(kv.second, nxs[kv.first]);
109 }
110 while(true) {
111 auto tmp = intg;
112 tmp = tmp.subs(w0*pow(w1*w2,w3)==w0*pow(w1,w3)*pow(w2,w3));
113 tmp = xyz_pow_simplify(tmp);
114 if(is_zero(tmp-intg)) break;
115 intg = tmp;
116 }
117 intg = intg.subs(pow(y(w1),w2)==1/(w2+1)).subs(y(w)==1/ex(2));
118 int_total += intg;
119 }
120 int_total = int_total.normal();
121 return normal(chk_total-int_total).is_zero();
122 }
123 bool SecDec::VerifySD(vector<exmap> map_vec, bool quick) {
124 return SecDecBase::VerifySD(map_vec, quick);
125 }
126
132 vector<exmap> SecDecBase::x2y(const lst & in_xpols) {
133 if(in_xpols.has(y(w))) throw Error("SecDecBase::x2y: y(w) found @ " + ex2str(in_xpols));
134 lst xpols_lst = in_xpols;
135 while(true) {
136 ex xpols = 1;
137 for(auto item : xpols_lst) {
138 if(item.match(x(w))) continue;
139 else if(item.match(pow(x(w1),w2))) continue;
140 else if(item.match(pow(w1,w2))) item = item.op(0);
141 //xpols *= factor_form(item, false);
142 xpols *= exfactor(item);
143 }
144 if(!is_a<mul>(xpols)) xpols = lst{ xpols };
145
146 xpols_lst.remove_all();
147 for(auto item : xpols) {
148 if(item.match(x(w))) continue;
149 else if(item.match(pow(x(w1),w2))) continue;
150 else if(item.match(pow(w1,w2))) xpols_lst.append(item.op(0));
151 else xpols_lst.append(item);
152 }
153 xpols_lst.sort();
154 xpols_lst.unique();
155
156 ex xpols2 = 1;
157 for(auto item : xpols_lst) xpols2 *= item;
158 if(is_a<lst>(xpols)) xpols = xpols.op(0);
159 if(is_zero(xpols2-xpols)) {
160 if(use_XMonomials) xpols = XMonomials(xpols);
161 return x2y(xpols);
162 }
163 }
164 throw Error("SecDecBase::x2y: unexpected region reached.");
165 return vector<exmap>();
166 }
167
174 bool SecDec::IsBad(ex f, vector<exmap> vmap) {
175 for(auto &vi : vmap) {
176 auto ft = f.subs(vi);
177 auto xs_tmp = get_x_from(ft);
178 auto ys_tmp = get_y_from(ft);
179 int ysn = ys_tmp.size();
180 vector<int> y_free_indexs;
181 for(int j=0; j<ys_tmp.size()+10; j++) {
182 if(!ft.has(y(j))) y_free_indexs.push_back(j);
183 }
184 if(xs_tmp.size()>y_free_indexs.size()) throw Error("IsBad: xsize>ysize");
185 for(int i=0; i<xs_tmp.size(); i++) {
186 vi[xs_tmp[i]] = y(y_free_indexs[i]);
187 }
188 if(xs_tmp.size()>0) ft = ft.subs(vi);
189
190 // need collect_common_factors
191 ft = collect_common_factors(expand_ex(ft,y(w)));
192 if(is_exactly_a<mul>(ft)) {
193 ex ret = 1;
194 for (auto item : ft) {
195 if( !(item.match(y(w)) || item.match(pow(y(w), w1))) ) {
196 ret *= item;
197 }
198 }
199 ft = ret;
200 } else if ( ft.match(y(w)) || ft.match(pow(y(w), w1)) ) {
201 ft = 1;
202 } // else ft not changed
203
204 ys_tmp = get_y_from(ft);
205 for(int pi=1; pi<std::pow(2, ys_tmp.size()); pi++) {
206 lst yrepl;
207 int ci = pi;
208 for(int i=0; i<ys_tmp.size(); i++) {
209 yrepl.append(ys_tmp[i] == ((ci%2)==1 ? 1 : 0));
210 ci /= 2;
211 }
212 if(normal(ft.subs(yrepl)).is_zero()) return true;
213 }
214 }
215 return false;
216 }
217
223 exvector SecDec::AutoEnd(ex po_ex) {
224 if(po_ex.nops()>2) throw Error("AutoEnd: Deltas found @ " + ex2str(po_ex));
225 lst const exlist = ex_to<lst>(po_ex.op(1));
226 if(!(exlist.op(0)-1).is_zero()) throw Error("AutoEnd: (!(exlist.op(0)-1).is_zero())");
227 auto xs = get_x_from(po_ex.op(0));
228 if(xs.size()<1) xs = get_y_from(po_ex.op(0));
229 int nx = xs.size();
230 for(int nn=0; nn<=nx; nn++) {
231 for(int pi=0; pi<std::pow(2, nx); pi++) {
232 int cpi = pi, cn1 = 0;
233 for(int i=0; i<nx; i++) {
234 if((cpi % 2) == 1) cn1++;
235 cpi /= 2;
236 }
237 if(cn1 != nn) continue;
238
239 lst polists = lst{ po_ex.op(0) };
240 int bi = 0, bs = BisectionPoints.nops();
241 cpi = pi;
242 for(int i=0; i<nx; i++) {
243 if((cpi % 2) == 1) {
244 lst polists2;
245 auto x0 = BisectionPoints.op(bi % bs);
246 for(auto item : polists) {
247 symbol xy;
248 auto tmp = ex_to<lst>(subs(subs(item, lst{xs[i]==x0*xy}), lst{xy==xs[i]}));
249 tmp[0] = tmp.op(0) * x0;
250 polists2.append(tmp);
251
252 tmp = ex_to<lst>(subs(subs(item, lst{xs[i]==(x0-1)*xy+1}), lst{xy==xs[i]}));
253 tmp[0] = tmp.op(0) * (1-x0);
254 polists2.append(tmp);
255 }
256 polists = polists2;
257 bi++;
258 }
259 cpi /= 2;
260 }
261 bool OK = true;
262 for(auto polist : polists) {
263 lst sdList;
264 for(int i=0; i<polist.nops(); i++) {
265 auto tmp = polist.op(i);
266 auto ntmp = NN(exlist.op(i));
267 if(!tmp.subs(lst{x(w)==0, y(w)==0}).normal().is_zero()) continue;
268 if( (!tmp.has(x(w)) && !tmp.has(y(w))) || (is_a<numeric>(ntmp) && ntmp>0) ) continue;
269 sdList.append(tmp);
270 }
271
272 vector<exmap> vmap = SecDec->x2y(sdList);
273
274 for(int ni=0; ni<polist.nops(); ni++) {
275 auto po = polist.op(ni);
276 auto expo = exlist.op(ni); // note that expo may decrease when using diff
277 if(expo.info(info_flags::posint)) continue;
278 if(IsBad(po, vmap)) {
279 OK = false;
280 break;
281 }
282 }
283 if(!OK) break;
284 }
285
286 if(OK) {
287 exvector res;
288 for(auto item : polists) res.push_back(lst{ex_to<lst>(item), exlist});
289 return exvector(std::move(res));
290 }
291 }}
292
293 cerr << ErrColor << "polynormial list: " << po_ex.op(0) << RESET << endl;
294 throw Error("AutoEnd Failed @ ALL possible bisections!");
295 return exvector();
296 }
297
298 /*-----------------------------------------------------*/
299 /* SD */
300 /*-----------------------------------------------------*/
301 //return a lst, element pattern: { {{x1,n1}, {x2,n2}, ...}, {{e1, n1},{e2,n2}, ...} }
302 //e1 is a const term, e2 still the F-term
303 exvector SecDec::DS(const ex po_ex) {
304 // 1st element in input polist is the constant term, guess NOT necessary
305 // 2nd element in input polist is the F-term, required!
306 lst const polist = ex_to<lst>(po_ex.op(0));
307 lst const exlist = ex_to<lst>(po_ex.op(1));
308 lst sdList;
309 for(int i=0; i<polist.nops(); i++) {
310 auto tmp = polist.op(i);
311 auto ntmp = exlist.op(i);
312 if(!tmp.subs(lst{x(w)==0, y(w)==0}).normal().is_zero()) continue;
313 ntmp = NN(ntmp);
314 if( (!tmp.has(x(w)) && !tmp.has(y(w))) || (is_a<numeric>(ntmp) && ntmp>0) ) continue;
315 sdList.append(tmp);
316 }
317
318 vector<exmap> vmap = SecDec->x2y(sdList);
319 if(!VerifySD(vmap)) {
320 for(auto vi : vmap) cout << vi << endl;
321 throw Error("VerifySD Failed!");
322 }
323
324 exvector sd;
325 for(auto vi : vmap) {
326 auto ypolist = polist.subs(vi);
327 auto xs_tmp = get_x_from(ypolist);
328 auto ys_tmp = get_y_from(ypolist);
329 int ysn = ys_tmp.size();
330 vector<int> y_free_indexs;
331 for(int j=0; j<xs_tmp.size()+ys_tmp.size()+10; j++) {
332 if(!ypolist.has(y(j))) y_free_indexs.push_back(j);
333 }
334 if(xs_tmp.size()>y_free_indexs.size()) throw Error("DS: xsize>ysize");
335 for(int i=0; i<xs_tmp.size(); i++) {
336 vi[xs_tmp[i]] = y(y_free_indexs[i]);
337 }
338 if(xs_tmp.size()>0) ypolist = ypolist.subs(vi);
339 if(ypolist.has(x(w))) throw Error("DS: x(w) found @ " + ex2str(ypolist));
340
341 // need collect_common_factors
342 auto ft = collect_common_factors(expand_ex(ypolist.op(1),y(w)));
343
344 ex ct = 1, fsgin = 1;
345 if(is_a<mul>(ft)) {
346 ex ret = 1;
347 for (auto item : ft) {
348 if( !(item.match(y(w)) || item.match(pow(y(w), w1))) ) {
349 ret *= item;
350 }
351 }
352 ft = ret;
353 } else if( ft.match(y(w)) || ft.match(pow(y(w), w1)) ) {
354 ft = 1;
355 } // else ft not changed
356 bool hasWRA = false;
357 if(ft.has(WRA(w))) {
358 ft = 1;
359 hasWRA = true;
360 }
361
362 exmap eps_map;
363 ex epn = ex(1)/111;
364 for(auto epi : eps_lst) {
365 eps_map[epi.op(0)] = epn;
366 epn = epn / 13;
367 }
368
369 bool need_contour_deformation = ft.has(PL(w));
370 if(ft.has(y(w)) && !need_contour_deformation) {
371 auto tmp = ft.subs(nReplacement).subs(lst{ CV(w1,w2)==w2 }).subs(eps_map).expand();
372 if(is_a<add>(tmp)) {
373 need_contour_deformation = false;
374 auto first = tmp.op(0).subs(y(w)==1);
375 for(auto item : tmp) {
376 auto chk = item.subs(y(w)==1)*first;
377 auto nchk = NN(chk,30);
378 if(!is_a<numeric>(nchk)) {
379 throw Error("DS: Not a number: " + ex2str(chk));
380 }
381 if(nchk<0) {
382 need_contour_deformation = true;
383 break;
384 }
385 }
386 }
387 }
388
389 if(disable_Contour || !need_contour_deformation) {
390 auto tmp = NN(ft.subs(y(w)==1).subs(nReplacement).subs(lst{ CV(w1,w2)==w2 }).subs(eps_map),30);
391
392 if(!is_a<numeric>(tmp)) throw Error("DS: NOT a numeric with " + ex2str(tmp));
393 if(tmp<0) {
394 ct = exp(-I * Pi * exlist.op(1)); // negtive F-term: -1-i ep --> exp(-I*Pi)
395 fsgin = -1;
396 }
397 ft = 1;
398 }
399
400 exmap ymol;
401
402 auto det = exfactor(vi[x(-1)]); // need factor
403 if(is_a<add>(det)) throw Error("DS: det is add " + ex2str(det));
404 auto ys = get_xy_from(det);
405 ex det1 = 1;
406 for(int i=0; i<ys.size(); i++) {
407 auto ndeg = det.degree(ys[i]);
408 if(ndeg!=det.ldegree(ys[i])) throw Error("DS: det is not a monomial with det = "+ex2str(det));
409 ymol[ys[i]] = ymol[ys[i]] + ndeg;
410 det1 *= pow(ys[i], ndeg);
411 }
412 if(!(is_a<numeric>(det/det1) && ex_to<numeric>(det/det1).is_integer())) {
413 throw Error("DS: det=" + ex2str(det) + ", det1=" + ex2str(det1));
414 }
415
416 lst ftxlst;
417 for(auto xi : get_xy_from(ft)) ftxlst.append(xi);
418
419 lst pol_exp_lst;
420 pol_exp_lst.append(lst{ subs(FTX(ft,ftxlst)*CT(ct*det/det1), y(w)==x(w)), 1 });
421
422 for(int i=0; i<ypolist.nops(); i++) {
423 auto tmp = ypolist.op(i);
424 auto nexp = exlist.op(i).normal();
425 bool nchk = (!is_a<numeric>(nexp) || (is_a<numeric>(nexp) && nexp<0));
426 if(nexp.has(x(w)) || nexp.has(y(w))) throw Error("DS: x or y found in exp: "+ex2str(nexp));
427
428 if(tmp.has(y(w))) {
429 lst ys;
430 for(auto yi : get_y_from(tmp)) ys.append(yi);
431 if(!tmp.is_polynomial(ys)) throw Error("DS: NOT a polynomial with "+ex2str(tmp));
432 }
433
434 if(i==1 && fsgin<0) tmp = ex(0)-tmp; // check complete negtive F-term
435 auto tmp1 = tmp;
436 while(true) {
437 tmp=tmp1.subs(pow(y(w1)*w2, w3)==pow(y(w1),w3) * pow(w2, w3));
438 tmp = tmp.subs(pow(pow(y(w1),w2),w3)==pow(y(w1),w2*w3));
439 tmp = tmp.subs(pow(sqrt(y(w1)),w2)==pow(y(w1),w2/2));
440 tmp = tmp.subs(sqrt(pow(y(w1),w2))==pow(y(w1),w2/2));
441 if((tmp1-tmp).is_zero()) break;
442 tmp1 = tmp;
443 }
444
445 if(tmp.has(y(w))) tmp = exfactor(tmp); // need factor
446
447 ex rem = 1;
448 ex ct = 1;
449 ex tmps = tmp;
450 if(!is_a<mul>(tmps)) tmps = lst{tmps};
451 for (auto item : tmps) {
452 if(item.match(y(w))) {
453 auto yi = item;
454 ymol[yi] = ymol[yi] + nexp;
455 } else if(item.match(pow(y(w1), w2))) {
456 auto yi = item.op(0);
457 ymol[yi] = ymol[yi] + item.op(1) * nexp;
458 } else if(!item.has(y(w)) && !item.has(x(w))) {
459 if(is_a<numeric>(nexp) && ex_to<numeric>(nexp).is_integer()) {
460 ct *= item;
461 } else if(!item.has(PL(w)) && !item.has(WRA(w))) {
462 auto tr = NN(item.subs(nReplacement).subs(lst{ CV(w1,w2)==w2 }).subs(eps_map),30);
463 if(!is_a<numeric>(tr)) {
464 throw Error("DS: not numeric - item: " + ex2str(tr) + " ; " + ex2str(item));
465 }
466 auto nitem = ex_to<numeric>(tr);
467 if( nitem.is_real() && nitem<0 ) {
468 ct *= ex(-1)*item;
469 rem *= ex(-1);
470 } else {
471 ct *= item;
472 }
473 } else {
474 rem *= item;
475 }
476 } else {
477 if(nchk && item.subs(lst{y(w)==0,iEpsilon==0}).normal().is_zero()) {
478 throw Error("DS: zero item: " + ex2str(item) + " and exlist.op(i) = " + ex2str(nexp));
479 }
480 rem *= item;
481 }
482 }
483
484 ex pnp = rem-(i==1 && (ft!=1 || hasWRA) ? iEpsilon : ex(0));
485 pnp = pnp.subs(y(w)==x(w));
486
487 pol_exp_lst.append(lst{pnp, nexp});
488 pol_exp_lst[0] = pol_exp_lst.op(0).subs(CT(w)==CT(w*pow(ct,nexp))).subs(CT(0)==0);
489 }
490
491 lst x_n_lst;
492 for(auto & kv : ymol) {
493 auto k = kv.first.subs(y(w)==x(w));
494 auto v = kv.second;
495 if(is_a<numeric>(v)) {
496 auto nv = ex_to<numeric>(v);
497 if(nv<=-1) {
498 throw Error("DS: " + ex2str(kv.first) + "^(" + ex2str(nv) + ") found, " + ex2str(vi));
499 }
500 }
501 x_n_lst.append(lst{k, v});
502 }
503 x_n_lst.sort();
504 sd.push_back(lst{x_n_lst, pol_exp_lst});
505 }
506
507 return exvector(std::move(sd));
508 }
509
510 // 1st element in output is the constant term
511 // 2nd element in both input and output is the F-term
512 lst SecDec::Normalize(const ex &input) {
513 ex const_term = 1;
514 lst plst, nlst;
515 lst in_plst = ex_to<lst>(input.op(0));
516 lst in_nlst = ex_to<lst>(input.op(1));
517
518 auto vars = vec2lst(get_xy_from(input.op(0)));
519 int pnN = in_plst.nops();
520 for(int i=0; i<pnN; i++) {
521 auto pi = in_plst.op(i);
522 auto ni = in_nlst.op(i);
523
524 if(!pi.is_polynomial(vars)) {
525 if(ni.info(info_flags::integer)) {
526 auto nd = numer_denom(exfactor(pi,o_flintf));
527 if(nd.op(0).is_polynomial(vars) && nd.op(1).is_polynomial(vars)) {
528 in_plst.append(nd.op(1));
529 in_nlst.append(ex(0)-ni);
530 in_plst[i] = nd.op(0);
531 goto ok;
532 }
533 } else {
534 auto nd = numer_denom(exfactor(pi,o_flintf));
535 if(nd.op(0).is_polynomial(vars) && nd.op(1).is_polynomial(vars)) {
536 if(xPositive(nd.op(1))) {
537 in_plst.append(nd.op(1));
538 in_nlst.append(ex(0)-ni);
539 in_plst[i] = nd.op(0);
540 goto ok;
541 } else if(xPositive(nd.op(0))) {
542 in_plst.append(nd.op(0));
543 in_nlst.append(ni);
544 in_plst[i] = nd.op(1);
545 in_nlst[i] = ex(0)-ni;
546 goto ok;
547 }
548 }
549 }
550
551 if(true) {
552 ex pis;
553 if(!is_a<mul>(pi)) pis = lst{ pi };
554 else pis = pi;
555 ex rem = 1;
556 for(auto item : pis) {
557 if(item.is_polynomial(vars)) rem *= item;
558 else if(item.match(pow(w0,w1))) {
559 ex pp = item.op(0);
560 ex nn = item.op(1);
561 if(pp.is_polynomial(vars) && xPositive(pp)) {
562 in_plst.append(pp);
563 in_nlst.append(nn*ni);
564 } else {
565 auto nd = numer_denom(exfactor(pp,o_flintf));
566 if(nd.op(0).is_polynomial(vars) && nd.op(1).is_polynomial(vars)) {
567 if(xPositive(nd.op(0)) && xPositive(nd.op(1))) {
568 in_plst.append(nd.op(0));
569 in_plst.append(nd.op(1));
570 in_nlst.append(nn*ni);
571 in_nlst.append(ex(0)-nn*ni);
572 } else { cout << item << endl; goto nok; }
573 } else { cout << item << endl; goto nok; }
574 }
575 } else goto nok;
576 }
577 in_plst[i] = rem;
578 goto ok;
579 }
580
581 nok: throw Error("SecDec::Normalize, NOT polynomial found: "+ex2str(pi));
582 ok: continue;
583 }
584 }
585
586 for(int i=0; i<in_plst.nops(); i++) {
587 if(i!=1 && (in_nlst.op(i).is_zero() || in_plst.op(i)==ex(1))) continue;
588 if(i!=1 && !in_plst.op(i).has(x(w)) && !in_plst.op(i).has(y(w)) && !in_plst.op(i).has(z(w))) {
589 if(in_nlst.op(i).info(info_flags::integer) || xPositive(in_plst.op(i))) {
590 const_term *= pow(in_plst.op(i), in_nlst.op(i));
591 } else if(is_a<numeric>(in_plst.op(i)) && in_plst.op(i)<0) {
592 const_term *= exp((log(-in_plst.op(i))-I*Pi) * in_nlst.op(i)); // note: -1-iep --> exp(-I*Pi), like F-term
593 } else {
594 const_term *= exp(log(in_plst.op(i)) * in_nlst.op(i)); // note: log(-1)==I*Pi in GiNaC
595 }
596 } else {
597 //auto ptmp = collect_common_factors(expand_ex(in_plst.op(i),{x(w),y(w),z(w)}));
598 auto ptmp = in_plst.op(i);
599 auto ntmp = in_nlst.op(i);
600 if(!is_a<mul>(ptmp)) ptmp = lst{ ptmp };
601
602 exmap eps_map;
603 ex epn = ex(1)/111;
604 for(auto epi : eps_lst) {
605 eps_map[epi.op(0)] = epn;
606 epn = epn / 13;
607 }
608 ex tmul = 1;
609 for(int j=0; j<ptmp.nops(); j++) {
610 auto tmp = ptmp.op(j);
611 if(!tmp.has(x(w)) && !tmp.has(y(w)) && !tmp.has(z(w))) { // constant terms
612 if(ntmp.info(info_flags::integer)) {
613 const_term *= pow(tmp,ntmp);
614 } else if((tmp-vs).is_zero() || tmp.match(pow(vs,w))) {
615 const_term *= pow(tmp,ntmp);
616 } else if(!tmp.has(PL(w)) && !tmp.has(vs) && !tmp.has(WRA(w))) {
617 auto tr = NN(tmp.subs(nReplacement).subs(lst{ CV(w1,w2)==w2 }).subs(eps_map),30);
618 if(!is_a<numeric>(tr) || !tr.info(info_flags::real)) {
619 cerr << "tmp: " << tmp << endl;
620 cerr << "tr: " << tr << endl;
621 cerr << "nReplacement: " << nReplacement << endl;
622 throw Error("Normalize: tr is NOT numeric with nReplacement.");
623 }
624
625 if(tr>0) {
626 const_term *= pow(tmp,ntmp);
627 } else {
628 const_term *= pow(-tmp,ntmp);
629 tmul = ex(0) - tmul;
630 }
631 } else {
632 tmul *= tmp;
633 }
634 } else if(tmp.match(pow(w1,w2)) && ntmp.info(info_flags::integer) && tmp.op(1).info(info_flags::integer)) {
635 plst.append(tmp.op(0));
636 nlst.append(ntmp * tmp.op(1));
637 } else if(tmp.match(pow(w1,w2)) && xPositive(tmp.op(0))) {
638 plst.append(tmp.op(0));
639 nlst.append(ntmp * tmp.op(1));
640 } else if(xSign(tmp)!=0 || xSign(tmp.subs(lst{y(w)==x(w),z(w)==x(w)}))!=0) {
641 if(tmp.subs(lst{x(w)==1, y(w)==1, z(w)==1})>0) {
642 plst.append(tmp);
643 nlst.append(ntmp);
644 } else {
645 plst.append(ex(0)-tmp);
646 nlst.append(ntmp);
647 tmul = ex(0) - tmul;
648 }
649 } else {
650 tmul *= tmp;
651 }
652 }
653
654 if(i==1) {
655 plst.prepend(tmul);
656 nlst.prepend(ntmp);
657 } else if(tmul != 1) {
658 plst.append(tmul);
659 nlst.append(ntmp);
660 }
661
662 }
663 }
664 plst.prepend(const_term);
665 nlst.prepend(1);
666
667 lst plst_comb, nlst_comb;
668 exmap np;
669 for(int i=0; i<nlst.nops(); i++) {
670 if(i!=1) np[plst[i]] += nlst[i];
671 }
672 map<ex,int,ex_is_less> inp;
673 for(int i=0; i<nlst.nops(); i++) {
674 if(i==1) {
675 plst_comb.append(plst[1]);
676 nlst_comb.append(nlst[1]);
677 } else {
678 if(inp[plst[i]]==1) continue;
679 plst_comb.append(plst[i]);
680 nlst_comb.append(np[plst[i]]);
681 inp[plst[i]] = 1;
682 }
683 }
684
685 if(nlst_comb.op(0)!=1) {
686 if(nlst_comb.op(0).info(info_flags::integer) || xPositive(plst_comb.op(0))) {
687 plst_comb[0] = pow(plst_comb.op(0),nlst_comb.op(0));
688 } else if(is_a<numeric>(plst_comb.op(0)) && plst_comb.op(0)<0) {
689 plst_comb[0] = exp((log(-plst_comb.op(0))-I*Pi) * nlst_comb.op(0)); // note: -1-iep --> exp(-I*Pi), like F-term
690 } else plst_comb[0] = exp(log(plst_comb.op(0))*nlst_comb.op(0));
691 nlst_comb[0] = 1;
692 }
693
694 return (input.nops()>2) ? lst{plst_comb, nlst_comb, input.op(2)} : lst{plst_comb, nlst_comb};
695 }
696
697 /*-----------------------------------------------------*/
698 /* 's Funtions in SD */
699 /*-----------------------------------------------------*/
700 // working with or without Deltas
701 void SecDec::XReOrders() {
702 if(IsZero || !use_XReOrders) return;
703 if(Integrands.size()<1) {
704 for(auto &fe : FunExp) {
705 auto xs = get_x_from(fe);
706 lst x2y;
707 for(int i=0; i<xs.size(); i++) x2y.append(xs[i]==y(i));
708 fe = ex_to<lst>(subs(fe, x2y).subs(y(w)==x(w)));
709 }
710 } else {
711 for(auto &vint : Integrands) {
712 auto xs = get_x_from(vint);
713 lst x2y;
714 for(int i=0; i<xs.size(); i++) x2y.append(xs[i]==y(i));
715 vint = vint.subs(x2y).subs(y(w)==x(w));
716 }
717 }
718 }
719
720 // working with or without Deltas
721 void SecDec::Normalizes() {
722 for(int ri=0; ri<2; ri++) { // run twice, needs to check in more details
723 if(IsZero) return;
724 exvector funexp;
725 if(FunExp.size()<10) {
726 for(auto fe : FunExp) funexp.push_back(Normalize(fe));
727 } else {
728 funexp = GiNaC_Parallel(FunExp.size(), [&](int idx)->ex { return Normalize(FunExp[idx]); }, "Normalize");
729 }
730 FunExp.clear();
731 FunExp.shrink_to_fit();
732
733 exmap fn;
734 for(auto fe : funexp) {
735 ex key = 1;
736 if(fe.nops()>2) key = iWF(fe.op(2)); // deltas
737 if(fe.op(1).op(0)!=1) {
738 cout << fe << endl;
739 throw Error("Normalizes: fe.op(0).op(0) is NOT 1.");
740 }
741 for(int i=1; i<fe.op(0).nops(); i++) key *= pow(fe.op(0).op(i), fe.op(1).op(i));
742 fn[key] += fe.op(0).op(0);
743 }
744
745 map<ex,int,ex_is_less> ifn;
746 for(auto fe : funexp) {
747 ex key = 1;
748 if(fe.nops()>2) key = iWF(fe.op(2));
749 for(int i=1; i<fe.op(0).nops(); i++) key *= pow(fe.op(0).op(i), fe.op(1).op(i));
750 if(ifn[key]==1) continue;
751 lst funs, exps;
752 funs.append(fn[key]);
753 exps.append(1);
754 for(int i=1; i<fe.op(0).nops(); i++) {
755 funs.append(fe.op(0).op(i));
756 exps.append(fe.op(1).op(i));
757 }
758 if(fe.nops()>2) FunExp.push_back(lst{funs, exps, fe.op(2)});
759 else FunExp.push_back(lst{funs, exps});
760 ifn[key] = 1;
761 }
762 }
763 }
764
765 // working with or without Deltas
766 void SecDec::XTogethers() {
767 exvector funexp;
768 for(auto fe : FunExp) {
769 funexp.push_back(fe);
770 }
771 FunExp.clear();
772 FunExp.shrink_to_fit();
773
774 map<ex, ex, ex_is_less> fe_cc;
775 for(auto fe : funexp) {
776 lst fun, exp;
777 fun.append(1);
778 exp.append(1);
779 fun.append(fe.op(0).op(1));
780 exp.append(fe.op(1).op(1));
781 ex rem = 1;
782 for(int i=0; i<fe.op(1).nops(); i++) {
783 if(i==1) continue;
784 auto expi = fe.op(1).op(i);
785 if(expi.info(info_flags::nonnegint)) {
786 rem *= pow(fe.op(0).op(i), expi);
787 } else {
788 fun.append(fe.op(0).op(i));
789 exp.append(fe.op(1).op(i));
790 }
791 }
792 auto key = fe;
793 key[0] = fun;
794 key[1] = exp;
795 fe_cc[key] += rem;
796 }
797
798 for(auto kv : fe_cc) {
799 lst fe = ex_to<lst>(kv.first);
800 let_op_append(fe, 0, kv.second);
801 let_op_append(fe, 1, 1);
802 FunExp.push_back(fe);
803 }
804 }
805
806 // working with or without Deltas
807 void SecDec::XExpands() {
808 exvector funexp;
809 for(auto fe : FunExp) {
810 funexp.push_back(fe);
811 }
812 FunExp.clear();
813 FunExp.shrink_to_fit();
814
815 for(auto fe : funexp) {
816 lst fun = lst{fe.op(0).op(0), fe.op(0).op(1)};
817 lst exp = lst{fe.op(1).op(0), fe.op(1).op(1)};
818 ex rem = 1;
819 for(int i=2; i<fe.op(1).nops(); i++) {
820 auto expi = fe.op(1).op(i);
821 if(expi.info(info_flags::nonnegint)) {
822 rem *= pow(fe.op(0).op(i), expi);
823 } else {
824 fun.append(fe.op(0).op(i));
825 exp.append(fe.op(1).op(i));
826 }
827 }
828
829 rem = collect_ex(rem, x(w));
830
831 lst rem_lst;
832 if(is_a<add>(rem)) {
833 for(auto item : rem) rem_lst.append(item);
834 } else {
835 rem_lst.append(rem);
836 }
837
838 for(auto item : rem_lst) {
839 auto fe2 = fe;
840 let_op_append(fe2, 0, item);
841 let_op_append(fe2, 1, 1);
842 fe2[0] = fun;
843 fe2[1] = exp;
844 FunExp.push_back(fe2);
845 }
846 }
847 }
848
849 // Section 2.1 @ https://arxiv.org/pdf/1712.04441.pdf
850 // also refers to Feng/Thinking.pdf
851 void SecDec::Scalelesses() {
852 if(IsZero) return;
853 if(Verbose > 2) cout << PRE << "\\--Scaleless: " << FunExp.size() << " :> " << flush;
854
855 auto verb = Verbose; Verbose = 0;
856 auto sl_res =
857 GiNaC_Parallel(FunExp.size(), [this](int idx)->ex {
858 auto funexp = FunExp[idx];
859 if(funexp.nops()<3) return funexp;
860 symbol s;
861 auto fun = funexp.op(0);
862 auto exp = funexp.op(1);
863 auto deltas = funexp.op(2);
864 bool is0;
865 for(int di=0; di<deltas.nops(); di++) {
866 auto delta = ex_to<lst>(deltas.op(di));
867 is0 = false;
868 if(delta.nops()<2) continue;
869 // to make sure the integrand is projective
870 if(delta.nops()>1) {
871 lst sRepl;
872 for(int j=0; j<delta.nops(); j++) {
873 sRepl.append(delta[j]==delta[j]*s);
874 }
875
876 bool is_s = true;
877 ex n_s = 0;
878 for(int j=0; j<fun.nops(); j++) {
879 auto tmp = expand(fun.op(j).subs(sRepl));
880 if(tmp.degree(s)!=tmp.ldegree(s)) {
881 is_s = false;
882 break;
883 }
884 n_s += tmp.degree(s) * exp.op(j);
885 }
886 if(!is_s || !normal(n_s+delta.nops()).is_zero()) continue;
887 }
888
889 for(size_t i=1; i<ex_to<numeric>(GiNaC::pow(2,delta.nops())).to_long()-1; i++) {
890 lst sRepl;
891 auto ci = i;
892 ex n_s = 0;
893 for(int j=0; (j<delta.nops() && ci>0); j++) {
894 if((ci % 2)==1) {
895 sRepl.append(delta[j]==delta[j]*s);
896 n_s += 1;
897 }
898 ci = ci / 2;
899 }
900
901 bool is_s = true;
902 for(int j=0; j<fun.nops(); j++) {
903 if(exp.op(j).info(info_flags::nonnegint)) continue;
904 auto tmp = collect_ex(fun.op(j).subs(sRepl),s);
905 if(tmp.degree(s)!=tmp.ldegree(s)) {
906 is_s = false;
907 break;
908 }
909 n_s += tmp.degree(s) * exp.op(j);
910 }
911 if(!is_s) continue;
912 if(!normal(n_s).is_zero()) {
913 is0 = true;
914 break;
915 }
916 }
917 if(is0) break;
918 }
919 if(!is0) return lst{fun, exp, deltas};
920 else return lst{};
921 }, "SL");
922 Verbose = verb;
923
924 FunExp.clear();
925 FunExp.shrink_to_fit();
926 for(auto item : sl_res) {
927 lst fed = ex_to<lst>(item);
928 if(fed.nops()<1) continue;
929 FunExp.push_back(fed);
930 }
931
932 if(Verbose > 2) cout << FunExp.size() << endl;
933 if(FunExp.size()<1) IsZero = true;
934 }
935
936 void SecDec::RemoveDeltas() {
937 if(IsZero) return;
938
939 while(true) {
940 bool exit = true;
941 exvector funexp = FunExp;
942 FunExp.clear();
943 FunExp.shrink_to_fit();
944 for(auto fe : funexp) {
945 if(fe.nops()<3 || !is_a<lst>(fe.op(2))) {
946 FunExp.push_back(fe);
947 continue;
948 }
949
950 if(fe.op(2).nops()==0) { // Deltas = { }
951 FunExp.push_back(lst{fe.op(0), fe.op(1)});
952 continue;
953 }
954
955 if(true) { // remove {} in Deltas
956 lst Dlts;
957 for(auto dlt : fe.op(2)) if(dlt.nops()>0) Dlts.append(dlt);
958 if(Dlts.nops()==0) {
959 FunExp.push_back(lst{fe.op(0), fe.op(1)});
960 continue;
961 }
962 fe[2] = Dlts;
963 }
964
965 auto xs = ex_to<lst>(fe.op(2).op(0));
966 lst re_deltas;
967 for(int i=1; i<fe.op(2).nops(); i++) {
968 re_deltas.append(fe.op(2).op(i));
969 }
970 if(re_deltas.nops()>0) exit = false;
971
972 if(xs.nops()<1) {
973 FunExp.push_back(lst{fe.op(0), fe.op(1), re_deltas});
974 } else {
975 for(int i=0; i<xs.nops(); i++) {
976 auto xj = xs.op(i);
977 ex jInv = 0;
978 for(auto xi : xs) jInv += xi;
979 jInv = jInv.subs(xj==1);
980
981 exmap repl;
982 for(int j=0; j<xs.nops(); j++) {
983 auto xxj = xs.op(j);
984 if(xxj != xj) repl[xxj] = xj*xxj;
985 }
986
987 lst funs;
988 lst exps = ex_to<lst>(fe.op(1));
989 ex expns = 0;
990 for(int j=0; j<fe.op(0).nops(); j++) {
991 auto fun = fe.op(0).op(j);
992 fun = expand_ex(fun.subs(repl),xj);
993 if(!fun.is_polynomial(xj)) {
994 cerr << "xj: " << xj << endl;
995 cerr << "fun: " << fun << endl;
996 cerr << funexp << endl;
997 throw Error("RemoveDeltas: fun is NOT polynormial of xj.");
998 }
999 auto expn = fun.degree(xj);
1000 fun = pow(xj, -expn) * fun;
1001 fun = expand_ex(fun.subs(xj==1/xj),xj);
1002 fun = fun.subs(xj==jInv);
1003 funs.append(fun);
1004 expns += expn * exps.op(j);
1005 }
1006
1007 funs.append(jInv);
1008 exps.append(ex(0)-xs.nops()-expns);
1009 if(re_deltas.nops()>0) FunExp.push_back(lst{funs, exps, re_deltas});
1010 else FunExp.push_back(lst{funs, exps});
1011 }
1012 }
1013 }
1014 if(exit) break;
1015 }
1016 XReOrders();
1017 if(use_Normalizes) Normalizes();
1018 }
1019
1020 void SecDec::XEnd() {
1021 if(Verbose > 2) cout << PRE << "\\--BiSection: " << FunExp.size() << " :> " << flush;
1022 auto verb = Verbose; Verbose=0;
1023 GiNaC_Parallel_RM["BiSec"] = !Debug;
1024 auto funexps =
1025 GiNaC_Parallel(FunExp.size(), [this](int idx)->ex {
1026 auto fe = FunExp[idx];
1027 lst para_res_lst;
1028 if(xSign(fe.op(0).op(1))==0 && !fe.has(WRA(w))) {
1029 auto fes = AutoEnd(fe);
1030 for(auto fei : fes) para_res_lst.append(fei);
1031 } else {
1032 para_res_lst.append(fe);
1033 }
1034 return para_res_lst;
1035 }, "BiSec");
1036 Verbose = verb;
1037
1038 FunExp.clear();
1039 FunExp.shrink_to_fit();
1040 for(auto &item : funexps) {
1041 for(auto &it : ex_to<lst>(item)) FunExp.push_back(ex_to<lst>(it));
1042 }
1043 if(Verbose > 2) cout << FunExp.size() << endl;
1044 }
1045
1046 void SecDec::BiSection(ex xi, ex x0) {
1047 auto fes = FunExp;
1048 FunExp.clear();
1049 for(auto fe : fes) {
1050 symbol xy;
1051 auto tmp = ex_to<lst>(subs(subs(fe, lst{xi==x0*xy}), lst{xy==xi}));
1052 tmp[0][0] = tmp.op(0).op(0) * x0;
1053 FunExp.push_back(tmp);
1054
1055 tmp = ex_to<lst>(subs(subs(fe, lst{xi==(x0-1)*xy+1}), lst{xy==xi}));
1056 tmp[0][0] = tmp.op(0).op(0) * (1-x0);
1057 FunExp.push_back(tmp);
1058 }
1059 }
1060
1061 // after SDPrepares, Integrands can be expanded in ep safely.
1062 void SecDec::SDPrepares() {
1063 if(IsZero) return;
1064 if(FunExp.size()<1) {
1065 IsZero = true;
1066 return;
1067 }
1068 if(SecDec==NULL) SecDec = new SecDecG();
1069
1070 MB();
1071 RemoveDeltas();
1072 if(CheckEnd) XEnd();
1073
1074 Integrands.clear();
1075 Integrands.shrink_to_fit();
1076 auto fes = FunExp;
1077 FunExp.clear();
1078 FunExp.shrink_to_fit();
1079 for(auto &fe : fes) {
1080 bool to_add = true;
1081 for(auto item : fe.op(0)) {
1082 if(item.is_zero()) {
1083 to_add = false;
1084 break;
1085 }
1086 }
1087 if(to_add) FunExp.push_back(fe);
1088 }
1089 if(FunExp.size()<1) {
1090 IsZero = true;
1091 return;
1092 }
1093
1094 exmap eps_map;
1095 for(auto epi : eps_lst) eps_map[epi.op(0)] = 0;
1096
1097 SecDec->use_XMonomials = use_XMonomials;
1098 if(Verbose > 1) cout << Color_HighLight << " SDPrepares @ " << now() << RESET << endl;
1099 auto sd_res =
1100 GiNaC_Parallel(FunExp.size(), [this,&eps_map](int idx)->ex {
1101 // return a lst, element pattern: { {{x1,n1}, {x2,n2}, ...}, {{e1, n1},{e2,n2}, ...} }.
1102 auto fe = FunExp[idx];
1103 auto xns_pns = DS(fe);
1104 lst para_res_lst;
1105 for(auto const &item : xns_pns) {
1106
1107 // take z-poles
1108 if(item.has(vz)) {
1109 auto ct = item.op(1).op(0).op(0);
1110 ct = ct.subs(lst{ CT(w)==w,FTX(w1,w2)==1 }).subs(pow(vs,vz)==1);
1111 int sNN = vsN - vsRank(ct.subs(pow(vs,vz)==1));
1112
1113 lst zpols;
1114 // poles from Gamma(-z)
1115 for(int vn=0; vn<=sNN; vn++) zpols.append(vn);
1116
1117 // poles from xi^{c1*z+c0} with c1<0
1118 for(auto xn : item.op(0)) {
1119 auto xn_op1 = expand(xn.op(1).normal());
1120 ex c1 = xn_op1.coeff(vz);
1121 ex c0 = xn_op1.subs(vz==0);
1122
1123 if(!is_a<numeric>(c1)) {
1124 cerr << ErrColor << "SDPrepares: c1 is not a number: " << c1 << RESET << endl;
1125 exit(1);
1126 }
1127
1128 if(c1<0) {
1129 int pxn = -1;
1130 while(true) {
1131 ex zp = (pxn-c0)/c1;
1132 ex zpn = zp.subs(eps_map).subs(lst{ep==0,epz==0});
1133 if(!is_a<numeric>(zpn)) {
1134 cerr << ErrColor << "SDPrepares: zpn is not a number: " << zpn << RESET << endl;
1135 exit(1);
1136 }
1137 if(zpn>sNN) break;
1138 zpols.append(zp);
1139 pxn -= 1;
1140 }
1141 }
1142 }
1143 zpols.sort();
1144 zpols.unique();
1145
1146 symbol ss;
1147 for(auto zp : zpols) {
1148 auto item2 = item.subs(vz==ss+zp).subs(ss==vz);
1149 para_res_lst.append(item2);
1150 }
1151 } else {
1152 para_res_lst.append(item);
1153 }
1154 }
1155 return para_res_lst;
1156 }, "SD");
1157
1158 ex min_expn = 1, min_expn2 = 10;
1159 exvector ibp_in_vec;
1160 for(auto &item : sd_res) {
1161 for(auto &it : ex_to<lst>(item)) {
1162 ex expn = 0;
1163 for(auto xn : it.op(0)) {
1164 ex nxn = xn.op(1).subs(eps_map).subs(lst{ep==0, vz==0});
1165 if(nxn<-1) expn += nxn+1;
1166 if(min_expn2>nxn) min_expn2 = nxn+1;
1167 }
1168 if(expn < min_expn) min_expn = expn;
1169
1170 lst xns = ex_to<lst>(it.op(0));
1171 lst pns;
1172 for(int i=0; i<it.op(1).nops(); i++) {
1173 lst pn = ex_to<lst>(it.op(1).op(i));
1174 if(i<2) {
1175 pns.append(pn);
1176 continue;
1177 }
1178 if(pn.op(0).is_equal(1)) continue;
1179 if(is_zero(pn.op(1))) {
1180 if(is_zero(pn.op(0))) throw Error("SDPrepares: 0^0 found.");
1181 continue;
1182 }
1183 pns.append(pn);
1184 }
1185 ibp_in_vec.push_back(lst{xns, pns});
1186 }
1187 }
1188
1189 if(Verbose > 1) cout << PRE << "\\--" << Color_HighLight << "Maximum x^-n: All(" << ex(0)-min_expn << "+1X), Max(" << (ex(0)-min_expn2) << "+1)" << RESET << endl;
1190
1191 int pn = 0;
1192 exvector ibp_res_vec;
1193 while(ibp_in_vec.size()>0) {
1194 pn++;
1195 ostringstream spn;
1196 spn << "XIBP-" << (pn-1);
1197 auto ibp_res =
1198 GiNaC_Parallel(ibp_in_vec.size(), [&eps_map,&ibp_in_vec,this](int idx)->ex {
1199 // return lst
1200 // {0, element} for input with pole reached and doing nothing
1201 // {1, {element, ...}} for input whth pole NOT reached
1202 // element pattern still as { {{x1,n1}, {x2,n2}, ...}, {{e1, n1},{e2,n2}, ...} }
1203
1204 auto xns_pns = ibp_in_vec[idx];
1205
1206 auto xns = xns_pns.op(0);
1207 auto pns = xns_pns.op(1);
1208
1209 exset fts;
1210 pns.op(0).find(FTX(w1,w2), fts);
1211 bool noFT = (fts.size()==1) && ( is_zero((*(fts.begin())).op(0)-1) );
1212 if(!noFT || disable_Contour) noFT = true;
1213
1214 ex pole_requested = -1;
1215 if(noFT || PoleRequested > -1) pole_requested = PoleRequested;
1216
1217 for(int n=0; n<xns.nops(); n++) {
1218 ex xn = xns.op(n);
1219 auto expn = xn.op(1).subs(eps_map).subs(lst{ep==0,vz==0,epz==0}).normal();
1220 if(!is_a<numeric>(expn)) throw Error("SDPrepares: expn NOT numeric: " + ex2str(expn));
1221
1222 if(ex_to<numeric>(expn) < pole_requested) {
1223 auto xx = xn.op(0);
1224 pns[0][0] = pns.op(0).op(0) / (xn.op(1)+1);
1225
1226 lst xns2;
1227 for(int i=0; i<xns.nops(); i++) {
1228 if(i!=n) xns2.append(xns.op(i));
1229 }
1230 lst pns2 = ex_to<lst>(pns);
1231 for(int i=0; i<pns.nops(); i++) {
1232 pns2[i][0] = pns2.op(i).op(0).subs(xx==1);
1233 }
1234
1235 lst xns_pns_lst;
1236 xns_pns_lst.append(lst{xns2, pns2});
1237
1238 for(int i=0; i<pns.nops(); i++) {
1239 lst xns3 = ex_to<lst>(xns);
1240 xns3[n][1] = xn.op(1)+1;
1241
1242 ex tmp = ex(0)-pns.op(i).op(1)*diff_ex(pns.op(i).op(0),xx);
1243 if(tmp.is_zero()) continue;
1244
1245 auto xs = get_x_from(tmp);
1246 bool tz = false;
1247 for(auto xi : xs) {
1248 if(tmp.subs(xi==0).is_zero()) {
1249 tz = true;
1250 break;
1251 }
1252 }
1253 // need collect_common_factors
1254 if(tz) tmp = collect_common_factors(expand_ex(tmp,x(w)));
1255 if(tmp.is_zero()) continue;
1256
1257 if(tz && is_a<mul>(tmp)) {
1258 ex rem = 1;
1259 for(auto ii : tmp) {
1260 if(ii.match(pow(x(w), w2))) {
1261 bool t = true;
1262 for(int ij=0; ij<xns3.nops(); ij++) {
1263 if(xns3.op(ij).op(0)==ii.op(0)) {
1264 xns3[ij][1] += ii.op(1);
1265 t = false;
1266 break;
1267 }
1268 }
1269 if(t) xns3.append(lst{ii.op(0), ii.op(1)});
1270 } else if(ii.match(x(w))) {
1271 bool t = true;
1272 for(int ij=0; ij<xns3.nops(); ij++) {
1273 if(xns3.op(ij).op(0)==ii) {
1274 xns3[ij][1] += 1;
1275 t = false;
1276 break;
1277 }
1278 }
1279 if(t) xns3.append(lst{ii, 1});
1280 } else {
1281 rem *= ii;
1282 }
1283 }
1284 tmp = rem;
1285 }
1286
1287 lst pns3 = ex_to<lst>(pns);
1288 if(is_zero(pns.op(i).op(1)-1)) {
1289 pns3[i][0] = tmp;
1290 } else {
1291 pns3[i][1] = pns.op(i).op(1)-1;
1292 int nn = pns.nops();
1293 if(!(pns.op(nn-1).op(1)-1).is_zero()) pns3.append(lst{ tmp, 1 });
1294 else pns3[nn-1][0] = pns.op(nn-1).op(0) * tmp;
1295 }
1296 xns_pns_lst.append(lst{xns3, pns3});
1297 }
1298 return lst{1, xns_pns_lst};
1299 }
1300 }
1301 return lst{0, xns_pns };
1302
1303 }, spn.str().c_str());
1304
1305 auto rets_vec =
1306 GiNaC_Parallel(ibp_res.size(), [&ibp_res](int idx)->ex {
1307 lst ret1, ret2;
1308 auto ii = ibp_res[idx];
1309 auto check = ii.op(0);
1310 if(check>0) {
1311 auto items = ii.op(1);
1312 for(auto &it : ex_to<lst>(items)) ret1.append(it);
1313 } else {
1314 exmap sub_exp;
1315 sub_exp[pow(exp(w1),w2)]=exp(w1*w2);
1316 sub_exp[sqrt(exp(w1))]=exp(w1/2);
1317 sub_exp[exp(w1)*exp(w2)*w0]=exp(w1+w2)*w0;
1318 sub_exp[exp(w1)*exp(w2)]=exp(w1+w2);
1319
1320 auto item = ii.op(1);
1321 ex expr = 1, expr_exp = 1;
1322 for(auto pn : item.op(1)) {
1323 if(pn.op(0).has(CT(w)) || pn.op(0).has(FTX(w1,w2))) {
1324 if(pn.op(1)!=1) throw Error("SDPrepares: exponent of CT is NOT 1.");
1325 expr *= pn.op(0);
1326 } else if(xPositive(pn.op(0)) || pn.op(1).info(info_flags::integer)) {
1327 if(pn.op(0).has(exp(w))) expr_exp *= pow(pn.op(0), pn.op(1));
1328 else expr *= pow(pn.op(0), pn.op(1));
1329 } else if(is_a<numeric>(pn.op(0)) && pn.op(0)<0) {
1330 expr_exp *= exp((log(-pn.op(0))-I*Pi) * pn.op(1)); // note: -1-iep --> exp(-I*Pi), like F-term
1331 } else {
1332 expr_exp *= exp(log(pn.op(0)) * pn.op(1));
1333 }
1334 }
1335 while(true) {
1336 auto expo = expr_exp.subs(sub_exp);
1337 if(is_zero(expo-expr_exp)) break;
1338 expr_exp = expo;
1339 }
1340 expr *= expr_exp;
1341 ret2.append(lst{ item.op(0), expr });
1342 }
1343 return lst{ret1, ret2};
1344 }, spn.str()+"R");
1345 ibp_in_vec.clear();
1346 ibp_in_vec.shrink_to_fit();
1347 for(auto rets : rets_vec) {
1348 for(auto item : rets.op(0)) ibp_in_vec.push_back(item);
1349 for(auto item : rets.op(1)) ibp_res_vec.push_back(item);
1350 }
1351 }
1352
1353 auto res =
1354 GiNaC_Parallel(ibp_res_vec.size(), [&ibp_res_vec,&eps_map](int idx)->ex {
1355
1356 // return single element in which ep/eps can be expanded safely.
1357 auto xns_expr = ibp_res_vec[idx];
1358 lst para_res_lst;
1359 auto xns = xns_expr.op(0);
1360 auto expr = xns_expr.op(1);
1361 lst exprs = { expr };
1362 symbol dx;
1363 for(auto xn : xns) {
1364 auto expn = xn.op(1).subs(eps_map).subs(lst{ep==0,vz==0,epz==0}).normal();
1365 if(!is_a<numeric>(expn)) throw Error("SDPrepares: Not a number with expn = " + ex2str(expn));
1366
1367 lst exprs2;
1368 for(auto it : exprs) {
1369 ex rem = pow(xn.op(0), xn.op(1)) * it;
1370 if(ex_to<numeric>(expn)<=-1) {
1371 ex dit = it;
1372 ex dit0 = dit.subs(xn.op(0)==0);
1373 ex ifact = 1;
1374 if(!is_zero(dit0)) {
1375 rem -= pow(xn.op(0), xn.op(1)) * dit0 / ifact;
1376 exprs2.append(dit0/(xn.op(1)+1)/ifact);
1377 }
1378 for(int i=1; i+expn<0; i++) {
1379 dit = diff_ex(dit, xn.op(0));
1380 if(is_zero(dit)) break;
1381 dit0 = dit.subs(xn.op(0)==0);
1382 ifact *= i;
1383 if(!is_zero(dit0)) {
1384 rem -= pow(xn.op(0), xn.op(1)+i) * dit0 / ifact;
1385 exprs2.append(dit0/(xn.op(1)+i+1)/ifact);
1386 }
1387 }
1388 }
1389 exprs2.append(rem);
1390 }
1391 exprs = exprs2;
1392 }
1393
1394 for(auto const &it : exprs) {
1395 if(it.is_zero()) continue;
1396 auto xs = get_x_from(it);
1397 lst x2y;
1398 for(int i=0; i<xs.size(); i++) x2y.append(xs[i]==y(i));
1399 para_res_lst.append(it.subs(x2y).subs(y(w)==x(w)));
1400 }
1401
1402 return para_res_lst;
1403 }, "XTaylor");
1404
1405 // Take z-residues
1406 bool zResides = false;
1407 exvector ints;
1408 for(auto &item : res) {
1409 for(auto it : ex_to<lst>(item)) {
1410 if(!it.is_zero()) ints.push_back(it);
1411 if(!zResides && it.has(vz)) zResides = true;
1412 }
1413 }
1414
1415 if(zResides) {
1416 Integrands =
1417 GiNaC_Parallel(ints.size(), [&ints](int idx)->ex {
1418 auto item = ints[idx];
1419 ex it = item;
1420 if(it.has(vz)) {
1421 exset cts;
1422 it.find(CT(w),cts);
1423 lst repl;
1424 for(auto ct : cts) {
1425 ex cc = 1;
1426 ex ll = 1;
1427 lst cls;
1428 if(is_a<mul>(ct.op(0))) {
1429 for(auto ii : ct.op(0)) cls.append(ii);
1430 } else {
1431 cls.append(ct.op(0));
1432 }
1433 for(auto cl : cls) {
1434 if(cl.has(vz)) cc *= cl;
1435 else ll *= cl;
1436 }
1437 if(cc!=1) repl.append(ct==cc*CT(ll));
1438 }
1439 it = it.subs(repl);
1440 it = series_ex(it,vz,-1);
1441 it = ex(0)-it.coeff(vz, -1);
1442 }
1443 return it;
1444 }, "zResidue");
1445 } else {
1446 Integrands = ints;
1447 }
1448
1449 }
1450
1451 void SecDec::EpsExpands() {
1452 if(IsZero) return;
1453 if(Integrands.size()<1) {
1454 IsZero = true;
1455 return;
1456 }
1457
1458 if(Verbose > 1) cout << Color_HighLight << " EpsExpands @ " << now() << RESET << endl;
1459
1460 if(Verbose > 1) cout << PRE << "\\--Collecting: " << Integrands.size() << " :> " << flush;
1461 exmap int_map;
1462 for(auto &item : Integrands) {
1463 if(item.is_zero()) continue;
1464 exset cts;
1465 item.find(CT(w), cts);
1466 if(cts.size() != 1) {
1467 cerr << "cts: " << cts << endl;
1468 cerr << "item: " << item << endl;
1469 throw Error("EpsExpands: CT size is NOT 1: ");
1470 }
1471 ex ct = (*(cts.begin())).subs(CT(w)==w);
1472 auto it = item.subs(CT(w)==1);
1473 int_map[it] = int_map[it]+ct;
1474 }
1475
1476 Integrands.clear();
1477 Integrands.shrink_to_fit();
1478 for(auto kv : int_map) {
1479 if(kv.second.is_zero()) continue;
1480 Integrands.push_back(CT(kv.second) * kv.first);
1481 }
1482 if(Verbose > 1) cout << Integrands.size() << endl;
1483
1484 GiNaC_Parallel_RM["EpsEx"] = !Debug;
1485 auto res =
1486 GiNaC_Parallel(Integrands.size(), [this](int idx)->ex {
1487 // return { {two elements}, {two elements}, ...},
1488 // 1st: x-independent coefficient, expanded in ep/eps
1489 // 2nd: x-integrand
1490 auto item = Integrands[idx];
1491 if(item.is_zero()) return lst{ lst{0, 0} };
1492 exset cts;
1493 item.find(CT(w), cts);
1494 if(cts.size() != 1) {
1495 cerr << "cts: " << cts << endl;
1496 cerr << "item: " << item << endl;
1497 throw Error("EpsExpands: CT size is NOT 1: ");
1498 }
1499 ex ct = (*(cts.begin())).subs(CT(w)==w);
1500 auto it = item.subs(CT(w)==1);
1501
1502 if(ct.has(epz)) {
1503 if(is_a<mul>(ct)) {
1504 ex ct0 = 1, ct1 = 1;
1505 for(auto ci : ct) {
1506 if(ci.has(epz)) ct1 *= ci;
1507 else ct0 *= ci;
1508 }
1509 ct = ct0;
1510 it *= ct1;
1511 } else {
1512 it *= ct;
1513 ct = 1;
1514 }
1515 }
1516 if(it.has(epz)) it = series_ex(it,epz,0);
1517
1518 auto cvs = collect_lst(it, lst{epz, vs});
1519 lst para_res_lst;
1520 for(auto cv : cvs) {
1521 auto cc = cv.op(1) * ct; // multiple ct here
1522 auto vv = cv.op(0);
1523 for(auto epi : eps_lst) {
1524 auto epis = epi.op(0);
1525 if(!cc.has(epis) && !vv.has(epis)) continue;
1526 int iN = ex2int(epi.op(1));
1527 int cN = epsRank(cc, epis);
1528 vv = series_ex(vv, epis, iN-cN);
1529 int vN = vv.ldegree(epis);
1530 cc = series_ex(cc, epis, iN-vN);
1531 }
1532
1533 lst pat_lst;
1534 for(auto item : eps_lst) pat_lst.append(item.op(0));
1535 auto ics = collect_lst(vv, pat_lst);
1536 for(auto ic : ics) {
1537 ex intg = ic.op(0);
1538 ex pref = ic.op(1)*cc;
1539 ex n1 = intg.subs(x(w)==ex(1)/7);
1540 if(is_zero(n1)) {
1541 n1 = intg.subs(x(w)==ex(1)/13);
1542 if(is_zero(n1)) intg = exnormal(intg);
1543 }
1544 for(auto epi : eps_lst) pref = series_ex(pref, epi.op(0), ex2int(epi.op(1)));
1545 para_res_lst.append(lst{pref, intg});
1546 }
1547 }
1548
1549 return para_res_lst;
1550
1551 }, "EpsEx");
1552
1553 if(Verbose > 1) cout << PRE << "\\--Collecting: ";
1554 map<ex, ex, ex_is_less> int_pref;
1555 size_t ncollect = 0;
1556 ex expr_nox = 0;
1557 for(auto &item : res) {
1558 ncollect += item.nops();
1559 for(auto &kv : ex_to<lst>(item)) {
1560 if(!kv.op(1).has(x(w))) expr_nox += kv.op(0) * kv.op(1);
1561 else int_pref[kv.op(1)] += kv.op(0);
1562 }
1563 }
1564
1565 if(Verbose > 1) cout << ncollect << " :> " << flush;
1566 expResult.clear();
1567 expResult.shrink_to_fit();
1568 for(auto kv : int_pref) {
1569 if(kv.second.is_zero()) continue;
1570 expResult.push_back(lst{kv.second, kv.first});
1571 }
1572 if(!is_zero(expr_nox)) {
1573 expr_nox = expr_nox.subs(FTX(w1,w2)==1);
1574 expResult.push_back(lst{expr_nox, 1});
1575 }
1576 if(Verbose > 1) cout << expResult.size() << endl;
1577 }
1578
1579}
#define RESET
Definition BASIC.h:79
int pn
Definition Others.cpp:25
lst intg
Definition Others.cpp:26
SecDec header file.
class used to wrap error message
Definition BASIC.h:242
bool use_XMonomials
Definition SD.h:98
static bool VerifySD(vector< exmap > vmap, bool quick=true)
Verify the Sector Decompostion is valid.
Definition SecDec.cpp:88
virtual vector< exmap > x2y(const ex &xpol)=0
static ex XMonomials(const ex &expr)
XMonomials.
Definition SecDec.cpp:18
SecDec by geometric method.
Definition SD.h:106
static vector< vector< int > > RunQHull(const matrix &pts)
Definition SecDecG.cpp:176
SecDec the main class to use Sector Decompostion method.
Definition SD.h:413
bool IsBad(ex f, vector< exmap > vmap)
Check the x-END.
Definition SecDec.cpp:174
static bool VerifySD(vector< exmap > vmap, bool quick=true)
Definition SecDec.cpp:123
exvector AutoEnd(ex po_ex)
Auto BiSection.
Definition SecDec.cpp:223
bool use_XMonomials
Definition SD.h:423
lst BisectionPoints
Definition SD.h:442
namespace for Numerical integration with Sector Decomposition method
Definition AsyMB.cpp:10
exvector get_xy_from(ex pol)
Definition Helpers.cpp:14
ex xyz_pow_simplify(const ex expr_in)
Definition Helpers.cpp:336
exvector get_y_from(ex pol)
Definition Helpers.cpp:44
exvector get_x_from(ex pol)
Definition Helpers.cpp:29
int epsRank(ex expr_in, ex epi)
Definition Helpers.cpp:195
ex expand_ex(ex const &expr_in, std::function< bool(const ex &)> has_func)
the expand like Mathematica
Definition BASIC.cpp:1188
const char * Color_HighLight
Definition BASIC.cpp:248
ex exfactor(const ex &expr_in, int opt)
factorize a expression
Definition BASIC.cpp:1854
const iSymbol iEpsilon
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
ex w0
Definition BASIC.h:499
map< string, bool > GiNaC_Parallel_RM
Definition Init.cpp:151
const char * ErrColor
Definition BASIC.cpp:246
const Symbol ep
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 series_ex(ex const &expr_in, ex const &s0, int sn0)
the series like Mathematica, include s^n
Definition BASIC.cpp:968
string now(bool use_date)
date/time string
Definition BASIC.cpp:525
bool Debug
Definition Init.cpp:144
ex w
Definition Init.cpp:93
const Symbol vs
ex exnormal(const ex &expr, int opt)
normalize a expression
Definition BASIC.cpp:1916
const int o_flintf
Definition Init.cpp:114
const Symbol epz
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
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:142
void let_op_append(ex &ex_in, const ex item)
append item into expression
Definition BASIC.cpp:1324
lst vec2lst(const exvector &ev)
convert exvector to lst
Definition BASIC.cpp:902
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 w1
Definition BASIC.h:499
ex w3
Definition BASIC.h:499
int xSign(ex const expr)
the always sign for expr
Definition BASIC.cpp:1312
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
const Symbol vz
string PRE
Definition Init.cpp:143
int ex2int(ex num)
ex to integer
Definition BASIC.cpp:893
ex subs(const ex &e, init_list sl)
Definition BASIC.h:51