diff --git a/lib/graph/graph.ts b/lib/graph/graph.ts new file mode 100644 index 0000000..5ecf1ee --- /dev/null +++ b/lib/graph/graph.ts @@ -0,0 +1,97 @@ +export type Graph = { + vertices: { + [v: string]: V + }, + edges: { + [v: string]: Set + } +} + +export type AddVertex = (name: string, v: V) => void +export type AddEdge = (source: string, dest: string) => void + +export const createGraph = (cons: (v: AddVertex, e: AddEdge) => void): Graph => { + const g: Graph = { vertices: {}, edges: {} } + + const addVertex = (name: string, v: V) => { + g.vertices[name] = v + g.edges[name] = new Set() + } + + const addEdge = (source: string, dest: string) => { + if (typeof g.vertices[source] === "undefined") { + throw new Error(`vertex \`${source}' does not exist in graph`) + } else if (typeof g.vertices[dest] === "undefined") { + throw new Error(`vertex \`${dest}' does not exist in graph`) + } + + g.edges[source].add(dest) + g.edges[dest].add(source) + } + + cons(addVertex, addEdge) + + return g +} + +export const neighbors = (g: Graph, name: string): Set => { + if (typeof g.vertices[name] === "undefined") { + throw new Error(`vertex \`${name}' does not exist in graph`) + } + + return g.edges[name] +} + +export const vertices = (g: Graph): Set => new Set(Object.keys(g.vertices)) + +export const maxCardinalitySearch = (g: Graph): Array => { + const weights: { [s: string]: number } = {} + const ordering: Array = [] + + let W = vertices(g) + const numVertices = W.size + + for (let i = 0; i < numVertices; ++i) { + const v = findMaxWeight(weights, W) + ordering.push(v) + + setIntersect(W, neighbors(g, v)).forEach(x => + weights[x] = (weights[x] || 0) + 1 + ) + + W.delete(v) + } + + return ordering +} + +const findMaxWeight = (weights: { [s: string]: number }, W: Set): string => { + let maxV = null + let maxWeight = -Infinity + + W.forEach(v => { + const vWeight = weights[v] || 0 + if (vWeight > maxWeight) { + maxV = v + maxWeight = vWeight + } + }) + + if (maxV === null) { + throw new Error(`remaining vertex set is empty`) + } + + return maxV +} + +const setIntersect = (xs: Set, ys: Set): Set => { + const intersection: Set = new Set() + + xs.forEach(x => { + if (ys.has(x)) { + intersection.add(x) + } + }) + + return intersection +}