@crstrskp/graph
Version:
High-performance TypeScript graph algorithms library optimized for trading bots and arbitrage detection
305 lines • 9.13 kB
JavaScript
"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