// Author: Simon-Pierre Boucher — contact@spboucher.ai // // Bias-corrected exponential moving average (TensorBoard semantics): with // smoothing s ∈ [0,1), ema_t = s·ema_{t-1} + (1−s)·x_t, displayed as // ema_t / (1 − s^(t+1)) so early points aren't dragged toward zero. import Foundation enum Smoothing { static func ema(_ values: [Double], smoothing: Double) -> [Double] { guard smoothing > 0, smoothing < 1, !values.isEmpty else { return values } var out: [Double] = [] out.reserveCapacity(values.count) var acc = 0.0 var correction = 1.0 for v in values { acc = smoothing * acc + (1 - smoothing) * v correction *= smoothing out.append(acc / (1 - correction)) } return out } }