1 /** @file inifcns_nstdsums.cpp
3 * Implementation of some special functions that have a representation as nested sums.
5 * classical polylogarithm Li(n,x)
6 * multiple polylogarithm Li(lst(n_1,...,n_k),lst(x_1,...,x_k)
7 * nielsen's generalized polylogarithm S(n,p,x)
8 * harmonic polylogarithm H(lst(m_1,...,m_k),x)
9 * multiple zeta value mZeta(lst(m_1,...,m_k))
12 * - All formulae used can be looked up in the following publication:
13 * Nielsen's Generalized Polylogarithms, K.S.Kolbig, SIAM J.Math.Anal. 17 (1986), pp. 1232-1258.
14 * This document will be referenced as [Kol] throughout this source code.
15 * - Classical polylogarithms (Li) and nielsen's generalized polylogarithms (S) can be numerically
16 * evaluated in the whole complex plane except for S(n,p,-1) when p is not unit (no formula yet
17 * to tackle these points). And of course, there is still room for speed optimizations ;-).
18 * - The remaining functions can only be numerically evaluated with arguments lying in the unit sphere
19 * at the moment. Sorry. The evaluation especially for mZeta is very slow ... better not use it
21 * - The functions have no series expansion. To do it, you have to convert these functions
22 * into the appropriate objects from the nestedsums library, do the expansion and convert the
24 * - Numerical testing of this implementation has been performed by doing a comparison of results
25 * between this software and the commercial M.......... 4.1.
30 * GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
32 * This program is free software; you can redistribute it and/or modify
33 * it under the terms of the GNU General Public License as published by
34 * the Free Software Foundation; either version 2 of the License, or
35 * (at your option) any later version.
37 * This program is distributed in the hope that it will be useful,
38 * but WITHOUT ANY WARRANTY; without even the implied warranty of
39 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40 * GNU General Public License for more details.
42 * You should have received a copy of the GNU General Public License
43 * along with this program; if not, write to the Free Software
44 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
54 #include "operators.h"
55 #include "relational.h"
62 //////////////////////
63 // helper functions //
64 //////////////////////
67 // helper function for classical polylog Li
68 static cln::cl_N Li_series(int n, const cln::cl_N& x, const cln::float_format_t& prec)
70 // Note: argument must be in the unit circle
72 cln::cl_N num = cln::complex(cln::cl_float(1, prec), 0);
78 den = cln::expt(ii, n);
82 } while (acc != acc+aug);
87 // helper function for classical polylog Li
88 static cln::cl_N Li_projection(int n, const cln::cl_N& x, const cln::float_format_t& prec)
90 return Li_series(n, x, prec);
94 // helper function for classical polylog Li
95 static numeric Li_num(int n, const numeric& x)
99 return -cln::log(1-x.to_cl_N());
110 return -(1-cln::expt(cln::cl_I(2),1-n)) * cln::zeta(n);
113 // what is the desired float format?
114 // first guess: default format
115 cln::float_format_t prec = cln::default_float_format;
116 const cln::cl_N value = x.to_cl_N();
117 // second guess: the argument's format
118 if (!x.real().is_rational())
119 prec = cln::float_format(cln::the<cln::cl_F>(cln::realpart(value)));
120 else if (!x.imag().is_rational())
121 prec = cln::float_format(cln::the<cln::cl_F>(cln::imagpart(value)));
124 if (cln::abs(value) > 1) {
125 cln::cl_N result = -cln::expt(cln::log(-value),n) / cln::factorial(n);
126 // check if argument is complex. if it is real, the new polylog has to be conjugated.
127 if (cln::zerop(cln::imagpart(value))) {
129 result = result + conjugate(Li_projection(n, cln::recip(value), prec));
132 result = result - conjugate(Li_projection(n, cln::recip(value), prec));
137 result = result + Li_projection(n, cln::recip(value), prec);
140 result = result - Li_projection(n, cln::recip(value), prec);
144 for (int j=0; j<n-1; j++) {
145 add = add + (1+cln::expt(cln::cl_I(-1),n-j)) * (1-cln::expt(cln::cl_I(2),1-n+j))
146 * Li_num(n-j,1).to_cl_N() * cln::expt(cln::log(-value),j) / cln::factorial(j);
148 result = result - add;
152 return Li_projection(n, value, prec);
157 // helper function for S(n,p,x)
158 static cln::cl_N numeric_nielsen(int n, int step)
162 for (int i=1; i<n; i++) {
163 res = res + numeric_nielsen(i, step-1) / cln::cl_I(i);
173 // forward declaration needed by function C below
174 static numeric S_num(int n, int p, const numeric& x);
177 // helper function for S(n,p,x)
179 static cln::cl_N C(int n, int p)
183 for (int k=0; k<p; k++) {
184 for (int j=0; j<=(n+k-1)/2; j++) {
188 result = result - 2 * cln::expt(cln::pi(),2*j) * S_num(n-2*j,p,1).to_cl_N() / cln::factorial(2*j);
191 result = result + 2 * cln::expt(cln::pi(),2*j) * S_num(n-2*j,p,1).to_cl_N() / cln::factorial(2*j);
198 result = result + cln::factorial(n+k-1)
199 * cln::expt(cln::pi(),2*j) * S_num(n+k-2*j,p-k,1).to_cl_N()
200 / (cln::factorial(k) * cln::factorial(n-1) * cln::factorial(2*j));
203 result = result - cln::factorial(n+k-1)
204 * cln::expt(cln::pi(),2*j) * S_num(n+k-2*j,p-k,1).to_cl_N()
205 / (cln::factorial(k) * cln::factorial(n-1) * cln::factorial(2*j));
210 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()
211 / (cln::factorial(k) * cln::factorial(n-1) * cln::factorial(2*j));
214 result = result + cln::factorial(n+k-1)
215 * cln::expt(cln::pi(),2*j) * S_num(n+k-2*j,p-k,1).to_cl_N()
216 / (cln::factorial(k) * cln::factorial(n-1) * cln::factorial(2*j));
224 if (((np)/2+n) & 1) {
225 result = -result - cln::expt(cln::pi(),np) / (np * cln::factorial(n-1) * cln::factorial(p));
228 result = -result + cln::expt(cln::pi(),np) / (np * cln::factorial(n-1) * cln::factorial(p));
236 // helper function for S(n,p,x)
237 // [Kol] remark to (9.1)
238 static cln::cl_N a_k(int k)
247 for (int m=2; m<=k; m++) {
248 result = result + cln::expt(cln::cl_N(-1),m) * cln::zeta(m) * a_k(k-m);
255 // helper function for S(n,p,x)
256 // [Kol] remark to (9.1)
257 static cln::cl_N b_k(int k)
266 for (int m=2; m<=k; m++) {
267 result = result + cln::expt(cln::cl_N(-1),m) * cln::zeta(m) * b_k(k-m);
274 // helper function for S(n,p,x)
275 static cln::cl_N S_series(int n, int p, const cln::cl_N& x, const cln::float_format_t& prec)
281 cln::cl_N num = cln::expt(x,p);
282 cln::cl_N converter = cln::complex(cln::cl_float(1, prec), 0);
286 den = cln::expt(cln::cl_I(i), n);
287 aug = num / den * numeric_nielsen(i, p);
290 } while (acc != acc+aug);
296 // helper function for S(n,p,x)
297 static cln::cl_N S_projection(int n, int p, const cln::cl_N& x, const cln::float_format_t& prec)
300 if (cln::abs(cln::realpart(x)) > cln::cl_F("0.5")) {
302 cln::cl_N result = cln::expt(cln::cl_I(-1),p) * cln::expt(cln::log(x),n)
303 * cln::expt(cln::log(1-x),p) / cln::factorial(n) / cln::factorial(p);
305 for (int s=0; s<n; s++) {
307 for (int r=0; r<p; r++) {
308 res2 = res2 + cln::expt(cln::cl_I(-1),r) * cln::expt(cln::log(1-x),r)
309 * S_series(p-r,n-s,1-x,prec) / cln::factorial(r);
311 result = result + cln::expt(cln::log(x),s) * (S_num(n-s,p,1).to_cl_N() - res2) / cln::factorial(s);
317 return S_series(n, p, x, prec);
321 // helper function for S(n,p,x)
322 static numeric S_num(int n, int p, const numeric& x)
326 // [Kol] (2.22) with (2.21)
327 return cln::zeta(p+1);
332 return cln::zeta(n+1);
337 for (int nu=0; nu<n; nu++) {
338 for (int rho=0; rho<=p; rho++) {
339 result = result + b_k(n-nu-1) * b_k(p-rho) * a_k(nu+rho+1)
340 * cln::factorial(nu+rho+1) / cln::factorial(rho) / cln::factorial(nu+1);
343 result = result * cln::expt(cln::cl_I(-1),n+p-1);
350 return -(1-cln::expt(cln::cl_I(2),-n)) * cln::zeta(n+1);
352 throw std::runtime_error("don't know how to evaluate this function!");
355 // what is the desired float format?
356 // first guess: default format
357 cln::float_format_t prec = cln::default_float_format;
358 const cln::cl_N value = x.to_cl_N();
359 // second guess: the argument's format
360 if (!x.real().is_rational())
361 prec = cln::float_format(cln::the<cln::cl_F>(cln::realpart(value)));
362 else if (!x.imag().is_rational())
363 prec = cln::float_format(cln::the<cln::cl_F>(cln::imagpart(value)));
367 if (cln::realpart(value) < -0.5) {
369 cln::cl_N result = cln::expt(cln::cl_I(-1),p) * cln::expt(cln::log(value),n)
370 * cln::expt(cln::log(1-value),p) / cln::factorial(n) / cln::factorial(p);
372 for (int s=0; s<n; s++) {
374 for (int r=0; r<p; r++) {
375 res2 = res2 + cln::expt(cln::cl_I(-1),r) * cln::expt(cln::log(1-value),r)
376 * S_num(p-r,n-s,1-value).to_cl_N() / cln::factorial(r);
378 result = result + cln::expt(cln::log(value),s) * (S_num(n-s,p,1).to_cl_N() - res2) / cln::factorial(s);
385 else if (cln::abs(value) > 1) {
389 for (int s=0; s<p; s++) {
390 for (int r=0; r<=s; r++) {
391 result = result + cln::expt(cln::cl_I(-1),s) * cln::expt(cln::log(-value),r) * cln::factorial(n+s-r-1)
392 / cln::factorial(r) / cln::factorial(s-r) / cln::factorial(n-1)
393 * S_num(n+s-r,p-s,cln::recip(value)).to_cl_N();
396 result = result * cln::expt(cln::cl_I(-1),n);
399 for (int r=0; r<n; r++) {
400 res2 = res2 + cln::expt(cln::log(-value),r) * C(n-r,p) / cln::factorial(r);
402 res2 = res2 + cln::expt(cln::log(-value),n+p) / cln::factorial(n+p);
404 result = result + cln::expt(cln::cl_I(-1),p) * res2;
409 return S_projection(n, p, value, prec);
414 // helper function for multiple polylogarithm
415 static cln::cl_N numeric_zsum(int n, std::vector<cln::cl_N>& x, std::vector<cln::cl_N>& m)
421 for (int i=1; i<n; i++) {
422 std::vector<cln::cl_N>::iterator be;
423 std::vector<cln::cl_N>::iterator en;
427 std::vector<cln::cl_N> xbuf(be, en);
431 std::vector<cln::cl_N> mbuf(be, en);
432 res = res + cln::expt(x[0],i) / cln::expt(i,m[0]) * numeric_zsum(i, xbuf, mbuf);
438 // helper function for harmonic polylogarithm
439 static cln::cl_N numeric_harmonic(int n, std::vector<cln::cl_N>& m)
445 for (int i=1; i<n; i++) {
446 std::vector<cln::cl_N>::iterator be;
447 std::vector<cln::cl_N>::iterator en;
451 std::vector<cln::cl_N> mbuf(be, en);
452 res = res + cln::recip(cln::expt(i,m[0])) * numeric_harmonic(i, mbuf);
458 /////////////////////////////
459 // end of helper functions //
460 /////////////////////////////
463 // Polylogarithm and multiple polylogarithm
465 static ex Li_eval(const ex& x1, const ex& x2)
471 return Li(x1,x2).hold();
475 static ex Li_evalf(const ex& x1, const ex& x2)
477 // classical polylogs
478 if (is_a<numeric>(x1) && is_a<numeric>(x2)) {
479 return Li_num(ex_to<numeric>(x1).to_int(), ex_to<numeric>(x2));
482 else if (is_a<lst>(x1) && is_a<lst>(x2)) {
483 for (int i=0; i<x1.nops(); i++) {
484 if (!is_a<numeric>(x1.op(i)))
485 return Li(x1,x2).hold();
486 if (!is_a<numeric>(x2.op(i)))
487 return Li(x1,x2).hold();
489 return Li(x1,x2).hold();
492 cln::cl_N m_1 = ex_to<numeric>(x1.op(x1.nops()-1)).to_cl_N();
493 cln::cl_N x_1 = ex_to<numeric>(x2.op(x2.nops()-1)).to_cl_N();
494 std::vector<cln::cl_N> x;
495 std::vector<cln::cl_N> m;
496 const int nops = ex_to<numeric>(x1.nops()).to_int();
497 for (int i=nops-2; i>=0; i--) {
498 m.push_back(ex_to<numeric>(x1.op(i)).to_cl_N());
499 x.push_back(ex_to<numeric>(x2.op(i)).to_cl_N());
504 for (int i=nops; true; i++) {
506 res = res + cln::expt(x_1,i) / cln::expt(i,m_1) * numeric_zsum(i, x, m);
507 if (cln::zerop(res-resbuf))
515 return Li(x1,x2).hold();
518 static ex Li_series(const ex& x1, const ex& x2, const relational& rel, int order, unsigned options)
521 seq.push_back(expair(Li(x1,x2), 0));
522 return pseries(rel,seq);
525 REGISTER_FUNCTION(Li, eval_func(Li_eval).evalf_func(Li_evalf).do_not_evalf_params().series_func(Li_series));
528 // Nielsen's generalized polylogarithm
530 static ex S_eval(const ex& x1, const ex& x2, const ex& x3)
535 return S(x1,x2,x3).hold();
538 static ex S_evalf(const ex& x1, const ex& x2, const ex& x3)
540 if (is_a<numeric>(x1) && is_a<numeric>(x2) && is_a<numeric>(x3)) {
541 if ((x3 == -1) && (x2 != 1)) {
542 // no formula to evaluate this ... sorry
543 return S(x1,x2,x3).hold();
545 return S_num(ex_to<numeric>(x1).to_int(), ex_to<numeric>(x2).to_int(), ex_to<numeric>(x3));
547 return S(x1,x2,x3).hold();
550 static ex S_series(const ex& x1, const ex& x2, const ex& x3, const relational& rel, int order, unsigned options)
553 seq.push_back(expair(S(x1,x2,x3), 0));
554 return pseries(rel,seq);
557 REGISTER_FUNCTION(S, eval_func(S_eval).evalf_func(S_evalf).do_not_evalf_params().series_func(S_series));
560 // Harmonic polylogarithm
562 static ex H_eval(const ex& x1, const ex& x2)
564 return H(x1,x2).hold();
567 static ex H_evalf(const ex& x1, const ex& x2)
569 if (is_a<lst>(x1) && is_a<numeric>(x2)) {
570 for (int i=0; i<x1.nops(); i++) {
571 if (!is_a<numeric>(x1.op(i)))
572 return H(x1,x2).hold();
575 return H(x1,x2).hold();
578 cln::cl_N m_1 = ex_to<numeric>(x1.op(x1.nops()-1)).to_cl_N();
579 cln::cl_N x_1 = ex_to<numeric>(x2).to_cl_N();
580 std::vector<cln::cl_N> m;
581 const int nops = ex_to<numeric>(x1.nops()).to_int();
582 for (int i=nops-2; i>=0; i--) {
583 m.push_back(ex_to<numeric>(x1.op(i)).to_cl_N());
588 for (int i=nops; true; i++) {
590 res = res + cln::expt(x_1,i) / cln::expt(i,m_1) * numeric_harmonic(i, m);
591 if (cln::zerop(res-resbuf))
599 return H(x1,x2).hold();
602 static ex H_series(const ex& x1, const ex& x2, const relational& rel, int order, unsigned options)
605 seq.push_back(expair(H(x1,x2), 0));
606 return pseries(rel,seq);
609 REGISTER_FUNCTION(H, eval_func(H_eval).evalf_func(H_evalf).do_not_evalf_params().series_func(H_series));
612 // Multiple zeta value
614 static ex mZeta_eval(const ex& x1)
616 return mZeta(x1).hold();
619 static ex mZeta_evalf(const ex& x1)
622 for (int i=0; i<x1.nops(); i++) {
623 if (!is_a<numeric>(x1.op(i)))
624 return mZeta(x1).hold();
627 cln::cl_N m_1 = ex_to<numeric>(x1.op(x1.nops()-1)).to_cl_N();
628 std::vector<cln::cl_N> m;
629 const int nops = ex_to<numeric>(x1.nops()).to_int();
630 for (int i=nops-2; i>=0; i--) {
631 m.push_back(ex_to<numeric>(x1.op(i)).to_cl_N());
634 cln::float_format_t prec = cln::default_float_format;
635 cln::cl_N res = cln::complex(cln::cl_float(0, prec), 0);
637 for (int i=nops; true; i++) {
638 // to infinity and beyond ... timewise
640 res = res + cln::recip(cln::expt(i,m_1)) * numeric_harmonic(i, m);
641 if (cln::zerop(res-resbuf))
649 return mZeta(x1).hold();
652 static ex mZeta_series(const ex& x1, const relational& rel, int order, unsigned options)
655 seq.push_back(expair(mZeta(x1), 0));
656 return pseries(rel,seq);
659 REGISTER_FUNCTION(mZeta, eval_func(mZeta_eval).evalf_func(mZeta_evalf).do_not_evalf_params().series_func(mZeta_series));