Mathematica规则和GraphEdit返回的对象之间有什么区别? [英] What is the difference between Mathematica Rules and the objects returned by GraphEdit?

查看:76
本文介绍了Mathematica规则和GraphEdit返回的对象之间有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这实际上是两个问题.首先:作为一个来自OO编程背景的人,我发现Mathematica使用列表作为一切麻烦的基础.因此,据我所知,这是Mathematica程序员定义图的方式:

This is actually a two-fold question. First: as someone coming from an OO programming background, I find Mathematica's use of lists as the basis of everything a bit annoying. So here is how a mathematica programmer (as far as I can tell) might define a graph:

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

然后程序员只需要记住这一点

and then the programmer would just have to remember that

graph[[1]] 

指的是顶点列表

graph[[2]]

是指边的列表(在这种情况下,它定义为一组规则.)

refers to the list of edges (in this case defined as a set of rules.)

因此,我正在学习Mathematica中的规则,并且看到了使我的数据结构更加面向对象的机会.我选择定义如下图:

So, I was learning about the rules in Mathematica and I saw an opportunity to make my data structures a little more object-oriented feeling. I chose to define a graph something like:

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

然后分别通过

引用顶点和边

and then refer to vertices and edges (respectively) by

Verts/.graph
Edges/.graph

但是,如果某些其他Mathematica文件在某个位置将Verts或Edges定义为全局变量,则可能会产生怪异的副作用,因为规则的左手边不是标识符,而是对象本身.

This can have weird side effects, however, if some other Mathematica file has defined Verts or Edges as a global variable somewhere, however, since the left hand side of the rule is not an identifier, but is itself an object.

所以问题1是这样的:这对创建Mathematica数据结构是一种好的做法还是一种不好的做法?我这样做的原因之一是可以附加任意属性,例如颜色:

So question 1 is this: is this a good practice, or a bad one for creating Mathematica data structures? One of the reasons I'm doing it this way is so that I can attach arbitrary properties, say colors:

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

并且我的函数不必知道添加特定属性的确切顺序.例如,您可能具有如下定义的GetColor函数:

and my functions don't have to know the exact order particular properties were added. For instance you might have a function GetColor defined like:

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

这是可取的,因为我可能不总是希望具有包含颜色信息的图形数据结构,因此不想在列表中保留一个点(例如graph [[[3]]])作为颜色信息

and this is preferable, because I might not always want to have graph data structures that have Color info and so don't want to reserve a spot in the list (like graph[[[3]]]) for color information.

第二:我看到GraphEdit返回的内容类似于我上面描述的规则.例如,如果我执行(并绘制图形)

Second: I see that GraphEdit returns something that looks like the rules I've described above. For instance, if I execute (and draw a graph)

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

我得到如下输出:

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

看起来很规律!所以我试试这个:

which looks like a rule! So I try this:

Graph/.g[[2]]

期望拥有

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

返回.但是相反,输出只是

returned. But instead the output is just

Graph

但是如果我改为执行

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

我得到了预期的输出,

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

这意味着g [[2]]确实是一个规则,但是由于某些原因g [[2]] [[1]](如果执行则显示Graph)与键入Graph不同.那么g [[2]] [[1]]到底是什么呢?

which means that g[[2]] really is a rule, but for some reason g[[2]][[1]] (which if executed prints Graph) is not the same as typing Graph. So what the heck is g[[2]][[1]]?

似乎几乎是一个真实的标识符,如果是的话,我想用它来解决上述问题1的问题.任何人都知道区别,或者如何在Mathematica中键入一个对另一个?

It seems almost like it is a real identifier, which if so, I would like to use to solve the problems with question 1 above. Anyone know the difference, or how to type one vs. the other into Mathematica?

我在文档中找不到任何相关内容(或在线内容).谢谢.

I cannot find anything in the documentation about any of this (or online). Thanks.

推荐答案

GraphEdit规则

GraphEdit返回一个列表,该列表的第一个元素是Graphics对象,其其余元素是描述图形的规则.每个规则的左侧是一个字符串,而不是一个符号.您可以使用g // FullForm确定.要提取图形规则,您必须忽略列表的第一个元素,例如

GraphEdit returns a list whose first element is a Graphics object and whose remaining elements are rules that describe the graph. The left-hand side of each rule is a string, not a symbol. You can determine this using g // FullForm. To extract the graph rules, you must ignore the first element of the list, e.g.

"Graph" /. Drop[g, 1]

模拟记录类型

按照您的建议,这是一种实现类似记录的数据类型的合理方法:

It is a reasonable approach to implement record-like data types as you propose:

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

的确,如果为VertsEdges分配了值,则将发生怪异的副作用".但是,有两种方法可以缓解该问题.

It is true that if Verts and Edges were assigned values, then "weird side effects" would occur. However, there are a couple of ways to mitigate that problem.

首先,在Mathematica中,有一个非常普遍的约定,就是避免将值(特别是OwnValues)分配给具有大写首字母的符号. Wolfram在所有顶级变量的前面加上$,例如$Context.如果遵守这些约定,您将获得一定程度的安全性.

First, there is an extremely widespread convention within Mathematica to avoid assigning values (specifically OwnValues) to symbols with upper case initial letters. Wolfram prefixes all top-level variables with $, e.g. $Context. If you stick to these conventions, you get some measure of safety.

第二,提供了使用 Packages 的单独名称空间的规定.在您定义的包范围内,您可以完全控制用作字段名称的符号的绑定.

Second, there is provision for separate namespaces using Packages. Within the bounds of a package you define, you can have complete control over the bindings of symbols that you use as field names.

第三,您可以使用保护以防止为字段名称分配值给他们.

Third, you can use Protect to prevent field names from having values assigned to them.

实现这些记录类型时,可以遵循LISP习惯用法并定义构造函数和访问函数.对于图示例,这些函数可能看起来像这样:

When implementing these record types, one could follow a LISP idiom and define constructor and accessor functions. For the graph example, these functions could look something like this:

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可以对包装私有,并受到保护,从而完全避免了偶然的值分配破坏事物的可能性.

Using this scheme, the field keys Verts and Edges can be private to a package and protected, completely avoiding the prospect of an accidental value assignment ruining things.

在Mathematica中,使用表达式的Head标识其类型是非常普遍的.我们可以遵循这个习惯用法,然后重新定义记录功能:

In Mathematica, it is extremely common to use the Head of an expression to identify its type. We can conform to this idiom and redefine our record functions thus:

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

这些定义与前面的定义之间唯一的实质区别是,图形对象现在由graphRecord[...]而不是{...}形式的表达式表示:

The only material difference between these and the preceding definitions is that the graph object is now represented by an expression of the form graphRecord[...] instead of {...}:

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起作用,而对其他功能不起作用.例如:

Why the change? The first reason is that the head graphRecord now positively identifies the type of data whereas before it was just a list. Second, we can define further functions (quasi-methods) that will only act on graphRecords and nothing else. For example:

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的无效参数:hi
$ Aborted
During evaluation of graphEdgeCount::invArg: Invalid argument to graphEdgeCount: hi
$Aborted

作为所有这些的最后详细说明,可以定义一个宏函数,该宏函数在给定类型和字段名称的情况下自动定义所有记录函数.但是,由于此响应已经是TL; DR,因此最好将其留给某天作为另一个问题的话题.

As a final elaboration to all of this, it would be possible to define a macro function that automatically defined all the record functions given the type and field names. However, as this response is already TL;DR, that is probably best left as topic for another question some day.

注意:如果这些功能都是在包的上下文中定义的,则它们的名称将使用大写字母(例如MakeGraph而不是makeGraph).但是请注意,Mathematica已经有很多内置符号,其中包括单词Graph.

Note: If these functions were all defined within the context of a package, their names would use initial capitals (e.g. MakeGraph instead of makeGraph). Beware, however, that Mathematica already has lots of built-in symbols that include the word Graph.

这篇关于Mathematica规则和GraphEdit返回的对象之间有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆