Skip to content

Commit 31dba13

Browse files
committed
feat: make Acc.rec and many related defs computable (#3535)
Lean 4 code generator has had no native supports for `Acc.rec`. This PR makes `Acc.rec` computable. This change makes many defs computable. Especially, computable `PFun.fix` and `Part.hasFix` enables us to reason about `partial` functions. This PR also renames some instances and gives `PFun.lift` `@[coe]` attr.
1 parent c21b166 commit 31dba13

File tree

9 files changed

+30
-49
lines changed

9 files changed

+30
-49
lines changed

Mathlib/Computability/TuringMachine.lean

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -739,8 +739,7 @@ theorem Tape.map_mk₁ {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMap
739739
/-- Run a state transition function `σ → Option σ` "to completion". The return value is the last
740740
state returned before a `none` result. If the state transition function always returns `some`,
741741
then the computation diverges, returning `Part.none`. -/
742-
-- Porting note: Added noncomputable, because `PFun.fix` is noncomputable.
743-
noncomputable def eval {σ} (f : σ → Option σ) : σ → Part σ :=
742+
def eval {σ} (f : σ → Option σ) : σ → Part σ :=
744743
PFun.fix fun s ↦ Part.some <| (f s).elim (Sum.inl s) Sum.inr
745744
#align turing.eval Turing.eval
746745

@@ -826,9 +825,8 @@ theorem Reaches₀.tail' {σ} {f : σ → Option σ} {a b c : σ} (h : Reaches
826825
which is either terminal (meaning `a = b`) or where the next point also satisfies `C`, then it
827826
holds of any point where `eval f a` evaluates to `b`. This formalizes the notion that if
828827
`eval f a` evaluates to `b` then it reaches terminal state `b` in finitely many steps. -/
829-
-- Porting note: Added noncomputable
830828
@[elab_as_elim]
831-
noncomputable def evalInduction {σ} {f : σ → Option σ} {b : σ} {C : σ → Sort _} {a : σ}
829+
def evalInduction {σ} {f : σ → Option σ} {b : σ} {C : σ → Sort _} {a : σ}
832830
(h : b ∈ eval f a) (H : ∀ a, b ∈ eval f a → (∀ a', f a = some a' → C a') → C a) : C a :=
833831
PFun.fixInduction h fun a' ha' h' ↦
834832
H _ ha' fun b' e ↦ h' _ <| Part.mem_some_iff.2 <| by rw [e]; rfl
@@ -1099,8 +1097,7 @@ def init (l : List Γ) : Cfg₀ :=
10991097

11001098
/-- Evaluate a Turing machine on initial input to a final state,
11011099
if it terminates. -/
1102-
-- Porting note: Added noncomputable
1103-
noncomputable def eval (M : Machine₀) (l : List Γ) : Part (ListBlank Γ) :=
1100+
def eval (M : Machine₀) (l : List Γ) : Part (ListBlank Γ) :=
11041101
(Turing.eval (step M) (init l)).map fun c ↦ c.Tape.right₀
11051102
#align turing.TM0.eval Turing.TM0.eval
11061103

@@ -1411,8 +1408,7 @@ def init (l : List Γ) : Cfg₁ :=
14111408

14121409
/-- Evaluate a TM to completion, resulting in an output list on the tape (with an indeterminate
14131410
number of blanks on the end). -/
1414-
-- Porting note: Added noncomputable
1415-
noncomputable def eval (M : Λ → Stmt₁) (l : List Γ) : Part (ListBlank Γ) :=
1411+
def eval (M : Λ → Stmt₁) (l : List Γ) : Part (ListBlank Γ) :=
14161412
(Turing.eval (step M) (init l)).map fun c ↦ c.Tape.right₀
14171413
#align turing.TM1.eval Turing.TM1.eval
14181414

@@ -2279,8 +2275,7 @@ def init (k : K) (L : List (Γ k)) : Cfg₂ :=
22792275
#align turing.TM2.init Turing.TM2.init
22802276

22812277
/-- Evaluates a TM2 program to completion, with the output on the same stack as the input. -/
2282-
-- Porting note: Added noncomputable
2283-
noncomputable def eval (M : Λ → Stmt₂) (k : K) (L : List (Γ k)) : Part (List (Γ k)) :=
2278+
def eval (M : Λ → Stmt₂) (k : K) (L : List (Γ k)) : Part (List (Γ k)) :=
22842279
(Turing.eval (step M) (init k L)).map fun c ↦ c.stk k
22852280
#align turing.TM2.eval Turing.TM2.eval
22862281

Mathlib/Control/Fix.lean

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,7 @@ it satisfies the equations:
6868
1. `fix f = f (fix f)` (is a fixed point)
6969
2. `∀ X, f X ≤ X → fix f ≤ X` (least fixed point)
7070
-/
71-
-- porting note: added noncomputable, because WellFounded.fix is noncomputable (for now?)
72-
protected noncomputable def fix (x : α) : Part (β x) :=
71+
protected def fix (x : α) : Part (β x) :=
7372
(Part.assert (∃ i, (Fix.approx f i x).Dom)) fun h =>
7473
WellFounded.fix.{1} (Nat.Upto.wf h) (fixAux f) Nat.Upto.zero x
7574
#align part.fix Part.fix
@@ -122,18 +121,17 @@ end Part
122121

123122
namespace Part
124123

125-
-- porting note: added noncomputable, because WellFounded.fix is noncomputable (for now?)
126-
noncomputable instance : Fix (Part α) :=
124+
instance hasFix : Fix (Part α) :=
127125
fun f => Part.fix (fun x u => f (x u)) ()⟩
126+
#align part.has_fix Part.hasFix
128127

129128
end Part
130129

131130
open Sigma
132131

133132
namespace Pi
134133

135-
-- porting note: added noncomputable, because WellFounded.fix is noncomputable (for now?)
136-
noncomputable instance Part.hasFix {β} : Fix (α → Part β) :=
134+
instance Part.hasFix {β} : Fix (α → Part β) :=
137135
⟨Part.fix⟩
138136
#align pi.part.has_fix Pi.Part.hasFix
139137

Mathlib/Control/LawfulFix.lean

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,7 @@ theorem to_unit_cont (f : Part α →o Part α) (hc : Continuous f) : Continuous
208208
erw [hc, Chain.map_comp]; rfl
209209
#align part.to_unit_cont Part.to_unit_cont
210210

211-
-- Porting note: `noncomputable` is required because the code generator does not support recursor
212-
-- `Acc.rec` yet.
213-
noncomputable instance lawfulFix : LawfulFix (Part α) :=
211+
instance lawfulFix : LawfulFix (Part α) :=
214212
fun {f : Part α →o Part α} hc ↦ show Part.fix (toUnitMono f) () = _ by
215213
rw [Part.fix_eq (to_unit_cont f hc)]; rfl⟩
216214
#align part.lawful_fix Part.lawfulFix
@@ -221,9 +219,7 @@ open Sigma
221219

222220
namespace Pi
223221

224-
-- Porting note: `noncomputable` is required because the code generator does not support recursor
225-
-- `Acc.rec` yet.
226-
noncomputable instance lawfulFix {β} : LawfulFix (α → Part β) :=
222+
instance lawfulFix {β} : LawfulFix (α → Part β) :=
227223
fun {_f} ↦ Part.fix_eq⟩
228224
#align pi.lawful_fix Pi.lawfulFix
229225

Mathlib/Data/Finset/PImage.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ variable [DecidableEq β] {f g : α →. β} [∀ x, Decidable (f x).Dom] [∀ x
6161
{s t : Finset α} {b : β}
6262

6363
/-- Image of `s : Finset α` under a partially defined function `f : α →. β`. -/
64-
noncomputable def pimage (f : α →. β) [∀ x, Decidable (f x).Dom] (s : Finset α) : Finset β :=
64+
def pimage (f : α →. β) [∀ x, Decidable (f x).Dom] (s : Finset α) : Finset β :=
6565
s.bunionᵢ fun x => (f x).toFinset
6666
#align finset.pimage Finset.pimage
6767

Mathlib/Data/PFun.lean

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,9 @@ namespace PFun
7070

7171
variable {α β γ δ ε ι : Type _}
7272

73-
instance : Inhabited (α →. β) :=
73+
instance inhabited : Inhabited (α →. β) :=
7474
fun _ => Part.none⟩
75+
#align pfun.inhabited PFun.inhabited
7576

7677
/-- The domain of a partial function -/
7778
def Dom (f : α →. β) : Set α :=
@@ -134,11 +135,13 @@ theorem asSubtype_eq_of_mem {f : α →. β} {x : α} {y : β} (fxy : y ∈ f x)
134135
#align pfun.as_subtype_eq_of_mem PFun.asSubtype_eq_of_mem
135136

136137
/-- Turn a total function into a partial function. -/
138+
@[coe]
137139
protected def lift (f : α → β) : α →. β := fun a => Part.some (f a)
138140
#align pfun.lift PFun.lift
139141

140-
instance : Coe (α → β) (α →. β) :=
142+
instance coe : Coe (α → β) (α →. β) :=
141143
⟨PFun.lift⟩
144+
#align pfun.has_coe PFun.coe
142145

143146
@[simp]
144147
theorem coe_val (f : α → β) (a : α) : (f : α →. β) a = Part.some (f a) :=
@@ -219,16 +222,18 @@ theorem bind_apply (f : α →. β) (g : β → α →. γ) (a : α) : f.bind g
219222
def map (f : β → γ) (g : α →. β) : α →. γ := fun a => (g a).map f
220223
#align pfun.map PFun.map
221224

222-
instance : Monad (PFun α) where
225+
instance monad : Monad (PFun α) where
223226
pure := PFun.pure
224227
bind := PFun.bind
225228
map := PFun.map
229+
#align pfun.monad PFun.monad
226230

227-
instance : LawfulMonad (PFun α) := LawfulMonad.mk'
231+
instance lawfulMonad : LawfulMonad (PFun α) := LawfulMonad.mk'
228232
(bind_pure_comp := fun f x => funext fun a => Part.bind_some_eq_map _ _)
229233
(id_map := fun f => by funext a ; dsimp [Functor.map, PFun.map] ; cases f a; rfl)
230234
(pure_bind := fun x f => funext fun a => Part.bind_some _ (f x))
231235
(bind_assoc := fun f g k => funext fun a => (f a).bind_assoc (fun b => g b a) fun b => k b a)
236+
#align pfun.is_lawful_monad PFun.lawfulMonad
232237

233238
theorem pure_defined (p : Set α) (x : β) : p ⊆ (@PFun.pure α _ x).Dom :=
234239
p.subset_univ
@@ -245,8 +250,7 @@ exists. By abusing notation to illustrate, either `f a` is in the `β` part of `
245250
case `f.fix a` returns `f a`), or it is undefined (in which case `f.fix a` is undefined as well), or
246251
it is in the `α` part of `β ⊕ α` (in which case we repeat the procedure, so `f.fix a` will return
247252
`f.fix (f a)`). -/
248-
-- Porting note: had to mark `noncomputable`
249-
noncomputable def fix (f : α →. Sum β α) : α →. β := fun a =>
253+
def fix (f : α →. Sum β α) : α →. β := fun a =>
250254
Part.assert (Acc (fun x y => Sum.inr x ∈ f y) a) $ fun h =>
251255
WellFounded.fixF
252256
(fun a IH =>
@@ -323,9 +327,8 @@ theorem fix_fwd {f : α →. Sum β α} {b : β} {a a' : α} (hb : b ∈ f.fix a
323327
#align pfun.fix_fwd PFun.fix_fwd
324328

325329
/-- A recursion principle for `PFun.fix`. -/
326-
-- Porting note: had to add `noncomputable`
327330
@[elab_as_elim]
328-
noncomputable def fixInduction {C : α → Sort _} {f : α →. Sum β α} {b : β} {a : α} (h : b ∈ f.fix a)
331+
def fixInduction {C : α → Sort _} {f : α →. Sum β α} {b : β} {a : α} (h : b ∈ f.fix a)
329332
(H : ∀ a', b ∈ f.fix a' → (∀ a'', Sum.inr a'' ∈ f a' → C a'') → C a') : C a := by
330333
have h₂ := (Part.mem_assert_iff.1 h).snd;
331334
-- Porting note: revert/intro trick required to address `generalize_proofs` bug
@@ -351,7 +354,7 @@ theorem fixInduction_spec {C : α → Sort _} {f : α →. Sum β α} {b : β} {
351354
`a` given that `f a` inherits `P` from `a` and `P` holds for preimages of `b`.
352355
-/
353356
@[elab_as_elim]
354-
noncomputable def fixInduction' {C : α → Sort _} {f : α →. Sum β α} {b : β} {a : α}
357+
def fixInduction' {C : α → Sort _} {f : α →. Sum β α} {b : β} {a : α}
355358
(h : b ∈ f.fix a) (hbase : ∀ a_final : α, Sum.inl b ∈ f a_final → C a_final)
356359
(hind : ∀ a₀ a₁ : α, b ∈ f.fix a₁ → Sum.inr a₁ ∈ f a₀ → C a₁ → C a₀) : C a := by
357360
refine' fixInduction h fun a' h ih => _

Mathlib/Init/Data/Nat/Lemmas.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ instance linearOrder : LinearOrder ℕ where
3939

4040
protected def strong_rec_on {p : ℕ → Sort u}
4141
(n : ℕ) (H : ∀ n, (∀ m, m < n → p m) → p n) : p n :=
42-
Nat.lt_wfRel.wf.fix' H n
42+
Nat.lt_wfRel.wf.fix H n
4343

4444
@[elab_as_elim]
4545
protected lemma strong_induction_on {p : Nat → Prop} (n : Nat) (h : ∀ n, (∀ m, m < n → p m) → p n) :
@@ -257,7 +257,7 @@ private def wf_lbp : WellFounded (lbp p) := by
257257
| succ m IH => exact IH _ (by rw [Nat.add_right_comm]; exact kn)
258258
/-- Used in the definition of `Nat.find`. Returns the smallest natural satisfying `p`-/
259259
protected def findX : {n // p n ∧ ∀ m, m < n → ¬p m} :=
260-
(wf_lbp H).fix' (C := fun k ↦ (∀n, n < k → ¬p n) → {n // p n ∧ ∀ m, m < n → ¬p m})
260+
(wf_lbp H).fix (C := fun k ↦ (∀n, n < k → ¬p n) → {n // p n ∧ ∀ m, m < n → ¬p m})
261261
(fun m IH al ↦ if pm : p m then ⟨m, pm, al⟩ else
262262
have this : ∀ n, n ≤ m → ¬p n := fun n h ↦
263263
(lt_or_eq_of_le h).elim (al n) fun e ↦ by rw [e]; exact pm

Mathlib/Init/Logic.lean

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Authors: Leonardo de Moura, Jeremy Avigad, Floris van Doorn
66
import Std.Tactic.Ext
77
import Std.Tactic.Lint.Basic
88
import Std.Logic
9+
import Std.WF
910
import Mathlib.Tactic.Alias
1011
import Mathlib.Tactic.Basic
1112
import Mathlib.Tactic.Relation.Rfl
@@ -543,18 +544,6 @@ theorem right_comm : Commutative f → Associative f → RightCommutative f :=
543544

544545
end Binary
545546

546-
namespace WellFounded
547-
548-
variable {α : Sort u} {C : α → Sort v} {r : α → α → Prop}
549-
550-
unsafe def fix'.impl (hwf : WellFounded r) (F : ∀ x, (∀ y, r y x → C y) → C x) (x : α) : C x :=
551-
F x fun y _ ↦ impl hwf F y
552-
553-
@[implemented_by fix'.impl]
554-
def fix' (hwf : WellFounded r) (F : ∀ x, (∀ y, r y x → C y) → C x) (x : α) : C x := hwf.fix F x
555-
556-
end WellFounded
557-
558547
#align not.elim Not.elim
559548
#align not.imp Not.imp
560549
#align not_not_of_not_imp not_not_of_not_imp

Mathlib/Order/GameAdd.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ namespace Prod
122122

123123
/-- Recursion on the well-founded `Prod.GameAdd` relation.
124124
Note that it's strictly more general to recurse on the lexicographic order instead. -/
125-
noncomputable def GameAdd.fix {C : α → β → Sort _} (hα : WellFounded rα) (hβ : WellFounded rβ)
125+
def GameAdd.fix {C : α → β → Sort _} (hα : WellFounded rα) (hβ : WellFounded rβ)
126126
(IH : ∀ a₁ b₁, (∀ a₂ b₂, GameAdd rα rβ (a₂, b₂) (a₁, b₁) → C a₂ b₂) → C a₁ b₁) (a : α) (b : β) :
127127
C a b :=
128128
@WellFounded.fix (α × β) (fun x => C x.1 x.2) _ (hα.prod_gameAdd hβ)
@@ -229,7 +229,7 @@ theorem WellFounded.sym2_gameAdd (h : WellFounded rα) : WellFounded (Sym2.GameA
229229
namespace Sym2
230230

231231
/-- Recursion on the well-founded `Sym2.GameAdd` relation. -/
232-
noncomputable def GameAdd.fix {C : α → α → Sort _} (hr : WellFounded rα)
232+
def GameAdd.fix {C : α → α → Sort _} (hr : WellFounded rα)
233233
(IH : ∀ a₁ b₁, (∀ a₂ b₂, Sym2.GameAdd rα ⟦(a₂, b₂)⟧ ⟦(a₁, b₁)⟧ → C a₂ b₂) → C a₁ b₁) (a b : α) :
234234
C a b :=
235235
@WellFounded.fix (α × α) (fun x => C x.1 x.2) _ hr.sym2_gameAdd.of_quotient_lift₂

lake-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@
1616
{"git":
1717
{"url": "https://github.com/leanprover/std4",
1818
"subDir?": null,
19-
"rev": "1852d720729c4651f251793f0155d8240d28acc2",
19+
"rev": "6006307d2ceb8743fea7e00ba0036af8654d0347",
2020
"name": "std",
2121
"inputRev?": "main"}}]}

0 commit comments

Comments
 (0)