File: Mathlib/Computability/PartrecCode.lean

full_name: Nat.Partrec.rfind'
code: theorem rfind' {f} (hf : Nat.Partrec f) :
    Nat.Partrec
      (Nat.unpaired fun a m =>
        (Nat.rfind fun n => (fun m => m = 0) <$> f (Nat.pair a (n + m))).map (· + m)) 
goal: Nat.Partrec
  (Nat.unpaired fun a m =>
    Part.map (fun x => x + m) (Nat.rfind fun n => (fun m => decide (m = 0)) <$> f (Nat.pair a (n + m))))

full_name: Nat.Partrec.Code.rfind'
code: /-- Code for partial recursive functions from ℕ to ℕ.
See `Nat.Partrec.Code.eval` for the interpretation of these constructors.
-/
inductive Code : Type
  | zero : Code
  | succ : Code
  | left : Code
  | right : Code
  | pair : Code → Code → Code
  | comp : Code → Code → Code
  | prec : Code → Code → Code
  | rfind' : Code → Code
goal: Nat.Partrec.Code → Nat.Partrec.Code

full_name: Nat.Partrec.Code.pair
code: /-- Code for partial recursive functions from ℕ to ℕ.
See `Nat.Partrec.Code.eval` for the interpretation of these constructors.
-/
inductive Code : Type
  | zero : Code
  | succ : Code
  | left : Code
  | right : Code
  | pair : Code → Code → Code
  | comp : Code → Code → Code
  | prec : Code → Code → Code
  | rfind' : Code → Code
goal: Nat.Partrec.Code → Nat.Partrec.Code → Nat.Partrec.Code

full_name: Nat.Partrec.Code
code: /-- Code for partial recursive functions from ℕ to ℕ.
See `Nat.Partrec.Code.eval` for the interpretation of these constructors.
-/
inductive Code : Type
  | zero : Code
  | succ : Code
  | left : Code
  | right : Code
  | pair : Code → Code → Code
  | comp : Code → Code → Code
  | prec : Code → Code → Code
  | rfind' : Code → Code
goal: Type

full_name: Nat.Partrec.Code.prec
code: /-- Code for partial recursive functions from ℕ to ℕ.
See `Nat.Partrec.Code.eval` for the interpretation of these constructors.
-/
inductive Code : Type
  | zero : Code
  | succ : Code
  | left : Code
  | right : Code
  | pair : Code → Code → Code
  | comp : Code → Code → Code
  | prec : Code → Code → Code
  | rfind' : Code → Code
goal: Nat.Partrec.Code → Nat.Partrec.Code → Nat.Partrec.Code

full_name: Nat.Partrec.Code.left
code: /-- Code for partial recursive functions from ℕ to ℕ.
See `Nat.Partrec.Code.eval` for the interpretation of these constructors.
-/
inductive Code : Type
  | zero : Code
  | succ : Code
  | left : Code
  | right : Code
  | pair : Code → Code → Code
  | comp : Code → Code → Code
  | prec : Code → Code → Code
  | rfind' : Code → Code
goal: Nat.Partrec.Code

full_name: Nat.Partrec.Code.right
code: /-- Code for partial recursive functions from ℕ to ℕ.
See `Nat.Partrec.Code.eval` for the interpretation of these constructors.
-/
inductive Code : Type
  | zero : Code
  | succ : Code
  | left : Code
  | right : Code
  | pair : Code → Code → Code
  | comp : Code → Code → Code
  | prec : Code → Code → Code
  | rfind' : Code → Code
goal: Nat.Partrec.Code

full_name: Nat.Partrec.Code.zero
code: /-- Code for partial recursive functions from ℕ to ℕ.
See `Nat.Partrec.Code.eval` for the interpretation of these constructors.
-/
inductive Code : Type
  | zero : Code
  | succ : Code
  | left : Code
  | right : Code
  | pair : Code → Code → Code
  | comp : Code → Code → Code
  | prec : Code → Code → Code
  | rfind' : Code → Code
goal: Nat.Partrec.Code

full_name: Nat.Partrec.Code.comp
code: /-- Code for partial recursive functions from ℕ to ℕ.
See `Nat.Partrec.Code.eval` for the interpretation of these constructors.
-/
inductive Code : Type
  | zero : Code
  | succ : Code
  | left : Code
  | right : Code
  | pair : Code → Code → Code
  | comp : Code → Code → Code
  | prec : Code → Code → Code
  | rfind' : Code → Code
goal: Nat.Partrec.Code → Nat.Partrec.Code → Nat.Partrec.Code

full_name: Nat.Partrec.Code.succ
code: /-- Code for partial recursive functions from ℕ to ℕ.
See `Nat.Partrec.Code.eval` for the interpretation of these constructors.
-/
inductive Code : Type
  | zero : Code
  | succ : Code
  | left : Code
  | right : Code
  | pair : Code → Code → Code
  | comp : Code → Code → Code
  | prec : Code → Code → Code
  | rfind' : Code → Code
goal: Nat.Partrec.Code

full_name: Nat.Partrec.Code.instInhabited
code: instance instInhabited : Inhabited Code 
goal: Inhabited Nat.Partrec.Code

full_name: Nat.Partrec.Code.const
code: /-- Returns a code for the constant function outputting a particular natural. -/
protected def const : ℕ → Code
  
goal: ℕ → Nat.Partrec.Code

full_name: Nat.Partrec.Code.const_inj
code: theorem const_inj : ∀ {n₁ n₂}, Nat.Partrec.Code.const n₁ = Nat.Partrec.Code.const n₂ → n₁ = n₂
  
goal: Nat.Partrec.Code.const n₁ = Nat.Partrec.Code.const n₂ → n₁ = n₂

full_name: Nat.Partrec.Code.id
code: /-- A code for the identity function. -/
protected def id : Code 
goal: Nat.Partrec.Code

full_name: Nat.Partrec.Code.curry
code: /-- Given a code `c` taking a pair as input, returns a code using `n` as the first argument to `c`.
-/
def curry (c : Code) (n : ℕ) : Code 
goal: Nat.Partrec.Code

full_name: Nat.Partrec.Code.encodeCode
code: /-- An encoding of a `Nat.Partrec.Code` as a ℕ. -/
def encodeCode : Code → ℕ
  
goal: Nat.Partrec.Code → ℕ

full_name: Nat.Partrec.Code.ofNatCode
code: /--
A decoder for `Nat.Partrec.Code.encodeCode`, taking any ℕ to the `Nat.Partrec.Code` it represents.
-/
def ofNatCode : ℕ → Code
  
goal: ℕ → Nat.Partrec.Code

full_name: _private.Mathlib.Computability.PartrecCode.0.Nat.Partrec.Code.encode_ofNatCode
code: /-- Proof that `Nat.Partrec.Code.ofNatCode` is the inverse of `Nat.Partrec.Code.encodeCode`-/
private theorem encode_ofNatCode : ∀ n, encodeCode (ofNatCode n) = n
  
goal: (Nat.Partrec.Code.ofNatCode n).encodeCode = n

full_name: Nat.Partrec.Code.instDenumerable
code: instance instDenumerable : Denumerable Code 
goal: Denumerable Nat.Partrec.Code

full_name: Nat.Partrec.Code.encodeCode_eq
code: theorem encodeCode_eq : encode = encodeCode 
goal: Encodable.encode = Nat.Partrec.Code.encodeCode

full_name: Nat.Partrec.Code.ofNatCode_eq
code: theorem ofNatCode_eq : ofNat Code = ofNatCode 
goal: Denumerable.ofNat Nat.Partrec.Code = Nat.Partrec.Code.ofNatCode

full_name: Nat.Partrec.Code.encode_lt_pair
code: theorem encode_lt_pair (cf cg) :
    encode cf < encode (pair cf cg) ∧ encode cg < encode (pair cf cg) 
goal: Encodable.encode cf < Encodable.encode (cf.pair cg) ∧ Encodable.encode cg < Encodable.encode (cf.pair cg)

full_name: Nat.Partrec.Code.encode_lt_comp
code: theorem encode_lt_comp (cf cg) :
    encode cf < encode (comp cf cg) ∧ encode cg < encode (comp cf cg) 
goal: Encodable.encode cf < Encodable.encode (cf.comp cg) ∧ Encodable.encode cg < Encodable.encode (cf.comp cg)

full_name: Nat.Partrec.Code.encode_lt_prec
code: theorem encode_lt_prec (cf cg) :
    encode cf < encode (prec cf cg) ∧ encode cg < encode (prec cf cg) 
goal: Encodable.encode cf < Encodable.encode (cf.prec cg) ∧ Encodable.encode cg < Encodable.encode (cf.prec cg)

full_name: Nat.Partrec.Code.encode_lt_rfind'
code: theorem encode_lt_rfind' (cf) : encode cf < encode (rfind' cf) 
goal: Encodable.encode cf < Encodable.encode cf.rfind'

full_name: Nat.Partrec.Code.pair_prim
code: theorem pair_prim : Primrec₂ pair 
goal: Primrec₂ Nat.Partrec.Code.pair

full_name: Nat.Partrec.Code.comp_prim
code: theorem comp_prim : Primrec₂ comp 
goal: Primrec₂ Nat.Partrec.Code.comp

full_name: Nat.Partrec.Code.prec_prim
code: theorem prec_prim : Primrec₂ prec 
goal: Primrec₂ Nat.Partrec.Code.prec

full_name: Nat.Partrec.Code.rfind_prim
code: theorem rfind_prim : Primrec rfind' 
goal: Primrec Nat.Partrec.Code.rfind'

full_name: Nat.Partrec.Code.rec_prim'
code: theorem rec_prim' {α σ} [Primcodable α] [Primcodable σ] {c : α → Code} (hc : Primrec c) {z : α → σ}
    (hz : Primrec z) {s : α → σ} (hs : Primrec s) {l : α → σ} (hl : Primrec l) {r : α → σ}
    (hr : Primrec r) {pr : α → Code × Code × σ × σ → σ} (hpr : Primrec₂ pr)
    {co : α → Code × Code × σ × σ → σ} (hco : Primrec₂ co) {pc : α → Code × Code × σ × σ → σ}
    (hpc : Primrec₂ pc) {rf : α → Code × σ → σ} (hrf : Primrec₂ rf) :
    let PR (a) cf cg hf hg := pr a (cf, cg, hf, hg)
    let CO (a) cf cg hf hg := co a (cf, cg, hf, hg)
    let PC (a) cf cg hf hg := pc a (cf, cg, hf, hg)
    let RF (a) cf hf := rf a (cf, hf)
    let F (a : α) (c : Code) : σ :=
      Nat.Partrec.Code.recOn c (z a) (s a) (l a) (r a) (PR a) (CO a) (PC a) (RF a)
    Primrec (fun a => F a (c a) : α → σ) 
goal: let PR := fun a cf cg hf hg => pr a (cf, cg, hf, hg);
let CO := fun a cf cg hf hg => co a (cf, cg, hf, hg);
let PC := fun a cf cg hf hg => pc a (cf, cg, hf, hg);
let RF := fun a cf hf => rf a (cf, hf);
let F := fun a c => Nat.Partrec.Code.recOn c (z a) (s a) (l a) (r a) (PR a) (CO a) (PC a) (RF a);
Primrec fun a => F a (c a)

full_name: Nat.Partrec.Code.rec_prim
code: /-- Recursion on `Nat.Partrec.Code` is primitive recursive. -/
theorem rec_prim {α σ} [Primcodable α] [Primcodable σ] {c : α → Code} (hc : Primrec c) {z : α → σ}
    (hz : Primrec z) {s : α → σ} (hs : Primrec s) {l : α → σ} (hl : Primrec l) {r : α → σ}
    (hr : Primrec r) {pr : α → Code → Code → σ → σ → σ}
    (hpr : Primrec fun a : α × Code × Code × σ × σ => pr a.1 a.2.1 a.2.2.1 a.2.2.2.1 a.2.2.2.2)
    {co : α → Code → Code → σ → σ → σ}
    (hco : Primrec fun a : α × Code × Code × σ × σ => co a.1 a.2.1 a.2.2.1 a.2.2.2.1 a.2.2.2.2)
    {pc : α → Code → Code → σ → σ → σ}
    (hpc : Primrec fun a : α × Code × Code × σ × σ => pc a.1 a.2.1 a.2.2.1 a.2.2.2.1 a.2.2.2.2)
    {rf : α → Code → σ → σ} (hrf : Primrec fun a : α × Code × σ => rf a.1 a.2.1 a.2.2) :
    let F (a : α) (c : Code) : σ :=
      Nat.Partrec.Code.recOn c (z a) (s a) (l a) (r a) (pr a) (co a) (pc a) (rf a)
    Primrec fun a => F a (c a) 
goal: let F := fun a c => Nat.Partrec.Code.recOn c (z a) (s a) (l a) (r a) (pr a) (co a) (pc a) (rf a);
Primrec fun a => F a (c a)

full_name: Nat.Partrec.Code.rec_computable
code: /-- Recursion on `Nat.Partrec.Code` is computable. -/
theorem rec_computable {α σ} [Primcodable α] [Primcodable σ] {c : α → Code} (hc : Computable c)
    {z : α → σ} (hz : Computable z) {s : α → σ} (hs : Computable s) {l : α → σ} (hl : Computable l)
    {r : α → σ} (hr : Computable r) {pr : α → Code × Code × σ × σ → σ} (hpr : Computable₂ pr)
    {co : α → Code × Code × σ × σ → σ} (hco : Computable₂ co) {pc : α → Code × Code × σ × σ → σ}
    (hpc : Computable₂ pc) {rf : α → Code × σ → σ} (hrf : Computable₂ rf) :
    let PR (a) cf cg hf hg := pr a (cf, cg, hf, hg)
    let CO (a) cf cg hf hg := co a (cf, cg, hf, hg)
    let PC (a) cf cg hf hg := pc a (cf, cg, hf, hg)
    let RF (a) cf hf := rf a (cf, hf)
    let F (a : α) (c : Code) : σ :=
      Nat.Partrec.Code.recOn c (z a) (s a) (l a) (r a) (PR a) (CO a) (PC a) (RF a)
    Computable fun a => F a (c a) 
goal: let PR := fun a cf cg hf hg => pr a (cf, cg, hf, hg);
let CO := fun a cf cg hf hg => co a (cf, cg, hf, hg);
let PC := fun a cf cg hf hg => pc a (cf, cg, hf, hg);
let RF := fun a cf hf => rf a (cf, hf);
let F := fun a c => Nat.Partrec.Code.recOn c (z a) (s a) (l a) (r a) (PR a) (CO a) (PC a) (RF a);
Computable fun a => F a (c a)

full_name: Nat.Partrec.Code.eval
code: /-- The interpretation of a `Nat.Partrec.Code` as a partial function.
* `Nat.Partrec.Code.zero`: The constant zero function.
* `Nat.Partrec.Code.succ`: The successor function.
* `Nat.Partrec.Code.left`: Left unpairing of a pair of ℕ (encoded by `Nat.pair`)
* `Nat.Partrec.Code.right`: Right unpairing of a pair of ℕ (encoded by `Nat.pair`)
* `Nat.Partrec.Code.pair`: Pairs the outputs of argument codes using `Nat.pair`.
* `Nat.Partrec.Code.comp`: Composition of two argument codes.
* `Nat.Partrec.Code.prec`: Primitive recursion. Given an argument of the form `Nat.pair a n`:
  * If `n = 0`, returns `eval cf a`.
  * If `n = succ k`, returns `eval cg (pair a (pair k (eval (prec cf cg) (pair a k))))`
* `Nat.Partrec.Code.rfind'`: Minimization. For `f` an argument of the form `Nat.pair a m`,
  `rfind' f m` returns the least `a` such that `f a m = 0`, if one exists and `f b m` terminates
  for `b < a`
-/
def eval : Code → ℕ →. ℕ
  
goal: Nat.Partrec.Code → ℕ →. ℕ

full_name: Nat.Partrec.Code.eval_prec_zero
code: /-- Helper lemma for the evaluation of `prec` in the base case. -/
@[simp]
theorem eval_prec_zero (cf cg : Code) (a : ℕ) : eval (prec cf cg) (Nat.pair a 0) = eval cf a 
goal: (cf.prec cg).eval (Nat.pair a 0) = cf.eval a

full_name: Nat.Partrec.Code.eval_prec_succ
code: /-- Helper lemma for the evaluation of `prec` in the recursive case. -/
theorem eval_prec_succ (cf cg : Code) (a k : ℕ) :
    eval (prec cf cg) (Nat.pair a (Nat.succ k)) =
      do {let ih ← eval (prec cf cg) (Nat.pair a k); eval cg (Nat.pair a (Nat.pair k ih))} 
goal: (cf.prec cg).eval (Nat.pair a k.succ) = do
  let ih ← (cf.prec cg).eval (Nat.pair a k)
  cg.eval (Nat.pair a (Nat.pair k ih))

full_name: Nat.Partrec.Code.instMembershipPFun
code: instance : Membership (ℕ →. ℕ) Code 
goal: Membership (ℕ →. ℕ) Nat.Partrec.Code

full_name: Nat.Partrec.Code.eval_const
code: @[simp]
theorem eval_const : ∀ n m, eval (Code.const n) m = Part.some n
  
goal: (Nat.Partrec.Code.const n).eval m = Part.some n

full_name: Nat.Partrec.Code.eval_id
code: @[simp]
theorem eval_id (n) : eval Code.id n = Part.some n 
goal: Nat.Partrec.Code.id.eval n = Part.some n

full_name: Nat.Partrec.Code.eval_curry
code: @[simp]
theorem eval_curry (c n x) : eval (curry c n) x = eval c (Nat.pair n x) 
goal: (c.curry n).eval x = c.eval (Nat.pair n x)

full_name: Nat.Partrec.Code.const_prim
code: theorem const_prim : Primrec Code.const 
goal: Primrec Nat.Partrec.Code.const

full_name: Nat.Partrec.Code.curry_prim
code: theorem curry_prim : Primrec₂ curry 
goal: Primrec₂ Nat.Partrec.Code.curry

full_name: Nat.Partrec.Code.curry_inj
code: theorem curry_inj {c₁ c₂ n₁ n₂} (h : curry c₁ n₁ = curry c₂ n₂) : c₁ = c₂ ∧ n₁ = n₂ 
goal: c₁ = c₂ ∧ n₁ = n₂

full_name: Nat.Partrec.Code.smn
code: /--
The $S_n^m$ theorem: There is a computable function, namely `Nat.Partrec.Code.curry`, that takes a
program and a ℕ `n`, and returns a new program using `n` as the first argument.
-/
theorem smn :
    ∃ f : Code → ℕ → Code, Computable₂ f ∧ ∀ c n x, eval (f c n) x = eval c (Nat.pair n x) 
goal: ∃ f, Computable₂ f ∧ ∀ (c : Nat.Partrec.Code) (n x : ℕ), (f c n).eval x = c.eval (Nat.pair n x)

full_name: Nat.Partrec.Code.exists_code
code: /-- A function is partial recursive if and only if there is a code implementing it. Therefore,
`eval` is a **universal partial recursive function**. -/
theorem exists_code {f : ℕ →. ℕ} : Nat.Partrec f ↔ ∃ c : Code, eval c = f 
goal: Nat.Partrec f ↔ ∃ c, c.eval = f

full_name: Nat.Partrec.Code.evaln
code: /-- A modified evaluation for the code which returns an `Option ℕ` instead of a `Part ℕ`. To avoid
undecidability, `evaln` takes a parameter `k` and fails if it encounters a number ≥ k in the course
of its execution. Other than this, the semantics are the same as in `Nat.Partrec.Code.eval`.
-/
def evaln : ℕ → Code → ℕ → Option ℕ
  
goal: ℕ → Nat.Partrec.Code → ℕ → Option ℕ

full_name: Nat.Partrec.Code.evaln_bound
code: theorem evaln_bound : ∀ {k c n x}, x ∈ evaln k c n → n < k
  
goal: x ∈ Nat.Partrec.Code.evaln k c n → n < k

full_name: Nat.Partrec.Code.evaln_mono
code: theorem evaln_mono : ∀ {k₁ k₂ c n x}, k₁ ≤ k₂ → x ∈ evaln k₁ c n → x ∈ evaln k₂ c n
  
goal: k₁ ≤ k₂ → x ∈ Nat.Partrec.Code.evaln k₁ c n → x ∈ Nat.Partrec.Code.evaln k₂ c n

full_name: Nat.Partrec.Code.evaln_sound
code: theorem evaln_sound : ∀ {k c n x}, x ∈ evaln k c n → x ∈ eval c n
  
goal: x ∈ Nat.Partrec.Code.evaln k c n → x ∈ c.eval n

full_name: Nat.Partrec.Code.evaln_complete
code: theorem evaln_complete {c n x} : x ∈ eval c n ↔ ∃ k, x ∈ evaln k c n 
goal: x ∈ c.eval n ↔ ∃ k, x ∈ Nat.Partrec.Code.evaln k c n

full_name: _private.Mathlib.Computability.PartrecCode.0.Nat.Partrec.Code.lup
code: private def lup (L : List (List (Option ℕ))) (p : ℕ × Code) (n : ℕ) 
goal: Option ℕ

full_name: _private.Mathlib.Computability.PartrecCode.0.Nat.Partrec.Code.hlup
code: private theorem hlup : Primrec fun p : _ × (_ × _) × _ => lup p.1 p.2.1 p.2.2 
goal: Primrec fun p => Nat.Partrec.Code.lup p.1 p.2.1 p.2.2

full_name: _private.Mathlib.Computability.PartrecCode.0.Nat.Partrec.Code.G
code: private def G (L : List (List (Option ℕ))) : Option (List (Option ℕ)) 
goal: Option (List (Option ℕ))

full_name: _private.Mathlib.Computability.PartrecCode.0.Nat.Partrec.Code.hG
code: private theorem hG : Primrec G 
goal: Primrec Nat.Partrec.Code.G

full_name: _private.Mathlib.Computability.PartrecCode.0.Nat.Partrec.Code.evaln_map
code: private theorem evaln_map (k c n) :
    ((((List.range k)[n]?).map (evaln k c)).bind fun b => b) = evaln k c n 
goal: ((Option.map (Nat.Partrec.Code.evaln k c) (List.range k)[n]?).bind fun b => b) = Nat.Partrec.Code.evaln k c n

full_name: Nat.Partrec.Code.evaln_prim
code: /-- The `Nat.Partrec.Code.evaln` function is primitive recursive. -/
theorem evaln_prim : Primrec fun a : (ℕ × Code) × ℕ => evaln a.1.1 a.1.2 a.2 
goal: Primrec fun a => Nat.Partrec.Code.evaln a.1.1 a.1.2 a.2

full_name: Nat.Partrec.Code.eval_eq_rfindOpt
code: theorem eval_eq_rfindOpt (c n) : eval c n = Nat.rfindOpt fun k => evaln k c n 
goal: c.eval n = Nat.rfindOpt fun k => Nat.Partrec.Code.evaln k c n

full_name: Nat.Partrec.Code.eval_part
code: theorem eval_part : Partrec₂ eval 
goal: Partrec₂ Nat.Partrec.Code.eval

full_name: Nat.Partrec.Code.fixed_point
code: /-- Roger's fixed-point theorem: Any total, computable `f` has a fixed point: That is, under the
interpretation given by `Nat.Partrec.Code.eval`, there is a code `c` such that `c` and `f c` have
the same evaluation.
-/
theorem fixed_point {f : Code → Code} (hf : Computable f) : ∃ c : Code, eval (f c) = eval c 
goal: ∃ c, (f c).eval = c.eval

full_name: Nat.Partrec.Code.fixed_point₂
code: theorem fixed_point₂ {f : Code → ℕ →. ℕ} (hf : Partrec₂ f) : ∃ c : Code, eval c = f c 
goal: ∃ c, c.eval = f c