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