@graphty/algorithms
Version:
Graph algorithms library for browser environments implemented in TypeScript
196 lines • 5.51 kB
JavaScript
import { Graph } from "../core/graph.js";
/**
* Convert Graph class to Map representation
* Used by community detection and flow algorithms
*/
export function graphToMap(graph) {
const map = new Map();
// Initialize all nodes
for (const node of graph.nodes()) {
map.set(String(node.id), new Map());
}
// Add edges with weights
for (const edge of graph.edges()) {
const source = String(edge.source);
const target = String(edge.target);
const weight = edge.weight ?? 1;
const sourceMap = map.get(source);
if (sourceMap) {
sourceMap.set(target, weight);
}
// For undirected graphs, add reverse edge
if (!graph.isDirected) {
const targetMap = map.get(target);
if (targetMap) {
targetMap.set(source, weight);
}
}
}
return map;
}
/**
* Convert Map representation to Graph class
*/
export function mapToGraph(map, isDirected = true) {
const graph = new Graph({ directed: isDirected });
// Add all nodes first
for (const node of map.keys()) {
graph.addNode(node);
}
// Add edges
const processedEdges = new Set();
for (const [source, neighbors] of map) {
for (const [target, weight] of neighbors) {
const edgeKey = isDirected ? `${source}->${target}` : [source, target].sort().join("-");
// Skip if we've already processed this edge (for undirected graphs)
if (!isDirected && processedEdges.has(edgeKey)) {
continue;
}
graph.addEdge(source, target, weight);
processedEdges.add(edgeKey);
}
}
return graph;
}
/**
* Adapter for using Graph algorithms with Map representation
* Implements a subset of Graph interface methods needed by algorithms
*/
export class GraphAdapter {
constructor(map, isDirected = true) {
this.map = map;
this.isDirected = isDirected;
}
/**
* Get all nodes
*/
nodes() {
return Array.from(this.map.keys()).map((id) => ({ id }));
}
/**
* Get node count
*/
get nodeCount() {
return this.map.size;
}
/**
* Check if node exists
*/
hasNode(nodeId) {
return this.map.has(String(nodeId));
}
/**
* Get neighbors of a node
*/
neighbors(nodeId) {
const neighbors = this.map.get(String(nodeId));
if (!neighbors) {
return [];
}
return Array.from(neighbors.keys());
}
/**
* Get edge between two nodes
*/
getEdge(source, target) {
const sourceNeighbors = this.map.get(String(source));
if (!sourceNeighbors) {
return null;
}
const weight = sourceNeighbors.get(String(target));
if (weight === undefined) {
return null;
}
return { source, target, weight };
}
/**
* Check if edge exists
*/
hasEdge(source, target) {
const sourceNeighbors = this.map.get(String(source));
if (!sourceNeighbors) {
return false;
}
return sourceNeighbors.has(String(target));
}
/**
* Get all edges
*/
edges() {
const edges = [];
const processedEdges = new Set();
for (const [source, neighbors] of this.map) {
for (const [target, weight] of neighbors) {
const edgeKey = this.isDirected ? `${source}->${target}` : [source, target].sort().join("-");
// Skip if we've already processed this edge (for undirected graphs)
if (!this.isDirected && processedEdges.has(edgeKey)) {
continue;
}
edges.push({ source, target, weight });
processedEdges.add(edgeKey);
}
}
return edges;
}
/**
* Get edge count
*/
get edgeCount() {
if (this.isDirected) {
let count = 0;
for (const neighbors of this.map.values()) {
count += neighbors.size;
}
return count;
}
// For undirected graphs, count each edge once
let count = 0;
const counted = new Set();
for (const [source, neighbors] of this.map) {
for (const target of neighbors.keys()) {
const edgeKey = [source, target].sort().join("-");
if (!counted.has(edgeKey)) {
counted.add(edgeKey);
count++;
}
}
}
return count;
}
/**
* Get node degree
*/
degree(nodeId) {
const neighbors = this.map.get(String(nodeId));
return neighbors ? neighbors.size : 0;
}
/**
* Get in-degree (for directed graphs)
*/
inDegree(nodeId) {
if (!this.isDirected) {
return this.degree(nodeId);
}
let count = 0;
const targetId = String(nodeId);
for (const neighbors of this.map.values()) {
if (neighbors.has(targetId)) {
count++;
}
}
return count;
}
/**
* Get out-degree (for directed graphs)
*/
outDegree(nodeId) {
return this.degree(nodeId);
}
/**
* Get underlying map representation
*/
getMap() {
return this.map;
}
}
//# sourceMappingURL=graph-converters.js.map