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.)
In the above, the pairing function is primitive recursive by definition. This deviates from the textbook definition of primitive recursive functions, which instead work with n-ary functions. We formalize the textbook definition in Nat.Primrec'. Nat.Primrec'.prim_iff then proves it is equivalent to our chosen formulation. For more discussion of this and other design choices in this formalization, see [Car19].
Main definitions #
Nat.Primrec f:fis primitive recursive, for functionsf : ℕ → ℕPrimrec f:fis primitive recursive, for functions betweenPrimcodabletypesPrimcodable α: well-behaved encoding ofαintoℕ, i.e. one such that roundtripping through the encoding functions adds no computational power
References #
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 succ
- left : Nat.Primrec fun (n : ℕ) => (unpair n).1
- right : Nat.Primrec fun (n : ℕ) => (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 (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, essentially, an Encodable type for which the encode/decode functions are primitive recursive. However, such a definition is circular.
Instead, we ask that the composition of decode : ℕ → Option α with encode : Option α → ℕ is primitive recursive. Said composition is the identity function, restricted to the image of encode. Thus, in a way, the added requirement ensures that no predicates can be smuggled in through a cunning choice of the subset of ℕ into which the type is encoded.
- prim : Nat.Primrec fun (n : ℕ) => Encodable.encode (Encodable.decode n)
Instances
Equations
- Primcodable.ofDenumerable α = { toEncodable := inst✝.toEncodable, prim := ⋯ }
Builds a Primcodable instance from an equivalence to a Primcodable type.
Equations
- Primcodable.ofEquiv α e = { toEncodable := Encodable.ofEquiv α e, prim := ⋯ }
Instances For
Equations
- Primcodable.empty = { toEncodable := IsEmpty.toEncodable, prim := Nat.Primrec.zero }
Equations
- Primcodable.unit = { toEncodable := PUnit.encodable, prim := Primcodable.unit._proof_1 }
Equations
- Primcodable.option = { toEncodable := Option.encodable, prim := ⋯ }
Equations
- Primcodable.bool = { toEncodable := Bool.encodable, prim := Primcodable.bool._proof_1 }
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 = { toEncodable := Encodable.Prod.encodable, prim := ⋯ }
Alias of Primrec.list_getElem?₁.
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 primitive recursive predicate, which is to say that decide ∘ p : α → Bool is primitive recursive.
Equations
- PrimrecPred p = ∃ (x : DecidablePred p), Primrec fun (a : α) => decide (p a)
Instances For
PrimrecRel p means p : α → β → Prop is a primitive recursive relation, which is to say that decide ∘ p : α → β → Bool is primitive recursive.
Equations
- PrimrecRel s = PrimrecPred fun (p : α × β) => s p.1 p.2
Instances For
Alias of Primrec.dom_finite.
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 = { toEncodable := Sum.encodable, prim := ⋯ }
Equations
- Primcodable.list = { toEncodable := List.encodable, prim := ⋯ }
Alias of Primrec.list_getElem?.
Filtering a list for elements that satisfy a decidable predicate is primitive recursive.
Checking if any element of a list satisfies a decidable predicate is primitive recursive.
Checking if every element of a list satisfies a decidable predicate is primitive recursive.
Bounded existential quantifiers are primitive recursive.
Bounded universal quantifiers are primitive recursive.
A helper lemma for proofs about bounded quantifiers on decidable relations.
If R a b is decidable, then given L : List α and b : β, it is primitive recursive to filter L for elements a with R a b
If R a b is decidable, then given L : List α and b : β, g L b ↔ ∃ a L, R a b is a primitive recursive relation.
If R a b is decidable, then given L : List α and b : β, g L b ↔ ∀ a L, R a b is a primitive recursive relation.
If R a b is decidable, then for any fixed n and y, g n y ↔ ∃ x < n, R x y is a primitive recursive relation.
If R a b is decidable, then for any fixed n and y, g n y ↔ ∀ x < n, R x y is a primitive recursive relation.
A subtype of a primitive recursive predicate is Primcodable.
Equations
- Primcodable.subtype hp = { toEncodable := Subtype.encodable, prim := ⋯ }
Instances For
Equations
- Primcodable.fin = Primcodable.ofEquiv { a : ℕ // id a < n } Fin.equivSubtype
Equations
Equations
Equations
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 : Primrec' fun (x : List.Vector ℕ 0) => 0
- succ : Primrec' fun (v : List.Vector ℕ 1) => v.head.succ
- get {n : ℕ} (i : Fin n) : Primrec' fun (v : List.Vector ℕ n) => v.get i
- comp {m n : ℕ} {f : List.Vector ℕ n → ℕ} (g : Fin n → List.Vector ℕ m → ℕ) : Primrec' f → (∀ (i : Fin n), Primrec' (g i)) → Primrec' fun (a : List.Vector ℕ m) => f (List.Vector.ofFn fun (i : Fin n) => g i a)
- prec {n : ℕ} {f : List.Vector ℕ n → ℕ} {g : List.Vector ℕ (n + 2) → ℕ} : Primrec' f → Primrec' g → Primrec' fun (v : List.Vector ℕ (n + 1)) => Nat.rec (f v.tail) (fun (y IH : ℕ) => g (y ::ᵥ IH ::ᵥ v.tail)) v.head
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 : List.Vector ℕ n) => (f v).get i