///|
// =====================================================================
// fspace.mbt — 有限集合上函數空間 Fun(X, F)(X = {0,…,n−1})
// 加權 ℓ² 內積、DFT、卷積、差分;可與任意內積空間 V 組合成
// Fun(X, V)(見 F-11)
// =====================================================================

/// F-1 加權 ℓ² 內積 Σ wᵢ f(i) g(i)
pub fn fn_inner_weighted(
  f : Array[Double],
  g : Array[Double],
  w : Array[Double],
) -> Double {
  let mut s = 0.0
  for i = 0; i < f.length(); i = i + 1 {
    s = s + w[i] * f[i] * g[i]
  }
  s
}

/// F-2 標準(等權)內積
pub fn fn_inner(f : Array[Double], g : Array[Double]) -> Double {
  let w = Array::make(f.length(), 1.0)
  fn_inner_weighted(f, g, w)
}

/// F-3 Fun(X, R) 內積空間字典(加權)
pub fn fn_ip(n : Int, w : Array[Double]) -> IPSp[Array[Double]] {
  ips_make(euc_sp(n), fn(a, b) { fn_inner_weighted(a, b, w) })
}

/// F-4 delta 基 {δ_0,…,δ_{n−1}}
pub fn fn_delta_basis(n : Int) -> Array[Array[Double]] {
  euc_basis(n)
}

/// F-5 逐點乘法(代數結構)
pub fn fn_pointwise_mul(f : Array[Double], g : Array[Double]) -> Array[Double] {
  euc_hadamard(f, g)
}

/// F-6 總和泛函
pub fn fn_sum(f : Array[Double]) -> Double {
  euc_sum(f)
}

/// F-7 循環前向差分 (Δf)(i) = f(i+1) − f(i)(指標模 n)
pub fn fn_finite_diff(f : Array[Double]) -> Array[Double] {
  let n = f.length()
  let out = Array::make(n, 0.0)
  for i = 0; i < n; i = i + 1 {
    out[i] = f[(i + 1) % n] - f[i]
  }
  out
}

/// F-8 離散傅里葉變換:F[k] = Σⱼ f[j] e^{−2πi·jk/n}
pub fn fn_dft(f : Array[C]) -> Array[C] {
  let n = f.length()
  let out : Array[C] = []
  for k = 0; k < n; k = k + 1 {
    let mut s = czero()
    for j = 0; j < n; j = j + 1 {
      let ang = -2.0 * @math.PI * j.to_double() * k.to_double() /
        n.to_double()
      s = cadd(s, cmul(f[j], cpolar(1.0, ang)))
    }
    out.push(s)
  }
  out
}

/// F-9 逆 DFT:f[j] = (1/n) Σₖ F[k] e^{2πi·jk/n}
pub fn fn_idft(fc : Array[C]) -> Array[C] {
  let n = fc.length()
  let out : Array[C] = []
  for j = 0; j < n; j = j + 1 {
    let mut s = czero()
    for k = 0; k < n; k = k + 1 {
      let ang = 2.0 * @math.PI * j.to_double() * k.to_double() /
        n.to_double()
      s = cadd(s, cmul(fc[k], cpolar(1.0, ang)))
    }
    out.push(cscale(1.0 / n.to_double(), s))
  }
  out
}

/// F-10 循環卷積 (f ∗ g)(k) = Σⱼ f[j] g(k−j mod n)
pub fn fn_convolution(f : Array[Double], g : Array[Double]) -> Array[Double] {
  let n = f.length()
  let out = Array::make(n, 0.0)
  for k = 0; k < n; k = k + 1 {
    let mut s = 0.0
    for j = 0; j < n; j = j + 1 {
      s = s + f[j] * g[(k - j + n) % n]
    }
    out[k] = s
  }
  out
}

/// F-11 函數空間組合子:Fun(X, V),V 為任意內積空間
/// 內積 = Σᵢ wᵢ ⟨f(i), g(i)⟩_V(空間 × 空間之組合)
pub fn[V] fn_space_ip(
  n : Int,
  w : Array[Double],
  ip : IPSp[V],
) -> IPSp[Array[V]] {
  let zero : Array[V] = []
  for _i = 0; _i < n; _i = _i + 1 {
    zero.push(ip.sp.zero)
  }
  ips_make(
    {
      zero,
      add: fn(f, g) {
        let out : Array[V] = []
        for i = 0; i < f.length(); i = i + 1 {
          out.push((ip.sp.add)(f[i], g[i]))
        }
        out
      },
      neg: fn(f) {
        let out : Array[V] = []
        for v in f {
          out.push((ip.sp.neg)(v))
        }
        out
      },
      scale: fn(c, f) {
        let out : Array[V] = []
        for v in f {
          out.push((ip.sp.scale)(c, v))
        }
        out
      },
    },
    fn(f, g) {
      let mut s = 0.0
      for i = 0; i < f.length(); i = i + 1 {
        s = s + w[i] * (ip.inner)(f[i], g[i])
      }
      s
    },
  )
}

/// F-12 Parseval 殘差 ‖f‖² − (1/n)‖F‖²(對 DFT 必為 0)
pub fn fn_parseval_residual(f : Array[C]) -> Double {
  let n = f.length()
  let fc = fn_dft(f)
  let mut lhs = 0.0
  for x in f {
    lhs = lhs + cnorm2(x)
  }
  let mut rhs = 0.0
  for x in fc {
    rhs = rhs + cnorm2(x)
  }
  lhs - rhs / n.to_double()
}