From 8c819b59e1b513a57ea85744b179fbcbc68eae81 Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 09:15:04 -0400 Subject: [PATCH 01/20] =?UTF-8?q?feat(Frontier/TensorNetwork):=20contracti?= =?UTF-8?q?on=20at=20truncation=20order=20=E2=84=93=20by=20evaluation=20an?= =?UTF-8?q?d=20interpolation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correctness half of #1538 milestone E2. Defines the contraction of a described network in B_{P,ℓ} = (ℤ/2^P)[V]/(V^ℓ) (`truncContraction`) and reduces it to contractions over A_P = (ℤ/2^P)[U]/(f) of the network specialized at binary-digit points, followed by Lagrange interpolation (`interpContract`, `interpContract_eq`). No resource bounds yet. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG --- Complexity.lean | 1 + .../Frontier/TensorNetwork/Truncated.lean | 378 ++++++++++++++++++ .../Frontier/TensorNetworkTruncated.lean | 101 +++++ 3 files changed, 480 insertions(+) create mode 100644 Complexity/Computability/Circuit/Frontier/TensorNetwork/Truncated.lean create mode 100644 ComplexityTests/Computability/Circuit/Frontier/TensorNetworkTruncated.lean diff --git a/Complexity.lean b/Complexity.lean index 868496413..cb0573599 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -964,6 +964,7 @@ public import Complexity.Computability.Circuit.Frontier.TensorNetwork.Schedule public import Complexity.Computability.Circuit.Frontier.TensorNetwork.ScheduleCount public import Complexity.Computability.Circuit.Frontier.TensorNetwork.ScheduledRecursion public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TaperedRecovery +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.Truncated public import Complexity.Computability.Circuit.Frontier.TensorNetwork.VertexDesc public import Complexity.Computability.Circuit.Frontier.TwoSidedWitness public import Complexity.Computability.Circuit.Frontier.Unconditional diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/Truncated.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/Truncated.lean new file mode 100644 index 000000000..baaf3b709 --- /dev/null +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/Truncated.lean @@ -0,0 +1,378 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.FastContraction +public import Complexity.Computability.PolyTime.GaloisRingInterpolation +import Complexity.Computability.Circuit.Frontier.TensorNetwork.DescribedLift +import Complexity.Computability.Circuit.Frontier.TensorNetwork.NativeRecovery +import Complexity.Computability.PolyTime.GaloisRingSeries +import Complexity.Foundations.Data.Polynomial.RingLagrange +import Mathlib.Algebra.Polynomial.BigOperators +import Mathlib.Data.List.GetD +import Mathlib.RingTheory.Ideal.Quotient.Operations + +/-! +# Contraction at truncation order `ℓ`, by evaluation and interpolation + +Theorem D.1 of [OpenAI2026ETH] (p. 53) contracts Boolean tensor networks whose entries lie in +`B_{P,ℓ} = (ℤ / 2 ^ P)[V] / (V ^ ℓ)`. This file gives that contraction for described networks +(`DescribedNetwork T`) and reduces it to contractions over `A_P = (ℤ / 2 ^ P)[U] / (f)` of networks +with the same ports, by evaluating `V` at points of `A_P` and interpolating. + +**Entries and the contraction.** An entry is a list of natural numbers, its coefficients of +`1, V, V ^ 2, …` (`coeffPoly`). The contraction over `ℕ[V]` of the entries +(`DescribedNetwork.polyContraction`) has, below `V ^ ℓ` and modulo `2 ^ P`, the coefficients of +the contraction in `B_{P,ℓ}` (`DescribedNetwork.truncContraction`): they depend only on the images +of the entries in `B_{P,ℓ}`, their coefficients below `ℓ` modulo `2 ^ P` +(`DescribedNetwork.truncContraction_congr`). So `truncContraction` is the `B_{P,ℓ}` contraction of +the canonical lifts of the entries, as in §D.4.1 (p. 58). + +**Evaluation.** Cutting the entries to `ℓ` coefficients (`DescribedNetwork.truncContraction_take`) +bounds the degree of the contraction over `ℕ[V]` by `(ℓ - 1) k` for `k` vertices +(`DescribedNetwork.natDegree_polyContraction_le`). The network specialized at a point `ζ` of +`A_P` (`DescribedNetwork.specNet`) has the same ports, and its entry at a vertex is the value at +`ζ` of the first `ℓ` coefficients of the original entry, by Horner's rule (`specEntry`). Its +contraction in `A_P` is the contraction over `ℕ[V]` evaluated at `ζ` +(`DescribedNetwork.val_contraction_specNet`). + +**Interpolation.** At `n` points of `A_P` with unit differences, the Lagrange interpolant of the +values (`GaloisRingArith.interp`) is a polynomial of degree below `n` agreeing with the contraction +at the points. When `(ℓ - 1) k < n` it is the contraction, so the constant coordinates of its first +`ℓ` coefficients, modulo `2 ^ P`, are the truncated contraction (`interpRecover`, +`DescribedNetwork.interpRecover_eq_truncContraction`). The binary digits of `0, …, n - 1` are such +points once `n ≤ 2 ^ deg f` and `f` is irreducible modulo `2` (`isUnit_val_sub_digits`). + +**The reduction** (`DescribedNetwork.interpContract`). Given a contraction `core` over `A_P` of the +specialized networks, contract the network specialized at each of the `(ℓ - 1) k + 1` digit +points and interpolate. If `core` is correct at those inputs, this is the truncated contraction +(`DescribedNetwork.interpContract_eq`). This route is not the manuscript's, which embeds the +entries into `A = O[V] / (V ^ ℓ)` and computes there throughout the recursion (§D.4.1, p. 57, and +the proof of Theorem D.1, §D.4.7, p. 64); it reduces truncation order `ℓ` to `ℓ = 1` over `A_P` +and leaves the recursion unchanged. + +This file proves correctness only. The native machine running the reduction, with the time and +space bounds of Theorem D.1, is not formalized here (#1538). + +## Main definitions + +* `Cslib.Circuits.Frontier.coeffPoly`: the polynomial of a list of coefficients. +* `Cslib.Circuits.Frontier.DescribedNetwork.polyContraction`: the contraction over `ℕ[V]`. +* `Cslib.Circuits.Frontier.DescribedNetwork.truncContraction`: the contraction in `B_{P,ℓ}`. +* `Cslib.Circuits.Frontier.specEntry`, `Cslib.Circuits.Frontier.DescribedNetwork.specNet`: the + network specialized at a point. +* `Cslib.Circuits.Frontier.interpRecover`: reading the truncated contraction off an interpolant. +* `Cslib.Circuits.Frontier.DescribedNetwork.interpContract`: the reduction to `ℓ = 1` over `A_P`. + +## Main results + +* `Cslib.Circuits.Frontier.DescribedNetwork.truncContraction_congr`: the contraction depends only + on the entries in `B_{P,ℓ}`. +* `Cslib.Circuits.Frontier.DescribedNetwork.natDegree_polyContraction_le`: the degree bound. +* `Cslib.Circuits.Frontier.DescribedNetwork.val_contraction_specNet`: specialization is + evaluation. +* `Cslib.Circuits.Frontier.interpRecover_eq`: recovery from values at points with unit + differences. +* `Cslib.Circuits.Frontier.DescribedNetwork.interpRecover_eq_truncContraction`: the truncated + contraction from the specialized contractions. +* `Cslib.Circuits.Frontier.DescribedNetwork.interpContract_eq`: the reduction is correct. + +## References + +* [OpenAI, *The Exponential Time Hypothesis is False*][OpenAI2026ETH], Theorem D.1 (p. 53), + §D.4.1 (pp. 57–58) and §D.4.7 (p. 64). +-/ + +public section + +namespace Cslib.Circuits.Frontier + +open Polynomial Finset GaloisRingArith + +/-! ### Entries as polynomials in `V` -/ + +/-- The polynomial `∑ i, c_i V ^ i` of a list of natural coefficients, constant first. -/ +@[expose] noncomputable def coeffPoly (c : List ℕ) : ℕ[X] := + ∑ i ∈ range c.length, C (c.getD i 0) * X ^ i + +/-- The coefficients of `coeffPoly c` are the entries of `c`, and zero past its end. -/ +@[simp] theorem coeff_coeffPoly (c : List ℕ) (j : ℕ) : (coeffPoly c).coeff j = c.getD j 0 := by + rw [coeffPoly, finsetSum_coeff] + simp only [coeff_C_mul, coeff_X_pow, mul_ite, mul_one, mul_zero, sum_ite_eq, mem_range] + split_ifs with h + · rfl + · rw [List.getD_eq_default _ _ (by omega)] + +/-- `coeffPoly c` has degree below the length of `c`. -/ +theorem natDegree_coeffPoly_le (c : List ℕ) : (coeffPoly c).natDegree ≤ c.length - 1 := + natDegree_le_iff_coeff_eq_zero.mpr fun N hN => by + rw [coeff_coeffPoly, List.getD_eq_default _ _ (by + have : c.length - 1 < N := by exact_mod_cast hN + omega)] + +/-! ### The contraction in `B_{P,ℓ}` -/ + +/-- The map `ℕ[V] → (ℤ / 2 ^ P)[V] / (V ^ ℓ)` onto `B_{P,ℓ}`. -/ +noncomputable def truncHom (P ℓ : ℕ) : + ℕ[X] →+* (ZMod (2 ^ P))[X] ⧸ Ideal.span {(X ^ ℓ : (ZMod (2 ^ P))[X])} := + (Ideal.Quotient.mk _).comp (mapRingHom (Nat.castRingHom (ZMod (2 ^ P)))) + +/-- **Two polynomials have the same image in `B_{P,ℓ}`** exactly when their coefficients below +`ℓ` agree modulo `2 ^ P`. -/ +theorem truncHom_eq_iff {P ℓ : ℕ} {p q : ℕ[X]} : + truncHom P ℓ p = truncHom P ℓ q ↔ ∀ j < ℓ, p.coeff j % 2 ^ P = q.coeff j % 2 ^ P := by + rw [truncHom, RingHom.comp_apply, RingHom.comp_apply, Ideal.Quotient.eq, + Ideal.mem_span_singleton, X_pow_dvd_iff] + refine forall₂_congr fun j _ => ?_ + rw [coeff_sub, sub_eq_zero, coe_mapRingHom, coeff_map, coeff_map] + exact ZMod.natCast_eq_natCast_iff' _ _ _ + +namespace DescribedNetwork + +variable {T : Type*} + +/-- **The contraction over `ℕ[V]`** of a network whose entries are lists of coefficients of +`1, V, V ^ 2, …`. -/ +@[expose] noncomputable def polyContraction (entry : T → List Bool → List ℕ) + (G : DescribedNetwork T) : ℕ[X] := + G.contraction fun t bs => coeffPoly (entry t bs) + +/-- **The contraction in `B_{P,ℓ} = (ℤ / 2 ^ P)[V] / (V ^ ℓ)`**, as its `ℓ` coefficients in +`[0, 2 ^ P)`: the coefficients below `ℓ` of the contraction over `ℕ[V]`, modulo `2 ^ P`. -/ +@[expose] noncomputable def truncContraction (entry : T → List Bool → List ℕ) (P ℓ : ℕ) + (G : DescribedNetwork T) : List ℕ := + (List.range ℓ).map fun j => (G.polyContraction entry).coeff j % 2 ^ P + +/-- The image of the contraction over `ℕ[V]` in `B_{P,ℓ}` is the contraction of the images. -/ +theorem truncHom_polyContraction (entry : T → List Bool → List ℕ) (P ℓ : ℕ) + (G : DescribedNetwork T) : + truncHom P ℓ (G.polyContraction entry) = + G.contraction fun t bs => truncHom P ℓ (coeffPoly (entry t bs)) := + map_contraction _ _ G + +/-- **The contraction depends only on the entries in `B_{P,ℓ}`**: entries whose coefficients +below `ℓ` agree modulo `2 ^ P` have the same truncated contraction. -/ +theorem truncContraction_congr {entry entry' : T → List Bool → List ℕ} {P ℓ : ℕ} + (G : DescribedNetwork T) + (h : ∀ t bs, ∀ i < ℓ, (entry t bs).getD i 0 % 2 ^ P = (entry' t bs).getD i 0 % 2 ^ P) : + G.truncContraction entry P ℓ = G.truncContraction entry' P ℓ := by + have hG : truncHom P ℓ (G.polyContraction entry) = truncHom P ℓ (G.polyContraction entry') := by + rw [truncHom_polyContraction, truncHom_polyContraction] + congr 1 + funext t bs + exact truncHom_eq_iff.mpr fun j hj => by simpa only [coeff_coeffPoly] using h t bs j hj + refine List.map_congr_left fun j hj => truncHom_eq_iff.mp hG j (List.mem_range.mp hj) + +/-- Cutting the entries to their first `ℓ` coefficients does not change the truncated +contraction. -/ +theorem truncContraction_take (entry : T → List Bool → List ℕ) (P ℓ : ℕ) + (G : DescribedNetwork T) : + G.truncContraction (fun t bs => (entry t bs).take ℓ) P ℓ = G.truncContraction entry P ℓ := + truncContraction_congr G fun t bs i hi => by + rw [List.getD_eq_getElem?_getD, List.getD_eq_getElem?_getD, List.getElem?_take_of_lt hi] + +/-- **The degree bound**: if every entry has at most `ℓ` coefficients, the contraction over +`ℕ[V]` has degree at most `(ℓ - 1) k` for `k` vertices. -/ +theorem natDegree_polyContraction_le {entry : T → List Bool → List ℕ} {ℓ : ℕ} + (G : DescribedNetwork T) (h : ∀ t bs, (entry t bs).length ≤ ℓ) : + (G.polyContraction entry).natDegree ≤ (ℓ - 1) * G.vertices.length := by + refine natDegree_sum_le_of_forall_le _ _ fun x _ => (natDegree_list_prod_le _).trans ?_ + rw [List.map_map] + refine (List.sum_le_length_nsmul _ (ℓ - 1) fun d hd => ?_).trans (by simp [mul_comm]) + obtain ⟨v, -, rfl⟩ := List.mem_map.mp hd + exact (natDegree_coeffPoly_le _).trans (Nat.sub_le_sub_right (h _ _) 1) + +end DescribedNetwork + +/-! ### Specialization at a point of `A_P` -/ + +/-- The descriptor of a vertex of a network specialized at a point: the original descriptor with +the precision `P`, the truncation order `ℓ`, the coefficients `fl` of the modulus and the point +`ζ`, a coefficient list of `A_P = (ℤ / 2 ^ P)[U] / (f)`. -/ +abbrev SpecDesc (T : Type*) : Type _ := T × ℕ × ℕ × List ℕ × List ℕ + +/-- The first `ℓ` coefficients of a list, each as a constant coefficient list of `A_P`. -/ +@[expose] def constCoeffs (ℓ : ℕ) (c : List ℕ) : List (List ℕ) := (c.take ℓ).map fun a => [a] + +variable {T : Type*} + +/-- **The entry of a specialized descriptor** `(t, P, ℓ, fl, ζ)`: the value at `ζ` in `A_P`, by +Horner's rule, of the first `ℓ` coefficients of the entry of `t`. -/ +@[expose] def specEntry (entry : T → List Bool → List ℕ) (d : SpecDesc T) (bs : List Bool) : + List ℕ := + peval d.2.1 d.2.2.2.1 (constCoeffs d.2.2.1 (entry d.1 bs)) d.2.2.2.2 + +/-- Constant coefficient lists represent the polynomial of the coefficients in `A_p`. -/ +theorem pval_constCoeffs (p ℓ : ℕ) (fl c : List ℕ) : + pval p fl (constCoeffs ℓ c) = (coeffPoly (c.take ℓ)).map (Nat.castRingHom (Ring p fl)) := by + rw [pval, coeffPoly, Polynomial.map_sum, constCoeffs, List.length_map] + refine sum_congr rfl fun k hk => ?_ + rw [List.getD_eq_getElem _ _ (by simpa using hk), List.getElem_map, val_singleton, + List.getD_eq_getElem _ _ (by simpa using hk)] + simp + +/-- **A specialized entry is the evaluation at the point** of the polynomial of the first `ℓ` +coefficients. -/ +theorem val_specEntry (entry : T → List Bool → List ℕ) (t : T) (P ℓ : ℕ) (fl ζ : List ℕ) + (bs : List Bool) : + val P fl (specEntry entry (t, P, ℓ, fl, ζ) bs) = + ((coeffPoly ((entry t bs).take ℓ)).map (Nat.castRingHom (Ring P fl))).eval (val P fl ζ) := by + rw [specEntry, peval_eq, pval_constCoeffs] + +namespace DescribedNetwork + +/-- **The network specialized at a point `ζ`**: the same ports, with each descriptor `t` +replaced by `(t, P, ℓ, fl, ζ)`. -/ +@[expose] def specNet (P ℓ : ℕ) (fl ζ : List ℕ) (G : DescribedNetwork T) : + DescribedNetwork (SpecDesc T) := + ⟨G.numEdges, G.vertices.map fun v => (v.1, (v.2, P, ℓ, fl, ζ))⟩ + +@[simp] theorem numEdges_specNet (P ℓ : ℕ) (fl ζ : List ℕ) (G : DescribedNetwork T) : + (specNet P ℓ fl ζ G).numEdges = G.numEdges := rfl + +@[simp] theorem vertices_specNet (P ℓ : ℕ) (fl ζ : List ℕ) (G : DescribedNetwork T) : + (specNet P ℓ fl ζ G).vertices = G.vertices.map fun v => (v.1, (v.2, P, ℓ, fl, ζ)) := rfl + +/-- The contraction of a specialized network, for any evaluator, is that of the original network +with the evaluator read at the specialized descriptors. -/ +theorem contraction_specNet {R : Type*} [CommSemiring R] (eval : SpecDesc T → List Bool → R) + (P ℓ : ℕ) (fl ζ : List ℕ) (G : DescribedNetwork T) : + (specNet P ℓ fl ζ G).contraction eval = G.contraction fun t bs => eval (t, P, ℓ, fl, ζ) bs := by + simp only [contraction, vertices_specNet, List.map_map, Function.comp_def] + rfl + +/-- **Specialization is evaluation**: the contraction in `A_P` of the network specialized at `ζ` +is the contraction over `ℕ[V]` of the entries cut to `ℓ` coefficients, evaluated at `ζ`. -/ +theorem val_contraction_specNet (entry : T → List Bool → List ℕ) (P ℓ : ℕ) (fl ζ : List ℕ) + (G : DescribedNetwork T) : + (specNet P ℓ fl ζ G).contraction (fun d bs => val P fl (specEntry entry d bs)) = + ((G.polyContraction fun t bs => (entry t bs).take ℓ).map + (Nat.castRingHom (Ring P fl))).eval (val P fl ζ) := by + rw [contraction_specNet] + have h := map_contraction ((evalRingHom (val P fl ζ)).comp + (mapRingHom (Nat.castRingHom (Ring P fl)))) (fun t bs => coeffPoly ((entry t bs).take ℓ)) G + simp only [RingHom.comp_apply, coe_evalRingHom, coe_mapRingHom] at h + rw [polyContraction, h] + simp only [val_specEntry] + +end DescribedNetwork + +/-! ### Recovery by interpolation -/ + +/-- **Reading the truncated contraction off an interpolant**: interpolate the values `ys` at the +points `pts` and take the constant coordinates, modulo `2 ^ P`, of the first `ℓ` coefficients. -/ +@[expose] def interpRecover (P ℓ : ℕ) (fl : List ℕ) (pts ys : List (List ℕ)) : List ℕ := + (List.range ℓ).map fun j => ((interp P fl pts ys).getD j []).getD 0 0 % 2 ^ P + +/-- An irreducible modulus has positive degree. -/ +theorem length_pos_of_irreducible {fl : List ℕ} + (hirr : Irreducible ((monicOf fl).map (Int.castRingHom (ZMod 2)))) : 0 < fl.length := by + refine Nat.pos_of_ne_zero fun h => hirr.not_isUnit ?_ + simp [monicOf, h] + +/-- **Recovery from values at points with unit differences.** If `Z` over `ℕ` has degree below the +number of points, the points have unit differences in `A_P`, and `ys` are the values of `Z` at +them, then reading off the interpolant gives the coefficients of `Z` below `ℓ` modulo `2 ^ P`. -/ +theorem interpRecover_eq {P ℓ : ℕ} {fl : List ℕ} + (hirr : Irreducible ((monicOf fl).map (Int.castRingHom (ZMod 2)))) {pts ys : List (List ℕ)} + (hunit : Pairwise fun i j : Fin pts.length => + IsUnit (val P fl (pts.getD i []) - val P fl (pts.getD j []))) + {Z : ℕ[X]} (hdeg : Z.natDegree < pts.length) + (hys : ∀ i < pts.length, val P fl (ys.getD i []) = + (Z.map (Nat.castRingHom (Ring P fl))).eval (val P fl (pts.getD i []))) : + interpRecover P ℓ fl pts ys = (List.range ℓ).map fun j => Z.coeff j % 2 ^ P := by + set Z' := Z.map (Nat.castRingHom (Ring P fl)) + set ζ : Fin pts.length → Ring P fl := fun i => val P fl (pts.getD i []) + -- The native interpolant is the interpolant of the values, which is `Z'`. + obtain ⟨g, hg⟩ := NativeRecovery.exists_pval_interp_eq_add hirr (RingHom.id _) ζ hunit pts rfl + (fun _ => rfl) (fun i => val P fl (ys.getD i [])) ys P fun _ => ⟨0, by simp⟩ + have h2 : (2 : Ring P fl) ^ P = 0 := by exact_mod_cast natCast_two_pow (p := P) (fl := fl) + rw [h2, C_0, zero_mul, add_zero, Polynomial.map_id] at hg + have hdeg' : Z'.degree < #(univ : Finset (Fin pts.length)) := by + rw [card_univ, Fintype.card_fin] + exact (degree_map_le.trans degree_le_natDegree).trans_lt (by exact_mod_cast hdeg) + have hZ : Z' = Lagrange.ringInterpolate univ ζ fun i => val P fl (ys.getD i []) := by + conv_lhs => rw [Lagrange.eq_ringInterpolate (fun i _ j _ hij => hunit hij) hdeg'] + congr 1 + funext i + exact (hys i i.2).symm + have hpval : pval P fl (interp P fl pts ys) = Z' := hg.trans hZ.symm + refine List.map_congr_left fun j _ => ?_ + have hval : val P fl ((interp P fl pts ys).getD j []) = val P fl [Z.coeff j] := by + rw [← NativeRecovery.coeff_pval, hpval, val_singleton, coeff_map, eq_natCast] + simpa using mod_eq_of_val_eq hval (length_pos_of_irreducible hirr) + +/-- **The binary digits are interpolation points of `A_P`.** The binary digits below +`e = fl.length` of `0, …, n - 1`, for `n ≤ 2 ^ e` and `f` irreducible modulo `2`, have unit +differences in `A_P`. -/ +theorem isUnit_val_sub_digits {P : ℕ} {fl : List ℕ} + (hirr : Irreducible ((monicOf fl).map (Int.castRingHom (ZMod 2)))) {n : ℕ} + (hn : n ≤ 2 ^ fl.length) : + Pairwise fun i j : Fin ((List.range n).map (FastContraction.digits fl.length)).length => + IsUnit (val P fl (((List.range n).map (FastContraction.digits fl.length)).getD i []) - + val P fl (((List.range n).map (FastContraction.digits fl.length)).getD j [])) := + fun i j hij => by + have h := (pairwise_isUnit_liftO_sub_digits hirr hn hij).map + (AdjoinRoot.reduction (monic_monicOf fl) hirr P) + rwa [map_sub, reduction_liftO, reduction_liftO] at h + +namespace DescribedNetwork + +/-- The number `(ℓ - 1) k + 1` of interpolation points for truncation order `ℓ` and `k` +vertices. -/ +@[expose] def pointCount (ℓ : ℕ) (G : DescribedNetwork T) : ℕ := (ℓ - 1) * G.vertices.length + 1 + +/-- **The truncated contraction from the specialized contractions.** At points with unit +differences in `A_P`, more than `(ℓ - 1) k` of them, if `ys` are the contractions in `A_P` of the +network specialized at the points, reading off the interpolant gives the truncated contraction. -/ +theorem interpRecover_eq_truncContraction {entry : T → List Bool → List ℕ} {P ℓ : ℕ} + {fl : List ℕ} (hirr : Irreducible ((monicOf fl).map (Int.castRingHom (ZMod 2)))) + (G : DescribedNetwork T) {pts ys : List (List ℕ)} + (hunit : Pairwise fun i j : Fin pts.length => + IsUnit (val P fl (pts.getD i []) - val P fl (pts.getD j []))) + (hlen : (ℓ - 1) * G.vertices.length < pts.length) + (hys : ∀ i < pts.length, val P fl (ys.getD i []) = + (specNet P ℓ fl (pts.getD i []) G).contraction fun d bs => val P fl (specEntry entry d bs)) : + interpRecover P ℓ fl pts ys = G.truncContraction entry P ℓ := by + rw [← truncContraction_take] + exact interpRecover_eq hirr hunit + ((natDegree_polyContraction_le G fun _ _ => List.length_take_le _ _).trans_lt hlen) + fun i hi => (hys i hi).trans (val_contraction_specNet entry P ℓ fl _ G) + +/-- **The reduction to `ℓ = 1` over `A_P`**: contract, with `core`, the network specialized at +each of the `(ℓ - 1) k + 1` binary-digit points of `A_P` for the modulus `fl`, and read the +truncated contraction off the interpolant. The input of `core` is the precision, the modulus, the +number `r` of rows and the specialized network. -/ +@[expose] def interpContract (core : ℕ × List ℕ × ℕ × DescribedNetwork (SpecDesc T) → List ℕ) + (fl : List ℕ) (P ℓ r : ℕ) (G : DescribedNetwork T) : List ℕ := + interpRecover P ℓ fl ((List.range (pointCount ℓ G)).map (FastContraction.digits fl.length)) + (((List.range (pointCount ℓ G)).map (FastContraction.digits fl.length)).map fun ζ => + core (P, fl, r, specNet P ℓ fl ζ G)) + +/-- **The reduction is correct.** If `f` is irreducible modulo `2`, `A_P` has at least +`(ℓ - 1) k + 1` residues, and `core` computes the contraction in `A_P` of the network specialized +at each digit point, then `interpContract` is the truncated contraction. -/ +theorem interpContract_eq {entry : T → List Bool → List ℕ} + {core : ℕ × List ℕ × ℕ × DescribedNetwork (SpecDesc T) → List ℕ} {fl : List ℕ} {P ℓ r : ℕ} + (hirr : Irreducible ((monicOf fl).map (Int.castRingHom (ZMod 2)))) + (G : DescribedNetwork T) (hn : pointCount ℓ G ≤ 2 ^ fl.length) + (hcore : ∀ k < pointCount ℓ G, + val P fl (core (P, fl, r, specNet P ℓ fl (FastContraction.digits fl.length k) G)) = + (specNet P ℓ fl (FastContraction.digits fl.length k) G).contraction + fun d bs => val P fl (specEntry entry d bs)) : + interpContract core fl P ℓ r G = G.truncContraction entry P ℓ := by + refine interpRecover_eq_truncContraction hirr G (isUnit_val_sub_digits hirr hn) + (by simp [pointCount]) fun i hi => ?_ + have hi' : i < pointCount ℓ G := by simpa using hi + rw [List.getD_eq_getElem _ _ (by simpa using hi), List.getElem_map, List.getElem_map, + List.getD_eq_getElem _ _ (by simpa using hi), List.getElem_map, List.getElem_range] + exact hcore i hi' + +end DescribedNetwork + +end Cslib.Circuits.Frontier diff --git a/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkTruncated.lean b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkTruncated.lean new file mode 100644 index 000000000..dea650606 --- /dev/null +++ b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkTruncated.lean @@ -0,0 +1,101 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: local-only (test driver) + +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.Truncated +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.FastContractionMachine + +/-! +# Tests for contraction at truncation order `ℓ` + +The networks have one edge between a row and a column, with tables of `V`-coefficient lists. +With row entries `1, V` and column entries `1 + V, 2`, the contraction is `1 + 3 V`; with row +entries `1 + V, 0` and column entries `1 + V, 5`, it is `(1 + V) ^ 2 = 1 + 2 V + V ^ 2`. The +reduction contracts the networks specialized at digit points of `A_3` by direct summation and +interpolates. At a modulus with enough residues it returns the truncated contraction; through +`DescribedNetwork.interpContract_eq` at the irreducible `FastContraction.modulus 1` this computes +`truncContraction`, which is not computable by itself. +-/ + +@[expose] public section + +namespace ComplexityTests.TensorNetworkTruncated + +open Cslib Cslib.Circuits.Frontier Cslib.Circuits.Frontier.DescribedNetwork + +/-- Tables of `V`-coefficient lists, read little-endian. -/ +def entry (table : List (List ℕ)) (bs : List Bool) : List ℕ := + table.getD (BitString.lsbValue bs) [] + +/-- Direct summation in `A_P` of a specialized network. -/ +def direct (x : ℕ × List ℕ × ℕ × DescribedNetwork (SpecDesc (List (List ℕ)))) : List ℕ := + sumValue SumOps.galois (specEntry entry) (x.1, x.2.1) x.2.2.2 + +/-- Row entries `1, V` and column entries `1 + V, 2`: the contraction `1 + 3 V`. -/ +def G₁ : DescribedNetwork (List (List ℕ)) := ⟨1, [([0], [[1], [0, 1]]), ([0], [[1, 1], [2]])]⟩ + +/-- Row entries `1 + V, 0` and column entries `1 + V, 5`: the contraction `1 + 2 V + V ^ 2`. -/ +def G₂ : DescribedNetwork (List (List ℕ)) := ⟨1, [([0], [[1, 1], [0]]), ([0], [[1, 1], [5]])]⟩ + +/-! ### Coefficients -/ + +example : (coeffPoly [3, 5]).coeff 1 = 5 := by simp + +example : (coeffPoly [3, 5]).coeff 7 = 0 := by simp + +example : (coeffPoly [3, 5, 2]).natDegree ≤ 2 := natDegree_coeffPoly_le _ + +/-! ### The reduction, computed -/ + +-- Three points of `A_3 = (ℤ / 8)[U] / (U ^ 2 + U + 1)` recover `1 + 3 V` at `ℓ = 2`. +example : pointCount 2 G₁ = 3 := rfl + +example : interpContract direct [1, 1] 3 2 1 G₁ = [1, 3] := by decide + +-- At `ℓ = 1` only the constant coefficient is kept. +example : interpContract direct [1, 1] 3 1 1 G₁ = [1] := by decide + +-- Five points of `(ℤ / 8)[U] / (U ^ 3 + U + 1)` recover `1 + 2 V + V ^ 2` at `ℓ = 3`, and the +-- entries are cut to `ℓ` coefficients at `ℓ = 2`. +example : interpContract direct [1, 1, 0] 3 3 1 G₂ = [1, 2, 1] := by decide + +example : interpContract direct [1, 1, 0] 3 2 1 G₂ = [1, 2] := by decide + +-- Modulo `2 ^ 1` the coefficients are reduced. +example : interpContract direct [1, 1, 0] 1 3 1 G₂ = [1, 0, 1] := by decide + +/-! ### The truncated contraction, through correctness -/ + +/-- Direct summation in `A_P` is correct on every specialized network. -/ +theorem direct_correct (P : ℕ) (fl : List ℕ) (r : ℕ) + (G : DescribedNetwork (SpecDesc (List (List ℕ)))) : + GaloisRingArith.val P fl (direct (P, fl, r, G)) = + G.contraction fun d bs => GaloisRingArith.val P fl (specEntry entry d bs) := + val_sumValue_galois _ (P, fl) G + +/-- The truncated contraction of `G₁` at `ℓ = 2` modulo `8` is `1 + 3 V`. -/ +example : G₁.truncContraction entry 3 2 = [1, 3] := by + rw [← interpContract_eq (core := direct) (r := 1) (FastContraction.irreducible_modulus 1) G₁ + (by decide) fun k _ => direct_correct _ _ _ _] + decide +kernel + +/-- The truncated contraction of `G₂` at `ℓ = 3` modulo `8` is `1 + 2 V + V ^ 2`. -/ +example : G₂.truncContraction entry 3 3 = [1, 2, 1] := by + rw [← interpContract_eq (core := direct) (r := 1) (FastContraction.irreducible_modulus 1) G₂ + (by decide) fun k _ => direct_correct _ _ _ _] + decide +kernel + +/-- The truncated contraction depends only on the entries in `B_{P,ℓ}`: changing the entries by +multiples of `2 ^ P` and past `V ^ ℓ` does not change it. -/ +example : G₁.truncContraction entry 1 1 = + G₁.truncContraction (fun t bs => (entry t bs).map (· + 2)) 1 1 := + truncContraction_congr G₁ fun t bs i hi => by + obtain rfl : i = 0 := by omega + cases entry t bs <;> simp + +end ComplexityTests.TensorNetworkTruncated From 6559c0287cec7008ad8236957407df8e4839339b Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 09:17:06 -0400 Subject: [PATCH 02/20] refactor(Frontier/TensorNetwork): cut entries by padded lookup instead of take The zero-padded cut `cutCoeffs` is a map over `List.range`, which has a plain polynomial-time rule; `List.take` does not. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG --- .../Frontier/TensorNetwork/Truncated.lean | 48 +++++++++++++------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/Truncated.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/Truncated.lean index baaf3b709..f6c9515e4 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/Truncated.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/Truncated.lean @@ -33,7 +33,8 @@ of the entries in `B_{P,ℓ}`, their coefficients below `ℓ` modulo `2 ^ P` (`DescribedNetwork.truncContraction_congr`). So `truncContraction` is the `B_{P,ℓ}` contraction of the canonical lifts of the entries, as in §D.4.1 (p. 58). -**Evaluation.** Cutting the entries to `ℓ` coefficients (`DescribedNetwork.truncContraction_take`) +**Evaluation.** Cutting the entries to `ℓ` coefficients (`cutCoeffs`, +`DescribedNetwork.truncContraction_cutCoeffs`) bounds the degree of the contraction over `ℕ[V]` by `(ℓ - 1) k` for `k` vertices (`DescribedNetwork.natDegree_polyContraction_le`). The network specialized at a point `ζ` of `A_P` (`DescribedNetwork.specNet`) has the same ports, and its entry at a vertex is the value at @@ -62,6 +63,7 @@ space bounds of Theorem D.1, is not formalized here (#1538). ## Main definitions * `Cslib.Circuits.Frontier.coeffPoly`: the polynomial of a list of coefficients. +* `Cslib.Circuits.Frontier.cutCoeffs`: the first `ℓ` coefficients. * `Cslib.Circuits.Frontier.DescribedNetwork.polyContraction`: the contraction over `ℕ[V]`. * `Cslib.Circuits.Frontier.DescribedNetwork.truncContraction`: the contraction in `B_{P,ℓ}`. * `Cslib.Circuits.Frontier.specEntry`, `Cslib.Circuits.Frontier.DescribedNetwork.specNet`: the @@ -115,6 +117,18 @@ theorem natDegree_coeffPoly_le (c : List ℕ) : (coeffPoly c).natDegree ≤ c.le have : c.length - 1 < N := by exact_mod_cast hN omega)] +/-- The first `ℓ` coefficients of a list, padded with zeros to length `ℓ`. -/ +@[expose] def cutCoeffs (ℓ : ℕ) (c : List ℕ) : List ℕ := (List.range ℓ).map fun i => c.getD i 0 + +@[simp] theorem length_cutCoeffs (ℓ : ℕ) (c : List ℕ) : (cutCoeffs ℓ c).length = ℓ := by + simp [cutCoeffs] + +/-- Below `ℓ`, the cut list has the coefficients of the list. -/ +theorem getD_cutCoeffs (c : List ℕ) {ℓ i : ℕ} (hi : i < ℓ) : + (cutCoeffs ℓ c).getD i 0 = c.getD i 0 := by + rw [cutCoeffs, List.getD_eq_getElem _ _ (by simpa using hi), List.getElem_map, + List.getElem_range] + /-! ### The contraction in `B_{P,ℓ}` -/ /-- The map `ℕ[V] → (ℤ / 2 ^ P)[V] / (V ^ ℓ)` onto `B_{P,ℓ}`. -/ @@ -170,11 +184,10 @@ theorem truncContraction_congr {entry entry' : T → List Bool → List ℕ} {P /-- Cutting the entries to their first `ℓ` coefficients does not change the truncated contraction. -/ -theorem truncContraction_take (entry : T → List Bool → List ℕ) (P ℓ : ℕ) +theorem truncContraction_cutCoeffs (entry : T → List Bool → List ℕ) (P ℓ : ℕ) (G : DescribedNetwork T) : - G.truncContraction (fun t bs => (entry t bs).take ℓ) P ℓ = G.truncContraction entry P ℓ := - truncContraction_congr G fun t bs i hi => by - rw [List.getD_eq_getElem?_getD, List.getD_eq_getElem?_getD, List.getElem?_take_of_lt hi] + G.truncContraction (fun t bs => cutCoeffs ℓ (entry t bs)) P ℓ = G.truncContraction entry P ℓ := + truncContraction_congr G fun t bs i hi => by rw [getD_cutCoeffs _ hi] /-- **The degree bound**: if every entry has at most `ℓ` coefficients, the contraction over `ℕ[V]` has degree at most `(ℓ - 1) k` for `k` vertices. -/ @@ -197,7 +210,8 @@ the precision `P`, the truncation order `ℓ`, the coefficients `fl` of the modu abbrev SpecDesc (T : Type*) : Type _ := T × ℕ × ℕ × List ℕ × List ℕ /-- The first `ℓ` coefficients of a list, each as a constant coefficient list of `A_P`. -/ -@[expose] def constCoeffs (ℓ : ℕ) (c : List ℕ) : List (List ℕ) := (c.take ℓ).map fun a => [a] +@[expose] def constCoeffs (ℓ : ℕ) (c : List ℕ) : List (List ℕ) := + (List.range ℓ).map fun i => [c.getD i 0] variable {T : Type*} @@ -209,11 +223,13 @@ Horner's rule, of the first `ℓ` coefficients of the entry of `t`. -/ /-- Constant coefficient lists represent the polynomial of the coefficients in `A_p`. -/ theorem pval_constCoeffs (p ℓ : ℕ) (fl c : List ℕ) : - pval p fl (constCoeffs ℓ c) = (coeffPoly (c.take ℓ)).map (Nat.castRingHom (Ring p fl)) := by - rw [pval, coeffPoly, Polynomial.map_sum, constCoeffs, List.length_map] + pval p fl (constCoeffs ℓ c) = + (coeffPoly (cutCoeffs ℓ c)).map (Nat.castRingHom (Ring p fl)) := by + rw [pval, coeffPoly, Polynomial.map_sum, constCoeffs, List.length_map, length_cutCoeffs, + List.length_range] refine sum_congr rfl fun k hk => ?_ - rw [List.getD_eq_getElem _ _ (by simpa using hk), List.getElem_map, val_singleton, - List.getD_eq_getElem _ _ (by simpa using hk)] + rw [List.getD_eq_getElem _ _ (by simpa using hk), List.getElem_map, List.getElem_range, + val_singleton, getD_cutCoeffs _ (mem_range.mp hk)] simp /-- **A specialized entry is the evaluation at the point** of the polynomial of the first `ℓ` @@ -221,7 +237,8 @@ coefficients. -/ theorem val_specEntry (entry : T → List Bool → List ℕ) (t : T) (P ℓ : ℕ) (fl ζ : List ℕ) (bs : List Bool) : val P fl (specEntry entry (t, P, ℓ, fl, ζ) bs) = - ((coeffPoly ((entry t bs).take ℓ)).map (Nat.castRingHom (Ring P fl))).eval (val P fl ζ) := by + ((coeffPoly (cutCoeffs ℓ (entry t bs))).map (Nat.castRingHom (Ring P fl))).eval + (val P fl ζ) := by rw [specEntry, peval_eq, pval_constCoeffs] namespace DescribedNetwork @@ -251,11 +268,12 @@ is the contraction over `ℕ[V]` of the entries cut to `ℓ` coefficients, evalu theorem val_contraction_specNet (entry : T → List Bool → List ℕ) (P ℓ : ℕ) (fl ζ : List ℕ) (G : DescribedNetwork T) : (specNet P ℓ fl ζ G).contraction (fun d bs => val P fl (specEntry entry d bs)) = - ((G.polyContraction fun t bs => (entry t bs).take ℓ).map + ((G.polyContraction fun t bs => cutCoeffs ℓ (entry t bs)).map (Nat.castRingHom (Ring P fl))).eval (val P fl ζ) := by rw [contraction_specNet] have h := map_contraction ((evalRingHom (val P fl ζ)).comp - (mapRingHom (Nat.castRingHom (Ring P fl)))) (fun t bs => coeffPoly ((entry t bs).take ℓ)) G + (mapRingHom (Nat.castRingHom (Ring P fl)))) (fun t bs => coeffPoly (cutCoeffs ℓ (entry t bs))) + G simp only [RingHom.comp_apply, coe_evalRingHom, coe_mapRingHom] at h rw [polyContraction, h] simp only [val_specEntry] @@ -339,9 +357,9 @@ theorem interpRecover_eq_truncContraction {entry : T → List Bool → List ℕ} (hys : ∀ i < pts.length, val P fl (ys.getD i []) = (specNet P ℓ fl (pts.getD i []) G).contraction fun d bs => val P fl (specEntry entry d bs)) : interpRecover P ℓ fl pts ys = G.truncContraction entry P ℓ := by - rw [← truncContraction_take] + rw [← truncContraction_cutCoeffs] exact interpRecover_eq hirr hunit - ((natDegree_polyContraction_le G fun _ _ => List.length_take_le _ _).trans_lt hlen) + ((natDegree_polyContraction_le G fun _ _ => (length_cutCoeffs _ _).le).trans_lt hlen) fun i hi => (hys i hi).trans (val_contraction_specNet entry P ℓ fl _ G) /-- **The reduction to `ℓ = 1` over `A_P`**: contract, with `core`, the network specialized at From 3015e73fb255fa58fe0f227aac71da71d970994c Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 09:26:07 -0400 Subject: [PATCH 03/20] feat(Frontier/TensorNetwork): native machine for the truncation-order reduction Stacked on the correctness layer (#2037), for #1538 milestone E2. `engineCertificate` runs `interpContract` as one native machine around any certificate of a contraction over A_P, streaming over the digit points with `IndexFold`. `truncDirectCertificate` instantiates it with direct summation at `FastContraction.modulus n`, a native machine for `truncContraction` on every input. No time or space bound of the loop yet. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG --- Complexity.lean | 1 + .../TensorNetwork/TruncatedPolyTime.lean | 467 ++++++++++++++++++ .../TensorNetworkTruncatedPolyTime.lean | 56 +++ 3 files changed, 524 insertions(+) create mode 100644 Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedPolyTime.lean create mode 100644 ComplexityTests/Computability/Circuit/Frontier/TensorNetworkTruncatedPolyTime.lean diff --git a/Complexity.lean b/Complexity.lean index cb0573599..2a5954850 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -965,6 +965,7 @@ public import Complexity.Computability.Circuit.Frontier.TensorNetwork.ScheduleCo public import Complexity.Computability.Circuit.Frontier.TensorNetwork.ScheduledRecursion public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TaperedRecovery public import Complexity.Computability.Circuit.Frontier.TensorNetwork.Truncated +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TruncatedPolyTime public import Complexity.Computability.Circuit.Frontier.TensorNetwork.VertexDesc public import Complexity.Computability.Circuit.Frontier.TwoSidedWitness public import Complexity.Computability.Circuit.Frontier.Unconditional diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedPolyTime.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedPolyTime.lean new file mode 100644 index 000000000..be28c99b3 --- /dev/null +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedPolyTime.lean @@ -0,0 +1,467 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.Truncated +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.DescribedContraction +public import Complexity.Computability.GenericRAM.Native.IndexFold +import Complexity.Computability.Circuit.Frontier.TensorNetwork.FastContractionPolyTime +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.FastContractionSchedule +import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimeListMap +import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimeListPrimitives +import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimeNatFrontends +import Complexity.Computability.Machines.Turing.MultiTape.Complexity.PolyTime.List +import Complexity.Computability.Machines.Turing.MultiTape.Complexity.PolyTime.Nat + +/-! +# The reduction of truncation order `ℓ` as a native machine + +The reduction of `Complexity/Computability/Circuit/Frontier/TensorNetwork/Truncated.lean` +(`Cslib.Circuits.Frontier.DescribedNetwork.interpContract`) contracts specialized networks over +`A_P = (ℤ / 2 ^ P)[U] / (f)` and interpolates. This file runs it as one native machine around any +native certificate of the contraction over `A_P` (`engineCertificate`), with the precision `P` and +the truncation order `ℓ` in unary. + +**Polynomial-time steps.** Specializing a network at a point (`DescribedNetwork.specNet_polyTime`), +the binary-digit points (`DescribedNetwork.digitPoints_polyTime`), the inputs of the contractions +(`coreInput_polyTime`) and reading the truncated contraction off the interpolant +(`interpRecover_polyTime`, `engineRecover_polyTime`) are polynomial-time. + +**The loop.** The machine visits the digit points with the binary-index fold +`Cslib.GenericRAM.IndexFold`, keeping the index, the input and the values so far; each round +calls the given certificate once (`engineStep`, `engineStepCertificate`, `run_engineStep`). Then it +interpolates. + +**Direct summation.** A native certificate of the entries gives one of the specialized entries +(`specEntryCertificate`: the entry, then Horner's rule), hence direct summation over `A_P` of a +specialized network (`directCoreCertificate`). Through the reduction at the modulus +`FastContraction.modulus n` for `n = (ℓ - 1) k + 1` points, which has enough residues +(`le_two_pow_length_modulus`), this computes the truncated contraction on every input +(`truncDirectCertificate`). Its cost is that of direct summation. + +No time or space bound of the loop is proved here. With the contraction of Theorem D.1 at `ℓ = 1` +over `A_P` in place of direct summation, a bound of the loop gives Theorem D.1 at truncation order +`ℓ` (#1538). + +## Main definitions + +* `Cslib.Circuits.Frontier.encSpecDesc`, `Cslib.Circuits.Frontier.encTrunc`, + `Cslib.Circuits.Frontier.encCore`, `Cslib.Circuits.Frontier.encEngine`: encodings. +* `Cslib.Circuits.Frontier.specEntryCertificate`: the native evaluator of specialized entries. +* `Cslib.Circuits.Frontier.engineCertificate`: the reduction around a contraction over `A_P`. +* `Cslib.Circuits.Frontier.directCoreCertificate`: direct summation over `A_P`. +* `Cslib.Circuits.Frontier.truncDirectCertificate`: the truncated contraction by direct summation. + +## Main results + +* `Cslib.Circuits.Frontier.DescribedNetwork.specNet_polyTime`, + `Cslib.Circuits.Frontier.interpRecover_polyTime`: polynomial-time steps. +* `Cslib.Circuits.Frontier.run_engineStep`, `Cslib.Circuits.Frontier.interpContract_eq_run`: the + loop computes the reduction. +* `Cslib.Circuits.Frontier.interpContract_direct_eq`: direct summation through the reduction is + the truncated contraction. + +## References + +* [OpenAI, *The Exponential Time Hypothesis is False*][OpenAI2026ETH], Theorem D.1 (p. 53). +-/ + +public section + +namespace Cslib.Circuits.Frontier + +open Turing.MultiTapeTM Cslib.GenericRAM GaloisRingArith + +variable {T : Type} (encT : T ↪ List Bool) + +/-- The encoding of the data `(P, ℓ, fl, ζ)` of a specialization: `P` and `ℓ` in unary, the +coefficients of the modulus and the point in binary. -/ +abbrev encSpecData : ℕ × ℕ × List ℕ × List ℕ ↪ List Bool := + encPair encUnary (encPair encUnary (encPair (encList encNat) (encList encNat))) + +/-- The encoding of a specialized descriptor: the original descriptor, then the data of the +specialization. -/ +abbrev encSpecDesc : SpecDesc T ↪ List Bool := encPair encT encSpecData + +variable {encT} + +/-- The first `ℓ` coefficients as constant coefficient lists, from `ℓ` in unary. -/ +theorem constCoeffs_polyTime : + ComputableInPolyTime (fun q : ℕ × List ℕ => constCoeffs q.1 q.2) + (encPair encUnary (encList encNat)) (encList (encList encNat)) := by + have hc : ComputableInPolyTime (fun q : (ℕ × List ℕ) × ℕ => q.1.2) + (encPair (encPair encUnary (encList encNat)) encUnary) (encList encNat) := + (ComputableInPolyTime.snd _ _).comp (ComputableInPolyTime.fst _ _) + have hget := computableInPolyTime_getD hc (ComputableInPolyTime.snd _ _) + exact ComputableInPolyTime.mapWithInput + (ComputableInPolyTime.range.comp (ComputableInPolyTime.fst _ _)) + (ComputableInPolyTime.cons' hget (ComputableInPolyTime.const [])) + +/-- **Horner's rule on the first `ℓ` coefficients**, from the data of a specialization and a +coefficient list, with `P` and `ℓ` in unary. -/ +theorem horner_polyTime : + ComputableInPolyTime + (fun q : (ℕ × ℕ × List ℕ × List ℕ) × List ℕ => + peval q.1.1 q.1.2.2.1 (constCoeffs q.1.2.1 q.2) q.1.2.2.2) + (encPair encSpecData (encList encNat)) (encList encNat) := by + have hd := ComputableInPolyTime.fst encSpecData (encList encNat) + have hc := ComputableInPolyTime.snd encSpecData (encList encNat) + have hP := (ComputableInPolyTime.fst _ _).comp hd + have hrest := (ComputableInPolyTime.snd _ _).comp hd + have hℓ := (ComputableInPolyTime.fst _ _).comp hrest + have hfz := (ComputableInPolyTime.snd _ _).comp hrest + have hfl := (ComputableInPolyTime.fst _ _).comp hfz + have hz := (ComputableInPolyTime.snd _ _).comp hfz + exact computableInPolyTime_peval hP hfl (constCoeffs_polyTime.comp (hℓ.prod hc)) hz + +variable (entry : T → List Bool → List ℕ) + +/-- **The native evaluator of specialized entries**, from a native certificate of the entries: +evaluate the original entry, then apply Horner's rule in `A_P`. -/ +noncomputable def specEntryCertificate + (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) : + NativeCertificate (fun q : SpecDesc T × List Bool => specEntry entry q.1 q.2) + (encPair (encSpecDesc encT) encBits) (encList encNat) := + ((NativeCertificate.ofPolyTime horner_polyTime).comp + ((NativeCertificate.ofPolyTime + ((ComputableInPolyTime.snd _ _).comp (ComputableInPolyTime.fst _ _))).prod + (ce.comp (NativeCertificate.ofPolyTime + ((((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.fst _ _))).prod + (ComputableInPolyTime.snd _ _)))))).congr fun _ => rfl + +namespace DescribedNetwork + +/-- **Specializing is polynomial-time**: from the data `(P, ℓ, fl, ζ)` and the network to the +specialized network. -/ +theorem specNet_polyTime : + ComputableInPolyTime + (fun q : (ℕ × ℕ × List ℕ × List ℕ) × DescribedNetwork T => + specNet q.1.1 q.1.2.1 q.1.2.2.1 q.1.2.2.2 q.2) + (encPair encSpecData (encDescribed encT)) (encDescribed (encSpecDesc encT)) := by + have hG := ComputableInPolyTime.snd encSpecData (encDescribed encT) + have hd := ComputableInPolyTime.fst encSpecData (encDescribed encT) + have hv : ComputableInPolyTime + (fun q : ((ℕ × ℕ × List ℕ × List ℕ) × DescribedNetwork T) × (List ℕ × T) => + (q.2.1, (q.2.2, q.1.1))) + (encPair (encPair encSpecData (encDescribed encT)) (encPair (encList encNat) encT)) + (encPair (encList encNat) (encSpecDesc encT)) := + ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _)).prod + (((ComputableInPolyTime.snd _ _).comp (ComputableInPolyTime.snd _ _)).prod + ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.fst _ _))) + have hpair : ComputableInPolyTime + (fun q : (ℕ × ℕ × List ℕ × List ℕ) × DescribedNetwork T => + (q.2.numEdges, q.2.vertices.map fun v => (v.1, (v.2, q.1)))) + (encPair encSpecData (encDescribed encT)) + (encPair encUnary (encList (encPair (encList encNat) (encSpecDesc encT)))) := + (numEdges_polyTime.comp hG).prod + (ComputableInPolyTime.mapWithInput (vertices_polyTime.comp hG) hv) + exact (ComputableInPolyTime.of_eq (encIn := encPair encUnary + (encList (encPair (encList encNat) (encSpecDesc encT)))) + (f := fun p : ℕ × List (List ℕ × SpecDesc T) => (⟨p.1, p.2⟩ : DescribedNetwork (SpecDesc T))) + fun _ => rfl).comp hpair + +/-- **The binary-digit points are polynomial-time**, from the number of coordinates and the +number of points in unary. -/ +theorem digitPoints_polyTime : + ComputableInPolyTime + (fun q : ℕ × ℕ => (List.range q.2).map (FastContraction.digits q.1)) + (encPair encUnary encUnary) (encList (encList encNat)) := + ComputableInPolyTime.mapWithInput + (ComputableInPolyTime.range.comp (ComputableInPolyTime.snd _ _)) + (FastContraction.digits_polyTime.comp + (((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.fst _ _)).prod + (ComputableInPolyTime.snd _ _))) + +end DescribedNetwork + +/-- **Reading off the interpolant is polynomial-time**, with `P` and `ℓ` in unary. -/ +theorem interpRecover_polyTime : + ComputableInPolyTime + (fun q : ℕ × ℕ × List ℕ × List (List ℕ) × List (List ℕ) => + interpRecover q.1 q.2.1 q.2.2.1 q.2.2.2.1 q.2.2.2.2) + (encPair encUnary (encPair encUnary (encPair (encList encNat) + (encPair (encList (encList encNat)) (encList (encList encNat)))))) + (encList encNat) := by + let encQ := encPair encUnary (encPair encUnary (encPair (encList encNat) + (encPair (encList (encList encNat)) (encList (encList encNat))))) + have hP := ComputableInPolyTime.fst encUnary (encPair encUnary (encPair (encList encNat) + (encPair (encList (encList encNat)) (encList (encList encNat))))) + have hr := ComputableInPolyTime.snd encUnary (encPair encUnary (encPair (encList encNat) + (encPair (encList (encList encNat)) (encList (encList encNat))))) + have hℓ := (ComputableInPolyTime.fst _ _).comp hr + have hr' := (ComputableInPolyTime.snd _ _).comp hr + have hfl := (ComputableInPolyTime.fst _ _).comp hr' + have hr'' := (ComputableInPolyTime.snd _ _).comp hr' + have hpts := (ComputableInPolyTime.fst _ _).comp hr'' + have hys := (ComputableInPolyTime.snd _ _).comp hr'' + have hI := computableInPolyTime_interp hP hfl hpts hys + have hq : ComputableInPolyTime + (fun q : (ℕ × ℕ × List ℕ × List (List ℕ) × List (List ℕ)) × ℕ => + ((interp q.1.1 q.1.2.2.1 q.1.2.2.2.1 q.1.2.2.2.2).getD q.2 []).getD 0 0 % 2 ^ q.1.1) + (encPair encQ encUnary) encNat := by + have h1 := ComputableInPolyTime.fst encQ encUnary + have hrow := (ComputableInPolyTime.listGetD (encA := encList encNat) []).comp + ((hI.comp h1).prod (ComputableInPolyTime.snd encQ encUnary)) + exact computableInPolyTime_mod_two_pow + (computableInPolyTime_getD hrow (ComputableInPolyTime.const 0)) (hP.comp h1) + exact ComputableInPolyTime.mapWithInput (ComputableInPolyTime.range.comp hℓ) hq + +/-! ### The reduction as a streaming loop -/ + +/-- The encoding of an input `(P, ℓ, r, G)` of the truncated contraction: `P` and `ℓ` in unary, +`r` in binary, then the network. -/ +abbrev encTrunc (encT : T ↪ List Bool) : ℕ × ℕ × ℕ × DescribedNetwork T ↪ List Bool := + encPair encUnary (encPair encUnary (encPair encNat (DescribedNetwork.encDescribed encT))) + +/-- The encoding of an input `(P, fl, r, G')` of a contraction over `A_P` of specialized +networks: `P` in unary, the modulus, `r` in binary, then the specialized network. -/ +abbrev encCore (encT : T ↪ List Bool) : + ℕ × List ℕ × ℕ × DescribedNetwork (SpecDesc T) ↪ List Bool := + encPair encUnary (encPair (encList encNat) + (encPair encNat (DescribedNetwork.encDescribed (encSpecDesc encT)))) + +/-- The input of the reduction: the modulus and the input `(P, ℓ, r, G)`. -/ +abbrev encEngine (encT : T ↪ List Bool) : List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T ↪ List Bool := + encPair (encList encNat) (encTrunc encT) + +/-- The input of the contraction at the `k`-th digit point, for a modulus `y.1` and an input +`y.2 = (P, ℓ, r, G)`. -/ +@[expose] def coreInput (y : List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T) (k : ℕ) : + ℕ × List ℕ × ℕ × DescribedNetwork (SpecDesc T) := + (y.2.1, y.1, y.2.2.2.1, + DescribedNetwork.specNet y.2.1 y.2.2.1 y.1 (FastContraction.digits y.1.length k) y.2.2.2.2) + +variable (core : ℕ × List ℕ × ℕ × DescribedNetwork (SpecDesc T) → List ℕ) + +/-- **One round of the reduction** at the index `p.1`: append the contraction at the `p.1`-th digit +point to the values so far. -/ +@[expose] def engineStep + (p : ℕ × ((List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T) × List (List ℕ))) : + (List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T) × List (List ℕ) := + (p.2.1, p.2.2 ++ [core (coreInput p.2.1 p.1)]) + +/-- After `j` rounds, the values are the contractions at the first `j` digit points. -/ +theorem run_engineStep (y : List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T) (j : ℕ) : + IndexFold.run (engineStep core) j (y, []) = + (j, (y, (List.range j).map fun k => core (coreInput y k))) := by + induction j with + | zero => rfl + | succ j ih => + rw [IndexFold.run_succ, ih] + simp only [IndexFold.step, engineStep, List.range_succ, List.map_append, List.map_cons, + List.map_nil] + +/-- **The reduction is the streaming loop followed by recovery.** -/ +theorem interpContract_eq_run (y : List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T) : + DescribedNetwork.interpContract core y.1 y.2.1 y.2.2.1 y.2.2.2.1 y.2.2.2.2 = + interpRecover y.2.1 y.2.2.1 y.1 + ((List.range (DescribedNetwork.pointCount y.2.2.1 y.2.2.2.2)).map + (FastContraction.digits y.1.length)) + (IndexFold.run (engineStep core) (DescribedNetwork.pointCount y.2.2.1 y.2.2.2.2) + (y, [])).2.2 := by + rw [run_engineStep, DescribedNetwork.interpContract, List.map_map] + rfl + +/-- The binary digits are polynomial-time from the number in binary. -/ +theorem digits_polyTime_binary : + ComputableInPolyTime (fun q : ℕ × ℕ => FastContraction.digits q.1 q.2) + (encPair encUnary encNat) (encList encNat) := + ComputableInPolyTime.mapWithInput + (ComputableInPolyTime.range.comp (ComputableInPolyTime.fst _ _)) + (ComputableInPolyTime.ite (encMid := encNat) + (ComputableInPolyTime.binary_testBit + ((ComputableInPolyTime.snd _ _).comp (ComputableInPolyTime.fst _ _)) + (ComputableInPolyTime.snd _ _)) + (ComputableInPolyTime.const 1) (ComputableInPolyTime.const 0)) + +/-- The number of points is polynomial-time, in unary. -/ +theorem pointCount_polyTime : + ComputableInPolyTime (fun y : List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T => + DescribedNetwork.pointCount y.2.2.1 y.2.2.2.2) (encEngine encT) encUnary := by + have hx := ComputableInPolyTime.snd (encList encNat) (encTrunc encT) + have hℓ := (ComputableInPolyTime.fst _ _).comp ((ComputableInPolyTime.snd _ _).comp hx) + have hG := (ComputableInPolyTime.snd _ _).comp ((ComputableInPolyTime.snd _ _).comp + ((ComputableInPolyTime.snd _ _).comp hx)) + have hk := (ComputableInPolyTime.length_list _).comp + (DescribedNetwork.vertices_polyTime.comp hG) + exact ComputableInPolyTime.unary_add' + (ComputableInPolyTime.unary_mul' (ComputableInPolyTime.unary_sub' hℓ + (ComputableInPolyTime.const 1)) hk) (ComputableInPolyTime.const 1) + +/-- The input of the contraction at a binary index is polynomial-time. -/ +theorem coreInput_polyTime : + ComputableInPolyTime + (fun p : ℕ × ((List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T) × List (List ℕ)) => + coreInput p.2.1 p.1) + (encPair encNat (encPair (encEngine encT) (encList (encList encNat)))) (encCore encT) := by + have hy := (ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd encNat + (encPair (encEngine encT) (encList (encList encNat)))) + have hk := ComputableInPolyTime.fst encNat (encPair (encEngine encT) (encList (encList encNat))) + have hfl := (ComputableInPolyTime.fst _ _).comp hy + have hx := (ComputableInPolyTime.snd _ _).comp hy + have hP := (ComputableInPolyTime.fst _ _).comp hx + have hx' := (ComputableInPolyTime.snd _ _).comp hx + have hℓ := (ComputableInPolyTime.fst _ _).comp hx' + have hx'' := (ComputableInPolyTime.snd _ _).comp hx' + have hr := (ComputableInPolyTime.fst _ _).comp hx'' + have hG := (ComputableInPolyTime.snd _ _).comp hx'' + have hζ := digits_polyTime_binary.comp + (((ComputableInPolyTime.length_list _).comp hfl).prod hk) + exact hP.prod (hfl.prod (hr.prod (DescribedNetwork.specNet_polyTime.comp + ((hP.prod (hℓ.prod (hfl.prod hζ))).prod hG)))) + +/-- The certificate of one round, from a certificate of the contraction over `A_P`. -/ +noncomputable def engineStepCertificate + (cc : NativeCertificate core (encCore encT) (encList encNat)) : + NativeCertificate (engineStep core) + (encPair encNat (encPair (encEngine encT) (encList (encList encNat)))) + (encPair (encEngine encT) (encList (encList encNat))) := + (NativeCertificate.ofPolyTime + ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _))).prod + ((NativeCertificate.ofPolyTime (ComputableInPolyTime.snoc (encList encNat))).comp + ((NativeCertificate.ofPolyTime + ((ComputableInPolyTime.snd _ _).comp (ComputableInPolyTime.snd _ _))).prod + (cc.comp (NativeCertificate.ofPolyTime coreInput_polyTime)))) + +/-- Recovery from the final state of the loop is polynomial-time. -/ +theorem engineRecover_polyTime : + ComputableInPolyTime + (fun p : ℕ × ((List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T) × List (List ℕ)) => + interpRecover p.2.1.2.1 p.2.1.2.2.1 p.2.1.1 + ((List.range (DescribedNetwork.pointCount p.2.1.2.2.1 p.2.1.2.2.2.2)).map + (FastContraction.digits p.2.1.1.length)) p.2.2) + (encPair encNat (encPair (encEngine encT) (encList (encList encNat)))) (encList encNat) := by + let encS := encPair encNat (encPair (encEngine encT) (encList (encList encNat))) + have hy : ComputableInPolyTime + (fun p : ℕ × ((List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T) × List (List ℕ)) => p.2.1) + encS (encEngine encT) := + (ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _) + have hys : ComputableInPolyTime + (fun p : ℕ × ((List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T) × List (List ℕ)) => p.2.2) + encS (encList (encList encNat)) := + (ComputableInPolyTime.snd _ _).comp (ComputableInPolyTime.snd _ _) + have hfl : ComputableInPolyTime + (fun p : ℕ × ((List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T) × List (List ℕ)) => p.2.1.1) + encS (encList encNat) := (ComputableInPolyTime.fst _ _).comp hy + have hP : ComputableInPolyTime + (fun p : ℕ × ((List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T) × List (List ℕ)) => p.2.1.2.1) + encS encUnary := + (ComputableInPolyTime.fst _ _).comp ((ComputableInPolyTime.snd _ _).comp hy) + have hℓ : ComputableInPolyTime + (fun p : ℕ × ((List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T) × List (List ℕ)) => p.2.1.2.2.1) + encS encUnary := + (ComputableInPolyTime.fst _ _).comp ((ComputableInPolyTime.snd _ _).comp + ((ComputableInPolyTime.snd _ _).comp hy)) + have hpts : ComputableInPolyTime + (fun p : ℕ × ((List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T) × List (List ℕ)) => + (List.range (DescribedNetwork.pointCount p.2.1.2.2.1 p.2.1.2.2.2.2)).map + (FastContraction.digits p.2.1.1.length)) + encS (encList (encList encNat)) := + DescribedNetwork.digitPoints_polyTime.comp + (((ComputableInPolyTime.length_list _).comp hfl).prod (pointCount_polyTime.comp hy)) + have h := interpRecover_polyTime.comp (hP.prod (hℓ.prod (hfl.prod (hpts.prod hys)))) + exact h + +/-- **The reduction as one native machine**, from a native certificate of the contraction over +`A_P` of specialized networks: the streaming loop over the digit points, keeping only the binary +index, the input and the values so far, then recovery. On input `(fl, (P, ℓ, r, G))` it computes +`interpContract core fl P ℓ r G`. -/ +noncomputable def engineCertificate + (cc : NativeCertificate core (encCore encT) (encList encNat)) : + NativeCertificate (fun y : List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T => + DescribedNetwork.interpContract core y.1 y.2.1 y.2.2.1 y.2.2.2.1 y.2.2.2.2) + (encEngine encT) (encList encNat) := + ((NativeCertificate.ofPolyTime engineRecover_polyTime).comp + (IndexFold.certificate + (NativeCertificate.ofPolyTime (ComputableInPolyTime.unary_to_binary.comp pointCount_polyTime)) + (NativeCertificate.ofPolyTime + (ComputableInPolyTime.id'.prod (ComputableInPolyTime.const []))) + (engineStepCertificate core cc))).congr fun y => by + simp only [Function.comp_apply] + rw [interpContract_eq_run, run_engineStep] + +/-! ### Direct summation as the contraction over `A_P` -/ + +/-- **Direct summation over a specialized network**, as a contraction over `A_P` with the input +`(P, fl, r, G')`, from a native certificate of the entries. -/ +noncomputable def directCoreCertificate + (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) : + NativeCertificate + (fun x : ℕ × List ℕ × ℕ × DescribedNetwork (SpecDesc T) => + DescribedNetwork.sumValue SumOps.galois (specEntry entry) (x.1, x.2.1) x.2.2.2) + (encCore encT) (encList encNat) := + ((DescribedNetwork.contractionCertificate (specEntry entry) SumOps.galois_polyTime + (specEntryCertificate entry ce)).comp + (NativeCertificate.ofPolyTime + ((((ComputableInPolyTime.fst _ _).prod + ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _))).prod + ((ComputableInPolyTime.snd _ _).comp ((ComputableInPolyTime.snd _ _).comp + (ComputableInPolyTime.snd _ _)))) : + ComputableInPolyTime + (fun x : ℕ × List ℕ × ℕ × DescribedNetwork (SpecDesc T) => ((x.1, x.2.1), x.2.2.2)) + (encCore encT) + (DescribedNetwork.encInput (encPair encUnary (encList encNat)) + (encSpecDesc encT))))).congr fun _ => rfl + +/-- `n ≤ 2 ^ deg f` for the modulus `FastContraction.modulus n`: it has enough residues for `n` +points. -/ +theorem le_two_pow_length_modulus (n : ℕ) : n ≤ 2 ^ (FastContraction.modulus n).length := by + have h4 := FastContraction.four_mul_log_le_length_modulus n + have hlt := Nat.lt_pow_succ_log_self (b := 2) one_lt_two n + rcases Nat.eq_zero_or_pos (Nat.log 2 n) with h0 | hpos + · have h2 : n < 2 := by simpa [h0] using hlt + exact (show n ≤ 1 by omega).trans Nat.one_le_two_pow + · exact hlt.le.trans (Nat.pow_le_pow_right (by norm_num) (by omega)) + +/-- Choosing the modulus `FastContraction.modulus n` for `n = (ℓ - 1) k + 1` points is +polynomial-time. -/ +theorem modulusChoice_polyTime : + ComputableInPolyTime + (fun x : ℕ × ℕ × ℕ × DescribedNetwork T => + (FastContraction.modulus (DescribedNetwork.pointCount x.2.1 x.2.2.2), x)) + (encTrunc encT) (encEngine encT) := by + have hpc : ComputableInPolyTime + (fun x : ℕ × ℕ × ℕ × DescribedNetwork T => DescribedNetwork.pointCount x.2.1 x.2.2.2) + (encTrunc encT) encUnary := by + have h := pointCount_polyTime (encT := encT).comp + ((ComputableInPolyTime.const ([] : List ℕ)).prod ComputableInPolyTime.id') + exact h + have h := (FastContraction.modulus_polyTime.comp hpc).prod ComputableInPolyTime.id' + exact h + +/-- **Direct summation through the reduction computes the truncated contraction**, at the modulus +`FastContraction.modulus n` for `n = (ℓ - 1) k + 1` points. -/ +theorem interpContract_direct_eq (P ℓ r : ℕ) (G : DescribedNetwork T) : + DescribedNetwork.interpContract + (fun x : ℕ × List ℕ × ℕ × DescribedNetwork (SpecDesc T) => + DescribedNetwork.sumValue SumOps.galois (specEntry entry) (x.1, x.2.1) x.2.2.2) + (FastContraction.modulus (DescribedNetwork.pointCount ℓ G)) P ℓ r G = + G.truncContraction entry P ℓ := by + refine DescribedNetwork.interpContract_eq (entry := entry) + (FastContraction.irreducible_modulus (DescribedNetwork.pointCount ℓ G)) G + (le_two_pow_length_modulus _) fun k _ => ?_ + exact DescribedNetwork.val_sumValue_galois (specEntry entry) + (P, FastContraction.modulus (DescribedNetwork.pointCount ℓ G)) _ + +/-- **The truncated contraction by direct summation**, as one native machine on every input +`(P, ℓ, r, G)`: the reduction with direct summation over `A_P` at the modulus +`FastContraction.modulus n`, for `n = (ℓ - 1) k + 1` points. It is correct everywhere; its cost is +that of direct summation, exponential in the number of edges. -/ +noncomputable def truncDirectCertificate + (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) : + NativeCertificate + (fun x : ℕ × ℕ × ℕ × DescribedNetwork T => x.2.2.2.truncContraction entry x.1 x.2.1) + (encTrunc encT) (encList encNat) := + ((engineCertificate _ (directCoreCertificate entry ce)).comp + (NativeCertificate.ofPolyTime modulusChoice_polyTime)).congr fun x => + interpContract_direct_eq entry x.1 x.2.1 x.2.2.1 x.2.2.2 + +end Cslib.Circuits.Frontier diff --git a/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkTruncatedPolyTime.lean b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkTruncatedPolyTime.lean new file mode 100644 index 000000000..4b8bdc3ef --- /dev/null +++ b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkTruncatedPolyTime.lean @@ -0,0 +1,56 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: local-only (test driver) + +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TruncatedPolyTime + +/-! +# Tests for the native machine of truncation order `ℓ` + +Descriptors that are their own entry (a constant list of `V`-coefficients) have a polynomial-time +entry certificate, so direct summation through the reduction is a native machine for their +truncated contraction on every input. The loop's values after `j` rounds are the contractions at +the first `j` digit points. +-/ + +@[expose] public section + +namespace ComplexityTests.TensorNetworkTruncatedPolyTime + +open Cslib Cslib.GenericRAM Cslib.Circuits.Frontier Turing.MultiTapeTM + +/-- A descriptor is its own entry, whatever the bits. -/ +def constEntry (t : List ℕ) (_ : List Bool) : List ℕ := t + +/-- The entry certificate of constant descriptors. -/ +noncomputable def constCert : + NativeCertificate (fun q : List ℕ × List Bool => constEntry q.1 q.2) + (encPair (encList encNat) encBits) (encList encNat) := + NativeCertificate.ofPolyTime (ComputableInPolyTime.fst _ _) + +/-- **A native machine for the truncated contraction** of constant-entry networks, on every +input `(P, ℓ, r, G)` with `P` and `ℓ` in unary. -/ +noncomputable def truncConstCert : + NativeCertificate + (fun x : ℕ × ℕ × ℕ × DescribedNetwork (List ℕ) => + x.2.2.2.truncContraction constEntry x.1 x.2.1) + (encTrunc (encList encNat)) (encList encNat) := + truncDirectCertificate constEntry constCert + +-- The loop's values are the contractions at the digit points, in order. +example (core : ℕ × List ℕ × ℕ × DescribedNetwork (SpecDesc (List ℕ)) → List ℕ) + (y : List ℕ × ℕ × ℕ × ℕ × DescribedNetwork (List ℕ)) : + (IndexFold.run (engineStep core) 2 (y, [])).2.2 = + [core (coreInput y 0), core (coreInput y 1)] := by + rw [run_engineStep] + rfl + +-- `FastContraction.modulus n` has at least `n` residues. +example : 100 ≤ 2 ^ (FastContraction.modulus 100).length := le_two_pow_length_modulus 100 + +end ComplexityTests.TensorNetworkTruncatedPolyTime From bbe9fb83dc30e27ee84d328903c4517b0b8bd468 Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 09:41:18 -0400 Subject: [PATCH 04/20] feat(Frontier/TensorNetwork): contraction interface for entry procedures (#1538 E1) Theorem D.1 of the ETH manuscript (p. 53) contracts networks whose entries are computed by procedures rather than listed in tables. This adds the interface the contraction algorithm provides for them: `EntryAdmissible` (Theorem D.1's hypotheses with one constant, degree at most `ceilNineTenths s`), `EntryContractionAlgorithm` (A_P-valued output, correct at the modulus `FastContraction.modulus m`, ContractionAlgorithm-shaped bounds), and direct summation with an entry procedure with its correctness and resources on every input and on admissible inputs. The input format matches the truncation-order reduction's `encCore`. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG --- Complexity.lean | 1 + .../TensorNetwork/EntryContraction.lean | 598 ++++++++++++++++++ .../TensorNetworkEntryContraction.lean | 79 +++ 3 files changed, 678 insertions(+) create mode 100644 Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContraction.lean create mode 100644 ComplexityTests/Computability/Circuit/Frontier/TensorNetworkEntryContraction.lean diff --git a/Complexity.lean b/Complexity.lean index 6d97ad37a..662c905a8 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -935,6 +935,7 @@ public import Complexity.Computability.Circuit.Frontier.TensorNetwork.Deformatio public import Complexity.Computability.Circuit.Frontier.TensorNetwork.DescribedContraction public import Complexity.Computability.Circuit.Frontier.TensorNetwork.DescribedLift public import Complexity.Computability.Circuit.Frontier.TensorNetwork.DirectContraction +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.EntryContraction public import Complexity.Computability.Circuit.Frontier.TensorNetwork.Explicit public import Complexity.Computability.Circuit.Frontier.TensorNetwork.FastContraction public import Complexity.Computability.Circuit.Frontier.TensorNetwork.FastContractionDerivation diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContraction.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContraction.lean new file mode 100644 index 000000000..857bf2b8d --- /dev/null +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContraction.lean @@ -0,0 +1,598 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.FastContractionMachine +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.Schedule +import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimePrimitives +import Complexity.Computability.Machines.Turing.MultiTape.Complexity.Lists +import Complexity.Computability.Machines.Turing.MultiTape.Complexity.PolyTime.BitString +import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimeListBinaryLookup +import Complexity.Foundations.Data.BitString.Binary +import Complexity.Foundations.Data.Nat.Asymptotics + +/-! +# Contraction with entry procedures: the interface + +Theorem D.1 of [OpenAI2026ETH] (p. 53) contracts Boolean tensor networks whose entries are not +given as tables but computed: "uniformly for every vertex and Boolean choice of its ports, … its +entry can be computed from the description in time `(s + L) ^ b 2 ^ (A s ^ (9/10))` and space +`(s + L) ^ b`", with maximum degree at most `⌈s ^ (9/10)⌉`. At that degree a table has +`2 ^ ⌈s ^ (9/10)⌉` entries, so Lemma D.2 (p. 56), which applies the theorem with entries computed +by procedures, needs this form for its polynomial-space bound. This file states the interface +that the contraction algorithm provides for such networks, milestone E1 of #1538. + +**Entry procedures.** A network is a described network `DescribedNetwork T` (the record shared +with explicit networks), with descriptors in a type `T` encoded by `encT`. An *entry procedure* +is a function `entry : T → List Bool → List ℕ`, the coefficient list over +`A_P = (ℤ / 2 ^ P)[U] / (f)` of the entry of a descriptor at the bits on its ports, with a native +certificate `ce` on `encPair encT encBits`. This is the evaluator of direct summation +(`DescribedNetwork.contractionCertificate`). Explicit networks are the case of tables, and the +specialized networks of the truncation-order reduction (#1538, E2) are another instance. + +**Admissible networks** (`EntryAdmissible`). Theorem D.1's hypotheses with one constant `C` for +the theorem's `C`, `A` and `b`: rows-first bipartite, between `s` and `C s` edges, maximum degree +at most `⌈s ^ (9/10)⌉` (`ceilNineTenths`), and every entry within time +`C (s + L + 1) ^ C 2 ^ (C ⌈s ^ (9/10)⌉)` and space `C (s + L + 1) ^ C`, where `L` is the encoded +length of the network. Entry outputs need no separate size condition, because a native +certificate's space bound charges its encoded output. As for explicit networks +(`Cslib.Complexity.CountingSimulation.ExplicitAdmissible`), admissibility asks for at least `s` +edges; a caller can pad with disjoint edges whose row tensor is `[x = 0]` and column tensor `1`, +which leave the contraction unchanged. The number of vertices is not bounded separately: the +encoded length bounds it. + +**The interface** (`EntryContractionAlgorithm`). One native certificate maps an input +`(P, fl, r, G)`, with the precision `P` in unary and the coefficients `fl` of a modulus, to a +coefficient list whose value in `A_P` at the modulus `FastContraction.modulus m`, for `m` the +number of edges, is the contraction of the entries' values, on every input. On admissible inputs +at that modulus it runs in time `K (n + 1) ^ K 2 ^ (K s / √⌊log₂ s⌋)` and space `K (n + 1) ^ K`, +the bound shape of `Cslib.Complexity.CountingSimulation.ContractionAlgorithm`. The input format is +that of the truncation-order reduction's contractions of specialized networks. + +**Direct summation** (`EntryContraction.directCore`). Summing over all edge assignments with the +entry procedure computes the contraction on every input (`EntryContraction.val_directCore`), in +time `(2 ^ m (k + 1) + 1) (K (n + ES + 1) ^ K + 2 E)` and space `K (n + ES + 1) ^ K + ES` when the +procedure takes time `E` and space `ES` on the vertices (`EntryContraction.directCore_le`). On +admissible inputs that is `K (n + 1) ^ K 2 ^ (K s)` and polynomial space +(`EntryContraction.exists_directCore_le`): the fallback of the contraction algorithm for small `s`. + +**Instances.** A polynomial-time entry procedure meets the entry bounds from some constant on +(`EntryContraction.exists_entryAdmissible_of_isPolynomial`), so admissibility reduces to the +shape of the network. Tables are the entry procedure `EntryContraction.tableEntry`, and direct +summation with it is the contraction of the explicit network +(`EntryContraction.val_directCore_tableEntry`). + +## Main definitions + +* `Cslib.Circuits.Frontier.ceilNineTenths`: `⌈s ^ (9/10)⌉`. +* `Cslib.Circuits.Frontier.EntryContraction.encInput`: the encoding of an input. +* `Cslib.Circuits.Frontier.EntryAdmissible`: Theorem D.1's hypotheses. +* `Cslib.Circuits.Frontier.EntryContractionAlgorithm`: the interface. +* `Cslib.Circuits.Frontier.EntryContraction.directCore`: direct summation with an entry procedure. +* `Cslib.Circuits.Frontier.EntryContraction.tableEntry`, + `Cslib.Circuits.Frontier.EntryContraction.tableEntryCertificate`: the entry procedure of tables. + +## Main results + +* `Cslib.Circuits.Frontier.le_ceilNineTenths_iff`: `x ≤ ⌈s ^ (9/10)⌉` iff `(x - 1) ^ 10 < s ^ 9`. +* `Cslib.Circuits.Frontier.ceilNineTenths_le_degreeBound`: the degree bound of the schedule is at + least `⌈s ^ (9/10)⌉`. +* `Cslib.Circuits.Frontier.exists_mul_ceilNineTenths_le`: `A ⌈s ^ (9/10)⌉ ≤ s / √⌊log₂ s⌋` from + some size on, so entry costs fit the time budget. +* `Cslib.Circuits.Frontier.EntryContraction.val_directCore`: direct summation is correct. +* `Cslib.Circuits.Frontier.EntryContraction.directCore_le`, + `Cslib.Circuits.Frontier.EntryContraction.exists_directCore_le`: its resources. +* `Cslib.Circuits.Frontier.EntryContraction.exists_entryAdmissible_of_isPolynomial`: + polynomial-time entry procedures meet the entry bounds. +* `Cslib.Circuits.Frontier.EntryContraction.val_directCore_tableEntry`: direct summation of an + explicit network. + +## References + +* [OpenAI, *The Exponential Time Hypothesis is False*][OpenAI2026ETH], Theorem D.1 (p. 53), + Lemma D.2 (pp. 54–56) and Appendix D.4.6–D.4.7 (pp. 63–64). +-/ + +public section + +namespace Cslib.Circuits.Frontier + +open GaloisRingArith Cslib.GenericRAM Turing.MultiTapeTM + +/-! ### The nine-tenths power -/ + +/-- `s ^ 9 ≤ s ^ 10`. -/ +theorem pow_nine_le_pow_ten_self (s : ℕ) : s ^ 9 ≤ s ^ 10 := by + rcases Nat.eq_zero_or_pos s with rfl | hs + · simp + · exact Nat.pow_le_pow_right hs (by norm_num) + +/-- Some `x` has `s ^ 9 ≤ x ^ 10`. -/ +theorem exists_pow_nine_le_pow_ten (s : ℕ) : ∃ x, s ^ 9 ≤ x ^ 10 := + ⟨s, pow_nine_le_pow_ten_self s⟩ + +/-- **`⌈s ^ (9/10)⌉`**, the least `x` with `s ^ 9 ≤ x ^ 10`. -/ +@[expose] def ceilNineTenths (s : ℕ) : ℕ := Nat.find (exists_pow_nine_le_pow_ten s) + +/-- `s ^ 9 ≤ ⌈s ^ (9/10)⌉ ^ 10`. -/ +theorem pow_nine_le_ceilNineTenths_pow_ten (s : ℕ) : s ^ 9 ≤ ceilNineTenths s ^ 10 := + Nat.find_spec (exists_pow_nine_le_pow_ten s) + +/-- `⌈s ^ (9/10)⌉ ≤ x` whenever `s ^ 9 ≤ x ^ 10`. -/ +theorem ceilNineTenths_le {s x : ℕ} (h : s ^ 9 ≤ x ^ 10) : ceilNineTenths s ≤ x := + Nat.find_min' _ h + +/-- **`x ≤ ⌈s ^ (9/10)⌉` iff `(x - 1) ^ 10 < s ^ 9`**: the condition of a degree at most +`⌈s ^ (9/10)⌉`, for `s ≥ 1`. -/ +theorem le_ceilNineTenths_iff {s x : ℕ} (hs : 1 ≤ s) : + x ≤ ceilNineTenths s ↔ (x - 1) ^ 10 < s ^ 9 := by + constructor + · intro hx + by_contra h + rw [not_lt] at h + have h1 := ceilNineTenths_le h + rcases Nat.eq_zero_or_pos x with rfl | hx0 + · have : 1 ≤ s ^ 9 := Nat.one_le_pow _ _ hs + simp at h + omega + · omega + · intro h + by_contra hx + rw [not_le] at hx + have h1 : ceilNineTenths s ≤ x - 1 := by omega + have h2 := (pow_nine_le_ceilNineTenths_pow_ten s).trans (Nat.pow_le_pow_left h1 10) + omega + +/-- `⌈s ^ (9/10)⌉ ≤ s`. -/ +theorem ceilNineTenths_le_self (s : ℕ) : ceilNineTenths s ≤ s := + ceilNineTenths_le (pow_nine_le_pow_ten_self s) + +/-- **The degree bound of the schedule is at least `⌈s ^ (9/10)⌉`** +(`ContractionSchedule.pow_nine_le_degreeBound_pow_ten`). -/ +theorem ceilNineTenths_le_degreeBound (s : ℕ) : + ceilNineTenths s ≤ ContractionSchedule.degreeBound s := + ceilNineTenths_le (ContractionSchedule.pow_nine_le_degreeBound_pow_ten s) + +/-- **Entry costs fit the budget**: for every `A`, from some size on, +`A ⌈s ^ (9/10)⌉ ≤ s / √⌊log₂ s⌋`. So the entry time `2 ^ (A s ^ (9/10))` allowed by Theorem D.1 +is within the `2 ^ O(s / √log s)` budget of a leaf (§D.4.7, p. 64). -/ +theorem exists_mul_ceilNineTenths_le (A : ℕ) : + ∃ s₀ : ℕ, ∀ s, s₀ ≤ s → A * ceilNineTenths s ≤ s / Nat.sqrt (Nat.log 2 s) := by + obtain ⟨L₀, hL₀⟩ := Filter.eventually_atTop.mp + (Nat.eventually_mul_add_one_pow_le_pow_div (4 * A) 1 10 one_lt_two (by norm_num)) + refine ⟨2 ^ (L₀ + 1), fun s hs => ?_⟩ + obtain ⟨L, hLdef⟩ : ∃ L, L = Nat.log 2 s := ⟨_, rfl⟩ + have hs0 : s ≠ 0 := by have := Nat.one_le_two_pow (n := L₀ + 1); omega + have hL : L₀ + 1 ≤ L := hLdef ▸ Nat.le_log_of_pow_le one_lt_two hs + have h1 := hL₀ L (by omega) + rw [pow_one] at h1 + have hsq : Nat.sqrt L ≤ L + 1 := (Nat.sqrt_le_self L).trans (Nat.le_succ L) + have hsq0 : 0 < Nat.sqrt L := Nat.sqrt_pos.2 (by omega) + have hD : ceilNineTenths s ≤ 2 ^ (9 * L / 10 + 2) := by + have := ceilNineTenths_le_degreeBound s + rwa [ContractionSchedule.degreeBound, ← hLdef] at this + have hpow : 2 ^ L ≤ s := hLdef ▸ Nat.pow_log_le_self 2 hs0 + rw [← hLdef, Nat.le_div_iff_mul_le hsq0] + calc A * ceilNineTenths s * Nat.sqrt L ≤ A * 2 ^ (9 * L / 10 + 2) * (L + 1) := + Nat.mul_le_mul (Nat.mul_le_mul_left _ hD) hsq + _ = 2 ^ (9 * L / 10) * (4 * A * (L + 1)) := by rw [pow_add]; ring + _ ≤ 2 ^ (9 * L / 10) * 2 ^ (L / 10) := Nat.mul_le_mul_left _ h1 + _ = 2 ^ (9 * L / 10 + L / 10) := (pow_add _ _ _).symm + _ ≤ 2 ^ L := Nat.pow_le_pow_right (by norm_num) (by omega) + _ ≤ s := hpow + +/-! ### The interface -/ + +namespace EntryContraction + +/-- **The encoding of an input `(P, fl, r, G)`**: the precision `P` in unary, the coefficients of +the modulus and the number of rows in binary, then the network. -/ +abbrev encInput {T : Type} (encT : T ↪ List Bool) : + ℕ × List ℕ × ℕ × DescribedNetwork T ↪ List Bool := + encPair encUnary (encPair (encList encNat) (encPair encNat (DescribedNetwork.encDescribed encT))) + +end EntryContraction + +variable {T : Type} {encT : T ↪ List Bool} {entry : T → List Bool → List ℕ} + +/-- **Admissible networks with an entry procedure** at size `s` with constant `C` (Theorem D.1's +hypotheses, with `C` for its constants `C`, `A` and `b`): the network `G` with `r` row vertices is +rows-first bipartite, has between `s` and `C s` edges, every vertex has at most +`⌈s ^ (9/10)⌉` ports, and on every vertex and bits on its ports the entry procedure's certificate +takes time at most `C (s + L + 1) ^ C 2 ^ (C ⌈s ^ (9/10)⌉)` and space at most `C (s + L + 1) ^ C`, +for `L` the encoded length of `G`. -/ +@[expose] def EntryAdmissible + (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) (C s : ℕ) (G : ℕ × DescribedNetwork T) : Prop := + G.2.IsRowsFirstBipartite G.1 ∧ s ≤ G.2.numEdges ∧ G.2.numEdges ≤ C * s ∧ + (∀ v ∈ G.2.vertices, v.1.length ≤ ceilNineTenths s) ∧ + ∀ v ∈ G.2.vertices, ∀ bs : List Bool, bs.length = v.1.length → + ce.time (v.2, bs) ≤ + C * (s + (DescribedNetwork.encDescribed encT G.2).length + 1) ^ C * + 2 ^ (C * ceilNineTenths s) ∧ + ce.space (v.2, bs) ≤ C * (s + (DescribedNetwork.encDescribed encT G.2).length + 1) ^ C + +variable (encT entry) in +/-- **The contraction interface for entry procedures** (Theorem D.1 with `ℓ = 1`, entries in +`A_P`). A native certificate maps `(P, fl, r, G)` to a coefficient list `core (P, fl, r, G)`. At +the modulus `fl = FastContraction.modulus m`, for `m` the number of edges of `G`, its value in +`A_P` is the contraction of the values of the entries, on every input. For all constants `C` and +`D` there is `K` such that on every network admissible at a size `s ≥ 2` with constant `C`, and +every precision `1 ≤ P ≤ D s`, at that modulus the certificate takes time at most +`K (n + 1) ^ K 2 ^ (K s / √⌊log₂ s⌋)` and space at most `K (n + 1) ^ K`, for `n` the encoded length +of the input. -/ +structure EntryContractionAlgorithm (Admissible : ℕ → ℕ → ℕ × DescribedNetwork T → Prop) where + /-- The output on an input `(P, fl, r, G)`. -/ + core : ℕ × List ℕ × ℕ × DescribedNetwork T → List ℕ + /-- Its native certificate. -/ + certificate : NativeCertificate core (EntryContraction.encInput encT) (encList encNat) + /-- **Correctness**: at the modulus of the number of edges, the value is the contraction. -/ + val_core : ∀ (P r : ℕ) (G : DescribedNetwork T), + val P (FastContraction.modulus G.numEdges) + (core (P, FastContraction.modulus G.numEdges, r, G)) = + G.contraction fun t bs => val P (FastContraction.modulus G.numEdges) (entry t bs) + /-- Its time and space on admissible inputs at the modulus of the number of edges. -/ + bound : ∀ C D : ℕ, ∃ K : ℕ, ∀ (s P r : ℕ) (G : DescribedNetwork T), 2 ≤ s → 1 ≤ P → + P ≤ D * s → Admissible C s (r, G) → + certificate.time (P, FastContraction.modulus G.numEdges, r, G) ≤ + K * ((EntryContraction.encInput encT + (P, FastContraction.modulus G.numEdges, r, G)).length + 1) ^ K * + 2 ^ (K * s / Nat.sqrt (Nat.log 2 s)) ∧ + certificate.space (P, FastContraction.modulus G.numEdges, r, G) ≤ + K * ((EntryContraction.encInput encT + (P, FastContraction.modulus G.numEdges, r, G)).length + 1) ^ K + +/-! ### Direct summation -/ + +namespace EntryContraction + +/-- The input of direct summation, `((P, fl), G)`, from `(P, fl, r, G)`. -/ +theorem sumInput_polyTime : + ComputableInPolyTime (fun x : ℕ × List ℕ × ℕ × DescribedNetwork T => ((x.1, x.2.1), x.2.2.2)) + (encInput encT) + (DescribedNetwork.encInput (encPair encUnary (encList encNat)) encT) := + ((ComputableInPolyTime.fst _ _).prod + ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _))).prod + ((ComputableInPolyTime.snd _ _).comp ((ComputableInPolyTime.snd _ _).comp + (ComputableInPolyTime.snd _ _))) + +variable (entry) in +/-- **Direct summation with an entry procedure**: on `(P, fl, r, G)`, the sum over all edge +assignments of the products of the entries, with the operations of `A_P` at the modulus `fl`. -/ +@[expose] noncomputable def directCore + (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) : + NativeCertificate + (fun x : ℕ × List ℕ × ℕ × DescribedNetwork T => + DescribedNetwork.sumValue SumOps.galois entry (x.1, x.2.1) x.2.2.2) + (encInput encT) (encList encNat) := + ((DescribedNetwork.contractionCertificate entry SumOps.galois_polyTime ce).comp + (NativeCertificate.ofPolyTime sumInput_polyTime)).congr fun _ => rfl + +/-- **Direct summation is correct**: at every modulus, the value is the contraction. -/ +theorem val_directCore (P : ℕ) (fl : List ℕ) (G : DescribedNetwork T) : + val P fl (DescribedNetwork.sumValue SumOps.galois entry (P, fl) G) = + G.contraction fun t bs => val P fl (entry t bs) := + DescribedNetwork.val_sumValue_galois entry (P, fl) G + + +/-- The time of direct summation: the input of the sum, then the sum. -/ +theorem directCore_time + (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : + (directCore entry ce).time x = + (NativeCertificate.ofPolyTime (sumInput_polyTime (encT := encT))).time x + + (DescribedNetwork.contractionCertificate entry SumOps.galois_polyTime ce).time + ((x.1, x.2.1), x.2.2.2) := rfl + +/-- The space of direct summation. -/ +theorem directCore_space + (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : + (directCore entry ce).space x = + (NativeCertificate.ofPolyTime (sumInput_polyTime (encT := encT))).space x + + (DescribedNetwork.contractionCertificate entry SumOps.galois_polyTime ce).space + ((x.1, x.2.1), x.2.2.2) := rfl + +/-- The precision, the modulus and the input of the sum against the encoded input. -/ +private theorem lengths_le (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : + x.1 + x.2.1.length ≤ (encInput encT x).length ∧ + (DescribedNetwork.encInput (encPair encUnary (encList encNat)) encT + ((x.1, x.2.1), x.2.2.2)).length ≤ 2 * (encInput encT x).length := by + obtain ⟨P, fl, r, G⟩ := x + have h := length_le_length_encList encNat fl + simp only [encInput, DescribedNetwork.encInput, length_encPair, encUnary_apply, + List.length_replicate] at h ⊢ + omega + +private theorem mul_pow_le {c W d E : ℕ} (hW : 1 ≤ W) (hd : d ≤ E) : c * W ^ d ≤ c * W ^ E := + Nat.mul_le_mul_left _ (Nat.pow_le_pow_right hW hd) + +/-- **The resources of direct summation with an entry procedure.** There is `K` such that on an +input `x = (P, fl, r, G)` of encoded length `n`, with `m` edges and `k` vertices, if the entry +procedure takes time at most `E` and space at most `ES` on every vertex and bits on its ports, +then direct summation takes time at most `(2 ^ m (k + 1) + 1) (K (n + ES + 1) ^ K + 2 E)` and +space at most `K (n + ES + 1) ^ K + ES`. -/ +theorem directCore_le + (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) : + ∃ K : ℕ, ∀ (x : ℕ × List ℕ × ℕ × DescribedNetwork T) (E ES : ℕ), + (∀ v ∈ x.2.2.2.vertices, ∀ bs : List Bool, bs.length = v.1.length → + ce.time (v.2, bs) ≤ E ∧ ce.space (v.2, bs) ≤ ES) → + (directCore entry ce).time x ≤ + (2 ^ x.2.2.2.numEdges * (x.2.2.2.vertices.length + 1) + 1) * + (K * ((encInput encT x).length + ES + 1) ^ K + 2 * E) ∧ + (directCore entry ce).space x ≤ K * ((encInput encT x).length + ES + 1) ^ K + ES := by + obtain ⟨K₁, hK₁⟩ := DescribedNetwork.contractionCertificate_le (ops := SumOps.galois) + (eval := entry) (encQ := encPair encUnary (encList encNat)) (encY := encList encNat) + (encT := encT) SumOps.galois_polyTime ce + obtain ⟨c, -, hout⟩ := ce.computes + have hI := NativeCertificate.ofPolyTime_isPolynomial (sumInput_polyTime (encT := encT)) + obtain ⟨ct, dt, hit⟩ := hI.1.exists_le + obtain ⟨cs, ds, his⟩ := hI.2.exists_le + obtain ⟨c₁, hc₁⟩ : ∃ c₁, c₁ = K₁ * (c + 6) ^ K₁ := ⟨_, rfl⟩ + refine ⟨ct + cs + c₁ + dt + ds + 2 * K₁, fun x E ES hE => ?_⟩ + obtain ⟨n, hn⟩ : ∃ n, n = (encInput encT x).length := ⟨_, rfl⟩ + obtain ⟨W, hW⟩ : ∃ W, W = n + ES + 1 := ⟨_, rfl⟩ + rw [← hn, show n + ES + 1 = W from hW.symm] + have hW1 : 1 ≤ W := by omega + obtain ⟨hPfl, hproj⟩ := lengths_le x + rw [← hn] at hPfl hproj + have hRv : ∀ y, SumOps.galois.Reduced (x.1, x.2.1) y → + (encList encNat y).length ≤ n * (2 * n + 3) := fun y hy => + (SumOps.length_encList_le_of_galois_reduced hy).trans (Nat.mul_le_mul (by simp only; omega) + (by simp only; omega)) + have hEv : ∀ v ∈ ((x.1, x.2.1), x.2.2.2).2.vertices, ∀ bs : List Bool, + bs.length = v.1.length → ce.time (v.2, bs) ≤ E ∧ ce.space (v.2, bs) ≤ ES ∧ + (encList encNat (entry v.2 bs)).length ≤ c * (ES + 1) := fun v hv bs hbs => + ⟨(hE v hv bs hbs).1, (hE v hv bs hbs).2, + (hout (v.2, bs)).trans (Nat.mul_le_mul_left _ (by have := (hE v hv bs hbs).2; omega))⟩ + obtain ⟨hT, hS⟩ := hK₁ ((x.1, x.2.1), x.2.2.2) E ES (c * (ES + 1)) (n * (2 * n + 3)) hEv hRv + -- The argument of direct summation's polynomial against `W ^ 2`. + have hA : (DescribedNetwork.encInput (encPair encUnary (encList encNat)) encT + ((x.1, x.2.1), x.2.2.2)).length + c * (ES + 1) + n * (2 * n + 3) + 1 ≤ (c + 6) * W ^ 2 := by + have h1 : c * (ES + 1) ≤ c * W := Nat.mul_le_mul_left _ (by omega) + have h2 : c * W ≤ c * W ^ 2 := Nat.mul_le_mul_left _ (by nlinarith) + have h3 : n * (2 * n + 3) + 2 * n + 1 ≤ 6 * W ^ 2 := by nlinarith + nlinarith + have hpoly : K₁ * ((DescribedNetwork.encInput (encPair encUnary (encList encNat)) encT + ((x.1, x.2.1), x.2.2.2)).length + c * (ES + 1) + n * (2 * n + 3) + 1) ^ K₁ ≤ + c₁ * W ^ (2 * K₁) := by + rw [hc₁, pow_mul, Nat.mul_assoc, ← Nat.mul_pow] + exact Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hA _) + have hnW : n + 1 ≤ W := by omega + have hit' : (NativeCertificate.ofPolyTime (sumInput_polyTime (encT := encT))).time x ≤ + ct * W ^ dt := by + have h := hit x + rw [← hn] at h + exact h.trans (Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hnW _)) + have his' : (NativeCertificate.ofPolyTime (sumInput_polyTime (encT := encT))).space x ≤ + cs * W ^ ds := by + have h := his x + rw [← hn] at h + exact h.trans (Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hnW _)) + obtain ⟨K, hK⟩ : ∃ K, K = ct + cs + c₁ + dt + ds + 2 * K₁ := ⟨_, rfl⟩ + rw [← hK] + have hct : ct * W ^ dt ≤ ct * W ^ K := mul_pow_le hW1 (by omega) + have hcs : cs * W ^ ds ≤ cs * W ^ K := mul_pow_le hW1 (by omega) + have hc1 : c₁ * W ^ (2 * K₁) ≤ c₁ * W ^ K := mul_pow_le hW1 (by omega) + have hsum : ct * W ^ K + cs * W ^ K + c₁ * W ^ K ≤ K * W ^ K := by + rw [← Nat.add_mul, ← Nat.add_mul]; exact Nat.mul_le_mul_right _ (by omega) + have hP1 : 1 ≤ 2 ^ x.2.2.2.numEdges * (x.2.2.2.vertices.length + 1) + 1 := by omega + constructor + · rw [directCore_time] + calc _ ≤ ct * W ^ dt + (2 ^ x.2.2.2.numEdges * (x.2.2.2.vertices.length + 1) + 1) * + (c₁ * W ^ (2 * K₁) + 2 * E) := + Nat.add_le_add hit' (hT.trans (Nat.mul_le_mul_left _ (Nat.add_le_add_right hpoly _))) + _ ≤ (2 ^ x.2.2.2.numEdges * (x.2.2.2.vertices.length + 1) + 1) * + (ct * W ^ K + (c₁ * W ^ K + 2 * E)) := by + rw [Nat.mul_add _ (ct * W ^ K)] + refine Nat.add_le_add ((hct.trans (Nat.le_mul_of_pos_left _ hP1))) ?_ + exact Nat.mul_le_mul_left _ (by omega) + _ ≤ _ := Nat.mul_le_mul_left _ (by omega) + · rw [directCore_space] + calc _ ≤ cs * W ^ ds + (c₁ * W ^ (2 * K₁) + ES) := + Nat.add_le_add his' (hS.trans (Nat.add_le_add_right hpoly _)) + _ ≤ _ := by omega + +/-- **Direct summation on admissible inputs** takes time `K (n + 1) ^ K 2 ^ (K s)` and space +`K (n + 1) ^ K`, at the modulus of the number of edges, for `K` depending only on the constants: +the fallback of the contraction algorithm for small sizes. -/ +theorem exists_directCore_le + (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) (C : ℕ) : + ∃ K : ℕ, ∀ (s P r : ℕ) (G : DescribedNetwork T), EntryAdmissible ce C s (r, G) → + (directCore entry ce).time (P, FastContraction.modulus G.numEdges, r, G) ≤ + K * ((encInput encT (P, FastContraction.modulus G.numEdges, r, G)).length + 1) ^ K * + 2 ^ (K * s) ∧ + (directCore entry ce).space (P, FastContraction.modulus G.numEdges, r, G) ≤ + K * ((encInput encT (P, FastContraction.modulus G.numEdges, r, G)).length + 1) ^ K := by + obtain ⟨K₀, hK₀⟩ := directCore_le (entry := entry) ce + obtain ⟨c₀, hc₀⟩ : ∃ c₀, c₀ = C * 3 ^ C + 1 := ⟨_, rfl⟩ + obtain ⟨K, hK⟩ : ∃ K, K = 4 * (K₀ * (c₀ + 1) ^ K₀ + c₀ + 1) * 2 + K₀ * (C + 1) + C + 3 := + ⟨_, rfl⟩ + refine ⟨K, fun s P r G hA => ?_⟩ + obtain ⟨-, hsm, hmC, -, hent⟩ := hA + simp only at hsm hmC hent + set x := (P, FastContraction.modulus G.numEdges, r, G) + obtain ⟨n, hn⟩ : ∃ n, n = (encInput encT x).length := ⟨_, rfl⟩ + rw [← hn] + -- The size, the network and the vertices against `n`. + have hG : (DescribedNetwork.encDescribed encT G).length ≤ n := by + rw [hn]; simp only [x, encInput, length_encPair]; omega + have hmk := DescribedNetwork.length_numEdges_vertices_le (encT := encT) G + have hsn : s ≤ n := by omega + have hB : s + (DescribedNetwork.encDescribed encT G).length + 1 ≤ 3 * (n + 1) := by omega + -- The entry bounds. + obtain ⟨E, hE⟩ : ∃ E, E = c₀ * (n + 1) ^ C * 2 ^ (C * s) := ⟨_, rfl⟩ + obtain ⟨ES, hES⟩ : ∃ ES, ES = c₀ * (n + 1) ^ C := ⟨_, rfl⟩ + have hpowB : C * (s + (DescribedNetwork.encDescribed encT G).length + 1) ^ C ≤ ES := by + rw [hES] + calc C * (s + (DescribedNetwork.encDescribed encT G).length + 1) ^ C + ≤ C * (3 * (n + 1)) ^ C := Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hB _) + _ = C * 3 ^ C * (n + 1) ^ C := by rw [Nat.mul_pow, Nat.mul_assoc] + _ ≤ c₀ * (n + 1) ^ C := Nat.mul_le_mul_right _ (by omega) + have hbnd : ∀ v ∈ x.2.2.2.vertices, ∀ bs : List Bool, bs.length = v.1.length → + ce.time (v.2, bs) ≤ E ∧ ce.space (v.2, bs) ≤ ES := by + intro v hv bs hbs + obtain ⟨ht, hs⟩ := hent v hv bs hbs + refine ⟨ht.trans ?_, hs.trans hpowB⟩ + rw [hE, show c₀ * (n + 1) ^ C * 2 ^ (C * s) = (c₀ * (n + 1) ^ C) * 2 ^ (C * s) from rfl] + exact Nat.mul_le_mul (hES ▸ hpowB) (Nat.pow_le_pow_right (by norm_num) + (Nat.mul_le_mul_left _ (ceilNineTenths_le_self s))) + obtain ⟨hT, hS⟩ := hK₀ x E ES hbnd + rw [← hn] at hT hS + simp only [x] at hT hS + -- Arithmetic. + have hn1 : 1 ≤ n + 1 := by omega + have hWES : n + ES + 1 ≤ (c₀ + 1) * (n + 1) ^ (C + 1) := by + have h1 : n + 1 ≤ (n + 1) ^ (C + 1) := by + calc n + 1 = (n + 1) ^ 1 := (pow_one _).symm + _ ≤ (n + 1) ^ (C + 1) := Nat.pow_le_pow_right hn1 (by omega) + have h2 : ES ≤ c₀ * (n + 1) ^ (C + 1) := by + rw [hES]; exact Nat.mul_le_mul_left _ (Nat.pow_le_pow_right hn1 (by omega)) + rw [Nat.add_mul, one_mul]; omega + obtain ⟨A₀, hA₀⟩ : ∃ A₀, A₀ = K₀ * (c₀ + 1) ^ K₀ := ⟨_, rfl⟩ + obtain ⟨X, hX⟩ : ∃ X, X = n + 1 := ⟨_, rfl⟩ + obtain ⟨Y, hY⟩ : ∃ Y, Y = 2 ^ (C * s) := ⟨_, rfl⟩ + obtain ⟨e, he⟩ : ∃ e, e = (C + 1) * K₀ + C := ⟨_, rfl⟩ + rw [← hX] at hn1 hWES hE hES ⊢ + rw [← hY] at hE + have hX1 : 1 ≤ X := hn1 + have hY1 : 1 ≤ Y := hY ▸ Nat.one_le_two_pow + have hpoly : K₀ * (n + ES + 1) ^ K₀ ≤ A₀ * X ^ ((C + 1) * K₀) := by + rw [hA₀, pow_mul, Nat.mul_assoc, ← Nat.mul_pow] + exact Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hWES _) + have hXe1 : X ^ ((C + 1) * K₀) ≤ X ^ e := Nat.pow_le_pow_right hX1 (by omega) + have hXe2 : X ^ C ≤ X ^ e := Nat.pow_le_pow_right hX1 (by omega) + -- The number of assignments and vertices. + have hk : x.2.2.2.vertices.length + 1 ≤ X := by simp only [x]; omega + have hm : 2 ^ x.2.2.2.numEdges ≤ Y := hY ▸ Nat.pow_le_pow_right (by norm_num) (by simpa [x]) + have hcount : 2 ^ x.2.2.2.numEdges * (x.2.2.2.vertices.length + 1) + 1 ≤ 2 * (Y * X) := by + have := Nat.mul_le_mul hm hk + have : 1 ≤ Y * X := Nat.one_le_iff_ne_zero.mpr (by positivity) + omega + have hinner : K₀ * (n + ES + 1) ^ K₀ + 2 * E ≤ (A₀ + 2 * c₀) * X ^ e * Y := by + have h1 : A₀ * X ^ ((C + 1) * K₀) ≤ A₀ * X ^ e * Y := + (Nat.mul_le_mul_left _ hXe1).trans (Nat.le_mul_of_pos_right _ hY1) + have h2 : 2 * E ≤ 2 * c₀ * X ^ e * Y := by + rw [hE, Nat.mul_assoc 2 c₀, Nat.mul_assoc, Nat.mul_assoc, Nat.mul_assoc] + exact Nat.mul_le_mul_left _ (Nat.mul_le_mul_left _ (Nat.mul_le_mul_right _ hXe2)) + have e3 : (A₀ + 2 * c₀) * X ^ e * Y = A₀ * X ^ e * Y + 2 * c₀ * X ^ e * Y := by ring + omega + have hCc : C ≤ c₀ := by + have : C ≤ C * 3 ^ C := Nat.le_mul_of_pos_right _ (by positivity) + omega + have hKc : 2 * (A₀ + 2 * c₀) ≤ K := by rw [hK, ← hA₀]; omega + have hKe : e + 1 ≤ K := by + have : (C + 1) * K₀ = K₀ * (C + 1) := Nat.mul_comm _ _ + rw [hK, he]; omega + have hKY : Y * Y ≤ 2 ^ (K * s) := by + have h2C : 2 * C ≤ K := by rw [hK]; omega + rw [hY, ← pow_add] + refine Nat.pow_le_pow_right (by norm_num) ?_ + calc C * s + C * s = 2 * C * s := by ring + _ ≤ K * s := Nat.mul_le_mul_right _ h2C + constructor + · calc _ ≤ 2 * (Y * X) * ((A₀ + 2 * c₀) * X ^ e * Y) := hT.trans (Nat.mul_le_mul hcount hinner) + _ = 2 * (A₀ + 2 * c₀) * X ^ (e + 1) * (Y * Y) := by rw [pow_succ]; ring + _ ≤ K * X ^ K * 2 ^ (K * s) := + Nat.mul_le_mul (Nat.mul_le_mul hKc (Nat.pow_le_pow_right hX1 hKe)) hKY + · have h1 : ES ≤ c₀ * X ^ e := hES ▸ Nat.mul_le_mul_left _ hXe2 + calc _ ≤ A₀ * X ^ e + c₀ * X ^ e := + hS.trans (Nat.add_le_add (hpoly.trans (Nat.mul_le_mul_left _ hXe1)) h1) + _ = (A₀ + c₀) * X ^ e := by ring + _ ≤ K * X ^ K := Nat.mul_le_mul (by omega) (Nat.pow_le_pow_right hX1 (by omega)) + +/-! ### Polynomial-time entry procedures and tables -/ + +/-- **Polynomial-time entry procedures meet the entry bounds.** For a polynomial certificate of the +entry procedure there is `C₀` such that, for every `C ≥ C₀`, a rows-first network with between +`s` and `C s` edges and degree at most `⌈s ^ (9/10)⌉` is admissible at size `s` with constant +`C`. -/ +theorem exists_entryAdmissible_of_isPolynomial + {ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)} (hce : ce.IsPolynomial) : + ∃ C₀ : ℕ, ∀ (C s r : ℕ) (G : DescribedNetwork T), C₀ ≤ C → G.IsRowsFirstBipartite r → + s ≤ G.numEdges → G.numEdges ≤ C * s → (∀ v ∈ G.vertices, v.1.length ≤ ceilNineTenths s) → + EntryAdmissible ce C s (r, G) := by + obtain ⟨ct, dt, ht⟩ := hce.1.exists_le + obtain ⟨cs, ds, hs⟩ := hce.2.exists_le + refine ⟨ct * 3 ^ dt + cs * 3 ^ ds + dt + ds + 1, fun C s r G hC hrows hsm hmC hdeg => + ⟨hrows, hsm, hmC, hdeg, fun v hv bs hbs => ?_⟩⟩ + change v ∈ G.vertices at hv + obtain ⟨B, hB⟩ : ∃ B, B = s + (DescribedNetwork.encDescribed encT G).length + 1 := ⟨_, rfl⟩ + rw [← hB] + have hB1 : 1 ≤ B := by omega + -- The argument of the procedure is at most `3 B`. + have hq : (encPair encT encBits (v.2, bs)).length + 1 ≤ 3 * B := by + have h1 := length_le_encList_of_mem (encPair (encList encNat) encT) hv + have h2 : (encList (encPair (encList encNat) encT) G.vertices).length ≤ + (DescribedNetwork.encDescribed encT G).length := by + change _ ≤ (encPair encUnary (encList (encPair (encList encNat) encT)) + (G.numEdges, G.vertices)).length + rw [length_encPair] + dsimp only + omega + have h3 := length_le_length_encList encNat v.1 + rw [length_encPair] at h1 ⊢ + change 2 * (encT v.2).length + 1 + bs.length + 1 ≤ 3 * B + omega + have hpow {c d : ℕ} : c * ((encPair encT encBits (v.2, bs)).length + 1) ^ d ≤ + c * 3 ^ d * B ^ d := by + rw [Nat.mul_assoc, ← Nat.mul_pow] + exact Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hq _) + have hBC {c d : ℕ} (hc : c ≤ C) (hd : d ≤ C) : c * B ^ d ≤ C * B ^ C := + Nat.mul_le_mul hc (Nat.pow_le_pow_right hB1 hd) + refine ⟨(ht _).trans (hpow.trans ((hBC (by omega) (by omega)).trans + (Nat.le_mul_of_pos_right _ Nat.one_le_two_pow))), (hs _).trans (hpow.trans + (hBC (by omega) (by omega)))⟩ + +/-- **The entry procedure of tables**: the table entry at the bits on the ports, as a constant +coefficient list. -/ +@[expose] def tableEntry (table : List ℕ) (bs : List Bool) : List ℕ := + [ExplicitTensorNetwork.entry table bs] + +/-- The entry procedure of tables is polynomial-time. -/ +theorem tableEntry_polyTime : + ComputableInPolyTime (fun q : List ℕ × List Bool => tableEntry q.1 q.2) + (encPair (encList encNat) encBits) (encList encNat) := by + have hindex := ComputableInPolyTime.bitsBinaryValue.comp + (ComputableInPolyTime.bitsReverse.comp (ComputableInPolyTime.snd (encList encNat) encBits)) + have hentry := ComputableInPolyTime.listGetD_binary (encA := encNat) (encL := encList encNat) 0 + (ComputableInPolyTime.fst _ _) hindex + exact (ComputableInPolyTime.cons' hentry (ComputableInPolyTime.const [])).of_enc_eq fun q => by + simp only [tableEntry, ExplicitTensorNetwork.entry, + BitString.lsbValue_eq_binaryValue_reverse, Function.comp_apply] + +/-- **The native certificate of the entry procedure of tables.** -/ +noncomputable def tableEntryCertificate : + NativeCertificate (fun q : List ℕ × List Bool => tableEntry q.1 q.2) + (encPair (encList encNat) encBits) (encList encNat) := + NativeCertificate.ofPolyTime tableEntry_polyTime + +/-- The certificate of the entry procedure of tables is polynomial. -/ +theorem tableEntryCertificate_isPolynomial : tableEntryCertificate.IsPolynomial := + NativeCertificate.ofPolyTime_isPolynomial tableEntry_polyTime + +/-- **Direct summation of a table network is its contraction**, in `A_P` at every modulus. -/ +theorem val_directCore_tableEntry (P : ℕ) (fl : List ℕ) (G : ExplicitTensorNetwork ℕ) : + val P fl (DescribedNetwork.sumValue SumOps.galois tableEntry (P, fl) G) = + (G.contraction : GaloisRingArith.Ring P fl) := by + rw [val_directCore, ← DescribedNetwork.contraction_entry] + have h := DescribedNetwork.map_contraction (Nat.castRingHom (GaloisRingArith.Ring P fl)) + ExplicitTensorNetwork.entry G + simp only [Nat.coe_castRingHom] at h + rw [h] + congr 1 + funext t bs + exact VertexDesc.val_entry_inl P fl t bs + +end EntryContraction + +end Cslib.Circuits.Frontier diff --git a/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkEntryContraction.lean b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkEntryContraction.lean new file mode 100644 index 000000000..a2e78344d --- /dev/null +++ b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkEntryContraction.lean @@ -0,0 +1,79 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: local-only (test driver) + +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.EntryContraction + +/-! +# Tests for the contraction interface with entry procedures + +`⌈s ^ (9/10)⌉` at a few sizes. Direct summation with the entry procedure of tables, on a network +of two parallel edges between a row vertex and a column vertex, computes `1 + 2 + 3 + 4 = 10`, +which is `2` in `A_3 = (ℤ / 8)[U] / (U ^ 2 + U + 1)`. That network is admissible at size `2` with +the entry procedure of tables, for some constant (`EntryAdmissible` is not vacuous). +-/ + +@[expose] public section + +namespace ComplexityTests.TensorNetworkEntryContraction + +open Cslib Cslib.Circuits.Frontier Cslib.Circuits.Frontier.EntryContraction + +/-! ### The nine-tenths power -/ + +example : ceilNineTenths 1 = 1 := + le_antisymm (ceilNineTenths_le (by norm_num)) ((le_ceilNineTenths_iff le_rfl).2 (by norm_num)) + +example : ceilNineTenths 2 = 2 := + le_antisymm (ceilNineTenths_le (by norm_num)) ((le_ceilNineTenths_iff (by norm_num)).2 + (by norm_num)) + +-- `1024 ^ (9/10) = 512` exactly. +example : ceilNineTenths 1024 = 512 := + le_antisymm (ceilNineTenths_le (by norm_num)) ((le_ceilNineTenths_iff (by norm_num)).2 + (by norm_num)) + +-- `⌈s ^ (9/10)⌉` is at most the degree bound of the schedule. +example : ceilNineTenths 1024 ≤ ContractionSchedule.degreeBound 1024 := + ceilNineTenths_le_degreeBound 1024 + +/-! ### Direct summation -/ + +/-- Two parallel edges between a row vertex with table `1, 2, 3, 4` and a column vertex of +ones. -/ +abbrev twoEdges : DescribedNetwork (List ℕ) := ⟨2, [([0, 1], [1, 2, 3, 4]), ([0, 1], [1, 1, 1, 1])]⟩ + +-- Its contraction is `10`, which is `2` modulo `8`, a constant coefficient list over +-- `(ℤ / 8)[U] / (U ^ 2 + U + 1)`. +example : DescribedNetwork.sumValue SumOps.galois tableEntry (3, [1, 1]) twoEdges = [2, 0] := by + decide + +example : ExplicitTensorNetwork.contraction (R := ℕ) twoEdges = 10 := by decide + +-- Direct summation is the contraction in `A_3`. +example : GaloisRingArith.val 3 [1, 1] + (DescribedNetwork.sumValue SumOps.galois tableEntry (3, [1, 1]) twoEdges) = + ((10 : ℕ) : GaloisRingArith.Ring 3 [1, 1]) := by + rw [val_directCore_tableEntry] + congr 1 + +/-! ### Admissibility is not vacuous -/ + +example : ∃ C, EntryAdmissible tableEntryCertificate C 2 (1, twoEdges) := by + obtain ⟨C₀, hC₀⟩ := exists_entryAdmissible_of_isPolynomial + tableEntryCertificate_isPolynomial + have h2 : ceilNineTenths 2 = 2 := + le_antisymm (ceilNineTenths_le (by norm_num)) ((le_ceilNineTenths_iff (by norm_num)).2 + (by norm_num)) + refine ⟨C₀ + 1, hC₀ (C₀ + 1) 2 1 twoEdges (by omega) (by decide) le_rfl (by simp) ?_⟩ + intro v hv + rw [h2] + simp only [List.mem_cons, List.not_mem_nil, or_false] at hv + rcases hv with rfl | rfl <;> rfl + +end ComplexityTests.TensorNetworkEntryContraction From d7f96695b19ff56e3413759533c3f94931622a8c Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 09:42:58 -0400 Subject: [PATCH 05/20] doc(Frontier/TensorNetwork): paraphrase Theorem D.1's entry hypothesis Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG --- .../Circuit/Frontier/TensorNetwork/EntryContraction.lean | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContraction.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContraction.lean index 857bf2b8d..5cf382e95 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContraction.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContraction.lean @@ -20,9 +20,10 @@ import Complexity.Foundations.Data.Nat.Asymptotics # Contraction with entry procedures: the interface Theorem D.1 of [OpenAI2026ETH] (p. 53) contracts Boolean tensor networks whose entries are not -given as tables but computed: "uniformly for every vertex and Boolean choice of its ports, … its -entry can be computed from the description in time `(s + L) ^ b 2 ^ (A s ^ (9/10))` and space -`(s + L) ^ b`", with maximum degree at most `⌈s ^ (9/10)⌉`. At that degree a table has +given as tables but computed: it assumes, uniformly over the vertices and the Boolean choices of +their ports, that each entry is computable from the description in time +`(s + L) ^ b 2 ^ (A s ^ (9/10))` and space `(s + L) ^ b` (a paraphrase), with maximum degree at +most `⌈s ^ (9/10)⌉`. At that degree a table has `2 ^ ⌈s ^ (9/10)⌉` entries, so Lemma D.2 (p. 56), which applies the theorem with entries computed by procedures, needs this form for its polynomial-space bound. This file states the interface that the contraction algorithm provides for such networks, milestone E1 of #1538. From 5cd05f4dfc8d0df1e25b769ef5661361da34ab35 Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 09:46:52 -0400 Subject: [PATCH 06/20] fix(Frontier/TensorNetwork): replace a non-terminal simp in le_ceilNineTenths_iff Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG --- .../Circuit/Frontier/TensorNetwork/EntryContraction.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContraction.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContraction.lean index 5cf382e95..3cc68d662 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContraction.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContraction.lean @@ -139,7 +139,7 @@ theorem le_ceilNineTenths_iff {s x : ℕ} (hs : 1 ≤ s) : have h1 := ceilNineTenths_le h rcases Nat.eq_zero_or_pos x with rfl | hx0 · have : 1 ≤ s ^ 9 := Nat.one_le_pow _ _ hs - simp at h + rw [Nat.zero_sub, zero_pow (by norm_num)] at h omega · omega · intro h From c75dd86d52d03a82493a85dddc453a48e6fad1d6 Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 09:47:32 -0400 Subject: [PATCH 07/20] feat(Frontier/TensorNetwork): time and space of the truncation-order reduction `engineCertificate_le` bounds the native machine of the truncation-order reduction by its calls: if each of the N + 1 charged calls takes time at most R, space at most Q and outputs at most Yb bits, the machine takes time (N + 1) (K (n + Yb + 1) ^ K + R) and space K (n + Yb + 1) ^ K + Q. `length_encCore_coreInput_le` bounds each call's input by 9 (n + 1) ^ 2, and `specEntryCertificate_le` bounds specialized entries by the original entry plus a polynomial. The certificates of `TruncatedPolyTime.lean` are exposed so that their resources can be bounded downstream, and its `PolyTime.List`/`PolyTime.Nat` imports become public because the exposed bodies use them. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG --- Complexity.lean | 1 + .../TensorNetwork/TruncatedPolyTime.lean | 21 +- .../TensorNetwork/TruncatedResources.lean | 434 ++++++++++++++++++ .../TensorNetworkTruncatedResources.lean | 78 ++++ 4 files changed, 524 insertions(+), 10 deletions(-) create mode 100644 Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedResources.lean create mode 100644 ComplexityTests/Computability/Circuit/Frontier/TensorNetworkTruncatedResources.lean diff --git a/Complexity.lean b/Complexity.lean index 2a5954850..ee64172d0 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -966,6 +966,7 @@ public import Complexity.Computability.Circuit.Frontier.TensorNetwork.ScheduledR public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TaperedRecovery public import Complexity.Computability.Circuit.Frontier.TensorNetwork.Truncated public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TruncatedPolyTime +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TruncatedResources public import Complexity.Computability.Circuit.Frontier.TensorNetwork.VertexDesc public import Complexity.Computability.Circuit.Frontier.TwoSidedWitness public import Complexity.Computability.Circuit.Frontier.Unconditional diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedPolyTime.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedPolyTime.lean index be28c99b3..e2f976d41 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedPolyTime.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedPolyTime.lean @@ -15,8 +15,8 @@ public import Complexity.Computability.Circuit.Frontier.TensorNetwork.FastContra import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimeListMap import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimeListPrimitives import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimeNatFrontends -import Complexity.Computability.Machines.Turing.MultiTape.Complexity.PolyTime.List -import Complexity.Computability.Machines.Turing.MultiTape.Complexity.PolyTime.Nat +public import Complexity.Computability.Machines.Turing.MultiTape.Complexity.PolyTime.List +public import Complexity.Computability.Machines.Turing.MultiTape.Complexity.PolyTime.Nat /-! # The reduction of truncation order `ℓ` as a native machine @@ -44,9 +44,10 @@ specialized network (`directCoreCertificate`). Through the reduction at the modu (`le_two_pow_length_modulus`), this computes the truncated contraction on every input (`truncDirectCertificate`). Its cost is that of direct summation. -No time or space bound of the loop is proved here. With the contraction of Theorem D.1 at `ℓ = 1` -over `A_P` in place of direct summation, a bound of the loop gives Theorem D.1 at truncation order -`ℓ` (#1538). +The time and space of the loop are bounded in +`Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedResources.lean`. With the +contraction of Theorem D.1 at `ℓ = 1` over `A_P` in place of direct summation, that bound gives +Theorem D.1 at truncation order `ℓ` (#1538). ## Main definitions @@ -123,7 +124,7 @@ variable (entry : T → List Bool → List ℕ) /-- **The native evaluator of specialized entries**, from a native certificate of the entries: evaluate the original entry, then apply Horner's rule in `A_P`. -/ -noncomputable def specEntryCertificate +@[expose] noncomputable def specEntryCertificate (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) (encList encNat)) : NativeCertificate (fun q : SpecDesc T × List Bool => specEntry entry q.1 q.2) @@ -317,7 +318,7 @@ theorem coreInput_polyTime : ((hP.prod (hℓ.prod (hfl.prod hζ))).prod hG)))) /-- The certificate of one round, from a certificate of the contraction over `A_P`. -/ -noncomputable def engineStepCertificate +@[expose] noncomputable def engineStepCertificate (cc : NativeCertificate core (encCore encT) (encList encNat)) : NativeCertificate (engineStep core) (encPair encNat (encPair (encEngine encT) (encList (encList encNat)))) @@ -372,7 +373,7 @@ theorem engineRecover_polyTime : `A_P` of specialized networks: the streaming loop over the digit points, keeping only the binary index, the input and the values so far, then recovery. On input `(fl, (P, ℓ, r, G))` it computes `interpContract core fl P ℓ r G`. -/ -noncomputable def engineCertificate +@[expose] noncomputable def engineCertificate (cc : NativeCertificate core (encCore encT) (encList encNat)) : NativeCertificate (fun y : List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T => DescribedNetwork.interpContract core y.1 y.2.1 y.2.2.1 y.2.2.2.1 y.2.2.2.2) @@ -390,7 +391,7 @@ noncomputable def engineCertificate /-- **Direct summation over a specialized network**, as a contraction over `A_P` with the input `(P, fl, r, G')`, from a native certificate of the entries. -/ -noncomputable def directCoreCertificate +@[expose] noncomputable def directCoreCertificate (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) (encList encNat)) : NativeCertificate @@ -454,7 +455,7 @@ theorem interpContract_direct_eq (P ℓ r : ℕ) (G : DescribedNetwork T) : `(P, ℓ, r, G)`: the reduction with direct summation over `A_P` at the modulus `FastContraction.modulus n`, for `n = (ℓ - 1) k + 1` points. It is correct everywhere; its cost is that of direct summation, exponential in the number of edges. -/ -noncomputable def truncDirectCertificate +@[expose] noncomputable def truncDirectCertificate (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) (encList encNat)) : NativeCertificate diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedResources.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedResources.lean new file mode 100644 index 000000000..eb07787e4 --- /dev/null +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedResources.lean @@ -0,0 +1,434 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TruncatedPolyTime +import Complexity.Computability.Machines.Turing.MultiTape.Encodings.Length +import Complexity.Computability.Machines.Turing.MultiTape.Complexity.LinearSpaceArith +import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimeListPrimitives +import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimeNatFrontends + +/-! +# Resources of the truncation-order reduction + +The native machine `Cslib.Circuits.Frontier.engineCertificate` of +`Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedPolyTime.lean` runs the reduction +of truncation order `ℓ` to contractions over `A_P = (ℤ / 2 ^ P)[U] / (f)`: it streams over the +`N = (ℓ - 1) k + 1` digit points, calling a given certificate of the contraction over `A_P` once per +point, and then interpolates. This file bounds its time and space by those of the calls. + +**The loop** (`Cslib.Circuits.Frontier.engineCertificate_le`). If at every point the call takes +time at most `R`, space at most `Q`, and outputs at most `Yb` bits, then the machine takes time at +most `(N + 1) (K (n + Yb + 1) ^ K + R)` and space at most `K (n + Yb + 1) ^ K + Q`, for a constant +`K` and the encoded length `n` of the input. The live state is the binary index, the input and the +values so far (`Cslib.Circuits.Frontier.length_run_engineStep_le`), and `N ≤ n ^ 2 + 1` +(`Cslib.Circuits.Frontier.pointCount_le`). + +**The calls.** The input of a call has length at most `9 (n + 1) ^ 2` +(`Cslib.Circuits.Frontier.length_encCore_coreInput_le`): the specialized network copies the +precision, the truncation order, the modulus and the point into every vertex. + +**Specialized entries** (`Cslib.Circuits.Frontier.specEntryCertificate_le`). Evaluating a +specialized entry costs the original entry plus a polynomial in the lengths of the input and of the +original entry. + +## Main results + +* `Cslib.Circuits.Frontier.engineCertificate_le`: time and space of the reduction. +* `Cslib.Circuits.Frontier.length_encCore_coreInput_le`: the size of a call. +* `Cslib.Circuits.Frontier.specEntryCertificate_le`: time and space of specialized entries. + +## References + +* [OpenAI, *The Exponential Time Hypothesis is False*][OpenAI2026ETH], Theorem D.1 (p. 53). +-/ + +public section + +namespace Cslib.Circuits.Frontier + +open Turing.MultiTapeTM Cslib.GenericRAM GaloisRingArith + +variable {T : Type} {encT : T ↪ List Bool} + +/-! ### Sizes -/ + +/-- A polynomial bound composed with a polynomially bounded size. -/ +private theorem polyBounded_comp_poly {α : Type} {size u : α → ℕ} {p : ℕ → ℕ} + (hp : Cslib.PolynomiallyBounded p) (hu : PolyBounded size u) : + PolyBounded size fun a => p (u a) := + (PolyBounded.of_polynomiallyBounded id hp).comp hu + +/-- A list of values, each at most `Yb` bits, is at most `(2 Yb + 1)` bits per value. -/ +private theorem length_encList_le_of_forall {vals : List (List ℕ)} {Yb : ℕ} + (h : ∀ v ∈ vals, (encList encNat v).length ≤ Yb) : + (encList (encList encNat) vals).length ≤ vals.length * (2 * Yb + 1) := by + rw [length_encList] + have h' := List.sum_le_length_nsmul (vals.map fun a => 2 * (encList encNat a).length + 1) + (2 * Yb + 1) fun x hx => by + obtain ⟨v, hv, rfl⟩ := List.mem_map.mp hx + have := h v hv + omega + rwa [List.length_map, smul_eq_mul] at h' + +/-- The length of an input of the reduction, by components. -/ +theorem length_encEngine (y : List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T) : + (encEngine encT y).length = 2 * (encList encNat y.1).length + 1 + + (2 * y.2.1 + 1 + (2 * y.2.2.1 + 1 + + (2 * (encNat y.2.2.2.1).length + 1 + + (DescribedNetwork.encDescribed encT y.2.2.2.2).length))) := by + simp [encEngine, encTrunc] + +/-- **The number of points is at most `n ^ 2 + 1`** for an input of length `n`: the truncation +order is in unary, and there are at most `n` vertices. -/ +theorem pointCount_le (y : List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T) : + DescribedNetwork.pointCount y.2.2.1 y.2.2.2.2 ≤ + (encEngine encT y).length * (encEngine encT y).length + 1 := by + have hk := DescribedNetwork.length_numEdges_vertices_le (encT := encT) y.2.2.2.2 + have hlen := length_encEngine (encT := encT) y + have hℓ : y.2.2.1 - 1 ≤ (encEngine encT y).length := by omega + have hv : y.2.2.2.2.vertices.length ≤ (encEngine encT y).length := by omega + exact Nat.add_le_add_right (Nat.mul_le_mul hℓ hv) 1 + +/-- The length of an encoded described network, by components. -/ +private theorem length_encDescribed {T' : Type} (encT' : T' ↪ List Bool) + (G : DescribedNetwork T') : + (DescribedNetwork.encDescribed encT' G).length = + 2 * G.numEdges + 1 + (encList (encPair (encList encNat) encT') G.vertices).length := by + simp [DescribedNetwork.encDescribed, DescribedNetwork.equivProd] + +/-- A binary-digit point has at most three bits per coordinate. -/ +private theorem length_encList_digits_le (e k : ℕ) : + (encList encNat (FastContraction.digits e k)).length ≤ 3 * e := by + rw [length_encList] + have h := List.sum_le_length_nsmul + ((FastContraction.digits e k).map fun a => 2 * (encNat a).length + 1) 3 fun x hx => by + obtain ⟨b, hb, rfl⟩ := List.mem_map.mp hx + obtain ⟨i, -, rfl⟩ := List.mem_map.mp hb + have := length_encNat_le_self (if k.testBit i then 1 else 0) + split_ifs at this ⊢ <;> omega + simpa [FastContraction.digits, mul_comm] using h + +/-- Copying the data `d` of a specialization into every vertex adds `2 |d|` bits per vertex, and +at most doubles the rest. -/ +private theorem length_encList_spec_le (vs : List (List ℕ × T)) (d : ℕ × ℕ × List ℕ × List ℕ) : + (encList (encPair (encList encNat) (encSpecDesc encT)) + (vs.map fun v => (v.1, (v.2, d)))).length ≤ + 2 * (encList (encPair (encList encNat) encT) vs).length + + vs.length * (2 * (encSpecData d).length) := by + induction vs with + | nil => simp + | cons v vs ih => + simp only [length_encList, List.map_cons, List.map_map, List.sum_cons, List.length_cons, + Function.comp_def, length_encPair, add_one_mul] at ih ⊢ + omega + +/-- **The size of a call.** The input of the contraction at a digit point is at most +`9 (n + 1) ^ 2` bits for an input of the reduction of length `n`: the specialized network copies +the precision, the truncation order, the modulus and the point, at most `3 n` bits, into each of +at most `n` vertices. -/ +theorem length_encCore_coreInput_le (y : List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T) (k : ℕ) : + (encCore encT (coreInput y k)).length ≤ 9 * ((encEngine encT y).length + 1) ^ 2 := by + obtain ⟨fl, P, ℓ, r, G⟩ := y + have hlen := length_encEngine (encT := encT) (fl, P, ℓ, r, G) + have hG := length_encDescribed encT G + have hk := DescribedNetwork.length_numEdges_vertices_le (encT := encT) G + have hζ := length_encList_digits_le fl.length k + have hfl := length_le_length_encList encNat fl + have hspec := length_encList_spec_le (encT := encT) G.vertices + (P, ℓ, fl, FastContraction.digits fl.length k) + set L := (encEngine encT (fl, P, ℓ, r, G)).length + have hd : (encSpecData (P, ℓ, fl, FastContraction.digits fl.length k)).length ≤ 3 * L := by + simp only [length_encPair, encUnary_apply, List.length_replicate] at hlen ⊢ + omega + have hkL : G.vertices.length ≤ L := by simp only at hlen; omega + have hmul : G.vertices.length * + (2 * (encSpecData (P, ℓ, fl, FastContraction.digits fl.length k)).length) ≤ L * (6 * L) := + Nat.mul_le_mul hkL (by omega) + simp only [coreInput, encCore, length_encPair, encUnary_apply, List.length_replicate, + length_encDescribed, DescribedNetwork.numEdges_specNet, DescribedNetwork.vertices_specNet] + at hspec ⊢ + simp only at hlen hG hk + nlinarith + +variable (core : ℕ × List ℕ × ℕ × DescribedNetwork (SpecDesc T) → List ℕ) + +/-- The encoding of the state of the loop: the binary index, the input and the values so far. -/ +local notation "encS" => encPair encNat (encPair (encEngine encT) (encList (encList encNat))) + +/-- **The live state of the loop.** After `j` rounds, if each of the first `j` values is at most +`Yb` bits, the state is at most `2 |j| + 2 n + 2 + j (2 Yb + 1)` bits, for the binary length `|j|` +of `j` and the length `n` of the input. -/ +theorem length_run_engineStep_le (y : List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T) {j Yb : ℕ} + (hY : ∀ k < j, (encList encNat (core (coreInput y k))).length ≤ Yb) : + (encS (IndexFold.run (engineStep core) j (y, []))).length ≤ + 2 * (encNat j).length + 2 * (encEngine encT y).length + 2 + j * (2 * Yb + 1) := by + rw [run_engineStep] + have h := length_encList_le_of_forall (vals := (List.range j).map fun k => core (coreInput y k)) + (Yb := Yb) fun v hv => by + obtain ⟨k, hk, rfl⟩ := List.mem_map.mp hv + exact hY k (List.mem_range.mp hk) + simp only [List.length_map, List.length_range] at h + simp only [length_encPair] + omega + +/-! ### The loop -/ + +/-- **Time and space of the reduction.** There is `K` such that, on an input `y` of length `n` with +`N = (ℓ - 1) k + 1` points, if at each of the indices `0, …, N` the call takes time at most `R` +and space at most `Q` and outputs at most `Yb` bits, the reduction takes time at most +`(N + 1) (K (n + Yb + 1) ^ K + R)` and space at most `K (n + Yb + 1) ^ K + Q`. (The loop charges +one more round than it runs, at the index `N`.) -/ +theorem engineCertificate_le (cc : NativeCertificate core (encCore encT) (encList encNat)) : + ∃ K : ℕ, ∀ (y : List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T) (R Q Yb : ℕ), + (∀ k ≤ DescribedNetwork.pointCount y.2.2.1 y.2.2.2.2, + cc.time (coreInput y k) ≤ R ∧ cc.space (coreInput y k) ≤ Q ∧ + (encList encNat (core (coreInput y k))).length ≤ Yb) → + (engineCertificate core cc).time y ≤ + (DescribedNetwork.pointCount y.2.2.1 y.2.2.2.2 + 1) * + (K * ((encEngine encT y).length + Yb + 1) ^ K + R) ∧ + (engineCertificate core cc).space y ≤ + K * ((encEngine encT y).length + Yb + 1) ^ K + Q := by + -- The polynomial-time pieces. + have hcN : ComputableInPolyTime + (fun y : List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T => + DescribedNetwork.pointCount y.2.2.1 y.2.2.2.2) (encEngine encT) encNat := + ComputableInPolyTime.unary_to_binary.comp pointCount_polyTime + have hcI : ComputableInPolyTime + (fun y : List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T => (y, ([] : List (List ℕ)))) + (encEngine encT) (encPair (encEngine encT) (encList (encList encNat))) := + ComputableInPolyTime.id'.prod (ComputableInPolyTime.const []) + have hcA : ComputableInPolyTime + (fun p : ℕ × ((List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T) × List (List ℕ)) => p.2.1) + encS (encEngine encT) := + (ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _) + have hcC : ComputableInPolyTime + (fun p : ℕ × ((List ℕ × ℕ × ℕ × ℕ × DescribedNetwork T) × List (List ℕ)) => p.2.2) + encS (encList (encList encNat)) := + (ComputableInPolyTime.snd _ _).comp (ComputableInPolyTime.snd _ _) + have hcB := ComputableInPolyTime.snoc (encList encNat) + obtain ⟨pN, hpN, mN, bN⟩ := exists_mono_poly_cert hcN + obtain ⟨pI, hpI, mI, bI⟩ := exists_mono_poly_cert hcI + obtain ⟨pA, hpA, mA, bA⟩ := exists_mono_poly_cert hcA + obtain ⟨pC, hpC, mC, bC⟩ := exists_mono_poly_cert hcC + obtain ⟨pB, hpB, mB, bB⟩ := exists_mono_poly_cert hcB + obtain ⟨pD, hpD, mD, bD⟩ := exists_mono_poly_cert (coreInput_polyTime (encT := encT)) + obtain ⟨pR, hpR, mR, bR⟩ := exists_mono_poly_cert (engineRecover_polyTime (encT := encT)) + -- The overhead, as a polynomial in `X = n + Yb`. + let Sh : ℕ → ℕ := fun X => 7 * (X + 1) ^ 3 + let U : ℕ → ℕ := fun X => pN X + X + pI X + 3 * Sh X + 3 * ((X + 1) ^ 2 + 1) ^ 2 + + pA (Sh X) + pC (Sh X) + pD (Sh X) + pB (2 * Sh X + 1 + X) + pR (Sh X) + have hSh : PolyBounded id Sh := + (PolyBounded.const 7).mul ((PolyBounded.self.add (PolyBounded.const 1)).pow 3) + have hU : PolyBounded id U := + (((((((((polyBounded_comp_poly hpN PolyBounded.self).add PolyBounded.self).add + (polyBounded_comp_poly hpI PolyBounded.self)).add ((PolyBounded.const 3).mul hSh)).add + ((PolyBounded.const 3).mul ((((PolyBounded.self.add (PolyBounded.const 1)).pow 2).add + (PolyBounded.const 1)).pow 2))).add (polyBounded_comp_poly hpA hSh)).add + (polyBounded_comp_poly hpC hSh)).add (polyBounded_comp_poly hpD hSh)).add + (polyBounded_comp_poly hpB ((((PolyBounded.const 2).mul hSh).add (PolyBounded.const 1)).add + PolyBounded.self))).add (polyBounded_comp_poly hpR hSh) + obtain ⟨a, d, hUad⟩ := hU.exists_le + refine ⟨a + d, fun y R Q Yb hcore => ?_⟩ + set L := (encEngine encT y).length with hL + set N := DescribedNetwork.pointCount y.2.2.1 y.2.2.2.2 with hN + set X := L + Yb with hX + have hUX : U X ≤ (a + d) * (X + 1) ^ (a + d) := by + have h1 := hUad X + have h2 : (X + 1) ^ d ≤ (X + 1) ^ (a + d) := Nat.pow_le_pow_right (by omega) (by omega) + simp only [id] at h1 + calc U X ≤ a * (X + 1) ^ d := h1 + _ ≤ (a + d) * (X + 1) ^ (a + d) := Nat.mul_le_mul (by omega) h2 + -- Sizes of the states. + have hNL : N ≤ L * L + 1 := pointCount_le y + have hNX : N ≤ (X + 1) ^ 2 := by + have : L * L ≤ X * X := Nat.mul_le_mul (by omega) (by omega) + nlinarith + let S := 2 * N + 2 * L + 2 + N * (2 * Yb + 1) + have hSSh : S ≤ Sh X := by + have h1 : N * (2 * Yb + 1) ≤ (X + 1) ^ 2 * (2 * X + 2) := Nat.mul_le_mul hNX (by omega) + have h2 : (X + 1) ^ 2 ≤ (X + 1) ^ 3 := Nat.pow_le_pow_right (by omega) (by omega) + have h3 : X + 1 ≤ (X + 1) ^ 3 := by + calc X + 1 = (X + 1) ^ 1 := (pow_one _).symm + _ ≤ (X + 1) ^ 3 := Nat.pow_le_pow_right (by omega) (by omega) + have h4 : (X + 1) ^ 2 * (2 * X + 2) = 2 * (X + 1) ^ 3 := by ring + simp only [Sh, S] + omega + have hstate (j : ℕ) (hj : j ≤ N) : + (encS (IndexFold.run (engineStep core) j (y, []))).length ≤ S := by + have h := length_run_engineStep_le (encT := encT) core y (j := j) (Yb := Yb) + fun k hk => (hcore k (by omega)).2.2 + have hj' : (encNat j).length ≤ N := (length_encNat_mono hj).trans (length_encNat_le_self N) + have hjN : j * (2 * Yb + 1) ≤ N * (2 * Yb + 1) := Nat.mul_le_mul_right _ hj + omega + -- The values so far, then the snoc input, are bounded by the state. + have hsnoc (j : ℕ) (hj : j ≤ N) : + (encPair (encList (encList encNat)) (encList encNat) + ((IndexFold.run (engineStep core) j (y, [])).2.2, + core (coreInput (IndexFold.run (engineStep core) j (y, [])).2.1 + (IndexFold.run (engineStep core) j (y, [])).1))).length ≤ 2 * S + 1 + Yb := by + have hs := hstate j hj + have hY := (hcore j hj).2.2 + rw [run_engineStep] at hs ⊢ + simp only [length_encPair] at hs ⊢ + omega + have hround_time (j : ℕ) (hj : j ≤ N) : + (IndexFold.roundCertificate (engineStepCertificate core cc)).time + (IndexFold.run (engineStep core) j (y, [])) ≤ + S + (N + 1) ^ 2 + pA (Sh X) + pC (Sh X) + pD (Sh X) + pB (2 * Sh X + 1 + X) + R := by + have hs := hstate j hj + have hsn := hsnoc j hj + simp only [IndexFold.roundCertificate, engineStepCertificate, NativeCertificate.comp_time, + NativeCertificate.prod_time] + have h1 := (bA (IndexFold.run (engineStep core) j (y, []))).1.trans (mA (hs.trans hSSh)) + have h2 := (bC (IndexFold.run (engineStep core) j (y, []))).1.trans (mC (hs.trans hSSh)) + have h3 := (bD (IndexFold.run (engineStep core) j (y, []))).1.trans (mD (hs.trans hSSh)) + have h4 := (bB _).1.trans (mB (hsn.trans (by omega : 2 * S + 1 + Yb ≤ 2 * Sh X + 1 + X))) + have hidx : (encNat (IndexFold.run (engineStep core) j (y, [])).1).length + 1 ≤ N + 1 := by + rw [IndexFold.run_index] + exact Nat.add_le_add_right ((length_encNat_mono hj).trans (length_encNat_le_self N)) 1 + have hsq := Nat.pow_le_pow_left hidx 2 + have hR := (hcore j hj).1 + rw [run_engineStep] at h1 h2 h3 h4 hs hsq ⊢ + simp only [Function.comp_apply] at h1 h2 h3 h4 hs hsq ⊢ + omega + have hround_space (j : ℕ) (hj : j ≤ N) : + (IndexFold.roundCertificate (engineStepCertificate core cc)).space + (IndexFold.run (engineStep core) j (y, [])) ≤ + S + (N + 1) + pA (Sh X) + pC (Sh X) + pD (Sh X) + pB (2 * Sh X + 1 + X) + Q := by + have hs := hstate j hj + have hsn := hsnoc j hj + simp only [IndexFold.roundCertificate, engineStepCertificate, NativeCertificate.comp_space, + NativeCertificate.prod_space] + have h1 := (bA (IndexFold.run (engineStep core) j (y, []))).2.trans (mA (hs.trans hSSh)) + have h2 := (bC (IndexFold.run (engineStep core) j (y, []))).2.trans (mC (hs.trans hSSh)) + have h3 := (bD (IndexFold.run (engineStep core) j (y, []))).2.trans (mD (hs.trans hSSh)) + have h4 := (bB _).2.trans (mB (hsn.trans (by omega : 2 * S + 1 + Yb ≤ 2 * Sh X + 1 + X))) + have hidx : (encNat (IndexFold.run (engineStep core) j (y, [])).1).length ≤ N := by + rw [IndexFold.run_index] + exact (length_encNat_mono hj).trans (length_encNat_le_self N) + have hQ := (hcore j hj).2.1 + rw [run_engineStep] at h1 h2 h3 h4 hs hidx ⊢ + simp only [Function.comp_apply] at h1 h2 h3 h4 hs hidx ⊢ + omega + -- The trajectory maxima. + have hmaxT : NativeCertificate.maxRoundTime + (IndexFold.roundCertificate (engineStepCertificate core cc)) N (0, y, []) ≤ + S + (N + 1) ^ 2 + pA (Sh X) + pC (Sh X) + pD (Sh X) + pB (2 * Sh X + 1 + X) + R := + NativeCertificate.maxRoundTime_le _ _ _ fun j hj => hround_time j hj + have hmaxS : NativeCertificate.maxRoundSpace + (IndexFold.roundCertificate (engineStepCertificate core cc)) N (0, y, []) ≤ + S + (N + 1) + pA (Sh X) + pC (Sh X) + pD (Sh X) + pB (2 * Sh X + 1 + X) + Q := + NativeCertificate.maxRoundSpace_le _ _ _ fun j hj => hround_space j hj + have hmaxL : NativeCertificate.maxStateLength encS (IndexFold.step (engineStep core)) N + (0, y, []) ≤ S := + NativeCertificate.maxStateLength_le _ _ _ _ fun j hj => hstate j hj + -- The pieces outside the loop. + have hLX : L ≤ X := by omega + have hNt := (bN y).1.trans (mN hLX) + have hNs := (bN y).2.trans (mN hLX) + have hIt := (bI y).1.trans (mI hLX) + have hIs := (bI y).2.trans (mI hLX) + have hRt := (bR (IndexFold.run (engineStep core) N (y, []))).1.trans + (mR ((hstate N le_rfl).trans hSSh)) + have hRs := (bR (IndexFold.run (engineStep core) N (y, []))).2.trans + (mR ((hstate N le_rfl).trans hSSh)) + have hNlen : (encNat N).length ≤ N := length_encNat_le_self N + have hsq : ((encNat N).length + 1) ^ 2 ≤ (N + 1) ^ 2 := Nat.pow_le_pow_left (by omega) 2 + have hNsq : (N + 1) ^ 2 ≤ ((X + 1) ^ 2 + 1) ^ 2 := Nat.pow_le_pow_left (by omega) 2 + have hN1 : N ≤ (N + 1) ^ 2 := by nlinarith + refine ⟨?_, ?_⟩ + · rw [engineCertificate, NativeCertificate.congr_time, NativeCertificate.comp_time, + IndexFold.certificate, NativeCertificate.iterate_time] + simp only [NativeCertificate.prod_time, NativeCertificate.const_time, Function.comp_apply] + rw [← hN, ← hL] + set P4 := pA (Sh X) + pC (Sh X) + pD (Sh X) + pB (2 * Sh X + 1 + X) + set A := pN X + X + pI X + pR (Sh X) + have hA : A ≤ (N + 1) * A := Nat.le_mul_of_pos_left _ (by omega) + have hB := Nat.mul_le_mul_left (N + 1) (show + NativeCertificate.maxRoundTime (IndexFold.roundCertificate (engineStepCertificate core cc)) + N (0, y, []) + + NativeCertificate.maxStateLength encS (IndexFold.step (engineStep core)) N (0, y, []) + + ((encNat N).length + 1) ^ 2 ≤ 2 * S + 2 * (N + 1) ^ 2 + P4 + R by omega) + have hsum : (N + 1) * A + (N + 1) * (2 * S + 2 * (N + 1) ^ 2 + P4 + R) = + (N + 1) * (A + 2 * S + 2 * (N + 1) ^ 2 + P4 + R) := by ring + have hC := Nat.mul_le_mul_left (N + 1) + (show A + 2 * S + 2 * (N + 1) ^ 2 + P4 + R ≤ (a + d) * (X + 1) ^ (a + d) + R by + simp only [U] at hUX + omega) + omega + · rw [engineCertificate, NativeCertificate.congr_space, NativeCertificate.comp_space, + IndexFold.certificate, NativeCertificate.iterate_space] + simp only [NativeCertificate.prod_space, NativeCertificate.const_space, Function.comp_apply] + rw [← hN, ← hL] + simp only [U] at hUX + omega + +/-! ### Specialized entries -/ + +/-- **Time and space of specialized entries.** There is `K` such that, for every entry +certificate `ce`, evaluating the specialized entry at `q = ((t, P, ℓ, fl, ζ), bs)` costs the +original entry at `(t, bs)` plus `K (n + e + 1) ^ K`, in time and in space, for the length `n` of +`q` and the length `e` of the original entry. -/ +theorem specEntryCertificate_le : + ∃ K : ℕ, ∀ (entry : T → List Bool → List ℕ) + (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) (q : SpecDesc T × List Bool), + (specEntryCertificate entry ce).time q ≤ ce.time (q.1.1, q.2) + + K * ((encPair (encSpecDesc encT) encBits q).length + + (encList encNat (entry q.1.1 q.2)).length + 1) ^ K ∧ + (specEntryCertificate entry ce).space q ≤ ce.space (q.1.1, q.2) + + K * ((encPair (encSpecDesc encT) encBits q).length + + (encList encNat (entry q.1.1 q.2)).length + 1) ^ K := by + have hcD : ComputableInPolyTime (fun q : SpecDesc T × List Bool => q.1.2) + (encPair (encSpecDesc encT) encBits) encSpecData := + (ComputableInPolyTime.snd _ _).comp (ComputableInPolyTime.fst _ _) + have hcE : ComputableInPolyTime (fun q : SpecDesc T × List Bool => (q.1.1, q.2)) + (encPair (encSpecDesc encT) encBits) (encPair encT encBits) := + ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.fst _ _)).prod + (ComputableInPolyTime.snd _ _) + obtain ⟨pD, hpD, mD, bD⟩ := exists_mono_poly_cert hcD + obtain ⟨pE, hpE, mE, bE⟩ := exists_mono_poly_cert hcE + obtain ⟨pH, hpH, mH, bH⟩ := exists_mono_poly_cert horner_polyTime + let U : ℕ → ℕ := fun Z => pD Z + pE Z + pH (2 * Z + 1) + have hU : PolyBounded id U := + ((polyBounded_comp_poly hpD PolyBounded.self).add + (polyBounded_comp_poly hpE PolyBounded.self)).add + (polyBounded_comp_poly hpH (((PolyBounded.const 2).mul PolyBounded.self).add + (PolyBounded.const 1))) + obtain ⟨a, d, hUad⟩ := hU.exists_le + refine ⟨a + d, fun entry ce q => ?_⟩ + set n := (encPair (encSpecDesc encT) encBits q).length with hn + set Z := n + (encList encNat (entry q.1.1 q.2)).length with hZ + have hUZ : U Z ≤ (a + d) * (Z + 1) ^ (a + d) := by + have h1 := hUad Z + simp only [id] at h1 + exact h1.trans (Nat.mul_le_mul (by omega) (Nat.pow_le_pow_right (by omega) (by omega))) + have hnZ : n ≤ Z := by omega + have hH : (encPair encSpecData (encList encNat) (q.1.2, entry q.1.1 q.2)).length ≤ 2 * Z + 1 := by + have : (encSpecData q.1.2).length ≤ n := by + simp only [hn, length_encPair] + omega + simp only [length_encPair] at this ⊢ + omega + simp only [U] at hUZ + have h1 := (bD q).1.trans (mD hnZ) + have h2 := (bE q).1.trans (mE hnZ) + have h3 := (bH (q.1.2, entry q.1.1 q.2)).1.trans (mH hH) + have h1' := (bD q).2.trans (mD hnZ) + have h2' := (bE q).2.trans (mE hnZ) + have h3' := (bH (q.1.2, entry q.1.1 q.2)).2.trans (mH hH) + refine ⟨?_, ?_⟩ + · simp only [specEntryCertificate, NativeCertificate.congr, NativeCertificate.comp_time, + NativeCertificate.prod_time, Function.comp_apply] + omega + · simp only [specEntryCertificate, NativeCertificate.congr, NativeCertificate.comp_space, + NativeCertificate.prod_space, Function.comp_apply] + omega + +end Cslib.Circuits.Frontier diff --git a/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkTruncatedResources.lean b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkTruncatedResources.lean new file mode 100644 index 000000000..ad0338ef5 --- /dev/null +++ b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkTruncatedResources.lean @@ -0,0 +1,78 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: local-only (test driver) + +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TruncatedResources + +/-! +# Tests for the resources of the truncation-order reduction + +Around a polynomial-time contraction over `A_P`, the reduction is polynomial-time: the calls are +polynomially long (`length_encCore_coreInput_le`), so the loop bound (`engineCertificate_le`) is a +polynomial. Specialized entries of a polynomial-time entry certificate are polynomial-time in the +input and the entry (`specEntryCertificate_le`). +-/ + +@[expose] public section + +namespace ComplexityTests.TensorNetworkTruncatedResources + +open Cslib Cslib.GenericRAM Cslib.Circuits.Frontier Turing.MultiTapeTM + +/-- A contraction over `A_P` that returns the zero coefficient list. -/ +def zeroCore (_ : ℕ × List ℕ × ℕ × DescribedNetwork (SpecDesc (List ℕ))) : List ℕ := [] + +/-- Its polynomial-time certificate. -/ +noncomputable def zeroCoreCert : + NativeCertificate zeroCore (encCore (encList encNat)) (encList encNat) := + NativeCertificate.ofPolyTime (ComputableInPolyTime.const []) + +/-- **A polynomial-time core gives a polynomial-time reduction.** -/ +example : ∃ c d : ℕ, ∀ y : List ℕ × ℕ × ℕ × ℕ × DescribedNetwork (List ℕ), + (engineCertificate zeroCore zeroCoreCert).time y ≤ + c * ((encEngine (encList encNat) y).length + 1) ^ d := by + obtain ⟨p, hp, hm, hb⟩ := exists_mono_poly_cert + (ComputableInPolyTime.const (encIn := encCore (encList encNat)) (encOut := encList encNat) + ([] : List ℕ)) + obtain ⟨K, hK⟩ := engineCertificate_le zeroCore zeroCoreCert + let L := fun y : List ℕ × ℕ × ℕ × ℕ × DescribedNetwork (List ℕ) => + (encEngine (encList encNat) y).length + have hpoly : PolyBounded L fun y => (L y * L y + 2) * + (K * (L y + 0 + 1) ^ K + p (9 * (L y + 1) ^ 2)) := + ((PolyBounded.self.mul PolyBounded.self).add (PolyBounded.const 2)).mul + (((PolyBounded.const K).mul ((PolyBounded.self.add (PolyBounded.const 0)).add + (PolyBounded.const 1) |>.pow K)).add + ((PolyBounded.of_polynomiallyBounded id hp).comp + ((PolyBounded.const 9).mul ((PolyBounded.self.add (PolyBounded.const 1)).pow 2)))) + obtain ⟨c, d, hcd⟩ := hpoly.exists_le + refine ⟨c, d, fun y => ?_⟩ + have h := (hK y (p (9 * (L y + 1) ^ 2)) (p (9 * (L y + 1) ^ 2)) 0 fun k _ => + ⟨(hb _).1.trans (hm (length_encCore_coreInput_le y k)), + (hb _).2.trans (hm (length_encCore_coreInput_le y k)), by simp [zeroCore]⟩).1 + have hN := pointCount_le (encT := encList encNat) y + have hmul := Nat.mul_le_mul_right (K * (L y + 0 + 1) ^ K + p (9 * (L y + 1) ^ 2)) + (show DescribedNetwork.pointCount y.2.2.1 y.2.2.2.2 + 1 ≤ L y * L y + 2 by + simp only [L] + omega) + exact h.trans (hmul.trans (hcd y)) + +/-- The entry certificate of descriptors that are their own entry. -/ +noncomputable def constCert : + NativeCertificate (fun q : List ℕ × List Bool => q.1) (encPair (encList encNat) encBits) + (encList encNat) := + NativeCertificate.ofPolyTime (ComputableInPolyTime.fst _ _) + +-- Specialized entries cost the original entry plus a polynomial in the input and the entry. +example : ∃ K : ℕ, ∀ q : SpecDesc (List ℕ) × List Bool, + (specEntryCertificate (fun t _ => t) constCert).time q ≤ constCert.time (q.1.1, q.2) + + K * ((encPair (encSpecDesc (encList encNat)) encBits q).length + + (encList encNat q.1.1).length + 1) ^ K := by + obtain ⟨K, hK⟩ := specEntryCertificate_le (encT := encList encNat) + exact ⟨K, fun q => (hK (fun t _ => t) constCert q).1⟩ + +end ComplexityTests.TensorNetworkTruncatedResources From 59a16a84f1a78e72dd0b5f4cc6f61657bb134972 Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 10:07:22 -0400 Subject: [PATCH 08/20] feat(Frontier/TensorNetwork): time and space of direct summation over specialized networks `directCoreCertificate_le` and `truncDirectCertificate_le` bound direct summation over a specialized network, and the truncated contraction by direct summation: with the entry certificate within time E and space ES on the vertices of a network with m edges, both take time K (n + ES + 1) ^ K 2 ^ m (E + 1) and space K (n + ES + 1) ^ K. This is the cost of the fallback branch of the truncation-order assembly. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG --- .../TensorNetwork/TruncatedResources.lean | 297 ++++++++++++++++++ 1 file changed, 297 insertions(+) diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedResources.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedResources.lean index eb07787e4..364360abc 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedResources.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedResources.lean @@ -37,11 +37,19 @@ precision, the truncation order, the modulus and the point into every vertex. specialized entry costs the original entry plus a polynomial in the lengths of the input and of the original entry. +**Direct summation** (`Cslib.Circuits.Frontier.directCoreCertificate_le`, +`Cslib.Circuits.Frontier.truncDirectCertificate_le`). If the entry certificate takes time at most +`E` and space at most `ES` on the vertices of a network with `m` edges, direct summation over a +specialized network, and the truncated contraction by direct summation, take time +`K (n + ES + 1) ^ K 2 ^ m (E + 1)` and space `K (n + ES + 1) ^ K`. + ## Main results * `Cslib.Circuits.Frontier.engineCertificate_le`: time and space of the reduction. * `Cslib.Circuits.Frontier.length_encCore_coreInput_le`: the size of a call. * `Cslib.Circuits.Frontier.specEntryCertificate_le`: time and space of specialized entries. +* `Cslib.Circuits.Frontier.directCoreCertificate_le`, + `Cslib.Circuits.Frontier.truncDirectCertificate_le`: time and space of direct summation. ## References @@ -431,4 +439,293 @@ theorem specEntryCertificate_le : NativeCertificate.prod_space, Function.comp_apply] omega +/-! ### Direct summation -/ + +/-- A vertex is no longer than its network. -/ +private theorem length_vertex_le {T' : Type} (encT' : T' ↪ List Bool) (G : DescribedNetwork T') + {v : List ℕ × T'} (hv : v ∈ G.vertices) : + (encPair (encList encNat) encT' v).length ≤ (DescribedNetwork.encDescribed encT' G).length := by + have h1 := List.le_sum_of_mem + (List.mem_map_of_mem (f := fun a => (encPair (encList encNat) encT' a).length) hv) + have h2 := sum_length_le_length_encList (encPair (encList encNat) encT') G.vertices + rw [length_encDescribed] + omega + +/-- **Time and space of direct summation over a specialized network.** There is `K` such that, +at the input `x = (P, fl, r, G')` for the network `G'` specialized at a point, of length `n`, if +the entry certificate takes time at most `E` and space at most `ES` at every vertex of the original +network `G` with `m` edges and every list of bits on its ports, then direct summation takes time +at most `K (n + ES + 1) ^ K 2 ^ m (E + 1)` and space at most `K (n + ES + 1) ^ K`. -/ +theorem directCoreCertificate_le (entry : T → List Bool → List ℕ) + (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) : + ∃ K : ℕ, ∀ (P ℓ r : ℕ) (fl ζ : List ℕ) (G : DescribedNetwork T) (E ES : ℕ), + (∀ v ∈ G.vertices, ∀ bs : List Bool, bs.length = v.1.length → + ce.time (v.2, bs) ≤ E ∧ ce.space (v.2, bs) ≤ ES) → + (directCoreCertificate entry ce).time (P, fl, r, DescribedNetwork.specNet P ℓ fl ζ G) ≤ + K * ((encCore encT (P, fl, r, DescribedNetwork.specNet P ℓ fl ζ G)).length + ES + 1) ^ K * + 2 ^ G.numEdges * (E + 1) ∧ + (directCoreCertificate entry ce).space (P, fl, r, DescribedNetwork.specNet P ℓ fl ζ G) ≤ + K * ((encCore encT (P, fl, r, DescribedNetwork.specNet P ℓ fl ζ G)).length + ES + 1) ^ + K := by + obtain ⟨cE, -, hcE⟩ := ce.computes + obtain ⟨K₃, hK₃⟩ := specEntryCertificate_le (encT := encT) + obtain ⟨cS, -, hcS⟩ := (specEntryCertificate entry ce).computes + obtain ⟨K₂, hK₂⟩ := DescribedNetwork.contractionCertificate_le (eval := specEntry entry) + SumOps.galois_polyTime (specEntryCertificate entry ce) + have hcR : ComputableInPolyTime + (fun x : ℕ × List ℕ × ℕ × DescribedNetwork (SpecDesc T) => ((x.1, x.2.1), x.2.2.2)) + (encCore encT) + (DescribedNetwork.encInput (encPair encUnary (encList encNat)) (encSpecDesc encT)) := + ((ComputableInPolyTime.fst _ _).prod + ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _))).prod + ((ComputableInPolyTime.snd _ _).comp ((ComputableInPolyTime.snd _ _).comp + (ComputableInPolyTime.snd _ _))) + obtain ⟨pS, hpS, mS, bS⟩ := exists_mono_poly_cert hcR + -- The overheads, as polynomials in `Z = n + ES`. + let Af : ℕ → ℕ := fun Z => 3 * Z + 1 + cE * (Z + 1) + 1 + let Uf : ℕ → ℕ := fun Z => K₃ * Af Z ^ K₃ + let Bf : ℕ → ℕ := fun Z => + K₂ * (2 * Z + 1 + cS * (Z + Uf Z + 1) + Z * (2 * Z + 3) + 1) ^ K₂ + let Tf : ℕ → ℕ := fun Z => pS Z + (Z + 2) * (Bf Z + 2 * Uf Z) + (Z + 2) * 2 + let Sf : ℕ → ℕ := fun Z => pS Z + Bf Z + (Z + Uf Z) + have hAp : PolyBounded id Af := + ((((PolyBounded.const 3).mul PolyBounded.self).add (PolyBounded.const 1)).add + ((PolyBounded.const cE).mul (PolyBounded.self.add (PolyBounded.const 1)))).add + (PolyBounded.const 1) + have hUp : PolyBounded id Uf := (PolyBounded.const K₃).mul (hAp.pow K₃) + have hBp : PolyBounded id Bf := + (PolyBounded.const K₂).mul ((((((PolyBounded.const 2).mul PolyBounded.self).add + (PolyBounded.const 1)).add ((PolyBounded.const cS).mul ((PolyBounded.self.add hUp).add + (PolyBounded.const 1)))).add (PolyBounded.self.mul (((PolyBounded.const 2).mul + PolyBounded.self).add (PolyBounded.const 3)))).add (PolyBounded.const 1) |>.pow K₂) + have hTSp : PolyBounded id fun Z => Tf Z + Sf Z := + ((((polyBounded_comp_poly hpS PolyBounded.self).add + ((PolyBounded.self.add (PolyBounded.const 2)).mul + (hBp.add ((PolyBounded.const 2).mul hUp)))).add + ((PolyBounded.self.add (PolyBounded.const 2)).mul (PolyBounded.const 2)))).add + (((polyBounded_comp_poly hpS PolyBounded.self).add hBp).add (PolyBounded.self.add hUp)) + obtain ⟨a, d, had⟩ := hTSp.exists_le + refine ⟨a + d, fun P ℓ r fl ζ G E ES hE => ?_⟩ + set G' := DescribedNetwork.specNet P ℓ fl ζ G with hG' + set n := (encCore encT (P, fl, r, G')).length with hn + set Z := n + ES with hZ + set X := 2 ^ G.numEdges with hX + have hX1 : 1 ≤ X := Nat.one_le_two_pow + have hG'n : (DescribedNetwork.encDescribed (encSpecDesc encT) G').length ≤ n := by + simp only [hn, encCore, length_encPair] + omega + -- The specialized entries. + have hv : ∀ v' ∈ G'.vertices, ∀ bs : List Bool, bs.length = v'.1.length → + (specEntryCertificate entry ce).time (v'.2, bs) ≤ E + Uf Z ∧ + (specEntryCertificate entry ce).space (v'.2, bs) ≤ ES + Uf Z ∧ + (encList encNat (specEntry entry v'.2 bs)).length ≤ cS * (Z + Uf Z + 1) := by + intro v' hv' bs hbs + have hvl := length_vertex_le (encSpecDesc encT) G' hv' + rw [hG', DescribedNetwork.vertices_specNet, List.mem_map] at hv' + obtain ⟨v, hvG, rfl⟩ := hv' + simp only at hbs ⊢ + obtain ⟨hEt, hEs⟩ := hE v hvG bs hbs + have hent : (encList encNat (entry v.2 bs)).length ≤ cE * (ES + 1) := + (hcE (v.2, bs)).trans (Nat.mul_le_mul_left _ (by omega)) + obtain ⟨h1, h2⟩ := hK₃ entry ce ((v.2, P, ℓ, fl, ζ), bs) + simp only at h1 h2 + have hq : (encPair (encSpecDesc encT) encBits ((v.2, P, ℓ, fl, ζ), bs)).length + + (encList encNat (entry v.2 bs)).length + 1 ≤ Af Z := by + have hports := length_le_length_encList encNat v.1 + have hcE' : cE * (ES + 1) ≤ cE * (Z + 1) := Nat.mul_le_mul_left _ (by omega) + simp only [length_encPair, encBits_apply] at hvl ⊢ + simp only [Af] + omega + have hpow : K₃ * ((encPair (encSpecDesc encT) encBits ((v.2, P, ℓ, fl, ζ), bs)).length + + (encList encNat (entry v.2 bs)).length + 1) ^ K₃ ≤ Uf Z := + Nat.mul_le_mul_left K₃ (Nat.pow_le_pow_left hq K₃) + have ht : (specEntryCertificate entry ce).time ((v.2, P, ℓ, fl, ζ), bs) ≤ E + Uf Z := + h1.trans (Nat.add_le_add hEt hpow) + have hs : (specEntryCertificate entry ce).space ((v.2, P, ℓ, fl, ζ), bs) ≤ ES + Uf Z := + h2.trans (Nat.add_le_add hEs hpow) + have hout := hcS ((v.2, P, ℓ, fl, ζ), bs) + have hZ' : ES ≤ Z := by omega + refine ⟨ht, hs, hout.trans (Nat.mul_le_mul_left _ ?_)⟩ + exact Nat.add_le_add_right (hs.trans (Nat.add_le_add_right hZ' _)) 1 + have hr : ∀ z, SumOps.galois.Reduced (P, fl) z → (encList encNat z).length ≤ Z * (2 * Z + 3) := + fun z hz => (SumOps.length_encList_le_of_galois_reduced hz).trans (by + have hfl := length_le_length_encList encNat fl + have hlen : (encList encNat fl).length + P ≤ n := by + simp only [hn, encCore, length_encPair, encUnary_apply, List.length_replicate] + omega + dsimp only + exact Nat.mul_le_mul (by omega) (by omega)) + obtain ⟨hT, hS⟩ := hK₂ ((P, fl), G') (E + Uf Z) (ES + Uf Z) (cS * (Z + Uf Z + 1)) + (Z * (2 * Z + 3)) hv hr + have hin : (DescribedNetwork.encInput (encPair encUnary (encList encNat)) (encSpecDesc encT) + ((P, fl), G')).length ≤ 2 * Z + 1 := by + have : (DescribedNetwork.encInput (encPair encUnary (encList encNat)) (encSpecDesc encT) + ((P, fl), G')).length ≤ 2 * n + 1 := by + simp only [hn, DescribedNetwork.encInput, encCore, length_encPair] + omega + omega + have hB : K₂ * ((DescribedNetwork.encInput (encPair encUnary (encList encNat)) + (encSpecDesc encT) ((P, fl), G')).length + cS * (Z + Uf Z + 1) + Z * (2 * Z + 3) + 1) ^ K₂ ≤ + Bf Z := Nat.mul_le_mul_left _ (Nat.pow_le_pow_left (by omega) _) + have hk : G'.vertices.length ≤ Z := by + have := DescribedNetwork.length_numEdges_vertices_le (encT := encSpecDesc encT) G' + omega + have hedges : G'.numEdges = G.numEdges := rfl + rw [hedges] at hT + have hfac : X * (G'.vertices.length + 1) + 1 ≤ X * (Z + 2) := by + have := Nat.mul_le_mul_left X (show G'.vertices.length + 1 ≤ Z + 1 by omega) + have e : X * (Z + 2) = X * (Z + 1) + X := by ring + omega + have hT' := hT.trans (Nat.mul_le_mul hfac (Nat.add_le_add_right hB _)) + have hRt := (bS (P, fl, r, G')).1.trans (mS (show n ≤ Z by omega)) + have hRs := (bS (P, fl, r, G')).2.trans (mS (show n ≤ Z by omega)) + have h1 := had Z + simp only [id] at h1 + have hK : a * (Z + 1) ^ d ≤ (a + d) * (Z + 1) ^ (a + d) := + Nat.mul_le_mul (by omega) (Nat.pow_le_pow_right (by omega) (by omega)) + refine ⟨?_, ?_⟩ + · simp only [directCoreCertificate, NativeCertificate.congr, NativeCertificate.comp_time, + Function.comp_apply] + -- `pS Z + X (Z + 2) (B + 2 (E + U)) ≤ X (E + 1) T`. + have hsplit : pS Z + X * (Z + 2) * (Bf Z + 2 * (E + Uf Z)) ≤ X * (Tf Z * (E + 1)) := by + have e : X * (Z + 2) * (Bf Z + 2 * (E + Uf Z)) = + X * ((Z + 2) * (Bf Z + 2 * Uf Z)) + X * ((Z + 2) * 2 * E) := by ring + have e2 : X * (Tf Z * (E + 1)) = X * (Tf Z * E) + X * Tf Z := by ring + have h3 : pS Z + X * ((Z + 2) * (Bf Z + 2 * Uf Z)) ≤ X * Tf Z := by + have := Nat.le_mul_of_pos_left (pS Z) hX1 + have e3 : X * Tf Z = X * pS Z + X * ((Z + 2) * (Bf Z + 2 * Uf Z)) + X * ((Z + 2) * 2) := + by simp only [Tf]; ring + omega + have hT2 : (Z + 2) * 2 ≤ Tf Z := by simp only [Tf]; omega + have h4 : X * ((Z + 2) * 2 * E) ≤ X * (Tf Z * E) := + Nat.mul_le_mul_left _ (Nat.mul_le_mul_right _ hT2) + omega + have hfin : X * (Tf Z * (E + 1)) ≤ (a + d) * (Z + 1) ^ (a + d) * X * (E + 1) := by + calc X * (Tf Z * (E + 1)) ≤ X * (a * (Z + 1) ^ d * (E + 1)) := + Nat.mul_le_mul_left _ (Nat.mul_le_mul_right _ (by omega)) + _ = a * (Z + 1) ^ d * X * (E + 1) := by ring + _ ≤ _ := Nat.mul_le_mul_right _ (Nat.mul_le_mul_right _ hK) + have hpS : (NativeCertificate.ofPolyTime hcR).time (P, fl, r, G') ≤ pS Z := hRt + omega + · simp only [directCoreCertificate, NativeCertificate.congr, NativeCertificate.comp_space, + Function.comp_apply] + have : Sf Z ≤ a * (Z + 1) ^ d := by omega + simp only [Sf] at this + omega + +/-- **Time and space of the truncated contraction by direct summation.** There is `K` such that, +on an input `x = (P, ℓ, r, G)` of length `n` with `m` edges, if the entry certificate takes time at +most `E` and space at most `ES` at every vertex and every list of bits on its ports, then +`truncDirectCertificate` takes time at most `K (n + ES + 1) ^ K 2 ^ m (E + 1)` and space at most +`K (n + ES + 1) ^ K`. -/ +theorem truncDirectCertificate_le (entry : T → List Bool → List ℕ) + (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) : + ∃ K : ℕ, ∀ (x : ℕ × ℕ × ℕ × DescribedNetwork T) (E ES : ℕ), + (∀ v ∈ x.2.2.2.vertices, ∀ bs : List Bool, bs.length = v.1.length → + ce.time (v.2, bs) ≤ E ∧ ce.space (v.2, bs) ≤ ES) → + (truncDirectCertificate entry ce).time x ≤ + K * ((encTrunc encT x).length + ES + 1) ^ K * 2 ^ x.2.2.2.numEdges * (E + 1) ∧ + (truncDirectCertificate entry ce).space x ≤ + K * ((encTrunc encT x).length + ES + 1) ^ K := by + obtain ⟨KA, hKA⟩ := directCoreCertificate_le entry ce + obtain ⟨cD, -, hcD⟩ := (directCoreCertificate entry ce).computes + obtain ⟨K₁, hK₁⟩ := engineCertificate_le (encT := encT) _ (directCoreCertificate entry ce) + obtain ⟨pM, hpM, mM, bM⟩ := exists_mono_poly_cert (modulusChoice_polyTime (encT := encT)) + obtain ⟨cY, dY, hY⟩ := (modulusChoice_polyTime (encT := encT)).polyBounded_length.exists_le + -- The overheads, as polynomials in `W = n + ES`. + let Yf : ℕ → ℕ := fun W => cY * (W + 1) ^ dY + let Rf : ℕ → ℕ := fun W => KA * (9 * (Yf W + 1) ^ 2 + W + 1) ^ KA + let Engf : ℕ → ℕ := fun W => K₁ * (Yf W + cD * (Rf W + 1) + 1) ^ K₁ + let Tf : ℕ → ℕ := fun W => pM W + (Yf W * Yf W + 2) * (Engf W + Rf W) + let Sf : ℕ → ℕ := fun W => pM W + (Engf W + Rf W) + have hYp : PolyBounded id Yf := + (PolyBounded.const cY).mul ((PolyBounded.self.add (PolyBounded.const 1)).pow dY) + have hRp : PolyBounded id Rf := + (PolyBounded.const KA).mul (((((PolyBounded.const 9).mul ((hYp.add + (PolyBounded.const 1)).pow 2)).add PolyBounded.self).add (PolyBounded.const 1)).pow KA) + have hEngp : PolyBounded id Engf := + (PolyBounded.const K₁).mul (((hYp.add ((PolyBounded.const cD).mul + (hRp.add (PolyBounded.const 1)))).add (PolyBounded.const 1)).pow K₁) + have hTSp : PolyBounded id fun W => Tf W + Sf W := + ((polyBounded_comp_poly hpM PolyBounded.self).add + (((hYp.mul hYp).add (PolyBounded.const 2)).mul (hEngp.add hRp))).add + ((polyBounded_comp_poly hpM PolyBounded.self).add (hEngp.add hRp)) + obtain ⟨a, d, had⟩ := hTSp.exists_le + refine ⟨a + d, fun x E ES hE => ?_⟩ + obtain ⟨P, ℓ, r, G⟩ := x + set n := (encTrunc encT (P, ℓ, r, G)).length with hn + set W := n + ES with hW + set X := 2 ^ G.numEdges with hX + have hX1 : 1 ≤ X := Nat.one_le_two_pow + set fl := FastContraction.modulus (DescribedNetwork.pointCount ℓ G) with hfl + have hLy : (encEngine encT (fl, P, ℓ, r, G)).length ≤ Yf W := (hY (P, ℓ, r, G)).trans + (Nat.mul_le_mul_left _ (Nat.pow_le_pow_left (by omega) _)) + have hNy : DescribedNetwork.pointCount ℓ G + 1 ≤ Yf W * Yf W + 2 := by + have h1 := pointCount_le (encT := encT) (fl, P, ℓ, r, G) + have h2 := Nat.mul_le_mul hLy hLy + dsimp only at h1 + omega + -- The calls of the loop. + have hcall (k : ℕ) : + (directCoreCertificate entry ce).time (coreInput (fl, P, ℓ, r, G) k) ≤ Rf W * X * (E + 1) ∧ + (directCoreCertificate entry ce).space (coreInput (fl, P, ℓ, r, G) k) ≤ Rf W ∧ + (encList encNat (DescribedNetwork.sumValue SumOps.galois (specEntry entry) + ((coreInput (fl, P, ℓ, r, G) k).1, (coreInput (fl, P, ℓ, r, G) k).2.1) + (coreInput (fl, P, ℓ, r, G) k).2.2.2)).length ≤ cD * (Rf W + 1) := by + have hc := length_encCore_coreInput_le (encT := encT) (fl, P, ℓ, r, G) k + have hci : coreInput (fl, P, ℓ, r, G) k = + (P, fl, r, DescribedNetwork.specNet P ℓ fl (FastContraction.digits fl.length k) G) := rfl + rw [hci] at hc ⊢ + obtain ⟨hT, hS⟩ := hKA P ℓ r fl (FastContraction.digits fl.length k) G E ES hE + have hR : KA * ((encCore encT (P, fl, r, DescribedNetwork.specNet P ℓ fl + (FastContraction.digits fl.length k) G)).length + ES + 1) ^ KA ≤ Rf W := by + refine Nat.mul_le_mul_left _ (Nat.pow_le_pow_left ?_ _) + have : 9 * ((encEngine encT (fl, P, ℓ, r, G)).length + 1) ^ 2 ≤ 9 * (Yf W + 1) ^ 2 := + Nat.mul_le_mul_left _ (Nat.pow_le_pow_left (by omega) _) + omega + have hS' := hS.trans hR + refine ⟨hT.trans (Nat.mul_le_mul_right _ (Nat.mul_le_mul_right _ hR)), hS', ?_⟩ + have hout := hcD + (P, fl, r, DescribedNetwork.specNet P ℓ fl (FastContraction.digits fl.length k) G) + exact hout.trans (Nat.mul_le_mul_left _ (Nat.add_le_add_right hS' 1)) + obtain ⟨hTe, hSe⟩ := hK₁ (fl, P, ℓ, r, G) _ _ _ fun k _ => hcall k + dsimp only at hTe hSe + have hEng : K₁ * ((encEngine encT (fl, P, ℓ, r, G)).length + cD * (Rf W + 1) + 1) ^ K₁ ≤ + Engf W := Nat.mul_le_mul_left _ (Nat.pow_le_pow_left (by omega) _) + have hMt := (bM (P, ℓ, r, G)).1.trans (mM (show n ≤ W by omega)) + have hMs := (bM (P, ℓ, r, G)).2.trans (mM (show n ≤ W by omega)) + have h1 := had W + simp only [id] at h1 + have hK : a * (W + 1) ^ d ≤ (a + d) * (W + 1) ^ (a + d) := + Nat.mul_le_mul (by omega) (Nat.pow_le_pow_right (by omega) (by omega)) + refine ⟨?_, ?_⟩ + · simp only [truncDirectCertificate, NativeCertificate.congr, NativeCertificate.comp_time] + have hTe' := hTe.trans (Nat.mul_le_mul hNy (Nat.add_le_add_right hEng _)) + have hsum : pM W + (Yf W * Yf W + 2) * (Engf W + Rf W * X * (E + 1)) ≤ + X * (E + 1) * Tf W := by + have hXE : 1 ≤ X * (E + 1) := Nat.one_le_iff_ne_zero.mpr (by positivity) + have h2 : pM W + (Yf W * Yf W + 2) * Engf W ≤ + X * (E + 1) * (pM W + (Yf W * Yf W + 2) * Engf W) := Nat.le_mul_of_pos_left _ hXE + have e1 : (Yf W * Yf W + 2) * (Engf W + Rf W * X * (E + 1)) = + (Yf W * Yf W + 2) * Engf W + X * (E + 1) * ((Yf W * Yf W + 2) * Rf W) := by ring + have e2 : X * (E + 1) * Tf W = X * (E + 1) * (pM W + (Yf W * Yf W + 2) * Engf W) + + X * (E + 1) * ((Yf W * Yf W + 2) * Rf W) := by simp only [Tf]; ring + omega + have hfin : X * (E + 1) * Tf W ≤ (a + d) * (W + 1) ^ (a + d) * X * (E + 1) := by + calc X * (E + 1) * Tf W ≤ X * (E + 1) * (a * (W + 1) ^ d) := + Nat.mul_le_mul_left _ (by omega) + _ ≤ X * (E + 1) * ((a + d) * (W + 1) ^ (a + d)) := Nat.mul_le_mul_left _ hK + _ = (a + d) * (W + 1) ^ (a + d) * X * (E + 1) := by ring + change (NativeCertificate.ofPolyTime modulusChoice_polyTime).time (P, ℓ, r, G) + + (engineCertificate _ (directCoreCertificate entry ce)).time (fl, P, ℓ, r, G) ≤ _ + omega + · simp only [truncDirectCertificate, NativeCertificate.congr, NativeCertificate.comp_space] + change (NativeCertificate.ofPolyTime modulusChoice_polyTime).space (P, ℓ, r, G) + + (engineCertificate _ (directCoreCertificate entry ce)).space (fl, P, ℓ, r, G) ≤ _ + have : Sf W ≤ a * (W + 1) ^ d := by omega + simp only [Sf] at this + omega + end Cslib.Circuits.Frontier From 105f481d09013586f428a754c8d41a0d5104f7b8 Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 10:07:23 -0400 Subject: [PATCH 09/20] =?UTF-8?q?feat(Frontier/TensorNetwork):=20Theorem?= =?UTF-8?q?=20D.1=20at=20truncation=20order=20=E2=84=93=20from=20a=20contr?= =?UTF-8?q?action=20over=20A=5FP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `TruncatedContractionAlgorithm` states Theorem D.1 at truncation order ℓ for described networks, in the shape of `ContractionAlgorithm`. `TruncatedContractionAlgorithm.ofCore` assembles it from a contraction over A_P of the specialized networks that is correct at the modulus of the number of edges and meets the interface's bound (the planned E1 interface of #1538): it branches on `truncGuard`, whether the modulus has enough residues for the interpolation points, to the reduction around the contraction or to direct summation. `truncGuard_of_le` shows that admissible inputs take the first branch once s ≥ 4 (C D + 1). A test instance for networks with boundedly many edges shows that the interface is not vacuous. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG --- Complexity.lean | 1 + .../TensorNetwork/TruncatedAlgorithm.lean | 445 ++++++++++++++++++ .../TensorNetworkTruncatedAlgorithm.lean | 108 +++++ 3 files changed, 554 insertions(+) create mode 100644 Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedAlgorithm.lean create mode 100644 ComplexityTests/Computability/Circuit/Frontier/TensorNetworkTruncatedAlgorithm.lean diff --git a/Complexity.lean b/Complexity.lean index ee64172d0..dc2251c14 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -965,6 +965,7 @@ public import Complexity.Computability.Circuit.Frontier.TensorNetwork.ScheduleCo public import Complexity.Computability.Circuit.Frontier.TensorNetwork.ScheduledRecursion public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TaperedRecovery public import Complexity.Computability.Circuit.Frontier.TensorNetwork.Truncated +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TruncatedAlgorithm public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TruncatedPolyTime public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TruncatedResources public import Complexity.Computability.Circuit.Frontier.TensorNetwork.VertexDesc diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedAlgorithm.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedAlgorithm.lean new file mode 100644 index 000000000..756451d70 --- /dev/null +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedAlgorithm.lean @@ -0,0 +1,445 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TruncatedResources +import Complexity.Computability.Circuit.Frontier.TensorNetwork.FastContractionPolyTime +import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimeListPrimitives +import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimeNatFrontends +import Complexity.Computability.Machines.Turing.MultiTape.Complexity.PolyTime.Nat.Binary + +/-! +# Theorem D.1 at truncation order `ℓ`, from a contraction over `A_P` + +Theorem D.1 of [OpenAI2026ETH] (p. 53) contracts networks whose entries lie in +`B_{P,ℓ} = (ℤ / 2 ^ P)[V] / (V ^ ℓ)`. This file states its interface for described networks +(`Cslib.Circuits.Frontier.TruncatedContractionAlgorithm`) and assembles it +(`Cslib.Circuits.Frontier.TruncatedContractionAlgorithm.ofCore`) from a native contraction over +`A_P = (ℤ / 2 ^ P)[U] / (f)` of the specialized networks, at the modulus +`f = FastContraction.modulus m` of a network with `m` edges. + +**The interface.** One native certificate computes the truncated contraction +(`DescribedNetwork.truncContraction`) from `(P, ℓ, r, G)`, with `P` and `ℓ` in unary. For all +constants `C` and `D` there is `K` such that, on every network admissible at a size `s ≥ 2` with +constant `C`, and every `1 ≤ P, ℓ ≤ D s`, it takes time at most +`K (n + 1) ^ K 2 ^ (K s / √⌊log₂ s⌋)` and space at most `K (n + 1) ^ K`, for the encoded length `n` +of the input. This is the shape of `Cslib.Complexity.CountingSimulation.ContractionAlgorithm`. + +**The assembly** branches on whether the modulus has enough residues for the +`N = (ℓ - 1) k + 1` interpolation points (`Cslib.Circuits.Frontier.truncGuard`): +* if `N ≤ 2 ^ deg f`, it runs the reduction of truncation order `ℓ` to `A_P` + (`engineCertificate`) around the given contraction over `A_P` + (`Cslib.Circuits.Frontier.fastTruncCertificate`); +* otherwise it sums directly (`truncDirectCertificate`). + +On admissible inputs with `k ≤ C s` vertices, `s ≤ m` and `ℓ ≤ D s`, the first branch is taken once +`s ≥ 4 (C D + 1)` (`Cslib.Circuits.Frontier.truncGuard_of_le`), since `deg f ≥ 4 ⌊log₂ m⌋`. Below +that size, direct summation costs a constant factor. + +**The hypotheses on the contraction over `A_P`** are those of the interface planned in #1538 for +milestone E1: it is correct on every network at the modulus of its number of edges, and meets the +bound of the interface on the networks admissible for it. The assembly also asks that the +specialized networks of admissible networks be admissible for it, and that the entries be computed +within time `poly(L) 2 ^ O(s)` and polynomial space for the encoded length `L` of the network (for +the small sizes). The reduction itself is ours, not the manuscript's; see +`Complexity/Computability/Circuit/Frontier/TensorNetwork/Truncated.lean`. + +## Main definitions + +* `Cslib.Circuits.Frontier.TruncatedContractionAlgorithm`: the interface. +* `Cslib.Circuits.Frontier.truncGuard`: whether the modulus has enough residues. +* `Cslib.Circuits.Frontier.fastTruncCertificate`: the reduction at the modulus of the network. +* `Cslib.Circuits.Frontier.TruncatedContractionAlgorithm.ofCore`: the assembly. + +## Main results + +* `Cslib.Circuits.Frontier.truncGuard_polyTime`: the guard is polynomial-time. +* `Cslib.Circuits.Frontier.truncGuard_of_le`: admissible inputs pass the guard from some size on. +* `Cslib.Circuits.Frontier.fastTruncCertificate_correct`: the reduction is correct on guarded + inputs. + +## References + +* [OpenAI, *The Exponential Time Hypothesis is False*][OpenAI2026ETH], Theorem D.1 (p. 53). +-/ + +public section + +namespace Cslib.Circuits.Frontier + +open Turing.MultiTapeTM Cslib.GenericRAM GaloisRingArith + +variable {T : Type} {encT : T ↪ List Bool} + +/-- **The interface of Theorem D.1 at truncation order `ℓ`** for described networks. One native +certificate computes the truncated contraction from `(P, ℓ, r, G)`, with `P` and `ℓ` in unary. For +all constants `C` and `D` there is `K` such that, on every network admissible at a size `s ≥ 2` +with constant `C`, and every `1 ≤ P, ℓ ≤ D s`, the certificate's time is at most +`K (n + 1) ^ K 2 ^ (K s / √⌊log₂ s⌋)` and its space at most `K (n + 1) ^ K`, where `n` is the +encoded length of the input. Outside admissible inputs the certificate need only be correct. -/ +structure TruncatedContractionAlgorithm (encT : T ↪ List Bool) (entry : T → List Bool → List ℕ) + (Admissible : ℕ → ℕ → ℕ × DescribedNetwork T → Prop) where + /-- The native truncated contraction. -/ + certificate : NativeCertificate + (fun x : ℕ × ℕ × ℕ × DescribedNetwork T => x.2.2.2.truncContraction entry x.1 x.2.1) + (encTrunc encT) (encList encNat) + /-- Its time and space on admissible inputs. -/ + bound : ∀ C D : ℕ, ∃ K : ℕ, ∀ (s P ℓ r : ℕ) (G : DescribedNetwork T), 2 ≤ s → 1 ≤ P → + P ≤ D * s → 1 ≤ ℓ → ℓ ≤ D * s → Admissible C s (r, G) → + certificate.time (P, ℓ, r, G) ≤ K * ((encTrunc encT (P, ℓ, r, G)).length + 1) ^ K * + 2 ^ (K * s / Nat.sqrt (Nat.log 2 s)) ∧ + certificate.space (P, ℓ, r, G) ≤ K * ((encTrunc encT (P, ℓ, r, G)).length + 1) ^ K + +/-- A polynomial bound composed with a polynomially bounded size. -/ +private theorem polyBounded_comp_poly {α : Type} {size u : α → ℕ} {p : ℕ → ℕ} + (hp : Cslib.PolynomiallyBounded p) (hu : PolyBounded size u) : + PolyBounded size fun a => p (u a) := + (PolyBounded.of_polynomiallyBounded id hp).comp hu + +/-! ### The guard -/ + +/-- **The guard**: the modulus `FastContraction.modulus m` of the network has at least as many +residues as the `(ℓ - 1) k + 1` interpolation points. -/ +@[expose] def truncGuard (x : ℕ × ℕ × ℕ × DescribedNetwork T) : Bool := + decide (DescribedNetwork.pointCount x.2.1 x.2.2.2 ≤ + 2 ^ (FastContraction.modulus x.2.2.2.numEdges).length) + +/-- The network of an input. -/ +private theorem network_polyTime : + ComputableInPolyTime (fun x : ℕ × ℕ × ℕ × DescribedNetwork T => x.2.2.2) (encTrunc encT) + (DescribedNetwork.encDescribed encT) := + (ComputableInPolyTime.snd _ _).comp ((ComputableInPolyTime.snd _ _).comp + (ComputableInPolyTime.snd _ _)) + +/-- **The guard is polynomial-time.** -/ +theorem truncGuard_polyTime : + ComputableInPolyTime (truncGuard (T := T)) (encTrunc encT) encBool := by + have hpc : ComputableInPolyTime + (fun x : ℕ × ℕ × ℕ × DescribedNetwork T => DescribedNetwork.pointCount x.2.1 x.2.2.2) + (encTrunc encT) encNat := + ComputableInPolyTime.unary_to_binary.comp (pointCount_polyTime (encT := encT).comp + ((ComputableInPolyTime.const ([] : List ℕ)).prod ComputableInPolyTime.id')) + have h2 : ComputableInPolyTime + (fun x : ℕ × ℕ × ℕ × DescribedNetwork T => + 2 ^ (FastContraction.modulus x.2.2.2.numEdges).length) (encTrunc encT) encNat := + ComputableInPolyTime.binary_two_pow.comp ((ComputableInPolyTime.length_list _).comp + (FastContraction.modulus_polyTime.comp + (DescribedNetwork.numEdges_polyTime.comp network_polyTime))) + refine (ComputableInPolyTime.bool_not.comp (ComputableInPolyTime.binary_lt' h2 hpc)).of_enc_eq + fun x => congrArg encBool ?_ + simp only [truncGuard, Function.comp_apply] + by_cases h : DescribedNetwork.pointCount x.2.1 x.2.2.2 ≤ + 2 ^ (FastContraction.modulus x.2.2.2.numEdges).length + · simp [h, Nat.not_lt.mpr h] + · simp [h, Nat.lt_of_not_le h] + +/-- **Admissible inputs pass the guard from some size on.** With at most `C s` vertices, at least +`s` edges and `ℓ ≤ D s`, the guard holds once `s ≥ 4 (C D + 1)`: the modulus has degree at least +`4 ⌊log₂ m⌋`, so more than `m ^ 4 / 16 ≥ C D s ^ 2 + 1` residues. -/ +theorem truncGuard_of_le {C D s P ℓ r : ℕ} {G : DescribedNetwork T} (hs : 4 * (C * D + 1) ≤ s) + (hℓ : ℓ ≤ D * s) (hk : G.vertices.length ≤ C * s) (hm : s ≤ G.numEdges) : + truncGuard (P, ℓ, r, G) = true := by + simp only [truncGuard, decide_eq_true_eq] + set m := G.numEdges + have hlog : m < 2 ^ (Nat.log 2 m + 1) := Nat.lt_pow_succ_log_self one_lt_two m + have h4 : m ^ 4 < 2 ^ (4 * Nat.log 2 m) * 16 := by + calc m ^ 4 < (2 ^ (Nat.log 2 m + 1)) ^ 4 := Nat.pow_lt_pow_left hlog (by norm_num) + _ = 2 ^ (4 * Nat.log 2 m) * 16 := by rw [← pow_mul]; ring + have h5 : 2 ^ (4 * Nat.log 2 m) ≤ 2 ^ (FastContraction.modulus m).length := + Nat.pow_le_pow_right (by norm_num) (FastContraction.four_mul_log_le_length_modulus m) + have hsm : s ^ 4 ≤ m ^ 4 := Nat.pow_le_pow_left hm 4 + have hpc : DescribedNetwork.pointCount ℓ G ≤ D * s * (C * s) + 1 := by + have : (ℓ - 1) * G.vertices.length ≤ D * s * (C * s) := + Nat.mul_le_mul (by omega) hk + simp only [DescribedNetwork.pointCount] + omega + have hss : 16 * (C * D + 1) ≤ s * s := by nlinarith + have hkey : 16 * (D * s * (C * s) + 1) ≤ s ^ 4 := by + have e : s ^ 4 = s * s * (s * s) := by ring + have e2 : D * s * (C * s) = C * D * (s * s) := by ring + rw [e, e2] + have h1 : 1 ≤ s * s := by nlinarith + nlinarith + omega + +/-! ### The fast branch -/ + +/-- The input of the reduction at the modulus of the network. -/ +theorem modulusEdges_polyTime : + ComputableInPolyTime + (fun x : ℕ × ℕ × ℕ × DescribedNetwork T => + (FastContraction.modulus x.2.2.2.numEdges, x)) + (encTrunc encT) (encEngine encT) := + (FastContraction.modulus_polyTime.comp + (DescribedNetwork.numEdges_polyTime.comp network_polyTime)).prod ComputableInPolyTime.id' + +variable {core : ℕ × List ℕ × ℕ × DescribedNetwork (SpecDesc T) → List ℕ} + +/-- **The reduction at the modulus of the network**: the native reduction of truncation order `ℓ` +to contractions over `A_P`, with the modulus `FastContraction.modulus m` for `m` edges. -/ +@[expose] noncomputable def fastTruncCertificate + (cc : NativeCertificate core (encCore encT) (encList encNat)) : + NativeCertificate + (fun x : ℕ × ℕ × ℕ × DescribedNetwork T => + DescribedNetwork.interpContract core (FastContraction.modulus x.2.2.2.numEdges) x.1 x.2.1 + x.2.2.1 x.2.2.2) + (encTrunc encT) (encList encNat) := + ((engineCertificate core cc).comp (NativeCertificate.ofPolyTime modulusEdges_polyTime)).congr + fun _ => by simp only [Function.comp_apply] + +/-- **The reduction is correct on guarded inputs**, for a contraction over `A_P` that is correct +at the modulus of the number of edges. -/ +theorem fastTruncCertificate_correct {entry : T → List Bool → List ℕ} + (hval : ∀ (P r : ℕ) (G' : DescribedNetwork (SpecDesc T)), + val P (FastContraction.modulus G'.numEdges) (core (P, FastContraction.modulus G'.numEdges, + r, G')) = + G'.contraction fun d bs => + val P (FastContraction.modulus G'.numEdges) (specEntry entry d bs)) + (x : ℕ × ℕ × ℕ × DescribedNetwork T) (hg : truncGuard x = true) : + DescribedNetwork.interpContract core (FastContraction.modulus x.2.2.2.numEdges) x.1 x.2.1 + x.2.2.1 x.2.2.2 = x.2.2.2.truncContraction entry x.1 x.2.1 := by + simp only [truncGuard, decide_eq_true_eq] at hg + refine DescribedNetwork.interpContract_eq (FastContraction.irreducible_modulus _) _ hg + fun k _ => ?_ + have h := hval x.1 x.2.2.1 (DescribedNetwork.specNet x.1 x.2.1 + (FastContraction.modulus x.2.2.2.numEdges) + (FastContraction.digits (FastContraction.modulus x.2.2.2.numEdges).length k) x.2.2.2) + rw [DescribedNetwork.numEdges_specNet] at h + exact h + +/-! ### The assembly -/ + +/-- **Theorem D.1 at truncation order `ℓ`, from a contraction over `A_P`.** Let `cc` be a native +contraction over `A_P` of specialized networks that is correct on every network at the modulus +`FastContraction.modulus m` of its number `m` of edges (`hval`) and meets the interface's bound on +the networks admissible for it (`hcore`, for an admissibility `CoreAdm`). Suppose that the networks +specialized at the digit points of admissible networks are admissible for it (`htransfer`), that +admissible networks have between `s` and `C s` edges and at most `C s` vertices (`hshape`), and +that the entries take time `K (L + 1) ^ K 2 ^ (K s)` and space `K (L + 1) ^ K` on admissible +networks of encoded length `L` (`hentry`). Then branching on `truncGuard` to the reduction around +`cc` or to direct summation is a truncated contraction algorithm. -/ +noncomputable def TruncatedContractionAlgorithm.ofCore {entry : T → List Bool → List ℕ} + {Adm : ℕ → ℕ → ℕ × DescribedNetwork T → Prop} + {CoreAdm : ℕ → ℕ → ℕ × DescribedNetwork (SpecDesc T) → Prop} + (cc : NativeCertificate core (encCore encT) (encList encNat)) + (hval : ∀ (P r : ℕ) (G' : DescribedNetwork (SpecDesc T)), + val P (FastContraction.modulus G'.numEdges) (core (P, FastContraction.modulus G'.numEdges, + r, G')) = + G'.contraction fun d bs => + val P (FastContraction.modulus G'.numEdges) (specEntry entry d bs)) + (hcore : ∀ C D : ℕ, ∃ K : ℕ, ∀ (s P r : ℕ) (G' : DescribedNetwork (SpecDesc T)), 2 ≤ s → + 1 ≤ P → P ≤ D * s → CoreAdm C s (r, G') → + cc.time (P, FastContraction.modulus G'.numEdges, r, G') ≤ + K * ((encCore encT (P, FastContraction.modulus G'.numEdges, r, G')).length + 1) ^ K * + 2 ^ (K * s / Nat.sqrt (Nat.log 2 s)) ∧ + cc.space (P, FastContraction.modulus G'.numEdges, r, G') ≤ + K * ((encCore encT (P, FastContraction.modulus G'.numEdges, r, G')).length + 1) ^ K) + (htransfer : ∀ C D : ℕ, ∃ C' : ℕ, ∀ (s P ℓ r k : ℕ) (G : DescribedNetwork T), 2 ≤ s → + 1 ≤ P → P ≤ D * s → 1 ≤ ℓ → ℓ ≤ D * s → Adm C s (r, G) → + CoreAdm C' s (r, DescribedNetwork.specNet P ℓ (FastContraction.modulus G.numEdges) + (FastContraction.digits (FastContraction.modulus G.numEdges).length k) G)) + (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) + (hentry : ∀ C : ℕ, ∃ K : ℕ, ∀ (s r : ℕ) (G : DescribedNetwork T), Adm C s (r, G) → + ∀ v ∈ G.vertices, ∀ bs : List Bool, bs.length = v.1.length → + ce.time (v.2, bs) ≤ + K * ((DescribedNetwork.encDescribed encT G).length + 1) ^ K * 2 ^ (K * s) ∧ + ce.space (v.2, bs) ≤ K * ((DescribedNetwork.encDescribed encT G).length + 1) ^ K) + (hshape : ∀ C s r G, Adm C s (r, G) → + s ≤ G.numEdges ∧ G.numEdges ≤ C * s ∧ G.vertices.length ≤ C * s) : + TruncatedContractionAlgorithm encT entry Adm where + certificate := + (NativeCertificate.branch (NativeCertificate.ofPolyTime truncGuard_polyTime) + (fastTruncCertificate cc) (truncDirectCertificate entry ce)).congr fun x => by + split + · next h => exact fastTruncCertificate_correct hval x h + · rfl + bound C D := by + obtain ⟨C', hC'⟩ := htransfer C D + obtain ⟨K₀, hK₀⟩ := hcore C' D + obtain ⟨Ke, hKe⟩ := hentry C + obtain ⟨Kd, hKd⟩ := truncDirectCertificate_le entry ce + obtain ⟨KE, hKE⟩ := engineCertificate_le (encT := encT) core cc + obtain ⟨cO, -, hcO⟩ := cc.computes + obtain ⟨pg, hpg, mg, bg⟩ := exists_mono_poly_cert (truncGuard_polyTime (encT := encT)) + obtain ⟨pM, hpM, mM, bM⟩ := exists_mono_poly_cert (modulusEdges_polyTime (encT := encT)) + obtain ⟨cY, dY, hY⟩ := (modulusEdges_polyTime (encT := encT)).polyBounded_length.exists_le + set s₀ := 4 * (C * D + 1) with hs₀ + -- The overheads, as polynomials in the length `n` of the input. + let Yf : ℕ → ℕ := fun n => cY * (n + 1) ^ dY + let Qf : ℕ → ℕ := fun n => K₀ * (9 * (Yf n + 1) ^ 2 + 1) ^ K₀ + let F1 : ℕ → ℕ := fun n => pM n + (Yf n * Yf n + 2) * + (KE * (Yf n + cO * (Qf n + 1) + 1) ^ KE + Qf n) + let Ef : ℕ → ℕ := fun n => Ke * (n + 1) ^ Ke + let F2 : ℕ → ℕ := fun n => + Kd * (n + Ef n + 1) ^ Kd * 2 ^ (C * s₀) * (Ef n * 2 ^ (Ke * s₀) + 1) + let F : ℕ → ℕ := fun n => pg n + F1 n + F2 n + have hYp : PolyBounded id Yf := + (PolyBounded.const cY).mul ((PolyBounded.self.add (PolyBounded.const 1)).pow dY) + have hQp : PolyBounded id Qf := + (PolyBounded.const K₀).mul (((PolyBounded.const 9).mul ((hYp.add + (PolyBounded.const 1)).pow 2)).add (PolyBounded.const 1) |>.pow K₀) + have hEp : PolyBounded id Ef := + (PolyBounded.const Ke).mul ((PolyBounded.self.add (PolyBounded.const 1)).pow Ke) + have hFp : PolyBounded id F := + ((polyBounded_comp_poly hpg PolyBounded.self).add + ((polyBounded_comp_poly hpM PolyBounded.self).add (((hYp.mul hYp).add + (PolyBounded.const 2)).mul (((PolyBounded.const KE).mul (((hYp.add + ((PolyBounded.const cO).mul (hQp.add (PolyBounded.const 1)))).add + (PolyBounded.const 1)).pow KE)).add hQp)))).add + ((((PolyBounded.const Kd).mul (((PolyBounded.self.add hEp).add + (PolyBounded.const 1)).pow Kd)).mul (PolyBounded.const (2 ^ (C * s₀)))).mul + ((hEp.mul (PolyBounded.const (2 ^ (Ke * s₀)))).add (PolyBounded.const 1))) + obtain ⟨a, d, had⟩ := hFp.exists_le + refine ⟨a + d + K₀, fun s P ℓ r G hs hP hPD hℓ hℓD hA => ?_⟩ + obtain ⟨hsm, hmC, hkC⟩ := hshape C s r G hA + set n := (encTrunc encT (P, ℓ, r, G)).length with hn + set Xs := 2 ^ (K₀ * s / Nat.sqrt (Nat.log 2 s)) with hXs + have hXs1 : 1 ≤ Xs := Nat.one_le_two_pow + have hFn := had n + simp only [id] at hFn + have hK : a * (n + 1) ^ d * Xs ≤ (a + d + K₀) * (n + 1) ^ (a + d + K₀) * + 2 ^ ((a + d + K₀) * s / Nat.sqrt (Nat.log 2 s)) := + Nat.mul_le_mul (Nat.mul_le_mul (by omega) (Nat.pow_le_pow_right (by omega) (by omega))) + (Nat.pow_le_pow_right (by norm_num) + (Nat.div_le_div_right (Nat.mul_le_mul_right _ (by omega)))) + have hKs : a * (n + 1) ^ d ≤ (a + d + K₀) * (n + 1) ^ (a + d + K₀) := + Nat.mul_le_mul (by omega) (Nat.pow_le_pow_right (by omega) (by omega)) + have hgt : (NativeCertificate.ofPolyTime truncGuard_polyTime).time (P, ℓ, r, G) ≤ pg n := + (bg (P, ℓ, r, G)).1 + have hgs : (NativeCertificate.ofPolyTime truncGuard_polyTime).space (P, ℓ, r, G) ≤ pg n := + (bg (P, ℓ, r, G)).2 + -- The two branches. + have hfast : truncGuard (P, ℓ, r, G) = true → + (fastTruncCertificate cc).time (P, ℓ, r, G) ≤ Xs * F1 n ∧ + (fastTruncCertificate cc).space (P, ℓ, r, G) ≤ F1 n := by + intro _ + set fl := FastContraction.modulus G.numEdges with hfl + have hLy : (encEngine encT (fl, P, ℓ, r, G)).length ≤ Yf n := hY (P, ℓ, r, G) + have hNy : DescribedNetwork.pointCount ℓ G + 1 ≤ Yf n * Yf n + 2 := by + have h1 := pointCount_le (encT := encT) (fl, P, ℓ, r, G) + have h2 := Nat.mul_le_mul hLy hLy + dsimp only at h1 + omega + have hcall (k : ℕ) : + cc.time (coreInput (fl, P, ℓ, r, G) k) ≤ Qf n * Xs ∧ + cc.space (coreInput (fl, P, ℓ, r, G) k) ≤ Qf n ∧ + (encList encNat (core (coreInput (fl, P, ℓ, r, G) k))).length ≤ + cO * (Qf n + 1) := by + have hc := length_encCore_coreInput_le (encT := encT) (fl, P, ℓ, r, G) k + have hci : coreInput (fl, P, ℓ, r, G) k = (P, FastContraction.modulus + (DescribedNetwork.specNet P ℓ fl (FastContraction.digits fl.length k) G).numEdges, + r, DescribedNetwork.specNet P ℓ fl (FastContraction.digits fl.length k) G) := rfl + rw [hci] at hc ⊢ + obtain ⟨hT, hS⟩ := hK₀ s P r _ hs hP hPD (hC' s P ℓ r k G hs hP hPD hℓ hℓD hA) + have hQ : K₀ * ((encCore encT (P, FastContraction.modulus + (DescribedNetwork.specNet P ℓ fl (FastContraction.digits fl.length k) G).numEdges, + r, DescribedNetwork.specNet P ℓ fl (FastContraction.digits fl.length k) G)).length + + 1) ^ K₀ ≤ Qf n := by + refine Nat.mul_le_mul_left _ (Nat.pow_le_pow_left ?_ _) + have : 9 * ((encEngine encT (fl, P, ℓ, r, G)).length + 1) ^ 2 ≤ 9 * (Yf n + 1) ^ 2 := + Nat.mul_le_mul_left _ (Nat.pow_le_pow_left (by omega) _) + omega + have hS' := hS.trans hQ + refine ⟨hT.trans (Nat.mul_le_mul_right _ hQ), hS', ?_⟩ + have hout := hcO (P, FastContraction.modulus + (DescribedNetwork.specNet P ℓ fl (FastContraction.digits fl.length k) G).numEdges, + r, DescribedNetwork.specNet P ℓ fl (FastContraction.digits fl.length k) G) + exact hout.trans (Nat.mul_le_mul_left _ (Nat.add_le_add_right hS' 1)) + obtain ⟨hTe, hSe⟩ := hKE (fl, P, ℓ, r, G) _ _ _ fun k _ => hcall k + dsimp only at hTe hSe + have hEng : KE * ((encEngine encT (fl, P, ℓ, r, G)).length + cO * (Qf n + 1) + 1) ^ KE ≤ + KE * (Yf n + cO * (Qf n + 1) + 1) ^ KE := + Nat.mul_le_mul_left _ (Nat.pow_le_pow_left (by omega) _) + have hMt : (NativeCertificate.ofPolyTime modulusEdges_polyTime).time (P, ℓ, r, G) ≤ pM n := + (bM (P, ℓ, r, G)).1 + have hMs : (NativeCertificate.ofPolyTime modulusEdges_polyTime).space (P, ℓ, r, G) ≤ + pM n := (bM (P, ℓ, r, G)).2 + refine ⟨?_, ?_⟩ + · simp only [fastTruncCertificate, NativeCertificate.congr, NativeCertificate.comp_time] + change (NativeCertificate.ofPolyTime modulusEdges_polyTime).time (P, ℓ, r, G) + + (engineCertificate core cc).time (fl, P, ℓ, r, G) ≤ _ + have hTe' := hTe.trans (Nat.mul_le_mul hNy (Nat.add_le_add_right hEng _)) + have e1 : (Yf n * Yf n + 2) * (KE * (Yf n + cO * (Qf n + 1) + 1) ^ KE + Qf n * Xs) ≤ + Xs * ((Yf n * Yf n + 2) * (KE * (Yf n + cO * (Qf n + 1) + 1) ^ KE + Qf n)) := by + have h1 : KE * (Yf n + cO * (Qf n + 1) + 1) ^ KE ≤ + Xs * (KE * (Yf n + cO * (Qf n + 1) + 1) ^ KE) := Nat.le_mul_of_pos_left _ hXs1 + calc (Yf n * Yf n + 2) * (KE * (Yf n + cO * (Qf n + 1) + 1) ^ KE + Qf n * Xs) + ≤ (Yf n * Yf n + 2) * (Xs * (KE * (Yf n + cO * (Qf n + 1) + 1) ^ KE) + + Qf n * Xs) := Nat.mul_le_mul_left _ (by omega) + _ = Xs * ((Yf n * Yf n + 2) * (KE * (Yf n + cO * (Qf n + 1) + 1) ^ KE + Qf n)) := by + ring + have e2 : pM n ≤ Xs * pM n := Nat.le_mul_of_pos_left _ hXs1 + have e3 : Xs * F1 n = Xs * pM n + + Xs * ((Yf n * Yf n + 2) * (KE * (Yf n + cO * (Qf n + 1) + 1) ^ KE + Qf n)) := by + simp only [F1]; ring + omega + · simp only [fastTruncCertificate, NativeCertificate.congr, NativeCertificate.comp_space] + change (NativeCertificate.ofPolyTime modulusEdges_polyTime).space (P, ℓ, r, G) + + (engineCertificate core cc).space (fl, P, ℓ, r, G) ≤ _ + have h1 : KE * (Yf n + cO * (Qf n + 1) + 1) ^ KE + Qf n ≤ + (Yf n * Yf n + 2) * (KE * (Yf n + cO * (Qf n + 1) + 1) ^ KE + Qf n) := + Nat.le_mul_of_pos_left _ (by omega) + simp only [F1] + omega + have hdirect : truncGuard (P, ℓ, r, G) = false → + (truncDirectCertificate entry ce).time (P, ℓ, r, G) ≤ F2 n ∧ + (truncDirectCertificate entry ce).space (P, ℓ, r, G) ≤ F2 n := by + intro hg + have hss : s < s₀ := by + by_contra h + have := truncGuard_of_le (P := P) (r := r) (show 4 * (C * D + 1) ≤ s by omega) hℓD hkC hsm + rw [this] at hg + exact Bool.noConfusion hg + have hL : (DescribedNetwork.encDescribed encT G).length ≤ n := by + simp only [hn, encTrunc, length_encPair] + omega + have hEf : Ke * ((DescribedNetwork.encDescribed encT G).length + 1) ^ Ke ≤ Ef n := + Nat.mul_le_mul_left _ (Nat.pow_le_pow_left (by omega) _) + have h2s : 2 ^ (Ke * s) ≤ 2 ^ (Ke * s₀) := + Nat.pow_le_pow_right (by norm_num) (Nat.mul_le_mul_left _ hss.le) + obtain ⟨hT, hS⟩ := hKd (P, ℓ, r, G) (Ef n * 2 ^ (Ke * s₀)) (Ef n) fun v hv bs hbs => by + obtain ⟨h1, h2⟩ := hKe s r G hA v hv bs hbs + exact ⟨h1.trans (Nat.mul_le_mul hEf h2s), h2.trans hEf⟩ + have h2m : 2 ^ G.numEdges ≤ 2 ^ (C * s₀) := + Nat.pow_le_pow_right (by norm_num) (hmC.trans (Nat.mul_le_mul_left _ hss.le)) + refine ⟨hT.trans (Nat.mul_le_mul_right _ (Nat.mul_le_mul_left _ h2m)), hS.trans ?_⟩ + simp only [F2] + have h1 : 1 ≤ 2 ^ (C * s₀) * (Ef n * 2 ^ (Ke * s₀) + 1) := + Nat.one_le_iff_ne_zero.mpr (by positivity) + calc Kd * (n + Ef n + 1) ^ Kd ≤ Kd * (n + Ef n + 1) ^ Kd * + (2 ^ (C * s₀) * (Ef n * 2 ^ (Ke * s₀) + 1)) := Nat.le_mul_of_pos_right _ h1 + _ = _ := by ring + refine ⟨?_, ?_⟩ + · simp only [NativeCertificate.congr, NativeCertificate.branch_time] + have hF : pg n + Xs * F1 n + F2 n ≤ Xs * F n := by + have h1 : pg n ≤ Xs * pg n := Nat.le_mul_of_pos_left _ hXs1 + have h2 : F2 n ≤ Xs * F2 n := Nat.le_mul_of_pos_left _ hXs1 + have e : Xs * F n = Xs * pg n + Xs * F1 n + Xs * F2 n := by simp only [F]; ring + omega + have hFX : Xs * F n ≤ a * (n + 1) ^ d * Xs := by + calc Xs * F n ≤ Xs * (a * (n + 1) ^ d) := Nat.mul_le_mul_left _ hFn + _ = a * (n + 1) ^ d * Xs := by ring + split + · next hg => + have := (hfast hg).1 + omega + · next hg => + have := (hdirect (by simpa using hg)).1 + omega + · simp only [NativeCertificate.congr, NativeCertificate.branch_space] + have hF : pg n + F1 n + F2 n ≤ F n := le_rfl + split + · next hg => + have := (hfast hg).2 + omega + · next hg => + have := (hdirect (by simpa using hg)).2 + omega + +end Cslib.Circuits.Frontier diff --git a/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkTruncatedAlgorithm.lean b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkTruncatedAlgorithm.lean new file mode 100644 index 000000000..cf09fa820 --- /dev/null +++ b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkTruncatedAlgorithm.lean @@ -0,0 +1,108 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: local-only (test driver) + +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TruncatedAlgorithm +import Complexity.Computability.Machines.Turing.MultiTape.Encodings.Length + +/-! +# Tests for the interface of Theorem D.1 at truncation order `ℓ` + +The interface is not vacuous: for networks with at most `C` edges and descriptors that are their +own entries, direct summation meets its bound (`boundedAlgorithm`). The guard holds on a small +network, and on admissible inputs from the size `4 (C D + 1)` on. +-/ + +@[expose] public section + +namespace ComplexityTests.TensorNetworkTruncatedAlgorithm + +open Cslib Cslib.GenericRAM Cslib.Circuits.Frontier Turing.MultiTapeTM + +/-- A descriptor is its own entry, whatever the bits. -/ +def constEntry (t : List ℕ) (_ : List Bool) : List ℕ := t + +/-- The entry certificate of constant descriptors. -/ +noncomputable def constCert : + NativeCertificate (fun q : List ℕ × List Bool => constEntry q.1 q.2) + (encPair (encList encNat) encBits) (encList encNat) := + NativeCertificate.ofPolyTime (ComputableInPolyTime.fst _ _) + +/-- Networks with at most `C` edges. -/ +def BoundedEdges (C _s : ℕ) (G : ℕ × DescribedNetwork (List ℕ)) : Prop := G.2.numEdges ≤ C + +/-- **The interface is not vacuous**: direct summation is a truncated contraction algorithm for +networks with boundedly many edges. -/ +noncomputable def boundedAlgorithm : + TruncatedContractionAlgorithm (encList encNat) constEntry BoundedEdges where + certificate := truncDirectCertificate constEntry constCert + bound C _ := by + obtain ⟨K, hK⟩ := truncDirectCertificate_le (encT := encList encNat) constEntry constCert + obtain ⟨p, hp, hm, hb⟩ := exists_mono_poly_cert + (ComputableInPolyTime.fst (encList encNat) encBits) + let F : ℕ → ℕ := fun n => K * (n + p (3 * n + 1) + 1) ^ K * 2 ^ C * (p (3 * n + 1) + 1) + have hF : PolyBounded id F := + ((((PolyBounded.const K).mul (((PolyBounded.self.add + ((PolyBounded.of_polynomiallyBounded id hp).comp (((PolyBounded.const 3).mul + PolyBounded.self).add (PolyBounded.const 1)))).add (PolyBounded.const 1)).pow K)).mul + (PolyBounded.const (2 ^ C))).mul + (((PolyBounded.of_polynomiallyBounded id hp).comp (((PolyBounded.const 3).mul + PolyBounded.self).add (PolyBounded.const 1))).add (PolyBounded.const 1))) + obtain ⟨a, d, had⟩ := hF.exists_le + refine ⟨a + d, fun s P ℓ r G _ _ _ _ _ hA => ?_⟩ + set n := (encTrunc (encList encNat) (P, ℓ, r, G)).length with hn + have hv : ∀ v ∈ G.vertices, ∀ bs : List Bool, bs.length = v.1.length → + constCert.time (v.2, bs) ≤ p (3 * n + 1) ∧ constCert.space (v.2, bs) ≤ p (3 * n + 1) := by + intro v hv bs hbs + have h1 := List.le_sum_of_mem + (List.mem_map_of_mem (f := fun a => (encPair (encList encNat) (encList encNat) a).length) + hv) + have h2 := sum_length_le_length_encList (encPair (encList encNat) (encList encNat)) + G.vertices + have h3 := length_le_length_encList encNat v.1 + have hG : (encList (encPair (encList encNat) (encList encNat)) G.vertices).length ≤ n := by + simp only [hn, encTrunc, DescribedNetwork.encDescribed, DescribedNetwork.equivProd, + encOfEquiv_apply, length_encPair] + simp + omega + have hvl : (encPair (encList encNat) (encList encNat) v).length ≤ n := by + omega + have hlen : (encPair (encList encNat) encBits (v.2, bs)).length ≤ 3 * n + 1 := by + simp only [length_encPair, encBits_apply] at hvl ⊢ + omega + exact ⟨(hb _).1.trans (hm hlen), (hb _).2.trans (hm hlen)⟩ + obtain ⟨hT, hS⟩ := hK (P, ℓ, r, G) _ _ hv + have h2 : 2 ^ G.numEdges ≤ 2 ^ C := Nat.pow_le_pow_right (by norm_num) hA + have hFn := had n + simp only [id] at hFn + have hK' : a * (n + 1) ^ d ≤ (a + d) * (n + 1) ^ (a + d) := + Nat.mul_le_mul (by omega) (Nat.pow_le_pow_right (by omega) (by omega)) + have hX : (a + d) * (n + 1) ^ (a + d) ≤ (a + d) * (n + 1) ^ (a + d) * + 2 ^ ((a + d) * s / Nat.sqrt (Nat.log 2 s)) := + Nat.le_mul_of_pos_right _ Nat.one_le_two_pow + have hT' : (truncDirectCertificate constEntry constCert).time (P, ℓ, r, G) ≤ F n := + hT.trans (Nat.mul_le_mul_right _ (Nat.mul_le_mul_left _ h2)) + have hS' : (truncDirectCertificate constEntry constCert).space (P, ℓ, r, G) ≤ F n := by + refine hS.trans ?_ + have h1 : 1 ≤ 2 ^ C * (p (3 * n + 1) + 1) := Nat.one_le_iff_ne_zero.mpr (by positivity) + calc K * (n + p (3 * n + 1) + 1) ^ K ≤ K * (n + p (3 * n + 1) + 1) ^ K * + (2 ^ C * (p (3 * n + 1) + 1)) := Nat.le_mul_of_pos_right _ h1 + _ = F n := by simp only [F]; ring + exact ⟨by omega, by omega⟩ + +-- The guard holds on a network with one edge and one vertex at truncation order `2`. +example : truncGuard (1, 2, 0, (⟨1, [([0], [1, 1])]⟩ : DescribedNetwork (List ℕ))) = true := by + decide + +-- Admissible inputs pass the guard from the size `4 (C D + 1)` on. +example {C D s P ℓ r : ℕ} {G : DescribedNetwork (List ℕ)} (hs : 4 * (C * D + 1) ≤ s) + (hℓ : ℓ ≤ D * s) (hk : G.vertices.length ≤ C * s) (hm : s ≤ G.numEdges) : + truncGuard (P, ℓ, r, G) = true := + truncGuard_of_le hs hℓ hk hm + +end ComplexityTests.TensorNetworkTruncatedAlgorithm From 9a2232e1aad48ba263b2f4e80533ff4b5b732692 Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 10:28:15 -0400 Subject: [PATCH 10/20] refactor(Frontier/TensorNetwork): make the contraction recursion generic in the root descriptor type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `VertexDesc T := T ⊕ PacketDesc`, read through an entry procedure `ev : T → List Bool → List ℕ`, and `Call T`, `scheme ev mk`, `value ev mk`, `StepCorrect ev mk WF` and the polynomial-time and size modules over any `T`. Explicit tables are `T = List ℕ` with `tableEntry`; the leaf machine and `CountingSimulation.Fast*` stay at tables, so `fastContractionAlgorithm` and the #1995 containments keep their statements. First PR of #1538 milestone E1.2. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG --- .../Frontier/TensorNetwork/ChildEntries.lean | 11 +- .../Frontier/TensorNetwork/DescribedLift.lean | 2 +- .../TensorNetwork/FastContraction.lean | 116 ++--- .../FastContractionDerivation.lean | 70 +-- .../TensorNetwork/FastContractionLeaf.lean | 157 ++++--- .../TensorNetwork/FastContractionMachine.lean | 136 +++--- .../FastContractionPolyTime.lean | 418 +++++++++--------- .../FastContractionSchedule.lean | 19 +- .../TensorNetwork/FastContractionShape.lean | 18 +- .../TensorNetwork/FastContractionSize.lean | 61 +-- .../TensorNetwork/FastContractionStep.lean | 17 +- .../Frontier/TensorNetwork/NativeCall.lean | 21 +- .../Frontier/TensorNetwork/NativeChild.lean | 68 +-- .../TensorNetwork/NativeChildBounds.lean | 13 +- .../TensorNetwork/NativeChildPolyTime.lean | 58 +-- .../Frontier/TensorNetwork/PacketTerms.lean | 1 + .../Frontier/TensorNetwork/VertexDesc.lean | 155 ++++--- .../CountingSimulation/FastAlgorithm.lean | 38 +- .../CountingSimulation/FastAnalysis.lean | 26 +- .../CountingSimulation/FastLeaves.lean | 16 +- .../Frontier/TensorNetworkNativeChild.lean | 6 +- .../TensorNetworkNativeChildPolyTime.lean | 16 +- .../Frontier/TensorNetworkVertexDesc.lean | 29 +- ComplexityTests/FastContractionAnalysis.lean | 10 +- ComplexityTests/FastContractionLeaf.lean | 5 +- ComplexityTests/FastContractionPolyTime.lean | 11 +- ComplexityTests/FastLeaves.lean | 2 +- 27 files changed, 824 insertions(+), 676 deletions(-) diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/ChildEntries.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/ChildEntries.lean index bb3b4b2d1..985186911 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/ChildEntries.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/ChildEntries.lean @@ -15,7 +15,7 @@ import Mathlib.Data.List.GetD # The entries of the child networks from their descriptors A child network of the contraction recursion of [OpenAI2026ETH] (`ModeSplitting.child`, §D.4.6, -p. 63) is carried natively as a network of vertex descriptors (`VertexDesc`) with port lists. This +p. 63) is carried natively as a network of vertex descriptors (`VertexDesc T`) with port lists. This file proves that such a network has the contraction of the child, once each descriptor reads its ports in the right order. @@ -230,7 +230,8 @@ valuation `i < a`, `L = 2 ^ a` slots, `2 ^ (i + 1)` tiles and `p` exponents per of `q` against `g`, an interpolation value mapping to `ζ`, and the dense exponents of `β` at `q`. Then along a ring map `ψ` from `A_p`, at the packet's precision, to `R`, the descriptor's entry at the bits on its ports is the child's entry. -/ -theorem map_val_entry_child_inr [DecidableEq V] (β : P × Fin (2 ^ (i + 1)) × Fin p → ℕ) (g : G) +theorem map_val_entry_child_inr [DecidableEq V] {T : Type} {ev : T → List Bool → List ℕ} + (β : P × Fin (2 ^ (i + 1)) × Fin p → ℕ) (g : G) (q : P) (cs : List ({e // (cauchyModeSplitting side hsrc htgt horient hslot hia κ ζ hp ht hti hti').group (N.src e) = g} ⊕ @@ -246,7 +247,7 @@ theorem map_val_entry_child_inr [DecidableEq V] (β : P × Fin (2 ^ (i + 1)) × (N.src e) = g} ⊕ {e // (cauchyModeSplitting side hsrc htgt horient hslot hia κ ζ hp ht hti hti').group (N.tgt e) = g} → Bool) : - ψ (val c.p c.fl (VertexDesc.entry + ψ (val c.p c.fl (VertexDesc.entry ev (.inr (c, cs.map fun e => (e.isLeft, slot (Sum.elim Subtype.val Subtype.val e)), βd)) (cs.map y))) = ((cauchyModeSplitting side hsrc htgt horient hslot hia κ ζ hp ht hti hti').child β g).tensor @@ -257,10 +258,10 @@ theorem map_val_entry_child_inr [DecidableEq V] (β : P × Fin (2 ^ (i + 1)) × intro x hx obtain ⟨e, -, rfl⟩ := List.mem_map.mp hx exact hslot _ - have key := VertexDesc.map_val_entry_inr (c, cs.map fun e => (e.isLeft, + have key := VertexDesc.map_val_entry_inr ev (c, cs.map fun e => (e.isLeft, slot (Sum.elim Subtype.val Subtype.val e)), βd) (cs.map y) ψ hp κ hL hia htiles ht hti hti' hports - have hgoal : ψ (val c.p c.fl (VertexDesc.entry (.inr (c, cs.map fun e => (e.isLeft, + have hgoal : ψ (val c.p c.fl (VertexDesc.entry ev (.inr (c, cs.map fun e => (e.isLeft, slot (Sum.elim Subtype.val Subtype.val e)), βd)) (cs.map y))) = _ := key rw [hgoal] dsimp only diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/DescribedLift.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/DescribedLift.lean index 62bfd5130..d998f60fc 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/DescribedLift.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/DescribedLift.lean @@ -24,7 +24,7 @@ import Mathlib.Data.List.Sort The contraction recursion of [OpenAI2026ETH] (§D.4, pp. 57–64) is proved correct over the valuation ring `O = ℤ_(2)[U] / (f)`, while the native algorithm carries networks of descriptors -(`DescribedNetwork VertexDesc`) and computes with coefficient lists in +(`DescribedNetwork (VertexDesc T)`) and computes with coefficient lists in `A_p = (ℤ / 2 ^ p)[U] / (f)`. This file gives the network over `O` that a described network stands for. diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContraction.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContraction.lean index aab15a930..71713d2ae 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContraction.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContraction.lean @@ -22,17 +22,19 @@ import Mathlib.Data.List.GetD The recursion of Theorem D.1 of [OpenAI2026ETH] (Appendix D.4.7, p. 64), as a depth-first stack recursion (`Cslib.GenericRAM.StackRecursion.Scheme`) over *calls*. A call -(`FastContraction.Call`) is a described network (`DescribedNetwork VertexDesc`) whose first `r` -vertices are its rows, with the schedule's scale `s` (the number of edges of the root, since the -machine sees no other size), its depth `d`, an edge bound, its precision `p` and the coefficients -`fl` of the modulus `f`. +(`FastContraction.Call T`) is a described network (`DescribedNetwork (VertexDesc T)`) whose first +`r` vertices are its rows, with the schedule's scale `s` (the number of edges of the root, since +the machine sees no other size), its depth `d`, an edge bound, its precision `p` and the +coefficients `fl` of the modulus `f`. The vertices of the input network have descriptors of a type +`T`, read by an entry procedure `ev : T → List Bool → List ℕ` (`VertexDesc.entry ev`); only the +leaves and the correctness statement read them, so the recursion is the same for every `T`. **Active calls and leaves.** A call with `M` edges is *active* (`FastContraction.active`) when the schedule makes it an active call (`ContractionSchedule.callParams`, with `a = slotBits s d`, `u = taper s d` and `h = ⌈3 M / u⌉`), its parameters satisfy the hypotheses of Lemma D.5, its degrees are at most `degreeBound s`, the `M (2 L - 1) + 1` interpolation points are distinct residues (`n ≤ 2 ^ e` for `e = deg f`), and `M` is below its edge bound. Every other call is a leaf, -evaluated by direct summation over the coefficient lists of `A_p` (`FastContraction.leafValue`). +evaluated by direct summation over the coefficient lists of `A_p` (`FastContraction.leafValue ev`). A child receives its parent's number of edges as its bound, so the recursion terminates, as `TensorNetwork.contractRec` does; a child that is not smaller is a leaf. @@ -93,13 +95,15 @@ open GaloisRingArith ChildCursor NativeRecovery ContractionSchedule NativeChild coefficients `fl` of the modulus and the number `r` of rows. -/ abbrev Params : Type := ℕ × ℕ × ℕ × ℕ × List ℕ × ℕ -/-- **A call** of the recursion: its parameters and its network, whose first `r` vertices are its -rows. -/ -abbrev Call : Type := Params × DescribedNetwork VertexDesc +/-- **A call** of the recursion: its parameters and its network over root descriptors `T`, whose +first `r` vertices are its rows. -/ +abbrev Call (T : Type) : Type := Params × DescribedNetwork (VertexDesc T) + +variable {T : Type} namespace Call -variable (x : Call) +variable (x : Call T) /-- The scale `s` of the schedule. -/ abbrev scale : ℕ := x.1.1 @@ -114,7 +118,7 @@ abbrev fl : List ℕ := x.1.2.2.2.2.1 /-- The number of rows. -/ abbrev rows : ℕ := x.1.2.2.2.2.2 /-- The network. -/ -abbrev net : DescribedNetwork VertexDesc := x.2 +abbrev net : DescribedNetwork (VertexDesc T) := x.2 /-- The number `M` of edges. -/ abbrev edges : ℕ := x.2.numEdges @@ -122,7 +126,9 @@ end Call /-! ### The data of a call -/ -variable (x : Call) +variable (ev : T → List Bool → List ℕ) + +variable (x : Call T) /-- The packets have `2 ^ a` slots, `a = slotBits s d`. -/ @[expose] def slots : ℕ := slotBits x.scale x.depth @@ -145,7 +151,7 @@ points are distinct residues (`n ≤ 2 ^ e`), and it has fewer edges than its bo x.edges < x.bound) /-- An active call has fewer edges than its bound. -/ -theorem edges_lt_bound_of_active {x : Call} (h : active x = true) : x.edges < x.bound := by +theorem edges_lt_bound_of_active {x : Call T} (h : active x = true) : x.edges < x.bound := by simp only [active, decide_eq_true_eq] at h exact h.2.2.2.2.2.2 @@ -169,7 +175,7 @@ of rows is stored in binary and the packing lists one word per row. -/ @[expose] def rowCap : ℕ := min x.rows x.net.vertices.length /-- The cap on the rows is inactive when there are at most as many rows as vertices. -/ -theorem rowCap_eq {x : Call} (h : x.rows ≤ x.net.vertices.length) : rowCap x = x.rows := +theorem rowCap_eq {x : Call T} (h : x.rows ≤ x.net.vertices.length) : rowCap x = x.rows := min_eq_left h /-- **The packing of Lemma D.3**, natively (`nativeParentPacking`, `r = 64`), with the rows @@ -179,7 +185,7 @@ capped (`FastContraction.rowCap`). -/ /-- The packing is the native packing of the rows when there are at most as many rows as vertices. -/ -theorem packing_eq {x : Call} (h : x.rows ≤ x.net.vertices.length) : +theorem packing_eq {x : Call T} (h : x.rows ≤ x.net.vertices.length) : packing x = nativeParentPacking x.rows (slots x) x.net := by rw [packing, rowCap_eq h] @@ -226,16 +232,16 @@ the stored values. -/ /-- **The value of a leaf**: direct summation in `A_p`. -/ @[expose] def leafValue : List ℕ := - DescribedNetwork.sumValue SumOps.galois VertexDesc.entry (x.prec, x.fl) x.net + DescribedNetwork.sumValue SumOps.galois (VertexDesc.entry ev) (x.prec, x.fl) x.net /-! ### The scheme -/ -variable (mk : Call → State → ℕ × DescribedNetwork VertexDesc) +variable (mk : Call T → State → ℕ × DescribedNetwork (VertexDesc T)) /-- **The child call** at a cursor state `c = (i, k, β, g)`: the rows and the network given by the child builder `mk`, at depth `d + 1`, with the parent's number of edges as its bound and the node's precision `p_i`. -/ -@[expose] def child (c : State) : Call := +@[expose] def child (c : State) : Call T := ((x.scale, x.depth + 1, x.edges, nodePrec x c.1, x.fl, (mk x c).1), (mk x c).2) /-- The accumulator of a call: the cursor state of the next child, if any, and the accumulator of @@ -243,9 +249,9 @@ the cursor. -/ abbrev Frame : Type := Option State × Acc (List ℕ) /-- **The recursion as a stack recursion**, with values tagged by the depth. -/ -@[expose] def scheme : Scheme Call Frame (ℕ × List ℕ) where +@[expose] def scheme : Scheme (Call T) Frame (ℕ × List ℕ) where isLeaf x := !active x - leaf x := (x.depth, leafValue x) + leaf x := (x.depth, leafValue ev x) start x := (some (cursorStart (weights x)), (one x.fl, zero x.fl, [])) next x a := a.1.map (child x mk) absorb x a y := match a.1 with @@ -257,18 +263,19 @@ abbrev Frame : Type := Option State × Acc (List ℕ) /-- **The value of a call**, by well-founded recursion on the edge bound: the leaf value, or the recovery from the values of the children. -/ -@[expose] def value (x : Call) : List ℕ := +@[expose] def value (x : Call T) : List ℕ := if _h : active x = true then finishValue x (runLoop x fun c => value (child x mk c)) - else leafValue x + else leafValue ev x termination_by x.bound decreasing_by exact edges_lt_bound_of_active _h -theorem value_of_active {x : Call} (h : active x = true) : - value mk x = finishValue x (runLoop x fun c => value mk (child x mk c)) := by +theorem value_of_active {x : Call T} (h : active x = true) : + value ev mk x = finishValue x (runLoop x fun c => value ev mk (child x mk c)) := by rw [value, dite_eq_left h] -theorem value_of_not_active {x : Call} (h : active x = false) : value mk x = leafValue x := by +theorem value_of_not_active {x : Call T} (h : active x = false) : + value ev mk x = leafValue ev x := by rw [value, dite_eq_right (by simp [h])] /-! ### Derivations -/ @@ -370,12 +377,12 @@ values `vals` of the earlier children absorbed. -/ /-- **The loop of an active call walks its children**: from `start`, the `c`-th frame asks for the child at the `c`-th cursor state, absorbing it gives the next frame, and the last frame stops. -/ -theorem walk {x : Call} (h : active x = true) (vals : State → List ℕ) : - frameAt x vals 0 = (scheme mk).start x ∧ - (∀ c < (children x).length, (scheme mk).next x (frameAt x vals c) = +theorem walk {x : Call T} (h : active x = true) (vals : State → List ℕ) : + frameAt x vals 0 = (scheme ev mk).start x ∧ + (∀ c < (children x).length, (scheme ev mk).next x (frameAt x vals c) = some (child x mk ((children x).getD c (0, 0, [], 0)))) ∧ - (scheme mk).next x (frameAt x vals (children x).length) = none ∧ - (∀ c < (children x).length, (scheme mk).absorb x (frameAt x vals c) + (scheme ev mk).next x (frameAt x vals (children x).length) = none ∧ + (∀ c < (children x).length, (scheme ev mk).absorb x (frameAt x vals c) (x.depth + 1, vals ((children x).getD c (0, 0, [], 0))) = frameAt x vals (c + 1)) ∧ runLoop x vals = (frameAt x vals (children x).length).2 := by have hM := one_le_edges_of_active h @@ -406,34 +413,35 @@ theorem walk {x : Call} (h : active x = true) (vals : State → List ℕ) : /-- The invariant of the derivation from a root `x₀` at depth `0`: the only node at depth `0` is the root, and a value tagged `0` is the root's value. -/ -@[expose] def inv (x₀ : Call) : Invariant Call Frame (ℕ × List ℕ) := - ⟨fun x => x.depth = 0 → x = x₀, fun _ _ => True, fun y => y.1 = 0 → y.2 = value mk x₀⟩ +@[expose] def inv (x₀ : Call T) : Invariant (Call T) Frame (ℕ × List ℕ) := + ⟨fun x => x.depth = 0 → x = x₀, fun _ _ => True, fun y => y.1 = 0 → y.2 = value ev mk x₀⟩ /-- **Derivations of the values.** Every call satisfying the invariant of a root `x₀` has a derivation of its tagged value. -/ -theorem exists_eval (x₀ : Call) (x : Call) (hx : (inv mk x₀).node x) : - ∃ n h, (scheme mk).Eval (inv mk x₀) x (x.depth, value mk x) n h := by - refine Scheme.exists_eval_of_measure (R := scheme mk) (I := inv mk x₀) Call.bound - (fun x => (x.depth, value mk x)) (fun x _ hl => ?_) (fun x _ hl => ?_) (fun x hx h0 => ?_) x hx +theorem exists_eval (x₀ : Call T) (x : Call T) (hx : (inv ev mk x₀).node x) : + ∃ n h, (scheme ev mk).Eval (inv ev mk x₀) x (x.depth, value ev mk x) n h := by + refine Scheme.exists_eval_of_measure (R := scheme ev mk) (I := inv ev mk x₀) Call.bound + (fun x => (x.depth, value ev mk x)) (fun x _ hl => ?_) (fun x _ hl => ?_) + (fun x hx h0 => ?_) x hx · have hl' : active x = false := by simpa [scheme] using hl - simp [scheme, value_of_not_active mk hl'] + simp [scheme, value_of_not_active ev mk hl'] · have hl' : active x = true := by simpa [scheme] using hl - obtain ⟨h0, hnext, hdone, habs, hfin⟩ := walk mk hl' fun c => value mk (child x mk c) - refine ⟨(children x).length, frameAt x fun c => value mk (child x mk c), + obtain ⟨h0, hnext, hdone, habs, hfin⟩ := walk ev mk hl' fun c => value ev mk (child x mk c) + refine ⟨(children x).length, frameAt x fun c => value ev mk (child x mk c), fun c => child x mk ((children x).getD c (0, 0, [], 0)), h0, hnext, hdone, fun c hc => habs c hc, fun c _ => ⟨trivial, fun h => absurd h (by simp [child]), edges_lt_bound_of_active hl'⟩, ?_⟩ simp only [scheme, Prod.mk.injEq, true_and] - rw [value_of_active mk hl', hfin] + rw [value_of_active ev mk hl', hfin] · simp only at h0 rw [hx h0] /-- **A tagged value returned by the run is the root's value**, for any fuel: if the root is at depth `0` and the run returns `(0, y)`, then `y` is the value of the root. -/ -theorem eq_value_of_run {J : Type} {fuel : J → ℕ} {root : J → Call} {a : J} {y : List ℕ} - (hroot : (root a).depth = 0) (hrun : (scheme mk).run fuel root a = some (0, y)) : - y = value mk (root a) := by - obtain ⟨n, h, he⟩ := exists_eval mk (root a) (root a) fun _ => rfl +theorem eq_value_of_run {J : Type} {fuel : J → ℕ} {root : J → Call T} {a : J} {y : List ℕ} + (hroot : (root a).depth = 0) (hrun : (scheme ev mk).run fuel root a = some (0, y)) : + y = value ev mk (root a) := by + obtain ⟨n, h, he⟩ := exists_eval ev mk (root a) (root a) fun _ => rfl rw [hroot] at he exact Scheme.value_of_run_eq_some he hrun rfl @@ -527,30 +535,30 @@ theorem val_table_runLoop (h : active x = true) (vals : State → List ℕ) {j : /-- **The correctness of one active call** for a well-formedness predicate `WF`: at a well-formed active call, if the values `vals` of the children are their contractions in `A_{p_i}`, then the recovered value is the contraction of the call's network in `A_p`. -/ -@[expose] def StepCorrect (WF : Call → Prop) : Prop := +@[expose] def StepCorrect (WF : Call T → Prop) : Prop := ∀ x, WF x → active x = true → ∀ vals : State → List ℕ, (∀ c ∈ children x, val (nodePrec x c.1) x.fl (vals c) = - (mk x c).2.contraction fun t bs => val (nodePrec x c.1) x.fl (VertexDesc.entry t bs)) → + (mk x c).2.contraction fun t bs => val (nodePrec x c.1) x.fl (VertexDesc.entry ev t bs)) → val x.prec x.fl (finishValue x (runLoop x vals)) = - x.net.contraction fun t bs => val x.prec x.fl (VertexDesc.entry t bs) + x.net.contraction fun t bs => val x.prec x.fl (VertexDesc.entry ev t bs) /-- **Well-formedness passes to the children** of an active call. -/ -@[expose] def WFChildren (WF : Call → Prop) : Prop := +@[expose] def WFChildren (WF : Call T → Prop) : Prop := ∀ x, WF x → active x = true → ∀ c ∈ children x, WF (child x mk c) /-- **Correctness of the recursion.** If the step of an active call is correct and well-formedness passes to the children, every well-formed call computes the contraction of its network in `A_p`. -/ -theorem val_value {WF : Call → Prop} (hstep : StepCorrect mk WF) (hwf : WFChildren mk WF) - (x : Call) (hx : WF x) : - val x.prec x.fl (value mk x) = - x.net.contraction fun t bs => val x.prec x.fl (VertexDesc.entry t bs) := by +theorem val_value {WF : Call T → Prop} (hstep : StepCorrect ev mk WF) (hwf : WFChildren mk WF) + (x : Call T) (hx : WF x) : + val x.prec x.fl (value ev mk x) = + x.net.contraction fun t bs => val x.prec x.fl (VertexDesc.entry ev t bs) := by induction hb : x.bound using Nat.strong_induction_on generalizing x with | _ b ih => cases ha : active x - · rw [value_of_not_active mk ha] - exact DescribedNetwork.val_sumValue_galois VertexDesc.entry (x.prec, x.fl) x.net - · rw [value_of_active mk ha] + · rw [value_of_not_active ev mk ha] + exact DescribedNetwork.val_sumValue_galois (VertexDesc.entry ev) (x.prec, x.fl) x.net + · rw [value_of_active ev mk ha] refine hstep x hx ha _ fun c hc => ?_ exact ih _ (hb ▸ edges_lt_bound_of_active ha) (child x mk c) (hwf x hx ha c hc) rfl diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionDerivation.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionDerivation.lean index 7d1f9b0e8..fdf577631 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionDerivation.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionDerivation.lean @@ -58,43 +58,44 @@ namespace Cslib.Circuits.Frontier.FastContraction open ChildCursor Cslib.GenericRAM Cslib.GenericRAM.StackRecursion -variable (mk : Call → State → ℕ × DescribedNetwork VertexDesc) +variable {T : Type} (ev : T → List Bool → List ℕ) + (mk : Call T → State → ℕ × DescribedNetwork (VertexDesc T)) /-- **The calls reached from a root** `x₀`: the root, and the children of reached active calls. -/ -inductive Reach (x₀ : Call) : Call → Prop +inductive Reach (x₀ : Call T) : Call T → Prop /-- The root is reached. -/ | root : Reach x₀ x₀ /-- The children of a reached active call are reached. -/ - | step {x : Call} (c : State) : Reach x₀ x → active x = true → c ∈ children x → + | step {x : Call T} (c : State) : Reach x₀ x → active x = true → c ∈ children x → Reach x₀ (child x mk c) /-- **The invariant of the derivations from a root** `x₀`: the reached calls, the frames of reached active calls along their children, and the tagged values of reached calls. -/ -@[expose] def reachInv (x₀ : Call) : Invariant Call Frame (ℕ × List ℕ) where +@[expose] def reachInv (x₀ : Call T) : Invariant (Call T) Frame (ℕ × List ℕ) where node := Reach mk x₀ frame x a := Reach mk x₀ x ∧ active x = true ∧ - ∃ c ≤ (children x).length, a = frameAt x (fun c => value mk (child x mk c)) c - value y := ∃ x, Reach mk x₀ x ∧ y = (x.depth, value mk x) + ∃ c ≤ (children x).length, a = frameAt x (fun c => value ev mk (child x mk c)) c + value y := ∃ x, Reach mk x₀ x ∧ y = (x.depth, value ev mk x) -variable {mk} {x₀ : Call} +variable {ev mk} {x₀ : Call T} namespace Reach /-- Reached calls keep the scale of the root. -/ -theorem scale_eq {x : Call} (h : Reach mk x₀ x) : x.scale = x₀.scale := by +theorem scale_eq {x : Call T} (h : Reach mk x₀ x) : x.scale = x₀.scale := by induction h with | root => rfl | step c _ _ _ ih => exact ih /-- Reached calls keep the modulus of the root. -/ -theorem fl_eq {x : Call} (h : Reach mk x₀ x) : x.fl = x₀.fl := by +theorem fl_eq {x : Call T} (h : Reach mk x₀ x) : x.fl = x₀.fl := by induction h with | root => rfl | step c _ _ _ ih => exact ih /-- **The bound plus the depth does not increase** along the recursion: a child's bound is its parent's number of edges, which is below the parent's bound at an active call. -/ -theorem bound_add_depth_le {x : Call} (h : Reach mk x₀ x) : +theorem bound_add_depth_le {x : Call T} (h : Reach mk x₀ x) : x.bound + x.depth ≤ x₀.bound + x₀.depth := by induction h with | root => exact le_rfl @@ -106,7 +107,7 @@ theorem bound_add_depth_le {x : Call} (h : Reach mk x₀ x) : /-- **A reached active call lies above depth `B - 1`**, for the root's bound `B` plus its depth: it has an edge and fewer edges than its bound. -/ -theorem depth_add_two_le_of_active {x : Call} (h : Reach mk x₀ x) (ha : active x = true) : +theorem depth_add_two_le_of_active {x : Call T} (h : Reach mk x₀ x) (ha : active x = true) : x.depth + 2 ≤ x₀.bound + x₀.depth := by have h1 := h.bound_add_depth_le have h2 := edges_lt_bound_of_active ha @@ -114,13 +115,13 @@ theorem depth_add_two_le_of_active {x : Call} (h : Reach mk x₀ x) (ha : active omega /-- Reached calls lie at or below the root's depth. -/ -theorem depth_le {x : Call} (h : Reach mk x₀ x) : x₀.depth ≤ x.depth := by +theorem depth_le {x : Call T} (h : Reach mk x₀ x) : x₀.depth ≤ x.depth := by induction h with | root => exact le_rfl | step c _ _ _ ih => change x₀.depth ≤ _ + 1; omega /-- A reached call at the root's depth is the root. -/ -theorem eq_root_of_depth_le {x : Call} (h : Reach mk x₀ x) (hd : x.depth ≤ x₀.depth) : +theorem eq_root_of_depth_le {x : Call T} (h : Reach mk x₀ x) (hd : x.depth ≤ x₀.depth) : x = x₀ := by cases h with | root => rfl @@ -133,40 +134,40 @@ end Reach /-- The derivation hypotheses of a reached active call: its frames along its children, which are reached, smaller in the bound and one level deeper, and its value from the last frame. -/ -private theorem reach_call {x : Call} (hx : Reach mk x₀ x) (ha : active x = true) : - ∃ (acc : ℕ → Frame) (child' : ℕ → Call), acc 0 = (scheme mk).start x ∧ - (∀ c < (children x).length, (scheme mk).next x (acc c) = some (child' c)) ∧ - (scheme mk).next x (acc (children x).length) = none ∧ - (∀ c < (children x).length, (scheme mk).absorb x (acc c) - ((child' c).depth, value mk (child' c)) = acc (c + 1)) ∧ - (∀ c < (children x).length, (reachInv mk x₀).frame x (acc c) ∧ +private theorem reach_call {x : Call T} (hx : Reach mk x₀ x) (ha : active x = true) : + ∃ (acc : ℕ → Frame) (child' : ℕ → Call T), acc 0 = (scheme ev mk).start x ∧ + (∀ c < (children x).length, (scheme ev mk).next x (acc c) = some (child' c)) ∧ + (scheme ev mk).next x (acc (children x).length) = none ∧ + (∀ c < (children x).length, (scheme ev mk).absorb x (acc c) + ((child' c).depth, value ev mk (child' c)) = acc (c + 1)) ∧ + (∀ c < (children x).length, (reachInv ev mk x₀).frame x (acc c) ∧ Reach mk x₀ (child' c) ∧ (child' c).bound < x.bound ∧ (child' c).depth = x.depth + 1) ∧ - (x.depth, value mk x) = (scheme mk).finish x (acc (children x).length) := by - obtain ⟨h0, hnext, hdone, habs, hfin⟩ := walk mk ha fun c => value mk (child x mk c) - refine ⟨frameAt x fun c => value mk (child x mk c), + (x.depth, value ev mk x) = (scheme ev mk).finish x (acc (children x).length) := by + obtain ⟨h0, hnext, hdone, habs, hfin⟩ := walk ev mk ha fun c => value ev mk (child x mk c) + refine ⟨frameAt x fun c => value ev mk (child x mk c), fun c => child x mk ((children x).getD c (0, 0, [], 0)), h0, hnext, hdone, fun c hc => habs c hc, fun c hc => ⟨⟨hx, ha, c, hc.le, rfl⟩, ?_, ?_, rfl⟩, ?_⟩ · exact Reach.step _ hx ha (List.getD_eq_getElem _ _ hc ▸ List.getElem_mem hc) · exact edges_lt_bound_of_active ha · simp only [scheme, Prod.mk.injEq, true_and] - rw [value_of_active mk ha, hfin] + rw [value_of_active ev mk ha, hfin] /-- The leaves and values of a derivation over the reached calls. -/ -private theorem reach_leaf {x : Call} (hl : (scheme mk).isLeaf x = true) : - (x.depth, value mk x) = (scheme mk).leaf x := by +private theorem reach_leaf {x : Call T} (hl : (scheme ev mk).isLeaf x = true) : + (x.depth, value ev mk x) = (scheme ev mk).leaf x := by have hl' : active x = false := by simpa [scheme] using hl - simp [scheme, value_of_not_active mk hl'] + simp [scheme, value_of_not_active ev mk hl'] -private theorem active_of_isLeaf_eq_false {x : Call} (hl : (scheme mk).isLeaf x = false) : +private theorem active_of_isLeaf_eq_false {x : Call T} (hl : (scheme ev mk).isLeaf x = false) : active x = true := by simpa [scheme] using hl /-- **A derivation of the root with its height.** A root at depth `0` with edge bound `B` has a derivation of its tagged value over the reached calls with at most `B` stack levels, for every child builder. -/ theorem exists_eval_reachInv (hx₀ : x₀.depth = 0) : - ∃ N H, (scheme mk).Eval (reachInv mk x₀) x₀ (0, value mk x₀) N H ∧ H ≤ x₀.bound := by - obtain ⟨N, H, he, hH⟩ := Scheme.exists_eval_of_height (R := scheme mk) (I := reachInv mk x₀) - Call.bound Call.depth (fun x => (x.depth, value mk x)) x₀.bound (fun x _ hl => reach_leaf hl) + ∃ N H, (scheme ev mk).Eval (reachInv ev mk x₀) x₀ (0, value ev mk x₀) N H ∧ H ≤ x₀.bound := by + obtain ⟨N, H, he, hH⟩ := Scheme.exists_eval_of_height (R := scheme ev mk) (I := reachInv ev mk x₀) + Call.bound Call.depth (fun x => (x.depth, value ev mk x)) x₀.bound (fun x _ hl => reach_leaf hl) (fun x hx hl => by have ha := active_of_isLeaf_eq_false hl have hd := (show Reach mk x₀ x from hx).depth_add_two_le_of_active ha @@ -182,10 +183,11 @@ value over the reached calls with at most `Nat.recursionBound b D 0` nodes and ` theorem exists_eval_reachInv_count (hx₀ : x₀.depth = 0) (D : ℕ) (b : ℕ → ℕ) (hcnt : ∀ x, Reach mk x₀ x → active x = true → x.depth < D ∧ (children x).length ≤ b x.depth) : - ∃ N H, (scheme mk).Eval (reachInv mk x₀) x₀ (0, value mk x₀) N H ∧ + ∃ N H, (scheme ev mk).Eval (reachInv ev mk x₀) x₀ (0, value ev mk x₀) N H ∧ N ≤ Nat.recursionBound b D 0 ∧ H ≤ D := by - obtain ⟨N, H, he, hN, hH⟩ := Scheme.exists_eval_of_counted (R := scheme mk) (I := reachInv mk x₀) - Call.bound Call.depth (fun x => (x.depth, value mk x)) b D (fun x _ hl => reach_leaf hl) + obtain ⟨N, H, he, hN, hH⟩ := Scheme.exists_eval_of_counted (R := scheme ev mk) + (I := reachInv ev mk x₀) + Call.bound Call.depth (fun x => (x.depth, value ev mk x)) b D (fun x _ hl => reach_leaf hl) (fun x hx hl => by have ha := active_of_isLeaf_eq_false hl obtain ⟨hd, hb⟩ := hcnt x hx ha diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionLeaf.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionLeaf.lean index 5a9865f61..46dd54e3e 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionLeaf.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionLeaf.lean @@ -17,11 +17,11 @@ import Complexity.Computability.Machines.Turing.MultiTape.Encodings.Length # The leaves of the fast contraction algorithm The cost of the leaves of the native recursion of Theorem D.1 of [OpenAI2026ETH] -(`Cslib.Circuits.Frontier.FastContraction.leafCertificate`), the leaf clause of the resource -analysis `Cslib.Complexity.CountingSimulation.FastAnalysis`. A leaf sums directly over the `2 ^ M` -edge assignments of a call with `M` edges (§D.4.7, p. 64), and the entry of a packet vertex costs -`(m + 2) ^ L` for `m` target modes and `L` row ports, the source's `exp(O(L log s))` (§D.4.6, -p. 63). +(`Cslib.Circuits.Frontier.FastContraction.leafCertificate`, over tables), the leaf clause of the +resource analysis `Cslib.Complexity.CountingSimulation.FastAnalysis`. A leaf sums directly over the +`2 ^ M` edge assignments of a call with `M` edges (§D.4.7, p. 64), and the entry of a packet vertex +costs `(m + 2) ^ L` for `m` target modes and `L` row ports, the source's `exp(O(L log s))` +(§D.4.6, p. 63). **The cost of a leaf** (`FastContraction.leafCertificate_le`): with at most `R` target modes and `Λ` row ports per vertex, time `K (n + R + 1) ^ K 2 ^ M (R + 2) ^ Λ` and space `K (n + R + 1) ^ K` @@ -74,12 +74,18 @@ namespace FastContraction open GaloisRingArith NativePacket ChildCursor NativeRecovery ContractionSchedule NativeChild Cslib.GenericRAM Cslib.GenericRAM.StackRecursion Turing.MultiTapeTM +variable {T : Type} + /-! ### Encoded lengths -/ +section Lengths + +variable (encT : T ↪ List Bool) + /-- The scale, the precision and the coefficients of the modulus are at most the encoded length of a call. -/ -theorem scale_add_prec_add_length_fl_le (x : Call) : - x.scale + x.prec + x.fl.length ≤ (encCall x).length := by +theorem scale_add_prec_add_length_fl_le (x : Call T) : + x.scale + x.prec + x.fl.length ≤ (encCall encT x).length := by have h := length_le_length_encList encNat x.fl obtain ⟨⟨s, d, b, p, fl, r⟩, D⟩ := x simp only [Call.scale, Call.prec, Call.fl, encCall, encParams, length_encPair, encUnary_apply, @@ -87,32 +93,37 @@ theorem scale_add_prec_add_length_fl_le (x : Call) : omega /-- The network of a call is at most its encoded length. -/ -theorem length_net_le (x : Call) : - (DescribedNetwork.encDescribed VertexDesc.enc x.net).length ≤ (encCall x).length := by +theorem length_net_le (x : Call T) : + (DescribedNetwork.encDescribed (VertexDesc.enc encT) x.net).length ≤ + (encCall encT x).length := by obtain ⟨p, D⟩ := x simp only [Call.net, encCall, length_encPair] omega /-- A vertex of a call is at most its encoded length. -/ -theorem length_vertex_le {x : Call} {v : List ℕ × VertexDesc} (hv : v ∈ x.net.vertices) : - (encPair (encList encNat) VertexDesc.enc v).length ≤ (encCall x).length := by - have h := length_le_encList_of_mem (encPair (encList encNat) VertexDesc.enc) hv - have h2 : (encList (encPair (encList encNat) VertexDesc.enc) x.net.vertices).length ≤ - (DescribedNetwork.encDescribed VertexDesc.enc x.net).length := by - change _ ≤ (encPair encUnary (encList (encPair (encList encNat) VertexDesc.enc)) +theorem length_vertex_le {x : Call T} {v : List ℕ × VertexDesc T} + (hv : v ∈ x.net.vertices) : + (encPair (encList encNat) (VertexDesc.enc encT) v).length ≤ (encCall encT x).length := by + have h := length_le_encList_of_mem (encPair (encList encNat) (VertexDesc.enc encT)) hv + have h2 : (encList (encPair (encList encNat) (VertexDesc.enc encT)) x.net.vertices).length ≤ + (DescribedNetwork.encDescribed (VertexDesc.enc encT) x.net).length := by + change _ ≤ (encPair encUnary (encList (encPair (encList encNat) (VertexDesc.enc encT))) (x.net.numEdges, x.net.vertices)).length rw [length_encPair] dsimp only omega - have h3 := length_net_le x + have h3 := length_net_le encT x omega /-- The number of vertices of a call is at most its encoded length. -/ -theorem length_vertices_le (x : Call) : x.net.vertices.length ≤ (encCall x).length := by - have h := DescribedNetwork.length_numEdges_vertices_le (encT := VertexDesc.enc) x.net - have h3 := length_net_le x +theorem length_vertices_le (x : Call T) : + x.net.vertices.length ≤ (encCall encT x).length := by + have h := DescribedNetwork.length_numEdges_vertices_le (encT := VertexDesc.enc encT) x.net + have h3 := length_net_le encT x omega +end Lengths + /-! ### The cost of a leaf -/ /-- `c (y + 1) ^ d ≤ c W ^ d` when `y + 1 ≤ W`. -/ @@ -261,25 +272,26 @@ private theorem space_assemble {Sd Si Ss cd dd ci di W A Zb c₁ c₂ E₀ K₁ whose vertices have at most `R` target modes and at most `Λ` row ports on every bit list on their ports, direct summation takes time at most `K (n + R + 1) ^ K 2 ^ M (R + 2) ^ Λ` and space at most `K (n + R + 1) ^ K`, whatever the child builder. -/ -theorem leafCertificate_le : ∃ K : ℕ, ∀ (mk : Call → State → ℕ × DescribedNetwork VertexDesc) - (x : Call) (R Λ : ℕ), +theorem leafCertificate_le : ∃ K : ℕ, + ∀ (mk : Call (List ℕ) → State → ℕ × DescribedNetwork (VertexDesc (List ℕ))) + (x : Call (List ℕ)) (R Λ : ℕ), (∀ v ∈ x.net.vertices, v.2.modes ≤ R ∧ ∀ bs : List Bool, bs.length = v.1.length → v.2.rowPorts bs ≤ Λ) → (leafCertificate mk).time x ≤ - K * ((encCall x).length + R + 1) ^ K * 2 ^ x.edges * (R + 2) ^ Λ ∧ - (leafCertificate mk).space x ≤ K * ((encCall x).length + R + 1) ^ K := by + K * ((encCall (encList encNat) x).length + R + 1) ^ K * 2 ^ x.edges * (R + 2) ^ Λ ∧ + (leafCertificate mk).space x ≤ K * ((encCall (encList encNat) x).length + R + 1) ^ K := by obtain ⟨K₁, hK₁⟩ := DescribedNetwork.contractionCertificate_le (ops := SumOps.galois) - (eval := VertexDesc.entry) (encQ := encPair encUnary (encList encNat)) - (encY := encList encNat) (encT := VertexDesc.enc) SumOps.galois_polyTime + (eval := VertexDesc.entry tableEntry) (encQ := encPair encUnary (encList encNat)) + (encY := encList encNat) (encT := VertexDesc.enc (encList encNat)) SumOps.galois_polyTime VertexDesc.entryCertificate obtain ⟨K₂, hK₂⟩ := VertexDesc.entryCertificate_le - have hD := NativeCertificate.ofPolyTime_isPolynomial depth_polyTime - have hI := NativeCertificate.ofPolyTime_isPolynomial leafInput_polyTime + have hD := NativeCertificate.ofPolyTime_isPolynomial (depth_polyTime (encList encNat)) + have hI := NativeCertificate.ofPolyTime_isPolynomial (leafInput_polyTime (encList encNat)) obtain ⟨cd, dd, hdt⟩ := hD.1.exists_le obtain ⟨cd', dd', hds⟩ := hD.2.exists_le obtain ⟨ci, di, hit⟩ := hI.1.exists_le obtain ⟨ci', di', his⟩ := hI.2.exists_le - obtain ⟨cl, dl, hl⟩ := leafInput_polyTime.polyBounded_length.exists_le + obtain ⟨cl, dl, hl⟩ := (leafInput_polyTime (encList encNat)).polyBounded_length.exists_le obtain ⟨cp, dp, hp⟩ := PacketCtx.p_polyTime.polyBounded_length.exists_le obtain ⟨cf, df, hf⟩ := PacketCtx.fl_polyTime.polyBounded_length.exists_le obtain ⟨ct, dt, ht⟩ := VertexDesc.tableEntry_polyTime.polyBounded_length.exists_le @@ -293,22 +305,22 @@ theorem leafCertificate_le : ∃ K : ℕ, ∀ (mk : Call → State → ℕ × De (K₁ * c₁ ^ K₁ + K₂ * c₂ ^ K₂) + cd' + ci' := ⟨_, rfl⟩ obtain ⟨Dg, hDg⟩ : ∃ Dg, Dg = 1 + E₀ * (K₁ + K₂) + dd + di + dd' + di' := ⟨_, rfl⟩ refine ⟨G + Dg, fun mk x R Λ hRΛ => ?_⟩ - obtain ⟨n, hn⟩ : ∃ n, n = (encCall x).length := ⟨_, rfl⟩ + obtain ⟨n, hn⟩ : ∃ n, n = (encCall (encList encNat) x).length := ⟨_, rfl⟩ obtain ⟨W, hW⟩ : ∃ W, W = n + R + 1 := ⟨_, rfl⟩ rw [← hn, show n + R + 1 = W from hW.symm] have hW1 : 1 ≤ W := by omega have hnW : n + 1 ≤ W := by omega -- The precision and the modulus of the call. - have hpfl := scale_add_prec_add_length_fl_le x + have hpfl := scale_add_prec_add_length_fl_le (encList encNat) x rw [← hn] at hpfl -- Every vertex and bit list on its ports is at most `3 n + 1` long. - have hq (v : List ℕ × VertexDesc) (hv : v ∈ x.net.vertices) (bs : List Bool) + have hq (v : List ℕ × VertexDesc (List ℕ)) (hv : v ∈ x.net.vertices) (bs : List Bool) (hbs : bs.length = v.1.length) : - (encPair VertexDesc.enc encBits (v.2, bs)).length ≤ 3 * n + 1 := by - have h1 := length_vertex_le hv + (encPair (VertexDesc.enc (encList encNat)) encBits (v.2, bs)).length ≤ 3 * n + 1 := by + have h1 := length_vertex_le (encList encNat) hv have h2 := length_le_length_encList encNat v.1 rw [length_encPair] at h1 ⊢ - change 2 * (VertexDesc.enc v.2).length + 1 + bs.length ≤ 3 * n + 1 + change 2 * (VertexDesc.enc (encList encNat) v.2).length + 1 + bs.length ≤ 3 * n + 1 omega -- The reduced coefficient lists. obtain ⟨Rv, hRv⟩ : ∃ Rv, Rv = n * (2 * n + 3) + @@ -320,13 +332,13 @@ theorem leafCertificate_le : ∃ K : ℕ, ∀ (mk : Call → State → ℕ × De have : x.fl.length * (2 * x.prec + 3) ≤ n * (2 * n + 3) := Nat.mul_le_mul (by omega) (by omega) omega - have hpacket (v : List ℕ × VertexDesc) (hv : v ∈ x.net.vertices) (d : PacketDesc) + have hpacket (v : List ℕ × VertexDesc (List ℕ)) (hv : v ∈ x.net.vertices) (d : PacketDesc) (hd : v.2 = .inr d) : ∀ y, SumOps.galois.Reduced (d.1.p, d.1.fl) y → (encList encNat y).length ≤ Rv := by intro y hy have h := SumOps.length_encList_le_of_galois_reduced hy simp only at h - have h1 := length_vertex_le hv + have h1 := length_vertex_le (encList encNat) hv rw [length_encPair, hd, length_encSum] at h1 simp only [Sum.elim_inr] at h1 have h2 : (PacketCtx.enc d.1).length ≤ n := by @@ -349,7 +361,7 @@ theorem leafCertificate_le : ∃ K : ℕ, ∀ (mk : Call → State → ℕ × De bs.length = v.1.length → VertexDesc.entryCertificate.time (v.2, bs) ≤ K₂ * (R + 2) ^ Λ * Zb ^ K₂ ∧ VertexDesc.entryCertificate.space (v.2, bs) ≤ K₂ * Zb ^ K₂ ∧ - (encList encNat (VertexDesc.entry v.2 bs)).length ≤ Rv := by + (encList encNat (VertexDesc.entry tableEntry v.2 bs)).length ≤ Rv := by intro v hv bs hbs have hlen := hq v hv bs hbs obtain ⟨hmodes, hrows⟩ := hRΛ v hv @@ -360,7 +372,8 @@ theorem leafCertificate_le : ∃ K : ℕ, ∀ (mk : Call → State → ℕ × De · exact hpacket v hv d hd obtain ⟨hT, hS⟩ := hK₂ (v.2, bs) Rv hRLE dsimp only at hT hS - have hZ : (encPair VertexDesc.enc encBits (v.2, bs)).length + v.2.modes + Rv + 2 ≤ Zb := by + have hZ : (encPair (VertexDesc.enc (encList encNat)) encBits (v.2, bs)).length + v.2.modes + + Rv + 2 ≤ Zb := by omega refine ⟨hT.trans ?_, hS.trans (Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hZ _)), ?_⟩ · refine Nat.mul_le_mul (Nat.mul_le_mul_left _ ?_) (Nat.pow_le_pow_left hZ _) @@ -369,30 +382,33 @@ theorem leafCertificate_le : ∃ K : ℕ, ∀ (mk : Call → State → ℕ × De · have := ht (v.2, bs) rw [hd] at this refine this.trans ?_ - have h3 : (encPair VertexDesc.enc encBits (Sum.inl t, bs)).length + 1 ≤ 3 * n + 2 := by + have h3 : (encPair (VertexDesc.enc (encList encNat)) encBits (Sum.inl t, bs)).length + 1 ≤ + 3 * n + 2 := by rw [← hd]; omega - calc ct * ((encPair VertexDesc.enc encBits (Sum.inl t, bs)).length + 1) ^ dt + calc ct * ((encPair (VertexDesc.enc (encList encNat)) encBits (Sum.inl t, bs)).length + + 1) ^ dt ≤ ct * (3 * n + 2) ^ dt := Nat.mul_le_mul_left _ (Nat.pow_le_pow_left h3 _) _ ≤ Rv := by omega - · exact hpacket v hv d hd _ (VertexDesc.reduced_entry_inr d bs) + · exact hpacket v hv d hd _ (VertexDesc.reduced_entry_inr tableEntry d bs) obtain ⟨hsT, hsS⟩ := hK₁ ((x.prec, x.fl), x.net) (K₂ * (R + 2) ^ Λ * Zb ^ K₂) (K₂ * Zb ^ K₂) Rv Rv hentry hred -- Polynomial pieces against `W`. - have hk : x.net.vertices.length + 1 ≤ W := by have := length_vertices_le x; omega + have hk : x.net.vertices.length + 1 ≤ W := by have := length_vertices_le (encList encNat) x; omega have hRvW : Rv ≤ cR * W ^ e := by rw [hRv, hcR, he]; exact rv_le hnW have hWE : W ^ e ≤ W ^ E₀ := Nat.pow_le_pow_right hW1 (by omega) - have hA1 : (DescribedNetwork.encInput (encPair encUnary (encList encNat)) VertexDesc.enc - ((x.prec, x.fl), x.net)).length + Rv + Rv + 1 ≤ c₁ * W ^ E₀ := by - have h1 : (DescribedNetwork.encInput (encPair encUnary (encList encNat)) VertexDesc.enc - ((x.prec, x.fl), x.net)).length ≤ cl * W ^ dl := + have hA1 : (DescribedNetwork.encInput (encPair encUnary (encList encNat)) + (VertexDesc.enc (encList encNat)) ((x.prec, x.fl), x.net)).length + Rv + Rv + 1 ≤ + c₁ * W ^ E₀ := by + have h1 : (DescribedNetwork.encInput (encPair encUnary (encList encNat)) + (VertexDesc.enc (encList encNat)) ((x.prec, x.fl), x.net)).length ≤ cl * W ^ dl := (hl x).trans (by rw [← hn]; exact mul_pow_le_of_le hnW) rw [hc₁] exact sum_le_of_le hW1 h1 (by omega) (hRvW.trans (Nat.mul_le_mul_left _ hWE)) have hZW : Zb ≤ c₂ * W ^ E₀ := by rw [hc₂, hZb] exact zb_le hW1 (by omega) (hRvW.trans (Nat.mul_le_mul_left _ hWE)) (by omega) - have hnW' : (encCall x).length + 1 ≤ W := by omega + have hnW' : (encCall (encList encNat) x).length + 1 ≤ W := by omega have hdt' := (hdt x).trans (mul_pow_le_of_le (c := cd) (d := dd) hnW') have hit' := (hit x).trans (mul_pow_le_of_le (c := ci) (d := di) hnW') have hds' := (hds x).trans (mul_pow_le_of_le (c := cd') (d := dd') hnW') @@ -415,7 +431,7 @@ theorem leafCertificate_le : ∃ K : ℕ, ∀ (mk : Call → State → ℕ × De `2 ^ a` and distinct among its row ports. So it has at most `2 ^ (⌊log₂ s⌋ / 32768) p` target modes and at most `2 ^ (⌊log₂ s⌋ / 32768)` row ports (`modes_le_of_packetShape`, `rowPorts_le_of_packetShape`). -/ -def PacketShape (x : Call) : Prop := +def PacketShape (x : Call T) : Prop := ∀ v ∈ x.net.vertices, ∀ d : PacketDesc, v.2 = .inr d → d.1.i < d.1.a ∧ d.1.a ≤ Nat.log 2 x.scale / 32768 ∧ d.1.tiles = 2 ^ (d.1.i + 1) ∧ d.1.nb ≤ x.prec ∧ (∀ y ∈ d.2.1, y.2 < 2 ^ d.1.a) ∧ ((d.2.1.filter (·.1)).map (·.2)).Nodup @@ -431,7 +447,7 @@ theorem packetShape_root (q : ℕ × ℕ × ExplicitTensorNetwork ℕ) : PacketS vertex keeps its descriptor, at a precision that only grows, and a new packet has `a` slot bits (`slotBits_le`), `i < a` (the valuation of its node), `2 ^ (i + 1)` tiles, the child's precision as its number of exponents per tile, and the slots of the packing, distinct within a packet. -/ -theorem packetShape_child {x : Call} (hx : WF x) (ha : active x = true) (hs : PacketShape x) +theorem packetShape_child {x : Call T} (hx : WF x) (ha : active x = true) (hs : PacketShape x) {c : State} (hc : c ∈ children x) : PacketShape (child x nativeMk c) := by -- The builder at a cursor state of a well-formed active call: the uncapped native child. have hmk : (nativeMk x c).2 = nativeChild x.fl (slots x) (level x ((nodes x).getD c.1 0)) @@ -484,7 +500,7 @@ theorem two_pow_log_div_le (s : ℕ) : 2 ^ (Nat.log 2 s / 32768) ≤ s + 1 := by _ ≤ s + 1 := Nat.le_succ s /-- **The target modes of a call with the packet shape**: at most `2 ^ (⌊log₂ s⌋ / 32768) p`. -/ -theorem modes_le_of_packetShape {x : Call} (hs : PacketShape x) {v : List ℕ × VertexDesc} +theorem modes_le_of_packetShape {x : Call T} (hs : PacketShape x) {v : List ℕ × VertexDesc T} (hv : v ∈ x.net.vertices) : v.2.modes ≤ 2 ^ (Nat.log 2 x.scale / 32768) * x.prec := by rcases hd : v.2 with t | d · simp [VertexDesc.modes] @@ -499,7 +515,7 @@ theorem modes_le_of_packetShape {x : Call} (hs : PacketShape x) {v : List ℕ × /-- **The row ports of a call with the packet shape**: at most `2 ^ (⌊log₂ s⌋ / 32768)`, since the slots of the row ports of a packet are distinct and below `2 ^ a`. -/ -theorem rowPorts_le_of_packetShape {x : Call} (hs : PacketShape x) {v : List ℕ × VertexDesc} +theorem rowPorts_le_of_packetShape {x : Call T} (hs : PacketShape x) {v : List ℕ × VertexDesc T} (hv : v ∈ x.net.vertices) (bs : List Bool) : v.2.rowPorts bs ≤ 2 ^ (Nat.log 2 x.scale / 32768) := by rcases hd : v.2 with t | d @@ -525,28 +541,32 @@ length `n` with `M` edges, scale `s` and precision `p` with the packet shape, wr `A = 2 ^ (⌊log₂ s⌋ / 32768)`, direct summation takes time at most `K (n + 1) ^ K 2 ^ M (A p + 2) ^ A` and space at most `K (n + 1) ^ K`. -/ theorem leafCertificate_le_of_packetShape : ∃ K : ℕ, - ∀ (mk : Call → State → ℕ × DescribedNetwork VertexDesc) (x : Call), PacketShape x → - (leafCertificate mk).time x ≤ K * ((encCall x).length + 1) ^ K * 2 ^ x.edges * + ∀ (mk : Call (List ℕ) → State → ℕ × DescribedNetwork (VertexDesc (List ℕ))) + (x : Call (List ℕ)), PacketShape x → + (leafCertificate mk).time x ≤ K * ((encCall (encList encNat) x).length + 1) ^ K * + 2 ^ x.edges * (2 ^ (Nat.log 2 x.scale / 32768) * x.prec + 2) ^ 2 ^ (Nat.log 2 x.scale / 32768) ∧ - (leafCertificate mk).space x ≤ K * ((encCall x).length + 1) ^ K := by + (leafCertificate mk).space x ≤ K * ((encCall (encList encNat) x).length + 1) ^ K := by obtain ⟨K, hK⟩ := leafCertificate_le refine ⟨2 * K, fun mk x hs => ?_⟩ obtain ⟨hT, hS⟩ := hK mk x (2 ^ (Nat.log 2 x.scale / 32768) * x.prec) (2 ^ (Nat.log 2 x.scale / 32768)) fun v hv => ⟨modes_le_of_packetShape hs hv, fun bs _ => rowPorts_le_of_packetShape hs hv bs⟩ - have hn := scale_add_prec_add_length_fl_le x + have hn := scale_add_prec_add_length_fl_le (encList encNat) x have hA := two_pow_log_div_le x.scale - have hR : (encCall x).length + 2 ^ (Nat.log 2 x.scale / 32768) * x.prec + 1 ≤ - ((encCall x).length + 1) ^ 2 := by + have hR : (encCall (encList encNat) x).length + 2 ^ (Nat.log 2 x.scale / 32768) * x.prec + 1 ≤ + ((encCall (encList encNat) x).length + 1) ^ 2 := by have : 2 ^ (Nat.log 2 x.scale / 32768) * x.prec ≤ - ((encCall x).length + 1) * (encCall x).length := Nat.mul_le_mul (by omega) (by omega) + ((encCall (encList encNat) x).length + 1) * (encCall (encList encNat) x).length := + Nat.mul_le_mul (by omega) (by omega) nlinarith - have hpow : K * ((encCall x).length + 2 ^ (Nat.log 2 x.scale / 32768) * x.prec + 1) ^ K ≤ - 2 * K * ((encCall x).length + 1) ^ (2 * K) := - calc _ ≤ K * (((encCall x).length + 1) ^ 2) ^ K := + have hpow : + K * ((encCall (encList encNat) x).length + 2 ^ (Nat.log 2 x.scale / 32768) * x.prec + 1) ^ K ≤ + 2 * K * ((encCall (encList encNat) x).length + 1) ^ (2 * K) := + calc _ ≤ K * (((encCall (encList encNat) x).length + 1) ^ 2) ^ K := Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hR _) - _ = K * ((encCall x).length + 1) ^ (2 * K) := by rw [← pow_mul] - _ ≤ 2 * K * ((encCall x).length + 1) ^ (2 * K) := + _ = K * ((encCall (encList encNat) x).length + 1) ^ (2 * K) := by rw [← pow_mul] + _ ≤ 2 * K * ((encCall (encList encNat) x).length + 1) ^ (2 * K) := Nat.mul_le_mul_right _ (by omega) exact ⟨hT.trans (Nat.mul_le_mul_right _ (Nat.mul_le_mul_right _ hpow)), hS.trans hpow⟩ @@ -634,18 +654,19 @@ provided that from `s₀` on it has at most `leafSize m` edges and precision at `s₀` on, `2 ^ M ≤ 2 ^ (C s / √⌊log₂ s⌋)` and the packet factor is subexponential (`exists_packetFactor_le`). -/ theorem exists_leafCertificate_le (C c s₀ : ℕ) : ∃ K : ℕ, - ∀ (mk : Call → State → ℕ × DescribedNetwork VertexDesc) (s : ℕ) (x : Call), 2 ≤ s → + ∀ (mk : Call (List ℕ) → State → ℕ × DescribedNetwork (VertexDesc (List ℕ))) (s : ℕ) + (x : Call (List ℕ)), 2 ≤ s → s ≤ x.scale → x.scale ≤ C * s → PacketShape x → x.edges ≤ 2 * x.scale → (s₀ ≤ s → x.edges ≤ leafSize x.scale ∧ x.prec ≤ x.scale ^ c) → (leafCertificate mk).time x ≤ - K * ((encCall x).length + 1) ^ K * 2 ^ (K * s / Nat.sqrt (Nat.log 2 s)) ∧ - (leafCertificate mk).space x ≤ K * ((encCall x).length + 1) ^ K := by + K * ((encCall (encList encNat) x).length + 1) ^ K * 2 ^ (K * s / Nat.sqrt (Nat.log 2 s)) ∧ + (leafCertificate mk).space x ≤ K * ((encCall (encList encNat) x).length + 1) ^ K := by obtain ⟨K₀, hK₀⟩ := leafCertificate_le_of_packetShape obtain ⟨K₁, hK₁⟩ := exists_packetFactor_le C c obtain ⟨Ks, hKs⟩ : ∃ Ks, Ks = K₀ * 2 ^ (2 * (C * s₀)) * (C * s₀ + 2) ^ (C * s₀) := ⟨_, rfl⟩ refine ⟨Ks + K₀ + C * s₀ + C + K₁, fun mk s x hs hsm hmC hshape hM hbig => ?_⟩ obtain ⟨hT, hS⟩ := hK₀ mk x hshape - set n := (encCall x).length with hn + set n := (encCall (encList encNat) x).length with hn set K := Ks + K₀ + C * s₀ + C + K₁ with hK set S := Nat.sqrt (Nat.log 2 s) with hSdef have hS1 : 1 ≤ S := Nat.one_le_sqrt_log_two hs @@ -659,7 +680,7 @@ theorem exists_leafCertificate_le (C c s₀ : ℕ) : ∃ K : ℕ, rcases lt_or_ge s s₀ with hsmall | hlarge · -- Below `s₀`: constants and a polynomial. have hmC' : x.scale ≤ C * s₀ := hmC.trans (Nat.mul_le_mul_left _ hsmall.le) - have hp : x.prec ≤ n := by have := scale_add_prec_add_length_fl_le x; omega + have hp : x.prec ≤ n := by have := scale_add_prec_add_length_fl_le (encList encNat) x; omega have h2M : 2 ^ x.edges ≤ 2 ^ (2 * (C * s₀)) := Nat.pow_le_pow_right (by norm_num) (by omega) have hbase : A * x.prec + 2 ≤ (C * s₀ + 2) * (n + 1) := by diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionMachine.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionMachine.lean index 922fff07f..0f1c09927 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionMachine.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionMachine.lean @@ -26,7 +26,10 @@ import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimeNatFr # The native machine of the fast contraction algorithm The stack recursion of `Cslib.Circuits.Frontier.FastContraction.scheme` as one native machine for -the contraction modulo `2 ^ P` of an explicit network `(r, G)`, with the precision `P` in binary. +the contraction modulo `2 ^ P` of an explicit network `(r, G)`, with the precision `P` in binary: +the root descriptors are tables (`T = List ℕ`), read by the entry procedure `tableEntry`. The +encodings, the root network (`FastContraction.rootNet`) and its polynomial-time construction are +stated for every type of root descriptors. **The root.** The precision is first capped at the encoded length of the network (`ExplicitTensorNetwork.capPrecision`), which does not change the residue. The root call @@ -81,6 +84,8 @@ namespace Cslib.Circuits.Frontier.FastContraction open GaloisRingArith ChildCursor Cslib.GenericRAM Cslib.GenericRAM.StackRecursion Turing.MultiTapeTM +variable {T : Type} + /-! ### Encodings -/ /-- The encoding of the parameters of a call: the scale, the depth, the edge bound and the @@ -90,9 +95,10 @@ abbrev encParams : Params ↪ List Bool := encPair encUnary (encPair encUnary (encPair encUnary (encPair encUnary (encPair (encList encNat) encNat)))) -/-- The encoding of a call: its parameters and its network. -/ -abbrev encCall : Call ↪ List Bool := - encPair encParams (DescribedNetwork.encDescribed VertexDesc.enc) +/-- The encoding of a call: its parameters and its network, with the root descriptors encoded by +`encT`. -/ +abbrev encCall (encT : T ↪ List Bool) : Call T ↪ List Bool := + encPair encParams (DescribedNetwork.encDescribed (VertexDesc.enc encT)) /-- The encoding of a frame: the cursor state and the accumulator, in binary. -/ abbrev encFrame : Frame ↪ List Bool := @@ -104,41 +110,47 @@ abbrev encValue : ℕ × List ℕ ↪ List Bool := encPair encUnary (encList enc /-! ### The leaves -/ +variable (encT : T ↪ List Bool) + /-- The depth of a call is polynomial-time. -/ -theorem depth_polyTime : ComputableInPolyTime Call.depth encCall encUnary := by +theorem depth_polyTime : ComputableInPolyTime (Call.depth (T := T)) (encCall encT) encUnary := by unfold Call.depth; fun_prop /-- The input of direct summation at a call, `((p, fl), D)`, is polynomial-time. -/ theorem leafInput_polyTime : - ComputableInPolyTime (fun x : Call => ((x.prec, x.fl), x.net)) encCall - (DescribedNetwork.encInput (encPair encUnary (encList encNat)) VertexDesc.enc) := by + ComputableInPolyTime (fun x : Call T => ((x.prec, x.fl), x.net)) (encCall encT) + (DescribedNetwork.encInput (encPair encUnary (encList encNat)) (VertexDesc.enc encT)) := by unfold Call.prec Call.fl Call.net; fun_prop -variable (mk : Call → State → ℕ × DescribedNetwork VertexDesc) +variable (mk : Call (List ℕ) → State → ℕ × DescribedNetwork (VertexDesc (List ℕ))) -/-- **The leaf certificate**: direct summation over the coefficient lists of `A_p`, with the native -evaluator of the vertex descriptors, tagged with the depth. -/ -@[expose] noncomputable def leafCertificate : NativeCertificate (scheme mk).leaf encCall encValue := - ((NativeCertificate.ofPolyTime depth_polyTime).prod - ((DescribedNetwork.contractionCertificate VertexDesc.entry SumOps.galois_polyTime - VertexDesc.entryCertificate).comp (NativeCertificate.ofPolyTime leafInput_polyTime))).congr +/-- **The leaf certificate** over tables: direct summation over the coefficient lists of `A_p`, +with the native evaluator of the vertex descriptors, tagged with the depth. -/ +@[expose] noncomputable def leafCertificate : + NativeCertificate (scheme tableEntry mk).leaf (encCall (encList encNat)) encValue := + ((NativeCertificate.ofPolyTime (depth_polyTime (encList encNat))).prod + ((DescribedNetwork.contractionCertificate (VertexDesc.entry tableEntry) + SumOps.galois_polyTime VertexDesc.entryCertificate).comp + (NativeCertificate.ofPolyTime (leafInput_polyTime (encList encNat))))).congr fun _ => rfl /-- The time of a leaf: the depth, the input of direct summation, and direct summation. -/ -theorem leafCertificate_time (x : Call) : +theorem leafCertificate_time (x : Call (List ℕ)) : (leafCertificate mk).time x = - (NativeCertificate.ofPolyTime depth_polyTime).time x + - ((NativeCertificate.ofPolyTime leafInput_polyTime).time x + - (DescribedNetwork.contractionCertificate VertexDesc.entry SumOps.galois_polyTime - VertexDesc.entryCertificate).time ((x.prec, x.fl), x.net)) := rfl + (NativeCertificate.ofPolyTime (depth_polyTime (encList encNat))).time x + + ((NativeCertificate.ofPolyTime (leafInput_polyTime (encList encNat))).time x + + (DescribedNetwork.contractionCertificate (VertexDesc.entry tableEntry) + SumOps.galois_polyTime VertexDesc.entryCertificate).time ((x.prec, x.fl), x.net)) := + rfl /-- The space of a leaf. -/ -theorem leafCertificate_space (x : Call) : +theorem leafCertificate_space (x : Call (List ℕ)) : (leafCertificate mk).space x = - (NativeCertificate.ofPolyTime depth_polyTime).space x + - ((NativeCertificate.ofPolyTime leafInput_polyTime).space x + - (DescribedNetwork.contractionCertificate VertexDesc.entry SumOps.galois_polyTime - VertexDesc.entryCertificate).space ((x.prec, x.fl), x.net)) := rfl + (NativeCertificate.ofPolyTime (depth_polyTime (encList encNat))).space x + + ((NativeCertificate.ofPolyTime (leafInput_polyTime (encList encNat))).space x + + (DescribedNetwork.contractionCertificate (VertexDesc.entry tableEntry) + SumOps.galois_polyTime VertexDesc.entryCertificate).space ((x.prec, x.fl), x.net)) := + rfl /-! ### The root -/ @@ -188,13 +200,14 @@ theorem irreducible_modulus (m : ℕ) : simpa [Polynomial.map_add, Polynomial.map_pow, Polynomial.map_X, Polynomial.map_one, Cslib.trinomial] using Cslib.irreducible_trinomial (modulusExp m) -/-- **The tables of an explicit network as vertex descriptors.** -/ -@[expose] def rootNet (G : ExplicitTensorNetwork ℕ) : DescribedNetwork VertexDesc := +/-- **The root descriptors of a network as vertex descriptors**; for an explicit network, its +tables. -/ +@[expose] def rootNet (G : DescribedNetwork T) : DescribedNetwork (VertexDesc T) := ⟨G.numEdges, G.vertices.map fun v => (v.1, .inl v.2)⟩ /-- **The root call** of a capped input `(p, r, G)`: scale `m`, depth `0`, edge bound `m + 1`, precision `p`, the modulus and the tables of `G`. -/ -@[expose] def root (q : ℕ × ℕ × ExplicitTensorNetwork ℕ) : Call := +@[expose] def root (q : ℕ × ℕ × ExplicitTensorNetwork ℕ) : Call (List ℕ) := ((q.2.2.numEdges, 0, q.2.2.numEdges + 1, q.1, modulus q.2.2.numEdges, q.2.1), rootNet q.2.2) /-- The constant of the clock. -/ @@ -207,7 +220,7 @@ precision `p`, the modulus and the tables of `G`. -/ /-- **The root computes the contraction of `G`**: in `A_p`, the contraction of the tables read as constants is the image of the contraction of `G`. -/ theorem val_rootNet (p : ℕ) (fl : List ℕ) (G : ExplicitTensorNetwork ℕ) : - (rootNet G).contraction (fun t bs => val p fl (VertexDesc.entry t bs)) = + (rootNet G).contraction (fun t bs => val p fl (VertexDesc.entry tableEntry t bs)) = (G.contraction : Ring p fl) := by rw [← DescribedNetwork.contraction_entry] have h := DescribedNetwork.map_contraction (Nat.castRingHom (Ring p fl)) @@ -287,33 +300,34 @@ private theorem network_polyTime : (ComputableInPolyTime.snd encNat ExplicitTensorNetwork.encExplicitNetwork).comp (ComputableInPolyTime.snd encUnary (encPair encNat ExplicitTensorNetwork.encExplicitNetwork)) -/-- **The tables as descriptors are polynomial-time.** -/ -theorem rootNet_polyTime : ComputableInPolyTime rootNet ExplicitTensorNetwork.encExplicitNetwork - (DescribedNetwork.encDescribed VertexDesc.enc) := by - have hpair : ComputableInPolyTime (DescribedNetwork.equivProd (T := List ℕ)) - ExplicitTensorNetwork.encExplicitNetwork - (encPair encUnary (encList (encPair (encList encNat) (encList encNat)))) := +/-- **The root descriptors as vertex descriptors are polynomial-time.** -/ +theorem rootNet_polyTime : + ComputableInPolyTime rootNet (DescribedNetwork.encDescribed encT) + (DescribedNetwork.encDescribed (VertexDesc.enc encT)) := by + have hpair : ComputableInPolyTime (DescribedNetwork.equivProd (T := T)) + (DescribedNetwork.encDescribed encT) + (encPair encUnary (encList (encPair (encList encNat) encT))) := ComputableInPolyTime.of_eq fun _ => rfl have hm := (ComputableInPolyTime.fst _ _).comp hpair have hvs := (ComputableInPolyTime.snd _ _).comp hpair - have hv : ComputableInPolyTime (fun q : ExplicitTensorNetwork ℕ × (List ℕ × List ℕ) => - (q.2.1, (Sum.inl q.2.2 : VertexDesc))) - (encPair ExplicitTensorNetwork.encExplicitNetwork (encPair (encList encNat) (encList encNat))) - (encPair (encList encNat) VertexDesc.enc) := + have hv : ComputableInPolyTime (fun q : DescribedNetwork T × (List ℕ × T) => + (q.2.1, (Sum.inl q.2.2 : VertexDesc T))) + (encPair (DescribedNetwork.encDescribed encT) (encPair (encList encNat) encT)) + (encPair (encList encNat) (VertexDesc.enc encT)) := ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _)).prod ((ComputableInPolyTime.sumInl _ _).comp ((ComputableInPolyTime.snd _ _).comp (ComputableInPolyTime.snd _ _))) - have hmap := ComputableInPolyTime.mapWithInput (f := fun _ v => (v.1, (Sum.inl v.2 : VertexDesc))) - hvs hv - have hout : ComputableInPolyTime (DescribedNetwork.equivProd (T := VertexDesc)).symm - (encPair encUnary (encList (encPair (encList encNat) VertexDesc.enc))) - (DescribedNetwork.encDescribed VertexDesc.enc) := + have hmap := ComputableInPolyTime.mapWithInput + (f := fun _ v => (v.1, (Sum.inl v.2 : VertexDesc T))) hvs hv + have hout : ComputableInPolyTime (DescribedNetwork.equivProd (T := VertexDesc T)).symm + (encPair encUnary (encList (encPair (encList encNat) (VertexDesc.enc encT)))) + (DescribedNetwork.encDescribed (VertexDesc.enc encT)) := ComputableInPolyTime.of_eq fun _ => rfl exact (hout.comp (hm.prod hmap)).of_enc_eq fun _ => rfl /-- **The root call is polynomial-time**, from a capped input. -/ theorem root_polyTime : ComputableInPolyTime root ExplicitTensorNetwork.encContractionInput - encCall := by + (encCall (encList encNat)) := by have hp := ComputableInPolyTime.fst encUnary (encPair encNat ExplicitTensorNetwork.encExplicitNetwork) have hr := (ComputableInPolyTime.fst encNat ExplicitTensorNetwork.encExplicitNetwork).comp @@ -321,7 +335,7 @@ theorem root_polyTime : ComputableInPolyTime root ExplicitTensorNetwork.encContr exact (edges_polyTime.prod ((ComputableInPolyTime.const 0).prod ((ComputableInPolyTime.unary_add' edges_polyTime (ComputableInPolyTime.const 1)).prod (hp.prod ((modulus_polyTime.comp edges_polyTime).prod hr))))).prod - (rootNet_polyTime.comp network_polyTime) + ((rootNet_polyTime (encList encNat)).comp network_polyTime) /-- **The clock is polynomial-time**, from a capped input. -/ theorem fuel_polyTime : ComputableInPolyTime fuel ExplicitTensorNetwork.encContractionInput @@ -337,7 +351,7 @@ theorem fuel_polyTime : ComputableInPolyTime fuel ExplicitTensorNetwork.encContr constant coordinate of a returned root value modulo `2 ^ p` if the run returns a value tagged `0`, and direct summation otherwise. -/ @[expose] noncomputable def fastValue (q : ℕ × ℕ × ExplicitTensorNetwork ℕ) : ℕ := - ((scheme mk).run fuel root (ExplicitTensorNetwork.capPrecision q)).elim + ((scheme tableEntry mk).run fuel root (ExplicitTensorNetwork.capPrecision q)).elim (q.2.2.contraction % 2 ^ q.1) fun v => if v.1 = 0 then v.2.getD 0 0 % 2 ^ (ExplicitTensorNetwork.capPrecision q).1 else q.2.2.contraction % 2 ^ q.1 @@ -345,23 +359,26 @@ constant coordinate of a returned root value modulo `2 ^ p` if the run returns a /-- **The machine is correct on well-formed inputs**, for every fuel. If the step of an active call is correct and well-formedness passes to the children, then on every input whose root is well-formed the result is the contraction modulo `2 ^ P`. -/ -theorem fastValue_eq {WF : Call → Prop} (hstep : StepCorrect mk WF) (hwf : WFChildren mk WF) +theorem fastValue_eq {WF : Call (List ℕ) → Prop} (hstep : StepCorrect tableEntry mk WF) + (hwf : WFChildren mk WF) (q : ℕ × ℕ × ExplicitTensorNetwork ℕ) (hroot : WF (root (ExplicitTensorNetwork.capPrecision q))) : fastValue mk q = q.2.2.contraction % 2 ^ q.1 := by unfold fastValue - rcases hrun : (scheme mk).run fuel root (ExplicitTensorNetwork.capPrecision q) with _ | ⟨t, y⟩ + rcases hrun : (scheme tableEntry mk).run fuel root (ExplicitTensorNetwork.capPrecision q) with + _ | ⟨t, y⟩ · rfl · simp only [Option.elim_some] split_ifs with ht · subst ht - have hy := eq_value_of_run mk (fuel := fuel) (root := root) rfl hrun + have hy := eq_value_of_run tableEntry mk (fuel := fuel) (root := root) rfl hrun have hval : val (ExplicitTensorNetwork.capPrecision q).1 (modulus (ExplicitTensorNetwork.capPrecision q).2.2.numEdges) y = (rootNet (ExplicitTensorNetwork.capPrecision q).2.2).contraction fun t bs => val (ExplicitTensorNetwork.capPrecision q).1 (modulus (ExplicitTensorNetwork.capPrecision q).2.2.numEdges) - (VertexDesc.entry t bs) := hy ▸ val_value mk hstep hwf _ hroot + (VertexDesc.entry tableEntry t bs) := + hy ▸ val_value tableEntry mk hstep hwf _ hroot rw [val_rootNet] at hval rw [getD_mod_of_val_eq (modulus_ne_nil _) hval] exact ExplicitTensorNetwork.contraction_mod_two_pow_min q.1 q.2.2 @@ -379,8 +396,9 @@ variable {mk} /-- **The clocked run** from a capped input, as one native machine, given polynomial-time components of the scheme. -/ @[expose] noncomputable def runCertificate - (hpoly : (scheme mk).PolyTime encCall encFrame encValue) : - NativeCertificate ((scheme mk).run fuel root) ExplicitTensorNetwork.encContractionInput + (hpoly : (scheme tableEntry mk).PolyTime (encCall (encList encNat)) encFrame encValue) : + NativeCertificate ((scheme tableEntry mk).run fuel root) + ExplicitTensorNetwork.encContractionInput (encOption encValue) := Scheme.certificate hpoly (leafCertificate mk) (NativeCertificate.ofPolyTime fuel_polyTime) (NativeCertificate.ofPolyTime root_polyTime) @@ -409,7 +427,7 @@ theorem tag_polyTime : /-- **The fast machine**: cap the precision and run the recursion; on a value tagged `0`, read off its constant coordinate, and otherwise sum directly. It computes `fastValue`. -/ @[expose] noncomputable def fastCertificate - (hpoly : (scheme mk).PolyTime encCall encFrame encValue) : + (hpoly : (scheme tableEntry mk).PolyTime (encCall (encList encNat)) encFrame encValue) : NativeCertificate (fastValue mk) encInput encNat := (NativeCertificate.option ((runCertificate hpoly).comp @@ -421,19 +439,20 @@ off its constant coordinate, and otherwise sum directly. It computes `fastValue` (NativeCertificate.ofPolyTime (ComputableInPolyTime.fst encInput encValue))))).congr fun q => by simp only [fastValue, Function.comp_apply] - cases (scheme mk).run fuel root (ExplicitTensorNetwork.capPrecision q) with + cases (scheme tableEntry mk).run fuel root (ExplicitTensorNetwork.capPrecision q) with | none => rfl | some v => simp only [Option.elim_some, decide_eq_true_eq] /-- The time of the fast machine, unfolded: the capped run twice, the input, and the decoding or direct summation. -/ -theorem fastCertificate_time (hpoly : (scheme mk).PolyTime encCall encFrame encValue) +theorem fastCertificate_time + (hpoly : (scheme tableEntry mk).PolyTime (encCall (encList encNat)) encFrame encValue) (q : ℕ × ℕ × ExplicitTensorNetwork ℕ) : (fastCertificate hpoly).time q = 2 * ((NativeCertificate.ofPolyTime ExplicitTensorNetwork.capPrecision_polyTime).time q + (runCertificate hpoly).time (ExplicitTensorNetwork.capPrecision q)) + (encInput q).length + - ((scheme mk).run fuel root (ExplicitTensorNetwork.capPrecision q)).elim + ((scheme tableEntry mk).run fuel root (ExplicitTensorNetwork.capPrecision q)).elim (ExplicitTensorNetwork.directContractionBinaryCertificate.time q) fun v => (NativeCertificate.ofPolyTime tag_polyTime).time (q, v) + if decide (v.1 = 0) = true then @@ -443,13 +462,14 @@ theorem fastCertificate_time (hpoly : (scheme mk).PolyTime encCall encFrame encV ExplicitTensorNetwork.directContractionBinaryCertificate.time q := rfl /-- The space of the fast machine, unfolded. -/ -theorem fastCertificate_space (hpoly : (scheme mk).PolyTime encCall encFrame encValue) +theorem fastCertificate_space + (hpoly : (scheme tableEntry mk).PolyTime (encCall (encList encNat)) encFrame encValue) (q : ℕ × ℕ × ExplicitTensorNetwork ℕ) : (fastCertificate hpoly).space q = 2 * ((NativeCertificate.ofPolyTime ExplicitTensorNetwork.capPrecision_polyTime).space q + (runCertificate hpoly).space (ExplicitTensorNetwork.capPrecision q)) + (encInput q).length + - ((scheme mk).run fuel root (ExplicitTensorNetwork.capPrecision q)).elim + ((scheme tableEntry mk).run fuel root (ExplicitTensorNetwork.capPrecision q)).elim (ExplicitTensorNetwork.directContractionBinaryCertificate.space q) fun v => (NativeCertificate.ofPolyTime tag_polyTime).space (q, v) + if decide (v.1 = 0) = true then diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionPolyTime.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionPolyTime.lean index 4d83637e2..a96d7467e 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionPolyTime.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionPolyTime.lean @@ -36,10 +36,12 @@ import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimeRadix /-! # The components of the native contraction recursion in polynomial time -The scheme `Cslib.Circuits.Frontier.FastContraction.scheme mk` of the contraction recursion of +The scheme `Cslib.Circuits.Frontier.FastContraction.scheme ev mk` of the contraction recursion of [OpenAI2026ETH] has polynomial-time components (`Cslib.GenericRAM.StackRecursion.Scheme.PolyTime`) -for the encodings `FastContraction.encCall`, `encFrame` and `encValue` whenever the child builder -`mk` is polynomial-time (`FastContraction.scheme_polyTime`). The native child builder is +for the encodings `FastContraction.encCall encT`, `encFrame` and `encValue` whenever the child +builder `mk` is polynomial-time (`FastContraction.scheme_polyTime`), for every type `T` of root +descriptors with an encoding `encT` and every entry procedure `ev`: the leaf test does not +evaluate an entry, and the descriptors are only copied. The native child builder is (`FastContraction.nativeMk_polyTime`), so the scheme of `FastContraction.nativeMk` has polynomial-time components (`FastContraction.scheme_nativeMk_polyTime`). @@ -190,53 +192,57 @@ namespace Cslib.Circuits.Frontier.FastContraction open GaloisRingArith ChildCursor NativeRecovery ContractionSchedule NativeChild Cslib.GenericRAM Cslib.GenericRAM.StackRecursion +variable {T : Type} {encT : T ↪ List Bool} + /-! ### The parameters of a call -/ /-- The scale is polynomial-time. -/ -theorem scale_polyTime : ComputableInPolyTime Call.scale encCall encUnary := by +theorem scale_polyTime : ComputableInPolyTime Call.scale (encCall encT) encUnary := by unfold Call.scale; fun_prop /-- The edge bound is polynomial-time. -/ -theorem bound_polyTime : ComputableInPolyTime Call.bound encCall encUnary := by +theorem bound_polyTime : ComputableInPolyTime Call.bound (encCall encT) encUnary := by unfold Call.bound; fun_prop /-- The precision is polynomial-time. -/ -theorem prec_polyTime : ComputableInPolyTime Call.prec encCall encUnary := by +theorem prec_polyTime : ComputableInPolyTime Call.prec (encCall encT) encUnary := by unfold Call.prec; fun_prop /-- The coefficients of the modulus are polynomial-time. -/ -theorem fl_polyTime : ComputableInPolyTime Call.fl encCall (encList encNat) := by +theorem fl_polyTime : ComputableInPolyTime Call.fl (encCall encT) (encList encNat) := by unfold Call.fl; fun_prop /-- The number of rows is polynomial-time. -/ -theorem rows_polyTime : ComputableInPolyTime Call.rows encCall encNat := by +theorem rows_polyTime : ComputableInPolyTime Call.rows (encCall encT) encNat := by unfold Call.rows; fun_prop /-- The network is polynomial-time. -/ theorem net_polyTime : - ComputableInPolyTime Call.net encCall (DescribedNetwork.encDescribed VertexDesc.enc) := by + ComputableInPolyTime Call.net (encCall encT) + (DescribedNetwork.encDescribed (VertexDesc.enc encT)) := by unfold Call.net; fun_prop /-- The number of edges is polynomial-time, in unary. -/ -theorem edges_polyTime : ComputableInPolyTime Call.edges encCall encUnary := +theorem edges_polyTime : ComputableInPolyTime Call.edges (encCall encT) encUnary := DescribedNetwork.numEdges_polyTime.comp net_polyTime /-- The vertices are polynomial-time. -/ -theorem vertices_polyTime : ComputableInPolyTime (fun x : Call => x.net.vertices) encCall - (encList (encPair (encList encNat) VertexDesc.enc)) := +theorem vertices_polyTime : ComputableInPolyTime (fun x : Call T => x.net.vertices) (encCall encT) + (encList (encPair (encList encNat) (VertexDesc.enc encT))) := DescribedNetwork.vertices_polyTime.comp net_polyTime /-! ### The schedule of a call -/ /-- The number of label coordinates is polynomial-time. -/ -theorem slots_polyTime : ComputableInPolyTime slots encCall encUnary := - slotBits_polyTime.comp (scale_polyTime.prod depth_polyTime) +theorem slots_polyTime : ComputableInPolyTime slots (encCall encT) encUnary := + slotBits_polyTime.comp (scale_polyTime.prod (depth_polyTime encT)) /-- `2 ^ a ≤ s + 1` at every call. -/ -theorem two_pow_slots_le (x : Call) : 2 ^ slots x ≤ x.scale + 1 := two_pow_slotBits_le _ _ +theorem two_pow_slots_le (x : Call T) : 2 ^ slots x ≤ x.scale + 1 := two_pow_slotBits_le _ _ /-- The number `2 ^ a` of slots is polynomial-time, in unary. -/ -theorem twoPowSlots_polyTime : ComputableInPolyTime (fun x => 2 ^ slots x) encCall encUnary := +theorem twoPowSlots_polyTime : ComputableInPolyTime (fun x => 2 ^ slots x) + (encCall encT) encUnary := ComputableInPolyTime.binary_to_unary_bounded (ComputableInPolyTime.binary_two_pow.comp slots_polyTime) (ComputableInPolyTime.unary_add' scale_polyTime (ComputableInPolyTime.const 1)) @@ -244,27 +250,27 @@ theorem twoPowSlots_polyTime : ComputableInPolyTime (fun x => 2 ^ slots x) encCa /-- The number `2 ^ (a + 1)` of grid indices is polynomial-time, in unary. -/ theorem twoPowSlotsSucc_polyTime : - ComputableInPolyTime (fun x => 2 ^ (slots x + 1)) encCall encUnary := + ComputableInPolyTime (fun x => 2 ^ (slots x + 1)) (encCall encT) encUnary := (ComputableInPolyTime.unary_add' twoPowSlots_polyTime twoPowSlots_polyTime).of_enc_eq fun x => by rw [pow_succ, mul_two] /-- The number of levels is polynomial-time. -/ -theorem levels_polyTime : ComputableInPolyTime levels encCall encUnary := - taper_polyTime.comp (scale_polyTime.prod depth_polyTime) +theorem levels_polyTime : ComputableInPolyTime levels (encCall encT) encUnary := + taper_polyTime.comp (scale_polyTime.prod (depth_polyTime encT)) /-- The multiplicity step is polynomial-time. -/ -theorem step_polyTime : ComputableInPolyTime step encCall encUnary := - taperStep_polyTime.comp (scale_polyTime.prod (depth_polyTime.prod edges_polyTime)) +theorem step_polyTime : ComputableInPolyTime step (encCall encT) encUnary := + taperStep_polyTime.comp (scale_polyTime.prod ((depth_polyTime encT).prod edges_polyTime)) /-- The number of interpolation points is polynomial-time, in unary. -/ -theorem numPoints_polyTime : ComputableInPolyTime numPoints encCall encUnary := +theorem numPoints_polyTime : ComputableInPolyTime numPoints (encCall encT) encUnary := ComputableInPolyTime.unary_add' (ComputableInPolyTime.unary_mul' edges_polyTime (ComputableInPolyTime.unary_sub' (ComputableInPolyTime.unary_mul' (ComputableInPolyTime.const 2) twoPowSlots_polyTime) (ComputableInPolyTime.const 1))) (ComputableInPolyTime.const 1) /-- The shift `Δ'` is polynomial-time, in unary. -/ -theorem shift_polyTime : ComputableInPolyTime shift encCall encUnary := +theorem shift_polyTime : ComputableInPolyTime shift (encCall encT) encUnary := ComputableInPolyTime.unary_add' (ComputableInPolyTime.unary_add' (ComputableInPolyTime.unary_mul' (ComputableInPolyTime.unary_mul' (ComputableInPolyTime.unary_mul' @@ -277,7 +283,7 @@ theorem shift_polyTime : ComputableInPolyTime shift encCall encUnary := (ComputableInPolyTime.unary_add' slots_polyTime (ComputableInPolyTime.const 1))) /-- The common precision `N = p + Δ'` is polynomial-time, in unary. -/ -theorem wide_polyTime : ComputableInPolyTime wide encCall encUnary := +theorem wide_polyTime : ComputableInPolyTime wide (encCall encT) encUnary := ComputableInPolyTime.unary_add' prec_polyTime shift_polyTime /-! ### Nodes, levels and precisions -/ @@ -290,14 +296,14 @@ private theorem twoVal_le (b d : ℕ) : twoVal b d ≤ b := by · exact (List.length_filter_le _ _).trans (List.length_range (n := b)).le /-- Every level is at most `a + 1`. -/ -theorem level_le (x : Call) (k : ℕ) : level x k ≤ slots x + 1 := twoVal_le _ _ +theorem level_le (x : Call T) (k : ℕ) : level x k ≤ slots x + 1 := twoVal_le _ _ /-- The level of a grid index is polynomial-time, in unary. -/ theorem level_polyTime : - ComputableInPolyTime (fun q : Call × ℕ => level q.1 q.2) (encPair encCall encUnary) + ComputableInPolyTime (fun q : Call T × ℕ => level q.1 q.2) (encPair (encCall encT) encUnary) encUnary := by - have hx := ComputableInPolyTime.fst encCall encUnary - have hk := ComputableInPolyTime.snd encCall encUnary + have hx := ComputableInPolyTime.fst (encCall encT) encUnary + have hk := ComputableInPolyTime.snd (encCall encT) encUnary have hL := twoPowSlots_polyTime.comp hx have h := computableInPolyTime_twoVal (ComputableInPolyTime.unary_add' (slots_polyTime.comp hx) (ComputableInPolyTime.const 1)) @@ -306,49 +312,52 @@ theorem level_polyTime : exact h /-- The nodes of positive multiplicity are polynomial-time, as unary grid indices. -/ -theorem nodes_polyTime : ComputableInPolyTime nodes encCall (encList encUnary) := by - have hx := ComputableInPolyTime.fst encCall encUnary - have hk := ComputableInPolyTime.snd encCall encUnary +theorem nodes_polyTime : ComputableInPolyTime nodes (encCall encT) (encList encUnary) := by + have hx := ComputableInPolyTime.fst (encCall encT) encUnary + have hk := ComputableInPolyTime.snd (encCall encT) encUnary have hL := twoPowSlots_polyTime.comp hx have hmult := computableInPolyTime_mult (slots_polyTime.comp hx) hL (levels_polyTime.comp hx) (step_polyTime.comp hx) hk - have htest : ComputableInPolyTime (fun q : Call × ℕ => + have htest : ComputableInPolyTime (fun q : Call T × ℕ => decide (q.2 ≠ 2 ^ slots q.1 ∧ 0 < mult (slots q.1) (levels q.1) (step q.1) q.2)) - (encPair encCall encUnary) encBool := + (encPair (encCall encT) encUnary) encBool := (ComputableInPolyTime.bool_and' (ComputableInPolyTime.bool_not.comp (ComputableInPolyTime.decide_eq' hk hL)) (ComputableInPolyTime.unary_lt' (ComputableInPolyTime.const 0) hmult)).of_enc_eq fun q => by simp only [Function.comp_apply, Bool.decide_and, decide_not] have h := ComputableInPolyTime.filterWithInput - (test := fun (x : Call) k => + (test := fun (x : Call T) k => decide (k ≠ 2 ^ slots x ∧ 0 < mult (slots x) (levels x) (step x) k)) (ComputableInPolyTime.range.comp twoPowSlotsSucc_polyTime) htest exact h /-- The grid index of the `i`-th node is polynomial-time, in unary. -/ theorem node_polyTime : - ComputableInPolyTime (fun q : Call × ℕ => (nodes q.1).getD q.2 0) (encPair encCall encUnary) + ComputableInPolyTime (fun q : Call T × ℕ => (nodes q.1).getD q.2 0) + (encPair (encCall encT) encUnary) encUnary := by have h := ComputableInPolyTime.listGetDWithInput - (nodes_polyTime.comp (ComputableInPolyTime.fst encCall encUnary)) - (ComputableInPolyTime.snd encCall encUnary) 0 + (nodes_polyTime.comp (ComputableInPolyTime.fst (encCall encT) encUnary)) + (ComputableInPolyTime.snd (encCall encT) encUnary) 0 exact h /-- The level of the `i`-th node is polynomial-time, in unary. -/ theorem nodeLevel_polyTime : - ComputableInPolyTime (fun q : Call × ℕ => level q.1 ((nodes q.1).getD q.2 0)) - (encPair encCall encUnary) encUnary := by - have h := level_polyTime.comp ((ComputableInPolyTime.fst encCall encUnary).prod node_polyTime) + ComputableInPolyTime (fun q : Call T × ℕ => level q.1 ((nodes q.1).getD q.2 0)) + (encPair (encCall encT) encUnary) encUnary := by + have h := level_polyTime.comp + ((ComputableInPolyTime.fst (encCall encT) encUnary).prod node_polyTime) exact h /-- The number `2 ^ (v₂ t + 1)` of tiles of the `i`-th node is polynomial-time, in unary. -/ theorem tiles_polyTime : - ComputableInPolyTime (fun q : Call × ℕ => 2 ^ (level q.1 ((nodes q.1).getD q.2 0) + 1)) - (encPair encCall encUnary) encUnary := by + ComputableInPolyTime (fun q : Call T × ℕ => 2 ^ (level q.1 ((nodes q.1).getD q.2 0) + 1)) + (encPair (encCall encT) encUnary) encUnary := by have hv := ComputableInPolyTime.binary_two_pow.comp - (ComputableInPolyTime.unary_add' nodeLevel_polyTime (ComputableInPolyTime.const 1)) + (ComputableInPolyTime.unary_add' (nodeLevel_polyTime (encT := encT)) + (ComputableInPolyTime.const 1)) have hb := ComputableInPolyTime.unary_mul' (ComputableInPolyTime.const 4) - (twoPowSlots_polyTime.comp (ComputableInPolyTime.fst encCall encUnary)) + (twoPowSlots_polyTime.comp (ComputableInPolyTime.fst (encCall encT) encUnary)) have h := ComputableInPolyTime.binary_to_unary_bounded hv hb fun q => by simp only [Function.comp_apply] calc 2 ^ (level q.1 ((nodes q.1).getD q.2 0) + 1) ≤ 2 ^ (slots q.1 + 2) := @@ -359,12 +368,12 @@ theorem tiles_polyTime : /-- **The precision of the `i`-th node is polynomial-time**, in unary. -/ theorem nodePrec_polyTime : - ComputableInPolyTime (fun q : Call × ℕ => nodePrec q.1 q.2) (encPair encCall encUnary) + ComputableInPolyTime (fun q : Call T × ℕ => nodePrec q.1 q.2) (encPair (encCall encT) encUnary) encUnary := by - have hx := ComputableInPolyTime.fst encCall encUnary + have hx := ComputableInPolyTime.fst (encCall encT) encUnary have hpow : ComputableInPolyTime - (fun q : Call × ℕ => 2 ^ (slots q.1 - level q.1 ((nodes q.1).getD q.2 0))) - (encPair encCall encUnary) encUnary := by + (fun q : Call T × ℕ => 2 ^ (slots q.1 - level q.1 ((nodes q.1).getD q.2 0))) + (encPair (encCall encT) encUnary) encUnary := by have h := ComputableInPolyTime.binary_to_unary_bounded (ComputableInPolyTime.binary_two_pow.comp (ComputableInPolyTime.unary_sub' (slots_polyTime.comp hx) nodeLevel_polyTime)) (twoPowSlots_polyTime.comp hx) @@ -381,47 +390,49 @@ theorem nodePrec_polyTime : /-! ### The packing and the weights -/ /-- The capped number of rows is polynomial-time, in unary. -/ -theorem rowCap_polyTime : ComputableInPolyTime rowCap encCall encUnary := +theorem rowCap_polyTime : ComputableInPolyTime rowCap (encCall encT) encUnary := (ComputableInPolyTime.binary_min_unary.comp (((ComputableInPolyTime.length_list _).comp vertices_polyTime).prod rows_polyTime)).of_enc_eq fun x => by simp only [Function.comp_apply, rowCap, min_comm] /-- **The packing is polynomial-time** on every call. -/ -theorem packing_polyTime : ComputableInPolyTime packing encCall PacketPacking.encNativePacking := +theorem packing_polyTime : ComputableInPolyTime packing + (encCall encT) PacketPacking.encNativePacking := computableInPolyTime_nativeParentPacking rowCap_polyTime slots_polyTime net_polyTime /-- **The number of packets is polynomial-time**, in unary, on every call: there are at most `M (2 ^ a) ^ 12 ≤ M (s + 1) ^ 12` of them (`NativeChild.numPackets_nativeParentPacking_le`). -/ theorem packets_polyTime : - ComputableInPolyTime (fun x : Call => (packing x).2.1) encCall encUnary := + ComputableInPolyTime (fun x : Call T => (packing x).2.1) (encCall encT) encUnary := computableInPolyTime_numPackets_nativeParentPacking rowCap_polyTime slots_polyTime twoPowSlots_polyTime net_polyTime /-- **The weights of the modes of the `i`-th node are polynomial-time.** -/ theorem weights_polyTime : - ComputableInPolyTime (fun q : Call × ℕ => weights q.1 q.2) (encPair encCall encUnary) + ComputableInPolyTime (fun q : Call T × ℕ => weights q.1 q.2) (encPair (encCall encT) encUnary) (encList encNat) := by - have hx := ComputableInPolyTime.fst encCall encUnary - have hp := nodePrec_polyTime + have hx := ComputableInPolyTime.fst (encCall encT) encUnary + have hp := nodePrec_polyTime (encT := encT) have hlen := ComputableInPolyTime.unary_mul' (packets_polyTime.comp hx) (ComputableInPolyTime.unary_mul' tiles_polyTime hp) - have hj := ComputableInPolyTime.snd (encPair encCall encUnary) encUnary - have hpj := hp.comp (ComputableInPolyTime.fst (encPair encCall encUnary) encUnary) - have hf : ComputableInPolyTime (fun r : (Call × ℕ) × ℕ => r.2 % nodePrec r.1.1 r.1.2 + 1) - (encPair (encPair encCall encUnary) encUnary) encNat := by + have hj := ComputableInPolyTime.snd (encPair (encCall encT) encUnary) encUnary + have hpj := hp.comp (ComputableInPolyTime.fst (encPair (encCall encT) encUnary) encUnary) + have hf : ComputableInPolyTime (fun r : (Call T × ℕ) × ℕ => r.2 % nodePrec r.1.1 r.1.2 + 1) + (encPair (encPair (encCall encT) encUnary) encUnary) encNat := by have h := ComputableInPolyTime.unary_to_binary.comp (ComputableInPolyTime.unary_add' (ComputableInPolyTime.unary_mod.comp (hj.prod hpj)) (ComputableInPolyTime.const 1)) exact h have h := ComputableInPolyTime.mapWithInput - (f := fun (q : Call × ℕ) j => j % nodePrec q.1 q.2 + 1) + (f := fun (q : Call T × ℕ) j => j % nodePrec q.1 q.2 + 1) (ComputableInPolyTime.range.comp hlen) hf exact h /-- The number of modes of the `i`-th node is polynomial-time, in unary. -/ theorem weightsLength_polyTime : - ComputableInPolyTime (fun q : Call × ℕ => (weights q.1 q.2).length) (encPair encCall encUnary) + ComputableInPolyTime (fun q : Call T × ℕ => (weights q.1 q.2).length) + (encPair (encCall encT) encUnary) encUnary := by - have h := (ComputableInPolyTime.length_list _).comp weights_polyTime + have h := (ComputableInPolyTime.length_list _).comp (weights_polyTime (encT := encT)) exact h /-! ### Points and the table -/ @@ -444,46 +455,47 @@ theorem digits_polyTime : exact h /-- **The interpolation points are polynomial-time.** -/ -theorem points_polyTime : ComputableInPolyTime points encCall (encList (encList encNat)) := by - have hf : ComputableInPolyTime (fun r : Call × ℕ => digits r.1.fl.length r.2) - (encPair encCall encUnary) (encList encNat) := by +theorem points_polyTime : ComputableInPolyTime points (encCall encT) + (encList (encList encNat)) := by + have hf : ComputableInPolyTime (fun r : Call T × ℕ => digits r.1.fl.length r.2) + (encPair (encCall encT) encUnary) (encList encNat) := by have h := digits_polyTime.comp ((((ComputableInPolyTime.length_list _).comp fl_polyTime).comp - (ComputableInPolyTime.fst encCall encUnary)).prod (ComputableInPolyTime.snd _ _)) + (ComputableInPolyTime.fst (encCall encT) encUnary)).prod (ComputableInPolyTime.snd _ _)) exact h - have h := ComputableInPolyTime.mapWithInput (f := fun (x : Call) k => digits x.fl.length k) + have h := ComputableInPolyTime.mapWithInput (f := fun (x : Call T) k => digits x.fl.length k) (ComputableInPolyTime.range.comp numPoints_polyTime) hf exact h /-- **The table of native recovery is polynomial-time**, from a call and the stored values. -/ theorem table_polyTime : - ComputableInPolyTime (fun q : Call × List (List ℕ) => table q.1 q.2) - (encPair encCall (encList (encList encNat))) (encList (encList (encList encNat))) := by - let e := encPair encCall (encList (encList encNat)) - have hx := ComputableInPolyTime.fst encCall (encList (encList encNat)) + ComputableInPolyTime (fun q : Call T × List (List ℕ) => table q.1 q.2) + (encPair (encCall encT) (encList (encList encNat))) (encList (encList (encList encNat))) := by + let e := encPair (encCall encT) (encList (encList encNat)) + have hx := ComputableInPolyTime.fst (encCall encT) (encList (encList encNat)) have hx' := hx.comp (ComputableInPolyTime.fst e encUnary) - have hV' := (ComputableInPolyTime.snd encCall (encList (encList encNat))).comp + have hV' := (ComputableInPolyTime.snd (encCall encT) (encList (encList encNat))).comp (ComputableInPolyTime.fst e encUnary) have hk := ComputableInPolyTime.snd e encUnary have hn := numPoints_polyTime.comp hx' have hmem := ComputableInPolyTime.decide_mem (nodes_polyTime.comp hx') hk have hidx := ComputableInPolyTime.idxOfWithInput (nodes_polyTime.comp hx') hk - have hdrop : ComputableInPolyTime (fun r : (Call × List (List ℕ)) × ℕ => + have hdrop : ComputableInPolyTime (fun r : (Call T × List (List ℕ)) × ℕ => r.1.2.drop ((nodes r.1.1).idxOf r.2 * numPoints r.1.1)) (encPair e encUnary) (encList (encList encNat)) := .of_tidy (ComputableTidilyInPolyTime.listDropWithInput hV'.tidy (ComputableInPolyTime.unary_mul' hidx hn).tidy) - have htake : ComputableInPolyTime (fun r : (Call × List (List ℕ)) × ℕ => + have htake : ComputableInPolyTime (fun r : (Call T × List (List ℕ)) × ℕ => (r.1.2.drop ((nodes r.1.1).idxOf r.2 * numPoints r.1.1)).take (numPoints r.1.1)) (encPair e encUnary) (encList (encList encNat)) := .of_tidy (ComputableTidilyInPolyTime.listTakeWithInput hdrop.tidy hn.tidy) - have hf : ComputableInPolyTime (fun r : (Call × List (List ℕ)) × ℕ => + have hf : ComputableInPolyTime (fun r : (Call T × List (List ℕ)) × ℕ => if r.2 ∈ nodes r.1.1 then (r.1.2.drop ((nodes r.1.1).idxOf r.2 * numPoints r.1.1)).take (numPoints r.1.1) else []) (encPair e encUnary) (encList (encList encNat)) := by have h := ComputableInPolyTime.ite hmem htake (ComputableInPolyTime.const []) refine h.of_enc_eq fun r => ?_ simp only [Function.comp_apply, decide_eq_true_eq] - have h := ComputableInPolyTime.mapWithInput (f := fun (q : Call × List (List ℕ)) k => + have h := ComputableInPolyTime.mapWithInput (f := fun (q : Call T × List (List ℕ)) k => if k ∈ nodes q.1 then (q.2.drop ((nodes q.1).idxOf k * numPoints q.1)).take (numPoints q.1) else []) (ComputableInPolyTime.range.comp (twoPowSlotsSucc_polyTime.comp hx)) hf @@ -492,7 +504,7 @@ theorem table_polyTime : /-! ### Active calls -/ /-- Whether a call is active, as a conjunction of tests. -/ -theorem active_eq (x : Call) : active x = +theorem active_eq (x : Call T) : active x = (decide (leafSize x.scale < x.edges) && decide (1 ≤ levels x) && decide (levels x ≤ x.edges) && decide (levels x ≤ slots x) && x.net.vertices.all (fun v => decide (v.1.length ≤ degreeBound x.scale)) && @@ -500,9 +512,10 @@ theorem active_eq (x : Call) : active x = simp only [active, Bool.decide_and, List.all_eq, decide_eq_true_eq, Bool.and_assoc] /-- **Whether a call is active is polynomial-time.** -/ -theorem active_polyTime : ComputableInPolyTime active encCall encBool := by - have hdeg : ComputableInPolyTime (fun x : Call => - x.net.vertices.all (fun v => decide (v.1.length ≤ degreeBound x.scale))) encCall encBool := +theorem active_polyTime : ComputableInPolyTime active (encCall encT) encBool := by + have hdeg : ComputableInPolyTime (fun x : Call T => + x.net.vertices.all (fun v => decide (v.1.length ≤ degreeBound x.scale))) + (encCall encT) encBool := ComputableInPolyTime.allWithInput vertices_polyTime (ComputableInPolyTime.binary_le' (ComputableInPolyTime.unary_to_binary.comp ((ComputableInPolyTime.length_list _).comp ((ComputableInPolyTime.fst _ _).comp @@ -528,27 +541,28 @@ theorem active_polyTime : ComputableInPolyTime active encCall encBool := by section Scheme -variable (mk : Call → State → ℕ × DescribedNetwork VertexDesc) +variable (ev : T → List Bool → List ℕ) (mk : Call T → State → ℕ × DescribedNetwork (VertexDesc T)) /-- **The leaf test is polynomial-time.** -/ -theorem isLeaf_polyTime : ComputableInPolyTime (scheme mk).isLeaf encCall encBool := by - have h := ComputableInPolyTime.bool_not.comp active_polyTime +theorem isLeaf_polyTime : ComputableInPolyTime (scheme ev mk).isLeaf (encCall encT) encBool := by + have h := ComputableInPolyTime.bool_not.comp (active_polyTime (encT := encT)) exact h /-- **The initial accumulator is polynomial-time.** -/ -theorem start_polyTime : ComputableInPolyTime (scheme mk).start encCall encFrame := by - have hlen : ComputableInPolyTime (fun x : Call => (weights x 0).length) encCall encUnary := by +theorem start_polyTime : ComputableInPolyTime (scheme ev mk).start (encCall encT) encFrame := by + have hlen : ComputableInPolyTime (fun x : Call T => (weights x 0).length) + (encCall encT) encUnary := by have h := weightsLength_polyTime.comp - ((ComputableInPolyTime.id' (encIn := encCall)).prod (ComputableInPolyTime.const 0)) + ((ComputableInPolyTime.id' (encIn := (encCall encT))).prod (ComputableInPolyTime.const 0)) exact h - have hst : ComputableInPolyTime (fun x : Call => cursorStart (weights x)) encCall + have hst : ComputableInPolyTime (fun x : Call T => cursorStart (weights x)) (encCall encT) (encPair encUnary (encPair encUnary (encPair (encList encNat) encUnary))) := (ComputableInPolyTime.const 0).prod ((ComputableInPolyTime.const 0).prod ((ComputableInPolyTime.replicate hlen (ComputableInPolyTime.const 0)).prod (ComputableInPolyTime.const 0))) - have hst' : ComputableInPolyTime (fun x : Call => cursorStart (weights x)) encCall + have hst' : ComputableInPolyTime (fun x : Call T => cursorStart (weights x)) (encCall encT) ChildCursor.encState := hst - have h : ComputableInPolyTime (scheme mk).start encCall + have h : ComputableInPolyTime (scheme ev mk).start (encCall encT) (encPair (encOption ChildCursor.encState) (encPair (encList encNat) (encPair (encList encNat) (encList (encList encNat))))) := ((ComputableInPolyTime.optionSome _).comp hst').prod @@ -576,26 +590,27 @@ private theorem stateGroup_polyTime : ComputableInPolyTime (fun c : State => c.2.2.2) ChildCursor.encState encUnary := by unfold ChildCursor.encState; fun_prop -variable {mk} +variable {ev mk} /-- **The child call at a cursor state is polynomial-time**, given a polynomial-time builder. -/ theorem child_polyTime - (hmk : ComputableInPolyTime (fun q : Call × State => mk q.1 q.2) - (encPair encCall ChildCursor.encState) - (encPair encNat (DescribedNetwork.encDescribed VertexDesc.enc))) : - ComputableInPolyTime (fun q : Call × State => child q.1 mk q.2) - (encPair encCall ChildCursor.encState) encCall := by - have hx := ComputableInPolyTime.fst encCall ChildCursor.encState - have ht := stateNode_polyTime.comp (ComputableInPolyTime.snd encCall ChildCursor.encState) - have hprec : ComputableInPolyTime (fun q : Call × State => nodePrec q.1 q.2.1) - (encPair encCall ChildCursor.encState) encUnary := by + (hmk : ComputableInPolyTime (fun q : Call T × State => mk q.1 q.2) + (encPair (encCall encT) ChildCursor.encState) + (encPair encNat (DescribedNetwork.encDescribed (VertexDesc.enc encT)))) : + ComputableInPolyTime (fun q : Call T × State => child q.1 mk q.2) + (encPair (encCall encT) ChildCursor.encState) (encCall encT) := by + have hx := ComputableInPolyTime.fst (encCall encT) ChildCursor.encState + have ht := stateNode_polyTime.comp (ComputableInPolyTime.snd (encCall encT) ChildCursor.encState) + have hprec : ComputableInPolyTime (fun q : Call T × State => nodePrec q.1 q.2.1) + (encPair (encCall encT) ChildCursor.encState) encUnary := by have h := nodePrec_polyTime.comp (hx.prod ht) exact h - have h : ComputableInPolyTime (fun q : Call × State => child q.1 mk q.2) - (encPair encCall ChildCursor.encState) + have h : ComputableInPolyTime (fun q : Call T × State => child q.1 mk q.2) + (encPair (encCall encT) ChildCursor.encState) (encPair (encPair encUnary (encPair encUnary (encPair encUnary (encPair encUnary - (encPair (encList encNat) encNat))))) (DescribedNetwork.encDescribed VertexDesc.enc)) := - ((scale_polyTime.comp hx).prod ((ComputableInPolyTime.unary_add' (depth_polyTime.comp hx) + (encPair (encList encNat) encNat))))) + (DescribedNetwork.encDescribed (VertexDesc.enc encT))) := + ((scale_polyTime.comp hx).prod ((ComputableInPolyTime.unary_add' ((depth_polyTime encT).comp hx) (ComputableInPolyTime.const 1)).prod ((edges_polyTime.comp hx).prod (hprec.prod ((fl_polyTime.comp hx).prod ((ComputableInPolyTime.fst _ _).comp hmk)))))).prod ((ComputableInPolyTime.snd _ _).comp hmk) @@ -603,133 +618,139 @@ theorem child_polyTime /-- **Child generation is polynomial-time**, given a polynomial-time builder. -/ theorem next_polyTime - (hmk : ComputableInPolyTime (fun q : Call × State => mk q.1 q.2) - (encPair encCall ChildCursor.encState) - (encPair encNat (DescribedNetwork.encDescribed VertexDesc.enc))) : - ComputableInPolyTime (fun p : Call × Frame => (scheme mk).next p.1 p.2) - (encPair encCall encFrame) (encOption encCall) := by - have hc : ComputableInPolyTime (fun p : Call × Frame => p.2.1) (encPair encCall encFrame) + (hmk : ComputableInPolyTime (fun q : Call T × State => mk q.1 q.2) + (encPair (encCall encT) ChildCursor.encState) + (encPair encNat (DescribedNetwork.encDescribed (VertexDesc.enc encT)))) : + ComputableInPolyTime (fun p : Call T × Frame => (scheme ev mk).next p.1 p.2) + (encPair (encCall encT) encFrame) (encOption (encCall encT)) := by + have hc : ComputableInPolyTime (fun p : Call T × Frame => p.2.1) (encPair (encCall encT) encFrame) (encOption ChildCursor.encState) := - (ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd encCall encFrame) - have hbody : ComputableInPolyTime (fun r : (Call × Frame) × State => some (child r.1.1 mk r.2)) - (encPair (encPair encCall encFrame) ChildCursor.encState) (encOption encCall) := by - have h := (ComputableInPolyTime.optionSome encCall).comp ((child_polyTime hmk).comp - (((ComputableInPolyTime.fst encCall encFrame).comp (ComputableInPolyTime.fst _ _)).prod + (ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd (encCall encT) encFrame) + have hbody : ComputableInPolyTime (fun r : (Call T × Frame) × State => some (child r.1.1 mk r.2)) + (encPair (encPair (encCall encT) encFrame) ChildCursor.encState) + (encOption (encCall encT)) := by + have h := (ComputableInPolyTime.optionSome (encCall encT)).comp ((child_polyTime hmk).comp + (((ComputableInPolyTime.fst (encCall encT) encFrame).comp (ComputableInPolyTime.fst _ _)).prod (ComputableInPolyTime.snd _ _))) exact h have h := ComputableInPolyTime.optionElimWithInput - (body := fun (p : Call × Frame) (c : State) => some (child p.1 mk c)) hc - (ComputableInPolyTime.const (encOut := encOption encCall) none) hbody + (body := fun (p : Call T × Frame) (c : State) => some (child p.1 mk c)) hc + (ComputableInPolyTime.const (encOut := encOption (encCall encT)) none) hbody refine h.of_enc_eq fun p => ?_ rcases p with ⟨x, _ | c, acc⟩ <;> rfl -variable (mk) +variable (ev mk) /-- The inputs of `absorb` at a cursor state: the call, its frame, the child's value and the state. -/ -private abbrev AbsorbIn : Type := ((Call × Frame) × (ℕ × List ℕ)) × State +private abbrev AbsorbIn (T : Type) : Type := ((Call T × Frame) × (ℕ × List ℕ)) × State /-- The encoding of `AbsorbIn`. -/ -private abbrev encAbsorbIn : AbsorbIn ↪ List Bool := - encPair (encPair (encPair encCall encFrame) encValue) ChildCursor.encState +private abbrev encAbsorbIn (encT : T ↪ List Bool) : AbsorbIn T ↪ List Bool := + encPair (encPair (encPair (encCall encT) encFrame) encValue) ChildCursor.encState /-- The call of an input of `absorb`. -/ private theorem absorbCall_polyTime : - ComputableInPolyTime (fun r : AbsorbIn => r.1.1.1) encAbsorbIn encCall := - (ComputableInPolyTime.fst encCall encFrame).comp ((ComputableInPolyTime.fst _ encValue).comp + ComputableInPolyTime (fun r : AbsorbIn T => r.1.1.1) (encAbsorbIn encT) (encCall encT) := + (ComputableInPolyTime.fst (encCall encT) encFrame).comp + ((ComputableInPolyTime.fst _ encValue).comp (ComputableInPolyTime.fst _ ChildCursor.encState)) /-- The state of an input of `absorb`. -/ private theorem absorbState_polyTime : - ComputableInPolyTime (fun r : AbsorbIn => r.2) encAbsorbIn ChildCursor.encState := + ComputableInPolyTime (fun r : AbsorbIn T => r.2) (encAbsorbIn encT) ChildCursor.encState := ComputableInPolyTime.snd _ _ /-- **The cursor step of `absorb` is polynomial-time.** -/ private theorem absorbCursor_polyTime : - ComputableInPolyTime (fun r : AbsorbIn => cursorNext (weights r.1.1.1) (nodePrec r.1.1.1) - (nodes r.1.1.1).length (numPoints r.1.1.1) 64 r.2) encAbsorbIn (encOption encState) := by - have hx := absorbCall_polyTime - have hc := absorbState_polyTime + ComputableInPolyTime (fun r : AbsorbIn T => cursorNext (weights r.1.1.1) (nodePrec r.1.1.1) + (nodes r.1.1.1).length (numPoints r.1.1.1) 64 r.2) (encAbsorbIn encT) + (encOption encState) := by + have hx := absorbCall_polyTime (encT := encT) + have hc := absorbState_polyTime (encT := encT) have ht := stateNode_polyTime.comp hc have hT := (ComputableInPolyTime.length_list _).comp (nodes_polyTime.comp hx) have hn := numPoints_polyTime.comp hx - have hwt : ComputableInPolyTime (fun r : AbsorbIn => weights r.1.1.1 r.2.1) encAbsorbIn + have hwt : ComputableInPolyTime (fun r : AbsorbIn T => weights r.1.1.1 r.2.1) (encAbsorbIn encT) (encList encNat) := by have h := weights_polyTime.comp (hx.prod ht) exact h - have hpt : ComputableInPolyTime (fun r : AbsorbIn => nodePrec r.1.1.1 r.2.1) encAbsorbIn + have hpt : ComputableInPolyTime (fun r : AbsorbIn T => nodePrec r.1.1.1 r.2.1) (encAbsorbIn encT) encNat := by have h := ComputableInPolyTime.unary_to_binary.comp (nodePrec_polyTime.comp (hx.prod ht)) exact h - have hnext : ComputableInPolyTime (fun r : AbsorbIn => (weights r.1.1.1 (r.2.1 + 1)).length) - encAbsorbIn encUnary := by + have hnext : ComputableInPolyTime (fun r : AbsorbIn T => (weights r.1.1.1 (r.2.1 + 1)).length) + (encAbsorbIn encT) encUnary := by have h := weightsLength_polyTime.comp (hx.prod (ComputableInPolyTime.unary_add' ht (ComputableInPolyTime.const 1))) exact h - have hin : ComputableInPolyTime (fun r : AbsorbIn => + have hin : ComputableInPolyTime (fun r : AbsorbIn T => (((((nodes r.1.1.1).length, numPoints r.1.1.1, (64 : ℕ)), (weights r.1.1.1 r.2.1, nodePrec r.1.1.1 r.2.1, (weights r.1.1.1 (r.2.1 + 1)).length)), r.2) : StepInput)) - encAbsorbIn (encPair (encPair (encPair encUnary (encPair encUnary encUnary)) + (encAbsorbIn encT) (encPair (encPair (encPair encUnary (encPair encUnary encUnary)) (encPair (encList encNat) (encPair encNat encUnary))) ChildCursor.encState) := ((hT.prod (hn.prod (ComputableInPolyTime.const 64))).prod (hwt.prod (hpt.prod hnext))).prod hc - have hin' : ComputableInPolyTime (fun r : AbsorbIn => + have hin' : ComputableInPolyTime (fun r : AbsorbIn T => (((((nodes r.1.1.1).length, numPoints r.1.1.1, (64 : ℕ)), (weights r.1.1.1 r.2.1, nodePrec r.1.1.1 r.2.1, (weights r.1.1.1 (r.2.1 + 1)).length)), r.2) : StepInput)) - encAbsorbIn encStepInput := hin + (encAbsorbIn encT) encStepInput := hin refine (computableInPolyTime_cursorStep.comp hin').of_enc_eq fun r => ?_ rw [cursorNext_eq_cursorStep] rfl /-- **The accumulator step of `absorb` is polynomial-time.** -/ private theorem absorbAcc_polyTime : - ComputableInPolyTime (fun r : AbsorbIn => absorbAt (weights r.1.1.1) (nodePrec r.1.1.1) 64 + ComputableInPolyTime (fun r : AbsorbIn T => absorbAt (weights r.1.1.1) (nodePrec r.1.1.1) 64 (mul (wide r.1.1.1) r.1.1.1.fl) (add (wide r.1.1.1) r.1.1.1.fl) (one r.1.1.1.fl) - (zero r.1.1.1.fl) r.2 r.1.1.2.2 r.1.2.2) encAbsorbIn + (zero r.1.1.1.fl) r.2 r.1.1.2.2 r.1.2.2) (encAbsorbIn encT) (encPair (encList encNat) (encPair (encList encNat) (encList (encList encNat)))) := by - have hx := absorbCall_polyTime - have hc := absorbState_polyTime + have hx := absorbCall_polyTime (encT := encT) + have hc := absorbState_polyTime (encT := encT) have ht := stateNode_polyTime.comp hc have hN := wide_polyTime.comp hx have hfl := fl_polyTime.comp hx - have hacc : ComputableInPolyTime (fun r : AbsorbIn => r.1.1.2.2) encAbsorbIn + have hacc : ComputableInPolyTime (fun r : AbsorbIn T => r.1.1.2.2) (encAbsorbIn encT) (encPair (encList encNat) (encPair (encList encNat) (encList (encList encNat)))) := - (ComputableInPolyTime.snd _ _).comp ((ComputableInPolyTime.snd encCall encFrame).comp + (ComputableInPolyTime.snd _ _).comp ((ComputableInPolyTime.snd (encCall encT) encFrame).comp ((ComputableInPolyTime.fst _ encValue).comp (ComputableInPolyTime.fst _ ChildCursor.encState))) have hprod := (ComputableInPolyTime.fst _ _).comp hacc have hsum := (ComputableInPolyTime.fst _ _).comp ((ComputableInPolyTime.snd _ _).comp hacc) have hstored := (ComputableInPolyTime.snd _ _).comp ((ComputableInPolyTime.snd _ _).comp hacc) - have hy : ComputableInPolyTime (fun r : AbsorbIn => r.1.2.2) encAbsorbIn (encList encNat) := + have hy : ComputableInPolyTime (fun r : AbsorbIn T => r.1.2.2) (encAbsorbIn encT) + (encList encNat) := (ComputableInPolyTime.snd encUnary (encList encNat)).comp ((ComputableInPolyTime.snd _ _).comp (ComputableInPolyTime.fst _ ChildCursor.encState)) have hpy := computableInPolyTime_mul hN hfl hprod hy have hnew := computableInPolyTime_add hN hfl hsum hpy have hone := computableInPolyTime_one hfl have hzero := computableInPolyTime_zero hfl - have hlast : ComputableInPolyTime (fun r : AbsorbIn => + have hlast : ComputableInPolyTime (fun r : AbsorbIn T => (BudgetTuples.budgetNext (weights r.1.1.1 r.2.1) (nodePrec r.1.1.1 r.2.1) r.2.2.2.1).isNone) - encAbsorbIn encBool := by - have hwt : ComputableInPolyTime (fun r : AbsorbIn => weights r.1.1.1 r.2.1) encAbsorbIn + (encAbsorbIn encT) encBool := by + have hwt : ComputableInPolyTime (fun r : AbsorbIn T => weights r.1.1.1 r.2.1) (encAbsorbIn encT) (encList encNat) := by have h := weights_polyTime.comp (hx.prod ht) exact h - have hpt : ComputableInPolyTime (fun r : AbsorbIn => nodePrec r.1.1.1 r.2.1) encAbsorbIn + have hpt : ComputableInPolyTime (fun r : AbsorbIn T => nodePrec r.1.1.1 r.2.1) + (encAbsorbIn encT) encNat := by have h := ComputableInPolyTime.unary_to_binary.comp (nodePrec_polyTime.comp (hx.prod ht)) exact h - have hin : ComputableInPolyTime (fun r : AbsorbIn => - (weights r.1.1.1 r.2.1, nodePrec r.1.1.1 r.2.1, r.2.2.2.1)) encAbsorbIn + have hin : ComputableInPolyTime (fun r : AbsorbIn T => + (weights r.1.1.1 r.2.1, nodePrec r.1.1.1 r.2.1, r.2.2.2.1)) (encAbsorbIn encT) (encPair (encList encNat) (encPair encNat (encList encNat))) := hwt.prod (hpt.prod (stateExps_polyTime.comp hc)) - have hin' : ComputableInPolyTime (fun r : AbsorbIn => - (weights r.1.1.1 r.2.1, nodePrec r.1.1.1 r.2.1, r.2.2.2.1)) encAbsorbIn + have hin' : ComputableInPolyTime (fun r : AbsorbIn T => + (weights r.1.1.1 r.2.1, nodePrec r.1.1.1 r.2.1, r.2.2.2.1)) (encAbsorbIn encT) BudgetTuples.encBudgetInput := hin have h := ComputableInPolyTime.bool_not.comp (ComputableInPolyTime.optionIsSome (BudgetTuples.computableInPolyTime_budgetNext.comp hin')) refine h.of_enc_eq fun r => ?_ simp only [Function.comp_apply] cases BudgetTuples.budgetNext (weights r.1.1.1 r.2.1) (nodePrec r.1.1.1 r.2.1) r.2.2.2.1 <;> rfl - have hg : ComputableInPolyTime (fun r : AbsorbIn => decide (r.2.2.2.2 + 1 < 64)) encAbsorbIn + have hg : ComputableInPolyTime (fun r : AbsorbIn T => decide (r.2.2.2.2 + 1 < 64)) + (encAbsorbIn encT) encBool := ComputableInPolyTime.unary_lt' (ComputableInPolyTime.unary_add' (stateGroup_polyTime.comp hc) (ComputableInPolyTime.const 1)) (ComputableInPolyTime.const 64) @@ -743,23 +764,23 @@ private theorem absorbAcc_polyTime : /-- **Absorbing a child's value is polynomial-time.** -/ theorem absorb_polyTime : ComputableInPolyTime - (fun p : (Call × Frame) × (ℕ × List ℕ) => (scheme mk).absorb p.1.1 p.1.2 p.2) - (encPair (encPair encCall encFrame) encValue) encFrame := by - have hc : ComputableInPolyTime (fun p : (Call × Frame) × (ℕ × List ℕ) => p.1.2.1) - (encPair (encPair encCall encFrame) encValue) (encOption ChildCursor.encState) := - (ComputableInPolyTime.fst _ _).comp ((ComputableInPolyTime.snd encCall encFrame).comp + (fun p : (Call T × Frame) × (ℕ × List ℕ) => (scheme ev mk).absorb p.1.1 p.1.2 p.2) + (encPair (encPair (encCall encT) encFrame) encValue) encFrame := by + have hc : ComputableInPolyTime (fun p : (Call T × Frame) × (ℕ × List ℕ) => p.1.2.1) + (encPair (encPair (encCall encT) encFrame) encValue) (encOption ChildCursor.encState) := + (ComputableInPolyTime.fst _ _).comp ((ComputableInPolyTime.snd (encCall encT) encFrame).comp (ComputableInPolyTime.fst _ encValue)) - have hfallback : ComputableInPolyTime (fun p : (Call × Frame) × (ℕ × List ℕ) => p.1.2) - (encPair (encPair encCall encFrame) encValue) encFrame := - (ComputableInPolyTime.snd encCall encFrame).comp (ComputableInPolyTime.fst _ encValue) - have hbody : ComputableInPolyTime (fun r : AbsorbIn => + have hfallback : ComputableInPolyTime (fun p : (Call T × Frame) × (ℕ × List ℕ) => p.1.2) + (encPair (encPair (encCall encT) encFrame) encValue) encFrame := + (ComputableInPolyTime.snd (encCall encT) encFrame).comp (ComputableInPolyTime.fst _ encValue) + have hbody : ComputableInPolyTime (fun r : AbsorbIn T => ((cursorNext (weights r.1.1.1) (nodePrec r.1.1.1) (nodes r.1.1.1).length (numPoints r.1.1.1) 64 r.2, absorbAt (weights r.1.1.1) (nodePrec r.1.1.1) 64 (mul (wide r.1.1.1) r.1.1.1.fl) (add (wide r.1.1.1) r.1.1.1.fl) (one r.1.1.1.fl) - (zero r.1.1.1.fl) r.2 r.1.1.2.2 r.1.2.2) : Frame)) encAbsorbIn encFrame := + (zero r.1.1.1.fl) r.2 r.1.1.2.2 r.1.2.2) : Frame)) (encAbsorbIn encT) encFrame := absorbCursor_polyTime.prod (absorbAcc_polyTime) have h := ComputableInPolyTime.optionElimWithInput - (body := fun (p : (Call × Frame) × (ℕ × List ℕ)) (c : State) => + (body := fun (p : (Call T × Frame) × (ℕ × List ℕ)) (c : State) => ((cursorNext (weights p.1.1) (nodePrec p.1.1) (nodes p.1.1).length (numPoints p.1.1) 64 c, absorbAt (weights p.1.1) (nodePrec p.1.1) 64 (mul (wide p.1.1) p.1.1.fl) (add (wide p.1.1) p.1.1.fl) (one p.1.1.fl) (zero p.1.1.fl) c p.1.2.2 p.2.2) : Frame)) @@ -769,33 +790,34 @@ theorem absorb_polyTime : /-- **The value of a call is polynomial-time.** -/ theorem finish_polyTime : - ComputableInPolyTime (fun p : Call × Frame => (scheme mk).finish p.1 p.2) - (encPair encCall encFrame) encValue := by - have hx := ComputableInPolyTime.fst encCall encFrame - have hV : ComputableInPolyTime (fun p : Call × Frame => p.2.2.2.2) (encPair encCall encFrame) + ComputableInPolyTime (fun p : Call T × Frame => (scheme ev mk).finish p.1 p.2) + (encPair (encCall encT) encFrame) encValue := by + have hx := ComputableInPolyTime.fst (encCall encT) encFrame + have hV : ComputableInPolyTime (fun p : Call T × Frame => p.2.2.2.2) + (encPair (encCall encT) encFrame) (encList (encList encNat)) := (ComputableInPolyTime.snd _ _).comp ((ComputableInPolyTime.snd _ _).comp - ((ComputableInPolyTime.snd _ _).comp (ComputableInPolyTime.snd encCall encFrame))) - have htab : ComputableInPolyTime (fun p : Call × Frame => table p.1 p.2.2.2.2) - (encPair encCall encFrame) (encList (encList (encList encNat))) := by + ((ComputableInPolyTime.snd _ _).comp (ComputableInPolyTime.snd (encCall encT) encFrame))) + have htab : ComputableInPolyTime (fun p : Call T × Frame => table p.1 p.2.2.2.2) + (encPair (encCall encT) encFrame) (encList (encList (encList encNat))) := by have h := table_polyTime.comp (hx.prod hV) exact h have hrec := computableInPolyTime_recover (prec_polyTime.comp hx) (shift_polyTime.comp hx) (fl_polyTime.comp hx) (slots_polyTime.comp hx) (twoPowSlots_polyTime.comp hx) (levels_polyTime.comp hx) (step_polyTime.comp hx) (points_polyTime.comp hx) htab - have h := (depth_polyTime.comp hx).prod hrec + have h := ((depth_polyTime encT).comp hx).prod hrec exact h -variable {mk} +variable {ev mk} /-- **The components of the scheme are polynomial-time**, for a polynomial-time child builder. -/ theorem scheme_polyTime - (hmk : ComputableInPolyTime (fun q : Call × State => mk q.1 q.2) - (encPair encCall ChildCursor.encState) - (encPair encNat (DescribedNetwork.encDescribed VertexDesc.enc))) : - (scheme mk).PolyTime encCall encFrame encValue := - ⟨isLeaf_polyTime mk, start_polyTime mk, next_polyTime hmk, absorb_polyTime mk, - finish_polyTime mk⟩ + (hmk : ComputableInPolyTime (fun q : Call T × State => mk q.1 q.2) + (encPair (encCall encT) ChildCursor.encState) + (encPair encNat (DescribedNetwork.encDescribed (VertexDesc.enc encT)))) : + (scheme ev mk).PolyTime (encCall encT) encFrame encValue := + ⟨isLeaf_polyTime ev mk, start_polyTime ev mk, next_polyTime hmk, absorb_polyTime ev mk, + finish_polyTime ev mk⟩ end Scheme @@ -807,11 +829,11 @@ number of vertices and the exponents at the node's precision, so both are polyno number `2 ^ a` of slots is at most `s + 1` and the number `2 ^ (v₂ t + 1)` of tiles at most `4 (s + 1)`. -/ theorem nativeMk_polyTime : - ComputableInPolyTime (fun q : Call × State => nativeMk q.1 q.2) - (encPair encCall ChildCursor.encState) - (encPair encNat (DescribedNetwork.encDescribed VertexDesc.enc)) := by - have hx := ComputableInPolyTime.fst encCall ChildCursor.encState - have hc := ComputableInPolyTime.snd encCall ChildCursor.encState + ComputableInPolyTime (fun q : Call T × State => nativeMk q.1 q.2) + (encPair (encCall encT) ChildCursor.encState) + (encPair encNat (DescribedNetwork.encDescribed (VertexDesc.enc encT))) := by + have hx := ComputableInPolyTime.fst (encCall encT) ChildCursor.encState + have hc := ComputableInPolyTime.snd (encCall encT) ChildCursor.encState have ht := stateNode_polyTime.comp hc have hj := statePoint_polyTime.comp hc have hβ := stateExps_polyTime.comp hc @@ -821,42 +843,43 @@ theorem nativeMk_polyTime : have hL := twoPowSlots_polyTime.comp hx have hfl := fl_polyTime.comp hx have hD := net_polyTime.comp hx - have hi : ComputableInPolyTime (fun q : Call × State => level q.1 ((nodes q.1).getD q.2.1 0)) - (encPair encCall ChildCursor.encState) encUnary := by + have hi : ComputableInPolyTime (fun q : Call T × State => level q.1 ((nodes q.1).getD q.2.1 0)) + (encPair (encCall encT) ChildCursor.encState) encUnary := by have h := nodeLevel_polyTime.comp (hx.prod ht) exact h have hT : ComputableInPolyTime - (fun q : Call × State => 2 ^ (level q.1 ((nodes q.1).getD q.2.1 0) + 1)) - (encPair encCall ChildCursor.encState) encUnary := by + (fun q : Call T × State => 2 ^ (level q.1 ((nodes q.1).getD q.2.1 0) + 1)) + (encPair (encCall encT) ChildCursor.encState) encUnary := by have h := tiles_polyTime.comp (hx.prod ht) exact h - have hpt : ComputableInPolyTime (fun q : Call × State => nodePrec q.1 q.2.1) - (encPair encCall ChildCursor.encState) encUnary := by + have hpt : ComputableInPolyTime (fun q : Call T × State => nodePrec q.1 q.2.1) + (encPair (encCall encT) ChildCursor.encState) encUnary := by have h := nodePrec_polyTime.comp (hx.prod ht) exact h have hnode : ComputableInPolyTime - (fun q : Call × State => node (slots q.1) ((nodes q.1).getD q.2.1 0)) - (encPair encCall ChildCursor.encState) encIntBin := by + (fun q : Call T × State => node (slots q.1) ((nodes q.1).getD q.2.1 0)) + (encPair (encCall encT) ChildCursor.encState) encIntBin := by have h := ComputableInPolyTime.intBin_subNatNat.comp ((ComputableInPolyTime.unary_to_binary.comp (node_polyTime.comp (hx.prod ht))).prod (ComputableInPolyTime.unary_to_binary.comp hL)) refine h.of_enc_eq fun q => ?_ simp only [Function.comp_apply, node, Int.subNatNat_eq_coe, Nat.cast_pow, Nat.cast_ofNat] - have hζ : ComputableInPolyTime (fun q : Call × State => (points q.1).getD q.2.2.1 []) - (encPair encCall ChildCursor.encState) (encList encNat) := by + have hζ : ComputableInPolyTime (fun q : Call T × State => (points q.1).getD q.2.2.1 []) + (encPair (encCall encT) ChildCursor.encState) (encList encNat) := by have h := ComputableInPolyTime.listGetDWithInput (points_polyTime.comp hx) hj [] exact h have hcap : ComputableInPolyTime - (fun q : Call × State => q.2.2.2.1.map (min · (nodePrec q.1 q.2.1))) - (encPair encCall ChildCursor.encState) (encList encUnary) := by - have hf : ComputableInPolyTime (fun r : (Call × State) × ℕ => min r.2 (nodePrec r.1.1 r.1.2.1)) - (encPair (encPair encCall ChildCursor.encState) encNat) encUnary := by + (fun q : Call T × State => q.2.2.2.1.map (min · (nodePrec q.1 q.2.1))) + (encPair (encCall encT) ChildCursor.encState) (encList encUnary) := by + have hf : ComputableInPolyTime + (fun r : (Call T × State) × ℕ => min r.2 (nodePrec r.1.1 r.1.2.1)) + (encPair (encPair (encCall encT) ChildCursor.encState) encNat) encUnary := by have h := ComputableInPolyTime.binary_min_unary.comp ((hpt.comp (ComputableInPolyTime.fst _ _)).prod (ComputableInPolyTime.snd _ _)) refine h.of_enc_eq fun r => ?_ simp only [Function.comp_apply, min_comm] have h := ComputableInPolyTime.mapWithInput - (f := fun (q : Call × State) (b : ℕ) => min b (nodePrec q.1 q.2.1)) hβ hf + (f := fun (q : Call T × State) (b : ℕ) => min b (nodePrec q.1 q.2.1)) hβ hf exact h have hrows := computableInPolyTime_childRows_nativeParentPacking hr ha hi hD hg have hchild := computableInPolyTime_nativeChild_nativeParentPacking hfl ha hL hi hT hpt hnode hζ @@ -866,7 +889,8 @@ theorem nativeMk_polyTime : /-- **The components of the native contraction recursion are polynomial-time**: the hypothesis `hpoly` of `CountingSimulation.contractionAlgorithmOfNative`. -/ -theorem scheme_nativeMk_polyTime : (scheme nativeMk).PolyTime encCall encFrame encValue := +theorem scheme_nativeMk_polyTime (ev : T → List Bool → List ℕ) : + (scheme ev (nativeMk (T := T))).PolyTime (encCall encT) encFrame encValue := scheme_polyTime nativeMk_polyTime end Cslib.Circuits.Frontier.FastContraction diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionSchedule.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionSchedule.lean index 2cf1e3f19..388e67f5e 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionSchedule.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionSchedule.lean @@ -69,10 +69,12 @@ namespace Cslib.Circuits.Frontier.FastContraction open ContractionSchedule ChildCursor NativeRecovery NativeChild +variable {T : Type} + /-- **A call on the schedule** of a root with `m` edges, for the constant `C`: it keeps the root's scale and modulus, is well-formed, has maximum degree at most `degreeBound m` and fewer edges than its bound, and has at most `leafSize m` edges or is an active call of the schedule. -/ -structure OnSchedule (C m : ℕ) (x : Call) : Prop where +structure OnSchedule (C m : ℕ) (x : Call T) : Prop where /-- The scale is the root's number of edges. -/ scale_eq : x.scale = m /-- The modulus is the root's. -/ @@ -95,7 +97,7 @@ theorem four_mul_log_le_length_modulus (m : ℕ) : 4 * Nat.log 2 m ≤ (modulus rw [pow_succ] at h1 omega -variable {C m : ℕ} {x : Call} +variable {C m : ℕ} {x : Call T} namespace OnSchedule @@ -202,7 +204,7 @@ end OnSchedule /-- **Every reached call is on the schedule**, from a root on the schedule, once the schedule's certificate holds. -/ -theorem Reach.onSchedule (hB : ∀ d M p, Active C m d M p → ActiveBounds C m d M p) {x₀ : Call} +theorem Reach.onSchedule (hB : ∀ d M p, Active C m d M p → ActiveBounds C m d M p) {x₀ : Call T} (h₀ : OnSchedule C m x₀) (h : Reach nativeMk x₀ x) : OnSchedule C m x := by induction h with | root => exact h₀ @@ -211,7 +213,7 @@ theorem Reach.onSchedule (hB : ∀ d M p, Active C m d M p → ActiveBounds C m /-- **The root is on the schedule**: a well-formed root with `m` edges, at scale `m` with the modulus of `m`, of maximum degree at most `degreeBound m`, with edge bound `m + 1` and precision at most `C m` for `1 ≤ C`. -/ -theorem onSchedule_root {x₀ : Call} (hC : 1 ≤ C) (hs : x₀.scale = m) (he : x₀.edges = m) +theorem onSchedule_root {x₀ : Call T} (hC : 1 ≤ C) (hs : x₀.scale = m) (he : x₀.edges = m) (hfl : x₀.fl = modulus m) (hwf : WF x₀) (hdeg : ∀ v ∈ x₀.net.vertices, v.1.length ≤ degreeBound m) (hb : x₀.bound = m + 1) (hd : x₀.depth = 0) (hp : x₀.prec ≤ C * m) : OnSchedule C m x₀ := by @@ -257,7 +259,7 @@ theorem length_cursorList_le {ws : ℕ → List ℕ} {ps : ℕ → ℕ} {T n r B rw [List.map_const', List.sum_replicate, smul_eq_mul, List.length_range]; ring /-- The nodes of positive multiplicity are at most `2 ^ (a + 1)`. -/ -theorem length_nodes_le (x : Call) : (nodes x).length ≤ 2 ^ (slots x + 1) := +theorem length_nodes_le (x : Call T) : (nodes x).length ≤ 2 ^ (slots x + 1) := (List.length_filter_le _ _).trans List.length_range.le namespace OnSchedule @@ -322,9 +324,10 @@ end OnSchedule schedule's certificate holds at scale `m ≥ 2`, a root on the schedule at depth `0` has a derivation of its tagged value over the reached calls with at most `2 ^ ((245760 C + 37) m / √⌊log₂ m⌋)` nodes and `⌊log₂ m⌋` stack levels. -/ -theorem exists_eval_onSchedule (hB : ∀ d M p, Active C m d M p → ActiveBounds C m d M p) - {x₀ : Call} (h₀ : OnSchedule C m x₀) (hd : x₀.depth = 0) (hm : 2 ≤ m) : - ∃ N H, (scheme nativeMk).Eval (reachInv nativeMk x₀) x₀ (0, value nativeMk x₀) N H ∧ +theorem exists_eval_onSchedule (ev : T → List Bool → List ℕ) + (hB : ∀ d M p, Active C m d M p → ActiveBounds C m d M p) + {x₀ : Call T} (h₀ : OnSchedule C m x₀) (hd : x₀.depth = 0) (hm : 2 ≤ m) : + ∃ N H, (scheme ev nativeMk).Eval (reachInv ev nativeMk x₀) x₀ (0, value ev nativeMk x₀) N H ∧ N ≤ 2 ^ ((245760 * C + 37) * m / Nat.sqrt (Nat.log 2 m)) ∧ H ≤ Nat.log 2 m := by obtain ⟨N, H, he, hN, hH⟩ := exists_eval_reachInv_count hd (Nat.log 2 m) (fun d => 2 ^ (2 * Nat.log 2 m + branchExponent C m d)) fun x hx ha => by diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionShape.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionShape.lean index 76f982e9f..84b65a919 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionShape.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionShape.lean @@ -21,8 +21,8 @@ the schedule: they are what makes the calls, frames and values polynomially long **The invariant** (`FastContraction.Shape`). A reached call at depth `d` keeps the root's scale and modulus, is well-formed, has at most `2 m` edges, precision at most `p₀ + 40 m² d` for the root's precision `p₀`, at most `V₀ + m² d` vertices for the root's `V₀` vertices, as many rows (unless it -is the root), and every vertex descriptor is a table of the root or a packet descriptor whose fields -are bounded (`FastContraction.PacketBound`). It passes to the native children +is the root), and every vertex descriptor is a descriptor of the root or a packet descriptor whose +fields are bounded (`FastContraction.PacketBound`). It passes to the native children (`FastContraction.Shape.child`): a child has at most twice the edges of its parent (`NativeChild.numEdges_nativeChild_le`), its precision `p_t = p + 8 h 2 ^ (a - i) + 8 M (a + 1)` is at most `p + 40 m²` since `2 ^ a ≤ m`, and it adds at most `M (2 ^ a) ^ 12 ≤ m²` packet vertices @@ -50,6 +50,8 @@ namespace Cslib.Circuits.Frontier.FastContraction open ContractionSchedule ChildCursor NativeRecovery NativeChild +variable {T : Type} + /-- **A bounded packet descriptor** for a root with modulus `fl` and `m` edges, at precision at most `P`, on a vertex with `k` ports: its precision is at most `P` and is its number of exponents per tile, its modulus is `fl`, it has `2 ^ a` slots with `a ≤ ⌊log₂ m⌋`, `2 ^ (i + 1)` tiles with @@ -68,7 +70,7 @@ theorem PacketBound.mono {fl : List ℕ} {m P P' k : ℕ} {d : NativePacket.Pack /-- **The shape of a call** reached from a root `x₀` with `m` edges, precision `p₀` and `V₀` vertices, at depth `d`. -/ -structure Shape (x₀ x : Call) : Prop where +structure Shape (x₀ x : Call T) : Prop where /-- The scale is the root's. -/ scale_eq : x.scale = x₀.scale /-- The modulus is the root's. -/ @@ -91,7 +93,7 @@ structure Shape (x₀ x : Call) : Prop where PacketBound x₀.fl x₀.edges (x₀.prec + x.depth * (40 * x₀.edges ^ 2)) v.1.length d /-- The exponent tuple of a child of an active call has entries below the node's precision. -/ -theorem lt_nodePrec_of_mem_children {x : Call} {c : State} (hc : c ∈ children x) : +theorem lt_nodePrec_of_mem_children {x : Call T} {c : State} (hc : c ∈ children x) : ∀ b ∈ c.2.2.1, b < nodePrec x c.1 := by simp only [children, cursorList, nodeBlock, pointBlock, groupBlock, List.mem_flatMap, List.mem_range, List.mem_map] at hc @@ -99,7 +101,7 @@ theorem lt_nodePrec_of_mem_children {x : Call} {c : State} (hc : c ∈ children exact fun b hb => BudgetTuples.lt_of_mem_budgetTuples (weights_pos j) hβ hb /-- The ports of a vertex of a well-formed call are at most its edges. -/ -theorem length_le_edges_of_wf {x : Call} (hx : WF x) {v : List ℕ × VertexDesc} +theorem length_le_edges_of_wf {x : Call T} (hx : WF x) {v : List ℕ × VertexDesc T} (hv : v ∈ x.net.vertices) : v.1.length ≤ x.edges := by obtain ⟨k, hk, rfl⟩ := List.getElem_of_mem hv have hnd : (x.net.vertices[k]).1.Nodup := nodup_ports hx.2 ⟨k, hk⟩ @@ -111,7 +113,7 @@ theorem length_le_edges_of_wf {x : Call} (hx : WF x) {v : List ℕ × VertexDesc section Child -variable {x₀ x : Call} +variable {x₀ x : Call T} /-- The schedule's numbers at an active call at scale `m`: `a ≤ ⌊log₂ m⌋`, `2 ^ (12 a) ≤ m`, `u ≤ ⌊log₂ m⌋ < m`, and `h ≤ 3 M + u`. -/ @@ -183,7 +185,7 @@ theorem level_le_slots_of_mem_children (ha : active x = true) {c : State} (hc : omega /-- The interpolation points are 0/1 lists with `e` coordinates. -/ -theorem getD_points_facts (x : Call) (i : ℕ) : +theorem getD_points_facts (x : Call T) (i : ℕ) : ((points x).getD i []).length ≤ x.fl.length ∧ ∀ z ∈ (points x).getD i [], z ≤ 1 := by by_cases hi : i < (points x).length · rw [List.getD_eq_getElem _ _ hi] @@ -195,7 +197,7 @@ theorem getD_points_facts (x : Call) (i : ℕ) : simp /-- The rows of a native child are at most the parent's vertices. -/ -theorem childRows_le (r i : ℕ) (D : DescribedNetwork VertexDesc) +theorem childRows_le (r i : ℕ) (D : DescribedNetwork (VertexDesc T)) (pk : (List (List ℕ) × List (List ℕ)) × ℕ × List (ℕ × ℕ)) (g : ℕ) : childRows r i D pk g ≤ D.vertices.length := by unfold childRows diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionSize.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionSize.lean index 0fd1f563a..a4800c808 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionSize.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionSize.lean @@ -42,6 +42,8 @@ namespace Cslib.Circuits.Frontier.FastContraction open Turing.MultiTapeTM NativePacket +variable {T : Type} {encT : T ↪ List Bool} + /-- A number at most `b` has at most `b` binary digits. -/ theorem length_encNat_le {a b : ℕ} (h : a ≤ b) : (encNat a).length ≤ b := by rw [encNat_apply, Nat.size_eq_bits_len] @@ -91,7 +93,7 @@ theorem two_pow_le_of_le_log {a m : ℕ} (ha : a ≤ Nat.log 2 m) (hm : m ≠ 0) modulus has 0/1 coefficients. -/ theorem length_enc_inr_le {fl : List ℕ} {m P k : ℕ} {d : PacketDesc} (h : PacketBound fl m P k d) {B : ℕ} (hB : 2 * (m + 1) * (P + 1) ≤ B) (hfl : fl.length ≤ B) (hfl1 : ∀ z ∈ fl, z ≤ 1) - (hk : k ≤ B) : (VertexDesc.enc (.inr d)).length ≤ 200 * (B + 1) ^ 2 := by + (hk : k ≤ B) : (VertexDesc.enc encT (.inr d)).length ≤ 200 * (B + 1) ^ 2 := by obtain ⟨hp, hnb, hfl', ha, hL, hi, htl, ht, hcols, hζ, hζ1, htags, hslots, hβ, hβ'⟩ := h have h2m : 2 * (m + 1) ≤ B := le_trans (Nat.le_mul_of_pos_right _ (by omega)) hB have hP1 : P + 1 ≤ B := le_trans (Nat.le_mul_of_pos_left _ (by omega)) hB @@ -132,14 +134,14 @@ theorem length_enc_inr_le {fl : List ℕ} {m P k : ℕ} {d : PacketDesc} (h : Pa bound, precision, number of edges, number of vertices, modulus length, the binary length of its rows and its ports are at most `B`, the modulus has 0/1 coefficients, and its descriptors are at most `R` long. -/ -theorem length_encCall_le {x : Call} {B R : ℕ} (hs : x.scale ≤ B) (hd : x.depth ≤ B) +theorem length_encCall_le {x : Call T} {B R : ℕ} (hs : x.scale ≤ B) (hd : x.depth ≤ B) (hb : x.bound ≤ B) (hp : x.prec ≤ B) (hfl : x.fl.length ≤ B) (hfl1 : ∀ z ∈ x.fl, z ≤ 1) (hr : (encNat x.rows).length ≤ B) (hE : x.edges ≤ B) (hV : x.net.vertices.length ≤ B) (hports : ∀ v ∈ x.net.vertices, v.1.length ≤ B ∧ ∀ i ∈ v.1, i ≤ B) - (hdesc : ∀ v ∈ x.net.vertices, (VertexDesc.enc v.2).length ≤ R) : - (encCall x).length ≤ 64 * (B + 1) ^ 3 + 2 * B * R := by + (hdesc : ∀ v ∈ x.net.vertices, (VertexDesc.enc encT v.2).length ≤ R) : + (encCall encT x).length ≤ 64 * (B + 1) ^ 3 + 2 * B * R := by have h1 := length_encList_le_of_le_one hfl1 - have hv : ∀ v ∈ x.net.vertices, (encPair (encList encNat) VertexDesc.enc v).length ≤ + have hv : ∀ v ∈ x.net.vertices, (encPair (encList encNat) (VertexDesc.enc encT) v).length ≤ 2 * (B * (2 * B + 1)) + 1 + R := fun v hv => by rw [length_encPair] have := (length_encList_le encNat (B := B) fun i hi => length_encNat_le @@ -180,15 +182,16 @@ theorem length_encList_le_of_reducedAt {p : ℕ} {fl c : List ℕ} (h : ReducedA ((h.2 z hz).trans_lt (Nat.pow_lt_pow_right (by norm_num) (Nat.lt_succ_self p))) /-- **The values of the calls are reduced** at their precision, for every child builder. -/ -theorem reducedAt_value (mk : Call → ChildCursor.State → ℕ × DescribedNetwork VertexDesc) - (x : Call) : - ReducedAt x.prec x.fl (value mk x) := by +theorem reducedAt_value (ev : T → List Bool → List ℕ) + (mk : Call T → ChildCursor.State → ℕ × DescribedNetwork (VertexDesc T)) + (x : Call T) : + ReducedAt x.prec x.fl (value ev mk x) := by cases ha : active x - · rw [value_of_not_active mk ha] - exact DescribedNetwork.reduced_sumValue (ops := SumOps.galois) (eval := VertexDesc.entry) + · rw [value_of_not_active ev mk ha] + exact DescribedNetwork.reduced_sumValue (ops := SumOps.galois) (eval := VertexDesc.entry ev) (x.prec, x.fl) x.net - · rw [value_of_active mk ha, finishValue, NativeRecovery.recover] - set W := table x (runLoop x fun c => value mk (child x mk c)).2.2 + · rw [value_of_active ev mk ha, finishValue, NativeRecovery.recover] + set W := table x (runLoop x fun c => value ev mk (child x mk c)).2.2 have hfold : ∀ (l : List ℕ) (S : List ℕ), ReducedAt (x.prec + shift x) x.fl S → ReducedAt (x.prec + shift x) x.fl (l.foldl (fun S k => if k = 2 ^ slots x then S else GaloisRingArith.add (x.prec + shift x) x.fl S @@ -213,12 +216,13 @@ theorem reducedAt_value (mk : Call → ChildCursor.State → ℕ × DescribedNet exact Nat.le_of_lt_succ (Nat.lt_succ_of_le (Nat.div_le_of_le_mul (by linarith))) /-- **The encoded length of a tagged value** of a call. -/ -theorem length_encValue_le (mk : Call → ChildCursor.State → ℕ × DescribedNetwork VertexDesc) - (x : Call) : - (encValue (x.depth, value mk x)).length ≤ +theorem length_encValue_le (ev : T → List Bool → List ℕ) + (mk : Call T → ChildCursor.State → ℕ × DescribedNetwork (VertexDesc T)) + (x : Call T) : + (encValue (x.depth, value ev mk x)).length ≤ 2 * x.depth + 1 + x.fl.length * (2 * (x.prec + 1) + 1) := by rw [length_encPair, encUnary_apply, List.length_replicate] - have := length_encList_le_of_reducedAt (reducedAt_value mk x) + have := length_encList_le_of_reducedAt (reducedAt_value ev mk x) simp only at this ⊢ omega @@ -292,11 +296,11 @@ end Frames section ActiveFrames -variable {x : Call} +variable {x : Call T} /-- The bound `256 (m + 1) ^ 5 (p + 1) + e` on the numbers of the frames of an active call at scale `m` with precision `p`. -/ -@[expose] def frameBound (x : Call) : ℕ := 256 * (x.scale + 1) ^ 5 * (x.prec + 1) + x.fl.length +@[expose] def frameBound (x : Call T) : ℕ := 256 * (x.scale + 1) ^ 5 * (x.prec + 1) + x.fl.length /-- The numbers of an active call with at most `m` edges at scale `m`. -/ theorem active_numbers (ha : active x = true) (hM : x.edges ≤ x.scale) : @@ -431,24 +435,25 @@ end ActiveFrames section Sizes -variable {x₀ x : Call} +variable {x₀ x : Call T} /-- **The sizes of a call of a given shape**: from a root `x₀` at depth `0`, at scale its number `m` of edges, with bound `m + 1`, a 0/1 modulus and descriptors at most `200 (Z + 1) ^ 2` long, a call of its shape, its tagged value and, if it is active, its frames are at most `1000 (Z + 1) ^ 3` long, once `Z` dominates `256 (m + 1) ^ 5 (P + 1) + e` for the precision bound `P = p₀ + 40 m² (m + 1)` and the vertices, rows and their growth. -/ -theorem Shape.length_le (h₀s : x₀.scale = x₀.edges) (h₀b : x₀.bound = x₀.edges + 1) +theorem Shape.length_le (ev : T → List Bool → List ℕ) (h₀s : x₀.scale = x₀.edges) + (h₀b : x₀.bound = x₀.edges + 1) (h₀d : x₀.depth = 0) (h : Shape x₀ x) {Z : ℕ} (hZ1 : 256 * (x₀.edges + 1) ^ 5 * (x₀.prec + (x₀.edges + 1) * (40 * x₀.edges ^ 2) + 1) + x₀.fl.length ≤ Z) (hZ2 : x₀.net.vertices.length + (x₀.edges + 1) * x₀.edges ^ 2 + (encNat x₀.rows).length ≤ Z) (hfl1 : ∀ z ∈ x₀.fl, z ≤ 1) - (hR₀ : ∀ w ∈ x₀.net.vertices, (VertexDesc.enc w.2).length ≤ 200 * (Z + 1) ^ 2) : - (encCall x).length ≤ 1000 * (Z + 1) ^ 3 ∧ - (encValue (x.depth, value nativeMk x)).length ≤ 1000 * (Z + 1) ^ 3 ∧ + (hR₀ : ∀ w ∈ x₀.net.vertices, (VertexDesc.enc encT w.2).length ≤ 200 * (Z + 1) ^ 2) : + (encCall encT x).length ≤ 1000 * (Z + 1) ^ 3 ∧ + (encValue (x.depth, value ev nativeMk x)).length ≤ 1000 * (Z + 1) ^ 3 ∧ (active x = true → ∀ vals c, - (encPair encCall encFrame (x, frameAt x vals c)).length ≤ 1000 * (Z + 1) ^ 3) := by + (encPair (encCall encT) encFrame (x, frameAt x vals c)).length ≤ 1000 * (Z + 1) ^ 3) := by set m := x₀.edges with hm set P := x₀.prec + (m + 1) * (40 * m ^ 2) with hP -- The numbers of `x`. @@ -476,7 +481,7 @@ theorem Shape.length_le (h₀s : x₀.scale = x₀.edges) (h₀b : x₀.bound = have hports : ∀ v ∈ x.net.vertices, v.1.length ≤ Z ∧ ∀ i ∈ v.1, i ≤ Z := fun v hv => ⟨(length_le_edges_of_wf h.wf hv).trans (hE.trans (by omega)), fun i hi => (h.wf.2.1 v hv i hi).le.trans (hE.trans (by omega))⟩ - have hR : ∀ v ∈ x.net.vertices, (VertexDesc.enc v.2).length ≤ 200 * (Z + 1) ^ 2 := by + have hR : ∀ v ∈ x.net.vertices, (VertexDesc.enc encT v.2).length ≤ 200 * (Z + 1) ^ 2 := by intro v hv rcases h.desc v hv with ⟨w, hw, hvw⟩ | ⟨d, hvd, hb⟩ · rw [hvw]; exact hR₀ w hw @@ -492,7 +497,7 @@ theorem Shape.length_le (h₀s : x₀.scale = x₀.edges) (h₀b : x₀.bound = have hcall := length_encCall_le (B := Z) (R := 200 * (Z + 1) ^ 2) (x := x) (by rw [hsc]; omega) (hd.trans (by omega)) (by omega) (hprec.trans (by omega)) (h.fl_eq ▸ hflZ) (h.fl_eq ▸ hfl1) hrows (hE.trans (by omega)) (hV.trans (by omega)) hports hR - have hcall' : (encCall x).length ≤ 464 * (Z + 1) ^ 3 := by + have hcall' : (encCall encT x).length ≤ 464 * (Z + 1) ^ 3 := by have : 2 * Z * (200 * (Z + 1) ^ 2) ≤ 400 * (Z + 1) ^ 3 := by have : Z ≤ Z + 1 := Nat.le_succ _ calc 2 * Z * (200 * (Z + 1) ^ 2) = 400 * (Z * (Z + 1) ^ 2) := by ring @@ -502,7 +507,7 @@ theorem Shape.length_le (h₀s : x₀.scale = x₀.edges) (h₀b : x₀.bound = have hZ3 : (Z + 1) ^ 2 ≤ (Z + 1) ^ 3 := Nat.pow_le_pow_right (by omega) (by norm_num) have hZ1' : Z + 1 ≤ (Z + 1) ^ 3 := Nat.le_self_pow (by norm_num) _ refine ⟨hcall'.trans (by omega), ?_, fun ha vals c => ?_⟩ - · have hv := length_encValue_le nativeMk x + · have hv := length_encValue_le ev nativeMk x rw [h.fl_eq] at hv have : x₀.fl.length * (2 * (x.prec + 1) + 1) ≤ Z * (2 * Z + 1) := Nat.mul_le_mul hflZ (by omega) @@ -519,7 +524,7 @@ theorem Shape.length_le (h₀s : x₀.scale = x₀.edges) (h₀b : x₀.bound = Nat.mul_le_mul_left _ (by omega) omega have hfZ : (frameBound x + 1) ^ 3 ≤ (Z + 1) ^ 3 := Nat.pow_le_pow_left (by omega) 3 - have hl := length_encPair (enc₁ := encCall) (enc₂ := encFrame) (x, frameAt x vals c) + have hl := length_encPair (enc₁ := encCall encT) (enc₂ := encFrame) (x, frameAt x vals c) simp only at hl rw [hl] omega diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionStep.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionStep.lean index 657277b1a..bc37a2e7a 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionStep.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionStep.lean @@ -51,6 +51,8 @@ namespace Cslib.Circuits.Frontier.FastContraction open Finset GaloisRingArith ChildCursor NativeRecovery ContractionSchedule NativeChild +variable {T : Type} + /-- **The native child builder**: at the cursor state `(j, i, β, g)`, the rows and the native child of group `g` at the `j`-th node, the `i`-th point and the exponents `β`. The rows are capped at the number of vertices (`FastContraction.rowCap`) and the exponents at the node's precision @@ -58,18 +60,18 @@ at the number of vertices (`FastContraction.rowCap`) and the exponents at the no (`FastContraction.nativeMk_eq`); on every call and state they keep the builder polynomial-time, since the number of rows and the exponents are stored in binary but the child lists one word per row and stores the exponents in unary. -/ -@[expose] def nativeMk (x : Call) (c : State) : ℕ × DescribedNetwork VertexDesc := +@[expose] def nativeMk (x : Call T) (c : State) : ℕ × DescribedNetwork (VertexDesc T) := (childRows (rowCap x) (level x ((nodes x).getD c.1 0)) x.net (packing x) c.2.2.2, nativeChild x.fl (slots x) (level x ((nodes x).getD c.1 0)) (nodePrec x c.1) (node (slots x) ((nodes x).getD c.1 0)) ((points x).getD c.2.1 []) (rowCap x) x.net (packing x) (c.2.2.1.map (min · (nodePrec x c.1))) c.2.2.2) /-- **A well-formed call**: its modulus is irreducible modulo `2` and its network is rows-first. -/ -@[expose] def WF (x : Call) : Prop := +@[expose] def WF (x : Call T) : Prop := Irreducible ((monicOf x.fl).map (Int.castRingHom (ZMod 2))) ∧ x.net.IsRowsFirstBipartite x.rows -variable {x : Call} +variable {x : Call T} /-- The cap of `nativeMk` leaves a tuple of weight below `p` unchanged, for positive weights. -/ theorem map_min_of_mem_budgetTuples {ws : List ℕ} (hw : ∀ w ∈ ws, 0 < w) {p : ℕ} {β : List ℕ} @@ -139,7 +141,8 @@ theorem pairwise_isUnit_points (hirr : Irreducible ((monicOf x.fl).map (Int.cast /-- **The step of an active call is correct**, for the native child builder and well-formed calls. -/ -theorem stepCorrect_nativeMk : StepCorrect nativeMk WF := by +theorem stepCorrect_nativeMk (ev : T → List Bool → List ℕ) : + StepCorrect ev (nativeMk (T := T)) WF := by intro x hx ha vals hvals obtain ⟨hirr, hD⟩ := hx have ha' := ha @@ -147,7 +150,7 @@ theorem stepCorrect_nativeMk : StepCorrect nativeMk WF := by obtain ⟨-, hu, huM, hua, -, -, -⟩ := ha' have hlen : (points x).length = numPoints x := by simp [points] have hr := DescribedNetwork.rows_le_of_isRowsFirstBipartite hD (one_le_edges_of_active ha) - refine NativeCall.val_recover_eq_contraction hirr hD hu huM hua (le_taperStep_mul hu) + refine NativeCall.val_recover_eq_contraction hirr hD ev hu huM hua (le_taperStep_mul hu) (taperStep_mul_le _ _ _) (pow_slots_le_edges_of_active ha) ?_ (points x) (pairwise_isUnit_points hirr ha) (by rw [hlen]; exact Nat.lt_succ_self _) _ ?_ @@ -185,7 +188,7 @@ theorem stepCorrect_nativeMk : StepCorrect nativeMk WF := by val P x.fl (vals (j, i, β, g)) = (nativeChild x.fl (slots x) v P (node (slots x) k) ((points x).getD i []) x.rows x.net (nativeParentPacking x.rows (slots x) x.net) β g).contraction - fun d bs => val P x.fl (d.entry bs) := by + fun d bs => val P x.fl (d.entry ev bs) := by rintro v P rfl rfl have h := hvals _ hmem rw [nativeMk_eq ⟨hirr, hD⟩ ha hmem] at h @@ -209,7 +212,7 @@ theorem lt_of_mem_children {c : State} (hc : c ∈ children x) : /-- **Well-formedness passes to the native children**: they keep the modulus, and they are rows-first (`NativeChild.isRowsFirstBipartite_nativeChild`). -/ -theorem wfChildren_nativeMk : WFChildren nativeMk WF := by +theorem wfChildren_nativeMk : WFChildren (nativeMk (T := T)) WF := by intro x hx ha c hc obtain ⟨hirr, hD⟩ := hx refine ⟨hirr, ?_⟩ diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/NativeCall.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/NativeCall.lean index 82af1b001..cbaf7c2e0 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/NativeCall.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/NativeCall.lean @@ -66,8 +66,10 @@ theorem prod_map_range {M : Type*} [CommMonoid M] (F : ℕ → M) (n : ℕ) : rw [← List.map_coe_finRange_eq_range, List.map_map, ← List.ofFn_eq_map, List.prod_ofFn] rfl -variable {fl : List ℕ} (hirr : Irreducible ((monicOf fl).map (Int.castRingHom (ZMod 2)))) - {D : DescribedNetwork VertexDesc} {r : ℕ} (hD : D.IsRowsFirstBipartite r) +variable {T : Type} {fl : List ℕ} + (hirr : Irreducible ((monicOf fl).map (Int.castRingHom (ZMod 2)))) + {D : DescribedNetwork (VertexDesc T)} {r : ℕ} (hD : D.IsRowsFirstBipartite r) + (ev : T → List Bool → List ℕ) include hD in /-- **One native active call is correct when its stored values are** ([OpenAI2026ETH], @@ -98,9 +100,9 @@ theorem val_recover_eq_contraction {a u h p Δ : ℕ} (hu : 1 ≤ u) (huM : u (nodePrecision p h a D.numEdges (padicValInt 2 (node a k))) (node a k) (ζl.getD i []) r D (nativeParentPacking r a D) β g).contraction fun d bs => val (nodePrecision p h a D.numEdges (padicValInt 2 (node a k))) fl - (d.entry bs)).prod).sum) : + (d.entry ev bs)).prod).sum) : val p fl (recover p Δ fl a u h ζl W) = - D.contraction fun d bs => val p fl (d.entry bs) := by + D.contraction fun d bs => val p fl (d.entry ev bs) := by have hB := AdjoinRoot.algebraMap_mem_integer_padicValuation (monic_monicOf fl) hirr have hcard : Fintype.card (Fin D.numEdges) = D.numEdges := Fintype.card_fin _ have hpk1 : (nativeParentPacking r a D).2.1 = (parentPacking hD a).numPackets := by @@ -117,7 +119,7 @@ theorem val_recover_eq_contraction {a u h p Δ : ℕ} (hu : 1 ≤ u) (huM : u Fin (nodePrecision p h a (Fintype.card (Fin D.numEdges)) (padicValInt 2 t)) => (Z.2.2 : ℕ) + 1) (nodePrecision p h a (Fintype.card (Fin D.numEdges)) (padicValInt 2 t)), - ∏ g, ((parentSplitting hirr hD a p u h hua ht hq (ζl.getD k [])).child β + ∏ g, ((parentSplitting hirr hD ev a p u h hua ht hq (ζl.getD k [])).child β g).contraction := by intro t ht hq k obtain ⟨kk, hkk, hkt⟩ : ∃ kk, (kk < 2 ^ (a + 1) ∧ kk ≠ 2 ^ a) ∧ node a kk = t := by @@ -138,9 +140,9 @@ theorem val_recover_eq_contraction {a u h p Δ : ℕ} (hu : 1 ≤ u) (huM : u refine Fintype.prod_congr _ _ fun g => ?_ simp only [Function.comp_apply] rw [DescribedNetwork.map_contraction] - exact contraction_nativeChild hirr hD hK hua ht hq (ζl.getD k []) β g + exact contraction_nativeChild hirr hD ev hK hua ht hq (ζl.getD k []) β g obtain ⟨b, hb, hx⟩ := TensorNetwork.exists_recoverFromValues_eq_add_of_children (RingO hirr) hB - (parentNetwork hirr hD) (parentSide r) (parentSide_src hD) (parentSide_tgt hD) + (parentNetwork hirr hD ev) (parentSide r) (parentSide_src hD) (parentSide_tgt hD) (parentPacking hD a) (p := p) hu (by rwa [hcard]) hua (by rwa [hcard]) (by rwa [hcard]) ζ hζ (by rwa [hcard]) v hv -- Native recovery computes the reduction of the recovered value. @@ -161,8 +163,9 @@ theorem val_recover_eq_contraction {a u h p Δ : ℕ} (hu : 1 ≤ u) (huM : u (fun t => nodePrecision p h a D.numEdges (padicValInt 2 t)) hpt ζ hζ ζl rfl (fun i => (reduction_liftO hirr _ _).symm) v W (fun k _ _ _ i => ⟨0, by simp only [v, toNat_node_add, reduction_liftO, mul_zero, add_zero]⟩) - (parentNetwork hirr hD).contraction hb hx - rw [hrec, ← DescribedNetwork.reduction_contraction_toNetwork hD hirr (fun d bs => d.entry bs) p] + (parentNetwork hirr hD ev).contraction hb hx + rw [hrec, ← DescribedNetwork.reduction_contraction_toNetwork hD hirr + (fun d bs => d.entry ev bs) p] exact RingHom.congr_fun (AdjoinRoot.castHom_comp_reduction (monic_monicOf fl) hirr (Nat.le_add_right p Δ)) _ diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/NativeChild.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/NativeChild.lean index 2d0a6a4ae..ab503a6a6 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/NativeChild.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/NativeChild.lean @@ -112,6 +112,8 @@ namespace NativeChild open ChildNumbering GaloisRingArith NativePacket open ContractionSchedule (nodePrecision) +variable {T : Type} + /-! ### The native child -/ /-- **The groups of the vertices** in coordinate `i`: digit `i` of the row word of a row @@ -168,17 +170,17 @@ and the interpolation value `ζ`: the precision `p_t` and `p_t` exponents per ti @[expose] def betaSlice (i pt : ℕ) (β : List ℕ) (q : ℕ) : List ℕ := (β.drop (q * (2 ^ (i + 1) * pt))).take (2 ^ (i + 1) * pt) -/-- The default vertex: no ports and the empty table. -/ -abbrev defaultVertex : List ℕ × VertexDesc := ([], .inl []) +/-- The default vertex: no ports and the default packet descriptor. -/ +abbrev defaultVertex : List ℕ × VertexDesc T := ([], .inr default) /-- **The native child** of group `g` at the node `t` of valuation `i`, the interpolation value `ζ`, the precision `p_t` and the packet-major exponents `β`, of the rows-first parent `D` with `r` rows and the native packing `pk` of its edges: the vertices of group `g` with their descriptors and renumbered ports, then one packet vertex per packet. -/ @[expose] def nativeChild (fl : List ℕ) (a i pt : ℕ) (t : ℤ) (ζ : List ℕ) (r : ℕ) - (D : DescribedNetwork VertexDesc) + (D : DescribedNetwork (VertexDesc T)) (pk : (List (List ℕ) × List (List ℕ)) × ℕ × List (ℕ × ℕ)) (β : List ℕ) (g : ℕ) : - DescribedNetwork VertexDesc := + DescribedNetwork (VertexDesc T) := let groups := groupsOf r i D.vertices.length pk.1 let cedges := childEdgeList groups g D.edgeEnds (pk.2.2.map Prod.fst) ⟨cedges.length, @@ -194,7 +196,7 @@ and renumbered ports, then one packet vertex per packet. -/ betaSlice i pt β q))⟩ /-- **The number of rows of the native child**: the number of vertices of group `g`. -/ -@[expose] def childRows (r i : ℕ) (D : DescribedNetwork VertexDesc) +@[expose] def childRows (r i : ℕ) (D : DescribedNetwork (VertexDesc T)) (pk : (List (List ℕ) × List (List ℕ)) × ℕ × List (ℕ × ℕ)) (g : ℕ) : ℕ := (groupsOf r i D.vertices.length pk.1).count g @@ -392,7 +394,8 @@ theorem map_filterMap_of_isSome {α β γ : Type*} (f : α → Option β) (y : section Parent variable {fl : List ℕ} (hirr : Irreducible ((monicOf fl).map (Int.castRingHom (ZMod 2)))) - {D : DescribedNetwork VertexDesc} {r : ℕ} (hD : D.IsRowsFirstBipartite r) + {D : DescribedNetwork (VertexDesc T)} {r : ℕ} (hD : D.IsRowsFirstBipartite r) + (ev : T → List Bool → List ℕ) /-- The valuation ring `O = ℤ_(2)[U] / (f)` of `f = monicOf fl`. -/ noncomputable abbrev RingO : Subring (AdjoinRoot ((monicOf fl).map (Int.castRingHom ℚ))) := @@ -401,7 +404,7 @@ noncomputable abbrev RingO : Subring (AdjoinRoot ((monicOf fl).map (Int.castRing /-- **The parent over `O`**: the network of the descriptors with the lifts of their entries. -/ @[expose] noncomputable def parentNetwork : TensorNetwork (RingO hirr) Bool (Fin D.vertices.length) (Fin D.numEdges) := - D.toNetwork hD fun d bs => liftO hirr (d.entry bs) + D.toNetwork hD fun d bs => liftO hirr (d.entry ev bs) /-- The sides of the parent: the first `r` vertices are the rows. -/ @[expose] def parentSide (r : ℕ) {k : ℕ} (v : Fin k) : Bool := decide ((v : ℕ) < r) @@ -425,7 +428,7 @@ theorem parentSide_tgt (j : Fin D.numEdges) : parentSide r (D.tgtFin hD j) = fal /-- **The native packing of the parent**: `nativePacking` of its `(row, column)` edges, with `r` rows, `k - r` columns, packets of `2 ^ a` slots and `64` symbols. -/ -@[expose] def nativeParentPacking (r a : ℕ) (D : DescribedNetwork VertexDesc) : +@[expose] def nativeParentPacking (r a : ℕ) (D : DescribedNetwork (VertexDesc T)) : (List (List ℕ) × List (List ℕ)) × ℕ × List (ℕ × ℕ) := PacketPacking.nativePacking r (D.vertices.length - r) a 64 (D.edgeEnds.map fun e => (e.1, e.2 - r)) @@ -490,7 +493,7 @@ its packing, at the node `t`, the precision `p`, and the lift of the interpolati @[expose] noncomputable def parentSplitting (a p u h : ℕ) (hua : u ≤ a) {t : ℤ} (ht : t ∈ recoveryNodes a) (hq : 0 < taperMult u h t) (ζ : List ℕ) := TensorNetwork.callSplitting (RingO hirr) - (AdjoinRoot.algebraMap_mem_integer_padicValuation _ hirr) (parentNetwork hirr hD) + (AdjoinRoot.algebraMap_mem_integer_padicValuation _ hirr) (parentNetwork hirr hD ev) (parentSide r) (parentSide_src hD) (parentSide_tgt hD) (parentPacking hD a) p u h hua ht hq (liftO hirr ζ) @@ -500,21 +503,22 @@ variable {a p u h : ℕ} (hua : u ≤ a) {t : ℤ} (ht : t ∈ recoveryNodes a) (hq : 0 < taperMult u h t) (ζ : List ℕ) /-- The rows of the splitting are the first `r` vertices. -/ -theorem parentSplitting_side : (parentSplitting hirr hD a p u h hua ht hq ζ).side = parentSide r := - TensorNetwork.callSplitting_side (RingO hirr) _ (parentNetwork hirr hD) (parentSide r) _ _ +theorem parentSplitting_side : + (parentSplitting hirr hD ev a p u h hua ht hq ζ).side = parentSide r := + TensorNetwork.callSplitting_side (RingO hirr) _ (parentNetwork hirr hD ev) (parentSide r) _ _ (parentPacking hD a) p u h hua ht hq (liftO hirr ζ) /-- The groups of the splitting are the groups of the packing in coordinate `v₂(t)`. -/ -theorem parentSplitting_group : (parentSplitting hirr hD a p u h hua ht hq ζ).group = +theorem parentSplitting_group : (parentSplitting hirr hD ev a p u h hua ht hq ζ).group = packingGroup (parentSide r) (parentPacking hD a) ⟨_, padicValInt_lt_of_taperMult_pos hq hua⟩ := - TensorNetwork.callSplitting_group (RingO hirr) _ (parentNetwork hirr hD) (parentSide r) _ _ + TensorNetwork.callSplitting_group (RingO hirr) _ (parentNetwork hirr hD ev) (parentSide r) _ _ (parentPacking hD a) p u h hua ht hq (liftO hirr ζ) /-- The packets of the splitting are the packets of the packing. -/ theorem parentSplitting_packet : - (parentSplitting hirr hD a p u h hua ht hq ζ).packet = (parentPacking hD a).packet := - TensorNetwork.callSplitting_packet (RingO hirr) _ (parentNetwork hirr hD) (parentSide r) _ _ + (parentSplitting hirr hD ev a p u h hua ht hq ζ).packet = (parentPacking hD a).packet := + TensorNetwork.callSplitting_packet (RingO hirr) _ (parentNetwork hirr hD ev) (parentSide r) _ _ (parentPacking hD a) p u h hua ht hq (liftO hirr ζ) end Fields @@ -584,7 +588,7 @@ vertex, and the child edges of a packet. -/ /-- **The descriptors of the numbered child vertices**: the parent descriptor of a retained vertex, and the packet descriptor of a packet. -/ @[expose] def numberedDesc (fl : List ℕ) (a i pt : ℕ) (t : ℤ) (ζ β : List ℕ) : - ChildVertex group g P → VertexDesc := + ChildVertex group g P → VertexDesc T := Sum.elim (fun v => (D.vertices[(v.1 : ℕ)]'v.1.2).2) fun q => .inr (packetCtx fl a i pt t ζ g q, (packetPorts hD group packet g q).map fun c => @@ -917,7 +921,7 @@ local notation "iₜ" => padicValInt 2 t /-- The precision of the node. -/ local notation "ptₜ" => nodePrecision p h a (Fintype.card (Fin D.numEdges)) (padicValInt 2 t) /-- The mode splitting at the node. -/ -local notation "S₀" => parentSplitting hirr hD a p u h hua ht hq ζ +local notation "S₀" => parentSplitting hirr hD ev a p u h hua ht hq ζ /-- The mode tuple of `β`. -/ local notation "β₀" => BudgetTuples.ofList (modeList (PacketPacking.Packing.numPackets (parentPacking hD a)) @@ -926,22 +930,22 @@ local notation "β₀" => BudgetTuples.ofList /-- The numbering of the child vertices. -/ local notation "ev₀" => childVertexEquiv (P := PacketPacking.Packing.numPackets (parentPacking hD a)) - (TensorNetwork.ModeSplitting.group (parentSplitting hirr hD a p u h hua ht hq ζ)) g + (TensorNetwork.ModeSplitting.group (parentSplitting hirr hD ev a p u h hua ht hq ζ)) g /-- The numbering of the child edges. -/ local notation "ee₀" => childEdgeEquiv (D.srcFin hD) (D.tgtFin hD) - (TensorNetwork.ModeSplitting.group (parentSplitting hirr hD a p u h hua ht hq ζ)) g + (TensorNetwork.ModeSplitting.group (parentSplitting hirr hD ev a p u h hua ht hq ζ)) g /-- **The entries of the retained vertices** of the numbered child are the tensors of the child. -/ theorem entry_numbered_inl (v : {v // (S₀).group v = g}) (y : ChildEdge (D.srcFin hD) (D.tgtFin hD) (S₀).group g → Bool) : reductionLift (monic_monicOf fl) hirr ptₜ (val ptₜ fl ((numberedDesc hD (S₀).group (S₀).packet (fun e => ((parentPacking hD a).slot e : ℕ)) g - fl a iₜ ptₜ t ζ β (.inl v)).entry + fl a iₜ ptₜ t ζ β (.inl v)).entry ev ((numberedPorts hD (S₀).group (S₀).packet g (.inl v)).map y))) = ((S₀).child β₀ g).tensor (.inl v) y := by rw [TensorNetwork.ModeSplitting.child_tensor_inl_eq_tensor (S₀) β₀ g v y, TensorNetwork.map_tensor, - ← mk_liftO, parentSplitting_side hirr hD hua ht hq ζ] + ← mk_liftO, parentSplitting_side hirr hD ev hua ht hq ζ] simp only [numberedDesc, numberedPorts, Sum.elim_inl, parentNetwork, DescribedNetwork.toNetwork, DescribedNetwork.wordBits] congr 3 @@ -959,13 +963,13 @@ theorem entry_numbered_inr (q : Fin (parentPacking hD a).numPackets) (y : ChildEdge (D.srcFin hD) (D.tgtFin hD) (S₀).group g → Bool) : reductionLift (monic_monicOf fl) hirr ptₜ (val ptₜ fl ((numberedDesc hD (S₀).group (S₀).packet (fun e => ((parentPacking hD a).slot e : ℕ)) g - fl a iₜ ptₜ t ζ β (.inr q)).entry + fl a iₜ ptₜ t ζ β (.inr q)).entry ev ((numberedPorts hD (S₀).group (S₀).packet g (.inr q)).map y))) = ((S₀).child β₀ g).tensor (.inr q) y := by have hia : iₜ < a := padicValInt_lt_of_taperMult_pos hq hua have hsym := PacketPacking.packetSymbols_eq (rowOfP hD) (colOfP hD) _ _ q ⟨iₜ, hia⟩ simp only [numberedDesc, numberedPorts, Sum.elim_inr] - exact TensorNetwork.map_val_entry_child_inr (N := (parentNetwork hirr hD).map + exact TensorNetwork.map_val_entry_child_inr (N := (parentNetwork hirr hD ev).map (Ideal.Quotient.mk (nodeIdeal (RingO hirr) (Fintype.card (Fin D.numEdges)) a h p t))) (parentSide r) (parentSide_src hD) (parentSide_tgt hD) (packingGroup_src_tgt (parentSide r) (parentSide_src hD) (parentSide_tgt hD) @@ -975,7 +979,7 @@ theorem entry_numbered_inr (q : Fin (parentPacking hD a).numPackets) (two_pow_padicValInt_dvd_and_not_dvd (Finset.ne_of_mem_erase ht)).2 β₀ g q _ (nodup_packetPorts hD (S₀).group (S₀).packet g q) (fun c => (mem_packetPorts hD (S₀).group (S₀).packet g q c).trans (by - rw [parentSplitting_packet hirr hD hua ht hq ζ] + rw [parentSplitting_packet hirr hD ev hua ht hq ζ] exact Iff.rfl)) (packetCtx fl a iₜ ptₜ t ζ g q) (betaSlice iₜ ptₜ β q) (reductionLift (monic_monicOf fl) hirr ptₜ) (mk_liftO hirr ptₜ ζ).symm rfl rfl rfl rfl rfl rfl @@ -998,27 +1002,27 @@ theorem contraction_nativeChild : (fun d bs => reductionLift (monic_monicOf fl) hirr (nodePrecision p h a (Fintype.card (Fin D.numEdges)) (padicValInt 2 t)) (val (nodePrecision p h a (Fintype.card (Fin D.numEdges)) (padicValInt 2 t)) fl - (d.entry bs))) = - ((parentSplitting hirr hD a p u h hua ht hq ζ).child + (d.entry ev bs))) = + ((parentSplitting hirr hD ev a p u h hua ht hq ζ).child (BudgetTuples.ofList (modeList (parentPacking hD a).numPackets (2 ^ (padicValInt 2 t + 1)) (nodePrecision p h a (Fintype.card (Fin D.numEdges)) (padicValInt 2 t))) β) g).contraction := by have hia : iₜ < a := padicValInt_lt_of_taperMult_pos hq hua have hgroups : groupsOf r iₜ D.vertices.length (nativeParentPacking r a D).1 = List.ofFn fun v => ((S₀).group v : ℕ) := by - rw [parentSplitting_group hirr hD hua ht hq ζ] + rw [parentSplitting_group hirr hD ev hua ht hq ζ] exact groupsOf_eq hD hK hia have hpk1 : (nativeParentPacking r a D).2.1 = (parentPacking hD a).numPackets := by rw [nativeParentPacking_eq hD hK] have hpk2 : (nativeParentPacking r a D).2.2 = List.ofFn fun e => (((S₀).packet e : ℕ), ((parentPacking hD a).slot e : ℕ)) := by - rw [nativeParentPacking_eq hD hK, parentSplitting_packet hirr hD hua ht hq ζ] + rw [nativeParentPacking_eq hD hK, parentSplitting_packet hirr hD ev hua ht hq ζ] rw [nativeChild_eq hD (S₀).group (S₀).packet (fun e => ((parentPacking hD a).slot e : ℕ)) g fl a iₜ ptₜ t ζ β _ hgroups hpk1 hpk2] refine DescribedNetwork.contraction_eq_of_ports ((S₀).child β₀ g) _ _ _ _ _ ?_ rintro (v | q) y - · exact entry_numbered_inl hirr hD hua ht hq ζ β g v y - · exact entry_numbered_inr hirr hD hua ht hq ζ β g q y + · exact entry_numbered_inl hirr hD ev hua ht hq ζ β g v y + · exact entry_numbered_inr hirr hD ev hua ht hq ζ β g q y end Child @@ -1026,7 +1030,7 @@ end Parent /-! ### The descriptors of the native children -/ -variable {D : DescribedNetwork VertexDesc} {r : ℕ} +variable {D : DescribedNetwork (VertexDesc T)} {r : ℕ} /-- **The descriptors of the native child.** A vertex of the native child of a rows-first parent with at least `64 ^ a` edges keeps the descriptor of a parent vertex, or is the packet `q`, with @@ -1034,7 +1038,7 @@ the packet context of `q`, the slice of `β` at `q`, and tags whose slots are be distinct among its row ports. -/ theorem desc_of_mem_nativeChild (hD : D.IsRowsFirstBipartite r) {fl : List ℕ} {a i : ℕ} (hK : 64 ^ a ≤ D.numEdges) (hia : i < a) (pt : ℕ) (t : ℤ) (ζ β : List ℕ) (g : Fin 64) - {v : List ℕ × VertexDesc} + {v : List ℕ × VertexDesc T} (hv : v ∈ (nativeChild fl a i pt t ζ r D (nativeParentPacking r a D) β g).vertices) : (∃ w ∈ D.vertices, v.2 = w.2) ∨ ∃ q tags, v.2 = .inr (packetCtx fl a i pt t ζ g q, tags, betaSlice i pt β q) ∧ diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/NativeChildBounds.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/NativeChildBounds.lean index 57b93e560..68e073649 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/NativeChildBounds.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/NativeChildBounds.lean @@ -52,7 +52,8 @@ namespace Cslib.Circuits.Frontier.NativeChild open Finset ChildNumbering -variable {r a i : ℕ} {D : DescribedNetwork VertexDesc} (hD : D.IsRowsFirstBipartite r) +variable {T : Type} {r a i : ℕ} {D : DescribedNetwork (VertexDesc T)} + (hD : D.IsRowsFirstBipartite r) /-- The group of a vertex of the parent in coordinate `i < a` of its packing. -/ noncomputable abbrev parentGroup (a : ℕ) {i : ℕ} (hia : i < a) : @@ -97,7 +98,7 @@ theorem numEdges_nativeChild_eq (hK : 64 ^ a ≤ D.numEdges) (hia : i < a) (fl : /-- A row of a rows-first network is the row of at most as many edges as it has ports. -/ theorem card_rowOfP_le (v : Fin r) : - #{e | rowOfP hD e = v} ≤ (D.vertices.getD v ([], .inl [])).1.length := by + #{e | rowOfP hD e = v} ≤ (D.vertices.getD v defaultVertex).1.length := by by_cases hv : (v : ℕ) < D.vertices.length · rw [List.getD_eq_getElem _ _ hv] calc #{e | rowOfP hD e = v} @@ -118,7 +119,7 @@ theorem card_rowOfP_le (v : Fin r) : /-- A column of a rows-first network is the column of at most as many edges as it has ports. -/ theorem card_colOfP_le (w : Fin (D.vertices.length - r)) : - #{e | colOfP hD e = w} ≤ (D.vertices.getD (r + w) ([], .inl [])).1.length := by + #{e | colOfP hD e = w} ≤ (D.vertices.getD (r + w) defaultVertex).1.length := by have hv : r + (w : ℕ) < D.vertices.length := by have := w.2; omega rw [List.getD_eq_getElem _ _ hv] calc #{e | colOfP hD e = w} @@ -142,7 +143,7 @@ theorem sixteen_mul_numEdges_nativeChild_le (hK : 64 ^ a ≤ D.numEdges) (hia : (fl : List ℕ) (pt : ℕ) (t : ℤ) (ζ β : List ℕ) (g : Fin 64) : 16 * (nativeChild fl a i pt t ζ r D (nativeParentPacking r a D) β g).numEdges ≤ D.numEdges := by - have hdeg' (v : ℕ) : (D.vertices.getD v ([], .inl [])).1.length ≤ Δ := by + have hdeg' (v : ℕ) : (D.vertices.getD v defaultVertex).1.length ≤ Δ := by by_cases hv : v < D.vertices.length · rw [List.getD_eq_getElem _ _ hv] exact hdeg _ (List.getElem_mem hv) @@ -185,7 +186,7 @@ theorem numPackets_nativeParentPacking_mul_le (hK : 64 ^ a ≤ D.numEdges) {Δ : (hdeg : ∀ v ∈ D.vertices, v.1.length ≤ Δ) (hM : 2 * Δ * (64 ^ (2 * a)) ^ 2 ≤ D.numEdges) (hL : 2 ^ a * 64 ^ (2 * a) ≤ D.numEdges) : (nativeParentPacking r a D).2.1 * 2 ^ a ≤ 3 * D.numEdges := by - have hdeg' (v : ℕ) : (D.vertices.getD v ([], .inl [])).1.length ≤ Δ := by + have hdeg' (v : ℕ) : (D.vertices.getD v defaultVertex).1.length ≤ Δ := by by_cases hv : v < D.vertices.length · rw [List.getD_eq_getElem _ _ hv] exact hdeg _ (List.getElem_mem hv) @@ -223,7 +224,7 @@ ports, and a packet vertex has one port per end in group `g` of an edge of its p there are at most `2 ^ a`. -/ theorem length_le_of_mem_vertices_nativeChild (hK : 64 ^ a ≤ D.numEdges) (hia : i < a) {Δ : ℕ} (hdeg : ∀ v ∈ D.vertices, v.1.length ≤ Δ) (hL : 2 * 2 ^ a ≤ Δ) (fl : List ℕ) (pt : ℕ) (t : ℤ) - (ζ β : List ℕ) (g : Fin 64) {v : List ℕ × VertexDesc} + (ζ β : List ℕ) (g : Fin 64) {v : List ℕ × VertexDesc T} (hv : v ∈ (nativeChild fl a i pt t ζ r D (nativeParentPacking r a D) β g).vertices) : v.1.length ≤ Δ := by rw [nativeChild_nativeParentPacking_eq hD hK hia] at hv diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/NativeChildPolyTime.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/NativeChildPolyTime.lean index a58650892..1ca5f3cfd 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/NativeChildPolyTime.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/NativeChildPolyTime.lean @@ -31,7 +31,8 @@ The native child of group `g` of an active call of the contraction recursion of computable in polynomial time over the encodings of the native recursion. The counts are unary, the node `t` is in binary sign-magnitude form, and the lists are binary, except the exponents `β`, which are unary as in a packet descriptor. The parent is encoded by -`DescribedNetwork.encDescribed VertexDesc.enc` and its packing by +`DescribedNetwork.encDescribed (VertexDesc.enc encT)`, for any encoding `encT` of the root +descriptors, and its packing by `PacketPacking.encNativePacking`. The theorems are stated in composition form, for components computed from any input. Besides the @@ -80,6 +81,8 @@ namespace Cslib.Circuits.Frontier.NativeChild open Turing.MultiTapeTM ChildNumbering NativePacket +variable {T : Type} {encT : T ↪ List Bool} + /-- **The rank of a port without a loop over the port**: the edges before `e` with an end in group `g`, the edges past the list counting as `(0, 0)`. -/ theorem portRank_eq_countP (groups : List ℕ) (g : ℕ) (ends : List (ℕ × ℕ)) (sel : ℕ × ℕ → ℕ) @@ -275,9 +278,9 @@ private theorem count_polyTime (hgroups : ComputableInPolyTime groups encIn (enc congr 2 /-- **The retained vertices**: the vertices of group `g` with their renumbered ports. -/ -private theorem retained_polyTime {r : δ → ℕ} {V : δ → List (List ℕ × VertexDesc)} +private theorem retained_polyTime {r : δ → ℕ} {V : δ → List (List ℕ × VertexDesc T)} (hr : ComputableInPolyTime r encIn encNat) - (hV : ComputableInPolyTime V encIn (encList (encPair (encList encNat) VertexDesc.enc))) + (hV : ComputableInPolyTime V encIn (encList (encPair (encList encNat) (VertexDesc.enc encT)))) (hgroups : ComputableInPolyTime groups encIn (encList encNat)) (hg : ComputableInPolyTime g encIn encNat) (hends : ComputableInPolyTime ends encIn (encList (encPair encNat encNat))) : @@ -285,7 +288,7 @@ private theorem retained_polyTime {r : δ → ℕ} {V : δ → List (List ℕ × ((List.range (V x).length).filter fun v => decide ((groups x).getD v 0 = g x)).map fun v => (((V x).getD v defaultVertex).1.map (childEdgeOf (r x) (groups x) (g x) (ends x) v), ((V x).getD v defaultVertex).2)) - encIn (encList (encPair (encList encNat) VertexDesc.enc)) := by + encIn (encList (encPair (encList encNat) (VertexDesc.enc encT))) := by let e₁ := encPair encIn encUnary have hx : ComputableInPolyTime (fun p : δ × ℕ => p.1) e₁ encIn := ComputableInPolyTime.fst _ _ have hy : ComputableInPolyTime (fun p : δ × ℕ => p.2) e₁ encUnary := @@ -298,9 +301,9 @@ private theorem retained_polyTime {r : δ → ℕ} {V : δ → List (List ℕ × ((ComputableInPolyTime.listGetD (encA := encNat) (encL := encList encNat) 0).comp ((hgroups.comp hx).prod hy)) (hg.comp hx)) have hvtx : ComputableInPolyTime (fun p : δ × ℕ => (V p.1).getD p.2 defaultVertex) e₁ - (encPair (encList encNat) VertexDesc.enc) := - (ComputableInPolyTime.listGetD (encA := encPair (encList encNat) VertexDesc.enc) - (encL := encList (encPair (encList encNat) VertexDesc.enc)) defaultVertex).comp + (encPair (encList encNat) (VertexDesc.enc encT)) := + (ComputableInPolyTime.listGetD (encA := encPair (encList encNat) (VertexDesc.enc encT)) + (encL := encList (encPair (encList encNat) (VertexDesc.enc encT))) defaultVertex).comp ((hV.comp hx).prod hy) have hxx : ComputableInPolyTime (fun q : (δ × ℕ) × ℕ => q.1.1) (encPair e₁ encNat) encIn := hx.comp (ComputableInPolyTime.fst _ _) @@ -332,7 +335,7 @@ private theorem retained_polyTime {r : δ → ℕ} {V : δ → List (List ℕ × hfilter (hports.prod ((ComputableInPolyTime.snd _ _).comp hvtx)) variable {fl ζ β : δ → List ℕ} {a i pt r : δ → ℕ} {t : δ → ℤ} - {D : δ → DescribedNetwork VertexDesc} + {D : δ → DescribedNetwork (VertexDesc T)} {pk : δ → (List (List ℕ) × List (List ℕ)) × ℕ × List (ℕ × ℕ)} /-- **The context of a packet** is polynomial-time, with the packet in unary. -/ @@ -394,8 +397,8 @@ private theorem packetVertices_polyTime {P : δ → ℕ} {cedges : δ → List ( (childPorts (cedges x) ((groups x).count (g x) + q)).map fun j => (decide (j < (portEdges (groups x) (g x) (ends x) Prod.fst).length), ((place x).getD (parentEdge (groups x) (g x) (ends x) j) (0, 0)).2), - betaSlice (i x) (pt x) (β x) q) : VertexDesc))) - encIn (encList (encPair (encList encNat) VertexDesc.enc)) := by + betaSlice (i x) (pt x) (β x) q) : VertexDesc T))) + encIn (encList (encPair (encList encNat) (VertexDesc.enc encT))) := by let e₁ := encPair encIn encUnary have hx : ComputableInPolyTime (fun p : δ × ℕ => p.1) e₁ encIn := ComputableInPolyTime.fst _ _ have hy : ComputableInPolyTime (fun p : δ × ℕ => p.2) e₁ encUnary := @@ -466,7 +469,7 @@ private theorem packing_parts (hpk : ComputableInPolyTime pk encIn PacketPacking /-- **The number of rows of the native child is polynomial-time.** -/ theorem computableInPolyTime_childRows (hr : ComputableInPolyTime r encIn encNat) (hi : ComputableInPolyTime i encIn encUnary) - (hD : ComputableInPolyTime D encIn (DescribedNetwork.encDescribed VertexDesc.enc)) + (hD : ComputableInPolyTime D encIn (DescribedNetwork.encDescribed (VertexDesc.enc encT))) (hpk : ComputableInPolyTime pk encIn PacketPacking.encNativePacking) (hg : ComputableInPolyTime g encIn encNat) : ComputableInPolyTime (fun x => childRows (r x) (i x) (D x) (pk x) (g x)) encIn encNat := @@ -486,17 +489,17 @@ theorem computableInPolyTime_nativeChild (hfl : ComputableInPolyTime fl encIn (e (hpt : ComputableInPolyTime pt encIn encUnary) (ht : ComputableInPolyTime t encIn encIntBin) (hζ : ComputableInPolyTime ζ encIn (encList encNat)) (hr : ComputableInPolyTime r encIn encNat) - (hD : ComputableInPolyTime D encIn (DescribedNetwork.encDescribed VertexDesc.enc)) + (hD : ComputableInPolyTime D encIn (DescribedNetwork.encDescribed (VertexDesc.enc encT))) (hpk : ComputableInPolyTime pk encIn PacketPacking.encNativePacking) (hP : ComputableInPolyTime (fun x => (pk x).2.1) encIn encUnary) (hβ : ComputableInPolyTime β encIn (encList encUnary)) (hg : ComputableInPolyTime g encIn encNat) : ComputableInPolyTime (fun x => nativeChild (fl x) (a x) (i x) (pt x) (t x) (ζ x) (r x) (D x) (pk x) (β x) (g x)) - encIn (DescribedNetwork.encDescribed VertexDesc.enc) := by + encIn (DescribedNetwork.encDescribed (VertexDesc.enc encT)) := by obtain ⟨hwords, hplace⟩ := packing_parts hpk have hV := DescribedNetwork.vertices_polyTime.comp hD - have hends := (DescribedNetwork.computableInPolyTime_edgeEnds VertexDesc.enc).comp hD + have hends := (DescribedNetwork.computableInPolyTime_edgeEnds (VertexDesc.enc encT)).comp hD have hgroups := computableInPolyTime_groupsOf hr hi ((ComputableInPolyTime.length_list _).comp hV) hwords have hpackets : ComputableInPolyTime (fun x => (pk x).2.2.map Prod.fst) encIn @@ -510,9 +513,9 @@ theorem computableInPolyTime_nativeChild (hfl : ComputableInPolyTime fl encIn (e have hpair := ((ComputableInPolyTime.length_list _).comp hcedges).prod (ComputableInPolyTime.listAppend' (retained_polyTime hr hV hgroups hg hends) (packetVertices_polyTime hfl ha hL hi hT hpt ht hζ hβ hg hgroups hends hP hcedges hplace)) - have hsymm : ComputableInPolyTime (DescribedNetwork.equivProd (T := VertexDesc)).symm - (encPair encUnary (encList (encPair (encList encNat) VertexDesc.enc))) - (DescribedNetwork.encDescribed VertexDesc.enc) := + have hsymm : ComputableInPolyTime (DescribedNetwork.equivProd (T := VertexDesc T)).symm + (encPair encUnary (encList (encPair (encList encNat) (VertexDesc.enc encT)))) + (DescribedNetwork.encDescribed (VertexDesc.enc encT)) := ComputableInPolyTime.of_eq fun y => by rw [DescribedNetwork.encDescribed, encOfEquiv_apply, Equiv.apply_symm_apply] exact (hsymm.comp hpair).of_enc_eq fun x => by @@ -534,7 +537,7 @@ private theorem foldl_max_le {l : List ℕ} {m n : ℕ} (hm : m ≤ n) (hl : ∀ /-- **At most `M (2 ^ a) ^ 12` packets**: the native parent packing of a network with `M` edges has at most one block of `2 ^ a` slots per edge, times the `4096 ^ a` words of pairs of symbols. -/ -theorem numPackets_nativeParentPacking_le (r a : ℕ) (D : DescribedNetwork VertexDesc) : +theorem numPackets_nativeParentPacking_le (r a : ℕ) (D : DescribedNetwork (VertexDesc T)) : (nativeParentPacking r a D).2.1 ≤ D.numEdges * (2 ^ a) ^ 12 := by set pairs := PacketPacking.edgeWordPairs (PacketPacking.labelWords r (D.vertices.length - r) a 64 (D.edgeEnds.map fun e => (e.1, e.2 - r))).1 (PacketPacking.labelWords r @@ -576,16 +579,16 @@ theorem numPackets_nativeParentPacking_le (r a : ℕ) (D : DescribedNetwork Vert section PolyTime variable {δ : Type} {encIn : δ ↪ List Bool} {fl ζ β : δ → List ℕ} {a i pt r g : δ → ℕ} - {t : δ → ℤ} {D : δ → DescribedNetwork VertexDesc} + {t : δ → ℤ} {D : δ → DescribedNetwork (VertexDesc T)} /-- **The native parent packing is polynomial-time**, with the number of rows and `a` in unary. -/ theorem computableInPolyTime_nativeParentPacking (hr : ComputableInPolyTime r encIn encUnary) (ha : ComputableInPolyTime a encIn encUnary) - (hD : ComputableInPolyTime D encIn (DescribedNetwork.encDescribed VertexDesc.enc)) : + (hD : ComputableInPolyTime D encIn (DescribedNetwork.encDescribed (VertexDesc.enc encT))) : ComputableInPolyTime (fun x => nativeParentPacking (r x) (a x) (D x)) encIn PacketPacking.encNativePacking := by - have hends := (DescribedNetwork.computableInPolyTime_edgeEnds VertexDesc.enc).comp hD + have hends := (DescribedNetwork.computableInPolyTime_edgeEnds (VertexDesc.enc encT)).comp hD have hrb := ComputableInPolyTime.unary_to_binary.comp hr have hshift : ComputableInPolyTime (fun x => (D x).edgeEnds.map fun e => (e.1, e.2 - r x)) encIn (encList (encPair encNat encNat)) := @@ -610,7 +613,7 @@ and `2 ^ a` in unary. -/ theorem computableInPolyTime_numPackets_nativeParentPacking (hr : ComputableInPolyTime r encIn encUnary) (ha : ComputableInPolyTime a encIn encUnary) (hL : ComputableInPolyTime (fun x => 2 ^ a x) encIn encUnary) - (hD : ComputableInPolyTime D encIn (DescribedNetwork.encDescribed VertexDesc.enc)) : + (hD : ComputableInPolyTime D encIn (DescribedNetwork.encDescribed (VertexDesc.enc encT))) : ComputableInPolyTime (fun x => (nativeParentPacking (r x) (a x) (D x)).2.1) encIn encUnary := by have hpk : ComputableInPolyTime (fun x => nativeParentPacking (r x) (a x) (D x)) encIn @@ -634,12 +637,12 @@ theorem computableInPolyTime_nativeChild_nativeParentPacking (hpt : ComputableInPolyTime pt encIn encUnary) (ht : ComputableInPolyTime t encIn encIntBin) (hζ : ComputableInPolyTime ζ encIn (encList encNat)) (hr : ComputableInPolyTime r encIn encUnary) - (hD : ComputableInPolyTime D encIn (DescribedNetwork.encDescribed VertexDesc.enc)) + (hD : ComputableInPolyTime D encIn (DescribedNetwork.encDescribed (VertexDesc.enc encT))) (hβ : ComputableInPolyTime β encIn (encList encUnary)) (hg : ComputableInPolyTime g encIn encNat) : ComputableInPolyTime (fun x => nativeChild (fl x) (a x) (i x) (pt x) (t x) (ζ x) (r x) (D x) (nativeParentPacking (r x) (a x) (D x)) (β x) (g x)) - encIn (DescribedNetwork.encDescribed VertexDesc.enc) := + encIn (DescribedNetwork.encDescribed (VertexDesc.enc encT)) := computableInPolyTime_nativeChild hfl ha hL hi hT hpt ht hζ (ComputableInPolyTime.unary_to_binary.comp hr) hD (computableInPolyTime_nativeParentPacking hr ha hD) @@ -649,7 +652,7 @@ theorem computableInPolyTime_nativeChild_nativeParentPacking theorem computableInPolyTime_childRows_nativeParentPacking (hr : ComputableInPolyTime r encIn encUnary) (ha : ComputableInPolyTime a encIn encUnary) (hi : ComputableInPolyTime i encIn encUnary) - (hD : ComputableInPolyTime D encIn (DescribedNetwork.encDescribed VertexDesc.enc)) + (hD : ComputableInPolyTime D encIn (DescribedNetwork.encDescribed (VertexDesc.enc encT))) (hg : ComputableInPolyTime g encIn encNat) : ComputableInPolyTime (fun x => childRows (r x) (i x) (D x) (nativeParentPacking (r x) (a x) (D x)) (g x)) encIn encNat := @@ -662,7 +665,8 @@ end PolyTime section Shape -variable (fl : List ℕ) (a i pt : ℕ) (t : ℤ) (ζ : List ℕ) (r : ℕ) (D : DescribedNetwork VertexDesc) +variable (fl : List ℕ) (a i pt : ℕ) (t : ℤ) (ζ : List ℕ) (r : ℕ) + (D : DescribedNetwork (VertexDesc T)) (pk : (List (List ℕ) × List (List ℕ)) × ℕ × List (ℕ × ℕ)) (β : List ℕ) (g : ℕ) /-- **The child has at most twice as many edges as the parent**: one per end of a parent edge in @@ -701,7 +705,7 @@ theorem length_vertices_nativeChild : either a parent vertex with renumbered ports, with the same descriptor and the same number of ports, or the vertex of a packet `q`, whose descriptor is its context, tags of its ports with slots from the packing (or `0`), and its slice of `β`. -/ -theorem mem_vertices_nativeChild {v : List ℕ × VertexDesc} +theorem mem_vertices_nativeChild {v : List ℕ × VertexDesc T} (hv : v ∈ (nativeChild fl a i pt t ζ r D pk β g).vertices) : (∃ w ∈ D.vertices, v.2 = w.2 ∧ v.1.length = w.1.length) ∨ ∃ q < pk.2.1, ∃ tags : List (Bool × ℕ), diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/PacketTerms.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/PacketTerms.lean index f614aa598..7280a7577 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/PacketTerms.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/PacketTerms.lean @@ -723,6 +723,7 @@ structure PacketCtx where cols : List (ℕ × Bool) /-- The interpolation value. -/ ζ : List ℕ + deriving Inhabited namespace PacketCtx diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/VertexDesc.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/VertexDesc.lean index 3fff52005..4f620b30f 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/VertexDesc.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/VertexDesc.lean @@ -22,30 +22,34 @@ import Mathlib.Data.List.GetD # Descriptors of the vertices of the recursion's networks The networks of the contraction recursion of [OpenAI2026ETH] (§D.4.6–§D.4.7, pp. 63–64) have two -kinds of vertices. The vertices of the input network keep their tables, and they survive into -every child of their group with the same ports. The packet vertices created at a call are -described by "its packet data, the tuple `β`, the interpolation value, and the creation -precision" (p. 63), and from then on they also survive into the children of their group. A -vertex descriptor (`VertexDesc`) is therefore a table or a packet descriptor +kinds of vertices. The vertices of the input network keep their original descriptions, and they +survive into every child of their group with the same ports. The packet vertices created at a call +are described by "its packet data, the tuple `β`, the interpolation value, and the creation +precision" (p. 63), and from then on they also survive into the children of their group. A vertex +descriptor (`VertexDesc T`) is therefore a root descriptor of type `T` or a packet descriptor (`NativePacket.PacketDesc`), and a retained vertex keeps its descriptor. -`VertexDesc.entry` evaluates a descriptor at the bits on its ports: the table entry, as a constant -coefficient list, or the native packet entry at the packet's creation precision. A network of the -recursion reads the entries at its own precision `(p, fl)` (`GaloisRingArith.val p fl`), so a -retained packet vertex created at a lower precision is read at the higher one: its coefficients -are those of the same element of `O = ℤ_(2)[U] / (f)`. One native machine evaluates every -descriptor (`VertexDesc.entryCertificate`), with the packet evaluator's bounds: time -`K (m + 2) ^ L Z ^ K` and space `K Z ^ K`, for `m` target modes and `L` row ports of a packet (none -for a table) and `Z` polynomial in the input and the reduced coefficient lists -(`VertexDesc.entryCertificate_le`). It is the evaluator of direct summation over networks of -descriptors at coefficient lists (`DescribedNetwork.contractionCertificate` at `SumOps.galois`). +`VertexDesc.entry ev` evaluates a descriptor at the bits on its ports: the root's entry procedure +`ev`, which returns a coefficient list, or the native packet entry at the packet's creation +precision. A network of the recursion reads the entries at its own precision `(p, fl)` +(`GaloisRingArith.val p fl`), so a vertex is read at every precision through the canonical lift of +its coefficient list: a retained packet vertex created at a lower precision is read at the higher +one as the same element of `O = ℤ_(2)[U] / (f)`. Explicit tables are the root descriptors +`T = List ℕ` with the entry procedure `tableEntry`, which returns the table entry as a constant. +For tables, one native machine evaluates every descriptor (`VertexDesc.entryCertificate`), with +the packet evaluator's bounds: time `K (m + 2) ^ L Z ^ K` and space `K Z ^ K`, for `m` target modes +and `L` row ports of a packet (none for a table) and `Z` polynomial in the input and the reduced +coefficient lists (`VertexDesc.entryCertificate_le`). It is the evaluator of direct summation over +networks of descriptors at coefficient lists (`DescribedNetwork.contractionCertificate` at +`SumOps.galois`). ## Main definitions -* `Cslib.Circuits.Frontier.VertexDesc`: a table or a packet descriptor. +* `Cslib.Circuits.Frontier.tableEntry`: the entry procedure of tables. +* `Cslib.Circuits.Frontier.VertexDesc`: a root descriptor or a packet descriptor. * `Cslib.Circuits.Frontier.VertexDesc.entry`: its entry at the bits on its ports. * `Cslib.Circuits.Frontier.VertexDesc.enc`: its encoding. -* `Cslib.Circuits.Frontier.VertexDesc.entryCertificate`: the native evaluator. +* `Cslib.Circuits.Frontier.VertexDesc.entryCertificate`: the native evaluator, for tables. ## Main results @@ -68,55 +72,62 @@ local notation "ℤ₍₂₎" => Valuation.integer (Rat.padicValuation 2) open GaloisRingArith NativePacket TensorNetwork Turing.MultiTapeTM Cslib.GenericRAM -/-- **The descriptor of a vertex** of a network of the contraction recursion: the table of a +/-- **The entry procedure of tables**: the table entry at the bits on the ports, as a constant +coefficient list. -/ +@[expose] def tableEntry (table : List ℕ) (bs : List Bool) : List ℕ := + [ExplicitTensorNetwork.entry table bs] + +/-- **The descriptor of a vertex** of a network of the contraction recursion: the descriptor of a vertex of the input network (`inl`), or the descriptor of a packet vertex (`inr`). -/ -abbrev VertexDesc : Type := List ℕ ⊕ PacketDesc +abbrev VertexDesc (T : Type) : Type := T ⊕ PacketDesc namespace VertexDesc -/-- **The entry of a vertex at the bits on its ports**: the table entry, as a constant coefficient -list, or the native packet entry at the packet's creation precision. -/ -@[expose] def entry : VertexDesc → List Bool → List ℕ - | .inl table, bs => [ExplicitTensorNetwork.entry table bs] +variable {T : Type} + +/-- **The entry of a vertex at the bits on its ports**: the entry procedure `ev` of the input +network, or the native packet entry at the packet's creation precision. -/ +@[expose] def entry (ev : T → List Bool → List ℕ) : VertexDesc T → List Bool → List ℕ + | .inl t, bs => ev t bs | .inr d, bs => packetVertexEntry d bs -/-- The encoding of a descriptor: a tag, then the table in binary or the packet descriptor. -/ -abbrev enc : VertexDesc ↪ List Bool := encSum (encList encNat) encPacketDesc +/-- The encoding of a descriptor: a tag, then the root descriptor or the packet descriptor. -/ +abbrev enc (encT : T ↪ List Bool) : VertexDesc T ↪ List Bool := encSum encT encPacketDesc -/-- The number of target modes of a descriptor: those of its packet, and none for a table. -/ -@[expose] def modes : VertexDesc → ℕ +/-- The number of target modes of a descriptor: those of its packet, and none for a root. -/ +@[expose] def modes : VertexDesc T → ℕ | .inl _ => 0 | .inr d => (targetModes d.1).length /-- The number of row ports of a descriptor at the bits on its ports: those of its packet, and -none for a table. -/ -@[expose] def rowPorts : VertexDesc → List Bool → ℕ +none for a root. -/ +@[expose] def rowPorts : VertexDesc T → List Bool → ℕ | .inl _, _ => 0 | .inr d, bs => (sidePorts d.2.1 bs true).length /-- The reduced coefficient lists of the creation precision of a descriptor are at most `Rv` bits -long; no condition for a table. -/ -@[expose] def ReducedLE (Rv : ℕ) : VertexDesc → Prop +long; no condition for a root. -/ +@[expose] def ReducedLE (Rv : ℕ) : VertexDesc T → Prop | .inl _ => True | .inr d => ∀ y, SumOps.galois.Reduced (d.1.p, d.1.fl) y → (encList encNat y).length ≤ Rv /-! ### Values -/ -@[simp] theorem entry_inl (table : List ℕ) (bs : List Bool) : - entry (.inl table) bs = [ExplicitTensorNetwork.entry table bs] := rfl +@[simp] theorem entry_inl (ev : T → List Bool → List ℕ) (t : T) (bs : List Bool) : + entry ev (.inl t) bs = ev t bs := rfl -@[simp] theorem entry_inr (d : PacketDesc) (bs : List Bool) : - entry (.inr d) bs = packetVertexEntry d bs := rfl +@[simp] theorem entry_inr (ev : T → List Bool → List ℕ) (d : PacketDesc) (bs : List Bool) : + entry ev (.inr d) bs = packetVertexEntry d bs := rfl /-- **A table entry is read as a constant** at every precision. -/ theorem val_entry_inl (p : ℕ) (fl table : List ℕ) (bs : List Bool) : - val p fl (entry (.inl table) bs) = + val p fl (entry tableEntry (.inl table) bs) = ((ExplicitTensorNetwork.entry table bs : ℕ) : Ring p fl) := by obtain h | ⟨e, he⟩ : fl.length = 0 ∨ ∃ e, fl.length = e + 1 := (Nat.eq_zero_or_pos _).imp id fun h => ⟨_, (Nat.succ_pred_eq_of_pos h).symm⟩ · have := subsingleton_of_length_eq_zero (p := p) h exact Subsingleton.elim _ _ - · rw [entry_inl, val, he, Finset.sum_range_succ', + · rw [entry_inl, tableEntry, val, he, Finset.sum_range_succ', Finset.sum_eq_zero fun i _ => by rw [List.getD_cons_succ, List.getD_nil]; simp] simp @@ -124,12 +135,13 @@ theorem val_entry_inl (p : ℕ) (fl table : List ℕ) (bs : List Bool) : precision `p` of the packet, to a ring in which `2` is nilpotent, the entry of a packet descriptor at the bits on its ports is `packetEntry` at any ring map `κ : ℤ_(2) → S`, the image of the interpolation value, the dense exponents, and the row and column ports read from the bits. -/ -theorem map_val_entry_inr {S : Type*} [CommRing S] (d : PacketDesc) (bs : List Bool) - (ψ : Ring d.1.p d.1.fl →+* S) {n : ℕ} (hn : (2 : S) ^ n = 0) (κ : ℤ₍₂₎ →+* S) +theorem map_val_entry_inr {S : Type*} [CommRing S] (ev : T → List Bool → List ℕ) + (d : PacketDesc) (bs : List Bool) (ψ : Ring d.1.p d.1.fl →+* S) {n : ℕ} + (hn : (2 : S) ^ n = 0) (κ : ℤ₍₂₎ →+* S) (hL : d.1.L = 2 ^ d.1.a) (hia : d.1.i < d.1.a) (htiles : d.1.tiles = 2 ^ (d.1.i + 1)) (ht : d.1.t ∈ cauchyGrid (2 ^ d.1.a)) (hti : (2 : ℤ) ^ d.1.i ∣ d.1.t) (hti' : ¬ (2 : ℤ) ^ (d.1.i + 1) ∣ d.1.t) (hports : ∀ x ∈ d.2.1, x.2 < 2 ^ d.1.a) : - ψ (val d.1.p d.1.fl (entry (.inr d) bs)) = + ψ (val d.1.p d.1.fl (entry ev (.inr d) bs)) = packetEntry (p := d.1.nb) κ (ψ (val d.1.p d.1.fl d.1.ζ)) d.1.a d.1.i d.1.t d.1.e₁ d.1.e₂ d.1.differ (fun Z => d.2.2.getD (finProdFinEquiv Z) 0) (sidePorts d.2.1 bs true) (sidePorts d.2.1 bs false) := by @@ -142,33 +154,35 @@ theorem map_val_entry_inr {S : Type*} [CommRing S] (d : PacketDesc) (bs : List B htiles ht hti hti' (hside true) (hside false) d.2.2 /-- A packet entry is a reduced coefficient list at the packet's precision. -/ -theorem reduced_entry_inr (d : PacketDesc) (bs : List Bool) : - SumOps.galois.Reduced (d.1.p, d.1.fl) (entry (.inr d) bs) := +theorem reduced_entry_inr (ev : T → List Bool → List ℕ) (d : PacketDesc) (bs : List Bool) : + SumOps.galois.Reduced (d.1.p, d.1.fl) (entry ev (.inr d) bs) := SumOps.galois.reduced_mul (d.1.p, d.1.fl) _ _ -/-! ### The native evaluator -/ +/-! ### The native evaluator of tables -/ /-- The right summand of a descriptor and its bits. -/ theorem getRight_polyTime : - ComputableInPolyTime (fun q : VertexDesc × List Bool => q.1.getRight?) (encPair enc encBits) - (encOption encPacketDesc) := + ComputableInPolyTime (fun q : VertexDesc (List ℕ) × List Bool => q.1.getRight?) + (encPair (enc (encList encNat)) encBits) (encOption encPacketDesc) := (ComputableInO.getRight?_deg _ _).computableInPolyTime.comp (ComputableInPolyTime.fst _ _) /-- The table entry of a descriptor at its bits, the empty table standing for a packet, as a singleton list. -/ theorem tableEntry_polyTime : - ComputableInPolyTime (fun q : VertexDesc × List Bool => - [ExplicitTensorNetwork.entry (q.1.getLeft?.getD []) q.2]) (encPair enc encBits) - (encList encNat) := by - have hleft : ComputableInPolyTime (fun q : VertexDesc × List Bool => q.1.getLeft?) - (encPair enc encBits) (encOption (encList encNat)) := + ComputableInPolyTime (fun q : VertexDesc (List ℕ) × List Bool => + [ExplicitTensorNetwork.entry (q.1.getLeft?.getD []) q.2]) + (encPair (enc (encList encNat)) encBits) (encList encNat) := by + have hleft : ComputableInPolyTime (fun q : VertexDesc (List ℕ) × List Bool => q.1.getLeft?) + (encPair (enc (encList encNat)) encBits) (encOption (encList encNat)) := (ComputableInO.getLeft?_deg _ _).computableInPolyTime.comp (ComputableInPolyTime.fst _ _) - have htable : ComputableInPolyTime (fun q : VertexDesc × List Bool => q.1.getLeft?.getD []) - (encPair enc encBits) (encList encNat) := + have htable : ComputableInPolyTime + (fun q : VertexDesc (List ℕ) × List Bool => q.1.getLeft?.getD []) + (encPair (enc (encList encNat)) encBits) (encList encNat) := (ComputableInDegree.getD (enc₁ := encList encNat) (enc := encOption (encList encNat)) []).computableInPolyTime.comp hleft have hindex := ComputableInPolyTime.bitsBinaryValue.comp - (ComputableInPolyTime.bitsReverse.comp (ComputableInPolyTime.snd enc encBits)) + (ComputableInPolyTime.bitsReverse.comp + (ComputableInPolyTime.snd (enc (encList encNat)) encBits)) have hentry := ComputableInPolyTime.listGetD_binary (encA := encNat) (encL := encList encNat) 0 htable hindex exact (ComputableInPolyTime.cons' hentry (ComputableInPolyTime.const [])).of_enc_eq fun q => by @@ -177,17 +191,18 @@ theorem tableEntry_polyTime : /-- The input of the packet evaluator from a descriptor's bits and its packet. -/ theorem packetInput_polyTime : - ComputableInPolyTime (fun p : (VertexDesc × List Bool) × PacketDesc => (p.2, p.1.2)) - (encPair (encPair enc encBits) encPacketDesc) (encPair encPacketDesc encBits) := + ComputableInPolyTime (fun p : (VertexDesc (List ℕ) × List Bool) × PacketDesc => (p.2, p.1.2)) + (encPair (encPair (enc (encList encNat)) encBits) encPacketDesc) + (encPair encPacketDesc encBits) := (ComputableInPolyTime.snd _ _).prod - ((ComputableInPolyTime.snd enc encBits).comp (ComputableInPolyTime.fst _ _)) + ((ComputableInPolyTime.snd (enc (encList encNat)) encBits).comp (ComputableInPolyTime.fst _ _)) -/-- **One native machine for the entries of all descriptors**: the table lookup for a table, and -the native packet evaluator (`NativePacket.vertexCertificate`) for a packet. -/ +/-- **One native machine for the entries of all descriptors over tables**: the table lookup for a +table, and the native packet evaluator (`NativePacket.vertexCertificate`) for a packet. -/ noncomputable def entryCertificate : - NativeCertificate (fun q : VertexDesc × List Bool => entry q.1 q.2) (encPair enc encBits) - (encList encNat) := - (NativeCertificate.option (value := fun q : VertexDesc × List Bool => q.1.getRight?) + NativeCertificate (fun q : VertexDesc (List ℕ) × List Bool => entry tableEntry q.1 q.2) + (encPair (enc (encList encNat)) encBits) (encList encNat) := + (NativeCertificate.option (value := fun q : VertexDesc (List ℕ) × List Bool => q.1.getRight?) (fallback := fun q => [ExplicitTensorNetwork.entry (q.1.getLeft?.getD []) q.2]) (body := fun p => packetVertexEntry p.2 p.1.2) (NativeCertificate.ofPolyTime getRight_polyTime) @@ -208,11 +223,11 @@ table), if the reduced coefficient lists of a packet's precision are at most `Rv with `Z = n + m + Rv + 2` the time is at most `K (m + 2) ^ L Z ^ K` and the space at most `K Z ^ K`. -/ theorem entryCertificate_le : - ∃ K : ℕ, ∀ (q : VertexDesc × List Bool) (Rv : ℕ), q.1.ReducedLE Rv → + ∃ K : ℕ, ∀ (q : VertexDesc (List ℕ) × List Bool) (Rv : ℕ), q.1.ReducedLE Rv → entryCertificate.time q ≤ K * (q.1.modes + 2) ^ q.1.rowPorts q.2 * - ((encPair enc encBits q).length + q.1.modes + Rv + 2) ^ K ∧ + ((encPair (enc (encList encNat)) encBits q).length + q.1.modes + Rv + 2) ^ K ∧ entryCertificate.space q ≤ - K * ((encPair enc encBits q).length + q.1.modes + Rv + 2) ^ K := by + K * ((encPair (enc (encList encNat)) encBits q).length + q.1.modes + Rv + 2) ^ K := by obtain ⟨K₀, hK₀⟩ := vertexCertificate_le have hR := NativeCertificate.ofPolyTime_isPolynomial getRight_polyTime have hT := NativeCertificate.ofPolyTime_isPolynomial tableEntry_polyTime @@ -227,7 +242,7 @@ theorem entryCertificate_le : obtain ⟨G, hG⟩ : ∃ G, G = K₀ + 2 * cr + 2 * cr' + ct + ct' + ci * 3 ^ di + ci' * 3 ^ di' + 1 := ⟨_, rfl⟩ refine ⟨G + D, fun q Rv hRv => ?_⟩ - obtain ⟨n, hn⟩ : ∃ n, n = (encPair enc encBits q).length := ⟨_, rfl⟩ + obtain ⟨n, hn⟩ : ∃ n, n = (encPair (enc (encList encNat)) encBits q).length := ⟨_, rfl⟩ obtain ⟨Z, hZ⟩ : ∃ Z, Z = n + q.1.modes + Rv + 2 := ⟨_, rfl⟩ obtain ⟨P, hP⟩ : ∃ P, P = (q.1.modes + 2) ^ q.1.rowPorts q.2 := ⟨_, rfl⟩ rw [← hn, ← hZ, ← hP] @@ -278,10 +293,12 @@ theorem entryCertificate_le : have h3 : (encPair encPacketDesc encBits (d, bs)).length = 2 * (encPacketDesc d).length + 1 + (encBits bs).length := length_encPair _ omega - have hlenI : (encPair (encPair enc encBits) encPacketDesc ((.inr d, bs), d)).length + 1 ≤ - 3 * Z := by - have h1 : (encPair (encPair enc encBits) encPacketDesc ((.inr d, bs), d)).length = - 2 * (encPair enc encBits (.inr d, bs)).length + 1 + (encPacketDesc d).length := + have hlenI : (encPair (encPair (enc (encList encNat)) encBits) encPacketDesc + ((.inr d, bs), d)).length + 1 ≤ 3 * Z := by + have h1 : (encPair (encPair (enc (encList encNat)) encBits) encPacketDesc + ((.inr d, bs), d)).length = + 2 * (encPair (enc (encList encNat)) encBits (.inr d, bs)).length + 1 + + (encPacketDesc d).length := length_encPair _ omega have hpow3 {c e : ℕ} (he : e ≤ D) : c * (3 * Z) ^ e ≤ c * 3 ^ e * Z ^ D := by diff --git a/Complexity/Computability/Complexity/Classes/CountingSimulation/FastAlgorithm.lean b/Complexity/Computability/Complexity/Classes/CountingSimulation/FastAlgorithm.lean index e652204be..483fcbb67 100644 --- a/Complexity/Computability/Complexity/Classes/CountingSimulation/FastAlgorithm.lean +++ b/Complexity/Computability/Complexity/Classes/CountingSimulation/FastAlgorithm.lean @@ -298,7 +298,7 @@ section Resources open FastContraction Cslib.GenericRAM Cslib.GenericRAM.StackRecursion Turing.MultiTapeTM -variable (mk : Call → ChildCursor.State → ℕ × DescribedNetwork VertexDesc) +variable (mk : Call (List ℕ) → ChildCursor.State → ℕ × DescribedNetwork (VertexDesc (List ℕ))) /-- **The resource analysis of the fast machine**, the remaining obligation of the running time. For all constants `C` and `D` there are `K` and `s₀` such that on every input `(P, r, G)` with @@ -310,13 +310,14 @@ whose leaves take time at most `TL` and space at most `SL`, with `H` open calls, @[expose] def FastAnalysis : Prop := ∀ C D : ℕ, ∃ K s₀ : ℕ, ∀ (s P : ℕ) (G : ℕ × ExplicitTensorNetwork ℕ), 2 ≤ s → 1 ≤ P → P ≤ D * s → ExplicitAdmissible C s G → fastGuard G = true → - ∃ (I : Invariant Call Frame (ℕ × List ℕ)) (N H F TL SL : ℕ), - (scheme mk).Eval I (root (ExplicitTensorNetwork.capPrecision (P, G))) - (0, value mk (root (ExplicitTensorNetwork.capPrecision (P, G)))) N H ∧ + ∃ (I : Invariant (Call (List ℕ)) Frame (ℕ × List ℕ)) (N H F TL SL : ℕ), + (scheme tableEntry mk).Eval I (root (ExplicitTensorNetwork.capPrecision (P, G))) + (0, value tableEntry mk (root (ExplicitTensorNetwork.capPrecision (P, G)))) N H ∧ (s₀ ≤ s → 2 * N - 1 ≤ fuel (ExplicitTensorNetwork.capPrecision (P, G))) ∧ - (∀ x, I.node x → (encCall x).length ≤ F ∧ ((scheme mk).isLeaf x = true → + (∀ x, I.node x → (encCall (encList encNat) x).length ≤ F ∧ + ((scheme tableEntry mk).isLeaf x = true → (leafCertificate mk).time x ≤ TL ∧ (leafCertificate mk).space x ≤ SL)) ∧ - (∀ x a, I.frame x a → (encPair encCall encFrame (x, a)).length ≤ F) ∧ + (∀ x a, I.frame x a → (encPair (encCall (encList encNat)) encFrame (x, a)).length ≤ F) ∧ (∀ v, I.value v → (encValue v).length ≤ F) ∧ H + F + SL ≤ K * ((FastContraction.encInput (P, G)).length + 1) ^ K ∧ TL ≤ K * ((FastContraction.encInput (P, G)).length + 1) ^ K * @@ -362,7 +363,8 @@ scheme and the resource analysis, for all constants `C` and `D` there is `K` suc guarded input admissible at size `s ≥ 2` with constant `C` and with precision `1 ≤ P ≤ D s`, the fast machine takes time at most `K (n + 1) ^ K 2 ^ (K s / √⌊log₂ s⌋)` and space at most `K (n + 1) ^ K`. -/ -theorem fastCertificate_le (hpoly : (scheme mk).PolyTime encCall encFrame encValue) +theorem fastCertificate_le + (hpoly : (scheme tableEntry mk).PolyTime (encCall (encList encNat)) encFrame encValue) (hana : FastAnalysis mk) (C D : ℕ) : ∃ K : ℕ, ∀ (s P : ℕ) (G : ℕ × ExplicitTensorNetwork ℕ), 2 ≤ s → 1 ≤ P → P ≤ D * s → ExplicitAdmissible C s G → fastGuard G = true → @@ -496,8 +498,8 @@ theorem fastCertificate_le (hpoly : (scheme mk).PolyTime encCall encFrame encVal K₂ * ((encInput q).length + 1) ^ K₂ * 2 ^ (C * s₀) := Nat.le_mul_of_pos_right _ Nat.one_le_two_pow _ = K₂ * 2 ^ (C * s₀) * B ^ K₂ := by ring) - have hbig : s₀ ≤ s → (scheme mk).run fuel root (ExplicitTensorNetwork.capPrecision q) = - some (0, value mk (root (ExplicitTensorNetwork.capPrecision q))) := + have hbig : s₀ ≤ s → (scheme tableEntry mk).run fuel root (ExplicitTensorNetwork.capPrecision q) = + some (0, value tableEntry mk (root (ExplicitTensorNetwork.capPrecision q))) := fun h => Scheme.run_eq_some he (hN h) clear hKa hK₁ hK₂ h₁ h₂ -- Everything against `W = B ^ E X`. @@ -548,7 +550,7 @@ theorem fastCertificate_le (hpoly : (scheme mk).PolyTime encCall encFrame encVal Nat.pow_le_pow_right (by norm_num) (Nat.div_le_div_right (Nat.mul_le_mul_right _ (by omega))) refine ⟨?_, ?_⟩ · rw [fastCertificate_time] - have hrest : ((scheme mk).run fuel root (ExplicitTensorNetwork.capPrecision q)).elim + have hrest : ((scheme tableEntry mk).run fuel root (ExplicitTensorNetwork.capPrecision q)).elim (ExplicitTensorNetwork.directContractionBinaryCertificate.time q) (fun v => (NativeCertificate.ofPolyTime tag_polyTime).time (q, v) + if decide (v.1 = 0) = true then @@ -556,7 +558,8 @@ theorem fastCertificate_le (hpoly : (scheme mk).PolyTime encCall encFrame encVal else (NativeCertificate.ofPolyTime (ComputableInPolyTime.fst FastContraction.encInput encValue)).time (q, v) + ExplicitTensorNetwork.directContractionBinaryCertificate.time q) ≤ R₁ + R₂ := by - rcases hr : (scheme mk).run fuel root (ExplicitTensorNetwork.capPrecision q) with _ | v + rcases hr : (scheme tableEntry mk).run fuel root + (ExplicitTensorNetwork.capPrecision q) with _ | v · by_cases hs₀ : s₀ ≤ s · rw [hbig hs₀] at hr; cases hr · simp only [Option.elim_none]; have := hdir (by omega); omega @@ -579,7 +582,7 @@ theorem fastCertificate_le (hpoly : (scheme mk).PolyTime encCall encFrame encVal rw [hWdef, ← Nat.mul_assoc] exact Nat.mul_le_mul (Nat.mul_le_mul hKK hBE) hXK · rw [fastCertificate_space] - have hrest : ((scheme mk).run fuel root (ExplicitTensorNetwork.capPrecision q)).elim + have hrest : ((scheme tableEntry mk).run fuel root (ExplicitTensorNetwork.capPrecision q)).elim (ExplicitTensorNetwork.directContractionBinaryCertificate.space q) (fun v => (NativeCertificate.ofPolyTime tag_polyTime).space (q, v) + if decide (v.1 = 0) = true then @@ -587,7 +590,8 @@ theorem fastCertificate_le (hpoly : (scheme mk).PolyTime encCall encFrame encVal else (NativeCertificate.ofPolyTime (ComputableInPolyTime.fst FastContraction.encInput encValue)).space (q, v) + ExplicitTensorNetwork.directContractionBinaryCertificate.space q) ≤ R₁ + R₂ := by - rcases hr : (scheme mk).run fuel root (ExplicitTensorNetwork.capPrecision q) with _ | v + rcases hr : (scheme tableEntry mk).run fuel root + (ExplicitTensorNetwork.capPrecision q) with _ | v · simp only [Option.elim_none]; omega · have hd := hdec v (Scheme.value_of_run_eq_some he hr) simp only [Option.elim_some] @@ -609,8 +613,9 @@ call and the passage of well-formedness to the children (`FastContraction.StepCo (`FastAnalysis`). It branches on the guard (`ContractionAlgorithm.ofGuarded`) to the fast machine or to direct summation. -/ noncomputable def contractionAlgorithmOfFast - (hpoly : (scheme mk).PolyTime encCall encFrame encValue) {WF : Call → Prop} - (hstep : StepCorrect mk WF) (hwf : WFChildren mk WF) + (hpoly : (scheme tableEntry mk).PolyTime (encCall (encList encNat)) encFrame encValue) + {WF : Call (List ℕ) → Prop} + (hstep : StepCorrect tableEntry mk WF) (hwf : WFChildren mk WF) (hroot : ∀ P G, fastGuard G = true → WF (root (ExplicitTensorNetwork.capPrecision (P, G)))) (hana : FastAnalysis mk) : ContractionAlgorithm (encPair encNat ExplicitTensorNetwork.encExplicitNetwork) @@ -645,7 +650,8 @@ children and the well-formed roots are proved (`FastContraction.stepCorrect_nati noncomputable def contractionAlgorithmOfNative (hana : FastAnalysis nativeMk) : ContractionAlgorithm (encPair encNat ExplicitTensorNetwork.encExplicitNetwork) (fun G => G.2.contraction) ExplicitAdmissible := - contractionAlgorithmOfFast scheme_nativeMk_polyTime stepCorrect_nativeMk wfChildren_nativeMk + contractionAlgorithmOfFast (scheme_nativeMk_polyTime tableEntry) + (stepCorrect_nativeMk tableEntry) wfChildren_nativeMk (fun P _ hg => wf_root P hg) hana end Resources diff --git a/Complexity/Computability/Complexity/Classes/CountingSimulation/FastAnalysis.lean b/Complexity/Computability/Complexity/Classes/CountingSimulation/FastAnalysis.lean index 9e69bf87b..ff5135680 100644 --- a/Complexity/Computability/Complexity/Classes/CountingSimulation/FastAnalysis.lean +++ b/Complexity/Computability/Complexity/Classes/CountingSimulation/FastAnalysis.lean @@ -179,11 +179,12 @@ such that on every guarded input admissible at size `s ≥ 2` with constant `C` ∀ C D : ℕ, ∃ c d : ℕ, ∀ (s P : ℕ) (G : ℕ × ExplicitTensorNetwork ℕ), 2 ≤ s → 1 ≤ P → P ≤ D * s → ExplicitAdmissible C s G → fastGuard G = true → ∀ x, Reach nativeMk (root (ExplicitTensorNetwork.capPrecision (P, G))) x → - (encCall x).length ≤ c * ((FastContraction.encInput (P, G)).length + 1) ^ d ∧ - (∀ a, (reachInv nativeMk (root (ExplicitTensorNetwork.capPrecision (P, G)))).frame x a → - (encPair encCall encFrame (x, a)).length ≤ + (encCall (encList encNat) x).length ≤ c * ((FastContraction.encInput (P, G)).length + 1) ^ d ∧ + (∀ a, (reachInv tableEntry nativeMk + (root (ExplicitTensorNetwork.capPrecision (P, G)))).frame x a → + (encPair (encCall (encList encNat)) encFrame (x, a)).length ≤ c * ((FastContraction.encInput (P, G)).length + 1) ^ d) ∧ - (encValue (x.depth, value nativeMk x)).length ≤ + (encValue (x.depth, value tableEntry nativeMk x)).length ≤ c * ((FastContraction.encInput (P, G)).length + 1) ^ d /-- **The leaf bounds**: for all constants `C` and `D` there is `K` such that on every guarded @@ -223,8 +224,9 @@ theorem fastAnalysis_nativeMk_of (hS : FastSizes) (hL : FastLeaves) : FastAnalys have hp₀ : q.1 ≤ D * m := (min_le_right _ _).trans (hPD.trans (Nat.mul_le_mul_left _ hsm)) -- The derivation. - obtain ⟨N, H, he, hN, hH⟩ : ∃ N H, (scheme nativeMk).Eval (reachInv nativeMk x₀) x₀ - (0, value nativeMk x₀) N H ∧ (max sA (D + 2) ≤ s → 2 * N - 1 ≤ fuel q) ∧ H ≤ m + 1 := by + obtain ⟨N, H, he, hN, hH⟩ : ∃ N H, (scheme tableEntry nativeMk).Eval + (reachInv tableEntry nativeMk x₀) x₀ (0, value tableEntry nativeMk x₀) N H ∧ + (max sA (D + 2) ≤ s → 2 * N - 1 ≤ fuel q) ∧ H ≤ m + 1 := by by_cases hs₀ : max sA (D + 2) ≤ s · have hm2 : D + 2 ≤ m := by omega have hC1 : q.1 / m + 1 ≤ D + 1 := by @@ -234,7 +236,7 @@ theorem fastAnalysis_nativeMk_of (hS : FastSizes) (hL : FastLeaves) : FastAnalys have hB := hsA m (by omega) (q.1 / m + 1) hC1 have hpC : q.1 ≤ (q.1 / m + 1) * m := (Nat.lt_div_mul_add (a := q.1) (b := m) (by omega)).le.trans (by rw [add_mul, one_mul]) - obtain ⟨N, H, he, hN, hH⟩ := exists_eval_onSchedule hB + obtain ⟨N, H, he, hN, hH⟩ := exists_eval_onSchedule tableEntry hB (onSchedule_root_capPrecision hg (Nat.le_add_left 1 _) hpC) rfl (by omega) refine ⟨N, H, he, fun _ => ?_, hH.trans ((Nat.log_lt_self 2 (by omega)).le.trans (Nat.le_succ _))⟩ @@ -246,8 +248,9 @@ theorem fastAnalysis_nativeMk_of (hS : FastSizes) (hL : FastLeaves) : FastAnalys obtain hKL' := hKL s P G hs hP hPD hA hg set K := cS + dS + KL + 1 have hB1 : 1 ≤ n + 1 := by omega - refine ⟨reachInv nativeMk x₀, N, H, cS * (n + 1) ^ dS, KL * (n + 1) ^ KL * 2 ^ (KL * s / - Nat.sqrt (Nat.log 2 s)), KL * (n + 1) ^ KL, he, hN, fun x hx => ⟨(hKS' x hx).1, fun hl => ?_⟩, + refine ⟨reachInv tableEntry nativeMk x₀, N, H, cS * (n + 1) ^ dS, + KL * (n + 1) ^ KL * 2 ^ (KL * s / Nat.sqrt (Nat.log 2 s)), KL * (n + 1) ^ KL, he, hN, + fun x hx => ⟨(hKS' x hx).1, fun hl => ?_⟩, fun x a ha => (hKS' x ha.1).2.1 a ha, fun v ⟨x, hx, hv⟩ => hv ▸ (hKS' x hx).2.2, ?_, ?_⟩ · have hl' : active x = false := by simpa [scheme] using hl exact hKL' x hx hl' @@ -371,7 +374,8 @@ theorem fastSizes : FastSizes := by have : (x₀.edges + 1) * x₀.edges ^ 2 ≤ Y * Y ^ 2 := Nat.mul_le_mul hmY hm2 have : Y * Y ^ 2 = Y ^ 3 := by ring omega - have hR₀ : ∀ w ∈ x₀.net.vertices, (VertexDesc.enc w.2).length ≤ 200 * (Z + 1) ^ 2 := by + have hR₀ : ∀ w ∈ x₀.net.vertices, + (VertexDesc.enc (encList encNat) w.2).length ≤ 200 * (Z + 1) ^ 2 := by intro w hw change w ∈ List.map _ G.2.vertices at hw obtain ⟨v, hv, rfl⟩ := List.mem_map.mp hw @@ -380,7 +384,7 @@ theorem fastSizes : FastSizes := by have := hdesc v hv have : Z ≤ (Z + 1) ^ 2 := (Nat.le_succ Z).trans (Nat.le_self_pow (by norm_num) _) omega - obtain ⟨hc, hv, hf⟩ := hsh.length_le rfl rfl rfl hZ1 hZ2 + obtain ⟨hc, hv, hf⟩ := hsh.length_le tableEntry rfl rfl rfl hZ1 hZ2 (fun z hz => le_one_of_mem_modulus hz) hR₀ -- `1000 (Z + 1) ^ 3 ≤ 2 ^ 55 (n + 1) ^ 24`. have hfin : 1000 * (Z + 1) ^ 3 ≤ 2 ^ 55 * Y ^ 24 := by diff --git a/Complexity/Computability/Complexity/Classes/CountingSimulation/FastLeaves.lean b/Complexity/Computability/Complexity/Classes/CountingSimulation/FastLeaves.lean index 805a16171..447d80216 100644 --- a/Complexity/Computability/Complexity/Classes/CountingSimulation/FastLeaves.lean +++ b/Complexity/Computability/Complexity/Classes/CountingSimulation/FastLeaves.lean @@ -51,7 +51,7 @@ namespace Cslib.Circuits.Frontier.FastContraction /-- **The reached calls are well-formed and have the packet shape**, from a well-formed root with the packet shape. -/ -theorem Reach.wf_packetShape {x₀ x : Call} (h : Reach nativeMk x₀ x) (hw : WF x₀) +theorem Reach.wf_packetShape {x₀ x : Call (List ℕ)} (h : Reach nativeMk x₀ x) (hw : WF x₀) (hs : PacketShape x₀) : WF x ∧ PacketShape x := by induction h with | root => exact ⟨hw, hs⟩ @@ -61,7 +61,7 @@ theorem Reach.wf_packetShape {x₀ x : Call} (h : Reach nativeMk x₀ x) (hw : W /-- **Reached calls have at most twice the scale in edges**, from a root at scale its number of edges with bound plus depth one more, for every input: a child has at most twice its parent's edges (`NativeChild.numEdges_nativeChild_le`), and an active parent has at most the root's. -/ -theorem Reach.edges_le_two_mul_scale {x₀ x : Call} (h₀s : x₀.scale = x₀.edges) +theorem Reach.edges_le_two_mul_scale {x₀ x : Call (List ℕ)} (h₀s : x₀.scale = x₀.edges) (h₀b : x₀.bound + x₀.depth = x₀.edges + 1) (h : Reach nativeMk x₀ x) : x.edges ≤ 2 * x.scale := by have key : x.edges ≤ 2 * x₀.edges := by @@ -84,13 +84,14 @@ namespace Cslib.Complexity.CountingSimulation open Cslib.Circuits.Frontier Cslib.Circuits.Frontier.ContractionSchedule Cslib.Circuits.Frontier.FastContraction +open Turing.MultiTapeTM (encList encNat) /-- **The leaf bounds of the native recursion**, from the sizes of the reached calls and three facts about them on admissible guarded inputs: every reached call has at most twice its scale in edges, and for each `C` and `D`, from some size on, every reached leaf has at most the leaf size in edges and precision at most the fourth power of its scale. -/ theorem fastLeaves_of (hS : FastSizes) - (hE : ∀ (P : ℕ) (G : ℕ × ExplicitTensorNetwork ℕ) (x : Call), + (hE : ∀ (P : ℕ) (G : ℕ × ExplicitTensorNetwork ℕ) (x : Call (List ℕ)), Reach nativeMk (root (ExplicitTensorNetwork.capPrecision (P, G))) x → x.edges ≤ 2 * x.scale) (hbig : ∀ C D : ℕ, ∃ s₀ : ℕ, ∀ (s P : ℕ) (G : ℕ × ExplicitTensorNetwork ℕ), 2 ≤ s → 1 ≤ P → @@ -113,15 +114,16 @@ theorem fastLeaves_of (hS : FastSizes) fun h => hs₀ s P G hs hP hPD hA hg h x hx hl have hlen' := (hKS s P G hs hP hPD hA hg x hx).1 rw [← hn] at hlen' - have hlen : (encCall x).length ≤ KS * (n + 1) ^ KS := + have hlen : (encCall (encList encNat) x).length ≤ KS * (n + 1) ^ KS := hlen'.trans (Nat.mul_le_mul (by omega) (Nat.pow_le_pow_right (by omega) (by omega))) -- `n_x + 1 ≤ (KS + 1) (n + 1) ^ KS`. have hB1 : 1 ≤ (n + 1) ^ KS := Nat.one_le_pow _ _ (by omega) - have hx1 : (encCall x).length + 1 ≤ (KS + 1) * (n + 1) ^ KS := by + have hx1 : (encCall (encList encNat) x).length + 1 ≤ (KS + 1) * (n + 1) ^ KS := by rw [add_mul, one_mul]; omega set K := KB * (KS + 1) ^ KB + KS * KB + KB - have hpoly : KB * ((encCall x).length + 1) ^ KB ≤ K * (n + 1) ^ K := - calc KB * ((encCall x).length + 1) ^ KB ≤ KB * ((KS + 1) * (n + 1) ^ KS) ^ KB := + have hpoly : KB * ((encCall (encList encNat) x).length + 1) ^ KB ≤ K * (n + 1) ^ K := + calc KB * ((encCall (encList encNat) x).length + 1) ^ KB + ≤ KB * ((KS + 1) * (n + 1) ^ KS) ^ KB := Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hx1 _) _ = KB * (KS + 1) ^ KB * (n + 1) ^ (KS * KB) := by rw [mul_pow, ← pow_mul]; ring _ ≤ K * (n + 1) ^ K := diff --git a/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkNativeChild.lean b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkNativeChild.lean index 1431e819e..deb70c052 100644 --- a/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkNativeChild.lean +++ b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkNativeChild.lean @@ -20,10 +20,10 @@ The row `0` joins the columns `1` and `2` by the edges `0` and `1`, and the vert The network is rows-first at `1`, and the ends of its edges are computed from the ports. -/ /-- The tables of the vertices. -/ -def table (n : ℕ) : VertexDesc := .inl (List.replicate n 1) +def table (n : ℕ) : VertexDesc (List ℕ) := .inl (List.replicate n 1) /-- The row `0` with ports `1, 0` (not in edge order), the columns `1` and `2`. -/ -def path : DescribedNetwork VertexDesc := +def path : DescribedNetwork (VertexDesc (List ℕ)) := ⟨2, [([1, 0], table 4), ([0], table 2), ([1], table 2)]⟩ example : path.IsRowsFirstBipartite 1 := by decide @@ -34,7 +34,7 @@ example : path.edgeEnds = [(0, 1), (0, 2)] := by decide /-- The native child of group `0` for a packing that puts the row and the column `1` in group `0`, the column `2` in group `1`, and both edges in packet `0` with slots `0` and `1`. -/ -def child : DescribedNetwork VertexDesc := +def child : DescribedNetwork (VertexDesc (List ℕ)) := nativeChild [1] 1 0 3 (-1) [0] 1 path (([[0]], [[0], [1]]), 1, [(0, 0), (0, 1)]) [] 0 /-- The child keeps the row and the column `1`, and adds the packet: three child edges, the two diff --git a/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkNativeChildPolyTime.lean b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkNativeChildPolyTime.lean index 5a4e66be6..3c9ba93ca 100644 --- a/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkNativeChildPolyTime.lean +++ b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkNativeChildPolyTime.lean @@ -33,10 +33,10 @@ The path of `TensorNetworkNativeChild` with one row joined to two columns. The c keeps the row and the column `1` and adds one packet. -/ /-- The tables of the vertices. -/ -def table (n : ℕ) : VertexDesc := .inl (List.replicate n 1) +def table (n : ℕ) : VertexDesc (List ℕ) := .inl (List.replicate n 1) /-- The row `0` with ports `1, 0`, the columns `1` and `2`. -/ -def path : DescribedNetwork VertexDesc := +def path : DescribedNetwork (VertexDesc (List ℕ)) := ⟨2, [([1, 0], table 4), ([0], table 2), ([1], table 2)]⟩ /-- The packing: the row and the column `1` in group `0`, the column `2` in group `1`, both edges @@ -58,17 +58,17 @@ and its number of packets in unary, with the other parameters fixed. -/ /-- A parent, the packing words, the number of packets and the placements. -/ abbrev Input : Type := - DescribedNetwork VertexDesc × (List (List ℕ) × List (List ℕ)) × ℕ × List (ℕ × ℕ) + DescribedNetwork (VertexDesc (List ℕ)) × (List (List ℕ) × List (List ℕ)) × ℕ × List (ℕ × ℕ) /-- The encoding of `Input`, with the number of packets in unary. -/ abbrev encInput : Input ↪ List Bool := - encPair (DescribedNetwork.encDescribed VertexDesc.enc) + encPair (DescribedNetwork.encDescribed (VertexDesc.enc (encList encNat))) (encPair (encPair (encList (encList encNat)) (encList (encList encNat))) (encPair encUnary (encList (encPair encNat encNat)))) example : ComputableInPolyTime (fun x : Input => nativeChild [1] 1 0 3 (-1) [0] 1 x.1 x.2 [] 0) encInput - (DescribedNetwork.encDescribed VertexDesc.enc) := by + (DescribedNetwork.encDescribed (VertexDesc.enc (encList encNat))) := by have hpk : ComputableInPolyTime (fun x : Input => x.2) encInput PacketPacking.encNativePacking := ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _)).prod @@ -85,10 +85,10 @@ example : ComputableInPolyTime (fun x : Input => (ComputableInPolyTime.const _) (ComputableInPolyTime.const _) /-- With the native parent packing, the number of rows and `a` are the only further inputs. -/ -example : ComputableInPolyTime (fun D : DescribedNetwork VertexDesc => +example : ComputableInPolyTime (fun D : DescribedNetwork (VertexDesc (List ℕ)) => nativeChild [1] 1 0 3 (-1) [0] 1 D (nativeParentPacking 1 1 D) [] 0) - (DescribedNetwork.encDescribed VertexDesc.enc) - (DescribedNetwork.encDescribed VertexDesc.enc) := + (DescribedNetwork.encDescribed (VertexDesc.enc (encList encNat))) + (DescribedNetwork.encDescribed (VertexDesc.enc (encList encNat))) := computableInPolyTime_nativeChild_nativeParentPacking (ComputableInPolyTime.const _) (ComputableInPolyTime.const _) (ComputableInPolyTime.const _) (ComputableInPolyTime.const _) (ComputableInPolyTime.const _) (ComputableInPolyTime.const _) (ComputableInPolyTime.const _) diff --git a/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkVertexDesc.lean b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkVertexDesc.lean index e3be36554..e84885bb7 100644 --- a/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkVertexDesc.lean +++ b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkVertexDesc.lean @@ -27,13 +27,14 @@ list come out in order. Reducing an element of `O` to `A_n` and mapping back alo namespace ComplexityTests.TensorNetworkVertexDesc open Cslib Cslib.Circuits.Frontier Cslib.Circuits.Frontier.NativePacket +open Turing.MultiTapeTM (encList encNat) /-! ### Tables -/ -- The bits `[true, false]` index the table at `1`. -example : VertexDesc.entry (.inl [3, 5, 7, 9]) [true, false] = [5] := by decide +example : VertexDesc.entry tableEntry (.inl [3, 5, 7, 9]) [true, false] = [5] := by decide -example : VertexDesc.entry (.inl [3, 5, 7, 9]) [false, true] = [7] := by decide +example : VertexDesc.entry tableEntry (.inl [3, 5, 7, 9]) [false, true] = [7] := by decide -- A table has no modes and no row ports. example : VertexDesc.modes (.inl [3, 5]) = 0 := rfl @@ -41,7 +42,7 @@ example : VertexDesc.modes (.inl [3, 5]) = 0 := rfl example : VertexDesc.rowPorts (.inl [3, 5]) [true] = 0 := rfl -- A table entry is a constant in `A_p`. -example : GaloisRingArith.val 3 [1, 1] (VertexDesc.entry (.inl [3, 5]) [true]) = +example : GaloisRingArith.val 3 [1, 1] (VertexDesc.entry tableEntry (.inl [3, 5]) [true]) = ((5 : ℕ) : GaloisRingArith.Ring 3 [1, 1]) := VertexDesc.val_entry_inl 3 [1, 1] [3, 5] [true] @@ -52,13 +53,23 @@ def ctx : PacketCtx := ⟨3, [1, 1], 1, 2, 0, 2, 1, 2, true, false, true, [], [0, 1]⟩ /-- The descriptor: a row port in slot `0` and a column port in slot `1`, zero exponents. -/ -def desc : VertexDesc := .inr (ctx, [(true, 0), (false, 1)], [0, 0, 0, 0]) +def desc : VertexDesc (List ℕ) := .inr (ctx, [(true, 0), (false, 1)], [0, 0, 0, 0]) -- The column ports are read from the tags and the bits: the entry is `W_1(T) = 5 + 2 U`. -example : VertexDesc.entry desc [true, true] = [5, 2] := by decide +example : VertexDesc.entry tableEntry desc [true, true] = [5, 2] := by decide example : VertexDesc.rowPorts desc [true, true] = 1 := by decide +/-! ### Other root descriptors -/ + +-- A root descriptor of any type is read by its entry procedure, here a number read as the +-- coefficient list `[n, 1]`. +example : VertexDesc.entry (fun (n : ℕ) _ => [n, 1]) (.inl 7) [true] = [7, 1] := rfl + +-- A packet descriptor reads the same entry whatever the type of the root descriptors. +example : VertexDesc.entry (fun (n : ℕ) _ => [n]) + (.inr (ctx, [(true, 0), (false, 1)], [0, 0, 0, 0])) [true, true] = [5, 2] := by decide + /-! ### Tagged ports -/ example : sidePorts [(true, 3), (false, 1), (true, 2)] [true, false, false] true = @@ -75,12 +86,14 @@ example : sidePorts ([4, 1, 2].map fun c => (decide (c % 2 = 0), c)) ([4, 1, 2]. /-! ### Resources -/ -example : ∃ K : ℕ, ∀ (q : VertexDesc × List Bool) (Rv : ℕ), q.1.ReducedLE Rv → +example : ∃ K : ℕ, ∀ (q : VertexDesc (List ℕ) × List Bool) (Rv : ℕ), q.1.ReducedLE Rv → VertexDesc.entryCertificate.time q ≤ K * (q.1.modes + 2) ^ q.1.rowPorts q.2 * - ((Turing.MultiTapeTM.encPair VertexDesc.enc Turing.MultiTapeTM.encBits q).length + + ((Turing.MultiTapeTM.encPair (VertexDesc.enc (encList encNat)) Turing.MultiTapeTM.encBits + q).length + q.1.modes + Rv + 2) ^ K ∧ VertexDesc.entryCertificate.space q ≤ - K * ((Turing.MultiTapeTM.encPair VertexDesc.enc Turing.MultiTapeTM.encBits q).length + + K * ((Turing.MultiTapeTM.encPair (VertexDesc.enc (encList encNat)) + Turing.MultiTapeTM.encBits q).length + q.1.modes + Rv + 2) ^ K := VertexDesc.entryCertificate_le diff --git a/ComplexityTests/FastContractionAnalysis.lean b/ComplexityTests/FastContractionAnalysis.lean index 29eb99127..10ad24c52 100644 --- a/ComplexityTests/FastContractionAnalysis.lean +++ b/ComplexityTests/FastContractionAnalysis.lean @@ -22,11 +22,11 @@ def tiny : ℕ × ExplicitTensorNetwork ℕ := (1, ⟨1, [([0], [1, 2]), ([0], [ example : fastGuard tiny = true := by decide /-- The root of `tiny` at precision `3`. -/ -abbrev tinyRoot : Call := root (ExplicitTensorNetwork.capPrecision (3, tiny)) +abbrev tinyRoot : Call (List ℕ) := root (ExplicitTensorNetwork.capPrecision (3, tiny)) -- The root is reached, and it is the only reached call at depth `0`. example : Reach nativeMk tinyRoot tinyRoot := .root -example (x : Call) (hx : Reach nativeMk tinyRoot x) (h0 : x.depth = 0) : x = tinyRoot := +example (x : Call (List ℕ)) (hx : Reach nativeMk tinyRoot x) (h0 : x.depth = 0) : x = tinyRoot := hx.eq_root_of_depth_le (by rw [h0]; rfl) -- The root is a leaf, so its derivation has one node and no open call. @@ -41,8 +41,8 @@ example : OnSchedule 3 tiny.2.numEdges tinyRoot := onSchedule_root_capPrecision (by decide) (by norm_num) (by decide) -- Values are reduced at their precision: at most `e` coordinates below `2 ^ p`. -example : ReducedAt tinyRoot.prec tinyRoot.fl (value nativeMk tinyRoot) := - reducedAt_value nativeMk tinyRoot +example : ReducedAt tinyRoot.prec tinyRoot.fl (value tableEntry nativeMk tinyRoot) := + reducedAt_value tableEntry nativeMk tinyRoot -- The modulus at `m = 1` has `2 ⬝ 3 ^ 1 = 6` coefficients, within `32 (m + 1) ^ 2`. example : (modulus 1).length = 6 := by decide @@ -55,7 +55,7 @@ example (N : ℕ) (hN : N ≤ 2 ^ ((245760 * (50 / 100 + 1) + 37) * 100 / Nat.sq two_mul_sub_one_le_fuel (D := 1) (by norm_num) (by norm_num) hN -- A child of a parent with `M` edges under (D.6) has at most `M / 16` edges. -example {r a i Δ : ℕ} {D : DescribedNetwork VertexDesc} (hD : D.IsRowsFirstBipartite r) +example {r a i Δ : ℕ} {D : DescribedNetwork (VertexDesc (List ℕ))} (hD : D.IsRowsFirstBipartite r) (hK : 64 ^ a ≤ D.numEdges) (hia : i < a) (hdeg : ∀ v ∈ D.vertices, v.1.length ≤ Δ) (hM : 2 * Δ * (64 ^ (2 * a)) ^ 2 ≤ D.numEdges) (fl : List ℕ) (pt : ℕ) (t : ℤ) (ζ β : List ℕ) (g : Fin 64) : diff --git a/ComplexityTests/FastContractionLeaf.lean b/ComplexityTests/FastContractionLeaf.lean index 5a2370278..dea272a33 100644 --- a/ComplexityTests/FastContractionLeaf.lean +++ b/ComplexityTests/FastContractionLeaf.lean @@ -53,10 +53,11 @@ def ctx : PacketCtx where ζ := [0] /-- A packet vertex with a row port in slot `0` and a column port in slot `1`. -/ -def packetVertex : List ℕ × VertexDesc := ([0, 1], .inr (ctx, [(true, 0), (false, 1)], [0, 0])) +def packetVertex : List ℕ × VertexDesc (List ℕ) := + ([0, 1], .inr (ctx, [(true, 0), (false, 1)], [0, 0])) /-- A call at scale `4` and precision `1` whose network is the packet vertex alone. -/ -def packetCall : Call := ((4, 1, 3, 1, [1], 0), ⟨2, [packetVertex]⟩) +def packetCall : Call (List ℕ) := ((4, 1, 3, 1, [1], 0), ⟨2, [packetVertex]⟩) -- The packet vertex has one row port, and at most `2 ⬝ 1` target modes. example : packetVertex.2.rowPorts [true, false] = 1 := by decide diff --git a/ComplexityTests/FastContractionPolyTime.lean b/ComplexityTests/FastContractionPolyTime.lean index 2b8c3ca97..b266ee102 100644 --- a/ComplexityTests/FastContractionPolyTime.lean +++ b/ComplexityTests/FastContractionPolyTime.lean @@ -32,15 +32,18 @@ example : (packing (root (3, 1, tiny))).2.1 ≤ NativeChild.numPackets_nativeParentPacking_le _ _ _ -- On every call, `2 ^ a ≤ s + 1`, and the levels are at most `a + 1`. -example (x : Call) : 2 ^ slots x ≤ x.scale + 1 := two_pow_slots_le x -example (x : Call) (k : ℕ) : level x k ≤ slots x + 1 := level_le x k +example {T : Type} (x : Call T) : 2 ^ slots x ≤ x.scale + 1 := two_pow_slots_le x +example {T : Type} (x : Call T) (k : ℕ) : level x k ≤ slots x + 1 := level_le x k -- The cap on the exponents leaves the tuples of weight below the budget unchanged. example : ([1, 0, 1] : List ℕ).map (min · 3) = [1, 0, 1] := map_min_of_mem_budgetTuples (ws := [1, 1, 1]) (by decide) (by decide) --- The components of the scheme of the native child builder are polynomial-time. -example : (scheme nativeMk).PolyTime encCall encFrame encValue := scheme_nativeMk_polyTime +-- The components of the scheme of the native child builder are polynomial-time, for every type +-- of root descriptors and every entry procedure. +example {T : Type} (encT : T ↪ List Bool) (ev : T → List Bool → List ℕ) : + (scheme ev (nativeMk (T := T))).PolyTime (encCall encT) encFrame encValue := + scheme_nativeMk_polyTime ev -- The contraction interface for admissible explicit networks, from the resource analysis alone. noncomputable example (hana : FastAnalysis nativeMk) : diff --git a/ComplexityTests/FastLeaves.lean b/ComplexityTests/FastLeaves.lean index 2e205e997..e241e2c01 100644 --- a/ComplexityTests/FastLeaves.lean +++ b/ComplexityTests/FastLeaves.lean @@ -28,7 +28,7 @@ example : WF (root (ExplicitTensorNetwork.capPrecision (1, pair))) ∧ (Reach.root (mk := nativeMk)).wf_packetShape (wf_root 1 (by decide)) (packetShape_root _) -- Reached calls have at most twice the scale in edges, on every input. -example (P : ℕ) (G : ℕ × ExplicitTensorNetwork ℕ) (x : Call) +example (P : ℕ) (G : ℕ × ExplicitTensorNetwork ℕ) (x : Call (List ℕ)) (hx : Reach nativeMk (root (ExplicitTensorNetwork.capPrecision (P, G))) x) : x.edges ≤ 2 * x.scale := hx.edges_le_two_mul_scale rfl rfl From 4fb48d210d80ef9774de0bf6ef860ca1f5a2b3cf Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 10:39:43 -0400 Subject: [PATCH 11/20] feat(Frontier/TensorNetwork): leaf certificate and leaf bound for any entry procedure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `VertexDesc.entryCertificate ce` evaluates every descriptor from a native certificate `ce` of the roots' entry procedure (option on `getLeft?`), and `entryCertificate_le` adds the root's time and space. `leafCertificate ce`, `leafCertificate_le ce` (time `K (n + R + ES + 1) ^ K 2 ^ M ((R + 2) ^ Λ + E)`) and `leafCertificate_le_of_packetShape ce` follow; tables are `tableEntryCertificate`, whose polynomial cost gives back the previous table bound. Second PR of #1538 milestone E1.2. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG --- .../TensorNetwork/FastContractionLeaf.lean | 417 +++++++++++------- .../TensorNetwork/FastContractionMachine.lean | 60 ++- .../Frontier/TensorNetwork/VertexDesc.lean | 346 ++++++++------- .../CountingSimulation/FastAlgorithm.lean | 5 +- .../CountingSimulation/FastAnalysis.lean | 4 +- .../Frontier/TensorNetworkVertexDesc.lean | 28 +- 6 files changed, 523 insertions(+), 337 deletions(-) diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionLeaf.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionLeaf.lean index 46dd54e3e..85f43339c 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionLeaf.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionLeaf.lean @@ -17,17 +17,22 @@ import Complexity.Computability.Machines.Turing.MultiTape.Encodings.Length # The leaves of the fast contraction algorithm The cost of the leaves of the native recursion of Theorem D.1 of [OpenAI2026ETH] -(`Cslib.Circuits.Frontier.FastContraction.leafCertificate`, over tables), the leaf clause of the -resource analysis `Cslib.Complexity.CountingSimulation.FastAnalysis`. A leaf sums directly over the -`2 ^ M` edge assignments of a call with `M` edges (§D.4.7, p. 64), and the entry of a packet vertex -costs `(m + 2) ^ L` for `m` target modes and `L` row ports, the source's `exp(O(L log s))` -(§D.4.6, p. 63). +(`Cslib.Circuits.Frontier.FastContraction.leafCertificate ce`, for a native certificate `ce` of the +entry procedure of the roots), the leaf clause of the resource analysis +`Cslib.Complexity.CountingSimulation.FastAnalysis`. A leaf sums directly over the `2 ^ M` edge +assignments of a call with `M` edges, with polynomially many entry evaluations each (§D.4.7, +p. 64). The entry of a packet vertex costs `(m + 2) ^ L` for `m` target modes and `L` row ports, +the source's `exp(O(L log s))` (§D.4.6, p. 63), and the entry of a root costs what `ce` costs. **The cost of a leaf** (`FastContraction.leafCertificate_le`): with at most `R` target modes and -`Λ` row ports per vertex, time `K (n + R + 1) ^ K 2 ^ M (R + 2) ^ Λ` and space `K (n + R + 1) ^ K` -on a call of encoded length `n`, from the bounds of direct summation +`Λ` row ports per vertex, and roots costing time at most `E` and space at most `ES` in `ce`, time +`K (n + R + ES + 1) ^ K 2 ^ M ((R + 2) ^ Λ + E)` and space `K (n + R + ES + 1) ^ K` on a call of +encoded length `n`, from the bounds of direct summation (`DescribedNetwork.contractionCertificate_le`) and of the evaluator of descriptors -(`VertexDesc.entryCertificate_le`). +(`VertexDesc.entryCertificate_le`). A root's output is at most a constant times `ES + 1` long, +since a native certificate charges its output to its space bound. For tables the root costs are +polynomial, which gives time `K (n + 1) ^ K 2 ^ M (A p + 2) ^ A` with the packet shape +(`FastContraction.leafCertificate_tableEntry_le_of_packetShape`). **The packet shape** (`FastContraction.PacketShape`). Every packet vertex of a call of the recursion has `i < a ≤ ⌊log₂ s⌋ / 32768`, `2 ^ (i + 1)` tiles, at most `p` exponents per tile, and @@ -54,8 +59,9 @@ but a polynomial in `n` is a constant. * `Cslib.Circuits.Frontier.FastContraction.packetShape_root`, `Cslib.Circuits.Frontier.FastContraction.packetShape_child`: the packet shape on the reached calls. -* `Cslib.Circuits.Frontier.FastContraction.leafCertificate_le_of_packetShape`: the cost of a leaf - with the packet shape. +* `Cslib.Circuits.Frontier.FastContraction.leafCertificate_le_of_packetShape`, + `Cslib.Circuits.Frontier.FastContraction.leafCertificate_tableEntry_le_of_packetShape`: the cost + of a leaf with the packet shape, and over tables. * `Cslib.Circuits.Frontier.FastContraction.exists_leafCertificate_le`: the leaf bound of the resource analysis. @@ -185,18 +191,21 @@ private theorem zb_le {W n R Rv cR E₀ : ℕ} (hW : 1 ≤ W) (hE : 1 ≤ E₀) omega /-- The arithmetic of the time of a leaf. -/ -private theorem time_assemble {Td Ti Ts cd dd ci di P X k W A Zb c₁ c₂ E₀ K₁ K₂ : ℕ} +private theorem time_assemble {Td Ti Ts cd dd ci di P X E k W A Zb c₁ c₂ E₀ K₁ K₂ : ℕ} (hW : 1 ≤ W) (hP : 1 ≤ P) (hX : 1 ≤ X) (hd : Td ≤ cd * W ^ dd) (hi : Ti ≤ ci * W ^ di) - (hs : Ts ≤ (P * (k + 1) + 1) * (K₁ * (A + 1) ^ K₁ + 2 * (K₂ * X * Zb ^ K₂))) + (hs : Ts ≤ (P * (k + 1) + 1) * (K₁ * (A + 1) ^ K₁ + 2 * (K₂ * X * Zb ^ K₂ + E))) (hk : k + 1 ≤ W) (hA : A + 1 ≤ c₁ * W ^ E₀) (hZ : Zb ≤ c₂ * W ^ E₀) : - Td + (Ti + Ts) ≤ (2 * (K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂)) + cd + ci) * - W ^ (1 + E₀ * (K₁ + K₂) + dd + di) * P * X := by + Td + (Ti + Ts) ≤ (2 * (K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂) + 2) + cd + ci) * + W ^ (1 + E₀ * (K₁ + K₂) + dd + di) * P * (X + E) := by have hWF1 : W ^ (E₀ * K₁) ≤ W ^ (E₀ * (K₁ + K₂)) := Nat.pow_le_pow_right hW (by rw [Nat.mul_add]; omega) have hWF2 : W ^ (E₀ * K₂) ≤ W ^ (E₀ * (K₁ + K₂)) := Nat.pow_le_pow_right hW (by rw [Nat.mul_add]; omega) set F := E₀ * (K₁ + K₂) set S := W ^ (1 + F + dd + di) + set Y := X + E with hY + have hY1 : 1 ≤ Y := by omega + have hF1 : 1 ≤ W ^ F := Nat.one_le_pow _ _ (by omega) have hA' : K₁ * (A + 1) ^ K₁ ≤ K₁ * c₁ ^ K₁ * W ^ F := calc K₁ * (A + 1) ^ K₁ ≤ K₁ * (c₁ * W ^ E₀) ^ K₁ := Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hA _) @@ -207,124 +216,138 @@ private theorem time_assemble {Td Ti Ts cd dd ci di P X k W A Zb c₁ c₂ E₀ Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hZ _) _ = K₂ * c₂ ^ K₂ * X * W ^ (E₀ * K₂) := by rw [mul_pow, ← pow_mul]; ring _ ≤ K₂ * c₂ ^ K₂ * X * W ^ F := Nat.mul_le_mul_left _ hWF2 - have hin : K₁ * (A + 1) ^ K₁ + 2 * (K₂ * X * Zb ^ K₂) ≤ - (K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂)) * X * W ^ F := by - have : K₁ * c₁ ^ K₁ * W ^ F ≤ K₁ * c₁ ^ K₁ * W ^ F * X := Nat.le_mul_of_pos_right _ hX - have e : (K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂)) * X * W ^ F = - K₁ * c₁ ^ K₁ * W ^ F * X + 2 * (K₂ * c₂ ^ K₂ * X * W ^ F) := by ring + have hin : K₁ * (A + 1) ^ K₁ + 2 * (K₂ * X * Zb ^ K₂ + E) ≤ + (K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂) + 2) * Y * W ^ F := by + have h1 : K₁ * c₁ ^ K₁ * W ^ F ≤ K₁ * c₁ ^ K₁ * W ^ F * Y := Nat.le_mul_of_pos_right _ hY1 + have h2 : K₂ * c₂ ^ K₂ * X * W ^ F ≤ K₂ * c₂ ^ K₂ * Y * W ^ F := + Nat.mul_le_mul_right _ (Nat.mul_le_mul_left _ (by omega)) + have h3 : E ≤ Y * W ^ F := (show E ≤ Y by omega).trans (Nat.le_mul_of_pos_right _ hF1) + have e : (K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂) + 2) * Y * W ^ F = + K₁ * c₁ ^ K₁ * W ^ F * Y + 2 * (K₂ * c₂ ^ K₂ * Y * W ^ F) + 2 * (Y * W ^ F) := by ring omega have hPk : P * (k + 1) + 1 ≤ 2 * P * W := by have : P * (k + 1) ≤ P * W := Nat.mul_le_mul_left _ hk have : 1 ≤ P * W := Nat.one_le_iff_ne_zero.mpr (by positivity) rw [Nat.mul_assoc]; omega - have hs' : Ts ≤ 2 * (K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂)) * S * P * X := - calc Ts ≤ (2 * P * W) * ((K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂)) * X * W ^ F) := + have hs' : Ts ≤ 2 * (K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂) + 2) * S * P * Y := + calc Ts ≤ (2 * P * W) * ((K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂) + 2) * Y * W ^ F) := hs.trans (Nat.mul_le_mul hPk hin) - _ = 2 * (K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂)) * W ^ (1 + F) * P * X := by + _ = 2 * (K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂) + 2) * W ^ (1 + F) * P * Y := by rw [pow_add, pow_one]; ring - _ ≤ 2 * (K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂)) * S * P * X := + _ ≤ 2 * (K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂) + 2) * S * P * Y := Nat.mul_le_mul_right _ (Nat.mul_le_mul_right _ (Nat.mul_le_mul_left _ (Nat.pow_le_pow_right hW (by omega)))) - have hPX : 1 ≤ P * X := Nat.one_le_iff_ne_zero.mpr (by positivity) - have hd' : Td ≤ cd * S * P * X := + have hPY : 1 ≤ P * Y := Nat.one_le_iff_ne_zero.mpr (by positivity) + have hd' : Td ≤ cd * S * P * Y := calc Td ≤ cd * S := hd.trans (mul_pow_le_mul_pow hW (by omega)) - _ ≤ cd * S * (P * X) := Nat.le_mul_of_pos_right _ hPX - _ = cd * S * P * X := by ring - have hi' : Ti ≤ ci * S * P * X := + _ ≤ cd * S * (P * Y) := Nat.le_mul_of_pos_right _ hPY + _ = cd * S * P * Y := by ring + have hi' : Ti ≤ ci * S * P * Y := calc Ti ≤ ci * S := hi.trans (mul_pow_le_mul_pow hW (by omega)) - _ ≤ ci * S * (P * X) := Nat.le_mul_of_pos_right _ hPX - _ = ci * S * P * X := by ring - have e : (2 * (K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂)) + cd + ci) * S * P * X = - 2 * (K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂)) * S * P * X + cd * S * P * X + ci * S * P * X := by + _ ≤ ci * S * (P * Y) := Nat.le_mul_of_pos_right _ hPY + _ = ci * S * P * Y := by ring + have e : (2 * (K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂) + 2) + cd + ci) * S * P * Y = + 2 * (K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂) + 2) * S * P * Y + cd * S * P * Y + + ci * S * P * Y := by ring omega /-- The arithmetic of the space of a leaf. -/ -private theorem space_assemble {Sd Si Ss cd dd ci di W A Zb c₁ c₂ E₀ K₁ K₂ ES : ℕ} +private theorem space_assemble {Sd Si Ss cd dd ci di W A Zb c₁ c₂ E₀ K₁ K₂ ES ES' : ℕ} (hW : 1 ≤ W) (hd : Sd ≤ cd * W ^ dd) (hi : Si ≤ ci * W ^ di) - (hs : Ss ≤ K₁ * (A + 1) ^ K₁ + ES) (hA : A + 1 ≤ c₁ * W ^ E₀) (hES : ES = K₂ * Zb ^ K₂) - (hZ : Zb ≤ c₂ * W ^ E₀) : - Sd + (Si + Ss) ≤ (K₁ * c₁ ^ K₁ + K₂ * c₂ ^ K₂ + cd + ci) * - W ^ (E₀ * (K₁ + K₂) + dd + di) := by - have hWF1 : W ^ (E₀ * K₁) ≤ W ^ (E₀ * (K₁ + K₂) + dd + di) := + (hs : Ss ≤ K₁ * (A + 1) ^ K₁ + ES') (hA : A + 1 ≤ c₁ * W ^ E₀) + (hES : ES' = K₂ * Zb ^ K₂ + ES) (hESW : ES ≤ W) (hZ : Zb ≤ c₂ * W ^ E₀) : + Sd + (Si + Ss) ≤ (K₁ * c₁ ^ K₁ + K₂ * c₂ ^ K₂ + cd + ci + 1) * + W ^ (1 + E₀ * (K₁ + K₂) + dd + di) := by + have hWF1 : W ^ (E₀ * K₁) ≤ W ^ (1 + E₀ * (K₁ + K₂) + dd + di) := Nat.pow_le_pow_right hW (by rw [Nat.mul_add]; omega) - have hWF2 : W ^ (E₀ * K₂) ≤ W ^ (E₀ * (K₁ + K₂) + dd + di) := + have hWF2 : W ^ (E₀ * K₂) ≤ W ^ (1 + E₀ * (K₁ + K₂) + dd + di) := Nat.pow_le_pow_right hW (by rw [Nat.mul_add]; omega) set F := E₀ * (K₁ + K₂) - set S := W ^ (F + dd + di) + set S := W ^ (1 + F + dd + di) have hA' : K₁ * (A + 1) ^ K₁ ≤ K₁ * c₁ ^ K₁ * S := calc K₁ * (A + 1) ^ K₁ ≤ K₁ * (c₁ * W ^ E₀) ^ K₁ := Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hA _) _ = K₁ * c₁ ^ K₁ * W ^ (E₀ * K₁) := by rw [mul_pow, ← pow_mul, Nat.mul_assoc] _ ≤ K₁ * c₁ ^ K₁ * S := Nat.mul_le_mul_left _ hWF1 - have hZ' : ES ≤ K₂ * c₂ ^ K₂ * S := - calc ES = K₂ * Zb ^ K₂ := hES - _ ≤ K₂ * (c₂ * W ^ E₀) ^ K₂ := Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hZ _) + have hZ' : K₂ * Zb ^ K₂ ≤ K₂ * c₂ ^ K₂ * S := + calc K₂ * Zb ^ K₂ ≤ K₂ * (c₂ * W ^ E₀) ^ K₂ := Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hZ _) _ = K₂ * c₂ ^ K₂ * W ^ (E₀ * K₂) := by rw [mul_pow, ← pow_mul, Nat.mul_assoc] _ ≤ K₂ * c₂ ^ K₂ * S := Nat.mul_le_mul_left _ hWF2 + have hWS : ES ≤ S := + hESW.trans ((pow_one W).symm.le.trans (Nat.pow_le_pow_right hW (by omega))) have hd' : Sd ≤ cd * S := hd.trans (mul_pow_le_mul_pow hW (by omega)) have hi' : Si ≤ ci * S := hi.trans (mul_pow_le_mul_pow hW (by omega)) - have e : (K₁ * c₁ ^ K₁ + K₂ * c₂ ^ K₂ + cd + ci) * S = - K₁ * c₁ ^ K₁ * S + K₂ * c₂ ^ K₂ * S + cd * S + ci * S := by ring + have e : (K₁ * c₁ ^ K₁ + K₂ * c₂ ^ K₂ + cd + ci + 1) * S = + K₁ * c₁ ^ K₁ * S + K₂ * c₂ ^ K₂ * S + cd * S + ci * S + S := by ring omega -/-- **The cost of a leaf.** There is `K` such that, on a call of encoded length `n` with `M` edges -whose vertices have at most `R` target modes and at most `Λ` row ports on every bit list on their -ports, direct summation takes time at most `K (n + R + 1) ^ K 2 ^ M (R + 2) ^ Λ` and space at most -`K (n + R + 1) ^ K`, whatever the child builder. -/ -theorem leafCertificate_le : ∃ K : ℕ, - ∀ (mk : Call (List ℕ) → State → ℕ × DescribedNetwork (VertexDesc (List ℕ))) - (x : Call (List ℕ)) (R Λ : ℕ), - (∀ v ∈ x.net.vertices, v.2.modes ≤ R ∧ - ∀ bs : List Bool, bs.length = v.1.length → v.2.rowPorts bs ≤ Λ) → - (leafCertificate mk).time x ≤ - K * ((encCall (encList encNat) x).length + R + 1) ^ K * 2 ^ x.edges * (R + 2) ^ Λ ∧ - (leafCertificate mk).space x ≤ K * ((encCall (encList encNat) x).length + R + 1) ^ K := by +variable {encT : T ↪ List Bool} {ev : T → List Bool → List ℕ} + +/-- **The cost of a leaf.** For a native certificate `ce` of the entry procedure of the roots, there +is `K` such that, on a call of encoded length `n` with `M` edges whose vertices have at most `R` +target modes and at most `Λ` row ports on every bit list on their ports, and whose roots take time +at most `E` and space at most `ES` in `ce` on every bit list on their ports, direct summation takes +time at most `K (n + R + ES + 1) ^ K 2 ^ M ((R + 2) ^ Λ + E)` and space at most +`K (n + R + ES + 1) ^ K`, whatever the child builder. -/ +theorem leafCertificate_le + (ce : NativeCertificate (fun q : T × List Bool => ev q.1 q.2) (encPair encT encBits) + (encList encNat)) : + ∃ K : ℕ, ∀ (mk : Call T → State → ℕ × DescribedNetwork (VertexDesc T)) (x : Call T) + (R Λ E ES : ℕ), + (∀ v ∈ x.net.vertices, v.2.modes ≤ R ∧ + ∀ bs : List Bool, bs.length = v.1.length → v.2.rowPorts bs ≤ Λ) → + (∀ v ∈ x.net.vertices, ∀ t, v.2 = .inl t → ∀ bs : List Bool, bs.length = v.1.length → + ce.time (t, bs) ≤ E ∧ ce.space (t, bs) ≤ ES) → + (leafCertificate ce mk).time x ≤ + K * ((encCall encT x).length + R + ES + 1) ^ K * 2 ^ x.edges * ((R + 2) ^ Λ + E) ∧ + (leafCertificate ce mk).space x ≤ K * ((encCall encT x).length + R + ES + 1) ^ K := by obtain ⟨K₁, hK₁⟩ := DescribedNetwork.contractionCertificate_le (ops := SumOps.galois) - (eval := VertexDesc.entry tableEntry) (encQ := encPair encUnary (encList encNat)) - (encY := encList encNat) (encT := VertexDesc.enc (encList encNat)) SumOps.galois_polyTime - VertexDesc.entryCertificate - obtain ⟨K₂, hK₂⟩ := VertexDesc.entryCertificate_le - have hD := NativeCertificate.ofPolyTime_isPolynomial (depth_polyTime (encList encNat)) - have hI := NativeCertificate.ofPolyTime_isPolynomial (leafInput_polyTime (encList encNat)) + (eval := VertexDesc.entry ev) (encQ := encPair encUnary (encList encNat)) + (encY := encList encNat) (encT := VertexDesc.enc encT) SumOps.galois_polyTime + (VertexDesc.entryCertificate ce) + obtain ⟨K₂, hK₂⟩ := VertexDesc.entryCertificate_le ce + obtain ⟨cE, -, hcE⟩ := ce.computes + have hD := NativeCertificate.ofPolyTime_isPolynomial (depth_polyTime encT) + have hI := NativeCertificate.ofPolyTime_isPolynomial (leafInput_polyTime encT) obtain ⟨cd, dd, hdt⟩ := hD.1.exists_le obtain ⟨cd', dd', hds⟩ := hD.2.exists_le obtain ⟨ci, di, hit⟩ := hI.1.exists_le obtain ⟨ci', di', his⟩ := hI.2.exists_le - obtain ⟨cl, dl, hl⟩ := (leafInput_polyTime (encList encNat)).polyBounded_length.exists_le + obtain ⟨cl, dl, hl⟩ := (leafInput_polyTime encT).polyBounded_length.exists_le obtain ⟨cp, dp, hp⟩ := PacketCtx.p_polyTime.polyBounded_length.exists_le obtain ⟨cf, df, hf⟩ := PacketCtx.fl_polyTime.polyBounded_length.exists_le - obtain ⟨ct, dt, ht⟩ := VertexDesc.tableEntry_polyTime.polyBounded_length.exists_le -- The constants. - obtain ⟨e, he⟩ : ∃ e, e = 2 + df + dp + dt := ⟨_, rfl⟩ - obtain ⟨cR, hcR⟩ : ∃ cR, cR = 5 + cf * (2 * cp + 3) + ct * 3 ^ dt := ⟨_, rfl⟩ + obtain ⟨e, he⟩ : ∃ e, e = 2 + df + dp + 0 := ⟨_, rfl⟩ + obtain ⟨cR, hcR⟩ : ∃ cR, cR = 5 + cf * (2 * cp + 3) + 0 * 3 ^ 0 + cE := ⟨_, rfl⟩ obtain ⟨E₀, hE₀⟩ : ∃ E₀, E₀ = dl + e := ⟨_, rfl⟩ obtain ⟨c₁, hc₁⟩ : ∃ c₁, c₁ = cl + 2 * cR + 1 := ⟨_, rfl⟩ obtain ⟨c₂, hc₂⟩ : ∃ c₂, c₂ = 3 + cR := ⟨_, rfl⟩ - obtain ⟨G, hG⟩ : ∃ G, G = 2 * (K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂)) + cd + ci + - (K₁ * c₁ ^ K₁ + K₂ * c₂ ^ K₂) + cd' + ci' := ⟨_, rfl⟩ + obtain ⟨G, hG⟩ : ∃ G, G = 2 * (K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂) + 2) + cd + ci + + (K₁ * c₁ ^ K₁ + K₂ * c₂ ^ K₂ + cd' + ci' + 1) := ⟨_, rfl⟩ obtain ⟨Dg, hDg⟩ : ∃ Dg, Dg = 1 + E₀ * (K₁ + K₂) + dd + di + dd' + di' := ⟨_, rfl⟩ - refine ⟨G + Dg, fun mk x R Λ hRΛ => ?_⟩ - obtain ⟨n, hn⟩ : ∃ n, n = (encCall (encList encNat) x).length := ⟨_, rfl⟩ - obtain ⟨W, hW⟩ : ∃ W, W = n + R + 1 := ⟨_, rfl⟩ - rw [← hn, show n + R + 1 = W from hW.symm] + refine ⟨G + Dg, fun mk x R Λ E ES hRΛ hroot => ?_⟩ + obtain ⟨n, hn⟩ : ∃ n, n = (encCall encT x).length := ⟨_, rfl⟩ + obtain ⟨W, hW⟩ : ∃ W, W = n + R + ES + 1 := ⟨_, rfl⟩ + rw [← hn, show n + R + ES + 1 = W from hW.symm] have hW1 : 1 ≤ W := by omega have hnW : n + 1 ≤ W := by omega -- The precision and the modulus of the call. - have hpfl := scale_add_prec_add_length_fl_le (encList encNat) x + have hpfl := scale_add_prec_add_length_fl_le encT x rw [← hn] at hpfl -- Every vertex and bit list on its ports is at most `3 n + 1` long. - have hq (v : List ℕ × VertexDesc (List ℕ)) (hv : v ∈ x.net.vertices) (bs : List Bool) + have hq (v : List ℕ × VertexDesc T) (hv : v ∈ x.net.vertices) (bs : List Bool) (hbs : bs.length = v.1.length) : - (encPair (VertexDesc.enc (encList encNat)) encBits (v.2, bs)).length ≤ 3 * n + 1 := by - have h1 := length_vertex_le (encList encNat) hv + (encPair (VertexDesc.enc encT) encBits (v.2, bs)).length ≤ 3 * n + 1 := by + have h1 := length_vertex_le encT hv have h2 := length_le_length_encList encNat v.1 rw [length_encPair] at h1 ⊢ - change 2 * (VertexDesc.enc (encList encNat) v.2).length + 1 + bs.length ≤ 3 * n + 1 + change 2 * (VertexDesc.enc encT v.2).length + 1 + bs.length ≤ 3 * n + 1 omega - -- The reduced coefficient lists. + -- The reduced coefficient lists, and the outputs of the roots. obtain ⟨Rv, hRv⟩ : ∃ Rv, Rv = n * (2 * n + 3) + - cf * (n + 1) ^ df * (2 * (cp * (n + 1) ^ dp) + 3) + ct * (3 * n + 2) ^ dt := ⟨_, rfl⟩ + cf * (n + 1) ^ df * (2 * (cp * (n + 1) ^ dp) + 3) + 0 * (3 * n + 2) ^ 0 := ⟨_, rfl⟩ + obtain ⟨Ev, hEv⟩ : ∃ Ev, Ev = Rv + cE * (ES + 1) := ⟨_, rfl⟩ have hred : ∀ y, SumOps.galois.Reduced (x.prec, x.fl) y → (encList encNat y).length ≤ Rv := by intro y hy have h := SumOps.length_encList_le_of_galois_reduced hy @@ -332,13 +355,13 @@ theorem leafCertificate_le : ∃ K : ℕ, have : x.fl.length * (2 * x.prec + 3) ≤ n * (2 * n + 3) := Nat.mul_le_mul (by omega) (by omega) omega - have hpacket (v : List ℕ × VertexDesc (List ℕ)) (hv : v ∈ x.net.vertices) (d : PacketDesc) + have hpacket (v : List ℕ × VertexDesc T) (hv : v ∈ x.net.vertices) (d : PacketDesc) (hd : v.2 = .inr d) : ∀ y, SumOps.galois.Reduced (d.1.p, d.1.fl) y → (encList encNat y).length ≤ Rv := by intro y hy have h := SumOps.length_encList_le_of_galois_reduced hy simp only at h - have h1 := length_vertex_le (encList encNat) hv + have h1 := length_vertex_le encT hv rw [length_encPair, hd, length_encSum] at h1 simp only [Sum.elim_inr] at h1 have h2 : (PacketCtx.enc d.1).length ≤ n := by @@ -359,9 +382,9 @@ theorem leafCertificate_le : ∃ K : ℕ, obtain ⟨Zb, hZb⟩ : ∃ Zb, Zb = 3 * n + R + Rv + 3 := ⟨_, rfl⟩ have hentry : ∀ v ∈ ((x.prec, x.fl), x.net).2.vertices, ∀ bs : List Bool, bs.length = v.1.length → - VertexDesc.entryCertificate.time (v.2, bs) ≤ K₂ * (R + 2) ^ Λ * Zb ^ K₂ ∧ - VertexDesc.entryCertificate.space (v.2, bs) ≤ K₂ * Zb ^ K₂ ∧ - (encList encNat (VertexDesc.entry tableEntry v.2 bs)).length ≤ Rv := by + (VertexDesc.entryCertificate ce).time (v.2, bs) ≤ K₂ * (R + 2) ^ Λ * Zb ^ K₂ + E ∧ + (VertexDesc.entryCertificate ce).space (v.2, bs) ≤ K₂ * Zb ^ K₂ + ES ∧ + (encList encNat (VertexDesc.entry ev v.2 bs)).length ≤ Ev := by intro v hv bs hbs have hlen := hq v hv bs hbs obtain ⟨hmodes, hrows⟩ := hRΛ v hv @@ -370,45 +393,57 @@ theorem leafCertificate_le : ∃ K : ℕ, rcases hd : v.2 with t | d · trivial · exact hpacket v hv d hd - obtain ⟨hT, hS⟩ := hK₂ (v.2, bs) Rv hRLE + obtain ⟨hT, hS⟩ := hK₂ (v.2, bs) Rv E ES hRLE fun t ht => hroot v hv t ht bs hbs dsimp only at hT hS - have hZ : (encPair (VertexDesc.enc (encList encNat)) encBits (v.2, bs)).length + v.2.modes + - Rv + 2 ≤ Zb := by + have hZ : (encPair (VertexDesc.enc encT) encBits (v.2, bs)).length + v.2.modes + Rv + 2 ≤ + Zb := by omega - refine ⟨hT.trans ?_, hS.trans (Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hZ _)), ?_⟩ + refine ⟨hT.trans (Nat.add_le_add_right ?_ _), + hS.trans (Nat.add_le_add_right (Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hZ _)) _), ?_⟩ · refine Nat.mul_le_mul (Nat.mul_le_mul_left _ ?_) (Nat.pow_le_pow_left hZ _) exact (Nat.pow_le_pow_left (by omega) _).trans (Nat.pow_le_pow_right (by omega) hrows) · rcases hd : v.2 with t | d - · have := ht (v.2, bs) - rw [hd] at this - refine this.trans ?_ - have h3 : (encPair (VertexDesc.enc (encList encNat)) encBits (Sum.inl t, bs)).length + 1 ≤ - 3 * n + 2 := by - rw [← hd]; omega - calc ct * ((encPair (VertexDesc.enc (encList encNat)) encBits (Sum.inl t, bs)).length - + 1) ^ dt - ≤ ct * (3 * n + 2) ^ dt := Nat.mul_le_mul_left _ (Nat.pow_le_pow_left h3 _) - _ ≤ Rv := by omega - · exact hpacket v hv d hd _ (VertexDesc.reduced_entry_inr tableEntry d bs) - obtain ⟨hsT, hsS⟩ := hK₁ ((x.prec, x.fl), x.net) (K₂ * (R + 2) ^ Λ * Zb ^ K₂) (K₂ * Zb ^ K₂) Rv - Rv hentry hred + · have h1 : (encList encNat (ev t bs)).length ≤ cE * (ce.space (t, bs) + 1) := hcE (t, bs) + have h2 : cE * (ce.space (t, bs) + 1) ≤ cE * (ES + 1) := + Nat.mul_le_mul_left _ (by have := (hroot v hv t hd bs hbs).2; omega) + simp only [VertexDesc.entry_inl] + omega + · have := hpacket v hv d hd _ (VertexDesc.reduced_entry_inr ev d bs) + omega + obtain ⟨hsT, hsS⟩ := hK₁ ((x.prec, x.fl), x.net) (K₂ * (R + 2) ^ Λ * Zb ^ K₂ + E) + (K₂ * Zb ^ K₂ + ES) Ev Rv hentry hred -- Polynomial pieces against `W`. - have hk : x.net.vertices.length + 1 ≤ W := by have := length_vertices_le (encList encNat) x; omega - have hRvW : Rv ≤ cR * W ^ e := by - rw [hRv, hcR, he]; exact rv_le hnW + have hk : x.net.vertices.length + 1 ≤ W := by have := length_vertices_le encT x; omega + have hRvW : Rv ≤ (cR - cE) * W ^ e := by + have h := rv_le (ct := 0) (dt := 0) (cf := cf) (df := df) (cp := cp) (dp := dp) hnW + rw [hRv, he] + refine h.trans (Nat.mul_le_mul_right _ ?_) + omega have hWE : W ^ e ≤ W ^ E₀ := Nat.pow_le_pow_right hW1 (by omega) + have hW1E : W ≤ W ^ E₀ := + (pow_one W).symm.le.trans (Nat.pow_le_pow_right hW1 (by omega)) + have hEvW : Ev ≤ cR * W ^ E₀ := by + have h1 : Rv ≤ (cR - cE) * W ^ E₀ := hRvW.trans (Nat.mul_le_mul_left _ hWE) + have h2 : cE * (ES + 1) ≤ cE * W ^ E₀ := Nat.mul_le_mul_left _ (by omega) + have e : cR * W ^ E₀ = (cR - cE) * W ^ E₀ + cE * W ^ E₀ := by + rw [← Nat.add_mul, Nat.sub_add_cancel (by omega)] + omega have hA1 : (DescribedNetwork.encInput (encPair encUnary (encList encNat)) - (VertexDesc.enc (encList encNat)) ((x.prec, x.fl), x.net)).length + Rv + Rv + 1 ≤ - c₁ * W ^ E₀ := by + (VertexDesc.enc encT) ((x.prec, x.fl), x.net)).length + Ev + Rv + 1 ≤ c₁ * W ^ E₀ := by have h1 : (DescribedNetwork.encInput (encPair encUnary (encList encNat)) - (VertexDesc.enc (encList encNat)) ((x.prec, x.fl), x.net)).length ≤ cl * W ^ dl := + (VertexDesc.enc encT) ((x.prec, x.fl), x.net)).length ≤ cl * W ^ dl := (hl x).trans (by rw [← hn]; exact mul_pow_le_of_le hnW) + have h2 : Rv ≤ Ev := by omega + have h3 := sum_le_of_le hW1 h1 (by omega) hEvW rw [hc₁] - exact sum_le_of_le hW1 h1 (by omega) (hRvW.trans (Nat.mul_le_mul_left _ hWE)) + omega have hZW : Zb ≤ c₂ * W ^ E₀ := by rw [hc₂, hZb] - exact zb_le hW1 (by omega) (hRvW.trans (Nat.mul_le_mul_left _ hWE)) (by omega) - have hnW' : (encCall (encList encNat) x).length + 1 ≤ W := by omega + have h1 : Rv ≤ cR * W ^ E₀ := by + have := hRvW.trans (Nat.mul_le_mul_left _ hWE) + exact this.trans (Nat.mul_le_mul_right _ (Nat.sub_le _ _)) + exact zb_le hW1 (by omega) h1 (by omega) + have hnW' : (encCall encT x).length + 1 ≤ W := by omega have hdt' := (hdt x).trans (mul_pow_le_of_le (c := cd) (d := dd) hnW') have hit' := (hit x).trans (mul_pow_le_of_le (c := ci) (d := di) hnW') have hds' := (hds x).trans (mul_pow_le_of_le (c := cd') (d := dd') hnW') @@ -417,11 +452,16 @@ theorem leafCertificate_le : ∃ K : ℕ, have hX : 1 ≤ (R + 2) ^ Λ := Nat.one_le_pow _ _ (by omega) refine ⟨?_, ?_⟩ · rw [leafCertificate_time] - refine (time_assemble hW1 hP hX hdt' hit' hsT hk hA1 hZW).trans ?_ - refine Nat.mul_le_mul_right _ (Nat.mul_le_mul_right _ (Nat.mul_le_mul (by omega) - (Nat.pow_le_pow_right hW1 (by omega)))) + refine (time_assemble hW1 hP hX hdt' hit' hsT hk (by omega) hZW).trans ?_ + have hpow : W ^ (1 + E₀ * (K₁ + K₂) + dd + di) ≤ W ^ (G + Dg) := + Nat.pow_le_pow_right hW1 (by omega) + calc _ = (2 * (K₁ * c₁ ^ K₁ + 2 * (K₂ * c₂ ^ K₂) + 2) + cd + ci) * + W ^ (1 + E₀ * (K₁ + K₂) + dd + di) * (2 ^ x.edges * ((R + 2) ^ Λ + E)) := by ring + _ ≤ (G + Dg) * W ^ (G + Dg) * (2 ^ x.edges * ((R + 2) ^ Λ + E)) := + Nat.mul_le_mul_right _ (Nat.mul_le_mul (by omega) hpow) + _ = _ := by ring · rw [leafCertificate_space] - refine (space_assemble hW1 hds' his' hsS hA1 rfl hZW).trans ?_ + refine (space_assemble hW1 hds' his' hsS (by omega) rfl (by omega) hZW).trans ?_ exact Nat.mul_le_mul (by omega) (Nat.pow_le_pow_right hW1 (by omega)) /-! ### The shape of the packets -/ @@ -536,40 +576,118 @@ theorem rowPorts_le_of_packetShape {x : Call T} (hs : PacketShape x) {v : List rw [hbeq] exact hcard.trans (Nat.pow_le_pow_right (by norm_num) h2) -/-- **The cost of a leaf with the packet shape.** There is `K` such that, on a call of encoded -length `n` with `M` edges, scale `s` and precision `p` with the packet shape, writing -`A = 2 ^ (⌊log₂ s⌋ / 32768)`, direct summation takes time at most -`K (n + 1) ^ K 2 ^ M (A p + 2) ^ A` and space at most `K (n + 1) ^ K`. -/ -theorem leafCertificate_le_of_packetShape : ∃ K : ℕ, - ∀ (mk : Call (List ℕ) → State → ℕ × DescribedNetwork (VertexDesc (List ℕ))) - (x : Call (List ℕ)), PacketShape x → - (leafCertificate mk).time x ≤ K * ((encCall (encList encNat) x).length + 1) ^ K * - 2 ^ x.edges * - (2 ^ (Nat.log 2 x.scale / 32768) * x.prec + 2) ^ 2 ^ (Nat.log 2 x.scale / 32768) ∧ - (leafCertificate mk).space x ≤ K * ((encCall (encList encNat) x).length + 1) ^ K := by - obtain ⟨K, hK⟩ := leafCertificate_le - refine ⟨2 * K, fun mk x hs => ?_⟩ +/-- **The cost of a leaf with the packet shape.** For a native certificate `ce` of the entry +procedure of the roots, there is `K` such that, on a call of encoded length `n` with `M` edges, +scale `s` and precision `p` with the packet shape, whose roots take time at most `E` and space at +most `ES` in `ce` on every bit list on their ports, writing `A = 2 ^ (⌊log₂ s⌋ / 32768)`, direct +summation takes time at most `K (n + ES + 1) ^ K 2 ^ M ((A p + 2) ^ A + E)` and space at most +`K (n + ES + 1) ^ K`. -/ +theorem leafCertificate_le_of_packetShape + (ce : NativeCertificate (fun q : T × List Bool => ev q.1 q.2) (encPair encT encBits) + (encList encNat)) : + ∃ K : ℕ, ∀ (mk : Call T → State → ℕ × DescribedNetwork (VertexDesc T)) (x : Call T) + (E ES : ℕ), PacketShape x → + (∀ v ∈ x.net.vertices, ∀ t, v.2 = .inl t → ∀ bs : List Bool, bs.length = v.1.length → + ce.time (t, bs) ≤ E ∧ ce.space (t, bs) ≤ ES) → + (leafCertificate ce mk).time x ≤ K * ((encCall encT x).length + ES + 1) ^ K * 2 ^ x.edges * + ((2 ^ (Nat.log 2 x.scale / 32768) * x.prec + 2) ^ 2 ^ (Nat.log 2 x.scale / 32768) + E) ∧ + (leafCertificate ce mk).space x ≤ K * ((encCall encT x).length + ES + 1) ^ K := by + obtain ⟨K, hK⟩ := leafCertificate_le ce + refine ⟨2 * K, fun mk x E ES hs hroot => ?_⟩ obtain ⟨hT, hS⟩ := hK mk x (2 ^ (Nat.log 2 x.scale / 32768) * x.prec) - (2 ^ (Nat.log 2 x.scale / 32768)) fun v hv => - ⟨modes_le_of_packetShape hs hv, fun bs _ => rowPorts_le_of_packetShape hs hv bs⟩ - have hn := scale_add_prec_add_length_fl_le (encList encNat) x + (2 ^ (Nat.log 2 x.scale / 32768)) E ES (fun v hv => + ⟨modes_le_of_packetShape hs hv, fun bs _ => rowPorts_le_of_packetShape hs hv bs⟩) hroot + have hn := scale_add_prec_add_length_fl_le encT x have hA := two_pow_log_div_le x.scale - have hR : (encCall (encList encNat) x).length + 2 ^ (Nat.log 2 x.scale / 32768) * x.prec + 1 ≤ - ((encCall (encList encNat) x).length + 1) ^ 2 := by - have : 2 ^ (Nat.log 2 x.scale / 32768) * x.prec ≤ - ((encCall (encList encNat) x).length + 1) * (encCall (encList encNat) x).length := + set N := (encCall encT x).length + ES with hN + have hR : (encCall encT x).length + 2 ^ (Nat.log 2 x.scale / 32768) * x.prec + ES + 1 ≤ + (N + 1) ^ 2 := by + have : 2 ^ (Nat.log 2 x.scale / 32768) * x.prec ≤ (N + 1) * N := Nat.mul_le_mul (by omega) (by omega) nlinarith - have hpow : - K * ((encCall (encList encNat) x).length + 2 ^ (Nat.log 2 x.scale / 32768) * x.prec + 1) ^ K ≤ - 2 * K * ((encCall (encList encNat) x).length + 1) ^ (2 * K) := - calc _ ≤ K * (((encCall (encList encNat) x).length + 1) ^ 2) ^ K := - Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hR _) - _ = K * ((encCall (encList encNat) x).length + 1) ^ (2 * K) := by rw [← pow_mul] - _ ≤ 2 * K * ((encCall (encList encNat) x).length + 1) ^ (2 * K) := - Nat.mul_le_mul_right _ (by omega) + have hpow : K * ((encCall encT x).length + 2 ^ (Nat.log 2 x.scale / 32768) * x.prec + ES + + 1) ^ K ≤ 2 * K * (N + 1) ^ (2 * K) := + calc _ ≤ K * ((N + 1) ^ 2) ^ K := Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hR _) + _ = K * (N + 1) ^ (2 * K) := by rw [← pow_mul] + _ ≤ 2 * K * (N + 1) ^ (2 * K) := Nat.mul_le_mul_right _ (by omega) exact ⟨hT.trans (Nat.mul_le_mul_right _ (Nat.mul_le_mul_right _ hpow)), hS.trans hpow⟩ +/-- **The cost of a leaf over tables with the packet shape.** The entry procedure of tables is +polynomial, so there is `K` such that, on a call over tables of encoded length `n` with `M` edges, +scale `s` and precision `p` with the packet shape, writing `A = 2 ^ (⌊log₂ s⌋ / 32768)`, direct +summation takes time at most `K (n + 1) ^ K 2 ^ M (A p + 2) ^ A` and space at most +`K (n + 1) ^ K`. -/ +theorem leafCertificate_tableEntry_le_of_packetShape : ∃ K : ℕ, + ∀ (mk : Call (List ℕ) → State → ℕ × DescribedNetwork (VertexDesc (List ℕ))) + (x : Call (List ℕ)), PacketShape x → + (leafCertificate tableEntryCertificate mk).time x ≤ + K * ((encCall (encList encNat) x).length + 1) ^ K * 2 ^ x.edges * + (2 ^ (Nat.log 2 x.scale / 32768) * x.prec + 2) ^ 2 ^ (Nat.log 2 x.scale / 32768) ∧ + (leafCertificate tableEntryCertificate mk).space x ≤ + K * ((encCall (encList encNat) x).length + 1) ^ K := by + obtain ⟨K, hK⟩ := leafCertificate_le_of_packetShape tableEntryCertificate + obtain ⟨ct, dt, ht⟩ := tableEntryCertificate_isPolynomial.1.exists_le + obtain ⟨cs, ds, hs⟩ := tableEntryCertificate_isPolynomial.2.exists_le + obtain ⟨c₁, hc₁⟩ : ∃ c₁, c₁ = 1 + cs * 3 ^ ds := ⟨_, rfl⟩ + obtain ⟨c₂, hc₂⟩ : ∃ c₂, c₂ = 1 + ct * 3 ^ dt := ⟨_, rfl⟩ + refine ⟨K * c₁ ^ K * c₂ + (ds + 1) * K + dt, fun mk x hshape => ?_⟩ + obtain ⟨n, hn⟩ : ∃ n, n = (encCall (encList encNat) x).length := ⟨_, rfl⟩ + rw [← hn] + -- A root and the bits on its ports are at most `3 n` long. + have hlen : ∀ v ∈ x.net.vertices, ∀ t, v.2 = .inl t → ∀ bs : List Bool, + bs.length = v.1.length → + (encPair (encList encNat) encBits (t, bs)).length + 1 ≤ 3 * (n + 1) := by + intro v hv t hvt bs hbs + have h1 := length_vertex_le (encList encNat) hv + have h2 := length_le_length_encList encNat v.1 + rw [← hn, length_encPair, hvt, length_encSum] at h1 + rw [length_encPair] + change 2 * (encList encNat t).length + 1 + bs.length + 1 ≤ 3 * (n + 1) + simp only [Sum.elim_inl] at h1 + omega + have hpow3 {c d : ℕ} : c * (3 * (n + 1)) ^ d = c * 3 ^ d * (n + 1) ^ d := by + rw [mul_pow]; ring + obtain ⟨hT, hS⟩ := hK mk x (ct * 3 ^ dt * (n + 1) ^ dt) (cs * 3 ^ ds * (n + 1) ^ ds) hshape + fun v hv t hvt bs hbs => ⟨(ht (t, bs)).trans (by + rw [← hpow3]; exact Nat.mul_le_mul_left _ (Nat.pow_le_pow_left (hlen v hv t hvt bs hbs) _)), + (hs (t, bs)).trans (by + rw [← hpow3]; exact Nat.mul_le_mul_left _ (Nat.pow_le_pow_left (hlen v hv t hvt bs hbs) _))⟩ + rw [← hn] at hT hS + set A := 2 ^ (Nat.log 2 x.scale / 32768) + set X := (A * x.prec + 2) ^ A + set B := n + 1 with hB + have hB1 : 1 ≤ B := by omega + have hX1 : 1 ≤ X := Nat.one_le_pow _ _ (by omega) + -- `n + ES + 1 ≤ c₁ B ^ (ds + 1)` and `X + E ≤ c₂ B ^ dt X`. + have hW : n + cs * 3 ^ ds * B ^ ds + 1 ≤ c₁ * B ^ (ds + 1) := by + have h1 : B ≤ B ^ (ds + 1) := (pow_one B).symm.le.trans (Nat.pow_le_pow_right hB1 (by omega)) + have h2 : cs * 3 ^ ds * B ^ ds ≤ cs * 3 ^ ds * B ^ (ds + 1) := + Nat.mul_le_mul_left _ (Nat.pow_le_pow_right hB1 (by omega)) + rw [hc₁, add_mul, one_mul] + omega + have hXE : X + ct * 3 ^ dt * B ^ dt ≤ c₂ * B ^ dt * X := by + have h1 : 1 ≤ B ^ dt := Nat.one_le_pow _ _ (by omega) + have h2 : ct * 3 ^ dt * B ^ dt ≤ ct * 3 ^ dt * B ^ dt * X := Nat.le_mul_of_pos_right _ hX1 + have h3 : X ≤ B ^ dt * X := Nat.le_mul_of_pos_left _ h1 + have e : c₂ * B ^ dt * X = B ^ dt * X + ct * 3 ^ dt * B ^ dt * X := by rw [hc₂]; ring + omega + have hWK : K * (n + cs * 3 ^ ds * B ^ ds + 1) ^ K ≤ K * c₁ ^ K * B ^ ((ds + 1) * K) := by + calc _ ≤ K * (c₁ * B ^ (ds + 1)) ^ K := Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hW _) + _ = K * c₁ ^ K * B ^ ((ds + 1) * K) := by rw [mul_pow, ← pow_mul]; ring + set K' := K * c₁ ^ K * c₂ + (ds + 1) * K + dt + have hc₂1 : 1 ≤ c₂ := by omega + refine ⟨hT.trans ?_, hS.trans ?_⟩ + · calc _ ≤ K * c₁ ^ K * B ^ ((ds + 1) * K) * 2 ^ x.edges * (c₂ * B ^ dt * X) := + Nat.mul_le_mul (Nat.mul_le_mul_right _ hWK) hXE + _ = K * c₁ ^ K * c₂ * B ^ ((ds + 1) * K + dt) * 2 ^ x.edges * X := by rw [pow_add]; ring + _ ≤ K' * B ^ K' * 2 ^ x.edges * X := + Nat.mul_le_mul_right _ (Nat.mul_le_mul_right _ + (Nat.mul_le_mul (by omega) (Nat.pow_le_pow_right hB1 (by omega)))) + · calc _ ≤ K * c₁ ^ K * B ^ ((ds + 1) * K) := hWK + _ ≤ K' * B ^ K' := Nat.mul_le_mul + ((Nat.le_mul_of_pos_right _ hc₂1).trans (by omega)) + (Nat.pow_le_pow_right hB1 (by omega)) + /-! ### The leaf bound of the analysis -/ /-- `(μ + 1) ^ 2 ≤ 16 · 2 ^ (μ / 2)`. -/ @@ -658,10 +776,11 @@ theorem exists_leafCertificate_le (C c s₀ : ℕ) : ∃ K : ℕ, (x : Call (List ℕ)), 2 ≤ s → s ≤ x.scale → x.scale ≤ C * s → PacketShape x → x.edges ≤ 2 * x.scale → (s₀ ≤ s → x.edges ≤ leafSize x.scale ∧ x.prec ≤ x.scale ^ c) → - (leafCertificate mk).time x ≤ + (leafCertificate tableEntryCertificate mk).time x ≤ K * ((encCall (encList encNat) x).length + 1) ^ K * 2 ^ (K * s / Nat.sqrt (Nat.log 2 s)) ∧ - (leafCertificate mk).space x ≤ K * ((encCall (encList encNat) x).length + 1) ^ K := by - obtain ⟨K₀, hK₀⟩ := leafCertificate_le_of_packetShape + (leafCertificate tableEntryCertificate mk).space x ≤ + K * ((encCall (encList encNat) x).length + 1) ^ K := by + obtain ⟨K₀, hK₀⟩ := leafCertificate_tableEntry_le_of_packetShape obtain ⟨K₁, hK₁⟩ := exists_packetFactor_le C c obtain ⟨Ks, hKs⟩ : ∃ Ks, Ks = K₀ * 2 ^ (2 * (C * s₀)) * (C * s₀ + 2) ^ (C * s₀) := ⟨_, rfl⟩ refine ⟨Ks + K₀ + C * s₀ + C + K₁, fun mk s x hs hsm hmC hshape hM hbig => ?_⟩ @@ -691,7 +810,8 @@ theorem exists_leafCertificate_le (C c s₀ : ℕ) : ∃ K : ℕ, _ ≤ ((C * s₀ + 2) * (n + 1)) ^ (C * s₀) := Nat.pow_le_pow_right (Nat.one_le_iff_ne_zero.mpr (by positivity)) (hAm.trans hmC') _ = (C * s₀ + 2) ^ (C * s₀) * (n + 1) ^ (C * s₀) := mul_pow _ _ _ - calc (leafCertificate mk).time x ≤ K₀ * (n + 1) ^ K₀ * 2 ^ x.edges * (A * x.prec + 2) ^ A := hT + calc (leafCertificate tableEntryCertificate mk).time x + ≤ K₀ * (n + 1) ^ K₀ * 2 ^ x.edges * (A * x.prec + 2) ^ A := hT _ ≤ K₀ * (n + 1) ^ K₀ * 2 ^ (2 * (C * s₀)) * ((C * s₀ + 2) ^ (C * s₀) * (n + 1) ^ (C * s₀)) := Nat.mul_le_mul (Nat.mul_le_mul_left _ h2M) hfac @@ -709,7 +829,8 @@ theorem exists_leafCertificate_le (C c s₀ : ℕ) : ∃ K : ℕ, have hCK : (C + K₁) * s ≤ K * s := Nat.mul_le_mul_right _ (by omega) have hexp : C * s / S + K₁ * s / S ≤ K * s / S := Nat.div_add_div_le_add_div.trans (Nat.div_le_div_right (by rw [← add_mul]; exact hCK)) - calc (leafCertificate mk).time x ≤ K₀ * (n + 1) ^ K₀ * 2 ^ x.edges * (A * x.prec + 2) ^ A := hT + calc (leafCertificate tableEntryCertificate mk).time x + ≤ K₀ * (n + 1) ^ K₀ * 2 ^ x.edges * (A * x.prec + 2) ^ A := hT _ ≤ K₀ * (n + 1) ^ K₀ * 2 ^ (C * s / S) * 2 ^ (K₁ * s / S) := Nat.mul_le_mul (Nat.mul_le_mul_left _ (Nat.pow_le_pow_right (by norm_num) hMs)) hfac _ = K₀ * (n + 1) ^ K₀ * 2 ^ (C * s / S + K₁ * s / S) := by rw [pow_add]; ring diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionMachine.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionMachine.lean index 0f1c09927..5ab35e0d3 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionMachine.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionMachine.lean @@ -28,8 +28,9 @@ import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimeNatFr The stack recursion of `Cslib.Circuits.Frontier.FastContraction.scheme` as one native machine for the contraction modulo `2 ^ P` of an explicit network `(r, G)`, with the precision `P` in binary: the root descriptors are tables (`T = List ℕ`), read by the entry procedure `tableEntry`. The -encodings, the root network (`FastContraction.rootNet`) and its polynomial-time construction are -stated for every type of root descriptors. +encodings, the leaf certificate (`FastContraction.leafCertificate ce`, from a native certificate +`ce` of any entry procedure), the root network (`FastContraction.rootNet`) and its polynomial-time +construction are stated for every type of root descriptors. **The root.** The precision is first capped at the encoded length of the network (`ExplicitTensorNetwork.capPrecision`), which does not change the residue. The root call @@ -122,36 +123,46 @@ theorem leafInput_polyTime : (DescribedNetwork.encInput (encPair encUnary (encList encNat)) (VertexDesc.enc encT)) := by unfold Call.prec Call.fl Call.net; fun_prop -variable (mk : Call (List ℕ) → State → ℕ × DescribedNetwork (VertexDesc (List ℕ))) +section Leaf + +variable {encT} {ev : T → List Bool → List ℕ} + (ce : NativeCertificate (fun q : T × List Bool => ev q.1 q.2) (encPair encT encBits) + (encList encNat)) + (mk : Call T → State → ℕ × DescribedNetwork (VertexDesc T)) -/-- **The leaf certificate** over tables: direct summation over the coefficient lists of `A_p`, -with the native evaluator of the vertex descriptors, tagged with the depth. -/ +/-- **The leaf certificate**: direct summation over the coefficient lists of `A_p`, with the native +evaluator of the vertex descriptors built from a native certificate `ce` of the entry procedure of +the roots, tagged with the depth. -/ @[expose] noncomputable def leafCertificate : - NativeCertificate (scheme tableEntry mk).leaf (encCall (encList encNat)) encValue := - ((NativeCertificate.ofPolyTime (depth_polyTime (encList encNat))).prod - ((DescribedNetwork.contractionCertificate (VertexDesc.entry tableEntry) - SumOps.galois_polyTime VertexDesc.entryCertificate).comp - (NativeCertificate.ofPolyTime (leafInput_polyTime (encList encNat))))).congr + NativeCertificate (scheme ev mk).leaf (encCall encT) encValue := + ((NativeCertificate.ofPolyTime (depth_polyTime encT)).prod + ((DescribedNetwork.contractionCertificate (VertexDesc.entry ev) SumOps.galois_polyTime + (VertexDesc.entryCertificate ce)).comp + (NativeCertificate.ofPolyTime (leafInput_polyTime encT)))).congr fun _ => rfl /-- The time of a leaf: the depth, the input of direct summation, and direct summation. -/ -theorem leafCertificate_time (x : Call (List ℕ)) : - (leafCertificate mk).time x = - (NativeCertificate.ofPolyTime (depth_polyTime (encList encNat))).time x + - ((NativeCertificate.ofPolyTime (leafInput_polyTime (encList encNat))).time x + - (DescribedNetwork.contractionCertificate (VertexDesc.entry tableEntry) - SumOps.galois_polyTime VertexDesc.entryCertificate).time ((x.prec, x.fl), x.net)) := +theorem leafCertificate_time (x : Call T) : + (leafCertificate ce mk).time x = + (NativeCertificate.ofPolyTime (depth_polyTime encT)).time x + + ((NativeCertificate.ofPolyTime (leafInput_polyTime encT)).time x + + (DescribedNetwork.contractionCertificate (VertexDesc.entry ev) + SumOps.galois_polyTime (VertexDesc.entryCertificate ce)).time + ((x.prec, x.fl), x.net)) := rfl /-- The space of a leaf. -/ -theorem leafCertificate_space (x : Call (List ℕ)) : - (leafCertificate mk).space x = - (NativeCertificate.ofPolyTime (depth_polyTime (encList encNat))).space x + - ((NativeCertificate.ofPolyTime (leafInput_polyTime (encList encNat))).space x + - (DescribedNetwork.contractionCertificate (VertexDesc.entry tableEntry) - SumOps.galois_polyTime VertexDesc.entryCertificate).space ((x.prec, x.fl), x.net)) := +theorem leafCertificate_space (x : Call T) : + (leafCertificate ce mk).space x = + (NativeCertificate.ofPolyTime (depth_polyTime encT)).space x + + ((NativeCertificate.ofPolyTime (leafInput_polyTime encT)).space x + + (DescribedNetwork.contractionCertificate (VertexDesc.entry ev) + SumOps.galois_polyTime (VertexDesc.entryCertificate ce)).space + ((x.prec, x.fl), x.net)) := rfl +end Leaf + /-! ### The root -/ /-- The exponent `t` of the modulus, with `2 ^ (t + 1) > 4 ⌊log₂ m⌋ + 2`. -/ @@ -347,6 +358,8 @@ theorem fuel_polyTime : ComputableInPolyTime fuel ExplicitTensorNetwork.encContr /-! ### The result -/ +variable (mk : Call (List ℕ) → State → ℕ × DescribedNetwork (VertexDesc (List ℕ))) + /-- **The result of the machine** on an input `(P, r, G)`: with the capped precision `p`, the constant coordinate of a returned root value modulo `2 ^ p` if the run returns a value tagged `0`, and direct summation otherwise. -/ @@ -400,7 +413,8 @@ components of the scheme. -/ NativeCertificate ((scheme tableEntry mk).run fuel root) ExplicitTensorNetwork.encContractionInput (encOption encValue) := - Scheme.certificate hpoly (leafCertificate mk) (NativeCertificate.ofPolyTime fuel_polyTime) + Scheme.certificate hpoly (leafCertificate tableEntryCertificate mk) + (NativeCertificate.ofPolyTime fuel_polyTime) (NativeCertificate.ofPolyTime root_polyTime) /-- The constant coordinate of a value modulo `2 ^ p`, for the capped precision `p`. -/ diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/VertexDesc.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/VertexDesc.lean index 4f620b30f..ebc387ad2 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/VertexDesc.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/VertexDesc.lean @@ -36,12 +36,13 @@ precision. A network of the recursion reads the entries at its own precision `(p its coefficient list: a retained packet vertex created at a lower precision is read at the higher one as the same element of `O = ℤ_(2)[U] / (f)`. Explicit tables are the root descriptors `T = List ℕ` with the entry procedure `tableEntry`, which returns the table entry as a constant. -For tables, one native machine evaluates every descriptor (`VertexDesc.entryCertificate`), with -the packet evaluator's bounds: time `K (m + 2) ^ L Z ^ K` and space `K Z ^ K`, for `m` target modes -and `L` row ports of a packet (none for a table) and `Z` polynomial in the input and the reduced -coefficient lists (`VertexDesc.entryCertificate_le`). It is the evaluator of direct summation over -networks of descriptors at coefficient lists (`DescribedNetwork.contractionCertificate` at -`SumOps.galois`). +From a native certificate `ce` of the entry procedure, one native machine evaluates every +descriptor (`VertexDesc.entryCertificate ce`): time `K (m + 2) ^ L Z ^ K + E` and space +`K Z ^ K + ES`, for `m` target modes and `L` row ports of a packet (none for a root), `Z` polynomial +in the input and the reduced coefficient lists, and `E` and `ES` the time and space of `ce` on a +root (`VertexDesc.entryCertificate_le`). It is the evaluator of direct summation over networks of +descriptors at coefficient lists (`DescribedNetwork.contractionCertificate` at `SumOps.galois`). +The entry procedure of tables has a polynomial native certificate (`tableEntryCertificate`). ## Main definitions @@ -49,7 +50,9 @@ networks of descriptors at coefficient lists (`DescribedNetwork.contractionCerti * `Cslib.Circuits.Frontier.VertexDesc`: a root descriptor or a packet descriptor. * `Cslib.Circuits.Frontier.VertexDesc.entry`: its entry at the bits on its ports. * `Cslib.Circuits.Frontier.VertexDesc.enc`: its encoding. -* `Cslib.Circuits.Frontier.VertexDesc.entryCertificate`: the native evaluator, for tables. +* `Cslib.Circuits.Frontier.VertexDesc.entryCertificate`: the native evaluator. +* `Cslib.Circuits.Frontier.tableEntryCertificate`: the native certificate of the entry procedure + of tables. ## Main results @@ -158,58 +161,55 @@ theorem reduced_entry_inr (ev : T → List Bool → List ℕ) (d : PacketDesc) ( SumOps.galois.Reduced (d.1.p, d.1.fl) (entry ev (.inr d) bs) := SumOps.galois.reduced_mul (d.1.p, d.1.fl) _ _ -/-! ### The native evaluator of tables -/ +/-! ### The native evaluator -/ -/-- The right summand of a descriptor and its bits. -/ -theorem getRight_polyTime : - ComputableInPolyTime (fun q : VertexDesc (List ℕ) × List Bool => q.1.getRight?) - (encPair (enc (encList encNat)) encBits) (encOption encPacketDesc) := - (ComputableInO.getRight?_deg _ _).computableInPolyTime.comp (ComputableInPolyTime.fst _ _) +section Evaluator -/-- The table entry of a descriptor at its bits, the empty table standing for a packet, as a -singleton list. -/ -theorem tableEntry_polyTime : - ComputableInPolyTime (fun q : VertexDesc (List ℕ) × List Bool => - [ExplicitTensorNetwork.entry (q.1.getLeft?.getD []) q.2]) - (encPair (enc (encList encNat)) encBits) (encList encNat) := by - have hleft : ComputableInPolyTime (fun q : VertexDesc (List ℕ) × List Bool => q.1.getLeft?) - (encPair (enc (encList encNat)) encBits) (encOption (encList encNat)) := - (ComputableInO.getLeft?_deg _ _).computableInPolyTime.comp (ComputableInPolyTime.fst _ _) - have htable : ComputableInPolyTime - (fun q : VertexDesc (List ℕ) × List Bool => q.1.getLeft?.getD []) - (encPair (enc (encList encNat)) encBits) (encList encNat) := - (ComputableInDegree.getD (enc₁ := encList encNat) (enc := encOption (encList encNat)) - []).computableInPolyTime.comp hleft - have hindex := ComputableInPolyTime.bitsBinaryValue.comp - (ComputableInPolyTime.bitsReverse.comp - (ComputableInPolyTime.snd (enc (encList encNat)) encBits)) - have hentry := ComputableInPolyTime.listGetD_binary (encA := encNat) (encL := encList encNat) 0 - htable hindex - exact (ComputableInPolyTime.cons' hentry (ComputableInPolyTime.const [])).of_enc_eq fun q => by - simp only [ExplicitTensorNetwork.entry, BitString.lsbValue_eq_binaryValue_reverse, - Function.comp_apply] +variable {encT : T ↪ List Bool} + +/-- The left summand of a descriptor and its bits. -/ +theorem getLeft_polyTime : + ComputableInPolyTime (fun q : VertexDesc T × List Bool => q.1.getLeft?) + (encPair (enc encT) encBits) (encOption encT) := + (ComputableInO.getLeft?_deg _ _).computableInPolyTime.comp (ComputableInPolyTime.fst _ _) -/-- The input of the packet evaluator from a descriptor's bits and its packet. -/ +/-- The input of the packet evaluator at a descriptor and its bits, the default packet standing for +a root. -/ theorem packetInput_polyTime : - ComputableInPolyTime (fun p : (VertexDesc (List ℕ) × List Bool) × PacketDesc => (p.2, p.1.2)) - (encPair (encPair (enc (encList encNat)) encBits) encPacketDesc) - (encPair encPacketDesc encBits) := + ComputableInPolyTime (fun q : VertexDesc T × List Bool => (q.1.getRight?.getD default, q.2)) + (encPair (enc encT) encBits) (encPair encPacketDesc encBits) := by + have hright : ComputableInPolyTime (fun q : VertexDesc T × List Bool => q.1.getRight?) + (encPair (enc encT) encBits) (encOption encPacketDesc) := + (ComputableInO.getRight?_deg _ _).computableInPolyTime.comp (ComputableInPolyTime.fst _ _) + exact ((ComputableInDegree.getD (enc₁ := encPacketDesc) (enc := encOption encPacketDesc) + default).computableInPolyTime.comp hright).prod (ComputableInPolyTime.snd _ _) + +/-- The input of the root's entry procedure from a descriptor's bits and its root descriptor. -/ +theorem rootInput_polyTime : + ComputableInPolyTime (fun p : (VertexDesc T × List Bool) × T => (p.2, p.1.2)) + (encPair (encPair (enc encT) encBits) encT) (encPair encT encBits) := (ComputableInPolyTime.snd _ _).prod - ((ComputableInPolyTime.snd (enc (encList encNat)) encBits).comp (ComputableInPolyTime.fst _ _)) - -/-- **One native machine for the entries of all descriptors over tables**: the table lookup for a -table, and the native packet evaluator (`NativePacket.vertexCertificate`) for a packet. -/ -noncomputable def entryCertificate : - NativeCertificate (fun q : VertexDesc (List ℕ) × List Bool => entry tableEntry q.1 q.2) - (encPair (enc (encList encNat)) encBits) (encList encNat) := - (NativeCertificate.option (value := fun q : VertexDesc (List ℕ) × List Bool => q.1.getRight?) - (fallback := fun q => [ExplicitTensorNetwork.entry (q.1.getLeft?.getD []) q.2]) - (body := fun p => packetVertexEntry p.2 p.1.2) - (NativeCertificate.ofPolyTime getRight_polyTime) - (NativeCertificate.ofPolyTime tableEntry_polyTime) + ((ComputableInPolyTime.snd (enc encT) encBits).comp (ComputableInPolyTime.fst _ _)) + +variable {ev : T → List Bool → List ℕ} + +/-- **One native machine for the entries of all descriptors**, from a native certificate `ce` of +the entry procedure `ev` of the root descriptors: `ce` for a root, and the native packet evaluator +(`NativePacket.vertexCertificate`) for a packet. -/ +noncomputable def entryCertificate + (ce : NativeCertificate (fun q : T × List Bool => ev q.1 q.2) (encPair encT encBits) + (encList encNat)) : + NativeCertificate (fun q : VertexDesc T × List Bool => entry ev q.1 q.2) + (encPair (enc encT) encBits) (encList encNat) := + (NativeCertificate.option (value := fun q : VertexDesc T × List Bool => q.1.getLeft?) + (fallback := fun q => packetVertexEntry (q.1.getRight?.getD default) q.2) + (body := fun p => ev p.2 p.1.2) + (NativeCertificate.ofPolyTime getLeft_polyTime) ((vertexCertificate.comp (NativeCertificate.ofPolyTime packetInput_polyTime)).congr - fun _ => rfl)).congr fun q => by - rcases q with ⟨d | d, bs⟩ <;> rfl + fun _ => rfl) + ((ce.comp (NativeCertificate.ofPolyTime rootInput_polyTime)).congr fun _ => rfl)).congr + fun q => by + rcases q with ⟨d | d, bs⟩ <;> rfl /-- `c (y + 1) ^ d ≤ c Z ^ D` when `y + 1 ≤ Z` and `d ≤ D`. -/ private theorem mul_pow_le_mul_pow {c y d Z D : ℕ} (hy : y + 1 ≤ Z) (hd : d ≤ D) : @@ -217,101 +217,116 @@ private theorem mul_pow_le_mul_pow {c y d Z D : ℕ} (hy : y + 1 ≤ Z) (hd : d Nat.mul_le_mul_left _ ((Nat.pow_le_pow_left hy _).trans (Nat.pow_le_pow_right (by omega) hd)) -/-- **The resources of the native evaluator of descriptors.** There is `K` such that on a -descriptor and bits of total length `n`, with `m` target modes and `L` row ports (`0` and `0` for a -table), if the reduced coefficient lists of a packet's precision are at most `Rv` bits long, then -with `Z = n + m + Rv + 2` the time is at most `K (m + 2) ^ L Z ^ K` and the space at most -`K Z ^ K`. -/ -theorem entryCertificate_le : - ∃ K : ℕ, ∀ (q : VertexDesc (List ℕ) × List Bool) (Rv : ℕ), q.1.ReducedLE Rv → - entryCertificate.time q ≤ K * (q.1.modes + 2) ^ q.1.rowPorts q.2 * - ((encPair (enc (encList encNat)) encBits q).length + q.1.modes + Rv + 2) ^ K ∧ - entryCertificate.space q ≤ - K * ((encPair (enc (encList encNat)) encBits q).length + q.1.modes + Rv + 2) ^ K := by +/-- **The resources of the native evaluator of descriptors.** For a native certificate `ce` of +the entry procedure of the roots, there is `K` such that on a descriptor and bits of total length +`n`, with `m` target modes and `L` row ports (`0` and `0` for a root), if the reduced coefficient +lists of a packet's precision are at most `Rv` bits long and `ce` takes time at most `E` and space +at most `ES` on a root and the bits, then with `Z = n + m + Rv + 2` the time is at most +`K (m + 2) ^ L Z ^ K + E` and the space at most `K Z ^ K + ES`. -/ +theorem entryCertificate_le + (ce : NativeCertificate (fun q : T × List Bool => ev q.1 q.2) (encPair encT encBits) + (encList encNat)) : + ∃ K : ℕ, ∀ (q : VertexDesc T × List Bool) (Rv E ES : ℕ), q.1.ReducedLE Rv → + (∀ t, q.1 = .inl t → ce.time (t, q.2) ≤ E ∧ ce.space (t, q.2) ≤ ES) → + (entryCertificate ce).time q ≤ K * (q.1.modes + 2) ^ q.1.rowPorts q.2 * + ((encPair (enc encT) encBits q).length + q.1.modes + Rv + 2) ^ K + E ∧ + (entryCertificate ce).space q ≤ + K * ((encPair (enc encT) encBits q).length + q.1.modes + Rv + 2) ^ K + ES := by obtain ⟨K₀, hK₀⟩ := vertexCertificate_le - have hR := NativeCertificate.ofPolyTime_isPolynomial getRight_polyTime - have hT := NativeCertificate.ofPolyTime_isPolynomial tableEntry_polyTime - have hI := NativeCertificate.ofPolyTime_isPolynomial packetInput_polyTime - obtain ⟨cr, dr, hrt⟩ := hR.1.exists_le - obtain ⟨cr', dr', hrs⟩ := hR.2.exists_le - obtain ⟨ct, dt, htt⟩ := hT.1.exists_le - obtain ⟨ct', dt', hts⟩ := hT.2.exists_le + have hL := NativeCertificate.ofPolyTime_isPolynomial (getLeft_polyTime (encT := encT)) + have hP := NativeCertificate.ofPolyTime_isPolynomial (packetInput_polyTime (encT := encT)) + have hI := NativeCertificate.ofPolyTime_isPolynomial (rootInput_polyTime (encT := encT)) + obtain ⟨cr, dr, hrt⟩ := hL.1.exists_le + obtain ⟨cr', dr', hrs⟩ := hL.2.exists_le + obtain ⟨cp, dp, hpt⟩ := hP.1.exists_le + obtain ⟨cp', dp', hps⟩ := hP.2.exists_le obtain ⟨ci, di, hit⟩ := hI.1.exists_le obtain ⟨ci', di', his⟩ := hI.2.exists_le - obtain ⟨D, hD⟩ : ∃ D, D = K₀ + dr + dr' + dt + dt' + di + di' + 1 := ⟨_, rfl⟩ - obtain ⟨G, hG⟩ : ∃ G, G = K₀ + 2 * cr + 2 * cr' + ct + ct' + ci * 3 ^ di + ci' * 3 ^ di' + 1 := + obtain ⟨D, hD⟩ : ∃ D, D = K₀ + dr + dr' + dp + dp' + di + di' + 1 := ⟨_, rfl⟩ + obtain ⟨G, hG⟩ : ∃ G, G = K₀ + 2 * cr + 2 * cr' + cp + cp' + ci * 3 ^ di + ci' * 3 ^ di' + 1 := ⟨_, rfl⟩ - refine ⟨G + D, fun q Rv hRv => ?_⟩ - obtain ⟨n, hn⟩ : ∃ n, n = (encPair (enc (encList encNat)) encBits q).length := ⟨_, rfl⟩ + refine ⟨G + D, fun q Rv E ES hRv hE => ?_⟩ + obtain ⟨n, hn⟩ : ∃ n, n = (encPair (enc encT) encBits q).length := ⟨_, rfl⟩ obtain ⟨Z, hZ⟩ : ∃ Z, Z = n + q.1.modes + Rv + 2 := ⟨_, rfl⟩ obtain ⟨P, hP⟩ : ∃ P, P = (q.1.modes + 2) ^ q.1.rowPorts q.2 := ⟨_, rfl⟩ rw [← hn, ← hZ, ← hP] have hP1 : 1 ≤ P := hP ▸ Nat.one_le_pow _ _ (by omega) have hnZ : n + 1 ≤ Z := by omega have hZD : Z ^ D ≤ Z ^ (G + D) := Nat.pow_le_pow_right (by omega) (by omega) - have hnD : n ≤ Z ^ D := by - calc n ≤ Z := by omega - _ = Z ^ 1 := (pow_one Z).symm - _ ≤ Z ^ D := Nat.pow_le_pow_right (by omega) (by omega) - have hrt' : (NativeCertificate.ofPolyTime getRight_polyTime).time q ≤ cr * Z ^ D := - (hrt q).trans (hn ▸ mul_pow_le_mul_pow hnZ (by omega)) - have hrs' : (NativeCertificate.ofPolyTime getRight_polyTime).space q ≤ cr' * Z ^ D := - (hrs q).trans (hn ▸ mul_pow_le_mul_pow hnZ (by omega)) - rcases q with ⟨d | d, bs⟩ - · -- A table: the lookup alone. - have htt' : (NativeCertificate.ofPolyTime tableEntry_polyTime).time (.inl d, bs) ≤ - ct * Z ^ D := (htt _).trans (hn ▸ mul_pow_le_mul_pow hnZ (by omega)) - have hts' : (NativeCertificate.ofPolyTime tableEntry_polyTime).space (.inl d, bs) ≤ - ct' * Z ^ D := (hts _).trans (hn ▸ mul_pow_le_mul_pow hnZ (by omega)) - have htime : entryCertificate.time (.inl d, bs) = - 2 * (NativeCertificate.ofPolyTime getRight_polyTime).time (.inl d, bs) + n + - (NativeCertificate.ofPolyTime tableEntry_polyTime).time (.inl d, bs) := by + have hrt' : (NativeCertificate.ofPolyTime (getLeft_polyTime (encT := encT))).time q ≤ + cr * Z ^ D := (hrt q).trans (hn ▸ mul_pow_le_mul_pow hnZ (by omega)) + have hrs' : (NativeCertificate.ofPolyTime (getLeft_polyTime (encT := encT))).space q ≤ + cr' * Z ^ D := (hrs q).trans (hn ▸ mul_pow_le_mul_pow hnZ (by omega)) + rcases q with ⟨t | d, bs⟩ + · -- A root: the input of the entry procedure, then the entry procedure. + obtain ⟨hEt, hEs⟩ : ce.time (t, bs) ≤ E ∧ ce.space (t, bs) ≤ ES := hE t rfl + have hlenI : (encPair (encPair (enc encT) encBits) encT ((.inl t, bs), t)).length + 1 ≤ + 3 * Z := by + have h1 : (encPair (encPair (enc encT) encBits) encT ((.inl t, bs), t)).length = + 2 * (encPair (enc encT) encBits (.inl t, bs)).length + 1 + (encT t).length := + length_encPair _ + have h2 : (encPair (enc encT) encBits (Sum.inl t, bs)).length = + 2 * ((enc encT) (.inl t)).length + 1 + (encBits bs).length := length_encPair _ + have h3 : ((enc encT) (Sum.inl t : VertexDesc T)).length = (encT t).length + 1 := by + rw [length_encSum]; rfl + omega + have hpow3 {c e : ℕ} (he : e ≤ D) : c * (3 * Z) ^ e ≤ c * 3 ^ e * Z ^ D := by + rw [Nat.mul_pow, ← Nat.mul_assoc] + exact Nat.mul_le_mul_left _ (Nat.pow_le_pow_right (by omega) he) + have hit' : (NativeCertificate.ofPolyTime (rootInput_polyTime (encT := encT))).time + ((.inl t, bs), t) ≤ ci * 3 ^ di * Z ^ D := + (hit _).trans ((Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hlenI _)).trans + (hpow3 (by omega))) + have his' : (NativeCertificate.ofPolyTime (rootInput_polyTime (encT := encT))).space + ((.inl t, bs), t) ≤ ci' * 3 ^ di' * Z ^ D := + (his _).trans ((Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hlenI _)).trans + (hpow3 (by omega))) + have htime : (entryCertificate ce).time (.inl t, bs) = + 2 * (NativeCertificate.ofPolyTime (getLeft_polyTime (encT := encT))).time (.inl t, bs) + + n + ((NativeCertificate.ofPolyTime (rootInput_polyTime (encT := encT))).time + ((.inl t, bs), t) + ce.time (t, bs)) := by rw [hn]; rfl - have hspace : entryCertificate.space (.inl d, bs) = - 2 * (NativeCertificate.ofPolyTime getRight_polyTime).space (.inl d, bs) + n + - (NativeCertificate.ofPolyTime tableEntry_polyTime).space (.inl d, bs) := by + have hspace : (entryCertificate ce).space (.inl t, bs) = + 2 * (NativeCertificate.ofPolyTime (getLeft_polyTime (encT := encT))).space (.inl t, bs) + + n + ((NativeCertificate.ofPolyTime (rootInput_polyTime (encT := encT))).space + ((.inl t, bs), t) + ce.space (t, bs)) := by rw [hn]; rfl + have hnD : n ≤ Z ^ D := by + calc n ≤ Z := by omega + _ = Z ^ 1 := (pow_one Z).symm + _ ≤ Z ^ D := Nat.pow_le_pow_right (by omega) (by omega) constructor · rw [htime] - calc _ ≤ G * Z ^ D := by - have : (2 * cr + 1 + ct) * Z ^ D ≤ G * Z ^ D := Nat.mul_le_mul_right _ (by omega) - have e : (2 * cr + 1 + ct) * Z ^ D = 2 * (cr * Z ^ D) + Z ^ D + ct * Z ^ D := by ring - omega - _ ≤ (G + D) * P * Z ^ (G + D) := - Nat.mul_le_mul ((Nat.le_add_right G D).trans (Nat.le_mul_of_pos_right _ hP1)) hZD + have h1 : 2 * (cr * Z ^ D) + Z ^ D + ci * 3 ^ di * Z ^ D ≤ G * Z ^ D := by + have : (2 * cr + 1 + ci * 3 ^ di) * Z ^ D ≤ G * Z ^ D := Nat.mul_le_mul_right _ (by omega) + have e : (2 * cr + 1 + ci * 3 ^ di) * Z ^ D = + 2 * (cr * Z ^ D) + Z ^ D + ci * 3 ^ di * Z ^ D := by ring + omega + have h2 : G * Z ^ D ≤ (G + D) * P * Z ^ (G + D) := + Nat.mul_le_mul ((Nat.le_add_right G D).trans (Nat.le_mul_of_pos_right _ hP1)) hZD + omega · rw [hspace] - calc _ ≤ G * Z ^ D := by - have : (2 * cr' + 1 + ct') * Z ^ D ≤ G * Z ^ D := Nat.mul_le_mul_right _ (by omega) - have e : (2 * cr' + 1 + ct') * Z ^ D = 2 * (cr' * Z ^ D) + Z ^ D + ct' * Z ^ D := by - ring - omega - _ ≤ (G + D) * Z ^ (G + D) := Nat.mul_le_mul (by omega) hZD + have h1 : 2 * (cr' * Z ^ D) + Z ^ D + ci' * 3 ^ di' * Z ^ D ≤ G * Z ^ D := by + have : (2 * cr' + 1 + ci' * 3 ^ di') * Z ^ D ≤ G * Z ^ D := + Nat.mul_le_mul_right _ (by omega) + have e : (2 * cr' + 1 + ci' * 3 ^ di') * Z ^ D = + 2 * (cr' * Z ^ D) + Z ^ D + ci' * 3 ^ di' * Z ^ D := by ring + omega + have h2 : G * Z ^ D ≤ (G + D) * Z ^ (G + D) := Nat.mul_le_mul (by omega) hZD + omega · -- A packet: the input of the packet evaluator, then the evaluator. - have hn' : n = 2 * ((encPacketDesc d).length + 1) + 1 + (encBits bs).length := by - rw [hn]; exact length_encPair _ + have hpt' : (NativeCertificate.ofPolyTime (packetInput_polyTime (encT := encT))).time + (.inr d, bs) ≤ cp * Z ^ D := + (hpt _).trans (hn ▸ mul_pow_le_mul_pow hnZ (by omega)) + have hps' : (NativeCertificate.ofPolyTime (packetInput_polyTime (encT := encT))).space + (.inr d, bs) ≤ cp' * Z ^ D := + (hps _).trans (hn ▸ mul_pow_le_mul_pow hnZ (by omega)) have hlen : (encPair encPacketDesc encBits (d, bs)).length ≤ n := by + have h1 : n = 2 * ((encPacketDesc d).length + 1) + 1 + (encBits bs).length := by + rw [hn]; exact length_encPair _ have h3 : (encPair encPacketDesc encBits (d, bs)).length = 2 * (encPacketDesc d).length + 1 + (encBits bs).length := length_encPair _ omega - have hlenI : (encPair (encPair (enc (encList encNat)) encBits) encPacketDesc - ((.inr d, bs), d)).length + 1 ≤ 3 * Z := by - have h1 : (encPair (encPair (enc (encList encNat)) encBits) encPacketDesc - ((.inr d, bs), d)).length = - 2 * (encPair (enc (encList encNat)) encBits (.inr d, bs)).length + 1 + - (encPacketDesc d).length := - length_encPair _ - omega - have hpow3 {c e : ℕ} (he : e ≤ D) : c * (3 * Z) ^ e ≤ c * 3 ^ e * Z ^ D := by - rw [Nat.mul_pow, ← Nat.mul_assoc] - exact Nat.mul_le_mul_left _ (Nat.pow_le_pow_right (by omega) he) - have hit' : (NativeCertificate.ofPolyTime packetInput_polyTime).time ((.inr d, bs), d) ≤ - ci * 3 ^ di * Z ^ D := - (hit _).trans ((Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hlenI _)).trans - (hpow3 (by omega))) - have his' : (NativeCertificate.ofPolyTime packetInput_polyTime).space ((.inr d, bs), d) ≤ - ci' * 3 ^ di' * Z ^ D := - (his _).trans ((Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hlenI _)).trans - (hpow3 (by omega))) obtain ⟨hvt, hvs⟩ := hK₀ (d, bs) Rv hRv have hZ' : (encPair encPacketDesc encBits (d, bs)).length + (targetModes d.1).length + Rv + 2 ≤ Z := by rw [hZ]; simp only [modes]; omega @@ -324,38 +339,67 @@ theorem entryCertificate_le : exact Nat.mul_le_mul_left _ hpowK have hvs' : vertexCertificate.space (d, bs) ≤ K₀ * Z ^ D := hvs.trans (Nat.mul_le_mul_left _ hpowK) - have htime : entryCertificate.time (.inr d, bs) = - 2 * (NativeCertificate.ofPolyTime getRight_polyTime).time (.inr d, bs) + n + - ((NativeCertificate.ofPolyTime packetInput_polyTime).time ((.inr d, bs), d) + - vertexCertificate.time (d, bs)) := by + have htime : (entryCertificate ce).time (.inr d, bs) = + 2 * (NativeCertificate.ofPolyTime (getLeft_polyTime (encT := encT))).time (.inr d, bs) + + n + ((NativeCertificate.ofPolyTime (packetInput_polyTime (encT := encT))).time + (.inr d, bs) + vertexCertificate.time (d, bs)) := by rw [hn]; rfl - have hspace : entryCertificate.space (.inr d, bs) = - 2 * (NativeCertificate.ofPolyTime getRight_polyTime).space (.inr d, bs) + n + - ((NativeCertificate.ofPolyTime packetInput_polyTime).space ((.inr d, bs), d) + - vertexCertificate.space (d, bs)) := by + have hspace : (entryCertificate ce).space (.inr d, bs) = + 2 * (NativeCertificate.ofPolyTime (getLeft_polyTime (encT := encT))).space (.inr d, bs) + + n + ((NativeCertificate.ofPolyTime (packetInput_polyTime (encT := encT))).space + (.inr d, bs) + vertexCertificate.space (d, bs)) := by rw [hn]; rfl + have hnD : n ≤ Z ^ D := by + calc n ≤ Z := by omega + _ = Z ^ 1 := (pow_one Z).symm + _ ≤ Z ^ D := Nat.pow_le_pow_right (by omega) (by omega) constructor · rw [htime] - have h1 : 2 * (cr * Z ^ D) + Z ^ D + ci * 3 ^ di * Z ^ D ≤ - P * ((2 * cr + 1 + ci * 3 ^ di) * Z ^ D) := by - calc _ = (2 * cr + 1 + ci * 3 ^ di) * Z ^ D := by ring + have h1 : 2 * (cr * Z ^ D) + Z ^ D + cp * Z ^ D ≤ P * ((2 * cr + 1 + cp) * Z ^ D) := by + calc _ = (2 * cr + 1 + cp) * Z ^ D := by ring _ ≤ _ := Nat.le_mul_of_pos_left _ hP1 - have h2 : P * ((2 * cr + 1 + ci * 3 ^ di) * Z ^ D) + K₀ * P * Z ^ D ≤ P * (G * Z ^ D) := by + have h2 : P * ((2 * cr + 1 + cp) * Z ^ D) + K₀ * P * Z ^ D ≤ P * (G * Z ^ D) := by rw [show K₀ * P * Z ^ D = P * (K₀ * Z ^ D) by ring, ← Nat.mul_add, ← Nat.add_mul] exact Nat.mul_le_mul_left _ (Nat.mul_le_mul_right _ (by omega)) - calc _ ≤ P * (G * Z ^ D) := by omega - _ ≤ (G + D) * P * Z ^ (G + D) := by - rw [show (G + D) * P * Z ^ (G + D) = P * ((G + D) * Z ^ (G + D)) by ring] - exact Nat.mul_le_mul_left _ (Nat.mul_le_mul (by omega) hZD) + have h3 : P * (G * Z ^ D) ≤ (G + D) * P * Z ^ (G + D) := by + rw [show (G + D) * P * Z ^ (G + D) = P * ((G + D) * Z ^ (G + D)) by ring] + exact Nat.mul_le_mul_left _ (Nat.mul_le_mul (by omega) hZD) + omega · rw [hspace] - calc _ ≤ G * Z ^ D := by - have : (2 * cr' + 1 + ci' * 3 ^ di' + K₀) * Z ^ D ≤ G * Z ^ D := - Nat.mul_le_mul_right _ (by omega) - have e : (2 * cr' + 1 + ci' * 3 ^ di' + K₀) * Z ^ D = - 2 * (cr' * Z ^ D) + Z ^ D + ci' * 3 ^ di' * Z ^ D + K₀ * Z ^ D := by ring - omega - _ ≤ (G + D) * Z ^ (G + D) := Nat.mul_le_mul (by omega) hZD + have h1 : 2 * (cr' * Z ^ D) + Z ^ D + cp' * Z ^ D + K₀ * Z ^ D ≤ G * Z ^ D := by + have : (2 * cr' + 1 + cp' + K₀) * Z ^ D ≤ G * Z ^ D := Nat.mul_le_mul_right _ (by omega) + have e : (2 * cr' + 1 + cp' + K₀) * Z ^ D = + 2 * (cr' * Z ^ D) + Z ^ D + cp' * Z ^ D + K₀ * Z ^ D := by ring + omega + have h2 : G * Z ^ D ≤ (G + D) * Z ^ (G + D) := Nat.mul_le_mul (by omega) hZD + omega + +end Evaluator end VertexDesc +/-! ### Tables -/ + +/-- The entry procedure of tables is polynomial-time. -/ +theorem tableEntry_polyTime : + ComputableInPolyTime (fun q : List ℕ × List Bool => tableEntry q.1 q.2) + (encPair (encList encNat) encBits) (encList encNat) := by + have hindex := ComputableInPolyTime.bitsBinaryValue.comp + (ComputableInPolyTime.bitsReverse.comp (ComputableInPolyTime.snd (encList encNat) encBits)) + have hentry := ComputableInPolyTime.listGetD_binary (encA := encNat) (encL := encList encNat) 0 + (ComputableInPolyTime.fst _ _) hindex + exact (ComputableInPolyTime.cons' hentry (ComputableInPolyTime.const [])).of_enc_eq fun q => by + simp only [tableEntry, ExplicitTensorNetwork.entry, + BitString.lsbValue_eq_binaryValue_reverse, Function.comp_apply] + +/-- **The native certificate of the entry procedure of tables.** -/ +noncomputable def tableEntryCertificate : + NativeCertificate (fun q : List ℕ × List Bool => tableEntry q.1 q.2) + (encPair (encList encNat) encBits) (encList encNat) := + NativeCertificate.ofPolyTime tableEntry_polyTime + +/-- The certificate of the entry procedure of tables is polynomial. -/ +theorem tableEntryCertificate_isPolynomial : tableEntryCertificate.IsPolynomial := + NativeCertificate.ofPolyTime_isPolynomial tableEntry_polyTime + end Cslib.Circuits.Frontier diff --git a/Complexity/Computability/Complexity/Classes/CountingSimulation/FastAlgorithm.lean b/Complexity/Computability/Complexity/Classes/CountingSimulation/FastAlgorithm.lean index 483fcbb67..0348e3bde 100644 --- a/Complexity/Computability/Complexity/Classes/CountingSimulation/FastAlgorithm.lean +++ b/Complexity/Computability/Complexity/Classes/CountingSimulation/FastAlgorithm.lean @@ -316,7 +316,8 @@ whose leaves take time at most `TL` and space at most `SL`, with `H` open calls, (s₀ ≤ s → 2 * N - 1 ≤ fuel (ExplicitTensorNetwork.capPrecision (P, G))) ∧ (∀ x, I.node x → (encCall (encList encNat) x).length ≤ F ∧ ((scheme tableEntry mk).isLeaf x = true → - (leafCertificate mk).time x ≤ TL ∧ (leafCertificate mk).space x ≤ SL)) ∧ + (leafCertificate tableEntryCertificate mk).time x ≤ TL ∧ + (leafCertificate tableEntryCertificate mk).space x ≤ SL)) ∧ (∀ x a, I.frame x a → (encPair (encCall (encList encNat)) encFrame (x, a)).length ≤ F) ∧ (∀ v, I.value v → (encValue v).length ≤ F) ∧ H + F + SL ≤ K * ((FastContraction.encInput (P, G)).length + 1) ^ K ∧ @@ -374,7 +375,7 @@ theorem fastCertificate_le (fastCertificate hpoly).space (P, G) ≤ K * ((FastContraction.encInput (P, G)).length + 1) ^ K := by obtain ⟨Ka, s₀, hKa⟩ := hana C D - obtain ⟨K₁, hK₁⟩ := Scheme.certificate_le hpoly (leafCertificate mk) + obtain ⟨K₁, hK₁⟩ := Scheme.certificate_le hpoly (leafCertificate tableEntryCertificate mk) obtain ⟨K₂, hK₂⟩ := ExplicitTensorNetwork.exists_directContractionBinaryCertificate_le have hcapP := NativeCertificate.ofPolyTime_isPolynomial ExplicitTensorNetwork.capPrecision_polyTime diff --git a/Complexity/Computability/Complexity/Classes/CountingSimulation/FastAnalysis.lean b/Complexity/Computability/Complexity/Classes/CountingSimulation/FastAnalysis.lean index ff5135680..977c11192 100644 --- a/Complexity/Computability/Complexity/Classes/CountingSimulation/FastAnalysis.lean +++ b/Complexity/Computability/Complexity/Classes/CountingSimulation/FastAnalysis.lean @@ -195,10 +195,10 @@ summation at every reached call that the machine treats as a leaf takes time at ∀ C D : ℕ, ∃ K : ℕ, ∀ (s P : ℕ) (G : ℕ × ExplicitTensorNetwork ℕ), 2 ≤ s → 1 ≤ P → P ≤ D * s → ExplicitAdmissible C s G → fastGuard G = true → ∀ x, Reach nativeMk (root (ExplicitTensorNetwork.capPrecision (P, G))) x → active x = false → - (leafCertificate nativeMk).time x ≤ + (leafCertificate tableEntryCertificate nativeMk).time x ≤ K * ((FastContraction.encInput (P, G)).length + 1) ^ K * 2 ^ (K * s / Nat.sqrt (Nat.log 2 s)) ∧ - (leafCertificate nativeMk).space x ≤ + (leafCertificate tableEntryCertificate nativeMk).space x ≤ K * ((FastContraction.encInput (P, G)).length + 1) ^ K /-- `a B ^ a ≤ a B ^ K` for `1 ≤ B` and `a ≤ K`. -/ diff --git a/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkVertexDesc.lean b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkVertexDesc.lean index e84885bb7..1d6bac050 100644 --- a/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkVertexDesc.lean +++ b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkVertexDesc.lean @@ -27,7 +27,8 @@ list come out in order. Reducing an element of `O` to `A_n` and mapping back alo namespace ComplexityTests.TensorNetworkVertexDesc open Cslib Cslib.Circuits.Frontier Cslib.Circuits.Frontier.NativePacket -open Turing.MultiTapeTM (encList encNat) +open Turing.MultiTapeTM (encList encNat encPair encBits) +open Cslib.GenericRAM (NativeCertificate) /-! ### Tables -/ @@ -86,16 +87,21 @@ example : sidePorts ([4, 1, 2].map fun c => (decide (c % 2 = 0), c)) ([4, 1, 2]. /-! ### Resources -/ -example : ∃ K : ℕ, ∀ (q : VertexDesc (List ℕ) × List Bool) (Rv : ℕ), q.1.ReducedLE Rv → - VertexDesc.entryCertificate.time q ≤ K * (q.1.modes + 2) ^ q.1.rowPorts q.2 * - ((Turing.MultiTapeTM.encPair (VertexDesc.enc (encList encNat)) Turing.MultiTapeTM.encBits - q).length + - q.1.modes + Rv + 2) ^ K ∧ - VertexDesc.entryCertificate.space q ≤ - K * ((Turing.MultiTapeTM.encPair (VertexDesc.enc (encList encNat)) - Turing.MultiTapeTM.encBits q).length + - q.1.modes + Rv + 2) ^ K := - VertexDesc.entryCertificate_le +-- The bounds of the evaluator, for every native certificate of the entry procedure of the roots: +-- the root's own time and space are added. +example {T : Type} {encT : T ↪ List Bool} {ev : T → List Bool → List ℕ} + (ce : NativeCertificate (fun q : T × List Bool => ev q.1 q.2) (encPair encT encBits) + (encList encNat)) : + ∃ K : ℕ, ∀ (q : VertexDesc T × List Bool) (Rv E ES : ℕ), q.1.ReducedLE Rv → + (∀ t, q.1 = .inl t → ce.time (t, q.2) ≤ E ∧ ce.space (t, q.2) ≤ ES) → + (VertexDesc.entryCertificate ce).time q ≤ K * (q.1.modes + 2) ^ q.1.rowPorts q.2 * + ((encPair (VertexDesc.enc encT) encBits q).length + q.1.modes + Rv + 2) ^ K + E ∧ + (VertexDesc.entryCertificate ce).space q ≤ + K * ((encPair (VertexDesc.enc encT) encBits q).length + q.1.modes + Rv + 2) ^ K + ES := + VertexDesc.entryCertificate_le ce + +-- The entry procedure of tables has a polynomial native certificate. +example : tableEntryCertificate.IsPolynomial := tableEntryCertificate_isPolynomial /-! ### Back from `A_n` to `O / (2 ^ n)` -/ From 21015c239ac53b1faad55b04c940dcc7489cb36b Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 10:43:12 -0400 Subject: [PATCH 12/20] refactor(Frontier/TensorNetwork): drop the table term from the leaf's reduced-list helper Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG --- .../TensorNetwork/FastContractionLeaf.lean | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionLeaf.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionLeaf.lean index 85f43339c..4fba5a66f 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionLeaf.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionLeaf.lean @@ -142,10 +142,9 @@ private theorem mul_pow_le_mul_pow {c W d E : ℕ} (hW : 1 ≤ W) (hd : d ≤ E) Nat.mul_le_mul_left _ (Nat.pow_le_pow_right hW hd) /-- The reduced coefficient lists against `W`. -/ -private theorem rv_le {n W cf df cp dp ct dt : ℕ} (hnW : n + 1 ≤ W) : - n * (2 * n + 3) + cf * (n + 1) ^ df * (2 * (cp * (n + 1) ^ dp) + 3) + - ct * (3 * n + 2) ^ dt ≤ - (5 + cf * (2 * cp + 3) + ct * 3 ^ dt) * W ^ (2 + df + dp + dt) := by +private theorem rv_le {n W cf df cp dp : ℕ} (hnW : n + 1 ≤ W) : + n * (2 * n + 3) + cf * (n + 1) ^ df * (2 * (cp * (n + 1) ^ dp) + 3) ≤ + (5 + cf * (2 * cp + 3)) * W ^ (2 + df + dp) := by have hW1 : 1 ≤ W := by omega have h1 : n * (2 * n + 3) ≤ 5 * W ^ 2 := calc n * (2 * n + 3) ≤ W * (5 * W) := Nat.mul_le_mul (by omega) (by omega) @@ -161,16 +160,10 @@ private theorem rv_le {n W cf df cp dp ct dt : ℕ} (hnW : n + 1 ≤ W) : ≤ cf * W ^ df * ((2 * cp + 3) * W ^ dp) := Nat.mul_le_mul (Nat.mul_le_mul_left _ hb1) this _ = cf * (2 * cp + 3) * W ^ (df + dp) := by rw [pow_add]; ring - have h3 : ct * (3 * n + 2) ^ dt ≤ ct * 3 ^ dt * W ^ dt := - calc ct * (3 * n + 2) ^ dt ≤ ct * (3 * W) ^ dt := - Nat.mul_le_mul_left _ (Nat.pow_le_pow_left (by omega) _) - _ = ct * 3 ^ dt * W ^ dt := by rw [mul_pow]; ring - have l1 : 5 * W ^ 2 ≤ 5 * W ^ (2 + df + dp + dt) := mul_pow_le_mul_pow hW1 (by omega) - have l2 : cf * (2 * cp + 3) * W ^ (df + dp) ≤ cf * (2 * cp + 3) * W ^ (2 + df + dp + dt) := + have l1 : 5 * W ^ 2 ≤ 5 * W ^ (2 + df + dp) := mul_pow_le_mul_pow hW1 (by omega) + have l2 : cf * (2 * cp + 3) * W ^ (df + dp) ≤ cf * (2 * cp + 3) * W ^ (2 + df + dp) := mul_pow_le_mul_pow hW1 (by omega) - have l3 : ct * 3 ^ dt * W ^ dt ≤ ct * 3 ^ dt * W ^ (2 + df + dp + dt) := - mul_pow_le_mul_pow hW1 (by omega) - rw [add_mul, add_mul] + rw [add_mul] omega /-- The input of direct summation against `W`. -/ @@ -318,8 +311,8 @@ theorem leafCertificate_le obtain ⟨cp, dp, hp⟩ := PacketCtx.p_polyTime.polyBounded_length.exists_le obtain ⟨cf, df, hf⟩ := PacketCtx.fl_polyTime.polyBounded_length.exists_le -- The constants. - obtain ⟨e, he⟩ : ∃ e, e = 2 + df + dp + 0 := ⟨_, rfl⟩ - obtain ⟨cR, hcR⟩ : ∃ cR, cR = 5 + cf * (2 * cp + 3) + 0 * 3 ^ 0 + cE := ⟨_, rfl⟩ + obtain ⟨e, he⟩ : ∃ e, e = 2 + df + dp := ⟨_, rfl⟩ + obtain ⟨cR, hcR⟩ : ∃ cR, cR = 5 + cf * (2 * cp + 3) + cE := ⟨_, rfl⟩ obtain ⟨E₀, hE₀⟩ : ∃ E₀, E₀ = dl + e := ⟨_, rfl⟩ obtain ⟨c₁, hc₁⟩ : ∃ c₁, c₁ = cl + 2 * cR + 1 := ⟨_, rfl⟩ obtain ⟨c₂, hc₂⟩ : ∃ c₂, c₂ = 3 + cR := ⟨_, rfl⟩ @@ -346,7 +339,7 @@ theorem leafCertificate_le omega -- The reduced coefficient lists, and the outputs of the roots. obtain ⟨Rv, hRv⟩ : ∃ Rv, Rv = n * (2 * n + 3) + - cf * (n + 1) ^ df * (2 * (cp * (n + 1) ^ dp) + 3) + 0 * (3 * n + 2) ^ 0 := ⟨_, rfl⟩ + cf * (n + 1) ^ df * (2 * (cp * (n + 1) ^ dp) + 3) := ⟨_, rfl⟩ obtain ⟨Ev, hEv⟩ : ∃ Ev, Ev = Rv + cE * (ES + 1) := ⟨_, rfl⟩ have hred : ∀ y, SumOps.galois.Reduced (x.prec, x.fl) y → (encList encNat y).length ≤ Rv := by intro y hy @@ -415,7 +408,7 @@ theorem leafCertificate_le -- Polynomial pieces against `W`. have hk : x.net.vertices.length + 1 ≤ W := by have := length_vertices_le encT x; omega have hRvW : Rv ≤ (cR - cE) * W ^ e := by - have h := rv_le (ct := 0) (dt := 0) (cf := cf) (df := df) (cp := cp) (dp := dp) hnW + have h := rv_le (cf := cf) (df := df) (cp := cp) (dp := dp) hnW rw [hRv, he] refine h.trans (Nat.mul_le_mul_right _ ?_) omega From 8c0bc44c9cc0c45d39bb656b3f965858f262d8c3 Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 11:06:07 -0400 Subject: [PATCH 13/20] feat(Frontier/TensorNetwork): native machine of the contraction with entry procedures Drops the copies of tableEntry and its certificate from EntryContraction.lean (VertexDesc.lean's win) and adds the guarded entry machine: the guard and its polynomial-time test, the root call and clock, the result and its correctness at the modulus of the number of edges, and the native certificate. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG --- .../TensorNetwork/EntryContraction.lean | 31 +- .../EntryContractionMachine.lean | 446 ++++++++++++++++++ 2 files changed, 447 insertions(+), 30 deletions(-) create mode 100644 Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContractionMachine.lean diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContraction.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContraction.lean index 3cc68d662..bb2367e83 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContraction.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContraction.lean @@ -64,7 +64,7 @@ admissible inputs that is `K (n + 1) ^ K 2 ^ (K s)` and polynomial space **Instances.** A polynomial-time entry procedure meets the entry bounds from some constant on (`EntryContraction.exists_entryAdmissible_of_isPolynomial`), so admissibility reduces to the -shape of the network. Tables are the entry procedure `EntryContraction.tableEntry`, and direct +shape of the network. Tables are the entry procedure `tableEntry` (`VertexDesc.lean`), and direct summation with it is the contraction of the explicit network (`EntryContraction.val_directCore_tableEntry`). @@ -75,8 +75,6 @@ summation with it is the contraction of the explicit network * `Cslib.Circuits.Frontier.EntryAdmissible`: Theorem D.1's hypotheses. * `Cslib.Circuits.Frontier.EntryContractionAlgorithm`: the interface. * `Cslib.Circuits.Frontier.EntryContraction.directCore`: direct summation with an entry procedure. -* `Cslib.Circuits.Frontier.EntryContraction.tableEntry`, - `Cslib.Circuits.Frontier.EntryContraction.tableEntryCertificate`: the entry procedure of tables. ## Main results @@ -554,33 +552,6 @@ theorem exists_entryAdmissible_of_isPolynomial (Nat.le_mul_of_pos_right _ Nat.one_le_two_pow))), (hs _).trans (hpow.trans (hBC (by omega) (by omega)))⟩ -/-- **The entry procedure of tables**: the table entry at the bits on the ports, as a constant -coefficient list. -/ -@[expose] def tableEntry (table : List ℕ) (bs : List Bool) : List ℕ := - [ExplicitTensorNetwork.entry table bs] - -/-- The entry procedure of tables is polynomial-time. -/ -theorem tableEntry_polyTime : - ComputableInPolyTime (fun q : List ℕ × List Bool => tableEntry q.1 q.2) - (encPair (encList encNat) encBits) (encList encNat) := by - have hindex := ComputableInPolyTime.bitsBinaryValue.comp - (ComputableInPolyTime.bitsReverse.comp (ComputableInPolyTime.snd (encList encNat) encBits)) - have hentry := ComputableInPolyTime.listGetD_binary (encA := encNat) (encL := encList encNat) 0 - (ComputableInPolyTime.fst _ _) hindex - exact (ComputableInPolyTime.cons' hentry (ComputableInPolyTime.const [])).of_enc_eq fun q => by - simp only [tableEntry, ExplicitTensorNetwork.entry, - BitString.lsbValue_eq_binaryValue_reverse, Function.comp_apply] - -/-- **The native certificate of the entry procedure of tables.** -/ -noncomputable def tableEntryCertificate : - NativeCertificate (fun q : List ℕ × List Bool => tableEntry q.1 q.2) - (encPair (encList encNat) encBits) (encList encNat) := - NativeCertificate.ofPolyTime tableEntry_polyTime - -/-- The certificate of the entry procedure of tables is polynomial. -/ -theorem tableEntryCertificate_isPolynomial : tableEntryCertificate.IsPolynomial := - NativeCertificate.ofPolyTime_isPolynomial tableEntry_polyTime - /-- **Direct summation of a table network is its contraction**, in `A_P` at every modulus. -/ theorem val_directCore_tableEntry (P : ℕ) (fl : List ℕ) (G : ExplicitTensorNetwork ℕ) : val P fl (DescribedNetwork.sumValue SumOps.galois tableEntry (P, fl) G) = diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContractionMachine.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContractionMachine.lean new file mode 100644 index 000000000..573974bd1 --- /dev/null +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContractionMachine.lean @@ -0,0 +1,446 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.EntryContraction +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.FastContractionPolyTime +import Complexity.Computability.Machines.Turing.MultiTape.Complexity.PolyTime.List +import Complexity.Computability.Machines.Turing.MultiTape.Complexity.PolyTime.Nat +import Complexity.Computability.Machines.Turing.MultiTape.Complexity.PolyTime.Nat.Binary +import Complexity.Computability.Machines.Turing.MultiTape.Complexity.PolyTime.Nat.SqrtLog +import Complexity.Computability.Machines.Turing.MultiTape.Internal.EqualityPrimitives +import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimeBinaryPrimitives +import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimeListPrimitives +import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimeNatFrontends +import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimePrimitives + +/-! +# The native machine of the contraction with entry procedures + +The machine behind the instance of the contraction interface for entry procedures +(`Cslib.Circuits.Frontier.EntryContractionAlgorithm`, milestone E1.3 of #1538): the recursion of +Theorem D.1 of [OpenAI2026ETH] (`FastContraction.scheme` with the native child builder) run from +a root call whose descriptors are the vertex descriptors of the input network, read by the entry +procedure, with direct summation as the fallback. + +**The input** `(P, fl, r, G)` has the precision `P` in unary (`EntryContraction.encInput`), so the +precision is not capped: the cap at the encoded length of the network that the explicit machine +uses (`ExplicitTensorNetwork.capPrecision`) keeps the residue only for tables of natural numbers. + +**The guard** (`EntryContraction.guard`) checks that `fl` is the modulus `FastContraction.modulus m` +of the number `m` of edges, that the network is rows-first bipartite, and that every vertex has at +most `degreeBound m` ports. It is polynomial-time (`EntryContraction.guard_polyTime`), and every +admissible input at the modulus passes it (`EntryContraction.guard_of_entryAdmissible`), since +`⌈s ^ (9/10)⌉ ≤ degreeBound s ≤ degreeBound m`. + +**The root and the clock.** The root call (`EntryContraction.rootCall`) has scale `m`, depth `0`, +edge bound `m + 1`, precision `P`, modulus `fl`, `r` rows and the network +`FastContraction.rootNet G`. The clock (`EntryContraction.clock`) is +`2 ^ (K₀ (m + P) / √⌊log₂ (m + P)⌋)`, as for explicit networks. On guarded inputs the root is well-formed (`EntryContraction.wf_rootCall`). + +**The result** (`EntryContraction.coreValue`): on guarded inputs, the coefficient list of a value +tagged `0` returned by the clocked run, and direct summation otherwise. It is correct at the modulus +of the number of edges for every fuel (`EntryContraction.val_coreValue`), from the correctness of +the recursion (`FastContraction.val_value`) and the root (`FastContraction.contraction_rootNet`). +Its native certificate is `EntryContraction.fastCore`; its resources are analyzed in +`Cslib.Complexity.CountingSimulation.EntryAnalysis`. + +## Main definitions + +* `Cslib.Circuits.Frontier.EntryContraction.guard`: the guard. +* `Cslib.Circuits.Frontier.EntryContraction.rootCall`, `EntryContraction.clock`: the root call and + the clock. +* `Cslib.Circuits.Frontier.EntryContraction.coreValue`: the result of the machine. +* `Cslib.Circuits.Frontier.EntryContraction.runCore`, `EntryContraction.fastCore`: the clocked run + and the machine. + +## Main results + +* `Cslib.Circuits.Frontier.FastContraction.contraction_rootNet`: the root network computes the + contraction of the network, for every entry procedure. +* `Cslib.Circuits.Frontier.DescribedNetwork.rowsFirst_polyTime`: rows-first bipartiteness is + decidable in polynomial time. +* `Cslib.Circuits.Frontier.EntryContraction.guard_polyTime`: the guard is polynomial-time. +* `Cslib.Circuits.Frontier.EntryContraction.guard_of_entryAdmissible`: admissible inputs pass it. +* `Cslib.Circuits.Frontier.EntryContraction.wf_rootCall`: guarded roots are well-formed. +* `Cslib.Circuits.Frontier.EntryContraction.val_coreValue`: the machine is correct. + +## References + +* [OpenAI, *The Exponential Time Hypothesis is False*][OpenAI2026ETH], Theorem D.1 (p. 53) and + Appendix D.4.7 (p. 64). +-/ + +public section + +namespace Cslib.Circuits.Frontier + +open GaloisRingArith Cslib.GenericRAM Cslib.GenericRAM.StackRecursion Turing.MultiTapeTM + ContractionSchedule + +variable {T : Type} + +/-! ### The root network -/ + +/-- **The root network computes the contraction**, for every entry procedure `ev` and every map +`f` of its outputs to a commutative semiring: reading the root descriptors through +`VertexDesc.entry ev` is reading the descriptors of `G` through `ev`. -/ +theorem FastContraction.contraction_rootNet {R : Type*} [CommSemiring R] (f : List ℕ → R) + (ev : T → List Bool → List ℕ) (G : DescribedNetwork T) : + (FastContraction.rootNet G).contraction (fun d bs => f (VertexDesc.entry ev d bs)) = + G.contraction fun t bs => f (ev t bs) := by + simp only [DescribedNetwork.contraction, FastContraction.rootNet, List.map_map] + rfl + +/-! ### Rows-first bipartiteness in polynomial time -/ + +namespace DescribedNetwork + +section RowsFirst + +variable {encT : T ↪ List Bool} + +/-- Rows-first bipartiteness as a conjunction of list tests. -/ +private def rowsTest (G : ℕ × DescribedNetwork T) : Bool := + G.2.vertices.all (fun v => v.1.all fun i => decide (i < G.2.numEdges)) && + (List.range G.2.numEdges).all (fun i => + decide (((G.2.vertices.take G.1).flatMap Prod.fst).count i = 1) && + decide (((G.2.vertices.drop G.1).flatMap Prod.fst).count i = 1)) + +private theorem decide_eq_rowsTest (G : ℕ × DescribedNetwork T) : + decide (G.2.IsRowsFirstBipartite G.1) = rowsTest G := by + refine Bool.eq_iff_iff.mpr ?_ + simp only [rowsTest, DescribedNetwork.IsRowsFirstBipartite, decide_eq_true_eq, Bool.and_eq_true, + List.all_eq_true, List.mem_range, List.count_flatMap, Function.comp_def] + +/-- **Rows-first bipartiteness is polynomial-time**, from a network with its number of rows. -/ +theorem rowsFirst_polyTime : + ComputableInPolyTime (fun G : ℕ × DescribedNetwork T => decide (G.2.IsRowsFirstBipartite G.1)) + (encPair encNat (encDescribed encT)) encBool := by + have hpair : ComputableInPolyTime (DescribedNetwork.equivProd (T := T)) (encDescribed encT) + (encPair encUnary (encList (encPair (encList encNat) encT))) := + ComputableInPolyTime.of_eq fun _ => rfl + have hd := ComputableInPolyTime.snd encNat (encDescribed encT) + have hr := ComputableInPolyTime.fst encNat (encDescribed encT) + have hm : ComputableInPolyTime (fun G : ℕ × DescribedNetwork T => G.2.numEdges) + (encPair encNat (encDescribed encT)) encUnary := + (ComputableInPolyTime.fst _ _).comp (hpair.comp hd) + have hvs : ComputableInPolyTime (fun G : ℕ × DescribedNetwork T => G.2.vertices) + (encPair encNat (encDescribed encT)) (encList (encPair (encList encNat) encT)) := + (ComputableInPolyTime.snd _ _).comp (hpair.comp hd) + -- Ports in range. + have h1 : ComputableInPolyTime (fun G : ℕ × DescribedNetwork T => + G.2.vertices.all (fun v => v.1.all fun i => decide (i < G.2.numEdges))) + (encPair encNat (encDescribed encT)) encBool := by + refine ComputableInPolyTime.allWithInput hvs ?_ + refine ComputableInPolyTime.allWithInput + ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _)) ?_ + exact ComputableInPolyTime.binary_lt.comp ((ComputableInPolyTime.snd _ _).prod + (ComputableInPolyTime.unary_to_binary.comp (hm.comp ((ComputableInPolyTime.fst _ _).comp + (ComputableInPolyTime.fst _ _))))) + -- Each edge has one row port and one column port. + have hlen := (ComputableInPolyTime.length_list _).comp hvs + have hcap := ComputableInPolyTime.binary_min_unary' hlen hr + have htake : ComputableInPolyTime (fun G : ℕ × DescribedNetwork T => + G.2.vertices.take (min G.2.vertices.length G.1)) (encPair encNat (encDescribed encT)) + (encList (encPair (encList encNat) encT)) := + .of_tidy (ComputableTidilyInPolyTime.listTakeWithInput hvs.tidy hcap.tidy) + have hdrop : ComputableInPolyTime (fun G : ℕ × DescribedNetwork T => + G.2.vertices.drop (min G.2.vertices.length G.1)) (encPair encNat (encDescribed encT)) + (encList (encPair (encList encNat) encT)) := + .of_tidy (ComputableTidilyInPolyTime.listDropWithInput hvs.tidy hcap.tidy) + have hflat {l : ℕ × DescribedNetwork T → List (List ℕ × T)} + (hl : ComputableInPolyTime l (encPair encNat (encDescribed encT)) + (encList (encPair (encList encNat) encT))) : + ComputableInPolyTime (fun G => (l G).flatMap Prod.fst) (encPair encNat (encDescribed encT)) + (encList encNat) := + ComputableInPolyTime.flatMapWithInput (f := fun _ v => v.1) hl + ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _)) + have hcount {l : ℕ × DescribedNetwork T → List ℕ} + (hl : ComputableInPolyTime l (encPair encNat (encDescribed encT)) (encList encNat)) : + ComputableInPolyTime (fun p : (ℕ × DescribedNetwork T) × ℕ => + decide ((l p.1).count p.2 = 1)) + (encPair (encPair encNat (encDescribed encT)) encUnary) encBool := by + have hc := ComputableInPolyTime.countPWithInput (test := fun p a => decide (a = p.2)) + (hl.comp (ComputableInPolyTime.fst (encPair encNat (encDescribed encT)) encUnary)) + (ComputableInPolyTime.decide_eq' (ComputableInPolyTime.snd _ _) + (ComputableInPolyTime.unary_to_binary.comp ((ComputableInPolyTime.snd _ _).comp + (ComputableInPolyTime.fst _ _)))) + refine (ComputableInPolyTime.decide_eq' hc (ComputableInPolyTime.const 1)).of_enc_eq + fun p => ?_ + simp only [Function.comp_apply, List.count_eq_countP] + congr 3 + have h2 : ComputableInPolyTime (fun G : ℕ × DescribedNetwork T => + (List.range G.2.numEdges).all (fun i => + decide (((G.2.vertices.take (min G.2.vertices.length G.1)).flatMap Prod.fst).count i = + 1) && + decide (((G.2.vertices.drop (min G.2.vertices.length G.1)).flatMap Prod.fst).count i = + 1))) (encPair encNat (encDescribed encT)) encBool := + ComputableInPolyTime.allWithInput (ComputableInPolyTime.range.comp hm) + (ComputableInPolyTime.bool_and.comp ((hcount (hflat htake)).prod (hcount (hflat hdrop)))) + refine (ComputableInPolyTime.bool_and.comp (h1.prod h2)).of_enc_eq fun G => ?_ + have ht : G.2.vertices.take (min G.2.vertices.length G.1) = G.2.vertices.take G.1 := by + rcases le_total G.2.vertices.length G.1 with hle | hle + · rw [min_eq_left hle, List.take_length, List.take_of_length_le hle] + · rw [min_eq_right hle] + have hdr : G.2.vertices.drop (min G.2.vertices.length G.1) = G.2.vertices.drop G.1 := by + rcases le_total G.2.vertices.length G.1 with hle | hle + · rw [min_eq_left hle, List.drop_length, List.drop_of_length_le hle] + · rw [min_eq_right hle] + rw [decide_eq_rowsTest, rowsTest] + simp only [Function.comp_apply, ht, hdr] + +end RowsFirst + +end DescribedNetwork + +namespace EntryContraction + +open FastContraction (Call scheme nativeMk value rootNet modulus fuelConst encCall encValue + leafCertificate irreducible_modulus) + +variable {encT : T ↪ List Bool} {entry : T → List Bool → List ℕ} + +/-! ### The guard -/ + +/-- **The guard**: `fl` is the modulus of the number `m` of edges, the network is rows-first +bipartite at its number of rows, and every vertex has at most `degreeBound m` ports. -/ +@[expose] def guard (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : Bool := + decide (x.2.1 = modulus x.2.2.2.numEdges ∧ x.2.2.2.IsRowsFirstBipartite x.2.2.1 ∧ + ∀ v ∈ x.2.2.2.vertices, v.1.length ≤ degreeBound x.2.2.2.numEdges) + +/-- The number of edges of an input, in unary. -/ +private theorem numEdges_polyTime : + ComputableInPolyTime (fun x : ℕ × List ℕ × ℕ × DescribedNetwork T => x.2.2.2.numEdges) + (encInput encT) encUnary := by + have hpair : ComputableInPolyTime (DescribedNetwork.equivProd (T := T)) + (DescribedNetwork.encDescribed encT) + (encPair encUnary (encList (encPair (encList encNat) encT))) := + ComputableInPolyTime.of_eq fun _ => rfl + exact (ComputableInPolyTime.fst _ _).comp (hpair.comp ((ComputableInPolyTime.snd _ _).comp + ((ComputableInPolyTime.snd _ _).comp (ComputableInPolyTime.snd _ _)))) + +/-- The network of an input with its number of rows. -/ +private theorem rowsNet_polyTime : + ComputableInPolyTime (fun x : ℕ × List ℕ × ℕ × DescribedNetwork T => x.2.2) (encInput encT) + (encPair encNat (DescribedNetwork.encDescribed encT)) := + (ComputableInPolyTime.snd _ _).comp (ComputableInPolyTime.snd _ _) + +/-- **The guard is polynomial-time.** -/ +theorem guard_polyTime : ComputableInPolyTime (guard (T := T)) (encInput encT) encBool := by + have hm := numEdges_polyTime (encT := encT) + have hfl : ComputableInPolyTime (fun x : ℕ × List ℕ × ℕ × DescribedNetwork T => + decide (x.2.1 = modulus x.2.2.2.numEdges)) (encInput encT) encBool := + ComputableInPolyTime.decide_eq' ((ComputableInPolyTime.fst _ _).comp + (ComputableInPolyTime.snd _ _)) (FastContraction.modulus_polyTime.comp hm) + have hrows := (DescribedNetwork.rowsFirst_polyTime (encT := encT)).comp rowsNet_polyTime + have hvs : ComputableInPolyTime (fun x : ℕ × List ℕ × ℕ × DescribedNetwork T => x.2.2.2.vertices) + (encInput encT) (encList (encPair (encList encNat) encT)) := by + have hpair : ComputableInPolyTime (DescribedNetwork.equivProd (T := T)) + (DescribedNetwork.encDescribed encT) + (encPair encUnary (encList (encPair (encList encNat) encT))) := + ComputableInPolyTime.of_eq fun _ => rfl + exact (ComputableInPolyTime.snd _ _).comp (hpair.comp ((ComputableInPolyTime.snd _ _).comp + ((ComputableInPolyTime.snd _ _).comp (ComputableInPolyTime.snd _ _)))) + have hdeg : ComputableInPolyTime (fun x : ℕ × List ℕ × ℕ × DescribedNetwork T => + x.2.2.2.vertices.all (fun v => decide (v.1.length ≤ degreeBound x.2.2.2.numEdges))) + (encInput encT) encBool := by + refine ComputableInPolyTime.allWithInput hvs ?_ + exact ComputableInPolyTime.binary_le' + (ComputableInPolyTime.unary_to_binary.comp ((ComputableInPolyTime.length_list _).comp + ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _)))) + (degreeBound_polyTime.comp (hm.comp (ComputableInPolyTime.fst _ _))) + refine (ComputableInPolyTime.bool_and.comp (hfl.prod (ComputableInPolyTime.bool_and.comp + (hrows.prod hdeg)))).of_enc_eq fun x => ?_ + simp only [guard, Function.comp_apply, Bool.decide_and, List.all_eq, decide_eq_true_eq] + +/-- `degreeBound` is monotone. -/ +theorem degreeBound_mono {a b : ℕ} (h : a ≤ b) : degreeBound a ≤ degreeBound b := + Nat.pow_le_pow_right (by norm_num) (by have := Nat.log_mono_right (b := 2) h; omega) + +/-- **Admissible inputs pass the guard** at the modulus of the number of edges: their degree is at +most `⌈s ^ (9/10)⌉ ≤ degreeBound s ≤ degreeBound m`, for `s ≤ m`. -/ +theorem guard_of_entryAdmissible + {ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)} {C s P r : ℕ} {G : DescribedNetwork T} + (hA : EntryAdmissible ce C s (r, G)) : guard (P, modulus G.numEdges, r, G) = true := by + obtain ⟨hrows, hsm, -, hdeg, -⟩ := hA + simp only [guard, decide_eq_true_eq, true_and] + exact ⟨hrows, fun v hv => + (hdeg v hv).trans ((ceilNineTenths_le_degreeBound s).trans (degreeBound_mono hsm))⟩ + +/-! ### The root and the clock -/ + +/-- **The root call** of an input `(P, fl, r, G)`: scale `m`, depth `0`, edge bound `m + 1`, +precision `P`, modulus `fl`, `r` rows and the descriptors of `G`. -/ +@[expose] def rootCall (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : Call T := + ((x.2.2.2.numEdges, 0, x.2.2.2.numEdges + 1, x.1, x.2.1, x.2.2.1), rootNet x.2.2.2) + +/-- **The clock** of an input `(P, fl, r, G)`: `2 ^ (K₀ (m + P) / √⌊log₂ (m + P)⌋)`. -/ +@[expose] def clock (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : ℕ := + 2 ^ (fuelConst * (x.2.2.2.numEdges + x.1) / Nat.sqrt (Nat.log 2 (x.2.2.2.numEdges + x.1))) + +/-- **The root call is polynomial-time.** -/ +theorem rootCall_polyTime : + ComputableInPolyTime (rootCall (T := T)) (encInput encT) (encCall encT) := by + have hm := numEdges_polyTime (encT := encT) + have hP := ComputableInPolyTime.fst encUnary + (encPair (encList encNat) (encPair encNat (DescribedNetwork.encDescribed encT))) + have hfl := (ComputableInPolyTime.fst (encList encNat) + (encPair encNat (DescribedNetwork.encDescribed encT))).comp + (ComputableInPolyTime.snd encUnary _) + have hr := (ComputableInPolyTime.fst encNat (DescribedNetwork.encDescribed encT)).comp + rowsNet_polyTime + have hG := (ComputableInPolyTime.snd encNat (DescribedNetwork.encDescribed encT)).comp + rowsNet_polyTime + exact (hm.prod ((ComputableInPolyTime.const 0).prod + ((ComputableInPolyTime.unary_add' hm (ComputableInPolyTime.const 1)).prod + (hP.prod (hfl.prod hr))))).prod ((FastContraction.rootNet_polyTime encT).comp hG) + +/-- **The clock is polynomial-time.** -/ +theorem clock_polyTime : ComputableInPolyTime (clock (T := T)) (encInput encT) encNat := + (ComputableInPolyTime.unary_two_pow_div_sqrt_log_two fuelConst).comp + (ComputableInPolyTime.unary_add' numEdges_polyTime (ComputableInPolyTime.fst _ _)) + +/-- **Guarded roots are well-formed**: the modulus is irreducible modulo `2`, and the descriptors +of `G` keep its rows-first ports. -/ +theorem wf_rootCall {x : ℕ × List ℕ × ℕ × DescribedNetwork T} (hg : guard x = true) : + FastContraction.WF (rootCall x) := by + simp only [guard, decide_eq_true_eq] at hg + obtain ⟨hfl, ⟨h1, h2⟩, -⟩ := hg + refine ⟨?_, fun v hv i hi => ?_, fun i hi => ?_⟩ + · change Irreducible ((monicOf x.2.1).map (Int.castRingHom (ZMod 2))) + rw [hfl] + exact irreducible_modulus _ + · simp only [rootCall, rootNet, List.mem_map] at hv + obtain ⟨w, hw, rfl⟩ := hv + exact h1 w hw i hi + · simp only [rootCall, rootNet, ← List.map_take, ← List.map_drop, List.map_map, + Function.comp_def] at hi ⊢ + exact h2 i hi + +/-! ### The result -/ + +variable (entry) in +/-- **The result of the machine** on an input `(P, fl, r, G)`: on guarded inputs, the coefficient +list of a value tagged `0` returned by the clocked run from the root call, and direct summation +otherwise. -/ +@[expose] noncomputable def coreValue (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : List ℕ := + if guard x then + ((scheme entry nativeMk).run clock rootCall x).elim + (DescribedNetwork.sumValue SumOps.galois entry (x.1, x.2.1) x.2.2.2) + fun v => if v.1 = 0 then v.2 + else DescribedNetwork.sumValue SumOps.galois entry (x.1, x.2.1) x.2.2.2 + else DescribedNetwork.sumValue SumOps.galois entry (x.1, x.2.1) x.2.2.2 + +/-- **The machine is correct**: at the modulus of the number of edges, the value of the result is +the contraction of the values of the entries, on every input and for every fuel. A value tagged +`0` returned by the run is the root's value (`FastContraction.eq_value_of_run`), which is the +contraction on well-formed roots (`FastContraction.val_value`). -/ +theorem val_coreValue (P r : ℕ) (G : DescribedNetwork T) : + val P (modulus G.numEdges) (coreValue entry (P, modulus G.numEdges, r, G)) = + G.contraction fun t bs => val P (modulus G.numEdges) (entry t bs) := by + unfold coreValue + split_ifs with hg + · rcases hrun : (scheme entry nativeMk).run clock rootCall (P, modulus G.numEdges, r, G) with + _ | ⟨d, y⟩ + · exact val_directCore _ _ _ + · simp only [Option.elim_some] + split_ifs with hd + · subst hd + have hy := FastContraction.eq_value_of_run entry nativeMk (fuel := clock) + (root := rootCall) rfl hrun + rw [hy] + exact (FastContraction.val_value entry nativeMk (FastContraction.stepCorrect_nativeMk entry) + FastContraction.wfChildren_nativeMk _ (wf_rootCall hg)).trans + (FastContraction.contraction_rootNet (val P (modulus G.numEdges)) entry G) + · exact val_directCore _ _ _ + · exact val_directCore _ _ _ + +/-! ### The machine -/ + +/-- Whether a returned value is tagged `0`. -/ +theorem valueTag_polyTime : + ComputableInPolyTime (fun q : (ℕ × List ℕ × ℕ × DescribedNetwork T) × (ℕ × List ℕ) => + decide (q.2.1 = 0)) (encPair (encInput encT) encValue) encBool := + ComputableInPolyTime.decide_eq' ((ComputableInPolyTime.fst encUnary (encList encNat)).comp + (ComputableInPolyTime.snd (encInput encT) encValue)) (ComputableInPolyTime.const 0) + +/-- The coefficient list of a returned value. -/ +theorem valueList_polyTime : + ComputableInPolyTime (fun q : (ℕ × List ℕ × ℕ × DescribedNetwork T) × (ℕ × List ℕ) => q.2.2) + (encPair (encInput encT) encValue) (encList encNat) := + (ComputableInPolyTime.snd encUnary (encList encNat)).comp + (ComputableInPolyTime.snd (encInput encT) encValue) + +variable (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) + +/-- **The clocked run** from the root call, as one native machine, with direct summation through +the entry procedure's certificate `ce` at the leaves. -/ +@[expose] noncomputable def runCore : + NativeCertificate ((scheme entry nativeMk).run clock rootCall) (encInput encT) + (encOption encValue) := + Scheme.certificate (FastContraction.scheme_nativeMk_polyTime entry) (leafCertificate ce nativeMk) + (NativeCertificate.ofPolyTime clock_polyTime) (NativeCertificate.ofPolyTime rootCall_polyTime) + +/-- **The machine**: branch on the guard; on guarded inputs run the recursion, and on a value +tagged `0` output its coefficient list; otherwise sum directly (`EntryContraction.directCore`). It +computes `coreValue`. -/ +@[expose] noncomputable def fastCore : + NativeCertificate (coreValue entry) (encInput encT) (encList encNat) := + (NativeCertificate.branch (NativeCertificate.ofPolyTime guard_polyTime) + (NativeCertificate.option (runCore ce) (directCore entry ce) + (NativeCertificate.branch (NativeCertificate.ofPolyTime valueTag_polyTime) + (NativeCertificate.ofPolyTime valueList_polyTime) + ((directCore entry ce).comp + (NativeCertificate.ofPolyTime (ComputableInPolyTime.fst (encInput encT) encValue))))) + (directCore entry ce)).congr fun x => by + simp only [coreValue, Function.comp_apply] + split + · cases (scheme entry nativeMk).run clock rootCall x with + | none => rfl + | some v => simp only [Option.elim_some, decide_eq_true_eq] + · rfl + +/-- The time of the machine, unfolded: the guard, and on guarded inputs the run twice, the input, +and the output or direct summation. -/ +theorem fastCore_time (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : + (fastCore ce).time x = + (NativeCertificate.ofPolyTime (guard_polyTime (encT := encT))).time x + + if guard x = true then + 2 * (runCore ce).time x + (encInput encT x).length + + ((scheme entry nativeMk).run clock rootCall x).elim ((directCore entry ce).time x) + fun v => (NativeCertificate.ofPolyTime (valueTag_polyTime (encT := encT))).time + (x, v) + + if decide (v.1 = 0) = true then + (NativeCertificate.ofPolyTime (valueList_polyTime (encT := encT))).time (x, v) + else (NativeCertificate.ofPolyTime + (ComputableInPolyTime.fst (encInput encT) encValue)).time (x, v) + + (directCore entry ce).time x + else (directCore entry ce).time x := rfl + +/-- The space of the machine, unfolded. -/ +theorem fastCore_space (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : + (fastCore ce).space x = + (NativeCertificate.ofPolyTime (guard_polyTime (encT := encT))).space x + + if guard x = true then + 2 * (runCore ce).space x + (encInput encT x).length + + ((scheme entry nativeMk).run clock rootCall x).elim ((directCore entry ce).space x) + fun v => (NativeCertificate.ofPolyTime (valueTag_polyTime (encT := encT))).space + (x, v) + + if decide (v.1 = 0) = true then + (NativeCertificate.ofPolyTime (valueList_polyTime (encT := encT))).space (x, v) + else (NativeCertificate.ofPolyTime + (ComputableInPolyTime.fst (encInput encT) encValue)).space (x, v) + + (directCore entry ce).space x + else (directCore entry ce).space x := rfl + +end EntryContraction + +end Cslib.Circuits.Frontier From f16c8c2387da3c8e8fb3c3e4c144e8caa494bb69 Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 11:13:46 -0400 Subject: [PATCH 14/20] feat(CountingSimulation): sizes and leaf bounds of the entry machine Root descriptors keep their number of ports along the native recursion, so the entry bounds of admissibility apply at every reached leaf; the leaf bound with entry costs; polynomial sizes from guarded roots; the leaf bounds on admissible inputs. Generalizes Reach.wf_packetShape and Reach.edges_le_two_mul_scale to any descriptor type and adds packetShape_of_net_eq_rootNet. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG --- .../EntryContractionMachine.lean | 3 +- .../TensorNetwork/FastContractionLeaf.lean | 13 +- .../CountingSimulation/EntryAnalysis.lean | 516 ++++++++++++++++++ .../CountingSimulation/FastLeaves.lean | 6 +- 4 files changed, 532 insertions(+), 6 deletions(-) create mode 100644 Complexity/Computability/Complexity/Classes/CountingSimulation/EntryAnalysis.lean diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContractionMachine.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContractionMachine.lean index 573974bd1..1f57e2a94 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContractionMachine.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContractionMachine.lean @@ -41,7 +41,8 @@ admissible input at the modulus passes it (`EntryContraction.guard_of_entryAdmis **The root and the clock.** The root call (`EntryContraction.rootCall`) has scale `m`, depth `0`, edge bound `m + 1`, precision `P`, modulus `fl`, `r` rows and the network `FastContraction.rootNet G`. The clock (`EntryContraction.clock`) is -`2 ^ (K₀ (m + P) / √⌊log₂ (m + P)⌋)`, as for explicit networks. On guarded inputs the root is well-formed (`EntryContraction.wf_rootCall`). +`2 ^ (K₀ (m + P) / √⌊log₂ (m + P)⌋)`, as for explicit networks. On guarded inputs the root is +well-formed (`EntryContraction.wf_rootCall`). **The result** (`EntryContraction.coreValue`): on guarded inputs, the coefficient list of a value tagged `0` returned by the clocked run, and direct summation otherwise. It is correct at the modulus diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionLeaf.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionLeaf.lean index 4fba5a66f..439f15498 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionLeaf.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionLeaf.lean @@ -469,13 +469,20 @@ def PacketShape (x : Call T) : Prop := d.1.i < d.1.a ∧ d.1.a ≤ Nat.log 2 x.scale / 32768 ∧ d.1.tiles = 2 ^ (d.1.i + 1) ∧ d.1.nb ≤ x.prec ∧ (∀ y ∈ d.2.1, y.2 < 2 ^ d.1.a) ∧ ((d.2.1.filter (·.1)).map (·.2)).Nodup -/-- **The root has no packets.** -/ -theorem packetShape_root (q : ℕ × ℕ × ExplicitTensorNetwork ℕ) : PacketShape (root q) := by +/-- **A call on a root network has no packets**: its descriptors are those of a network +`G`, by `rootNet G`. -/ +theorem packetShape_of_net_eq_rootNet {x : Call T} {G : DescribedNetwork T} + (h : x.net = rootNet G) : PacketShape x := by intro v hv d hd - simp only [root, rootNet, Call.net, List.mem_map] at hv + rw [h] at hv + simp only [rootNet, List.mem_map] at hv obtain ⟨w, -, rfl⟩ := hv cases hd +/-- **The root has no packets.** -/ +theorem packetShape_root (q : ℕ × ℕ × ExplicitTensorNetwork ℕ) : PacketShape (root q) := + packetShape_of_net_eq_rootNet rfl + /-- **The packet shape passes to the native children** of a well-formed active call: a retained vertex keeps its descriptor, at a precision that only grows, and a new packet has `a` slot bits (`slotBits_le`), `i < a` (the valuation of its node), `2 ^ (i + 1)` tiles, the child's precision diff --git a/Complexity/Computability/Complexity/Classes/CountingSimulation/EntryAnalysis.lean b/Complexity/Computability/Complexity/Classes/CountingSimulation/EntryAnalysis.lean new file mode 100644 index 000000000..1b42489f9 --- /dev/null +++ b/Complexity/Computability/Complexity/Classes/CountingSimulation/EntryAnalysis.lean @@ -0,0 +1,516 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Computability.Complexity.Classes.CountingSimulation.FastLeaves +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.EntryContractionMachine +import Complexity.Computability.Machines.Turing.MultiTape.Encodings.Length +import Mathlib.Data.List.GetD + +/-! +# Theorem D.1 for entry procedures: the resource analysis + +The instance of the contraction interface for entry procedures +(`Cslib.Circuits.Frontier.EntryContractionAlgorithm`) given by the native machine +`EntryContraction.fastCore` (milestone E1.3 of #1538): for every native certificate `ce` of an +entry procedure, `CountingSimulation.entryContractionAlgorithm ce` contracts the networks admissible +for `ce` (`Cslib.Circuits.Frontier.EntryAdmissible`) in time `poly(n) 2 ^ O(s / √⌊log₂ s⌋)` and +polynomial space. This is Theorem D.1 of [OpenAI2026ETH] (p. 53) at truncation order `1`, with +the entries given by procedures. + +The analysis follows the one for explicit networks (`CountingSimulation.FastAnalysis`, +`CountingSimulation.fastSizes`, `CountingSimulation.fastLeaves`), with the root call of +`EntryContraction.rootCall`, the precision in unary and the guard `EntryContraction.guard`, which +every admissible input at the modulus passes. The one new ingredient is the cost of the root +entries at a leaf (§D.4.7, p. 64): + +* **root descriptors stay with their ports** (`FastContraction.Reach.exists_root_of_inl`): every + root descriptor of a reached call is the descriptor of a vertex of the input network with as many + ports, since the native child renumbers the ports of the vertices it keeps. So the entry bounds of + admissibility apply at every reached leaf; +* **the leaf bound with entry costs** (`FastContraction.exists_leafCertificate_le_of_entry`): a + leaf whose root entries take time `E` and space `ES` takes time + `K (n + ES + 1) ^ K 2 ^ (K s / √⌊log₂ s⌋) (E + 1)`; +* **the entry costs fit the budget**: `E ≤ C (s + L + 1) ^ C 2 ^ (C ⌈s ^ (9/10)⌉)`, and + `C ⌈s ^ (9/10)⌉ ≤ s / √⌊log₂ s⌋` from some size on (`exists_mul_ceilNineTenths_le`). + +## Main results + +* `Cslib.Circuits.Frontier.FastContraction.Reach.exists_root_of_inl`: root descriptors keep their + number of ports along the recursion. +* `Cslib.Circuits.Frontier.FastContraction.exists_leafCertificate_le_of_entry`: the leaf bound + with the costs of the root entries. +* `Cslib.Complexity.CountingSimulation.entry_length_le_of_reach`: polynomial sizes along the + recursion from a guarded input. +* `Cslib.Complexity.CountingSimulation.exists_entryLeaves_le`: the leaf bounds on admissible + inputs. +* `Cslib.Complexity.CountingSimulation.exists_entryAnalysis`: the resource analysis of the + recursion on admissible inputs. +* `Cslib.Complexity.CountingSimulation.exists_fastCore_le`: the machine within the interface's + bounds. +* `Cslib.Complexity.CountingSimulation.entryContractionAlgorithm`: the contraction algorithm for + entry procedures. + +## References + +* [OpenAI, *The Exponential Time Hypothesis is False*][OpenAI2026ETH], Theorem D.1 (p. 53) and + Appendix D.4.7 (p. 64). +-/ + +public section + +namespace Cslib.Circuits.Frontier + +open Turing.MultiTapeTM Cslib.GenericRAM ChildCursor ContractionSchedule + +variable {T : Type} + +/-! ### Root descriptors along the recursion -/ + +/-- **A kept vertex of the native child keeps its descriptor and its number of ports**: every root +descriptor of the native child is the descriptor of a parent vertex with as many ports. -/ +theorem NativeChild.exists_mem_of_mem_nativeChild_inl {fl : List ℕ} {a i pt : ℕ} {τ : ℤ} + {ζ : List ℕ} {r : ℕ} {D : DescribedNetwork (VertexDesc T)} + {pk : (List (List ℕ) × List (List ℕ)) × ℕ × List (ℕ × ℕ)} {β : List ℕ} {g : ℕ} + {v : List ℕ × VertexDesc T} + (hv : v ∈ (NativeChild.nativeChild fl a i pt τ ζ r D pk β g).vertices) {t : T} + (ht : v.2 = .inl t) : + ∃ u ∈ D.vertices, u.2 = .inl t ∧ u.1.length = v.1.length := by + simp only [NativeChild.nativeChild, List.mem_append, List.mem_map, List.mem_filter, + List.mem_range] at hv + rcases hv with ⟨k, ⟨hk, -⟩, rfl⟩ | ⟨q, -, rfl⟩ + · refine ⟨D.vertices[k], List.getElem_mem hk, ?_, ?_⟩ + · simpa only [List.getD_eq_getElem _ _ hk] using ht + · simp only [List.length_map, List.getD_eq_getElem _ _ hk] + · cases ht + +namespace FastContraction + +/-- **Root descriptors keep their number of ports along the recursion**: every root descriptor of a +call reached by the native child builder is the descriptor of a vertex of the root with as many +ports. -/ +theorem Reach.exists_root_of_inl {x₀ x : Call T} (h : Reach nativeMk x₀ x) + {v : List ℕ × VertexDesc T} (hv : v ∈ x.net.vertices) {t : T} (ht : v.2 = .inl t) : + ∃ w ∈ x₀.net.vertices, w.2 = .inl t ∧ w.1.length = v.1.length := by + induction h generalizing v with + | root => exact ⟨v, hv, ht, rfl⟩ + | step c _ _ _ ih => + obtain ⟨u, hu, hut, hlen⟩ := NativeChild.exists_mem_of_mem_nativeChild_inl hv ht + obtain ⟨w, hw, hwt, hwlen⟩ := ih hu hut + exact ⟨w, hw, hwt, hwlen.trans hlen⟩ + +variable {encT : T ↪ List Bool} {ev : T → List Bool → List ℕ} + +/-- **The leaf bound with the costs of the root entries.** For a native certificate `ce` of the +entry procedure and all constants `C`, `c` and `s₀` there is `K` such that a call with the packet +shape, scale `m` with `s ≤ m ≤ C s` and at most `2 m` edges, whose root entries take time at most +`E` and space at most `ES`, takes time at most `K (n + ES + 1) ^ K 2 ^ (K s / √⌊log₂ s⌋) (E + 1)` +and space at most `K (n + ES + 1) ^ K` at a leaf, provided that from `s₀` on it has at most +`leafSize m` edges and precision at most `m ^ c`. The packet factor and `2 ^ M` are bounded as for +tables (`exists_leafCertificate_le`). -/ +theorem exists_leafCertificate_le_of_entry + (ce : NativeCertificate (fun q : T × List Bool => ev q.1 q.2) (encPair encT encBits) + (encList encNat)) (C c s₀ : ℕ) : ∃ K : ℕ, + ∀ (mk : Call T → State → ℕ × DescribedNetwork (VertexDesc T)) (s : ℕ) (x : Call T) + (E ES : ℕ), 2 ≤ s → s ≤ x.scale → x.scale ≤ C * s → PacketShape x → + x.edges ≤ 2 * x.scale → (s₀ ≤ s → x.edges ≤ leafSize x.scale ∧ x.prec ≤ x.scale ^ c) → + (∀ v ∈ x.net.vertices, ∀ t, v.2 = .inl t → ∀ bs : List Bool, bs.length = v.1.length → + ce.time (t, bs) ≤ E ∧ ce.space (t, bs) ≤ ES) → + (leafCertificate ce mk).time x ≤ K * ((encCall encT x).length + ES + 1) ^ K * + 2 ^ (K * s / Nat.sqrt (Nat.log 2 s)) * (E + 1) ∧ + (leafCertificate ce mk).space x ≤ K * ((encCall encT x).length + ES + 1) ^ K := by + obtain ⟨K₀, hK₀⟩ := leafCertificate_le_of_packetShape ce + obtain ⟨K₁, hK₁⟩ := exists_packetFactor_le C c + obtain ⟨Ks, hKs⟩ : ∃ Ks, Ks = K₀ * 2 ^ (2 * (C * s₀)) * (C * s₀ + 2) ^ (C * s₀) := ⟨_, rfl⟩ + refine ⟨Ks + K₀ + C * s₀ + C + K₁, fun mk s x E ES hs hsm hmC hshape hM hbig hroot => ?_⟩ + obtain ⟨hT, hS⟩ := hK₀ mk x E ES hshape hroot + set W := (encCall encT x).length + ES + 1 with hW + set K := Ks + K₀ + C * s₀ + C + K₁ with hK + set S := Nat.sqrt (Nat.log 2 s) with hSdef + have hS1 : 1 ≤ S := Nat.one_le_sqrt_log_two hs + have hB1 : 1 ≤ W := by omega + have hX1 : 1 ≤ 2 ^ (K * s / S) := Nat.one_le_two_pow + have hnK : W ^ K₀ ≤ W ^ K := Nat.pow_le_pow_right hB1 (by omega) + refine ⟨?_, hS.trans (Nat.mul_le_mul (by omega) hnK)⟩ + set A := 2 ^ (Nat.log 2 x.scale / 32768) with hA + have hAm : A ≤ x.scale := (Nat.pow_le_pow_right (by norm_num) (Nat.div_le_self _ _)).trans + (Nat.pow_log_le_self 2 (by omega)) + set Pk := (A * x.prec + 2) ^ A with hPk + have hPk1 : 1 ≤ Pk := Nat.one_le_pow _ _ (by omega) + have hT' : (leafCertificate ce mk).time x ≤ K₀ * W ^ K₀ * (2 ^ x.edges * Pk) * (E + 1) := by + have hPE : Pk + E ≤ Pk * (E + 1) := by nlinarith + calc _ ≤ K₀ * W ^ K₀ * 2 ^ x.edges * (Pk + E) := hT + _ ≤ K₀ * W ^ K₀ * 2 ^ x.edges * (Pk * (E + 1)) := Nat.mul_le_mul_left _ hPE + _ = _ := by ring + suffices hMP : K₀ * W ^ K₀ * (2 ^ x.edges * Pk) ≤ K * W ^ K * 2 ^ (K * s / S) from + hT'.trans (Nat.mul_le_mul_right _ hMP) + rcases lt_or_ge s s₀ with hsmall | hlarge + · -- Below `s₀`: constants and a polynomial. + have hmC' : x.scale ≤ C * s₀ := hmC.trans (Nat.mul_le_mul_left _ hsmall.le) + have hp : x.prec ≤ W := by have := scale_add_prec_add_length_fl_le encT x; omega + have h2M : 2 ^ x.edges ≤ 2 ^ (2 * (C * s₀)) := + Nat.pow_le_pow_right (by norm_num) (by omega) + have hbase : A * x.prec + 2 ≤ (C * s₀ + 2) * W := by + have : A * x.prec ≤ C * s₀ * W := Nat.mul_le_mul (hAm.trans hmC') hp + nlinarith + have hfac : Pk ≤ (C * s₀ + 2) ^ (C * s₀) * W ^ (C * s₀) := by + calc Pk ≤ ((C * s₀ + 2) * W) ^ A := Nat.pow_le_pow_left hbase _ + _ ≤ ((C * s₀ + 2) * W) ^ (C * s₀) := + Nat.pow_le_pow_right (Nat.one_le_iff_ne_zero.mpr (by positivity)) (hAm.trans hmC') + _ = (C * s₀ + 2) ^ (C * s₀) * W ^ (C * s₀) := mul_pow _ _ _ + calc K₀ * W ^ K₀ * (2 ^ x.edges * Pk) + ≤ K₀ * W ^ K₀ * (2 ^ (2 * (C * s₀)) * ((C * s₀ + 2) ^ (C * s₀) * W ^ (C * s₀))) := + Nat.mul_le_mul_left _ (Nat.mul_le_mul h2M hfac) + _ = Ks * W ^ (K₀ + C * s₀) := by rw [hKs, pow_add]; ring + _ ≤ K * W ^ K := Nat.mul_le_mul (by omega) (Nat.pow_le_pow_right hB1 (by omega)) + _ ≤ K * W ^ K * 2 ^ (K * s / S) := Nat.le_mul_of_pos_right _ hX1 + · -- From `s₀` on: the leaf size and the packet factor. + obtain ⟨hleaf, hp⟩ := hbig hlarge + have hlog : S ≤ Nat.sqrt (Nat.log 2 x.scale) := Nat.sqrt_log_two_mono hsm + have hMs : x.edges ≤ C * s / S := + calc x.edges ≤ x.scale / Nat.sqrt (Nat.log 2 x.scale) := hleaf + _ ≤ x.scale / S := Nat.div_le_div_left hlog hS1 + _ ≤ C * s / S := Nat.div_le_div_right hmC + have hfac : Pk ≤ 2 ^ (K₁ * s / S) := hK₁ s x.scale x.prec hs hsm hmC hp + have hCK : (C + K₁) * s ≤ K * s := Nat.mul_le_mul_right _ (by omega) + have hexp : C * s / S + K₁ * s / S ≤ K * s / S := + Nat.div_add_div_le_add_div.trans (Nat.div_le_div_right (by rw [← add_mul]; exact hCK)) + calc K₀ * W ^ K₀ * (2 ^ x.edges * Pk) + ≤ K₀ * W ^ K₀ * (2 ^ (C * s / S) * 2 ^ (K₁ * s / S)) := + Nat.mul_le_mul_left _ (Nat.mul_le_mul (Nat.pow_le_pow_right (by norm_num) hMs) hfac) + _ = K₀ * W ^ K₀ * 2 ^ (C * s / S + K₁ * s / S) := by rw [pow_add] + _ ≤ K * W ^ K * 2 ^ (K * s / S) := + Nat.mul_le_mul (Nat.mul_le_mul (by omega) hnK) (Nat.pow_le_pow_right (by norm_num) hexp) + +end FastContraction + +/-- **The root call has no packets.** -/ +theorem EntryContraction.packetShape_rootCall (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : + FastContraction.PacketShape (EntryContraction.rootCall x) := + FastContraction.packetShape_of_net_eq_rootNet rfl + +end Cslib.Circuits.Frontier + +namespace Cslib.Complexity.CountingSimulation + +open Cslib.Circuits.Frontier Cslib.Circuits.Frontier.ContractionSchedule + Cslib.Circuits.Frontier.EntryContraction Cslib.GenericRAM Cslib.GenericRAM.StackRecursion + Turing.MultiTapeTM +open Cslib.Circuits.Frontier.FastContraction (Call Reach reachInv scheme nativeMk value encCall + encFrame encValue leafCertificate modulus active OnSchedule fuelConst) + +variable {T : Type} {encT : T ↪ List Bool} {entry : T → List Bool → List ℕ} + +/-! ### The root -/ + +/-- The parts of an encoded input `(P, fl, r, G)` against its length. -/ +theorem length_parts_le (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : + x.1 + x.2.1.length + (encNat x.2.2.1).length + + (DescribedNetwork.encDescribed encT x.2.2.2).length ≤ (encInput encT x).length := by + obtain ⟨P, fl, r, G⟩ := x + have h := length_le_length_encList encNat fl + simp only [encInput, length_encPair, encUnary_apply, List.length_replicate] at h ⊢ + omega + +/-- **Guarded roots are on the schedule**, for every constant `C ≥ 1` with precision at most +`C m`. -/ +theorem onSchedule_rootCall {P C r : ℕ} {G : DescribedNetwork T} + (hg : EntryContraction.guard (P, modulus G.numEdges, r, G) = true) (hC : 1 ≤ C) + (hp : P ≤ C * G.numEdges) : + OnSchedule C G.numEdges (rootCall (P, modulus G.numEdges, r, G)) := by + have hdeg : ∀ v ∈ G.vertices, v.1.length ≤ degreeBound G.numEdges := by + simp only [EntryContraction.guard, decide_eq_true_eq] at hg + exact hg.2.2 + refine FastContraction.onSchedule_root hC rfl rfl rfl (wf_rootCall hg) (fun v hv => ?_) rfl rfl + hp + simp only [rootCall, FastContraction.rootNet, List.mem_map] at hv + obtain ⟨w, hw, rfl⟩ := hv + exact hdeg w hw + +/-- **The clock is subexponential on admissible inputs**: with `s ≤ m ≤ C s` edges and precision +`P ≤ D s`, it is at most `2 ^ (K₀ (C + D) s / √⌊log₂ s⌋)`. -/ +theorem clock_le {C D s P r : ℕ} {fl : List ℕ} {G : DescribedNetwork T} (hs : 2 ≤ s) + (hsm : s ≤ G.numEdges) (hmC : G.numEdges ≤ C * s) (hP : P ≤ D * s) : + clock (P, fl, r, G) ≤ 2 ^ (fuelConst * (C + D) * s / Nat.sqrt (Nat.log 2 s)) := by + simp only [clock] + refine Nat.pow_le_pow_right (by norm_num) ?_ + set y := G.numEdges + P + have hy : y ≤ (C + D) * s := by rw [add_mul]; omega + have hsy : s ≤ y := by omega + have hq : 1 ≤ Nat.sqrt (Nat.log 2 s) := Nat.one_le_sqrt_log_two hs + have hq' : Nat.sqrt (Nat.log 2 s) ≤ Nat.sqrt (Nat.log 2 y) := Nat.sqrt_log_two_mono hsy + calc fuelConst * y / Nat.sqrt (Nat.log 2 y) ≤ fuelConst * y / Nat.sqrt (Nat.log 2 s) := + Nat.div_le_div_left hq' hq + _ ≤ fuelConst * (C + D) * s / Nat.sqrt (Nat.log 2 s) := by + refine Nat.div_le_div_right ?_ + rw [Nat.mul_assoc] + exact Nat.mul_le_mul_left _ hy + +/-! ### The sizes -/ + +/-- **Polynomial sizes along the recursion**: every call reached from the root of a guarded input +of encoded length `n`, its frames and its tagged value are at most `2 ^ 55 (n + 1) ^ 24` long. -/ +theorem entry_length_le_of_reach {x : ℕ × List ℕ × ℕ × DescribedNetwork T} + (hg : EntryContraction.guard x = true) {y : Call T} (hy : Reach nativeMk (rootCall x) y) : + (encCall encT y).length ≤ 2 ^ 55 * ((encInput encT x).length + 1) ^ 24 ∧ + (∀ a, (reachInv entry nativeMk (rootCall x)).frame y a → + (encPair (encCall encT) encFrame (y, a)).length ≤ + 2 ^ 55 * ((encInput encT x).length + 1) ^ 24) ∧ + (encValue (y.depth, value entry nativeMk y)).length ≤ + 2 ^ 55 * ((encInput encT x).length + 1) ^ 24 := by + obtain ⟨P, fl, r, G⟩ := x + set x₀ := rootCall (P, fl, r, G) with hx₀ + set m := G.numEdges with hm + set n := (encInput encT (P, fl, r, G)).length with hn + set Y := n + 1 with hY + have hparts := length_parts_le (encT := encT) (P, fl, r, G) + have hmv := DescribedNetwork.length_numEdges_vertices_le (encT := encT) G + simp only at hparts + rw [← hn] at hparts + have hfl : fl = modulus m := by + simp only [EntryContraction.guard, decide_eq_true_eq] at hg + exact hg.1 + have hsh := FastContraction.Reach.shape (x₀ := x₀) rfl rfl (wf_rootCall hg) hy + set Z := 2 ^ 14 * Y ^ 8 with hZ + have hY1 : 1 ≤ Y := by omega + have hmY : m + 1 ≤ Y := by omega + have hY3 : Y ≤ Y ^ 3 := Nat.le_self_pow (by norm_num) _ + have hY8 : Y ^ 3 ≤ Y ^ 8 := Nat.pow_le_pow_right hY1 (by norm_num) + have hY2 : Y ^ 2 ≤ Y ^ 3 := Nat.pow_le_pow_right hY1 (by norm_num) + have hm2 : m ^ 2 ≤ Y ^ 2 := Nat.pow_le_pow_left (by omega) 2 + have hm5 : (m + 1) ^ 5 ≤ Y ^ 5 := Nat.pow_le_pow_left hmY 5 + have hPm : x₀.prec + (x₀.edges + 1) * (40 * x₀.edges ^ 2) + 1 ≤ 41 * Y ^ 3 := by + change P + (m + 1) * (40 * m ^ 2) + 1 ≤ 41 * Y ^ 3 + have : (m + 1) * (40 * m ^ 2) ≤ Y * (40 * Y ^ 2) := Nat.mul_le_mul hmY (by omega) + have : Y * (40 * Y ^ 2) = 40 * Y ^ 3 := by ring + omega + have hZ1 : 256 * (x₀.edges + 1) ^ 5 * (x₀.prec + (x₀.edges + 1) * (40 * x₀.edges ^ 2) + 1) + + x₀.fl.length ≤ Z := by + have h1 : 256 * (x₀.edges + 1) ^ 5 * (x₀.prec + (x₀.edges + 1) * (40 * x₀.edges ^ 2) + 1) ≤ + 256 * Y ^ 5 * (41 * Y ^ 3) := Nat.mul_le_mul (Nat.mul_le_mul_left _ hm5) hPm + have h2 : 256 * Y ^ 5 * (41 * Y ^ 3) = 10496 * Y ^ 8 := by ring + have h3 : x₀.fl.length ≤ 32 * Y ^ 8 := by + change fl.length ≤ 32 * Y ^ 8 + omega + omega + have hZ2 : x₀.net.vertices.length + (x₀.edges + 1) * x₀.edges ^ 2 + (encNat x₀.rows).length ≤ + Z := by + have : (x₀.edges + 1) * x₀.edges ^ 2 ≤ Y * Y ^ 2 := Nat.mul_le_mul hmY hm2 + have : Y * Y ^ 2 = Y ^ 3 := by ring + have hV : x₀.net.vertices.length = G.vertices.length := List.length_map _ + change _ + _ + (encNat r).length ≤ Z + omega + have hR₀ : ∀ w ∈ x₀.net.vertices, + (VertexDesc.enc encT w.2).length ≤ 200 * (Z + 1) ^ 2 := by + intro w hw + change w ∈ List.map _ G.vertices at hw + obtain ⟨u, hu, rfl⟩ := List.mem_map.mp hw + rw [length_encSum] + simp only [Sum.elim_inl] + have h1 := length_le_encList_of_mem (encPair (encList encNat) encT) hu + have h2 : (encList (encPair (encList encNat) encT) G.vertices).length ≤ + (DescribedNetwork.encDescribed encT G).length := by + change _ ≤ (encPair encUnary (encList (encPair (encList encNat) encT)) + (G.numEdges, G.vertices)).length + rw [length_encPair] + dsimp only + omega + rw [length_encPair] at h1 + have : Z ≤ (Z + 1) ^ 2 := (Nat.le_succ Z).trans (Nat.le_self_pow (by norm_num) _) + omega + obtain ⟨hc, hv, hf⟩ := hsh.length_le entry rfl rfl rfl hZ1 hZ2 + (fun z hz => by + change z ∈ fl at hz + rw [hfl] at hz + exact le_one_of_mem_modulus hz) hR₀ + -- `1000 (Z + 1) ^ 3 ≤ 2 ^ 55 (n + 1) ^ 24`. + have hfin : 1000 * (Z + 1) ^ 3 ≤ 2 ^ 55 * Y ^ 24 := by + have h1 : Z + 1 ≤ 2 ^ 15 * Y ^ 8 := by + have : 1 ≤ Y ^ 8 := Nat.one_le_pow _ _ hY1 + omega + have h2 : (Z + 1) ^ 3 ≤ (2 ^ 15 * Y ^ 8) ^ 3 := Nat.pow_le_pow_left h1 3 + have h3 : (2 ^ 15 * Y ^ 8) ^ 3 = 2 ^ 45 * Y ^ 24 := by ring + rw [h3] at h2 + have h4 : 1000 * (2 ^ 45 * Y ^ 24) ≤ 2 ^ 55 * Y ^ 24 := by + rw [← Nat.mul_assoc] + exact Nat.mul_le_mul_right _ (by norm_num) + exact (Nat.mul_le_mul_left 1000 h2).trans h4 + refine ⟨hc.trans hfin, fun a ⟨_, ha, c, _, hac⟩ => ?_, hv.trans hfin⟩ + rw [hac] + exact (hf ha _ c).trans hfin + +/-! ### The leaves -/ + +/-- **The facts at the reached calls that the leaf bounds use.** For all constants `C` and `D` +there is `s₀` such that on every guarded input at the modulus with `s ≤ m ≤ C s` edges and +precision `P ≤ D s`, every reached call has scale `m`, at most `2 m` edges, and, from `s₀` on, +precision at most `m ^ 4`, and at most `leafSize m` edges if the machine treats it as a leaf. -/ +theorem entry_reach_facts (C D : ℕ) : ∃ s₀, ∀ (s P r : ℕ) (G : DescribedNetwork T), 2 ≤ s → + P ≤ D * s → s ≤ G.numEdges → G.numEdges ≤ C * s → + EntryContraction.guard (P, modulus G.numEdges, r, G) = true → + ∀ y, Reach nativeMk (rootCall (P, modulus G.numEdges, r, G)) y → + y.scale = G.numEdges ∧ y.edges ≤ 2 * y.scale ∧ + (s₀ ≤ s → y.prec ≤ y.scale ^ 4 ∧ (active y = false → y.edges ≤ leafSize y.scale)) := by + obtain ⟨sA, hsA⟩ := exists_activeBounds_le D + refine ⟨max sA (D + 81), fun s P r G hs hPD hsm hmC hg y hy => ?_⟩ + set m := G.numEdges with hm + have hp₀ : P ≤ D * m := hPD.trans (Nat.mul_le_mul_left _ hsm) + have hsh := FastContraction.Reach.shape (x₀ := rootCall (P, modulus m, r, G)) rfl rfl + (wf_rootCall hg) hy + have hsc : y.scale = m := hsh.scale_eq + refine ⟨hsc, hsc ▸ hsh.edges_le, fun hs₀ => ⟨?_, fun hl => ?_⟩⟩ + · have hbd := hsh.bound_add_depth_le + change y.bound + y.depth ≤ (m + 1) + 0 at hbd + have hprec : y.prec ≤ P + y.depth * (40 * m ^ 2) := hsh.prec_le + have : y.depth * (40 * m ^ 2) ≤ (m + 1) * (40 * m ^ 2) := Nat.mul_le_mul_right _ (by omega) + have h4 : D * m + (m + 1) * (40 * m ^ 2) ≤ m ^ 4 := by + have hm81 : D + 81 ≤ m := by omega + have h1 : D * m ≤ m * m := Nat.mul_le_mul_right _ (by omega) + have h2 : 81 * m ^ 3 ≤ m ^ 4 := by + rw [pow_succ m 3, mul_comm (m ^ 3) m] + exact Nat.mul_le_mul_right _ (by omega) + have h3 : m * m ≤ m ^ 3 := by nlinarith + have h4 : m ^ 2 ≤ m ^ 3 := Nat.pow_le_pow_right (by omega) (by norm_num) + have e : (m + 1) * (40 * m ^ 2) = 40 * m ^ 3 + 40 * m ^ 2 := by ring + have h5 : m * m = m ^ 2 := by ring + omega + rw [hsc] + omega + · have hm2 : D + 2 ≤ m := by omega + have hC1 : P / m + 1 ≤ D + 1 := by + have := Nat.div_le_div_right (c := m) hp₀ + rw [Nat.mul_div_cancel _ (by omega)] at this + omega + have hB := hsA m (by omega) (P / m + 1) hC1 + have hpC : P ≤ (P / m + 1) * m := + (Nat.lt_div_mul_add (a := P) (b := m) (by omega)).le.trans (by rw [add_mul, one_mul]) + have h := hy.onSchedule hB (onSchedule_rootCall hg (Nat.le_add_left 1 _) hpC) + rw [hsc] + exact h.edges_le_leafSize hB hl + +/-- `2 ^ (C ⌈s ^ (9/10)⌉) ≤ 2 ^ (C s₁) 2 ^ (s / √⌊log₂ s⌋)` once `C ⌈s ^ (9/10)⌉` fits the budget +from `s₁` on. -/ +private theorem two_pow_mul_ceilNineTenths_le {C s₁ : ℕ} + (hs₁ : ∀ s, s₁ ≤ s → C * ceilNineTenths s ≤ s / Nat.sqrt (Nat.log 2 s)) (s : ℕ) : + 2 ^ (C * ceilNineTenths s) ≤ 2 ^ (C * s₁) * 2 ^ (s / Nat.sqrt (Nat.log 2 s)) := by + rw [← pow_add] + refine Nat.pow_le_pow_right (by norm_num) ?_ + rcases le_or_gt s₁ s with h | h + · have := hs₁ s h + omega + · exact (Nat.mul_le_mul_left C ((ceilNineTenths_le_self s).trans h.le)).trans + (Nat.le_add_right _ _) + +/-- **The leaf bounds on admissible inputs**: for a native certificate `ce` of the entry procedure +and all constants `C` and `D` there is `K` such that on every input at the modulus admissible at +size `s ≥ 2` with constant `C` and with precision `1 ≤ P ≤ D s`, direct summation at every reached +call that the machine treats as a leaf takes time at most `K (n + 1) ^ K 2 ^ (K s / √⌊log₂ s⌋)` and +space at most `K (n + 1) ^ K`. The root entries take time at most +`C (s + L + 1) ^ C 2 ^ (C ⌈s ^ (9/10)⌉)` at every reached leaf +(`FastContraction.Reach.exists_root_of_inl`), within the budget from some size on +(`exists_mul_ceilNineTenths_le`). -/ +theorem exists_entryLeaves_le + (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) (C D : ℕ) : + ∃ K : ℕ, ∀ (s P r : ℕ) (G : DescribedNetwork T), 2 ≤ s → 1 ≤ P → P ≤ D * s → + EntryAdmissible ce C s (r, G) → + ∀ y, Reach nativeMk (rootCall (P, modulus G.numEdges, r, G)) y → active y = false → + (leafCertificate ce nativeMk).time y ≤ + K * ((encInput encT (P, modulus G.numEdges, r, G)).length + 1) ^ K * + 2 ^ (K * s / Nat.sqrt (Nat.log 2 s)) ∧ + (leafCertificate ce nativeMk).space y ≤ + K * ((encInput encT (P, modulus G.numEdges, r, G)).length + 1) ^ K := by + obtain ⟨s₀, hs₀⟩ := entry_reach_facts (T := T) C D + obtain ⟨KB, hKB⟩ := FastContraction.exists_leafCertificate_le_of_entry ce C 4 s₀ + obtain ⟨s₁, hs₁⟩ := exists_mul_ceilNineTenths_le C + obtain ⟨cW, hcW⟩ : ∃ cW, cW = 2 ^ 55 + C * 2 ^ C + 1 := ⟨_, rfl⟩ + obtain ⟨cE, hcE⟩ : ∃ cE, cE = (C * 2 ^ C + 1) * 2 ^ (C * s₁) := ⟨_, rfl⟩ + obtain ⟨K, hK⟩ : ∃ K, K = KB * cW ^ KB * cE + (24 + C) * KB + C + KB + 1 := ⟨_, rfl⟩ + refine ⟨K, fun s P r G hs hP hPD hA y hy hl => ?_⟩ + have hg : EntryContraction.guard (P, modulus G.numEdges, r, G) = true := + guard_of_entryAdmissible hA + obtain ⟨-, hsm, hmC, -, hent⟩ := hA + simp only at hsm hmC hent + set n := (encInput encT (P, modulus G.numEdges, r, G)).length with hn + set Y := n + 1 with hY + set S := Nat.sqrt (Nat.log 2 s) with hS + set L := (DescribedNetwork.encDescribed encT G).length with hL + have hparts := length_parts_le (encT := encT) (P, modulus G.numEdges, r, G) + have hmv := DescribedNetwork.length_numEdges_vertices_le (encT := encT) G + simp only at hparts + rw [← hn] at hparts + obtain ⟨hsc, hE2, hbig⟩ := hs₀ s P r G hs hPD hsm hmC hg y hy + obtain ⟨-, hshape⟩ := hy.wf_packetShape (wf_rootCall hg) (packetShape_rootCall _) + -- The root entries at the leaf. + have hroot : ∀ v ∈ y.net.vertices, ∀ t, v.2 = .inl t → ∀ bs : List Bool, + bs.length = v.1.length → + ce.time (t, bs) ≤ C * (s + L + 1) ^ C * 2 ^ (C * ceilNineTenths s) ∧ + ce.space (t, bs) ≤ C * (s + L + 1) ^ C := by + intro v hv t ht bs hbs + obtain ⟨w, hw, hwt, hwlen⟩ := hy.exists_root_of_inl hv ht + change w ∈ List.map _ G.vertices at hw + obtain ⟨u, hu, rfl⟩ := List.mem_map.mp hw + simp only [Sum.inl.injEq] at hwt + subst hwt + exact hent u hu bs (hbs.trans hwlen.symm) + obtain ⟨hT, hSp⟩ := hKB nativeMk s y _ _ hs (hsc ▸ hsm) (hsc ▸ hmC) hshape hE2 + (fun h => ⟨(hbig h).2 hl, (hbig h).1⟩) hroot + have hny := (entry_length_le_of_reach (encT := encT) (entry := entry) hg hy).1 + rw [← hn] at hny + change _ ≤ 2 ^ 55 * Y ^ 24 at hny + -- The arithmetic against `Y = n + 1`. + have hY1 : 1 ≤ Y := by omega + have hsLY : s + L + 1 ≤ 2 * Y := by omega + have hES : C * (s + L + 1) ^ C ≤ C * 2 ^ C * Y ^ C := by + calc C * (s + L + 1) ^ C ≤ C * (2 * Y) ^ C := Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hsLY _) + _ = C * 2 ^ C * Y ^ C := by rw [mul_pow, Nat.mul_assoc] + have hYC : Y ^ C ≤ Y ^ (24 + C) := Nat.pow_le_pow_right hY1 (by omega) + have hY24 : Y ^ 24 ≤ Y ^ (24 + C) := Nat.pow_le_pow_right hY1 (by omega) + have hW : (encCall encT y).length + C * (s + L + 1) ^ C + 1 ≤ cW * Y ^ (24 + C) := by + have h1 : 2 ^ 55 * Y ^ 24 ≤ 2 ^ 55 * Y ^ (24 + C) := Nat.mul_le_mul_left _ hY24 + have h2 : C * 2 ^ C * Y ^ C ≤ C * 2 ^ C * Y ^ (24 + C) := Nat.mul_le_mul_left _ hYC + have h3 : 1 ≤ Y ^ (24 + C) := Nat.one_le_pow _ _ hY1 + have e : cW * Y ^ (24 + C) = 2 ^ 55 * Y ^ (24 + C) + C * 2 ^ C * Y ^ (24 + C) + + Y ^ (24 + C) := by rw [hcW]; ring + omega + have hWK : KB * ((encCall encT y).length + C * (s + L + 1) ^ C + 1) ^ KB ≤ + KB * cW ^ KB * Y ^ ((24 + C) * KB) := by + calc _ ≤ KB * (cW * Y ^ (24 + C)) ^ KB := Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hW _) + _ = KB * cW ^ KB * Y ^ ((24 + C) * KB) := by rw [mul_pow, ← pow_mul]; ring + have hE1 : C * (s + L + 1) ^ C * 2 ^ (C * ceilNineTenths s) + 1 ≤ + cE * Y ^ C * 2 ^ (s / S) := by + have h1 := two_pow_mul_ceilNineTenths_le hs₁ s + have h2 : C * (s + L + 1) ^ C * 2 ^ (C * ceilNineTenths s) ≤ + C * 2 ^ C * Y ^ C * (2 ^ (C * s₁) * 2 ^ (s / S)) := Nat.mul_le_mul hES h1 + have h3 : 1 ≤ Y ^ C * (2 ^ (C * s₁) * 2 ^ (s / S)) := + Nat.one_le_iff_ne_zero.mpr (by positivity) + have e : cE * Y ^ C * 2 ^ (s / S) = C * 2 ^ C * Y ^ C * (2 ^ (C * s₁) * 2 ^ (s / S)) + + Y ^ C * (2 ^ (C * s₁) * 2 ^ (s / S)) := by rw [hcE]; ring + omega + have hexp : KB * s / S + s / S ≤ K * s / S := + Nat.div_add_div_le_add_div.trans (Nat.div_le_div_right (by + rw [← Nat.add_one_mul]; exact Nat.mul_le_mul_right _ (by omega))) + constructor + · calc _ ≤ KB * ((encCall encT y).length + C * (s + L + 1) ^ C + 1) ^ KB * + 2 ^ (KB * s / S) * (C * (s + L + 1) ^ C * 2 ^ (C * ceilNineTenths s) + 1) := hT + _ ≤ KB * cW ^ KB * Y ^ ((24 + C) * KB) * 2 ^ (KB * s / S) * (cE * Y ^ C * 2 ^ (s / S)) := + Nat.mul_le_mul (Nat.mul_le_mul_right _ hWK) hE1 + _ = KB * cW ^ KB * cE * Y ^ ((24 + C) * KB + C) * 2 ^ (KB * s / S + s / S) := by + rw [pow_add, pow_add]; ring + _ ≤ K * Y ^ K * 2 ^ (K * s / S) := + Nat.mul_le_mul (Nat.mul_le_mul (by omega) (Nat.pow_le_pow_right hY1 (by omega))) + (Nat.pow_le_pow_right (by norm_num) hexp) + · calc _ ≤ KB * ((encCall encT y).length + C * (s + L + 1) ^ C + 1) ^ KB := hSp + _ ≤ KB * cW ^ KB * Y ^ ((24 + C) * KB) := hWK + _ ≤ K * Y ^ K := by + have hcE1 : 1 ≤ cE := by rw [hcE]; exact Nat.one_le_iff_ne_zero.mpr (by positivity) + refine Nat.mul_le_mul ?_ (Nat.pow_le_pow_right hY1 (by omega)) + calc KB * cW ^ KB ≤ KB * cW ^ KB * cE := Nat.le_mul_of_pos_right _ hcE1 + _ ≤ K := by omega + +end Cslib.Complexity.CountingSimulation diff --git a/Complexity/Computability/Complexity/Classes/CountingSimulation/FastLeaves.lean b/Complexity/Computability/Complexity/Classes/CountingSimulation/FastLeaves.lean index 447d80216..8893e8b98 100644 --- a/Complexity/Computability/Complexity/Classes/CountingSimulation/FastLeaves.lean +++ b/Complexity/Computability/Complexity/Classes/CountingSimulation/FastLeaves.lean @@ -49,9 +49,11 @@ public section namespace Cslib.Circuits.Frontier.FastContraction +variable {T : Type} + /-- **The reached calls are well-formed and have the packet shape**, from a well-formed root with the packet shape. -/ -theorem Reach.wf_packetShape {x₀ x : Call (List ℕ)} (h : Reach nativeMk x₀ x) (hw : WF x₀) +theorem Reach.wf_packetShape {x₀ x : Call T} (h : Reach nativeMk x₀ x) (hw : WF x₀) (hs : PacketShape x₀) : WF x ∧ PacketShape x := by induction h with | root => exact ⟨hw, hs⟩ @@ -61,7 +63,7 @@ theorem Reach.wf_packetShape {x₀ x : Call (List ℕ)} (h : Reach nativeMk x₀ /-- **Reached calls have at most twice the scale in edges**, from a root at scale its number of edges with bound plus depth one more, for every input: a child has at most twice its parent's edges (`NativeChild.numEdges_nativeChild_le`), and an active parent has at most the root's. -/ -theorem Reach.edges_le_two_mul_scale {x₀ x : Call (List ℕ)} (h₀s : x₀.scale = x₀.edges) +theorem Reach.edges_le_two_mul_scale {x₀ x : Call T} (h₀s : x₀.scale = x₀.edges) (h₀b : x₀.bound + x₀.depth = x₀.edges + 1) (h : Reach nativeMk x₀ x) : x.edges ≤ 2 * x.scale := by have key : x.edges ≤ 2 * x₀.edges := by From 537d7f579884a4a791672d450be2857466beca9c Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 11:19:29 -0400 Subject: [PATCH 15/20] feat(CountingSimulation): Theorem D.1 for entry procedures The resource analysis of the entry machine on admissible inputs, the machine within the interface's bounds (exists_fastCore_le), and the instance entryContractionAlgorithm ce : EntryContractionAlgorithm encT entry (EntryAdmissible ce), with tests. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG --- Complexity.lean | 2 + .../CountingSimulation/EntryAnalysis.lean | 375 ++++++++++++++++++ .../Frontier/TensorNetworkEntryAnalysis.lean | 93 +++++ 3 files changed, 470 insertions(+) create mode 100644 ComplexityTests/Computability/Circuit/Frontier/TensorNetworkEntryAnalysis.lean diff --git a/Complexity.lean b/Complexity.lean index e3a24b99d..5f6059aed 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -936,6 +936,7 @@ public import Complexity.Computability.Circuit.Frontier.TensorNetwork.DescribedC public import Complexity.Computability.Circuit.Frontier.TensorNetwork.DescribedLift public import Complexity.Computability.Circuit.Frontier.TensorNetwork.DirectContraction public import Complexity.Computability.Circuit.Frontier.TensorNetwork.EntryContraction +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.EntryContractionMachine public import Complexity.Computability.Circuit.Frontier.TensorNetwork.Explicit public import Complexity.Computability.Circuit.Frontier.TensorNetwork.FastContraction public import Complexity.Computability.Circuit.Frontier.TensorNetwork.FastContractionDerivation @@ -1161,6 +1162,7 @@ public import Complexity.Computability.Complexity.Classes.CountingSimulation.Ass public import Complexity.Computability.Complexity.Classes.CountingSimulation.BlockNetworks public import Complexity.Computability.Complexity.Classes.CountingSimulation.Containments public import Complexity.Computability.Complexity.Classes.CountingSimulation.Count +public import Complexity.Computability.Complexity.Classes.CountingSimulation.EntryAnalysis public import Complexity.Computability.Complexity.Classes.CountingSimulation.FastAlgorithm public import Complexity.Computability.Complexity.Classes.CountingSimulation.FastAnalysis public import Complexity.Computability.Complexity.Classes.CountingSimulation.FastLeaves diff --git a/Complexity/Computability/Complexity/Classes/CountingSimulation/EntryAnalysis.lean b/Complexity/Computability/Complexity/Classes/CountingSimulation/EntryAnalysis.lean index 1b42489f9..4093bdc1a 100644 --- a/Complexity/Computability/Complexity/Classes/CountingSimulation/EntryAnalysis.lean +++ b/Complexity/Computability/Complexity/Classes/CountingSimulation/EntryAnalysis.lean @@ -513,4 +513,379 @@ theorem exists_entryLeaves_le calc KB * cW ^ KB ≤ KB * cW ^ KB * cE := Nat.le_mul_of_pos_right _ hcE1 _ ≤ K := by omega +/-! ### The resource analysis -/ + +/-- **The resource analysis of the recursion on admissible inputs.** For a native certificate `ce` +of the entry procedure and all constants `C` and `D` there are `K` and `s₀` such that on every input +at the modulus admissible at size `s ≥ 2` with constant `C` and with precision `1 ≤ P ≤ D s`, the +root call has a derivation whose nodes, frames and values are at most `F` long, whose leaves take +time at most `TL` and space at most `SL`, with `H` open calls, such that +`H + F + SL ≤ K (n + 1) ^ K` and `TL ≤ K (n + 1) ^ K 2 ^ (K s / √⌊log₂ s⌋)` for the input length +`n`; and from `s₀` on its `N` nodes fit in the clock, `2 N - 1 ≤ clock`. -/ +theorem exists_entryAnalysis + (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) (C D : ℕ) : + ∃ K s₀ : ℕ, ∀ (s P r : ℕ) (G : DescribedNetwork T), 2 ≤ s → 1 ≤ P → P ≤ D * s → + EntryAdmissible ce C s (r, G) → + ∃ N H F TL SL : ℕ, + (scheme entry nativeMk).Eval + (reachInv entry nativeMk (rootCall (P, modulus G.numEdges, r, G))) + (rootCall (P, modulus G.numEdges, r, G)) + (0, value entry nativeMk (rootCall (P, modulus G.numEdges, r, G))) N H ∧ + (s₀ ≤ s → 2 * N - 1 ≤ clock (P, modulus G.numEdges, r, G)) ∧ + (∀ y, (reachInv entry nativeMk (rootCall (P, modulus G.numEdges, r, G))).node y → + (encCall encT y).length ≤ F ∧ + ((scheme entry nativeMk).isLeaf y = true → + (leafCertificate ce nativeMk).time y ≤ TL ∧ + (leafCertificate ce nativeMk).space y ≤ SL)) ∧ + (∀ y a, (reachInv entry nativeMk (rootCall (P, modulus G.numEdges, r, G))).frame y a → + (encPair (encCall encT) encFrame (y, a)).length ≤ F) ∧ + (∀ v, (reachInv entry nativeMk (rootCall (P, modulus G.numEdges, r, G))).value v → + (encValue v).length ≤ F) ∧ + H + F + SL ≤ K * ((encInput encT (P, modulus G.numEdges, r, G)).length + 1) ^ K ∧ + TL ≤ K * ((encInput encT (P, modulus G.numEdges, r, G)).length + 1) ^ K * + 2 ^ (K * s / Nat.sqrt (Nat.log 2 s)) := by + obtain ⟨KL, hKL⟩ := exists_entryLeaves_le ce C D + obtain ⟨sA, hsA⟩ := exists_activeBounds_le D + refine ⟨2 ^ 55 + 24 + KL + 1, max sA (D + 2), fun s P r G hs hP hPD hA => ?_⟩ + have hg : EntryContraction.guard (P, modulus G.numEdges, r, G) = true := + guard_of_entryAdmissible hA + have hsm : s ≤ G.numEdges := hA.2.1 + have hKL' := hKL s P r G hs hP hPD hA + set x := (P, modulus G.numEdges, r, G) with hx + set x₀ := rootCall x with hx₀ + set m := G.numEdges with hm + set n := (encInput encT x).length with hn + have hparts := length_parts_le (encT := encT) x + have hmv := DescribedNetwork.length_numEdges_vertices_le (encT := encT) G + simp only [hx] at hparts + rw [← hx, ← hn] at hparts + have hmn : m ≤ n := by omega + have hp₀ : P ≤ D * m := hPD.trans (Nat.mul_le_mul_left _ hsm) + -- The derivation. + obtain ⟨N, H, he, hN, hH⟩ : ∃ N H, (scheme entry nativeMk).Eval (reachInv entry nativeMk x₀) x₀ + (0, value entry nativeMk x₀) N H ∧ (max sA (D + 2) ≤ s → 2 * N - 1 ≤ clock x) ∧ + H ≤ m + 1 := by + by_cases hs₀ : max sA (D + 2) ≤ s + · have hm2 : D + 2 ≤ m := by omega + have hC1 : P / m + 1 ≤ D + 1 := by + have := Nat.div_le_div_right (c := m) hp₀ + rw [Nat.mul_div_cancel _ (by omega)] at this + omega + have hB := hsA m (by omega) (P / m + 1) hC1 + have hpC : P ≤ (P / m + 1) * m := + (Nat.lt_div_mul_add (a := P) (b := m) (by omega)).le.trans (by rw [add_mul, one_mul]) + obtain ⟨N, H, he, hN, hH⟩ := FastContraction.exists_eval_onSchedule entry hB + (onSchedule_rootCall hg (Nat.le_add_left 1 _) hpC) rfl (by omega) + exact ⟨N, H, he, fun _ => two_mul_sub_one_le_fuel hm2 hp₀ hN, + hH.trans ((Nat.log_lt_self 2 (by omega)).le.trans (Nat.le_succ _))⟩ + · obtain ⟨N, H, he, hH⟩ := FastContraction.exists_eval_reachInv (ev := entry) (mk := nativeMk) + (x₀ := x₀) rfl + exact ⟨N, H, he, fun h => absurd h hs₀, hH⟩ + -- The bounds. + set K := 2 ^ 55 + 24 + KL + 1 with hK + have hB1 : 1 ≤ n + 1 := by omega + refine ⟨N, H, 2 ^ 55 * (n + 1) ^ 24, + KL * (n + 1) ^ KL * 2 ^ (KL * s / Nat.sqrt (Nat.log 2 s)), KL * (n + 1) ^ KL, he, hN, + fun y hy => ⟨(entry_length_le_of_reach (entry := entry) hg hy).1, fun hl => ?_⟩, + fun y a ha => (entry_length_le_of_reach (entry := entry) hg ha.1).2.1 a ha, + fun v ⟨y, hy, hv⟩ => hv ▸ (entry_length_le_of_reach (entry := entry) hg hy).2.2, ?_, ?_⟩ + · exact hKL' y hy (by simpa [scheme] using hl) + · have h1 : H ≤ 1 * (n + 1) ^ K := by + have : n + 1 ≤ (n + 1) ^ K := Nat.le_self_pow (by omega) _ + omega + have h2 : 2 ^ 55 * (n + 1) ^ 24 ≤ 2 ^ 55 * (n + 1) ^ K := + Nat.mul_le_mul_left _ (Nat.pow_le_pow_right hB1 (by omega)) + have h3 : KL * (n + 1) ^ KL ≤ KL * (n + 1) ^ K := + Nat.mul_le_mul_left _ (Nat.pow_le_pow_right hB1 (by omega)) + calc H + 2 ^ 55 * (n + 1) ^ 24 + KL * (n + 1) ^ KL + ≤ 1 * (n + 1) ^ K + 2 ^ 55 * (n + 1) ^ K + KL * (n + 1) ^ K := by omega + _ ≤ K * (n + 1) ^ K := by + rw [← add_mul, ← add_mul] + exact Nat.mul_le_mul_right _ (by omega) + · exact Nat.mul_le_mul (Nat.mul_le_mul (by omega) (Nat.pow_le_pow_right hB1 (by omega))) + (Nat.pow_le_pow_right (by norm_num) (Nat.div_le_div_right (Nat.mul_le_mul_right _ + (by omega)))) + +/-! ### The resources of the machine -/ + +private theorem mul_succ_le_sq (H F : ℕ) : (H + 1) * (F + 1) ≤ (H + F + 1) ^ 2 := by nlinarith + +private theorem mul_add_one_le {c x : ℕ} (hx : 1 ≤ x) : c * x + 1 ≤ (c + 1) * x := by nlinarith + +/-- The arithmetic of the time bound. -/ +private theorem time_assemble {gT runT cT rT fuel Z TL Wb n rest Q W c₁ k₁ c₃ ka R : ℕ} + (hrun : runT ≤ cT + rT + 2 * n + (fuel + 1) * (Z + TL + Wb)) + (hq : gT + cT + rT ≤ Q) (hQ : Q ≤ c₁ * W) + (hP1 : (fuel + 1) * Z ≤ 2 * k₁ * W) (hP2 : (fuel + 1) * TL ≤ 2 * ka * W) + (hP3 : (fuel + 1) * Wb ≤ 2 * c₃ * W) (hn : n + 1 ≤ W) (hR : rest ≤ R * W) : + gT + (2 * runT + n + rest) ≤ (2 * c₁ + 5 + 4 * k₁ + 4 * c₃ + 4 * ka + R) * W := by + have e : (fuel + 1) * (Z + TL + Wb) = (fuel + 1) * Z + (fuel + 1) * TL + (fuel + 1) * Wb := by + ring + rw [e] at hrun + nlinarith + +/-- The arithmetic of the space bound. -/ +private theorem space_assemble {gS runS cS rS fb Z SL n rest Q W c₁ k₁ ka R : ℕ} + (hrun : runS ≤ cS + rS + 2 * n + Z + SL + fb) + (hq : gS + cS + rS + fb ≤ Q) (hQ : Q ≤ c₁ * W) (hZ : Z ≤ k₁ * W) (hSL : SL ≤ ka * W) + (hn : n + 1 ≤ W) (hR : rest ≤ R * W) : + gS + (2 * runS + n + rest) ≤ (2 * c₁ + 5 + 2 * k₁ + 2 * ka + R) * W := by + nlinarith + +/-- **The machine within the interface's bounds.** For a native certificate `ce` of the entry +procedure and all constants `C` and `D` there is `K` such that on every input at the modulus +admissible at size `s ≥ 2` with constant `C` and with precision `1 ≤ P ≤ D s`, the machine +`EntryContraction.fastCore ce` takes time at most `K (n + 1) ^ K 2 ^ (K s / √⌊log₂ s⌋)` and space at +most `K (n + 1) ^ K`. Admissible inputs pass the guard; from some size on the clocked run returns +the root's value, and below it direct summation costs a constant factor. -/ +theorem exists_fastCore_le + (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) (C D : ℕ) : + ∃ K : ℕ, ∀ (s P r : ℕ) (G : DescribedNetwork T), 2 ≤ s → 1 ≤ P → P ≤ D * s → + EntryAdmissible ce C s (r, G) → + (fastCore ce).time (P, modulus G.numEdges, r, G) ≤ + K * ((encInput encT (P, modulus G.numEdges, r, G)).length + 1) ^ K * + 2 ^ (K * s / Nat.sqrt (Nat.log 2 s)) ∧ + (fastCore ce).space (P, modulus G.numEdges, r, G) ≤ + K * ((encInput encT (P, modulus G.numEdges, r, G)).length + 1) ^ K := by + obtain ⟨Ka, s₀, hKa⟩ := exists_entryAnalysis ce C D + obtain ⟨K₁, hK₁⟩ := Scheme.certificate_le + (FastContraction.scheme_nativeMk_polyTime (encT := encT) entry) (leafCertificate ce nativeMk) + obtain ⟨K₂, hK₂⟩ := exists_directCore_le (entry := entry) ce C + have hgP := NativeCertificate.ofPolyTime_isPolynomial (guard_polyTime (encT := encT)) + have hcnP := NativeCertificate.ofPolyTime_isPolynomial (clock_polyTime (encT := encT)) + have hcrP := NativeCertificate.ofPolyTime_isPolynomial (rootCall_polyTime (encT := encT)) + have hfuelL := (clock_polyTime (encT := encT)).polyBounded_length + obtain ⟨c₁, d₁, h₁⟩ := ((((((hgP.1.add hgP.2).add hcnP.1).add hcnP.2).add hcrP.1).add + hcrP.2).add hfuelL).exists_le + have htP := NativeCertificate.ofPolyTime_isPolynomial (valueTag_polyTime (encT := encT)) + have hoP := NativeCertificate.ofPolyTime_isPolynomial (valueList_polyTime (encT := encT)) + have hfP := NativeCertificate.ofPolyTime_isPolynomial + (ComputableInPolyTime.fst (encInput encT) encValue) + obtain ⟨c₂, d₂, h₂⟩ := (((((htP.1.add htP.2).add hoP.1).add hoP.2).add hfP.1).add + hfP.2).exists_le + -- The constants. + set E := 2 * d₁ + 2 * Ka * K₁ + (Ka + 1) * d₂ + K₂ + Ka + 1 with hE + set Kc := 2 * c₁ + 5 + 4 * (K₁ * (Ka + 1) ^ (2 * K₁)) + 4 * (c₁ + 1) ^ 2 + 4 * Ka + + (c₂ * (Ka + 2) ^ d₂ + K₂ * 2 ^ (K₂ * s₀)) with hKc + refine ⟨Kc + E + fuelConst * (C + D) + Ka, fun s P r G hs hP hPD hA => ?_⟩ + obtain ⟨N, H, F, TL, SL, he, hN, hnode, hframe, hvalue, hHFS, hTL⟩ := + hKa s P r G hs hP hPD hA + have hg : EntryContraction.guard (P, modulus G.numEdges, r, G) = true := + guard_of_entryAdmissible hA + obtain ⟨hdT, hdS⟩ := hK₂ s P r G hA + have hsm : s ≤ G.numEdges := hA.2.1 + have hmC : G.numEdges ≤ C * s := hA.2.2.1 + set x := (P, modulus G.numEdges, r, G) with hx + set n := (encInput encT x).length with hn + set B := n + 1 with hB + have hB1 : 1 ≤ B := by omega + set S := Nat.sqrt (Nat.log 2 s) + set Xf := 2 ^ (fuelConst * (C + D) * s / S) + set Xa := 2 ^ (Ka * s / S) + set X := 2 ^ ((fuelConst * (C + D) + Ka) * s / S) + have hXfX : Xf ≤ X := Nat.pow_le_pow_right (by norm_num) + (Nat.div_le_div_right (Nat.mul_le_mul_right _ (by omega))) + have hXfXa : Xf * Xa ≤ X := by + rw [← pow_add] + refine Nat.pow_le_pow_right (by norm_num) (Nat.div_add_div_le_add_div.trans ?_) + rw [add_mul] + have hX1 : 1 ≤ X := Nat.one_le_two_pow + -- The run. + obtain ⟨hrT, hrS⟩ := hK₁ (NativeCertificate.ofPolyTime clock_polyTime) + (NativeCertificate.ofPolyTime rootCall_polyTime) _ F TL SL hnode hframe hvalue x _ N H he + have hclock : clock x ≤ Xf := clock_le hs hsm hmC hPD + have hq1 := h₁ x + have hrT' : (runCore ce).time x ≤ _ := hrT + have hrS' : (runCore ce).space x ≤ _ := hrS + -- Polynomial pieces. + set Q₁ := c₁ * B ^ d₁ with hQ₁ + have hBK (k : ℕ) : 1 ≤ B ^ k := Nat.one_le_pow _ _ (by omega) + have hHF : (H + 1) * (F + 1) ≤ ((Ka + 1) * B ^ Ka) ^ 2 := by + have h1 : H + F ≤ Ka * B ^ Ka := by have := hHFS; omega + have h2 := hBK Ka + calc (H + 1) * (F + 1) ≤ (H + F + 1) ^ 2 := mul_succ_le_sq H F + _ ≤ (Ka * B ^ Ka + B ^ Ka) ^ 2 := Nat.pow_le_pow_left (by omega) 2 + _ = ((Ka + 1) * B ^ Ka) ^ 2 := by ring + have hZ : K₁ * ((H + 1) * (F + 1)) ^ K₁ ≤ K₁ * (Ka + 1) ^ (2 * K₁) * B ^ (2 * Ka * K₁) := by + calc K₁ * ((H + 1) * (F + 1)) ^ K₁ ≤ K₁ * (((Ka + 1) * B ^ Ka) ^ 2) ^ K₁ := + Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hHF _) + _ = K₁ * (Ka + 1) ^ (2 * K₁) * B ^ (2 * Ka * K₁) := by + rw [mul_pow, ← pow_mul, mul_pow, ← pow_mul, ← pow_mul, + show Ka * 2 * K₁ = 2 * Ka * K₁ by ring] + ring + have hW : ((encNat (clock x)).length + 1) ^ 2 ≤ (c₁ + 1) ^ 2 * B ^ (2 * d₁) := by + have h1 : (encNat (clock x)).length ≤ Q₁ := by omega + have h2 := hBK d₁ + calc _ ≤ (Q₁ + 1) ^ 2 := Nat.pow_le_pow_left (by omega) 2 + _ ≤ ((c₁ + 1) * B ^ d₁) ^ 2 := Nat.pow_le_pow_left (mul_add_one_le h2) 2 + _ = (c₁ + 1) ^ 2 * B ^ (2 * d₁) := by ring + have hTL' : TL ≤ Ka * B ^ Ka * Xa := hTL + have hSL : SL ≤ Ka * B ^ Ka := by have := hHFS; omega + -- The output and direct summation. + set R₁ := c₂ * (Ka + 2) ^ d₂ * B ^ ((Ka + 1) * d₂) with hR₁ + set R₂ := K₂ * 2 ^ (K₂ * s₀) * B ^ K₂ with hR₂ + have hdec : ∀ v : ℕ × List ℕ, (reachInv entry nativeMk (rootCall x)).value v → + (NativeCertificate.ofPolyTime (valueTag_polyTime (encT := encT))).time (x, v) + + (NativeCertificate.ofPolyTime (valueTag_polyTime (encT := encT))).space (x, v) + + (NativeCertificate.ofPolyTime (valueList_polyTime (encT := encT))).time (x, v) + + (NativeCertificate.ofPolyTime (valueList_polyTime (encT := encT))).space (x, v) + + (NativeCertificate.ofPolyTime + (ComputableInPolyTime.fst (encInput encT) encValue)).time (x, v) + + (NativeCertificate.ofPolyTime + (ComputableInPolyTime.fst (encInput encT) encValue)).space (x, v) ≤ R₁ := by + intro v hv + have h := h₂ (x, v) + have hv' := hvalue v hv + have hF : F ≤ Ka * B ^ Ka := by have := hHFS; omega + have hk1 : B ≤ B ^ (Ka + 1) := by + calc B = B ^ 1 := (pow_one B).symm + _ ≤ B ^ (Ka + 1) := Nat.pow_le_pow_right hB1 (by omega) + have hk2 : B ^ Ka ≤ B ^ (Ka + 1) := Nat.pow_le_pow_right hB1 (by omega) + have hlen : (encPair (encInput encT) encValue (x, v)).length + 1 ≤ + (Ka + 2) * B ^ (Ka + 1) := by + have hl := length_encPair (enc₁ := encInput encT) (enc₂ := encValue) (x, v) + simp only at hl + rw [hl] + have : Ka * B ^ Ka ≤ Ka * B ^ (Ka + 1) := Nat.mul_le_mul_left _ hk2 + have e : (Ka + 2) * B ^ (Ka + 1) = Ka * B ^ (Ka + 1) + 2 * B ^ (Ka + 1) := by ring + omega + calc _ ≤ c₂ * ((encPair (encInput encT) encValue (x, v)).length + 1) ^ d₂ := h + _ ≤ c₂ * ((Ka + 2) * B ^ (Ka + 1)) ^ d₂ := + Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hlen _) + _ = R₁ := by rw [hR₁, mul_pow, ← pow_mul, Nat.mul_assoc] + have hdir (hs₀ : s < s₀) : (directCore entry ce).time x ≤ R₂ := by + refine hdT.trans ?_ + have h2 : 2 ^ (K₂ * s) ≤ 2 ^ (K₂ * s₀) := + Nat.pow_le_pow_right (by norm_num) (Nat.mul_le_mul_left _ hs₀.le) + calc K₂ * B ^ K₂ * 2 ^ (K₂ * s) ≤ K₂ * B ^ K₂ * 2 ^ (K₂ * s₀) := Nat.mul_le_mul_left _ h2 + _ = R₂ := by rw [hR₂]; ring + have hdirS : (directCore entry ce).space x ≤ R₂ := + hdS.trans (by + rw [hR₂] + calc K₂ * B ^ K₂ ≤ K₂ * B ^ K₂ * 2 ^ (K₂ * s₀) := + Nat.le_mul_of_pos_right _ Nat.one_le_two_pow + _ = K₂ * 2 ^ (K₂ * s₀) * B ^ K₂ := by ring) + have hbig : s₀ ≤ s → (scheme entry nativeMk).run clock rootCall x = + some (0, value entry nativeMk (rootCall x)) := + fun h => Scheme.run_eq_some he (hN h) + clear hKa hK₁ hK₂ h₁ h₂ + -- Everything against `W = B ^ E X`. + set W := B ^ E * X with hWdef + have lift {c d : ℕ} (hd : d ≤ E) : c * B ^ d ≤ c * W := by + rw [hWdef, ← Nat.mul_assoc] + exact (Nat.mul_le_mul_left c (Nat.pow_le_pow_right hB1 hd)).trans + (Nat.le_mul_of_pos_right _ hX1) + have lift' {c d : ℕ} (hd : d ≤ E) : c * B ^ d ≤ c * B ^ E := + Nat.mul_le_mul_left _ (Nat.pow_le_pow_right hB1 hd) + have hQW : Q₁ ≤ c₁ * W := lift (by omega) + have hR₁W : R₁ ≤ c₂ * (Ka + 2) ^ d₂ * W := lift (by omega) + have hR₂W : R₂ ≤ K₂ * 2 ^ (K₂ * s₀) * W := lift (by omega) + have hnW : n + 1 ≤ W := by + have := lift (c := 1) (d := 1) (by omega); rw [pow_one] at this; omega + have hfuel1 : clock x + 1 ≤ 2 * Xf := by + have : 1 ≤ Xf := Nat.one_le_two_pow + omega + have hP1 : (clock x + 1) * (K₁ * ((H + 1) * (F + 1)) ^ K₁) ≤ + 2 * (K₁ * (Ka + 1) ^ (2 * K₁)) * W := by + calc _ ≤ (2 * Xf) * (K₁ * (Ka + 1) ^ (2 * K₁) * B ^ (2 * Ka * K₁)) := + Nat.mul_le_mul hfuel1 hZ + _ = 2 * (K₁ * (Ka + 1) ^ (2 * K₁)) * (B ^ (2 * Ka * K₁) * Xf) := by ring + _ ≤ 2 * (K₁ * (Ka + 1) ^ (2 * K₁)) * W := Nat.mul_le_mul_left _ + (Nat.mul_le_mul (Nat.pow_le_pow_right hB1 (by omega)) hXfX) + have hP2 : (clock x + 1) * TL ≤ 2 * Ka * W := by + calc _ ≤ (2 * Xf) * (Ka * B ^ Ka * Xa) := Nat.mul_le_mul hfuel1 hTL' + _ = 2 * Ka * (B ^ Ka * (Xf * Xa)) := by ring + _ ≤ 2 * Ka * W := Nat.mul_le_mul_left _ + (Nat.mul_le_mul (Nat.pow_le_pow_right hB1 (by omega)) hXfXa) + have hP3 : (clock x + 1) * ((encNat (clock x)).length + 1) ^ 2 ≤ 2 * (c₁ + 1) ^ 2 * W := by + calc _ ≤ (2 * Xf) * ((c₁ + 1) ^ 2 * B ^ (2 * d₁)) := Nat.mul_le_mul hfuel1 hW + _ = 2 * (c₁ + 1) ^ 2 * (B ^ (2 * d₁) * Xf) := by ring + _ ≤ 2 * (c₁ + 1) ^ 2 * W := Nat.mul_le_mul_left _ + (Nat.mul_le_mul (Nat.pow_le_pow_right hB1 (by omega)) hXfX) + have hZE : K₁ * ((H + 1) * (F + 1)) ^ K₁ ≤ K₁ * (Ka + 1) ^ (2 * K₁) * B ^ E := + hZ.trans (lift' (by omega)) + have hQE : Q₁ ≤ c₁ * B ^ E := lift' (by omega) + have hR₁E : R₁ ≤ c₂ * (Ka + 2) ^ d₂ * B ^ E := lift' (by omega) + have hR₂E : R₂ ≤ K₂ * 2 ^ (K₂ * s₀) * B ^ E := lift' (by omega) + have hSLE : SL ≤ Ka * B ^ E := hSL.trans (lift' (by omega)) + have hnE : n + 1 ≤ B ^ E := by + have := lift' (c := 1) (d := 1) (by omega); rw [pow_one] at this; omega + have hKK : Kc ≤ Kc + E + fuelConst * (C + D) + Ka := by omega + have hBE : B ^ E ≤ B ^ (Kc + E + fuelConst * (C + D) + Ka) := + Nat.pow_le_pow_right hB1 (by omega) + have hXK : X ≤ 2 ^ ((Kc + E + fuelConst * (C + D) + Ka) * s / S) := + Nat.pow_le_pow_right (by norm_num) (Nat.div_le_div_right (Nat.mul_le_mul_right _ (by omega))) + have hR : R₁ + R₂ ≤ (c₂ * (Ka + 2) ^ d₂ + K₂ * 2 ^ (K₂ * s₀)) * W := by + rw [Nat.add_mul]; exact Nat.add_le_add hR₁W hR₂W + have hRE : R₁ + R₂ ≤ (c₂ * (Ka + 2) ^ d₂ + K₂ * 2 ^ (K₂ * s₀)) * B ^ E := by + rw [Nat.add_mul]; exact Nat.add_le_add hR₁E hR₂E + refine ⟨?_, ?_⟩ + · rw [fastCore_time] + simp only [hg, ↓reduceIte] + have hrest : ((scheme entry nativeMk).run clock rootCall x).elim + ((directCore entry ce).time x) (fun v => + (NativeCertificate.ofPolyTime (valueTag_polyTime (encT := encT))).time (x, v) + + if decide (v.1 = 0) = true then + (NativeCertificate.ofPolyTime (valueList_polyTime (encT := encT))).time (x, v) + else (NativeCertificate.ofPolyTime + (ComputableInPolyTime.fst (encInput encT) encValue)).time (x, v) + + (directCore entry ce).time x) ≤ R₁ + R₂ := by + rcases hr : (scheme entry nativeMk).run clock rootCall x with _ | v + · by_cases hs₀ : s₀ ≤ s + · rw [hbig hs₀] at hr; cases hr + · simp only [Option.elim_none]; have := hdir (by omega); omega + · have hd := hdec v (Scheme.value_of_run_eq_some he hr) + simp only [Option.elim_some] + split_ifs with h0 + · omega + · by_cases hs₀ : s₀ ≤ s + · rw [hbig hs₀] at hr; cases hr; simp at h0 + · have := hdir (by omega); omega + have htot := time_assemble (gT := (NativeCertificate.ofPolyTime + (guard_polyTime (encT := encT))).time x) hrT' (by omega) hQW hP1 hP2 hP3 hnW + (hrest.trans hR) + calc _ ≤ Kc * W := by rw [hKc]; exact htot + _ ≤ _ := by + rw [hWdef, ← Nat.mul_assoc] + exact Nat.mul_le_mul (Nat.mul_le_mul hKK hBE) hXK + · rw [fastCore_space] + simp only [hg, ↓reduceIte] + have hrest : ((scheme entry nativeMk).run clock rootCall x).elim + ((directCore entry ce).space x) (fun v => + (NativeCertificate.ofPolyTime (valueTag_polyTime (encT := encT))).space (x, v) + + if decide (v.1 = 0) = true then + (NativeCertificate.ofPolyTime (valueList_polyTime (encT := encT))).space (x, v) + else (NativeCertificate.ofPolyTime + (ComputableInPolyTime.fst (encInput encT) encValue)).space (x, v) + + (directCore entry ce).space x) ≤ R₁ + R₂ := by + rcases hr : (scheme entry nativeMk).run clock rootCall x with _ | v + · simp only [Option.elim_none]; omega + · have hd := hdec v (Scheme.value_of_run_eq_some he hr) + simp only [Option.elim_some] + split_ifs <;> omega + have htot := space_assemble (gS := (NativeCertificate.ofPolyTime + (guard_polyTime (encT := encT))).space x) hrS' (by omega) hQE hZE hSLE hnE + (hrest.trans hRE) + calc _ ≤ (2 * c₁ + 5 + 2 * (K₁ * (Ka + 1) ^ (2 * K₁)) + 2 * Ka + + (c₂ * (Ka + 2) ^ d₂ + K₂ * 2 ^ (K₂ * s₀))) * B ^ E := htot + _ ≤ Kc * B ^ E := Nat.mul_le_mul_right _ (by rw [hKc]; omega) + _ ≤ _ := Nat.mul_le_mul hKK hBE + +/-! ### The contraction algorithm -/ + +/-- **Theorem D.1 for entry procedures** ([OpenAI2026ETH], p. 53, at truncation order `1`): for +every native certificate `ce` of an entry procedure, the guarded native recursion with direct +summation as the fallback (`EntryContraction.fastCore ce`) is a contraction algorithm for the +networks admissible for `ce`, in time `poly(n) 2 ^ O(s / √⌊log₂ s⌋)` and polynomial space. -/ +noncomputable def entryContractionAlgorithm + (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) : + EntryContractionAlgorithm encT entry (EntryAdmissible ce) where + core := coreValue entry + certificate := fastCore ce + val_core := val_coreValue + bound C D := exists_fastCore_le ce C D + end Cslib.Complexity.CountingSimulation diff --git a/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkEntryAnalysis.lean b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkEntryAnalysis.lean new file mode 100644 index 000000000..f5a5a6d8c --- /dev/null +++ b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkEntryAnalysis.lean @@ -0,0 +1,93 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: local-only (test driver) + +public import Complexity.Computability.Complexity.Classes.CountingSimulation.EntryAnalysis + +/-! +# Tests for the contraction algorithm with entry procedures + +The guard of the entry machine on a network of two parallel edges between a row vertex and a +column vertex, at the modulus of its number of edges and at another modulus; the guarded root is +well-formed and has no packets; an admissible input passes the guard; and the contraction +algorithm for entry procedures, instantiated at the entry procedure of tables, is correct with no +remaining hypothesis. +-/ + +@[expose] public section + +namespace ComplexityTests.TensorNetworkEntryAnalysis + +open Cslib Cslib.Circuits.Frontier Cslib.Circuits.Frontier.EntryContraction + Cslib.Complexity.CountingSimulation +open Turing.MultiTapeTM (encList encNat) + +/-- Two parallel edges between a row vertex with table `1, 2, 3, 4` and a column vertex of +ones. -/ +abbrev twoEdges : DescribedNetwork (List ℕ) := ⟨2, [([0, 1], [1, 2, 3, 4]), ([0, 1], [1, 1, 1, 1])]⟩ + +/-! ### The guard -/ + +-- The guard holds at the modulus of the number of edges. +example : EntryContraction.guard (3, FastContraction.modulus 2, 1, twoEdges) = true := by decide + +-- It fails at another modulus, and when the rows are not first. +example : EntryContraction.guard (3, [1, 1], 1, twoEdges) = false := by decide + +example : EntryContraction.guard (3, FastContraction.modulus 2, 0, twoEdges) = false := by decide + +-- The guarded root is well-formed and has no packets. +example : FastContraction.WF (rootCall (3, FastContraction.modulus 2, 1, twoEdges)) ∧ + FastContraction.PacketShape (rootCall (3, FastContraction.modulus 2, 1, twoEdges)) := + ⟨wf_rootCall (by decide), packetShape_rootCall _⟩ + +-- An admissible input passes the guard at the modulus, at every precision. +example (P : ℕ) {C s : ℕ} (hA : EntryAdmissible tableEntryCertificate C s (1, twoEdges)) : + EntryContraction.guard (P, FastContraction.modulus twoEdges.numEdges, 1, twoEdges) = true := + guard_of_entryAdmissible hA + +/-! ### Root descriptors along the recursion -/ + +-- Every root descriptor of a reached call comes from a vertex of the input with as many ports. +example (x : ℕ × List ℕ × ℕ × DescribedNetwork (List ℕ)) (y : FastContraction.Call (List ℕ)) + (hy : FastContraction.Reach FastContraction.nativeMk (rootCall x) y) + (v : List ℕ × VertexDesc (List ℕ)) (hv : v ∈ y.net.vertices) (t : List ℕ) + (ht : v.2 = .inl t) : ∃ w ∈ x.2.2.2.vertices, w.2 = t ∧ w.1.length = v.1.length := by + obtain ⟨w, hw, hwt, hlen⟩ := hy.exists_root_of_inl hv ht + change w ∈ List.map _ x.2.2.2.vertices at hw + obtain ⟨u, hu, rfl⟩ := List.mem_map.mp hw + exact ⟨u, hu, Sum.inl_injective hwt, hlen⟩ + +/-! ### The contraction algorithm -/ + +/-- The contraction algorithm for the entry procedure of tables, with no remaining hypothesis. -/ +noncomputable def tableAlgorithm : + EntryContractionAlgorithm (encList encNat) tableEntry (EntryAdmissible tableEntryCertificate) := + entryContractionAlgorithm tableEntryCertificate + +-- It is correct at the modulus of the number of edges. +example : GaloisRingArith.val 3 (FastContraction.modulus 2) + (tableAlgorithm.core (3, FastContraction.modulus 2, 1, twoEdges)) = + ((10 : ℕ) : GaloisRingArith.Ring 3 (FastContraction.modulus 2)) := by + have hval := val_directCore_tableEntry 3 (FastContraction.modulus 2) twoEdges + rw [val_directCore] at hval + refine (tableAlgorithm.val_core 3 1 twoEdges).trans (hval.trans ?_) + congr 1 + +-- Its bound holds for all constants. +example (C D : ℕ) : ∃ K : ℕ, ∀ (s P r : ℕ) (G : DescribedNetwork (List ℕ)), 2 ≤ s → 1 ≤ P → + P ≤ D * s → EntryAdmissible tableEntryCertificate C s (r, G) → + tableAlgorithm.certificate.time (P, FastContraction.modulus G.numEdges, r, G) ≤ + K * ((encInput (encList encNat) (P, FastContraction.modulus G.numEdges, r, G)).length + + 1) ^ K * 2 ^ (K * s / Nat.sqrt (Nat.log 2 s)) ∧ + tableAlgorithm.certificate.space (P, FastContraction.modulus G.numEdges, r, G) ≤ + K * ((encInput (encList encNat) (P, FastContraction.modulus G.numEdges, r, G)).length + + 1) ^ K := + tableAlgorithm.bound C D + +end ComplexityTests.TensorNetworkEntryAnalysis From 48ee919e8f0684b051551d7a7505855f89c6adc0 Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 11:21:56 -0400 Subject: [PATCH 16/20] chore(Frontier/TensorNetwork): name degreeBound_mono in ContractionSchedule; tidy exposure Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG --- .../Frontier/TensorNetwork/EntryContractionMachine.lean | 6 ++++-- .../Classes/CountingSimulation/EntryAnalysis.lean | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContractionMachine.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContractionMachine.lean index 1f57e2a94..f6aad0ffa 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContractionMachine.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContractionMachine.lean @@ -67,6 +67,7 @@ Its native certificate is `EntryContraction.fastCore`; its resources are analyze * `Cslib.Circuits.Frontier.DescribedNetwork.rowsFirst_polyTime`: rows-first bipartiteness is decidable in polynomial time. * `Cslib.Circuits.Frontier.EntryContraction.guard_polyTime`: the guard is polynomial-time. +* `Cslib.Circuits.Frontier.ContractionSchedule.degreeBound_mono`: the degree bound is monotone. * `Cslib.Circuits.Frontier.EntryContraction.guard_of_entryAdmissible`: admissible inputs pass it. * `Cslib.Circuits.Frontier.EntryContraction.wf_rootCall`: guarded roots are well-formed. * `Cslib.Circuits.Frontier.EntryContraction.val_coreValue`: the machine is correct. @@ -261,7 +262,8 @@ theorem guard_polyTime : ComputableInPolyTime (guard (T := T)) (encInput encT) e simp only [guard, Function.comp_apply, Bool.decide_and, List.all_eq, decide_eq_true_eq] /-- `degreeBound` is monotone. -/ -theorem degreeBound_mono {a b : ℕ} (h : a ≤ b) : degreeBound a ≤ degreeBound b := +theorem _root_.Cslib.Circuits.Frontier.ContractionSchedule.degreeBound_mono {a b : ℕ} (h : a ≤ b) : + degreeBound a ≤ degreeBound b := Nat.pow_le_pow_right (by norm_num) (by have := Nat.log_mono_right (b := 2) h; omega) /-- **Admissible inputs pass the guard** at the modulus of the number of edges: their degree is at @@ -331,7 +333,7 @@ variable (entry) in /-- **The result of the machine** on an input `(P, fl, r, G)`: on guarded inputs, the coefficient list of a value tagged `0` returned by the clocked run from the root call, and direct summation otherwise. -/ -@[expose] noncomputable def coreValue (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : List ℕ := +noncomputable def coreValue (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : List ℕ := if guard x then ((scheme entry nativeMk).run clock rootCall x).elim (DescribedNetwork.sumValue SumOps.galois entry (x.1, x.2.1) x.2.2.2) diff --git a/Complexity/Computability/Complexity/Classes/CountingSimulation/EntryAnalysis.lean b/Complexity/Computability/Complexity/Classes/CountingSimulation/EntryAnalysis.lean index 4093bdc1a..0bbf9e5e7 100644 --- a/Complexity/Computability/Complexity/Classes/CountingSimulation/EntryAnalysis.lean +++ b/Complexity/Computability/Complexity/Classes/CountingSimulation/EntryAnalysis.lean @@ -209,7 +209,7 @@ variable {T : Type} {encT : T ↪ List Bool} {entry : T → List Bool → List /-! ### The root -/ /-- The parts of an encoded input `(P, fl, r, G)` against its length. -/ -theorem length_parts_le (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : +theorem length_parts_le_encInput (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : x.1 + x.2.1.length + (encNat x.2.2.1).length + (DescribedNetwork.encDescribed encT x.2.2.2).length ≤ (encInput encT x).length := by obtain ⟨P, fl, r, G⟩ := x @@ -268,7 +268,7 @@ theorem entry_length_le_of_reach {x : ℕ × List ℕ × ℕ × DescribedNetwork set m := G.numEdges with hm set n := (encInput encT (P, fl, r, G)).length with hn set Y := n + 1 with hY - have hparts := length_parts_le (encT := encT) (P, fl, r, G) + have hparts := length_parts_le_encInput (encT := encT) (P, fl, r, G) have hmv := DescribedNetwork.length_numEdges_vertices_le (encT := encT) G simp only at hparts rw [← hn] at hparts @@ -440,7 +440,7 @@ theorem exists_entryLeaves_le set Y := n + 1 with hY set S := Nat.sqrt (Nat.log 2 s) with hS set L := (DescribedNetwork.encDescribed encT G).length with hL - have hparts := length_parts_le (encT := encT) (P, modulus G.numEdges, r, G) + have hparts := length_parts_le_encInput (encT := encT) (P, modulus G.numEdges, r, G) have hmv := DescribedNetwork.length_numEdges_vertices_le (encT := encT) G simp only at hparts rw [← hn] at hparts @@ -556,7 +556,7 @@ theorem exists_entryAnalysis set x₀ := rootCall x with hx₀ set m := G.numEdges with hm set n := (encInput encT x).length with hn - have hparts := length_parts_le (encT := encT) x + have hparts := length_parts_le_encInput (encT := encT) x have hmv := DescribedNetwork.length_numEdges_vertices_le (encT := encT) G simp only [hx] at hparts rw [← hx, ← hn] at hparts From 87ca2950e2aaac5c87e183b7885264cd0223f29f Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 11:35:03 -0400 Subject: [PATCH 17/20] =?UTF-8?q?feat(CountingSimulation):=20Theorem=20D.1?= =?UTF-8?q?=20at=20truncation=20order=20=E2=84=93=20for=20entry=20procedur?= =?UTF-8?q?es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `TruncatedContractionAlgorithm.ofEntry` instantiates `ofCore` with a contraction algorithm for the specialized entries and discharges its hypotheses: specialization keeps networks admissible (`exists_entryAdmissible_specNet`), entries fit `poly(L) 2 ^ O(s)` (`exists_entry_le_of_entryAdmissible`), and the shape comes from `TruncEntryAdmissible`, which adds the vertex bound `k ≤ C s` to `EntryAdmissible`. `CountingSimulation.truncEntryContractionAlgorithm ce` applies it to `entryContractionAlgorithm (specEntryCertificate entry ce)`. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG --- Complexity.lean | 2 + .../TensorNetwork/TruncatedEntry.lean | 287 ++++++++++++++++++ .../CountingSimulation/TruncatedEntry.lean | 67 ++++ .../Frontier/TensorNetworkTruncatedEntry.lean | 90 ++++++ 4 files changed, 446 insertions(+) create mode 100644 Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedEntry.lean create mode 100644 Complexity/Computability/Complexity/Classes/CountingSimulation/TruncatedEntry.lean create mode 100644 ComplexityTests/Computability/Circuit/Frontier/TensorNetworkTruncatedEntry.lean diff --git a/Complexity.lean b/Complexity.lean index dc8f3386b..339310fcd 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -968,6 +968,7 @@ public import Complexity.Computability.Circuit.Frontier.TensorNetwork.ScheduledR public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TaperedRecovery public import Complexity.Computability.Circuit.Frontier.TensorNetwork.Truncated public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TruncatedAlgorithm +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TruncatedEntry public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TruncatedPolyTime public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TruncatedResources public import Complexity.Computability.Circuit.Frontier.TensorNetwork.VertexDesc @@ -1173,6 +1174,7 @@ public import Complexity.Computability.Complexity.Classes.CountingSimulation.Fas public import Complexity.Computability.Complexity.Classes.CountingSimulation.FastSimulation public import Complexity.Computability.Complexity.Classes.CountingSimulation.Guarded public import Complexity.Computability.Complexity.Classes.CountingSimulation.Interfaces +public import Complexity.Computability.Complexity.Classes.CountingSimulation.TruncatedEntry public import Complexity.Computability.Complexity.Classes.DP public import Complexity.Computability.Complexity.Classes.EXP public import Complexity.Computability.Complexity.Classes.FewP diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedEntry.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedEntry.lean new file mode 100644 index 000000000..a45969f7f --- /dev/null +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/TruncatedEntry.lean @@ -0,0 +1,287 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TruncatedAlgorithm +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.EntryContraction +import Complexity.Computability.Machines.Turing.MultiTape.Encodings.Length + +/-! +# Theorem D.1 at truncation order `ℓ` for entry procedures + +Theorem D.1 of [OpenAI2026ETH] (p. 53) contracts networks whose entries lie in +`B_{P,ℓ} = (ℤ / 2 ^ P)[V] / (V ^ ℓ)` and are computed by procedures. This file reduces it to the +case `ℓ = 1` with entries in `A_P = (ℤ / 2 ^ P)[U] / (f)`: from a contraction algorithm for entry +procedures (`Cslib.Circuits.Frontier.EntryContractionAlgorithm`) for the specialized entries, +`Cslib.Circuits.Frontier.TruncatedContractionAlgorithm.ofEntry` builds a truncated contraction +algorithm for the original entries. It instantiates the assembly +`Cslib.Circuits.Frontier.TruncatedContractionAlgorithm.ofCore` and discharges its hypotheses. + +**Admissible networks** (`Cslib.Circuits.Frontier.TruncEntryAdmissible`). The hypotheses of +Theorem D.1 as in `Cslib.Circuits.Frontier.EntryAdmissible`, plus **at most `C s` vertices**. The +precision and the truncation order are bounded by `P, ℓ ≤ D s` in the interface itself. + +*Narrowing against Theorem D.1.* The theorem asks only that the number of vertices be bounded by +a fixed polynomial in `s`. The bound `k ≤ C s` is what the assembly needs: the reduction of +truncation order `ℓ` to `A_P` interpolates at `(ℓ - 1) k + 1` points, which must fit in the +residues of the modulus `FastContraction.modulus m`, more than `m ^ 4 / 16` of them for `m` edges. +With `k ≤ C s` and `ℓ ≤ D s` they fit once `s ≥ 4 (C D + 1)` +(`Cslib.Circuits.Frontier.truncGuard_of_le`), and below that size direct summation costs a constant +factor. The applications satisfy the narrower bound: the network of Lemma D.2 (p. 56) has +`2 J = 2 ⌈n ^ (1/4)⌉` vertices at size `s = n ν`, and that of the fixed-density bound (§D.2, +p. 54) has `O_k(n + m)` vertices at size `s = n + m`. + +**The hypotheses of the assembly.** +* *Specialization keeps networks admissible* (`EntryContraction.exists_entryAdmissible_specNet`): + the specialized network has the same ports, and evaluating a specialized entry costs the original + entry plus a polynomial in the lengths of its input and of the original entry + (`Cslib.Circuits.Frontier.specEntryCertificate_le`). The original entry is at most linear in its + space, and specialization does not shorten the encoded network + (`DescribedNetwork.length_encDescribed_le_specNet`). +* *Entries within `poly(L) 2 ^ O(s)`* (`EntryContraction.exists_entry_le_of_entryAdmissible`): the + number of edges is in unary in the encoding, so `s ≤ L`, and `⌈s ^ (9/10)⌉ ≤ s`. +* *The shape*: between `s` and `C s` edges by `EntryAdmissible`, and at most `C s` vertices. + +## Main definitions + +* `Cslib.Circuits.Frontier.TruncEntryAdmissible`: the admissible networks. +* `Cslib.Circuits.Frontier.TruncatedContractionAlgorithm.ofEntry`: the truncated contraction + algorithm from a contraction algorithm for the specialized entries. + +## Main results + +* `Cslib.Circuits.Frontier.DescribedNetwork.isRowsFirstBipartite_specNet_iff`: specialization + keeps a network rows-first. +* `Cslib.Circuits.Frontier.DescribedNetwork.length_encDescribed_le_specNet`: specialization does + not shorten the encoded network. +* `Cslib.Circuits.Frontier.EntryContraction.exists_entryAdmissible_specNet`: specialization keeps + networks admissible. +* `Cslib.Circuits.Frontier.EntryContraction.exists_entry_le_of_entryAdmissible`: entries within + `poly(L) 2 ^ O(s)` on admissible networks. + +## References + +* [OpenAI, *The Exponential Time Hypothesis is False*][OpenAI2026ETH], Theorem D.1 (p. 53), the + fixed-density bound (§D.2, p. 54) and Lemma D.2 (pp. 54–56). +-/ + +public section + +namespace Cslib.Circuits.Frontier + +open Turing.MultiTapeTM Cslib.GenericRAM + +variable {T : Type} {encT : T ↪ List Bool} {entry : T → List Bool → List ℕ} + +namespace DescribedNetwork + +/-- **Specialization keeps a network rows-first**: it keeps the ports. -/ +theorem isRowsFirstBipartite_specNet_iff (P ℓ : ℕ) (fl ζ : List ℕ) (G : DescribedNetwork T) + (r : ℕ) : (specNet P ℓ fl ζ G).IsRowsFirstBipartite r ↔ G.IsRowsFirstBipartite r := by + simp only [IsRowsFirstBipartite, numEdges_specNet, vertices_specNet, List.forall_mem_map, + ← List.map_take, ← List.map_drop, List.map_map, Function.comp_def] + +/-- **Specialization does not shorten the encoded network**: each descriptor `t` becomes +`(t, P, ℓ, fl, ζ)`. -/ +theorem length_encDescribed_le_specNet (P ℓ : ℕ) (fl ζ : List ℕ) (G : DescribedNetwork T) : + (encDescribed encT G).length ≤ + (encDescribed (encSpecDesc encT) (specNet P ℓ fl ζ G)).length := by + change (encPair encUnary (encList (encPair (encList encNat) encT)) + (G.numEdges, G.vertices)).length ≤ + (encPair encUnary (encList (encPair (encList encNat) (encSpecDesc encT))) + (G.numEdges, G.vertices.map fun v => (v.1, (v.2, P, ℓ, fl, ζ)))).length + simp only [length_encPair, length_encList, List.map_map] + refine Nat.add_le_add_left (List.sum_le_sum fun v _ => ?_) _ + simp only [Function.comp_apply] + omega + +end DescribedNetwork + +/-- **Admissible networks for Theorem D.1 at truncation order `ℓ`**, with an entry procedure, at +size `s` with constant `C`: the network `G` with `r` row vertices is admissible for `ce` +(`EntryAdmissible`: rows-first bipartite, between `s` and `C s` edges, degree at most +`⌈s ^ (9/10)⌉`, entries within `C (s + L + 1) ^ C 2 ^ (C ⌈s ^ (9/10)⌉)` time and +`C (s + L + 1) ^ C` space) and has **at most `C s` vertices**. + +The vertex bound narrows Theorem D.1 of [OpenAI2026ETH] (p. 53), which asks only for a polynomial +bound in `s`. The networks of Lemma D.2 (p. 56) and of the fixed-density bound (§D.2, p. 54) +satisfy it. -/ +@[expose] def TruncEntryAdmissible + (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) (C s : ℕ) (G : ℕ × DescribedNetwork T) : Prop := + EntryAdmissible ce C s G ∧ G.2.vertices.length ≤ C * s + +namespace EntryContraction + +variable (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) + +/-- **Specialization keeps networks admissible.** For every entry certificate `ce` and constant +`C` there is `C'` such that, for every network `G` admissible for `ce` at size `s` with constant +`C`, every network specialized from it, at any precision `P`, truncation order `ℓ`, modulus `fl` +and point `ζ`, is admissible for the specialized entries (`specEntryCertificate entry ce`) at +size `s` with constant `C'`. -/ +theorem exists_entryAdmissible_specNet (C : ℕ) : + ∃ C' : ℕ, ∀ (s P ℓ r : ℕ) (fl ζ : List ℕ) (G : DescribedNetwork T), + EntryAdmissible ce C s (r, G) → + EntryAdmissible (specEntryCertificate entry ce) C' s + (r, DescribedNetwork.specNet P ℓ fl ζ G) := by + obtain ⟨K₁, hK₁⟩ := specEntryCertificate_le (encT := encT) + obtain ⟨cO, -, hcO⟩ := ce.computes + -- The overhead of specialization, as a polynomial in `s + L'`. + let f : ℕ → ℕ := fun n => K₁ * (3 * n + 3 + cO * (C * (n + 1) ^ C + 1) + 1) ^ K₁ + have hf : PolyBounded id f := + (PolyBounded.const K₁).mul (((((PolyBounded.const 3).mul PolyBounded.self).add + (PolyBounded.const 3)).add ((PolyBounded.const cO).mul (((PolyBounded.const C).mul + ((PolyBounded.self.add (PolyBounded.const 1)).pow C)).add (PolyBounded.const 1)))).add + (PolyBounded.const 1) |>.pow K₁) + obtain ⟨a, d, had⟩ := hf.exists_le + refine ⟨C + a + d, fun s P ℓ r fl ζ G hA => ?_⟩ + obtain ⟨hrows, hsm, hmC, hdeg, hent⟩ := hA + refine ⟨(DescribedNetwork.isRowsFirstBipartite_specNet_iff P ℓ fl ζ G r).2 hrows, hsm, + hmC.trans (Nat.mul_le_mul_right _ (by omega)), ?_, ?_⟩ + · intro v hv + change v ∈ G.vertices.map _ at hv + obtain ⟨u, hu, rfl⟩ := List.mem_map.mp hv + exact hdeg u hu + · intro v hv bs hbs + have hv' := hv + change v ∈ G.vertices.map _ at hv' + obtain ⟨u, hu, rfl⟩ := List.mem_map.mp hv' + change bs.length = u.1.length at hbs + set L' := (DescribedNetwork.encDescribed (encSpecDesc encT) + (DescribedNetwork.specNet P ℓ fl ζ G)).length with hL' + have hLL : (DescribedNetwork.encDescribed encT G).length ≤ L' := + DescribedNetwork.length_encDescribed_le_specNet P ℓ fl ζ G + set n := s + L' with hn + have hn1 : 1 ≤ n + 1 := by omega + obtain ⟨hT, hS⟩ := hent u hu bs hbs + have hbase : C * (s + (DescribedNetwork.encDescribed encT G).length + 1) ^ C ≤ + C * (n + 1) ^ C := + Nat.mul_le_mul_left _ (Nat.pow_le_pow_left (by omega) _) + -- The input of the specialized entry is at most `3 n + 3` bits. + have hq : (encPair (encSpecDesc encT) encBits ((u.2, P, ℓ, fl, ζ), bs)).length ≤ 3 * n + 3 := by + have h1 := length_le_encList_of_mem (encPair (encList encNat) (encSpecDesc encT)) hv + have h2 : (encList (encPair (encList encNat) (encSpecDesc encT)) + (DescribedNetwork.specNet P ℓ fl ζ G).vertices).length ≤ L' := by + rw [hL'] + change _ ≤ (encPair encUnary (encList (encPair (encList encNat) (encSpecDesc encT))) + ((DescribedNetwork.specNet P ℓ fl ζ G).numEdges, + (DescribedNetwork.specNet P ℓ fl ζ G).vertices)).length + rw [length_encPair] + dsimp only + omega + have h3 := length_le_length_encList encNat u.1 + rw [length_encPair] at h1 ⊢ + change 2 * (encSpecDesc encT (u.2, P, ℓ, fl, ζ)).length + 1 + bs.length ≤ 3 * n + 3 + dsimp only at h1 + omega + -- The original entry is at most `cO (C (n + 1) ^ C + 1)` bits. + have hout : (encList encNat (entry u.2 bs)).length ≤ cO * (C * (n + 1) ^ C + 1) := + (hcO (u.2, bs)).trans (Nat.mul_le_mul_left _ (Nat.add_le_add_right (hS.trans hbase) 1)) + obtain ⟨hT', hS'⟩ := hK₁ entry ce ((u.2, P, ℓ, fl, ζ), bs) + have hover : K₁ * ((encPair (encSpecDesc encT) encBits ((u.2, P, ℓ, fl, ζ), bs)).length + + (encList encNat (entry u.2 bs)).length + 1) ^ K₁ ≤ a * (n + 1) ^ d := by + refine le_trans ?_ (had n) + exact Nat.mul_le_mul_left _ (Nat.pow_le_pow_left (by omega) _) + have hpow {c e : ℕ} (hc : c ≤ C + a + d) (he : e ≤ C + a + d) : + c * (n + 1) ^ e ≤ (C + a + d) * (n + 1) ^ (C + a + d) := + Nat.mul_le_mul hc (Nat.pow_le_pow_right hn1 he) + have h2 : 2 ^ (C * ceilNineTenths s) ≤ 2 ^ ((C + a + d) * ceilNineTenths s) := + Nat.pow_le_pow_right (by norm_num) (Nat.mul_le_mul_right _ (by omega)) + have hX1 : 1 ≤ 2 ^ ((C + a + d) * ceilNineTenths s) := Nat.one_le_two_pow + have hsplit : C * (n + 1) ^ C + a * (n + 1) ^ d ≤ + (C + a + d) * (n + 1) ^ (C + a + d) := by + have e1 := hpow (c := C) (e := C) (by omega) (by omega) + have e2 := hpow (c := a) (e := d) (by omega) (by omega) + have e3 : C * (n + 1) ^ (C + a + d) + a * (n + 1) ^ (C + a + d) ≤ + (C + a + d) * (n + 1) ^ (C + a + d) := by + rw [← Nat.add_mul] + exact Nat.mul_le_mul_right _ (by omega) + have e1' : C * (n + 1) ^ C ≤ C * (n + 1) ^ (C + a + d) := + Nat.mul_le_mul_left _ (Nat.pow_le_pow_right hn1 (by omega)) + have e2' : a * (n + 1) ^ d ≤ a * (n + 1) ^ (C + a + d) := + Nat.mul_le_mul_left _ (Nat.pow_le_pow_right hn1 (by omega)) + omega + refine ⟨?_, ?_⟩ + · change (specEntryCertificate entry ce).time ((u.2, P, ℓ, fl, ζ), bs) ≤ + (C + a + d) * (n + 1) ^ (C + a + d) * 2 ^ ((C + a + d) * ceilNineTenths s) + have hT2 : ce.time (u.2, bs) ≤ C * (n + 1) ^ C * 2 ^ ((C + a + d) * ceilNineTenths s) := + hT.trans (Nat.mul_le_mul (hbase) h2) + have hA2 : a * (n + 1) ^ d ≤ a * (n + 1) ^ d * 2 ^ ((C + a + d) * ceilNineTenths s) := + Nat.le_mul_of_pos_right _ hX1 + calc (specEntryCertificate entry ce).time ((u.2, P, ℓ, fl, ζ), bs) + ≤ C * (n + 1) ^ C * 2 ^ ((C + a + d) * ceilNineTenths s) + + a * (n + 1) ^ d * 2 ^ ((C + a + d) * ceilNineTenths s) := by + dsimp only at hT' + omega + _ = (C * (n + 1) ^ C + a * (n + 1) ^ d) * 2 ^ ((C + a + d) * ceilNineTenths s) := by + ring + _ ≤ (C + a + d) * (n + 1) ^ (C + a + d) * 2 ^ ((C + a + d) * ceilNineTenths s) := + Nat.mul_le_mul_right _ hsplit + · change (specEntryCertificate entry ce).space ((u.2, P, ℓ, fl, ζ), bs) ≤ + (C + a + d) * (n + 1) ^ (C + a + d) + dsimp only at hS' + have := hS.trans hbase + omega + +/-- **Entries within `poly(L) 2 ^ O(s)` on admissible networks.** For every constant `C` there is +`K` such that on every network admissible for `ce` at size `s` with constant `C`, of encoded length +`L`, every entry takes time at most `K (L + 1) ^ K 2 ^ (K s)` and space at most `K (L + 1) ^ K`: +the number of edges is in unary in the encoding, so `s ≤ L`, and `⌈s ^ (9/10)⌉ ≤ s`. -/ +theorem exists_entry_le_of_entryAdmissible (C : ℕ) : + ∃ K : ℕ, ∀ (s r : ℕ) (G : DescribedNetwork T), EntryAdmissible ce C s (r, G) → + ∀ v ∈ G.vertices, ∀ bs : List Bool, bs.length = v.1.length → + ce.time (v.2, bs) ≤ + K * ((DescribedNetwork.encDescribed encT G).length + 1) ^ K * 2 ^ (K * s) ∧ + ce.space (v.2, bs) ≤ K * ((DescribedNetwork.encDescribed encT G).length + 1) ^ K := by + refine ⟨C * 2 ^ C + C, fun s r G hA v hv bs hbs => ?_⟩ + obtain ⟨-, hsm, -, -, hent⟩ := hA + change s ≤ G.numEdges at hsm + obtain ⟨hT, hS⟩ := hent v hv bs hbs + set L := (DescribedNetwork.encDescribed encT G).length with hL + have hmL := DescribedNetwork.length_numEdges_vertices_le (encT := encT) G + have hL1 : 1 ≤ L + 1 := by omega + -- `C (s + L + 1) ^ C ≤ C 2 ^ C (L + 1) ^ C ≤ K (L + 1) ^ K`. + have hbase : C * (s + L + 1) ^ C ≤ (C * 2 ^ C + C) * (L + 1) ^ (C * 2 ^ C + C) := by + calc C * (s + L + 1) ^ C ≤ C * (2 * (L + 1)) ^ C := + Nat.mul_le_mul_left _ (Nat.pow_le_pow_left (by omega) _) + _ = C * 2 ^ C * (L + 1) ^ C := by rw [Nat.mul_pow, Nat.mul_assoc] + _ ≤ (C * 2 ^ C + C) * (L + 1) ^ (C * 2 ^ C + C) := + Nat.mul_le_mul (by omega) (Nat.pow_le_pow_right hL1 (by omega)) + have h2 : 2 ^ (C * ceilNineTenths s) ≤ 2 ^ ((C * 2 ^ C + C) * s) := + Nat.pow_le_pow_right (by norm_num) + (Nat.mul_le_mul (by omega) (ceilNineTenths_le_self s)) + exact ⟨hT.trans (Nat.mul_le_mul hbase h2), hS.trans hbase⟩ + +end EntryContraction + +/-- **Theorem D.1 at truncation order `ℓ` for entry procedures, from the case `ℓ = 1`.** Let `ce` +be a native certificate of an entry procedure, and `A` a contraction algorithm for the specialized +entries (`specEntry entry`, with the certificate `specEntryCertificate entry ce`) on the networks +admissible for them. Then the assembly `TruncatedContractionAlgorithm.ofCore` around `A` is a +truncated contraction algorithm for the networks admissible for `ce` with at most `C s` vertices +(`TruncEntryAdmissible ce`): it computes the contraction in `B_{P,ℓ}` in time +`poly(n) 2 ^ O(s / √⌊log₂ s⌋)` and polynomial space, for `1 ≤ P, ℓ ≤ D s`. -/ +noncomputable def TruncatedContractionAlgorithm.ofEntry + (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) + (A : EntryContractionAlgorithm (encSpecDesc encT) (specEntry entry) + (EntryAdmissible (specEntryCertificate entry ce))) : + TruncatedContractionAlgorithm encT entry (TruncEntryAdmissible ce) := + ofCore (core := A.core) A.certificate A.val_core A.bound + (fun C _ => by + obtain ⟨C', hC'⟩ := EntryContraction.exists_entryAdmissible_specNet ce C + exact ⟨C', fun s P ℓ r _ G _ _ _ _ _ hA => hC' s P ℓ r _ _ G hA.1⟩) + ce + (fun C => by + obtain ⟨K, hK⟩ := EntryContraction.exists_entry_le_of_entryAdmissible ce C + exact ⟨K, fun s r G hA => hK s r G hA.1⟩) + (fun _ _ _ _ hA => ⟨hA.1.2.1, hA.1.2.2.1, hA.2⟩) + +end Cslib.Circuits.Frontier diff --git a/Complexity/Computability/Complexity/Classes/CountingSimulation/TruncatedEntry.lean b/Complexity/Computability/Complexity/Classes/CountingSimulation/TruncatedEntry.lean new file mode 100644 index 000000000..6a849014b --- /dev/null +++ b/Complexity/Computability/Complexity/Classes/CountingSimulation/TruncatedEntry.lean @@ -0,0 +1,67 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Computability.Complexity.Classes.CountingSimulation.EntryAnalysis +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.TruncatedEntry + +/-! +# Theorem D.1 at truncation order `ℓ` for entry procedures + +The instance of the interface of Theorem D.1 at truncation order `ℓ` +(`Cslib.Circuits.Frontier.TruncatedContractionAlgorithm`) for networks whose entries are +computed by procedures: for every native certificate `ce` of an entry procedure, +`CountingSimulation.truncEntryContractionAlgorithm ce` computes the contraction in +`B_{P,ℓ} = (ℤ / 2 ^ P)[V] / (V ^ ℓ)` of the networks admissible for `ce` with at most `C s` vertices +(`Cslib.Circuits.Frontier.TruncEntryAdmissible`), for `1 ≤ P, ℓ ≤ D s`, in time +`poly(n) 2 ^ O(s / √⌊log₂ s⌋)` and polynomial space. + +It combines the reduction of truncation order `ℓ` to `A_P = (ℤ / 2 ^ P)[U] / (f)` +(`Cslib.Circuits.Frontier.TruncatedContractionAlgorithm.ofEntry`) with the contraction algorithm +for entry procedures (`CountingSimulation.entryContractionAlgorithm`), applied to the specialized +entries. + +This is Theorem D.1 of [OpenAI2026ETH] (p. 53) with one narrowing: the theorem asks for at most +polynomially many vertices in `s`, and admissibility here asks for at most `C s`. The networks of +Lemma D.2 (p. 56) and of the fixed-density bound (§D.2, p. 54) have that many. As for all the +interfaces of this development, admissibility also asks for at least `s` edges, which a caller +gets by padding (see `Cslib.Circuits.Frontier.EntryAdmissible`). + +## Main definitions + +* `Cslib.Complexity.CountingSimulation.truncEntryContractionAlgorithm`: Theorem D.1 at truncation + order `ℓ` for entry procedures. + +## References + +* [OpenAI, *The Exponential Time Hypothesis is False*][OpenAI2026ETH], Theorem D.1 (p. 53). +-/ + +public section + +namespace Cslib.Complexity.CountingSimulation + +open Cslib.Circuits.Frontier Cslib.GenericRAM Turing.MultiTapeTM + +variable {T : Type} {encT : T ↪ List Bool} {entry : T → List Bool → List ℕ} + +/-- **Theorem D.1 at truncation order `ℓ` for entry procedures** ([OpenAI2026ETH], p. 53, for +networks with at most `C s` vertices): for every native certificate `ce` of an entry procedure, +the reduction of truncation order `ℓ` to `A_P` around the contraction algorithm for the +specialized entries is a truncated contraction algorithm for the networks admissible for `ce` with +at most `C s` vertices. It computes the contraction in `B_{P,ℓ}` from `(P, ℓ, r, G)` on every +input, and on admissible inputs with `1 ≤ P, ℓ ≤ D s` in time `poly(n) 2 ^ O(s / √⌊log₂ s⌋)` and +polynomial space. -/ +noncomputable def truncEntryContractionAlgorithm + (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) + (encList encNat)) : + TruncatedContractionAlgorithm encT entry (TruncEntryAdmissible ce) := + TruncatedContractionAlgorithm.ofEntry ce + (entryContractionAlgorithm (specEntryCertificate entry ce)) + +end Cslib.Complexity.CountingSimulation diff --git a/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkTruncatedEntry.lean b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkTruncatedEntry.lean new file mode 100644 index 000000000..b9ccd07f6 --- /dev/null +++ b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkTruncatedEntry.lean @@ -0,0 +1,90 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: local-only (test driver) + +public import Complexity.Computability.Complexity.Classes.CountingSimulation.TruncatedEntry + +/-! +# Tests for Theorem D.1 at truncation order `ℓ` for entry procedures + +A network of two parallel edges between a row vertex and a column vertex is admissible at size `2` +with the entry procedure of tables, with its two vertices (`TruncEntryAdmissible` is not vacuous); +its specialization at a point is rows-first and admissible for the specialized entries; and the +truncated contraction algorithm for entry procedures, instantiated at the entry procedure of +tables, has no remaining hypothesis. +-/ + +@[expose] public section + +namespace ComplexityTests.TensorNetworkTruncatedEntry + +open Cslib Cslib.Circuits.Frontier Cslib.Circuits.Frontier.EntryContraction + Cslib.Complexity.CountingSimulation +open Turing.MultiTapeTM (encList encNat) + +/-- Two parallel edges between a row vertex with table `1, 2, 3, 4` and a column vertex of +ones. -/ +abbrev twoEdges : DescribedNetwork (List ℕ) := ⟨2, [([0, 1], [1, 2, 3, 4]), ([0, 1], [1, 1, 1, 1])]⟩ + +/-- `⌈2 ^ (9/10)⌉ = 2`. -/ +theorem ceilNineTenths_two : ceilNineTenths 2 = 2 := + le_antisymm (ceilNineTenths_le (by norm_num)) ((le_ceilNineTenths_iff (by norm_num)).2 + (by norm_num)) + +/-- The network is admissible at size `2` with the entry procedure of tables, for some constant. -/ +theorem exists_entryAdmissible_twoEdges : + ∃ C, 1 ≤ C ∧ EntryAdmissible tableEntryCertificate C 2 (1, twoEdges) := by + obtain ⟨C₀, hC₀⟩ := exists_entryAdmissible_of_isPolynomial + tableEntryCertificate_isPolynomial + refine ⟨C₀ + 1, by omega, hC₀ (C₀ + 1) 2 1 twoEdges (by omega) (by decide) le_rfl (by simp) ?_⟩ + intro v hv + rw [ceilNineTenths_two] + simp only [List.mem_cons, List.not_mem_nil, or_false] at hv + rcases hv with rfl | rfl <;> rfl + +/-! ### Admissibility is not vacuous -/ + +-- With its two vertices, the network is admissible for Theorem D.1 at truncation order `ℓ`. +example : ∃ C, TruncEntryAdmissible tableEntryCertificate C 2 (1, twoEdges) := by + obtain ⟨C, hC1, hC⟩ := exists_entryAdmissible_twoEdges + exact ⟨C, hC, by simp only [List.length_cons, List.length_nil]; omega⟩ + +/-! ### Specialization -/ + +-- Specializing at the point `U` of `A_3 = (ℤ / 8)[U] / (U ^ 2 + U + 1)` keeps the network +-- rows-first. +example : (DescribedNetwork.specNet 3 2 [1, 1] [0, 1] twoEdges).IsRowsFirstBipartite 1 := by + decide + +-- Specialization keeps the network admissible, for the specialized entries. +example : ∃ C', EntryAdmissible (specEntryCertificate tableEntry tableEntryCertificate) C' 2 + (1, DescribedNetwork.specNet 3 2 [1, 1] [0, 1] twoEdges) := by + obtain ⟨C, -, hC⟩ := exists_entryAdmissible_twoEdges + obtain ⟨C', hC'⟩ := exists_entryAdmissible_specNet tableEntryCertificate C + exact ⟨C', hC' 2 3 2 1 [1, 1] [0, 1] twoEdges hC⟩ + +/-! ### The truncated contraction algorithm -/ + +/-- The truncated contraction algorithm for the entry procedure of tables, with no remaining +hypothesis. Its certificate computes the contraction in `B_{P,ℓ}` on every input, by its type. -/ +noncomputable def tableTruncAlgorithm : + TruncatedContractionAlgorithm (encList encNat) tableEntry + (TruncEntryAdmissible tableEntryCertificate) := + truncEntryContractionAlgorithm tableEntryCertificate + +-- Its bound holds for all constants. +example (C D : ℕ) : ∃ K : ℕ, ∀ (s P ℓ r : ℕ) (G : DescribedNetwork (List ℕ)), 2 ≤ s → 1 ≤ P → + P ≤ D * s → 1 ≤ ℓ → ℓ ≤ D * s → TruncEntryAdmissible tableEntryCertificate C s (r, G) → + tableTruncAlgorithm.certificate.time (P, ℓ, r, G) ≤ + K * ((encTrunc (encList encNat) (P, ℓ, r, G)).length + 1) ^ K * + 2 ^ (K * s / Nat.sqrt (Nat.log 2 s)) ∧ + tableTruncAlgorithm.certificate.space (P, ℓ, r, G) ≤ + K * ((encTrunc (encList encNat) (P, ℓ, r, G)).length + 1) ^ K := + tableTruncAlgorithm.bound C D + +end ComplexityTests.TensorNetworkTruncatedEntry From 8f4daefb7dbe94539071792fb0e9de655aa1f1fa Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 11:46:26 -0400 Subject: [PATCH 18/20] fix(Frontier/TensorNetwork): named components and a nonvacuous instance for the entry interface Address the two findings of the review of #2042 at 5cd05f4df, whose layer this branch carries: - Bind `(P, fl, _, G)` by name in `sumInput_polyTime` and in the result function of `directCore`, and state `directCore_time`, `directCore_space` and `directCore_le` over `P fl r G` instead of reaching into `x.2.2.2`. Definitional behavior is unchanged (`directCore_time`/`_space` remain `rfl`, and `fastCore`'s `congr` proof is untouched). - Test that the instance `tableAlgorithm : EntryContractionAlgorithm ..` satisfies its `bound` on an admissible input (two parallel edges at size 2), and point to it from the interface's test. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG --- .../TensorNetwork/EntryContraction.lean | 98 +++++++++---------- .../Frontier/TensorNetworkEntryAnalysis.lean | 33 ++++++- .../TensorNetworkEntryContraction.lean | 4 +- 3 files changed, 83 insertions(+), 52 deletions(-) diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContraction.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContraction.lean index bb2367e83..eeeb0d439 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContraction.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContraction.lean @@ -252,8 +252,8 @@ namespace EntryContraction /-- The input of direct summation, `((P, fl), G)`, from `(P, fl, r, G)`. -/ theorem sumInput_polyTime : - ComputableInPolyTime (fun x : ℕ × List ℕ × ℕ × DescribedNetwork T => ((x.1, x.2.1), x.2.2.2)) - (encInput encT) + ComputableInPolyTime + (fun ((P, fl, _, G) : ℕ × List ℕ × ℕ × DescribedNetwork T) => ((P, fl), G)) (encInput encT) (DescribedNetwork.encInput (encPair encUnary (encList encNat)) encT) := ((ComputableInPolyTime.fst _ _).prod ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _))).prod @@ -267,8 +267,8 @@ assignments of the products of the entries, with the operations of `A_P` at the (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) (encList encNat)) : NativeCertificate - (fun x : ℕ × List ℕ × ℕ × DescribedNetwork T => - DescribedNetwork.sumValue SumOps.galois entry (x.1, x.2.1) x.2.2.2) + (fun ((P, fl, _, G) : ℕ × List ℕ × ℕ × DescribedNetwork T) => + DescribedNetwork.sumValue SumOps.galois entry (P, fl) G) (encInput encT) (encList encNat) := ((DescribedNetwork.contractionCertificate entry SumOps.galois_polyTime ce).comp (NativeCertificate.ofPolyTime sumInput_polyTime)).congr fun _ => rfl @@ -279,31 +279,29 @@ theorem val_directCore (P : ℕ) (fl : List ℕ) (G : DescribedNetwork T) : G.contraction fun t bs => val P fl (entry t bs) := DescribedNetwork.val_sumValue_galois entry (P, fl) G - /-- The time of direct summation: the input of the sum, then the sum. -/ theorem directCore_time (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) - (encList encNat)) (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : - (directCore entry ce).time x = - (NativeCertificate.ofPolyTime (sumInput_polyTime (encT := encT))).time x + + (encList encNat)) (P : ℕ) (fl : List ℕ) (r : ℕ) (G : DescribedNetwork T) : + (directCore entry ce).time (P, fl, r, G) = + (NativeCertificate.ofPolyTime (sumInput_polyTime (encT := encT))).time (P, fl, r, G) + (DescribedNetwork.contractionCertificate entry SumOps.galois_polyTime ce).time - ((x.1, x.2.1), x.2.2.2) := rfl + ((P, fl), G) := rfl /-- The space of direct summation. -/ theorem directCore_space (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) - (encList encNat)) (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : - (directCore entry ce).space x = - (NativeCertificate.ofPolyTime (sumInput_polyTime (encT := encT))).space x + + (encList encNat)) (P : ℕ) (fl : List ℕ) (r : ℕ) (G : DescribedNetwork T) : + (directCore entry ce).space (P, fl, r, G) = + (NativeCertificate.ofPolyTime (sumInput_polyTime (encT := encT))).space (P, fl, r, G) + (DescribedNetwork.contractionCertificate entry SumOps.galois_polyTime ce).space - ((x.1, x.2.1), x.2.2.2) := rfl + ((P, fl), G) := rfl /-- The precision, the modulus and the input of the sum against the encoded input. -/ -private theorem lengths_le (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : - x.1 + x.2.1.length ≤ (encInput encT x).length ∧ +private theorem lengths_le (P : ℕ) (fl : List ℕ) (r : ℕ) (G : DescribedNetwork T) : + P + fl.length ≤ (encInput encT (P, fl, r, G)).length ∧ (DescribedNetwork.encInput (encPair encUnary (encList encNat)) encT - ((x.1, x.2.1), x.2.2.2)).length ≤ 2 * (encInput encT x).length := by - obtain ⟨P, fl, r, G⟩ := x + ((P, fl), G)).length ≤ 2 * (encInput encT (P, fl, r, G)).length := by have h := length_le_length_encList encNat fl simp only [encInput, DescribedNetwork.encInput, length_encPair, encUnary_apply, List.length_replicate] at h ⊢ @@ -313,20 +311,21 @@ private theorem mul_pow_le {c W d E : ℕ} (hW : 1 ≤ W) (hd : d ≤ E) : c * W Nat.mul_le_mul_left _ (Nat.pow_le_pow_right hW hd) /-- **The resources of direct summation with an entry procedure.** There is `K` such that on an -input `x = (P, fl, r, G)` of encoded length `n`, with `m` edges and `k` vertices, if the entry +input `(P, fl, r, G)` of encoded length `n`, with `m` edges and `k` vertices in `G`, if the entry procedure takes time at most `E` and space at most `ES` on every vertex and bits on its ports, then direct summation takes time at most `(2 ^ m (k + 1) + 1) (K (n + ES + 1) ^ K + 2 E)` and space at most `K (n + ES + 1) ^ K + ES`. -/ theorem directCore_le (ce : NativeCertificate (fun q : T × List Bool => entry q.1 q.2) (encPair encT encBits) (encList encNat)) : - ∃ K : ℕ, ∀ (x : ℕ × List ℕ × ℕ × DescribedNetwork T) (E ES : ℕ), - (∀ v ∈ x.2.2.2.vertices, ∀ bs : List Bool, bs.length = v.1.length → + ∃ K : ℕ, ∀ (P : ℕ) (fl : List ℕ) (r : ℕ) (G : DescribedNetwork T) (E ES : ℕ), + (∀ v ∈ G.vertices, ∀ bs : List Bool, bs.length = v.1.length → ce.time (v.2, bs) ≤ E ∧ ce.space (v.2, bs) ≤ ES) → - (directCore entry ce).time x ≤ - (2 ^ x.2.2.2.numEdges * (x.2.2.2.vertices.length + 1) + 1) * - (K * ((encInput encT x).length + ES + 1) ^ K + 2 * E) ∧ - (directCore entry ce).space x ≤ K * ((encInput encT x).length + ES + 1) ^ K + ES := by + (directCore entry ce).time (P, fl, r, G) ≤ + (2 ^ G.numEdges * (G.vertices.length + 1) + 1) * + (K * ((encInput encT (P, fl, r, G)).length + ES + 1) ^ K + 2 * E) ∧ + (directCore entry ce).space (P, fl, r, G) ≤ + K * ((encInput encT (P, fl, r, G)).length + ES + 1) ^ K + ES := by obtain ⟨K₁, hK₁⟩ := DescribedNetwork.contractionCertificate_le (ops := SumOps.galois) (eval := entry) (encQ := encPair encUnary (encList encNat)) (encY := encList encNat) (encT := encT) SumOps.galois_polyTime ce @@ -335,44 +334,44 @@ theorem directCore_le obtain ⟨ct, dt, hit⟩ := hI.1.exists_le obtain ⟨cs, ds, his⟩ := hI.2.exists_le obtain ⟨c₁, hc₁⟩ : ∃ c₁, c₁ = K₁ * (c + 6) ^ K₁ := ⟨_, rfl⟩ - refine ⟨ct + cs + c₁ + dt + ds + 2 * K₁, fun x E ES hE => ?_⟩ - obtain ⟨n, hn⟩ : ∃ n, n = (encInput encT x).length := ⟨_, rfl⟩ + refine ⟨ct + cs + c₁ + dt + ds + 2 * K₁, fun P fl r G E ES hE => ?_⟩ + obtain ⟨n, hn⟩ : ∃ n, n = (encInput encT (P, fl, r, G)).length := ⟨_, rfl⟩ obtain ⟨W, hW⟩ : ∃ W, W = n + ES + 1 := ⟨_, rfl⟩ rw [← hn, show n + ES + 1 = W from hW.symm] have hW1 : 1 ≤ W := by omega - obtain ⟨hPfl, hproj⟩ := lengths_le x + obtain ⟨hPfl, hproj⟩ := lengths_le P fl r G rw [← hn] at hPfl hproj - have hRv : ∀ y, SumOps.galois.Reduced (x.1, x.2.1) y → + have hRv : ∀ y, SumOps.galois.Reduced (P, fl) y → (encList encNat y).length ≤ n * (2 * n + 3) := fun y hy => (SumOps.length_encList_le_of_galois_reduced hy).trans (Nat.mul_le_mul (by simp only; omega) (by simp only; omega)) - have hEv : ∀ v ∈ ((x.1, x.2.1), x.2.2.2).2.vertices, ∀ bs : List Bool, + have hEv : ∀ v ∈ G.vertices, ∀ bs : List Bool, bs.length = v.1.length → ce.time (v.2, bs) ≤ E ∧ ce.space (v.2, bs) ≤ ES ∧ (encList encNat (entry v.2 bs)).length ≤ c * (ES + 1) := fun v hv bs hbs => ⟨(hE v hv bs hbs).1, (hE v hv bs hbs).2, (hout (v.2, bs)).trans (Nat.mul_le_mul_left _ (by have := (hE v hv bs hbs).2; omega))⟩ - obtain ⟨hT, hS⟩ := hK₁ ((x.1, x.2.1), x.2.2.2) E ES (c * (ES + 1)) (n * (2 * n + 3)) hEv hRv + obtain ⟨hT, hS⟩ := hK₁ ((P, fl), G) E ES (c * (ES + 1)) (n * (2 * n + 3)) hEv hRv -- The argument of direct summation's polynomial against `W ^ 2`. have hA : (DescribedNetwork.encInput (encPair encUnary (encList encNat)) encT - ((x.1, x.2.1), x.2.2.2)).length + c * (ES + 1) + n * (2 * n + 3) + 1 ≤ (c + 6) * W ^ 2 := by + ((P, fl), G)).length + c * (ES + 1) + n * (2 * n + 3) + 1 ≤ (c + 6) * W ^ 2 := by have h1 : c * (ES + 1) ≤ c * W := Nat.mul_le_mul_left _ (by omega) have h2 : c * W ≤ c * W ^ 2 := Nat.mul_le_mul_left _ (by nlinarith) have h3 : n * (2 * n + 3) + 2 * n + 1 ≤ 6 * W ^ 2 := by nlinarith nlinarith have hpoly : K₁ * ((DescribedNetwork.encInput (encPair encUnary (encList encNat)) encT - ((x.1, x.2.1), x.2.2.2)).length + c * (ES + 1) + n * (2 * n + 3) + 1) ^ K₁ ≤ + ((P, fl), G)).length + c * (ES + 1) + n * (2 * n + 3) + 1) ^ K₁ ≤ c₁ * W ^ (2 * K₁) := by rw [hc₁, pow_mul, Nat.mul_assoc, ← Nat.mul_pow] exact Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hA _) have hnW : n + 1 ≤ W := by omega - have hit' : (NativeCertificate.ofPolyTime (sumInput_polyTime (encT := encT))).time x ≤ - ct * W ^ dt := by - have h := hit x + have hit' : (NativeCertificate.ofPolyTime (sumInput_polyTime (encT := encT))).time + (P, fl, r, G) ≤ ct * W ^ dt := by + have h := hit (P, fl, r, G) rw [← hn] at h exact h.trans (Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hnW _)) - have his' : (NativeCertificate.ofPolyTime (sumInput_polyTime (encT := encT))).space x ≤ - cs * W ^ ds := by - have h := his x + have his' : (NativeCertificate.ofPolyTime (sumInput_polyTime (encT := encT))).space + (P, fl, r, G) ≤ cs * W ^ ds := by + have h := his (P, fl, r, G) rw [← hn] at h exact h.trans (Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hnW _)) obtain ⟨K, hK⟩ : ∃ K, K = ct + cs + c₁ + dt + ds + 2 * K₁ := ⟨_, rfl⟩ @@ -382,13 +381,13 @@ theorem directCore_le have hc1 : c₁ * W ^ (2 * K₁) ≤ c₁ * W ^ K := mul_pow_le hW1 (by omega) have hsum : ct * W ^ K + cs * W ^ K + c₁ * W ^ K ≤ K * W ^ K := by rw [← Nat.add_mul, ← Nat.add_mul]; exact Nat.mul_le_mul_right _ (by omega) - have hP1 : 1 ≤ 2 ^ x.2.2.2.numEdges * (x.2.2.2.vertices.length + 1) + 1 := by omega + have hP1 : 1 ≤ 2 ^ G.numEdges * (G.vertices.length + 1) + 1 := by omega constructor · rw [directCore_time] - calc _ ≤ ct * W ^ dt + (2 ^ x.2.2.2.numEdges * (x.2.2.2.vertices.length + 1) + 1) * + calc _ ≤ ct * W ^ dt + (2 ^ G.numEdges * (G.vertices.length + 1) + 1) * (c₁ * W ^ (2 * K₁) + 2 * E) := Nat.add_le_add hit' (hT.trans (Nat.mul_le_mul_left _ (Nat.add_le_add_right hpoly _))) - _ ≤ (2 ^ x.2.2.2.numEdges * (x.2.2.2.vertices.length + 1) + 1) * + _ ≤ (2 ^ G.numEdges * (G.vertices.length + 1) + 1) * (ct * W ^ K + (c₁ * W ^ K + 2 * E)) := by rw [Nat.mul_add _ (ct * W ^ K)] refine Nat.add_le_add ((hct.trans (Nat.le_mul_of_pos_left _ hP1))) ?_ @@ -418,12 +417,12 @@ theorem exists_directCore_le refine ⟨K, fun s P r G hA => ?_⟩ obtain ⟨-, hsm, hmC, -, hent⟩ := hA simp only at hsm hmC hent - set x := (P, FastContraction.modulus G.numEdges, r, G) - obtain ⟨n, hn⟩ : ∃ n, n = (encInput encT x).length := ⟨_, rfl⟩ + obtain ⟨n, hn⟩ : ∃ n, n = (encInput encT (P, FastContraction.modulus G.numEdges, r, G)).length := + ⟨_, rfl⟩ rw [← hn] -- The size, the network and the vertices against `n`. have hG : (DescribedNetwork.encDescribed encT G).length ≤ n := by - rw [hn]; simp only [x, encInput, length_encPair]; omega + rw [hn]; simp only [encInput, length_encPair]; omega have hmk := DescribedNetwork.length_numEdges_vertices_le (encT := encT) G have hsn : s ≤ n := by omega have hB : s + (DescribedNetwork.encDescribed encT G).length + 1 ≤ 3 * (n + 1) := by omega @@ -436,7 +435,7 @@ theorem exists_directCore_le ≤ C * (3 * (n + 1)) ^ C := Nat.mul_le_mul_left _ (Nat.pow_le_pow_left hB _) _ = C * 3 ^ C * (n + 1) ^ C := by rw [Nat.mul_pow, Nat.mul_assoc] _ ≤ c₀ * (n + 1) ^ C := Nat.mul_le_mul_right _ (by omega) - have hbnd : ∀ v ∈ x.2.2.2.vertices, ∀ bs : List Bool, bs.length = v.1.length → + have hbnd : ∀ v ∈ G.vertices, ∀ bs : List Bool, bs.length = v.1.length → ce.time (v.2, bs) ≤ E ∧ ce.space (v.2, bs) ≤ ES := by intro v hv bs hbs obtain ⟨ht, hs⟩ := hent v hv bs hbs @@ -444,9 +443,8 @@ theorem exists_directCore_le rw [hE, show c₀ * (n + 1) ^ C * 2 ^ (C * s) = (c₀ * (n + 1) ^ C) * 2 ^ (C * s) from rfl] exact Nat.mul_le_mul (hES ▸ hpowB) (Nat.pow_le_pow_right (by norm_num) (Nat.mul_le_mul_left _ (ceilNineTenths_le_self s))) - obtain ⟨hT, hS⟩ := hK₀ x E ES hbnd + obtain ⟨hT, hS⟩ := hK₀ P (FastContraction.modulus G.numEdges) r G E ES hbnd rw [← hn] at hT hS - simp only [x] at hT hS -- Arithmetic. have hn1 : 1 ≤ n + 1 := by omega have hWES : n + ES + 1 ≤ (c₀ + 1) * (n + 1) ^ (C + 1) := by @@ -470,9 +468,9 @@ theorem exists_directCore_le have hXe1 : X ^ ((C + 1) * K₀) ≤ X ^ e := Nat.pow_le_pow_right hX1 (by omega) have hXe2 : X ^ C ≤ X ^ e := Nat.pow_le_pow_right hX1 (by omega) -- The number of assignments and vertices. - have hk : x.2.2.2.vertices.length + 1 ≤ X := by simp only [x]; omega - have hm : 2 ^ x.2.2.2.numEdges ≤ Y := hY ▸ Nat.pow_le_pow_right (by norm_num) (by simpa [x]) - have hcount : 2 ^ x.2.2.2.numEdges * (x.2.2.2.vertices.length + 1) + 1 ≤ 2 * (Y * X) := by + have hk : G.vertices.length + 1 ≤ X := by omega + have hm : 2 ^ G.numEdges ≤ Y := hY ▸ Nat.pow_le_pow_right (by norm_num) hmC + have hcount : 2 ^ G.numEdges * (G.vertices.length + 1) + 1 ≤ 2 * (Y * X) := by have := Nat.mul_le_mul hm hk have : 1 ≤ Y * X := Nat.one_le_iff_ne_zero.mpr (by positivity) omega diff --git a/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkEntryAnalysis.lean b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkEntryAnalysis.lean index f5a5a6d8c..4afe8c6a2 100644 --- a/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkEntryAnalysis.lean +++ b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkEntryAnalysis.lean @@ -16,7 +16,8 @@ The guard of the entry machine on a network of two parallel edges between a row column vertex, at the modulus of its number of edges and at another modulus; the guarded root is well-formed and has no packets; an admissible input passes the guard; and the contraction algorithm for entry procedures, instantiated at the entry procedure of tables, is correct with no -remaining hypothesis. +remaining hypothesis. That instance is an `EntryContractionAlgorithm` whose `bound` applies to an +admissible input, the network of two parallel edges at size `2`, so the interface is not vacuous. -/ @[expose] public section @@ -90,4 +91,34 @@ example (C D : ℕ) : ∃ K : ℕ, ∀ (s P r : ℕ) (G : DescribedNetwork (List 1) ^ K := tableAlgorithm.bound C D +/-! ### The interface is not vacuous -/ + +/-- The network of two parallel edges is admissible at size `2` with the entry procedure of +tables, for some constant. -/ +theorem exists_entryAdmissible_twoEdges : + ∃ C, EntryAdmissible tableEntryCertificate C 2 (1, twoEdges) := by + obtain ⟨C₀, hC₀⟩ := exists_entryAdmissible_of_isPolynomial + tableEntryCertificate_isPolynomial + have h2 : ceilNineTenths 2 = 2 := + le_antisymm (ceilNineTenths_le (by norm_num)) ((le_ceilNineTenths_iff (by norm_num)).2 + (by norm_num)) + refine ⟨C₀ + 1, hC₀ (C₀ + 1) 2 1 twoEdges (by omega) (by decide) le_rfl (by simp) ?_⟩ + intro v hv + rw [h2] + simp only [List.mem_cons, List.not_mem_nil, or_false] at hv + rcases hv with rfl | rfl <;> rfl + +-- The bound of the instance applies to that admissible input: at size `2`, precision `1` and the +-- modulus of its two edges, the time and space of the certificate are within the bound. +example : ∃ C K : ℕ, EntryAdmissible tableEntryCertificate C 2 (1, twoEdges) ∧ + tableAlgorithm.certificate.time (1, FastContraction.modulus 2, 1, twoEdges) ≤ + K * ((encInput (encList encNat) (1, FastContraction.modulus 2, 1, twoEdges)).length + + 1) ^ K * 2 ^ (K * 2 / Nat.sqrt (Nat.log 2 2)) ∧ + tableAlgorithm.certificate.space (1, FastContraction.modulus 2, 1, twoEdges) ≤ + K * ((encInput (encList encNat) (1, FastContraction.modulus 2, 1, twoEdges)).length + + 1) ^ K := by + obtain ⟨C, hC⟩ := exists_entryAdmissible_twoEdges + obtain ⟨K, hK⟩ := tableAlgorithm.bound C 1 + exact ⟨C, K, hC, hK 2 1 1 twoEdges le_rfl le_rfl (by norm_num) hC⟩ + end ComplexityTests.TensorNetworkEntryAnalysis diff --git a/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkEntryContraction.lean b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkEntryContraction.lean index a2e78344d..4e1969b60 100644 --- a/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkEntryContraction.lean +++ b/ComplexityTests/Computability/Circuit/Frontier/TensorNetworkEntryContraction.lean @@ -15,7 +15,9 @@ public import Complexity.Computability.Circuit.Frontier.TensorNetwork.EntryContr `⌈s ^ (9/10)⌉` at a few sizes. Direct summation with the entry procedure of tables, on a network of two parallel edges between a row vertex and a column vertex, computes `1 + 2 + 3 + 4 = 10`, which is `2` in `A_3 = (ℤ / 8)[U] / (U ^ 2 + U + 1)`. That network is admissible at size `2` with -the entry procedure of tables, for some constant (`EntryAdmissible` is not vacuous). +the entry procedure of tables, for some constant (`EntryAdmissible` is not vacuous). An instance of +`EntryContractionAlgorithm` whose bound applies to that input is +`ComplexityTests.TensorNetworkEntryAnalysis.tableAlgorithm` (`TensorNetworkEntryAnalysis.lean`). -/ @[expose] public section From e7499606f7a99ceb5f366642e69be58bf4f249f0 Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 12:04:48 -0400 Subject: [PATCH 19/20] fix(Frontier/TensorNetwork): name the components of the root entry input Address the review of #2047 at 21015c239: `rootInput_polyTime` and the body of `entryCertificate` bind `((_, bs), t)` by name instead of reaching into `p.1.2`. Both forms are definitionally equal, so the certificate, its `congr` proofs and the resource bound are unchanged. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG --- .../Circuit/Frontier/TensorNetwork/VertexDesc.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/VertexDesc.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/VertexDesc.lean index ebc387ad2..0abab83ad 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/VertexDesc.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/VertexDesc.lean @@ -186,7 +186,7 @@ theorem packetInput_polyTime : /-- The input of the root's entry procedure from a descriptor's bits and its root descriptor. -/ theorem rootInput_polyTime : - ComputableInPolyTime (fun p : (VertexDesc T × List Bool) × T => (p.2, p.1.2)) + ComputableInPolyTime (fun (((_, bs), t) : (VertexDesc T × List Bool) × T) => (t, bs)) (encPair (encPair (enc encT) encBits) encT) (encPair encT encBits) := (ComputableInPolyTime.snd _ _).prod ((ComputableInPolyTime.snd (enc encT) encBits).comp (ComputableInPolyTime.fst _ _)) @@ -203,7 +203,7 @@ noncomputable def entryCertificate (encPair (enc encT) encBits) (encList encNat) := (NativeCertificate.option (value := fun q : VertexDesc T × List Bool => q.1.getLeft?) (fallback := fun q => packetVertexEntry (q.1.getRight?.getD default) q.2) - (body := fun p => ev p.2 p.1.2) + (body := fun ((_, bs), t) => ev t bs) (NativeCertificate.ofPolyTime getLeft_polyTime) ((vertexCertificate.comp (NativeCertificate.ofPolyTime packetInput_polyTime)).congr fun _ => rfl) From 4e6852df58a199162f144870ad27b2e108aeefae Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 12:10:31 -0400 Subject: [PATCH 20/20] fix(Frontier/TensorNetwork): named components, shared rows-first test and leaf factor Address the review of #2060 at 48ee919e8: - Named components (#1764). `EntryContraction.guard`, `rootCall` and `clock` match on `(P, fl, r, G)`; `coreValue` on `x@(P, fl, _, G)` and the returned value `(tag, coeffs)`; `valueTag_polyTime`, `valueList_polyTime` and `fastCore_time`/`_space` bind `(tag, coeffs)`; and `CountingSimulation.length_parts_le_encInput` is stated over `P fl r G`. All are definitionally equal to the projection forms. - One rows-first test. `DescribedNetwork.rowsFirst_polyTime` moves to the new module `Frontier/TensorNetwork/RowsFirstPolyTime.lean`, and `CountingSimulation.fastGuard_polyTime` uses it in place of its own copy. `ContractionSchedule.degreeBound_mono` moves to `Schedule.lean`. - One leaf factor. `FastContraction.exists_leafFactor_le` bounds `2 ^ M (A p + 2) ^ A` once; `exists_leafCertificate_le` (tables) and `exists_leafCertificate_le_of_entry` both use it. - Frontier facts out of `CountingSimulation`: `NativeChild.exists_mem_of_mem_nativeChild_inl` moves to `NativeChild.lean`, `FastContraction.Reach.exists_root_of_inl` to `FastContractionShape.lean`, `FastContraction.exists_leafCertificate_le_of_entry` to `FastContractionLeaf.lean`, and `EntryContraction.packetShape_rootCall` to `EntryContractionMachine.lean`. Their names and statements are unchanged. The elaborated types of #1995's six theorems and of `fastContractionAlgorithm` are unchanged. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG --- Complexity.lean | 1 + .../EntryContractionMachine.lean | 258 ++++++------------ .../TensorNetwork/FastContractionLeaf.lean | 183 +++++++++---- .../TensorNetwork/FastContractionShape.lean | 19 ++ .../Frontier/TensorNetwork/NativeChild.lean | 16 ++ .../TensorNetwork/RowsFirstPolyTime.lean | 136 +++++++++ .../Frontier/TensorNetwork/Schedule.lean | 7 +- .../CountingSimulation/EntryAnalysis.lean | 185 ++----------- .../CountingSimulation/FastAlgorithm.lean | 106 ++----- 9 files changed, 428 insertions(+), 483 deletions(-) create mode 100644 Complexity/Computability/Circuit/Frontier/TensorNetwork/RowsFirstPolyTime.lean diff --git a/Complexity.lean b/Complexity.lean index 6520dfcc2..8d0a10837 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -964,6 +964,7 @@ public import Complexity.Computability.Circuit.Frontier.TensorNetwork.PacketTerm public import Complexity.Computability.Circuit.Frontier.TensorNetwork.Recursion public import Complexity.Computability.Circuit.Frontier.TensorNetwork.ReductionLift public import Complexity.Computability.Circuit.Frontier.TensorNetwork.Reindex +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.RowsFirstPolyTime public import Complexity.Computability.Circuit.Frontier.TensorNetwork.Schedule public import Complexity.Computability.Circuit.Frontier.TensorNetwork.ScheduleCount public import Complexity.Computability.Circuit.Frontier.TensorNetwork.ScheduledRecursion diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContractionMachine.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContractionMachine.lean index f6aad0ffa..c23f6e016 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContractionMachine.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/EntryContractionMachine.lean @@ -9,6 +9,8 @@ module public import Complexity.Computability.Circuit.Frontier.TensorNetwork.EntryContraction public import Complexity.Computability.Circuit.Frontier.TensorNetwork.FastContractionPolyTime +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.FastContractionLeaf +import Complexity.Computability.Circuit.Frontier.TensorNetwork.RowsFirstPolyTime import Complexity.Computability.Machines.Turing.MultiTape.Complexity.PolyTime.List import Complexity.Computability.Machines.Turing.MultiTape.Complexity.PolyTime.Nat import Complexity.Computability.Machines.Turing.MultiTape.Complexity.PolyTime.Nat.Binary @@ -34,15 +36,17 @@ uses (`ExplicitTensorNetwork.capPrecision`) keeps the residue only for tables of **The guard** (`EntryContraction.guard`) checks that `fl` is the modulus `FastContraction.modulus m` of the number `m` of edges, that the network is rows-first bipartite, and that every vertex has at -most `degreeBound m` ports. It is polynomial-time (`EntryContraction.guard_polyTime`), and every -admissible input at the modulus passes it (`EntryContraction.guard_of_entryAdmissible`), since -`⌈s ^ (9/10)⌉ ≤ degreeBound s ≤ degreeBound m`. +most `degreeBound m` ports. It is polynomial-time (`EntryContraction.guard_polyTime`), with the +rows-first test `DescribedNetwork.rowsFirst_polyTime`, and every admissible input at the modulus +passes it (`EntryContraction.guard_of_entryAdmissible`), since +`⌈s ^ (9/10)⌉ ≤ degreeBound s ≤ degreeBound m` (`ContractionSchedule.degreeBound_mono`). **The root and the clock.** The root call (`EntryContraction.rootCall`) has scale `m`, depth `0`, edge bound `m + 1`, precision `P`, modulus `fl`, `r` rows and the network `FastContraction.rootNet G`. The clock (`EntryContraction.clock`) is `2 ^ (K₀ (m + P) / √⌊log₂ (m + P)⌋)`, as for explicit networks. On guarded inputs the root is -well-formed (`EntryContraction.wf_rootCall`). +well-formed (`EntryContraction.wf_rootCall`), and it has no packets +(`EntryContraction.packetShape_rootCall`). **The result** (`EntryContraction.coreValue`): on guarded inputs, the coefficient list of a value tagged `0` returned by the clocked run, and direct summation otherwise. It is correct at the modulus @@ -64,12 +68,10 @@ Its native certificate is `EntryContraction.fastCore`; its resources are analyze * `Cslib.Circuits.Frontier.FastContraction.contraction_rootNet`: the root network computes the contraction of the network, for every entry procedure. -* `Cslib.Circuits.Frontier.DescribedNetwork.rowsFirst_polyTime`: rows-first bipartiteness is - decidable in polynomial time. * `Cslib.Circuits.Frontier.EntryContraction.guard_polyTime`: the guard is polynomial-time. -* `Cslib.Circuits.Frontier.ContractionSchedule.degreeBound_mono`: the degree bound is monotone. * `Cslib.Circuits.Frontier.EntryContraction.guard_of_entryAdmissible`: admissible inputs pass it. * `Cslib.Circuits.Frontier.EntryContraction.wf_rootCall`: guarded roots are well-formed. +* `Cslib.Circuits.Frontier.EntryContraction.packetShape_rootCall`: the root has no packets. * `Cslib.Circuits.Frontier.EntryContraction.val_coreValue`: the machine is correct. ## References @@ -99,108 +101,6 @@ theorem FastContraction.contraction_rootNet {R : Type*} [CommSemiring R] (f : Li simp only [DescribedNetwork.contraction, FastContraction.rootNet, List.map_map] rfl -/-! ### Rows-first bipartiteness in polynomial time -/ - -namespace DescribedNetwork - -section RowsFirst - -variable {encT : T ↪ List Bool} - -/-- Rows-first bipartiteness as a conjunction of list tests. -/ -private def rowsTest (G : ℕ × DescribedNetwork T) : Bool := - G.2.vertices.all (fun v => v.1.all fun i => decide (i < G.2.numEdges)) && - (List.range G.2.numEdges).all (fun i => - decide (((G.2.vertices.take G.1).flatMap Prod.fst).count i = 1) && - decide (((G.2.vertices.drop G.1).flatMap Prod.fst).count i = 1)) - -private theorem decide_eq_rowsTest (G : ℕ × DescribedNetwork T) : - decide (G.2.IsRowsFirstBipartite G.1) = rowsTest G := by - refine Bool.eq_iff_iff.mpr ?_ - simp only [rowsTest, DescribedNetwork.IsRowsFirstBipartite, decide_eq_true_eq, Bool.and_eq_true, - List.all_eq_true, List.mem_range, List.count_flatMap, Function.comp_def] - -/-- **Rows-first bipartiteness is polynomial-time**, from a network with its number of rows. -/ -theorem rowsFirst_polyTime : - ComputableInPolyTime (fun G : ℕ × DescribedNetwork T => decide (G.2.IsRowsFirstBipartite G.1)) - (encPair encNat (encDescribed encT)) encBool := by - have hpair : ComputableInPolyTime (DescribedNetwork.equivProd (T := T)) (encDescribed encT) - (encPair encUnary (encList (encPair (encList encNat) encT))) := - ComputableInPolyTime.of_eq fun _ => rfl - have hd := ComputableInPolyTime.snd encNat (encDescribed encT) - have hr := ComputableInPolyTime.fst encNat (encDescribed encT) - have hm : ComputableInPolyTime (fun G : ℕ × DescribedNetwork T => G.2.numEdges) - (encPair encNat (encDescribed encT)) encUnary := - (ComputableInPolyTime.fst _ _).comp (hpair.comp hd) - have hvs : ComputableInPolyTime (fun G : ℕ × DescribedNetwork T => G.2.vertices) - (encPair encNat (encDescribed encT)) (encList (encPair (encList encNat) encT)) := - (ComputableInPolyTime.snd _ _).comp (hpair.comp hd) - -- Ports in range. - have h1 : ComputableInPolyTime (fun G : ℕ × DescribedNetwork T => - G.2.vertices.all (fun v => v.1.all fun i => decide (i < G.2.numEdges))) - (encPair encNat (encDescribed encT)) encBool := by - refine ComputableInPolyTime.allWithInput hvs ?_ - refine ComputableInPolyTime.allWithInput - ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _)) ?_ - exact ComputableInPolyTime.binary_lt.comp ((ComputableInPolyTime.snd _ _).prod - (ComputableInPolyTime.unary_to_binary.comp (hm.comp ((ComputableInPolyTime.fst _ _).comp - (ComputableInPolyTime.fst _ _))))) - -- Each edge has one row port and one column port. - have hlen := (ComputableInPolyTime.length_list _).comp hvs - have hcap := ComputableInPolyTime.binary_min_unary' hlen hr - have htake : ComputableInPolyTime (fun G : ℕ × DescribedNetwork T => - G.2.vertices.take (min G.2.vertices.length G.1)) (encPair encNat (encDescribed encT)) - (encList (encPair (encList encNat) encT)) := - .of_tidy (ComputableTidilyInPolyTime.listTakeWithInput hvs.tidy hcap.tidy) - have hdrop : ComputableInPolyTime (fun G : ℕ × DescribedNetwork T => - G.2.vertices.drop (min G.2.vertices.length G.1)) (encPair encNat (encDescribed encT)) - (encList (encPair (encList encNat) encT)) := - .of_tidy (ComputableTidilyInPolyTime.listDropWithInput hvs.tidy hcap.tidy) - have hflat {l : ℕ × DescribedNetwork T → List (List ℕ × T)} - (hl : ComputableInPolyTime l (encPair encNat (encDescribed encT)) - (encList (encPair (encList encNat) encT))) : - ComputableInPolyTime (fun G => (l G).flatMap Prod.fst) (encPair encNat (encDescribed encT)) - (encList encNat) := - ComputableInPolyTime.flatMapWithInput (f := fun _ v => v.1) hl - ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _)) - have hcount {l : ℕ × DescribedNetwork T → List ℕ} - (hl : ComputableInPolyTime l (encPair encNat (encDescribed encT)) (encList encNat)) : - ComputableInPolyTime (fun p : (ℕ × DescribedNetwork T) × ℕ => - decide ((l p.1).count p.2 = 1)) - (encPair (encPair encNat (encDescribed encT)) encUnary) encBool := by - have hc := ComputableInPolyTime.countPWithInput (test := fun p a => decide (a = p.2)) - (hl.comp (ComputableInPolyTime.fst (encPair encNat (encDescribed encT)) encUnary)) - (ComputableInPolyTime.decide_eq' (ComputableInPolyTime.snd _ _) - (ComputableInPolyTime.unary_to_binary.comp ((ComputableInPolyTime.snd _ _).comp - (ComputableInPolyTime.fst _ _)))) - refine (ComputableInPolyTime.decide_eq' hc (ComputableInPolyTime.const 1)).of_enc_eq - fun p => ?_ - simp only [Function.comp_apply, List.count_eq_countP] - congr 3 - have h2 : ComputableInPolyTime (fun G : ℕ × DescribedNetwork T => - (List.range G.2.numEdges).all (fun i => - decide (((G.2.vertices.take (min G.2.vertices.length G.1)).flatMap Prod.fst).count i = - 1) && - decide (((G.2.vertices.drop (min G.2.vertices.length G.1)).flatMap Prod.fst).count i = - 1))) (encPair encNat (encDescribed encT)) encBool := - ComputableInPolyTime.allWithInput (ComputableInPolyTime.range.comp hm) - (ComputableInPolyTime.bool_and.comp ((hcount (hflat htake)).prod (hcount (hflat hdrop)))) - refine (ComputableInPolyTime.bool_and.comp (h1.prod h2)).of_enc_eq fun G => ?_ - have ht : G.2.vertices.take (min G.2.vertices.length G.1) = G.2.vertices.take G.1 := by - rcases le_total G.2.vertices.length G.1 with hle | hle - · rw [min_eq_left hle, List.take_length, List.take_of_length_le hle] - · rw [min_eq_right hle] - have hdr : G.2.vertices.drop (min G.2.vertices.length G.1) = G.2.vertices.drop G.1 := by - rcases le_total G.2.vertices.length G.1 with hle | hle - · rw [min_eq_left hle, List.drop_length, List.drop_of_length_le hle] - · rw [min_eq_right hle] - rw [decide_eq_rowsTest, rowsTest] - simp only [Function.comp_apply, ht, hdr] - -end RowsFirst - -end DescribedNetwork - namespace EntryContraction open FastContraction (Call scheme nativeMk value rootNet modulus fuelConst encCall encValue @@ -210,47 +110,43 @@ variable {encT : T ↪ List Bool} {entry : T → List Bool → List ℕ} /-! ### The guard -/ -/-- **The guard**: `fl` is the modulus of the number `m` of edges, the network is rows-first -bipartite at its number of rows, and every vertex has at most `degreeBound m` ports. -/ -@[expose] def guard (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : Bool := - decide (x.2.1 = modulus x.2.2.2.numEdges ∧ x.2.2.2.IsRowsFirstBipartite x.2.2.1 ∧ - ∀ v ∈ x.2.2.2.vertices, v.1.length ≤ degreeBound x.2.2.2.numEdges) +/-- **The guard** on an input `(P, fl, r, G)`: `fl` is the modulus of the number `m` of edges of +`G`, `G` is rows-first bipartite at `r` rows, and every vertex has at most `degreeBound m` +ports. -/ +@[expose] def guard : ℕ × List ℕ × ℕ × DescribedNetwork T → Bool + | (_, fl, r, G) => decide (fl = modulus G.numEdges ∧ G.IsRowsFirstBipartite r ∧ + ∀ v ∈ G.vertices, v.1.length ≤ degreeBound G.numEdges) + +/-- The network of an input, from `(P, fl, r, G)`. -/ +private theorem network_polyTime : + ComputableInPolyTime (fun ((_, _, _, G) : ℕ × List ℕ × ℕ × DescribedNetwork T) => G) + (encInput encT) (DescribedNetwork.encDescribed encT) := + (ComputableInPolyTime.snd _ _).comp + ((ComputableInPolyTime.snd _ _).comp (ComputableInPolyTime.snd _ _)) /-- The number of edges of an input, in unary. -/ private theorem numEdges_polyTime : - ComputableInPolyTime (fun x : ℕ × List ℕ × ℕ × DescribedNetwork T => x.2.2.2.numEdges) - (encInput encT) encUnary := by - have hpair : ComputableInPolyTime (DescribedNetwork.equivProd (T := T)) - (DescribedNetwork.encDescribed encT) - (encPair encUnary (encList (encPair (encList encNat) encT))) := - ComputableInPolyTime.of_eq fun _ => rfl - exact (ComputableInPolyTime.fst _ _).comp (hpair.comp ((ComputableInPolyTime.snd _ _).comp - ((ComputableInPolyTime.snd _ _).comp (ComputableInPolyTime.snd _ _)))) - -/-- The network of an input with its number of rows. -/ + ComputableInPolyTime (fun ((_, _, _, G) : ℕ × List ℕ × ℕ × DescribedNetwork T) => G.numEdges) + (encInput encT) encUnary := + DescribedNetwork.numEdges_polyTime.comp network_polyTime + +/-- The network of an input with its number of rows, from `(P, fl, r, G)`. -/ private theorem rowsNet_polyTime : - ComputableInPolyTime (fun x : ℕ × List ℕ × ℕ × DescribedNetwork T => x.2.2) (encInput encT) - (encPair encNat (DescribedNetwork.encDescribed encT)) := + ComputableInPolyTime (fun ((_, _, r, G) : ℕ × List ℕ × ℕ × DescribedNetwork T) => (r, G)) + (encInput encT) (encPair encNat (DescribedNetwork.encDescribed encT)) := (ComputableInPolyTime.snd _ _).comp (ComputableInPolyTime.snd _ _) /-- **The guard is polynomial-time.** -/ theorem guard_polyTime : ComputableInPolyTime (guard (T := T)) (encInput encT) encBool := by have hm := numEdges_polyTime (encT := encT) - have hfl : ComputableInPolyTime (fun x : ℕ × List ℕ × ℕ × DescribedNetwork T => - decide (x.2.1 = modulus x.2.2.2.numEdges)) (encInput encT) encBool := + have hfl : ComputableInPolyTime (fun ((_, fl, _, G) : ℕ × List ℕ × ℕ × DescribedNetwork T) => + decide (fl = modulus G.numEdges)) (encInput encT) encBool := ComputableInPolyTime.decide_eq' ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _)) (FastContraction.modulus_polyTime.comp hm) have hrows := (DescribedNetwork.rowsFirst_polyTime (encT := encT)).comp rowsNet_polyTime - have hvs : ComputableInPolyTime (fun x : ℕ × List ℕ × ℕ × DescribedNetwork T => x.2.2.2.vertices) - (encInput encT) (encList (encPair (encList encNat) encT)) := by - have hpair : ComputableInPolyTime (DescribedNetwork.equivProd (T := T)) - (DescribedNetwork.encDescribed encT) - (encPair encUnary (encList (encPair (encList encNat) encT))) := - ComputableInPolyTime.of_eq fun _ => rfl - exact (ComputableInPolyTime.snd _ _).comp (hpair.comp ((ComputableInPolyTime.snd _ _).comp - ((ComputableInPolyTime.snd _ _).comp (ComputableInPolyTime.snd _ _)))) - have hdeg : ComputableInPolyTime (fun x : ℕ × List ℕ × ℕ × DescribedNetwork T => - x.2.2.2.vertices.all (fun v => decide (v.1.length ≤ degreeBound x.2.2.2.numEdges))) + have hvs := (DescribedNetwork.vertices_polyTime (encT := encT)).comp network_polyTime + have hdeg : ComputableInPolyTime (fun ((_, _, _, G) : ℕ × List ℕ × ℕ × DescribedNetwork T) => + G.vertices.all (fun v => decide (v.1.length ≤ degreeBound G.numEdges))) (encInput encT) encBool := by refine ComputableInPolyTime.allWithInput hvs ?_ exact ComputableInPolyTime.binary_le' @@ -258,14 +154,9 @@ theorem guard_polyTime : ComputableInPolyTime (guard (T := T)) (encInput encT) e ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _)))) (degreeBound_polyTime.comp (hm.comp (ComputableInPolyTime.fst _ _))) refine (ComputableInPolyTime.bool_and.comp (hfl.prod (ComputableInPolyTime.bool_and.comp - (hrows.prod hdeg)))).of_enc_eq fun x => ?_ + (hrows.prod hdeg)))).of_enc_eq fun ⟨P, fl, r, G⟩ => ?_ simp only [guard, Function.comp_apply, Bool.decide_and, List.all_eq, decide_eq_true_eq] -/-- `degreeBound` is monotone. -/ -theorem _root_.Cslib.Circuits.Frontier.ContractionSchedule.degreeBound_mono {a b : ℕ} (h : a ≤ b) : - degreeBound a ≤ degreeBound b := - Nat.pow_le_pow_right (by norm_num) (by have := Nat.log_mono_right (b := 2) h; omega) - /-- **Admissible inputs pass the guard** at the modulus of the number of edges: their degree is at most `⌈s ^ (9/10)⌉ ≤ degreeBound s ≤ degreeBound m`, for `s ≤ m`. -/ theorem guard_of_entryAdmissible @@ -281,12 +172,12 @@ theorem guard_of_entryAdmissible /-- **The root call** of an input `(P, fl, r, G)`: scale `m`, depth `0`, edge bound `m + 1`, precision `P`, modulus `fl`, `r` rows and the descriptors of `G`. -/ -@[expose] def rootCall (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : Call T := - ((x.2.2.2.numEdges, 0, x.2.2.2.numEdges + 1, x.1, x.2.1, x.2.2.1), rootNet x.2.2.2) +@[expose] def rootCall : ℕ × List ℕ × ℕ × DescribedNetwork T → Call T + | (P, fl, r, G) => ((G.numEdges, 0, G.numEdges + 1, P, fl, r), rootNet G) /-- **The clock** of an input `(P, fl, r, G)`: `2 ^ (K₀ (m + P) / √⌊log₂ (m + P)⌋)`. -/ -@[expose] def clock (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : ℕ := - 2 ^ (fuelConst * (x.2.2.2.numEdges + x.1) / Nat.sqrt (Nat.log 2 (x.2.2.2.numEdges + x.1))) +@[expose] def clock : ℕ × List ℕ × ℕ × DescribedNetwork T → ℕ + | (P, _, _, G) => 2 ^ (fuelConst * (G.numEdges + P) / Nat.sqrt (Nat.log 2 (G.numEdges + P))) /-- **The root call is polynomial-time.** -/ theorem rootCall_polyTime : @@ -299,11 +190,10 @@ theorem rootCall_polyTime : (ComputableInPolyTime.snd encUnary _) have hr := (ComputableInPolyTime.fst encNat (DescribedNetwork.encDescribed encT)).comp rowsNet_polyTime - have hG := (ComputableInPolyTime.snd encNat (DescribedNetwork.encDescribed encT)).comp - rowsNet_polyTime exact (hm.prod ((ComputableInPolyTime.const 0).prod ((ComputableInPolyTime.unary_add' hm (ComputableInPolyTime.const 1)).prod - (hP.prod (hfl.prod hr))))).prod ((FastContraction.rootNet_polyTime encT).comp hG) + (hP.prod (hfl.prod hr))))).prod + ((FastContraction.rootNet_polyTime encT).comp network_polyTime) /-- **The clock is polynomial-time.** -/ theorem clock_polyTime : ComputableInPolyTime (clock (T := T)) (encInput encT) encNat := @@ -314,10 +204,11 @@ theorem clock_polyTime : ComputableInPolyTime (clock (T := T)) (encInput encT) e of `G` keep its rows-first ports. -/ theorem wf_rootCall {x : ℕ × List ℕ × ℕ × DescribedNetwork T} (hg : guard x = true) : FastContraction.WF (rootCall x) := by + obtain ⟨P, fl, r, G⟩ := x simp only [guard, decide_eq_true_eq] at hg obtain ⟨hfl, ⟨h1, h2⟩, -⟩ := hg refine ⟨?_, fun v hv i hi => ?_, fun i hi => ?_⟩ - · change Irreducible ((monicOf x.2.1).map (Int.castRingHom (ZMod 2))) + · change Irreducible ((monicOf fl).map (Int.castRingHom (ZMod 2))) rw [hfl] exact irreducible_modulus _ · simp only [rootCall, rootNet, List.mem_map] at hv @@ -327,19 +218,26 @@ theorem wf_rootCall {x : ℕ × List ℕ × ℕ × DescribedNetwork T} (hg : gua Function.comp_def] at hi ⊢ exact h2 i hi +/-- **The root call has no packets**: its descriptors are those of the input network. -/ +theorem packetShape_rootCall (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : + FastContraction.PacketShape (rootCall x) := by + obtain ⟨P, fl, r, G⟩ := x + exact FastContraction.packetShape_of_net_eq_rootNet rfl + /-! ### The result -/ variable (entry) in /-- **The result of the machine** on an input `(P, fl, r, G)`: on guarded inputs, the coefficient list of a value tagged `0` returned by the clocked run from the root call, and direct summation otherwise. -/ -noncomputable def coreValue (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : List ℕ := - if guard x then - ((scheme entry nativeMk).run clock rootCall x).elim - (DescribedNetwork.sumValue SumOps.galois entry (x.1, x.2.1) x.2.2.2) - fun v => if v.1 = 0 then v.2 - else DescribedNetwork.sumValue SumOps.galois entry (x.1, x.2.1) x.2.2.2 - else DescribedNetwork.sumValue SumOps.galois entry (x.1, x.2.1) x.2.2.2 +noncomputable def coreValue : ℕ × List ℕ × ℕ × DescribedNetwork T → List ℕ + | x@(P, fl, _, G) => + if guard x then + ((scheme entry nativeMk).run clock rootCall x).elim + (DescribedNetwork.sumValue SumOps.galois entry (P, fl) G) + fun (tag, coeffs) => if tag = 0 then coeffs + else DescribedNetwork.sumValue SumOps.galois entry (P, fl) G + else DescribedNetwork.sumValue SumOps.galois entry (P, fl) G /-- **The machine is correct**: at the modulus of the number of edges, the value of the result is the contraction of the values of the entries, on every input and for every fuel. A value tagged @@ -348,7 +246,7 @@ contraction on well-formed roots (`FastContraction.val_value`). -/ theorem val_coreValue (P r : ℕ) (G : DescribedNetwork T) : val P (modulus G.numEdges) (coreValue entry (P, modulus G.numEdges, r, G)) = G.contraction fun t bs => val P (modulus G.numEdges) (entry t bs) := by - unfold coreValue + rw [coreValue] split_ifs with hg · rcases hrun : (scheme entry nativeMk).run clock rootCall (P, modulus G.numEdges, r, G) with _ | ⟨d, y⟩ @@ -369,14 +267,16 @@ theorem val_coreValue (P r : ℕ) (G : DescribedNetwork T) : /-- Whether a returned value is tagged `0`. -/ theorem valueTag_polyTime : - ComputableInPolyTime (fun q : (ℕ × List ℕ × ℕ × DescribedNetwork T) × (ℕ × List ℕ) => - decide (q.2.1 = 0)) (encPair (encInput encT) encValue) encBool := + ComputableInPolyTime + (fun ((_, (tag, _)) : (ℕ × List ℕ × ℕ × DescribedNetwork T) × (ℕ × List ℕ)) => + decide (tag = 0)) (encPair (encInput encT) encValue) encBool := ComputableInPolyTime.decide_eq' ((ComputableInPolyTime.fst encUnary (encList encNat)).comp (ComputableInPolyTime.snd (encInput encT) encValue)) (ComputableInPolyTime.const 0) /-- The coefficient list of a returned value. -/ theorem valueList_polyTime : - ComputableInPolyTime (fun q : (ℕ × List ℕ × ℕ × DescribedNetwork T) × (ℕ × List ℕ) => q.2.2) + ComputableInPolyTime + (fun ((_, (_, coeffs)) : (ℕ × List ℕ × ℕ × DescribedNetwork T) × (ℕ × List ℕ)) => coeffs) (encPair (encInput encT) encValue) (encList encNat) := (ComputableInPolyTime.snd encUnary (encList encNat)).comp (ComputableInPolyTime.snd (encInput encT) encValue) @@ -403,12 +303,14 @@ computes `coreValue`. -/ (NativeCertificate.ofPolyTime valueList_polyTime) ((directCore entry ce).comp (NativeCertificate.ofPolyTime (ComputableInPolyTime.fst (encInput encT) encValue))))) - (directCore entry ce)).congr fun x => by + (directCore entry ce)).congr fun ⟨P, fl, r, G⟩ => by simp only [coreValue, Function.comp_apply] split - · cases (scheme entry nativeMk).run clock rootCall x with + · cases (scheme entry nativeMk).run clock rootCall (P, fl, r, G) with | none => rfl - | some v => simp only [Option.elim_some, decide_eq_true_eq] + | some v => + obtain ⟨tag, coeffs⟩ := v + simp only [Option.elim_some, decide_eq_true_eq] · rfl /-- The time of the machine, unfolded: the guard, and on guarded inputs the run twice, the input, @@ -419,12 +321,14 @@ theorem fastCore_time (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : if guard x = true then 2 * (runCore ce).time x + (encInput encT x).length + ((scheme entry nativeMk).run clock rootCall x).elim ((directCore entry ce).time x) - fun v => (NativeCertificate.ofPolyTime (valueTag_polyTime (encT := encT))).time - (x, v) + - if decide (v.1 = 0) = true then - (NativeCertificate.ofPolyTime (valueList_polyTime (encT := encT))).time (x, v) + fun (tag, coeffs) => + (NativeCertificate.ofPolyTime (valueTag_polyTime (encT := encT))).time + (x, (tag, coeffs)) + + if decide (tag = 0) = true then + (NativeCertificate.ofPolyTime (valueList_polyTime (encT := encT))).time + (x, (tag, coeffs)) else (NativeCertificate.ofPolyTime - (ComputableInPolyTime.fst (encInput encT) encValue)).time (x, v) + + (ComputableInPolyTime.fst (encInput encT) encValue)).time (x, (tag, coeffs)) + (directCore entry ce).time x else (directCore entry ce).time x := rfl @@ -435,12 +339,14 @@ theorem fastCore_space (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : if guard x = true then 2 * (runCore ce).space x + (encInput encT x).length + ((scheme entry nativeMk).run clock rootCall x).elim ((directCore entry ce).space x) - fun v => (NativeCertificate.ofPolyTime (valueTag_polyTime (encT := encT))).space - (x, v) + - if decide (v.1 = 0) = true then - (NativeCertificate.ofPolyTime (valueList_polyTime (encT := encT))).space (x, v) + fun (tag, coeffs) => + (NativeCertificate.ofPolyTime (valueTag_polyTime (encT := encT))).space + (x, (tag, coeffs)) + + if decide (tag = 0) = true then + (NativeCertificate.ofPolyTime (valueList_polyTime (encT := encT))).space + (x, (tag, coeffs)) else (NativeCertificate.ofPolyTime - (ComputableInPolyTime.fst (encInput encT) encValue)).space (x, v) + + (ComputableInPolyTime.fst (encInput encT) encValue)).space (x, (tag, coeffs)) + (directCore entry ce).space x else (directCore entry ce).space x := rfl diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionLeaf.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionLeaf.lean index 439f15498..fa8f9ecdb 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionLeaf.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionLeaf.lean @@ -47,7 +47,10 @@ the packet shape and at most `2 m` edges takes time `K (n + 1) ^ K 2 ^ (K s / `K (n + 1) ^ K`, provided that from some `s₀` on it has at most `leafSize m` edges and precision at most `m ^ c`: then `2 ^ M ≤ 2 ^ (C s / √⌊log₂ s⌋)`, and `(A p + 2) ^ A` is `2 ^ O(s ^ (1 / 32768) log s)` (`FastContraction.exists_packetFactor_le`). Below `s₀` everything -but a polynomial in `n` is a constant. +but a polynomial in `n` is a constant (`FastContraction.exists_leafFactor_le`). With an entry +procedure whose roots cost time `E` and space `ES`, the leaf takes time +`K (n + ES + 1) ^ K 2 ^ (K s / √⌊log₂ s⌋) (E + 1)` and space `K (n + ES + 1) ^ K` +(`FastContraction.exists_leafCertificate_le_of_entry`). ## Main definitions @@ -62,8 +65,11 @@ but a polynomial in `n` is a constant. * `Cslib.Circuits.Frontier.FastContraction.leafCertificate_le_of_packetShape`, `Cslib.Circuits.Frontier.FastContraction.leafCertificate_tableEntry_le_of_packetShape`: the cost of a leaf with the packet shape, and over tables. -* `Cslib.Circuits.Frontier.FastContraction.exists_leafCertificate_le`: the leaf bound of the - resource analysis. +* `Cslib.Circuits.Frontier.FastContraction.exists_leafFactor_le`: the factor `2 ^ M (A p + 2) ^ A` + is subexponential. +* `Cslib.Circuits.Frontier.FastContraction.exists_leafCertificate_le`, + `Cslib.Circuits.Frontier.FastContraction.exists_leafCertificate_le_of_entry`: the leaf bound of + the resource analysis, over tables and with the costs of the root entries. ## References @@ -764,78 +770,143 @@ theorem exists_packetFactor_le (C c : ℕ) : ∃ K : ℕ, ∀ s m p : ℕ, 2 ≤ _ ≤ 2 ^ (16 * ((c₀ + 2) * (c + 1)) * 2 ^ c₀ * s / Nat.sqrt μ) := Nat.pow_le_pow_right (by norm_num) hE' -/-- **The leaf bound of the resource analysis.** For all constants `C`, `c` and `s₀` there is `K` -such that a call with the packet shape, scale `m` with `s ≤ m ≤ C s` and at most `2 m` edges takes -time at most `K (n + 1) ^ K 2 ^ (K s / √⌊log₂ s⌋)` and space at most `K (n + 1) ^ K` at a leaf, -provided that from `s₀` on it has at most `leafSize m` edges and precision at most `m ^ c`. Below -`s₀`, the scale is bounded, so the packet factor is polynomial and `2 ^ M` is a constant; from -`s₀` on, `2 ^ M ≤ 2 ^ (C s / √⌊log₂ s⌋)` and the packet factor is subexponential -(`exists_packetFactor_le`). -/ -theorem exists_leafCertificate_le (C c s₀ : ℕ) : ∃ K : ℕ, - ∀ (mk : Call (List ℕ) → State → ℕ × DescribedNetwork (VertexDesc (List ℕ))) (s : ℕ) - (x : Call (List ℕ)), 2 ≤ s → - s ≤ x.scale → x.scale ≤ C * s → PacketShape x → x.edges ≤ 2 * x.scale → - (s₀ ≤ s → x.edges ≤ leafSize x.scale ∧ x.prec ≤ x.scale ^ c) → - (leafCertificate tableEntryCertificate mk).time x ≤ - K * ((encCall (encList encNat) x).length + 1) ^ K * 2 ^ (K * s / Nat.sqrt (Nat.log 2 s)) ∧ - (leafCertificate tableEntryCertificate mk).space x ≤ - K * ((encCall (encList encNat) x).length + 1) ^ K := by - obtain ⟨K₀, hK₀⟩ := leafCertificate_tableEntry_le_of_packetShape +/-- **The leaf factor is subexponential.** For all constants `C`, `c` and `s₀` there is `K` such +that, for `s ≤ m ≤ C s`, `M ≤ 2 m` and `p ≤ n`, writing `A = 2 ^ (⌊log₂ m⌋ / 32768)`, +`2 ^ M (A p + 2) ^ A ≤ K (n + 1) ^ K 2 ^ (K s / √⌊log₂ s⌋)`, provided that from `s₀` on +`M ≤ leafSize m` and `p ≤ m ^ c`. Below `s₀`, `m` is bounded, so the packet factor is polynomial +in `n` and `2 ^ M` is a constant; from `s₀` on, `2 ^ M ≤ 2 ^ (C s / √⌊log₂ s⌋)` and the packet +factor is subexponential (`exists_packetFactor_le`). This is the factor of the cost of a leaf with +the packet shape (`leafCertificate_le_of_packetShape`) that is not polynomial. -/ +theorem exists_leafFactor_le (C c s₀ : ℕ) : ∃ K : ℕ, ∀ s m M p n : ℕ, 2 ≤ s → s ≤ m → + m ≤ C * s → M ≤ 2 * m → p ≤ n → (s₀ ≤ s → M ≤ leafSize m ∧ p ≤ m ^ c) → + 2 ^ M * (2 ^ (Nat.log 2 m / 32768) * p + 2) ^ 2 ^ (Nat.log 2 m / 32768) ≤ + K * (n + 1) ^ K * 2 ^ (K * s / Nat.sqrt (Nat.log 2 s)) := by obtain ⟨K₁, hK₁⟩ := exists_packetFactor_le C c - obtain ⟨Ks, hKs⟩ : ∃ Ks, Ks = K₀ * 2 ^ (2 * (C * s₀)) * (C * s₀ + 2) ^ (C * s₀) := ⟨_, rfl⟩ - refine ⟨Ks + K₀ + C * s₀ + C + K₁, fun mk s x hs hsm hmC hshape hM hbig => ?_⟩ - obtain ⟨hT, hS⟩ := hK₀ mk x hshape - set n := (encCall (encList encNat) x).length with hn - set K := Ks + K₀ + C * s₀ + C + K₁ with hK + obtain ⟨Ks, hKs⟩ : ∃ Ks, Ks = 2 ^ (2 * (C * s₀)) * (C * s₀ + 2) ^ (C * s₀) := ⟨_, rfl⟩ + have hKs1 : 1 ≤ Ks := by rw [hKs]; exact Nat.one_le_iff_ne_zero.mpr (by positivity) + refine ⟨Ks + C * s₀ + C + K₁, fun s m M p n hs hsm hmC hM hp hbig => ?_⟩ + set K := Ks + C * s₀ + C + K₁ with hK set S := Nat.sqrt (Nat.log 2 s) with hSdef + set A := 2 ^ (Nat.log 2 m / 32768) with hA have hS1 : 1 ≤ S := Nat.one_le_sqrt_log_two hs have hB1 : 1 ≤ n + 1 := by omega have hX1 : 1 ≤ 2 ^ (K * s / S) := Nat.one_le_two_pow - have hnK : (n + 1) ^ K₀ ≤ (n + 1) ^ K := Nat.pow_le_pow_right hB1 (by omega) - refine ⟨?_, hS.trans (Nat.mul_le_mul (by omega) hnK)⟩ - set A := 2 ^ (Nat.log 2 x.scale / 32768) with hA - have hAm : A ≤ x.scale := (Nat.pow_le_pow_right (by norm_num) (Nat.div_le_self _ _)).trans + have hAm : A ≤ m := (Nat.pow_le_pow_right (by norm_num) (Nat.div_le_self _ _)).trans (Nat.pow_log_le_self 2 (by omega)) rcases lt_or_ge s s₀ with hsmall | hlarge · -- Below `s₀`: constants and a polynomial. - have hmC' : x.scale ≤ C * s₀ := hmC.trans (Nat.mul_le_mul_left _ hsmall.le) - have hp : x.prec ≤ n := by have := scale_add_prec_add_length_fl_le (encList encNat) x; omega - have h2M : 2 ^ x.edges ≤ 2 ^ (2 * (C * s₀)) := - Nat.pow_le_pow_right (by norm_num) (by omega) - have hbase : A * x.prec + 2 ≤ (C * s₀ + 2) * (n + 1) := by - have : A * x.prec ≤ C * s₀ * n := Nat.mul_le_mul (hAm.trans hmC') hp + have hmC' : m ≤ C * s₀ := hmC.trans (Nat.mul_le_mul_left _ hsmall.le) + have h2M : 2 ^ M ≤ 2 ^ (2 * (C * s₀)) := Nat.pow_le_pow_right (by norm_num) (by omega) + have hbase : A * p + 2 ≤ (C * s₀ + 2) * (n + 1) := by + have : A * p ≤ C * s₀ * n := Nat.mul_le_mul (hAm.trans hmC') hp nlinarith - have hfac : (A * x.prec + 2) ^ A ≤ (C * s₀ + 2) ^ (C * s₀) * (n + 1) ^ (C * s₀) := by - calc (A * x.prec + 2) ^ A ≤ ((C * s₀ + 2) * (n + 1)) ^ A := Nat.pow_le_pow_left hbase _ + have hfac : (A * p + 2) ^ A ≤ (C * s₀ + 2) ^ (C * s₀) * (n + 1) ^ (C * s₀) := by + calc (A * p + 2) ^ A ≤ ((C * s₀ + 2) * (n + 1)) ^ A := Nat.pow_le_pow_left hbase _ _ ≤ ((C * s₀ + 2) * (n + 1)) ^ (C * s₀) := Nat.pow_le_pow_right (Nat.one_le_iff_ne_zero.mpr (by positivity)) (hAm.trans hmC') _ = (C * s₀ + 2) ^ (C * s₀) * (n + 1) ^ (C * s₀) := mul_pow _ _ _ - calc (leafCertificate tableEntryCertificate mk).time x - ≤ K₀ * (n + 1) ^ K₀ * 2 ^ x.edges * (A * x.prec + 2) ^ A := hT - _ ≤ K₀ * (n + 1) ^ K₀ * 2 ^ (2 * (C * s₀)) * - ((C * s₀ + 2) ^ (C * s₀) * (n + 1) ^ (C * s₀)) := - Nat.mul_le_mul (Nat.mul_le_mul_left _ h2M) hfac - _ = Ks * (n + 1) ^ (K₀ + C * s₀) := by rw [hKs, pow_add]; ring + calc 2 ^ M * (A * p + 2) ^ A + ≤ 2 ^ (2 * (C * s₀)) * ((C * s₀ + 2) ^ (C * s₀) * (n + 1) ^ (C * s₀)) := + Nat.mul_le_mul h2M hfac + _ = Ks * (n + 1) ^ (C * s₀) := by rw [hKs]; ring _ ≤ K * (n + 1) ^ K := Nat.mul_le_mul (by omega) (Nat.pow_le_pow_right hB1 (by omega)) _ ≤ K * (n + 1) ^ K * 2 ^ (K * s / S) := Nat.le_mul_of_pos_right _ hX1 · -- From `s₀` on: the leaf size and the packet factor. - obtain ⟨hleaf, hp⟩ := hbig hlarge - have hlog : S ≤ Nat.sqrt (Nat.log 2 x.scale) := Nat.sqrt_log_two_mono hsm - have hMs : x.edges ≤ C * s / S := - calc x.edges ≤ x.scale / Nat.sqrt (Nat.log 2 x.scale) := hleaf - _ ≤ x.scale / S := Nat.div_le_div_left hlog hS1 + obtain ⟨hleaf, hpm⟩ := hbig hlarge + have hlog : S ≤ Nat.sqrt (Nat.log 2 m) := Nat.sqrt_log_two_mono hsm + have hMs : M ≤ C * s / S := + calc M ≤ m / Nat.sqrt (Nat.log 2 m) := hleaf + _ ≤ m / S := Nat.div_le_div_left hlog hS1 _ ≤ C * s / S := Nat.div_le_div_right hmC - have hfac := hK₁ s x.scale x.prec hs hsm hmC hp + have hfac : (A * p + 2) ^ A ≤ 2 ^ (K₁ * s / S) := hK₁ s m p hs hsm hmC hpm have hCK : (C + K₁) * s ≤ K * s := Nat.mul_le_mul_right _ (by omega) have hexp : C * s / S + K₁ * s / S ≤ K * s / S := Nat.div_add_div_le_add_div.trans (Nat.div_le_div_right (by rw [← add_mul]; exact hCK)) - calc (leafCertificate tableEntryCertificate mk).time x - ≤ K₀ * (n + 1) ^ K₀ * 2 ^ x.edges * (A * x.prec + 2) ^ A := hT - _ ≤ K₀ * (n + 1) ^ K₀ * 2 ^ (C * s / S) * 2 ^ (K₁ * s / S) := - Nat.mul_le_mul (Nat.mul_le_mul_left _ (Nat.pow_le_pow_right (by norm_num) hMs)) hfac - _ = K₀ * (n + 1) ^ K₀ * 2 ^ (C * s / S + K₁ * s / S) := by rw [pow_add]; ring - _ ≤ K * (n + 1) ^ K * 2 ^ (K * s / S) := - Nat.mul_le_mul (Nat.mul_le_mul (by omega) hnK) (Nat.pow_le_pow_right (by norm_num) hexp) + have hKn : 1 ≤ K * (n + 1) ^ K := Nat.mul_pos (by omega) (Nat.pos_of_ne_zero (by positivity)) + calc 2 ^ M * (A * p + 2) ^ A ≤ 2 ^ (C * s / S) * 2 ^ (K₁ * s / S) := + Nat.mul_le_mul (Nat.pow_le_pow_right (by norm_num) hMs) hfac + _ = 2 ^ (C * s / S + K₁ * s / S) := by rw [pow_add] + _ ≤ 2 ^ (K * s / S) := Nat.pow_le_pow_right (by norm_num) hexp + _ ≤ K * (n + 1) ^ K * 2 ^ (K * s / S) := Nat.le_mul_of_pos_left _ hKn + +/-- A polynomial factor `K₀ B ^ K₀` absorbed into a leaf bound `K₁ B ^ K₁ 2 ^ (K₁ s / S)`. -/ +private theorem mul_leafBound_le {K₀ K₁ B s S : ℕ} (hB : 1 ≤ B) : + K₀ * B ^ K₀ * (K₁ * B ^ K₁ * 2 ^ (K₁ * s / S)) ≤ + (K₀ * K₁ + K₀ + K₁) * B ^ (K₀ * K₁ + K₀ + K₁) * 2 ^ ((K₀ * K₁ + K₀ + K₁) * s / S) := + calc K₀ * B ^ K₀ * (K₁ * B ^ K₁ * 2 ^ (K₁ * s / S)) + = K₀ * K₁ * B ^ (K₀ + K₁) * 2 ^ (K₁ * s / S) := by rw [pow_add]; ring + _ ≤ _ := Nat.mul_le_mul (Nat.mul_le_mul (Nat.le_add_right _ _ |>.trans (Nat.le_add_right _ _)) + (Nat.pow_le_pow_right hB (by omega))) + (Nat.pow_le_pow_right (by norm_num) (Nat.div_le_div_right + (Nat.mul_le_mul_right _ (by omega)))) + +/-- **The leaf bound of the resource analysis.** For all constants `C`, `c` and `s₀` there is `K` +such that a call with the packet shape, scale `m` with `s ≤ m ≤ C s` and at most `2 m` edges takes +time at most `K (n + 1) ^ K 2 ^ (K s / √⌊log₂ s⌋)` and space at most `K (n + 1) ^ K` at a leaf, +provided that from `s₀` on it has at most `leafSize m` edges and precision at most `m ^ c`: the +cost of a leaf over tables with the packet shape +(`leafCertificate_tableEntry_le_of_packetShape`), with its factor `2 ^ M (A p + 2) ^ A` bounded by +`exists_leafFactor_le`. -/ +theorem exists_leafCertificate_le (C c s₀ : ℕ) : ∃ K : ℕ, + ∀ (mk : Call (List ℕ) → State → ℕ × DescribedNetwork (VertexDesc (List ℕ))) (s : ℕ) + (x : Call (List ℕ)), 2 ≤ s → + s ≤ x.scale → x.scale ≤ C * s → PacketShape x → x.edges ≤ 2 * x.scale → + (s₀ ≤ s → x.edges ≤ leafSize x.scale ∧ x.prec ≤ x.scale ^ c) → + (leafCertificate tableEntryCertificate mk).time x ≤ + K * ((encCall (encList encNat) x).length + 1) ^ K * 2 ^ (K * s / Nat.sqrt (Nat.log 2 s)) ∧ + (leafCertificate tableEntryCertificate mk).space x ≤ + K * ((encCall (encList encNat) x).length + 1) ^ K := by + obtain ⟨K₀, hK₀⟩ := leafCertificate_tableEntry_le_of_packetShape + obtain ⟨K₁, hK₁⟩ := exists_leafFactor_le C c s₀ + refine ⟨K₀ * K₁ + K₀ + K₁, fun mk s x hs hsm hmC hshape hM hbig => ?_⟩ + obtain ⟨hT, hS⟩ := hK₀ mk x hshape + set n := (encCall (encList encNat) x).length with hn + have hB1 : 1 ≤ n + 1 := by omega + have hp : x.prec ≤ n := by have := scale_add_prec_add_length_fl_le (encList encNat) x; omega + have hF := hK₁ s x.scale x.edges x.prec n hs hsm hmC hM hp hbig + refine ⟨hT.trans ?_, hS.trans (Nat.mul_le_mul (by omega) (Nat.pow_le_pow_right hB1 (by omega)))⟩ + rw [Nat.mul_assoc] + exact (Nat.mul_le_mul_left _ hF).trans (mul_leafBound_le hB1) + +/-- **The leaf bound with the costs of the root entries.** For a native certificate `ce` of the +entry procedure and all constants `C`, `c` and `s₀` there is `K` such that a call with the packet +shape, scale `m` with `s ≤ m ≤ C s` and at most `2 m` edges, whose root entries take time at most +`E` and space at most `ES`, takes time at most `K (n + ES + 1) ^ K 2 ^ (K s / √⌊log₂ s⌋) (E + 1)` +and space at most `K (n + ES + 1) ^ K` at a leaf, provided that from `s₀` on it has at most +`leafSize m` edges and precision at most `m ^ c`: the cost of a leaf with the packet shape +(`leafCertificate_le_of_packetShape`), with its factor `2 ^ M (A p + 2) ^ A` bounded as for tables +by `exists_leafFactor_le`. -/ +theorem exists_leafCertificate_le_of_entry + (ce : NativeCertificate (fun q : T × List Bool => ev q.1 q.2) (encPair encT encBits) + (encList encNat)) (C c s₀ : ℕ) : ∃ K : ℕ, + ∀ (mk : Call T → State → ℕ × DescribedNetwork (VertexDesc T)) (s : ℕ) (x : Call T) + (E ES : ℕ), 2 ≤ s → s ≤ x.scale → x.scale ≤ C * s → PacketShape x → + x.edges ≤ 2 * x.scale → (s₀ ≤ s → x.edges ≤ leafSize x.scale ∧ x.prec ≤ x.scale ^ c) → + (∀ v ∈ x.net.vertices, ∀ t, v.2 = .inl t → ∀ bs : List Bool, bs.length = v.1.length → + ce.time (t, bs) ≤ E ∧ ce.space (t, bs) ≤ ES) → + (leafCertificate ce mk).time x ≤ K * ((encCall encT x).length + ES + 1) ^ K * + 2 ^ (K * s / Nat.sqrt (Nat.log 2 s)) * (E + 1) ∧ + (leafCertificate ce mk).space x ≤ K * ((encCall encT x).length + ES + 1) ^ K := by + obtain ⟨K₀, hK₀⟩ := leafCertificate_le_of_packetShape ce + obtain ⟨K₁, hK₁⟩ := exists_leafFactor_le C c s₀ + refine ⟨K₀ * K₁ + K₀ + K₁, fun mk s x E ES hs hsm hmC hshape hM hbig hroot => ?_⟩ + obtain ⟨hT, hS⟩ := hK₀ mk x E ES hshape hroot + set W := (encCall encT x).length + ES + 1 with hW + have hB1 : 1 ≤ W := by omega + have hp : x.prec ≤ (encCall encT x).length + ES := by + have := scale_add_prec_add_length_fl_le encT x; omega + have hF := hK₁ s x.scale x.edges x.prec _ hs hsm hmC hM hp hbig + rw [← hW] at hF + set Pk := (2 ^ (Nat.log 2 x.scale / 32768) * x.prec + 2) ^ 2 ^ (Nat.log 2 x.scale / 32768) + refine ⟨?_, hS.trans (Nat.mul_le_mul (by omega) (Nat.pow_le_pow_right hB1 (by omega)))⟩ + have hPE : Pk + E ≤ Pk * (E + 1) := by + have : 1 ≤ Pk := Nat.one_le_pow _ _ (by omega) + nlinarith + calc _ ≤ K₀ * W ^ K₀ * 2 ^ x.edges * (Pk + E) := hT + _ ≤ K₀ * W ^ K₀ * (2 ^ x.edges * Pk) * (E + 1) := by + rw [Nat.mul_assoc (K₀ * W ^ K₀), Nat.mul_assoc (K₀ * W ^ K₀), Nat.mul_assoc (2 ^ x.edges)] + exact Nat.mul_le_mul_left _ (Nat.mul_le_mul_left _ hPE) + _ ≤ _ := Nat.mul_le_mul_right _ ((Nat.mul_le_mul_left _ hF).trans (mul_leafBound_le hB1)) end FastContraction diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionShape.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionShape.lean index 84b65a919..f0570881c 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionShape.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/FastContractionShape.lean @@ -28,6 +28,10 @@ fields are bounded (`FastContraction.PacketBound`). It passes to the native chil at most `p + 40 m²` since `2 ^ a ≤ m`, and it adds at most `M (2 ^ a) ^ 12 ≤ m²` packet vertices (`NativeChild.numPackets_nativeParentPacking_le`). +**Root descriptors** keep their number of ports along the recursion +(`FastContraction.Reach.exists_root_of_inl`), since the native child renumbers the ports of the +vertices it keeps (`NativeChild.exists_mem_of_mem_nativeChild_inl`). + ## Main definitions * `Cslib.Circuits.Frontier.FastContraction.PacketBound`: the bounded packet descriptors. @@ -38,6 +42,8 @@ at most `p + 40 m²` since `2 ^ a ≤ m`, and it adds at most `M (2 ^ a) ^ 12 * `Cslib.Circuits.Frontier.FastContraction.Shape.child`: the invariant passes to the native children. * `Cslib.Circuits.Frontier.FastContraction.Reach.shape`: every reached call satisfies it. +* `Cslib.Circuits.Frontier.FastContraction.Reach.exists_root_of_inl`: root descriptors keep their + number of ports. ## References @@ -315,4 +321,17 @@ theorem Reach.shape (h₀s : x₀.scale = x₀.edges) (h₀b : x₀.bound + x₀ end Child +/-- **Root descriptors keep their number of ports along the recursion**: every root descriptor of a +call reached by the native child builder is the descriptor of a vertex of the root with as many +ports. -/ +theorem Reach.exists_root_of_inl {x₀ x : Call T} (h : Reach nativeMk x₀ x) + {v : List ℕ × VertexDesc T} (hv : v ∈ x.net.vertices) {t : T} (ht : v.2 = .inl t) : + ∃ w ∈ x₀.net.vertices, w.2 = .inl t ∧ w.1.length = v.1.length := by + induction h generalizing v with + | root => exact ⟨v, hv, ht, rfl⟩ + | step c _ _ _ ih => + obtain ⟨u, hu, hut, hlen⟩ := NativeChild.exists_mem_of_mem_nativeChild_inl hv ht + obtain ⟨w, hw, hwt, hwlen⟩ := ih hu hut + exact ⟨w, hw, hwt, hwlen.trans hlen⟩ + end Cslib.Circuits.Frontier.FastContraction diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/NativeChild.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/NativeChild.lean index ab503a6a6..fa553d228 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/NativeChild.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/NativeChild.lean @@ -69,6 +69,8 @@ vertices as rows (`NativeChild.isRowsFirstBipartite_nativeChild`). * `Cslib.Circuits.Frontier.NativeChild.isRowsFirstBipartite_nativeChild`: it is rows-first. * `Cslib.Circuits.Frontier.NativeChild.desc_of_mem_nativeChild`: its retained and packet descriptors. +* `Cslib.Circuits.Frontier.NativeChild.exists_mem_of_mem_nativeChild_inl`: a retained vertex keeps + its number of ports. ## References @@ -1081,6 +1083,20 @@ theorem desc_of_mem_nativeChild (hD : D.IsRowsFirstBipartite r) {fl : List ℕ} · simp at hl₂ · simp at hl₁ +/-- **A kept vertex of the native child keeps its descriptor and its number of ports**: every root +descriptor of the native child is the descriptor of a parent vertex with as many ports. -/ +theorem exists_mem_of_mem_nativeChild_inl {fl : List ℕ} {a i pt : ℕ} {τ : ℤ} {ζ : List ℕ} + {pk : (List (List ℕ) × List (List ℕ)) × ℕ × List (ℕ × ℕ)} {β : List ℕ} {g : ℕ} + {v : List ℕ × VertexDesc T} (hv : v ∈ (nativeChild fl a i pt τ ζ r D pk β g).vertices) + {t : T} (ht : v.2 = .inl t) : + ∃ u ∈ D.vertices, u.2 = .inl t ∧ u.1.length = v.1.length := by + simp only [nativeChild, List.mem_append, List.mem_map, List.mem_filter, List.mem_range] at hv + rcases hv with ⟨k, ⟨hk, -⟩, rfl⟩ | ⟨q, -, rfl⟩ + · refine ⟨D.vertices[k], List.getElem_mem hk, ?_, ?_⟩ + · simpa only [List.getD_eq_getElem _ _ hk] using ht + · simp only [List.length_map, List.getD_eq_getElem _ _ hk] + · cases ht + end NativeChild end Cslib.Circuits.Frontier diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/RowsFirstPolyTime.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/RowsFirstPolyTime.lean new file mode 100644 index 000000000..785a9fa64 --- /dev/null +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/RowsFirstPolyTime.lean @@ -0,0 +1,136 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Computability.Circuit.Frontier.TensorNetwork.DescribedContraction +import Complexity.Computability.Machines.Turing.MultiTape.Complexity.PolyTime.List +import Complexity.Computability.Machines.Turing.MultiTape.Complexity.PolyTime.Nat +import Complexity.Computability.Machines.Turing.MultiTape.Complexity.PolyTime.Nat.Binary +import Complexity.Computability.Machines.Turing.MultiTape.Internal.EqualityPrimitives +import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimeBinaryPrimitives +import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimeListPrimitives +import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimeNatFrontends +import Complexity.Computability.Machines.Turing.MultiTape.Internal.PolyTimePrimitives + +/-! +# Rows-first bipartiteness in polynomial time + +Rows-first bipartiteness of a described network at a number of rows +(`DescribedNetwork.IsRowsFirstBipartite`) is decidable in polynomial time, from the number of rows +in binary and the network as encoded by `DescribedNetwork.encDescribed`. The test checks that every +port names an edge and counts, for each edge, its ports among the first `r` vertices and among the +others. It is the rows-first part of the guards of the contraction machines, for explicit networks +and for entry procedures. + +## Main results + +* `Cslib.Circuits.Frontier.DescribedNetwork.rowsFirst_polyTime`: rows-first bipartiteness is + decidable in polynomial time. +-/ + +public section + +namespace Cslib.Circuits.Frontier.DescribedNetwork + +open Turing.MultiTapeTM + +variable {T : Type} {encT : T ↪ List Bool} + +/-- Rows-first bipartiteness as a conjunction of list tests. -/ +private def rowsTest (r : ℕ) (d : DescribedNetwork T) : Bool := + d.vertices.all (fun v => v.1.all fun i => decide (i < d.numEdges)) && + (List.range d.numEdges).all (fun i => + decide (((d.vertices.take r).flatMap Prod.fst).count i = 1) && + decide (((d.vertices.drop r).flatMap Prod.fst).count i = 1)) + +private theorem decide_eq_rowsTest (r : ℕ) (d : DescribedNetwork T) : + decide (d.IsRowsFirstBipartite r) = rowsTest r d := by + refine Bool.eq_iff_iff.mpr ?_ + simp only [rowsTest, IsRowsFirstBipartite, decide_eq_true_eq, Bool.and_eq_true, + List.all_eq_true, List.mem_range, List.count_flatMap, Function.comp_def] + +/-- Taking or dropping `min |l| r` elements is taking or dropping `r`. -/ +private theorem take_drop_min {α : Type} (l : List α) (r : ℕ) : + l.take (min l.length r) = l.take r ∧ l.drop (min l.length r) = l.drop r := by + rcases le_total l.length r with hle | hle + · rw [min_eq_left hle, List.take_length, List.take_of_length_le hle, List.drop_length, + List.drop_of_length_le hle] + exact ⟨rfl, rfl⟩ + · rw [min_eq_right hle] + exact ⟨rfl, rfl⟩ + +/-- **Rows-first bipartiteness is decidable in polynomial time**, from the number of rows and the +network. -/ +theorem rowsFirst_polyTime : + ComputableInPolyTime + (fun ((r, d) : ℕ × DescribedNetwork T) => decide (d.IsRowsFirstBipartite r)) + (encPair encNat (encDescribed encT)) encBool := by + have hr := ComputableInPolyTime.fst encNat (encDescribed encT) + have hm : ComputableInPolyTime (fun G : ℕ × DescribedNetwork T => G.2.numEdges) + (encPair encNat (encDescribed encT)) encUnary := + numEdges_polyTime.comp (ComputableInPolyTime.snd _ _) + have hvs : ComputableInPolyTime (fun G : ℕ × DescribedNetwork T => G.2.vertices) + (encPair encNat (encDescribed encT)) (encList (encPair (encList encNat) encT)) := + vertices_polyTime.comp (ComputableInPolyTime.snd _ _) + -- Ports in range. + have h1 : ComputableInPolyTime (fun G : ℕ × DescribedNetwork T => + G.2.vertices.all (fun v => v.1.all fun i => decide (i < G.2.numEdges))) + (encPair encNat (encDescribed encT)) encBool := by + refine ComputableInPolyTime.allWithInput hvs ?_ + refine ComputableInPolyTime.allWithInput + ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _)) ?_ + exact ComputableInPolyTime.binary_lt.comp ((ComputableInPolyTime.snd _ _).prod + (ComputableInPolyTime.unary_to_binary.comp (hm.comp ((ComputableInPolyTime.fst _ _).comp + (ComputableInPolyTime.fst _ _))))) + -- Each edge has one row port and one column port. + have hlen := (ComputableInPolyTime.length_list _).comp hvs + have hcap := ComputableInPolyTime.binary_min_unary' hlen hr + have htake : ComputableInPolyTime (fun G : ℕ × DescribedNetwork T => + G.2.vertices.take (min G.2.vertices.length G.1)) (encPair encNat (encDescribed encT)) + (encList (encPair (encList encNat) encT)) := + .of_tidy (ComputableTidilyInPolyTime.listTakeWithInput hvs.tidy hcap.tidy) + have hdrop : ComputableInPolyTime (fun G : ℕ × DescribedNetwork T => + G.2.vertices.drop (min G.2.vertices.length G.1)) (encPair encNat (encDescribed encT)) + (encList (encPair (encList encNat) encT)) := + .of_tidy (ComputableTidilyInPolyTime.listDropWithInput hvs.tidy hcap.tidy) + have hflat {l : ℕ × DescribedNetwork T → List (List ℕ × T)} + (hl : ComputableInPolyTime l (encPair encNat (encDescribed encT)) + (encList (encPair (encList encNat) encT))) : + ComputableInPolyTime (fun G => (l G).flatMap Prod.fst) (encPair encNat (encDescribed encT)) + (encList encNat) := + ComputableInPolyTime.flatMapWithInput (f := fun _ v => v.1) hl + ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _)) + have hcount {l : ℕ × DescribedNetwork T → List ℕ} + (hl : ComputableInPolyTime l (encPair encNat (encDescribed encT)) (encList encNat)) : + ComputableInPolyTime (fun p : (ℕ × DescribedNetwork T) × ℕ => + decide ((l p.1).count p.2 = 1)) + (encPair (encPair encNat (encDescribed encT)) encUnary) encBool := by + have hc := ComputableInPolyTime.countPWithInput (test := fun p a => decide (a = p.2)) + (hl.comp (ComputableInPolyTime.fst (encPair encNat (encDescribed encT)) encUnary)) + (ComputableInPolyTime.decide_eq' (ComputableInPolyTime.snd _ _) + (ComputableInPolyTime.unary_to_binary.comp ((ComputableInPolyTime.snd _ _).comp + (ComputableInPolyTime.fst _ _)))) + refine (ComputableInPolyTime.decide_eq' hc (ComputableInPolyTime.const 1)).of_enc_eq + fun p => ?_ + simp only [Function.comp_apply, List.count_eq_countP] + congr 3 + have h2 : ComputableInPolyTime (fun G : ℕ × DescribedNetwork T => + (List.range G.2.numEdges).all (fun i => + decide (((G.2.vertices.take (min G.2.vertices.length G.1)).flatMap Prod.fst).count i = + 1) && + decide (((G.2.vertices.drop (min G.2.vertices.length G.1)).flatMap Prod.fst).count i = + 1))) (encPair encNat (encDescribed encT)) encBool := + ComputableInPolyTime.allWithInput (ComputableInPolyTime.range.comp hm) + (ComputableInPolyTime.bool_and.comp ((hcount (hflat htake)).prod (hcount (hflat hdrop)))) + refine (ComputableInPolyTime.bool_and.comp (h1.prod h2)).of_enc_eq fun ⟨r, d⟩ => ?_ + obtain ⟨ht, hdr⟩ := take_drop_min d.vertices r + dsimp only + rw [decide_eq_rowsTest, rowsTest] + simp only [Function.comp_apply, ht, hdr] + +end Cslib.Circuits.Frontier.DescribedNetwork diff --git a/Complexity/Computability/Circuit/Frontier/TensorNetwork/Schedule.lean b/Complexity/Computability/Circuit/Frontier/TensorNetwork/Schedule.lean index 66eafea95..4bde8f16f 100644 --- a/Complexity/Computability/Circuit/Frontier/TensorNetwork/Schedule.lean +++ b/Complexity/Computability/Circuit/Frontier/TensorNetwork/Schedule.lean @@ -32,7 +32,8 @@ p. 64). * Labels have `a_d = 2 ∑_{j ≤ d} u_j` coordinates (`slotBits`), packets `L = 2 ^ a_d` slots, and there are `D_arr = 64 ^ (2 a_d)` pairs of labels (`r = 64`). * The degree bound is `Δ = 2 ^ (⌊9 λ / 10⌋ + 2)` (`degreeBound`), a power of two that is at least - `s ^ (9/10)` (`pow_nine_le_degreeBound_pow_ten`) and at most `2 ^ 20 s ^ 9` in tenth power. + `s ^ (9/10)` (`pow_nine_le_degreeBound_pow_ten`) and at most `2 ^ 20 s ^ 9` in tenth power, + and monotone in `s` (`degreeBound_mono`). * The node `t` of valuation `i` is recovered from its children at precision `p_t = p + 8 h 2 ^ (a - i) + 8 M (a + 1)` (`nodePrecision`), as in Lemma D.5, where `D_t = L / 2 ^ i`. @@ -209,6 +210,10 @@ theorem degreeBound_pow_ten_le {s : ℕ} (hs : s ≠ 0) : degreeBound s ^ 10 ≤ _ = 2 ^ 20 * (2 ^ Nat.log 2 s) ^ 9 := by rw [← pow_mul, ← pow_add]; ring_nf _ ≤ 2 ^ 20 * s ^ 9 := Nat.mul_le_mul_left _ (Nat.pow_le_pow_left h2 9) +/-- **The degree bound is monotone.** -/ +theorem degreeBound_mono {a b : ℕ} (h : a ≤ b) : degreeBound a ≤ degreeBound b := + Nat.pow_le_pow_right (by norm_num) (by have := Nat.log_mono_right (b := 2) h; omega) + /-- **The precision bound** of (D.11), `p ≤ s λ^{O(1)} 2 ^ (a_{d - 1})`: `precisionBound C s d ≤ C s 2 ^ (a_{d - 1}) (1 + d (8 λ + 40))`. -/ theorem precisionBound_le (C s d : ℕ) : diff --git a/Complexity/Computability/Complexity/Classes/CountingSimulation/EntryAnalysis.lean b/Complexity/Computability/Complexity/Classes/CountingSimulation/EntryAnalysis.lean index 0bbf9e5e7..44f0e9c8a 100644 --- a/Complexity/Computability/Complexity/Classes/CountingSimulation/EntryAnalysis.lean +++ b/Complexity/Computability/Complexity/Classes/CountingSimulation/EntryAnalysis.lean @@ -10,7 +10,6 @@ module public import Complexity.Computability.Complexity.Classes.CountingSimulation.FastLeaves public import Complexity.Computability.Circuit.Frontier.TensorNetwork.EntryContractionMachine import Complexity.Computability.Machines.Turing.MultiTape.Encodings.Length -import Mathlib.Data.List.GetD /-! # Theorem D.1 for entry procedures: the resource analysis @@ -41,10 +40,6 @@ entries at a leaf (§D.4.7, p. 64): ## Main results -* `Cslib.Circuits.Frontier.FastContraction.Reach.exists_root_of_inl`: root descriptors keep their - number of ports along the recursion. -* `Cslib.Circuits.Frontier.FastContraction.exists_leafCertificate_le_of_entry`: the leaf bound - with the costs of the root entries. * `Cslib.Complexity.CountingSimulation.entry_length_le_of_reach`: polynomial sizes along the recursion from a guarded input. * `Cslib.Complexity.CountingSimulation.exists_entryLeaves_le`: the leaf bounds on admissible @@ -64,138 +59,6 @@ entries at a leaf (§D.4.7, p. 64): public section -namespace Cslib.Circuits.Frontier - -open Turing.MultiTapeTM Cslib.GenericRAM ChildCursor ContractionSchedule - -variable {T : Type} - -/-! ### Root descriptors along the recursion -/ - -/-- **A kept vertex of the native child keeps its descriptor and its number of ports**: every root -descriptor of the native child is the descriptor of a parent vertex with as many ports. -/ -theorem NativeChild.exists_mem_of_mem_nativeChild_inl {fl : List ℕ} {a i pt : ℕ} {τ : ℤ} - {ζ : List ℕ} {r : ℕ} {D : DescribedNetwork (VertexDesc T)} - {pk : (List (List ℕ) × List (List ℕ)) × ℕ × List (ℕ × ℕ)} {β : List ℕ} {g : ℕ} - {v : List ℕ × VertexDesc T} - (hv : v ∈ (NativeChild.nativeChild fl a i pt τ ζ r D pk β g).vertices) {t : T} - (ht : v.2 = .inl t) : - ∃ u ∈ D.vertices, u.2 = .inl t ∧ u.1.length = v.1.length := by - simp only [NativeChild.nativeChild, List.mem_append, List.mem_map, List.mem_filter, - List.mem_range] at hv - rcases hv with ⟨k, ⟨hk, -⟩, rfl⟩ | ⟨q, -, rfl⟩ - · refine ⟨D.vertices[k], List.getElem_mem hk, ?_, ?_⟩ - · simpa only [List.getD_eq_getElem _ _ hk] using ht - · simp only [List.length_map, List.getD_eq_getElem _ _ hk] - · cases ht - -namespace FastContraction - -/-- **Root descriptors keep their number of ports along the recursion**: every root descriptor of a -call reached by the native child builder is the descriptor of a vertex of the root with as many -ports. -/ -theorem Reach.exists_root_of_inl {x₀ x : Call T} (h : Reach nativeMk x₀ x) - {v : List ℕ × VertexDesc T} (hv : v ∈ x.net.vertices) {t : T} (ht : v.2 = .inl t) : - ∃ w ∈ x₀.net.vertices, w.2 = .inl t ∧ w.1.length = v.1.length := by - induction h generalizing v with - | root => exact ⟨v, hv, ht, rfl⟩ - | step c _ _ _ ih => - obtain ⟨u, hu, hut, hlen⟩ := NativeChild.exists_mem_of_mem_nativeChild_inl hv ht - obtain ⟨w, hw, hwt, hwlen⟩ := ih hu hut - exact ⟨w, hw, hwt, hwlen.trans hlen⟩ - -variable {encT : T ↪ List Bool} {ev : T → List Bool → List ℕ} - -/-- **The leaf bound with the costs of the root entries.** For a native certificate `ce` of the -entry procedure and all constants `C`, `c` and `s₀` there is `K` such that a call with the packet -shape, scale `m` with `s ≤ m ≤ C s` and at most `2 m` edges, whose root entries take time at most -`E` and space at most `ES`, takes time at most `K (n + ES + 1) ^ K 2 ^ (K s / √⌊log₂ s⌋) (E + 1)` -and space at most `K (n + ES + 1) ^ K` at a leaf, provided that from `s₀` on it has at most -`leafSize m` edges and precision at most `m ^ c`. The packet factor and `2 ^ M` are bounded as for -tables (`exists_leafCertificate_le`). -/ -theorem exists_leafCertificate_le_of_entry - (ce : NativeCertificate (fun q : T × List Bool => ev q.1 q.2) (encPair encT encBits) - (encList encNat)) (C c s₀ : ℕ) : ∃ K : ℕ, - ∀ (mk : Call T → State → ℕ × DescribedNetwork (VertexDesc T)) (s : ℕ) (x : Call T) - (E ES : ℕ), 2 ≤ s → s ≤ x.scale → x.scale ≤ C * s → PacketShape x → - x.edges ≤ 2 * x.scale → (s₀ ≤ s → x.edges ≤ leafSize x.scale ∧ x.prec ≤ x.scale ^ c) → - (∀ v ∈ x.net.vertices, ∀ t, v.2 = .inl t → ∀ bs : List Bool, bs.length = v.1.length → - ce.time (t, bs) ≤ E ∧ ce.space (t, bs) ≤ ES) → - (leafCertificate ce mk).time x ≤ K * ((encCall encT x).length + ES + 1) ^ K * - 2 ^ (K * s / Nat.sqrt (Nat.log 2 s)) * (E + 1) ∧ - (leafCertificate ce mk).space x ≤ K * ((encCall encT x).length + ES + 1) ^ K := by - obtain ⟨K₀, hK₀⟩ := leafCertificate_le_of_packetShape ce - obtain ⟨K₁, hK₁⟩ := exists_packetFactor_le C c - obtain ⟨Ks, hKs⟩ : ∃ Ks, Ks = K₀ * 2 ^ (2 * (C * s₀)) * (C * s₀ + 2) ^ (C * s₀) := ⟨_, rfl⟩ - refine ⟨Ks + K₀ + C * s₀ + C + K₁, fun mk s x E ES hs hsm hmC hshape hM hbig hroot => ?_⟩ - obtain ⟨hT, hS⟩ := hK₀ mk x E ES hshape hroot - set W := (encCall encT x).length + ES + 1 with hW - set K := Ks + K₀ + C * s₀ + C + K₁ with hK - set S := Nat.sqrt (Nat.log 2 s) with hSdef - have hS1 : 1 ≤ S := Nat.one_le_sqrt_log_two hs - have hB1 : 1 ≤ W := by omega - have hX1 : 1 ≤ 2 ^ (K * s / S) := Nat.one_le_two_pow - have hnK : W ^ K₀ ≤ W ^ K := Nat.pow_le_pow_right hB1 (by omega) - refine ⟨?_, hS.trans (Nat.mul_le_mul (by omega) hnK)⟩ - set A := 2 ^ (Nat.log 2 x.scale / 32768) with hA - have hAm : A ≤ x.scale := (Nat.pow_le_pow_right (by norm_num) (Nat.div_le_self _ _)).trans - (Nat.pow_log_le_self 2 (by omega)) - set Pk := (A * x.prec + 2) ^ A with hPk - have hPk1 : 1 ≤ Pk := Nat.one_le_pow _ _ (by omega) - have hT' : (leafCertificate ce mk).time x ≤ K₀ * W ^ K₀ * (2 ^ x.edges * Pk) * (E + 1) := by - have hPE : Pk + E ≤ Pk * (E + 1) := by nlinarith - calc _ ≤ K₀ * W ^ K₀ * 2 ^ x.edges * (Pk + E) := hT - _ ≤ K₀ * W ^ K₀ * 2 ^ x.edges * (Pk * (E + 1)) := Nat.mul_le_mul_left _ hPE - _ = _ := by ring - suffices hMP : K₀ * W ^ K₀ * (2 ^ x.edges * Pk) ≤ K * W ^ K * 2 ^ (K * s / S) from - hT'.trans (Nat.mul_le_mul_right _ hMP) - rcases lt_or_ge s s₀ with hsmall | hlarge - · -- Below `s₀`: constants and a polynomial. - have hmC' : x.scale ≤ C * s₀ := hmC.trans (Nat.mul_le_mul_left _ hsmall.le) - have hp : x.prec ≤ W := by have := scale_add_prec_add_length_fl_le encT x; omega - have h2M : 2 ^ x.edges ≤ 2 ^ (2 * (C * s₀)) := - Nat.pow_le_pow_right (by norm_num) (by omega) - have hbase : A * x.prec + 2 ≤ (C * s₀ + 2) * W := by - have : A * x.prec ≤ C * s₀ * W := Nat.mul_le_mul (hAm.trans hmC') hp - nlinarith - have hfac : Pk ≤ (C * s₀ + 2) ^ (C * s₀) * W ^ (C * s₀) := by - calc Pk ≤ ((C * s₀ + 2) * W) ^ A := Nat.pow_le_pow_left hbase _ - _ ≤ ((C * s₀ + 2) * W) ^ (C * s₀) := - Nat.pow_le_pow_right (Nat.one_le_iff_ne_zero.mpr (by positivity)) (hAm.trans hmC') - _ = (C * s₀ + 2) ^ (C * s₀) * W ^ (C * s₀) := mul_pow _ _ _ - calc K₀ * W ^ K₀ * (2 ^ x.edges * Pk) - ≤ K₀ * W ^ K₀ * (2 ^ (2 * (C * s₀)) * ((C * s₀ + 2) ^ (C * s₀) * W ^ (C * s₀))) := - Nat.mul_le_mul_left _ (Nat.mul_le_mul h2M hfac) - _ = Ks * W ^ (K₀ + C * s₀) := by rw [hKs, pow_add]; ring - _ ≤ K * W ^ K := Nat.mul_le_mul (by omega) (Nat.pow_le_pow_right hB1 (by omega)) - _ ≤ K * W ^ K * 2 ^ (K * s / S) := Nat.le_mul_of_pos_right _ hX1 - · -- From `s₀` on: the leaf size and the packet factor. - obtain ⟨hleaf, hp⟩ := hbig hlarge - have hlog : S ≤ Nat.sqrt (Nat.log 2 x.scale) := Nat.sqrt_log_two_mono hsm - have hMs : x.edges ≤ C * s / S := - calc x.edges ≤ x.scale / Nat.sqrt (Nat.log 2 x.scale) := hleaf - _ ≤ x.scale / S := Nat.div_le_div_left hlog hS1 - _ ≤ C * s / S := Nat.div_le_div_right hmC - have hfac : Pk ≤ 2 ^ (K₁ * s / S) := hK₁ s x.scale x.prec hs hsm hmC hp - have hCK : (C + K₁) * s ≤ K * s := Nat.mul_le_mul_right _ (by omega) - have hexp : C * s / S + K₁ * s / S ≤ K * s / S := - Nat.div_add_div_le_add_div.trans (Nat.div_le_div_right (by rw [← add_mul]; exact hCK)) - calc K₀ * W ^ K₀ * (2 ^ x.edges * Pk) - ≤ K₀ * W ^ K₀ * (2 ^ (C * s / S) * 2 ^ (K₁ * s / S)) := - Nat.mul_le_mul_left _ (Nat.mul_le_mul (Nat.pow_le_pow_right (by norm_num) hMs) hfac) - _ = K₀ * W ^ K₀ * 2 ^ (C * s / S + K₁ * s / S) := by rw [pow_add] - _ ≤ K * W ^ K * 2 ^ (K * s / S) := - Nat.mul_le_mul (Nat.mul_le_mul (by omega) hnK) (Nat.pow_le_pow_right (by norm_num) hexp) - -end FastContraction - -/-- **The root call has no packets.** -/ -theorem EntryContraction.packetShape_rootCall (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : - FastContraction.PacketShape (EntryContraction.rootCall x) := - FastContraction.packetShape_of_net_eq_rootNet rfl - -end Cslib.Circuits.Frontier - namespace Cslib.Complexity.CountingSimulation open Cslib.Circuits.Frontier Cslib.Circuits.Frontier.ContractionSchedule @@ -209,10 +72,9 @@ variable {T : Type} {encT : T ↪ List Bool} {entry : T → List Bool → List /-! ### The root -/ /-- The parts of an encoded input `(P, fl, r, G)` against its length. -/ -theorem length_parts_le_encInput (x : ℕ × List ℕ × ℕ × DescribedNetwork T) : - x.1 + x.2.1.length + (encNat x.2.2.1).length + - (DescribedNetwork.encDescribed encT x.2.2.2).length ≤ (encInput encT x).length := by - obtain ⟨P, fl, r, G⟩ := x +theorem length_parts_le_encInput (P : ℕ) (fl : List ℕ) (r : ℕ) (G : DescribedNetwork T) : + P + fl.length + (encNat r).length + (DescribedNetwork.encDescribed encT G).length ≤ + (encInput encT (P, fl, r, G)).length := by have h := length_le_length_encList encNat fl simp only [encInput, length_encPair, encUnary_apply, List.length_replicate] at h ⊢ omega @@ -268,9 +130,8 @@ theorem entry_length_le_of_reach {x : ℕ × List ℕ × ℕ × DescribedNetwork set m := G.numEdges with hm set n := (encInput encT (P, fl, r, G)).length with hn set Y := n + 1 with hY - have hparts := length_parts_le_encInput (encT := encT) (P, fl, r, G) + have hparts := length_parts_le_encInput (encT := encT) P fl r G have hmv := DescribedNetwork.length_numEdges_vertices_le (encT := encT) G - simp only at hparts rw [← hn] at hparts have hfl : fl = modulus m := by simp only [EntryContraction.guard, decide_eq_true_eq] at hg @@ -440,9 +301,8 @@ theorem exists_entryLeaves_le set Y := n + 1 with hY set S := Nat.sqrt (Nat.log 2 s) with hS set L := (DescribedNetwork.encDescribed encT G).length with hL - have hparts := length_parts_le_encInput (encT := encT) (P, modulus G.numEdges, r, G) + have hparts := length_parts_le_encInput (encT := encT) P (modulus G.numEdges) r G have hmv := DescribedNetwork.length_numEdges_vertices_le (encT := encT) G - simp only at hparts rw [← hn] at hparts obtain ⟨hsc, hE2, hbig⟩ := hs₀ s P r G hs hPD hsm hmC hg y hy obtain ⟨-, hshape⟩ := hy.wf_packetShape (wf_rootCall hg) (packetShape_rootCall _) @@ -556,9 +416,8 @@ theorem exists_entryAnalysis set x₀ := rootCall x with hx₀ set m := G.numEdges with hm set n := (encInput encT x).length with hn - have hparts := length_parts_le_encInput (encT := encT) x + have hparts := length_parts_le_encInput (encT := encT) P (modulus G.numEdges) r G have hmv := DescribedNetwork.length_numEdges_vertices_le (encT := encT) G - simp only [hx] at hparts rw [← hx, ← hn] at hparts have hmn : m ≤ n := by omega have hp₀ : P ≤ D * m := hPD.trans (Nat.mul_le_mul_left _ hsm) @@ -825,18 +684,20 @@ theorem exists_fastCore_le · rw [fastCore_time] simp only [hg, ↓reduceIte] have hrest : ((scheme entry nativeMk).run clock rootCall x).elim - ((directCore entry ce).time x) (fun v => - (NativeCertificate.ofPolyTime (valueTag_polyTime (encT := encT))).time (x, v) + - if decide (v.1 = 0) = true then - (NativeCertificate.ofPolyTime (valueList_polyTime (encT := encT))).time (x, v) + ((directCore entry ce).time x) (fun (tag, coeffs) => + (NativeCertificate.ofPolyTime (valueTag_polyTime (encT := encT))).time + (x, (tag, coeffs)) + + if decide (tag = 0) = true then + (NativeCertificate.ofPolyTime (valueList_polyTime (encT := encT))).time + (x, (tag, coeffs)) else (NativeCertificate.ofPolyTime - (ComputableInPolyTime.fst (encInput encT) encValue)).time (x, v) + + (ComputableInPolyTime.fst (encInput encT) encValue)).time (x, (tag, coeffs)) + (directCore entry ce).time x) ≤ R₁ + R₂ := by - rcases hr : (scheme entry nativeMk).run clock rootCall x with _ | v + rcases hr : (scheme entry nativeMk).run clock rootCall x with _ | ⟨tag, coeffs⟩ · by_cases hs₀ : s₀ ≤ s · rw [hbig hs₀] at hr; cases hr · simp only [Option.elim_none]; have := hdir (by omega); omega - · have hd := hdec v (Scheme.value_of_run_eq_some he hr) + · have hd := hdec (tag, coeffs) (Scheme.value_of_run_eq_some he hr) simp only [Option.elim_some] split_ifs with h0 · omega @@ -853,16 +714,18 @@ theorem exists_fastCore_le · rw [fastCore_space] simp only [hg, ↓reduceIte] have hrest : ((scheme entry nativeMk).run clock rootCall x).elim - ((directCore entry ce).space x) (fun v => - (NativeCertificate.ofPolyTime (valueTag_polyTime (encT := encT))).space (x, v) + - if decide (v.1 = 0) = true then - (NativeCertificate.ofPolyTime (valueList_polyTime (encT := encT))).space (x, v) + ((directCore entry ce).space x) (fun (tag, coeffs) => + (NativeCertificate.ofPolyTime (valueTag_polyTime (encT := encT))).space + (x, (tag, coeffs)) + + if decide (tag = 0) = true then + (NativeCertificate.ofPolyTime (valueList_polyTime (encT := encT))).space + (x, (tag, coeffs)) else (NativeCertificate.ofPolyTime - (ComputableInPolyTime.fst (encInput encT) encValue)).space (x, v) + + (ComputableInPolyTime.fst (encInput encT) encValue)).space (x, (tag, coeffs)) + (directCore entry ce).space x) ≤ R₁ + R₂ := by - rcases hr : (scheme entry nativeMk).run clock rootCall x with _ | v + rcases hr : (scheme entry nativeMk).run clock rootCall x with _ | ⟨tag, coeffs⟩ · simp only [Option.elim_none]; omega - · have hd := hdec v (Scheme.value_of_run_eq_some he hr) + · have hd := hdec (tag, coeffs) (Scheme.value_of_run_eq_some he hr) simp only [Option.elim_some] split_ifs <;> omega have htot := space_assemble (gS := (NativeCertificate.ofPolyTime diff --git a/Complexity/Computability/Complexity/Classes/CountingSimulation/FastAlgorithm.lean b/Complexity/Computability/Complexity/Classes/CountingSimulation/FastAlgorithm.lean index 0348e3bde..229fd0594 100644 --- a/Complexity/Computability/Complexity/Classes/CountingSimulation/FastAlgorithm.lean +++ b/Complexity/Computability/Complexity/Classes/CountingSimulation/FastAlgorithm.lean @@ -12,6 +12,7 @@ public import Complexity.Computability.Complexity.Classes.CountingSimulation.Adm public import Complexity.Computability.Circuit.Frontier.TensorNetwork.FastContractionMachine public import Complexity.Computability.Circuit.Frontier.TensorNetwork.FastContractionStep public import Complexity.Computability.Circuit.Frontier.TensorNetwork.FastContractionPolyTime +import Complexity.Computability.Circuit.Frontier.TensorNetwork.RowsFirstPolyTime import Mathlib.Analysis.SpecificLimits.Normed import Complexity.Computability.Machines.Turing.MultiTape.Complexity.PolyTime.List import Complexity.Computability.Machines.Turing.MultiTape.Complexity.PolyTime.Nat @@ -50,7 +51,8 @@ interface's bounds (`CountingSimulation.fastCertificate_le`), through `Cslib.GenericRAM.StackRecursion.Scheme.certificate_le`. Below the size threshold the run may not finish, and the machine falls back to direct summation, at a constant factor. -The guard is polynomial-time (`CountingSimulation.fastGuard_polyTime`). +The guard is polynomial-time (`CountingSimulation.fastGuard_polyTime`), with the rows-first test +`DescribedNetwork.rowsFirst_polyTime`. For the native child builder (`FastContraction.nativeMk`), the components of the scheme are polynomial-time (`FastContraction.scheme_nativeMk_polyTime`), and the step, the passage of @@ -151,87 +153,21 @@ open Turing.MultiTapeTM /-- The encoding of an explicit network with its number of rows. -/ local notation "encG" => encPair encNat ExplicitTensorNetwork.encExplicitNetwork -/-- The guard as a conjunction of list tests. -/ -private def guardTest (G : ℕ × ExplicitTensorNetwork ℕ) : Bool := - G.2.vertices.all (fun v => v.1.all fun i => decide (i < G.2.numEdges)) && - (List.range G.2.numEdges).all (fun i => - decide (((G.2.vertices.take G.1).flatMap Prod.fst).count i = 1) && - decide (((G.2.vertices.drop G.1).flatMap Prod.fst).count i = 1)) && - G.2.vertices.all (fun v => decide (v.2.length = 2 ^ v.1.length)) && - G.2.vertices.all (fun v => decide (v.1.length ≤ degreeBound G.2.numEdges)) - -private theorem fastGuard_eq_guardTest (G : ℕ × ExplicitTensorNetwork ℕ) : - fastGuard G = guardTest G := by - refine Bool.eq_iff_iff.mpr ?_ - simp only [fastGuard, guardTest, DescribedNetwork.IsRowsFirstBipartite, - ExplicitTensorNetwork.maxDegree_le_iff, decide_eq_true_eq, Bool.and_eq_true, - List.all_eq_true, List.mem_range, List.count_flatMap, Function.comp_def] - constructor - · rintro ⟨⟨h1, h2⟩, h3, h4⟩ - exact ⟨⟨⟨fun v hv i hi => h1 v hv i hi, fun i hi => h2 i hi⟩, h3⟩, h4⟩ - · rintro ⟨⟨⟨h1, h2⟩, h3⟩, h4⟩ - exact ⟨⟨fun v hv i hi => h1 v hv i hi, fun i hi => h2 i hi⟩, h3, h4⟩ - -/-- **The guard is polynomial-time.** -/ +/-- **The guard is polynomial-time**: the rows-first test (`DescribedNetwork.rowsFirst_polyTime`), +the lengths of the tables and the degrees of the vertices. -/ theorem fastGuard_polyTime : ComputableInPolyTime fastGuard encG encBool := by - have hpair : ComputableInPolyTime (DescribedNetwork.equivProd (T := List ℕ)) - ExplicitTensorNetwork.encExplicitNetwork - (encPair encUnary (encList (encPair (encList encNat) (encList encNat)))) := - ComputableInPolyTime.of_eq fun _ => rfl have hd := ComputableInPolyTime.snd encNat ExplicitTensorNetwork.encExplicitNetwork - have hr := ComputableInPolyTime.fst encNat ExplicitTensorNetwork.encExplicitNetwork have hm : ComputableInPolyTime (fun G : ℕ × ExplicitTensorNetwork ℕ => G.2.numEdges) encG - encUnary := (ComputableInPolyTime.fst _ _).comp (hpair.comp hd) + encUnary := DescribedNetwork.numEdges_polyTime.comp hd have hvs : ComputableInPolyTime (fun G : ℕ × ExplicitTensorNetwork ℕ => G.2.vertices) encG (encList (encPair (encList encNat) (encList encNat))) := - (ComputableInPolyTime.snd _ _).comp (hpair.comp hd) - -- Ports in range. - have h1 : ComputableInPolyTime (fun G : ℕ × ExplicitTensorNetwork ℕ => - G.2.vertices.all (fun v => v.1.all fun i => decide (i < G.2.numEdges))) encG encBool := by - refine ComputableInPolyTime.allWithInput hvs ?_ - refine ComputableInPolyTime.allWithInput - ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _)) ?_ - exact ComputableInPolyTime.binary_lt.comp ((ComputableInPolyTime.snd _ _).prod - (ComputableInPolyTime.unary_to_binary.comp (hm.comp ((ComputableInPolyTime.fst _ _).comp - (ComputableInPolyTime.fst _ _))))) - -- Each edge has one row port and one column port. - have hlen := (ComputableInPolyTime.length_list _).comp hvs - have hcap := ComputableInPolyTime.binary_min_unary' hlen hr - have htake : ComputableInPolyTime (fun G : ℕ × ExplicitTensorNetwork ℕ => - G.2.vertices.take (min G.2.vertices.length G.1)) encG - (encList (encPair (encList encNat) (encList encNat))) := - .of_tidy (ComputableTidilyInPolyTime.listTakeWithInput hvs.tidy hcap.tidy) - have hdrop : ComputableInPolyTime (fun G : ℕ × ExplicitTensorNetwork ℕ => - G.2.vertices.drop (min G.2.vertices.length G.1)) encG - (encList (encPair (encList encNat) (encList encNat))) := - .of_tidy (ComputableTidilyInPolyTime.listDropWithInput hvs.tidy hcap.tidy) - have hflat {l : ℕ × ExplicitTensorNetwork ℕ → List (List ℕ × List ℕ)} - (hl : ComputableInPolyTime l encG (encList (encPair (encList encNat) (encList encNat)))) : - ComputableInPolyTime (fun G => (l G).flatMap Prod.fst) encG (encList encNat) := - ComputableInPolyTime.flatMapWithInput (f := fun _ v => v.1) hl - ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _)) - have hcount {l : ℕ × ExplicitTensorNetwork ℕ → List ℕ} - (hl : ComputableInPolyTime l encG (encList encNat)) : - ComputableInPolyTime (fun p : (ℕ × ExplicitTensorNetwork ℕ) × ℕ => - decide ((l p.1).count p.2 = 1)) (encPair encG encUnary) encBool := by - have hc := ComputableInPolyTime.countPWithInput (test := fun p a => decide (a = p.2)) - (hl.comp (ComputableInPolyTime.fst encG encUnary)) - (ComputableInPolyTime.decide_eq' (ComputableInPolyTime.snd _ _) - (ComputableInPolyTime.unary_to_binary.comp ((ComputableInPolyTime.snd _ _).comp - (ComputableInPolyTime.fst _ _)))) - refine (ComputableInPolyTime.decide_eq' hc (ComputableInPolyTime.const 1)).of_enc_eq - fun p => ?_ - simp only [Function.comp_apply, List.count_eq_countP] - congr 3 - have h2 : ComputableInPolyTime (fun G : ℕ × ExplicitTensorNetwork ℕ => - (List.range G.2.numEdges).all (fun i => - decide (((G.2.vertices.take (min G.2.vertices.length G.1)).flatMap Prod.fst).count i = 1) && - decide (((G.2.vertices.drop (min G.2.vertices.length G.1)).flatMap Prod.fst).count i = - 1))) encG encBool := - ComputableInPolyTime.allWithInput (ComputableInPolyTime.range.comp hm) - (ComputableInPolyTime.bool_and.comp ((hcount (hflat htake)).prod (hcount (hflat hdrop)))) + DescribedNetwork.vertices_polyTime.comp hd + -- Rows first. + have hrows : ComputableInPolyTime (fun G : ℕ × ExplicitTensorNetwork ℕ => + decide (G.2.IsRowsFirstBipartite G.1)) encG encBool := + DescribedNetwork.rowsFirst_polyTime -- Full tables. - have h3 : ComputableInPolyTime (fun G : ℕ × ExplicitTensorNetwork ℕ => + have htab : ComputableInPolyTime (fun G : ℕ × ExplicitTensorNetwork ℕ => G.2.vertices.all (fun v => decide (v.2.length = 2 ^ v.1.length))) encG encBool := by refine ComputableInPolyTime.allWithInput hvs ?_ have hv := ComputableInPolyTime.snd encG (encPair (encList encNat) (encList encNat)) @@ -241,7 +177,7 @@ theorem fastGuard_polyTime : ComputableInPolyTime fastGuard encG encBool := by (ComputableInPolyTime.binary_two_pow.comp ((ComputableInPolyTime.length_list _).comp ((ComputableInPolyTime.fst _ _).comp hv))) -- The degree bound. - have h4 : ComputableInPolyTime (fun G : ℕ × ExplicitTensorNetwork ℕ => + have hdeg : ComputableInPolyTime (fun G : ℕ × ExplicitTensorNetwork ℕ => G.2.vertices.all (fun v => decide (v.1.length ≤ degreeBound G.2.numEdges))) encG encBool := by refine ComputableInPolyTime.allWithInput hvs ?_ @@ -249,18 +185,10 @@ theorem fastGuard_polyTime : ComputableInPolyTime fastGuard encG encBool := by (ComputableInPolyTime.unary_to_binary.comp ((ComputableInPolyTime.length_list _).comp ((ComputableInPolyTime.fst _ _).comp (ComputableInPolyTime.snd _ _)))) (degreeBound_polyTime.comp (hm.comp (ComputableInPolyTime.fst _ _))) - refine (ComputableInPolyTime.bool_and.comp ((ComputableInPolyTime.bool_and.comp - ((ComputableInPolyTime.bool_and.comp (h1.prod h2)).prod h3)).prod h4)).of_enc_eq fun G => ?_ - have ht : G.2.vertices.take (min G.2.vertices.length G.1) = G.2.vertices.take G.1 := by - rcases le_total G.2.vertices.length G.1 with hle | hle - · rw [min_eq_left hle, List.take_length, List.take_of_length_le hle] - · rw [min_eq_right hle] - have hdr : G.2.vertices.drop (min G.2.vertices.length G.1) = G.2.vertices.drop G.1 := by - rcases le_total G.2.vertices.length G.1 with hle | hle - · rw [min_eq_left hle, List.drop_length, List.drop_of_length_le hle] - · rw [min_eq_right hle] - rw [fastGuard_eq_guardTest, guardTest] - simp only [Function.comp_apply, ht, hdr] + refine (ComputableInPolyTime.bool_and.comp (hrows.prod (ComputableInPolyTime.bool_and.comp + (htab.prod hdeg)))).of_enc_eq fun G => ?_ + simp only [fastGuard, ExplicitTensorNetwork.maxDegree_le_iff, Function.comp_apply, + Bool.decide_and, List.all_eq, decide_eq_true_eq] end GuardPolyTime