using System.Runtime.CompilerServices; namespace QuanTAlib; /// /// MSE: Mean Squared Error /// /// /// MSE measures the average of the squares of the errors between actual and /// predicted values. It penalizes larger errors more heavily than MAE. /// /// Formula: /// MSE = (1/n) * Σ(actual - predicted)² /// /// Uses a RingBuffer for O(1) streaming updates with running sum. /// /// Key properties: /// - Always non-negative (MSE ≥ 0) /// - Units are squared (e.g., if data is in dollars, MSE is in dollars²) /// - Heavily penalizes outliers due to squaring /// - MSE = 0 indicates perfect prediction /// [SkipLocalsInit] public sealed class Mse : BiInputIndicatorBase { /// /// Creates MSE with specified period. /// /// Number of values to average (must be > 0) public Mse(int period) : base(period, $"Mse({period})") { } /// /// Computes squared error: (actual - predicted)² /// [MethodImpl(MethodImplOptions.AggressiveInlining)] protected override double ComputeError(double actual, double predicted) { double diff = actual - predicted; return diff * diff; } /// /// Calculates MSE for the entire series pair. /// /// Actual values series /// Predicted values series /// MSE period /// MSE series public static TSeries Batch(TSeries actual, TSeries predicted, int period) => CalculateImpl(actual, predicted, period, Batch); /// /// Calculates MSE in-place using pre-allocated spans. /// Uses SIMD acceleration when available. /// /// Actual values /// Predicted values /// Output span (must be same length as inputs) /// MSE period (must be > 0) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Batch(ReadOnlySpan actual, ReadOnlySpan predicted, Span output, int period) { ValidateBatchInputs(actual, predicted, output, period); if (actual.Length == 0) { return; } // Allocate temporary buffer for squared errors const int StackAllocThreshold = 256; Span sqErrors = actual.Length <= StackAllocThreshold ? stackalloc double[actual.Length] : new double[actual.Length]; // Compute squared errors using shared SIMD helper ErrorHelpers.ComputeSquaredErrors(actual, predicted, sqErrors); // Apply rolling mean using shared helper ErrorHelpers.ApplyRollingMean(sqErrors, output, period); } public static (TSeries Results, Mse Indicator) Calculate(TSeries actual, TSeries predicted, int period) { var indicator = new Mse(period); TSeries results = Batch(actual, predicted, period); return (results, indicator); } }