+unsigned H2_SERIAL::serial =
+ function::register_new(function_options("H").
+ eval_func(H2_eval).
+ evalf_func(H2_evalf).
+ do_not_evalf_params().
+ derivative_func(H2_deriv).
+ latex_name("\\mbox{H}").
+ overloaded(2));
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Harmonic polylogarithm H(m,s,x)
+//
+// GiNaC function
+//
+//////////////////////////////////////////////////////////////////////
+
+
+static ex H3_eval(const ex& x1, const ex& x2, const ex& x3)
+{
+ if (x3 == 0) {
+ return 0;
+ }
+ if (x3 == 1) {
+ return zeta(x1, x2);
+ }
+ if (x3.info(info_flags::numeric) && (!x3.info(info_flags::crational))) {
+ return H(x1, x2, x3).evalf();
+ }
+ return H(x1, x2, x3).hold();
+}
+
+
+static ex H3_evalf(const ex& x1, const ex& x2, const ex& x3)
+{
+ if (is_a<lst>(x1) && is_a<numeric>(x3)) {
+ for (int i=0; i<x1.nops(); i++) {
+ if (!x1.op(i).info(info_flags::posint)) {
+ return H(x1, x2, x3).hold();
+ }
+ }
+ if (x1.nops() < 1) {
+ return _ex1;
+ }
+ if (x1.nops() == 1) {
+ return x2.op(0) * Li(x1.op(0), x2.op(0)*x3).evalf();
+ }
+ cln::cl_N x = ex_to<numeric>(x3).to_cl_N();
+ if (x == 1) {
+ return zeta(x1, x2).evalf();
+ }
+
+ // choose trafo
+ if (cln::abs(x) > 1) {
+ //TODO
+ return H(x1, x2, x3).hold();
+// symbol xtemp("xtemp");
+// lst para = ex_to<lst>(x1);
+// for (int i=0; i<para.nops(); i++) {
+// para.let_op(i) = para.op(i) * x2.op(i);
+// }
+// map_trafo_H_1overx trafo;
+// ex res = trafo(H(convert_to_RV(para), xtemp));
+// map_trafo_H_convert converter;
+// res = converter(res);
+// return res.subs(xtemp==x3).evalf();
+ }
+
+// // since the x->1-x transformation produces a lot of terms, it is only
+// // efficient for argument near one.
+// if (cln::realpart(x) > 0.95) {
+// symbol xtemp("xtemp");
+// map_trafo_H_1mx trafo;
+// ex res = trafo(H(convert_to_RV(ex_to<lst>(x1)), xtemp));
+// map_trafo_H_convert converter;
+// res = converter(res);
+// return res.subs(xtemp==x2).evalf();
+// }
+
+ // no trafo -> do summation
+ int count = x1.nops();
+ std::vector<int> m(count);
+ std::vector<cln::cl_N> s(count);
+ cln::cl_N signbuf = 1;
+ for (int i=0; i<count; i++) {
+ m[i] = ex_to<numeric>(x1.op(i)).to_int();
+ signbuf = signbuf * ex_to<numeric>(x2.op(i)).to_cl_N();
+ s[i] = signbuf;
+ }
+ s[0] = s[0] * ex_to<numeric>(x3).to_cl_N();
+
+ return numeric(signbuf * multipleLi_do_sum(m, s));
+ }
+
+ return H(x1, x2, x3).hold();
+}
+
+
+static ex H3_series(const ex& x1, const ex& x2, const ex& x3, const relational& rel, int order, unsigned options)
+{
+ epvector seq;
+ seq.push_back(expair(H(x1, x2, x3), 0));
+ return pseries(rel, seq);
+}
+
+
+static ex H3_deriv(const ex& x1, const ex& x2, const ex& x3, unsigned deriv_param)
+{
+ //TODO
+
+ GINAC_ASSERT(deriv_param < 2);
+ if (deriv_param == 0) {
+ return _ex0;
+ }
+ if (is_a<lst>(x1)) {
+ lst newparameter = ex_to<lst>(x1);
+ if (x1.op(0) == 1) {
+ newparameter.remove_first();
+ return 1/(1-x2) * H(newparameter, x2);
+ } else {
+ newparameter[0]--;
+ return H(newparameter, x2).hold() / x2;
+ }
+ } else {
+ if (x1 == 1) {
+ return 1/(1-x2);
+ } else {
+ return H(x1-1, x2).hold() / x2;
+ }
+ }
+}
+
+
+unsigned H3_SERIAL::serial =
+ function::register_new(function_options("H").
+ eval_func(H3_eval).
+ evalf_func(H3_evalf).
+ do_not_evalf_params().
+ derivative_func(H3_deriv).
+ latex_name("\\mbox{H}").
+ overloaded(2));
+
+
+ex convert_H_notation(const ex& parameterlst, const ex& arg)
+{
+ if (is_a<lst>(parameterlst)) {
+ for (int i=0; i<parameterlst.nops(); i++) {
+ if (parameterlst.op(i) == 1) continue;
+ if (parameterlst.op(i) == 0) continue;
+ if (parameterlst.op(i) == -1) continue;
+ throw std::runtime_error("first parameter has to be a list containing only 0, 1 or -1!");
+ }
+ return convert_from_RV(ex_to<lst>(parameterlst), arg).eval();
+ }
+ if (parameterlst == 1) {
+ return -log(1-arg);
+ }
+ if (parameterlst == 0) {
+ return log(arg);
+ }
+ if (parameterlst == -1) {
+ return log(1+arg);
+ }
+ throw std::runtime_error("first parameter has to be a list containing only 0, 1 or -1!");
+}