From d3b0841af6cb96ac430fb6d07f5459923176504b Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Wed, 23 Mar 2016 17:24:11 +0100 Subject: [PATCH] Poincare: Add a simplifier Change-Id: Iac53c9b7dda5cb284fe750bb84c92ce5d1fba497 --- poincare/Makefile | 4 ++++ poincare/include/poincare/addition.h | 2 ++ poincare/include/poincare/expression.h | 5 ++++- poincare/include/poincare/float.h | 2 ++ poincare/include/poincare/fraction.h | 2 ++ poincare/include/poincare/integer.h | 8 ++++--- poincare/include/poincare/power.h | 3 +++ poincare/include/poincare/product.h | 4 +++- poincare/include/poincare/subtraction.h | 2 ++ poincare/include/poincare/symbol.h | 2 ++ poincare/src/addition.cpp | 4 ++++ poincare/src/expression.cpp | 27 ++++++++++++++++++++++- poincare/src/float.cpp | 5 +++++ poincare/src/fraction.cpp | 5 +++++ poincare/src/integer.cpp | 4 ++++ poincare/src/power.cpp | 5 +++++ poincare/src/product.cpp | 5 +++++ poincare/src/simplify/simplifier.h | 8 +++++++ poincare/src/simplify/simplifier_zero.cpp | 20 +++++++++++++++++ poincare/src/simplify/simplifier_zero.h | 8 +++++++ poincare/src/subtraction.cpp | 5 +++++ poincare/src/symbol.cpp | 4 ++++ poincare/test/simplify.cpp | 16 ++++++++++++++ 23 files changed, 144 insertions(+), 6 deletions(-) create mode 100644 poincare/src/simplify/simplifier.h create mode 100644 poincare/src/simplify/simplifier_zero.cpp create mode 100644 poincare/src/simplify/simplifier_zero.h create mode 100644 poincare/test/simplify.cpp diff --git a/poincare/Makefile b/poincare/Makefile index 97c090c0d..6233ea1c3 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -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\ ) diff --git a/poincare/include/poincare/addition.h b/poincare/include/poincare/addition.h index 7039f59d2..be77c56b8 100644 --- a/poincare/include/poincare/addition.h +++ b/poincare/include/poincare/addition.h @@ -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; diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 69237bffb..707913c9d 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -5,6 +5,7 @@ #include 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: diff --git a/poincare/include/poincare/float.h b/poincare/include/poincare/float.h index 0ced2a0e8..bddc48e0b 100644 --- a/poincare/include/poincare/float.h +++ b/poincare/include/poincare/float.h @@ -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; }; diff --git a/poincare/include/poincare/fraction.h b/poincare/include/poincare/fraction.h index 4ea0446f2..0a5f7f0f1 100644 --- a/poincare/include/poincare/fraction.h +++ b/poincare/include/poincare/fraction.h @@ -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; diff --git a/poincare/include/poincare/integer.h b/poincare/include/poincare/integer.h index f168fa2e5..2e61b10b6 100644 --- a/poincare/include/poincare/integer.h +++ b/poincare/include/poincare/integer.h @@ -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; diff --git a/poincare/include/poincare/power.h b/poincare/include/poincare/power.h index 295067ff3..f2c580c25 100644 --- a/poincare/include/poincare/power.h +++ b/poincare/include/poincare/power.h @@ -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; diff --git a/poincare/include/poincare/product.h b/poincare/include/poincare/product.h index ea3b8f3a1..6b62782d4 100644 --- a/poincare/include/poincare/product.h +++ b/poincare/include/poincare/product.h @@ -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]; }; diff --git a/poincare/include/poincare/subtraction.h b/poincare/include/poincare/subtraction.h index 911387bd6..3411f84cd 100644 --- a/poincare/include/poincare/subtraction.h +++ b/poincare/include/poincare/subtraction.h @@ -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; diff --git a/poincare/include/poincare/symbol.h b/poincare/include/poincare/symbol.h index 6f0c1b8b2..c259b9a62 100644 --- a/poincare/include/poincare/symbol.h +++ b/poincare/include/poincare/symbol.h @@ -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; }; diff --git a/poincare/src/addition.cpp b/poincare/src/addition.cpp index 60781950a..e39f34e86 100644 --- a/poincare/src/addition.cpp +++ b/poincare/src/addition.cpp @@ -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; diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index f5b2ed4e1..c6733f9b6 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -1,9 +1,19 @@ #include #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; } + diff --git a/poincare/src/float.cpp b/poincare/src/float.cpp index 61a1b5874..94426454f 100644 --- a/poincare/src/float.cpp +++ b/poincare/src/float.cpp @@ -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; diff --git a/poincare/src/fraction.cpp b/poincare/src/fraction.cpp index bfa23160f..a974558ed 100644 --- a/poincare/src/fraction.cpp +++ b/poincare/src/fraction.cpp @@ -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; +} + diff --git a/poincare/src/integer.cpp b/poincare/src/integer.cpp index 0074d6760..c8b7b90fb 100644 --- a/poincare/src/integer.cpp +++ b/poincare/src/integer.cpp @@ -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]; diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index 39e435e62..e6713aab5 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -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); } diff --git a/poincare/src/product.cpp b/poincare/src/product.cpp index 2f5f28618..831eb6bc9 100644 --- a/poincare/src/product.cpp +++ b/poincare/src/product.cpp @@ -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]); } diff --git a/poincare/src/simplify/simplifier.h b/poincare/src/simplify/simplifier.h new file mode 100644 index 000000000..2216f0f2c --- /dev/null +++ b/poincare/src/simplify/simplifier.h @@ -0,0 +1,8 @@ +#ifndef POINCARE_SIMPLIFIER_H +#define POINCARE_SIMPLIFIER_H + +#include + +typedef Expression * (*expression_simplifier_t)(Expression *); + +#endif diff --git a/poincare/src/simplify/simplifier_zero.cpp b/poincare/src/simplify/simplifier_zero.cpp new file mode 100644 index 000000000..cb9a07fa1 --- /dev/null +++ b/poincare/src/simplify/simplifier_zero.cpp @@ -0,0 +1,20 @@ +#include "simplifier_zero.h" +#include +#include + +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; +} diff --git a/poincare/src/simplify/simplifier_zero.h b/poincare/src/simplify/simplifier_zero.h new file mode 100644 index 000000000..6ffd71bd7 --- /dev/null +++ b/poincare/src/simplify/simplifier_zero.h @@ -0,0 +1,8 @@ +#ifndef POINCARE_SIMPLIFIER_ZERO_H +#define POINCARE_SIMPLIFIER_ZERO_H + +#include "simplifier.h" + +Expression * SimplifierZero(Expression * e); + +#endif diff --git a/poincare/src/subtraction.cpp b/poincare/src/subtraction.cpp index 48892e7bc..8c0a93248 100644 --- a/poincare/src/subtraction.cpp +++ b/poincare/src/subtraction.cpp @@ -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); } diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index 113eff72a..1b084416c 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -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); diff --git a/poincare/test/simplify.cpp b/poincare/test/simplify.cpp new file mode 100644 index 000000000..de595f1d3 --- /dev/null +++ b/poincare/test/simplify.cpp @@ -0,0 +1,16 @@ +#include +#include +#include + +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); + } +}