TorchLean API

NN.MLTheory.Proofs.StateSpace.Scan

Proofs for affine selective scan #

The Mamba/S4 scan theorem is an algebra theorem about affine maps. A sequential recurrent update and a parallel prefix scan are equivalent because affine transition composition is associative:

$$ (a_2,b_2)\circ(a_1,b_1)=(a_2a_1,a_2b_1+b_2). $$

Over a semiring, prefix summaries denote the same state as the left-to-right recurrence. This does not assert equality between differently ordered floating-point computations or verify a native implementation. The stateful scan and prefix-causality results preserve the sequential step order and do not require semiring laws.

@[simp]
theorem NN.MLTheory.StateSpace.ScalarAffineTransition.compose_apply {α : Type} [Semiring α] (t₂ t₁ : Spec.ScalarAffineTransition α) (h : α) :
(t₂.compose t₁).apply h = t₂.apply (t₁.apply h)

Composing scalar affine transitions agrees with function composition.

@[simp]

The identity transition is a left identity for composition.

@[simp]

The identity transition is a right identity for composition.

@[simp]
theorem NN.MLTheory.StateSpace.ScalarAffineTransition.compose_assoc {α : Type} [Semiring α] (t₃ t₂ t₁ : Spec.ScalarAffineTransition α) :
(t₃.compose t₂).compose t₁ = t₃.compose (t₂.compose t₁)

Scalar affine transition composition is associative.

@[simp]

Zero is a fixed point of a homogeneous scalar transition.

@[simp]
theorem NN.MLTheory.StateSpace.DiagonalTransition.apply_getScalar {α : Type} [Add α] [Mul α] {stateDim : ℕ} (tr : Spec.DiagonalTransition α stateDim) (h : TorchLean.Tensor α [stateDim]) (i : Fin stateDim) :
(tr.apply h).getScalar i = tr.a.getScalar i * h.getScalar i + tr.b.getScalar i

Applying a diagonal transition is exactly the scalar affine update in each channel.

@[simp]
theorem NN.MLTheory.StateSpace.DiagonalTransition.compose_apply_getScalar {α : Type} [Semiring α] {stateDim : ℕ} (t₂ t₁ : Spec.DiagonalTransition α stateDim) (h : TorchLean.Tensor α [stateDim]) (i : Fin stateDim) :
((t₂.compose t₁).apply h).getScalar i = (t₂.apply (t₁.apply h)).getScalar i

Composing diagonal transitions agrees channelwise with composing the corresponding scalar affine maps. This is the exact algebraic invariant used by the variable-coefficient selective-scan kernel: each flattened state lane is an independent affine scan.

theorem NN.MLTheory.StateSpace.scanArrayFrom_eq {State Input Output : Type} (step : State → Input → State × Output) (initial : State) (initialOutputs : Array Output) (xs : Array Input) :
Spec.scanArrayFrom step initial initialOutputs xs = have result := Spec.scanArray step initial xs; (result.1, initialOutputs ++ result.2)

Seeding a scan with existing output preserves its state evolution and prepends that output.

theorem NN.MLTheory.StateSpace.scanArrayFrom_state_eq_foldl {State Input Output : Type} (step : State → Input → State × Output) (initial : State) (initialOutputs : Array Output) (xs : Array Input) :
(Spec.scanArrayFrom step initial initialOutputs xs).1 = Array.foldl (fun (state : State) (input : Input) => (step state input).1) initial xs

The output buffer carried by a scan does not affect its final state.

theorem NN.MLTheory.StateSpace.scanArray_state_eq_foldl {State Input Output : Type} (step : State → Input → State × Output) (initial : State) (xs : Array Input) :
(Spec.scanArray step initial xs).1 = Array.foldl (fun (state : State) (input : Input) => (step state input).1) initial xs

The state component of scanArray is the ordinary state-only left fold.

theorem NN.MLTheory.StateSpace.scanArray_append {State Input Output : Type} (step : State → Input → State × Output) (initial : State) (xs ys : Array Input) :
Spec.scanArray step initial (xs ++ ys) = have first := Spec.scanArray step initial xs; have second := Spec.scanArray step first.1 ys; (second.1, first.2 ++ second.2)

A scan over appended inputs is the prefix scan followed by the state-dependent suffix scan.

theorem NN.MLTheory.StateSpace.scanArray_append_outputs_take {State Input Output : Type} (step : State → Input → State × Output) (initial : State) (xs ys : Array Input) :
(Spec.scanArray step initial (xs ++ ys)).2.take xs.size = (Spec.scanArray step initial xs).2

Appending future inputs cannot change outputs already emitted by a stateful scan.

Running appended scalar transitions factors through the state reached after the prefix.

@[simp]

Running one scalar transition is the same as applying it.

The affine summary denotes the same state as the sequential recurrence.

Prefix summaries compose across array append in execution order.

Scanning appended scalar transitions is the prefix scan followed by the suffix scan.

Running appended diagonal transitions factors through the state after the prefix.

The diagonal scan of an append is the prefix scan followed by the state-dependent suffix scan.

theorem NN.MLTheory.StateSpace.abs_homogeneous_apply_le (a ρ h : ℝ) (ha : |a| ≤ ρ) :
|{ a := a, b := 0 }.apply h| ≤ ρ * |h|

A homogeneous affine transition over $\mathbb{R}$ is Lipschitz with factor $\rho$ whenever $|a|\leq\rho$.

This is the one-channel stability lemma used to lift diagonal SSMs into contraction proofs.

theorem NN.MLTheory.StateSpace.abs_homogeneous_apply_le_self (a h : ℝ) (ha : |a| ≤ 1) :
|{ a := a, b := 0 }.apply h| ≤ |h|

A homogeneous scalar transition with $|a|\leq 1$ is non-expansive.