make isIdenticalTo aware of commutativity.

Change-Id: I43c333d9aef9fe10ad042c56996a157c04c0830a
This commit is contained in:
Felix Raimundo
2016-04-08 16:35:14 +02:00
parent 44ec987008
commit 39d6f9b1d5
4 changed files with 107 additions and 2 deletions

View File

@@ -35,6 +35,7 @@ tests += $(addprefix poincare/test/,\
addition.cpp\
fraction.cpp\
integer.cpp\
identity.cpp\
product.cpp\
simplify_utils.cpp\
simplify_addition.cpp\

View File

@@ -45,6 +45,11 @@ class Expression {
virtual bool isCommutative();
virtual float approximate(Context& context) = 0;
private:
bool sequentialOperandsIdentity(Expression * e);
bool commutativeOperandsIdentity(Expression * e);
bool combinatoryCommutativeOperandsIdentity(Expression * e, bool * operandMatched,
int leftToMatch);
};
#endif

View File

@@ -66,12 +66,75 @@ Expression * Expression::simplify() {
return result;
}
bool Expression::sequentialOperandsIdentity(Expression * e) {
/* Here we simply test all operands for identity in the order they are defined
* in. */
for (int i=0; i<this->numberOfOperands(); i++) {
if (!e->operand(i)->isIdenticalTo(this->operand(i))) {
return false;
}
}
return true;
}
bool Expression::combinatoryCommutativeOperandsIdentity(Expression * e,
bool * operandMatched, int leftToMatch) {
if (leftToMatch == 0) {
return true;
}
// We try to test for equality the i-th operand of our first expression.
int i = this->numberOfOperands() - leftToMatch;
for (int j = 0; j<e->numberOfOperands(); j++) {
/* If the operand of the second expression has already been associated with
* a previous operand we skip it */
if (operandMatched[j]) {
continue;
}
if (this->operand(i)->isIdenticalTo(e->operand(j))) {
// We managed to match this operand.
operandMatched[j] = true;
/* We check that we can match the rest in this configuration, if so we
* are good. */
if (this->combinatoryCommutativeOperandsIdentity(e, operandMatched, leftToMatch - 1)) {
return true;
}
// Otherwise we backtrack.
operandMatched[j] = false;
}
}
return false;
}
bool Expression::commutativeOperandsIdentity(Expression * e) {
int leftToMatch = this->numberOfOperands();
/* We create a table allowing us to know which operands of the second
* expression have been associated with one of the operands of the first
* expression */
bool * operandMatched = (bool *) malloc (this->numberOfOperands() * sizeof(bool));
for (int i(0); i<this->numberOfOperands(); i++) {
operandMatched[i] = false;
}
// We call our recursive helper.
bool commutativelyIdentical = this->combinatoryCommutativeOperandsIdentity(e, operandMatched, leftToMatch);
free(operandMatched);
return commutativelyIdentical;
}
bool Expression::isIdenticalTo(Expression * e) {
if (e->type() != this->type() || e->numberOfOperands() != this->numberOfOperands()) {
return false;
}
for (int i=0; i<this->numberOfOperands(); i++) {
if (!e->operand(i)->isIdenticalTo(this->operand(i))) {
if (this->isCommutative()) {
if (!this->commutativeOperandsIdentity(e)) {
return false;
}
} else {
if (!this->sequentialOperandsIdentity(e)) {
return false;
}
}

View File

@@ -0,0 +1,36 @@
#include <assert.h>
#include <quiz.h>
#include "simplify_utils.h"
QUIZ_CASE(poincare_identity_simple_term) {
assert(identical_to("1", "1"));
assert(!identical_to("1", "2"));
assert(identical_to("a", "a"));
assert(!identical_to("a", "b"));
assert(identical_to("1+2", "1+2"));
assert(!identical_to("1+2", "1+3"));
assert(identical_to("1-2", "1-2"));
assert(!identical_to("1-2", "1-3"));
assert(identical_to("1*2", "1*2"));
assert(!identical_to("1*2", "1*3"));
assert(identical_to("1/2", "1/2"));
assert(!identical_to("1/2", "1/3"));
assert(identical_to("1^2", "1^2"));
assert(!identical_to("1^2", "1^3"));
assert(identical_to("cos(1)", "cos(1)"));
assert(!identical_to("cos(1)", "cos(2)"));
}
QUIZ_CASE(poincare_identity_commutativity) {
assert(identical_to("1+2", "2+1"));
assert(identical_to("1*2", "2*1"));
assert(!identical_to("1-2", "2-1"));
assert(!identical_to("1/2", "2/1"));
}