|
GiNaC
1.6.2
|
00001 00049 /* 00050 * GiNaC Copyright (C) 1999-2011 Johannes Gutenberg University Mainz, Germany 00051 * 00052 * This program is free software; you can redistribute it and/or modify 00053 * it under the terms of the GNU General Public License as published by 00054 * the Free Software Foundation; either version 2 of the License, or 00055 * (at your option) any later version. 00056 * 00057 * This program is distributed in the hope that it will be useful, 00058 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00059 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00060 * GNU General Public License for more details. 00061 * 00062 * You should have received a copy of the GNU General Public License 00063 * along with this program; if not, write to the Free Software 00064 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00065 */ 00066 00067 #include "inifcns.h" 00068 00069 #include "add.h" 00070 #include "constant.h" 00071 #include "lst.h" 00072 #include "mul.h" 00073 #include "numeric.h" 00074 #include "operators.h" 00075 #include "power.h" 00076 #include "pseries.h" 00077 #include "relational.h" 00078 #include "symbol.h" 00079 #include "utils.h" 00080 #include "wildcard.h" 00081 00082 #include <cln/cln.h> 00083 #include <sstream> 00084 #include <stdexcept> 00085 #include <vector> 00086 00087 namespace GiNaC { 00088 00089 00091 // 00092 // Classical polylogarithm Li(n,x) 00093 // 00094 // helper functions 00095 // 00097 00098 00099 // anonymous namespace for helper functions 00100 namespace { 00101 00102 00103 // lookup table for factors built from Bernoulli numbers 00104 // see fill_Xn() 00105 std::vector<std::vector<cln::cl_N> > Xn; 00106 // initial size of Xn that should suffice for 32bit machines (must be even) 00107 const int xninitsizestep = 26; 00108 int xninitsize = xninitsizestep; 00109 int xnsize = 0; 00110 00111 00112 // This function calculates the X_n. The X_n are needed for speed up of classical polylogarithms. 00113 // With these numbers the polylogs can be calculated as follows: 00114 // Li_p (x) = \sum_{n=0}^\infty X_{p-2}(n) u^{n+1}/(n+1)! with u = -log(1-x) 00115 // X_0(n) = B_n (Bernoulli numbers) 00116 // X_p(n) = \sum_{k=0}^n binomial(n,k) B_{n-k} / (k+1) * X_{p-1}(k) 00117 // The calculation of Xn depends on X0 and X{n-1}. 00118 // X_0 is special, it holds only the non-zero Bernoulli numbers with index 2 or greater. 00119 // This results in a slightly more complicated algorithm for the X_n. 00120 // The first index in Xn corresponds to the index of the polylog minus 2. 00121 // The second index in Xn corresponds to the index from the actual sum. 00122 void fill_Xn(int n) 00123 { 00124 if (n>1) { 00125 // calculate X_2 and higher (corresponding to Li_4 and higher) 00126 std::vector<cln::cl_N> buf(xninitsize); 00127 std::vector<cln::cl_N>::iterator it = buf.begin(); 00128 cln::cl_N result; 00129 *it = -(cln::expt(cln::cl_I(2),n+1) - 1) / cln::expt(cln::cl_I(2),n+1); // i == 1 00130 it++; 00131 for (int i=2; i<=xninitsize; i++) { 00132 if (i&1) { 00133 result = 0; // k == 0 00134 } else { 00135 result = Xn[0][i/2-1]; // k == 0 00136 } 00137 for (int k=1; k<i-1; k++) { 00138 if ( !(((i-k) & 1) && ((i-k) > 1)) ) { 00139 result = result + cln::binomial(i,k) * Xn[0][(i-k)/2-1] * Xn[n-1][k-1] / (k+1); 00140 } 00141 } 00142 result = result - cln::binomial(i,i-1) * Xn[n-1][i-2] / 2 / i; // k == i-1 00143 result = result + Xn[n-1][i-1] / (i+1); // k == i 00144 00145 *it = result; 00146 it++; 00147 } 00148 Xn.push_back(buf); 00149 } else if (n==1) { 00150 // special case to handle the X_0 correct 00151 std::vector<cln::cl_N> buf(xninitsize); 00152 std::vector<cln::cl_N>::iterator it = buf.begin(); 00153 cln::cl_N result; 00154 *it = cln::cl_I(-3)/cln::cl_I(4); // i == 1 00155 it++; 00156 *it = cln::cl_I(17)/cln::cl_I(36); // i == 2 00157 it++; 00158 for (int i=3; i<=xninitsize; i++) { 00159 if (i & 1) { 00160 result = -Xn[0][(i-3)/2]/2; 00161 *it = (cln::binomial(i,1)/cln::cl_I(2) + cln::binomial(i,i-1)/cln::cl_I(i))*result; 00162 it++; 00163 } else { 00164 result = Xn[0][i/2-1] + Xn[0][i/2-1]/(i+1); 00165 for (int k=1; k<i/2; k++) { 00166 result = result + cln::binomial(i,k*2) * Xn[0][k-1] * Xn[0][i/2-k-1] / (k*2+1); 00167 } 00168 *it = result; 00169 it++; 00170 } 00171 } 00172 Xn.push_back(buf); 00173 } else { 00174 // calculate X_0 00175 std::vector<cln::cl_N> buf(xninitsize/2); 00176 std::vector<cln::cl_N>::iterator it = buf.begin(); 00177 for (int i=1; i<=xninitsize/2; i++) { 00178 *it = bernoulli(i*2).to_cl_N(); 00179 it++; 00180 } 00181 Xn.push_back(buf); 00182 } 00183 00184 xnsize++; 00185 } 00186 00187 // doubles the number of entries in each Xn[] 00188 void double_Xn() 00189 { 00190 const int pos0 = xninitsize / 2; 00191 // X_0 00192 for (int i=1; i<=xninitsizestep/2; ++i) { 00193 Xn[0].push_back(bernoulli((i+pos0)*2).to_cl_N()); 00194 } 00195 if (Xn.size() > 1) { 00196 int xend = xninitsize + xninitsizestep; 00197 cln::cl_N result; 00198 // X_1 00199 for (int i=xninitsize+1; i<=xend; ++i) { 00200 if (i & 1) { 00201 result = -Xn[0][(i-3)/2]/2; 00202 Xn[1].push_back((cln::binomial(i,1)/cln::cl_I(2) + cln::binomial(i,i-1)/cln::cl_I(i))*result); 00203 } else { 00204 result = Xn[0][i/2-1] + Xn[0][i/2-1]/(i+1); 00205 for (int k=1; k<i/2; k++) { 00206 result = result + cln::binomial(i,k*2) * Xn[0][k-1] * Xn[0][i/2-k-1] / (k*2+1); 00207 } 00208 Xn[1].push_back(result); 00209 } 00210 } 00211 // X_n 00212 for (size_t n=2; n<Xn.size(); ++n) { 00213 for (int i=xninitsize+1; i<=xend; ++i) { 00214 if (i & 1) { 00215 result = 0; // k == 0 00216 } else { 00217 result = Xn[0][i/2-1]; // k == 0 00218 } 00219 for (int k=1; k<i-1; ++k) { 00220 if ( !(((i-k) & 1) && ((i-k) > 1)) ) { 00221 result = result + cln::binomial(i,k) * Xn[0][(i-k)/2-1] * Xn[n-1][k-1] / (k+1); 00222 } 00223 } 00224 result = result - cln::binomial(i,i-1) * Xn[n-1][i-2] / 2 / i; // k == i-1 00225 result = result + Xn[n-1][i-1] / (i+1); // k == i 00226 Xn[n].push_back(result); 00227 } 00228 } 00229 } 00230 xninitsize += xninitsizestep; 00231 } 00232 00233 00234 // calculates Li(2,x) without Xn 00235 cln::cl_N Li2_do_sum(const cln::cl_N& x) 00236 { 00237 cln::cl_N res = x; 00238 cln::cl_N resbuf; 00239 cln::cl_N num = x * cln::cl_float(1, cln::float_format(Digits)); 00240 cln::cl_I den = 1; // n^2 = 1 00241 unsigned i = 3; 00242 do { 00243 resbuf = res; 00244 num = num * x; 00245 den = den + i; // n^2 = 4, 9, 16, ... 00246 i += 2; 00247 res = res + num / den; 00248 } while (res != resbuf); 00249 return res; 00250 } 00251 00252 00253 // calculates Li(2,x) with Xn 00254 cln::cl_N Li2_do_sum_Xn(const cln::cl_N& x) 00255 { 00256 std::vector<cln::cl_N>::const_iterator it = Xn[0].begin(); 00257 std::vector<cln::cl_N>::const_iterator xend = Xn[0].end(); 00258 cln::cl_N u = -cln::log(1-x); 00259 cln::cl_N factor = u * cln::cl_float(1, cln::float_format(Digits)); 00260 cln::cl_N uu = cln::square(u); 00261 cln::cl_N res = u - uu/4; 00262 cln::cl_N resbuf; 00263 unsigned i = 1; 00264 do { 00265 resbuf = res; 00266 factor = factor * uu / (2*i * (2*i+1)); 00267 res = res + (*it) * factor; 00268 i++; 00269 if (++it == xend) { 00270 double_Xn(); 00271 it = Xn[0].begin() + (i-1); 00272 xend = Xn[0].end(); 00273 } 00274 } while (res != resbuf); 00275 return res; 00276 } 00277 00278 00279 // calculates Li(n,x), n>2 without Xn 00280 cln::cl_N Lin_do_sum(int n, const cln::cl_N& x) 00281 { 00282 cln::cl_N factor = x * cln::cl_float(1, cln::float_format(Digits)); 00283 cln::cl_N res = x; 00284 cln::cl_N resbuf; 00285 int i=2; 00286 do { 00287 resbuf = res; 00288 factor = factor * x; 00289 res = res + factor / cln::expt(cln::cl_I(i),n); 00290 i++; 00291 } while (res != resbuf); 00292 return res; 00293 } 00294 00295 00296 // calculates Li(n,x), n>2 with Xn 00297 cln::cl_N Lin_do_sum_Xn(int n, const cln::cl_N& x) 00298 { 00299 std::vector<cln::cl_N>::const_iterator it = Xn[n-2].begin(); 00300 std::vector<cln::cl_N>::const_iterator xend = Xn[n-2].end(); 00301 cln::cl_N u = -cln::log(1-x); 00302 cln::cl_N factor = u * cln::cl_float(1, cln::float_format(Digits)); 00303 cln::cl_N res = u; 00304 cln::cl_N resbuf; 00305 unsigned i=2; 00306 do { 00307 resbuf = res; 00308 factor = factor * u / i; 00309 res = res + (*it) * factor; 00310 i++; 00311 if (++it == xend) { 00312 double_Xn(); 00313 it = Xn[n-2].begin() + (i-2); 00314 xend = Xn[n-2].end(); 00315 } 00316 } while (res != resbuf); 00317 return res; 00318 } 00319 00320 00321 // forward declaration needed by function Li_projection and C below 00322 const cln::cl_N S_num(int n, int p, const cln::cl_N& x); 00323 00324 00325 // helper function for classical polylog Li 00326 cln::cl_N Li_projection(int n, const cln::cl_N& x, const cln::float_format_t& prec) 00327 { 00328 // treat n=2 as special case 00329 if (n == 2) { 00330 // check if precalculated X0 exists 00331 if (xnsize == 0) { 00332 fill_Xn(0); 00333 } 00334 00335 if (cln::realpart(x) < 0.5) { 00336 // choose the faster algorithm 00337 // the switching point was empirically determined. the optimal point 00338 // depends on hardware, Digits, ... so an approx value is okay. 00339 // it solves also the problem with precision due to the u=-log(1-x) transformation 00340 if (cln::abs(cln::realpart(x)) < 0.25) { 00341 00342 return Li2_do_sum(x); 00343 } else { 00344 return Li2_do_sum_Xn(x); 00345 } 00346 } else { 00347 // choose the faster algorithm 00348 if (cln::abs(cln::realpart(x)) > 0.75) { 00349 return -Li2_do_sum(1-x) - cln::log(x) * cln::log(1-x) + cln::zeta(2); 00350 } else { 00351 return -Li2_do_sum_Xn(1-x) - cln::log(x) * cln::log(1-x) + cln::zeta(2); 00352 } 00353 } 00354 } else { 00355 // check if precalculated Xn exist 00356 if (n > xnsize+1) { 00357 for (int i=xnsize; i<n-1; i++) { 00358 fill_Xn(i); 00359 } 00360 } 00361 00362 if (cln::realpart(x) < 0.5) { 00363 // choose the faster algorithm 00364 // with n>=12 the "normal" summation always wins against the method with Xn 00365 if ((cln::abs(cln::realpart(x)) < 0.3) || (n >= 12)) { 00366 return Lin_do_sum(n, x); 00367 } else { 00368 return Lin_do_sum_Xn(n, x); 00369 } 00370 } else { 00371 cln::cl_N result = -cln::expt(cln::log(x), n-1) * cln::log(1-x) / cln::factorial(n-1); 00372 for (int j=0; j<n-1; j++) { 00373 result = result + (S_num(n-j-1, 1, 1) - S_num(1, n-j-1, 1-x)) 00374 * cln::expt(cln::log(x), j) / cln::factorial(j); 00375 } 00376 return result; 00377 } 00378 } 00379 } 00380 00381 // helper function for classical polylog Li 00382 const cln::cl_N Lin_numeric(const int n, const cln::cl_N& x) 00383 { 00384 if (n == 1) { 00385 // just a log 00386 return -cln::log(1-x); 00387 } 00388 if (zerop(x)) { 00389 return 0; 00390 } 00391 if (x == 1) { 00392 // [Kol] (2.22) 00393 return cln::zeta(n); 00394 } 00395 else if (x == -1) { 00396 // [Kol] (2.22) 00397 return -(1-cln::expt(cln::cl_I(2),1-n)) * cln::zeta(n); 00398 } 00399 if (cln::abs(realpart(x)) < 0.4 && cln::abs(cln::abs(x)-1) < 0.01) { 00400 cln::cl_N result = -cln::expt(cln::log(x), n-1) * cln::log(1-x) / cln::factorial(n-1); 00401 for (int j=0; j<n-1; j++) { 00402 result = result + (S_num(n-j-1, 1, 1) - S_num(1, n-j-1, 1-x)) 00403 * cln::expt(cln::log(x), j) / cln::factorial(j); 00404 } 00405 return result; 00406 } 00407 00408 // what is the desired float format? 00409 // first guess: default format 00410 cln::float_format_t prec = cln::default_float_format; 00411 const cln::cl_N value = x; 00412 // second guess: the argument's format 00413 if (!instanceof(realpart(x), cln::cl_RA_ring)) 00414 prec = cln::float_format(cln::the<cln::cl_F>(cln::realpart(value))); 00415 else if (!instanceof(imagpart(x), cln::cl_RA_ring)) 00416 prec = cln::float_format(cln::the<cln::cl_F>(cln::imagpart(value))); 00417 00418 // [Kol] (5.15) 00419 if (cln::abs(value) > 1) { 00420 cln::cl_N result = -cln::expt(cln::log(-value),n) / cln::factorial(n); 00421 // check if argument is complex. if it is real, the new polylog has to be conjugated. 00422 if (cln::zerop(cln::imagpart(value))) { 00423 if (n & 1) { 00424 result = result + conjugate(Li_projection(n, cln::recip(value), prec)); 00425 } 00426 else { 00427 result = result - conjugate(Li_projection(n, cln::recip(value), prec)); 00428 } 00429 } 00430 else { 00431 if (n & 1) { 00432 result = result + Li_projection(n, cln::recip(value), prec); 00433 } 00434 else { 00435 result = result - Li_projection(n, cln::recip(value), prec); 00436 } 00437 } 00438 cln::cl_N add; 00439 for (int j=0; j<n-1; j++) { 00440 add = add + (1+cln::expt(cln::cl_I(-1),n-j)) * (1-cln::expt(cln::cl_I(2),1-n+j)) 00441 * Lin_numeric(n-j,1) * cln::expt(cln::log(-value),j) / cln::factorial(j); 00442 } 00443 result = result - add; 00444 return result; 00445 } 00446 else { 00447 return Li_projection(n, value, prec); 00448 } 00449 } 00450 00451 00452 } // end of anonymous namespace 00453 00454 00456 // 00457 // Multiple polylogarithm Li(n,x) 00458 // 00459 // helper function 00460 // 00462 00463 00464 // anonymous namespace for helper function 00465 namespace { 00466 00467 00468 // performs the actual series summation for multiple polylogarithms 00469 cln::cl_N multipleLi_do_sum(const std::vector<int>& s, const std::vector<cln::cl_N>& x) 00470 { 00471 // ensure all x <> 0. 00472 for (std::vector<cln::cl_N>::const_iterator it = x.begin(); it != x.end(); ++it) { 00473 if ( *it == 0 ) return cln::cl_float(0, cln::float_format(Digits)); 00474 } 00475 00476 const int j = s.size(); 00477 bool flag_accidental_zero = false; 00478 00479 std::vector<cln::cl_N> t(j); 00480 cln::cl_F one = cln::cl_float(1, cln::float_format(Digits)); 00481 00482 cln::cl_N t0buf; 00483 int q = 0; 00484 do { 00485 t0buf = t[0]; 00486 q++; 00487 t[j-1] = t[j-1] + cln::expt(x[j-1], q) / cln::expt(cln::cl_I(q),s[j-1]) * one; 00488 for (int k=j-2; k>=0; k--) { 00489 t[k] = t[k] + t[k+1] * cln::expt(x[k], q+j-1-k) / cln::expt(cln::cl_I(q+j-1-k), s[k]); 00490 } 00491 q++; 00492 t[j-1] = t[j-1] + cln::expt(x[j-1], q) / cln::expt(cln::cl_I(q),s[j-1]) * one; 00493 for (int k=j-2; k>=0; k--) { 00494 flag_accidental_zero = cln::zerop(t[k+1]); 00495 t[k] = t[k] + t[k+1] * cln::expt(x[k], q+j-1-k) / cln::expt(cln::cl_I(q+j-1-k), s[k]); 00496 } 00497 } while ( (t[0] != t0buf) || cln::zerop(t[0]) || flag_accidental_zero ); 00498 00499 return t[0]; 00500 } 00501 00502 00503 // forward declaration for Li_eval() 00504 lst convert_parameter_Li_to_H(const lst& m, const lst& x, ex& pf); 00505 00506 00507 // type used by the transformation functions for G 00508 typedef std::vector<int> Gparameter; 00509 00510 00511 // G_eval1-function for G transformations 00512 ex G_eval1(int a, int scale, const exvector& gsyms) 00513 { 00514 if (a != 0) { 00515 const ex& scs = gsyms[std::abs(scale)]; 00516 const ex& as = gsyms[std::abs(a)]; 00517 if (as != scs) { 00518 return -log(1 - scs/as); 00519 } else { 00520 return -zeta(1); 00521 } 00522 } else { 00523 return log(gsyms[std::abs(scale)]); 00524 } 00525 } 00526 00527 00528 // G_eval-function for G transformations 00529 ex G_eval(const Gparameter& a, int scale, const exvector& gsyms) 00530 { 00531 // check for properties of G 00532 ex sc = gsyms[std::abs(scale)]; 00533 lst newa; 00534 bool all_zero = true; 00535 bool all_ones = true; 00536 int count_ones = 0; 00537 for (Gparameter::const_iterator it = a.begin(); it != a.end(); ++it) { 00538 if (*it != 0) { 00539 const ex sym = gsyms[std::abs(*it)]; 00540 newa.append(sym); 00541 all_zero = false; 00542 if (sym != sc) { 00543 all_ones = false; 00544 } 00545 if (all_ones) { 00546 ++count_ones; 00547 } 00548 } else { 00549 all_ones = false; 00550 } 00551 } 00552 00553 // care about divergent G: shuffle to separate divergencies that will be canceled 00554 // later on in the transformation 00555 if (newa.nops() > 1 && newa.op(0) == sc && !all_ones && a.front()!=0) { 00556 // do shuffle 00557 Gparameter short_a; 00558 Gparameter::const_iterator it = a.begin(); 00559 ++it; 00560 for (; it != a.end(); ++it) { 00561 short_a.push_back(*it); 00562 } 00563 ex result = G_eval1(a.front(), scale, gsyms) * G_eval(short_a, scale, gsyms); 00564 it = short_a.begin(); 00565 for (int i=1; i<count_ones; ++i) { 00566 ++it; 00567 } 00568 for (; it != short_a.end(); ++it) { 00569 00570 Gparameter newa; 00571 Gparameter::const_iterator it2 = short_a.begin(); 00572 for (; it2 != it; ++it2) { 00573 newa.push_back(*it2); 00574 } 00575 newa.push_back(*it); 00576 newa.push_back(a[0]); 00577 it2 = it; 00578 ++it2; 00579 for (; it2 != short_a.end(); ++it2) { 00580 newa.push_back(*it2); 00581 } 00582 result -= G_eval(newa, scale, gsyms); 00583 } 00584 return result / count_ones; 00585 } 00586 00587 // G({1,...,1};y) -> G({1};y)^k / k! 00588 if (all_ones && a.size() > 1) { 00589 return pow(G_eval1(a.front(),scale, gsyms), count_ones) / factorial(count_ones); 00590 } 00591 00592 // G({0,...,0};y) -> log(y)^k / k! 00593 if (all_zero) { 00594 return pow(log(gsyms[std::abs(scale)]), a.size()) / factorial(a.size()); 00595 } 00596 00597 // no special cases anymore -> convert it into Li 00598 lst m; 00599 lst x; 00600 ex argbuf = gsyms[std::abs(scale)]; 00601 ex mval = _ex1; 00602 for (Gparameter::const_iterator it=a.begin(); it!=a.end(); ++it) { 00603 if (*it != 0) { 00604 const ex& sym = gsyms[std::abs(*it)]; 00605 x.append(argbuf / sym); 00606 m.append(mval); 00607 mval = _ex1; 00608 argbuf = sym; 00609 } else { 00610 ++mval; 00611 } 00612 } 00613 return pow(-1, x.nops()) * Li(m, x); 00614 } 00615 00616 00617 // converts data for G: pending_integrals -> a 00618 Gparameter convert_pending_integrals_G(const Gparameter& pending_integrals) 00619 { 00620 GINAC_ASSERT(pending_integrals.size() != 1); 00621 00622 if (pending_integrals.size() > 0) { 00623 // get rid of the first element, which would stand for the new upper limit 00624 Gparameter new_a(pending_integrals.begin()+1, pending_integrals.end()); 00625 return new_a; 00626 } else { 00627 // just return empty parameter list 00628 Gparameter new_a; 00629 return new_a; 00630 } 00631 } 00632 00633 00634 // check the parameters a and scale for G and return information about convergence, depth, etc. 00635 // convergent : true if G(a,scale) is convergent 00636 // depth : depth of G(a,scale) 00637 // trailing_zeros : number of trailing zeros of a 00638 // min_it : iterator of a pointing on the smallest element in a 00639 Gparameter::const_iterator check_parameter_G(const Gparameter& a, int scale, 00640 bool& convergent, int& depth, int& trailing_zeros, Gparameter::const_iterator& min_it) 00641 { 00642 convergent = true; 00643 depth = 0; 00644 trailing_zeros = 0; 00645 min_it = a.end(); 00646 Gparameter::const_iterator lastnonzero = a.end(); 00647 for (Gparameter::const_iterator it = a.begin(); it != a.end(); ++it) { 00648 if (std::abs(*it) > 0) { 00649 ++depth; 00650 trailing_zeros = 0; 00651 lastnonzero = it; 00652 if (std::abs(*it) < scale) { 00653 convergent = false; 00654 if ((min_it == a.end()) || (std::abs(*it) < std::abs(*min_it))) { 00655 min_it = it; 00656 } 00657 } 00658 } else { 00659 ++trailing_zeros; 00660 } 00661 } 00662 if (lastnonzero == a.end()) 00663 return a.end(); 00664 return ++lastnonzero; 00665 } 00666 00667 00668 // add scale to pending_integrals if pending_integrals is empty 00669 Gparameter prepare_pending_integrals(const Gparameter& pending_integrals, int scale) 00670 { 00671 GINAC_ASSERT(pending_integrals.size() != 1); 00672 00673 if (pending_integrals.size() > 0) { 00674 return pending_integrals; 00675 } else { 00676 Gparameter new_pending_integrals; 00677 new_pending_integrals.push_back(scale); 00678 return new_pending_integrals; 00679 } 00680 } 00681 00682 00683 // handles trailing zeroes for an otherwise convergent integral 00684 ex trailing_zeros_G(const Gparameter& a, int scale, const exvector& gsyms) 00685 { 00686 bool convergent; 00687 int depth, trailing_zeros; 00688 Gparameter::const_iterator last, dummyit; 00689 last = check_parameter_G(a, scale, convergent, depth, trailing_zeros, dummyit); 00690 00691 GINAC_ASSERT(convergent); 00692 00693 if ((trailing_zeros > 0) && (depth > 0)) { 00694 ex result; 00695 Gparameter new_a(a.begin(), a.end()-1); 00696 result += G_eval1(0, scale, gsyms) * trailing_zeros_G(new_a, scale, gsyms); 00697 for (Gparameter::const_iterator it = a.begin(); it != last; ++it) { 00698 Gparameter new_a(a.begin(), it); 00699 new_a.push_back(0); 00700 new_a.insert(new_a.end(), it, a.end()-1); 00701 result -= trailing_zeros_G(new_a, scale, gsyms); 00702 } 00703 00704 return result / trailing_zeros; 00705 } else { 00706 return G_eval(a, scale, gsyms); 00707 } 00708 } 00709 00710 00711 // G transformation [VSW] (57),(58) 00712 ex depth_one_trafo_G(const Gparameter& pending_integrals, const Gparameter& a, int scale, const exvector& gsyms) 00713 { 00714 // pendint = ( y1, b1, ..., br ) 00715 // a = ( 0, ..., 0, amin ) 00716 // scale = y2 00717 // 00718 // int_0^y1 ds1/(s1-b1) ... int dsr/(sr-br) G(0, ..., 0, sr; y2) 00719 // where sr replaces amin 00720 00721 GINAC_ASSERT(a.back() != 0); 00722 GINAC_ASSERT(a.size() > 0); 00723 00724 ex result; 00725 Gparameter new_pending_integrals = prepare_pending_integrals(pending_integrals, std::abs(a.back())); 00726 const int psize = pending_integrals.size(); 00727 00728 // length == 1 00729 // G(sr_{+-}; y2 ) = G(y2_{-+}; sr) - G(0; sr) + ln(-y2_{-+}) 00730 00731 if (a.size() == 1) { 00732 00733 // ln(-y2_{-+}) 00734 result += log(gsyms[ex_to<numeric>(scale).to_int()]); 00735 if (a.back() > 0) { 00736 new_pending_integrals.push_back(-scale); 00737 result += I*Pi; 00738 } else { 00739 new_pending_integrals.push_back(scale); 00740 result -= I*Pi; 00741 } 00742 if (psize) { 00743 result *= trailing_zeros_G(convert_pending_integrals_G(pending_integrals), 00744 pending_integrals.front(), 00745 gsyms); 00746 } 00747 00748 // G(y2_{-+}; sr) 00749 result += trailing_zeros_G(convert_pending_integrals_G(new_pending_integrals), 00750 new_pending_integrals.front(), 00751 gsyms); 00752 00753 // G(0; sr) 00754 new_pending_integrals.back() = 0; 00755 result -= trailing_zeros_G(convert_pending_integrals_G(new_pending_integrals), 00756 new_pending_integrals.front(), 00757 gsyms); 00758 00759 return result; 00760 } 00761 00762 // length > 1 00763 // G_m(sr_{+-}; y2) = -zeta_m + int_0^y2 dt/t G_{m-1}( (1/y2)_{+-}; 1/t ) 00764 // - int_0^sr dt/t G_{m-1}( (1/y2)_{+-}; 1/t ) 00765 00766 //term zeta_m 00767 result -= zeta(a.size()); 00768 if (psize) { 00769 result *= trailing_zeros_G(convert_pending_integrals_G(pending_integrals), 00770 pending_integrals.front(), 00771 gsyms); 00772 } 00773 00774 // term int_0^sr dt/t G_{m-1}( (1/y2)_{+-}; 1/t ) 00775 // = int_0^sr dt/t G_{m-1}( t_{+-}; y2 ) 00776 Gparameter new_a(a.begin()+1, a.end()); 00777 new_pending_integrals.push_back(0); 00778 result -= depth_one_trafo_G(new_pending_integrals, new_a, scale, gsyms); 00779 00780 // term int_0^y2 dt/t G_{m-1}( (1/y2)_{+-}; 1/t ) 00781 // = int_0^y2 dt/t G_{m-1}( t_{+-}; y2 ) 00782 Gparameter new_pending_integrals_2; 00783 new_pending_integrals_2.push_back(scale); 00784 new_pending_integrals_2.push_back(0); 00785 if (psize) { 00786 result += trailing_zeros_G(convert_pending_integrals_G(pending_integrals), 00787 pending_integrals.front(), 00788 gsyms) 00789 * depth_one_trafo_G(new_pending_integrals_2, new_a, scale, gsyms); 00790 } else { 00791 result += depth_one_trafo_G(new_pending_integrals_2, new_a, scale, gsyms); 00792 } 00793 00794 return result; 00795 } 00796 00797 00798 // forward declaration 00799 ex shuffle_G(const Gparameter & a0, const Gparameter & a1, const Gparameter & a2, 00800 const Gparameter& pendint, const Gparameter& a_old, int scale, 00801 const exvector& gsyms); 00802 00803 00804 // G transformation [VSW] 00805 ex G_transform(const Gparameter& pendint, const Gparameter& a, int scale, 00806 const exvector& gsyms) 00807 { 00808 // main recursion routine 00809 // 00810 // pendint = ( y1, b1, ..., br ) 00811 // a = ( a1, ..., amin, ..., aw ) 00812 // scale = y2 00813 // 00814 // int_0^y1 ds1/(s1-b1) ... int dsr/(sr-br) G(a1,...,sr,...,aw,y2) 00815 // where sr replaces amin 00816 00817 // find smallest alpha, determine depth and trailing zeros, and check for convergence 00818 bool convergent; 00819 int depth, trailing_zeros; 00820 Gparameter::const_iterator min_it; 00821 Gparameter::const_iterator firstzero = 00822 check_parameter_G(a, scale, convergent, depth, trailing_zeros, min_it); 00823 int min_it_pos = min_it - a.begin(); 00824 00825 // special case: all a's are zero 00826 if (depth == 0) { 00827 ex result; 00828 00829 if (a.size() == 0) { 00830 result = 1; 00831 } else { 00832 result = G_eval(a, scale, gsyms); 00833 } 00834 if (pendint.size() > 0) { 00835 result *= trailing_zeros_G(convert_pending_integrals_G(pendint), 00836 pendint.front(), 00837 gsyms); 00838 } 00839 return result; 00840 } 00841 00842 // handle trailing zeros 00843 if (trailing_zeros > 0) { 00844 ex result; 00845 Gparameter new_a(a.begin(), a.end()-1); 00846 result += G_eval1(0, scale, gsyms) * G_transform(pendint, new_a, scale, gsyms); 00847 for (Gparameter::const_iterator it = a.begin(); it != firstzero; ++it) { 00848 Gparameter new_a(a.begin(), it); 00849 new_a.push_back(0); 00850 new_a.insert(new_a.end(), it, a.end()-1); 00851 result -= G_transform(pendint, new_a, scale, gsyms); 00852 } 00853 return result / trailing_zeros; 00854 } 00855 00856 // convergence case 00857 if (convergent) { 00858 if (pendint.size() > 0) { 00859 return G_eval(convert_pending_integrals_G(pendint), 00860 pendint.front(), gsyms)* 00861 G_eval(a, scale, gsyms); 00862 } else { 00863 return G_eval(a, scale, gsyms); 00864 } 00865 } 00866 00867 // call basic transformation for depth equal one 00868 if (depth == 1) { 00869 return depth_one_trafo_G(pendint, a, scale, gsyms); 00870 } 00871 00872 // do recursion 00873 // int_0^y1 ds1/(s1-b1) ... int dsr/(sr-br) G(a1,...,sr,...,aw,y2) 00874 // = int_0^y1 ds1/(s1-b1) ... int dsr/(sr-br) G(a1,...,0,...,aw,y2) 00875 // + int_0^y1 ds1/(s1-b1) ... int dsr/(sr-br) int_0^{sr} ds_{r+1} d/ds_{r+1} G(a1,...,s_{r+1},...,aw,y2) 00876 00877 // smallest element in last place 00878 if (min_it + 1 == a.end()) { 00879 do { --min_it; } while (*min_it == 0); 00880 Gparameter empty; 00881 Gparameter a1(a.begin(),min_it+1); 00882 Gparameter a2(min_it+1,a.end()); 00883 00884 ex result = G_transform(pendint, a2, scale, gsyms)* 00885 G_transform(empty, a1, scale, gsyms); 00886 00887 result -= shuffle_G(empty, a1, a2, pendint, a, scale, gsyms); 00888 return result; 00889 } 00890 00891 Gparameter empty; 00892 Gparameter::iterator changeit; 00893 00894 // first term G(a_1,..,0,...,a_w;a_0) 00895 Gparameter new_pendint = prepare_pending_integrals(pendint, a[min_it_pos]); 00896 Gparameter new_a = a; 00897 new_a[min_it_pos] = 0; 00898 ex result = G_transform(empty, new_a, scale, gsyms); 00899 if (pendint.size() > 0) { 00900 result *= trailing_zeros_G(convert_pending_integrals_G(pendint), 00901 pendint.front(), gsyms); 00902 } 00903 00904 // other terms 00905 changeit = new_a.begin() + min_it_pos; 00906 changeit = new_a.erase(changeit); 00907 if (changeit != new_a.begin()) { 00908 // smallest in the middle 00909 new_pendint.push_back(*changeit); 00910 result -= trailing_zeros_G(convert_pending_integrals_G(new_pendint), 00911 new_pendint.front(), gsyms)* 00912 G_transform(empty, new_a, scale, gsyms); 00913 int buffer = *changeit; 00914 *changeit = *min_it; 00915 result += G_transform(new_pendint, new_a, scale, gsyms); 00916 *changeit = buffer; 00917 new_pendint.pop_back(); 00918 --changeit; 00919 new_pendint.push_back(*changeit); 00920 result += trailing_zeros_G(convert_pending_integrals_G(new_pendint), 00921 new_pendint.front(), gsyms)* 00922 G_transform(empty, new_a, scale, gsyms); 00923 *changeit = *min_it; 00924 result -= G_transform(new_pendint, new_a, scale, gsyms); 00925 } else { 00926 // smallest at the front 00927 new_pendint.push_back(scale); 00928 result += trailing_zeros_G(convert_pending_integrals_G(new_pendint), 00929 new_pendint.front(), gsyms)* 00930 G_transform(empty, new_a, scale, gsyms); 00931 new_pendint.back() = *changeit; 00932 result -= trailing_zeros_G(convert_pending_integrals_G(new_pendint), 00933 new_pendint.front(), gsyms)* 00934 G_transform(empty, new_a, scale, gsyms); 00935 *changeit = *min_it; 00936 result += G_transform(new_pendint, new_a, scale, gsyms); 00937 } 00938 return result; 00939 } 00940 00941 00942 // shuffles the two parameter list a1 and a2 and calls G_transform for every term except 00943 // for the one that is equal to a_old 00944 ex shuffle_G(const Gparameter & a0, const Gparameter & a1, const Gparameter & a2, 00945 const Gparameter& pendint, const Gparameter& a_old, int scale, 00946 const exvector& gsyms) 00947 { 00948 if (a1.size()==0 && a2.size()==0) { 00949 // veto the one configuration we don't want 00950 if ( a0 == a_old ) return 0; 00951 00952 return G_transform(pendint, a0, scale, gsyms); 00953 } 00954 00955 if (a2.size()==0) { 00956 Gparameter empty; 00957 Gparameter aa0 = a0; 00958 aa0.insert(aa0.end(),a1.begin(),a1.end()); 00959 return shuffle_G(aa0, empty, empty, pendint, a_old, scale, gsyms); 00960 } 00961 00962 if (a1.size()==0) { 00963 Gparameter empty; 00964 Gparameter aa0 = a0; 00965 aa0.insert(aa0.end(),a2.begin(),a2.end()); 00966 return shuffle_G(aa0, empty, empty, pendint, a_old, scale, gsyms); 00967 } 00968 00969 Gparameter a1_removed(a1.begin()+1,a1.end()); 00970 Gparameter a2_removed(a2.begin()+1,a2.end()); 00971 00972 Gparameter a01 = a0; 00973 Gparameter a02 = a0; 00974 00975 a01.push_back( a1[0] ); 00976 a02.push_back( a2[0] ); 00977 00978 return shuffle_G(a01, a1_removed, a2, pendint, a_old, scale, gsyms) 00979 + shuffle_G(a02, a1, a2_removed, pendint, a_old, scale, gsyms); 00980 } 00981 00982 // handles the transformations and the numerical evaluation of G 00983 // the parameter x, s and y must only contain numerics 00984 static cln::cl_N 00985 G_numeric(const std::vector<cln::cl_N>& x, const std::vector<int>& s, 00986 const cln::cl_N& y); 00987 00988 // do acceleration transformation (hoelder convolution [BBB]) 00989 // the parameter x, s and y must only contain numerics 00990 static cln::cl_N 00991 G_do_hoelder(std::vector<cln::cl_N> x, /* yes, it's passed by value */ 00992 const std::vector<int>& s, const cln::cl_N& y) 00993 { 00994 cln::cl_N result; 00995 const std::size_t size = x.size(); 00996 for (std::size_t i = 0; i < size; ++i) 00997 x[i] = x[i]/y; 00998 00999 for (std::size_t r = 0; r <= size; ++r) { 01000 cln::cl_N buffer(1 & r ? -1 : 1); 01001 cln::cl_RA p(2); 01002 bool adjustp; 01003 do { 01004 adjustp = false; 01005 for (std::size_t i = 0; i < size; ++i) { 01006 if (x[i] == cln::cl_RA(1)/p) { 01007 p = p/2 + cln::cl_RA(3)/2; 01008 adjustp = true; 01009 continue; 01010 } 01011 } 01012 } while (adjustp); 01013 cln::cl_RA q = p/(p-1); 01014 std::vector<cln::cl_N> qlstx; 01015 std::vector<int> qlsts; 01016 for (std::size_t j = r; j >= 1; --j) { 01017 qlstx.push_back(cln::cl_N(1) - x[j-1]); 01018 if (instanceof(x[j-1], cln::cl_R_ring) && 01019 realpart(x[j-1]) > 1 && realpart(x[j-1]) <= 2) { 01020 qlsts.push_back(s[j-1]); 01021 } else { 01022 qlsts.push_back(-s[j-1]); 01023 } 01024 } 01025 if (qlstx.size() > 0) { 01026 buffer = buffer*G_numeric(qlstx, qlsts, 1/q); 01027 } 01028 std::vector<cln::cl_N> plstx; 01029 std::vector<int> plsts; 01030 for (std::size_t j = r+1; j <= size; ++j) { 01031 plstx.push_back(x[j-1]); 01032 plsts.push_back(s[j-1]); 01033 } 01034 if (plstx.size() > 0) { 01035 buffer = buffer*G_numeric(plstx, plsts, 1/p); 01036 } 01037 result = result + buffer; 01038 } 01039 return result; 01040 } 01041 01042 // convergence transformation, used for numerical evaluation of G function. 01043 // the parameter x, s and y must only contain numerics 01044 static cln::cl_N 01045 G_do_trafo(const std::vector<cln::cl_N>& x, const std::vector<int>& s, 01046 const cln::cl_N& y) 01047 { 01048 // sort (|x|<->position) to determine indices 01049 typedef std::multimap<cln::cl_R, std::size_t> sortmap_t; 01050 sortmap_t sortmap; 01051 std::size_t size = 0; 01052 for (std::size_t i = 0; i < x.size(); ++i) { 01053 if (!zerop(x[i])) { 01054 sortmap.insert(std::make_pair(abs(x[i]), i)); 01055 ++size; 01056 } 01057 } 01058 // include upper limit (scale) 01059 sortmap.insert(std::make_pair(abs(y), x.size())); 01060 01061 // generate missing dummy-symbols 01062 int i = 1; 01063 // holding dummy-symbols for the G/Li transformations 01064 exvector gsyms; 01065 gsyms.push_back(symbol("GSYMS_ERROR")); 01066 cln::cl_N lastentry(0); 01067 for (sortmap_t::const_iterator it = sortmap.begin(); it != sortmap.end(); ++it) { 01068 if (it != sortmap.begin()) { 01069 if (it->second < x.size()) { 01070 if (x[it->second] == lastentry) { 01071 gsyms.push_back(gsyms.back()); 01072 continue; 01073 } 01074 } else { 01075 if (y == lastentry) { 01076 gsyms.push_back(gsyms.back()); 01077 continue; 01078 } 01079 } 01080 } 01081 std::ostringstream os; 01082 os << "a" << i; 01083 gsyms.push_back(symbol(os.str())); 01084 ++i; 01085 if (it->second < x.size()) { 01086 lastentry = x[it->second]; 01087 } else { 01088 lastentry = y; 01089 } 01090 } 01091 01092 // fill position data according to sorted indices and prepare substitution list 01093 Gparameter a(x.size()); 01094 exmap subslst; 01095 std::size_t pos = 1; 01096 int scale = pos; 01097 for (sortmap_t::const_iterator it = sortmap.begin(); it != sortmap.end(); ++it) { 01098 if (it->second < x.size()) { 01099 if (s[it->second] > 0) { 01100 a[it->second] = pos; 01101 } else { 01102 a[it->second] = -int(pos); 01103 } 01104 subslst[gsyms[pos]] = numeric(x[it->second]); 01105 } else { 01106 scale = pos; 01107 subslst[gsyms[pos]] = numeric(y); 01108 } 01109 ++pos; 01110 } 01111 01112 // do transformation 01113 Gparameter pendint; 01114 ex result = G_transform(pendint, a, scale, gsyms); 01115 // replace dummy symbols with their values 01116 result = result.eval().expand(); 01117 result = result.subs(subslst).evalf(); 01118 if (!is_a<numeric>(result)) 01119 throw std::logic_error("G_do_trafo: G_transform returned non-numeric result"); 01120 01121 cln::cl_N ret = ex_to<numeric>(result).to_cl_N(); 01122 return ret; 01123 } 01124 01125 // handles the transformations and the numerical evaluation of G 01126 // the parameter x, s and y must only contain numerics 01127 static cln::cl_N 01128 G_numeric(const std::vector<cln::cl_N>& x, const std::vector<int>& s, 01129 const cln::cl_N& y) 01130 { 01131 // check for convergence and necessary accelerations 01132 bool need_trafo = false; 01133 bool need_hoelder = false; 01134 std::size_t depth = 0; 01135 for (std::size_t i = 0; i < x.size(); ++i) { 01136 if (!zerop(x[i])) { 01137 ++depth; 01138 const cln::cl_N x_y = abs(x[i]) - y; 01139 if (instanceof(x_y, cln::cl_R_ring) && 01140 realpart(x_y) < cln::least_negative_float(cln::float_format(Digits - 2))) 01141 need_trafo = true; 01142 01143 if (abs(abs(x[i]/y) - 1) < 0.01) 01144 need_hoelder = true; 01145 } 01146 } 01147 if (zerop(x[x.size() - 1])) 01148 need_trafo = true; 01149 01150 if (depth == 1 && x.size() == 2 && !need_trafo) 01151 return - Li_projection(2, y/x[1], cln::float_format(Digits)); 01152 01153 // do acceleration transformation (hoelder convolution [BBB]) 01154 if (need_hoelder) 01155 return G_do_hoelder(x, s, y); 01156 01157 // convergence transformation 01158 if (need_trafo) 01159 return G_do_trafo(x, s, y); 01160 01161 // do summation 01162 std::vector<cln::cl_N> newx; 01163 newx.reserve(x.size()); 01164 std::vector<int> m; 01165 m.reserve(x.size()); 01166 int mcount = 1; 01167 int sign = 1; 01168 cln::cl_N factor = y; 01169 for (std::size_t i = 0; i < x.size(); ++i) { 01170 if (zerop(x[i])) { 01171 ++mcount; 01172 } else { 01173 newx.push_back(factor/x[i]); 01174 factor = x[i]; 01175 m.push_back(mcount); 01176 mcount = 1; 01177 sign = -sign; 01178 } 01179 } 01180 01181 return sign*multipleLi_do_sum(m, newx); 01182 } 01183 01184 01185 ex mLi_numeric(const lst& m, const lst& x) 01186 { 01187 // let G_numeric do the transformation 01188 std::vector<cln::cl_N> newx; 01189 newx.reserve(x.nops()); 01190 std::vector<int> s; 01191 s.reserve(x.nops()); 01192 cln::cl_N factor(1); 01193 for (lst::const_iterator itm = m.begin(), itx = x.begin(); itm != m.end(); ++itm, ++itx) { 01194 for (int i = 1; i < *itm; ++i) { 01195 newx.push_back(cln::cl_N(0)); 01196 s.push_back(1); 01197 } 01198 const cln::cl_N xi = ex_to<numeric>(*itx).to_cl_N(); 01199 newx.push_back(factor/xi); 01200 factor = factor/xi; 01201 s.push_back(1); 01202 } 01203 return numeric(cln::cl_N(1 & m.nops() ? - 1 : 1)*G_numeric(newx, s, cln::cl_N(1))); 01204 } 01205 01206 01207 } // end of anonymous namespace 01208 01209 01211 // 01212 // Generalized multiple polylogarithm G(x, y) and G(x, s, y) 01213 // 01214 // GiNaC function 01215 // 01217 01218 01219 static ex G2_evalf(const ex& x_, const ex& y) 01220 { 01221 if (!y.info(info_flags::positive)) { 01222 return G(x_, y).hold(); 01223 } 01224 lst x = is_a<lst>(x_) ? ex_to<lst>(x_) : lst(x_); 01225 if (x.nops() == 0) { 01226 return _ex1; 01227 } 01228 if (x.op(0) == y) { 01229 return G(x_, y).hold(); 01230 } 01231 std::vector<int> s; 01232 s.reserve(x.nops()); 01233 bool all_zero = true; 01234 for (lst::const_iterator it = x.begin(); it != x.end(); ++it) { 01235 if (!(*it).info(info_flags::numeric)) { 01236 return G(x_, y).hold(); 01237 } 01238 if (*it != _ex0) { 01239 all_zero = false; 01240 } 01241 if ( !ex_to<numeric>(*it).is_real() && ex_to<numeric>(*it).imag() < 0 ) { 01242 s.push_back(-1); 01243 } 01244 else { 01245 s.push_back(1); 01246 } 01247 } 01248 if (all_zero) { 01249 return pow(log(y), x.nops()) / factorial(x.nops()); 01250 } 01251 std::vector<cln::cl_N> xv; 01252 xv.reserve(x.nops()); 01253 for (lst::const_iterator it = x.begin(); it != x.end(); ++it) 01254 xv.push_back(ex_to<numeric>(*it).to_cl_N()); 01255 cln::cl_N result = G_numeric(xv, s, ex_to<numeric>(y).to_cl_N()); 01256 return numeric(result); 01257 } 01258 01259 01260 static ex G2_eval(const ex& x_, const ex& y) 01261 { 01262 //TODO eval to MZV or H or S or Lin 01263 01264 if (!y.info(info_flags::positive)) { 01265 return G(x_, y).hold(); 01266 } 01267 lst x = is_a<lst>(x_) ? ex_to<lst>(x_) : lst(x_); 01268 if (x.nops() == 0) { 01269 return _ex1; 01270 } 01271 if (x.op(0) == y) { 01272 return G(x_, y).hold(); 01273 } 01274 std::vector<int> s; 01275 s.reserve(x.nops()); 01276 bool all_zero = true; 01277 bool crational = true; 01278 for (lst::const_iterator it = x.begin(); it != x.end(); ++it) { 01279 if (!(*it).info(info_flags::numeric)) { 01280 return G(x_, y).hold(); 01281 } 01282 if (!(*it).info(info_flags::crational)) { 01283 crational = false; 01284 } 01285 if (*it != _ex0) { 01286 all_zero = false; 01287 } 01288 if ( !ex_to<numeric>(*it).is_real() && ex_to<numeric>(*it).imag() < 0 ) { 01289 s.push_back(-1); 01290 } 01291 else { 01292 s.push_back(+1); 01293 } 01294 } 01295 if (all_zero) { 01296 return pow(log(y), x.nops()) / factorial(x.nops()); 01297 } 01298 if (!y.info(info_flags::crational)) { 01299 crational = false; 01300 } 01301 if (crational) { 01302 return G(x_, y).hold(); 01303 } 01304 std::vector<cln::cl_N> xv; 01305 xv.reserve(x.nops()); 01306 for (lst::const_iterator it = x.begin(); it != x.end(); ++it) 01307 xv.push_back(ex_to<numeric>(*it).to_cl_N()); 01308 cln::cl_N result = G_numeric(xv, s, ex_to<numeric>(y).to_cl_N()); 01309 return numeric(result); 01310 } 01311 01312 01313 unsigned G2_SERIAL::serial = function::register_new(function_options("G", 2). 01314 evalf_func(G2_evalf). 01315 eval_func(G2_eval). 01316 do_not_evalf_params(). 01317 overloaded(2)); 01318 //TODO 01319 // derivative_func(G2_deriv). 01320 // print_func<print_latex>(G2_print_latex). 01321 01322 01323 static ex G3_evalf(const ex& x_, const ex& s_, const ex& y) 01324 { 01325 if (!y.info(info_flags::positive)) { 01326 return G(x_, s_, y).hold(); 01327 } 01328 lst x = is_a<lst>(x_) ? ex_to<lst>(x_) : lst(x_); 01329 lst s = is_a<lst>(s_) ? ex_to<lst>(s_) : lst(s_); 01330 if (x.nops() != s.nops()) { 01331 return G(x_, s_, y).hold(); 01332 } 01333 if (x.nops() == 0) { 01334 return _ex1; 01335 } 01336 if (x.op(0) == y) { 01337 return G(x_, s_, y).hold(); 01338 } 01339 std::vector<int> sn; 01340 sn.reserve(s.nops()); 01341 bool all_zero = true; 01342 for (lst::const_iterator itx = x.begin(), its = s.begin(); itx != x.end(); ++itx, ++its) { 01343 if (!(*itx).info(info_flags::numeric)) { 01344 return G(x_, y).hold(); 01345 } 01346 if (!(*its).info(info_flags::real)) { 01347 return G(x_, y).hold(); 01348 } 01349 if (*itx != _ex0) { 01350 all_zero = false; 01351 } 01352 if ( ex_to<numeric>(*itx).is_real() ) { 01353 if ( *its >= 0 ) { 01354 sn.push_back(1); 01355 } 01356 else { 01357 sn.push_back(-1); 01358 } 01359 } 01360 else { 01361 if ( ex_to<numeric>(*itx).imag() > 0 ) { 01362 sn.push_back(1); 01363 } 01364 else { 01365 sn.push_back(-1); 01366 } 01367 } 01368 } 01369 if (all_zero) { 01370 return pow(log(y), x.nops()) / factorial(x.nops()); 01371 } 01372 std::vector<cln::cl_N> xn; 01373 xn.reserve(x.nops()); 01374 for (lst::const_iterator it = x.begin(); it != x.end(); ++it) 01375 xn.push_back(ex_to<numeric>(*it).to_cl_N()); 01376 cln::cl_N result = G_numeric(xn, sn, ex_to<numeric>(y).to_cl_N()); 01377 return numeric(result); 01378 } 01379 01380 01381 static ex G3_eval(const ex& x_, const ex& s_, const ex& y) 01382 { 01383 //TODO eval to MZV or H or S or Lin 01384 01385 if (!y.info(info_flags::positive)) { 01386 return G(x_, s_, y).hold(); 01387 } 01388 lst x = is_a<lst>(x_) ? ex_to<lst>(x_) : lst(x_); 01389 lst s = is_a<lst>(s_) ? ex_to<lst>(s_) : lst(s_); 01390 if (x.nops() != s.nops()) { 01391 return G(x_, s_, y).hold(); 01392 } 01393 if (x.nops() == 0) { 01394 return _ex1; 01395 } 01396 if (x.op(0) == y) { 01397 return G(x_, s_, y).hold(); 01398 } 01399 std::vector<int> sn; 01400 sn.reserve(s.nops()); 01401 bool all_zero = true; 01402 bool crational = true; 01403 for (lst::const_iterator itx = x.begin(), its = s.begin(); itx != x.end(); ++itx, ++its) { 01404 if (!(*itx).info(info_flags::numeric)) { 01405 return G(x_, s_, y).hold(); 01406 } 01407 if (!(*its).info(info_flags::real)) { 01408 return G(x_, s_, y).hold(); 01409 } 01410 if (!(*itx).info(info_flags::crational)) { 01411 crational = false; 01412 } 01413 if (*itx != _ex0) { 01414 all_zero = false; 01415 } 01416 if ( ex_to<numeric>(*itx).is_real() ) { 01417 if ( *its >= 0 ) { 01418 sn.push_back(1); 01419 } 01420 else { 01421 sn.push_back(-1); 01422 } 01423 } 01424 else { 01425 if ( ex_to<numeric>(*itx).imag() > 0 ) { 01426 sn.push_back(1); 01427 } 01428 else { 01429 sn.push_back(-1); 01430 } 01431 } 01432 } 01433 if (all_zero) { 01434 return pow(log(y), x.nops()) / factorial(x.nops()); 01435 } 01436 if (!y.info(info_flags::crational)) { 01437 crational = false; 01438 } 01439 if (crational) { 01440 return G(x_, s_, y).hold(); 01441 } 01442 std::vector<cln::cl_N> xn; 01443 xn.reserve(x.nops()); 01444 for (lst::const_iterator it = x.begin(); it != x.end(); ++it) 01445 xn.push_back(ex_to<numeric>(*it).to_cl_N()); 01446 cln::cl_N result = G_numeric(xn, sn, ex_to<numeric>(y).to_cl_N()); 01447 return numeric(result); 01448 } 01449 01450 01451 unsigned G3_SERIAL::serial = function::register_new(function_options("G", 3). 01452 evalf_func(G3_evalf). 01453 eval_func(G3_eval). 01454 do_not_evalf_params(). 01455 overloaded(2)); 01456 //TODO 01457 // derivative_func(G3_deriv). 01458 // print_func<print_latex>(G3_print_latex). 01459 01460 01462 // 01463 // Classical polylogarithm and multiple polylogarithm Li(m,x) 01464 // 01465 // GiNaC function 01466 // 01468 01469 01470 static ex Li_evalf(const ex& m_, const ex& x_) 01471 { 01472 // classical polylogs 01473 if (m_.info(info_flags::posint)) { 01474 if (x_.info(info_flags::numeric)) { 01475 int m__ = ex_to<numeric>(m_).to_int(); 01476 const cln::cl_N x__ = ex_to<numeric>(x_).to_cl_N(); 01477 const cln::cl_N result = Lin_numeric(m__, x__); 01478 return numeric(result); 01479 } else { 01480 // try to numerically evaluate second argument 01481 ex x_val = x_.evalf(); 01482 if (x_val.info(info_flags::numeric)) { 01483 int m__ = ex_to<numeric>(m_).to_int(); 01484 const cln::cl_N x__ = ex_to<numeric>(x_val).to_cl_N(); 01485 const cln::cl_N result = Lin_numeric(m__, x__); 01486 return numeric(result); 01487 } 01488 } 01489 } 01490 // multiple polylogs 01491 if (is_a<lst>(m_) && is_a<lst>(x_)) { 01492 01493 const lst& m = ex_to<lst>(m_); 01494 const lst& x = ex_to<lst>(x_); 01495 if (m.nops() != x.nops()) { 01496 return Li(m_,x_).hold(); 01497 } 01498 if (x.nops() == 0) { 01499 return _ex1; 01500 } 01501 if ((m.op(0) == _ex1) && (x.op(0) == _ex1)) { 01502 return Li(m_,x_).hold(); 01503 } 01504 01505 for (lst::const_iterator itm = m.begin(), itx = x.begin(); itm != m.end(); ++itm, ++itx) { 01506 if (!(*itm).info(info_flags::posint)) { 01507 return Li(m_, x_).hold(); 01508 } 01509 if (!(*itx).info(info_flags::numeric)) { 01510 return Li(m_, x_).hold(); 01511 } 01512 if (*itx == _ex0) { 01513 return _ex0; 01514 } 01515 } 01516 01517 return mLi_numeric(m, x); 01518 } 01519 01520 return Li(m_,x_).hold(); 01521 } 01522 01523 01524 static ex Li_eval(const ex& m_, const ex& x_) 01525 { 01526 if (is_a<lst>(m_)) { 01527 if (is_a<lst>(x_)) { 01528 // multiple polylogs 01529 const lst& m = ex_to<lst>(m_); 01530 const lst& x = ex_to<lst>(x_); 01531 if (m.nops() != x.nops()) { 01532 return Li(m_,x_).hold(); 01533 } 01534 if (x.nops() == 0) { 01535 return _ex1; 01536 } 01537 bool is_H = true; 01538 bool is_zeta = true; 01539 bool do_evalf = true; 01540 bool crational = true; 01541 for (lst::const_iterator itm = m.begin(), itx = x.begin(); itm != m.end(); ++itm, ++itx) { 01542 if (!(*itm).info(info_flags::posint)) { 01543 return Li(m_,x_).hold(); 01544 } 01545 if ((*itx != _ex1) && (*itx != _ex_1)) { 01546 if (itx != x.begin()) { 01547 is_H = false; 01548 } 01549 is_zeta = false; 01550 } 01551 if (*itx == _ex0) { 01552 return _ex0; 01553 } 01554 if (!(*itx).info(info_flags::numeric)) { 01555 do_evalf = false; 01556 } 01557 if (!(*itx).info(info_flags::crational)) { 01558 crational = false; 01559 } 01560 } 01561 if (is_zeta) { 01562 return zeta(m_,x_); 01563 } 01564 if (is_H) { 01565 ex prefactor; 01566 lst newm = convert_parameter_Li_to_H(m, x, prefactor); 01567 return prefactor * H(newm, x[0]); 01568 } 01569 if (do_evalf && !crational) { 01570 return mLi_numeric(m,x); 01571 } 01572 } 01573 return Li(m_, x_).hold(); 01574 } else if (is_a<lst>(x_)) { 01575 return Li(m_, x_).hold(); 01576 } 01577 01578 // classical polylogs 01579 if (x_ == _ex0) { 01580 return _ex0; 01581 } 01582 if (x_ == _ex1) { 01583 return zeta(m_); 01584 } 01585 if (x_ == _ex_1) { 01586 return (pow(2,1-m_)-1) * zeta(m_); 01587 } 01588 if (m_ == _ex1) { 01589 return -log(1-x_); 01590 } 01591 if (m_ == _ex2) { 01592 if (x_.is_equal(I)) { 01593 return power(Pi,_ex2)/_ex_48 + Catalan*I; 01594 } 01595 if (x_.is_equal(-I)) { 01596 return power(Pi,_ex2)/_ex_48 - Catalan*I; 01597 } 01598 } 01599 if (m_.info(info_flags::posint) && x_.info(info_flags::numeric) && !x_.info(info_flags::crational)) { 01600 int m__ = ex_to<numeric>(m_).to_int(); 01601 const cln::cl_N x__ = ex_to<numeric>(x_).to_cl_N(); 01602 const cln::cl_N result = Lin_numeric(m__, x__); 01603 return numeric(result); 01604 } 01605 01606 return Li(m_, x_).hold(); 01607 } 01608 01609 01610 static ex Li_series(const ex& m, const ex& x, const relational& rel, int order, unsigned options) 01611 { 01612 if (is_a<lst>(m) || is_a<lst>(x)) { 01613 // multiple polylog 01614 epvector seq; 01615 seq.push_back(expair(Li(m, x), 0)); 01616 return pseries(rel, seq); 01617 } 01618 01619 // classical polylog 01620 const ex x_pt = x.subs(rel, subs_options::no_pattern); 01621 if (m.info(info_flags::numeric) && x_pt.info(info_flags::numeric)) { 01622 // First special case: x==0 (derivatives have poles) 01623 if (x_pt.is_zero()) { 01624 const symbol s; 01625 ex ser; 01626 // manually construct the primitive expansion 01627 for (int i=1; i<order; ++i) 01628 ser += pow(s,i) / pow(numeric(i), m); 01629 // substitute the argument's series expansion 01630 ser = ser.subs(s==x.series(rel, order), subs_options::no_pattern); 01631 // maybe that was terminating, so add a proper order term 01632 epvector nseq; 01633 nseq.push_back(expair(Order(_ex1), order)); 01634 ser += pseries(rel, nseq); 01635 // reexpanding it will collapse the series again 01636 return ser.series(rel, order); 01637 } 01638 // TODO special cases: x==1 (branch point) and x real, >=1 (branch cut) 01639 throw std::runtime_error("Li_series: don't know how to do the series expansion at this point!"); 01640 } 01641 // all other cases should be safe, by now: 01642 throw do_taylor(); // caught by function::series() 01643 } 01644 01645 01646 static ex Li_deriv(const ex& m_, const ex& x_, unsigned deriv_param) 01647 { 01648 GINAC_ASSERT(deriv_param < 2); 01649 if (deriv_param == 0) { 01650 return _ex0; 01651 } 01652 if (m_.nops() > 1) { 01653 throw std::runtime_error("don't know how to derivate multiple polylogarithm!"); 01654 } 01655 ex m; 01656 if (is_a<lst>(m_)) { 01657 m = m_.op(0); 01658 } else { 01659 m = m_; 01660 } 01661 ex x; 01662 if (is_a<lst>(x_)) { 01663 x = x_.op(0); 01664 } else { 01665 x = x_; 01666 } 01667 if (m > 0) { 01668 return Li(m-1, x) / x; 01669 } else { 01670 return 1/(1-x); 01671 } 01672 } 01673 01674 01675 static void Li_print_latex(const ex& m_, const ex& x_, const print_context& c) 01676 { 01677 lst m; 01678 if (is_a<lst>(m_)) { 01679 m = ex_to<lst>(m_); 01680 } else { 01681 m = lst(m_); 01682 } 01683 lst x; 01684 if (is_a<lst>(x_)) { 01685 x = ex_to<lst>(x_); 01686 } else { 01687 x = lst(x_); 01688 } 01689 c.s << "\\mathrm{Li}_{"; 01690 lst::const_iterator itm = m.begin(); 01691 (*itm).print(c); 01692 itm++; 01693 for (; itm != m.end(); itm++) { 01694 c.s << ","; 01695 (*itm).print(c); 01696 } 01697 c.s << "}("; 01698 lst::const_iterator itx = x.begin(); 01699 (*itx).print(c); 01700 itx++; 01701 for (; itx != x.end(); itx++) { 01702 c.s << ","; 01703 (*itx).print(c); 01704 } 01705 c.s << ")"; 01706 } 01707 01708 01709 REGISTER_FUNCTION(Li, 01710 evalf_func(Li_evalf). 01711 eval_func(Li_eval). 01712 series_func(Li_series). 01713 derivative_func(Li_deriv). 01714 print_func<print_latex>(Li_print_latex). 01715 do_not_evalf_params()); 01716 01717 01719 // 01720 // Nielsen's generalized polylogarithm S(n,p,x) 01721 // 01722 // helper functions 01723 // 01725 01726 01727 // anonymous namespace for helper functions 01728 namespace { 01729 01730 01731 // lookup table for special Euler-Zagier-Sums (used for S_n,p(x)) 01732 // see fill_Yn() 01733 std::vector<std::vector<cln::cl_N> > Yn; 01734 int ynsize = 0; // number of Yn[] 01735 int ynlength = 100; // initial length of all Yn[i] 01736 01737 01738 // This function calculates the Y_n. The Y_n are needed for the evaluation of S_{n,p}(x). 01739 // The Y_n are basically Euler-Zagier sums with all m_i=1. They are subsums in the Z-sum 01740 // representing S_{n,p}(x). 01741 // The first index in Y_n corresponds to the parameter p minus one, i.e. the depth of the 01742 // equivalent Z-sum. 01743 // The second index in Y_n corresponds to the running index of the outermost sum in the full Z-sum 01744 // representing S_{n,p}(x). 01745 // The calculation of Y_n uses the values from Y_{n-1}. 01746 void fill_Yn(int n, const cln::float_format_t& prec) 01747 { 01748 const int initsize = ynlength; 01749 //const int initsize = initsize_Yn; 01750 cln::cl_N one = cln::cl_float(1, prec); 01751 01752 if (n) { 01753 std::vector<cln::cl_N> buf(initsize); 01754 std::vector<cln::cl_N>::iterator it = buf.begin(); 01755 std::vector<cln::cl_N>::iterator itprev = Yn[n-1].begin(); 01756 *it = (*itprev) / cln::cl_N(n+1) * one; 01757 it++; 01758 itprev++; 01759 // sums with an index smaller than the depth are zero and need not to be calculated. 01760 // calculation starts with depth, which is n+2) 01761 for (int i=n+2; i<=initsize+n; i++) { 01762 *it = *(it-1) + (*itprev) / cln::cl_N(i) * one; 01763 it++; 01764 itprev++; 01765 } 01766 Yn.push_back(buf); 01767 } else { 01768 std::vector<cln::cl_N> buf(initsize); 01769 std::vector<cln::cl_N>::iterator it = buf.begin(); 01770 *it = 1 * one; 01771 it++; 01772 for (int i=2; i<=initsize; i++) { 01773 *it = *(it-1) + 1 / cln::cl_N(i) * one; 01774 it++; 01775 } 01776 Yn.push_back(buf); 01777 } 01778 ynsize++; 01779 } 01780 01781 01782 // make Yn longer ... 01783 void make_Yn_longer(int newsize, const cln::float_format_t& prec) 01784 { 01785 01786 cln::cl_N one = cln::cl_float(1, prec); 01787 01788 Yn[0].resize(newsize); 01789 std::vector<cln::cl_N>::iterator it = Yn[0].begin(); 01790 it += ynlength; 01791 for (int i=ynlength+1; i<=newsize; i++) { 01792 *it = *(it-1) + 1 / cln::cl_N(i) * one; 01793 it++; 01794 } 01795 01796 for (int n=1; n<ynsize; n++) { 01797 Yn[n].resize(newsize); 01798 std::vector<cln::cl_N>::iterator it = Yn[n].begin(); 01799 std::vector<cln::cl_N>::iterator itprev = Yn[n-1].begin(); 01800 it += ynlength; 01801 itprev += ynlength; 01802 for (int i=ynlength+n+1; i<=newsize+n; i++) { 01803 *it = *(it-1) + (*itprev) / cln::cl_N(i) * one; 01804 it++; 01805 itprev++; 01806 } 01807 } 01808 01809 ynlength = newsize; 01810 } 01811 01812 01813 // helper function for S(n,p,x) 01814 // [Kol] (7.2) 01815 cln::cl_N C(int n, int p) 01816 { 01817 cln::cl_N result; 01818 01819 for (int k=0; k<p; k++) { 01820 for (int j=0; j<=(n+k-1)/2; j++) { 01821 if (k == 0) { 01822 if (n & 1) { 01823 if (j & 1) { 01824 result = result - 2 * cln::expt(cln::pi(),2*j) * S_num(n-2*j,p,1) / cln::factorial(2*j); 01825 } 01826 else { 01827 result = result + 2 * cln::expt(cln::pi(),2*j) * S_num(n-2*j,p,1) / cln::factorial(2*j); 01828 } 01829 } 01830 } 01831 else { 01832 if (k & 1) { 01833 if (j & 1) { 01834 result = result + cln::factorial(n+k-1) 01835 * cln::expt(cln::pi(),2*j) * S_num(n+k-2*j,p-k,1) 01836 / (cln::factorial(k) * cln::factorial(n-1) * cln::factorial(2*j)); 01837 } 01838 else { 01839 result = result - cln::factorial(n+k-1) 01840 * cln::expt(cln::pi(),2*j) * S_num(n+k-2*j,p-k,1) 01841 / (cln::factorial(k) * cln::factorial(n-1) * cln::factorial(2*j)); 01842 } 01843 } 01844 else { 01845 if (j & 1) { 01846 result = result - cln::factorial(n+k-1) * cln::expt(cln::pi(),2*j) * S_num(n+k-2*j,p-k,1) 01847 / (cln::factorial(k) * cln::factorial(n-1) * cln::factorial(2*j)); 01848 } 01849 else { 01850 result = result + cln::factorial(n+k-1) 01851 * cln::expt(cln::pi(),2*j) * S_num(n+k-2*j,p-k,1) 01852 / (cln::factorial(k) * cln::factorial(n-1) * cln::factorial(2*j)); 01853 } 01854 } 01855 } 01856 } 01857 } 01858 int np = n+p; 01859 if ((np-1) & 1) { 01860 if (((np)/2+n) & 1) { 01861 result = -result - cln::expt(cln::pi(),np) / (np * cln::factorial(n-1) * cln::factorial(p)); 01862 } 01863 else { 01864 result = -result + cln::expt(cln::pi(),np) / (np * cln::factorial(n-1) * cln::factorial(p)); 01865 } 01866 } 01867 01868 return result; 01869 } 01870 01871 01872 // helper function for S(n,p,x) 01873 // [Kol] remark to (9.1) 01874 cln::cl_N a_k(int k) 01875 { 01876 cln::cl_N result; 01877 01878 if (k == 0) { 01879 return 1; 01880 } 01881 01882 result = result; 01883 for (int m=2; m<=k; m++) { 01884 result = result + cln::expt(cln::cl_N(-1),m) * cln::zeta(m) * a_k(k-m); 01885 } 01886 01887 return -result / k; 01888 } 01889 01890 01891 // helper function for S(n,p,x) 01892 // [Kol] remark to (9.1) 01893 cln::cl_N b_k(int k) 01894 { 01895 cln::cl_N result; 01896 01897 if (k == 0) { 01898 return 1; 01899 } 01900 01901 result = result; 01902 for (int m=2; m<=k; m++) { 01903 result = result + cln::expt(cln::cl_N(-1),m) * cln::zeta(m) * b_k(k-m); 01904 } 01905 01906 return result / k; 01907 } 01908 01909 01910 // helper function for S(n,p,x) 01911 cln::cl_N S_do_sum(int n, int p, const cln::cl_N& x, const cln::float_format_t& prec) 01912 { 01913 static cln::float_format_t oldprec = cln::default_float_format; 01914 01915 if (p==1) { 01916 return Li_projection(n+1, x, prec); 01917 } 01918 01919 // precision has changed, we need to clear lookup table Yn 01920 if ( oldprec != prec ) { 01921 Yn.clear(); 01922 ynsize = 0; 01923 ynlength = 100; 01924 oldprec = prec; 01925 } 01926 01927 // check if precalculated values are sufficient 01928 if (p > ynsize+1) { 01929 for (int i=ynsize; i<p-1; i++) { 01930 fill_Yn(i, prec); 01931 } 01932 } 01933 01934 // should be done otherwise 01935 cln::cl_F one = cln::cl_float(1, cln::float_format(Digits)); 01936 cln::cl_N xf = x * one; 01937 //cln::cl_N xf = x * cln::cl_float(1, prec); 01938 01939 cln::cl_N res; 01940 cln::cl_N resbuf; 01941 cln::cl_N factor = cln::expt(xf, p); 01942 int i = p; 01943 do { 01944 resbuf = res; 01945 if (i-p >= ynlength) { 01946 // make Yn longer 01947 make_Yn_longer(ynlength*2, prec); 01948 } 01949 res = res + factor / cln::expt(cln::cl_I(i),n+1) * Yn[p-2][i-p]; // should we check it? or rely on magic number? ... 01950 //res = res + factor / cln::expt(cln::cl_I(i),n+1) * (*it); // should we check it? or rely on magic number? ... 01951 factor = factor * xf; 01952 i++; 01953 } while (res != resbuf); 01954 01955 return res; 01956 } 01957 01958 01959 // helper function for S(n,p,x) 01960 cln::cl_N S_projection(int n, int p, const cln::cl_N& x, const cln::float_format_t& prec) 01961 { 01962 // [Kol] (5.3) 01963 if (cln::abs(cln::realpart(x)) > cln::cl_F("0.5")) { 01964 01965 cln::cl_N result = cln::expt(cln::cl_I(-1),p) * cln::expt(cln::log(x),n) 01966 * cln::expt(cln::log(1-x),p) / cln::factorial(n) / cln::factorial(p); 01967 01968 for (int s=0; s<n; s++) { 01969 cln::cl_N res2; 01970 for (int r=0; r<p; r++) { 01971 res2 = res2 + cln::expt(cln::cl_I(-1),r) * cln::expt(cln::log(1-x),r) 01972 * S_do_sum(p-r,n-s,1-x,prec) / cln::factorial(r); 01973 } 01974 result = result + cln::expt(cln::log(x),s) * (S_num(n-s,p,1) - res2) / cln::factorial(s); 01975 } 01976 01977 return result; 01978 } 01979 01980 return S_do_sum(n, p, x, prec); 01981 } 01982 01983 01984 // helper function for S(n,p,x) 01985 const cln::cl_N S_num(int n, int p, const cln::cl_N& x) 01986 { 01987 if (x == 1) { 01988 if (n == 1) { 01989 // [Kol] (2.22) with (2.21) 01990 return cln::zeta(p+1); 01991 } 01992 01993 if (p == 1) { 01994 // [Kol] (2.22) 01995 return cln::zeta(n+1); 01996 } 01997 01998 // [Kol] (9.1) 01999 cln::cl_N result; 02000 for (int nu=0; nu<n; nu++) { 02001 for (int rho=0; rho<=p; rho++) { 02002 result = result + b_k(n-nu-1) * b_k(p-rho) * a_k(nu+rho+1) 02003 * cln::factorial(nu+rho+1) / cln::factorial(rho) / cln::factorial(nu+1); 02004 } 02005 } 02006 result = result * cln::expt(cln::cl_I(-1),n+p-1); 02007 02008 return result; 02009 } 02010 else if (x == -1) { 02011 // [Kol] (2.22) 02012 if (p == 1) { 02013 return -(1-cln::expt(cln::cl_I(2),-n)) * cln::zeta(n+1); 02014 } 02015 // throw std::runtime_error("don't know how to evaluate this function!"); 02016 } 02017 02018 // what is the desired float format? 02019 // first guess: default format 02020 cln::float_format_t prec = cln::default_float_format; 02021 const cln::cl_N value = x; 02022 // second guess: the argument's format 02023 if (!instanceof(realpart(value), cln::cl_RA_ring)) 02024 prec = cln::float_format(cln::the<cln::cl_F>(cln::realpart(value))); 02025 else if (!instanceof(imagpart(value), cln::cl_RA_ring)) 02026 prec = cln::float_format(cln::the<cln::cl_F>(cln::imagpart(value))); 02027 02028 // [Kol] (5.3) 02029 if ((cln::realpart(value) < -0.5) || (n == 0) || ((cln::abs(value) <= 1) && (cln::abs(value) > 0.95))) { 02030 02031 cln::cl_N result = cln::expt(cln::cl_I(-1),p) * cln::expt(cln::log(value),n) 02032 * cln::expt(cln::log(1-value),p) / cln::factorial(n) / cln::factorial(p); 02033 02034 for (int s=0; s<n; s++) { 02035 cln::cl_N res2; 02036 for (int r=0; r<p; r++) { 02037 res2 = res2 + cln::expt(cln::cl_I(-1),r) * cln::expt(cln::log(1-value),r) 02038 * S_num(p-r,n-s,1-value) / cln::factorial(r); 02039 } 02040 result = result + cln::expt(cln::log(value),s) * (S_num(n-s,p,1) - res2) / cln::factorial(s); 02041 } 02042 02043 return result; 02044 02045 } 02046 // [Kol] (5.12) 02047 if (cln::abs(value) > 1) { 02048 02049 cln::cl_N result; 02050 02051 for (int s=0; s<p; s++) { 02052 for (int r=0; r<=s; r++) { 02053 result = result + cln::expt(cln::cl_I(-1),s) * cln::expt(cln::log(-value),r) * cln::factorial(n+s-r-1) 02054 / cln::factorial(r) / cln::factorial(s-r) / cln::factorial(n-1) 02055 * S_num(n+s-r,p-s,cln::recip(value)); 02056 } 02057 } 02058 result = result * cln::expt(cln::cl_I(-1),n); 02059 02060 cln::cl_N res2; 02061 for (int r=0; r<n; r++) { 02062 res2 = res2 + cln::expt(cln::log(-value),r) * C(n-r,p) / cln::factorial(r); 02063 } 02064 res2 = res2 + cln::expt(cln::log(-value),n+p) / cln::factorial(n+p); 02065 02066 result = result + cln::expt(cln::cl_I(-1),p) * res2; 02067 02068 return result; 02069 } 02070 else { 02071 return S_projection(n, p, value, prec); 02072 } 02073 } 02074 02075 02076 } // end of anonymous namespace 02077 02078 02080 // 02081 // Nielsen's generalized polylogarithm S(n,p,x) 02082 // 02083 // GiNaC function 02084 // 02086 02087 02088 static ex S_evalf(const ex& n, const ex& p, const ex& x) 02089 { 02090 if (n.info(info_flags::posint) && p.info(info_flags::posint)) { 02091 const int n_ = ex_to<numeric>(n).to_int(); 02092 const int p_ = ex_to<numeric>(p).to_int(); 02093 if (is_a<numeric>(x)) { 02094 const cln::cl_N x_ = ex_to<numeric>(x).to_cl_N(); 02095 const cln::cl_N result = S_num(n_, p_, x_); 02096 return numeric(result); 02097 } else { 02098 ex x_val = x.evalf(); 02099 if (is_a<numeric>(x_val)) { 02100 const cln::cl_N x_val_ = ex_to<numeric>(x_val).to_cl_N(); 02101 const cln::cl_N result = S_num(n_, p_, x_val_); 02102 return numeric(result); 02103 } 02104 } 02105 } 02106 return S(n, p, x).hold(); 02107 } 02108 02109 02110 static ex S_eval(const ex& n, const ex& p, const ex& x) 02111 { 02112 if (n.info(info_flags::posint) && p.info(info_flags::posint)) { 02113 if (x == 0) { 02114 return _ex0; 02115 } 02116 if (x == 1) { 02117 lst m(n+1); 02118 for (int i=ex_to<numeric>(p).to_int()-1; i>0; i--) { 02119 m.append(1); 02120 } 02121 return zeta(m); 02122 } 02123 if (p == 1) { 02124 return Li(n+1, x); 02125 } 02126 if (x.info(info_flags::numeric) && (!x.info(info_flags::crational))) { 02127 int n_ = ex_to<numeric>(n).to_int(); 02128 int p_ = ex_to<numeric>(p).to_int(); 02129 const cln::cl_N x_ = ex_to<numeric>(x).to_cl_N(); 02130 const cln::cl_N result = S_num(n_, p_, x_); 02131 return numeric(result); 02132 } 02133 } 02134 if (n.is_zero()) { 02135 // [Kol] (5.3) 02136 return pow(-log(1-x), p) / factorial(p); 02137 } 02138 return S(n, p, x).hold(); 02139 } 02140 02141 02142 static ex S_series(const ex& n, const ex& p, const ex& x, const relational& rel, int order, unsigned options) 02143 { 02144 if (p == _ex1) { 02145 return Li(n+1, x).series(rel, order, options); 02146 } 02147 02148 const ex x_pt = x.subs(rel, subs_options::no_pattern); 02149 if (n.info(info_flags::posint) && p.info(info_flags::posint) && x_pt.info(info_flags::numeric)) { 02150 // First special case: x==0 (derivatives have poles) 02151 if (x_pt.is_zero()) { 02152 const symbol s; 02153 ex ser; 02154 // manually construct the primitive expansion 02155 // subsum = Euler-Zagier-Sum is needed 02156 // dirty hack (slow ...) calculation of subsum: 02157 std::vector<ex> presubsum, subsum; 02158 subsum.push_back(0); 02159 for (int i=1; i<order-1; ++i) { 02160 subsum.push_back(subsum[i-1] + numeric(1, i)); 02161 } 02162 for (int depth=2; depth<p; ++depth) { 02163 presubsum = subsum; 02164 for (int i=1; i<order-1; ++i) { 02165 subsum[i] = subsum[i-1] + numeric(1, i) * presubsum[i-1]; 02166 } 02167 } 02168 02169 for (int i=1; i<order; ++i) { 02170 ser += pow(s,i) / pow(numeric(i), n+1) * subsum[i-1]; 02171 } 02172 // substitute the argument's series expansion 02173 ser = ser.subs(s==x.series(rel, order), subs_options::no_pattern); 02174 // maybe that was terminating, so add a proper order term 02175 epvector nseq; 02176 nseq.push_back(expair(Order(_ex1), order)); 02177 ser += pseries(rel, nseq); 02178 // reexpanding it will collapse the series again 02179 return ser.series(rel, order); 02180 } 02181 // TODO special cases: x==1 (branch point) and x real, >=1 (branch cut) 02182 throw std::runtime_error("S_series: don't know how to do the series expansion at this point!"); 02183 } 02184 // all other cases should be safe, by now: 02185 throw do_taylor(); // caught by function::series() 02186 } 02187 02188 02189 static ex S_deriv(const ex& n, const ex& p, const ex& x, unsigned deriv_param) 02190 { 02191 GINAC_ASSERT(deriv_param < 3); 02192 if (deriv_param < 2) { 02193 return _ex0; 02194 } 02195 if (n > 0) { 02196 return S(n-1, p, x) / x; 02197 } else { 02198 return S(n, p-1, x) / (1-x); 02199 } 02200 } 02201 02202 02203 static void S_print_latex(const ex& n, const ex& p, const ex& x, const print_context& c) 02204 { 02205 c.s << "\\mathrm{S}_{"; 02206 n.print(c); 02207 c.s << ","; 02208 p.print(c); 02209 c.s << "}("; 02210 x.print(c); 02211 c.s << ")"; 02212 } 02213 02214 02215 REGISTER_FUNCTION(S, 02216 evalf_func(S_evalf). 02217 eval_func(S_eval). 02218 series_func(S_series). 02219 derivative_func(S_deriv). 02220 print_func<print_latex>(S_print_latex). 02221 do_not_evalf_params()); 02222 02223 02225 // 02226 // Harmonic polylogarithm H(m,x) 02227 // 02228 // helper functions 02229 // 02231 02232 02233 // anonymous namespace for helper functions 02234 namespace { 02235 02236 02237 // regulates the pole (used by 1/x-transformation) 02238 symbol H_polesign("IMSIGN"); 02239 02240 02241 // convert parameters from H to Li representation 02242 // parameters are expected to be in expanded form, i.e. only 0, 1 and -1 02243 // returns true if some parameters are negative 02244 bool convert_parameter_H_to_Li(const lst& l, lst& m, lst& s, ex& pf) 02245 { 02246 // expand parameter list 02247 lst mexp; 02248 for (lst::const_iterator it = l.begin(); it != l.end(); it++) { 02249 if (*it > 1) { 02250 for (ex count=*it-1; count > 0; count--) { 02251 mexp.append(0); 02252 } 02253 mexp.append(1); 02254 } else if (*it < -1) { 02255 for (ex count=*it+1; count < 0; count++) { 02256 mexp.append(0); 02257 } 02258 mexp.append(-1); 02259 } else { 02260 mexp.append(*it); 02261 } 02262 } 02263 02264 ex signum = 1; 02265 pf = 1; 02266 bool has_negative_parameters = false; 02267 ex acc = 1; 02268 for (lst::const_iterator it = mexp.begin(); it != mexp.end(); it++) { 02269 if (*it == 0) { 02270 acc++; 02271 continue; 02272 } 02273 if (*it > 0) { 02274 m.append((*it+acc-1) * signum); 02275 } else { 02276 m.append((*it-acc+1) * signum); 02277 } 02278 acc = 1; 02279 signum = *it; 02280 pf *= *it; 02281 if (pf < 0) { 02282 has_negative_parameters = true; 02283 } 02284 } 02285 if (has_negative_parameters) { 02286 for (std::size_t i=0; i<m.nops(); i++) { 02287 if (m.op(i) < 0) { 02288 m.let_op(i) = -m.op(i); 02289 s.append(-1); 02290 } else { 02291 s.append(1); 02292 } 02293 } 02294 } 02295 02296 return has_negative_parameters; 02297 } 02298 02299 02300 // recursivly transforms H to corresponding multiple polylogarithms 02301 struct map_trafo_H_convert_to_Li : public map_function 02302 { 02303 ex operator()(const ex& e) 02304 { 02305 if (is_a<add>(e) || is_a<mul>(e)) { 02306 return e.map(*this); 02307 } 02308 if (is_a<function>(e)) { 02309 std::string name = ex_to<function>(e).get_name(); 02310 if (name == "H") { 02311 lst parameter; 02312 if (is_a<lst>(e.op(0))) { 02313 parameter = ex_to<lst>(e.op(0)); 02314 } else { 02315 parameter = lst(e.op(0)); 02316 } 02317 ex arg = e.op(1); 02318 02319 lst m; 02320 lst s; 02321 ex pf; 02322 if (convert_parameter_H_to_Li(parameter, m, s, pf)) { 02323 s.let_op(0) = s.op(0) * arg; 02324 return pf * Li(m, s).hold(); 02325 } else { 02326 for (std::size_t i=0; i<m.nops(); i++) { 02327 s.append(1); 02328 } 02329 s.let_op(0) = s.op(0) * arg; 02330 return Li(m, s).hold(); 02331 } 02332 } 02333 } 02334 return e; 02335 } 02336 }; 02337 02338 02339 // recursivly transforms H to corresponding zetas 02340 struct map_trafo_H_convert_to_zeta : public map_function 02341 { 02342 ex operator()(const ex& e) 02343 { 02344 if (is_a<add>(e) || is_a<mul>(e)) { 02345 return e.map(*this); 02346 } 02347 if (is_a<function>(e)) { 02348 std::string name = ex_to<function>(e).get_name(); 02349 if (name == "H") { 02350 lst parameter; 02351 if (is_a<lst>(e.op(0))) { 02352 parameter = ex_to<lst>(e.op(0)); 02353 } else { 02354 parameter = lst(e.op(0)); 02355 } 02356 02357 lst m; 02358 lst s; 02359 ex pf; 02360 if (convert_parameter_H_to_Li(parameter, m, s, pf)) { 02361 return pf * zeta(m, s); 02362 } else { 02363 return zeta(m); 02364 } 02365 } 02366 } 02367 return e; 02368 } 02369 }; 02370 02371 02372 // remove trailing zeros from H-parameters 02373 struct map_trafo_H_reduce_trailing_zeros : public map_function 02374 { 02375 ex operator()(const ex& e) 02376 { 02377 if (is_a<add>(e) || is_a<mul>(e)) { 02378 return e.map(*this); 02379 } 02380 if (is_a<function>(e)) { 02381 std::string name = ex_to<function>(e).get_name(); 02382 if (name == "H") { 02383 lst parameter; 02384 if (is_a<lst>(e.op(0))) { 02385 parameter = ex_to<lst>(e.op(0)); 02386 } else { 02387 parameter = lst(e.op(0)); 02388 } 02389 ex arg = e.op(1); 02390 if (parameter.op(parameter.nops()-1) == 0) { 02391 02392 // 02393 if (parameter.nops() == 1) { 02394 return log(arg); 02395 } 02396 02397 // 02398 lst::const_iterator it = parameter.begin(); 02399 while ((it != parameter.end()) && (*it == 0)) { 02400 it++; 02401 } 02402 if (it == parameter.end()) { 02403 return pow(log(arg),parameter.nops()) / factorial(parameter.nops()); 02404 } 02405 02406 // 02407 parameter.remove_last(); 02408 std::size_t lastentry = parameter.nops(); 02409 while ((lastentry > 0) && (parameter[lastentry-1] == 0)) { 02410 lastentry--; 02411 } 02412 02413 // 02414 ex result = log(arg) * H(parameter,arg).hold(); 02415 ex acc = 0; 02416 for (ex i=0; i<lastentry; i++) { 02417 if (parameter[i] > 0) { 02418 parameter[i]++; 02419 result -= (acc + parameter[i]-1) * H(parameter, arg).hold(); 02420 parameter[i]--; 02421 acc = 0; 02422 } else if (parameter[i] < 0) { 02423 parameter[i]--; 02424 result -= (acc + abs(parameter[i]+1)) * H(parameter, arg).hold(); 02425 parameter[i]++; 02426 acc = 0; 02427 } else { 02428 acc++; 02429 } 02430 } 02431 02432 if (lastentry < parameter.nops()) { 02433 result = result / (parameter.nops()-lastentry+1); 02434 return result.map(*this); 02435 } else { 02436 return result; 02437 } 02438 } 02439 } 02440 } 02441 return e; 02442 } 02443 }; 02444 02445 02446 // returns an expression with zeta functions corresponding to the parameter list for H 02447 ex convert_H_to_zeta(const lst& m) 02448 { 02449 symbol xtemp("xtemp"); 02450 map_trafo_H_reduce_trailing_zeros filter; 02451 map_trafo_H_convert_to_zeta filter2; 02452 return filter2(filter(H(m, xtemp).hold())).subs(xtemp == 1); 02453 } 02454 02455 02456 // convert signs form Li to H representation 02457 lst convert_parameter_Li_to_H(const lst& m, const lst& x, ex& pf) 02458 { 02459 lst res; 02460 lst::const_iterator itm = m.begin(); 02461 lst::const_iterator itx = ++x.begin(); 02462 int signum = 1; 02463 pf = _ex1; 02464 res.append(*itm); 02465 itm++; 02466 while (itx != x.end()) { 02467 signum *= (*itx > 0) ? 1 : -1; 02468 pf *= signum; 02469 res.append((*itm) * signum); 02470 itm++; 02471 itx++; 02472 } 02473 return res; 02474 } 02475 02476 02477 // multiplies an one-dimensional H with another H 02478 // [ReV] (18) 02479 ex trafo_H_mult(const ex& h1, const ex& h2) 02480 { 02481 ex res; 02482 ex hshort; 02483 lst hlong; 02484 ex h1nops = h1.op(0).nops(); 02485 ex h2nops = h2.op(0).nops(); 02486 if (h1nops > 1) { 02487 hshort = h2.op(0).op(0); 02488 hlong = ex_to<lst>(h1.op(0)); 02489 } else { 02490 hshort = h1.op(0).op(0); 02491 if (h2nops > 1) { 02492 hlong = ex_to<lst>(h2.op(0)); 02493 } else { 02494 hlong = h2.op(0).op(0); 02495 } 02496 } 02497 for (std::size_t i=0; i<=hlong.nops(); i++) { 02498 lst newparameter; 02499 std::size_t j=0; 02500 for (; j<i; j++) { 02501 newparameter.append(hlong[j]); 02502 } 02503 newparameter.append(hshort); 02504 for (; j<hlong.nops(); j++) { 02505 newparameter.append(hlong[j]); 02506 } 02507 res += H(newparameter, h1.op(1)).hold(); 02508 } 02509 return res; 02510 } 02511 02512 02513 // applies trafo_H_mult recursively on expressions 02514 struct map_trafo_H_mult : public map_function 02515 { 02516 ex operator()(const ex& e) 02517 { 02518 if (is_a<add>(e)) { 02519 return e.map(*this); 02520 } 02521 02522 if (is_a<mul>(e)) { 02523 02524 ex result = 1; 02525 ex firstH; 02526 lst Hlst; 02527 for (std::size_t pos=0; pos<e.nops(); pos++) { 02528 if (is_a<power>(e.op(pos)) && is_a<function>(e.op(pos).op(0))) { 02529 std::string name = ex_to<function>(e.op(pos).op(0)).get_name(); 02530 if (name == "H") { 02531 for (ex i=0; i<e.op(pos).op(1); i++) { 02532 Hlst.append(e.op(pos).op(0)); 02533 } 02534 continue; 02535 } 02536 } else if (is_a<function>(e.op(pos))) { 02537 std::string name = ex_to<function>(e.op(pos)).get_name(); 02538 if (name == "H") { 02539 if (e.op(pos).op(0).nops() > 1) { 02540 firstH = e.op(pos); 02541 } else { 02542 Hlst.append(e.op(pos)); 02543 } 02544 continue; 02545 } 02546 } 02547 result *= e.op(pos); 02548 } 02549 if (firstH == 0) { 02550 if (Hlst.nops() > 0) { 02551 firstH = Hlst[Hlst.nops()-1]; 02552 Hlst.remove_last(); 02553 } else { 02554 return e; 02555 } 02556 } 02557 02558 if (Hlst.nops() > 0) { 02559 ex buffer = trafo_H_mult(firstH, Hlst.op(0)); 02560 result *= buffer; 02561 for (std::size_t i=1; i<Hlst.nops(); i++) { 02562 result *= Hlst.op(i); 02563 } 02564 result = result.expand(); 02565 map_trafo_H_mult recursion; 02566 return recursion(result); 02567 } else { 02568 return e; 02569 } 02570 02571 } 02572 return e; 02573 } 02574 }; 02575 02576 02577 // do integration [ReV] (55) 02578 // put parameter 0 in front of existing parameters 02579 ex trafo_H_1tx_prepend_zero(const ex& e, const ex& arg) 02580 { 02581 ex h; 02582 std::string name; 02583 if (is_a<function>(e)) { 02584 name = ex_to<function>(e).get_name(); 02585 } 02586 if (name == "H") { 02587 h = e; 02588 } else { 02589 for (std::size_t i=0; i<e.nops(); i++) { 02590 if (is_a<function>(e.op(i))) { 02591 std::string name = ex_to<function>(e.op(i)).get_name(); 02592 if (name == "H") { 02593 h = e.op(i); 02594 } 02595 } 02596 } 02597 } 02598 if (h != 0) { 02599 lst newparameter = ex_to<lst>(h.op(0)); 02600 newparameter.prepend(0); 02601 ex addzeta = convert_H_to_zeta(newparameter); 02602 return e.subs(h == (addzeta-H(newparameter, h.op(1)).hold())).expand(); 02603 } else { 02604 return e * (-H(lst(0),1/arg).hold()); 02605 } 02606 } 02607 02608 02609 // do integration [ReV] (49) 02610 // put parameter 1 in front of existing parameters 02611 ex trafo_H_prepend_one(const ex& e, const ex& arg) 02612 { 02613 ex h; 02614 std::string name; 02615 if (is_a<function>(e)) { 02616 name = ex_to<function>(e).get_name(); 02617 } 02618 if (name == "H") { 02619 h = e; 02620 } else { 02621 for (std::size_t i=0; i<e.nops(); i++) { 02622 if (is_a<function>(e.op(i))) { 02623 std::string name = ex_to<function>(e.op(i)).get_name(); 02624 if (name == "H") { 02625 h = e.op(i); 02626 } 02627 } 02628 } 02629 } 02630 if (h != 0) { 02631 lst newparameter = ex_to<lst>(h.op(0)); 02632 newparameter.prepend(1); 02633 return e.subs(h == H(newparameter, h.op(1)).hold()); 02634 } else { 02635 return e * H(lst(1),1-arg).hold(); 02636 } 02637 } 02638 02639 02640 // do integration [ReV] (55) 02641 // put parameter -1 in front of existing parameters 02642 ex trafo_H_1tx_prepend_minusone(const ex& e, const ex& arg) 02643 { 02644 ex h; 02645 std::string name; 02646 if (is_a<function>(e)) { 02647 name = ex_to<function>(e).get_name(); 02648 } 02649 if (name == "H") { 02650 h = e; 02651 } else { 02652 for (std::size_t i=0; i<e.nops(); i++) { 02653 if (is_a<function>(e.op(i))) { 02654 std::string name = ex_to<function>(e.op(i)).get_name(); 02655 if (name == "H") { 02656 h = e.op(i); 02657 } 02658 } 02659 } 02660 } 02661 if (h != 0) { 02662 lst newparameter = ex_to<lst>(h.op(0)); 02663 newparameter.prepend(-1); 02664 ex addzeta = convert_H_to_zeta(newparameter); 02665 return e.subs(h == (addzeta-H(newparameter, h.op(1)).hold())).expand(); 02666 } else { 02667 ex addzeta = convert_H_to_zeta(lst(-1)); 02668 return (e * (addzeta - H(lst(-1),1/arg).hold())).expand(); 02669 } 02670 } 02671 02672 02673 // do integration [ReV] (55) 02674 // put parameter -1 in front of existing parameters 02675 ex trafo_H_1mxt1px_prepend_minusone(const ex& e, const ex& arg) 02676 { 02677 ex h; 02678 std::string name; 02679 if (is_a<function>(e)) { 02680 name = ex_to<function>(e).get_name(); 02681 } 02682 if (name == "H") { 02683 h = e; 02684 } else { 02685 for (std::size_t i = 0; i < e.nops(); i++) { 02686 if (is_a<function>(e.op(i))) { 02687 std::string name = ex_to<function>(e.op(i)).get_name(); 02688 if (name == "H") { 02689 h = e.op(i); 02690 } 02691 } 02692 } 02693 } 02694 if (h != 0) { 02695 lst newparameter = ex_to<lst>(h.op(0)); 02696 newparameter.prepend(-1); 02697 return e.subs(h == H(newparameter, h.op(1)).hold()).expand(); 02698 } else { 02699 return (e * H(lst(-1),(1-arg)/(1+arg)).hold()).expand(); 02700 } 02701 } 02702 02703 02704 // do integration [ReV] (55) 02705 // put parameter 1 in front of existing parameters 02706 ex trafo_H_1mxt1px_prepend_one(const ex& e, const ex& arg) 02707 { 02708 ex h; 02709 std::string name; 02710 if (is_a<function>(e)) { 02711 name = ex_to<function>(e).get_name(); 02712 } 02713 if (name == "H") { 02714 h = e; 02715 } else { 02716 for (std::size_t i = 0; i < e.nops(); i++) { 02717 if (is_a<function>(e.op(i))) { 02718 std::string name = ex_to<function>(e.op(i)).get_name(); 02719 if (name == "H") { 02720 h = e.op(i); 02721 } 02722 } 02723 } 02724 } 02725 if (h != 0) { 02726 lst newparameter = ex_to<lst>(h.op(0)); 02727 newparameter.prepend(1); 02728 return e.subs(h == H(newparameter, h.op(1)).hold()).expand(); 02729 } else { 02730 return (e * H(lst(1),(1-arg)/(1+arg)).hold()).expand(); 02731 } 02732 } 02733 02734 02735 // do x -> 1-x transformation 02736 struct map_trafo_H_1mx : public map_function 02737 { 02738 ex operator()(const ex& e) 02739 { 02740 if (is_a<add>(e) || is_a<mul>(e)) { 02741 return e.map(*this); 02742 } 02743 02744 if (is_a<function>(e)) { 02745 std::string name = ex_to<function>(e).get_name(); 02746 if (name == "H") { 02747 02748 lst parameter = ex_to<lst>(e.op(0)); 02749 ex arg = e.op(1); 02750 02751 // special cases if all parameters are either 0, 1 or -1 02752 bool allthesame = true; 02753 if (parameter.op(0) == 0) { 02754 for (std::size_t i = 1; i < parameter.nops(); i++) { 02755 if (parameter.op(i) != 0) { 02756 allthesame = false; 02757 break; 02758 } 02759 } 02760 if (allthesame) { 02761 lst newparameter; 02762 for (int i=parameter.nops(); i>0; i--) { 02763 newparameter.append(1); 02764 } 02765 return pow(-1, parameter.nops()) * H(newparameter, 1-arg).hold(); 02766 } 02767 } else if (parameter.op(0) == -1) { 02768 throw std::runtime_error("map_trafo_H_1mx: cannot handle weights equal -1!"); 02769 } else { 02770 for (std::size_t i = 1; i < parameter.nops(); i++) { 02771 if (parameter.op(i) != 1) { 02772 allthesame = false; 02773 break; 02774 } 02775 } 02776 if (allthesame) { 02777 lst newparameter; 02778 for (int i=parameter.nops(); i>0; i--) { 02779 newparameter.append(0); 02780 } 02781 return pow(-1, parameter.nops()) * H(newparameter, 1-arg).hold(); 02782 } 02783 } 02784 02785 lst newparameter = parameter; 02786 newparameter.remove_first(); 02787 02788 if (parameter.op(0) == 0) { 02789 02790 // leading zero 02791 ex res = convert_H_to_zeta(parameter); 02792 //ex res = convert_from_RV(parameter, 1).subs(H(wild(1),wild(2))==zeta(wild(1))); 02793 map_trafo_H_1mx recursion; 02794 ex buffer = recursion(H(newparameter, arg).hold()); 02795 if (is_a<add>(buffer)) { 02796 for (std::size_t i = 0; i < buffer.nops(); i++) { 02797 res -= trafo_H_prepend_one(buffer.op(i), arg); 02798 } 02799 } else { 02800 res -= trafo_H_prepend_one(buffer, arg); 02801 } 02802 return res; 02803 02804 } else { 02805 02806 // leading one 02807 map_trafo_H_1mx recursion; 02808 map_trafo_H_mult unify; 02809 ex res = H(lst(1), arg).hold() * H(newparameter, arg).hold(); 02810 std::size_t firstzero = 0; 02811 while (parameter.op(firstzero) == 1) { 02812 firstzero++; 02813 } 02814 for (std::size_t i = firstzero-1; i < parameter.nops()-1; i++) { 02815 lst newparameter; 02816 std::size_t j=0; 02817 for (; j<=i; j++) { 02818 newparameter.append(parameter[j+1]); 02819 } 02820 newparameter.append(1); 02821 for (; j<parameter.nops()-1; j++) { 02822 newparameter.append(parameter[j+1]); 02823 } 02824 res -= H(newparameter, arg).hold(); 02825 } 02826 res = recursion(res).expand() / firstzero; 02827 return unify(res); 02828 } 02829 } 02830 } 02831 return e; 02832 } 02833 }; 02834 02835 02836 // do x -> 1/x transformation 02837 struct map_trafo_H_1overx : public map_function 02838 { 02839 ex operator()(const ex& e) 02840 { 02841 if (is_a<add>(e) || is_a<mul>(e)) { 02842 return e.map(*this); 02843 } 02844 02845 if (is_a<function>(e)) { 02846 std::string name = ex_to<function>(e).get_name(); 02847 if (name == "H") { 02848 02849 lst parameter = ex_to<lst>(e.op(0)); 02850 ex arg = e.op(1); 02851 02852 // special cases if all parameters are either 0, 1 or -1 02853 bool allthesame = true; 02854 if (parameter.op(0) == 0) { 02855 for (std::size_t i = 1; i < parameter.nops(); i++) { 02856 if (parameter.op(i) != 0) { 02857 allthesame = false; 02858 break; 02859 } 02860 } 02861 if (allthesame) { 02862 return pow(-1, parameter.nops()) * H(parameter, 1/arg).hold(); 02863 } 02864 } else if (parameter.op(0) == -1) { 02865 for (std::size_t i = 1; i < parameter.nops(); i++) { 02866 if (parameter.op(i) != -1) { 02867 allthesame = false; 02868 break; 02869 } 02870 } 02871 if (allthesame) { 02872 map_trafo_H_mult unify; 02873 return unify((pow(H(lst(-1),1/arg).hold() - H(lst(0),1/arg).hold(), parameter.nops()) 02874 / factorial(parameter.nops())).expand()); 02875 } 02876 } else { 02877 for (std::size_t i = 1; i < parameter.nops(); i++) { 02878 if (parameter.op(i) != 1) { 02879 allthesame = false; 02880 break; 02881 } 02882 } 02883 if (allthesame) { 02884 map_trafo_H_mult unify; 02885 return unify((pow(H(lst(1),1/arg).hold() + H(lst(0),1/arg).hold() + H_polesign, parameter.nops()) 02886 / factorial(parameter.nops())).expand()); 02887 } 02888 } 02889 02890 lst newparameter = parameter; 02891 newparameter.remove_first(); 02892 02893 if (parameter.op(0) == 0) { 02894 02895 // leading zero 02896 ex res = convert_H_to_zeta(parameter); 02897 map_trafo_H_1overx recursion; 02898 ex buffer = recursion(H(newparameter, arg).hold()); 02899 if (is_a<add>(buffer)) { 02900 for (std::size_t i = 0; i < buffer.nops(); i++) { 02901 res += trafo_H_1tx_prepend_zero(buffer.op(i), arg); 02902 } 02903 } else { 02904 res += trafo_H_1tx_prepend_zero(buffer, arg); 02905 } 02906 return res; 02907 02908 } else if (parameter.op(0) == -1) { 02909 02910 // leading negative one 02911 ex res = convert_H_to_zeta(parameter); 02912 map_trafo_H_1overx recursion; 02913 ex buffer = recursion(H(newparameter, arg).hold()); 02914 if (is_a<add>(buffer)) { 02915 for (std::size_t i = 0; i < buffer.nops(); i++) { 02916 res += trafo_H_1tx_prepend_zero(buffer.op(i), arg) - trafo_H_1tx_prepend_minusone(buffer.op(i), arg); 02917 } 02918 } else { 02919 res += trafo_H_1tx_prepend_zero(buffer, arg) - trafo_H_1tx_prepend_minusone(buffer, arg); 02920 } 02921 return res; 02922 02923 } else { 02924 02925 // leading one 02926 map_trafo_H_1overx recursion; 02927 map_trafo_H_mult unify; 02928 ex res = H(lst(1), arg).hold() * H(newparameter, arg).hold(); 02929 std::size_t firstzero = 0; 02930 while (parameter.op(firstzero) == 1) { 02931 firstzero++; 02932 } 02933 for (std::size_t i = firstzero-1; i < parameter.nops() - 1; i++) { 02934 lst newparameter; 02935 std::size_t j = 0; 02936 for (; j<=i; j++) { 02937 newparameter.append(parameter[j+1]); 02938 } 02939 newparameter.append(1); 02940 for (; j<parameter.nops()-1; j++) { 02941 newparameter.append(parameter[j+1]); 02942 } 02943 res -= H(newparameter, arg).hold(); 02944 } 02945 res = recursion(res).expand() / firstzero; 02946 return unify(res); 02947 02948 } 02949 02950 } 02951 } 02952 return e; 02953 } 02954 }; 02955 02956 02957 // do x -> (1-x)/(1+x) transformation 02958 struct map_trafo_H_1mxt1px : public map_function 02959 { 02960 ex operator()(const ex& e) 02961 { 02962 if (is_a<add>(e) || is_a<mul>(e)) { 02963 return e.map(*this); 02964 } 02965 02966 if (is_a<function>(e)) { 02967 std::string name = ex_to<function>(e).get_name(); 02968 if (name == "H") { 02969 02970 lst parameter = ex_to<lst>(e.op(0)); 02971 ex arg = e.op(1); 02972 02973 // special cases if all parameters are either 0, 1 or -1 02974 bool allthesame = true; 02975 if (parameter.op(0) == 0) { 02976 for (std::size_t i = 1; i < parameter.nops(); i++) { 02977 if (parameter.op(i) != 0) { 02978 allthesame = false; 02979 break; 02980 } 02981 } 02982 if (allthesame) { 02983 map_trafo_H_mult unify; 02984 return unify((pow(-H(lst(1),(1-arg)/(1+arg)).hold() - H(lst(-1),(1-arg)/(1+arg)).hold(), parameter.nops()) 02985 / factorial(parameter.nops())).expand()); 02986 } 02987 } else if (parameter.op(0) == -1) { 02988 for (std::size_t i = 1; i < parameter.nops(); i++) { 02989 if (parameter.op(i) != -1) { 02990 allthesame = false; 02991 break; 02992 } 02993 } 02994 if (allthesame) { 02995 map_trafo_H_mult unify; 02996 return unify((pow(log(2) - H(lst(-1),(1-arg)/(1+arg)).hold(), parameter.nops()) 02997 / factorial(parameter.nops())).expand()); 02998 } 02999 } else { 03000 for (std::size_t i = 1; i < parameter.nops(); i++) { 03001 if (parameter.op(i) != 1) { 03002 allthesame = false; 03003 break; 03004 } 03005 } 03006 if (allthesame) { 03007 map_trafo_H_mult unify; 03008 return unify((pow(-log(2) - H(lst(0),(1-arg)/(1+arg)).hold() + H(lst(-1),(1-arg)/(1+arg)).hold(), parameter.nops()) 03009 / factorial(parameter.nops())).expand()); 03010 } 03011 } 03012 03013 lst newparameter = parameter; 03014 newparameter.remove_first(); 03015 03016 if (parameter.op(0) == 0) { 03017 03018 // leading zero 03019 ex res = convert_H_to_zeta(parameter); 03020 map_trafo_H_1mxt1px recursion; 03021 ex buffer = recursion(H(newparameter, arg).hold()); 03022 if (is_a<add>(buffer)) { 03023 for (std::size_t i = 0; i < buffer.nops(); i++) { 03024 res -= trafo_H_1mxt1px_prepend_one(buffer.op(i), arg) + trafo_H_1mxt1px_prepend_minusone(buffer.op(i), arg); 03025 } 03026 } else { 03027 res -= trafo_H_1mxt1px_prepend_one(buffer, arg) + trafo_H_1mxt1px_prepend_minusone(buffer, arg); 03028 } 03029 return res; 03030 03031 } else if (parameter.op(0) == -1) { 03032 03033 // leading negative one 03034 ex res = convert_H_to_zeta(parameter); 03035 map_trafo_H_1mxt1px recursion; 03036 ex buffer = recursion(H(newparameter, arg).hold()); 03037 if (is_a<add>(buffer)) { 03038 for (std::size_t i = 0; i < buffer.nops(); i++) { 03039 res -= trafo_H_1mxt1px_prepend_minusone(buffer.op(i), arg); 03040 } 03041 } else { 03042 res -= trafo_H_1mxt1px_prepend_minusone(buffer, arg); 03043 } 03044 return res; 03045 03046 } else { 03047 03048 // leading one 03049 map_trafo_H_1mxt1px recursion; 03050 map_trafo_H_mult unify; 03051 ex res = H(lst(1), arg).hold() * H(newparameter, arg).hold(); 03052 std::size_t firstzero = 0; 03053 while (parameter.op(firstzero) == 1) { 03054 firstzero++; 03055 } 03056 for (std::size_t i = firstzero - 1; i < parameter.nops() - 1; i++) { 03057 lst newparameter; 03058 std::size_t j=0; 03059 for (; j<=i; j++) { 03060 newparameter.append(parameter[j+1]); 03061 } 03062 newparameter.append(1); 03063 for (; j<parameter.nops()-1; j++) { 03064 newparameter.append(parameter[j+1]); 03065 } 03066 res -= H(newparameter, arg).hold(); 03067 } 03068 res = recursion(res).expand() / firstzero; 03069 return unify(res); 03070 03071 } 03072 03073 } 03074 } 03075 return e; 03076 } 03077 }; 03078 03079 03080 // do the actual summation. 03081 cln::cl_N H_do_sum(const std::vector<int>& m, const cln::cl_N& x) 03082 { 03083 const int j = m.size(); 03084 03085 std::vector<cln::cl_N> t(j); 03086 03087 cln::cl_F one = cln::cl_float(1, cln::float_format(Digits)); 03088 cln::cl_N factor = cln::expt(x, j) * one; 03089 cln::cl_N t0buf; 03090 int q = 0; 03091 do { 03092 t0buf = t[0]; 03093 q++; 03094 t[j-1] = t[j-1] + 1 / cln::expt(cln::cl_I(q),m[j-1]); 03095 for (int k=j-2; k>=1; k--) { 03096 t[k] = t[k] + t[k+1] / cln::expt(cln::cl_I(q+j-1-k), m[k]); 03097 } 03098 t[0] = t[0] + t[1] * factor / cln::expt(cln::cl_I(q+j-1), m[0]); 03099 factor = factor * x; 03100 } while (t[0] != t0buf); 03101 03102 return t[0]; 03103 } 03104 03105 03106 } // end of anonymous namespace 03107 03108 03110 // 03111 // Harmonic polylogarithm H(m,x) 03112 // 03113 // GiNaC function 03114 // 03116 03117 03118 static ex H_evalf(const ex& x1, const ex& x2) 03119 { 03120 if (is_a<lst>(x1)) { 03121 03122 cln::cl_N x; 03123 if (is_a<numeric>(x2)) { 03124 x = ex_to<numeric>(x2).to_cl_N(); 03125 } else { 03126 ex x2_val = x2.evalf(); 03127 if (is_a<numeric>(x2_val)) { 03128 x = ex_to<numeric>(x2_val).to_cl_N(); 03129 } 03130 } 03131 03132 for (std::size_t i = 0; i < x1.nops(); i++) { 03133 if (!x1.op(i).info(info_flags::integer)) { 03134 return H(x1, x2).hold(); 03135 } 03136 } 03137 if (x1.nops() < 1) { 03138 return H(x1, x2).hold(); 03139 } 03140 03141 const lst& morg = ex_to<lst>(x1); 03142 // remove trailing zeros ... 03143 if (*(--morg.end()) == 0) { 03144 symbol xtemp("xtemp"); 03145 map_trafo_H_reduce_trailing_zeros filter; 03146 return filter(H(x1, xtemp).hold()).subs(xtemp==x2).evalf(); 03147 } 03148 // ... and expand parameter notation 03149 bool has_minus_one = false; 03150 lst m; 03151 for (lst::const_iterator it = morg.begin(); it != morg.end(); it++) { 03152 if (*it > 1) { 03153 for (ex count=*it-1; count > 0; count--) { 03154 m.append(0); 03155 } 03156 m.append(1); 03157 } else if (*it <= -1) { 03158 for (ex count=*it+1; count < 0; count++) { 03159 m.append(0); 03160 } 03161 m.append(-1); 03162 has_minus_one = true; 03163 } else { 03164 m.append(*it); 03165 } 03166 } 03167 03168 // do summation 03169 if (cln::abs(x) < 0.95) { 03170 lst m_lst; 03171 lst s_lst; 03172 ex pf; 03173 if (convert_parameter_H_to_Li(m, m_lst, s_lst, pf)) { 03174 // negative parameters -> s_lst is filled 03175 std::vector<int> m_int; 03176 std::vector<cln::cl_N> x_cln; 03177 for (lst::const_iterator it_int = m_lst.begin(), it_cln = s_lst.begin(); 03178 it_int != m_lst.end(); it_int++, it_cln++) { 03179 m_int.push_back(ex_to<numeric>(*it_int).to_int()); 03180 x_cln.push_back(ex_to<numeric>(*it_cln).to_cl_N()); 03181 } 03182 x_cln.front() = x_cln.front() * x; 03183 return pf * numeric(multipleLi_do_sum(m_int, x_cln)); 03184 } else { 03185 // only positive parameters 03186 //TODO 03187 if (m_lst.nops() == 1) { 03188 return Li(m_lst.op(0), x2).evalf(); 03189 } 03190 std::vector<int> m_int; 03191 for (lst::const_iterator it = m_lst.begin(); it != m_lst.end(); it++) { 03192 m_int.push_back(ex_to<numeric>(*it).to_int()); 03193 } 03194 return numeric(H_do_sum(m_int, x)); 03195 } 03196 } 03197 03198 symbol xtemp("xtemp"); 03199 ex res = 1; 03200 03201 // ensure that the realpart of the argument is positive 03202 if (cln::realpart(x) < 0) { 03203 x = -x; 03204 for (std::size_t i = 0; i < m.nops(); i++) { 03205 if (m.op(i) != 0) { 03206 m.let_op(i) = -m.op(i); 03207 res *= -1; 03208 } 03209 } 03210 } 03211 03212 // x -> 1/x 03213 if (cln::abs(x) >= 2.0) { 03214 map_trafo_H_1overx trafo; 03215 res *= trafo(H(m, xtemp)); 03216 if (cln::imagpart(x) <= 0) { 03217 res = res.subs(H_polesign == -I*Pi); 03218 } else { 03219 res = res.subs(H_polesign == I*Pi); 03220 } 03221 return res.subs(xtemp == numeric(x)).evalf(); 03222 } 03223 03224 // check transformations for 0.95 <= |x| < 2.0 03225 03226 // |(1-x)/(1+x)| < 0.9 -> circular area with center=9.53+0i and radius=9.47 03227 if (cln::abs(x-9.53) <= 9.47) { 03228 // x -> (1-x)/(1+x) 03229 map_trafo_H_1mxt1px trafo; 03230 res *= trafo(H(m, xtemp)); 03231 } else { 03232 // x -> 1-x 03233 if (has_minus_one) { 03234 map_trafo_H_convert_to_Li filter; 03235 return filter(H(m, numeric(x)).hold()).evalf(); 03236 } 03237 map_trafo_H_1mx trafo; 03238 res *= trafo(H(m, xtemp)); 03239 } 03240 03241 return res.subs(xtemp == numeric(x)).evalf(); 03242 } 03243 03244 return H(x1,x2).hold(); 03245 } 03246 03247 03248 static ex H_eval(const ex& m_, const ex& x) 03249 { 03250 lst m; 03251 if (is_a<lst>(m_)) { 03252 m = ex_to<lst>(m_); 03253 } else { 03254 m = lst(m_); 03255 } 03256 if (m.nops() == 0) { 03257 return _ex1; 03258 } 03259 ex pos1; 03260 ex pos2; 03261 ex n; 03262 ex p; 03263 int step = 0; 03264 if (*m.begin() > _ex1) { 03265 step++; 03266 pos1 = _ex0; 03267 pos2 = _ex1; 03268 n = *m.begin()-1; 03269 p = _ex1; 03270 } else if (*m.begin() < _ex_1) { 03271 step++; 03272 pos1 = _ex0; 03273 pos2 = _ex_1; 03274 n = -*m.begin()-1; 03275 p = _ex1; 03276 } else if (*m.begin() == _ex0) { 03277 pos1 = _ex0; 03278 n = _ex1; 03279 } else { 03280 pos1 = *m.begin(); 03281 p = _ex1; 03282 } 03283 for (lst::const_iterator it = ++m.begin(); it != m.end(); it++) { 03284 if ((*it).info(info_flags::integer)) { 03285 if (step == 0) { 03286 if (*it > _ex1) { 03287 if (pos1 == _ex0) { 03288 step = 1; 03289 pos2 = _ex1; 03290 n += *it-1; 03291 p = _ex1; 03292 } else { 03293 step = 2; 03294 } 03295 } else if (*it < _ex_1) { 03296 if (pos1 == _ex0) { 03297 step = 1; 03298 pos2 = _ex_1; 03299 n += -*it-1; 03300 p = _ex1; 03301 } else { 03302 step = 2; 03303 } 03304 } else { 03305 if (*it != pos1) { 03306 step = 1; 03307 pos2 = *it; 03308 } 03309 if (*it == _ex0) { 03310 n++; 03311 } else { 03312 p++; 03313 } 03314 } 03315 } else if (step == 1) { 03316 if (*it != pos2) { 03317 step = 2; 03318 } else { 03319 if (*it == _ex0) { 03320 n++; 03321 } else { 03322 p++; 03323 } 03324 } 03325 } 03326 } else { 03327 // if some m_i is not an integer 03328 return H(m_, x).hold(); 03329 } 03330 } 03331 if ((x == _ex1) && (*(--m.end()) != _ex0)) { 03332 return convert_H_to_zeta(m); 03333 } 03334 if (step == 0) { 03335 if (pos1 == _ex0) { 03336 // all zero 03337 if (x == _ex0) { 03338 return H(m_, x).hold(); 03339 } 03340 return pow(log(x), m.nops()) / factorial(m.nops()); 03341 } else { 03342 // all (minus) one 03343 return pow(-pos1*log(1-pos1*x), m.nops()) / factorial(m.nops()); 03344 } 03345 } else if ((step == 1) && (pos1 == _ex0)){ 03346 // convertible to S 03347 if (pos2 == _ex1) { 03348 return S(n, p, x); 03349 } else { 03350 return pow(-1, p) * S(n, p, -x); 03351 } 03352 } 03353 if (x == _ex0) { 03354 return _ex0; 03355 } 03356 if (x.info(info_flags::numeric) && (!x.info(info_flags::crational))) { 03357 return H(m_, x).evalf(); 03358 } 03359 return H(m_, x).hold(); 03360 } 03361 03362 03363 static ex H_series(const ex& m, const ex& x, const relational& rel, int order, unsigned options) 03364 { 03365 epvector seq; 03366 seq.push_back(expair(H(m, x), 0)); 03367 return pseries(rel, seq); 03368 } 03369 03370 03371 static ex H_deriv(const ex& m_, const ex& x, unsigned deriv_param) 03372 { 03373 GINAC_ASSERT(deriv_param < 2); 03374 if (deriv_param == 0) { 03375 return _ex0; 03376 } 03377 lst m; 03378 if (is_a<lst>(m_)) { 03379 m = ex_to<lst>(m_); 03380 } else { 03381 m = lst(m_); 03382 } 03383 ex mb = *m.begin(); 03384 if (mb > _ex1) { 03385 m[0]--; 03386 return H(m, x) / x; 03387 } 03388 if (mb < _ex_1) { 03389 m[0]++; 03390 return H(m, x) / x; 03391 } 03392 m.remove_first(); 03393 if (mb == _ex1) { 03394 return 1/(1-x) * H(m, x); 03395 } else if (mb == _ex_1) { 03396 return 1/(1+x) * H(m, x); 03397 } else { 03398 return H(m, x) / x; 03399 } 03400 } 03401 03402 03403 static void H_print_latex(const ex& m_, const ex& x, const print_context& c) 03404 { 03405 lst m; 03406 if (is_a<lst>(m_)) { 03407 m = ex_to<lst>(m_); 03408 } else { 03409 m = lst(m_); 03410 } 03411 c.s << "\\mathrm{H}_{"; 03412 lst::const_iterator itm = m.begin(); 03413 (*itm).print(c); 03414 itm++; 03415 for (; itm != m.end(); itm++) { 03416 c.s << ","; 03417 (*itm).print(c); 03418 } 03419 c.s << "}("; 03420 x.print(c); 03421 c.s << ")"; 03422 } 03423 03424 03425 REGISTER_FUNCTION(H, 03426 evalf_func(H_evalf). 03427 eval_func(H_eval). 03428 series_func(H_series). 03429 derivative_func(H_deriv). 03430 print_func<print_latex>(H_print_latex). 03431 do_not_evalf_params()); 03432 03433 03434 // takes a parameter list for H and returns an expression with corresponding multiple polylogarithms 03435 ex convert_H_to_Li(const ex& m, const ex& x) 03436 { 03437 map_trafo_H_reduce_trailing_zeros filter; 03438 map_trafo_H_convert_to_Li filter2; 03439 if (is_a<lst>(m)) { 03440 return filter2(filter(H(m, x).hold())); 03441 } else { 03442 return filter2(filter(H(lst(m), x).hold())); 03443 } 03444 } 03445 03446 03448 // 03449 // Multiple zeta values zeta(x) and zeta(x,s) 03450 // 03451 // helper functions 03452 // 03454 03455 03456 // anonymous namespace for helper functions 03457 namespace { 03458 03459 03460 // parameters and data for [Cra] algorithm 03461 const cln::cl_N lambda = cln::cl_N("319/320"); 03462 03463 void halfcyclic_convolute(const std::vector<cln::cl_N>& a, const std::vector<cln::cl_N>& b, std::vector<cln::cl_N>& c) 03464 { 03465 const int size = a.size(); 03466 for (int n=0; n<size; n++) { 03467 c[n] = 0; 03468 for (int m=0; m<=n; m++) { 03469 c[n] = c[n] + a[m]*b[n-m]; 03470 } 03471 } 03472 } 03473 03474 03475 // [Cra] section 4 03476 static void initcX(std::vector<cln::cl_N>& crX, 03477 const std::vector<int>& s, 03478 const int L2) 03479 { 03480 std::vector<cln::cl_N> crB(L2 + 1); 03481 for (int i=0; i<=L2; i++) 03482 crB[i] = bernoulli(i).to_cl_N() / cln::factorial(i); 03483 03484 int Sm = 0; 03485 int Smp1 = 0; 03486 std::vector<std::vector<cln::cl_N> > crG(s.size() - 1, std::vector<cln::cl_N>(L2 + 1)); 03487 for (int m=0; m < (int)s.size() - 1; m++) { 03488 Sm += s[m]; 03489 Smp1 = Sm + s[m+1]; 03490 for (int i = 0; i <= L2; i++) 03491 crG[m][i] = cln::factorial(i + Sm - m - 2) / cln::factorial(i + Smp1 - m - 2); 03492 } 03493 03494 crX = crB; 03495 03496 for (std::size_t m = 0; m < s.size() - 1; m++) { 03497 std::vector<cln::cl_N> Xbuf(L2 + 1); 03498 for (int i = 0; i <= L2; i++) 03499 Xbuf[i] = crX[i] * crG[m][i]; 03500 03501 halfcyclic_convolute(Xbuf, crB, crX); 03502 } 03503 } 03504 03505 03506 // [Cra] section 4 03507 static cln::cl_N crandall_Y_loop(const cln::cl_N& Sqk, 03508 const std::vector<cln::cl_N>& crX) 03509 { 03510 cln::cl_F one = cln::cl_float(1, cln::float_format(Digits)); 03511 cln::cl_N factor = cln::expt(lambda, Sqk); 03512 cln::cl_N res = factor / Sqk * crX[0] * one; 03513 cln::cl_N resbuf; 03514 int N = 0; 03515 do { 03516 resbuf = res; 03517 factor = factor * lambda; 03518 N++; 03519 res = res + crX[N] * factor / (N+Sqk); 03520 } while ((res != resbuf) || cln::zerop(crX[N])); 03521 return res; 03522 } 03523 03524 03525 // [Cra] section 4 03526 static void calc_f(std::vector<std::vector<cln::cl_N> >& f_kj, 03527 const int maxr, const int L1) 03528 { 03529 cln::cl_N t0, t1, t2, t3, t4; 03530 int i, j, k; 03531 std::vector<std::vector<cln::cl_N> >::iterator it = f_kj.begin(); 03532 cln::cl_F one = cln::cl_float(1, cln::float_format(Digits)); 03533 03534 t0 = cln::exp(-lambda); 03535 t2 = 1; 03536 for (k=1; k<=L1; k++) { 03537 t1 = k * lambda; 03538 t2 = t0 * t2; 03539 for (j=1; j<=maxr; j++) { 03540 t3 = 1; 03541 t4 = 1; 03542 for (i=2; i<=j; i++) { 03543 t4 = t4 * (j-i+1); 03544 t3 = t1 * t3 + t4; 03545 } 03546 (*it).push_back(t2 * t3 * cln::expt(cln::cl_I(k),-j) * one); 03547 } 03548 it++; 03549 } 03550 } 03551 03552 03553 // [Cra] (3.1) 03554 static cln::cl_N crandall_Z(const std::vector<int>& s, 03555 const std::vector<std::vector<cln::cl_N> >& f_kj) 03556 { 03557 const int j = s.size(); 03558 03559 if (j == 1) { 03560 cln::cl_N t0; 03561 cln::cl_N t0buf; 03562 int q = 0; 03563 do { 03564 t0buf = t0; 03565 q++; 03566 t0 = t0 + f_kj[q+j-2][s[0]-1]; 03567 } while (t0 != t0buf); 03568 03569 return t0 / cln::factorial(s[0]-1); 03570 } 03571 03572 std::vector<cln::cl_N> t(j); 03573 03574 cln::cl_N t0buf; 03575 int q = 0; 03576 do { 03577 t0buf = t[0]; 03578 q++; 03579 t[j-1] = t[j-1] + 1 / cln::expt(cln::cl_I(q),s[j-1]); 03580 for (int k=j-2; k>=1; k--) { 03581 t[k] = t[k] + t[k+1] / cln::expt(cln::cl_I(q+j-1-k), s[k]); 03582 } 03583 t[0] = t[0] + t[1] * f_kj[q+j-2][s[0]-1]; 03584 } while (t[0] != t0buf); 03585 03586 return t[0] / cln::factorial(s[0]-1); 03587 } 03588 03589 03590 // [Cra] (2.4) 03591 cln::cl_N zeta_do_sum_Crandall(const std::vector<int>& s) 03592 { 03593 std::vector<int> r = s; 03594 const int j = r.size(); 03595 03596 std::size_t L1; 03597 03598 // decide on maximal size of f_kj for crandall_Z 03599 if (Digits < 50) { 03600 L1 = 150; 03601 } else { 03602 L1 = Digits * 3 + j*2; 03603 } 03604 03605 std::size_t L2; 03606 // decide on maximal size of crX for crandall_Y 03607 if (Digits < 38) { 03608 L2 = 63; 03609 } else if (Digits < 86) { 03610 L2 = 127; 03611 } else if (Digits < 192) { 03612 L2 = 255; 03613 } else if (Digits < 394) { 03614 L2 = 511; 03615 } else if (Digits < 808) { 03616 L2 = 1023; 03617 } else { 03618 L2 = 2047; 03619 } 03620 03621 cln::cl_N res; 03622 03623 int maxr = 0; 03624 int S = 0; 03625 for (int i=0; i<j; i++) { 03626 S += r[i]; 03627 if (r[i] > maxr) { 03628 maxr = r[i]; 03629 } 03630 } 03631 03632 std::vector<std::vector<cln::cl_N> > f_kj(L1); 03633 calc_f(f_kj, maxr, L1); 03634 03635 const cln::cl_N r0factorial = cln::factorial(r[0]-1); 03636 03637 std::vector<int> rz; 03638 int skp1buf; 03639 int Srun = S; 03640 for (int k=r.size()-1; k>0; k--) { 03641 03642 rz.insert(rz.begin(), r.back()); 03643 skp1buf = rz.front(); 03644 Srun -= skp1buf; 03645 r.pop_back(); 03646 03647 std::vector<cln::cl_N> crX; 03648 initcX(crX, r, L2); 03649 03650 for (int q=0; q<skp1buf; q++) { 03651 03652 cln::cl_N pp1 = crandall_Y_loop(Srun+q-k, crX); 03653 cln::cl_N pp2 = crandall_Z(rz, f_kj); 03654 03655 rz.front()--; 03656 03657 if (q & 1) { 03658 res = res - pp1 * pp2 / cln::factorial(q); 03659 } else { 03660 res = res + pp1 * pp2 / cln::factorial(q); 03661 } 03662 } 03663 rz.front() = skp1buf; 03664 } 03665 rz.insert(rz.begin(), r.back()); 03666 03667 std::vector<cln::cl_N> crX; 03668 initcX(crX, rz, L2); 03669 03670 res = (res + crandall_Y_loop(S-j, crX)) / r0factorial 03671 + crandall_Z(rz, f_kj); 03672 03673 return res; 03674 } 03675 03676 03677 cln::cl_N zeta_do_sum_simple(const std::vector<int>& r) 03678 { 03679 const int j = r.size(); 03680 03681 // buffer for subsums 03682 std::vector<cln::cl_N> t(j); 03683 cln::cl_F one = cln::cl_float(1, cln::float_format(Digits)); 03684 03685 cln::cl_N t0buf; 03686 int q = 0; 03687 do { 03688 t0buf = t[0]; 03689 q++; 03690 t[j-1] = t[j-1] + one / cln::expt(cln::cl_I(q),r[j-1]); 03691 for (int k=j-2; k>=0; k--) { 03692 t[k] = t[k] + one * t[k+1] / cln::expt(cln::cl_I(q+j-1-k), r[k]); 03693 } 03694 } while (t[0] != t0buf); 03695 03696 return t[0]; 03697 } 03698 03699 03700 // does Hoelder convolution. see [BBB] (7.0) 03701 cln::cl_N zeta_do_Hoelder_convolution(const std::vector<int>& m_, const std::vector<int>& s_) 03702 { 03703 // prepare parameters 03704 // holds Li arguments in [BBB] notation 03705 std::vector<int> s = s_; 03706 std::vector<int> m_p = m_; 03707 std::vector<int> m_q; 03708 // holds Li arguments in nested sums notation 03709 std::vector<cln::cl_N> s_p(s.size(), cln::cl_N(1)); 03710 s_p[0] = s_p[0] * cln::cl_N("1/2"); 03711 // convert notations 03712 int sig = 1; 03713 for (std::size_t i = 0; i < s_.size(); i++) { 03714 if (s_[i] < 0) { 03715 sig = -sig; 03716 s_p[i] = -s_p[i]; 03717 } 03718 s[i] = sig * std::abs(s[i]); 03719 } 03720 std::vector<cln::cl_N> s_q; 03721 cln::cl_N signum = 1; 03722 03723 // first term 03724 cln::cl_N res = multipleLi_do_sum(m_p, s_p); 03725 03726 // middle terms 03727 do { 03728 03729 // change parameters 03730 if (s.front() > 0) { 03731 if (m_p.front() == 1) { 03732 m_p.erase(m_p.begin()); 03733 s_p.erase(s_p.begin()); 03734 if (s_p.size() > 0) { 03735 s_p.front() = s_p.front() * cln::cl_N("1/2"); 03736 } 03737 s.erase(s.begin()); 03738 m_q.front()++; 03739 } else { 03740 m_p.front()--; 03741 m_q.insert(m_q.begin(), 1); 03742 if (s_q.size() > 0) { 03743 s_q.front() = s_q.front() * 2; 03744 } 03745 s_q.insert(s_q.begin(), cln::cl_N("1/2")); 03746 } 03747 } else { 03748 if (m_p.front() == 1) { 03749 m_p.erase(m_p.begin()); 03750 cln::cl_N spbuf = s_p.front(); 03751 s_p.erase(s_p.begin()); 03752 if (s_p.size() > 0) { 03753 s_p.front() = s_p.front() * spbuf; 03754 } 03755 s.erase(s.begin()); 03756 m_q.insert(m_q.begin(), 1); 03757 if (s_q.size() > 0) { 03758 s_q.front() = s_q.front() * 4; 03759 } 03760 s_q.insert(s_q.begin(), cln::cl_N("1/4")); 03761 signum = -signum; 03762 } else { 03763 m_p.front()--; 03764 m_q.insert(m_q.begin(), 1); 03765 if (s_q.size() > 0) { 03766 s_q.front() = s_q.front() * 2; 03767 } 03768 s_q.insert(s_q.begin(), cln::cl_N("1/2")); 03769 } 03770 } 03771 03772 // exiting the loop 03773 if (m_p.size() == 0) break; 03774 03775 res = res + signum * multipleLi_do_sum(m_p, s_p) * multipleLi_do_sum(m_q, s_q); 03776 03777 } while (true); 03778 03779 // last term 03780 res = res + signum * multipleLi_do_sum(m_q, s_q); 03781 03782 return res; 03783 } 03784 03785 03786 } // end of anonymous namespace 03787 03788 03790 // 03791 // Multiple zeta values zeta(x) 03792 // 03793 // GiNaC function 03794 // 03796 03797 03798 static ex zeta1_evalf(const ex& x) 03799 { 03800 if (is_exactly_a<lst>(x) && (x.nops()>1)) { 03801 03802 // multiple zeta value 03803 const int count = x.nops(); 03804 const lst& xlst = ex_to<lst>(x); 03805 std::vector<int> r(count); 03806 03807 // check parameters and convert them 03808 lst::const_iterator it1 = xlst.begin(); 03809 std::vector<int>::iterator it2 = r.begin(); 03810 do { 03811 if (!(*it1).info(info_flags::posint)) { 03812 return zeta(x).hold(); 03813 } 03814 *it2 = ex_to<numeric>(*it1).to_int(); 03815 it1++; 03816 it2++; 03817 } while (it2 != r.end()); 03818 03819 // check for divergence 03820 if (r[0] == 1) { 03821 return zeta(x).hold(); 03822 } 03823 03824 // decide on summation algorithm 03825 // this is still a bit clumsy 03826 int limit = (Digits>17) ? 10 : 6; 03827 if ((r[0] < limit) || ((count > 3) && (r[1] < limit/2))) { 03828 return numeric(zeta_do_sum_Crandall(r)); 03829 } else { 03830 return numeric(zeta_do_sum_simple(r)); 03831 } 03832 } 03833 03834 // single zeta value 03835 if (is_exactly_a<numeric>(x) && (x != 1)) { 03836 try { 03837 return zeta(ex_to<numeric>(x)); 03838 } catch (const dunno &e) { } 03839 } 03840 03841 return zeta(x).hold(); 03842 } 03843 03844 03845 static ex zeta1_eval(const ex& m) 03846 { 03847 if (is_exactly_a<lst>(m)) { 03848 if (m.nops() == 1) { 03849 return zeta(m.op(0)); 03850 } 03851 return zeta(m).hold(); 03852 } 03853 03854 if (m.info(info_flags::numeric)) { 03855 const numeric& y = ex_to<numeric>(m); 03856 // trap integer arguments: 03857 if (y.is_integer()) { 03858 if (y.is_zero()) { 03859 return _ex_1_2; 03860 } 03861 if (y.is_equal(*_num1_p)) { 03862 return zeta(m).hold(); 03863 } 03864 if (y.info(info_flags::posint)) { 03865 if (y.info(info_flags::odd)) { 03866 return zeta(m).hold(); 03867 } else { 03868 return abs(bernoulli(y)) * pow(Pi, y) * pow(*_num2_p, y-(*_num1_p)) / factorial(y); 03869 } 03870 } else { 03871 if (y.info(info_flags::odd)) { 03872 return -bernoulli((*_num1_p)-y) / ((*_num1_p)-y); 03873 } else { 03874 return _ex0; 03875 } 03876 } 03877 } 03878 // zeta(float) 03879 if (y.info(info_flags::numeric) && !y.info(info_flags::crational)) { 03880 return zeta1_evalf(m); 03881 } 03882 } 03883 return zeta(m).hold(); 03884 } 03885 03886 03887 static ex zeta1_deriv(const ex& m, unsigned deriv_param) 03888 { 03889 GINAC_ASSERT(deriv_param==0); 03890 03891 if (is_exactly_a<lst>(m)) { 03892 return _ex0; 03893 } else { 03894 return zetaderiv(_ex1, m); 03895 } 03896 } 03897 03898 03899 static void zeta1_print_latex(const ex& m_, const print_context& c) 03900 { 03901 c.s << "\\zeta("; 03902 if (is_a<lst>(m_)) { 03903 const lst& m = ex_to<lst>(m_); 03904 lst::const_iterator it = m.begin(); 03905 (*it).print(c); 03906 it++; 03907 for (; it != m.end(); it++) { 03908 c.s << ","; 03909 (*it).print(c); 03910 } 03911 } else { 03912 m_.print(c); 03913 } 03914 c.s << ")"; 03915 } 03916 03917 03918 unsigned zeta1_SERIAL::serial = function::register_new(function_options("zeta", 1). 03919 evalf_func(zeta1_evalf). 03920 eval_func(zeta1_eval). 03921 derivative_func(zeta1_deriv). 03922 print_func<print_latex>(zeta1_print_latex). 03923 do_not_evalf_params(). 03924 overloaded(2)); 03925 03926 03928 // 03929 // Alternating Euler sum zeta(x,s) 03930 // 03931 // GiNaC function 03932 // 03934 03935 03936 static ex zeta2_evalf(const ex& x, const ex& s) 03937 { 03938 if (is_exactly_a<lst>(x)) { 03939 03940 // alternating Euler sum 03941 const int count = x.nops(); 03942 const lst& xlst = ex_to<lst>(x); 03943 const lst& slst = ex_to<lst>(s); 03944 std::vector<int> xi(count); 03945 std::vector<int> si(count); 03946 03947 // check parameters and convert them 03948 lst::const_iterator it_xread = xlst.begin(); 03949 lst::const_iterator it_sread = slst.begin(); 03950 std::vector<int>::iterator it_xwrite = xi.begin(); 03951 std::vector<int>::iterator it_swrite = si.begin(); 03952 do { 03953 if (!(*it_xread).info(info_flags::posint)) { 03954 return zeta(x, s).hold(); 03955 } 03956 *it_xwrite = ex_to<numeric>(*it_xread).to_int(); 03957 if (*it_sread > 0) { 03958 *it_swrite = 1; 03959 } else { 03960 *it_swrite = -1; 03961 } 03962 it_xread++; 03963 it_sread++; 03964 it_xwrite++; 03965 it_swrite++; 03966 } while (it_xwrite != xi.end()); 03967 03968 // check for divergence 03969 if ((xi[0] == 1) && (si[0] == 1)) { 03970 return zeta(x, s).hold(); 03971 } 03972 03973 // use Hoelder convolution 03974 return numeric(zeta_do_Hoelder_convolution(xi, si)); 03975 } 03976 03977 return zeta(x, s).hold(); 03978 } 03979 03980 03981 static ex zeta2_eval(const ex& m, const ex& s_) 03982 { 03983 if (is_exactly_a<lst>(s_)) { 03984 const lst& s = ex_to<lst>(s_); 03985 for (lst::const_iterator it = s.begin(); it != s.end(); it++) { 03986 if ((*it).info(info_flags::positive)) { 03987 continue; 03988 } 03989 return zeta(m, s_).hold(); 03990 } 03991 return zeta(m); 03992 } else if (s_.info(info_flags::positive)) { 03993 return zeta(m); 03994 } 03995 03996 return zeta(m, s_).hold(); 03997 } 03998 03999 04000 static ex zeta2_deriv(const ex& m, const ex& s, unsigned deriv_param) 04001 { 04002 GINAC_ASSERT(deriv_param==0); 04003 04004 if (is_exactly_a<lst>(m)) { 04005 return _ex0; 04006 } else { 04007 if ((is_exactly_a<lst>(s) && s.op(0).info(info_flags::positive)) || s.info(info_flags::positive)) { 04008 return zetaderiv(_ex1, m); 04009 } 04010 return _ex0; 04011 } 04012 } 04013 04014 04015 static void zeta2_print_latex(const ex& m_, const ex& s_, const print_context& c) 04016 { 04017 lst m; 04018 if (is_a<lst>(m_)) { 04019 m = ex_to<lst>(m_); 04020 } else { 04021 m = lst(m_); 04022 } 04023 lst s; 04024 if (is_a<lst>(s_)) { 04025 s = ex_to<lst>(s_); 04026 } else { 04027 s = lst(s_); 04028 } 04029 c.s << "\\zeta("; 04030 lst::const_iterator itm = m.begin(); 04031 lst::const_iterator its = s.begin(); 04032 if (*its < 0) { 04033 c.s << "\\overline{"; 04034 (*itm).print(c); 04035 c.s << "}"; 04036 } else { 04037 (*itm).print(c); 04038 } 04039 its++; 04040 itm++; 04041 for (; itm != m.end(); itm++, its++) { 04042 c.s << ","; 04043 if (*its < 0) { 04044 c.s << "\\overline{"; 04045 (*itm).print(c); 04046 c.s << "}"; 04047 } else { 04048 (*itm).print(c); 04049 } 04050 } 04051 c.s << ")"; 04052 } 04053 04054 04055 unsigned zeta2_SERIAL::serial = function::register_new(function_options("zeta", 2). 04056 evalf_func(zeta2_evalf). 04057 eval_func(zeta2_eval). 04058 derivative_func(zeta2_deriv). 04059 print_func<print_latex>(zeta2_print_latex). 04060 do_not_evalf_params(). 04061 overloaded(2)); 04062 04063 04064 } // namespace GiNaC 04065