UNPKG

@crstrskp/graph

Version:

High-performance TypeScript graph algorithms library optimized for trading bots and arbitrage detection

305 lines 9.13 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ThreadSafeGraphImpl = void 0; const Edge_1 = require("./Edge"); const Vertex_1 = require("./Vertex"); const Path_1 = require("./Path"); const PriorityQueue_1 = require("./PriorityQueue"); class ThreadSafeGraphImpl { constructor() { this.edges = []; this.vertices = []; this.vertexMap = new Map(); this.readWriteLock = new ReadWriteLock(); } async bellmanFord(src) { return this.readWriteLock.withReadLock(async () => { return this.bellmanFordInternal(src); }); } bellmanFordInternal(src) { var vDists = new Map(); this.vertices.forEach((v) => { vDists.set(v, Number.MAX_VALUE); }); vDists.set(src, 0); for (var i = 0; i < this.vertices.length; i++) { for (var j = 0; j < this.edges.length; j++) { var start = this.edges[j].start; var end = this.edges[j].end; var cost = this.edges[j].getCost(); var startCost = vDists.get(start); var newCost = startCost + cost; if (newCost < vDists.get(end)) { vDists.set(end, newCost); end.prev = this.edges[j]; this.edges[j].prev = start; } } } return vDists; } async dijkstra_shortestPath(src, dest) { return this.readWriteLock.withReadLock(async () => { return this.dijkstraInternal(src, dest); }); } dijkstraInternal(src, dest) { var path = new Path_1.Path(); var vDists = new Map(); var visited = new Set(); var pq = new PriorityQueue_1.PriorityQueue(); this.vertices.forEach((v) => { vDists.set(v.label, Number.MAX_VALUE); }); vDists.set(src.label, 0); pq.enqueue(src, 0); while (!pq.isEmpty()) { var currentVertex = pq.dequeue(); if (visited.has(currentVertex.label)) continue; visited.add(currentVertex.label); if (currentVertex === dest) break; var incidentEdges = this.getIncidentStartEdges(currentVertex); incidentEdges.forEach((edge) => { var neighbor = edge.end; var currentCost = vDists.get(currentVertex.label); var newCost = currentCost + edge.getCost(); if (newCost < vDists.get(neighbor.label)) { vDists.set(neighbor.label, newCost); neighbor.prev = edge; edge.prev = currentVertex; pq.enqueue(neighbor, newCost); } }); } if (dest.prev == undefined) { // No path found - return empty path silently return path; } var step = dest; path.addStep(step); while (step != undefined) { step = step.getPrev(); if (step instanceof Vertex_1.Vertex) path.addStep(step); if (step instanceof Edge_1.Edge) path.addStep(step); } path.reverse(); return path; } async insertVertex(o) { return this.readWriteLock.withWriteLock(async () => { return this.insertVertexInternal(o); }); } insertVertexInternal(o) { var v; if (this.isOfTypeVertex(o)) { v = o; } else { v = new Vertex_1.Vertex(o); } this.vertices.push(v); this.vertexMap.set(v.label, v); return v; } async insertEdge(v, w, o) { return this.readWriteLock.withWriteLock(async () => { return this.insertEdgeInternal(v, w, o); }); } insertEdgeInternal(v, w, o) { var e = new Edge_1.Edge(v, w); if (typeof o === 'number') { e.setCost(o); } else { e.setAttribute("payload", o); } this.edges.push(e); return e; } async removeVertex(v) { return this.readWriteLock.withWriteLock(async () => { return this.removeVertexInternal(v); }); } removeVertexInternal(v) { var edges = this.getIncidentEdges(v); for (var i = 0; i < edges.length; i++) { this.removeEdgeInternal(edges[i]); } var i = this.vertices.indexOf(v); if (i !== -1) { this.vertices.splice(i, 1); this.vertexMap.delete(v.label); } } async removeEdge(e) { return this.readWriteLock.withWriteLock(async () => { return this.removeEdgeInternal(e); }); } removeEdgeInternal(e) { for (var i = 0; i < this.edges.length; i++) { if (this.edges[i] === e) { this.edges.splice(i, 1); break; } } } async getVertexByLabel(label) { return this.readWriteLock.withReadLock(async () => { return this.vertexMap.get(label); }); } // Synchronous methods for internal use and backward compatibility getAllVertices() { return [...this.vertices]; } getAllEdges() { return [...this.edges]; } getIncidentEdges(v) { var incidentEdges = []; this.edges.forEach((edge) => { if (edge.end === v || edge.start === v) { if (!incidentEdges.includes(edge)) { incidentEdges.push(edge); } } }); return incidentEdges; } getIncidentStartEdges(v) { var incidentEdges = []; this.edges.forEach((edge) => { if (edge.start === v) { if (!incidentEdges.includes(edge)) { incidentEdges.push(edge); } } }); return incidentEdges; } getIncidentEndEdges(v) { var incidentEdges = []; this.edges.forEach((edge) => { if (edge.end === v) { if (!incidentEdges.includes(edge)) { incidentEdges.push(edge); } } }); return incidentEdges; } getOpposite(v, e) { if (e.start === v) return e.end; else if (e.end === v) return e.start; else return undefined; } getVertices(e) { return [e.start, e.end]; } getAdjacentVertices(v) { var edges = this.getIncidentEdges(v); var neighbors = []; edges.forEach((e) => { var opp = this.getOpposite(v, e); if (opp != undefined && !neighbors.includes(opp)) { neighbors.push(opp); } }); return neighbors; } areAdjacent(v, w) { return this.edges.some(e => (e.start === v && e.end === w) || (e.start === w && e.end === v)); } isOfTypeVertex(input) { return input instanceof Vertex_1.Vertex; } } exports.ThreadSafeGraphImpl = ThreadSafeGraphImpl; class ReadWriteLock { constructor() { this.readers = 0; this.writers = 0; this.readQueue = []; this.writeQueue = []; } async withReadLock(fn) { await this.acquireReadLock(); try { return await fn(); } finally { this.releaseReadLock(); } } async withWriteLock(fn) { await this.acquireWriteLock(); try { return await fn(); } finally { this.releaseWriteLock(); } } async acquireReadLock() { return new Promise((resolve) => { if (this.writers === 0) { this.readers++; resolve(); } else { this.readQueue.push(() => { this.readers++; resolve(); }); } }); } releaseReadLock() { this.readers--; if (this.readers === 0 && this.writeQueue.length > 0) { const nextWriter = this.writeQueue.shift(); nextWriter(); } } async acquireWriteLock() { return new Promise((resolve) => { if (this.readers === 0 && this.writers === 0) { this.writers++; resolve(); } else { this.writeQueue.push(() => { this.writers++; resolve(); }); } }); } releaseWriteLock() { this.writers--; if (this.writeQueue.length > 0) { const nextWriter = this.writeQueue.shift(); nextWriter(); } else { while (this.readQueue.length > 0) { const nextReader = this.readQueue.shift(); nextReader(); } } } } //# sourceMappingURL=ThreadSafeGraphImpl.js.map