Documentation

LeanMlir.Proofs.Architectures.Attention

Attention — the Capstone #

The fanciest architectural primitive in modern vision and language models, formalized in one file. If you're reading the book straight through, this is the chapter where everything you've learned clicks together and you realize there's nothing left to learn.

The cast of characters #

Scaled dot-product attention:

out = softmax((Q * K^T) / sqrt(d)) * V

where Q = X Wq, K = X Wk, V = X Wv — three dense projections of the same input X. Every piece is something we already have:

PieceChapterVJP move
Q = X WqMLP.leandense backward
K = X WkMLP.leandense backward
V = X WvMLP.leandense backward
Q * K^T(matmul = dense)chain rule
/ sqrt(d)(scalar)chain rule + scale
softmax(...)Softmax.leanclosed-form collapse
... * V(matmul = dense)chain rule
three-way fan-in at XResidual.leanbiPathHasVJP

So the only genuinely new ingredient in attention is the standalone softmax VJP (softmaxHasVJP, separate from the CE-loss gradient). Once that's in hand, everything else is composition via tools we built in earlier chapters.

Structure of this file #

  1. The multi-head matrix kit — column-slab independence (pdivMat_colIndep, colSlabwiseHasVJPMat) and the ternary matrix VJP HasVJPMat3; then the differentiability helpers.
  2. The standalone softmax VJP is in Softmax.lean (imported here).
  3. Scaled dot-product attention — SDPA as a composition.
  4. Multi-head wrapper — reshape/transpose boilerplate, no new math.
  5. Transformer block — LN -> MHSA -> + -> LN -> MLP -> +, pure composition.
  6. Final commentary — why the taxonomy is complete.
  7. Bridging ranks — patch embedding, classifier head, and the weight-tied whole-ViT witness vitFullHasVJP (vitFullHasVJP_correct).

References #

Per-head / per-slab column independence #

Multi-head attention applies the same per-head function to each of heads column slabs of width d_in from a Mat n (heads * d_in) input. The column-slab analog of rowwiseHasVJPMat factors that vmap-over-heads structure: each head's output depends only on its own slab of the input, so the matrix Jacobian is block-diagonal across the head axis. The general form lets each slab have its own map (colSlabApplyH); the shared-map colSlabApply is its constant-family case.

noncomputable def Proofs.colSlabApplyH {n heads d_in d_out : ℕ} (g : Fin heads → Mat n d_in → Mat n d_out) :
Mat n (heads * d_in) → Mat n (heads * d_out)

colSlabApply with its own map on each head's slab: output column (h, j) is column j of g h applied to input slab h. The attention core in one of Q, K, V is one, since head h reads the other two projections' slab h.

Equations
  • One or more equations did not get rendered due to their size.
Instances For
    theorem Proofs.pdivMat_colIndepH {n heads d_in d_out : ℕ} (g : Fin heads → Mat n d_in → Mat n d_out) (h_g_diff : ∀ (h : Fin heads), Differentiable ℝ fun (v : Vec (n * d_in)) => (g h (Mat.unflatten v)).flatten) (A : Mat n (heads * d_in)) (i : Fin n) (h_j : Fin heads) (j' : Fin d_in) (k : Fin n) (h_l : Fin heads) (j'' : Fin d_out) :
    pdivMat (colSlabApplyH g) A i (finProdFinEquiv (h_j, j')) k (finProdFinEquiv (h_l, j'')) = if h_j = h_l then pdivMat (g h_l) (fun (r' : Fin n) (j_in : Fin d_in) => A r' (finProdFinEquiv (h_l, j_in))) i j' k j'' else 0

    The Jacobian stays block-diagonal across heads — pdivMat_colIndep with a per-slab map: zero unless the input and output slabs agree, and g h's own Jacobian on slab h if they do.

    noncomputable def Proofs.colSlabApply {n heads d_in d_out : ℕ} (g : Mat n d_in → Mat n d_out) :
    Mat n (heads * d_in) → Mat n (heads * d_out)

    Apply g : Mat n d_in → Mat n d_out to each of the heads column slabs of width d_in in a Mat n (heads * d_in) input, producing a Mat n (heads * d_out) output. Output column (h, j_out) is column j_out of g (slab h M), where slab h M extracts the d_in-wide column block at head index h. Definitionally colSlabApplyH (fun _ => g).

    Equations
    Instances For
      theorem Proofs.pdivMat_colIndep {n heads d_in d_out : ℕ} (g : Mat n d_in → Mat n d_out) (h_g_diff : Differentiable ℝ fun (v : Vec (n * d_in)) => (g (Mat.unflatten v)).flatten) (A : Mat n (heads * d_in)) (i : Fin n) (h_j : Fin heads) (j' : Fin d_in) (k : Fin n) (h_l : Fin heads) (j'' : Fin d_out) :
      pdivMat (colSlabApply g) A i (finProdFinEquiv (h_j, j')) k (finProdFinEquiv (h_l, j'')) = if h_j = h_l then pdivMat g (fun (r' : Fin n) (j_in : Fin d_in) => A r' (finProdFinEquiv (h_l, j_in))) i j' k j'' else 0

      Column-slab independence Jacobian — column-axis analog of pdivMat_rowIndep. For a slab-applied function colSlabApply g, the Jacobian is block-diagonal across the heads axis: zero unless the input slab h_j matches the output slab h_l, otherwise equal to pdivMat g on that slab.

      Requires Differentiable ℝ (flat g) for the same reason as pdivMat_rowIndep: the Pi-valued flat form must be differentiable everywhere so fderiv doesn't fall back to junk-default 0. The constant-family case of pdivMat_colIndepH.

      noncomputable def Proofs.colSlabwiseHasVJPMatH {n heads d_in d_out : ℕ} {g : Fin heads → Mat n d_in → Mat n d_out} (hg : (h : Fin heads) → HasVJPMat (g h)) (hg_diff : ∀ (h : Fin heads), Differentiable ℝ fun (v : Vec (n * d_in)) => (g h (Mat.unflatten v)).flatten) :

      Lift per-slab VJPs to colSlabApplyH — colSlabwiseHasVJPMat with a per-slab map: the backward runs slab h's own backward on slab h.

      Equations
      • One or more equations did not get rendered due to their size.
      Instances For
        noncomputable def Proofs.colSlabwiseHasVJPMat {n heads d_in d_out : ℕ} {g : Mat n d_in → Mat n d_out} (hg : HasVJPMat g) (hg_diff : Differentiable ℝ fun (v : Vec (n * d_in)) => (g (Mat.unflatten v)).flatten) :

        Lift HasVJPMat g to column-slab vmap — column-axis analog of rowwiseHasVJPMat. Given g : Mat n d_in → Mat n d_out with a matrix VJP, applying g independently to each of heads-many column slabs gives a HasVJPMat for colSlabApply g. The backward applies g.backward per slab; its correctness is colSlabwiseHasVJPMatH's at a constant family.

        Equations
        • One or more equations did not get rendered due to their size.
        Instances For

          Ternary matrix VJP #

          For ternary-input functions like SDPA (Q, K, V) ↦ out, package the three per-input VJPs as a single structure analogous to HasVJPMat. The backward returns the triple of per-input gradients; correctness holds independently for each input (with the others fixed).

          structure Proofs.HasVJPMat3 {n d_in d_out : ℕ} (F : Mat n d_in → Mat n d_in → Mat n d_in → Mat n d_out) :

          VJP structure for Mat × Mat × Mat → Mat functions where all three inputs share the same shape Mat n d_in and the output is Mat n d_out. Backward returns the triple of per-input gradients; correct_{1,2,3} ensure each gradient matches the partial derivative treating the other two inputs as constants.

          • backward : Mat n d_in → Mat n d_in → Mat n d_in → Mat n d_out → Mat n d_in × Mat n d_in × Mat n d_in
          • correct_1 (A B C : Mat n d_in) (dY : Mat n d_out) (i : Fin n) (j : Fin d_in) : (self.backward A B C dY).1 i j = ∑ k : Fin n, ∑ l : Fin d_out, pdivMat (fun (A' : Mat n d_in) => F A' B C) A i j k l * dY k l
          • correct_2 (A B C : Mat n d_in) (dY : Mat n d_out) (i : Fin n) (j : Fin d_in) : (self.backward A B C dY).2.1 i j = ∑ k : Fin n, ∑ l : Fin d_out, pdivMat (fun (B' : Mat n d_in) => F A B' C) B i j k l * dY k l
          • correct_3 (A B C : Mat n d_in) (dY : Mat n d_out) (i : Fin n) (j : Fin d_in) : (self.backward A B C dY).2.2 i j = ∑ k : Fin n, ∑ l : Fin d_out, pdivMat (fun (C' : Mat n d_in) => F A B C') C i j k l * dY k l
          Instances For
            theorem Proofs.HasVJPMat3.ext_iff {n d_in d_out : ℕ} {F : Mat n d_in → Mat n d_in → Mat n d_in → Mat n d_out} {x y : HasVJPMat3 F} :
            theorem Proofs.HasVJPMat3.ext {n d_in d_out : ℕ} {F : Mat n d_in → Mat n d_in → Mat n d_in → Mat n d_out} {x y : HasVJPMat3 F} (backward : x.backward = y.backward) :
            x = y
            instance Proofs.instSubsingletonHasVJPMat3 {n d_in d_out : ℕ} {F : Mat n d_in → Mat n d_in → Mat n d_in → Mat n d_out} :

            A ternary matrix map has at most one VJP witness: each component of backward is pinned by its correct_i.

            noncomputable def Proofs.HasVJPMat3.canonical {n d_in d_out : ℕ} (F : Mat n d_in → Mat n d_in → Mat n d_in → Mat n d_out) :

            The canonical ternary witness: each component of the backward is its pdivMat contraction.

            Equations
            • One or more equations did not get rendered due to their size.
            Instances For
              theorem Proofs.scalarScale_flat_differentiable {m n : ℕ} (s : ℝ) :
              Differentiable ℝ fun (v : Vec (m * n)) => Mat.flatten fun (r : Fin m) (c : Fin n) => s * Mat.unflatten v r c
              theorem Proofs.dense_per_token_flat_differentiable {N inD outD : ℕ} (W : Mat inD outD) (b : Vec outD) :
              Differentiable ℝ fun (v : Vec (N * inD)) => Mat.flatten ((fun (X : Mat N inD) (n : Fin N) => dense W b (X n)) (Mat.unflatten v))

              Differentiability of the flattened per-token dense map. fun X => fun n => dense W b (X n) is linear in X, so the flattened version is Differentiable everywhere.

              theorem Proofs.rowDense_weight_differentiable {tk a c : ℕ} (b : Vec c) (x : Vec (tk * a)) :
              Differentiable ℝ fun (θ : Vec (a * c)) => Mat.flatten fun (r : Fin tk) => dense (Mat.unflatten θ) b (Mat.unflatten x r)

              The per-token dense is differentiable in its weight, flattened (input fixed).

              theorem Proofs.rowDense_bias_differentiable {tk a c : ℕ} (W : Mat a c) (x : Vec (tk * a)) :
              Differentiable ℝ fun (θ : Vec c) => Mat.flatten fun (r : Fin tk) => dense W θ (Mat.unflatten x r)

              …in its bias.

              theorem Proofs.gelu_per_token_flat_differentiable {gf : GeluForm} (N D : ℕ) :
              Differentiable ℝ fun (v : Vec (N * D)) => Mat.flatten ((fun (X : Mat N D) (n : Fin N) => gf.map D (X n)) (Mat.unflatten v))

              Differentiability of the flattened per-token GELU map, at either form of the GELU. GeluForm.scalar_differentiable is tagged for fun_prop, so the proof discharges automatically.

              theorem Proofs.layerNorm_differentiable (D : ℕ) (ε γ β : ℝ) (hε : 0 < ε) :

              Differentiability of layerNormForward D ε γ β — it is bnForward (definitionally), differentiable when ε > 0. Tagged for fun_prop.

              theorem Proofs.layerNorm_per_token_flat_differentiable (N D : ℕ) (ε γ β : ℝ) (hε : 0 < ε) :
              Differentiable ℝ fun (v : Vec (N * D)) => Mat.flatten ((fun (X : Mat N D) (n : Fin N) => layerNormForward D ε γ β (X n)) (Mat.unflatten v))

              Differentiability of the flattened per-token LayerNorm map: each output coordinate is a coordinate of layerNormForward (layerNorm_differentiable) applied to one row of the input.

              theorem Proofs.identity_mat_flat_differentiable (a b : ℕ) :
              Differentiable ℝ fun (v : Vec (a * b)) => ((fun (X : Mat a b) => X) (Mat.unflatten v)).flatten

              Differentiability of the flattened identity matrix map. Mat.flatten ∘ id ∘ Mat.unflatten = id on Vec (a*b).

              theorem Proofs.flat_differentiable_comp {a b c d e f : ℕ} {F : Mat a b → Mat c d} {G : Mat c d → Mat e f} (hF : Differentiable ℝ fun (v : Vec (a * b)) => (F (Mat.unflatten v)).flatten) (hG : Differentiable ℝ fun (u : Vec (c * d)) => (G (Mat.unflatten u)).flatten) :
              Differentiable ℝ fun (v : Vec (a * b)) => ((G ∘ F) (Mat.unflatten v)).flatten

              Differentiability of a flattened composition G ∘ F from those of F and G: the Mat.unflatten (Mat.flatten _) round trip in the middle is the identity.

              Attention as a composition #

              For a single sequence of n tokens, each with feature dim d, let X : Mat n d be the input. Attention produces out : Mat n d via:

              Q = X * Wq        -- (n x d), dense projection
              K = X * Wk        -- (n x d)
              V = X * Wv        -- (n x d)
              scores = Q * K^T   -- (n x n)
              scaled = scores / sqrt(d)
              weights = softmax_row(scaled)   -- softmax applied per row
              out = weights * V               -- (n x d)
              

              Because the input X is a matrix, we need matrix-level types. We work with Mat n d throughout this section (already defined in Tensor.lean).

              Row-wise softmax is just "apply the 1D softmax to each row independently." Its VJP is just "apply the 1D softmax VJP to each row independently." No new derivation; the fan-out structure is trivially parallel.

              noncomputable def Proofs.rowSoftmax {m n : ℕ} (A : Mat m n) :
              Mat m n

              Row-wise softmax of a matrix.

              Equations
              Instances For

                Smoothness of rowSoftmax: each output coordinate of the flattened map is a coordinate of softmax n (softmax_differentiable) applied to one row of the input.

                noncomputable def Proofs.rowSoftmaxHasVJPMat {m n : ℕ} :
                HasVJPMat fun (A : Mat m n) (r : Fin m) => softmax n (A r)

                Row-wise softmax VJP — proved, no sorry.

                Rows are independent, so the Jacobian is block-diagonal with the standalone softmax Jacobian in each block. The backward just applies softmaxHasVJP per row; correctness is rowwiseHasVJPMat's.

                Equations
                Instances For

                  Alias so rowSoftmaxHasVJPMat types against the actual rowSoftmax definition (definitionally equal, but lets Lean unify on the name).

                  Equations
                  Instances For
                    noncomputable def Proofs.sdpa (n d : ℕ) (Q K V : Mat n d) :
                    Mat n d

                    Scaled dot-product attention, for a single sequence and a single head. Q K V : Mat n d.

                    sdpa Q K V = softmax_row(Q * K^T / sqrt(d)) * V

                    MLIR (MlirCodegen.emitMHSAForward): %mh_sc = dot_general %mh_q, %mh_k, contracting_dims = [3] x [3] %mh_ss = multiply %mh_sc, broadcast(1/sqrt(d)) %mh_sm = softmax(%mh_ss) -- via reduce max, shift, exp, reduce sum, divide %mh_av = dot_general %mh_sm, %mh_v, contracting_dims = [3] x [2]

                    Equations
                    Instances For

                      The backward pass through SDPA (by hand, then compositionally) #

                      Working backward from d_out : Mat n d, four steps:

                      Step 1. Through the final matmul out = weights * V. By the dense layer VJP generalized to matrices (same derivation as denseHasVJP, just with a batch dimension):

                      d_V       = weights^T * d_out     -- (n x d)
                      d_weights = d_out * V^T           -- (n x n)
                      

                      Step 2. Through the per-row softmax. Each row is independent, so we apply softmaxHasVJP row-by-row:

                      d_scaled_i = weights_i * (d_weights_i - <weights_i, d_weights_i> * 1)
                      

                      Step 3. Through the scalar scale scaled = scores / sqrt(d). Just divide the incoming gradient by sqrt(d):

                      d_scores = d_scaled / sqrt(d)
                      

                      Step 4. Through scores = Q * K^T. Same matrix-matmul VJP as step 1, but now Q and K both flow back:

                      d_Q = d_scores * K                       -- (n x d)
                      d_K = d_scores^T * Q                     -- (n x d)
                      

                      Step 5. Three parallel dense backwards from Q, K, V back to X. Each uses denseHasVJP:

                      d_X_via_Q = d_Q * Wq^T
                      d_X_via_K = d_K * Wk^T
                      d_X_via_V = d_V * Wv^T
                      

                      Step 6. Fan-in at X — the three paths add:

                      d_X = d_X_via_Q + d_X_via_K + d_X_via_V
                      

                      This is biPathHasVJP from Residual.lean, applied twice (to combine three paths). The three-way fan-in is the attention backward pass at the input. Q, K, V are parallel branches reading from X, so their gradients accumulate at X.

                      And the parameter gradients (for W_q, W_k, W_v, W_o) are collected at each dense layer along the way — exactly as with any other dense layer in the book.

                      There is no novel structural move in attention. It's three dense layers, two matmuls, one row-softmax, one scale, and a three-way fan-in. Every piece has been proved. The composition is mechanical.

                      The backward, concretely #

                      This section gives:

                      1. Concrete definitions of sdpaBackQ, sdpaBackK, sdpaBackV transcribed from the step-by-step derivation above.
                      2. Correctness theorems sdpaBackQ_correct, sdpaBackK_correct, sdpaBackV_correct, stated in terms of pdivMat (the matrix-level partial derivative primitive from Tensor.lean), each proved compositionally as a vjpMatComp chain (four steps for Q).

                      The concrete formulas are also numerically gradient-checked in check_jacobians.py (test_sdpaBackQ/K/V) for cross-validation.

                      noncomputable def Proofs.sdpaScale (d : ℕ) :

                      1 / sqrt(d), the SDPA scale factor.

                      Equations
                      Instances For
                        noncomputable def Proofs.sdpaWeights (n d : ℕ) (Q K : Mat n d) :
                        Mat n n

                        Softmax-weights under the SDPA scale, reused by all three backwards.

                        Equations
                        Instances For
                          noncomputable def Proofs.sdpaDWeights {n d : ℕ} (V dOut : Mat n d) :
                          Mat n n

                          Gradient flowing into weights from the final matmul out = weights · V.

                          Equations
                          Instances For
                            noncomputable def Proofs.sdpaDScaled (n d : ℕ) (Q K V dOut : Mat n d) :
                            Mat n n

                            Per-row softmax VJP: p_i * (dw_i - <p_i, dw_i>).

                            Equations
                            • One or more equations did not get rendered due to their size.
                            Instances For
                              noncomputable def Proofs.sdpaDScores (n d : ℕ) (Q K V dOut : Mat n d) :
                              Mat n n

                              Gradient w.r.t. the pre-softmax scores, after undoing the / sqrt(d) scale.

                              Equations
                              Instances For
                                noncomputable def Proofs.sdpaBackQ (n d : ℕ) (Q K V dOut : Mat n d) :
                                Mat n d

                                Backward w.r.t. Q: dQ = dScores · K.

                                Equations
                                Instances For
                                  noncomputable def Proofs.sdpaBackK (n d : ℕ) (Q K V dOut : Mat n d) :
                                  Mat n d

                                  Backward w.r.t. K: dK = dScores^T · Q.

                                  Equations
                                  Instances For
                                    noncomputable def Proofs.sdpaBackV (n d : ℕ) (Q K _V dOut : Mat n d) :
                                    Mat n d

                                    Backward w.r.t. V: dV = weights^T · dOut. (V does not appear on the RHS: V's gradient flows only through the final matmul, not through weights.)

                                    Equations
                                    Instances For

                                      Q and K correctness via compositional SDPA forward chain #

                                      For Q (with K, V fixed), sdpa n d · K V is the composition:

                                      Q ↦ Q · K^T   ↦   scale * _   ↦   rowSoftmax _   ↦   _ · V
                                      

                                      Four steps, four already-proved HasVJPMat building blocks:

                                      1. matmulRightConstHasVJP (Mat.transpose K) — ∂(Q · K^T)/∂Q
                                      2. scalarScaleHasVJP (sdpaScale d) — ∂(scale · scores)/∂scores
                                      3. rowSoftmaxHasVJPMat — ∂(rowSoftmax scaled)/∂scaled
                                      4. matmulRightConstHasVJP V — ∂(weights · V)/∂weights

                                      Chain them with vjpMatComp thrice → a HasVJPMat for the full Q-path. Then show the chain's backward function equals sdpaBackQ pointwise (trivial — the chain's backward literally computes the same nested formula) and invoke its .correct to discharge the goal.

                                      noncomputable def Proofs.sdpaQChain (n d : ℕ) (K V : Mat n d) :
                                      Mat n d → Mat n d

                                      Explicit 4-composition forward for SDPA, varying Q with K, V fixed.

                                      Equations
                                      • One or more equations did not get rendered due to their size.
                                      Instances For
                                        noncomputable def Proofs.sdpaQChainHasVJP (n d : ℕ) (K V : Mat n d) :

                                        HasVJPMat for the chain — built by nesting vjpMatComp thrice.

                                        Equations
                                        • One or more equations did not get rendered due to their size.
                                        Instances For
                                          theorem Proofs.sdpaBackQ_correct (n d : ℕ) (Q K V dOut : Mat n d) (i : Fin n) (j : Fin d) :
                                          sdpaBackQ n d Q K V dOut i j = ∑ k : Fin n, ∑ l : Fin d, pdivMat (fun (Q' : Mat n d) => sdpa n d Q' K V) Q i j k l * dOut k l

                                          Correctness of sdpaBackQ — proved, no sorry.

                                          Two moves: (1) replace fun Q' => sdpa n d Q' K V by the chain via sdpaQChain_eq; (2) apply the chain's .correct and verify that the chain's backward reduces to sdpaBackQ (pure unfolding).

                                          K case #

                                          K enters through a transpose before the first matmul. One extra step in the chain: K ↦ K^T, then follow the Q chain (but with the matmul being "left factor constant" this time because Q is fixed and K^T is on the right).

                                          noncomputable def Proofs.sdpaKChain (n d : ℕ) (Q V : Mat n d) :
                                          Mat n d → Mat n d

                                          Attention as a function of K alone: transpose, Q · Kᵀ, scale, row softmax, · V.

                                          Equations
                                          • One or more equations did not get rendered due to their size.
                                          Instances For
                                            noncomputable def Proofs.sdpaKChainHasVJP (n d : ℕ) (Q V : Mat n d) :

                                            The VJP of sdpaKChain, vjpMatComp down its five steps.

                                            Equations
                                            • One or more equations did not get rendered due to their size.
                                            Instances For
                                              theorem Proofs.sdpaBackK_correct (n d : ℕ) (Q K V dOut : Mat n d) (i : Fin n) (j : Fin d) :
                                              sdpaBackK n d Q K V dOut i j = ∑ k : Fin n, ∑ l : Fin d, pdivMat (fun (K' : Mat n d) => sdpa n d Q K' V) K i j k l * dOut k l

                                              Correctness of sdpaBackK — proved, no sorry.

                                              Same shape as Q, but the chain goes through a leading transpose step. The resulting backward computes ∑ k, Q k j * dScores k i whereas sdpaBackK is Mat.mul (Mat.transpose dScores) Q, which expands to ∑ k, dScores k i * Q k j. Equal by mul_comm at the summand level.

                                              theorem Proofs.sdpa_eq_mul_weights (n d : ℕ) (Q K V : Mat n d) :
                                              sdpa n d Q K V = (sdpaWeights n d Q K).mul V

                                              The final matmul in SDPA: for fixed Q, K, the function V' ↦ sdpa Q K V' is V' ↦ W · V' where W = sdpaWeights Q K. Pure rewrite; definitional.

                                              theorem Proofs.sdpaBackV_correct (n d : ℕ) (Q K V dOut : Mat n d) (i : Fin n) (j : Fin d) :
                                              sdpaBackV n d Q K V dOut i j = ∑ k : Fin n, ∑ l : Fin d, pdivMat (fun (V' : Mat n d) => sdpa n d Q K V') V i j k l * dOut k l

                                              Correctness of sdpaBackV — proved, no sorry.

                                              The V-path is the simplest case: V' only enters through the final matmul out = weights · V'. So fun V' => sdpa n d Q K V' is just fun V' => Mat.mul W V' where W is fixed (= sdpaWeights n d Q K), and the VJP comes directly from matmulLeftConstHasVJP.

                                              noncomputable def Proofs.sdpaHasVJPMat3 (n d : ℕ) :

                                              Bundled SDPA ternary VJP. Packages sdpaBackQ_correct, sdpaBackK_correct and sdpaBackV_correct into a single HasVJPMat3 instance. The backward triple (sdpaBackQ, sdpaBackK, sdpaBackV) gives per-input gradients; correctness is the three existing per-input theorems in one structure.

                                              Equations
                                              • One or more equations did not get rendered due to their size.
                                              Instances For

                                                Multi-head: parallelism over a partition #

                                                Multi-head attention is:

                                                1. Project X : Mat N D three ways: Q = X·Wq + bq, K = X·Wk + bk, V = X·Wv + bv.
                                                2. Reshape each projection (N, D) → (N, heads, d_head) by slicing the feature axis.
                                                3. Run SDPA independently on each of the heads slices.
                                                4. Concatenate the head outputs back to (N, D).
                                                5. Apply the output projection Y = concat · Wo + bo.

                                                In the MLIR (emitMHSAForward): reshape (B, N, D) -> (B, N, H, D_h) transpose -> (B, H, N, D_h) [SDPA per head, using batching_dims = [0, 1]] transpose -> (B, N, H, D_h) reshape -> (B, N, D) dense projection (the "output projection" Wo)

                                                This section proves mhsaHasVJPMat end-to-end: we define mhsaLayer concretely in Lean (Q/K/V projections → per-head slice → sdpa-per-head → concat → Wo projection), then prove its HasVJPMat via the pdivMat_colIndep + colSlabwiseHasVJPMat framework, which lifts the per-head SDPA backward over the head axis. Formula remains numerically gradient-checked in check_jacobians.py for cross-validation.

                                                noncomputable def Proofs.mhsaLayer (N heads d_head : ℕ) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) (X : Mat N (heads * d_head)) :
                                                Mat N (heads * d_head)

                                                Multi-head SDPA on a single sequence: Mat N (heads·d_head) → Mat N (heads·d_head).

                                                Concretely defined (not opaque):

                                                1. Q, K, V projections (each a per-token dense with its own Wq/Wk/Wv).
                                                2. For each head h : Fin heads, extract the (N, d_head) slice of Q/K/V by indexing finProdFinEquiv (h, k) in the combined axis.
                                                3. Run sdpa on each slice.
                                                4. Concatenate the head outputs back along the feature axis.
                                                5. Output projection Wo · concat + bo (per-token dense).

                                                The bundled VJP theorem below packages the correctness of this whole thing — composing dense Jacobians, the per-head SDPA jacobians (sdpaBackQ_correct, sdpaBackK_correct, sdpaBackV_correct), and the reshape/unreshape pdiv_reindex facts, with the per-head independence handled by the column-stacking framework (pdivMat_colIndep + colSlabwiseHasVJPMat).

                                                Equations
                                                • One or more equations did not get rendered due to their size.
                                                Instances For

                                                  Column-stacked SDPA — the bridge from HasVJPMat3 to multi-head. #

                                                  Two facts are needed for multi-head attention:
                                                  (1) joint differentiability of `(Q, K, V) ↦ sdpa Q K V`, which doesn't
                                                  follow from the per-input `_flat_diff` lemmas; (2) the per-head
                                                  "vmap" structure, which `colSlabwiseHasVJPMat` handles for
                                                  *unary* per-slab functions but SDPA is naturally ternary.
                                                  
                                                  The fix: column-stack `(Q | K | V)` into a single `Mat n (3 * d_head)`
                                                  "qkv slab", define `mhsaG : Mat n (3 * d_head) → Mat n d_head` as the
                                                  unary view of SDPA on this slab, and lift via the existing framework.
                                                  
                                                  Both `mhsaG_flat_differentiable` and `mhsaGHasVJPMat` are then mechanical
                                                  composition of existing pieces: the joint `_flat_diff` factors through
                                                  `rowSoftmax_flat_differentiable` after stage-by-stage chaining, and the VJP comes
                                                  from `sdpaHasVJPMat3` plus a "column-third projection" argument that
                                                  matches the `(c : Fin 3)` index of the slab to the Q/K/V partial. 
                                                  
                                                  noncomputable def Proofs.mhsaG (n d : ℕ) (slab : Mat n (3 * d)) :
                                                  Mat n d

                                                  Column-stacked SDPA: takes a slab Mat n (3 * d_head) whose columns encode (c : Fin 3, j : Fin d_head) via finProdFinEquiv, with c = 0 being the Q-third, c = 1 the K-third, c = 2 the V-third. Returns sdpa applied to those three thirds.

                                                  Equations
                                                  • One or more equations did not get rendered due to their size.
                                                  Instances For
                                                    noncomputable def Proofs.mhsaPreWeights (n d : ℕ) (slab : Mat n (3 * d)) :
                                                    Mat n n

                                                    Pre-softmax matrix in mhsaG: scale · Q · K^T as a function of slab. Each entry is a polynomial in the slab's coords (linear projections times each other), so fun_prop discharges flat-diff after unfolding.

                                                    Equations
                                                    • One or more equations did not get rendered due to their size.
                                                    Instances For
                                                      noncomputable def Proofs.mhsaWeights (n d : ℕ) (slab : Mat n (3 * d)) :
                                                      Mat n n

                                                      Post-softmax weights in mhsaG: rowSoftmax(scale · Q · K^T).

                                                      Equations
                                                      Instances For
                                                        theorem Proofs.mhsaG_flat_differentiable (n d : ℕ) :
                                                        Differentiable ℝ fun (v : Vec (n * (3 * d))) => (mhsaG n d (Mat.unflatten v)).flatten

                                                        Joint flat-diff of column-stacked SDPA.

                                                        Joint diff in (Q, K, V) doesn't follow from the existing per-input _flat_diff lemmas. Here we prove it by treating the qkv-slab as the variable, factoring SDPA as Mat.mul ∘ rowSoftmax ∘ scaled-matmul: the weights are differentiable (mhsaWeights_flat_differentiable), and the final matmul with the V-third of the slab is polynomial in the weights and the slab coordinates.

                                                        Column-stacked SDPA VJP #

                                                        `HasVJPMat (mhsaG n d)`: the backward column-stacks
                                                        `(sdpaBackQ, sdpaBackK, sdpaBackV)` according to the c-third
                                                        of the slab column index. Correctness reduces to `sdpaHasVJPMat3`
                                                        after observing that perturbing the c-th third of the slab only
                                                        perturbs the c-th input of SDPA. 
                                                        
                                                        noncomputable def Proofs.mhsaProjC {n d : ℕ} (c : Fin 3) (slab : Mat n (3 * d)) :
                                                        Mat n d

                                                        Column projection slab ↦ slab^[c] for a fixed c : Fin 3. Linear, so its flat form is a reindexCLM.

                                                        Equations
                                                        Instances For
                                                          noncomputable def Proofs.mhsaLiftCCLM (n d : ℕ) (c : Fin 3) :
                                                          Vec (n * d) →L[ℝ] Vec (n * (3 * d))

                                                          "Lift to slab third c": embeds Vec (n * d) into Vec (n * (3 * d)) by placing u in the c-th column third and zero elsewhere. Linear, hence a CLM. Constructed from per-coord CLMs via ContinuousLinearMap.pi: each output coord is either a projection (if the index is in the c-third) or zero.

                                                          Equations
                                                          • One or more equations did not get rendered due to their size.
                                                          Instances For
                                                            noncomputable def Proofs.mhsaEmbedC (n d : ℕ) (c : Fin 3) (slab : Mat n (3 * d)) (u : Vec (n * d)) :
                                                            Vec (n * (3 * d))

                                                            "Embed Q' into slab at the c-th third, keep other thirds at slab's values." Affine function: mhsaLiftCCLM c · u + (slab with c-th third zeroed).

                                                            Equations
                                                            • One or more equations did not get rendered due to their size.
                                                            Instances For
                                                              theorem Proofs.pdivMat_mhsaG_split (n d : ℕ) (slab : Mat n (3 * d)) (i : Fin n) (c : Fin 3) (j : Fin d) (k : Fin n) (l : Fin d) :
                                                              pdivMat (mhsaG n d) slab i (finProdFinEquiv (c, j)) k l = if c = 0 then pdivMat (fun (Q' : Mat n d) => sdpa n d Q' (mhsaProjC 1 slab) (mhsaProjC 2 slab)) (mhsaProjC 0 slab) i j k l else if c = 1 then pdivMat (fun (K' : Mat n d) => sdpa n d (mhsaProjC 0 slab) K' (mhsaProjC 2 slab)) (mhsaProjC 1 slab) i j k l else pdivMat (fun (V' : Mat n d) => sdpa n d (mhsaProjC 0 slab) (mhsaProjC 1 slab) V') (mhsaProjC 2 slab) i j k l

                                                              pdivMat of mhsaG splits per-c into the corresponding pdivMat of SDPA against its c-th argument. The freezing lemma: changes in the c-th column third of the slab only perturb the c-th input of SDPA. Proved via the chain rule mhsaG ∘ mhsaEmbedC = freeze_c.

                                                              noncomputable def Proofs.mhsaGHasVJPMat (n d : ℕ) :

                                                              HasVJPMat for column-stacked SDPA. Backward column-stacks the three sdpaBackQ/sdpaBackK/sdpaBackV outputs by their c : Fin 3 slot. Correctness comes from pdivMat_mhsaG_split (case-splits on c into the corresponding one-input SDPA pdivMat) and sdpaHasVJPMat3.correct_*.

                                                              Equations
                                                              • One or more equations did not get rendered due to their size.
                                                              Instances For
                                                                theorem Proofs.colSlabApplyH_flat_differentiable {n heads d_in d_out : ℕ} (g : Fin heads → Mat n d_in → Mat n d_out) (hg_diff : ∀ (h : Fin heads), Differentiable ℝ fun (v : Vec (n * d_in)) => (g h (Mat.unflatten v)).flatten) :
                                                                Differentiable ℝ fun (v : Vec (n * (heads * d_in))) => (colSlabApplyH g (Mat.unflatten v)).flatten

                                                                colSlabApplyH is differentiable, flattened, when every slab's map is: each output coordinate factors through the linear slab projection and g h by flat_differentiable_comp.

                                                                theorem Proofs.sdpaQ_flat_differentiable (n d : ℕ) (K V : Mat n d) :
                                                                Differentiable ℝ fun (v : Vec (n * d)) => (sdpa n d (Mat.unflatten v) K V).flatten

                                                                Single-head attention is differentiable in Q, flattened (K, V fixed).

                                                                theorem Proofs.sdpaK_flat_differentiable (n d : ℕ) (Q V : Mat n d) :
                                                                Differentiable ℝ fun (v : Vec (n * d)) => (sdpa n d Q (Mat.unflatten v) V).flatten

                                                                …in K.

                                                                theorem Proofs.sdpaV_flat_differentiable (n d : ℕ) (Q K : Mat n d) :
                                                                Differentiable ℝ fun (v : Vec (n * d)) => (sdpa n d Q K (Mat.unflatten v)).flatten

                                                                …in V (the softmax weights are a constant).

                                                                theorem Proofs.colSlabApply_flat_differentiable {n heads d_in d_out : ℕ} (g : Mat n d_in → Mat n d_out) (hg_diff : Differentiable ℝ fun (v : Vec (n * d_in)) => (g (Mat.unflatten v)).flatten) :
                                                                Differentiable ℝ fun (v : Vec (n * (heads * d_in))) => (colSlabApply g (Mat.unflatten v)).flatten

                                                                Flat-diff for colSlabApply g: the constant-family case of colSlabApplyH_flat_differentiable.

                                                                noncomputable def Proofs.mhsaQkvW (heads d_head : ℕ) (Wq Wk Wv : Mat (heads * d_head) (heads * d_head)) :
                                                                Mat (heads * d_head) (heads * (3 * d_head))

                                                                Combined Q/K/V weight matrix: stack Wq | Wk | Wv with the per-head interleave layout. Output column (h, c, j) ↦ (Wq | Wk | Wv)[k, fPF(h, j)] based on c : Fin 3. Used to express the three Q/K/V projections as a single per-token dense, enabling clean composition with colSlabApply mhsaG.

                                                                Equations
                                                                • One or more equations did not get rendered due to their size.
                                                                Instances For
                                                                  noncomputable def Proofs.mhsaQkvB (heads d_head : ℕ) (bq bk bv : Vec (heads * d_head)) :
                                                                  Vec (heads * (3 * d_head))

                                                                  Combined Q/K/V bias vector: bq | bk | bv in mhsaQkvW's per-head interleave layout.

                                                                  Equations
                                                                  • One or more equations did not get rendered due to their size.
                                                                  Instances For
                                                                    @[simp]
                                                                    theorem Proofs.mhsaQkvW_eq0 (heads d_head : ℕ) (Wq Wk Wv : Mat (heads * d_head) (heads * d_head)) (k : Fin (heads * d_head)) (h : Fin heads) (j : Fin d_head) :
                                                                    mhsaQkvW heads d_head Wq Wk Wv k (finProdFinEquiv (h, finProdFinEquiv (0, j))) = Wq k (finProdFinEquiv (h, j))
                                                                    @[simp]
                                                                    theorem Proofs.mhsaQkvW_eq1 (heads d_head : ℕ) (Wq Wk Wv : Mat (heads * d_head) (heads * d_head)) (k : Fin (heads * d_head)) (h : Fin heads) (j : Fin d_head) :
                                                                    mhsaQkvW heads d_head Wq Wk Wv k (finProdFinEquiv (h, finProdFinEquiv (1, j))) = Wk k (finProdFinEquiv (h, j))
                                                                    @[simp]
                                                                    theorem Proofs.mhsaQkvW_eq2 (heads d_head : ℕ) (Wq Wk Wv : Mat (heads * d_head) (heads * d_head)) (k : Fin (heads * d_head)) (h : Fin heads) (j : Fin d_head) :
                                                                    mhsaQkvW heads d_head Wq Wk Wv k (finProdFinEquiv (h, finProdFinEquiv (2, j))) = Wv k (finProdFinEquiv (h, j))
                                                                    @[simp]
                                                                    theorem Proofs.mhsaQkvB_eq0 (heads d_head : ℕ) (bq bk bv : Vec (heads * d_head)) (h : Fin heads) (j : Fin d_head) :
                                                                    mhsaQkvB heads d_head bq bk bv (finProdFinEquiv (h, finProdFinEquiv (0, j))) = bq (finProdFinEquiv (h, j))
                                                                    @[simp]
                                                                    theorem Proofs.mhsaQkvB_eq1 (heads d_head : ℕ) (bq bk bv : Vec (heads * d_head)) (h : Fin heads) (j : Fin d_head) :
                                                                    mhsaQkvB heads d_head bq bk bv (finProdFinEquiv (h, finProdFinEquiv (1, j))) = bk (finProdFinEquiv (h, j))
                                                                    @[simp]
                                                                    theorem Proofs.mhsaQkvB_eq2 (heads d_head : ℕ) (bq bk bv : Vec (heads * d_head)) (h : Fin heads) (j : Fin d_head) :
                                                                    mhsaQkvB heads d_head bq bk bv (finProdFinEquiv (h, finProdFinEquiv (2, j))) = bv (finProdFinEquiv (h, j))
                                                                    theorem Proofs.mhsaLayer_eq_compose (N heads d_head : ℕ) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) (X : Mat N (heads * d_head)) :
                                                                    mhsaLayer N heads d_head Wq Wk Wv Wo bq bk bv bo X = (fun (M : Mat N (heads * d_head)) (n : Fin N) => dense Wo bo (M n)) (colSlabApply (mhsaG N d_head) ((fun (X' : Mat N (heads * d_head)) (n : Fin N) => dense (mhsaQkvW heads d_head Wq Wk Wv) (mhsaQkvB heads d_head bq bk bv) (X' n)) X))

                                                                    The mhsaLayer factorization: it equals output_dense ∘ colSlabApply mhsaG ∘ qkv_stack_dense.

                                                                    All three pieces have HasVJPMat and flat-diff:

                                                                    noncomputable def Proofs.mhsaComposedHasVJPMat (N heads d_head : ℕ) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) :
                                                                    HasVJPMat ((fun (M : Mat N (heads * d_head)) (n : Fin N) => dense Wo bo (M n)) ∘ colSlabApply (mhsaG N d_head) ∘ fun (X' : Mat N (heads * d_head)) (n : Fin N) => dense (mhsaQkvW heads d_head Wq Wk Wv) (mhsaQkvB heads d_head bq bk bv) (X' n))

                                                                    The composed MHSA VJP — Wo-dense ∘ colSlabApply mhsaG ∘ qkv-dense, stated on the explicit composition (no mhsaLayer_eq_compose transport). This is the substantive witness; mhsaHasVJPMat below re-types it to mhsaLayer with the cast confined to the correct field, so (mhsaHasVJPMat …).backward reduces in one projection.

                                                                    Equations
                                                                    • One or more equations did not get rendered due to their size.
                                                                    Instances For
                                                                      noncomputable def Proofs.mhsaHasVJPMat (N heads d_head : ℕ) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) :
                                                                      HasVJPMat (mhsaLayer N heads d_head Wq Wk Wv Wo bq bk bv bo)

                                                                      Multi-head SDPA VJP, composed from mhsaGHasVJPMat, colSlabwiseHasVJPMat, and the per-token dense framework. backward is the composed witness's field DIRECTLY (kernel-cheap projection); the mhsaLayer_eq_compose transport lives only in correct — a Prop the kernel never reduces. See mhsaComposedHasVJPMat's docstring for why.

                                                                      Equations
                                                                      Instances For
                                                                        theorem Proofs.mhsaLayer_flat_differentiable (N heads d_head : ℕ) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) :
                                                                        Differentiable ℝ fun (v : Vec (N * (heads * d_head))) => (mhsaLayer N heads d_head Wq Wk Wv Wo bq bk bv bo (Mat.unflatten v)).flatten

                                                                        Differentiability of the flattened multi-head SDPA layer — composition of three _flat_diff lemmas.

                                                                        Per-token liftings (theorems) #

                                                                        Every per-token operation in a transformer (LN, dense, GELU) lifts from HasVJP on Vec D to HasVJPMat on Mat N D via the single helper rowwiseHasVJPMat (Tensor.lean).

                                                                        noncomputable def Proofs.layerNormPerTokenHasVJPMat (N D : ℕ) (ε γ β : ℝ) (hε : 0 < ε) :
                                                                        HasVJPMat fun (X : Mat N D) (n : Fin N) => layerNormForward D ε γ β (X n)

                                                                        Per-token layer norm across a sequence. Applies layerNormForward to each row of the (N, D) input; the backward is block-diagonal.

                                                                        Equations
                                                                        Instances For
                                                                          noncomputable def Proofs.densePerTokenHasVJPMat (N inD outD : ℕ) (W : Mat inD outD) (b : Vec outD) :
                                                                          HasVJPMat fun (X : Mat N inD) (n : Fin N) => dense W b (X n)

                                                                          Per-token dense projection across a sequence. Q = X · W + b, row-by-row dense with shared weights.

                                                                          Equations
                                                                          Instances For
                                                                            noncomputable def Proofs.geluPerTokenHasVJPMat (gf : GeluForm) (N D : ℕ) :
                                                                            HasVJPMat fun (X : Mat N D) (n : Fin N) => gf.map D (X n)

                                                                            Per-token GELU across a sequence. Elementwise activation, so diagonal Jacobian both across rows and within a row.

                                                                            Equations
                                                                            Instances For
                                                                              theorem Proofs.geluFlat_eq_backward {gf : GeluForm} {N D : ℕ} (A dY : Mat N D) :

                                                                              Per-token GELU input-VJP: the flat gf.hasVJP (N*D) backward IS the flatten of the rowwise geluPerTokenHasVJPMat.backward at the saved pre-GELU activation A (GELU is elementwise, so flat and rowwise agree).

                                                                              A transformer encoder block #

                                                                              From MlirCodegen.emitTransformerBlockForward:

                                                                              block(x) = h1 + MLP(LN2(h1))       where h1 = x + MHSA(LN1(x))
                                                                              

                                                                              Expanding:

                                                                              h1 = x + MHSA(LN1(x))       -- attention sub-layer with residual
                                                                              out = h1 + MLP(LN2(h1))     -- MLP sub-layer with residual
                                                                              

                                                                              where MLP(z) = dense(Wfc2, bfc2, gelu(dense(Wfc1, bfc1, z))).

                                                                              Every piece is now a HasVJPMat on Mat N D:

                                                                              The transformer block theorem below glues these with vjpMatComp and biPathMatHasVJP.

                                                                              noncomputable def Proofs.transformerMlp (gf : GeluForm) (N D mlpDim : ℕ) (Wfc1 : Mat D mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim D) (bfc2 : Vec D) :
                                                                              Mat N D → Mat N D

                                                                              MLP sublayer of a transformer block: dense ∘ GELU ∘ dense applied per-token.

                                                                              Concretely: MLP(z) = Wfc2 · gelu(Wfc1 · z + bfc1) + bfc2, applied row-wise. gf is the form of the GELU — the tanh approximation or the exact x · Φ(x) (GeluForm) — and every definition and theorem built on this one carries it and holds for both.

                                                                              Equations
                                                                              • One or more equations did not get rendered due to their size.
                                                                              Instances For
                                                                                theorem Proofs.transformerMlp_flat_differentiable {gf : GeluForm} (N D mlpDim : ℕ) (Wfc1 : Mat D mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim D) (bfc2 : Vec D) :
                                                                                Differentiable ℝ fun (v : Vec (N * D)) => (transformerMlp gf N D mlpDim Wfc1 bfc1 Wfc2 bfc2 (Mat.unflatten v)).flatten

                                                                                Differentiability of the flattened transformerMlp — dense ∘ gelu ∘ dense per token, all smooth at either GELU (GeluForm.scalar_differentiable is tagged for fun_prop).

                                                                                noncomputable def Proofs.transformerMlpHasVJPMat (gf : GeluForm) (N D mlpDim : ℕ) (Wfc1 : Mat D mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim D) (bfc2 : Vec D) :
                                                                                HasVJPMat (transformerMlp gf N D mlpDim Wfc1 bfc1 Wfc2 bfc2)

                                                                                HasVJPMat for the MLP sublayer — chain of two vjpMatComp steps over per-token liftings (dense ∘ gelu ∘ dense). Every Diff hypothesis is discharged by the per-token-flat helpers above.

                                                                                Equations
                                                                                • One or more equations did not get rendered due to their size.
                                                                                Instances For
                                                                                  noncomputable def Proofs.preLNResHasVJPMat {N D : ℕ} (L F : Mat N D → Mat N D) (hL : Differentiable ℝ fun (v : Vec (N * D)) => (L (Mat.unflatten v)).flatten) (hF : Differentiable ℝ fun (v : Vec (N * D)) => (F (Mat.unflatten v)).flatten) (vL : HasVJPMat L) (vF : HasVJPMat F) :
                                                                                  HasVJPMat (biPathMat (fun (X : Mat N D) => X) (F ∘ L))

                                                                                  VJP of a pre-norm residual sublayer X ↦ X + F (L X) (norm L, then body F): biPathMatHasVJP of the identity skip and the vjpMatComp chain L-back ∘ F-back. Every transformer sublayer (scalar- and vector-LN, attention and MLP) is an instance.

                                                                                  Equations
                                                                                  Instances For
                                                                                    noncomputable def Proofs.transformerAttnSublayer (N heads d_head : ℕ) (ε γ1 β1 : ℝ) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) :
                                                                                    Mat N (heads * d_head) → Mat N (heads * d_head)

                                                                                    Attention sublayer: X ↦ X + MHSA(LN1(X)). Top-level composition; the biPathMat skip-adds identity to the MHSA∘LN1 branch.

                                                                                    Equations
                                                                                    • One or more equations did not get rendered due to their size.
                                                                                    Instances For
                                                                                      noncomputable def Proofs.transformerMlpSublayer (gf : GeluForm) (N heads d_head mlpDim : ℕ) (ε γ2 β2 : ℝ) (Wfc1 : Mat (heads * d_head) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d_head)) (bfc2 : Vec (heads * d_head)) :
                                                                                      Mat N (heads * d_head) → Mat N (heads * d_head)

                                                                                      MLP sublayer: h ↦ h + MLP(LN2(h)). Same biPathMat structure.

                                                                                      Equations
                                                                                      • One or more equations did not get rendered due to their size.
                                                                                      Instances For
                                                                                        noncomputable def Proofs.transformerBlock (gf : GeluForm) (N heads d_head mlpDim : ℕ) (ε γ1 β1 : ℝ) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) (γ2 β2 : ℝ) (Wfc1 : Mat (heads * d_head) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d_head)) (bfc2 : Vec (heads * d_head)) :
                                                                                        Mat N (heads * d_head) → Mat N (heads * d_head)

                                                                                        Transformer encoder block forward: MLP-sublayer ∘ attention-sublayer. Signature matches the codegen: Mat N (heads·d_head) → Mat N (heads·d_head).

                                                                                        Equations
                                                                                        • One or more equations did not get rendered due to their size.
                                                                                        Instances For
                                                                                          theorem Proofs.transformerAttnSublayer_flat_differentiable (N heads d_head : ℕ) (ε γ1 β1 : ℝ) (hε : 0 < ε) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) :
                                                                                          Differentiable ℝ fun (v : Vec (N * (heads * d_head))) => (transformerAttnSublayer N heads d_head ε γ1 β1 Wq Wk Wv Wo bq bk bv bo (Mat.unflatten v)).flatten

                                                                                          Differentiability of the flattened attention sublayer. biPathMat (id) (mhsa ∘ LN1) flattens to a sum, both arms Differentiable.

                                                                                          noncomputable def Proofs.transformerAttnSublayerHasVJPMat (N heads d_head : ℕ) (ε γ1 β1 : ℝ) (hε : 0 < ε) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) :
                                                                                          HasVJPMat (transformerAttnSublayer N heads d_head ε γ1 β1 Wq Wk Wv Wo bq bk bv bo)

                                                                                          Attention sublayer VJP: preLNResHasVJPMat at L = LN1, F = mhsa.

                                                                                          Equations
                                                                                          • One or more equations did not get rendered due to their size.
                                                                                          Instances For
                                                                                            theorem Proofs.transformerMlpSublayer_flat_differentiable {gf : GeluForm} (N heads d_head mlpDim : ℕ) (ε γ2 β2 : ℝ) (hε : 0 < ε) (Wfc1 : Mat (heads * d_head) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d_head)) (bfc2 : Vec (heads * d_head)) :
                                                                                            Differentiable ℝ fun (v : Vec (N * (heads * d_head))) => (transformerMlpSublayer gf N heads d_head mlpDim ε γ2 β2 Wfc1 bfc1 Wfc2 bfc2 (Mat.unflatten v)).flatten

                                                                                            Differentiability of the flattened MLP sublayer. biPathMat (id) (transformerMlp ∘ LN2) flattens to a sum, both arms Differentiable.

                                                                                            noncomputable def Proofs.transformerMlpSublayerHasVJPMat (gf : GeluForm) (N heads d_head mlpDim : ℕ) (ε γ2 β2 : ℝ) (hε : 0 < ε) (Wfc1 : Mat (heads * d_head) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d_head)) (bfc2 : Vec (heads * d_head)) :
                                                                                            HasVJPMat (transformerMlpSublayer gf N heads d_head mlpDim ε γ2 β2 Wfc1 bfc1 Wfc2 bfc2)

                                                                                            MLP sublayer VJP: preLNResHasVJPMat at L = LN2, F = transformerMlp.

                                                                                            Equations
                                                                                            • One or more equations did not get rendered due to their size.
                                                                                            Instances For
                                                                                              theorem Proofs.transformerBlock_flat_differentiable {gf : GeluForm} (N heads d_head mlpDim : ℕ) (ε γ1 β1 : ℝ) (hε : 0 < ε) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) (γ2 β2 : ℝ) (Wfc1 : Mat (heads * d_head) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d_head)) (bfc2 : Vec (heads * d_head)) :
                                                                                              Differentiable ℝ fun (v : Vec (N * (heads * d_head))) => (transformerBlock gf N heads d_head mlpDim ε γ1 β1 Wq Wk Wv Wo bq bk bv bo γ2 β2 Wfc1 bfc1 Wfc2 bfc2 (Mat.unflatten v)).flatten

                                                                                              Differentiability of the flattened transformer block. MlpSublayer ∘ AttnSublayer; both sublayers' flat Diff are theorems above.

                                                                                              noncomputable def Proofs.transformerBlockHasVJPMat (gf : GeluForm) (N heads d_head mlpDim : ℕ) (ε γ1 β1 : ℝ) (hε : 0 < ε) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) (γ2 β2 : ℝ) (Wfc1 : Mat (heads * d_head) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d_head)) (bfc2 : Vec (heads * d_head)) :
                                                                                              HasVJPMat (transformerBlock gf N heads d_head mlpDim ε γ1 β1 Wq Wk Wv Wo bq bk bv bo γ2 β2 Wfc1 bfc1 Wfc2 bfc2)

                                                                                              Transformer block VJP — composition of attn + mlp sublayers: a single vjpMatComp of the two sublayer witnesses with their Diff helpers. Both LayerNorms are scalar-affine (γ1 β1 γ2 β2 : ℝ).

                                                                                              Equations
                                                                                              • One or more equations did not get rendered due to their size.
                                                                                              Instances For

                                                                                                Stacking transformer blocks #

                                                                                                ViT-Tiny has 12 transformer blocks; ViT-Base has 12, ViT-Large has 24. The stack is just k-fold composition of individual blocks. By vjpMatComp and induction on k, if each block has a HasVJPMat then so does the stack — for any depth.

                                                                                                The formal tower transformerTower uses a single shared parameter tuple across all k blocks (Nat.rec over one tuple), with scalar-affine LayerNorms; in practice every block has its own weights and a per-feature LN. Per-block parameters are not formalized in this file.

                                                                                                noncomputable def Proofs.transformerTower (gf : GeluForm) (k N heads d_head mlpDim : ℕ) (ε γ1 β1 : ℝ) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) (γ2 β2 : ℝ) (Wfc1 : Mat (heads * d_head) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d_head)) (bfc2 : Vec (heads * d_head)) :
                                                                                                Mat N (heads * d_head) → Mat N (heads * d_head)

                                                                                                k-fold iterated transformer block, sharing parameters across all k layers. Defined by Nat.rec so the HasVJPMat proof is a straightforward induction on k.

                                                                                                Equations
                                                                                                • One or more equations did not get rendered due to their size.
                                                                                                Instances For
                                                                                                  theorem Proofs.transformerTower_flat_differentiable {gf : GeluForm} (k N heads d_head mlpDim : ℕ) (ε γ1 β1 : ℝ) (hε : 0 < ε) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) (γ2 β2 : ℝ) (Wfc1 : Mat (heads * d_head) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d_head)) (bfc2 : Vec (heads * d_head)) :
                                                                                                  Differentiable ℝ fun (v : Vec (N * (heads * d_head))) => (transformerTower gf k N heads d_head mlpDim ε γ1 β1 Wq Wk Wv Wo bq bk bv bo γ2 β2 Wfc1 bfc1 Wfc2 bfc2 (Mat.unflatten v)).flatten

                                                                                                  Differentiability of the flattened k-fold transformer tower. Induction on k: zero case is identity, successor case is block ∘ tower(k) composed via Differentiable.comp.

                                                                                                  noncomputable def Proofs.transformerTowerHasVJPMat (gf : GeluForm) (k N heads d_head mlpDim : ℕ) (ε γ1 β1 : ℝ) (hε : 0 < ε) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) (γ2 β2 : ℝ) (Wfc1 : Mat (heads * d_head) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d_head)) (bfc2 : Vec (heads * d_head)) :
                                                                                                  HasVJPMat (transformerTower gf k N heads d_head mlpDim ε γ1 β1 Wq Wk Wv Wo bq bk bv bo γ2 β2 Wfc1 bfc1 Wfc2 bfc2)

                                                                                                  Transformer tower VJP — k-fold composition of one shared block (transformerTower): induction on k via vjpMatComp and transformerBlockHasVJPMat.

                                                                                                  Equations
                                                                                                  • One or more equations did not get rendered due to their size.
                                                                                                  Instances For

                                                                                                    ViT body: tower + final LN #

                                                                                                    vitBody is the ViT backbone operating on a single (N, D) sequence, after the patch embedding produced a Mat N D input and before the classifier head slices the CLS token and runs dense+softmax CE.

                                                                                                    patch_embed(X : Tensor3 ic h w) : Mat N D   ← outside Mat-land
                                                                                                    vitBody(M : Mat N D) : Mat N D             ← the backbone (this file)
                                                                                                    classifier(M) = dense(W_cls, b_cls, M[0])   ← Mat → Vec, then softmax CE loss
                                                                                                    

                                                                                                    The backbone is finalLN ∘ transformerTower. Both sides are Mat N D, so vjpMatComp glues the two VJPs.

                                                                                                    The patch-embedding and classifier-head steps exit Mat-land (they change type to/from Tensor3 and Vec respectively), so they don't fit in the uniform HasVJPMat frame. They are bridged below (§ Bridging ranks): the body is flattened with HasVJPMat.toHasVJP and composed with patchEmbedFlatHasVJP and classifierFlatHasVJP in vitFullHasVJP.

                                                                                                    noncomputable def Proofs.vitBody (gf : GeluForm) (k N heads d_head mlpDim : ℕ) (ε γ1 β1 : ℝ) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) (γ2 β2 : ℝ) (Wfc1 : Mat (heads * d_head) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d_head)) (bfc2 : Vec (heads * d_head)) (γF βF : ℝ) :
                                                                                                    Mat N (heads * d_head) → Mat N (heads * d_head)

                                                                                                    ViT body — transformer tower followed by final per-token LayerNorm.

                                                                                                    Composition is finalLN ∘ transformerTower; matches the codegen's emitForwardBody ordering for a .transformerEncoder followed by the implicit final LN block.

                                                                                                    Equations
                                                                                                    • One or more equations did not get rendered due to their size.
                                                                                                    Instances For
                                                                                                      theorem Proofs.vitBody_flat_differentiable {gf : GeluForm} (k N heads d_head mlpDim : ℕ) (ε : ℝ) (hε : 0 < ε) (γ1 β1 : ℝ) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) (γ2 β2 : ℝ) (Wfc1 : Mat (heads * d_head) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d_head)) (bfc2 : Vec (heads * d_head)) (γF βF : ℝ) :
                                                                                                      Differentiable ℝ fun (v : Vec (N * (heads * d_head))) => (vitBody gf k N heads d_head mlpDim ε γ1 β1 Wq Wk Wv Wo bq bk bv bo γ2 β2 Wfc1 bfc1 Wfc2 bfc2 γF βF (Mat.unflatten v)).flatten

                                                                                                      Differentiability of the flattened ViT body. finalLN ∘ transformerTower — both have flat Diff theorems above.

                                                                                                      noncomputable def Proofs.vitBodyHasVJPMat (gf : GeluForm) (k N heads d_head mlpDim : ℕ) (ε : ℝ) (hε : 0 < ε) (γ1 β1 : ℝ) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) (γ2 β2 : ℝ) (Wfc1 : Mat (heads * d_head) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d_head)) (bfc2 : Vec (heads * d_head)) (γF βF : ℝ) :
                                                                                                      HasVJPMat (vitBody gf k N heads d_head mlpDim ε γ1 β1 Wq Wk Wv Wo bq bk bv bo γ2 β2 Wfc1 bfc1 Wfc2 bfc2 γF βF)

                                                                                                      The ViT body VJP — finalLN ∘ transformerTower: a single vjpMatComp of the tower + final LN with their Diff helpers.

                                                                                                      A depth-k weight-tied backbone (one parameter tuple for every block, scalar-affine LayerNorms) has a correct VJP, composed entirely from proved building blocks; mhsaHasVJPMat and mhsaLayer_flat_differentiable are proved through the column-stacking framework, so the chain uses no project axioms.

                                                                                                      Equations
                                                                                                      • One or more equations did not get rendered due to their size.
                                                                                                      Instances For

                                                                                                        What we've proved (and what's left) #

                                                                                                        Proved (zero sorry's, machine-checked):

                                                                                                        Three calculus rules do all the structural work (theorems proved from Mathlib's fderiv):

                                                                                                        pdiv_comp   (chain rule — functions compose, derivatives compose)
                                                                                                        pdiv_add    (linearity — derivatives of sums are sums of derivatives)
                                                                                                        pdiv_mul    (product rule — derivatives of elementwise products)
                                                                                                        

                                                                                                        Five closed-form "Jacobian-structure tricks" handle the layers whose Jacobians are dense but exploitable:

                                                                                                        1. Diagonal (activations) — collapse the sum_j to one term.
                                                                                                        2. Sparse toeplitz (conv, depthwise) — reversed/transposed kernels.
                                                                                                        3. Binary selection (max-pool) — route gradients to argmax cells.
                                                                                                        4. Rank-1 correction to diagonal (softmax, BN, LN) — one extra scalar reduction, everything else is pointwise.
                                                                                                        5. Outer product + reductions (dense, matmul) — rank-1 update accumulation.

                                                                                                        That is the complete taxonomy. I've thought hard about this and cannot find a sixth trick or a fourth calculus rule anywhere in the modern architecture zoo. Every paper, every block, every optimization is a rearrangement of these eight things.

                                                                                                        What this means for the reader #

                                                                                                        If you've read this far, you have a complete decoder for the architecture-of-the-month. Pick any paper — Swin, ConvNeXt, CLIP, Mamba, anything — and walk through the forward pass. For each operation, ask:

                                                                                                        1. Is it composition of known ops? -> chain rule.
                                                                                                        2. Is it a sum of branches? -> fan-in add.
                                                                                                        3. Is it an elementwise / scalar product of branches? -> fan-in mul.
                                                                                                        4. Is it an activation? -> diagonal Jacobian template.
                                                                                                        5. Is it a normalization? -> closed-form three-term formula.
                                                                                                        6. Is it a convolution or linear map? -> the structured-matmul machinery.
                                                                                                        7. Is it an attention or softmax-based selection? -> the closed-form rank-1 collapse.

                                                                                                        If the answer is "none of the above" — which it won't be — then you've found the first genuinely new layer of the decade, and you get to write the next chapter of this book.

                                                                                                        Until then, welcome to the end of the road.

                                                                                                        Bridging ranks: from Mat-land back to Vec-land #

                                                                                                        vitBodyHasVJPMat lives in HasVJPMat territory. The pieces at the boundaries — patch embedding (image → tokens) and classifier head (tokens → logits) — change tensor rank. Rather than invent new mixed-rank VJP frameworks, we flatten everything to Vec at the interfaces and compose via plain HasVJP, glued by vjpComp.

                                                                                                        Two ingredients needed:

                                                                                                        noncomputable def Proofs.clsTokenFlat (N D : ℕ) :
                                                                                                        Vec ((N + 1) * D) → Vec D

                                                                                                        CLS token extraction, stated on the flattened matrix. Row 0 of a Mat (N+1) D is a Vec D; on the flattened Vec ((N+1)*D) this is the gather v ↦ fun k => v (fPF (0, k)).

                                                                                                        Equations
                                                                                                        Instances For
                                                                                                          noncomputable def Proofs.clsTokenFlatHasVJP (N D : ℕ) :

                                                                                                          CLS slice VJP — gather-style; backward scatters dy to row 0. Derived from pdiv_reindex.

                                                                                                          Equations
                                                                                                          • One or more equations did not get rendered due to their size.
                                                                                                          Instances For
                                                                                                            noncomputable def Proofs.classifierFlat (N D nClasses : ℕ) (Wcls : Mat D nClasses) (bcls : Vec nClasses) :
                                                                                                            Vec ((N + 1) * D) → Vec nClasses

                                                                                                            Classifier head: flattened CLS slice + dense projection to Vec nClasses.

                                                                                                            fun v : Vec ((N+1)*D) => dense W_cls b_cls (clsTokenFlat v)

                                                                                                            Equations
                                                                                                            Instances For

                                                                                                              Differentiability of clsTokenFlat — linear reindex.

                                                                                                              noncomputable def Proofs.classifierFlatHasVJP (N D nClasses : ℕ) (Wcls : Mat D nClasses) (bcls : Vec nClasses) :
                                                                                                              HasVJP (classifierFlat N D nClasses Wcls bcls)

                                                                                                              Classifier head VJP — composition via vjpComp. clsTokenFlat and dense are both linear, so their Diff hypotheses discharge by fun_prop.

                                                                                                              Equations
                                                                                                              Instances For

                                                                                                                Patch embedding #

                                                                                                                The patch embedding takes a flattened image Vec (ic*H*W) and produces a flattened Vec ((N+1)*D) interpreted as Mat (N+1) D:

                                                                                                                1. Conv projection with stride = patchSize: per-patch dense projection W_conv : Kernel4 D ic patchSize patchSize + bias b_conv : Vec D.
                                                                                                                2. Reshape spatial (D, H', W') to tokens (N, D) — pure permutation.
                                                                                                                3. Prepend learnable CLS token at row 0 → (N+1, D).
                                                                                                                4. Add learnable positional embedding matrix → (N+1, D).

                                                                                                                The forward patchEmbedFlat is a concrete def; its VJP patchEmbedFlatHasVJP and patchEmbedFlat_differentiable are proved from foundation rules.

                                                                                                                The N parameter is independent of (H, W, patchSize) — out-of-range patches contribute zero (via a hpad guard on the image read), so the API does not require N = (H/patchSize) * (W/patchSize).

                                                                                                                noncomputable def Proofs.patchEmbedFlat (ic H W patchSize N D : ℕ) (W_conv : Kernel4 D ic patchSize patchSize) (b_conv cls_token : Vec D) (pos_embed : Mat (N + 1) D) :
                                                                                                                Vec (ic * H * W) → Vec ((N + 1) * D)

                                                                                                                Patch embedding forward on flattened endpoints.

                                                                                                                Output at flat-index idx_out = finProdFinEquiv (n, d):

                                                                                                                • n = 0: cls_token d + pos_embed 0 d.
                                                                                                                • n > 0 (let p := n - 1, h' := p / (W/patchSize), w' := p % (W/patchSize)): `b_conv d + Σ c kh kw, W_conv d c kh kw * img(c, h'*P+kh, w'*P+kw)
                                                                                                                  • pos_embed n d, where the image read is guarded by h'*P+kh < H ∧ w'*P+kw < W` (returns 0 if out of range).

                                                                                                                This handles arbitrary N cleanly: for n whose decoded patch (h', w') falls outside the image grid, the inner sum is identically zero.

                                                                                                                Equations
                                                                                                                • One or more equations did not get rendered due to their size.
                                                                                                                Instances For
                                                                                                                  theorem Proofs.patchEmbedFlat_differentiable (ic H W patchSize N D : ℕ) (W_conv : Kernel4 D ic patchSize patchSize) (b_conv cls_token : Vec D) (pos_embed : Mat (N + 1) D) :
                                                                                                                  Differentiable ℝ (patchEmbedFlat ic H W patchSize N D W_conv b_conv cls_token pos_embed)

                                                                                                                  Patch embedding differentiability — proved from foundation rules. patchEmbedFlat is linear in img plus constants (pos_embed, cls_token, b_conv); the only non-trivial part is the dependent if hpad : ... then img(σ hpad) else 0 pattern handled by differentiableAt_pad_eval.

                                                                                                                  noncomputable def Proofs.patchEmbedInputGradFormula (ic H W patchSize N D : ℕ) (W_conv : Kernel4 D ic patchSize patchSize) (dy : Vec ((N + 1) * D)) :
                                                                                                                  Vec (ic * H * W)

                                                                                                                  Closed-form input gradient for patchEmbedFlat — direct formula, written as a sum over patches p : Fin N with reconstructed kernel offsets (kh, kw) matching the input position (hh, ww) decoded from idx_in. Equivalent (under the patch-row decomposition h' := p/(W/P), w' := p%(W/P)) to the standard "deconvolution" formula for patchEmbed.

                                                                                                                  The CLS row (n = 0) does not appear here — idx_in only flows through the conv-projection branch (n > 0), so the gradient sums over p : Fin N (corresponding to output rows n = p+1).

                                                                                                                  Equations
                                                                                                                  • One or more equations did not get rendered due to their size.
                                                                                                                  Instances For
                                                                                                                    noncomputable def Proofs.patchEmbedFlatHasVJP (ic H W patchSize N D : ℕ) (W_conv : Kernel4 D ic patchSize patchSize) (b_conv cls_token : Vec D) (pos_embed : Mat (N + 1) D) :
                                                                                                                    HasVJP (patchEmbedFlat ic H W patchSize N D W_conv b_conv cls_token pos_embed)

                                                                                                                    Patch embedding VJP — proved from foundation rules.

                                                                                                                    The forward is affine in img (pdiv_of_affine): the pad-guarded conv read, identically zero on the CLS row, plus the constant pos_embed + (cls_token | b_conv). Closing collapse mirrors conv2dHasVJP3, with one new wrinkle: split Σ n : Fin (N+1) into n = 0 (CLS row, contributes 0 to img-grad) + Σ p : Fin N (n = p+1) via Fin.sum_univ_succ.

                                                                                                                    Backward: patchEmbedInputGradFormula W_conv dy.

                                                                                                                    Equations
                                                                                                                    • One or more equations did not get rendered due to their size.
                                                                                                                    Instances For

                                                                                                                      The full ViT theorem #

                                                                                                                      Compose patch embed + ViT body (via the Mat→Vec bridge) + classifier. All three are HasVJPs on Vec, so vjpComp chains them directly.

                                                                                                                      noncomputable def Proofs.vitFull (gf : GeluForm) (ic H W patchSize N mlpDim heads d_head kBlocks nClasses : ℕ) (W_conv : Kernel4 (heads * d_head) ic patchSize patchSize) (b_conv cls_token : Vec (heads * d_head)) (pos_embed : Mat (N + 1) (heads * d_head)) (ε γ1 β1 : ℝ) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) (γ2 β2 : ℝ) (Wfc1 : Mat (heads * d_head) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d_head)) (bfc2 : Vec (heads * d_head)) (γF βF : ℝ) (Wcls : Mat (heads * d_head) nClasses) (bcls : Vec nClasses) :
                                                                                                                      Vec (ic * H * W) → Vec nClasses

                                                                                                                      vitFull — a weight-tied ViT forward from flattened image pixels to logits: all kBlocks transformer blocks share one parameter tuple, and every LayerNorm (γ1 β1, γ2 β2, final γF βF) is scalar-affine.

                                                                                                                      Vec (ic*H*W) → Vec nClasses

                                                                                                                      Composition: patchEmbed → (flatten ∘ vitBody ∘ unflatten) → classifier. Uses D := heads * d_head directly (no separate D parameter) so the type-level reinterpretation at the body is a no-op.

                                                                                                                      Equations
                                                                                                                      • One or more equations did not get rendered due to their size.
                                                                                                                      Instances For
                                                                                                                        theorem Proofs.classifierFlat_differentiable (N D nClasses : ℕ) (Wcls : Mat D nClasses) (bcls : Vec nClasses) :
                                                                                                                        Differentiable ℝ (classifierFlat N D nClasses Wcls bcls)

                                                                                                                        Differentiability of the classifier head — composition of linear ops.

                                                                                                                        noncomputable def Proofs.vitFullHasVJP (gf : GeluForm) (ic H W patchSize N mlpDim heads d_head kBlocks nClasses : ℕ) (W_conv : Kernel4 (heads * d_head) ic patchSize patchSize) (b_conv cls_token : Vec (heads * d_head)) (pos_embed : Mat (N + 1) (heads * d_head)) (ε γ1 β1 : ℝ) (hε : 0 < ε) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) (γ2 β2 : ℝ) (Wfc1 : Mat (heads * d_head) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d_head)) (bfc2 : Vec (heads * d_head)) (γF βF : ℝ) (Wcls : Mat (heads * d_head) nClasses) (bcls : Vec nClasses) :
                                                                                                                        HasVJP (vitFull gf ic H W patchSize N mlpDim heads d_head kBlocks nClasses W_conv b_conv cls_token pos_embed ε γ1 β1 Wq Wk Wv Wo bq bk bv bo γ2 β2 Wfc1 bfc1 Wfc2 bfc2 γF βF Wcls bcls)

                                                                                                                        vitFull VJP — the VJP of the weight-tied vitFull: three vjpComp steps glueing patchEmbedFlatHasVJP, HasVJPMat.toHasVJP (vitBodyHasVJPMat ...), and classifierFlatHasVJP. Each vjpComp's Diff hypotheses are discharged by the per-stage Diff theorems above.

                                                                                                                        Equations
                                                                                                                        • One or more equations did not get rendered due to their size.
                                                                                                                        Instances For

                                                                                                                          Public correctness theorems for the attention defs #

                                                                                                                          The HasVJP / HasVJPMat defs above bundle a backward function with a .correct field; these _correct theorems expose that field as a top-level proposition so consumers can refer to the contract directly without reaching into record internals.

                                                                                                                          theorem Proofs.mhsaHasVJPMat_correct (N heads d_head : ℕ) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) (X dY : Mat N (heads * d_head)) (i : Fin N) (j : Fin (heads * d_head)) :
                                                                                                                          (mhsaHasVJPMat N heads d_head Wq Wk Wv Wo bq bk bv bo).backward X dY i j = ∑ k : Fin N, ∑ l : Fin (heads * d_head), pdivMat (mhsaLayer N heads d_head Wq Wk Wv Wo bq bk bv bo) X i j k l * dY k l

                                                                                                                          Public correctness theorem for mhsaHasVJPMat: multi-head SDPA's backward equals the pdivMat-contracted Jacobian. The column-stacking proof (mhsaGHasVJPMat, colSlabwiseHasVJPMat) uses no project axiom.

                                                                                                                          theorem Proofs.transformerBlockHasVJPMat_correct {gf : GeluForm} (N heads d_head mlpDim : ℕ) (ε γ1 β1 : ℝ) (hε : 0 < ε) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) (γ2 β2 : ℝ) (Wfc1 : Mat (heads * d_head) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d_head)) (bfc2 : Vec (heads * d_head)) (X dY : Mat N (heads * d_head)) (i : Fin N) (j : Fin (heads * d_head)) :
                                                                                                                          (transformerBlockHasVJPMat gf N heads d_head mlpDim ε γ1 β1 hε Wq Wk Wv Wo bq bk bv bo γ2 β2 Wfc1 bfc1 Wfc2 bfc2).backward X dY i j = ∑ k : Fin N, ∑ l : Fin (heads * d_head), pdivMat (transformerBlock gf N heads d_head mlpDim ε γ1 β1 Wq Wk Wv Wo bq bk bv bo γ2 β2 Wfc1 bfc1 Wfc2 bfc2) X i j k l * dY k l

                                                                                                                          Public correctness theorem for transformerBlockHasVJPMat: the full transformer block backward (attention sublayer + MLP sublayer glued by vjpMatComp) equals the pdivMat-contracted Jacobian.

                                                                                                                          theorem Proofs.vitFullHasVJP_correct {gf : GeluForm} (ic H W patchSize N mlpDim heads d_head kBlocks nClasses : ℕ) (W_conv : Kernel4 (heads * d_head) ic patchSize patchSize) (b_conv cls_token : Vec (heads * d_head)) (pos_embed : Mat (N + 1) (heads * d_head)) (ε γ1 β1 : ℝ) (hε : 0 < ε) (Wq Wk Wv Wo : Mat (heads * d_head) (heads * d_head)) (bq bk bv bo : Vec (heads * d_head)) (γ2 β2 : ℝ) (Wfc1 : Mat (heads * d_head) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d_head)) (bfc2 : Vec (heads * d_head)) (γF βF : ℝ) (Wcls : Mat (heads * d_head) nClasses) (bcls : Vec nClasses) (x : Vec (ic * H * W)) (dy : Vec nClasses) (i : Fin (ic * H * W)) :
                                                                                                                          (vitFullHasVJP gf ic H W patchSize N mlpDim heads d_head kBlocks nClasses W_conv b_conv cls_token pos_embed ε γ1 β1 hε Wq Wk Wv Wo bq bk bv bo γ2 β2 Wfc1 bfc1 Wfc2 bfc2 γF βF Wcls bcls).backward x dy i = ∑ j : Fin nClasses, pdiv (vitFull gf ic H W patchSize N mlpDim heads d_head kBlocks nClasses W_conv b_conv cls_token pos_embed ε γ1 β1 Wq Wk Wv Wo bq bk bv bo γ2 β2 Wfc1 bfc1 Wfc2 bfc2 γF βF Wcls bcls) x i j * dy j

                                                                                                                          Public correctness theorem for vitFullHasVJP: the backward of vitFull (weight-tied blocks, scalar-affine LayerNorms) equals the pdiv-contracted Jacobian (Jacobian-transpose applied to the cotangent). Exposes the witness's .correct field as a top-level proposition so consumers (and #print axioms audits) can cite the apex contract directly instead of reaching into the record. The long signature is vitFull's parameter set; the proof is the witness field.