(*<*)
theory T2NotacionUniformeIngles
imports Main T1SintaxisSemanticaIngles

begin
(*>*)

section \<open> Notación uniforme \<close>

text \<open>
  En el texto de Fitting \cite{Fitting} se considera la noción de @{text
  "notación uniforme"}, introducida por R. M. Smullyan \cite{Smullyan},
  que permite clasificar las fórmulas de tal forma que algunos teoremas
  de la lógica de primer orden y, como consecuencia, algunos
  procedimientos utilizados en la prueba automática de teoremas, pueden
  describirse de manera mucho más simple. En esta sección formalizamos
  este concepto dividiendo las fórmulas proposicionales en cuatro tipos
  de fórmulas: {\em literales} (\ref{literal}), {\em dobles negationes}
  (\ref{NoNO}), {\em fórmulas alfa} (\ref{alfa}) y {\em fórmulas beta}
  (\ref{beta}); y definiendo el tipo {\em tipoNotaciónUniforme}
  (\ref{tipoformula}) con estos cuatro t_v_evaluationes.  Los si\-guientes lemas
  y funciones caracterizan esta clasificación.

  \begin{definicion}\label{literal}
  Una fórmula es un \textbf{literal} si es un símbolo proposicional, la
  negación de un símbolo proposicional, $\bot$, $\top$, $\neg \bot$ o
  $\neg \top$.
  \end{definicion}

  \noindent Su formalización es:
\<close>

fun FormulaLiteral :: "'b formula \<Rightarrow> bool" where
  "FormulaLiteral FF = True"
| "FormulaLiteral (\<not>. FF) = True"
| "FormulaLiteral TT = True"
| "FormulaLiteral (\<not>. TT) = True"
| "FormulaLiteral (atom P) = True"
| "FormulaLiteral (\<not>.(atom P)) = True"
| "FormulaLiteral F = False"

text \<open>
  \begin{definicion}\label{NoNO}
  Una \textbf{doble negación} es una fórmula de la forma @{text "\<not>\<not> F"}, donde
  @{text F} es una fórmula proposicional.
  \end{definicion}

  \noindent Su formalización es:
\<close>

fun FormulaNoNo :: "'b formula \<Rightarrow> bool" where
  "FormulaNoNo (\<not>. (\<not>. F)) = True"
| "FormulaNoNo F = False"

text\<open>
  \begin{definicion}\label{alfa}
  Una \textbf{fórmula alfa} es una fórmula de la forma $F \wedge G$,
  $\neg(F \vee G)$, o  $\neg(F \rightarrow G)$, donde $F$ y $G$ son
  fórmulas proposicionales.
  \end{definicion}

  \noindent Su formalización es:
\<close>

fun FormulaAlfa :: "'b formula \<Rightarrow> bool" where
  "FormulaAlfa (F \<and>. G) = True"
| "FormulaAlfa (\<not>. (F \<or>. G)) = True"
| "FormulaAlfa (\<not>. (F \<rightarrow>. G)) =  True"
| "FormulaAlfa F = False"

text \<open>
  \begin{definicion}\label{beta}
  Una \textbf{fórmula beta} es una fórmula de la forma
  @{text "F \<or> G, \<not>(F \<and> G), o F \<rightarrow> G"}, donde @{text F} y @{text G} son
  fórmulas proposicionales.
  \end{definicion}

  \noindent Su formalización es:
\<close>

fun FormulaBeta :: "'b formula \<Rightarrow> bool" where
  "FormulaBeta (F \<or>. G) = True"
| "FormulaBeta (\<not>. (F \<and>. G)) = True"
| "FormulaBeta (F \<rightarrow>. G) =  True"
| "FormulaBeta F = False"

(*<*)
text \<open>
  \begin{lema}
  Si @{text F} es un literal, entonces existe un @{text n} tal que @{text F} es
  igual a @{text "p\<^sub>n"} o @{text "\<not>p\<^bsub>n\<^esub>"}.
  \end{lema}
\<close>

lemma Literal:
  assumes "FormulaLiteral F"
  shows "F = FF \<or> F = TT \<or> F = (\<not>. FF) \<or> F = (\<not>. TT) \<or> (\<exists>n. F = (atom n) \<or> F = (\<not>. (atom n)))"
using assms
by (induct F rule: FormulaLiteral.induct, auto)

text \<open>
  \begin{lema}
  Si @{text F} es una doble negación, entonces existe una @{text G} tal que
  @{text F} es @{text "\<not>\<not> G"}.
  \end{lema}
\<close>

lemma NoNo:
  assumes "FormulaNoNo F"
  shows "\<exists>G. F = (\<not>. (\<not>. G))"
using assms
by (induct F rule: FormulaNoNo.induct, auto)

text \<open>
  \begin{lema}
  Si @{text F} es una fórmula alfa, entonces existen @{text G} y @{text H}
  tales que @{text F} es de una de las siguientes formas
  @{text "G \<and> H,  \<not>(G \<or> H),  \<not>(G \<rightarrow> H)"}.
  \end{lema}
\<close>

lemma Alfa:
  assumes "FormulaAlfa F"
  shows "\<exists>G H.  F = (G \<and>. H) \<or> F = (\<not>. (G \<or>. H)) \<or> F = (\<not>. (G \<rightarrow>. H))"
using assms
by (induct F rule: FormulaAlfa.induct, auto)

text \<open>
  \begin{lema}
  Si @{text F} es una fórmula beta, entonces existen @{text G} y @{text H}
  tales que @{text F} es de una de las siguientes formas
  @{text "G \<or> H, \<not>(G \<and> H), G \<rightarrow> H"}.
  \end{lema}
\<close>

lemma Beta:
  assumes "FormulaBeta F"
  shows "\<exists>G H. F = (G \<or>. H) \<or> F = (\<not>. (G \<and>. H)) \<or> F = (G \<rightarrow>. H)"
using assms
by (induct F rule: FormulaBeta.induct, auto)

(*>*)
text \<open>
  Los siguientes lemas garantizan que cada fórmula proposicional
  pertenence exactamente a una de las cuatro categorías anteriores.

  \begin{lema}
  Los literales no son dobles negationes.
  \end{lema}

  \noindent Su formalización es:
\<close>

lemma noLiteralNoNo:
  assumes "FormulaLiteral formula"
  shows "\<not>(FormulaNoNo formula)"
using assms Literal NoNo
by (induct formula rule: FormulaLiteral.induct, auto)

text \<open>
  \begin{lema}
  Los literales no son fórmulas alfa.
  \end{lema}

  \noindent Su formalización es:
\<close>

lemma noLiteralAlfa:
  assumes "FormulaLiteral formula"
  shows "\<not>(FormulaAlfa formula)"
using assms Literal Alfa
by (induct formula rule: FormulaLiteral.induct, auto)

text \<open>
  \begin{lema}
  Los literales no son fórmulas beta.
  \end{lema}

  \noindent Su formalización es:
\<close>

lemma noLiteralBeta:
  assumes "FormulaLiteral formula"
  shows "\<not>(FormulaBeta formula)"
using assms Literal Beta
by (induct formula rule: FormulaLiteral.induct, auto)

text \<open>
  \begin{lema}
  Los fórmulas alfa no son dobles negationes.
  \end{lema}

  \noindent Su formalización es:
\<close>

lemma noAlfaNoNo:
  assumes "FormulaAlfa formula"
  shows "\<not>(FormulaNoNo formula)"
using assms Alfa NoNo
by (induct formula rule: FormulaAlfa.induct, auto)

text \<open>
  \begin{lema}
  Los fórmulas beta no son dobles negationes.
  \end{lema}

  \noindent Su formalización es:
\<close>

lemma noBetaNoNo:
  assumes "FormulaBeta formula"
  shows "\<not>(FormulaNoNo formula)"
using assms Beta NoNo
by (induct formula rule: FormulaBeta.induct, auto)

text \<open>
  \begin{lema}
  Los fórmulas alfa no son fórmulas betas.
  \end{lema}

  \noindent Su formalización es:
\<close>

lemma noAlfaBeta:
  assumes "FormulaAlfa formula"
  shows "\<not>(FormulaBeta formula)"
using assms Alfa Beta
by (induct formula rule: FormulaAlfa.induct, auto)

text \<open>
  \begin{lema}
  Toda fórmula es de una de las clases literal, doble negación, alfa o
  beta.
  \end{lema}

  \noindent Su formalización es:
\<close>

lemma NotacionUniforme:
 "FormulaLiteral F \<or> FormulaNoNo F \<or> FormulaAlfa F \<or> FormulaBeta F"
(*<*)
by (induct F rule: FormulaLiteral.induct,
    induct F rule: FormulaNoNo.induct,
    induct F rule: FormulaAlfa.induct,
    induct F rule: FormulaBeta.induct,
    induct F,
    auto)
(*>*)

text \<open>
  \begin{definicion}\label{tipoformula}
  Los tipos de fórmulas son literal, alfa, beta y doble negación.
  \end{definicion}

  \noindent Su formalización es:
\<close>

datatype tipoNotacionUniforme = Literal | NoNo | Alfa| Beta

text \<open>
  \begin{definicion}
  El tipo de una fórmula @{text F} es la clase del tipo de @{text F}.
  \end{definicion}

  \noindent Su formalización es:
\<close>

fun tipoFormula :: "'b formula \<Rightarrow> tipoNotacionUniforme" where
"tipoFormula F =
  (if FormulaBeta F then Beta
   else if FormulaNoNo F then NoNo
   else if FormulaAlfa F then Alfa
   else Literal)"

(*<*)
text \<open>
  \begin{lema}
  Si el tipo de la fórmula @{text F} es literal, entonces @{text F} es un
  literal.
  \end{lema}

\noindent Su formalización es:
\<close>

lemma tipoLiteral:
  assumes "tipoFormula F = Literal"
  shows "FormulaLiteral F"
(*<*)
by (metis NotacionUniforme
          assms
          tipoNotacionUniforme.distinct
          tipoFormula.simps)
(*>*)

text \<open>
  \begin{lema}
  Si el tipo de la fórmula @{text F} es alfa, entonces @{text F} es una
  fórmula alfa.
  \end{lema}

  \noindent Su formalización es:
\<close>

lemma tipoAlfa:
  assumes "tipoFormula F = Alfa"
  shows "FormulaAlfa F"
(*<*)
by (metis NotacionUniforme
          assms
          tipoNotacionUniforme.distinct
          tipoFormula.simps)
(*>*)

text \<open>
  \begin{lema}
  Si el tipo de la fórmula @{text F} es beta, entonces @{text F} es una
  fórmula beta.
  \end{lema}
\<close>

lemma tipoBeta:
  assumes "tipoFormula F = Beta"
  shows "FormulaBeta F"
(*<*)
by (metis NotacionUniforme
          assms
          tipoNotacionUniforme.distinct
          tipoFormula.simps)
(*>*)

text \<open>
  \begin{lema}
  Si el tipo de la fórmula @{text F} es NoNo, entonces @{text F} es una
  doble negación.
  \end{lema}
\<close>

lemma tipoNoNo:
  assumes "tipoFormula F = NoNo"
  shows "FormulaNoNo F"
(*<*)
by (metis NotacionUniforme
          assms
          tipoNotacionUniforme.distinct
          tipoFormula.simps)
(*>*)

text\<open>
  \begin{nota}
  Otra forma de demostrar el lema @{text "NotacionUniforme"} es la
  siguiente:
  \end{nota}
\<close>

lemma NotacionUniforme1:
  "FormulaLiteral F \<or> FormulaNoNo F \<or> FormulaAlfa F \<or> FormulaBeta F"
using tipoLiteral tipoNoNo tipoAlfa tipoBeta tipoNotacionUniforme.exhaust
by blast
(*>*)

text \<open>
  \begin{definicion}
  El conjunto de las componentes de la fórmula @{text F} es
  \begin{itemize}
  \item @{text "{G}"} si @{text F} es @{text "\<not>\<not>G"}
  \item @{text "{G, H}"} si @{text F} es @{text "G \<and> H"}
  \item @{text "{\<not>G, \<not>H}"} si @{text F} es @{text "\<not>(G \<or> H)"}
  \item @{text "{G, \<not>H}"} si @{text F} es @{text "\<not>(G \<rightarrow> H)"}
  \item @{text "{G, H}"} si @{text F} es @{text "G \<or> H"}
  \item @{text "{\<not>G, \<not>H}"} si @{text F} es @{text "\<not>(G \<and> H)"}
  \item @{text "{\<not>G, H}"} si @{text F} es @{text "G \<rightarrow> H"}
  \end{itemize}
  \end{definicion}

  \noindent Su formalización es:
\<close>

fun componentes  :: "'b formula \<Rightarrow> 'b formula list" where
  "componentes (\<not>. (\<not>. G)) = [G]"
| "componentes (G \<and>. H) = [G, H]"
| "componentes (\<not>. (G \<or>. H)) = [\<not>. G, \<not>. H]"
| "componentes (\<not>. (G \<rightarrow>. H)) = [G, \<not>. H]"
| "componentes (G \<or>. H) = [G, H]"
| "componentes (\<not>. (G \<and>. H)) = [\<not>. G, \<not>. H]"
| "componentes (G \<rightarrow>. H) = [\<not>.G,  H]"

text \<open>
  Para acceder a las componentes de una fórmula definimos las funciones
  $Comp_1$ y $Comp_2$.

  \begin{definicion}
   La primera componente de la fórmula @{text F} es $Comp_1(F)$.
  \end{definicion}

  \noindent Su formalización es:
\<close>

definition Comp1 :: "'b formula \<Rightarrow> 'b formula" where
  "Comp1 F = hd (componentes F)"

text \<open>
  \begin{definicion}
  La segunda componente de la fórmula @{text F} es $Comp_2(F)$.
  \end{definicion}

  \noindent Su formalización es:
\<close>

definition Comp2 :: "'b formula \<Rightarrow> 'b formula" where
  "Comp2 F =  hd (tl (componentes F))"

text \<open>
 \begin{nota}
  Las componentes de una fórmula de tipo alfa se denotan
  @{text "\<alpha>\<^bsub>1\<^esub>"} y @{text "\<alpha>\<^bsub>2\<^esub>"} respectivamente; de la misma forma,
  las componentes de una fórmula de tipo beta se denotan
  @{text "\<beta>\<^bsub>1\<^esub>"} y  @{text "\<beta>\<^bsub>2\<^esub>"} respectivamente.
 \end{nota}
\<close>

section \<open> Disyunciones y conjunctiones generalizadas \<close>

text \<open>
  Para facilitar el desarrollo de las formas normales, introducimos las
  disjunctiones y conjunctiones generalizadas.

  \begin{definicion}
   La \textbf{disyunción generalizada} de las fórmulas $X_1, X_2,\dots, X_n$ es
  $X_1\vee X_2 \vee \cdots \vee X_n$ y se representa por
  $[X_1,\, X_2,\dots , X_n]$.
  \end{definicion}

  En Isabelle representaremos una disyunción generalizada por medio de
  una lista de fórmulas: @{text "'b formula list"}.

  \begin{definicion}
  La \textbf{conjunción generalizada} de las fórmulas
  $X_1, X_2, \dots, X_n$ es $X_1\wedge X_2 \wedge \cdots \wedge X_n$  y
  se representa por $\langle X_1,\, X_2,\dots , X_n\rangle$.
  \end{definicion}

  En el estudio que sigue estamos interesados en considerar únicamente
  conjunctiones generalizadas de disjunctiones generalizadas.

  En Isabelle representaremos una conjunción generali\-zada de
  disjunctiones gene\-ralizadas por medio de una lista de elementos del
  tipo disyunción generalizada: @{text "('b formula list) list"}.
\<close>

subsection \<open> Semántica de las disjunctiones y conjunctiones generalizadas \<close>

text\<open>
  En esta sección extendemos la semántica para incluir las disjunctiones
  y conjunctiones generalizadas.

  \begin{definicion}
  El \textbf{t_v_evaluation} de una disyunción generalizada $[X_1,\, X_2,\dots , X_n]$
  en una interpretación @{text I} se define como sigue:

  $I'[X_1,\, X_2, \dots , X_n] = \begin{cases}
                                  \V, & \text{si $I'(X_i)=\V$ para algún $i$}\\
                                  \F, & \text{en caso contrario.}
                                 \end{cases}$
  \end{definicion}

  \noindent Su formalización es:
\<close>

primrec t_v_evaluationDisyuncionG :: "('b \<Rightarrow> v_truth) \<Rightarrow> ('b formula list) \<Rightarrow> v_truth" where
  "t_v_evaluationDisyuncionG I [] = Ffalse"
| "t_v_evaluationDisyuncionG I (F#Fs) = (if t_v_evaluation I F = Ttrue then Ttrue else t_v_evaluationDisyuncionG I Fs)"

text \<open>
  \begin{definicion}
  El \textbf{t_v_evaluation} de una conjunción generalizada de disjunctiones
  generalizadas $\langle D_1,$ \linebreak
  $D_2, \dots , D_n\rangle$, en una
  interpretación $I$, se define como sigue:

    $I'\langle D_1,\, D_2, \dots , D_n\rangle =
      \begin{cases}
        \V, & \text{si $I'(D_i)=\V$ para todo $i$}\\
        \F, & \text{en caso contrario.}
      \end{cases}$
  \end{definicion}

  \noindent Su formalización es:
\<close>

primrec t_v_evaluationConjuncionG :: "('b \<Rightarrow> v_truth) \<Rightarrow> ('b formula list) list \<Rightarrow> v_truth" where
  "t_v_evaluationConjuncionG I [] = Ttrue"
| "t_v_evaluationConjuncionG I (D#Ds) =
     (if t_v_evaluationDisyuncionG I D = Ffalse then Ffalse else t_v_evaluationConjuncionG I Ds)"

text \<open>
  Concluimos esta sección definiendo el concepto de equivalencia ente
  conjunctiones generalizadas y probando las equivalencias entre las
  fórmulas y conjunctiones obtenidas a partir de sus componentes.

  \begin{definicion}
  Las conjunctiones generalizadas $C_1$ y $C_2$ son \textbf{equivalentes}
  si para toda interpretación @{text I} el t_v_evaluation de $C_1$ en $I$ es
  igual al t_v_evaluation de $C_2$ en $I$, y se representa por $C_1\equiv C_2$.
  \end{definicion}

  \noindent Su formalización es:
\<close>
definition equivalentesG :: "('b formula list) list  \<Rightarrow> ('b formula list) list \<Rightarrow> bool" where
 "equivalentesG C1 C2 \<equiv> (\<forall>I. ((t_v_evaluationConjuncionG I C1) = (t_v_evaluationConjuncionG I C2)))"

text \<open>   Se tienen las siguientes equivalencias con relación a las fórmulas
  alfa, beta y dobles negationes, y sus respectivas componentes.
\<close>
(*<*)
lemma EquiNoNoa: "equivalentesG [[\<not>. \<not>. F]] [[F]]"
proof (unfold equivalentesG_def)
  show "\<forall>I. t_v_evaluationConjuncionG I [[\<not>. \<not>. F]] = t_v_evaluationConjuncionG I [[F]]"
  proof
    fix I
    show  "t_v_evaluationConjuncionG I [[\<not>. \<not>. F]] = t_v_evaluationConjuncionG I [[F]]"
    proof (cases "t_v_evaluation I F")
      text  \<open> Caso 1:  \<close>
      { assume 1:"t_v_evaluation I F = Ttrue"
        thus ?thesis by (simp add: v_negation_def) }
    next
       text  \<open> Caso 2:  \<close>
      { assume "t_v_evaluation I F = Ffalse"
        thus ?thesis by (simp add: v_negation_def) }
    qed
  qed
qed
(*>*)

text \<open>
  \begin{lema}
  Si $F$ es una doble negación y $G$ es su componente, entonces
  $\langle[F]\rangle \equiv \langle[G]\rangle$.
\end{lema}

\noindent Su formalizacion es
\<close>

lemma EquiNoNo:
  assumes "tipoFormula F = NoNo"
  shows "equivalentesG [[F]] [[Comp1 F]]"
(*<*)
proof -
  have 1: "\<exists>G. F = \<not>. \<not>. G" using assms tipoNoNo NoNo by auto
  obtain G where "F = \<not>. \<not>. G" using 1 by auto
  moreover
  hence "Comp1 F = G" by(simp add: Comp1_def)
  ultimately
  have "equivalentesG [[F]] [[Comp1 F]] = equivalentesG [[\<not>. \<not>. G]] [[G]]"
    by simp
  thus ?thesis using EquiNoNoa by simp
qed
(*>*)

(*<*)
lemma EquiAlfaa: "equivalentesG [[G \<and>. H]] [[G],[H]]"
proof (unfold equivalentesG_def)
  show "\<forall>I. t_v_evaluationConjuncionG I [[G \<and>. H]] = t_v_evaluationConjuncionG I [[G], [H]]"
  proof
    fix I
    show  "t_v_evaluationConjuncionG I [[G \<and>. H]] = t_v_evaluationConjuncionG I [[G], [H]]"
    proof (cases "t_v_evaluation I G")
            text  \<open> Caso 1:  \<close>
      { assume 1:"t_v_evaluation I G = Ttrue"
        thus ?thesis
        proof(cases "t_v_evaluation I H")
          assume  "t_v_evaluation I H = Ttrue"
          thus ?thesis using 1  by (simp add: v_conjunction_def)
        next
          assume  "t_v_evaluation I H = Ffalse"
          thus ?thesis using 1  by (simp add: v_conjunction_def)
        qed }
    next
       text  \<open> Caso 2:  \<close>
      { assume "t_v_evaluation I G = Ffalse"
        thus ?thesis by (simp add: v_conjunction_def) }
    qed
  qed
qed

lemma EquiAlfab: "equivalentesG [[\<not>. (G \<or>. H)]] [[\<not>. G],[\<not>. H]]"
proof (unfold equivalentesG_def)
  show "\<forall>I. t_v_evaluationConjuncionG I [[\<not>. (G \<or>. H)]] =
            t_v_evaluationConjuncionG I [[\<not>. G], [\<not>. H]]"
  proof
    fix I
    show "t_v_evaluationConjuncionG I [[\<not>. (G \<or>. H)]] =
          t_v_evaluationConjuncionG I [[\<not>. G], [\<not>. H]]"
    proof (cases "t_v_evaluation I G")
           text  \<open> Caso 1:  \<close>
      { assume 1:"t_v_evaluation I G = Ttrue"
        thus ?thesis
        proof (cases "t_v_evaluation I H")
          assume  "t_v_evaluation I H = Ttrue"
          thus ?thesis using 1
            by (simp add: v_negation_def, simp add: v_disjunction_def)
        next
          assume  "t_v_evaluation I H = Ffalse"
          thus ?thesis using 1
            by (simp add: v_negation_def, simp add: v_disjunction_def)
        qed }
    next
        text  \<open> Caso 2:  \<close>
      { assume "t_v_evaluation I G = Ffalse"
        thus ?thesis
          by (simp add: v_negation_def, simp add: v_disjunction_def) }
    qed
  qed
qed

lemma EquiAlfac: "equivalentesG [[\<not>. (G \<rightarrow>. H)]] [[G],[\<not>. H]]"
proof (unfold equivalentesG_def)
  show "\<forall>I. t_v_evaluationConjuncionG I [[\<not>. (G \<rightarrow>. H)]] =
            t_v_evaluationConjuncionG I [[G], [\<not>. H]]"
  proof
    fix I
    show  "t_v_evaluationConjuncionG I [[\<not>. (G \<rightarrow>. H)]] =
           t_v_evaluationConjuncionG I [[G], [\<not>. H]]"
    proof (cases "t_v_evaluation I G")
               text  \<open> Caso 1:  \<close>
      { assume 1:"t_v_evaluation I G = Ttrue"
        thus ?thesis
        proof(cases "t_v_evaluation I H")
          assume  "t_v_evaluation I H = Ttrue"
          thus ?thesis using 1
            by (simp add: v_negation_def, simp add: v_implication_def)
        next
          assume  "t_v_evaluation I H = Ffalse"
          thus ?thesis using 1
            by (simp add: v_negation_def, simp add: v_implication_def)
        qed }
    next
        text  \<open> Caso 2:  \<close>
      { assume "t_v_evaluation I G = Ffalse"
        thus ?thesis
          by (simp add: v_negation_def, simp add: v_implication_def) }
    qed
  qed
qed
(*>*)

text\<open>
  \begin{lema}
  Si $F$ es una fórmula alfa y sus componentes son $F_1$ y $F_2$,
  $\langle[F]\rangle \equiv \langle[F_1], [F_2]\rangle$.
  \end{lema}

  \noindent Su formalización es:
\<close>

lemma EquiAlfa:
  assumes "tipoFormula F = Alfa"
  shows "equivalentesG [[F]] [[Comp1 F],[Comp2 F]]"
(*<*)
proof -
  have 1: "\<exists>G H. F = (G \<and>. H) \<or> F = (\<not>. (G \<or>. H)) \<or> F = (\<not>. (G \<rightarrow>. H))"
    using assms tipoAlfa Alfa by auto
  obtain G and H
    where H: "F = (G \<and>. H) \<or> F = (\<not>. (G \<or>. H)) \<or> F = (\<not>. (G \<rightarrow>. H))"
    using 1 by auto
  moreover
  { assume hip: "F = G \<and>. H"
    hence "Comp1 F = G" and "Comp2 F = H"
      by (simp add: Comp1_def, simp add: Comp2_def)
    hence ?thesis using hip EquiAlfaa by simp }
  moreover
  { assume hip:  "F = \<not>. (G \<or>. H)"
    hence "Comp1 F = \<not>. G" and "Comp2 F = \<not>. H"
      by (simp add: Comp1_def, simp add: Comp2_def)
    hence ?thesis using hip EquiAlfab by simp }
  moreover
  { assume hip:  "F = \<not>. (G \<rightarrow>. H)"
    hence "Comp1 F = G" and "Comp2 F = \<not>. H"
      by (simp add: Comp1_def, simp add: Comp2_def)
    hence ?thesis using hip EquiAlfac by simp }
  ultimately show ?thesis by blast
qed
(*>*)

(*<*)
lemma EquiBetaa: "equivalentesG [[G \<or>. H]] [[G, H]]"
proof (unfold equivalentesG_def)
  show "\<forall>I. t_v_evaluationConjuncionG I [[G \<or>. H]] = t_v_evaluationConjuncionG I [[G, H]]"
  proof
    fix I
    show  "t_v_evaluationConjuncionG I [[G \<or>. H]] = t_v_evaluationConjuncionG I [[G, H]]"
    proof (cases "t_v_evaluation I G")
        text  \<open> Caso 1:  \<close>
      { assume 1:"t_v_evaluation I G = Ttrue"
        thus ?thesis by (simp add: v_disjunction_def) }
    next
        text  \<open> Caso 2:  \<close>
      { assume 2: "t_v_evaluation I G = Ffalse"
        thus ?thesis
        proof(cases "t_v_evaluation I H")
          assume  "t_v_evaluation I H = Ttrue"
          thus ?thesis by (simp add: v_disjunction_def)
        next
          assume  "t_v_evaluation I H = Ffalse"
          thus ?thesis using 2 by (simp add: v_disjunction_def)
        qed }
    qed
  qed
qed

lemma EquiBetab: "equivalentesG [[\<not>. (G \<and>. H)]] [[\<not>. G, \<not>. H]]"
proof (unfold equivalentesG_def)
  show "\<forall>I. t_v_evaluationConjuncionG I [[\<not>. (G \<and>. H)]] =
            t_v_evaluationConjuncionG I [[\<not>. G, \<not>. H]]"
  proof
    fix I
    show "t_v_evaluationConjuncionG I [[\<not>. (G \<and>. H)]] =
          t_v_evaluationConjuncionG I [[\<not>. G, \<not>. H]]"
    proof (cases "t_v_evaluation I G")
             text  \<open> Caso 1:  \<close>
      { assume 1:"t_v_evaluation I G = Ttrue"
        thus ?thesis
        proof(cases "t_v_evaluation I H")
          assume  "t_v_evaluation I H = Ttrue"
          thus ?thesis using 1
            by (simp add: v_negation_def, simp add: v_conjunction_def)
        next
          assume  "t_v_evaluation I H = Ffalse"
          thus ?thesis using 1
            by (simp add: v_negation_def, simp add: v_conjunction_def)
        qed }
    next
         text  \<open> Caso 2:  \<close>
      { assume "t_v_evaluation I G = Ffalse"
        thus ?thesis
          by (simp add: v_negation_def, simp add: v_conjunction_def) }
    qed
  qed
qed

lemma EquiBetac: "equivalentesG [[G \<rightarrow>. H]] [[\<not>. G, H]]"
proof (unfold equivalentesG_def)
  show "\<forall>I. t_v_evaluationConjuncionG I [[G \<rightarrow>. H]] = t_v_evaluationConjuncionG I [[\<not>. G, H]]"
  proof
    fix I
    show  "t_v_evaluationConjuncionG I [[G \<rightarrow>. H]] = t_v_evaluationConjuncionG I [[\<not>. G, H]]"
    proof (cases "t_v_evaluation I G")
           text  \<open> Caso 1:  \<close>
      { assume 1:"t_v_evaluation I G = Ttrue"
        thus ?thesis
        proof(cases "t_v_evaluation I H")
          assume  "t_v_evaluation I H = Ttrue"
          thus ?thesis using 1
            by (simp add: v_negation_def, simp add: v_implication_def)
        next
          assume  "t_v_evaluation I H = Ffalse"
          thus ?thesis using 1
            by (simp add: v_negation_def, simp add: v_implication_def)
        qed }
    next
        text  \<open> Caso 2:  \<close>
      { assume "t_v_evaluation I G = Ffalse"
        thus ?thesis
          by (simp add: v_negation_def, simp add: v_implication_def) }
    qed
  qed
qed
(*>*)

text \<open>
  \begin{lema}
  Si $F$ es una fórmula beta y sus componentes son $F_1$ y
  $F_2$, $\langle[F]\rangle \equiv \langle[F_1, F_2]\rangle$.
  \end{lema}

  \noindent Su formalización es:
\<close>

lemma EquiBeta:
  assumes "tipoFormula F = Beta"
  shows "equivalentesG [[F]] [[Comp1 F, Comp2 F]]"
(*<*)
proof -
  have 1: "\<exists>G H. F = (G  \<or>. H) \<or> F = (\<not>. (G \<and>. H)) \<or> F = (G \<rightarrow>. H)"
    using assms tipoBeta Beta by blast
  obtain G and H
    where H: "F = (G \<or>. H) \<or> F = (\<not>. (G \<and>. H)) \<or> F =  (G \<rightarrow>. H)"
    using 1 by auto
  moreover
  { assume hip: "F = G \<or>. H"
    hence "Comp1 F = G" and "Comp2 F = H"
      by (simp add: Comp1_def, simp add: Comp2_def)
    hence ?thesis using hip EquiBetaa by simp }
  moreover
  { assume hip:  "F = \<not>. (G \<and>. H)"
    hence "Comp1 F = \<not>. G" and "Comp2 F = \<not>. H"
      by (simp add: Comp1_def, simp add: Comp2_def)
    hence ?thesis using hip EquiBetab by simp }
  moreover
  { assume hip:  "F = G \<rightarrow>. H"
    hence "Comp1 F = \<not>. G" and "Comp2 F = H"
      by (simp add: Comp1_def, simp add: Comp2_def)
    hence ?thesis using hip EquiBetac by simp }
  ultimately show ?thesis by blast
qed
(*>*)

text \<open>
  Se tienen las siguientes equivalencias entre las fórmulas alfa, beta y
  las dobles negationes, y sus respectivas componentes.

  \begin{lema}
  Si $F$ es una doble negación y $G$ es su componente, entonces $F \equiv G$.
  \end{lema}

  \noindent Su formalización es:
 \<close>

lemma EquivNoNoComp:
  assumes "tipoFormula F = NoNo"
  shows "equivalentes F (Comp1 F)"
(*<*)
proof (unfold equivalentes_def)
  show "\<forall>I. t_v_evaluation I F = t_v_evaluation I (Comp1 F)"
  proof (rule allI)+
    fix I
    have "equivalentesG [[F]] [[Comp1 F]]" using EquiNoNo assms by simp
    hence 1: "t_v_evaluationConjuncionG I [[F]] = t_v_evaluationConjuncionG I [[Comp1 F]]"
      by (unfold equivalentesG_def, simp)
    show "t_v_evaluation I F = t_v_evaluation I (Comp1 F)"
    proof (cases "t_v_evaluation I F")
      assume hip1: "t_v_evaluation I F =  Ttrue"
      hence "t_v_evaluationConjuncionG I [[F]] = Ttrue" by simp
      hence 2: "t_v_evaluationConjuncionG I [[Comp1 F]] = Ttrue" using 1 by simp
      have "t_v_evaluation I (Comp1 F) = Ttrue"
      proof -
        { assume "t_v_evaluation I (Comp1 F) \<noteq> Ttrue"
          hence  "t_v_evaluation I (Comp1 F) = Ffalse" using CasosValor by auto
          hence "t_v_evaluationConjuncionG I [[Comp1 F]] = Ffalse" by simp
          hence "False" using 2 by simp}
        thus "t_v_evaluation I (Comp1 F) = Ttrue" by auto
      qed
      thus "t_v_evaluation I F = t_v_evaluation I (Comp1 F)" using hip1 by simp
    next
      assume hip2: "t_v_evaluation I F =  Ffalse"
      hence "t_v_evaluationConjuncionG I [[F]] = Ffalse" by simp
      hence 2: "t_v_evaluationConjuncionG I [[Comp1 F]] = Ffalse" using 1 by simp
      have "t_v_evaluation I (Comp1 F) = Ffalse"
      proof -
       { assume "t_v_evaluation I (Comp1 F) \<noteq> Ffalse"
         hence  "t_v_evaluation I (Comp1 F) = Ttrue" using CasosValor by auto
         hence "t_v_evaluationConjuncionG I [[Comp1 F]] = Ttrue" by simp
         hence "False" using 2 by simp}
       thus "t_v_evaluation I (Comp1 F) = Ffalse" by auto
     qed
     thus "t_v_evaluation I F = t_v_evaluation I (Comp1 F)" using hip2 by simp
   qed
 qed
qed
(*>*)

text \<open>
  \begin{lema}
  Si $F$ es una fórmula alfa y sus componentes son $F_1$ y
  $F_2$, entonces $F \equiv F_1 \wedge F_2$.
  \end{lema}

  \noindent Su formalización es:
\<close>

lemma EquivAlfaComp:
  assumes "tipoFormula F = Alfa"
  shows "equivalentes F (Comp1 F \<and>. Comp2 F)"
(*<*)
proof(unfold equivalentes_def)
  show "\<forall> I. t_v_evaluation I F = t_v_evaluation I (Comp1 F \<and>. Comp2 F)"
  proof (rule allI)+
    fix I
    have "equivalentesG [[F]] [[Comp1 F], [Comp2 F]]"
      using EquiAlfa assms by simp
    hence 1: "t_v_evaluationConjuncionG I [[F]] =
              t_v_evaluationConjuncionG I [[Comp1 F], [Comp2 F]]"
      by (unfold equivalentesG_def,simp)
    show "t_v_evaluation I F = t_v_evaluation I (Comp1 F \<and>. Comp2 F)"
    proof (cases "t_v_evaluation I F")
      assume hip1: "t_v_evaluation I F =  Ttrue"
      have "t_v_evaluation I (Comp1 F \<and>. Comp2 F) = Ttrue"
      proof -
        have "t_v_evaluationConjuncionG I [[F]] = Ttrue" using hip1 by simp
        hence 2:"t_v_evaluationConjuncionG I [[Comp1 F], [Comp2 F]] = Ttrue"
          using 1 by simp
        have 3: "t_v_evaluation I (Comp1 F) = Ttrue"
        proof -
         { assume "t_v_evaluation I (Comp1 F) = Ffalse"
           hence "t_v_evaluationConjuncionG I [[Comp1 F], [Comp2 F]] = Ffalse" by simp
           hence "False" using 2 by simp}
         hence "t_v_evaluation I (Comp1 F) \<noteq> Ffalse" by auto
         thus "t_v_evaluation I (Comp1 F) = Ttrue" using CasosValor by auto
       qed
       have "t_v_evaluation I (Comp2 F) = Ttrue"
       proof -
         { assume "t_v_evaluation I (Comp2 F) = Ffalse"
           hence "t_v_evaluationConjuncionG I [[Comp1 F], [Comp2 F]] = Ffalse" by simp
           hence "False" using 2 by simp}
         hence "t_v_evaluation I (Comp2 F) \<noteq> Ffalse" by auto
         thus "t_v_evaluation I (Comp2 F) = Ttrue" using CasosValor by auto
       qed
       thus "t_v_evaluation I (Comp1 F \<and>. Comp2 F) = Ttrue" using 3
         by (auto, unfold v_conjunction_def, simp)
     qed
     thus "t_v_evaluation I F = t_v_evaluation I (Comp1 F \<and>. Comp2 F)" using hip1 by simp
   next
     assume hip2: "t_v_evaluation I F = Ffalse"
     show "t_v_evaluation I F = t_v_evaluation I (Comp1 F \<and>. Comp2 F)"
     proof -
       have  "t_v_evaluation I (Comp1 F \<and>. Comp2 F) = Ffalse"
       proof -
         have "t_v_evaluationConjuncionG I [[F]] = Ffalse" using hip2 by simp
         hence 4: "t_v_evaluationConjuncionG I [[Comp1 F], [Comp2 F]] = Ffalse"
           using 1 by simp
         have "t_v_evaluation I (Comp1 F) = Ffalse \<or> t_v_evaluation I (Comp2 F) = Ffalse"
         proof -
           { assume "\<not>(t_v_evaluation I (Comp1 F) = Ffalse \<or>
                       t_v_evaluation I (Comp2 F) = Ffalse)"
             hence "(t_v_evaluation I (Comp1 F) \<noteq> Ffalse \<and>
                     t_v_evaluation I (Comp2 F) \<noteq> Ffalse)"
               by simp
             hence  "(t_v_evaluation I (Comp1 F) = Ttrue \<and>
                      t_v_evaluation I (Comp2 F) = Ttrue)"
               using CasosValor by auto
             hence "t_v_evaluation I (Comp1 F) = Ttrue" and
               "t_v_evaluation I (Comp2 F) = Ttrue"
               by auto
             hence  "t_v_evaluationConjuncionG I [[Comp1 F], [Comp2 F]] = Ttrue" by auto
             hence "False" using 4 by auto}
           thus "t_v_evaluation I (Comp1 F) = Ffalse \<or> t_v_evaluation I (Comp2 F) = Ffalse"
             by auto
         qed
         thus "t_v_evaluation I (Comp1 F \<and>. Comp2 F) = Ffalse"
           by (auto, unfold v_conjunction_def, auto)
       qed
       thus "t_v_evaluation I F = t_v_evaluation I (Comp1 F \<and>. Comp2 F)" using hip2 by simp
     qed
   qed
 qed
qed
(*>*)

text \<open>
  \begin{lema}
  Si $F$ es una fórmula beta y sus componentes son $F_1$ y $F_2$,
  entonces $F \equiv F_1 \vee F_2$.
  \end{lema}

  \noindent Su formalización es:
\<close>

lemma EquivBetaComp:
  assumes "tipoFormula F = Beta"
  shows "equivalentes F (Comp1 F \<or>. Comp2 F)"
(*<*)
proof (unfold equivalentes_def)
  show "\<forall> I. t_v_evaluation I F = t_v_evaluation I (Comp1 F \<or>. Comp2 F)"
  proof(rule allI)+
    fix I
    have "equivalentesG [[F]] [[Comp1 F, Comp2 F]]"
      using EquiBeta assms by simp
    hence 1: "t_v_evaluationConjuncionG I [[F]] =
              t_v_evaluationConjuncionG I [[Comp1 F, Comp2 F]]"
      by (unfold equivalentesG_def,simp)
    show "t_v_evaluation I F = t_v_evaluation I (Comp1 F \<or>. Comp2 F)"
    proof (cases "t_v_evaluation I F")
      assume hip1: "t_v_evaluation I F =  Ttrue"
      have "t_v_evaluation I (Comp1 F \<or>. Comp2 F) = Ttrue"
      proof -
        have "t_v_evaluationConjuncionG I [[F]] = Ttrue" using hip1 by simp
        hence 2:"t_v_evaluationConjuncionG I [[Comp1 F, Comp2 F]] = Ttrue"
          using 1 by simp
        hence "(t_v_evaluation I (Comp1 F) = Ttrue) \<or> (t_v_evaluation I (Comp2 F) = Ttrue)"
        proof -
         { assume  "\<not>((t_v_evaluation I (Comp1 F) = Ttrue) \<or>
                      (t_v_evaluation I (Comp2 F) = Ttrue))"
           hence  "(t_v_evaluation I (Comp1 F) \<noteq> Ttrue \<and>
                    t_v_evaluation I (Comp2 F) \<noteq> Ttrue)"
            by simp
          hence  "(t_v_evaluation I (Comp1 F) = Ffalse \<and>
                   t_v_evaluation I (Comp2 F) = Ffalse)"
            using CasosValor by auto
          hence  "t_v_evaluationConjuncionG I [[Comp1 F, Comp2 F]] = Ffalse" by auto
          hence "False" using 2 by auto}
          thus "(t_v_evaluation I (Comp1 F) = Ttrue) \<or> (t_v_evaluation I (Comp2 F) = Ttrue)"
            by auto
        qed
        thus "t_v_evaluation I (Comp1 F \<or>. Comp2 F) = Ttrue"
          by (auto, unfold v_disjunction_def, auto)
      qed
      thus "t_v_evaluation I F = t_v_evaluation I (Comp1 F \<or>. Comp2 F)" using hip1 by simp
    next
      assume hip2: "t_v_evaluation I F =  Ffalse"
      have "t_v_evaluation I (Comp1 F \<or>. Comp2 F) = Ffalse"
      proof -
        have "t_v_evaluationConjuncionG I [[F]] = Ffalse" using hip2 by simp
        hence 3:"t_v_evaluationConjuncionG I [[Comp1 F, Comp2 F]] = Ffalse"
          using 1 by simp
        have  4:"t_v_evaluation I (Comp1 F) = Ffalse"
        proof -
         { assume "t_v_evaluation I (Comp1 F) = Ttrue"
           hence "t_v_evaluationConjuncionG I [[Comp1 F, Comp2 F]] = Ttrue" by simp
           hence "False" using 3 by simp}
         hence "t_v_evaluation I (Comp1 F) \<noteq> Ttrue" by auto
         thus "t_v_evaluation I (Comp1 F) = Ffalse" using CasosValor by auto
       qed
       have "t_v_evaluation I (Comp2 F) = Ffalse"
       proof -
         { assume "t_v_evaluation I (Comp2 F) = Ttrue"
           hence "t_v_evaluationConjuncionG I [[Comp1 F, Comp2 F]] = Ttrue" by simp
           hence "False" using 3 by simp}
         hence "t_v_evaluation I (Comp2 F) \<noteq> Ttrue" by auto
         thus "t_v_evaluation I (Comp2 F) = Ffalse" using CasosValor by auto
       qed
       thus "t_v_evaluation I (Comp1 F \<or>. Comp2 F) = Ffalse" using 4
         by (auto, unfold v_disjunction_def, simp)
     qed
     thus "t_v_evaluation I F = t_v_evaluation I (Comp1 F \<or>. Comp2 F)" using hip2 by simp
   qed
 qed
qed

(*>*)

(*<*)
end
(*>*)


theory Padic_Int_Topology
imports Padic_Integers Function_Ring
begin

type_synonym padic_int_seq = "nat \<Rightarrow> padic_int"

type_synonym padic_int_fun = "padic_int \<Rightarrow> padic_int"

sublocale padic_integers < FunZp?: U_function_ring "Zp"
  unfolding U_function_ring_def
  by (simp add: R.ring_axioms)

context padic_integers
begin

(**************************************************************************************************)
(**************************************************************************************************)
(***********************************)section\<open>Sequences over Zp\<close>(***********************************)
(**************************************************************************************************)
(**************************************************************************************************)

text\<open>
  The $p$-adic valuation can be thought of as equivalent to the $p$-adic absolute value, but with
  the notion of size inverted so that small numbers have large valuation, and zero has maximally
  large valuation. The $p$-adic distance between two points is just the valuation of the difference
  of those points, and is thus equivalent to the metric induced by the $p$-adic absolute value.
  For background on valuations and absolute values for $p$-adic rings see \<^cite>\<open>"engler2005valued"\<close>.
  In what follows, we develop the topology of the $p$-adic from a valuative perspective rather than
  a metric perspective. Though equivalent to the metric approach in the $p$-adic case, this
  approach is more general in that there exist valued rings whose valuations take values in
  non-Archimedean ordered ablelian groups which do not embed into the real numbers.
\<close>

  (**********************************************************************)
  (**********************************************************************)
  subsection\<open>The Valuative Distance Function on $\mathbb{Z}_p$\<close>
  (**********************************************************************)
  (**********************************************************************)

text\<open>
  The following lemmas establish that the $p$-adic distance function satifies the standard
  properties of an ultrametric. It is symmetric, obeys the ultrametric inequality, and only
  identical elements are infinitely close.
\<close>

definition val_Zp_dist :: "padic_int \<Rightarrow> padic_int \<Rightarrow> eint" where
"val_Zp_dist a b \<equiv> val_Zp (a \<ominus> b)"

lemma val_Zp_dist_sym:
  assumes "a \<in> carrier Zp"
  assumes "b \<in> carrier Zp"
  shows "val_Zp_dist a b = val_Zp_dist b a"
proof-
  have 1: "a \<ominus> b = \<ominus> (b \<ominus> a)" using assms(1) assms(2)
    using minus_a_inv by blast
  then show ?thesis
    using R.minus_closed Zp_def assms(1) assms(2) padic_integers.val_Zp_of_minus
      padic_integers_axioms val_Zp_dist_def by auto
qed

lemma val_Zp_dist_ultrametric:
  assumes "a \<in> carrier Zp"
  assumes "b \<in> carrier Zp"
  assumes "c \<in> carrier Zp"
  shows "val_Zp_dist b c \<ge> min (val_Zp_dist a c) (val_Zp_dist a b)"
proof-
  let ?X = "b \<ominus> a"
  let ?Y = "a \<ominus> c"
  let ?Z = "b \<ominus> c"
  have 0: "?Z = ?X \<oplus> ?Y"
    using R.add.m_comm assms(1) assms(2) assms(3) R.plus_diff_simp by auto
  have 4: "val_Zp ?Z \<ge> min (val_Zp ?X) (val_Zp ?Y)"
    using "0" assms(1) assms(2) assms(3) val_Zp_ultrametric by auto
  then show ?thesis
    using  assms val_Zp_dist_sym
    unfolding  val_Zp_dist_def
    by (simp add: min.commute)
qed

lemma val_Zp_dist_infty:
  assumes "a \<in> carrier Zp"
  assumes "b \<in> carrier Zp"
  assumes "val_Zp_dist a b = \<infinity>"
  shows "a = b"
  using assms unfolding val_Zp_dist_def
  by (metis R.r_right_minus_eq not_eint_eq val_ord_Zp)

lemma val_Zp_dist_infty':
  assumes "a \<in> carrier Zp"
  assumes "b \<in> carrier Zp"
  assumes "a = b"
  shows "val_Zp_dist a b = \<infinity>"
  using assms unfolding val_Zp_dist_def
  by (simp add: val_Zp_def)

text\<open>
  The following property will be useful in the proof of Hensel's Lemma: two $p$-adic integers are
  close together if and only if their residues are equal at high orders.
\<close>

lemma val_Zp_dist_res_eq:
  assumes "a \<in> carrier Zp"
  assumes "b \<in> carrier Zp"
  assumes "val_Zp_dist a b > k"
  shows "(a k) = (b k)"
  using  assms(1) assms(2) assms(3) val_Zp_dist_def
  by (simp add: Zp_residue_eq)

lemma val_Zp_dist_res_eq2:
  assumes "a \<in> carrier Zp"
  assumes "b \<in> carrier Zp"
  assumes "(a k) = (b k)"
  shows "val_Zp_dist a b \<ge> k"
  using assms(1) assms(2) assms(3) Zp_residue_eq2
  unfolding val_Zp_dist_def
  by (simp add: val_Zp_def)

lemma val_Zp_dist_triangle_eqs:
  assumes "a \<in> carrier Zp"
  assumes "b \<in> carrier Zp"
  assumes "c \<in> carrier Zp"
  assumes "val_Zp_dist a b > n"
  assumes "val_Zp_dist a c > n"
  assumes "(k::nat) < n"
  shows "a k = b k"
        "a k = c k"
        "b k = c k"
  unfolding val_Zp_dist_def
proof-
  show 0: "a k = b k"
    using assms(1) assms(2) assms(4) assms(6) val_Zp_dist_res_eq
    by (metis less_imp_le_nat p_residue_padic_int)
  show 1: "a k = c k"
    using assms(1) assms(3) assms(5) assms(6) val_Zp_dist_res_eq
    by (meson eint_ord_simps(1) le_less_trans less_imp_triv not_less of_nat_le_iff)
  show "b k = c k"
    using 0 1 by auto
qed

  (**********************************************************************)
  (**********************************************************************)
  subsection\<open>Cauchy Sequences\<close>
  (**********************************************************************)
  (**********************************************************************)

text\<open>
  The definition of Cauchy sequence here is equivalent to standard the metric notion, and is
  identical to the one found on page 50 of \<^cite>\<open>"engler2005valued"\<close>.
\<close>

lemma closed_seqs_diff_closed:
  assumes "s \<in> closed_seqs Zp"
  assumes "a \<in> carrier Zp"
  shows "s m \<ominus> a \<in> carrier Zp"
  using assms
  by (simp add: closed_seqs_memE)

definition is_Zp_cauchy :: "padic_int_seq \<Rightarrow> bool" where
"is_Zp_cauchy s = ((s \<in> closed_seqs Zp) \<and> (\<forall> (n::int). \<exists> (N::nat). \<forall> m k::nat.

                  (m>N \<and> k>N \<longrightarrow> (val_Zp_dist (s m) (s k)) > eint n)))"

text\<open>Relation for a sequence which converges to a point:\<close>

definition Zp_converges_to :: "padic_int_seq \<Rightarrow> padic_int \<Rightarrow> bool" where
          "Zp_converges_to s a = ((a \<in> carrier Zp \<and> s \<in> closed_seqs Zp)
                              \<and> (\<forall>(n::int). (\<exists>(k:: nat). (\<forall>( m::nat).
                                (m > k \<longrightarrow> (val_Zp ((s m) \<ominus> a)) > eint n) ))))"

lemma is_Zp_cauchy_imp_closed:
  assumes "is_Zp_cauchy s"
  shows "s \<in> closed_seqs Zp"
  using assms unfolding is_Zp_cauchy_def by blast

text\<open>
  Analogous to the lemmas about residues and $p$-adic distances, we can characterize Cauchy
  sequences without reference to a distance function: a sequence is Cauchy if and only if for
  every natural number $k$, the $k^{th}$ residues of the elements in the sequence are eventually
  all equal.
\<close>

lemma is_Zp_cauchy_imp_res_eventually_const_0:
  assumes "is_Zp_cauchy s"
  fixes n::nat
  obtains N where "\<And> n0 n1. n0 > N \<and> n1 > N \<Longrightarrow> (s n0) n = (s n1) n"
proof-
  have "\<exists> (N::nat). \<forall> m k::nat. (m>N \<and> k>N \<longrightarrow> (val_Zp_dist (s m) (s k)) > (int n))"
    using assms is_Zp_cauchy_def by blast
  then obtain N where P0: " \<forall> m k::nat. (m>N \<and> k>N \<longrightarrow> (val_Zp_dist (s m) (s k)) > (int n))"
    by blast
  have P1: "\<And> n0 n1. n0 > N \<and> n1 > N \<Longrightarrow> (s n0) n = (s n1) n"
  proof-
    fix n0 n1
    assume A: "n0 > N \<and> n1 > N"
    have "(n0>N \<and> n1>N \<longrightarrow> (val_Zp_dist (s n0) (s n1)) > (int n))"
      using P0 by blast
    then have C0: "(val_Zp_dist (s n0) (s n1)) > (int n)"
      using A  by blast
    show "(s n0) n = (s n1) n"
    proof-
      have A0: "(val_Zp_dist (s n0) (s n1)) > (int n)"
        using C0 by blast
      have A1: "s n0 \<in> carrier Zp"
        using is_Zp_cauchy_imp_closed[of s] assms
        by (simp add: closed_seqs_memE)
      have A2: "s n1 \<in> carrier Zp"
        using is_Zp_cauchy_def assms closed_seqs_memE[of _ Zp]
        by blast
      show ?thesis
        using A0 val_Zp_dist_res_eq  A1 A2 by metis
    qed
  qed
  then show ?thesis
    using that by blast
qed

lemma is_Zp_cauchyI:
  assumes "s \<in> closed_seqs Zp"
  assumes "\<And> n.  (\<exists>N. (\<forall> n0 n1. n0 > N \<and> n1 > N \<longrightarrow> (s n0) n = (s n1) n))"
  shows "is_Zp_cauchy s"
proof-
  have "(\<forall> (n::int). \<exists> (N::nat). \<forall> m k::nat. (m>N \<and> k>N \<longrightarrow> (val_Zp_dist (s m) (s k)) > n))"
  proof
    fix n
    show "\<exists> (N::nat). \<forall> m k::nat. (m>N \<and> k>N \<longrightarrow> (val_Zp_dist (s m) (s k)) > eint n)"
    proof-
      have "(\<exists>N. (\<forall> n0 n1. n0 > N \<and> n1 > N \<longrightarrow> (s n0) (Suc (nat n)) = (s n1) (Suc (nat n))))"
        using assms(2) by blast
      then obtain N where N_def: "(\<forall> n0 n1. n0 > N \<and> n1 > N \<longrightarrow> (s n0) (Suc (nat n)) = (s n1) (Suc (nat n)))"
        by blast
      have 0: "n \<le> eint (int (nat n))"
        by simp
      have "\<forall>m k. N < m \<and> N < k \<longrightarrow> (nat n) < val_Zp_dist (s m) (s k)"
      proof
      fix m
      show "\<forall>k. N < m \<and> N < k \<longrightarrow> int (nat n) < val_Zp_dist (s m) (s k)"
      proof
        fix k
        show "N < m \<and> N < k \<longrightarrow> int(nat n) < val_Zp_dist (s m) (s k)"
        proof
          assume A: "N < m \<and> N < k"
          then have E: "(s m) (Suc(nat n)) = (s k) (Suc(nat n))"
            using N_def by blast
          then show " int (nat n) < val_Zp_dist (s m) (s k)"
          proof-
            have 0: "(s m) \<in> carrier Zp"
              by (simp add: assms(1) closed_seqs_memE)
            have 1: "(s k) \<in> carrier Zp"
              using Zp_def assms(1) closed_seqs_memE[of _ Zp] padic_integers_axioms by blast
            have "int (Suc (nat n)) \<le> val_Zp_dist (s m) (s k)"
              using   E 0 1 val_Zp_dist_res_eq[of "(s m)" "(s k)" "Suc (nat n)"] val_Zp_dist_res_eq2
              by blast
            then have "int (nat n) < val_Zp_dist (s m) (s k)"
              by (metis Suc_ile_eq add.commute of_nat_Suc)
            then show ?thesis
              by blast
          qed
        qed
      qed
      qed
      hence "\<forall>m k. N < m \<and> N < k \<longrightarrow> n < val_Zp_dist (s m) (s k)"
      using 0
      by (simp add: order_le_less_subst2)
      thus ?thesis by blast
    qed
  qed
  then show ?thesis
    using is_Zp_cauchy_def assms  by blast
qed

lemma is_Zp_cauchy_imp_res_eventually_const:
  assumes "is_Zp_cauchy s"
  fixes n::nat
  obtains N r where "r \<in> carrier (Zp_res_ring n)" and "\<And> m. m > N \<Longrightarrow> (s m) n = r"
proof-
  obtain N where A0: "\<And> n0 n1. n0 > N \<and> n1 > N \<Longrightarrow> (s n0) n = (s n1) n"
    using assms is_Zp_cauchy_imp_res_eventually_const_0 padic_integers_axioms by blast
  obtain r where A1: "s (Suc N) n = r"
    by simp
  have 0: "r \<in> carrier (Zp_res_ring n)"
    using  Zp_def \<open>s (Suc N) n = r\<close> assms closed_seqs_memE[of _ Zp]
      is_Zp_cauchy_def padic_integers_axioms residues_closed
    by blast
  have 1: "\<And> m. m > N \<Longrightarrow> (s m) n = r"
  proof-
    fix m
    assume " m > N"
    then show "(s m) n = r"
      using A0 A1  by blast
  qed
  then show ?thesis
    using 0 1  that by blast
qed

text\<open>
  This function identifies the eventual residues of the elements of a cauchy sequence.
  Since a $p$-adic integer is defined to be the map which identifies its residues, this map
  will turn out to be precisely the limit of a cauchy sequence.
\<close>
definition res_lim :: "padic_int_seq \<Rightarrow> padic_int" where
"res_lim s = (\<lambda> k. (THE r. (\<exists>N.  (\<forall> m. m > N \<longrightarrow> (s m) k = r))))"

lemma res_lim_Zp_cauchy_0:
  assumes "is_Zp_cauchy s"
  assumes "f = (res_lim s) k"
  shows "(\<exists>N.  (\<forall> m. (m > N \<longrightarrow> (s m) k = f)))"
        "f \<in> carrier (Zp_res_ring k)"
proof-
  obtain N r where P0: "r \<in> carrier (Zp_res_ring k)" and P1: "\<And> m. m > N \<Longrightarrow> (s m) k = r"
    by (meson assms(1) is_Zp_cauchy_imp_res_eventually_const)
  obtain P where  P_def: "P = (\<lambda> x. (\<exists>N.  (\<forall> m. m > N \<longrightarrow> (s m) k = x)))"
    by simp
  have 0: "P r"
    using P1 P_def by auto
  have 1: "(\<And>x. P x \<Longrightarrow> x = r)"
  proof-
    fix x
    assume A_x: "P x"
    obtain N0 where "(\<forall> m. m > N0 \<longrightarrow> (s m) k = x)"
      using A_x P_def by blast
    let ?M = "max N0 N"
    have C0: "s (Suc ?M) k = x"
      by (simp add: \<open>\<forall>m>N0. s m k = x\<close>)
    have C1: "s (Suc ?M) k = r"
      by (simp add: P1)
    show "x = r"
      using C0 C1 by auto
  qed
  have R: "r = (THE x. P x)"
    using the_equality 0 1 by metis
  have "(res_lim s) k = (THE r. \<exists>N. \<forall>m>N. s m k = r)"
    using res_lim_def by simp
  then have "f = (THE r. \<exists>N. \<forall>m>N. s m k = r)"
    using assms by auto
  then have "f = (THE r. P r)"
    using P_def by auto
  then have "r = f"
    using R by auto
  then show "(\<exists>N.  (\<forall> m. (m > N \<longrightarrow> (s m) k = f)))" using 0 P_def
    by blast
  show "f \<in> carrier (Zp_res_ring k)"
    using P0 \<open>r = f\<close> by auto
qed

lemma res_lim_Zp_cauchy:
  assumes "is_Zp_cauchy s"
  obtains N where "\<And> m.  (m > N \<longrightarrow> (s m) k = (res_lim s) k)"
  using res_lim_Zp_cauchy_0 assms by presburger

lemma res_lim_in_Zp:
  assumes "is_Zp_cauchy s"
  shows "res_lim s \<in> carrier Zp"
proof-
  have "res_lim s \<in> padic_set p"
  proof(rule padic_set_memI)
    show "\<And>m. res_lim s m \<in> carrier (residue_ring (p^ m))"
      using res_lim_Zp_cauchy_0     by (simp add:  assms)
    show "\<And>m n. m < n \<Longrightarrow> residue (p^ m) (res_lim s n) = res_lim s m"
    proof-
      fix m n
      obtain N where  N0: "\<And> l.  (l > N \<longrightarrow> (s l) m = (res_lim s) m)"
        using assms res_lim_Zp_cauchy by blast
      obtain M where M0: "\<And> l.  (l > M \<longrightarrow> (s l) n = (res_lim s) n)"
        using assms prod.simps(2) res_lim_Zp_cauchy by auto
      obtain K where K_def: "K = max M N"
        by simp
      have Km: "\<And> l.  (l > K \<longrightarrow> (s l) m = (res_lim s) m)"
        using K_def N0  by simp
      have Kn: "\<And> l.  (l > K \<longrightarrow> (s l) n = (res_lim s) n)"
        using K_def M0  by simp
      assume "m < n"
      show "residue (p^ m) (res_lim s n) = res_lim s m"
      proof-
        obtain l where l_def: "l = Suc K"
          by simp
        have ln: "(res_lim s n) = (s l) n"
          by (simp add: Kn l_def)
        have lm: "(res_lim s m) = (s l) m"
          by (simp add: Km l_def)
        have s_car: "s l \<in> carrier Zp"
          using assms is_Zp_cauchy_def closed_seqs_memE[of _ Zp] by blast
        then show ?thesis
          using s_car lm ln \<open>m < n\<close> p_residue_def p_residue_padic_int by auto
      qed
    qed
  qed
  then show ?thesis
    by (simp add: Zp_def padic_int_simps(5))
qed

  (**********************************************************************)
  (**********************************************************************)
  subsection\<open>Completeness of $\mathbb{Z}_p$\<close>
  (**********************************************************************)
  (**********************************************************************)

text\<open>
  We can use the developments above to show that a sequence of $p$-adic integers is convergent
  if and only if it is cauchy, and that limits of convergent sequences are always unique.
\<close>

lemma is_Zp_cauchy_imp_has_limit:
  assumes "is_Zp_cauchy s"
  assumes "a = res_lim s"
  shows "Zp_converges_to s a"
proof-
  have 0: "(a \<in> carrier Zp \<and> s \<in> closed_seqs Zp)"
    using assms(1) assms(2) is_Zp_cauchy_def res_lim_in_Zp by blast
  have 1: "(\<forall>(n::int). (\<exists>(k:: nat). (\<forall>( m::nat).
            (m > k \<longrightarrow> (val_Zp ((s m) \<ominus> a)) \<ge> n))))"
  proof
    fix n
    show "\<exists>k. \<forall>m>k.  eint n \<le> val_Zp (s m \<ominus> a)"
    proof-
      obtain K where K_def: "\<And>m. (m > K \<longrightarrow> (s m) (nat n) = (res_lim s) (nat n))"
        using assms(1) res_lim_Zp_cauchy
        by blast
      have "\<forall>m>K.  n \<le> val_Zp_dist (s m) a"
      proof
        fix m
        show "K < m \<longrightarrow>  n \<le> val_Zp_dist (s m) a"
        proof
          assume A: "K < m"
          show " n \<le> val_Zp_dist (s m) a"
          proof-
            have X: "(s m) \<in> carrier Zp"
              using "0" closed_seqs_memE[of _ Zp]
              by blast
            have "(s m) (nat n) = (res_lim s) (nat n)"
              using A K_def  by blast
            then have "(s m) (nat n) = a (nat n)"
              using assms(2) by blast
            then have "int (nat n) \<le> val_Zp_dist (s m) a"
              using  X val_Zp_dist_res_eq2 "0" by blast
            then show ?thesis
              by (metis eint_ord_simps(1) int_ops(1) less_not_sym nat_eq_iff2 not_le order_trans zero_eint_def)
          qed
        qed
      qed
      then show ?thesis
        using val_Zp_dist_def by auto
    qed
  qed
  then show ?thesis using
    "0" Zp_converges_to_def
    by (metis Suc_ile_eq val_Zp_dist_def)
qed

lemma convergent_imp_Zp_cauchy:
  assumes "s \<in> closed_seqs Zp"
  assumes "a \<in> carrier Zp"
  assumes "Zp_converges_to s a"
  shows "is_Zp_cauchy s"
  apply(rule is_Zp_cauchyI)
  using assms apply simp
proof-
  fix n
  show "\<exists>N. \<forall>n0 n1. N < n0 \<and> N < n1 \<longrightarrow> s n0 n = s n1 n "
  proof-
    obtain k where k_def:"\<forall>m>k.  n < val_Zp_dist (s m) a"
      using assms val_Zp_dist_def
      unfolding Zp_converges_to_def
      by presburger
    have A0:  "\<forall>n0 n1. k < n0 \<and> k < n1 \<longrightarrow> s n0 n = s n1 n "
    proof- have "\<And>n0 n1. k < n0 \<and> k < n1 \<longrightarrow> s n0 n = s n1 n"
      proof
      fix n0 n1
      assume A: " k < n0 \<and> k < n1"
      show " s n0 n = s n1 n "
      proof-
        have 0: "n < val_Zp_dist (s n0) a"
          using k_def using  A
          by blast
        have 1: "n < val_Zp_dist (s n1) a"
          using k_def using  A
          by blast
        hence 2: "(s n0) n = a n"
          using 0 assms val_Zp_dist_res_eq[of "s n0" a n] closed_seqs_memE
          by blast
        hence 3: "(s n1) n = a n"
          using 1 assms val_Zp_dist_res_eq[of "s n1" a n] closed_seqs_memE
          by blast
        show ?thesis
          using 2 3
          by auto
      qed
       qed
       thus ?thesis by blast
    qed
    show ?thesis
      using A0
      by blast
  qed
qed

lemma unique_limit:
  assumes "s \<in> closed_seqs Zp"
  assumes "a \<in> carrier Zp"
  assumes "b \<in> carrier Zp"
  assumes "Zp_converges_to s a"
  assumes "Zp_converges_to s b"
  shows "a = b"
proof-
  have "\<And>k. a k = b k"
  proof-
    fix k::nat
    obtain k0 where k0_def:"\<forall>m>k0.  k < val_Zp_dist (s m) a"
      using assms  unfolding val_Zp_dist_def Zp_converges_to_def
      by blast
    obtain k1 where k1_def:"\<forall>m>k1. k <  val_Zp_dist (s m) b"
      using assms unfolding val_Zp_dist_def Zp_converges_to_def
      by blast
    have k0_prop: "\<And>m. m> k0 \<Longrightarrow> (s m) k = a k" proof- fix m assume A: "m > k0"
      then show "(s m) k = a k"
      using k0_def assms closed_seqs_memE[of s Zp] val_Zp_dist_res_eq[of _ a k] of_nat_Suc
       by blast
    qed
    have k1_prop: "\<And>m. m> k1 \<Longrightarrow> (s m) k = b k"
      using k1_def assms closed_seqs_memE[of s Zp]
      by (simp add: val_Zp_dist_res_eq)
    have "\<And> m. m > (max k0 k1) \<Longrightarrow> a k = b k"
      using k0_prop k1_prop
      by force
    then show "a k = b k"
      by blast
  qed
  then show ?thesis
    by blast
qed

lemma unique_limit':
  assumes "s \<in> closed_seqs Zp"
  assumes "a \<in> carrier Zp"
  assumes "Zp_converges_to s a"
  shows "a = res_lim s"
  using unique_limit[of s a "res_lim s"] assms
        convergent_imp_Zp_cauchy is_Zp_cauchy_imp_has_limit res_lim_in_Zp
  by blast

lemma Zp_converges_toE:
  assumes "s \<in> closed_seqs Zp"
  assumes "a \<in> carrier Zp"
  assumes "Zp_converges_to s a"
  shows "\<exists>N. \<forall>k > N. s k n = a n"
  by (metis assms(1) assms(2) assms(3)
      convergent_imp_Zp_cauchy
      res_lim_Zp_cauchy unique_limit')

lemma Zp_converges_toI:
  assumes "s \<in> closed_seqs Zp"
  assumes "a \<in> carrier Zp"
  assumes "\<And>n. \<exists>N. \<forall>k > N. s k n = a n"
  shows "Zp_converges_to s a"
proof-
  have 0: "(a \<in> carrier Zp \<and> s \<in> closed_seqs Zp)"
    using assms
    by auto
  have 1: "(\<forall>n::int. \<exists>k. \<forall>m>k.  n < val_Zp_dist (s m) a) "
  proof
    fix n::int
    show "\<exists>k. \<forall>m>k.  n < val_Zp_dist (s m) a "
    proof(cases "n < 0")
      case True
      have "\<forall>m>0.  n < val_Zp_dist (s m) a "
      proof
        fix m ::nat
        show "0 < m \<longrightarrow>  n < val_Zp_dist (s m) a"
        proof
          have 0: "eint n < 0"
            by (simp add: True zero_eint_def)
          have 1: " s m \<ominus> a \<in> carrier Zp"
            using assms
            by (simp add: closed_seqs_diff_closed)
          thus " n < val_Zp_dist (s m) a"
            using 0  True val_pos[of "s m \<ominus> a"]
            unfolding val_Zp_dist_def
            by auto
        qed
      qed
      then show ?thesis
        by blast
    next
      case False
      then have P0: "n \<ge> 0"
        by auto
      obtain N where N_def: "\<forall>k > N. s k (Suc (nat n)) = a (Suc (nat n))"
        using assms by blast
      have "\<forall>m>N.  n < val_Zp_dist (s m) a "
      proof
        fix m
        show " N < m \<longrightarrow>  n < val_Zp_dist (s m) a"
        proof
          assume A: "N < m"
          then have A0: "s m (Suc (nat n)) = a (Suc (nat n))"
            using N_def by blast
          have "(Suc (nat n)) \<le> val_Zp_dist (s m) a"
            using assms A0 val_Zp_dist_res_eq2[of "s m" a "Suc (nat n)"] closed_seqs_memE
            by blast
          thus "n < val_Zp_dist (s m) a"
            using False
            by (meson P0 eint_ord_simps(2) less_Suc_eq less_le_trans nat_less_iff)
        qed
      qed
      then show ?thesis
        by blast
    qed
  qed
  show ?thesis
    unfolding Zp_converges_to_def
    using 0 1
    by (simp add: val_Zp_dist_def)
qed

text\<open>Sums and products of cauchy sequences are cauchy:\<close>

lemma sum_of_Zp_cauchy_is_Zp_cauchy:
  assumes "is_Zp_cauchy s"
  assumes "is_Zp_cauchy t"
  shows "is_Zp_cauchy (s \<oplus>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t)"
proof(rule is_Zp_cauchyI)
  show "(s \<oplus>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) \<in> closed_seqs Zp"
    using assms seq_plus_closed is_Zp_cauchy_def by blast
  show "\<And>n. \<exists>N. \<forall>n0 n1. N < n0 \<and> N < n1 \<longrightarrow> (s \<oplus>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n0 n = (s \<oplus>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n1 n"
  proof-
    fix n
    show "\<exists>N. \<forall>n0 n1. N < n0 \<and> N < n1 \<longrightarrow> (s \<oplus>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n0 n = (s \<oplus>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n1 n"
    proof-
      obtain N1 where N1_def: "\<forall>n0 n1. N1 < n0 \<and> N1 < n1 \<longrightarrow> s n0 n = s n1 n"
        using assms(1) is_Zp_cauchy_imp_res_eventually_const_0 padic_integers_axioms  by blast
      obtain N2 where N2_def: "\<forall>n0 n1. N2 < n0 \<and> N2 < n1 \<longrightarrow> t n0 n = t n1 n"
        using assms(2) is_Zp_cauchy_imp_res_eventually_const_0 padic_integers_axioms by blast
      obtain M where M_def: "M = max N1 N2"
        by simp
      have "\<forall>n0 n1. M < n0 \<and> M < n1 \<longrightarrow> (s \<oplus>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n0 n = (s \<oplus>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n1 n"
      proof
        fix n0
        show "\<forall>n1. M < n0 \<and> M < n1 \<longrightarrow> (s \<oplus>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n0 n = (s \<oplus>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n1 n"
        proof
          fix n1
          show " M < n0 \<and> M < n1 \<longrightarrow> (s \<oplus>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n0 n = (s \<oplus>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n1 n"
          proof
            assume A: "M < n0 \<and> M < n1 "
            have Fs: " s n0 n = s n1 n" using A M_def N1_def by auto
            have Ft: " t n0 n = t n1 n" using A M_def N2_def by auto
            then show "(s \<oplus>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n0 n = (s \<oplus>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n1 n"
              using seq_plus_simp[of s t] assms
              by (simp add: Fs is_Zp_cauchy_imp_closed residue_of_sum)
          qed
        qed
      qed
      then show ?thesis
        by blast
    qed
  qed
qed

lemma prod_of_Zp_cauchy_is_Zp_cauchy:
  assumes "is_Zp_cauchy s"
  assumes "is_Zp_cauchy t"
  shows "is_Zp_cauchy (s \<otimes>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t)"
proof(rule is_Zp_cauchyI)
  show "(s \<otimes>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) \<in> closed_seqs Zp"
    using assms(1) assms(2) is_Zp_cauchy_def seq_mult_closed by auto
  show "\<And>n. \<exists>N. \<forall>n0 n1. N < n0 \<and> N < n1 \<longrightarrow> (s \<otimes>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n0 n = (s \<otimes>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n1 n"
  proof-
    fix n
    show "\<exists>N. \<forall>n0 n1. N < n0 \<and> N < n1 \<longrightarrow> (s \<otimes>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n0 n = (s \<otimes>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n1 n"
    proof-
      obtain N1 where N1_def: "\<forall>n0 n1. N1 < n0 \<and> N1 < n1 \<longrightarrow> s n0 n = s n1 n"
        using assms(1) is_Zp_cauchy_imp_res_eventually_const_0 padic_integers_axioms by blast
      obtain N2 where N2_def: "\<forall>n0 n1. N2 < n0 \<and> N2 < n1 \<longrightarrow> t n0 n = t n1 n"
        using assms(2) is_Zp_cauchy_imp_res_eventually_const_0 padic_integers_axioms by blast
      obtain M where M_def: "M = max N1 N2"
        by simp
      have "\<forall>n0 n1. M < n0 \<and> M < n1 \<longrightarrow> (s \<otimes>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n0 n = (s \<otimes>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n1 n"
      proof
        fix n0
        show "\<forall>n1. M < n0 \<and> M < n1 \<longrightarrow> (s \<otimes>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n0 n = (s \<otimes>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n1 n"
        proof
          fix n1
          show " M < n0 \<and> M < n1 \<longrightarrow> (s \<otimes>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n0 n = (s \<otimes>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n1 n"
          proof
            assume A: "M < n0 \<and> M < n1 "
            have Fs: " s n0 n = s n1 n" using A M_def N1_def by auto
            have Ft: " t n0 n = t n1 n" using A M_def N2_def by auto
            then show "(s \<otimes>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n0 n = (s \<otimes>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> t) n1 n"
              using seq_mult_simp[of s t] is_Zp_cauchy_imp_closed assms
              by (simp add: Fs residue_of_prod)
          qed
        qed
      qed
      then show ?thesis
        by blast
    qed
  qed
qed

text\<open>Constant sequences are cauchy:\<close>

lemma constant_is_Zp_cauchy:
  assumes "is_constant_seq Zp s"
  shows "is_Zp_cauchy s"
proof(rule is_Zp_cauchyI)
  show "s \<in> closed_seqs Zp"
  proof(rule closed_seqs_memI)
    fix k
    show "s k \<in> carrier Zp"
      using assms is_constant_seq_imp_closed
      by (simp add: is_constant_seq_imp_closed closed_seqs_memE)
  qed
  obtain x where "\<And> k. s k = x"
    using assms
    by (meson is_constant_seqE)
  then show "\<And>n. \<exists>N. \<forall>n0 n1. N < n0 \<and> N < n1 \<longrightarrow> s n0 n = s n1 n"
    by simp
qed

text\<open>Scalar multiplies of cauchy sequences are cauchy:\<close>

lemma smult_is_Zp_cauchy:
  assumes "is_Zp_cauchy s"
  assumes "a \<in> carrier Zp"
  shows "is_Zp_cauchy (a \<odot>\<^bsub>Zp\<^bsup>\<omega>\<^esup>\<^esub> s)"
  apply(rule is_Zp_cauchyI)
  apply (meson U_function_ring.ring_seq_smult_closed U_function_ring_axioms assms(1) assms(2) is_Zp_cauchy_def)
  using assms ring_seq_smult_eval[of s a] is_Zp_cauchy_imp_closed[of s]
  by (metis res_lim_Zp_cauchy residue_of_prod)

lemma Zp_cauchy_imp_approaches_res_lim:
  assumes "is_Zp_cauchy s"
  assumes "a = res_lim s"
  obtains N where "\<And>n. n> N \<Longrightarrow> val_Zp (a \<ominus> (s n)) > eint k"
proof-
  have " (\<forall>n::int. \<exists>k. \<forall>m>k.  n < val_Zp_dist (s m) a)"
    using Zp_converges_to_def[of s a] assms is_Zp_cauchy_imp_has_limit[of s a] val_Zp_dist_def
    by simp
  then have "\<exists>N. \<forall>m>N.  k < val_Zp_dist (s m) a"
    by blast
  then obtain N where N_def: "\<forall>m>N.  k < val_Zp_dist (s m) a"
    by blast
  have "\<And>n. n> N \<Longrightarrow> val_Zp (a \<ominus> (s n)) > k"
  proof-
    fix m
    assume "m > N"
    then have 0: "k < val_Zp_dist (s m) a"
      using N_def
      by (simp add: val_Zp_def)
    show "k < val_Zp (a \<ominus> s m)"
      using "0" assms(1) assms(2) is_Zp_cauchy_def closed_seqs_memE[of _ Zp] val_Zp_dist_def val_Zp_dist_sym res_lim_in_Zp by auto
  qed
  then show ?thesis
    using that
    by blast
qed

(**************************************************************************************************)
(**************************************************************************************************)
(****************************)  section\<open>Continuous Functions\<close>  (***********************************)
(**************************************************************************************************)
(**************************************************************************************************)

text\<open>
  For convenience, we will use a slightly unorthodox definition of continuity here.
  Since $\mathbb{Z}_p$ is complete, a function is continuous if and only if its compositions
  with cauchy sequences are cauchy sequences. Thus we can define a continuous function on
  $\mathbb{Z}_p$ as a function which carries cauchy sequences to cauchy sequences under
  composition. Note that this does not generalize to a definition of continuity for functions
  defined on incomplete subsets of $\mathbb{Z}_p$. For example, the function $1/x$ defined on
  $\mathbb{Z}_p - \{0\}$ clearly does not have this property but is continuous. However, towards
  a proof of Hensel's Lemma we will only need to consider polynomial functions and so this
  definition suffices for our purposes.
\<close>

subsection\<open>Defining Continuous Functions and Basic Examples\<close>
abbreviation Zp_constant_function ("\<cc>\<^bsub>Zp\<^esub>") where
"\<cc>\<^bsub>Zp\<^esub> a \<equiv> constant_function (carrier Zp) a"

definition is_Zp_continuous ::"padic_int_fun \<Rightarrow> bool" where
"is_Zp_continuous f = (f \<in> carrier (Fun Zp) \<and>(\<forall> s. is_Zp_cauchy s \<longrightarrow> is_Zp_cauchy(f \<circ> s)))"

lemma Zp_continuous_is_Zp_closed:
  assumes "is_Zp_continuous f"
  shows "f \<in> carrier (Fun Zp)"
  using assms is_Zp_continuous_def by blast

lemma is_Zp_continuousI:
  assumes "f \<in> carrier (Fun Zp)"
  assumes "\<And>s. is_Zp_cauchy s \<Longrightarrow> is_Zp_cauchy (f \<circ> s)"
  shows "is_Zp_continuous f"
proof-
  have "(\<forall> s. is_Zp_cauchy s \<longrightarrow> is_Zp_cauchy(f \<circ> s))"
  proof
    fix s
    show "is_Zp_cauchy s \<longrightarrow> is_Zp_cauchy (f \<circ> s) "
      by (simp add: assms(2))
  qed
  then show ?thesis
    using assms(1) is_Zp_continuous_def by blast
qed

lemma Zp_continuous_is_closed:
  assumes "is_Zp_continuous f"
  shows "f \<in> carrier (Fun Zp)"
  using assms unfolding is_Zp_continuous_def by blast

lemma constant_is_Zp_continuous:
  assumes "a \<in> carrier Zp"
  shows "is_Zp_continuous (const a)"
proof(rule is_Zp_continuousI)
  show "\<cc>\<^bsub>Zp\<^esub> a \<in> carrier (function_ring (carrier Zp) Zp)"
    by (simp add: assms constant_function_closed)
  show "\<And>s. is_Zp_cauchy s \<Longrightarrow> is_Zp_cauchy (\<cc>\<^bsub>Zp\<^esub> a \<circ> s) "
  proof-
    fix s
    assume A: "is_Zp_cauchy s"
    have "is_constant_seq Zp (\<cc>\<^bsub>Zp\<^esub> a \<circ> s)"
      using constant_function_comp_is_constant_seq[of a s] A assms
        is_Zp_cauchy_imp_closed by blast
    then show "is_Zp_cauchy (\<cc>\<^bsub>Zp\<^esub> a \<circ> s)"
      using A assms  constant_is_Zp_cauchy
      by blast
  qed
qed

lemma sum_of_cont_is_cont:
  assumes "is_Zp_continuous f"
  assumes "is_Zp_continuous g"
  shows "is_Zp_continuous (f \<oplus>\<^bsub>Fun Zp\<^esub> g)"
  apply(rule is_Zp_continuousI)
  using assms Zp_continuous_is_closed assms function_sum_comp_is_seq_sum[of _ f g]
  apply (simp add: fun_add_closed)
  using assms(1) assms(2) function_sum_comp_is_seq_sum is_Zp_cauchy_def is_Zp_continuous_def sum_of_Zp_cauchy_is_Zp_cauchy by auto

lemma prod_of_cont_is_cont:
  assumes "is_Zp_continuous f"
  assumes "is_Zp_continuous g"
  shows "is_Zp_continuous (f \<otimes>\<^bsub>Fun Zp\<^esub> g)"
  apply(rule is_Zp_continuousI)
  using assms Zp_continuous_is_closed assms
  apply (simp add: fun_mult_closed)
  using  function_mult_comp_is_seq_mult[of _ f g] assms(1) assms(2) is_Zp_cauchy_imp_closed
    is_Zp_continuous_def prod_of_Zp_cauchy_is_Zp_cauchy by auto

lemma smult_is_continuous:
  assumes "is_Zp_continuous f"
  assumes "a \<in> carrier Zp"
  shows "is_Zp_continuous (a \<odot>\<^bsub>Fun Zp\<^esub> f)"
  apply(rule is_Zp_continuousI)
  using assms  apply (simp add: assms function_smult_closed is_Zp_continuous_def)
  using ring_seq_smult_comp_assoc assms
  by (simp add: is_Zp_cauchy_imp_closed is_Zp_continuous_def smult_is_Zp_cauchy)

lemma id_Zp_is_Zp_continuous:
"is_Zp_continuous ring_id"
  apply(rule is_Zp_continuousI)
  by (auto simp add: is_Zp_cauchy_imp_closed ring_id_seq_comp)

lemma nat_pow_is_Zp_continuous:
  assumes "is_Zp_continuous f"
  shows "is_Zp_continuous (f[^]\<^bsub>Fun Zp\<^esub>(n::nat))"
  apply(induction n)
  using constant_is_Zp_continuous function_one_is_constant apply force
  by (simp add: assms prod_of_cont_is_cont)

lemma ring_id_pow_closed:
"(ring_id)[^]\<^bsub>Fun Zp\<^esub> (n::nat) \<in> carrier (Fun Zp)"
  by (simp add: function_ring_is_monoid monoid.nat_pow_closed)

lemma monomial_equation:
  assumes "c \<in> carrier Zp"
  shows "monomial c n = c \<odot>\<^bsub>Fun Zp\<^esub> (ring_id)[^]\<^bsub>Fun Zp\<^esub>n"
  apply(rule function_ring_car_eqI)
    apply (simp add: assms monomial_functions)
  using assms function_smult_closed[of c "ring_id [^]\<^bsub>Fun Zp\<^esub> n"] ring_id_pow_closed apply blast
  unfolding monomial_function_def
  using assms function_smult_eval[of c "(ring_id)[^]\<^bsub>Fun Zp\<^esub> (n::nat)"]
        function_nat_pow_eval[of ring_id _ n]
  by (simp add: ring_id_eval ring_id_pow_closed)

lemma monomial_is_Zp_continuous:
  assumes "c \<in> carrier Zp"
  shows "is_Zp_continuous (monomial c n)"
  using monomial_equation[of c n] nat_pow_is_Zp_continuous
  by (simp add: assms id_Zp_is_Zp_continuous smult_is_continuous)

subsection\<open>Composition by a Continuous Function Commutes with Taking Limits of Sequences\<close>

text \<open>
  Due to our choice of definition for continuity, a little bit of care is required to show that
  taking the limit of a cauchy sequence commutes with composition by a continuous function.
  For a sequence $(s_n)_{n \in \mathbb{N}}$ converging to a point $t$, we can consider the
  alternating sequence $(s_0, t, s_1, t, s_2, t, \dots)$ which is also cauchy. Clearly
  composition with $f$ yields $(f(s_0), f(t), f(s_1), f(t), f(s_2), f(t), \dots)$ from which
  we can see that the limit must be $f(t)$.
\<close>
definition alt_seq where
"alt_seq s = (\<lambda>k. (if (even k) then (s k) else (res_lim s)))"

lemma alt_seq_Zp_cauchy:
  assumes "is_Zp_cauchy s"
  shows "is_Zp_cauchy (alt_seq s)"
proof(rule is_Zp_cauchyI)
  show "(alt_seq s) \<in> closed_seqs Zp"
    unfolding alt_seq_def using assms is_Zp_cauchy_imp_closed
    by (simp add: closed_seqs_memE closed_seqs_memI res_lim_in_Zp)
  fix n
  show "\<exists>N. \<forall>n0 n1. N < n0 \<and> N < n1 \<longrightarrow> alt_seq s n0 n = alt_seq s n1 n "
  proof-
    obtain N where N_def: " \<forall>n0 n1. N < n0 \<and> N < n1 \<longrightarrow> s n0 n =  s n1 n "
      using assms is_Zp_cauchy_imp_res_eventually_const_0
            padic_integers_axioms
      by blast
    have "\<forall>n0 n1. N < n0 \<and> N < n1 \<longrightarrow> alt_seq s n0 n = alt_seq s n1 n "
      apply auto
    proof-
      fix n0 n1
      assume A: "N < n0" "N < n1"
      show "alt_seq s n0 n = alt_seq s n1 n"
        using N_def
        unfolding alt_seq_def
        by (smt A(1) A(2) assms lessI max_less_iff_conj
            res_lim_Zp_cauchy padic_integers_axioms)
    qed
    then show ?thesis
      by blast
  qed
qed

lemma alt_seq_limit:
  assumes "is_Zp_cauchy s"
  shows "res_lim(alt_seq s) = res_lim s"
proof-
  have "\<And>k. res_lim(alt_seq s) k = res_lim s k"
  proof-
    fix k
    obtain N where N_def: "\<forall> m. m> N \<longrightarrow>  s m k = res_lim s k"
      using assms res_lim_Zp_cauchy
      by blast
    obtain N' where N'_def: "\<forall> m. m> N' \<longrightarrow>  (alt_seq s) m k = res_lim (alt_seq s) k"
      using assms res_lim_Zp_cauchy
            alt_seq_Zp_cauchy
      by blast
    have "\<And>m. m > (max N N') \<Longrightarrow> s m k = res_lim (alt_seq s) k"
    proof-
      fix m
      assume A0: "m > (max N N')"
      have A1: "s m k = res_lim s k"
        using A0 N_def
        by simp
      have A2: "(alt_seq s) m k = res_lim (alt_seq s) k"
        using A0 N'_def
        by simp
      have A3: "(alt_seq s) m k = res_lim s k"
        using alt_seq_def A1 A2
        by presburger
      show "s m k = res_lim (alt_seq s) k"
        using A1 A2 A3
        by auto
    qed
    then have P:"\<And>m. m > (max N N') \<Longrightarrow> (res_lim s k) = res_lim (alt_seq s) k"
      using N_def
      by auto
    show "res_lim(alt_seq s) k = res_lim s k"
      using P[of "Suc (max N N')"]
      by auto
  qed
  then show ?thesis
    by (simp add: ext)
qed

lemma res_lim_pushforward:
  assumes "is_Zp_continuous f"
  assumes "is_Zp_cauchy s"
  assumes "t = alt_seq s"
  shows "res_lim (f \<circ> t) = f (res_lim t)"
proof-
  have 0: "Zp_converges_to (f \<circ> t) (res_lim (f \<circ> t))"
    using assms alt_seq_Zp_cauchy is_Zp_cauchy_imp_has_limit
          is_Zp_continuous_def
    by blast
  have  "\<And>k. res_lim (f \<circ> t) k = f (res_lim t) k"
  proof-
    fix k
    show "res_lim (f \<circ> t) k = f (res_lim t) k"
    proof-
      obtain N where N_def: "\<And>m. m> N \<Longrightarrow> (f \<circ> t) m k = (res_lim (f \<circ> t)) k"
        using 0
        by (meson convergent_imp_Zp_cauchy Zp_converges_to_def res_lim_Zp_cauchy)
      obtain M where M_def: "M = 2*(Suc N) + 1"
        by simp
      have 0: "t M = res_lim s"
        using assms
        unfolding alt_seq_def
        by (simp add: M_def)
      have 1: "(f \<circ> t) M k = (res_lim (f \<circ> t)) k"
        using N_def M_def
        by auto
      have 2: "(f \<circ> t) M k = f (t M) k"
        by simp
      have 3: "(f \<circ> t) M k = f (res_lim s) k"
        using 0 2 by simp
      have 4: "(f \<circ> t) M k = f (res_lim t) k"
        using 3 assms alt_seq_limit[of s]
        by auto
      show ?thesis
        using 4 1 by auto
    qed
  qed
  then show ?thesis by(simp add: ext)
qed

lemma res_lim_pushforward':
  assumes "is_Zp_continuous f"
  assumes "is_Zp_cauchy s"
  assumes "t = alt_seq s"
  shows "res_lim (f \<circ> s) = res_lim (f \<circ> t)"
proof-
  obtain a where a_def: "a = res_lim (f \<circ> s)"
    by simp
  obtain b where b_def: "b = res_lim (f \<circ> t)"
    by simp
  have "\<And>k. a k = b k"
  proof-
    fix k
    obtain Na where Na_def: "\<And>m. m > Na \<Longrightarrow> (f \<circ> s) m k = a k"
      using a_def assms  is_Zp_continuous_def
            padic_integers_axioms res_lim_Zp_cauchy
      by blast
    obtain Nb where Nb_def: "\<And>m. m > Nb \<Longrightarrow> (f \<circ> t) m k = b k"
      using b_def assms is_Zp_continuous_def
            padic_integers_axioms res_lim_Zp_cauchy
            alt_seq_Zp_cauchy
      by blast
    obtain M where M_def: "M = 2*(max Na Nb) + 1"
      by simp
    have M0: "odd M"
      by (simp add: M_def)
    have M1: "M > Na"
      using M_def
      by auto
    have M2: "M > Nb"
      using M_def
      by auto
    have M3: "t M = res_lim s"
      using assms alt_seq_def M0
      by auto
    have M4: "((f \<circ> t) M) = f (res_lim s)"
      using M3
      by auto
    have M5: "((f \<circ> t) M) k = b k"
      using M2 Nb_def by auto
    have M6: "f (res_lim s) = f (res_lim t)"
      using assms alt_seq_limit[of s]
      by auto
    have M7: "f (res_lim t) k = b k"
      using M4 M5 M6 by auto
    have M8: "(f \<circ> s) M k = (f \<circ> s) (Suc M) k"
      using M1 Na_def by auto
    have M9: "(f \<circ> s) (Suc M) = (f \<circ> t) (Suc M)"
      using assms unfolding alt_seq_def
      using M_def
      by auto
    have M10: "(f \<circ> t) M k = (f \<circ> t) (Suc M) k"
      using M2 Nb_def by auto
    have M11: "(f \<circ> t) M k = (f \<circ> s) M k"
      using M10 M8 M9 by auto
    show "a k = b k"
      using M1 M11 M5 Na_def by auto
  qed
  then show ?thesis using a_def b_def ext[of a b] by auto
qed

lemma continuous_limit:
  assumes "is_Zp_continuous f"
  assumes "is_Zp_cauchy s"
  shows "Zp_converges_to (f \<circ> s) (f (res_lim s))"
proof-
  obtain t where t_def: "t = alt_seq s"
    by simp
  have 0: "Zp_converges_to (f \<circ> s) (res_lim (f \<circ> s))"
    using assms(1) assms(2) is_Zp_continuous_def
      is_Zp_cauchy_imp_has_limit padic_integers_axioms by blast
  have 1: "Zp_converges_to (f \<circ> s) (res_lim (f \<circ> t))"
    using "0" assms(1) assms(2) res_lim_pushforward' t_def by auto
  have 2: "Zp_converges_to (f \<circ> s) (f (res_lim t))"
    using "1" assms(1) assms(2) res_lim_pushforward padic_integers_axioms t_def by auto
  then show  "Zp_converges_to (f \<circ> s) (f (res_lim s))"
    by (simp add: alt_seq_limit assms(2) t_def)
qed

end
end


theory T144
imports Main
begin
lemma "(
(\<forall> x::nat. \<forall> y::nat. meet(x, y) = meet(y, x)) &
(\<forall> x::nat. \<forall> y::nat. join(x, y) = join(y, x)) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. meet(x, meet(y, z)) = meet(meet(x, y), z)) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. join(x, join(y, z)) = join(join(x, y), z)) &
(\<forall> x::nat. \<forall> y::nat. meet(x, join(x, y)) = x) &
(\<forall> x::nat. \<forall> y::nat. join(x, meet(x, y)) = x) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. mult(x, join(y, z)) = join(mult(x, y), mult(x, z))) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. mult(join(x, y), z) = join(mult(x, z), mult(y, z))) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. meet(x, over(join(mult(x, y), z), y)) = x) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. meet(y, undr(x, join(mult(x, y), z))) = y) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. join(mult(over(x, y), y), x) = x) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. join(mult(y, undr(y, x)), x) = x) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. mult(x, meet(y, z)) = meet(mult(x, y), mult(x, z))) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. over(join(x, y), z) = join(over(x, z), over(y, z))) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. undr(meet(x, y), z) = join(undr(x, z), undr(y, z))) &
(\<forall> x::nat. \<forall> y::nat. invo(join(x, y)) = meet(invo(x), invo(y))) &
(\<forall> x::nat. \<forall> y::nat. invo(meet(x, y)) = join(invo(x), invo(y))) &
(\<forall> x::nat. invo(invo(x)) = x)
) \<longrightarrow>
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. over(x, meet(y, z)) = join(over(x, y), over(x, z)))
"
nitpick[card nat=7,timeout=86400]
oops
end


theory T145
imports Main
begin
lemma "(
(\<forall> x::nat. \<forall> y::nat. meet(x, y) = meet(y, x)) &
(\<forall> x::nat. \<forall> y::nat. join(x, y) = join(y, x)) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. meet(x, meet(y, z)) = meet(meet(x, y), z)) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. join(x, join(y, z)) = join(join(x, y), z)) &
(\<forall> x::nat. \<forall> y::nat. meet(x, join(x, y)) = x) &
(\<forall> x::nat. \<forall> y::nat. join(x, meet(x, y)) = x) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. mult(x, join(y, z)) = join(mult(x, y), mult(x, z))) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. mult(join(x, y), z) = join(mult(x, z), mult(y, z))) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. meet(x, over(join(mult(x, y), z), y)) = x) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. meet(y, undr(x, join(mult(x, y), z))) = y) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. join(mult(over(x, y), y), x) = x) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. join(mult(y, undr(y, x)), x) = x) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. mult(meet(x, y), z) = meet(mult(x, z), mult(y, z))) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. undr(x, join(y, z)) = join(undr(x, y), undr(x, z))) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. over(join(x, y), z) = join(over(x, z), over(y, z))) &
(\<forall> x::nat. \<forall> y::nat. invo(join(x, y)) = meet(invo(x), invo(y))) &
(\<forall> x::nat. \<forall> y::nat. invo(meet(x, y)) = join(invo(x), invo(y))) &
(\<forall> x::nat. invo(invo(x)) = x)
) \<longrightarrow>
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. over(x, meet(y, z)) = join(over(x, y), over(x, z)))
"
nitpick[card nat=4,timeout=86400]
oops
end


theory T73
imports Main
begin
lemma "(
(\<forall> x::nat. \<forall> y::nat. meet(x, y) = meet(y, x)) &
(\<forall> x::nat. \<forall> y::nat. join(x, y) = join(y, x)) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. meet(x, meet(y, z)) = meet(meet(x, y), z)) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. join(x, join(y, z)) = join(join(x, y), z)) &
(\<forall> x::nat. \<forall> y::nat. meet(x, join(x, y)) = x) &
(\<forall> x::nat. \<forall> y::nat. join(x, meet(x, y)) = x) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. mult(x, join(y, z)) = join(mult(x, y), mult(x, z))) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. mult(join(x, y), z) = join(mult(x, z), mult(y, z))) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. meet(x, over(join(mult(x, y), z), y)) = x) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. meet(y, undr(x, join(mult(x, y), z))) = y) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. join(mult(over(x, y), y), x) = x) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. join(mult(y, undr(y, x)), x) = x) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. mult(meet(x, y), z) = meet(mult(x, z), mult(y, z))) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. undr(meet(x, y), z) = join(undr(x, z), undr(y, z))) &
(\<forall> x::nat. \<forall> y::nat. invo(join(x, y)) = meet(invo(x), invo(y))) &
(\<forall> x::nat. \<forall> y::nat. invo(meet(x, y)) = join(invo(x), invo(y))) &
(\<forall> x::nat. invo(invo(x)) = x)
) \<longrightarrow>
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. undr(x, join(y, z)) = join(undr(x, y), undr(x, z)))
"
nitpick[card nat=4,timeout=86400]
oops
end


(*  Title:      HOL/ex/Lagrange.thy
    Author:     Tobias Nipkow
    Copyright   1996 TU Muenchen
*)

section \<open>A lemma for Lagrange's theorem\<close>

theory Lagrange imports Main begin

text \<open>This theory only contains a single theorem, which is a lemma
in Lagrange's proof that every natural number is the sum of 4 squares.
Its sole purpose is to demonstrate ordered rewriting for commutative
rings.

The enterprising reader might consider proving all of Lagrange's
theorem.\<close>

definition sq :: "'a::times => 'a" where "sq x == x*x"

text \<open>The following lemma essentially shows that every natural
number is the sum of four squares, provided all prime numbers are.
However, this is an abstract theorem about commutative rings.  It has,
a priori, nothing to do with nat.\<close>

lemma Lagrange_lemma: fixes x1 :: "'a::comm_ring" shows
  "(sq x1 + sq x2 + sq x3 + sq x4) * (sq y1 + sq y2 + sq y3 + sq y4) =
   sq (x1*y1 - x2*y2 - x3*y3 - x4*y4)  +
   sq (x1*y2 + x2*y1 + x3*y4 - x4*y3)  +
   sq (x1*y3 - x2*y4 + x3*y1 + x4*y2)  +
   sq (x1*y4 + x2*y3 - x3*y2 + x4*y1)"
by (simp only: sq_def algebra_simps)

text \<open>A challenge by John Harrison. Takes about 12s on a 1.6GHz machine.\<close>

lemma fixes p1 :: "'a::comm_ring" shows
  "(sq p1 + sq q1 + sq r1 + sq s1 + sq t1 + sq u1 + sq v1 + sq w1) *
   (sq p2 + sq q2 + sq r2 + sq s2 + sq t2 + sq u2 + sq v2 + sq w2)
    = sq (p1*p2 - q1*q2 - r1*r2 - s1*s2 - t1*t2 - u1*u2 - v1*v2 - w1*w2) +
      sq (p1*q2 + q1*p2 + r1*s2 - s1*r2 + t1*u2 - u1*t2 - v1*w2 + w1*v2) +
      sq (p1*r2 - q1*s2 + r1*p2 + s1*q2 + t1*v2 + u1*w2 - v1*t2 - w1*u2) +
      sq (p1*s2 + q1*r2 - r1*q2 + s1*p2 + t1*w2 - u1*v2 + v1*u2 - w1*t2) +
      sq (p1*t2 - q1*u2 - r1*v2 - s1*w2 + t1*p2 + u1*q2 + v1*r2 + w1*s2) +
      sq (p1*u2 + q1*t2 - r1*w2 + s1*v2 - t1*q2 + u1*p2 - v1*s2 + w1*r2) +
      sq (p1*v2 + q1*w2 + r1*t2 - s1*u2 - t1*r2 + u1*s2 + v1*p2 - w1*q2) +
      sq (p1*w2 - q1*v2 + r1*u2 + s1*t2 - t1*s2 - u1*r2 + v1*q2 + w1*p2)"
by (simp only: sq_def algebra_simps)

end


(*
 * Copyright Data61, CSIRO (ABN 41 687 119 230)
 *
 * SPDX-License-Identifier: BSD-2-Clause
 *)

section \<open>Signed division on word\<close>

theory Signed_Division_Word
  imports "HOL-Library.Signed_Division" "HOL-Library.Word"
begin

instantiation word :: (len) signed_division
begin

lift_definition signed_divide_word :: \<open>'a::len word \<Rightarrow> 'a word \<Rightarrow> 'a word\<close>
  is \<open>\<lambda>k l. signed_take_bit (LENGTH('a) - Suc 0) k sdiv signed_take_bit (LENGTH('a) - Suc 0) l\<close>
  by (simp flip: signed_take_bit_decr_length_iff)

lift_definition signed_modulo_word :: \<open>'a::len word \<Rightarrow> 'a word \<Rightarrow> 'a word\<close>
  is \<open>\<lambda>k l. signed_take_bit (LENGTH('a) - Suc 0) k smod signed_take_bit (LENGTH('a) - Suc 0) l\<close>
  by (simp flip: signed_take_bit_decr_length_iff)

instance ..

end

lemma sdiv_word_def [code]:
  \<open>v sdiv w = word_of_int (sint v sdiv sint w)\<close>
  for v w :: \<open>'a::len word\<close>
  by transfer simp

lemma smod_word_def [code]:
  \<open>v smod w = word_of_int (sint v smod sint w)\<close>
  for v w :: \<open>'a::len word\<close>
  by transfer simp

lemma sdiv_smod_id:
  \<open>(a sdiv b) * b + (a smod b) = a\<close>
  for a b :: \<open>'a::len word\<close>
  by (cases \<open>sint a < 0\<close>; cases \<open>sint b < 0\<close>) (simp_all add: signed_modulo_int_def sdiv_word_def smod_word_def)

lemma signed_div_arith:
    "sint ((a::('a::len) word) sdiv b) = signed_take_bit (LENGTH('a) - 1) (sint a sdiv sint b)"
  apply transfer
  apply simp
  done

lemma signed_mod_arith:
    "sint ((a::('a::len) word) smod b) = signed_take_bit (LENGTH('a) - 1) (sint a smod sint b)"
  apply transfer
  apply simp
  done

lemma word_sdiv_div0 [simp]:
    "(a :: ('a::len) word) sdiv 0 = 0"
  apply (auto simp: sdiv_word_def signed_divide_int_def sgn_if)
  done

lemma word_sdiv_div_minus1 [simp]:
    "(a :: ('a::len) word) sdiv -1 = -a"
  apply (auto simp: sdiv_word_def signed_divide_int_def sgn_if)
  apply transfer
  apply simp
  apply (metis Suc_pred len_gt_0 signed_take_bit_eq_iff_take_bit_eq signed_take_bit_of_0 take_bit_of_0)
  done

lemmas word_sdiv_0 = word_sdiv_div0

lemma sdiv_word_min:
    "- (2 ^ (size a - 1)) \<le> sint (a :: ('a::len) word) sdiv sint (b :: ('a::len) word)"
  using sdiv_int_range [where a="sint a" and b="sint b"]
  apply auto
  apply (cases \<open>LENGTH('a)\<close>)
   apply simp_all
  apply transfer
  apply simp
  apply (rule order_trans)
   defer
   apply assumption
  apply simp
  apply (metis abs_le_iff add.inverse_inverse le_cases le_minus_iff not_le signed_take_bit_int_eq_self_iff signed_take_bit_minus)
  done

lemmas word_sdiv_numerals_lhs = sdiv_word_def[where v="numeral x" for x]
    sdiv_word_def[where v=0] sdiv_word_def[where v=1]

lemmas word_sdiv_numerals = word_sdiv_numerals_lhs[where w="numeral y" for y]
    word_sdiv_numerals_lhs[where w=0] word_sdiv_numerals_lhs[where w=1]

lemma smod_word_mod_0 [simp]:
  "x smod (0 :: ('a::len) word) = x"
  by (clarsimp simp: smod_word_def)

lemma smod_word_0_mod [simp]:
  "0 smod (x :: ('a::len) word) = 0"
  by (clarsimp simp: smod_word_def)

lemma smod_word_max:
  "sint (a::'a word) smod sint (b::'a word) < 2 ^ (LENGTH('a::len) - Suc 0)"
  apply (cases \<open>sint b = 0\<close>)
   apply (simp_all add: sint_less)
  apply (cases \<open>LENGTH('a)\<close>)
   apply simp_all
  using smod_int_range [where a="sint a" and b="sint b"]
  apply auto
  apply (rule less_le_trans)
   apply assumption
  apply (auto simp add: abs_le_iff)
   apply (metis diff_Suc_1 le_cases linorder_not_le sint_lt)
  apply (metis add.inverse_inverse diff_Suc_1 linorder_not_less neg_less_iff_less sint_ge)
  done

lemma smod_word_min:
  "- (2 ^ (LENGTH('a::len) - Suc 0)) \<le> sint (a::'a word) smod sint (b::'a word)"
  apply (cases \<open>LENGTH('a)\<close>)
   apply simp_all
  apply (cases \<open>sint b = 0\<close>)
   apply simp_all
   apply (metis diff_Suc_1 sint_ge)
  using smod_int_range [where a="sint a" and b="sint b"]
  apply auto
  apply (rule order_trans)
   defer
   apply assumption
  apply (auto simp add: algebra_simps abs_le_iff)
   apply (metis abs_zero add.left_neutral add_mono_thms_linordered_semiring(1) diff_Suc_1 le_cases linorder_not_less sint_lt zabs_less_one_iff)
  apply (metis abs_zero add.inverse_inverse add.left_neutral add_mono_thms_linordered_semiring(1) diff_Suc_1 le_cases le_minus_iff linorder_not_less sint_ge zabs_less_one_iff)
  done

lemma smod_word_alt_def:
  "(a :: ('a::len) word) smod b = a - (a sdiv b) * b"
  apply (cases \<open>a \<noteq> - (2 ^ (LENGTH('a) - 1)) \<or> b \<noteq> - 1\<close>)
   apply (clarsimp simp: smod_word_def sdiv_word_def signed_modulo_int_def
     simp flip: wi_hom_sub wi_hom_mult)
  apply (clarsimp simp: smod_word_def signed_modulo_int_def)
  done

lemmas word_smod_numerals_lhs = smod_word_def[where v="numeral x" for x]
    smod_word_def[where v=0] smod_word_def[where v=1]

lemmas word_smod_numerals = word_smod_numerals_lhs[where w="numeral y" for y]
    word_smod_numerals_lhs[where w=0] word_smod_numerals_lhs[where w=1]

end


theory Group_Example
imports MainRLT
begin

(* The original constant and properties, as discussed in Section 3.1.
The properties labeled (1), (2), (3) are here lemma1, lemma2 and lemma3. *)

thm eq_onp_def
thm perOfSet_def

definition group where
  "group tms e \<longleftrightarrow>
     (\<forall>x y z. tms (tms x y) z = tms x (tms y z)) \<and>
     (\<forall>x. tms x e = x \<and> tms e x = x) \<and>
     (\<forall>x. \<exists>y. tms x y = e \<and> tms y x = e)"

lemma lemma1: "group tms e \<longrightarrow> (\<forall>x y z. tms x y = tms x z \<longrightarrow> y = z)"
  unfolding group_def by metis

lemma lemma2: "group tms e \<longrightarrow> (\<forall>inv inv'. (\<forall>x. tms (inv x) x = e) \<and> (\<forall>x. tms (inv' x) x = e) \<longrightarrow> inv = inv')"
  unfolding group_def fun_eq_iff by metis

lemma lemma3_aux1:
  assumes "group tms e"
  shows "foldl tms x ys = tms x (foldl tms e ys)"
proof (induct ys arbitrary: x)
  case Nil
  with assms show ?case
    unfolding group_def by simp
next
  case (Cons y ys)
  from assms show ?case
    unfolding group_def foldl.simps o_def
    by (subst (1 2) Cons) auto
qed

lemma lemma3_aux2:
  assumes "group tms e"
  shows "foldl tms x (xs @ ys) = tms (foldl tms x xs) (foldl tms e ys)"
  by (induct xs) (auto intro: lemma3_aux1[OF assms])

lemma lemma3: "group tms e \<longrightarrow> (\<forall>xs ys. foldl tms e (xs @ ys) = tms (foldl tms e xs) (foldl tms e ys))"
  by (metis lemma3_aux2)

(* This command, RLTCST, read "relativize constant",
relativizes a constant -- here, the constat "group", which yields
the parametric constant "group_rlt":  *)
local_setup \<open>RLCST @{term group}\<close>

(* Here is the definition of group_rlt: *)
thm group_rlt_def

(* We obtain a more readable (and more usable) version of
this definition after applying some default simplification rules
for relativized connectives and quantifiers (referred to in the paper as
Connective & Quantifier Suitability):
*)

lemma group_rlt_alt:
  "neper R \<Longrightarrow> group_rlt R tms e \<longleftrightarrow>
    (\<forall>x y z. R x x \<and> R y y \<and> R z z \<longrightarrow> R (tms (tms x y) z) (tms x (tms y z))) \<and>
    (\<forall>x. R x x \<longrightarrow> R (tms x e) x \<and> R (tms e x) x) \<and>
    (\<forall>x. R x x \<longrightarrow> (\<exists>y. R y y \<and> R (tms x y) e \<and> R (tms y x) e))"
  unfolding group_rlt_def by auto

(* The notations from Section 3.1 (we use closed0 for constants
and closed2 for binary operators, whereas the paper uses the same notation for both): *)

definition "closed0 A x = (x \<in> A)"
definition "closed2 A f = (\<forall>x \<in> A. \<forall>y \<in> A. f x y \<in> A)"

(* Each set A gives rise to a PER, the equality of A.
In our formalization, we call it "perOfSet A", whereas in the paper
this is denoted by "eqOf A". *)
abbreviation "eqOf A \<equiv> perOfSet A"

lemma eqOf_alt: "eqOf A = eq_onp (\<lambda>x. x \<in> A)"
  unfolding perOfSet_def eq_onp_def by auto

lemma neper_eq_on: "closed0 A x \<Longrightarrow> neper (eqOf A)"
  by (meson closed0_def neper_def perOfSet_def per_perOfSet)

(* Set-based relativization is a particular case of PER relativization, via the
"eqOf" view of sets as PERs. This is illustrated next for "group_rlt", as discussed
in Section 4.3: *)
lemma group_rlt_set:
  assumes "closed0 A e" "closed2 A tms"
  shows "group_rlt (eqOf A) tms e \<longleftrightarrow>
    (\<forall>x \<in> A. \<forall>y \<in> A. \<forall>z \<in> A. tms (tms x y) z = tms x (tms y z)) \<and>
    (\<forall>x \<in> A. tms x e = x \<and> tms e x = x) \<and>
    (\<forall>x \<in> A. \<exists>y \<in> A. tms x y = e \<and> tms y x = e)"
  by (subst group_rlt_alt[OF neper_eq_on[OF assms(1)]])
    (insert assms, unfold closed0_def closed2_def perOfSet_def, meson)

(* This command, RLTTHM, read "relativize constant",
relativizes a theorem -- here, the theorem is "lemma1",
and relativization yields the theorem "lemma1_rlt":  *)
local_setup \<open>RLTHM @{binding lemma1_rlt} @{thm lemma1}\<close>

(* Again, the Connective & Quantifier Suitability simplification rules
are applied for turning it into a readable/usable version:  *)

lemma lemma1_rlt_readable:
  assumes [simp]: "neper R" and "R e e" "rel_fun R (rel_fun R R) tms tms"
  shows "group_rlt R tms e \<longrightarrow>
  (\<forall>x y z. R x x \<and> R y y \<and> R z z \<longrightarrow> R (tms x y) (tms x z) \<longrightarrow> R y z)"
  using lemma1_rlt[OF assms, simplified]
  by blast

(* As noted in the Recoverability (Meta)Theorem,
the relativized version recovers the original version of the theorem
as a particular instance, as discussed in Section 4.3: *)
lemmas lemma1_recovered = lemma1_rlt_readable[of "(=)",
  simplified rlt_eq relator_eq neper simp_thms True_implies_equals]

(* ... and it also implies the set-based version, as discussed in Section 4.3: *)
lemma lemma1_rlt_set_readable:
  assumes "closed0 A e" "closed2 A tms"
  shows "group_rlt (eqOf A) tms e \<longrightarrow> (\<forall>x \<in> A. \<forall>y \<in> A. \<forall>z \<in> A. tms x y = tms x z \<longrightarrow> y = z)"
  using lemma1_rlt_readable[OF neper_eq_on[OF assms(1)], of e tms] assms
  by (unfold perOfSet_def rel_fun_def closed2_def closed0_def) blast

(* The relativizaton of lemma2, along the same lines as that for lemma1: *)

local_setup \<open>RLTHM @{binding lemma2_rlt} @{thm lemma2}\<close>

lemma lemma2_rlt_readable:
  assumes [simp]: "neper R" and "R e e" "rel_fun R (rel_fun R R) tms tms"
  shows "group_rlt R tms e \<longrightarrow>
  (\<forall>inv inv'. rel_fun R R inv inv \<longrightarrow> rel_fun R R inv' inv' \<longrightarrow>
     (\<forall>x. R x x \<longrightarrow> R (tms (inv x) x) e) \<and> (\<forall>x. R x x \<longrightarrow> R (tms (inv' x) x) e) \<longrightarrow>
     rel_fun R R inv inv')"
  using lemma2_rlt[OF assms, simplified]
  by blast

(* ... and again the original lemma "recovered": *)

lemmas lemma2_recovered = lemma2_rlt_readable[of "(=)",
  simplified rlt_eq relator_eq neper simp_thms True_implies_equals]

(* ... and (more-generally) the set-based version inferred: *)

abbreviation "fun_set A B \<equiv> {f. pred_fun (\<lambda>x. x \<in> A) (\<lambda>x. x \<in> B) f}"

lemma rel_fun_eq_onp_self:
  "rel_fun (eq_onp A) (eq_onp B) f f = pred_fun A B f"
  by (auto simp: rel_fun_def eq_onp_def)

lemma lemma2_rlt_set_readable:
  assumes "closed0 A e" "closed2 A tms"
  shows "group_rlt (eqOf A) tms e \<longrightarrow>
    (\<forall>inv \<in> fun_set A A. \<forall>inv' \<in> fun_set A A. (\<forall>x \<in> A. tms (inv x) x = e) \<and> (\<forall>x \<in> A. tms (inv' x) x = e) \<longrightarrow> (\<forall>x \<in> A. inv x = inv' x))"
  using lemma2_rlt_readable[OF neper_eq_on[OF assms(1)], of e tms] assms
  unfolding rel_fun_eq_onp_self
  by (auto simp: rel_fun_def perOfSet_def closed0_def closed2_def)

(* Finally, the same happens for lemma3 where, as discussed in Section 6.1,
Compatibility and PER-Parametricity ensure that the relativization of the
already parametric constants such as @ (append) and foldl (fold left) is provably
equal to th original constants.
(list_all2 denotes the list relator, for which in the paper we simply write "list".) *)

local_setup \<open>RLTHM @{binding lemma3_rlt} @{thm lemma3}\<close>

lemma lemma3_rlt_readable:
  assumes [simp, THEN list.rrel_neper, simp]: "neper R" and "R e e" "rel_fun R (rel_fun R R) tms tms"
  shows "group_rlt R tms e \<longrightarrow>
  (\<forall>xs ys. list_all2 R xs xs \<longrightarrow> list_all2 R ys ys \<longrightarrow> R (foldl tms e (xs @ ys)) (tms (foldl tms e xs) (foldl tms e ys)))"
  using lemma3_rlt[OF assms, simplified]
  by (auto simp only: rrel_alt rlt_param neper assms(1))

lemmas lemma3_recovered = lemma3_rlt_readable[of "(=)",
  simplified rlt_eq relator_eq neper simp_thms True_implies_equals]

lemma lists_alt: "lists A = {xs. list_all (\<lambda>x. x \<in> A) xs}"
  by (auto simp: list_all_iff)

lemma lemma3_rlt_set_readable:
  assumes "closed0 A e" "closed2 A tms"
  shows "group_rlt (eqOf A) tms e \<longrightarrow>
    (\<forall>xs \<in> lists A. \<forall>ys \<in> lists A. foldl tms e (xs @ ys) = tms (foldl tms e xs) (foldl tms e ys))"
  using lemma3_rlt_readable[OF neper_eq_on[OF assms(1)], of e tms] assms
  unfolding eqOf_alt list.rel_eq_onp lists_alt
  by (auto simp: eq_onp_def  closed0_def closed2_def)

end