Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/Isabelle/Archive-of-Formal-Proofs/thys/ConcurrentHOL/ex/   (Sammlung formaler Beweise Version 2026-5©)  Datei vom 31.4.2026 mit Größe 19 kB image not shown  

Quelle  BFS.thy

  Sprache: Isabelle
 

(*<*)
theory BFS
imports
  "Assume_Guarantee"
begin

(*>*)
section Example: data refinement (search)\label{sec:ex-data_refinement}

text

  show a very simple example of data refinement: implementing sets with functional queues
  breadth-first search (BFS). The objective here is to transfer a simple correctness property
  on the abstract level to the concrete level.

 :
 ▪ there is no concurrency in the BFS: this is just about data refinement
 ▪ however arbitrary interference is allowed
 ▪ the abstract level does not require the implementation of the pending set to make progress
 ▪ the concrete level does not require a representation invariant
 ▪ depth optimality is not shown

 :
 ▪ queue ADT: 🍋$ISABELLE_HOME/src/Doc/Codegen/Introduction.thy
 ▪ BFS verification:
 ▪ J. C. Filliâtre 🪙http://toccata.lri.fr/gallery/vstte12_bfs.en.html
 ▪ 🍋$AFP/Refine_Monadic/examples/Breadth_First_Search.thy
 ▪ our model is quite different

 


setup Sign.mandatory_path "pending"

record ('a, 's) interface =
  init :: "('s, unit) prog"
  enq :: "'a ==> ('s, unit) prog"
  deq :: "('s, 'a option) prog"

type_synonym 'a abstract = "'a set"

definition abstract :: "('a, 'a pending.abstract × 's) pending.interface" where
  "abstract =
    ( pending.interface.init = prog.write (map_prod {} id)
    , pending.interface.enq = λx. prog.write (map_prod (insert x) id)
    , pending.interface.deq = prog.action ({(None, s, s) |s. fst s = {}}
                                          {(Some x, (insert x X, s), (X, s)) |X s x. True})
    )"

type_synonym 'a concrete = "'a list × 'a list" ― a queue

fun cdeq_update :: "'a pending.concrete × 's ==> 'a option × 'a pending.concrete × 's" where
  "cdeq_update (([], []), s) = (None, (([], []), s))"
"cdeq_update ((xs, []), s) = cdeq_update (([], rev xs), s)"
"cdeq_update ((xs, y # ys), s) = (Some y, ((xs, ys), s))"

definition concrete :: "('a, 'a pending.concrete × 's) pending.interface" where
  "concrete =
    ( pending.interface.init = prog.write (map_prod ([], []) id)
    , pending.interface.enq = λx. prog.write (map_prod (map_prod ((#) x) id) id)
    , pending.interface.deq = prog.det_action pending.cdeq_update
    )"

abbreviation absfn' :: "'a pending.concrete ==> 'a list" where ― queue as a list
  "absfn' s snd s @ rev (fst s)"

definition absfn :: "'a pending.concrete ==> 'a pending.abstract" where
  "absfn s = set (pending.absfn' s)"

setup Sign.mandatory_path "ag"

lemma init:
  fixes Q :: "unit ==> 'a pending.abstract × 's ==> bool"
  fixes A :: "'s rel"
  assumes "stable (Id ×R A) (Q ())"
  shows "prog.p2s (pending.init pending.abstract) {λs. Q () ({}, snd s)}, Id ×R A UNIV ×R Id, {Q}"
using assms by (auto intro: ag.prog.action simp: pending.abstract_def stable_def monotone_def)

lemma enq:
  fixes x :: 'a
  fixes Q :: "unit ==> 'a pending.abstract × 's ==> bool"
  fixes A :: "'s rel"
  assumes "stable (Id ×R A) (Q ())"
  shows "prog.p2s (pending.enq pending.abstract x) {λs. Q () (insert x (fst s), snd s)}, Id ×R A UNIV ×R Id, {Q}"
using assms by (auto intro: ag.prog.action simp: pending.abstract_def stable_def monotone_def)

lemma deq:
  fixes Q :: "'a option ==> 'a pending.abstract × 's ==> bool"
  fixes A :: "'s rel"
  assumes "v. stable (Id ×R A) (Q v)"
  shows "prog.p2s (pending.deq pending.abstract) {λs. if fst s = {} then Q None s else (x X. fst s = insert x X Q (Some x) (X, snd s))}, Id ×R A UNIV ×R Id, {Q}"
unfolding pending.abstract_def pending.interface.simps
by (rule ag.prog.action)
   (use assms in auto simp: stable_def monotone_def le_bool_def split: if_split_asm)

setup Sign.parent_path

setup Sign.parent_path

setup Sign.mandatory_path "set"

record ('a, 's) interface =
  init :: "('s, unit) prog"
  ins :: "'a ==> ('s, unit) prog"
  mem :: "'a ==> ('s, bool) prog"

type_synonym 'a abstract = "'a list" ― model finite sets

definition abstract :: "('a, 's × 'a set.abstract × 't) set.interface" where
  "abstract =
    ( set.interface.init = prog.write (map_prod id (map_prod [] id))
    , set.interface.ins = λx. prog.write (map_prod id (map_prod ((#) x) id))
    , set.interface.mem = λx. prog.read (λs. x set (fst (snd s)))
    )"

setup Sign.mandatory_path "ag"

lemma init:
  fixes Q :: "unit ==> 's × 'a set.abstract × 't ==> bool"
  fixes A :: "'s rel"
  assumes "stable (A ×R Id ×R B) (Q ())"
  shows "prog.p2s (set.init set.abstract) {λs. Q () (fst s, [], snd (snd s))}, A ×R Id ×R B Id ×R UNIV ×R Id, {Q}"
using assms by (auto intro: ag.prog.action simp: set.abstract_def stable_def monotone_def)

lemma ins:
  fixes x :: 'a
  fixes Q :: "unit ==> 's × 'a set.abstract × 't ==> bool"
  fixes A :: "'s rel"
  assumes "stable (A ×R Id ×R B) (Q ())"
  shows "prog.p2s (set.ins set.abstract x) {λs. Q () (fst s, x # fst (snd s), snd (snd s))}, A ×R Id ×R B Id ×R UNIV ×R Id, {Q}"
using assms by (auto intro: ag.prog.action simp: set.abstract_def stable_def monotone_def)

lemma mem:
  fixes Q :: "bool ==> 's × 'a set.abstract × 't ==> bool"
  assumes "v. stable (A ×R Id ×R B) (Q v)"
  shows "prog.p2s (set.mem set.abstract x) {λs. Q (x set (fst (snd s))) s}, A ×R Id ×R B Id ×R UNIV ×R Id, {Q}"
using assms by (auto intro: ag.prog.action simp: set.abstract_def stable_def monotone_def)

setup Sign.parent_path

setup Sign.parent_path

context
  fixes pending :: "('a, 'p × 'a set.abstract × 's) pending.interface"
  fixes f :: "'a ==> 'a list"
begin

definition loop :: "'a pred ==> ('p × 'a set.abstract × 's, 'a option) prog" where
  "loop p =
    prog.while (λ_.
      do { aopt pending.deq pending
         ; case aopt of
             None ==> prog.return (Inr None)
           | Some x ==>
               if p x
               then prog.return (Inr (Some x))
               else do { prog.app (λy. do { b set.mem set.abstract y;
                                            prog.unlessM b (do { set.ins set.abstract y
                                                               ; pending.enq pending y }) })
                                  (f x)
                       ; prog.return (Inl ())
                       }
       }) ()"

definition main :: "'a pred ==> 'a ==> ('p × 'a set.abstract × 's, 'a option) prog" where
  "main p x =
    do {
      set.init set.abstract
    ; pending.init pending
    ; set.ins set.abstract x
    ; pending.enq pending x
    ; loop p
    }"

definition search :: "'a pred ==> 'a ==> ('s, 'a option) prog" where
  "search p x = prog.local (prog.local (main p x))"

end

abbreviation (input) "aloop loop pending.abstract"
abbreviation (input) "amain main pending.abstract"
abbreviation (input) "asearch search pending.abstract"
abbreviation (input) "bfs search pending.concrete"

lemma
  shows pending_g: "UNIV ×R Id UNIV ×R UNIV ×R Id"
    and set_g: "Id ×R UNIV ×R Id UNIV ×R UNIV ×R Id"
by fastforce+

context
  fixes f :: "'a ==> 'a list"
  fixes P :: "'a pred"
  fixes x0 :: "'a"
begin

abbreviation (input) step :: "'a rel" where
  "step {(x, y). y set (f x)}"

abbreviation (input) path :: "'a rel" where
  "path step*"

definition aloop_invP :: "'a pending.abstract ==> 'a set.abstract ==> bool" where
  "aloop_invP q v
        q set v
       set v path `` {x0}
       set v Collect P q
       x0 set v"

definition vclosureP :: "'a ==> 'a pending.abstract ==> 'a set.abstract ==> bool" where
  "vclosureP x q v (x set v - q step `` {x} set v)"

definition search_postP :: "'a option ==> bool" where
  "search_postP rv = (case rv of
      None ==> finite (path `` {x0}) (path `` {x0} Collect P = {})
    | Some y ==> (x0, y) path P y)"

abbreviation "aloop_inv s aloop_invP (fst s) (fst (snd s))"
abbreviation "vclosure x s vclosureP x (fst s) (fst (snd s))"
abbreviation "search_post rv search_postP rv"

lemma vclosureP_closed:
  assumes "set v path `` {x0}"
  assumes "y. vclosureP y {} v"
  assumes "x0 set v"
  shows "path `` {x0} = set v"
proof -
  have "y set v" if "(x0, y) path" for y
    using that assms(2,3by induct (auto simp: vclosureP_def)
  with assms(1show ?thesis
    by fast
qed

lemma vclosureP_app:
  assumes "y. x y local.vclosureP y q v"
  assumes "set (f x) set v"
  shows "vclosureP y q v"
using assms by (fastforce simp: vclosureP_def)

lemma vclosureP_init:
  shows "vclosureP x {x0} [x0]"
by (simp add: vclosureP_def)

lemma vclosureP_step:
  assumes "z. x z vclosureP z q v"
  assumes "x z"
  shows "vclosureP z (insert y q) (y # v)"
using assms by (fastforce simp: vclosureP_def)

lemma vclosureP_dequeue:
  assumes "z. vclosureP z (insert x q) v"
  assumes "x z"
  shows "vclosureP z q v"
using assms by (fastforce simp: vclosureP_def)

lemma aloop_invPD:
  assumes "aloop_invP q v"
  assumes "x q"
  shows "(x0, x) path"
using assms by (auto simp: aloop_invP_def)

lemma aloop_invP_init:
  shows "aloop_invP {x0} [x0]"
by (simp add: aloop_invP_def)

lemma aloop_invP_step:
  assumes "aloop_invP q v"
  assumes "(x0, x) path"
  assumes "y set (f x) - set v"
  shows "aloop_invP (insert y q) (y # v)"
using assms by (auto simp: aloop_invP_def elim: rtrancl_into_rtrancl)

lemma aloop_invP_dequeue:
  assumes "aloop_invP (insert x q) v"
  assumes "¬ P x"
  shows "aloop_invP q v"
using assms by (auto simp: aloop_invP_def)

lemma search_postcond_None:
  assumes "aloop_invP {} v"
  assumes "y. vclosureP y {} v"
  shows "search_postP None"
using assms by (auto simp: search_postP_def aloop_invP_def dest: vclosureP_closed)

lemma search_postcond_Some:
  assumes "aloop_invP q v"
  assumes "x q"
  assumes "P x"
  shows "search_postP (Some x)"
using assms by (auto simp: search_postP_def aloop_invP_def)

lemmas stable_simps =
  prod.sel
  split_def
  sum.simps

lemma ag_aloop:
  shows "prog.p2s (aloop f P) {aloop_inv \<and> (\<forall>x. vclosure x)}, Id ×R Id ×R UNIV UNIV ×R UNIV ×R Id, {search_post}"
unfolding loop_def
apply (rule ag.prog.while[OF _ _ stable.Id_fst_fst_snd])
 apply (rule ag.prog.bind)
  apply (rule ag.prog.case_option)
   apply (rule ag.prog.return)
   apply ((simp only: stable_simps)?; (rule stable.intro)+; fail)
  apply (rule ag.prog.if)
   apply (rule ag.prog.return)
   apply ((simp only: stable_simps)?; (rule stable.intro)+; fail)
  apply (rule ag.prog.bind)
   apply (rule ag.prog.return)
   apply ((simp only: stable_simps)?; (rule stable.intro)+; fail)
  apply (rename_tac x)
  apply (rule_tac Q="λ_. aloop_inv \<and> (\<forall>y. x y \<longrightarrow> vclosure y) \<and> (λs. set (f x) set (fst (snd s)) (x0, x) path)" in ag.post_imp)
   apply (force elim: vclosureP_app)
  apply (rule ag.prog.app)
   apply (rule ag.prog.bind)
    apply (rule ag.prog.if)
     apply (rule ag.prog.return)
     apply ((simp only: stable_simps)?; (rule stable.intro)+; fail)
    apply (rule ag.prog.bind)
     apply (rule ag.pre_g[OF pending.ag.enq pending_g])
     apply ((simp only: stable_simps)?; (rule stable.intro)+; fail)
    apply (rule ag.pre_g[OF set.ag.ins set_g])
    apply ((simp only: stable_simps)?; (rule stable.intro)+; fail)
   apply (rule ag.pre_pre[OF ag.pre_g[OF set.ag.mem set_g]])
    apply ((simp only: stable_simps)?; (rule stable.intro)+; fail)
   apply (force simp: aloop_invP_step vclosureP_step)
  apply ((simp only: stable_simps)?; (rule stable.intro)+; fail)
 apply (rule ag.pre_g[OF pending.ag.deq pending_g])
 apply ((simp only: stable_simps)?; (rule stable.intro)+; fail)
apply (auto elim: search_postcond_Some search_postcond_None aloop_invP_dequeue
                  aloop_invPD vclosureP_dequeue)
done

lemma ag_amain:
  shows "prog.p2s (amain f P x0) {True}, Id ×R Id ×R UNIV UNIV ×R UNIV ×R Id, {search_post}"
unfolding main_def
apply (rule ag.pre_pre)
 apply (rule ag.prog.bind)+
     apply (rule ag_aloop)
    apply (rule ag.post_imp[where Q="λ(q, v, _). q = {x0} v = [x0]"])
     apply (clarsimp simp: aloop_invP_init vclosureP_init; fail)
    apply (rule ag.pre_g[OF pending.ag.enq pending_g])
    apply ((simp only: stable_simps)?; (rule stable.intro)+; fail)
   apply (rule ag.pre_g[OF set.ag.ins set_g])
   apply ((simp only: stable_simps)?; (rule stable.intro)+; fail)
  apply (rule ag.pre_g[OF pending.ag.init pending_g])
  apply ((simp only: stable_simps)?; (rule stable.intro)+; fail)
 apply (rule ag.pre_g[OF set.ag.init set_g])
 apply ((simp only: stable_simps)?; (rule stable.intro)+; fail)
apply simp
done

lemma ag_asearch:
  shows "prog.p2s (asearch f P x0 :: ('s, 'a option) prog) {True}, UNIV Id, {search_post}"
unfolding search_def by (rule ag.prog.local ag_amain)+


paragraph Refinement

abbreviation "A ag.assm (Id ×R Id ×R UNIV)"
abbreviation "absfn c prog.sinvmap (map_prod pending.absfn id) c"
abbreviation "p2s_absfn c prog.p2s (absfn c)"

visited set: reflexive
lemma ref_set_init:
  shows "prog.p2s (set.init set.abstract) {λs. True}, A ⊨!!! p2s_absfn (set.init set.abstract), {λv s. True}"
by (auto simp: set.abstract_def intro: rair.prog.action stable.intro)

lemma ref_set_ins:
  shows "prog.p2s (set.ins set.abstract x) {λs. True}, A ⊨!!! p2s_absfn (set.ins set.abstract x), {λv s. True}"
by (auto simp: set.abstract_def intro: rair.prog.action stable.intro)

lemma ref_set_mem:
  shows "prog.p2s (set.mem set.abstract x) {λs. True}, A ⊨!!! p2s_absfn (set.mem set.abstract x), {λv s. True}"
by (auto simp: set.abstract_def intro: rair.prog.action stable.intro)

queue
lemma ref_queue_init:
  shows "prog.p2s (pending.init pending.concrete) {λs. True}, A ⊨!!! p2s_absfn (pending.init pending.abstract), {λv s. True}"
by (auto simp: pending.abstract_def pending.concrete_def pending.absfn_def intro: rair.prog.action stable.intro)

lemma ref_queue_enq:
  shows "prog.p2s (pending.enq pending.concrete x) {λs. True}, A ⊨!!! p2s_absfn (pending.enq pending.abstract x), {λv s. True}"
by (auto simp: pending.abstract_def pending.concrete_def pending.absfn_def intro: rair.prog.action stable.intro)

lemma ref_queue_deq:
  shows "prog.p2s (pending.deq pending.concrete) {λs. True}, A ⊨!!! p2s_absfn (pending.deq pending.abstract), {λv s. True}"
by (auto simp: pending.abstract_def pending.concrete_def pending.absfn_def
        intro: rair.prog.action stable.intro elim!: pending.cdeq_update.elims[OF sym])

program
lemma ref_bfs_loop:
  shows "prog.p2s (loop pending.concrete f P) {λs. True}, A ⊨!!! p2s_absfn (loop pending.abstract f P), {λv s. True}"
apply (simp add: loop_def)
apply (rule rair.prog.while)
  apply (rule rair.prog.rev_bind)
   apply (rule ref_queue_deq)
  apply (rule refinement.pre_pre[OF rair.prog.case_option])
    apply (rule rair.prog.return)
    apply ((simp only: stable_simps)?; (rule stable.intro)+; fail)
   apply (rule rair.prog.if)
    apply (rule rair.prog.return)
    apply ((simp only: stable_simps)?; (rule stable.intro)+; fail)
   apply (rule rair.prog.rev_bind)
    apply (rule rair.prog.app)
     apply (rule rair.prog.rev_bind)
      apply (rule ref_set_mem)
     apply (rule refinement.pre_pre[OF rair.prog.if])
       apply (rule rair.prog.return)
       apply ((simp only: stable_simps)?; (rule stable.intro)+; fail)
      apply (rule rair.prog.rev_bind)
       apply (rule ref_set_ins)
      apply (rule ref_queue_enq)
     apply (simp; fail)
    apply ((simp only: stable_simps)?; (rule stable.intro)+; fail)
   apply (rule refinement.pre_pre[OF rair.prog.return])
    apply ((simp only: stable_simps)?; (rule stable.intro)+; fail)
   apply (auto intro: stable.intro split: option.split)
done

lemma ref_bfs_main:
  shows "prog.p2s (main pending.concrete f P x) {True}, A ⊨!!! p2s_absfn (amain f P x), {λv s. True}"
apply (simp add: main_def)
apply (rule rair.prog.rev_bind)
 apply (rule ref_set_init)
apply (rule rair.prog.rev_bind)
 apply (rule ref_queue_init)
apply (rule rair.prog.rev_bind)
 apply (rule ref_set_ins)
apply (rule rair.prog.rev_bind)
 apply (rule ref_queue_enq)
apply (rule ref_bfs_loop)
done

theorem ref_bfs:
  shows "bfs f P x asearch f P x"
unfolding search_def
apply (intro refinement.prog.leI refinement.prog.data[where sf=id])
apply (simp add: spec.invmap.id spec.localizeA.top)
apply (rule refinement.prog.data[where sf=pending.absfn])
apply (simp flip: prog.p2s.invmap)
apply (rule refinement.pre_a[OF ref_bfs_main])
apply (auto simp: spec.localizeA_def spec.invmap.rel
       simp flip: spec.rel.inf
           intro: spec.rel.mono)
done

theorem bfs_post_le:
  shows "prog.p2s (bfs f P x0) spec.post (search_post)"
apply (strengthen ord_to_strengthen[OF ref_bfs])
apply (strengthen ord_to_strengthen(1)[OF ag_asearch])
apply (simp add: ag_def spec.rel.UNIV flip: Sigma_Un_distrib1)
done

end
(*<*)

end
(*>*)

Messung V0.5 in Prozent
C=94 H=91 G=92

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet am  2026-06-10) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.