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

式ツリーの使用についてはどうですか? リンクされたページには、カリー化された関数の並べ替えを構築する例もあります(一般的な「未満」演算子と固定定数から「5未満」関数を構築します)。

于 2010-02-05T17:05:26.980 に答える
0

面白いことに、私は実際に数か月前に D でこれを行いましたが、特に興味深いものとして受け入れられませんでした。私のアプローチは、テンプレート化された式ツリー クラスを使用することでした。、 などでインスタンス化できるバイナリ クラス テンプレートと、+など*でインスタンス化できる単項クラスがありました。デリバティブは、主にチェーンと積のルールを再帰的に適用するだけで機能しました。例えば: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 に答える