Theory Directed_Graph_Impl

section ‹Weighted Digraph Implementation by Adjacency Map›
theory Directed_Graph_Impl
imports 
  Directed_Graph_Specs
  "HOL-Data_Structures.Map_Specs"
begin

locale wgraph_by_map = 
  M: Map M_empty M_update M_delete M_lookup M_invar 
  
  for M_empty M_update M_delete 
  and M_lookup :: "'m  'v  ((nat×'v) list) option" and M_invar 
begin

definition α :: "'m  ('v) wgraph" where
  "α g  λ(u,v). case M_lookup g u of 
    None   
  | Some l  if d. (d,v)set l then enat (SOME d. (d,v)set l) else "

definition invar :: "'m  bool" where "invar g  
    M_invar g 
   (lran (M_lookup g). distinct (map snd l)) 
   finite (WGraph.edges (α g))"

definition succ :: "'m  'v  (nat × 'v) list" where
  "succ g v = the_default [] (M_lookup g v)"
  
definition empty_graph :: "'m" where "empty_graph = M_empty"

definition add_edge :: "'v×'v  nat  'm  'm" where
  "add_edge  λ(u,v) d g. M_update u ((d,v) # the_default [] (M_lookup g u)) g"

sublocale adt_finite_wgraph invar succ empty_graph add_edge α
  apply unfold_locales
  subgoal for g u 
    by (cases "M_lookup g u")
       (auto 
          simp: invar_def α_def succ_def ran_def
          intro: distinct_map_snd_inj someI
          split: option.splits
        )
  subgoal by (auto 
                simp: invar_def α_def empty_graph_def add_edge_def M.map_specs 
                split: option.split)
  subgoal by (auto 
                simp: invar_def α_def empty_graph_def add_edge_def M.map_specs 
                split: option.split)
proof -    
  text ‹Explicit proof to nicely handle finiteness constraint, using already
     proved shape of abstract result›
  fix g e d
  assume A: "invar g" "α g e = "
  then show AAE: "α (add_edge e d g) = (α g)(e := enat d)"
    by (auto 
      simp: invar_def α_def add_edge_def M.map_specs
      split: option.splits if_splits prod.splits
    )
  
  from A show "invar (add_edge e d g)"  
    apply (simp add: invar_def AAE)
    by (force
      simp: invar_def α_def empty_graph_def add_edge_def M.map_specs ran_def
      split: option.splits if_splits prod.splits)      
qed (simp add: invar_def)     

end  

end