[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
This commit is contained in:
Gabriel Ozouf
2020-05-19 17:58:46 +02:00
committed by Émilie Feral
parent 6f378ef3ef
commit 648cdbaa29
3 changed files with 56 additions and 7 deletions

View File

@@ -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<typename T> static MatrixComplex<T> computeOnComplexAndMatrix(const std::complex<T> c, const MatrixComplex<T> n, Preferences::ComplexFormat complexFormat);
template<typename T> static MatrixComplex<T> computeOnMatrixAndComplex(const MatrixComplex<T> m, const std::complex<T> 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;

View File

@@ -4,6 +4,7 @@
#include <poincare/binomial_coefficient.h>
#include <poincare/constant.h>
#include <poincare/cosine.h>
#include <poincare/derivative.h>
#include <poincare/division.h>
#include <poincare/float.h>
#include <poincare/horizontal_layout.h>
@@ -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<typename T> MatrixComplex<T> PowerNode::computeOnComplexAndMatrix(const std::complex<T> c, const MatrixComplex<T> n, Preferences::ComplexFormat complexFormat) {
return MatrixComplex<T>::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<Symbol>(),
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<Symbol>(),
symbolValue.clone()
), 2, 2);
Addition result = Addition::Builder(derivedFromBase, derivedFromExponent);
replaceWithInPlace(result);
return true;
}
// Private
// Simplification

View File

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