Poincare: Add a simplifier

Change-Id: Iac53c9b7dda5cb284fe750bb84c92ce5d1fba497
This commit is contained in:
Romain Goyet
2016-03-23 17:24:11 +01:00
parent 55a76ac530
commit d3b0841af6
23 changed files with 144 additions and 6 deletions

View File

@@ -20,11 +20,15 @@ objs += $(addprefix poincare/src/layout/,\
exponent_layout.o\
string_layout.o\
)
objs += $(addprefix poincare/src/simplify/,\
simplifier_zero.o\
)
tests += $(addprefix poincare/test/,\
addition.cpp\
fraction.cpp\
integer.cpp\
product.cpp\
simplify.cpp\
subtraction.cpp\
)

View File

@@ -5,10 +5,12 @@
class Addition : public Expression {
public:
static const expression_type_t Type = 0x00;
Addition(Expression * first_operand, Expression * second_operand);
~Addition();
ExpressionLayout * createLayout(ExpressionLayout * parent) override;
float approximate(Context& context) override;
expression_type_t type() override;
private:
Expression * m_left;
Expression * m_right;

View File

@@ -5,6 +5,7 @@
#include <kandinsky.h>
class Context;
typedef uint8_t expression_type_t;
class Expression {
public:
@@ -19,7 +20,9 @@ class Expression {
/* identicalTo means strictly the same tree. For example, 3+5 is NOT identi-
* cal to 5+3. Those are equal, but not identical. */
//virtual bool identicalTo(Expression * e);
//virtual Expression * simplify();
Expression * simplify();
virtual expression_type_t type() = 0;
virtual float approximate(Context& context) = 0;
/*private:

View File

@@ -5,11 +5,13 @@
class Float : public Expression {
public:
static const expression_type_t Type = 0x03;
Float(float f);
~Float();
ExpressionLayout * createLayout(ExpressionLayout * parent) override;
float approximate(Context& context) override;
expression_type_t type() override;
private:
float m_float;
};

View File

@@ -5,10 +5,12 @@
class Fraction : public Expression {
public:
static const expression_type_t Type = 0x02;
Fraction(Expression * numerator, Expression * denominator);
~Fraction();
ExpressionLayout * createLayout(ExpressionLayout * parent) override;
float approximate(Context& context) override;
expression_type_t type() override;
private:
Expression * m_numerator;
Expression * m_denominator;

View File

@@ -10,10 +10,12 @@ typedef uint64_t double_native_uint_t;
class Integer : public Expression {
public:
// TODO static const Integer Zero;
static const expression_type_t Type = 0x01;
Integer(native_int_t i);
Integer(Integer&& other); // C++11 move constructor
Integer(const char * string); // NULL-terminated
expression_type_t type() override;
~Integer();
Integer& operator=(Integer&& other); // C++11 move assignment operator
@@ -30,8 +32,8 @@ class Integer : public Expression {
/*virtual Expression ** children();
virtual bool identicalTo(Expression * e);
*/
virtual ExpressionLayout * createLayout(ExpressionLayout * parent);
virtual float approximate(Context& context);
virtual ExpressionLayout * createLayout(ExpressionLayout * parent) override;
virtual float approximate(Context& context) override;
private:
int8_t ucmp(const Integer &other) const; // -1, 0, or 1
Integer usum(const Integer &other, bool subtract, bool output_negative) const;

View File

@@ -5,10 +5,13 @@
class Power : public Expression {
public:
static const expression_type_t Type = 0x04;
Power(Expression * base, Expression * exponent);
~Power();
ExpressionLayout * createLayout(ExpressionLayout * parent) override;
float approximate(Context& context) override;
expression_type_t type() override;
private:
Expression * m_base;
Expression * m_exponent;

View File

@@ -5,11 +5,13 @@
class Product : public Expression {
public:
static const expression_type_t Type = 0x05;
Product(Expression * first_factor, Expression * second_factor);
~Product();
ExpressionLayout * createLayout(ExpressionLayout * parent) override;
float approximate(Context& context) override;
private:
expression_type_t type() override;
//private:
Expression * m_children[2];
};

View File

@@ -5,10 +5,12 @@
class Subtraction : public Expression {
public:
static const expression_type_t Type = 0x06;
Subtraction(Expression * first_operand, Expression * second_operand);
~Subtraction();
ExpressionLayout * createLayout(ExpressionLayout * parent) override;
float approximate(Context& context) override;
expression_type_t type() override;
private:
Expression * m_left;
Expression * m_right;

View File

@@ -5,10 +5,12 @@
class Symbol : public Expression {
public:
static const expression_type_t Type = 0x07;
Symbol(char * name);
~Symbol();
ExpressionLayout * createLayout(ExpressionLayout * parent) override;
float approximate(Context& context) override;
expression_type_t type() override;
private:
char * m_name;
};

View File

@@ -6,6 +6,10 @@ Addition::Addition(Expression * first_operand, Expression * second_operand) {
m_right = second_operand;
}
expression_type_t Addition::type() {
return Addition::Type;
}
Addition::~Addition() {
delete m_left;
delete m_right;

View File

@@ -1,9 +1,19 @@
#include <poincare/expression.h>
#include "expression_parser.hpp"
#include "expression_lexer.hpp"
#include "simplify/simplifier.h"
#include "simplify/simplifier_zero.h"
static expression_simplifier_t kSimplifiers[] = {
&SimplifierZero,
nullptr
};
int poincare_expression_yyparse(yyscan_t scanner, Expression ** expressionOutput);
Expression::~Expression() {
}
Expression * Expression::parse(char * string) {
void * scanner;
poincare_expression_yylex_init(&scanner);
@@ -16,5 +26,20 @@ Expression * Expression::parse(char * string) {
return expression;
}
Expression::~Expression() {
Expression * Expression::simplify() {
Expression * result = this;
expression_simplifier_t * simplifier_pointer = kSimplifiers;
while (expression_simplifier_t simplifier = *simplifier_pointer) {
Expression * simplification = simplifier(result);
if (simplification != nullptr) {
if (result != this) {
delete result;
}
result = simplification;
}
simplifier_pointer++;
}
return result;
}

View File

@@ -11,6 +11,11 @@ float Float::approximate(Context& context) {
return m_float;
}
expression_type_t Float::type() {
return Float::Type;
}
ExpressionLayout * Float::createLayout(ExpressionLayout * parent) {
assert(0); // Should not come here, ever...
return nullptr;

View File

@@ -20,3 +20,8 @@ float Fraction::approximate(Context& context) {
// TODO: handle division by zero
return m_numerator->approximate(context)/m_denominator->approximate(context);
}
expression_type_t Fraction::type() {
return Fraction::Type;
}

View File

@@ -305,6 +305,10 @@ float Integer::approximate(Context& context) {
return float_result;
}
expression_type_t Integer::type() {
return Integer::Type;
}
ExpressionLayout * Integer::createLayout(ExpressionLayout * parent) {
char buffer[255];

View File

@@ -16,6 +16,11 @@ float Power::approximate(Context& context) {
return powf(m_base->approximate(context), m_exponent->approximate(context));
}
expression_type_t Power::type() {
return Power::Type;
}
ExpressionLayout * Power::createLayout(ExpressionLayout * parent) {
return new ExponentLayout(parent, m_base, m_exponent);
}

View File

@@ -15,6 +15,11 @@ float Product::approximate(Context& context) {
return m_children[0]->approximate(context) * m_children[1]->approximate(context);
}
expression_type_t Product::type() {
return Product::Type;
}
ExpressionLayout * Product::createLayout(ExpressionLayout * parent) {
return new HorizontalLayout(parent, m_children[0], '*', m_children[1]);
}

View File

@@ -0,0 +1,8 @@
#ifndef POINCARE_SIMPLIFIER_H
#define POINCARE_SIMPLIFIER_H
#include <poincare/expression.h>
typedef Expression * (*expression_simplifier_t)(Expression *);
#endif

View File

@@ -0,0 +1,20 @@
#include "simplifier_zero.h"
#include <poincare/product.h>
#include <poincare/integer.h>
Expression * SimplifierZero(Expression * e) {
if (e->type() != Product::Type) {
return nullptr;
}
Product * p = (Product *)e;
for (int i=0; i<2; i++) {
Expression * factor = p->m_children[i];
if (factor->type() == Integer::Type) {
Integer * integer = (Integer *)factor;
if (*integer == Integer((native_int_t)0)) {
return new Integer("0");
}
}
}
return nullptr;
}

View File

@@ -0,0 +1,8 @@
#ifndef POINCARE_SIMPLIFIER_ZERO_H
#define POINCARE_SIMPLIFIER_ZERO_H
#include "simplifier.h"
Expression * SimplifierZero(Expression * e);
#endif

View File

@@ -15,6 +15,11 @@ float Subtraction::approximate(Context& context) {
return m_left->approximate(context) - m_right->approximate(context);
}
expression_type_t Subtraction::type() {
return Subtraction::Type;
}
ExpressionLayout * Subtraction::createLayout(ExpressionLayout * parent) {
return new HorizontalLayout(parent, m_left, '-', m_right);
}

View File

@@ -18,6 +18,10 @@ float Symbol::approximate(Context& context) {
return context[m_name]->approximate(context);
}
expression_type_t Symbol::type() {
return Symbol::Type;
}
ExpressionLayout * Symbol::createLayout(ExpressionLayout * parent) {
size_t length = strlen(m_name);
return new StringLayout(parent, m_name, length);

View File

@@ -0,0 +1,16 @@
#include <quiz.h>
#include <poincare.h>
#include <assert.h>
QUIZ_CASE(poincare_simplify) {
{
Expression * e = Expression::parse((char *)"3*0");
Expression * e2 = e->simplify();
assert(e2->type() == Integer::Type);
}
{
Expression * e = Expression::parse((char *)"0*foo");
Expression * e2 = e->simplify();
assert(e2->type() == Integer::Type);
}
}