From 648cdbaa29222cda1f9fb672bfa95fa8d8a65211 Mon Sep 17 00:00:00 2001 From: Gabriel Ozouf Date: Tue, 19 May 2020 17:58:46 +0200 Subject: [PATCH] [poincare] Implemented didDerivate method for Power Derivation now propagates to powers as expected, whether the base, the exponent, or both are functions of the variable. This also makes division derive as intended. Change-Id: I51cbd5f7ec9f6aaa1df068625bbda1437941fa08 --- poincare/include/poincare/power.h | 2 ++ poincare/src/power.cpp | 46 +++++++++++++++++++++++++++++++ poincare/test/derivative.cpp | 15 +++++----- 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/poincare/include/poincare/power.h b/poincare/include/poincare/power.h index 815dc065c..1d6ebe70a 100644 --- a/poincare/include/poincare/power.h +++ b/poincare/include/poincare/power.h @@ -55,6 +55,7 @@ private: int simplificationOrderGreaterType(const ExpressionNode * e, bool ascending, bool canBeInterrupted, bool ignoreParentheses) const override; int simplificationOrderSameType(const ExpressionNode * e, bool ascending, bool canBeInterrupted, bool ignoreParentheses) const override; Expression denominator(ReductionContext reductionContext) const override; + bool didDerivate(ReductionContext reductionContext, Expression symbol, Expression symbolValue) override; // Evaluation template static MatrixComplex computeOnComplexAndMatrix(const std::complex c, const MatrixComplex n, Preferences::ComplexFormat complexFormat); template static MatrixComplex computeOnMatrixAndComplex(const MatrixComplex m, const std::complex d, Preferences::ComplexFormat complexFormat); @@ -79,6 +80,7 @@ public: int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const; Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); Expression shallowBeautify(ExpressionNode::ReductionContext reductionContext); + bool didDerivate(ExpressionNode::ReductionContext reductionContext, Expression symbol, Expression symbolValue); private: constexpr static int k_maxExactPowerMatrix = 100; diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index 7d6f48ed8..a8d801ce0 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -251,6 +252,10 @@ Expression PowerNode::denominator(ReductionContext reductionContext) const { return Power(this).denominator(reductionContext); } +bool PowerNode::didDerivate(ReductionContext reductionContext, Expression symbol, Expression symbolValue) { + return Power(this).didDerivate(reductionContext, symbol, symbolValue); +} + // Evaluation template MatrixComplex PowerNode::computeOnComplexAndMatrix(const std::complex c, const MatrixComplex n, Preferences::ComplexFormat complexFormat) { return MatrixComplex::Undefined(); @@ -1015,6 +1020,47 @@ Expression Power::shallowBeautify(ExpressionNode::ReductionContext reductionCont return *this; } +bool Power::didDerivate(ExpressionNode::ReductionContext reductionContext, Expression symbol, Expression symbolValue) { + /* Generalized power derivation formula + * (f^g)` = (e^(g * ln(f)))` + * = (g * ln(f))` * f^g + * = (g`ln(f) + gf`/f) * f^g + * = g`ln(f)f^g + gf`f^(g-1) + * + * Valid whenever f,g are derivable and f > 0 */ + + /* We might want to be able to derivate f^n when f <= 0 and n is a positive + * integer */ + + Expression base = childAtIndex(0); + Expression exponent = childAtIndex(1); + Multiplication derivedFromBase = Multiplication::Builder(); + Multiplication derivedFromExponent = Multiplication::Builder(); + + derivedFromExponent.addChildAtIndexInPlace(NaperianLogarithm::Builder(base.clone()), 0, 0); + derivedFromExponent.addChildAtIndexInPlace(clone(), 1, 1); + derivedFromExponent.addChildAtIndexInPlace(Derivative::Builder( + exponent.clone(), + symbol.clone().convert(), + symbolValue.clone() + ), 2, 2); + + derivedFromBase.addChildAtIndexInPlace(exponent.clone() , 0, 0); + derivedFromBase.addChildAtIndexInPlace(Power::Builder( + base.clone(), + Subtraction::Builder(exponent.clone(), Rational::Builder(1)) + ), 1, 1); + derivedFromBase.addChildAtIndexInPlace(Derivative::Builder( + base.clone(), + symbol.clone().convert(), + symbolValue.clone() + ), 2, 2); + + Addition result = Addition::Builder(derivedFromBase, derivedFromExponent); + replaceWithInPlace(result); + return true; +} + // Private // Simplification diff --git a/poincare/test/derivative.cpp b/poincare/test/derivative.cpp index 21be79100..cb16ff8b7 100644 --- a/poincare/test/derivative.cpp +++ b/poincare/test/derivative.cpp @@ -7,12 +7,6 @@ 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); -} - void assert_parses_and_reduces_as(const char * expression, const char * derivative) { Shared::GlobalContext globalContext; Expression e = parse_expression(expression, &globalContext, false); @@ -32,8 +26,15 @@ QUIZ_CASE(poincare_differential_addition) { assert_parses_and_reduces_as("diff(x+x,x,4)", "2"); assert_parses_and_reduces_as("diff(2*x,x,1)", "2"); + assert_parses_and_reduces_as("diff(-x,x,1)", "-1"); + assert_parses_and_reduces_as("diff(3-x,x,1)", "-1"); assert_parses_and_reduces_as("diff(a*x,x,2)", "a"); assert_parses_and_reduces_as("diff(a*x+b,x,x)", "a"); - // assert_parses_and_reduces_as("diff(x*x,x,3)", "3"); + assert_parses_and_reduces_as("diff(x*x,x,3)", "6"); + assert_parses_and_reduces_as("diff(x^2,x,2)", "4"); + assert_parses_and_reduces_as("diff(2^x,x,0)", "ln(2)"); + assert_parses_and_reduces_as("diff(x^2,x,x)", "2*x"); + assert_parses_and_reduces_as("diff(a*x^2+b*x+c,x,x)", "2*a*x+b"); + assert_parses_and_reduces_as("diff(1/x,x,1)", "-1"); } \ No newline at end of file