Theory NetCheck

theory NetCheck
imports Network Graph_Impl Reachable_Nodes
theory NetCheck
imports 
  Fofu_Impl_Base
   Network 
  "Graph_Impl"
  "cava/DFS_Framework/Examples/Reachable_Nodes"
begin

  declare [[coercion_delete int]]
  declare [[coercion_delete "real::nat=>real"]]

  type_synonym edge_list = "(node × node × capacity_impl) list"

  definition ln_invar :: "edge_list => bool" where 
    "ln_invar el ≡ 
      distinct (map (λ(u, v, _). (u,v)) el) 
    ∧ (∀(u,v,c)∈set el. c>0) 
    "
  definition ln_α :: "edge_list => capacity_impl graph" where 
    "ln_α el ≡ λ(u,v). 
      if ∃c. (u, v, c) ∈ set el ∧ c ≠ 0 then 
        SOME c. (u, v, c) ∈ set el ∧ c ≠ 0
      else 0"

  definition "ln_rel ≡ br ln_α ln_invar"
  
  lemma ln_equivalence: "(el, c') ∈ ln_rel <-> ln_invar el ∧ c' = ln_α el"
    unfolding ln_rel_def br_def by auto 

  (*export_code ln_invar in SML*)

  definition ln_N :: "(node×node×_) list => nat" where
    "ln_N el ≡ Max ((fst`set el) ∪ ((fst o snd)`set el)) + 1"

  lemma ln_α_imp_in_set: "[|ln_α el (u,v)≠(0)|] ==> (u,v,ln_α el (u,v))∈set el"
    apply (auto simp: ln_α_def split: split_if_asm)
    apply (metis (mono_tags, lifting) someI_ex)
    done

  lemma ln_N_correct: "Graph.V (ln_α el) ⊆ {0..<ln_N el}"  
    apply (clarsimp simp: Graph.V_def Graph.E_def)
    apply (safe dest!: ln_α_imp_in_set)
    apply (fastforce simp: ln_N_def less_Suc_eq_le intro: Max_ge)
    apply (force simp: ln_N_def less_Suc_eq_le intro: Max_ge)
    done



  record pre_network =
    pn_c :: "capacity_impl graph"
    pn_V :: "nat set"
    pn_succ :: "nat => nat list"
    pn_pred :: "nat => nat list"
    pn_adjmap :: "nat => nat list"
    pn_s_node :: bool
    pn_t_node :: bool

  fun read :: "edge_list => nat => nat =>
    pre_network option" where
    "read [] _ _ = Some (|
      pn_c = (λ _. 0), 
      pn_V = {}, 
      pn_succ = (λ _. []),
      pn_pred = (λ _. []),
      pn_adjmap = (λ _. []), 
      pn_s_node = False, 
      pn_t_node = False
    |)),"
  | "read ((u, v, c) # es) s t = ((case (read es s t) of 
      Some x =>
        (if (pn_c x) (u, v) = 0 ∧ (pn_c x) (v, u) = 0 ∧ c > 0 then
          (if u = v ∨ v = s ∨ u = t then
            None
          else
            Some (x(| 
              pn_c := (pn_c x) ((u, v) := c),
              pn_V := insert u (insert v (pn_V x)),
              pn_succ := (pn_succ x) (u := v # ((pn_succ x) u)),
              pn_pred := (pn_pred x) (v := u # ((pn_pred x) v)),
              pn_adjmap := ((pn_adjmap x) (u := v # (pn_adjmap x) u)) (v := u # (pn_adjmap x) v),
              pn_s_node := pn_s_node x ∨ u = s,
              pn_t_node := pn_t_node x ∨ v = t
            |)),))
        else
          None)
    | None => None))"
      
  lemma read_correct1: "read es s t = Some (|pn_c = c, pn_V = V, pn_succ = succ, 
    pn_pred = pred , pn_adjmap = adjmap, pn_s_node = s_n, pn_t_node = t_n|)), ==> 
    (es, c) ∈ ln_rel ∧ Graph.V c = V ∧ finite V ∧ 
    (s_n --> s ∈ V) ∧ (t_n --> t ∈ V) ∧ (¬s_n --> s ∉ V) ∧ (¬t_n --> t ∉ V) ∧
    (∀u v. c (u,v) ≥ 0) ∧
    (∀u. c(u, u) = 0) ∧ (∀u. c (u, s) = 0) ∧ (∀u. c (t, u) = 0) ∧
    (∀u v. c (u, v) ≠ 0 --> c (v, u) = 0) ∧ 
    (∀u. set (succ u) = Graph.E c``{u} ∧ distinct (succ u)) ∧ 
    (∀u. set (pred u) = (Graph.E c)¯``{u} ∧ distinct (pred u)) ∧ 
    (∀u. set (adjmap u) = Graph.E c``{u} ∪ (Graph.E c)¯``{u} ∧ distinct (adjmap u))"
    proof (induction es arbitrary: c V succ pred adjmap s_n t_n)
      case Nil
        thus ?case unfolding Graph.V_def Graph.E_def ln_rel_def br_def ln_α_def ln_invar_def by auto
    next
      case (Cons e es)
        obtain u1 v1 c1 where obt1: "e = (u1, v1, c1)" by (meson prod_cases3)
        obtain x where obt2: "read es s t = Some x"
          using Cons.prems obt1 by (auto split: option.splits)
        have fct0: "(pn_c x) (u1, v1) = 0 ∧ (pn_c x) (v1, u1) = 0 ∧ c1 > 0"
          using Cons.prems obt1 obt2 by (auto split: option.splits if_splits)
        have fct1: "c1 > 0 ∧ u1 ≠ v1 ∧ v1 ≠ s ∧ u1 ≠ t"
          using Cons.prems obt1 obt2 by (auto split: option.splits if_splits)
        
        obtain c' V' sc' ps' pd' s_n' t_n' where obt3: "x = (|pn_c = c', pn_V = V',
          pn_succ = sc', pn_pred = pd',  pn_adjmap = ps', pn_s_node = s_n', pn_t_node = t_n'|))," 
          apply (cases x) by auto
        then have "read es s t = Some (|pn_c = c', pn_V = V', pn_succ = sc', pn_pred = pd',
          pn_adjmap = ps', pn_s_node = s_n', pn_t_node = t_n'|))," using obt2 by blast
        note fct = Cons.IH[OF this]
        have fct2: "s_n = (s_n' ∨ u1 = s)" 
          using fct0 fct1 Cons.prems obt1 obt2 obt3 by simp
        have fct3: "t_n = (t_n' ∨ v1 = t)"
          using fct0 fct1 Cons.prems obt1 obt2 obt3 by simp
        have fct4: "c = c' ((u1, v1) := c1)"
          using fct0 fct1 Cons.prems obt1 obt2 obt3 by simp
        have fct5: "V = V' ∪ {u1, v1}" 
          using fct0 fct1 Cons.prems obt1 obt2 obt3 by simp
        have fct6: "succ = sc' (u1 := v1 # sc' u1)" 
          using fct0 fct1 Cons.prems obt1 obt2 obt3 by simp
        have fct7: "pred = pd' (v1 := u1 # pd' v1)"
          using fct0 fct1 Cons.prems obt1 obt2 obt3 by simp
        have fct8: "adjmap = (ps' (u1 := v1 # ps' u1)) (v1 := u1 # ps' v1)"
          using fct0 fct1 Cons.prems obt1 obt2 obt3 by simp
        
          
        {
          have "(es, c') ∈ ln_rel" using fct by blast
          then have "ln_invar es" and "c' = ln_α es" unfolding ln_rel_def br_def by auto
          
          have "ln_invar (e # es)"
            proof (rule ccontr)
              assume "¬ ?thesis"
              have f1: "∀(u, v, c) ∈ set (e # es). c>0" using `ln_invar es` fct0 obt1
                unfolding ln_invar_def by auto
              have f2: "distinct (map (λ(u, v, _). (u,v)) es)" using `ln_invar es`
                unfolding ln_invar_def by auto
              
              have "∃c1'. (u1, v1, c1') ∈ (set es) ∧ c1' ≠ 0"
                proof (rule ccontr)
                  assume "¬ ?thesis"
                  then have "∀c1'. (u1, v1, c1') ∉ (set es) ∨ c1' = 0" by blast
                  then have "distinct (map (λ(u, v, _). (u,v)) (e # es))" using obt1 f2 f1 by auto
                  then have "ln_invar (e # es)" unfolding ln_invar_def using f1 by simp
                  thus "False" using `¬ ln_invar (e # es)` by blast
                qed
              then obtain c1' where "(u1, v1, c1') ∈ (set es) ∧ c1' ≠ 0" by blast
              then have "c' (u1, v1) = (SOME c. (u1, v1, c) ∈ set es ∧ c ≠ 0)"
                using `c' = ln_α es` unfolding ln_α_def by auto
              then have "c' (u1, v1) ≠ 0" using `(u1, v1, c1') ∈ (set es) ∧ c1' ≠ 0` f1
                by (metis (mono_tags, lifting) tfl_some)
              thus "False" using fct0 obt3 by simp
            qed
          moreover {
            {
              fix a
              have f1: "distinct (map (λ(u, v, _). (u,v)) (e # es))"
                and f2: "∀u v. (u, v, 0) ∉ set (e # es)"
                using `ln_invar (e # es)` unfolding ln_invar_def by auto
              have "c a = ln_α (e # es) a"
                proof (cases "a = (u1, v1)")
                  case True
                    have "c a = c1" using fct4 True by simp
                    moreover {
                      have "(ln_α (e # es)) a = (SOME c. (u1, v1, c) ∈ set (e # es) ∧ c ≠ 0)"
                        (is "?L = ?R") unfolding ln_α_def using obt1 fct0 True by auto
                      moreover have "?R = c1"
                        proof (rule ccontr)
                          assume "¬ ?thesis"
                          then obtain c1' where "(u1, v1, c1') ∈ set (e # es) 
                            ∧ c1' ≠ 0 ∧ c1' ≠ c1" using fct0 obt1 by auto
                          then have "¬distinct (map (λ(u, v, _). (u,v)) (e # es))" 
                            using obt1 by (metis (mono_tags, lifting) Pair_inject 
                              distinct_map_eq list.set_intros(1) split_conv) 
                          thus "False" using f1 by blast
                        qed
                      ultimately have "?L = c1" by blast
                    }
                    ultimately show ?thesis by simp
                next
                  case False
                    have f1: "∀u1' v1' c1'. u1' ≠ u1 ∨ v1' ≠ v1 --> ((u1', v1', c1') ∈ set (e # es)
                      <-> (u1', v1', c1') ∈ set es)" using obt1 by auto
                    obtain u1' v1' where "a = (u1', v1')" apply (cases a) by auto
                    {
                      have "(ln_α (e # es)) (u1', v1') = (ln_α es) (u1', v1')"
                        proof (cases "∃ c1'. (u1', v1', c1') ∈ set (e # es) ∧ c1' ≠ 0")
                          case True
                            thus ?thesis unfolding ln_α_def 
                              using f1 False True `a = (u1', v1')` by auto
                        next
                          case False
                            thus ?thesis unfolding ln_α_def by auto
                        qed
                      then have "(ln_α (e # es)) a = (ln_α es) a" using `a = (u1', v1')` by simp
                    }
                    moreover have "c a = c' a" using False fct4 by simp
                    moreover have "c' a = ln_α es a" using `c' = ln_α es` by simp
                    ultimately show ?thesis by simp
                qed
            }
            then have "c = ln_α (e # es)" by auto
          }
          ultimately have "(e # es, c) ∈ ln_rel" unfolding ln_rel_def br_def by simp
        }
        moreover {
          have "Graph.V c = Graph.V c' ∪ {u1, v1}" unfolding Graph.V_def Graph.E_def
            using fct0 fct4 by auto
          moreover have "Graph.V c' = V'" using fct by blast
          ultimately have "Graph.V c = V" using fct5 by auto
        }
        moreover {
          have "finite V'" using fct by blast
          then have "finite V" using fct5 by auto
        }
        moreover {
          assume "s_n"
          then have "s_n' ∨ u1 = s" using fct2 by blast
          then have "s ∈ V"
            proof
              assume "s_n'"
                thus ?thesis using fct fct5 by auto
            next
              assume "u1 = s"
                thus ?thesis using fct5 by simp
            qed
        }
        moreover {
          assume "t_n"
          then have "t_n' ∨ v1 = t" using fct3 by blast
          then have "t ∈ V"
            proof
              assume "t_n'"
                thus ?thesis using fct fct5 by auto
            next
              assume "v1 = t"
                thus ?thesis using fct5 by simp
            qed
        }
        moreover {
          assume "¬s_n"
          then have "¬s_n' ∧ u1 ≠ s" using fct2 by blast
          then have "s ∉ V" using fct fct5 fct1  by auto
        }
        moreover {
          assume "¬t_n"
          then have "¬t_n' ∧ v1 ≠ t" using fct3 by blast
          then have "t ∉ V" using fct fct5 fct1  by auto
        }
        moreover have "∀u v. (c (u, v) ≥ 0)" using fct fct4 fct1 fct0 by auto
        moreover have "∀u. c (u, u) = 0" using fct fct4 fct1 fct0 by auto
        moreover have "∀u. c (u, s) = 0" using fct fct4 fct1 fct0 by auto
        moreover have "∀u. c (t, u) = 0" using fct fct4 fct1 fct0 by auto
        moreover {
          fix a b
          assume "c (a, b) ≠ 0"
          then have "a ≠ b" using `∀u. c (u, u) = 0` by auto
          have "c (b, a) = 0"
            proof (cases "(a, b) = (u1, v1)")
              case True
                then have "c (b, a) = c' (v1, u1)" using fct4 `a ≠ b` by auto 
                moreover have "c' (v1, u1) = 0" using fct0 obt3 by auto
                ultimately show ?thesis by simp
            next
              case False
                thus ?thesis
                  proof (cases "(b, a) = (u1, v1)")
                    case True
                      then have "c (a, b) = c' (v1, u1)" using fct4 `a ≠ b` by auto
                      moreover have "c' (v1, u1) = 0" using fct0 obt3 by auto
                      ultimately show ?thesis using `c (a, b) ≠ 0` by simp
                  next
                    case False
                      then have "c (b, a) = c' (b, a)" using fct4 by auto
                      moreover have "c (a, b) = c' (a, b)" 
                        using False `(a, b) ≠ (u1, v1)` fct4 by auto
                      ultimately show ?thesis using fct `c (a, b) ≠ 0` by auto 
                  qed
            qed
        } note n_fct = this
        moreover {
          {
            fix a
            assume "a ≠ u1"
            then have "succ a = sc' a" using fct6 by simp
            moreover have "set (sc' a) = Graph.E c' `` {a} ∧ distinct (sc' a)"
              using fct by blast
            ultimately have "set (succ a) = Graph.E c``{a} ∧ distinct (succ a)"
              unfolding Graph.E_def using fct4 `a ≠ u1` by auto 
          }
          moreover {
            fix a
            assume "a = u1"
            have "set (succ a) = Graph.E c``{a} ∧ distinct (succ a)"
              proof (cases "c' (u1, v1) = 0")
                case True
                  have fct: "set (sc' a) = Graph.E c' `` {a} ∧ distinct (sc' a)"
                    using fct by blast
                  
                  have "succ a = v1 # sc' a" using `a = u1` fct6 True by simp
                  moreover have "Graph.E c = Graph.E c' ∪ {(u1, v1)}" 
                    unfolding Graph.E_def using fct4 fct0 by auto
                  moreover have "v1 ∉ set (sc' a)"
                    proof (rule ccontr)
                      assume "¬ ?thesis"
                      then have "c' (a, v1) ≠ 0" using fct unfolding Graph.E_def by auto
                      thus "False" using True `a = u1` by simp
                    qed
                  ultimately show ?thesis using `a = u1` fct by auto
              next
                case False
                  thus ?thesis using fct0 obt3 by auto
              qed
        }
        ultimately have "∀u. set (succ u) = Graph.E c `` {u} ∧ distinct (succ u)" by metis
      }
        moreover {
          {
            fix a
            assume "a ≠ v1"
            then have "pred a = pd' a" using fct7 by simp
            moreover have "set (pd' a) = (Graph.E c')¯ `` {a} ∧ distinct (pd' a)"
              using fct by blast
            ultimately have "set (pred a) = (Graph.E c)¯``{a} ∧ distinct (pred a)"
              unfolding Graph.E_def using fct4 `a ≠ v1` by auto 
          }
          moreover {
            fix a
            assume "a = v1"
            have "set (pred a) = (Graph.E c)¯``{a} ∧ distinct (pred a)"
              proof (cases "c' (u1, v1) = 0")
                case True
                  have fct: "set (pd' a) = (Graph.E c')¯ `` {a} ∧ distinct (pd' a)"
                    using fct by blast
                  
                  have "pred a = u1 # pd' a" using `a = v1` fct7 True by simp
                  moreover have "Graph.E c = Graph.E c' ∪ {(u1, v1)}" 
                    unfolding Graph.E_def using fct4 fct0 by auto
                  moreover have "u1 ∉ set (pd' a)"
                    proof (rule ccontr)
                      assume "¬ ?thesis"
                      then have "c' (u1, a) ≠ 0" using fct unfolding Graph.E_def by auto
                      thus "False" using True `a = v1` by simp
                    qed
                  ultimately show ?thesis using `a = v1` fct by auto
              next
                case False
                  thus ?thesis using fct0 obt3 by auto
              qed
        }
        ultimately have "∀u. set (pred u) = (Graph.E c)¯`` {u} ∧ distinct (pred u)" by metis
      }
      moreover {
        {
          fix a
          assume "a ≠ u1 ∧ a ≠ v1"
          then have "adjmap a = ps' a" using fct8 by simp
            moreover have "set (ps' a) = 
              Graph.E c'``{a} ∪ (Graph.E c')¯``{a} ∧ distinct (ps' a)" using fct by blast
            ultimately have "set (adjmap a) = Graph.E c``{a} ∪ (Graph.E c)¯``{a} ∧ 
              distinct (adjmap a)" unfolding Graph.E_def using fct4 `a ≠ u1 ∧ a ≠ v1` by auto
        }
        moreover {
          fix a
          assume "a = u1 ∨ a = v1"
          then have "set (adjmap a) = Graph.E c``{a} ∪ (Graph.E c)¯``{a} ∧ distinct (adjmap a)"
            proof
              assume "a = u1"
              show ?thesis
                proof (cases "c' (u1, v1) = 0 ∧ c' (v1, u1) = 0")
                  case True
                    have fct: "set (ps' a) = Graph.E c' `` {a} ∪ (Graph.E c')¯ `` {a} ∧ 
                      distinct (ps' a)" using fct by blast
                    
                    have "adjmap a = v1 # ps' a" using `a = u1` fct8 True by simp
                    moreover have "Graph.E c = Graph.E c' ∪ {(u1, v1)}" 
                      unfolding Graph.E_def using fct4 fct0 by auto
                    moreover have "v1 ∉ set (ps' a)"
                      proof (rule ccontr)
                        assume "¬ ?thesis"
                        then have "c' (a, v1) ≠ 0 ∨ c' (v1, a) ≠ 0"
                          using fct unfolding Graph.E_def by auto
                        thus "False" using True `a = u1` by simp
                      qed
                    ultimately show ?thesis using `a = u1` fct by auto
                next
                  case False
                    thus ?thesis using fct0 obt3 by auto 
                qed
            next
              assume "a = v1"
              show ?thesis
                proof (cases "c' (u1, v1) = 0 ∧ c' (v1, u1) = 0")
                  case True
                    have fct: "set (ps' a) = Graph.E c' `` {a} ∪ (Graph.E c')¯ `` {a} ∧ 
                      distinct (ps' a)" using fct by blast
                    
                    have "adjmap a = u1 # ps' a" using `a = v1` fct8 True by simp
                    moreover have "Graph.E c = Graph.E c' ∪ {(u1, v1)}" 
                      unfolding Graph.E_def using fct4 fct0 by auto
                    moreover have "u1 ∉ set (ps' a)"
                      proof (rule ccontr)
                        assume "¬ ?thesis"
                        then have "c' (u1, a) ≠ 0 ∨ c' (a, u1) ≠ 0"
                          using fct unfolding Graph.E_def by auto
                        thus "False" using True `a = v1` by simp
                      qed
                    ultimately show ?thesis using `a = v1` fct by auto
                next
                  case False
                    thus ?thesis using fct0 obt3 by auto
                qed
            qed
        }
        ultimately have "∀u. set (adjmap u) = Graph.E c``{u} ∪ (Graph.E c)¯``{u} ∧
          distinct (adjmap u)" by metis
      }
      ultimately show ?case by simp  
    qed
    
  lemma read_correct2: "read el s t = None ==> ¬ln_invar el 
    ∨ (∃u v c. (u,v,c) ∈ set el ∧ ¬(c > 0))
    ∨ (∃u c. (u, u, c) ∈ set el ∧ c ≠ 0) ∨ 
    (∃u c. (u, s, c) ∈ set el ∧ c ≠ 0) ∨ (∃u c. (t, u, c) ∈ set el ∧ c ≠ 0) ∨
    (∃u v c1 c2. (u, v, c1) ∈ set el ∧ (v, u, c2) ∈ set el ∧ c1 ≠ 0 ∧ c2 ≠ 0)"
    proof (induction el)
      case Nil
        thus ?case by auto
    next
      case (Cons e el)
        thus ?case
          proof (cases "read el s t = None")
            case True
              note Cons.IH[OF this]
              thus ?thesis
                proof
                  assume "¬ln_invar el"
                  then have "¬distinct (map (λ(u, v, _). (u,v)) (e # el)) ∨ 
                    (∃(u, v, c) ∈ set (e # el). ¬(c>0))" unfolding ln_invar_def by fastforce
                  thus ?thesis unfolding ln_invar_def by fastforce
                next
                  assume "(∃u v c. (u, v, c) ∈ set (el) ∧ ¬(c > 0)) 
                  ∨ (∃u c. (u, u, c) ∈ set el ∧ c ≠ 0) ∨ 
                    (∃u c. (u, s, c) ∈ set el ∧ c ≠ 0) ∨ (∃u c. (t, u, c) ∈ set el ∧ c ≠ 0) ∨
                    (∃u v c1 c2. (u, v, c1) ∈ set el ∧ (v, u, c2) ∈ set el ∧ c1 ≠ 0 ∧ c2 ≠ 0)" 
                  
                  moreover {
                    assume "(∃u v c. (u, v, c) ∈ set el ∧ ¬(c > 0))"
                    then have "(∃u v c. (u, v, c) ∈ set (e # el) ∧ ¬(c > 0))" by auto
                  }
                  moreover {
                    assume "(∃u c. (u, u, c) ∈ set el ∧ c ≠ 0)"
                    then have "(∃u c. (u, u, c) ∈ set (e # el) ∧ c ≠ 0)" by auto
                  }
                  moreover {
                    assume "(∃u c. (u, s, c) ∈ set el ∧ c ≠ 0)"
                    then have "(∃u c. (u, s, c) ∈ set (e # el) ∧ c ≠ 0)" by auto
                  }
                  moreover {
                    assume "(∃u c. (t, u, c) ∈ set el ∧ c ≠ 0)"
                    then have "(∃u c. (t, u, c) ∈ set (e # el) ∧ c ≠ 0)" by auto
                  }
                  moreover {
                    assume "(∃u v c1 c2. (u, v, c1) ∈ set el ∧ (v, u, c2) ∈ set el ∧ c1 ≠ 0 ∧ c2 ≠ 0)"
                    then have "(∃u v c1 c2. (u, v, c1) ∈ set (e # el) ∧
                      (v, u, c2) ∈ set (e # el) ∧ c1 ≠ 0 ∧ c2 ≠ 0)" by auto
                  }
                  ultimately show ?thesis by blast
                qed
          next
            case False
            then obtain x where obt1: "read el s t = Some x" by auto
            obtain u1 v1 c1 where obt2: "e = (u1, v1, c1)" apply (cases e) by auto
            obtain c' V' sc' pd' ps' s_n' t_n' where obt3: "x = (|pn_c = c', pn_V = V', pn_succ = sc',
              pn_pred = pd', pn_adjmap = ps', pn_s_node = s_n', pn_t_node = t_n'|))," 
              apply (cases x) by auto 
            then have "(el, c') ∈ ln_rel" using obt1 read_correct1[of el s t] by simp
            then have "c' = ln_α el" unfolding ln_rel_def br_def by simp
            

            have "(c' (u1, v1) ≠ 0 ∨ c' (v1, u1) ≠ 0 ∨ c1 ≤ 0) ∨ 
              (c1 > 0 ∧ (u1 = v1 ∨ v1 = s ∨ u1 = t))"
              using obt1 obt2 obt3 False Cons.prems 
                by (auto split:option.splits if_splits)
            moreover {
              assume "c1 ≤ 0"
              then have "¬ ln_invar (e # el)" unfolding ln_invar_def using obt2 by auto
            }
            moreover {
              assume "c1 > 0 ∧ u1 = v1"
              then have "(∃u c. (u, u, c) ∈ set (e # el) ∧ c > 0)" using obt2 by auto
            }
            moreover {
              assume "c1 > 0 ∧ v1 = s"
              then have "(∃u c. (u, s, c) ∈ set (e # el) ∧ c > 0)" using obt2 by auto
            }
            moreover {
              assume "c1 > 0 ∧ u1 = t"
              then have "(∃u c. (t, u, c) ∈ set (e # el) ∧ c > 0)" using obt2 by auto
            }
            moreover {
              assume "c' (u1, v1) ≠ 0"
              then have "∃c1'. (u1, v1, c1') ∈ set el" using `c' = ln_α el` unfolding ln_α_def
                by (auto split:if_splits)
              then have "¬ distinct (map (λ(u, v, _). (u, v)) (e # el))" using obt2 by force
              then have "¬ln_invar (e # el)" unfolding ln_invar_def by auto
            }
            moreover {
              assume "c' (v1, u1) ≠ 0"
              then have "∃c1'. (v1, u1, c1') ∈ set el ∧ c1' ≠ 0" 
                using `c' = ln_α el` unfolding ln_α_def by (auto split:if_splits)
              then have "¬ln_invar (e # el) ∨ (∃u v c1 c2.
                (u, v, c1) ∈ set (e # el) ∧ (v, u, c2) ∈ set (e # el) ∧ c1 ≠ 0 ∧ c2 ≠ 0)"
                proof (cases "c1 ≠ 0")
                  case True
                    thus ?thesis using `∃c1'. (v1, u1, c1') ∈ set el  ∧ c1' ≠ 0` obt2 by auto
                next
                  case False
                    then have "¬ln_invar (e # el)" unfolding ln_invar_def using obt2 by auto
                    thus ?thesis by blast
                qed
            }
            ultimately show ?thesis by blast
          qed
    qed
    
  record 'capacity::linordered_idom pre_network' =
    pn_c' :: "(nat*nat,'capacity) ahm"
    pn_V' :: "nat ahs"
    pn_succ' :: "(nat,nat list) ahm"
    pn_pred' :: "(nat,nat list) ahm"
    pn_adjmap' :: "(nat,nat list) ahm"
    pn_s_node' :: bool
    pn_t_node' :: bool


  definition "pnet_α pn' ≡ (|
      pn_c = the_default 0 o (ahm.α (pn_c' pn')), 
      pn_V = ahs_α (pn_V' pn'), 
      pn_succ = the_default [] o (ahm.α (pn_succ' pn')),
      pn_pred = the_default [] o (ahm.α (pn_pred' pn')),
      pn_adjmap = the_default [] o (ahm.α (pn_adjmap' pn')), 
      pn_s_node = pn_s_node' pn', 
      pn_t_node = pn_t_node' pn'
  |)),"  

  definition "pnet_rel ≡ br pnet_α (λ_. True)"
  
  definition "ahm_ld a ahm k ≡ the_default a (ahm.lookup k ahm)"
  abbreviation "cap_lookup ≡ ahm_ld 0"
  abbreviation "succ_lookup ≡ ahm_ld []"


  fun read' :: "(nat × nat × 'capacity::linordered_idom) list => nat => nat =>
    'capacity pre_network' option" where
    "read' [] _ _ = Some (|
      pn_c' = ahm.empty (), 
      pn_V' = ahs.empty (), 
      pn_succ' = ahm.empty (),
      pn_pred' = ahm.empty (),
      pn_adjmap' = ahm.empty (), 
      pn_s_node' = False, 
      pn_t_node' = False
    |)),"
  | "read' ((u, v, c) # es) s t = ((case (read' es s t) of 
      Some x =>
        (if cap_lookup (pn_c' x) (u, v) = 0 ∧ cap_lookup (pn_c' x) (v, u) = 0 ∧ c > 0 then
          (if u = v ∨ v = s ∨ u = t then
            None
          else
            Some (x(| 
              pn_c' := ahm.update (u, v) c (pn_c' x),
              pn_V' := ahs.ins u (ahs.ins v (pn_V' x)),
              pn_succ' := ahm.update u (v # (succ_lookup (pn_succ' x) u)) (pn_succ' x),
              pn_pred' := ahm.update v (u # (succ_lookup (pn_pred' x) v)) (pn_pred' x),
              pn_adjmap' := ahm.update u (v # (succ_lookup (pn_adjmap' x) u))
                (ahm.update v (u # (succ_lookup (pn_adjmap' x) v)) (pn_adjmap' x)),
              pn_s_node' := pn_s_node' x ∨ u = s,
              pn_t_node' := pn_t_node' x ∨ v = t
            |)),))
        else
          None)
    | None => None))"

  lemma read'_correct: "read el s t = map_option pnet_α (read' el s t)"
    apply (induction el s t rule: read.induct)
    by (auto 
      simp: pnet_α_def o_def ahm.correct ahs.correct ahm_ld_def 
      split: option.splits) (* Takes long *)
    
  lemma read'_correct_alt: "(read' el s t, read el s t) ∈ ⟨pnet_rel⟩option_rel"
    unfolding pnet_rel_def br_def
    apply (simp add: option_rel_def read'_correct)
    using domIff by force

  export_code read in SML     
  
  definition "reachable_spec c s ≡ RETURN (((Graph.E c)*)``{s}) "
  definition "reaching_spec c t ≡ RETURN ((((Graph.E c)¯)*)``{t})"

  definition "checkNet cc s t ≡ do {
    if s = t then
      RETURN None
    else do {
      let rd = read cc s t;
      case rd of 
        None => RETURN None
      | Some x => do {                
          if pn_s_node x ∧ pn_t_node x then
            do {
              ASSERT(finite ((Graph.E (pn_c x))* `` {s}));
              ASSERT(finite (((Graph.E (pn_c x))¯)* `` {t}));
              ASSERT(∀u. set ((pn_succ x) u) = Graph.E (pn_c x) `` {u} ∧ distinct ((pn_succ x) u));
              ASSERT(∀u. set ((pn_pred x) u) = (Graph.E (pn_c x))¯ `` {u} ∧ distinct ((pn_pred x) u));
              
              succ_s \<leftarrow> reachable_spec (pn_c x) s;
              pred_t \<leftarrow> reaching_spec (pn_c x) t;
              if (pn_V x) = succ_s ∧ (pn_V x) = pred_t then
                RETURN (Some (pn_c x, pn_adjmap x))
              else
                RETURN None
            }
          else
            RETURN None
        }
      }
    }"

  lemma checkNet_pre_correct1 : "checkNet el s t ≤ 
    SPEC (λ r. r = Some (c, adjmap) --> (el, c) ∈ ln_rel ∧ Network c s t ∧ 
    (∀u. set (adjmap u) = Graph.E c``{u} ∪ (Graph.E c)¯``{u} ∧ distinct (adjmap u)))"
    unfolding checkNet_def reachable_spec_def reaching_spec_def
    apply (refine_vcg)
    apply clarsimp_all
      proof -
        {
          fix x
          assume asm1: "s ≠ t"
          assume asm2: "read el s t = Some x"
          assume asm3: "pn_s_node x"
          assume asm4: "pn_t_node x"
          obtain c V sc pd adjmap  where obt: "x = (|pn_c = c, pn_V = V,
            pn_succ = sc, pn_pred = pd,  pn_adjmap = adjmap, pn_s_node = True, pn_t_node = True|)),"
            apply (cases x) using asm3 asm4 by auto
          then have "read el s t = Some (|pn_c = c, pn_V = V, pn_succ = sc, pn_pred = pd, 
            pn_adjmap = adjmap, pn_s_node = True, pn_t_node = True|))," using asm2 by simp
          note fct = read_correct1[OF this]
          
          then have [simp, intro!]: "finite (Graph.V c)" by blast
          have "Graph.E c ⊆ (Graph.V c) × (Graph.V c)" unfolding Graph.V_def by auto
          from finite_subset[OF this] have "finite (Graph.E (pn_c x))" by (simp add: obt)
          then show  "finite ((Graph.E (pn_c x))* `` {s})" 
            and "finite (((Graph.E (pn_c x))¯)* `` {t})"  by (auto simp add: finite_rtrancl_Image)
        }
        {
          fix x
          assume asm1: "s ≠ t"
          assume asm2: "read el s t = Some x"
          assume asm3: "finite ((Graph.E (pn_c x))* `` {s})"
          assume asm4: "finite (((Graph.E (pn_c x))¯)* `` {t})"
          assume asm5: "pn_s_node x"
          assume asm6: "pn_t_node x" 
          obtain c V sc pd adjmap  where obt: "x = (|pn_c = c, pn_V = V,
            pn_succ = sc, pn_pred = pd,  pn_adjmap = adjmap, pn_s_node = True, pn_t_node = True|)),"
            apply (cases x) using asm5 asm6 by auto
          then have "read el s t = Some (|pn_c = c, pn_V = V, pn_succ = sc, pn_pred = pd, 
            pn_adjmap = adjmap, pn_s_node = True, pn_t_node = True|))," using asm2 by simp
          note fct = read_correct1[OF this]
          
          have "!!u. set ((pn_succ x) u) = Graph.E (pn_c x) `` {u} ∧ distinct ((pn_succ x) u)"
            using fct obt by simp
          moreover have "!!u. set ((pn_pred x) u) = (Graph.E (pn_c x))¯ `` {u} ∧ 
            distinct ((pn_pred x) u)" using fct obt by simp
          ultimately show  "!!u. set ((pn_succ x) u) = Graph.E (pn_c x) `` {u}" and 
            "!!u. distinct ((pn_succ x) u)" and "!!u. set ((pn_pred x) u) = (Graph.E (pn_c x))¯ `` {u}"
            and  "!!u.  distinct ((pn_pred x) u)" by auto 
        }
        {
          fix x
          assume asm1: "s ≠ t"
          assume asm2: "read el s t = Some x"
          assume asm3: "pn_s_node x"
          assume asm4: "pn_t_node x"
          assume asm5: "((Graph.E (pn_c x))¯)* `` {t} = (Graph.E (pn_c x))* `` {s}"
          assume asm6: "pn_V x = (Graph.E (pn_c x))* `` {s}" 
          assume asm7: "c = pn_c x"
          assume asm8: "adjmap = pn_adjmap x"
          obtain V sc pd  where obt: "x = (|pn_c = c, pn_V = V,
            pn_succ = sc, pn_pred = pd,  pn_adjmap = adjmap, pn_s_node = True, pn_t_node = True|)),"
            apply (cases x) using asm3 asm4 asm7 asm8 by auto
          then have "read el s t = Some (|pn_c = c, pn_V = V, pn_succ = sc, pn_pred = pd, 
            pn_adjmap = adjmap, pn_s_node = True, pn_t_node = True|))," using asm2 by simp
          note fct = read_correct1[OF this]
          
          have "!!u. set ((pn_succ x) u) = Graph.E (pn_c x) `` {u} ∧ distinct ((pn_succ x) u)"
            using fct obt by simp
          moreover have "!!u. set ((pn_pred x) u) = (Graph.E (pn_c x))¯ `` {u} ∧ 
            distinct ((pn_pred x) u)" using fct obt by simp
          moreover have "(el, pn_c x) ∈ ln_rel" using fct asm7 by simp
          moreover {
            {
              {
                have "Graph.V c ⊆ ((Graph.E c))* `` {s}" using asm6 obt fct by simp
                then have "∀v∈(Graph.V c). Graph.isReachable c s v" 
                  unfolding Graph.connected_def using Graph.rtc_isPath[of s _ c] by auto
              }
              moreover {
                have "Graph.V c ⊆ ((Graph.E c)¯)* `` {t}" using asm5 asm6 obt fct by simp
                then have "∀v∈(Graph.V c). Graph.isReachable c v t"
                  unfolding Graph.connected_def using Graph.rtci_isPath by fastforce
              }
              ultimately have "∀v∈(Graph.V c). Graph.isReachable c s v ∧ Graph.isReachable c v t" by simp
            }
            moreover {
              have "finite (Graph.V c)" and "s ∈ (Graph.V c)" using fct obt by auto
              note Graph.reachable_ss_V[OF `s ∈ (Graph.V c)`]
              note finite_subset[OF this `finite (Graph.V c)`]
            }
            ultimately have "Network (pn_c x) s t" unfolding Network_def using asm1 fct asm7 
              by (simp add: Graph.E_def)
          }
          moreover have "∀u.(set (pn_adjmap x u) =
            Graph.E (pn_c x) `` {u} ∪ (Graph.E (pn_c x))¯ `` {u})" using fct obt by simp
          moreover have "∀u. distinct (pn_adjmap x u)" using fct obt by simp
          ultimately show "(el, pn_c x) ∈ ln_rel" and "Network (pn_c x) s t" and
            "!!u. set (pn_adjmap x u) = Graph.E (pn_c x) `` {u} ∪ (Graph.E (pn_c x))¯ `` {u}" and
            "!!u. distinct (pn_adjmap x u)" by auto
        }
      qed
  
  lemma checkNet_pre_correct2_aux: 
    assumes asm1: "s ≠ t"
    assumes asm2: "read el s t = Some x" 
    assumes asm3: "∀u. set (pn_succ x u) = Graph.E (pn_c x) `` {u} ∧ distinct (pn_succ x u)"
    assumes asm4: "∀u. set (pn_pred x u) = (Graph.E (pn_c x))¯ `` {u} ∧ distinct (pn_pred x u)"
    assumes asm5: "pn_V x = (Graph.E (pn_c x))* `` {s} --> (Graph.E (pn_c x))* `` {s} ≠
      ((Graph.E (pn_c x))¯)* `` {t}"
    assumes asm6: "pn_s_node x"
    assumes asm7: "pn_t_node x"
    assumes asm8: "ln_invar el"
    assumes asm9: "Network (ln_α el) s t"
    shows "False"
    proof -          
      obtain c V sc pd ps  where obt: "x = (|pn_c = c, pn_V = V, pn_succ = sc, pn_pred = pd, 
        pn_adjmap = ps, pn_s_node = True, pn_t_node = True|)),"
        apply (cases x) using asm3 asm4 asm6 asm7 by auto
      then have "read el s t = Some (|pn_c = c, pn_V = V, pn_succ = sc, pn_pred = pd, 
        pn_adjmap = ps, pn_s_node = True, pn_t_node = True|))," using asm2 by simp
      note fct = read_correct1[OF this]
      
      have "pn_V x ≠ (Graph.E (pn_c x))* `` {s} ∨ (pn_V x = (Graph.E (pn_c x))* `` {s} ∧
        ((Graph.E (pn_c x))¯)* `` {t} ≠ (Graph.E (pn_c x))* `` {s})" using asm5 by blast
      thus "False"
        proof
          assume "pn_V x = (Graph.E (pn_c x))* `` {s} ∧ 
            ((Graph.E (pn_c x))¯)* `` {t} ≠ (Graph.E (pn_c x))* `` {s}"
          then have "¬(Graph.V c ⊆ ((Graph.E c)¯)* `` {t}) ∨ ¬(((Graph.E c)¯)* `` {t} ⊆ Graph.V c)"
            using asm5  obt fct by simp
          then have "∃v∈(Graph.V c). ¬Graph.isReachable c v t"
            proof
              assume "¬(((Graph.E c)¯)* `` {t} ⊆ Graph.V c)"
              then obtain x where o1:"x ∈ ((Graph.E c)¯)* `` {t} ∧ x ∉ Graph.V c" by blast
              then have "∃p. Graph.isPath c x p t" using Graph.rtci_isPath by auto
              then obtain p where "Graph.isPath c x p t" by blast
              then have "x ∈ Graph.V c"
                proof (cases "p = []")
                  case True
                    then have "x = t" using `Graph.isPath c x p t` Graph.isPath.simps(1) by auto
                    thus ?thesis using fct by auto
                next
                  case False
                    then obtain p1 ps where "p = p1 # ps" by (meson neq_Nil_conv)
                    then have "Graph.isPath c x (p1 # ps) t" using `Graph.isPath c x p t` by auto
                    then have "fst p1 = x ∧ c p1 ≠ 0" using Graph.isPath_head[of c x p1 ps t] by (auto simp: Graph.E_def)
                    then have "∃v. c (x, v) ≠ 0" by (metis prod.collapse)
                    then have "x ∈ Graph.V c" unfolding Graph.V_def Graph.E_def by auto
                    thus ?thesis by simp
                qed
              thus ?thesis using o1 by auto
            next
              assume "¬(Graph.V c ⊆ ((Graph.E c)¯)* `` {t})"
              then obtain x where o1:"x ∉ ((Graph.E c)¯)* `` {t} ∧ x ∈ Graph.V c" by blast
              then have "(x , t) ∉ (Graph.E c)*" by (meson Image_singleton_iff rtrancl_converseI)
              have "∀p. ¬Graph.isPath c x p t"
                proof (rule ccontr)
                  assume "¬?thesis"
                  then obtain p where "Graph.isPath c x p t" by blast
                  thus "False" using Graph.isPath_rtc `(x , t) ∉ (Graph.E c)*` by auto
                qed
              then have "¬Graph.isReachable c x t" unfolding Graph.connected_def by auto
              thus ?thesis using o1 by auto
            qed
          moreover {
            have "(el, c) ∈ ln_rel" using fct obt by simp
            then have "c = ln_α el" unfolding ln_rel_def br_def by auto
          }
          ultimately have "¬Network (ln_α el) s t" unfolding Network_def by auto
          thus ?thesis using asm9 by blast
        next
          assume "pn_V x ≠ (Graph.E (pn_c x))* `` {s}"
          
          
          then have "¬(Graph.V c ⊆ (Graph.E c)* `` {s}) ∨ ¬((Graph.E c)* `` {s} ⊆ Graph.V c)"
            using asm5  obt fct by simp
          then have "∃v∈(Graph.V c). ¬Graph.isReachable c s v"
            proof
              assume "¬((Graph.E c)* `` {s} ⊆ Graph.V c)"
              then obtain x where o1:"x ∈ (Graph.E c)* `` {s} ∧ x ∉ Graph.V c" by blast
              then have "∃p. Graph.isPath c s p x" using Graph.rtc_isPath by auto
              then obtain p where "Graph.isPath c s p x" by blast
              then have "x ∈ Graph.V c"
                proof (cases "p = []")
                  case True
                    then have "x = s" using `Graph.isPath c s p x` by (auto simp: Graph.isPath.simps(1))
                    thus ?thesis using fct by auto
                next
                  case False
                    then obtain p1 ps where "p = ps @ [p1]" by (metis append_butlast_last_id)
                    then have "Graph.isPath c s (ps @ [p1]) x" using `Graph.isPath c s p x` by auto
                    then have "snd p1 = x ∧ c p1 ≠ 0" using Graph.isPath_tail[of c s ps p1 x] by (auto simp: Graph.E_def)
                    then have "∃v. c (v, x) ≠ 0" by (metis prod.collapse)
                    then have "x ∈ Graph.V c" unfolding Graph.V_def Graph.E_def by auto
                    thus ?thesis by simp
                qed
              thus ?thesis using o1 by auto
            next
              assume "¬(Graph.V c ⊆ (Graph.E c)* `` {s})"
              then obtain x where o1:"x ∉ (Graph.E c)* `` {s} ∧ x ∈ Graph.V c" by blast
              then have "(s , x) ∉ (Graph.E c)*" by (meson Image_singleton_iff rtrancl_converseI)
              have "∀p. ¬Graph.isPath c s p x"
                proof (rule ccontr)
                  assume "¬?thesis"
                  then obtain p where "Graph.isPath c s p x" by blast
                  thus "False" using Graph.isPath_rtc `(s, x) ∉ (Graph.E c)*` by auto
                qed
              then have "¬Graph.isReachable c s x" unfolding Graph.connected_def by auto
              thus ?thesis using o1 by auto
            qed
          moreover {
            have "(el, c) ∈ ln_rel" using fct obt by simp
            then have "c = ln_α el" unfolding ln_rel_def br_def by auto
          }
          ultimately have "¬Network (ln_α el) s t" unfolding Network_def by auto
          thus ?thesis using asm9 by blast
        qed
    qed

  lemma checkNet_pre_correct2:
    "checkNet el s t ≤ SPEC (λr. r = None --> ¬ln_invar el ∨ ¬Network (ln_α el) s t)"
    unfolding checkNet_def reachable_spec_def reaching_spec_def
    apply (refine_vcg)
    apply (clarsimp_all) 
    proof -
      {
        assume "s = t" and "ln_invar el" and "Network (ln_α el) t t"
        thus "False" using Network_def by auto
      }
      next {
        assume "s ≠ t" and "read el s t = None" and "ln_invar el" and "Network (ln_α el) s t"
        note read_correct2[OF `read el s t = None`]
        thus "False"
          proof
            assume "¬ln_invar el"
            thus ?thesis using `ln_invar el` by blast
          next
            assume asm: "(∃u v c. (u, v, c) ∈ set el ∧ ¬(c > 0)) 
            ∨ (∃u c. (u, u, c) ∈ set el ∧ c≠0) ∨ (∃u c. (u, s, c) ∈ set el ∧ c≠0) ∨
              (∃u c. (t, u, c) ∈ set el ∧ c≠0) ∨ (∃u v c1 c2. (u, v, c1) ∈ set el ∧
              (v, u, c2) ∈ set el ∧ c1≠0 ∧ c2≠0)"
            
            moreover {
              assume A: "(∃u v c. (u, v, c) ∈ set el ∧ ¬(c>0))"
              then have "¬ln_invar el" using not_less by (fastforce simp: ln_invar_def)
              with ‹ln_invar el› have False by simp
            }
            moreover {
              assume "(∃u c. (u, u, c) ∈ set el ∧ c≠0)"
              then have "∃ u. ln_α el (u, u) ≠ 0" unfolding ln_α_def apply (auto split:if_splits)
                by (metis (mono_tags, lifting) tfl_some)
              then have "False" using `Network (ln_α el) s t` unfolding Network_def by (auto simp: Graph.E_def)
            }
            moreover {
              assume "(∃u c. (u, s, c) ∈ set el ∧ c≠0)"
              then have "∃ u. ln_α el (u, s) ≠ 0" unfolding ln_α_def apply (auto split:if_splits)
                by (metis (mono_tags, lifting) tfl_some)
              then have "False" using `Network (ln_α el) s t` unfolding Network_def by (auto simp: Graph.E_def)
            }
            moreover {
              assume "(∃u c. (t, u, c) ∈ set el ∧ c≠0)"
              then have "∃ u. ln_α el (t, u) ≠ 0" unfolding ln_α_def apply (auto split:if_splits)
                by (metis (mono_tags, lifting) tfl_some)
              then have "False" using `Network (ln_α el) s t` unfolding Network_def by (auto simp: Graph.E_def)
            }
            moreover {
              assume "(∃u v c1 c2. (u, v, c1) ∈ set el ∧ (v, u, c2) ∈ set el ∧ c1≠0 ∧ c2≠0)"
              then obtain u v c1 c2 where o1: "(u, v, c1) ∈ set el ∧ (v, u, c2) ∈ set el 
                ∧ c1≠0 ∧ c2≠0" by blast
              then have "ln_α el (u, v) ≠ 0" unfolding ln_α_def
                apply (auto split:if_splits) by (metis (mono_tags, lifting) tfl_some)
              moreover have "ln_α el (v, u) ≠ 0" unfolding ln_α_def using o1 
                apply (auto split:if_splits) by (metis (mono_tags, lifting) tfl_some)
              ultimately have "¬ (∀u v. (ln_α el) (u, v) ≠ 0 --> (ln_α el) (v, u) = 0)" by auto
              then have "False" using `Network (ln_α el) s t` unfolding Network_def by (auto simp: Graph.E_def)
            }
            ultimately show ?thesis by force
          qed
      }
      next {
        fix x
        assume asm1: "s ≠ t"
        assume asm2: "read el s t = Some x"
        assume asm3: "pn_s_node x"
        assume asm4: "pn_t_node x"
        obtain c V sc pd adjmap  where obt: "x = (|pn_c = c, pn_V = V,
          pn_succ = sc, pn_pred = pd,  pn_adjmap = adjmap, pn_s_node = True, pn_t_node = True|)),"
          apply (cases x) using asm3 asm4 by auto
        then have "read el s t = Some (|pn_c = c, pn_V = V, pn_succ = sc, pn_pred = pd, 
          pn_adjmap = adjmap, pn_s_node = True, pn_t_node = True|))," using asm2 by simp
        note fct = read_correct1[OF this]
        
        then have [simp]: "finite (Graph.V c)" by blast
        have "Graph.E c ⊆ (Graph.V c) × (Graph.V c)" unfolding Graph.V_def by auto
        from finite_subset[OF this] have "finite (Graph.E (pn_c x))" by (auto simp: obt)
        then show  "finite ((Graph.E (pn_c x))* `` {s})" 
          and "finite (((Graph.E (pn_c x))¯)* `` {t})"  by (auto simp add: finite_rtrancl_Image)
      }
      {
        fix x
        assume asm1: "s ≠ t"
        assume asm2: "read el s t = Some x"
        assume asm3: "finite ((Graph.E (pn_c x))* `` {s})"
        assume asm4: "finite (((Graph.E (pn_c x))¯)* `` {t})"
        assume asm5: "pn_s_node x"
        assume asm6: "pn_t_node x" 
        obtain c V sc pd adjmap  where obt: "x = (|pn_c = c, pn_V = V,
          pn_succ = sc, pn_pred = pd,  pn_adjmap = adjmap, pn_s_node = True, pn_t_node = True|)),"
          apply (cases x) using asm5 asm6 by auto
        then have "read el s t = Some (|pn_c = c, pn_V = V, pn_succ = sc, pn_pred = pd, 
          pn_adjmap = adjmap, pn_s_node = True, pn_t_node = True|))," using asm2 by simp
        note fct = read_correct1[OF this]
        
        have "!!u. set ((pn_succ x) u) = Graph.E (pn_c x) `` {u} ∧ distinct ((pn_succ x) u)"
          using fct obt by simp
        moreover have "!!u. set ((pn_pred x) u) = (Graph.E (pn_c x))¯ `` {u} ∧ 
          distinct ((pn_pred x) u)" using fct obt by simp
        ultimately show  "!!u. set ((pn_succ x) u) = Graph.E (pn_c x) `` {u}" and 
          "!!u. distinct ((pn_succ x) u)" and "!!u. set ((pn_pred x) u) = (Graph.E (pn_c x))¯ `` {u}"
          and  "!!u.  distinct ((pn_pred x) u)" by auto 
      }
      next {
        fix x
        assume asm1: "s ≠ t"
        assume asm2: "read el s t = Some x"
        assume asm3: "pn_s_node x --> ¬pn_t_node x"
        assume asm4: "ln_invar el"
        assume asm5: "Network (ln_α el) s t"
        obtain c V sc pd ps s_node t_node where obt: "x = (|pn_c = c, pn_V = V, pn_succ = sc, pn_pred = pd, 
          pn_adjmap = ps, pn_s_node = s_node, pn_t_node = t_node|))," apply (cases x) by auto 
        then have "read el s t = Some (|pn_c = c, pn_V = V, pn_succ = sc, pn_pred = pd, 
          pn_adjmap = ps, pn_s_node = s_node, pn_t_node = t_node|))," using asm2 by simp
        note fct = read_correct1[OF this]
        
        have "(el, c) ∈ ln_rel" using fct obt by simp
        then have "c = ln_α el" unfolding ln_rel_def br_def by auto
        
        have "¬pn_s_node x ∨ ¬pn_t_node x" using asm3 by auto 
        then show "False"
          proof
            assume "¬pn_s_node x"
            then have "¬s_node" using obt fct by auto
            then have "s ∉ Graph.V c" using fct by auto
            thus ?thesis using `c = ln_α el` asm5 Network_def by auto
          next
            assume "¬pn_t_node x"
            then have "¬t_node" using obt fct by auto
            then have "t ∉ Graph.V c" using fct by auto
            thus ?thesis using `c = ln_α el` asm5 Network_def by auto
          qed
      }
      next show "!!x. s ≠ t ==>
         read el s t = Some x ==>
         ∀u. set (pn_succ x u) = Graph.E (pn_c x) `` {u} ∧ distinct (pn_succ x u) ==>
         ∀u. set (pn_pred x u) = (Graph.E (pn_c x))¯ `` {u} ∧ distinct (pn_pred x u) ==>
         pn_V x = (Graph.E (pn_c x))* `` {s} --> (Graph.E (pn_c x))* `` {s} ≠ ((Graph.E (pn_c x))¯)* `` {t} ==>
         pn_s_node x ==> pn_t_node x ==> ln_invar el ==> Network (ln_α el) s t ==> False"
         using checkNet_pre_correct2_aux by blast
    qed

  lemma checkNet_correct' : "checkNet el s t ≤ SPEC (λ r. case r of 
      Some (c, adjmap) =>
        (el, c) ∈ ln_rel ∧ Network c s t 
        ∧ (∀u. set (adjmap u) = Graph.E c``{u} ∪ (Graph.E c)¯``{u} ∧ distinct (adjmap u))
    | None => ¬ln_invar el ∨ ¬Network (ln_α el) s t)"
    using checkNet_pre_correct1[of el s t] checkNet_pre_correct2[of el s t]
    by (auto split: option.splits simp: pw_le_iff refine_pw_simps)

  lemma checkNet_correct : "checkNet el s t ≤ SPEC (λr. case r of 
      Some (c, adjmap) => (el, c) ∈ ln_rel ∧ Network c s t ∧ Graph.is_adj_map c adjmap
    | None => ¬ln_invar el ∨ ¬Network (ln_α el) s t)"
    using checkNet_pre_correct1[of el s t] checkNet_pre_correct2[of el s t]
    by (auto split: option.splits simp: Graph.is_adj_map_def pw_le_iff refine_pw_simps)

  definition "graph_of pn s ≡ (|
    g_V = UNIV,
    g_E = Graph.E (pn_c pn),
    g_V0 = {s}
  |)),"

  definition "rev_graph_of pn s ≡ (|
    g_V = UNIV,
    g_E = (Graph.E (pn_c pn))¯,
    g_V0 = {s}
  |)),"

  
  definition "checkNet2 cc s t ≡ do {
    if s = t then
      RETURN None
    else do {
      let rd = read cc s t;
      case rd of 
        None => RETURN None
      | Some x => do {                
          if pn_s_node x ∧ pn_t_node x then
            do {
              ASSERT(finite ((Graph.E (pn_c x))* `` {s}));
              ASSERT(finite (((Graph.E (pn_c x))¯)* `` {t}));
              ASSERT(∀u. set ((pn_succ x) u) = Graph.E (pn_c x) `` {u} ∧ distinct ((pn_succ x) u));
              ASSERT(∀u. set ((pn_pred x) u) = (Graph.E (pn_c x))¯ `` {u} ∧ distinct ((pn_pred x) u));
              
              let succ_s = (op_reachable (graph_of x s));
              let pred_t = (op_reachable (rev_graph_of x t));
              if (pn_V x) = succ_s ∧ (pn_V x) = pred_t then
                RETURN (Some (pn_c x, pn_adjmap x))
              else
                RETURN None
            }
          else
            RETURN None
        }
      }
    }"
    
  lemma checkNet2_correct: "checkNet2 c s t ≤ checkNet c s t"
    apply (rule refine_IdD)
    unfolding checkNet_def checkNet2_def graph_of_def rev_graph_of_def reachable_spec_def reaching_spec_def
    apply (refine_rcg)
    apply refine_dref_type
    apply auto
    done
    
  definition "graph_of_impl pn' s ≡ (|
    gi_V = λ_. True,
    gi_E = succ_lookup (pn_succ' pn'),
    gi_V0 = [s]
  |)),"

  definition "rev_graph_of_impl pn' t ≡ (|
    gi_V = λ_. True,
    gi_E = succ_lookup (pn_pred' pn'),
    gi_V0 = [t]
  |)),"
    
  definition "well_formed_pn x ≡ 
    (∀u. set ((pn_succ x) u) = Graph.E (pn_c x) `` {u} ∧ distinct ((pn_succ x) u))"
  
  definition "rev_well_formed_pn x ≡ 
    (∀u. set ((pn_pred x) u) = (Graph.E (pn_c x))¯ `` {u} ∧ distinct ((pn_pred x) u))"
    
  lemma id_slg_rel_alt_a: "⟨Id⟩slg_rel 
    = { (s,E). ∀u. distinct (s u) ∧ set (s u) = E``{u} }"
    by (auto simp add: slg_rel_def br_def list_set_rel_def dest: fun_relD)  
    
  lemma graph_of_impl_correct: "well_formed_pn pn ==> (pn', pn) ∈ pnet_rel ==>
    (graph_of_impl pn' s, graph_of pn s) ∈ ⟨unit_rel,Id⟩g_impl_rel_ext"
    unfolding pnet_rel_def graph_of_impl_def graph_of_def
      g_impl_rel_ext_def gen_g_impl_rel_ext_def
    apply (auto simp: fun_set_rel_def br_def list_set_rel_def id_slg_rel_alt_a ahm_ld_def)
    apply (auto simp: well_formed_pn_def Graph.E_def pnet_α_def o_def ahm_correct)
    done
    
  lemma rev_graph_of_impl_correct:"[|rev_well_formed_pn pn; (pn',pn)∈pnet_rel|] ==> 
    (rev_graph_of_impl pn' s, rev_graph_of pn s) ∈ ⟨unit_rel,Id⟩g_impl_rel_ext"
    unfolding pnet_rel_def rev_graph_of_impl_def rev_graph_of_def
      g_impl_rel_ext_def gen_g_impl_rel_ext_def
    apply (auto simp: fun_set_rel_def br_def list_set_rel_def id_slg_rel_alt_a ahm_ld_def)
    apply (auto simp: rev_well_formed_pn_def Graph.E_def pnet_α_def o_def ahm_correct)
    done   
  
  schematic_lemma reachable_impl:
    assumes [simp]: "finite ((g_E G)* `` g_V0 G)" "graph G"
    assumes [autoref_rules]: "(Gi,G)∈⟨unit_rel,nat_rel⟩g_impl_rel_ext"
    shows "RETURN (?c::?'c) ≤ \<Down>?R (RETURN (op_reachable G))"  
    by autoref_monadic
  concrete_definition reachable_impl uses reachable_impl
  thm reachable_impl.refine

  term reachable_impl term pn_V'
  term "⟨nat_rel⟩dflt_ahs_rel"
  term ahs.rel

  context begin
    interpretation autoref_syn .

    schematic_lemma sets_eq_impl:
      fixes a b :: "nat set"
      assumes [autoref_rules]: "(ai,a) ∈ ⟨nat_rel⟩ahs.rel"
      assumes [autoref_rules]: "(bi,b) ∈ ⟨nat_rel⟩dflt_ahs_rel"
      shows "(?c, (a ::: ⟨nat_rel⟩ahs.rel) = (b ::: ⟨nat_rel⟩dflt_ahs_rel )) ∈ bool_rel"
      apply (autoref (keep_goal) )
      done
    concrete_definition sets_eq_impl uses sets_eq_impl  

  end
  
  definition "net_α ≡ (λ(ci, adjmapi) . 
    ((the_default 0 o (ahm.α ci)), (the_default [] o (ahm.α adjmapi))))"

  lemma [code]: "net_α (ci, adjmapi) = (
    cap_lookup ci, succ_lookup adjmapi
    )"
    unfolding net_α_def by (auto split: option.splits simp: ahm.correct ahm_ld_def)

    
  (*definition "net_invar ≡  (λ(ci, adjmapi) . ahm.invar ci ∧ ahm.invar adjmapi)"
  
  definition "net_rel ≡ br net_α net_invar"*)

  definition "checkNet3 cc s t ≡ do {
    if s = t then
      RETURN None
    else do {
      let rd = read' cc s t;
      case rd of 
        None => RETURN None
      | Some x => do {                
          if pn_s_node' x ∧ pn_t_node' x then
            do {
              ASSERT(finite ((Graph.E (pn_c (pnet_α x)))* `` {s}));
              ASSERT(finite (((Graph.E (pn_c (pnet_α x)))¯)* `` {t}));
              ASSERT(∀u. set ((pn_succ (pnet_α x)) u) =
                Graph.E (pn_c (pnet_α x)) `` {u} ∧ distinct ((pn_succ (pnet_α x)) u));
              ASSERT(∀u. set ((pn_pred (pnet_α x)) u) = 
                (Graph.E (pn_c (pnet_α x)))¯ `` {u} ∧ distinct ((pn_pred (pnet_α x)) u));
            
              let succ_s = (reachable_impl (graph_of_impl x s));
              let pred_t = (reachable_impl (rev_graph_of_impl x t));
              if (sets_eq_impl (pn_V' x) succ_s) ∧ (sets_eq_impl (pn_V' x) pred_t) then
                RETURN (Some (net_α (pn_c' x, pn_adjmap' x)))
              else
                RETURN None
            }
          else
            RETURN None
        }
      }
    }"     

    thm reachable_impl.refine

  term map2set_rel  
  thm sets_eq_impl.refine[simplified]

    
  lemma aux1: "(x', x) ∈ pnet_rel ==> (pn_V' x', pn_V x) ∈ br ahs.α ahs.invar"
    unfolding pnet_rel_def br_def pnet_α_def by auto

  lemma [simp]: "graph (graph_of pn s)"
    apply unfold_locales
    unfolding graph_of_def
    by auto

  lemma [simp]: "graph (rev_graph_of pn s)"
    apply unfold_locales
    unfolding rev_graph_of_def
    by auto


  context begin
  private lemma sets_eq_impl_correct_aux1:
    assumes A: "(pn', pn) ∈ pnet_rel"  
    assumes WF: "well_formed_pn pn" 

    assumes F: "finite ((Graph.E (pn_c (pnet_α pn')))* `` {s})"
    shows "sets_eq_impl (pn_V' pn') (reachable_impl (graph_of_impl pn' s))
      <-> pn_V pn = (g_E (graph_of pn s))* `` g_V0 (graph_of pn s)"
  proof -
    from A have S1i: "(pn_V' pn', pn_V pn) ∈ br ahs.α ahs.invar"
      unfolding pnet_rel_def br_def pnet_α_def by auto

    note GI = graph_of_impl_correct[OF WF A]
    have G: "graph (graph_of pn s)" by simp

    have F': "finite ((g_E (graph_of pn s))* `` g_V0 (graph_of pn s))"
      using F A by (simp add: graph_of_def pnet_α_def pnet_rel_def br_def)

    note S2i = reachable_impl.refine[simplified, OF F' G GI]  

    from sets_eq_impl.refine[simplified, OF S1i S2i] show ?thesis .
  qed 

  private lemma sets_eq_impl_correct_aux2:
    assumes A: "(pn', pn) ∈ pnet_rel"  
    assumes WF: "rev_well_formed_pn pn" 

    assumes F: "finite (((Graph.E (pn_c (pnet_α pn')))¯)* `` {s})"
    shows "sets_eq_impl (pn_V' pn') (reachable_impl (rev_graph_of_impl pn' s))
      <-> pn_V pn = (g_E (rev_graph_of pn s))* `` g_V0 (rev_graph_of pn s)"
  proof -
    from A have S1i: "(pn_V' pn', pn_V pn) ∈ br ahs.α ahs.invar"
      unfolding pnet_rel_def br_def pnet_α_def by auto

    note GI = rev_graph_of_impl_correct[OF WF A]
    have G: "graph (rev_graph_of pn s)" by simp

    have F': "finite ((g_E (rev_graph_of pn s))* `` g_V0 (rev_graph_of pn s))"
      using F A by (simp add: rev_graph_of_def pnet_α_def pnet_rel_def br_def)

    note S2i = reachable_impl.refine[simplified, OF F' G GI]  

    from sets_eq_impl.refine[simplified, OF S1i S2i] show ?thesis .
  qed 



  lemma checkNet3_correct: "checkNet3 el s t ≤ checkNet2 el s t" 
    unfolding checkNet3_def checkNet2_def
    apply (rule refine_IdD)
    apply (refine_rcg)
    apply clarsimp_all
    apply (rule introR[where R="⟨pnet_rel⟩option_rel"])
    (*apply (rule asm_rl [of "(read' el s t, read el s t) ∈ ⟨pnet_rel⟩option_rel"])*)
    apply (simp add: read'_correct_alt; fail)
    apply ((simp add: pnet_rel_def br_def pnet_α_def)+) [7]
    apply (subst sets_eq_impl_correct_aux1; assumption?)
    apply (simp add: well_formed_pn_def)
    
    apply (subst sets_eq_impl_correct_aux2; assumption?)
    apply (simp add: rev_well_formed_pn_def)

    apply simp

    apply (simp add: net_α_def o_def pnet_α_def pnet_rel_def br_def)
    done

  end  


  schematic_lemma checkNet4: "RETURN ?c ≤ checkNet3 el s t"
    unfolding checkNet3_def
    by (refine_transfer)
  concrete_definition checkNet4 for el s t uses checkNet4
    

  lemma checkNet4_correct: "case checkNet4 el s t of 
      Some (c, adjmap) => (el, c) ∈ ln_rel ∧ Network c s t ∧ Graph.is_adj_map c adjmap
    | None => ¬ln_invar el ∨ ¬Network (ln_α el) s t"
  proof -  
    note checkNet4.refine 
    also note checkNet3_correct 
    also note checkNet2_correct
    also note checkNet_correct
    finally show ?thesis by simp
  qed  

  definition prepareNet :: "edge_list => node => node => (capacity_impl graph × (node=>node list) × nat) option"
  where
    "prepareNet el s t ≡ do {
      (c,adjmap) \<leftarrow> checkNet4 el s t;
      let N = ln_N el;
      Some (c,adjmap,N)
    }"

  export_code prepareNet checking SML  

  lemma prepareNet_correct: "case (prepareNet el s t) of 
      Some (c, adjmap,N) => (el, c) ∈ ln_rel ∧ Network c s t ∧ Graph.is_adj_map c adjmap ∧ Graph.V c ⊆ {0..<N}
    | None => ¬ln_invar el ∨ ¬Network (ln_α el) s t"
    using checkNet4_correct[of el s t] ln_N_correct[of el]
    unfolding prepareNet_def
    by (auto split: Option.bind_split simp: ln_rel_def br_def)

end