( graph: Graph<N, E, T> | MutableGraph<N, E, T>, config: BellmanFordConfig<E> )
| 2878 | * @category algorithms |
| 2879 | */ |
| 2880 | export const bellmanFord = <N, E, T extends Kind = "directed">( |
| 2881 | graph: Graph<N, E, T> | MutableGraph<N, E, T>, |
| 2882 | config: BellmanFordConfig<E> |
| 2883 | ): Option.Option<PathResult<E>> => { |
| 2884 | const { cost, source, target } = config |
| 2885 | // Validate that source and target nodes exist |
| 2886 | if (!graph.nodes.has(source)) { |
| 2887 | throw missingNode(source) |
| 2888 | } |
| 2889 | if (!graph.nodes.has(target)) { |
| 2890 | throw missingNode(target) |
| 2891 | } |
| 2892 | |
| 2893 | // Early return if source equals target |
| 2894 | if (source === target) { |
| 2895 | return Option.some({ |
| 2896 | path: [source], |
| 2897 | distance: 0, |
| 2898 | costs: [] |
| 2899 | }) |
| 2900 | } |
| 2901 | |
| 2902 | // Initialize distances and predecessors |
| 2903 | const distances = new Map<NodeIndex, number>() |
| 2904 | const previous = new Map<NodeIndex, { node: NodeIndex; edgeData: E } | null>() |
| 2905 | // Iterate directly over node keys |
| 2906 | |
| 2907 | for (const node of graph.nodes.keys()) { |
| 2908 | distances.set(node, node === source ? 0 : Infinity) |
| 2909 | previous.set(node, null) |
| 2910 | } |
| 2911 | |
| 2912 | // Collect all edges for relaxation |
| 2913 | const edges: Array<{ source: NodeIndex; target: NodeIndex; weight: number; edgeData: E }> = [] |
| 2914 | for (const [, edgeData] of graph.edges) { |
| 2915 | const weight = cost(edgeData.data) |
| 2916 | edges.push({ |
| 2917 | source: edgeData.source, |
| 2918 | target: edgeData.target, |
| 2919 | weight, |
| 2920 | edgeData: edgeData.data |
| 2921 | }) |
| 2922 | if (graph.type === "undirected" && edgeData.source !== edgeData.target) { |
| 2923 | edges.push({ |
| 2924 | source: edgeData.target, |
| 2925 | target: edgeData.source, |
| 2926 | weight, |
| 2927 | edgeData: edgeData.data |
| 2928 | }) |
| 2929 | } |
| 2930 | } |
| 2931 | |
| 2932 | // Relax edges up to V-1 times |
| 2933 | const nodeCount = graph.nodes.size |
| 2934 | for (let i = 0; i < nodeCount - 1; i++) { |
| 2935 | let hasUpdate = false |
| 2936 | |
| 2937 | for (const edge of edges) { |
nothing calls this directly
no test coverage detected