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