mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-24 00:00:44 +01:00
[poincare] Added framework to derivate unary functions, and implemented it for Sine
Added a method unaryFunctionDifferential to ExpressionNode and Expression, to be implemented by subclasses representing unary functions. Added a function derivateUnaryFunction to Derivative, to factor (f°g)' -> g' * f'°g. Change-Id: Id1780f1082ccd001f1282fe4ddfff2b7055d3a27
This commit is contained in:
committed by
Émilie Feral
parent
648cdbaa29
commit
5cf85368ea
@@ -52,6 +52,7 @@ public:
|
||||
static Derivative Builder(Expression child0, Symbol child1, Expression child2) { return TreeHandle::FixedArityBuilder<Derivative, DerivativeNode>({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);
|
||||
};
|
||||
|
||||
@@ -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<typename U> Evaluation<U> approximateToEvaluation(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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<float> approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override {
|
||||
return ApproximationHelper::Map<float>(this, context, complexFormat, angleUnit,computeOnComplex<float>);
|
||||
@@ -52,6 +56,9 @@ public:
|
||||
static constexpr Expression::FunctionHelper s_functionHelper = Expression::FunctionHelper("sin", 1, &UntypedBuilderOneChild<Sine>);
|
||||
|
||||
Expression shallowReduce(ExpressionNode::ReductionContext reductionContext);
|
||||
|
||||
bool didDerivate(ExpressionNode::ReductionContext reductionContext, Expression symbol, Expression symbolValue);
|
||||
Expression unaryFunctionDifferential();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include <poincare/derivative.h>
|
||||
#include <poincare/ieee754.h>
|
||||
#include <poincare/layout_helper.h>
|
||||
#include <poincare/multiplication.h>
|
||||
#include <poincare/serialization_helper.h>
|
||||
|
||||
#include <poincare/symbol.h>
|
||||
#include <poincare/undefined.h>
|
||||
#include <cmath>
|
||||
@@ -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<Symbol>(), symbolValue.clone());
|
||||
function.replaceWithInPlace(Multiplication::Builder(df, dg));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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]) {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <poincare/sine.h>
|
||||
#include <poincare/complex.h>
|
||||
#include <poincare/cosine.h>
|
||||
#include <poincare/derivative.h>
|
||||
#include <poincare/layout_helper.h>
|
||||
#include <poincare/serialization_helper.h>
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
Reference in New Issue
Block a user