Loading...
Searching...
No Matches
SymEngine::ExpandVisitor Class Reference
+ Inheritance diagram for SymEngine::ExpandVisitor:
+ Collaboration diagram for SymEngine::ExpandVisitor:

Public Member Functions

 ExpandVisitor (bool deep_=true)
 
RCP< const Basicapply (const Basic &b)
 
void bvisit (const Basic &x)
 
void bvisit (const Number &x)
 
void bvisit (const Add &self)
 
void bvisit (const Mul &self)
 
void mul_expand_two (const RCP< const Basic > &a, const RCP< const Basic > &b)
 
void square_expand (umap_basic_num &base_dict)
 
void pow_expand (umap_basic_num &base_dict, unsigned n)
 
void bvisit (const Pow &self)
 
void _coef_dict_add_term (const RCP< const Number > &c, const RCP< const Basic > &term)
 

Private Member Functions

RCP< const Basicexpand_if_deep (const RCP< const Basic > &expr)
 

Private Attributes

umap_basic_num d_
 
RCP< const Numbercoeff = zero
 
RCP< const Numbermultiply = one
 
bool deep
 

Detailed Description

Definition at line 22 of file expand.cpp.

Constructor & Destructor Documentation

◆ ExpandVisitor()

SymEngine::ExpandVisitor::ExpandVisitor ( bool  deep_ = true)
inline

Definition at line 31 of file expand.cpp.

31: deep(deep_) {}

Member Function Documentation

◆ _coef_dict_add_term()

void SymEngine::ExpandVisitor::_coef_dict_add_term ( const RCP< const Number > &  c,
const RCP< const Basic > &  term 
)
inline

Definition at line 338 of file expand.cpp.

340 {
341 if (is_a_Number(*term)) {
342 iaddnum(outArg(coeff),
343 _mulnum(c, rcp_static_cast<const Number>(term)));
344 } else if (is_a<Add>(*term)) {
345 for (const auto &q : (down_cast<const Add &>(*term)).get_dict())
346 Add::dict_add_term(d_, _mulnum(q.second, c), q.first);
347 iaddnum(outArg(coeff),
348 _mulnum(down_cast<const Add &>(*term).get_coef(), c));
349 } else {
350 RCP<const Number> coef2;
351 RCP<const Basic> t;
352 Add::as_coef_term(term, outArg(coef2), outArg(t));
353 Add::dict_add_term(d_, _mulnum(c, coef2), t);
354 }
355 }
static void dict_add_term(umap_basic_num &d, const RCP< const Number > &coef, const RCP< const Basic > &t)
Adds a new term to the expression.
Definition: add.cpp:237
static void as_coef_term(const RCP< const Basic > &self, const Ptr< RCP< const Number > > &coef, const Ptr< RCP< const Basic > > &term)
Converts a Basic self into the form of coefficient * term.
Definition: add.cpp:306
bool is_a_Number(const Basic &b)
Definition: number.h:130

◆ apply()

RCP< const Basic > SymEngine::ExpandVisitor::apply ( const Basic b)
inline

Definition at line 32 of file expand.cpp.

33 {
34 b.accept(*this);
35 return Add::from_dict(coeff, std::move(d_));
36 }
static RCP< const Basic > from_dict(const RCP< const Number > &coef, umap_basic_num &&d)
Create an appropriate instance from dictionary quickly.
Definition: add.cpp:140
T move(T... args)

◆ bvisit() [1/5]

void SymEngine::ExpandVisitor::bvisit ( const Add self)
inline

Definition at line 49 of file expand.cpp.

50 {
51 RCP<const Number> _multiply = multiply;
52 iaddnum(outArg(coeff), _mulnum(multiply, self.get_coef()));
53 for (auto &p : self.get_dict()) {
54 multiply = _mulnum(_multiply, p.second);
55 if (deep) {
56 p.first->accept(*this);
57 } else {
58 Add::dict_add_term(d_, multiply, p.first);
59 }
60 }
61 multiply = _multiply;
62 }

◆ bvisit() [2/5]

void SymEngine::ExpandVisitor::bvisit ( const Basic x)
inline

Definition at line 38 of file expand.cpp.

39 {
40 Add::dict_add_term(d_, multiply, x.rcp_from_this());
41 }

◆ bvisit() [3/5]

void SymEngine::ExpandVisitor::bvisit ( const Mul self)
inline

Definition at line 64 of file expand.cpp.

65 {
66 for (auto &p : self.get_dict()) {
67 if (!is_a<Symbol>(*p.first)) {
68 RCP<const Basic> a, b;
69 self.as_two_terms(outArg(a), outArg(b));
70 a = expand_if_deep(a);
71 b = expand_if_deep(b);
72 mul_expand_two(a, b);
73 return;
74 }
75 }
76 this->_coef_dict_add_term(multiply, self.rcp_from_this());
77 }

◆ bvisit() [4/5]

void SymEngine::ExpandVisitor::bvisit ( const Number x)
inline

Definition at line 43 of file expand.cpp.

44 {
45 iaddnum(outArg(coeff),
46 _mulnum(multiply, x.rcp_from_this_cast<const Number>()));
47 }

◆ bvisit() [5/5]

void SymEngine::ExpandVisitor::bvisit ( const Pow self)
inline

Definition at line 289 of file expand.cpp.

290 {
291 RCP<const Basic> _base = expand_if_deep(self.get_base());
292 // TODO add all types of polys
293 if (is_a<Integer>(*self.get_exp()) && is_a<UExprPoly>(*_base)) {
294 unsigned q = numeric_cast<unsigned>(
295 down_cast<const Integer &>(*self.get_exp()).as_uint());
296 RCP<const UExprPoly> p = rcp_static_cast<const UExprPoly>(_base);
297 RCP<const UExprPoly> r = pow_upoly(*p, q);
298 _coef_dict_add_term(multiply, r);
299 return;
300 }
301 if (is_a<Integer>(*self.get_exp()) && is_a<UIntPoly>(*_base)) {
302 unsigned q = numeric_cast<unsigned>(
303 down_cast<const Integer &>(*self.get_exp()).as_uint());
304 RCP<const UIntPoly> p = rcp_static_cast<const UIntPoly>(_base);
305 RCP<const UIntPoly> r = pow_upoly(*p, q);
306 _coef_dict_add_term(multiply, r);
307 return;
308 }
309
310 if (!is_a<Integer>(*self.get_exp()) || !is_a<Add>(*_base)) {
311 if (neq(*_base, *self.get_base())) {
312 Add::dict_add_term(d_, multiply, pow(_base, self.get_exp()));
313 } else {
314 Add::dict_add_term(d_, multiply, self.rcp_from_this());
315 }
316 return;
317 }
318
319 integer_class n
320 = down_cast<const Integer &>(*self.get_exp()).as_integer_class();
321 if (n < 0)
322 return _coef_dict_add_term(
323 multiply, div(one, expand_if_deep(pow(_base, integer(-n)))));
324 RCP<const Add> base = rcp_static_cast<const Add>(_base);
325 umap_basic_num base_dict = base->get_dict();
326 if (!(base->get_coef()->is_zero())) {
327 // Add the numerical coefficient into the dictionary. This
328 // allows a little bit easier treatment below.
329 insert(base_dict, base->get_coef(), one);
330 } else
331 iaddnum(outArg(coeff), base->get_coef());
332 if (n == 2)
333 return square_expand(base_dict);
334 else
335 return pow_expand(base_dict, numeric_cast<unsigned>(mp_get_ui(n)));
336 }
RCP< const Basic > div(const RCP< const Basic > &a, const RCP< const Basic > &b)
Division.
Definition: mul.cpp:431
void insert(T1 &m, const T2 &first, const T3 &second)
Definition: dict.h:83
bool neq(const Basic &a, const Basic &b)
Checks inequality for a and b
Definition: basic-inl.h:29
std::enable_if< std::is_integral< T >::value, RCP< constInteger > >::type integer(T i)
Definition: integer.h:197
T pow(T... args)

◆ expand_if_deep()

RCP< const Basic > SymEngine::ExpandVisitor::expand_if_deep ( const RCP< const Basic > &  expr)
inlineprivate

Definition at line 358 of file expand.cpp.

359 {
360 if (deep) {
361 return expand(expr);
362 } else {
363 return expr;
364 }
365 }
RCP< const Basic > expand(const RCP< const Basic > &self, bool deep=true)
Expands self
Definition: expand.cpp:369

◆ mul_expand_two()

void SymEngine::ExpandVisitor::mul_expand_two ( const RCP< const Basic > &  a,
const RCP< const Basic > &  b 
)
inline

Definition at line 79 of file expand.cpp.

80 {
81 // Both a and b are assumed to be expanded
82 if (is_a<Add>(*a) && is_a<Add>(*b)) {
83 iaddnum(outArg(coeff),
84 _mulnum(multiply,
85 _mulnum(down_cast<const Add &>(*a).get_coef(),
86 down_cast<const Add &>(*b).get_coef())));
87// Improves (x+1)**3*(x+2)**3*...(x+350)**3 expansion from 0.97s to 0.93s:
88#if defined(HAVE_SYMENGINE_RESERVE)
89 d_.reserve(d_.size()
90 + (down_cast<const Add &>(*a)).get_dict().size()
91 * (down_cast<const Add &>(*b)).get_dict().size());
92#endif
93 // Expand dicts first:
94 for (auto &p : (down_cast<const Add &>(*a)).get_dict()) {
95 RCP<const Number> temp = _mulnum(p.second, multiply);
96 for (auto &q : (down_cast<const Add &>(*b)).get_dict()) {
97 // The main bottleneck here is the mul(p.first, q.first)
98 // command
99 RCP<const Basic> term = mul(p.first, q.first);
100 if (is_a_Number(*term)) {
101 iaddnum(outArg(coeff),
102 _mulnum(_mulnum(temp, q.second),
103 rcp_static_cast<const Number>(term)));
104 } else {
105 if (is_a<Mul>(*term)
106 && !(down_cast<const Mul &>(*term)
107 .get_coef()
108 ->is_one())) {
109 // Tidy up things like {2x: 3} -> {x: 6}
110 RCP<const Number> coef2
111 = down_cast<const Mul &>(*term).get_coef();
112 // We make a copy of the dict_:
113 map_basic_basic d2
114 = down_cast<const Mul &>(*term).get_dict();
115 term = Mul::from_dict(one, std::move(d2));
117 d_, _mulnum(_mulnum(temp, q.second), coef2),
118 term);
119 } else {
120 Add::dict_add_term(d_, _mulnum(temp, q.second),
121 term);
122 }
123 }
124 }
126 d_, _mulnum(down_cast<const Add &>(*b).get_coef(), temp),
127 p.first);
128 }
129 // Handle the coefficient of "a":
130 RCP<const Number> temp
131 = _mulnum(down_cast<const Add &>(*a).get_coef(), multiply);
132 for (auto &q : (down_cast<const Add &>(*b)).get_dict()) {
133 Add::dict_add_term(d_, _mulnum(temp, q.second), q.first);
134 }
135 return;
136 } else if (is_a<Add>(*a)) {
137 mul_expand_two(b, a);
138 return;
139 } else if (is_a<Add>(*b)) {
140 RCP<const Number> a_coef;
141 RCP<const Basic> a_term;
142 Add::as_coef_term(a, outArg(a_coef), outArg(a_term));
143 _imulnum(outArg(a_coef), multiply);
144
145#if defined(HAVE_SYMENGINE_RESERVE)
146 d_.reserve(d_.size()
147 + (down_cast<const Add &>(*b)).get_dict().size());
148#endif
149 for (auto &q : (down_cast<const Add &>(*b)).get_dict()) {
150 RCP<const Basic> term = mul(a_term, q.first);
151 if (is_a_Number(*term)) {
152 iaddnum(outArg(coeff),
153 _mulnum(_mulnum(q.second, a_coef),
154 rcp_static_cast<const Number>(term)));
155 } else {
156 if (is_a<Mul>(*term)
157 && !(down_cast<const Mul &>(*term)
158 .get_coef()
159 ->is_one())) {
160 // Tidy up things like {2x: 3} -> {x: 6}
161 RCP<const Number> coef2
162 = down_cast<const Mul &>(*term).get_coef();
163 // We make a copy of the dict_:
164 map_basic_basic d2
165 = down_cast<const Mul &>(*term).get_dict();
166 term = Mul::from_dict(one, std::move(d2));
168 d_, _mulnum(_mulnum(q.second, a_coef), coef2),
169 term);
170 } else {
171 // TODO: check if it's a Add
172 Add::dict_add_term(d_, _mulnum(a_coef, q.second), term);
173 }
174 }
175 }
176 if (eq(*a_term, *one)) {
177 iaddnum(outArg(coeff),
178 _mulnum(down_cast<const Add &>(*b).get_coef(), a_coef));
179 } else {
181 d_, _mulnum(down_cast<const Add &>(*b).get_coef(), a_coef),
182 a_term);
183 }
184 return;
185 }
186 _coef_dict_add_term(multiply, mul(a, b));
187 }
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
bool eq(const Basic &a, const Basic &b)
Checks equality for a and b
Definition: basic-inl.h:21
RCP< const Basic > mul(const RCP< const Basic > &a, const RCP< const Basic > &b)
Multiplication.
Definition: mul.cpp:352
T reserve(T... args)
T size(T... args)

◆ pow_expand()

void SymEngine::ExpandVisitor::pow_expand ( umap_basic_num base_dict,
unsigned  n 
)
inline

Definition at line 213 of file expand.cpp.

214 {
215 map_vec_mpz r;
216 unsigned m = numeric_cast<unsigned>(base_dict.size());
217 multinomial_coefficients_mpz(m, n, r);
218// This speeds up overall expansion. For example for the benchmark
219// (y + x + z + w)**60 it improves the timing from 135ms to 124ms.
220#if defined(HAVE_SYMENGINE_RESERVE)
221 d_.reserve(d_.size() + 2 * r.size());
222#endif
223 for (auto &p : r) {
224 auto power = p.first.begin();
225 auto i2 = base_dict.begin();
226 map_basic_basic d;
227 RCP<const Number> overall_coeff = one;
228 for (; power != p.first.end(); ++power, ++i2) {
229 if (*power > 0) {
230 RCP<const Integer> exp = integer(std::move(*power));
231 RCP<const Basic> base = i2->first;
232 if (is_a<Integer>(*base)) {
233 _imulnum(outArg(overall_coeff),
234 rcp_static_cast<const Number>(
235 down_cast<const Integer &>(*base).powint(
236 *exp)));
237 } else if (is_a<Symbol>(*base)) {
238 Mul::dict_add_term(d, exp, base);
239 } else {
240 RCP<const Basic> exp2, t, tmp;
241 tmp = pow(base, exp);
242 if (is_a<Mul>(*tmp)) {
243 for (auto &p :
244 (down_cast<const Mul &>(*tmp)).get_dict()) {
245 Mul::dict_add_term_new(outArg(overall_coeff), d,
246 p.second, p.first);
247 }
248 _imulnum(outArg(overall_coeff),
249 (down_cast<const Mul &>(*tmp)).get_coef());
250 } else if (is_a_Number(*tmp)) {
251 _imulnum(outArg(overall_coeff),
252 rcp_static_cast<const Number>(tmp));
253 } else {
254 Mul::as_base_exp(tmp, outArg(exp2), outArg(t));
255 Mul::dict_add_term_new(outArg(overall_coeff), d,
256 exp2, t);
257 }
258 }
259 if (!(i2->second->is_one())) {
260 _imulnum(outArg(overall_coeff),
261 pownum(i2->second,
262 rcp_static_cast<const Number>(exp)));
263 }
264 }
265 }
266 RCP<const Basic> term = Mul::from_dict(overall_coeff, std::move(d));
267 RCP<const Number> coef2 = integer(p.second);
268 if (is_a_Number(*term)) {
269 iaddnum(outArg(coeff),
270 _mulnum(_mulnum(multiply,
271 rcp_static_cast<const Number>(term)),
272 coef2));
273 } else {
274 if (is_a<Mul>(*term)
275 && !(down_cast<const Mul &>(*term).get_coef()->is_one())) {
276 // Tidy up things like {2x: 3} -> {x: 6}
277 _imulnum(outArg(coef2),
278 down_cast<const Mul &>(*term).get_coef());
279 // We make a copy of the dict_:
280 map_basic_basic d2
281 = down_cast<const Mul &>(*term).get_dict();
282 term = Mul::from_dict(one, std::move(d2));
283 }
284 Add::dict_add_term(d_, _mulnum(multiply, coef2), term);
285 }
286 }
287 }
static void as_base_exp(const RCP< const Basic > &self, const Ptr< RCP< const Basic > > &exp, const Ptr< RCP< const Basic > > &base)
Convert to a base and exponent form.
Definition: mul.cpp:320
static void dict_add_term(map_basic_basic &d, const RCP< const Basic > &exp, const RCP< const Basic > &t)
Add terms to dict.
Definition: mul.cpp:150
T exp2(T... args)
RCP< const Number > pownum(const RCP< const Number > &self, const RCP< const Number > &other)
Raise self to power other
Definition: number.h:105
RCP< const Basic > exp(const RCP< const Basic > &x)
Returns the natural exponential function E**x = pow(E, x)
Definition: pow.cpp:271

◆ square_expand()

void SymEngine::ExpandVisitor::square_expand ( umap_basic_num base_dict)
inline

Definition at line 189 of file expand.cpp.

190 {
191 auto m = base_dict.size();
192#if defined(HAVE_SYMENGINE_RESERVE)
193 d_.reserve(d_.size() + m * (m + 1) / 2);
194#endif
195 RCP<const Basic> t;
196 RCP<const Number> coef, two = integer(2);
197 for (auto p = base_dict.begin(); p != base_dict.end(); ++p) {
198 for (auto q = p; q != base_dict.end(); ++q) {
199 if (q == p) {
200 _coef_dict_add_term(
201 _mulnum(mulnum((*p).second, (*p).second), multiply),
202 pow((*p).first, two));
203 } else {
204 _coef_dict_add_term(
205 _mulnum(multiply, _mulnum((*p).second,
206 _mulnum((*q).second, two))),
207 mul((*q).first, (*p).first));
208 }
209 }
210 }
211 }
RCP< const Number > mulnum(const RCP< const Number > &self, const RCP< const Number > &other)
Multiply self and other
Definition: number.h:93

Field Documentation

◆ coeff

RCP<const Number> SymEngine::ExpandVisitor::coeff = zero
private

Definition at line 26 of file expand.cpp.

◆ d_

umap_basic_num SymEngine::ExpandVisitor::d_
private

Definition at line 25 of file expand.cpp.

◆ deep

bool SymEngine::ExpandVisitor::deep
private

Definition at line 28 of file expand.cpp.

◆ multiply

RCP<const Number> SymEngine::ExpandVisitor::multiply = one
private

Definition at line 27 of file expand.cpp.


The documentation for this class was generated from the following file: