///|
// =====================================================================
// product.mbt — 空間組合子:直和(積空間)、對角嵌入、加權組合
// 「空間 × 空間」之組合,可迭代套用(如 Fun(X, Sym(n)) ≅ 直和)
// =====================================================================

/// PR-1 向量空間直和 V ⊕ W
pub fn[V, W] vec_prod(a : VecSp[V], b : VecSp[W]) -> VecSp[(V, W)] {
  {
    zero: (a.zero, b.zero),
    add: fn(p, q) { ((a.add)(p.0, q.0), (b.add)(p.1, q.1)) },
    neg: fn(p) { ((a.neg)(p.0), (b.neg)(p.1)) },
    scale: fn(c, p) { ((a.scale)(c, p.0), (b.scale)(c, p.1)) },
  }
}

/// PR-2 內積空間直和:⟨(v₁,w₁),(v₂,w₂)⟩ = ⟨v₁,v₂⟩ + ⟨w₁,w₂⟩
pub fn[V, W] ips_prod(a : IPSp[V], b : IPSp[W]) -> IPSp[(V, W)] {
  ips_make(
    vec_prod(a.sp, b.sp),
    fn(p, q) { (a.inner)(p.0, q.0) + (b.inner)(p.1, q.1) },
  )
}

/// PR-3 加權直和:⟨,⟩ = α⟨,⟩_V + β⟨,⟩_W
pub fn[V, W] ips_prod_weighted(
  a : IPSp[V],
  b : IPSp[W],
  alpha : Double,
  beta : Double,
) -> IPSp[(V, W)] {
  ips_make(
    vec_prod(a.sp, b.sp),
    fn(p, q) { alpha * (a.inner)(p.0, q.0) + beta * (b.inner)(p.1, q.1) },
  )
}

/// PR-4 對角嵌入 Δ : V → V ⊕ V,v ↦ (v, v)
pub fn[V] diag_embed(v : V) -> (V, V) {
  (v, v)
}

/// PR-5 投影 π₁ : V ⊕ W → V
pub fn[V, W] prod_proj1(p : (V, W)) -> V {
  p.0
}

/// PR-6 投影 π₂ : V ⊕ W → W
pub fn[V, W] prod_proj2(p : (V, W)) -> W {
  p.1
}

/// PR-7 單射 ι₁ : V → V ⊕ W(w 取零)
pub fn[V, W] inj1(a : IPSp[V], b : IPSp[W], v : V) -> (V, W) {
  (v, b.sp.zero)
}

/// PR-8 單射 ι₂ : W → V ⊕ W
pub fn[V, W] inj2(a : IPSp[V], b : IPSp[W], w : W) -> (V, W) {
  (a.sp.zero, w)
}

/// PR-9 直和維數相加
pub fn prod_dim_sum(dv : Int, dw : Int) -> Int {
  dv + dw
}

/// PR-10 線性映射直和 A ⊕ B 之矩陣(分塊對角)
pub fn map_direct_sum(a : Mat, b : Mat) -> Mat {
  let out = mat_new(a.rows + b.rows, a.cols + b.cols)
  for i = 0; i < a.rows; i = i + 1 {
    for j = 0; j < a.cols; j = j + 1 {
      mat_set(out, i, j, mat_get(a, i, j))
    }
  }
  for i = 0; i < b.rows; i = i + 1 {
    for j = 0; j < b.cols; j = j + 1 {
      mat_set(out, a.rows + i, a.cols + j, mat_get(b, i, j))
    }
  }
  out
}