src/HOL/Boogie/Tools/boogie_vcs.ML
changeset 34068 a78307d72e58
parent 33522 737589bb9bb8
child 34181 003333ffa543
equal deleted inserted replaced
34067:a03f3f9874f6 34068:a78307d72e58
     4 Store for Boogie's verification conditions.
     4 Store for Boogie's verification conditions.
     5 *)
     5 *)
     6 
     6 
     7 signature BOOGIE_VCS =
     7 signature BOOGIE_VCS =
     8 sig
     8 sig
       
     9   datatype skel = Nil of string | Imp of skel | Con1 of skel | Con2 of skel |
       
    10     Conj of skel * skel
       
    11   val size_of: skel * 'a -> int
       
    12   val names_of: skel * 'a -> string list
       
    13   val paths_of: skel * term -> (skel * term) list
       
    14   val split_path: int -> skel * term -> (skel * term) * (skel * term)
       
    15   val extract: skel * term -> string -> (skel * term) option
       
    16 
     9   val set: (string * term) list -> theory -> theory
    17   val set: (string * term) list -> theory -> theory
    10   val lookup: theory -> string -> term option
    18   val lookup: theory -> string -> (skel * term) option
    11   val discharge: string * thm -> theory -> theory
    19   val discharge: string * (skel * thm) -> theory -> theory
    12   val close: theory -> theory
    20   val close: theory -> theory
    13   val is_closed: theory -> bool
    21   val is_closed: theory -> bool
    14   val as_list: theory -> (string * term * bool) list
    22 
       
    23   datatype state = Proved | NotProved | PartiallyProved
       
    24   val state_of: theory -> (string * state) list
       
    25   val state_of_vc: theory -> string -> string list * string list
    15 end
    26 end
    16 
    27 
    17 structure Boogie_VCs: BOOGIE_VCS =
    28 structure Boogie_VCs: BOOGIE_VCS =
    18 struct
    29 struct
    19 
    30 
       
    31 (* simplify VCs: drop True, fold premises into conjunctions *)
       
    32 
       
    33 local
       
    34   val dest_eq = HOLogic.dest_eq o HOLogic.dest_Trueprop o Thm.prop_of
       
    35 
       
    36   val true_rules = map dest_eq @{lemma
       
    37     "(True & P) = P" 
       
    38     "(P & True) = P"
       
    39     "(P --> True) = True"
       
    40     "(True --> P) = P"
       
    41     by simp_all}
       
    42 
       
    43   val fold_prems =
       
    44     dest_eq @{lemma "(P1 --> P2 --> Q) = ((P1 & P2) --> Q)" by fast}
       
    45 in
       
    46 fun simp_vc thy = Pattern.rewrite_term thy (true_rules @ [fold_prems]) []
       
    47 end
       
    48 
       
    49 
       
    50 (* VC skeleton: reflect the structure of implications and conjunctions *)
       
    51 
       
    52 datatype skel =
       
    53   Nil of string |  (* assertion with label name *)
       
    54   Imp of skel |    (* implication: only conclusion is relevant *)
       
    55   Con1 of skel |   (* only left conjunct *)
       
    56   Con2 of skel |   (* right left conjunct *)
       
    57   Conj of skel * skel   (* full conjunction *)
       
    58 
       
    59 val skel_of =
       
    60   let
       
    61     fun skel (@{term "op -->"} $ _ $ u) = Imp (skel u)
       
    62       | skel (@{term "op &"} $ t $ u) = Conj (skel t, skel u)
       
    63       | skel (@{term assert_at} $ Free (n, _) $ _) = Nil n
       
    64       | skel t = raise TERM ("skel_of", [t])
       
    65   in skel o HOLogic.dest_Trueprop end
       
    66 
       
    67 fun size (Nil _) = 1
       
    68   | size (Imp sk) = size sk
       
    69   | size (Con1 sk) = size sk
       
    70   | size (Con2 sk) = size sk
       
    71   | size (Conj (sk1, sk2)) = size sk1 + size sk2
       
    72 
       
    73 fun size_of (sk, _) = size sk
       
    74 
       
    75 fun add_names (Nil name) = cons name   (* label names are unique! *)
       
    76   | add_names (Imp sk) = add_names sk
       
    77   | add_names (Con1 sk) = add_names sk
       
    78   | add_names (Con2 sk) = add_names sk
       
    79   | add_names (Conj (sk1, sk2)) = add_names sk1 #> add_names sk2
       
    80 
       
    81 fun names_of (sk, _) = add_names sk []
       
    82 
       
    83 
       
    84 fun make_app t u = t $ u
       
    85 fun dest_app (t $ u) = (t, u)
       
    86   | dest_app t = raise TERM ("dest_app", [t])
       
    87 
       
    88 val make_prop = HOLogic.mk_Trueprop
       
    89 val dest_prop = HOLogic.dest_Trueprop
       
    90 
       
    91 val make_imp = curry HOLogic.mk_imp
       
    92 val dest_imp = HOLogic.dest_imp
       
    93 
       
    94 val make_conj = curry HOLogic.mk_conj
       
    95 fun dest_conj (@{term "op &"} $ t $ u) = (t, u)
       
    96   | dest_conj t = raise TERM ("dest_conj", [t])
       
    97 
       
    98 
       
    99 fun app_both f g (x, y) = (f x, g y)
       
   100 
       
   101 fun under_imp f r (sk, t) =
       
   102   let val (t1, t2) = dest_imp t
       
   103   in f (sk, t2) |> r (app_both Imp (make_imp t1)) end
       
   104 
       
   105 fun split_conj f r1 r2 r (sk1, sk2, t) =
       
   106   let val (t1, t2) = dest_conj t
       
   107   in
       
   108     f (sk2, t2)
       
   109     |>> r1 (app_both (Conj o pair sk1) (make_conj t1))
       
   110     ||> r2 (apfst Con2)
       
   111     |> r
       
   112   end
       
   113 
       
   114 val paths_of =
       
   115   let
       
   116     fun chop1 xs = (hd xs, tl xs)     
       
   117 
       
   118     fun split (sk, t) =
       
   119       (case sk of
       
   120         Nil _ => [(sk, t)]
       
   121       | Imp sk' => under_imp split map (sk', t)
       
   122       | Con1 sk1 => splt Con1 (sk1, t)
       
   123       | Con2 sk2 => splt Con2 (sk2, t)
       
   124       | Conj (sk1 as Nil _, sk2) =>
       
   125           split_conj (chop1 o split) I map (op ::) (sk1, sk2, t)
       
   126       | Conj (sk1, sk2) =>
       
   127           let val (t1, t2) = dest_conj t
       
   128           in splt Con1 (sk1, t1) @ splt Con2 (sk2, t2) end)
       
   129     and splt c st = split st |> map (apfst c)
       
   130 
       
   131   in map (apsnd make_prop) o split o apsnd dest_prop end
       
   132 
       
   133 fun split_path i =
       
   134   let
       
   135     fun split_at i (sk, t) =
       
   136       (case sk of
       
   137         Imp sk' => under_imp (split_at i) pairself (sk', t)
       
   138       | Con1 sk1 => split_at i (sk1, t) |> pairself (apfst Con1)
       
   139       | Con2 sk2 => split_at i (sk2, t) |> pairself (apfst Con2)
       
   140       | Conj (sk1, sk2) =>
       
   141           if i > 1
       
   142           then split_conj (split_at (i-1)) I I I (sk1, sk2, t)
       
   143           else app_both (pair (Con1 sk1)) (pair (Con2 sk2)) (dest_conj t)
       
   144       | _ => raise TERM ("split_path: " ^ string_of_int i, [t]))
       
   145   in pairself (apsnd make_prop) o split_at i o apsnd dest_prop end
       
   146 
       
   147 fun extract (sk, t) name =
       
   148   let
       
   149     fun is_in (Nil n) = (n = name, false)
       
   150       | is_in (Imp sk) = is_in sk
       
   151       | is_in (Con1 sk) = is_in sk
       
   152       | is_in (Con2 sk) = is_in sk
       
   153       | is_in (Conj (sk1, sk2)) =
       
   154           if fst (is_in sk1) then (true, true) else is_in sk2 ||> K true
       
   155 
       
   156     fun extr (sk, t) =
       
   157       (case sk of
       
   158         Nil _ => (sk, t)
       
   159       | Imp sk' => under_imp extr I (sk', t)
       
   160       | Con1 sk1 => extr (sk1, t) |> apfst Con1
       
   161       | Con2 sk2 => extr (sk2, t) |> apfst Con2
       
   162       | Conj (sk1, sk2) =>
       
   163           (case is_in sk1 of
       
   164             (true, true) => extr (sk1, fst (dest_conj t)) |> apfst Con1
       
   165           | (true, false) => (Con1 sk1, fst (dest_conj t))
       
   166           | (false, _) => extr (sk2, snd (dest_conj t)) |> apfst Con2))
       
   167   in
       
   168     (case is_in sk of
       
   169       (true, true) => SOME ((sk, dest_prop t) |> extr |> apsnd make_prop)
       
   170     | (true, false) => SOME (sk, t)
       
   171     | (false, _) => NONE)
       
   172   end
       
   173 
       
   174 
       
   175 fun cut thy =
       
   176   let
       
   177     fun opt_map_both f g = Option.map (app_both f g)
       
   178 
       
   179     fun cut_err (u, t) = raise TERM ("cut: not matching", [u, t])
       
   180 
       
   181     val matches = Pattern.matches thy
       
   182 
       
   183     fun sub (usk, u) (sk, t) =
       
   184       (case (usk, sk) of
       
   185         (Nil _, Nil _) => if matches (u, t) then NONE else cut_err (u, t)
       
   186       | (Imp usk', Imp sk') => sub_imp (usk', u) (sk', t)
       
   187 
       
   188       | (Con1 usk1, Con1 sk1) =>
       
   189           sub (usk1, u) (sk1, t) |> Option.map (apfst Con1)
       
   190       | (Con2 usk2, Con2 sk2) =>
       
   191           sub (usk2, u) (sk2, t) |> Option.map (apfst Con2)
       
   192 
       
   193       | (Con1 _, Con2 _) => SOME (sk, t)
       
   194       | (Con2 _, Con1 _) => SOME (sk, t)
       
   195 
       
   196       | (Con1 usk1, Conj (sk1, sk2)) =>
       
   197           let val (t1, t2) = dest_conj t
       
   198           in
       
   199             sub (usk1, u) (sk1, t1)
       
   200             |> opt_map_both (Conj o rpair sk2) (fn t1' => make_conj t1' t2)
       
   201             |> SOME o the_default (Con2 sk2, t2)
       
   202           end
       
   203       | (Con2 usk2, Conj (sk1, sk2)) => 
       
   204           let val (t1, t2) = dest_conj t
       
   205           in
       
   206             sub (usk2, u) (sk2, t2)
       
   207             |> opt_map_both (Conj o pair sk1) (make_conj t1)
       
   208             |> SOME o the_default (Con1 sk1, t1)
       
   209           end
       
   210       | (Conj (usk1, _), Con1 sk1) =>
       
   211           let val (u1, _) = dest_conj u
       
   212           in sub (usk1, u1) (sk1, t) |> Option.map (apfst Con1) end
       
   213       | (Conj (_, usk2), Con2 sk2) =>
       
   214           let val (_, u2) = dest_conj u
       
   215           in sub (usk2, u2) (sk2, t) |> Option.map (apfst Con2) end
       
   216 
       
   217       | (Conj (usk1, usk2), Conj (sk1, sk2)) =>
       
   218           sub_conj (usk1, usk2, u) (sk1, sk2, t)
       
   219 
       
   220       | _ => cut_err (u, t))
       
   221 
       
   222     and sub_imp (usk', u) (sk', t) =
       
   223       let
       
   224         val (u1, u2) = dest_imp u
       
   225         val (t1, t2) = dest_imp t
       
   226       in
       
   227         if matches (u1, t1)
       
   228         then sub (usk', u2) (sk', t2) |> opt_map_both Imp (make_imp t1)
       
   229         else cut_err (u, t)
       
   230       end
       
   231 
       
   232     and sub_conj (usk1, usk2, u) (sk1, sk2, t) =
       
   233       let
       
   234         val (u1, u2) = dest_conj u
       
   235         val (t1, t2) = dest_conj t
       
   236       in
       
   237         (case (sub (usk1, u1) (sk1, t1), sub (usk2, u2) (sk2, t2)) of
       
   238           (NONE, NONE) => NONE
       
   239         | (NONE, SOME (sk2', t2')) => SOME (Con2 sk2', t2')
       
   240         | (SOME (sk1', t1'), NONE) => SOME (Con1 sk1', t1')
       
   241         | (SOME (sk1', t1'), SOME (sk2', t2')) =>
       
   242             SOME (Conj (sk1', sk2'), make_conj t1' t2'))
       
   243       end
       
   244   in
       
   245     (fn su => fn st =>
       
   246     (su, st)
       
   247     |> pairself (apsnd dest_prop)
       
   248     |> uncurry sub
       
   249     |> Option.map (apsnd make_prop))
       
   250   end
       
   251 
       
   252 
       
   253 local
       
   254   fun imp f (lsk, lthm) (rsk, rthm) =
       
   255     let
       
   256       val mk_prop = Thm.capply @{cterm Trueprop}
       
   257       val ct = Thm.cprop_of lthm |> Thm.dest_arg |> Thm.dest_arg1 |> mk_prop
       
   258       val th = Thm.assume ct
       
   259       fun imp_elim thm = @{thm mp} OF [thm, th]
       
   260       fun imp_intr thm = Thm.implies_intr ct thm COMP_INCR @{thm impI}
       
   261       val (sk, thm) = f (lsk, imp_elim lthm) (rsk, imp_elim rthm)
       
   262     in (Imp sk, imp_intr thm) end
       
   263 
       
   264   fun conj1 thm = @{thm conjunct1} OF [thm]
       
   265   fun conj2 thm = @{thm conjunct2} OF [thm]
       
   266 in
       
   267 fun join (lsk, lthm) (rsk, rthm) =
       
   268   (case (lsk, rsk) of
       
   269     (Nil _, Nil _) => (lsk, lthm)
       
   270   | (Imp lsk', Imp rsk') => imp join (lsk', lthm) (rsk', rthm)
       
   271 
       
   272   | (Con1 lsk1, Con1 rsk1) => join (lsk1, lthm) (rsk1, rthm) |>> Con1
       
   273   | (Con2 lsk2, Con2 rsk2) => join (lsk2, lthm) (rsk2, rthm) |>> Con2
       
   274 
       
   275   | (Con1 lsk1, Con2 rsk2) => (Conj (lsk1, rsk2), @{thm conjI} OF [lthm, rthm])
       
   276   | (Con2 lsk2, Con1 rsk1) => (Conj (rsk1, lsk2), @{thm conjI} OF [rthm, lthm])
       
   277 
       
   278   | (Con1 lsk1, Conj (rsk1, rsk2)) =>
       
   279       let val (sk1, thm) = join (lsk1, lthm) (rsk1, conj1 rthm)
       
   280       in (Conj (sk1, rsk2), @{thm conjI} OF [thm, conj2 rthm]) end
       
   281   | (Con2 lsk2, Conj (rsk1, rsk2)) =>
       
   282       let val (sk2, thm) = join (lsk2, lthm) (rsk2, conj2 rthm)
       
   283       in (Conj (rsk1, sk2), @{thm conjI} OF [conj1 rthm, thm]) end
       
   284   | (Conj (lsk1, lsk2), Con1 rsk1) =>
       
   285       let val (sk1, thm) = join (lsk1, conj1 lthm) (rsk1, rthm)
       
   286       in (Conj (sk1, lsk2), @{thm conjI} OF [thm, conj2 lthm]) end
       
   287   | (Conj (lsk1, lsk2), Con2 rsk2) =>
       
   288       let val (sk2, thm) = join (lsk2, conj2 lthm) (rsk2, rthm)
       
   289       in (Conj (lsk1, sk2), @{thm conjI} OF [conj1 lthm, thm]) end
       
   290 
       
   291   | (Conj (lsk1, lsk2), Conj (rsk1, rsk2)) =>
       
   292       let
       
   293         val (sk1, th1) = join (lsk1, conj1 lthm) (rsk1, conj1 rthm)
       
   294         val (sk2, th2) = join (lsk2, conj2 lthm) (rsk2, conj2 rthm)
       
   295       in (Conj (sk1, sk2), @{thm conjI} OF [th1, th2]) end
       
   296 
       
   297   | _ => raise THM ("join: different structure", 0, [lthm, rthm]))
       
   298 end
       
   299 
       
   300 
       
   301 (* the VC store *)
       
   302 
    20 fun err_vcs () = error "undischarged Boogie verification conditions found"
   303 fun err_vcs () = error "undischarged Boogie verification conditions found"
       
   304 
       
   305 datatype vc =
       
   306   VC_NotProved of skel * term |
       
   307   VC_PartiallyProved of (skel * term) * (skel * thm) |
       
   308   VC_Proved of skel * thm
       
   309 
       
   310 fun goal_of (VC_NotProved g) = SOME g
       
   311   | goal_of (VC_PartiallyProved (g, _)) = SOME g
       
   312   | goal_of (VC_Proved _) = NONE
       
   313 
       
   314 fun proof_of (VC_NotProved _) = NONE
       
   315   | proof_of (VC_PartiallyProved (_, p)) = SOME p
       
   316   | proof_of (VC_Proved p) = SOME p
    21 
   317 
    22 structure VCs = Theory_Data
   318 structure VCs = Theory_Data
    23 (
   319 (
    24   type T = (term * bool) Symtab.table option
   320   type T = vc Symtab.table option
    25   val empty = NONE
   321   val empty = NONE
    26   val extend = I
   322   val extend = I
    27   fun merge (NONE, NONE) = NONE
   323   fun merge (NONE, NONE) = NONE
    28     | merge _ = err_vcs ()
   324     | merge _ = err_vcs ()
    29 )
   325 )
    30 
   326 
    31 fun set vcs = VCs.map (fn
   327 fun prep thy t = VC_NotProved (` skel_of (simp_vc thy (HOLogic.mk_Trueprop t)))
    32     NONE => SOME (Symtab.make (map (apsnd (rpair false)) vcs))
   328 
    33   | SOME _ => err_vcs ())
   329 fun set vcs thy = VCs.map (fn
    34 
   330     NONE => SOME (Symtab.make (map (apsnd (prep thy)) vcs))
    35 fun lookup thy name = 
   331   | SOME _ => err_vcs ()) thy
       
   332 
       
   333 fun lookup thy name =
    36   (case VCs.get thy of
   334   (case VCs.get thy of
    37     SOME vcs => Option.map fst (Symtab.lookup vcs name)
   335     SOME vcs =>
       
   336       (case Symtab.lookup vcs name of
       
   337         SOME vc => goal_of vc
       
   338       | NONE => NONE)
    38   | NONE => NONE)
   339   | NONE => NONE)
    39 
   340 
    40 fun discharge (name, thm) thy = VCs.map (fn
   341 fun discharge (name, prf) thy = thy |> VCs.map (Option.map
    41     SOME vcs => SOME (Symtab.map_entry name (fn (t, proved) =>
   342   (Symtab.map_entry name (fn
    42       if proved then (t, proved)
   343       VC_NotProved goal =>
    43       else (t, Pattern.matches thy (Thm.prop_of thm, t))) vcs)
   344         (case cut thy (apsnd Thm.prop_of prf) goal of
    44   | NONE => NONE) thy
   345           SOME goal' => VC_PartiallyProved (goal', prf)
       
   346         | NONE => VC_Proved prf)
       
   347     | VC_PartiallyProved (goal, proof) =>
       
   348         (case cut thy (apsnd Thm.prop_of prf) goal of
       
   349           SOME goal' => VC_PartiallyProved (goal', join prf proof)
       
   350         | NONE => VC_Proved (join prf proof))
       
   351     | VC_Proved proof => VC_Proved proof)))
    45 
   352 
    46 val close = VCs.map (fn
   353 val close = VCs.map (fn
    47     SOME vcs =>
   354     SOME vcs =>
    48       if Symtab.exists (fn (_, (_, proved)) => not proved) vcs then err_vcs ()
   355       if Symtab.exists (is_some o goal_of o snd) vcs
       
   356       then err_vcs ()
    49       else NONE
   357       else NONE
    50   | NONE => NONE)
   358   | NONE => NONE)
    51 
   359 
    52 val is_closed = is_none o VCs.get
   360 val is_closed = is_none o VCs.get
    53 
   361 
    54 fun as_list thy =
   362 
       
   363 datatype state = Proved | NotProved | PartiallyProved
       
   364 
       
   365 fun state_of thy =
    55   (case VCs.get thy of
   366   (case VCs.get thy of
    56     SOME vcs => map (fn (n, (t, p)) => (n, t, p)) (Symtab.dest vcs)
   367     SOME vcs => Symtab.dest vcs |> map (apsnd (fn
       
   368         VC_NotProved _ => NotProved
       
   369       | VC_PartiallyProved _ => PartiallyProved
       
   370       | VC_Proved _ => Proved))
    57   | NONE => [])
   371   | NONE => [])
    58 
   372 
       
   373 fun names_of' skx = these (Option.map names_of skx)
       
   374 
       
   375 fun state_of_vc thy name =
       
   376   (case VCs.get thy of
       
   377     SOME vcs =>
       
   378       (case Symtab.lookup vcs name of
       
   379         SOME vc => (names_of' (proof_of vc), names_of' (goal_of vc))
       
   380       | NONE => ([], []))
       
   381   | NONE => ([], []))
       
   382 
    59 end
   383 end