diff --git a/poincare/include/poincare/derivative.h b/poincare/include/poincare/derivative.h index bfa1a7319..0456c54b5 100644 --- a/poincare/include/poincare/derivative.h +++ b/poincare/include/poincare/derivative.h @@ -52,6 +52,7 @@ public: static Derivative Builder(Expression child0, Symbol child1, Expression child2) { return TreeHandle::FixedArityBuilder({child0, child1, child2}); } static Expression UntypedBuilder(Expression children); static constexpr Expression::FunctionHelper s_functionHelper = Expression::FunctionHelper("diff", 3, &UntypedBuilder); + static void DerivateUnaryFunction(Expression function, Expression symbol, Expression symbolValue); Expression shallowReduce(ExpressionNode::ReductionContext context); }; diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 05944ba41..4dfc93fbf 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -385,6 +385,7 @@ protected: * 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); } + Expression unaryFunctionDifferential() { return node()->unaryFunctionDifferential(); } private: static constexpr int k_maxSymbolReplacementsCount = 10; @@ -414,6 +415,7 @@ private: Expression shallowReduceUsingApproximation(ExpressionNode::ReductionContext reductionContext); Expression defaultShallowBeautify() { return *this; } bool defaultDidDerivate() { return false; } + Expression defaultUnaryFunctionDifferential() { return *this; } /* 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 4ab8b1c64..99a58cfe7 100644 --- a/poincare/include/poincare/expression_node.h +++ b/poincare/include/poincare/expression_node.h @@ -224,6 +224,7 @@ public: /*!*/ virtual Expression shallowReduce(ReductionContext reductionContext); /*!*/ virtual Expression shallowBeautify(ReductionContext reductionContext); /*!*/ virtual bool didDerivate(ReductionContext, Expression symbol, Expression symbolValue); + virtual Expression unaryFunctionDifferential(); /* 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/include/poincare/sine.h b/poincare/include/poincare/sine.h index 80307a048..701288952 100644 --- a/poincare/include/poincare/sine.h +++ b/poincare/include/poincare/sine.h @@ -35,6 +35,10 @@ private: LayoutShape leftLayoutShape() const override { return LayoutShape::MoreLetters; }; LayoutShape rightLayoutShape() const override { return LayoutShape::BoundaryPunctuation; } + // Derivation + bool didDerivate(ReductionContext reductionContext, Expression symbol, Expression symbolValue) override; + Expression unaryFunctionDifferential() override; + // Evaluation Evaluation approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return ApproximationHelper::Map(this, context, complexFormat, angleUnit,computeOnComplex); @@ -52,6 +56,9 @@ public: static constexpr Expression::FunctionHelper s_functionHelper = Expression::FunctionHelper("sin", 1, &UntypedBuilderOneChild); Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); + + bool didDerivate(ExpressionNode::ReductionContext reductionContext, Expression symbol, Expression symbolValue); + Expression unaryFunctionDifferential(); }; } diff --git a/poincare/src/derivative.cpp b/poincare/src/derivative.cpp index e24a7148b..1caff18b5 100644 --- a/poincare/src/derivative.cpp +++ b/poincare/src/derivative.cpp @@ -1,8 +1,8 @@ #include #include #include +#include #include - #include #include #include @@ -184,6 +184,12 @@ Expression Derivative::shallowReduce(ExpressionNode::ReductionContext reductionC derivand = derivand.deepReduce(reductionContext); replaceWithInPlace(derivand); return derivand; +} + +void Derivative::DerivateUnaryFunction(Expression function, Expression symbol, Expression symbolValue) { + Expression df = function.unaryFunctionDifferential(); + Expression dg = Derivative::Builder(function.childAtIndex(0), symbol.clone().convert(), symbolValue.clone()); + function.replaceWithInPlace(Multiplication::Builder(df, dg)); } diff --git a/poincare/src/expression_node.cpp b/poincare/src/expression_node.cpp index 5c02fe3e5..91c63e59a 100644 --- a/poincare/src/expression_node.cpp +++ b/poincare/src/expression_node.cpp @@ -131,6 +131,10 @@ bool ExpressionNode::didDerivate(ReductionContext reductionContext, Expression s return Expression(this).defaultDidDerivate(); } +Expression ExpressionNode::unaryFunctionDifferential() { + return Expression(this).defaultUnaryFunctionDifferential(); +} + bool ExpressionNode::isOfType(Type * types, int length) const { for (int i = 0; i < length; i++) { if (type() == types[i]) { diff --git a/poincare/src/sine.cpp b/poincare/src/sine.cpp index 3668d8a3a..9673c9e3d 100644 --- a/poincare/src/sine.cpp +++ b/poincare/src/sine.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include @@ -34,6 +36,13 @@ Expression SineNode::shallowReduce(ReductionContext reductionContext) { return Sine(this).shallowReduce(reductionContext); } +bool SineNode::didDerivate(ReductionContext reductionContext, Expression symbol, Expression symbolValue) { + return Sine(this).didDerivate(reductionContext, symbol, symbolValue); +} + +Expression SineNode::unaryFunctionDifferential() { + return Sine(this).unaryFunctionDifferential(); +} Expression Sine::shallowReduce(ExpressionNode::ReductionContext reductionContext) { { @@ -46,4 +55,13 @@ Expression Sine::shallowReduce(ExpressionNode::ReductionContext reductionContext return Trigonometry::shallowReduceDirectFunction(*this, reductionContext); } +bool Sine::didDerivate(ExpressionNode::ReductionContext reductionContext, Expression symbol, Expression symbolValue) { + Derivative::DerivateUnaryFunction(*this, symbol, symbolValue); + return true; +} + +Expression Sine::unaryFunctionDifferential() { + return Cosine::Builder(childAtIndex(0).clone()); +} + } diff --git a/poincare/test/derivative.cpp b/poincare/test/derivative.cpp index cb16ff8b7..5567bf1a6 100644 --- a/poincare/test/derivative.cpp +++ b/poincare/test/derivative.cpp @@ -15,11 +15,12 @@ void assert_parses_and_reduces_as(const char * expression, const char * derivati quiz_assert_print_if_failure(eReduced.isIdenticalTo(d), expression); } -QUIZ_CASE(poincare_differential_addition) { +QUIZ_CASE(poincare_differential_operations) { assert_parses_and_reduces_as("diff(1,x,1)", "0"); assert_parses_and_reduces_as("diff(x,x,1)", "1"); assert_parses_and_reduces_as("diff(1+2,x,1)", "0"); assert_parses_and_reduces_as("diff(a,x,1)", "0"); + assert_parses_and_reduces_as("diff(diff(x^2,x,y),y,1)","2"); assert_parses_and_reduces_as("diff(1+x,x,1)", "1"); assert_parses_and_reduces_as("diff(undef,x,1)", "undef"); @@ -37,4 +38,10 @@ QUIZ_CASE(poincare_differential_addition) { 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"); +} + +QUIZ_CASE(poicare_differential_unary_functions) { + assert_parses_and_reduces_as("diff(sin(x),x,π)","-1"); + assert_parses_and_reduces_as("diff(sin(2y),y,π/12)","√(3)"); + assert_parses_and_reduces_as("diff(sin(2x)+sin(3x),x,π/6)","1"); } \ No newline at end of file