2011-07-27 26 views
1

這實際上是一個雙重問題。首先:作爲來自OO編程背景的人,我發現Mathematica使用列表作爲一切煩人的基礎。因此,這裏是怎樣一個Mathematica程序員(據我可以告訴)可能定義圖:Mathematica規則和GraphEdit返回的對象之間有什麼區別?

graph={{1, 2, 3, 4, 5}, {1->2, 2->4, 4->4, 4->5}}; 

,然後,程序員只需要記住,

graph[[1]] 

指頂點列表和

graph[[2]] 

指邊緣的列表(在這種情況下,定義爲一組的規則。)

所以,我正在學習Mathematica中的規則,並且我看到了讓我的數據結構更具面向對象感的機會。我選擇定義圖是這樣的:

graph={Verts->{1,2,3,4,5}, Edges->{1->2, 2->4, 4->4, 4->5}}; 

然後

Verts/.graph 
Edges/.graph 

指頂點和邊(分別)這可能有奇怪的副作用,但是,如果一些其他的數學文件定義然而,Verts或Edges作爲全局變量存在於某個地方,因爲該規則的左手邊不是標識符,而是它本身的一個對象。

所以問題1是這樣的:這是一個很好的做法,或者是創建Mathematica數據結構的一個壞習慣嗎?其中一個我做這種方式是如此,我可以將任意屬性的原因,說顏色:

AppendTo[graph, Colors->{Red, Red, Blue, Red, Red}]; (* Labels ea. vert with a color *) 

,我的功能不必知道加入特殊性能的確切順序。例如,你可能有一個功能GETCOLOR等被定義:

GetColor[graph_, vertIdx_]:=(Colors/.graph)[[vertIdx]]; 

這是可取的,因爲我可能不會總是希望有一個有顏色信息,所以不希望保留在一個點圖數據結構列表(如圖[[[3]]])以獲取顏色信息。

第二:我看到GraphEdit返回的東西看起來像我上面描述的規則。舉例來說,如果我執行(和繪製圖形)

Needs["GraphUtilities`"]; 
g = GraphEdit[]; 
g[[2]] 

我得到的輸出,如:

Graph->{1->2,3->3,4->4,5->4} 

它看起來像一個規則!所以,我試試這個:

Graph/.g[[2]] 

期待有

{1->2,3->3,4->4,5->4} 

返回。而是輸出只是

Graph 

但是,如果我不是執行

g[[2]][[1]] /. g[[2]] 

我得到預期的輸出,

{1->2,3->3,4->4,5->4} 

這意味着G [[2]]真的是一個規則,但由於某種原因,g [[2]] [[1]](如果執行的話打印Graph)與輸入Graph不同。那麼g [[2]] [[1]]是什麼?

看起來好像它是一個真正的標識符,如果是這樣,我想用上面的問題1解決問題。任何人都知道其中的差異,或者如何在Mathematica中輸入一個和另一個?

我找不到關於這個(或在線)任何文檔的任何內容。謝謝。

回答

4

的GraphEdit規則

GraphEdit返回其第一元件是Graphics對象,並且其剩下的元素是描述圖形規則的列表。每條規則的左側是一個字符串,而不是一個符號。您可以使用g // FullForm來確定。要提取圖形規則,必須忽略列表的第一個元素,例如

"Graph" /. Drop[g, 1] 

模擬記錄類型

這是實現諸如記錄的數據類型合理的方法,因爲你建議:

graph={Verts->{1,2,3,4,5}, Edges->{1->2, 2->4, 4->4, 4->5}}; 

這是事實,如果VertsEdges被指定值,那麼會出現「奇怪的副作用」。但是,有幾種方法可以緩解這個問題。

首先,Mathematica中存在一個非常普遍的約定,以避免將值(具體爲OwnValues)分配給帶大寫首字母的符號。鎢與前綴$,例如所有頂級變量$Context。如果你堅持這些慣例,你會得到一些安全措施。

其次,存在用於使用Packages不同的命名空間。在您定義的包的範圍內,您可以完全控制用作字段名稱的符號的綁定。

第三,你可以使用Protect旨在防止分配給它們的值的字段名。

在實施這些記錄類型,一個可以遵循一個LISP成語,定義構造函數和訪問功能。對於圖形例如,這些功能可以是這個樣子:

ClearAll[makeGraph, graphVertices, graphEdges] 
makeGraph[vertices_, edges_] := {Verts -> vertices, Edges -> edges} 
graphVertices[graph_] := Verts /. graph 
graphEdges[graph_] := Edges /. graph 

這些功能將被如此使用:

graph = makeGraph[{1,2,3,4,5}, {1->2,2->4,4->4,4->5}] 
(* {Verts -> {1, 2, 3, 4, 5}, Edges -> {1 -> 2, 2 -> 4, 4 -> 4, 4 -> 5}} *) 

graphVertices[graph] 
(* {1, 2, 3, 4, 5} *) 

graphEdges[graph] 
(* {1 -> 2, 2 -> 4, 4 -> 4, 4 -> 5} *) 

採用這種方案,現場鍵VertsEdges可以是私有的包並受到保護,完全避免了意外價值分配破壞事物的前景。

在Mathematica中,使用表達式的Head來識別它的類型是非常常見的。我們可以符合這個成語,從而重新定義我們記錄功能:

ClearAll[makeGraph, graphVertices, graphEdges] 
makeGraph[vertices_, edges_] := graphRecord[Verts -> vertices, Edges -> edges] 
graphVertices[graphRecord[rules___]] := Verts /. {rules} 
graphEdges[graphRecord[rules___]] := Edges /. {rules} 

這些和前述定義之間的唯一材料不同的是,圖表對象現在由形式graphRecord[...]代替{...}的表達式表示:

graph = makeGraph[{1,2,3,4,5}, {1->2,2->4,4->4,4->5}] 
(* graphRecord[Verts -> {1, 2, 3, 4, 5}, Edges -> {1->2, 2->4, 4->4, 4->5}] *) 

graphVertices[graph] 
(* {1, 2, 3, 4, 5} *) 

graphEdges[graph] 
(* {1 -> 2, 2 -> 4, 4 -> 4, 4 -> 5} *) 

爲什麼要改變?第一個原因是頭部graphRecord現在肯定地識別而在此之前,這只是一個列表的數據類型。其次,我們可以進一步定義函數(準方法),將只在graphRecord S和沒有別的作用。例如:

graphEdgeCount[r_graphRecord] := graphEdges[r] // Length 
graphEdgeCount[x_] := (Message[graphEdgeCount::invArg, x]; Abort[]) 
graphEdgeCount::invArg = "Invalid argument to graphEdgeCount: ``"; 

用途:

graphEdgeCount[graph] 
(* 4 *) 

graphEdgeCount["hi"] 
在graphEdgeCount :: invArg的評價:無效參數graphEdgeCount:喜
$中止

作爲最後的闡述了這一切,可以定義一個宏函數,該宏函數自動定義給定類型和字段名稱的所有記錄函數。然而,由於這種迴應已經是TL; DR,這可能最好留待日後作爲另一個問題的話題。注意:如果這些函數都是在包的上下文中定義的,則它們的名稱將使用首字母大寫(例如,MakeGraph而不是makeGraph)。然而,請注意,Mathematica已經有很多內置符號,包括字Graph

+0

哇,這非常有用,並填補了我對Mathematica理解中的很多漏洞。我認爲他們應該爲Mathematica文檔編寫一個類似於Mathematica Programming for C/Java/C++程序員的文檔,其內容類似於C/Java/C++,下面是適當的方式在Mathematica中做...他們可能會想到你寫了它。 – jcb

+1

@quadelirus當談到填補人們對Mathematica的理解時,一個很好的資源是Leonid Shifrin的[Mathematica編程:高級介紹](http://www.mathprogramming-intro.org/)。 – WReach

0

我找到了答案用InputForm []第2題(還不知道今天之前的功能。)

InputForm[g[[2]][[1]]]; 

回報

"Graph" 

因此,它似乎避免方式問題1中的問題以及他們如何定義GraphEdit東西的答案是將規則中的字符串用作「標識符」。

問題1,然後可以修改爲:這是一個很好的做法?

+0

你也可能會發現'FullForm'有趣。例如,嘗試'FullForm [g]'。 mathematica中的大多數對象都以這種方式感興趣,例如嘗試'繪製[Sin [x],{x,-5,5}]',接着是'FullForm @%'。所以通常可以做這樣的事情:http://stackoverflow.com/questions/6477649/replacing-disks-by-crosses-using-graphics-in-mathematica/6478079#6478079(這在mathematica中相當普遍: 「真實」的東西形式是表達式,可以像其他表達式一樣操作) – acl

4

我想知道你使用的是什麼版本的Mathematica?

圖論更緊密地集成到V8的核心,這在很大程度上是一種改進。您可以以面向對象的程序員可能喜歡的方式與圖形進行交互。在V8中,我會像這樣執行你的例子:

g = Graph[Range[5], {1 -> 2, 2 -> 4, 4 -> 4, 4 -> 5}]; 
g = SetProperty[{g, 3}, VertexStyle -> Red] 

然後我就可以查詢的屬性,如下:

PropertyValue[{g, 3}, VertexStyle] 

不幸的是,大多數的舊圖論的功能不能很好地發揮中V8。雖然,如果您對上下文規範非常小心,可以使用它。在V7中,我可能訪問的GraphEdit輸出像這樣:

Needs["GraphUtilities`"]; 
g = GraphEdit[]; 

然後,

{vertices, edges} = {"VertexLabels", "Graph"} /. Rest[g] 

得到的東西價值傳遞給其他的功能,如GraphPlot

這部分地回答了你的問題,這是否是一個合理的表示。這種表示方式可以通過替換規則輕鬆訪問信息。 XML導入的工作方式就是一個很好的例子。

相關問題