[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
This commit is contained in:
Gabriel Ozouf
2020-05-19 11:25:59 +02:00
committed by Émilie Feral
parent eed1648363
commit 051e608835
7 changed files with 54 additions and 5 deletions

View File

@@ -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\

View File

@@ -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);
};
}

View File

@@ -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<typename U> Evaluation<U> approximateToEvaluation(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;

View File

@@ -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 */

View File

@@ -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<typename T>
@@ -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<Symbol>();
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) {

View File

@@ -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]) {

View File

@@ -0,0 +1,18 @@
#include <poincare/derivative.h>
#include <poincare/init.h>
#include <poincare/src/parsing/parser.h>
#include <poincare_nodes.h>
#include <apps/shared/global_context.h>
#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) {
}