Skip to content

Commit b94f5b4

Browse files
committed
Complete Partrec module: prove prec closure and fix sub_computable (#27)
- Prove URMComputable1.prec: primitive recursion closure for unary functions - Build nested pair composition g_step(a,k,acc) = g(pair(a, pair(k, acc))) - Apply URMComputable.primRec closure theorem - Compose with unpair to get URMComputable 1 - Prove semantic equivalence via induction on recursion depth - Fix sub_computable: replace sorry with monus_computable (identical theorem) This completes Nat.Partrec.toURMComputable1 without any sorries, establishing that every Nat.Partrec function is URM-computable.
1 parent a3efff6 commit b94f5b4

1 file changed

Lines changed: 107 additions & 5 deletions

File tree

Urm/Partrec.lean

Lines changed: 107 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ section Arithmetic
8080

8181
/-- Monus (truncated subtraction) is URM-computable.
8282
sub(x, 0) = x, sub(x, y+1) = pred(sub(x, y)) -/
83-
theorem sub_computable : URMComputable 2 (fun xy => Part.some (xy 0 - xy 1)) := by
84-
sorry
83+
theorem sub_computable : URMComputable 2 (fun xy => Part.some (xy 0 - xy 1)) :=
84+
monus_computable
8585

8686
-- mul_computable is now provided by Urm.Arithmetic
8787

@@ -1167,9 +1167,111 @@ theorem URMComputable1.prec {f g : ℕ →. ℕ}
11671167
(hf : URMComputable1 f) (hg : URMComputable1 g) :
11681168
URMComputable1 (Nat.unpaired fun a n =>
11691169
n.rec (f a) fun y IH => do let i ← IH; g (Nat.pair a (Nat.pair y i))) := by
1170-
-- Adapt: f_base(x) = f(x 0), g_step(x,k,acc) = g(pair(x 0, pair(k, acc)))
1171-
-- Then compose PrFunction with unpair using unpairLeft_computable, unpairRight_computable
1172-
sorry
1170+
unfold URMComputable1 at *
1171+
1172+
-- Step 1: Build nested pair: (Fin 3 → ℕ) → Part ℕ computing pair(x0, pair(x1, x2))
1173+
1174+
-- Inner pair: projects (xka 1, xka 2) then pairs them
1175+
let innerPairGs : Fin 2 → (Fin 3 → ℕ) → Part ℕ := fun i xka =>
1176+
if i.val = 0 then Part.some (xka 1) else Part.some (xka 2)
1177+
have h_innerPairGs : ∀ i, URMComputable 3 (innerPairGs i) := fun i => by
1178+
fin_cases i <;> simp only [innerPairGs, ↓reduceIte,
1179+
Nat.one_ne_zero] <;> exact URMComputable.proj_computable _ _
1180+
have h_innerPair := URMComputable.comp_general (m := 2) (n := 3) pair_computable h_innerPairGs
1181+
1182+
-- Prove the composition equals pair(xka 1, xka 2)
1183+
have h_innerPair_eq : compFunction 2 3 (fun xy => Part.some (Nat.pair (xy 0) (xy 1))) innerPairGs
1184+
= fun xka => Part.some (Nat.pair (xka 1) (xka 2)) := by
1185+
funext xka
1186+
simp only [compFunction, Part.sequence, innerPairGs, Fin.val_zero, ↓reduceIte, Part.bind_some,
1187+
Part.map_some, Fin.cons_zero, Fin.cons_one, Fin.val_succ, Nat.add_one_ne_zero]
1188+
1189+
-- Outer pair: projects (xka 0, innerPair) then pairs them
1190+
let outerPairGs : Fin 2 → (Fin 3 → ℕ) → Part ℕ := fun i xka =>
1191+
if i.val = 0 then Part.some (xka 0)
1192+
else Part.some (Nat.pair (xka 1) (xka 2))
1193+
have h_outerPairGs : ∀ i, URMComputable 3 (outerPairGs i) := fun i => by
1194+
fin_cases i
1195+
· simp only [outerPairGs, ↓reduceIte]
1196+
exact URMComputable.proj_computable _ _
1197+
· simp only [outerPairGs, Nat.one_ne_zero, ↓reduceIte]
1198+
rw [← h_innerPair_eq]
1199+
exact h_innerPair.toComputable
1200+
have h_nestedPair := URMComputable.comp_general (m := 2) (n := 3) pair_computable h_outerPairGs
1201+
1202+
-- Prove the composition equals pair(xka 0, pair(xka 1, xka 2))
1203+
have h_nestedPair_eq : compFunction 2 3 (fun xy => Part.some (Nat.pair (xy 0) (xy 1))) outerPairGs
1204+
= fun xka => Part.some (Nat.pair (xka 0) (Nat.pair (xka 1) (xka 2))) := by
1205+
funext xka
1206+
simp only [compFunction, Part.sequence, outerPairGs, Fin.val_zero, ↓reduceIte, Part.bind_some,
1207+
Part.map_some, Fin.cons_zero, Fin.cons_one, Fin.val_succ, Nat.add_one_ne_zero]
1208+
1209+
-- Step 2: Build g_step = g ∘ nestedPair
1210+
let nestedPairGs : Fin 1 → (Fin 3 → ℕ) → Part ℕ := fun _ xka =>
1211+
Part.some (Nat.pair (xka 0) (Nat.pair (xka 1) (xka 2)))
1212+
have h_nestedPairGs : ∀ i, URMComputable 3 (nestedPairGs i) := fun _ => by
1213+
simp only [nestedPairGs]
1214+
rw [← h_nestedPair_eq]
1215+
exact h_nestedPair.toComputable
1216+
have h_gstep := URMComputable.comp_general (m := 1) (n := 3) hg h_nestedPairGs
1217+
1218+
-- Prove g_step computes g(pair(xka 0, pair(xka 1, xka 2)))
1219+
have h_gstep_eq : compFunction 1 3 (fun x => g (x 0)) nestedPairGs
1220+
= fun xka => g (Nat.pair (xka 0) (Nat.pair (xka 1) (xka 2))) := by
1221+
funext xka
1222+
simp only [compFunction, Part.sequence, nestedPairGs, Part.bind_some, Part.map_some,
1223+
Fin.cons_zero]
1224+
1225+
-- Step 3: Apply primRec
1226+
let g_step : (Fin 3 → ℕ) → Part ℕ := fun xka => g (Nat.pair (xka 0) (Nat.pair (xka 1) (xka 2)))
1227+
have h_gstep_computable : URMComputable 3 g_step := by
1228+
simp only [g_step]
1229+
rw [← h_gstep_eq]
1230+
exact h_gstep.toComputable
1231+
1232+
have h_primRec := URMComputable.primRec (n := 1) hf h_gstep_computable
1233+
1234+
-- Step 4: Compose with unpair to get URMComputable 1
1235+
let unpairGs : Fin 2 → (Fin 1 → ℕ) → Part ℕ := fun i x =>
1236+
if i.val = 0 then Part.some (x 0).unpair.1 else Part.some (x 0).unpair.2
1237+
have h_unpairGs : ∀ i, URMComputable 1 (unpairGs i) := fun i => by
1238+
fin_cases i
1239+
· simp only [unpairGs, ↓reduceIte]; exact unpairLeft_computable
1240+
· simp only [unpairGs, Nat.one_ne_zero, ↓reduceIte]; exact unpairRight_computable
1241+
have h_final := URMComputable.comp_general (m := 2) (n := 1) h_primRec h_unpairGs
1242+
1243+
-- Step 5: Prove semantic equivalence
1244+
convert h_final.toComputable using 1
1245+
funext x
1246+
-- Simplify the compFunction on RHS
1247+
simp only [Nat.unpaired, compFunction, Part.sequence, unpairGs, Fin.val_zero, ↓reduceIte,
1248+
Part.bind_some, Part.map_some, Fin.val_succ, Nat.add_one_ne_zero]
1249+
-- Now RHS is: PrFunction ... (Fin.cons (unpair (x 0)).1 (Fin.cons (unpair (x 0)).2 Fin.elim0))
1250+
1251+
-- Generalize for induction
1252+
set a := (x 0).unpair.1
1253+
set n := (x 0).unpair.2
1254+
1255+
-- Key lemma: PrFunction unfolds as Pr
1256+
simp only [PrFunction, Pr]
1257+
1258+
-- Helper: compute initInputs and lastInput on Fin.cons a (Fin.cons m Fin.elim0)
1259+
have h_init : ∀ m, initInputs (Fin.cons a (Fin.cons m Fin.elim0)) = fun _ : Fin 1 => a := by
1260+
intro m; funext i; fin_cases i; simp [initInputs, Fin.castSucc_zero, Fin.cons_zero]
1261+
have h_last : ∀ m, lastInput (Fin.cons a (Fin.cons m Fin.elim0)) = m := by
1262+
intro m; simp [lastInput, Fin.cons_one, Fin.cons_zero]
1263+
1264+
simp only [h_init, h_last]
1265+
1266+
-- Prove by induction on n
1267+
induction n with
1268+
| zero =>
1269+
-- Both sides reduce to: f a = f ((fun _ => a) 0)
1270+
simp only [Nat.rec_zero]
1271+
| succ n ih =>
1272+
-- Both sides reduce to: (n.rec ...).bind (fun acc => g (pair a (pair n acc)))
1273+
-- The Fin.snoc expressions are definitionally equal: snoc (snoc _ k) acc i = [a,k,acc][i]
1274+
rfl
11731275

11741276
/-- Minimization preserves URMComputable1.
11751277

0 commit comments

Comments
 (0)