///|
/// LayerNorm over a 1D array.
/// x, gamma, beta shape: (features)
pub fn layer_norm(
  x : Array[Double],
  gamma : Array[Double],
  beta : Array[Double],
  eps : Double,
) -> Array[Double] {
  let len = x.length()
  let output = Array::make(len, 0.0)
  if len == 0 {
    output
  } else {
    let mut mean = 0.0
    for i = 0; i < len; i = i + 1 {
      mean = mean + x[i]
    }
    mean = mean / len.to_double()
    let mut variance = 0.0
    for i = 0; i < len; i = i + 1 {
      let diff = x[i] - mean
      variance = variance + diff * diff
    }
    variance = variance / len.to_double()
    let scale = 1.0 / (variance + eps).sqrt()
    for i = 0; i < len; i = i + 1 {
      output[i] = (x[i] - mean) * scale * gamma[i] + beta[i]
    }
    output
  }
}

///|
/// RMSNorm over a 1D array.
/// x, gamma shape: (features)
pub fn rms_norm(
  x : Array[Double],
  gamma : Array[Double],
  eps : Double,
) -> Array[Double] {
  let len = x.length()
  let output = Array::make(len, 0.0)
  if len == 0 {
    output
  } else {
    let mut mean_square = 0.0
    for i = 0; i < len; i = i + 1 {
      mean_square = mean_square + x[i] * x[i]
    }
    mean_square = mean_square / len.to_double()
    let scale = 1.0 / (mean_square + eps).sqrt()
    for i = 0; i < len; i = i + 1 {
      output[i] = x[i] * scale * gamma[i]
    }
    output
  }
}