UNPKG

@graphty/algorithms

Version:

Graph algorithms library for browser environments implemented in TypeScript

148 lines 4.91 kB
import { Graph } from "../core/graph.js"; /** * Reconstructs a path from source to target using a predecessor map * @param target - The target node * @param predecessor - Map of node to its predecessor in the path * @returns Array of nodes from source to target, or empty array if no path exists */ export function reconstructPath(target, predecessor) { const path = []; let current = target; // Build path backwards from target to source while (current !== null) { path.unshift(current); const pred = predecessor.get(current); if (pred === undefined) { // No path exists return []; } current = pred; } return path; } /** * Find common neighbors between two nodes * @param graph - The graph * @param source - First node * @param target - Second node * @param directed - Whether to consider edge direction * @returns Set of common neighbor node IDs */ export function getCommonNeighbors(graph, source, target, directed = false) { const sourceNeighbors = new Set(directed ? graph.outNeighbors(source) : graph.neighbors(source)); const targetNeighbors = new Set(directed ? graph.outNeighbors(target) : graph.neighbors(target)); const common = new Set(); for (const neighbor of sourceNeighbors) { if (targetNeighbors.has(neighbor)) { common.add(neighbor); } } return common; } /** * Find common neighbors for link prediction in directed graphs * This finds nodes that form a path from source to target (source->X->target) * @param graph - The graph * @param source - First node * @param target - Second node * @returns Set of intermediate node IDs */ export function getIntermediateNodes(graph, source, target) { const sourceOutNeighbors = new Set(graph.outNeighbors(source)); const targetInNeighbors = new Set(graph.inNeighbors(target)); const common = new Set(); for (const neighbor of sourceOutNeighbors) { if (targetInNeighbors.has(neighbor)) { common.add(neighbor); } } return common; } /** * Generate a consistent edge key for undirected graphs * @param source - Source node * @param target - Target node * @param isDirected - Whether the graph is directed * @returns A consistent edge identifier */ export function getEdgeKey(source, target, isDirected) { if (isDirected) { return `${String(source)}->${String(target)}`; } // For undirected graphs, sort to ensure consistency const [first, second] = source < target ? [source, target] : [target, source]; return `${String(first)}-${String(second)}`; } /** * Calculate total edge weight in a graph * @param graph - The graph * @returns Total weight of all edges */ export function getTotalEdgeWeight(graph) { let totalWeight = 0; for (const edge of graph.edges()) { totalWeight += edge.weight ?? 1; } return graph.isDirected ? totalWeight : totalWeight / 2; } /** * Get node degree with optional mode for directed graphs * @param graph - The graph * @param nodeId - The node ID * @param mode - Degree mode for directed graphs * @returns Node degree */ export function getNodeDegree(graph, nodeId, mode = "total") { if (!graph.isDirected || mode === "total") { return graph.degree(nodeId); } if (mode === "in") { return graph.inDegree(nodeId); } return graph.outDegree(nodeId); } /** * Convert directed graph to undirected * @param graph - The directed graph * @returns A new undirected graph */ export function makeUndirected(graph) { if (!graph.isDirected) { return graph; } const undirected = new Graph({ directed: false }); // Add all nodes for (const node of graph.nodes()) { undirected.addNode(node.id, node.data); } // Add edges (will automatically be made bidirectional) for (const edge of graph.edges()) { // For undirected, we only add each edge once if (!undirected.hasEdge(edge.source, edge.target)) { undirected.addEdge(edge.source, edge.target, edge.weight, edge.data); } } return undirected; } /** * Renumber communities consecutively starting from 0 * @param communities - Map of node to community ID * @returns Map with renumbered community IDs */ export function renumberCommunities(communities) { const uniqueCommunities = new Set(communities.values()); const remapping = new Map(); let newId = 0; for (const community of uniqueCommunities) { remapping.set(community, newId++); } const renumbered = new Map(); for (const [node, community] of communities) { const newCommunity = remapping.get(community); if (newCommunity !== undefined) { renumbered.set(node, newCommunity); } } return renumbered; } //# sourceMappingURL=graph-utilities.js.map