upolybase.h
1 
5 #ifndef SYMENGINE_UINT_BASE_H
6 #define SYMENGINE_UINT_BASE_H
7 
8 #include <symengine/basic.h>
9 #include <symengine/pow.h>
10 #include <symengine/add.h>
11 #include <symengine/rational.h>
12 #include <symengine/expression.h>
13 #include <memory>
14 #include <type_traits>
15 #include <utility>
16 
17 #ifdef HAVE_SYMENGINE_FLINT
18 #include <symengine/flint_wrapper.h>
19 using fz_t = SymEngine::fmpz_wrapper;
20 using fq_t = SymEngine::fmpq_wrapper;
21 #endif
22 #ifdef HAVE_SYMENGINE_PIRANHA
23 #include <piranha/mp_integer.hpp>
24 #include <piranha/mp_rational.hpp>
25 #endif
26 
27 namespace SymEngine
28 {
29 // misc methods
30 
31 #if SYMENGINE_INTEGER_CLASS == SYMENGINE_GMPXX \
32  || SYMENGINE_INTEGER_CLASS == SYMENGINE_GMP
33 #ifdef HAVE_SYMENGINE_FLINT
34 inline integer_class to_mp_class(const fz_t &i)
35 {
36  integer_class x;
37  fmpz_get_mpz(x.get_mpz_t(), i.get_fmpz_t());
38  return x;
39 }
40 inline rational_class to_mp_class(const fq_t &i)
41 {
42  rational_class x;
43  fmpq_get_mpq(x.get_mpq_t(), i.get_fmpq_t());
44  return x;
45 }
46 #endif
47 
48 #ifdef HAVE_SYMENGINE_PIRANHA
49 inline integer_class to_mp_class(const piranha::integer &i)
50 {
51  integer_class x;
52  mpz_set(x.get_mpz_t(), i.get_mpz_view());
53  return x;
54 }
55 inline rational_class to_mp_class(const piranha::rational &i)
56 {
57  rational_class x;
58  mpq_set(x.get_mpq_t(), i.get_mpq_view());
59  return x;
60 }
61 #endif
62 
63 #elif SYMENGINE_INTEGER_CLASS == SYMENGINE_PIRANHA
64 #ifdef HAVE_SYMENGINE_FLINT
65 inline integer_class to_mp_class(const fz_t &i)
66 {
67  integer_class x;
68  fmpz_get_mpz(get_mpz_t(x), i.get_fmpz_t());
69  return x;
70 }
71 inline rational_class to_mp_class(const fq_t &i)
72 {
73  rational_class s;
74  fmpz_get_mpz(get_mpz_t(s._num()), i.get_num().get_fmpz_t());
75  fmpz_get_mpz(get_mpz_t(s._den()), i.get_den().get_fmpz_t());
76  return s;
77 }
78 #endif
79 
80 #elif SYMENGINE_INTEGER_CLASS == SYMENGINE_FLINT
81 #ifdef HAVE_SYMENGINE_PIRANHA
82 inline integer_class to_mp_class(const piranha::integer &x)
83 {
84  return integer_class(x.get_mpz_view());
85 }
86 inline rational_class to_mp_class(const piranha::rational &x)
87 {
88  return rational_class(x.get_mpq_view());
89 }
90 #endif
91 
92 #endif
93 
94 inline integer_class to_mp_class(const integer_class &i)
95 {
96  return i;
97 }
98 
99 inline rational_class to_mp_class(const rational_class &i)
100 {
101  return i;
102 }
103 
104 // dict wrapper
105 template <typename Key, typename Value, typename Wrapper>
107 {
108 public:
109  std::map<Key, Value> dict_;
110  typedef Key key_type;
111 
112 public:
113  ODictWrapper() SYMENGINE_NOEXCEPT {}
114  ~ODictWrapper() SYMENGINE_NOEXCEPT {}
115 
116  ODictWrapper(const int &i)
117  {
118  if (i != 0)
119  dict_ = {{0, Value(i)}};
120  }
121 
122  ODictWrapper(const std::map<Key, Value> &p)
123  {
124  for (auto &iter : p) {
125  if (iter.second != Value(0))
126  dict_[iter.first] = iter.second;
127  }
128  }
129 
130  ODictWrapper(std::map<Key, Value> &&p)
131  {
132  for (auto it = p.begin(); it != p.end();) {
133  if (it->second == Value(0))
134  it = p.erase(it);
135  else
136  ++it;
137  }
138  dict_ = std::move(p);
139  }
140 
141  ODictWrapper(const Value &p)
142  {
143  if (p != Value(0))
144  dict_[0] = p;
145  }
146 
147  ODictWrapper(std::string s)
148  {
149  dict_[1] = Value(1);
150  }
151 
152  static Wrapper from_vec(const std::vector<Value> &v)
153  {
154  Wrapper x;
155  x.dict_ = {};
156  for (unsigned int i = 0; i < v.size(); i++) {
157  if (v[i] != Value(0)) {
158  x.dict_[i] = v[i];
159  }
160  }
161  return x;
162  }
163 
164  Wrapper &operator=(Wrapper &&other) SYMENGINE_NOEXCEPT
165  {
166  if (this != &other)
167  dict_ = std::move(other.dict_);
168  return static_cast<Wrapper &>(*this);
169  }
170 
171  friend Wrapper operator+(const Wrapper &a, const Wrapper &b)
172  {
173  Wrapper c = a;
174  c += b;
175  return c;
176  }
177 
178  Wrapper &operator+=(const Wrapper &other)
179  {
180  for (auto &iter : other.dict_) {
181  auto t = dict_.lower_bound(iter.first);
182  if (t != dict_.end() and t->first == iter.first) {
183  t->second += iter.second;
184  if (t->second == 0) {
185  dict_.erase(t);
186  }
187  } else {
188  dict_.insert(t, {iter.first, iter.second});
189  }
190  }
191  return static_cast<Wrapper &>(*this);
192  }
193 
194  friend Wrapper operator-(const Wrapper &a, const Wrapper &b)
195  {
196  Wrapper c = a;
197  c -= b;
198  return c;
199  }
200 
201  Wrapper operator-() const
202  {
203  ODictWrapper c = *this;
204  for (auto &iter : c.dict_)
205  iter.second *= -1;
206  return static_cast<Wrapper &>(c);
207  }
208 
209  Wrapper &operator-=(const Wrapper &other)
210  {
211  for (auto &iter : other.dict_) {
212  auto t = dict_.lower_bound(iter.first);
213  if (t != dict_.end() and t->first == iter.first) {
214  t->second -= iter.second;
215  if (t->second == 0) {
216  dict_.erase(t);
217  }
218  } else {
219  dict_.insert(t, {iter.first, -iter.second});
220  }
221  }
222  return static_cast<Wrapper &>(*this);
223  }
224 
225  static Wrapper mul(const Wrapper &a, const Wrapper &b)
226  {
227  if (a.get_dict().empty())
228  return a;
229  if (b.get_dict().empty())
230  return b;
231 
232  Wrapper p;
233  for (const auto &i1 : a.dict_)
234  for (const auto &i2 : b.dict_)
235  p.dict_[i1.first + i2.first] += i1.second * i2.second;
236 
237  for (auto it = p.dict_.cbegin(); it != p.dict_.cend();) {
238  if (it->second == 0) {
239  p.dict_.erase(it++);
240  } else {
241  ++it;
242  }
243  }
244  return p;
245  }
246 
247  static Wrapper pow(const Wrapper &a, unsigned int p)
248  {
249  Wrapper tmp = a, res(1);
250 
251  while (p != 1) {
252  if (p % 2 == 0) {
253  tmp = tmp * tmp;
254  } else {
255  res = res * tmp;
256  tmp = tmp * tmp;
257  }
258  p >>= 1;
259  }
260 
261  return (res * tmp);
262  }
263 
264  template <typename FromPoly>
265  static Wrapper from_poly(const FromPoly &p)
266  {
267  Wrapper t;
268  for (auto it = p.begin(); it != p.end(); ++it)
269  t.dict_[it->first] = it->second;
270  return t;
271  }
272 
273  friend Wrapper operator*(const Wrapper &a, const Wrapper &b)
274  {
275  return Wrapper::mul(a, b);
276  }
277 
278  Wrapper &operator*=(const Wrapper &other)
279  {
280  if (dict_.empty())
281  return static_cast<Wrapper &>(*this);
282 
283  if (other.dict_.empty()) {
284  dict_.clear();
285  return static_cast<Wrapper &>(*this);
286  }
287 
288  // ! other is a just constant term
289  if (other.dict_.size() == 1
290  and other.dict_.find(0) != other.dict_.end()) {
291  auto t = other.dict_.begin();
292  for (auto &i1 : dict_)
293  i1.second *= t->second;
294  return static_cast<Wrapper &>(*this);
295  }
296 
297  Wrapper res = Wrapper::mul(static_cast<Wrapper &>(*this), other);
298  res.dict_.swap(this->dict_);
299  return static_cast<Wrapper &>(*this);
300  }
301 
302  friend bool operator==(const Wrapper &a, const Wrapper &b)
303  {
304  return a.dict_ == b.dict_;
305  }
306 
307  bool operator!=(const Wrapper &other) const
308  {
309  return not(static_cast<const Wrapper &>(*this) == other);
310  }
311 
312  const std::map<Key, Value> &get_dict() const
313  {
314  return dict_;
315  }
316 
317  size_t size() const
318  {
319  return dict_.size();
320  }
321 
322  bool empty() const
323  {
324  return dict_.empty();
325  }
326 
327  Key degree() const
328  {
329  if (dict_.empty())
330  return Key(0);
331  return dict_.rbegin()->first;
332  }
333 
334  Value get_coeff(Key x) const
335  {
336  auto ite = dict_.find(x);
337  if (ite != dict_.end())
338  return ite->second;
339  return Value(0);
340  }
341 
342  Value get_lc() const
343  {
344  if (dict_.empty())
345  return Value(0);
346  return dict_.rbegin()->second;
347  }
348 };
349 
350 SYMENGINE_EXPORT
351 umap_basic_num _find_gens_poly(const RCP<const Basic> &x);
352 
353 template <typename Container, typename Poly>
354 class UPolyBase : public Basic
355 {
356 private:
357  RCP<const Basic> var_;
358  Container poly_;
359 
360 public:
361  UPolyBase(const RCP<const Basic> &var, Container &&container)
362  : var_{var}, poly_{container}
363  {
364  }
365 
366  typedef Container container_type;
367 
369  int compare(const Basic &o) const override = 0;
370  hash_t __hash__() const override = 0;
371 
372  // return `degree` + 1. `0` returned for zero poly.
373  virtual int size() const = 0;
374 
376  inline bool __eq__(const Basic &o) const override
377  {
378  if (is_a<Poly>(o))
379  return eq(*var_, *(down_cast<const Poly &>(o).var_))
380  and poly_ == down_cast<const Poly &>(o).poly_;
381  return false;
382  }
383 
384  inline const RCP<const Basic> &get_var() const
385  {
386  return var_;
387  }
388 
389  inline const Container &get_poly() const
390  {
391  return poly_;
392  }
393 
394  inline vec_basic get_args() const override
395  {
396  return {};
397  }
398 
399  static RCP<const Poly> from_container(const RCP<const Basic> &var,
400  Container &&d)
401  {
402  return make_rcp<const Poly>(var, std::move(d));
403  }
404 };
405 
406 template <typename Cont, typename Poly>
407 class UExprPolyBase : public UPolyBase<Cont, Poly>
408 {
409 public:
410  typedef Expression coef_type;
411 
412  UExprPolyBase(const RCP<const Basic> &var, Cont &&container)
413  : UPolyBase<Cont, Poly>(var, std::move(container))
414  {
415  }
416 
417  inline int get_degree() const
418  {
419  return this->get_poly().degree();
420  }
421 
422  static RCP<const Poly> from_dict(const RCP<const Basic> &var,
423  std::map<int, Expression> &&d)
424  {
425  return Poly::from_container(
426  var, Poly::container_from_dict(var, std::move(d)));
427  }
428 
429  RCP<const Basic> as_symbolic() const
430  {
431  auto it = (down_cast<const Poly &>(*this)).begin();
432  auto end = (down_cast<const Poly &>(*this)).end();
433 
434  vec_basic args;
435  for (; it != end; ++it) {
436  if (it->first == 0)
437  args.push_back(it->second.get_basic());
438  else if (it->first == 1) {
439  if (it->second == Expression(1))
440  args.push_back(this->get_var());
441  else
442  args.push_back(
443  mul(it->second.get_basic(), this->get_var()));
444  } else if (it->second == 1)
445  args.push_back(pow(this->get_var(), integer(it->first)));
446  else
447  args.push_back(mul(it->second.get_basic(),
448  pow(this->get_var(), integer(it->first))));
449  }
450  if (this->get_poly().empty())
451  args.push_back(zero);
452  return SymEngine::add(args);
453  }
454 };
455 // super class for all non-expr polys, all methods which are
456 // common for all non-expr polys go here eg. degree, eval etc.
457 template <typename Container, typename Poly, typename Cf>
458 class UNonExprPoly : public UPolyBase<Container, Poly>
459 {
460 public:
461  typedef Cf coef_type;
462 
463  UNonExprPoly(const RCP<const Basic> &var, Container &&container)
464  : UPolyBase<Container, Poly>(var, std::move(container))
465  {
466  }
467 
468  // return coefficient of degree 'i'
469  virtual Cf get_coeff(unsigned int i) const = 0;
470  // return value of poly when ealudated at `x`
471  virtual Cf eval(const Cf &x) const = 0;
472 
473  std::vector<Cf> multieval(const std::vector<Cf> &v) const
474  {
475  // this is not the optimal algorithm
476  std::vector<Cf> res(v.size());
477  for (unsigned int i = 0; i < v.size(); ++i)
478  res[i] = eval(v[i]);
479  return res;
480  }
481 
482  inline int get_degree() const
483  {
484  return numeric_cast<int>(this->get_poly().degree());
485  }
486 
487  Cf get_lc() const
488  {
489  return get_coeff(get_degree());
490  }
491 
492  static RCP<const Poly> from_dict(const RCP<const Basic> &var,
493  std::map<unsigned, Cf> &&d)
494  {
495  return Poly::from_container(
496  var, Poly::container_from_dict(var, std::move(d)));
497  }
498 };
499 
500 template <typename Container, typename Poly>
501 class UIntPolyBase : public UNonExprPoly<Container, Poly, integer_class>
502 {
503 private:
504  template <typename It>
506  template <typename T>
507  static auto test(int)
508  -> decltype(std::declval<T &>().operator->()->first,
509  std::declval<T &>().operator->()->second,
510  std::true_type());
511  template <typename>
512  static std::false_type test(...);
513  static const bool value = decltype(test<It>(0))::value;
514  };
515 
516  void append_symbolic_term(vec_basic &args, unsigned int i,
517  const integer_class &m) const
518  {
519  if (i == 0) {
520  args.push_back(integer(m));
521  } else if (i == 1) {
522  if (m == 1) {
523  args.push_back(this->get_var());
524  } else {
525  args.push_back(
526  Mul::from_dict(integer(m), {{this->get_var(), one}}));
527  }
528  } else {
529  if (m == 1) {
530  args.push_back(pow(this->get_var(), integer(i)));
531  } else {
532  args.push_back(Mul::from_dict(integer(m),
533  {{this->get_var(), integer(i)}}));
534  }
535  }
536  }
537 
538  template <typename P = Poly,
539  typename std::enable_if<
540  is_pair_iterator<typename P::iterator>::value, int>::type
541  = 0>
542  RCP<const Basic> as_symbolic_impl() const
543  {
544  const auto &self = down_cast<const P &>(*this);
545  auto it = self.begin();
546  auto end = self.end();
547 
548  vec_basic args;
549  for (; it != end; ++it) {
550  append_symbolic_term(args, it->first, it->second);
551  }
552  return SymEngine::add(args);
553  }
554 
555  template <typename P = Poly,
556  typename std::enable_if<
557  not is_pair_iterator<typename P::iterator>::value, int>::type
558  = 0>
559  RCP<const Basic> as_symbolic_impl() const
560  {
561  const auto &self = down_cast<const P &>(*this);
562  vec_basic args;
563  auto deg = self.get_degree();
564  for (int i = 0; i <= deg; ++i) {
565  integer_class m = self.get_coeff(i);
566  if (m == 0)
567  continue;
568  append_symbolic_term(args, numeric_cast<unsigned int>(i), m);
569  }
570  return SymEngine::add(args);
571  }
572 
573 public:
574  UIntPolyBase(const RCP<const Basic> &var, Container &&container)
575  : UNonExprPoly<Container, Poly, integer_class>(var,
576  std::move(container))
577  {
578  }
579 
580  RCP<const Basic> as_symbolic() const
581  {
582  return as_symbolic_impl();
583  }
584 };
585 
586 template <typename Container, typename Poly>
587 class URatPolyBase : public UNonExprPoly<Container, Poly, rational_class>
588 {
589 public:
590  URatPolyBase(const RCP<const Basic> &var, Container &&container)
592  std::move(container))
593  {
594  }
595 
596  RCP<const Basic> as_symbolic() const
597  {
598  auto it = (down_cast<const Poly &>(*this)).begin();
599  auto end = (down_cast<const Poly &>(*this)).end();
600 
601  vec_basic args;
602  for (; it != end; ++it) {
603  rational_class m = it->second;
604 
605  if (it->first == 0) {
606  args.push_back(Rational::from_mpq(m));
607  } else if (it->first == 1) {
608  if (m == 1) {
609  args.push_back(this->get_var());
610  } else {
611  args.push_back(Mul::from_dict(Rational::from_mpq(m),
612  {{this->get_var(), one}}));
613  }
614  } else {
615  if (m == 1) {
616  args.push_back(pow(this->get_var(), integer(it->first)));
617  } else {
618  args.push_back(Mul::from_dict(
620  {{this->get_var(), integer(it->first)}}));
621  }
622  }
623  }
624  return SymEngine::add(args);
625  }
626 };
627 
628 template <typename T, typename Int>
630 {
631 protected:
632  RCP<const T> ptr_;
633  long i_;
634 
635 public:
636  ContainerBaseIter(RCP<const T> ptr, long x) : ptr_{ptr}, i_{x} {}
637 
638  friend bool operator==(const ContainerBaseIter &lhs,
639  const ContainerBaseIter &rhs)
640  {
641  return (lhs.ptr_ == rhs.ptr_) and (lhs.i_ == rhs.i_);
642  }
643 
644  bool operator!=(const ContainerBaseIter &rhs)
645  {
646  return not(*this == rhs);
647  }
648 
649  std::pair<long, Int> operator*()
650  {
651  return std::make_pair(i_, ptr_->get_coeff_ref(i_));
652  }
653 
654  std::shared_ptr<std::pair<unsigned, Int>> operator->()
655  {
656  return std::make_shared<std::pair<unsigned, Int>>(
657  numeric_cast<unsigned>(i_),
658  ptr_->get_coeff_ref(numeric_cast<unsigned>(i_)));
659  }
660 };
661 
662 template <typename T, typename Int>
663 class ContainerForIter : public ContainerBaseIter<T, Int>
664 {
665 public:
666  ContainerForIter(RCP<const T> ptr, long x)
667  : ContainerBaseIter<T, Int>(ptr, x)
668  {
669  if (this->ptr_->get_coeff_ref(numeric_cast<unsigned>(this->i_)) == 0
670  and this->i_ < this->ptr_->size()) {
671  ++(*this);
672  }
673  }
674 
675  ContainerForIter operator++()
676  {
677  this->i_++;
678  while (this->i_ < this->ptr_->size()) {
679  if (this->ptr_->get_coeff_ref(numeric_cast<unsigned>(this->i_))
680  != 0)
681  break;
682  this->i_++;
683  }
684  return *this;
685  }
686 };
687 
688 template <typename T, typename Int>
689 class ContainerRevIter : public ContainerBaseIter<T, Int>
690 {
691 public:
692  ContainerRevIter(RCP<const T> ptr, long x)
693  : ContainerBaseIter<T, Int>(ptr, x)
694  {
695  }
696 
697  ContainerRevIter operator++()
698  {
699  this->i_--;
700  while (this->i_ >= 0) {
701  if (this->ptr_->get_coeff_ref(numeric_cast<unsigned>(this->i_))
702  != 0)
703  break;
704  this->i_--;
705  }
706  return *this;
707  }
708 };
709 
710 template <typename P>
711 struct is_a_UPoly {
712  static const bool value
713  = std::is_base_of<UPolyBase<typename P::container_type, P>, P>::value;
714 };
715 
716 template <typename Poly>
717 RCP<const Poly> add_upoly(const Poly &a, const Poly &b)
718 {
719  if (!(a.get_var()->__eq__(*b.get_var())))
720  throw SymEngineException("Error: variables must agree.");
721 
722  auto dict = a.get_poly();
723  dict += b.get_poly();
724  return Poly::from_container(a.get_var(), std::move(dict));
725 }
726 
727 template <typename Poly>
728 RCP<const Poly> neg_upoly(const Poly &a)
729 {
730  auto dict = a.get_poly();
731  dict = -dict;
732  return Poly::from_container(a.get_var(), std::move(dict));
733 }
734 
735 template <typename Poly>
736 RCP<const Poly> sub_upoly(const Poly &a, const Poly &b)
737 {
738  if (!(a.get_var()->__eq__(*b.get_var())))
739  throw SymEngineException("Error: variables must agree.");
740 
741  auto dict = a.get_poly();
742  dict -= b.get_poly();
743  return Poly::from_container(a.get_var(), std::move(dict));
744 }
745 
746 template <typename Poly>
747 RCP<const Poly> mul_upoly(const Poly &a, const Poly &b)
748 {
749  if (!(a.get_var()->__eq__(*b.get_var())))
750  throw SymEngineException("Error: variables must agree.");
751 
752  auto dict = a.get_poly();
753  dict *= b.get_poly();
754  return Poly::from_container(a.get_var(), std::move(dict));
755 }
756 
757 template <typename Poly>
758 RCP<const Poly> quo_upoly(const Poly &a, const Poly &b)
759 {
760  if (!(a.get_var()->__eq__(*b.get_var())))
761  throw SymEngineException("Error: variables must agree.");
762 
763  auto dict = a.get_poly();
764  dict /= b.get_poly();
765  return Poly::from_dict(a.get_var(), std::move(dict));
766 }
767 } // namespace SymEngine
768 
769 #endif // SYMENGINE_UINT_BASE_H
Classes and functions relating to the binary operation of addition.
The base class for SymEngine.
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
static RCP< const Number > from_mpq(const rational_class &i)
Definition: rational.cpp:23
bool __eq__(const Basic &o) const override
Definition: upolybase.h:376
hash_t __hash__() const override=0
int compare(const Basic &o) const override=0
vec_basic get_args() const override
Returns the list of arguments.
Definition: upolybase.h:394
Main namespace for SymEngine package.
Definition: add.cpp:19
RCP< const Basic > add(const RCP< const Basic > &a, const RCP< const Basic > &b)
Adds two objects (safely).
Definition: add.cpp:425
std::enable_if< std::is_integral< T >::value, RCP< const Integer > >::type integer(T i)
Definition: integer.h:197
RCP< const Basic > mul(const RCP< const Basic > &a, const RCP< const Basic > &b)
Multiplication.
Definition: mul.cpp:352
bool eq(const Basic &a, const Basic &b)
Checks equality for a and b
Definition: basic-inl.h:21
RCP< const Number > rational(long n, long d)
convenience creator from two longs
Definition: rational.h:329