1 /** @file inifcns_trans.cpp
3 * Implementation of transcendental (and trigonometric and hyperbolic)
7 * GiNaC Copyright (C) 1999-2001 Johannes Gutenberg University Mainz, Germany
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #include "relational.h"
37 #ifndef NO_NAMESPACE_GINAC
39 #endif // ndef NO_NAMESPACE_GINAC
42 // exponential function
45 static ex exp_evalf(const ex & x)
51 return exp(ex_to_numeric(x)); // -> numeric exp(numeric)
54 static ex exp_eval(const ex & x)
60 // exp(n*Pi*I/2) -> {+1|+I|-1|-I}
61 ex TwoExOverPiI=(_ex2()*x)/(Pi*I);
62 if (TwoExOverPiI.info(info_flags::integer)) {
63 numeric z=mod(ex_to_numeric(TwoExOverPiI),_num4());
64 if (z.is_equal(_num0()))
66 if (z.is_equal(_num1()))
68 if (z.is_equal(_num2()))
70 if (z.is_equal(_num3()))
74 if (is_ex_the_function(x, log))
78 if (x.info(info_flags::numeric) && !x.info(info_flags::crational))
84 static ex exp_deriv(const ex & x, unsigned deriv_param)
86 GINAC_ASSERT(deriv_param==0);
88 // d/dx exp(x) -> exp(x)
92 REGISTER_FUNCTION(exp, eval_func(exp_eval).
93 evalf_func(exp_evalf).
94 derivative_func(exp_deriv));
100 static ex log_evalf(const ex & x)
104 END_TYPECHECK(log(x))
106 return log(ex_to_numeric(x)); // -> numeric log(numeric)
109 static ex log_eval(const ex & x)
111 if (x.info(info_flags::numeric)) {
112 if (x.is_equal(_ex0())) // log(0) -> infinity
113 throw(pole_error("log_eval(): log(0)",0));
114 if (x.info(info_flags::real) && x.info(info_flags::negative))
115 return (log(-x)+I*Pi);
116 if (x.is_equal(_ex1())) // log(1) -> 0
118 if (x.is_equal(I)) // log(I) -> Pi*I/2
119 return (Pi*I*_num1_2());
120 if (x.is_equal(-I)) // log(-I) -> -Pi*I/2
121 return (Pi*I*_num_1_2());
123 if (!x.info(info_flags::crational))
126 // log(exp(t)) -> t (if -Pi < t.imag() <= Pi):
127 if (is_ex_the_function(x, exp)) {
129 if (t.info(info_flags::numeric)) {
130 numeric nt = ex_to_numeric(t);
136 return log(x).hold();
139 static ex log_deriv(const ex & x, unsigned deriv_param)
141 GINAC_ASSERT(deriv_param==0);
143 // d/dx log(x) -> 1/x
144 return power(x, _ex_1());
147 static ex log_series(const ex &arg,
148 const relational &rel,
152 GINAC_ASSERT(is_ex_exactly_of_type(rel.lhs(),symbol));
154 bool must_expand_arg = false;
155 // maybe substitution of rel into arg fails because of a pole
157 arg_pt = arg.subs(rel);
158 } catch (pole_error) {
159 must_expand_arg = true;
161 // or we are at the branch point anyways
162 if (arg_pt.is_zero())
163 must_expand_arg = true;
165 if (must_expand_arg) {
167 // This is the branch point: Series expand the argument first, then
168 // trivially factorize it to isolate that part which has constant
169 // leading coefficient in this fashion:
170 // x^n + Order(x^(n+m)) -> x^n * (1 + Order(x^m)).
171 // Return a plain n*log(x) for the x^n part and series expand the
172 // other part. Add them together and reexpand again in order to have
173 // one unnested pseries object. All this also works for negative n.
174 const pseries argser = ex_to_pseries(arg.series(rel, order, options));
175 const symbol *s = static_cast<symbol *>(rel.lhs().bp);
176 const ex point = rel.rhs();
177 const int n = argser.ldegree(*s);
179 // construct what we carelessly called the n*log(x) term above
180 ex coeff = argser.coeff(*s, n);
181 // expand the log, but only if coeff is real and > 0, since otherwise
182 // it would make the branch cut run into the wrong direction
183 if (coeff.info(info_flags::positive))
184 seq.push_back(expair(n*log(*s-point)+log(coeff), _ex0()));
186 seq.push_back(expair(log(coeff*pow(*s-point, n)), _ex0()));
187 if (!argser.is_terminating() || argser.nops()!=1) {
188 // in this case n more terms are needed
189 // (sadly, to generate them, we have to start from the beginning)
190 ex newarg = ex_to_pseries((arg/coeff).series(rel, order+n, options)).shift_exponents(-n).convert_to_poly(true);
191 return pseries(rel, seq).add_series(ex_to_pseries(log(newarg).series(rel, order, options)));
192 } else // it was a monomial
193 return pseries(rel, seq);
195 if (!(options & series_options::suppress_branchcut) &&
196 arg_pt.info(info_flags::negative)) {
198 // This is the branch cut: assemble the primitive series manually and
199 // then add the corresponding complex step function.
200 const symbol *s = static_cast<symbol *>(rel.lhs().bp);
201 const ex point = rel.rhs();
203 ex replarg = series(log(arg), *s==foo, order).subs(foo==point);
205 seq.push_back(expair(-I*csgn(arg*I)*Pi, _ex0()));
206 seq.push_back(expair(Order(_ex1()), order));
207 return series(replarg - I*Pi + pseries(rel, seq), rel, order);
209 throw do_taylor(); // caught by function::series()
212 REGISTER_FUNCTION(log, eval_func(log_eval).
213 evalf_func(log_evalf).
214 derivative_func(log_deriv).
215 series_func(log_series));
218 // sine (trigonometric function)
221 static ex sin_evalf(const ex & x)
225 END_TYPECHECK(sin(x))
227 return sin(ex_to_numeric(x)); // -> numeric sin(numeric)
230 static ex sin_eval(const ex & x)
232 // sin(n/d*Pi) -> { all known non-nested radicals }
233 ex SixtyExOverPi = _ex60()*x/Pi;
235 if (SixtyExOverPi.info(info_flags::integer)) {
236 numeric z = mod(ex_to_numeric(SixtyExOverPi),_num120());
238 // wrap to interval [0, Pi)
243 // wrap to interval [0, Pi/2)
246 if (z.is_equal(_num0())) // sin(0) -> 0
248 if (z.is_equal(_num5())) // sin(Pi/12) -> sqrt(6)/4*(1-sqrt(3)/3)
249 return sign*_ex1_4()*power(_ex6(),_ex1_2())*(_ex1()+_ex_1_3()*power(_ex3(),_ex1_2()));
250 if (z.is_equal(_num6())) // sin(Pi/10) -> sqrt(5)/4-1/4
251 return sign*(_ex1_4()*power(_ex5(),_ex1_2())+_ex_1_4());
252 if (z.is_equal(_num10())) // sin(Pi/6) -> 1/2
253 return sign*_ex1_2();
254 if (z.is_equal(_num15())) // sin(Pi/4) -> sqrt(2)/2
255 return sign*_ex1_2()*power(_ex2(),_ex1_2());
256 if (z.is_equal(_num18())) // sin(3/10*Pi) -> sqrt(5)/4+1/4
257 return sign*(_ex1_4()*power(_ex5(),_ex1_2())+_ex1_4());
258 if (z.is_equal(_num20())) // sin(Pi/3) -> sqrt(3)/2
259 return sign*_ex1_2()*power(_ex3(),_ex1_2());
260 if (z.is_equal(_num25())) // sin(5/12*Pi) -> sqrt(6)/4*(1+sqrt(3)/3)
261 return sign*_ex1_4()*power(_ex6(),_ex1_2())*(_ex1()+_ex1_3()*power(_ex3(),_ex1_2()));
262 if (z.is_equal(_num30())) // sin(Pi/2) -> 1
266 if (is_ex_exactly_of_type(x, function)) {
269 if (is_ex_the_function(x, asin))
271 // sin(acos(x)) -> sqrt(1-x^2)
272 if (is_ex_the_function(x, acos))
273 return power(_ex1()-power(t,_ex2()),_ex1_2());
274 // sin(atan(x)) -> x*(1+x^2)^(-1/2)
275 if (is_ex_the_function(x, atan))
276 return t*power(_ex1()+power(t,_ex2()),_ex_1_2());
279 // sin(float) -> float
280 if (x.info(info_flags::numeric) && !x.info(info_flags::crational))
283 return sin(x).hold();
286 static ex sin_deriv(const ex & x, unsigned deriv_param)
288 GINAC_ASSERT(deriv_param==0);
290 // d/dx sin(x) -> cos(x)
294 REGISTER_FUNCTION(sin, eval_func(sin_eval).
295 evalf_func(sin_evalf).
296 derivative_func(sin_deriv));
299 // cosine (trigonometric function)
302 static ex cos_evalf(const ex & x)
306 END_TYPECHECK(cos(x))
308 return cos(ex_to_numeric(x)); // -> numeric cos(numeric)
311 static ex cos_eval(const ex & x)
313 // cos(n/d*Pi) -> { all known non-nested radicals }
314 ex SixtyExOverPi = _ex60()*x/Pi;
316 if (SixtyExOverPi.info(info_flags::integer)) {
317 numeric z = mod(ex_to_numeric(SixtyExOverPi),_num120());
319 // wrap to interval [0, Pi)
323 // wrap to interval [0, Pi/2)
327 if (z.is_equal(_num0())) // cos(0) -> 1
329 if (z.is_equal(_num5())) // cos(Pi/12) -> sqrt(6)/4*(1+sqrt(3)/3)
330 return sign*_ex1_4()*power(_ex6(),_ex1_2())*(_ex1()+_ex1_3()*power(_ex3(),_ex1_2()));
331 if (z.is_equal(_num10())) // cos(Pi/6) -> sqrt(3)/2
332 return sign*_ex1_2()*power(_ex3(),_ex1_2());
333 if (z.is_equal(_num12())) // cos(Pi/5) -> sqrt(5)/4+1/4
334 return sign*(_ex1_4()*power(_ex5(),_ex1_2())+_ex1_4());
335 if (z.is_equal(_num15())) // cos(Pi/4) -> sqrt(2)/2
336 return sign*_ex1_2()*power(_ex2(),_ex1_2());
337 if (z.is_equal(_num20())) // cos(Pi/3) -> 1/2
338 return sign*_ex1_2();
339 if (z.is_equal(_num24())) // cos(2/5*Pi) -> sqrt(5)/4-1/4x
340 return sign*(_ex1_4()*power(_ex5(),_ex1_2())+_ex_1_4());
341 if (z.is_equal(_num25())) // cos(5/12*Pi) -> sqrt(6)/4*(1-sqrt(3)/3)
342 return sign*_ex1_4()*power(_ex6(),_ex1_2())*(_ex1()+_ex_1_3()*power(_ex3(),_ex1_2()));
343 if (z.is_equal(_num30())) // cos(Pi/2) -> 0
347 if (is_ex_exactly_of_type(x, function)) {
350 if (is_ex_the_function(x, acos))
352 // cos(asin(x)) -> (1-x^2)^(1/2)
353 if (is_ex_the_function(x, asin))
354 return power(_ex1()-power(t,_ex2()),_ex1_2());
355 // cos(atan(x)) -> (1+x^2)^(-1/2)
356 if (is_ex_the_function(x, atan))
357 return power(_ex1()+power(t,_ex2()),_ex_1_2());
360 // cos(float) -> float
361 if (x.info(info_flags::numeric) && !x.info(info_flags::crational))
364 return cos(x).hold();
367 static ex cos_deriv(const ex & x, unsigned deriv_param)
369 GINAC_ASSERT(deriv_param==0);
371 // d/dx cos(x) -> -sin(x)
372 return _ex_1()*sin(x);
375 REGISTER_FUNCTION(cos, eval_func(cos_eval).
376 evalf_func(cos_evalf).
377 derivative_func(cos_deriv));
380 // tangent (trigonometric function)
383 static ex tan_evalf(const ex & x)
387 END_TYPECHECK(tan(x)) // -> numeric tan(numeric)
389 return tan(ex_to_numeric(x));
392 static ex tan_eval(const ex & x)
394 // tan(n/d*Pi) -> { all known non-nested radicals }
395 ex SixtyExOverPi = _ex60()*x/Pi;
397 if (SixtyExOverPi.info(info_flags::integer)) {
398 numeric z = mod(ex_to_numeric(SixtyExOverPi),_num60());
400 // wrap to interval [0, Pi)
404 // wrap to interval [0, Pi/2)
408 if (z.is_equal(_num0())) // tan(0) -> 0
410 if (z.is_equal(_num5())) // tan(Pi/12) -> 2-sqrt(3)
411 return sign*(_ex2()-power(_ex3(),_ex1_2()));
412 if (z.is_equal(_num10())) // tan(Pi/6) -> sqrt(3)/3
413 return sign*_ex1_3()*power(_ex3(),_ex1_2());
414 if (z.is_equal(_num15())) // tan(Pi/4) -> 1
416 if (z.is_equal(_num20())) // tan(Pi/3) -> sqrt(3)
417 return sign*power(_ex3(),_ex1_2());
418 if (z.is_equal(_num25())) // tan(5/12*Pi) -> 2+sqrt(3)
419 return sign*(power(_ex3(),_ex1_2())+_ex2());
420 if (z.is_equal(_num30())) // tan(Pi/2) -> infinity
421 throw (pole_error("tan_eval(): simple pole",1));
424 if (is_ex_exactly_of_type(x, function)) {
427 if (is_ex_the_function(x, atan))
429 // tan(asin(x)) -> x*(1+x^2)^(-1/2)
430 if (is_ex_the_function(x, asin))
431 return t*power(_ex1()-power(t,_ex2()),_ex_1_2());
432 // tan(acos(x)) -> (1-x^2)^(1/2)/x
433 if (is_ex_the_function(x, acos))
434 return power(t,_ex_1())*power(_ex1()-power(t,_ex2()),_ex1_2());
437 // tan(float) -> float
438 if (x.info(info_flags::numeric) && !x.info(info_flags::crational)) {
442 return tan(x).hold();
445 static ex tan_deriv(const ex & x, unsigned deriv_param)
447 GINAC_ASSERT(deriv_param==0);
449 // d/dx tan(x) -> 1+tan(x)^2;
450 return (_ex1()+power(tan(x),_ex2()));
453 static ex tan_series(const ex &x,
454 const relational &rel,
458 GINAC_ASSERT(is_ex_exactly_of_type(rel.lhs(),symbol));
460 // Taylor series where there is no pole falls back to tan_deriv.
461 // On a pole simply expand sin(x)/cos(x).
462 const ex x_pt = x.subs(rel);
463 if (!(2*x_pt/Pi).info(info_flags::odd))
464 throw do_taylor(); // caught by function::series()
465 // if we got here we have to care for a simple pole
466 return (sin(x)/cos(x)).series(rel, order+2, options);
469 REGISTER_FUNCTION(tan, eval_func(tan_eval).
470 evalf_func(tan_evalf).
471 derivative_func(tan_deriv).
472 series_func(tan_series));
475 // inverse sine (arc sine)
478 static ex asin_evalf(const ex & x)
482 END_TYPECHECK(asin(x))
484 return asin(ex_to_numeric(x)); // -> numeric asin(numeric)
487 static ex asin_eval(const ex & x)
489 if (x.info(info_flags::numeric)) {
494 if (x.is_equal(_ex1_2()))
495 return numeric(1,6)*Pi;
497 if (x.is_equal(_ex1()))
499 // asin(-1/2) -> -Pi/6
500 if (x.is_equal(_ex_1_2()))
501 return numeric(-1,6)*Pi;
503 if (x.is_equal(_ex_1()))
504 return _num_1_2()*Pi;
505 // asin(float) -> float
506 if (!x.info(info_flags::crational))
507 return asin_evalf(x);
510 return asin(x).hold();
513 static ex asin_deriv(const ex & x, unsigned deriv_param)
515 GINAC_ASSERT(deriv_param==0);
517 // d/dx asin(x) -> 1/sqrt(1-x^2)
518 return power(1-power(x,_ex2()),_ex_1_2());
521 REGISTER_FUNCTION(asin, eval_func(asin_eval).
522 evalf_func(asin_evalf).
523 derivative_func(asin_deriv));
526 // inverse cosine (arc cosine)
529 static ex acos_evalf(const ex & x)
533 END_TYPECHECK(acos(x))
535 return acos(ex_to_numeric(x)); // -> numeric acos(numeric)
538 static ex acos_eval(const ex & x)
540 if (x.info(info_flags::numeric)) {
542 if (x.is_equal(_ex1()))
545 if (x.is_equal(_ex1_2()))
550 // acos(-1/2) -> 2/3*Pi
551 if (x.is_equal(_ex_1_2()))
552 return numeric(2,3)*Pi;
554 if (x.is_equal(_ex_1()))
556 // acos(float) -> float
557 if (!x.info(info_flags::crational))
558 return acos_evalf(x);
561 return acos(x).hold();
564 static ex acos_deriv(const ex & x, unsigned deriv_param)
566 GINAC_ASSERT(deriv_param==0);
568 // d/dx acos(x) -> -1/sqrt(1-x^2)
569 return _ex_1()*power(1-power(x,_ex2()),_ex_1_2());
572 REGISTER_FUNCTION(acos, eval_func(acos_eval).
573 evalf_func(acos_evalf).
574 derivative_func(acos_deriv));
577 // inverse tangent (arc tangent)
580 static ex atan_evalf(const ex & x)
584 END_TYPECHECK(atan(x))
586 return atan(ex_to_numeric(x)); // -> numeric atan(numeric)
589 static ex atan_eval(const ex & x)
591 if (x.info(info_flags::numeric)) {
593 if (x.is_equal(_ex0()))
596 if (x.is_equal(_ex1()))
599 if (x.is_equal(_ex_1()))
601 if (x.is_equal(I) || x.is_equal(-I))
602 throw (pole_error("atan_eval(): logarithmic pole",0));
603 // atan(float) -> float
604 if (!x.info(info_flags::crational))
605 return atan_evalf(x);
608 return atan(x).hold();
611 static ex atan_deriv(const ex & x, unsigned deriv_param)
613 GINAC_ASSERT(deriv_param==0);
615 // d/dx atan(x) -> 1/(1+x^2)
616 return power(_ex1()+power(x,_ex2()), _ex_1());
619 static ex atan_series(const ex &arg,
620 const relational &rel,
624 GINAC_ASSERT(is_ex_exactly_of_type(rel.lhs(),symbol));
626 // Taylor series where there is no pole or cut falls back to atan_deriv.
627 // There are two branch cuts, one runnig from I up the imaginary axis and
628 // one running from -I down the imaginary axis. The points I and -I are
630 // On the branch cuts and the poles series expand
631 // (log(1+I*x)-log(1-I*x))/(2*I)
633 const ex arg_pt = arg.subs(rel);
634 if (!(I*arg_pt).info(info_flags::real))
635 throw do_taylor(); // Re(x) != 0
636 if ((I*arg_pt).info(info_flags::real) && abs(I*arg_pt)<_ex1())
637 throw do_taylor(); // Re(x) == 0, but abs(x)<1
638 // care for the poles, using the defining formula for atan()...
639 if (arg_pt.is_equal(I) || arg_pt.is_equal(-I))
640 return ((log(1+I*arg)-log(1-I*arg))/(2*I)).series(rel, order, options);
641 if (!(options & series_options::suppress_branchcut)) {
643 // This is the branch cut: assemble the primitive series manually and
644 // then add the corresponding complex step function.
645 const symbol *s = static_cast<symbol *>(rel.lhs().bp);
646 const ex point = rel.rhs();
648 ex replarg = series(atan(arg), *s==foo, order).subs(foo==point);
649 ex Order0correction = replarg.op(0)+csgn(arg)*Pi*_ex_1_2();
650 if ((I*arg_pt)<_ex0())
651 Order0correction += log((I*arg_pt+_ex_1())/(I*arg_pt+_ex1()))*I*_ex_1_2();
653 Order0correction += log((I*arg_pt+_ex1())/(I*arg_pt+_ex_1()))*I*_ex1_2();
655 seq.push_back(expair(Order0correction, _ex0()));
656 seq.push_back(expair(Order(_ex1()), order));
657 return series(replarg - pseries(rel, seq), rel, order);
662 REGISTER_FUNCTION(atan, eval_func(atan_eval).
663 evalf_func(atan_evalf).
664 derivative_func(atan_deriv).
665 series_func(atan_series));
668 // inverse tangent (atan2(y,x))
671 static ex atan2_evalf(const ex & y, const ex & x)
676 END_TYPECHECK(atan2(y,x))
678 return atan(ex_to_numeric(y),ex_to_numeric(x)); // -> numeric atan(numeric)
681 static ex atan2_eval(const ex & y, const ex & x)
683 if (y.info(info_flags::numeric) && !y.info(info_flags::crational) &&
684 x.info(info_flags::numeric) && !x.info(info_flags::crational)) {
685 return atan2_evalf(y,x);
688 return atan2(y,x).hold();
691 static ex atan2_deriv(const ex & y, const ex & x, unsigned deriv_param)
693 GINAC_ASSERT(deriv_param<2);
695 if (deriv_param==0) {
697 return x*power(power(x,_ex2())+power(y,_ex2()),_ex_1());
700 return -y*power(power(x,_ex2())+power(y,_ex2()),_ex_1());
703 REGISTER_FUNCTION(atan2, eval_func(atan2_eval).
704 evalf_func(atan2_evalf).
705 derivative_func(atan2_deriv));
708 // hyperbolic sine (trigonometric function)
711 static ex sinh_evalf(const ex & x)
715 END_TYPECHECK(sinh(x))
717 return sinh(ex_to_numeric(x)); // -> numeric sinh(numeric)
720 static ex sinh_eval(const ex & x)
722 if (x.info(info_flags::numeric)) {
723 if (x.is_zero()) // sinh(0) -> 0
725 if (!x.info(info_flags::crational)) // sinh(float) -> float
726 return sinh_evalf(x);
729 if ((x/Pi).info(info_flags::numeric) &&
730 ex_to_numeric(x/Pi).real().is_zero()) // sinh(I*x) -> I*sin(x)
733 if (is_ex_exactly_of_type(x, function)) {
735 // sinh(asinh(x)) -> x
736 if (is_ex_the_function(x, asinh))
738 // sinh(acosh(x)) -> (x-1)^(1/2) * (x+1)^(1/2)
739 if (is_ex_the_function(x, acosh))
740 return power(t-_ex1(),_ex1_2())*power(t+_ex1(),_ex1_2());
741 // sinh(atanh(x)) -> x*(1-x^2)^(-1/2)
742 if (is_ex_the_function(x, atanh))
743 return t*power(_ex1()-power(t,_ex2()),_ex_1_2());
746 return sinh(x).hold();
749 static ex sinh_deriv(const ex & x, unsigned deriv_param)
751 GINAC_ASSERT(deriv_param==0);
753 // d/dx sinh(x) -> cosh(x)
757 REGISTER_FUNCTION(sinh, eval_func(sinh_eval).
758 evalf_func(sinh_evalf).
759 derivative_func(sinh_deriv));
762 // hyperbolic cosine (trigonometric function)
765 static ex cosh_evalf(const ex & x)
769 END_TYPECHECK(cosh(x))
771 return cosh(ex_to_numeric(x)); // -> numeric cosh(numeric)
774 static ex cosh_eval(const ex & x)
776 if (x.info(info_flags::numeric)) {
777 if (x.is_zero()) // cosh(0) -> 1
779 if (!x.info(info_flags::crational)) // cosh(float) -> float
780 return cosh_evalf(x);
783 if ((x/Pi).info(info_flags::numeric) &&
784 ex_to_numeric(x/Pi).real().is_zero()) // cosh(I*x) -> cos(x)
787 if (is_ex_exactly_of_type(x, function)) {
789 // cosh(acosh(x)) -> x
790 if (is_ex_the_function(x, acosh))
792 // cosh(asinh(x)) -> (1+x^2)^(1/2)
793 if (is_ex_the_function(x, asinh))
794 return power(_ex1()+power(t,_ex2()),_ex1_2());
795 // cosh(atanh(x)) -> (1-x^2)^(-1/2)
796 if (is_ex_the_function(x, atanh))
797 return power(_ex1()-power(t,_ex2()),_ex_1_2());
800 return cosh(x).hold();
803 static ex cosh_deriv(const ex & x, unsigned deriv_param)
805 GINAC_ASSERT(deriv_param==0);
807 // d/dx cosh(x) -> sinh(x)
811 REGISTER_FUNCTION(cosh, eval_func(cosh_eval).
812 evalf_func(cosh_evalf).
813 derivative_func(cosh_deriv));
817 // hyperbolic tangent (trigonometric function)
820 static ex tanh_evalf(const ex & x)
824 END_TYPECHECK(tanh(x))
826 return tanh(ex_to_numeric(x)); // -> numeric tanh(numeric)
829 static ex tanh_eval(const ex & x)
831 if (x.info(info_flags::numeric)) {
832 if (x.is_zero()) // tanh(0) -> 0
834 if (!x.info(info_flags::crational)) // tanh(float) -> float
835 return tanh_evalf(x);
838 if ((x/Pi).info(info_flags::numeric) &&
839 ex_to_numeric(x/Pi).real().is_zero()) // tanh(I*x) -> I*tan(x);
842 if (is_ex_exactly_of_type(x, function)) {
844 // tanh(atanh(x)) -> x
845 if (is_ex_the_function(x, atanh))
847 // tanh(asinh(x)) -> x*(1+x^2)^(-1/2)
848 if (is_ex_the_function(x, asinh))
849 return t*power(_ex1()+power(t,_ex2()),_ex_1_2());
850 // tanh(acosh(x)) -> (x-1)^(1/2)*(x+1)^(1/2)/x
851 if (is_ex_the_function(x, acosh))
852 return power(t-_ex1(),_ex1_2())*power(t+_ex1(),_ex1_2())*power(t,_ex_1());
855 return tanh(x).hold();
858 static ex tanh_deriv(const ex & x, unsigned deriv_param)
860 GINAC_ASSERT(deriv_param==0);
862 // d/dx tanh(x) -> 1-tanh(x)^2
863 return _ex1()-power(tanh(x),_ex2());
866 static ex tanh_series(const ex &x,
867 const relational &rel,
871 GINAC_ASSERT(is_ex_exactly_of_type(rel.lhs(),symbol));
873 // Taylor series where there is no pole falls back to tanh_deriv.
874 // On a pole simply expand sinh(x)/cosh(x).
875 const ex x_pt = x.subs(rel);
876 if (!(2*I*x_pt/Pi).info(info_flags::odd))
877 throw do_taylor(); // caught by function::series()
878 // if we got here we have to care for a simple pole
879 return (sinh(x)/cosh(x)).series(rel, order+2, options);
882 REGISTER_FUNCTION(tanh, eval_func(tanh_eval).
883 evalf_func(tanh_evalf).
884 derivative_func(tanh_deriv).
885 series_func(tanh_series));
888 // inverse hyperbolic sine (trigonometric function)
891 static ex asinh_evalf(const ex & x)
895 END_TYPECHECK(asinh(x))
897 return asinh(ex_to_numeric(x)); // -> numeric asinh(numeric)
900 static ex asinh_eval(const ex & x)
902 if (x.info(info_flags::numeric)) {
906 // asinh(float) -> float
907 if (!x.info(info_flags::crational))
908 return asinh_evalf(x);
911 return asinh(x).hold();
914 static ex asinh_deriv(const ex & x, unsigned deriv_param)
916 GINAC_ASSERT(deriv_param==0);
918 // d/dx asinh(x) -> 1/sqrt(1+x^2)
919 return power(_ex1()+power(x,_ex2()),_ex_1_2());
922 REGISTER_FUNCTION(asinh, eval_func(asinh_eval).
923 evalf_func(asinh_evalf).
924 derivative_func(asinh_deriv));
927 // inverse hyperbolic cosine (trigonometric function)
930 static ex acosh_evalf(const ex & x)
934 END_TYPECHECK(acosh(x))
936 return acosh(ex_to_numeric(x)); // -> numeric acosh(numeric)
939 static ex acosh_eval(const ex & x)
941 if (x.info(info_flags::numeric)) {
942 // acosh(0) -> Pi*I/2
944 return Pi*I*numeric(1,2);
946 if (x.is_equal(_ex1()))
949 if (x.is_equal(_ex_1()))
951 // acosh(float) -> float
952 if (!x.info(info_flags::crational))
953 return acosh_evalf(x);
956 return acosh(x).hold();
959 static ex acosh_deriv(const ex & x, unsigned deriv_param)
961 GINAC_ASSERT(deriv_param==0);
963 // d/dx acosh(x) -> 1/(sqrt(x-1)*sqrt(x+1))
964 return power(x+_ex_1(),_ex_1_2())*power(x+_ex1(),_ex_1_2());
967 REGISTER_FUNCTION(acosh, eval_func(acosh_eval).
968 evalf_func(acosh_evalf).
969 derivative_func(acosh_deriv));
972 // inverse hyperbolic tangent (trigonometric function)
975 static ex atanh_evalf(const ex & x)
979 END_TYPECHECK(atanh(x))
981 return atanh(ex_to_numeric(x)); // -> numeric atanh(numeric)
984 static ex atanh_eval(const ex & x)
986 if (x.info(info_flags::numeric)) {
990 // atanh({+|-}1) -> throw
991 if (x.is_equal(_ex1()) || x.is_equal(_ex_1()))
992 throw (pole_error("atanh_eval(): logarithmic pole",0));
993 // atanh(float) -> float
994 if (!x.info(info_flags::crational))
995 return atanh_evalf(x);
998 return atanh(x).hold();
1001 static ex atanh_deriv(const ex & x, unsigned deriv_param)
1003 GINAC_ASSERT(deriv_param==0);
1005 // d/dx atanh(x) -> 1/(1-x^2)
1006 return power(_ex1()-power(x,_ex2()),_ex_1());
1009 static ex atanh_series(const ex &arg,
1010 const relational &rel,
1014 GINAC_ASSERT(is_ex_exactly_of_type(rel.lhs(),symbol));
1016 // Taylor series where there is no pole or cut falls back to atanh_deriv.
1017 // There are two branch cuts, one runnig from 1 up the real axis and one
1018 // one running from -1 down the real axis. The points 1 and -1 are poles
1019 // On the branch cuts and the poles series expand
1020 // (log(1+x)-log(1-x))/2
1022 const ex arg_pt = arg.subs(rel);
1023 if (!(arg_pt).info(info_flags::real))
1024 throw do_taylor(); // Im(x) != 0
1025 if ((arg_pt).info(info_flags::real) && abs(arg_pt)<_ex1())
1026 throw do_taylor(); // Im(x) == 0, but abs(x)<1
1027 // care for the poles, using the defining formula for atanh()...
1028 if (arg_pt.is_equal(_ex1()) || arg_pt.is_equal(_ex_1()))
1029 return ((log(_ex1()+arg)-log(_ex1()-arg))*_ex1_2()).series(rel, order, options);
1030 // ...and the branch cuts (the discontinuity at the cut being just I*Pi)
1031 if (!(options & series_options::suppress_branchcut)) {
1033 // This is the branch cut: assemble the primitive series manually and
1034 // then add the corresponding complex step function.
1035 const symbol *s = static_cast<symbol *>(rel.lhs().bp);
1036 const ex point = rel.rhs();
1038 ex replarg = series(atanh(arg), *s==foo, order).subs(foo==point);
1039 ex Order0correction = replarg.op(0)+csgn(I*arg)*Pi*I*_ex1_2();
1041 Order0correction += log((arg_pt+_ex_1())/(arg_pt+_ex1()))*_ex1_2();
1043 Order0correction += log((arg_pt+_ex1())/(arg_pt+_ex_1()))*_ex_1_2();
1045 seq.push_back(expair(Order0correction, _ex0()));
1046 seq.push_back(expair(Order(_ex1()), order));
1047 return series(replarg - pseries(rel, seq), rel, order);
1052 REGISTER_FUNCTION(atanh, eval_func(atanh_eval).
1053 evalf_func(atanh_evalf).
1054 derivative_func(atanh_deriv).
1055 series_func(atanh_series));
1058 #ifndef NO_NAMESPACE_GINAC
1059 } // namespace GiNaC
1060 #endif // ndef NO_NAMESPACE_GINAC