From 051e6088357bfdb8cc9727d07de845ea45234ab3 Mon Sep 17 00:00:00 2001 From: Gabriel Ozouf Date: Tue, 19 May 2020 11:25:59 +0200 Subject: [PATCH] [poincare] Added method didDerivate to Expression and ExpressionNode This method is to be implemented by derivable expression subclasses, for use in Derivative::shallowReduce. It performs the calculation for the derivative, and returns whether calculations happened. Change-Id: I13cdb131e2044578392f5178a9f389314c1c4c8a --- poincare/Makefile | 1 + poincare/include/poincare/derivative.h | 2 +- poincare/include/poincare/expression.h | 7 ++++++ poincare/include/poincare/expression_node.h | 1 + poincare/src/derivative.cpp | 26 +++++++++++++++++---- poincare/src/expression_node.cpp | 4 ++++ poincare/test/derivative.cpp | 18 ++++++++++++++ 7 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 poincare/test/derivative.cpp diff --git a/poincare/Makefile b/poincare/Makefile index bac81600c..b1f4215c6 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -162,6 +162,7 @@ tests_src += $(addprefix poincare/test/,\ arithmetic.cpp\ context.cpp\ erf_inv.cpp \ + derivative.cpp\ expression.cpp\ expression_order.cpp\ expression_properties.cpp\ diff --git a/poincare/include/poincare/derivative.h b/poincare/include/poincare/derivative.h index ad622c73b..bfa1a7319 100644 --- a/poincare/include/poincare/derivative.h +++ b/poincare/include/poincare/derivative.h @@ -53,7 +53,7 @@ public: static Expression UntypedBuilder(Expression children); static constexpr Expression::FunctionHelper s_functionHelper = Expression::FunctionHelper("diff", 3, &UntypedBuilder); - Expression shallowReduce(Context * context); + Expression shallowReduce(ExpressionNode::ReductionContext context); }; } diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 6bdb4008e..05944ba41 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -380,6 +380,12 @@ protected: // WARNING: this must be called on reduced expressions Expression setSign(ExpressionNode::Sign s, ExpressionNode::ReductionContext reductionContext); + /* Derivation */ + /* This method is used for the reduction of Derivative expressions. + * It returns whether the instance is differentiable, and differentiates it if + * able. */ + bool didDerivate(ExpressionNode::ReductionContext reductionContext, Expression symbol, Expression symbolValue) { return node()->didDerivate(reductionContext, symbol, symbolValue); } + private: static constexpr int k_maxSymbolReplacementsCount = 10; static bool sSymbolReplacementsCountLock; @@ -407,6 +413,7 @@ private: Expression defaultHandleUnitsInChildren(); // Children must be reduced Expression shallowReduceUsingApproximation(ExpressionNode::ReductionContext reductionContext); Expression defaultShallowBeautify() { return *this; } + bool defaultDidDerivate() { return false; } /* Approximation */ template Evaluation approximateToEvaluation(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; diff --git a/poincare/include/poincare/expression_node.h b/poincare/include/poincare/expression_node.h index 2d3b33a33..4ab8b1c64 100644 --- a/poincare/include/poincare/expression_node.h +++ b/poincare/include/poincare/expression_node.h @@ -223,6 +223,7 @@ public: /*!*/ virtual void deepReduceChildren(ReductionContext reductionContext); /*!*/ virtual Expression shallowReduce(ReductionContext reductionContext); /*!*/ virtual Expression shallowBeautify(ReductionContext reductionContext); + /*!*/ virtual bool didDerivate(ReductionContext, Expression symbol, Expression symbolValue); /* Return a clone of the denominator part of the expression */ /*!*/ virtual Expression denominator(ExpressionNode::ReductionContext reductionContext) const; /* LayoutShape is used to check if the multiplication sign can be omitted between two expressions. It depends on the "layout syle" of the on the right of the left expression */ diff --git a/poincare/src/derivative.cpp b/poincare/src/derivative.cpp index 3a9b857a8..c010f2108 100644 --- a/poincare/src/derivative.cpp +++ b/poincare/src/derivative.cpp @@ -36,7 +36,7 @@ int DerivativeNode::serialize(char * buffer, int bufferSize, Preferences::PrintF } Expression DerivativeNode::shallowReduce(ReductionContext reductionContext) { - return Derivative(this).shallowReduce(reductionContext.context()); + return Derivative(this).shallowReduce(reductionContext); } template @@ -151,7 +151,7 @@ T DerivativeNode::riddersApproximation(Context * context, Preferences::ComplexFo return ans; } -Expression Derivative::shallowReduce(Context * context) { +Expression Derivative::shallowReduce(ExpressionNode::ReductionContext reductionContext) { { Expression e = Expression::defaultShallowReduce(); e = e.defaultHandleUnitsInChildren(); @@ -159,12 +159,30 @@ Expression Derivative::shallowReduce(Context * context) { return e; } } + Context * context = reductionContext.context(); assert(!childAtIndex(1).deepIsMatrix(context)); if (childAtIndex(0).deepIsMatrix(context) || childAtIndex(2).deepIsMatrix(context)) { return replaceWithUndefinedInPlace(); } - // TODO: to be implemented diff(+) -> +diff() etc - return *this; + + Expression derivand = childAtIndex(0); + Symbol symbol = childAtIndex(1).convert(); + Expression symbolValue = childAtIndex(2); + + /* Since derivand is a child to the derivative node, it can be replaced in + * place without didDerivate having to return the derivative. */ + if (!derivand.didDerivate(reductionContext, symbol, symbolValue)) { + return *this; + } + /* Updates the value of derivand, because didDerivate may call + * replaceWithInplace on it */ + derivand = childAtIndex(0); + /* Deep reduces the child, because didDerivate may not preserve its reduced + * status. */ + derivand = derivand.deepReduce(reductionContext); + replaceWithInPlace(derivand); + return derivand; + } Expression Derivative::UntypedBuilder(Expression children) { diff --git a/poincare/src/expression_node.cpp b/poincare/src/expression_node.cpp index fe117da7e..5c02fe3e5 100644 --- a/poincare/src/expression_node.cpp +++ b/poincare/src/expression_node.cpp @@ -127,6 +127,10 @@ Expression ExpressionNode::shallowBeautify(ReductionContext reductionContext) { return Expression(this).defaultShallowBeautify(); } +bool ExpressionNode::didDerivate(ReductionContext reductionContext, Expression symbol, Expression symbolValue) { + return Expression(this).defaultDidDerivate(); +} + bool ExpressionNode::isOfType(Type * types, int length) const { for (int i = 0; i < length; i++) { if (type() == types[i]) { diff --git a/poincare/test/derivative.cpp b/poincare/test/derivative.cpp new file mode 100644 index 000000000..8fe59061b --- /dev/null +++ b/poincare/test/derivative.cpp @@ -0,0 +1,18 @@ +#include +#include +#include +#include +#include +#include "helper.h" + +using namespace Poincare; + +void assert_differentiates_as(Expression expression, Expression derivative, const char * information) { + Shared::GlobalContext globalContext; + Expression expressionReduced = expression.reduce(ExpressionNode::ReductionContext(&globalContext, Cartesian, Radian, User)); + quiz_assert_print_if_failure(expressionReduced.isIdenticalTo(derivative), information); +} + +QUIZ_CASE(poincare_differential_addition) { + +} \ No newline at end of file