Theory Padic_Fields

theory Padic_Fields
  imports Fraction_Field Padic_Ints.Hensels_Lemma

begin


(**************************************************************************************************)
(**************************************************************************************************)
section‹Constructing the $p$-adic Valued Field›
(**************************************************************************************************)
(**************************************************************************************************)

text‹
  As a field, we can define the field $\mathbb{Q}_p$ immediately as the fraction field of 
  $\mathbb{Z}_p$. The valuation can then be extended from to $\mathbb{Z}_p$ to $\mathbb{Q}_p$ by 
  defining $\text{val}(a/b) = \text{val}\ a - \text{val}\ b$ where $a, b \in \mathbb{Z}_p$. ›

(**********************************************************************************************)
(**************************************************************************************************)
subsection‹A Locale for $p$-adic Fields›
(**************************************************************************************************)
(**************************************************************************************************)

text‹
  This section builds a locale for reasoning about general $p$-adic fields for a fixed $p$. 
  The locale fixes constants for the ring of $p$-adic integers ($\mathbb{Z}_p$) and the inclusion
   map $\iota: \mathbb{Z}_p \to \mathbb{Q}_p$. ›
type_synonym padic_number = "((nat  int) × (nat  int)) set"
locale padic_fields= 
fixes Qp:: "_ ring" (structure)
fixes Zp:: "_ ring" (structure)
fixes p
fixes ι
defines "Zp  padic_int p"
defines "Qp  Frac Zp"
defines "ι  domain_frac.inc Zp"
assumes prime: "prime p"

sublocale padic_fields < Zp?: domain_frac Zp
  by (simp add: Zp_def domain_frac.intro padic_int_is_domain prime)

sublocale padic_fields < Qp?: ring Qp
  unfolding Qp_def 
  by (simp add: Fraction_Field.domain_frac_def domain_axioms domain_frac.fraction_field_is_field field.is_ring)
 
sublocale padic_fields < Qp?: cring Qp
  unfolding Qp_def 
  by (simp add: Fraction_Field.domain_frac_def domain.axioms(1) domain_axioms domain_frac.fraction_field_is_domain)
 
sublocale padic_fields < Qp?: field Qp
  unfolding Qp_def 
  by (simp add: Fraction_Field.domain_frac_def domain_axioms domain_frac.fraction_field_is_field)

sublocale padic_fields < Qp?: domain Qp
  by (simp add: Qp.domain_axioms)

sublocale padic_fields <  padic_integers Zp  
apply (simp add: padic_integers_def prime) 
using Zp_def by auto

sublocale padic_fields < UPQ?: UP_cring Qp "UP Qp"
  using Qp.is_cring UP_cring_def apply blast
  by auto 

(**************************************************************************************************)
(**************************************************************************************************)
subsection‹The Valuation Ring in $\mathbb{Q}_p$›
(**************************************************************************************************)
(**************************************************************************************************)

text‹
  The valuation ring $\mathcal{O}_p$ is the subring of elements in $\mathbb{Q}_p$ with positive 
  valuation. It is an isomorphic copy of $\mathbb{Z}_p$.›
context padic_fields
begin

abbreviation 𝒪p where
"𝒪p  ι ` carrier Zp"

lemma inc_closed: 
  assumes "a  carrier Zp"
  shows "ι a  carrier Qp"
  using Qp_def ι_def assms Zp.inc_is_hom ring_hom_closed
  by fastforce

lemma inc_is_hom:
"ι  ring_hom Zp Qp"
  unfolding Qp_def ι_def  
by(rule Zp.inc_is_hom)

text‹An alternate formula of the map $\iota$›

lemma inc_def: 
  assumes "a  carrier Zp"
  shows "ι a = frac a 𝟭Zp⇙" 
  using assms inc_equation[of a] ι_def by auto

lemma inc_of_nonzero:
  assumes "a  nonzero Zp"
  shows "ι a  nonzero Qp"
  using  ι_def assms Qp_def Qp.nonzero_memI 
    Zp.nonzero_closed Zp.nonzero_one_closed frac_closed local.inc_def nonzero_fraction 
  by (metis Zp.nonzero_memE(2) inc_closed inc_inj1)
 
lemma inc_of_one:
"ι 𝟭Zp= 𝟭"
  by (simp add: inc_is_hom ring_hom_one)

lemma inc_of_zero:
"ι 𝟬Zp= 𝟬"
  apply(rule ring_hom_zero[of ι], rule inc_is_hom)
  apply (simp add: Zp.ring_axioms)
  by (simp add: Qp.ring_axioms)

lemma inc_of_sum:
  assumes "a  carrier Zp"
  assumes "b  carrier Zp"
  shows "ι (a Zpb) = (ι a)  (ι b)"
by(rule ring_hom_add[of _ Zp], rule inc_is_hom, rule assms, rule assms)

lemma inc_of_prod:
  assumes "a  carrier Zp"
  assumes "b  carrier Zp"
  shows "ι (a Zpb) = (ι a)  (ι b)"
  by (simp add: assms(1) assms(2) inc_is_hom ring_hom_mult)

lemma inc_pow:
  assumes "a  nonzero Zp"
  shows "ι (a[^]Zp(n::nat)) = (ι a)[^] n"
  apply(induction n)
  apply (simp add: inc_of_one)
  by (simp add: assms inc_of_prod Zp.nonzero_closed)

lemma inc_of_diff:
  assumes "a  carrier Zp"
  assumes "b  carrier Zp"
  shows "ι (a Zpb) = (ι a)  (ι b)"
  using assms unfolding a_minus_def 
  using inc_is_hom Qp.ring_axioms Qp_def Zp.ring_hom_a_inv inc_of_sum by fastforce  

lemma Units_nonzero_Qp:
assumes "u  Units Qp"
shows "u  nonzero Qp"
  by (simp add: Qp.Units_nonzero assms) 

lemma Units_eq_nonzero:
 "Units Qp = nonzero Qp"
  using frac_nonzero_Units unfolding Qp_def Zp_def 
by blast 

lemma Units_inverse_Qp:
  assumes "u  Units Qp"
  shows "invQpu  Units Qp"
  using Qp_def Units_eq_nonzero assms frac_nonzero_inv_Unit by auto
  
lemma nonzero_inverse_Qp:
  assumes "u  nonzero Qp"
  shows "invQpu  nonzero Qp"
  using Units_eq_nonzero Units_inverse_Qp assms by auto  

lemma frac_add:
  assumes "a  carrier Zp"
  assumes "b  nonzero Zp"
  assumes "c  carrier Zp"
  assumes "d  nonzero Zp"
  shows "(frac a b)  (frac c d) = (frac ((a Zpd) Zp(b Zpc)) (b Zpd))"
  by (simp add: Qp_def assms(1) assms(2) assms(3) assms(4) local.frac_add)

lemma frac_add_common_denom:
  assumes "a  carrier Zp"
  assumes "b  carrier Zp"
  assumes "c  nonzero Zp"
  shows "(frac a c)  (frac b c) = frac (a Zpb) c"
  by (simp add: Qp_def assms(1) assms(2) assms(3) frac_add_common_denom)

lemma frac_mult:
  assumes "a  carrier Zp"
  assumes "b  nonzero Zp"
  assumes "c  carrier Zp"
  assumes "d  nonzero Zp"
  shows "(frac a b)  (frac c d) = (frac (a Zpc) (b Zpd))"
  by (simp add: Qp_def assms(1) assms(2) assms(3) assms(4) frac_mult)

lemma frac_one:
  assumes "a  nonzero Zp"
  shows "frac a a = 𝟭"
  by (simp add: Qp_def assms frac_one)

lemma frac_closed:
  assumes "a  carrier Zp"
  assumes "b  nonzero Zp"
  shows "frac a b  carrier Qp"
  by (simp add: Qp_def assms(1) assms(2) frac_closed)  

lemma inv_in_frac:
  assumes "a  carrier Qp"
  assumes "a 𝟬"
  shows "invQpa  carrier Qp"
        "invQpa 𝟬"
        "invQpa  nonzero Qp"
  apply (simp add: assms(1) assms(2) field_inv(3))
    using assms(1) assms(2) field_inv(1) apply fastforce
      using Qp.not_nonzero_memE assms(1) assms(2) nonzero_inverse_Qp by blast

lemma nonzero_numer_imp_nonzero_fraction:
  assumes "a  nonzero Zp"
  assumes "b  nonzero Zp"
  shows "frac a b  𝟬"
  by (simp add: Qp_def assms(1) assms(2) nonzero_fraction)

lemma nonzero_fraction_imp_numer_not_zero:
  assumes "a  carrier Zp"
  assumes "b  nonzero Zp"
  assumes "frac a b  𝟬"
  shows "a  𝟬Zp⇙"
  using assms fraction_zero Qp_def by blast

lemma nonzero_fraction_imp_nonzero_numer:
  assumes "a  carrier Zp"
  assumes "b  nonzero Zp"
  assumes "frac a b  𝟬"
  shows "a  nonzero Zp"
  using assms(1) assms(2) assms(3) nonzero_fraction_imp_numer_not_zero not_nonzero_Zp by blast

lemma(in padic_fields) frac_inv_id:
  assumes "a  nonzero Zp"
  assumes "b  nonzero Zp" 
  assumes "c  nonzero Zp"
  assumes "d  nonzero Zp" 
  assumes "frac a b = frac c d"
  shows "frac b a = frac d c"
  using frac_inv assms  
  by metis  

lemma(in padic_fields) frac_uminus:
  assumes "a  carrier Zp"
  assumes "b  nonzero Zp"
  shows " (frac a b) = frac (Zpa) b" 
  by (simp add: Qp_def assms(1) assms(2) frac_uminus)

lemma(in padic_fields) i_mult:
  assumes "a  carrier Zp"
  assumes "c  carrier Zp"
  assumes "d  nonzero Zp"
  shows "(ι a)  (frac c d) = frac (a Zpc) d"
  by (simp add: Qp_def ι_def assms(1) assms(2) assms(3) i_mult)

lemma numer_denom_facts:
  assumes "a  carrier Qp"
  shows "(numer a)  carrier Zp"
        "(denom a)  nonzero Zp"
        "a  𝟬  numer a  𝟬Zp⇙"
        "a  (ι (denom a)) = ι (numer a)"
        "a = frac (numer a) (denom a)" 
  unfolding Qp_def
  using Qp_def assms numer_denom_facts(2) apply auto[1]
    using Qp_def assms numer_denom_facts(3) apply blast
      using Qp_def assms numer_denom_facts(4) apply blast
        using Qp_def ι_def assms numer_denom_facts(5) apply auto[1]
          using Qp_def assms numer_denom_facts(1) by auto

lemma get_common_denominator:
  assumes "x  carrier Qp"
  assumes "y  carrier Qp"
  obtains a b c where
    "a  carrier Zp"
    "b  carrier Zp" 
    "c  nonzero Zp"
    "x = frac a c"
    "y = frac b c"
  using Qp_def assms(1) assms(2) common_denominator[of x y]
  by blast  

abbreviation fract :: "_  _  _" (infixl "÷" 50) where
"(fract a b)  (a  (invQpb))"

text‹fract generalizes frac›

lemma fract_frac:
  assumes "a  carrier Zp"
  assumes "b  nonzero Zp"
  shows "(frac a b) = (ι a ÷ ι b)" 
proof-
  have B: "b  carrier Zp" 
    using Zp.nonzero_closed assms(2) by auto    
  have P0:"(invQp(ι b)) = frac 𝟭Zpb" 
    by (simp add: B Qp_def Zp.nonzero_one_closed assms(2) frac_inv local.inc_def)
  have P1: "(frac a b) = (ι a)  (frac 𝟭Zpb)"
    by (simp add: assms(1) assms(2) i_mult)    
  show ?thesis 
    by (simp add: P0 P1)
qed

lemma frac_eq:
  assumes "a  nonzero Zp"
  assumes "b  nonzero Zp"
  assumes "frac a b = 𝟭"
  shows "a = b"
proof-
  have "frac a b = frac b b"
    by (simp add: assms(2) assms(3) frac_one)
  then have "frac a 𝟭Zp= frac b 𝟭Zp⇙"
    using assms 
    by (metis (no_types, lifting) Zp.nonzero_closed 
        Zp.nonzero_one_closed frac_eqE frac_eqI')
  then show ?thesis
    using ι_def assms(1) assms(2) inc_inj2 local.inc_def 
    by (simp add: Zp.nonzero_closed)
qed

lemma fract_cancel_right:
  assumes "a  carrier Qp"
  assumes "b  nonzero Qp"
  shows "b  (a ÷ b) = a"
  by (simp add: Qp.Units_closed Qp.m_lcomm Units_eq_nonzero assms(1)
      assms(2))
  
lemma fract_cancel_left:
  assumes "a  carrier Qp"
  assumes "b  nonzero Qp"
  shows "(a ÷ b)  b = a"
  by (simp add: Qp.m_comm Qp.nonzero_closed assms(1) assms(2) 
      local.fract_cancel_right nonzero_inverse_Qp)
  
lemma fract_mult:
  assumes "a  carrier Qp"
  assumes "b  nonzero Qp"
  assumes "c  carrier Qp"
  assumes "d  nonzero Qp"
  shows  "(a ÷ b)  (c ÷ d) = ((a  c)÷ (b  d))"
  using Qp_def assms(1) assms(2) assms(3) assms(4) 
  by (simp add: fract_mult)
  
lemma Qp_nat_pow_nonzero:
  assumes "x  nonzero Qp"
  shows "x[^](n::nat)  nonzero Qp"
  using Qp.Units_pow_closed Units_eq_nonzero assms by auto

lemma Qp_nonzero_nat_pow:
  assumes "x  carrier Qp"
  assumes "n > 0"
  assumes "x[^](n::nat)  nonzero Qp"
  shows "x  nonzero Qp"
  using Frac_nonzero_nat_pow Qp_def assms(1) assms(2) assms(3) by blast
  
lemma Qp_int_pow_nonzero:
  assumes "x  nonzero Qp"
  shows "x[^](n::int)  nonzero Qp"
  using Frac_int_pow_nonzero Qp_def assms by blast

lemma Qp_nonzero_int_pow:
  assumes "x  carrier Qp"
  assumes "n > 0"
  assumes "x[^](n::int)  nonzero Qp"
  shows "x  nonzero Qp"
  using Frac_nonzero_int_pow Qp_def assms 
  by auto 

lemma pow_p_frac_0:
  assumes "(m::int)  n"
  assumes "n 0"
  shows "(frac (𝗉[^]Zpm) (𝗉[^]Zpn)) = ι (𝗉[^]Zp(m-n))"
proof-
  have 0: "𝗉carrier Zp" 
    by (simp add: Zp.nat_inc_closed) 
  have 1: "m - n 0" 
    using assms(1) by auto 
  have 2: "nat (m - n) + (nat n) = nat m" 
    using "1" assms(2) by linarith 
  have 3: "m 0" 
    using assms by auto
  then have "(𝗉[^]Zp(nat (m-n))) Zp(𝗉[^]Zp(nat n)) = (𝗉[^]Zp(nat m))" 
    by (simp add: "2" p_natpow_prod)
  then have "(𝗉[^]Zp(m-n)) Zp(𝗉[^]Zpn) = (𝗉[^]Zpm)" 
    using int_pow_int 1 3 assms(2) int_nat_eq by metis  
  then have P0: "(frac (𝗉[^]Zpm) (𝗉[^]Zpn)) = frac ((𝗉[^]Zp(m-n))Zp(𝗉[^]Zpn)) (𝗉[^]Zpn)"
    by simp 
  have "𝗉 carrier Zp" 
    by (simp add: "0") 
  have "(𝗉[^]Zp(nat n)) = [(p^(nat n))] Zp𝟭Zp⇙"
    by (simp add: p_pow_rep0) 
  then have "(𝗉[^]Zp(nat n))  carrier Zp" 
    by (simp add: Zp_nat_inc_closed) 
  then have "(𝗉[^]Zpn)  carrier Zp" 
    using assms(2) by (metis int_nat_eq int_pow_int) 
  then have P1: "(frac (𝗉[^]Zpm) (𝗉[^]Zpn)) = frac ((𝗉[^]Zp(m-n))Zp(𝗉[^]Zpn)) ((𝟭ZpZp(𝗉[^]Zpn)))"
    by (simp add: [p] Zp𝟭Zp[^]Zp(m - n) Zp[p] Zp𝟭Zp[^]Zpn = [p] Zp𝟭Zp[^]Zpm)  
  have P2: "(𝗉[^]Zp(m-n))  carrier Zp" 
    using "1" p_pow_car by blast 
  have P3: "(𝗉[^]Zpn)  carrier Zp" 
    using 𝗉 [^]Zpn  carrier Zp
    by blast 
  have P4: "(𝗉[^]Zpn)  nonzero Zp" 
    using assms(2) p_int_pow_nonzero 
    by blast 
  have P5: "𝟭Zp nonzero Zp" 
    using nonzero_def 
    by (simp add: Zp.nonzero_one_closed)   
  have "(frac (𝗉[^]Zp(m-n)) 𝟭Zp)  (frac (𝗉[^]Zpn) (𝗉[^]Zpn)) 
        = frac ((𝗉[^]Zp(m-n))Zp(𝗉[^]Zpn)) ((𝟭ZpZp(𝗉[^]Zpn)))"
    by (simp add: P2 P3 P4 Zp.nonzero_one_closed local.frac_mult)    
  then have "frac ((𝗉[^]Zp(m-n))Zp(𝗉[^]Zpn)) ((𝟭ZpZp(𝗉[^]Zpn))) = (frac (𝗉[^]Zp(m-n)) 𝟭Zp) "
    by (simp add: P2 P4 Zp.nonzero_one_closed frac_cancel_lr mult_comm)  
  then have P6: "(frac (𝗉[^]Zpm) (𝗉[^]Zpn)) = (frac (𝗉[^]Zp(m-n)) 𝟭Zp) " 
    using P1 by blast 
  have "(frac (𝗉[^]Zp(m-n)) 𝟭Zp) = ι (𝗉[^]Zp(m-n))" 
    using inc_def  by (simp add: P2) 
  then show ?thesis 
    using P6 by blast
qed

lemma pow_p_frac:
  assumes "(m::int)  n"
  assumes "m 0"
  shows "(frac (𝗉[^]Zpm) (𝗉[^]Zpn)) = frac 𝟭Zp(𝗉[^]Zp(n-m))"
proof-
  have "(frac (𝗉[^]Zpn) (𝗉[^]Zpm)) = ι (𝗉[^]Zp(n-m))" 
    by (simp add: assms(1) assms(2) pow_p_frac_0) 
  then have P0:"(frac (𝗉[^]Zpn) (𝗉[^]Zpm)) = frac (𝗉[^]Zp(n-m)) 𝟭Zp⇙"
   by (simp add: assms(1) local.inc_def p_pow_car)   
  have P1: "𝟭Zpnonzero Zp" 
    by (simp add: Zp.nonzero_one_closed)
  have P2: "𝗉[^]Zpn  nonzero Zp"
    using assms(1) assms(2) p_int_pow_nonzero by auto
  have P3: "𝗉[^]Zpm  nonzero Zp" 
    by (simp add: assms(2) p_int_pow_nonzero)    
  have P4: "(𝗉[^]Zp(n-m))  nonzero Zp" 
    by (simp add: assms(1) p_int_pow_nonzero)
  show " frac (𝗉[^]Zpm) (𝗉[^]Zpn) = frac 𝟭Zp(𝗉[^]Zp(n-m))"
    using P0 P1 P2 P3 P4 p_pow_nonzero 
    by (meson local.frac_inv_id)   
qed

text‹The copy of the prime p› living in $\mathbb{Q}_p$:›

abbreviation 𝔭 where
"𝔭  [p] Qp𝟭"

lemma(in domain_frac) frac_inc_of_nat:
"Frac_inc R ([(n::nat)] 𝟭) = [n]Frac R𝟭Frac R⇙"
  by (simp add: inc_equation nat_inc_rep)

lemma inc_of_nat:
"(ι ([(n::nat)]Zp𝟭Zp)) = [n]Qp𝟭"
  unfolding Qp_def ι_def
  using  frac_inc_of_nat[of n]
  by auto 
  
lemma(in domain_frac) frac_inc_of_int:
"Frac_inc R ([(n::int)] 𝟭) = [n]Frac R𝟭Frac R⇙"
  apply(induction n)
  apply (simp add: add_pow_int_ge inc_equation nat_inc_rep)
    by (simp add: add_pow_int_lt frac_uminus inc_equation nat_inc_rep nonzero_one_closed)

lemma inc_of_int:
"(ι ([(n::int)]Zp𝟭Zp)) = [n]Qp𝟭"
  unfolding Qp_def ι_def
  using  frac_inc_of_int[of n]
  by auto 
  
lemma p_inc:
"𝔭 = ι 𝗉"
  by (simp add: inc_of_int)

lemma p_nonzero:
"𝔭  nonzero Qp"
  using Zp_def Zp_nat_inc_closed inc_of_nonzero ord_Zp_p p_inc 
    p_nonzero by auto
 
lemma p_natpow_inc:
  fixes n::nat
  shows "𝔭[^]n = ι (𝗉 [^]Zpn)"
  by (simp add: Qp.int_nat_pow_rep inc_of_int p_pow_rep0)

lemma p_intpow_inc:
  fixes n::int
  assumes "n 0"
  shows "𝔭[^]n = ι (𝗉 [^]Zpn)"
  using p_natpow_inc  
  by (metis assms int_nat_eq int_pow_int)

lemma p_intpow:
  fixes n::int
  assumes "n < 0"
  shows "𝔭[^]n = (frac 𝟭Zp(𝗉 [^]Zp(-n)))"
proof-
  have U0: "(𝔭 [^] (nat (-n)))  Units Qp" 
    using Qp.Units_pow_closed Units_eq_nonzero p_nonzero by blast   
  have E0: "(𝔭 [^] (nat (-n))) = (𝔭 [^] (-n))" 
    using assms  by (simp add: int_pow_def nat_pow_def)
  then have U1: "(𝔭 [^]  (-n))  Units Qp" using U0 
    by simp
  have "(𝔭[^]n) = invQp(𝔭 [^] (nat (-n)))"
    using assms by (simp add: int_pow_def nat_pow_def)
  then have "(𝔭[^]n) = invQp(𝔭 [^] (-n))" 
    using E0 by simp
  then have "(𝔭[^]n) = invQpι (𝗉 [^]Zp(-n))" 
    using assms p_intpow_inc by auto
  then have E1: "(𝔭[^]n) = invQpfrac (𝗉 [^]Zp(-n)) 𝟭Zp⇙"
    using assms local.inc_def p_pow_car by auto
  have A: "(𝗉 [^]Zp(-n))  nonzero Zp"
    using assms p_pow_nonzero  p_int_pow_nonzero 
    by auto 
  then show ?thesis 
    using A frac_inv inc_def E1 
    by (simp add: Qp_def Zp.nonzero_one_closed)
qed

lemma p_natpow_closed[simp]:
  fixes n::nat
  shows "(𝔭[^]n)  (carrier Qp)"
        "(𝔭[^]n)  (nonzero Qp)"
  apply blast 
    using Qp_nat_pow_nonzero p_nonzero by blast
  
lemma nonzero_int_pow_distrib:
  assumes "a  nonzero Qp"
  assumes "b  nonzero Qp"
  shows "(a  b) [^](k::int) = a[^]k  b[^]k"
proof(induction k)
  case (nonneg n)
  then show ?case using pow_nat[of n _ Qp] 
    by (smt Qp.nat_pow_distrib Qp.nonzero_closed assms(1) assms(2) int_pow_int)
next
  case N: (neg n)
  have "a  b  Units Qp"
    using assms Units_eq_nonzero by blast  
  hence "(a  b) [^] - int (Suc n) = inv ((a  b) [^] (Suc n))"
     by (metis Qp.int_pow_inv' int_pow_int)
   then show ?case using 
       Qp.int_pow_inv' Qp.int_pow_unit_closed Qp.inv_of_prod[of "a[^]Suc n" "b[^]Suc n"] 
       Qp.nat_pow_distrib Qp.nonzero_closed Units_eq_nonzero assms(1) assms(2) int_pow_int  by metis
qed

lemma val_ring_subring:
"subring 𝒪p Qp"
  using Qp_def ι_def inc_im_is_subring by blast

lemma val_ring_closed: 
"𝒪p  carrier Qp"      
  by (simp add: subringE(1) val_ring_subring)

lemma p_pow_diff: 
  fixes n::int 
  fixes m::int 
  assumes "n 0"
  assumes "m 0"
  shows "𝔭 [^] (n - m) = frac (𝗉[^]Zpn) (𝗉[^]Zpm)"
proof-
  have 0: "comm_monoid Qp"
    by (simp add: Qp.comm_monoid_axioms)
  have 1: "𝔭  Units Qp"
    using Units_eq_nonzero p_nonzero 
    by blast
  have 2: "𝔭 [^] (n - m) = (𝔭[^]n)  (𝔭 [^] -m)"
    by (metis "1" Qp.int_pow_add diff_conv_add_uminus)    
  have 3: "𝔭 [^] (n - m) = (𝔭[^]n)  invQp(𝔭 [^] m)"
    by (simp add: "1" "2" Qp.int_pow_inv')  
  then show ?thesis using assms 
    using fract_frac p_int_pow_nonzero p_intpow_inc p_pow_car by presburger
qed

lemma Qp_int_pow_add: 
  fixes n::int 
  fixes m::int
  assumes "a  nonzero Qp"
  shows "a [^] (n + m) = (a [^] n)  (a [^] m)"
  using monoid.int_pow_add[of Qp a n m] Units_eq_nonzero assms 
  by (simp add: Qp.monoid_axioms)
  
lemma Qp_nat_pow_pow: 
  fixes n::nat 
  fixes m::nat
  assumes "a  carrier Qp"
  shows "(a[^](n*m)) = ((a[^]n)[^]m)"
  by (simp add: Qp.nat_pow_pow assms)
  
lemma Qp_p_nat_pow_pow: 
  fixes n::nat 
  fixes m::nat
  shows "(𝔭 [^] (n*m)) = ((𝔭[^]n)[^]m)"
  using Qp_nat_pow_pow 
  by simp
  
lemma Qp_units_int_pow:
  fixes n::int
  assumes "a  nonzero Qp"
  shows "a[^]n = a[^]units_of Qpn"
  apply(cases "n  0")
  using monoid.units_of_pow[of Qp]
   apply (metis int_pow_def2 mult_of_is_Units nat_pow_mult_of not_le)
    by (metis Qp.Units_pow_closed Qp.units_of_inv Units_eq_nonzero assms int_pow_def2 mult_of_is_Units nat_pow_mult_of)
 
lemma Qp_int_pow_pow: 
  fixes n::int
  fixes m::int
  assumes "a  nonzero Qp"
  shows "(a[^](n*m)) = ((a[^]n)[^]m)"
proof-
  have 0: "a  carrier (units_of Qp)"
    by (simp add: Units_eq_nonzero assms units_of_carrier)
  have "group (units_of Qp)"
    using  monoid.units_group Qp.units_group 
    by blast 
  then show ?thesis 
    using 0 group.int_pow_pow[of "units_of Qp"] Qp_int_pow_nonzero Qp_units_int_pow assms 
    by auto
qed

lemma Qp_p_int_pow_pow: 
  fixes n::int
  fixes m::int
  shows "(𝔭 [^] (n*m)) = ((𝔭[^]n)[^]m)"
  using Qp_int_pow_pow p_nonzero by blast
  
lemma Qp_int_nat_pow_pow: 
  fixes n::int
  fixes m::nat
  assumes "a  nonzero Qp"
  shows "(a[^](n*m)) = ((a[^]n)[^]m)"
  by (simp add: Qp_int_pow_pow assms int_pow_int)

lemma Qp_p_int_nat_pow_pow: 
  fixes n::int
  fixes m::nat
  shows "(𝔭 [^] (n*m)) = ((𝔭[^]n)[^]m)"
  by (simp add: Qp_int_nat_pow_pow p_nonzero)

lemma Qp_nat_int_pow_pow: 
  fixes n::nat
  fixes m::int
  assumes "a  nonzero Qp"
  shows "(a[^](n*m)) = ((a[^]n)[^]m)"
  by (simp add: Qp_int_pow_pow assms int_pow_int)

lemma Qp_p_nat_int_pow_pow: 
  fixes n::nat
  fixes m::int
  shows "(𝔭 [^] (n*m)) = ((𝔭[^]n)[^]m)"
  by (simp add: Qp_nat_int_pow_pow p_nonzero)

lemma p_intpow_closed:
  fixes n::int
  shows "(𝔭[^]n)  (carrier Qp)"
        "(𝔭[^]n)  (nonzero Qp)"
  apply (simp add: Qp.nonzero_closed Qp_int_pow_nonzero p_nonzero)
    by (simp add: Qp_int_pow_nonzero p_nonzero)
  
lemma p_intpow_add:
  fixes n::int 
  fixes m::int
  shows "𝔭 [^] (n + m) = (𝔭 [^] n)  (𝔭 [^] m)"
  using Qp_int_pow_add p_nonzero by blast

lemma p_intpow_inv:
  fixes n::int
  shows  "(𝔭 [^] n)  (𝔭 [^] -n) = 𝟭"
  using Units_eq_nonzero monoid.int_pow_inv'[of Qp 𝔭 n] 
  by (metis add.right_inverse int_pow_0 p_intpow_add)
    
lemma p_intpow_inv':
  fixes n::int
  shows  "(𝔭 [^] -n)  (𝔭 [^] n) = 𝟭"
  using p_intpow_inv 
  by (metis add.commute p_intpow_add)

lemma p_intpow_inv'':
  fixes n::int
  shows "(𝔭 [^] -n) = invQp(𝔭 [^] n)"
  by (simp add: Qp.int_pow_inv' Units_eq_nonzero p_nonzero)

lemma p_int_pow_factor_int_pow:
  assumes "a  nonzero Qp"
  shows "(𝔭[^](n::int)  a)[^](k::int) = 𝔭[^](n*k)  a[^]k"
  using assms nonzero_int_pow_distrib p_intpow_closed(2) Qp_p_int_pow_pow by presburger

lemma p_nat_pow_factor_int_pow:
  assumes "a  nonzero Qp"
  shows "(𝔭[^](n::nat)  a)[^](k::int) = 𝔭[^](n*k)  a[^]k"
  using assms  Qp_p_int_nat_pow_pow p_natpow_closed(1) 
  by (metis int_pow_int p_int_pow_factor_int_pow)

lemma p_pow_factor:
"𝔭[^]((int N)*l  + k) = (𝔭[^]l)[^](N::nat)  𝔭[^] k"
  by (metis Qp_p_int_nat_pow_pow mult_of_nat_commute p_intpow_add)

lemma p_nat_pow_factor_nat_pow:
  assumes "a  carrier Qp"
  shows "(𝔭[^](n::nat)  a)[^](k::nat) = 𝔭[^](n*k)  a[^]k"
  using Qp.nat_pow_distrib Qp_p_nat_pow_pow assms p_natpow_closed(1) by presburger

lemma p_int_pow_factor_nat_pow:
  assumes "a  carrier Qp"
  shows "(𝔭[^](n::int)  a)[^](k::nat) = 𝔭[^](n*k)  a[^]k"
  using assms Qp.nat_pow_distrib Qp_p_int_nat_pow_pow p_intpow_closed(1) by presburger

lemma(in ring) r_minus_distr:
  assumes "a  carrier R"
  assumes "b  carrier R"
  assumes "c  carrier R"
  shows "a  b  a  c = a  (b  c)"
  using assms 
  unfolding a_minus_def  
  by (simp add: r_distr r_minus)


(**************************************************************************************************)
(**************************************************************************************************)
subsection‹The Valuation on $\mathbb{Q}_p$›
(**************************************************************************************************)
(**************************************************************************************************)

      (********************************************************************************************)
      (********************************************************************************************)
      subsubsection‹Extending the Valuation from $\mathbb{Z}_p$ to $\mathbb{Q}_p$›
      (********************************************************************************************)
      (********************************************************************************************)

text‹
  The valuation of a $p$-adic number can be defined as the difference of the valuations of an
  arbitrary choice of numerator and denominator.›
definition ord where
"ord x = (ord_Zp (numer x)) - (ord_Zp (denom x))"

definition val where
"val x = (if x = 𝟬 then (::eint) else eint (ord x))"

lemma val_ord[simp]:
  assumes "a  nonzero Qp"
  shows "val a = ord a"
  using assms nonzero_def val_def by force

      (********************************************************************************************)
      (********************************************************************************************)
      subsubsection‹Properties of the Valuation›
      (********************************************************************************************)
      (********************************************************************************************)

lemma ord_of_frac:
  assumes "a  nonzero Zp"
  assumes "b  nonzero Zp"
  shows "ord (frac a b) = (ord_Zp a) - (ord_Zp b)"
proof-
  have "frac a b = frac (numer (frac a b)) (denom (frac a b))"
    by (simp add: assms(1) assms(2))
  then have "a Zp(denom (frac a b)) = b Zp(numer (frac a b))"
    by (simp add: assms(1) assms(2) numer_denom_swap)   
  then have "(ord_Zp a) - (ord_Zp b) =  (ord_Zp (numer (frac a b))) - (ord_Zp (denom (frac a b)))"
    using ord_Zp_eq_frac Qp_def Zp_def 
    by (metis Zp.frac_closed Zp.nonzero_closed Zp.numer_denom_facts(4) assms(1) assms(2) local.numer_denom_facts(1) local.numer_denom_facts(2) nonzero_fraction ord_of_nonzero(2) ord_pos) 
  then show ?thesis 
    using ord_def 
    by presburger
qed

lemma val_zero:
"val 𝟬 = " by (simp add: val_def)

lemma ord_one[simp]:
"ord 𝟭 = 0"
  using Zp.nonzero_one_closed local.frac_one ord_of_frac by fastforce
  
lemma val_one[simp]:
"val (𝟭) = 0"
  using ord_one 
  by (simp add: Qp.one_nonzero zero_eint_def)      
  
lemma val_of_frac:
  assumes "a  carrier Zp"
  assumes "b  nonzero Zp"
  shows "val (frac a b) = (val_Zp a) - (val_Zp b)"
proof(cases "a = 𝟬Zp⇙")
  case True
  then show ?thesis 
    using assms(1) assms(2)  local.val_zero
    by (simp add: Qp_def val_Zp_def)
next
  case False
  then have "a  nonzero Zp" 
    by (simp add: assms(1) nonzero_def)
  then show ?thesis
    using ord_of_frac[of a b] assms(2)  val_def val_ord_Zp 
          nonzero_numer_imp_nonzero_fraction
  by (simp add: Zp.nonzero_memE(2))
qed

lemma Zp_division_Qp_0[simp]:
  assumes "u  Units Zp"
  assumes "v  Units Zp"
  shows "frac (u Zp(invZpv)) 𝟭Zp= frac u v"
proof-  
  have 0: "frac v v = 𝟭" 
    using frac_one
    by (simp add: Qp_def Zp.Units_nonzero assms(2))
  have 1:"(invZpv)  carrier Zp"
    using assms  by blast
  have 2:"frac (u Zp(invZpv))  𝟭Zp carrier Qp"
    by (simp add: "1" Zp.Units_closed Zp.nonzero_one_closed assms(1) local.frac_closed)
  have 3: "frac (u Zp(invZpv)) 𝟭Zp=  (frac (u Zp(invZpv)) 𝟭Zp)  frac v v"
    by (simp add: "0" "2")
  then have 4:  "frac (u Zp(invZpv)) 𝟭Zp=  (frac ((u Zp(invZpv)) Zpv)  v)"
    by (simp add: Zp.Units_nonzero Zp.nonzero_closed assms(1) assms(2) frac_eqI') 
  then have 4:  "frac (u Zp(invZpv)) 𝟭Zp=  (frac (u Zp((invZpv) Zpv))  v)"
    by (simp add: mult_assoc) 
  have 5:"(invZpv) Zpv = 𝟭Zp⇙"
    by (simp add: assms(2))
  then show  "frac (u Zp(invZpv)) 𝟭Zp=  (frac u  v)"
    by (simp add: "4" Zp.Units_closed assms(1))
qed

lemma Zp_division_Qp_1:
  assumes "u  Units Zp"
  assumes "v  Units Zp"
  obtains w where "w  Units Zp"
                  "ι w = frac u v"
proof-
  have " (invZpv)  Units Zp" 
    by (simp add: assms(2))
  then have "(u Zp(invZpv))  Units Zp" 
    using assms 
    by blast     
  then show ?thesis 
    using  Zp_division_Qp_0  Zp.Units_closed assms(1) assms(2) 
      local.inc_def that by presburger
qed

lemma val_ring_ord_criterion:
  assumes "a  carrier Qp"
  assumes "a  𝟬"
  assumes "ord a  0"
  shows "a  𝒪p"
proof-
  obtain c d where P0: "a = frac c d" and P1: "c  nonzero Zp" and P2: "d  nonzero Zp"
   by (metis assms(1) assms(2) get_common_denominator nonzero_fraction_imp_nonzero_numer)  
  obtain m n where P3: "m = ord_Zp c" and P4:"n = ord_Zp d"
    by metis 
  obtain u where "u = ac_Zp c" 
    by simp
  then have P5:"c = (𝗉[^]Zpm) Zpu" and P6:"u  Units Zp"
     apply (simp add: P1 P3 u = ac_Zp c ac_Zp_factors')
     using P1 Zp.nonzero_memE 
     by (simp add: u = ac_Zp c ac_Zp_is_Unit)
  obtain v where "v = ac_Zp d" by simp
  have  P7:"d = (𝗉[^]Zpn) Zpv" and P8:"v  Units Zp"
     using P2 P4 v = ac_Zp d ac_Zp_factors' apply blast
     using P2 Zp.nonzero_memE 
     by (simp add: v = ac_Zp d ac_Zp_is_Unit)
  have P9: "a = frac ((𝗉[^]Zpm) Zpu) ((𝗉[^]Zpn) Zpv)"
    by (simp add: P0 P5 P7)
  have P10: "(𝗉[^]Zpm)  carrier Zp"
    using P1 P3 Zp_def ord_pos Zp.nonzero_closed Zp.nonzero_memE(2) p_pow_car
    by auto
  have P11: "(𝗉[^]Zpn)  nonzero Zp" 
    by (simp add: P2 P4 Zp.nonzero_closed Zp.nonzero_memE(2) ord_pos p_int_pow_nonzero)
  have P12: "u  carrier Zp"
    using P6 Units_def 
    by blast
  have P13: "v  nonzero Zp"
    using P8 Units_def ord_of_nonzero(2) 
    by (simp add: Zp.Units_nonzero)    
  have P14: "a = (frac (𝗉[^]Zpm) (𝗉[^]Zpn))  (frac u v)"
    using P12 P13 P10 P9 P11 Qp_def  frac_mult by metis 
  have P15: "m  n" 
  proof-
    have "ord_Zp c  ord_Zp d" 
      using P0 P1 P2 assms(3) ord_of_frac[of c d] 
      by (metis P3 P4 antisym eq_iff eq_iff_diff_eq_0 le_cases le_iff_diff_le_0 ord_Zp_def) 
    then show ?thesis 
      using P3 P4 by blast
  qed
  have P16: "n  0" 
    by (simp add: P2 P4 Zp.nonzero_closed Zp.nonzero_memE(2) ord_pos)
  have P17: "a = (frac (𝗉[^]Zp(m-n)) 𝟭Zp)  (frac u v)" 
    using P14 P15 P16 local.inc_def[of "(𝗉 [^]Zp(n - m))"] pow_p_frac_0[of n m] 
    by (simp add: local.inc_def p_pow_car)    
  obtain w where P18: "w  Units Zp" and P19: "ι w = frac u v "
    using  Zp_division_Qp_1 P6 P8 by blast
  have P20: "w  carrier Zp" 
    using P18 Units_def by blast
  have P21:  "a = ι (𝗉[^]Zp(m-n))  ι w" 
    using P15 P17 P19 ι_def inc_equation p_pow_car by auto    
  have P22:  "a = (frac (𝗉[^]Zp(m-n)) 𝟭Zp)  (frac w 𝟭Zp)" 
    using P17 P19 P20 local.inc_def by auto
  have P23: "𝗉[^]Zp(m-n)  carrier Zp" 
    by (simp add: P15 p_pow_car)   
  have P24: "a = (frac ((𝗉[^]Zp(m-n)) Zpw) 𝟭Zp)" 
    using P20 P22 P23 frac_mult 
    by (simp add: Zp.nonzero_one_closed)
  have P24:  "a = ι((𝗉[^]Zp(m-n)) Zpw)" 
    by (simp add: P20 P23 P24  cring.cring_simprules(5) domain.axioms(1) local.inc_def)
  then show ?thesis 
    using P20 P23 by blast
qed

lemma val_ring_val_criterion:
  assumes "a  carrier Qp"
  assumes "val a  0"
  shows "a  𝒪p"
  apply(cases "a = 𝟬")
  using Qp.int_inc_zero Qp_def inc_of_int apply blast
    using assms unfolding val_def 
    by (simp add: val_ring_ord_criterion zero_eint_def)  

lemma ord_of_inv:
  assumes "a  carrier Qp"
  assumes "a  𝟬"
  shows "ord (invQpa) = - (ord a)"
proof-
  obtain b c where 
   Frac: "a = frac b c" and 
   Car: "b  carrier Zp" and 
   Nz_c: "c  nonzero Zp"
    using assms(1) local.numer_denom_facts(1) local.numer_denom_facts(2)
          local.numer_denom_facts(5) by blast   
    have Nz_b: "b  nonzero Zp" 
      using Frac Car Nz_c  assms(2) nonzero_fraction_imp_nonzero_numer by metis 
    then have "(invQpa) = frac c b" 
      using Frac Nz_c frac_inv Qp_def 
      by auto
    then show ?thesis using Frac Nz_b Nz_c ord_of_frac[of b c] ord_of_frac[of c b]  
      by (simp add: nonzero_def ord_Zp_def)
qed

lemma val_of_inv:
  assumes "a  carrier Qp"
  assumes "a  𝟬"
  shows "val (invQpa) = - (val a)"
  using ord_of_inv unfolding uminus_eint_def 
  by (simp add: assms(1) assms(2) inv_in_frac(2) val_def)

text‹Zp is a valuation ring in Qp›

lemma Zp_mem:
  assumes "a  carrier Qp"
  shows "a  𝒪p  (invQpa  𝒪p)"
proof(cases "invQpa  𝒪p  a = 𝟬")
  case True
  then show ?thesis 
    using val_ring_subring subringE(2) by auto
next
  case False
  then have Nz: "a  𝟬" by auto 
  have "¬ (ord a < 0)"
  proof
    assume "ord a < 0"
    then have "ord (invQpa) >0" 
      by (simp add: assms(1) Nz ord_of_inv)
    then have 0: "ord (invQpa) 0"
      by auto
    have 1: "(invQpa)  carrier Qp"
      by (simp add: assms(1) Nz inv_in_frac)
    have 2: "(invQpa) 𝟬" 
      by (simp add: assms(1) Nz inv_in_frac(2))
    then have "(invQpa)  𝒪p" 
      using  val_ring_ord_criterion  by (simp add: "0" "1")
    then show False 
      using False by blast
  qed
  then show ?thesis 
    using val_ring_ord_criterion assms(1) Nz by auto
qed 

lemma Qp_val_ringI:
  assumes "a  carrier Qp"
  assumes "val a  0"
  shows "a  𝒪p" 
using assms val_ring_val_criterion by blast


text‹Criterion for determining when an element in Qp is zero›
lemma val_nonzero:
  assumes "a  carrier Qp"
  assumes "s > val a"
  shows "a  nonzero Qp"
proof-
  have "val a  "
    by (metis assms(2) eint_ord_simps(6))    
  then show ?thesis 
    using assms 
    by (metis (mono_tags, opaque_lifting) local.val_zero  not_nonzero_Qp)
qed

lemma val_ineq:
  assumes "a  carrier Qp"
  assumes "val 𝟬  val a"
  shows "a = 𝟬"
  using assms unfolding val_def 
  by (metis (mono_tags, lifting) eint_ord_code(5))
  
lemma ord_minus:
  assumes "a   nonzero Qp"
  shows "ord a = ord (a)"
proof-
  have " a =  (frac (numer a) (denom a))"
    using assms Qp.nonzero_closed local.numer_denom_facts(5) by auto    
  then have " a = (frac (Zp(numer a)) (denom a))"
    by (simp add: Qp.nonzero_closed assms local.frac_uminus local.numer_denom_facts(1) local.numer_denom_facts(2))
  then show ?thesis 
    by (metis Qp_def Qp.add.inv_eq_1_iff Qp.nonzero_closed Zp.add.inv_closed assms 
        local.numer_denom_facts(1) local.numer_denom_facts(2) nonzero_fraction_imp_nonzero_numer 
        numer_nonzero ord_Zp_of_a_inv ord_def ord_of_frac)
qed

lemma val_minus:
  assumes "a   carrier Qp"
  shows "val a = val (a)"
proof(cases "a = 𝟬")
  case True
  then show ?thesis 
    using Qp.minus_zero by presburger  
next
  case False
  then show ?thesis using Qp.domain_axioms assms cring.cring_simprules(21)
        cring.cring_simprules(22) domain.axioms(1) not_nonzero_Qp 
        ord_minus val_def 
    by metis 
qed

text‹The valuation is multiplicative:›

lemma ord_mult:
  assumes "x  nonzero Qp"
  assumes "y  nonzero Qp"
  shows "(ord (x  y)) = (ord x) + (ord y)"
proof-
  have 0:"x  carrier Qp" using assms by(simp add:nonzero_def)
  have 1:"y carrier Qp" using assms by(simp add:nonzero_def)
  obtain a b c where
   A: "a  carrier Zp" and
   B: "b  carrier Zp" and
   C: "c  nonzero Zp" and
   Fx: "x = frac a c" and
   Fy: "y = frac b c" 
    using get_common_denominator 0 1 by blast
  have An: "a  nonzero Zp"
    using A C Fx assms(1) nonzero_def nonzero_fraction_imp_nonzero_numer 
          Qp.nonzero_memE(2) by auto
  have Bn: " b  nonzero Zp" 
    using B C Fy assms(2) nonzero_def nonzero_fraction_imp_nonzero_numer 
          Qp.nonzero_memE(2) by auto
  have Fxy: "x  y = frac (a Zpb) (c Zpc)" 
    by (simp add: A B C Fx Fy frac_mult)
  have Cn: "c Zpc  nonzero Zp" 
    using C Localization.submonoid.m_closed Zp.domain_axioms domain.nonzero_is_submonoid 
    by metis
  have Ordxy0: "ord (x  y) = ord_Zp (a Zpb) - ord_Zp (c Zpc)"
    by (metis "0" "1" An Bn C Cn Fx Fxy Fy Qp.integral
        Zp.nonzero_mult_closed Zp.zero_closed fraction_zero 
        nonzero_fraction nonzero_fraction_imp_nonzero_numer ord_of_frac)
  have Ordxy1: "ord (x  y) = (ord_Zp a) + (ord_Zp b) - ((ord_Zp c) + (ord_Zp c))" 
    using  An Bn C 
    by (simp add: Ordxy0 ord_Zp_mult)
  show ?thesis 
  proof-
    have "ord x + ord y = (ord_Zp a) - (ord_Zp c) + ((ord_Zp b) - (ord_Zp c))"
      using An Bn C Fx Fy ord_of_frac[of a c] ord_of_frac[of b c] by presburger 
    then show ?thesis 
      using Ordxy1 
      by presburger 
  qed
qed

lemma val_mult0:
  assumes "x  nonzero Qp"
  assumes "y  nonzero Qp"
  shows "(val (x  y)) = (val x) + (val y)"
proof-
  have 0: "val x = ord x" 
    using assms(1) val_ord by metis  
  have 1: "val y = ord y" 
    using assms(2) val_ord by metis   
  have "x  y  𝟬"
    using field_axioms assms(1) assms(2) integral  Qp.integral_iff 
      Qp.nonzero_closed Qp.nonzero_memE(2) by presburger
  then have 2: "val (x  y) = ord (x  y)" 
    by (simp add:  val_def) 
  have 3: "val x + val y = ord x + ord y "
    by (simp add: "0" "1")   
  have 4: "val (x  y) = ord  (x  y)" 
    using "2" by auto 
  then show ?thesis using 3 4 ord_mult assms nonzero_def 
    by (simp add: nonzero_def)   
qed  

text‹val is multiplicative everywhere›

lemma val_mult:
  assumes "x  carrier Qp"
  assumes "y  carrier Qp"
  shows "(val (x  y)) = (val x) + (val y)"
  apply(cases "x = 𝟬  y = 𝟬")
  using assms local.val_zero apply auto[1]
    by (meson assms(1) assms(2) not_nonzero_Qp val_mult0)

text‹val and ord are compatible with inclusion›

lemma ord_of_inc:
assumes "x  nonzero Zp"
shows "ord_Zp x = ord(ι x)" 
proof-
  have "ι x = frac x 𝟭Zp⇙"
    using assms(1) 
    by (simp add: Zp.nonzero_closed local.inc_def)
  then have "ord ( ι x) = ord_Zp x - ord_Zp 𝟭Zp⇙"
    using assms(1) ord_of_frac 
    by (simp add: Zp.nonzero_one_closed)
  then show ?thesis
    using ord_Zp_one 
    by (simp add: ord_Zp_def)
qed

lemma val_of_inc:
assumes "x  carrier Zp"
shows "val_Zp x = val (ι x)" 
proof(cases "x  nonzero Zp")
  case True
  then show ?thesis 
    using inc_of_nonzero nonzero_def ord_Zp_def ord_of_inc val_Zp_def val_ord 
    by (simp add: nonzero_def)
next
  case False
  then show ?thesis 
    by (metis Zp.nonzero_memI Zp.nonzero_one_closed assms local.inc_def nonzero_fraction_imp_numer_not_zero val_Zp_def val_def)
qed

lemma Qp_inc_id:
  assumes "a  nonzero Qp"
  assumes "ord a 0"
  obtains b where "b  nonzero Zp" and "a = ι b"
  using assms 
  by (metis (no_types, opaque_lifting) Qp.nonzero_closed Qp.nonzero_memE(2) 
      Zp.nonzero_one_closed Zp.zero_closed Zp_defs(2) val_ring_ord_criterion image_iff local.inc_def 
      nonzero_fraction_imp_numer_not_zero not_nonzero_Zp  that)

lemma val_ring_memI:
  assumes "a  carrier Qp"
  assumes "val a  0"
  shows "a  𝒪p"
  using assms Qp_val_ringI by blast

lemma val_ring_memE:
  assumes "a  𝒪p"
  shows "val a  0" "a  carrier  Qp"
  using assms  val_of_inc val_pos apply auto[1]
  using assms inc_closed by auto
  
lemma val_ring_add_closed: 
  assumes "a  𝒪p"
  assumes "b  𝒪p"
  shows "a  b  𝒪p"
  using val_ring_subring subringE(7) by (metis assms(1) assms(2))

lemma val_ring_times_closed: 
  assumes "a  𝒪p"
  assumes "b  𝒪p"
  shows "a  b  𝒪p"
  using val_ring_subring subringE(6)  by (metis assms(1) assms(2))

lemma val_ring_ainv_closed: 
  assumes "a  𝒪p"
  shows " a  𝒪p"
  using val_ring_subring subringE(5)  by (metis assms)

lemma val_ring_minus_closed:
  assumes "a  𝒪p"
  assumes "b  𝒪p"
  shows "a  b  𝒪p"
  using assms val_ring_subring val_ring_ainv_closed val_ring_add_closed
  unfolding a_minus_def   by blast 

lemma one_in_val_ring:
"𝟭  𝒪p"
  apply(rule val_ring_memI)
  apply blast
  unfolding val_one by blast 

lemma zero_in_val_ring:
"𝟬  𝒪p"
  apply(rule val_ring_memI)
  apply blast
  unfolding val_zero 
  by simp  

lemma ord_p:
"ord 𝔭 = 1"
  using p_nonzero ord_Zp_p ord_of_inc p_inc 
  by (smt Zp_int_inc_closed ord_of_nonzero(2))

lemma ord_p_pow_nat:
"ord (𝔭 [^] (n::nat)) = n"
  using p_pow_nonzero ord_Zp_p ord_of_inc p_inc ord_Zp_p_pow p_natpow_inc  p_pow_nonzero' 
  by auto

lemma ord_p_pow_int:
"ord (𝔭 [^] (n::int)) = n"
proof(cases "n 0")
  case True
  then show ?thesis 
    by (metis int_nat_eq int_pow_int ord_p_pow_nat)
next
  case False
  then have Neg: "n <0" by auto 
  then have 0: "𝔭[^]n = frac 𝟭Zp(𝗉[^]Zp(-n))" 
    using p_intpow by auto
  have "(𝗉[^]Zp(-n))  nonzero Zp"
    using False p_int_pow_nonzero 
    by (simp add: nonzero_def)
  then have "ord (𝔭 [^] (n::int)) = ord_Zp 𝟭Zp- ord_Zp (𝗉[^]Zp(-n))" 
    using "0" ord_of_frac 
    by (simp add: Zp.nonzero_one_closed)
  then have "ord (𝔭 [^] (n::int)) = - ord_Zp (𝗉[^]Zp(-n))" 
    using ord_Zp_one by linarith
  then have "ord (𝔭 [^] (n::int)) = -(-n)" 
    using Neg ord_Zp_p_int_pow 
    by (metis int.lless_eq neg_0_le_iff_le)
  then show ?thesis 
    by auto 
qed

lemma ord_nonneg:
  assumes "x   𝒪p"
  assumes "x  𝟬"
  shows "ord x 0"
proof-
  obtain a where A: "x = ι a  a  carrier Zp" 
    using assms(1) by blast
  then have "a  nonzero Zp" using assms(2) 
      local.inc_def nonzero_fraction_imp_numer_not_zero not_nonzero_Zp
    using Zp.nonzero_one_closed by blast
  then have "ord_Zp a 0" 
    using A 
    by (simp add: Zp.nonzero_memE(2) ord_pos)
  then show ?thesis 
    using A a  nonzero Zp ord_of_inc by metis 
qed

lemma val_p:
"val 𝔭 = 1"
  using p_inc val_Zp_p val_of_inc val_def ord_p p_nonzero val_ord 
  by simp  

lemma val_p_int_pow:
"val (𝔭[^](k::int)) = k"
  using ord_p_pow_int p_intpow_closed(2) val_ord by presburger

lemma val_p_int_pow_neg:
"val (𝔭[^](-k::int)) = - eint k"
  by (metis eint.distinct(2) local.val_zero p_intpow_closed(1) p_intpow_inv'' val_of_inv val_p_int_pow)

lemma nonzero_nat_pow_ord:
  assumes "a  nonzero Qp"
  shows "ord (a [^] (n::nat)) = n * ord a"
  apply(induction n)
  apply simp
    using Qp_nat_pow_nonzero assms semiring_normalization_rules(2) 
    by (simp add: semiring_normalization_rules(2) ord_mult)


lemma add_cancel_eint_geq:
  assumes "(eint a) + x  (eint a ) + y"
  shows "x y"
  using assms eint_add_left_cancel_le by blast

lemma(in padic_fields) prod_equal_val_imp_equal_val:
  assumes "a  nonzero Qp"
  assumes "b  carrier Qp"
  assumes "c  carrier Qp"
  assumes "val (a  b) = val (a  c)"
  shows "val b = val c"
proof(cases "b = 𝟬")
  case True
  then have "val (a  b) = "
    using Qp.nonzero_closed Qp.r_null assms(1) local.val_zero by presburger
  then have "c = 𝟬"
    using assms True 
    by (metis Qp.integral Qp.nonzero_closed Qp.nonzero_mult_in_car Qp.not_nonzero_memI eint_ord_simps(3) not_nonzero_Qp val_ineq)   
  then show ?thesis 
    using True by blast
next
  case False
  obtain n where n_def: "val a = eint n"
    using assms val_ord by blast
  then show ?thesis using val_mult[of a b] val_mult[of a c] unfolding n_def 
  by (simp add: Qp.nonzero_closed assms(1) assms(2) assms(3) assms(4))
qed


lemma two_times_eint:
  shows "2*(x::eint) = x + x"
  by (metis eint_2_minus_1_mult eint_add_cancel_fact plus_eq_infty_iff_eint times_eint_simps(4))

lemma times_cfs_val_mono:
  assumes "u  Units Qp"
  assumes "a  carrier Qp"
  assumes "b  carrier Qp"
  assumes "val (u  a)  val (u  b)"
  shows "val a  val b"
proof-
  have "eint (ord u) + val a  eint (ord u) + val b"
    using assms val_ord  val_mult Qp.Units_nonzero Qp.nonzero_closed Units_eq_nonzero by metis 
  thus ?thesis  
    apply(induction "val a")
    using add_cancel_eint_geq apply blast
    using add_cancel_eint_geq by blast
qed

lemma times_cfs_val_mono':
  assumes "u  Units Qp"
  assumes "a  carrier Qp"
  assumes "b  carrier Qp"
  assumes "val (u  a)  val (u  b) + α"
  shows "val a  val b + α"
proof-
  obtain c where c_def: "c  carrier Qp  val c = α"
    by (metis Qp.zero_closed eint.exhaust local.val_zero p_intpow_closed(1) val_p_int_pow)     
  have 0: "val (u  a)  val (u  (b  c))"
    using assms val_mult[of "u  b" c] Qp.m_assoc[of u b c] c_def Qp.Units_closed Qp.cring_simprules(5) 
    by metis
  have 1: "val a  val (b  c)" 
    apply(rule times_cfs_val_mono[of u])
    using assms apply blast using assms apply blast
     apply(rule Qp.ring_simprules) using assms apply blast using c_def apply blast
    by(rule 0)
  show ?thesis 
    using 1 val_mult[of b c] assms c_def by smt 
qed

lemma times_cfs_val_mono'':
  assumes "u  Units Qp"
  assumes "a  carrier Qp"
  assumes "b  carrier Qp"
  assumes "val a  val b + α"
  shows "val (u  a)  val (u  b) + α"
  apply(rule times_cfs_val_mono'[of "inv u" "u  a" "u  b" α])
  using assms apply blast
  apply(rule Qp.ring_simprules)
  using assms apply blast using assms apply blast
  apply(rule Qp.ring_simprules)
  using assms apply blast using assms apply blast
  using m_assoc assms 
  by (metis Qp.Units_closed Qp.cring_simprules(5) Qp.inv_cancelR(1))

lemma val_ineq_cancel_leq: 
  assumes "a  nonzero Qp"
  assumes "b  carrier Qp"
  assumes "c  carrier Qp"
  assumes "val (a  b)  val (a  c)"
  shows "val b  val c"
  using Units_eq_nonzero assms(1) assms(2) assms(3) assms(4) times_cfs_val_mono by blast 

lemma val_ineq_cancel_leq': 
  assumes "a  nonzero Qp"
  assumes "b  carrier Qp"
  assumes "c  carrier Qp"
  assumes "val b  val c"
  shows "val (a  b)  val (a  c)"
  apply(rule val_ineq_cancel_leq[of "inv a" "a  b" "a  c"])
  using assms(1) nonzero_inverse_Qp apply blast
  using Qp.nonzero_closed assms(1) assms(2) apply blast
  using Qp.nonzero_closed assms assms(2) apply blast
  by (metis Qp.inv_cancelR(1) Qp.m_closed Qp.nonzero_closed Units_eq_nonzero assms(1) assms(2) assms(3) assms(4))

lemma val_ineq_cancel_le: 
  assumes "a  nonzero Qp"
  assumes "b  carrier Qp"
  assumes "c  carrier Qp"
  assumes "val (a  b) < val (a  c)"
  shows "val b < val c"
  using Qp.nonzero_closed assms(1) assms(2) assms(3) assms(4) val_mult by auto 

lemma val_ineq_cancel_le': 
  assumes "a  nonzero Qp"
  assumes "b  carrier Qp"
  assumes "c  carrier Qp"
  assumes "val b < val c"
  shows "val (a  b) < val (a  c)"
  apply(rule val_ineq_cancel_le[of "inv a" "a  b" "a  c"])
  using assms(1) nonzero_inverse_Qp apply blast
  using Qp.nonzero_closed assms(1) assms(2) apply blast
  using Qp.nonzero_closed assms assms(2) apply blast
  by (metis Qp.inv_cancelR(1) Qp.m_closed Qp.nonzero_closed Units_eq_nonzero assms(1) assms(2) assms(3) assms(4))

lemma finite_val_imp_nonzero:
  assumes "a  carrier Qp"
  assumes "val a  "
  shows "a  nonzero Qp"
  using assms unfolding val_def nonzero_def 
  by (metis (mono_tags, lifting) mem_Collect_eq)

lemma val_ineq_cancel_leq'': 
  assumes "a  nonzero Qp"
  assumes "b  carrier Qp"
  assumes "c  carrier Qp"
  assumes "val b  val c + eint N"
  shows "val (a  b)  val (a  c) + eint N"
proof- 
  obtain d where d_def: "d = 𝔭[^]N  c"
    by blast 
  show ?thesis 
  proof(cases "c = 𝟬")
    case True
    then show ?thesis unfolding True 
      using True Units_eq_nonzero assms(1) assms(2) assms(4) times_cfs_val_mono'' by blast
  next
    case False
    have F0: "c  nonzero Qp"
      using False assms  Qp.not_nonzero_memE by blast
    have F1: "val (a  c) < "
      using F0 assms 
      by (metis (no_types, lifting) Qp.integral Qp.nonzero_closed Qp.nonzero_memE(2) eint.distinct(1) eint_ord_simps(4) val_def) 
    have F2: "b  nonzero Qp"
      using F0 assms 
      by (metis False Groups.add_ac(2) add_cancel_eint_geq finite_val_imp_nonzero local.val_zero plus_eint_simps(2) val_ineq)
    have F3: "ord b  ord c + N"
      using assms F0
      by (metis F2 eint_ord_simps(1) plus_eint_simps(1) val_ord)
    have F4: "ord a + ord b  ord a + ord c+ N"
      using assms F0 F1 F2 ord_mult F3 by presburger
    have F5: "ord (a  b)  ord (a  c) + N"
      using F4 F2 F0 assms ord_mult by presburger
    have F6: "a  b  nonzero Qp"
      by (metis F2 Qp.integral Qp.nonzero_memE(1) Qp.nonzero_mult_closed Qp.not_nonzero_memE assms(1))
    have F7: "a  c  nonzero Qp"
      by (metis False Qp.integral Qp.nonzero_closed Qp.nonzero_memI Qp.nonzero_mult_closed assms(1) assms(3))
    show "val (a  b)  val (a  c) + eint N"
      using val_ord[of "a  b" ] val_ord[of "a c"] F7 F7 F4 
        Units_eq_nonzero assms(1) assms(2) assms(3) assms(4) times_cfs_val_mono'' by blast
  qed
qed


      (********************************************************************************************)
      (********************************************************************************************)
      subsubsection‹The Ultrametric Inequality on $\mathbb{Q}_p$›
      (********************************************************************************************)
      (********************************************************************************************)


lemma ord_ultrametric:
  assumes "x  nonzero Qp"
  assumes "y  nonzero Qp"
  assumes "x  y  nonzero Qp"
  shows "ord (x  y)  min (ord x) (ord y)"
proof-
  have 0:"x  carrier Qp" using assms by(simp add:nonzero_def)
  have 1:"y carrier Qp" using assms by(simp add:nonzero_def)
  obtain a b c where
   A: "a  carrier Zp" and
   B: "b  carrier Zp" and
   C: "c  nonzero Zp" and
   Fx: "x = frac a c" and
   Fy: "y = frac b c" 
    using  0 1  get_common_denominator by blast
  have An: "a  nonzero Zp" 
    using A C Fx assms(1) nonzero_fraction_imp_nonzero_numer 
          Qp.nonzero_memE(2) by auto
  have Bn: " b  nonzero Zp" 
    using B C Fy assms(2)   nonzero_fraction_imp_nonzero_numer  Qp.nonzero_memE(2) by auto
  have Fxy: "x  y = frac (a Zpb) c" using 0 1  
    by (simp add: A B C Fx Fy frac_add_common_denom)
  have ABn: " a Zpb  nonzero Zp" 
  proof-
    have "a Zpb  carrier Zp" 
      using A B Zp_def padic_add_closed prime by blast
    then show ?thesis 
      using Fxy C assms(3) Qp.nonzero_memE(2) 
        nonzero_fraction_imp_nonzero_numer by blast     
  qed
  have Ordx: "ord x = ord_Zp a - ord_Zp c"
      using Fx An C ord_of_frac by metis 
  have Ordy: "ord y = ord_Zp b - ord_Zp c" 
    using Fy Bn C ord_of_frac by metis   
  have Ordxy: "ord (x  y) = ord_Zp (a Zpb) - ord_Zp c"
    using Fxy ABn C ord_of_frac by metis   
  then show ?thesis
    using Ordx Ordy Ordxy ord_Zp_ultrametric[of a b] ABn An Bn 
    by linarith
qed

lemma ord_ultrametric':
  assumes "x  nonzero Qp"
  assumes "y  nonzero Qp"
  assumes "x Qpy  nonzero Qp"
  shows "ord (x Qpy)  min (ord x) (ord y)"
proof-
  have "ord y = ord (y)"
    using assms(2) ord_minus by blast
  then show ?thesis 
    using assms ord_ultrametric[of x "y"]
    unfolding a_minus_def 
    using Qp.add.inv_closed Qp.add.inv_eq_1_iff Qp.nonzero_closed Qp.nonzero_memE(2) Qp.nonzero_memI 
    by metis
qed

lemma val_ultrametric0:
  assumes "x  nonzero Qp"
  assumes "y  nonzero Qp"
  assumes "x  y  nonzero Qp"
  shows " min (val x) (val y)  val (x  y)  "
proof-
  have 0: "val (x  y) = ord (x  y)" 
    using assms(3) nonzero_def val_def[of "(x  y)"] by fastforce
  have 1: "val x = ord x" 
    using assms(1) nonzero_def val_def 
    by (simp add: nonzero_def)
  have 2: "val y = ord y" 
    using assms(2) nonzero_def val_def val_ord by auto
  have 3: "ord (x  y)  min (ord x) (ord y)" 
    by (simp add: assms(1) assms(2) assms(3) ord_ultrametric)   
  then show ?thesis 
    by (simp add: "0" "1" "2")   
qed

lemma val_ultrametric:
  assumes "x  carrier Qp"
  assumes "y  carrier Qp"
  shows " min (val x) (val y)  val (x  y)"
  apply(cases "x = 𝟬  y = 𝟬")
  using assms(1) assms(2) apply auto[1]
    by (metis Qp.add.m_closed assms(1) assms(2) eint_ord_code(3) local.val_zero not_nonzero_Qp val_ultrametric0)

lemma val_ultrametric':
  assumes "x  carrier Qp"
  assumes "y  carrier Qp"
  shows " min (val x) (val y)  val (x  y)"
  using val_ultrametric[of x "y"]
        val_minus[of y]
        assms 
  by (metis Qp.domain_axioms a_minus_def cring.cring_simprules(3) domain.axioms(1))

lemma diff_ord_nonzero:
  assumes "x  nonzero Qp"
  assumes "y  nonzero Qp"  
  assumes "ord x  ord y"
  shows "x  y  nonzero Qp"
proof(rule ccontr)
  assume " x  y  nonzero Qp"
  then have "x  y = 𝟬"
    using Qp.add.m_closed Qp.nonzero_closed Qp.nonzero_memI assms(1) assms(2) by blast
  then have "x =  y"
    using Qp.minus_equality Qp.nonzero_closed assms(1) assms(2) by blast
  then have "ord x = ord y"
    using assms(2) ord_minus by presburger
  then show False 
    using assms(3) by blast
qed

lemma ord_ultrametric_noteq:
  assumes "x  nonzero Qp"
  assumes "y  nonzero Qp"
  assumes "ord x > ord y"
  shows "ord (x  y) = (ord y)"
proof(rule ccontr)
  assume "ord (x  y)  ord y"
  have 00:"x  y  nonzero Qp"
  proof(rule ccontr)
    assume "x  y  nonzero Qp"
    then have "x  y = 𝟬"
      using Qp.add.m_closed Qp.nonzero_closed Qp.nonzero_memI assms(1) assms(2) by blast
    then have "x =  y"
      by (smt x  y  nonzero Qp assms(1) assms(2) assms(3) diff_ord_nonzero)      
    then have "ord x = ord y"
      using assms(2) ord_minus by presburger
    then show False 
      using assms(3) by linarith
  qed
  then have 0: "ord (x  y) > ord y"
    using ord_ultrametric[of x y] ord (x  y)  ord y assms(1) assms(2) assms(3) 
    by linarith    
  have 1: "((y  x)  x) = y"
    using "00" Qp.add.inv_solve_right' Qp.add.m_comm Qp.minus_eq Qp.nonzero_closed assms(1) assms(2) by presburger 
  have 2: "ord ((y  x)  x)  min (ord (y  x)) (ord x) "
    using 1 assms ord_ultrametric'[of "(y  x)" x] diff_ord_nonzero by auto
  have 3:  "ord y  min (ord x) (ord (x  y))"
    using 2 1 Qp_def Qp.domain_axioms Zp_def assms(1) assms(2) cring.cring_simprules(10) 
          domain.axioms(1) Qp.nonzero_closed by fastforce  
  show False 
    using 3 0 assms 
    by linarith
qed

lemma ord_ultrametric_noteq':
  assumes "x  nonzero Qp"
  assumes "y  nonzero Qp"
  assumes "ord x > ord y"
  shows "ord (x  y) = (ord y)"
  using assms ord_ultrametric_noteq[of x "y"]
  by (metis Qp.add.inv_closed Qp.minus_eq Qp.nonzero_closed Qp.nonzero_memI Qp.r_neg Qp.r_zero ord_minus)
  
lemma ord_ultrametric_noteq'':
  assumes "x  nonzero Qp"
  assumes "y  nonzero Qp"
  assumes "ord y > ord x"
  shows "ord (x  y) = (ord x)"
  using assms ord_ultrametric_noteq'[of y x]
  by (metis Qp.minus_a_inv Qp.nonzero_closed Qp.not_eq_diff_nonzero ord_minus)
  
lemma val_ultrametric_noteq:
  assumes "x  carrier Qp"
  assumes "y  carrier Qp"
  assumes "val x > val y"
  shows "val (x  y) = val y"
  apply(cases "x = 𝟬")
  apply (simp add: assms(2))
    using assms unfolding val_def 
    by (smt Qp.not_nonzero_memI diff_ord_nonzero eint_ord_simps(2) not_nonzero_Qp ord_ultrametric_noteq val_def val_nonzero)

lemma val_ultrametric_noteq':
  assumes "x  carrier Qp"
  assumes "y  carrier Qp"
  assumes "val x > val y"
  shows "val (x  y) = val y"
  using assms  val_ultrametric_noteq[of x "y"]
  by (metis Qp.domain_axioms a_minus_def cring.cring_simprules(3) domain.axioms(1) val_minus)

lemma ultrametric_equal_eq:
  assumes "x  carrier Qp"
  assumes "y  carrier Qp"
  assumes "val (y  x) > val x"
  shows "val x = val y"
  using assms 
  by (metis (no_types, lifting) Qp.add.inv_closed Qp.add.m_assoc Qp.l_neg Qp.minus_closed Qp.minus_eq Qp.r_zero val_ultrametric_noteq)

lemma ultrametric_equal_eq':
  assumes "x  carrier Qp"
  assumes "y  carrier Qp"
  assumes "val (x  y) > val x"
  shows "val x = val y"
  using assms ultrametric_equal_eq[of x y] 
  by (metis Qp.minus_a_inv Qp.minus_closed val_minus)

lemma val_ultrametric_noteq'':
  assumes "x  carrier Qp"
  assumes "y  carrier Qp"
  assumes "val x > val y"
  shows "val (y  x) = val y"
  by (metis Qp.minus_a_inv Qp.minus_closed assms(1) assms(2) assms(3) val_minus val_ultrametric_noteq')
  
text‹Ultrametric over finite sums:›

lemma Min_mono:
  assumes "finite A"
  assumes "A  {}"
  assumes " a. a  A   f a  a"
  shows "Min (f`A)  Min A"
  by (meson Min_in Min_le_iff assms(1) assms(2) assms(3) finite_imageI image_eqI image_is_empty)

lemma Min_mono':
  assumes "finite A"
  assumes " (a::'a). a  A  (f::'a  eint)  a   g a"
  shows "Min (f`A)  Min (g `A)"
proof-
  have "(a   A. f a  g a)  Min (f`A)  Min (g` A)"
  apply(rule finite.induct[of A])
      apply (simp add: assms(1))
  apply simp
  proof fix A a assume F: "finite A" "(aA. f a  g a)  Min (f ` A)  Min (g ` A)"
"ainsert a A. f a  g a"
    show "Min (f ` insert a A)  Min (g ` insert a A)"
    proof-
      obtain k where k_def: "k  insert a A  g k = Min (g ` insert a A)"
        using assms 
        by (metis (mono_tags, opaque_lifting) F(1) Min_eq_iff finite.insertI finite_imageI image_iff image_is_empty insert_not_empty)
      then have 0: "f k  g k"
        using F(3) by blast
      thus ?thesis using k_def 
        by (metis F(1) Min_le dual_order.trans finite.insertI finite_imageI image_eqI)
    qed
  qed
  thus ?thesis using assms by blast 
qed

lemma eint_ord_trans:
  assumes "(a::eint)  b"
  assumes "b  c"
  shows "a  c"
  using assms by auto 

lemma eint_Min_geq:
  assumes "finite (A::eint set)"
  assumes "x. x  A  x  c"
  assumes "A  {}"
  shows "Min A  c"
  using Min_in[of A] assms(2)[of "Min A"] assms by blast 

lemma eint_Min_gr:
  assumes "finite (A::eint set)"
  assumes "x. x  A  x > c"
  assumes "A  {}"
  shows "Min A > c"
  using Min_in[of A] assms(2)[of "Min A"] assms by blast 

lemma finsum_val_ultrametric:
  assumes "g  A  carrier Qp"
  assumes "finite A"
  assumes "A  {}"
  shows " val (finsum Qp g A)  Min (val ` (g`A))"  
proof-
  have "A  {}  g  A  carrier Qp  val (finsum Qp g A)  Min (val ` (g`A))"  
    apply(rule finite.induct[of A])
      apply (simp add: assms(2))
      apply blast
  proof fix A a assume A: "finite A" "A  {} g  A  carrier Qp  val (finsum Qp g A)  Min (val ` g ` A)"
                          " insert a A  {}  g  insert a A  carrier Qp "
    show "val (finsum Qp g (insert a A))  Min (val ` g ` insert a A)"
      apply(cases "a  A")
       apply (metis A(2) A(3) insert_absorb)
    proof(cases "A = {}")
      have g_closed: "g  A  carrier Qp"
        using A(3) by blast
      have g_closed': "g  insert a A  carrier Qp"
        using A(3) by linarith
      then have ga: "g a  carrier Qp"
        by blast 
      assume a_notin: "a  A"
      case True
      have "g a  carrier Qp" using A(3) 
        by blast
      then have 0: "(finsum Qp g (insert a A)) = g a"
        using A True abelian_monoid.finsum_insert[of Qp A a g]  abelian_monoid.finsum_empty[of Qp g]
              Qp.abelian_monoid_axioms Qp.add.l_cancel_one Qp.zero_closed a_notin g_closed 
        by metis  
      have 1: "Min (val ` g ` insert a A) = val (g a)"
        by (metis A(1) True Min_in finite.insertI finite_imageI image_empty 
            image_insert insert_not_empty singletonD)
      show ?thesis 
        using 0 1 
        by simp       
    next
      case False
      assume a_notin: "a  A"
      have g_closed: "g  A  carrier Qp"
        using A(3) by blast
      have g_closed': "g  insert a A  carrier Qp"
        using A(3) by linarith
      then have ga: "g a  carrier Qp"
        by blast 
      have 0: "finsum Qp g (insert a A) = g a  finsum Qp g A" 
        by (simp add: A(1) a_notin g_closed ga)     
      have 1: "min (val (g a)) (Min (val ` g ` A)) = Min (insert (val (g a)) (val ` g ` A))"
      proof-
        have 10: "finite (val ` g ` A) " using A
          by blast
        then have 11: "val ` g ` A  {}"
          using False 
          by blast
        show ?thesis 
          using  10 11 Min_insert 
          by simp          
      qed
      have 2: " val (g a  finsum Qp g A)  min (val (g a)) (val (finsum Qp g A))"
        using val_ultrametric[of "g a" "finsum Qp g A" ] abelian_monoid.finsum_closed[of Qp g A]
              g_closed ga  Qp.abelian_monoid_axioms by blast   
      have 3: " val (finsum Qp g A)  Min (val ` g ` A)"
        using A False 
        by blast
      have 4: " val (finsum Qp g (insert a A))   min (val (g a)) (val (finsum Qp g A))"
        using 2 "0" 
        by presburger
      have 5: " val (finsum Qp g A)  Min (val ` g ` A)"
        using False "3" by blast
      show " val (finsum Qp g (insert a A))  Min (val ` g ` insert a A)"
        using 5 4 1 
        by (smt image_insert min.cobounded1 min_def order_trans)        
    qed
  qed
  then show ?thesis 
    using assms 
    by blast
qed

lemma (in padic_fields) finsum_val_ultrametric':
  assumes "g  A  carrier Qp"
  assumes "finite A"
  assumes "i. i  A  val (g i)  c"
  shows " val (finsum Qp g A)  c"
proof(cases "A = {}")
  case True
  then show ?thesis using assms
    unfolding True Qp.finsum_empty  
    using eint_ord_code(3) local.val_zero by presburger
next
  case False
  show ?thesis
  proof(rule eint_ord_trans[of _ "Min (val ` g ` A)"])
    have 0: "s. s  val ` g ` A  s  c" 
    proof- fix s assume A: "s  val ` g ` A"
      then obtain a where a_def: "a  A  s = val (g a)"
        by blast
      have s_eq: "s = val (g a)"
        using a_def by blast 
      show "c  s"
        using assms(3)[of a] A a_def unfolding s_eq  by blast 
    qed
    show "c  Min (val ` g ` A)"
      apply(rule eint_Min_geq)
      using assms apply blast using assms apply blast
      using False by blast
    show "Min (val ` g ` A)  val (finsum Qp g A)"
      by(rule finsum_val_ultrametric[of g A], rule assms, rule assms, rule False)
  qed
qed

lemma (in padic_fields) finsum_val_ultrametric'':
  assumes "g  A  carrier Qp"
  assumes "finite A"
  assumes "i. i  A  val (g i) > c"
  assumes "c < "
  shows " val (finsum Qp g A) > c"
proof(cases "A = {}")
  case True
  then show ?thesis using assms
    unfolding True Qp.finsum_empty  val_zero
    using eint_ord_code(3) local.val_zero  by blast   
next
  case False
  show ?thesis
  proof(rule less_le_trans[of _ "Min (val ` g ` A)"])
    have 0: "s. s  val ` g ` A  s > c" 
    proof- fix s assume A: "s  val ` g ` A"
      then obtain a where a_def: "a  A  s = val (g a)"
        by blast
      have s_eq: "s = val (g a)"
        using a_def by blast 
      show "c < s"
        using assms(3)[of a] A a_def unfolding s_eq  by blast 
    qed
    show "c < Min (val ` g ` A)"
      apply(rule eint_Min_gr)
      using assms apply blast using assms 
      using "0" apply blast
      using False by blast
    show "Min (val ` g ` A)  val (finsum Qp g A)"
      by(rule finsum_val_ultrametric[of g A], rule assms, rule assms, rule False)
  qed
qed

lemma Qp_diff_diff:
  assumes "x  carrier Qp"
  assumes "c  carrier Qp"
  assumes "d  carrier Qp"
  shows "(x  c)  (d  c) = x  d "
  by (smt Qp.domain_axioms a_minus_def assms(1) assms(2) assms(3) cring.cring_simprules(10) 
      cring.cring_simprules(19) cring.cring_simprules(3) cring.cring_simprules(4) 
      cring.cring_simprules(7) domain.axioms(1))

text‹This variant of the ultrametric identity formalizes the common saying that "all triangles in $\mathbb{Q}_p$ are isosceles":›
lemma Qp_isosceles:
  assumes "x  carrier Qp"
  assumes "c  carrier Qp"
  assumes "d  carrier Qp"
  assumes "val (x  c)  v"
  assumes "val (d  c)  v"
  shows "val (x  d)  v"
proof-
  have "val (x  d)  min (val (x  c)) (val (d  c))"
    using assms Qp_diff_diff[of x c d]
    by (metis Qp.domain_axioms cring.cring_simprules(4) domain.axioms(1) val_ultrametric')
  then show ?thesis using assms 
    by (meson dual_order.trans min_le_iff_disj)    
qed

text‹More variants on the ultrametric inequality›

lemma MinE:
  assumes "finite (A::eint set)"
  assumes "a = Min A"
  assumes "b  A"
  shows "a  b"
  using assms by (simp add: assms(3))

lemma MinE':
  assumes "finite (A::eint set)"
  assumes "a = Min A"
  assumes "b  A - {a}"
  shows "a < b"
proof-
  have 0: "a  b" 
    using assms MinE by blast 
  have 1: "a  b" using assms by blast 
  show ?thesis using 0 1 
    by simp
qed

lemma MinE'':
  assumes "finite A"
  assumes "f  A  (UNIV :: eint set)"
  assumes "a = Min (f ` A)"
  assumes "b  A"
  shows "a  f b"
  apply(rule MinE[of "f` A"]) using assms apply blast using assms apply blast  using assms by blast

lemma finsum_val_ultrametric_diff:
  assumes "g  A  carrier Qp"
  assumes "finite A"
  assumes "A  {}"
  assumes "a b. a  A  b  A  a  b  val (g a)  val (g b)"
  shows " val (finsum Qp g A) = Min (val ` g`A)"
proof-
  have "Min (val ` g ` A)  val ` g ` A"
    using Min_in[of "val ` g ` A"] assms by blast
  then obtain a where a_def: "a  A  Min (val ` g`A) = val (g a)"
    by blast 
  have 0: "b. b  A  b  a  val (g b) >  val (g a)"
    apply(rule MinE'[of "val ` g ` A"]) using assms apply blast 
    using a_def assms apply presburger
    using assms(4)[of a] a_def 
    by (metis image_eqI insert_Diff insert_iff)
  have 1: "g a  finsum Qp g (A - {a}) = finsum Qp g (insert a (A - {a}))"
    using assms Qp.finsum_insert[of "A - {a}" a g] a_def finite_subset[of "A - {a}" A]  by blast 
  have 2: "finsum Qp g A = g a  finsum Qp g (A - {a})"  
    unfolding 1 using a_def  
    by (metis insert_Diff_single insert_absorb)
  have 3: "g a  carrier Qp"
    using a_def assms by blast 
  show "val (finsum Qp g A) = Min (val ` g`A)"
  proof(cases "A = {a}")
    case True
    show ?thesis using 3 Qp.finsum_empty[of g] a_def unfolding 2 unfolding True  
      by auto       
  next
    case False
    then have F0: "A - {a}  {}"
      using assms by blast 
    have F1: "finsum Qp g (A - {a})  carrier Qp"
      apply(rule Qp.finsum_closed)
      using assms by blast 
    have F2: "val (finsum Qp g (A - {a}))  Min (val ` g` (A- {a}))"
      apply(rule finsum_val_ultrametric)
      using assms apply blast using assms apply blast using False a_def by blast 
    have F3: "Min (val ` g` (A- {a}))  (val ` g` (A- {a}))"
      apply(rule Min_in)
      using assms apply blast using False a_def by blast 
    obtain b where b_def: "b  A - {a}  Min (val ` g` (A- {a})) = val (g b)"
      using F3 by blast 
    have F4: "Min (val ` g` (A- {a})) > val (g a)"
      using a_def assms b_def  by (metis "0" Diff_iff singletonI)
    have F5: "val (finsum Qp g (A - {a})) > val (g a)"
      using F4 F2 less_le_trans by blast  
    then show ?thesis using 2 F1 3 
      by (metis Qp.a_ac(2) a_def val_ultrametric_noteq)
  qed
qed

lemma finsum_val_ultrametric_diff':
  assumes "g  A  carrier Qp"
  assumes "finite A"
  assumes "A  {}"
  assumes "a b. a  A  b  A  a  b  val (g a)  val (g b)"
  shows " val (finsum Qp g A) = (MIN a  A. (val (g a)))"
proof-
  have 0: "(λ a. val (g a)) ` A = (val ` g`A)"
    by blast 
  show ?thesis using assms finsum_val_ultrametric_diff[of g A] unfolding 0 by blast 
qed


(**************************************************************************************************)
(**************************************************************************************************)
subsection‹Constructing the Angular Component Maps on $\mathbb{Q}_p$›
(**************************************************************************************************)
(**************************************************************************************************)

      (********************************************************************************************)
      (********************************************************************************************)
      subsubsection‹Unreduced Angular Component Map›
      (********************************************************************************************)
      (********************************************************************************************)

text‹While one can compute the residue of a $p$-adic integer mod $p^n$, this operation does not generalize to the $p$-adic field unless we restrict our attention to the valuation ring. However, we can still define the angular component maps on the field $\mathbb{Q}_p$, which allows us to take a sort of residue for any element $x \in \mathbb{Q}_p$. Given a nonzero element $x \in \mathbb{Q}_p^{\times}$, we can normalize it to obtain $p^{-ord( x)}x$ which has of valuation zero, and then computes its residue (viewed as an element of $\mathbb{Z}_p$). The resulting map agrees with the standard residue map on elements of $\mathbb{Q}_p$ of valuation zero, but not on terms of positive or negative valuation. For example, the element $p^2$ has an order $1$ residue of $0$, but its order $1$ angular component is $1$. In the formalism below, we will use the term "\texttt{angular\_component}" to refer to the unreduced normalization map $x \mapsto p^{-ord( x)}x$, and use the notation "\texttt{ac n}" to refer to the angular component which has been reduced mod $p^n$. This is line with the terminology used in cite"denef1986".  ›
definition angular_component where 
"angular_component a = (ac_Zp (numer a)) Zp(invZpac_Zp (denom a))"

lemma ac_fract:
  assumes "c  carrier Qp"
  assumes "a  nonzero Zp"
  assumes "b  nonzero Zp"
  assumes "c = frac a b"
  shows "angular_component c = (ac_Zp a)ZpinvZp(ac_Zp b)"
proof-
  have "(numer c) Zpb = (denom c) Zpa"
    by (simp add: assms(2) assms(3) assms(4) mult_comm numer_denom_swap)
  then have "ac_Zp ((numer c) Zpb) = ac_Zp ((denom c) Zpa)"
    by simp
  then have "(ac_Zp (numer c)) Zp(ac_Zp b) = (ac_Zp (denom c)) Zp(ac_Zp a)"
    by (metis Qp_def Zp.nonzero_closed Zp.numer_denom_facts(3) ac_Zp_mult assms(2) assms(3) assms(4) local.frac_closed local.numer_denom_facts(1) nonzero_fraction_imp_nonzero_numer nonzero_numer_imp_nonzero_fraction numer_denom_frac)    
  then have "(invZp(ac_Zp (denom c))) Zp(ac_Zp (numer c)) Zp(ac_Zp b) =  (ac_Zp a)"
    using ac_Zp_is_Unit[of "ac_Zp (denom c)"] Zp.domain_axioms inv_cancelR(1) 
          Qp_def Zp.Units_closed Zp.inv_cancelR(1) Zp.m_closed Zp.nonzero_closed Zp.nonzero_memE(2) Zp_def ac_Zp_is_Unit assms(1) assms(2) mult_assoc padic_fields.numer_denom_facts(2) padic_fields_axioms by auto   
  then have "(invZp(ac_Zp (denom c))) Zp(ac_Zp (numer c))  =  (ac_Zp a) ZpinvZp(ac_Zp b)"
    using ac_Zp_is_Unit[of "ac_Zp b"] Zp.domain_axioms inv_cancelL(2) 
    by (smt Qp_def Zp.Units_inv_closed Zp.Units_r_inv Zp.nonzero_closed Zp.nonzero_memE(2) Zp.r_one Zp_def ac_Zp_is_Unit assms(1) assms(3) mult_assoc mult_comm padic_fields.numer_denom_facts(2) padic_fields_axioms)
  then show ?thesis 
    by (simp add: angular_component_def mult_comm)
qed

lemma angular_component_closed: 
  assumes "a  nonzero Qp"
  shows "angular_component a  carrier Zp"
  using ac_fract assms Qp_def Qp.nonzero_closed Qp.nonzero_memE(2) Zp.Units_inv_closed Zp.m_closed
      Zp.nonzero_closed Zp.nonzero_memE(2) Zp_def ac_Zp_is_Unit angular_component_def local.numer_denom_facts(3)
      padic_fields.numer_denom_facts(1) padic_fields.numer_denom_facts(2) padic_fields_axioms padic_integers.ac_Zp_in_Zp padic_integers_def prime by auto
 
lemma angular_component_unit: 
  assumes "a  nonzero Qp"
  shows "angular_component a  Units Zp"
  using ac_fract[of a "numer a" "denom a"]  Qp_def Qp.nonzero_closed 
    Qp.nonzero_memE(2) Zp.Units_inv_Units Zp.Units_m_closed 
    Zp.nonzero_closed Zp.nonzero_memE(2) Zp_def ac_Zp_is_Unit 
    angular_component_def assms local.numer_denom_facts(1) 
    local.numer_denom_facts(2) padic_fields.numer_denom_facts(3) 
    padic_fields_axioms by auto

lemma angular_component_factors_x:
  assumes "x  nonzero Qp"
  shows "x = (𝔭[^](ord x))  ι (angular_component x)"
proof-
  have 0: "angular_component x = (ac_Zp (numer x)) Zp(invZpac_Zp (denom x))"
    by (simp add: angular_component_def)
  have 1:  "(numer x) = (𝗉[^]Zp(ord_Zp (numer x))) Zp(ac_Zp (numer x))"
  proof-
    have "numer x  nonzero Zp"
     using assms unfolding Qp_def 
     by (simp add: numer_nonzero)
    then show ?thesis using ac_Zp_factors_x[of "numer x"]
      by (simp add: ac_Zp_factors')
  qed
  have 2: "(denom x) = (𝗉[^]Zp(ord_Zp (denom x))) Zp(ac_Zp (denom x))"
  proof-
    have "denom x  nonzero Zp"
      using nonzero_memE assms numer_denom_facts(2) 
      by (simp add: Qp.nonzero_closed)
    then show ?thesis 
      using ac_Zp_factors_x[of "denom x"] Zp.nonzero_closed Zp.nonzero_memE(2) by auto
  qed
  have 3: "ι (angular_component x) = frac (ac_Zp (numer x)) (ac_Zp (denom x))"
    by (metis "0" Qp_def Qp.nonzero_closed Qp.nonzero_memE(2) Zp.nonzero_closed Zp.nonzero_memE(2) Zp.numer_denom_facts(2) Zp_def Zp_division_Qp_0 ac_Zp_is_Unit angular_component_closed assms local.inc_def padic_fields.numer_denom_facts(2) padic_fields.numer_denom_facts(3) padic_fields_axioms)
  have 4: "(𝔭[^]((ord x)))  ι (angular_component x) = 
           (𝔭[^]((ord_Zp (numer x)) - (ord_Zp (denom x))))  frac (ac_Zp (numer x)) (ac_Zp (denom x))"
    using "3" ord_def by presburger
  have 5: "(𝔭[^]((ord x)))  ι (angular_component x) = 
           frac (𝗉[^]Zp((ord_Zp (numer x)))) (𝗉[^]Zp(ord_Zp (denom x)))  frac (ac_Zp (numer x)) (ac_Zp (denom x))"
  proof-
    have "(𝔭[^]((ord_Zp (numer x)) - (ord_Zp (denom x)))) 
        =  frac (𝗉[^]Zp((ord_Zp (numer x)))) (𝗉[^]Zp(ord_Zp (denom x)))"
      by (metis Qp_def Qp.nonzero_closed Zp_def assms domain.nonzero_memE(1) domain.nonzero_memE(2) numer_nonzero ord_pos p_pow_diff padic_fields.numer_denom_facts(2) padic_fields_axioms padic_int_is_domain prime)             
    then show ?thesis using 4 by metis 
  qed
  have 6: "(𝔭[^]((ord x)))  ι (angular_component x) = 
           frac (𝗉[^]Zp((ord_Zp (numer x))) Zp(ac_Zp (numer x))) (𝗉[^]Zp(ord_Zp (denom x)) Zp(ac_Zp (denom x)))"
    using 5 frac_mult[of "𝗉[^]Zp((ord_Zp (numer x)))" " (𝗉[^]Zp(ord_Zp (denom x)))" "(ac_Zp (numer x)) " " (ac_Zp (denom x))"] mult_comm 
    by (metis "2" Qp_def Qp.nonzero_closed Zp.integral_iff Zp.nonzero_closed Zp.nonzero_memE(2) ac_Zp_in_Zp assms local.numer_denom_facts(2) not_nonzero_Zp numer_nonzero ord_pos p_int_pow_nonzero)
  then show ?thesis 
    using "1" "2" nonzero_memE assms numer_denom_facts(5) Qp.nonzero_closed by auto   
qed

lemma angular_component_mult:
  assumes "x  nonzero Qp"
  assumes "y  nonzero Qp"
  shows "angular_component (x  y) = (angular_component  x) Zp(angular_component  y)"
proof-
  obtain a b where "a = numer x" and
                   "b = denom x" and 
                   a_nz: "a  nonzero Zp" and
                   b_nz: "b  nonzero Zp" and
                   x_frac: "x = frac a b"
    using assms Qp.nonzero_memE[of x] 
    by (meson local.numer_denom_facts(1) local.numer_denom_facts(2) 
        local.numer_denom_facts(3) local.numer_denom_facts(5) not_nonzero_Zp)
  obtain c d where "c = numer y" and
                   "d = denom y" and 
                   c_nz: "c  nonzero Zp" and
                   d_nz: "d  nonzero Zp" and 
                   y_frac: "y = frac c d"
        using assms Qp.nonzero_memE[of y] 
    by (meson local.numer_denom_facts(1) local.numer_denom_facts(2) local.numer_denom_facts(3) local.numer_denom_facts(5) not_nonzero_Zp)      
  have 0: "(x  y) = frac (a Zpc) (b Zpd)"
    using  a_nz b_nz c_nz d_nz frac_mult x_frac y_frac
    by (simp add: Zp.nonzero_closed)
  have 1: "angular_component (x  y) = (ac_Zp (a Zpc)) ZpinvZp(ac_Zp (b Zpd))"
    by (metis (mono_tags, lifting) "0" Qp.nonzero_mult_closed Zp.integral_iff Zp.nonzero_closed Zp.nonzero_mult_closed a_nz ac_fract assms(1) assms(2) b_nz c_nz d_nz not_nonzero_Zp)   
  have 2: "angular_component (x  y) = (ac_Zp a) Zp(ac_Zp c) ZpinvZp((ac_Zp b) Zp(ac_Zp d))"
    by (simp add: "1" a_nz ac_Zp_mult b_nz c_nz d_nz)
  have 3: "angular_component (x  y) = (ac_Zp a) Zp(ac_Zp c) ZpinvZp(ac_Zp b) ZpinvZp(ac_Zp d)"
    using 2 
    by (simp add: Zp.inv_of_prod Zp.nonzero_closed Zp.nonzero_memE(2) ac_Zp_is_Unit b_nz d_nz mult_assoc)

  have 4: "angular_component (x  y) = (ac_Zp a) ZpinvZp(ac_Zp b) Zp(ac_Zp c) ZpinvZp(ac_Zp d)"
    using "3"  a_nz ac_Zp_in_Zp ac_Zp_is_Unit b_nz c_nz m_assoc mult_comm 
          mult_assoc by auto  
  have 5: "angular_component (x  y) = ((ac_Zp a) ZpinvZp(ac_Zp b)) Zp( (ac_Zp c) ZpinvZp(ac_Zp d))"
    using 4 by (simp add: mult_assoc) 
  then show ?thesis 
    by (simp add: Zp_def a = numer x b = denom x c = numer y d = denom y
        padic_fields.angular_component_def padic_fields_axioms)
qed

lemma angular_component_inv:
  assumes "x  nonzero Qp"
  shows "angular_component (invQpx) = invZp(angular_component x)"
  by (metis Qp_def Qp.one_closed Zp.Units_r_inv Zp.inv_unique' Zp.nonzero_closed Zp.nonzero_one_closed Zp.zero_not_one Zp_def ι_def ac_Zp_is_Unit angular_component_closed angular_component_mult assms frac_nonzero_inv(1) frac_nonzero_inv(2) inc_equation inc_of_one nonzero_inverse_Qp padic_fields.ac_fract padic_fields_axioms)

lemma angular_component_one: 
"angular_component 𝟭 = 𝟭Zp⇙"
  using ι_def ac_Zp_one ac_fract inc_equation inc_of_one 
    Zp.nonzero_one_closed by fastforce

lemma angular_component_ord_zero:
  assumes "ord x = 0"
  assumes "x  nonzero Qp"
  shows "ι (angular_component x) = x"
proof-
  have 0: "ord x 0"
    using assms by auto 
  have 1: "x  nonzero Qp"
  proof-
    have "x  𝟬"
      using nonzero_def assms(2)  Qp.nonzero_memE(2) by auto      
    then show ?thesis 
      by (simp add: assms(2))
  qed
  obtain a where a_def: "a  nonzero Zp  ι a = x"
    using 0 1 assms Qp_inc_id[of x] 
    by metis
  then have "x = frac a 𝟭Zp⇙"
    using local.inc_def Zp.nonzero_closed by blast
  then have "angular_component x = ac_Zp a ZpinvZp(ac_Zp 𝟭Zp)"
    using ac_fract[of x a ]  "1" nonzero_memE Qp_def Zp.nonzero_closed Zp.nonzero_one_closed Zp_def a_def 
      local.frac_closed padic_fields.ac_fract padic_fields_axioms by auto
  then have "angular_component x = ac_Zp a ZpinvZp𝟭Zp⇙"
    by (simp add: ac_Zp_one)
  then have 0: "angular_component x = ac_Zp a Zp𝟭Zp⇙"
    by simp
  have "ac_Zp a  nonzero Zp"
    using Zp.Units_nonzero Zp.nonzero_closed Zp.not_nonzero_memI a_def ac_Zp_is_Unit by auto
  thus ?thesis using 0 
    by (metis Zp.l_one Zp.nonzero_closed Zp_defs(1) Zp_defs(4) a_def ac_Zp_factors' 
        assms(1) int_pow_0 mult_comm ord_of_inc)
qed

lemma angular_component_of_inclusion:
  assumes "x  nonzero Zp"
  assumes "y = ι x"
  shows "angular_component y = ac_Zp x"
proof-
  have "y = local.frac x 𝟭Zp⇙"
    using assms 
    by (simp add: Zp.nonzero_closed local.inc_def)
  then have 0: "angular_component y = (ac_Zp x) ZpinvZpac_Zp (𝟭Zp)"
    using assms  ac_fract[of y x ] 
    by (simp add: y = ι x Zp.nonzero_closed Zp.nonzero_one_closed local.frac_closed)
  have 1: "ac_Zp 𝟭Zp= 𝟭Zp⇙"
    using ac_Zp_one by blast
  have 2: "(ac_Zp x)   carrier Zp"
    using Zp.Units_closed Zp.nonzero_closed ac_Zp_is_Unit assms(1) nonzero_fraction_imp_numer_not_zero nonzero_numer_imp_nonzero_fraction by auto  
  have 3: "invZp(ac_Zp 𝟭Zp) = 𝟭Zp⇙"
    using 1 
    by simp  
  have 4: "(ac_Zp x) ZpinvZpac_Zp (𝟭Zp) = (ac_Zp x) Zp𝟭Zp⇙"
    using "3" by auto
  have 5: "(ac_Zp x) ZpinvZpac_Zp (𝟭Zp) = (ac_Zp x)"
    using 4 2 Zp.domain_axioms  by simp
  then show ?thesis 
    by (simp add: "0")
qed

lemma res_uminus:
  assumes "k > 0"
  assumes "f  carrier Zp"
  assumes "c  carrier (Zp_res_ring k)"
  assumes "c = Zp_res_ring k(f k)"
  shows "c = ((Zpf) k)"
  using Zp_def assms(2) assms(4)  prime  Zp_residue_a_inv(1) by auto

lemma ord_fract:
  assumes "a  nonzero Qp"
  assumes "b  nonzero Qp"
  shows "ord (a ÷ b) = ord a - ord b"
  using assms nonzero_memE nonzero_def nonzero_inverse_Qp ord_mult ord_of_inv 
        Qp.nonzero_closed Qp.nonzero_memE(2) by presburger

lemma val_fract:
  assumes "a  carrier Qp"
  assumes "b  nonzero Qp"
  shows "val (a ÷ b) = val a - val b"
  apply(cases "a = 𝟬")
   apply (simp add: Units_eq_nonzero assms(2) val_def)
proof-
  assume "a  𝟬"
  then have 0: "a  nonzero Qp"
    by (simp add: Qp.nonzero_memI assms(1))
  have 1: "(a ÷ b)  nonzero Qp"
    by (simp add: "0" Localization.submonoid.m_closed Qp.nonzero_is_submonoid assms(2) nonzero_inverse_Qp)
  show ?thesis using 0 1 assms  
    by (simp add: ord_fract)
qed
  
lemma zero_fract:
  assumes "a  nonzero Qp"
  shows "𝟬 ÷ a = 𝟬"
  by (simp add: Units_eq_nonzero assms)

lemma fract_closed:
  assumes "a  carrier Qp"
  assumes "b  nonzero Qp"
  shows "(a ÷ b)  carrier Qp"
  by (simp add: Units_eq_nonzero assms(1) assms(2))

lemma val_of_power:
  assumes "a  nonzero Qp"
  shows "val (a[^](n::nat)) = n*(val a)"
  unfolding val_def using assms 
  by (simp add: Qp.nonzero_memE(2) Qp_nat_pow_nonzero nonzero_nat_pow_ord)

lemma val_zero_imp_val_pow_zero:
  assumes "a  carrier Qp"
  assumes "val a = 0"
  shows "val (a[^](n::nat)) = 0"
  apply(induction n) 
  using assms apply simp
proof- 
  fix n ::nat
  assume A: "val (a [^] n) = 0"
  have 0: "a [^] Suc n = a [^] n  a"
    by simp 
  show "val (a [^] Suc n) = 0 "
    unfolding 0 using A assms 
    by (simp add: val_mult)
qed

text‹val and ord of powers of p›

lemma val_p_nat_pow:
"val (𝔭[^](k::nat)) = eint k"
  by (simp add: ord_p_pow_nat)

lemma ord_p_int_pow:
"ord (𝔭[^](k::int)) = k"
  by (simp add: ord_p_pow_int)

lemma ord_p_nat_pow:
"ord (𝔭[^](k::nat)) = k"
  by (simp add: ord_p_pow_nat)

lemma val_nonzero_frac:
  assumes "a  nonzero Qp"
  assumes "b  nonzero Qp"
  assumes "val (a ÷ b) = c"
  shows "val a = val b + c"
proof-
  obtain n where n_def: "c = eint n"
    using assms val_ord by (metis (no_types, lifting) Qp.integral Qp.nonzero_closed inv_in_frac(1) inv_in_frac(2) val_def)
  have 0: "ord (a ÷ b) = n"
    by (metis assms(3) eint.distinct(2) eint.inject n_def val_def)
  have 1: "ord a - ord b = n"
    using 0 assms by (metis ord_fract)
  have 2: "ord a = ord b + n"
    using 1 by presburger 
  show "val a = val b + c"
    unfolding n_def using 2 assms 
    by (metis Qp.nonzero_memE(1) fract_closed local.fract_cancel_right n_def val_mult)
qed

lemma val_nonzero_frac':
  assumes "a  nonzero Qp"
  assumes "b  nonzero Qp"
  assumes "val (a ÷ b) = 0"
  shows "val a = val b"
  using val_nonzero_frac[of a b 0]
  by (metis arith_simps(50) assms(1) assms(2) assms(3))

lemma equal_val_imp_equal_ord: 
  assumes "a  nonzero Qp"
  assumes "b  carrier Qp"
  assumes "val a = val b"
  shows "ord a = ord b" "b  nonzero Qp"
  using assms 
   apply (metis eint.inject eint.simps(3) eint_ord_simps(4) val_nonzero val_ord)
  using assms unfolding nonzero_def 
  using val_def by auto

lemma int_pow_ord:
  assumes "a  nonzero Qp"
  shows "ord (a[^](i::int)) = i* (ord a)"
proof(induction i)
  show "n. ord (a [^] int n) = int n * ord a"
    using assms 
    by (metis int_pow_int mult_of_nat_commute nonzero_nat_pow_ord)
  show "n. ord (a [^] - int (Suc n)) = - int (Suc n) * ord a"
  proof- fix n 
    have "(a [^] - int (Suc n))  (a [^]  int (Suc n)) = a [^] (- int (Suc n) + int  (Suc n))"
      using assms Qp_int_pow_add by blast
    hence "(a [^] - int (Suc n))  (a [^]  int (Suc n)) = 𝟭"
      using assms 
      by (metis ab_group_add_class.ab_left_minus int_pow_0)
    hence "ord (a [^] - int (Suc n)) + ord (a [^]  int (Suc n)) = 0"
      by (metis Qp_int_pow_nonzero assms ord_mult ord_one)
    thus "ord (a [^] - int (Suc n)) = - int (Suc n) * ord a"
      using nonzero_nat_pow_ord assms 
      by (metis n. ord (a [^] int n) = int n * ord a add.inverse_inverse add_left_cancel more_arith_simps(4) more_arith_simps(7))
  qed
qed

lemma int_pow_val:
  assumes "a  nonzero Qp"
  shows "val (a[^](i::int)) = i* (val a)"
  using int_pow_ord Qp_int_pow_nonzero assms times_eint_simps(1) val_ord by presburger

lemma neg_int_pow_val:
  assumes "a  nonzero Qp"
  shows "val (a[^]-(i::int)) = - (val (a[^]i))"
  using int_pow_val[of a i]
  by (metis Qp_int_pow_nonzero assms int_pow_ord mult_minus_left val_ord val_p_int_pow val_p_int_pow_neg)

lemma int_pow_sum_val:
  assumes "a  nonzero Qp"
  shows "val (a[^]((i::int) + j)) =  (val (a[^]i)) + val (a[^]j)"
  using assms Qp.int_pow_add Qp_int_pow_nonzero Units_eq_nonzero val_mult0 by presburger

lemma int_pow_diff_val:
  assumes "a  nonzero Qp"
  shows "val (a[^]((i::int) - j)) =  (val (a[^]i)) - val (a[^]j)"
proof-
  obtain k where k_def: "val a = eint k"
    using assms val_ord by blast
  have 0: "val (a[^]((i::int) - j)) = eint ((i-j)*k)"
    using assms k_def int_pow_val times_eint_simps(1) by presburger
  show ?thesis unfolding 0 using k_def 
    by (metis "0" Qp_int_pow_nonzero Rings.ring_distribs(3) assms eint.simps(1) idiff_eint_eint int_pow_ord val_ord)
qed

lemma nat_add_pow_mult_assoc:
  assumes "a  carrier Qp"
  shows "[(n::nat)]a = [n]𝟭  a"
  using assms Qp.add_pow_ldistr Qp.l_one Qp.one_closed by presburger

lemma(in padic_integers) equal_res_imp_equal_ord_Zp:
  assumes "N > 0"
  assumes "a  carrier Zp"
  assumes "b  carrier Zp"
  assumes "a N = b N"
  assumes "a N  0"
  shows "ord_Zp a = ord_Zp b" 
proof-
  have "(a  b) N = 0"
    using assms(2) assms(3) assms(4) res_diff_zero_fact'' by blast 
  have "ord_Zp a < N"
    using assms zero_below_ord by force    
  then show ?thesis 
    by (smt R.minus_closed Zp_def (a  b) N = 0 above_ord_nonzero assms(2) assms(3) assms(4) assms(5) ord_Zp_ultrametric_eq' ord_Zp_ultrametric_eq'' padic_integers.ord_Zp_not_equal_imp_notequal(2) padic_integers.ord_of_nonzero(2) padic_integers.ord_pos padic_integers_axioms residue_of_zero(2))
qed

lemma(in padic_integers) equal_res_mod:
  assumes "N > k"
  assumes "a  carrier Zp"
  assumes "b  carrier Zp"
  assumes "a N = b N"
  shows "a k = b k"
proof-
  have 0: "a k = a N mod p^k"
    using assms 
    by (metis Zp_int_inc_rep Zp_int_inc_res less_or_eq_imp_le p_residue_padic_int)
  have 1: "b k = b N mod p^k"
    using assms 
    by (metis Zp_int_inc_rep Zp_int_inc_res less_or_eq_imp_le p_residue_padic_int) 
  show ?thesis unfolding 0 1 assms  using assms by blast 
qed

lemma Qp_char_0:
  assumes "(n::nat)  0"
  shows "[n]𝟭  𝟬"
proof-
  have "[n]Zp𝟭Zp 𝟬Zp⇙"
    using Zp_char_0' assms by blast
  thus ?thesis using inc_of_nat 
    by (metis Qp.nat_inc_zero Zp.nat_inc_zero Zp_nat_inc_closed ι_def inc_inj2)
qed

lemma Qp_char_0_int:
  assumes "(n::int)  0"
  shows "[n]𝟭  𝟬"
proof-
  have "[n]Zp𝟭Zp 𝟬Zp⇙"
    using Zp_char_0 assms 
    by (metis int_inc_mult linorder_neqE_linordered_idom mult_zero_l zero_less_mult_iff)    
  thus ?thesis using inc_of_int 
    by (metis Qp_def Zp_int_inc_closed ι_def inc_inj1)    
qed

lemma add_int_pow_inject:
  assumes "[(k::int)]𝟭 = [(j::int)]𝟭"
  shows "k = j"
proof(rule ccontr)
  assume A: "k  j"
  then have 0: "k - j 0 "
    by presburger 
  hence 1: "[(k-j)]𝟭  𝟬 "
    using Qp_char_0_int by blast
  hence 2: "[k]𝟭  [(-j)] 𝟭   𝟬 "
    by (metis (no_types, opaque_lifting) Qp.add.int_pow_mult Qp.one_closed diff_minus_eq_add diff_zero minus_diff_eq)
  hence 2: "[k]𝟭  [j] 𝟭   𝟬 "
    by (metis Qp.add.int_pow_mult Qp.int_inc_zero Qp.one_closed assms more_arith_simps(4))
  thus False using assms 
    using Qp.int_inc_closed Qp.r_right_minus_eq by blast
qed

lemma val_ord_nat_inc:
  assumes "(n::nat) > 0"
  shows "ord ([n]𝟭) = val([n]𝟭)"
  using val_ord assms Qp_char_0 
  by (metis less_irrefl_nat val_def)

lemma val_ord_int_inc:
  assumes "(n::int)  0"
  shows "ord ([n]𝟭) = val([n]𝟭)"
  using val_ord assms Qp_char_0_int val_def by presburger


      (********************************************************************************************)
      (********************************************************************************************)
      subsubsection‹Reduced Angular Component Maps›
      (********************************************************************************************)
      (********************************************************************************************)
  
definition ac :: "nat  padic_number  int" where
"ac n x = (if x = 𝟬 then 0 else (angular_component x) n)"

lemma ac_in_res_ring:
  assumes "x  nonzero Qp"
  shows "ac n x  carrier (Zp_res_ring n)"
  unfolding ac_def 
  using assms angular_component_closed[of x] 
  by (simp add: Qp.nonzero_memE(2) residues_closed)

lemma ac_in_res_ring'[simp]:
  assumes "x  carrier Qp"
  shows "ac n x  carrier (Zp_res_ring n)"
  apply(cases "x  nonzero Qp")
  using ac_in_res_ring apply blast
  by (metis Qp.nonzero_memI ac_def assms mod_0 mod_in_carrier p_res_ring_car p_residue_alt_def)
  
lemma ac_mult':
  assumes "x  nonzero Qp"
  assumes "y  nonzero Qp"
  shows "ac n (x  y) = (ac n x) Zp_res_ring n(ac n y)"
  unfolding ac_def 
proof-
  have 0: "angular_component (x  y) = angular_component x Zpangular_component y"
    using assms angular_component_mult[of x y]
    by auto 
  show "(if x  y = 𝟬 then 0 else angular_component (x  y) n) =
    (if x = 𝟬 then 0 else angular_component x n) Zp_res_ring n(if y = 𝟬 then 0 else angular_component y n)"
    using assms angular_component_closed[of x] angular_component_closed[of y]
    by (simp add: "0" Qp.integral_iff Qp.nonzero_closed Qp.nonzero_memE(2) residue_of_prod) 
qed

lemma ac_mult:
  assumes "x  carrier Qp"
  assumes "y  carrier Qp"
  shows "ac n (x  y) = (ac n x) Zp_res_ring n(ac n y)"
  apply(cases "x  nonzero Qp  y  nonzero Qp")
  apply (simp add: ac_mult')
  using assms unfolding ac_def 
  by (smt Qp.integral_iff Qp.nonzero_memI residue_times_zero_l residue_times_zero_r)
 
lemma ac_one[simp]:
  assumes "n  1"
  shows "ac n 𝟭 = 1"  
proof-
  have "ac n 𝟭 = 𝟭Zpn"
    unfolding ac_def
    using angular_component_one 
    by simp    
  then show ?thesis 
    using assms residue_of_one(2) by auto   
qed

lemma ac_one':
  assumes "n > 0"
  shows "ac n 𝟭 = 𝟭Zp_res_ring n⇙"
  using assms residue_ring_def 
  by auto

lemma ac_units:
  assumes "x  nonzero Qp"
  assumes "n > 0"
  shows "ac n x  Units (Zp_res_ring n)"
proof-
  obtain y where y_def: "y = inv x"
    by simp 
  have y_nz: "y  nonzero Qp"
    using assms(1) nonzero_inverse_Qp y_def 
    by blast    
  have 0: "ac n (x  y) = (ac n x) Zp_res_ring n(ac n y)"
    using ac_mult' assms(1) y_nz by blast
  have 1: "x  y = 𝟭" 
    by (metis Qp.field_axioms Qp.nonzero_memE Qp.nonzero_memE assms(1) field.field_inv(2) y_def)
  have 2: "(ac n x) Zp_res_ring n(ac n y) = 𝟭Zp_res_ring n⇙"
    using "0" "1" ac_one' assms(2) 
    by auto
  show ?thesis 
    by (metis "2" R_comm_monoid ac_in_res_ring assms(1) assms(2) comm_monoid.UnitsI(1) nonzero_inverse_Qp y_def)
        
qed

lemma ac_inv:
  assumes "x  nonzero Qp"
  assumes "n > 0"
  shows "ac n (inv x) = invZp_res_ring n(ac n x)"
proof-
  have "x  inv x = 𝟭"  
    by (simp add: Qp.monoid_axioms Units_eq_nonzero assms(1) monoid.Units_r_inv)    
  then have "ac n (x  inv x) = 𝟭Zp_res_ring n⇙"
    by (simp add: (x ÷ x) = 𝟭 ac_one' assms(2))
  then have "ac n x Zp_res_ring nac n (inv x) = 𝟭Zp_res_ring n⇙"
    using Units_eq_nonzero Units_inverse_Qp ac_mult' assms(1) 
    by metis    
  then show ?thesis 
    by (metis R_comm_monoid ac_in_res_ring assms(1) assms(2) comm_monoid.comm_inv_char nonzero_inverse_Qp)
qed

lemma ac_inv':
  assumes "x  nonzero Qp"
  assumes "n > 0"
  shows "ac n (inv x) Zp_res_ring n(ac n x) = 𝟭Zp_res_ring n⇙"
  using ac_inv[of x n] ac_units[of x n] assms 
  by (metis (no_types, opaque_lifting) Qp.field_axioms Qp.nonzero_memE 
      Qp.nonzero_memE Units_eq_nonzero Units_inverse_Qp ac_mult ac_one' field.field_inv(1))  

lemma ac_inv'':
  assumes "x  nonzero Qp"
  assumes "n > 0"
  shows " (ac n x) Zp_res_ring nac n (inv x)= 𝟭Zp_res_ring n⇙"
  using ac_inv' assms(1) assms(2) residue_mult_comm by auto

lemma ac_inv''':
  assumes "x  nonzero Qp"
  assumes "n > 0"
  shows "(ac n x) Zp_res_ring nac n (inv x)= 1"
        "ac n (inv x) Zp_res_ring n(ac n x) = 1"
  by (auto simp add: ac_inv'' ac_inv' assms(1) assms(2) p_res_ring_one)

lemma ac_val:
  assumes  "a  nonzero Qp"
  assumes "b  nonzero Qp"
  assumes "val a = val b"
  assumes "val (a  b)  val a + n" 
  shows "ac n a = ac n b"
proof-
  obtain m where m_def: "m = ord a"
    by simp 
  have 0: "a = (𝔭[^]m)  ι (angular_component a)"
    by (simp add: angular_component_factors_x assms(1) m_def)
  have 1: "b = (𝔭[^]m)  ι (angular_component b)"
  proof-
    have "ord b = ord a"
      using assms(1) assms(2) assms(3) by auto     
    then show ?thesis 
      by (metis angular_component_factors_x assms(2) m_def)
  qed    
  have 2: "(a b) = (𝔭[^]m)  ι (angular_component a)
                      (𝔭[^]m)  ι (angular_component b)"
    using "0" "1" by auto
  have 3: "(a b) = (𝔭[^]m) ( ι (angular_component a)
                                      ι (angular_component b))"
    using 2 assms angular_component_closed inc_closed Qp.cring_simprules Qp.r_minus_distr
    by (metis (no_types, lifting) p_intpow_closed(1))
  have 4: "(a b) = (𝔭[^]m) ( ι ((angular_component a)
                                          Zp(angular_component b)))"
    by (simp add: "3" angular_component_closed assms(1) assms(2) inc_of_diff)    
  have 5: "val (a b) = m + val (( ι ((angular_component a)
                                          Zp(angular_component b))))"
    by (metis "4" Zp.nonzero_one_closed angular_component_closed assms(1) assms(2)
        cring.cring_simprules(4) frac_closed local.inc_def ord_p_pow_int p_intpow_closed(1)
        p_intpow_closed(2) Zp.domain_axioms domain_def val_mult val_ord)
  have 6: "m = val a"
    using Qp_def assms(1) m_def by auto
  have 7: "m + val (ι (angular_component a Zpangular_component b))  val a + n"
    using "5" assms(4) by presburger
  have 8: "m + val (ι (angular_component a Zpangular_component b))  m + n"
    using "6" "7" 
    by (metis plus_eint_simps(1))
  have 9: "val (ι (angular_component a Zpangular_component b))  n"
    using 8 add_le_cancel_left eint_ile eint_ord_simps(1) linear plus_eint_simps(1)
    by metis
  have 10: "val_Zp (angular_component a Zpangular_component b)  n"
    using 9 
    by (metis angular_component_closed assms(1) assms(2) cring.cring_simprules(4)
        Zp.domain_axioms domain_def val_of_inc)
  have 11: "(angular_component a Zpangular_component b) n = 𝟬Zp_res_ring n⇙"
    using 9 
    by (simp add: "10" angular_component_closed assms(1) assms(2) p_res_ring_zero zero_below_val_Zp)          
  have 12: "(angular_component a n) Zp_res_ring n(angular_component b n) = 𝟬Zp_res_ring n⇙"
    using "11" angular_component_closed assms(2) residue_of_diff by auto
  have 13: "(angular_component a n) = (angular_component b n)"
    apply(cases "n = 0")
    apply (metis angular_component_closed assms(1) assms(2) p_res_ring_0' residues_closed)   
    using 12 angular_component_closed residue_closed ring.ring_simprules[of "Zp_res_ring n"] 
    by (meson assms(1) assms(2) cring_def prime residues.cring residues_n ring.r_right_minus_eq) 
  then show ?thesis 
    by (simp add: Qp.nonzero_memE ac_def assms(1) assms(2))
qed

lemma angular_component_nat_pow:
  assumes "a  nonzero Qp"
  shows "angular_component (a [^] (k::nat)) = (angular_component a) [^]Zpk"
  apply(induction k)
  apply (simp add: angular_component_one)
  by (simp add: Qp_nat_pow_nonzero angular_component_mult assms) 

lemma angular_component_int_pow:
  assumes "a  nonzero Qp"
  shows "angular_component (a [^] (k::int)) = (angular_component a) [^]Zpk"
  apply(cases "k  0")
  using angular_component_nat_pow assms 
   apply (metis int_pow_int nonneg_int_cases)
proof-
  assume "¬ 0 k"
  show "angular_component (a [^] k) = angular_component a [^]Zpk"
    using angular_component_nat_pow[of a "nat (-k)"] assms 
        Qp_nat_pow_nonzero[of a] ¬ 0  k angular_component_inv[of "(a [^] k)"] int_pow_def2
    by (metis angular_component_nat_pow angular_component_inv)
qed

lemma ac_nat_pow:
  assumes "a  nonzero Qp"
  shows "ac n (a [^] (k::nat)) = (ac n a)^ k mod (p^n)"
proof(cases "k = 0")
  case True
  show ?thesis apply(cases "n = 0")
  apply (metis Group.nat_pow_0 Qp.one_closed True ac_in_res_ring' mod_self p_res_ring_0' power_0)
  using True prime residues.one_cong residues.res_one_eq residues_n by auto
next
  case False
  show ?thesis 
    apply(cases "n = 0")
     apply (metis Qp_nat_pow_nonzero ac_in_res_ring assms mod_by_1 p_res_ring_0' power_0)
      using assms angular_component_nat_pow 
      by (metis Qp.nonzero_closed Qp.nonzero_pow_nonzero Qp.not_nonzero_memI ac_def angular_component_closed neq0_conv power_residue)
qed

lemma ac_nat_pow':
  assumes "a  nonzero Qp"
  assumes "n 0"
  shows "ac n (a [^] (k::nat)) = (ac n a)[^]Zp_res_ring nk"
proof-
  have "(ac n a)^ k mod (p^n) = (ac n a)[^]Zp_res_ring nk"
    apply(induction k)
    apply (metis Group.nat_pow_0 assms(2) prime residues.pow_cong residues_n)
    by (metis Group.nat_pow_Suc Qp_nat_pow_nonzero ac_mult' ac_nat_pow assms(1))
  then show ?thesis 
    by (simp add: ac_nat_pow assms(1))
qed

lemma ac_int_pow:
  assumes "a  nonzero Qp"
  assumes "n > 0"
  shows "ac n (a [^] (k::int)) = (ac n a)[^]Zp_res_ring nk"
  apply(cases "k 0") 
  using assms ac_nat_pow' 
  apply (metis int.lless_eq int.nat_pow_0 p_residues pow_nat residues_def)
  using assms ac_nat_pow' ac_inv[of "a [^] k"] ac_units[of "a [^] k"]
  by (metis Qp_nat_pow_nonzero ac_inv int_pow_def2 neq0_conv)  

lemma angular_component_p:
"angular_component 𝔭 = 𝟭Zp⇙"
proof-
  have "𝔭 = frac 𝗉 𝟭Zp⇙"
    by (simp add: Zp_nat_inc_closed local.inc_def p_inc)
  then have 0: "angular_component 𝔭 = (ac_Zp 𝗉) ZpinvZp(ac_Zp 𝟭Zp)"
    using ac_Zp_one unfolding angular_component_def 
    by (metis Qp_def Qp.int_inc_closed Zp.one_nonzero Zp_int_inc_closed ac_fract 
        local.numer_denom_facts(2) local.numer_denom_facts(5) nonzero_fraction_imp_nonzero_numer
        nonzero_numer_imp_nonzero_fraction numer_nonzero p_nonzero)
  then have "angular_component 𝔭 = (ac_Zp 𝗉) ZpinvZp𝟭Zp⇙"
    by (simp add: ac_Zp_one)
  then have "angular_component 𝔭 = (ac_Zp 𝗉)"
    by (simp add: ac_Zp_p)  
  then show ?thesis 
    using ac_Zp_p
    by simp
qed

lemma angular_component_p_nat_pow:
"angular_component (𝔭 [^] (n::nat)) = 𝟭Zp⇙"
  apply(induction n)
  apply (simp add: angular_component_one)
  using angular_component_nat_pow angular_component_p nat_pow_one p_nonzero  Zp.nat_pow_one 
  by presburger

lemma angular_component_p_int_pow:
"angular_component (𝔭 [^] (n::int)) = 𝟭Zp⇙"
  apply(cases "n  0")
  apply (metis angular_component_p_nat_pow int_pow_int nonneg_int_cases)
  using angular_component_p_nat_pow[of "nat (-n)"] angular_component_inv[of "(𝔭 [^] n)"] angular_component_inv[of "𝔭 [^] (nat (-n))"] 
  by (metis (mono_tags, opaque_lifting) Group.nat_pow_0 Zp.inv_one add.inverse_neutral angular_component_one int_nat_eq
      int_pow_def2 nat_0_iff nat_int nat_zminus_int p_natpow_closed(2) )
  
lemma ac_p_nat_pow:
  assumes "k > 0"
  shows "ac k (𝔭 [^] (n::nat)) = 1"
proof-
  have "¬ (𝔭 [^] n) = 𝟬"
    by (simp add: Qp.nonzero_memE)
  have " angular_component (𝔭 [^] n) k = 1"
    using assms angular_component_p_nat_pow[of n]  ac_def ac_one angular_component_one 
    by auto
  then show ?thesis 
    unfolding ac_def using angular_component_p_nat_pow[of n] 
    by (simp add: (𝔭 [^] n)  𝟬)
qed

lemma ac_p:
  assumes "k > 0"
  shows "ac k 𝔭 = 1"
  by (metis Qp.int_inc_closed Qp.nat_pow_eone ac_p_nat_pow assms)

lemma ac_p_int_pow:
  assumes "k > 0"
  shows "ac k (𝔭 [^] (n::int)) = 1"
  using Qp.nonzero_memE(2) ac_def ac_one' angular_component_one angular_component_p_int_pow
        assms p_intpow_closed(2) p_res_ring_one by auto
  
lemma angular_component_p_nat_pow_factor:
  assumes "a  nonzero Qp"
  shows "angular_component ((𝔭 [^] (n::nat))  a) = angular_component a"
proof-
  have 0: "angular_component ((𝔭 [^] n)  a) = angular_component (𝔭 [^] n) Zpangular_component a"
    using assms angular_component_mult[of "(𝔭 [^] (n::nat))" a] p_natpow_closed(2) 
    by blast
  have 1: "angular_component (𝔭 [^] n) = 𝟭Zp⇙"
    by (simp add: angular_component_p_nat_pow)
  have 2: "angular_component ((𝔭 [^] n)  a) = 𝟭ZpZpangular_component a"
    by (simp add: "0" "1")
  then show ?thesis using angular_component_closed[of a] assms Zp.domain_axioms
    by (simp add: assms cring.cring_simprules(12) domain.axioms(1))
qed

lemma ac_p_nat_pow_factor:
  assumes "m > 0"
  assumes "a  nonzero Qp"
  shows "ac m ((𝔭 [^] (n::nat))  a) = ac m a"
  using angular_component_p_nat_pow_factor assms  ac_def 
  by (metis (no_types, lifting) Qp.field_axioms Qp_nat_pow_nonzero Qp.nonzero_memE 
      Qp.nonzero_memE Ring.integral p_nonzero)
  
lemma angular_component_p_nat_pow_factor_right:
  assumes "a  nonzero Qp"
  shows "angular_component (a  (𝔭 [^] (n::nat))) = angular_component a"
proof-
  have "((𝔭 [^] (n::nat))  a) = (a  (𝔭 [^] (n::nat)))"
    using assms Qp.domain_axioms domain_def 
    by (simp add: assms domain_def Qp.nonzero_memE cring.cring_simprules(14))
  then show ?thesis 
    using angular_component_p_nat_pow_factor[of a n] 
    by (simp add: assms)
qed

lemma ac_p_nat_pow_factor_right:
  assumes "m > 0"
  assumes "a  carrier Qp"
  shows "ac m (a  (𝔭 [^] (n::nat))) = ac m a"
  using assms angular_component_p_nat_pow_factor_right[of a n] 
  unfolding ac_def 
  by (metis Qp.integral Qp.l_null Qp.not_nonzero_memE Qp.not_nonzero_memI
      angular_component_p_nat_pow_factor_right p_natpow_closed(1) p_natpow_closed(2))

lemma angular_component_p_int_pow_factor:
  assumes "a  carrier Qp"
  shows "angular_component ((𝔭 [^] (n::int))  a) = angular_component a"
  by (metis Qp.integral_iff Qp.l_one Qp.nonzero_memI Qp.one_nonzero angular_component_mult
      angular_component_one angular_component_p_int_pow assms p_intpow_closed(1) p_intpow_closed(2))
  
lemma ac_p_int_pow_factor:
  assumes "a  nonzero Qp"
  shows "ac m ((𝔭 [^] (n::int))  a) = ac m a"
  apply(cases "m = 0")
   apply (metis (no_types, lifting) Qp.integral Qp.nonzero_closed Qp.nonzero_memE(2) 
          ac_def angular_component_p_int_pow_factor assms p_intpow_closed(2))
  using assms angular_component_p_int_pow_factor[of a n]
  by (metis (no_types, lifting) Qp.integral Qp.nonzero_closed Qp.not_nonzero_memI ac_def 
      p_intpow_closed(2))

lemma angular_component_p_int_pow_factor_right:
  assumes "a  carrier Qp"
  shows "angular_component (a  (𝔭 [^] (n::int))) = angular_component a"
  using Qp.m_comm angular_component_p_int_pow_factor assms p_intpow_closed(1) by auto

lemma ac_p_int_pow_factor_right:
  assumes "a  carrier Qp"
  shows "ac m (a  (𝔭 [^] (n::int))) = ac m a"
  using assms angular_component_p_int_pow_factor_right unfolding ac_def 
  using Qp.integral_iff Qp.nonzero_memE(2) p_intpow_closed(1) p_intpow_closed(2) by presburger


(**************************************************************************************************)
(**************************************************************************************************)
subsection‹An Inverse for the inclusion map $\iota$›
(**************************************************************************************************)
(**************************************************************************************************)

definition to_Zp where 
"to_Zp a = (if (a  𝒪p) then (SOME x. x  carrier Zp  ι x = a) else 𝟬Zp)"

lemma to_Zp_closed:
  assumes "a  carrier Qp"
  shows "to_Zp a  carrier Zp"
  apply(cases "a  𝒪p")
  using assms unfolding to_Zp_def ι_def 
  apply (smt image_iff tfl_some)
    by simp

lemma to_Zp_inc: 
  assumes "a  𝒪p"
  shows "ι (to_Zp a) = a"
proof-
  obtain c where c_def: "c = (SOME x. x  carrier Zp  ι x = a)"
    by simp
  have "( x. x  carrier Zp  ι x = a)"
    using assms(1) 
    by blast
  then  have "c  carrier Zp  ι c = a"
    using c_def 
    by (metis (mono_tags, lifting)  tfl_some)
  then show "ι (to_Zp a) = a" 
    using to_Zp_def c_def assms(1) 
    by auto 
qed

lemma inc_to_Zp: 
 assumes "b  carrier Zp"
 shows "to_Zp (ι b) = b"
proof-
  have "ι (to_Zp (ι b)) = (ι b)"
    using assms to_Zp_inc[of "ι b"]
    by blast
  then show ?thesis 
    using inc_inj2[of b "to_Zp (ι b)"] assms to_Zp_closed inc_closed 
    unfolding ι_def Qp_def 
    by auto      
qed

lemma to_Zp_add: 
  assumes "a  𝒪p"
  assumes "b  𝒪p"
  shows "to_Zp (a  b) = to_Zp a Zp(to_Zp b)"
  by (metis (no_types, lifting) Zp.domain_axioms assms(1) assms(2)
      cring.cring_simprules(1) domain.axioms(1) imageE inc_of_sum inc_to_Zp)

lemma to_Zp_mult: 
  assumes "a  𝒪p"
  assumes "b  𝒪p"
  shows "to_Zp (a  b) = to_Zp a Zp(to_Zp b)"
proof-
  have "(a  b)  𝒪p"
    by (simp add: val_ring_subring assms(1) assms(2) subringE(6))
  then have 
    "ι ((to_Zp a) Zp(to_Zp) b) =  ((ι (to_Zp a))  (ι (to_Zp b)))"
    using assms(1) assms(2) inc_of_prod inc_to_Zp 
    by auto
  then have "ι ((to_Zp a) Zp(to_Zp) b) =  a b"
    by (simp add: assms(1) assms(2) to_Zp_inc)
  then have "to_Zp ( ι ((to_Zp a) Zp(to_Zp) b)) = to_Zp (a b)"
    by simp
  then show ?thesis 
    by (metis (no_types, opaque_lifting) Zp.domain_axioms val_ring_subring assms(1) assms(2) 
        cring.cring_simprules(5) domain.axioms(1) inc_to_Zp subringE(1) subset_iff to_Zp_closed)
qed

lemma to_Zp_minus:
  assumes "a  𝒪p"
  assumes "b  𝒪p"
  shows "to_Zp (a  b) = to_Zp a Zp(to_Zp b)"
  by (metis (no_types, lifting) Zp.domain_axioms assms(1) assms(2) cring_def domain.axioms(1)
      image_iff inc_of_diff inc_to_Zp ring.ring_simprules(4))

lemma to_Zp_one: 
  shows "to_Zp 𝟭 = 𝟭Zp⇙"
  using Zp_def Zp.one_closed ι_def inc_of_one inc_to_Zp padic_integers_axioms 
  by fastforce

lemma to_Zp_zero: 
  shows "to_Zp 𝟬 = 𝟬Zp⇙"
  using Qp_def Zp_def Zp.domain_axioms ι_def domain_frac.inc_inj1 inc_to_Zp 
        padic_integers_axioms to_Zp_def domain_frac_axioms by fastforce

lemma to_Zp_ominus:
  assumes "a  𝒪p"
  shows "to_Zp ( a) = Zp(to_Zp a)"
proof-
  have "a  𝒪p"
    by (simp add: val_ring_subring assms subringE(5))
  then show ?thesis 
    by (metis (no_types, lifting) Zp.domain_axioms Zp.nonzero_one_closed assms
        cring.cring_simprules(3) domain.axioms(1) frac_uminus image_iff inc_to_Zp local.inc_def)
qed

lemma to_Zp_val:
  assumes "a  𝒪p"
  shows "val_Zp (to_Zp a) = val a"
  by (metis assms imageE inc_to_Zp val_of_inc)

lemma val_of_nat_inc:
"val ([(k::nat)]𝟭)  0"
proof-
  have "[(k::nat)]𝟭  𝒪p"
    by (metis Zp.one_closed Zp_nat_mult_closed image_eqI inc_of_nat)
  thus ?thesis 
    using val_ring_memE(1) by blast
qed

lemma val_of_int_inc:
"val ([(k::int)]𝟭)  0"
proof-
  have "ι ([k] Zp𝟭Zp) = [k]𝟭"
    using inc_of_int by blast
  hence "[k]𝟭  𝒪p"
    using Zp.one_closed Zp_nat_mult_closed image_eqI inc_of_int 
    by blast    
  thus ?thesis 
    using val_ring_memE(1) by blast
qed

lemma to_Zp_nat_inc:
"to_Zp ([(a::nat)]𝟭) = [a]Zp𝟭Zp⇙"
  apply(induction a)
  using Qp.nat_inc_zero Zp.nat_inc_zero to_Zp_zero apply presburger
proof-
  fix a::nat assume A: "to_Zp ([a]  𝟭) = [a] Zp𝟭Zp⇙"
  have 0: "[(Suc a)]𝟭 = [a]𝟭  𝟭"
    using Qp.add.nat_pow_Suc by blast
  have 1: "[a]𝟭  𝒪p"
    using Qp.nat_inc_closed val_of_nat_inc val_ring_memI by blast
  have 2: "to_Zp ([Suc a]  𝟭) = (to_Zp ([a]𝟭)) Zp𝟭Zp⇙"
    using A 1 unfolding 0 
    by (metis Zp.cring_simprules(6) Zp.nat_inc_closed inc_of_nat inc_of_one inc_of_sum inc_to_Zp sum_closed)
  show "to_Zp ([Suc a]  𝟭) = [Suc a] Zp𝟭Zp⇙"
    unfolding  2 A 
    using add_comm nat_suc by presburger
qed

lemma to_Zp_int_neg:
"to_Zp ([(-int (a::nat))]𝟭) = Zp([int a]Zp𝟭Zp)"
proof-
  have 0: "[(-int (a::nat))]𝟭 =  ([int a]𝟭)"
    using Qp.add.int_pow_neg by blast
  have 1: "[int a]𝟭  𝒪p"
    using Qp.int_inc_closed val_of_int_inc val_ring_memI by blast
  show ?thesis using 1 unfolding 0 
    by (metis Zp.int_inc_closed inc_of_int inc_to_Zp to_Zp_ominus)
qed

lemma(in ring) int_add_pow:
"[int n]  𝟭 = [n]𝟭"
  unfolding add_pow_def 
  by (simp add: int_pow_int)

lemma int_add_pow:
"[int n]  𝟭 = [n]𝟭"
  unfolding add_pow_def 
  by (simp add: int_pow_int)

lemma Zp_int_add_pow:
"[int n] Zp𝟭Zp= [n]Zp𝟭Zp⇙"
  unfolding add_pow_def 
  by (simp add: int_pow_int)

lemma to_Zp_int_inc:
"to_Zp ([(a::int)]𝟭) = ([a]Zp𝟭Zp)"
  apply(induction a)
  unfolding int_add_pow Zp_int_add_pow
    using to_Zp_nat_inc apply blast
    unfolding to_Zp_int_neg using  Zp.add.int_pow_neg Zp.one_closed 
    by presburger

lemma to_Zp_nat_add_pow:
  assumes "a  𝒪p"
  shows "to_Zp ([(n::nat)]a) = [n]Zpto_Zp a"
  apply( induction n)
  using Qp.nat_mult_zero Zp_nat_inc_zero to_Zp_zero apply presburger
proof- fix n::nat assume A: "to_Zp ([n]  a) = [n] Zpto_Zp a"
  have 0: "[Suc n]  a = [n]a  a"
    using Qp.add.nat_pow_Suc by blast
  have 1: "to_Zp ([n]  a  a) = to_Zp ([n]  a) Zpto_Zp a"
    apply(rule to_Zp_add[of "[n]a" a] )
    apply( induction n) 
    using Qp.nat_mult_zero zero_in_val_ring apply blast
    unfolding Qp.add.nat_pow_Suc by(rule val_ring_add_closed, blast, rule assms, rule assms)
  show "to_Zp ([Suc n]  a) = [Suc n] Zpto_Zp a "
    unfolding Qp.add.nat_pow_Suc Zp.add.nat_pow_Suc 1 A by blast 
qed

lemma val_ring_res:
  assumes "a  𝒪p"
  assumes "b  𝒪p"
  shows "to_Zp (a  b) N = to_Zp a N Zp_res_ring Nto_Zp b N"
proof-
  have "to_Zp (a  b) N = (to_Zp a Zpto_Zp b) N"
    using assms to_Zp_minus by presburger
  then show ?thesis using assms residue_of_diff to_Zp_closed val_ring_memE(2)
    by (simp add: val_ring_memE(1))
qed

lemma res_diff_in_val_ring_imp_in_val_ring:
  assumes "a  𝒪p"
  assumes "b  carrier Qp"
  assumes "a  b  𝒪p"
  shows "b  𝒪p"
proof-
  have "b = a  (a  b)"
    unfolding a_minus_def 
    using assms val_ring_memE(2)[of a] Qp.r_neg2 Qp_def Qp.minus_sum by auto
  thus ?thesis  using assms val_ring_minus_closed[of a "a  b"]
    by presburger
qed

lemma(in padic_fields) equal_res_imp_res_diff_zero:
  assumes "a  𝒪p"
  assumes "b  𝒪p"
  assumes "to_Zp a N = to_Zp b N"
  shows "to_Zp (a  b) N = 0"
  using val_ring_res[of a b] assms 
  by (metis res_diff_zero_fact' to_Zp_closed val_ring_memE(2))

lemma(in padic_fields) equal_res_imp_val_diff_bound:
  assumes "a  𝒪p"
  assumes "b  𝒪p"
  assumes "to_Zp a N = to_Zp b N"
  shows "val (a  b)  N"
  using assms equal_res_imp_res_diff_zero[of a b N]
  by (metis to_Zp_closed to_Zp_minus to_Zp_val val_Zp_dist_def val_Zp_dist_res_eq2 val_ring_memE(2) val_ring_minus_closed) 
  
lemma(in padic_fields) equal_res_equal_val:
  assumes "a  𝒪p"
  assumes "b  𝒪p"
  assumes "val a < N"
  assumes "to_Zp a N = to_Zp b N"
  shows "val a = val b"
proof-
  have "val (a  b)  N"
    using assms equal_res_imp_val_diff_bound by blast 
  then have "val (a  b) > val a"
    using assms less_le_trans by blast
  then show "val a = val b"
    using assms by (meson ultrametric_equal_eq' val_ring_memE)
qed

lemma(in padic_fields) val_ring_equal_res_imp_equal_val:
  assumes "a  𝒪p"
  assumes "b  𝒪p"
  assumes "val a < eint N"
  assumes "val b < eint N"
  assumes "to_Zp a N = to_Zp b N"
  shows "val a = val b"
proof-
  have "val_Zp (to_Zp (a  b))  N"
    using assms val_ring_memE to_Zp_closed to_Zp_minus val_Zp_dist_def val_Zp_dist_res_eq2 by presburger
  thus ?thesis 
    by (meson assms(1) assms(2) assms(3) assms(5) equal_res_equal_val) 
qed

end
end