Problem: dfs

Your task is to implement a Depth First Search (DFS) algorithm to determine reachability in a directed graph and verify its functional correctness in Lean using Mathlib. The graph is represented as an adjacency list (Array of Array Nat). You need to implement dfs_check_reachability, which returns true if and only if a path exists from the start node to the target node. There are several verification challenges: (1) Soundness (Path Validity): Proving that if the function returns true, a valid sequence of edges actually exists connecting the start to the target. (2) Completeness (Unreachability): Proving that if the function returns false, no such path exists. This is the hardest part; it requires a strong loop invariant relating the visited set to the stack. You typically need to prove that "any path from the start to an unvisited node must pass through a node currently in the stack." (3) Termination: Proving that the algorithm finishes. Since cycles may exist in the graph, you must prove that the visited set grows (or the count of unvisited nodes decreases) to guarantee termination.


import Mathlib

structure DFSGraph where
  adj : Array (Array Nat)

def DFSGraph.well_formed (g : DFSGraph) : Prop :=
  ∀ u, u < g.adj.size →
    ∀ v, v ∈ g.adj.getD u #[] → v < g.adj.size

def DFSGraph.size (g : DFSGraph) : Nat :=
  g.adj.size

def DFSGraph.has_edge (g : DFSGraph) (u v : Nat) : Prop :=
  u < g.adj.size ∧
  v ∈ g.adj.getD u #[]

def DFSGraph.is_path (g : DFSGraph) (p : List Nat) : Prop :=
  p.length > 0 ∧
  ∀ i, i + 1 < p.length →
    g.has_edge (p.getD i 0) (p.getD (i + 1) 0)

def DFSGraph.reachable (g : DFSGraph) (start target : Nat) : Prop :=
  ∃ p, g.is_path p ∧ p.head? = some start ∧ p.getLast? = some target

-- Precondition definitions
@[reducible, simp]
def dfs_check_reachability_precond (graph : DFSGraph) (start target : Nat) : Prop :=
  -- !benchmark @start precond
  graph.well_formed ∧ start < graph.size ∧ target < graph.size
  -- !benchmark @end precond

-- !benchmark @start auxcode
-- !benchmark @end auxcode

-- Main function definition
def dfs_check_reachability (graph : DFSGraph) (start target : Nat)
    (h_precond : dfs_check_reachability_precond graph start target) : Bool :=
  -- !benchmark @start code
  sorry
  -- !benchmark @end code

-- Postcondition definitions
@[reducible, simp]
def dfs_check_reachability_postcond (graph : DFSGraph) (start target : Nat) (result : Bool)
    (_ : dfs_check_reachability_precond graph start target) : Prop :=
  -- !benchmark @start postcond
  result = graph.reachable start target
  -- !benchmark @end postcond

-- !benchmark @start lemma
-- !benchmark @end lemma

-- Proof content
theorem dfs_check_reachability_postcond_satisfied (graph : DFSGraph) (start target : Nat)
    (h_precond : dfs_check_reachability_precond graph start target) :
    dfs_check_reachability_postcond graph start target
      (dfs_check_reachability graph start target h_precond) h_precond := by
  -- !benchmark @start proof
  sorry
  -- !benchmark @end proof