GiNaC  1.6.2
inifcns_nstdsums.cpp
Go to the documentation of this file.
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 

This page is part of the GiNaC developer's reference. It was generated automatically by doxygen. For an introduction, see the tutorial.