import {IEdge} from './iedge' import {Queue} from 'queue-typescript' export function mkGraphOnEdges(edges: Array): BasicGraphOnEdges { const n = new BasicGraphOnEdges() n.SetEdges(edges, BasicGraphOnEdges.vertexCount(edges)) return n } export function mkGraphOnEdgesArray(edges: TEdge[]): BasicGraphOnEdges { const n = new BasicGraphOnEdges() n.SetEdges(edges, BasicGraphOnEdges.vertexCount(edges)) return n } export function mkGraphOnEdgesN(edges: TEdge[], numberOfVerts: number) { const n = new BasicGraphOnEdges() n.SetEdges(edges, numberOfVerts) return n } export class BasicGraphOnEdges { edges: TEdge[] nodeCount = 0 inEdges: TEdge[][] outEdges: TEdge[][] selfEdges: TEdge[][]; *incidentEdges(v: number): IterableIterator { for (const e of this.outEdges[v]) yield e for (const e of this.inEdges[v]) yield e } static deleteFromArray(arr: any, obj: any) { const index = arr.indexOf(obj, 0) if (index > -1) { arr.splice(index, 1) } } // the method is not efficient, takes linear time removeEdge(edge: TEdge) { BasicGraphOnEdges.deleteFromArray(this.edges, edge) if (edge.source !== edge.target) { BasicGraphOnEdges.deleteFromArray(this.outEdges[edge.source], edge) BasicGraphOnEdges.deleteFromArray(this.inEdges[edge.target], edge) } else { BasicGraphOnEdges.deleteFromArray(this.selfEdges[edge.source], edge) } } // This method should be static be // finds the maximum of sources and targets, and return it incremented by 1 static vertexCount(edges: Iterable) { let nov = 0 for (const ie of edges) { if (ie.source >= nov) nov = ie.source if (ie.target >= nov) nov = ie.target } return ++nov } // sets edges of the graph SetEdges(valEdges: TEdge[], nov: number) { this.edges = valEdges this.nodeCount = nov const outEdgesCounts = new Array(this.nodeCount).fill(0) const inEdgesCounts = new Array(this.nodeCount).fill(0) const selfEdgesCounts = new Array(this.nodeCount).fill(0) this.outEdges = new Array(this.nodeCount) this.inEdges = new Array(this.nodeCount) this.selfEdges = new Array(this.nodeCount) for (const e of this.edges) { if (e.source !== e.target) { outEdgesCounts[e.source]++ inEdgesCounts[e.target]++ } else { selfEdgesCounts[e.source]++ } } //allocate now for (let i = 0; i < this.nodeCount; i++) { this.outEdges[i] = new Array(outEdgesCounts[i]) outEdgesCounts[i] = 0 //used later for edge insertion this.inEdges[i] = new Array(inEdgesCounts[i]) inEdgesCounts[i] = 0 //used later for edge insertion this.selfEdges[i] = new Array(selfEdgesCounts[i]) selfEdgesCounts[i] = 0 //used later for edge insertion } //set the edges now for (const e of this.edges) { const u = e.source const v = e.target if (u !== v) { this.outEdges[u][outEdgesCounts[u]++] = e this.inEdges[v][inEdgesCounts[v]++] = e } else { this.selfEdges[u][selfEdgesCounts[u]++] = e } } } inEdgesCount(node: number) { return this.inEdges[node].length } outEdgesCount(node: number) { return this.outEdges[node].length } selfEdgesCount(node: number) { return this.selfEdges[node].length } addEdge(e: TEdge) { this.edges.push(e) if (e.source !== e.target) { this.outEdges[e.source].push(e) this.inEdges[e.target].push(e) } else { this.selfEdges[e.source].push(e) } } // We assume that the graph is connected here *nodesOfConnectedGraph(): IterableIterator { if (this.edges.length === 0) return const enqueed = new Set() const q = new Queue() let i = this.edges[0].source BasicGraphOnEdges.enqueue(enqueed, q, i) yield i while (q.length > 0) { i = q.dequeue() for (const e of this.outEdges[i]) { const s = e.target if (!enqueed.has(s)) { BasicGraphOnEdges.enqueue(enqueed, q, s) yield s } } for (const e of this.inEdges[i]) { const s = e.source if (!enqueed.has(s)) { BasicGraphOnEdges.enqueue(enqueed, q, s) yield s } } } } *pred(n: number): IterableIterator { for (const e of this.inEdges[n]) { yield e.source } } *succ(n: number): IterableIterator { for (const e of this.outEdges[n]) { yield e.target } } static enqueue(enqueed: Set, q: Queue, i: number) { q.enqueue(i) enqueed.add(i) } }