用 C# 确认格林斯潘第十定律

发布于 2024-08-20 14:04:21 字数 1218 浏览 8 评论 0原文

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

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

感谢您的意见!

I am trying to implement an infrastructure in C# that would allow me to make arbitrary mathematical expressions. For example, I want to be able to take an expression like

asin(sqrt(z - sin(x+y)^2))

and turn it into an object that will allow me to evaluate it in terms of x,y, and z, get derivatives, and possibly do some kind of symbolic algebra on it. What are people's thoughts on a good model for this in C#?

I have my own take, which I am afraid is heading off into architecture astronautics, so I want to make sure that is not the case.

Basically, the functions like sin, +, sqrt, etc. have classes based off a base class:

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

So far, so simple. The trick is how to compose the functions. Here I believe I want something like a currying approach so that I can evaluate the function for a single parameter, and have the other ones remain. So I am thinking of having a factory class like this:

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

and so on. My main concerns are that the generic types might make the system unusable (if the user is required to know the full generic types just to evaluate), and that I might not be able to construct all of the generic types from the input arguments.

Thanks for your input!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

故人如初 2024-08-27 14:04:21

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

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

Note that it is possible to use the C# compiler to evaluate expressions.

Evaluating Mathematical Expressions by Compiling C# Code at Runtime
http://www.codeproject.com/KB/recipes/matheval.aspx

迷雾森÷林ヴ 2024-08-27 14:04:21

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

What about using Expression Trees? Note that on the linked page, there's even an example for building sort of a curried function (building a "less than five" function from a generic "less than" operator and a fixed constant)

枯叶蝶 2024-08-27 14:04:21

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


[编辑]恐怕您的评论毫无意义。从它的声音来看,您想要解析一个表达式并构建一个 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
    }
}

I'm not entirely sure what currying is, but the usual approach to parsing expressions is to build an abstract syntax tree.
From this it shouldn't be difficult to evalute the expression, find the derivative, or whatever it is you want to do.


[Edit] I'm afraid your comments make no sense. From the sounds of it, you want to parse an expression and build an AST, from which you can do whatever you want with it. Yes, you will build classes for each type of node; something like this

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
    }
}
少女情怀诗 2024-08-27 14:04:21

有趣的是,实际上我几个月前在 D 中就这样做过,但并没有被认为特别有趣。我的方法是使用模板化表达式树类。我有一个可以用 +* 等实例化的二进制类模板,可以用 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);
    }
}

Funny, I actually did this a few months ago in D and it wasn't received as particularly interesting. My approach was to use templated expression tree classes. I had a Binary class template that could be instantiated with +, *, etc, a unary class that could be instantiated with sin, exp, etc. Derivatives worked by mostly just recursively applying the chain and product rules. For example:

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);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文