Loading...
Searching...
No Matches
numer_denom.cpp
1#include <symengine/visitor.h>
2
3namespace SymEngine
4{
5
6class NumerDenomVisitor : public BaseVisitor<NumerDenomVisitor>
7{
8private:
9 Ptr<RCP<const Basic>> numer_, denom_;
10
11public:
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
133void 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_base() const
Definition: pow.h:37
RCP< const Basic > get_exp() const
Definition: pow.h:42
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
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:49
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
std::enable_if< std::is_integral< T >::value, RCP< constInteger > >::type integer(T i)
Definition: integer.h:197