1
$\begingroup$

I am building a tool to manipulate Feynman diagrams and depict them using the Graph functionality. A diagram might have the following syntax

f=diag[g[a,i[1]],g[b,i[2]],g[i[1],c],g[i[2],d],v[i[1],i[2]]]

This is just an example. Now we would like to represent it as a graph.

First way (using RuleDelayed):

Clear[pic]
pic[diag[x__]]:=Module[{i},Graph[List[x]/.{g[i_,j_]:> DirectedEdge[j,i],v[j_,k_]:> UndirectedEdge[j,k]},VertexLabels->"Name",PlotTheme->"Business",ImageSize->300,ImagePadding->10,VertexLabelStyle->Directive[Black,11],GraphHighlight->Cases[List[x],v[i_,j_]:> UndirectedEdge[i,j]]]]

Using it

pic[f]
i=5;
pic[f]

produces

enter image description here enter image description here

Thus we have an expected result and a result with wrong labels.

Second way (using Rule)

Clear[i,g,v,f]
f=diag[g[a,i[1]],g[b,i[2]],g[i[1],c],g[i[2],d],v[i[1],i[2]]];
Clear[pic]
pic[diag[x__]]:=Module[{i,j,k},Graph[List[x]/.{g[i_,j_]->DirectedEdge[j,i],v[j_,k_]->UndirectedEdge[j,k]},VertexLabels->"Name",PlotTheme->"Business",ImageSize->300,ImagePadding->10,VertexLabelStyle->Directive[Black,11],GraphHighlight->Cases[List[x],v[i_,j_]->UndirectedEdge[i,j]]]]

Now using it

pic[f]
i=5;
pic[f]

Produces the correct picture only the first time, and does not work at all second time.

$\endgroup$
12
  • $\begingroup$ RuleDelayed solves your problem in the second snippet. It is true that Rule treats named pattern as local to the rule. However in the second snippet, the right-hand side gets evaluated to Times[2, 5] before any replacing takes place. RuleDelayed first performs replacements, and then evaluates the expression on the right-hand side of the rule. I am still confused about the first snippet, though. $\endgroup$
    – Natas
    Commented Oct 30, 2020 at 10:55
  • $\begingroup$ I think SetDelayed is not relevant here. The confusing part is this: Clear[i, x]; i = n; Module[{i}, x /. {i_ -> i}] (*n*). To be honest, if this is expected behavior I have understood nothing about Module. $\endgroup$
    – Natas
    Commented Oct 30, 2020 at 11:03
  • $\begingroup$ OK, the relevant documentation for Module is this "Before evaluating expr, Module substitutes new symbols for each of the local variables that appear anywhere in expr except as local variables in scoping constructs." The issue now is that Rule is also a scoping construct (with named patterns). Therefore Module does not replace the i in the Rule. $\endgroup$
    – Natas
    Commented Oct 30, 2020 at 11:10
  • $\begingroup$ As a general rule I suggest: Any time you write a rule where the name of the pattern appears on the right-hand side, use RuleDelayed. This would be the "canonical way" in my opinion. $\endgroup$
    – Natas
    Commented Oct 30, 2020 at 11:13
  • $\begingroup$ Ok, in the second one the problem is of course again using Rule instead of RuleDelayed. In the first the problem for the label is that f is defined using i. Of course, if you later set i it will be used for the value of f. Mathematica usually evaluates expressions unless being told to hold them. $\endgroup$
    – Natas
    Commented Oct 30, 2020 at 11:29

1 Answer 1

5
$\begingroup$

Your question boils down to: "How can I prevent my special symbols to conflict with other global symbols?"

Solution 1: Block

With Block you can localize your symbols, protecting them from any global assignments. This is the recommended solution. (Note that Block is also used in the definition of pic.)

Clear[pic]
pic[diag[x__]] := 
 Block[{g, v}, 
  Graph[List[x] /. {g[i_, j_] :> DirectedEdge[j, i], 
     v[j_, k_] :> UndirectedEdge[j, k]}, VertexLabels -> "Name", 
   PlotTheme -> "Business", ImageSize -> 300, ImagePadding -> 10, 
   VertexLabelStyle -> Directive[Black, 11], 
   GraphHighlight -> 
    Cases[List[x], v[i_, j_] :> UndirectedEdge[i, j]]]]
Block[{i, g, v, a, b, c, d},
 f = diag[g[a, i[1]], g[b, i[2]], g[i[1], c], g[i[2], d], 
   v[i[1], i[2]]];
 pic[f]
 ]

Solution 2: Protect

This is a quick and easy solution to your problem. Protecting a symbol means that no one can assign to it. This should probably appear at the top of your notebook.

Clear[i, g, v, a, b, c, d];
Protect[i, g, v, a, b, c, d];
f = diag[g[a, i[1]], g[b, i[2]], g[i[1], c], g[i[2], d], v[i[1], i[2]]];

Solution 3: Formal symbols

This is probably a more cumbersome solution, since special symbols are hard to type in Mathematica. However, Mathematica features Formal variants of many symbols which cannot be assigned to.

Clear[pic]
pic[diag[x__]] := 
 Graph[List[
    x] /. {\[FormalG][i_, j_] :> 
     DirectedEdge[j, i], \[FormalV][j_, k_] :> UndirectedEdge[j, k]}, 
  VertexLabels -> "Name", PlotTheme -> "Business", ImageSize -> 300, 
  ImagePadding -> 10, VertexLabelStyle -> Directive[Black, 11], 
  GraphHighlight -> 
   Cases[List[x], \[FormalV][i_, j_] :> UndirectedEdge[i, j]]]
f = diag[\[FormalG][\[FormalA], \[FormalI][
     1]], \[FormalG][\[FormalB], \[FormalI][
     2]], \[FormalG][\[FormalI][
     1], \[FormalC]], \[FormalG][\[FormalI][
     2], \[FormalD]], \[FormalV][\[FormalI][1], \[FormalI][2]]];
pic[f]

(Another possible issue is that now the labels of the graph are the formal symbols.)

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.