2 #include <symengine/symengine_exception.h>
7 extern RCP<const Basic> &i2;
8 extern RCP<const Basic> &i3;
9 extern RCP<const Basic> &i5;
10 extern RCP<const Basic> &im2;
11 extern RCP<const Basic> &im3;
12 extern RCP<const Basic> &im5;
14 RCP<const Basic> sqrt(RCP<const Basic> &arg)
16 return pow(arg,
div(one, i2));
18 RCP<const Basic> cbrt(RCP<const Basic> &arg)
20 return pow(arg,
div(one, i3));
23 extern RCP<const Basic> &sq3;
24 extern RCP<const Basic> &sq2;
25 extern RCP<const Basic> &sq5;
27 extern RCP<const Basic> &C0;
28 extern RCP<const Basic> &C1;
29 extern RCP<const Basic> &C2;
30 extern RCP<const Basic> &C3;
31 extern RCP<const Basic> &C4;
32 extern RCP<const Basic> &C5;
33 extern RCP<const Basic> &C6;
35 extern RCP<const Basic> &mC0;
36 extern RCP<const Basic> &mC1;
37 extern RCP<const Basic> &mC2;
38 extern RCP<const Basic> &mC3;
39 extern RCP<const Basic> &mC4;
40 extern RCP<const Basic> &mC5;
41 extern RCP<const Basic> &mC6;
44 static const RCP<const Basic> *sin_table()
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};
52 static const umap_basic_basic &inverse_cst()
54 static const umap_basic_basic inverse_cst_ = {
71 static const umap_basic_basic &inverse_tct()
73 static const umap_basic_basic inverse_tct_ = {
74 {
div(one, sq3),
mul(i2, i3)},
75 {
div(minus_one, sq3),
mul(im2, 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)},
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)},
87 {minus_one,
mul(minus_one, pow(i2, i2))},
94 SYMENGINE_ASSIGN_TYPEID()
101 if (
eq(*arg, *ComplexInf)) {
106 if (is_a<Constant>(*arg)) {
109 if (is_a<Mul>(*arg)) {
112 if (is_a<Pow>(*arg)) {
113 if (is_a<Integer>(*down_cast<const Pow &>(*arg).get_exp())) {
118 if (is_a<Sign>(*arg) or is_a<Conjugate>(*arg) or is_a<Erf>(*arg)
119 or is_a<Erfc>(*arg) or is_a<Gamma>(*arg) or is_a<LogGamma>(*arg)
120 or is_a<Abs>(*arg)) {
123 if (is_a<Sin>(*arg) or is_a<Cos>(*arg) or is_a<Tan>(*arg) or is_a<Cot>(*arg)
124 or is_a<Sec>(*arg) or is_a<Csc>(*arg)) {
127 if (is_a<Sinh>(*arg) or is_a<Cosh>(*arg) or is_a<Tanh>(*arg)
128 or is_a<Coth>(*arg) or is_a<Sech>(*arg) or is_a<Csch>(*arg)) {
132 if (is_a<KroneckerDelta>(*arg) or is_a<ATan2>(*arg)
133 or is_a<LowerGamma>(*arg) or is_a<UpperGamma>(*arg)
134 or is_a<Beta>(*arg)) {
138 if (is_a<LeviCivita>(*arg)) {
152 return down_cast<const Number &>(*arg).conjugate();
154 if (is_a<Constant>(*arg) or is_a<Abs>(*arg) or is_a<KroneckerDelta>(*arg)
155 or is_a<LeviCivita>(*arg)) {
158 if (is_a<Mul>(*arg)) {
159 const map_basic_basic &dict = down_cast<const Mul &>(*arg).get_dict();
160 map_basic_basic new_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,
168 Mul::dict_add_term_new(
169 outArg(coef), new_dict, one,
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)) {
182 if (is_a<Conjugate>(*arg)) {
183 return down_cast<const Conjugate &>(*arg).get_arg();
185 if (is_a<Sign>(*arg) or is_a<Erf>(*arg) or is_a<Erfc>(*arg)
186 or is_a<Gamma>(*arg) or is_a<LogGamma>(*arg) or is_a<Sin>(*arg)
187 or is_a<Cos>(*arg) or is_a<Tan>(*arg) or is_a<Cot>(*arg)
188 or is_a<Sec>(*arg) or is_a<Csc>(*arg) or is_a<Sinh>(*arg)
189 or is_a<Cosh>(*arg) or is_a<Tanh>(*arg) or is_a<Coth>(*arg)
190 or is_a<Sech>(*arg) or is_a<Csch>(*arg)) {
191 const OneArgFunction &func = down_cast<const OneArgFunction &>(*arg);
194 if (is_a<ATan2>(*arg) or is_a<LowerGamma>(*arg) or is_a<UpperGamma>(*arg)
195 or is_a<Beta>(*arg)) {
196 const TwoArgFunction &func = down_cast<const TwoArgFunction &>(*arg);
200 return make_rcp<const Conjugate>(arg);
203 bool get_pi_shift(
const RCP<const Basic> &arg,
const Ptr<RCP<const Number>> &n,
204 const Ptr<RCP<const Basic>> &x)
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();
214 bool check_pi =
false;
215 RCP<const Basic> temp;
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))) {
224 *x =
add(
mul(p.first, p.second), *x);
231 }
else if (size == 1) {
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))) {
247 }
else if (is_a<Mul>(*arg)) {
249 const Mul &s = down_cast<const Mul &>(*arg);
250 auto p = s.get_dict().begin();
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()))) {
262 }
else if (
eq(*arg, *pi)) {
266 }
else if (
eq(*arg, *zero)) {
277 bool trig_has_basic_shift(
const RCP<const Basic> &arg)
279 if (is_a<Add>(*arg)) {
280 const Add &s = down_cast<const Add &>(*arg);
281 for (
const auto &p : s.get_dict()) {
283 if (
eq(*p.first, *pi)) {
284 if (is_a<Integer>(*temp)) {
287 if (is_a<Rational>(*temp)) {
288 auto m = down_cast<const Rational &>(*temp)
289 .as_rational_class();
290 return (m < 0) or (m > 1);
296 }
else if (is_a<Mul>(*arg)) {
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)) {
308 if (is_a<Rational>(*coef)) {
309 auto m = down_cast<const Rational &>(*coef).as_rational_class();
310 return (m < 0) or (m > 1);
316 }
else if (
eq(*arg, *pi)) {
318 }
else if (
eq(*arg, *zero)) {
328 if (down_cast<const Number &>(arg).is_negative()) {
331 const ComplexBase &c = down_cast<const ComplexBase &>(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());
339 }
else if (is_a<Mul>(arg)) {
340 const Mul &s = down_cast<const Mul &>(arg);
342 }
else if (is_a<Add>(arg)) {
343 const Add &s = down_cast<const Add &>(arg);
345 map_basic_num d(s.get_dict().begin(), s.get_dict().end());
355 bool handle_minus(
const RCP<const Basic> &arg,
356 const Ptr<RCP<const Basic>> &rarg)
358 if (is_a<Mul>(*arg)) {
359 const Mul &s = down_cast<const Mul &>(*arg);
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);
365 *rarg =
mul(minus_one, arg);
368 }
else if (is_a<Add>(*arg)) {
370 const Add &s = down_cast<const Add &>(*arg);
371 umap_basic_num d = s.get_dict();
373 p.second = p.second->mul(*minus_one);
375 *rarg =
Add::from_dict(s.get_coef()->mul(*minus_one), std::move(d));
379 *rarg =
mul(minus_one, arg);
387 bool trig_simplify(
const RCP<const Basic> &arg,
unsigned period,
bool odd,
389 const Ptr<RCP<const Basic>> &rarg,
int &index,
395 RCP<const Basic> ret_arg;
400 if (is_a<Integer>(*t)) {
401 int m = numeric_cast<int>(
402 mod_f(down_cast<const Integer &>(*t), *
integer(12 * period))
410 bool b = handle_minus(r, outArg(ret_arg));
419 if (is_a<Integer>(*n)) {
421 m = mp_abs(down_cast<const Integer &>(*n).as_integer_class());
424 SYMENGINE_ASSERT(is_a<Rational>(*n));
425 m = down_cast<const Rational &>(*n).as_rational_class() / period;
427 #if SYMENGINE_INTEGER_CLASS != SYMENGINE_BOOSTMP
428 mp_fdiv_r(t, get_num(m), get_den(m));
432 mp_fdiv_qr(quo, t, get_num(m), get_den(m));
433 m -= rational_class(quo);
440 if (m >= 2 and m < 3) {
443 bool b = handle_minus(r, outArg(ret_arg));
458 bool b = handle_minus(r, outArg(ret_arg));
460 if (not b and conj_odd)
469 bool b = handle_minus(arg, outArg(ret_arg));
481 const Ptr<RCP<const Basic>> &index)
488 *index = (it->second);
495 SYMENGINE_ASSIGN_TYPEID()
502 if (
eq(*arg, *ComplexInf)) {
507 if (is_a<Constant>(*arg)) {
510 if (is_a<Sign>(*arg)) {
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)) {
527 RCP<const Basic>
sign(
const RCP<const Basic> &arg)
530 if (is_a<NaN>(*arg)) {
533 if (down_cast<const Number &>(*arg).is_zero()) {
536 if (down_cast<const Number &>(*arg).is_positive()) {
539 if (down_cast<const Number &>(*arg).is_negative()) {
543 and down_cast<const ComplexBase &>(*arg).is_re_zero()) {
545 = down_cast<const ComplexBase &>(*arg).imaginary_part();
546 if (down_cast<const Number &>(*r).is_positive()) {
549 if (down_cast<const Number &>(*r).is_negative()) {
550 return mul(minus_one, I);
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))
559 if (is_a<Sign>(*arg)) {
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();
568 if (is_a<Pow>(*arg)) {
569 RCP<const Pow> pow_arg = rcp_static_cast<const Pow>(arg);
570 RCP<const Basic> s =
sign(pow_arg->get_base());
571 if (not is_a<Sign>(*s) and not
eq(*s, *pow_arg->get_base())) {
572 return sign(pow(s, pow_arg->get_exp()));
575 return make_rcp<const Sign>(arg);
580 SYMENGINE_ASSIGN_TYPEID()
589 if (is_a<Constant>(*arg)) {
592 if (is_a<Floor>(*arg)) {
595 if (is_a<Ceiling>(*arg)) {
598 if (is_a<Truncate>(*arg)) {
601 if (is_a<BooleanAtom>(*arg) or is_a_Relational(*arg)) {
604 if (is_a<Add>(*arg)) {
605 RCP<const Number> s = down_cast<const Add &>(*arg).get_coef();
606 if (
neq(*zero, *s) and is_a<Integer>(*s)) {
618 RCP<const Basic>
floor(
const RCP<const Basic> &arg)
621 if (down_cast<const Number &>(*arg).is_exact()) {
622 if (is_a<Rational>(*arg)) {
623 const Rational &s = down_cast<const Rational &>(*arg);
631 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
632 return _arg->get_eval().floor(*_arg);
634 if (is_a<Constant>(*arg)) {
641 if (
eq(*arg, *GoldenRatio)) {
644 if (
eq(*arg, *Catalan) or
eq(*arg, *EulerGamma)) {
648 if (is_a<Floor>(*arg)) {
651 if (is_a<Ceiling>(*arg)) {
654 if (is_a<Truncate>(*arg)) {
657 if (is_a<BooleanAtom>(*arg) or is_a_Relational(*arg)) {
658 throw SymEngineException(
659 "Boolean objects not allowed in this context.");
661 if (is_a<Add>(*arg)) {
662 RCP<const Number> s = down_cast<const Add &>(*arg).get_coef();
663 umap_basic_num d = down_cast<const Add &>(*arg).get_dict();
664 if (is_a<Integer>(*s)
665 and not down_cast<const Integer &>(*s).is_zero()) {
669 return make_rcp<const Floor>(arg);
674 SYMENGINE_ASSIGN_TYPEID()
683 if (is_a<Constant>(*arg)) {
686 if (is_a<Floor>(*arg)) {
689 if (is_a<Ceiling>(*arg)) {
692 if (is_a<Truncate>(*arg)) {
695 if (is_a<BooleanAtom>(*arg) or is_a_Relational(*arg)) {
698 if (is_a<Add>(*arg)) {
699 RCP<const Number> s = down_cast<const Add &>(*arg).get_coef();
700 if (
neq(*zero, *s) and is_a<Integer>(*s)) {
712 RCP<const Basic>
ceiling(
const RCP<const Basic> &arg)
715 if (down_cast<const Number &>(*arg).is_exact()) {
716 if (is_a<Rational>(*arg)) {
717 const Rational &s = down_cast<const Rational &>(*arg);
725 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
726 return _arg->get_eval().ceiling(*_arg);
728 if (is_a<Constant>(*arg)) {
735 if (
eq(*arg, *GoldenRatio)) {
738 if (
eq(*arg, *Catalan) or
eq(*arg, *EulerGamma)) {
742 if (is_a<Floor>(*arg)) {
745 if (is_a<Ceiling>(*arg)) {
748 if (is_a<Truncate>(*arg)) {
751 if (is_a<BooleanAtom>(*arg) or is_a_Relational(*arg)) {
752 throw SymEngineException(
753 "Boolean objects not allowed in this context.");
755 if (is_a<Add>(*arg)) {
756 RCP<const Number> s = down_cast<const Add &>(*arg).get_coef();
757 umap_basic_num d = down_cast<const Add &>(*arg).get_dict();
758 if (is_a<Integer>(*s)) {
763 return make_rcp<const Ceiling>(arg);
768 SYMENGINE_ASSIGN_TYPEID()
777 if (is_a<Constant>(*arg)) {
780 if (is_a<Floor>(*arg)) {
783 if (is_a<Ceiling>(*arg)) {
786 if (is_a<Truncate>(*arg)) {
789 if (is_a<BooleanAtom>(*arg) or is_a_Relational(*arg)) {
792 if (is_a<Add>(*arg)) {
793 RCP<const Number> s = down_cast<const Add &>(*arg).get_coef();
794 if (
neq(*zero, *s) and is_a<Integer>(*s)) {
806 RCP<const Basic>
truncate(
const RCP<const Basic> &arg)
809 if (down_cast<const Number &>(*arg).is_exact()) {
810 if (is_a<Rational>(*arg)) {
811 const Rational &s = down_cast<const Rational &>(*arg);
819 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
820 return _arg->get_eval().truncate(*_arg);
822 if (is_a<Constant>(*arg)) {
829 if (
eq(*arg, *GoldenRatio)) {
832 if (
eq(*arg, *Catalan) or
eq(*arg, *EulerGamma)) {
836 if (is_a<Floor>(*arg)) {
839 if (is_a<Ceiling>(*arg)) {
842 if (is_a<Truncate>(*arg)) {
845 if (is_a<BooleanAtom>(*arg) or is_a_Relational(*arg)) {
846 throw SymEngineException(
847 "Boolean objects not allowed in this context.");
849 if (is_a<Add>(*arg)) {
850 RCP<const Number> s = down_cast<const Add &>(*arg).get_coef();
851 umap_basic_num d = down_cast<const Add &>(*arg).get_dict();
852 if (is_a<Integer>(*s)) {
853 return add(s, make_rcp<const Truncate>(
857 return make_rcp<const Truncate>(arg);
862 SYMENGINE_ASSIGN_TYPEID()
869 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
872 if (trig_has_basic_shift(arg)) {
875 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
881 RCP<const Basic>
sin(
const RCP<const Basic> &arg)
885 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
886 return down_cast<const Number &>(*arg).get_eval().sin(*arg);
889 if (is_a<ASin>(*arg)) {
890 return down_cast<const ASin &>(*arg).get_arg();
891 }
else if (is_a<ACsc>(*arg)) {
892 return div(one, down_cast<const ACsc &>(*arg).get_arg());
895 RCP<const Basic> ret_arg;
897 bool conjugate = trig_simplify(arg, 2,
true,
false,
898 outArg(ret_arg), index,
sign);
905 return mul(minus_one,
cos(ret_arg));
908 if (
eq(*ret_arg, *zero)) {
914 if (
neq(*ret_arg, *arg)) {
917 return make_rcp<const Sin>(arg);
920 return mul(minus_one,
sin(ret_arg));
930 SYMENGINE_ASSIGN_TYPEID()
937 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
940 if (trig_has_basic_shift(arg)) {
943 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
949 RCP<const Basic>
cos(
const RCP<const Basic> &arg)
953 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
954 return down_cast<const Number &>(*arg).get_eval().cos(*arg);
957 if (is_a<ACos>(*arg)) {
958 return down_cast<const ACos &>(*arg).get_arg();
959 }
else if (is_a<ASec>(*arg)) {
960 return div(one, down_cast<const ASec &>(*arg).get_arg());
963 RCP<const Basic> ret_arg;
965 bool conjugate = trig_simplify(arg, 2,
false,
true,
966 outArg(ret_arg), index,
sign);
973 return mul(minus_one,
sin(ret_arg));
976 if (
eq(*ret_arg, *zero)) {
980 if (
neq(*ret_arg, *arg)) {
983 return make_rcp<const Cos>(ret_arg);
986 return mul(minus_one,
cos(ret_arg));
996 SYMENGINE_ASSIGN_TYPEID()
1002 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
1005 if (trig_has_basic_shift(arg)) {
1008 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1014 RCP<const Basic>
tan(
const RCP<const Basic> &arg)
1016 if (
eq(*arg, *zero))
1018 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1019 return down_cast<const Number &>(*arg).get_eval().tan(*arg);
1022 if (is_a<ATan>(*arg)) {
1023 return down_cast<const ATan &>(*arg).get_arg();
1024 }
else if (is_a<ACot>(*arg)) {
1025 return div(one, down_cast<const ACot &>(*arg).get_arg());
1028 RCP<const Basic> ret_arg;
1030 bool conjugate = trig_simplify(arg, 1,
true,
true,
1031 outArg(ret_arg), index,
sign);
1036 return cot(ret_arg);
1038 return mul(minus_one,
cot(ret_arg));
1041 if (
eq(*ret_arg, *zero)) {
1043 div(sin_table()[index], sin_table()[(index + 6) % 24]));
1046 if (
neq(*ret_arg, *arg)) {
1047 return tan(ret_arg);
1049 return make_rcp<const Tan>(ret_arg);
1052 return mul(minus_one,
tan(ret_arg));
1062 SYMENGINE_ASSIGN_TYPEID()
1068 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
1071 if (trig_has_basic_shift(arg)) {
1074 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1080 RCP<const Basic>
cot(
const RCP<const Basic> &arg)
1082 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1083 return down_cast<const Number &>(*arg).get_eval().cot(*arg);
1086 if (is_a<ACot>(*arg)) {
1087 return down_cast<const ACot &>(*arg).get_arg();
1088 }
else if (is_a<ATan>(*arg)) {
1089 return div(one, down_cast<const ATan &>(*arg).get_arg());
1092 RCP<const Basic> ret_arg;
1094 bool conjugate = trig_simplify(arg, 1,
true,
true,
1095 outArg(ret_arg), index,
sign);
1100 return tan(ret_arg);
1102 return mul(minus_one,
tan(ret_arg));
1105 if (
eq(*ret_arg, *zero)) {
1107 div(sin_table()[(index + 6) % 24], sin_table()[index]));
1110 if (
neq(*ret_arg, *arg)) {
1111 return cot(ret_arg);
1113 return make_rcp<const Cot>(ret_arg);
1116 return mul(minus_one,
cot(ret_arg));
1126 SYMENGINE_ASSIGN_TYPEID()
1133 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
1136 if (trig_has_basic_shift(arg)) {
1139 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1145 RCP<const Basic>
csc(
const RCP<const Basic> &arg)
1147 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1148 return down_cast<const Number &>(*arg).get_eval().csc(*arg);
1151 if (is_a<ACsc>(*arg)) {
1152 return down_cast<const ACsc &>(*arg).get_arg();
1153 }
else if (is_a<ASin>(*arg)) {
1154 return div(one, down_cast<const ASin &>(*arg).get_arg());
1157 RCP<const Basic> ret_arg;
1159 bool conjugate = trig_simplify(arg, 2,
true,
false,
1160 outArg(ret_arg), index,
sign);
1165 return sec(ret_arg);
1167 return mul(minus_one,
sec(ret_arg));
1170 if (
eq(*ret_arg, *zero)) {
1174 if (
neq(*ret_arg, *arg)) {
1175 return csc(ret_arg);
1177 return make_rcp<const Csc>(ret_arg);
1180 return mul(minus_one,
csc(ret_arg));
1190 SYMENGINE_ASSIGN_TYPEID()
1197 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
1200 if (trig_has_basic_shift(arg)) {
1203 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1209 RCP<const Basic>
sec(
const RCP<const Basic> &arg)
1211 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1212 return down_cast<const Number &>(*arg).get_eval().sec(*arg);
1215 if (is_a<ASec>(*arg)) {
1216 return down_cast<const ASec &>(*arg).get_arg();
1217 }
else if (is_a<ACos>(*arg)) {
1218 return div(one, down_cast<const ACos &>(*arg).get_arg());
1221 RCP<const Basic> ret_arg;
1223 bool conjugate = trig_simplify(arg, 2,
false,
true,
1224 outArg(ret_arg), index,
sign);
1229 return csc(ret_arg);
1231 return mul(minus_one,
csc(ret_arg));
1234 if (
eq(*ret_arg, *zero)) {
1238 if (
neq(*ret_arg, *arg)) {
1239 return sec(ret_arg);
1241 return make_rcp<const Sec>(ret_arg);
1244 return mul(minus_one,
sec(ret_arg));
1255 RCP<const Basic> i_arg;
1257 if (is_a<Sin>(*arg)) {
1258 if (is_a<ACos>(*arg->get_args()[0])) {
1259 i_arg = down_cast<const ACos &>(*(arg->get_args()[0])).get_arg();
1260 return sqrt(
sub(one, pow(i_arg, i2)));
1261 }
else if (is_a<ATan>(*arg->get_args()[0])) {
1262 i_arg = down_cast<const ATan &>(*(arg->get_args()[0])).get_arg();
1263 return div(i_arg, sqrt(
add(one, pow(i_arg, i2))));
1264 }
else if (is_a<ASec>(*arg->get_args()[0])) {
1265 i_arg = down_cast<const ASec &>(*(arg->get_args()[0])).get_arg();
1266 return sqrt(
sub(one, pow(i_arg, im2)));
1267 }
else if (is_a<ACot>(*arg->get_args()[0])) {
1268 i_arg = down_cast<const ACot &>(*(arg->get_args()[0])).get_arg();
1269 return div(one,
mul(i_arg, sqrt(
add(one, pow(i_arg, im2)))));
1271 }
else if (is_a<Cos>(*arg)) {
1272 if (is_a<ASin>(*arg->get_args()[0])) {
1273 i_arg = down_cast<const ASin &>(*(arg->get_args()[0])).get_arg();
1274 return sqrt(
sub(one, pow(i_arg, i2)));
1275 }
else if (is_a<ATan>(*arg->get_args()[0])) {
1276 i_arg = down_cast<const ATan &>(*(arg->get_args()[0])).get_arg();
1277 return div(one, sqrt(
add(one, pow(i_arg, i2))));
1278 }
else if (is_a<ACsc>(*arg->get_args()[0])) {
1279 i_arg = down_cast<const ACsc &>(*(arg->get_args()[0])).get_arg();
1280 return sqrt(
sub(one, pow(i_arg, im2)));
1281 }
else if (is_a<ACot>(*arg->get_args()[0])) {
1282 i_arg = down_cast<const ACot &>(*(arg->get_args()[0])).get_arg();
1283 return div(one, sqrt(
add(one, pow(i_arg, im2))));
1285 }
else if (is_a<Tan>(*arg)) {
1286 if (is_a<ASin>(*arg->get_args()[0])) {
1287 i_arg = down_cast<const ASin &>(*(arg->get_args()[0])).get_arg();
1288 return div(i_arg, sqrt(
sub(one, pow(i_arg, i2))));
1289 }
else if (is_a<ACos>(*arg->get_args()[0])) {
1290 i_arg = down_cast<const ACos &>(*(arg->get_args()[0])).get_arg();
1291 return div(sqrt(
sub(one, pow(i_arg, i2))), i_arg);
1292 }
else if (is_a<ACsc>(*arg->get_args()[0])) {
1293 i_arg = down_cast<const ACsc &>(*(arg->get_args()[0])).get_arg();
1294 return div(one,
mul(i_arg, sqrt(
sub(one, pow(i_arg, im2)))));
1295 }
else if (is_a<ASec>(*arg->get_args()[0])) {
1296 i_arg = down_cast<const ASec &>(*(arg->get_args()[0])).get_arg();
1297 return mul(i_arg, sqrt(
sub(one, pow(i_arg, im2))));
1299 }
else if (is_a<Csc>(*arg)) {
1300 if (is_a<ACos>(*arg->get_args()[0])) {
1301 i_arg = down_cast<const ACos &>(*(arg->get_args()[0])).get_arg();
1302 return div(one, sqrt(
sub(one, pow(i_arg, i2))));
1303 }
else if (is_a<ATan>(*arg->get_args()[0])) {
1304 i_arg = down_cast<const ATan &>(*(arg->get_args()[0])).get_arg();
1305 return div(sqrt(
add(one, pow(i_arg, i2))), i_arg);
1306 }
else if (is_a<ASec>(*arg->get_args()[0])) {
1307 i_arg = down_cast<const ASec &>(*(arg->get_args()[0])).get_arg();
1308 return div(one, sqrt(
sub(one, pow(i_arg, im2))));
1309 }
else if (is_a<ACot>(*arg->get_args()[0])) {
1310 i_arg = down_cast<const ACot &>(*(arg->get_args()[0])).get_arg();
1311 return mul(i_arg, sqrt(
add(one, pow(i_arg, im2))));
1313 }
else if (is_a<Sec>(*arg)) {
1314 if (is_a<ASin>(*arg->get_args()[0])) {
1315 i_arg = down_cast<const ASin &>(*(arg->get_args()[0])).get_arg();
1316 return div(one, sqrt(
sub(one, pow(i_arg, i2))));
1317 }
else if (is_a<ATan>(*arg->get_args()[0])) {
1318 i_arg = down_cast<const ATan &>(*(arg->get_args()[0])).get_arg();
1319 return sqrt(
add(one, pow(i_arg, i2)));
1320 }
else if (is_a<ACsc>(*arg->get_args()[0])) {
1321 i_arg = down_cast<const ACsc &>(*(arg->get_args()[0])).get_arg();
1322 return div(one, sqrt(
sub(one, pow(i_arg, im2))));
1323 }
else if (is_a<ACot>(*arg->get_args()[0])) {
1324 i_arg = down_cast<const ACot &>(*(arg->get_args()[0])).get_arg();
1325 return sqrt(
add(one, pow(i_arg, im2)));
1327 }
else if (is_a<Cot>(*arg)) {
1328 if (is_a<ASin>(*arg->get_args()[0])) {
1329 i_arg = down_cast<const ASin &>(*(arg->get_args()[0])).get_arg();
1330 return div(sqrt(
sub(one, pow(i_arg, i2))), i_arg);
1331 }
else if (is_a<ACos>(*arg->get_args()[0])) {
1332 i_arg = down_cast<const ACos &>(*(arg->get_args()[0])).get_arg();
1333 return div(i_arg, sqrt(
sub(one, pow(i_arg, i2))));
1334 }
else if (is_a<ACsc>(*arg->get_args()[0])) {
1335 i_arg = down_cast<const ACsc &>(*(arg->get_args()[0])).get_arg();
1336 return mul(i_arg, sqrt(
sub(one, pow(i_arg, im2))));
1337 }
else if (is_a<ASec>(*arg->get_args()[0])) {
1338 i_arg = down_cast<const ASec &>(*(arg->get_args()[0])).get_arg();
1339 return div(one,
mul(i_arg, sqrt(
sub(one, pow(i_arg, im2)))));
1349 SYMENGINE_ASSIGN_TYPEID()
1355 if (
eq(*arg, *zero) or
eq(*arg, *one) or
eq(*arg, *minus_one))
1357 RCP<const Basic> index;
1361 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1367 RCP<const Basic>
asin(
const RCP<const Basic> &arg)
1369 if (
eq(*arg, *zero))
1371 else if (
eq(*arg, *one))
1373 else if (
eq(*arg, *minus_one))
1374 return mul(minus_one,
div(pi, i2));
1376 and not down_cast<const Number &>(*arg).is_exact()) {
1377 return down_cast<const Number &>(*arg).get_eval().asin(*arg);
1380 RCP<const Basic> index;
1383 return div(pi, index);
1385 return make_rcp<const ASin>(arg);
1391 SYMENGINE_ASSIGN_TYPEID()
1397 if (
eq(*arg, *zero) or
eq(*arg, *one) or
eq(*arg, *minus_one))
1399 RCP<const Basic> index;
1403 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1409 RCP<const Basic>
acos(
const RCP<const Basic> &arg)
1411 if (
eq(*arg, *zero))
1413 else if (
eq(*arg, *one))
1415 else if (
eq(*arg, *minus_one))
1418 and not down_cast<const Number &>(*arg).is_exact()) {
1419 return down_cast<const Number &>(*arg).get_eval().acos(*arg);
1422 RCP<const Basic> index;
1425 return sub(
div(pi, i2),
div(pi, index));
1427 return make_rcp<const ACos>(arg);
1433 SYMENGINE_ASSIGN_TYPEID()
1439 if (
eq(*arg, *one) or
eq(*arg, *minus_one))
1441 RCP<const Basic> index;
1445 and not down_cast<const Number &>(*arg).is_exact()) {
1451 RCP<const Basic>
asec(
const RCP<const Basic> &arg)
1455 else if (
eq(*arg, *minus_one))
1458 and not down_cast<const Number &>(*arg).is_exact()) {
1459 return down_cast<const Number &>(*arg).get_eval().asec(*arg);
1462 RCP<const Basic> index;
1465 return sub(
div(pi, i2),
div(pi, index));
1467 return make_rcp<const ASec>(arg);
1473 SYMENGINE_ASSIGN_TYPEID()
1479 if (
eq(*arg, *one) or
eq(*arg, *minus_one))
1481 RCP<const Basic> index;
1485 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1491 RCP<const Basic>
acsc(
const RCP<const Basic> &arg)
1495 else if (
eq(*arg, *minus_one))
1496 return div(pi, im2);
1498 and not down_cast<const Number &>(*arg).is_exact()) {
1499 return down_cast<const Number &>(*arg).get_eval().acsc(*arg);
1502 RCP<const Basic> index;
1505 return div(pi, index);
1507 return make_rcp<const ACsc>(arg);
1513 SYMENGINE_ASSIGN_TYPEID()
1519 if (
eq(*arg, *zero) or
eq(*arg, *one) or
eq(*arg, *minus_one))
1521 RCP<const Basic> index;
1525 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1531 RCP<const Basic>
atan(
const RCP<const Basic> &arg)
1533 if (
eq(*arg, *zero))
1535 else if (
eq(*arg, *one))
1536 return div(pi,
mul(i2, i2));
1537 else if (
eq(*arg, *minus_one))
1538 return mul(minus_one,
div(pi,
mul(i2, i2)));
1540 and not down_cast<const Number &>(*arg).is_exact()) {
1541 return down_cast<const Number &>(*arg).get_eval().atan(*arg);
1544 RCP<const Basic> index;
1547 return div(pi, index);
1549 return make_rcp<const ATan>(arg);
1555 SYMENGINE_ASSIGN_TYPEID()
1561 if (
eq(*arg, *zero) or
eq(*arg, *one) or
eq(*arg, *minus_one))
1563 RCP<const Basic> index;
1567 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1573 RCP<const Basic>
acot(
const RCP<const Basic> &arg)
1575 if (
eq(*arg, *zero))
1577 else if (
eq(*arg, *one))
1578 return div(pi,
mul(i2, i2));
1579 else if (
eq(*arg, *minus_one))
1582 and not down_cast<const Number &>(*arg).is_exact()) {
1583 return down_cast<const Number &>(*arg).get_eval().acot(*arg);
1586 RCP<const Basic> index;
1589 return sub(
div(pi, i2),
div(pi, index));
1591 return make_rcp<const ACot>(arg);
1598 SYMENGINE_ASSIGN_TYPEID()
1603 const RCP<const Basic> &den)
const
1605 if (
eq(*num, *den) or
eq(*num, *
mul(minus_one, den)))
1607 if (
eq(*num, *zero)) {
1610 if (
eq(*den, *zero)) {
1613 RCP<const Basic> index;
1622 const RCP<const Basic> &b)
const
1627 RCP<const Basic>
atan2(
const RCP<const Basic> &num,
const RCP<const Basic> &den)
1629 if (
eq(*num, *zero)) {
1630 if (
eq(*den, *zero)) {
1634 RCP<const Number> den_new = rcp_static_cast<const Number>(den);
1635 if (den_new->is_negative())
1637 else if (den_new->is_positive())
1643 return make_rcp<const ATan2>(num, den);
1644 }
else if (
eq(*den, *zero)) {
1646 RCP<const Number> num_new = rcp_static_cast<const Number>(num);
1647 if (num_new->is_negative())
1648 return div(pi, im2);
1652 return make_rcp<const ATan2>(num, den);
1654 RCP<const Basic> index;
1658 RCP<const Number> index_num = rcp_static_cast<const Number>(index);
1659 if (index_num->is_positive()) {
1665 return make_rcp<const ATan2>(num, den);
1735 SYMENGINE_ASSIGN_TYPEID()
1742 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
1745 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_one())
1751 if (
is_a_Number(*arg) and down_cast<const Number &>(*arg).is_negative())
1755 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact())
1759 if (is_a<Complex>(*arg) and down_cast<const Complex &>(*arg).is_re_zero())
1762 if (is_a<Rational>(*arg))
1772 RCP<const Basic>
log(
const RCP<const Basic> &arg)
1774 if (
eq(*arg, *zero))
1782 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
1783 if (not _arg->is_exact()) {
1784 return _arg->get_eval().log(*_arg);
1785 }
else if (_arg->is_negative()) {
1790 if (is_a<Rational>(*arg)) {
1791 RCP<const Integer> num, den;
1792 get_num_den(down_cast<const Rational &>(*arg), outArg(num),
1797 if (is_a<Complex>(*arg)) {
1798 RCP<const Complex> _arg = rcp_static_cast<const Complex>(arg);
1799 if (_arg->is_re_zero()) {
1800 RCP<const Number> arg_img = _arg->imaginary_part();
1801 if (arg_img->is_negative()) {
1802 return sub(
log(
mul(minus_one, arg_img)),
1804 }
else if (arg_img->is_zero()) {
1806 }
else if (arg_img->is_positive()) {
1812 return make_rcp<const Log>(arg);
1815 RCP<const Basic>
log(
const RCP<const Basic> &arg,
const RCP<const Basic> &base)
1822 SYMENGINE_ASSIGN_TYPEID()
1828 if (
eq(*arg, *zero))
1846 if (
eq(*arg, *zero))
1853 return mul(minus_one,
log(i2));
1854 return make_rcp<const LambertW>(arg);
1858 : MultiArgFunction({arg}), name_{name} {SYMENGINE_ASSIGN_TYPEID()
1860 is_canonical(get_vec()))}
1865 SYMENGINE_ASSIGN_TYPEID()
1866 SYMENGINE_ASSERT(is_canonical(get_vec()))
1874 hash_t FunctionSymbol::__hash__()
const
1876 hash_t seed = SYMENGINE_FUNCTIONSYMBOL;
1877 for (
const auto &a : get_vec())
1878 hash_combine<Basic>(seed, *a);
1879 hash_combine<std::string>(seed, name_);
1883 bool FunctionSymbol::__eq__(
const Basic &o)
const
1885 if (is_a<FunctionSymbol>(o)
1886 and name_ == down_cast<const FunctionSymbol &>(o).name_
1887 and unified_eq(get_vec(),
1888 down_cast<const FunctionSymbol &>(o).get_vec()))
1893 int FunctionSymbol::compare(
const Basic &o)
const
1895 SYMENGINE_ASSERT(is_a<FunctionSymbol>(o))
1897 if (name_ == s.name_)
1900 return name_ < s.name_ ? -1 : 1;
1903 RCP<const Basic> FunctionSymbol::create(
const vec_basic &x)
const
1905 return make_rcp<const FunctionSymbol>(name_, x);
1908 RCP<const Basic> function_symbol(std::string name,
const vec_basic &arg)
1910 return make_rcp<const FunctionSymbol>(name, arg);
1913 RCP<const Basic> function_symbol(std::string name,
const RCP<const Basic> &arg)
1915 return make_rcp<const FunctionSymbol>(name, arg);
1918 FunctionWrapper::FunctionWrapper(std::string name,
const RCP<const Basic> &arg)
1919 : FunctionSymbol(name, arg){SYMENGINE_ASSIGN_TYPEID()}
1921 FunctionWrapper::FunctionWrapper(std::string name,
const vec_basic &vec)
1922 : FunctionSymbol(name, vec){SYMENGINE_ASSIGN_TYPEID()}
1926 Derivative::Derivative(
const RCP<const Basic> &arg,
1927 const multiset_basic &x)
1930 SYMENGINE_ASSIGN_TYPEID()
1931 SYMENGINE_ASSERT(is_canonical(arg, x))
1934 bool Derivative::is_canonical(const RCP<const Basic> &arg,
1935 const multiset_basic &x)
const
1938 for (
const auto &a : x)
1939 if (not is_a<Symbol>(*a))
1941 if (is_a<FunctionSymbol>(*arg) or is_a<LeviCivita>(*arg)) {
1943 RCP<const Symbol> s = rcp_static_cast<const Symbol>(p);
1944 RCP<const MultiArgFunction> f
1945 = rcp_static_cast<const MultiArgFunction>(arg);
1946 bool found_s =
false;
1949 for (
const auto &a : f->get_args()) {
1956 }
else if (
neq(*a->diff(s), *zero)) {
1965 }
else if (is_a<Abs>(*arg)) {
1967 }
else if (is_a<FunctionWrapper>(*arg)) {
1969 }
else if (is_a<PolyGamma>(*arg) or is_a<Zeta>(*arg)
1970 or is_a<UpperGamma>(*arg) or is_a<LowerGamma>(*arg)
1971 or is_a<Dirichlet_eta>(*arg)) {
1973 auto v = arg->get_args();
1975 if (has_symbol(*v[0], *rcp_static_cast<const Symbol>(p))) {
1981 }
else if (is_a<KroneckerDelta>(*arg)) {
1983 auto v = arg->get_args();
1985 if (has_symbol(*v[0], *rcp_static_cast<const Symbol>(p))
1986 or has_symbol(*v[1], *rcp_static_cast<const Symbol>(p))) {
1998 hash_t seed = SYMENGINE_DERIVATIVE;
1999 hash_combine<Basic>(seed, *arg_);
2000 for (
auto &p :
x_) {
2001 hash_combine<Basic>(seed, *p);
2008 if (is_a<Derivative>(o)
2009 and
eq(*arg_, *(down_cast<const Derivative &>(o).arg_))
2010 and unified_eq(
x_, down_cast<const Derivative &>(o).
x_))
2017 SYMENGINE_ASSERT(is_a<Derivative>(o))
2018 const Derivative &s = down_cast<const Derivative &>(o);
2019 int cmp = arg_->__cmp__(*(s.arg_));
2027 Subs::Subs(
const RCP<const Basic> &arg,
const map_basic_basic &dict)
2028 : arg_{arg}, dict_{dict}
2030 SYMENGINE_ASSIGN_TYPEID()
2031 SYMENGINE_ASSERT(is_canonical(arg, dict))
2034 bool Subs::is_canonical(const RCP<const
Basic> &arg,
2035 const map_basic_basic &dict)
const
2037 if (is_a<Derivative>(*arg)) {
2045 hash_t seed = SYMENGINE_SUBS;
2046 hash_combine<Basic>(seed, *arg_);
2047 for (
const auto &p : dict_) {
2048 hash_combine<Basic>(seed, *p.first);
2049 hash_combine<Basic>(seed, *p.second);
2056 if (is_a<Subs>(o) and
eq(*arg_, *(down_cast<const Subs &>(o).arg_))
2057 and unified_eq(dict_, down_cast<const Subs &>(o).dict_))
2064 SYMENGINE_ASSERT(is_a<Subs>(o))
2065 const Subs &s = down_cast<const Subs &>(o);
2066 int cmp = arg_->__cmp__(*(s.arg_));
2073 vec_basic Subs::get_variables()
const
2076 for (
const auto &p : dict_) {
2077 v.push_back(p.first);
2082 vec_basic Subs::get_point()
const
2085 for (
const auto &p : dict_) {
2086 v.push_back(p.second);
2093 vec_basic v = {arg_};
2094 for (
const auto &p : dict_) {
2095 v.push_back(p.first);
2097 for (
const auto &p : dict_) {
2098 v.push_back(p.second);
2105 SYMENGINE_ASSIGN_TYPEID()
2111 if (
eq(*arg, *zero))
2114 if (down_cast<const Number &>(*arg).is_negative()) {
2116 }
else if (not down_cast<const Number &>(*arg).is_exact()) {
2125 RCP<const Basic>
sinh(
const RCP<const Basic> &arg)
2127 if (
eq(*arg, *zero))
2130 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2131 if (not _arg->is_exact()) {
2132 return _arg->get_eval().sinh(*_arg);
2133 }
else if (_arg->is_negative()) {
2134 return neg(
sinh(zero->sub(*_arg)));
2138 bool b = handle_minus(arg, outArg(d));
2142 return make_rcp<const Sinh>(d);
2147 SYMENGINE_ASSIGN_TYPEID()
2153 if (
eq(*arg, *zero))
2156 if (down_cast<const Number &>(*arg).is_negative()) {
2158 }
else if (not down_cast<const Number &>(*arg).is_exact()) {
2167 RCP<const Basic>
csch(
const RCP<const Basic> &arg)
2169 if (
eq(*arg, *zero)) {
2173 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2174 if (not _arg->is_exact()) {
2175 return _arg->get_eval().csch(*_arg);
2176 }
else if (_arg->is_negative()) {
2177 return neg(
csch(zero->sub(*_arg)));
2181 bool b = handle_minus(arg, outArg(d));
2185 return make_rcp<const Csch>(d);
2190 SYMENGINE_ASSIGN_TYPEID()
2196 if (
eq(*arg, *zero))
2199 if (down_cast<const Number &>(*arg).is_negative()) {
2201 }
else if (not down_cast<const Number &>(*arg).is_exact()) {
2210 RCP<const Basic>
cosh(
const RCP<const Basic> &arg)
2212 if (
eq(*arg, *zero))
2215 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2216 if (not _arg->is_exact()) {
2217 return _arg->get_eval().cosh(*_arg);
2218 }
else if (_arg->is_negative()) {
2219 return cosh(zero->sub(*_arg));
2223 handle_minus(arg, outArg(d));
2224 return make_rcp<const Cosh>(d);
2229 SYMENGINE_ASSIGN_TYPEID()
2235 if (
eq(*arg, *zero))
2238 if (down_cast<const Number &>(*arg).is_negative()) {
2240 }
else if (not down_cast<const Number &>(*arg).is_exact()) {
2249 RCP<const Basic>
sech(
const RCP<const Basic> &arg)
2251 if (
eq(*arg, *zero))
2254 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2255 if (not _arg->is_exact()) {
2256 return _arg->get_eval().sech(*_arg);
2257 }
else if (_arg->is_negative()) {
2258 return sech(zero->sub(*_arg));
2262 handle_minus(arg, outArg(d));
2263 return make_rcp<const Sech>(d);
2268 SYMENGINE_ASSIGN_TYPEID()
2274 if (
eq(*arg, *zero))
2277 if (down_cast<const Number &>(*arg).is_negative()) {
2279 }
else if (not down_cast<const Number &>(*arg).is_exact()) {
2288 RCP<const Basic>
tanh(
const RCP<const Basic> &arg)
2290 if (
eq(*arg, *zero))
2293 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2294 if (not _arg->is_exact()) {
2295 return _arg->get_eval().tanh(*_arg);
2296 }
else if (_arg->is_negative()) {
2297 return neg(
tanh(zero->sub(*_arg)));
2302 bool b = handle_minus(arg, outArg(d));
2306 return make_rcp<const Tanh>(d);
2311 SYMENGINE_ASSIGN_TYPEID()
2317 if (
eq(*arg, *zero))
2320 if (down_cast<const Number &>(*arg).is_negative()) {
2322 }
else if (not down_cast<const Number &>(*arg).is_exact()) {
2331 RCP<const Basic>
coth(
const RCP<const Basic> &arg)
2333 if (
eq(*arg, *zero)) {
2337 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2338 if (not _arg->is_exact()) {
2339 return _arg->get_eval().coth(*_arg);
2340 }
else if (_arg->is_negative()) {
2341 return neg(
coth(zero->sub(*_arg)));
2345 bool b = handle_minus(arg, outArg(d));
2349 return make_rcp<const Coth>(d);
2354 SYMENGINE_ASSIGN_TYPEID()
2360 if (
eq(*arg, *zero) or
eq(*arg, *one) or
eq(*arg, *minus_one))
2363 if (down_cast<const Number &>(*arg).is_negative()) {
2365 }
else if (not down_cast<const Number &>(*arg).is_exact()) {
2374 RCP<const Basic>
asinh(
const RCP<const Basic> &arg)
2376 if (
eq(*arg, *zero))
2379 return log(
add(one, sq2));
2380 if (
eq(*arg, *minus_one))
2381 return log(
sub(sq2, one));
2383 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2384 if (not _arg->is_exact()) {
2385 return _arg->get_eval().asinh(*_arg);
2386 }
else if (_arg->is_negative()) {
2387 return neg(
asinh(zero->sub(*_arg)));
2391 bool b = handle_minus(arg, outArg(d));
2395 return make_rcp<const ASinh>(d);
2400 SYMENGINE_ASSIGN_TYPEID()
2406 if (
eq(*arg, *one) or
eq(*arg, *minus_one))
2409 if (down_cast<const Number &>(*arg).is_negative()) {
2411 }
else if (not down_cast<const Number &>(*arg).is_exact()) {
2420 RCP<const Basic>
acsch(
const RCP<const Basic> &arg)
2423 return log(
add(one, sq2));
2424 if (
eq(*arg, *minus_one))
2425 return log(
sub(sq2, one));
2428 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2429 if (not _arg->is_exact()) {
2430 return _arg->get_eval().acsch(*_arg);
2435 bool b = handle_minus(arg, outArg(d));
2439 return make_rcp<const ACsch>(d);
2444 SYMENGINE_ASSIGN_TYPEID()
2453 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
2459 RCP<const Basic>
acosh(
const RCP<const Basic> &arg)
2464 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
2465 return down_cast<const Number &>(*arg).get_eval().acosh(*arg);
2467 return make_rcp<const ACosh>(arg);
2472 SYMENGINE_ASSIGN_TYPEID()
2478 if (
eq(*arg, *zero))
2481 if (down_cast<const Number &>(*arg).is_negative()) {
2483 }
else if (not down_cast<const Number &>(*arg).is_exact()) {
2492 RCP<const Basic>
atanh(
const RCP<const Basic> &arg)
2494 if (
eq(*arg, *zero))
2497 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2498 if (not _arg->is_exact()) {
2499 return _arg->get_eval().atanh(*_arg);
2500 }
else if (_arg->is_negative()) {
2501 return neg(
atanh(zero->sub(*_arg)));
2505 bool b = handle_minus(arg, outArg(d));
2509 return make_rcp<const ATanh>(d);
2514 SYMENGINE_ASSIGN_TYPEID()
2521 if (down_cast<const Number &>(*arg).is_negative()) {
2523 }
else if (not down_cast<const Number &>(*arg).is_exact()) {
2532 RCP<const Basic>
acoth(
const RCP<const Basic> &arg)
2535 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2536 if (not _arg->is_exact()) {
2537 return _arg->get_eval().acoth(*_arg);
2538 }
else if (_arg->is_negative()) {
2539 return neg(
acoth(zero->sub(*_arg)));
2543 bool b = handle_minus(arg, outArg(d));
2547 return make_rcp<const ACoth>(d);
2552 SYMENGINE_ASSIGN_TYPEID()
2561 if (
eq(*arg, *zero))
2563 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
2569 RCP<const Basic>
asech(
const RCP<const Basic> &arg)
2574 if (
eq(*arg, *zero))
2577 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2578 if (not _arg->is_exact()) {
2579 return _arg->get_eval().asech(*_arg);
2582 return make_rcp<const ASech>(arg);
2646 const RCP<const Basic> &j)
2649 SYMENGINE_ASSIGN_TYPEID()
2654 const RCP<const Basic> &j)
const
2656 RCP<const Basic> diff =
expand(
sub(i, j));
2657 if (
eq(*diff, *zero)) {
2668 const RCP<const Basic> &b)
const
2674 const RCP<const Basic> &j)
2677 RCP<const Basic> diff =
expand(
sub(i, j));
2678 if (
eq(*diff, *zero)) {
2684 return make_rcp<const KroneckerDelta>(i, j);
2688 bool has_dup(
const vec_basic &arg)
2692 for (
const auto &p : arg) {
2694 if (it == d.end()) {
2705 SYMENGINE_ASSIGN_TYPEID()
2711 bool are_int =
true;
2712 for (
const auto &p : arg) {
2720 }
else if (has_dup(arg)) {
2732 RCP<const Basic> eval_levicivita(
const vec_basic &arg,
int len)
2735 RCP<const Basic> res = one;
2736 for (i = 0; i < len; i++) {
2737 for (j = i + 1; j < len; j++) {
2738 res =
mul(
sub(arg[j], arg[i]), res);
2747 bool are_int =
true;
2749 for (
const auto &p : arg) {
2758 return eval_levicivita(arg, len);
2759 }
else if (has_dup(arg)) {
2762 return make_rcp<const LeviCivita>(std::move(arg));
2773 SYMENGINE_ASSIGN_TYPEID()
2778 const RCP<const Basic> &a)
const
2784 if (is_a<Integer>(*s) and is_a<Integer>(*a)) {
2785 auto s_ = down_cast<const Integer &>(*s).as_int();
2786 if (s_ < 0 || s_ % 2 == 0)
2793 const RCP<const Basic> &b)
const
2798 RCP<const Basic>
zeta(
const RCP<const Basic> &s,
const RCP<const Basic> &a)
2801 if (down_cast<const Number &>(*s).is_zero()) {
2802 return sub(
div(one, i2), a);
2803 }
else if (down_cast<const Number &>(*s).is_one()) {
2805 }
else if (is_a<Integer>(*s) and is_a<Integer>(*a)) {
2806 auto s_ = down_cast<const Integer &>(*s).as_int();
2807 auto a_ = down_cast<const Integer &>(*a).as_int();
2808 RCP<const Basic>
zeta;
2810 RCP<const Number> res = (s_ % 2 == 0) ? one : minus_one;
2813 }
else if (s_ % 2 == 0) {
2819 return make_rcp<const Zeta>(s, a);
2826 return make_rcp<const Zeta>(s, a);
2829 RCP<const Basic>
zeta(
const RCP<const Basic> &s)
2831 return zeta(s, one);
2836 SYMENGINE_ASSIGN_TYPEID()
2844 if (not(is_a<Zeta>(*
zeta(s))))
2861 if (
is_a_Number(*s) and down_cast<const Number &>(*s).is_one()) {
2864 RCP<const Basic> z =
zeta(s);
2865 if (is_a<Zeta>(*z)) {
2866 return make_rcp<const Dirichlet_eta>(s);
2868 return mul(
sub(one, pow(i2,
sub(one, s))), z);
2874 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
2878 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
2889 RCP<const Basic>
erf(
const RCP<const Basic> &arg)
2891 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero()) {
2895 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2896 if (not _arg->is_exact()) {
2897 return _arg->get_eval().erf(*_arg);
2901 bool b = handle_minus(arg, outArg(d));
2905 return make_rcp<const Erf>(d);
2910 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
2914 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
2925 RCP<const Basic>
erfc(
const RCP<const Basic> &arg)
2927 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero()) {
2931 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2932 if (not _arg->is_exact()) {
2933 return _arg->get_eval().erfc(*_arg);
2938 bool b = handle_minus(arg, outArg(d));
2942 return make_rcp<const Erfc>(d);
2947 SYMENGINE_ASSIGN_TYPEID()
2953 if (is_a<Integer>(*arg))
2955 if (is_a<Rational>(*arg)
2956 and (get_den(down_cast<const Rational &>(*arg).as_rational_class()))
2960 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
2971 RCP<const Basic> gamma_positive_int(
const RCP<const Basic> &arg)
2973 SYMENGINE_ASSERT(is_a<Integer>(*arg))
2974 RCP<const Integer> arg_ = rcp_static_cast<const Integer>(arg);
2975 SYMENGINE_ASSERT(arg_->is_positive())
2976 return
factorial((arg_->subint(*one))->as_int());
2979 RCP<const
Basic> gamma_multiple_2(const RCP<const
Basic> &arg)
2981 SYMENGINE_ASSERT(is_a<Rational>(*arg))
2982 RCP<const Rational> arg_ = rcp_static_cast<const Rational>(arg);
2983 SYMENGINE_ASSERT(get_den(arg_->as_rational_class()) == 2)
2987 *(
integer(get_den(arg_->as_rational_class()))));
2988 if (arg_->is_positive()) {
2992 n = n->addint(*one);
2994 if ((n->as_int() & 1) == 0) {
3001 for (
int i = 3; i < 2 * k->as_int(); i = i + 2) {
3005 if (arg_->is_positive()) {
3006 return div(
mul(coeff, sqrt(pi)), pow(i2, n));
3008 return div(
mul(pow(i2, n), sqrt(pi)), coeff);
3012 RCP<const Basic>
gamma(
const RCP<const Basic> &arg)
3014 if (is_a<Integer>(*arg)) {
3015 RCP<const Integer> arg_ = rcp_static_cast<const Integer>(arg);
3016 if (arg_->is_positive()) {
3017 return gamma_positive_int(arg);
3021 }
else if (is_a<Rational>(*arg)) {
3022 RCP<const Rational> arg_ = rcp_static_cast<const Rational>(arg);
3023 if ((get_den(arg_->as_rational_class())) == 2) {
3024 return gamma_multiple_2(arg);
3026 return make_rcp<const Gamma>(arg);
3029 and not down_cast<const Number &>(*arg).is_exact()) {
3030 return down_cast<const Number &>(*arg).get_eval().gamma(*arg);
3032 return make_rcp<const Gamma>(arg);
3038 SYMENGINE_ASSIGN_TYPEID()
3043 const RCP<const Basic> &x)
const
3048 if (is_a<Integer>(*s)
3049 and down_cast<const Integer &>(*s).as_integer_class() > 1)
3051 if (is_a<Integer>(*
mul(i2, s)))
3053 #ifdef HAVE_SYMENGINE_MPFR
3054 #if MPFR_VERSION_MAJOR > 3
3055 if (is_a<RealMPFR>(*s) && is_a<RealMPFR>(*x))
3063 const RCP<const Basic> &b)
const
3069 const RCP<const Basic> &x)
3072 if (is_a<Integer>(*s)) {
3073 RCP<const Integer> s_int = rcp_static_cast<const Integer>(s);
3074 if (s_int->is_one()) {
3075 return sub(one,
exp(
mul(minus_one, x)));
3076 }
else if (s_int->as_integer_class() > 1) {
3077 s_int = s_int->subint(*one);
3079 mul(pow(x, s_int),
exp(
mul(minus_one, x))));
3081 return make_rcp<const LowerGamma>(s, x);
3083 }
else if (is_a<Integer>(*(
mul(i2, s)))) {
3084 RCP<const Number> s_num = rcp_static_cast<const Number>(s);
3085 s_num =
subnum(s_num, one);
3087 return mul(sqrt(pi),
3089 }
else if (s_num->is_positive()) {
3091 mul(pow(x, s_num),
exp(
mul(minus_one, x))));
3094 mul(pow(x, s),
exp(
mul(minus_one, x)))),
3097 #ifdef HAVE_SYMENGINE_MPFR
3098 #if MPFR_VERSION_MAJOR > 3
3099 }
else if (is_a<RealMPFR>(*s) && is_a<RealMPFR>(*x)) {
3100 const auto &s_ = down_cast<const RealMPFR &>(*s).i.get_mpfr_t();
3101 const auto &x_ = down_cast<const RealMPFR &>(*x).i.get_mpfr_t();
3102 if (mpfr_cmp_si(x_, 0) >= 0) {
3103 mpfr_class t(std::max(mpfr_get_prec(s_), mpfr_get_prec(x_)));
3104 mpfr_class u(std::max(mpfr_get_prec(s_), mpfr_get_prec(x_)));
3105 mpfr_gamma_inc(t.get_mpfr_t(), s_, x_, MPFR_RNDN);
3106 mpfr_gamma(u.get_mpfr_t(), s_, MPFR_RNDN);
3107 mpfr_sub(t.get_mpfr_t(), u.get_mpfr_t(), t.get_mpfr_t(), MPFR_RNDN);
3108 return real_mpfr(std::move(t));
3110 throw NotImplementedError(
"Not implemented.");
3115 return make_rcp<const LowerGamma>(s, x);
3121 SYMENGINE_ASSIGN_TYPEID()
3126 const RCP<const Basic> &x)
const
3131 if (is_a<Integer>(*s)
3132 and down_cast<const Integer &>(*s).as_integer_class() > 1)
3134 if (is_a<Integer>(*
mul(i2, s)))
3136 #ifdef HAVE_SYMENGINE_MPFR
3137 #if MPFR_VERSION_MAJOR > 3
3138 if (is_a<RealMPFR>(*s) && is_a<RealMPFR>(*x))
3146 const RCP<const Basic> &b)
const
3152 const RCP<const Basic> &x)
3155 if (is_a<Integer>(*s)) {
3156 RCP<const Integer> s_int = rcp_static_cast<const Integer>(s);
3157 if (s_int->is_one()) {
3158 return exp(
mul(minus_one, x));
3159 }
else if (s_int->as_integer_class() > 1) {
3160 s_int = s_int->subint(*one);
3162 mul(pow(x, s_int),
exp(
mul(minus_one, x))));
3165 return make_rcp<const LowerGamma>(s, x);
3167 }
else if (is_a<Integer>(*(
mul(i2, s)))) {
3168 RCP<const Number> s_num = rcp_static_cast<const Number>(s);
3169 s_num =
subnum(s_num, one);
3171 return mul(sqrt(pi),
3173 }
else if (s_num->is_positive()) {
3175 mul(pow(x, s_num),
exp(
mul(minus_one, x))));
3178 mul(pow(x, s),
exp(
mul(minus_one, x)))),
3181 #ifdef HAVE_SYMENGINE_MPFR
3182 #if MPFR_VERSION_MAJOR > 3
3183 }
else if (is_a<RealMPFR>(*s) && is_a<RealMPFR>(*x)) {
3184 const auto &s_ = down_cast<const RealMPFR &>(*s).i.get_mpfr_t();
3185 const auto &x_ = down_cast<const RealMPFR &>(*x).i.get_mpfr_t();
3186 if (mpfr_cmp_si(x_, 0) >= 0) {
3187 mpfr_class t(std::max(mpfr_get_prec(s_), mpfr_get_prec(x_)));
3188 mpfr_gamma_inc(t.get_mpfr_t(), s_, x_, MPFR_RNDN);
3189 return real_mpfr(std::move(t));
3191 throw NotImplementedError(
"Not implemented.");
3196 return make_rcp<const UpperGamma>(s, x);
3201 if (is_a<Integer>(*arg)) {
3202 RCP<const Integer> arg_int = rcp_static_cast<const Integer>(arg);
3203 if (not arg_int->is_positive()) {
3214 RCP<const Basic> LogGamma::rewrite_as_gamma()
const
3226 if (is_a<Integer>(*arg)) {
3227 RCP<const Integer> arg_int = rcp_static_cast<const Integer>(arg);
3228 if (not arg_int->is_positive()) {
3237 return make_rcp<const LogGamma>(arg);
3241 const RCP<const Basic> &y)
3243 if (x->__cmp__(*y) == -1) {
3244 return make_rcp<const Beta>(y, x);
3246 return make_rcp<const Beta>(x, y);
3251 if (x->__cmp__(*y) == -1) {
3254 if (is_a<Integer>(*x)
3255 or (is_a<Rational>(*x)
3256 and (get_den(down_cast<const Rational &>(*x).as_rational_class()))
3258 if (is_a<Integer>(*y)
3259 or (is_a<Rational>(*y)
3261 down_cast<const Rational &>(*y).as_rational_class()))
3269 RCP<const Basic> Beta::rewrite_as_gamma()
const
3276 const RCP<const Basic> &b)
const
3281 RCP<const Basic>
beta(
const RCP<const Basic> &x,
const RCP<const Basic> &y)
3284 if (
eq(*
add(x, y), *one)) {
3288 if (is_a<Integer>(*x)) {
3289 RCP<const Integer> x_int = rcp_static_cast<const Integer>(x);
3290 if (x_int->is_positive()) {
3291 if (is_a<Integer>(*y)) {
3292 RCP<const Integer> y_int = rcp_static_cast<const Integer>(y);
3293 if (y_int->is_positive()) {
3295 mul(gamma_positive_int(x), gamma_positive_int(y)),
3296 gamma_positive_int(
add(x, y)));
3300 }
else if (is_a<Rational>(*y)) {
3301 RCP<const Rational> y_ = rcp_static_cast<const Rational>(y);
3302 if (get_den(y_->as_rational_class()) == 2) {
3303 return div(
mul(gamma_positive_int(x), gamma_multiple_2(y)),
3304 gamma_multiple_2(
add(x, y)));
3314 if (is_a<Integer>(*y)) {
3315 RCP<const Integer> y_int = rcp_static_cast<const Integer>(y);
3316 if (y_int->is_positive()) {
3317 if (is_a<Rational>(*x)) {
3318 RCP<const Rational> x_ = rcp_static_cast<const Rational>(x);
3319 if (get_den(x_->as_rational_class()) == 2) {
3320 return div(
mul(gamma_positive_int(y), gamma_multiple_2(x)),
3321 gamma_multiple_2(
add(x, y)));
3331 if (is_a<const Rational>(*x)
3332 and get_den(down_cast<const Rational &>(*x).as_rational_class()) == 2) {
3333 if (is_a<Integer>(*y)) {
3334 RCP<const Integer> y_int = rcp_static_cast<const Integer>(y);
3335 if (y_int->is_positive()) {
3336 return div(
mul(gamma_multiple_2(x), gamma_positive_int(y)),
3337 gamma_multiple_2(
add(x, y)));
3342 if (is_a<const Rational>(*y)
3343 and get_den((down_cast<const Rational &>(*y)).as_rational_class())
3345 return div(
mul(gamma_multiple_2(x), gamma_multiple_2(y)),
3346 gamma_positive_int(
add(x, y)));
3352 bool PolyGamma::is_canonical(
const RCP<const Basic> &n,
3353 const RCP<const Basic> &x)
3355 if (
is_a_Number(*x) and not(down_cast<const Number &>(*x)).is_positive()) {
3358 if (
eq(*n, *zero)) {
3362 if (is_a<Rational>(*x)) {
3363 auto x_ = rcp_static_cast<const Rational>(x);
3364 auto den = get_den(x_->as_rational_class());
3365 if (den == 2 or den == 3 or den == 4) {
3373 RCP<const Basic> PolyGamma::rewrite_as_zeta()
const
3375 if (not is_a<Integer>(*
get_arg1())) {
3376 return rcp_from_this();
3378 RCP<const Integer> n = rcp_static_cast<const Integer>(
get_arg1());
3379 if (not(n->is_positive())) {
3380 return rcp_from_this();
3382 if ((n->as_int() & 1) == 0) {
3390 const RCP<const Basic> &b)
const
3396 const RCP<const Basic> &x_)
3400 and not(down_cast<const Number &>(*x_)).is_positive()) {
3403 if (is_a<Integer>(*n_) and is_a<Integer>(*x_)) {
3404 auto n = down_cast<const Integer &>(*n_).as_int();
3405 auto x = down_cast<const Integer &>(*x_).as_int();
3408 }
else if (n % 2 == 1) {
3412 if (
eq(*n_, *zero)) {
3413 if (
eq(*x_, *one)) {
3414 return neg(EulerGamma);
3416 if (is_a<Rational>(*x_)) {
3417 RCP<const Rational> x = rcp_static_cast<const Rational>(x_);
3418 const auto den = get_den(x->as_rational_class());
3419 const auto num = get_num(x->as_rational_class());
3420 const integer_class r = num % den;
3421 RCP<const Basic> res;
3423 res =
sub(
mul(im2,
log(i2)), EulerGamma);
3424 }
else if (den == 3) {
3432 }
else if (den == 4) {
3439 return make_rcp<const PolyGamma>(n_, x_);
3441 rational_class a(0), f(r, den);
3442 for (
unsigned long i = 0; i < (num - r) / den; ++i) {
3448 return make_rcp<const PolyGamma>(n_, x_);
3451 RCP<const Basic> digamma(
const RCP<const Basic> &x)
3456 RCP<const Basic> trigamma(
const RCP<const Basic> &x)
3463 SYMENGINE_ASSIGN_TYPEID()
3469 if (is_a<Integer>(*arg) or is_a<Rational>(*arg) or is_a<Complex>(*arg))
3471 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
3474 if (is_a<Abs>(*arg)) {
3490 RCP<const Basic>
abs(
const RCP<const Basic> &arg)
3492 if (is_a<Integer>(*arg)) {
3493 RCP<const Integer> arg_ = rcp_static_cast<const Integer>(arg);
3494 if (arg_->is_negative()) {
3499 }
else if (is_a<Rational>(*arg)) {
3500 RCP<const Rational> arg_ = rcp_static_cast<const Rational>(arg);
3501 if (arg_->is_negative()) {
3506 }
else if (is_a<Complex>(*arg)) {
3507 RCP<const Complex> arg_ = rcp_static_cast<const Complex>(arg);
3509 + arg_->imaginary_ * arg_->imaginary_));
3511 and not down_cast<const Number &>(*arg).is_exact()) {
3512 return down_cast<const Number &>(*arg).get_eval().abs(*arg);
3514 if (is_a<Abs>(*arg)) {
3519 handle_minus(arg, outArg(d));
3520 return make_rcp<const Abs>(d);
3525 SYMENGINE_ASSIGN_TYPEID()
3534 bool non_number_exists =
false;
3536 for (
const auto &p : arg) {
3537 if (is_a<Complex>(*p) or is_a<Max>(*p))
3540 non_number_exists =
true;
3545 return non_number_exists;
3553 RCP<const Basic>
max(
const vec_basic &arg)
3555 bool number_set =
false;
3556 RCP<const Number> max_number, difference;
3559 for (
const auto &p : arg) {
3560 if (is_a<Complex>(*p))
3561 throw SymEngineException(
"Complex can't be passed to max!");
3564 if (not number_set) {
3565 max_number = rcp_static_cast<const Number>(p);
3570 }
else if (
eq(*p, *NegInf)) {
3573 difference = down_cast<const Number &>(*p).sub(*max_number);
3575 if (difference->is_zero() and not difference->is_exact()) {
3576 if (max_number->is_exact())
3577 max_number = rcp_static_cast<const Number>(p);
3578 }
else if (difference->is_positive()) {
3579 max_number = rcp_static_cast<const Number>(p);
3584 }
else if (is_a<Max>(*p)) {
3585 for (
const auto &l : down_cast<const Max &>(*p).get_args()) {
3587 if (not number_set) {
3588 max_number = rcp_static_cast<const Number>(l);
3591 difference = rcp_static_cast<const Number>(l)->sub(
3594 if (difference->is_zero()
3595 and not difference->is_exact()) {
3596 if (max_number->is_exact())
3597 max_number = rcp_static_cast<const Number>(l);
3598 }
else if (difference->is_positive()) {
3599 max_number = rcp_static_cast<const Number>(l);
3613 new_args.insert(max_number);
3615 vec_basic final_args(new_args.size());
3616 std::copy(new_args.begin(), new_args.end(), final_args.begin());
3618 if (final_args.size() > 1) {
3619 return make_rcp<const Max>(std::move(final_args));
3620 }
else if (final_args.size() == 1) {
3621 return final_args[0];
3623 throw SymEngineException(
"Empty vec_basic passed to max!");
3629 SYMENGINE_ASSIGN_TYPEID()
3638 bool non_number_exists =
false;
3640 for (
const auto &p : arg) {
3641 if (is_a<Complex>(*p) or is_a<Min>(*p))
3644 non_number_exists =
true;
3649 return non_number_exists;
3657 RCP<const Basic>
min(
const vec_basic &arg)
3659 bool number_set =
false;
3660 RCP<const Number> min_number, difference;
3663 for (
const auto &p : arg) {
3664 if (is_a<Complex>(*p))
3665 throw SymEngineException(
"Complex can't be passed to min!");
3668 if (not number_set) {
3669 min_number = rcp_static_cast<const Number>(p);
3674 }
else if (
eq(*p, *NegInf)) {
3677 difference = min_number->sub(*rcp_static_cast<const Number>(p));
3679 if (difference->is_zero() and not difference->is_exact()) {
3680 if (min_number->is_exact())
3681 min_number = rcp_static_cast<const Number>(p);
3682 }
else if (difference->is_positive()) {
3683 min_number = rcp_static_cast<const Number>(p);
3688 }
else if (is_a<Min>(*p)) {
3689 for (
const auto &l : down_cast<const Min &>(*p).get_args()) {
3691 if (not number_set) {
3692 min_number = rcp_static_cast<const Number>(l);
3695 difference = min_number->sub(
3696 *rcp_static_cast<const Number>(l));
3698 if (difference->is_zero()
3699 and not difference->is_exact()) {
3700 if (min_number->is_exact())
3701 min_number = rcp_static_cast<const Number>(l);
3702 }
else if (difference->is_positive()) {
3703 min_number = rcp_static_cast<const Number>(l);
3717 new_args.insert(min_number);
3719 vec_basic final_args(new_args.size());
3720 std::copy(new_args.begin(), new_args.end(), final_args.begin());
3722 if (final_args.size() > 1) {
3723 return make_rcp<const Min>(std::move(final_args));
3724 }
else if (final_args.size() == 1) {
3725 return final_args[0];
3727 throw SymEngineException(
"Empty vec_basic passed to min!");
3734 SYMENGINE_ASSIGN_TYPEID()
3745 return make_rcp<const UnevaluatedExpr>(arg);
3748 RCP<const Basic> unevaluated_expr(
const RCP<const Basic> &arg)
3750 return make_rcp<const UnevaluatedExpr>(arg);
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.
static RCP< const Basic > from_dict(const RCP< const Number > &coef, umap_basic_num &&d)
Create an appropriate instance from dictionary quickly.
const RCP< const Number > & get_coef() const
The lowest unit of symbolic representation.
static RCP< const Beta > from_two_basic(const RCP< const Basic > &x, const RCP< const Basic > &y)
return Beta with ordered arguments
virtual RCP< const Basic > create(const RCP< const Basic > &a, const RCP< const Basic > &b) const=0
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.
Conjugate(const RCP< const Basic > &arg)
Conjugate constructor.
RCP< const Basic > create(const RCP< const Basic > &arg) const override
bool is_canonical(const RCP< const Basic > &arg) const
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.
int compare(const Basic &o) const override
bool is_canonical(const RCP< const Basic > &s) const
virtual RCP< const Basic > create(const RCP< const Basic > &arg) const=0
Method to construct classes with canonicalization.
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.
bool is_canonical(const RCP< const Basic > &i, const RCP< const Basic > &j) const
virtual RCP< const Basic > create(const RCP< const Basic > &a, const RCP< const Basic > &b) const=0
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
virtual RCP< const Basic > create(const RCP< const Basic > &a, const RCP< const Basic > &b) const=0
The lower incomplete gamma function.
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.
virtual RCP< const Basic > create(const RCP< const Basic > &arg) const =0
Method to construct classes with canonicalization.
RCP< const Basic > get_arg() const
virtual RCP< const Basic > create(const RCP< const Basic > &a, const RCP< const Basic > &b) const=0
static RCP< const Number > from_mpq(const rational_class &i)
const rational_class & as_rational_class() const
Convert to rational_class.
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
virtual RCP< const Basic > create(const RCP< const Basic > &a, const RCP< const Basic > &b) const =0
Method to construct classes with canonicalization.
RCP< const Basic > get_arg1() const
RCP< const Basic > get_arg2() const
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.
virtual RCP< const Basic > create(const RCP< const Basic > &a, const RCP< const Basic > &b) const=0
The upper incomplete gamma function.
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.
virtual RCP< const Basic > create(const RCP< const Basic > &a, const RCP< const Basic > &b) const=0
Method to construct classes with canonicalization.
bool is_canonical(const RCP< const Basic > &s, const RCP< const Basic > &a) const
Main namespace for SymEngine package.
bool is_a_Number(const Basic &b)
RCP< const Basic > csc(const RCP< const Basic > &arg)
Canonicalize Csc:
RCP< const Basic > atan(const RCP< const Basic > &arg)
Canonicalize ATan:
RCP< const Basic > add(const RCP< const Basic > &a, const RCP< const Basic > &b)
Adds two objects (safely).
RCP< const Integer > quotient_f(const Integer &n, const Integer &d)
RCP< const Basic > sec(const RCP< const Basic > &arg)
Canonicalize Sec:
RCP< const Basic > cos(const RCP< const Basic > &arg)
Canonicalize Cos:
std::enable_if< std::is_integral< T >::value, RCP< const Integer > >::type integer(T i)
RCP< const Basic > sinh(const RCP< const Basic > &arg)
Canonicalize Sinh:
RCP< const Integer > mod_f(const Integer &n, const Integer &d)
modulo round toward -inf
RCP< const Basic > beta(const RCP< const Basic > &x, const RCP< const Basic > &y)
Canonicalize Beta:
RCP< const Number > mulnum(const RCP< const Number > &self, const RCP< const Number > &other)
Multiply self and other
RCP< const Number > pownum(const RCP< const Number > &self, const RCP< const Number > &other)
Raise self to power other
RCP< const Number > bernoulli(unsigned long n)
RCP< const Basic > conjugate(const RCP< const Basic > &arg)
Canonicalize Conjugate.
RCP< const Basic > coth(const RCP< const Basic > &arg)
Canonicalize Coth:
RCP< const Basic > sin(const RCP< const Basic > &arg)
Canonicalize Sin:
RCP< const Basic > mul(const RCP< const Basic > &a, const RCP< const Basic > &b)
Multiplication.
RCP< const Basic > tan(const RCP< const Basic > &arg)
Canonicalize Tan:
RCP< const Integer > quotient(const Integer &n, const Integer &d)
RCP< const Basic > acos(const RCP< const Basic > &arg)
Canonicalize ACos:
RCP< const Number > divnum(const RCP< const Number > &self, const RCP< const Number > &other)
Divide self and other
RCP< const Number > subnum(const RCP< const Number > &self, const RCP< const Number > &other)
Subtract self and other
RCP< const Basic > erf(const RCP< const Basic > &arg)
Canonicalize Erf:
RCP< const Basic > neg(const RCP< const Basic > &a)
Negation.
RCP< const Basic > acsch(const RCP< const Basic > &arg)
Canonicalize ACsch:
RCP< const Basic > max(const vec_basic &arg)
Canonicalize Max:
RCP< const Basic > lowergamma(const RCP< const Basic > &s, const RCP< const Basic > &x)
Canonicalize LowerGamma:
RCP< const Basic > ceiling(const RCP< const Basic > &arg)
Canonicalize Ceiling:
RCP< const Basic > tanh(const RCP< const Basic > &arg)
Canonicalize Tanh:
RCP< const Basic > asin(const RCP< const Basic > &arg)
Canonicalize ASin:
RCP< const Basic > trig_to_sqrt(const RCP< const Basic > &arg)
RCP< const Basic > kronecker_delta(const RCP< const Basic > &i, const RCP< const Basic > &j)
Canonicalize KroneckerDelta:
bool inverse_lookup(const umap_basic_basic &d, const RCP< const Basic > &t, const Ptr< RCP< const Basic >> &index)
RCP< const Basic > sech(const RCP< const Basic > &arg)
Canonicalize Sech:
RCP< const Basic > cosh(const RCP< const Basic > &arg)
Canonicalize Cosh:
RCP< const Basic > zeta(const RCP< const Basic > &s, const RCP< const Basic > &a)
Create a new Zeta instance:
RCP< const Basic > acsc(const RCP< const Basic > &arg)
Canonicalize ACsc:
RCP< const Basic > floor(const RCP< const Basic > &arg)
Canonicalize Floor:
bool could_extract_minus(const Basic &arg)
RCP< const Basic > exp(const RCP< const Basic > &x)
Returns the natural exponential function E**x = pow(E, x)
RCP< const Number > harmonic(unsigned long n, long m)
Computes the sum of the inverses of the first perfect mth powers.
RCP< const Basic > uppergamma(const RCP< const Basic > &s, const RCP< const Basic > &x)
Canonicalize UpperGamma:
void insert(T1 &m, const T2 &first, const T3 &second)
RCP< const Integer > factorial(unsigned long n)
Factorial.
bool eq(const Basic &a, const Basic &b)
Checks equality for a and b
RCP< const Basic > sub(const RCP< const Basic > &a, const RCP< const Basic > &b)
Substracts b from a.
RCP< const Basic > erfc(const RCP< const Basic > &arg)
Canonicalize Erfc:
RCP< const Basic > lambertw(const RCP< const Basic > &arg)
Create a new LambertW instance:
RCP< const Basic > atan2(const RCP< const Basic > &num, const RCP< const Basic > &den)
Canonicalize ATan2:
RCP< const Basic > gamma(const RCP< const Basic > &arg)
Canonicalize Gamma:
RCP< const Basic > dirichlet_eta(const RCP< const Basic > &s)
Create a new Dirichlet_eta instance:
RCP< const Basic > csch(const RCP< const Basic > &arg)
Canonicalize Csch:
bool neq(const Basic &a, const Basic &b)
Checks inequality for a and b
RCP< const Basic > polygamma(const RCP< const Basic > &n_, const RCP< const Basic > &x_)
Canonicalize PolyGamma.
RCP< const Basic > div(const RCP< const Basic > &a, const RCP< const Basic > &b)
Division.
int unified_compare(const T &a, const T &b)
RCP< const Basic > asech(const RCP< const Basic > &arg)
Canonicalize ASech:
SYMENGINE_EXPORT RCP< const Basic > expand(const RCP< const Basic > &self, bool deep=true)
Expands self
bool is_a_Complex(const Basic &b)
RCP< const Basic > cot(const RCP< const Basic > &arg)
Canonicalize Cot:
RCP< const Basic > min(const vec_basic &arg)
Canonicalize Min:
RCP< const Basic > asec(const RCP< const Basic > &arg)
Canonicalize ASec:
RCP< const Basic > atanh(const RCP< const Basic > &arg)
Canonicalize ATanh:
RCP< const Basic > sign(const RCP< const Basic > &arg)
Canonicalize Sign.
RCP< const Basic > abs(const RCP< const Basic > &arg)
Canonicalize Abs:
RCP< const Basic > truncate(const RCP< const Basic > &arg)
Canonicalize Truncate:
RCP< const Basic > levi_civita(const vec_basic &arg)
Canonicalize LeviCivita:
RCP< const Basic > loggamma(const RCP< const Basic > &arg)
Canonicalize LogGamma:
bool get_pi_shift(const RCP< const Basic > &arg, const Ptr< RCP< const Number >> &n, const Ptr< RCP< const Basic >> &x)
RCP< const Basic > acoth(const RCP< const Basic > &arg)
Canonicalize ACoth:
RCP< const Basic > acosh(const RCP< const Basic > &arg)
Canonicalize ACosh:
RCP< const Basic > asinh(const RCP< const Basic > &arg)
Canonicalize ASinh:
RCP< const Basic > log(const RCP< const Basic > &arg)
Returns the Natural Logarithm from argument arg
RCP< const Basic > acot(const RCP< const Basic > &arg)
Canonicalize ACot:
void get_num_den(const Rational &rat, const Ptr< RCP< const Integer >> &num, const Ptr< RCP< const Integer >> &den)
returns the num and den of rational rat as RCP<const Integer>