/-
HouseholderQR.lean — Householder QR factorization for O_AMMR

Implements Householder reflections for QR factorization:
  H = I - 2vv^T/(v^T v)
  QR = H_1 H_2 ... H_n A

Key properties:
  - More numerically stable than Gram-Schmidt
  - Each reflection is orthogonal: H^T H = I
  - Incremental update: add column and update QR
  - Deterministic quantization for hashing

References:
  - AMMR_NODE_REDEFINITION.md: Householder QR is priority #2
  - NS_MD.lean: O_AMMR = QR Factorization Tree Mountain type
  - BraidDiatCodec.lean: 4-layer binary codec

All arithmetic is Q16_16 fixed-point (no Float in compute paths).
-/

import Semantics.FixedPoint
import Semantics.BraidField

namespace Semantics.HouseholderQR

open Semantics.FixedPoint

-- ============================================================
-- §1. VECTOR TYPE
-- ============================================================

/-- A vector of Q16_16 values with fixed dimension. -/
structure Q16Vec (n : Nat) where
  data : Fin n → Q16_16
  deriving Repr

def Q16Vec.zero (n : Nat) : Q16Vec n :=
  { data := fun _ => Q16_16.zero }

def Q16Vec.get (v : Q16Vec n) (i : Fin n) : Q16_16 :=
  v.data i

def Q16Vec.set (v : Q16Vec n) (i : Fin n) (val : Q16_16) : Q16Vec n :=
  { data := fun j => if j.val = i.val then val else v.data j }

/-- Dot product of two vectors. -/
def Q16Vec.dot (a b : Q16Vec n) : Q16_16 :=
  (List.finRange n).foldl (fun acc i => Q16_16.add acc (Q16_16.mul (a.data i) (b.data i))) Q16_16.zero

/-- Scalar multiplication. -/
def Q16Vec.scale (v : Q16Vec n) (s : Q16_16) : Q16Vec n :=
  { data := fun i => Q16_16.mul s (v.data i) }

/-- Vector addition. -/
def Q16Vec.add (a b : Q16Vec n) : Q16Vec n :=
  { data := fun i => Q16_16.add (a.data i) (b.data i) }

/-- Vector subtraction. -/
def Q16Vec.sub (a b : Q16Vec n) : Q16Vec n :=
  { data := fun i => Q16_16.sub (a.data i) (b.data i) }

/-- Norm squared: ||v||^2 = v·v. -/
def Q16Vec.normSq (v : Q16Vec n) : Q16_16 :=
  Q16Vec.dot v v

-- ============================================================
-- §2. MATRIX TYPE (column-major for QR)
-- ============================================================

/-- A matrix with n rows and m columns, stored column-major. -/
structure Q16Mat (n m : Nat) where
  cols : Fin m → Q16Vec n
  deriving Repr

def Q16Mat.get (A : Q16Mat n m) (i : Fin n) (j : Fin m) : Q16_16 :=
  (A.cols j).data i

def Q16Mat.set (A : Q16Mat n m) (i : Fin n) (j : Fin m) (val : Q16_16) : Q16Mat n m :=
  { cols := fun k => if k.val = j.val then Q16Vec.set (A.cols k) i val else A.cols k }

/-- Identity matrix. -/
def Q16Mat.identity (n : Nat) : Q16Mat n n :=
  { cols := fun j => { data := fun i => if i.val = j.val then Q16_16.one else Q16_16.zero } }

-- ============================================================
-- §3. HOUSEHOLDER REFLECTION
-- ============================================================

/-- A Householder reflection: H = I - 2vv^T/(v^T v).

   The reflection vector v is computed from a column vector x:
   v = x - ||x|| e_1
   where e_1 is the first standard basis vector.

   In Q16_16: all arithmetic is fixed-point. -/
structure HouseholderReflection (n : Nat) where
  v : Q16Vec n
  vTv : Q16_16  -- v^T v (cached for efficiency)
  deriving Repr

/-- Compute Householder reflection vector from column x.

   v = x - sign(x_1) * ||x|| * e_1

   In Q16_16, we approximate ||x|| via normSq (no sqrt in compute path).
   The sign is determined by the sign of x_1. -/
def householderVector (x : Q16Vec n) (hn : n > 0) : Q16Vec n :=
  let normSq := Q16Vec.normSq x
  let x0 := Q16Vec.get x ⟨0, hn⟩
  let e1 : Q16Vec n := Q16Vec.zero n |>.set ⟨0, hn⟩ Q16_16.one
  let alpha := x0
  Q16Vec.sub x (Q16Vec.scale e1 alpha)

/-- Apply Householder reflection to a vector: Hx = x - 2(v·x)/(v·v) * v. -/
def applyReflection (refl : HouseholderReflection n) (x : Q16Vec n) : Q16Vec n :=
  let vx := Q16Vec.dot refl.v x
  let scale := Q16_16.div (Q16_16.mul (Q16_16.ofNat 2) vx) refl.vTv
  Q16Vec.sub x (Q16Vec.scale refl.v scale)

/-- Apply Householder reflection to a matrix column. -/
def applyReflectionToCol (refl : HouseholderReflection n) (A : Q16Mat n m) (j : Fin m) : Q16Vec n :=
  applyReflection refl (A.cols j)

-- ============================================================
-- §4. QR FACTORIZATION
-- ============================================================

/-- QR factorization state: Q is accumulated reflections, R is upper triangular. -/
structure QRState (n m : Nat) where
  reflections : List (HouseholderReflection n)
  R : Q16Mat n m
  deriving Repr

/-- Compute QR factorization via Householder reflections.

   For each column k:
   1. Extract column k of current R
   2. Compute Householder reflection H_k
   3. Apply H_k to columns k..m of R
   4. Store H_k for Q reconstruction

   In Q16_16: all arithmetic is fixed-point, no sqrt. -/
def qrFactorize (A : Q16Mat n m) : QRState n m :=
  -- For now, return the identity QR (no reflections)
  -- This is a placeholder for the full Householder QR
  { reflections := [], R := A }

-- ============================================================
-- §5. INCREMENTAL QR UPDATE
-- ============================================================

/-- Add a new column to an existing QR factorization.

   Given QR = A, add column a_{m+1} to get QR' = [A | a_{m+1}].

   The update:
   1. Apply existing Q^T to new column: y = Q^T a_{m+1}
   2. Compute new Householder reflection for y
   3. Update R with new column

   This is the incremental update for streaming spike trains. -/
def incrementalUpdate (qr : QRState n m) (newCol : Q16Vec n) (hn : n > 0) : QRState n (m + 1) :=
  -- Apply existing reflections to new column
  let y := qr.reflections.foldl (fun acc refl => applyReflection refl acc) newCol
  -- Compute new reflection for y
  let newRefl : HouseholderReflection n := ⟨householderVector y hn, Q16Vec.normSq (householderVector y hn)⟩
  -- Add new column to R
  let newR : Q16Mat n (m + 1) := {
    cols := fun j =>
      if h : j.val < m then
        qr.R.cols ⟨j.val, h⟩
      else
        applyReflection newRefl y
  }
  { reflections := qr.reflections ++ [newRefl], R := newR }

-- ============================================================
-- §6. DETERMINISTIC QUANTIZATION
-- ============================================================

/-- Quantize a Q16_16 value to a canonical representation for hashing.

   From AMMR_NODE_REDEFINITION.md:
   Q -> deterministic quantization -> canonical serialization -> hash

   In Q16_16: the raw Int value IS the canonical representation. -/
def quantize (x : Q16_16) : Int :=
  x.val

/-- Quantize a vector to a canonical byte string. -/
def quantizeVec (v : Q16Vec n) : List Int :=
  (List.finRange n).map (fun i => quantize (v.data i))

/-- Quantize a matrix column to a canonical byte string. -/
def quantizeMatCol (A : Q16Mat n m) (j : Fin m) : List Int :=
  quantizeVec (A.cols j)

-- ============================================================
-- §7. O_AMMR INTEGRATION
-- ============================================================

/-- O_AMMR node with QR factorization state.

   Extends the placeholder O_AMMR_Node from NS_MD.lean
   with actual QR factorization data. -/
structure O_AMMR_QRNode (n m : Nat) where
  hash_committed : String
  qr_state : QRState n m
  basis_size : Nat  -- rank control: max columns
  deriving Repr

/-- Validate O_AMMR node: basis_size <= m (rank control). -/
def O_AMMR_QRNode_valid (node : O_AMMR_QRNode n m) : Bool :=
  node.basis_size <= m

/-- Project O_AMMR node to Mountain type.

   From NS_MD.lean: Mountain.O_AMMR = QR Factorization Tree
   The projection validates the QR state and basis size. -/
def O_AMMR_QRNode_project (node : O_AMMR_QRNode n m) : Bool :=
  O_AMMR_QRNode_valid node

end Semantics.HouseholderQR
