protected override sealed void TransformCore(ref TInput input, FixedSizeQueue <TInput> windowedBuffer, long iteration, ref VBuffer <Double> dst) { var outputLength = Parent._outputLength; Host.Assert(outputLength >= 2); var result = dst.Values; if (Utils.Size(result) < outputLength) { result = new Double[outputLength]; } float rawScore = 0; for (int i = 0; i < outputLength; ++i) { result[i] = Double.NaN; } // Step 1: Computing the raw anomaly score result[1] = ComputeRawAnomalyScore(ref input, windowedBuffer, iteration); if (Double.IsNaN(result[1])) { result[0] = 0; } else { if (WindowSize > 0) { // Step 2: Computing the p-value score rawScore = (float)result[1]; if (Parent.ThresholdScore == AlertingScore.RawScore) { switch (Parent.Side) { case AnomalySide.Negative: rawScore = (float)(-result[1]); break; case AnomalySide.Positive: break; default: rawScore = (float)Math.Abs(result[1]); break; } } else { result[2] = ComputeKernelPValue(rawScore); switch (Parent.Side) { case AnomalySide.Negative: result[2] = 1 - result[2]; break; case AnomalySide.Positive: break; default: result[2] = Math.Min(result[2], 1 - result[2]); break; } // Keeping the p-value in the safe range if (result[2] < MinPValue) { result[2] = MinPValue; } else if (result[2] > MaxPValue) { result[2] = MaxPValue; } _rawScoreBuffer.AddLast(rawScore); // Step 3: Computing the martingale value if (Parent.Martingale != MartingaleType.None && Parent.ThresholdScore == AlertingScore.MartingaleScore) { Double martingaleUpdate = 0; switch (Parent.Martingale) { case MartingaleType.Power: martingaleUpdate = Parent.LogPowerMartigaleBettingFunc(result[2], Parent.PowerMartingaleEpsilon); break; case MartingaleType.Mixture: martingaleUpdate = Parent.LogMixtureMartigaleBettingFunc(result[2]); break; } if (_logMartingaleUpdateBuffer.Count == 0) { for (int i = 0; i < _logMartingaleUpdateBuffer.Capacity; ++i) { _logMartingaleUpdateBuffer.AddLast(martingaleUpdate); } _logMartingaleValue += _logMartingaleUpdateBuffer.Capacity * martingaleUpdate; } else { _logMartingaleValue += martingaleUpdate; _logMartingaleValue -= _logMartingaleUpdateBuffer.PeekFirst(); _logMartingaleUpdateBuffer.AddLast(martingaleUpdate); } result[3] = Math.Exp(_logMartingaleValue); } } } // Generating alert bool alert = false; if (_rawScoreBuffer.IsFull) // No alert until the buffer is completely full. { switch (Parent.ThresholdScore) { case AlertingScore.RawScore: alert = rawScore >= Parent.AlertThreshold; break; case AlertingScore.PValueScore: alert = result[2] <= Parent.AlertThreshold; break; case AlertingScore.MartingaleScore: alert = (Parent.Martingale != MartingaleType.None) && (result[3] >= Parent.AlertThreshold); if (alert) { if (_martingaleAlertCounter > 0) { alert = false; } else { _martingaleAlertCounter = Parent.WindowSize; } } _martingaleAlertCounter--; _martingaleAlertCounter = _martingaleAlertCounter < 0 ? 0 : _martingaleAlertCounter; break; } } result[0] = Convert.ToDouble(alert); } dst = new VBuffer <Double>(outputLength, result, dst.Indices); }