basic_conversions.cpp
1 #include <symengine/visitor.h>
2 #include <symengine/polys/basic_conversions.h>
3 
4 namespace SymEngine
5 {
6 // all throughout Number refers to either a Rational or an Integer only
7 umap_basic_num _find_gens_poly_pow(const RCP<const Basic> &x,
8  const RCP<const Basic> &base);
9 
10 class PolyGeneratorVisitor : public BaseVisitor<PolyGeneratorVisitor>
11 {
12 private:
13  // the generators are pow(it.first, it.second)
14  // those which are not Pow are stored as (x, one)
15  // numbers must always be positive and of the form (1/d, d belongs to N)
16  umap_basic_num gen_set;
17 
18 public:
19  umap_basic_num apply(const Basic &b)
20  {
21  b.accept(*this);
22  return std::move(gen_set);
23  }
24 
25  // adds curr to gen_set, or updates already existing gen
26  void add_to_gen_set(const RCP<const Basic> &base,
27  const RCP<const Number> &exp)
28  {
29  auto it = gen_set.find(base);
30  if (it == gen_set.end()) {
31  gen_set[base] = exp;
32  return;
33  }
34 
35  if (is_a<const Rational>(*exp)) {
36  RCP<const Integer> den
37  = down_cast<const Rational &>(*exp).get_den();
38  if (is_a<const Rational>(*it->second))
39  gen_set[base] = divnum(
40  one,
41  lcm(*den,
42  *down_cast<const Rational &>(*it->second).get_den()));
43  else
44  gen_set[base] = divnum(one, den);
45  }
46  }
47 
48  void bvisit(const Pow &x)
49  {
50  if (is_a<const Integer>(*x.get_exp())) {
51  if (down_cast<const Integer &>(*x.get_exp()).is_positive()) {
52  x.get_base()->accept(*this);
53  } else {
54  add_to_gen_set(pow(x.get_base(), minus_one), one);
55  }
56 
57  } else if (is_a<const Rational>(*x.get_exp())) {
58 
59  RCP<const Basic> base = x.get_base();
60  RCP<const Rational> r
61  = rcp_static_cast<const Rational>(x.get_exp());
62  if (r->is_negative())
63  base = pow(base, minus_one);
64  add_to_gen_set(base, divnum(one, r->get_den()));
65 
66  } else {
67  umap_basic_num pow_pairs
68  = _find_gens_poly_pow(x.get_exp(), x.get_base());
69  for (auto it : pow_pairs)
70  add_to_gen_set(pow(x.get_base(), it.first), it.second);
71  }
72  }
73 
74  void bvisit(const Add &x)
75  {
76  for (auto it : x.get_dict())
77  it.first->accept(*this);
78  }
79 
80  void bvisit(const Mul &x)
81  {
82  for (auto it : x.get_dict())
83  it.first->accept(*this);
84  }
85 
86  void bvisit(const Number &x)
87  {
88  // intentionally blank
89  }
90 
91  void bvisit(const Basic &x)
92  {
93  add_to_gen_set(x.rcp_from_this(), one);
94  }
95 };
96 
97 class PolyGeneratorVisitorPow : public BaseVisitor<PolyGeneratorVisitorPow>
98 {
99 private:
100  // the generators are mul(it.first, it.second) not Pow
101  // the_base is the base of the Pow (whose exp we are currently dealing)
102  // numbers must always be positive and of the form (1/d, d belongs to N)
103  umap_basic_num gen_set;
104  RCP<const Basic> the_base;
105 
106 public:
107  umap_basic_num apply(const Basic &b, const RCP<const Basic> &base)
108  {
109  the_base = base;
110  b.accept(*this);
111  return std::move(gen_set);
112  }
113 
114  void bvisit(const Add &x)
115  {
116  if (not x.get_coef()->is_zero())
117  x.get_coef()->accept(*this);
118 
119  for (auto it : x.get_dict()) {
120  RCP<const Number> mulx = one, divx = one;
121 
122  if (it.second->is_negative())
123  mulx = minus_one;
124 
125  if (is_a<const Rational>(*it.second))
126  divx = down_cast<const Rational &>(*it.second).get_den();
127 
128  gen_set[mul(mulx, it.first)] = divnum(one, divx);
129  }
130  }
131 
132  void bvisit(const Mul &x)
133  {
134  // won't handle cases like 2**((x+1)(x+2))
135  // needs `expand` to have been called
136  RCP<const Number> mulx = one, divx = one;
137 
138  if (x.get_coef()->is_negative())
139  mulx = minus_one;
140 
141  if (is_a<const Rational>(*x.get_coef()))
142  divx = down_cast<const Rational &>(*x.get_coef()).get_den();
143 
144  auto dict = x.get_dict();
145  gen_set[Mul::from_dict(mulx, std::move(dict))] = divnum(one, divx);
146  }
147 
148  void bvisit(const Number &x)
149  {
150  if (not is_a_Number(*pow(the_base, x.rcp_from_this()))) {
151  if (x.is_positive())
152  gen_set[one] = x.rcp_from_this_cast<const Number>();
153  else
154  gen_set[minus_one]
155  = mulnum(x.rcp_from_this_cast<const Number>(), minus_one);
156  }
157  }
158 
159  void bvisit(const Basic &x)
160  {
161  gen_set[x.rcp_from_this()] = one;
162  }
163 };
164 
165 umap_basic_num _find_gens_poly(const RCP<const Basic> &x)
166 {
168  return v.apply(*x);
169 }
170 
171 umap_basic_num _find_gens_poly_pow(const RCP<const Basic> &x,
172  const RCP<const Basic> &base)
173 {
174  PolyGeneratorVisitorPow v;
175  return v.apply(*x, base);
176 }
177 
178 } // namespace SymEngine
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< const T2 > rcp_from_this_cast() const
Get RCP<T2> pointer to self (it will cast the pointer to T2)
RCP< T > rcp_from_this()
Get RCP<T> pointer to self (it will cast the pointer to T)
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
virtual bool is_positive() const =0
RCP< const Basic > get_exp() const
Definition: pow.h:42
RCP< const Basic > get_base() const
Definition: pow.h:37
T end(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
RCP< const Number > mulnum(const RCP< const Number > &self, const RCP< const Number > &other)
Multiply self and other
Definition: number.h:93
RCP< const Number > divnum(const RCP< const Number > &self, const RCP< const Number > &other)
Divide self and other
Definition: number.h:99
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 Integer > lcm(const Integer &a, const Integer &b)
Least Common Multiple.
Definition: ntheory.cpp:50
RCP< const Basic > mul(const RCP< const Basic > &a, const RCP< const Basic > &b)
Multiplication.
Definition: mul.cpp:352