# Adding edges to a TreeForm of an expression

Say I have an expression {1,{{2,3},4}}. It's TreeForm looks as follows:

{1,{{2,3},4}} //TreeForm

Now, on each level of that tree I would like to draw an edge where there isn't one, i.e. between 1 and List (first level), between List and 4 (second level) and between 2 and 3 (third level). Is it possible to do it in an efficient way? Can I somehow control the direction of all of these edges (including already existing ones)? I tried to use IGExpressionTree from the IGraph package together with EdgeAdd but it didn't work. Any suggestions?

• maybe EdgeAdd[GraphComputationExpressionGraph[{1, {{2, 3}, 4}} ], {2->3,4->7,5->6}]?
– kglr
May 23, 2019 at 11:50
• @kglr Thanks! Does that work, I've tried EdgeAdd[IGExpressionTree[{1, {{2, 3}, 4}}, VertexLabels->"Subexpression"],4\[UndirectedEdge]6], but that didn't work, I wonder why.. May 23, 2019 at 11:55
• What if you have more than two nodes at the same level in the tree? May 23, 2019 at 12:02
• @amator2357 IGExpressionTree does not use the same vertex names as GraphComputationExpressionGraph May 23, 2019 at 12:07
• @Szabolcs it'll never happen for my case May 23, 2019 at 12:07

g0 = GraphComputationExpressionGraph[{1, {{2, 3}, 4}} , ImageSize -> 200];
newedges = UndirectedEdge @@@ GatherBy[Rest@VertexList@g0, GraphDistance[g0, 1, #] &]

{2 \[UndirectedEdge] 3, 4 \[UndirectedEdge] 7, 5 \[UndirectedEdge] 6}

Row[{g0, g1}, Spacer[10]]

Alternatively, you can use newedges to post-process the TreeForm of the input expression to add the new lines:

tf1 = TreeForm[{1, {{2, 3}, 4}}, DirectedEdges -> True, ImageSize -> Medium];
tf2 = RawBoxes[ToBoxes[tf1] /.  l : (_ArrowBox | _LineBox) :>
{l, Dashing @ Small, LineBox @ # }] &[List @@@ newedges];
Row @ {tf1, tf2}

If there are more than two nodes at the same level in the tree:

g0 = GraphComputationExpressionGraph[{1, {{2, 3}, 4, 5}} , ImageSize -> 200];
newedges = Join @@ Map[UndirectedEdge @@@ # &,
Subsets[#, {2}] & /@ GatherBy[Rest@VertexList@g0, GraphDistance[g0, 1, #] &]]

{2 \[UndirectedEdge] 3, 4 \[UndirectedEdge] 7, 4 \[UndirectedEdge] 8, 7 \[UndirectedEdge] 8, 5 \[UndirectedEdge] 6}

{EdgeShapeFunction -> {Alternatives @@ newedges :> "CurvedArc"}}]
Row[{g0, g1}, Spacer[10]]

g = IGExpressionTree[{1, {{2, 3}, 4}}]

Notice that the vertices created by this function are lists (encoding subexpression positions), and their length is the same if they are on the same tree level.

IGExpressionTree[{1, {{2, 3}, 4}}, VertexLabels -> "Name"]

Thus we can easily create the additional edges:

pathEdges[list_] := DirectedEdge @@@ Partition[list, 2, 1]

newEdges = Flatten[pathEdges /@ GatherBy[VertexList[g], Length]]
(* {{1} \[DirectedEdge] {2}, {2, 1, 1} \[DirectedEdge] {2, 1, 2}, {2, 1} \[DirectedEdge] {2, 2}} *)