Numworks Epsilon  1.4.1
Graphing Calculator Operating System
addition.cpp
Go to the documentation of this file.
1 #include <poincare/addition.h>
3 #include <poincare/subtraction.h>
4 #include <poincare/power.h>
5 #include <poincare/opposite.h>
6 #include <poincare/undefined.h>
7 #include <poincare/matrix.h>
8 extern "C" {
9 #include <assert.h>
10 #include <stdlib.h>
11 }
12 
13 namespace Poincare {
14 
16  return Type::Addition;
17 }
18 
20  if (numberOfOperands() == 0) {
21  return new Addition();
22  }
23  return new Addition(operands(), numberOfOperands(), true);
24 }
25 
26 int Addition::polynomialDegree(char symbolName) const {
27  int degree = 0;
28  for (int i = 0; i < numberOfOperands(); i++) {
29  int d = operand(i)->polynomialDegree(symbolName);
30  if (d < 0) {
31  return -1;
32  }
33  degree = d > degree ? d : degree;
34  }
35  return degree;
36 }
37 
38 /* Layout */
39 
40 bool Addition::needParenthesisWithParent(const Expression * e) const {
42  return e->isOfType(types, 6);
43 }
44 
45 /* Simplication */
46 
47 Expression * Addition::shallowReduce(Context& context, AngleUnit angleUnit) {
48  Expression * e = Expression::shallowReduce(context, angleUnit);
49  if (e != this) {
50  return e;
51  }
52  /* Step 1: Addition is associative, so let's start by merging children which
53  * also are additions themselves. */
54  int i = 0;
55  int initialNumberOfOperands = numberOfOperands();
56  while (i < initialNumberOfOperands) {
57  Expression * o = editableOperand(i);
58  if (o->type() == Type::Addition) {
59  mergeOperands(static_cast<Addition *>(o));
60  continue;
61  }
62  i++;
63  }
64 
65  // Step 2: Sort the operands
67 
68 #if MATRIX_EXACT_REDUCING
69  /* Step 2bis: get rid of matrix */
70  int n = 1;
71  int m = 1;
72  /* All operands have been simplified so if any operand contains a matrix, it
73  * is at the root node of the operand. Moreover, thanks to the simplification
74  * order, all matrix operands (if any) are the last operands. */
75  Expression * lastOperand = editableOperand(numberOfOperands()-1);
76  if (lastOperand->type() == Type::Matrix) {
77  // Create in-place the matrix of addition M (in place of the last operand)
78  Matrix * resultMatrix = static_cast<Matrix *>(lastOperand);
79  n = resultMatrix->numberOfRows();
80  m = resultMatrix->numberOfColumns();
81  removeOperand(resultMatrix, false);
82  /* Scan (starting at the end) accross the addition operands to find any
83  * other matrix */
84  int i = numberOfOperands()-1;
85  while (i >= 0 && operand(i)->type() == Type::Matrix) {
86  Matrix * currentMatrix = static_cast<Matrix *>(editableOperand(i));
87  int on = currentMatrix->numberOfRows();
88  int om = currentMatrix->numberOfColumns();
89  if (on != n || om != m) {
90  return replaceWith(new Undefined(), true);
91  }
92  // Dispatch the current matrix operands in the created additions matrix
93  for (int j = 0; j < n*m; j++) {
94  Addition * a = new Addition();
95  Expression * resultMatrixEntryJ = resultMatrix->editableOperand(j);
96  resultMatrix->replaceOperand(resultMatrixEntryJ, a, false);
97  a->addOperand(currentMatrix->editableOperand(j));
98  a->addOperand(resultMatrixEntryJ);
99  a->shallowReduce(context, angleUnit);
100  }
101  currentMatrix->detachOperands();
102  removeOperand(currentMatrix, true);
103  i--;
104  }
105  // Distribute the remaining addition on matrix operands
106  for (int i = 0; i < n*m; i++) {
107  Addition * a = static_cast<Addition *>(clone());
108  Expression * entryI = resultMatrix->editableOperand(i);
109  resultMatrix->replaceOperand(entryI, a, false);
110  a->addOperand(entryI);
111  a->shallowReduce(context, angleUnit);
112  }
113  return replaceWith(resultMatrix, true)->shallowReduce(context, angleUnit);
114  }
115 #endif
116 
117  /* Step 3: Factorize like terms. Thanks to the simplification order, those are
118  * next to each other at this point. */
119  i = 0;
120  while (i < numberOfOperands()-1) {
121  Expression * o1 = editableOperand(i);
122  Expression * o2 = editableOperand(i+1);
123  if (o1->type() == Type::Rational && o2->type() == Type::Rational) {
124  Rational r1 = *static_cast<Rational *>(o1);
125  Rational r2 = *static_cast<Rational *>(o2);
126  Rational a = Rational::Addition(r1, r2);
127  replaceOperand(o1, new Rational(a), true);
128  removeOperand(o2, true);
129  continue;
130  }
131  if (TermsHaveIdenticalNonRationalFactors(o1, o2)) {
132  factorizeOperands(o1, o2, context, angleUnit);
133  continue;
134  }
135  i++;
136  }
137 
138  /* Step 4: Let's remove zeroes if there's any. It's important to do this after
139  * having factorized because factorization can lead to new zeroes. For example
140  * pi+(-1)*pi. We don't remove the last zero if it's the only operand left
141  * though. */
142  i = 0;
143  while (i < numberOfOperands()) {
144  Expression * o = editableOperand(i);
145  if (o->type() == Type::Rational && static_cast<Rational *>(o)->isZero() && numberOfOperands() > 1) {
146  removeOperand(o, true);
147  continue;
148  }
149  i++;
150  }
151 
152  // Step 5: Let's remove the addition altogether if it has a single operand
153  Expression * result = squashUnaryHierarchy();
154 
155  // Step 6: Last but not least, let's put everything under a common denominator
156  if (result == this && parent()->type() != Type::Addition) {
157  // squashUnaryHierarchy didn't do anything: we're not an unary hierarchy
158  result = factorizeOnCommonDenominator(context, angleUnit);
159  }
160 
161  return result;
162 }
163 
164 Expression * Addition::factorizeOnCommonDenominator(Context & context, AngleUnit angleUnit) {
165  // We want to turn (a/b+c/d+e/b) into (a*d+b*c+e*d)/(b*d)
166 
167  // Step 1: We want to compute the common denominator, b*d
168  Multiplication * commonDenominator = new Multiplication();
169  for (int i = 0; i < numberOfOperands(); i++) {
170  Expression * denominator = operand(i)->cloneDenominator(context, angleUnit);
171  if (denominator) {
172  // Make commonDenominator = LeastCommonMultiple(commonDenominator, denominator);
173  commonDenominator->addMissingFactors(denominator, context, angleUnit);
174  delete denominator;
175  }
176  }
177  if (commonDenominator->numberOfOperands() == 0) {
178  delete commonDenominator;
179  // If commonDenominator is empty this means that no operand was a fraction.
180  return this;
181  }
182 
183  // Step 2: Create the numerator. We start with this being a/b+c/d+e/b and we
184  // want to create numerator = a/b*b*d + c/d*b*d + e/b*b*d
185  Addition * numerator = new Addition();
186  for (int i=0; i < numberOfOperands(); i++) {
187  Multiplication * m = new Multiplication(operand(i), commonDenominator, true);
188  numerator->addOperand(m);
189  m->privateShallowReduce(context, angleUnit, true, false);
190  }
191  // Step 3: Add the denominator
192  Power * inverseDenominator = new Power(commonDenominator, new Rational(-1), false);
193  Multiplication * result = new Multiplication(numerator, inverseDenominator, false);
194 
195  // Step 4: Simplify the numerator to a*d + c*b + e*d
196  numerator->shallowReduce(context, angleUnit);
197 
198  // Step 5: Simplify the denominator (in case it's a rational number)
199  commonDenominator->deepReduce(context, angleUnit);
200  inverseDenominator->shallowReduce(context, angleUnit);
201 
202  /* Step 6: We simplify the resulting multiplication forbidding any
203  * distribution of multiplication on additions (to avoid an infinite loop). */
204  return static_cast<Multiplication *>(replaceWith(result, true))->privateShallowReduce(context, angleUnit, false, true);
205 }
206 
207 void Addition::factorizeOperands(Expression * e1, Expression * e2, Context & context, AngleUnit angleUnit) {
208  /* This function factorizes two operands which only differ by a rational
209  * factor. For example, if this is Addition(2*pi, 3*pi), then 2*pi and 3*pi
210  * could be merged, and this turned into Addition(5*pi). */
211  assert(e1->parent() == this && e2->parent() == this);
212 
213  // Step 1: Find the new rational factor
214  Rational * r = new Rational(Rational::Addition(RationalFactor(e1), RationalFactor(e2)));
215 
216  // Step 2: Get rid of one of the operands
217  removeOperand(e2, true);
218 
219  // Step 3: Use the new rational factor. Create a multiplication if needed
220  Multiplication * m = nullptr;
221  if (e1->type() == Type::Multiplication) {
222  m = static_cast<Multiplication *>(e1);
223  } else {
224  m = new Multiplication();
225  e1->replaceWith(m, false);
226  m->addOperand(e1);
227  }
228  if (m->operand(0)->type() == Type::Rational) {
229  m->replaceOperand(m->operand(0), r, true);
230  } else {
231  m->addOperand(r);
232  }
233 
234  // Step 4: Reduce the multiplication (in case the new rational factor is zero)
235  m->shallowReduce(context, angleUnit);
236 }
237 
238 const Rational Addition::RationalFactor(Expression * e) {
239  if (e->type() == Type::Multiplication && e->operand(0)->type() == Type::Rational) {
240  return *(static_cast<const Rational *>(e->operand(0)));
241  }
242  return Rational(1);
243 }
244 
245 static inline int NumberOfNonRationalFactors(const Expression * e) {
246  if (e->type() != Expression::Type::Multiplication) {
247  return 1; // Or (e->type() != Type::Rational);
248  }
249  int result = e->numberOfOperands();
250  if (e->operand(0)->type() == Expression::Type::Rational) {
251  result--;
252  }
253  return result;
254 }
255 
256 static inline const Expression * FirstNonRationalFactor(const Expression * e) {
257  if (e->type() != Expression::Type::Multiplication) {
258  return e;
259  }
260  if (e->operand(0)->type() == Expression::Type::Rational) {
261  return e->numberOfOperands() > 1 ? e->operand(1) : nullptr;
262  }
263  return e->operand(0);
264 }
265 
266 bool Addition::TermsHaveIdenticalNonRationalFactors(const Expression * e1, const Expression * e2) {
267  /* Given two expressions, say wether they only differ by a rational factor.
268  * For example, 2*pi and pi do, 2*pi and 2*ln(2) don't. */
269 
270  int numberOfNonRationalFactorsInE1 = NumberOfNonRationalFactors(e1);
271  int numberOfNonRationalFactorsInE2 = NumberOfNonRationalFactors(e2);
272 
273  if (numberOfNonRationalFactorsInE1 != numberOfNonRationalFactorsInE2) {
274  return false;
275  }
276 
277  int numberOfNonRationalFactors = numberOfNonRationalFactorsInE1;
278  if (numberOfNonRationalFactors == 1) {
279  return FirstNonRationalFactor(e1)->isIdenticalTo(FirstNonRationalFactor(e2));
280  } else {
281  assert(numberOfNonRationalFactors > 1);
282  return Multiplication::HaveSameNonRationalFactors(e1, e2);
283  }
284 }
285 
286 Expression * Addition::shallowBeautify(Context & context, AngleUnit angleUnit) {
287  /* Beautifying Addition essentially consists in adding Subtractions if needed.
288  * In practice, we want to turn "a+(-1)*b" into "a-b". Or, more precisely, any
289  * "a+(-r)*b" into "a-r*b" where r is a positive Rational.
290  * Note: the process will slightly differ if the negative product occurs on
291  * the first term: we want to turn "Addition(Multiplication(-1,b))" into
292  * "Opposite(b)".
293  * Last but not least, special care must be taken when iterating over operands
294  * since we may remove some during the process. */
295 
296  for (int i=0; i<numberOfOperands(); i++) {
297  if (operand(i)->type() != Type::Multiplication || operand(i)->operand(0)->type() != Type::Rational || operand(i)->operand(0)->sign() != Sign::Negative) {
298  // Ignore terms which are not like "(-r)*a"
299  continue;
300  }
301 
302  Multiplication * m = static_cast<Multiplication *>(editableOperand(i));
303 
304  if (static_cast<const Rational *>(m->operand(0))->isMinusOne()) {
305  m->removeOperand(m->operand(0), true);
306  } else {
307  m->editableOperand(0)->setSign(Sign::Positive, context, angleUnit);
308  }
309  Expression * subtractant = m->squashUnaryHierarchy();
310 
311  if (i == 0) {
312  Opposite * o = new Opposite(subtractant, true);
313  replaceOperand(subtractant, o, true);
314  } else {
315  const Expression * op1 = operand(i-1);
316  removeOperand(op1, false);
317  Subtraction * s = new Subtraction(op1, subtractant, false);
318  replaceOperand(subtractant, s, false);
319  /* CAUTION: we removed an operand. So we need to decrement i to make sure
320  * the next iteration is actually on the next operand. */
321  i--;
322  }
323  }
324 
325  return squashUnaryHierarchy();
326 }
327 
328 /* Evaluation */
329 
330 template<typename T>
332  return Complex<T>::Cartesian(c.a()+d.a(), c.b()+d.b());
333 }
334 
335 template Complex<float> Poincare::Addition::compute<float>(Poincare::Complex<float>, Poincare::Complex<float>);
336 template Complex<double> Poincare::Addition::compute<double>(Poincare::Complex<double>, Poincare::Complex<double>);
337 
338 template Matrix* Addition::computeOnMatrices<float>(const Matrix*,const Matrix*);
339 template Matrix* Addition::computeOnMatrices<double>(const Matrix*,const Matrix*);
340 
341 template Matrix* Addition::computeOnComplexAndMatrix<float>(Complex<float> const*, const Matrix*);
342 template Matrix* Addition::computeOnComplexAndMatrix<double>(Complex<double> const*, const Matrix*);
343 
344 }
int polynomialDegree(char symbolName) const override
Definition: addition.cpp:26
void removeOperand(const Expression *e, bool deleteAfterRemoval=true)
friend class Addition
Definition: expression.h:22
Expression * parent() const
Definition: expression.h:185
static Complex< T > Cartesian(T a, T b)
Definition: complex.cpp:28
#define assert(e)
Definition: assert.h:9
Expression * replaceWith(Expression *newOperand, bool deleteAfterReplace=true)
Definition: expression.cpp:85
T a() const
Definition: complex.cpp:99
static Rational Addition(const Rational &i, const Rational &j)
Definition: rational.cpp:104
Type type() const override
Definition: addition.cpp:15
Expression * clone() const override
Definition: addition.cpp:19
static Complex< T > compute(const Complex< T > c, const Complex< T > d)
Definition: addition.cpp:331
c(generic_all_nodes)
Expression * editableOperand(int i)
Definition: expression.h:176
friend class Rational
Definition: expression.h:18
static int SimplificationOrder(const Expression *e1, const Expression *e2, bool canBeInterrupted=false)
Definition: expression.cpp:226
virtual int numberOfOperands() const =0
friend class Power
Definition: addition.h:16
bool isIdenticalTo(const Expression *e) const
Definition: expression.h:219
friend class Opposite
Definition: expression.h:62
const Expression *const * operands() const override
void mergeOperands(DynamicHierarchy *d)
friend class Multiplication
Definition: addition.h:14
friend class Subtraction
Definition: addition.h:15
friend class Matrix
Definition: expression.h:73
virtual Sign sign() const
Definition: expression.h:195
void sortOperands(ExpressionOrder order, bool canBeInterrupted)
int numberOfOperands() const override
const Expression * operand(int i) const
Definition: expression.cpp:78
virtual int polynomialDegree(char symbolName) const
Definition: expression.cpp:202
virtual Type type() const =0
friend class Undefined
Definition: expression.h:17
void replaceOperand(const Expression *oldOperand, Expression *newOperand, bool deleteOldOperand=true)
Definition: expression.cpp:91