///|
/// `erff` from libm. MoonBit's `@math` has no error function, and GELU in both
/// ModernBERT and the Laya heads is the exact `erf` form rather than the `tanh`
/// approximation, so an approximation here would show up as a real parity gap.
extern "c" fn erff(x : Float) -> Float = "erff"
///|
/// Allocate a zeroed activation buffer.
pub fn zeros(len : Int) -> FixedArray[Float] {
FixedArray::make(len, 0.0)
}
///|
/// Layer normalisation over the last axis of a `[rows, cols]` buffer.
///
/// Means and variances accumulate in `Double` — at `cols = 1024` the float32
/// sums drift enough to be visible against the reference.
pub fn layer_norm(
x : FixedArray[Float],
out : FixedArray[Float],
rows~ : Int,
cols~ : Int,
gamma : FixedArray[Float],
beta : FixedArray[Float]?,
eps~ : Float,
) -> Unit {
let eps = eps.to_double()
for row in 0..
for i in 0..
for i in 0.. Float {
0.5 * x * (1.0 + erff(x * Float::from_double(1.0 / Double::sqrt(2.0))))
}
///|
/// GeGLU over a `[rows, 2 · inner]` buffer produced by ModernBERT's `Wi`.
///
/// `Wi` emits the value and gate halves concatenated along the last axis;
/// `out[rows, inner] = gelu(value) · gate`.
pub fn geglu(
x : FixedArray[Float],
out : FixedArray[Float],
rows~ : Int,
inner~ : Int,
) -> Unit {
for row in 0.. Unit {
for i in 0.. Unit {
for i in 0.. Unit {
for i in 0.. Unit {
let half = dim / 2
let inv_freq = FixedArray::make(half, 0.0)
for i in 0.. Unit {
for row in 0.. max {
max = x[base + i]
}
}
let mut total = 0.0
for i in 0.. Array[Double] {
let mut max = logits[0]
for value in logits {
if value > max {
max = value
}
}
let out = Array::make(logits.length(), 0.0)
let mut total = 0.0
for i, value in logits {
let e = @math.exp(value - max)
out[i] = e
total += e
}
for i in 0..