subs.h
1 #ifndef SYMENGINE_SUBS_H
2 #define SYMENGINE_SUBS_H
3 
4 #include <symengine/logic.h>
5 #include <symengine/visitor.h>
6 
7 namespace SymEngine
8 {
9 // xreplace replaces subtrees of a node in the expression tree
10 // with a new subtree
11 SYMENGINE_EXPORT
12 RCP<const Basic> xreplace(const RCP<const Basic> &x,
13  const map_basic_basic &subs_dict, bool cache = true);
14 // subs substitutes expressions similar to xreplace, but keeps
15 // the mathematical equivalence for derivatives and subs
16 SYMENGINE_EXPORT
17 RCP<const Basic> subs(const RCP<const Basic> &x,
18  const map_basic_basic &subs_dict, bool cache = true);
19 // port of sympy.physics.mechanics.msubs where f'(x) and f(x)
20 // are considered independent
21 SYMENGINE_EXPORT
22 RCP<const Basic> msubs(const RCP<const Basic> &x,
23  const map_basic_basic &subs_dict, bool cache = true);
24 // port of sympy's subs where subs inside derivatives are done
25 SYMENGINE_EXPORT
26 RCP<const Basic> ssubs(const RCP<const Basic> &x,
27  const map_basic_basic &subs_dict, bool cache = true);
28 
29 class XReplaceVisitor : public BaseVisitor<XReplaceVisitor>
30 {
31 
32 protected:
33  RCP<const Basic> result_;
34  const map_basic_basic &subs_dict_;
35  map_basic_basic visited;
36  bool cache;
37 
38 public:
39  XReplaceVisitor(const map_basic_basic &subs_dict, bool cache = true)
40  : subs_dict_(subs_dict), cache(cache)
41  {
42  if (cache) {
43  visited = subs_dict;
44  }
45  }
46  // TODO : Polynomials, Series, Sets
47  void bvisit(const Basic &x)
48  {
49  result_ = x.rcp_from_this();
50  }
51 
52  void bvisit(const Add &x)
53  {
54  SymEngine::umap_basic_num d;
55  RCP<const Number> coef;
56 
57  auto it = subs_dict_.find(x.get_coef());
58  if (it != subs_dict_.end()) {
59  coef = zero;
60  Add::coef_dict_add_term(outArg(coef), d, one, it->second);
61  } else {
62  coef = x.get_coef();
63  }
64 
65  for (const auto &p : x.get_dict()) {
66  auto it
67  = subs_dict_.find(Add::from_dict(zero, {{p.first, p.second}}));
68  if (it != subs_dict_.end()) {
69  Add::coef_dict_add_term(outArg(coef), d, one, it->second);
70  } else {
71  it = subs_dict_.find(p.second);
72  if (it != subs_dict_.end()) {
73  Add::coef_dict_add_term(outArg(coef), d, one,
74  mul(it->second, apply(p.first)));
75  } else {
76  Add::coef_dict_add_term(outArg(coef), d, p.second,
77  apply(p.first));
78  }
79  }
80  }
81  result_ = Add::from_dict(coef, std::move(d));
82  }
83 
84  void bvisit(const Mul &x)
85  {
86  RCP<const Number> coef = one;
87  map_basic_basic d;
88  for (const auto &p : x.get_dict()) {
89  RCP<const Basic> factor_old;
90  if (eq(*p.second, *one)) {
91  factor_old = p.first;
92  } else {
93  factor_old = make_rcp<Pow>(p.first, p.second);
94  }
95  RCP<const Basic> factor = apply(factor_old);
96  if (factor == factor_old) {
97  // TODO: Check if Mul::dict_add_term is enough
98  Mul::dict_add_term_new(outArg(coef), d, p.second, p.first);
99  } else if (is_a_Number(*factor)) {
100  imulnum(outArg(coef), rcp_static_cast<const Number>(factor));
101  } else if (is_a<Mul>(*factor)) {
102  RCP<const Mul> tmp = rcp_static_cast<const Mul>(factor);
103  imulnum(outArg(coef), tmp->get_coef());
104  for (const auto &q : tmp->get_dict()) {
105  Mul::dict_add_term_new(outArg(coef), d, q.second, q.first);
106  }
107  } else {
108  RCP<const Basic> exp, t;
109  Mul::as_base_exp(factor, outArg(exp), outArg(t));
110  Mul::dict_add_term_new(outArg(coef), d, exp, t);
111  }
112  }
113 
114  // Replace the coefficient
115  RCP<const Basic> factor = apply(x.get_coef());
116  if (is_a_Number(*factor)) {
117  imulnum(outArg(coef), rcp_static_cast<const Number>(factor));
118  } else if (is_a<Mul>(*factor)) {
119  RCP<const Mul> tmp = rcp_static_cast<const Mul>(factor);
120  imulnum(outArg(coef), tmp->get_coef());
121  for (const auto &q : tmp->get_dict()) {
122  Mul::dict_add_term_new(outArg(coef), d, q.second, q.first);
123  }
124  } else {
125  RCP<const Basic> exp, t;
126  Mul::as_base_exp(factor, outArg(exp), outArg(t));
127  Mul::dict_add_term_new(outArg(coef), d, exp, t);
128  }
129  result_ = Mul::from_dict(coef, std::move(d));
130  }
131 
132  void bvisit(const Pow &x)
133  {
134  RCP<const Basic> base_new = apply(x.get_base());
135  RCP<const Basic> exp_new = apply(x.get_exp());
136  if (base_new == x.get_base() and exp_new == x.get_exp()) {
137  result_ = x.rcp_from_this();
138  } else {
139  result_ = pow(base_new, exp_new);
140  }
141  }
142 
143  void bvisit(const OneArgFunction &x)
144  {
145  apply(x.get_arg());
146  if (result_ == x.get_arg()) {
147  result_ = x.rcp_from_this();
148  } else {
149  result_ = x.create(result_);
150  }
151  }
152 
153  template <class T>
154  void bvisit(const TwoArgBasic<T> &x)
155  {
156  RCP<const Basic> a = apply(x.get_arg1());
157  RCP<const Basic> b = apply(x.get_arg2());
158  if (a == x.get_arg1() and b == x.get_arg2())
159  result_ = x.rcp_from_this();
160  else
161  result_ = x.create(a, b);
162  }
163 
164  void bvisit(const MultiArgFunction &x)
165  {
166  vec_basic v = x.get_args();
167  for (auto &elem : v) {
168  elem = apply(elem);
169  }
170  result_ = x.create(v);
171  }
172 
173  void bvisit(const FunctionSymbol &x)
174  {
175  vec_basic v = x.get_args();
176  for (auto &elem : v) {
177  elem = apply(elem);
178  }
179  result_ = x.create(v);
180  }
181 
182  void bvisit(const Contains &x)
183  {
184  RCP<const Basic> a = apply(x.get_expr());
185  auto c = apply(x.get_set());
186  if (not is_a_Set(*c))
187  throw SymEngineException("expected an object of type Set");
188  RCP<const Set> b = rcp_static_cast<const Set>(c);
189  if (a == x.get_expr() and b == x.get_set())
190  result_ = x.rcp_from_this();
191  else
192  result_ = x.create(a, b);
193  }
194 
195  void bvisit(const And &x)
196  {
197  set_boolean v;
198  for (const auto &elem : x.get_container()) {
199  auto a = apply(elem);
200  if (not is_a_Boolean(*a))
201  throw SymEngineException("expected an object of type Boolean");
202  v.insert(rcp_static_cast<const Boolean>(a));
203  }
204  result_ = logical_and(v);
205  }
206 
207  void bvisit(const Or &x)
208  {
209  set_boolean v;
210  for (const auto &elem : x.get_container()) {
211  auto a = apply(elem);
212  if (not is_a_Boolean(*a))
213  throw SymEngineException("expected an object of type Boolean");
214  v.insert(rcp_static_cast<const Boolean>(a));
215  }
216  result_ = logical_or(v);
217  }
218 
219  void bvisit(const Not &x)
220  {
221  RCP<const Basic> a = apply(x.get_arg());
222  if (not is_a_Boolean(*a))
223  throw SymEngineException("expected an object of type Boolean");
224  result_ = logical_not(rcp_static_cast<const Boolean>(a));
225  }
226 
227  void bvisit(const Xor &x)
228  {
229  vec_boolean v;
230  for (const auto &elem : x.get_container()) {
231  auto a = apply(elem);
232  if (not is_a_Boolean(*a))
233  throw SymEngineException("expected an object of type Boolean");
234  v.push_back(rcp_static_cast<const Boolean>(a));
235  }
236  result_ = logical_xor(v);
237  }
238 
239  void bvisit(const FiniteSet &x)
240  {
241  set_basic v;
242  for (const auto &elem : x.get_container()) {
243  v.insert(apply(elem));
244  }
245  result_ = x.create(v);
246  }
247 
248  void bvisit(const ImageSet &x)
249  {
250  RCP<const Basic> s = apply(x.get_symbol());
251  RCP<const Basic> expr = apply(x.get_expr());
252  auto bs_ = apply(x.get_baseset());
253  if (not is_a_Set(*bs_))
254  throw SymEngineException("expected an object of type Set");
255  RCP<const Set> bs = rcp_static_cast<const Set>(bs_);
256  if (s == x.get_symbol() and expr == x.get_expr()
257  and bs == x.get_baseset()) {
258  result_ = x.rcp_from_this();
259  } else {
260  result_ = x.create(s, expr, bs);
261  }
262  }
263 
264  void bvisit(const Union &x)
265  {
266  set_set v;
267  for (const auto &elem : x.get_container()) {
268  auto a = apply(elem);
269  if (not is_a_Set(*a))
270  throw SymEngineException("expected an object of type Set");
271  v.insert(rcp_static_cast<const Set>(a));
272  }
273  result_ = x.create(v);
274  }
275 
276  void bvisit(const Piecewise &pw)
277  {
278  PiecewiseVec pwv;
279  pwv.reserve(pw.get_vec().size());
280  for (const auto &expr_pred : pw.get_vec()) {
281  const auto expr = apply(*expr_pred.first);
282  const auto pred = apply(*expr_pred.second);
283  pwv.emplace_back(
284  std::make_pair(expr, rcp_static_cast<const Boolean>(pred)));
285  }
286  result_ = piecewise(std::move(pwv));
287  }
288 
289  void bvisit(const Derivative &x)
290  {
291  auto expr = apply(x.get_arg());
292  for (const auto &sym : x.get_symbols()) {
293  auto s = apply(sym);
294  if (not is_a<Symbol>(*s)) {
295  throw SymEngineException("expected an object of type Symbol");
296  }
297  expr = expr->diff(rcp_static_cast<const Symbol>(s));
298  }
299  result_ = expr;
300  }
301 
302  void bvisit(const Subs &x)
303  {
304  auto expr = apply(x.get_arg());
305  map_basic_basic new_subs_dict;
306  for (const auto &sym : x.get_dict()) {
307  insert(new_subs_dict, apply(sym.first), apply(sym.second));
308  }
309  result_ = subs(expr, new_subs_dict);
310  }
311 
312  void bvisit(const ComplexBase &x)
313  {
314  auto it = subs_dict_.find(I);
315  if (it != subs_dict_.end()) {
316  result_ = add(apply(x.real_part()),
317  mul(apply(x.imaginary_part()), it->second));
318  } else {
319  result_ = x.rcp_from_this();
320  }
321  }
322 
323  RCP<const Basic> apply(const Basic &x)
324  {
325  return apply(x.rcp_from_this());
326  }
327 
328  RCP<const Basic> apply(const RCP<const Basic> &x)
329  {
330  if (cache) {
331  auto it = visited.find(x);
332  if (it != visited.end()) {
333  result_ = it->second;
334  } else {
335  x->accept(*this);
336  insert(visited, x, result_);
337  }
338  } else {
339  auto it = subs_dict_.find(x);
340  if (it != subs_dict_.end()) {
341  result_ = it->second;
342  } else {
343  x->accept(*this);
344  }
345  }
346  return result_;
347  }
348 };
349 
351 inline RCP<const Basic> xreplace(const RCP<const Basic> &x,
352  const map_basic_basic &subs_dict, bool cache)
353 {
354  XReplaceVisitor s(subs_dict, cache);
355  return s.apply(x);
356 }
357 
358 class SubsVisitor : public BaseVisitor<SubsVisitor, XReplaceVisitor>
359 {
360 public:
361  using XReplaceVisitor::bvisit;
362 
363  SubsVisitor(const map_basic_basic &subs_dict_, bool cache = true)
364  : BaseVisitor<SubsVisitor, XReplaceVisitor>(subs_dict_, cache)
365  {
366  }
367 
368  void bvisit(const Pow &x)
369  {
370  RCP<const Basic> base_new = apply(x.get_base());
371  RCP<const Basic> exp_new = apply(x.get_exp());
372  if (subs_dict_.size() == 1 and is_a<Pow>(*((*subs_dict_.begin()).first))
373  and not is_a<Add>(
374  *down_cast<const Pow &>(*(*subs_dict_.begin()).first)
375  .get_exp())) {
376  auto &subs_first
377  = down_cast<const Pow &>(*(*subs_dict_.begin()).first);
378  if (eq(*subs_first.get_base(), *base_new)) {
379  auto newexpo = div(exp_new, subs_first.get_exp());
380  if (is_a_Number(*newexpo) or is_a<Constant>(*newexpo)) {
381  result_ = pow((*subs_dict_.begin()).second, newexpo);
382  return;
383  }
384  }
385  }
386  if (base_new == x.get_base() and exp_new == x.get_exp()) {
387  result_ = x.rcp_from_this();
388  } else {
389  result_ = pow(base_new, exp_new);
390  }
391  }
392 
393  void bvisit(const Derivative &x)
394  {
395  RCP<const Symbol> s;
396  map_basic_basic m, n;
397  bool subs;
398 
399  for (const auto &p : subs_dict_) {
400  // If the derivative arg is to be replaced in its entirety, allow
401  // it.
402  if (eq(*x.get_arg(), *p.first)) {
403  RCP<const Basic> t = p.second;
404  for (auto &sym : x.get_symbols()) {
405  if (not is_a<Symbol>(*sym)) {
406  throw SymEngineException("Error, expected a Symbol.");
407  }
408  t = t->diff(rcp_static_cast<const Symbol>(sym));
409  }
410  result_ = t;
411  return;
412  }
413  }
414  for (const auto &p : subs_dict_) {
415  subs = true;
416  if (eq(*x.get_arg()->subs({{p.first, p.second}}), *x.get_arg()))
417  continue;
418 
419  // If p.first and p.second are symbols and arg_ is
420  // independent of p.second, p.first can be replaced
421  if (is_a<Symbol>(*p.first) and is_a<Symbol>(*p.second)
422  and eq(
423  *x.get_arg()->diff(rcp_static_cast<const Symbol>(p.second)),
424  *zero)) {
425  insert(n, p.first, p.second);
426  continue;
427  }
428  for (const auto &d : x.get_symbols()) {
429  if (is_a<Symbol>(*d)) {
430  s = rcp_static_cast<const Symbol>(d);
431  // If p.first or p.second has non zero derivates wrt to s
432  // p.first cannot be replaced
433  if (neq(*zero, *(p.first->diff(s)))
434  || neq(*zero, *(p.second->diff(s)))) {
435  subs = false;
436  break;
437  }
438  } else {
439  result_
440  = make_rcp<const Subs>(x.rcp_from_this(), subs_dict_);
441  return;
442  }
443  }
444  if (subs) {
445  insert(n, p.first, p.second);
446  } else {
447  insert(m, p.first, p.second);
448  }
449  }
450  auto t = x.get_arg()->subs(n);
451  for (auto &p : x.get_symbols()) {
452  auto t2 = p->subs(n);
453  if (not is_a<Symbol>(*t2)) {
454  throw SymEngineException("Error, expected a Symbol.");
455  }
456  t = t->diff(rcp_static_cast<const Symbol>(t2));
457  }
458  if (m.empty()) {
459  result_ = t;
460  } else {
461  result_ = make_rcp<const Subs>(t, m);
462  }
463  }
464 
465  void bvisit(const Subs &x)
466  {
467  map_basic_basic m, n;
468  for (const auto &p : subs_dict_) {
469  bool found = false;
470  for (const auto &s : x.get_dict()) {
471  if (neq(*(s.first->subs({{p.first, p.second}})), *(s.first))) {
472  found = true;
473  break;
474  }
475  }
476  // If p.first is not replaced in arg_ by dict_,
477  // store p.first in n to replace in arg_
478  if (not found) {
479  insert(n, p.first, p.second);
480  }
481  }
482  for (const auto &s : x.get_dict()) {
483  insert(m, s.first, apply(s.second));
484  }
485  RCP<const Basic> presub = x.get_arg()->subs(n);
486  if (is_a<Subs>(*presub)) {
487  for (auto &q : down_cast<const Subs &>(*presub).get_dict()) {
488  insert(m, q.first, q.second);
489  }
490  result_ = down_cast<const Subs &>(*presub).get_arg()->subs(m);
491  } else {
492  result_ = presub->subs(m);
493  }
494  }
495 };
496 
497 class MSubsVisitor : public BaseVisitor<MSubsVisitor, XReplaceVisitor>
498 {
499 public:
500  using XReplaceVisitor::bvisit;
501 
502  MSubsVisitor(const map_basic_basic &d, bool cache = true)
504  {
505  }
506 
507  void bvisit(const Derivative &x)
508  {
509  result_ = x.rcp_from_this();
510  }
511 
512  void bvisit(const Subs &x)
513  {
514  map_basic_basic m = x.get_dict();
515  for (const auto &p : subs_dict_) {
516  m[p.first] = p.second;
517  }
518  result_ = msubs(x.get_arg(), m);
519  }
520 };
521 
522 class SSubsVisitor : public BaseVisitor<SSubsVisitor, SubsVisitor>
523 {
524 public:
525  using XReplaceVisitor::bvisit;
526 
527  SSubsVisitor(const map_basic_basic &d, bool cache = true)
529  {
530  }
531 
532  void bvisit(const Derivative &x)
533  {
534  apply(x.get_arg());
535  auto t = result_;
536  multiset_basic m;
537  for (auto &p : x.get_symbols()) {
538  apply(p);
539  m.insert(result_);
540  }
541  result_ = Derivative::create(t, m);
542  }
543 
544  void bvisit(const Subs &x)
545  {
546  map_basic_basic m = x.get_dict();
547  for (const auto &p : subs_dict_) {
548  m[p.first] = p.second;
549  }
550  result_ = ssubs(x.get_arg(), m);
551  }
552 };
553 
555 inline RCP<const Basic> msubs(const RCP<const Basic> &x,
556  const map_basic_basic &subs_dict, bool cache)
557 {
558  MSubsVisitor s(subs_dict, cache);
559  return s.apply(x);
560 }
561 
563 inline RCP<const Basic> ssubs(const RCP<const Basic> &x,
564  const map_basic_basic &subs_dict, bool cache)
565 {
566  SSubsVisitor s(subs_dict, cache);
567  return s.apply(x);
568 }
569 
570 inline RCP<const Basic> subs(const RCP<const Basic> &x,
571  const map_basic_basic &subs_dict, bool cache)
572 {
573  SubsVisitor b(subs_dict, cache);
574  return b.apply(x);
575 }
576 
577 } // namespace SymEngine
578 
579 #endif // SYMENGINE_SUBS_H
The base class for representing addition in symbolic expressions.
Definition: add.h:27
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
static void coef_dict_add_term(const Ptr< RCP< const Number >> &coef, umap_basic_num &d, const RCP< const Number > &c, const RCP< const Basic > &term)
Updates the numerical coefficient and the dictionary.
Definition: add.cpp:261
const RCP< const Number > & get_coef() const
Definition: add.h:142
The lowest unit of symbolic representation.
Definition: basic.h:97
RCP< const Basic > subs(const map_basic_basic &subs_dict) const
Substitutes 'subs_dict' into 'self'.
Definition: basic.cpp:90
ComplexBase Class for deriving all complex classes.
Definition: complex.h:16
RCP< T > rcp_from_this()
Get RCP<T> pointer to self (it will cast the pointer to T)
RCP< const Basic > create(const vec_basic &x) const override
Method to construct classes with canonicalization.
Definition: functions.cpp:1903
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 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 RCP< const Basic > create(const vec_basic &v) const =0
Method to construct classes with canonicalization.
vec_basic get_args() const override
Returns the list of arguments.
Definition: functions.h:159
virtual RCP< const Basic > create(const RCP< const Basic > &arg) const =0
Method to construct classes with canonicalization.
RCP< const Basic > get_arg() const
Definition: functions.h:36
RCP< const Basic > get_exp() const
Definition: pow.h:42
RCP< const Basic > get_base() const
Definition: pow.h:37
virtual RCP< const Basic > create(const RCP< const Basic > &a, const RCP< const Basic > &b) const =0
Method to construct classes with canonicalization.
RCP< const Basic > get_arg1() const
Definition: functions.h:91
RCP< const Basic > get_arg2() const
Definition: functions.h:96
Main namespace for SymEngine package.
Definition: add.cpp:19
bool is_a_Number(const Basic &b)
Definition: number.h:130
RCP< const Basic > add(const RCP< const Basic > &a, const RCP< const Basic > &b)
Adds two objects (safely).
Definition: add.cpp:425
int factor(const Ptr< RCP< const Integer >> &f, const Integer &n, double B1)
Definition: ntheory.cpp:371
RCP< const Basic > mul(const RCP< const Basic > &a, const RCP< const Basic > &b)
Multiplication.
Definition: mul.cpp:352
SYMENGINE_EXPORT RCP< const Basic > msubs(const RCP< const Basic > &x, const map_basic_basic &subs_dict, bool cache=true)
Subs which treat f(t) and Derivative(f(t), t) as separate variables.
Definition: subs.h:555
RCP< const Basic > exp(const RCP< const Basic > &x)
Returns the natural exponential function E**x = pow(E, x)
Definition: pow.cpp:271
void insert(T1 &m, const T2 &first, const T3 &second)
Definition: dict.h:83
bool eq(const Basic &a, const Basic &b)
Checks equality for a and b
Definition: basic-inl.h:21
bool neq(const Basic &a, const Basic &b)
Checks inequality for a and b
Definition: basic-inl.h:29
RCP< const Basic > div(const RCP< const Basic > &a, const RCP< const Basic > &b)
Division.
Definition: mul.cpp:431
SYMENGINE_EXPORT RCP< const Basic > xreplace(const RCP< const Basic > &x, const map_basic_basic &subs_dict, bool cache=true)
Mappings in the subs_dict are applied to the expression tree of x
Definition: subs.h:351
SYMENGINE_EXPORT RCP< const Basic > ssubs(const RCP< const Basic > &x, const map_basic_basic &subs_dict, bool cache=true)
SymPy compatible subs.
Definition: subs.h:563