Problem: Dijkstra Algorithm Functions Implementation

The problem requires implementing an enhanced Dijkstra's algorithm (with A* framework) and its core components—initializing distances/visited states, finding unvisited minimum-distance nodes, relaxing neighbors—while handling diverse input types, ensuring numerical stability, validating inputs, and computing shortest paths from a start node.

Background: ### Industry Background for Enhanced Dijkstra's Algorithm Implementation
Dijkstra's algorithm is a foundational shortest-path algorithm widely adopted across industries including **transportation routing (GPS navigation)**, **telecommunications network optimization**, **supply chain logistics**, **robotics path planning**, and **graph neural network (GNN) preprocessing**. This implementation extends the classic algorithm with production-grade enhancements and mathematical rigor critical for real-world deployment:

1. **Numerical Stability & Tie-Breaking Mathematics**:
   - Initialization (`init_dijkstra`) uses a large infinity value (1e18) with tiny random offsets (0-1e-9) for non-start nodes and ±1e-9 perturbations for start nodes. This avoids floating-point equality issues that cause non-deterministic path selection.
   - Tie-breaking in `get_min_dist_node` uses hash-based perturbation: for nodes with identical minimum distances, a small epsilon (1e-12) multiplied by the node's hash value is added to distances, ensuring deterministic selection without altering relative order.

2. **Multi-Format Graph & Vectorized Computation**:
   - The algorithm supports sparse graphs (Python dictionaries for large, connected networks) and dense graphs (NumPy arrays/PyTorch tensors for vectorized, high-performance computations). For array/tensor inputs, it uses boolean masking to filter unvisited nodes efficiently, leveraging vectorization to reduce runtime complexity—critical for ML/AI industries processing large graph datasets.

3. **Stochastic Edge Weight Processing**:
   - `relax_neighbors` handles diverse weight types with mathematical normalization:
     - **NumPy arrays**: Uses Frobenius norm (`linalg.norm(weight, 'fro')`) to compute distance magnitudes, adding Gaussian noise scaled to 1e-6 of the norm for numerical stability.
     - **Complex numbers**: Compares distances using absolute values, with noise added to both real and imaginary components.
     - **Statistical distributions**: `dijkstra_algorithm` integrates distributional weights via their `mean()` method, enabling stochastic path optimization for systems like telecommunications (link reliability) and supply chains (uncertain delivery times).

4. **A* Heuristic Framework**:
   - The full algorithm implements the A* search formula \( f(n) = g(n) + h(n) \), where \( g(n) \) is the current shortest distance to node \( n \), and \( h(n) \) is a heuristic estimate of the distance to the goal. The default heuristic uses Euclidean distance (fallback to 0 for pure Dijkstra), a common choice in autonomous vehicles and game development to reduce search time by prioritizing goal-directed paths.

5. **High-Precision Arithmetic**:
   - `dijkstra_algorithm` uses Python's `Decimal` type with 28-digit precision to avoid floating-point accumulation errors, essential for long-path calculations in logistics and financial modeling where small errors can lead to significant cost discrepancies.

6. **Production-Grade Robustness**:
   - Strict input validation ensures graph structure integrity, node presence, and type compatibility. This includes checks for missing start nodes, invalid adjacency list formats, and incompatible weight types—critical for safety-critical systems like robotics and healthcare logistics where algorithm failures have direct consequences.

7. **Reproducibility & Determinism**:
   - Controlled randomness via seedable generators ensures reproducible results, a requirement in scientific computing and simulation industries where algorithm behavior must be validated and replicated consistently.

This implementation balances mathematical rigor, performance, and flexibility, making it suitable for both research and production environments across diverse industrial applications.

Input/Output: The problem receives a graph (an adjacency list as a dictionary where each key is a hashable node, each value is a dictionary mapping neighboring hashable nodes to edge weights—numeric values or distributions with a `mean()` method) and a start_node (a hashable node present in the graph). It generates a dictionary where each key is a node from the graph and each value is a float representing the shortest path distance from the start_node; unreachable nodes have a value of `float('inf')`. The processing flow: The algorithm initializes distance values (0 for the start_node, infinity for others with small randomness) and visited status via `init_dijkstra`, iteratively retrieves the unvisited node with the minimum distance using `get_min_dist_node` (supporting dict, numpy.ndarray, or torch.Tensor inputs), relaxes the node’s neighbors (updating distances with Gaussian noise for numerical stability) using `relax_neighbors`, and uses a priority heap for efficient node selection. It validates input structures (e.g., graph is a dict of dicts, start_node exists) and edge weight types. The algorithm supports A* search with a heuristic function (falling back to Dijkstra) and uses Decimal for precision. Each input node’s output distance corresponds to the shortest path length from the start_node, with the start_node having a distance of 0.0.

Required dependencies:
from typing import Iterable, Hashable, Dict, Tuple, Union, Optional, Any
import random
import sys
import heapq
from decimal import Decimal, getcontext
import numpy as np
from numpy import linalg, isinf, isnan
import torch

Sub-steps:
step_number: 1
step_description_prompt: Please write Python code for a function named init_dijkstra. It initializes distances and visited status for Dijkstra's algorithm. Takes nodes (iterable of hashables) and start_node (single/iterable hashable). Start nodes get ~0 distance with small randomness; others get large INF plus tiny random. Visited all set to False. Validate nodes are non-empty and start nodes exist in nodes.
function_header: def init_dijkstra(nodes, start_node):
test_cases: for nodes, start, exp_dist, exp_vis in [
    (['A', 'B'], 'A', {'A': 0.0, 'B': 1e18}, {'A': False, 'B': False}),  # Updated: B uses 1e18 instead of inf
    (['X'], 'X', {'X': 0.0}, {'X': False}),
    ([1, 2, 3], 2, {1: 1e18, 2: 0.0, 3: 1e18}, {1: False, 2: False, 3: False})  # Updated: use 1e18 instead of inf
]:
    dist, vis = init_dijkstra(nodes, start)
    # Compare with tolerance for floating point values
    assert vis == exp_vis, f"vis mismatch: actual={vis}, expected={exp_vis}"
    assert set(dist.keys()) == set(exp_dist.keys()), f"dist keys mismatch: actual={dist.keys()}, expected={exp_dist.keys()}"
    for key in dist.keys():
        exp_val = exp_dist.get(key)
        if exp_val is None:
            continue
        actual_val = dist[key]
        # Handle infinity and large values
        if exp_val == float('inf') or (isinstance(exp_val, (int, float)) and exp_val >= 1e17):
            assert actual_val >= 1e17 or actual_val == float('inf'), f"dist[{key}] should be large: actual={actual_val}"
        else:
            assert abs(actual_val - exp_val) < 1e-6, f"dist[{key}] mismatch: actual={actual_val}, expected={exp_val}"

step_number: 2
step_description_prompt: Please write a Python function named get_min_dist_node. It finds the unvisited node with the minimum distance, supporting dict, numpy.ndarray, torch.Tensor inputs. It validates input types/shapes, filters unvisited finite distances, uses perturbation for tie-breaking, and returns the node/index or None if no valid node exists.
function_header: def get_min_dist_node(distances, visited):
test_cases: test_get_min = [
    ({'A': 5, 'B': 2}, {'A': False, 'B': False}, 'B'),           
    ({'A': 5, 'B': 2}, {'A': False, 'B': True}, 'A'),            
    ({'A': float('inf')}, {'A': False}, None)                    
]
for dists, vis, expected in test_get_min:
    actual = get_min_dist_node(dists, vis)
    # Check that result is valid (either matches expected or is a valid node)
    if expected is None:
        assert actual is None, f"Expected None but got {actual}"
    else:
        assert actual in dists, f"Result {actual} must be a valid node in distances"
        # Get unvisited nodes and their distances
        unvisited_dists = {node: dist for node, dist in dists.items() if not vis[node]}
        if unvisited_dists:
            min_dist = min(unvisited_dists.values())
            # The function should always return a node with the minimum distance
            # If multiple nodes have the same minimum distance, hash-based tie-breaking is used
            nodes_with_min_dist = [node for node, dist in unvisited_dists.items() if dist == min_dist]
            assert actual in nodes_with_min_dist, \
                f"Result {actual} (dist={dists[actual]}) should have minimum distance {min_dist} among unvisited nodes {unvisited_dists}"
            # If expected is specified and there's only one node with min distance, it should match
            if len(nodes_with_min_dist) == 1:
                assert actual == expected, f"Expected {expected} but got {actual}"

step_number: 3
step_description_prompt: Please write a Python function named relax_neighbors. It relaxes neighbors of node u: adds small Gaussian noise to edge weights from u to neighbors (handling ndarray, complex, int/float), computes new neighbor distance as u's distance plus perturbed weight, updates if new is smaller (norm for arrays, abs otherwise). Include input validation for graph, distances, node presence. Return updated distances.
function_header: def relax_neighbors(u, graph, distances):
test_cases: test_relax = [
    ('A', {'A': {'B': 10}}, {'A': 0, 'B': float('inf')}, {'A': 0, 'B': 10}), 
    ('A', {'A': {'B': 10}}, {'A': 5, 'B': 12}, {'A': 5, 'B': 12}),           
    ('A', {'A': {}}, {'A': 0, 'B': 5}, {'A': 0, 'B': 5})  # Fixed: empty neighbors dict instead of empty graph
]
for u, graph, dists, expected in test_relax:
    try:
        actual = relax_neighbors(u, graph, dists)
        # Round values to 4 decimals for comparison
        if isinstance(actual, dict) and isinstance(expected, dict):
            assert set(actual.keys()) == set(expected.keys()), f"Keys mismatch: actual={actual.keys()}, expected={expected.keys()}"
            for k in actual.keys():
                # Handle different types
                if isinstance(actual[k], dict) or isinstance(expected[k], dict):
                    # If value is dict, compare directly
                    assert actual[k] == expected[k], f"Dict value mismatch for key '{k}': actual={actual[k]}, expected={expected[k]}"
                elif isinstance(actual[k], (int, float)) and isinstance(expected[k], (int, float)):
                    actual_val = round(float(actual[k]), 4)
                    exp_val = round(float(expected[k]), 4)
                    # Handle infinity
                    if exp_val == float('inf') or exp_val >= 1e17:
                        assert actual_val >= 1e17 or actual_val == float('inf'), f"Value for key '{k}' should be large: actual={actual_val}"
                    else:
                        assert actual_val == exp_val, f"Value mismatch for key '{k}': actual={actual_val}, expected={exp_val}"
                elif isinstance(actual[k], (int, float)) or isinstance(expected[k], (int, float)):
                    # One is numeric, one is not - convert numeric to float for comparison
                    if isinstance(actual[k], (int, float)):
                        actual_val = round(float(actual[k]), 4)
                        exp_val = expected[k]
                    else:
                        actual_val = actual[k]
                        exp_val = round(float(expected[k]), 4) if isinstance(expected[k], (int, float)) else expected[k]
                    assert actual_val == exp_val, f"Value mismatch for key '{k}': actual={actual_val}, expected={exp_val}"
                else:
                    # For other types, compare directly
                    assert actual[k] == expected[k], f"Value mismatch for key '{k}': actual={actual[k]}, expected={expected[k]}"
        else:
            assert actual == expected, f"Result mismatch: actual={actual}, expected={expected}"
    except (KeyError, TypeError) as e:
        # If function raises error, check if it's expected
        # For empty graph case, function may raise error - skip silently
        if not graph or (isinstance(graph, dict) and u not in graph):
            pass  # Skip test for invalid graph/node combination
        else:
            raise

step_number: 4
step_description_prompt: Please write a Python function named dijkstra_algorithm. This function implements an enhanced Dijkstra's algorithm (with A* framework) using a priority heap. It validates graph structure, handles numeric/distribution edge weights, computes shortest paths from a start node, supports heuristic functions (Euclidean fallback to Dijkstra), and returns distances as floats.
function_header: def dijkstra_algorithm(graph, start_node):
test_cases: test_dijkstra = [
    ({'A': {'C': 10}, 'B': {'C': 3}}, 'A', {'A': 0, 'B': float('inf'), 'C': 10}),  # Fixed: removed duplicate 'A' key, kept last value
    ({'A': {'B': 1, 'C': 4}, 'B': {'C': 2}}, 'A', {'A': 0, 'B': 1, 'C': 3}),         
    ({'A': {'B': 2}, 'C': {'D': 1}}, 'A', {'A': 0, 'B': 2, 'C': float('inf'), 'D': float('inf')})
]
for graph, start, expected in test_dijkstra:
    res = dijkstra_algorithm(graph, start)

    for node, dist in expected.items():
        assert res[node] == dist

General solution:

General tests: