Theory RecEnSet

(*  Title:       Computably enumerable sets of natural numbers
    Author:      Michael Nedzelsky <MichaelNedzelsky at yandex.ru>, 2008
    Maintainer:  Michael Nedzelsky <MichaelNedzelsky at yandex.ru>
*)

section ‹Computably enumerable sets of natural numbers›

theory RecEnSet
imports PRecList PRecFun2 PRecFinSet PRecUnGr
begin

subsection ‹Basic definitions›

definition
  fn_to_set :: "(nat  nat  nat)  nat set" where
  "fn_to_set f = { x.  y. f x y = 0 }"

definition
  ce_sets :: "(nat set) set" where
  "ce_sets = { (fn_to_set p) | p. p  PrimRec2 }"

subsection ‹Basic properties of computably enumerable sets›

lemma ce_set_lm_1: "p  PrimRec2  fn_to_set p  ce_sets" by (auto simp add: ce_sets_def)

lemma ce_set_lm_2: " p  PrimRec2;  x. (x  A) = ( y. p x y = 0)  A  ce_sets"
proof -
  assume p_is_pr: "p  PrimRec2"
  assume " x. (x  A) = ( y. p x y = 0)"
  then have "A = fn_to_set p" by (unfold fn_to_set_def, auto)
  with p_is_pr show "A  ce_sets" by (simp add: ce_set_lm_1)
qed

lemma ce_set_lm_3: "A  ce_sets   p  PrimRec2. A = fn_to_set p"
proof -
  assume "A  ce_sets"
  then have "A  { (fn_to_set p) | p. p  PrimRec2 }" by (simp add: ce_sets_def)
  thus ?thesis by auto
qed

lemma ce_set_lm_4: "A  ce_sets   p  PrimRec2.  x. (x  A) = ( y. p x y = 0)"
proof -
  assume "A  ce_sets"
  then have " p  PrimRec2. A = fn_to_set p" by (rule ce_set_lm_3)
  then obtain p where p_is_pr: "p  PrimRec2" and L1: "A = fn_to_set p" ..
  from p_is_pr L1 show ?thesis by (unfold fn_to_set_def, auto)
qed

lemma ce_set_lm_5: " A  ce_sets; p  PrimRec1   { x . p x  A }  ce_sets"
proof -
  assume A1: "A  ce_sets"
  assume A2: "p  PrimRec1"
  from A1 have " pA  PrimRec2. A = fn_to_set pA" by (rule ce_set_lm_3)
  then obtain pA where pA_is_pr: "pA  PrimRec2" and S1: "A = fn_to_set pA" ..
  from S1 have S2: "A = { x .  y. pA x y = 0 }" by (simp add: fn_to_set_def)
  define q where "q x y = pA (p x) y" for x y
  from pA_is_pr A2 have q_is_pr: "q  PrimRec2" unfolding q_def by prec
  have " x. (p x  A) = ( y. q x y = 0)"
  proof -
    fix x show "(p x  A) = ( y. q x y = 0)"
    proof
      assume A: "p x  A"
      with S2 obtain y where L1: "pA (p x) y = 0" by auto
      then have "q x y = 0" by (simp add: q_def)
      thus " y. q x y = 0" ..
    next
      assume A: "y. q x y = 0"
      then obtain y where L1: "q x y = 0" ..
      then have "pA (p x) y = 0" by (simp add: q_def)
      with S2 show "p x  A" by auto
    qed
  qed
  then have "{ x . p x  A } = { x.  y. q x y = 0 }" by auto
  then have "{ x . p x  A } = fn_to_set q" by (simp add: fn_to_set_def)
  moreover from q_is_pr have "fn_to_set q  ce_sets" by (rule ce_set_lm_1)
  ultimately show ?thesis by auto
qed

lemma ce_set_lm_6: " A  ce_sets; A  {}   q  PrimRec1. A = { q x | x. x  UNIV }"
proof -
  assume A1: "A  ce_sets"
  assume A2: "A  {}"
  from A1 have " pA  PrimRec2. A = fn_to_set pA" by (rule ce_set_lm_3)
  then obtain pA where pA_is_pr: "pA  PrimRec2" and S1: "A = fn_to_set pA" ..
  from S1 have S2: "A = { x.  y. pA x y = 0 }" by (simp add: fn_to_set_def)
  from A2 obtain a where a_in: "a  A" by auto
  define q where "q z = (if pA (c_fst z) (c_snd z) = 0 then c_fst z else a)" for z
  from pA_is_pr have q_is_pr: "q  PrimRec1" unfolding q_def by prec
  have S3: " z. q z  A"
  proof
    fix z show "q z  A"
    proof cases
      assume A: "pA (c_fst z) (c_snd z) = 0"
      with S2 have "c_fst z  A" by auto
      moreover from A q_def have "q z = c_fst z" by simp
      ultimately show "q z  A" by auto
    next
      assume A: "pA (c_fst z) (c_snd z)  0"
      with q_def have "q z = a" by simp
      with a_in show "q z  A" by auto
    qed
  qed
  then have S4: "{ q x | x. x  UNIV }  A" by auto
  have S5: "A  { q x | x. x  UNIV }"
  proof
    fix x assume A: "x  A" show "x  {q x |x. x  UNIV}"
    proof
      from A S2 obtain y where L1: "pA x y = 0" by auto
      let ?z = "c_pair x y"
      from L1 have "q ?z = x" by (simp add: q_def)
      then have " u. q u = x" by blast
      then show "u. x = q u  u  UNIV" by auto
    qed
  qed
  from S4 S5 have S6: "A = { q x | x. x  UNIV }" by auto
  with q_is_pr show ?thesis by blast
qed

lemma ce_set_lm_7: " A  ce_sets; p  PrimRec1  { p x | x. x  A }  ce_sets"
proof -
  assume A1: "A  ce_sets"
  assume A2: "p  PrimRec1"
  let ?B = "{ p x | x. x  A }"
  fix y have S1: "(y  ?B) = ( x. x  A  (y = p x))" by auto
  from A1 have " pA  PrimRec2. A = fn_to_set pA" by (rule ce_set_lm_3)
  then obtain pA where pA_is_pr: "pA  PrimRec2" and S2: "A = fn_to_set pA" ..
  from S2 have S3: "A = { x.  y. pA x y = 0 }" by (simp add: fn_to_set_def)
  define q where "q y t = (if y = p (c_snd t) then pA (c_snd t) (c_fst t) else 1)" for y t
  from pA_is_pr A2 have q_is_pr: "q  PrimRec2" unfolding q_def by prec
  have L1: " y. (y  ?B) = ( z. q y z = 0)"
  proof - fix y show "(y  ?B) = ( z. q y z = 0)"
  proof
    assume AA1: "y  ?B"
    then obtain x0 where LL_2: "x0  A" and LL_3: "y = p x0" by auto
    from S3 have LL_4: "(x0  A) = ( z. pA x0 z = 0)" by auto
    from LL_2 LL_4 obtain z0 where LL_5: "pA x0 z0 = 0" by auto
    define t where "t = c_pair z0 x0"
    from t_def q_def LL_3 LL_5 have "q y t = 0" by simp
    then show " z. q y z = 0" by auto
  next
    assume A1: " z. q y z = 0"
    then obtain z0 where LL_1: "q y z0 = 0" ..
    have LL2: "y = p (c_snd z0)"
    proof (rule ccontr)
      assume "y  p (c_snd z0)"
      with q_def LL_1 have "q y z0 = 1" by auto
      with LL_1 show False by auto
    qed
    from LL2 LL_1 q_def have LL3: "pA (c_snd z0) (c_fst z0) = 0" by auto
    with S3 have LL4: "c_snd z0  A" by auto
    with LL2 show "y  {p x | x. x  A}" by auto
  qed
  qed
  then have L2: "?B = { y | y.  z. q y z = 0}" by auto
  with fn_to_set_def have "?B = fn_to_set q" by auto
  with q_is_pr ce_set_lm_1 show ?thesis by auto
qed

theorem ce_empty: "{}  ce_sets"
proof -
  let ?f = "(λ x a. (1::nat))"
  have S1: "?f  PrimRec2" by (rule const_is_pr_2)
  then have " x a. ?f x a  0" by simp
  then have "{x.  a. ?f x a = 0 }={}" by auto
  also have "fn_to_set ?f = " by (simp add: fn_to_set_def)
  with S1 show ?thesis by (auto simp add: ce_sets_def)
qed

theorem ce_univ: "UNIV  ce_sets"
proof -
  let ?f = "(λ x a. (0::nat))"
  have S1: "?f  PrimRec2" by (rule const_is_pr_2)
  then have " x a. ?f x a = 0" by simp
  then have "{x.  a. ?f x a = 0 }=UNIV" by auto
  also have "fn_to_set ?f = " by (simp add: fn_to_set_def)
  with S1 show ?thesis by (auto simp add: ce_sets_def)
qed

theorem ce_singleton: "{a}  ce_sets"
proof -
  let ?f = "λ x y. (abs_of_diff x a) + y"
  have S1: "?f  PrimRec2" using const_is_pr_2 [where ?n="a"] by prec
  then have " x y. (?f x y = 0) = (x=a  y=0)" by (simp add: abs_of_diff_eq)
  then have S2: "{x.  y. ?f x y = 0 }={a}" by auto
  have "fn_to_set ?f = {x.  y. ?f x y = 0 }" by (simp add: fn_to_set_def)
  with S2 have "fn_to_set ?f = {a}" by simp
  with S1 show ?thesis by (auto simp add: ce_sets_def)
qed

theorem ce_union: " A  ce_sets; B  ce_sets   A  B  ce_sets"
proof -
  assume A1: "A  ce_sets"
  then obtain p_a where S2: "p_a  PrimRec2" and S3: "A = fn_to_set p_a"
    by (auto simp add: ce_sets_def)
  assume A2: "B  ce_sets"
  then obtain p_b where S5: "p_b  PrimRec2" and S6: "B = fn_to_set p_b"
    by (auto simp add: ce_sets_def)
  let ?p = "(λ x y. (p_a x y) * (p_b x y))"
  from S2 S5 have S7: "?p  PrimRec2" by prec
  have S8: " x y. (?p x y = 0) = ((p_a x y = 0)  (p_b x y = 0))" by simp
  let ?C = "fn_to_set ?p"
  have S9: "?C = {x.  y. ?p x y = 0}" by (simp add: fn_to_set_def)
  from S3 have S10: "A = {x.  y. p_a x y = 0}" by (simp add: fn_to_set_def)
  from S6 have S11: "B = {x.  y. p_b x y = 0}" by (simp add: fn_to_set_def)
  from S10 S11 S9 S8 have S12: "?C = A  B" by auto
  from S7 have "?C  ce_sets" by (auto simp add: ce_sets_def)
  with S12 show ?thesis by simp
qed

theorem ce_intersect: " A  ce_sets; B  ce_sets   A  B  ce_sets"
proof -
  assume A1: "A  ce_sets"
  then obtain p_a where S2: "p_a  PrimRec2" and S3: "A = fn_to_set p_a"
    by (auto simp add: ce_sets_def)
  assume A2: "B  ce_sets"
  then obtain p_b where S5: "p_b  PrimRec2" and S6: "B = fn_to_set p_b"
    by (auto simp add: ce_sets_def)
  let ?p = "(λ x y. (p_a x (c_fst y)) + (p_b x (c_snd y)))"
  from S2 S5 have S7: "?p  PrimRec2" by prec
  have S8: " x. ( y. ?p x y = 0) = (( z. p_a x z = 0)  ( z. p_b x z = 0))"
  proof
    fix x show "( y. ?p x y = 0) = (( z. p_a x z = 0)  ( z. p_b x z = 0))"
    proof -
    have 1: "( y. ?p x y = 0)  (( z. p_a x z = 0)  ( z. p_b x z = 0))"
    by blast
    have 2: "(( z. p_a x z = 0)  ( z. p_b x z = 0))  ( y. ?p x y = 0)"
    proof -
      assume "(( z. p_a x z = 0)  ( z. p_b x z = 0))"
      then obtain z1 z2 where s_23: "p_a x z1 = 0" and s_24: "p_b x z2 = 0" by auto
      let ?y1 = "c_pair z1 z2"
      from s_23 have s_25: "p_a x (c_fst ?y1) = 0" by simp
      from s_24 have s_26: "p_b x (c_snd ?y1) = 0" by simp
      from s_25 s_26 have s_27: "p_a x (c_fst ?y1) + p_b x (c_snd ?y1) = 0" by simp
      then show ?thesis ..
    qed
    from 1 2 have "( y. ?p x y = 0) = (( z. p_a x z = 0)  ( z. p_b x z = 0))" by (rule iffI)
    then show ?thesis by auto
    qed
  qed
  let ?C = "fn_to_set ?p"
  have S9: "?C = {x.  y. ?p x y = 0}" by (simp add: fn_to_set_def)
  from S3 have S10: "A = {x.  y. p_a x y = 0}" by (simp add: fn_to_set_def)
  from S6 have S11: "B = {x.  y. p_b x y = 0}" by (simp add: fn_to_set_def)
  from S10 S11 S9 S8 have S12: "?C = A  B" by auto
  from S7 have "?C  ce_sets" by (auto simp add: ce_sets_def)
  with S12 show ?thesis by simp
qed

subsection ‹Enumeration of computably enumerable sets›

definition
  nat_to_ce_set :: "nat  (nat set)" where
  "nat_to_ce_set = (λ n. fn_to_set (pr_conv_1_to_2 (nat_to_pr n)))"

lemma nat_to_ce_set_lm_1: "nat_to_ce_set n = { x .  y. (nat_to_pr n) (c_pair x y) = 0 }"
proof -
  have S1: "nat_to_ce_set n = fn_to_set (pr_conv_1_to_2 (nat_to_pr n))" by (simp add: nat_to_ce_set_def)
  then have S2: "nat_to_ce_set n = { x .  y. (pr_conv_1_to_2 (nat_to_pr n)) x y = 0}" by (simp add: fn_to_set_def)
  have S3: " x y. (pr_conv_1_to_2 (nat_to_pr n)) x y = (nat_to_pr n) (c_pair x y)" by (simp add: pr_conv_1_to_2_def)
  from S2 S3 show ?thesis by auto
qed

lemma nat_to_ce_set_into_ce: "nat_to_ce_set n  ce_sets"
proof -
  have S1: "nat_to_ce_set n = fn_to_set (pr_conv_1_to_2 (nat_to_pr n))" by (simp add: nat_to_ce_set_def)
  have "(nat_to_pr n)  PrimRec1" by (rule nat_to_pr_into_pr)
  then have S2: "(pr_conv_1_to_2 (nat_to_pr n))  PrimRec2" by (rule pr_conv_1_to_2_lm)
  from S2 S1 show ?thesis by (simp add: ce_set_lm_1)
qed

lemma nat_to_ce_set_srj: "A  ce_sets   n. A = nat_to_ce_set n"
proof -
  assume A: "A  ce_sets"
  then have " p  PrimRec2. A = fn_to_set p" by (rule ce_set_lm_3)
  then obtain p where p_is_pr: "p  PrimRec2" and S1: "A = fn_to_set p" ..
  define q where "q = pr_conv_2_to_1 p"
  from p_is_pr have q_is_pr: "q  PrimRec1" by (unfold q_def, rule pr_conv_2_to_1_lm)
  from q_def have S2: "pr_conv_1_to_2 q = p" by simp
  let ?n = "index_of_pr q"
  from q_is_pr have "nat_to_pr ?n = q" by (rule index_of_pr_is_real)
  with S2 S1 have "A = fn_to_set (pr_conv_1_to_2 (nat_to_pr ?n))" by auto
  then have "A = nat_to_ce_set ?n" by (simp add: nat_to_ce_set_def)
  thus ?thesis ..
qed


subsection ‹Characteristic functions›

definition
  chf :: "nat set  (nat  nat)" ― ‹Characteristic function› where
  "chf = (λ A x. if x  A then 0 else 1 )"

definition
  zero_set :: "(nat  nat)  nat set" where
  "zero_set = (λ f. { x. f x = 0})"

lemma chf_lm_1 [simp]: "zero_set (chf A) = A" by (unfold chf_def, unfold zero_set_def, simp)

lemma chf_lm_2: "(x  A) = (chf A x = 0)" by (unfold chf_def, simp)

lemma chf_lm_3: "(x  A) = (chf A x = 1)" by (unfold chf_def, simp)

lemma chf_lm_4: "chf A  PrimRec1  A  ce_sets"
proof -
  assume A: "chf A  PrimRec1"
  define p where "p = chf A"
  from A p_def have p_is_pr: "p  PrimRec1" by auto
  define q where "q x y = p x" for x y :: nat
  from p_is_pr have q_is_pr: "q  PrimRec2" unfolding q_def by prec
  have S1: "A = {x. p(x) = 0}"
  proof -
    have "zero_set p = A" by (unfold p_def, simp)
    thus ?thesis by (simp add: zero_set_def)
  qed
  have S2: "fn_to_set q = {x.  y. q x y = 0}" by (simp add: fn_to_set_def)
  have S3: " x. (p x = 0) = ( y. q x y = 0)" by (unfold q_def, auto)
  then have S4: "{x. p x = 0} = {x.  y. q x y = 0}" by auto
  with S1 S2 have S5: "fn_to_set q = A" by auto
  from q_is_pr have "fn_to_set q  ce_sets" by (rule ce_set_lm_1)
  with S5 show ?thesis by auto
qed

lemma chf_lm_5: "finite A  chf A  PrimRec1"
proof -
  assume A: "finite A"
  define u where "u = set_to_nat A"
  from A have S1: "nat_to_set u = A" by (unfold u_def, rule nat_to_set_srj)
  have "chf A = (λ x. sgn2 (c_in x u))"
  proof
    fix x show "chf A x = sgn2 (c_in x u)"
    proof cases
      assume A: "x  A"
      then have S1_1: "chf A x = 0" by (simp add: chf_lm_2)
      from A S1 have "x  nat_to_set u" by auto
      then have "c_in x u = 1" by (simp add: x_in_u_eq)
      with S1_1 show ?thesis by simp
    next
      assume A: "x  A"
      then have S1_1: "chf A x = 1" by (simp add: chf_def)
      from A S1 have "x  nat_to_set u" by auto
      then have "c_in x u = 0" by (simp add: x_in_u_eq c_in_def)
      with S1_1 show ?thesis by simp
    qed
  qed
  moreover from c_in_is_pr have "(λ x. sgn2 (c_in x u))  PrimRec1" by prec
  ultimately show ?thesis by auto
qed

theorem ce_finite: "finite A  A  ce_sets"
proof -
  assume A: "finite A"
  then have "chf A  PrimRec1" by (rule chf_lm_5)
  then show ?thesis by (rule chf_lm_4)
qed

subsection ‹Computably enumerable relations›

definition
  ce_set_to_rel :: "nat set  (nat * nat) set" where
  "ce_set_to_rel = (λ A. { (c_fst x, c_snd x) | x. x  A})"

definition
  ce_rel_to_set :: "(nat * nat) set  nat set" where
  "ce_rel_to_set = (λ R. { c_pair x y | x y. (x,y)  R})"

definition
  ce_rels :: "((nat * nat) set) set" where
  "ce_rels = { R | R. ce_rel_to_set R  ce_sets }"

lemma ce_rel_lm_1 [simp]: "ce_set_to_rel (ce_rel_to_set r) = r"
proof
  show " ce_set_to_rel (ce_rel_to_set r)  r"
  proof fix z
    assume A: "z  ce_set_to_rel (ce_rel_to_set r)"
    then obtain u where L1: "u  (ce_rel_to_set r)" and L2: "z = (c_fst u, c_snd u)"
      unfolding ce_set_to_rel_def by auto
    from L1 obtain x y where L3: "(x,y)  r" and L4: "u = c_pair x y"
      unfolding ce_rel_to_set_def by auto
    from L4 have L5: "c_fst u = x" by simp
    from L4 have L6: "c_snd u = y" by simp
    from L5 L6 L2 have "z = (x,y)" by simp
    with L3 show "z  r" by auto
  qed
next
  show "r  ce_set_to_rel (ce_rel_to_set r)"
  proof fix z show "z  r  z  ce_set_to_rel (ce_rel_to_set r)"
    proof -
      assume A: "z  r"
      define x where "x = fst z"
      define y where "y = snd z"
      from x_def y_def have L1: "z = (x,y)" by simp
      define u where "u = c_pair x y"
      from A L1 u_def have L2: "u  ce_rel_to_set r" by (unfold ce_rel_to_set_def, auto)
      from L1 u_def have L3: "z = (c_fst u, c_snd u)" by simp
      from L2 L3 show "z  ce_set_to_rel (ce_rel_to_set r)" by (unfold ce_set_to_rel_def, auto)
    qed
  qed
qed

lemma ce_rel_lm_2 [simp]: "ce_rel_to_set (ce_set_to_rel A) = A"
proof
  show "ce_rel_to_set (ce_set_to_rel A)  A"
  proof fix z show "z  ce_rel_to_set (ce_set_to_rel A)  z  A"
    proof -
      assume A: "z  ce_rel_to_set (ce_set_to_rel A)"
      then obtain x y where L1: "z = c_pair x y" and L2: "(x,y)  ce_set_to_rel A"
        unfolding ce_rel_to_set_def by auto
      from L2 obtain u where L3: "(x,y) = (c_fst u, c_snd u)" and L4: "u  A"
        unfolding ce_set_to_rel_def by auto
      from L3 L1 have L5: "z = u" by simp
      with L4 show "z  A" by auto
    qed
  qed
next
  show "A  ce_rel_to_set (ce_set_to_rel A)"
  proof fix z show "z  A  z  ce_rel_to_set (ce_set_to_rel A)"
    proof -
      assume A: "z  A"
      then have L1: "(c_fst z, c_snd z)  ce_set_to_rel A" by (unfold ce_set_to_rel_def, auto)
      define x where "x = c_fst z"
      define y where "y = c_snd z"
      from L1 x_def y_def have L2: "(x,y)  ce_set_to_rel A" by simp
      then have L3: "c_pair x y  ce_rel_to_set (ce_set_to_rel A)" by (unfold ce_rel_to_set_def, auto)
      with x_def y_def show "z  ce_rel_to_set (ce_set_to_rel A)" by simp
    qed
  qed
qed

lemma ce_rels_def1: "ce_rels = { ce_set_to_rel A | A. A  ce_sets}"
proof
  show "ce_rels  {ce_set_to_rel A |A. A  ce_sets}"
  proof fix r show " r  ce_rels  r  {ce_set_to_rel A |A. A  ce_sets}"
    proof -
      assume A: "r  ce_rels"
      then have L1: "ce_rel_to_set r  ce_sets" by (unfold ce_rels_def, auto)
      define A where "A = ce_rel_to_set r"
      from A_def L1 have L2: "A  ce_sets" by auto
      from A_def have L3: "ce_set_to_rel A = r" by simp
      with L2 show "r  {ce_set_to_rel A |A. A  ce_sets}" by auto
    qed
  qed
next
  show "{ce_set_to_rel A |A. A  ce_sets}  ce_rels"
  proof fix r show "r  {ce_set_to_rel A |A. A  ce_sets}  r  ce_rels"
    proof -
      assume A: "r  {ce_set_to_rel A |A. A  ce_sets}"
      then obtain A where L1: "r = ce_set_to_rel A" and L2: "A  ce_sets" by auto
      from L1 have "ce_rel_to_set r = A" by simp
      with L2 show "r  ce_rels" unfolding ce_rels_def by auto
    qed
  qed
qed

lemma ce_rel_to_set_inj: "inj ce_rel_to_set"
proof (rule inj_on_inverseI)
  fix x assume A: "(x::(nat×nat) set)  UNIV" show "ce_set_to_rel (ce_rel_to_set x) = x" by (rule ce_rel_lm_1)
qed

lemma ce_rel_to_set_srj: "surj ce_rel_to_set"
proof (rule surjI [where ?f=ce_set_to_rel])
  fix x show "ce_rel_to_set (ce_set_to_rel x) = x" by (rule ce_rel_lm_2)
qed

lemma ce_rel_to_set_bij: "bij ce_rel_to_set"
proof (rule bijI)
  show "inj ce_rel_to_set" by (rule ce_rel_to_set_inj)
next
  show "surj ce_rel_to_set" by (rule ce_rel_to_set_srj)
qed

lemma ce_set_to_rel_inj: "inj ce_set_to_rel"
proof (rule inj_on_inverseI)
  fix x assume A: "(x::nat set)  UNIV" show "ce_rel_to_set (ce_set_to_rel x) = x" by (rule ce_rel_lm_2)
qed

lemma ce_set_to_rel_srj: "surj ce_set_to_rel"
proof (rule surjI [where ?f=ce_rel_to_set])
  fix x show "ce_set_to_rel (ce_rel_to_set x) = x" by (rule ce_rel_lm_1)
qed

lemma ce_set_to_rel_bij: "bij ce_set_to_rel"
proof (rule bijI)
  show "inj ce_set_to_rel" by (rule ce_set_to_rel_inj)
next
  show "surj ce_set_to_rel" by (rule ce_set_to_rel_srj)
qed

lemma ce_rel_lm_3: "A  ce_sets  ce_set_to_rel A  ce_rels"
proof -
  assume A: "A  ce_sets"
  from A ce_rels_def1 show ?thesis by auto
qed

lemma ce_rel_lm_4: "ce_set_to_rel A  ce_rels  A  ce_sets"
proof -
  assume A: "ce_set_to_rel A  ce_rels"
  from A show ?thesis by (unfold ce_rels_def, auto)
qed

lemma ce_rel_lm_5: "(A  ce_sets) = (ce_set_to_rel A  ce_rels)"
proof
  assume "A  ce_sets" then show "ce_set_to_rel A  ce_rels" by (rule ce_rel_lm_3)
next
  assume "ce_set_to_rel A  ce_rels" then show "A  ce_sets" by (rule ce_rel_lm_4)
qed

lemma ce_rel_lm_6: "r  ce_rels  ce_rel_to_set r  ce_sets"
proof -
  assume A: "r  ce_rels"
  then show ?thesis by (unfold ce_rels_def, auto)
qed

lemma ce_rel_lm_7: "ce_rel_to_set r  ce_sets  r  ce_rels"
proof -
  assume "ce_rel_to_set r  ce_sets"
  then show ?thesis by (unfold ce_rels_def, auto)
qed

lemma ce_rel_lm_8: "(r  ce_rels) = (ce_rel_to_set r  ce_sets)" by (unfold ce_rels_def, auto)

lemma ce_rel_lm_9: "(x,y)  r  c_pair x y  ce_rel_to_set r" by (unfold ce_rel_to_set_def, auto)

lemma ce_rel_lm_10: "x  A  (c_fst x, c_snd x)  ce_set_to_rel A" by (unfold ce_set_to_rel_def, auto)

lemma ce_rel_lm_11: "c_pair x y  ce_rel_to_set r  (x,y)  r"
proof -
  assume A: "c_pair x y  ce_rel_to_set r"
  let ?z = "c_pair x y"
  from A have "(c_fst ?z, c_snd ?z)  ce_set_to_rel (ce_rel_to_set r)" by (rule ce_rel_lm_10)
  then show "(x,y)  r" by simp
qed

lemma ce_rel_lm_12: "(c_pair x y  ce_rel_to_set r) = ((x,y)  r)"
proof
  assume "c_pair x y  ce_rel_to_set r" then show "(x, y)  r" by (rule ce_rel_lm_11)
next
  assume "(x, y)  r" then show "c_pair x y  ce_rel_to_set r" by (rule ce_rel_lm_9)
qed

lemma ce_rel_lm_13: "(x,y)  ce_set_to_rel A  c_pair x y  A"
proof -
  assume "(x,y)  ce_set_to_rel A"
  then have "c_pair x y  ce_rel_to_set (ce_set_to_rel A)" by (rule ce_rel_lm_9)
  then show ?thesis by simp
qed

lemma ce_rel_lm_14: "c_pair x y  A  (x,y)  ce_set_to_rel A"
proof -
  assume "c_pair x y  A"
  then have "c_pair x y  ce_rel_to_set (ce_set_to_rel A)" by simp
  then show ?thesis by (rule ce_rel_lm_11)
qed

lemma ce_rel_lm_15: "((x,y)  ce_set_to_rel A) = (c_pair x y  A)"
proof
  assume "(x, y)  ce_set_to_rel A" then show "c_pair x y  A" by (rule ce_rel_lm_13)
next
  assume "c_pair x y  A" then show "(x, y)  ce_set_to_rel A" by (rule ce_rel_lm_14)
qed

lemma ce_rel_lm_16: "x  ce_rel_to_set r  (c_fst x, c_snd x)  r"
proof -
  assume "x  ce_rel_to_set r"
  then have "(c_fst x, c_snd x)  ce_set_to_rel (ce_rel_to_set r)" by (rule ce_rel_lm_10)
  then show ?thesis by simp
qed

lemma ce_rel_lm_17: "(c_fst x, c_snd x)  ce_set_to_rel A  x  A"
proof -
  assume "(c_fst x, c_snd x)  ce_set_to_rel A"
  then have "c_pair (c_fst x) (c_snd x)  A" by (rule ce_rel_lm_13)
  then show ?thesis by simp
qed

lemma ce_rel_lm_18: "((c_fst x, c_snd x)  ce_set_to_rel A) = (x  A)"
proof
  assume "(c_fst x, c_snd x)  ce_set_to_rel A" then show "x  A" by (rule ce_rel_lm_17)
next
  assume "x  A" then show "(c_fst x, c_snd x)  ce_set_to_rel A" by (rule ce_rel_lm_10)
qed

lemma ce_rel_lm_19: "(c_fst x, c_snd x)  r  x  ce_rel_to_set r"
proof -
  assume "(c_fst x, c_snd x)  r"
  then have "(c_fst x, c_snd x)  ce_set_to_rel (ce_rel_to_set r)" by simp
  then show ?thesis by (rule ce_rel_lm_17)
qed

lemma ce_rel_lm_20: "((c_fst x, c_snd x)  r) = (x  ce_rel_to_set r)"
proof
  assume "(c_fst x, c_snd x)  r" then show "x  ce_rel_to_set r" by (rule ce_rel_lm_19)
next
  assume "x  ce_rel_to_set r" then show "(c_fst x, c_snd x)  r" by (rule ce_rel_lm_16)
qed

lemma ce_rel_lm_21: "r  ce_rels   p  PrimRec3.  x y. ((x,y)  r) = ( u. p x y u = 0)"
proof -
  assume r_ce: "r  ce_rels"
  define A where "A = ce_rel_to_set r"
  from r_ce have A_ce: "A  ce_sets" by (unfold A_def, rule ce_rel_lm_6)
  then have " p  PrimRec2. A = fn_to_set p" by (rule ce_set_lm_3)
  then obtain q where q_is_pr: "q  PrimRec2" and A_def1: "A = fn_to_set q" ..
  from A_def1 have A_def2: "A = { x.  y. q x y = 0}" by (unfold fn_to_set_def)
  define p where "p x y u = q (c_pair x y) u" for x y u
  from q_is_pr have p_is_pr: "p  PrimRec3" unfolding p_def by prec
  have " x y. ((x,y)  r) = ( u. p x y u = 0)"
  proof - fix x y show "((x,y)  r) = ( u. p x y u = 0)"
    proof
      assume A: "(x,y)  r"
      define z where "z = c_pair x y"
      with A_def A have z_in_A: "z  A" by (unfold ce_rel_to_set_def, auto)
      with A_def2 have "z  { x.  y. q x y = 0}" by auto
      then obtain u where "q z u = 0" by auto
      with z_def have "p x y u = 0" by (simp add: z_def p_def)
      then show " u. p x y u = 0" by auto
    next
      assume A: " u. p x y u = 0"
      define z where "z = c_pair x y"
      from A obtain u where "p x y u = 0" by auto
      then have q_z: "q z u = 0" by (simp add: z_def p_def)
      with A_def2 have z_in_A: "z  A" by auto
      then have "c_pair x y  A" by (unfold z_def)
      then have "c_pair x y  ce_rel_to_set r" by (unfold A_def)
      then show "(x,y)  r" by (rule ce_rel_lm_11)
    qed
  qed
  with p_is_pr show ?thesis by auto
qed

lemma ce_rel_lm_22: "r  ce_rels   p  PrimRec3. r = { (x,y).  u. p x y u = 0 }"
proof -
  assume r_ce: "r  ce_rels"
  then have " p  PrimRec3.  x y. ((x,y)  r) = ( u. p x y u = 0)" by (rule ce_rel_lm_21)
  then obtain p where p_is_pr: "p  PrimRec3" and L1: " x y. ((x,y)  r) = ( u. p x y u = 0)" by auto
  from p_is_pr L1 show ?thesis by blast
qed

lemma ce_rel_lm_23: " p  PrimRec3;  x y. ((x,y)  r) = ( u. p x y u = 0)   r  ce_rels"
proof -
  assume p_is_pr: "p  PrimRec3"
  assume A: " x y. ((x,y)  r) = ( u. p x y u = 0)"
  define q where "q z u = p (c_fst z) (c_snd z) u" for z u
  from p_is_pr have q_is_pr: "q  PrimRec2" unfolding q_def by prec
  define A where "A = { x.  y. q x y = 0}"
  then have A_def1: "A = fn_to_set q" by (unfold fn_to_set_def, auto)
  from q_is_pr A_def1 have A_ce: "A  ce_sets" by (simp add: ce_set_lm_1)
  have main: "A = ce_rel_to_set r"
  proof
    show "A  ce_rel_to_set r"
    proof
      fix z assume z_in_A: "z  A"
      show "z  ce_rel_to_set r"
      proof -
        define x where "x = c_fst z"
        define y where "y = c_snd z"
        from z_in_A A_def obtain u where L2: "q z u = 0" by auto
        with x_def y_def q_def have L3: "p x y u = 0" by simp
        then have "u. p x y u = 0" by auto
        with A have "(x,y)  r" by auto
        then have "c_pair x y  ce_rel_to_set r" by (rule ce_rel_lm_9)
        with x_def y_def show ?thesis by simp
      qed
    qed
  next
    show "ce_rel_to_set r  A"
    proof
      fix z assume z_in_r: "z  ce_rel_to_set r"
      show "z  A"
      proof -
        define x where "x = c_fst z"
        define y where "y = c_snd z"
        from z_in_r have "(c_fst z, c_snd z)  r" by (rule ce_rel_lm_16)
        with x_def y_def have "(x,y)  r" by simp
        with A obtain u where L1: "p x y u = 0" by auto
        with x_def y_def q_def have "q z u = 0" by simp
        with A_def show "z  A" by auto
      qed
    qed
  qed
  with A_ce have "ce_rel_to_set r  ce_sets" by auto
  then show "r  ce_rels" by (rule ce_rel_lm_7)
qed

lemma ce_rel_lm_24: " r  ce_rels; s  ce_rels   s O r  ce_rels"
proof -
  assume r_ce: "r  ce_rels"
  assume s_ce: "s  ce_rels"
  from r_ce have " p  PrimRec3.  x y. ((x,y)  r)=( u. p x y u = 0)" by (rule ce_rel_lm_21)
  then obtain p_r where p_r_is_pr: "p_r  PrimRec3" and R1: " x y. ((x,y)  r)=( u. p_r x y u = 0)"
    by auto
  from s_ce have " p  PrimRec3.  x y. ((x,y)  s)=( u. p x y u = 0)" by (rule ce_rel_lm_21)
  then obtain p_s where p_s_is_pr: "p_s  PrimRec3" and S1: " x y. ((x,y)  s)=( u. p_s x y u = 0)"
    by auto
  define p where "p x z u = (p_s x (c_fst u) (c_fst (c_snd u))) + (p_r (c_fst u) z (c_snd (c_snd u)))"
    for x z u
  from p_r_is_pr p_s_is_pr have p_is_pr: "p  PrimRec3" unfolding p_def by prec
  define sr where "sr = s O r"
  have main: " x z. ((x,z)  sr) = ( u. p x z u = 0)"
  proof (rule allI, rule allI)
    fix x z
    show "((x, z)  sr) = (u. p x z u = 0)"
    proof
      assume A: "(x, z)  sr"
      show "u. p x z u = 0"
      proof -
        from A sr_def obtain y where L1: "(x,y)  s" and L2: "(y,z)  r" by auto
        from L1 S1 obtain u_s where L3: "p_s x y u_s = 0" by auto
        from L2 R1 obtain u_r where L4: "p_r y z u_r = 0" by auto
        define u where "u = c_pair y (c_pair u_s u_r)"
        from L3 L4 have "p x z u = 0" by (unfold p_def, unfold u_def, simp)
        then show ?thesis by auto
      qed
    next
      assume A: "u. p x z u = 0"
      show "(x, z)  sr"
      proof -
        from A obtain u where L1: "p x z u = 0" by auto
        then have L2: "(p_s x (c_fst u) (c_fst (c_snd u))) + (p_r (c_fst u) z (c_snd (c_snd u))) = 0" by (unfold p_def)
        from L2 have L3: "p_s x (c_fst u) (c_fst (c_snd u)) = 0" by auto
        from L2 have L4: "p_r (c_fst u) z (c_snd (c_snd u)) = 0" by auto
        from L3 S1 have L5: "(x,(c_fst u))  s" by auto
        from L4 R1 have L6: "((c_fst u),z)  r" by auto
        from L5 L6 have "(x,z)  s O r" by auto
        with sr_def show ?thesis by auto
      qed
    qed
  qed
  from p_is_pr main have "sr  ce_rels" by (rule ce_rel_lm_23)
  then show ?thesis by (unfold sr_def)
qed

lemma ce_rel_lm_25: "r  ce_rels  r^-1  ce_rels"
proof -
  assume r_ce: "r  ce_rels"
  have "r^-1 = {(y,x). (x,y)  r}" by auto
  then have L1: " x y. ((x,y)  r) = ((y,x)  r^-1)" by auto
  from r_ce have " p  PrimRec3.  x y. ((x,y)  r) = ( u. p x y u = 0)" by (rule ce_rel_lm_21)
  then obtain p where p_is_pr: "p  PrimRec3" and R1: " x y. ((x,y)  r) = ( u. p x y u = 0)" by auto
  define q where "q x y u = p y x u" for x y u
  from p_is_pr have q_is_pr: "q  PrimRec3" unfolding q_def by prec
  from L1 R1 have L2: " x y. ((x,y)  r^-1) = ( u. p y x u = 0)" by auto
  with q_def have L3: " x y. ((x,y)  r^-1) = ( u. q x y u = 0)" by auto
  with q_is_pr show ?thesis by (rule ce_rel_lm_23)
qed

lemma ce_rel_lm_26: "r  ce_rels  Domain r  ce_sets"
proof -
  assume r_ce: "r  ce_rels"
  have L1: " x. (x  Domain r) = ( y. (x,y)  r)" by auto
  define A where "A = ce_rel_to_set r"
  from r_ce have "ce_rel_to_set r  ce_sets" by (rule ce_rel_lm_6)
  then have A_ce: "A  ce_sets" by (unfold A_def)
  have " x y. ((x,y)  r) = (c_pair x y  ce_rel_to_set r)" by (simp add: ce_rel_lm_12)
  then have L2: " x y. ((x,y)  r) = (c_pair x y  A)" by (unfold A_def)
  from A_ce c_fst_is_pr have L3: "{ c_fst z |z.  z  A }  ce_sets" by (rule ce_set_lm_7)
  have L4: " x. (x  { c_fst z |z.  z  A }) =( y. c_pair x y  A)"
  proof fix x show "(x  { c_fst z |z.  z  A }) =( y. c_pair x y  A)"
    proof
      assume A: "x  {c_fst z |z. z  A}"
      then obtain z where z_in_A: "z  A" and x_z: "x = c_fst z" by auto
      from x_z have "z = c_pair x (c_snd z)" by simp
      with z_in_A have "c_pair x (c_snd z)  A" by auto
      then show "y. c_pair x y  A" by auto
    next
      assume A: "y. c_pair x y  A"
      then obtain y where y_1: "c_pair x y  A" by auto
      define z where "z = c_pair x y"
      from y_1 have z_in_A: "z  A" by (unfold z_def)
      from z_def have x_z: "x = c_fst z" by (unfold z_def, simp)
      from z_in_A x_z show "x  {c_fst z |z. z  A}" by auto
    qed
  qed
  from L1 L2 have L5: " x. (x  Domain r) = ( y. c_pair x y  A)" by auto
  from L4 L5 have L6: " x. (x  Domain r) = (x  { c_fst z |z.  z  A })" by auto
  then have "Domain r = { c_fst z |z.  z  A }" by auto  
  with L3 show "Domain r  ce_sets" by auto
qed

lemma ce_rel_lm_27: "r  ce_rels  Range r  ce_sets"
proof -
  assume r_ce: "r  ce_rels"
  then have "r^-1  ce_rels" by (rule ce_rel_lm_25)
  then have "Domain (r^-1)  ce_sets" by (rule ce_rel_lm_26)
  then show ?thesis by (unfold Domain_converse [symmetric])
qed

lemma ce_rel_lm_28: "r  ce_rels  Field r  ce_sets"
proof -
  assume r_ce: "r  ce_rels"
  from r_ce have L1: "Domain r  ce_sets" by (rule ce_rel_lm_26)
  from r_ce have L2: "Range r  ce_sets" by (rule ce_rel_lm_27)
  from L1 L2 have L3: "Domain r  Range r  ce_sets" by (rule ce_union)
  then show ?thesis by (unfold Field_def)
qed

lemma ce_rel_lm_29: " A  ce_sets; B  ce_sets   A × B  ce_rels"
proof -
  assume A_ce: "A  ce_sets"
  assume B_ce: "B  ce_sets"
  define r_a where "r_a = {(x,(0::nat)) | x. x  A}"
  define r_b where "r_b = {((0::nat),z) | z. z  B}"
  have L1: "r_a O r_b = A × B" by (unfold r_a_def, unfold r_b_def, auto)
  have r_a_ce: "r_a  ce_rels"
  proof -
    have loc1: "ce_rel_to_set r_a = { c_pair x 0 | x. x  A}" by (unfold r_a_def, unfold ce_rel_to_set_def, auto)
    define p where "p x = c_pair x 0" for x
    have p_is_pr: "p  PrimRec1" unfolding p_def by prec
    from A_ce p_is_pr have "{ c_pair x 0 | x. x  A}  ce_sets"
      unfolding p_def by (simp add: ce_set_lm_7)
    with loc1 have "ce_rel_to_set r_a  ce_sets" by auto
    then show ?thesis by (rule ce_rel_lm_7)
  qed
  have r_b_ce: "r_b  ce_rels"
  proof -
    have loc1: "ce_rel_to_set r_b = { c_pair 0 z | z. z  B}"
      by (unfold r_b_def, unfold ce_rel_to_set_def, auto)
    define p where "p z = c_pair 0 z" for z
    have p_is_pr: "p  PrimRec1" unfolding p_def by prec
    from B_ce p_is_pr have "{ c_pair 0 z | z. z  B}  ce_sets"
      unfolding p_def by (simp add: ce_set_lm_7)
    with loc1 have "ce_rel_to_set r_b  ce_sets" by auto
    then show ?thesis by (rule ce_rel_lm_7)
  qed
  from r_b_ce r_a_ce have "r_a O r_b  ce_rels" by (rule ce_rel_lm_24)
  with L1 show ?thesis by auto
qed

lemma ce_rel_lm_30: "{}  ce_rels"
proof -
  have "ce_rel_to_set {} = {}" by (unfold ce_rel_to_set_def, auto)
  with ce_empty have "ce_rel_to_set {}  ce_sets" by auto
  then show ?thesis by (rule ce_rel_lm_7)
qed

lemma ce_rel_lm_31: "UNIV  ce_rels"
proof -
  from ce_univ ce_univ have "UNIV × UNIV  ce_rels" by (rule ce_rel_lm_29)
  then show ?thesis by auto
qed

lemma ce_rel_lm_32: "ce_rel_to_set (r  s) = (ce_rel_to_set r)  (ce_rel_to_set s)" by (unfold ce_rel_to_set_def, auto)

lemma ce_rel_lm_33: " r  ce_rels; s  ce_rels   r  s  ce_rels"
proof -
  assume "r  ce_rels"
  then have r_ce: "ce_rel_to_set r  ce_sets" by (rule ce_rel_lm_6)
  assume "s  ce_rels"
  then have s_ce: "ce_rel_to_set s  ce_sets" by (rule ce_rel_lm_6)  
  have "ce_rel_to_set (r  s) = (ce_rel_to_set r)  (ce_rel_to_set s)" by (unfold ce_rel_to_set_def, auto)
  moreover from r_ce s_ce have "(ce_rel_to_set r)  (ce_rel_to_set s)  ce_sets" by (rule ce_union)
  ultimately have "ce_rel_to_set (r  s)  ce_sets" by auto
  then show ?thesis by (rule ce_rel_lm_7)
qed

lemma ce_rel_lm_34: "ce_rel_to_set (r  s) = (ce_rel_to_set r)  (ce_rel_to_set s)"
proof
  show "ce_rel_to_set (r  s)  ce_rel_to_set r  ce_rel_to_set s" by (unfold ce_rel_to_set_def, auto)
next
  show "ce_rel_to_set r  ce_rel_to_set s  ce_rel_to_set (r  s)"
  proof fix x assume A: "x  ce_rel_to_set r  ce_rel_to_set s"
    from A have L1: "x  ce_rel_to_set r" by auto
    from A have L2: "x  ce_rel_to_set s" by auto
    from L1 obtain u v where L3: "(u,v)  r" and L4: "x = c_pair u v" 
      unfolding ce_rel_to_set_def by auto
    from L2 obtain u1 v1 where L5: "(u1,v1)  s" and L6: "x = c_pair u1 v1" 
      unfolding ce_rel_to_set_def by auto
    from L4 L6 have L7: "c_pair u1 v1 = c_pair u v" by auto
    then have "u1=u" by (rule c_pair_inj1)
    moreover from L7 have "v1=v" by (rule c_pair_inj2)
    ultimately have "(u,v)=(u1,v1)" by auto
    with L3 L5 have "(u,v)  r  s" by auto
    with L4 show "x  ce_rel_to_set (r  s)" by (unfold ce_rel_to_set_def, auto)
  qed
qed

lemma ce_rel_lm_35: " r  ce_rels; s  ce_rels   r  s  ce_rels"
proof -
  assume "r  ce_rels"
  then have r_ce: "ce_rel_to_set r  ce_sets" by (rule ce_rel_lm_6)
  assume "s  ce_rels"
  then have s_ce: "ce_rel_to_set s  ce_sets" by (rule ce_rel_lm_6)  
  have "ce_rel_to_set (r  s) = (ce_rel_to_set r)  (ce_rel_to_set s)" by (rule ce_rel_lm_34)
  moreover from r_ce s_ce have "(ce_rel_to_set r)  (ce_rel_to_set s)  ce_sets" by (rule ce_intersect)
  ultimately have "ce_rel_to_set (r  s)  ce_sets" by auto
  then show ?thesis by (rule ce_rel_lm_7)
qed

lemma ce_rel_lm_36: "ce_set_to_rel (A  B) = (ce_set_to_rel A)  (ce_set_to_rel B)"
  by (unfold ce_set_to_rel_def, auto)

lemma ce_rel_lm_37: "ce_set_to_rel (A  B) = (ce_set_to_rel A)  (ce_set_to_rel B)"
proof -
  define f where "f x = (c_fst x, c_snd x)" for x
  have f_inj: "inj f"
  proof (unfold f_def, rule inj_on_inverseI [where ?g="λ (u,v). c_pair u v"])
    fix x :: nat
    assume "x  UNIV"
    show "case_prod c_pair (c_fst x, c_snd x) = x" by simp
  qed
  from f_inj have "f ` (A  B) = f ` A  f ` B" by (rule image_Int)
  then show ?thesis by (unfold f_def, unfold ce_set_to_rel_def, auto)
qed

lemma ce_rel_lm_38: " r  ce_rels; A  ce_sets   r``A  ce_sets"
proof -
  assume r_ce: "r  ce_rels"
  assume A_ce: "A  ce_sets"
  have L1: "r``A = Range (r  A × UNIV)" by blast
  have L2: "Range (r  A × UNIV)  ce_sets"
  proof (rule ce_rel_lm_27)
    show "r  A × UNIV  ce_rels"
    proof (rule ce_rel_lm_35)
      show "r  ce_rels" by (rule r_ce)
    next
      show "A × UNIV  ce_rels"
      proof (rule ce_rel_lm_29)
        show "A  ce_sets" by (rule A_ce)
      next
        show "UNIV  ce_sets" by (rule ce_univ)
      qed
    qed
  qed
  from L1 L2 show ?thesis by auto
qed


subsection ‹Total computable functions›

definition
  graph :: "(nat  nat)  (nat × nat) set" where
  "graph = (λ f. { (x, f x) | x. x  UNIV})"

lemma graph_lm_1: "(x,y)  graph f  y = f x" by (unfold graph_def, auto)

lemma graph_lm_2: "y = f x  (x,y)  graph f" by (unfold graph_def, auto)

lemma graph_lm_3: "((x,y)  graph f) = (y = f x)" by (unfold graph_def, auto)

lemma graph_lm_4: "graph (f o g) = (graph g) O (graph f)" by (unfold graph_def, auto)

definition
  c_graph :: "(nat  nat)  nat set" where
  "c_graph = (λ f. { c_pair x (f x) | x. x  UNIV})"

lemma c_graph_lm_1: "c_pair x y  c_graph f  y = f x"
proof -
  assume A: "c_pair x y  c_graph f"
  have S1: "c_graph f = {c_pair x (f x) | x. x  UNIV}" by (simp add: c_graph_def)
  from A S1 obtain z where S2: "c_pair x y = c_pair z (f z)" by auto
  then have "x = z" by (rule c_pair_inj1)
  moreover from S2 have "y = f z" by (rule c_pair_inj2)
  ultimately show ?thesis by auto
qed

lemma c_graph_lm_2: "y = f x  c_pair x y  c_graph f" by (unfold c_graph_def, auto)

lemma c_graph_lm_3: "(c_pair x y  c_graph f) = (y = f x)"
proof
  assume "c_pair x y  c_graph f" then show "y = f x" by (rule c_graph_lm_1)
next
  assume "y = f x" then show "c_pair x y  c_graph f" by (rule c_graph_lm_2)
qed

lemma c_graph_lm_4: "c_graph f = ce_rel_to_set (graph f)" by (unfold c_graph_def ce_rel_to_set_def graph_def, auto)

lemma c_graph_lm_5: "graph f = ce_set_to_rel (c_graph f)" by (simp add: c_graph_lm_4)

definition
  total_recursive :: "(nat  nat)  bool" where
  "total_recursive = (λ f. graph f  ce_rels)"

lemma total_recursive_def1: "total_recursive = (λ f. c_graph f  ce_sets)"
proof (rule ext) fix f show " total_recursive f = (c_graph f  ce_sets)"
  proof
    assume A: "total_recursive f"
    then have "graph f  ce_rels" by (unfold total_recursive_def)
    then have "ce_rel_to_set (graph f)  ce_sets" by (rule ce_rel_lm_6)
    then show "c_graph f  ce_sets" by (simp add: c_graph_lm_4)
  next
    assume "c_graph f  ce_sets"
    then have "ce_rel_to_set (graph f)  ce_sets" by (simp add: c_graph_lm_4)
    then have "graph f  ce_rels" by (rule ce_rel_lm_7)
    then show "total_recursive f" by (unfold total_recursive_def)
  qed
qed

theorem pr_is_total_rec: "f  PrimRec1  total_recursive f"
proof -
  assume A: "f  PrimRec1"
  define p where "p x = c_pair x (f x)" for x
  from A have p_is_pr: "p  PrimRec1" unfolding p_def by prec
  let ?U = "{ p x | x. x  UNIV }"
  from ce_univ p_is_pr have U_ce: "?U  ce_sets" by (rule ce_set_lm_7)
  have U_1: "?U = { c_pair x (f x) | x. x  UNIV}" by (simp add: p_def)
  with U_ce have S1: "{ c_pair x (f x) | x. x  UNIV}  ce_sets" by simp
  with c_graph_def have c_graph_f_is_ce: "c_graph f  ce_sets" by (unfold c_graph_def, auto)
  then show ?thesis by (unfold total_recursive_def1, auto)
qed

theorem comp_tot_rec: " total_recursive f; total_recursive g   total_recursive (f o g)"
proof -
  assume "total_recursive f"
  then have f_ce: "graph f  ce_rels" by (unfold total_recursive_def)
  assume "total_recursive g"
  then have g_ce: "graph g  ce_rels" by (unfold total_recursive_def)
  from f_ce g_ce have "graph g O graph f  ce_rels" by (rule ce_rel_lm_24)
  then have "graph (f o g)  ce_rels" by (simp add: graph_lm_4)
  then show ?thesis by (unfold total_recursive_def)
qed

lemma univ_for_pr_tot_rec_lm: "c_graph univ_for_pr  ce_sets"
proof -
  define A where "A = c_graph univ_for_pr"
  from A_def have S1: "A = { c_pair x (univ_for_pr x) | x. x  UNIV }"
    by (simp add: c_graph_def)
  from S1 have S2: "A = { z .  x. z = c_pair x (univ_for_pr x) }" by auto
  have S3: " z. ( x. (z = c_pair x (univ_for_pr x))) = (univ_for_pr (c_fst z) = c_snd z)"
  proof -
    fix z show "( x. (z = c_pair x (univ_for_pr x))) = (univ_for_pr (c_fst z) = c_snd z)"
    proof
      assume A: "x. z = c_pair x (univ_for_pr x)"
      then obtain x where S3_1: "z = c_pair x (univ_for_pr x)" ..
      then show "univ_for_pr (c_fst z) = c_snd z" by simp
    next
      assume A: "univ_for_pr (c_fst z) = c_snd z"
      from A have "z = c_pair (c_fst z) (univ_for_pr (c_fst z))" by simp
      thus "x. z = c_pair x (univ_for_pr x)" ..
    qed
  qed
  with S2 have S4: "A = { z . univ_for_pr (c_fst z) = c_snd z }" by auto
  define p where "p x y =
    (if c_assoc_have_key (pr_gr y) (c_fst x) = 0 then
      (if c_assoc_value (pr_gr y) (c_fst x) = c_snd x then (0::nat) else 1)
    else 1)" for x y
  from c_assoc_have_key_is_pr c_assoc_value_is_pr pr_gr_is_pr have p_is_pr: "p  PrimRec2"
    unfolding p_def by prec
  have S5: " z. (univ_for_pr (c_fst z) = c_snd z) = ( y. p z y = 0)"
  proof -
    fix z show "(univ_for_pr (c_fst z) = c_snd z) = ( y. p z y = 0)"
    proof
      assume A: "univ_for_pr (c_fst z) = c_snd z"
      let ?n = "c_fst (c_fst z)"
      let ?x = "c_snd (c_fst z)"
      let ?y = "loc_upb ?n ?x"
      have S5_1: "c_assoc_have_key (pr_gr ?y) (c_pair ?n ?x) = 0" by (rule loc_upb_main)
      have S5_2: "c_assoc_value (pr_gr ?y) (c_pair ?n ?x) = univ_for_pr (c_pair ?n ?x)" by (rule pr_gr_value)
      from S5_1 have S5_3: "c_assoc_have_key (pr_gr ?y) (c_fst z) = 0" by simp
      from S5_2 A have S5_4: "c_assoc_value (pr_gr ?y) (c_fst z) = c_snd z" by simp
      from S5_3 S5_4 have "p z ?y = 0" by (simp add: p_def)
      thus " y. p z y = 0" ..
    next
      assume A: "y. p z y = 0"
      then obtain y where S5_1: "p z y = 0" ..
      have S5_2: "c_assoc_have_key (pr_gr y) (c_fst z) = 0"
      proof (rule ccontr)
        assume A_1: "c_assoc_have_key (pr_gr y) (c_fst z)  0"
        then have "p z y = 1" by (simp add: p_def)
        with S5_1 show False by auto
      qed
      then have S5_3: "p z y = (if c_assoc_value (pr_gr y) (c_fst z) = c_snd z then (0::nat) else 1)" by (simp add: p_def)
      have S5_4: "c_assoc_value (pr_gr y) (c_fst z) = c_snd z"
      proof (rule ccontr)
        assume A_2: "c_assoc_value (pr_gr y) (c_fst z)  c_snd z"
        then have "p z y = 1" by (simp add: p_def)
        with S5_1 show False by auto
      qed
      have S5_5: "c_is_sub_fun (pr_gr y) univ_for_pr" by (rule pr_gr_1)
      from S5_5 S5_2 have S5_6: "c_assoc_value (pr_gr y) (c_fst z) = univ_for_pr (c_fst z)" by (rule c_is_sub_fun_lm_1)
      with S5_4 show "univ_for_pr (c_fst z) = c_snd z" by auto
    qed
  qed
  from S5 S4 have "A = {z.  y. p z y = 0}" by auto
  then have "A = fn_to_set p" by (simp add: fn_to_set_def)
  moreover from p_is_pr have "fn_to_set p  ce_sets" by (rule ce_set_lm_1)
  ultimately have "A  ce_sets" by auto
  with A_def show ?thesis by auto
qed

theorem univ_for_pr_tot_rec: "total_recursive univ_for_pr"
proof -
  have "c_graph univ_for_pr  ce_sets" by (rule univ_for_pr_tot_rec_lm)
  then show ?thesis by (unfold total_recursive_def1, auto)
qed

subsection ‹Computable sets, Post's theorem›

definition
  computable :: "nat set  bool" where
  "computable = (λ A. A  ce_sets  -A  ce_sets)"

lemma computable_complement_1: "computable A  computable (- A)"
proof -
  assume "computable A"
  then show ?thesis by (unfold computable_def, auto)
qed

lemma computable_complement_2: "computable (- A)  computable A"
proof -
  assume "computable (- A)"
  then show ?thesis by (unfold computable_def, auto)
qed

lemma computable_complement_3: "(computable A) = (computable (- A))" by (unfold computable_def, auto)

theorem comp_impl_tot_rec: "computable A  total_recursive (chf A)"
proof -
  assume A: "computable A"
  from A have A1: "A  ce_sets" by (unfold computable_def, simp)
  from A have A2: "-A  ce_sets" by (unfold computable_def, simp)
  define p where "p x = c_pair x 0" for x
  define q where "q x = c_pair x 1" for x
  from p_def have p_is_pr: "p  PrimRec1" unfolding p_def by prec
  from q_def have q_is_pr: "q  PrimRec1" unfolding q_def by prec
  define U0 where "U0 = {p x | x. x  A}"
  define U1 where "U1 = {q x | x. x  - A}"
  from A1 p_is_pr have U0_ce: "U0  ce_sets" by(unfold U0_def, rule ce_set_lm_7)
  from A2 q_is_pr have U1_ce: "U1  ce_sets" by(unfold U1_def, rule ce_set_lm_7)
  define U where "U = U0  U1"
  from U0_ce U1_ce have U_ce: "U  ce_sets" by (unfold U_def, rule ce_union)
  define V where "V = c_graph (chf A)"
  have V_1: "V = { c_pair x (chf A x) | x. x  UNIV}" by (simp add: V_def c_graph_def)
  from U0_def p_def have U0_1: "U0 = { c_pair x y | x y. x  A  y=0}" by auto
  from U1_def q_def have U1_1: "U1 = { c_pair x y | x y. x  A  y=1}" by auto
  from U0_1 U1_1 U_def have U_1: "U = { c_pair x y | x y. (x  A  y=0)  (x  A  y=1)}" by auto
  from V_1 have V_2: "V = { c_pair x y | x y. y = chf A x}" by auto
  have L1: " x y. ((x  A  y=0)  (x  A  y=1)) = (y = chf A x)"
  proof -
    fix x y
    show "((x  A  y=0)  (x  A  y=1)) = (y = chf A x)" by(unfold chf_def, auto)
  qed
  from V_2 U_1 L1 have "U=V" by simp
  with U_ce have V_ce: "V  ce_sets" by auto
  with V_def have "c_graph (chf A)  ce_sets" by auto
  then show ?thesis by (unfold total_recursive_def1)
qed

theorem tot_rec_impl_comp: "total_recursive (chf A)  computable A"
proof -
  assume A: "total_recursive (chf A)"
  then have A1: "c_graph (chf A)  ce_sets" by (unfold total_recursive_def1)
  let ?U = "c_graph (chf A)"
  have L1: "?U = { c_pair x (chf A x) | x. x  UNIV}" by (simp add: c_graph_def)
  have L2: " x y. ((x  A  y=0)  (x  A  y=1)) = (y = chf A x)"
  proof - fix x y show "((x  A  y=0)  (x  A  y=1)) = (y = chf A x)" by(unfold chf_def, auto)
  qed
  from L1 L2 have L3: "?U = { c_pair x y | x y. (x  A  y=0)  (x  A  y=1)}" by auto
  define p where "p x = c_pair x 0" for x
  define q where "q x = c_pair x 1" for x
  have p_is_pr: "p  PrimRec1" unfolding p_def by prec
  have q_is_pr: "q  PrimRec1" unfolding q_def by prec
  define V where "V = { c_pair x y | x y. (x  A  y=0)  (x  A  y=1)}"
  from V_def L3 A1 have V_ce: "V  ce_sets" by auto
  from V_def have L4: " z. (z  V) = ( x y. z = c_pair x y   ((x  A  y=0)  (x  A  y=1)))" by blast
  have L5: " x. (p x  V) = (x  A)"
  proof - fix x show "(p x  V) = (x  A)"
    proof
      assume A: "p x  V"
      then have "c_pair x 0  V" by (unfold p_def)
      with V_def obtain x1 y1 where L5_2: "c_pair x 0 = c_pair x1 y1"
        and L5_3: "((x1  A  y1=0)  (x1  A  y1=1))" by auto
      from L5_2 have X_eq_X1: "x=x1" by (rule c_pair_inj1)
      from L5_2 have Y1_eq_0: "0=y1" by (rule c_pair_inj2)
      from L5_3 X_eq_X1 Y1_eq_0 show "x  A" by auto
    next
      assume A: "x  A"
      let ?z = "c_pair x 0"
      from A have L5_1: " x1 y1. c_pair x 0 = c_pair x1 y1   ((x1  A  y1=0)  (x1  A  y1=1))" by auto
      with V_def have "c_pair x 0  V" by auto
      with p_def show "p x  V" by simp
    qed
  qed
  then have A_eq: "A = { x. p x  V}" by auto
  from V_ce p_is_pr have "{ x. p x  V}  ce_sets" by (rule ce_set_lm_5)
  with A_eq have A_ce: "A  ce_sets" by simp
  have CA_eq: "- A = {x. q x  V}"
  proof -
    have " x. (q x  V) = (x  A)"
    proof - fix x show "(q x  V) = (x  A)"
      proof
        assume A: "q x  V"
        then have "c_pair x 1  V" by (unfold q_def)
        with V_def obtain x1 y1 where L5_2: "c_pair x 1 = c_pair x1 y1"
          and L5_3: "((x1  A  y1=0)  (x1  A  y1=1))" by auto
        from L5_2 have X_eq_X1: "x=x1" by (rule c_pair_inj1)
        from L5_2 have Y1_eq_1: "1=y1" by (rule c_pair_inj2)
        from L5_3 X_eq_X1 Y1_eq_1 show "x  A" by auto
      next
        assume A: "x  A"
        from A have L5_1: " x1 y1. c_pair x 1 = c_pair x1 y1   ((x1  A  y1=0)  (x1  A  y1=1))" by auto
        with V_def have "c_pair x 1  V" by auto
        with q_def show "q x  V" by simp
      qed
    qed
    then show ?thesis by auto
  qed
  from V_ce q_is_pr have "{ x. q x  V}  ce_sets" by (rule ce_set_lm_5)
  with CA_eq have CA_ce: "- A  ce_sets" by simp
  from A_ce CA_ce show ?thesis by (simp add: computable_def)
qed

theorem post_th_0: "(computable A) = (total_recursive (chf A))"
proof
  assume "computable A" then show "total_recursive (chf A)" by (rule comp_impl_tot_rec)
next
  assume "total_recursive (chf A)" then show "computable A" by (rule tot_rec_impl_comp)
qed

subsection ‹Universal computably enumerable set›

definition
  univ_ce :: "nat set" where
  "univ_ce = { c_pair n x | n x. x  nat_to_ce_set n }"

lemma univ_for_pr_lm: "univ_for_pr (c_pair n x) = (nat_to_pr n) x"
  by (simp add: univ_for_pr_def pr_conv_2_to_1_def)

theorem univ_is_ce: "univ_ce  ce_sets"
proof -
  define A where "A = c_graph univ_for_pr"
  then have "A  ce_sets" by (simp add: univ_for_pr_tot_rec_lm)
  then have " pA  PrimRec2. A = fn_to_set pA" by (rule ce_set_lm_3)
  then obtain pA where pA_is_pr: "pA  PrimRec2" and S1: "A = fn_to_set pA" by auto
  from S1 have S2: "A = { x.  y. pA x y = 0 }" by (simp add: fn_to_set_def)
  define p where "p z y = pA (c_pair (c_pair (c_fst z) (c_pair (c_snd z) (c_fst y))) 0) (c_snd y)"
    for z y
  from pA_is_pr have p_is_pr: "p  PrimRec2" unfolding p_def by prec
  have " z. ( n x. z = c_pair n x  x  nat_to_ce_set n) = (c_snd z  nat_to_ce_set (c_fst z))"
  proof -
    fix z show "( n x. z = c_pair n x  x  nat_to_ce_set n) = (c_snd z  nat_to_ce_set (c_fst z))"
    proof
      assume A: "n x. z = c_pair n x  x  nat_to_ce_set n"
      then obtain n x where L1: "z = c_pair n x  x  nat_to_ce_set n" by auto
      from L1 have L2: "z = c_pair n x" by auto
      from L1 have L3: "x  nat_to_ce_set n" by auto
      from L1 have L4: "c_fst z = n" by simp
      from L1 have L5: "c_snd z = x" by simp
      from L3 L4 L5 show "c_snd z  nat_to_ce_set (c_fst z)" by auto
    next
      assume A: "c_snd z  nat_to_ce_set (c_fst z)"
      let ?n = "c_fst z"
      let ?x = "c_snd z"
      have L1: "z = c_pair ?n ?x" by simp
      from L1 A have "z = c_pair ?n ?x  ?x  nat_to_ce_set ?n" by auto
      thus "n x. z = c_pair n x  x  nat_to_ce_set n" by blast
    qed
  qed
  then have "{ c_pair n x | n x. x  nat_to_ce_set n } = { z. c_snd z  nat_to_ce_set (c_fst z)}" by auto
  then have S3: "univ_ce  = { z. c_snd z  nat_to_ce_set (c_fst z)}" by (simp add: univ_ce_def)
  have S4: " z. (c_snd z  nat_to_ce_set (c_fst z)) = ( y. p z y = 0)"
  proof -
    fix z show "(c_snd z  nat_to_ce_set (c_fst z)) = ( y. p z y = 0)"
    proof
      assume A: "c_snd z  nat_to_ce_set (c_fst z)"
      have "nat_to_ce_set (c_fst z) = { x .  y. (nat_to_pr (c_fst z)) (c_pair x y) = 0 }" by (simp add: nat_to_ce_set_lm_1)
      with A obtain u where S4_1: "(nat_to_pr (c_fst z)) (c_pair (c_snd z) u) = 0"  by auto
      then have S4_2: "univ_for_pr (c_pair (c_fst z) (c_pair (c_snd z) u)) = 0" by (simp add: univ_for_pr_lm)
      from A_def have S4_3: "A = { c_pair x (univ_for_pr x) | x. x  UNIV }" by (simp add: c_graph_def)
      then have S4_4: " x. c_pair x (univ_for_pr x)  A" by auto
      then have "c_pair (c_pair (c_fst z) (c_pair (c_snd z) u)) (univ_for_pr (c_pair (c_fst z) (c_pair (c_snd z) u)))  A" by auto
      with S4_2 have S4_5: "c_pair (c_pair (c_fst z) (c_pair (c_snd z) u)) 0  A" by auto
      with S2 obtain v where S4_6: "pA (c_pair (c_pair (c_fst z) (c_pair (c_snd z) u)) 0) v = 0" 
        by auto
      define y where "y = c_pair u v"
      from y_def have S4_7: "u = c_fst y" by simp
      from y_def have S4_8: "v = c_snd y" by simp
      from S4_6 S4_7 S4_8 p_def have "p z y = 0" by simp
      thus " y. p z y = 0" ..
    next
      assume A: "y. p z y = 0"
      then obtain y where S4_1: "p z y = 0" ..
      from S4_1 p_def have S4_2: "pA (c_pair (c_pair (c_fst z) (c_pair (c_snd z) (c_fst y))) 0) (c_snd y) = 0" by simp
      with S2 have S4_3: "c_pair (c_pair (c_fst z) (c_pair (c_snd z) (c_fst y))) 0  A" by auto
      with A_def have "c_pair (c_pair (c_fst z) (c_pair (c_snd z) (c_fst y))) 0  c_graph univ_for_pr" by simp
      then have S4_4: "0 = univ_for_pr (c_pair (c_fst z) (c_pair (c_snd z) (c_fst y)))" by (rule c_graph_lm_1)
      then have S4_5: "univ_for_pr (c_pair (c_fst z) (c_pair (c_snd z) (c_fst y))) = 0" by auto
      then have S4_6: "(nat_to_pr (c_fst z)) (c_pair (c_snd z) (c_fst y)) = 0" by (simp add: univ_for_pr_lm)
      then have S4_7: " y. (nat_to_pr (c_fst z)) (c_pair (c_snd z) y) = 0" ..
      have S4_8: "nat_to_ce_set (c_fst z) = { x .  y. (nat_to_pr (c_fst z)) (c_pair x y) = 0 }" by (simp add: nat_to_ce_set_lm_1)
      from S4_7 have S4_9: "c_snd z  { x .  y. (nat_to_pr (c_fst z)) (c_pair x y) = 0 }" by auto
      with S4_8 show "c_snd z  nat_to_ce_set (c_fst z)" by auto
    qed
  qed
  with S3 have "univ_ce = {z.  y. p z y = 0}" by auto
  then have "univ_ce = fn_to_set p" by (simp add: fn_to_set_def)
  moreover from p_is_pr have "fn_to_set p  ce_sets" by (rule ce_set_lm_1)
  ultimately show "univ_ce  ce_sets" by auto
qed

lemma univ_ce_lm_1: "(c_pair n x  univ_ce) = (x  nat_to_ce_set n)"
proof -
  from univ_ce_def have S1: "univ_ce = {z .  n x. z = c_pair n x  x  nat_to_ce_set n}" by auto
  have S2: "( n1 x1. c_pair n x = c_pair n1 x1  x1  nat_to_ce_set n1) = (x  nat_to_ce_set n)"
  proof
    assume "n1 x1. c_pair n x = c_pair n1 x1  x1  nat_to_ce_set n1"
    then obtain n1 x1 where L1: "c_pair n x = c_pair n1 x1" and L2: "x1  nat_to_ce_set n1" by auto
    from L1 have L3: "n = n1" by (rule c_pair_inj1)
    from L1 have L4: "x = x1" by (rule c_pair_inj2)
    from L2 L3 L4 show "x  nat_to_ce_set n" by auto
  next
    assume A: "x  nat_to_ce_set n"
    then have "c_pair n x = c_pair n x  x  nat_to_ce_set n" by auto
    thus " n1 x1. c_pair n x = c_pair n1 x1  x1  nat_to_ce_set n1" by blast
  qed
  with S1 show ?thesis by auto
qed

theorem univ_ce_is_not_comp1: "- univ_ce  ce_sets"
proof (rule ccontr)
  assume "¬ - univ_ce  ce_sets"
  then have A: "- univ_ce  ce_sets" by auto
  define p where "p x = c_pair x x" for x
  have p_is_pr: "p  PrimRec1" unfolding p_def by prec
  define A where "A = { x. p x  - univ_ce }"
  from A p_is_pr have "{ x. p x  - univ_ce }  ce_sets" by (rule ce_set_lm_5)
  with A_def have S1: "A  ce_sets" by auto
  then have " n. A = nat_to_ce_set n" by (rule nat_to_ce_set_srj)
  then obtain n where S2: "A = nat_to_ce_set n" ..
  from A_def have "(n  A) = (p n  - univ_ce)" by auto
  with p_def have "(n  A) = (c_pair n n  univ_ce)" by auto
  with univ_ce_def univ_ce_lm_1 have "(n  A) = (n  nat_to_ce_set n)" by auto
  with S2 have "(n  A) = (n  A)" by auto
  thus False by auto
qed

theorem univ_ce_is_not_comp2: "¬ total_recursive (chf univ_ce)"
proof
  assume "total_recursive (chf univ_ce)"
  then have "computable univ_ce" by (rule tot_rec_impl_comp)
  then have "- univ_ce  ce_sets" by (unfold computable_def, auto)
  with univ_ce_is_not_comp1 show False by auto
qed

theorem univ_ce_is_not_comp3: "¬ computable univ_ce"
proof (rule ccontr)
  assume "¬ ¬ computable univ_ce"
  then have "computable univ_ce" by auto
  then have "total_recursive (chf univ_ce)" by (rule comp_impl_tot_rec)
  with univ_ce_is_not_comp2 show False by auto
qed

subsection ‹s-1-1 theorem, one-one and many-one reducibilities›

definition
  index_of_r_to_l :: nat where
  "index_of_r_to_l =
  pair_by_index
    (pair_by_index index_of_c_fst (comp_by_index index_of_c_fst index_of_c_snd))
    (comp_by_index index_of_c_snd index_of_c_snd)"

lemma index_of_r_to_l_lm: "nat_to_pr index_of_r_to_l (c_pair x (c_pair y z)) = c_pair (c_pair x y) z"
  apply(unfold index_of_r_to_l_def)
  apply(simp add: pair_by_index_main)
  apply(unfold c_f_pair_def)
  apply(simp add: index_of_c_fst_main)
  apply(simp add: comp_by_index_main)
  apply(simp add: index_of_c_fst_main)
  apply(simp add: index_of_c_snd_main)
done

definition
  s_ce :: "nat  nat  nat" where
  "s_ce == (λ e x. s1_1 (comp_by_index e index_of_r_to_l) x)"

lemma s_ce_is_pr: "s_ce  PrimRec2"
  unfolding s_ce_def using comp_by_index_is_pr s1_1_is_pr by prec

lemma s_ce_inj: "s_ce e1 x1 = s_ce e2 x2  e1=e2  x1=x2"
proof -
  let ?n1 = "index_of_r_to_l"
  assume "s_ce e1 x1 = s_ce e2 x2"
  then have "s1_1 (comp_by_index e1 ?n1) x1 = s1_1 (comp_by_index e2 ?n1) x2" by (unfold s_ce_def)
  then have L1: "comp_by_index e1 ?n1 = comp_by_index e2 ?n1  x1=x2" by (rule s1_1_inj)
  from L1 have "comp_by_index e1 ?n1 = comp_by_index e2 ?n1" ..
  then have "e1=e2" by (rule comp_by_index_inj1)
  moreover from L1 have "x1=x2" by auto
  ultimately show ?thesis by auto
qed

lemma s_ce_inj1: "s_ce e1 x = s_ce e2 x  e1=e2"
proof -
  assume "s_ce e1 x = s_ce e2 x"
  then have "e1=e2  x=x" by (rule s_ce_inj)
  then show "e1=e2" by auto
qed

lemma s_ce_inj2: "s_ce e x1 = s_ce e x2  x1=x2"
proof -
  assume "s_ce e x1 = s_ce e x2"
  then have "e=e  x1=x2" by (rule s_ce_inj)
  then show "x1=x2" by auto
qed

theorem s1_1_th1: " n x y. ((nat_to_pr n) (c_pair x y)) = (nat_to_pr (s1_1 n x)) y"
proof (rule allI, rule allI, rule allI)
  fix n x y show "nat_to_pr n (c_pair x y) = nat_to_pr (s1_1 n x) y"
  proof -
    have "(λ y. (nat_to_pr n) (c_pair x y)) = nat_to_pr (s1_1 n x)" by (rule s1_1_th)
    then show ?thesis by (simp add: fun_eq_iff)
  qed
qed

lemma s_lm: "(nat_to_pr (s_ce e x)) (c_pair y z) = (nat_to_pr e) (c_pair (c_pair x y) z)"
proof -
  let ?n1 = "index_of_r_to_l"
  have "(nat_to_pr (s_ce e x)) (c_pair y z) = nat_to_pr (s1_1 (comp_by_index e ?n1) x) (c_pair y z)" by (unfold s_ce_def, simp)
  also have " = (nat_to_pr (comp_by_index e ?n1)) (c_pair x (c_pair y z))" by (simp add: s1_1_th1)
  also have " = (nat_to_pr e) ((nat_to_pr ?n1) (c_pair x (c_pair y z)))" by (simp add: comp_by_index_main)
  finally show ?thesis by (simp add: index_of_r_to_l_lm)
qed

theorem s_ce_1_1_th: "(c_pair x y  nat_to_ce_set e) = (y  nat_to_ce_set (s_ce e x))"
proof
  assume A: "c_pair x y  nat_to_ce_set e"
  then obtain z where L1: "(nat_to_pr e) (c_pair (c_pair x y) z) = 0" 
    by (auto simp add: nat_to_ce_set_lm_1)
  have "(nat_to_pr (s_ce e x)) (c_pair y z) = 0" by (simp add: s_lm L1)
  with nat_to_ce_set_lm_1 show "y  nat_to_ce_set (s_ce e x)" by auto
next
  assume A: "y  nat_to_ce_set (s_ce e x)"
  then obtain z where L1: "(nat_to_pr (s_ce e x)) (c_pair y z) = 0" 
    by (auto simp add: nat_to_ce_set_lm_1)
  then have "(nat_to_pr e) (c_pair (c_pair x y) z) = 0" by (simp add: s_lm)
  with nat_to_ce_set_lm_1 show "c_pair x y  nat_to_ce_set e" by auto
qed

definition
  one_reducible_to_via :: "(nat set)  (nat set)  (nat  nat)  bool" where
  "one_reducible_to_via = (λ A B f. total_recursive f  inj f  ( x. (x  A) = (f x  B)))"

definition
  one_reducible_to :: "(nat set)  (nat set)  bool" where
  "one_reducible_to = (λ A B.  f. one_reducible_to_via A B f)"

definition
  many_reducible_to_via :: "(nat set)  (nat set)  (nat  nat)  bool" where
  "many_reducible_to_via = (λ A B f. total_recursive f  ( x. (x  A) = (f x  B)))"

definition
  many_reducible_to :: "(nat set)  (nat set)  bool" where
  "many_reducible_to = (λ A B.  f. many_reducible_to_via A B f)"

lemma one_reducible_to_via_trans: " one_reducible_to_via A B f; one_reducible_to_via B C g   one_reducible_to_via A C (g o f)"
proof -
  assume A1: "one_reducible_to_via A B f"
  assume A2: "one_reducible_to_via B C g"
  from A1 have f_tr: "total_recursive f" by (unfold one_reducible_to_via_def, auto)
  from A1 have f_inj: "inj f" by (unfold one_reducible_to_via_def, auto)
  from A1 have L1: " x. (x  A) = (f x  B)" by (unfold one_reducible_to_via_def, auto)
  from A2 have g_tr: "total_recursive g" by (unfold one_reducible_to_via_def, auto)
  from A2 have g_inj: "inj g" by (unfold one_reducible_to_via_def, auto)
  from A2 have L2: " x. (x  B) = (g x  C)" by (unfold one_reducible_to_via_def, auto)
  from g_tr f_tr have fg_tr: "total_recursive (g o f)" by (rule comp_tot_rec)
  from g_inj f_inj have fg_inj: "inj (g o f)" by (rule inj_compose)
  from L1 L2 have L3: "( x. (x  A) = ((g o f) x  C))" by auto
  with fg_tr fg_inj show ?thesis by (unfold one_reducible_to_via_def, auto)
qed

lemma one_reducible_to_trans: " one_reducible_to A B; one_reducible_to B C   one_reducible_to A C"
proof -
  assume "one_reducible_to A B"
  then obtain f where A1: "one_reducible_to_via A B f" unfolding one_reducible_to_def by auto
  assume "one_reducible_to B C"
  then obtain g where A2: "one_reducible_to_via B C g" unfolding one_reducible_to_def by auto
  from A1 A2 have "one_reducible_to_via A C (g o f)" by (rule one_reducible_to_via_trans)
  then show ?thesis unfolding one_reducible_to_def by auto
qed

lemma one_reducible_to_via_refl: "one_reducible_to_via A A (λ x. x)"
proof -
  have is_pr: "(λ x. x)  PrimRec1" by (rule pr_id1_1)
  then have is_tr: "total_recursive (λ x. x)" by (rule pr_is_total_rec)
  have is_inj: "inj (λ x. x)" by simp
  have L1: " x. (x  A) = (((λ x. x) x)  A)" by simp
  with is_tr is_inj show ?thesis by (unfold one_reducible_to_via_def, auto)
qed

lemma one_reducible_to_refl: "one_reducible_to A A"
proof -
  have "one_reducible_to_via A A (λ x. x)" by (rule one_reducible_to_via_refl)
  then show ?thesis by (unfold one_reducible_to_def, auto)
qed

lemma many_reducible_to_via_trans: " many_reducible_to_via A B f; many_reducible_to_via B C g   many_reducible_to_via A C (g o f)"
proof -
  assume A1: "many_reducible_to_via A B f"
  assume A2: "many_reducible_to_via B C g"
  from A1 have f_tr: "total_recursive f" by (unfold many_reducible_to_via_def, auto)
  from A1 have L1: " x. (x  A) = (f x  B)" by (unfold many_reducible_to_via_def, auto)
  from A2 have g_tr: "total_recursive g" by (unfold many_reducible_to_via_def, auto)
  from A2 have L2: " x. (x  B) = (g x  C)" by (unfold many_reducible_to_via_def, auto)
  from g_tr f_tr have fg_tr: "total_recursive (g o f)" by (rule comp_tot_rec)
  from L1 L2 have L3: "( x. (x  A) = ((g o f) x  C))" by auto
  with fg_tr show ?thesis by (unfold many_reducible_to_via_def, auto)
qed

lemma many_reducible_to_trans: " many_reducible_to A B; many_reducible_to B C   many_reducible_to A C"
proof -
  assume "many_reducible_to A B"
  then obtain f where A1: "many_reducible_to_via A B f"
    unfolding many_reducible_to_def by auto
  assume "many_reducible_to B C"
  then obtain g where A2: "many_reducible_to_via B C g"
    unfolding many_reducible_to_def by auto
  from A1 A2 have "many_reducible_to_via A C (g o f)" by (rule many_reducible_to_via_trans)
  then show ?thesis unfolding many_reducible_to_def by auto
qed

lemma one_reducibility_via_is_many: "one_reducible_to_via A B f  many_reducible_to_via A B f"
proof -
  assume A: "one_reducible_to_via A B f"
  from A have f_tr: "total_recursive f" by (unfold one_reducible_to_via_def, auto)
  from A have " x. (x  A) = (f x  B)" by (unfold one_reducible_to_via_def, auto)
  with f_tr show ?thesis by (unfold many_reducible_to_via_def, auto)
qed

lemma one_reducibility_is_many: "one_reducible_to A B  many_reducible_to A B"
proof -
  assume "one_reducible_to A B"
  then obtain f where A: "one_reducible_to_via A B f" 
    unfolding one_reducible_to_def by auto
  then have "many_reducible_to_via A B f" by (rule one_reducibility_via_is_many)
  then show ?thesis unfolding many_reducible_to_def by auto
qed

lemma many_reducible_to_via_refl: "many_reducible_to_via A A (λ x. x)"
proof -
  have "one_reducible_to_via A A (λ x. x)" by (rule one_reducible_to_via_refl)
  then show ?thesis by (rule one_reducibility_via_is_many)
qed

lemma many_reducible_to_refl: "many_reducible_to A A"
proof -
  have "one_reducible_to A A" by (rule one_reducible_to_refl)
  then show ?thesis by (rule one_reducibility_is_many)
qed

theorem m_red_to_comp: " many_reducible_to A B; computable B   computable A"
proof -
  assume "many_reducible_to A B"
  then obtain f where A1: "many_reducible_to_via A B f" 
    unfolding many_reducible_to_def by auto
  from A1 have f_tr: "total_recursive f" by (unfold many_reducible_to_via_def, auto)
  from A1 have L1: " x. (x  A) = (f x  B)" by (unfold many_reducible_to_via_def, auto)
  assume "computable B"
  then have L2: "total_recursive (chf B)" by (rule comp_impl_tot_rec)
  have L3: "chf A = (chf B) o f"
  proof fix x
    have "chf A x = (chf B) (f x)"
    proof cases
      assume A: "x  A"
      then have L3_1: "chf A x = 0" by (simp add: chf_lm_2)
      from A L1 have "f x  B" by auto
      then have L3_2: "(chf B) (f x) = 0" by (simp add: chf_lm_2)
      from L3_1 L3_2 show "chf A x = (chf B) (f x)" by auto
    next
      assume A: "x  A"
      then have L3_1: "chf A x = 1" by (simp add: chf_lm_3)
      from A L1 have "f x  B" by auto
      then have L3_2: "(chf B) (f x) = 1" by (simp add: chf_lm_3)
      from L3_1 L3_2 show "chf A x = (chf B) (f x)" by auto
    qed
    then show "chf A x = (chf B  f) x" by auto
  qed
  from L2 f_tr have "total_recursive (chf B  f)" by (rule comp_tot_rec)
  with L3 have "total_recursive (chf A)" by auto
  then show ?thesis by (rule tot_rec_impl_comp)
qed

lemma many_reducible_lm_1: "many_reducible_to univ_ce A  ¬ computable A"
proof (rule ccontr)
  assume A1: "many_reducible_to univ_ce A"
  assume "¬ ¬ computable A"
  then have A2: "computable A" by auto
  from A1 A2 have "computable univ_ce" by (rule m_red_to_comp)
  with univ_ce_is_not_comp3 show False by auto
qed

lemma one_reducible_lm_1: "one_reducible_to univ_ce A  ¬ computable A"
proof -
  assume "one_reducible_to univ_ce A"
  then have "many_reducible_to univ_ce A" by (rule one_reducibility_is_many)
  then show ?thesis by (rule many_reducible_lm_1)
qed

lemma one_reducible_lm_2: "one_reducible_to_via (nat_to_ce_set n) univ_ce (λ x. c_pair n x)"
proof -
  define f where "f x = c_pair n x" for x
  have f_is_pr: "f  PrimRec1" unfolding f_def by prec
  then have f_tr: "total_recursive f" by (rule pr_is_total_rec)
  have f_inj: "inj f"
  proof (rule injI)
    fix x y assume A: "f x = f y"
    then have "c_pair n x = c_pair n y" by (unfold f_def)
    then show "x = y" by (rule c_pair_inj2)
  qed
  have " x. (x  (nat_to_ce_set n)) = (f x  univ_ce)"
  proof fix x show "(x  nat_to_ce_set n) = (f x  univ_ce)" by (unfold f_def, simp add: univ_ce_lm_1)
  qed
  with f_tr f_inj show ?thesis by (unfold f_def, unfold one_reducible_to_via_def, auto)
qed

lemma one_reducible_lm_3: "one_reducible_to (nat_to_ce_set n) univ_ce"
proof -
  have "one_reducible_to_via (nat_to_ce_set n) univ_ce (λ x. c_pair n x)" by (rule one_reducible_lm_2)
  then show ?thesis by (unfold one_reducible_to_def, auto)
qed

lemma one_reducible_lm_4: "A  ce_sets  one_reducible_to A univ_ce"
proof -
  assume "A  ce_sets"
  then have " n. A = nat_to_ce_set n" by (rule nat_to_ce_set_srj)
  then obtain n where "A = nat_to_ce_set n" by auto
  with one_reducible_lm_3 show ?thesis by auto
qed

subsection ‹One-complete sets›

definition
  one_complete :: "nat set  bool" where
  "one_complete = (λ A. A  ce_sets  ( B. B  ce_sets  one_reducible_to B A))"

theorem univ_is_complete: "one_complete univ_ce"
proof (unfold one_complete_def)
  show "univ_ce  ce_sets  (B. B  ce_sets  one_reducible_to B univ_ce)"
  proof
    show "univ_ce  ce_sets" by (rule univ_is_ce)
  next
    show "B. B  ce_sets  one_reducible_to B univ_ce"
    proof (rule allI, rule impI)
      fix B assume "B  ce_sets" then show "one_reducible_to B univ_ce" by (rule one_reducible_lm_4)
    qed
  qed
qed

subsection ‹Index sets, Rice's theorem›

definition
  index_set :: "nat set  bool" where
  "index_set = (λ A.  n m. n  A  (nat_to_ce_set n = nat_to_ce_set m)  m  A)"

lemma index_set_lm_1: " index_set A; n A; nat_to_ce_set n = nat_to_ce_set m   m  A"
proof -
  assume A1: "index_set A"
  assume A2: "n  A"
  assume A3: "nat_to_ce_set n = nat_to_ce_set m"
  from A2 A3 have L1: "n  A  (nat_to_ce_set n = nat_to_ce_set m)" by auto
  from A1 have L2: " n m. n  A  (nat_to_ce_set n = nat_to_ce_set m)  m  A" by (unfold index_set_def)
  from L1 L2 show ?thesis by auto
qed

lemma index_set_lm_2: "index_set A  index_set (-A)"
proof -
  assume A: "index_set A"
  show "index_set (-A)"
  proof (unfold index_set_def)
    show "n m. n  - A  nat_to_ce_set n = nat_to_ce_set m  m  - A"
    proof (rule allI, rule allI, rule impI)
      fix n m assume A1: "n  - A  nat_to_ce_set n = nat_to_ce_set m"
      from A1 have A2: "n  -A" by auto
      from A1 have A3: "nat_to_ce_set m = nat_to_ce_set n" by auto
      show "m  - A"
      proof
        assume "m  A"
        from A this A3 have "n  A" by (rule index_set_lm_1)
        with A2 show False by auto
      qed
    qed
  qed
qed

lemma Rice_lm_1: " index_set A; A  {}; A  UNIV;  n  A. nat_to_ce_set n = {}   one_reducible_to univ_ce (- A)"
proof -
  assume A1: "index_set A"
  assume A2: "A  {}"
  assume A3: "A  UNIV"
  assume " n  A. nat_to_ce_set n = {}"
  then obtain e_0 where e_0_in_A: "e_0  A" and e_0_empty: "nat_to_ce_set e_0 = {}" by auto
  from e_0_in_A A3 obtain e_1 where e_1_not_in_A: "e_1  (- A)" by auto
  with e_0_in_A have e_0_neq_e_1: "e_0  e_1" by auto
  have "nat_to_ce_set e_0  nat_to_ce_set e_1"
  proof
    assume "nat_to_ce_set e_0 = nat_to_ce_set e_1"
    with A1 e_0_in_A have "e_1  A" by (rule index_set_lm_1)
    with e_1_not_in_A show False by auto
  qed
  with e_0_empty have e1_not_empty: "nat_to_ce_set e_1  {}" by auto
  define we_1 where "we_1 = nat_to_ce_set e_1"
  from e1_not_empty have we_1_not_empty: "we_1  {}" by (unfold we_1_def)
  define r where "r = univ_ce × we_1"
  have loc_lm_1: " x. x  univ_ce   y. (y  we_1) = ((x,y)  r)" by (unfold r_def, auto)
  have loc_lm_2: " x. x  univ_ce   y. (y  {}) = ((x,y)  r)" by (unfold r_def, auto)
  have r_ce: "r  ce_rels"
  proof (unfold r_def, rule ce_rel_lm_29)
    show "univ_ce  ce_sets" by (rule univ_is_ce)
    show "we_1  ce_sets" by (unfold we_1_def, rule nat_to_ce_set_into_ce)
  qed
  define we_n where "we_n = ce_rel_to_set r"
  from r_ce have we_n_ce: "we_n  ce_sets" by (unfold we_n_def, rule ce_rel_lm_6)
  then have " n. we_n = nat_to_ce_set n" by (rule nat_to_ce_set_srj)
  then obtain n where we_n_df1: "we_n = nat_to_ce_set n" by auto
  define f where "f x = s_ce n x" for x
  from s_ce_is_pr have f_is_pr: "f  PrimRec1" unfolding f_def by prec
  then have f_tr: "total_recursive f" by (rule pr_is_total_rec)
  have f_inj: "inj f"
  proof (rule injI)
    fix x y
    assume "f x = f y"
    then have "s_ce n x = s_ce n y" by (unfold f_def)
    then show "x = y" by (rule s_ce_inj2)
  qed
  have loc_lm_3: " x y. (c_pair x y  we_n) = (y  nat_to_ce_set (f x))"
  proof (rule allI, rule allI)
    fix x y show "(c_pair x y  we_n) = (y  nat_to_ce_set (f x))" by (unfold f_def, unfold we_n_df1, simp add: s_ce_1_1_th)
  qed
  from A1 have loc_lm_4: "index_set (- A)" by (rule index_set_lm_2)
  have loc_lm_5: " x. (x  univ_ce) = (f x  -A)"
  proof fix x show "(x  univ_ce) = (f x  -A)"
    proof
      assume A: "x  univ_ce"
      then have S1: " y. (y  we_1) = ((x,y)  r)" by (rule loc_lm_1)
      from ce_rel_lm_12 have " y. (c_pair x y  ce_rel_to_set r) = ((x,y)  r)" by auto
      then have " y. ((x,y)  r) = (c_pair x y  we_n)" by (unfold we_n_def, auto)
      with S1 have " y. (y  we_1) = (c_pair x y  we_n)" by auto
      with loc_lm_3 have " y. (y  we_1) = (y  nat_to_ce_set (f x))" by auto
      then have S2: "we_1 = nat_to_ce_set (f x)" by auto
      then have "nat_to_ce_set e_1 = nat_to_ce_set (f x)" by (unfold we_1_def)
      with loc_lm_4 e_1_not_in_A show "f x  -A" by (rule index_set_lm_1)
    next
      show " f x  - A  x  univ_ce"
      proof (rule ccontr)
        assume fx_in_A: "f x  - A"
        assume x_not_in_univ: "x  univ_ce"
        then have S1: " y. (y  {}) = ((x,y)  r)" by (rule loc_lm_2)
        from ce_rel_lm_12 have " y. (c_pair x y  ce_rel_to_set r) = ((x,y)  r)" by auto
        then have " y. ((x,y)  r) = (c_pair x y  we_n)" by (unfold we_n_def, auto)
        with S1 have " y. (y  {}) = (c_pair x y  we_n)" by auto
        with loc_lm_3 have " y. (y  {}) = (y  nat_to_ce_set (f x))" by auto
        then have S2: "{} = nat_to_ce_set (f x)" by auto
        then have "nat_to_ce_set e_0 = nat_to_ce_set (f x)" by (unfold e_0_empty)
        with A1 e_0_in_A have "f x  A" by (rule index_set_lm_1)
        with fx_in_A show False by auto
      qed
    qed
  qed
  with f_tr f_inj have "one_reducible_to_via univ_ce (-A) f" by (unfold one_reducible_to_via_def, auto)
  then show ?thesis by (unfold one_reducible_to_def, auto)
qed

lemma Rice_lm_2: " index_set A; A  {}; A  UNIV; n  A;  nat_to_ce_set n = {}   one_reducible_to univ_ce (- A)"
proof -
  assume A1: "index_set A"
  assume A2: "A  {}"
  assume A3: "A  UNIV"
  assume A4: "n  A"
  assume A5: "nat_to_ce_set n = {}"
  from A4 A5 have S1: " n  A. nat_to_ce_set n = {}" by auto
  from A1 A2 A3 S1 show ?thesis by (rule Rice_lm_1)
qed

theorem Rice_1: " index_set A; A  {}; A  UNIV   one_reducible_to univ_ce A  one_reducible_to univ_ce (- A)"
proof -
  assume A1: "index_set A"
  assume A2: "A  {}"
  assume A3: "A  UNIV"
  from ce_empty have " n. {} = nat_to_ce_set n" by (rule nat_to_ce_set_srj)
  then obtain n where n_empty: "nat_to_ce_set n = {}" by auto
  show ?thesis
  proof cases
    assume A: "n  A"
    from A1 A2 A3 A n_empty have "one_reducible_to univ_ce (- A)" by (rule Rice_lm_2)
    then show ?thesis by auto
  next
    assume "n  A" then have A: "n  - A" by auto
    from A1 have S1: "index_set (- A)" by (rule index_set_lm_2)
    from A3 have S2: "- A  {}" by auto
    from A2 have S3: "- A  UNIV" by auto
    from S1 S2 S3 A n_empty have "one_reducible_to univ_ce (- (- A))" by (rule Rice_lm_2)
    then have "one_reducible_to univ_ce A" by simp
    then show ?thesis by auto
  qed
qed

theorem Rice_2: " index_set A; A  {}; A  UNIV   ¬ computable A"
proof -
  assume A1: "index_set A"
  assume A2: "A  {}"
  assume A3: "A  UNIV"
  from A1 A2 A3 have "one_reducible_to univ_ce A  one_reducible_to univ_ce (- A)" by (rule Rice_1)
  then have S1: "¬ one_reducible_to univ_ce A  one_reducible_to univ_ce (- A)" by auto
  show ?thesis
  proof cases
    assume "one_reducible_to univ_ce A"
    then show "¬ computable A" by (rule one_reducible_lm_1)
  next
    assume "¬ one_reducible_to univ_ce A"
    with S1 have "one_reducible_to univ_ce (- A)" by auto
    then have "¬ computable (- A)" by (rule one_reducible_lm_1)
    with computable_complement_3 show "¬ computable A" by auto
  qed
qed

theorem Rice_3: " C  ce_sets; computable { n. nat_to_ce_set n  C}   C = {}  C = ce_sets"
proof (rule ccontr)
  assume A1: "C  ce_sets"
  assume A2: "computable { n. nat_to_ce_set n  C}"
  assume A3: "¬ (C = {}  C = ce_sets)"
  from A3 have A4: "C  {}" by auto
  from A3 have A5: "C  ce_sets" by auto
  define A where "A = { n. nat_to_ce_set n  C}"
  have S1: "index_set A"
  proof (unfold index_set_def)
    show "n m. n  A  nat_to_ce_set n = nat_to_ce_set m  m  A"
    proof (rule allI, rule allI, rule impI)
      fix n m assume A1_1: "n  A  nat_to_ce_set n = nat_to_ce_set m"
      from A1_1 have "n  A" by auto
      then have S1_1: "nat_to_ce_set n  C" by (unfold A_def, auto)
      from A1_1 have "nat_to_ce_set n = nat_to_ce_set m" by auto
      with S1_1 have "nat_to_ce_set m  C" by auto
      then show "m  A" by (unfold A_def, auto)
    qed
  qed
  have S2: "A  {}"
  proof -
    from A4 obtain B where S2_1: "B  C" by auto
    with A1 have "B  ce_sets" by auto
    then have " n. B = nat_to_ce_set n" by (rule nat_to_ce_set_srj)
    then obtain n where "B = nat_to_ce_set n" ..
    with S2_1 have "nat_to_ce_set n  C" by auto
    then show ?thesis by (unfold A_def, auto)
  qed
  have S3: "A  UNIV"
  proof -
    from A1 A5 obtain B where S2_1: "B  C" and S2_2: "B  ce_sets" by auto
    from S2_2 have " n. B = nat_to_ce_set n" by (rule nat_to_ce_set_srj)
    then obtain n where "B = nat_to_ce_set n" ..
    with S2_1 have "nat_to_ce_set n  C" by auto
    then show ?thesis by (unfold A_def, auto)
  qed
  from S1 S2 S3 have "¬ computable A" by (rule Rice_2)
  with A2 show False unfolding A_def by auto
qed

end