Loading...
Searching...
No Matches
functions.cpp
1#include <symengine/visitor.h>
2#include <symengine/symengine_exception.h>
3
4namespace SymEngine
5{
6
7extern RCP<const Basic> i2;
8extern RCP<const Basic> i3;
9extern RCP<const Basic> i5;
10extern RCP<const Basic> im2;
11extern RCP<const Basic> im3;
12extern RCP<const Basic> im5;
13
14RCP<const Basic> sqrt(RCP<const Basic> &arg)
15{
16 return pow(arg, div(one, i2));
17}
18RCP<const Basic> cbrt(RCP<const Basic> &arg)
19{
20 return pow(arg, div(one, i3));
21}
22
23extern RCP<const Basic> sq3;
24extern RCP<const Basic> sq2;
25extern RCP<const Basic> sq5;
26
27extern RCP<const Basic> C0;
28extern RCP<const Basic> C1;
29extern RCP<const Basic> C2;
30extern RCP<const Basic> C3;
31extern RCP<const Basic> C4;
32extern RCP<const Basic> C5;
33extern RCP<const Basic> C6;
34
35extern RCP<const Basic> mC0;
36extern RCP<const Basic> mC1;
37extern RCP<const Basic> mC2;
38extern RCP<const Basic> mC3;
39extern RCP<const Basic> mC4;
40extern RCP<const Basic> mC5;
41extern RCP<const Basic> mC6;
42
43// sin_table()[n] represents the value of sin(pi*n/12) for n = 0..23
44static const RCP<const Basic> *sin_table()
45{
46 static const RCP<const Basic> table[]
47 = {zero, C0, C1, C2, C3, C4, one, C4, C3, C2, C1, C0,
48 zero, mC0, mC1, mC2, mC3, mC4, minus_one, mC4, mC3, mC2, mC1, mC0};
49 return table;
50}
51
52static const umap_basic_basic &inverse_cst()
53{
54 static const umap_basic_basic inverse_cst_ = {
55 {C3, i3},
56 {mC3, im3},
57 {C2, mul(i2, i2)},
58 {mC2, mul(im2, i2)},
59 {C4, integer(12)},
60 {mC4, integer(-12)},
61 {C5, i5},
62 {mC5, im5},
63 {C6, integer(10)},
64 {mC6, integer(-10)},
65 {div(one, i2), integer(6)},
66 {div(minus_one, i2), integer(-6)},
67 };
68 return inverse_cst_;
69}
70
71static const umap_basic_basic &inverse_tct()
72{
73 static const umap_basic_basic inverse_tct_ = {
74 {div(one, sq3), mul(i2, i3)},
75 {div(minus_one, sq3), mul(im2, i3)},
76 {sq3, i3},
77 {mul(minus_one, sq3), im3},
78 {add(one, sq2), div(pow(i2, i3), i3)},
79 {mul(minus_one, add(one, sq2)), div(pow(i2, i3), im3)},
80 {sub(sq2, one), pow(i2, i3)},
81 {sub(one, sq2), pow(im2, i3)},
82 {sub(i2, sq3), mul(mul(i2, i2), i3)},
83 {sub(sq3, i2), mul(mul(im2, i2), i3)},
84 {sqrt(add(i5, mul(i2, sqrt(i5)))), div(i5, i2)},
85 {mul(minus_one, sqrt(add(i5, mul(i2, sqrt(i5))))), div(im5, i2)},
86 {one, pow(i2, i2)},
87 {minus_one, mul(minus_one, pow(i2, i2))},
88 };
89 return inverse_tct_;
90}
91
92Conjugate::Conjugate(const RCP<const Basic> &arg) : OneArgFunction(arg)
93{
94 SYMENGINE_ASSIGN_TYPEID()
95 SYMENGINE_ASSERT(is_canonical(arg))
96}
97
98bool Conjugate::is_canonical(const RCP<const Basic> &arg) const
99{
100 if (is_a_Number(*arg)) {
101 if (eq(*arg, *ComplexInf)) {
102 return true;
103 }
104 return false;
105 }
106 if (is_a<Constant>(*arg)) {
107 return false;
108 }
109 if (is_a<Mul>(*arg)) {
110 return false;
111 }
112 if (is_a<Pow>(*arg)) {
113 if (is_a<Integer>(*down_cast<const Pow &>(*arg).get_exp())) {
114 return false;
115 }
116 }
117 // OneArgFunction classes
120 or is_a<Abs>(*arg)) {
121 return false;
122 }
125 return false;
126 }
129 return false;
130 }
131 // TwoArgFunction classes
134 or is_a<Beta>(*arg)) {
135 return false;
136 }
137 // MultiArgFunction class
138 if (is_a<LeviCivita>(*arg)) {
139 return false;
140 }
141 return true;
142}
143
144RCP<const Basic> Conjugate::create(const RCP<const Basic> &arg) const
145{
146 return conjugate(arg);
147}
148
149RCP<const Basic> conjugate(const RCP<const Basic> &arg)
150{
151 if (is_a_Number(*arg)) {
152 return down_cast<const Number &>(*arg).conjugate();
153 }
156 return arg;
157 }
158 if (is_a<Mul>(*arg)) {
159 const map_basic_basic &dict = down_cast<const Mul &>(*arg).get_dict();
161 RCP<const Number> coef = rcp_static_cast<const Number>(
162 conjugate(down_cast<const Mul &>(*arg).get_coef()));
163 for (const auto &p : dict) {
164 if (is_a<Integer>(*p.second)) {
165 Mul::dict_add_term_new(outArg(coef), new_dict, p.second,
166 conjugate(p.first));
167 } else {
168 Mul::dict_add_term_new(
169 outArg(coef), new_dict, one,
170 conjugate(Mul::from_dict(one, {{p.first, p.second}})));
171 }
172 }
174 }
175 if (is_a<Pow>(*arg)) {
176 RCP<const Basic> base = down_cast<const Pow &>(*arg).get_base();
177 RCP<const Basic> exp = down_cast<const Pow &>(*arg).get_exp();
178 if (is_a<Integer>(*exp)) {
179 return pow(conjugate(base), exp);
180 }
181 }
182 if (is_a<Conjugate>(*arg)) {
183 return down_cast<const Conjugate &>(*arg).get_arg();
184 }
192 return func.create(conjugate(func.get_arg()));
193 }
195 or is_a<Beta>(*arg)) {
197 return func.create(conjugate(func.get_arg1()),
198 conjugate(func.get_arg2()));
199 }
201}
202
203bool get_pi_shift(const RCP<const Basic> &arg, const Ptr<RCP<const Number>> &n,
204 const Ptr<RCP<const Basic>> &x)
205{
206 if (is_a<Add>(*arg)) {
207 const Add &s = down_cast<const Add &>(*arg);
208 RCP<const Basic> coef = s.get_coef();
209 auto size = s.get_dict().size();
210 if (size > 1) {
211 // arg should be of form `x + n*pi`
212 // `n` is an integer
213 // `x` is an `Expression`
214 bool check_pi = false;
215 RCP<const Basic> temp;
216 *x = coef;
217 for (const auto &p : s.get_dict()) {
218 if (eq(*p.first, *pi)
219 and (is_a<Integer>(*p.second)
220 or is_a<Rational>(*p.second))) {
221 check_pi = true;
222 *n = p.second;
223 } else {
224 *x = add(mul(p.first, p.second), *x);
225 }
226 }
227 if (check_pi)
228 return true;
229 else // No term with `pi` found
230 return false;
231 } else if (size == 1) {
232 // arg should be of form `a + n*pi`
233 // where `a` is a `Number`.
234 auto p = s.get_dict().begin();
235 if (eq(*p->first, *pi)
236 and (is_a<Integer>(*p->second) or is_a<Rational>(*p->second))) {
237 *n = p->second;
238 *x = coef;
239 return true;
240 } else {
241 return false;
242 }
243 } else { // Should never reach here though!
244 // Dict of size < 1
245 return false;
246 }
247 } else if (is_a<Mul>(*arg)) {
248 // `arg` is of the form `k*pi/12`
249 const Mul &s = down_cast<const Mul &>(*arg);
250 auto p = s.get_dict().begin();
251 // dict should contain symbol `pi` only
252 if (s.get_dict().size() == 1 and eq(*p->first, *pi)
253 and eq(*p->second, *one)
254 and (is_a<Integer>(*s.get_coef())
255 or is_a<Rational>(*s.get_coef()))) {
256 *n = s.get_coef();
257 *x = zero;
258 return true;
259 } else {
260 return false;
261 }
262 } else if (eq(*arg, *pi)) {
263 *n = one;
264 *x = zero;
265 return true;
266 } else if (eq(*arg, *zero)) {
267 *n = zero;
268 *x = zero;
269 return true;
270 } else {
271 return false;
272 }
273}
274
275// Return true if arg is of form a+b*pi, with b integer or rational
276// with denominator 2. The a may be zero or any expression.
277bool trig_has_basic_shift(const RCP<const Basic> &arg)
278{
279 if (is_a<Add>(*arg)) {
280 const Add &s = down_cast<const Add &>(*arg);
281 for (const auto &p : s.get_dict()) {
282 const auto &temp = mul(p.second, integer(2));
283 if (eq(*p.first, *pi)) {
284 if (is_a<Integer>(*temp)) {
285 return true;
286 }
287 if (is_a<Rational>(*temp)) {
289 .as_rational_class();
290 return (m < 0) or (m > 1);
291 }
292 return false;
293 }
294 }
295 return false;
296 } else if (is_a<Mul>(*arg)) {
297 // is `arg` of the form `k*pi/2`?
298 // dict should contain symbol `pi` only
299 // and `k` should be a rational s.t. 0 < k < 1
300 const Mul &s = down_cast<const Mul &>(*arg);
301 RCP<const Basic> coef = mul(s.get_coef(), integer(2));
302 auto p = s.get_dict().begin();
303 if (s.get_dict().size() == 1 and eq(*p->first, *pi)
304 and eq(*p->second, *one)) {
305 if (is_a<Integer>(*coef)) {
306 return true;
307 }
308 if (is_a<Rational>(*coef)) {
309 auto m = down_cast<const Rational &>(*coef).as_rational_class();
310 return (m < 0) or (m > 1);
311 }
312 return false;
313 } else {
314 return false;
315 }
316 } else if (eq(*arg, *pi)) {
317 return true;
318 } else if (eq(*arg, *zero)) {
319 return true;
320 } else {
321 return false;
322 }
323}
324
326{
327 if (is_a_Number(arg)) {
328 if (down_cast<const Number &>(arg).is_negative()) {
329 return true;
330 } else if (is_a_Complex(arg)) {
332 RCP<const Number> real_part = c.real_part();
333 return (real_part->is_negative())
334 or (eq(*real_part, *zero)
335 and c.imaginary_part()->is_negative());
336 } else {
337 return false;
338 }
339 } else if (is_a<Mul>(arg)) {
340 const Mul &s = down_cast<const Mul &>(arg);
341 return could_extract_minus(*s.get_coef());
342 } else if (is_a<Add>(arg)) {
343 const Add &s = down_cast<const Add &>(arg);
344 if (s.get_coef()->is_zero()) {
345 map_basic_num d(s.get_dict().begin(), s.get_dict().end());
346 return could_extract_minus(*d.begin()->second);
347 } else {
348 return could_extract_minus(*s.get_coef());
349 }
350 } else {
351 return false;
352 }
353}
354
355bool handle_minus(const RCP<const Basic> &arg,
356 const Ptr<RCP<const Basic>> &rarg)
357{
358 if (is_a<Mul>(*arg)) {
359 const Mul &s = down_cast<const Mul &>(*arg);
360 // Check for -Add instances to transform -(-x + 2*y) to (x - 2*y)
361 if (s.get_coef()->is_minus_one() && s.get_dict().size() == 1
362 && eq(*s.get_dict().begin()->second, *one)) {
363 return not handle_minus(mul(minus_one, arg), rarg);
364 } else if (could_extract_minus(*s.get_coef())) {
365 *rarg = mul(minus_one, arg);
366 return true;
367 }
368 } else if (is_a<Add>(*arg)) {
369 if (could_extract_minus(*arg)) {
370 const Add &s = down_cast<const Add &>(*arg);
371 umap_basic_num d = s.get_dict();
372 for (auto &p : d) {
373 p.second = p.second->mul(*minus_one);
374 }
375 *rarg = Add::from_dict(s.get_coef()->mul(*minus_one), std::move(d));
376 return true;
377 }
378 } else if (could_extract_minus(*arg)) {
379 *rarg = mul(minus_one, arg);
380 return true;
381 }
382 *rarg = arg;
383 return false;
384}
385
386// \return true if conjugate has to be returned finally else false
387bool trig_simplify(const RCP<const Basic> &arg, unsigned period, bool odd,
388 bool conj_odd, // input
389 const Ptr<RCP<const Basic>> &rarg, int &index,
390 int &sign) // output
391{
392 bool check;
393 RCP<const Number> n;
394 RCP<const Basic> r;
395 RCP<const Basic> ret_arg;
396 check = get_pi_shift(arg, outArg(n), outArg(r));
397 if (check) {
398 RCP<const Number> t = mulnum(n, integer(12));
399 sign = 1;
400 if (is_a<Integer>(*t)) {
401 int m = numeric_cast<int>(
403 ->as_int());
404 if (eq(*r, *zero)) {
405 index = m;
406 *rarg = zero;
407 return false;
408 } else if (m == 0) {
409 index = 0;
410 bool b = handle_minus(r, outArg(ret_arg));
411 *rarg = ret_arg;
412 if (odd and b)
413 sign = -1;
414 return false;
415 }
416 }
417
418 rational_class m;
419 if (is_a<Integer>(*n)) {
420 // 2*pi periodic => f(r + pi * n) = f(r - pi * n)
421 m = mp_abs(down_cast<const Integer &>(*n).as_integer_class());
422 m /= period;
423 } else {
424 SYMENGINE_ASSERT(is_a<Rational>(*n));
425 m = down_cast<const Rational &>(*n).as_rational_class() / period;
426 integer_class t;
427#if SYMENGINE_INTEGER_CLASS != SYMENGINE_BOOSTMP
428 mp_fdiv_r(t, get_num(m), get_den(m));
429 get_num(m) = t;
430#else
431 integer_class quo;
432 mp_fdiv_qr(quo, t, get_num(m), get_den(m));
433 m -= rational_class(quo);
434#endif
435 // m = a / b => m = (a % b / b)
436 }
437 // Now, arg = r + 2 * pi * m where 0 <= m < 1
438 m *= 2 * period;
439 // Now, arg = r + pi * m / 2 where 0 <= m < 4
440 if (m >= 2 and m < 3) {
441 sign = -1;
442 r = add(r, mul(pi, Rational::from_mpq((m - 2) / 2)));
443 bool b = handle_minus(r, outArg(ret_arg));
444 *rarg = ret_arg;
445 if (odd and b)
446 sign = -1 * sign;
447 return false;
448 } else if (m >= 1) {
449 if (m < 2) {
450 // 1 <= m < 2
451 sign = 1;
452 r = add(r, mul(pi, Rational::from_mpq((m - 1) / 2)));
453 } else {
454 // 3 <= m < 4
455 sign = -1;
456 r = add(r, mul(pi, Rational::from_mpq((m - 3) / 2)));
457 }
458 bool b = handle_minus(r, outArg(ret_arg));
459 *rarg = ret_arg;
460 if (not b and conj_odd)
461 sign = -sign;
462 return true;
463 } else {
464 *rarg = add(r, mul(pi, Rational::from_mpq(m / 2)));
465 index = -1;
466 return false;
467 }
468 } else {
469 bool b = handle_minus(arg, outArg(ret_arg));
470 *rarg = ret_arg;
471 index = -1;
472 if (odd and b)
473 sign = -1;
474 else
475 sign = 1;
476 return false;
477 }
478}
479
480bool inverse_lookup(const umap_basic_basic &d, const RCP<const Basic> &t,
481 const Ptr<RCP<const Basic>> &index)
482{
483 auto it = d.find(t);
484 if (it == d.end()) {
485 // Not found in lookup
486 return false;
487 } else {
488 *index = (it->second);
489 return true;
490 }
491}
492
493Sign::Sign(const RCP<const Basic> &arg) : OneArgFunction(arg)
494{
495 SYMENGINE_ASSIGN_TYPEID()
496 SYMENGINE_ASSERT(is_canonical(arg))
497}
498
499bool Sign::is_canonical(const RCP<const Basic> &arg) const
500{
501 if (is_a_Number(*arg)) {
502 if (eq(*arg, *ComplexInf)) {
503 return true;
504 }
505 return false;
506 }
507 if (is_a<Constant>(*arg)) {
508 return false;
509 }
510 if (is_a<Sign>(*arg)) {
511 return false;
512 }
513 if (is_a<Mul>(*arg)) {
514 if (neq(*down_cast<const Mul &>(*arg).get_coef(), *one)
515 and neq(*down_cast<const Mul &>(*arg).get_coef(), *minus_one)) {
516 return false;
517 }
518 }
519 return true;
520}
521
522RCP<const Basic> Sign::create(const RCP<const Basic> &arg) const
523{
524 return sign(arg);
525}
526
527RCP<const Basic> sign(const RCP<const Basic> &arg)
528{
529 if (is_a_Number(*arg)) {
530 if (is_a<NaN>(*arg)) {
531 return Nan;
532 }
533 if (down_cast<const Number &>(*arg).is_zero()) {
534 return zero;
535 }
536 if (down_cast<const Number &>(*arg).is_positive()) {
537 return one;
538 }
539 if (down_cast<const Number &>(*arg).is_negative()) {
540 return minus_one;
541 }
542 if (is_a_Complex(*arg)
543 and down_cast<const ComplexBase &>(*arg).is_re_zero()) {
544 RCP<const Number> r
545 = down_cast<const ComplexBase &>(*arg).imaginary_part();
546 if (down_cast<const Number &>(*r).is_positive()) {
547 return I;
548 }
549 if (down_cast<const Number &>(*r).is_negative()) {
550 return mul(minus_one, I);
551 }
552 }
553 }
554 if (is_a<Constant>(*arg)) {
555 if (eq(*arg, *pi) or eq(*arg, *E) or eq(*arg, *EulerGamma)
556 or eq(*arg, *Catalan) or eq(*arg, *GoldenRatio))
557 return one;
558 }
559 if (is_a<Sign>(*arg)) {
560 return arg;
561 }
562 if (is_a<Mul>(*arg)) {
563 RCP<const Basic> s = sign(down_cast<const Mul &>(*arg).get_coef());
564 map_basic_basic dict = down_cast<const Mul &>(*arg).get_dict();
565 return mul(s,
567 }
569}
570
571Floor::Floor(const RCP<const Basic> &arg) : OneArgFunction(arg)
572{
573 SYMENGINE_ASSIGN_TYPEID()
574 SYMENGINE_ASSERT(is_canonical(arg))
575}
576
577bool Floor::is_canonical(const RCP<const Basic> &arg) const
578{
579 if (is_a_Number(*arg)) {
580 return false;
581 }
582 if (is_a<Constant>(*arg)) {
583 return false;
584 }
585 if (is_a<Floor>(*arg)) {
586 return false;
587 }
588 if (is_a<Ceiling>(*arg)) {
589 return false;
590 }
591 if (is_a<Truncate>(*arg)) {
592 return false;
593 }
594 if (is_a<BooleanAtom>(*arg) or is_a_Relational(*arg)) {
595 return false;
596 }
597 if (is_a<Add>(*arg)) {
598 RCP<const Number> s = down_cast<const Add &>(*arg).get_coef();
599 if (neq(*zero, *s) and is_a<Integer>(*s)) {
600 return false;
601 }
602 }
603 return true;
604}
605
606RCP<const Basic> Floor::create(const RCP<const Basic> &arg) const
607{
608 return floor(arg);
609}
610
611RCP<const Basic> floor(const RCP<const Basic> &arg)
612{
613 if (is_a_Number(*arg)) {
614 if (down_cast<const Number &>(*arg).is_exact()) {
615 if (is_a<Rational>(*arg)) {
617 integer_class quotient;
618 mp_fdiv_q(quotient, SymEngine::get_num(s.as_rational_class()),
619 SymEngine::get_den(s.as_rational_class()));
620 return integer(std::move(quotient));
621 }
622 return arg;
623 }
624 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
625 return _arg->get_eval().floor(*_arg);
626 }
627 if (is_a<Constant>(*arg)) {
628 if (eq(*arg, *pi)) {
629 return integer(3);
630 }
631 if (eq(*arg, *E)) {
632 return integer(2);
633 }
634 if (eq(*arg, *GoldenRatio)) {
635 return integer(1);
636 }
637 if (eq(*arg, *Catalan) or eq(*arg, *EulerGamma)) {
638 return integer(0);
639 }
640 }
641 if (is_a<Floor>(*arg)) {
642 return arg;
643 }
644 if (is_a<Ceiling>(*arg)) {
645 return arg;
646 }
647 if (is_a<Truncate>(*arg)) {
648 return arg;
649 }
650 if (is_a<BooleanAtom>(*arg) or is_a_Relational(*arg)) {
651 throw SymEngineException(
652 "Boolean objects not allowed in this context.");
653 }
654 if (is_a<Add>(*arg)) {
655 RCP<const Number> s = down_cast<const Add &>(*arg).get_coef();
656 umap_basic_num d = down_cast<const Add &>(*arg).get_dict();
657 if (is_a<Integer>(*s)
658 and not down_cast<const Integer &>(*s).is_zero()) {
659 return add(s, floor(Add::from_dict(zero, std::move(d))));
660 }
661 }
663}
664
665Ceiling::Ceiling(const RCP<const Basic> &arg) : OneArgFunction(arg)
666{
667 SYMENGINE_ASSIGN_TYPEID()
668 SYMENGINE_ASSERT(is_canonical(arg))
669}
670
671bool Ceiling::is_canonical(const RCP<const Basic> &arg) const
672{
673 if (is_a_Number(*arg)) {
674 return false;
675 }
676 if (is_a<Constant>(*arg)) {
677 return false;
678 }
679 if (is_a<Floor>(*arg)) {
680 return false;
681 }
682 if (is_a<Ceiling>(*arg)) {
683 return false;
684 }
685 if (is_a<Truncate>(*arg)) {
686 return false;
687 }
688 if (is_a<BooleanAtom>(*arg) or is_a_Relational(*arg)) {
689 return false;
690 }
691 if (is_a<Add>(*arg)) {
692 RCP<const Number> s = down_cast<const Add &>(*arg).get_coef();
693 if (neq(*zero, *s) and is_a<Integer>(*s)) {
694 return false;
695 }
696 }
697 return true;
698}
699
700RCP<const Basic> Ceiling::create(const RCP<const Basic> &arg) const
701{
702 return ceiling(arg);
703}
704
705RCP<const Basic> ceiling(const RCP<const Basic> &arg)
706{
707 if (is_a_Number(*arg)) {
708 if (down_cast<const Number &>(*arg).is_exact()) {
709 if (is_a<Rational>(*arg)) {
711 integer_class quotient;
712 mp_cdiv_q(quotient, SymEngine::get_num(s.as_rational_class()),
713 SymEngine::get_den(s.as_rational_class()));
714 return integer(std::move(quotient));
715 }
716 return arg;
717 }
718 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
719 return _arg->get_eval().ceiling(*_arg);
720 }
721 if (is_a<Constant>(*arg)) {
722 if (eq(*arg, *pi)) {
723 return integer(4);
724 }
725 if (eq(*arg, *E)) {
726 return integer(3);
727 }
728 if (eq(*arg, *GoldenRatio)) {
729 return integer(2);
730 }
731 if (eq(*arg, *Catalan) or eq(*arg, *EulerGamma)) {
732 return integer(1);
733 }
734 }
735 if (is_a<Floor>(*arg)) {
736 return arg;
737 }
738 if (is_a<Ceiling>(*arg)) {
739 return arg;
740 }
741 if (is_a<Truncate>(*arg)) {
742 return arg;
743 }
744 if (is_a<BooleanAtom>(*arg) or is_a_Relational(*arg)) {
745 throw SymEngineException(
746 "Boolean objects not allowed in this context.");
747 }
748 if (is_a<Add>(*arg)) {
749 RCP<const Number> s = down_cast<const Add &>(*arg).get_coef();
750 umap_basic_num d = down_cast<const Add &>(*arg).get_dict();
751 if (is_a<Integer>(*s)) {
752 return add(
754 }
755 }
757}
758
759Truncate::Truncate(const RCP<const Basic> &arg) : OneArgFunction(arg)
760{
761 SYMENGINE_ASSIGN_TYPEID()
762 SYMENGINE_ASSERT(is_canonical(arg))
763}
764
765bool Truncate::is_canonical(const RCP<const Basic> &arg) const
766{
767 if (is_a_Number(*arg)) {
768 return false;
769 }
770 if (is_a<Constant>(*arg)) {
771 return false;
772 }
773 if (is_a<Floor>(*arg)) {
774 return false;
775 }
776 if (is_a<Ceiling>(*arg)) {
777 return false;
778 }
779 if (is_a<Truncate>(*arg)) {
780 return false;
781 }
782 if (is_a<BooleanAtom>(*arg) or is_a_Relational(*arg)) {
783 return false;
784 }
785 if (is_a<Add>(*arg)) {
786 RCP<const Number> s = down_cast<const Add &>(*arg).get_coef();
787 if (neq(*zero, *s) and is_a<Integer>(*s)) {
788 return false;
789 }
790 }
791 return true;
792}
793
794RCP<const Basic> Truncate::create(const RCP<const Basic> &arg) const
795{
796 return truncate(arg);
797}
798
799RCP<const Basic> truncate(const RCP<const Basic> &arg)
800{
801 if (is_a_Number(*arg)) {
802 if (down_cast<const Number &>(*arg).is_exact()) {
803 if (is_a<Rational>(*arg)) {
805 integer_class quotient;
806 mp_tdiv_q(quotient, SymEngine::get_num(s.as_rational_class()),
807 SymEngine::get_den(s.as_rational_class()));
808 return integer(std::move(quotient));
809 }
810 return arg;
811 }
812 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
813 return _arg->get_eval().truncate(*_arg);
814 }
815 if (is_a<Constant>(*arg)) {
816 if (eq(*arg, *pi)) {
817 return integer(3);
818 }
819 if (eq(*arg, *E)) {
820 return integer(2);
821 }
822 if (eq(*arg, *GoldenRatio)) {
823 return integer(1);
824 }
825 if (eq(*arg, *Catalan) or eq(*arg, *EulerGamma)) {
826 return integer(0);
827 }
828 }
829 if (is_a<Floor>(*arg)) {
830 return arg;
831 }
832 if (is_a<Ceiling>(*arg)) {
833 return arg;
834 }
835 if (is_a<Truncate>(*arg)) {
836 return arg;
837 }
838 if (is_a<BooleanAtom>(*arg) or is_a_Relational(*arg)) {
839 throw SymEngineException(
840 "Boolean objects not allowed in this context.");
841 }
842 if (is_a<Add>(*arg)) {
843 RCP<const Number> s = down_cast<const Add &>(*arg).get_coef();
844 umap_basic_num d = down_cast<const Add &>(*arg).get_dict();
845 if (is_a<Integer>(*s)) {
847 Add::from_dict(zero, std::move(d))));
848 }
849 }
851}
852
853Sin::Sin(const RCP<const Basic> &arg) : TrigFunction(arg)
854{
855 SYMENGINE_ASSIGN_TYPEID()
856 SYMENGINE_ASSERT(is_canonical(arg))
857}
858
859bool Sin::is_canonical(const RCP<const Basic> &arg) const
860{
861 // e.g. sin(0)
862 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
863 return false;
864 // e.g sin(7*pi/2+y)
865 if (trig_has_basic_shift(arg)) {
866 return false;
867 }
868 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
869 return false;
870 }
871 return true;
872}
873
874RCP<const Basic> sin(const RCP<const Basic> &arg)
875{
876 if (eq(*arg, *zero))
877 return zero;
878 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
879 return down_cast<const Number &>(*arg).get_eval().sin(*arg);
880 }
881
882 if (is_a<ASin>(*arg)) {
883 return down_cast<const ASin &>(*arg).get_arg();
884 } else if (is_a<ACsc>(*arg)) {
885 return div(one, down_cast<const ACsc &>(*arg).get_arg());
886 }
887
888 RCP<const Basic> ret_arg;
889 int index, sign;
890 bool conjugate = trig_simplify(arg, 2, true, false, // input
891 outArg(ret_arg), index, sign); // output
892
893 if (conjugate) {
894 // cos has to be returned
895 if (sign == 1) {
896 return cos(ret_arg);
897 } else {
898 return mul(minus_one, cos(ret_arg));
899 }
900 } else {
901 if (eq(*ret_arg, *zero)) {
902 return mul(integer(sign), sin_table()[index]);
903 } else {
904 // If ret_arg is the same as arg, a `Sin` instance is returned
905 // Or else `sin` is called again.
906 if (sign == 1) {
907 if (neq(*ret_arg, *arg)) {
908 return sin(ret_arg);
909 } else {
910 return make_rcp<const Sin>(arg);
911 }
912 } else {
913 return mul(minus_one, sin(ret_arg));
914 }
915 }
916 }
917}
918
919/* ---------------------------- */
920
921Cos::Cos(const RCP<const Basic> &arg) : TrigFunction(arg)
922{
923 SYMENGINE_ASSIGN_TYPEID()
924 SYMENGINE_ASSERT(is_canonical(arg))
925}
926
927bool Cos::is_canonical(const RCP<const Basic> &arg) const
928{
929 // e.g. cos(0)
930 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
931 return false;
932 // e.g cos(k*pi/2)
933 if (trig_has_basic_shift(arg)) {
934 return false;
935 }
936 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
937 return false;
938 }
939 return true;
940}
941
942RCP<const Basic> cos(const RCP<const Basic> &arg)
943{
944 if (eq(*arg, *zero))
945 return one;
946 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
947 return down_cast<const Number &>(*arg).get_eval().cos(*arg);
948 }
949
950 if (is_a<ACos>(*arg)) {
951 return down_cast<const ACos &>(*arg).get_arg();
952 } else if (is_a<ASec>(*arg)) {
953 return div(one, down_cast<const ASec &>(*arg).get_arg());
954 }
955
956 RCP<const Basic> ret_arg;
957 int index, sign;
958 bool conjugate = trig_simplify(arg, 2, false, true, // input
959 outArg(ret_arg), index, sign); // output
960
961 if (conjugate) {
962 // sin has to be returned
963 if (sign == 1) {
964 return sin(ret_arg);
965 } else {
966 return mul(minus_one, sin(ret_arg));
967 }
968 } else {
969 if (eq(*ret_arg, *zero)) {
970 return mul(integer(sign), sin_table()[(index + 6) % 24]);
971 } else {
972 if (sign == 1) {
973 if (neq(*ret_arg, *arg)) {
974 return cos(ret_arg);
975 } else {
977 }
978 } else {
979 return mul(minus_one, cos(ret_arg));
980 }
981 }
982 }
983}
984
985/* ---------------------------- */
986
987Tan::Tan(const RCP<const Basic> &arg) : TrigFunction(arg)
988{
989 SYMENGINE_ASSIGN_TYPEID()
990 SYMENGINE_ASSERT(is_canonical(arg))
991}
992
993bool Tan::is_canonical(const RCP<const Basic> &arg) const
994{
995 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
996 return false;
997 // e.g tan(k*pi/2)
998 if (trig_has_basic_shift(arg)) {
999 return false;
1000 }
1001 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1002 return false;
1003 }
1004 return true;
1005}
1006
1007RCP<const Basic> tan(const RCP<const Basic> &arg)
1008{
1009 if (eq(*arg, *zero))
1010 return zero;
1011 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1012 return down_cast<const Number &>(*arg).get_eval().tan(*arg);
1013 }
1014
1015 if (is_a<ATan>(*arg)) {
1016 return down_cast<const ATan &>(*arg).get_arg();
1017 } else if (is_a<ACot>(*arg)) {
1018 return div(one, down_cast<const ACot &>(*arg).get_arg());
1019 }
1020
1021 RCP<const Basic> ret_arg;
1022 int index, sign;
1023 bool conjugate = trig_simplify(arg, 1, true, true, // input
1024 outArg(ret_arg), index, sign); // output
1025
1026 if (conjugate) {
1027 // cot has to be returned
1028 if (sign == 1) {
1029 return cot(ret_arg);
1030 } else {
1031 return mul(minus_one, cot(ret_arg));
1032 }
1033 } else {
1034 if (eq(*ret_arg, *zero)) {
1035 return mul(integer(sign),
1036 div(sin_table()[index], sin_table()[(index + 6) % 24]));
1037 } else {
1038 if (sign == 1) {
1039 if (neq(*ret_arg, *arg)) {
1040 return tan(ret_arg);
1041 } else {
1043 }
1044 } else {
1045 return mul(minus_one, tan(ret_arg));
1046 }
1047 }
1048 }
1049}
1050
1051/* ---------------------------- */
1052
1053Cot::Cot(const RCP<const Basic> &arg) : TrigFunction(arg)
1054{
1055 SYMENGINE_ASSIGN_TYPEID()
1056 SYMENGINE_ASSERT(is_canonical(arg))
1057}
1058
1059bool Cot::is_canonical(const RCP<const Basic> &arg) const
1060{
1061 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
1062 return false;
1063 // e.g cot(k*pi/2)
1064 if (trig_has_basic_shift(arg)) {
1065 return false;
1066 }
1067 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1068 return false;
1069 }
1070 return true;
1071}
1072
1073RCP<const Basic> cot(const RCP<const Basic> &arg)
1074{
1075 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1076 return down_cast<const Number &>(*arg).get_eval().cot(*arg);
1077 }
1078
1079 if (is_a<ACot>(*arg)) {
1080 return down_cast<const ACot &>(*arg).get_arg();
1081 } else if (is_a<ATan>(*arg)) {
1082 return div(one, down_cast<const ATan &>(*arg).get_arg());
1083 }
1084
1085 RCP<const Basic> ret_arg;
1086 int index, sign;
1087 bool conjugate = trig_simplify(arg, 1, true, true, // input
1088 outArg(ret_arg), index, sign); // output
1089
1090 if (conjugate) {
1091 // tan has to be returned
1092 if (sign == 1) {
1093 return tan(ret_arg);
1094 } else {
1095 return mul(minus_one, tan(ret_arg));
1096 }
1097 } else {
1098 if (eq(*ret_arg, *zero)) {
1099 return mul(integer(sign),
1100 div(sin_table()[(index + 6) % 24], sin_table()[index]));
1101 } else {
1102 if (sign == 1) {
1103 if (neq(*ret_arg, *arg)) {
1104 return cot(ret_arg);
1105 } else {
1107 }
1108 } else {
1109 return mul(minus_one, cot(ret_arg));
1110 }
1111 }
1112 }
1113}
1114
1115/* ---------------------------- */
1116
1117Csc::Csc(const RCP<const Basic> &arg) : TrigFunction(arg)
1118{
1119 SYMENGINE_ASSIGN_TYPEID()
1120 SYMENGINE_ASSERT(is_canonical(arg))
1121}
1122
1123bool Csc::is_canonical(const RCP<const Basic> &arg) const
1124{
1125 // e.g. Csc(0)
1126 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
1127 return false;
1128 // e.g csc(k*pi/2)
1129 if (trig_has_basic_shift(arg)) {
1130 return false;
1131 }
1132 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1133 return false;
1134 }
1135 return true;
1136}
1137
1138RCP<const Basic> csc(const RCP<const Basic> &arg)
1139{
1140 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1141 return down_cast<const Number &>(*arg).get_eval().csc(*arg);
1142 }
1143
1144 if (is_a<ACsc>(*arg)) {
1145 return down_cast<const ACsc &>(*arg).get_arg();
1146 } else if (is_a<ASin>(*arg)) {
1147 return div(one, down_cast<const ASin &>(*arg).get_arg());
1148 }
1149
1150 RCP<const Basic> ret_arg;
1151 int index, sign;
1152 bool conjugate = trig_simplify(arg, 2, true, false, // input
1153 outArg(ret_arg), index, sign); // output
1154
1155 if (conjugate) {
1156 // cos has to be returned
1157 if (sign == 1) {
1158 return sec(ret_arg);
1159 } else {
1160 return mul(minus_one, sec(ret_arg));
1161 }
1162 } else {
1163 if (eq(*ret_arg, *zero)) {
1164 return mul(integer(sign), div(one, sin_table()[index]));
1165 } else {
1166 if (sign == 1) {
1167 if (neq(*ret_arg, *arg)) {
1168 return csc(ret_arg);
1169 } else {
1171 }
1172 } else {
1173 return mul(minus_one, csc(ret_arg));
1174 }
1175 }
1176 }
1177}
1178
1179/* ---------------------------- */
1180
1181Sec::Sec(const RCP<const Basic> &arg) : TrigFunction(arg)
1182{
1183 SYMENGINE_ASSIGN_TYPEID()
1184 SYMENGINE_ASSERT(is_canonical(arg))
1185}
1186
1187bool Sec::is_canonical(const RCP<const Basic> &arg) const
1188{
1189 // e.g. Sec(0)
1190 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
1191 return false;
1192 // e.g sec(k*pi/2)
1193 if (trig_has_basic_shift(arg)) {
1194 return false;
1195 }
1196 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1197 return false;
1198 }
1199 return true;
1200}
1201
1202RCP<const Basic> sec(const RCP<const Basic> &arg)
1203{
1204 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1205 return down_cast<const Number &>(*arg).get_eval().sec(*arg);
1206 }
1207
1208 if (is_a<ASec>(*arg)) {
1209 return down_cast<const ASec &>(*arg).get_arg();
1210 } else if (is_a<ACos>(*arg)) {
1211 return div(one, down_cast<const ACos &>(*arg).get_arg());
1212 }
1213
1214 RCP<const Basic> ret_arg;
1215 int index, sign;
1216 bool conjugate = trig_simplify(arg, 2, false, true, // input
1217 outArg(ret_arg), index, sign); // output
1218
1219 if (conjugate) {
1220 // csc has to be returned
1221 if (sign == 1) {
1222 return csc(ret_arg);
1223 } else {
1224 return mul(minus_one, csc(ret_arg));
1225 }
1226 } else {
1227 if (eq(*ret_arg, *zero)) {
1228 return mul(integer(sign), div(one, sin_table()[(index + 6) % 24]));
1229 } else {
1230 if (sign == 1) {
1231 if (neq(*ret_arg, *arg)) {
1232 return sec(ret_arg);
1233 } else {
1235 }
1236 } else {
1237 return mul(minus_one, sec(ret_arg));
1238 }
1239 }
1240 }
1241}
1242/* ---------------------------- */
1243
1244// simplifies trigonometric functions wherever possible
1245// currently deals with simplifications of type sin(acos())
1246RCP<const Basic> trig_to_sqrt(const RCP<const Basic> &arg)
1247{
1248 RCP<const Basic> i_arg;
1249
1250 if (is_a<Sin>(*arg)) {
1251 if (is_a<ACos>(*arg->get_args()[0])) {
1252 i_arg = down_cast<const ACos &>(*(arg->get_args()[0])).get_arg();
1253 return sqrt(sub(one, pow(i_arg, i2)));
1254 } else if (is_a<ATan>(*arg->get_args()[0])) {
1255 i_arg = down_cast<const ATan &>(*(arg->get_args()[0])).get_arg();
1256 return div(i_arg, sqrt(add(one, pow(i_arg, i2))));
1257 } else if (is_a<ASec>(*arg->get_args()[0])) {
1258 i_arg = down_cast<const ASec &>(*(arg->get_args()[0])).get_arg();
1259 return sqrt(sub(one, pow(i_arg, im2)));
1260 } else if (is_a<ACot>(*arg->get_args()[0])) {
1261 i_arg = down_cast<const ACot &>(*(arg->get_args()[0])).get_arg();
1262 return div(one, mul(i_arg, sqrt(add(one, pow(i_arg, im2)))));
1263 }
1264 } else if (is_a<Cos>(*arg)) {
1265 if (is_a<ASin>(*arg->get_args()[0])) {
1266 i_arg = down_cast<const ASin &>(*(arg->get_args()[0])).get_arg();
1267 return sqrt(sub(one, pow(i_arg, i2)));
1268 } else if (is_a<ATan>(*arg->get_args()[0])) {
1269 i_arg = down_cast<const ATan &>(*(arg->get_args()[0])).get_arg();
1270 return div(one, sqrt(add(one, pow(i_arg, i2))));
1271 } else if (is_a<ACsc>(*arg->get_args()[0])) {
1272 i_arg = down_cast<const ACsc &>(*(arg->get_args()[0])).get_arg();
1273 return sqrt(sub(one, pow(i_arg, im2)));
1274 } else if (is_a<ACot>(*arg->get_args()[0])) {
1275 i_arg = down_cast<const ACot &>(*(arg->get_args()[0])).get_arg();
1276 return div(one, sqrt(add(one, pow(i_arg, im2))));
1277 }
1278 } else if (is_a<Tan>(*arg)) {
1279 if (is_a<ASin>(*arg->get_args()[0])) {
1280 i_arg = down_cast<const ASin &>(*(arg->get_args()[0])).get_arg();
1281 return div(i_arg, sqrt(sub(one, pow(i_arg, i2))));
1282 } else if (is_a<ACos>(*arg->get_args()[0])) {
1283 i_arg = down_cast<const ACos &>(*(arg->get_args()[0])).get_arg();
1284 return div(sqrt(sub(one, pow(i_arg, i2))), i_arg);
1285 } else if (is_a<ACsc>(*arg->get_args()[0])) {
1286 i_arg = down_cast<const ACsc &>(*(arg->get_args()[0])).get_arg();
1287 return div(one, mul(i_arg, sqrt(sub(one, pow(i_arg, im2)))));
1288 } else if (is_a<ASec>(*arg->get_args()[0])) {
1289 i_arg = down_cast<const ASec &>(*(arg->get_args()[0])).get_arg();
1290 return mul(i_arg, sqrt(sub(one, pow(i_arg, im2))));
1291 }
1292 } else if (is_a<Csc>(*arg)) {
1293 if (is_a<ACos>(*arg->get_args()[0])) {
1294 i_arg = down_cast<const ACos &>(*(arg->get_args()[0])).get_arg();
1295 return div(one, sqrt(sub(one, pow(i_arg, i2))));
1296 } else if (is_a<ATan>(*arg->get_args()[0])) {
1297 i_arg = down_cast<const ATan &>(*(arg->get_args()[0])).get_arg();
1298 return div(sqrt(add(one, pow(i_arg, i2))), i_arg);
1299 } else if (is_a<ASec>(*arg->get_args()[0])) {
1300 i_arg = down_cast<const ASec &>(*(arg->get_args()[0])).get_arg();
1301 return div(one, sqrt(sub(one, pow(i_arg, im2))));
1302 } else if (is_a<ACot>(*arg->get_args()[0])) {
1303 i_arg = down_cast<const ACot &>(*(arg->get_args()[0])).get_arg();
1304 return mul(i_arg, sqrt(add(one, pow(i_arg, im2))));
1305 }
1306 } else if (is_a<Sec>(*arg)) {
1307 if (is_a<ASin>(*arg->get_args()[0])) {
1308 i_arg = down_cast<const ASin &>(*(arg->get_args()[0])).get_arg();
1309 return div(one, sqrt(sub(one, pow(i_arg, i2))));
1310 } else if (is_a<ATan>(*arg->get_args()[0])) {
1311 i_arg = down_cast<const ATan &>(*(arg->get_args()[0])).get_arg();
1312 return sqrt(add(one, pow(i_arg, i2)));
1313 } else if (is_a<ACsc>(*arg->get_args()[0])) {
1314 i_arg = down_cast<const ACsc &>(*(arg->get_args()[0])).get_arg();
1315 return div(one, sqrt(sub(one, pow(i_arg, im2))));
1316 } else if (is_a<ACot>(*arg->get_args()[0])) {
1317 i_arg = down_cast<const ACot &>(*(arg->get_args()[0])).get_arg();
1318 return sqrt(add(one, pow(i_arg, im2)));
1319 }
1320 } else if (is_a<Cot>(*arg)) {
1321 if (is_a<ASin>(*arg->get_args()[0])) {
1322 i_arg = down_cast<const ASin &>(*(arg->get_args()[0])).get_arg();
1323 return div(sqrt(sub(one, pow(i_arg, i2))), i_arg);
1324 } else if (is_a<ACos>(*arg->get_args()[0])) {
1325 i_arg = down_cast<const ACos &>(*(arg->get_args()[0])).get_arg();
1326 return div(i_arg, sqrt(sub(one, pow(i_arg, i2))));
1327 } else if (is_a<ACsc>(*arg->get_args()[0])) {
1328 i_arg = down_cast<const ACsc &>(*(arg->get_args()[0])).get_arg();
1329 return mul(i_arg, sqrt(sub(one, pow(i_arg, im2))));
1330 } else if (is_a<ASec>(*arg->get_args()[0])) {
1331 i_arg = down_cast<const ASec &>(*(arg->get_args()[0])).get_arg();
1332 return div(one, mul(i_arg, sqrt(sub(one, pow(i_arg, im2)))));
1333 }
1334 }
1335
1336 return arg;
1337}
1338
1339/* ---------------------------- */
1340ASin::ASin(const RCP<const Basic> &arg) : InverseTrigFunction(arg)
1341{
1342 SYMENGINE_ASSIGN_TYPEID()
1343 SYMENGINE_ASSERT(is_canonical(arg))
1344}
1345
1346bool ASin::is_canonical(const RCP<const Basic> &arg) const
1347{
1348 if (eq(*arg, *zero) or eq(*arg, *one) or eq(*arg, *minus_one))
1349 return false;
1350 RCP<const Basic> index;
1351 if (inverse_lookup(inverse_cst(), get_arg(), outArg(index))) {
1352 return false;
1353 }
1354 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1355 return false;
1356 }
1357 return true;
1358}
1359
1360RCP<const Basic> asin(const RCP<const Basic> &arg)
1361{
1362 if (eq(*arg, *zero))
1363 return zero;
1364 else if (eq(*arg, *one))
1365 return div(pi, i2);
1366 else if (eq(*arg, *minus_one))
1367 return mul(minus_one, div(pi, i2));
1368 else if (is_a_Number(*arg)
1369 and not down_cast<const Number &>(*arg).is_exact()) {
1370 return down_cast<const Number &>(*arg).get_eval().asin(*arg);
1371 }
1372
1373 RCP<const Basic> index;
1374 bool b = inverse_lookup(inverse_cst(), arg, outArg(index));
1375 if (b) {
1376 return div(pi, index);
1377 } else {
1378 return make_rcp<const ASin>(arg);
1379 }
1380}
1381
1382ACos::ACos(const RCP<const Basic> &arg) : InverseTrigFunction(arg)
1383{
1384 SYMENGINE_ASSIGN_TYPEID()
1385 SYMENGINE_ASSERT(is_canonical(arg))
1386}
1387
1388bool ACos::is_canonical(const RCP<const Basic> &arg) const
1389{
1390 if (eq(*arg, *zero) or eq(*arg, *one) or eq(*arg, *minus_one))
1391 return false;
1392 RCP<const Basic> index;
1393 if (inverse_lookup(inverse_cst(), get_arg(), outArg(index))) {
1394 return false;
1395 }
1396 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1397 return false;
1398 }
1399 return true;
1400}
1401
1402RCP<const Basic> acos(const RCP<const Basic> &arg)
1403{
1404 if (eq(*arg, *zero))
1405 return div(pi, i2);
1406 else if (eq(*arg, *one))
1407 return zero;
1408 else if (eq(*arg, *minus_one))
1409 return pi;
1410 else if (is_a_Number(*arg)
1411 and not down_cast<const Number &>(*arg).is_exact()) {
1412 return down_cast<const Number &>(*arg).get_eval().acos(*arg);
1413 }
1414
1415 RCP<const Basic> index;
1416 bool b = inverse_lookup(inverse_cst(), arg, outArg(index));
1417 if (b) {
1418 return sub(div(pi, i2), div(pi, index));
1419 } else {
1420 return make_rcp<const ACos>(arg);
1421 }
1422}
1423
1424ASec::ASec(const RCP<const Basic> &arg) : InverseTrigFunction(arg)
1425{
1426 SYMENGINE_ASSIGN_TYPEID()
1427 SYMENGINE_ASSERT(is_canonical(arg))
1428}
1429
1430bool ASec::is_canonical(const RCP<const Basic> &arg) const
1431{
1432 if (eq(*arg, *one) or eq(*arg, *minus_one))
1433 return false;
1434 RCP<const Basic> index;
1435 if (inverse_lookup(inverse_cst(), div(one, get_arg()), outArg(index))) {
1436 return false;
1437 } else if (is_a_Number(*arg)
1438 and not down_cast<const Number &>(*arg).is_exact()) {
1439 return false;
1440 }
1441 return true;
1442}
1443
1444RCP<const Basic> asec(const RCP<const Basic> &arg)
1445{
1446 if (eq(*arg, *one))
1447 return zero;
1448 else if (eq(*arg, *minus_one))
1449 return pi;
1450 else if (is_a_Number(*arg)
1451 and not down_cast<const Number &>(*arg).is_exact()) {
1452 return down_cast<const Number &>(*arg).get_eval().asec(*arg);
1453 }
1454
1455 RCP<const Basic> index;
1456 bool b = inverse_lookup(inverse_cst(), div(one, arg), outArg(index));
1457 if (b) {
1458 return sub(div(pi, i2), div(pi, index));
1459 } else {
1460 return make_rcp<const ASec>(arg);
1461 }
1462}
1463
1464ACsc::ACsc(const RCP<const Basic> &arg) : InverseTrigFunction(arg)
1465{
1466 SYMENGINE_ASSIGN_TYPEID()
1467 SYMENGINE_ASSERT(is_canonical(arg))
1468}
1469
1470bool ACsc::is_canonical(const RCP<const Basic> &arg) const
1471{
1472 if (eq(*arg, *one) or eq(*arg, *minus_one))
1473 return false;
1474 RCP<const Basic> index;
1475 if (inverse_lookup(inverse_cst(), div(one, arg), outArg(index))) {
1476 return false;
1477 }
1478 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1479 return false;
1480 }
1481 return true;
1482}
1483
1484RCP<const Basic> acsc(const RCP<const Basic> &arg)
1485{
1486 if (eq(*arg, *one))
1487 return div(pi, i2);
1488 else if (eq(*arg, *minus_one))
1489 return div(pi, im2);
1490 else if (is_a_Number(*arg)
1491 and not down_cast<const Number &>(*arg).is_exact()) {
1492 return down_cast<const Number &>(*arg).get_eval().acsc(*arg);
1493 }
1494
1495 RCP<const Basic> index;
1496 bool b = inverse_lookup(inverse_cst(), div(one, arg), outArg(index));
1497 if (b) {
1498 return div(pi, index);
1499 } else {
1500 return make_rcp<const ACsc>(arg);
1501 }
1502}
1503
1504ATan::ATan(const RCP<const Basic> &arg) : InverseTrigFunction(arg)
1505{
1506 SYMENGINE_ASSIGN_TYPEID()
1507 SYMENGINE_ASSERT(is_canonical(arg))
1508}
1509
1510bool ATan::is_canonical(const RCP<const Basic> &arg) const
1511{
1512 if (eq(*arg, *zero) or eq(*arg, *one) or eq(*arg, *minus_one))
1513 return false;
1514 RCP<const Basic> index;
1515 if (inverse_lookup(inverse_tct(), get_arg(), outArg(index))) {
1516 return false;
1517 }
1518 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1519 return false;
1520 }
1521 return true;
1522}
1523
1524RCP<const Basic> atan(const RCP<const Basic> &arg)
1525{
1526 if (eq(*arg, *zero))
1527 return zero;
1528 else if (eq(*arg, *one))
1529 return div(pi, mul(i2, i2));
1530 else if (eq(*arg, *minus_one))
1531 return mul(minus_one, div(pi, mul(i2, i2)));
1532 else if (is_a_Number(*arg)
1533 and not down_cast<const Number &>(*arg).is_exact()) {
1534 return down_cast<const Number &>(*arg).get_eval().atan(*arg);
1535 }
1536
1537 RCP<const Basic> index;
1538 bool b = inverse_lookup(inverse_tct(), arg, outArg(index));
1539 if (b) {
1540 return div(pi, index);
1541 } else {
1542 return make_rcp<const ATan>(arg);
1543 }
1544}
1545
1546ACot::ACot(const RCP<const Basic> &arg) : InverseTrigFunction(arg)
1547{
1548 SYMENGINE_ASSIGN_TYPEID()
1549 SYMENGINE_ASSERT(is_canonical(arg))
1550}
1551
1552bool ACot::is_canonical(const RCP<const Basic> &arg) const
1553{
1554 if (eq(*arg, *zero) or eq(*arg, *one) or eq(*arg, *minus_one))
1555 return false;
1556 RCP<const Basic> index;
1557 if (inverse_lookup(inverse_tct(), arg, outArg(index))) {
1558 return false;
1559 }
1560 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1561 return false;
1562 }
1563 return true;
1564}
1565
1566RCP<const Basic> acot(const RCP<const Basic> &arg)
1567{
1568 if (eq(*arg, *zero))
1569 return div(pi, i2);
1570 else if (eq(*arg, *one))
1571 return div(pi, mul(i2, i2));
1572 else if (eq(*arg, *minus_one))
1573 return mul(i3, div(pi, mul(i2, i2)));
1574 else if (is_a_Number(*arg)
1575 and not down_cast<const Number &>(*arg).is_exact()) {
1576 return down_cast<const Number &>(*arg).get_eval().acot(*arg);
1577 }
1578
1579 RCP<const Basic> index;
1580 bool b = inverse_lookup(inverse_tct(), arg, outArg(index));
1581 if (b) {
1582 return sub(div(pi, i2), div(pi, index));
1583 } else {
1584 return make_rcp<const ACot>(arg);
1585 }
1586}
1587
1588ATan2::ATan2(const RCP<const Basic> &num, const RCP<const Basic> &den)
1590{
1591 SYMENGINE_ASSIGN_TYPEID()
1592 SYMENGINE_ASSERT(is_canonical(num, den))
1593}
1594
1595bool ATan2::is_canonical(const RCP<const Basic> &num,
1596 const RCP<const Basic> &den) const
1597{
1598 if (eq(*num, *zero) or eq(*num, *den) or eq(*num, *mul(minus_one, den)))
1599 return false;
1600 RCP<const Basic> index;
1601 bool b = inverse_lookup(inverse_tct(), div(num, den), outArg(index));
1602 if (b)
1603 return false;
1604 else
1605 return true;
1606}
1607
1608RCP<const Basic> ATan2::create(const RCP<const Basic> &a,
1609 const RCP<const Basic> &b) const
1610{
1611 return atan2(a, b);
1612}
1613
1614RCP<const Basic> atan2(const RCP<const Basic> &num, const RCP<const Basic> &den)
1615{
1616 if (eq(*num, *zero)) {
1617 if (is_a_Number(*den)) {
1618 RCP<const Number> den_new = rcp_static_cast<const Number>(den);
1619 if (den_new->is_negative())
1620 return pi;
1621 else if (den_new->is_positive())
1622 return zero;
1623 else {
1624 return Nan;
1625 }
1626 }
1627 } else if (eq(*den, *zero)) {
1628 if (is_a_Number(*num)) {
1629 RCP<const Number> num_new = rcp_static_cast<const Number>(num);
1630 if (num_new->is_negative())
1631 return div(pi, im2);
1632 else
1633 return div(pi, i2);
1634 }
1635 }
1636 RCP<const Basic> index;
1637 bool b = inverse_lookup(inverse_tct(), div(num, den), outArg(index));
1638 if (b) {
1639 // Ideally the answer should depend on the signs of `num` and `den`
1640 // Currently is_positive() and is_negative() is not implemented for
1641 // types other than `Number`
1642 // Hence this will give exact answers in case when num and den are
1643 // numbers in SymEngine sense and when num and den are positive.
1644 // for the remaining cases in which we just return the value from
1645 // the lookup table.
1646 // TODO: update once is_positive() and is_negative() is implemented
1647 // in `Basic`
1648 if (is_a_Number(*den) and is_a_Number(*num)) {
1649 RCP<const Number> den_new = rcp_static_cast<const Number>(den);
1650 RCP<const Number> num_new = rcp_static_cast<const Number>(num);
1651
1652 if (den_new->is_positive()) {
1653 return div(pi, index);
1654 } else if (den_new->is_negative()) {
1655 if (num_new->is_negative()) {
1656 return sub(div(pi, index), pi);
1657 } else {
1658 return add(div(pi, index), pi);
1659 }
1660 } else {
1661 return div(pi, index);
1662 }
1663 } else {
1664 return div(pi, index);
1665 }
1666 } else {
1667 return make_rcp<const ATan2>(num, den);
1668 }
1669}
1670
1671/* ---------------------------- */
1672
1673RCP<const Basic> Sin::create(const RCP<const Basic> &arg) const
1674{
1675 return sin(arg);
1676}
1677
1678RCP<const Basic> Cos::create(const RCP<const Basic> &arg) const
1679{
1680 return cos(arg);
1681}
1682
1683RCP<const Basic> Tan::create(const RCP<const Basic> &arg) const
1684{
1685 return tan(arg);
1686}
1687
1688RCP<const Basic> Cot::create(const RCP<const Basic> &arg) const
1689{
1690 return cot(arg);
1691}
1692
1693RCP<const Basic> Sec::create(const RCP<const Basic> &arg) const
1694{
1695 return sec(arg);
1696}
1697
1698RCP<const Basic> Csc::create(const RCP<const Basic> &arg) const
1699{
1700 return csc(arg);
1701}
1702
1703RCP<const Basic> ASin::create(const RCP<const Basic> &arg) const
1704{
1705 return asin(arg);
1706}
1707
1708RCP<const Basic> ACos::create(const RCP<const Basic> &arg) const
1709{
1710 return acos(arg);
1711}
1712
1713RCP<const Basic> ATan::create(const RCP<const Basic> &arg) const
1714{
1715 return atan(arg);
1716}
1717
1718RCP<const Basic> ACot::create(const RCP<const Basic> &arg) const
1719{
1720 return acot(arg);
1721}
1722
1723RCP<const Basic> ASec::create(const RCP<const Basic> &arg) const
1724{
1725 return asec(arg);
1726}
1727
1728RCP<const Basic> ACsc::create(const RCP<const Basic> &arg) const
1729{
1730 return acsc(arg);
1731}
1732
1733/* ---------------------------- */
1734
1735Log::Log(const RCP<const Basic> &arg) : OneArgFunction(arg)
1736{
1737 SYMENGINE_ASSIGN_TYPEID()
1738 SYMENGINE_ASSERT(is_canonical(arg))
1739}
1740
1741bool Log::is_canonical(const RCP<const Basic> &arg) const
1742{
1743 // log(0)
1744 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
1745 return false;
1746 // log(1)
1747 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_one())
1748 return false;
1749 // log(E)
1750 if (eq(*arg, *E))
1751 return false;
1752
1753 if (is_a_Number(*arg) and down_cast<const Number &>(*arg).is_negative())
1754 return false;
1755
1756 // log(Inf) is also handled here.
1757 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact())
1758 return false;
1759
1760 // log(3I) should be expanded to log(3) + I*pi/2
1761 if (is_a<Complex>(*arg) and down_cast<const Complex &>(*arg).is_re_zero())
1762 return false;
1763 // log(num/den) = log(num) - log(den)
1764 if (is_a<Rational>(*arg))
1765 return false;
1766 return true;
1767}
1768
1769RCP<const Basic> Log::create(const RCP<const Basic> &a) const
1770{
1771 return log(a);
1772}
1773
1774RCP<const Basic> log(const RCP<const Basic> &arg)
1775{
1776 if (eq(*arg, *zero))
1777 return ComplexInf;
1778 if (eq(*arg, *one))
1779 return zero;
1780 if (eq(*arg, *E))
1781 return one;
1782
1783 if (is_a_Number(*arg)) {
1784 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
1785 if (not _arg->is_exact()) {
1786 return _arg->get_eval().log(*_arg);
1787 } else if (_arg->is_negative()) {
1788 return add(log(mul(minus_one, _arg)), mul(pi, I));
1789 }
1790 }
1791
1792 if (is_a<Rational>(*arg)) {
1795 outArg(den));
1796 return sub(log(num), log(den));
1797 }
1798
1799 if (is_a<Complex>(*arg)) {
1801 if (_arg->is_re_zero()) {
1802 RCP<const Number> arg_img = _arg->imaginary_part();
1803 if (arg_img->is_negative()) {
1804 return sub(log(mul(minus_one, arg_img)),
1805 mul(I, div(pi, integer(2))));
1806 } else if (arg_img->is_zero()) {
1807 return ComplexInf;
1808 } else if (arg_img->is_positive()) {
1809 return add(log(arg_img), mul(I, div(pi, integer(2))));
1810 }
1811 }
1812 }
1813
1814 return make_rcp<const Log>(arg);
1815}
1816
1817RCP<const Basic> log(const RCP<const Basic> &arg, const RCP<const Basic> &base)
1818{
1819 return div(log(arg), log(base));
1820}
1821
1822LambertW::LambertW(const RCP<const Basic> &arg) : OneArgFunction{arg}
1823{
1824 SYMENGINE_ASSIGN_TYPEID()
1825 SYMENGINE_ASSERT(is_canonical(arg))
1826}
1827
1828bool LambertW::is_canonical(const RCP<const Basic> &arg) const
1829{
1830 if (eq(*arg, *zero))
1831 return false;
1832 if (eq(*arg, *E))
1833 return false;
1834 if (eq(*arg, *div(neg(one), E)))
1835 return false;
1836 if (eq(*arg, *div(log(i2), im2)))
1837 return false;
1838 return true;
1839}
1840
1841RCP<const Basic> LambertW::create(const RCP<const Basic> &arg) const
1842{
1843 return lambertw(arg);
1844}
1845
1846RCP<const Basic> lambertw(const RCP<const Basic> &arg)
1847{
1848 if (eq(*arg, *zero))
1849 return zero;
1850 if (eq(*arg, *E))
1851 return one;
1852 if (eq(*arg, *div(neg(one), E)))
1853 return minus_one;
1854 if (eq(*arg, *div(log(i2), im2)))
1855 return mul(minus_one, log(i2));
1857}
1858
1859FunctionSymbol::FunctionSymbol(std::string name, const RCP<const Basic> &arg)
1860 : MultiArgFunction({arg}), name_{name} {SYMENGINE_ASSIGN_TYPEID()
1861 SYMENGINE_ASSERT(
1862 is_canonical(get_vec()))}
1863
1864 FunctionSymbol::FunctionSymbol(std::string name, const vec_basic &arg)
1865 : MultiArgFunction(arg), name_{name}
1866{
1867 SYMENGINE_ASSIGN_TYPEID()
1868 SYMENGINE_ASSERT(is_canonical(get_vec()))
1869}
1870
1871bool FunctionSymbol::is_canonical(const vec_basic &arg) const
1872{
1873 return true;
1874}
1875
1876hash_t FunctionSymbol::__hash__() const
1877{
1878 hash_t seed = SYMENGINE_FUNCTIONSYMBOL;
1879 for (const auto &a : get_vec())
1880 hash_combine<Basic>(seed, *a);
1881 hash_combine<std::string>(seed, name_);
1882 return seed;
1883}
1884
1885bool FunctionSymbol::__eq__(const Basic &o) const
1886{
1887 if (is_a<FunctionSymbol>(o)
1888 and name_ == down_cast<const FunctionSymbol &>(o).name_
1889 and unified_eq(get_vec(),
1890 down_cast<const FunctionSymbol &>(o).get_vec()))
1891 return true;
1892 return false;
1893}
1894
1895int FunctionSymbol::compare(const Basic &o) const
1896{
1897 SYMENGINE_ASSERT(is_a<FunctionSymbol>(o))
1898 const FunctionSymbol &s = down_cast<const FunctionSymbol &>(o);
1899 if (name_ == s.name_)
1900 return unified_compare(get_vec(), s.get_vec());
1901 else
1902 return name_ < s.name_ ? -1 : 1;
1903}
1904
1905RCP<const Basic> FunctionSymbol::create(const vec_basic &x) const
1906{
1907 return make_rcp<const FunctionSymbol>(name_, x);
1908}
1909
1910RCP<const Basic> function_symbol(std::string name, const vec_basic &arg)
1911{
1912 return make_rcp<const FunctionSymbol>(name, arg);
1913}
1914
1915RCP<const Basic> function_symbol(std::string name, const RCP<const Basic> &arg)
1916{
1917 return make_rcp<const FunctionSymbol>(name, arg);
1918}
1919
1920FunctionWrapper::FunctionWrapper(std::string name, const RCP<const Basic> &arg)
1921 : FunctionSymbol(name, arg){SYMENGINE_ASSIGN_TYPEID()}
1922
1923 FunctionWrapper::FunctionWrapper(std::string name, const vec_basic &vec)
1924 : FunctionSymbol(name, vec){SYMENGINE_ASSIGN_TYPEID()}
1925
1926 /* ---------------------------- */
1927
1928 Derivative::Derivative(const RCP<const Basic> &arg,
1929 const multiset_basic &x)
1930 : arg_{arg}, x_{x}
1931{
1932 SYMENGINE_ASSIGN_TYPEID()
1933 SYMENGINE_ASSERT(is_canonical(arg, x))
1934}
1935
1936bool Derivative::is_canonical(const RCP<const Basic> &arg,
1937 const multiset_basic &x) const
1938{
1939 // Check that 'x' are Symbols:
1940 for (const auto &a : x)
1941 if (not is_a<Symbol>(*a))
1942 return false;
1944 for (auto &p : x) {
1948 bool found_s = false;
1949 // 's' should be one of the args of the function
1950 // and should not appear anywhere else.
1951 for (const auto &a : f->get_args()) {
1952 if (eq(*a, *s)) {
1953 if (found_s) {
1954 return false;
1955 } else {
1956 found_s = true;
1957 }
1958 } else if (neq(*a->diff(s), *zero)) {
1959 return false;
1960 }
1961 }
1962 if (!found_s) {
1963 return false;
1964 }
1965 }
1966 return true;
1967 } else if (is_a<Abs>(*arg)) {
1968 return true;
1969 } else if (is_a<FunctionWrapper>(*arg)) {
1970 return true;
1971 } else if (is_a<PolyGamma>(*arg) or is_a<Zeta>(*arg)
1974 bool found = false;
1975 auto v = arg->get_args();
1976 for (auto &p : x) {
1977 if (has_symbol(*v[0], *rcp_static_cast<const Symbol>(p))) {
1978 found = true;
1979 break;
1980 }
1981 }
1982 return found;
1983 } else if (is_a<KroneckerDelta>(*arg)) {
1984 bool found = false;
1985 auto v = arg->get_args();
1986 for (auto &p : x) {
1987 if (has_symbol(*v[0], *rcp_static_cast<const Symbol>(p))
1988 or has_symbol(*v[1], *rcp_static_cast<const Symbol>(p))) {
1989 found = true;
1990 break;
1991 }
1992 }
1993 return found;
1994 }
1995 return false;
1996}
1997
1999{
2000 hash_t seed = SYMENGINE_DERIVATIVE;
2001 hash_combine<Basic>(seed, *arg_);
2002 for (auto &p : x_) {
2003 hash_combine<Basic>(seed, *p);
2004 }
2005 return seed;
2006}
2007
2008bool Derivative::__eq__(const Basic &o) const
2009{
2010 if (is_a<Derivative>(o)
2011 and eq(*arg_, *(down_cast<const Derivative &>(o).arg_))
2012 and unified_eq(x_, down_cast<const Derivative &>(o).x_))
2013 return true;
2014 return false;
2015}
2016
2017int Derivative::compare(const Basic &o) const
2018{
2019 SYMENGINE_ASSERT(is_a<Derivative>(o))
2021 int cmp = arg_->__cmp__(*(s.arg_));
2022 if (cmp != 0)
2023 return cmp;
2024 cmp = unified_compare(x_, s.x_);
2025 return cmp;
2026}
2027
2028// Subs class
2029Subs::Subs(const RCP<const Basic> &arg, const map_basic_basic &dict)
2030 : arg_{arg}, dict_{dict}
2031{
2032 SYMENGINE_ASSIGN_TYPEID()
2033 SYMENGINE_ASSERT(is_canonical(arg, dict))
2034}
2035
2036bool Subs::is_canonical(const RCP<const Basic> &arg,
2037 const map_basic_basic &dict) const
2038{
2039 if (is_a<Derivative>(*arg)) {
2040 return true;
2041 }
2042 return false;
2043}
2044
2045hash_t Subs::__hash__() const
2046{
2047 hash_t seed = SYMENGINE_SUBS;
2048 hash_combine<Basic>(seed, *arg_);
2049 for (const auto &p : dict_) {
2050 hash_combine<Basic>(seed, *p.first);
2051 hash_combine<Basic>(seed, *p.second);
2052 }
2053 return seed;
2054}
2055
2056bool Subs::__eq__(const Basic &o) const
2057{
2058 if (is_a<Subs>(o) and eq(*arg_, *(down_cast<const Subs &>(o).arg_))
2059 and unified_eq(dict_, down_cast<const Subs &>(o).dict_))
2060 return true;
2061 return false;
2062}
2063
2064int Subs::compare(const Basic &o) const
2065{
2066 SYMENGINE_ASSERT(is_a<Subs>(o))
2067 const Subs &s = down_cast<const Subs &>(o);
2068 int cmp = arg_->__cmp__(*(s.arg_));
2069 if (cmp != 0)
2070 return cmp;
2071 cmp = unified_compare(dict_, s.dict_);
2072 return cmp;
2073}
2074
2075vec_basic Subs::get_variables() const
2076{
2077 vec_basic v;
2078 for (const auto &p : dict_) {
2079 v.push_back(p.first);
2080 }
2081 return v;
2082}
2083
2084vec_basic Subs::get_point() const
2085{
2086 vec_basic v;
2087 for (const auto &p : dict_) {
2088 v.push_back(p.second);
2089 }
2090 return v;
2091}
2092
2094{
2095 vec_basic v = {arg_};
2096 for (const auto &p : dict_) {
2097 v.push_back(p.first);
2098 }
2099 for (const auto &p : dict_) {
2100 v.push_back(p.second);
2101 }
2102 return v;
2103}
2104
2105Sinh::Sinh(const RCP<const Basic> &arg) : HyperbolicFunction(arg)
2106{
2107 SYMENGINE_ASSIGN_TYPEID()
2108 SYMENGINE_ASSERT(is_canonical(arg))
2109}
2110
2111bool Sinh::is_canonical(const RCP<const Basic> &arg) const
2112{
2113 if (eq(*arg, *zero))
2114 return false;
2115 if (is_a_Number(*arg)) {
2116 if (down_cast<const Number &>(*arg).is_negative()) {
2117 return false;
2118 } else if (not down_cast<const Number &>(*arg).is_exact()) {
2119 return false;
2120 }
2121 }
2123 return false;
2124 return true;
2125}
2126
2127RCP<const Basic> sinh(const RCP<const Basic> &arg)
2128{
2129 if (eq(*arg, *zero))
2130 return zero;
2131 if (is_a_Number(*arg)) {
2132 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2133 if (not _arg->is_exact()) {
2134 return _arg->get_eval().sinh(*_arg);
2135 } else if (_arg->is_negative()) {
2136 return neg(sinh(zero->sub(*_arg)));
2137 }
2138 }
2139 RCP<const Basic> d;
2140 bool b = handle_minus(arg, outArg(d));
2141 if (b) {
2142 return neg(sinh(d));
2143 }
2144 return make_rcp<const Sinh>(d);
2145}
2146
2147Csch::Csch(const RCP<const Basic> &arg) : HyperbolicFunction(arg)
2148{
2149 SYMENGINE_ASSIGN_TYPEID()
2150 SYMENGINE_ASSERT(is_canonical(arg))
2151}
2152
2153bool Csch::is_canonical(const RCP<const Basic> &arg) const
2154{
2155 if (eq(*arg, *zero))
2156 return false;
2157 if (is_a_Number(*arg)) {
2158 if (down_cast<const Number &>(*arg).is_negative()) {
2159 return false;
2160 } else if (not down_cast<const Number &>(*arg).is_exact()) {
2161 return false;
2162 }
2163 }
2165 return false;
2166 return true;
2167}
2168
2169RCP<const Basic> csch(const RCP<const Basic> &arg)
2170{
2171 if (eq(*arg, *zero)) {
2172 return ComplexInf;
2173 }
2174 if (is_a_Number(*arg)) {
2175 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2176 if (not _arg->is_exact()) {
2177 return _arg->get_eval().csch(*_arg);
2178 } else if (_arg->is_negative()) {
2179 return neg(csch(zero->sub(*_arg)));
2180 }
2181 }
2182 RCP<const Basic> d;
2183 bool b = handle_minus(arg, outArg(d));
2184 if (b) {
2185 return neg(csch(d));
2186 }
2187 return make_rcp<const Csch>(d);
2188}
2189
2190Cosh::Cosh(const RCP<const Basic> &arg) : HyperbolicFunction(arg)
2191{
2192 SYMENGINE_ASSIGN_TYPEID()
2193 SYMENGINE_ASSERT(is_canonical(arg))
2194}
2195
2196bool Cosh::is_canonical(const RCP<const Basic> &arg) const
2197{
2198 if (eq(*arg, *zero))
2199 return false;
2200 if (is_a_Number(*arg)) {
2201 if (down_cast<const Number &>(*arg).is_negative()) {
2202 return false;
2203 } else if (not down_cast<const Number &>(*arg).is_exact()) {
2204 return false;
2205 }
2206 }
2208 return false;
2209 return true;
2210}
2211
2212RCP<const Basic> cosh(const RCP<const Basic> &arg)
2213{
2214 if (eq(*arg, *zero))
2215 return one;
2216 if (is_a_Number(*arg)) {
2217 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2218 if (not _arg->is_exact()) {
2219 return _arg->get_eval().cosh(*_arg);
2220 } else if (_arg->is_negative()) {
2221 return cosh(zero->sub(*_arg));
2222 }
2223 }
2224 RCP<const Basic> d;
2225 handle_minus(arg, outArg(d));
2226 return make_rcp<const Cosh>(d);
2227}
2228
2229Sech::Sech(const RCP<const Basic> &arg) : HyperbolicFunction(arg)
2230{
2231 SYMENGINE_ASSIGN_TYPEID()
2232 SYMENGINE_ASSERT(is_canonical(arg))
2233}
2234
2235bool Sech::is_canonical(const RCP<const Basic> &arg) const
2236{
2237 if (eq(*arg, *zero))
2238 return false;
2239 if (is_a_Number(*arg)) {
2240 if (down_cast<const Number &>(*arg).is_negative()) {
2241 return false;
2242 } else if (not down_cast<const Number &>(*arg).is_exact()) {
2243 return false;
2244 }
2245 }
2247 return false;
2248 return true;
2249}
2250
2251RCP<const Basic> sech(const RCP<const Basic> &arg)
2252{
2253 if (eq(*arg, *zero))
2254 return one;
2255 if (is_a_Number(*arg)) {
2256 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2257 if (not _arg->is_exact()) {
2258 return _arg->get_eval().sech(*_arg);
2259 } else if (_arg->is_negative()) {
2260 return sech(zero->sub(*_arg));
2261 }
2262 }
2263 RCP<const Basic> d;
2264 handle_minus(arg, outArg(d));
2265 return make_rcp<const Sech>(d);
2266}
2267
2268Tanh::Tanh(const RCP<const Basic> &arg) : HyperbolicFunction(arg)
2269{
2270 SYMENGINE_ASSIGN_TYPEID()
2271 SYMENGINE_ASSERT(is_canonical(arg))
2272}
2273
2274bool Tanh::is_canonical(const RCP<const Basic> &arg) const
2275{
2276 if (eq(*arg, *zero))
2277 return false;
2278 if (is_a_Number(*arg)) {
2279 if (down_cast<const Number &>(*arg).is_negative()) {
2280 return false;
2281 } else if (not down_cast<const Number &>(*arg).is_exact()) {
2282 return false;
2283 }
2284 }
2286 return false;
2287 return true;
2288}
2289
2290RCP<const Basic> tanh(const RCP<const Basic> &arg)
2291{
2292 if (eq(*arg, *zero))
2293 return zero;
2294 if (is_a_Number(*arg)) {
2295 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2296 if (not _arg->is_exact()) {
2297 return _arg->get_eval().tanh(*_arg);
2298 } else if (_arg->is_negative()) {
2299 return neg(tanh(zero->sub(*_arg)));
2300 }
2301 }
2302
2303 RCP<const Basic> d;
2304 bool b = handle_minus(arg, outArg(d));
2305 if (b) {
2306 return neg(tanh(d));
2307 }
2308 return make_rcp<const Tanh>(d);
2309}
2310
2311Coth::Coth(const RCP<const Basic> &arg) : HyperbolicFunction(arg)
2312{
2313 SYMENGINE_ASSIGN_TYPEID()
2314 SYMENGINE_ASSERT(is_canonical(arg))
2315}
2316
2317bool Coth::is_canonical(const RCP<const Basic> &arg) const
2318{
2319 if (eq(*arg, *zero))
2320 return false;
2321 if (is_a_Number(*arg)) {
2322 if (down_cast<const Number &>(*arg).is_negative()) {
2323 return false;
2324 } else if (not down_cast<const Number &>(*arg).is_exact()) {
2325 return false;
2326 }
2327 }
2329 return false;
2330 return true;
2331}
2332
2333RCP<const Basic> coth(const RCP<const Basic> &arg)
2334{
2335 if (eq(*arg, *zero)) {
2336 return ComplexInf;
2337 }
2338 if (is_a_Number(*arg)) {
2339 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2340 if (not _arg->is_exact()) {
2341 return _arg->get_eval().coth(*_arg);
2342 } else if (_arg->is_negative()) {
2343 return neg(coth(zero->sub(*_arg)));
2344 }
2345 }
2346 RCP<const Basic> d;
2347 bool b = handle_minus(arg, outArg(d));
2348 if (b) {
2349 return neg(coth(d));
2350 }
2351 return make_rcp<const Coth>(d);
2352}
2353
2355{
2356 SYMENGINE_ASSIGN_TYPEID()
2357 SYMENGINE_ASSERT(is_canonical(arg))
2358}
2359
2360bool ASinh::is_canonical(const RCP<const Basic> &arg) const
2361{
2362 if (eq(*arg, *zero) or eq(*arg, *one) or eq(*arg, *minus_one))
2363 return false;
2364 if (is_a_Number(*arg)) {
2365 if (down_cast<const Number &>(*arg).is_negative()) {
2366 return false;
2367 } else if (not down_cast<const Number &>(*arg).is_exact()) {
2368 return false;
2369 }
2370 }
2372 return false;
2373 return true;
2374}
2375
2376RCP<const Basic> asinh(const RCP<const Basic> &arg)
2377{
2378 if (eq(*arg, *zero))
2379 return zero;
2380 if (eq(*arg, *one))
2381 return log(add(one, sq2));
2382 if (eq(*arg, *minus_one))
2383 return log(sub(sq2, one));
2384 if (is_a_Number(*arg)) {
2385 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2386 if (not _arg->is_exact()) {
2387 return _arg->get_eval().asinh(*_arg);
2388 } else if (_arg->is_negative()) {
2389 return neg(asinh(zero->sub(*_arg)));
2390 }
2391 }
2392 RCP<const Basic> d;
2393 bool b = handle_minus(arg, outArg(d));
2394 if (b) {
2395 return neg(asinh(d));
2396 }
2397 return make_rcp<const ASinh>(d);
2398}
2399
2401{
2402 SYMENGINE_ASSIGN_TYPEID()
2403 SYMENGINE_ASSERT(is_canonical(arg))
2404}
2405
2406bool ACsch::is_canonical(const RCP<const Basic> &arg) const
2407{
2408 if (eq(*arg, *one) or eq(*arg, *minus_one))
2409 return false;
2410 if (is_a_Number(*arg)) {
2411 if (down_cast<const Number &>(*arg).is_negative()) {
2412 return false;
2413 } else if (not down_cast<const Number &>(*arg).is_exact()) {
2414 return false;
2415 }
2416 }
2418 return false;
2419 return true;
2420}
2421
2422RCP<const Basic> acsch(const RCP<const Basic> &arg)
2423{
2424 if (eq(*arg, *one))
2425 return log(add(one, sq2));
2426 if (eq(*arg, *minus_one))
2427 return log(sub(sq2, one));
2428
2429 if (is_a_Number(*arg)) {
2430 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2431 if (not _arg->is_exact()) {
2432 return _arg->get_eval().acsch(*_arg);
2433 }
2434 }
2435
2436 RCP<const Basic> d;
2437 bool b = handle_minus(arg, outArg(d));
2438 if (b) {
2439 return neg(acsch(d));
2440 }
2441 return make_rcp<const ACsch>(d);
2442}
2443
2445{
2446 SYMENGINE_ASSIGN_TYPEID()
2447 SYMENGINE_ASSERT(is_canonical(arg))
2448}
2449
2450bool ACosh::is_canonical(const RCP<const Basic> &arg) const
2451{
2452 // TODO: Lookup into a cst table once complex is implemented
2453 if (eq(*arg, *one))
2454 return false;
2455 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
2456 return false;
2457 }
2458 return true;
2459}
2460
2461RCP<const Basic> acosh(const RCP<const Basic> &arg)
2462{
2463 // TODO: Lookup into a cst table once complex is implemented
2464 if (eq(*arg, *one))
2465 return zero;
2466 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
2467 return down_cast<const Number &>(*arg).get_eval().acosh(*arg);
2468 }
2469 return make_rcp<const ACosh>(arg);
2470}
2471
2473{
2474 SYMENGINE_ASSIGN_TYPEID()
2475 SYMENGINE_ASSERT(is_canonical(arg))
2476}
2477
2478bool ATanh::is_canonical(const RCP<const Basic> &arg) const
2479{
2480 if (eq(*arg, *zero))
2481 return false;
2482 if (is_a_Number(*arg)) {
2483 if (down_cast<const Number &>(*arg).is_negative()) {
2484 return false;
2485 } else if (not down_cast<const Number &>(*arg).is_exact()) {
2486 return false;
2487 }
2488 }
2490 return false;
2491 return true;
2492}
2493
2494RCP<const Basic> atanh(const RCP<const Basic> &arg)
2495{
2496 if (eq(*arg, *zero))
2497 return zero;
2498 if (is_a_Number(*arg)) {
2499 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2500 if (not _arg->is_exact()) {
2501 return _arg->get_eval().atanh(*_arg);
2502 } else if (_arg->is_negative()) {
2503 return neg(atanh(zero->sub(*_arg)));
2504 }
2505 }
2506 RCP<const Basic> d;
2507 bool b = handle_minus(arg, outArg(d));
2508 if (b) {
2509 return neg(atanh(d));
2510 }
2511 return make_rcp<const ATanh>(d);
2512}
2513
2515{
2516 SYMENGINE_ASSIGN_TYPEID()
2517 SYMENGINE_ASSERT(is_canonical(arg))
2518}
2519
2520bool ACoth::is_canonical(const RCP<const Basic> &arg) const
2521{
2522 if (is_a_Number(*arg)) {
2523 if (down_cast<const Number &>(*arg).is_negative()) {
2524 return false;
2525 } else if (not down_cast<const Number &>(*arg).is_exact()) {
2526 return false;
2527 }
2528 }
2530 return false;
2531 return true;
2532}
2533
2534RCP<const Basic> acoth(const RCP<const Basic> &arg)
2535{
2536 if (is_a_Number(*arg)) {
2537 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2538 if (not _arg->is_exact()) {
2539 return _arg->get_eval().acoth(*_arg);
2540 } else if (_arg->is_negative()) {
2541 return neg(acoth(zero->sub(*_arg)));
2542 }
2543 }
2544 RCP<const Basic> d;
2545 bool b = handle_minus(arg, outArg(d));
2546 if (b) {
2547 return neg(acoth(d));
2548 }
2549 return make_rcp<const ACoth>(d);
2550}
2551
2553{
2554 SYMENGINE_ASSIGN_TYPEID()
2555 SYMENGINE_ASSERT(is_canonical(arg))
2556}
2557
2558bool ASech::is_canonical(const RCP<const Basic> &arg) const
2559{
2560 // TODO: Lookup into a cst table once complex is implemented
2561 if (eq(*arg, *one))
2562 return false;
2563 if (eq(*arg, *zero))
2564 return false;
2565 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
2566 return false;
2567 }
2568 return true;
2569}
2570
2571RCP<const Basic> asech(const RCP<const Basic> &arg)
2572{
2573 // TODO: Lookup into a cst table once complex is implemented
2574 if (eq(*arg, *one))
2575 return zero;
2576 if (eq(*arg, *zero))
2577 return Inf;
2578 if (is_a_Number(*arg)) {
2579 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2580 if (not _arg->is_exact()) {
2581 return _arg->get_eval().asech(*_arg);
2582 }
2583 }
2584 return make_rcp<const ASech>(arg);
2585}
2586
2587RCP<const Basic> Sinh::create(const RCP<const Basic> &arg) const
2588{
2589 return sinh(arg);
2590}
2591
2592RCP<const Basic> Csch::create(const RCP<const Basic> &arg) const
2593{
2594 return csch(arg);
2595}
2596
2597RCP<const Basic> Cosh::create(const RCP<const Basic> &arg) const
2598{
2599 return cosh(arg);
2600}
2601
2602RCP<const Basic> Sech::create(const RCP<const Basic> &arg) const
2603{
2604 return sech(arg);
2605}
2606
2607RCP<const Basic> Tanh::create(const RCP<const Basic> &arg) const
2608{
2609 return tanh(arg);
2610}
2611
2612RCP<const Basic> Coth::create(const RCP<const Basic> &arg) const
2613{
2614 return coth(arg);
2615}
2616
2617RCP<const Basic> ASinh::create(const RCP<const Basic> &arg) const
2618{
2619 return asinh(arg);
2620}
2621
2622RCP<const Basic> ACsch::create(const RCP<const Basic> &arg) const
2623{
2624 return acsch(arg);
2625}
2626
2627RCP<const Basic> ACosh::create(const RCP<const Basic> &arg) const
2628{
2629 return acosh(arg);
2630}
2631
2632RCP<const Basic> ATanh::create(const RCP<const Basic> &arg) const
2633{
2634 return atanh(arg);
2635}
2636
2637RCP<const Basic> ACoth::create(const RCP<const Basic> &arg) const
2638{
2639 return acoth(arg);
2640}
2641
2642RCP<const Basic> ASech::create(const RCP<const Basic> &arg) const
2643{
2644 return asech(arg);
2645}
2646
2647KroneckerDelta::KroneckerDelta(const RCP<const Basic> &i,
2648 const RCP<const Basic> &j)
2649 : TwoArgFunction(i, j)
2650{
2651 SYMENGINE_ASSIGN_TYPEID()
2652 SYMENGINE_ASSERT(is_canonical(i, j))
2653}
2654
2655bool KroneckerDelta::is_canonical(const RCP<const Basic> &i,
2656 const RCP<const Basic> &j) const
2657{
2658 RCP<const Basic> diff = expand(sub(i, j));
2659 if (eq(*diff, *zero)) {
2660 return false;
2661 } else if (is_a_Number(*diff)) {
2662 return false;
2663 } else {
2664 // TODO: SymPy uses default key sorting to return in order
2665 return true;
2666 }
2667}
2668
2669RCP<const Basic> KroneckerDelta::create(const RCP<const Basic> &a,
2670 const RCP<const Basic> &b) const
2671{
2672 return kronecker_delta(a, b);
2673}
2674
2675RCP<const Basic> kronecker_delta(const RCP<const Basic> &i,
2676 const RCP<const Basic> &j)
2677{
2678 // Expand is needed to simplify things like `i-(i+1)` to `-1`
2679 RCP<const Basic> diff = expand(sub(i, j));
2680 if (eq(*diff, *zero)) {
2681 return one;
2682 } else if (is_a_Number(*diff)) {
2683 return zero;
2684 } else {
2685 // SymPy uses default key sorting to return in order
2687 }
2688}
2689
2690bool has_dup(const vec_basic &arg)
2691{
2692 map_basic_basic d;
2693 auto it = d.end();
2694 for (const auto &p : arg) {
2695 it = d.find(p);
2696 if (it == d.end()) {
2697 insert(d, p, one);
2698 } else {
2699 return true;
2700 }
2701 }
2702 return false;
2703}
2704
2706{
2707 SYMENGINE_ASSIGN_TYPEID()
2708 SYMENGINE_ASSERT(is_canonical(get_vec()))
2709}
2710
2712{
2713 bool are_int = true;
2714 for (const auto &p : arg) {
2715 if (not(is_a_Number(*p))) {
2716 are_int = false;
2717 break;
2718 }
2719 }
2720 if (are_int) {
2721 return false;
2722 } else if (has_dup(arg)) {
2723 return false;
2724 } else {
2725 return true;
2726 }
2727}
2728
2729RCP<const Basic> LeviCivita::create(const vec_basic &a) const
2730{
2731 return levi_civita(a);
2732}
2733
2734RCP<const Basic> eval_levicivita(const vec_basic &arg, int len)
2735{
2736 int i, j;
2737 RCP<const Basic> res = one;
2738 for (i = 0; i < len; i++) {
2739 for (j = i + 1; j < len; j++) {
2740 res = mul(sub(arg[j], arg[i]), res);
2741 }
2742 res = div(res, factorial(i));
2743 }
2744 return res;
2745}
2746
2747RCP<const Basic> levi_civita(const vec_basic &arg)
2748{
2749 bool are_int = true;
2750 int len = 0;
2751 for (const auto &p : arg) {
2752 if (not(is_a_Number(*p))) {
2753 are_int = false;
2754 break;
2755 } else {
2756 len++;
2757 }
2758 }
2759 if (are_int) {
2760 return eval_levicivita(arg, len);
2761 } else if (has_dup(arg)) {
2762 return zero;
2763 } else {
2765 }
2766}
2767
2768Zeta::Zeta(const RCP<const Basic> &s, const RCP<const Basic> &a)
2769 : TwoArgFunction(s, a){SYMENGINE_ASSIGN_TYPEID()
2770 SYMENGINE_ASSERT(is_canonical(s, a))}
2771
2772 Zeta::Zeta(const RCP<const Basic> &s)
2773 : TwoArgFunction(s, one)
2774{
2775 SYMENGINE_ASSIGN_TYPEID()
2776 SYMENGINE_ASSERT(is_canonical(s, one))
2777}
2778
2779bool Zeta::is_canonical(const RCP<const Basic> &s,
2780 const RCP<const Basic> &a) const
2781{
2782 if (eq(*s, *zero))
2783 return false;
2784 if (eq(*s, *one))
2785 return false;
2786 if (is_a<Integer>(*s) and is_a<Integer>(*a)) {
2787 auto s_ = down_cast<const Integer &>(*s).as_int();
2788 if (s_ < 0 || s_ % 2 == 0)
2789 return false;
2790 }
2791 return true;
2792}
2793
2794RCP<const Basic> Zeta::create(const RCP<const Basic> &a,
2795 const RCP<const Basic> &b) const
2796{
2797 return zeta(a, b);
2798}
2799
2800RCP<const Basic> zeta(const RCP<const Basic> &s, const RCP<const Basic> &a)
2801{
2802 if (is_a_Number(*s)) {
2803 if (down_cast<const Number &>(*s).is_zero()) {
2804 return sub(div(one, i2), a);
2805 } else if (down_cast<const Number &>(*s).is_one()) {
2806 return infty(0);
2807 } else if (is_a<Integer>(*s) and is_a<Integer>(*a)) {
2808 auto s_ = down_cast<const Integer &>(*s).as_int();
2809 auto a_ = down_cast<const Integer &>(*a).as_int();
2810 RCP<const Basic> zeta;
2811 if (s_ < 0) {
2812 RCP<const Number> res = (s_ % 2 == 0) ? one : minus_one;
2813 zeta
2814 = mulnum(res, divnum(bernoulli(-s_ + 1), integer(-s_ + 1)));
2815 } else if (s_ % 2 == 0) {
2816 RCP<const Number> b = bernoulli(s_);
2817 RCP<const Number> f = factorial(s_);
2818 zeta = divnum(pownum(integer(2), integer(s_ - 1)), f);
2819 zeta = mul(zeta, mul(pow(pi, s), abs(b)));
2820 } else {
2821 return make_rcp<const Zeta>(s, a);
2822 }
2823 if (a_ < 0)
2824 return add(zeta, harmonic(-a_, s_));
2825 return sub(zeta, harmonic(a_ - 1, s_));
2826 }
2827 }
2828 return make_rcp<const Zeta>(s, a);
2829}
2830
2831RCP<const Basic> zeta(const RCP<const Basic> &s)
2832{
2833 return zeta(s, one);
2834}
2835
2836Dirichlet_eta::Dirichlet_eta(const RCP<const Basic> &s) : OneArgFunction(s)
2837{
2838 SYMENGINE_ASSIGN_TYPEID()
2839 SYMENGINE_ASSERT(is_canonical(s))
2840}
2841
2842bool Dirichlet_eta::is_canonical(const RCP<const Basic> &s) const
2843{
2844 if (eq(*s, *one))
2845 return false;
2846 if (not(is_a<Zeta>(*zeta(s))))
2847 return false;
2848 return true;
2849}
2850
2851RCP<const Basic> Dirichlet_eta::rewrite_as_zeta() const
2852{
2853 return mul(sub(one, pow(i2, sub(one, get_arg()))), zeta(get_arg()));
2854}
2855
2856RCP<const Basic> Dirichlet_eta::create(const RCP<const Basic> &arg) const
2857{
2858 return dirichlet_eta(arg);
2859}
2860
2861RCP<const Basic> dirichlet_eta(const RCP<const Basic> &s)
2862{
2863 if (is_a_Number(*s) and down_cast<const Number &>(*s).is_one()) {
2864 return log(i2);
2865 }
2866 RCP<const Basic> z = zeta(s);
2867 if (is_a<Zeta>(*z)) {
2869 } else {
2870 return mul(sub(one, pow(i2, sub(one, s))), z);
2871 }
2872}
2873
2874bool Erf::is_canonical(const RCP<const Basic> &arg) const
2875{
2876 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
2877 return false;
2879 return false;
2880 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
2881 return false;
2882 }
2883 return true;
2884}
2885
2886RCP<const Basic> Erf::create(const RCP<const Basic> &arg) const
2887{
2888 return erf(arg);
2889}
2890
2891RCP<const Basic> erf(const RCP<const Basic> &arg)
2892{
2893 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero()) {
2894 return zero;
2895 }
2896 if (is_a_Number(*arg)) {
2897 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2898 if (not _arg->is_exact()) {
2899 return _arg->get_eval().erf(*_arg);
2900 }
2901 }
2902 RCP<const Basic> d;
2903 bool b = handle_minus(arg, outArg(d));
2904 if (b) {
2905 return neg(erf(d));
2906 }
2907 return make_rcp<const Erf>(d);
2908}
2909
2910bool Erfc::is_canonical(const RCP<const Basic> &arg) const
2911{
2912 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
2913 return false;
2915 return false;
2916 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
2917 return false;
2918 }
2919 return true;
2920}
2921
2922RCP<const Basic> Erfc::create(const RCP<const Basic> &arg) const
2923{
2924 return erfc(arg);
2925}
2926
2927RCP<const Basic> erfc(const RCP<const Basic> &arg)
2928{
2929 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero()) {
2930 return one;
2931 }
2932 if (is_a_Number(*arg)) {
2933 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2934 if (not _arg->is_exact()) {
2935 return _arg->get_eval().erfc(*_arg);
2936 }
2937 }
2938
2939 RCP<const Basic> d;
2940 bool b = handle_minus(arg, outArg(d));
2941 if (b) {
2942 return add(integer(2), neg(erfc(d)));
2943 }
2944 return make_rcp<const Erfc>(d);
2945}
2946
2947Gamma::Gamma(const RCP<const Basic> &arg) : OneArgFunction{arg}
2948{
2949 SYMENGINE_ASSIGN_TYPEID()
2950 SYMENGINE_ASSERT(is_canonical(arg))
2951}
2952
2953bool Gamma::is_canonical(const RCP<const Basic> &arg) const
2954{
2955 if (is_a<Integer>(*arg))
2956 return false;
2957 if (is_a<Rational>(*arg)
2958 and (get_den(down_cast<const Rational &>(*arg).as_rational_class()))
2959 == 2) {
2960 return false;
2961 }
2962 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
2963 return false;
2964 }
2965 return true;
2966}
2967
2968RCP<const Basic> Gamma::create(const RCP<const Basic> &arg) const
2969{
2970 return gamma(arg);
2971}
2972
2973RCP<const Basic> gamma_positive_int(const RCP<const Basic> &arg)
2974{
2975 SYMENGINE_ASSERT(is_a<Integer>(*arg))
2977 SYMENGINE_ASSERT(arg_->is_positive())
2978 return factorial((arg_->subint(*one))->as_int());
2979}
2980
2981RCP<const Basic> gamma_multiple_2(const RCP<const Basic> &arg)
2982{
2983 SYMENGINE_ASSERT(is_a<Rational>(*arg))
2985 SYMENGINE_ASSERT(get_den(arg_->as_rational_class()) == 2)
2986 RCP<const Integer> n, k;
2987 RCP<const Number> coeff;
2988 n = quotient_f(*(integer(mp_abs(get_num(arg_->as_rational_class())))),
2989 *(integer(get_den(arg_->as_rational_class()))));
2990 if (arg_->is_positive()) {
2991 k = n;
2992 coeff = one;
2993 } else {
2994 n = n->addint(*one);
2995 k = n;
2996 if ((n->as_int() & 1) == 0) {
2997 coeff = one;
2998 } else {
2999 coeff = minus_one;
3000 }
3001 }
3002 int j = 1;
3003 for (int i = 3; i < 2 * k->as_int(); i = i + 2) {
3004 j = j * i;
3005 }
3006 coeff = mulnum(coeff, integer(j));
3007 if (arg_->is_positive()) {
3008 return div(mul(coeff, sqrt(pi)), pow(i2, n));
3009 } else {
3010 return div(mul(pow(i2, n), sqrt(pi)), coeff);
3011 }
3012}
3013
3014RCP<const Basic> gamma(const RCP<const Basic> &arg)
3015{
3016 if (is_a<Integer>(*arg)) {
3018 if (arg_->is_positive()) {
3019 return gamma_positive_int(arg);
3020 } else {
3021 return ComplexInf;
3022 }
3023 } else if (is_a<Rational>(*arg)) {
3025 if ((get_den(arg_->as_rational_class())) == 2) {
3026 return gamma_multiple_2(arg);
3027 } else {
3028 return make_rcp<const Gamma>(arg);
3029 }
3030 } else if (is_a_Number(*arg)
3031 and not down_cast<const Number &>(*arg).is_exact()) {
3032 return down_cast<const Number &>(*arg).get_eval().gamma(*arg);
3033 }
3034 return make_rcp<const Gamma>(arg);
3035}
3036
3037LowerGamma::LowerGamma(const RCP<const Basic> &s, const RCP<const Basic> &x)
3038 : TwoArgFunction(s, x)
3039{
3040 SYMENGINE_ASSIGN_TYPEID()
3041 SYMENGINE_ASSERT(is_canonical(s, x))
3042}
3043
3044bool LowerGamma::is_canonical(const RCP<const Basic> &s,
3045 const RCP<const Basic> &x) const
3046{
3047 // Only special values are evaluated
3048 if (eq(*s, *one))
3049 return false;
3050 if (is_a<Integer>(*s)
3051 and down_cast<const Integer &>(*s).as_integer_class() > 1)
3052 return false;
3053 if (is_a<Integer>(*mul(i2, s)))
3054 return false;
3055#ifdef HAVE_SYMENGINE_MPFR
3056#if MPFR_VERSION_MAJOR > 3
3057 if (is_a<RealMPFR>(*s) && is_a<RealMPFR>(*x))
3058 return false;
3059#endif
3060#endif
3061 return true;
3062}
3063
3064RCP<const Basic> LowerGamma::create(const RCP<const Basic> &a,
3065 const RCP<const Basic> &b) const
3066{
3067 return lowergamma(a, b);
3068}
3069
3070RCP<const Basic> lowergamma(const RCP<const Basic> &s,
3071 const RCP<const Basic> &x)
3072{
3073 // Only special values are being evaluated
3074 if (is_a<Integer>(*s)) {
3076 if (s_int->is_one()) {
3077 return sub(one, exp(mul(minus_one, x)));
3078 } else if (s_int->as_integer_class() > 1) {
3079 s_int = s_int->subint(*one);
3080 return sub(mul(s_int, lowergamma(s_int, x)),
3081 mul(pow(x, s_int), exp(mul(minus_one, x))));
3082 } else {
3083 return make_rcp<const LowerGamma>(s, x);
3084 }
3085 } else if (is_a<Integer>(*(mul(i2, s)))) {
3086 RCP<const Number> s_num = rcp_static_cast<const Number>(s);
3087 s_num = subnum(s_num, one);
3088 if (eq(*s, *div(one, integer(2)))) {
3089 return mul(sqrt(pi),
3090 erf(sqrt(x))); // base case for s of the form n/2
3091 } else if (s_num->is_positive()) {
3092 return sub(mul(s_num, lowergamma(s_num, x)),
3093 mul(pow(x, s_num), exp(mul(minus_one, x))));
3094 } else {
3095 return div(add(lowergamma(add(s, one), x),
3096 mul(pow(x, s), exp(mul(minus_one, x)))),
3097 s);
3098 }
3099#ifdef HAVE_SYMENGINE_MPFR
3100#if MPFR_VERSION_MAJOR > 3
3101 } else if (is_a<RealMPFR>(*s) && is_a<RealMPFR>(*x)) {
3102 const auto &s_ = down_cast<const RealMPFR &>(*s).i.get_mpfr_t();
3103 const auto &x_ = down_cast<const RealMPFR &>(*x).i.get_mpfr_t();
3104 if (mpfr_cmp_si(x_, 0) >= 0) {
3107 mpfr_gamma_inc(t.get_mpfr_t(), s_, x_, MPFR_RNDN);
3108 mpfr_gamma(u.get_mpfr_t(), s_, MPFR_RNDN);
3109 mpfr_sub(t.get_mpfr_t(), u.get_mpfr_t(), t.get_mpfr_t(), MPFR_RNDN);
3110 return real_mpfr(std::move(t));
3111 } else {
3112 throw NotImplementedError("Not implemented.");
3113 }
3114#endif
3115#endif
3116 }
3117 return make_rcp<const LowerGamma>(s, x);
3118}
3119
3120UpperGamma::UpperGamma(const RCP<const Basic> &s, const RCP<const Basic> &x)
3121 : TwoArgFunction(s, x)
3122{
3123 SYMENGINE_ASSIGN_TYPEID()
3124 SYMENGINE_ASSERT(is_canonical(s, x))
3125}
3126
3127bool UpperGamma::is_canonical(const RCP<const Basic> &s,
3128 const RCP<const Basic> &x) const
3129{
3130 // Only special values are evaluated
3131 if (eq(*s, *one))
3132 return false;
3133 if (is_a<Integer>(*s)
3134 and down_cast<const Integer &>(*s).as_integer_class() > 1)
3135 return false;
3136 if (is_a<Integer>(*mul(i2, s)))
3137 return false;
3138#ifdef HAVE_SYMENGINE_MPFR
3139#if MPFR_VERSION_MAJOR > 3
3140 if (is_a<RealMPFR>(*s) && is_a<RealMPFR>(*x))
3141 return false;
3142#endif
3143#endif
3144 return true;
3145}
3146
3147RCP<const Basic> UpperGamma::create(const RCP<const Basic> &a,
3148 const RCP<const Basic> &b) const
3149{
3150 return uppergamma(a, b);
3151}
3152
3153RCP<const Basic> uppergamma(const RCP<const Basic> &s,
3154 const RCP<const Basic> &x)
3155{
3156 // Only special values are being evaluated
3157 if (is_a<Integer>(*s)) {
3159 if (s_int->is_one()) {
3160 return exp(mul(minus_one, x));
3161 } else if (s_int->as_integer_class() > 1) {
3162 s_int = s_int->subint(*one);
3163 return add(mul(s_int, uppergamma(s_int, x)),
3164 mul(pow(x, s_int), exp(mul(minus_one, x))));
3165 } else {
3166 // TODO: implement unpolarfy to handle this case
3167 return make_rcp<const LowerGamma>(s, x);
3168 }
3169 } else if (is_a<Integer>(*(mul(i2, s)))) {
3170 RCP<const Number> s_num = rcp_static_cast<const Number>(s);
3171 s_num = subnum(s_num, one);
3172 if (eq(*s, *div(one, integer(2)))) {
3173 return mul(sqrt(pi),
3174 erfc(sqrt(x))); // base case for s of the form n/2
3175 } else if (s_num->is_positive()) {
3176 return add(mul(s_num, uppergamma(s_num, x)),
3177 mul(pow(x, s_num), exp(mul(minus_one, x))));
3178 } else {
3179 return div(sub(uppergamma(add(s, one), x),
3180 mul(pow(x, s), exp(mul(minus_one, x)))),
3181 s);
3182 }
3183#ifdef HAVE_SYMENGINE_MPFR
3184#if MPFR_VERSION_MAJOR > 3
3185 } else if (is_a<RealMPFR>(*s) && is_a<RealMPFR>(*x)) {
3186 const auto &s_ = down_cast<const RealMPFR &>(*s).i.get_mpfr_t();
3187 const auto &x_ = down_cast<const RealMPFR &>(*x).i.get_mpfr_t();
3188 if (mpfr_cmp_si(x_, 0) >= 0) {
3190 mpfr_gamma_inc(t.get_mpfr_t(), s_, x_, MPFR_RNDN);
3191 return real_mpfr(std::move(t));
3192 } else {
3193 throw NotImplementedError("Not implemented.");
3194 }
3195#endif
3196#endif
3197 }
3198 return make_rcp<const UpperGamma>(s, x);
3199}
3200
3201bool LogGamma::is_canonical(const RCP<const Basic> &arg) const
3202{
3203 if (is_a<Integer>(*arg)) {
3205 if (not arg_int->is_positive()) {
3206 return false;
3207 }
3208 if (eq(*integer(1), *arg_int) or eq(*integer(2), *arg_int)
3209 or eq(*integer(3), *arg_int)) {
3210 return false;
3211 }
3212 }
3213 return true;
3214}
3215
3216RCP<const Basic> LogGamma::rewrite_as_gamma() const
3217{
3218 return log(gamma(get_arg()));
3219}
3220
3221RCP<const Basic> LogGamma::create(const RCP<const Basic> &arg) const
3222{
3223 return loggamma(arg);
3224}
3225
3226RCP<const Basic> loggamma(const RCP<const Basic> &arg)
3227{
3228 if (is_a<Integer>(*arg)) {
3230 if (not arg_int->is_positive()) {
3231 return Inf;
3232 }
3233 if (eq(*integer(1), *arg_int) or eq(*integer(2), *arg_int)) {
3234 return zero;
3235 } else if (eq(*integer(3), *arg_int)) {
3236 return log(integer(2));
3237 }
3238 }
3240}
3241
3242RCP<const Beta> Beta::from_two_basic(const RCP<const Basic> &x,
3243 const RCP<const Basic> &y)
3244{
3245 if (x->__cmp__(*y) == -1) {
3246 return make_rcp<const Beta>(y, x);
3247 }
3248 return make_rcp<const Beta>(x, y);
3249}
3250
3251bool Beta::is_canonical(const RCP<const Basic> &x, const RCP<const Basic> &y)
3252{
3253 if (x->__cmp__(*y) == -1) {
3254 return false;
3255 }
3256 if (is_a<Integer>(*x)
3257 or (is_a<Rational>(*x)
3258 and (get_den(down_cast<const Rational &>(*x).as_rational_class()))
3259 == 2)) {
3260 if (is_a<Integer>(*y)
3262 and (get_den(
3263 down_cast<const Rational &>(*y).as_rational_class()))
3264 == 2)) {
3265 return false;
3266 }
3267 }
3268 return true;
3269}
3270
3271RCP<const Basic> Beta::rewrite_as_gamma() const
3272{
3273 return div(mul(gamma(get_arg1()), gamma(get_arg2())),
3274 gamma(add(get_arg1(), get_arg2())));
3275}
3276
3277RCP<const Basic> Beta::create(const RCP<const Basic> &a,
3278 const RCP<const Basic> &b) const
3279{
3280 return beta(a, b);
3281}
3282
3283RCP<const Basic> beta(const RCP<const Basic> &x, const RCP<const Basic> &y)
3284{
3285 // Only special values are being evaluated
3286 if (eq(*add(x, y), *one)) {
3287 return ComplexInf;
3288 }
3289
3290 if (is_a<Integer>(*x)) {
3292 if (x_int->is_positive()) {
3293 if (is_a<Integer>(*y)) {
3295 if (y_int->is_positive()) {
3296 return div(
3297 mul(gamma_positive_int(x), gamma_positive_int(y)),
3298 gamma_positive_int(add(x, y)));
3299 } else {
3300 return ComplexInf;
3301 }
3302 } else if (is_a<Rational>(*y)) {
3304 if (get_den(y_->as_rational_class()) == 2) {
3305 return div(mul(gamma_positive_int(x), gamma_multiple_2(y)),
3306 gamma_multiple_2(add(x, y)));
3307 } else {
3308 return Beta::from_two_basic(x, y);
3309 }
3310 }
3311 } else {
3312 return ComplexInf;
3313 }
3314 }
3315
3316 if (is_a<Integer>(*y)) {
3318 if (y_int->is_positive()) {
3319 if (is_a<Rational>(*x)) {
3321 if (get_den(x_->as_rational_class()) == 2) {
3322 return div(mul(gamma_positive_int(y), gamma_multiple_2(x)),
3323 gamma_multiple_2(add(x, y)));
3324 } else {
3325 return Beta::from_two_basic(x, y);
3326 }
3327 }
3328 } else {
3329 return ComplexInf;
3330 }
3331 }
3332
3333 if (is_a<const Rational>(*x)
3334 and get_den(down_cast<const Rational &>(*x).as_rational_class()) == 2) {
3335 if (is_a<Integer>(*y)) {
3337 if (y_int->is_positive()) {
3338 return div(mul(gamma_multiple_2(x), gamma_positive_int(y)),
3339 gamma_multiple_2(add(x, y)));
3340 } else {
3341 return ComplexInf;
3342 }
3343 }
3345 and get_den((down_cast<const Rational &>(*y)).as_rational_class())
3346 == 2) {
3347 return div(mul(gamma_multiple_2(x), gamma_multiple_2(y)),
3348 gamma_positive_int(add(x, y)));
3349 }
3350 }
3351 return Beta::from_two_basic(x, y);
3352}
3353
3354bool PolyGamma::is_canonical(const RCP<const Basic> &n,
3355 const RCP<const Basic> &x)
3356{
3357 if (is_a_Number(*x) and not(down_cast<const Number &>(*x)).is_positive()) {
3358 return false;
3359 }
3360 if (eq(*n, *zero)) {
3361 if (eq(*x, *one)) {
3362 return false;
3363 }
3364 if (is_a<Rational>(*x)) {
3366 auto den = get_den(x_->as_rational_class());
3367 if (den == 2 or den == 3 or den == 4) {
3368 return false;
3369 }
3370 }
3371 }
3372 return true;
3373}
3374
3375RCP<const Basic> PolyGamma::rewrite_as_zeta() const
3376{
3377 if (not is_a<Integer>(*get_arg1())) {
3378 return rcp_from_this();
3379 }
3381 if (not(n->is_positive())) {
3382 return rcp_from_this();
3383 }
3384 if ((n->as_int() & 1) == 0) {
3385 return neg(mul(factorial(n->as_int()), zeta(add(n, one), get_arg2())));
3386 } else {
3387 return mul(factorial(n->as_int()), zeta(add(n, one), get_arg2()));
3388 }
3389}
3390
3391RCP<const Basic> PolyGamma::create(const RCP<const Basic> &a,
3392 const RCP<const Basic> &b) const
3393{
3394 return polygamma(a, b);
3395}
3396
3397RCP<const Basic> polygamma(const RCP<const Basic> &n_,
3398 const RCP<const Basic> &x_)
3399{
3400 // Only special values are being evaluated
3401 if (is_a_Number(*x_)
3402 and not(down_cast<const Number &>(*x_)).is_positive()) {
3403 return ComplexInf;
3404 }
3405 if (is_a<Integer>(*n_) and is_a<Integer>(*x_)) {
3406 auto n = down_cast<const Integer &>(*n_).as_int();
3407 auto x = down_cast<const Integer &>(*x_).as_int();
3408 if (n == 0) {
3409 return sub(harmonic(x - 1, 1), EulerGamma);
3410 } else if (n % 2 == 1) {
3411 return mul(factorial(n), zeta(add(n_, one), x_));
3412 }
3413 }
3414 if (eq(*n_, *zero)) {
3415 if (eq(*x_, *one)) {
3416 return neg(EulerGamma);
3417 }
3418 if (is_a<Rational>(*x_)) {
3420 const auto den = get_den(x->as_rational_class());
3421 const auto num = get_num(x->as_rational_class());
3422 const integer_class r = num % den;
3423 RCP<const Basic> res;
3424 if (den == 2) {
3425 res = sub(mul(im2, log(i2)), EulerGamma);
3426 } else if (den == 3) {
3427 if (num == 1) {
3428 res = add(neg(div(div(pi, i2), sqrt(i3))),
3429 sub(div(mul(im3, log(i3)), i2), EulerGamma));
3430 } else {
3431 res = add(div(div(pi, i2), sqrt(i3)),
3432 sub(div(mul(im3, log(i3)), i2), EulerGamma));
3433 }
3434 } else if (den == 4) {
3435 if (num == 1) {
3436 res = add(div(pi, im2), sub(mul(im3, log(i2)), EulerGamma));
3437 } else {
3438 res = add(div(pi, i2), sub(mul(im3, log(i2)), EulerGamma));
3439 }
3440 } else {
3441 return make_rcp<const PolyGamma>(n_, x_);
3442 }
3443 rational_class a(0), f(r, den);
3444 for (unsigned long i = 0; i < (num - r) / den; ++i) {
3445 a += 1 / (f + i);
3446 }
3447 return add(Rational::from_mpq(a), res);
3448 }
3449 }
3450 return make_rcp<const PolyGamma>(n_, x_);
3451}
3452
3453RCP<const Basic> digamma(const RCP<const Basic> &x)
3454{
3455 return polygamma(zero, x);
3456}
3457
3458RCP<const Basic> trigamma(const RCP<const Basic> &x)
3459{
3460 return polygamma(one, x);
3461}
3462
3463Abs::Abs(const RCP<const Basic> &arg) : OneArgFunction(arg)
3464{
3465 SYMENGINE_ASSIGN_TYPEID()
3466 SYMENGINE_ASSERT(is_canonical(arg))
3467}
3468
3469bool Abs::is_canonical(const RCP<const Basic> &arg) const
3470{
3472 return false;
3473 if (is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
3474 return false;
3475 }
3476 if (is_a<Abs>(*arg)) {
3477 return false;
3478 }
3479
3480 if (could_extract_minus(*arg)) {
3481 return false;
3482 }
3483
3484 return true;
3485}
3486
3487RCP<const Basic> Abs::create(const RCP<const Basic> &arg) const
3488{
3489 return abs(arg);
3490}
3491
3492RCP<const Basic> abs(const RCP<const Basic> &arg)
3493{
3494 if (is_a<Integer>(*arg)) {
3496 if (arg_->is_negative()) {
3497 return arg_->neg();
3498 } else {
3499 return arg_;
3500 }
3501 } else if (is_a<Rational>(*arg)) {
3503 if (arg_->is_negative()) {
3504 return arg_->neg();
3505 } else {
3506 return arg_;
3507 }
3508 } else if (is_a<Complex>(*arg)) {
3510 return sqrt(Rational::from_mpq(arg_->real_ * arg_->real_
3511 + arg_->imaginary_ * arg_->imaginary_));
3512 } else if (is_a_Number(*arg)
3513 and not down_cast<const Number &>(*arg).is_exact()) {
3514 return down_cast<const Number &>(*arg).get_eval().abs(*arg);
3515 }
3516 if (is_a<Abs>(*arg)) {
3517 return arg;
3518 }
3519
3520 RCP<const Basic> d;
3521 handle_minus(arg, outArg(d));
3522 return make_rcp<const Abs>(d);
3523}
3524
3526{
3527 SYMENGINE_ASSIGN_TYPEID()
3528 SYMENGINE_ASSERT(is_canonical(get_vec()))
3529}
3530
3532{
3533 if (arg.size() < 2)
3534 return false;
3535
3536 bool non_number_exists = false;
3537
3538 for (const auto &p : arg) {
3539 if (is_a<Complex>(*p) or is_a<Max>(*p))
3540 return false;
3541 if (not is_a_Number(*p))
3542 non_number_exists = true;
3543 }
3544 if (not std::is_sorted(arg.begin(), arg.end(), RCPBasicKeyLess()))
3545 return false;
3546
3547 return non_number_exists; // all arguments cant be numbers
3548}
3549
3550RCP<const Basic> Max::create(const vec_basic &a) const
3551{
3552 return max(a);
3553}
3554
3555RCP<const Basic> max(const vec_basic &arg)
3556{
3557 bool number_set = false;
3558 RCP<const Number> max_number, difference;
3560
3561 for (const auto &p : arg) {
3562 if (is_a<Complex>(*p))
3563 throw SymEngineException("Complex can't be passed to max!");
3564
3565 if (is_a_Number(*p)) {
3566 if (not number_set) {
3568
3569 } else {
3570 if (eq(*p, *Inf)) {
3571 return Inf;
3572 } else if (eq(*p, *NegInf)) {
3573 continue;
3574 }
3576
3577 if (difference->is_zero() and not difference->is_exact()) {
3578 if (max_number->is_exact())
3580 } else if (difference->is_positive()) {
3582 }
3583 }
3584 number_set = true;
3585
3586 } else if (is_a<Max>(*p)) {
3587 for (const auto &l : down_cast<const Max &>(*p).get_args()) {
3588 if (is_a_Number(*l)) {
3589 if (not number_set) {
3591
3592 } else {
3594 *max_number);
3595
3596 if (difference->is_zero()
3597 and not difference->is_exact()) {
3598 if (max_number->is_exact())
3600 } else if (difference->is_positive()) {
3602 }
3603 }
3604 number_set = true;
3605 } else {
3606 new_args.insert(l);
3607 }
3608 }
3609 } else {
3610 new_args.insert(p);
3611 }
3612 }
3613
3614 if (number_set)
3615 new_args.insert(max_number);
3616
3618 std::copy(new_args.begin(), new_args.end(), final_args.begin());
3619
3620 if (final_args.size() > 1) {
3622 } else if (final_args.size() == 1) {
3623 return final_args[0];
3624 } else {
3625 throw SymEngineException("Empty vec_basic passed to max!");
3626 }
3627}
3628
3630{
3631 SYMENGINE_ASSIGN_TYPEID()
3632 SYMENGINE_ASSERT(is_canonical(get_vec()))
3633}
3634
3636{
3637 if (arg.size() < 2)
3638 return false;
3639
3640 bool non_number_exists = false;
3641
3642 for (const auto &p : arg) {
3643 if (is_a<Complex>(*p) or is_a<Min>(*p))
3644 return false;
3645 if (not is_a_Number(*p))
3646 non_number_exists = true;
3647 }
3648 if (not std::is_sorted(arg.begin(), arg.end(), RCPBasicKeyLess()))
3649 return false;
3650
3651 return non_number_exists; // all arguments cant be numbers
3652}
3653
3654RCP<const Basic> Min::create(const vec_basic &a) const
3655{
3656 return min(a);
3657}
3658
3659RCP<const Basic> min(const vec_basic &arg)
3660{
3661 bool number_set = false;
3662 RCP<const Number> min_number, difference;
3664
3665 for (const auto &p : arg) {
3666 if (is_a<Complex>(*p))
3667 throw SymEngineException("Complex can't be passed to min!");
3668
3669 if (is_a_Number(*p)) {
3670 if (not number_set) {
3672
3673 } else {
3674 if (eq(*p, *Inf)) {
3675 continue;
3676 } else if (eq(*p, *NegInf)) {
3677 return NegInf;
3678 }
3680
3681 if (difference->is_zero() and not difference->is_exact()) {
3682 if (min_number->is_exact())
3684 } else if (difference->is_positive()) {
3686 }
3687 }
3688 number_set = true;
3689
3690 } else if (is_a<Min>(*p)) {
3691 for (const auto &l : down_cast<const Min &>(*p).get_args()) {
3692 if (is_a_Number(*l)) {
3693 if (not number_set) {
3695
3696 } else {
3697 difference = min_number->sub(
3699
3700 if (difference->is_zero()
3701 and not difference->is_exact()) {
3702 if (min_number->is_exact())
3704 } else if (difference->is_positive()) {
3706 }
3707 }
3708 number_set = true;
3709 } else {
3710 new_args.insert(l);
3711 }
3712 }
3713 } else {
3714 new_args.insert(p);
3715 }
3716 }
3717
3718 if (number_set)
3719 new_args.insert(min_number);
3720
3722 std::copy(new_args.begin(), new_args.end(), final_args.begin());
3723
3724 if (final_args.size() > 1) {
3726 } else if (final_args.size() == 1) {
3727 return final_args[0];
3728 } else {
3729 throw SymEngineException("Empty vec_basic passed to min!");
3730 }
3731}
3732
3735{
3736 SYMENGINE_ASSIGN_TYPEID()
3737 SYMENGINE_ASSERT(is_canonical(arg))
3738}
3739
3740bool UnevaluatedExpr::is_canonical(const RCP<const Basic> &arg) const
3741{
3742 return true;
3743}
3744
3745RCP<const Basic> UnevaluatedExpr::create(const RCP<const Basic> &arg) const
3746{
3748}
3749
3750RCP<const Basic> unevaluated_expr(const RCP<const Basic> &arg)
3751{
3753}
3754
3755} // namespace SymEngine
T begin(T... args)
T cbrt(T... args)
RCP< const Basic > create(const RCP< const Basic > &arg) const override
bool is_canonical(const RCP< const Basic > &arg) const
ACos(const RCP< const Basic > &arg)
ACos Constructor.
bool is_canonical(const RCP< const Basic > &arg) const
RCP< const Basic > create(const RCP< const Basic > &arg) const override
ACosh(const RCP< const Basic > &arg)
ACosh Constructor.
bool is_canonical(const RCP< const Basic > &arg) const
ACot(const RCP< const Basic > &arg)
ACot Constructor.
RCP< const Basic > create(const RCP< const Basic > &arg) const override
ACoth(const RCP< const Basic > &arg)
ACoth Constructor.
RCP< const Basic > create(const RCP< const Basic > &arg) const override
bool is_canonical(const RCP< const Basic > &arg) const
ACsc(const RCP< const Basic > &arg)
ACsc Constructor.
bool is_canonical(const RCP< const Basic > &arg) const
RCP< const Basic > create(const RCP< const Basic > &arg) const override
RCP< const Basic > create(const RCP< const Basic > &arg) const override
ACsch(const RCP< const Basic > &arg)
ACsch Constructor.
bool is_canonical(const RCP< const Basic > &arg) const
RCP< const Basic > create(const RCP< const Basic > &arg) const override
ASec(const RCP< const Basic > &arg)
ASec Constructor.
bool is_canonical(const RCP< const Basic > &arg) const
RCP< const Basic > create(const RCP< const Basic > &arg) const override
ASech(const RCP< const Basic > &arg)
ASech Constructor.
bool is_canonical(const RCP< const Basic > &arg) const
RCP< const Basic > create(const RCP< const Basic > &arg) const override
bool is_canonical(const RCP< const Basic > &arg) const
ASin(const RCP< const Basic > &arg)
ASin Constructor.
RCP< const Basic > create(const RCP< const Basic > &arg) const override
bool is_canonical(const RCP< const Basic > &arg) const
ASinh(const RCP< const Basic > &arg)
ASinh Constructor.
RCP< const Basic > create(const RCP< const Basic > &a, const RCP< const Basic > &b) const override
bool is_canonical(const RCP< const Basic > &num, const RCP< const Basic > &den) const
ATan2(const RCP< const Basic > &num, const RCP< const Basic > &den)
ATan2 Constructor.
bool is_canonical(const RCP< const Basic > &arg) const
RCP< const Basic > create(const RCP< const Basic > &arg) const override
ATan(const RCP< const Basic > &arg)
ATan Constructor.
ATanh(const RCP< const Basic > &arg)
ATanh Constructor.
RCP< const Basic > create(const RCP< const Basic > &arg) const override
bool is_canonical(const RCP< const Basic > &arg) const
RCP< const Basic > create(const RCP< const Basic > &arg) const override
Abs(const RCP< const Basic > &arg)
Abs Constructor.
bool is_canonical(const RCP< const Basic > &arg) const
The base class for representing addition in symbolic expressions.
Definition add.h:27
static RCP< const Basic > from_dict(const RCP< const Number > &coef, umap_basic_num &&d)
Create an appropriate instance from dictionary quickly.
Definition add.cpp:140
const RCP< const Number > & get_coef() const
Definition add.h:142
The lowest unit of symbolic representation.
Definition basic.h:97
static RCP< const Beta > from_two_basic(const RCP< const Basic > &x, const RCP< const Basic > &y)
return Beta with ordered arguments
RCP< const Basic > create(const RCP< const Basic > &a, const RCP< const Basic > &b) const override
bool is_canonical(const RCP< const Basic > &s, const RCP< const Basic > &x)
RCP< const Basic > create(const RCP< const Basic > &arg) const override
Ceiling(const RCP< const Basic > &arg)
Ceiling Constructor.
bool is_canonical(const RCP< const Basic > &arg) const
ComplexBase Class for deriving all complex classes.
Definition complex.h:16
Conjugate(const RCP< const Basic > &arg)
Conjugate constructor.
Definition functions.cpp:92
RCP< const Basic > create(const RCP< const Basic > &arg) const override
bool is_canonical(const RCP< const Basic > &arg) const
Definition functions.cpp:98
Cos(const RCP< const Basic > &arg)
Cos Constructor.
RCP< const Basic > create(const RCP< const Basic > &arg) const override
bool is_canonical(const RCP< const Basic > &arg) const
Cosh(const RCP< const Basic > &arg)
Cosh Constructor.
bool is_canonical(const RCP< const Basic > &arg) const
RCP< const Basic > create(const RCP< const Basic > &arg) const override
bool is_canonical(const RCP< const Basic > &arg) const
RCP< const Basic > create(const RCP< const Basic > &arg) const override
Cot(const RCP< const Basic > &arg)
Cot Constructor.
Coth(const RCP< const Basic > &arg)
Coth Constructor.
RCP< const Basic > create(const RCP< const Basic > &arg) const override
bool is_canonical(const RCP< const Basic > &arg) const
Csc(const RCP< const Basic > &arg)
Csc Constructor.
bool is_canonical(const RCP< const Basic > &arg) const
RCP< const Basic > create(const RCP< const Basic > &arg) const override
RCP< const Basic > create(const RCP< const Basic > &arg) const override
bool is_canonical(const RCP< const Basic > &arg) const
Csch(const RCP< const Basic > &arg)
Csch Constructor.
hash_t __hash__() const override
bool __eq__(const Basic &o) const override
Test equality.
multiset_basic x_
The expression to be differentiated.
Definition functions.h:701
int compare(const Basic &o) const override
bool is_canonical(const RCP< const Basic > &s) const
RCP< const Basic > create(const RCP< const Basic > &arg) const override
Dirichlet_eta(const RCP< const Basic > &s)
Dirichlet_eta Constructor.
RCP< const Basic > rewrite_as_zeta() const
Rewrites in the form of zeta.
RCP< const Basic > create(const RCP< const Basic > &arg) const override
bool is_canonical(const RCP< const Basic > &arg) const
RCP< const Basic > create(const RCP< const Basic > &arg) const override
bool is_canonical(const RCP< const Basic > &arg) const
Floor(const RCP< const Basic > &arg)
Floor Constructor.
RCP< const Basic > create(const RCP< const Basic > &arg) const override
bool is_canonical(const RCP< const Basic > &arg) const
FunctionSymbol(std::string name, const vec_basic &arg)
FunctionSymbol Constructors.
bool is_canonical(const RCP< const Basic > &arg) const
RCP< const Basic > create(const RCP< const Basic > &arg) const override
Gamma(const RCP< const Basic > &arg)
Gamma Constructor.
Integer Class.
Definition integer.h:19
bool is_canonical(const RCP< const Basic > &i, const RCP< const Basic > &j) const
RCP< const Basic > create(const RCP< const Basic > &a, const RCP< const Basic > &b) const override
KroneckerDelta(const RCP< const Basic > &i, const RCP< const Basic > &j)
KroneckerDelta Constructor.
RCP< const Basic > create(const RCP< const Basic > &arg) const override
LambertW(const RCP< const Basic > &arg)
LambertW Constructor.
bool is_canonical(const RCP< const Basic > &arg) const
bool is_canonical(const vec_basic &arg) const
LeviCivita(const vec_basic &&arg)
LeviCivita Constructor.
RCP< const Basic > create(const vec_basic &arg) const override
RCP< const Basic > create(const RCP< const Basic > &arg) const override
bool is_canonical(const RCP< const Basic > &arg) const
bool is_canonical(const RCP< const Basic > &arg) const
Log(const RCP< const Basic > &arg)
Log Constructor.
RCP< const Basic > create(const RCP< const Basic > &arg) const override
RCP< const Basic > create(const RCP< const Basic > &a, const RCP< const Basic > &b) const override
LowerGamma(const RCP< const Basic > &s, const RCP< const Basic > &x)
LowerGamma Constructor.
bool is_canonical(const RCP< const Basic > &s, const RCP< const Basic > &x) const
bool is_canonical(const vec_basic &arg) const
RCP< const Basic > create(const vec_basic &arg) const override
Max(const vec_basic &&arg)
Max Constructor.
bool is_canonical(const vec_basic &arg) const
Min(const vec_basic &&arg)
Min Constructor.
RCP< const Basic > create(const vec_basic &arg) const override
static RCP< const Basic > from_dict(const RCP< const Number > &coef, map_basic_basic &&d)
Create a Mul from a dict.
Definition mul.cpp:115
RCP< const Basic > get_arg() const
Definition functions.h:36
RCP< const Basic > create(const RCP< const Basic > &a, const RCP< const Basic > &b) const override
Rational Class.
Definition rational.h:16
static RCP< const Number > from_mpq(const rational_class &i)
Definition rational.cpp:23
const rational_class & as_rational_class() const
Convert to rational_class.
Definition rational.h:50
RCP< const Basic > create(const RCP< const Basic > &arg) const override
Sec(const RCP< const Basic > &arg)
Sec Constructor.
bool is_canonical(const RCP< const Basic > &arg) const
Sech(const RCP< const Basic > &arg)
Sech Constructor.
RCP< const Basic > create(const RCP< const Basic > &arg) const override
bool is_canonical(const RCP< const Basic > &arg) const
bool is_canonical(const RCP< const Basic > &arg) const
RCP< const Basic > create(const RCP< const Basic > &arg) const override
Sign(const RCP< const Basic > &arg)
Sign constructor.
RCP< const Basic > create(const RCP< const Basic > &arg) const override
bool is_canonical(const RCP< const Basic > &arg) const
Sin(const RCP< const Basic > &arg)
Sin Constructor.
bool is_canonical(const RCP< const Basic > &arg) const
Sinh(const RCP< const Basic > &arg)
Sinh Constructor.
RCP< const Basic > create(const RCP< const Basic > &arg) const override
vec_basic get_args() const override
Returns the list of arguments.
int compare(const Basic &o) const override
hash_t __hash__() const override
bool __eq__(const Basic &o) const override
Test equality.
RCP< const Basic > create(const RCP< const Basic > &arg) const override
bool is_canonical(const RCP< const Basic > &arg) const
Tan(const RCP< const Basic > &arg)
Tan Constructor.
bool is_canonical(const RCP< const Basic > &arg) const
RCP< const Basic > create(const RCP< const Basic > &arg) const override
Tanh(const RCP< const Basic > &arg)
Tanh Constructor.
bool is_canonical(const RCP< const Basic > &arg) const
Truncate(const RCP< const Basic > &arg)
Truncate Constructor.
RCP< const Basic > create(const RCP< const Basic > &arg) const override
RCP< const Basic > get_arg2() const
Definition functions.h:96
RCP< const Basic > get_arg1() const
Definition functions.h:91
RCP< const Basic > create(const RCP< const Basic > &arg) const override
UnevaluatedExpr(const RCP< const Basic > &arg)
UnevaluatedExpr Constructor.
bool is_canonical(const RCP< const Basic > &arg) const
UpperGamma(const RCP< const Basic > &s, const RCP< const Basic > &x)
UpperGamma Constructor.
RCP< const Basic > create(const RCP< const Basic > &a, const RCP< const Basic > &b) const override
bool is_canonical(const RCP< const Basic > &s, const RCP< const Basic > &x) const
Zeta(const RCP< const Basic > &s, const RCP< const Basic > &a)
Zeta Constructor.
RCP< const Basic > create(const RCP< const Basic > &a, const RCP< const Basic > &b) const override
bool is_canonical(const RCP< const Basic > &s, const RCP< const Basic > &a) const
T copy(T... args)
T end(T... args)
T is_sorted(T... args)
T max(T... args)
T move(T... args)
Main namespace for SymEngine package.
Definition add.cpp:19
bool is_a_Number(const Basic &b)
Definition number.h:130
RCP< const Basic > acos(const RCP< const Basic > &arg)
Canonicalize ACos:
RCP< const Basic > div(const RCP< const Basic > &a, const RCP< const Basic > &b)
Division.
Definition mul.cpp:431
RCP< const Basic > sec(const RCP< const Basic > &arg)
Canonicalize Sec:
RCP< const Basic > polygamma(const RCP< const Basic > &n_, const RCP< const Basic > &x_)
Canonicalize PolyGamma.
RCP< const Basic > beta(const RCP< const Basic > &x, const RCP< const Basic > &y)
Canonicalize Beta:
RCP< const Basic > zeta(const RCP< const Basic > &s, const RCP< const Basic > &a)
Create a new Zeta instance:
RCP< const Basic > max(const vec_basic &arg)
Canonicalize Max:
bool eq(const Basic &a, const Basic &b)
Checks equality for a and b
Definition basic-inl.h:21
RCP< const Basic > coth(const RCP< const Basic > &arg)
Canonicalize Coth:
RCP< const Basic > sign(const RCP< const Basic > &arg)
Canonicalize Sign.
RCP< const Basic > atan2(const RCP< const Basic > &num, const RCP< const Basic > &den)
Canonicalize ATan2:
RCP< const Basic > ceiling(const RCP< const Basic > &arg)
Canonicalize Ceiling:
bool get_pi_shift(const RCP< const Basic > &arg, const Ptr< RCP< const Number > > &n, const Ptr< RCP< const Basic > > &x)
RCP< const Basic > abs(const RCP< const Basic > &arg)
Canonicalize Abs:
RCP< const Basic > acsc(const RCP< const Basic > &arg)
Canonicalize ACsc:
RCP< const Number > pownum(const RCP< const Number > &self, const RCP< const Number > &other)
Raise self to power other
Definition number.h:105
RCP< const Integer > quotient_f(const Integer &n, const Integer &d)
Definition ntheory.cpp:93
void hash_combine(hash_t &seed, const T &v)
Definition basic-inl.h:95
RCP< const Basic > sech(const RCP< const Basic > &arg)
Canonicalize Sech:
Definition functions.cp