Download or view GraphTest.frink in plain text format
use Graph.frink
/** This class tests graph algorithms defined in Graph.frink
*/
/**
Sample 1. From an adjacency matrix.
See the diagrams at
https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-greedy-algo-7/
*/
adj = [[0, 4, 0, 0, 0, 0, 0, 8, 0],
[4, 0, 8, 0, 0, 0, 0, 11, 0],
[0, 8, 0, 7, 0, 4, 0, 0, 2],
[0, 0, 7, 0, 9, 14, 0, 0, 0],
[0, 0, 0, 9, 0, 10, 0, 0, 0],
[0, 0, 4, 14, 10, 0, 2, 0, 0],
[0, 0, 0, 0, 0, 2, 0, 1, 6],
[8, 11, 0, 0, 0, 0, 1, 0, 7],
[0, 0, 2, 0, 0, 0, 6, 7, 0]]
//println[formatTable[[["adj = ", formatTableInput[adj]]], "left", "top"]]
println["Sample 1:"]
g = Graph.fromDirectedAdjacencyMatrix[adj, 0]
start = now[]
allShortest = g.allShortestDistancesInt[0]
for n = 0 to 8
{
gp = g.findShortestPath[0, n]
println["Node 0 to node $n: " + gp.getDistance[] + "\t" + gp.getNodes[]]
println["Node 0 to node $n: " + g.shortestDistance[0, n]]
println["Node 0 to node $n: " + allShortest@n]
}
end = now[]
println["Time in Dijkstra: " + (end-start->"ms")]
println[]
//println["Original adjacency:"]
//println[formatTable[adj]]
s = now[]
alldist = g.allShortestDistances[]
for out = 0 to 8
println["Node 0 to node $out: " + alldist.getDistance[0,out]]
e = now[]
println["Time in Floyd: " + (e-s -> "ms")]
println[]
//println[formatTable[alldist.toDict[]]]
/**
Sample 2. From a 4-way grid
Solver for Advent of Code 2021, day 15, part 1
https://adventofcode.com/2021/day/15
This uses Graph.frink to perform the solution and is super-simple!
*/
//lines = readLines["file:input15.txt"]
lines = splitLines["""1163751742
1381373672
2136511328
3694931569
7463417111
1319128137
1359912421
3125421639
1293138521
2311944581"""]
grid = new array
for line = lines
grid.push[eval[toArray[charList[line]]]]
[rows, cols] = grid.dimensions[]
graph = Graph.from4WayGrid[grid, 0]
gp = graph.findShortestPath[ [0,0], [rows-1, cols-1] ]
println["Sample 2:"]
println[" distance is " + gp.getDistance[]]
println[]
// Now graph the path for fun
g = new graphics
g.font["Monospaced", 1]
p = new polyline
for [row,col] = gp.getNodes[]
{
g.text[ grid@row@col, col, row ]
p.addPoint[col,row]
}
g.add[p]
g.show[]
/**
Sample 2.1 From a 4-way grid using A* search
Solver for Advent of Code 2021, day 15, part 1
https://adventofcode.com/2021/day/15
This uses Graph.frink to perform the solution and is super-simple!
*/
//lines = readLines["file:input15.txt"]
lines = splitLines["""1163751742
1381373672
2136511328
3694931569
7463417111
1319128137
1359912421
3125421639
1293138521
2311944581"""]
grid = new array
for line = lines
grid.push[eval[toArray[charList[line]]]]
[rows, cols] = grid.dimensions[]
graph = Graph.from4WayGrid[grid, 0]
f = {|node,data|
[row, col] = node
[trow, tcol] = data
return abs[trow-row] + abs[tcol-col]
}
gpa = graph.findShortestPathAStar[ [0,0], [rows-1, cols-1], f, [rows-1,cols-1] ]
gpd = graph.findShortestPath[ [0,0], [rows-1, cols-1]]
println["Sample 2.1:"]
println[" distance (A*) is " + gpa.getDistance[]]
println[" distance (Dijkstra) is " + gpd.getDistance[]]
println[]
// Now graph the path for fun
g = new graphics
g.font["Monospaced", 1]
p = new polyline
for [row,col] = gp.getNodes[]
{
g.text[ grid@row@col, col, row ]
p.addPoint[col,row]
}
g.add[p]
g.show[]
/**
Sample 3. Solver for Crash and Compile problem.
Find the shortest path between nodes.
*/
line = """(N100,N33),(N44,N27),(N16,N44),(N1,N9),(N16,N22),(N49,N34),(N33,N16),(N22,N0),(N3,N16),(N41,N44),(N3,N35),(N27,N8),(N0,N8),(N9,N0),(N17,N35),(N26,N46)"""
graph = new Graph
for [node1, node2] = line =~ %r/\((.*?),(.*?)\)/g
graph.addBidiEdge[node1, node2]
gp = graph.findShortestPathBreadthFirst["N0", "N100"]
println["Sample 3:"]
println["Node 0 to node $n: " + gp.getDistance[] + "\t" + gp.getNodes[]]
println[]
/**
Sample 4. Maze solver. Crash and Compile DC25 escape easy problem.
https://bitbucket.org/crashandcompile/dc25-problems/src/master/
*/
maze = ["========S=============",
"======== = ========",
"== = = = = = =",
"== = === = = = = =",
"== = ==== = = = ==",
"== = == = = =",
"=== ===== == == =",
"== = = = = == == =",
"E == = == = = =",
"= === = = = = ==",
"= == ==== = ===",
" = = = = == = ===",
"= = = == = == ==",
"== ==== = = = == =",
"== == = == = = = =",
"== = = = = = =",
"==== === = = == =",
"== == = = = = = ==",
"== = = = == = =",
"== ==== = = = === =",
"== = == =",
"======================",
"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"]
graph = new Graph
grid = new array
row = 0
start = undef
end = undef
g = new graphics
g.font["Monospaced", 1]
LINES:
for line = maze
{
if line =~ %r/%/
break LINES
gridline = new array
grid.push[gridline]
col = 0
for c = charList[line]
{
g.text[c,col,row]
if c == "S"
start = [row, col]
if c == "E"
end = [row, col]
if c == " " or c == "S" or c == "E"
gridline.push[1]
else
gridline.push[0]
col = col + 1
}
row = row + 1
}
println["Sample 4:"]
graph = Graph.from4WayGrid[grid, 0]
gp = graph.findShortestPathBreadthFirst[ start, end ]
p = new polyline
for [y, x] = gp.getPath[]
{
println["(" + (x+1) + "," + (y+1) + ")"]
p.addPoint[x, y]
}
g.add[p]
g.show[]
/** Test 5. Test for directed graph with negative edge weights which requires
the Bellman-Ford algorithm. See
https://www.geeksforgeeks.org/bellman-ford-algorithm-dp-23/
*/
graph = new Graph
graph.addDirectedEdge[0, 1, -1]
graph.addDirectedEdge[0, 2, 4]
graph.addDirectedEdge[1, 2, 3]
graph.addDirectedEdge[1, 3, 2]
graph.addDirectedEdge[1, 4, 2]
graph.addDirectedEdge[3, 2, 5]
graph.addDirectedEdge[3, 1, 1]
graph.addDirectedEdge[4, 3, -3]
println[]
println["Sample 5:"]
println["connected components from 0: " + graph.countConnected[0]]
println["connected components from 1: " + graph.countConnected[1]]
println["connected components from 2: " + graph.countConnected[2]]
println["connected components from 3: " + graph.countConnected[3]]
println["connected components from 4: " + graph.countConnected[4]]
println["connected components from 5: " + graph.countConnected[5]] // Fake node
for n = 0 to 4
{
gp = graph.findShortestPathBellmanFord[0, n]
println["Node 0 to node $n: " + gp.getDistance[] + "\t" + gp.getNodes[]]
}
println[]
println["inverted:"]
gi = graph.invert[]
for n = 0 to 4
{
gp = gi.findShortestPathBellmanFord[n, 0]
println["Node $n to node 0: " + gp.getDistance[] + "\t" + gp.getNodes[]]
}
println[]
/** Sample 6. Create a minimum spanning tree.
See:
https://www.geeksforgeeks.org/prims-minimum-spanning-tree-mst-greedy-algo-5/
*/
// This is the graph fron Skiena Figure 6.3
g = new Graph
g.addBidiEdge["A", "B", 5]
g.addBidiEdge["A", "D", 7]
g.addBidiEdge["A", "E", 12]
g.addBidiEdge["B", "C", 7]
g.addBidiEdge["B", "D", 9]
g.addBidiEdge["C", "D", 4]
g.addBidiEdge["C", "F", 2]
g.addBidiEdge["C", "G", 5]
g.addBidiEdge["D", "E", 4]
g.addBidiEdge["D", "F", 3]
g.addBidiEdge["E", "F", 7]
g.addBidiEdge["F", "G", 2]
//println[formatTable[[["adj =", formatTableInput[adj]]], "left", "top"]]
g2 = g.minimumSpanningTree["A", false]
edges = sort[g2.getBidiEdges[], byColumn[0]]
edges.pushFirst[["from", "to", "weight"]]
println["Sample 6:"]
println[formatTable[edges]]
println[]
// Output a graphviz .dot file. This can be rendered with something like:
// dot -Tsvg graph6.dot > graph6.svg
dot = g.toDotFile[false, """node [fontname="sans-serif"]"""]
w = new Writer["graph6.dot"]
w.print[dot]
w.close[]
/** Sample 7. Create a minimal spanning tree using Kruskal's algorithm */
g3 = g.minimumSpanningForest[]
edges = sort[g3.getAllEdgesWithFlags[], byColumn[0]]
edges.pushFirst[["from", "to", "weight"]]
println["Sample 7:"]
println[formatTable[edges]]
println[]
/** Sample 8. Create a minimal spanning forest using Kruskal's algorithm */
// This is the graph fron Skiena Figure 6.3 plus some diconnected edges.
g = new Graph
g.addBidiEdge["A", "B", 5]
g.addBidiEdge["A", "D", 7]
g.addBidiEdge["A", "E", 12]
g.addBidiEdge["B", "C", 7]
g.addBidiEdge["B", "D", 9]
g.addBidiEdge["C", "D", 4]
g.addBidiEdge["C", "F", 2]
g.addBidiEdge["C", "G", 5]
g.addBidiEdge["D", "E", 4]
g.addBidiEdge["D", "F", 3]
g.addBidiEdge["E", "F", 7]
g.addBidiEdge["F", "G", 2]
// The following are disconnected from the main graph
g.addBidiEdge["H", "I", 1]
g.addBidiEdge["J", "K", 10]
g.addBidiEdge["K", "L", 5]
g.addNode["M"]
g4 = g.minimumSpanningForest[]
edges = sort[g4.getAllEdgesWithFlags[], byColumn[0]]
edges.pushFirst[["from", "to", "weight"]]
println["Sample 8:"]
println[formatTable[edges]]
println[]
println["Disconnected nodes: " + g.getDisconnectedNodes[]]
/** Sample 9. Performs a breadth-first search of a graph and prints the nodes
visited. */
g9 = new Graph
// This is the graph in figure 5.9 of Skiena
g9.addBidiEdge[1,6]
g9.addBidiEdge[1,5]
g9.addBidiEdge[1,2]
g9.addBidiEdge[2,3]
g9.addBidiEdge[2,5]
g9.addBidiEdge[3,4]
g9.addBidiEdge[4,5]
println["\nSample 9: Breadth first traversal"]
watcher = new GraphNodeLogger
g9.breadthFirstTraverse[1, watcher]
/** Sample 10. Performs a depth-first search of a graph and prints the nodes
visited. */
println["\nSample 10: depth-first traversal"]
watcher = new GraphNodeLogger
g9.depthFirstTraverse[1, watcher]
/** Sample 11. Topological sort. */
println["\nSample 11: topological sort"]
// Example from https://en.wikipedia.org/wiki/Topological_sorting
g11 = new Graph
g11.addDirectedEdge[5,11]
g11.addDirectedEdge[11,2]
g11.addDirectedEdge[11,9]
g11.addDirectedEdge[11,10]
g11.addDirectedEdge[7,11]
g11.addDirectedEdge[7,8]
g11.addDirectedEdge[8,9]
g11.addDirectedEdge[3,8]
g11.addDirectedEdge[3,10]
println[g11.topologicalSort[]]
// Sample 12: All topological sorts
println["\nSample 12: all topological sorts"]
s12 = g11.allTopologicalSorts[]
while r = s12.nextResult[]
println[r]
// Sample 13: All topological sorts of example page
// From:
// https://www.geeksforgeeks.org/all-topological-sorts-of-a-directed-acyclic-graph/
println["\nSample 13: all topological sorts 2"]
g13 = new Graph
g13.addDirectedEdge[5,0]
g13.addDirectedEdge[5,2]
g13.addDirectedEdge[4,0]
g13.addDirectedEdge[4,1]
g13.addDirectedEdge[2,3]
g13.addDirectedEdge[3,1]
s13 = g13.allTopologicalSorts[]
while r = s13.nextResult[]
println[r]
Download or view GraphTest.frink in plain text format
This is a program written in the programming language Frink.
For more information, view the Frink
Documentation or see More Sample Frink Programs.
Alan Eliasen, eliasen@mindspring.com