/[GiNaC]/ginac/inifcns_nstdsums.cpp
ViewVC logotype

Contents of /ginac/inifcns_nstdsums.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.32 - (show annotations)
Mon Mar 5 17:05:49 2007 UTC (6 years, 3 months ago) by vollinga
Branch: MAIN
CVS Tags: release_1-4-1, release_1-4-0, HEAD
Branch point for: ginac_1-4
Changes since 1.31: +54 -55 lines
Improved handling of convergence transformationis for Li/G (fixes problems with certain H() evaluations).

1 /** @file inifcns_nstdsums.cpp
2 *
3 * Implementation of some special functions that have a representation as nested sums.
4 *
5 * The functions are:
6 * classical polylogarithm Li(n,x)
7 * multiple polylogarithm Li(lst(m_1,...,m_k),lst(x_1,...,x_k))
8 * G(lst(a_1,...,a_k),y) or G(lst(a_1,...,a_k),lst(s_1,...,s_k),y)
9 * Nielsen's generalized polylogarithm S(n,p,x)
10 * harmonic polylogarithm H(m,x) or H(lst(m_1,...,m_k),x)
11 * multiple zeta value zeta(m) or zeta(lst(m_1,...,m_k))
12 * alternating Euler sum zeta(m,s) or zeta(lst(m_1,...,m_k),lst(s_1,...,s_k))
13 *
14 * Some remarks:
15 *
16 * - All formulae used can be looked up in the following publications:
17 * [Kol] Nielsen's Generalized Polylogarithms, K.S.Kolbig, SIAM J.Math.Anal. 17 (1986), pp. 1232-1258.
18 * [Cra] Fast Evaluation of Multiple Zeta Sums, R.E.Crandall, Math.Comp. 67 (1998), pp. 1163-1172.
19 * [ReV] Harmonic Polylogarithms, E.Remiddi, J.A.M.Vermaseren, Int.J.Mod.Phys. A15 (2000), pp. 725-754
20 * [BBB] Special Values of Multiple Polylogarithms, J.Borwein, D.Bradley, D.Broadhurst, P.Lisonek, Trans.Amer.Math.Soc. 353/3 (2001), pp. 907-941
21 * [VSW] Numerical evaluation of multiple polylogarithms, J.Vollinga, S.Weinzierl, hep-ph/0410259
22 *
23 * - The order of parameters and arguments of Li and zeta is defined according to the nested sums
24 * representation. The parameters for H are understood as in [ReV]. They can be in expanded --- only
25 * 0, 1 and -1 --- or in compactified --- a string with zeros in front of 1 or -1 is written as a single
26 * number --- notation.
27 *
28 * - All functions can be nummerically evaluated with arguments in the whole complex plane. The parameters
29 * for Li, zeta and S must be positive integers. If you want to have an alternating Euler sum, you have
30 * to give the signs of the parameters as a second argument s to zeta(m,s) containing 1 and -1.
31 *
32 * - The calculation of classical polylogarithms is speeded up by using Bernoulli numbers and
33 * look-up tables. S uses look-up tables as well. The zeta function applies the algorithms in
34 * [Cra] and [BBB] for speed up. Multiple polylogarithms use Hoelder convolution [BBB].
35 *
36 * - The functions have no means to do a series expansion into nested sums. To do this, you have to convert
37 * these functions into the appropriate objects from the nestedsums library, do the expansion and convert
38 * the result back.
39 *
40 * - Numerical testing of this implementation has been performed by doing a comparison of results
41 * between this software and the commercial M.......... 4.1. Multiple zeta values have been checked
42 * by means of evaluations into simple zeta values. Harmonic polylogarithms have been checked by
43 * comparison to S(n,p,x) for corresponding parameter combinations and by continuity checks
44 * around |x|=1 along with comparisons to corresponding zeta functions. Multiple polylogarithms were
45 * checked against H and zeta and by means of shuffle and quasi-shuffle relations.
46 *
47 */
48
49 /*
50 * GiNaC Copyright (C) 1999-2007 Johannes Gutenberg University Mainz, Germany
51 *
52 * This program is free software; you can redistribute it and/or modify
53 * it under the terms of the GNU General Public License as published by
54 * the Free Software Foundation; either version 2 of the License, or
55 * (at your option) any later version.
56 *
57 * This program is distributed in the hope that it will be useful,
58 * but WITHOUT ANY WARRANTY; without even the implied warranty of
59 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
60 * GNU General Public License for more details.
61 *
62 * You should have received a copy of the GNU General Public License
63 * along with this program; if not, write to the Free Software
64 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
65 */
66
67 #include <sstream>
68 #include <stdexcept>
69 #include <vector>
70 #include <cln/cln.h>
71
72 #include "inifcns.h"
73
74 #include "add.h"
75 #include "constant.h"
76 #include "lst.h"
77 #include "mul.h"
78 #include "numeric.h"
79 #include "operators.h"
80 #include "power.h"
81 #include "pseries.h"
82 #include "relational.h"
83 #include "symbol.h"
84 #include "utils.h"
85 #include "wildcard.h"
86
87
88 namespace GiNaC {
89
90
91 //////////////////////////////////////////////////////////////////////
92 //
93 // Classical polylogarithm Li(n,x)
94 //
95 // helper functions
96 //
97 //////////////////////////////////////////////////////////////////////
98
99
100 // anonymous namespace for helper functions
101 namespace {
102
103
104 // lookup table for factors built from Bernoulli numbers
105 // see fill_Xn()
106 std::vector<std::vector<cln::cl_N> > Xn;
107 // initial size of Xn that should suffice for 32bit machines (must be even)
108 const int xninitsizestep = 26;
109 int xninitsize = xninitsizestep;
110 int xnsize = 0;
111
112
113 // This function calculates the X_n. The X_n are needed for speed up of classical polylogarithms.
114 // With these numbers the polylogs can be calculated as follows:
115 // Li_p (x) = \sum_{n=0}^\infty X_{p-2}(n) u^{n+1}/(n+1)! with u = -log(1-x)
116 // X_0(n) = B_n (Bernoulli numbers)
117 // X_p(n) = \sum_{k=0}^n binomial(n,k) B_{n-k} / (k+1) * X_{p-1}(k)
118 // The calculation of Xn depends on X0 and X{n-1}.
119 // X_0 is special, it holds only the non-zero Bernoulli numbers with index 2 or greater.
120 // This results in a slightly more complicated algorithm for the X_n.
121 // The first index in Xn corresponds to the index of the polylog minus 2.
122 // The second index in Xn corresponds to the index from the actual sum.
123 void fill_Xn(int n)
124 {
125 if (n>1) {
126 // calculate X_2 and higher (corresponding to Li_4 and higher)
127 std::vector<cln::cl_N> buf(xninitsize);
128 std::vector<cln::cl_N>::iterator it = buf.begin();
129 cln::cl_N result;
130 *it = -(cln::expt(cln::cl_I(2),n+1) - 1) / cln::expt(cln::cl_I(2),n+1); // i == 1
131 it++;
132 for (int i=2; i<=xninitsize; i++) {
133 if (i&1) {
134 result = 0; // k == 0
135 } else {
136 result = Xn[0][i/2-1]; // k == 0
137 }
138 for (int k=1; k<i-1; k++) {
139 if ( !(((i-k) & 1) && ((i-k) > 1)) ) {
140 result = result + cln::binomial(i,k) * Xn[0][(i-k)/2-1] * Xn[n-1][k-1] / (k+1);
141 }
142 }
143 result = result - cln::binomial(i,i-1) * Xn[n-1][i-2] / 2 / i; // k == i-1
144 result = result + Xn[n-1][i-1] / (i+1); // k == i
145
146 *it = result;
147 it++;
148 }
149 Xn.push_back(buf);
150 } else if (n==1) {
151 // special case to handle the X_0 correct
152 std::vector<cln::cl_N> buf(xninitsize);
153 std::vector<cln::cl_N>::iterator it = buf.begin();
154 cln::cl_N result;
155 *it = cln::cl_I(-3)/cln::cl_I(4); // i == 1
156 it++;
157 *it = cln::cl_I(17)/cln::cl_I(36); // i == 2
158 it++;
159 for (int i=3; i<=xninitsize; i++) {
160 if (i & 1) {
161 result = -Xn[0][(i-3)/2]/2;
162 *it = (cln::binomial(i,1)/cln::cl_I(2) + cln::binomial(i,i-1)/cln::cl_I(i))*result;
163 it++;
164 } else {
165 result = Xn[0][i/2-1] + Xn[0][i/2-1]/(i+1);
166 for (int k=1; k<i/2; k++) {
167 result = result + cln::binomial(i,k*2) * Xn[0][k-1] * Xn[0][i/2-k-1] / (k*2+1);
168 }
169 *it = result;
170 it++;
171 }
172 }
173 Xn.push_back(buf);
174 } else {
175 // calculate X_0
176 std::vector<cln::cl_N> buf(xninitsize/2);
177 std::vector<cln::cl_N>::iterator it = buf.begin();
178 for (int i=1; i<=xninitsize/2; i++) {
179 *it = bernoulli(i*2).to_cl_N();
180 it++;
181 }
182 Xn.push_back(buf);
183 }
184
185 xnsize++;
186 }
187
188 // doubles the number of entries in each Xn[]
189 void double_Xn()
190 {
191 const int pos0 = xninitsize / 2;
192 // X_0
193 for (int i=1; i<=xninitsizestep/2; ++i) {
194 Xn[0].push_back(bernoulli((i+pos0)*2).to_cl_N());
195 }
196 if (Xn.size() > 1) {
197 int xend = xninitsize + xninitsizestep;
198 cln::cl_N result;
199 // X_1
200 for (int i=xninitsize+1; i<=xend; ++i) {
201 if (i & 1) {
202 result = -Xn[0][(i-3)/2]/2;
203 Xn[1].push_back((cln::binomial(i,1)/cln::cl_I(2) + cln::binomial(i,i-1)/cln::cl_I(i))*result);
204 } else {
205 result = Xn[0][i/2-1] + Xn[0][i/2-1]/(i+1);
206 for (int k=1; k<i/2; k++) {
207 result = result + cln::binomial(i,k*2) * Xn[0][k-1] * Xn[0][i/2-k-1] / (k*2+1);
208 }
209 Xn[1].push_back(result);
210 }
211 }
212 // X_n
213 for (int n=2; n<Xn.size(); ++n) {
214 for (int i=xninitsize+1; i<=xend; ++i) {
215 if (i & 1) {
216 result = 0; // k == 0
217 } else {
218 result = Xn[0][i/2-1]; // k == 0
219 }
220 for (int k=1; k<i-1; ++k) {
221 if ( !(((i-k) & 1) && ((i-k) > 1)) ) {
222 result = result + cln::binomial(i,k) * Xn[0][(i-k)/2-1] * Xn[n-1][k-1] / (k+1);
223 }
224 }
225 result = result - cln::binomial(i,i-1) * Xn[n-1][i-2] / 2 / i; // k == i-1
226 result = result + Xn[n-1][i-1] / (i+1); // k == i
227 Xn[n].push_back(result);
228 }
229 }
230 }
231 xninitsize += xninitsizestep;
232 }
233
234
235 // calculates Li(2,x) without Xn
236 cln::cl_N Li2_do_sum(const cln::cl_N& x)
237 {
238 cln::cl_N res = x;
239 cln::cl_N resbuf;
240 cln::cl_N num = x * cln::cl_float(1, cln::float_format(Digits));
241 cln::cl_I den = 1; // n^2 = 1
242 unsigned i = 3;
243 do {
244 resbuf = res;
245 num = num * x;
246 den = den + i; // n^2 = 4, 9, 16, ...
247 i += 2;
248 res = res + num / den;
249 } while (res != resbuf);
250 return res;
251 }
252
253
254 // calculates Li(2,x) with Xn
255 cln::cl_N Li2_do_sum_Xn(const cln::cl_N& x)
256 {
257 std::vector<cln::cl_N>::const_iterator it = Xn[0].begin();
258 std::vector<cln::cl_N>::const_iterator xend = Xn[0].end();
259 cln::cl_N u = -cln::log(1-x);
260 cln::cl_N factor = u * cln::cl_float(1, cln::float_format(Digits));
261 cln::cl_N uu = cln::square(u);
262 cln::cl_N res = u - uu/4;
263 cln::cl_N resbuf;
264 unsigned i = 1;
265 do {
266 resbuf = res;
267 factor = factor * uu / (2*i * (2*i+1));
268 res = res + (*it) * factor;
269 i++;
270 if (++it == xend) {
271 double_Xn();
272 it = Xn[0].begin() + (i-1);
273 xend = Xn[0].end();
274 }
275 } while (res != resbuf);
276 return res;
277 }
278
279
280 // calculates Li(n,x), n>2 without Xn
281 cln::cl_N Lin_do_sum(int n, const cln::cl_N& x)
282 {
283 cln::cl_N factor = x * cln::cl_float(1, cln::float_format(Digits));
284 cln::cl_N res = x;
285 cln::cl_N resbuf;
286 int i=2;
287 do {
288 resbuf = res;
289 factor = factor * x;
290 res = res + factor / cln::expt(cln::cl_I(i),n);
291 i++;
292 } while (res != resbuf);
293 return res;
294 }
295
296
297 // calculates Li(n,x), n>2 with Xn
298 cln::cl_N Lin_do_sum_Xn(int n, const cln::cl_N& x)
299 {
300 std::vector<cln::cl_N>::const_iterator it = Xn[n-2].begin();
301 std::vector<cln::cl_N>::const_iterator xend = Xn[n-2].end();
302 cln::cl_N u = -cln::log(1-x);
303 cln::cl_N factor = u * cln::cl_float(1, cln::float_format(Digits));
304 cln::cl_N res = u;
305 cln::cl_N resbuf;
306 unsigned i=2;
307 do {
308 resbuf = res;
309 factor = factor * u / i;
310 res = res + (*it) * factor;
311 i++;
312 if (++it == xend) {
313 double_Xn();
314 it = Xn[n-2].begin() + (i-2);
315 xend = Xn[n-2].end();
316 }
317 } while (res != resbuf);
318 return res;
319 }
320
321
322 // forward declaration needed by function Li_projection and C below
323 numeric S_num(int n, int p, const numeric& x);
324
325
326 // helper function for classical polylog Li
327 cln::cl_N Li_projection(int n, const cln::cl_N& x, const cln::float_format_t& prec)
328 {
329 // treat n=2 as special case
330 if (n == 2) {
331 // check if precalculated X0 exists
332 if (xnsize == 0) {
333 fill_Xn(0);
334 }
335
336 if (cln::realpart(x) < 0.5) {
337 // choose the faster algorithm
338 // the switching point was empirically determined. the optimal point
339 // depends on hardware, Digits, ... so an approx value is okay.
340 // it solves also the problem with precision due to the u=-log(1-x) transformation
341 if (cln::abs(cln::realpart(x)) < 0.25) {
342
343 return Li2_do_sum(x);
344 } else {
345 return Li2_do_sum_Xn(x);
346 }
347 } else {
348 // choose the faster algorithm
349 if (cln::abs(cln::realpart(x)) > 0.75) {
350 return -Li2_do_sum(1-x) - cln::log(x) * cln::log(1-x) + cln::zeta(2);
351 } else {
352 return -Li2_do_sum_Xn(1-x) - cln::log(x) * cln::log(1-x) + cln::zeta(2);
353 }
354 }
355 } else {
356 // check if precalculated Xn exist
357 if (n > xnsize+1) {
358 for (int i=xnsize; i<n-1; i++) {
359 fill_Xn(i);
360 }
361 }
362
363 if (cln::realpart(x) < 0.5) {
364 // choose the faster algorithm
365 // with n>=12 the "normal" summation always wins against the method with Xn
366 if ((cln::abs(cln::realpart(x)) < 0.3) || (n >= 12)) {
367 return Lin_do_sum(n, x);
368 } else {
369 return Lin_do_sum_Xn(n, x);
370 }
371 } else {
372 cln::cl_N result = -cln::expt(cln::log(x), n-1) * cln::log(1-x) / cln::factorial(n-1);
373 for (int j=0; j<n-1; j++) {
374 result = result + (S_num(n-j-1, 1, 1).to_cl_N() - S_num(1, n-j-1, 1-x).to_cl_N())
375 * cln::expt(cln::log(x), j) / cln::factorial(j);
376 }
377 return result;
378 }
379 }
380 }
381
382
383 // helper function for classical polylog Li
384 numeric Lin_numeric(int n, const numeric& x)
385 {
386 if (n == 1) {
387 // just a log
388 return -cln::log(1-x.to_cl_N());
389 }
390 if (x.is_zero()) {
391 return 0;
392 }
393 if (x == 1) {
394 // [Kol] (2.22)
395 return cln::zeta(n);
396 }
397 else if (x == -1) {
398 // [Kol] (2.22)
399 return -(1-cln::expt(cln::cl_I(2),1-n)) * cln::zeta(n);
400 }
401 if (abs(x.real()) < 0.4 && abs(abs(x)-1) < 0.01) {
402 cln::cl_N x_ = ex_to<numeric>(x).to_cl_N();
403 cln::cl_N result = -cln::expt(cln::log(x_), n-1) * cln::log(1-x_) / cln::factorial(n-1);
404 for (int j=0; j<n-1; j++) {
405 result = result + (S_num(n-j-1, 1, 1).to_cl_N() - S_num(1, n-j-1, 1-x_).to_cl_N())
406 * cln::expt(cln::log(x_), j) / cln::factorial(j);
407 }
408 return result;
409 }
410
411 // what is the desired float format?
412 // first guess: default format
413 cln::float_format_t prec = cln::default_float_format;
414 const cln::cl_N value = x.to_cl_N();
415 // second guess: the argument's format
416 if (!x.real().is_rational())
417 prec = cln::float_format(cln::the<cln::cl_F>(cln::realpart(value)));
418 else if (!x.imag().is_rational())
419 prec = cln::float_format(cln::the<cln::cl_F>(cln::imagpart(value)));
420
421 // [Kol] (5.15)
422 if (cln::abs(value) > 1) {
423 cln::cl_N result = -cln::expt(cln::log(-value),n) / cln::factorial(n);
424 // check if argument is complex. if it is real, the new polylog has to be conjugated.
425 if (cln::zerop(cln::imagpart(value))) {
426 if (n & 1) {
427 result = result + conjugate(Li_projection(n, cln::recip(value), prec));
428 }
429 else {
430 result = result - conjugate(Li_projection(n, cln::recip(value), prec));
431 }
432 }
433 else {
434 if (n & 1) {
435 result = result + Li_projection(n, cln::recip(value), prec);
436 }
437 else {
438 result = result - Li_projection(n, cln::recip(value), prec);
439 }
440 }
441 cln::cl_N add;
442 for (int j=0; j<n-1; j++) {
443 add = add + (1+cln::expt(cln::cl_I(-1),n-j)) * (1-cln::expt(cln::cl_I(2),1-n+j))
444 * Lin_numeric(n-j,1).to_cl_N() * cln::expt(cln::log(-value),j) / cln::factorial(j);
445 }
446 result = result - add;
447 return result;
448 }
449 else {
450 return Li_projection(n, value, prec);
451 }
452 }
453
454
455 } // end of anonymous namespace
456
457
458 //////////////////////////////////////////////////////////////////////
459 //
460 // Multiple polylogarithm Li(n,x)
461 //
462 // helper function
463 //
464 //////////////////////////////////////////////////////////////////////
465
466
467 // anonymous namespace for helper function
468 namespace {
469
470
471 // performs the actual series summation for multiple polylogarithms
472 cln::cl_N multipleLi_do_sum(const std::vector<int>& s, const std::vector<cln::cl_N>& x)
473 {
474 // ensure all x <> 0.
475 for (std::vector<cln::cl_N>::const_iterator it = x.begin(); it != x.end(); ++it) {
476 if ( *it == 0 ) return cln::cl_float(0, cln::float_format(Digits));
477 }
478
479 const int j = s.size();
480 bool flag_accidental_zero = false;
481
482 std::vector<cln::cl_N> t(j);
483 cln::cl_F one = cln::cl_float(1, cln::float_format(Digits));
484
485 cln::cl_N t0buf;
486 int q = 0;
487 do {
488 t0buf = t[0];
489 q++;
490 t[j-1] = t[j-1] + cln::expt(x[j-1], q) / cln::expt(cln::cl_I(q),s[j-1]) * one;
491 for (int k=j-2; k>=0; k--) {
492 flag_accidental_zero = cln::zerop(t[k+1]);
493 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]);
494 }
495 } while ( (t[0] != t0buf) || flag_accidental_zero );
496
497 return t[0];
498 }
499
500
501 // converts parameter types and calls multipleLi_do_sum (convenience function for G_numeric)
502 cln::cl_N mLi_do_summation(const lst& m, const lst& x)
503 {
504 std::vector<int> m_int;
505 std::vector<cln::cl_N> x_cln;
506 for (lst::const_iterator itm = m.begin(), itx = x.begin(); itm != m.end(); ++itm, ++itx) {
507 m_int.push_back(ex_to<numeric>(*itm).to_int());
508 x_cln.push_back(ex_to<numeric>(*itx).to_cl_N());
509 }
510 return multipleLi_do_sum(m_int, x_cln);
511 }
512
513
514 // forward declaration for Li_eval()
515 lst convert_parameter_Li_to_H(const lst& m, const lst& x, ex& pf);
516
517
518 // holding dummy-symbols for the G/Li transformations
519 std::vector<ex> gsyms;
520
521
522 // type used by the transformation functions for G
523 typedef std::vector<int> Gparameter;
524
525
526 // G_eval1-function for G transformations
527 ex G_eval1(int a, int scale)
528 {
529 if (a != 0) {
530 const ex& scs = gsyms[std::abs(scale)];
531 const ex& as = gsyms[std::abs(a)];
532 if (as != scs) {
533 return -log(1 - scs/as);
534 } else {
535 return -zeta(1);
536 }
537 } else {
538 return log(gsyms[std::abs(scale)]);
539 }
540 }
541
542
543 // G_eval-function for G transformations
544 ex G_eval(const Gparameter& a, int scale)
545 {
546 // check for properties of G
547 ex sc = gsyms[std::abs(scale)];
548 lst newa;
549 bool all_zero = true;
550 bool all_ones = true;
551 int count_ones = 0;
552 for (Gparameter::const_iterator it = a.begin(); it != a.end(); ++it) {
553 if (*it != 0) {
554 const ex sym = gsyms[std::abs(*it)];
555 newa.append(sym);
556 all_zero = false;
557 if (sym != sc) {
558 all_ones = false;
559 }
560 if (all_ones) {
561 ++count_ones;
562 }
563 } else {
564 all_ones = false;
565 }
566 }
567
568 // care about divergent G: shuffle to separate divergencies that will be canceled
569 // later on in the transformation
570 if (newa.nops() > 1 && newa.op(0) == sc && !all_ones && a.front()!=0) {
571 // do shuffle
572 Gparameter short_a;
573 Gparameter::const_iterator it = a.begin();
574 ++it;
575 for (; it != a.end(); ++it) {
576 short_a.push_back(*it);
577 }
578 ex result = G_eval1(a.front(), scale) * G_eval(short_a, scale);
579 it = short_a.begin();
580 for (int i=1; i<count_ones; ++i) {
581 ++it;
582 }
583 for (; it != short_a.end(); ++it) {
584
585 Gparameter newa;
586 Gparameter::const_iterator it2 = short_a.begin();
587 for (--it2; it2 != it;) {
588 ++it2;
589 newa.push_back(*it2);
590 }
591 newa.push_back(a[0]);
592 ++it2;
593 for (; it2 != short_a.end(); ++it2) {
594 newa.push_back(*it2);
595 }
596 result -= G_eval(newa, scale);
597 }
598 return result / count_ones;
599 }
600
601 // G({1,...,1};y) -> G({1};y)^k / k!
602 if (all_ones && a.size() > 1) {
603 return pow(G_eval1(a.front(),scale), count_ones) / factorial(count_ones);
604 }
605
606 // G({0,...,0};y) -> log(y)^k / k!
607 if (all_zero) {
608 return pow(log(gsyms[std::abs(scale)]), a.size()) / factorial(a.size());
609 }
610
611 // no special cases anymore -> convert it into Li
612 lst m;
613 lst x;
614 ex argbuf = gsyms[std::abs(scale)];
615 ex mval = _ex1;
616 for (Gparameter::const_iterator it=a.begin(); it!=a.end(); ++it) {
617 if (*it != 0) {
618 const ex& sym = gsyms[std::abs(*it)];
619 x.append(argbuf / sym);
620 m.append(mval);
621 mval = _ex1;
622 argbuf = sym;
623 } else {
624 ++mval;
625 }
626 }
627 return pow(-1, x.nops()) * Li(m, x);
628 }
629
630
631 // converts data for G: pending_integrals -> a
632 Gparameter convert_pending_integrals_G(const Gparameter& pending_integrals)
633 {
634 GINAC_ASSERT(pending_integrals.size() != 1);
635
636 if (pending_integrals.size() > 0) {
637 // get rid of the first element, which would stand for the new upper limit
638 Gparameter new_a(pending_integrals.begin()+1, pending_integrals.end());
639 return new_a;
640 } else {
641 // just return empty parameter list
642 Gparameter new_a;
643 return new_a;
644 }
645 }
646
647
648 // check the parameters a and scale for G and return information about convergence, depth, etc.
649 // convergent : true if G(a,scale) is convergent
650 // depth : depth of G(a,scale)
651 // trailing_zeros : number of trailing zeros of a
652 // min_it : iterator of a pointing on the smallest element in a
653 Gparameter::const_iterator check_parameter_G(const Gparameter& a, int scale,
654 bool& convergent, int& depth, int& trailing_zeros, Gparameter::const_iterator& min_it)
655 {
656 convergent = true;
657 depth = 0;
658 trailing_zeros = 0;
659 min_it = a.end();
660 Gparameter::const_iterator lastnonzero = a.end();
661 for (Gparameter::const_iterator it = a.begin(); it != a.end(); ++it) {
662 if (std::abs(*it) > 0) {
663 ++depth;
664 trailing_zeros = 0;
665 lastnonzero = it;
666 if (std::abs(*it) < scale) {
667 convergent = false;
668 if ((min_it == a.end()) || (std::abs(*it) < std::abs(*min_it))) {
669 min_it = it;
670 }
671 }
672 } else {
673 ++trailing_zeros;
674 }
675 }
676 return ++lastnonzero;
677 }
678
679
680 // add scale to pending_integrals if pending_integrals is empty
681 Gparameter prepare_pending_integrals(const Gparameter& pending_integrals, int scale)
682 {
683 GINAC_ASSERT(pending_integrals.size() != 1);
684
685 if (pending_integrals.size() > 0) {
686 return pending_integrals;
687 } else {
688 Gparameter new_pending_integrals;
689 new_pending_integrals.push_back(scale);
690 return new_pending_integrals;
691 }
692 }
693
694
695 // handles trailing zeroes for an otherwise convergent integral
696 ex trailing_zeros_G(const Gparameter& a, int scale)
697 {
698 bool convergent;
699 int depth, trailing_zeros;
700 Gparameter::const_iterator last, dummyit;
701 last = check_parameter_G(a, scale, convergent, depth, trailing_zeros, dummyit);
702
703 GINAC_ASSERT(convergent);
704
705 if ((trailing_zeros > 0) && (depth > 0)) {
706 ex result;
707 Gparameter new_a(a.begin(), a.end()-1);
708 result += G_eval1(0, scale) * trailing_zeros_G(new_a, scale);
709 for (Gparameter::const_iterator it = a.begin(); it != last; ++it) {
710 Gparameter new_a(a.begin(), it);
711 new_a.push_back(0);
712 new_a.insert(new_a.end(), it, a.end()-1);
713 result -= trailing_zeros_G(new_a, scale);
714 }
715
716 return result / trailing_zeros;
717 } else {
718 return G_eval(a, scale);
719 }
720 }
721
722
723 // G transformation [VSW] (57),(58)
724 ex depth_one_trafo_G(const Gparameter& pending_integrals, const Gparameter& a, int scale)
725 {
726 // pendint = ( y1, b1, ..., br )
727 // a = ( 0, ..., 0, amin )
728 // scale = y2
729 //
730 // int_0^y1 ds1/(s1-b1) ... int dsr/(sr-br) G(0, ..., 0, sr; y2)
731 // where sr replaces amin
732
733 GINAC_ASSERT(a.back() != 0);
734 GINAC_ASSERT(a.size() > 0);
735
736 ex result;
737 Gparameter new_pending_integrals = prepare_pending_integrals(pending_integrals, std::abs(a.back()));
738 const int psize = pending_integrals.size();
739
740 // length == 1
741 // G(sr_{+-}; y2 ) = G(y2_{-+}; sr) - G(0; sr) + ln(-y2_{-+})
742
743 if (a.size() == 1) {
744
745 // ln(-y2_{-+})
746 result += log(gsyms[ex_to<numeric>(scale).to_int()]);
747 if (a.back() > 0) {
748 new_pending_integrals.push_back(-scale);
749 result += I*Pi;
750 } else {
751 new_pending_integrals.push_back(scale);
752 result -= I*Pi;
753 }
754 if (psize) {
755 result *= trailing_zeros_G(convert_pending_integrals_G(pending_integrals), pending_integrals.front());
756 }
757
758 // G(y2_{-+}; sr)
759 result += trailing_zeros_G(convert_pending_integrals_G(new_pending_integrals), new_pending_integrals.front());
760
761 // G(0; sr)
762 new_pending_integrals.back() = 0;
763 result -= trailing_zeros_G(convert_pending_integrals_G(new_pending_integrals), new_pending_integrals.front());
764
765 return result;
766 }
767
768 // length > 1
769 // G_m(sr_{+-}; y2) = -zeta_m + int_0^y2 dt/t G_{m-1}( (1/y2)_{+-}; 1/t )
770 // - int_0^sr dt/t G_{m-1}( (1/y2)_{+-}; 1/t )
771
772 //term zeta_m
773 result -= zeta(a.size());
774 if (psize) {
775 result *= trailing_zeros_G(convert_pending_integrals_G(pending_integrals), pending_integrals.front());
776 }
777
778 // term int_0^sr dt/t G_{m-1}( (1/y2)_{+-}; 1/t )
779 // = int_0^sr dt/t G_{m-1}( t_{+-}; y2 )
780 Gparameter new_a(a.begin()+1, a.end());
781 new_pending_integrals.push_back(0);
782 result -= depth_one_trafo_G(new_pending_integrals, new_a, scale);
783
784 // term int_0^y2 dt/t G_{m-1}( (1/y2)_{+-}; 1/t )
785 // = int_0^y2 dt/t G_{m-1}( t_{+-}; y2 )
786 Gparameter new_pending_integrals_2;
787 new_pending_integrals_2.push_back(scale);
788 new_pending_integrals_2.push_back(0);
789 if (psize) {
790 result += trailing_zeros_G(convert_pending_integrals_G(pending_integrals), pending_integrals.front())
791 * depth_one_trafo_G(new_pending_integrals_2, new_a, scale);
792 } else {
793 result += depth_one_trafo_G(new_pending_integrals_2, new_a, scale);
794 }
795
796 return result;
797 }
798
799
800 // forward declaration
801 ex shuffle_G(const Gparameter & a0, const Gparameter & a1, const Gparameter & a2,
802 const Gparameter& pendint, const Gparameter& a_old, int scale);
803
804
805 // G transformation [VSW]
806 ex G_transform(const Gparameter& pendint, const Gparameter& a, int scale)
807 {
808 // main recursion routine
809 //
810 // pendint = ( y1, b1, ..., br )
811 // a = ( a1, ..., amin, ..., aw )
812 // scale = y2
813 //
814 // int_0^y1 ds1/(s1-b1) ... int dsr/(sr-br) G(a1,...,sr,...,aw,y2)
815 // where sr replaces amin
816
817 // find smallest alpha, determine depth and trailing zeros, and check for convergence
818 bool convergent;
819 int depth, trailing_zeros;
820 Gparameter::const_iterator min_it;
821 Gparameter::const_iterator firstzero =
822 check_parameter_G(a, scale, convergent, depth, trailing_zeros, min_it);
823 int min_it_pos = min_it - a.begin();
824
825 // special case: all a's are zero
826 if (depth == 0) {
827 ex result;
828
829 if (a.size() == 0) {
830 result = 1;
831 } else {
832 result = G_eval(a, scale);
833 }
834 if (pendint.size() > 0) {
835 result *= trailing_zeros_G(convert_pending_integrals_G(pendint), pendint.front());
836 }
837 return result;
838 }
839
840 // handle trailing zeros
841 if (trailing_zeros > 0) {
842 ex result;
843 Gparameter new_a(a.begin(), a.end()-1);
844 result += G_eval1(0, scale) * G_transform(pendint, new_a, scale);
845 for (Gparameter::const_iterator it = a.begin(); it != firstzero; ++it) {
846 Gparameter new_a(a.begin(), it);
847 new_a.push_back(0);
848 new_a.insert(new_a.end(), it, a.end()-1);
849 result -= G_transform(pendint, new_a, scale);
850 }
851 return result / trailing_zeros;
852 }
853
854 // convergence case
855 if (convergent) {
856 if (pendint.size() > 0) {
857 return G_eval(convert_pending_integrals_G(pendint), pendint.front()) * G_eval(a, scale);
858 } else {
859 return G_eval(a, scale);
860 }
861 }
862
863 // call basic transformation for depth equal one
864 if (depth == 1) {
865 return depth_one_trafo_G(pendint, a, scale);
866 }
867
868 // do recursion
869 // int_0^y1 ds1/(s1-b1) ... int dsr/(sr-br) G(a1,...,sr,...,aw,y2)
870 // = int_0^y1 ds1/(s1-b1) ... int dsr/(sr-br) G(a1,...,0,...,aw,y2)
871 // + 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)
872
873 // smallest element in last place
874 if (min_it + 1 == a.end()) {
875 do { --min_it; } while (*min_it == 0);
876 Gparameter empty;
877 Gparameter a1(a.begin(),min_it+1);
878 Gparameter a2(min_it+1,a.end());
879
880 ex result = G_transform(pendint,a2,scale)*G_transform(empty,a1,scale);
881
882 result -= shuffle_G(empty,a1,a2,pendint,a,scale);
883 return result;
884 }
885
886 Gparameter empty;
887 Gparameter::iterator changeit;
888
889 // first term G(a_1,..,0,...,a_w;a_0)
890 Gparameter new_pendint = prepare_pending_integrals(pendint, a[min_it_pos]);
891 Gparameter new_a = a;
892 new_a[min_it_pos] = 0;
893 ex result = G_transform(empty, new_a, scale);
894 if (pendint.size() > 0) {
895 result *= trailing_zeros_G(convert_pending_integrals_G(pendint), pendint.front());
896 }
897
898 // other terms
899 changeit = new_a.begin() + min_it_pos;
900 changeit = new_a.erase(changeit);
901 if (changeit != new_a.begin()) {
902 // smallest in the middle
903 new_pendint.push_back(*changeit);
904 result -= trailing_zeros_G(convert_pending_integrals_G(new_pendint), new_pendint.front())
905 * G_transform(empty, new_a, scale);
906 int buffer = *changeit;
907 *changeit = *min_it;
908 result += G_transform(new_pendint, new_a, scale);
909 *changeit = buffer;
910 new_pendint.pop_back();
911 --changeit;
912 new_pendint.push_back(*changeit);
913 result += trailing_zeros_G(convert_pending_integrals_G(new_pendint), new_pendint.front())
914 * G_transform(empty, new_a, scale);
915 *changeit = *min_it;
916 result -= G_transform(new_pendint, new_a, scale);
917 } else {
918 // smallest at the front
919 new_pendint.push_back(scale);
920 result += trailing_zeros_G(convert_pending_integrals_G(new_pendint), new_pendint.front())
921 * G_transform(empty, new_a, scale);
922 new_pendint.back() = *changeit;
923 result -= trailing_zeros_G(convert_pending_integrals_G(new_pendint), new_pendint.front())
924 * G_transform(empty, new_a, scale);
925 *changeit = *min_it;
926 result += G_transform(new_pendint, new_a, scale);
927 }
928 return result;
929 }
930
931
932 // shuffles the two parameter list a1 and a2 and calls G_transform for every term except
933 // for the one that is equal to a_old
934 ex shuffle_G(const Gparameter & a0, const Gparameter & a1, const Gparameter & a2,
935 const Gparameter& pendint, const Gparameter& a_old, int scale)
936 {
937 if (a1.size()==0 && a2.size()==0) {
938 // veto the one configuration we don't want
939 if ( a0 == a_old ) return 0;
940
941 return G_transform(pendint,a0,scale);
942 }
943
944 if (a2.size()==0) {
945 Gparameter empty;
946 Gparameter aa0 = a0;
947 aa0.insert(aa0.end(),a1.begin(),a1.end());
948 return shuffle_G(aa0,empty,empty,pendint,a_old,scale);
949 }
950
951 if (a1.size()==0) {
952 Gparameter empty;
953 Gparameter aa0 = a0;
954 aa0.insert(aa0.end(),a2.begin(),a2.end());
955 return shuffle_G(aa0,empty,empty,pendint,a_old,scale);
956 }
957
958 Gparameter a1_removed(a1.begin()+1,a1.end());
959 Gparameter a2_removed(a2.begin()+1,a2.end());
960
961 Gparameter a01 = a0;
962 Gparameter a02 = a0;
963
964 a01.push_back( a1[0] );
965 a02.push_back( a2[0] );
966
967 return shuffle_G(a01,a1_removed,a2,pendint,a_old,scale)
968 + shuffle_G(a02,a1,a2_removed,pendint,a_old,scale);
969 }
970
971
972 // handles the transformations and the numerical evaluation of G
973 // the parameter x, s and y must only contain numerics
974 ex G_numeric(const lst& x, const lst& s, const ex& y)
975 {
976 // check for convergence and necessary accelerations
977 bool need_trafo = false;
978 bool need_hoelder = false;
979 int depth = 0;
980 for (lst::const_iterator it = x.begin(); it != x.end(); ++it) {
981 if (!(*it).is_zero()) {
982 ++depth;
983 if (abs(*it) - y < -pow(10,-Digits+1)) {
984 need_trafo = true;
985 }
986 if (abs((abs(*it) - y)/y) < 0.01) {
987 need_hoelder = true;
988 }
989 }
990 }
991 if (x.op(x.nops()-1).is_zero()) {
992 need_trafo = true;
993 }
994 if (depth == 1 && !need_trafo) {
995 return -Li(x.nops(), y / x.op(x.nops()-1)).evalf();
996 }
997
998 // do acceleration transformation (hoelder convolution [BBB])
999 if (need_hoelder) {
1000
1001 ex result;
1002 const int size = x.nops();
1003 lst newx;
1004 for (lst::const_iterator it = x.begin(); it != x.end(); ++it) {
1005 newx.append(*it / y);
1006 }
1007
1008 for (int r=0; r<=size; ++r) {
1009 ex buffer = pow(-1, r);
1010 ex p = 2;
1011 bool adjustp;
1012 do {
1013 adjustp = false;
1014 for (lst::const_iterator it = newx.begin(); it != newx.end(); ++it) {
1015 if (*it == 1/p) {
1016 p += (3-p)/2;
1017 adjustp = true;
1018 continue;
1019 }
1020 }
1021 } while (adjustp);
1022 ex q = p / (p-1);
1023 lst qlstx;
1024 lst qlsts;
1025 for (int j=r; j>=1; --j) {
1026 qlstx.append(1-newx.op(j-1));
1027 if (newx.op(j-1).info(info_flags::real) && newx.op(j-1) > 1 && newx.op(j-1) <= 2) {
1028 qlsts.append( s.op(j-1));
1029 } else {
1030 qlsts.append( -s.op(j-1));
1031 }
1032 }
1033 if (qlstx.nops() > 0) {
1034 buffer *= G_numeric(qlstx, qlsts, 1/q);
1035 }
1036 lst plstx;
1037 lst plsts;
1038 for (int j=r+1; j<=size; ++j) {
1039 plstx.append(newx.op(j-1));
1040 plsts.append(s.op(j-1));
1041 }
1042 if (plstx.nops() > 0) {
1043 buffer *= G_numeric(plstx, plsts, 1/p);
1044 }
1045 result += buffer;
1046 }
1047 return result;
1048 }
1049
1050 // convergence transformation
1051 if (need_trafo) {
1052
1053 // sort (|x|<->position) to determine indices
1054 std::multimap<ex,int> sortmap;
1055 int size = 0;
1056 for (int i=0; i<x.nops(); ++i) {
1057 if (!x[i].is_zero()) {
1058 sortmap.insert(std::pair<ex,int>(abs(x[i]), i));
1059 ++size;
1060 }
1061 }
1062 // include upper limit (scale)
1063 sortmap.insert(std::pair<ex,int>(abs(y), x.nops()));
1064
1065 // generate missing dummy-symbols
1066 int i = 1;
1067 gsyms.clear();
1068 gsyms.push_back(symbol("GSYMS_ERROR"));
1069 ex lastentry;
1070 for (std::multimap<ex,int>::const_iterator it = sortmap.begin(); it != sortmap.end(); ++it) {
1071 if (it != sortmap.begin()) {
1072 if (it->second < x.nops()) {
1073 if (x[it->second] == lastentry) {
1074 gsyms.push_back(gsyms.back());
1075 continue;
1076 }
1077 } else {
1078 if (y == lastentry) {
1079 gsyms.push_back(gsyms.back());
1080 continue;
1081 }
1082 }
1083 }
1084 std::ostringstream os;
1085 os << "a" << i;
1086 gsyms.push_back(symbol(os.str()));
1087 ++i;
1088 if (it->second < x.nops()) {
1089 lastentry = x[it->second];
1090 } else {
1091 lastentry = y;
1092 }
1093 }
1094
1095 // fill position data according to sorted indices and prepare substitution list
1096 Gparameter a(x.nops());
1097 lst subslst;
1098 int pos = 1;
1099 int scale;
1100 for (std::multimap<ex,int>::const_iterator it = sortmap.begin(); it != sortmap.end(); ++it) {
1101 if (it->second < x.nops()) {
1102 if (s[it->second] > 0) {
1103 a[it->second] = pos;
1104 } else {
1105 a[it->second] = -pos;
1106 }
1107 subslst.append(gsyms[pos] == x[it->second]);
1108 } else {
1109 scale = pos;
1110 subslst.append(gsyms[pos] == y);
1111 }
1112 ++pos;
1113 }
1114
1115 // do transformation
1116 Gparameter pendint;
1117 ex result = G_transform(pendint, a, scale);
1118 // replace dummy symbols with their values
1119 result = result.eval().expand();
1120 result = result.subs(subslst).evalf();
1121
1122 return result;
1123 }
1124
1125 // do summation
1126 lst newx;
1127 lst m;
1128 int mcount = 1;
1129 ex sign = 1;
1130 ex factor = y;
1131 for (lst::const_iterator it = x.begin(); it != x.end(); ++it) {
1132 if ((*it).is_zero()) {
1133 ++mcount;
1134 } else {
1135 newx.append(factor / (*it));
1136 factor = *it;
1137 m.append(mcount);
1138 mcount = 1;
1139 sign = -sign;
1140 }
1141 }
1142
1143 return sign * numeric(mLi_do_summation(m, newx));
1144 }
1145
1146
1147 ex mLi_numeric(const lst& m, const lst& x)
1148 {
1149 // let G_numeric do the transformation
1150 lst newx;
1151 lst s;
1152 ex factor = 1;
1153 for (lst::const_iterator itm = m.begin(), itx = x.begin(); itm != m.end(); ++itm, ++itx) {
1154 for (int i = 1; i < *itm; ++i) {
1155 newx.append(0);
1156 s.append(1);
1157 }
1158 newx.append(factor / *itx);
1159 factor /= *itx;
1160 s.append(1);
1161 }
1162 return pow(-1, m.nops()) * G_numeric(newx, s, _ex1);
1163 }
1164
1165
1166 } // end of anonymous namespace
1167
1168
1169 //////////////////////////////////////////////////////////////////////
1170 //
1171 // Generalized multiple polylogarithm G(x, y) and G(x, s, y)
1172 //
1173 // GiNaC function
1174 //
1175 //////////////////////////////////////////////////////////////////////
1176
1177
1178 static ex G2_evalf(const ex& x_, const ex& y)
1179 {
1180 if (!y.info(info_flags::positive)) {
1181 return G(x_, y).hold();
1182 }
1183 lst x = is_a<lst>(x_) ? ex_to<lst>(x_) : lst(x_);
1184 if (x.nops() == 0) {
1185 return _ex1;
1186 }
1187 if (x.op(0) == y) {
1188 return G(x_, y).hold();
1189 }
1190 lst s;
1191 bool all_zero = true;
1192 for (lst::const_iterator it = x.begin(); it != x.end(); ++it) {
1193 if (!(*it).info(info_flags::numeric)) {
1194 return G(x_, y).hold();
1195 }
1196 if (*it != _ex0) {
1197 all_zero = false;
1198 }
1199 s.append(+1);
1200 }
1201 if (all_zero) {
1202 return pow(log(y), x.nops()) / factorial(x.nops());
1203 }
1204 return G_numeric(x, s, y);
1205 }
1206
1207
1208 static ex G2_eval(const ex& x_, const ex& y)
1209 {
1210 //TODO eval to MZV or H or S or Lin
1211
1212 if (!y.info(info_flags::positive)) {
1213 return G(x_, y).hold();
1214 }
1215 lst x = is_a<lst>(x_) ? ex_to<lst>(x_) : lst(x_);
1216 if (x.nops() == 0) {
1217 return _ex1;
1218 }
1219 if (x.op(0) == y) {
1220 return G(x_, y).hold();
1221 }
1222 lst s;
1223 bool all_zero = true;
1224 bool crational = true;
1225 for (lst::const_iterator it = x.begin(); it != x.end(); ++it) {
1226 if (!(*it).info(info_flags::numeric)) {
1227 return G(x_, y).hold();
1228 }
1229 if (!(*it).info(info_flags::crational)) {
1230 crational = false;
1231 }
1232 if (*it != _ex0) {
1233 all_zero = false;
1234 }
1235 s.append(+1);
1236 }
1237 if (all_zero) {
1238 return pow(log(y), x.nops()) / factorial(x.nops());
1239 }
1240 if (!y.info(info_flags::crational)) {
1241 crational = false;
1242 }
1243 if (crational) {
1244 return G(x_, y).hold();
1245 }
1246 return G_numeric(x, s, y);
1247 }
1248
1249
1250 unsigned G2_SERIAL::serial = function::register_new(function_options("G", 2).
1251 evalf_func(G2_evalf).
1252 eval_func(G2_eval).
1253 do_not_evalf_params().
1254 overloaded(2));
1255 //TODO
1256 // derivative_func(G2_deriv).
1257 // print_func<print_latex>(G2_print_latex).
1258
1259
1260 static ex G3_evalf(const ex& x_, const ex& s_, const ex& y)
1261 {
1262 if (!y.info(info_flags::positive)) {
1263 return G(x_, s_, y).hold();
1264 }
1265 lst x = is_a<lst>(x_) ? ex_to<lst>(x_) : lst(x_);
1266 lst s = is_a<lst>(s_) ? ex_to<lst>(s_) : lst(s_);
1267 if (x.nops() != s.nops()) {
1268 return G(x_, s_, y).hold();
1269 }
1270 if (x.nops() == 0) {
1271 return _ex1;
1272 }
1273 if (x.op(0) == y) {
1274 return G(x_, s_, y).hold();
1275 }
1276 lst sn;
1277 bool all_zero = true;
1278 for (lst::const_iterator itx = x.begin(), its = s.begin(); itx != x.end(); ++itx, ++its) {
1279 if (!(*itx).info(info_flags::numeric)) {
1280 return G(x_, y).hold();
1281 }
1282 if (!(*its).info(info_flags::real)) {
1283 return G(x_, y).hold();
1284 }
1285 if (*itx != _ex0) {
1286 all_zero = false;
1287 }
1288 if (*its >= 0) {
1289 sn.append(+1);
1290 } else {
1291 sn.append(-1);
1292 }
1293 }
1294 if (all_zero) {
1295 return pow(log(y), x.nops()) / factorial(x.nops());
1296 }
1297 return G_numeric(x, sn, y);
1298 }
1299
1300
1301 static ex G3_eval(const ex& x_, const ex& s_, const ex& y)
1302 {
1303 //TODO eval to MZV or H or S or Lin
1304
1305 if (!y.info(info_flags::positive)) {
1306 return G(x_, s_, y).hold();
1307 }
1308 lst x = is_a<lst>(x_) ? ex_to<lst>(x_) : lst(x_);
1309 lst s = is_a<lst>(s_) ? ex_to<lst>(s_) : lst(s_);
1310 if (x.nops() != s.nops()) {
1311 return G(x_, s_, y).hold();
1312 }
1313 if (x.nops() == 0) {
1314 return _ex1;
1315 }
1316 if (x.op(0) == y) {
1317 return G(x_, s_, y).hold();
1318 }
1319 lst sn;
1320 bool all_zero = true;
1321 bool crational = true;
1322 for (lst::const_iterator itx = x.begin(), its = s.begin(); itx != x.end(); ++itx, ++its) {
1323 if (!(*itx).info(info_flags::numeric)) {
1324 return G(x_, s_, y).hold();
1325 }
1326 if (!(*its).info(info_flags::real)) {
1327 return G(x_, s_, y).hold();
1328 }
1329 if (!(*itx).info(info_flags::crational)) {
1330 crational = false;
1331 }
1332 if (*itx != _ex0) {
1333 all_zero = false;
1334 }
1335 if (*its >= 0) {
1336 sn.append(+1);
1337 } else {
1338 sn.append(-1);
1339 }
1340 }
1341 if (all_zero) {
1342 return pow(log(y), x.nops()) / factorial(x.nops());
1343 }
1344 if (!y.info(info_flags::crational)) {
1345 crational = false;
1346 }
1347 if (crational) {
1348 return G(x_, s_, y).hold();
1349 }
1350 return G_numeric(x, sn, y);
1351 }
1352
1353
1354 unsigned G3_SERIAL::serial = function::register_new(function_options("G", 3).
1355 evalf_func(G3_evalf).
1356 eval_func(G3_eval).
1357 do_not_evalf_params().
1358 overloaded(2));
1359 //TODO
1360 // derivative_func(G3_deriv).
1361 // print_func<print_latex>(G3_print_latex).
1362
1363
1364 //////////////////////////////////////////////////////////////////////
1365 //
1366 // Classical polylogarithm and multiple polylogarithm Li(m,x)
1367 //
1368 // GiNaC function
1369 //
1370 //////////////////////////////////////////////////////////////////////
1371
1372
1373 static ex Li_evalf(const ex& m_, const ex& x_)
1374 {
1375 // classical polylogs
1376 if (m_.info(info_flags::posint)) {
1377 if (x_.info(info_flags::numeric)) {
1378 return Lin_numeric(ex_to<numeric>(m_).to_int(), ex_to<numeric>(x_));
1379 } else {
1380 // try to numerically evaluate second argument
1381 ex x_val = x_.evalf();
1382 if (x_val.info(info_flags::numeric)) {
1383 return Lin_numeric(ex_to<numeric>(m_).to_int(), ex_to<numeric>(x_val));
1384 }
1385 }
1386 }
1387 // multiple polylogs
1388 if (is_a<lst>(m_) && is_a<lst>(x_)) {
1389
1390 const lst& m = ex_to<lst>(m_);
1391 const lst& x = ex_to<lst>(x_);
1392 if (m.nops() != x.nops()) {
1393 return Li(m_,x_).hold();
1394 }
1395 if (x.nops() == 0) {
1396 return _ex1;
1397 }
1398 if ((m.op(0) == _ex1) && (x.op(0) == _ex1)) {
1399 return Li(m_,x_).hold();
1400 }
1401
1402 for (lst::const_iterator itm = m.begin(), itx = x.begin(); itm != m.end(); ++itm, ++itx) {
1403 if (!(*itm).info(info_flags::posint)) {
1404 return Li(m_, x_).hold();
1405 }
1406 if (!(*itx).info(info_flags::numeric)) {
1407 return Li(m_, x_).hold();
1408 }
1409 if (*itx == _ex0) {
1410 return _ex0;
1411 }
1412 }
1413
1414 return mLi_numeric(m, x);
1415 }
1416
1417 return Li(m_,x_).hold();
1418 }
1419
1420
1421 static ex Li_eval(const ex& m_, const ex& x_)
1422 {
1423 if (is_a<lst>(m_)) {
1424 if (is_a<lst>(x_)) {
1425 // multiple polylogs
1426 const lst& m = ex_to<lst>(m_);
1427 const lst& x = ex_to<lst>(x_);
1428 if (m.nops() != x.nops()) {
1429 return Li(m_,x_).hold();
1430 }
1431 if (x.nops() == 0) {
1432 return _ex1;
1433 }
1434 bool is_H = true;
1435 bool is_zeta = true;
1436 bool do_evalf = true;
1437 bool crational = true;
1438 for (lst::const_iterator itm = m.begin(), itx = x.begin(); itm != m.end(); ++itm, ++itx) {
1439 if (!(*itm).info(info_flags::posint)) {
1440 return Li(m_,x_).hold();
1441 }
1442 if ((*itx != _ex1) && (*itx != _ex_1)) {
1443 if (itx != x.begin()) {
1444 is_H = false;
1445 }
1446 is_zeta = false;
1447 }
1448 if (*itx == _ex0) {
1449 return _ex0;
1450 }
1451 if (!(*itx).info(info_flags::numeric)) {
1452 do_evalf = false;
1453 }
1454 if (!(*itx).info(info_flags::crational)) {
1455 crational = false;
1456 }
1457 }
1458 if (is_zeta) {
1459 return zeta(m_,x_);
1460 }
1461 if (is_H) {
1462 ex prefactor;
1463 lst newm = convert_parameter_Li_to_H(m, x, prefactor);
1464 return prefactor * H(newm, x[0]);
1465 }
1466 if (do_evalf && !crational) {
1467 return mLi_numeric(m,x);
1468 }
1469 }
1470 return Li(m_, x_).hold();
1471 } else if (is_a<lst>(x_)) {
1472 return Li(m_, x_).hold();
1473 }
1474
1475 // classical polylogs
1476 if (x_ == _ex0) {
1477 return _ex0;
1478 }
1479 if (x_ == _ex1) {
1480 return zeta(m_);
1481 }
1482 if (x_ == _ex_1) {
1483 return (pow(2,1-m_)-1) * zeta(m_);
1484 }
1485 if (m_ == _ex1) {
1486 return -log(1-x_);
1487 }
1488 if (m_ == _ex2) {
1489 if (x_.is_equal(I)) {
1490 return power(Pi,_ex2)/_ex_48 + Catalan*I;
1491 }
1492 if (x_.is_equal(-I)) {
1493 return power(Pi,_ex2)/_ex_48 - Catalan*I;
1494 }
1495 }
1496 if (m_.info(info_flags::posint) && x_.info(info_flags::numeric) && !x_.info(info_flags::crational)) {
1497 return Lin_numeric(ex_to<numeric>(m_).to_int(), ex_to<numeric>(x_));
1498 }
1499
1500 return Li(m_, x_).hold();
1501 }
1502
1503
1504 static ex Li_series(const ex& m, const ex& x, const relational& rel, int order, unsigned options)
1505 {
1506 if (is_a<lst>(m) || is_a<lst>(x)) {
1507 // multiple polylog
1508 epvector seq;
1509 seq.push_back(expair(Li(m, x), 0));
1510 return pseries(rel, seq);
1511 }
1512
1513 // classical polylog
1514 const ex x_pt = x.subs(rel, subs_options::no_pattern);
1515 if (m.info(info_flags::numeric) && x_pt.info(info_flags::numeric)) {
1516 // First special case: x==0 (derivatives have poles)
1517 if (x_pt.is_zero()) {
1518 const symbol s;
1519 ex ser;
1520 // manually construct the primitive expansion
1521 for (int i=1; i<order; ++i)
1522 ser += pow(s,i) / pow(numeric(i), m);
1523 // substitute the argument's series expansion
1524 ser = ser.subs(s==x.series(rel, order), subs_options::no_pattern);
1525 // maybe that was terminating, so add a proper order term
1526 epvector nseq;
1527 nseq.push_back(expair(Order(_ex1), order));
1528 ser += pseries(rel, nseq);
1529 // reexpanding it will collapse the series again
1530 return ser.series(rel, order);
1531 }
1532 // TODO special cases: x==1 (branch point) and x real, >=1 (branch cut)
1533 throw std::runtime_error("Li_series: don't know how to do the series expansion at this point!");
1534 }
1535 // all other cases should be safe, by now:
1536 throw do_taylor(); // caught by function::series()
1537 }
1538
1539
1540 static ex Li_deriv(const ex& m_, const ex& x_, unsigned deriv_param)
1541 {
1542 GINAC_ASSERT(deriv_param < 2);
1543 if (deriv_param == 0) {
1544 return _ex0;
1545 }
1546 if (m_.nops() > 1) {
1547 throw std::runtime_error("don't know how to derivate multiple polylogarithm!");
1548 }
1549 ex m;
1550 if (is_a<lst>(m_)) {
1551 m = m_.op(0);
1552 } else {
1553 m = m_;
1554 }
1555 ex x;
1556 if (is_a<lst>(x_)) {
1557 x = x_.op(0);
1558 } else {
1559 x = x_;
1560 }
1561 if (m > 0) {
1562 return Li(m-1, x) / x;
1563 } else {
1564 return 1/(1-x);
1565 }
1566 }
1567
1568
1569 static void Li_print_latex(const ex& m_, const ex& x_, const print_context& c)
1570 {
1571 lst m;
1572 if (is_a<lst>(m_)) {
1573 m = ex_to<lst>(m_);
1574 } else {
1575 m = lst(m_);
1576 }
1577 lst x;
1578 if (is_a<lst>(x_)) {
1579 x = ex_to<lst>(x_);
1580 } else {
1581 x = lst(x_);
1582 }
1583 c.s << "\\mbox{Li}_{";
1584 lst::const_iterator itm = m.begin();
1585 (*itm).print(c);
1586 itm++;
1587 for (; itm != m.end(); itm++) {
1588 c.s << ",";
1589 (*itm).print(c);
1590 }
1591 c.s << "}(";
1592 lst::const_iterator itx = x.begin();
1593 (*itx).print(c);
1594 itx++;
1595 for (; itx != x.end(); itx++) {
1596 c.s << ",";
1597 (*itx).print(c);
1598 }
1599 c.s << ")";
1600 }
1601
1602
1603 REGISTER_FUNCTION(Li,
1604 evalf_func(Li_evalf).
1605 eval_func(Li_eval).
1606 series_func(Li_series).
1607 derivative_func(Li_deriv).
1608 print_func<print_latex>(Li_print_latex).
1609 do_not_evalf_params());
1610
1611
1612 //////////////////////////////////////////////////////////////////////
1613 //
1614 // Nielsen's generalized polylogarithm S(n,p,x)
1615 //
1616 // helper functions
1617 //
1618 //////////////////////////////////////////////////////////////////////
1619
1620
1621 // anonymous namespace for helper functions
1622 namespace {
1623
1624
1625 // lookup table for special Euler-Zagier-Sums (used for S_n,p(x))
1626 // see fill_Yn()
1627 std::vector<std::vector<cln::cl_N> > Yn;
1628 int ynsize = 0; // number of Yn[]
1629 int ynlength = 100; // initial length of all Yn[i]
1630
1631
1632 // This function calculates the Y_n. The Y_n are needed for the evaluation of S_{n,p}(x).
1633 // The Y_n are basically Euler-Zagier sums with all m_i=1. They are subsums in the Z-sum
1634 // representing S_{n,p}(x).
1635 // The first index in Y_n corresponds to the parameter p minus one, i.e. the depth of the
1636 // equivalent Z-sum.
1637 // The second index in Y_n corresponds to the running index of the outermost sum in the full Z-sum
1638 // representing S_{n,p}(x).
1639 // The calculation of Y_n uses the values from Y_{n-1}.
1640 void fill_Yn(int n, const cln::float_format_t& prec)
1641 {
1642 const int initsize = ynlength;
1643 //const int initsize = initsize_Yn;
1644 cln::cl_N one = cln::cl_float(1, prec);
1645
1646 if (n) {
1647 std::vector<cln::cl_N> buf(initsize);
1648 std::vector<cln::cl_N>::iterator it = buf.begin();
1649 std::vector<cln::cl_N>::iterator itprev = Yn[n-1].begin();
1650 *it = (*itprev) / cln::cl_N(n+1) * one;
1651 it++;
1652 itprev++;
1653 // sums with an index smaller than the depth are zero and need not to be calculated.
1654 // calculation starts with depth, which is n+2)
1655 for (int i=n+2; i<=initsize+n; i++) {
1656 *it = *(it-1) + (*itprev) / cln::cl_N(i) * one;
1657 it++;
1658 itprev++;
1659 }
1660 Yn.push_back(buf);
1661 } else {
1662 std::vector<cln::cl_N> buf(initsize);
1663 std::vector<cln::cl_N>::iterator it = buf.begin();
1664 *it = 1 * one;
1665 it++;
1666 for (int i=2; i<=initsize; i++) {
1667 *it = *(it-1) + 1 / cln::cl_N(i) * one;
1668 it++;
1669 }
1670 Yn.push_back(buf);
1671 }
1672 ynsize++;
1673 }
1674
1675
1676 // make Yn longer ...
1677 void make_Yn_longer(int newsize, const cln::float_format_t& prec)
1678 {
1679
1680 cln::cl_N one = cln::cl_float(1, prec);
1681
1682 Yn[0].resize(newsize);
1683 std::vector<cln::cl_N>::iterator it = Yn[0].begin();
1684 it += ynlength;
1685 for (int i=ynlength+1; i<=newsize; i++) {
1686 *it = *(it-1) + 1 / cln::cl_N(i) * one;
1687 it++;
1688 }
1689
1690 for (int n=1; n<ynsize; n++) {
1691 Yn[n].resize(newsize);
1692 std::vector<cln::cl_N>::iterator it = Yn[n].begin();
1693 std::vector<cln::cl_N>::iterator itprev = Yn[n-1].begin();
1694 it += ynlength;
1695 itprev += ynlength;
1696 for (int i=ynlength+n+1; i<=newsize+n; i++) {
1697 *it = *(it-1) + (*itprev) / cln::cl_N(i) * one;
1698 it++;
1699 itprev++;
1700 }
1701 }
1702
1703 ynlength = newsize;
1704 }
1705
1706
1707 // helper function for S(n,p,x)
1708 // [Kol] (7.2)
1709 cln::cl_N C(int n, int p)
1710 {
1711 cln::cl_N result;
1712
1713 for (int k=0; k<p; k++) {
1714 for (int j=0; j<=(n+k-1)/2; j++) {
1715 if (k == 0) {
1716 if (n & 1) {
1717 if (j & 1) {
1718 result = result - 2 * cln::expt(cln::pi(),2*j) * S_num(n-2*j,p,1).to_cl_N() / cln::factorial(2*j);
1719 }
1720 else {
1721 result = result + 2 * cln::expt(cln::pi(),2*j) * S_num(n-2*j,p,1).to_cl_N() / cln::factorial(2*j);
1722 }
1723 }
1724 }
1725 else {
1726 if (k & 1) {
1727 if (j & 1) {
1728 result = result + cln::factorial(n+k-1)
1729 * cln::expt(cln::pi(),2*j) * S_num(n+k-2*j,p-k,1).to_cl_N()
1730 / (cln::factorial(k) * cln::factorial(n-1) * cln::factorial(2*j));
1731 }
1732 else {
1733 result = result - cln::factorial(n+k-1)
1734 * cln::expt(cln::pi(),2*j) * S_num(n+k-2*j,p-k,1).to_cl_N()
1735 / (cln::factorial(k) * cln::factorial(n-1) * cln::factorial(2*j));
1736 }
1737 }
1738 else {
1739 if (j & 1) {
1740 result = result - cln::factorial(n+k-1) * cln::expt(cln::pi(),2*j) * S_num(n+k-2*j,p-k,1).to_cl_N()
1741 / (cln::factorial(k) * cln::factorial(n-1) * cln::factorial(2*j));
1742 }
1743 else {
1744 result = result + cln::factorial(n+k-1)
1745 * cln::expt(cln::pi(),2*j) * S_num(n+k-2*j,p-k,1).to_cl_N()
1746 / (cln::factorial(k) * cln::factorial(n-1) * cln::factorial(2*j));
1747 }
1748 }
1749 }
1750 }
1751 }
1752 int np = n+p;
1753 if ((np-1) & 1) {
1754 if (((np)/2+n) & 1) {
1755 result = -result - cln::expt(cln::pi(),np) / (np * cln::factorial(n-1) * cln::factorial(p));
1756 }
1757 else {
1758 result = -result + cln::expt(cln::pi(),np) / (np * cln::factorial(n-1) * cln::factorial(p));
1759 }
1760 }
1761
1762 return result;
1763 }
1764
1765
1766 // helper function for S(n,p,x)
1767 // [Kol] remark to (9.1)
1768 cln::cl_N a_k(int k)
1769 {
1770 cln::cl_N result;
1771
1772 if (k == 0) {
1773 return 1;
1774 }
1775
1776 result = result;
1777 for (int m=2; m<=k; m++) {
1778 result = result + cln::expt(cln::cl_N(-1),m) * cln::zeta(m) * a_k(k-m);
1779 }
1780
1781 return -result / k;
1782 }
1783
1784
1785 // helper function for S(n,p,x)
1786 // [Kol] remark to (9.1)
1787 cln::cl_N b_k(int k)
1788 {
1789 cln::cl_N result;
1790
1791 if (k == 0) {
1792 return 1;
1793 }
1794
1795 result = result;
1796 for (int m=2; m<=k; m++) {
1797 result = result + cln::expt(cln::cl_N(-1),m) * cln::zeta(m) * b_k(k-m);
1798 }
1799
1800 return result / k;
1801 }
1802
1803
1804 // helper function for S(n,p,x)
1805 cln::cl_N S_do_sum(int n, int p, const cln::cl_N& x, const cln::float_format_t& prec)
1806 {
1807 if (p==1) {
1808 return Li_projection(n+1, x, prec);
1809 }
1810
1811 // check if precalculated values are sufficient
1812 if (p > ynsize+1) {
1813 for (int i=ynsize; i<p-1; i++) {
1814 fill_Yn(i, prec);
1815 }
1816 }
1817
1818 // should be done otherwise
1819 cln::cl_F one = cln::cl_float(1, cln::float_format(Digits));
1820 cln::cl_N xf = x * one;
1821 //cln::cl_N xf = x * cln::cl_float(1, prec);
1822
1823 cln::cl_N res;
1824 cln::cl_N resbuf;
1825 cln::cl_N factor = cln::expt(xf, p);
1826 int i = p;
1827 do {
1828 resbuf = res;
1829 if (i-p >= ynlength) {
1830 // make Yn longer
1831 make_Yn_longer(ynlength*2, prec);
1832 }
1833 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? ...
1834 //res = res + factor / cln::expt(cln::cl_I(i),n+1) * (*it); // should we check it? or rely on magic number? ...
1835 factor = factor * xf;
1836 i++;
1837 } while (res != resbuf);
1838
1839 return res;
1840 }
1841
1842
1843 // helper function for S(n,p,x)
1844 cln::cl_N S_projection(int n, int p, const cln::cl_N& x, const cln::float_format_t& prec)
1845 {
1846 // [Kol] (5.3)
1847 if (cln::abs(cln::realpart(x)) > cln::cl_F("0.5")) {
1848
1849 cln::cl_N result = cln::expt(cln::cl_I(-1),p) * cln::expt(cln::log(x),n)
1850 * cln::expt(cln::log(1-x),p) / cln::factorial(n) / cln::factorial(p);
1851
1852 for (int s=0; s<n; s++) {
1853 cln::cl_N res2;
1854 for (int r=0; r<p; r++) {
1855 res2 = res2 + cln::expt(cln::cl_I(-1),r) * cln::expt(cln::log(1-x),r)
1856 * S_do_sum(p-r,n-s,1-x,prec) / cln::factorial(r);
1857 }
1858 result = result + cln::expt(cln::log(x),s) * (S_num(n-s,p,1).to_cl_N() - res2) / cln::factorial(s);
1859 }
1860
1861 return result;
1862 }
1863
1864 return S_do_sum(n, p, x, prec);
1865 }
1866
1867
1868 // helper function for S(n,p,x)
1869 numeric S_num(int n, int p, const numeric& x)
1870 {
1871 if (x == 1) {
1872 if (n == 1) {
1873 // [Kol] (2.22) with (2.21)
1874 return cln::zeta(p+1);
1875 }
1876
1877 if (p == 1) {
1878 // [Kol] (2.22)
1879 return cln::zeta(n+1);
1880 }
1881
1882 // [Kol] (9.1)
1883 cln::cl_N result;
1884 for (int nu=0; nu<n; nu++) {
1885 for (int rho=0; rho<=p; rho++) {
1886 result = result + b_k(n-nu-1) * b_k(p-rho) * a_k(nu+rho+1)
1887 * cln::factorial(nu+rho+1) / cln::factorial(rho) / cln::factorial(nu+1);
1888 }
1889 }
1890 result = result * cln::expt(cln::cl_I(-1),n+p-1);
1891
1892 return result;
1893 }
1894 else if (x == -1) {
1895 // [Kol] (2.22)
1896 if (p == 1) {
1897 return -(1-cln::expt(cln::cl_I(2),-n)) * cln::zeta(n+1);
1898 }
1899 // throw std::runtime_error("don't know how to evaluate this function!");
1900 }
1901
1902 // what is the desired float format?
1903 // first guess: default format
1904 cln::float_format_t prec = cln::default_float_format;
1905 const cln::cl_N value = x.to_cl_N();
1906 // second guess: the argument's format
1907 if (!x.real().is_rational())
1908 prec = cln::float_format(cln::the<cln::cl_F>(cln::realpart(value)));
1909 else if (!x.imag().is_rational())
1910 prec = cln::float_format(cln::the<cln::cl_F>(cln::imagpart(value)));
1911
1912 // [Kol] (5.3)
1913 if ((cln::realpart(value) < -0.5) || (n == 0) || ((cln::abs(value) <= 1) && (cln::abs(value) > 0.95))) {
1914
1915 cln::cl_N result = cln::expt(cln::cl_I(-1),p) * cln::expt(cln::log(value),n)
1916 * cln::expt(cln::log(1-value),p) / cln::factorial(n) / cln::factorial(p);
1917
1918 for (int s=0; s<n; s++) {
1919 cln::cl_N res2;
1920 for (int r=0; r<p; r++) {
1921 res2 = res2 + cln::expt(cln::cl_I(-1),r) * cln::expt(cln::log(1-value),r)
1922 * S_num(p-r,n-s,1-value).to_cl_N() / cln::factorial(r);
1923 }
1924 result = result + cln::expt(cln::log(value),s) * (S_num(n-s,p,1).to_cl_N() - res2) / cln::factorial(s);
1925 }
1926
1927 return result;
1928
1929 }
1930 // [Kol] (5.12)
1931 if (cln::abs(value) > 1) {
1932
1933 cln::cl_N result;
1934
1935 for (int s=0; s<p; s++) {
1936 for (int r=0; r<=s; r++) {
1937 result = result + cln::expt(cln::cl_I(-1),s) * cln::expt(cln::log(-value),r) * cln::factorial(n+s-r-1)
1938 / cln::factorial(r) / cln::factorial(s-r) / cln::factorial(n-1)
1939 * S_num(n+s-r,p-s,cln::recip(value)).to_cl_N();
1940 }
1941 }
1942 result = result * cln::expt(cln::cl_I(-1),n);
1943
1944 cln::cl_N res2;
1945 for (int r=0; r<n; r++) {
1946 res2 = res2 + cln::expt(cln::log(-value),r) * C(n-r,p) / cln::factorial(r);
1947 }
1948 res2 = res2 + cln::expt(cln::log(-value),n+p) / cln::factorial(n+p);
1949
1950 result = result + cln::expt(cln::cl_I(-1),p) * res2;
1951
1952 return result;
1953 }
1954 else {
1955 return S_projection(n, p, value, prec);
1956 }
1957 }
1958
1959
1960 } // end of anonymous namespace
1961
1962
1963 //////////////////////////////////////////////////////////////////////
1964 //
1965 // Nielsen's generalized polylogarithm S(n,p,x)
1966 //
1967 // GiNaC function
1968 //
1969 //////////////////////////////////////////////////////////////////////
1970
1971
1972 static ex S_evalf(const ex& n, const ex& p, const ex& x)
1973 {
1974 if (n.info(info_flags::posint) && p.info(info_flags::posint)) {
1975 if (is_a<numeric>(x)) {
1976 return S_num(ex_to<numeric>(n).to_int(), ex_to<numeric>(p).to_int(), ex_to<numeric>(x));
1977 } else {
1978 ex x_val = x.evalf();
1979 if (is_a<numeric>(x_val)) {
1980 return S_num(ex_to<numeric>(n).to_int(), ex_to<numeric>(p).to_int(), ex_to<numeric>(x_val));
1981 }
1982 }
1983 }
1984 return S(n, p, x).hold();
1985 }
1986
1987
1988 static ex S_eval(const ex& n, const ex& p, const ex& x)
1989 {
1990 if (n.info(info_flags::posint) && p.info(info_flags::posint)) {
1991 if (x == 0) {
1992 return _ex0;
1993 }
1994 if (x == 1) {
1995 lst m(n+1);
1996 for (int i=ex_to<numeric>(p).to_int()-1; i>0; i--) {
1997 m.append(1);
1998 }
1999 return zeta(m);
2000 }
2001 if (p == 1) {
2002 return Li(n+1, x);
2003 }
2004 if (x.info(info_flags::numeric) && (!x.info(info_flags::crational))) {
2005 return S_num(ex_to<numeric>(n).to_int(), ex_to<numeric>(p).to_int(), ex_to<numeric>(x));
2006 }
2007 }
2008 if (n.is_zero()) {
2009 // [Kol] (5.3)
2010 return pow(-log(1-x), p) / factorial(p);
2011 }
2012 return S(n, p, x).hold();
2013 }
2014
2015
2016 static ex S_series(const ex& n, const ex& p, const ex& x, const relational& rel, int order, unsigned options)
2017 {
2018 if (p == _ex1) {
2019 return Li(n+1, x).series(rel, order, options);
2020 }
2021
2022 const ex x_pt = x.subs(rel, subs_options::no_pattern);
2023 if (n.info(info_flags::posint) && p.info(info_flags::posint) && x_pt.info(info_flags::numeric)) {
2024 // First special case: x==0 (derivatives have poles)
2025 if (x_pt.is_zero()) {
2026 const symbol s;
2027 ex ser;
2028 // manually construct the primitive expansion
2029 // subsum = Euler-Zagier-Sum is needed
2030 // dirty hack (slow ...) calculation of subsum:
2031 std::vector<ex> presubsum, subsum;
2032 subsum.push_back(0);
2033 for (int i=1; i<order-1; ++i) {
2034 subsum.push_back(subsum[i-1] + numeric(1, i));
2035 }
2036 for (int depth=2; depth<p; ++depth) {
2037 presubsum = subsum;
2038 for (int i=1; i<order-1; ++i) {
2039 subsum[i] = subsum[i-1] + numeric(1, i) * presubsum[i-1];
2040 }
2041 }
2042
2043 for (int i=1; i<order; ++i) {
2044 ser += pow(s,i) / pow(numeric(i), n+1) * subsum[i-1];
2045 }
2046 // substitute the argument's series expansion
2047 ser = ser.subs(s==x.series(rel, order), subs_options::no_pattern);
2048 // maybe that was terminating, so add a proper order term
2049 epvector nseq;
2050 nseq.push_back(expair(Order(_ex1), order));
2051 ser += pseries(rel, nseq);
2052 // reexpanding it will collapse the series again
2053 return ser.series(rel, order);
2054 }
2055 // TODO special cases: x==1 (branch point) and x real, >=1 (branch cut)
2056 throw std::runtime_error("S_series: don't know how to do the series expansion at this point!");
2057 }
2058 // all other cases should be safe, by now:
2059 throw do_taylor(); // caught by function::series()
2060 }
2061
2062
2063 static ex S_deriv(const ex& n, const ex& p, const ex& x, unsigned deriv_param)
2064 {
2065 GINAC_ASSERT(deriv_param < 3);
2066 if (deriv_param < 2) {
2067 return _ex0;
2068 }
2069 if (n > 0) {
2070 return S(n-1, p, x) / x;
2071 } else {
2072 return S(n, p-1, x) / (1-x);
2073 }
2074 }
2075
2076
2077 static void S_print_latex(const ex& n, const ex& p, const ex& x, const print_context& c)
2078 {
2079 c.s << "\\mbox{S}_{";
2080 n.print(c);
2081 c.s << ",";
2082 p.print(c);
2083 c.s << "}(";
2084 x.print(c);
2085 c.s << ")";
2086 }
2087
2088
2089 REGISTER_FUNCTION(S,
2090 evalf_func(S_evalf).
2091 eval_func(S_eval).
2092 series_func(S_series).
2093 derivative_func(S_deriv).
2094 print_func<print_latex>(S_print_latex).
2095 do_not_evalf_params());
2096
2097
2098 //////////////////////////////////////////////////////////////////////
2099 //
2100 // Harmonic polylogarithm H(m,x)
2101 //
2102 // helper functions
2103 //
2104 //////////////////////////////////////////////////////////////////////
2105
2106
2107 // anonymous namespace for helper functions
2108 namespace {
2109
2110
2111 // regulates the pole (used by 1/x-transformation)
2112 symbol H_polesign("IMSIGN");
2113
2114
2115 // convert parameters from H to Li representation
2116 // parameters are expected to be in expanded form, i.e. only 0, 1 and -1
2117 // returns true if some parameters are negative
2118 bool convert_parameter_H_to_Li(const lst& l, lst& m, lst& s, ex& pf)
2119 {
2120 // expand parameter list
2121 lst mexp;
2122 for (lst::const_iterator it = l.begin(); it != l.end(); it++) {
2123 if (*it > 1) {
2124 for (ex count=*it-1; count > 0; count--) {
2125 mexp.append(0);
2126 }
2127 mexp.append(1);
2128 } else if (*it < -1) {
2129 for (ex count=*it+1; count < 0; count++) {
2130 mexp.append(0);
2131 }
2132 mexp.append(-1);
2133 } else {
2134 mexp.append(*it);
2135 }
2136 }
2137
2138 ex signum = 1;
2139 pf = 1;
2140 bool has_negative_parameters = false;
2141 ex acc = 1;
2142 for (lst::const_iterator it = mexp.begin(); it != mexp.end(); it++) {
2143 if (*it == 0) {
2144 acc++;
2145 continue;
2146 }
2147 if (*it > 0) {
2148 m.append((*it+acc-1) * signum);
2149 } else {
2150 m.append((*it-acc+1) * signum);
2151 }
2152 acc = 1;
2153 signum = *it;
2154 pf *= *it;
2155 if (pf < 0) {
2156 has_negative_parameters = true;
2157 }
2158 }
2159 if (has_negative_parameters) {
2160 for (int i=0; i<m.nops(); i++) {
2161 if (m.op(i) < 0) {
2162 m.let_op(i) = -m.op(i);
2163 s.append(-1);
2164 } else {
2165 s.append(1);
2166 }
2167 }
2168 }
2169
2170 return has_negative_parameters;
2171 }
2172
2173
2174 // recursivly transforms H to corresponding multiple polylogarithms
2175 struct map_trafo_H_convert_to_Li : public map_function
2176 {
2177 ex operator()(const ex& e)
2178 {
2179 if (is_a<add>(e) || is_a<mul>(e)) {
2180 return e.map(*this);
2181 }
2182 if (is_a<function>(e)) {
2183 std::string name = ex_to<function>(e).get_name();
2184 if (name == "H") {
2185 lst parameter;
2186 if (is_a<lst>(e.op(0))) {
2187 parameter = ex_to<lst>(e.op(0));
2188 } else {
2189 parameter = lst(e.op(0));
2190 }
2191 ex arg = e.op(1);
2192
2193 lst m;
2194 lst s;
2195 ex pf;
2196 if (convert_parameter_H_to_Li(parameter, m, s, pf)) {
2197 s.let_op(0) = s.op(0) * arg;
2198 return pf * Li(m, s).hold();
2199 } else {
2200 for (int i=0; i<m.nops(); i++) {
2201 s.append(1);
2202 }
2203 s.let_op(0) = s.op(0) * arg;
2204 return Li(m, s).hold();
2205 }
2206 }
2207 }
2208 return e;
2209 }
2210 };
2211
2212
2213 // recursivly transforms H to corresponding zetas
2214 struct map_trafo_H_convert_to_zeta : public map_function
2215 {
2216 ex operator()(const ex& e)
2217 {
2218 if (is_a<add>(e) || is_a<mul>(e)) {
2219 return e.map(*this);
2220 }
2221 if (is_a<function>(e)) {
2222 std::string name = ex_to<function>(e).get_name();
2223 if (name == "H") {
2224 lst parameter;
2225 if (is_a<lst>(e.op(0))) {
2226 parameter = ex_to<lst>(e.op(0));
2227 } else {
2228 parameter = lst(e.op(0));
2229 }
2230
2231 lst m;
2232 lst s;
2233 ex pf;
2234 if (convert_parameter_H_to_Li(parameter, m, s, pf)) {
2235 return pf * zeta(m, s);
2236 } else {
2237 return zeta(m);
2238 }
2239 }
2240 }
2241 return e;
2242 }
2243 };
2244
2245
2246 // remove trailing zeros from H-parameters
2247 struct map_trafo_H_reduce_trailing_zeros : public map_function
2248 {
2249 ex operator()(const ex& e)
2250 {
2251 if (is_a<add>(e) || is_a<mul>(e)) {
2252 return e.map(*this);
2253 }
2254 if (is_a<function>(e)) {
2255 std::string name = ex_to<function>(e).get_name();
2256 if (name == "H") {
2257 lst parameter;
2258 if (is_a<lst>(e.op(0))) {
2259 parameter = ex_to<lst>(e.op(0));
2260 } else {
2261 parameter = lst(e.op(0));
2262 }
2263 ex arg = e.op(1);
2264 if (parameter.op(parameter.nops()-1) == 0) {
2265
2266 //
2267 if (parameter.nops() == 1) {
2268 return log(arg);
2269 }
2270
2271 //
2272 lst::const_iterator it = parameter.begin();
2273 while ((it != parameter.end()) && (*it == 0)) {
2274 it++;
2275 }
2276 if (it == parameter.end()) {
2277 return pow(log(arg),parameter.nops()) / factorial(parameter.nops());
2278 }
2279
2280 //
2281 parameter.remove_last();
2282 int lastentry = parameter.nops();
2283 while ((lastentry > 0) && (parameter[lastentry-1] == 0)) {
2284 lastentry--;
2285 }
2286
2287 //
2288 ex result = log(arg) * H(parameter,arg).hold();
2289 ex acc = 0;
2290 for (ex i=0; i<lastentry; i++) {
2291 if (parameter[i] > 0) {
2292 parameter[i]++;
2293 result -= (acc + parameter[i]-1) * H(parameter, arg).hold();
2294 parameter[i]--;
2295 acc = 0;
2296 } else if (parameter[i] < 0) {
2297 parameter[i]--;
2298 result -= (acc + abs(parameter[i]+1)) * H(parameter, arg).hold();
2299 parameter[i]++;
2300 acc = 0;
2301 } else {
2302 acc++;
2303 }
2304 }
2305
2306 if (lastentry < parameter.nops()) {
2307 result = result / (parameter.nops()-lastentry+1);
2308 return result.map(*this);
2309 } else {
2310 return result;
2311 }
2312 }
2313 }
2314 }
2315 return e;
2316 }
2317 };
2318
2319
2320 // returns an expression with zeta functions corresponding to the parameter list for H
2321 ex convert_H_to_zeta(const lst& m)
2322 {
2323 symbol xtemp("xtemp");
2324 map_trafo_H_reduce_trailing_zeros filter;
2325 map_trafo_H_convert_to_zeta filter2;
2326 return filter2(filter(H(m, xtemp).hold())).subs(xtemp == 1);
2327 }
2328
2329
2330 // convert signs form Li to H representation
2331 lst convert_parameter_Li_to_H(const lst& m, const lst& x, ex& pf)
2332 {
2333 lst res;
2334 lst::const_iterator itm = m.begin();
2335 lst::const_iterator itx = ++x.begin();
2336 int signum = 1;
2337 pf = _ex1;
2338 res.append(*itm);
2339 itm++;
2340 while (itx != x.end()) {
2341 signum *= (*itx > 0) ? 1 : -1;
2342 pf *= signum;
2343 res.append((*itm) * signum);
2344 itm++;
2345 itx++;
2346 }
2347 return res;
2348 }
2349
2350
2351 // multiplies an one-dimensional H with another H
2352 // [ReV] (18)
2353 ex trafo_H_mult(const ex& h1, const ex& h2)
2354 {
2355 ex res;
2356 ex hshort;
2357 lst hlong;
2358 ex h1nops = h1.op(0).nops();
2359 ex h2nops = h2.op(0).nops();
2360 if (h1nops > 1) {
2361 hshort = h2.op(0).op(0);
2362 hlong = ex_to<lst>(h1.op(0));
2363 } else {
2364 hshort = h1.op(0).op(0);
2365 if (h2nops > 1) {
2366 hlong = ex_to<lst>(h2.op(0));
2367 } else {
2368 hlong = h2.op(0).op(0);
2369 }
2370 }
2371 for (int i=0; i<=hlong.nops(); i++) {
2372 lst newparameter;
2373 int j=0;
2374 for (; j<i; j++) {
2375 newparameter.append(hlong[j]);
2376 }
2377 newparameter.append(hshort);
2378 for (; j<hlong.nops(); j++) {
2379 newparameter.append(hlong[j]);
2380 }
2381 res += H(newparameter, h1.op(1)).hold();
2382 }
2383 return res;
2384 }
2385
2386
2387 // applies trafo_H_mult recursively on expressions
2388 struct map_trafo_H_mult : public map_function
2389 {
2390 ex operator()(const ex& e)
2391 {
2392 if (is_a<add>(e)) {
2393 return e.map(*this);
2394 }
2395
2396 if (is_a<mul>(e)) {
2397
2398 ex result = 1;
2399 ex firstH;
2400 lst Hlst;
2401 for (int pos=0; pos<e.nops(); pos++) {
2402 if (is_a<power>(e.op(pos)) && is_a<function>(e.op(pos).op(0))) {
2403 std::string name = ex_to<function>(e.op(pos).op(0)).get_name();
2404 if (name == "H") {
2405 for (ex i=0; i<e.op(pos).op(1); i++) {
2406 Hlst.append(e.op(pos).op(0));
2407 }
2408 continue;
2409 }
2410 } else if (is_a<function>(e.op(pos))) {
2411 std::string name = ex_to<function>(e.op(pos)).get_name();
2412 if (name == "H") {
2413 if (e.op(pos).op(0).nops() > 1) {
2414 firstH = e.op(pos);
2415 } else {
2416 Hlst.append(e.op(pos));
2417 }
2418 continue;
2419 }
2420 }
2421 result *= e.op(pos);
2422 }
2423 if (firstH == 0) {
2424 if (Hlst.nops() > 0) {
2425 firstH = Hlst[Hlst.nops()-1];
2426 Hlst.remove_last();
2427 } else {
2428 return e;
2429 }
2430 }
2431
2432 if (Hlst.nops() > 0) {
2433 ex buffer = trafo_H_mult(firstH, Hlst.op(0));
2434 result *= buffer;
2435 for (int i=1; i<Hlst.nops(); i++) {
2436 result *= Hlst.op(i);
2437 }
2438 result = result.expand();
2439 map_trafo_H_mult recursion;
2440 return recursion(result);
2441 } else {
2442 return e;
2443 }
2444
2445 }
2446 return e;
2447 }
2448 };
2449
2450
2451 // do integration [ReV] (55)
2452 // put parameter 0 in front of existing parameters
2453 ex trafo_H_1tx_prepend_zero(const ex& e, const ex& arg)
2454 {
2455 ex h;
2456 std::string name;
2457 if (is_a<function>(e)) {
2458 name = ex_to<function>(e).get_name();
2459 }
2460 if (name == "H") {
2461 h = e;
2462 } else {
2463 for (int i=0; i<e.nops(); i++) {
2464 if (is_a<function>(e.op(i))) {
2465 std::string name = ex_to<function>(e.op(i)).get_name();
2466 if (name == "H") {
2467 h = e.op(i);
2468 }
2469 }
2470 }
2471 }
2472 if (h != 0) {
2473 lst newparameter = ex_to<lst>(h.op(0));
2474 newparameter.prepend(0);
2475 ex addzeta = convert_H_to_zeta(newparameter);
2476 return e.subs(h == (addzeta-H(newparameter, h.op(1)).hold())).expand();
2477 } else {
2478 return e * (-H(lst(0),1/arg).hold());
2479 }
2480 }
2481
2482
2483 // do integration [ReV] (49)
2484 // put parameter 1 in front of existing parameters
2485 ex trafo_H_prepend_one(const ex& e, const ex& arg)
2486 {
2487 ex h;
2488 std::string name;
2489 if (is_a<function>(e)) {
2490 name = ex_to<function>(e).get_name();
2491 }
2492 if (name == "H") {
2493 h = e;
2494 } else {
2495 for (int i=0; i<e.nops(); i++) {
2496 if (is_a<function>(e.op(i))) {
2497 std::string name = ex_to<function>(e.op(i)).get_name();
2498 if (name == "H") {
2499 h = e.op(i);
2500 }
2501 }
2502 }
2503 }
2504 if (h != 0) {
2505 lst newparameter = ex_to<lst>(h.op(0));
2506 newparameter.prepend(1);
2507 return e.subs(h == H(newparameter, h.op(1)).hold());
2508 } else {
2509 return e * H(lst(1),1-arg).hold();
2510 }
2511 }
2512
2513
2514 // do integration [ReV] (55)
2515 // put parameter -1 in front of existing parameters
2516 ex trafo_H_1tx_prepend_minusone(const ex& e, const ex& arg)
2517 {
2518 ex h;
2519 std::string name;
2520 if (is_a<function>(e)) {
2521 name = ex_to<function>(e).get_name();
2522 }
2523 if (name == "H") {
2524 h = e;
2525 } else {
2526 for (int i=0; i<e.nops(); i++) {
2527 if (is_a<function>(e.op(i))) {
2528 std::string name = ex_to<function>(e.op(i)).get_name();
2529 if (name == "H") {
2530 h = e.op(i);
2531 }
2532 }
2533 }
2534 }
2535 if (h != 0) {
2536 lst newparameter = ex_to<lst>(h.op(0));
2537 newparameter.prepend(-1);
2538 ex addzeta = convert_H_to_zeta(newparameter);
2539 return e.subs(h == (addzeta-H(newparameter, h.op(1)).hold())).expand();
2540 } else {
2541 ex addzeta = convert_H_to_zeta(lst(-1));
2542 return (e * (addzeta - H(lst(-1),1/arg).hold())).expand();
2543 }
2544 }
2545
2546
2547 // do integration [ReV] (55)
2548 // put parameter -1 in front of existing parameters
2549 ex trafo_H_1mxt1px_prepend_minusone(const ex& e, const ex& arg)
2550 {
2551 ex h;
2552 std::string name;
2553 if (is_a<function>(e)) {
2554 name = ex_to<function>(e).get_name();
2555 }
2556 if (name == "H") {
2557 h = e;
2558 } else {
2559 for (int i=0; i<e.nops(); i++) {
2560 if (is_a<function>(e.op(i))) {
2561 std::string name = ex_to<function>(e.op(i)).get_name();
2562 if (name == "H") {
2563 h = e.op(i);
2564 }
2565 }
2566 }
2567 }
2568 if (h != 0) {
2569 lst newparameter = ex_to<lst>(h.op(0));
2570 newparameter.prepend(-1);
2571 return e.subs(h == H(newparameter, h.op(1)).hold()).expand();
2572 } else {
2573 return (e * H(lst(-1),(1-arg)/(1+arg)).hold()).expand();
2574 }
2575 }
2576
2577
2578 // do integration [ReV] (55)
2579 // put parameter 1 in front of existing parameters
2580 ex trafo_H_1mxt1px_prepend_one(const ex& e, const ex& arg)
2581 {
2582 ex h;
2583 std::string name;
2584 if (is_a<function>(e)) {
2585 name = ex_to<function>(e).get_name();
2586 }
2587 if (name == "H") {
2588 h = e;
2589 } else {
2590 for (int i=0; i<e.nops(); i++) {
2591 if (is_a<function>(e.op(i))) {
2592 std::string name = ex_to<function>(e.op(i)).get_name();
2593 if (name == "H") {
2594 h = e.op(i);
2595 }
2596 }
2597 }
2598 }
2599 if (h != 0) {
2600 lst newparameter = ex_to<lst>(h.op(0));
2601 newparameter.prepend(1);
2602 return e.subs(h == H(newparameter, h.op(1)).hold()).expand();
2603 } else {
2604 return (e * H(lst(1),(1-arg)/(1+arg)).hold()).expand();
2605 }
2606 }
2607
2608
2609 // do x -> 1-x transformation
2610 struct map_trafo_H_1mx : public map_function
2611 {
2612 ex operator()(const ex& e)
2613 {
2614 if (is_a<add>(e) || is_a<mul>(e)) {
2615 return e.map(*this);
2616 }
2617
2618 if (is_a<function>(e)) {
2619 std::string name = ex_to<function>(e).get_name();
2620 if (name == "H") {
2621
2622 lst parameter = ex_to<lst>(e.op(0));
2623 ex arg = e.op(1);
2624
2625 // special cases if all parameters are either 0, 1 or -1
2626 bool allthesame = true;
2627 if (parameter.op(0) == 0) {
2628 for (int i=1; i<parameter.nops(); i++) {
2629 if (parameter.op(i) != 0) {
2630 allthesame = false;
2631 break;
2632 }
2633 }
2634 if (allthesame) {
2635 lst newparameter;
2636 for (int i=parameter.nops(); i>0; i--) {
2637 newparameter.append(1);
2638 }
2639 return pow(-1, parameter.nops()) * H(newparameter, 1-arg).hold();
2640 }
2641 } else if (parameter.op(0) == -1) {
2642 throw std::runtime_error("map_trafo_H_1mx: cannot handle weights equal -1!");
2643 } else {
2644 for (int i=1; i<parameter.nops(); i++) {
2645 if (parameter.op(i) != 1) {
2646 allthesame = false;
2647 break;
2648 }
2649 }
2650 if (allthesame) {
2651 lst newparameter;
2652 for (int i=parameter.nops(); i>0; i--) {
2653 newparameter.append(0);
2654 }
2655 return pow(-1, parameter.nops()) * H(newparameter, 1-arg).hold();
2656 }
2657 }
2658
2659 lst newparameter = parameter;
2660 newparameter.remove_first();
2661
2662 if (parameter.op(0) == 0) {
2663
2664 // leading zero
2665 ex res = convert_H_to_zeta(parameter);
2666 //ex res = convert_from_RV(parameter, 1).subs(H(wild(1),wild(2))==zeta(wild(1)));
2667 map_trafo_H_1mx recursion;
2668 ex buffer = recursion(H(newparameter, arg).hold());
2669 if (is_a<add>(buffer)) {
2670 for (int i=0; i<buffer.nops(); i++) {
2671 res -= trafo_H_prepend_one(buffer.op(i), arg);
2672 }
2673 } else {
2674 res -= trafo_H_prepend_one(buffer, arg);
2675 }
2676 return res;
2677
2678 } else {
2679
2680 // leading one
2681 map_trafo_H_1mx recursion;
2682 map_trafo_H_mult unify;
2683 ex res = H(lst(1), arg).hold() * H(newparameter, arg).hold();
2684 int firstzero = 0;
2685 while (parameter.op(firstzero) == 1) {
2686 firstzero++;
2687 }
2688 for (int i=firstzero-1; i<parameter.nops()-1; i++) {
2689 lst newparameter;
2690 int j=0;
2691 for (; j<=i; j++) {
2692 newparameter.append(parameter[j+1]);
2693 }
2694 newparameter.append(1);
2695 for (; j<parameter.nops()-1; j++) {
2696 newparameter.append(parameter[j+1]);
2697 }
2698 res -= H(newparameter, arg).hold();
2699 }
2700 res = recursion(res).expand() / firstzero;
2701 return unify(res);
2702 }
2703 }
2704 }
2705 return e;
2706 }
2707 };
2708
2709
2710 // do x -> 1/x transformation
2711 struct map_trafo_H_1overx : public map_function
2712 {
2713 ex operator()(const ex& e)
2714 {
2715 if (is_a<add>(e) || is_a<mul>(e)) {
2716 return e.map(*this);
2717 }
2718
2719 if (is_a<function>(e)) {
2720 std::string name = ex_to<function>(e).get_name();
2721 if (name == "H") {
2722
2723 lst parameter = ex_to<lst>(e.op(0));
2724 ex arg = e.op(1);
2725
2726 // special cases if all parameters are either 0, 1 or -1
2727 bool allthesame = true;
2728 if (parameter.op(0) == 0) {
2729 for (int i=1; i<parameter.nops(); i++) {
2730 if (parameter.op(i) != 0) {
2731 allthesame = false;
2732 break;
2733 }
2734 }
2735 if (allthesame) {
2736 return pow(-1, parameter.nops()) * H(parameter, 1/arg).hold();
2737 }
2738 } else if (parameter.op(0) == -1) {
2739 for (int i=1; i<parameter.nops(); i++) {
2740 if (parameter.op(i) != -1) {
2741 allthesame = false;
2742 break;
2743 }
2744 }
2745 if (allthesame) {
2746 map_trafo_H_mult unify;
2747 return unify((pow(H(lst(-1),1/arg).hold() - H(lst(0),1/arg).hold(), parameter.nops())
2748 / factorial(parameter.nops())).expand());
2749 }
2750 } else {
2751 for (int i=1; i<parameter.nops(); i++) {
2752 if (parameter.op(i) != 1) {
2753 allthesame = false;
2754 break;
2755 }
2756 }
2757 if (allthesame) {
2758 map_trafo_H_mult unify;
2759 return unify((pow(H(lst(1),1/arg).hold() + H(lst(0),1/arg).hold() + H_polesign, parameter.nops())
2760 / factorial(parameter.nops())).expand());
2761 }
2762 }
2763
2764 lst newparameter = parameter;
2765 newparameter.remove_first();
2766
2767 if (parameter.op(0) == 0) {
2768
2769 // leading zero
2770 ex res = convert_H_to_zeta(parameter);
2771 map_trafo_H_1overx recursion;
2772 ex buffer = recursion(H(newparameter, arg).hold());
2773 if (is_a<add>(buffer)) {
2774 for (int i=0; i<buffer.nops(); i++) {
2775 res += trafo_H_1tx_prepend_zero(buffer.op(i), arg);
2776 }
2777 } else {
2778 res += trafo_H_1tx_prepend_zero(buffer, arg);
2779 }
2780 return res;
2781
2782 } else if (parameter.op(0) == -1) {
2783
2784 // leading negative one
2785 ex res = convert_H_to_zeta(parameter);
2786 map_trafo_H_1overx recursion;
2787 ex buffer = recursion(H(newparameter, arg).hold());
2788 if (is_a<add>(buffer)) {
2789 for (int i=0; i<buffer.nops(); i++) {
2790 res += trafo_H_1tx_prepend_zero(buffer.op(i), arg) - trafo_H_1tx_prepend_minusone(buffer.op(i), arg);
2791 }
2792 } else {
2793 res += trafo_H_1tx_prepend_zero(buffer, arg) - trafo_H_1tx_prepend_minusone(buffer, arg);
2794 }
2795 return res;
2796
2797 } else {
2798
2799 // leading one
2800 map_trafo_H_1overx recursion;
2801 map_trafo_H_mult unify;
2802 ex res = H(lst(1), arg).hold() * H(newparameter, arg).hold();
2803 int firstzero = 0;
2804 while (parameter.op(firstzero) == 1) {
2805 firstzero++;
2806 }
2807 for (int i=firstzero-1; i<parameter.nops()-1; i++) {
2808 lst newparameter;
2809 int j=0;
2810 for (; j<=i; j++) {
2811 newparameter.append(parameter[j+1]);
2812 }
2813 newparameter.append(1);
2814 for (; j<parameter.nops()-1; j++) {
2815 newparameter.append(parameter[j+1]);
2816 }
2817 res -= H(newparameter, arg).hold();
2818 }
2819 res = recursion(res).expand() / firstzero;
2820 return unify(res);
2821
2822 }
2823
2824 }
2825 }
2826 return e;
2827 }
2828 };
2829
2830
2831 // do x -> (1-x)/(1+x) transformation
2832 struct map_trafo_H_1mxt1px : public map_function
2833 {
2834 ex operator()(const ex& e)
2835 {
2836 if (is_a<add>(e) || is_a<mul>(e)) {
2837 return e.map(*this);
2838 }
2839
2840 if (is_a<function>(e)) {
2841 std::string name = ex_to<function>(e).get_name();
2842 if (name == "H") {
2843
2844 lst parameter = ex_to<lst>(e.op(0));
2845 ex arg = e.op(1);
2846
2847 // special cases if all parameters are either 0, 1 or -1
2848 bool allthesame = true;
2849 if (parameter.op(0) == 0) {
2850 for (int i=1; i<parameter.nops(); i++) {
2851 if (parameter.op(i) != 0) {
2852 allthesame = false;
2853 break;
2854 }
2855 }
2856 if (allthesame) {
2857 map_trafo_H_mult unify;
2858 return unify((pow(-H(lst(1),(1-arg)/(1+arg)).hold() - H(lst(-1),(1-arg)/(1+arg)).hold(), parameter.nops())
2859 / factorial(parameter.nops())).expand());
2860 }
2861 } else if (parameter.op(0) == -1) {
2862 for (int i=1; i<parameter.nops(); i++) {
2863 if (parameter.op(i) != -1) {
2864 allthesame = false;
2865 break;
2866 }
2867 }
2868 if (allthesame) {
2869 map_trafo_H_mult unify;
2870 return unify((pow(log(2) - H(lst(-1),(1-arg)/(1+arg)).hold(), parameter.nops())
2871 / factorial(parameter.nops())).expand());
2872 }
2873 } else {
2874 for (int i=1; i<parameter.nops(); i++) {
2875 if (parameter.op(i) != 1) {
2876 allthesame = false;
2877 break;
2878 }
2879 }
2880 if (allthesame) {
2881 map_trafo_H_mult unify;
2882 return unify((pow(-log(2) - H(lst(0),(1-arg)/(1+arg)).hold() + H(lst(-1),(1-arg)/(1+arg)).hold(), parameter.nops())
2883 / factorial(parameter.nops())).expand());
2884 }
2885 }
2886
2887 lst newparameter = parameter;
2888 newparameter.remove_first();
2889
2890 if (parameter.op(0) == 0) {
2891
2892 // leading zero
2893 ex res = convert_H_to_zeta(parameter);
2894 map_trafo_H_1mxt1px recursion;
2895 ex buffer = recursion(H(newparameter, arg).hold());
2896 if (is_a<add>(buffer)) {
2897 for (int i=0; i<buffer.nops(); i++) {
2898 res -= trafo_H_1mxt1px_prepend_one(buffer.op(i), arg) + trafo_H_1mxt1px_prepend_minusone(buffer.op(i), arg);
2899 }
2900 } else {
2901 res -= trafo_H_1mxt1px_prepend_one(buffer, arg) + trafo_H_1mxt1px_prepend_minusone(buffer, arg);
2902 }
2903 return res;
2904
2905 } else if (parameter.op(0) == -1) {
2906
2907 // leading negative one
2908 ex res = convert_H_to_zeta(parameter);
2909 map_trafo_H_1mxt1px recursion;
2910 ex buffer = recursion(H(newparameter, arg).hold());
2911 if (is_a<add>(buffer)) {
2912 for (int i=0; i<buffer.nops(); i++) {
2913 res -= trafo_H_1mxt1px_prepend_minusone(buffer.op(i), arg);
2914 }
2915 } else {
2916 res -= trafo_H_1mxt1px_prepend_minusone(buffer, arg);
2917 }
2918 return res;
2919
2920 } else {
2921
2922 // leading one
2923 map_trafo_H_1mxt1px recursion;
2924 map_trafo_H_mult unify;
2925 ex res = H(lst(1), arg).hold() * H(newparameter, arg).hold();
2926 int firstzero = 0;
2927 while (parameter.op(firstzero) == 1) {
2928 firstzero++;
2929 }
2930 for (int i=firstzero-1; i<parameter.nops()-1; i++) {
2931 lst newparameter;
2932 int j=0;
2933 for (; j<=i; j++) {
2934 newparameter.append(parameter[j+1]);
2935 }
2936 newparameter.append(1);
2937 for (; j<parameter.nops()-1; j++) {
2938 newparameter.append(parameter[j+1]);
2939 }
2940 res -= H(newparameter, arg).hold();
2941 }
2942 res = recursion(res).expand() / firstzero;
2943 return unify(res);
2944
2945 }
2946
2947 }
2948 }
2949 return e;
2950 }
2951 };
2952
2953
2954 // do the actual summation.
2955 cln::cl_N H_do_sum(const std::vector<int>& m, const cln::cl_N& x)
2956 {
2957 const int j = m.size();
2958
2959 std::vector<cln::cl_N> t(j);
2960
2961 cln::cl_F one = cln::cl_float(1, cln::float_format(Digits));
2962 cln::cl_N factor = cln::expt(x, j) * one;
2963 cln::cl_N t0buf;
2964 int q = 0;
2965 do {
2966 t0buf = t[0];
2967 q++;
2968 t[j-1] = t[j-1] + 1 / cln::expt(cln::cl_I(q),m[j-1]);
2969 for (int k=j-2; k>=1; k--) {
2970 t[k] = t[k] + t[k+1] / cln::expt(cln::cl_I(q+j-1-k), m[k]);
2971 }
2972 t[0] = t[0] + t[1] * factor / cln::expt(cln::cl_I(q+j-1), m[0]);
2973 factor = factor * x;
2974 } while (t[0] != t0buf);
2975
2976 return t[0];
2977 }
2978
2979
2980 } // end of anonymous namespace
2981
2982
2983 //////////////////////////////////////////////////////////////////////
2984 //
2985 // Harmonic polylogarithm H(m,x)
2986 //
2987 // GiNaC function
2988 //
2989 //////////////////////////////////////////////////////////////////////
2990
2991
2992 static ex H_evalf(const ex& x1, const ex& x2)
2993 {
2994 if (is_a<lst>(x1)) {
2995
2996 cln::cl_N x;
2997 if (is_a<numeric>(x2)) {
2998 x = ex_to<numeric>(x2).to_cl_N();
2999 } else {
3000 ex x2_val = x2.evalf();
3001 if (is_a<numeric>(x2_val)) {
3002 x = ex_to<numeric>(x2_val).to_cl_N();
3003 }
3004 }
3005
3006 for (int i=0; i<x1.nops(); i++) {
3007 if (!x1.op(i).info(info_flags::integer)) {
3008 return H(x1, x2).hold();
3009 }
3010 }
3011 if (x1.nops() < 1) {
3012 return H(x1, x2).hold();
3013 }
3014
3015 const lst& morg = ex_to<lst>(x1);
3016 // remove trailing zeros ...
3017 if (*(--morg.end()) == 0) {
3018 symbol xtemp("xtemp");
3019 map_trafo_H_reduce_trailing_zeros filter;
3020 return filter(H(x1, xtemp).hold()).subs(xtemp==x2).evalf();
3021 }
3022 // ... and expand parameter notation
3023 bool has_minus_one = false;
3024 lst m;
3025 for (lst::const_iterator it = morg.begin(); it != morg.end(); it++) {
3026 if (*it > 1) {
3027 for (ex count=*it-1; count > 0; count--) {
3028 m.append(0);
3029 }
3030 m.append(1);
3031 } else if (*it <= -1) {
3032 for (ex count=*it+1; count < 0; count++) {
3033 m.append(0);
3034 }
3035 m.append(-1);
3036 has_minus_one = true;
3037 } else {
3038 m.append(*it);
3039 }
3040 }
3041
3042 // do summation
3043 if (cln::abs(x) < 0.95) {
3044 lst m_lst;
3045 lst s_lst;
3046 ex pf;
3047 if (convert_parameter_H_to_Li(m, m_lst, s_lst, pf)) {
3048 // negative parameters -> s_lst is filled
3049 std::vector<int> m_int;
3050 std::vector<cln::cl_N> x_cln;
3051 for (lst::const_iterator it_int = m_lst.begin(), it_cln = s_lst.begin();
3052 it_int != m_lst.end(); it_int++, it_cln++) {
3053 m_int.push_back(ex_to<numeric>(*it_int).to_int());
3054 x_cln.push_back(ex_to<numeric>(*it_cln).to_cl_N());
3055 }
3056 x_cln.front() = x_cln.front() * x;
3057 return pf * numeric(multipleLi_do_sum(m_int, x_cln));
3058 } else {
3059 // only positive parameters
3060 //TODO
3061 if (m_lst.nops() == 1) {
3062 return Li(m_lst.op(0), x2).evalf();
3063 }
3064 std::vector<int> m_int;
3065 for (lst::const_iterator it = m_lst.begin(); it != m_lst.end(); it++) {
3066 m_int.push_back(ex_to<numeric>(*it).to_int());
3067 }
3068 return numeric(H_do_sum(m_int, x));
3069 }
3070 }
3071
3072 symbol xtemp("xtemp");
3073 ex res = 1;
3074
3075 // ensure that the realpart of the argument is positive
3076 if (cln::realpart(x) < 0) {
3077 x = -x;
3078 for (int i=0; i<m.nops(); i++) {
3079 if (m.op(i) != 0) {
3080 m.let_op(i) = -m.op(i);
3081 res *= -1;
3082 }
3083 }
3084 }
3085
3086 // x -> 1/x
3087 if (cln::abs(x) >= 2.0) {
3088 map_trafo_H_1overx trafo;
3089 res *= trafo(H(m, xtemp));
3090 if (cln::imagpart(x) <= 0) {
3091 res = res.subs(H_polesign == -I*Pi);
3092 } else {
3093 res = res.subs(H_polesign == I*Pi);
3094 }
3095 return res.subs(xtemp == numeric(x)).evalf();
3096 }
3097
3098 // check transformations for 0.95 <= |x| < 2.0
3099
3100 // |(1-x)/(1+x)| < 0.9 -> circular area with center=9.53+0i and radius=9.47
3101 if (cln::abs(x-9.53) <= 9.47) {
3102 // x -> (1-x)/(1+x)
3103 map_trafo_H_1mxt1px trafo;
3104 res *= trafo(H(m, xtemp));
3105 } else {
3106 // x -> 1-x
3107 if (has_minus_one) {
3108 map_trafo_H_convert_to_Li filter;
3109 return filter(H(m, numeric(x)).hold()).evalf();
3110 }
3111 map_trafo_H_1mx trafo;
3112 res *= trafo(H(m, xtemp));
3113 }
3114
3115 return res.subs(xtemp == numeric(x)).evalf();
3116 }
3117
3118 return H(x1,x2).hold();
3119 }
3120
3121
3122 static ex H_eval(const ex& m_, const ex& x)
3123 {
3124 lst m;
3125 if (is_a<lst>(m_)) {
3126 m = ex_to<lst>(m_);
3127 } else {
3128 m = lst(m_);
3129 }
3130 if (m.nops() == 0) {
3131 return _ex1;
3132 }
3133 ex pos1;
3134 ex pos2;
3135 ex n;
3136 ex p;
3137 int step = 0;
3138 if (*m.begin() > _ex1) {
3139 step++;
3140 pos1 = _ex0;
3141 pos2 = _ex1;
3142 n = *m.begin()-1;
3143 p = _ex1;
3144 } else if (*m.begin() < _ex_1) {
3145 step++;
3146 pos1 = _ex0;
3147 pos2 = _ex_1;
3148 n = -*m.begin()-1;
3149 p = _ex1;
3150 } else if (*m.begin() == _ex0) {
3151 pos1 = _ex0;
3152 n = _ex1;
3153 } else {
3154 pos1 = *m.begin();
3155 p = _ex1;
3156 }
3157 for (lst::const_iterator it = ++m.begin(); it != m.end(); it++) {
3158 if ((*it).info(info_flags::integer)) {
3159 if (step == 0) {
3160 if (*it > _ex1) {
3161 if (pos1 == _ex0) {
3162 step = 1;
3163 pos2 = _ex1;
3164 n += *it-1;
3165 p = _ex1;
3166 } else {
3167 step = 2;
3168 }
3169 } else if (*it < _ex_1) {
3170 if (pos1 == _ex0) {
3171 step = 1;
3172 pos2 = _ex_1;
3173 n += -*it-1;
3174 p = _ex1;
3175 } else {
3176 step = 2;
3177 }
3178 } else {
3179 if (*it != pos1) {
3180 step = 1;
3181 pos2 = *it;
3182 }
3183 if (*it == _ex0) {
3184 n++;
3185 } else {
3186 p++;
3187 }
3188 }
3189 } else if (step == 1) {
3190 if (*it != pos2) {
3191 step = 2;
3192 } else {
3193 if (*it == _ex0) {
3194 n++;
3195 } else {
3196 p++;
3197 }
3198 }
3199 }
3200 } else {
3201 // if some m_i is not an integer
3202 return H(m_, x).hold();
3203 }
3204 }
3205 if ((x == _ex1) && (*(--m.end()) != _ex0)) {
3206 return convert_H_to_zeta(m);
3207 }
3208 if (step == 0) {
3209 if (pos1 == _ex0) {
3210 // all zero
3211 if (x == _ex0) {
3212 return H(m_, x).hold();
3213 }
3214 return pow(log(x), m.nops()) / factorial(m.nops());
3215 } else {
3216 // all (minus) one
3217 return pow(-pos1*log(1-pos1*x), m.nops()) / factorial(m.nops());
3218 }
3219 } else if ((step == 1) && (pos1 == _ex0)){
3220 // convertible to S
3221 if (pos2 == _ex1) {
3222 return S(n, p, x);
3223 } else {
3224 return pow(-1, p) * S(n, p, -x);
3225 }
3226 }
3227 if (x == _ex0) {
3228 return _ex0;
3229 }
3230 if (x.info(info_flags::numeric) && (!x.info(info_flags::crational))) {
3231 return H(m_, x).evalf();
3232 }
3233 return H(m_, x).hold();
3234 }
3235
3236
3237 static ex H_series(const ex& m, const ex& x, const relational& rel, int order, unsigned options)
3238 {
3239 epvector seq;
3240 seq.push_back(expair(H(m, x), 0));
3241 return pseries(rel, seq);
3242 }
3243
3244
3245 static ex H_deriv(const ex& m_, const ex& x, unsigned deriv_param)
3246 {
3247 GINAC_ASSERT(deriv_param < 2);
3248 if (deriv_param == 0) {
3249 return _ex0;
3250 }
3251 lst m;
3252 if (is_a<lst>(m_)) {
3253 m = ex_to<lst>(m_);
3254 } else {
3255 m = lst(m_);
3256 }
3257 ex mb = *m.begin();
3258 if (mb > _ex1) {
3259 m[0]--;
3260 return H(m, x) / x;
3261 }
3262 if (mb < _ex_1) {
3263 m[0]++;
3264 return H(m, x) / x;
3265 }
3266 m.remove_first();
3267 if (mb == _ex1) {
3268 return 1/(1-x) * H(m, x);
3269 } else if (mb == _ex_1) {
3270 return 1/(1+x) * H(m, x);
3271 } else {
3272 return H(m, x) / x;
3273 }
3274 }
3275
3276
3277 static void H_print_latex(const ex& m_, const ex& x, const print_context& c)
3278 {
3279 lst m;
3280 if (is_a<lst>(m_)) {
3281 m = ex_to<lst>(m_);
3282 } else {
3283 m = lst(m_);
3284 }
3285 c.s << "\\mbox{H}_{";
3286 lst::const_iterator itm = m.begin();
3287 (*itm).print(c);
3288 itm++;
3289 for (; itm != m.end(); itm++) {
3290 c.s << ",";
3291 (*itm).print(c);
3292 }
3293 c.s << "}(";
3294 x.print(c);
3295 c.s << ")";
3296 }
3297
3298
3299 REGISTER_FUNCTION(H,
3300 evalf_func(H_evalf).
3301 eval_func(H_eval).
3302 series_func(H_series).
3303 derivative_func(H_deriv).
3304 print_func<print_latex>(H_print_latex).
3305 do_not_evalf_params());
3306
3307
3308 // takes a parameter list for H and returns an expression with corresponding multiple polylogarithms
3309 ex convert_H_to_Li(const ex& m, const ex& x)
3310 {
3311 map_trafo_H_reduce_trailing_zeros filter;
3312 map_trafo_H_convert_to_Li filter2;
3313 if (is_a<lst>(m)) {
3314 return filter2(filter(H(m, x).hold()));
3315 } else {
3316 return filter2(filter(H(lst(m), x).hold()));
3317 }
3318 }
3319
3320
3321 //////////////////////////////////////////////////////////////////////
3322 //
3323 // Multiple zeta values zeta(x) and zeta(x,s)
3324 //
3325 // helper functions
3326 //
3327 //////////////////////////////////////////////////////////////////////
3328
3329
3330 // anonymous namespace for helper functions
3331 namespace {
3332
3333
3334 // parameters and data for [Cra] algorithm
3335 const cln::cl_N lambda = cln::cl_N("319/320");
3336 int L1;
3337 int L2;
3338 std::vector<std::vector<cln::cl_N> > f_kj;
3339 std::vector<cln::cl_N> crB;
3340 std::vector<std::vector<cln::cl_N> > crG;
3341 std::vector<cln::cl_N> crX;
3342
3343
3344 void halfcyclic_convolute(const std::vector<cln::cl_N>& a, const std::vector<cln::cl_N>& b, std::vector<cln::cl_N>& c)
3345 {
3346 const int size = a.size();
3347 for (int n=0; n<size; n++) {
3348 c[n] = 0;
3349 for (int m=0; m<=n; m++) {
3350 c[n] = c[n] + a[m]*b[n-m];
3351 }
3352 }
3353 }
3354
3355
3356 // [Cra] section 4
3357 void initcX(const std::vector<int>& s)
3358 {
3359 const int k = s.size();
3360
3361 crX.clear();
3362 crG.clear();
3363 crB.clear();
3364
3365 for (int i=0; i<=L2; i++) {
3366 crB.push_back(bernoulli(i).to_cl_N() / cln::factorial(i));
3367 }
3368
3369 int Sm = 0;
3370 int Smp1 = 0;
3371 for (int m=0; m<k-1; m++) {
3372 std::vector<cln::cl_N> crGbuf;
3373 Sm = Sm + s[m];
3374 Smp1 = Sm + s[m+1];
3375 for (int i=0; i<=L2; i++) {
3376 crGbuf.push_back(cln::factorial(i + Sm - m - 2) / cln::factorial(i + Smp1 - m - 2));
3377 }
3378 crG.push_back(crGbuf);
3379 }
3380
3381 crX = crB;
3382
3383 for (int m=0; m<k-1; m++) {
3384 std::vector<cln::cl_N> Xbuf;
3385 for (int i=0; i<=L2; i++) {
3386 Xbuf.push_back(crX[i] * crG[m][i]);
3387 }
3388 halfcyclic_convolute(Xbuf, crB, crX);
3389 }
3390 }
3391
3392
3393 // [Cra] section 4
3394 cln::cl_N crandall_Y_loop(const cln::cl_N& Sqk)
3395 {
3396 cln::cl_F one = cln::cl_float(1, cln::float_format(Digits));
3397 cln::cl_N factor = cln::expt(lambda, Sqk);
3398 cln::cl_N res = factor / Sqk * crX[0] * one;
3399 cln::cl_N resbuf;
3400 int N = 0;
3401 do {
3402 resbuf = res;
3403 factor = factor * lambda;
3404 N++;
3405 res = res + crX[N] * factor / (N+Sqk);
3406 } while ((res != resbuf) || cln::zerop(crX[N]));
3407 return res;
3408 }
3409
3410
3411 // [Cra] section 4
3412 void calc_f(int maxr)
3413 {
3414 f_kj.clear();
3415 f_kj.resize(L1);
3416
3417 cln::cl_N t0, t1, t2, t3, t4;
3418 int i, j, k;
3419 std::vector<std::vector<cln::cl_N> >::iterator it = f_kj.begin();
3420 cln::cl_F one = cln::cl_float(1, cln::float_format(Digits));
3421
3422 t0 = cln::exp(-lambda);
3423 t2 = 1;
3424 for (k=1; k<=L1; k++) {
3425 t1 = k * lambda;
3426 t2 = t0 * t2;
3427 for (j=1; j<=maxr; j++) {
3428 t3 = 1;
3429 t4 = 1;
3430 for (i=2; i<=j; i++) {
3431 t4 = t4 * (j-i+1);
3432 t3 = t1 * t3 + t4;
3433 }
3434 (*it).push_back(t2 * t3 * cln::expt(cln::cl_I(k),-j) * one);
3435 }
3436 it++;
3437 }
3438 }
3439
3440
3441 // [Cra] (3.1)
3442 cln::cl_N crandall_Z(const std::vector<int>& s)
3443 {
3444 const int j = s.size();
3445
3446 if (j == 1) {
3447 cln::cl_N t0;
3448 cln::cl_N t0buf;
3449 int q = 0;
3450 do {
3451 t0buf = t0;
3452 q++;
3453 t0 = t0 + f_kj[q+j-2][s[0]-1];
3454 } while (t0 != t0buf);
3455
3456 return t0 / cln::factorial(s[0]-1);
3457 }
3458
3459 std::vector<cln::cl_N> t(j);
3460
3461 cln::cl_N t0buf;
3462 int q = 0;
3463 do {
3464 t0buf = t[0];
3465 q++;
3466 t[j-1] = t[j-1] + 1 / cln::expt(cln::cl_I(q),s[j-1]);
3467 for (int k=j-2; k>=1; k--) {
3468 t[k] = t[k] + t[k+1] / cln::expt(cln::cl_I(q+j-1-k), s[k]);
3469 }
3470 t[0] = t[0] + t[1] * f_kj[q+j-2][s[0]-1];
3471 } while (t[0] != t0buf);
3472
3473 return t[0] / cln::factorial(s[0]-1);
3474 }
3475
3476
3477 // [Cra] (2.4)
3478 cln::cl_N zeta_do_sum_Crandall(const std::vector<int>& s)
3479 {
3480 std::vector<int> r = s;
3481 const int j = r.size();
3482
3483 // decide on maximal size of f_kj for crandall_Z
3484 if (Digits < 50) {
3485 L1 = 150;
3486 } else {
3487 L1 = Digits * 3 + j*2;
3488 }
3489
3490 // decide on maximal size of crX for crandall_Y
3491 if (Digits < 38) {
3492 L2 = 63;
3493 } else if (Digits < 86) {
3494 L2 = 127;
3495 } else if (Digits < 192) {
3496 L2 = 255;
3497 } else if (Digits < 394) {
3498 L2 = 511;
3499 } else if (Digits < 808) {
3500 L2 = 1023;
3501 } else {
3502 L2 = 2047;
3503 }
3504
3505 cln::cl_N res;
3506
3507 int maxr = 0;
3508 int S = 0;
3509 for (int i=0; i<j; i++) {
3510 S += r[i];
3511 if (r[i] > maxr) {
3512 maxr = r[i];
3513 }
3514 }
3515
3516 calc_f(maxr);
3517
3518 const cln::cl_N r0factorial = cln::factorial(r[0]-1);
3519
3520 std::vector<int> rz;
3521 int skp1buf;
3522 int Srun = S;
3523 for (int k=r.size()-1; k>0; k--) {
3524
3525 rz.insert(rz.begin(), r.back());
3526 skp1buf = rz.front();
3527 Srun -= skp1buf;
3528 r.pop_back();
3529
3530 initcX(r);
3531
3532 for (int q=0; q<skp1buf; q++) {
3533
3534 cln::cl_N pp1 = crandall_Y_loop(Srun+q-k);
3535 cln::cl_N pp2 = crandall_Z(rz);
3536
3537 rz.front()--;
3538
3539 if (q & 1) {
3540 res = res - pp1 * pp2 / cln::factorial(q);
3541 } else {
3542 res = res + pp1 * pp2 / cln::factorial(q);
3543 }
3544 }
3545 rz.front() = skp1buf;
3546 }
3547 rz.insert(rz.begin(), r.back());
3548
3549 initcX(rz);
3550
3551 res = (res + crandall_Y_loop(S-j)) / r0factorial + crandall_Z(rz);
3552
3553 return res;
3554 }
3555
3556
3557 cln::cl_N zeta_do_sum_simple(const std::vector<int>& r)
3558 {
3559 const int j = r.size();
3560
3561 // buffer for subsums
3562 std::vector<cln::cl_N> t(j);
3563 cln::cl_F one = cln::cl_float(1, cln::float_format(Digits));
3564
3565 cln::cl_N t0buf;
3566 int q = 0;
3567 do {
3568 t0buf = t[0];
3569 q++;
3570 t[j-1] = t[j-1] + one / cln::expt(cln::cl_I(q),r[j-1]);
3571 for (int k=j-2; k>=0; k--) {
3572 t[k] = t[k] + one * t[k+1] / cln::expt(cln::cl_I(q+j-1-k), r[k]);
3573 }
3574 } while (t[0] != t0buf);
3575
3576 return t[0];
3577 }
3578
3579
3580 // does Hoelder convolution. see [BBB] (7.0)
3581 cln::cl_N zeta_do_Hoelder_convolution(const std::vector<int>& m_, const std::vector<int>& s_)
3582 {
3583 // prepare parameters
3584 // holds Li arguments in [BBB] notation
3585 std::vector<int> s = s_;
3586 std::vector<int> m_p = m_;
3587 std::vector<int> m_q;
3588 // holds Li arguments in nested sums notation
3589 std::vector<cln::cl_N> s_p(s.size(), cln::cl_N(1));
3590 s_p[0] = s_p[0] * cln::cl_N("1/2");
3591 // convert notations
3592 int sig = 1;
3593 for (int i=0; i<s_.size(); i++) {
3594 if (s_[i] < 0) {
3595 sig = -sig;
3596 s_p[i] = -s_p[i];
3597 }
3598 s[i] = sig * std::abs(s[i]);
3599 }
3600 std::vector<cln::cl_N> s_q;
3601 cln::cl_N signum = 1;
3602
3603 // first term
3604 cln::cl_N res = multipleLi_do_sum(m_p, s_p);
3605
3606 // middle terms
3607 do {
3608
3609 // change parameters
3610 if (s.front() > 0) {
3611 if (m_p.front() == 1) {
3612 m_p.erase(m_p.begin());
3613 s_p.erase(s_p.begin());
3614 if (s_p.size() > 0) {
3615 s_p.front() = s_p.front() * cln::cl_N("1/2");
3616 }
3617 s.erase(s.begin());
3618 m_q.front()++;
3619 } else {
3620 m_p.front()--;
3621 m_q.insert(m_q.begin(), 1);
3622 if (s_q.size() > 0) {
3623 s_q.front() = s_q.front() * 2;
3624 }
3625 s_q.insert(s_q.begin(), cln::cl_N("1/2"));
3626 }
3627 } else {
3628 if (m_p.front() == 1) {
3629 m_p.erase(m_p.begin());
3630 cln::cl_N spbuf = s_p.front();
3631 s_p.erase(s_p.begin());
3632 if (s_p.size() > 0) {
3633 s_p.front() = s_p.front() * spbuf;
3634 }
3635 s.erase(s.begin());
3636 m_q.insert(m_q.begin(), 1);
3637 if (s_q.size() > 0) {
3638 s_q.front() = s_q.front() * 4;
3639 }
3640 s_q.insert(s_q.begin(), cln::cl_N("1/4"));
3641 signum = -signum;
3642 } else {
3643 m_p.front()--;
3644 m_q.insert(m_q.begin(), 1);
3645 if (s_q.size() > 0) {
3646 s_q.front() = s_q.front() * 2;
3647 }
3648 s_q.insert(s_q.begin(), cln::cl_N("1/2"));
3649 }
3650 }
3651
3652 // exiting the loop
3653 if (m_p.size() == 0) break;
3654
3655 res = res + signum * multipleLi_do_sum(m_p, s_p) * multipleLi_do_sum(m_q, s_q);
3656
3657 } while (true);
3658
3659 // last term
3660 res = res + signum * multipleLi_do_sum(m_q, s_q);
3661
3662 return res;
3663 }
3664
3665
3666 } // end of anonymous namespace
3667
3668
3669 //////////////////////////////////////////////////////////////////////
3670 //
3671 // Multiple zeta values zeta(x)
3672 //
3673 // GiNaC function
3674 //
3675 //////////////////////////////////////////////////////////////////////
3676
3677
3678 static ex zeta1_evalf(const ex& x)
3679 {
3680 if (is_exactly_a<lst>(x) && (x.nops()>1)) {
3681
3682 // multiple zeta value
3683 const int count = x.nops();
3684 const lst& xlst = ex_to<lst>(x);
3685 std::vector<int> r(count);
3686
3687 // check parameters and convert them
3688 lst::const_iterator it1 = xlst.begin();
3689 std::vector<int>::iterator it2 = r.begin();
3690 do {
3691 if (!(*it1).info(info_flags::posint)) {
3692 return zeta(x).hold();
3693 }
3694 *it2 = ex_to<numeric>(*it1).to_int();
3695 it1++;
3696 it2++;
3697 } while (it2 != r.end());
3698
3699 // check for divergence
3700 if (r[0] == 1) {
3701 return zeta(x).hold();
3702 }
3703
3704 // decide on summation algorithm
3705 // this is still a bit clumsy
3706 int limit = (Digits>17) ? 10 : 6;
3707 if ((r[0] < limit) || ((count > 3) && (r[1] < limit/2))) {
3708 return numeric(zeta_do_sum_Crandall(r));
3709 } else {
3710 return numeric(zeta_do_sum_simple(r));
3711 }
3712 }
3713
3714 // single zeta value
3715 if (is_exactly_a<numeric>(x) && (x != 1)) {
3716 try {
3717 return zeta(ex_to<numeric>(x));
3718 } catch (const dunno &e) { }
3719 }
3720
3721 return zeta(x).hold();
3722 }
3723
3724
3725 static ex zeta1_eval(const ex& m)
3726 {
3727 if (is_exactly_a<lst>(m)) {
3728 if (m.nops() == 1) {
3729 return zeta(m.op(0));
3730 }
3731 return zeta(m).hold();
3732 }
3733
3734 if (m.info(info_flags::numeric)) {
3735 const numeric& y = ex_to<numeric>(m);
3736 // trap integer arguments:
3737 if (y.is_integer()) {
3738 if (y.is_zero()) {
3739 return _ex_1_2;
3740 }
3741 if (y.is_equal(*_num1_p)) {
3742 return zeta(m).hold();
3743 }
3744 if (y.info(info_flags::posint)) {
3745 if (y.info(info_flags::odd)) {
3746 return zeta(m).hold();
3747 } else {
3748 return abs(bernoulli(y)) * pow(Pi, y) * pow(*_num2_p, y-(*_num1_p)) / factorial(y);
3749 }
3750 } else {
3751 if (y.info(info_flags::odd)) {
3752 return -bernoulli((*_num1_p)-y) / ((*_num1_p)-y);
3753 } else {
3754 return _ex0;
3755 }
3756 }
3757 }
3758 // zeta(float)
3759 if (y.info(info_flags::numeric) && !y.info(info_flags::crational)) {
3760 return zeta1_evalf(m);
3761 }
3762 }
3763 return zeta(m).hold();
3764 }
3765
3766
3767 static ex zeta1_deriv(const ex& m, unsigned deriv_param)
3768 {
3769 GINAC_ASSERT(deriv_param==0);
3770
3771 if (is_exactly_a<lst>(m)) {
3772 return _ex0;
3773 } else {
3774 return zetaderiv(_ex1, m);
3775 }
3776 }
3777
3778
3779 static void zeta1_print_latex(const ex& m_, const print_context& c)
3780 {
3781 c.s << "\\zeta(";
3782 if (is_a<lst>(m_)) {
3783 const lst& m = ex_to<lst>(m_);
3784 lst::const_iterator it = m.begin();
3785 (*it).print(c);
3786 it++;
3787 for (; it != m.end(); it++) {
3788 c.s << ",";
3789 (*it).print(c);
3790 }
3791 } else {
3792 m_.print(c);
3793 }
3794 c.s << ")";
3795 }
3796
3797
3798 unsigned zeta1_SERIAL::serial = function::register_new(function_options("zeta", 1).
3799 evalf_func(zeta1_evalf).
3800 eval_func(zeta1_eval).
3801 derivative_func(zeta1_deriv).
3802 print_func<print_latex>(zeta1_print_latex).
3803 do_not_evalf_params().
3804 overloaded(2));
3805
3806
3807 //////////////////////////////////////////////////////////////////////
3808 //
3809 // Alternating Euler sum zeta(x,s)
3810 //
3811 // GiNaC function
3812 //
3813 //////////////////////////////////////////////////////////////////////
3814
3815
3816 static ex zeta2_evalf(const ex& x, const ex& s)
3817 {
3818 if (is_exactly_a<lst>(x)) {
3819
3820 // alternating Euler sum
3821 const int count = x.nops();
3822 const lst& xlst = ex_to<lst>(x);
3823 const lst& slst = ex_to<lst>(s);
3824 std::vector<int> xi(count);
3825 std::vector<int> si(count);
3826
3827 // check parameters and convert them
3828 lst::const_iterator it_xread = xlst.begin();
3829 lst::const_iterator it_sread = slst.begin();
3830 std::vector<int>::iterator it_xwrite = xi.begin();
3831 std::vector<int>::iterator it_swrite = si.begin();
3832 do {
3833 if (!(*it_xread).info(info_flags::posint)) {
3834 return zeta(x, s).hold();
3835 }
3836 *it_xwrite = ex_to<numeric>(*it_xread).to_int();
3837 if (*it_sread > 0) {
3838 *it_swrite = 1;
3839 } else {
3840 *it_swrite = -1;
3841 }
3842 it_xread++;
3843 it_sread++;
3844 it_xwrite++;
3845 it_swrite++;
3846 } while (it_xwrite != xi.end());
3847
3848 // check for divergence
3849 if ((xi[0] == 1) && (si[0] == 1)) {
3850 return zeta(x, s).hold();
3851 }
3852
3853 // use Hoelder convolution
3854 return numeric(zeta_do_Hoelder_convolution(xi, si));
3855 }
3856
3857 return zeta(x, s).hold();
3858 }
3859
3860
3861 static ex zeta2_eval(const ex& m, const ex& s_)
3862 {
3863 if (is_exactly_a<lst>(s_)) {
3864 const lst& s = ex_to<lst>(s_);
3865 for (lst::const_iterator it = s.begin(); it != s.end(); it++) {
3866 if ((*it).info(info_flags::positive)) {
3867 continue;
3868 }
3869 return zeta(m, s_).hold();
3870 }
3871 return zeta(m);
3872 } else if (s_.info(info_flags::positive)) {
3873 return zeta(m);
3874 }
3875
3876 return zeta(m, s_).hold();
3877 }
3878
3879
3880 static ex zeta2_deriv(const ex& m, const ex& s, unsigned deriv_param)
3881 {
3882 GINAC_ASSERT(deriv_param==0);
3883
3884 if (is_exactly_a<lst>(m)) {
3885 return _ex0;
3886 } else {
3887 if ((is_exactly_a<lst>(s) && s.op(0).info(info_flags::positive)) || s.info(info_flags::positive)) {
3888 return zetaderiv(_ex1, m);
3889 }
3890 return _ex0;
3891 }
3892 }
3893
3894
3895 static void zeta2_print_latex(const ex& m_, const ex& s_, const print_context& c)
3896 {
3897 lst m;
3898 if (is_a<lst>(m_)) {
3899 m = ex_to<lst>(m_);
3900 } else {
3901 m = lst(m_);
3902 }
3903 lst s;
3904 if (is_a<lst>(s_)) {
3905 s = ex_to<lst>(s_);
3906 } else {
3907 s = lst(s_);
3908 }
3909 c.s << "\\zeta(";
3910 lst::const_iterator itm = m.begin();
3911 lst::const_iterator its = s.begin();
3912 if (*its < 0) {
3913 c.s << "\\overline{";
3914 (*itm).print(c);
3915 c.s << "}";
3916 } else {
3917 (*itm).print(c);
3918 }
3919 its++;
3920 itm++;
3921 for (; itm != m.end(); itm++, its++) {
3922 c.s << ",";
3923 if (*its < 0) {
3924 c.s << "\\overline{";
3925 (*itm).print(c);
3926 c.s << "}";
3927 } else {
3928 (*itm).print(c);
3929 }
3930 }
3931 c.s << ")";
3932 }
3933
3934
3935 unsigned zeta2_SERIAL::serial = function::register_new(function_options("zeta", 2).
3936 evalf_func(zeta2_evalf).
3937 eval_func(zeta2_eval).
3938 derivative_func(zeta2_deriv).
3939 print_func<print_latex>(zeta2_print_latex).
3940 do_not_evalf_params().
3941 overloaded(2));
3942
3943
3944 } // namespace GiNaC
3945

Christian Bauer">Christian Bauer
ViewVC Help
Powered by ViewVC 1.1.15