|
|
@ -0,0 +1,97 @@ |
|
|
|
export type Graph<V> = { |
|
|
|
vertices: { |
|
|
|
[v: string]: V |
|
|
|
}, |
|
|
|
edges: { |
|
|
|
[v: string]: Set<string> |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
export type AddVertex<V> = (name: string, v: V) => void |
|
|
|
export type AddEdge = (source: string, dest: string) => void |
|
|
|
|
|
|
|
export const createGraph = <V>(cons: (v: AddVertex<V>, e: AddEdge) => void): Graph<V> => { |
|
|
|
const g: Graph<V> = { 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 = <V>(g: Graph<V>, name: string): Set<string> => { |
|
|
|
if (typeof g.vertices[name] === "undefined") { |
|
|
|
throw new Error(`vertex \`${name}' does not exist in graph`) |
|
|
|
} |
|
|
|
|
|
|
|
return g.edges[name] |
|
|
|
} |
|
|
|
|
|
|
|
export const vertices = <V>(g: Graph<V>): Set<string> => new Set(Object.keys(g.vertices)) |
|
|
|
|
|
|
|
export const maxCardinalitySearch = <V>(g: Graph<V>): Array<string> => { |
|
|
|
const weights: { [s: string]: number } = {} |
|
|
|
const ordering: Array<string> = [] |
|
|
|
|
|
|
|
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>): 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 = <A>(xs: Set<A>, ys: Set<A>): Set<A> => { |
|
|
|
const intersection: Set<A> = new Set() |
|
|
|
|
|
|
|
xs.forEach(x => { |
|
|
|
if (ys.has(x)) { |
|
|
|
intersection.add(x) |
|
|
|
} |
|
|
|
}) |
|
|
|
|
|
|
|
return intersection |
|
|
|
} |