Last active
November 18, 2019 21:59
-
-
Save busypeoples/896603ad90cae035e7ae2d1418873973 to your computer and use it in GitHub Desktop.
Data Structures in ReasonML: #8 Graph
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Graph */ | |
exception Not_found; | |
type nodes = list(int); | |
type edges = list((int, int)); | |
type graph = | |
| Empty | |
| Graph(nodes, edges); | |
module type Graph = { | |
type t = int; | |
let empty: graph; | |
let addNode: (t, graph) => graph; | |
let addEdge: (t, t, graph) => graph; | |
let removeNode: (t, graph) => graph; | |
let removeEdge: (t, t, graph) => graph; | |
let path: (t, t, graph) => list(t); | |
let relations: graph => int; | |
let size: graph => int; | |
}; | |
module Graph: Graph = { | |
type t = int; | |
let empty = Empty; | |
let addNode = (node, graph) => | |
switch (graph) { | |
| Empty => Graph([node], []) | |
| Graph(nodes, edges) => Graph([node, ...nodes], edges) | |
}; | |
let removeNode = (node, graph) => | |
switch (graph) { | |
| Empty => Empty | |
| Graph([], edges) => Graph([], edges) | |
| Graph(nodes, edges) => | |
Graph( | |
List.filter(n => n !== node, nodes), | |
List.filter(((f, t)) => node !== f && node !== t, edges), | |
) | |
}; | |
let addEdge = (from_, to_, graph) => | |
switch (graph) { | |
| Empty => Empty | |
| Graph(nodes, edges) => Graph(nodes, [(from_, to_), ...edges]) | |
}; | |
let removeEdge = (from_, to_, graph) => | |
switch (graph) { | |
| Empty => Empty | |
| Graph(nodes, []) => Graph(nodes, []) | |
| Graph(nodes, edges) => | |
Graph( | |
nodes, | |
List.filter(((f, t)) => from_ !== f || to_ !== t, edges), | |
) | |
}; | |
let size = graph => | |
switch (graph) { | |
| Empty => 0 | |
| Graph(nodes, _) => List.length(nodes) | |
}; | |
let relations = graph => | |
switch (graph) { | |
| Empty => 0 | |
| Graph(_, edges) => List.length(edges) | |
}; | |
let getNeighbors = (from_, cond, graph) => | |
switch (graph) { | |
| Empty => [] | |
| Graph(_, edges) => | |
List.fold_left( | |
(list, (fr_, to_)) => | |
if (fr_ == from_ && cond(to_)) { | |
[to_, ...list]; | |
} else if (to_ == from_ && cond(fr_)) { | |
[fr_, ...list]; | |
} else { | |
list; | |
}, | |
[], | |
edges, | |
) | |
}; | |
let rec listPath = (from_, to_, graph) => | |
switch (to_) { | |
| [] => raise(Not_found) | |
| [first, ..._] => | |
if (first === from_) { | |
to_; | |
} else { | |
let possiblePaths = | |
List.map( | |
t => listPath(from_, [t, ...to_], graph), | |
getNeighbors(first, a => ! List.mem(a, to_), graph), | |
); | |
List.fold_left( | |
(shortestPath, path) => | |
switch (shortestPath, path) { | |
| ([], []) => [] | |
| (currentPath, []) => currentPath | |
| ([], path) => path | |
| (currentPath, path) => | |
if (List.length(path) < List.length(currentPath)) { | |
path; | |
} else { | |
currentPath; | |
} | |
}, | |
[], | |
possiblePaths, | |
); | |
} | |
}; | |
let path = (from_, to_, graph) => | |
if (from_ === to_) { | |
[to_]; | |
} else { | |
listPath(from_, [to_], graph); | |
}; | |
}; | |
let run = () => { | |
let printPath = path => | |
List.fold_left((s, v) => s ++ string_of_int(v) ++ " ", "", path); | |
let t = Graph.empty; | |
let t = Graph.addNode(1, t); | |
let t = Graph.addNode(2, t); | |
let t = Graph.addNode(3, t); | |
let t = Graph.addNode(4, t); | |
let t = Graph.addNode(5, t); | |
let t = Graph.addEdge(1, 2, t); | |
let t = Graph.addEdge(1, 4, t); | |
let t = Graph.addEdge(2, 5, t); | |
let t = Graph.addEdge(3, 4, t); | |
let t = Graph.addEdge(3, 5, t); | |
let t = Graph.addEdge(4, 5, t); | |
Js.log2("Size is 5: ", Graph.size(t) === 5); | |
Js.log2("Relations is 6: ", Graph.relations(t) === 6); | |
Js.log2("path from 5 to 1 is 5 2 1 -> ", printPath(Graph.path(5, 1, t))); | |
Js.log2("path from 2 to 4 is 2 1 4 -> ", printPath(Graph.path(2, 4, t))); | |
let t = Graph.removeEdge(1, 2, t); | |
let t = Graph.removeEdge(4, 5, t); | |
Js.log2("Relations is 4:", Graph.relations(t) === 4); | |
Js.log2( | |
"path from 5 to 1 is 5 3 4 1 -> ", | |
printPath(Graph.path(5, 1, t)), | |
); | |
Js.log2( | |
"path from 2 to 4 is 2 5 3 4 -> ", | |
printPath(Graph.path(2, 4, t)), | |
); | |
let t = Graph.addEdge(1, 2, t); | |
let t = Graph.addEdge(4, 5, t); | |
Js.log2("Relations is 6:", Graph.relations(t) === 6); | |
Js.log2("path from 5 to 1 is 5 4 1 -> ", printPath(Graph.path(5, 1, t))); | |
Js.log2("path from 2 to 4 is 2 1 4 -> ", printPath(Graph.path(2, 4, t))); | |
let t = Graph.removeNode(3, t); | |
Js.log2("Size is 4: ", Graph.size(t) === 4); | |
Js.log2("Relations is 4: ", Graph.relations(t) === 4); | |
Js.log2("path from 5 to 1 is 5 4 1 -> ", printPath(Graph.path(5, 1, t))); | |
Js.log2("path from 2 to 4 is 2 1 4 -> ", printPath(Graph.path(2, 4, t))); | |
}; | |
run(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment