+ return power(_ex1+power(x,_ex2), _ex_1);
+}
+
+static ex atan_series(const ex &arg,
+ const relational &rel,
+ int order,
+ unsigned options)
+{
+ GINAC_ASSERT(is_a<symbol>(rel.lhs()));
+ // method:
+ // Taylor series where there is no pole or cut falls back to atan_deriv.
+ // There are two branch cuts, one runnig from I up the imaginary axis and
+ // one running from -I down the imaginary axis. The points I and -I are
+ // poles.
+ // On the branch cuts and the poles series expand
+ // (log(1+I*x)-log(1-I*x))/(2*I)
+ // instead.
+ const ex arg_pt = arg.subs(rel, subs_options::no_pattern);
+ if (!(I*arg_pt).info(info_flags::real))
+ throw do_taylor(); // Re(x) != 0
+ if ((I*arg_pt).info(info_flags::real) && abs(I*arg_pt)<_ex1)
+ throw do_taylor(); // Re(x) == 0, but abs(x)<1
+ // care for the poles, using the defining formula for atan()...
+ if (arg_pt.is_equal(I) || arg_pt.is_equal(-I))
+ return ((log(1+I*arg)-log(1-I*arg))/(2*I)).series(rel, order, options);
+ if (!(options & series_options::suppress_branchcut)) {
+ // method:
+ // This is the branch cut: assemble the primitive series manually and
+ // then add the corresponding complex step function.
+ const symbol &s = ex_to<symbol>(rel.lhs());
+ const ex &point = rel.rhs();
+ const symbol foo;
+ const ex replarg = series(atan(arg), s==foo, order).subs(foo==point, subs_options::no_pattern);
+ ex Order0correction = replarg.op(0)+csgn(arg)*Pi*_ex_1_2;
+ if ((I*arg_pt)<_ex0)
+ Order0correction += log((I*arg_pt+_ex_1)/(I*arg_pt+_ex1))*I*_ex_1_2;
+ else
+ Order0correction += log((I*arg_pt+_ex1)/(I*arg_pt+_ex_1))*I*_ex1_2;
+ epvector seq;
+ seq.push_back(expair(Order0correction, _ex0));
+ seq.push_back(expair(Order(_ex1), order));
+ return series(replarg - pseries(rel, seq), rel, order);
+ }
+ throw do_taylor();
+}
+
+static ex atan_conjugate(const ex & x)
+{
+ // conjugate(atan(x))==atan(conjugate(x)) unless on the branch cuts which
+ // run along the imaginary axis outside the interval [-I, +I].
+ if (x.info(info_flags::real))
+ return atan(x);
+ if (is_exactly_a<numeric>(x)) {
+ const numeric x_re = ex_to<numeric>(x.real_part());
+ const numeric x_im = ex_to<numeric>(x.imag_part());
+ if (!x_re.is_zero() ||
+ (x_im > *_num_1_p && x_im < *_num1_p))
+ return atan(x.conjugate());
+ }
+ return conjugate_function(atan(x)).hold();