[poincare] Parametered expression

This commit is contained in:
Léa Saviot
2019-04-08 11:31:52 +02:00
committed by Émilie Feral
parent f95cbd4998
commit 3dc8c11347
14 changed files with 97 additions and 101 deletions

View File

@@ -96,7 +96,7 @@ src += $(addprefix poincare/src/,\
nth_root.cpp \
number.cpp \
opposite.cpp \
parametered_expression_helper.cpp \
parametered_expression.cpp \
parenthesis.cpp \
permute_coefficient.cpp \
power.cpp \

View File

@@ -1,13 +1,13 @@
#ifndef POINCARE_DERIVATIVE_H
#define POINCARE_DERIVATIVE_H
#include <poincare/expression.h>
#include <poincare/parametered_expression.h>
#include <poincare/symbol.h>
#include <poincare/variable_context.h>
namespace Poincare {
class DerivativeNode final : public ExpressionNode {
class DerivativeNode final : public ParameteredExpressionNode {
public:
// TreeNode
@@ -25,7 +25,6 @@ public:
// Properties
Type type() const override { return Type::Derivative; }
int polynomialDegree(Context & context, const char * symbolName) const override;
Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) override;
private:
// Layout
@@ -48,9 +47,9 @@ private:
constexpr static double k_rateStepSize = 1.4;
};
class Derivative final : public Expression {
class Derivative final : public ParameteredExpression {
public:
Derivative(const DerivativeNode * n) : Expression(n) {}
Derivative(const DerivativeNode * n) : ParameteredExpression(n) {}
static Derivative Builder(Expression child0, Symbol child1, Expression child2) { return TreeHandle::FixedArityBuilder<Derivative, DerivativeNode>(ArrayBuilder<TreeHandle>(child0, child1, child2).array(), 3); }
static Expression UntypedBuilder(Expression children);
static constexpr Expression::FunctionHelper s_functionHelper = Expression::FunctionHelper("diff", 3, &UntypedBuilder);

View File

@@ -1,12 +1,12 @@
#ifndef POINCARE_INTEGRAL_H
#define POINCARE_INTEGRAL_H
#include <poincare/expression.h>
#include <poincare/parametered_expression.h>
#include <poincare/symbol.h>
namespace Poincare {
class IntegralNode final : public ExpressionNode {
class IntegralNode final : public ParameteredExpressionNode {
public:
// TreeNode
@@ -21,7 +21,6 @@ public:
// ExpressionNode
Type type() const override { return Type::Integral; }
int polynomialDegree(Context & context, const char * symbolName) const override;
Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) override;
// Complex
bool isReal(Context & context) const override { return true; }
@@ -52,9 +51,9 @@ private:
template<typename T> T functionValueAtAbscissa(T x, Context & xcontext, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
};
class Integral final : public Expression {
class Integral final : public ParameteredExpression {
public:
Integral(const IntegralNode * n) : Expression(n) {}
Integral(const IntegralNode * n) : ParameteredExpression(n) {}
static Integral Builder(Expression child0, Symbol child1, Expression child2, Expression child3) { return TreeHandle::FixedArityBuilder<Integral, IntegralNode>(ArrayBuilder<TreeHandle>(child0, child1, child2, child3).array(), 4); }
static Expression UntypedBuilder(Expression children);

View File

@@ -0,0 +1,45 @@
#ifndef POINCARE_PARAMETERED_EXPRESSION_H
#define POINCARE_PARAMETERED_EXPRESSION_H
#include <poincare/expression.h>
namespace Poincare {
/* Parametered expressions are Integral, Derivative, Sum and Product. Their
* child at index 0 is parametered, and the child at index 1 is the parameter
* symbol. */
class ParameteredExpressionNode : public ExpressionNode {
public:
// Expression
Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) override;
};
class ParameteredExpression : public Expression {
friend class ParameteredExpressionNode;
public:
// ParameteredExpression
static constexpr int ParameteredChildIndex() { return 0; }
static constexpr int ParameterChildIndex() { return 1; }
// Expression
/* We sometimes replace 'x' by 'UnknownX' to differentiate between a variable
* and a function parameter. For instance, when defining the function
* f(x)=cos(x) in Graph, we want x to be an unknown, instead of having f be
* the constant function equal to cos(user variable that is named x).
*
* In parametered expressions, we do not want to replace all the 'x' with
* unknowns: for instance, we want to change f(x)=diff(cos(x),x,x) into
* f(X)=diff(cos(x),x,X), X being an unknown. ReplaceUnknownInExpression does
* that. */
Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol);
protected:
ParameteredExpression(const ParameteredExpressionNode * node) : Expression(node) {}
};
static_assert(ParameteredExpression::ParameteredChildIndex() == 0, "ParameteredExpression::replaceUnknown might not be valid");
static_assert(ParameteredExpression::ParameterChildIndex() == 1, "ParameteredExpression::replaceUnknown might not be valid");
}
#endif

View File

@@ -1,28 +0,0 @@
#ifndef POINCARE_PARAMETERED_EXPRESSION_HELPER_H
#define POINCARE_PARAMETERED_EXPRESSION_HELPER_H
#include <poincare/expression.h>
namespace Poincare {
class SymbolAbstract;
class Symbol;
// Parametered expressions are Integral, Derivative, Sum and Product.
namespace ParameteredExpressionHelper {
/* We sometimes replace 'x' by 'UnknownX' to differentiate between a variable
* and a function parameter. For instance, when defining the function
* f(x)=cos(x) in Graph, we want x to be an unknown, instead of having f be
* the constant function equal to cos(user variable that is named x).
*
* In parametered expression, we do not want to replace all the 'x' with
* unknowns: for instance, we want to change f(x)=diff(cos(x),x,x) into
* f(X)=diff(cos(x),x,X), X being an unknown. ReplaceUnknownInExpression does
* that. */
Expression ReplaceUnknownInExpression(Expression e, const Symbol & symbolToReplace, const Symbol & unknownSymbols);
};
}
#endif

View File

@@ -16,7 +16,6 @@ public:
#endif
Type type() const override { return Type::Product; }
Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) override;
private:
float emptySequenceValue() const override { return 1.0f; }
@@ -31,10 +30,10 @@ private:
template<typename T> Evaluation<T> templatedApproximateWithNextTerm(Evaluation<T> a, Evaluation<T> b, Preferences::ComplexFormat complexFormat) const;
};
class Product final : public Expression {
class Product final : public ParameteredExpression {
friend class ProductNode;
public:
Product(const ProductNode * n) : Expression(n) {}
Product(const ProductNode * n) : ParameteredExpression(n) {}
static Product Builder(Expression child0, Symbol child1, Expression child2, Expression child3) { return TreeHandle::FixedArityBuilder<Product, ProductNode>(ArrayBuilder<TreeHandle>(child0, child1, child2, child3).array(), 4); }
static Expression UntypedBuilder(Expression children);

View File

@@ -1,13 +1,15 @@
#ifndef POINCARE_SEQUENCE_H
#define POINCARE_SEQUENCE_H
#include <poincare/expression.h>
#include <poincare/parametered_expression.h>
#include <poincare/symbol.h>
#include <poincare/approximation_helper.h>
namespace Poincare {
class SequenceNode : public ExpressionNode {
// Sequences are Product and Sum
class SequenceNode : public ParameteredExpressionNode {
public:
int numberOfChildren() const override { return 4; }
private:

View File

@@ -16,7 +16,6 @@ public:
#endif
Type type() const override { return Type::Sum; }
Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) override;
private:
float emptySequenceValue() const override { return 0.0f; }
@@ -31,10 +30,10 @@ private:
template<typename T> Evaluation<T> templatedApproximateWithNextTerm(Evaluation<T> a, Evaluation<T> b, Preferences::ComplexFormat complexFormat) const;
};
class Sum final : public Expression {
class Sum final : public ParameteredExpression {
friend class SumNode;
public:
Sum(const SumNode * n) : Expression(n) {}
Sum(const SumNode * n) : ParameteredExpression(n) {}
static Sum Builder(Expression child0, Symbol child1, Expression child2, Expression child3) { return TreeHandle::FixedArityBuilder<Sum, SumNode>(ArrayBuilder<TreeHandle>(child0, child1, child2, child3).array(), 4); }
static Expression UntypedBuilder(Expression children);

View File

@@ -1,6 +1,5 @@
#include <poincare/derivative.h>
#include <poincare/layout_helper.h>
#include <poincare/parametered_expression_helper.h>
#include <poincare/serialization_helper.h>
#include <poincare/simplification_helper.h>
#include <poincare/symbol.h>
@@ -27,10 +26,6 @@ int DerivativeNode::polynomialDegree(Context & context, const char * symbolName)
return ExpressionNode::polynomialDegree(context, symbolName);
}
Expression DerivativeNode::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) {
return ParameteredExpressionHelper::ReplaceUnknownInExpression(Derivative(this), symbol, unknownSymbol);
}
Layout DerivativeNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
return LayoutHelper::Prefix(this, floatDisplayMode, numberOfSignificantDigits, Derivative::s_functionHelper.name());
}

View File

@@ -1,8 +1,6 @@
#include <poincare/integral.h>
#include <poincare/complex.h>
#include <poincare/integral_layout.h>
#include <poincare/parametered_expression_helper.h>
#include <poincare/serialization_helper.h>
#include <poincare/symbol.h>
#include <poincare/undefined.h>
@@ -29,10 +27,6 @@ int IntegralNode::polynomialDegree(Context & context, const char * symbolName) c
return ExpressionNode::polynomialDegree(context, symbolName);
}
Expression IntegralNode::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) {
return ParameteredExpressionHelper::ReplaceUnknownInExpression(Integral(this), symbol, unknownSymbol);
}
Layout IntegralNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
return IntegralLayout::Builder(
childAtIndex(0)->createLayout(floatDisplayMode, numberOfSignificantDigits),

View File

@@ -0,0 +1,35 @@
#include <poincare/parametered_expression.h>
#include <poincare/symbol.h>
#include <string.h>
#include <assert.h>
namespace Poincare {
Expression ParameteredExpressionNode::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) {
return ParameteredExpression(this).replaceUnknown(symbol, unknownSymbol);
}
Expression ParameteredExpression::replaceUnknown(const Symbol & symbolToReplace, const Symbol & unknownSymbol) {
assert(!symbolToReplace.isUninitialized());
assert(symbolToReplace.type() == ExpressionNode::Type::Symbol);
Expression c = childAtIndex(ParameterChildIndex());
assert(c.type() == ExpressionNode::Type::Symbol);
Symbol& parameterChild = static_cast<Symbol &>(c);
if (strcmp(parameterChild.name(), symbolToReplace.name()) != 0) {
// If the unknown is not the parameter, replace normally
return defaultReplaceUnknown(symbolToReplace, unknownSymbol);
}
/* If the unknown is the parameter, replace the unknown in all children except
* in the parameter and the parametered children */
int childrenCount = numberOfChildren();
assert(ParameteredChildIndex() == 0);
assert(ParameterChildIndex() == 1);
for (int i = 2; i < childrenCount; i++) {
childAtIndex(i).replaceUnknown(symbolToReplace, unknownSymbol);
}
return *this;
}
}

View File

@@ -1,33 +0,0 @@
#include <poincare/parametered_expression_helper.h>
#include <poincare/symbol.h>
#include <string.h>
#include <assert.h>
namespace Poincare {
Expression ParameteredExpressionHelper::ReplaceUnknownInExpression(Expression e, const Symbol & symbolToReplace, const Symbol & unknownSymbol) {
assert(!e.isUninitialized());
assert(e.type() == ExpressionNode::Type::Integral
|| e.type() == ExpressionNode::Type::Derivative
|| e.type() == ExpressionNode::Type::Sum
|| e.type() == ExpressionNode::Type::Product);
assert(!symbolToReplace.isUninitialized());
assert(symbolToReplace.type() == ExpressionNode::Type::Symbol);
int numberOfChildren = e.numberOfChildren();
assert(numberOfChildren > 2);
Expression child1 = e.childAtIndex(1);
assert(child1.type() == ExpressionNode::Type::Symbol);
Symbol& parameterChild = static_cast<Symbol &>(child1);
if (strcmp(parameterChild.name(), symbolToReplace.name()) != 0) {
return e.defaultReplaceUnknown(symbolToReplace, unknownSymbol);
}
for (int i = 2; i < numberOfChildren; i++) {
e.childAtIndex(i).replaceUnknown(symbolToReplace, unknownSymbol);
}
return e;
}
}

View File

@@ -1,6 +1,5 @@
#include <poincare/product.h>
#include <poincare/multiplication.h>
#include <poincare/parametered_expression_helper.h>
#include <poincare/product_layout.h>
#include <poincare/layout_helper.h>
#include <poincare/serialization_helper.h>
@@ -14,10 +13,6 @@ namespace Poincare {
constexpr Expression::FunctionHelper Product::s_functionHelper;
Expression ProductNode::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) {
return ParameteredExpressionHelper::ReplaceUnknownInExpression(Product(this), symbol, unknownSymbol);
}
Layout ProductNode::createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const {
return ProductLayout::Builder(argumentLayout, symbolLayout, subscriptLayout, superscriptLayout);
}

View File

@@ -2,7 +2,6 @@
#include <poincare/addition.h>
#include <poincare/sum_layout.h>
#include <poincare/layout_helper.h>
#include <poincare/parametered_expression_helper.h>
#include <poincare/serialization_helper.h>
extern "C" {
#include <assert.h>
@@ -14,10 +13,6 @@ namespace Poincare {
constexpr Expression::FunctionHelper Sum::s_functionHelper;
Expression SumNode::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) {
return ParameteredExpressionHelper::ReplaceUnknownInExpression(Sum(this), symbol, unknownSymbol);
}
Layout SumNode::createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const {
return SumLayout::Builder(argumentLayout, symbolLayout, subscriptLayout, superscriptLayout);
}