Theory Check_Non_Planarity_Impl

section ‹Implementation of a Non-Planarity Checker›

theory Check_Non_Planarity_Impl
imports
  Simpl.Vcg
  Simpl_Anno
  Graph_Theory.Graph_Theory
begin

subsection ‹An abstract graph datatype›

type_synonym ig_vertex = nat
type_synonym ig_edge = "ig_vertex × ig_vertex"

typedef IGraph = "{(vs :: ig_vertex list, es :: ig_edge list). distinct vs}"
  by auto

definition ig_verts :: "IGraph  ig_vertex list" where
  "ig_verts G  fst (Rep_IGraph G)"

definition ig_arcs :: "IGraph  ig_edge list" where
  "ig_arcs G  snd (Rep_IGraph G)"

definition ig_verts_cnt :: "IGraph  nat"
  where "ig_verts_cnt G  length (ig_verts G)"

definition ig_arcs_cnt :: "IGraph  nat"
  where "ig_arcs_cnt G  length (ig_arcs G)"

declare ig_verts_cnt_def[simp]
declare ig_arcs_cnt_def[simp]

definition IGraph_inv :: "IGraph  bool" where
  "IGraph_inv G  (e  set (ig_arcs G). fst e  set (ig_verts G)  snd e  set (ig_verts G))"

definition ig_empty :: "IGraph" where
  "ig_empty  Abs_IGraph ([],[])"

definition ig_add_v :: "IGraph  ig_vertex  IGraph" where
  "ig_add_v G v = (if v  set (ig_verts G) then G else Abs_IGraph (ig_verts G @ [v], ig_arcs G ))"

definition ig_add_e :: "IGraph  ig_vertex  ig_vertex  IGraph" where
  "ig_add_e G u v  Abs_IGraph (ig_verts G, ig_arcs G @ [(u,v)])"

definition ig_in_out_arcs :: "IGraph  ig_vertex  ig_edge list" where
  "ig_in_out_arcs G u  filter (λe. fst e = u  snd e = u) (ig_arcs G)"

definition ig_opposite :: "IGraph  ig_edge  ig_vertex  ig_vertex" where
  "ig_opposite G e u = (if fst e = u then snd e else fst e)"

definition ig_neighbors :: "IGraph => ig_vertex => ig_vertex set" where
  "ig_neighbors G u  {v  set (ig_verts G). (u,v)  set (ig_arcs G)  (v,u)  set (ig_arcs G)}"



subsection ‹Code›

procedures is_subgraph (G :: IGraph, H :: IGraph | R :: bool)
  where
    i :: nat
    v :: "ig_vertex"
    ends :: "ig_edge"
  in "
    TRY
      ´i :== 0 ;;
      WHILE ´i < ig_verts_cnt ´G INV named_loop ''verts''
      DO
        ´v :== ig_verts ´G ! ´i ;;
        IF ´v ∉ set (ig_verts ´H) THEN
          RAISE ´R :== False
        FI ;;
        ´i :== ´i + 1
      OD ;;

      ´i :== 0 ;;
      WHILE ´i < ig_arcs_cnt ´G INV named_loop ''arcs''
      DO
        ´ends :== ig_arcs ´G ! ´i ;;
        IF ´ends ∉ set (ig_arcs ´H) ∧ (snd ´ends, fst ´ends) ∉ set (ig_arcs ´H) THEN
          RAISE ´R :== False
        FI ;;
        IF fst ´ends ∉ set (ig_verts ´G) ∨ snd ´ends ∉ set (ig_verts ´G) THEN
          RAISE ´R :== False
        FI ;;
        ´i :== ´i + 1
      OD ;;
      ´R :== True
    CATCH SKIP END
  "

procedures is_loopfree (G :: IGraph | R :: bool)
  where
    i :: nat
    ends :: "ig_edge"
    edge_map :: "ig_edge ⇒ bool"
  in "
    TRY
      ´i :== 0 ;;
      WHILE ´i < ig_arcs_cnt ´G INV named_loop ''loop''
      DO
        ´ends :== ig_arcs ´G ! ´i ;;
        IF fst ´ends = snd ´ends THEN
          RAISE ´R :== False
        FI ;;
        ´i :== ´i + 1
      OD ;;
      ´R :== True
    CATCH SKIP END
  "


procedures select_nodes (G :: IGraph | R :: IGraph)
  where
    i :: nat
    v :: ig_vertex
  in "
    ´R :== ig_empty ;;

    ´i :== 0 ;;
    WHILE ´i < ig_verts_cnt ´G
    INV named_loop ''loop''
    DO
      ´v :== ig_verts ´G ! ´i ;;
      IF 2 < card (ig_neighbors ´G ´v) THEN
        ´R :== ig_add_v ´R ´v
      FI ;;
      ´i :== ´i + 1
    OD
  "

procedures find_endpoint (G :: IGraph, H :: IGraph,  v_tail :: ig_vertex, v_next :: ig_vertex | R :: "ig_vertex option")
  where
    found :: bool
    i :: nat
    len :: nat
    io_arcs :: "ig_edge list"
    v0 :: ig_vertex
    v1 :: ig_vertex
    vt :: ig_vertex
  in "
    TRY
      IF ´v_tail = ´v_next THEN RAISE ´R :== None FI ;;
      ´v0 :== ´v_tail ;;
      ´v1 :== ´v_next ;;
      ´len :== 1 ;;
      WHILE ´v1 ∉ set (ig_verts ´H)
      INV named_loop ''path''
      DO
        ´io_arcs :== ig_in_out_arcs ´G ´v1 ;;
        ´i :== 0 ;;
        ´found :== False ;;
        WHILE ´found = False ∧ ´i < length ´io_arcs
        INV named_loop ''arcs''
        DO
          ´vt :== ig_opposite ´G (´io_arcs ! ´i) ´v1 ;;
          IF ´vt ≠ ´v0 THEN
            ´found :== True ;;
            ´v0 :== ´v1 ;;
            ´v1 :== ´vt
          FI ;;
          ´i :== ´i + 1
        OD ;;
        ´len :== ´len + 1 ;;
        IF ¬ ´found THEN RAISE ´R :== None FI
      OD ;;
      IF ´v1 = ´v_tail THEN RAISE ´R :== None FI ;;
      ´R :== Some ´v1
    CATCH SKIP END
  "

procedures contract (G :: IGraph, H :: IGraph | R :: "IGraph")
  where
    i :: nat
    j :: nat
    u :: ig_vertex
    v :: ig_vertex
    vo :: "ig_vertex option"
    io_arcs :: "ig_edge list"
  in "
    ´i :== 0 ;;
    WHILE ´i < ig_verts_cnt ´H
    INV named_loop ''iter_nodes''
    DO
      ´u :== ig_verts ´H ! ´i ;;
      ´io_arcs :== ig_in_out_arcs ´G ´u ;;

      ´j :== 0 ;;
      WHILE ´j < length ´io_arcs
      INV named_loop ''iter_adj''
      DO
        ´v :== ig_opposite ´G (´io_arcs ! ´j) ´u ;;
        ´vo :== CALL find_endpoint(´G, ´H, ´u, ´v) ;;
        IF ´vo ≠ None THEN
          ´H :== ig_add_e ´H ´u (the ´vo)
        FI ;;
        ´j :== ´j + 1
      OD ;;
      ´i :== ´i + 1
    OD ;;
    ´R :== ´H
  "

procedures is_K33 (G :: IGraph | R :: bool)
  where
    i :: nat
    j :: nat
    u :: ig_vertex
    v :: ig_vertex
    blue :: "ig_vertex ⇒ bool"
    blue_cnt :: nat
    io_arcs :: "ig_edge list"
  in "
    TRY
      IF ig_verts_cnt ´G ≠ 6 THEN RAISE ´R :== False FI ;;
      ´blue :== (λ_. False) ;;

      ´u :== ig_verts ´G ! 0 ;;
      ´i :== 0 ;;
      ´io_arcs :== ig_in_out_arcs ´G ´u ;;

      WHILE ´i < length ´io_arcs INV named_loop ''colorize''
      DO
        ´v :== ig_opposite ´G (´io_arcs ! ´i) ´u ;;
        ´blue :== ´blue(´v := True) ;;
        ´i :== ´i + 1
      OD ;;

      ´blue_cnt :== 0 ;;
      ´i :== 0 ;;
      WHILE ´i < ig_verts_cnt ´G INV named_loop ''component_size''
      DO
        IF ´blue (ig_verts ´G ! ´i) THEN ´blue_cnt :== ´blue_cnt + 1 FI ;;
        ´i :== ´i + 1
      OD ;;
      IF ´blue_cnt ≠ 3 THEN RAISE ´R :== False FI ;;

      ´i :== 0 ;;
      WHILE ´i < ig_verts_cnt ´G INV named_loop ''connected_outer''
      DO
        ´u :== ig_verts ´G ! ´i ;;
        ´j :== 0 ;;
        WHILE ´j < ig_verts_cnt ´G INV named_loop ''connected_inner''
        DO
          ´v :== ig_verts ´G ! ´j ;;
          IF ¬((´blue ´u = ´blue ´v) ⟷ (´u, ´v) ∉ set (ig_arcs ´G)) THEN RAISE ´R :== False FI ;;
          ´j :== ´j + 1
        OD ;;
        ´i :== ´i + 1
      OD ;;
      ´R :== True
    CATCH SKIP END
  "

procedures is_K5 (G :: IGraph | R :: bool)
  where
    i :: nat
    j :: nat
    u :: ig_vertex
  in "
    TRY
      IF ig_verts_cnt ´G ≠ 5 THEN RAISE ´R :== False FI ;;
      ´i :== 0 ;;
      WHILE ´i < 5 INV named_loop ''outer_loop''
        DO
        ´u :== ig_verts ´G ! ´i ;;
        ´j :== 0 ;;
        WHILE ´j < 5 INV named_loop ''inner_loop''
        DO
          IF ¬(´i ≠ ´j ⟷ (´u, ig_verts ´G ! ´j) ∈ set (ig_arcs ´G))
          THEN
            RAISE ´R :== False
          FI ;;
          ´j :== ´j + 1
        OD ;;
        ´i :== ´i + 1
      OD ;;
      ´R :== True
    CATCH SKIP END
  "

procedures check_kuratowski (G :: IGraph, K :: IGraph | R :: bool)
  where
    H :: IGraph
  in "
    TRY
      ´R :== CALL is_subgraph(´K, ´G) ;;
      IF ¬´R THEN RAISE ´R :== False FI ;;
      ´R :== CALL is_loopfree(´K) ;;
      IF ¬´R THEN RAISE ´R :== False FI ;;
      ´H :== CALL select_nodes(´K) ;;
      ´H :== CALL contract(´K, ´H) ;;
      ´R :== CALL is_K5(´H) ;;
      IF ´R THEN RAISE ´R :== True FI ;;
      ´R :== CALL is_K33(´H)
    CATCH SKIP END
  "



end