我正在尝试在C#中实现一个允许我制作任意数学表达式的基础结构。例如,我希望能够采用像
这样的表达式asin(sqrt(z - sin(x + y)^ 2))
并将其转换为一个对象,允许我根据x,y和z来评估它,得到导数,并可能在其上做某种符号代数。在C#中人们对这个好模型的看法是什么?
我有自己的想法,我担心它会走向建筑航天,所以我想确保不是这样。
基本上,像sin,+,sqrt等函数的类基于基类:
Function
Function<TOut> : Function
TOut Value
Function<Tin, TOut> : Function
TOut Evaluate(TIn value)
Function Derivative
Function<TOut, TIn> INverse
Function<TInA, TInB, TOut> : Function
TOut Evaluate(TInA valueA, TInB valueB)
Function PartialDerivativeA
Function PartialDerivativeB
到目前为止,这么简单。诀窍是如何组合功能。在这里,我相信我想要一个像currying方法的东西,这样我就可以评估单个参数的功能,并保留其他参数。所以我想有一个像这样的工厂类:
Function<TInA, TInB, TOut> ->
Function<TInA, Function<TInB, TOut>>
(Function<TInA, TInB, TOut>, Function<TInX, TInA>, null) ->
Function<TInX, Function<TInB, TOut>>
(Function<TInA, TInB, TOut>, Function<TInA>, Function<TInX, TInY, TInB>) ->
Function<TInX, Function<TInY, TInB>>
等等。我主要担心的是泛型类型可能会使系统无法使用(如果要求用户知道要评估的完整泛型类型),并且我可能无法从输入参数构造所有泛型类型。 / p>
感谢您的投入!
答案 0 :(得分:1)
请注意,可以使用C#编译器来计算表达式。
通过在运行时编译C#代码来评估数学表达式 http://www.codeproject.com/KB/recipes/matheval.aspx
答案 1 :(得分:0)
我不完全确定curry是什么,但解析表达式的常用方法是构建abstract syntax tree。
从中可以很难评估表达式,找到衍生物,或者你想做什么。
[编辑] 我担心你的评论毫无意义。从它的声音中,你想要解析一个表达式并构建一个AST,你可以用它做任何你想做的事情。是的,您将为每种类型的节点构建类;像这样的东西
public class PlusNode : BinaryNode
{
public PlusNode(Node left, Node right) { base(left, right); }
public virtual double Evaluate() { return Left.Evaluate() + Right.Evaluate(); }
public virtual Node BuildDerivative()
{
return new PlusNode(Left.BuildDerivative(), Right.BuildDerivative());
}
}
public class SinNode : UnaryNode
{
public SinNode(Node child) { base(child); }
public virtual double Evaluate() { return Math.Sin(Child.Evaluate()); }
public virtual Node BuildDerivative()
{
return new MultiplyNode(new CosNode(Child.Clone()), Child.BuildDerivative()); //chain rule
}
}
答案 2 :(得分:0)
使用Expression Trees怎么样?请注意,在链接页面上,甚至还有一个用于构建curried函数的示例(从通用的“less than”运算符和固定常量构建“少于5个”函数)
答案 3 :(得分:0)
+
,*
等实例化,这是一个可以用sin
,exp
等实例化的一元类。衍生工具由主要是递归应用链和产品规则。例如:
class Binary(alias fun) : MathExpression {
MathExpression left, right;
MathExpression derivative() {
static if(is(fun == add)) {
return left.derivative + right.derivative;
} else static if(is(fun == mul)) {
return left.derivative * right + right.derivative * left;
}
}
real opCall(real x) {
return fun(left(x), right(x));
}
}
class Unary(alias fun) : MathExpression {
MathExpression inner;
MathExpression derivative() {
static if(is(fun == sin)) {
return Unary!(sin)(inner.derivative);
}
}
real opCall(real x) {
return fun(inner(x));
}
}
class Constant : MathExpression {
real val;
real opCall(real x) {
return val;
}
real derivative() {
return new Constant(0);
}
}