+
+ for (int r=0; r<=size; ++r) {
+ ex buffer = pow(-1, r);
+ ex p = 2;
+ bool adjustp;
+ do {
+ adjustp = false;
+ for (lst::const_iterator it = newx.begin(); it != newx.end(); ++it) {
+ if (*it == 1/p) {
+ p += (3-p)/2;
+ adjustp = true;
+ continue;
+ }
+ }
+ } while (adjustp);
+ ex q = p / (p-1);
+ lst qlstx;
+ lst qlsts;
+ for (int j=r; j>=1; --j) {
+ qlstx.append(1-newx.op(j-1));
+ if (newx.op(j-1).info(info_flags::real) && newx.op(j-1) > 1 && newx.op(j-1) <= 2) {
+ qlsts.append( s.op(j-1));
+ } else {
+ qlsts.append( -s.op(j-1));
+ }
+ }
+ if (qlstx.nops() > 0) {
+ buffer *= G_numeric(qlstx, qlsts, 1/q);
+ }
+ lst plstx;
+ lst plsts;
+ for (int j=r+1; j<=size; ++j) {
+ plstx.append(newx.op(j-1));
+ plsts.append(s.op(j-1));
+ }
+ if (plstx.nops() > 0) {
+ buffer *= G_numeric(plstx, plsts, 1/p);
+ }
+ result += buffer;
+ }
+ return result;
+ }
+
+ // do summation
+ lst newx;
+ lst m;
+ int mcount = 1;
+ ex sign = 1;
+ ex factor = y;
+ for (lst::const_iterator it = x.begin(); it != x.end(); ++it) {
+ if ((*it).is_zero()) {
+ ++mcount;
+ } else {
+ newx.append(factor / (*it));
+ factor = *it;
+ m.append(mcount);
+ mcount = 1;
+ sign = -sign;
+ }
+ }
+
+ return sign * numeric(mLi_do_summation(m, newx));
+}
+
+
+ex mLi_numeric(const lst& m, const lst& x)
+{
+ // let G_numeric do the transformation
+ lst newx;
+ lst s;
+ ex factor = 1;
+ for (lst::const_iterator itm = m.begin(), itx = x.begin(); itm != m.end(); ++itm, ++itx) {
+ for (int i = 1; i < *itm; ++i) {
+ newx.append(0);
+ s.append(1);
+ }
+ newx.append(factor / *itx);
+ factor /= *itx;
+ s.append(1);
+ }
+ return pow(-1, m.nops()) * G_numeric(newx, s, _ex1);
+}
+
+
+} // end of anonymous namespace
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Generalized multiple polylogarithm G(x, y) and G(x, s, y)
+//
+// GiNaC function
+//
+//////////////////////////////////////////////////////////////////////
+
+
+static ex G2_evalf(const ex& x_, const ex& y)
+{
+ if (!y.info(info_flags::positive)) {
+ return G(x_, y).hold();
+ }
+ lst x = is_a<lst>(x_) ? ex_to<lst>(x_) : lst(x_);
+ if (x.nops() == 0) {
+ return _ex1;
+ }
+ if (x.op(0) == y) {
+ return G(x_, y).hold();
+ }
+ lst s;
+ bool all_zero = true;
+ for (lst::const_iterator it = x.begin(); it != x.end(); ++it) {
+ if (!(*it).info(info_flags::numeric)) {
+ return G(x_, y).hold();
+ }
+ if (*it != _ex0) {
+ all_zero = false;
+ }
+ s.append(+1);
+ }
+ if (all_zero) {
+ return pow(log(y), x.nops()) / factorial(x.nops());
+ }
+ return G_numeric(x, s, y);
+}
+
+
+static ex G2_eval(const ex& x_, const ex& y)
+{
+ //TODO eval to MZV or H or S or Lin
+
+ if (!y.info(info_flags::positive)) {
+ return G(x_, y).hold();
+ }
+ lst x = is_a<lst>(x_) ? ex_to<lst>(x_) : lst(x_);
+ if (x.nops() == 0) {
+ return _ex1;
+ }
+ if (x.op(0) == y) {
+ return G(x_, y).hold();
+ }
+ lst s;
+ bool all_zero = true;
+ bool crational = true;
+ for (lst::const_iterator it = x.begin(); it != x.end(); ++it) {
+ if (!(*it).info(info_flags::numeric)) {
+ return G(x_, y).hold();
+ }
+ if (!(*it).info(info_flags::crational)) {
+ crational = false;
+ }
+ if (*it != _ex0) {
+ all_zero = false;
+ }
+ s.append(+1);
+ }
+ if (all_zero) {
+ return pow(log(y), x.nops()) / factorial(x.nops());
+ }
+ if (!y.info(info_flags::crational)) {
+ crational = false;
+ }
+ if (crational) {
+ return G(x_, y).hold();
+ }
+ return G_numeric(x, s, y);
+}
+
+
+unsigned G2_SERIAL::serial = function::register_new(function_options("G", 2).
+ evalf_func(G2_evalf).
+ eval_func(G2_eval).
+ do_not_evalf_params().
+ overloaded(2));
+//TODO
+// derivative_func(G2_deriv).
+// print_func<print_latex>(G2_print_latex).
+
+
+static ex G3_evalf(const ex& x_, const ex& s_, const ex& y)
+{
+ if (!y.info(info_flags::positive)) {
+ return G(x_, s_, y).hold();
+ }
+ lst x = is_a<lst>(x_) ? ex_to<lst>(x_) : lst(x_);
+ lst s = is_a<lst>(s_) ? ex_to<lst>(s_) : lst(s_);
+ if (x.nops() != s.nops()) {
+ return G(x_, s_, y).hold();
+ }
+ if (x.nops() == 0) {
+ return _ex1;
+ }
+ if (x.op(0) == y) {
+ return G(x_, s_, y).hold();
+ }
+ lst sn;
+ bool all_zero = true;
+ for (lst::const_iterator itx = x.begin(), its = s.begin(); itx != x.end(); ++itx, ++its) {
+ if (!(*itx).info(info_flags::numeric)) {
+ return G(x_, y).hold();
+ }
+ if (!(*its).info(info_flags::real)) {
+ return G(x_, y).hold();
+ }
+ if (*itx != _ex0) {
+ all_zero = false;
+ }
+ if (*its >= 0) {
+ sn.append(+1);
+ } else {
+ sn.append(-1);
+ }
+ }
+ if (all_zero) {
+ return pow(log(y), x.nops()) / factorial(x.nops());
+ }
+ return G_numeric(x, sn, y);
+}
+
+
+static ex G3_eval(const ex& x_, const ex& s_, const ex& y)
+{
+ //TODO eval to MZV or H or S or Lin
+
+ if (!y.info(info_flags::positive)) {
+ return G(x_, s_, y).hold();
+ }
+ lst x = is_a<lst>(x_) ? ex_to<lst>(x_) : lst(x_);
+ lst s = is_a<lst>(s_) ? ex_to<lst>(s_) : lst(s_);
+ if (x.nops() != s.nops()) {
+ return G(x_, s_, y).hold();
+ }
+ if (x.nops() == 0) {
+ return _ex1;
+ }
+ if (x.op(0) == y) {
+ return G(x_, s_, y).hold();
+ }
+ lst sn;
+ bool all_zero = true;
+ bool crational = true;
+ for (lst::const_iterator itx = x.begin(), its = s.begin(); itx != x.end(); ++itx, ++its) {
+ if (!(*itx).info(info_flags::numeric)) {
+ return G(x_, s_, y).hold();
+ }
+ if (!(*its).info(info_flags::real)) {
+ return G(x_, s_, y).hold();
+ }
+ if (!(*itx).info(info_flags::crational)) {
+ crational = false;
+ }
+ if (*itx != _ex0) {
+ all_zero = false;
+ }
+ if (*its >= 0) {
+ sn.append(+1);
+ } else {
+ sn.append(-1);
+ }
+ }
+ if (all_zero) {
+ return pow(log(y), x.nops()) / factorial(x.nops());
+ }
+ if (!y.info(info_flags::crational)) {
+ crational = false;
+ }
+ if (crational) {
+ return G(x_, s_, y).hold();
+ }
+ return G_numeric(x, sn, y);
+}
+
+
+unsigned G3_SERIAL::serial = function::register_new(function_options("G", 3).
+ evalf_func(G3_evalf).
+ eval_func(G3_eval).
+ do_not_evalf_params().
+ overloaded(2));
+//TODO
+// derivative_func(G3_deriv).
+// print_func<print_latex>(G3_print_latex).
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Classical polylogarithm and multiple polylogarithm Li(m,x)
+//
+// GiNaC function
+//
+//////////////////////////////////////////////////////////////////////
+
+
+static ex Li_evalf(const ex& m_, const ex& x_)
+{
+ // classical polylogs
+ if (m_.info(info_flags::posint)) {
+ if (x_.info(info_flags::numeric)) {
+ return Lin_numeric(ex_to<numeric>(m_).to_int(), ex_to<numeric>(x_));
+ } else {
+ // try to numerically evaluate second argument
+ ex x_val = x_.evalf();
+ if (x_val.info(info_flags::numeric)) {
+ return Lin_numeric(ex_to<numeric>(m_).to_int(), ex_to<numeric>(x_val));
+ }
+ }
+ }
+ // multiple polylogs
+ if (is_a<lst>(m_) && is_a<lst>(x_)) {
+