UNPKG

@graphty/algorithms

Version:

Graph algorithms library for browser environments implemented in TypeScript

109 lines 4.11 kB
import { bfsDistancesOnly, bfsWeightedDistances } from "../traversal/bfs-variants.js"; /** * Calculate closeness centrality from distances */ function calculateClosenessFromDistances(distances, sourceNode, totalNodes, options) { if (distances.size <= 1) { return 0; // No other nodes reachable } let centrality = 0; if (options.harmonic) { // Harmonic centrality: sum of reciprocals of distances for (const [targetNode, distance] of distances) { if (targetNode !== sourceNode && distance > 0 && distance < Infinity) { centrality += 1 / distance; } } // Normalization for harmonic centrality if (options.normalized && totalNodes > 1) { centrality = centrality / (totalNodes - 1); } } else { // Standard closeness: reciprocal of sum of distances let totalDistance = 0; let reachableNodes = 0; for (const [targetNode, distance] of distances) { if (targetNode !== sourceNode && distance < Infinity) { totalDistance += distance; reachableNodes++; } } if (totalDistance > 0) { centrality = 1 / totalDistance; // Wasserman and Faust normalization for disconnected graphs if (options.normalized && totalNodes > 1) { centrality = centrality * reachableNodes / (totalNodes - 1); } } } return centrality; } /** * Calculate closeness centrality for all nodes in the graph * * Closeness centrality measures how close a node is to all other nodes * in the graph. It is the reciprocal of the sum of the shortest path * distances to all other reachable nodes. * * @param graph - The input graph * @param options - Algorithm options * @returns Centrality scores for each node * * @example * ```typescript * const graph = new Graph(); * graph.addEdge("A", "B"); * graph.addEdge("B", "C"); * * const centrality = closenessCentrality(graph); * // { A: 0.5, B: 1.0, C: 0.5 } * ``` * * Time Complexity: O(V * (V + E)) for unweighted graphs * Space Complexity: O(V) */ export function closenessCentrality(graph, options = {}) { const nodes = Array.from(graph.nodes()).map((node) => node.id); const centrality = {}; for (const sourceNode of nodes) { centrality[String(sourceNode)] = nodeClosenessCentrality(graph, sourceNode, options); } return centrality; } /** * Calculate closeness centrality for a specific node */ export function nodeClosenessCentrality(graph, node, options = {}) { if (!graph.hasNode(node)) { throw new Error(`Node ${String(node)} not found in graph`); } // Use optimized BFS variant for unweighted graphs const distances = bfsDistancesOnly(graph, node, options.cutoff, options.optimized !== undefined ? { optimized: options.optimized } : {}); const totalNodes = graph.nodeCount; return calculateClosenessFromDistances(distances, node, totalNodes, options); } /** * Calculate weighted closeness centrality using Dijkstra's algorithm */ export function weightedClosenessCentrality(graph, options = {}) { const nodes = Array.from(graph.nodes()).map((node) => node.id); const centrality = {}; for (const sourceNode of nodes) { centrality[String(sourceNode)] = nodeWeightedClosenessCentrality(graph, sourceNode, options); } return centrality; } /** * Calculate weighted closeness centrality for a specific node using Dijkstra */ export function nodeWeightedClosenessCentrality(graph, node, options = {}) { if (!graph.hasNode(node)) { throw new Error(`Node ${String(node)} not found in graph`); } // Use optimized weighted BFS variant (simplified Dijkstra) const distances = bfsWeightedDistances(graph, node, options.cutoff, options.optimized !== undefined ? { optimized: options.optimized } : {}); const totalNodes = graph.nodeCount; return calculateClosenessFromDistances(distances, node, totalNodes, options); } //# sourceMappingURL=closeness.js.map