///|
// =====================================================================
// symm.mbt — 對稱矩陣空間 Sym(n) ⊂ M_n(R),Frobenius 內積
// 維數 n(n+1)/2;正交投影 = 對稱化(定理自證於 symm_wbtest.mbt)
// =====================================================================

/// S-1 對稱空間維數 n(n+1)/2
pub fn sym_dim(n : Int) -> Int {
  n * (n + 1) / 2
}

/// S-2 上三角座標 (i≤j) → 線性索引
pub fn sym_index(n : Int, i : Int, j : Int) -> Int {
  let a = if i <= j { i } else { j }
  let b = if i <= j { j } else { i }
  // 前 a 行共有 a*n - a*(a-1)/2 個元素
  a * n - a * (a - 1) / 2 + (b - a)
}

/// S-3 向量打包為對稱矩陣(維數 n(n+1)/2 之座標)
pub fn sym_pack(n : Int, v : Array[Double]) -> Mat {
  let out = mat_new(n, n)
  for i = 0; i < n; i = i + 1 {
    for j = i; j < n; j = j + 1 {
      let x = v[sym_index(n, i, j)]
      mat_set(out, i, j, x)
      mat_set(out, j, i, x)
    }
  }
  out
}

/// S-4 對稱矩陣展開為向量(pack 之逆)
pub fn sym_unpack(m : Mat) -> Array[Double] {
  let n = m.rows
  let out : Array[Double] = []
  for i = 0; i < n; i = i + 1 {
    for j = i; j < n; j = j + 1 {
      out.push(mat_get(m, i, j))
    }
  }
  out
}

/// S-5 Sym(n) 加法
pub fn sym_add(a : Mat, b : Mat) -> Mat {
  mat_add(a, b)
}

/// S-6 Sym(n) 純量乘法
pub fn sym_scale(c : Double, a : Mat) -> Mat {
  mat_scale(c, a)
}

/// S-7 Sym(n) 內積(Frobenius 限制)
pub fn sym_inner(a : Mat, b : Mat) -> Double {
  mat_frob_inner(a, b)
}

/// S-8 Sym(n) 向量空間字典
pub fn sym_sp(n : Int) -> VecSp[Mat] {
  {
    zero: mat_new(n, n),
    add: sym_add,
    neg: fn(m) { mat_scale(-1.0, m) },
    scale: sym_scale,
  }
}

/// S-9 Sym(n) 內積空間字典
pub fn sym_ip(n : Int) -> IPSp[Mat] {
  ips_make(sym_sp(n), sym_inner)
}

/// S-10 Sym(n) 標準正交基:{E_ii} ∪ {(E_ij+E_ji)/√2}
pub fn sym_basis(n : Int) -> Array[Mat] {
  let out : Array[Mat] = []
  for i = 0; i < n; i = i + 1 {
    let m = mat_new(n, n)
    mat_set(m, i, i, 1.0)
    out.push(m)
  }
  for i = 0; i < n; i = i + 1 {
    for j = i + 1; j < n; j = j + 1 {
      let m = mat_new(n, n)
      let c = 1.0 / (2.0).sqrt()
      mat_set(m, i, j, c)
      mat_set(m, j, i, c)
      out.push(m)
    }
  }
  out
}

/// S-11 譜定理驗證用:對稱矩陣特徵分解重構誤差
pub fn sym_spectral_error(a : Mat) -> Double {
  let n = a.rows
  let (vals, q) = jacobi_eigen(a, 60)
  let recon = spectral_reconstruct(vals, q)
  let _ = n
  mat_frob_norm(mat_sub(a, recon))
}

/// S-12 二次型 q(x) = xᵀAx
pub fn sym_quadratic(a : Mat, x : Array[Double]) -> Double {
  euc_inner(x, mat_vec(a, x))
}