///|
// =====================================================================
// exterior.mbt — 外代數 Λ^k(R^n)
// 分量按遞增 k-組合索引;外積、Hodge 星、內縮、體積
// =====================================================================

/// k-向量(Λ^k(R^n) 之元素)
pub struct ExtVec {
  n : Int
  k : Int
  data : Array[Double] // 長度 C(n, k),按組合字典序
} derive(Debug, Eq)

/// X-1 組合數 C(n, k)
pub fn comb_count(n : Int, k : Int) -> Int {
  if k < 0 || k > n {
    0
  } else {
    let mut num = 1.0
    let mut den = 1.0
    for i = 1; i <= k; i = i + 1 {
      num = num * (n - k + i).to_double()
      den = den * i.to_double()
    }
    (num / den + 0.5).trunc().to_int()
  }
}

/// 列舉全部遞增 k-組合(字典序)
pub fn comb_list(n : Int, k : Int) -> Array[Array[Int]] {
  let out : Array[Array[Int]] = []
  if k == 0 {
    out.push([])
    return out
  }
  let cur = Array::make(k, 0)
  fn rec(pos : Int, start : Int) -> Unit {
    if pos == k {
      out.push(cur.copy())
      return
    }
    for v = start; v <= n - (k - pos); v = v + 1 {
      cur[pos] = v
      rec(pos + 1, v + 1)
    }
  }
  rec(0, 0)
  out
}

/// X-2 組合 → 分量索引
pub fn comb_index(combs : Array[Array[Int]], c : Array[Int]) -> Int {
  let mut idx = -1
  for i = 0; i < combs.length(); i = i + 1 {
    let mut eq = true
    for j = 0; j < c.length(); j = j + 1 {
      if combs[i][j] != c[j] {
        eq = false
      }
    }
    if eq {
      idx = i
    }
  }
  idx
}

/// X-3 逆序數(排列奇偶性用)
pub fn inversion_count(p : Array[Int]) -> Int {
  let mut inv = 0
  for i = 0; i < p.length(); i = i + 1 {
    for j = i + 1; j < p.length(); j = j + 1 {
      if p[i] > p[j] {
        inv = inv + 1
      }
    }
  }
  inv
}

/// X-4 Λ^k 之零元素
pub fn ext_zero(n : Int, k : Int) -> ExtVec {
  { n, k, data: Array::make(comb_count(n, k), 0.0) }
}

/// X-5 向量 v ∈ R^n 嵌入 Λ^1
pub fn ext_from_vec(n : Int, v : Array[Double]) -> ExtVec {
  { n, k: 1, data: v.copy() }
}

/// X-6 外積 u ∧ v(兩個 1-向量 → 2-向量)
pub fn ext_wedge_vecs(n : Int, u : Array[Double], v : Array[Double]) -> ExtVec {
  let combs = comb_list(n, 2)
  let out = ext_zero(n, 2)
  for idx = 0; idx < combs.length(); idx = idx + 1 {
    let i = combs[idx][0]
    let j = combs[idx][1]
    out.data[idx] = u[i] * v[j] - u[j] * v[i]
  }
  out
}

/// X-7 一般外積:α ∈ Λ^p ∧ β ∈ Λ^q → Λ^{p+q}
pub fn ext_wedge(a : ExtVec, b : ExtVec) -> ExtVec {
  let n = a.n
  let p = a.k
  let q = b.k
  let ca = comb_list(n, p)
  let cb = comb_list(n, q)
  let cc = comb_list(n, p + q)
  let out = ext_zero(n, p + q)
  for ia = 0; ia < ca.length(); ia = ia + 1 {
    for ib = 0; ib < cb.length(); ib = ib + 1 {
      let coef = a.data[ia] * b.data[ib]
      if coef == 0.0 {
        continue
      }
      // 合併指數集;若相交則該項為 0
      let merged : Array[Int] = []
      let used = Array::make(n, false)
      let mut ok = true
      for x in ca[ia] {
        if used[x] {
          ok = false
        }
        used[x] = true
      }
      for x in cb[ib] {
        if used[x] {
          ok = false
        }
        used[x] = true
      }
      if !ok {
        continue
      }
      // 合併排列之奇偶性 = 交織符號
      let concat : Array[Int] = []
      for x in ca[ia] {
        concat.push(x)
      }
      for x in cb[ib] {
        concat.push(x)
      }
      for x = 0; x < n; x = x + 1 {
        if used[x] {
          merged.push(x)
        }
      }
      let sign = if inversion_count(concat) % 2 == 0 { 1.0 } else { -1.0 }
      let idx = comb_index(cc, merged)
      out.data[idx] = out.data[idx] + sign * coef
    }
  }
  out
}

/// X-8 Λ^k 之誘導內積(單形分量逐點積;對一般元素用 Gram 行列式性質)
pub fn ext_inner(a : ExtVec, b : ExtVec) -> Double {
  let mut s = 0.0
  for i = 0; i < a.data.length(); i = i + 1 {
    s = s + a.data[i] * b.data[i]
  }
  s
}

/// X-9 k-向量範數(= 對應平行體之體積,當為純量時)
pub fn ext_norm(a : ExtVec) -> Double {
  ext_inner(a, a).sqrt()
}

/// X-10 Hodge 星 ⋆ : Λ^k → Λ^{n−k}(標準定向)
pub fn ext_hodge_star(a : ExtVec) -> ExtVec {
  let n = a.n
  let k = a.k
  let ck = comb_list(n, k)
  let cnk = comb_list(n, n - k)
  let out = ext_zero(n, n - k)
  for idx = 0; idx < ck.length(); idx = idx + 1 {
    if a.data[idx] == 0.0 {
      continue
    }
    let used = Array::make(n, false)
    for x in ck[idx] {
      used[x] = true
    }
    let comp : Array[Int] = []
    for x = 0; x < n; x = x + 1 {
      if !used[x] {
        comp.push(x)
      }
    }
    // 符號 = (ck[idx] ++ comp) 之奇偶性
    let perm : Array[Int] = []
    for x in ck[idx] {
      perm.push(x)
    }
    for x in comp {
      perm.push(x)
    }
    let sign = if inversion_count(perm) % 2 == 0 { 1.0 } else { -1.0 }
    let j = comb_index(cnk, comp)
    out.data[j] = sign * a.data[idx]
  }
  out
}

/// X-11 內縮 i_v : Λ^k → Λ^{k−1}(與向量之內積)
pub fn ext_interior(v : Array[Double], a : ExtVec) -> ExtVec {
  let n = a.n
  let k = a.k
  if k == 0 {
    return ext_zero(n, 0)
  }
  let ck = comb_list(n, k)
  let ck1 = comb_list(n, k - 1)
  let out = ext_zero(n, k - 1)
  for idx = 0; idx < ck.length(); idx = idx + 1 {
    let coef = a.data[idx]
    if coef == 0.0 {
      continue
    }
    for pos = 0; pos < k; pos = pos + 1 {
      let removed : Array[Int] = []
      for j = 0; j < k; j = j + 1 {
        if j != pos {
          removed.push(ck[idx][j])
        }
      }
      let sign = if pos % 2 == 0 { 1.0 } else { -1.0 }
      let j = comb_index(ck1, removed)
      out.data[j] = out.data[j] + sign * v[ck[idx][pos]] * coef
    }
  }
  out
}

/// X-12 頂層外積判定行列式:v_1 ∧ … ∧ v_n = det(V)·e₁∧…∧e_n
pub fn ext_det(vectors : Array[Array[Double]]) -> Double {
  let n = vectors.length()
  if n == 0 {
    return 1.0
  }
  let mut acc = ext_from_vec(n, vectors[0])
  for i = 1; i < n; i = i + 1 {
    acc = ext_wedge(acc, ext_from_vec(n, vectors[i]))
  }
  acc.data[0]
}

/// X-13 R³ 叉積由外代數導出:u × v = ⋆(u ∧ v)
pub fn ext_cross3(u : Array[Double], v : Array[Double]) -> Array[Double] {
  let w = ext_wedge_vecs(3, u, v)
  let s = ext_hodge_star(w)
  s.data.copy()
}

/// X-14 Λ^k 之內積空間字典
pub fn ext_ip(n : Int, k : Int) -> IPSp[ExtVec] {
  ips_make(
    {
      zero: ext_zero(n, k),
      add: fn(a, b) {
        let out = ext_zero(n, k)
        for i = 0; i < a.data.length(); i = i + 1 {
          out.data[i] = a.data[i] + b.data[i]
        }
        out
      },
      neg: fn(a) {
        let out = ext_zero(n, k)
        for i = 0; i < a.data.length(); i = i + 1 {
          out.data[i] = -a.data[i]
        }
        out
      },
      scale: fn(c, a) {
        let out = ext_zero(n, k)
        for i = 0; i < a.data.length(); i = i + 1 {
          out.data[i] = c * a.data[i]
        }
        out
      },
    },
    ext_inner,
  )
}

/// X-15 兩向量張成平行四邊形之面積 = ‖u ∧ v‖
pub fn ext_parallelogram_area(u : Array[Double], v : Array[Double]) -> Double {
  ext_norm(ext_wedge_vecs(u.length(), u, v))
}