Loading...
Searching...
No Matches
basic_conversions.h
1#ifndef SYMENGINE_BASIC_CONVERSIONS_H
2#define SYMENGINE_BASIC_CONVERSIONS_H
3
4#include <symengine/visitor.h>
5
6namespace 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.
12template <typename P>
13RCP<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
20template <typename P>
21enable_if_t<is_a_UPoly<P>::value, RCP<const P>>
22from_basic(const RCP<const Basic> &basic, bool ex = false);
23
24template <typename T, typename P>
25enable_if_t<std::is_same<T, UExprDict>::value, T>
26_basic_to_upoly(const RCP<const Basic> &basic, const RCP<const Basic> &gen);
27
28template <typename T, typename P>
29enable_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
32template <typename T, typename P>
33enable_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
36template <typename P, typename V>
38{
39public:
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<
139 P>::value
140 and std::is_base_of<
142 Poly>::value)
144 P>::value
145 and (std::is_base_of<
147 Poly>::value
150 Poly>::value))
152 and std::is_base_of<
154 Poly>::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
189template <typename Poly>
191{
192public:
193 using BasicToUPolyBase<Poly, BasicToUIntPoly>::bvisit;
194 using BasicToUPolyBase<Poly, BasicToUIntPoly>::apply;
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
217class BasicToUExprPoly : public BasicToUPolyBase<UExprPoly, BasicToUExprPoly>
218{
219public:
222
223 BasicToUExprPoly(const RCP<const Basic> &gen) : BasicToUPolyBase(gen) {}
224
225 void bvisit(const Rational &x)
226 {
227 dict = UExprDict(x.rcp_from_this());
228 }
229
230 void dict_set(unsigned int pow, const Basic &x)
231 {
232 dict = UExprDict({{pow, x.rcp_from_this()}});
233 }
234};
235
236template <typename Poly>
237class BasicToURatPoly : public BasicToUPolyBase<Poly, BasicToURatPoly<Poly>>
238{
239public:
240 using BasicToUPolyBase<Poly, BasicToURatPoly>::bvisit;
241 using BasicToUPolyBase<Poly, BasicToURatPoly>::apply;
242
243 BasicToURatPoly(const RCP<const Basic> &gen)
245 {
246 }
247
248 void bvisit(const Rational &x)
249 {
250 this->dict = URatDict(x.as_rational_class());
251 }
252
253 void dict_set(unsigned int pow, const Basic &x)
254 {
255 if (is_a<const Integer>(x))
256 this->dict = Poly::container_from_dict(
257 this->gen, {{pow, rational_class(static_cast<const Integer &>(x)
258 .as_integer_class())}});
259 else if (is_a<const Rational>(x))
260 this->dict = Poly::container_from_dict(
261 this->gen,
262 {{pow, static_cast<const Rational &>(x).as_rational_class()}});
263 else
264 throw SymEngineException("Non-rational found");
265 }
266};
267
268template <typename T, typename P>
269enable_if_t<std::is_same<T, UExprDict>::value, T>
270_basic_to_upoly(const RCP<const Basic> &basic, const RCP<const Basic> &gen)
271{
272 BasicToUExprPoly v(gen);
273 return v.apply(*basic);
274}
275
276template <typename T, typename P>
277enable_if_t<std::is_base_of<UIntPolyBase<T, P>, P>::value, T>
278_basic_to_upoly(const RCP<const Basic> &basic, const RCP<const Basic> &gen)
279{
280 BasicToUIntPoly<P> v(gen);
281 return v.apply(*basic);
282}
283
284template <typename T, typename P>
285enable_if_t<std::is_base_of<URatPolyBase<T, P>, P>::value, T>
286_basic_to_upoly(const RCP<const Basic> &basic, const RCP<const Basic> &gen)
287{
288 BasicToURatPoly<P> v(gen);
289 return v.apply(*basic);
290}
291
292template <typename P>
293RCP<const P> from_basic(const RCP<const Basic> &basic,
294 const RCP<const Basic> &gen, bool ex)
295{
296 RCP<const Basic> exp = basic;
297 if (ex)
298 exp = expand(basic);
299 return P::from_container(
300 gen, _basic_to_upoly<typename P::container_type, P>(exp, gen));
301}
302
303template <typename P>
304enable_if_t<is_a_UPoly<P>::value, RCP<const P>>
305from_basic(const RCP<const Basic> &basic, bool ex)
306{
307 RCP<const Basic> exp = basic;
308 if (ex)
309 exp = expand(basic);
310
311 umap_basic_num tmp = _find_gens_poly(exp);
312
313 if (tmp.size() != 1)
314 throw SymEngineException("Did not find exactly 1 generator");
315
316 RCP<const Basic> gen = pow(tmp.begin()->first, tmp.begin()->second);
317 return P::from_container(
318 gen, _basic_to_upoly<typename P::container_type, P>(exp, gen));
319}
320
321template <typename P>
322enable_if_t<std::is_same<MIntPoly, P>::value, typename P::container_type>
323_basic_to_mpoly(const RCP<const Basic> &basic, const set_basic &gens);
324
325template <typename P, typename V>
327{
328public:
329 using Dict = typename P::container_type;
330 using Vec = typename Dict::vec_type;
331 Dict dict;
332 set_basic gens;
334 gens_pow;
335 umap_basic_uint gens_map;
336
337 BasicToMPolyBase(const set_basic &gens_)
338 {
339 gens = gens_;
340 dict.vec_size = static_cast<int>(gens.size());
341
342 RCP<const Basic> genpow, genbase;
343 unsigned int i = 0;
344
345 for (auto it : gens) {
346 genpow = one;
347 genbase = it;
348 if (is_a<const Pow>(*it)) {
349 genpow = down_cast<const Pow &>(*it).get_exp();
350 genbase = down_cast<const Pow &>(*it).get_base();
351 }
352 auto ite = gens_pow.find(genbase);
353 if (ite == gens_pow.end())
354 gens_pow[genbase] = {genpow};
355 else
356 gens_pow[genbase].push_back(genpow);
357 gens_map[it] = i++;
358 }
359 }
360
361 Dict apply(const Basic &b)
362 {
363 b.accept(*this);
364 return std::move(dict);
365 }
366
367 void dict_set(Vec pow, const Basic &x)
368 {
369 down_cast<V *>(this)->dict_set(pow, x);
370 }
371
372 void bvisit(const Pow &x)
373 {
374 if (is_a<const Integer>(*x.get_exp())) {
375 int i = numeric_cast<int>(
376 down_cast<const Integer &>(*x.get_exp()).as_int());
377 if (i > 0) {
378 dict = Dict::pow(_basic_to_mpoly<P>(x.get_base(), gens), i);
379 return;
380 }
381 }
382
383 Vec zero_v(gens.size(), 0);
384 RCP<const Basic> coef = one, tmp;
385 RCP<const Integer> i;
386 bool found;
387 auto ite = gens_pow.find(x.get_base());
388
389 if (ite != gens_pow.end()) {
390
391 set_basic expos;
392
393 if (is_a<const Add>(*x.get_exp())) {
394 RCP<const Add> addx = rcp_static_cast<const Add>(x.get_exp());
395 for (auto const &it : addx->get_dict())
396 expos.insert(mul(it.first, it.second));
397 if (not addx->get_coef()->is_zero())
398 expos.insert(addx->get_coef());
399 } else {
400 expos.insert(x.get_exp());
401 }
402
403 for (auto const &it : expos) {
404
405 found = false;
406
407 for (auto powr : ite->second) {
408 tmp = div(it, powr);
409 if (is_a<const Integer>(*tmp)) {
410 i = rcp_static_cast<const Integer>(tmp);
411 if (i->is_positive()) {
412 zero_v[gens_map[pow(ite->first, powr)]]
413 = static_cast<int>(i->as_int());
414 found = true;
415 break;
416 }
417 }
418 }
419
420 if (not found)
421 coef = mul(coef, pow(ite->first, it));
422 }
423 dict_set(zero_v, *coef);
424
425 } else {
426 dict_set(zero_v, x);
427 }
428 }
429
430 void bvisit(const Add &x)
431 {
432 Dict res = apply(*x.get_coef());
433 for (auto const &it : x.get_dict())
434 res += apply(*it.first) * apply(*it.second);
435 dict = std::move(res);
436 }
437
438 void bvisit(const Mul &x)
439 {
440 Dict res = apply(*x.get_coef());
441 for (auto const &it : x.get_dict())
442 res *= apply(*pow(it.first, it.second));
443 dict = std::move(res);
444 }
445
446 void bvisit(const Integer &x)
447 {
448 integer_class i = x.as_integer_class();
449 Vec zero_v(gens.size(), 0);
450 dict = P::container_from_dict(gens, {{zero_v, i}});
451 }
452
453 void bvisit(const Basic &x)
454 {
455 RCP<const Basic> powr;
456 Vec zero_v(gens.size(), 0);
457
458 auto it = gens_pow.find(x.rcp_from_this());
459 if (it != gens_pow.end()) {
460
461 for (auto pows : it->second) {
462 powr = div(one, pows);
463 if (is_a<const Integer>(*powr)) {
464 int i = numeric_cast<int>(
465 down_cast<const Integer &>(*powr).as_int());
466 if (i > 0) {
467 // can be optimized
468 zero_v[gens_map[pow(it->first, pows)]] = i;
469 dict = P::container_from_dict(
470 gens, {{zero_v, typename P::coef_type(1)}});
471 return;
472 }
473 }
474 }
475 }
476
477 dict_set(zero_v, x);
478 }
479};
480
481class BasicToMIntPoly : public BasicToMPolyBase<MIntPoly, BasicToMIntPoly>
482{
483public:
486
487 BasicToMIntPoly(const set_basic &gens) : BasicToMPolyBase(gens) {}
488
489 void bvisit(const Rational &x)
490 {
491 throw SymEngineException("Non-integer found");
492 }
493
494 void dict_set(vec_uint pow, const Basic &x)
495 {
496 if (is_a<const Integer>(x))
497 dict = MIntPoly::container_from_dict(
498 gens,
499 {{pow, down_cast<const Integer &>(x).as_integer_class()}});
500 else
501 throw SymEngineException("Non-integer found");
502 }
503};
504
505class BasicToMExprPoly : public BasicToMPolyBase<MExprPoly, BasicToMExprPoly>
506{
507public:
510
511 BasicToMExprPoly(const set_basic &gens) : BasicToMPolyBase(gens) {}
512
513 void bvisit(const Rational &x)
514 {
515 Vec v(gens.size(), 0);
516 dict = MExprPoly::container_from_dict(gens, {{v, x.rcp_from_this()}});
517 }
518
519 void dict_set(vec_int pow, const Basic &x)
520 {
521 dict = MExprPoly::container_from_dict(gens, {{pow, x.rcp_from_this()}});
522 }
523};
524
525template <typename P>
526enable_if_t<std::is_same<MIntPoly, P>::value, typename P::container_type>
527_basic_to_mpoly(const RCP<const Basic> &basic, const set_basic &gens)
528{
529 BasicToMIntPoly v(gens);
530 return v.apply(*basic);
531}
532
533template <typename P>
534enable_if_t<std::is_same<MExprPoly, P>::value, typename P::container_type>
535_basic_to_mpoly(const RCP<const Basic> &basic, const set_basic &gens)
536{
537 BasicToMExprPoly v(gens);
538 return v.apply(*basic);
539}
540
541template <typename P>
542RCP<const P> from_basic(const RCP<const Basic> &basic, set_basic &gens,
543 bool ex = false)
544{
545 RCP<const Basic> exp = basic;
546 if (ex)
547 exp = expand(basic);
548 // need to add a check to see if generators are valid
549 // for eg. we dont want x and x**2 as the gens
550 return P::from_container(gens, _basic_to_mpoly<P>(exp, gens));
551}
552
553template <typename P>
554enable_if_t<
556 RCP<const P>>
557from_basic(const RCP<const Basic> &basic, bool ex = false)
558{
559 RCP<const Basic> exp = basic;
560 if (ex)
561 exp = expand(basic);
562
563 umap_basic_num tmp = _find_gens_poly(exp);
564 set_basic gens;
565 for (auto it : tmp)
566 gens.insert(pow(it.first, it.second));
567
568 return P::from_container(gens, _basic_to_mpoly<P>(exp, gens));
569}
570} // namespace SymEngine
571
572#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:48
RCP< const Basic > get_base() const
Definition: pow.h:37
RCP< const Basic > get_exp() const
Definition: pow.h:42
Rational Class.
Definition: rational.h:16
const rational_class & as_rational_class() const
Convert to rational_class.
Definition: rational.h:50
T end(T... args)
T find(T... args)
T insert(T... args)
T move(T... args)
Main namespace for SymEngine package.
Definition: add.cpp:19
RCP< const Basic > div(const RCP< const Basic > &a, const RCP< const Basic > &b)
Division.
Definition: mul.cpp:431
bool eq(const Basic &a, const Basic &b)
Checks equality for a and b
Definition: basic-inl.h:21
RCP< const Basic > exp(const RCP< const Basic > &x)
Returns the natural exponential function E**x = pow(E, x)
Definition: pow.cpp:271
RCP< const Basic > mul(const RCP< const Basic > &a, const RCP< const Basic > &b)
Multiplication.
Definition: mul.cpp:352
RCP< const Basic > expand(const RCP< const Basic > &self, bool deep=true)
Expands self
Definition: expand.cpp:369
T pow(T... args)
T size(T... args)
Our comparison (==)
Definition: basic.h:219