A "high-level" language for the Gameboy
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

87 lines
2.2 KiB

  1. import { intersect } from "./set"
  2. export type Graph<V> = {
  3. vertices: {
  4. [v: string]: V
  5. },
  6. edges: {
  7. [v: string]: Set<string>
  8. }
  9. }
  10. export type AddVertex<V> = (name: string, v: V) => void
  11. export type AddEdge = (source: string, dest: string) => void
  12. export const createGraph = <V>(cons: (v: AddVertex<V>, e: AddEdge) => void): Graph<V> => {
  13. const g: Graph<V> = { vertices: {}, edges: {} }
  14. const addVertex = (name: string, v: V) => {
  15. g.vertices[name] = v
  16. g.edges[name] = new Set()
  17. }
  18. const addEdge = (source: string, dest: string) => {
  19. if (typeof g.vertices[source] === "undefined") {
  20. throw new Error(`vertex \`${source}' does not exist in graph`)
  21. } else if (typeof g.vertices[dest] === "undefined") {
  22. throw new Error(`vertex \`${dest}' does not exist in graph`)
  23. }
  24. g.edges[source].add(dest)
  25. g.edges[dest].add(source)
  26. }
  27. cons(addVertex, addEdge)
  28. return g
  29. }
  30. export const neighbors = <V>(g: Graph<V>, name: string): Set<string> => {
  31. if (typeof g.vertices[name] === "undefined") {
  32. throw new Error(`vertex \`${name}' does not exist in graph`)
  33. }
  34. return g.edges[name]
  35. }
  36. export const vertices = <V>(g: Graph<V>): Set<string> => new Set(Object.keys(g.vertices))
  37. export const maxCardinalitySearch = <V>(g: Graph<V>): Array<string> => {
  38. const weights: { [s: string]: number } = {}
  39. const ordering: Array<string> = []
  40. const W = vertices(g)
  41. const numVertices = W.size
  42. for (let i = 0; i < numVertices; ++i) {
  43. const v = findMaxWeight(weights, W)
  44. ordering.push(v)
  45. intersect(W, neighbors(g, v)).forEach(x =>
  46. weights[x] = (weights[x] || 0) + 1
  47. )
  48. W.delete(v)
  49. }
  50. return ordering
  51. }
  52. const findMaxWeight = (weights: { [s: string]: number }, W: Set<string>): string => {
  53. let maxV = null
  54. let maxWeight = -Infinity
  55. W.forEach(v => {
  56. const vWeight = weights[v] || 0
  57. if (vWeight > maxWeight) {
  58. maxV = v
  59. maxWeight = vWeight
  60. }
  61. })
  62. if (maxV === null) {
  63. throw new Error(`remaining vertex set is empty`)
  64. }
  65. return maxV
  66. }