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},
80 {
sub(sq2, one),
pow(i2, i3)},
81 {
sub(one, sq2),
pow(im2, i3)},
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)) {
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);
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);
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());
568 return make_rcp<const Sign>(arg);
573 SYMENGINE_ASSIGN_TYPEID()
582 if (is_a<Constant>(*arg)) {
585 if (is_a<Floor>(*arg)) {
588 if (is_a<Ceiling>(*arg)) {
591 if (is_a<Truncate>(*arg)) {
594 if (is_a<BooleanAtom>(*arg) or is_a_Relational(*arg)) {
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)) {
611 RCP<const Basic>
floor(
const RCP<const Basic> &arg)
614 if (down_cast<const Number &>(*arg).is_exact()) {
615 if (is_a<Rational>(*arg)) {
616 const Rational &s = down_cast<const Rational &>(*arg);
624 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
625 return _arg->get_eval().floor(*_arg);
627 if (is_a<Constant>(*arg)) {
634 if (
eq(*arg, *GoldenRatio)) {
637 if (
eq(*arg, *Catalan) or
eq(*arg, *EulerGamma)) {
641 if (is_a<Floor>(*arg)) {
644 if (is_a<Ceiling>(*arg)) {
647 if (is_a<Truncate>(*arg)) {
650 if (is_a<BooleanAtom>(*arg) or is_a_Relational(*arg)) {
651 throw SymEngineException(
652 "Boolean objects not allowed in this context.");
654 if (is_a<Add>(*arg)) {
655 RCP<const Number> s = down_cast<const Add &>(*arg).get_coef();
657 if (is_a<Integer>(*s)
658 and not down_cast<const Integer &>(*s).is_zero()) {
662 return make_rcp<const Floor>(arg);
667 SYMENGINE_ASSIGN_TYPEID()
676 if (is_a<Constant>(*arg)) {
679 if (is_a<Floor>(*arg)) {
682 if (is_a<Ceiling>(*arg)) {
685 if (is_a<Truncate>(*arg)) {
688 if (is_a<BooleanAtom>(*arg) or is_a_Relational(*arg)) {
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)) {
705 RCP<const Basic>
ceiling(
const RCP<const Basic> &arg)
708 if (down_cast<const Number &>(*arg).is_exact()) {
709 if (is_a<Rational>(*arg)) {
710 const Rational &s = down_cast<const Rational &>(*arg);
718 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
719 return _arg->get_eval().ceiling(*_arg);
721 if (is_a<Constant>(*arg)) {
728 if (
eq(*arg, *GoldenRatio)) {
731 if (
eq(*arg, *Catalan) or
eq(*arg, *EulerGamma)) {
735 if (is_a<Floor>(*arg)) {
738 if (is_a<Ceiling>(*arg)) {
741 if (is_a<Truncate>(*arg)) {
744 if (is_a<BooleanAtom>(*arg) or is_a_Relational(*arg)) {
745 throw SymEngineException(
746 "Boolean objects not allowed in this context.");
748 if (is_a<Add>(*arg)) {
749 RCP<const Number> s = down_cast<const Add &>(*arg).get_coef();
751 if (is_a<Integer>(*s)) {
756 return make_rcp<const Ceiling>(arg);
761 SYMENGINE_ASSIGN_TYPEID()
770 if (is_a<Constant>(*arg)) {
773 if (is_a<Floor>(*arg)) {
776 if (is_a<Ceiling>(*arg)) {
779 if (is_a<Truncate>(*arg)) {
782 if (is_a<BooleanAtom>(*arg) or is_a_Relational(*arg)) {
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)) {
799 RCP<const Basic>
truncate(
const RCP<const Basic> &arg)
802 if (down_cast<const Number &>(*arg).is_exact()) {
803 if (is_a<Rational>(*arg)) {
804 const Rational &s = down_cast<const Rational &>(*arg);
812 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
813 return _arg->get_eval().truncate(*_arg);
815 if (is_a<Constant>(*arg)) {
822 if (
eq(*arg, *GoldenRatio)) {
825 if (
eq(*arg, *Catalan) or
eq(*arg, *EulerGamma)) {
829 if (is_a<Floor>(*arg)) {
832 if (is_a<Ceiling>(*arg)) {
835 if (is_a<Truncate>(*arg)) {
838 if (is_a<BooleanAtom>(*arg) or is_a_Relational(*arg)) {
839 throw SymEngineException(
840 "Boolean objects not allowed in this context.");
842 if (is_a<Add>(*arg)) {
843 RCP<const Number> s = down_cast<const Add &>(*arg).get_coef();
845 if (is_a<Integer>(*s)) {
846 return add(s, make_rcp<const Truncate>(
850 return make_rcp<const Truncate>(arg);
855 SYMENGINE_ASSIGN_TYPEID()
862 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
865 if (trig_has_basic_shift(arg)) {
868 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
874 RCP<const Basic>
sin(
const RCP<const Basic> &arg)
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);
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());
888 RCP<const Basic> ret_arg;
890 bool conjugate = trig_simplify(arg, 2,
true,
false,
891 outArg(ret_arg), index,
sign);
898 return mul(minus_one,
cos(ret_arg));
901 if (
eq(*ret_arg, *zero)) {
907 if (
neq(*ret_arg, *arg)) {
910 return make_rcp<const Sin>(arg);
913 return mul(minus_one,
sin(ret_arg));
923 SYMENGINE_ASSIGN_TYPEID()
930 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
933 if (trig_has_basic_shift(arg)) {
936 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
942 RCP<const Basic>
cos(
const RCP<const Basic> &arg)
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);
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());
956 RCP<const Basic> ret_arg;
958 bool conjugate = trig_simplify(arg, 2,
false,
true,
959 outArg(ret_arg), index,
sign);
966 return mul(minus_one,
sin(ret_arg));
969 if (
eq(*ret_arg, *zero)) {
973 if (
neq(*ret_arg, *arg)) {
976 return make_rcp<const Cos>(ret_arg);
979 return mul(minus_one,
cos(ret_arg));
989 SYMENGINE_ASSIGN_TYPEID()
995 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
998 if (trig_has_basic_shift(arg)) {
1001 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1007 RCP<const Basic>
tan(
const RCP<const Basic> &arg)
1009 if (
eq(*arg, *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);
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());
1021 RCP<const Basic> ret_arg;
1023 bool conjugate = trig_simplify(arg, 1,
true,
true,
1024 outArg(ret_arg), index,
sign);
1029 return cot(ret_arg);
1031 return mul(minus_one,
cot(ret_arg));
1034 if (
eq(*ret_arg, *zero)) {
1036 div(sin_table()[index], sin_table()[(index + 6) % 24]));
1039 if (
neq(*ret_arg, *arg)) {
1040 return tan(ret_arg);
1042 return make_rcp<const Tan>(ret_arg);
1045 return mul(minus_one,
tan(ret_arg));
1055 SYMENGINE_ASSIGN_TYPEID()
1061 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
1064 if (trig_has_basic_shift(arg)) {
1067 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1073 RCP<const Basic>
cot(
const RCP<const Basic> &arg)
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);
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());
1085 RCP<const Basic> ret_arg;
1087 bool conjugate = trig_simplify(arg, 1,
true,
true,
1088 outArg(ret_arg), index,
sign);
1093 return tan(ret_arg);
1095 return mul(minus_one,
tan(ret_arg));
1098 if (
eq(*ret_arg, *zero)) {
1100 div(sin_table()[(index + 6) % 24], sin_table()[index]));
1103 if (
neq(*ret_arg, *arg)) {
1104 return cot(ret_arg);
1106 return make_rcp<const Cot>(ret_arg);
1109 return mul(minus_one,
cot(ret_arg));
1119 SYMENGINE_ASSIGN_TYPEID()
1126 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
1129 if (trig_has_basic_shift(arg)) {
1132 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1138 RCP<const Basic>
csc(
const RCP<const Basic> &arg)
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);
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());
1150 RCP<const Basic> ret_arg;
1152 bool conjugate = trig_simplify(arg, 2,
true,
false,
1153 outArg(ret_arg), index,
sign);
1158 return sec(ret_arg);
1160 return mul(minus_one,
sec(ret_arg));
1163 if (
eq(*ret_arg, *zero)) {
1167 if (
neq(*ret_arg, *arg)) {
1168 return csc(ret_arg);
1170 return make_rcp<const Csc>(ret_arg);
1173 return mul(minus_one,
csc(ret_arg));
1183 SYMENGINE_ASSIGN_TYPEID()
1190 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
1193 if (trig_has_basic_shift(arg)) {
1196 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1202 RCP<const Basic>
sec(
const RCP<const Basic> &arg)
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);
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());
1214 RCP<const Basic> ret_arg;
1216 bool conjugate = trig_simplify(arg, 2,
false,
true,
1217 outArg(ret_arg), index,
sign);
1222 return csc(ret_arg);
1224 return mul(minus_one,
csc(ret_arg));
1227 if (
eq(*ret_arg, *zero)) {
1231 if (
neq(*ret_arg, *arg)) {
1232 return sec(ret_arg);
1234 return make_rcp<const Sec>(ret_arg);
1237 return mul(minus_one,
sec(ret_arg));
1248 RCP<const Basic> i_arg;
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)))));
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))));
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))));
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))));
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)));
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)))));
1342 SYMENGINE_ASSIGN_TYPEID()
1348 if (
eq(*arg, *zero) or
eq(*arg, *one) or
eq(*arg, *minus_one))
1350 RCP<const Basic> index;
1354 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1360 RCP<const Basic>
asin(
const RCP<const Basic> &arg)
1362 if (
eq(*arg, *zero))
1364 else if (
eq(*arg, *one))
1366 else if (
eq(*arg, *minus_one))
1367 return mul(minus_one,
div(pi, i2));
1369 and not down_cast<const Number &>(*arg).is_exact()) {
1370 return down_cast<const Number &>(*arg).get_eval().asin(*arg);
1373 RCP<const Basic> index;
1376 return div(pi, index);
1378 return make_rcp<const ASin>(arg);
1384 SYMENGINE_ASSIGN_TYPEID()
1390 if (
eq(*arg, *zero) or
eq(*arg, *one) or
eq(*arg, *minus_one))
1392 RCP<const Basic> index;
1396 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1402 RCP<const Basic>
acos(
const RCP<const Basic> &arg)
1404 if (
eq(*arg, *zero))
1406 else if (
eq(*arg, *one))
1408 else if (
eq(*arg, *minus_one))
1411 and not down_cast<const Number &>(*arg).is_exact()) {
1412 return down_cast<const Number &>(*arg).get_eval().acos(*arg);
1415 RCP<const Basic> index;
1418 return sub(
div(pi, i2),
div(pi, index));
1420 return make_rcp<const ACos>(arg);
1426 SYMENGINE_ASSIGN_TYPEID()
1432 if (
eq(*arg, *one) or
eq(*arg, *minus_one))
1434 RCP<const Basic> index;
1438 and not down_cast<const Number &>(*arg).is_exact()) {
1444 RCP<const Basic>
asec(
const RCP<const Basic> &arg)
1448 else if (
eq(*arg, *minus_one))
1451 and not down_cast<const Number &>(*arg).is_exact()) {
1452 return down_cast<const Number &>(*arg).get_eval().asec(*arg);
1455 RCP<const Basic> index;
1458 return sub(
div(pi, i2),
div(pi, index));
1460 return make_rcp<const ASec>(arg);
1466 SYMENGINE_ASSIGN_TYPEID()
1472 if (
eq(*arg, *one) or
eq(*arg, *minus_one))
1474 RCP<const Basic> index;
1478 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1484 RCP<const Basic>
acsc(
const RCP<const Basic> &arg)
1488 else if (
eq(*arg, *minus_one))
1489 return div(pi, im2);
1491 and not down_cast<const Number &>(*arg).is_exact()) {
1492 return down_cast<const Number &>(*arg).get_eval().acsc(*arg);
1495 RCP<const Basic> index;
1498 return div(pi, index);
1500 return make_rcp<const ACsc>(arg);
1506 SYMENGINE_ASSIGN_TYPEID()
1512 if (
eq(*arg, *zero) or
eq(*arg, *one) or
eq(*arg, *minus_one))
1514 RCP<const Basic> index;
1518 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1524 RCP<const Basic>
atan(
const RCP<const Basic> &arg)
1526 if (
eq(*arg, *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)));
1533 and not down_cast<const Number &>(*arg).is_exact()) {
1534 return down_cast<const Number &>(*arg).get_eval().atan(*arg);
1537 RCP<const Basic> index;
1540 return div(pi, index);
1542 return make_rcp<const ATan>(arg);
1548 SYMENGINE_ASSIGN_TYPEID()
1554 if (
eq(*arg, *zero) or
eq(*arg, *one) or
eq(*arg, *minus_one))
1556 RCP<const Basic> index;
1560 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
1566 RCP<const Basic>
acot(
const RCP<const Basic> &arg)
1568 if (
eq(*arg, *zero))
1570 else if (
eq(*arg, *one))
1571 return div(pi,
mul(i2, i2));
1572 else if (
eq(*arg, *minus_one))
1575 and not down_cast<const Number &>(*arg).is_exact()) {
1576 return down_cast<const Number &>(*arg).get_eval().acot(*arg);
1579 RCP<const Basic> index;
1582 return sub(
div(pi, i2),
div(pi, index));
1584 return make_rcp<const ACot>(arg);
1591 SYMENGINE_ASSIGN_TYPEID()
1596 const RCP<const Basic> &den)
const
1598 if (
eq(*num, *zero) or
eq(*num, *den) or
eq(*num, *
mul(minus_one, den)))
1600 RCP<const Basic> index;
1609 const RCP<const Basic> &b)
const
1614 RCP<const Basic>
atan2(
const RCP<const Basic> &num,
const RCP<const Basic> &den)
1616 if (
eq(*num, *zero)) {
1618 RCP<const Number> den_new = rcp_static_cast<const Number>(den);
1619 if (den_new->is_negative())
1621 else if (den_new->is_positive())
1627 }
else if (
eq(*den, *zero)) {
1629 RCP<const Number> num_new = rcp_static_cast<const Number>(num);
1630 if (num_new->is_negative())
1631 return div(pi, im2);
1636 RCP<const Basic> index;
1649 RCP<const Number> den_new = rcp_static_cast<const Number>(den);
1650 RCP<const Number> num_new = rcp_static_cast<const Number>(num);
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);
1658 return add(
div(pi, index), pi);
1661 return div(pi, index);
1664 return div(pi, index);
1667 return make_rcp<const ATan2>(num, den);
1737 SYMENGINE_ASSIGN_TYPEID()
1744 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
1747 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_one())
1753 if (
is_a_Number(*arg) and down_cast<const Number &>(*arg).is_negative())
1757 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact())
1761 if (is_a<Complex>(*arg) and down_cast<const Complex &>(*arg).is_re_zero())
1764 if (is_a<Rational>(*arg))
1774 RCP<const Basic>
log(
const RCP<const Basic> &arg)
1776 if (
eq(*arg, *zero))
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()) {
1792 if (is_a<Rational>(*arg)) {
1793 RCP<const Integer> num, den;
1794 get_num_den(down_cast<const Rational &>(*arg), outArg(num),
1799 if (is_a<Complex>(*arg)) {
1800 RCP<const Complex> _arg = rcp_static_cast<const 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)),
1806 }
else if (arg_img->is_zero()) {
1808 }
else if (arg_img->is_positive()) {
1814 return make_rcp<const Log>(arg);
1817 RCP<const Basic>
log(
const RCP<const Basic> &arg,
const RCP<const Basic> &base)
1824 SYMENGINE_ASSIGN_TYPEID()
1830 if (
eq(*arg, *zero))
1848 if (
eq(*arg, *zero))
1855 return mul(minus_one,
log(i2));
1856 return make_rcp<const LambertW>(arg);
1860 : MultiArgFunction({arg}), name_{name} {SYMENGINE_ASSIGN_TYPEID()
1862 is_canonical(get_vec()))}
1867 SYMENGINE_ASSIGN_TYPEID()
1868 SYMENGINE_ASSERT(is_canonical(get_vec()))
1876 hash_t FunctionSymbol::__hash__()
const
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_);
1885 bool FunctionSymbol::__eq__(
const Basic &o)
const
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()))
1895 int FunctionSymbol::compare(
const Basic &o)
const
1897 SYMENGINE_ASSERT(is_a<FunctionSymbol>(o))
1899 if (name_ == s.name_)
1902 return name_ < s.name_ ? -1 : 1;
1905 RCP<const Basic> FunctionSymbol::create(
const vec_basic &x)
const
1907 return make_rcp<const FunctionSymbol>(name_, x);
1912 return make_rcp<const FunctionSymbol>(name, arg);
1915 RCP<const Basic> function_symbol(
std::string name,
const RCP<const Basic> &arg)
1917 return make_rcp<const FunctionSymbol>(name, arg);
1920 FunctionWrapper::FunctionWrapper(
std::string name,
const RCP<const Basic> &arg)
1921 : FunctionSymbol(name, arg){SYMENGINE_ASSIGN_TYPEID()}
1923 FunctionWrapper::FunctionWrapper(
std::string name,
const vec_basic &vec)
1924 : FunctionSymbol(name, vec){SYMENGINE_ASSIGN_TYPEID()}
1928 Derivative::Derivative(
const RCP<const Basic> &arg,
1929 const multiset_basic &x)
1932 SYMENGINE_ASSIGN_TYPEID()
1933 SYMENGINE_ASSERT(is_canonical(arg, x))
1936 bool Derivative::is_canonical(const RCP<const Basic> &arg,
1937 const multiset_basic &x)
const
1940 for (
const auto &a : x)
1941 if (not is_a<Symbol>(*a))
1943 if (is_a<FunctionSymbol>(*arg) or is_a<LeviCivita>(*arg)) {
1945 RCP<const Symbol> s = rcp_static_cast<const Symbol>(p);
1946 RCP<const MultiArgFunction> f
1947 = rcp_static_cast<const MultiArgFunction>(arg);
1948 bool found_s =
false;
1951 for (
const auto &a : f->get_args()) {
1958 }
else if (
neq(*a->diff(s), *zero)) {
1967 }
else if (is_a<Abs>(*arg)) {
1969 }
else if (is_a<FunctionWrapper>(*arg)) {
1971 }
else if (is_a<PolyGamma>(*arg) or is_a<Zeta>(*arg)
1972 or is_a<UpperGamma>(*arg) or is_a<LowerGamma>(*arg)
1973 or is_a<Dirichlet_eta>(*arg)) {
1975 auto v = arg->get_args();
1977 if (has_symbol(*v[0], *rcp_static_cast<const Symbol>(p))) {
1983 }
else if (is_a<KroneckerDelta>(*arg)) {
1985 auto v = arg->get_args();
1987 if (has_symbol(*v[0], *rcp_static_cast<const Symbol>(p))
1988 or has_symbol(*v[1], *rcp_static_cast<const Symbol>(p))) {
2000 hash_t seed = SYMENGINE_DERIVATIVE;
2001 hash_combine<Basic>(seed, *arg_);
2002 for (
auto &p :
x_) {
2003 hash_combine<Basic>(seed, *p);
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_))
2019 SYMENGINE_ASSERT(is_a<Derivative>(o))
2020 const Derivative &s = down_cast<const Derivative &>(o);
2021 int cmp = arg_->__cmp__(*(s.arg_));
2030 : arg_{arg}, dict_{dict}
2032 SYMENGINE_ASSIGN_TYPEID()
2033 SYMENGINE_ASSERT(is_canonical(arg, dict))
2036 bool Subs::is_canonical(const RCP<const
Basic> &arg,
2039 if (is_a<Derivative>(*arg)) {
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);
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_))
2066 SYMENGINE_ASSERT(is_a<Subs>(o))
2067 const Subs &s = down_cast<const Subs &>(o);
2068 int cmp = arg_->__cmp__(*(s.arg_));
2078 for (
const auto &p : dict_) {
2084 vec_basic Subs::get_point()
const
2087 for (
const auto &p : dict_) {
2096 for (
const auto &p : dict_) {
2099 for (
const auto &p : dict_) {
2107 SYMENGINE_ASSIGN_TYPEID()
2113 if (
eq(*arg, *zero))
2116 if (down_cast<const Number &>(*arg).is_negative()) {
2118 }
else if (not down_cast<const Number &>(*arg).is_exact()) {
2127 RCP<const Basic>
sinh(
const RCP<const Basic> &arg)
2129 if (
eq(*arg, *zero))
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)));
2140 bool b = handle_minus(arg, outArg(d));
2144 return make_rcp<const Sinh>(d);
2149 SYMENGINE_ASSIGN_TYPEID()
2155 if (
eq(*arg, *zero))
2158 if (down_cast<const Number &>(*arg).is_negative()) {
2160 }
else if (not down_cast<const Number &>(*arg).is_exact()) {
2169 RCP<const Basic>
csch(
const RCP<const Basic> &arg)
2171 if (
eq(*arg, *zero)) {
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)));
2183 bool b = handle_minus(arg, outArg(d));
2187 return make_rcp<const Csch>(d);
2192 SYMENGINE_ASSIGN_TYPEID()
2198 if (
eq(*arg, *zero))
2201 if (down_cast<const Number &>(*arg).is_negative()) {
2203 }
else if (not down_cast<const Number &>(*arg).is_exact()) {
2212 RCP<const Basic>
cosh(
const RCP<const Basic> &arg)
2214 if (
eq(*arg, *zero))
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));
2225 handle_minus(arg, outArg(d));
2226 return make_rcp<const Cosh>(d);
2231 SYMENGINE_ASSIGN_TYPEID()
2237 if (
eq(*arg, *zero))
2240 if (down_cast<const Number &>(*arg).is_negative()) {
2242 }
else if (not down_cast<const Number &>(*arg).is_exact()) {
2251 RCP<const Basic>
sech(
const RCP<const Basic> &arg)
2253 if (
eq(*arg, *zero))
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));
2264 handle_minus(arg, outArg(d));
2265 return make_rcp<const Sech>(d);
2270 SYMENGINE_ASSIGN_TYPEID()
2276 if (
eq(*arg, *zero))
2279 if (down_cast<const Number &>(*arg).is_negative()) {
2281 }
else if (not down_cast<const Number &>(*arg).is_exact()) {
2290 RCP<const Basic>
tanh(
const RCP<const Basic> &arg)
2292 if (
eq(*arg, *zero))
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)));
2304 bool b = handle_minus(arg, outArg(d));
2308 return make_rcp<const Tanh>(d);
2313 SYMENGINE_ASSIGN_TYPEID()
2319 if (
eq(*arg, *zero))
2322 if (down_cast<const Number &>(*arg).is_negative()) {
2324 }
else if (not down_cast<const Number &>(*arg).is_exact()) {
2333 RCP<const Basic>
coth(
const RCP<const Basic> &arg)
2335 if (
eq(*arg, *zero)) {
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)));
2347 bool b = handle_minus(arg, outArg(d));
2351 return make_rcp<const Coth>(d);
2356 SYMENGINE_ASSIGN_TYPEID()
2362 if (
eq(*arg, *zero) or
eq(*arg, *one) or
eq(*arg, *minus_one))
2365 if (down_cast<const Number &>(*arg).is_negative()) {
2367 }
else if (not down_cast<const Number &>(*arg).is_exact()) {
2376 RCP<const Basic>
asinh(
const RCP<const Basic> &arg)
2378 if (
eq(*arg, *zero))
2381 return log(
add(one, sq2));
2382 if (
eq(*arg, *minus_one))
2383 return log(
sub(sq2, one));
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)));
2393 bool b = handle_minus(arg, outArg(d));
2397 return make_rcp<const ASinh>(d);
2402 SYMENGINE_ASSIGN_TYPEID()
2408 if (
eq(*arg, *one) or
eq(*arg, *minus_one))
2411 if (down_cast<const Number &>(*arg).is_negative()) {
2413 }
else if (not down_cast<const Number &>(*arg).is_exact()) {
2422 RCP<const Basic>
acsch(
const RCP<const Basic> &arg)
2425 return log(
add(one, sq2));
2426 if (
eq(*arg, *minus_one))
2427 return log(
sub(sq2, one));
2430 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2431 if (not _arg->is_exact()) {
2432 return _arg->get_eval().acsch(*_arg);
2437 bool b = handle_minus(arg, outArg(d));
2441 return make_rcp<const ACsch>(d);
2446 SYMENGINE_ASSIGN_TYPEID()
2455 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
2461 RCP<const Basic>
acosh(
const RCP<const Basic> &arg)
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);
2469 return make_rcp<const ACosh>(arg);
2474 SYMENGINE_ASSIGN_TYPEID()
2480 if (
eq(*arg, *zero))
2483 if (down_cast<const Number &>(*arg).is_negative()) {
2485 }
else if (not down_cast<const Number &>(*arg).is_exact()) {
2494 RCP<const Basic>
atanh(
const RCP<const Basic> &arg)
2496 if (
eq(*arg, *zero))
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)));
2507 bool b = handle_minus(arg, outArg(d));
2511 return make_rcp<const ATanh>(d);
2516 SYMENGINE_ASSIGN_TYPEID()
2523 if (down_cast<const Number &>(*arg).is_negative()) {
2525 }
else if (not down_cast<const Number &>(*arg).is_exact()) {
2534 RCP<const Basic>
acoth(
const RCP<const Basic> &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)));
2545 bool b = handle_minus(arg, outArg(d));
2549 return make_rcp<const ACoth>(d);
2554 SYMENGINE_ASSIGN_TYPEID()
2563 if (
eq(*arg, *zero))
2565 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
2571 RCP<const Basic>
asech(
const RCP<const Basic> &arg)
2576 if (
eq(*arg, *zero))
2579 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2580 if (not _arg->is_exact()) {
2581 return _arg->get_eval().asech(*_arg);
2584 return make_rcp<const ASech>(arg);
2648 const RCP<const Basic> &j)
2651 SYMENGINE_ASSIGN_TYPEID()
2656 const RCP<const Basic> &j)
const
2658 RCP<const Basic> diff =
expand(
sub(i, j));
2659 if (
eq(*diff, *zero)) {
2670 const RCP<const Basic> &b)
const
2676 const RCP<const Basic> &j)
2679 RCP<const Basic> diff =
expand(
sub(i, j));
2680 if (
eq(*diff, *zero)) {
2686 return make_rcp<const KroneckerDelta>(i, j);
2690 bool has_dup(
const vec_basic &arg)
2694 for (
const auto &p : arg) {
2696 if (it == d.end()) {
2707 SYMENGINE_ASSIGN_TYPEID()
2713 bool are_int =
true;
2714 for (
const auto &p : arg) {
2722 }
else if (has_dup(arg)) {
2734 RCP<const Basic> eval_levicivita(
const vec_basic &arg,
int len)
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);
2749 bool are_int =
true;
2751 for (
const auto &p : arg) {
2760 return eval_levicivita(arg, len);
2761 }
else if (has_dup(arg)) {
2764 return make_rcp<const LeviCivita>(
std::move(arg));
2775 SYMENGINE_ASSIGN_TYPEID()
2780 const RCP<const Basic> &a)
const
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)
2795 const RCP<const Basic> &b)
const
2800 RCP<const Basic>
zeta(
const RCP<const Basic> &s,
const RCP<const Basic> &a)
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()) {
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;
2812 RCP<const Number> res = (s_ % 2 == 0) ? one : minus_one;
2815 }
else if (s_ % 2 == 0) {
2821 return make_rcp<const Zeta>(s, a);
2828 return make_rcp<const Zeta>(s, a);
2831 RCP<const Basic>
zeta(
const RCP<const Basic> &s)
2833 return zeta(s, one);
2838 SYMENGINE_ASSIGN_TYPEID()
2846 if (not(is_a<Zeta>(*
zeta(s))))
2863 if (
is_a_Number(*s) and down_cast<const Number &>(*s).is_one()) {
2866 RCP<const Basic> z =
zeta(s);
2867 if (is_a<Zeta>(*z)) {
2868 return make_rcp<const Dirichlet_eta>(s);
2870 return mul(
sub(one, pow(i2,
sub(one, s))), z);
2876 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
2880 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
2891 RCP<const Basic>
erf(
const RCP<const Basic> &arg)
2893 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero()) {
2897 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2898 if (not _arg->is_exact()) {
2899 return _arg->get_eval().erf(*_arg);
2903 bool b = handle_minus(arg, outArg(d));
2907 return make_rcp<const Erf>(d);
2912 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero())
2916 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
2927 RCP<const Basic>
erfc(
const RCP<const Basic> &arg)
2929 if (is_a<Integer>(*arg) and down_cast<const Integer &>(*arg).is_zero()) {
2933 RCP<const Number> _arg = rcp_static_cast<const Number>(arg);
2934 if (not _arg->is_exact()) {
2935 return _arg->get_eval().erfc(*_arg);
2940 bool b = handle_minus(arg, outArg(d));
2944 return make_rcp<const Erfc>(d);
2949 SYMENGINE_ASSIGN_TYPEID()
2955 if (is_a<Integer>(*arg))
2957 if (is_a<Rational>(*arg)
2958 and (get_den(down_cast<const Rational &>(*arg).as_rational_class()))
2962 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
2973 RCP<const Basic> gamma_positive_int(
const RCP<const Basic> &arg)
2975 SYMENGINE_ASSERT(is_a<Integer>(*arg))
2976 RCP<const Integer> arg_ = rcp_static_cast<const Integer>(arg);
2977 SYMENGINE_ASSERT(arg_->is_positive())
2978 return
factorial((arg_->subint(*one))->as_int());
2981 RCP<const
Basic> gamma_multiple_2(const RCP<const
Basic> &arg)
2983 SYMENGINE_ASSERT(is_a<Rational>(*arg))
2984 RCP<const Rational> arg_ = rcp_static_cast<const Rational>(arg);
2985 SYMENGINE_ASSERT(get_den(arg_->as_rational_class()) == 2)
2989 *(
integer(get_den(arg_->as_rational_class()))));
2990 if (arg_->is_positive()) {
2994 n = n->addint(*one);
2996 if ((n->as_int() & 1) == 0) {
3003 for (
int i = 3; i < 2 * k->as_int(); i = i + 2) {
3007 if (arg_->is_positive()) {
3014 RCP<const Basic>
gamma(
const RCP<const Basic> &arg)
3016 if (is_a<Integer>(*arg)) {
3017 RCP<const Integer> arg_ = rcp_static_cast<const Integer>(arg);
3018 if (arg_->is_positive()) {
3019 return gamma_positive_int(arg);
3023 }
else if (is_a<Rational>(*arg)) {
3024 RCP<const Rational> arg_ = rcp_static_cast<const Rational>(arg);
3025 if ((get_den(arg_->as_rational_class())) == 2) {
3026 return gamma_multiple_2(arg);
3028 return make_rcp<const Gamma>(arg);
3031 and not down_cast<const Number &>(*arg).is_exact()) {
3032 return down_cast<const Number &>(*arg).get_eval().gamma(*arg);
3034 return make_rcp<const Gamma>(arg);
3040 SYMENGINE_ASSIGN_TYPEID()
3045 const RCP<const Basic> &x)
const
3050 if (is_a<Integer>(*s)
3051 and down_cast<const Integer &>(*s).as_integer_class() > 1)
3053 if (is_a<Integer>(*
mul(i2, s)))
3055 #ifdef HAVE_SYMENGINE_MPFR
3056 #if MPFR_VERSION_MAJOR > 3
3057 if (is_a<RealMPFR>(*s) && is_a<RealMPFR>(*x))
3065 const RCP<const Basic> &b)
const
3071 const RCP<const Basic> &x)
3074 if (is_a<Integer>(*s)) {
3075 RCP<const Integer> s_int = rcp_static_cast<const 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);
3081 mul(pow(x, s_int),
exp(
mul(minus_one, x))));
3083 return make_rcp<const LowerGamma>(s, x);
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);
3089 return mul(sqrt(pi),
3091 }
else if (s_num->is_positive()) {
3093 mul(pow(x, s_num),
exp(
mul(minus_one, x))));
3096 mul(pow(x, s),
exp(
mul(minus_one, x)))),
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) {
3105 mpfr_class t(
std::max(mpfr_get_prec(s_), mpfr_get_prec(x_)));
3106 mpfr_class u(
std::max(mpfr_get_prec(s_), mpfr_get_prec(x_)));
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);
3112 throw NotImplementedError(
"Not implemented.");
3117 return make_rcp<const LowerGamma>(s, x);
3123 SYMENGINE_ASSIGN_TYPEID()
3128 const RCP<const Basic> &x)
const
3133 if (is_a<Integer>(*s)
3134 and down_cast<const Integer &>(*s).as_integer_class() > 1)
3136 if (is_a<Integer>(*
mul(i2, s)))
3138 #ifdef HAVE_SYMENGINE_MPFR
3139 #if MPFR_VERSION_MAJOR > 3
3140 if (is_a<RealMPFR>(*s) && is_a<RealMPFR>(*x))
3148 const RCP<const Basic> &b)
const
3154 const RCP<const Basic> &x)
3157 if (is_a<Integer>(*s)) {
3158 RCP<const Integer> s_int = rcp_static_cast<const 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);
3164 mul(pow(x, s_int),
exp(
mul(minus_one, x))));
3167 return make_rcp<const LowerGamma>(s, x);
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);
3173 return mul(sqrt(pi),
3175 }
else if (s_num->is_positive()) {
3177 mul(pow(x, s_num),
exp(
mul(minus_one, x))));
3180 mul(pow(x, s),
exp(
mul(minus_one, x)))),
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) {
3189 mpfr_class t(
std::max(mpfr_get_prec(s_), mpfr_get_prec(x_)));
3190 mpfr_gamma_inc(t.get_mpfr_t(), s_, x_, MPFR_RNDN);
3193 throw NotImplementedError(
"Not implemented.");
3198 return make_rcp<const UpperGamma>(s, x);
3203 if (is_a<Integer>(*arg)) {
3204 RCP<const Integer> arg_int = rcp_static_cast<const Integer>(arg);
3205 if (not arg_int->is_positive()) {
3216 RCP<const Basic> LogGamma::rewrite_as_gamma()
const
3228 if (is_a<Integer>(*arg)) {
3229 RCP<const Integer> arg_int = rcp_static_cast<const Integer>(arg);
3230 if (not arg_int->is_positive()) {
3239 return make_rcp<const LogGamma>(arg);
3243 const RCP<const Basic> &y)
3245 if (x->__cmp__(*y) == -1) {
3246 return make_rcp<const Beta>(y, x);
3248 return make_rcp<const Beta>(x, y);
3253 if (x->__cmp__(*y) == -1) {
3256 if (is_a<Integer>(*x)
3257 or (is_a<Rational>(*x)
3258 and (get_den(down_cast<const Rational &>(*x).as_rational_class()))
3260 if (is_a<Integer>(*y)
3261 or (is_a<Rational>(*y)
3263 down_cast<const Rational &>(*y).as_rational_class()))
3271 RCP<const Basic> Beta::rewrite_as_gamma()
const
3278 const RCP<const Basic> &b)
const
3283 RCP<const Basic>
beta(
const RCP<const Basic> &x,
const RCP<const Basic> &y)
3286 if (
eq(*
add(x, y), *one)) {
3290 if (is_a<Integer>(*x)) {
3291 RCP<const Integer> x_int = rcp_static_cast<const Integer>(x);
3292 if (x_int->is_positive()) {
3293 if (is_a<Integer>(*y)) {
3294 RCP<const Integer> y_int = rcp_static_cast<const Integer>(y);
3295 if (y_int->is_positive()) {
3297 mul(gamma_positive_int(x), gamma_positive_int(y)),
3298 gamma_positive_int(
add(x, y)));
3302 }
else if (is_a<Rational>(*y)) {
3303 RCP<const Rational> y_ = rcp_static_cast<const 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)));
3316 if (is_a<Integer>(*y)) {
3317 RCP<const Integer> y_int = rcp_static_cast<const Integer>(y);
3318 if (y_int->is_positive()) {
3319 if (is_a<Rational>(*x)) {
3320 RCP<const Rational> x_ = rcp_static_cast<const 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)));
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)) {
3336 RCP<const Integer> y_int = rcp_static_cast<const 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)));
3344 if (is_a<const Rational>(*y)
3345 and get_den((down_cast<const Rational &>(*y)).as_rational_class())
3347 return div(
mul(gamma_multiple_2(x), gamma_multiple_2(y)),
3348 gamma_positive_int(
add(x, y)));
3354 bool PolyGamma::is_canonical(
const RCP<const Basic> &n,
3355 const RCP<const Basic> &x)
3357 if (
is_a_Number(*x) and not(down_cast<const Number &>(*x)).is_positive()) {
3360 if (
eq(*n, *zero)) {
3364 if (is_a<Rational>(*x)) {
3365 auto x_ = rcp_static_cast<const Rational>(x);
3366 auto den = get_den(x_->as_rational_class());
3367 if (den == 2 or den == 3 or den == 4) {
3375 RCP<const Basic> PolyGamma::rewrite_as_zeta()
const
3377 if (not is_a<Integer>(*
get_arg1())) {
3378 return rcp_from_this();
3380 RCP<const Integer> n = rcp_static_cast<const Integer>(
get_arg1());
3381 if (not(n->is_positive())) {
3382 return rcp_from_this();
3384 if ((n->as_int() & 1) == 0) {
3392 const RCP<const Basic> &b)
const
3398 const RCP<const Basic> &x_)
3402 and not(down_cast<const Number &>(*x_)).is_positive()) {
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();
3410 }
else if (n % 2 == 1) {
3414 if (
eq(*n_, *zero)) {
3415 if (
eq(*x_, *one)) {
3416 return neg(EulerGamma);
3418 if (is_a<Rational>(*x_)) {
3419 RCP<const Rational> x = rcp_static_cast<const 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;
3425 res =
sub(
mul(im2,
log(i2)), EulerGamma);
3426 }
else if (den == 3) {
3434 }
else if (den == 4) {
3441 return make_rcp<const PolyGamma>(n_, x_);
3443 rational_class a(0), f(r, den);
3444 for (
unsigned long i = 0; i < (num - r) / den; ++i) {
3450 return make_rcp<const PolyGamma>(n_, x_);
3453 RCP<const Basic> digamma(
const RCP<const Basic> &x)
3458 RCP<const Basic> trigamma(
const RCP<const Basic> &x)
3465 SYMENGINE_ASSIGN_TYPEID()
3471 if (is_a<Integer>(*arg) or is_a<Rational>(*arg) or is_a<Complex>(*arg))
3473 if (
is_a_Number(*arg) and not down_cast<const Number &>(*arg).is_exact()) {
3476 if (is_a<Abs>(*arg)) {
3492 RCP<const Basic>
abs(
const RCP<const Basic> &arg)
3494 if (is_a<Integer>(*arg)) {
3495 RCP<const Integer> arg_ = rcp_static_cast<const Integer>(arg);
3496 if (arg_->is_negative()) {
3501 }
else if (is_a<Rational>(*arg)) {
3502 RCP<const Rational> arg_ = rcp_static_cast<const Rational>(arg);
3503 if (arg_->is_negative()) {
3508 }
else if (is_a<Complex>(*arg)) {
3509 RCP<const Complex> arg_ = rcp_static_cast<const Complex>(arg);
3511 + arg_->imaginary_ * arg_->imaginary_));
3513 and not down_cast<const Number &>(*arg).is_exact()) {
3514 return down_cast<const Number &>(*arg).get_eval().abs(*arg);
3516 if (is_a<Abs>(*arg)) {
3521 handle_minus(arg, outArg(d));
3522 return make_rcp<const Abs>(d);
3527 SYMENGINE_ASSIGN_TYPEID()
3536 bool non_number_exists =
false;
3538 for (
const auto &p : arg) {
3539 if (is_a<Complex>(*p) or is_a<Max>(*p))
3542 non_number_exists =
true;
3547 return non_number_exists;
3557 bool number_set =
false;
3558 RCP<const Number> max_number, difference;
3561 for (
const auto &p : arg) {
3562 if (is_a<Complex>(*p))
3563 throw SymEngineException(
"Complex can't be passed to max!");
3566 if (not number_set) {
3567 max_number = rcp_static_cast<const Number>(p);
3572 }
else if (
eq(*p, *NegInf)) {
3575 difference = down_cast<const Number &>(*p).sub(*max_number);
3577 if (difference->is_zero() and not difference->is_exact()) {
3578 if (max_number->is_exact())
3579 max_number = rcp_static_cast<const Number>(p);
3580 }
else if (difference->is_positive()) {
3581 max_number = rcp_static_cast<const Number>(p);
3586 }
else if (is_a<Max>(*p)) {
3587 for (
const auto &l : down_cast<const Max &>(*p).get_args()) {
3589 if (not number_set) {
3590 max_number = rcp_static_cast<const Number>(l);
3593 difference = rcp_static_cast<const Number>(l)->sub(
3596 if (difference->is_zero()
3597 and not difference->is_exact()) {
3598 if (max_number->is_exact())
3599 max_number = rcp_static_cast<const Number>(l);
3600 }
else if (difference->is_positive()) {
3601 max_number = rcp_static_cast<const Number>(l);
3615 new_args.
insert(max_number);
3620 if (final_args.
size() > 1) {
3621 return make_rcp<const Max>(
std::move(final_args));
3622 }
else if (final_args.
size() == 1) {
3623 return final_args[0];
3625 throw SymEngineException(
"Empty vec_basic passed to max!");
3631 SYMENGINE_ASSIGN_TYPEID()
3640 bool non_number_exists =
false;
3642 for (
const auto &p : arg) {
3643 if (is_a<Complex>(*p) or is_a<Min>(*p))
3646 non_number_exists =
true;
3651 return non_number_exists;
3661 bool number_set =
false;
3662 RCP<const Number> min_number, difference;
3665 for (
const auto &p : arg) {
3666 if (is_a<Complex>(*p))
3667 throw SymEngineException(
"Complex can't be passed to min!");
3670 if (not number_set) {
3671 min_number = rcp_static_cast<const Number>(p);
3676 }
else if (
eq(*p, *NegInf)) {
3679 difference = min_number->sub(*rcp_static_cast<const Number>(p));
3681 if (difference->is_zero() and not difference->is_exact()) {
3682 if (min_number->is_exact())
3683 min_number = rcp_static_cast<const Number>(p);
3684 }
else if (difference->is_positive()) {
3685 min_number = rcp_static_cast<const Number>(p);
3690 }
else if (is_a<Min>(*p)) {
3691 for (
const auto &l : down_cast<const Min &>(*p).get_args()) {
3693 if (not number_set) {
3694 min_number = rcp_static_cast<const Number>(l);
3697 difference = min_number->sub(
3698 *rcp_static_cast<const Number>(l));
3700 if (difference->is_zero()
3701 and not difference->is_exact()) {
3702 if (min_number->is_exact())
3703 min_number = rcp_static_cast<const Number>(l);
3704 }
else if (difference->is_positive()) {
3705 min_number = rcp_static_cast<const Number>(l);
3719 new_args.
insert(min_number);
3724 if (final_args.
size() > 1) {
3725 return make_rcp<const Min>(
std::move(final_args));
3726 }
else if (final_args.
size() == 1) {
3727 return final_args[0];
3729 throw SymEngineException(
"Empty vec_basic passed to min!");
3736 SYMENGINE_ASSIGN_TYPEID()
3747 return make_rcp<const UnevaluatedExpr>(arg);
3750 RCP<const Basic> unevaluated_expr(
const RCP<const Basic> &arg)
3752 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)
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>
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.
std::enable_if< std::is_integral< T >::value, RCP< const Integer > >::type integer(T i)
RCP< const Basic > sec(const RCP< const Basic > &arg)
Canonicalize Sec:
RCP< const Number > mulnum(const RCP< const Number > &self, const RCP< const Number > &other)
Multiply self and other
RCP< const Basic > polygamma(const RCP< const Basic > &n_, const RCP< const Basic > &x_)
Canonicalize PolyGamma.
RCP< const Number > pownum(const RCP< const Number > &self, const RCP< const Number > &other)
Raise self to power other
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
RCP< const Basic > coth(const RCP< const Basic > &arg)
Canonicalize Coth:
bool get_pi_shift(const RCP< const Basic > &arg, const Ptr< RCP< const Number >> &n, const Ptr< RCP< const Basic >> &x)
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:
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 > abs(const RCP< const Basic > &arg)
Canonicalize Abs:
RCP< const Basic > acsc(const RCP< const Basic > &arg)
Canonicalize ACsc:
RCP< const Integer > quotient_f(const Integer &n, const Integer &d)
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 > gamma(const RCP< const Basic > &arg)
Canonicalize Gamma:
RCP< const Basic > sub(const RCP< const Basic > &a, const RCP< const Basic > &b)
Substracts b from a.
RCP< const Basic > exp(const RCP< const Basic > &x)
Returns the natural exponential function E**x = pow(E, x)
RCP< const Integer > mod_f(const Integer &n, const Integer &d)
modulo round toward -inf
RCP< const Integer > quotient(const Integer &n, const Integer &d)
RCP< const Basic > asin(const RCP< const Basic > &arg)
Canonicalize ASin:
RCP< const Basic > acoth(const RCP< const Basic > &arg)
Canonicalize ACoth:
RCP< const Basic > tan(const RCP< const Basic > &arg)
Canonicalize Tan:
RCP< const Basic > cosh(const RCP< const Basic > &arg)
Canonicalize Cosh:
RCP< const Basic > asec(const RCP< const Basic > &arg)
Canonicalize ASec:
RCP< const Basic > acsch(const RCP< const Basic > &arg)
Canonicalize ACsch:
bool could_extract_minus(const Basic &arg)
RCP< const Basic > atan(const RCP< const Basic > &arg)
Canonicalize ATan:
RCP< const Basic > asinh(const RCP< const Basic > &arg)
Canonicalize ASinh:
RCP< const Basic > tanh(const RCP< const Basic > &arg)
Canonicalize Tanh:
RCP< const Basic > cot(const RCP< const Basic > &arg)
Canonicalize Cot:
RCP< const Basic > mul(const RCP< const Basic > &a, const RCP< const Basic > &b)
Multiplication.
void insert(T1 &m, const T2 &first, const T3 &second)
RCP< const Basic > atanh(const RCP< const Basic > &arg)
Canonicalize ATanh:
RCP< const Basic > floor(const RCP< const Basic > &arg)
Canonicalize Floor:
RCP< const Basic > erfc(const RCP< const Basic > &arg)
Canonicalize Erfc:
RCP< const Basic > levi_civita(const vec_basic &arg)
Canonicalize LeviCivita:
RCP< const Basic > acosh(const RCP< const Basic > &arg)
Canonicalize ACosh:
RCP< const Basic > lowergamma(const RCP< const Basic > &s, const RCP< const Basic > &x)
Canonicalize LowerGamma:
RCP< const Basic > truncate(const RCP< const Basic > &arg)
Canonicalize Truncate:
RCP< const Basic > loggamma(const RCP< const Basic > &arg)
Canonicalize LogGamma:
RCP< const Basic > cos(const RCP< const Basic > &arg)
Canonicalize Cos:
RCP< const Basic > log(const RCP< const Basic > &arg)
Returns the Natural Logarithm from argument arg
RCP< const Basic > csc(const RCP< const Basic > &arg)
Canonicalize Csc:
RCP< const Basic > dirichlet_eta(const RCP< const Basic > &s)
Create a new Dirichlet_eta instance:
RCP< const Integer > factorial(unsigned long n)
Factorial.
RCP< const Basic > add(const RCP< const Basic > &a, const RCP< const Basic > &b)
Adds two objects (safely).
RCP< const Basic > csch(const RCP< const Basic > &arg)
Canonicalize Csch:
int unified_compare(const T &a, const T &b)
bool neq(const Basic &a, const Basic &b)
Checks inequality for a and b
RCP< const Basic > expand(const RCP< const Basic > &self, bool deep=true)
Expands self
RCP< const Basic > min(const vec_basic &arg)
Canonicalize Min:
bool is_a_Complex(const Basic &b)
RCP< const Basic > erf(const RCP< const Basic > &arg)
Canonicalize Erf:
RCP< const Number > bernoulli(unsigned long n)
RCP< const Basic > trig_to_sqrt(const RCP< const Basic > &arg)
RCP< const Basic > asech(const RCP< const Basic > &arg)
Canonicalize ASech:
RCP< const Basic > lambertw(const RCP< const Basic > &arg)
Create a new LambertW instance:
RCP< const Number > harmonic(unsigned long n, long m)
Computes the sum of the inverses of the first perfect mth powers.
RCP< const Basic > sinh(const RCP< const Basic > &arg)
Canonicalize Sinh:
RCP< const Basic > kronecker_delta(const RCP< const Basic > &i, const RCP< const Basic > &j)
Canonicalize KroneckerDelta:
RCP< const Basic > neg(const RCP< const Basic > &a)
Negation.
RCP< const Basic > acot(const RCP< const Basic > &arg)
Canonicalize ACot:
RCP< const Basic > conjugate(const RCP< const Basic > &arg)
Canonicalize Conjugate.
RCP< const Basic > sin(const RCP< const Basic > &arg)
Canonicalize Sin:
RCP< const Basic > uppergamma(const RCP< const Basic > &s, const RCP< const Basic > &x)
Canonicalize UpperGamma: