mul.cpp
1 #include <symengine/add.h>
2 #include <symengine/pow.h>
3 #include <symengine/complex.h>
4 #include <symengine/symengine_exception.h>
5 #include <symengine/test_visitors.h>
6 
7 namespace SymEngine
8 {
9 
10 Mul::Mul(const RCP<const Number> &coef, map_basic_basic &&dict)
11  : coef_{coef}, dict_{std::move(dict)}
12 {
13  SYMENGINE_ASSIGN_TYPEID()
14  SYMENGINE_ASSERT(is_canonical(coef, dict_))
15 }
16 
17 bool Mul::is_canonical(const RCP<const Number> &coef,
18  const map_basic_basic &dict) const
19 {
20  if (coef == null)
21  return false;
22  // e.g. 0*x*y
23  if (coef->is_zero())
24  return false;
25  if (dict.size() == 0)
26  return false;
27  if (dict.size() == 1) {
28  // e.g. 1*x, 1*x**2
29  if (coef->is_one())
30  return false;
31  }
32  // Check that each term in 'dict' is in canonical form
33  for (const auto &p : dict) {
34  if (p.first == null)
35  return false;
36  if (p.second == null)
37  return false;
38  // e.g. 2**3, (2/3)**4
39  // However for Complex no simplification is done
40  if ((is_a<Integer>(*p.first) or is_a<Rational>(*p.first))
41  and is_a<Integer>(*p.second))
42  return false;
43  // e.g. 0**x
44  if (is_a<Integer>(*p.first)
45  and down_cast<const Integer &>(*p.first).is_zero())
46  return false;
47  // e.g. 1**x
48  if (is_a<Integer>(*p.first)
49  and down_cast<const Integer &>(*p.first).is_one())
50  return false;
51  // e.g. x**0
52  if (is_a_Number(*p.second)
53  and down_cast<const Number &>(*p.second).is_zero())
54  return false;
55  // e.g. (x*y)**2 (={xy:2}), which should be represented as x**2*y**2
56  // (={x:2, y:2})
57  if (is_a<Mul>(*p.first)) {
58  if (is_a<Integer>(*p.second))
59  return false;
60  if (is_a_Number(*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))
63  return false;
64  }
65  // e.g. x**2**y (={x**2:y}), which should be represented as x**(2y)
66  // (={x:2y})
67  if (is_a<Pow>(*p.first) && is_a<Integer>(*p.second))
68  return false;
69  // e.g. 0.5^2.0 should be represented as 0.25
70  if (is_a_Number(*p.first) and is_a_Number(*p.second)
71  and (not down_cast<const Number &>(*p.first).is_exact()
72  or not down_cast<const Number &>(*p.second).is_exact()))
73  return false;
74  }
75  return true;
76 }
77 
78 hash_t Mul::__hash__() const
79 {
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));
85  }
86  return seed;
87 }
88 
89 bool Mul::__eq__(const Basic &o) const
90 {
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_))
93  return true;
94 
95  return false;
96 }
97 
98 int Mul::compare(const Basic &o) const
99 {
100  SYMENGINE_ASSERT(is_a<Mul>(o))
101  const Mul &s = down_cast<const Mul &>(o);
102  // # of elements
103  if (dict_.size() != s.dict_.size())
104  return (dict_.size() < s.dict_.size()) ? -1 : 1;
105 
106  // coef
107  int cmp = coef_->__cmp__(*s.coef_);
108  if (cmp != 0)
109  return cmp;
110 
111  // Compare dictionaries:
112  return unified_compare(dict_, s.dict_);
113 }
114 
115 RCP<const SymEngine::Basic> Mul::from_dict(const RCP<const Number> &coef,
116  map_basic_basic &&d)
117 {
118  if (coef->is_zero())
119  return coef;
120  if (d.size() == 0) {
121  return coef;
122  } else if (d.size() == 1) {
123  auto p = d.begin();
124  if (is_a<Integer>(*(p->second))) {
125  if (coef->is_one()) {
126  if ((down_cast<const Integer &>(*(p->second))).is_one()) {
127  // For x**1 we simply return "x":
128  return p->first;
129  }
130  } else {
131  // For coef*x or coef*x**3 we simply return Mul:
132  return make_rcp<const Mul>(coef, std::move(d));
133  }
134  }
135  if (coef->is_one()) {
136  // Create a Pow() here:
137  if (eq(*p->second, *one)) {
138  return p->first;
139  }
140  return make_rcp<const Pow>(p->first, p->second);
141  } else {
142  return make_rcp<const Mul>(coef, std::move(d));
143  }
144  } else {
145  return make_rcp<const Mul>(coef, std::move(d));
146  }
147 }
148 
149 // Mul (t**exp) to the dict "d"
150 void Mul::dict_add_term(map_basic_basic &d, const RCP<const Basic> &exp,
151  const RCP<const Basic> &t)
152 {
153  auto it = d.find(t);
154  if (it == d.end()) {
155  insert(d, t, exp);
156  } else {
157  // Very common case, needs to be fast:
158  if (is_a_Number(*it->second) and is_a_Number(*exp)) {
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()) {
162  d.erase(it);
163  } else {
164  it->second = tmp;
165  }
166  } else {
167  // General case:
168  it->second = add(it->second, exp);
169  if (is_number_and_zero(*it->second)) {
170  d.erase(it);
171  }
172  }
173  }
174 }
175 
176 // Mul (t**exp) to the dict "d"
177 void Mul::dict_add_term_new(const Ptr<RCP<const Number>> &coef,
178  map_basic_basic &d, const RCP<const Basic> &exp,
179  const RCP<const Basic> &t)
180 {
181  auto it = d.find(t);
182  if (it == d.end()) {
183  // Don't check for `exp = 0` here
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));
194  } else {
195  res = down_cast<const Rational &>(*t).powrat(
196  down_cast<const Rational &>(*exp));
197  }
198  if (is_a_Number(*res)) {
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);
205  }
206  } else {
207  insert(d, t, exp);
208  }
209  } else if (is_a_Number(*exp)
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)));
213  } else {
214  insert(d, t, exp);
215  }
216  } else if (is_a_Number(*t) and is_a_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)));
221  } else {
222  insert(d, t, exp);
223  }
224  } else {
225  // Very common case, needs to be fast:
226  if (is_a_Number(*exp) and is_a_Number(*it->second)) {
227  RCP<const Number> tmp = rcp_static_cast<const Number>(it->second);
228  iaddnum(outArg(tmp), rcp_static_cast<const Number>(exp));
229  it->second = tmp;
230  } else
231  it->second = add(it->second, exp);
232 
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)));
239  }
240  d.erase(it);
241  return;
242  } else if (down_cast<const Integer &>(*(it->second)).is_zero()) {
243  d.erase(it);
244  return;
245  }
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));
252  } else {
253  res = down_cast<const Rational &>(*t).powrat(
254  down_cast<const Rational &>(*it->second));
255  }
256  if (is_a_Number(*res)) {
257  d.erase(it);
258  imulnum(outArg(*coef), rcp_static_cast<const Number>(res));
259  return;
260  } else if (is_a<Mul>(*res)) {
261  d.erase(it);
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);
266  }
267  return;
268  }
269  }
270  }
271  if (is_a_Number(*it->second)) {
272  if (down_cast<const Number &>(*it->second).is_zero()) {
273  // In 1*x**0.0, result should be 1.0
274  imulnum(
275  outArg(*coef),
276  pownum(rcp_static_cast<const Number>(it->second), zero));
277  d.erase(it);
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);
284  d.erase(it);
285  m->power_num(outArg(*coef), d, exp_);
286  }
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()) {
290  // Evaluate E**0.2, but not E**2
291  RCP<const Basic> exp_ = p->get_eval().exp(*p);
292  if (is_a_Number(*exp_)) {
293  imulnum(outArg(*coef),
294  rcp_static_cast<const Number>(exp_));
295  d.erase(it);
296  }
297  }
298  } else if (is_a_Number(*t)
299  and (not down_cast<const Number &>(*it->second)
300  .is_exact()
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)));
304  }
305  }
306  }
307 }
308 
309 void Mul::as_two_terms(const Ptr<RCP<const Basic>> &a,
310  const Ptr<RCP<const Basic>> &b) const
311 {
312  // Example: if this=3*x**2*y**2*z**2, then a=x**2 and b=3*y**2*z**2
313  auto p = dict_.begin();
314  *a = pow(p->first, p->second);
316  d.erase(p->first);
317  *b = Mul::from_dict(coef_, std::move(d));
318 }
319 
320 void Mul::as_base_exp(const RCP<const Basic> &self,
321  const Ptr<RCP<const Basic>> &exp,
322  const Ptr<RCP<const Basic>> &base)
323 {
324  if (is_a_Number(*self)) {
325  // Always ensure it is of form |num| > |den|
326  // in case of Integers den = 1
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()))) {
332  *exp = minus_one;
333  *base = self_new->rdiv(*rcp_static_cast<const Number>(one));
334  } else {
335  *exp = one;
336  *base = self;
337  }
338  } else {
339  *exp = one;
340  *base = self;
341  }
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();
345  } else {
346  SYMENGINE_ASSERT(not is_a<Mul>(*self));
347  *exp = one;
348  *base = self;
349  }
350 }
351 
352 RCP<const Basic> mul(const RCP<const Basic> &a, const RCP<const Basic> &b)
353 {
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);
359  // This is important optimization, as coef=1 if Mul is inside an Add.
360  // To further speed this up, the upper level code could tell us that we
361  // are inside an Add, then we don't even have can simply skip the
362  // following two lines.
363  if (not(A->get_coef()->is_one()) or not(B->get_coef()->is_one()))
364  coef = mulnum(A->get_coef(), B->get_coef());
365  d = A->get_dict();
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;
370  RCP<const Basic> t;
371  coef = (down_cast<const Mul &>(*a)).get_coef();
372  d = (down_cast<const Mul &>(*a)).get_dict();
373  if (is_a_Number(*b)) {
374  imulnum(outArg(coef), rcp_static_cast<const Number>(b));
375  } else {
376  Mul::as_base_exp(b, outArg(exp), outArg(t));
377  Mul::dict_add_term_new(outArg(coef), d, exp, t);
378  }
379  } else if (is_a<Mul>(*b)) {
380  RCP<const Basic> exp;
381  RCP<const Basic> t;
382  coef = (down_cast<const Mul &>(*b)).get_coef();
383  d = (down_cast<const Mul &>(*b)).get_dict();
384  if (is_a_Number(*a)) {
385  imulnum(outArg(coef), rcp_static_cast<const Number>(a));
386  } else {
387  Mul::as_base_exp(a, outArg(exp), outArg(t));
388  Mul::dict_add_term_new(outArg(coef), d, exp, t);
389  }
390  } else {
391  RCP<const Basic> exp;
392  RCP<const Basic> t;
393  if (is_a_Number(*a)) {
394  imulnum(outArg(coef), rcp_static_cast<const Number>(a));
395  } else {
396  Mul::as_base_exp(a, outArg(exp), outArg(t));
397  Mul::dict_add_term_new(outArg(coef), d, exp, t);
398  }
399  if (is_a_Number(*b)) {
400  imulnum(outArg(coef), rcp_static_cast<const Number>(b));
401  } else {
402  Mul::as_base_exp(b, outArg(exp), outArg(t));
403  Mul::dict_add_term_new(outArg(coef), d, exp, t);
404  }
405  }
406  return Mul::from_dict(coef, std::move(d));
407 }
408 
409 RCP<const Basic> mul(const vec_basic &a)
410 {
412  RCP<const Number> coef = one;
413  for (const auto &i : a) {
414  if (is_a<Mul>(*i)) {
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);
419  } else if (is_a_Number(*i)) {
420  imulnum(outArg(coef), rcp_static_cast<const Number>(i));
421  } else {
422  RCP<const Basic> exp;
423  RCP<const Basic> t;
424  Mul::as_base_exp(i, outArg(exp), outArg(t));
425  Mul::dict_add_term_new(outArg(coef), d, exp, t);
426  }
427  }
428  return Mul::from_dict(coef, std::move(d));
429 }
430 
431 RCP<const Basic> div(const RCP<const Basic> &a, const RCP<const Basic> &b)
432 {
433  if (is_number_and_zero(*b)) {
434  if (is_number_and_zero(*a)) {
435  return Nan;
436  } else {
437  return ComplexInf;
438  }
439  }
440  return mul(a, pow(b, minus_one));
441 }
442 
443 RCP<const Basic> neg(const RCP<const Basic> &a)
444 {
445  return mul(minus_one, a);
446 }
447 
448 void Mul::power_num(const Ptr<RCP<const Number>> &coef, map_basic_basic &d,
449  const RCP<const Number> &exp) const
450 {
451  if (exp->is_zero()) {
452  // (x*y)**(0.0) should return 1.0
453  imulnum(coef, pownum(rcp_static_cast<const Number>(exp), zero));
454  return;
455  }
456  RCP<const Basic> new_coef;
457  RCP<const Basic> new_exp;
458  if (is_a<Integer>(*exp)) {
459  // For eg. (3*y*(x**(1/2))**2 should be expanded to 9*x*y**2
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));
466  } else {
467  // No need for additional dict checks here.
468  // The dict should be of standard form before this is
469  // called.
470  Mul::dict_add_term_new(coef, d, new_exp, p.first);
471  }
472  }
473  } else {
474  if (coef_->is_negative() and not coef_->is_minus_one()) {
475  // (-3*x*y)**(1/2) -> 3**(1/2)*(-x*y)**(1/2)
476  new_coef = pow(coef_->mul(*minus_one), exp);
477  map_basic_basic d1 = dict_;
478  Mul::dict_add_term_new(coef, d, exp,
479  Mul::from_dict(minus_one, std::move(d1)));
480  } else if (coef_->is_positive() and not coef_->is_one()) {
481  // (3*x*y)**(1/2) -> 3**(1/2)*(x*y)**(1/2)
482  new_coef = pow(coef_, exp);
483  map_basic_basic d1 = dict_;
484  Mul::dict_add_term_new(coef, d, exp,
485  Mul::from_dict(one, std::move(d1)));
486  } else {
487  // ((1+2*I)*x*y)**(1/2) is kept as it is
488  new_coef = one;
489  Mul::dict_add_term_new(coef, d, exp, this->rcp_from_this());
490  }
491  }
492  if (is_a_Number(*new_coef)) {
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);
499  }
500  } else {
501  RCP<const Basic> _exp, t;
502  Mul::as_base_exp(new_coef, outArg(_exp), outArg(t));
503  Mul::dict_add_term_new(coef, d, _exp, t);
504  }
505 }
506 
508 {
509  vec_basic args;
510  if (not coef_->is_one()) {
511  args.reserve(dict_.size() + 1);
512  args.push_back(coef_);
513  } else {
514  args.reserve(dict_.size());
515  }
516  for (const auto &p : dict_) {
517  if (eq(*p.second, *one)) {
518  args.push_back(p.first);
519  } else {
520  args.push_back(make_rcp<const Pow>(p.first, p.second));
521  }
522  }
523  return args;
524 }
525 
526 } // namespace SymEngine
Classes and functions relating to the binary operation of addition.
T begin(T... args)
The lowest unit of symbolic representation.
Definition: basic.h:97
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
Definition: mul.cpp:17
bool __eq__(const Basic &o) const override
Definition: mul.cpp:89
int compare(const Basic &o) const override
Definition: mul.cpp:98
Mul(const RCP< const Number > &coef, map_basic_basic &&dict)
Definition: mul.cpp:10
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.
Definition: mul.cpp:320
static void dict_add_term(map_basic_basic &d, const RCP< const Basic > &exp, const RCP< const Basic > &t)
Add terms to dict.
Definition: mul.cpp:150
void as_two_terms(const Ptr< RCP< const Basic >> &a, const Ptr< RCP< const Basic >> &b) const
Rewrite as 2 terms.
Definition: mul.cpp:309
static RCP< const Basic > from_dict(const RCP< const Number > &coef, map_basic_basic &&d)
Create a Mul from a dict.
Definition: mul.cpp:115
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
Definition: mul.cpp:448
vec_basic get_args() const override
Returns the list of arguments.
Definition: mul.cpp:507
map_basic_basic dict_
The coefficient (e.g. 2 in 2*x*y)
Definition: mul.h:78
hash_t __hash__() const override
Definition: mul.cpp:78
T end(T... args)
T erase(T... args)
T find(T... args)
T move(T... args)
Main namespace for SymEngine package.
Definition: add.cpp:19
bool is_a_Number(const Basic &b)
Definition: number.h:130
RCP< const Basic > div(const RCP< const Basic > &a, const RCP< const Basic > &b)
Division.
Definition: mul.cpp:431
bool is_number_and_zero(const Basic &b)
Definition: number.h:139
RCP< const Number > mulnum(const RCP< const Number > &self, const RCP< const Number > &other)
Multiply self and other
Definition: number.h:93
RCP< const Number > pownum(const RCP< const Number > &self, const RCP< const Number > &other)
Raise self to power other
Definition: number.h:105
bool eq(const Basic &a, const Basic &b)
Checks equality for a and b
Definition: basic-inl.h:21
RCP< const Basic > exp(const RCP< const Basic > &x)
Returns the natural exponential function E**x = pow(E, x)
Definition: pow.cpp:271
RCP< const Basic > mul(const RCP< const Basic > &a, const RCP< const Basic > &b)
Multiplication.
Definition: mul.cpp:352
void insert(T1 &m, const T2 &first, const T3 &second)
Definition: dict.h:83
RCP< const Basic > add(const RCP< const Basic > &a, const RCP< const Basic > &b)
Adds two objects (safely).
Definition: add.cpp:425
int unified_compare(const T &a, const T &b)
Definition: dict.h:205
bool neq(const Basic &a, const Basic &b)
Checks inequality for a and b
Definition: basic-inl.h:29
RCP< const Basic > neg(const RCP< const Basic > &a)
Negation.
Definition: mul.cpp:443
STL namespace.
T push_back(T... args)
T reserve(T... args)
T size(T... args)