5

我正在尝试在 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

到目前为止,如此简单。诀窍是如何组合函数。在这里,我相信我想要一种类似柯里化的方法,以便我可以评估单个参数的函数,并保留其他参数。所以我正在考虑有一个这样的工厂类:

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>>

等等。我主要担心的是泛型类型可能会使系统无法使用(如果用户需要知道完整的泛型类型只是为了评估),并且我可能无法从输入参数构造所有泛型类型。

感谢您的输入!

4

4 回答 4

1

请注意,可以使用 C# 编译器来计算表达式。

通过在运行时编译 C# 代码来评估数学表达式 http://www.codeproject.com/KB/recipes/matheval.aspx

于 2010-02-05T16:59:17.587 回答
0

有趣的是,我实际上是在几个月前在 D 中这样做的,但它并不是特别有趣。我的方法是使用模板化的表达式树类。我有一个可以用,等实例化的 Binary 类模板,一个可以用 , 等实例化+*一元类。派生类主要通过递归应用链和乘积规则来工作。例如:sinexp

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);
    }
}
于 2010-02-05T21:33:37.377 回答
0

我不完全确定柯里化是什么,但解析表达式的常用方法是构建抽象语法树
由此,评估表达式、找到导数或您想做的任何事情应该不难。


[编辑]恐怕您的评论毫无意义。从它的声音来看,你想解析一个表达式并构建一个 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
    }
}
于 2010-02-05T17:04:13.863 回答
0

使用表达式树怎么样?请注意,在链接页面上,甚至还有一个构建某种柯里化函数的示例(从通用“小于”运算符和固定常量构建“小于五个”函数)

于 2010-02-05T17:05:26.980 回答