A* search algorithm
DefinitionConsistent heuristic#✓fully proved
Let \(G\) be a directed graph on the vertices \(\{0, \dots, n-1\}\) and let \(w\) assign a natural number \(w(u, v)\) to each pair of vertices. A heuristic \(h\) assigning a natural number to each vertex is consistent (monotone) if \(h(u) \le w(u, v) + h(v)\) for every edge \(u \to v\) of \(G\).
def Consistent : Prop := ∀ u v, graph.Edge u v → h u ≤ weight u v + h v
Uses 2 · Used by 7
DefinitionAdmissible heuristic#✓fully proved
For a directed graph \(G\) with natural edge weights \(w\), a heuristic \(h\) with natural values is admissible for a goal vertex \(t\) when it never overestimates the weight of a path to \(t\): \(h(v) \le d\) for every vertex \(v\) and every weight \(d\) of a path in \(G\) from \(v\) to \(t\).
def Admissible (goal : Fin n) : Prop :=
∀ v d, HasPathWeight graph weight v goal d → h v ≤ d
@[expose] public def HasPathWeight (graph : DirectedAdjacency V) (weight : V → V → Nat)
(source target : V) (distance : Nat) : Prop :=
∃ path, path.IsChainFromTo graph.Edge source target ∧
pathWeight weight path = distance
CSLibExt/Algorithms/Lean/Graph/ShortestPath/Dijkstra.lean:40
Uses 2 · Used by 1
DefinitionReduced weight#✓fully proved
Let \(w\) assign a natural number \(w(u, v)\) to each pair of vertices and let \(h\) assign a natural number to each vertex. The reduced weight of the pair \((u, v)\) is the natural number \(w(u, v) + h(v) - h(u)\), computed with truncated subtraction, so it is \(0\) when \(h(u) > w(u, v) + h(v)\).
def reducedWeight (u v : Fin n) : ℕ := weight u v + h v - h u
Used by 10
StructureOutput of A-star search#✓fully proved
An A result on \(n\) vertices consists of a Dijkstra result on \(n\) vertices (the underlying search, with its source, final keys and predecessor pointers) and a vector that assigns to each vertex \(v\) a value \(g(v) \in \mathbb{N} \cup \{\infty\}\). In the output of A from a source \(s\) with a consistent heuristic \(h\), the underlying search runs on the reduced weights, its keys are \(f(v) - h(s)\) where \(f = g + h\), and \(g(v)\) is the least weight of a path from \(s\) to \(v\), with \(\infty\) when there is none.
structure AStarResult (n : ℕ) where
/-- The search on reduced weights: its distances are the keys `f v - h source`. -/
search : DijkstraResult n
/-- The best path weight `g v` from the source. -/
g : Vector (Option ℕ) n
public structure DijkstraResult (n : Nat) where
/-- The starting vertex. -/
source : Fin n
/-- Final distance estimates, with `none` denoting infinity. -/
distance : Vector (Option Nat) n
/-- Shortest-path predecessor pointers. -/
predecessor : Vector (Option (Fin n)) n
CSLibExt/Algorithms/Lean/Graph/ShortestPath/Dijkstra.lean:186
Uses 1 · Used by 9
DefinitionPath recovered from an A-star result#✓fully proved
Given an A* result \(r\) on \(n\) vertices and a vertex \(v\), follow the predecessor pointers of the underlying Dijkstra search backward from \(v\), at most \(n\) times, until the source is reached, and return the visited vertices in order from the source to \(v\). There is no result if a vertex without a predecessor is met before the source, or if the source is not reached within \(n\) steps.
def AStarResult.pathTo? (r : AStarResult n) (v : Fin n) : Option (List (Fin n)) :=
r.search.pathTo? v
structure AStarResult (n : ℕ) where
/-- The search on reduced weights: its distances are the keys `f v - h source`. -/
search : DijkstraResult n
/-- The best path weight `g v` from the source. -/
g : Vector (Option ℕ) n
CSLibExt/Algorithms/Lean/AStar/Consistent.lean:75
Uses 3 · Used by 1
DefinitionA* search#✓fully proved
A* search. Given a directed graph \(G\) on the vertices \(\{0, \dots, n-1\}\) with natural edge weights \(w\), a heuristic \(h\) with natural values and a source vertex \(s\), A* runs Dijkstra's algorithm from \(s\) on the reduced weights \(w(u, v) + h(v) - h(u)\) at Dijkstra's cost, and returns Dijkstra's result (its distances \(g'\) and predecessor pointers) together with the path weights \(g(v) = g'(v) + h(s) - h(v)\), where both subtractions are truncated at \(0\) and \(g(v)\) is infinite when \(g'(v)\) is.
For a consistent heuristic, Dijkstra's distances on the reduced weights are A*'s values \(f = g + h\) shifted by \(h(s)\).
def aStar (source : Fin n) : TimeM DijkstraCost (AStarResult n) := do
let r ← dijkstra graph (reducedWeight weight h) source
pure ⟨r, Vector.ofFn fun v => (r.distance.get v).map (· + h source - h v)⟩
public structure DijkstraCost where
/-- Vertex entries inspected by minimum selection. -/
minScans : Nat
/-- Adjacency entries inspected by relaxation. -/
edgeRelaxations : Nat
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/Dijkstra.lean:136
structure AStarResult (n : ℕ) where
/-- The search on reduced weights: its distances are the keys `f v - h source`. -/
search : DijkstraResult n
/-- The best path weight `g v` from the source. -/
g : Vector (Option ℕ) n
CSLibExt/Algorithms/Lean/AStar/Consistent.lean:75
public def dijkstra {n : Nat} (graph : DirectedAdjacency (Fin n))
(weight : Fin n → Fin n → Nat) (source : Fin n) :
TimeM DijkstraCost (DijkstraResult n) :=
let State := Vector (Option Nat) n × Vector (Option (Fin n)) n ×
Vector Bool n × Vector (Option Nat) n × List (Fin n)
let update {α : Type} (values : Vector α n) (index : Fin n) (value : α) :
Vector α n :=
values.set index.val value index.isLt
let distanceLess (left right : Option Nat) : Bool :=
match left, right with
| some leftDistance, some rightDistance => leftDistance < rightDistance
| some _, none => true
⋯
CSLibExt/Algorithms/Lean/Graph/ShortestPath/Dijkstra.lean:222
def reducedWeight (u v : Fin n) : ℕ := weight u v + h v - h u
CSLibExt/Algorithms/Lean/AStar/Consistent.lean:71
Uses 6 · Used by 7
TheoremReduced weights telescope along paths#✓fully proved
Let \(G\) be a directed graph on the vertices \(\{0, \dots, n-1\}\) with natural edge weights \(w\), let \(h\) be a consistent heuristic with natural values, and let \(w_h(x, y) = w(x, y) + h(y) - h(x)\) be the reduced weight, with the subtraction truncated at \(0\). For all vertices \(u\) and \(v\) and every nonempty list of vertices \(v_0, v_1, \dots, v_k\) with \(v_0 = u\), \(v_k = v\) and an edge of \(G\) from each \(v_i\) to \(v_{i+1}\), the sum of \(w_h(v_i, v_{i+1})\) over \(i < k\), plus \(h(u)\), equals the sum of \(w(v_i, v_{i+1})\) over \(i < k\), plus \(h(v)\).
theorem pathWeight_reducedWeight (hc : Consistent graph weight h) :
∀ (path : List (Fin n)) (u v : Fin n), path.IsChainFromTo graph.Edge u v →
pathWeight (reducedWeight weight h) path + h u = pathWeight weight path + h v
def Consistent : Prop := ∀ u v, graph.Edge u v → h u ≤ weight u v + h v
CSLibExt/Algorithms/Lean/AStar/Consistent.lean:64
@[expose] public def pathWeight (weight : V → V → Nat) : List V → Nat
| [] | [_] => 0
| source :: target :: rest =>
weight source target + pathWeight weight (target :: rest)
CSLibExt/Algorithms/Lean/Graph/ShortestPath/Dijkstra.lean:34
def reducedWeight (u v : Fin n) : ℕ := weight u v + h v - h u
CSLibExt/Algorithms/Lean/AStar/Consistent.lean:71
Uses 5 · Used by 6
TheoremA consistent heuristic that vanishes at the goal is admissible#✓fully proved
A consistent heuristic that vanishes at the goal is admissible.
theorem admissible_of_consistent (hc : Consistent graph weight h) {goal : Fin n}
(hgoal : h goal = 0) : Admissible graph weight h goal
def Consistent : Prop := ∀ u v, graph.Edge u v → h u ≤ weight u v + h v
CSLibExt/Algorithms/Lean/AStar/Consistent.lean:64
def Admissible (goal : Fin n) : Prop :=
∀ v d, HasPathWeight graph weight v goal d → h v ≤ d
CSLibExt/Algorithms/Lean/AStar/Consistent.lean:67
TheoremThe final keys of A*#✓fully proved
The final keys of A*. Let \(G\) be a directed graph on the vertices \(\{0, \dots, n-1\}\) with natural edge weights \(w\), let \(h\) be a consistent heuristic with natural values and let \(s\) be a source vertex. If the path weight \(g(v)\) that A from \(s\) returns for a vertex \(v\) is finite, then the distance \(g'(v)\) that Dijkstra's algorithm from \(s\) computes for \(v\) on the reduced weights \(w(x, y) + h(y) - h(x)\) (subtraction truncated at \(0\)) is finite as well, and \(g(v) + h(v) = g'(v) + h(s)\); that is, the key \(g'(v)\) is A's value \(f(v) = g(v) + h(v)\) shifted down by \(h(s)\).
theorem aStar_key (hc : Consistent graph weight h) {v : Fin n} {g : ℕ}
(hv : (aStar graph weight h source).ret.g.get v = some g) :
∃ g', (dijkstra graph (reducedWeight weight h) source).ret.distance.get v = some g' ∧
g + h v = g' + h source
def Consistent : Prop := ∀ u v, graph.Edge u v → h u ≤ weight u v + h v
CSLibExt/Algorithms/Lean/AStar/Consistent.lean:64
def aStar (source : Fin n) : TimeM DijkstraCost (AStarResult n) := do
let r ← dijkstra graph (reducedWeight weight h) source
pure ⟨r, Vector.ofFn fun v => (r.distance.get v).map (· + h source - h v)⟩
CSLibExt/Algorithms/Lean/AStar/Consistent.lean:87
public def dijkstra {n : Nat} (graph : DirectedAdjacency (Fin n))
(weight : Fin n → Fin n → Nat) (source : Fin n) :
TimeM DijkstraCost (DijkstraResult n) :=
let State := Vector (Option Nat) n × Vector (Option (Fin n)) n ×
Vector Bool n × Vector (Option Nat) n × List (Fin n)
let update {α : Type} (values : Vector α n) (index : Fin n) (value : α) :
Vector α n :=
values.set index.val value index.isLt
let distanceLess (left right : Option Nat) : Bool :=
match left, right with
| some leftDistance, some rightDistance => leftDistance < rightDistance
| some _, none => true
⋯
CSLibExt/Algorithms/Lean/Graph/ShortestPath/Dijkstra.lean:222
def reducedWeight (u v : Fin n) : ℕ := weight u v + h v - h u
CSLibExt/Algorithms/Lean/AStar/Consistent.lean:71
Uses 13
TheoremA*'s finite path weights are realized by paths#✓fully proved
A*'s finite path weights are realized by paths. Let \(G\) be a directed graph on the vertices \(\{0, \dots, n-1\}\) with natural edge weights \(w\), let \(h\) be a consistent heuristic with natural values and let \(s\) be a source vertex. If the path weight \(g(v)\) that A* from \(s\) returns for a vertex \(v\) is finite, then some path in \(G\) from \(s\) to \(v\) has weight exactly \(g(v)\).
theorem aStar_distance_realized (hc : Consistent graph weight h) {v : Fin n} {g : ℕ}
(hv : (aStar graph weight h source).ret.g.get v = some g) :
HasPathWeight graph weight source v g
def Consistent : Prop := ∀ u v, graph.Edge u v → h u ≤ weight u v + h v
CSLibExt/Algorithms/Lean/AStar/Consistent.lean:64
def aStar (source : Fin n) : TimeM DijkstraCost (AStarResult n) := do
let r ← dijkstra graph (reducedWeight weight h) source
pure ⟨r, Vector.ofFn fun v => (r.distance.get v).map (· + h source - h v)⟩
CSLibExt/Algorithms/Lean/AStar/Consistent.lean:87
@[expose] public def HasPathWeight (graph : DirectedAdjacency V) (weight : V → V → Nat)
(source target : V) (distance : Nat) : Prop :=
∃ path, path.IsChainFromTo graph.Edge source target ∧
pathWeight weight path = distance
CSLibExt/Algorithms/Lean/Graph/ShortestPath/Dijkstra.lean:40
Uses 13
TheoremA* with a consistent heuristic is optimal#✓fully proved
A* with a consistent heuristic is optimal. Let \(G\) be a directed graph on the vertices \(\{0, \dots, n-1\}\) with natural edge weights \(w\), let \(h\) be a consistent heuristic with natural values and let \(s\) be a source vertex. If the path weight \(g(v)\) that A* from \(s\) returns for a vertex \(v\) is finite, then \(g(v) \le d\) for every weight \(d\) of a path in \(G\) from \(s\) to \(v\).
theorem aStar_distance_minimal (hc : Consistent graph weight h) {v : Fin n} {g d : ℕ}
(hv : (aStar graph weight h source).ret.g.get v = some g)
(hpath : HasPathWeight graph weight source v d) : g ≤ d
def Consistent : Prop := ∀ u v, graph.Edge u v → h u ≤ weight u v + h v
CSLibExt/Algorithms/Lean/AStar/Consistent.lean:64
def aStar (source : Fin n) : TimeM DijkstraCost (AStarResult n) := do
let r ← dijkstra graph (reducedWeight weight h) source
pure ⟨r, Vector.ofFn fun v => (r.distance.get v).map (· + h source - h v)⟩
CSLibExt/Algorithms/Lean/AStar/Consistent.lean:87
@[expose] public def HasPathWeight (graph : DirectedAdjacency V) (weight : V → V → Nat)
(source target : V) (distance : Nat) : Prop :=
∃ path, path.IsChainFromTo graph.Edge source target ∧
pathWeight weight path = distance
CSLibExt/Algorithms/Lean/Graph/ShortestPath/Dijkstra.lean:40
Uses 13
TheoremA* leaves exactly the unreachable vertices at infinity#✓fully proved
A* leaves exactly the unreachable vertices at infinity. Let \(G\) be a directed graph on the vertices \(\{0, \dots, n-1\}\) with natural edge weights \(w\), let \(h\) be any heuristic with natural values and let \(s\) be a source vertex. The path weight \(g(v)\) that A* from \(s\) returns for a vertex \(v\) is infinite if and only if \(v\) is not reachable from \(s\) in \(G\).
theorem aStar_distance_eq_none_iff (v : Fin n) :
(aStar graph weight h source).ret.g.get v = none ↔
¬graph.Reachable source v
def aStar (source : Fin n) : TimeM DijkstraCost (AStarResult n) := do
let r ← dijkstra graph (reducedWeight weight h) source
pure ⟨r, Vector.ofFn fun v => (r.distance.get v).map (· + h source - h v)⟩
CSLibExt/Algorithms/Lean/AStar/Consistent.lean:87
TheoremA*'s predecessor paths are simple and realize its path weights#✓fully proved
A*'s predecessor paths are simple and realize its path weights. Let \(G\) be a directed graph on the vertices \(\{0, \dots, n-1\}\) with natural edge weights \(w\), let \(h\) be a consistent heuristic with natural values and let \(s\) be a source vertex. If following the predecessor pointers that A from \(s\) returns, back from a vertex \(v\), yields the vertex list \(p\) (listed from \(s\) to \(v\)), then the path weight \(g(v)\) that A returns for \(v\) is finite, \(p\) starts at \(s\) and ends at \(v\), \(G\) has an edge from each vertex of \(p\) to the next one, no vertex occurs twice in \(p\), and the weight of \(p\) (the sum of \(w\) over its consecutive pairs) equals \(g(v)\).
theorem aStar_pathTo?_spec (hc : Consistent graph weight h) (v : Fin n) (path : List (Fin n))
(hpath : (aStar graph weight h source).ret.pathTo? v = some path) :
∃ g, (aStar graph weight h source).ret.g.get v = some g ∧
path.head? = some source ∧ path.getLast? = some v ∧
path.IsChain graph.Edge ∧ path.Nodup ∧ pathWeight weight path = g
def Consistent : Prop := ∀ u v, graph.Edge u v → h u ≤ weight u v + h v
CSLibExt/Algorithms/Lean/AStar/Consistent.lean:64
def aStar (source : Fin n) : TimeM DijkstraCost (AStarResult n) := do
let r ← dijkstra graph (reducedWeight weight h) source
pure ⟨r, Vector.ofFn fun v => (r.distance.get v).map (· + h source - h v)⟩
CSLibExt/Algorithms/Lean/AStar/Consistent.lean:87
@[expose] public def pathWeight (weight : V → V → Nat) : List V → Nat
| [] | [_] => 0
| source :: target :: rest =>
weight source target + pathWeight weight (target :: rest)
CSLibExt/Algorithms/Lean/Graph/ShortestPath/Dijkstra.lean:34
TheoremA*'s predecessor edges are tight#✓fully proved
A*'s predecessor edges are tight. Let \(G\) be a directed graph on the vertices \(\{0, \dots, n-1\}\) with natural edge weights \(w\), let \(h\) be a consistent heuristic with natural values and let \(s\) be a source vertex. If A from \(s\) records \(u\) as the predecessor of a vertex \(v\), then \(G\) has an edge from \(u\) to \(v\), the path weights \(g(u)\) and \(g(v)\) that A returns are both finite, and \(g(v) = g(u) + w(u, v)\).
theorem aStar_predecessor_spec (hc : Consistent graph weight h) (v u : Fin n)
(hpred : (aStar graph weight h source).ret.search.predecessor.get v = some u) :
graph.Edge u v ∧ ∃ gu gv,
(aStar graph weight h source).ret.g.get u = some gu ∧
(aStar graph weight h source).ret.g.get v = some gv ∧ gv = gu + weight u v
def Consistent : Prop := ∀ u v, graph.Edge u v → h u ≤ weight u v + h v
CSLibExt/Algorithms/Lean/AStar/Consistent.lean:64
def aStar (source : Fin n) : TimeM DijkstraCost (AStarResult n) := do
let r ← dijkstra graph (reducedWeight weight h) source
pure ⟨r, Vector.ofFn fun v => (r.distance.get v).map (· + h source - h v)⟩
CSLibExt/Algorithms/Lean/AStar/Consistent.lean:87
TheoremCost of A*#✓fully proved
Cost of A*. Let \(G\) be a directed graph on the vertices \(\{0, \dots, n-1\}\) with natural edge weights \(w\), let \(h\) be any heuristic with natural values and let \(s\) be a source vertex. In Dijkstra's dense cost model, which counts the vertex entries inspected by minimum selection and the adjacency entries inspected by relaxation, A* from \(s\) charges exactly \(n^2 + m\) events in total, where \(m\) is the number of entries in the adjacency lists of \(G\), counting duplicates and self-loops.
theorem aStar_time :
(aStar graph weight h source).time.total = n * n + adjacencyEntryCount graph
def aStar (source : Fin n) : TimeM DijkstraCost (AStarResult n) := do
let r ← dijkstra graph (reducedWeight weight h) source
pure ⟨r, Vector.ofFn fun v => (r.distance.get v).map (· + h source - h v)⟩
CSLibExt/Algorithms/Lean/AStar/Consistent.lean:87
@[expose] public def adjacencyEntryCount (graph : DirectedAdjacency V) : Nat :=
(graph.vertices.map fun vertex => (graph.adjacency vertex).length).sum
CSLibExt/Algorithms/Lean/Graph/ShortestPath/Dijkstra.lean:132
Uses 10
Loading dependency explorer…
The dependency explorer needs JavaScript and its graph data.