4 #include <symengine/symengine_exception.h>
5 #include <symengine/test_visitors.h>
11 : coef_{coef}, dict_{
std::move(dict)}
13 SYMENGINE_ASSIGN_TYPEID()
27 if (dict.
size() == 1) {
33 for (
const auto &p : dict) {
40 if ((is_a<Integer>(*p.first) or is_a<Rational>(*p.first))
41 and is_a<Integer>(*p.second))
44 if (is_a<Integer>(*p.first)
45 and down_cast<const Integer &>(*p.first).is_zero())
48 if (is_a<Integer>(*p.first)
49 and down_cast<const Integer &>(*p.first).is_one())
53 and down_cast<const Number &>(*p.second).is_zero())
57 if (is_a<Mul>(*p.first)) {
58 if (is_a<Integer>(*p.second))
61 and
neq(*down_cast<const Mul &>(*p.first).coef_, *one)
62 and
neq(*down_cast<const Mul &>(*p.first).coef_, *minus_one))
67 if (is_a<Pow>(*p.first) && is_a<Integer>(*p.second))
71 and (not down_cast<const Number &>(*p.first).is_exact()
72 or not down_cast<const Number &>(*p.second).is_exact()))
80 hash_t seed = SYMENGINE_MUL;
81 hash_combine<Basic>(seed, *coef_);
82 for (
const auto &p :
dict_) {
83 hash_combine<Basic>(seed, *(p.first));
84 hash_combine<Basic>(seed, *(p.second));
91 if (is_a<Mul>(o) and
eq(*coef_, *(down_cast<const Mul &>(o).coef_))
92 and unified_eq(
dict_, down_cast<const Mul &>(o).
dict_))
100 SYMENGINE_ASSERT(is_a<Mul>(o))
101 const Mul &s = down_cast<const Mul &>(o);
107 int cmp = coef_->__cmp__(*s.coef_);
122 }
else if (d.size() == 1) {
124 if (is_a<Integer>(*(p->second))) {
125 if (coef->is_one()) {
126 if ((down_cast<const Integer &>(*(p->second))).is_one()) {
132 return make_rcp<const Mul>(coef,
std::move(d));
135 if (coef->is_one()) {
137 if (
eq(*p->second, *one)) {
140 return make_rcp<const Pow>(p->first, p->second);
142 return make_rcp<const Mul>(coef,
std::move(d));
145 return make_rcp<const Mul>(coef,
std::move(d));
151 const RCP<const Basic> &t)
159 RCP<const Number> tmp = rcp_static_cast<const Number>(it->second);
160 iaddnum(outArg(tmp), rcp_static_cast<const Number>(
exp));
161 if (tmp->is_zero()) {
168 it->second =
add(it->second,
exp);
177 void Mul::dict_add_term_new(
const Ptr<RCP<const Number>> &coef,
179 const RCP<const Basic> &t)
184 if (is_a<Integer>(*t) or is_a<Rational>(*t) or is_a<Complex>(*t)) {
185 if (is_a<Integer>(*
exp)) {
186 imulnum(outArg(*coef),
187 pownum(rcp_static_cast<const Number>(t),
188 rcp_static_cast<const Number>(
exp)));
189 }
else if (is_a<Rational>(*
exp) and not is_a<Complex>(*t)) {
190 RCP<const Basic> res;
191 if (is_a<Integer>(*t)) {
192 res = down_cast<const Rational &>(*exp).rpowrat(
193 down_cast<const Integer &>(*t));
195 res = down_cast<const Rational &>(*t).powrat(
196 down_cast<const Rational &>(*
exp));
199 imulnum(outArg(*coef), rcp_static_cast<const Number>(res));
200 }
else if (is_a<Mul>(*res)) {
201 RCP<const Mul> m = rcp_static_cast<const Mul>(res);
202 imulnum(outArg(*coef), m->coef_);
203 for (
auto &p : m->dict_) {
204 Mul::dict_add_term_new(coef, d, p.second, p.first);
210 and not down_cast<const Number &>(*exp).is_exact()) {
211 imulnum(outArg(*coef), down_cast<const Number &>(*t).pow(
212 down_cast<const Number &>(*
exp)));
217 and (not down_cast<const Number &>(*exp).is_exact()
218 or not down_cast<const Number &>(*t).is_exact())) {
219 imulnum(outArg(*coef), down_cast<const Number &>(*t).pow(
220 down_cast<const Number &>(*
exp)));
227 RCP<const Number> tmp = rcp_static_cast<const Number>(it->second);
228 iaddnum(outArg(tmp), rcp_static_cast<const Number>(
exp));
231 it->second =
add(it->second,
exp);
233 if (is_a<Integer>(*it->second)) {
234 if (is_a<Integer>(*t) or is_a<Rational>(*t) or is_a<Complex>(*t)) {
235 if (not down_cast<const Integer &>(*(it->second)).is_zero()) {
236 imulnum(outArg(*coef),
237 pownum(rcp_static_cast<const Number>(t),
238 rcp_static_cast<const Number>(it->second)));
242 }
else if (down_cast<const Integer &>(*(it->second)).is_zero()) {
246 }
else if (is_a<Rational>(*it->second)) {
247 if (is_a<Integer>(*t) or is_a<Rational>(*t)) {
248 RCP<const Basic> res;
249 if (is_a<Integer>(*t)) {
250 res = down_cast<const Rational &>(*it->second)
251 .rpowrat(down_cast<const Integer &>(*t));
253 res = down_cast<const Rational &>(*t).powrat(
254 down_cast<const Rational &>(*it->second));
258 imulnum(outArg(*coef), rcp_static_cast<const Number>(res));
260 }
else if (is_a<Mul>(*res)) {
262 RCP<const Mul> m = rcp_static_cast<const Mul>(res);
263 imulnum(outArg(*coef), m->coef_);
264 for (
auto &p : m->dict_) {
265 Mul::dict_add_term_new(coef, d, p.second, p.first);
272 if (down_cast<const Number &>(*it->second).is_zero()) {
276 pownum(rcp_static_cast<const Number>(it->second), zero));
278 }
else if (is_a<Mul>(*it->first)) {
279 RCP<const Mul> m = rcp_static_cast<const Mul>(it->first);
280 if (is_a<Integer>(*it->second)
281 or (
neq(*m->coef_, *one) and
neq(*m->coef_, *minus_one))) {
282 RCP<const Number> exp_
283 = rcp_static_cast<const Number>(it->second);
285 m->power_num(outArg(*coef), d, exp_);
287 }
else if (
eq(*it->first, *E)) {
288 RCP<const Number> p = rcp_static_cast<const Number>(it->second);
289 if (not p->is_exact()) {
291 RCP<const Basic> exp_ = p->get_eval().exp(*p);
293 imulnum(outArg(*coef),
294 rcp_static_cast<const Number>(exp_));
299 and (not down_cast<const Number &>(*it->second)
301 or not down_cast<const Number &>(*t).is_exact())) {
302 imulnum(outArg(*coef), down_cast<const Number &>(*t).pow(
303 down_cast<const Number &>(*
exp)));
310 const Ptr<RCP<const Basic>> &b)
const
314 *a = pow(p->first, p->second);
321 const Ptr<RCP<const Basic>> &
exp,
322 const Ptr<RCP<const Basic>> &base)
327 if (is_a<Rational>(*
self)) {
328 RCP<const Rational> self_new
329 = rcp_static_cast<const Rational>(
self);
330 if (mp_abs(get_num(self_new->as_rational_class()))
331 < mp_abs(get_den(self_new->as_rational_class()))) {
333 *base = self_new->rdiv(*rcp_static_cast<const Number>(one));
342 }
else if (is_a<Pow>(*
self)) {
343 *
exp = down_cast<const Pow &>(*self).get_exp();
344 *base = down_cast<const Pow &>(*self).get_base();
346 SYMENGINE_ASSERT(not is_a<Mul>(*
self));
352 RCP<const Basic>
mul(
const RCP<const Basic> &a,
const RCP<const Basic> &b)
355 RCP<const Number> coef = one;
356 if (is_a<Mul>(*a) and is_a<Mul>(*b)) {
357 RCP<const Mul> A = rcp_static_cast<const Mul>(a);
358 RCP<const Mul> B = rcp_static_cast<const Mul>(b);
363 if (not(A->get_coef()->is_one()) or not(B->get_coef()->is_one()))
364 coef =
mulnum(A->get_coef(), B->get_coef());
366 for (
const auto &p : B->get_dict())
367 Mul::dict_add_term_new(outArg(coef), d, p.second, p.first);
368 }
else if (is_a<Mul>(*a)) {
369 RCP<const Basic>
exp;
371 coef = (down_cast<const Mul &>(*a)).get_coef();
372 d = (down_cast<const Mul &>(*a)).get_dict();
374 imulnum(outArg(coef), rcp_static_cast<const Number>(b));
377 Mul::dict_add_term_new(outArg(coef), d,
exp, t);
379 }
else if (is_a<Mul>(*b)) {
380 RCP<const Basic>
exp;
382 coef = (down_cast<const Mul &>(*b)).get_coef();
383 d = (down_cast<const Mul &>(*b)).get_dict();
385 imulnum(outArg(coef), rcp_static_cast<const Number>(a));
388 Mul::dict_add_term_new(outArg(coef), d,
exp, t);
391 RCP<const Basic>
exp;
394 imulnum(outArg(coef), rcp_static_cast<const Number>(a));
397 Mul::dict_add_term_new(outArg(coef), d,
exp, t);
400 imulnum(outArg(coef), rcp_static_cast<const Number>(b));
403 Mul::dict_add_term_new(outArg(coef), d,
exp, t);
409 RCP<const Basic>
mul(
const vec_basic &a)
412 RCP<const Number> coef = one;
413 for (
const auto &i : a) {
415 RCP<const Mul> A = rcp_static_cast<const Mul>(i);
416 imulnum(outArg(coef), A->get_coef());
417 for (
const auto &p : A->get_dict())
418 Mul::dict_add_term_new(outArg(coef), d, p.second, p.first);
420 imulnum(outArg(coef), rcp_static_cast<const Number>(i));
422 RCP<const Basic>
exp;
425 Mul::dict_add_term_new(outArg(coef), d,
exp, t);
431 RCP<const Basic>
div(
const RCP<const Basic> &a,
const RCP<const Basic> &b)
440 return mul(a, pow(b, minus_one));
443 RCP<const Basic>
neg(
const RCP<const Basic> &a)
445 return mul(minus_one, a);
449 const RCP<const Number> &
exp)
const
451 if (
exp->is_zero()) {
453 imulnum(coef,
pownum(rcp_static_cast<const Number>(
exp), zero));
456 RCP<const Basic> new_coef;
457 RCP<const Basic> new_exp;
458 if (is_a<Integer>(*
exp)) {
460 new_coef = pow(coef_,
exp);
461 for (
const auto &p :
dict_) {
462 new_exp =
mul(p.second,
exp);
463 if (is_a<Integer>(*new_exp) and is_a<Mul>(*p.first)) {
464 down_cast<const Mul &>(*p.first).power_num(
465 coef, d, rcp_static_cast<const Number>(new_exp));
470 Mul::dict_add_term_new(coef, d, new_exp, p.first);
474 if (coef_->is_negative() and not coef_->is_minus_one()) {
476 new_coef = pow(coef_->mul(*minus_one),
exp);
478 Mul::dict_add_term_new(coef, d,
exp,
480 }
else if (coef_->is_positive() and not coef_->is_one()) {
482 new_coef = pow(coef_,
exp);
484 Mul::dict_add_term_new(coef, d,
exp,
493 imulnum(coef, rcp_static_cast<const Number>(new_coef));
494 }
else if (is_a<Mul>(*new_coef)) {
495 RCP<const Mul> tmp = rcp_static_cast<const Mul>(new_coef);
496 imulnum(coef, tmp->coef_);
497 for (
const auto &q : tmp->dict_) {
498 Mul::dict_add_term_new(coef, d, q.second, q.first);
501 RCP<const Basic> _exp, t;
503 Mul::dict_add_term_new(coef, d, _exp, t);
510 if (not coef_->is_one()) {
516 for (
const auto &p :
dict_) {
517 if (
eq(*p.second, *one)) {
520 args.
push_back(make_rcp<const Pow>(p.first, p.second));
Classes and functions relating to the binary operation of addition.
The lowest unit of symbolic representation.
RCP< Basic > rcp_from_this()
Get RCP<T> pointer to self (it will cast the pointer to T)
bool is_canonical(const RCP< const Number > &coef, const map_basic_basic &dict) const
bool __eq__(const Basic &o) const override
int compare(const Basic &o) const override
Mul(const RCP< const Number > &coef, map_basic_basic &&dict)
static void as_base_exp(const RCP< const Basic > &self, const Ptr< RCP< const Basic >> &exp, const Ptr< RCP< const Basic >> &base)
Convert to a base and exponent form.
static void dict_add_term(map_basic_basic &d, const RCP< const Basic > &exp, const RCP< const Basic > &t)
Add terms to dict.
void as_two_terms(const Ptr< RCP< const Basic >> &a, const Ptr< RCP< const Basic >> &b) const
Rewrite as 2 terms.
static RCP< const Basic > from_dict(const RCP< const Number > &coef, map_basic_basic &&d)
Create a Mul from a dict.
void power_num(const Ptr< RCP< const Number >> &coef, map_basic_basic &d, const RCP< const Number > &exp) const
Power all terms with the exponent exp
vec_basic get_args() const override
Returns the list of arguments.
map_basic_basic dict_
The coefficient (e.g. 2 in 2*x*y)
hash_t __hash__() const override
Main namespace for SymEngine package.
bool is_a_Number(const Basic &b)
RCP< const Basic > div(const RCP< const Basic > &a, const RCP< const Basic > &b)
Division.
bool is_number_and_zero(const Basic &b)
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
bool eq(const Basic &a, const Basic &b)
Checks equality for a and b
RCP< const Basic > exp(const RCP< const Basic > &x)
Returns the natural exponential function E**x = pow(E, x)
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 > add(const RCP< const Basic > &a, const RCP< const Basic > &b)
Adds two objects (safely).
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 > neg(const RCP< const Basic > &a)
Negation.