12 unsigned ApartIR1_SERIAL::serial = GiNaC::function::register_new(function_options(
"ApartIR",1).
do_not_evalf_params().overloaded(2));
13 unsigned ApartIR2_SERIAL::serial = GiNaC::function::register_new(function_options(
"ApartIR",2).
do_not_evalf_params().overloaded(2));
18 inline bool isOK(
const ex &expr_in,
const lst &vars) {
20 if(is_a<power>(item)) {
21 if(!is_a<numeric>(item.op(1)) || !ex_to<numeric>(item.op(1)).is_integer())
return false;
25 for(
auto v : vars)
vs[v] = s*v;
38 if(e.match(ApartIR(1)) || e.match(ApartIR(1,
w)))
return 1;
39 else if(!e.has(ApartIR(
w1,
w2)))
return e;
40 else if(e.match(ApartIR(
w1,
w2))) {
43 matrix mat = ex_to<matrix>(e.op(0));
44 for(
int c=0; c<mat.cols(); c++) {
46 for(
int r=0; r<mat.rows()-2; r++) sum += mat(r,c) * vars.op(r);
47 sum += mat(mat.rows()-2,c);
48 ret *= pow(sum, mat(mat.rows()-1,c));
51 }
else return e.map(
self);
64 if(e.match(ApartIR(1)) || e.match(ApartIR(1,
w)))
return 1;
65 else if(!e.has(ApartIR(
w1,
w2)))
return e;
66 else if(e.match(ApartIR(
w1,
w2))) {
68 matrix mat = ex_to<matrix>(e.op(0));
70 for(
int c=0; c<mat.cols(); c++) {
72 for(
int r=0; r<mat.rows()-2; r++) sum += mat(r,c) * vars.op(r);
73 sum += mat(mat.rows()-2,c);
74 if(is_zero(mat(mat.rows()-1,c)))
continue;
75 pns.append(lst{ sum, ex(0)-mat(mat.rows()-1,c) });
79 for(
auto item : pns) {
80 ps.append(item.op(0));
81 ns.append(item.op(1));
84 }
else return e.map(
self);
90 matrix mat = ex_to<matrix>(air.op(0));
91 auto vars = air.op(1);
93 for(
int c=0; c<mat.cols(); c++) {
95 for(
int r=0; r<mat.rows()-2; r++) sum += mat(r,c) * vars.op(r);
96 sum += mat(mat.rows()-2,c);
97 if(is_zero(mat(mat.rows()-1,c)))
continue;
98 pns.append(lst{ sum, mat(mat.rows()-1,c) });
102 for(
auto item : pns) {
103 ps.append(item.op(0));
104 ns.append(item.op(1));
109 inline ex
pn2mat(ex ps, ex ns, ex vars) {
111 for(
int i=0; i<ps.nops(); i++) pnlst.append(lst{ ps.op(i), ns.op(i) });
113 int nrow=vars.nops(), ncol=pnlst.nops();
115 for(
auto v : vars) vars0[v]=0;
116 matrix mat(nrow+2, ncol);
117 for(
int c=0; c<ncol; c++) {
119 mat(nrow+1,c) = normal(pn.op(1));
121 for(
int r=0; r<nrow; r++) {
122 mat(r,c) = (tmp.coeff(vars.op(r)));
124 mat(nrow,c) = (tmp.subs(vars0,
nopat));
134 if(t1>t2)
return false;
136 if(t1-i1>t2-i2)
return false;
137 if(e1.op(i1).is_equal(e2.op(i2))) {
138 i1++; i2++;
continue;
149 for(
int i=0; i<n.nops(); i++) {
150 if(n.op(i).is_zero())
continue;
158 if(airs.size()<1)
return rules;
161 vector<exset> nps_set(airs[0].op(1).nops());
162 for(
auto air : airs) {
165 nps_set[l.nops()-1].insert(l);
167 vector<exvector> nps(nps_set.size());
168 for(
int i=0; i<nps_set.size(); i++) nps[i] = exvector(nps_set[i].begin(), nps_set[i].end());
172 for(
int i=0; i<nps.size()-1; i++) {
174 if(psi.size()<1)
continue;
175 if(psi.size()<nlimit) {
177 for(
int j=nps.size()-1; j>i; j--) {
180 if(
is_subset(si,sj)) { s2s[si] = sj;
goto nextsi; }
186 exvector psi_vec(psi.begin(), psi.end());
187 auto ret =
GiNaC_Parallel(psi_vec.size(), [&psi_vec,&nps,i](
int idx)->ex{
188 auto si = psi_vec[idx];
189 for(int j=nps.size()-1; j>i; j--) {
191 for(int jj=0; jj<psj.size(); jj++) {
194 if(is_subset(si,sj)) return lst{idx, j, jj};
198 },
"AR-"+to_string(nps.size()-1)+
"-"+to_string(i+1));
199 for(
auto item : ret)
if(item.nops()>1) {
200 int idx = ex_to<numeric>(item.op(0)).to_int();
201 int j = ex_to<numeric>(item.op(1)).to_int();
202 int jj = ex_to<numeric>(item.op(2)).to_int();
203 s2s[psi_vec[idx]] = nps[j][jj];
208 if(airs.size()<nlimit) {
209 for(
int k=0; k<airs.size(); k++) {
210 auto pn =
air2pn(airs[k]);
214 for(
int i=0; i<p.nops(); i++)
if(!is_zero(n.op(i))) p2n[p.op(i)] = n.op(i);
216 auto fi = s2s.find(pk);
218 auto pp = fi->second;
220 for(
int i=0; i<pp.nops(); i++) nn.append(p2n[pp.op(i)]);
221 ex air = ApartIR(
pn2mat(pp,nn,airs[k].op(1)),airs[k].op(1));
224 for(
int i=0; i<p.nops(); i++)
if(!n.op(i).is_zero()) eL *= pow(WF(p.op(i)), n.op(i));
225 for(
int i=0; i<pp.nops(); i++)
if(!nn.op(i).is_zero()) eR *= pow(WF(pp.op(i)), nn.op(i));
226 ex chk = normal(eL-eR);
228 cout << p <<
", " << n << endl;
229 cout << pp <<
", " << nn << endl;
230 throw Error(
"ApartRules: check failed!");
234 rules[airs[k]] = air;
235 }
else if(irc) rules[airs[k]] =
ApartIRC(airs[k]);
238 auto ret =
GiNaC_Parallel(airs.size(), [&airs,&s2s,irc](
int k)->ex{
239 auto pn = air2pn(airs[k]);
243 for(int i=0; i<p.nops(); i++) if(!is_zero(n.op(i))) p2n[p.op(i)] = n.op(i);
245 auto fi = s2s.find(pk);
247 auto pp = fi->second;
249 for(int i=0; i<pp.nops(); i++) nn.append(p2n[pp.op(i)]);
250 ex air = ApartIR(pn2mat(pp,nn,airs[k].op(1)),airs[k].op(1));
254 for(int i=0; i<p.nops(); i++) if(!n.op(i).is_zero()) eL *= pow(WF(p.op(i)), n.op(i));
255 for(int i=0; i<pp.nops(); i++) if(!nn.op(i).is_zero()) eR *= pow(WF(pp.op(i)), nn.op(i));
256 ex chk = normal(eL-eR);
258 cout << p <<
", " << n << endl;
259 cout << pp <<
", " << nn << endl;
260 throw Error(
"ApartRules: check failed!");
263 if(irc) air = ApartIRC(air);
264 return lst{ airs[k], air };
265 }
else if(irc)
return lst{ airs[k], ApartIRC(airs[k]) };
269 for(
auto lr : ret)
if(lr.nops()>1) rules[lr.op(0)] = lr.op(1);
281 static exmap mat_cache;
283 auto mat_itr = mat_cache.find(mat);
284 if(mat_itr!=mat_cache.end())
return mat_itr->second;
286 int nrow = mat.rows()-2;
287 int ncol = mat.cols();
291 static exmap null_cache;
293 ex key = sub_matrix(mat,0,nrow,0,ncol);
294 auto null_itr = null_cache.find(key);
295 if(null_itr==null_cache.end()) {
297 Fermat &fermat = Fermat::get();
298 int &v_max = fermat.
vmax;
302 for(const_preorder_iterator i = tree.preorder_begin(); i != tree.preorder_end(); ++i) {
304 if(is_a<symbol>(e) || is_a<Pair>(e) || is_a<Eps>(e)) {
314 for(
auto vi : rep_vs) {
315 auto name =
"v" + to_string(fvi);
323 cout << rep_vs << endl;
324 throw Error(
"Fermat: Too many variables.");
327 for(
int i=v_max; i<fvi; i++) ss <<
"&(J=v" << i <<
");" << endl;
334 ss <<
"Array m[" << nrow <<
"," << ncol+1 <<
"];" << endl;
340 for(
int c=0; c<ncol; c++) {
341 for(
int r=0; r<nrow; r++) {
345 for(
int r=0; r<nrow; r++) ss <<
"0,";
347 ss <<
"Redrowech([m]);" << endl;
354 ss <<
"&(U=1);" << endl;
356 auto ostr = fermat.
Execute(ss.str());
362 ss <<
"&(U=0);" << endl;
363 ss <<
"@([m]);" << endl;
364 ss <<
"&_G;" << endl;
370 if(ostr[ostr.length()-1]!=
'0')
throw Error(
"Apart: last char is NOT 0.");
371 ostr = ostr.substr(0, ostr.length()-1);
374 ostr.erase(0, ostr.find(
":=")+2);
378 auto mat2 = fp.
Read(ostr);
381 for(
int c=0; c<ncol; c++) xs[c] = iWF(c);
382 for(
int r=nrow-1; r>=0; r--) {
385 for(
int c=0; c<ncol; c++) {
386 if(!is_zero(
get_op(mat2,r,c)) && pi<0) pi = c;
387 else xadd -=
get_op(mat2,r,c)*xs[c];
391 for(
int c=0; c<ncol; c++) null_vec.append(xs[c]);
395 for (
int c=0; c<ncol; c++) {
401 matrix zero(nrow, 1);
402 matrix s = ex_to<matrix>(key.subs(
iEpsilon==0,
nopat)).solve(v,zero);
403 for(
int r=0; r<ncol; r++) null_vec.append(s(r,0).
subs(sRepl,
nopat));
405 null_cache.insert({key,null_vec});
407 null_vec = ex_to<lst>(null_itr->second);
412 for(
int c=0; c<ncol; c++) {
413 if(!is_zero(null_vec.op(c))) {
419 ex res = ApartIR(mat);
426 for(
int c=0; c<ncol; c++) {
427 if(mat(nrow+1,c)>0 && !is_zero(null_vec.op(c))) {
437 find(null_vec.op(ni),iWF(
w),wfs);
438 if(wfs.size()<1)
throw Error(
"Apart: something is wrong!");
443 auto n1 =
subs(null_vec, wf==s);
444 n1 =
subs(n1, iWF(
w)==0);
445 for(
int i=0; i<3; i++) {
446 auto n2 =
subs(n1, s==i);
447 if(!is_zero(n2.op(ni))) {
449 for(
auto ii : n2)
if(ii.is_zero()) nt++;
450 if(nt>max && nt!=ncol) { nvec = n2; max = nt; }
455 if(nvec.has(iWF(
w)) || is_zero(nvec.op(ni)))
throw Error(
"Apart: iWF to int failed with "+
ex2str(null_vec.op(ni)));
459 for(
int c=0; c<ncol; c++) {
461 sol -= nvec.op(c) * (iWF(c)-mat(nrow,c));
463 sol = sol/nvec.op(ni) + mat(nrow,ni);
466 if(!is_a<add>(sol)) sol = lst{ sol };
468 for(
auto item : sol) {
470 matrix mat2(nrow+2, ncol-1);
471 for(
int c=0; c<ncol; c++) {
473 int c2 = (c<ni ? c : c-1);
474 for(
int r=0; r<nrow+1; r++) {
475 mat2(r,c2) = mat(r,c);
477 auto expn = mat(nrow+1,c) + item.degree(iWF(c));
478 if(is_zero(expn)) nzero++;
479 mat2(nrow+1,c2) = expn;
482 if((ncol-1-nzero)==0) {
483 res += ApartIR(1) * item.subs(iWF(
w)==1);
485 matrix mat3(nrow+2, ncol-1-nzero);
487 for(
int c=0; c<ncol-1; c++) {
488 if(is_zero(mat2(nrow+1,c)))
continue;
489 for(
int r=0; r<nrow+2; r++) {
490 mat3(r,cc) = mat2(r,c);
494 res +=
Apart(mat3) * item.subs(iWF(
w)==1);
497 res +=
Apart(mat2) * item.subs(iWF(
w)==1);
507 for(
int c=0; c<ncol; c++) cres0 += mat(nrow,c)*null_vec.op(c);
513 find(lst{cres0, null_vec},iWF(
w),wfs);
522 auto c1 =
subs(cres0, wf==s);
523 auto n1 =
subs(null_vec, wf==s);
524 c1 =
subs(c1, iWF(
w)==0);
525 n1 =
subs(n1, iWF(
w)==0);
526 for(
int i=0; i<5; i++) {
527 auto c2 =
subs(c1, s==i).normal();
528 auto n2 =
subs(n1, s==i);
529 if(!c0 && c2.is_zero())
continue;
530 if(c0 && !c2.is_zero()) {
532 nvec = n2; cres = c2;
535 for(
auto ii : n2)
if(ii.is_zero()) nt++;
536 if(nt>max && nt!=ncol) { nvec = n2; cres = c2; max = nt; }
543 if(nvec.has(iWF(
w)) || cres.has(iWF(
w))) {
544 cout << cres0 <<
", " << null_vec << endl;
545 throw Error(
"Apart: iWF still left.");
551 for(
int c=0; c<ncol; c++) {
552 if(is_zero(nvec.op(c)))
continue;
553 if(is_zero(mat(nrow+1,c)+1)) {
554 matrix mat2(nrow+2,ncol-1);
556 for(
int cc=0; cc<ncol; cc++) {
558 for(
int r=0; r<nrow+2; r++) mat2(r,ccc)=mat(r,cc);
561 res +=
Apart(mat2) * nvec.op(c);
564 mat2(nrow+1,c) = mat2(nrow+1,c)+1;
565 res +=
Apart(mat2) * nvec.op(c);
574 for(
int c=0; c<ncol; c++) {
575 if(!is_zero(nvec.op(c))) {
582 for(
int c=0; c<ncol; c++) {
583 if(is_zero(nvec.op(c)) || c==ni)
continue;
584 if(is_zero(mat(nrow+1,c)+1)) {
585 matrix mat2(nrow+2,ncol-1);
587 for(
int cc=0; cc<ncol; cc++) {
589 for(
int r=0; r<nrow+2; r++) mat2(r,ccc)=mat(r,cc);
592 int ni2 = ni>c ? ni-1 : ni;
593 mat2(nrow+1,ni2) = mat2(nrow+1,ni2)-1;
594 res -=
Apart(mat2) * nvec.op(c);
597 mat2(nrow+1,c) = mat2(nrow+1,c)+1;
598 mat2(nrow+1,ni) = mat2(nrow+1,ni)-1;
599 res -=
Apart(mat2) * nvec.op(c);
602 res = res/nvec.op(ni);
616 ex
Apart(
const ex &expr_ino,
const lst &vars_in, exmap smap) {
618 if(!is_a<lst>(expr_ino)) {
621 for(
auto item : cv_lst) res += item.op(0) *
Apart(lst{item.op(1)}, vars_in, smap);
626 for(const_preorder_iterator i = res.preorder_begin(); i != res.preorder_end(); ++i) {
628 if(is_a<symbol>(e) || is_a<Pair>(e)) nlst.append(e);
630 for(
auto var : vars_in) nlst.append(var);
635 for(
auto ni : nlst) {
637 nrepl[ni] = ex(1)/pi;
642 if(!is_zero(chk))
throw Error(
"Apart@1 random check Failed.");
647 if(expr_ino.nops()!=1)
throw Error(
"Apart: wrong convention found!");
648 ex expr_in = expr_ino.op(0);
652 auto itr = cache.find(expr_in);
653 if(itr!=cache.end())
return itr->second;
657 for(
int i=0; i<vars_in.nops(); i++) {
658 auto v = vars_in.op(i);
659 Symbol s(
"_apX"+to_string(i));
665 for(
auto kv : smap) sgnmap[kv.first.subs(map1,
nopat)] = kv.second.
subs(map1,
nopat);
667 ex expr = expr_in.subs(map1,
nopat);
668 if(!is_a<mul>(expr)) expr = lst{expr};
672 for(
auto item : expr) {
681 if(!isOK(item,vars)) {
688 expr = expr_in.subs(map1,
nopat);
690 if(!is_a<mul>(expr)) expr = lst{expr};
695 map<ex,int,ex_is_less> count_ip;
697 for(
auto item : expr) {
706 if(!isOK(item,vars)) {
707 cout << expr_in << endl;
708 cout << item << endl;
709 throw Error(
"Apart: item is not linear wrt vars.");
713 if(is_a<power>(item)) {
722 bool has_sgn =
false;
727 if(itr != sgnmap.end() && !is_zero(itr->second)) si = itr->second;
729 pref /= pow(sign, nc);
736 auto cc = pc.coeff(v);
737 if(is_zero(cc) || !
key_exists(sgnmap,v) || is_zero(sgnmap[v]))
continue;
738 ex sign = sgnmap[v]/cc;
739 pref /= pow(sign, nc);
749 auto cc = pc.coeff(v);
750 if(is_zero(cc) || !is_a<numeric>(cc))
continue;
752 pref /= pow(sign, nc);
760 if(ie_map.find(-key) != ie_map.end()) {
761 cout << expr_ino << endl;
762 cout <<
"Item 1: " << ie_map[-key].subs(map2,
nopat) << endl;
763 cout <<
"Item 2: " << pc.subs(map2,
nopat) << endl;
764 throw Error(
"iEpsilon Error: maybe pinch singularity?");
769 auto itr = count_ip.find(key);
770 if(itr==count_ip.end()) itr = count_ip.find(-key);
771 if(itr==count_ip.end()) count_ip[key] = 1;
774 pnlst.append(lst{ pc, nc });
778 bool needs_again =
false;
779 for(
auto kv : count_ip) {
780 if(kv.second>1) { needs_again =
true;
break; }
784 for(
auto pn : pnlst) {
788 if(imap.find(-k) != imap.end()) {
789 cout <<
"Item 1: " << imap[k] << endl;
790 cout <<
"Item 2: " << key << endl;
791 throw Error(
"iEpsilon Error: maybe pinch singularity?");
793 if(imap.find(k)==imap.end()) imap[k] = key;
797 for(
auto pn : pnlst) {
799 auto itr = imap.find(key);
800 if(itr!=imap.end()) key = itr->second;
802 itr = imap.find(-key);
803 if(itr!=imap.end()) {
805 pref *= pow(-1, pn.op(1));
808 p2n[key] = p2n[key] + pn.op(1);
812 if(is_zero(kv.second))
continue;
815 if(is_a<numeric>(v) && ex_to<numeric>(v)>0) {
818 pnlst.append(lst{k, v});
823 if(pnlst.nops()==0)
return cache[expr_in] = pref * ApartIR(1,vars_in);
825 int nrow=vars.nops(), ncol=pnlst.nops();
827 for(
auto v : vars) vars0[v]=0;
828 matrix mat(nrow+2, ncol);
829 for(
int c=0; c<ncol; c++) {
831 if(pn.op(0).is_zero() && pn.op(1).is_zero())
throw Error(
"Apart: 0^0 is found!");
832 mat(nrow+1,c) = normal(pn.op(1));
834 for(
int r=0; r<nrow; r++) {
835 mat(r,c) =
exnormal(tmp.coeff(vars.op(r)));
844 for(
auto cv : cv_lst) {
845 ret += pref * cv.op(0) * ApartIR(cv.op(1).op(0), vars).subs(map2,
nopat);
848 return cache[expr_in] = ret;
859 ex
Apart(
const ex &expr_ino,
const lst &loops,
const lst & extps, exmap smap) {
864 for(
auto li : loops) {
865 for(
auto li2: loops) {
867 if(is_a<Pair>(item)) sps.append(item);
869 for(
auto ei: extps) {
871 if(is_a<Pair>(item)) sps.append(item);
879 for(
auto item : cv_lst) {
880 res += item.op(0) *
Apart(lst{item.op(1)}, sps, smap);
887 for(const_preorder_iterator i = res.preorder_begin(); i != res.preorder_end(); ++i) {
889 if(is_a<symbol>(e) || is_a<Pair>(e)) nlst.append(e);
895 for(
auto ni : nlst) {
903 throw Error(
"Apart@2 random check Failed.");
917 if(!e.has(ApartIR(
w1,
w2)))
return e;
918 else if(e.match(ApartIR(
w1,
w2))) {
919 auto i = cache.find(e);
920 if(i!=cache.end())
return i->second;
921 int n = e.op(1).nops();
922 if((e.op(0)).is_equal(1)) {
924 for(int r=0; r<n+2; r++) {
925 for(int c=0; c<n; c++) mat(r,c) = 0;
927 for(
int i=0; i<n; i++) mat(i,i) = 1;
928 return cache[e] = ApartIR(mat, e.op(1));
930 if(!is_a<matrix>(e.op(0)))
throw Error(
"ApartIRC: Not matrix : " +
ex2str(e.op(0)));
931 auto mat0 = ex_to<matrix>(e.op(0));
933 int cc = mat0.cols();
937 for(
int r=0; r<n+2; r++) {
938 for(
int c=0; c<cc; c++) mat(r,c) = 0;
941 for(
int r=0; r<n; r++) {
942 for(
int c=0; c<cc; c++) mat(r,c) = mat0(r,c);
944 for(
int i=0; i<n; i++) {
951 if(mat.rank()!=n)
throw Error(
"ApartIRC failed, NOT full rank.");
953 for(
int r=n; r<n+2; r++) {
954 for(
int c=0; c<mat0.cols(); c++) mat(r,c) = mat0(r,c);
957 return cache[e] = ApartIR(mat, e.op(1));
958 }
else return e.map(
self);
class used to wrap error message
interface to communicate with Fermat program
class to wrap map_function of GiNaC
class to parse for string or file, helpful with Symbol class
ex Read(const string &instr, bool s2S=true)
class extended to GiNaC symbol class, represent a positive symbol
ex subs(const exmap &m, unsigned options=0) const override
do_not_evalf_params().expl_derivative_func(zd1D).derivative_func(zp1D)) REGISTER_FUNCTION(FTX
ex pn2mat(ex ps, ex ns, ex vars)
ex Apart(const ex &expr_ino, const lst &loops, const lst &extps, exmap smap)
Apart on ex.
ex ApartIR2F(const ex &expr_in)
convert ApartIR to F(ps, ns), ns is like FIRE convention
ex ApartIRC(const ex &expr_in)
complete the ApartIR elements
ex collect_ex(ex const &expr_in, std::function< bool(const ex &)> has_func, int opt)
the collect function like Mathematica
ex ApartIR2ex(const ex &expr_in)
convert ApartIR to ex
bool key_exists(const exmap &map, const ex &key)
ex get_op(const ex ex_in, int index1, int index2)
return index1-th.index2-th of expression
ex exnormal(const ex &expr, int opt)
normalize a expression
ex nextprime(const ex &n)
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}, ... }
exmap ApartRules(const exvector &airs, bool irc)
void sort_lst(lst &ilst, bool less=true)
sort the list in less order, or the reverse
void string_replace_all(string &str, const string &from, const string &to)
bool is_subset(const ex &e1, const ex &e2)
string ex2str(const ex &expr)
convert ex to output string, the defalut printer format will be used
exvector GiNaC_Parallel(int ntotal, std::function< ex(int)> f, const string &key)
GiNaC Parallel Evaluation using fork.
void string_trim(string &str)
ex SP(const ex &a, bool use_map=false)
ex subs(const ex &e, init_list sl)