msymenginepoly.h
1 #ifndef SYMENGINE_POLYNOMIALS_MULTIVARIATE
2 #define SYMENGINE_POLYNOMIALS_MULTIVARIATE
3 
4 #include <symengine/expression.h>
5 #include <symengine/monomials.h>
7 #include <symengine/polys/uexprpoly.h>
8 #include <symengine/symengine_casts.h>
9 
10 namespace SymEngine
11 {
12 
13 template <typename Vec, typename Value, typename Wrapper>
15 {
16 public:
17  using Dict = std::unordered_map<Vec, Value, vec_hash<Vec>>;
18  Dict dict_;
19  unsigned int vec_size;
20 
21  typedef Vec vec_type;
22  typedef Value coef_type;
23  typedef Dict dict_type;
24 
25  UDictWrapper(unsigned int s) SYMENGINE_NOEXCEPT
26  {
27  vec_size = s;
28  }
29 
30  UDictWrapper() SYMENGINE_NOEXCEPT {}
31 
32  ~UDictWrapper() SYMENGINE_NOEXCEPT {}
33 
34  UDictWrapper(Dict &&p, unsigned int sz)
35  {
36  auto iter = p.begin();
37  while (iter != p.end()) {
38  if (iter->second == 0) {
39  auto toErase = iter;
40  iter++;
41  p.erase(toErase);
42  } else {
43  iter++;
44  }
45  }
46 
47  dict_ = p;
48  vec_size = sz;
49  }
50 
51  UDictWrapper(const Dict &p, unsigned int sz)
52  {
53  for (auto &iter : p) {
54  if (iter.second != Value(0))
55  dict_[iter.first] = iter.second;
56  }
57  vec_size = sz;
58  }
59 
60  Wrapper &operator=(Wrapper &&other)
61  {
62  if (this != &other)
63  dict_ = std::move(other.dict_);
64  return static_cast<Wrapper &>(*this);
65  }
66 
67  friend Wrapper operator+(const Wrapper &a, const Wrapper &b)
68  {
69  SYMENGINE_ASSERT(a.vec_size == b.vec_size)
70  Wrapper c = a;
71  c += b;
72  return c;
73  }
74 
75  // both wrappers must have "aligned" vectors, ie same size
76  // and vector positions refer to the same generators
77  Wrapper &operator+=(const Wrapper &other)
78  {
79  SYMENGINE_ASSERT(vec_size == other.vec_size)
80 
81  for (auto &iter : other.dict_) {
82  auto t = dict_.find(iter.first);
83  if (t != dict_.end()) {
84  t->second += iter.second;
85  if (t->second == 0)
86  dict_.erase(t);
87  } else {
88  dict_.insert(t, {iter.first, iter.second});
89  }
90  }
91  return static_cast<Wrapper &>(*this);
92  }
93 
94  friend Wrapper operator-(const Wrapper &a, const Wrapper &b)
95  {
96  SYMENGINE_ASSERT(a.vec_size == b.vec_size)
97 
98  Wrapper c = a;
99  c -= b;
100  return c;
101  }
102 
103  Wrapper operator-() const
104  {
105  auto c = *this;
106  for (auto &iter : c.dict_)
107  iter.second *= -1;
108  return static_cast<Wrapper &>(c);
109  }
110 
111  // both wrappers must have "aligned" vectors, ie same size
112  // and vector positions refer to the same generators
113  Wrapper &operator-=(const Wrapper &other)
114  {
115  SYMENGINE_ASSERT(vec_size == other.vec_size)
116 
117  for (auto &iter : other.dict_) {
118  auto t = dict_.find(iter.first);
119  if (t != dict_.end()) {
120  t->second -= iter.second;
121  if (t->second == 0)
122  dict_.erase(t);
123  } else {
124  dict_.insert(t, {iter.first, -iter.second});
125  }
126  }
127  return static_cast<Wrapper &>(*this);
128  }
129 
130  static Wrapper mul(const Wrapper &a, const Wrapper &b)
131  {
132  SYMENGINE_ASSERT(a.vec_size == b.vec_size)
133 
134  Wrapper p(a.vec_size);
135  for (auto const &a_ : a.dict_) {
136  for (auto const &b_ : b.dict_) {
137 
138  Vec target(a.vec_size, 0);
139  for (unsigned int i = 0; i < a.vec_size; i++)
140  target[i] = a_.first[i] + b_.first[i];
141 
142  if (p.dict_.find(target) == p.dict_.end()) {
143  p.dict_.insert({target, a_.second * b_.second});
144  } else {
145  p.dict_.find(target)->second += a_.second * b_.second;
146  }
147  }
148  }
149 
150  for (auto it = p.dict_.begin(); it != p.dict_.end();) {
151  if (it->second == 0) {
152  p.dict_.erase(it++);
153  } else {
154  ++it;
155  }
156  }
157  return p;
158  }
159 
160  static Wrapper pow(const Wrapper &a, unsigned int p)
161  {
162  Wrapper tmp = a, res(a.vec_size);
163 
164  Vec zero_v(a.vec_size, 0);
165  res.dict_[zero_v] = 1_z;
166 
167  while (p != 1) {
168  if (p % 2 == 0) {
169  tmp = tmp * tmp;
170  } else {
171  res = res * tmp;
172  tmp = tmp * tmp;
173  }
174  p >>= 1;
175  }
176 
177  return (res * tmp);
178  }
179 
180  friend Wrapper operator*(const Wrapper &a, const Wrapper &b)
181  {
182  SYMENGINE_ASSERT(a.vec_size == b.vec_size)
183  return Wrapper::mul(a, b);
184  }
185 
186  Wrapper &operator*=(const Wrapper &other)
187  {
188  SYMENGINE_ASSERT(vec_size == other.vec_size)
189 
190  if (dict_.empty())
191  return static_cast<Wrapper &>(*this);
192 
193  if (other.dict_.empty()) {
194  dict_.clear();
195  return static_cast<Wrapper &>(*this);
196  }
197 
198  Vec zero_v(vec_size, 0);
199  // ! other is a just constant term
200  if (other.dict_.size() == 1
201  and other.dict_.find(zero_v) != other.dict_.end()) {
202  auto t = other.dict_.begin();
203  for (auto &i1 : dict_)
204  i1.second *= t->second;
205  return static_cast<Wrapper &>(*this);
206  }
207 
208  Wrapper res = Wrapper::mul(static_cast<Wrapper &>(*this), other);
209  res.dict_.swap(this->dict_);
210  return static_cast<Wrapper &>(*this);
211  }
212 
213  bool operator==(const Wrapper &other) const
214  {
215  return dict_ == other.dict_;
216  }
217 
218  bool operator!=(const Wrapper &other) const
219  {
220  return not(*this == other);
221  }
222 
223  const Dict &get_dict() const
224  {
225  return dict_;
226  }
227 
228  bool empty() const
229  {
230  return dict_.empty();
231  }
232 
233  Value get_coeff(Vec &x) const
234  {
235  auto ite = dict_.find(x);
236  if (ite != dict_.end())
237  return ite->second;
238  return Value(0);
239  }
240 
241  Wrapper translate(const vec_uint &translator, unsigned int size) const
242  {
243  SYMENGINE_ASSERT(translator.size() == vec_size)
244  SYMENGINE_ASSERT(size >= vec_size)
245 
246  Dict d;
247 
248  for (auto it : dict_) {
249  Vec changed;
250  changed.resize(size, 0);
251  for (unsigned int i = 0; i < vec_size; i++)
252  changed[translator[i]] = it.first[i];
253  d.insert({changed, it.second});
254  }
255 
256  return Wrapper(std::move(d), size);
257  }
258 };
259 
260 class SYMENGINE_EXPORT MIntDict
261  : public UDictWrapper<vec_uint, integer_class, MIntDict>
262 {
263 public:
264  MIntDict(unsigned int s) SYMENGINE_NOEXCEPT : UDictWrapper(s) {}
265 
266  MIntDict() SYMENGINE_NOEXCEPT {}
267 
268  ~MIntDict() SYMENGINE_NOEXCEPT {}
269 
270  MIntDict(MIntDict &&other) SYMENGINE_NOEXCEPT
271  : UDictWrapper(std::move(other))
272  {
273  }
274 
275  MIntDict(umap_uvec_mpz &&p, unsigned int sz)
276  : UDictWrapper(std::move(p), sz)
277  {
278  }
279 
280  MIntDict(const umap_uvec_mpz &p, unsigned int sz) : UDictWrapper(p, sz) {}
281 
282  MIntDict(const MIntDict &) = default;
283 
284  MIntDict &operator=(const MIntDict &) = default;
285 };
286 
287 class SYMENGINE_EXPORT MExprDict
288  : public UDictWrapper<vec_int, Expression, MExprDict>
289 {
290 public:
291  MExprDict(unsigned int s) SYMENGINE_NOEXCEPT : UDictWrapper(s) {}
292 
293  MExprDict() SYMENGINE_NOEXCEPT {}
294 
295  ~MExprDict() SYMENGINE_NOEXCEPT {}
296 
297  MExprDict(MExprDict &&other) SYMENGINE_NOEXCEPT
298  : UDictWrapper(std::move(other))
299  {
300  }
301 
302  MExprDict(umap_vec_expr &&p, unsigned int sz)
303  : UDictWrapper(std::move(p), sz)
304  {
305  }
306 
307  MExprDict(const umap_vec_expr &p, unsigned int sz) : UDictWrapper(p, sz) {}
308 
309  MExprDict(const MExprDict &) = default;
310 
311  MExprDict &operator=(const MExprDict &) = default;
312 };
313 
314 template <typename Container, typename Poly>
315 class MSymEnginePoly : public Basic
316 {
317 private:
318  Container poly_;
319  set_basic vars_;
320 
321 public:
322  typedef Container container_type;
323  typedef typename Container::coef_type coef_type;
324 
325  MSymEnginePoly(const set_basic &vars, Container &&dict)
326  : poly_{dict}, vars_{vars}
327  {
328  }
329 
330  static RCP<const Poly> from_container(const set_basic &vars, Container &&d)
331  {
332  return make_rcp<const Poly>(vars, std::move(d));
333  }
334 
335  int compare(const Basic &o) const override
336  {
337  SYMENGINE_ASSERT(is_a<Poly>(o))
338 
339  const Poly &s = down_cast<const Poly &>(o);
340 
341  if (vars_.size() != s.vars_.size())
342  return vars_.size() < s.vars_.size() ? -1 : 1;
343  if (poly_.dict_.size() != s.poly_.dict_.size())
344  return poly_.dict_.size() < s.poly_.dict_.size() ? -1 : 1;
345 
346  int cmp = unified_compare(vars_, s.vars_);
347  if (cmp != 0)
348  return cmp;
349 
350  return unified_compare(poly_.dict_, s.poly_.dict_);
351  }
352 
353  template <typename FromPoly>
354  static enable_if_t<is_a_UPoly<FromPoly>::value, RCP<const Poly>>
355  from_poly(const FromPoly &p)
356  {
357  Container c;
358  for (auto it = p.begin(); it != p.end(); ++it)
359  c.dict_[{it->first}] = it->second;
360  c.vec_size = 1;
361 
362  return Poly::from_container({p.get_var()}, std::move(c));
363  }
364 
365  static RCP<const Poly> from_dict(const vec_basic &v,
366  typename Container::dict_type &&d)
367  {
368  set_basic s;
369  std::map<RCP<const Basic>, unsigned int, RCPBasicKeyLess> m;
370  // Symbols in the vector are sorted by placeing them in an map image
371  // of the symbols in the map is their original location in the vector
372 
373  for (unsigned int i = 0; i < v.size(); i++) {
374  m.insert({v[i], i});
375  s.insert(v[i]);
376  }
377 
378  // vec_uint translator represents the permutation of the exponents
379  vec_uint trans(s.size());
380  auto mptr = m.begin();
381  for (unsigned int i = 0; i < s.size(); i++) {
382  trans[mptr->second] = i;
383  mptr++;
384  }
385 
386  Container x(std::move(d), numeric_cast<unsigned>(s.size()));
387  return Poly::from_container(
388  s, std::move(x.translate(trans, numeric_cast<unsigned>(s.size()))));
389  }
390 
391  static Container container_from_dict(const set_basic &s,
392  typename Container::dict_type &&d)
393  {
394  return Container(std::move(d), numeric_cast<unsigned>(s.size()));
395  }
396 
397  inline vec_basic get_args() const override
398  {
399  return {};
400  }
401 
402  inline const Container &get_poly() const
403  {
404  return poly_;
405  }
406 
407  inline const set_basic &get_vars() const
408  {
409  return vars_;
410  }
411 
412  bool __eq__(const Basic &o) const override
413  {
414  // TODO : fix for when vars are different, but there is an intersection
415  if (not is_a<Poly>(o))
416  return false;
417  const Poly &o_ = down_cast<const Poly &>(o);
418  // compare constants without regards to vars
419  if (1 == poly_.dict_.size() && 1 == o_.poly_.dict_.size()) {
420  if (poly_.dict_.begin()->second != o_.poly_.dict_.begin()->second)
421  return false;
422  if (poly_.dict_.begin()->first == o_.poly_.dict_.begin()->first
423  && unified_eq(vars_, o_.vars_))
424  return true;
425  typename Container::vec_type v1, v2;
426  v1.resize(vars_.size(), 0);
427  v2.resize(o_.vars_.size(), 0);
428  if (poly_.dict_.begin()->first == v1
429  || o_.poly_.dict_.begin()->first == v2)
430  return true;
431  return false;
432  } else if (0 == poly_.dict_.size() && 0 == o_.poly_.dict_.size()) {
433  return true;
434  } else {
435  return (unified_eq(vars_, o_.vars_)
436  && unified_eq(poly_.dict_, o_.poly_.dict_));
437  }
438  }
439 };
440 
441 class SYMENGINE_EXPORT MIntPoly : public MSymEnginePoly<MIntDict, MIntPoly>
442 {
443 public:
444  MIntPoly(const set_basic &vars, MIntDict &&dict)
445  : MSymEnginePoly(vars, std::move(dict)){SYMENGINE_ASSIGN_TYPEID()}
446 
447  IMPLEMENT_TYPEID(SYMENGINE_MINTPOLY)
448 
449  hash_t __hash__() const override;
450  RCP<const Basic> as_symbolic() const;
451 
452  integer_class eval(
453  std::map<RCP<const Basic>, integer_class, RCPBasicKeyLess> &vals) const;
454 };
455 
456 class SYMENGINE_EXPORT MExprPoly : public MSymEnginePoly<MExprDict, MExprPoly>
457 {
458 public:
459  MExprPoly(const set_basic &vars, MExprDict &&dict)
460  : MSymEnginePoly(vars, std::move(dict)){SYMENGINE_ASSIGN_TYPEID()}
461 
462  IMPLEMENT_TYPEID(SYMENGINE_MEXPRPOLY)
463 
464  hash_t __hash__() const override;
465  RCP<const Basic> as_symbolic() const;
466  Expression
467  eval(std::map<RCP<const Basic>, Expression, RCPBasicKeyLess> &vals) const;
468 };
469 
470 // reconciles the positioning of the exponents in the vectors in the
471 // Dict dict_ of the arguments with the positioning of the exponents in
472 // the correspondng vectors of the output of the function. f1 and f2 are
473 // vectors whose indices are the positions in the arguments and whose values
474 // are the positions in the output. set_basic s is the set of symbols of
475 // the output, and s1 and s2 are the sets of the symbols of the inputs.
476 SYMENGINE_EXPORT
477 unsigned int reconcile(vec_uint &v1, vec_uint &v2, set_basic &s,
478  const set_basic &s1, const set_basic &s2);
479 
480 template <typename Poly, typename Container>
481 set_basic get_translated_container(Container &x, Container &y, const Poly &a,
482  const Poly &b)
483 {
484  vec_uint v1, v2;
485  set_basic s;
486 
487  unsigned int sz = reconcile(v1, v2, s, a.get_vars(), b.get_vars());
488  x = a.get_poly().translate(v1, sz);
489  y = b.get_poly().translate(v2, sz);
490 
491  return s;
492 }
493 
494 template <typename Poly>
495 RCP<const Poly> add_mpoly(const Poly &a, const Poly &b)
496 {
497  typename Poly::container_type x, y;
498  set_basic s = get_translated_container(x, y, a, b);
499  x += y;
500  return Poly::from_container(s, std::move(x));
501 }
502 
503 template <typename Poly>
504 RCP<const Poly> sub_mpoly(const Poly &a, const Poly &b)
505 {
506  typename Poly::container_type x, y;
507  set_basic s = get_translated_container(x, y, a, b);
508  x -= y;
509  return Poly::from_container(s, std::move(x));
510 }
511 
512 template <typename Poly>
513 RCP<const Poly> mul_mpoly(const Poly &a, const Poly &b)
514 {
515  typename Poly::container_type x, y;
516  set_basic s = get_translated_container(x, y, a, b);
517  x *= y;
518  return Poly::from_container(s, std::move(x));
519 }
520 
521 template <typename Poly>
522 RCP<const Poly> neg_mpoly(const Poly &a)
523 {
524  auto x = a.get_poly();
525  return Poly::from_container(a.get_vars(), std::move(-x));
526 }
527 
528 template <typename Poly>
529 RCP<const Poly> pow_mpoly(const Poly &a, unsigned int n)
530 {
531  auto x = a.get_poly();
532  return Poly::from_container(a.get_vars(), Poly::container_type::pow(x, n));
533 }
534 } // namespace SymEngine
535 
536 #endif
#define IMPLEMENT_TYPEID(SYMENGINE_ID)
Inline members and functions.
Definition: basic.h:344
The lowest unit of symbolic representation.
Definition: basic.h:97
vec_basic get_args() const override
Returns the list of arguments.
bool __eq__(const Basic &o) const override
Test equality.
int compare(const Basic &o) const override
Main namespace for SymEngine package.
Definition: add.cpp:19
int unified_compare(const T &a, const T &b)
Definition: dict.h:205
Our less operator (<):
Definition: basic.h:228