using System; using System.Collections.Generic; using System.Linq; using LeafWeb.Core.Entities; using MathNet.Numerics; namespace LeafWeb.Core.Utility { public class TimeInProgressEstimater { private readonly double[] _xData; private readonly double[] _yData; public TimeInProgressEstimater(IEnumerable leafInputs) { var xData = new List(); var yData = new List(); foreach (var leafInput in leafInputs) { xData.Add(leafInput.InputFiles.Count); yData.Add(ConvertFromTimeSpan(leafInput.TimeInProgress)); } _xData = xData.ToArray(); _yData = yData.ToArray(); } private static Func Positivize => i => i <= 0 ? 1 : i; private IEnumerable Div => _xData.Zip(_yData, (x, y) => y/x); private Func AverageFitFunc => i => Div.Average()*i; private Func LineFitFunc => Fit.LineFunc(_xData, _yData); private Func FitFunc => i => (Positivize(LineFitFunc(i)) + AverageFitFunc(i))/2; public TimeSpan EstimateTimeInProgress(ILeafInput leafInput) { return EstimateTimeInProgress(leafInput.InputFiles.Count); } public TimeSpan EstimateTimeInProgress(int inputFileCount) { var estimate = FitFunc(inputFileCount); if (estimate <= 0) estimate = 1; return ConvertToTimeSpan(estimate); } private static double ConvertFromTimeSpan(TimeSpan timeSpan) { return timeSpan.TotalSeconds; } private static TimeSpan ConvertToTimeSpan(double estimate) { return TimeSpan.FromSeconds(ConvertToInt32Guarded(estimate)); } private static Func ConvertToInt32Guarded => d => { try { return Convert.ToInt32(d); } catch (OverflowException) { return int.MaxValue; } }; } }