(*******************************************************************************

  Project: Refining Authenticated Key Agreement with Strong Adversaries

  Module:  Message_derivation.thy (Isabelle/HOL 2016-1)
  ID:      $Id: Message_derivation.thy 132885 2016-12-23 18:41:32Z csprenge $
  Author:  Joseph Lallemand, INRIA Nancy <joseph.lallemand@loria.fr>
           Christoph Sprenger, ETH Zurich <sprenger@inf.ethz.ch>

  A theory of message derivations (analz, synth, parts).
  Based on Larry Paulson's theory HOL/Auth/Message.thy, but extended with
  - composed keys
  - including ephemeral asymmetric keys
  - Diffie-Hellman exponentiation and associated equational theory

  Copyright (c) 2015-2016 Joseph Lallemand and Christoph Sprenger
  Licence: LGPL

*******************************************************************************)

section \<open>Message theory\<close>

theory Message_derivation
imports Messages
begin

text \<open>This theory is adapted from Larry Paulson's original Message theory.\<close>

(****************************************************************************************)
subsection \<open>Message composition\<close>
(****************************************************************************************)

text \<open>Dolev-Yao message synthesis.\<close>

inductive_set
  synth :: "msg set \<Rightarrow> msg set"
  for H :: "msg set"
  where
    Ax [intro]: "X \<in> H \<Longrightarrow> X \<in> synth H"
  | Agent [simp, intro]: "Agent A \<in> synth H"
  | Number [simp, intro]: "Number n \<in> synth H"
  | NonceA [simp, intro]: "NonceA n \<in> synth H"
  | EpubKA [simp, intro]: "epubKA n \<in> synth H"
  | EpriKA [simp, intro]: "epriKA n \<in> synth H"
  | Hash [intro]: "X \<in> synth H \<Longrightarrow> Hash X \<in> synth H"
  | Pair [intro]: "X \<in> synth H \<Longrightarrow> Y \<in> synth H \<Longrightarrow> (Pair X Y) \<in> synth H"
  | Enc [intro]: "X \<in> synth H \<Longrightarrow> Y \<in> synth H \<Longrightarrow> (Enc X Y) \<in> synth H"
  | Aenc [intro]: "X \<in> synth H \<Longrightarrow> Y \<in> synth H \<Longrightarrow> (Aenc X Y) \<in> synth H"
  | Sign [intro]: "X \<in> synth H \<Longrightarrow> Y \<in> synth H \<Longrightarrow> Sign X Y \<in> synth H"
  | Exp [intro]: "X \<in> synth H \<Longrightarrow> Y \<in> synth H \<Longrightarrow> (Exp X Y) \<in> synth H"

text \<open>Lemmas about Dolev-Yao message synthesis.\<close>

lemma synth_mono [mono_set]: "G \<subseteq> H \<Longrightarrow> synth G \<subseteq> synth H"
  by (auto, erule synth.induct, auto)

lemmas synth_monotone = synth_mono [THEN [2] rev_subsetD]

\<comment> \<open>\<open>[elim!]\<close> slows down certain proofs, e.g., \<open>\<lbrakk> synth H \<inter> B \<subseteq> {} \<rbrakk> \<Longrightarrow> P\<close>\<close>
inductive_cases NonceF_synth: "NonceF n \<in> synth H"
inductive_cases LtK_synth: "LtK K \<in> synth H"
inductive_cases EpubKF_synth: "epubKF K \<in> synth H"
inductive_cases EpriKF_synth: "epriKF K \<in> synth H"
inductive_cases Hash_synth: "Hash X \<in> synth H"
inductive_cases Pair_synth: "Pair X Y \<in> synth H"
inductive_cases Enc_synth: "Enc X K \<in> synth H"
inductive_cases Aenc_synth: "Aenc X K \<in> synth H"
inductive_cases Sign_synth: "Sign X K \<in> synth H"
inductive_cases Tag_synth: "Tag t \<in> synth H"

lemma EpriK_synth [elim]: "epriK K \<in> synth H \<Longrightarrow>
       epriK K \<in> H \<or> (\<exists> N. epriK K = epriKA N)"
by (cases K, auto elim: EpriKF_synth)

lemma EpubK_synth [elim]: "epubK K \<in> synth H \<Longrightarrow>
       epubK K \<in> H \<or> (\<exists> N. epubK K = epubKA N)"
by (cases K, auto elim: EpubKF_synth)

lemmas synth_inversion [elim] =
  NonceF_synth LtK_synth EpubKF_synth EpriKF_synth Hash_synth Pair_synth
  Enc_synth Aenc_synth Sign_synth Tag_synth

lemma synth_increasing: "H \<subseteq> synth H"
by blast

lemma synth_Int1: "x \<in> synth (A \<inter> B) \<Longrightarrow> x \<in> synth A "
  by (erule synth.induct) (auto)

lemma synth_Int2: "x \<in> synth (A \<inter> B) \<Longrightarrow> x \<in> synth B"
  by (erule synth.induct) (auto)

lemma synth_Int: "x \<in> synth (A \<inter> B) \<Longrightarrow> x \<in> synth A \<inter> synth B"
  by (blast intro: synth_Int1 synth_Int2)

lemma synth_Un: "synth G \<union> synth H \<subseteq> synth (G \<union> H)"
by (intro Un_least synth_mono Un_upper1 Un_upper2)

lemma synth_insert: "insert X (synth H) \<subseteq> synth (insert X H)"
by (blast intro: synth_mono [THEN [2] rev_subsetD])

lemma synth_synthD [dest!]: "X \<in> synth (synth H) \<Longrightarrow> X \<in> synth H"
by (erule synth.induct, blast+)

lemma synth_idem [simp]: "synth (synth H) = synth H"
by blast

lemma synth_subset_iff: "synth G \<subseteq> synth H \<longleftrightarrow> G \<subseteq> synth H"
by (blast dest: synth_mono)

lemma synth_trans: "\<lbrakk> X \<in> synth G; G \<subseteq> synth H \<rbrakk> \<Longrightarrow> X \<in> synth H"
by (drule synth_mono, blast)

lemma synth_cut: "\<lbrakk> Y \<in> synth (insert X H); X \<in> synth H \<rbrakk> \<Longrightarrow> Y \<in> synth H"
by (erule synth_trans, blast)

lemma Nonce_synth_eq [simp]: "(NonceF N \<in> synth H) = (NonceF N \<in> H)"
by blast

lemma LtK_synth_eq [simp]: "(LtK K \<in> synth H) = (LtK K \<in> H)"
by blast

lemma EpubKF_synth_eq [simp]: "(epubKF K \<in> synth H) = (epubKF K \<in> H)"
by blast

lemma EpriKF_synth_eq [simp]: "(epriKF K \<in> synth H) = (epriKF K \<in> H)"
by blast

lemma Enc_synth_eq1 [simp]:
     "K \<notin> synth H \<Longrightarrow> (Enc X K \<in> synth H) = (Enc X K \<in> H)"
by blast

lemma Enc_synth_eq2 [simp]:
     "X \<notin> synth H \<Longrightarrow> (Enc X K \<in> synth H) = (Enc X K \<in> H)"
by blast

lemma Aenc_synth_eq1 [simp]:
     "K \<notin> synth H \<Longrightarrow> (Aenc X K \<in> synth H) = (Aenc X K \<in> H)"
by blast

lemma Aenc_synth_eq2 [simp]:
     "X \<notin> synth H \<Longrightarrow> (Aenc X K \<in> synth H) = (Aenc X K \<in> H)"
by blast

lemma Sign_synth_eq1 [simp]:
     "K \<notin> synth H \<Longrightarrow> (Sign X K \<in> synth H) = (Sign X K \<in> H)"
by blast

lemma Sign_synth_eq2 [simp]:
     "X \<notin> synth H \<Longrightarrow> (Sign X K \<in> synth H) = (Sign X K \<in> H)"
by blast

(****************************************************************************************)
subsection \<open>Message decomposition\<close>
(****************************************************************************************)

text \<open>Dolev-Yao message decomposition using known keys.\<close>

inductive_set
  analz :: "msg set \<Rightarrow> msg set"
  for H :: "msg set"
  where
    Ax [intro]: "X \<in> H \<Longrightarrow> X \<in> analz H"
  | Fst: "Pair X Y \<in> analz H \<Longrightarrow> X \<in> analz H"
  | Snd: "Pair X Y \<in> analz H \<Longrightarrow> Y \<in> analz H"
  | Dec [dest]:
      "\<lbrakk> Enc X Y \<in> analz H; Y \<in> synth (analz H) \<rbrakk> \<Longrightarrow> X \<in> analz H"
  | Adec_lt [dest]:
      "\<lbrakk> Aenc X (LtK (publK Y)) \<in> analz H; priK Y \<in> analz H \<rbrakk> \<Longrightarrow> X \<in> analz H"
  | Adec_eph [dest]:
      "\<lbrakk> Aenc X (EphK (epublK Y)) \<in> analz H; epriK Y \<in> synth (analz H) \<rbrakk> \<Longrightarrow> X \<in> analz H"
  | Sign_getmsg [dest]:
      "Sign X (priK Y) \<in> analz H \<Longrightarrow> pubK Y \<in> analz H \<Longrightarrow> X \<in> analz H"

text \<open>Lemmas about Dolev-Yao message decomposition.\<close>

lemma analz_mono: "G \<subseteq> H \<Longrightarrow> analz(G) \<subseteq> analz(H)"
by (safe, erule analz.induct) (auto dest: Fst Snd synth_Int2)

lemmas analz_monotone = analz_mono [THEN [2] rev_subsetD]

lemma Pair_analz [elim!]:
  "\<lbrakk> Pair X Y \<in> analz H; \<lbrakk> X \<in> analz H; Y \<in> analz H \<rbrakk> \<Longrightarrow> P \<rbrakk> \<Longrightarrow> P"
by (blast dest: analz.Fst analz.Snd)

lemma analz_empty [simp]: "analz {} = {}"
by (safe, erule analz.induct) (blast+)

lemma analz_increasing: "H \<subseteq> analz(H)"
by auto

lemma analz_analzD [dest!]: "X \<in> analz (analz H) \<Longrightarrow> X \<in> analz H"
by (induction X rule: analz.induct) (auto dest: synth_monotone)

lemma analz_idem [simp]: "analz (analz H) = analz H"
by auto

lemma analz_Un: "analz G \<union> analz H \<subseteq> analz (G \<union> H)"
by (intro Un_least analz_mono Un_upper1 Un_upper2)

lemma analz_insertI: "X \<in> analz H \<Longrightarrow> X \<in> analz (insert Y H)"
by (blast intro: analz_monotone)

lemma analz_insert: "insert X (analz H) \<subseteq> analz (insert X H)"
by (blast intro: analz_monotone)

lemmas analz_insert_eq_I = equalityI [OF subsetI analz_insert]

lemma analz_subset_iff [simp]: "analz G \<subseteq> analz H \<longleftrightarrow> G \<subseteq> analz H"
by (blast dest: analz_mono)

lemma analz_trans: "X \<in> analz G \<Longrightarrow>  G \<subseteq> analz H \<Longrightarrow> X \<in> analz H"
by (drule analz_mono) blast

lemma analz_cut: "Y \<in> analz (insert X H) \<Longrightarrow>  X \<in> analz H \<Longrightarrow> Y \<in> analz H"
by (erule analz_trans) blast

lemma analz_insert_eq: "X \<in> analz H \<Longrightarrow> analz (insert X H) = analz H"
by (blast intro: analz_cut analz_insertI)

lemma analz_subset_cong:
  "analz G \<subseteq> analz G' \<Longrightarrow>
   analz H \<subseteq> analz H' \<Longrightarrow>
   analz (G \<union> H) \<subseteq> analz (G' \<union> H')"
apply simp
apply (iprover intro: conjI subset_trans analz_mono Un_upper1 Un_upper2)
done

lemma analz_cong:
  "analz G = analz G' \<Longrightarrow>
   analz H = analz H' \<Longrightarrow>
   analz (G \<union> H) = analz (G' \<union> H')"
by (intro equalityI analz_subset_cong, simp_all)

lemma analz_insert_cong:
  "analz H = analz H' \<Longrightarrow>
   analz (insert X H) = analz (insert X H')"
by (force simp only: insert_def intro!: analz_cong)

lemma analz_trivial:
  "\<forall>X Y. Pair X Y \<notin> H \<Longrightarrow>
   \<forall>X Y. Enc X Y \<notin> H \<Longrightarrow>
   \<forall>X Y. Aenc X Y \<notin> H \<Longrightarrow>
   \<forall>X Y. Sign X Y \<notin> H \<Longrightarrow>
   analz H = H"
apply safe
apply (erule analz.induct, blast+)
done

lemma analz_analz_Un [simp]: "analz (analz G \<union> H) = analz (G \<union> H)"
apply (intro equalityI analz_subset_cong)+
apply simp_all
done

lemma analz_Un_analz [simp]: "analz (G \<union> analz H) = analz (G \<union> H)"
by (subst Un_commute, auto)+

text \<open>Lemmas about analz and insert.\<close>

lemma analz_insert_Agent [simp]:
  "analz (insert (Agent A) H) = insert (Agent A) (analz H)"
apply (rule analz_insert_eq_I)
apply (erule analz.induct)
thm analz.induct
apply fastforce
apply fastforce
apply fastforce
defer 1
apply fastforce
defer 1
apply fastforce

apply (rename_tac x X Y)
apply (subgoal_tac "Y \<in> synth (analz H)", auto)
apply (thin_tac "Enc X Y \<in> Z" for Z)+
apply (drule synth_Int2, auto)
apply (erule synth.induct, auto)

apply (rename_tac X Y)
apply (subgoal_tac "epriK Y \<in> synth (analz H)", auto)
apply (thin_tac "Aenc X (epubK Y) \<in> Z" for Z)+
apply (erule synth.induct, auto)
done

(****************************************************************************************)
subsection \<open>Lemmas about combined composition/decomposition\<close>
(****************************************************************************************)

lemma synth_analz_incr: "H \<subseteq> synth (analz H)"
by auto

lemmas synth_analz_increasing = synth_analz_incr [THEN [2] rev_subsetD]

lemma synth_analz_mono: "G \<subseteq> H \<Longrightarrow> synth (analz G) \<subseteq> synth (analz H)"
by (blast intro!: analz_mono synth_mono)

lemmas synth_analz_monotone = synth_analz_mono [THEN [2] rev_subsetD]

lemma lem1:
  "Y \<in> synth (analz (synth G \<union> H) \<inter> (analz (G \<union> H) \<union> synth G))
\<Longrightarrow> Y \<in> synth (analz (G \<union> H))"
apply (rule subsetD, auto simp add: synth_subset_iff intro: analz_increasing synth_monotone)
done

lemma analz_synth_Un: "analz (synth G \<union> H) = analz (G \<union> H) \<union> synth G"
proof (intro equalityI subsetI)
  fix x
  assume "x \<in> analz (synth G \<union> H)"
  thus "x \<in> analz (G \<union> H) \<union> synth G"
  by (induction x rule: analz.induct)
     (auto simp add: lem2 intro: analz_monotone Fst Snd Dec Adec_eph Adec_lt Sign_getmsg
           dest: lem1)
next
  fix x
  assume "x \<in> analz (G \<union> H) \<union> synth G"
  thus "x \<in> analz (synth G \<union> H)"
    by (blast intro: analz_monotone)
qed

lemma analz_synth: "analz (synth H) = analz H \<union> synth H"
by (rule analz_synth_Un [where H="{}", simplified])

lemma analz_synth_Un2 [simp]: "analz (G \<union> synth H) = analz (G \<union> H) \<union> synth H"
by (subst Un_commute, auto simp add: analz_synth_Un)+

lemma synth_analz_synth [simp]: "synth (analz (synth H)) = synth (analz H)"
by (auto del:subsetI) (auto simp add: synth_subset_iff analz_synth)

lemma analz_synth_analz [simp]: "analz (synth (analz H)) = synth (analz H)"
by (auto simp add: analz_synth)

lemma synth_analz_idem [simp]: "synth (analz (synth (analz H))) = synth (analz H)"
by (simp only: analz_synth_analz) simp

lemma insert_subset_synth_analz [simp]:
  "X \<in> synth (analz H) \<Longrightarrow> insert X H \<subseteq> synth (analz H)"
by auto

lemma synth_analz_insert [simp]:
  assumes "X \<in> synth (analz H)"
  shows "synth (analz (insert X H)) = synth (analz H)"
using assms
proof (intro equalityI subsetI)
  fix Z
  assume "Z \<in> synth (analz (insert X H))"
  hence "Z \<in> synth (analz (synth (analz H)))" using assms
    by - (erule synth_analz_monotone, rule insert_subset_synth_analz)
  thus "Z \<in> synth (analz H)" using assms by simp
qed (auto intro: synth_analz_monotone)

(****************************************************************************************)
subsection \<open>Accessible message parts\<close>
(****************************************************************************************)

text \<open>Accessible message parts: all subterms that are in principle extractable
by the Dolev-Yao attacker, i.e., provided he knows all keys. Note that keys in
key positions and messages under hashes are not message parts in this sense.\<close>

inductive_set
  parts :: "msg set => msg set"
  for H :: "msg set"
where
    Inj [intro]: "X \<in> H \<Longrightarrow> X \<in> parts H"
  | Fst [intro]: "Pair X Y \<in> parts H \<Longrightarrow> X \<in> parts H"
  | Snd [intro]: "Pair X Y \<in> parts H \<Longrightarrow> Y \<in> parts H"
  | Dec [intro]: "Enc X Y \<in> parts H \<Longrightarrow> X \<in> parts H"
  | Adec [intro]: "Aenc X Y \<in> parts H \<Longrightarrow> X \<in> parts H"
  | Sign_getmsg [intro]: "Sign X Y \<in> parts H \<Longrightarrow> X \<in> parts H"

text \<open>Lemmas about accessible message parts.\<close>

lemma parts_mono [mono_set]: "G \<subseteq> H \<Longrightarrow> parts G \<subseteq> parts H"
by (auto, erule parts.induct, auto)

lemmas parts_monotone = parts_mono [THEN [2] rev_subsetD]

lemma Pair_parts [elim]:
  "\<lbrakk> Pair X Y \<in> parts H; \<lbrakk> X \<in> parts H; Y \<in> parts H \<rbrakk> \<Longrightarrow> P \<rbrakk> \<Longrightarrow> P"
by blast

lemma parts_increasing: "H \<subseteq> parts H"
by blast

lemmas parts_insertI = subset_insertI [THEN parts_mono, THEN subsetD]

lemma parts_empty [simp]: "parts {} = {}"
by (safe, erule parts.induct, auto)

lemma parts_atomic [simp]: "atomic x \<Longrightarrow> parts {x} = {x}"
by (auto, erule parts.induct, auto)

lemma parts_InsecTag [simp]: "parts {Tag t} = {Tag t}"
by (safe, erule parts.induct) (auto)

lemma parts_emptyE [elim!]: "X \<in> parts {} \<Longrightarrow> P"
by simp

lemma parts_Tags [simp]:
  "parts Tags = Tags"
by (rule, rule, erule parts.induct, auto)

lemma parts_singleton: "X \<in> parts H \<Longrightarrow> \<exists> Y\<in>H. X \<in> parts {Y}"
by (erule parts.induct, blast+)

lemma parts_Un [simp]: "parts (G \<union> H) = parts G \<union> parts H"
proof
  show "parts (G \<union> H) \<subseteq> parts G \<union> parts H"
    by (rule, erule parts.induct) (auto)
next
  show "parts G \<union> parts H \<subseteq> parts (G \<union> H)"
    by (intro Un_least parts_mono Un_upper1 Un_upper2)
qed

lemma parts_insert_subset_Un:
  assumes "X \<in> G"
  shows "parts (insert X H) \<subseteq> parts G \<union> parts H"
proof -
  from assms have "parts (insert X H) \<subseteq> parts (G \<union> H)" by (blast intro!: parts_mono)
  thus ?thesis by simp
qed

lemma parts_insert: "parts (insert X H) = parts {X} \<union> parts H"
by (blast intro!: parts_insert_subset_Un intro: parts_monotone)

lemma parts_insert2:
  "parts (insert X (insert Y H)) = parts {X} \<union> parts {Y} \<union> parts H"
apply (simp add: Un_assoc)
apply (simp add: parts_insert [symmetric])
done

lemmas in_parts_UnE [elim!] = parts_Un [THEN equalityD1, THEN subsetD, THEN UnE]

lemma parts_insert_subset: "insert X (parts H) \<subseteq> parts (insert X H)"
by (blast intro: parts_mono [THEN [2] rev_subsetD])

lemma parts_partsD [dest!]: "X \<in> parts (parts H) \<Longrightarrow> X \<in> parts H"
by (erule parts.induct, blast+)

lemma parts_idem [simp]: "parts (parts H) = parts H"
by blast

lemma parts_subset_iff [simp]: "(parts G \<subseteq> parts H) \<longleftrightarrow> (G \<subseteq> parts H)"
by (blast dest: parts_mono)

lemma parts_trans: "X \<in> parts G \<Longrightarrow>  G \<subseteq> parts H \<Longrightarrow> X \<in> parts H"
by (drule parts_mono, blast)

lemma parts_cut:
  "Y \<in> parts (insert X G) \<Longrightarrow>  X \<in> parts H \<Longrightarrow> Y \<in> parts (G \<union> H)"
by (blast intro: parts_trans)

lemma parts_cut_eq [simp]: "X \<in> parts H \<Longrightarrow> parts (insert X H) = parts H"
by (force dest!: parts_cut intro: parts_insertI)

lemmas parts_insert_eq_I = equalityI [OF subsetI parts_insert_subset]

lemma parts_insert_Agent [simp]:
  "parts (insert (Agent agt) H) = insert (Agent agt) (parts H)"
by (rule parts_insert_eq_I, erule parts.induct, auto)

lemma parts_insert_Nonce [simp]:
  "parts (insert (Nonce N) H) = insert (Nonce N) (parts H)"
by (rule parts_insert_eq_I, erule parts.induct, auto)

lemma parts_insert_Number [simp]:
  "parts (insert (Number N) H) = insert (Number N) (parts H)"
by (rule parts_insert_eq_I, erule parts.induct, auto)

lemma parts_insert_LtK [simp]:
  "parts (insert (LtK K) H) = insert (LtK K) (parts H)"
by (rule parts_insert_eq_I, erule parts.induct, auto)

lemma parts_insert_Hash [simp]:
  "parts (insert (Hash X) H) = insert (Hash X) (parts H)"
by (rule parts_insert_eq_I, erule parts.induct, auto)

lemma parts_insert_Enc [simp]:
  "parts (insert (Enc X Y) H) = insert (Enc X Y) (parts {X} \<union> parts H)"
apply (rule equalityI)
apply (rule subsetI)
apply (erule parts.induct, auto)
done

lemma parts_insert_Aenc [simp]:
  "parts (insert (Aenc X Y) H) = insert (Aenc X Y) (parts {X} \<union> parts H)"
apply (rule equalityI)
apply (rule subsetI)
apply (erule parts.induct, auto)
done

lemma parts_insert_Sign [simp]:
  "parts (insert (Sign X Y) H) = insert (Sign X Y) (parts {X} \<union> parts H)"
apply (rule equalityI)
apply (rule subsetI)
apply (erule parts.induct, auto)
done

lemma parts_insert_Pair [simp]:
  "parts (insert (Pair X Y) H) = insert (Pair X Y) (parts {X} \<union> parts {Y} \<union> parts H)"
apply (rule equalityI)
apply (rule subsetI)
apply (erule parts.induct, auto)
done

subsubsection \<open>Lemmas about combinations with composition and decomposition\<close>
(****************************************************************************************)

lemma analz_subset_parts: "analz H \<subseteq> parts H"
apply (rule subsetI)
apply (erule analz.induct, blast+)
done

lemmas analz_into_parts [simp] = analz_subset_parts [THEN subsetD]

lemmas not_parts_not_analz = analz_subset_parts [THEN contra_subsetD]

lemma parts_analz [simp]: "parts (analz H) = parts H"
apply (rule equalityI)
apply (rule analz_subset_parts [THEN parts_mono, THEN subset_trans], simp)
apply (blast intro: analz_increasing [THEN parts_mono, THEN subsetD])
done

lemma analz_parts [simp]: "analz (parts H) = parts H"
apply auto
apply (erule analz.induct, auto)
done

lemma parts_synth [simp]: "parts (synth H) = parts H \<union> synth H"
apply (rule equalityI)
apply (rule subsetI)
apply (erule parts.induct)
apply (blast intro: synth_increasing [THEN parts_mono, THEN subsetD] )+
done

lemma Fake_parts_insert:
  "X \<in> synth (analz H) \<Longrightarrow> parts (insert X H) \<subseteq> synth (analz H) \<union> parts H"
apply (drule parts_insert_subset_Un)
apply (simp (no_asm_use))
apply blast
done

lemma Fake_parts_insert_in_Un:
  "Z \<in> parts (insert X H) \<Longrightarrow>
   X \<in> synth (analz H) \<Longrightarrow>
   Z \<in>  synth (analz H) \<union> parts H"
by (blast dest: Fake_parts_insert [THEN subsetD, dest])

lemma analz_conj_parts [simp]:
  "X \<in> analz H \<and> X \<in> parts H \<longleftrightarrow> X \<in> analz H"
by (blast intro: analz_subset_parts [THEN subsetD])

lemma analz_disj_parts [simp]:
  "X \<in> analz H \<or> X \<in> parts H \<longleftrightarrow> X \<in> parts H"
by (blast intro: analz_subset_parts [THEN subsetD])

(****************************************************************************************)
subsection \<open>More lemmas about combinations of closures\<close>
(****************************************************************************************)

text \<open>Combinations of @{term synth} and @{term analz}.\<close>

lemma Pair_synth_analz [simp]:
  "Pair X Y \<in> synth (analz H) \<longleftrightarrow> X \<in> synth (analz H) \<and> Y \<in> synth (analz H)"
by blast

lemma Enc_synth_analz:
  "Y \<in> synth (analz H) \<Longrightarrow>
   (Enc X Y \<in> synth (analz H)) \<longleftrightarrow> (X \<in> synth (analz H))"
by blast

lemma Hash_synth_analz [simp]:
  "X \<notin> synth (analz H) \<Longrightarrow>
   (Hash (Pair X Y) \<in> synth (analz H)) \<longleftrightarrow> (Hash (Pair X Y) \<in> analz H)"
by blast

lemma gen_analz_insert_eq:
  "\<lbrakk> X \<in> analz G; G \<subseteq> H \<rbrakk> \<Longrightarrow> analz (insert X H) = analz H"
by (blast intro: analz_cut analz_insertI analz_monotone)

lemma synth_analz_insert_eq:
  "\<lbrakk> X \<in> synth (analz G); G \<subseteq> H \<rbrakk> \<Longrightarrow> synth (analz (insert X H)) = synth (analz H)"
by (blast intro!: synth_analz_insert synth_analz_monotone)

lemma Fake_parts_sing:
  "X \<in> synth (analz H) \<Longrightarrow> parts {X} \<subseteq> synth (analz H) \<union> parts H"
apply (rule subset_trans)
apply (erule_tac [2] Fake_parts_insert)
apply (rule parts_mono, blast)
done

lemmas Fake_parts_sing_imp_Un = Fake_parts_sing [THEN [2] rev_subsetD]

lemma analz_hash_nonce [simp]:
  "analz {M. \<exists>N. M = Hash (Nonce N)} = {M. \<exists>N. M = Hash (Nonce N)}"
by (auto, rule analz.induct, auto)

lemma synth_analz_hash_nonce [simp]:
  "NonceF N \<notin> synth (analz {M. \<exists>N. M = Hash (Nonce N)})"
by auto

lemma synth_analz_idem_mono:
  "S \<subseteq> synth (analz S') \<Longrightarrow> synth (analz S) \<subseteq> synth (analz S')"
by (frule synth_analz_mono, auto)

lemmas synth_analz_idem_monoI =
  synth_analz_idem_mono [THEN [2] rev_subsetD]

lemma analz_synth_subset:
  "analz X \<subseteq> synth (analz X') \<Longrightarrow>
   analz Y \<subseteq> synth (analz Y') \<Longrightarrow>
   analz (X \<union> Y) \<subseteq> synth (analz (X' \<union> Y'))"
proof -
  assume "analz X \<subseteq> synth (analz X')"
  then have HX:"analz X \<subseteq> analz (synth (analz X'))" by blast
  assume "analz Y \<subseteq> synth (analz Y')"
  then have HY:"analz Y \<subseteq> analz (synth (analz Y'))" by blast
  from analz_subset_cong [OF HX HY]
  have "analz (X \<union> Y) \<subseteq> analz (synth (analz X') \<union> synth (analz Y'))"
    by blast
  also have "... \<subseteq> analz (synth (analz X' \<union> analz Y'))"
    by (intro analz_mono synth_Un)
  also have "... \<subseteq> analz (synth (analz (X' \<union> Y')))"
    by (intro synth_mono analz_mono analz_Un)
  also have "... \<subseteq> synth (analz (X' \<union> Y'))"
    by auto
  finally show "analz (X \<union> Y) \<subseteq> synth (analz (X' \<union> Y'))"
    by auto
qed

lemma analz_synth_subset_Un1 :
  "analz X \<subseteq> synth (analz X') \<Longrightarrow> analz (X \<union> Y) \<subseteq> synth (analz (X' \<union> Y))"
using analz_synth_subset by blast

lemma analz_synth_subset_Un2 :
  "analz X \<subseteq> synth (analz X') \<Longrightarrow> analz (Y \<union> X) \<subseteq> synth (analz (Y \<union> X'))"
using analz_synth_subset by blast

lemma analz_synth_insert:
  "analz X \<subseteq> synth (analz X') \<Longrightarrow> analz (insert Y X) \<subseteq> synth (analz (insert Y X'))"
by (metis analz_synth_subset_Un2 insert_def)

lemma Fake_analz_insert_Un:
  assumes "Y \<in> analz (insert X H)" and "X \<in> synth (analz G)"
  shows "Y \<in> synth (analz G) \<union> analz (G \<union> H)"
proof -
  from assms have "Y \<in> analz (synth (analz G) \<union> H)"
    by (blast intro: analz_mono [THEN [2] rev_subsetD]
                     analz_mono [THEN synth_mono, THEN [2] rev_subsetD])
  thus ?thesis by (simp add: sup.commute)
qed

end


section {* Encoding of the Alarm example in Isabelle/UTP *}

theory Alarm
  imports "../VDM"
begin

type_synonym Period = real
type_synonym Expert = real

alphabet Plant = vlocal +
  staff    :: "Expert set"
  schedule :: "Period \<rightharpoonup> Expert set"

declare Plant.defs [simp]

abbreviation "mk_Plant \<equiv> vuop (bpfun' Plant.make)"

abbreviation
  "inv_Plant \<equiv> (\<Union>\<^sub>v (rng\<^sub>v(&\<^sub>vschedule)) \<subseteq>\<^sub>v &\<^sub>vstaff \<and>\<^sub>v (\<forall>\<^sub>v exs \<in> rng\<^sub>v(&\<^sub>vschedule) \<bullet> \<guillemotleft>exs\<guillemotright>\<^sub>v <>\<^sub>v {}\<^sub>v))"

abbreviation
  "init_Plant \<equiv> (staff :=\<^sub>v {}\<^sub>v ;; schedule :=\<^sub>v \<lbrace>\<mapsto>\<rbrace>\<^sub>v)"

text {* init_Plant establishes the invariant *}

lemma init_Plant_est: "(true \<turnstile>\<^sub>r \<lceil> \<lfloor> inv_Plant \<rfloor>\<^sub>v \<rceil>\<^sub>>) \<sqsubseteq> init_Plant"
  oops

abbreviation
  "addExpert \<equiv> val e :: Expert \<bullet>\<^sub>N [pre &\<^sub>ve \<notin>\<^sub>v &\<^sub>vstaff post true\<^sub>v body staff :=\<^sub>v (&\<^sub>vstaff \<union>\<^sub>v {&\<^sub>ve}\<^sub>v)]\<^sub>v"

abbreviation
  "Assign \<equiv> val e :: Expert, val p :: Period \<bullet>\<^sub>N
              [pre (&\<^sub>ve \<in>\<^sub>v &\<^sub>vstaff \<and>\<^sub>v &\<^sub>vp \<in>\<^sub>v dom\<^sub>v(&\<^sub>vschedule))
               post $\<^sub>ve\<acute> \<in>\<^sub>v $\<^sub>vschedule\<acute>($\<^sub>vp)\<^sub>v
               body schedule(&\<^sub>vp) :=\<^sub>v ({&\<^sub>ve}\<^sub>v \<union>\<^sub>v (&\<^sub>vschedule(&\<^sub>vp)\<^sub>v))]\<^sub>v"

lemma Assign_pres_inv:
  "Assign(e,p) \<sqsubseteq> \<lfloor> inv_Plant \<rfloor>\<^sub>v \<turnstile>\<^sub>n \<lceil> \<lfloor> inv_Plant \<rfloor>\<^sub>v \<rceil>\<^sub>>"
  oops

lemma addExpert_twice: "(addExpert(\<guillemotleft>x\<guillemotright>) ;; addExpert(\<guillemotleft>x\<guillemotright>)) = \<bottom>\<^sub>D"
  apply (rule wpd_H3_eq_intro)
  apply (simp_all add: closure wp)
  apply (simp add: val_parm_def ndes_assigns_def)
  apply (simp add: wp closure usubst)
  oops

lemma "(\<lfloor> inv_Plant \<and>\<^sub>v \<guillemotleft>p\<guillemotright>\<^sub>v \<in>\<^sub>v dom\<^sub>v(&\<^sub>vschedule) \<rfloor>\<^sub>v \<turnstile>\<^sub>n \<lceil> \<lfloor> inv_Plant \<rfloor>\<^sub>v \<rceil>\<^sub>>)
       \<sqsubseteq> (schedule(\<guillemotleft>p\<guillemotright>\<^sub>v) :=\<^sub>v ({\<guillemotleft>e\<guillemotright>\<^sub>v}\<^sub>v \<union>\<^sub>v (&\<^sub>vschedule(\<guillemotleft>p\<guillemotright>\<^sub>v)\<^sub>v)))"
   apply (simp add: vassign_uvar_def)
   apply (rule ndesign_refine_intro)
oops
end


theory Hash_Obligation
imports Hash_User

begin

lemma goal12'1:
  assumes R1: " Hash_Declaration.ca_init'' = (1732584193 :: int) "
  assumes R2: " Hash_Declaration.cb_init'' = (4023233417 :: int) "
  assumes R3: " Hash_Declaration.cc_init'' = (2562383102 :: int) "
  assumes R4: " Hash_Declaration.cd_init'' = (271733878 :: int) "
  assumes R5: " Hash_Declaration.ce_init'' = (3285377520 :: int) "
  assumes R6:
  " (0 :: int) <= Hash_Declaration.interfaces__unsigned_32__size''
  "
  assumes R7:
  " Hash_Declaration.interfaces__unsigned_32__first'' = (0 :: int)
  "
  assumes R8:
  " Hash_Declaration.interfaces__unsigned_32__last''
    = (4294967295 :: int)
  "
  assumes R9:
  " Hash_Declaration.interfaces__unsigned_32__base__first''
    = (0 :: int)
  "
  assumes R10:
  " Hash_Declaration.interfaces__unsigned_32__base__last''
    = (4294967295 :: int)
  "
  assumes R11:
  " Hash_Declaration.interfaces__unsigned_32__modulus''
    = (4294967296 :: int)
  "
  assumes R12: " (0 :: int) <= Hash_Declaration.word__size'' "
  assumes R13: " Hash_Declaration.word__first'' = (0 :: int) "
  assumes R14:
  " Hash_Declaration.word__last'' = (4294967295 :: int)
  "
  assumes R15:
  " Hash_Declaration.word__base__first'' = (0 :: int)
  "
  assumes R16:
  " Hash_Declaration.word__base__last'' = (4294967295 :: int)
  "
  assumes R17:
  " Hash_Declaration.word__modulus'' = (4294967296 :: int)
  "
  assumes R18: " (0 :: int) <= Hash_Declaration.chain__size'' "
  assumes R19:
  " ALL ( A'' :: chain' ) ( B'' :: chain' )
    .   h0'chain A'' = h0'chain B''
        & h1'chain A'' = h1'chain B''
        & h2'chain A'' = h2'chain B''
        & h3'chain A'' = h3'chain B''
        & h4'chain A'' = h4'chain B''
        --> A'' = B''
  "
  assumes R20:
  " (0 :: int) <= Hash_Declaration.block_index__size''
  "
  assumes R21:
  " Hash_Declaration.block_index__first'' = (0 :: int)
  "
  assumes R22:
  " Hash_Declaration.block_index__last'' = (15 :: int)
  "
  assumes R23:
  " Hash_Declaration.block_index__base__first''
    <= Hash_Declaration.block_index__base__last''
  "
  assumes R24:
  " Hash_Declaration.block_index__base__first''
    <= Hash_Declaration.block_index__first''
  "
  assumes R25:
  " Hash_Declaration.block_index__last''
    <= Hash_Declaration.block_index__base__last''
  "
  assumes R26:
  " (0 :: int) <= Hash_Declaration.message_index__size''
  "
  assumes R27:
  " Hash_Declaration.message_index__first'' = (0 :: int)
  "
  assumes R28:
  " Hash_Declaration.message_index__last'' = (4294967296 :: int)
  "
  assumes R29:
  " Hash_Declaration.message_index__base__first''
    <= Hash_Declaration.message_index__base__last''
  "
  assumes R30:
  " Hash_Declaration.message_index__base__first''
    <= Hash_Declaration.message_index__first''
  "
  assumes R31:
  " Hash_Declaration.message_index__last''
    <= Hash_Declaration.message_index__base__last''
  "
  assumes R32:
  " Hash_Declaration.message_index__first''
    <= Hash_Declaration.x__index__subtype__1__first''
  "
  assumes R33:
  " Hash_Declaration.x__index__subtype__1__last''
    <= Hash_Declaration.message_index__last''
  "
  assumes R34:
  " Hash_Declaration.x__index__subtype__1__first''
    <= Hash_Declaration.x__index__subtype__1__last''
  "
  assumes R35:
  " Hash_Declaration.message_index__first''
    <= Hash_Declaration.x__index__subtype__1__last''
  "
  assumes R36:
  " Hash_Declaration.x__index__subtype__1__first''
    <= Hash_Declaration.message_index__last''
  "
  assumes R37:
  " ALL ( i1'' :: int ) ( v'' :: int )
    .   ( Hash_Declaration.block___mk_const_arr' v'' ) i1'' = v''
  "
  assumes R38:
  " ALL ( i1'' :: int ) ( v'' :: block' )
    .   ( Hash_Declaration.message___mk_const_arr' v'' ) i1'' = v''
  "
  assumes H1:
  " Hash_Declaration.x__index__subtype__1__first'' = (0 :: int)
  "
  assumes H2:
  " ALL ( i___2'' :: int )
    .   (0 :: int) <= i___2'' & i___2'' <= (15 :: int)
        --> ( ALL ( i___1'' :: int )
              .   Hash_Declaration.x__index__subtype__1__first'' <= i___1''
                  & i___1'' <= Hash_Declaration.x__index__subtype__1__last''
                  --> (0 :: int) <= ( Hash_Declaration.x'' i___1'' ) i___2''
                      & ( Hash_Declaration.x'' i___1'' ) i___2'' <= (4294967295 :: int)
            )
  "
  assumes H3:
  " (0 :: int) <= Hash_Declaration.x__index__subtype__1__last''
  "
  assumes H4:
  " Hash_Declaration.x__index__subtype__1__last''
    <= (4294967296 :: int)
  "
  assumes H5:
  " Hash_Declaration.x__index__subtype__1__first''
    <= Hash_Declaration.x__index__subtype__1__last''
  "
  assumes H6:
  " Hash_Declaration.chain___default_rcd''
    (| h0'chain
       := Hash_Declaration.ca__1''
    |)
    (| h1'chain
       := Hash_Declaration.cb__1''
    |)
    (| h2'chain
       := Hash_Declaration.cc__1''
    |)
    (| h3'chain
       := Hash_Declaration.cd__1''
    |)
    (| h4'chain
       := Hash_Declaration.ce__1''
    |)
    = Hash_Specification.round'
        ( Hash_Declaration.chain___default_rcd''
          (| h0'chain
             := (1732584193 :: int)
          |)
          (| h1'chain
             := (4023233417 :: int)
          |)
          (| h2'chain
             := (2562383102 :: int)
          |)
          (| h3'chain
             := (271733878 :: int)
          |)
          (| h4'chain
             := (3285377520 :: int)
          |)
        )
        ( Hash_Declaration.x'' Hash_Declaration.x__index__subtype__1__first''
        )
  "
  assumes H7: " (0 :: int) <= Hash_Declaration.ca__1'' "
  assumes H8: " Hash_Declaration.ca__1'' <= (4294967295 :: int) "
  assumes H9: " (0 :: int) <= Hash_Declaration.cb__1'' "
  assumes H10: " Hash_Declaration.cb__1'' <= (4294967295 :: int) "
  assumes H11: " (0 :: int) <= Hash_Declaration.cc__1'' "
  assumes H12: " Hash_Declaration.cc__1'' <= (4294967295 :: int) "
  assumes H13: " (0 :: int) <= Hash_Declaration.cd__1'' "
  assumes H14: " Hash_Declaration.cd__1'' <= (4294967295 :: int) "
  assumes H15: " (0 :: int) <= Hash_Declaration.ce__1'' "
  assumes H16: " Hash_Declaration.ce__1'' <= (4294967295 :: int) "
  shows " Hash_Declaration.chain___default_rcd''
          (| h0'chain
             := Hash_Declaration.ca__1''
          |)
          (| h1'chain
             := Hash_Declaration.cb__1''
          |)
          (| h2'chain
             := Hash_Declaration.cc__1''
          |)
          (| h3'chain
             := Hash_Declaration.cd__1''
          |)
          (| h4'chain
             := Hash_Declaration.ce__1''
          |)
          = Hash_Specification.rounds'
              ( Hash_Declaration.chain___default_rcd''
                (| h0'chain
                   := (1732584193 :: int)
                |)
                (| h1'chain
                   := (4023233417 :: int)
                |)
                (| h2'chain
                   := (2562383102 :: int)
                |)
                (| h3'chain
                   := (271733878 :: int)
                |)
                (| h4'chain
                   := (3285377520 :: int)
                |)
              )
              ( Hash_Declaration.x__index__subtype__1__first'' + (1 :: int) )
              Hash_Declaration.x''
        " (is "?C1")
apply (insert assms) by (rule userlemmas)

lemma goal13'1:
  assumes R1: " Hash_Declaration.ca_init'' = (1732584193 :: int) "
  assumes R2: " Hash_Declaration.cb_init'' = (4023233417 :: int) "
  assumes R3: " Hash_Declaration.cc_init'' = (2562383102 :: int) "
  assumes R4: " Hash_Declaration.cd_init'' = (271733878 :: int) "
  assumes R5: " Hash_Declaration.ce_init'' = (3285377520 :: int) "
  assumes R6:
  " (0 :: int) <= Hash_Declaration.interfaces__unsigned_32__size''
  "
  assumes R7:
  " Hash_Declaration.interfaces__unsigned_32__first'' = (0 :: int)
  "
  assumes R8:
  " Hash_Declaration.interfaces__unsigned_32__last''
    = (4294967295 :: int)
  "
  assumes R9:
  " Hash_Declaration.interfaces__unsigned_32__base__first''
    = (0 :: int)
  "
  assumes R10:
  " Hash_Declaration.interfaces__unsigned_32__base__last''
    = (4294967295 :: int)
  "
  assumes R11:
  " Hash_Declaration.interfaces__unsigned_32__modulus''
    = (4294967296 :: int)
  "
  assumes R12: " (0 :: int) <= Hash_Declaration.word__size'' "
  assumes R13: " Hash_Declaration.word__first'' = (0 :: int) "
  assumes R14:
  " Hash_Declaration.word__last'' = (4294967295 :: int)
  "
  assumes R15:
  " Hash_Declaration.word__base__first'' = (0 :: int)
  "
  assumes R16:
  " Hash_Declaration.word__base__last'' = (4294967295 :: int)
  "
  assumes R17:
  " Hash_Declaration.word__modulus'' = (4294967296 :: int)
  "
  assumes R18: " (0 :: int) <= Hash_Declaration.chain__size'' "
  assumes R19:
  " ALL ( A'' :: chain' ) ( B'' :: chain' )
    .   h0'chain A'' = h0'chain B''
        & h1'chain A'' = h1'chain B''
        & h2'chain A'' = h2'chain B''
        & h3'chain A'' = h3'chain B''
        & h4'chain A'' = h4'chain B''
        --> A'' = B''
  "
  assumes R20:
  " (0 :: int) <= Hash_Declaration.block_index__size''
  "
  assumes R21:
  " Hash_Declaration.block_index__first'' = (0 :: int)
  "
  assumes R22:
  " Hash_Declaration.block_index__last'' = (15 :: int)
  "
  assumes R23:
  " Hash_Declaration.block_index__base__first''
    <= Hash_Declaration.block_index__base__last''
  "
  assumes R24:
  " Hash_Declaration.block_index__base__first''
    <= Hash_Declaration.block_index__first''
  "
  assumes R25:
  " Hash_Declaration.block_index__last''
    <= Hash_Declaration.block_index__base__last''
  "
  assumes R26:
  " (0 :: int) <= Hash_Declaration.message_index__size''
  "
  assumes R27:
  " Hash_Declaration.message_index__first'' = (0 :: int)
  "
  assumes R28:
  " Hash_Declaration.message_index__last'' = (4294967296 :: int)
  "
  assumes R29:
  " Hash_Declaration.message_index__base__first''
    <= Hash_Declaration.message_index__base__last''
  "
  assumes R30:
  " Hash_Declaration.message_index__base__first''
    <= Hash_Declaration.message_index__first''
  "
  assumes R31:
  " Hash_Declaration.message_index__last''
    <= Hash_Declaration.message_index__base__last''
  "
  assumes R32:
  " Hash_Declaration.message_index__first''
    <= Hash_Declaration.x__index__subtype__1__first''
  "
  assumes R33:
  " Hash_Declaration.x__index__subtype__1__last''
    <= Hash_Declaration.message_index__last''
  "
  assumes R34:
  " Hash_Declaration.x__index__subtype__1__first''
    <= Hash_Declaration.x__index__subtype__1__last''
  "
  assumes R35:
  " Hash_Declaration.message_index__first''
    <= Hash_Declaration.x__index__subtype__1__last''
  "
  assumes R36:
  " Hash_Declaration.x__index__subtype__1__first''
    <= Hash_Declaration.message_index__last''
  "
  assumes R37:
  " ALL ( i1'' :: int ) ( v'' :: int )
    .   ( Hash_Declaration.block___mk_const_arr' v'' ) i1'' = v''
  "
  assumes R38:
  " ALL ( i1'' :: int ) ( v'' :: block' )
    .   ( Hash_Declaration.message___mk_const_arr' v'' ) i1'' = v''
  "
  assumes H1:
  " Hash_Declaration.chain___default_rcd''
    (| h0'chain
       := Hash_Declaration.ca''
    |)
    (| h1'chain
       := Hash_Declaration.cb''
    |)
    (| h2'chain
       := Hash_Declaration.cc''
    |)
    (| h3'chain
       := Hash_Declaration.cd''
    |)
    (| h4'chain
       := Hash_Declaration.ce''
    |)
    = Hash_Specification.rounds'
        ( Hash_Declaration.chain___default_rcd''
          (| h0'chain
             := (1732584193 :: int)
          |)
          (| h1'chain
             := (4023233417 :: int)
          |)
          (| h2'chain
             := (2562383102 :: int)
          |)
          (| h3'chain
             := (271733878 :: int)
          |)
          (| h4'chain
             := (3285377520 :: int)
          |)
        )
        ( Hash_Declaration.loop__1__i'' + (1 :: int) )
        Hash_Declaration.x''
  "
  assumes H2:
  " ALL ( i___2'' :: int )
    .   (0 :: int) <= i___2'' & i___2'' <= (15 :: int)
        --> ( ALL ( i___1'' :: int )
              .   Hash_Declaration.x__index__subtype__1__first'' <= i___1''
                  & i___1'' <= Hash_Declaration.x__index__subtype__1__last''
                  --> (0 :: int) <= ( Hash_Declaration.x'' i___1'' ) i___2''
                      & ( Hash_Declaration.x'' i___1'' ) i___2'' <= (4294967295 :: int)
            )
  "
  assumes H3:
  " Hash_Declaration.x__index__subtype__1__first'' = (0 :: int)
  "
  assumes H4: " (0 :: int) <= Hash_Declaration.loop__1__i'' "
  assumes H5:
  " Hash_Declaration.loop__1__i'' <= (4294967296 :: int)
  "
  assumes H6:
  " Hash_Declaration.x__index__subtype__1__first''
    <= Hash_Declaration.loop__1__i''
  "
  assumes H7: " (0 :: int) <= Hash_Declaration.ca'' "
  assumes H8: " Hash_Declaration.ca'' <= (4294967295 :: int) "
  assumes H9: " (0 :: int) <= Hash_Declaration.cb'' "
  assumes H10: " Hash_Declaration.cb'' <= (4294967295 :: int) "
  assumes H11: " (0 :: int) <= Hash_Declaration.cc'' "
  assumes H12: " Hash_Declaration.cc'' <= (4294967295 :: int) "
  assumes H13: " (0 :: int) <= Hash_Declaration.cd'' "
  assumes H14: " Hash_Declaration.cd'' <= (4294967295 :: int) "
  assumes H15: " (0 :: int) <= Hash_Declaration.ce'' "
  assumes H16: " Hash_Declaration.ce'' <= (4294967295 :: int) "
  assumes H17:
  " Hash_Declaration.loop__1__i'' + (1 :: int)
    <= Hash_Declaration.x__index__subtype__1__last''
  "
  assumes H18:
  " Hash_Declaration.chain___default_rcd''
    (| h0'chain
       := Hash_Declaration.ca__1''
    |)
    (| h1'chain
       := Hash_Declaration.cb__1''
    |)
    (| h2'chain
       := Hash_Declaration.cc__1''
    |)
    (| h3'chain
       := Hash_Declaration.cd__1''
    |)
    (| h4'chain
       := Hash_Declaration.ce__1''
    |)
    = Hash_Specification.round'
        ( Hash_Declaration.chain___default_rcd''
          (| h0'chain
             := Hash_Declaration.ca''
          |)
          (| h1'chain
             := Hash_Declaration.cb''
          |)
          (| h2'chain
             := Hash_Declaration.cc''
          |)
          (| h3'chain
             := Hash_Declaration.cd''
          |)
          (| h4'chain
             := Hash_Declaration.ce''
          |)
        )
        ( Hash_Declaration.x'' ( Hash_Declaration.loop__1__i'' + (1 :: int) )
        )
  "
  assumes H19: " (0 :: int) <= Hash_Declaration.ca__1'' "
  assumes H20: " Hash_Declaration.ca__1'' <= (4294967295 :: int) "
  assumes H21: " (0 :: int) <= Hash_Declaration.cb__1'' "
  assumes H22: " Hash_Declaration.cb__1'' <= (4294967295 :: int) "
  assumes H23: " (0 :: int) <= Hash_Declaration.cc__1'' "
  assumes H24: " Hash_Declaration.cc__1'' <= (4294967295 :: int) "
  assumes H25: " (0 :: int) <= Hash_Declaration.cd__1'' "
  assumes H26: " Hash_Declaration.cd__1'' <= (4294967295 :: int) "
  assumes H27: " (0 :: int) <= Hash_Declaration.ce__1'' "
  assumes H28: " Hash_Declaration.ce__1'' <= (4294967295 :: int) "
  assumes H29:
  " (0 :: int) <= Hash_Declaration.interfaces__unsigned_32__size''
  "
  assumes H30: " (0 :: int) <= Hash_Declaration.word__size'' "
  assumes H31: " (0 :: int) <= Hash_Declaration.chain__size'' "
  assumes H32:
  " (0 :: int) <= Hash_Declaration.block_index__size''
  "
  assumes H33:
  " Hash_Declaration.block_index__base__first''
    <= Hash_Declaration.block_index__base__last''
  "
  assumes H34:
  " (0 :: int) <= Hash_Declaration.message_index__size''
  "
  assumes H35:
  " Hash_Declaration.message_index__base__first''
    <= Hash_Declaration.message_index__base__last''
  "
  assumes H36:
  " Hash_Declaration.x__index__subtype__1__first''
    <= Hash_Declaration.x__index__subtype__1__last''
  "
  assumes H37:
  " Hash_Declaration.block_index__base__first'' <= (0 :: int)
  "
  assumes H38:
  " (15 :: int) <= Hash_Declaration.block_index__base__last''
  "
  assumes H39:
  " Hash_Declaration.message_index__base__first'' <= (0 :: int)
  "
  assumes H40:
  " (0 :: int) <= Hash_Declaration.x__index__subtype__1__first''
  "
  assumes H41:
  " (0 :: int) <= Hash_Declaration.x__index__subtype__1__last''
  "
  assumes H42:
  " (4294967296 :: int)
    <= Hash_Declaration.message_index__base__last''
  "
  assumes H43:
  " Hash_Declaration.x__index__subtype__1__last''
    <= (4294967296 :: int)
  "
  assumes H44:
  " Hash_Declaration.x__index__subtype__1__first''
    <= (4294967296 :: int)
  "
  shows " Hash_Declaration.chain___default_rcd''
          (| h0'chain
             := Hash_Declaration.ca__1''
          |)
          (| h1'chain
             := Hash_Declaration.cb__1''
          |)
          (| h2'chain
             := Hash_Declaration.cc__1''
          |)
          (| h3'chain
             := Hash_Declaration.cd__1''
          |)
          (| h4'chain
             := Hash_Declaration.ce__1''
          |)
          = Hash_Specification.rounds'
              ( Hash_Declaration.chain___default_rcd''
                (| h0'chain
                   := (1732584193 :: int)
                |)
                (| h1'chain
                   := (4023233417 :: int)
                |)
                (| h2'chain
                   := (2562383102 :: int)
                |)
                (| h3'chain
                   := (271733878 :: int)
                |)
                (| h4'chain
                   := (3285377520 :: int)
                |)
              )
              ( Hash_Declaration.loop__1__i'' + (2 :: int) )
              Hash_Declaration.x''
        " (is "?C1")
apply (insert assms) by (rule userlemmas)

lemma goal17'1:
  assumes R1: " Hash_Declaration.ca_init'' = (1732584193 :: int) "
  assumes R2: " Hash_Declaration.cb_init'' = (4023233417 :: int) "
  assumes R3: " Hash_Declaration.cc_init'' = (2562383102 :: int) "
  assumes R4: " Hash_Declaration.cd_init'' = (271733878 :: int) "
  assumes R5: " Hash_Declaration.ce_init'' = (3285377520 :: int) "
  assumes R6:
  " (0 :: int) <= Hash_Declaration.interfaces__unsigned_32__size''
  "
  assumes R7:
  " Hash_Declaration.interfaces__unsigned_32__first'' = (0 :: int)
  "
  assumes R8:
  " Hash_Declaration.interfaces__unsigned_32__last''
    = (4294967295 :: int)
  "
  assumes R9:
  " Hash_Declaration.interfaces__unsigned_32__base__first''
    = (0 :: int)
  "
  assumes R10:
  " Hash_Declaration.interfaces__unsigned_32__base__last''
    = (4294967295 :: int)
  "
  assumes R11:
  " Hash_Declaration.interfaces__unsigned_32__modulus''
    = (4294967296 :: int)
  "
  assumes R12: " (0 :: int) <= Hash_Declaration.word__size'' "
  assumes R13: " Hash_Declaration.word__first'' = (0 :: int) "
  assumes R14:
  " Hash_Declaration.word__last'' = (4294967295 :: int)
  "
  assumes R15:
  " Hash_Declaration.word__base__first'' = (0 :: int)
  "
  assumes R16:
  " Hash_Declaration.word__base__last'' = (4294967295 :: int)
  "
  assumes R17:
  " Hash_Declaration.word__modulus'' = (4294967296 :: int)
  "
  assumes R18: " (0 :: int) <= Hash_Declaration.chain__size'' "
  assumes R19:
  " ALL ( A'' :: chain' ) ( B'' :: chain' )
    .   h0'chain A'' = h0'chain B''
        & h1'chain A'' = h1'chain B''
        & h2'chain A'' = h2'chain B''
        & h3'chain A'' = h3'chain B''
        & h4'chain A'' = h4'chain B''
        --> A'' = B''
  "
  assumes R20:
  " (0 :: int) <= Hash_Declaration.block_index__size''
  "
  assumes R21:
  " Hash_Declaration.block_index__first'' = (0 :: int)
  "
  assumes R22:
  " Hash_Declaration.block_index__last'' = (15 :: int)
  "
  assumes R23:
  " Hash_Declaration.block_index__base__first''
    <= Hash_Declaration.block_index__base__last''
  "
  assumes R24:
  " Hash_Declaration.block_index__base__first''
    <= Hash_Declaration.block_index__first''
  "
  assumes R25:
  " Hash_Declaration.block_index__last''
    <= Hash_Declaration.block_index__base__last''
  "
  assumes R26:
  " (0 :: int) <= Hash_Declaration.message_index__size''
  "
  assumes R27:
  " Hash_Declaration.message_index__first'' = (0 :: int)
  "
  assumes R28:
  " Hash_Declaration.message_index__last'' = (4294967296 :: int)
  "
  assumes R29:
  " Hash_Declaration.message_index__base__first''
    <= Hash_Declaration.message_index__base__last''
  "
  assumes R30:
  " Hash_Declaration.message_index__base__first''
    <= Hash_Declaration.message_index__first''
  "
  assumes R31:
  " Hash_Declaration.message_index__last''
    <= Hash_Declaration.message_index__base__last''
  "
  assumes R32:
  " Hash_Declaration.message_index__first''
    <= Hash_Declaration.x__index__subtype__1__first''
  "
  assumes R33:
  " Hash_Declaration.x__index__subtype__1__last''
    <= Hash_Declaration.message_index__last''
  "
  assumes R34:
  " Hash_Declaration.x__index__subtype__1__first''
    <= Hash_Declaration.x__index__subtype__1__last''
  "
  assumes R35:
  " Hash_Declaration.message_index__first''
    <= Hash_Declaration.x__index__subtype__1__last''
  "
  assumes R36:
  " Hash_Declaration.x__index__subtype__1__first''
    <= Hash_Declaration.message_index__last''
  "
  assumes R37:
  " ALL ( i1'' :: int ) ( v'' :: int )
    .   ( Hash_Declaration.block___mk_const_arr' v'' ) i1'' = v''
  "
  assumes R38:
  " ALL ( i1'' :: int ) ( v'' :: block' )
    .   ( Hash_Declaration.message___mk_const_arr' v'' ) i1'' = v''
  "
  assumes H1:
  " Hash_Declaration.chain___default_rcd''
    (| h0'chain
       := Hash_Declaration.ca''
    |)
    (| h1'chain
       := Hash_Declaration.cb''
    |)
    (| h2'chain
       := Hash_Declaration.cc''
    |)
    (| h3'chain
       := Hash_Declaration.cd''
    |)
    (| h4'chain
       := Hash_Declaration.ce''
    |)
    = Hash_Specification.rounds'
        ( Hash_Declaration.chain___default_rcd''
          (| h0'chain
             := (1732584193 :: int)
          |)
          (| h1'chain
             := (4023233417 :: int)
          |)
          (| h2'chain
             := (2562383102 :: int)
          |)
          (| h3'chain
             := (271733878 :: int)
          |)
          (| h4'chain
             := (3285377520 :: int)
          |)
        )
        ( Hash_Declaration.x__index__subtype__1__last'' + (1 :: int) )
        Hash_Declaration.x''
  "
  assumes H2:
  " ALL ( i___2'' :: int )
    .   (0 :: int) <= i___2'' & i___2'' <= (15 :: int)
        --> ( ALL ( i___1'' :: int )
              .   Hash_Declaration.x__index__subtype__1__first'' <= i___1''
                  & i___1'' <= Hash_Declaration.x__index__subtype__1__last''
                  --> (0 :: int) <= ( Hash_Declaration.x'' i___1'' ) i___2''
                      & ( Hash_Declaration.x'' i___1'' ) i___2'' <= (4294967295 :: int)
            )
  "
  assumes H3:
  " Hash_Declaration.x__index__subtype__1__first'' = (0 :: int)
  "
  assumes H4:
  " (0 :: int) <= Hash_Declaration.x__index__subtype__1__last''
  "
  assumes H5:
  " Hash_Declaration.x__index__subtype__1__last''
    <= (4294967296 :: int)
  "
  assumes H6:
  " Hash_Declaration.x__index__subtype__1__first''
    <= Hash_Declaration.x__index__subtype__1__last''
  "
  assumes H7: " (0 :: int) <= Hash_Declaration.ca'' "
  assumes H8: " Hash_Declaration.ca'' <= (4294967295 :: int) "
  assumes H9: " (0 :: int) <= Hash_Declaration.cb'' "
  assumes H10: " Hash_Declaration.cb'' <= (4294967295 :: int) "
  assumes H11: " (0 :: int) <= Hash_Declaration.cc'' "
  assumes H12: " Hash_Declaration.cc'' <= (4294967295 :: int) "
  assumes H13: " (0 :: int) <= Hash_Declaration.cd'' "
  assumes H14: " Hash_Declaration.cd'' <= (4294967295 :: int) "
  assumes H15: " (0 :: int) <= Hash_Declaration.ce'' "
  assumes H16: " Hash_Declaration.ce'' <= (4294967295 :: int) "
  assumes H17:
  " (0 :: int) <= Hash_Declaration.interfaces__unsigned_32__size''
  "
  assumes H18: " (0 :: int) <= Hash_Declaration.word__size'' "
  assumes H19: " (0 :: int) <= Hash_Declaration.chain__size'' "
  assumes H20:
  " (0 :: int) <= Hash_Declaration.block_index__size''
  "
  assumes H21:
  " Hash_Declaration.block_index__base__first''
    <= Hash_Declaration.block_index__base__last''
  "
  assumes H22:
  " (0 :: int) <= Hash_Declaration.message_index__size''
  "
  assumes H23:
  " Hash_Declaration.message_index__base__first''
    <= Hash_Declaration.message_index__base__last''
  "
  assumes H24:
  " Hash_Declaration.x__index__subtype__1__first''
    <= Hash_Declaration.x__index__subtype__1__last''
  "
  assumes H25:
  " Hash_Declaration.block_index__base__first'' <= (0 :: int)
  "
  assumes H26:
  " (15 :: int) <= Hash_Declaration.block_index__base__last''
  "
  assumes H27:
  " Hash_Declaration.message_index__base__first'' <= (0 :: int)
  "
  assumes H28:
  " (0 :: int) <= Hash_Declaration.x__index__subtype__1__first''
  "
  assumes H29:
  " (4294967296 :: int)
    <= Hash_Declaration.message_index__base__last''
  "
  assumes H30:
  " Hash_Declaration.x__index__subtype__1__first''
    <= (4294967296 :: int)
  "
  shows " Hash_Declaration.chain___default_rcd''
          (| h0'chain
             := Hash_Declaration.ca''
          |)
          (| h1'chain
             := Hash_Declaration.cb''
          |)
          (| h2'chain
             := Hash_Declaration.cc''
          |)
          (| h3'chain
             := Hash_Declaration.cd''
          |)
          (| h4'chain
             := Hash_Declaration.ce''
          |)
          = Hash_Specification.rmd_hash'
              Hash_Declaration.x''
              ( Hash_Declaration.x__index__subtype__1__last'' + (1 :: int) )
        " (is "?C1")
apply (insert assms) by (rule userlemmas)
end


theory LazyPrelude_ListNoNumbers_E1
imports "$HETS_LIB/Isabelle/MainHCPairs"
uses "$HETS_LIB/Isabelle/prelude"
begin

ML "Header.initialize
    [\"Comp1\", \"IdDef\", \"FlipDef\", \"FstDef\", \"SndDef\",
     \"CurryDef\", \"UncurryDef\", \"NotFalse\", \"NotTrue\",
     \"AndFalse\", \"AndTrue\", \"AndSym\", \"OrDef\", \"OtherwiseDef\",
     \"NotFalse1\", \"NotTrue1\", \"notNot1\", \"notNot2\",
     \"EqualTDef\", \"EqualSymDef\", \"EqualReflex\", \"EqualTransT\",
     \"DiffDef\", \"DiffSymDef\", \"DiffTDef\", \"DiffFDef\", \"TE1\",
     \"TE2\", \"TE3\", \"TE4\", \"IUE1\", \"IUE2\", \"IBE1\", \"IBE2\",
     \"IBE3\", \"IBE4\", \"IBE5\", \"IBE6\", \"IBE7\", \"IBE8\",
     \"IOE01\", \"IOE02\", \"IOE03\", \"IOE04\", \"IOE05\", \"IOE06\",
     \"IOE07\", \"IOE08\", \"IOE09\", \"LeIrreflexivity\",
     \"LeTAsymmetry\", \"LeTTransitive\", \"LeTTotal\", \"GeDef\",
     \"GeIrreflexivity\", \"GeTAsymmetry\", \"GeTTransitive\",
     \"GeTTotal\", \"LeqDef\", \"LeqReflexivity\", \"LeqTTransitive\",
     \"LeqTTotal\", \"GeqDef\", \"GeqReflexivity\", \"GeqTTransitive\",
     \"GeqTTotal\", \"EqTSOrdRel\", \"EqFSOrdRel\", \"EqTOrdRel\",
     \"EqFOrdRel\", \"EqTOrdTSubstE\", \"EqTOrdFSubstE\",
     \"EqTOrdTSubstD\", \"EqTOrdFSubstD\", \"LeTGeFEqFRel\",
     \"LeFGeTEqTRel\", \"LeTGeTRel\", \"LeFGeFRel\", \"LeqTGetTRel\",
     \"LeqFGetFRel\", \"GeTLeTRel\", \"GeFLeFRel\", \"GeqTLeqTRel\",
     \"GeqFLeqFRel\", \"LeqTGeFRel\", \"LeqFGeTRel\", \"GeTLeFEqFRel\",
     \"GeFLeTEqTRel\", \"GeqTLeFRel\", \"GeqFLeTRel\",
     \"LeqTLeTEqTRel\", \"LeqFLeFEqFRel\", \"GeqTGeTEqTRel\",
     \"GeqFGeFEqFRel\", \"LeTGeqFRel\", \"GeTLeqFRel\", \"LeLeqDiff\",
     \"CmpLTDef\", \"CmpEQDef\", \"CmpGTDef\", \"MaxYDef\", \"MaxXDef\",
     \"MinXDef\", \"MinYDef\", \"MaxSym\", \"MinSym\", \"TO1\", \"TO2\",
     \"TO3\", \"TO4\", \"TO5\", \"TO6\", \"TO7\", \"IUO01\", \"IUO02\",
     \"IUO03\", \"IUO04\", \"IUO05\", \"IUO06\", \"IUO07\", \"IOO13\",
     \"IOO14\", \"IOO15\", \"IOO16\", \"IOO17\", \"IOO18\", \"IOO19\",
     \"IOO20\", \"IOO21\", \"IOO22\", \"IOO23\", \"IOO24\", \"IOO25\",
     \"IOO26\", \"IOO27\", \"IOO28\", \"IOO29\", \"IOO30\", \"IOO31\",
     \"IOO32\", \"IOO33\", \"IBO5\", \"IBO6\", \"IBO7\", \"IBO8\",
     \"IBO9\", \"IBO10\", \"IBO11\", \"IBO12\", \"NotDefHead\",
     \"HeadDef\", \"NotDefTail\", \"TailDef\", \"FoldrNil\",
     \"FoldrCons\", \"FoldlNil\", \"FoldlCons\", \"MapNil\",
     \"MapCons\", \"XPlusXPlusNil\", \"XPlusXPlusCons\", \"FilterNil\",
     \"FilterConsT\", \"FilterConsF\", \"ZipNil\", \"ZipConsNil\",
     \"ZipConsCons\", \"UnzipNil\", \"UnzipCons\", \"ILE01\", \"ILE02\",
     \"ILO01\", \"ILO02\", \"ILO03\", \"ILO04\", \"ILO05\", \"ILO06\",
     \"ILO07\", \"ILO08\", \"ILO09\", \"ILO10\", \"ILO11\", \"ILO12\",
     \"ILO13\", \"ILO14\", \"ILO15\", \"ILO16\", \"ILO17\", \"ILO18\",
     \"ILO19\", \"ILO20\", \"ILO21\", \"ILO22\", \"FoldlDecomp\",
     \"MapDecomp\", \"MapFunctor\", \"FilterProm\", \"InitNil\",
     \"InitConsNil\", \"InitConsCons\", \"LastNil\", \"LastConsNil\",
     \"LastConsCons\", \"NullNil\", \"NullCons\", \"ReverseNil\",
     \"ReverseCons\", \"Foldr1Nil\", \"Foldr1ConsNil\",
     \"Foldr1ConsCons\", \"Foldl1Nil\", \"Foldl1ConsNil\",
     \"Foldl1ConsCons\", \"ScanlNil\", \"ScanlCons\", \"Scanl1Nil\",
     \"Scanl1Cons\", \"ScanrNil\", \"ScanrCons\", \"Scanr1Nil\",
     \"Scanr1ConsNil\", \"Scanr1ConsCons\", \"ScanlProperty\",
     \"ScanrProperty\", \"ConcatDef\", \"ConcatMapDef\", \"MaximunNil\",
     \"MaximumDef\", \"MinimunNil\", \"MinimumDef\", \"TakeWhileNil\",
     \"TakeWhileConsT\", \"TakeWhileConsF\", \"DropWhileNil\",
     \"DropWhileConsT\", \"DropWhileConsF\", \"SpanNil\", \"SpanConsT\",
     \"SpanConsF\", \"BreakDef\", \"SpanThm\", \"BreakThm\"]"

typedecl Bool
typedecl ('a1) DList
typedecl Unit
typedecl X_Nat

datatype Ordering = EQ | GT | LT
datatype 'a List = X_Cons "'a partial" "'a List partial" | X_Nil ("Nil''")

consts
Not__X :: "bool => bool" ("(Not''/ _)" [56] 56)
X__XAmpXAmp__X :: "bool => bool => bool" ("(_/ &&/ _)" [54,54] 52)
X__XEqXEq__X :: "'a partial => 'a partial => bool" ("(_/ ==''/ _)" [54,54] 52)
X__XGtXEq__X :: "'a partial => 'a partial => bool" ("(_/ >=''/ _)" [54,54] 52)
X__XGt__X :: "'a partial => 'a partial => bool" ("(_/ >''/ _)" [54,54] 52)
X__XLtXEq__X :: "'a partial => 'a partial => bool" ("(_/ <=''/ _)" [54,54] 52)
X__XLt__X :: "'a partial => 'a partial => bool" ("(_/ <''/ _)" [54,54] 52)
X__XPlusXPlus__X :: "'a List partial => 'a List partial => 'a List partial" ("(_/ ++''/ _)" [54,54] 52)
X__XSlashXEq__X :: "'a partial => 'a partial => bool" ("(_/ '/=/ _)" [54,54] 52)
X__XVBarXVBar__X :: "bool => bool => bool" ("(_/ ||/ _)" [54,54] 52)
X__o__X :: "('b partial => 'c partial) * ('a partial => 'b partial) => 'a partial => 'c partial"
X_all :: "('a partial => bool) => 'a List partial => bool"
X_andL :: "bool List partial => bool" ("andL/'(_')" [3] 999)
X_any :: "('a partial => bool) => 'a List partial => bool"
X_concat :: "'a List List partial => 'a List partial" ("concat''/'(_')" [3] 999)
X_curry :: "('a partial * 'b partial => 'c partial) => 'a partial => 'b partial => 'c partial"
X_dropWhile :: "('a partial => bool) => 'a List partial => 'a List partial"
X_filter :: "('a partial => bool) => 'a List partial => 'a List partial"
X_flip :: "('a partial => 'b partial => 'c partial) => 'b partial => 'a partial => 'c partial"
X_foldl :: "('a partial => 'b partial => 'a partial) => 'a partial => 'b List partial => 'a partial"
X_foldr :: "('a partial => 'b partial => 'b partial) => 'b partial => 'a List partial => 'b partial"
X_fst :: "'a partial => 'b partial => 'a partial" ("fst''/'(_,/ _')" [3,3] 999)
X_head :: "'a List partial => 'a partial" ("head/'(_')" [3] 999)
X_id :: "'a partial => 'a partial" ("id''/'(_')" [3] 999)
X_init :: "'a List partial => 'a List partial" ("init/'(_')" [3] 999)
X_last :: "'a List partial => 'a partial" ("last''/'(_')" [3] 999)
X_map :: "('a partial => 'b partial) => 'a List partial => 'b List partial"
X_max :: "'a partial => 'a partial => 'a partial"
X_maximum :: "'d List partial => 'd partial" ("maximum/'(_')" [3] 999)
X_min :: "'a partial => 'a partial => 'a partial"
X_minimum :: "'d List partial => 'd partial" ("minimum/'(_')" [3] 999)
X_null :: "'a List partial => bool" ("null''/'(_')" [3] 999)
X_orL :: "bool List partial => bool" ("orL/'(_')" [3] 999)
X_reverse :: "'a List partial => 'a List partial" ("reverse/'(_')" [3] 999)
X_snd :: "'a partial => 'b partial => 'b partial" ("snd''/'(_,/ _')" [3,3] 999)
X_tail :: "'a List partial => 'a List partial" ("tail/'(_')" [3] 999)
X_takeWhile :: "('a partial => bool) => 'a List partial => 'a List partial"
X_unzip :: "('a * 'b) List partial => 'a List partial * 'b List partial" ("unzip/'(_')" [3] 999)
X_zip :: "'a List partial => 'b List partial => ('a * 'b) List partial"
break :: "('a partial => bool) => 'a List partial => 'a List partial * 'a List partial"
compare :: "'a partial => 'a partial => Ordering partial"
concatMap :: "('a partial => 'b List partial) => 'a List partial => 'b List partial"
foldl1 :: "('a partial => 'a partial => 'a partial) => 'a List partial => 'a partial"
foldr1 :: "('a partial => 'a partial => 'a partial) => 'a List partial => 'a partial"
otherwiseH :: "bool"
scanl :: "('a partial => 'b partial => 'a partial) => 'a partial => 'b List partial => 'a List partial"
scanl1 :: "('a partial => 'a partial => 'a partial) => 'a List partial => 'a List partial"
scanr :: "('a partial => 'b partial => 'b partial) => 'b partial => 'a List partial => 'b List partial"
scanr1 :: "('a partial => 'a partial => 'a partial) => 'a List partial => 'a List partial"
span :: "('a partial => bool) => 'a List partial => 'a List partial * 'a List partial"
uncurry :: "('a partial => 'b partial => 'c partial) => 'a partial * 'b partial => 'c partial"

axioms
Comp1 [rule_format] :
"ALL f. ALL g. ALL y. X__o__X (f, g) y = f (g y)"

IdDef [rule_format] : "ALL x. id'(x) = x"

FlipDef [rule_format] : "ALL f. ALL x. ALL y. X_flip f y x = f x y"

FstDef [rule_format] : "ALL x. ALL y. fst'(x, y) = x"

SndDef [rule_format] : "ALL x. ALL y. snd'(x, y) = y"

CurryDef [rule_format] :
"ALL g. ALL x. ALL y. X_curry g x y = g (x, y)"

UncurryDef [rule_format] :
"ALL f. ALL x. ALL y. uncurry f (x, y) = f x y"

NotFalse [rule_format] : "Not' False"

NotTrue [rule_format] : "~ Not' True"

AndFalse [rule_format] : "ALL x. ~ False && x"

AndTrue [rule_format] : "ALL x. True && x = x"

AndSym [rule_format] : "ALL x. ALL y. x && y = y && x"

OrDef [rule_format] :
"ALL x. ALL y. x || y = Not' (Not' x && Not' y)"

OtherwiseDef [rule_format] : "otherwiseH"

NotFalse1 [rule_format] : "ALL x. Not' x = (~ x)"

NotTrue1 [rule_format] : "ALL x. ~ Not' x = x"

notNot1 [rule_format] : "ALL x. (~ x) = Not' x"

notNot2 [rule_format] : "ALL x. (~ ~ x) = (~ Not' x)"

EqualTDef [rule_format] : "ALL x. ALL y. x = y --> x ==' y"

EqualSymDef [rule_format] : "ALL x. ALL y. x ==' y = y ==' x"

EqualReflex [rule_format] : "ALL x. x ==' x"

EqualTransT [rule_format] :
"ALL x. ALL y. ALL z. x ==' y & y ==' z --> x ==' z"

DiffDef [rule_format] : "ALL x. ALL y. x /= y = Not' (x ==' y)"

DiffSymDef [rule_format] : "ALL x. ALL y. x /= y = y /= x"

DiffTDef [rule_format] : "ALL x. ALL y. x /= y = Not' (x ==' y)"

DiffFDef [rule_format] : "ALL x. ALL y. (~ x /= y) = x ==' y"

TE1 [rule_format] : "ALL x. ALL y. ~ x ==' y --> ~ x = y"

TE2 [rule_format] : "ALL x. ALL y. Not' (x ==' y) = (~ x ==' y)"

TE3 [rule_format] : "ALL x. ALL y. (~ Not' (x ==' y)) = x ==' y"

TE4 [rule_format] : "ALL x. ALL y. (~ x ==' y) = (~ x ==' y)"

IUE1 [rule_format] : "makePartial () ==' makePartial ()"

IUE2 [rule_format] : "~ makePartial () /= makePartial ()"

IBE1 [rule_format] : "makePartial () ==' makePartial ()"

IBE2 [rule_format] : "undefinedOp ==' undefinedOp"

IBE3 [rule_format] : "~ undefinedOp ==' makePartial ()"

IBE4 [rule_format] : "~ makePartial () ==' undefinedOp"

IBE5 [rule_format] : "makePartial () /= undefinedOp"

IBE6 [rule_format] : "undefinedOp /= makePartial ()"

IBE7 [rule_format] : "Not' (makePartial () ==' undefinedOp)"

IBE8 [rule_format] : "~ Not' Not' (makePartial () ==' undefinedOp)"

IOE01 [rule_format] : "makePartial LT ==' makePartial LT"

IOE02 [rule_format] : "makePartial EQ ==' makePartial EQ"

IOE03 [rule_format] : "makePartial GT ==' makePartial GT"

IOE04 [rule_format] : "~ makePartial LT ==' makePartial EQ"

IOE05 [rule_format] : "~ makePartial LT ==' makePartial GT"

IOE06 [rule_format] : "~ makePartial EQ ==' makePartial GT"

IOE07 [rule_format] : "makePartial LT /= makePartial EQ"

IOE08 [rule_format] : "makePartial LT /= makePartial GT"

IOE09 [rule_format] : "makePartial EQ /= makePartial GT"

LeIrreflexivity [rule_format] :
"ALL x. ALL y. x ==' y --> ~ x <' y"

LeTAsymmetry [rule_format] : "ALL x. ALL y. x <' y --> ~ y <' x"

LeTTransitive [rule_format] :
"ALL x. ALL y. ALL z. x <' y & y <' z --> x <' z"

LeTTotal [rule_format] :
"ALL x. ALL y. (x <' y | y <' x) | x ==' y"

GeDef [rule_format] : "ALL x. ALL y. x >' y = y <' x"

GeIrreflexivity [rule_format] :
"ALL x. ALL y. x ==' y --> ~ x >' y"

GeTAsymmetry [rule_format] : "ALL x. ALL y. x >' y --> ~ y >' x"

GeTTransitive [rule_format] :
"ALL x. ALL y. ALL z. (x >' y) && (y >' z) --> x >' z"

GeTTotal [rule_format] :
"ALL x. ALL y. ((x >' y) || (y >' x)) || (x ==' y)"

LeqDef [rule_format] :
"ALL x. ALL y. x <=' y = (x <' y) || (x ==' y)"

LeqReflexivity [rule_format] : "ALL x. x <=' x"

LeqTTransitive [rule_format] :
"ALL x. ALL y. ALL z. (x <=' y) && (y <=' z) --> x <=' z"

LeqTTotal [rule_format] :
"ALL x. ALL y. (x <=' y) && (y <=' x) = x ==' y"

GeqDef [rule_format] :
"ALL x. ALL y. x >=' y = (x >' y) || (x ==' y)"

GeqReflexivity [rule_format] : "ALL x. x >=' x"

GeqTTransitive [rule_format] :
"ALL x. ALL y. ALL z. (x >=' y) && (y >=' z) --> x >=' z"

GeqTTotal [rule_format] :
"ALL x. ALL y. (x >=' y) && (y >=' x) = x ==' y"

EqTSOrdRel [rule_format] :
"ALL x. ALL y. x ==' y = (~ x <' y & ~ x >' y)"

EqFSOrdRel [rule_format] :
"ALL x. ALL y. (~ x ==' y) = (x <' y | x >' y)"

EqTOrdRel [rule_format] :
"ALL x. ALL y. x ==' y = (x <=' y & x >=' y)"

EqFOrdRel [rule_format] :
"ALL x. ALL y. (~ x ==' y) = (x <=' y | x >=' y)"

EqTOrdTSubstE [rule_format] :
"ALL x. ALL y. ALL z. x ==' y & y <' z --> x <' z"

EqTOrdFSubstE [rule_format] :
"ALL x. ALL y. ALL z. x ==' y & ~ y <' z --> ~ x <' z"

EqTOrdTSubstD [rule_format] :
"ALL x. ALL y. ALL z. x ==' y & z <' y --> z <' x"

EqTOrdFSubstD [rule_format] :
"ALL x. ALL y. ALL z. x ==' y & ~ z <' y --> ~ z <' x"

LeTGeFEqFRel [rule_format] :
"ALL x. ALL y. x <' y = (~ x >' y & ~ x ==' y)"

LeFGeTEqTRel [rule_format] :
"ALL x. ALL y. (~ x <' y) = (x >' y | x ==' y)"

LeTGeTRel [rule_format] : "ALL x. ALL y. x <' y = y >' x"

LeFGeFRel [rule_format] : "ALL x. ALL y. (~ x <' y) = (~ y >' x)"

LeqTGetTRel [rule_format] : "ALL x. ALL y. x <=' y = y >=' x"

LeqFGetFRel [rule_format] :
"ALL x. ALL y. (~ x <=' y) = (~ y >=' x)"

GeTLeTRel [rule_format] : "ALL x. ALL y. x >' y = y <' x"

GeFLeFRel [rule_format] : "ALL x. ALL y. (~ x >' y) = (~ y <' x)"

GeqTLeqTRel [rule_format] : "ALL x. ALL y. x >=' y = y <=' x"

GeqFLeqFRel [rule_format] :
"ALL x. ALL y. (~ x >=' y) = (~ y <=' x)"

LeqTGeFRel [rule_format] : "ALL x. ALL y. x <=' y = (~ x >' y)"

LeqFGeTRel [rule_format] : "ALL x. ALL y. (~ x <=' y) = x >' y"

GeTLeFEqFRel [rule_format] :
"ALL x. ALL y. x >' y = (~ x <' y & ~ x ==' y)"

GeFLeTEqTRel [rule_format] :
"ALL x. ALL y. (~ x >' y) = (x <' y | x ==' y)"

GeqTLeFRel [rule_format] : "ALL x. ALL y. x >=' y = (~ x <' y)"

GeqFLeTRel [rule_format] : "ALL x. ALL y. (~ x >=' y) = x <' y"

LeqTLeTEqTRel [rule_format] :
"ALL x. ALL y. x <=' y = (x <' y | x ==' y)"

LeqFLeFEqFRel [rule_format] :
"ALL x. ALL y. (~ x <=' y) = (~ x <' y & ~ x ==' y)"

GeqTGeTEqTRel [rule_format] :
"ALL x. ALL y. x >=' y = (x >' y | x ==' y)"

GeqFGeFEqFRel [rule_format] :
"ALL x. ALL y. (~ x >=' y) = (~ x >' y & ~ x ==' y)"

LeTGeqFRel [rule_format] : "ALL x. ALL y. x <' y = (~ x >=' y)"

GeTLeqFRel [rule_format] : "ALL x. ALL y. x >' y = (~ x <=' y)"

LeLeqDiff [rule_format] :
"ALL x. ALL y. x <' y = (x <=' y) && (x /= y)"

CmpLTDef [rule_format] :
"ALL x. ALL y. compare x y ==' makePartial LT = x <' y"

CmpEQDef [rule_format] :
"ALL x. ALL y. compare x y ==' makePartial EQ = x ==' y"

CmpGTDef [rule_format] :
"ALL x. ALL y. compare x y ==' makePartial GT = x >' y"

MaxYDef [rule_format] : "ALL x. ALL y. X_max x y ==' y = x <=' y"

MaxXDef [rule_format] : "ALL x. ALL y. X_max x y ==' x = y <=' x"

MinXDef [rule_format] : "ALL x. ALL y. X_min x y ==' x = x <=' y"

MinYDef [rule_format] : "ALL x. ALL y. X_min x y ==' y = y <=' x"

MaxSym [rule_format] :
"ALL x. ALL y. X_max x y ==' y = X_max y x ==' y"

MinSym [rule_format] :
"ALL x. ALL y. X_min x y ==' y = X_min y x ==' y"

TO1 [rule_format] : "ALL x. ALL y. (x ==' y | x <' y) = x <=' y"

TO2 [rule_format] : "ALL x. ALL y. x ==' y --> ~ x <' y"

TO3 [rule_format] :
"ALL x. ALL y. Not' Not' (x <' y) | Not' (x <' y)"

TO4 [rule_format] : "ALL x. ALL y. x <' y --> Not' (x ==' y)"

TO5 [rule_format] :
"ALL w. ALL x. ALL y. ALL z. (x <' y & y <' z) & z <' w --> x <' w"

TO6 [rule_format] : "ALL x. ALL z. z <' x --> Not' (x <' z)"

TO7 [rule_format] : "ALL x. ALL y. x <' y = y >' x"

IUO01 [rule_format] : "makePartial () <=' makePartial ()"

IUO02 [rule_format] : "~ makePartial () <' makePartial ()"

IUO03 [rule_format] : "makePartial () >=' makePartial ()"

IUO04 [rule_format] : "~ makePartial () >' makePartial ()"

IUO05 [rule_format] :
"X_max (makePartial ()) (makePartial ()) ==' makePartial ()"

IUO06 [rule_format] :
"X_min (makePartial ()) (makePartial ()) ==' makePartial ()"

IUO07 [rule_format] :
"compare (makePartial ()) (makePartial ()) ==' makePartial EQ"

IOO13 [rule_format] : "makePartial LT <' makePartial EQ"

IOO14 [rule_format] : "makePartial EQ <' makePartial GT"

IOO15 [rule_format] : "makePartial LT <' makePartial GT"

IOO16 [rule_format] : "makePartial LT <=' makePartial EQ"

IOO17 [rule_format] : "makePartial EQ <=' makePartial GT"

IOO18 [rule_format] : "makePartial LT <=' makePartial GT"

IOO19 [rule_format] : "makePartial EQ >=' makePartial LT"

IOO20 [rule_format] : "makePartial GT >=' makePartial EQ"

IOO21 [rule_format] : "makePartial GT >=' makePartial LT"

IOO22 [rule_format] : "makePartial EQ >' makePartial LT"

IOO23 [rule_format] : "makePartial GT >' makePartial EQ"

IOO24 [rule_format] : "makePartial GT >' makePartial LT"

IOO25 [rule_format] :
"X_max (makePartial LT) (makePartial EQ) ==' makePartial EQ"

IOO26 [rule_format] :
"X_max (makePartial EQ) (makePartial GT) ==' makePartial GT"

IOO27 [rule_format] :
"X_max (makePartial LT) (makePartial GT) ==' makePartial GT"

IOO28 [rule_format] :
"X_min (makePartial LT) (makePartial EQ) ==' makePartial LT"

IOO29 [rule_format] :
"X_min (makePartial EQ) (makePartial GT) ==' makePartial EQ"

IOO30 [rule_format] :
"X_min (makePartial LT) (makePartial GT) ==' makePartial LT"

IOO31 [rule_format] :
"compare (makePartial LT) (makePartial LT) ==' makePartial EQ"

IOO32 [rule_format] :
"compare (makePartial EQ) (makePartial EQ) ==' makePartial EQ"

IOO33 [rule_format] :
"compare (makePartial GT) (makePartial GT) ==' makePartial EQ"

IBO5 [rule_format] : "undefinedOp <' makePartial ()"

IBO6 [rule_format] : "~ undefinedOp >=' makePartial ()"

IBO7 [rule_format] : "makePartial () >=' undefinedOp"

IBO8 [rule_format] : "~ makePartial () <' undefinedOp"

IBO9 [rule_format] :
"X_max undefinedOp (makePartial ()) ==' makePartial ()"

IBO10 [rule_format] :
"X_min undefinedOp (makePartial ()) ==' undefinedOp"

IBO11 [rule_format] :
"compare (makePartial ()) (makePartial ()) ==' makePartial EQ"

IBO12 [rule_format] :
"compare undefinedOp undefinedOp ==' makePartial EQ"

NotDefHead [rule_format] : "~ defOp (head(makePartial Nil'))"

HeadDef [rule_format] :
"ALL x. ALL xs. head(makePartial (X_Cons x xs)) = x"

NotDefTail [rule_format] : "~ defOp (tail(makePartial Nil'))"

TailDef [rule_format] :
"ALL x. ALL xs. tail(makePartial (X_Cons x xs)) = xs"

FoldrNil [rule_format] :
"ALL f. ALL s. X_foldr f s (makePartial Nil') = s"

FoldrCons [rule_format] :
"ALL f.
 ALL s.
 ALL x.
 ALL xs.
 X_foldr f s (makePartial (X_Cons x xs)) = f x (X_foldr f s xs)"

FoldlNil [rule_format] :
"ALL g. ALL t. X_foldl g t (makePartial Nil') = t"

FoldlCons [rule_format] :
"ALL g.
 ALL t.
 ALL z.
 ALL zs.
 X_foldl g t (makePartial (X_Cons z zs)) = X_foldl g (g t z) zs"

MapNil [rule_format] :
"ALL h. X_map h (makePartial Nil') = makePartial Nil'"

MapCons [rule_format] :
"ALL h.
 ALL x.
 ALL xs.
 X_map h (makePartial (X_Cons x xs)) =
 makePartial (X_Cons (h x) (X_map h xs))"

XPlusXPlusNil [rule_format] : "ALL l. makePartial Nil' ++' l = l"

XPlusXPlusCons [rule_format] :
"ALL l.
 ALL x.
 ALL xs.
 makePartial (X_Cons x xs) ++' l =
 makePartial (X_Cons x (xs ++' l))"

FilterNil [rule_format] :
"ALL p. X_filter p (makePartial Nil') = makePartial Nil'"

FilterConsT [rule_format] :
"ALL p.
 ALL x.
 ALL xs.
 p x -->
 X_filter p (makePartial (X_Cons x xs)) =
 makePartial (X_Cons x (X_filter p xs))"

FilterConsF [rule_format] :
"ALL p.
 ALL x.
 ALL xs.
 ~ p x --> X_filter p (makePartial (X_Cons x xs)) = X_filter p xs"

ZipNil [rule_format] :
"ALL l. X_zip (makePartial Nil') l = makePartial Nil'"

ZipConsNil [rule_format] :
"ALL l.
 ALL x.
 ALL xs.
 l = makePartial Nil' -->
 X_zip (makePartial (X_Cons x xs)) l = makePartial Nil'"

ZipConsCons [rule_format] :
"ALL l.
 ALL x.
 ALL xs.
 ALL y.
 ALL ys.
 l = makePartial (X_Cons y ys) -->
 X_zip (makePartial (X_Cons x xs)) l =
 makePartial
 (X_Cons
  (restrictOp (makePartial (makeTotal x, makeTotal y))
   (defOp x & defOp y))
  (X_zip xs ys))"

UnzipNil [rule_format] :
"mapSnd makeTotal (mapFst makeTotal (unzip(makePartial Nil'))) =
 (Nil', Nil')"

UnzipCons [rule_format] :
"ALL ps.
 ALL x.
 ALL z.
 mapSnd makeTotal
 (mapFst makeTotal
  (unzip(makePartial
         (X_Cons
          (restrictOp (makePartial (makeTotal x, makeTotal z))
           (defOp x & defOp z))
          ps)))) =
 (let (ys, zs) = unzip(ps) in (X_Cons x ys, X_Cons z zs))"

ILE01 [rule_format] : "makePartial Nil' ==' makePartial Nil'"

ILE02 [rule_format] :
"ALL x.
 ALL xs.
 ALL y.
 ALL ys.
 makePartial (X_Cons x xs) ==' makePartial (X_Cons y ys) =
 (x ==' y) && (xs ==' ys)"

ILO01 [rule_format] : "~ makePartial Nil' <' makePartial Nil'"

ILO02 [rule_format] : "makePartial Nil' <=' makePartial Nil'"

ILO03 [rule_format] : "~ makePartial Nil' >' makePartial Nil'"

ILO04 [rule_format] : "makePartial Nil' >=' makePartial Nil'"

ILO05 [rule_format] :
"ALL w.
 ALL ws.
 ALL z.
 ALL zs.
 z <' w --> makePartial (X_Cons z zs) <' makePartial (X_Cons w ws)"

ILO06 [rule_format] :
"ALL w.
 ALL ws.
 ALL z.
 ALL zs.
 z ==' w -->
 makePartial (X_Cons z zs) <' makePartial (X_Cons w ws) = zs <' ws"

ILO07 [rule_format] :
"ALL w.
 ALL ws.
 ALL z.
 ALL zs.
 ~ z <' w & ~ z ==' w -->
 ~ makePartial (X_Cons z zs) <' makePartial (X_Cons w ws)"

ILO08 [rule_format] :
"ALL w.
 ALL ws.
 ALL z.
 ALL zs.
 makePartial (X_Cons z zs) <=' makePartial (X_Cons w ws) =
 (makePartial (X_Cons z zs) <' makePartial (X_Cons w ws)) ||
 (makePartial (X_Cons z zs) ==' makePartial (X_Cons w ws))"

ILO09 [rule_format] :
"ALL w.
 ALL ws.
 ALL z.
 ALL zs.
 makePartial (X_Cons z zs) >' makePartial (X_Cons w ws) =
 makePartial (X_Cons w ws) <' makePartial (X_Cons z zs)"

ILO10 [rule_format] :
"ALL w.
 ALL ws.
 ALL z.
 ALL zs.
 makePartial (X_Cons z zs) >=' makePartial (X_Cons w ws) =
 (makePartial (X_Cons z zs) >' makePartial (X_Cons w ws)) ||
 (makePartial (X_Cons z zs) ==' makePartial (X_Cons w ws))"

ILO11 [rule_format] :
"compare (makePartial Nil') (makePartial Nil') ==' makePartial EQ =
 makePartial Nil' ==' makePartial Nil'"

ILO12 [rule_format] :
"compare (makePartial Nil') (makePartial Nil') ==' makePartial LT =
 makePartial Nil' <' makePartial Nil'"

ILO13 [rule_format] :
"compare (makePartial Nil') (makePartial Nil') ==' makePartial GT =
 makePartial Nil' >' makePartial Nil'"

ILO14 [rule_format] :
"ALL w.
 ALL ws.
 ALL z.
 ALL zs.
 compare (makePartial (X_Cons z zs)) (makePartial (X_Cons w ws)) =='
 makePartial EQ =
 makePartial (X_Cons z zs) ==' makePartial (X_Cons w ws)"

ILO15 [rule_format] :
"ALL w.
 ALL ws.
 ALL z.
 ALL zs.
 compare (makePartial (X_Cons z zs)) (makePartial (X_Cons w ws)) =='
 makePartial LT =
 makePartial (X_Cons z zs) <' makePartial (X_Cons w ws)"

ILO16 [rule_format] :
"ALL w.
 ALL ws.
 ALL z.
 ALL zs.
 compare (makePartial (X_Cons z zs)) (makePartial (X_Cons w ws)) =='
 makePartial GT =
 makePartial (X_Cons z zs) >' makePartial (X_Cons w ws)"

ILO17 [rule_format] :
"X_max (makePartial Nil') (makePartial Nil') ==' makePartial Nil' =
 makePartial Nil' <=' makePartial Nil'"

ILO18 [rule_format] :
"X_min (makePartial Nil') (makePartial Nil') ==' makePartial Nil' =
 makePartial Nil' <=' makePartial Nil'"

ILO19 [rule_format] :
"ALL w.
 ALL ws.
 ALL z.
 ALL zs.
 makePartial (X_Cons z zs) <=' makePartial (X_Cons w ws) =
 X_max (makePartial (X_Cons z zs)) (makePartial (X_Cons w ws)) =='
 makePartial (X_Cons w ws)"

ILO20 [rule_format] :
"ALL w.
 ALL ws.
 ALL z.
 ALL zs.
 makePartial (X_Cons w ws) <=' makePartial (X_Cons z zs) =
 X_max (makePartial (X_Cons z zs)) (makePartial (X_Cons w ws)) =='
 makePartial (X_Cons z zs)"

ILO21 [rule_format] :
"ALL w.
 ALL ws.
 ALL z.
 ALL zs.
 makePartial (X_Cons z zs) <=' makePartial (X_Cons w ws) =
 X_min (makePartial (X_Cons z zs)) (makePartial (X_Cons w ws)) =='
 makePartial (X_Cons z zs)"

ILO22 [rule_format] :
"ALL w.
 ALL ws.
 ALL z.
 ALL zs.
 makePartial (X_Cons w ws) <=' makePartial (X_Cons z zs) =
 X_min (makePartial (X_Cons z zs)) (makePartial (X_Cons w ws)) =='
 makePartial (X_Cons w ws)"

FoldlDecomp [rule_format] :
"ALL e.
 ALL i.
 ALL ts.
 ALL ys. X_foldl i e (ys ++' ts) = X_foldl i (X_foldl i e ys) ts"

MapDecomp [rule_format] :
"ALL f.
 ALL xs. ALL zs. X_map f (xs ++' zs) = X_map f xs ++' X_map f zs"

MapFunctor [rule_format] :
"ALL f.
 ALL g. ALL xs. X_map (X__o__X (g, f)) xs = X_map g (X_map f xs)"

FilterProm [rule_format] :
"ALL f.
 ALL p.
 ALL xs.
 X_filter p (X_map f xs) =
 X_map f (X_filter (id o defOp o X__o__X (bool2partial o p, f)) xs)"

InitNil [rule_format] : "~ defOp (init(makePartial Nil'))"

InitConsNil [rule_format] :
"ALL x.
 init(makePartial (X_Cons x (makePartial Nil'))) = makePartial Nil'"

InitConsCons [rule_format] :
"ALL x.
 ALL xs.
 init(makePartial (X_Cons x xs)) =
 makePartial (X_Cons x (init(xs)))"

LastNil [rule_format] : "~ defOp (last'(makePartial Nil'))"

LastConsNil [rule_format] :
"ALL x. last'(makePartial (X_Cons x (makePartial Nil'))) = x"

LastConsCons [rule_format] :
"ALL x. ALL xs. last'(makePartial (X_Cons x xs)) = last'(xs)"

NullNil [rule_format] : "null'(makePartial Nil')"

NullCons [rule_format] :
"ALL x. ALL xs. ~ null'(makePartial (X_Cons x xs))"

ReverseNil [rule_format] :
"reverse(makePartial Nil') = makePartial Nil'"

ReverseCons [rule_format] :
"ALL x.
 ALL xs.
 reverse(makePartial (X_Cons x xs)) =
 reverse(xs) ++' makePartial (X_Cons x (makePartial Nil'))"

Foldr1Nil [rule_format] :
"ALL f. ~ defOp (foldr1 f (makePartial Nil'))"

Foldr1ConsNil [rule_format] :
"ALL f.
 ALL x. foldr1 f (makePartial (X_Cons x (makePartial Nil'))) = x"

Foldr1ConsCons [rule_format] :
"ALL f.
 ALL x.
 ALL xs. foldr1 f (makePartial (X_Cons x xs)) = f x (foldr1 f xs)"

Foldl1Nil [rule_format] :
"ALL f. ~ defOp (foldl1 f (makePartial Nil'))"

Foldl1ConsNil [rule_format] :
"ALL f.
 ALL x. foldl1 f (makePartial (X_Cons x (makePartial Nil'))) = x"

Foldl1ConsCons [rule_format] :
"ALL f.
 ALL x.
 ALL xs. foldl1 f (makePartial (X_Cons x xs)) = f x (foldr1 f xs)"

ScanlNil [rule_format] :
"ALL g.
 ALL q.
 ALL xs.
 xs = makePartial Nil' -->
 scanl g q xs = makePartial (X_Cons q (makePartial Nil'))"

ScanlCons [rule_format] :
"ALL g.
 ALL q.
 ALL r.
 ALL rs.
 ALL xs.
 xs = makePartial (X_Cons r rs) -->
 scanl g q xs = makePartial (X_Cons q (scanl g (g q r) rs))"

Scanl1Nil [rule_format] :
"ALL f. scanl1 f (makePartial Nil') = makePartial Nil'"

Scanl1Cons [rule_format] :
"ALL f.
 ALL x. ALL xs. scanl1 f (makePartial (X_Cons x xs)) = scanl f x xs"

ScanrNil [rule_format] :
"ALL h.
 ALL q.
 scanr h q (makePartial Nil') =
 makePartial (X_Cons q (makePartial Nil'))"

ScanrCons [rule_format] :
"ALL h.
 ALL q.
 ALL r.
 ALL rs.
 ALL x.
 ALL xs.
 makePartial (X_Cons r rs) = scanr h q xs -->
 scanr h q (makePartial (X_Cons x xs)) =
 makePartial (X_Cons (h x r) (makePartial (X_Cons r rs)))"

Scanr1Nil [rule_format] :
"ALL f. scanr1 f (makePartial Nil') = makePartial Nil'"

Scanr1ConsNil [rule_format] :
"ALL f.
 ALL x.
 scanr1 f (makePartial (X_Cons x (makePartial Nil'))) =
 makePartial (X_Cons x (makePartial Nil'))"

Scanr1ConsCons [rule_format] :
"ALL f.
 ALL q.
 ALL qs.
 ALL x.
 ALL xs.
 makePartial (X_Cons q qs) = scanr1 f xs -->
 scanr1 f (makePartial (X_Cons x xs)) =
 makePartial (X_Cons (f x q) (makePartial (X_Cons q qs)))"

ScanlProperty [rule_format] :
"ALL g. ALL x. ALL xs. last'(scanl g x xs) = X_foldl g x xs"

ScanrProperty [rule_format] :
"ALL h. ALL x. ALL xs. head(scanr h x xs) = X_foldr h x xs"

ConcatDef [rule_format] :
"ALL xxs.
 concat'(xxs) =
 X_foldr (X_curry (uncurryOp X__XPlusXPlus__X)) (makePartial Nil')
 xxs"

ConcatMapDef [rule_format] :
"ALL g. ALL xs. concatMap g xs = concat'(X_map g xs)"

MaximunNil [rule_format] : "~ defOp (maximum(makePartial Nil'))"

MaximumDef [rule_format] : "ALL ds. maximum(ds) = foldl1 X_max ds"

MinimunNil [rule_format] : "~ defOp (minimum(makePartial Nil'))"

MinimumDef [rule_format] : "ALL ds. minimum(ds) = foldl1 X_min ds"

TakeWhileNil [rule_format] :
"ALL p. X_takeWhile p (makePartial Nil') = makePartial Nil'"

TakeWhileConsT [rule_format] :
"ALL p.
 ALL x.
 ALL xs.
 p x -->
 X_takeWhile p (makePartial (X_Cons x xs)) =
 makePartial (X_Cons x (X_takeWhile p xs))"

TakeWhileConsF [rule_format] :
"ALL p.
 ALL x.
 ALL xs.
 ~ p x -->
 X_takeWhile p (makePartial (X_Cons x xs)) = makePartial Nil'"

DropWhileNil [rule_format] :
"ALL p. X_dropWhile p (makePartial Nil') = makePartial Nil'"

DropWhileConsT [rule_format] :
"ALL p.
 ALL x.
 ALL xs.
 p x -->
 X_dropWhile p (makePartial (X_Cons x xs)) = X_dropWhile p xs"

DropWhileConsF [rule_format] :
"ALL p.
 ALL x.
 ALL xs.
 ~ p x -->
 X_dropWhile p (makePartial (X_Cons x xs)) =
 makePartial (X_Cons x xs)"

SpanNil [rule_format] :
"ALL p.
 mapSnd makeTotal (mapFst makeTotal (span p (makePartial Nil'))) =
 (Nil', Nil')"

SpanConsT [rule_format] :
"ALL p.
 ALL x.
 ALL xs.
 p x -->
 mapSnd makeTotal
 (mapFst makeTotal (span p (makePartial (X_Cons x xs)))) =
 mapSnd makeTotal (let (ys, zs) = span p xs in (X_Cons x ys, zs))"

SpanConsF [rule_format] :
"ALL p.
 ALL x.
 ALL xs.
 ~ p x -->
 mapSnd makeTotal
 (mapFst makeTotal (span p (makePartial (X_Cons x xs)))) =
 (let (ys, zs) = span p xs in (Nil', X_Cons x xs))"

BreakDef [rule_format] :
"ALL p.
 ALL xs.
 mapSnd makeTotal (mapFst makeTotal (break p xs)) =
 mapSnd makeTotal
 (mapFst makeTotal
  (let q =
       id o defOp o
       X__o__X (bool2partial o Not__X o defOp, bool2partial o p)
   in span q xs))"

declare Comp1 [simp]
declare IdDef [simp]
declare FlipDef [simp]
declare FstDef [simp]
declare SndDef [simp]
declare CurryDef [simp]
declare UncurryDef [simp]
declare NotFalse [simp]
declare NotTrue [simp]
declare AndFalse [simp]
declare AndTrue [simp]
declare OtherwiseDef [simp]
declare NotTrue1 [simp]
declare EqualReflex [simp]
declare IUE1 [simp]
declare IUE2 [simp]
declare IBE1 [simp]
declare IBE2 [simp]
declare IBE3 [simp]
declare IBE4 [simp]
declare IBE5 [simp]
declare IBE6 [simp]
declare IBE7 [simp]
declare IBE8 [simp]
declare IOE01 [simp]
declare IOE02 [simp]
declare IOE03 [simp]
declare IOE04 [simp]
declare IOE05 [simp]
declare IOE06 [simp]
declare IOE07 [simp]
declare IOE08 [simp]
declare IOE09 [simp]
declare LeIrreflexivity [simp]
declare LeTAsymmetry [simp]
declare GeIrreflexivity [simp]
declare GeTAsymmetry [simp]
declare GeTTransitive [simp]
declare GeTTotal [simp]
declare LeqReflexivity [simp]
declare LeqTTransitive [simp]
declare LeqTTotal [simp]
declare GeqReflexivity [simp]
declare GeqTTransitive [simp]
declare GeqTTotal [simp]
declare CmpLTDef [simp]
declare CmpEQDef [simp]
declare CmpGTDef [simp]
declare MaxYDef [simp]
declare MaxXDef [simp]
declare MinXDef [simp]
declare MinYDef [simp]
declare TO2 [simp]
declare TO4 [simp]
declare TO6 [simp]
declare IUO01 [simp]
declare IUO02 [simp]
declare IUO03 [simp]
declare IUO04 [simp]
declare IUO05 [simp]
declare IUO06 [simp]
declare IUO07 [simp]
declare IOO13 [simp]
declare IOO14 [simp]
declare IOO15 [simp]
declare IOO16 [simp]
declare IOO17 [simp]
declare IOO18 [simp]
declare IOO19 [simp]
declare IOO20 [simp]
declare IOO21 [simp]
declare IOO22 [simp]
declare IOO23 [simp]
declare IOO24 [simp]
declare IOO25 [simp]
declare IOO26 [simp]
declare IOO27 [simp]
declare IOO28 [simp]
declare IOO29 [simp]
declare IOO30 [simp]
declare IOO31 [simp]
declare IOO32 [simp]
declare IOO33 [simp]
declare IBO5 [simp]
declare IBO6 [simp]
declare IBO7 [simp]
declare IBO8 [simp]
declare IBO9 [simp]
declare IBO10 [simp]
declare IBO11 [simp]
declare IBO12 [simp]
declare NotDefHead [simp]
declare HeadDef [simp]
declare NotDefTail [simp]
declare TailDef [simp]
declare FoldrNil [simp]
declare FoldrCons [simp]
declare FoldlNil [simp]
declare FoldlCons [simp]
declare MapNil [simp]
declare XPlusXPlusNil [simp]
declare FilterNil [simp]
declare FilterConsF [simp]
declare ZipNil [simp]
declare UnzipNil [simp]
declare ILE01 [simp]
declare ILE02 [simp]
declare ILO01 [simp]
declare ILO02 [simp]
declare ILO03 [simp]
declare ILO04 [simp]
declare ILO05 [simp]
declare ILO06 [simp]
declare ILO11 [simp]
declare ILO12 [simp]
declare ILO13 [simp]
declare ILO14 [simp]
declare ILO15 [simp]
declare ILO16 [simp]
declare ILO17 [simp]
declare ILO18 [simp]
declare InitNil [simp]
declare InitConsNil [simp]
declare LastNil [simp]
declare LastConsNil [simp]
declare LastConsCons [simp]
declare NullNil [simp]
declare NullCons [simp]
declare ReverseNil [simp]
declare Foldr1Nil [simp]
declare Foldr1ConsNil [simp]
declare Foldr1ConsCons [simp]
declare Foldl1Nil [simp]
declare Foldl1ConsNil [simp]
declare Foldl1ConsCons [simp]
declare Scanl1Nil [simp]
declare Scanl1Cons [simp]
declare Scanr1Nil [simp]
declare Scanr1ConsNil [simp]
declare ScanlProperty [simp]
declare ScanrProperty [simp]
declare MaximunNil [simp]
declare MinimunNil [simp]
declare TakeWhileNil [simp]
declare TakeWhileConsF [simp]
declare DropWhileNil [simp]
declare DropWhileConsT [simp]
declare DropWhileConsF [simp]
declare SpanNil [simp]

theorem SpanThm :
"ALL p.
 ALL xs.
 makePartial (mapSnd makeTotal (mapFst makeTotal (span p xs))) =
 restrictOp
 (makePartial
  (makeTotal (X_takeWhile p xs), makeTotal (X_dropWhile p xs)))
 (defOp (X_takeWhile p xs) & defOp (X_dropWhile p xs))"
apply(auto)
apply(case_tac xs)
apply(auto)
apply(induct_tac List)
apply(case_tac "p a")
apply(simp add: TakeWhileConsF DropWhileConsF SpanConsF)
apply(case_tac "p aa")
apply(simp add: TakeWhileConsT DropWhileConsT SpanConsT TakeWhileConsF DropWhileConsF SpanConsF TakeWhileNil DropWhileNil SpanNil)+
apply(simp only: Let_def)
apply(simp add: split_def)
apply(case_tac "p a")
apply(simp add: TakeWhileConsT DropWhileConsT SpanConsT TakeWhileConsF DropWhileConsF SpanConsF TakeWhileNil DropWhileNil SpanNil)+
done

ML "Header.record \"SpanThm\""

theorem BreakThm :
"ALL p.
 ALL xs.
 mapSnd makeTotal (mapFst makeTotal (break p xs)) =
 mapSnd makeTotal
 (mapFst makeTotal
  (span
   (id o defOp o
    X__o__X (bool2partial o Not__X o defOp, bool2partial o p))
   xs))"
apply(auto)
apply(case_tac xs)
apply(auto)
apply(simp add: BreakDef)
apply(simp add: Let_def)
apply(simp add: BreakDef)
done

ML "Header.record \"BreakThm\""

end


theory UGraph_Impl
imports
 Kruskal_Impl "../../../Kruskal/UGraph" "Imperative_HOL_Time.Asymptotics_2D"
begin

abbreviation "subforest' EE F \<equiv> forest F \<and> F \<subseteq> EE"

definition "spanningforest' EE F \<longleftrightarrow> subforest' EE F \<and> (\<forall>x \<in> EE - F. \<not> subforest' EE (insert x F))"

definition "MST' EE w F \<longleftrightarrow> spanningforest' EE F \<and> (\<forall>F'. spanningforest' EE F' \<longrightarrow> sum w F \<le> sum w F')"

locale uGraph_impl = uGraph E w for E :: "nat uprod set" and w :: "nat uprod \<Rightarrow> int" +
  fixes getEdges_impl :: "(nat \<times> int \<times> nat) list Heap"
    and getEdges_time sort_time :: nat
    and empty_uf_time indep_test_time insert_uf_time :: nat
  assumes getEdges_impl[sepref_fr_rules]:
    "(uncurry0 getEdges_impl,  uncurry0 (PR_CONST (SPECT (emb (\<lambda>L. lst_graph_P' w L E) getEdges_time)))) \<in> unit_assn\<^sup>k \<rightarrow>\<^sub>a list_assn (nat_assn \<times>\<^sub>a int_assn \<times>\<^sub>a nat_assn)"

begin

abbreviation "subforest EE F \<equiv> forest F \<and> F \<subseteq> EE"

sublocale  Kruskal_intermediate_Impl0 E "subforest E" "uconnectedV" "epath" w
    "PR_CONST (SPECT (emb (\<lambda>L. lst_graph_P' w L E) getEdges_time))" getEdges_impl
    getEdges_time sort_time
    empty_uf_time indep_test_time insert_uf_time
proof (unfold_locales, goal_cases)
  fix e
  assume "e\<in>E"
  then show "proper_uprod e" using ecard2 by auto
next
  show "finite E" by simp
next
  fix E'
  assume "forest E' \<and> E' \<subseteq> E"
  then show "E' \<subseteq> E" by auto
next
  show "forest {} \<and> {} \<subseteq> E" apply (auto simp: decycle_def forest_def)
    using epath.elims(2) by fastforce
next
  fix X Y
  assume "forest X \<and> X \<subseteq> E" "Y \<subseteq> X"
  then show "forest Y \<and> Y \<subseteq> E" using forest_mono by auto
next
  fix u v E'
  show " ((u, v) \<in> uconnectedV E') = (\<exists>p. epath E' u p v \<and> u \<in> Kruskal_intermediate_defs.V E \<and> v \<in> Kruskal_intermediate_defs.V E)"
    unfolding uconnected_def Kruskal_intermediate_defs.V_def by auto
next
  case (7 u v)
  then show ?case unfolding uconnected_def Kruskal_intermediate_defs.V_def apply auto
    using epath.elims(2) by force
next
  case (8 E1 u p v E2)
  then have "\<exists>a b. (a, b) \<notin> uconnected E2
           \<and> Upair a b \<notin> E2 \<and> Upair a b \<in> E1" by(rule findaugmenting_edge)
  then show ?case by auto
next
  fix F u v
  assume f: "forest F \<and> F \<subseteq> E" and notin: "Upair u v \<in> E - F"
  from notin ecard2 have unv: "u\<noteq>v" by fastforce
  show "(forest (insert (Upair u v) F) \<and> insert (Upair u v) F \<subseteq> E) = ((u, v) \<notin> uconnectedV F)"
  proof
    assume a: "forest (insert (Upair u v) F) \<and> insert (Upair u v) F \<subseteq> E "
    have "(u, v) \<notin> uconnected F" apply(rule insert_stays_forest_means_not_connected)
      using notin a unv by auto
    then show "((u, v) \<notin> Restr (uconnected F) (UNION E set_uprod))" by auto
  next
    assume a: "(u, v) \<notin> Restr (uconnected F) (UNION E set_uprod)"
    have "forest (insert (Upair u v) F)" apply(rule augment_forest_overedges[where E=E])
      using notin f a unv  by auto
    moreover have "insert (Upair u v) F \<subseteq> E"
      using notin f by auto
    ultimately show "forest (insert (Upair u v) F) \<and> insert (Upair u v) F \<subseteq> E" by auto
  qed
next
  fix F
  assume "F\<subseteq>E"
  show "equiv (Kruskal_intermediate_defs.V E) (uconnectedV F)"
    unfolding  Kruskal_intermediate_defs.V_def by(rule equiv_vert_uconnected)
next
  case (11 F)
  then show ?case unfolding  Kruskal_intermediate_defs.V_def by auto
next
  case (12 x y F)
  then show ?case unfolding  Kruskal_intermediate_defs.V_def by (rule insert_uconnectedV_per)
next
  show "E \<noteq> {}" by simp
  show "PR_CONST (getEdges' w E (enat getEdges_time)) \<le> \<Down> Id (getEdges' w E (enat getEdges_time))" using  PR_CONST_def by simp
  show "(uncurry0 getEdges_impl, uncurry0 (PR_CONST (getEdges' w E (enat getEdges_time)))) \<in> unit_assn\<^sup>k \<rightarrow>\<^sub>a list_assn (nat_assn \<times>\<^sub>a int_assn \<times>\<^sub>a nat_assn)"
    using getEdges_impl by simp
qed

lemma minBasis_is_MST': "minBasis = MST' E w"
  unfolding minBasis_def MST'_def
   basis_def  spanningforest'_def by simp

end

locale uGraph_impl2 = uGraph_impl + UnionFind_Impl + sortMaxnode +
  assumes
  [simp]:  "uf_init_time (Suc (Max V)) \<le> empty_uf_time"
    "uf_cmp_time (Suc (Max V)) \<le> indep_test_time"
    "uf_union_time (Suc (Max V)) \<le> insert_uf_time"
    "sort_time' (card E) \<le> sort_time"
begin

sublocale s: Kruskal_intermediate_Impl E "subforest E" "uconnectedV" "epath" w "PR_CONST getEdges" getEdges_impl
  getEdges_time sort_time empty_uf_time indep_test_time insert_uf_time is_uf
     uf_init uf_init_time uf_cmp uf_cmp_time uf_union uf_union_time sortEdges_impl sort_time'
  apply (unfold_locales)
        apply simp apply simp
  subgoal  using getEdges_impl PR_CONST_def by auto
     apply simp_all
  done

term MST

lemmas kurskal_horetriple =  s.kruskal_correct_forest
thm s.kruskal_ref_spec
abbreviation "kruskal \<equiv> s.kruskal"

end

thm uGraph_impl2.kurskal_horetriple
thm uGraph_impl2_def
(*
definition getEdges_time :: "nat \<Rightarrow>  nat" where "getEdges_time = undefined"
definition sort_time' :: "nat \<Rightarrow>  nat" where "sort_time' = undefined"
definition uf_init_time :: "nat \<Rightarrow>  nat" where "uf_init_time = undefined"
definition uf_cmp_time :: "nat \<Rightarrow>  nat" where "uf_cmp_time = undefined"
definition uf_union_time :: "nat \<Rightarrow>  nat" where "uf_union_time = undefined"
lemma [asym_bound]: "getEdges_time \<in> \<Theta>(\<lambda>n::nat. n)" sorry
  lemma [asym_bound]: "sort_time' \<in> \<Theta>(\<lambda>n::nat. n * ln n)" sorry
  lemma [asym_bound]: "uf_init_time \<in> \<Theta>(\<lambda>n::nat. 1)" sorry
  lemma [asym_bound]: "uf_cmp_time \<in> \<Theta>(\<lambda>n::nat. 1)" sorry
  lemma [asym_bound]: "uf_union_time \<in> \<Theta>(\<lambda>n::nat. ln n)" sorry

fun kruskal_time :: "nat * nat \<Rightarrow> nat" where "kruskal_time (sE, mV) =
      (getEdges_time sE + sort_time' sE + (12 + uf_init_time mV) +
      sE * (uf_cmp_time mV + (23 + uf_union_time mV)))"

term "\<Theta>\<^sub>2(\<lambda>(e::nat,m::nat). e * ln e + e * ln m + e )"

lemma "kruskal_time \<in> \<Theta>\<^sub>2(\<lambda>(e::nat,m::nat). e * ln e + e * ln m  )"
  apply (subst surjective_pairing)
  unfolding kruskal_time.simps
  by auto2

locale krtime = fixes
  getEdges_time :: "nat \<Rightarrow>  nat"
 and sort_time' :: "nat \<Rightarrow>  nat"
and uf_init_time :: "nat \<Rightarrow>  nat"
and uf_cmp_time :: "nat \<Rightarrow>  nat"
and uf_union_time :: "nat \<Rightarrow>  nat"
assumes [asym_bound]: "getEdges_time \<in> \<Theta>(\<lambda>n::nat. n)"
  and [asym_bound]: "sort_time' \<in> \<Theta>(\<lambda>n::nat. n * ln n)"
  and [asym_bound]: "uf_init_time \<in> \<Theta>(\<lambda>n::nat. 1)"
  and [asym_bound]: "uf_cmp_time \<in> \<Theta>(\<lambda>n::nat. 1)"
  and [asym_bound]: "uf_union_time \<in> \<Theta>(\<lambda>n::nat. ln n)"
begin

fun kruskal_time :: "nat * nat \<Rightarrow> nat" where "kruskal_time (sE, mV) =
      (getEdges_time sE + sort_time' sE + (12 + uf_init_time mV) +
      sE * (uf_cmp_time mV + (23 + uf_union_time mV)))"

lemma "kruskal_time \<in> \<Theta>\<^sub>2(\<lambda>(e::nat,m::nat). e * ln e + e * ln m  )"
  apply (subst surjective_pairing)
  unfolding kruskal_time.simps
  by auto2

end
*)

locale stuffdone = UnionFind_Impl + sortMaxnode
  + fixes "getEdges_time" :: "nat \<Rightarrow> nat"
  assumes
      [asym_bound]: "getEdges_time \<in> \<Theta>(\<lambda>n::nat. n)"
  and [asym_bound]: "sort_time' \<in> \<Theta>(\<lambda>n::nat. n * ln n)"
  and [asym_bound]: "uf_init_time \<in> \<Theta>(\<lambda>n::nat. 1)"
  and [asym_bound]: "uf_cmp_time \<in> \<Theta>(\<lambda>n::nat. 1)"
  and [asym_bound]: "uf_union_time \<in> \<Theta>(\<lambda>n::nat. ln n)"
begin

fun kruskal_time :: "nat * nat \<Rightarrow> nat" where "kruskal_time (sE, mV) =
      (getEdges_time sE + sort_time' sE + (12 + uf_init_time mV) +
      sE * (uf_cmp_time mV + (23 + uf_union_time mV)))"

term "\<Theta>\<^sub>2(\<lambda>(e::nat,m::nat). e * ln e + e * ln m + e )"

lemma "kruskal_time \<in> \<Theta>\<^sub>2(\<lambda>(e::nat,m::nat). e * ln e + e * ln m   )"
  apply (subst surjective_pairing)
  unfolding kruskal_time.simps
  apply (auto2) sorry

lemma
  assumes [simp]: "\<And>e. e \<in> E \<Longrightarrow> proper_uprod e" "finite E" "E \<noteq> {}"
      and getEdges_impl:
    "(uncurry0 getEdges_impl,  uncurry0 (PR_CONST (SPECT (emb (\<lambda>L. lst_graph_P' w L E) (enat (getEdges_time (card E))))))) \<in> unit_assn\<^sup>k \<rightarrow>\<^sub>a list_assn (nat_assn \<times>\<^sub>a int_assn \<times>\<^sub>a nat_assn)"

  shows "<$ (kruskal_time (card E,Suc (Max (uGraph.verts E))) )>
             uGraph_impl2.kruskal getEdges_impl uf_init uf_cmp uf_union sortEdges_impl
         <\<lambda>r. \<exists>\<^sub>Ara. hr_comp (da_assn id_assn) (lst_graph_rel' w) ra r * \<up> ( MST' E w ra)>\<^sub>t"
proof -

  interpret uGraph_impl2 E w  getEdges_impl
      "getEdges_time (card E)" "sort_time' (card E)"   "uf_init_time (Suc (Max (uGraph.verts E)))"
        "uf_cmp_time (Suc (Max (uGraph.verts E)))" "uf_union_time (Suc (Max (uGraph.verts E)))"
  is_uf   uf_init  uf_init_time uf_cmp  uf_cmp_time  uf_union  uf_union_time  sortEdges_impl  sort_time'
    apply unfold_locales
       apply (simp_all add: Kruskal_intermediate_defs.V_def)
    using getEdges_impl
    by auto

  from kurskal_horetriple show ?thesis
    unfolding minBasis_time_def minBasis_is_MST' kruskal_time.simps .
qed

end

end