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[]
for n = 0 to 8
{
gp = g.findShortestPath[0, n]
println["Node 0 to node $n: " + gp.getDistance[] + "\t" + gp.getNodes[]]
}
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 was born 20217 days, 15 hours, 14 minutes ago.