C# 用表达式求lambda函数的导数
假设您在输入上有一个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
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);