C# 用表达式求lambda函数的导数

C# 用表达式求lambda函数的导数,c#,lambda,reflection,C#,Lambda,Reflection,假设您在输入上有一个lambda函数,如下所示 Function<double, double> f = x => x*x +2 我现在得到的是: public static Expression<Func<double, double>> GetDerivative(Expression<Func<double, double>> func) { var eps = 1e-5; var

假设您在输入上有一个lambda函数,如下所示

Function<double, double> f = x => x*x +2
我现在得到的是:

public static Expression<Func<double, double>> GetDerivative(Expression<Func<double, double>> func)
    {
        var eps = 1e-5;
        var paramX = Expression.Parameter(typeof(double), "x");
        var epsilon = Expression.Constant(eps);
        var secondExpression = Expression.Lambda(func, paramX);
        //var firstExpression = ..
        var expression =  Expression.Divide(Expression.Subtract(firstExpression, secondExpression), epsilon);
        return Expression.Lambda<Func<double, double>>(expression, paramX);
    }
公共静态表达式getDerivation(表达式func)
{
var-eps=1e-5;
var paramX=表达式参数(typeof(double),“x”);
varε=表达式常数(eps);
var secondExpression=Expression.Lambda(func,paramX);
//var firstExpression=。。
var表达式=表达式.除法(表达式.减法(第一个表达式,第二个表达式),ε);
返回表达式.Lambda(表达式,paramX);
}

如何使用参数(paramX+epsilon)创建firstExpression?

您有了一个良好的开端,代码明确地澄清了一些问题

我将分步骤构建它。你想建立表达,以避免迷失在中间。

首先,要添加
x0
eps
。您已经有了
x0
参数和ε常数。我正在重命名一些东西,以便按原样显示它们

ParameterExpression x0Parameter = Expression.Parameter(typeof(double), "x0");
ConstantExpression epsilonConstant = Expression.Constant(1e-5);
要添加它们,请使用一个简单的表达式:

Expression.Add(x0Parameter, epsilonConstant)
现在,您希望将其传递给f(即,
func
)。要做到这一点,你需要做一些事情。首先,你需要一名代表。作为一个表达式,没有方法作为目标,所以必须编译它。然后,您必须获取类型及其
Invoke
方法。您还需要将编译后的函数作为调用的目标

Func<double, double> funcInstance = func.Compile();
Type funcType = typeof(Func<double, double>);
System.Reflection.MethodInfo invokeMethod = funcType.GetMethod("Invoke");
ConstantExpression funcConstant = Expression.Constant(funcInstance, typeof(Func<double, double>));
下一个表达式是从第一个表达式中减去的表达式,
f(x0)
。当然,这个更简单。您重用了迄今为止定义的大部分内容

Expression.Call(funcConstant, invokeMethod, x0Parameter)
现在你要减去这两个表达式

Expression.Subtract(
    Expression.Call(funcConstant, invokeMethod, Expression.Add(x0Parameter, epsilonConstant)),
    Expression.Call(funcConstant, invokeMethod, x0Parameter)
    )
最后,您要将其除以eps

Expression.Divide(
    Expression.Subtract(
        Expression.Call(funcConstant, invokeMethod, Expression.Add(x0Parameter, epsilonConstant)),
        Expression.Call(funcConstant, invokeMethod, x0Parameter)
        ),
        epsilonConstant
    )
综上所述,它看起来是这样的:

public static Expression<Func<double, double>> GetDerivative(Expression<Func<double, double>> func)
{
    ParameterExpression x0Parameter = Expression.Parameter(typeof(double), "x0");
    ConstantExpression epsilonConstant = Expression.Constant(1e-5);

    Func<double, double> funcInstance = func.Compile();
    Type funcType = typeof(Func<double, double>);
    System.Reflection.MethodInfo invokeMethod = funcType.GetMethod("Invoke");
    ConstantExpression funcConstant = Expression.Constant(funcInstance, typeof(Func<double, double>));

    BinaryExpression body = Expression.Divide(
        Expression.Subtract(
            Expression.Call(funcConstant, invokeMethod, Expression.Add(x0Parameter, epsilonConstant)),
            Expression.Call(funcConstant, invokeMethod, x0Parameter)
            ),
            epsilonConstant
        );

    return Expression.Lambda<Func<double, double>>(body, x0Parameter);
}
回到现实世界,定义您的函数,获取派生函数,将派生函数编译为委托,然后调用委托:

Expression<Func<double, double>> f = x => x * x + 2;

Expression<Func<double, double>> df = GetDerivative(f);

Func<double, double> dfFunc = df.Compile();

double result = dfFunc(someInput);
表达式f=x=>x*x+2;
表达式df=导数(f);
Func-dfFunc=df.Compile();
双结果=dfFunc(someInput);

一旦它成为功能,可能会变得有点不切实际。。。也许你想要表达,然后仔细看看这个表达tree@DarkSquirrel42当然更正了签名。那么你的问题是关于数学或者关于如何分解表达式树?你已经学习了关于构建表达式树的知识了吗?这些表达式是构建最简单的表达式之一。其中大部分涉及表达式、加/减/除和表达式、调用(
f.Invoke()
,而不是
f()
),在某些地方,你必须定义
eps
。一旦你试过了,再细化这个问题。我试过了,但不知道如何用参数(x+eps)构建lambda。这是主要问题。
Expression.Divide(
    Expression.Subtract(
        Expression.Call(funcConstant, invokeMethod, Expression.Add(x0Parameter, epsilonConstant)),
        Expression.Call(funcConstant, invokeMethod, x0Parameter)
        ),
        epsilonConstant
    )
public static Expression<Func<double, double>> GetDerivative(Expression<Func<double, double>> func)
{
    ParameterExpression x0Parameter = Expression.Parameter(typeof(double), "x0");
    ConstantExpression epsilonConstant = Expression.Constant(1e-5);

    Func<double, double> funcInstance = func.Compile();
    Type funcType = typeof(Func<double, double>);
    System.Reflection.MethodInfo invokeMethod = funcType.GetMethod("Invoke");
    ConstantExpression funcConstant = Expression.Constant(funcInstance, typeof(Func<double, double>));

    BinaryExpression body = Expression.Divide(
        Expression.Subtract(
            Expression.Call(funcConstant, invokeMethod, Expression.Add(x0Parameter, epsilonConstant)),
            Expression.Call(funcConstant, invokeMethod, x0Parameter)
            ),
            epsilonConstant
        );

    return Expression.Lambda<Func<double, double>>(body, x0Parameter);
}
public static Expression<Func<double, double>> GetDerivative(Expression<Func<double, double>> func)
{
    ParameterExpression x0Parameter = Expression.Parameter(typeof(double), "x0");
    ConstantExpression epsilonConstant = Expression.Constant(1e-5);

    BinaryExpression body = Expression.Divide(
        Expression.Subtract(
            Expression.Invoke(func, Expression.Add(x0Parameter, epsilonConstant)),
            Expression.Invoke(func, x0Parameter)
            ),
            epsilonConstant
        );

    return Expression.Lambda<Func<double, double>>(body, x0Parameter);
}
Expression<Func<double, double>> f = x => x * x + 2;

Expression<Func<double, double>> df = GetDerivative(f);

Func<double, double> dfFunc = df.Compile();

double result = dfFunc(someInput);