GiNaC 1.8.10
inifcns_trans.cpp
Go to the documentation of this file.
1
6/*
7 * GiNaC Copyright (C) 1999-2026 Johannes Gutenberg University Mainz, Germany
8 *
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.
13 *
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.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23#include "inifcns.h"
24#include "ex.h"
25#include "constant.h"
26#include "add.h"
27#include "mul.h"
28#include "numeric.h"
29#include "power.h"
30#include "operators.h"
31#include "relational.h"
32#include "symbol.h"
33#include "pseries.h"
34#include "utils.h"
35
36#include <stdexcept>
37#include <vector>
38
39namespace GiNaC {
40
42// exponential function
44
45static ex exp_evalf(const ex & x)
46{
47 if (is_exactly_a<numeric>(x))
48 return exp(ex_to<numeric>(x));
49
50 return exp(x).hold();
51}
52
53static ex exp_eval(const ex & x)
54{
55 // exp(0) -> 1
56 if (x.is_zero()) {
57 return _ex1;
58 }
59
60 // exp(n*Pi*I/2) -> {+1|+I|-1|-I}
61 const ex TwoExOverPiI=(_ex2*x)/(Pi*I);
62 if (TwoExOverPiI.info(info_flags::integer)) {
63 const numeric z = mod(ex_to<numeric>(TwoExOverPiI),*_num4_p);
64 if (z.is_equal(*_num0_p))
65 return _ex1;
66 if (z.is_equal(*_num1_p))
67 return ex(I);
68 if (z.is_equal(*_num2_p))
69 return _ex_1;
70 if (z.is_equal(*_num3_p))
71 return ex(-I);
72 }
73
74 // exp(log(x)) -> x
76 return x.op(0);
77
78 // exp(float) -> float
80 return exp(ex_to<numeric>(x));
81
82 return exp(x).hold();
83}
84
85static ex exp_expand(const ex & arg, unsigned options)
86{
87 ex exp_arg;
89 exp_arg = arg.expand(options);
90 else
91 exp_arg=arg;
92
94 && is_exactly_a<add>(exp_arg)) {
95 exvector prodseq;
96 prodseq.reserve(exp_arg.nops());
97 for (const_iterator i = exp_arg.begin(); i != exp_arg.end(); ++i)
98 prodseq.push_back(exp(*i));
99
100 return dynallocate<mul>(prodseq).setflag(status_flags::expanded);
101 }
102
103 return exp(exp_arg).hold();
104}
105
106static ex exp_deriv(const ex & x, unsigned deriv_param)
107{
108 GINAC_ASSERT(deriv_param==0);
109
110 // d/dx exp(x) -> exp(x)
111 return exp(x);
112}
113
114static ex exp_real_part(const ex & x)
115{
117}
118
119static ex exp_imag_part(const ex & x)
120{
122}
123
124static ex exp_conjugate(const ex & x)
125{
126 // conjugate(exp(x))==exp(conjugate(x))
127 return exp(x.conjugate());
128}
129
130static ex exp_power(const ex & x, const ex & a)
131{
132 /*
133 * The power law (e^x)^a=e^(x*a) is used in two cases:
134 * a) a is an integer and x may be complex;
135 * b) both x and a are reals.
136 * Negative a is excluded to keep automatic simplifications like exp(x)/exp(x)=1.
137 */
140 return exp(x*a);
141 else if (a.info(info_flags::negative)
143 return power(exp(-x*a), _ex_1).hold();
144
145 return power(exp(x), a).hold();
146}
147
148static bool exp_info(const ex & x, unsigned inf)
149{
150 switch (inf) {
152 case info_flags::real:
153 return x.info(inf);
156 return x.info(info_flags::real);
157 default:
158 return false;
159 }
160}
161
163 evalf_func(exp_evalf).
164 info_func(exp_info).
165 expand_func(exp_expand).
166 derivative_func(exp_deriv).
167 real_part_func(exp_real_part).
168 imag_part_func(exp_imag_part).
169 conjugate_func(exp_conjugate).
170 power_func(exp_power).
171 latex_name("\\exp"));
172
174// natural logarithm
176
177static ex log_evalf(const ex & x)
178{
179 if (is_exactly_a<numeric>(x))
180 return log(ex_to<numeric>(x));
181
182 return log(x).hold();
183}
184
185static ex log_eval(const ex & x)
186{
188 if (x.is_zero()) // log(0) -> infinity
189 throw(pole_error("log_eval(): log(0)",0));
191 return (log(-x)+I*Pi);
192 if (x.is_equal(_ex1)) // log(1) -> 0
193 return _ex0;
194 if (x.is_equal(I)) // log(I) -> Pi*I/2
195 return (Pi*I*_ex1_2);
196 if (x.is_equal(-I)) // log(-I) -> -Pi*I/2
197 return (Pi*I*_ex_1_2);
198
199 // log(float) -> float
201 return log(ex_to<numeric>(x));
202 }
203
204 // log(exp(t)) -> t (if -Pi < t.imag() <= Pi):
205 if (is_ex_the_function(x, exp)) {
206 const ex &t = x.op(0);
207 if (t.info(info_flags::real))
208 return t;
209 }
210
211 return log(x).hold();
212}
213
214static ex log_deriv(const ex & x, unsigned deriv_param)
215{
216 GINAC_ASSERT(deriv_param==0);
217
218 // d/dx log(x) -> 1/x
219 return power(x, _ex_1);
220}
221
222static ex log_series(const ex &arg,
223 const relational &rel,
224 int order,
225 unsigned options)
226{
227 GINAC_ASSERT(is_a<symbol>(rel.lhs()));
228 ex arg_pt;
229 bool must_expand_arg = false;
230 // maybe substitution of rel into arg fails because of a pole
231 try {
232 arg_pt = arg.subs(rel, subs_options::no_pattern);
233 } catch (pole_error &) {
234 must_expand_arg = true;
235 }
236 // or we are at the branch point anyways
237 if (arg_pt.is_zero())
238 must_expand_arg = true;
239
240 if (arg.diff(ex_to<symbol>(rel.lhs())).is_zero()) {
241 throw do_taylor();
242 }
243
244 if (must_expand_arg) {
245 // method:
246 // This is the branch point: Series expand the argument first, then
247 // trivially factorize it to isolate that part which has constant
248 // leading coefficient in this fashion:
249 // x^n + x^(n+1) +...+ Order(x^(n+m)) -> x^n * (1 + x +...+ Order(x^m)).
250 // Return a plain n*log(x) for the x^n part and series expand the
251 // other part. Add them together and reexpand again in order to have
252 // one unnested pseries object. All this also works for negative n.
253 pseries argser; // series expansion of log's argument
254 unsigned extra_ord = 0; // extra expansion order
255 do {
256 // oops, the argument expanded to a pure Order(x^something)...
257 argser = ex_to<pseries>(arg.series(rel, order+extra_ord, options));
258 ++extra_ord;
259 } while (!argser.is_terminating() && argser.nops()==1);
260
261 const symbol &s = ex_to<symbol>(rel.lhs());
262 const ex &point = rel.rhs();
263 const int n = argser.ldegree(s);
264 epvector seq;
265 // construct what we carelessly called the n*log(x) term above
266 const ex coeff = argser.coeff(s, n);
267 // expand the log, but only if coeff is real and > 0, since otherwise
268 // it would make the branch cut run into the wrong direction
270 seq.push_back(expair(n*log(s-point)+log(coeff), _ex0));
271 else
272 seq.push_back(expair(log(coeff*pow(s-point, n)), _ex0));
273
274 if (!argser.is_terminating() || argser.nops()!=1) {
275 // in this case n more (or less) terms are needed
276 // (sadly, to generate them, we have to start from the beginning)
277 if (n == 0 && coeff == 1) {
278 ex rest = pseries(rel, epvector{expair(-1, _ex0), expair(Order(_ex1), order)}).add_series(argser);
279 ex acc = dynallocate<pseries>(rel, epvector());
280 for (int i = order-1; i>0; --i) {
281 epvector cterm { expair(i%2 ? _ex1/i : _ex_1/i, _ex0) };
282 acc = pseries(rel, std::move(cterm)).add_series(ex_to<pseries>(acc));
283 acc = (ex_to<pseries>(rest)).mul_series(ex_to<pseries>(acc));
284 }
285 return acc;
286 }
287 const ex newarg = ex_to<pseries>((arg/coeff).series(rel, order+n, options)).shift_exponents(-n).convert_to_poly(true);
288 return pseries(rel, std::move(seq)).add_series(ex_to<pseries>(log(newarg).series(rel, order, options)));
289 } else // it was a monomial
290 return pseries(rel, std::move(seq));
291 }
293 arg_pt.info(info_flags::negative)) {
294 // method:
295 // This is the branch cut: assemble the primitive series manually and
296 // then add the corresponding complex step function.
297 const symbol &s = ex_to<symbol>(rel.lhs());
298 const ex &point = rel.rhs();
299 const symbol foo;
300 const ex replarg = series(log(arg), s==foo, order).subs(foo==point, subs_options::no_pattern);
301 epvector seq;
302 if (order > 0) {
303 seq.reserve(2);
304 seq.push_back(expair(-I*csgn(arg*I)*Pi, _ex0));
305 }
306 seq.push_back(expair(Order(_ex1), order));
307 return series(replarg - I*Pi + pseries(rel, std::move(seq)), rel, order);
308 }
309 throw do_taylor(); // caught by function::series()
310}
311
312static ex log_real_part(const ex & x)
313{
315 return log(x).hold();
316 return log(abs(x));
317}
318
319static ex log_imag_part(const ex & x)
320{
322 return 0;
323 return atan2(GiNaC::imag_part(x), GiNaC::real_part(x));
324}
325
326static ex log_expand(const ex & arg, unsigned options)
327{
329 && is_exactly_a<mul>(arg) && !arg.info(info_flags::indefinite)) {
330 exvector sumseq;
331 exvector prodseq;
332 sumseq.reserve(arg.nops());
333 prodseq.reserve(arg.nops());
334 bool possign=true;
335
336 // searching for positive/negative factors
337 for (const_iterator i = arg.begin(); i != arg.end(); ++i) {
338 ex e;
340 e=i->expand(options);
341 else
342 e=*i;
344 sumseq.push_back(log(e));
345 else if (e.info(info_flags::negative)) {
346 sumseq.push_back(log(-e));
347 possign = !possign;
348 } else
349 prodseq.push_back(e);
350 }
351
352 if (sumseq.size() > 0) {
353 ex newarg;
355 newarg=((possign?_ex1:_ex_1)*mul(prodseq)).expand(options);
356 else {
357 newarg=(possign?_ex1:_ex_1)*mul(prodseq);
358 ex_to<basic>(newarg).setflag(status_flags::purely_indefinite);
359 }
360 return add(sumseq)+log(newarg);
361 } else {
363 ex_to<basic>(arg).setflag(status_flags::purely_indefinite);
364 }
365 }
366
368 return log(arg.expand(options)).hold();
369 else
370 return log(arg).hold();
371}
372
373static ex log_conjugate(const ex & x)
374{
375 // conjugate(log(x))==log(conjugate(x)) unless on the branch cut which
376 // runs along the negative real axis.
378 return log(x);
379 }
380 if (is_exactly_a<numeric>(x) &&
381 !x.imag_part().is_zero()) {
382 return log(x.conjugate());
383 }
384 return conjugate_function(log(x)).hold();
385}
386
387static bool log_info(const ex & x, unsigned inf)
388{
389 switch (inf) {
391 return x.info(inf);
392 case info_flags::real:
394 default:
395 return false;
396 }
397}
398
400 evalf_func(log_evalf).
401 info_func(log_info).
402 expand_func(log_expand).
403 derivative_func(log_deriv).
404 series_func(log_series).
405 real_part_func(log_real_part).
406 imag_part_func(log_imag_part).
407 conjugate_func(log_conjugate).
408 latex_name("\\ln"));
409
411// sine (trigonometric function)
413
414static ex sin_evalf(const ex & x)
415{
416 if (is_exactly_a<numeric>(x))
417 return sin(ex_to<numeric>(x));
418
419 return sin(x).hold();
420}
421
422static ex sin_eval(const ex & x)
423{
424 // sin(n/d*Pi) -> { all known non-nested radicals }
425 const ex SixtyExOverPi = _ex60*x/Pi;
426 ex sign = _ex1;
427 if (SixtyExOverPi.info(info_flags::integer)) {
428 numeric z = mod(ex_to<numeric>(SixtyExOverPi),*_num120_p);
429 if (z>=*_num60_p) {
430 // wrap to interval [0, Pi)
431 z -= *_num60_p;
432 sign = _ex_1;
433 }
434 if (z>*_num30_p) {
435 // wrap to interval [0, Pi/2)
436 z = *_num60_p-z;
437 }
438 if (z.is_equal(*_num0_p)) // sin(0) -> 0
439 return _ex0;
440 if (z.is_equal(*_num5_p)) // sin(Pi/12) -> sqrt(6)/4*(1-sqrt(3)/3)
441 return sign*_ex1_4*sqrt(_ex6)*(_ex1+_ex_1_3*sqrt(_ex3));
442 if (z.is_equal(*_num6_p)) // sin(Pi/10) -> sqrt(5)/4-1/4
443 return sign*(_ex1_4*sqrt(_ex5)+_ex_1_4);
444 if (z.is_equal(*_num10_p)) // sin(Pi/6) -> 1/2
445 return sign*_ex1_2;
446 if (z.is_equal(*_num15_p)) // sin(Pi/4) -> sqrt(2)/2
447 return sign*_ex1_2*sqrt(_ex2);
448 if (z.is_equal(*_num18_p)) // sin(3/10*Pi) -> sqrt(5)/4+1/4
449 return sign*(_ex1_4*sqrt(_ex5)+_ex1_4);
450 if (z.is_equal(*_num20_p)) // sin(Pi/3) -> sqrt(3)/2
451 return sign*_ex1_2*sqrt(_ex3);
452 if (z.is_equal(*_num25_p)) // sin(5/12*Pi) -> sqrt(6)/4*(1+sqrt(3)/3)
453 return sign*_ex1_4*sqrt(_ex6)*(_ex1+_ex1_3*sqrt(_ex3));
454 if (z.is_equal(*_num30_p)) // sin(Pi/2) -> 1
455 return sign;
456 }
457
458 if (is_exactly_a<function>(x)) {
459 const ex &t = x.op(0);
460
461 // sin(asin(x)) -> x
463 return t;
464
465 // sin(acos(x)) -> sqrt(1-x^2)
467 return sqrt(_ex1-power(t,_ex2));
468
469 // sin(atan(x)) -> x/sqrt(1+x^2)
471 return t*power(_ex1+power(t,_ex2),_ex_1_2);
472 }
473
474 // sin(float) -> float
476 return sin(ex_to<numeric>(x));
477
478 // sin() is odd
480 return -sin(-x);
481
482 return sin(x).hold();
483}
484
485static ex sin_deriv(const ex & x, unsigned deriv_param)
486{
487 GINAC_ASSERT(deriv_param==0);
488
489 // d/dx sin(x) -> cos(x)
490 return cos(x);
491}
492
493static ex sin_real_part(const ex & x)
494{
496}
497
498static ex sin_imag_part(const ex & x)
499{
501}
502
503static ex sin_conjugate(const ex & x)
504{
505 // conjugate(sin(x))==sin(conjugate(x))
506 return sin(x.conjugate());
507}
508
509static bool trig_info(const ex & x, unsigned inf)
510{
511 switch (inf) {
513 case info_flags::real:
514 return x.info(inf);
515 default:
516 return false;
517 }
518}
519
521 evalf_func(sin_evalf).
522 info_func(trig_info).
523 derivative_func(sin_deriv).
524 real_part_func(sin_real_part).
525 imag_part_func(sin_imag_part).
526 conjugate_func(sin_conjugate).
527 latex_name("\\sin"));
528
530// cosine (trigonometric function)
532
533static ex cos_evalf(const ex & x)
534{
535 if (is_exactly_a<numeric>(x))
536 return cos(ex_to<numeric>(x));
537
538 return cos(x).hold();
539}
540
541static ex cos_eval(const ex & x)
542{
543 // cos(n/d*Pi) -> { all known non-nested radicals }
544 const ex SixtyExOverPi = _ex60*x/Pi;
545 ex sign = _ex1;
546 if (SixtyExOverPi.info(info_flags::integer)) {
547 numeric z = mod(ex_to<numeric>(SixtyExOverPi),*_num120_p);
548 if (z>=*_num60_p) {
549 // wrap to interval [0, Pi)
550 z = *_num120_p-z;
551 }
552 if (z>=*_num30_p) {
553 // wrap to interval [0, Pi/2)
554 z = *_num60_p-z;
555 sign = _ex_1;
556 }
557 if (z.is_equal(*_num0_p)) // cos(0) -> 1
558 return sign;
559 if (z.is_equal(*_num5_p)) // cos(Pi/12) -> sqrt(6)/4*(1+sqrt(3)/3)
560 return sign*_ex1_4*sqrt(_ex6)*(_ex1+_ex1_3*sqrt(_ex3));
561 if (z.is_equal(*_num10_p)) // cos(Pi/6) -> sqrt(3)/2
562 return sign*_ex1_2*sqrt(_ex3);
563 if (z.is_equal(*_num12_p)) // cos(Pi/5) -> sqrt(5)/4+1/4
564 return sign*(_ex1_4*sqrt(_ex5)+_ex1_4);
565 if (z.is_equal(*_num15_p)) // cos(Pi/4) -> sqrt(2)/2
566 return sign*_ex1_2*sqrt(_ex2);
567 if (z.is_equal(*_num20_p)) // cos(Pi/3) -> 1/2
568 return sign*_ex1_2;
569 if (z.is_equal(*_num24_p)) // cos(2/5*Pi) -> sqrt(5)/4-1/4x
570 return sign*(_ex1_4*sqrt(_ex5)+_ex_1_4);
571 if (z.is_equal(*_num25_p)) // cos(5/12*Pi) -> sqrt(6)/4*(1-sqrt(3)/3)
572 return sign*_ex1_4*sqrt(_ex6)*(_ex1+_ex_1_3*sqrt(_ex3));
573 if (z.is_equal(*_num30_p)) // cos(Pi/2) -> 0
574 return _ex0;
575 }
576
577 if (is_exactly_a<function>(x)) {
578 const ex &t = x.op(0);
579
580 // cos(acos(x)) -> x
582 return t;
583
584 // cos(asin(x)) -> sqrt(1-x^2)
586 return sqrt(_ex1-power(t,_ex2));
587
588 // cos(atan(x)) -> 1/sqrt(1+x^2)
590 return power(_ex1+power(t,_ex2),_ex_1_2);
591 }
592
593 // cos(float) -> float
595 return cos(ex_to<numeric>(x));
596
597 // cos() is even
599 return cos(-x);
600
601 return cos(x).hold();
602}
603
604static ex cos_deriv(const ex & x, unsigned deriv_param)
605{
606 GINAC_ASSERT(deriv_param==0);
607
608 // d/dx cos(x) -> -sin(x)
609 return -sin(x);
610}
611
612static ex cos_real_part(const ex & x)
613{
615}
616
617static ex cos_imag_part(const ex & x)
618{
620}
621
622static ex cos_conjugate(const ex & x)
623{
624 // conjugate(cos(x))==cos(conjugate(x))
625 return cos(x.conjugate());
626}
627
629 info_func(trig_info).
630 evalf_func(cos_evalf).
631 derivative_func(cos_deriv).
632 real_part_func(cos_real_part).
633 imag_part_func(cos_imag_part).
634 conjugate_func(cos_conjugate).
635 latex_name("\\cos"));
636
638// tangent (trigonometric function)
640
641static ex tan_evalf(const ex & x)
642{
643 if (is_exactly_a<numeric>(x))
644 return tan(ex_to<numeric>(x));
645
646 return tan(x).hold();
647}
648
649static ex tan_eval(const ex & x)
650{
651 // tan(n/d*Pi) -> { all known non-nested radicals }
652 const ex SixtyExOverPi = _ex60*x/Pi;
653 ex sign = _ex1;
654 if (SixtyExOverPi.info(info_flags::integer)) {
655 numeric z = mod(ex_to<numeric>(SixtyExOverPi),*_num60_p);
656 if (z>=*_num60_p) {
657 // wrap to interval [0, Pi)
658 z -= *_num60_p;
659 }
660 if (z>=*_num30_p) {
661 // wrap to interval [0, Pi/2)
662 z = *_num60_p-z;
663 sign = _ex_1;
664 }
665 if (z.is_equal(*_num0_p)) // tan(0) -> 0
666 return _ex0;
667 if (z.is_equal(*_num5_p)) // tan(Pi/12) -> 2-sqrt(3)
668 return sign*(_ex2-sqrt(_ex3));
669 if (z.is_equal(*_num10_p)) // tan(Pi/6) -> sqrt(3)/3
670 return sign*_ex1_3*sqrt(_ex3);
671 if (z.is_equal(*_num15_p)) // tan(Pi/4) -> 1
672 return sign;
673 if (z.is_equal(*_num20_p)) // tan(Pi/3) -> sqrt(3)
674 return sign*sqrt(_ex3);
675 if (z.is_equal(*_num25_p)) // tan(5/12*Pi) -> 2+sqrt(3)
676 return sign*(sqrt(_ex3)+_ex2);
677 if (z.is_equal(*_num30_p)) // tan(Pi/2) -> infinity
678 throw (pole_error("tan_eval(): simple pole",1));
679 }
680
681 if (is_exactly_a<function>(x)) {
682 const ex &t = x.op(0);
683
684 // tan(atan(x)) -> x
686 return t;
687
688 // tan(asin(x)) -> x/sqrt(1+x^2)
690 return t*power(_ex1-power(t,_ex2),_ex_1_2);
691
692 // tan(acos(x)) -> sqrt(1-x^2)/x
694 return power(t,_ex_1)*sqrt(_ex1-power(t,_ex2));
695 }
696
697 // tan(float) -> float
699 return tan(ex_to<numeric>(x));
700 }
701
702 // tan() is odd
704 return -tan(-x);
705
706 return tan(x).hold();
707}
708
709static ex tan_deriv(const ex & x, unsigned deriv_param)
710{
711 GINAC_ASSERT(deriv_param==0);
712
713 // d/dx tan(x) -> 1+tan(x)^2;
714 return (_ex1+power(tan(x),_ex2));
715}
716
717static ex tan_real_part(const ex & x)
718{
719 ex a = GiNaC::real_part(x);
720 ex b = GiNaC::imag_part(x);
721 return tan(a)/(1+power(tan(a),2)*power(tan(b),2));
722}
723
724static ex tan_imag_part(const ex & x)
725{
726 ex a = GiNaC::real_part(x);
727 ex b = GiNaC::imag_part(x);
728 return tanh(b)/(1+power(tan(a),2)*power(tan(b),2));
729}
730
731static ex tan_series(const ex &x,
732 const relational &rel,
733 int order,
734 unsigned options)
735{
736 GINAC_ASSERT(is_a<symbol>(rel.lhs()));
737 // method:
738 // Taylor series where there is no pole falls back to tan_deriv.
739 // On a pole simply expand sin(x)/cos(x).
740 const ex x_pt = x.subs(rel, subs_options::no_pattern);
741 if (!(2*x_pt/Pi).info(info_flags::odd))
742 throw do_taylor(); // caught by function::series()
743 // if we got here we have to care for a simple pole
744 return (sin(x)/cos(x)).series(rel, order, options);
745}
746
747static ex tan_conjugate(const ex & x)
748{
749 // conjugate(tan(x))==tan(conjugate(x))
750 return tan(x.conjugate());
751}
752
754 evalf_func(tan_evalf).
755 info_func(trig_info).
756 derivative_func(tan_deriv).
757 series_func(tan_series).
758 real_part_func(tan_real_part).
759 imag_part_func(tan_imag_part).
760 conjugate_func(tan_conjugate).
761 latex_name("\\tan"));
762
764// inverse sine (arc sine)
766
767static ex asin_evalf(const ex & x)
768{
769 if (is_exactly_a<numeric>(x))
770 return asin(ex_to<numeric>(x));
771
772 return asin(x).hold();
773}
774
775static ex asin_eval(const ex & x)
776{
778
779 // asin(0) -> 0
780 if (x.is_zero())
781 return x;
782
783 // asin(1/2) -> Pi/6
784 if (x.is_equal(_ex1_2))
785 return numeric(1,6)*Pi;
786
787 // asin(1) -> Pi/2
788 if (x.is_equal(_ex1))
789 return _ex1_2*Pi;
790
791 // asin(-1/2) -> -Pi/6
792 if (x.is_equal(_ex_1_2))
793 return numeric(-1,6)*Pi;
794
795 // asin(-1) -> -Pi/2
796 if (x.is_equal(_ex_1))
797 return _ex_1_2*Pi;
798
799 // asin(float) -> float
801 return asin(ex_to<numeric>(x));
802
803 // asin() is odd
805 return -asin(-x);
806 }
807
808 return asin(x).hold();
809}
810
811static ex asin_deriv(const ex & x, unsigned deriv_param)
812{
813 GINAC_ASSERT(deriv_param==0);
814
815 // d/dx asin(x) -> 1/sqrt(1-x^2)
816 return power(1-power(x,_ex2),_ex_1_2);
817}
818
819static ex asin_conjugate(const ex & x)
820{
821 // conjugate(asin(x))==asin(conjugate(x)) unless on the branch cuts which
822 // run along the real axis outside the interval [-1, +1].
823 if (is_exactly_a<numeric>(x) &&
824 (!x.imag_part().is_zero() || (x > *_num_1_p && x < *_num1_p))) {
825 return asin(x.conjugate());
826 }
827 return conjugate_function(asin(x)).hold();
828}
829
830static bool asin_info(const ex & x, unsigned inf)
831{
832 switch (inf) {
834 return x.info(inf);
835 default:
836 return false;
837 }
838}
839
841 evalf_func(asin_evalf).
842 info_func(asin_info).
843 derivative_func(asin_deriv).
844 conjugate_func(asin_conjugate).
845 latex_name("\\arcsin"));
846
848// inverse cosine (arc cosine)
850
851static ex acos_evalf(const ex & x)
852{
853 if (is_exactly_a<numeric>(x))
854 return acos(ex_to<numeric>(x));
855
856 return acos(x).hold();
857}
858
859static ex acos_eval(const ex & x)
860{
862
863 // acos(1) -> 0
864 if (x.is_equal(_ex1))
865 return _ex0;
866
867 // acos(1/2) -> Pi/3
868 if (x.is_equal(_ex1_2))
869 return _ex1_3*Pi;
870
871 // acos(0) -> Pi/2
872 if (x.is_zero())
873 return _ex1_2*Pi;
874
875 // acos(-1/2) -> 2/3*Pi
876 if (x.is_equal(_ex_1_2))
877 return numeric(2,3)*Pi;
878
879 // acos(-1) -> Pi
880 if (x.is_equal(_ex_1))
881 return Pi;
882
883 // acos(float) -> float
885 return acos(ex_to<numeric>(x));
886
887 // acos(-x) -> Pi-acos(x)
889 return Pi-acos(-x);
890 }
891
892 return acos(x).hold();
893}
894
895static ex acos_deriv(const ex & x, unsigned deriv_param)
896{
897 GINAC_ASSERT(deriv_param==0);
898
899 // d/dx acos(x) -> -1/sqrt(1-x^2)
900 return -power(1-power(x,_ex2),_ex_1_2);
901}
902
903static ex acos_conjugate(const ex & x)
904{
905 // conjugate(acos(x))==acos(conjugate(x)) unless on the branch cuts which
906 // run along the real axis outside the interval [-1, +1].
907 if (is_exactly_a<numeric>(x) &&
908 (!x.imag_part().is_zero() || (x > *_num_1_p && x < *_num1_p))) {
909 return acos(x.conjugate());
910 }
911 return conjugate_function(acos(x)).hold();
912}
913
915 evalf_func(acos_evalf).
916 info_func(asin_info). // Flags of acos are shared with asin functions
917 derivative_func(acos_deriv).
918 conjugate_func(acos_conjugate).
919 latex_name("\\arccos"));
920
922// inverse tangent (arc tangent)
924
925static ex atan_evalf(const ex & x)
926{
927 if (is_exactly_a<numeric>(x))
928 return atan(ex_to<numeric>(x));
929
930 return atan(x).hold();
931}
932
933static ex atan_eval(const ex & x)
934{
936
937 // atan(0) -> 0
938 if (x.is_zero())
939 return _ex0;
940
941 // atan(1) -> Pi/4
942 if (x.is_equal(_ex1))
943 return _ex1_4*Pi;
944
945 // atan(-1) -> -Pi/4
946 if (x.is_equal(_ex_1))
947 return _ex_1_4*Pi;
948
949 if (x.is_equal(I) || x.is_equal(-I))
950 throw (pole_error("atan_eval(): logarithmic pole",0));
951
952 // atan(float) -> float
954 return atan(ex_to<numeric>(x));
955
956 // atan() is odd
958 return -atan(-x);
959 }
960
961 return atan(x).hold();
962}
963
964static ex atan_deriv(const ex & x, unsigned deriv_param)
965{
966 GINAC_ASSERT(deriv_param==0);
967
968 // d/dx atan(x) -> 1/(1+x^2)
969 return power(_ex1+power(x,_ex2), _ex_1);
970}
971
972static ex atan_series(const ex &arg,
973 const relational &rel,
974 int order,
975 unsigned options)
976{
977 GINAC_ASSERT(is_a<symbol>(rel.lhs()));
978 // method:
979 // Taylor series where there is no pole or cut falls back to atan_deriv.
980 // There are two branch cuts, one runnig from I up the imaginary axis and
981 // one running from -I down the imaginary axis. The points I and -I are
982 // poles.
983 // On the branch cuts and the poles series expand
984 // (log(1+I*x)-log(1-I*x))/(2*I)
985 // instead.
986 const ex arg_pt = arg.subs(rel, subs_options::no_pattern);
987 if (!(I*arg_pt).info(info_flags::real))
988 throw do_taylor(); // Re(x) != 0
989 if ((I*arg_pt).info(info_flags::real) && abs(I*arg_pt)<_ex1)
990 throw do_taylor(); // Re(x) == 0, but abs(x)<1
991 // care for the poles, using the defining formula for atan()...
992 if (arg_pt.is_equal(I) || arg_pt.is_equal(-I))
993 return ((log(1+I*arg)-log(1-I*arg))/(2*I)).series(rel, order, options);
995 // method:
996 // This is the branch cut: assemble the primitive series manually and
997 // then add the corresponding complex step function.
998 const symbol &s = ex_to<symbol>(rel.lhs());
999 const ex &point = rel.rhs();
1000 const symbol foo;
1001 const ex replarg = series(atan(arg), s==foo, order).subs(foo==point, subs_options::no_pattern);
1002 ex Order0correction = replarg.op(0)+csgn(arg)*Pi*_ex_1_2;
1003 if ((I*arg_pt)<_ex0)
1004 Order0correction += log((I*arg_pt+_ex_1)/(I*arg_pt+_ex1))*I*_ex_1_2;
1005 else
1006 Order0correction += log((I*arg_pt+_ex1)/(I*arg_pt+_ex_1))*I*_ex1_2;
1007 epvector seq;
1008 if (order > 0) {
1009 seq.reserve(2);
1010 seq.push_back(expair(Order0correction, _ex0));
1011 }
1012 seq.push_back(expair(Order(_ex1), order));
1013 return series(replarg - pseries(rel, std::move(seq)), rel, order);
1014 }
1015 throw do_taylor();
1016}
1017
1018static ex atan_conjugate(const ex & x)
1019{
1020 // conjugate(atan(x))==atan(conjugate(x)) unless on the branch cuts which
1021 // run along the imaginary axis outside the interval [-I, +I].
1022 if (x.info(info_flags::real))
1023 return atan(x);
1024 if (is_exactly_a<numeric>(x)) {
1025 const numeric x_re = ex_to<numeric>(x.real_part());
1026 const numeric x_im = ex_to<numeric>(x.imag_part());
1027 if (!x_re.is_zero() ||
1028 (x_im > *_num_1_p && x_im < *_num1_p))
1029 return atan(x.conjugate());
1030 }
1031 return conjugate_function(atan(x)).hold();
1032}
1033
1034static bool atan_info(const ex & x, unsigned inf)
1035{
1036 switch (inf) {
1038 case info_flags::real:
1039 return x.info(inf);
1043 return x.info(info_flags::real) && x.info(inf);
1044 default:
1045 return false;
1046 }
1047}
1048
1050 evalf_func(atan_evalf).
1051 info_func(atan_info).
1052 derivative_func(atan_deriv).
1053 series_func(atan_series).
1054 conjugate_func(atan_conjugate).
1055 latex_name("\\arctan"));
1056
1058// inverse tangent (atan2(y,x))
1060
1061static ex atan2_evalf(const ex &y, const ex &x)
1062{
1063 if (is_exactly_a<numeric>(y) && is_exactly_a<numeric>(x))
1064 return atan(ex_to<numeric>(y), ex_to<numeric>(x));
1065
1066 return atan2(y, x).hold();
1067}
1068
1069static ex atan2_eval(const ex & y, const ex & x)
1070{
1071 if (y.is_zero()) {
1072
1073 // atan2(0, 0) -> 0
1074 if (x.is_zero())
1075 return _ex0;
1076
1077 // atan2(0, x), x real and positive -> 0
1079 return _ex0;
1080
1081 // atan2(0, x), x real and negative -> Pi
1083 return Pi;
1084 }
1085
1086 if (x.is_zero()) {
1087
1088 // atan2(y, 0), y real and positive -> Pi/2
1090 return _ex1_2*Pi;
1091
1092 // atan2(y, 0), y real and negative -> -Pi/2
1094 return _ex_1_2*Pi;
1095 }
1096
1097 if (y.is_equal(x)) {
1098
1099 // atan2(y, y), y real and positive -> Pi/4
1101 return _ex1_4*Pi;
1102
1103 // atan2(y, y), y real and negative -> -3/4*Pi
1105 return numeric(-3, 4)*Pi;
1106 }
1107
1108 if (y.is_equal(-x)) {
1109
1110 // atan2(y, -y), y real and positive -> 3*Pi/4
1112 return numeric(3, 4)*Pi;
1113
1114 // atan2(y, -y), y real and negative -> -Pi/4
1116 return _ex_1_4*Pi;
1117 }
1118
1119 // atan2(float, float) -> float
1120 if (is_a<numeric>(y) && !y.info(info_flags::crational) &&
1121 is_a<numeric>(x) && !x.info(info_flags::crational))
1122 return atan(ex_to<numeric>(y), ex_to<numeric>(x));
1123
1124 // atan2(real, real) -> atan(y/x) +/- Pi
1127 return atan(y/x);
1128
1131 return atan(y/x)+Pi;
1133 return atan(y/x)-Pi;
1134 }
1135 }
1136
1137 return atan2(y, x).hold();
1138}
1139
1140static ex atan2_deriv(const ex & y, const ex & x, unsigned deriv_param)
1141{
1142 GINAC_ASSERT(deriv_param<2);
1143
1144 if (deriv_param==0) {
1145 // d/dy atan2(y,x)
1146 return x*power(power(x,_ex2)+power(y,_ex2),_ex_1);
1147 }
1148 // d/dx atan2(y,x)
1149 return -y*power(power(x,_ex2)+power(y,_ex2),_ex_1);
1150}
1151
1152static bool atan2_info(const ex & y, const ex & x, unsigned inf)
1153{
1154 switch (inf) {
1156 case info_flags::real:
1157 return y.info(inf) && x.info(inf);
1162 && y.info(inf);
1163 default:
1164 return false;
1165 }
1166}
1167
1169 evalf_func(atan2_evalf).
1170 info_func(atan2_info).
1171 evalf_func(atan2_evalf).
1172 derivative_func(atan2_deriv));
1173
1175// hyperbolic sine (trigonometric function)
1177
1178static ex sinh_evalf(const ex & x)
1179{
1180 if (is_exactly_a<numeric>(x))
1181 return sinh(ex_to<numeric>(x));
1182
1183 return sinh(x).hold();
1184}
1185
1186static ex sinh_eval(const ex & x)
1187{
1188 if (x.info(info_flags::numeric)) {
1189
1190 // sinh(0) -> 0
1191 if (x.is_zero())
1192 return _ex0;
1193
1194 // sinh(float) -> float
1196 return sinh(ex_to<numeric>(x));
1197
1198 // sinh() is odd
1200 return -sinh(-x);
1201 }
1202
1203 if ((x/Pi).info(info_flags::numeric) &&
1204 ex_to<numeric>(x/Pi).real().is_zero()) // sinh(I*x) -> I*sin(x)
1205 return I*sin(x/I);
1206
1207 if (is_exactly_a<function>(x)) {
1208 const ex &t = x.op(0);
1209
1210 // sinh(asinh(x)) -> x
1212 return t;
1213
1214 // sinh(acosh(x)) -> sqrt(x-1) * sqrt(x+1)
1216 return sqrt(t-_ex1)*sqrt(t+_ex1);
1217
1218 // sinh(atanh(x)) -> x/sqrt(1-x^2)
1220 return t*power(_ex1-power(t,_ex2),_ex_1_2);
1221 }
1222
1223 return sinh(x).hold();
1224}
1225
1226static ex sinh_deriv(const ex & x, unsigned deriv_param)
1227{
1228 GINAC_ASSERT(deriv_param==0);
1229
1230 // d/dx sinh(x) -> cosh(x)
1231 return cosh(x);
1232}
1233
1234static ex sinh_real_part(const ex & x)
1235{
1237}
1238
1239static ex sinh_imag_part(const ex & x)
1240{
1242}
1243
1244static ex sinh_conjugate(const ex & x)
1245{
1246 // conjugate(sinh(x))==sinh(conjugate(x))
1247 return sinh(x.conjugate());
1248}
1249
1251 evalf_func(sinh_evalf).
1252 info_func(atan_info). // Flags of sinh are shared with atan functions
1253 derivative_func(sinh_deriv).
1254 real_part_func(sinh_real_part).
1255 imag_part_func(sinh_imag_part).
1256 conjugate_func(sinh_conjugate).
1257 latex_name("\\sinh"));
1258
1260// hyperbolic cosine (trigonometric function)
1262
1263static ex cosh_evalf(const ex & x)
1264{
1265 if (is_exactly_a<numeric>(x))
1266 return cosh(ex_to<numeric>(x));
1267
1268 return cosh(x).hold();
1269}
1270
1271static ex cosh_eval(const ex & x)
1272{
1273 if (x.info(info_flags::numeric)) {
1274
1275 // cosh(0) -> 1
1276 if (x.is_zero())
1277 return _ex1;
1278
1279 // cosh(float) -> float
1281 return cosh(ex_to<numeric>(x));
1282
1283 // cosh() is even
1285 return cosh(-x);
1286 }
1287
1288 if ((x/Pi).info(info_flags::numeric) &&
1289 ex_to<numeric>(x/Pi).real().is_zero()) // cosh(I*x) -> cos(x)
1290 return cos(x/I);
1291
1292 if (is_exactly_a<function>(x)) {
1293 const ex &t = x.op(0);
1294
1295 // cosh(acosh(x)) -> x
1297 return t;
1298
1299 // cosh(asinh(x)) -> sqrt(1+x^2)
1301 return sqrt(_ex1+power(t,_ex2));
1302
1303 // cosh(atanh(x)) -> 1/sqrt(1-x^2)
1305 return power(_ex1-power(t,_ex2),_ex_1_2);
1306 }
1307
1308 return cosh(x).hold();
1309}
1310
1311static ex cosh_deriv(const ex & x, unsigned deriv_param)
1312{
1313 GINAC_ASSERT(deriv_param==0);
1314
1315 // d/dx cosh(x) -> sinh(x)
1316 return sinh(x);
1317}
1318
1319static ex cosh_real_part(const ex & x)
1320{
1322}
1323
1324static ex cosh_imag_part(const ex & x)
1325{
1327}
1328
1329static ex cosh_conjugate(const ex & x)
1330{
1331 // conjugate(cosh(x))==cosh(conjugate(x))
1332 return cosh(x.conjugate());
1333}
1334
1336 evalf_func(cosh_evalf).
1337 info_func(exp_info). // Flags of cosh are shared with exp functions
1338 derivative_func(cosh_deriv).
1339 real_part_func(cosh_real_part).
1340 imag_part_func(cosh_imag_part).
1341 conjugate_func(cosh_conjugate).
1342 latex_name("\\cosh"));
1343
1345// hyperbolic tangent (trigonometric function)
1347
1348static ex tanh_evalf(const ex & x)
1349{
1350 if (is_exactly_a<numeric>(x))
1351 return tanh(ex_to<numeric>(x));
1352
1353 return tanh(x).hold();
1354}
1355
1356static ex tanh_eval(const ex & x)
1357{
1358 if (x.info(info_flags::numeric)) {
1359
1360 // tanh(0) -> 0
1361 if (x.is_zero())
1362 return _ex0;
1363
1364 // tanh(float) -> float
1366 return tanh(ex_to<numeric>(x));
1367
1368 // tanh() is odd
1370 return -tanh(-x);
1371 }
1372
1373 if ((x/Pi).info(info_flags::numeric) &&
1374 ex_to<numeric>(x/Pi).real().is_zero()) // tanh(I*x) -> I*tan(x);
1375 return I*tan(x/I);
1376
1377 if (is_exactly_a<function>(x)) {
1378 const ex &t = x.op(0);
1379
1380 // tanh(atanh(x)) -> x
1382 return t;
1383
1384 // tanh(asinh(x)) -> x/sqrt(1+x^2)
1386 return t*power(_ex1+power(t,_ex2),_ex_1_2);
1387
1388 // tanh(acosh(x)) -> sqrt(x-1)*sqrt(x+1)/x
1390 return sqrt(t-_ex1)*sqrt(t+_ex1)*power(t,_ex_1);
1391 }
1392
1393 return tanh(x).hold();
1394}
1395
1396static ex tanh_deriv(const ex & x, unsigned deriv_param)
1397{
1398 GINAC_ASSERT(deriv_param==0);
1399
1400 // d/dx tanh(x) -> 1-tanh(x)^2
1401 return _ex1-power(tanh(x),_ex2);
1402}
1403
1404static ex tanh_series(const ex &x,
1405 const relational &rel,
1406 int order,
1407 unsigned options)
1408{
1409 GINAC_ASSERT(is_a<symbol>(rel.lhs()));
1410 // method:
1411 // Taylor series where there is no pole falls back to tanh_deriv.
1412 // On a pole simply expand sinh(x)/cosh(x).
1413 const ex x_pt = x.subs(rel, subs_options::no_pattern);
1414 if (!(2*I*x_pt/Pi).info(info_flags::odd))
1415 throw do_taylor(); // caught by function::series()
1416 // if we got here we have to care for a simple pole
1417 return (sinh(x)/cosh(x)).series(rel, order, options);
1418}
1419
1420static ex tanh_real_part(const ex & x)
1421{
1422 ex a = GiNaC::real_part(x);
1423 ex b = GiNaC::imag_part(x);
1424 return tanh(a)/(1+power(tanh(a),2)*power(tan(b),2));
1425}
1426
1427static ex tanh_imag_part(const ex & x)
1428{
1429 ex a = GiNaC::real_part(x);
1430 ex b = GiNaC::imag_part(x);
1431 return tan(b)/(1+power(tanh(a),2)*power(tan(b),2));
1432}
1433
1434static ex tanh_conjugate(const ex & x)
1435{
1436 // conjugate(tanh(x))==tanh(conjugate(x))
1437 return tanh(x.conjugate());
1438}
1439
1441 evalf_func(tanh_evalf).
1442 info_func(atan_info). // Flags of tanh are shared with atan functions
1443 derivative_func(tanh_deriv).
1444 series_func(tanh_series).
1445 real_part_func(tanh_real_part).
1446 imag_part_func(tanh_imag_part).
1447 conjugate_func(tanh_conjugate).
1448 latex_name("\\tanh"));
1449
1451// inverse hyperbolic sine (trigonometric function)
1453
1454static ex asinh_evalf(const ex & x)
1455{
1456 if (is_exactly_a<numeric>(x))
1457 return asinh(ex_to<numeric>(x));
1458
1459 return asinh(x).hold();
1460}
1461
1462static ex asinh_eval(const ex & x)
1463{
1464 if (x.info(info_flags::numeric)) {
1465
1466 // asinh(0) -> 0
1467 if (x.is_zero())
1468 return _ex0;
1469
1470 // asinh(float) -> float
1472 return asinh(ex_to<numeric>(x));
1473
1474 // asinh() is odd
1476 return -asinh(-x);
1477 }
1478
1479 return asinh(x).hold();
1480}
1481
1482static ex asinh_deriv(const ex & x, unsigned deriv_param)
1483{
1484 GINAC_ASSERT(deriv_param==0);
1485
1486 // d/dx asinh(x) -> 1/sqrt(1+x^2)
1487 return power(_ex1+power(x,_ex2),_ex_1_2);
1488}
1489
1490static ex asinh_conjugate(const ex & x)
1491{
1492 // conjugate(asinh(x))==asinh(conjugate(x)) unless on the branch cuts which
1493 // run along the imaginary axis outside the interval [-I, +I].
1494 if (x.info(info_flags::real))
1495 return asinh(x);
1496 if (is_exactly_a<numeric>(x)) {
1497 const numeric x_re = ex_to<numeric>(x.real_part());
1498 const numeric x_im = ex_to<numeric>(x.imag_part());
1499 if (!x_re.is_zero() ||
1500 (x_im > *_num_1_p && x_im < *_num1_p))
1501 return asinh(x.conjugate());
1502 }
1503 return conjugate_function(asinh(x)).hold();
1504}
1505
1507 evalf_func(asinh_evalf).
1508 info_func(atan_info). // Flags of asinh are shared with atan functions
1509 derivative_func(asinh_deriv).
1510 conjugate_func(asinh_conjugate));
1511
1513// inverse hyperbolic cosine (trigonometric function)
1515
1516static ex acosh_evalf(const ex & x)
1517{
1518 if (is_exactly_a<numeric>(x))
1519 return acosh(ex_to<numeric>(x));
1520
1521 return acosh(x).hold();
1522}
1523
1524static ex acosh_eval(const ex & x)
1525{
1526 if (x.info(info_flags::numeric)) {
1527
1528 // acosh(0) -> Pi*I/2
1529 if (x.is_zero())
1530 return Pi*I*numeric(1,2);
1531
1532 // acosh(1) -> 0
1533 if (x.is_equal(_ex1))
1534 return _ex0;
1535
1536 // acosh(-1) -> Pi*I
1537 if (x.is_equal(_ex_1))
1538 return Pi*I;
1539
1540 // acosh(float) -> float
1542 return acosh(ex_to<numeric>(x));
1543
1544 // acosh(-x) -> Pi*I-acosh(x)
1546 return Pi*I-acosh(-x);
1547 }
1548
1549 return acosh(x).hold();
1550}
1551
1552static ex acosh_deriv(const ex & x, unsigned deriv_param)
1553{
1554 GINAC_ASSERT(deriv_param==0);
1555
1556 // d/dx acosh(x) -> 1/(sqrt(x-1)*sqrt(x+1))
1558}
1559
1560static ex acosh_conjugate(const ex & x)
1561{
1562 // conjugate(acosh(x))==acosh(conjugate(x)) unless on the branch cut
1563 // which runs along the real axis from +1 to -inf.
1564 if (is_exactly_a<numeric>(x) &&
1565 (!x.imag_part().is_zero() || x > *_num1_p)) {
1566 return acosh(x.conjugate());
1567 }
1568 return conjugate_function(acosh(x)).hold();
1569}
1570
1572 evalf_func(acosh_evalf).
1573 info_func(asin_info). // Flags of acosh are shared with asin functions
1574 derivative_func(acosh_deriv).
1575 conjugate_func(acosh_conjugate));
1576
1578// inverse hyperbolic tangent (trigonometric function)
1580
1581static ex atanh_evalf(const ex & x)
1582{
1583 if (is_exactly_a<numeric>(x))
1584 return atanh(ex_to<numeric>(x));
1585
1586 return atanh(x).hold();
1587}
1588
1589static ex atanh_eval(const ex & x)
1590{
1591 if (x.info(info_flags::numeric)) {
1592
1593 // atanh(0) -> 0
1594 if (x.is_zero())
1595 return _ex0;
1596
1597 // atanh({+|-}1) -> throw
1598 if (x.is_equal(_ex1) || x.is_equal(_ex_1))
1599 throw (pole_error("atanh_eval(): logarithmic pole",0));
1600
1601 // atanh(float) -> float
1603 return atanh(ex_to<numeric>(x));
1604
1605 // atanh() is odd
1607 return -atanh(-x);
1608 }
1609
1610 return atanh(x).hold();
1611}
1612
1613static ex atanh_deriv(const ex & x, unsigned deriv_param)
1614{
1615 GINAC_ASSERT(deriv_param==0);
1616
1617 // d/dx atanh(x) -> 1/(1-x^2)
1618 return power(_ex1-power(x,_ex2),_ex_1);
1619}
1620
1621static ex atanh_series(const ex &arg,
1622 const relational &rel,
1623 int order,
1624 unsigned options)
1625{
1626 GINAC_ASSERT(is_a<symbol>(rel.lhs()));
1627 // method:
1628 // Taylor series where there is no pole or cut falls back to atanh_deriv.
1629 // There are two branch cuts, one runnig from 1 up the real axis and one
1630 // one running from -1 down the real axis. The points 1 and -1 are poles
1631 // On the branch cuts and the poles series expand
1632 // (log(1+x)-log(1-x))/2
1633 // instead.
1634 const ex arg_pt = arg.subs(rel, subs_options::no_pattern);
1635 if (!(arg_pt).info(info_flags::real))
1636 throw do_taylor(); // Im(x) != 0
1637 if ((arg_pt).info(info_flags::real) && abs(arg_pt)<_ex1)
1638 throw do_taylor(); // Im(x) == 0, but abs(x)<1
1639 // care for the poles, using the defining formula for atanh()...
1640 if (arg_pt.is_equal(_ex1) || arg_pt.is_equal(_ex_1))
1641 return ((log(_ex1+arg)-log(_ex1-arg))*_ex1_2).series(rel, order, options);
1642 // ...and the branch cuts (the discontinuity at the cut being just I*Pi)
1644 // method:
1645 // This is the branch cut: assemble the primitive series manually and
1646 // then add the corresponding complex step function.
1647 const symbol &s = ex_to<symbol>(rel.lhs());
1648 const ex &point = rel.rhs();
1649 const symbol foo;
1650 const ex replarg = series(atanh(arg), s==foo, order).subs(foo==point, subs_options::no_pattern);
1651 ex Order0correction = replarg.op(0)+csgn(I*arg)*Pi*I*_ex1_2;
1652 if (arg_pt<_ex0)
1653 Order0correction += log((arg_pt+_ex_1)/(arg_pt+_ex1))*_ex1_2;
1654 else
1655 Order0correction += log((arg_pt+_ex1)/(arg_pt+_ex_1))*_ex_1_2;
1656 epvector seq;
1657 if (order > 0) {
1658 seq.reserve(2);
1659 seq.push_back(expair(Order0correction, _ex0));
1660 }
1661 seq.push_back(expair(Order(_ex1), order));
1662 return series(replarg - pseries(rel, std::move(seq)), rel, order);
1663 }
1664 throw do_taylor();
1665}
1666
1667static ex atanh_conjugate(const ex & x)
1668{
1669 // conjugate(atanh(x))==atanh(conjugate(x)) unless on the branch cuts which
1670 // run along the real axis outside the interval [-1, +1].
1671 if (is_exactly_a<numeric>(x) &&
1672 (!x.imag_part().is_zero() || (x > *_num_1_p && x < *_num1_p))) {
1673 return atanh(x.conjugate());
1674 }
1675 return conjugate_function(atanh(x)).hold();
1676}
1677
1679 evalf_func(atanh_evalf).
1680 info_func(asin_info). // Flags of atanh are shared with asin functions
1681 derivative_func(atanh_deriv).
1682 series_func(atanh_series).
1683 conjugate_func(atanh_conjugate));
1684
1685
1686} // namespace GiNaC
Interface to GiNaC's sums of expressions.
#define GINAC_ASSERT(X)
Assertion macro for checking invariances.
Definition assertion.h:32
Sum of expressions.
Definition add.h:31
const basic & setflag(unsigned f) const
Set some status_flags.
Definition basic.h:287
const basic & hold() const
Stop further evaluation.
Definition basic.cpp:886
Exception class thrown by classes which provide their own series expansion to signal that ordinary Ta...
Definition function.h:667
Lightweight wrapper for GiNaC's symbolic objects.
Definition ex.h:72
const_iterator begin() const noexcept
Definition ex.h:662
ex diff(const symbol &s, unsigned nth=1) const
Compute partial derivative of an expression.
Definition ex.cpp:86
ex expand(unsigned options=0) const
Expand an expression.
Definition ex.cpp:73
bool is_equal(const ex &other) const
Definition ex.h:345
ex conjugate() const
Definition ex.h:146
const_iterator end() const noexcept
Definition ex.h:667
size_t nops() const
Definition ex.h:135
ex series(const ex &r, int order, unsigned options=0) const
Compute the truncated series expansion of an expression.
Definition pseries.cpp:1271
ex imag_part() const
Definition ex.h:148
ex subs(const exmap &m, unsigned options=0) const
Definition ex.h:841
bool info(unsigned inf) const
Definition ex.h:132
bool is_zero() const
Definition ex.h:213
ex op(size_t i) const
Definition ex.h:136
ex real_part() const
Definition ex.h:147
A pair of expressions.
Definition expair.h:37
@ expand_transcendental
expands transcendental functions like log and exp
Definition flags.h:34
@ expand_function_args
expands the arguments of functions
Definition flags.h:32
Product of expressions.
Definition mul.h:31
This class is a wrapper around CLN-numbers within the GiNaC class hierarchy.
Definition numeric.h:81
bool is_equal(const numeric &other) const
Definition numeric.cpp:1121
bool is_zero() const
True if object is zero.
Definition numeric.cpp:1128
Exception class thrown when a singularity is encountered.
Definition numeric.h:69
This class holds a two-component object, a basis and and exponent representing exponentiation.
Definition power.h:38
This class holds a extended truncated power series (positive and negative integer powers).
Definition pseries.h:35
int ldegree(const ex &s) const override
Return degree of lowest power of the series.
Definition pseries.cpp:333
ex coeff(const ex &s, int n=1) const override
Return coefficient of degree n in power series if s is the expansion variable.
Definition pseries.cpp:355
size_t nops() const override
Return the number of operands including a possible order term.
Definition pseries.cpp:294
bool is_terminating() const
Returns true if there is no order term, i.e.
Definition pseries.cpp:584
ex add_series(const pseries &other) const
Add one series object to another, producing a pseries object that represents the sum.
Definition pseries.cpp:679
This class holds a relation consisting of two expressions and a logical relation between them.
Definition relational.h:34
ex rhs() const
Definition relational.h:81
ex lhs() const
Definition relational.h:80
@ suppress_branchcut
Suppress branch cuts in series expansion.
Definition flags.h:82
@ expanded
.expand(0) has already done its job (other expand() options ignore this flag)
Definition flags.h:203
@ no_pattern
disable pattern matching
Definition flags.h:50
Basic CAS symbol.
Definition symbol.h:38
Interface to GiNaC's constant types and some special constants.
Interface to GiNaC's light-weight expression handles.
unsigned options
Definition factor.cpp:2473
size_t n
Definition factor.cpp:1431
ex x
Definition factor.cpp:1609
#define REGISTER_FUNCTION(NAME, OPT)
Definition function.h:119
#define is_ex_the_function(OBJ, FUNCNAME)
Definition function.h:764
Interface to GiNaC's initially known functions.
Interface to GiNaC's products of expressions.
Definition add.cpp:35
static ex atan_eval(const ex &x)
bool is_zero(const ex &thisex)
Definition ex.h:835
const numeric I
Imaginary unit.
Definition numeric.cpp:1432
const numeric atan(const numeric &x)
Numeric arcustangent.
Definition numeric.cpp:1507
ex real_part(const ex &thisex)
Definition ex.h:736
static ex acosh_eval(const ex &x)
const numeric * _num_1_p
Definition utils.cpp:350
static ex atanh_series(const ex &arg, const relational &rel, int order, unsigned options)
const ex _ex2
Definition utils.cpp:388
const numeric pow(const numeric &x, const numeric &y)
Definition numeric.h:250
const ex _ex_1_2
Definition utils.cpp:355
const numeric * _num6_p
Definition utils.cpp:403
static ex atanh_deriv(const ex &x, unsigned deriv_param)
static ex log_eval(const ex &x)
static ex tanh_eval(const ex &x)
const ex _ex1_2
Definition utils.cpp:380
static ex asinh_eval(const ex &x)
static ex atanh_conjugate(const ex &x)
static ex asin_evalf(const ex &x)
const numeric cosh(const numeric &x)
Numeric hyperbolic cosine (trigonometric function).
Definition numeric.cpp:1562
static ex atan_deriv(const ex &x, unsigned deriv_param)
static ex tan_eval(const ex &x)
const numeric * _num3_p
Definition utils.cpp:391
std::vector< expair > epvector
expair-vector
Definition expairseq.h:32
static ex cosh_eval(const ex &x)
const numeric mod(const numeric &a, const numeric &b)
Modulus (in positive representation).
Definition numeric.cpp:2332
static ex log_deriv(const ex &x, unsigned deriv_param)
static ex asin_deriv(const ex &x, unsigned deriv_param)
const numeric abs(const numeric &x)
Absolute value.
Definition numeric.cpp:2319
static ex sinh_conjugate(const ex &x)
const numeric asin(const numeric &x)
Numeric inverse sine (trigonometric function).
Definition numeric.cpp:1487
const numeric * _num25_p
Definition utils.cpp:447
const ex _ex1
Definition utils.cpp:384
static bool atan2_info(const ex &y, const ex &x, unsigned inf)
const numeric tanh(const numeric &x)
Numeric hyperbolic tangent (trigonometric function).
Definition numeric.cpp:1571
static ex tan_evalf(const ex &x)
int csgn(const numeric &x)
Definition numeric.h:259
const numeric acos(const numeric &x)
Numeric inverse cosine (trigonometric function).
Definition numeric.cpp:1496
static ex tan_real_part(const ex &x)
static ex atan_conjugate(const ex &x)
static bool asin_info(const ex &x, unsigned inf)
const numeric * _num24_p
Definition utils.cpp:443
static ex tan_deriv(const ex &x, unsigned deriv_param)
const numeric sqrt(const numeric &x)
Numeric square root.
Definition numeric.cpp:2479
static ex acos_conjugate(const ex &x)
const numeric * _num30_p
Definition utils.cpp:451
const ex _ex3
Definition utils.cpp:392
const numeric * _num10_p
Definition utils.cpp:419
ex series(const ex &thisex, const ex &r, int order, unsigned options=0)
Definition ex.h:796
static bool trig_info(const ex &x, unsigned inf)
const ex _ex6
Definition utils.cpp:404
const numeric sinh(const numeric &x)
Numeric hyperbolic sine (trigonometric function).
Definition numeric.cpp:1553
const numeric * _num4_p
Definition utils.cpp:395
static ex asin_eval(const ex &x)
static ex atan_evalf(const ex &x)
const numeric * _num2_p
Definition utils.cpp:387
const numeric exp(const numeric &x)
Exponential function.
Definition numeric.cpp:1438
static ex cosh_conjugate(const ex &x)
static ex atan2_eval(const ex &y, const ex &x)
static ex sinh_deriv(const ex &x, unsigned deriv_param)
static ex sin_conjugate(const ex &x)
static bool log_info(const ex &x, unsigned inf)
static ex exp_real_part(const ex &x)
static ex tanh_deriv(const ex &x, unsigned deriv_param)
static ex acosh_evalf(const ex &x)
const numeric acosh(const numeric &x)
Numeric inverse hyperbolic cosine (trigonometric function).
Definition numeric.cpp:1589
const numeric cos(const numeric &x)
Numeric cosine (trigonometric function).
Definition numeric.cpp:1469
const ex _ex_1
Definition utils.cpp:351
static ex cos_imag_part(const ex &x)
static ex atanh_evalf(const ex &x)
const numeric * _num12_p
Definition utils.cpp:427
static ex cos_conjugate(const ex &x)
static ex acosh_deriv(const ex &x, unsigned deriv_param)
static ex acos_evalf(const ex &x)
const constant Pi("Pi", PiEvalf, "\\pi", domain::positive)
Pi.
Definition constant.h:84
static ex exp_eval(const ex &x)
static ex cosh_evalf(const ex &x)
const numeric atanh(const numeric &x)
Numeric inverse hyperbolic tangent (trigonometric function).
Definition numeric.cpp:1598
static ex exp_expand(const ex &arg, unsigned options)
static ex cosh_real_part(const ex &x)
static ex atan_series(const ex &arg, const relational &rel, int order, unsigned options)
static bool exp_info(const ex &x, unsigned inf)
static ex acos_eval(const ex &x)
static ex sinh_imag_part(const ex &x)
const ex _ex5
Definition utils.cpp:400
static ex cos_real_part(const ex &x)
static ex tanh_conjugate(const ex &x)
const numeric log(const numeric &x)
Natural logarithm.
Definition numeric.cpp:1449
const numeric real(const numeric &x)
Definition numeric.h:310
const numeric sin(const numeric &x)
Numeric sine (trigonometric function).
Definition numeric.cpp:1460
static ex cos_evalf(const ex &x)
static ex atan2_evalf(const ex &y, const ex &x)
static ex atan2_deriv(const ex &y, const ex &x, unsigned deriv_param)
const numeric * _num1_p
Definition utils.cpp:383
static ex sin_evalf(const ex &x)
static ex log_real_part(const ex &x)
ex coeff(const ex &thisex, const ex &s, int n=1)
Definition ex.h:757
static ex exp_power(const ex &x, const ex &a)
static ex sin_deriv(const ex &x, unsigned deriv_param)
static ex cos_eval(const ex &x)
static ex asinh_evalf(const ex &x)
static ex sinh_eval(const ex &x)
static ex tanh_evalf(const ex &x)
const numeric * _num60_p
Definition utils.cpp:459
const ex _ex_1_4
Definition utils.cpp:363
static ex sinh_evalf(const ex &x)
static ex exp_imag_part(const ex &x)
const numeric asinh(const numeric &x)
Numeric inverse hyperbolic sine (trigonometric function).
Definition numeric.cpp:1580
static ex sin_imag_part(const ex &x)
const ex _ex60
Definition utils.cpp:460
const numeric tan(const numeric &x)
Numeric tangent (trigonometric function).
Definition numeric.cpp:1478
static ex tan_series(const ex &x, const relational &rel, int order, unsigned options)
const ex _ex1_4
Definition utils.cpp:372
static ex tan_conjugate(const ex &x)
static ex tan_imag_part(const ex &x)
static ex log_expand(const ex &arg, unsigned options)
static ex log_evalf(const ex &x)
static ex cosh_imag_part(const ex &x)
static ex exp_evalf(const ex &x)
static ex acos_deriv(const ex &x, unsigned deriv_param)
static ex log_conjugate(const ex &x)
static ex sinh_real_part(const ex &x)
const numeric * _num15_p
Definition utils.cpp:431
static ex log_series(const ex &arg, const relational &rel, int order, unsigned options)
static ex sin_eval(const ex &x)
static ex asinh_conjugate(const ex &x)
static ex asin_conjugate(const ex &x)
static ex cosh_deriv(const ex &x, unsigned deriv_param)
static ex acosh_conjugate(const ex &x)
static bool atan_info(const ex &x, unsigned inf)
const ex _ex_1_3
Definition utils.cpp:359
const ex _ex0
Definition utils.cpp:368
const numeric * _num120_p
Definition utils.cpp:463
std::vector< ex > exvector
Definition basic.h:47
static ex log_imag_part(const ex &x)
static ex tanh_series(const ex &x, const relational &rel, int order, unsigned options)
static ex tanh_real_part(const ex &x)
ex imag_part(const ex &thisex)
Definition ex.h:739
static ex tanh_imag_part(const ex &x)
static ex cos_deriv(const ex &x, unsigned deriv_param)
static ex sin_real_part(const ex &x)
static ex exp_deriv(const ex &x, unsigned deriv_param)
static ex exp_conjugate(const ex &x)
const numeric * _num20_p
Definition utils.cpp:439
static ex atanh_eval(const ex &x)
const numeric * _num18_p
Definition utils.cpp:435
const numeric * _num0_p
Definition utils.cpp:366
const numeric * _num5_p
Definition utils.cpp:399
static ex asinh_deriv(const ex &x, unsigned deriv_param)
const ex _ex1_3
Definition utils.cpp:376
ex expand(const ex &thisex, unsigned options=0)
Definition ex.h:730
Makes the interface to the underlying bignum package available.
Interface to GiNaC's overloaded operators.
Interface to GiNaC's symbolic exponentiation (basis^exponent).
Interface to class for extended truncated power series.
Interface to relations between expressions.
Interface to GiNaC's symbolic objects.
Interface to several small and furry utilities needed within GiNaC but not of any interest to the use...

This page is part of the GiNaC developer's reference. It was generated automatically by doxygen. For an introduction, see the tutorial.