// gelu_backward.mbt — GELU backward pass.
//
// GELU forward (tanh approximation):
//   inner  = √(2/π) · (x + 0.044715 · x³)
//   t      = tanhf(inner)
//   y      = 0.5 · x · (1 + t)
//
// dgelu/dx = ∂y/∂x
//          = 0.5·(1 + t)                                  [product rule, 2nd term]
//          + 0.5·x · sech²(inner) · d(inner)/dx         [chain rule]
//          = 0.5·(1 + t)
//          + 0.5·x · (1 - t²) · √(2/π) · (1 + 3·0.044715·x²)

///|
/// GELU scalar derivative dgelu/dx (tanh approximation).
pub fn gelu_grad(x : Float) -> Float {
  let x2 = x * x
  let x3 = x2 * x
  let inner = 0.7978845608028654F * (x + 0.044715F * x3)
  let t = tanhf(inner)
  let sech2 = 1.0F - t * t
  let d_inner_dx = 0.7978845608028654F * (1.0F + 3.0F * 0.044715F * x2)
  0.5F * (1.0F + t) + 0.5F * x * sech2 * d_inner_dx
}

///|
/// GELU backward pass. `input` is the original forward input;
/// `d_output` is the upstream gradient. Returns `d_input` (new array).
pub fn gelu_backward(
  input : Array[Float],
  d_output : Array[Float],
) -> Array[Float] {
  let n = input.length()
  let d_input : Array[Float] = Array::make(n, 0.0F)
  for i in 0..