[poincare] Change Expression::compareTo to SimplificationOrder

Change-Id: I0f3dff0a0933f55164573623253ee24f1a85d2a7
This commit is contained in:
Émilie Feral
2017-10-31 11:25:12 +01:00
parent 29f88f05d7
commit 13ef08d628
23 changed files with 95 additions and 79 deletions

View File

@@ -29,7 +29,7 @@ private:
int numberOfDigitsInMantissa() const;
/* Sorting */
int compareToSameTypeExpression(const Expression * e) const override;
int simplificationOrderSameType(const Expression * e) const override;
constexpr static int k_maxLength = 10;
Integer m_mantissa;

View File

@@ -23,14 +23,15 @@ public:
void addOperands(const Expression * const * operands, int numberOfOperands);
void addOperandAtIndex(Expression * operand, int index);
void mergeOperands(DynamicHierarchy * d);
void sortChildren();
typedef int (*ExpressionOrder)(const Expression * e1, const Expression * e2);
void sortOperands(ExpressionOrder order);
Expression * squashUnaryHierarchy();
protected:
bool deleteUselessOperand(int index);
private:
void removeOperandAtIndex(int i, bool deleteAfterRemoval);
int compareToSameTypeExpression(const Expression * e) const override;
int compareToGreaterTypeExpression(const Expression * e) const override;
int simplificationOrderSameType(const Expression * e) const override;
int simplificationOrderGreaterType(const Expression * e) const override;
virtual bool isUselessOperand(const Rational * r) = 0;
const Expression ** m_operands;
int m_numberOfOperands;

View File

@@ -135,12 +135,16 @@ public:
virtual void swapOperands(int i, int j) = 0;
//void removeFromParent();
/* Sorting */
/* compareTo returns:
* 1 if this > e
* -1 if this < e
* 0 if this == e */
int compareTo(const Expression * e) const;
// Comparison
/* isIdenticalTo is the "easy" equality, it returns true if both trees have
* same structures and all their nodes have same types and values (ie,
* sqrt(pi^2) is NOT identical to pi). */
bool isIdenticalTo(const Expression * e) const {
/* We use the simplification order only because it is a already-coded total
* order on expresssions. */
return SimplificationOrder(this, e) == 0;
}
/* Layout Engine */
ExpressionLayout * createLayout(FloatDisplayMode floatDisplayMode = FloatDisplayMode::Default, ComplexFormat complexFormat = ComplexFormat::Default) const; // Returned object must be deleted
@@ -166,10 +170,17 @@ protected:
typedef float SinglePrecision;
typedef double DoublePrecision;
template<typename T> static T epsilon();
/* Compare (== < and >) the type of the root node of 2 expressions.
* This behavior makes sense for value-less nodes (addition, product, fraction
* power, etc… For nodes with a value (Integer, Complex), this must be over-
* -riden. */
/* Simplification order returns:
* 1 if e1 > e2
* -1 if e1 < e2
* 0 if e1 == e
* Following the order described in Computer Algebra and Symbolic Computation,
* Joel S. Cohen (section 3.1). The order groups like terms together to avoid
* quadratic complexity when factorizing addition or multiplication. For
* example, it groups terms with same bases together (ie Pi, Pi^3) and with
* same non-rational factors together (ie Pi, 2*Pi). */
static int SimplificationOrder(const Expression * e1, const Expression * e2);
private:
/* Simplification */
Expression * deepBeautify(Context & context, AngleUnit angleUnit);
@@ -182,15 +193,19 @@ private:
/* Evaluation Engine */
virtual Evaluation<float> * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const = 0;
virtual Evaluation<double> * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const = 0;
/* Sorting */
virtual int compareToGreaterTypeExpression(const Expression * e) const {
return -1;
}
/* What should be the implementation of complex? */
virtual int compareToSameTypeExpression(const Expression * e) const {
return 0;
}
virtual Expression * setSign(Sign s, Context & context, AngleUnit angleUnit) { assert(false); return nullptr; }
/* In the simplification order, most expressions are compared by only
* comparing their types. However hierarchical expressions of same type would
* compare their operands and thus need to reimplement
* simplificationOrderSameType. Besides, operations that can be simplified
* (ie +, *, ^, !) have specific rules to group like terms together and thus
* reimplement simplificationOrderGreaterType. */
virtual int simplificationOrderGreaterType(const Expression * e) const { return -1; }
virtual int simplificationOrderSameType(const Expression * e) const { return 0; }
/* TODO: What should be the implementation for complex? */
Expression * m_parent;
};

View File

@@ -22,8 +22,8 @@ private:
Expression * shallowSimplify(Context& context, AngleUnit angleUnit) override;
ExpressionLayout * privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const override;
int writeTextInBuffer(char * buffer, int bufferSize) const override;
int compareToGreaterTypeExpression(const Expression * e) const override;
int compareToSameTypeExpression(const Expression * e) const override;
int simplificationOrderGreaterType(const Expression * e) const override;
int simplificationOrderSameType(const Expression * e) const override;
};
}

View File

@@ -39,8 +39,8 @@ private:
return LayoutEngine::writeInfixExpressionTextInBuffer(this, buffer, bufferSize, name());
}
static const char * name() { return "^"; }
int compareToGreaterTypeExpression(const Expression * e) const override;
int compareToSameTypeExpression(const Expression * e) const override;
int simplificationOrderGreaterType(const Expression * e) const override;
int simplificationOrderSameType(const Expression * e) const override;
Expression * simplifyPowerPower(Power * p, Expression * r, Context & context, AngleUnit angleUnit);
Expression * simplifyPowerMultiplication(Multiplication * m, Expression * r, Context & context, AngleUnit angleUnit);
Expression * simplifyRationalRationalPower(Expression * result, Rational * a, Rational * b, Context & context, AngleUnit angleUnit);

View File

@@ -50,7 +50,7 @@ private:
}
/* Sorting */
int compareToSameTypeExpression(const Expression * e) const override;
int simplificationOrderSameType(const Expression * e) const override;
Integer m_numerator;
Integer m_denominator;

View File

@@ -23,7 +23,7 @@ public:
virtual bool hasValidNumberOfOperands(int numberOfOperands) const;
protected:
void build(const Expression * const * operands, int numberOfOperands, bool cloneOperands);
int compareToSameTypeExpression(const Expression * e) const override;
int simplificationOrderSameType(const Expression * e) const override;
const Expression * m_operands[T];
};

View File

@@ -42,7 +42,7 @@ private:
template<typename T> Evaluation<T> * templatedEvaluate(Context& context, AngleUnit angleUnit) const;
ExpressionLayout * privateCreateLayout(FloatDisplayMode floatDisplayMode, ComplexFormat complexFormat) const override;
int writeTextInBuffer(char * buffer, int bufferSize) const override;
int compareToSameTypeExpression(const Expression * e) const override;
int simplificationOrderSameType(const Expression * e) const override;
const char m_name;
};

View File

@@ -35,7 +35,7 @@ Expression * Addition::shallowSimplify(Context& context, AngleUnit angleUnit) {
index = 0;
}
}
sortChildren();
sortOperands(Expression::SimplificationOrder);
int i = 0;
while (i < numberOfOperands()) {
if (deleteUselessOperand(i) && i > 0) {
@@ -128,7 +128,7 @@ bool Addition::TermsHaveIdenticalNonRationalFactors(const Expression * e1, const
}
const Expression * f1 = (e1->type() == Type::Multiplication && e1->numberOfOperands() == 2 && e1->operand(0)->type() == Type::Rational) ? e1->operand(1) : e1;
const Expression * f2 = (e2->type() == Type::Multiplication && e2->numberOfOperands() == 2 && e2->operand(0)->type() == Type::Rational) ? e2->operand(1) : e2;
return (f1->compareTo(f2) == 0);
return f1->isIdenticalTo(f2);
}
Expression * Addition::shallowBeautify(Context & context, AngleUnit angleUnit) {

View File

@@ -165,7 +165,7 @@ Expression * Decimal::shallowSimplify(Context& context, AngleUnit angleUnit) {
return replaceWith(new Rational(numerator, denominator), true);
}
int Decimal::compareToSameTypeExpression(const Expression * e) const {
int Decimal::simplificationOrderSameType(const Expression * e) const {
// We should not get there are decimal are turned into Rational before simplification
assert(false);
return 0;

View File

@@ -42,7 +42,7 @@ Expression * Division::shallowBeautify(Context & context, AngleUnit angleUnit) {
if (sin == nullptr || cos == nullptr) {
break;
}
if (sin->operand(0)->compareTo(cos->operand(0)) != 0) {
if (!sin->operand(0)->isIdenticalTo(cos->operand(0))) {
k++;
continue;
}

View File

@@ -102,7 +102,7 @@ void DynamicHierarchy::removeOperandAtIndex(int i, bool deleteAfterRemoval) {
m_numberOfOperands--;
}
int DynamicHierarchy::compareToSameTypeExpression(const Expression * e) const {
int DynamicHierarchy::simplificationOrderSameType(const Expression * e) const {
int m = this->numberOfOperands();
int n = e->numberOfOperands();
for (int i = 1; i <= m; i++) {
@@ -110,8 +110,8 @@ int DynamicHierarchy::compareToSameTypeExpression(const Expression * e) const {
if (n < i) {
return 1;
}
if (this->operand(m-i)->compareTo(e->operand(n-i)) != 0) {
return this->operand(m-i)->compareTo(e->operand(n-i));
if (SimplificationOrder(this->operand(m-i), e->operand(n-i)) != 0) {
return SimplificationOrder(this->operand(m-i), e->operand(n-i));
}
}
// The NULL node is the least node type.
@@ -121,14 +121,14 @@ int DynamicHierarchy::compareToSameTypeExpression(const Expression * e) const {
return 0;
}
int DynamicHierarchy::compareToGreaterTypeExpression(const Expression * e) const {
int DynamicHierarchy::simplificationOrderGreaterType(const Expression * e) const {
int m = numberOfOperands();
if (m == 0) {
return -1;
}
/* Compare e to last term of hierarchy. */
if (operand(m-1)->compareTo(e) != 0) {
return operand(m-1)->compareTo(e);
if (SimplificationOrder(operand(m-1), e) != 0) {
return SimplificationOrder(operand(m-1), e);
}
if (m > 1) {
return 1;
@@ -136,11 +136,11 @@ int DynamicHierarchy::compareToGreaterTypeExpression(const Expression * e) const
return 0;
}
void DynamicHierarchy::sortChildren() {
void DynamicHierarchy::sortOperands(ExpressionOrder order) {
for (int i = numberOfOperands()-1; i > 0; i--) {
bool isSorted = true;
for (int j = 0; j < numberOfOperands()-1; j++) {
if (operand(j)->compareTo(operand(j+1)) > 0) {
if (order(operand(j), operand(j+1)) > 0) {
swapOperands(j, j+1);
isSorted = false;
}

View File

@@ -130,13 +130,13 @@ Expression * Expression::replaceWith(Expression * newOperand, bool deleteAfterRe
static_cast<DynamicHierarchy *>(m_parent)->removeOperand(this);
}*/
int Expression::compareTo(const Expression * e) const {
if (this->type() > e->type()) {
return -(e->compareTo(this));
} else if (this->type() == e->type()) {
return compareToSameTypeExpression(e);
int Expression::SimplificationOrder(const Expression * e1, const Expression * e2) {
if (e1->type() > e2->type()) {
return -(e2->simplificationOrderGreaterType(e1));
} else if (e1->type() == e2->type()) {
return e1->simplificationOrderSameType(e2);
} else {
return compareToGreaterTypeExpression(e);
return e1->simplificationOrderGreaterType(e2);
}
}

View File

@@ -69,11 +69,11 @@ ExpressionLayout * Factorial::privateCreateLayout(FloatDisplayMode floatDisplayM
return new HorizontalLayout(childrenLayouts, 2);
}
int Factorial::compareToGreaterTypeExpression(const Expression * e) const {
if (operand(0)->compareTo(e) == 0) {
int Factorial::simplificationOrderGreaterType(const Expression * e) const {
if (SimplificationOrder(operand(0),e) == 0) {
return 1;
}
return operand(0)->compareTo(e);
return SimplificationOrder(operand(0), e);
}
int Factorial::writeTextInBuffer(char * buffer, int bufferSize) const {
@@ -90,8 +90,8 @@ int Factorial::writeTextInBuffer(char * buffer, int bufferSize) const {
return numberOfChar;
}
int Factorial::compareToSameTypeExpression(const Expression * e) const {
return operand(0)->compareTo(e->operand(0));
int Factorial::simplificationOrderSameType(const Expression * e) const {
return SimplificationOrder(operand(0), e->operand(0));
}
}

View File

@@ -102,12 +102,12 @@ Expression * Logarithm::splitInteger(Integer i, bool isDenominator, Context & co
Expression * Logarithm::shallowBeautify(Context & context, AngleUnit angleUnit) {
Symbol e = Symbol(Ion::Charset::Exponential);
const Expression * logOperand[1] = {operand(0)};
if (numberOfOperands() == 2 && operand(1)->compareTo(&e) == 0) {
if (numberOfOperands() == 2 && operand(1)->isIdenticalTo(&e)) {
NaperianLogarithm * nl = new NaperianLogarithm(logOperand, true);
return replaceWith(nl, true);
}
Rational one = Rational(Integer(1));
if (numberOfOperands() == 2 && operand(1)->compareTo(&one) == 0) {
if (numberOfOperands() == 2 && operand(1)->isIdenticalTo(&one)) {
Logarithm * l = new Logarithm(logOperand, 1, true);
return replaceWith(l, true);
}

View File

@@ -97,7 +97,7 @@ bool Multiplication::HaveSameNonRationalFactors(const Expression * e1, const Exp
int firstNonRationalOperand1 = e1->operand(0)->type() == Type::Rational ? 1 : 0;
int firstNonRationalOperand2 = e2->operand(0)->type() == Type::Rational ? 1 : 0;
for (int i = 0; i < numberOfNonRationalFactors1; i++) {
if (e1->operand(firstNonRationalOperand1+i)->compareTo(e2->operand(firstNonRationalOperand2+i)) != 0) {
if (!(e1->operand(firstNonRationalOperand1+i)->isIdenticalTo(e2->operand(firstNonRationalOperand2+i)))) {
return false;
}
}
@@ -208,7 +208,7 @@ bool Multiplication::resolveSquareRootAtDenominator(Context & context, AngleUnit
}
void Multiplication::factorize(Context & context, AngleUnit angleUnit) {
sortChildren();
sortOperands(SimplificationOrder);
int i = 0;
while (i < numberOfOperands()) {
if (deleteUselessOperand(i) && i > 0) {
@@ -320,11 +320,11 @@ const Rational * Multiplication::RationalFactorInExpression(const Expression * e
bool Multiplication::TermsHaveIdenticalBase(const Expression * e1, const Expression * e2) {
const Expression * f1 = e1->type() == Type::Power ? e1->operand(0) : e1;
const Expression * f2 = e2->type() == Type::Power ? e2->operand(0) : e2;
return (f1->compareTo(f2) == 0);
return f1->isIdenticalTo(f2);
}
bool Multiplication::TermsHaveIdenticalNonUnitaryExponent(const Expression * e1, const Expression * e2) {
return e1->type() == Type::Power && e2->type() == Type::Power && (e1->operand(1)->compareTo(e2->operand(1)) == 0);
return e1->type() == Type::Power && e2->type() == Type::Power && (e1->operand(1)->isIdenticalTo(e2->operand(1)));
}
bool Multiplication::TermHasRationalBase(const Expression * e) {
@@ -397,7 +397,7 @@ Expression * Multiplication::shallowBeautify(Context & context, AngleUnit angleU
if (denominatorOperand->type() == Type::Multiplication) {
const Expression * integerDenominator[1] = {new Rational(r->denominator())};
static_cast<Multiplication *>(denominatorOperand)->addOperands(integerDenominator, 1);
static_cast<Multiplication *>(denominatorOperand)->sortChildren();
static_cast<Multiplication *>(denominatorOperand)->sortOperands(SimplificationOrder);
} else {
const Expression * multOperands[2] = {new Rational(r->denominator()), denominatorOperand->clone()};
Multiplication * m = new Multiplication(multOperands, 2, false);
@@ -482,11 +482,11 @@ Expression * Multiplication::mergeNegativePower(Context & context, AngleUnit ang
}
const Expression * powOperands[2] = {m, new Rational(Integer(-1))};
Power * p = new Power(powOperands, false);
m->sortChildren();
m->sortOperands(SimplificationOrder);
m->squashUnaryHierarchy();
const Expression * multOperand[1] = {p};
addOperands(multOperand, 1);
sortChildren();
sortOperands(SimplificationOrder);
return squashUnaryHierarchy();
}
@@ -515,7 +515,7 @@ void Multiplication::leastCommonMultiple(Expression * factor, Context & context,
}
const Expression * newOp[1] = {factor->clone()};
addOperands(newOp, 1);
sortChildren();
sortOperands(SimplificationOrder);
}
template Poincare::Evaluation<float>* Poincare::Multiplication::computeOnComplexAndMatrix<float>(Poincare::Complex<float> const*, Poincare::Evaluation<float>*);

View File

@@ -117,21 +117,21 @@ ExpressionLayout * Power::privateCreateLayout(FloatDisplayMode floatDisplayMode,
return new BaselineRelativeLayout(m_operands[0]->createLayout(floatDisplayMode, complexFormat),indiceOperand->createLayout(floatDisplayMode, complexFormat), BaselineRelativeLayout::Type::Superscript);
}
int Power::compareToSameTypeExpression(const Expression * e) const {
int baseComparison = operand(0)->compareTo(static_cast<const Power *>(e)->operand(0));
int Power::simplificationOrderSameType(const Expression * e) const {
int baseComparison = SimplificationOrder(operand(0), e->operand(0));
if (baseComparison != 0) {
return baseComparison;
}
return operand(1)->compareTo(static_cast<const Power *>(e)->operand(1));
return SimplificationOrder(operand(1), e->operand(1));
}
int Power::compareToGreaterTypeExpression(const Expression * e) const {
int baseComparison = operand(0)->compareTo(e);
int Power::simplificationOrderGreaterType(const Expression * e) const {
int baseComparison = SimplificationOrder(operand(0), e);
if (baseComparison != 0) {
return baseComparison;
}
Rational one(Integer(1));
return operand(1)->compareTo(&one);
return SimplificationOrder(operand(1), &one);
}
Expression * Power::shallowSimplify(Context& context, AngleUnit angleUnit) {
@@ -320,7 +320,7 @@ Expression * Power::CreateSimplifiedIntegerRationalPower(Integer i, Rational * r
const Expression * operand[1] = {pExp};
m->addOperands(operand, 1);
}
m->sortChildren();
m->sortOperands(SimplificationOrder);
return m;
}

View File

@@ -114,7 +114,7 @@ Rational Rational::Power(const Rational & i, const Integer & j) {
// Comparison
int Rational::compareToSameTypeExpression(const Expression * e) const {
int Rational::simplificationOrderSameType(const Expression * e) const {
assert(e->type() == Expression::Type::Rational);
const Rational * other = static_cast<const Rational *>(e);
Integer i1 = Integer::Multiplication(m_numerator, other->denominator());

View File

@@ -54,14 +54,14 @@ void StaticHierarchy<T>::build(const Expression * const * operands, int numberOf
}
template<int T>
int StaticHierarchy<T>::compareToSameTypeExpression(const Expression * e) const {
int StaticHierarchy<T>::simplificationOrderSameType(const Expression * e) const {
for (int i = 0; i < this->numberOfOperands(); i++) {
// The NULL node is the least node type.
if (e->numberOfOperands() <= i) {
return 1;
}
if (this->operand(i)->compareTo(e->operand(i)) != 0) {
return this->operand(i)->compareTo(e->operand(i));
if (SimplificationOrder(this->operand(i), e->operand(i)) != 0) {
return SimplificationOrder(this->operand(i), e->operand(i));
}
}
// The NULL node is the least node type.

View File

@@ -135,7 +135,7 @@ bool Symbol::isMatrixSymbol() const {
return false;
}
int Symbol::compareToSameTypeExpression(const Expression * e) const {
int Symbol::simplificationOrderSameType(const Expression * e) const {
assert(e->type() == Expression::Type::Symbol);
if (m_name == ((Symbol *)e)->m_name) {
return 0;

View File

@@ -186,7 +186,7 @@ Expression * Trigonometry::table(const Expression * e, Expression::Type type, Co
}
SimplificationRoot inputRoot(input);
inputRoot.deepSimplify(context, angleUnit); // input expression does not change, no root needed and we can use entry after
if (inputRoot.operand(0)->compareTo(e) == 0) {
if (inputRoot.operand(0)->isIdenticalTo(e)) {
Expression * output = Expression::parse(cheatTable[i][outputIndex]);
if (output == nullptr) {
return nullptr;

View File

@@ -27,7 +27,7 @@ void assert_parsed_expression_simplify_to(const char * expression, const char *
cout << "---- compared to: " << simplifiedExpression << "----" << endl;
print_expression(f, 0);
#endif
assert(e->compareTo(f) == 0);
assert(e->isIdenticalTo(f));
delete e;
delete f;
}

View File

@@ -34,7 +34,7 @@ bool simplifies_to(const char * input_string, const char * expected_string) {
print_expression(expected);
#endif
bool isIdentical = input->compareTo(expected) == 0;
bool isIdentical = input->isIdentical(expected);
delete expected;
delete input;
@@ -61,7 +61,7 @@ bool identical_to(const char * input_string, const char * expected_string) {
print_expression(expected);
#endif
bool isIdentical = input->compareTo(expected) == 0;
bool isIdentical = input->isIdentical(expected);
delete expected;
delete input;
@@ -99,7 +99,7 @@ bool equivalent_to(const char * input_string, const char * expected_string) {
cout << "Simplified Expected = " << endl;
print_expression(expected);
#endif
bool isEquivalent = input->compareTo(expected) == 0;
bool isEquivalent = input->isIdentical(expected);
delete expected;
delete input;