add.cpp
Go to the documentation of this file.
1 
14 #include <symengine/add.h>
15 #include <symengine/pow.h>
16 #include <symengine/complex.h>
17 
18 namespace SymEngine
19 {
20 
64 Add::Add(const RCP<const Number> &coef, umap_basic_num &&dict)
65  : coef_{coef}, dict_{std::move(dict)} {
66  SYMENGINE_ASSIGN_TYPEID()
67  SYMENGINE_ASSERT(is_canonical(coef, dict_))}
68 
72  hash_t Add::__hash__() const
73 {
74  hash_t seed = SYMENGINE_ADD, temp;
75  hash_combine<Basic>(seed, *coef_);
76  for (const auto &p : dict_) {
77  temp = p.first->hash();
78  hash_combine<Basic>(temp, *(p.second));
79  seed ^= temp;
80  }
81  return seed;
82 }
83 
88 bool Add::__eq__(const Basic &o) const
89 {
90  if (is_a<Add>(o) and eq(*coef_, *(down_cast<const Add &>(o).coef_))
91  and unified_eq(dict_, down_cast<const Add &>(o).dict_))
92  return true;
93 
94  return false;
95 }
96 
107 int Add::compare(const Basic &o) const
108 {
109  SYMENGINE_ASSERT(is_a<Add>(o))
110  const Add &s = down_cast<const Add &>(o);
111  // # of elements
112  if (dict_.size() != s.dict_.size())
113  return (dict_.size() < s.dict_.size()) ? -1 : 1;
114 
115  // coef
116  int cmp = coef_->__cmp__(*s.coef_);
117  if (cmp != 0)
118  return cmp;
119 
120  // Compare dictionaries (slow):
122  map_basic_num adict(dict_.begin(), dict_.end());
123  map_basic_num bdict(s.dict_.begin(), s.dict_.end());
124  return unified_compare(adict, bdict);
125 }
126 
140 RCP<const Basic> Add::from_dict(const RCP<const Number> &coef,
141  umap_basic_num &&d)
142 {
143  if (d.size() == 0) {
144  return coef;
145  } else if (d.size() == 1 and coef->is_zero()) {
146  auto p = d.begin();
147  if (is_a<Integer>(*(p->second))) {
148  if (down_cast<const Integer &>(*(p->second)).is_zero()) {
149  return p->second; // Symbol
150  }
151  if (down_cast<const Integer &>(*(p->second)).is_one()) {
152  return p->first; // Integer
153  }
154  if (is_a<Mul>(*(p->first))) {
155 #if !defined(WITH_SYMENGINE_THREAD_SAFE) && defined(WITH_SYMENGINE_RCP)
156  if (down_cast<const Mul &>(*(p->first)).use_count() == 1) {
157  // We can steal the dictionary:
158  // Cast away const'ness, so that we can move 'dict_', since
159  // 'p->first' will be destroyed when 'd' is at the end of
160  // this function, so we "steal" its dict_ to avoid an
161  // unnecessary copy. We know the refcount_ is one, so
162  // nobody else is using the Mul except us.
163  const map_basic_basic &d2
164  = down_cast<const Mul &>(*(p->first)).get_dict();
165  map_basic_basic &d3 = const_cast<map_basic_basic &>(d2);
166  return Mul::from_dict(p->second, std::move(d3));
167  } else {
168 #else
169  {
170 #endif
171  // We need to copy the dictionary:
172  map_basic_basic d2
173  = down_cast<const Mul &>(*(p->first)).get_dict();
174  return Mul::from_dict(
175  p->second,
176  std::move(d2)); // Can return a Pow object here
177  }
178  }
179  map_basic_basic m;
180  if (is_a<Pow>(*(p->first))) {
181  insert(m, down_cast<const Pow &>(*(p->first)).get_base(),
182  down_cast<const Pow &>(*(p->first)).get_exp());
183  } else {
184  insert(m, p->first, one);
185  }
186  return make_rcp<const Mul>(p->second,
187  std::move(m)); // Returns a Mul from here
188  }
189  map_basic_basic m;
190  if (is_a_Number(*p->second)) {
191  if (is_a<Mul>(*(p->first))) {
192 #if !defined(WITH_SYMENGINE_THREAD_SAFE) && defined(WITH_SYMENGINE_RCP)
193  if (down_cast<const Mul &>(*(p->first)).use_count() == 1) {
194  // We can steal the dictionary:
195  // Cast away const'ness, so that we can move 'dict_', since
196  // 'p->first' will be destroyed when 'd' is at the end of
197  // this function, so we "steal" its dict_ to avoid an
198  // unnecessary copy. We know the refcount_ is one, so
199  // nobody else is using the Mul except us.
200  const map_basic_basic &d2
201  = down_cast<const Mul &>(*(p->first)).get_dict();
202  map_basic_basic &d3 = const_cast<map_basic_basic &>(d2);
203  return Mul::from_dict(p->second, std::move(d3));
204  } else {
205 #else
206  {
207 #endif
208  // We need to copy the dictionary:
209  map_basic_basic d2
210  = down_cast<const Mul &>(*(p->first)).get_dict();
211  return Mul::from_dict(p->second,
212  std::move(d2)); // May return a Pow
213  }
214  }
215  if (is_a<Pow>(*p->first)) {
216  insert(m, down_cast<const Pow &>(*(p->first)).get_base(),
217  down_cast<const Pow &>(*(p->first)).get_exp());
218  } else {
219  insert(m, p->first, one);
220  }
221  return make_rcp<const Mul>(p->second, std::move(m));
222  } else {
223  insert(m, p->first, one);
224  insert(m, p->second, one);
225  return make_rcp<const Mul>(one, std::move(m));
226  }
227  } else {
228  return make_rcp<const Add>(coef, std::move(d)); // returns an Add
229  }
230 }
231 
237 void Add::dict_add_term(umap_basic_num &d, const RCP<const Number> &coef,
238  const RCP<const Basic> &t)
239 {
240  auto it = d.find(t);
241  if (it == d.end()) {
242  // Not found, add it in if it is nonzero:
243  if (not(coef->is_zero()))
244  insert(d, t, coef);
245  } else {
246  iaddnum(outArg(it->second), coef);
247  if (it->second->is_zero())
248  d.erase(it);
249  }
250 }
251 
261 void Add::coef_dict_add_term(const Ptr<RCP<const Number>> &coef,
262  umap_basic_num &d, const RCP<const Number> &c,
263  const RCP<const Basic> &term)
264 {
265  if (is_a_Number(*term)) {
266  iaddnum(coef, mulnum(c, rcp_static_cast<const Number>(term)));
267  } else if (is_a<Add>(*term)) {
268  if (c->is_one()) {
269  for (const auto &q : (down_cast<const Add &>(*term)).dict_)
270  Add::dict_add_term(d, q.second, q.first);
271  iaddnum(coef, down_cast<const Add &>(*term).coef_);
272  } else {
273  Add::dict_add_term(d, c, term);
274  }
275  } else {
276  RCP<const Number> coef2;
277  RCP<const Basic> t;
278  Add::as_coef_term(term, outArg(coef2), outArg(t));
279  Add::dict_add_term(d, mulnum(c, coef2), t);
280  }
281 }
282 
287 void Add::as_two_terms(const Ptr<RCP<const Basic>> &a,
288  const Ptr<RCP<const Basic>> &b) const
289 {
290  auto p = dict_.begin();
291  *a = mul(p->first, p->second);
292  umap_basic_num d = dict_;
293  d.erase(p->first);
294  *b = Add::from_dict(coef_, std::move(d));
295 }
296 
306 void Add::as_coef_term(const RCP<const Basic> &self,
307  const Ptr<RCP<const Number>> &coef,
308  const Ptr<RCP<const Basic>> &term)
309 {
310  if (is_a<Mul>(*self)) {
311  if (neq(*(down_cast<const Mul &>(*self).get_coef()), *one)) {
312  *coef = (down_cast<const Mul &>(*self)).get_coef();
313  // We need to copy our 'dict_' here, as 'term' has to have its own.
314  map_basic_basic d2 = (down_cast<const Mul &>(*self)).get_dict();
315  *term = Mul::from_dict(one, std::move(d2));
316  } else {
317  *coef = one;
318  *term = self;
319  }
320  } else if (is_a_Number(*self)) {
321  *coef = rcp_static_cast<const Number>(self);
322  *term = one;
323  } else {
324  SYMENGINE_ASSERT(not is_a<Add>(*self));
325  *coef = one;
326  *term = self;
327  }
328 }
329 
348 bool Add::is_canonical(const RCP<const Number> &coef,
349  const umap_basic_num &dict) const
350 {
351  if (coef == null)
352  return false;
353  if (dict.size() == 0)
354  return false;
355  if (dict.size() == 1) {
356  // e.g. 0 + x, 0 + 2x
357  if (coef->is_zero())
358  return false;
359  }
360  // Check that each term in 'dict' is in canonical form
361  for (const auto &p : dict) {
362  if (p.first == null)
363  return false;
364  if (p.second == null)
365  return false;
366  // e.g. 2*3
367  if (is_a_Number(*p.first))
368  return false;
369  // e.g. 1*x (={1:x}), this should rather be just x (={x:1})
370  if (is_a<Integer>(*p.first)
371  and down_cast<const Integer &>(*p.first).is_one())
372  return false;
373  // e.g. x*0
374  if (is_a_Number(*p.second)
375  and down_cast<const Number &>(*p.second).is_zero())
376  return false;
377 
378  // e.g. {3x: 2}, this should rather be just {x: 6}
379  if (is_a<Mul>(*p.first)
380  and not(down_cast<const Mul &>(*p.first).get_coef()->is_one()))
381  return false;
382  }
383  return true;
384 }
385 
398 {
399  vec_basic args;
400  if (not coef_->is_zero()) {
401  args.reserve(dict_.size() + 1);
402  args.push_back(coef_);
403  } else {
404  args.reserve(dict_.size());
405  }
406  for (const auto &p : dict_) {
407  if (eq(*p.second, *one)) {
408  args.push_back(p.first);
409  } else {
410  args.push_back(Add::from_dict(zero, {{p.first, p.second}}));
411  }
412  }
413  return args;
414 }
415 
425 RCP<const Basic> add(const RCP<const Basic> &a, const RCP<const Basic> &b)
426 {
428  RCP<const Number> coef;
429  RCP<const Basic> t;
430  if (is_a<Add>(*a) and is_a<Add>(*b)) {
431  coef = (down_cast<const Add &>(*a)).get_coef();
432  d = (down_cast<const Add &>(*a)).get_dict();
433  for (const auto &p : (down_cast<const Add &>(*b)).get_dict())
434  Add::dict_add_term(d, p.second, p.first);
435  iaddnum(outArg(coef), down_cast<const Add &>(*b).get_coef());
436  } else if (is_a<Add>(*a)) {
437  coef = (down_cast<const Add &>(*a)).get_coef();
438  d = (down_cast<const Add &>(*a)).get_dict();
439  if (is_a_Number(*b)) {
440  if (not down_cast<const Number &>(*b).is_zero()) {
441  iaddnum(outArg(coef), rcp_static_cast<const Number>(b));
442  }
443  } else {
444  RCP<const Number> coef2;
445  Add::as_coef_term(b, outArg(coef2), outArg(t));
446  Add::dict_add_term(d, coef2, t);
447  }
448  } else if (is_a<Add>(*b)) {
449  coef = (down_cast<const Add &>(*b)).get_coef();
450  d = (down_cast<const Add &>(*b)).get_dict();
451  if (is_a_Number(*a)) {
452  if (not down_cast<const Number &>(*a).is_zero()) {
453  iaddnum(outArg(coef), rcp_static_cast<const Number>(a));
454  }
455  } else {
456  RCP<const Number> coef2;
457  Add::as_coef_term(a, outArg(coef2), outArg(t));
458  Add::dict_add_term(d, coef2, t);
459  }
460  } else {
461  Add::as_coef_term(a, outArg(coef), outArg(t));
462  Add::dict_add_term(d, coef, t);
463  Add::as_coef_term(b, outArg(coef), outArg(t));
464  Add::dict_add_term(d, coef, t);
465  auto it = d.find(one);
466  if (it == d.end()) {
467  coef = zero;
468  } else {
469  coef = it->second;
470  d.erase(it);
471  }
472  return Add::from_dict(coef, std::move(d));
473  }
474  return Add::from_dict(coef, std::move(d));
475 }
476 
481 RCP<const Basic> add(const vec_basic &a)
482 {
484  RCP<const Number> coef = zero;
485  for (const auto &i : a) {
486  Add::coef_dict_add_term(outArg(coef), d, one, i);
487  }
488  return Add::from_dict(coef, std::move(d));
489 }
490 
495 RCP<const Basic> sub(const RCP<const Basic> &a, const RCP<const Basic> &b)
496 {
497  return add(a, mul(minus_one, b));
498 }
499 
500 } // namespace SymEngine
Classes and functions relating to the binary operation of addition.
T begin(T... args)
The base class for representing addition in symbolic expressions.
Definition: add.h:27
virtual hash_t __hash__() const
Generates the hash representation.
Definition: add.cpp:72
umap_basic_num dict_
Definition: add.h:31
static RCP< const Basic > from_dict(const RCP< const Number > &coef, umap_basic_num &&d)
Create an appropriate instance from dictionary quickly.
Definition: add.cpp:140
RCP< const Number > coef_
Definition: add.h:29
RCP< const Basic > sub(const RCP< const Basic > &a, const RCP< const Basic > &b)
Substracts b from a.
Definition: add.cpp:495
virtual int compare(const Basic &o) const
Compares Add objects.
Definition: add.cpp:107
static void coef_dict_add_term(const Ptr< RCP< const Number >> &coef, umap_basic_num &d, const RCP< const Number > &c, const RCP< const Basic > &term)
Updates the numerical coefficient and the dictionary.
Definition: add.cpp:261
void as_two_terms(const Ptr< RCP< const Basic >> &a, const Ptr< RCP< const Basic >> &b) const
Converts the Add into a sum of two Basic objects.
Definition: add.cpp:287
bool is_canonical(const RCP< const Number > &coef, const umap_basic_num &dict) const
Checks if a given dictionary and coeffient is in cannonical form.
Definition: add.cpp:348
virtual bool __eq__(const Basic &o) const
Test equality.
Definition: add.cpp:88
RCP< const Basic > add(const RCP< const Basic > &a, const RCP< const Basic > &b)
Adds two objects (safely).
Definition: add.cpp:425
const RCP< const Number > & get_coef() const
Definition: add.h:142
static void dict_add_term(umap_basic_num &d, const RCP< const Number > &coef, const RCP< const Basic > &t)
Adds a new term to the expression.
Definition: add.cpp:237
Add(const RCP< const Number > &coef, umap_basic_num &&dict)
Default constructor.
Definition: add.cpp:64
virtual vec_basic get_args() const
Returns the arguments of the Add.
Definition: add.cpp:397
static void as_coef_term(const RCP< const Basic > &self, const Ptr< RCP< const Number >> &coef, const Ptr< RCP< const Basic >> &term)
Converts a Basic self into the form of coefficient * term.
Definition: add.cpp:306
The lowest unit of symbolic representation.
Definition: basic.h:95
static RCP< const Basic > from_dict(const RCP< const Number > &coef, map_basic_basic &&d)
Create a Mul from a dict.
Definition: mul.cpp:116
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 Number > mulnum(const RCP< const Number > &self, const RCP< const Number > &other)
Multiply self and other
Definition: number.h:93
bool eq(const Basic &a, const Basic &b)
Checks equality for a and b
Definition: basic-inl.h:21
RCP< const Basic > mul(const RCP< const Basic > &a, const RCP< const Basic > &b)
Multiplication.
Definition: mul.cpp:347
void insert(T1 &m, const T2 &first, const T3 &second)
Definition: dict.h:83
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
STL namespace.
T push_back(T... args)
T reserve(T... args)
T size(T... args)