2010-02-05 74 views
5

我想在C#中實現一個基礎架構,它允許我創建任意的數學表達式。舉例來說,我希望能夠採取一種表達喜歡確認格林布恩在C中的第10條定律#

ASIN(開方(Z - SIN(X + Y)^ 2))

,並把它變成一個對象,讓我來評價它就x,y和z而言,可以得到導數,並且可能對它做某種象徵代數。在C#中,人們對此有何看法?

我有我自己的想法,我恐怕要去建築航天學,所以我想確保不是這樣。

基本上,像罪,+,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>> 

等等。我主要關心的是泛型類型可能會使系統無法使用(如果用戶需要知道完整的泛型類型以便評估),並且我可能無法從輸入參數構造所有泛型類型。

感謝您的輸入!

+0

我建議使用類似Matlab或Mathematica之類的東西,而不是試圖重新發明車輪。 – davr 2010-02-05 21:30:18

+0

你爲什麼認爲你需要用泛型來做到這一點?它看起來完全可行(並且更簡單一些),使用普通的類層次結構。 – RBarryYoung 2010-02-05 21:32:02

回答

1

請注意,可以使用C#編譯器來評估表達式。

在運行時 http://www.codeproject.com/KB/recipes/matheval.aspx

+0

看起來編譯好的表達式對於我來說就像代表一樣不透明。 。 。我將需要對這些對象進行元顯示,比如顯示底層表達式。 – reveazure 2010-02-05 17:03:46

+0

果然如此。 Anders和他的團隊打算打開C#編譯器,允許它用作服務(這將提供更大的靈活性,因爲當前的編譯器本質上是一個黑匣子),但該功能尚不存在。 – 2010-02-05 20:59:43

0

編譯C#代碼評估數學表達式我不能完全肯定是什麼鑽營,但通常的做法來解析表達式是要建立一個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 
    } 
} 
+0

對,問題是,基本上,如何表示AST的自由參數,以及靈活性與類型安全性之間的正確平衡是什麼? – reveazure 2010-02-05 17:05:11

+0

@Reveazure:如果用「自由參數」表示「變量」,不管你想要做什麼;你可以存儲字符串,或者作爲具有名稱和值的對象。它並不重要,只要當你到達樹中的一個時,你就可以識別它(請注意,所有的葉子將是數字或變量,反之亦然) – 2010-02-05 17:11:49

+0

這是我的關於什麼是咖喱的文章,如果你對該主題感興趣:http://blogs.msdn.com/ericlippert/archive/2009/06/25/mmm-curry.aspx – 2010-02-05 17:53:06

0

怎麼樣使用Expression Trees?請注意,在鏈接頁面上,甚至還有一個用於構建咖喱函數的示例(從通用「小於」運算符和固定常量構建「小於5」函數)

+0

這裏的麻煩是我真正想要的是一個類的樹,它有ToString之類的東西,讓我得到它們的派生物。另外,我並不需要編譯表達式或從C#代碼動態生成表達式的能力。 – reveazure 2010-02-05 17:16:26

0

有趣的是,我實際上做了這個幾個月前在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); 
    } 
}