4

子のリンクされたリストと同じノード型の単一の親を含むTree<E>ルート オブジェクトを参照するクラスを持つ C# でジェネリック ツリー データ構造を実装したいと考えています。TreeNode<E>これは基本的なツリー構造であり、この部分の実装に問題はありません。

このツリー構造を拡張して、拡張する を作成しFunction、適切に拡張Tree<double>する補数ノード タイプを作成します。この構造を使用して、関数の適切な変数で評価できる数学関数を表現したいと考えています。ExpressionTreeNode<double>

私は現在、このプロジェクトの設計段階にあるので、これを実装する方法はたくさんありますが、パラメーター署名を気密に保ちながら、すべてのタイプの関数をカバーする適切なレベルの抽象化を持つ設計を探しています. たとえばFunction、数学関数の実行時にを作成できるはずです。

f() = 42f(x) = x^2f(x, y) = x/y + 5、など

everyExpressionに独自の子のリスト (引数が与えられた関数のプロセスを定義するために分割される部分式) がある場合は、値を取り込んでスカラー値を吐き出すExpression何らかの評価方法を使用する必要があります (または、可能であれば、doubleこれをベクトル レベルに抽出します)。

私は LINQ のような関数型言語の経験があまりありませんが、誰かがそうであれば、それを使用して計画していることを実装するためのシンプルで強力な方法はありますか? SinExpression(X)あらゆる種類の基本的な操作 (またはAdditionExpression(X,Y)ものなど) に対して具体的なクラスを作成する必要がなく、その代わりに辞書に格納できる可能性のある数学関数をその場で定義できれば素晴らしいと思います。他の式になるか、浮動小数点値に要約されます。その時点で、基本コンストラクターで評価関数を定義するだけで、必要に応じて具体的な関数クラスでこれらの抽象化された関数クラスを拡張できます。

また、関数の式ツリーを直接変更する (ノードの変更、ブランチの削除など) 別のプログラムでこれらの式を使用する予定であるため、ツリー構造を維持することが重要であることにも注意してください。

誰かが私を正しい方向に向けることができますか? 私はそれを大いに感謝します。

4

1 に答える 1

5

複雑な操作をノード ツリーとして表す API は既に存在します。LINQ ExpressionAPI。些細な例として、コンパイラーにツリーを作成させることができます。例えば:

Expression<Func<double,double,double>> f = (x,y) => Math.Sin(x/y) + 5;

これは、 を呼び出して物事を評価するために使用できます。Compile()

var func = f.Compile(); // this is a Func<double,double,double>
Console.WriteLine(func(12,5));
Console.WriteLine(func(23,4));

しかし、式ツリーはより複雑で、任意に調べることができます。ExpressionVisitorさらに、ピースを交換するために使用できます。たとえば、ランダムな遺伝子変異の一部として「x」を「ln(x)」に置き換えたいとします。

// swap x for ln(x)
var munged = SwapExpressionVisitor.Swap(
    f, // the lambda to rewrite
    f.Parameters[0], // "x"
    Expression.Call(typeof(Math), "Log", null, f.Parameters[0]) // ln(x)
); // (x, y) => (Sin((Log(x) / y)) + 5)

func = munged.Compile();
Console.WriteLine(func(12, 5));
Console.WriteLine(func(23, 4));

次のようなユーティリティを使用します。

class SwapExpressionVisitor : ExpressionVisitor
{
    public static Expression<T> Swap<T>(Expression<T> lambda,
        Expression from, Expression to)
    {
        return Expression.Lambda<T>(
            Swap(lambda.Body, from, to), lambda.Parameters);
    }
    public static Expression Swap(
        Expression body, Expression from, Expression to)
    {
        return new SwapExpressionVisitor(from, to).Visit(body);
    }
    private readonly Expression from, to;
    public SwapExpressionVisitor(Expression from, Expression to)
    {
        this.from = from;
        this.to = to;
    }
    public override Expression Visit(Expression node)
    {
        return node == from ? to : base.Visit(node);
    }
}
于 2013-03-08T11:57:25.590 に答える