pub fn astar<G, H>(
graph: &G,
start: NodeId,
goal: NodeId,
h: H,
) -> Result<Option<(Vec<NodeId>, f64)>, GraphError>Expand description
Finds the shortest path from start to goal using the A* search
algorithm with a caller-supplied heuristic function.
A* extends Dijkstra by adding a heuristic h(node) that estimates the
remaining cost to goal. The priority of a node is g(node) + h(node)
where g is the known shortest distance from start. When the heuristic
is admissible (never overestimates the true cost), A* is guaranteed to
find the optimal path.
§Parameters
graph— any graph withf64weights.start— source node.goal— target node.h— heuristic closure:h(node) -> f64. Must satisfyh(node) ≤ true_distance(node, goal). Pass|_| 0.0to degrade to Dijkstra.
§Returns
Some((path, total_cost)) where path[0] == start and
path.last() == &goal, or None if no path exists.
§Errors
Returns GraphError::NodeNotFound if start or goal is not in the
graph.
§Complexity
O(E log V) with a good heuristic; degrades to O((V+E) log V) with h=0.
§Examples
use graph_core::{AdjacencyList, Graph, NodeId};
use graph_shortest_path::astar;
// Simple grid: four nodes in a line.
// 0 --1-- 1 --1-- 2 --1-- 3
let mut g: AdjacencyList<u32> = AdjacencyList::directed();
let n: Vec<_> = (0u32..4).map(|i| g.add_node(i)).collect();
for i in 0..3 {
g.add_edge(n[i], n[i + 1], 1.0).unwrap();
}
// Heuristic: remaining index distance (admissible for unit-weight grid).
let goal_idx = 3usize;
let (path, cost) = astar(&g, n[0], n[3], |id| {
(goal_idx as f64) - (id.index() as f64)
})
.unwrap()
.unwrap();
assert_eq!(cost, 3.0);
assert_eq!(path, n);