basic_conversions.h
1 #ifndef SYMENGINE_BASIC_CONVERSIONS_H
2 #define SYMENGINE_BASIC_CONVERSIONS_H
3 
4 #include <symengine/visitor.h>
5 
6 namespace SymEngine
7 {
8 
9 // convert a `basic`, to a UPoly `P` (eg. UIntPoly, UExprPoly, UIntPolyFlint)
10 // using `gen` as the genarator. Throws, if poly constructions not possible.
11 // `ex` is the optional parameter for expanding the given `basic` or not.
12 template <typename P>
13 RCP<const P> from_basic(const RCP<const Basic> &basic,
14  const RCP<const Basic> &gen, bool ex = false);
15 // convert a `basic`, to a UPoly `P` (eg. UIntPoly, UExprPoly, UIntPolyFlint)
16 // after finding out the generator automatically. Throws, if number
17 // of generators found != 1, or poly construction not possible.
18 // `ex` is the optional parameter for expanding the given `basic` or not.
19 
20 template <typename P>
21 enable_if_t<is_a_UPoly<P>::value, RCP<const P>>
22 from_basic(const RCP<const Basic> &basic, bool ex = false);
23 
24 template <typename T, typename P>
25 enable_if_t<std::is_same<T, UExprDict>::value, T>
26 _basic_to_upoly(const RCP<const Basic> &basic, const RCP<const Basic> &gen);
27 
28 template <typename T, typename P>
29 enable_if_t<std::is_base_of<UIntPolyBase<T, P>, P>::value, T>
30 _basic_to_upoly(const RCP<const Basic> &basic, const RCP<const Basic> &gen);
31 
32 template <typename T, typename P>
33 enable_if_t<std::is_base_of<URatPolyBase<T, P>, P>::value, T>
34 _basic_to_upoly(const RCP<const Basic> &basic, const RCP<const Basic> &gen);
35 
36 template <typename P, typename V>
37 class BasicToUPolyBase : public BaseVisitor<V>
38 {
39 public:
40  RCP<const Basic> gen;
41  using D = typename P::container_type;
42  D dict;
43 
44  BasicToUPolyBase(const RCP<const Basic> &gen_)
45  {
46  gen = gen_;
47  }
48 
49  D apply(const Basic &b)
50  {
51  b.accept(*this);
52  return std::move(dict);
53  }
54 
55  void dict_set(unsigned int pow, const Basic &x)
56  {
57  down_cast<V *>(this)->dict_set(pow, x);
58  }
59 
60  void bvisit(const Pow &x)
61  {
62  if (is_a<const Integer>(*x.get_exp())) {
63  int i = numeric_cast<int>(
64  down_cast<const Integer &>(*x.get_exp()).as_int());
65  if (i > 0) {
66  dict
67  = pow_upoly(*P::from_container(gen, _basic_to_upoly<D, P>(
68  x.get_base(), gen)),
69  i)
70  ->get_poly();
71  return;
72  }
73  }
74 
75  RCP<const Basic> genbase = gen, genpow = one, coef = one, tmp;
76  if (is_a<const Pow>(*gen)) {
77  genbase = down_cast<const Pow &>(*gen).get_base();
78  genpow = down_cast<const Pow &>(*gen).get_exp();
79  }
80 
81  if (eq(*genbase, *x.get_base())) {
82 
83  set_basic expos;
84 
85  if (is_a<const Add>(*x.get_exp())) {
86  RCP<const Add> addx = rcp_static_cast<const Add>(x.get_exp());
87  for (auto const &it : addx->get_dict())
88  expos.insert(mul(it.first, it.second));
89  if (not addx->get_coef()->is_zero())
90  expos.insert(addx->get_coef());
91  } else {
92  expos.insert(x.get_exp());
93  }
94 
95  int powr = 0;
96  for (auto const &it : expos) {
97  tmp = div(it, genpow);
98  if (is_a<const Integer>(*tmp)) {
99  RCP<const Integer> i = rcp_static_cast<const Integer>(tmp);
100  if (i->is_positive()) {
101  powr = static_cast<int>(i->as_int());
102  continue;
103  }
104  }
105  coef = mul(coef, pow(genbase, it));
106  }
107  dict_set(powr, *coef);
108  } else {
109  this->bvisit((const Basic &)x);
110  }
111  }
112 
113  void bvisit(const Add &x)
114  {
115  D res = apply(*x.get_coef());
116  for (auto const &it : x.get_dict())
117  res += apply(*it.first) * apply(*it.second);
118  dict = std::move(res);
119  }
120 
121  void bvisit(const Mul &x)
122  {
123  D res = apply(*x.get_coef());
124  for (auto const &it : x.get_dict())
125  res *= apply(*pow(it.first, it.second));
126  dict = std::move(res);
127  }
128 
129  void bvisit(const Integer &x)
130  {
131  integer_class i = x.as_integer_class();
132  dict = P::container_from_dict(gen, {{0, typename P::coef_type(i)}});
133  }
134 
135  template <
136  typename Poly,
137  typename = enable_if_t<
138  ((std::is_base_of<UIntPolyBase<typename P::container_type, P>,
139  P>::value
140  and std::is_base_of<
142  Poly>::value)
144  P>::value
145  and (std::is_base_of<
147  Poly>::value
148  or std::is_base_of<
150  Poly>::value))
151  or (std::is_same<P, UExprPoly>::value
152  and std::is_base_of<
154  Poly>::value))
155  and not std::is_same<Poly, GaloisField>::value>>
156  void bvisit(const Poly &x)
157  {
158  dict = (P::from_poly(x))->get_poly();
159  }
160 
161  void bvisit(const Basic &x)
162  {
163  RCP<const Basic> genpow = one, genbase = gen, powr;
164  if (is_a<const Pow>(*gen)) {
165  genpow = down_cast<const Pow &>(*gen).get_exp();
166  genbase = down_cast<const Pow &>(*gen).get_base();
167  }
168  if (eq(*genbase, x)) {
169  powr = div(one, genpow);
170  if (is_a<const Integer>(*powr)) {
171  int i = numeric_cast<int>(
172  down_cast<const Integer &>(*powr).as_int());
173  if (i > 0) {
174  dict = P::container_from_dict(
175  gen, {{i, typename P::coef_type(1)}});
176  return;
177  }
178  }
179  }
180  if (is_a<const Symbol>(*gen)) {
181  if (has_symbol(x, *gen)) {
182  throw SymEngineException("Not a Polynomial");
183  }
184  }
185  dict_set(0, x);
186  }
187 };
188 
189 template <typename Poly>
191 {
192 public:
195 
196  BasicToUIntPoly(const RCP<const Basic> &gen)
198  {
199  }
200 
201  void bvisit(const Rational &x)
202  {
203  throw SymEngineException("Non-integer found");
204  }
205 
206  void dict_set(unsigned int pow, const Basic &x)
207  {
208  if (is_a<const Integer>(x))
209  this->dict = Poly::container_from_dict(
210  this->gen,
211  {{pow, down_cast<const Integer &>(x).as_integer_class()}});
212  else
213  throw SymEngineException("Non-integer found");
214  }
215 };
216 
217 class SYMENGINE_EXPORT BasicToUExprPoly
218  : public BasicToUPolyBase<UExprPoly, BasicToUExprPoly>
219 {
220 public:
223 
224  BasicToUExprPoly(const RCP<const Basic> &gen) : BasicToUPolyBase(gen) {}
225 
226  void bvisit(const Rational &x)
227  {
228  dict = UExprDict(x.rcp_from_this());
229  }
230 
231  void dict_set(unsigned int pow, const Basic &x)
232  {
233  dict = UExprDict({{pow, x.rcp_from_this()}});
234  }
235 };
236 
237 template <typename Poly>
238 class BasicToURatPoly : public BasicToUPolyBase<Poly, BasicToURatPoly<Poly>>
239 {
240 public:
243 
244  BasicToURatPoly(const RCP<const Basic> &gen)
246  {
247  }
248 
249  void bvisit(const Rational &x)
250  {
251  this->dict = URatDict(x.as_rational_class());
252  }
253 
254  void dict_set(unsigned int pow, const Basic &x)
255  {
256  if (is_a<const Integer>(x))
257  this->dict = Poly::container_from_dict(
258  this->gen, {{pow, rational_class(static_cast<const Integer &>(x)
259  .as_integer_class())}});
260  else if (is_a<const Rational>(x))
261  this->dict = Poly::container_from_dict(
262  this->gen,
263  {{pow, static_cast<const Rational &>(x).as_rational_class()}});
264  else
265  throw SymEngineException("Non-rational found");
266  }
267 };
268 
269 template <typename T, typename P>
270 enable_if_t<std::is_same<T, UExprDict>::value, T>
271 _basic_to_upoly(const RCP<const Basic> &basic, const RCP<const Basic> &gen)
272 {
273  BasicToUExprPoly v(gen);
274  return v.apply(*basic);
275 }
276 
277 template <typename T, typename P>
278 enable_if_t<std::is_base_of<UIntPolyBase<T, P>, P>::value, T>
279 _basic_to_upoly(const RCP<const Basic> &basic, const RCP<const Basic> &gen)
280 {
281  BasicToUIntPoly<P> v(gen);
282  return v.apply(*basic);
283 }
284 
285 template <typename T, typename P>
286 enable_if_t<std::is_base_of<URatPolyBase<T, P>, P>::value, T>
287 _basic_to_upoly(const RCP<const Basic> &basic, const RCP<const Basic> &gen)
288 {
289  BasicToURatPoly<P> v(gen);
290  return v.apply(*basic);
291 }
292 
293 template <typename P>
294 RCP<const P> from_basic(const RCP<const Basic> &basic,
295  const RCP<const Basic> &gen, bool ex)
296 {
297  RCP<const Basic> exp = basic;
298  if (ex)
299  exp = expand(basic);
300  return P::from_container(
301  gen, _basic_to_upoly<typename P::container_type, P>(exp, gen));
302 }
303 
304 template <typename P>
305 enable_if_t<is_a_UPoly<P>::value, RCP<const P>>
306 from_basic(const RCP<const Basic> &basic, bool ex)
307 {
308  RCP<const Basic> exp = basic;
309  if (ex)
310  exp = expand(basic);
311 
312  umap_basic_num tmp = _find_gens_poly(exp);
313 
314  if (tmp.size() != 1)
315  throw SymEngineException("Did not find exactly 1 generator");
316 
317  RCP<const Basic> gen = pow(tmp.begin()->first, tmp.begin()->second);
318  return P::from_container(
319  gen, _basic_to_upoly<typename P::container_type, P>(exp, gen));
320 }
321 
322 template <typename P>
323 enable_if_t<std::is_same<MIntPoly, P>::value, typename P::container_type>
324 _basic_to_mpoly(const RCP<const Basic> &basic, const set_basic &gens);
325 
326 template <typename P, typename V>
327 class BasicToMPolyBase : public BaseVisitor<V>
328 {
329 public:
330  using Dict = typename P::container_type;
331  using Vec = typename Dict::vec_type;
332  Dict dict;
333  set_basic gens;
334  std::unordered_map<RCP<const Basic>, vec_basic, RCPBasicHash, RCPBasicKeyEq>
335  gens_pow;
336  umap_basic_uint gens_map;
337 
338  BasicToMPolyBase(const set_basic &gens_)
339  {
340  gens = gens_;
341  dict.vec_size = static_cast<int>(gens.size());
342 
343  RCP<const Basic> genpow, genbase;
344  unsigned int i = 0;
345 
346  for (auto it : gens) {
347  genpow = one;
348  genbase = it;
349  if (is_a<const Pow>(*it)) {
350  genpow = down_cast<const Pow &>(*it).get_exp();
351  genbase = down_cast<const Pow &>(*it).get_base();
352  }
353  auto ite = gens_pow.find(genbase);
354  if (ite == gens_pow.end())
355  gens_pow[genbase] = {genpow};
356  else
357  gens_pow[genbase].push_back(genpow);
358  gens_map[it] = i++;
359  }
360  }
361 
362  Dict apply(const Basic &b)
363  {
364  b.accept(*this);
365  return std::move(dict);
366  }
367 
368  void dict_set(Vec pow, const Basic &x)
369  {
370  down_cast<V *>(this)->dict_set(pow, x);
371  }
372 
373  void bvisit(const Pow &x)
374  {
375  if (is_a<const Integer>(*x.get_exp())) {
376  int i = numeric_cast<int>(
377  down_cast<const Integer &>(*x.get_exp()).as_int());
378  if (i > 0) {
379  dict = Dict::pow(_basic_to_mpoly<P>(x.get_base(), gens), i);
380  return;
381  }
382  }
383 
384  Vec zero_v(gens.size(), 0);
385  RCP<const Basic> coef = one, tmp;
386  RCP<const Integer> i;
387  bool found;
388  auto ite = gens_pow.find(x.get_base());
389 
390  if (ite != gens_pow.end()) {
391 
392  set_basic expos;
393 
394  if (is_a<const Add>(*x.get_exp())) {
395  RCP<const Add> addx = rcp_static_cast<const Add>(x.get_exp());
396  for (auto const &it : addx->get_dict())
397  expos.insert(mul(it.first, it.second));
398  if (not addx->get_coef()->is_zero())
399  expos.insert(addx->get_coef());
400  } else {
401  expos.insert(x.get_exp());
402  }
403 
404  for (auto const &it : expos) {
405 
406  found = false;
407 
408  for (auto powr : ite->second) {
409  tmp = div(it, powr);
410  if (is_a<const Integer>(*tmp)) {
411  i = rcp_static_cast<const Integer>(tmp);
412  if (i->is_positive()) {
413  zero_v[gens_map[pow(ite->first, powr)]]
414  = static_cast<int>(i->as_int());
415  found = true;
416  break;
417  }
418  }
419  }
420 
421  if (not found)
422  coef = mul(coef, pow(ite->first, it));
423  }
424  dict_set(zero_v, *coef);
425 
426  } else {
427  dict_set(zero_v, x);
428  }
429  }
430 
431  void bvisit(const Add &x)
432  {
433  Dict res = apply(*x.get_coef());
434  for (auto const &it : x.get_dict())
435  res += apply(*it.first) * apply(*it.second);
436  dict = std::move(res);
437  }
438 
439  void bvisit(const Mul &x)
440  {
441  Dict res = apply(*x.get_coef());
442  for (auto const &it : x.get_dict())
443  res *= apply(*pow(it.first, it.second));
444  dict = std::move(res);
445  }
446 
447  void bvisit(const Integer &x)
448  {
449  integer_class i = x.as_integer_class();
450  Vec zero_v(gens.size(), 0);
451  dict = P::container_from_dict(gens, {{zero_v, i}});
452  }
453 
454  void bvisit(const Basic &x)
455  {
456  RCP<const Basic> powr;
457  Vec zero_v(gens.size(), 0);
458 
459  auto it = gens_pow.find(x.rcp_from_this());
460  if (it != gens_pow.end()) {
461 
462  for (auto pows : it->second) {
463  powr = div(one, pows);
464  if (is_a<const Integer>(*powr)) {
465  int i = numeric_cast<int>(
466  down_cast<const Integer &>(*powr).as_int());
467  if (i > 0) {
468  // can be optimized
469  zero_v[gens_map[pow(it->first, pows)]] = i;
470  dict = P::container_from_dict(
471  gens, {{zero_v, typename P::coef_type(1)}});
472  return;
473  }
474  }
475  }
476  }
477 
478  dict_set(zero_v, x);
479  }
480 };
481 
482 class SYMENGINE_EXPORT BasicToMIntPoly
483  : public BasicToMPolyBase<MIntPoly, BasicToMIntPoly>
484 {
485 public:
488 
489  BasicToMIntPoly(const set_basic &gens) : BasicToMPolyBase(gens) {}
490 
491  void bvisit(const Rational &x)
492  {
493  throw SymEngineException("Non-integer found");
494  }
495 
496  void dict_set(vec_uint pow, const Basic &x)
497  {
498  if (is_a<const Integer>(x))
499  dict = MIntPoly::container_from_dict(
500  gens,
501  {{pow, down_cast<const Integer &>(x).as_integer_class()}});
502  else
503  throw SymEngineException("Non-integer found");
504  }
505 };
506 
507 class SYMENGINE_EXPORT BasicToMExprPoly
508  : public BasicToMPolyBase<MExprPoly, BasicToMExprPoly>
509 {
510 public:
513 
514  BasicToMExprPoly(const set_basic &gens) : BasicToMPolyBase(gens) {}
515 
516  void bvisit(const Rational &x)
517  {
518  Vec v(gens.size(), 0);
519  dict = MExprPoly::container_from_dict(gens, {{v, x.rcp_from_this()}});
520  }
521 
522  void dict_set(vec_int pow, const Basic &x)
523  {
524  dict = MExprPoly::container_from_dict(gens, {{pow, x.rcp_from_this()}});
525  }
526 };
527 
528 template <typename P>
529 enable_if_t<std::is_same<MIntPoly, P>::value, typename P::container_type>
530 _basic_to_mpoly(const RCP<const Basic> &basic, const set_basic &gens)
531 {
532  BasicToMIntPoly v(gens);
533  return v.apply(*basic);
534 }
535 
536 template <typename P>
537 enable_if_t<std::is_same<MExprPoly, P>::value, typename P::container_type>
538 _basic_to_mpoly(const RCP<const Basic> &basic, const set_basic &gens)
539 {
540  BasicToMExprPoly v(gens);
541  return v.apply(*basic);
542 }
543 
544 template <typename P>
545 RCP<const P> from_basic(const RCP<const Basic> &basic, set_basic &gens,
546  bool ex = false)
547 {
548  RCP<const Basic> exp = basic;
549  if (ex)
550  exp = expand(basic);
551  // need to add a check to see if generators are valid
552  // for eg. we dont want x and x**2 as the gens
553  return P::from_container(gens, _basic_to_mpoly<P>(exp, gens));
554 }
555 
556 template <typename P>
557 enable_if_t<
558  std::is_base_of<MSymEnginePoly<typename P::container_type, P>, P>::value,
559  RCP<const P>>
560 from_basic(const RCP<const Basic> &basic, bool ex = false)
561 {
562  RCP<const Basic> exp = basic;
563  if (ex)
564  exp = expand(basic);
565 
566  umap_basic_num tmp = _find_gens_poly(exp);
567  set_basic gens;
568  for (auto it : tmp)
569  gens.insert(pow(it.first, it.second));
570 
571  return P::from_container(gens, _basic_to_mpoly<P>(exp, gens));
572 }
573 } // namespace SymEngine
574 
575 #endif
The base class for representing addition in symbolic expressions.
Definition: add.h:27
const RCP< const Number > & get_coef() const
Definition: add.h:142
The lowest unit of symbolic representation.
Definition: basic.h:97
RCP< T > rcp_from_this()
Get RCP<T> pointer to self (it will cast the pointer to T)
Integer Class.
Definition: integer.h:19
const integer_class & as_integer_class() const
Convert to integer_class.
Definition: integer.h:45
RCP< const Basic > get_exp() const
Definition: pow.h:42
RCP< const Basic > get_base() const
Definition: pow.h:37
Rational Class.
Definition: rational.h:16
const rational_class & as_rational_class() const
Convert to rational_class.
Definition: rational.h:50
Main namespace for SymEngine package.
Definition: add.cpp:19
RCP< const Basic > mul(const RCP< const Basic > &a, const RCP< const Basic > &b)
Multiplication.
Definition: mul.cpp:352
RCP< const Basic > exp(const RCP< const Basic > &x)
Returns the natural exponential function E**x = pow(E, x)
Definition: pow.cpp:271
bool eq(const Basic &a, const Basic &b)
Checks equality for a and b
Definition: basic-inl.h:21
RCP< const Basic > div(const RCP< const Basic > &a, const RCP< const Basic > &b)
Division.
Definition: mul.cpp:431
SYMENGINE_EXPORT RCP< const Basic > expand(const RCP< const Basic > &self, bool deep=true)
Expands self
Definition: expand.cpp:369
Our comparison (==)
Definition: basic.h:219