|
|
- import { intersect } from "./set"
-
- export type Graph<V> = {
- numVertices: number,
- numEdges: number,
- 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> = { numVertices: 0, numEdges: 0, vertices: {}, edges: {} }
-
- const addVertex = (name: string, v: V) => {
- if (typeof g.vertices[name] !== "undefined") {
- return
- }
-
- g.vertices[name] = v
- g.edges[name] = new Set()
- g.numVertices++
- }
-
- 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)
- g.numEdges++
- }
-
- 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 edgeConnects = <V>(g: Graph<V>, v1: string, v2: string): boolean => g.edges[v1].has(v2)
-
- export const maxCardinalitySearch = <V>(g: Graph<V>): Array<string> => {
- const weights: { [s: string]: number } = {}
- const ordering: Array<string> = []
-
- const W = vertices(g)
- const numVertices = W.size
-
- for (let i = 0; i < numVertices; ++i) {
- const v = findMaxWeight(weights, W)
- ordering.push(v)
-
- intersect(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
- }
-
- export type GraphColoring = {
- numColors: number,
- colors: VertexColoring,
- }
-
- export type VertexColoring = {
- [s: string]: number,
- }
-
- export const colorGreedy = <V>(g: Graph<V>, vertexOrdering: Array<string>): GraphColoring => {
- if (vertexOrdering.length !== g.numVertices) {
- throw new Error("ordering does not cover all vertices")
- }
-
- const coloring: GraphColoring = { numColors: 0, colors: {} }
- const usedColors: { [c: number]: boolean } = {}
-
- vertexOrdering.forEach(v => {
- const ns = neighbors(g, v)
-
- let color = 0
- while (!colorAvailable(color, ns, coloring.colors)) {
- color++
- }
-
- coloring.colors[v] = color
- usedColors[color] = true
- })
-
- coloring.numColors = Object.keys(usedColors).length
- return coloring
- }
-
- const colorAvailable = (color: number, neighbors: Set<string>, colors: VertexColoring): boolean => {
- // TODO: Why can't I just iterate over neighbors directly...?
- for (const nbor of Array.from(neighbors)) {
- if (colors[nbor] === color) {
- return false
- }
- }
-
- return true
- }
|