///|
/// Naive 1D convolution (no padding, stride=1).
/// 
/// Input shape:  (C_in, L)        flat layout: input[c * L + l]
/// Kernel shape: (C_out, C_in, K) flat layout: kernel[o * C_in * K + c * K + k]
/// Output shape: (C_out, L - K + 1)
pub fn conv1d(
  input : Array[Double],
  kernel : Array[Double],
  c_in : Int,
  l : Int,
  c_out : Int,
  k : Int,
) -> Array[Double] {
  let l_out = l - k + 1
  let output = Array::make(c_out * l_out, 0.0)
  for o = 0; o < c_out; o = o + 1 {
    for x = 0; x < l_out; x = x + 1 {
      let mut sum = 0.0
      for c = 0; c < c_in; c = c + 1 {
        for kk = 0; kk < k; kk = kk + 1 {
          let in_val = input[c * l + (x + kk)]
          let w_val = kernel[o * c_in * k + c * k + kk]
          sum = sum + in_val * w_val
        }
      }
      output[o * l_out + x] = sum
    }
  }
  output
}