From 9a2232e1aad48ba263b2f4e80533ff4b5b732692 Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 10:28:15 -0400 Subject: [PATCH 1/4] 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 bb3b4b2d16..985186911a 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 62bfd5130d..d998f60fce 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 aab15a930b..71713d2ae0 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 7d1f9b0e8d..fdf5776317 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 5a9865f610..46dd54e3ec 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 922fff07f2..0f1c099277 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 4d83637e21..a96d7467ee 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 2cf1e3f191..388e67f5eb 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 76f982e9f8..84b65a919b 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 0fd1f563a8..a4800c8085 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 657277b1a1..bc37a2e7a0 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 82af1b001c..cbaf7c2e04 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 2d0a6a4ae9..ab503a6a60 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 57b93e560b..68e0736498 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 a58650892b..1ca5f3cfd3 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 f614aa598e..7280a75770 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 3fff52005a..4f620b30fd 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 e652204be5..483fcbb679 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 9e69bf87bf..ff5135680d 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 805a16171d..447d802167 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 1431e819e9..deb70c0523 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 5a4e66be69..3c9ba93ca9 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 e3be365541..e84885bb7d 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 29eb99127e..10ad24c521 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 5a2370278f..dea272a33a 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 2b8c3ca973..b266ee1029 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 2e205e997d..e241e2c014 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 2/4] 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 46dd54e3ec..85f43339ca 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 0f1c099277..5ab35e0d38 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 4f620b30fd..ebc387ad27 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 483fcbb679..0348e3bded 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 ff5135680d..977c111927 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 e84885bb7d..1d6bac0503 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 3/4] 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 85f43339ca..4fba5a66f5 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 e7499606f7a99ceb5f366642e69be58bf4f249f0 Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Sat, 31 Oct 2026 12:04:48 -0400 Subject: [PATCH 4/4] 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 ebc387ad27..0abab83ad8 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)