2011-11-27 56 views
14

至於在包裝設計中的性能和可擴展性,最好是到:設計方法:Overload vs Switch?

  1. ...「超載」函數名(讓數學理清了基於模式/條件/測試和路系統使用的版本訂單定義)?
  2. ...或用Switch [](或類似命令)構造單個函數來直接評估?

Mathematica的表現力經常讓我和這樣的愚蠢(?)問題混淆。

+3

我覺得你應該爲你的問題增加一些細節。這一點非常廣泛。 –

+1

不能說我不同意你的評價。我原本寫了更多,但意識到我正在重新調整我們大多數人從手冊和個人經驗中所知道的基本知識。我會盡力澄清,如果我可以---但在比賽結束後。 :) – telefunkenvf14

+2

我也寫了一個較長的答案,然後意識到我的例子是平庸的,所以我把它保留下來。玩的開心。 –

回答

6

你的問題是很模糊的,因爲書面的,有不同的解釋「超載」,這將改變我的答案。但是,如果您正在討論針對不同類型(頭部)和參數模式重載您自己的函數,那麼請儘量利用Mathematica緊密集成的模式匹配。


舉一個實際的例子,我將使用this solution of mine。供參考:

f[k_, {}, c__] := If[Plus[c] == k, {{c}}, {}] 

f[k_, {x_, r___}, c___] := Join @@ (f[k, {r}, c, #] & /@ Range[0, Min[x, k - Plus[c]]]) 

如果我重寫f沒有模式匹配,並調用它g

g = Function[{k, L, c}, 
     If[L === {}, 
     If[[email protected] == k, {c}, {}], 
     Join @@ (g[k, [email protected], Append[c, #]] & /@ Range[0, Min[[email protected], k - [email protected]]]) 
     ] 
    ]; 

我覺得這是不太清楚,也肯定不太方便寫。我必須使用明確的RestFirst函數,並且我不得不引入Append,因爲我無法容納可變數量的參數。這也需要使用虛擬的第三個參數:{}

計時錶明原來的形式也相當快:

f[12, {1, 5, 8, 10, 9, 9, 4, 10, 8}]; // Timing 
g[12, {1, 5, 8, 10, 9, 9, 4, 10, 8}, {}]; // Timing 
{0.951, Null}
{1.576, Null}

針對蒂莫的回答,我覺得這是有價值的分享我的時序結果,如他們與他不同。 (我在Windows 7上使用Mathematica 7)。另外,我相信他將DownValues版本超越了Switch版本的功能。

首先,我的職務定時書面,但使用範圍值:

Array[switchFunc2, 1*^6]; // Timing 
Array[overloadFunc2, 1*^6]; // Timing 
{1.014, Null}
{0.749, Null}

因此,即使在寫的,DownValues功能是對我更快。但第二個條件是不需要的:

ClearAll[overloadFunc2] 

overloadFunc2[a_ /; a < 5] := 6; 
overloadFunc2[a_] := 4; 

Array[overloadFunc2, 1*^6]; // Timing 
{0.546, Null}

當然,在這樣一個簡單的功能的情況下,人們也可以使用If

ifFunc[a_] := If[a < 5, 6, 4] 

Array[ifFunc, 1*^6]; // Timing 
{0.593, Null}

,如果是這樣寫作爲Mathematica在Array內部編譯的一個純函數:

ClearAll[ifFunc] 
ifFunc = If[# < 5, 6, 4] &; 

Array[ifFunc, 1*^6]; // Timing 
{0.031, Null}
+0

這讓我想起了我喜歡功能的第三個原因 - 能夠命名模式並在以後重用它們。 –

+0

不錯的檢查時機!關於過度加載,我會爭取相同的功能,我的DownValues都需要。考慮'overloadFunc2 [「string」]'和'switchFunc2 [「string」]'。當然,我的expamnles非常簡單,任何真實世界的應用程序都應該自行測試。 – Timo

+0

@Timo我很困惑:'* Func2'應該是處理字符串嗎?怎麼樣? –

9

除非是非常簡單的情況,我更喜歡使用具有多個定義的函數而不是Switch。其原因有三個:

  1. 我發現只要功能命名方便,就可以更容易地閱讀代碼。
  2. 對於fall-through/error情況,更容易設置適當的默認值並再次調用該函數。
  3. 如果使用函數,則可以在計算結果時使用命名模式。

編輯

這裏是作爲Sjoerd的#2的例子創建了一個例子:

createNColors[fn_, Automatic, n_] := Table[Hue[i/n], {i, n}] 

createNColors[fn_, colors_List, n_] := PadRight[colors, n, colors] 

createNColors[fn_, color:(Hue | RGBColor | CMYKColor | GrayLevel)[__], n_] := 
    Table[color, {n}] 

createNColors[fn_, color_, n_] := (
    Message[fn::"color", HoldForm[color]]; 
    createNColors[fn, Automatic, n] 
    ) 

它可以被用來生成一些選項的一組ñ顏色。

+0

如果你可以提供第二點的好例子,你會得到+1 ;-) –

+0

非常有益!最後一個定義,不應該是'createNColors'而不是'createNStyle',這樣你就可以像'createNColors [fn,CIELab [1,0.5,0.25],6]'一樣調用適當的處理了嗎? –

+0

@Sjoerd:感謝您發現錯誤。我在最後一刻不完美地重新命名了事物。 –

9

要回答你的問題的性能部分,考慮超載和使用Switch[]

switchFunc[a_] := Switch[a, _String, 5, _Integer, var, _Symbol, "string"] 

overloadFunc[a_String] := 5; 
overloadFunc[a_Integer] := var; 
overloadFunc[a_Symbol] := "string"; 

這是非常簡單的,但足以證明在性能

In[1] := [email protected][switchFunc, x, 1000000] 
Out[1] := {3.435, "string"} 

In[2] := [email protected][overloadFunc, x, 1000000] 
Out[2] := {0.754, "string"} 

的差異下面兩個例子但是,如果您打算根據條件測試超載您的功能,則性能會比Switch[]差:

switchFunc2[a_] := Switch[a < 5, True, 6, False, 4]; 

overloadFunc2[a_ /; a < 5] := 6; 
overloadFunc2[a_ /; a > 5] := 4; 
overloadFunc2[a_] := a; 

In[3] := [email protected][switchFunc2, 4, 1000000] 
Out[3] := {2.63146, 4} 

In[4] := [email protected][overloadFunc2, 6, 1000000] 
Out[4] := {4.349, 6} 

編輯:在這個答案的時間是在OS X 10.7.2上使用Mathematica 8.0.1。在上述順序顛倒的情況下,請參閱Mr.Wizard的答案以獲得一些額外的結果。儘管如此,我認爲在函數參數上進行邏輯模式檢查對性能不利。

從設計的角度來看,我的個人經驗是Switch[],它的行程很糟糕,因爲它們很難讀懂,也很慢。但是,我也認爲具有相同功能的表達方式在參數類型上表現不同,通常是不好的設計,並且使得您的代碼更加難以使用(即使它可能更易於閱讀)。

11

這是一個廣泛的問題,但我會藉此機會給出一個廣泛的答案...

我主張應該接受一種編程語言的主要範式,而不是試圖與它對抗或編寫遵循另一種語言的習語的代碼。 Mathematica是圍繞模式匹配的概念構建的,因此,恕我直言,我們應該在嘗試表達自己時首先考慮模式匹配。遵循該原則,我傾向於使用Switch以上的定義。

在性能問題上,比較Mathematica結構時,越來越重視microbenchmarks,我越來越感到煩惱。雖然知道與構建相關的成本是很有價值的,但我們應該聽取Knuth(或者是Hoare?):「我們應該忘記小效率,大約97%的時間:過早優化是萬惡之源。」 「邪惡」是指爲了提高效率而使用一些模糊或間接的方法來實現效果的程序中可讀性的喪失。這是我的性能清單:

  1. 性能有問題嗎?如果不是,則跳過清單的其餘部分。

  2. 性能瓶頸在哪裏?分析器在這裏有所幫助,但通常可以通過檢查或幾個打印語句輕鬆找到瓶頸。然後...

  3. 該算法效率低下嗎?非常頻繁:是否存在可通過索引方案進行線性化或幫助的雙嵌套循環?

  4. 好的,算法很好,所以我想現在是時候微基準。

我不知道我對Mathematica的使用是否不夠雄心勃勃,但大部分時間我都沒有通過第一步。然後#3獲得其餘大部分。在Mathematica中,我發現我通常只是喜出望外,我可以用少量代碼執行一些宏大的任務 - 總體性能通常不會進入圖片。

呃 - 哦,我最好把肥皂箱拿開。對不起'回合。

+2

關於使用自然範例的一個很好的觀點。關於你對mma的使用可能不夠雄心勃勃,你使用它的可能性太高。至少在我的情況下,我主要使用mma做一些事情:構建非常大的稀疏矩陣,獲取特徵值和向量,對它們做一些簡單的事情。通常,最耗時的部分是構建矩陣,而不是解決特徵系統。在這種情況下,微基準(或者只是「編譯」到C)是C之前的最後希望。對於更復雜的使用,我完全同意你的觀點。 – acl

+4

呃,他很煩。 http://www.youtube.com/watch?v=0t2pWUWE1Y8 –

+0

除非我的記憶讓我失望,否則我從來沒有對10K代表表示祝賀......恭喜! –