The primitive recursive functions #
The primitive recursive functions are the least collection of functions
ℕ → ℕ
which are closed under projections (using the pair
pairing function), composition, zero, successor, and primitive recursion
(i.e. Nat.rec
where the motive is C n := ℕ
).
We can extend this definition to a large class of basic types by
using canonical encodings of types as natural numbers (Gödel numbering),
which we implement through the type class Encodable
. (More precisely,
we need that the composition of encode with decode yields a
primitive recursive function, so we have the Primcodable
type class
for this.)
References #
- [Mario Carneiro, Formalizing computability theory via partial recursive functions][carneiro2019]
Calls the given function on a pair of entries n
, encoded via the pairing function.
Equations
- Nat.unpaired f n = f (Nat.unpair n).1 (Nat.unpair n).2
Instances For
The primitive recursive functions ℕ → ℕ
.
- zero: Nat.Primrec fun (x : ℕ) => 0
- succ: Nat.Primrec Nat.succ
- left: Nat.Primrec fun (n : ℕ) => (Nat.unpair n).1
- right: Nat.Primrec fun (n : ℕ) => (Nat.unpair n).2
- pair: ∀ {f g : ℕ → ℕ}, Nat.Primrec f → Nat.Primrec g → Nat.Primrec fun (n : ℕ) => Nat.pair (f n) (g n)
- comp: ∀ {f g : ℕ → ℕ}, Nat.Primrec f → Nat.Primrec g → Nat.Primrec fun (n : ℕ) => f (g n)
- prec: ∀ {f g : ℕ → ℕ}, Nat.Primrec f → Nat.Primrec g → Nat.Primrec (Nat.unpaired fun (z n : ℕ) => Nat.rec (f z) (fun (y IH : ℕ) => g (Nat.pair z (Nat.pair y IH))) n)
Instances For
A Primcodable
type is an Encodable
type for which
the encode/decode functions are primitive recursive.
- encode : α → ℕ
- encodek : ∀ (a : α), Encodable.decode (Encodable.encode a) = some a
- prim : Nat.Primrec fun (n : ℕ) => Encodable.encode (Encodable.decode n)
Instances
Equations
- Primcodable.ofDenumerable α = Primcodable.mk (_ : Nat.Primrec fun (n : ℕ) => Encodable.encode (Encodable.decode n))
Builds a Primcodable
instance from an equivalence to a Primcodable
type.
Equations
- Primcodable.ofEquiv α e = let src := Encodable.ofEquiv α e; Primcodable.mk (_ : Nat.Primrec fun (n : ℕ) => Encodable.encode (Encodable.decode n))
Instances For
Equations
Equations
- Primcodable.option = Primcodable.mk (_ : Nat.Primrec fun (n : ℕ) => Encodable.encode (Encodable.decode n))
Primrec f
means f
is primitive recursive (after
encoding its input and output as natural numbers).
Equations
- Primrec f = Nat.Primrec fun (n : ℕ) => Encodable.encode (Option.map f (Encodable.decode n))
Instances For
Equations
- Primcodable.prod = Primcodable.mk (_ : Nat.Primrec fun (n : ℕ) => Encodable.encode (Encodable.decode n))
Primrec₂ f
means f
is a binary primitive recursive function.
This is technically unnecessary since we can always curry all
the arguments together, but there are enough natural two-arg
functions that it is convenient to express this directly.
Instances For
PrimrecPred p
means p : α → Prop
is a (decidable)
primitive recursive predicate, which is to say that
decide ∘ p : α → Bool
is primitive recursive.
Equations
- PrimrecPred p = Primrec fun (a : α) => decide (p a)
Instances For
PrimrecRel p
means p : α → β → Prop
is a (decidable)
primitive recursive relation, which is to say that
decide ∘ p : α → β → Bool
is primitive recursive.
Equations
- PrimrecRel s = Primrec₂ fun (a : α) (b : β) => decide (s a b)
Instances For
A function is PrimrecBounded
if its size is bounded by a primitive recursive function
Equations
- Primrec.PrimrecBounded f = ∃ (g : α → ℕ), Primrec g ∧ ∀ (x : α), Encodable.encode (f x) ≤ g x
Instances For
To show a function f : α → ℕ
is primitive recursive, it is enough to show that the function
is bounded by a primitive recursive function and that its graph is primitive recursive
Equations
- Primcodable.sum = Primcodable.mk (_ : Nat.Primrec fun (n : ℕ) => Encodable.encode (Encodable.decode n))
Equations
- Primcodable.list = Primcodable.mk (_ : Nat.Primrec fun (n : ℕ) => Encodable.encode (Encodable.decode n))
A subtype of a primitive recursive predicate is Primcodable
.
Equations
- Primcodable.subtype hp = Primcodable.mk (_ : Nat.Primrec fun (n : ℕ) => Encodable.encode (Encodable.decode n))
Instances For
Equations
- Primcodable.fin = Primcodable.ofEquiv { a : ℕ // id a < n } Fin.equivSubtype
Equations
- Primcodable.vector = Primcodable.subtype (_ : PrimrecPred fun (a : List α) => List.length a = n)
Equations
- Primcodable.finArrow = Primcodable.ofEquiv (Vector α n) (Equiv.vectorEquivFin α n).symm
Equations
- Primcodable.ulower = Primcodable.subtype (_ : PrimrecPred fun (n : ℕ) => n ∈ Set.range Encodable.encode)
An alternative inductive definition of Primrec
which
does not use the pairing function on ℕ, and so has to
work with n-ary functions on ℕ instead of unary functions.
We prove that this is equivalent to the regular notion
in to_prim
and of_prim
.
- zero: Nat.Primrec' fun (x : Vector ℕ 0) => 0
- succ: Nat.Primrec' fun (v : Vector ℕ 1) => Nat.succ (Vector.head v)
- get: ∀ {n : ℕ} (i : Fin n), Nat.Primrec' fun (v : Vector ℕ n) => Vector.get v i
- comp: ∀ {m n : ℕ} {f : Vector ℕ n → ℕ} (g : Fin n → Vector ℕ m → ℕ), Nat.Primrec' f → (∀ (i : Fin n), Nat.Primrec' (g i)) → Nat.Primrec' fun (a : Vector ℕ m) => f (Vector.ofFn fun (i : Fin n) => g i a)
- prec: ∀ {n : ℕ} {f : Vector ℕ n → ℕ} {g : Vector ℕ (n + 2) → ℕ}, Nat.Primrec' f → Nat.Primrec' g → Nat.Primrec' fun (v : Vector ℕ (n + 1)) => Nat.rec (f (Vector.tail v)) (fun (y IH : ℕ) => g (y ::ᵥ IH ::ᵥ Vector.tail v)) (Vector.head v)
Instances For
A function from vectors to vectors is primitive recursive when all of its projections are.
Equations
- Nat.Primrec'.Vec f = ∀ (i : Fin m), Nat.Primrec' fun (v : Vector ℕ n) => Vector.get (f v) i