@AntonAntonov's answer with the TriesWithFrequencies.m package is more elegant and useful, but here is a brute force approach without any extra packages.
(Note: This approach finds all simple paths including dead ends, see comments for more details. Edited to process more general graphs with more than 10 vertices.)
The main challenge is that the final tree should have the same graph vertices and edges depicted in different positions based on path order. One way to get around this problem is to relabel the vertices as we construct paths, and then use the VertexLabels
function to relabel the vertices at the end.
Step 1 - Define the undirected graph
Edit: introduced maxVertexValue
here to make subsequent code applicable to larger graphs
exampleGraph = Graph[{1 <-> 2, 1 <-> 4, 1 <-> 5, 2 <-> 3, 3 <-> 4, 3 <-> 5, 4 <-> 5}, VertexLabels -> "Name"]
maxVertexValue = Max[VertexList[exampleGraph]];
Step 2 - UseFindPath
to construct a list of all relevant paths. This include the paths that successfully get from "1" to "2" as well as the lists that start from "1" but do not contain "2".
successfulPaths = FindPath[exampleGraph, 1, 2, 5, All];
unsuccessfulPaths = Flatten[Table[Select[FindPath[exampleGraph, 1, x, maxVertexValue, All],!MemberQ[#, 2] &], {x, 3, maxVertexValue}], 1]
allPaths = Join[successfulPaths, unsuccessfulPaths];
Or more concisely:
allPaths = Flatten[Table[Select[FindPath[exampleGraph, 1, x, maxVertexValue, All], Last[#] == 2 || ! MemberQ[#, 2] &], {x, 2, maxVertexValue}],1];
Either case returns the following allPaths list:
{{1, 2}, {1, 5, 3, 2}, {1, 4, 3, 2}, {1, 5, 4, 3, 2}, {1, 4, 5, 3, 2}, {1, 5, 3}, {1, 4, 3}, {1, 5, 4, 3}, {1, 4, 5, 3}, {1, 4}, {1, 5, 4}, {1, 5, 3, 4}, {1, 5}, {1, 4, 5}, {1, 4, 3, 5}}
Step 3 - Give every vertix a path dependent name (EDITED to label each vertex with a path list). For example, the path list {1,5,3,2} can be relabeled as {{1},{1,5},{1,5,3},{1,5,3,2}}. These labels will help us group all 1->5 paths in the first step together.
relabeldPaths = Table[x[[1 ;; y]]], {x, allPaths}, {y, Length[x]}];
Step 4 - Convert the relabeled paths list to a unique set of directed edges and vertices. There is probably a much better way to do this, but I combined EdgeList
with PathGraph
as follows:
pathEdges = Flatten[Map[EdgeList[PathGraph[#, DirectedEdges -> True]] &, relabeldPaths] /. DirectedEdge -> Rule];
treeEdges = DeleteDuplicates[pathEdges];
treeVertices = VertexList[Graph[treeEdges]];
Step 5 - Plot final graph using VertexLabels
to select the Last
part of each vertex name. (EDITED to make labels clearer)
Graph[treeEdges, VertexSize -> Large, VertexLabels -> Table[x -> Placed[Last[x], Center], {x, treeVertices}], ImageSize -> Medium]
EDIT: Here is a generalized module for this approach for quick copy/paste
pathTreeGraph[graph_, startingVertex_, endingVertex_] :=
Module[{maxVertexValue, allPaths, relabeldPaths, pathEdges,
treeEdges, treeVertices}, maxVertexValue = Max[VertexList[graph]];
allPaths = Flatten[Table[
Select[FindPath[graph, startingVertex, x, maxVertexValue, All],
Last[#] == endingVertex || !MemberQ[#, endingVertex] &],
{x, DeleteCases[VertexList[graph], startingVertex]}], 1];
relabeldPaths = Table[Flatten[x[[1 ;; y]]], {x, allPaths}, {y, Length[x]}];
pathEdges = Flatten[Map[EdgeList[PathGraph[#, DirectedEdges -> True]] &, relabeldPaths] /. DirectedEdge -> Rule];
treeEdges = DeleteDuplicates[pathEdges];
treeVertices = VertexList[Graph[treeEdges]];
Graph[treeEdges, VertexSize -> Large,
VertexLabels -> Table[x -> Placed[Last[x], Center], {x, treeVertices}],
ImageSize -> Medium]]
exampleGraph = Graph[{1 <-> 2, 1 <-> 4, 1 <-> 5, 2 <-> 3, 3 <-> 4, 3 <-> 5, 4 <-> 5}, VertexLabels -> "Name"]
pathTreeGraph[exampleGraph, 1, 2]
UPDATE: Example with more than 10 vertices
ButterflyGraph[2, VertexLabels -> "Name", ImageSize -> Medium]
pathTreeGraph[ButterflyGraph[2], 1, 2]
TreeGraph
, you can find all the paths usingFindPath
and you can visualise paths on a graph usingPathGraph
andGraphHighlight
. $\endgroup${1,4,6}
a "deadlock path" in this graph ? $\endgroup$