numer_denom.cpp
1 #include <symengine/visitor.h>
2 
3 namespace SymEngine
4 {
5 
6 class NumerDenomVisitor : public BaseVisitor<NumerDenomVisitor>
7 {
8 private:
9  Ptr<RCP<const Basic>> numer_, denom_;
10 
11 public:
12  NumerDenomVisitor(const Ptr<RCP<const Basic>> &numer,
13  const Ptr<RCP<const Basic>> &denom)
14  : numer_{numer}, denom_{denom}
15  {
16  }
17 
18  void apply(const Basic &b)
19  {
20  b.accept(*this);
21  }
22 
23  void bvisit(const Mul &x)
24  {
25  RCP<const Basic> curr = one;
26  RCP<const Basic> arg_num, arg_den, t;
27 
28  for (const auto &arg : x.get_args()) {
29  as_numer_denom(arg, outArg(arg_num), outArg(arg_den));
30  curr = div(mul(curr, arg_num), arg_den);
31  }
32 
33  if (not is_a<Mul>(*curr)) {
34  apply(*curr);
35  return;
36  }
37 
38  RCP<const Basic> curr_num = one, curr_den = one;
39  for (const auto &arg : curr->get_args()) {
40  as_numer_denom(arg, outArg(arg_num), outArg(arg_den));
41  curr_num = mul(curr_num, arg_num);
42  curr_den = mul(curr_den, arg_den);
43  }
44 
45  *numer_ = curr_num;
46  *denom_ = curr_den;
47  }
48 
49  void bvisit(const Add &x)
50  {
51 
52  RCP<const Basic> curr_num = zero;
53  RCP<const Basic> curr_den = one;
54  RCP<const Basic> arg_num, arg_den, den_mul, divx;
55  RCP<const Basic> divx_num, divx_den;
56 
57  for (const auto &arg : x.get_args()) {
58  // TODO: This is naive and slow. Fix it
59  as_numer_denom(arg, outArg(arg_num), outArg(arg_den));
60 
61  divx = div(arg_den, curr_den);
62  as_numer_denom(divx, outArg(divx_num), outArg(divx_den));
63  if (eq(*divx_den, *one)) {
64  // the curr_den completely divides the arg_den
65  curr_den = arg_den;
66  curr_num = add(mul(curr_num, divx), arg_num);
67  continue;
68  }
69 
70  divx = div(curr_den, arg_den);
71  as_numer_denom(divx, outArg(divx_num), outArg(divx_den));
72  // the below two lines, cover the general case, as well as the case
73  // where arg_den completely divides curr_den
74  curr_den = mul(curr_den, divx_den);
75  curr_num = add(mul(curr_num, divx_den), mul(arg_num, divx_num));
76  }
77 
78  *numer_ = curr_num;
79  *denom_ = curr_den;
80  }
81 
82  void bvisit(const Pow &x)
83  {
84 
85  RCP<const Basic> base_, exp_, num, den;
86  base_ = x.get_base();
87  exp_ = x.get_exp();
88  as_numer_denom(base_, outArg(num), outArg(den));
89 
90  // if the exp is a negative numer, or is intuitively 'negative'
91  if (handle_minus(exp_, outArg(exp_))) {
92  *numer_ = pow(den, exp_);
93  *denom_ = pow(num, exp_);
94  } else {
95  *numer_ = pow(num, exp_);
96  *denom_ = pow(den, exp_);
97  }
98  }
99 
100  void bvisit(const Complex &x)
101  {
102 
103  RCP<const Integer> den, den1, den2;
104  RCP<const Integer> num1, num2;
105 
106  num1 = integer(get_num(x.real_));
107  num2 = integer(get_num(x.imaginary_));
108 
109  den1 = integer(get_den(x.real_));
110  den2 = integer(get_den(x.imaginary_));
111  den = lcm(*den1, *den2);
112 
113  num1 = rcp_static_cast<const Integer>(mul(num1, div(den, den1)));
114  num2 = rcp_static_cast<const Integer>(mul(num2, div(den, den2)));
115 
116  *numer_ = Complex::from_two_nums(*num1, *num2);
117  *denom_ = den;
118  }
119 
120  void bvisit(const Rational &x)
121  {
122  *numer_ = x.get_num();
123  *denom_ = x.get_den();
124  }
125 
126  void bvisit(const Basic &x)
127  {
128  *numer_ = x.rcp_from_this();
129  *denom_ = one;
130  }
131 };
132 
133 void as_numer_denom(const RCP<const Basic> &x,
134  const Ptr<RCP<const Basic>> &numer,
135  const Ptr<RCP<const Basic>> &denom)
136 {
137  NumerDenomVisitor v(numer, denom);
138  v.apply(*x);
139 }
140 
141 } // namespace SymEngine
The base class for representing addition in symbolic expressions.
Definition: add.h:27
vec_basic get_args() const override
Returns the arguments of the Add.
Definition: add.cpp:397
The lowest unit of symbolic representation.
Definition: basic.h:97
Complex Class.
Definition: complex.h:33
rational_class real_
Definition: complex.h:38
static RCP< const Number > from_two_nums(const Number &re, const Number &im)
Definition: complex.cpp:109
RCP< T > rcp_from_this()
Get RCP<T> pointer to self (it will cast the pointer to T)
vec_basic get_args() const override
Returns the list of arguments.
Definition: mul.cpp:507
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
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
std::enable_if< std::is_integral< T >::value, RCP< const Integer > >::type integer(T i)
Definition: integer.h:197
bool eq(const Basic &a, const Basic &b)
Checks equality for a and b
Definition: basic-inl.h:21
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
RCP< const Basic > add(const RCP< const Basic > &a, const RCP< const Basic > &b)
Adds two objects (safely).
Definition: add.cpp:425