Loading...
Searching...
No Matches
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
18namespace SymEngine
19{
20
64Add::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
88bool 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
107int 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
140RCP<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:
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 }
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 }
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:
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
237void 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
261void 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
287void 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);
293 d.erase(p->first);
295}
296
306void 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
348bool 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
425RCP<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
481RCP<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
495RCP<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
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
bool __eq__(const Basic &o) const override
Test equality.
Definition: add.cpp:88
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
vec_basic get_args() const override
Returns the arguments of the Add.
Definition: add.cpp:397
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
int compare(const Basic &o) const override
Compares Add objects.
Definition: add.cpp:107
const RCP< const Number > & get_coef() const
Definition: add.h:142
RCP< const Basic > add(const RCP< const Basic > &a, const RCP< const Basic > &b)
Adds two objects (safely).
Definition: add.cpp:425
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
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
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
hash_t __hash__() const override
Generates the hash representation.
Definition: add.cpp:72
The lowest unit of symbolic representation.
Definition: basic.h:97
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
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
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:352
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
RCP< const Number > mulnum(const RCP< const Number > &self, const RCP< const Number > &other)
Multiply self and other
Definition: number.h:93
STL namespace.
T push_back(T... args)
T reserve(T... args)
T size(T... args)