Shortest paths in directed acyclic graphs
StructureCost of the DAG shortest-path pass#✓fully proved
The cost of the one-pass relaxation in topological order consists of three natural-number counters: the number of vertices taken from the order, the number of edge occurrences checked for relaxation, and the number of distance installations (strict improvements or first finite distances).
Preparation and topological sorting are not counted.
public structure Cost where
/-- Vertices taken from the certified order. -/
vertexVisits : Nat
/-- Original weighted edge occurrences checked for relaxation. -/
edgeRelaxations : Nat
/-- Strict improvements or first finite distances installed. -/
distanceUpdates : Nat
deriving DecidableEq, Repr
Used by 23
DefinitionOne-pass DAG shortest-path relaxation#✓fully proved
Let \(E\) be a list of integer-weighted directed edge occurrences on the vertices \(\{0, \dots, n-1\}\), let \(s\) be a source vertex, and let \(\sigma\) be a topological order of the directed graph obtained from \(E\) by forgetting weights. The relaxation starts from distance estimate \(0\) at \(s\), infinite estimates at every other vertex and no predecessor edges. It then takes the vertices \(u\) of \(\sigma\) in turn and relaxes each occurrence \(e\) in \(E\) from \(u\) to some \(v\) with weight \(c\), in the order of \(E\): if the estimate \(d\) at \(u\) is finite and the estimate at \(v\) is infinite or greater than \(d + c\), it sets the estimate at \(v\) to \(d + c\) and the predecessor of \(v\) to \(e\). The result records \(s\) as its source together with the final estimates and predecessors. Its cost counts one vertex visit per vertex of \(\sigma\), one edge relaxation per occurrence relaxed, and one distance update per estimate set.
The original edge occurrences are retained, so every parallel occurrence is checked. The proof that \(\sigma\) is a topological order is not used by the computation.
public def run {n : Nat} (edges : List (Edge n)) (source : Fin n) (order : List (Fin n))
(_horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
TimeM Cost (Distances n) :=
let buckets := bucketize edges
pass (fun vertex => buckets.get vertex) order (initialState source)
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public def IsTopologicalOrder {α : Type u} [DecidableEq α]
(g : DirectedAdjacency α) (order : List α) : Prop :=
order.Nodup ∧
(∀ v, v ∈ order ↔ v ∈ g.vertices) ∧
∀ u v, g.Edge u v → order.idxOf u < order.idxOf v
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1358
@[expose] public def toDirectedAdjacency {n : Nat}
(edges : List (Edge n)) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency source :=
(edges.filter fun edge => decide (edge.source = source)).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:69
public structure Cost where
/-- Vertices taken from the certified order. -/
vertexVisits : Nat
/-- Original weighted edge occurrences checked for relaxation. -/
edgeRelaxations : Nat
/-- Strict improvements or first finite distances installed. -/
distanceUpdates : Nat
deriving DecidableEq, Repr
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:44
public structure Distances (n : Nat) where
/-- The source used for the run. -/
source : Fin n
/-- Finite shortest weights, with `none` denoting infinity. -/
distance : Vector (Option Int) n
/-- The final predecessor edge for every vertex. -/
predecessor : Vector (Option (Edge n)) n
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:268
@[no_expose] private def bucketize {n : Nat} (edges : List (Edge n)) :
Vector (List (Edge n)) n :=
(edges.foldl (fun acc edge => acc.set edge.source (edge :: acc.get edge.source))
(Vector.replicate n [])).map List.reverse
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:99
@[no_expose] private def pass {n : Nat} (buckets : Fin n → List (Edge n)) :
List (Fin n) → Distances n → TimeM Cost (Distances n)
| [], state => pure state
| vertex :: rest, state => do
TimeM.tick ⟨1, 0, 0⟩
let state ← relaxOutgoing (buckets vertex) state
pass buckets rest state
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:185
@[no_expose] private def initialState {n : Nat} (source : Fin n) : Distances n where
source := source
distance := Vector.ofFn fun vertex => if vertex = source then some 0 else none
predecessor := Vector.replicate n none
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:193
Uses 5 · Used by 19
DefinitionShortest paths in a DAG with a topology check#✓fully proved
Given a list \(E\) of integer-weighted edges on the vertices \(0, \dots, n-1\) and a source \(s\), run Kahn's topological sort on the directed graph obtained from \(E\) by forgetting weights. If it succeeds with order \(\sigma\), start from distance \(0\) at \(s\) and \(\infty\) elsewhere, relax the outgoing edge occurrences of each vertex in the order \(\sigma\), and return the resulting distances and predecessor edges. If it fails after processing the list \(P\) of vertices and leaving the list \(R\), return the error \((P, R)\). Only the relaxation pass is charged in the recorded cost.
Failure preserves the sorter's processed and remaining lists; it does not return a cycle list.
public def dagShortestPaths {n : Nat} (edges : List (Edge n)) (source : Fin n) :
TimeM Cost (Except (List (Fin n) × List (Fin n)) (Distances n)) :=
let buckets := bucketize edges
match TopologicalSort.sort (bucketGraph buckets) with
| .success order => do
let result ← pass (fun vertex => buckets.get vertex) order (initialState source)
pure (.ok result)
| .failure processed remaining => pure (.error (processed, remaining))
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public structure Cost where
/-- Vertices taken from the certified order. -/
vertexVisits : Nat
/-- Original weighted edge occurrences checked for relaxation. -/
edgeRelaxations : Nat
/-- Strict improvements or first finite distances installed. -/
distanceUpdates : Nat
deriving DecidableEq, Repr
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:44
public structure Distances (n : Nat) where
/-- The source used for the run. -/
source : Fin n
/-- Finite shortest weights, with `none` denoting infinity. -/
distance : Vector (Option Int) n
/-- The final predecessor edge for every vertex. -/
predecessor : Vector (Option (Edge n)) n
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:268
@[no_expose] private def bucketize {n : Nat} (edges : List (Edge n)) :
Vector (List (Edge n)) n :=
(edges.foldl (fun acc edge => acc.set edge.source (edge :: acc.get edge.source))
(Vector.replicate n [])).map List.reverse
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:99
public def sort {α : Type u} [DecidableEq α] [Hashable α]
(g : DirectedAdjacency α) : Result α :=
let advance := fun (s : List α × (α → Nat) × Std.Queue α × List α) =>
match s.2.2.1.dequeue? with
| none => s
| some (vertex, queue) =>
let remaining := s.1.erase vertex
let rec dedup (seen : α → Bool) : List α → List α
| [] => []
| target :: neighbors =>
if seen target then dedup seen neighbors
else target :: dedup (Function.update seen target true) neighbors
⋯
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1008
@[no_expose] private def bucketGraph {n : Nat}
(buckets : Vector (List (Edge n)) n) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency vertex := (buckets.get vertex).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:148
@[no_expose] private def pass {n : Nat} (buckets : Fin n → List (Edge n)) :
List (Fin n) → Distances n → TimeM Cost (Distances n)
| [], state => pure state
| vertex :: rest, state => do
TimeM.tick ⟨1, 0, 0⟩
let state ← relaxOutgoing (buckets vertex) state
pass buckets rest state
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:185
@[no_expose] private def initialState {n : Nat} (source : Fin n) : Distances n where
source := source
distance := Vector.ofFn fun vertex => if vertex = source then some 0 else none
predecessor := Vector.replicate n none
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:193
Uses 6 · Used by 7
TheoremThe DAG shortest-path pass is charged one vertex visit per vertex#✓fully proved
Let \(E\) be a list of integer-weighted directed edge occurrences on the vertices \(\{0, \dots, n-1\}\), let \(s\) be a source vertex, and let \(\sigma\) be a topological order of the directed graph obtained from \(E\) by forgetting weights. The one-pass DAG shortest-path relaxation of \(E\) from \(s\) in the order \(\sigma\) is charged exactly \(n\) vertex visits.
public theorem run_vertexVisits {n : Nat} (edges : List (Edge n)) (source : Fin n)
(order : List (Fin n))
(horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
(run edges source order horder).time.vertexVisits = n
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public def IsTopologicalOrder {α : Type u} [DecidableEq α]
(g : DirectedAdjacency α) (order : List α) : Prop :=
order.Nodup ∧
(∀ v, v ∈ order ↔ v ∈ g.vertices) ∧
∀ u v, g.Edge u v → order.idxOf u < order.idxOf v
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1358
@[expose] public def toDirectedAdjacency {n : Nat}
(edges : List (Edge n)) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency source :=
(edges.filter fun edge => decide (edge.source = source)).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:69
public def run {n : Nat} (edges : List (Edge n)) (source : Fin n) (order : List (Fin n))
(_horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
TimeM Cost (Distances n) :=
let buckets := bucketize edges
pass (fun vertex => buckets.get vertex) order (initialState source)
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:200
TheoremEdge relaxation count of the DAG pass#✓fully proved
Let \(E\) be a list of integer-weighted edges on \(n\) vertices, \(s\) a source, and \(\sigma\) a topological order of the directed graph obtained from \(E\) by forgetting weights. In the cost of the one-pass relaxation from \(s\) in the order \(\sigma\), the number of edge relaxations equals the length of \(E\), with identical duplicate edges counted separately.
public theorem run_edgeRelaxations {n : Nat} (edges : List (Edge n)) (source : Fin n)
(order : List (Fin n))
(horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
(run edges source order horder).time.edgeRelaxations = edges.length
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public def IsTopologicalOrder {α : Type u} [DecidableEq α]
(g : DirectedAdjacency α) (order : List α) : Prop :=
order.Nodup ∧
(∀ v, v ∈ order ↔ v ∈ g.vertices) ∧
∀ u v, g.Edge u v → order.idxOf u < order.idxOf v
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1358
@[expose] public def toDirectedAdjacency {n : Nat}
(edges : List (Edge n)) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency source :=
(edges.filter fun edge => decide (edge.source = source)).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:69
public def run {n : Nat} (edges : List (Edge n)) (source : Fin n) (order : List (Fin n))
(_horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
TimeM Cost (Distances n) :=
let buckets := bucketize edges
pass (fun vertex => buckets.get vertex) order (initialState source)
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:200
TheoremDistance updates are bounded by edge relaxations#✓fully proved
Let \(E\) be a list of integer-weighted edges on \(n\) vertices, \(s\) a source, and \(\sigma\) a topological order of the directed graph obtained from \(E\) by forgetting weights. In the cost of the one-pass relaxation from \(s\) in the order \(\sigma\), the number of distance installations is at most the number of edge relaxations.
Only actual strict improvements or first finite estimates install a predecessor.
public theorem run_distanceUpdates_le {n : Nat} (edges : List (Edge n)) (source : Fin n)
(order : List (Fin n))
(horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
(run edges source order horder).time.distanceUpdates ≤
(run edges source order horder).time.edgeRelaxations
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public def IsTopologicalOrder {α : Type u} [DecidableEq α]
(g : DirectedAdjacency α) (order : List α) : Prop :=
order.Nodup ∧
(∀ v, v ∈ order ↔ v ∈ g.vertices) ∧
∀ u v, g.Edge u v → order.idxOf u < order.idxOf v
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1358
@[expose] public def toDirectedAdjacency {n : Nat}
(edges : List (Edge n)) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency source :=
(edges.filter fun edge => decide (edge.source = source)).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:69
public def run {n : Nat} (edges : List (Edge n)) (source : Fin n) (order : List (Fin n))
(_horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
TimeM Cost (Distances n) :=
let buckets := bucketize edges
pass (fun vertex => buckets.get vertex) order (initialState source)
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:200
TheoremFinite DAG distances are path weights#✓fully proved
Let \(E\) be a list of integer-weighted edges on \(n\) vertices, \(s\) a source, and \(\sigma\) a topological order of the directed graph obtained from \(E\) by forgetting weights. If the one-pass relaxation from \(s\) in the order \(\sigma\) gives a vertex \(t\) the finite distance \(d\), then there is a path from \(s\) to \(t\) made of edge occurrences of \(E\) whose edge weights sum to \(d\).
public theorem run_distance_realized {n : Nat} (edges : List (Edge n)) (source : Fin n)
(order : List (Fin n))
(horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order)
(target : Fin n) (value : Int)
(hd : (run edges source order horder).ret.distance.get target = some value) :
∃ path, IsWeightedPath edges source target path ∧ pathWeight path = value
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public def IsTopologicalOrder {α : Type u} [DecidableEq α]
(g : DirectedAdjacency α) (order : List α) : Prop :=
order.Nodup ∧
(∀ v, v ∈ order ↔ v ∈ g.vertices) ∧
∀ u v, g.Edge u v → order.idxOf u < order.idxOf v
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1358
@[expose] public def toDirectedAdjacency {n : Nat}
(edges : List (Edge n)) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency source :=
(edges.filter fun edge => decide (edge.source = source)).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:69
public def run {n : Nat} (edges : List (Edge n)) (source : Fin n) (order : List (Fin n))
(_horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
TimeM Cost (Distances n) :=
let buckets := bucketize edges
pass (fun vertex => buckets.get vertex) order (initialState source)
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:200
@[expose] public def IsWeightedPath {n : Nat} (edges : List (Edge n)) (source target : Fin n)
(path : List (Edge n)) : Prop :=
(∀ edge ∈ path, edge ∈ edges) ∧
path.IsChain (fun left right => left.target = right.source) ∧
match path with
| [] => source = target
| first :: rest =>
first.source = source ∧ (first :: rest).getLast?.map Edge.target = some target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:87
@[expose] public def pathWeight {n : Nat} (path : List (Edge n)) : Int :=
(path.map Edge.weight).sum
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:83
TheoremThe DAG shortest-path pass keeps its source#✓fully proved
Let \(E\) be a list of integer-weighted directed edge occurrences on the vertices \(\{0, \dots, n-1\}\), let \(s\) be a source vertex, and let \(\sigma\) be a topological order of the directed graph obtained from \(E\) by forgetting weights. The result of the one-pass DAG shortest-path relaxation of \(E\) from \(s\) in the order \(\sigma\) records \(s\) as its source.
public theorem run_source {n : Nat} (edges : List (Edge n)) (source : Fin n)
(order : List (Fin n))
(horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
(run edges source order horder).ret.source = source
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public def IsTopologicalOrder {α : Type u} [DecidableEq α]
(g : DirectedAdjacency α) (order : List α) : Prop :=
order.Nodup ∧
(∀ v, v ∈ order ↔ v ∈ g.vertices) ∧
∀ u v, g.Edge u v → order.idxOf u < order.idxOf v
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1358
@[expose] public def toDirectedAdjacency {n : Nat}
(edges : List (Edge n)) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency source :=
(edges.filter fun edge => decide (edge.source = source)).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:69
public def run {n : Nat} (edges : List (Edge n)) (source : Fin n) (order : List (Fin n))
(_horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
TimeM Cost (Distances n) :=
let buckets := bucketize edges
pass (fun vertex => buckets.get vertex) order (initialState source)
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:200
Uses 15 · Used by 2
TheoremThe DAG shortest-path pass gives the source distance zero#✓fully proved
Let \(E\) be a list of integer-weighted directed edge occurrences on the vertices \(\{0, \dots, n-1\}\), let \(s\) be a source vertex, and let \(\sigma\) be a topological order of the directed graph obtained from \(E\) by forgetting weights. The one-pass DAG shortest-path relaxation of \(E\) from \(s\) in the order \(\sigma\) ends with distance estimate \(0\) at \(s\).
This holds even when edges of negative weight enter \(s\).
public theorem run_source_distance {n : Nat} (edges : List (Edge n)) (source : Fin n)
(order : List (Fin n))
(horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
(run edges source order horder).ret.distance.get source = some 0
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public def IsTopologicalOrder {α : Type u} [DecidableEq α]
(g : DirectedAdjacency α) (order : List α) : Prop :=
order.Nodup ∧
(∀ v, v ∈ order ↔ v ∈ g.vertices) ∧
∀ u v, g.Edge u v → order.idxOf u < order.idxOf v
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1358
@[expose] public def toDirectedAdjacency {n : Nat}
(edges : List (Edge n)) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency source :=
(edges.filter fun edge => decide (edge.source = source)).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:69
public def run {n : Nat} (edges : List (Edge n)) (source : Fin n) (order : List (Fin n))
(_horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
TimeM Cost (Distances n) :=
let buckets := bucketize edges
pass (fun vertex => buckets.get vertex) order (initialState source)
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:200
Uses 15 · Used by 4
TheoremThe source has no DAG shortest-path predecessor#✓fully proved
Let \(E\) be a list of integer-weighted directed edge occurrences on the vertices \(\{0, \dots, n-1\}\), let \(s\) be a source vertex, and let \(\sigma\) be a topological order of the directed graph obtained from \(E\) by forgetting weights. The one-pass DAG shortest-path relaxation of \(E\) from \(s\) in the order \(\sigma\) records no predecessor edge for \(s\).
public theorem run_source_predecessor {n : Nat} (edges : List (Edge n)) (source : Fin n)
(order : List (Fin n))
(horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
(run edges source order horder).ret.predecessor.get source = none
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public def IsTopologicalOrder {α : Type u} [DecidableEq α]
(g : DirectedAdjacency α) (order : List α) : Prop :=
order.Nodup ∧
(∀ v, v ∈ order ↔ v ∈ g.vertices) ∧
∀ u v, g.Edge u v → order.idxOf u < order.idxOf v
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1358
@[expose] public def toDirectedAdjacency {n : Nat}
(edges : List (Edge n)) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency source :=
(edges.filter fun edge => decide (edge.source = source)).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:69
public def run {n : Nat} (edges : List (Edge n)) (source : Fin n) (order : List (Fin n))
(_horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
TimeM Cost (Distances n) :=
let buckets := bucketize edges
pass (fun vertex => buckets.get vertex) order (initialState source)
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:200
Uses 15
TheoremFinite DAG distances are at most every path weight#✓fully proved
Let \(E\) be a list of integer-weighted edges on \(n\) vertices, \(s\) a source, and \(\sigma\) a topological order of the directed graph obtained from \(E\) by forgetting weights. If the one-pass relaxation from \(s\) in the order \(\sigma\) gives a vertex \(t\) the finite distance \(d\), then \(d \le w(p)\) for every path \(p\) from \(s\) to \(t\) made of edge occurrences of \(E\), where \(w(p)\) is the sum of the weights of the edges of \(p\).
public theorem run_distance_minimal {n : Nat} (edges : List (Edge n)) (source : Fin n)
(order : List (Fin n))
(horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order)
(target : Fin n) (value : Int)
(hd : (run edges source order horder).ret.distance.get target = some value)
(path : List (Edge n)) (hp : IsWeightedPath edges source target path) :
value ≤ pathWeight path
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public def IsTopologicalOrder {α : Type u} [DecidableEq α]
(g : DirectedAdjacency α) (order : List α) : Prop :=
order.Nodup ∧
(∀ v, v ∈ order ↔ v ∈ g.vertices) ∧
∀ u v, g.Edge u v → order.idxOf u < order.idxOf v
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1358
@[expose] public def toDirectedAdjacency {n : Nat}
(edges : List (Edge n)) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency source :=
(edges.filter fun edge => decide (edge.source = source)).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:69
public def run {n : Nat} (edges : List (Edge n)) (source : Fin n) (order : List (Fin n))
(_horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
TimeM Cost (Distances n) :=
let buckets := bucketize edges
pass (fun vertex => buckets.get vertex) order (initialState source)
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:200
@[expose] public def IsWeightedPath {n : Nat} (edges : List (Edge n)) (source target : Fin n)
(path : List (Edge n)) : Prop :=
(∀ edge ∈ path, edge ∈ edges) ∧
path.IsChain (fun left right => left.target = right.source) ∧
match path with
| [] => source = target
| first :: rest =>
first.source = source ∧ (first :: rest).getLast?.map Edge.target = some target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:87
@[expose] public def pathWeight {n : Nat} (path : List (Edge n)) : Int :=
(path.map Edge.weight).sum
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:83
Uses 17 · Used by 2
TheoremInfinite DAG distances are exactly unreachable vertices#✓fully proved
Let \(E\) be a list of integer-weighted edges on \(n\) vertices, \(s\) a source, and \(\sigma\) a topological order of the directed graph \(G\) obtained from \(E\) by forgetting weights. For every vertex \(t\), the one-pass relaxation from \(s\) in the order \(\sigma\) leaves the distance of \(t\) infinite if and only if \(t\) is not reachable from \(s\) in \(G\).
public theorem run_distance_eq_none_iff {n : Nat} (edges : List (Edge n)) (source : Fin n)
(order : List (Fin n))
(horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order)
(target : Fin n) :
(run edges source order horder).ret.distance.get target = none ↔
¬(toDirectedAdjacency edges).Reachable source target
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public def IsTopologicalOrder {α : Type u} [DecidableEq α]
(g : DirectedAdjacency α) (order : List α) : Prop :=
order.Nodup ∧
(∀ v, v ∈ order ↔ v ∈ g.vertices) ∧
∀ u v, g.Edge u v → order.idxOf u < order.idxOf v
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1358
@[expose] public def toDirectedAdjacency {n : Nat}
(edges : List (Edge n)) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency source :=
(edges.filter fun edge => decide (edge.source = source)).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:69
public def run {n : Nat} (edges : List (Edge n)) (source : Fin n) (order : List (Fin n))
(_horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
TimeM Cost (Distances n) :=
let buckets := bucketize edges
pass (fun vertex => buckets.get vertex) order (initialState source)
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:200
Uses 20 · Used by 1
TheoremPredecessor edges of the DAG shortest-path pass#✓fully proved
Let \(E\) be a list of integer-weighted directed edge occurrences on the vertices \(\{0, \dots, n-1\}\), let \(s\) be a source vertex, and let \(\sigma\) be a topological order of the directed graph obtained from \(E\) by forgetting weights. Suppose the one-pass DAG shortest-path relaxation of \(E\) from \(s\) in the order \(\sigma\) records an edge occurrence \(e\) from \(u\) to \(w\) with weight \(c\) as the predecessor of a vertex \(v\). Then \(e\) occurs in \(E\), \(w = v\), and there is an integer \(d\) such that the final distance estimate at \(u\) is \(d\), the final distance estimate at \(v\) is \(d + c\), and the position of \(u\) in \(\sigma\) is less than the position of \(v\) in \(\sigma\).
public theorem run_predecessor_spec {n : Nat} (edges : List (Edge n)) (source : Fin n)
(order : List (Fin n))
(horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order)
(target : Fin n) (edge : Edge n)
(hp : (run edges source order horder).ret.predecessor.get target = some edge) :
edge ∈ edges ∧ edge.target = target ∧
∃ value, (run edges source order horder).ret.distance.get edge.source = some value ∧
(run edges source order horder).ret.distance.get target = some (value + edge.weight) ∧
order.idxOf edge.source < order.idxOf target
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public def IsTopologicalOrder {α : Type u} [DecidableEq α]
(g : DirectedAdjacency α) (order : List α) : Prop :=
order.Nodup ∧
(∀ v, v ∈ order ↔ v ∈ g.vertices) ∧
∀ u v, g.Edge u v → order.idxOf u < order.idxOf v
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1358
@[expose] public def toDirectedAdjacency {n : Nat}
(edges : List (Edge n)) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency source :=
(edges.filter fun edge => decide (edge.source = source)).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:69
public def run {n : Nat} (edges : List (Edge n)) (source : Fin n) (order : List (Fin n))
(_horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
TimeM Cost (Distances n) :=
let buckets := bucketize edges
pass (fun vertex => buckets.get vertex) order (initialState source)
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:200
Uses 15 · Used by 2
TheoremUnreached vertices have no DAG shortest-path predecessor#✓fully proved
Let \(E\) be a list of integer-weighted directed edge occurrences on the vertices \(\{0, \dots, n-1\}\), let \(s\) be a source vertex, and let \(\sigma\) be a topological order of the directed graph obtained from \(E\) by forgetting weights. If the one-pass DAG shortest-path relaxation of \(E\) from \(s\) in the order \(\sigma\) ends with an infinite distance estimate at a vertex \(v\), then it records no predecessor edge for \(v\).
public theorem run_infinite_predecessor {n : Nat} (edges : List (Edge n)) (source : Fin n)
(order : List (Fin n))
(horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order)
(target : Fin n) (hd : (run edges source order horder).ret.distance.get target = none) :
(run edges source order horder).ret.predecessor.get target = none
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public def IsTopologicalOrder {α : Type u} [DecidableEq α]
(g : DirectedAdjacency α) (order : List α) : Prop :=
order.Nodup ∧
(∀ v, v ∈ order ↔ v ∈ g.vertices) ∧
∀ u v, g.Edge u v → order.idxOf u < order.idxOf v
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1358
@[expose] public def toDirectedAdjacency {n : Nat}
(edges : List (Edge n)) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency source :=
(edges.filter fun edge => decide (edge.source = source)).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:69
public def run {n : Nat} (edges : List (Edge n)) (source : Fin n) (order : List (Fin n))
(_horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
TimeM Cost (Distances n) :=
let buckets := bucketize edges
pass (fun vertex => buckets.get vertex) order (initialState source)
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:200
Uses 15 · Used by 2
TheoremFinite non-source vertices have predecessors#✓fully proved
Let \(E\) be a list of integer-weighted edges on \(n\) vertices, \(s\) a source, and \(\sigma\) a topological order of the directed graph obtained from \(E\) by forgetting weights. If the one-pass relaxation from \(s\) in the order \(\sigma\) gives a vertex \(t \ne s\) a finite distance, then it records a predecessor edge for \(t\).
public theorem run_finite_predecessor {n : Nat} (edges : List (Edge n)) (source : Fin n)
(order : List (Fin n))
(horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order)
(target : Fin n) (value : Int)
(hd : (run edges source order horder).ret.distance.get target = some value)
(hne : target ≠ source) : ∃ edge, (run edges source order horder).ret.predecessor.get target =
some edge
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public def IsTopologicalOrder {α : Type u} [DecidableEq α]
(g : DirectedAdjacency α) (order : List α) : Prop :=
order.Nodup ∧
(∀ v, v ∈ order ↔ v ∈ g.vertices) ∧
∀ u v, g.Edge u v → order.idxOf u < order.idxOf v
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1358
@[expose] public def toDirectedAdjacency {n : Nat}
(edges : List (Edge n)) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency source :=
(edges.filter fun edge => decide (edge.source = source)).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:69
public def run {n : Nat} (edges : List (Edge n)) (source : Fin n) (order : List (Fin n))
(_horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
TimeM Cost (Distances n) :=
let buckets := bucketize edges
pass (fun vertex => buckets.get vertex) order (initialState source)
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:200
Uses 15 · Used by 2
TheoremSuccessful output of DAG shortest paths#✓fully proved
For a list \(E\) of integer-weighted edges on \(n\) vertices, a source \(s\), and a distance record \(D\), the DAG shortest-path algorithm on \(E\) from \(s\) returns \(D\) if and only if there is a topological order \(\sigma\) of the directed graph obtained from \(E\) by forgetting weights such that Kahn's topological sort of that graph succeeds with \(\sigma\) and \(D\) is the result of the one-pass relaxation from \(s\) in the order \(\sigma\).
public theorem dagShortestPaths_eq_ok_iff {n : Nat} (edges : List (Edge n)) (source : Fin n)
(result : Distances n) :
(dagShortestPaths edges source).ret = .ok result ↔
∃ order, ∃ horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order,
TopologicalSort.sort (toDirectedAdjacency edges) = .success order ∧
result = (run edges source order horder).ret
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public structure Distances (n : Nat) where
/-- The source used for the run. -/
source : Fin n
/-- Finite shortest weights, with `none` denoting infinity. -/
distance : Vector (Option Int) n
/-- The final predecessor edge for every vertex. -/
predecessor : Vector (Option (Edge n)) n
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:268
public def dagShortestPaths {n : Nat} (edges : List (Edge n)) (source : Fin n) :
TimeM Cost (Except (List (Fin n) × List (Fin n)) (Distances n)) :=
let buckets := bucketize edges
match TopologicalSort.sort (bucketGraph buckets) with
| .success order => do
let result ← pass (fun vertex => buckets.get vertex) order (initialState source)
pure (.ok result)
| .failure processed remaining => pure (.error (processed, remaining))
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:208
public def IsTopologicalOrder {α : Type u} [DecidableEq α]
(g : DirectedAdjacency α) (order : List α) : Prop :=
order.Nodup ∧
(∀ v, v ∈ order ↔ v ∈ g.vertices) ∧
∀ u v, g.Edge u v → order.idxOf u < order.idxOf v
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1358
@[expose] public def toDirectedAdjacency {n : Nat}
(edges : List (Edge n)) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency source :=
(edges.filter fun edge => decide (edge.source = source)).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:69
public def sort {α : Type u} [DecidableEq α] [Hashable α]
(g : DirectedAdjacency α) : Result α :=
let advance := fun (s : List α × (α → Nat) × Std.Queue α × List α) =>
match s.2.2.1.dequeue? with
| none => s
| some (vertex, queue) =>
let remaining := s.1.erase vertex
let rec dedup (seen : α → Bool) : List α → List α
| [] => []
| target :: neighbors =>
if seen target then dedup seen neighbors
else target :: dedup (Function.update seen target true) neighbors
⋯
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1008
public def run {n : Nat} (edges : List (Edge n)) (source : Fin n) (order : List (Fin n))
(_horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
TimeM Cost (Distances n) :=
let buckets := bucketize edges
pass (fun vertex => buckets.get vertex) order (initialState source)
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:200
Uses 11 · Used by 4
TheoremFailure output of DAG shortest paths#✓fully proved
For a list \(E\) of integer-weighted edges on \(n\) vertices, a source \(s\), and lists \(P\) and \(R\) of vertices, the DAG shortest-path algorithm on \(E\) from \(s\) returns the error \((P, R)\) if and only if Kahn's topological sort of the directed graph obtained from \(E\) by forgetting weights fails after processing \(P\) and leaving \(R\).
public theorem dagShortestPaths_eq_error_iff {n : Nat} (edges : List (Edge n)) (source : Fin n)
(processed remaining : List (Fin n)) :
(dagShortestPaths edges source).ret = .error (processed, remaining) ↔
TopologicalSort.sort (toDirectedAdjacency edges) = .failure processed remaining
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public def dagShortestPaths {n : Nat} (edges : List (Edge n)) (source : Fin n) :
TimeM Cost (Except (List (Fin n) × List (Fin n)) (Distances n)) :=
let buckets := bucketize edges
match TopologicalSort.sort (bucketGraph buckets) with
| .success order => do
let result ← pass (fun vertex => buckets.get vertex) order (initialState source)
pure (.ok result)
| .failure processed remaining => pure (.error (processed, remaining))
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:208
public def sort {α : Type u} [DecidableEq α] [Hashable α]
(g : DirectedAdjacency α) : Result α :=
let advance := fun (s : List α × (α → Nat) × Std.Queue α × List α) =>
match s.2.2.1.dequeue? with
| none => s
| some (vertex, queue) =>
let remaining := s.1.erase vertex
let rec dedup (seen : α → Bool) : List α → List α
| [] => []
| target :: neighbors =>
if seen target then dedup seen neighbors
else target :: dedup (Function.update seen target true) neighbors
⋯
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1008
@[expose] public def toDirectedAdjacency {n : Nat}
(edges : List (Edge n)) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency source :=
(edges.filter fun edge => decide (edge.source = source)).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:69
Uses 8 · Used by 1
TheoremPredecessor extraction fails exactly at infinite distances#✓fully proved
Let \(E\) be a list of integer-weighted directed edges on the vertices \(\{0, \dots, n-1\}\), \(s\) a source vertex, and \(\sigma\) a topological order of the directed graph with an edge \(u \to v\) for each edge of \(E\) from \(u\) to \(v\). After the one-pass relaxation of \(E\) from \(s\) in the order \(\sigma\), for every vertex \(t\), following the predecessor edges back from \(t\) fails to reach \(s\) within \(n\) steps if and only if the computed distance to \(t\) is infinite.
public theorem run_pathTo?_eq_none_iff {n : Nat} (edges : List (Edge n)) (source : Fin n)
(order : List (Fin n))
(horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order)
(target : Fin n) :
(run edges source order horder).ret.pathTo? target = none ↔
(run edges source order horder).ret.distance.get target = none
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public def IsTopologicalOrder {α : Type u} [DecidableEq α]
(g : DirectedAdjacency α) (order : List α) : Prop :=
order.Nodup ∧
(∀ v, v ∈ order ↔ v ∈ g.vertices) ∧
∀ u v, g.Edge u v → order.idxOf u < order.idxOf v
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1358
@[expose] public def toDirectedAdjacency {n : Nat}
(edges : List (Edge n)) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency source :=
(edges.filter fun edge => decide (edge.source = source)).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:69
public def run {n : Nat} (edges : List (Edge n)) (source : Fin n) (order : List (Fin n))
(_horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
TimeM Cost (Distances n) :=
let buckets := bucketize edges
pass (fun vertex => buckets.get vertex) order (initialState source)
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:200
Uses 17 · Used by 1
TheoremPaths extracted after topological relaxation are shortest paths#✓fully proved
Let \(E\) be a list of integer-weighted directed edges on the vertices \(\{0, \dots, n-1\}\), \(s\) a source vertex, and \(\sigma\) a topological order of the directed graph with an edge \(u \to v\) for each edge of \(E\) from \(u\) to \(v\). After the one-pass relaxation of \(E\) from \(s\) in the order \(\sigma\), suppose following the predecessor edges back from a vertex \(t\) reaches \(s\) within \(n\) steps, giving the path \(P\). Then \(P\) is a path from \(s\) to \(t\) in \(E\), the computed distance to \(t\) is finite and equals the weight of \(P\), \(P\) has fewer than \(n\) edges, and every path from \(s\) to \(t\) in \(E\) has weight at least the weight of \(P\). Here a path from \(s\) to \(t\) in \(E\) is a list of edges of \(E\), each starting where the previous one ends, the first starting at \(s\) and the last ending at \(t\) (the empty list when \(t = s\)), and its weight is the sum of its edge weights.
public theorem run_pathTo?_spec {n : Nat} (edges : List (Edge n)) (source : Fin n)
(order : List (Fin n))
(horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order)
(target : Fin n) (path : List (Edge n))
(hpath : (run edges source order horder).ret.pathTo? target = some path) :
IsWeightedPath edges source target path ∧
(run edges source order horder).ret.distance.get target = some (pathWeight path) ∧
path.length < n ∧
∀ other, IsWeightedPath edges source target other → pathWeight path ≤ pathWeight other
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public def IsTopologicalOrder {α : Type u} [DecidableEq α]
(g : DirectedAdjacency α) (order : List α) : Prop :=
order.Nodup ∧
(∀ v, v ∈ order ↔ v ∈ g.vertices) ∧
∀ u v, g.Edge u v → order.idxOf u < order.idxOf v
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1358
@[expose] public def toDirectedAdjacency {n : Nat}
(edges : List (Edge n)) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency source :=
(edges.filter fun edge => decide (edge.source = source)).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:69
public def run {n : Nat} (edges : List (Edge n)) (source : Fin n) (order : List (Fin n))
(_horder : TopologicalSort.IsTopologicalOrder (toDirectedAdjacency edges) order) :
TimeM Cost (Distances n) :=
let buckets := bucketize edges
pass (fun vertex => buckets.get vertex) order (initialState source)
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:200
@[expose] public def IsWeightedPath {n : Nat} (edges : List (Edge n)) (source target : Fin n)
(path : List (Edge n)) : Prop :=
(∀ edge ∈ path, edge ∈ edges) ∧
path.IsChain (fun left right => left.target = right.source) ∧
match path with
| [] => source = target
| first :: rest =>
first.source = source ∧ (first :: rest).getLast?.map Edge.target = some target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:87
@[expose] public def pathWeight {n : Nat} (path : List (Edge n)) : Int :=
(path.map Edge.weight).sum
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:83
Uses 19 · Used by 1
TheoremA failed DAG shortest-path run exhibits a cycle#✓fully proved
Let \(E\) be a list of integer-weighted directed edges on the vertices \(\{0, \dots, n-1\}\) and \(s\) a source vertex. If the DAG shortest-path algorithm on \(E\) from \(s\) fails, reporting the processed vertices and the list \(R\) of remaining vertices of its topological sort, then the directed graph with an edge \(u \to v\) for each edge of \(E\) from \(u\) to \(v\) contains a nonempty directed cycle without repeated vertices whose vertices all lie in \(R\).
public theorem dagShortestPaths_failure_cycle {n : Nat} (edges : List (Edge n)) (source : Fin n)
(processed remaining : List (Fin n))
(hf : (dagShortestPaths edges source).ret = .error (processed, remaining)) :
∃ cycle, TopologicalSort.DirectedCycleIn (toDirectedAdjacency edges) remaining cycle
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public def dagShortestPaths {n : Nat} (edges : List (Edge n)) (source : Fin n) :
TimeM Cost (Except (List (Fin n) × List (Fin n)) (Distances n)) :=
let buckets := bucketize edges
match TopologicalSort.sort (bucketGraph buckets) with
| .success order => do
let result ← pass (fun vertex => buckets.get vertex) order (initialState source)
pure (.ok result)
| .failure processed remaining => pure (.error (processed, remaining))
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:208
public def DirectedCycleIn {α : Type u}
(g : DirectedAdjacency α) (remaining cycle : List α) : Prop :=
cycle ≠ [] ∧
cycle.Nodup ∧
cycle.IsChain g.Edge ∧
(match cycle with
| [] => false
| first :: rest => g.Edge (List.getLast (first :: rest) (by simp)) first) ∧
∀ v ∈ cycle, v ∈ remaining
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1215
@[expose] public def toDirectedAdjacency {n : Nat}
(edges : List (Edge n)) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency source :=
(edges.filter fun edge => decide (edge.source = source)).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:69
TheoremThe DAG shortest-path algorithm succeeds exactly on acyclic graphs#✓fully proved
Let \(E\) be a list of integer-weighted directed edges on the vertices \(\{0, \dots, n-1\}\) and \(s\) a source vertex. The DAG shortest-path algorithm on \(E\) from \(s\) succeeds if and only if the directed graph with an edge \(u \to v\) for each edge of \(E\) from \(u\) to \(v\) has no directed cycle.
This includes disconnected graphs: a cycle unreachable from \(s\) still causes failure.
public theorem dagShortestPaths_returns_iff_acyclic {n : Nat} (edges : List (Edge n))
(source : Fin n) :
(∃ result, (dagShortestPaths edges source).ret = .ok result) ↔
TopologicalSort.IsAcyclic (toDirectedAdjacency edges)
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public def dagShortestPaths {n : Nat} (edges : List (Edge n)) (source : Fin n) :
TimeM Cost (Except (List (Fin n) × List (Fin n)) (Distances n)) :=
let buckets := bucketize edges
match TopologicalSort.sort (bucketGraph buckets) with
| .success order => do
let result ← pass (fun vertex => buckets.get vertex) order (initialState source)
pure (.ok result)
| .failure processed remaining => pure (.error (processed, remaining))
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:208
public def IsAcyclic {α : Type u} (g : DirectedAdjacency α) : Prop :=
¬ ∃ cycle, DirectedCycleIn g g.vertices cycle
CSLibExt/Algorithms/Lean/Graph/TopologicalSort.lean:1349
@[expose] public def toDirectedAdjacency {n : Nat}
(edges : List (Edge n)) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency source :=
(edges.filter fun edge => decide (edge.source = source)).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:69
TheoremDAG shortest-path distances are shortest-path weights#✓fully proved
Let \(E\) be a list of integer-weighted directed edges on the vertices \(\{0, \dots, n-1\}\) and \(s\) a source vertex. Suppose the DAG shortest-path algorithm on \(E\) from \(s\) succeeds and returns a finite distance \(d \in \mathbb{Z}\) for a vertex \(t\). Then some path from \(s\) to \(t\) in \(E\) has weight \(d\), and every path from \(s\) to \(t\) in \(E\) has weight at least \(d\). Here a path from \(s\) to \(t\) in \(E\) is a list of edges of \(E\), each starting where the previous one ends, the first starting at \(s\) and the last ending at \(t\) (the empty list when \(t = s\)), and its weight is the sum of its edge weights.
public theorem dagShortestPaths_distance_spec {n : Nat} (edges : List (Edge n))
(source : Fin n) (result : Distances n)
(hr : (dagShortestPaths edges source).ret = .ok result) (target : Fin n) (value : Int)
(hd : result.distance.get target = some value) :
(∃ path, IsWeightedPath edges source target path ∧ pathWeight path = value) ∧
∀ path, IsWeightedPath edges source target path → value ≤ pathWeight path
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public structure Distances (n : Nat) where
/-- The source used for the run. -/
source : Fin n
/-- Finite shortest weights, with `none` denoting infinity. -/
distance : Vector (Option Int) n
/-- The final predecessor edge for every vertex. -/
predecessor : Vector (Option (Edge n)) n
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:268
public def dagShortestPaths {n : Nat} (edges : List (Edge n)) (source : Fin n) :
TimeM Cost (Except (List (Fin n) × List (Fin n)) (Distances n)) :=
let buckets := bucketize edges
match TopologicalSort.sort (bucketGraph buckets) with
| .success order => do
let result ← pass (fun vertex => buckets.get vertex) order (initialState source)
pure (.ok result)
| .failure processed remaining => pure (.error (processed, remaining))
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:208
@[expose] public def IsWeightedPath {n : Nat} (edges : List (Edge n)) (source target : Fin n)
(path : List (Edge n)) : Prop :=
(∀ edge ∈ path, edge ∈ edges) ∧
path.IsChain (fun left right => left.target = right.source) ∧
match path with
| [] => source = target
| first :: rest =>
first.source = source ∧ (first :: rest).getLast?.map Edge.target = some target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:87
@[expose] public def pathWeight {n : Nat} (path : List (Edge n)) : Int :=
(path.map Edge.weight).sum
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:83
Uses 14
TheoremUnreachable vertices are exactly those at infinite DAG distance#✓fully proved
Let \(E\) be a list of integer-weighted directed edges on the vertices \(\{0, \dots, n-1\}\) and \(s\) a source vertex. If the DAG shortest-path algorithm on \(E\) from \(s\) succeeds, then for every vertex \(t\) the returned distance to \(t\) is infinite if and only if \(t\) is not reachable from \(s\) in the directed graph with an edge \(u \to v\) for each edge of \(E\) from \(u\) to \(v\).
public theorem dagShortestPaths_distance_eq_none_iff {n : Nat} (edges : List (Edge n))
(source : Fin n) (result : Distances n)
(hr : (dagShortestPaths edges source).ret = .ok result) (target : Fin n) :
result.distance.get target = none ↔ ¬(toDirectedAdjacency edges).Reachable source target
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public structure Distances (n : Nat) where
/-- The source used for the run. -/
source : Fin n
/-- Finite shortest weights, with `none` denoting infinity. -/
distance : Vector (Option Int) n
/-- The final predecessor edge for every vertex. -/
predecessor : Vector (Option (Edge n)) n
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:268
public def dagShortestPaths {n : Nat} (edges : List (Edge n)) (source : Fin n) :
TimeM Cost (Except (List (Fin n) × List (Fin n)) (Distances n)) :=
let buckets := bucketize edges
match TopologicalSort.sort (bucketGraph buckets) with
| .success order => do
let result ← pass (fun vertex => buckets.get vertex) order (initialState source)
pure (.ok result)
| .failure processed remaining => pure (.error (processed, remaining))
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:208
@[expose] public def toDirectedAdjacency {n : Nat}
(edges : List (Edge n)) : DirectedAdjacency (Fin n) where
vertices := List.finRange n
vertices_nodup := List.nodup_finRange n
vertices_complete := List.mem_finRange
adjacency source :=
(edges.filter fun edge => decide (edge.source = source)).map Edge.target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:69
TheoremExtracted DAG shortest paths are shortest paths#✓fully proved
Let \(E\) be a list of integer-weighted directed edges on the vertices \(\{0, \dots, n-1\}\) and \(s\) a source vertex. Suppose the DAG shortest-path algorithm on \(E\) from \(s\) succeeds, and following its predecessor edges back from a vertex \(t\) reaches \(s\) within \(n\) steps, giving the path \(P\). Then \(P\) is a path from \(s\) to \(t\) in \(E\), the returned distance to \(t\) is finite and equals the weight of \(P\), \(P\) has fewer than \(n\) edges, and every path from \(s\) to \(t\) in \(E\) has weight at least the weight of \(P\). Here a path from \(s\) to \(t\) in \(E\) is a list of edges of \(E\), each starting where the previous one ends, the first starting at \(s\) and the last ending at \(t\) (the empty list when \(t = s\)), and its weight is the sum of its edge weights.
public theorem dagShortestPaths_pathTo?_spec {n : Nat} (edges : List (Edge n))
(source : Fin n) (result : Distances n)
(hr : (dagShortestPaths edges source).ret = .ok result) (target : Fin n)
(path : List (Edge n)) (hp : result.pathTo? target = some path) :
IsWeightedPath edges source target path ∧ result.distance.get target = some (pathWeight path) ∧
path.length < n ∧
∀ other, IsWeightedPath edges source target other → pathWeight path ≤ pathWeight other
public structure Edge (n : Nat) where
/-- The source vertex. -/
source : Fin n
/-- The target vertex. -/
target : Fin n
/-- The integer edge weight. -/
weight : Int
deriving DecidableEq
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:59
public structure Distances (n : Nat) where
/-- The source used for the run. -/
source : Fin n
/-- Finite shortest weights, with `none` denoting infinity. -/
distance : Vector (Option Int) n
/-- The final predecessor edge for every vertex. -/
predecessor : Vector (Option (Edge n)) n
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:268
public def dagShortestPaths {n : Nat} (edges : List (Edge n)) (source : Fin n) :
TimeM Cost (Except (List (Fin n) × List (Fin n)) (Distances n)) :=
let buckets := bucketize edges
match TopologicalSort.sort (bucketGraph buckets) with
| .success order => do
let result ← pass (fun vertex => buckets.get vertex) order (initialState source)
pure (.ok result)
| .failure processed remaining => pure (.error (processed, remaining))
CSLibExt/Algorithms/Lean/Graph/ShortestPath/DAG/Basic.lean:208
@[expose] public def IsWeightedPath {n : Nat} (edges : List (Edge n)) (source target : Fin n)
(path : List (Edge n)) : Prop :=
(∀ edge ∈ path, edge ∈ edges) ∧
path.IsChain (fun left right => left.target = right.source) ∧
match path with
| [] => source = target
| first :: rest =>
first.source = source ∧ (first :: rest).getLast?.map Edge.target = some target
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:87
@[expose] public def pathWeight {n : Nat} (path : List (Edge n)) : Int :=
(path.map Edge.weight).sum
CSLibExt/Algorithms/Lean/Graph/ShortestPath/BellmanFord/Basic.lean:83
Loading dependency explorer…
The dependency explorer needs JavaScript and its graph data.