Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2895_PushGP_GenealogyAnalysis/HeuristicLab.Problems.ProgramSynthesis/Push/Evaluator/PushBenchmarkSuiteEvaluator.cs @ 18183

Last change on this file since 18183 was 15771, checked in by bburlacu, 7 years ago

#2895: Add solution skeleton for PushGP with genealogy analysis.

File size: 24.3 KB
Line 
1namespace HeuristicLab.Problems.ProgramSynthesis {
2  using System;
3  using System.Collections.Generic;
4  using System.Globalization;
5  using System.Linq;
6
7  using HeuristicLab.BenchmarkSuite;
8  using HeuristicLab.Common;
9  using HeuristicLab.Core;
10  using HeuristicLab.Parameters;
11  using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
12
13  [StorableClass]
14  public class PushBenchmarkSuiteEvaluator : ParameterizedNamedItem, IPushEvaluator {
15
16    private const string DATA_BOUNDS_PARAMETER_NAME = "DataBounds";
17    private const string DATA_PARAMETER_NAME = "Data";
18    private const string DATA_PARAMETER_DESCRIPTION = "Program Synthesis";
19
20    public PushBenchmarkSuiteEvaluator() {
21      Parameters.Add(new FixedValueParameter<DataBounds>(DATA_BOUNDS_PARAMETER_NAME));
22
23      Parameters.Add(new ValueParameter<ProblemData>(
24        DATA_PARAMETER_NAME,
25        DATA_PARAMETER_DESCRIPTION));
26    }
27
28    public PushBenchmarkSuiteEvaluator(ProblemData data) : this() {
29      LoadData(data);
30    }
31
32    [StorableConstructor]
33    public PushBenchmarkSuiteEvaluator(bool deserializing) : base(deserializing) { }
34
35    public PushBenchmarkSuiteEvaluator(PushBenchmarkSuiteEvaluator origin, Cloner cloner) : base(origin, cloner) {
36      Data = cloner.Clone(origin.Data);
37    }
38
39    public override IDeepCloneable Clone(Cloner cloner) {
40      return new PushBenchmarkSuiteEvaluator(this, cloner);
41    }
42
43    public IValueParameter<ProblemData> DataParameter {
44      get { return (IValueParameter<ProblemData>)Parameters[DATA_PARAMETER_NAME]; }
45    }
46
47    public ProblemData Data {
48      get { return DataParameter.Value; }
49      set { DataParameter.Value = value; }
50    }
51
52    public IValueParameter<DataBounds> DataBoundsParameter {
53      get { return (IValueParameter<DataBounds>)Parameters[DATA_BOUNDS_PARAMETER_NAME]; }
54    }
55
56    public DataBounds DataBounds {
57      get { return DataBoundsParameter.Value; }
58      set { DataBoundsParameter.Value = value; }
59    }
60
61    public void LoadData(ProblemData data) {
62      Data = data;
63
64      DataBounds.TrainingRange.Start = 0;
65      DataBounds.TrainingRange.End = Data.TrainingCount;
66      DataBounds.TestRange.Start = Data.TrainingCount;
67      DataBounds.TestRange.End = Data.TrainingCount + Data.TestCount;
68    }
69
70    public EvaluationResult Evaluate(IPushInterpreter interpreter, PushProgram program, int start, int end) {
71      var length = end - start;
72      if (length <= 0) return null;
73
74      var evaluationResult = new EvaluationResult(length);
75
76      for (var i = start; i < end; i++) {
77        var result = Evaluate(interpreter, program, i);
78        evaluationResult.ExampleQualities[i - start] = result;
79        evaluationResult.AvgQuality += result;
80        interpreter.Reset();
81      }
82
83      evaluationResult.AvgQuality /= length;
84
85      return evaluationResult;
86    }
87
88    public EvaluationResult EvaluateTest(IPushInterpreter interpreter, PushProgram program) {
89      return Evaluate(interpreter, program, DataBounds.TestRange.Start, DataBounds.TestRange.End);
90    }
91
92    public EvaluationResult EvaluateTest(IReadOnlyPushConfiguration config, PushProgram program, IRandom random) {
93      var interpreter = new PushInterpreter(config, random);
94      return EvaluateTest(interpreter, program);
95    }
96
97    public EvaluationResult EvaluateTest(PushInterpreterPool pool, PushProgram program, IRandom random) {
98      using (var interpreter = pool.Create(random)) {
99        return EvaluateTest(interpreter, program);
100      }
101    }
102
103    public EvaluationResult EvaluateTraining(IPushInterpreter interpreter, PushProgram program) {
104      return Evaluate(interpreter, program, DataBounds.TrainingRange.Start, DataBounds.TrainingRange.End);
105    }
106
107    public EvaluationResult EvaluateTraining(IReadOnlyPushConfiguration config, PushProgram program, IRandom random) {
108      var interpreter = new PushInterpreter(config, random);
109      return EvaluateTraining(interpreter, program);
110    }
111
112    public EvaluationResult EvaluateTraining(PushInterpreterPool pool, PushProgram program, IRandom random) {
113      using (var interpreter = pool.Create(random)) {
114        return EvaluateTraining(interpreter, program);
115      }
116    }
117
118    public double Evaluate(IPushInterpreter interpreter, PushProgram program, int exampleIndex) {
119      var example = Data.Examples[exampleIndex];
120
121      interpreter.InitExample(example);
122      interpreter.Run(program);
123
124      switch (Data.ProblemType) {
125        // special
126        case ProblemType.NumberIO: return NumberIo(interpreter, example);
127        case ProblemType.StringDifferences: return StringDifferences(interpreter, example);
128        case ProblemType.EvenSquares: return EvenSquares(interpreter, example);
129        case ProblemType.WallisPi: return WallisPi(interpreter, example);
130        case ProblemType.VectorSummed: return VectorsSummed(interpreter, example);
131        case ProblemType.XWordLines: return XWordLines(interpreter, example);
132        case ProblemType.NegativeToZero: return NegativeToZero(interpreter, example);
133        case ProblemType.WordStats: return WordStats(interpreter, example);
134        case ProblemType.Checksum: return Checksum(interpreter, example);
135        case ProblemType.Grades: return Grade(interpreter, example);
136        case ProblemType.Syllables: return Syllables(interpreter, example);
137
138        // printed string right/wrong
139        case ProblemType.Smallest:
140        case ProblemType.Median: return PrintedStringRight(interpreter, example);
141        case ProblemType.MedianIntegerError: return MedianIntegerError(interpreter, example);
142
143        // boolean error
144        case ProblemType.MirrorImage:
145        case ProblemType.SuperAnagrams:
146        case ProblemType.CompareStringLengths: return GetDiff(example.OutputBoolean, interpreter.BooleanStack, Data.WorstResult, BooleanDiffer);
147
148        // float error
149        case ProblemType.VectorAverage: return GetDiff(example.OutputFloat, interpreter.FloatStack, Data.WorstResult, (a, b) => FloatDiffer(a, b, example.OutputFloatPrecision, Data.WorstResult));
150
151        // integer error
152        case ProblemType.LastIndexOfZero:
153        case ProblemType.CountOdds:
154        case ProblemType.SumOfSquares:
155        case ProblemType.ScrabbleScore:
156        case ProblemType.CollatzNumbers: return GetDiff(example.OutputInteger, interpreter.IntegerStack, Data.WorstResult, IntegerDiffer);
157
158        // levenshtein distance + integer error
159        case ProblemType.ReplaceSpaceWithNewline:
160          return GetPrintDiffer(example.OutputPrint, interpreter.PrintStack, Data.WorstResult)
161               + GetDiff(example.OutputInteger, interpreter.IntegerStack, Data.WorstResult, IntegerDiffer);
162
163        // printed levenshtein distance
164        case ProblemType.ForLoopIndex:
165        case ProblemType.DoubleLetters:
166        case ProblemType.StringLengthsBackwards:
167        case ProblemType.PigLatin:
168        case ProblemType.Digits:
169        case ProblemType.SmallOrLarge: return GetPrintDiffer(example.OutputPrint, interpreter.PrintStack, Data.WorstResult);
170      }
171
172      return Default(interpreter, example);
173    }
174
175    private double Default(IPushInterpreter interpreter, Example example) {
176      var integerDiff = GetDiff(example.OutputInteger, interpreter.IntegerStack, Data.WorstResult, IntegerDiffer);
177      var floatDiff = GetDiff(example.OutputFloat, interpreter.FloatStack, Data.WorstResult, (a, b) => FloatDiffer(a, b, example.OutputFloatPrecision, Data.WorstResult));
178      var booleanDiff = GetDiff(example.OutputBoolean, interpreter.BooleanStack, Data.WorstResult, BooleanDiffer);
179      var stringDiff = GetDiff(example.OutputString, interpreter.StringStack, Data.WorstResult, StringDiffer);
180      var charDiff = GetDiff(example.OutputChar, interpreter.CharStack, Data.WorstResult, CharDiffer);
181      var printDiff = GetPrintDiffer(example.OutputPrint, interpreter.PrintStack, Data.WorstResult);
182      var integerVectorDiff = GetVectorDiff(example.OutputIntegerVector, interpreter.IntegerVectorStack, Data.WorstResult, (a, b) => VectorDiffer(a, b, IntegerDiffer));
183      var floatVectorDiff = GetVectorDiff(example.OutputFloatVector, interpreter.FloatVectorStack, Data.WorstResult, (a, b) => VectorDiffer(a, b, (x, y) => FloatDiffer(x, y, example.OutputFloatVectorPrecision, Data.WorstResult)));
184      var stringVectorDiff = GetVectorDiff(example.OutputStringVector, interpreter.StringVectorStack, Data.WorstResult, (a, b) => VectorDiffer(a, b, StringDiffer));
185
186      var result =
187          integerDiff
188        + floatDiff
189        + booleanDiff
190        + stringDiff
191        + charDiff
192        + printDiff
193        + integerVectorDiff
194        + floatVectorDiff
195        + stringVectorDiff;
196
197      return result;
198    }
199
200    private double PrintedStringRight(IPushInterpreter interpreter, Example example) {
201      return interpreter.PrintStack.IsEmpty ||
202             !interpreter.PrintStack.ToString().Equals(example.OutputPrint)
203             ? 1
204             : 0;
205    }
206
207    private double MedianIntegerError(IPushInterpreter interpreter, Example example) {
208      var printResult = interpreter.PrintStack.ToString();
209
210      long result;
211      if (long.TryParse(printResult, out result)) {
212        var diff = result.AbsoluteDiff(example.OutputInteger[0]);
213
214        return Math.Min(Data.WorstResult, diff);
215      }
216
217      return Data.WorstResult;
218    }
219
220    private double NumberIo(IPushInterpreter interpreter, Example example) {
221      if (!string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty)
222        return Data.WorstResult;
223
224      var printResult = interpreter.PrintStack.ToString();
225
226      double value;
227      if (double.TryParse(printResult, NumberStyles.Number | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out value)) {
228        var diff = example.OutputFloat[0].AbsoluteDiff(value);
229        diff = Math.Min(diff, Data.WorstResult);
230
231        return diff;
232      }
233
234      var penaltyError = Data.WorstResult / 4.0d;
235      var levenshteinDistance = GetPrintDiffer(
236        example.OutputPrint,
237        printResult,
238        Data.WorstResult);
239
240      var result = levenshteinDistance + penaltyError;
241      return Math.Min(result, Data.WorstResult);
242    }
243
244    private double StringDifferences(IPushInterpreter interpreter, Example example) {
245      if (string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty) {
246        return 0.0;
247      }
248
249      if (!string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty) {
250        return Data.WorstResult;
251      }
252
253      var printResult = interpreter.PrintStack.ToString();
254      var distance = example.OutputPrint.LevenshteinDistance(printResult);
255
256      var lineCountWithCorrectFormat = interpreter.PrintStack
257        .AsStrings()
258        .Count(line => {
259          var parts = line.Split(' ');
260
261          if (parts.Length != 3)
262            return false;
263
264          var part0 = parts[0].Trim();
265          if (part0.Length == 0 || !part0.IsNumeric())
266            return false;
267
268          var part1 = parts[1].Trim();
269          if (part1.Length != 1)
270            return false;
271
272          var part2 = parts[2].Trim();
273          if (part2.Length != 1)
274            return false;
275
276          return true;
277        });
278
279      var lineCountWithInvalidFormat = example.OutputPrintLineCount - lineCountWithCorrectFormat;
280      lineCountWithInvalidFormat = Math.Min(lineCountWithInvalidFormat, example.OutputPrintLineCount);
281
282      var result = distance + lineCountWithInvalidFormat;
283      return Math.Min(result, Data.WorstResult);
284    }
285
286    private double EvenSquares(IPushInterpreter interpreter, Example example) {
287      if (string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty) {
288        return 0.0;
289      }
290
291      if (!string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty) {
292        return Data.WorstResult;
293      }
294
295      var printResult = interpreter.PrintStack.ToString();
296      var distance = example.OutputPrint.LevenshteinDistance(printResult);
297
298      var printLines = interpreter.PrintStack.AsStrings().ToArray();
299
300      var lineCountWithInvalidFormat = printLines
301        .Take(example.OutputPrintLineCount)
302        .Count(line => !line.IsNumeric());
303
304      var compareLength = Math.Min(printLines.Length, example.OutputPrintLineCount);
305      var integerError = 0L;
306
307      for (var i = 0; i < compareLength; i++) {
308        long value;
309        if (long.TryParse(printLines[i], out value)) {
310          integerError += value.AbsoluteDiff(example.OutputIntegerVector[0][i]);
311        }
312      }
313
314      var result = distance + lineCountWithInvalidFormat + integerError / compareLength;
315      return Math.Min(result, Data.WorstResult);
316    }
317
318    private double WallisPi(IPushInterpreter interpreter, Example example) {
319      if (interpreter.FloatStack.IsEmpty)
320        return Data.WorstResult;
321
322      var floatDiff = GetDiff(example.OutputFloat, interpreter.FloatStack, Data.WorstResult, (a, b) => FloatDiffer(a, b, example.OutputFloatPrecision, Data.WorstResult));
323      var expectedStr = example.OutputFloat[0].ToString(Data.FloatStringFormat, CultureInfo.CurrentCulture);
324      var resultStr = interpreter.FloatStack.TopOrDefault.ToString(Data.FloatStringFormat, CultureInfo.CurrentCulture);
325      var distance = expectedStr.LevenshteinDistance(resultStr);
326
327      var result = floatDiff + distance;
328      return Math.Min(result, Data.WorstResult);
329    }
330
331    private double VectorsSummed(IPushInterpreter interpreter, Example example) {
332      if (interpreter.IntegerVectorStack.IsEmpty && example.OutputIntegerVector.Length > 0)
333        return Data.WorstResult;
334
335      var resultVector = interpreter.IntegerVectorStack[0];
336      var expectedVector = example.OutputIntegerVector[0];
337      var comparableLength = Math.Min(resultVector.Count, expectedVector.Length);
338
339      // add penalty if length does not match
340      //var result = expectedVector.Length > 0
341      //  ? (expectedVector.Length - comparableLength) * (Data.WorstResult / expectedVector.Length)
342      //  : 0;
343
344      if (comparableLength == 0) {
345        return Data.WorstResult;
346      }
347
348      var result = 0d;
349
350      for (var i = 0; i < comparableLength; i++) {
351        result += resultVector[i].AbsoluteDiff(expectedVector[i]);
352      }
353
354      for (var i = comparableLength; i < expectedVector.Length; i++) {
355        result += expectedVector[i];
356      }
357
358      return Math.Min(result, Data.WorstResult);
359    }
360
361    private double XWordLines(IPushInterpreter interpreter, Example example) {
362      if (string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty) {
363        return 0.0;
364      }
365
366      if (!string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty)
367        return Data.WorstResult;
368
369      var estimatedWordsPerLineCount = example.InputInteger[0];
370      var estimatedWordCount = example.OutputInteger[0];
371      var estimatedLastWordCount = estimatedWordCount - estimatedWordsPerLineCount * Math.Max(0, example.OutputPrintLineCount - 1);
372      var printResult = interpreter.PrintStack.ToString();
373      var distance = example.OutputPrint.LevenshteinDistance(printResult);
374      var lineCount = interpreter.PrintStack.Count;
375      var lineCountError = example.OutputPrintLineCount.AbsoluteDiff(lineCount);
376      var totalWordsPerLineError = 0L;
377
378      for (var i = 0; i < interpreter.PrintStack.Lines.Count - 1; i++) {
379        totalWordsPerLineError += interpreter.PrintStack.Lines[i].Split(' ').Length.AbsoluteDiff(estimatedWordsPerLineCount);
380      }
381
382      // last line
383      var lastLine = interpreter.PrintStack.Lines[interpreter.PrintStack.Lines.Count - 1];
384      totalWordsPerLineError += lastLine.Split(' ').Length.AbsoluteDiff(estimatedLastWordCount);
385
386      var result = distance + lineCountError + totalWordsPerLineError;
387      return Math.Min(result, Data.WorstResult);
388    }
389
390    private double NegativeToZero(IPushInterpreter interpreter, Example example) {
391      if (interpreter.IntegerVectorStack.IsEmpty && example.OutputIntegerVector.Length > 0)
392        return Data.WorstResult;
393
394      var resultVector = interpreter.IntegerVectorStack.Top;
395      var expectedVector = example.OutputIntegerVector[0];
396      var comparableLength = Math.Min(resultVector.Count, expectedVector.Length);
397
398      // add penalty if length does not match
399      //var result = expectedVector.Length > 0
400      //  ? (expectedVector.Length - comparableLength) * (Data.WorstResult / expectedVector.Length)
401      //  : 0;
402
403      if (comparableLength == 0) {
404        return Data.WorstResult;
405      }
406
407      var result = 0d;
408
409      for (var i = 0; i < comparableLength; i++) {
410        var expectedStr = expectedVector[i].ToString();
411        var resultStr = resultVector[i].ToString();
412
413        result += expectedStr.LevenshteinDistance(resultStr);
414      }
415
416      for (var i = comparableLength; i < expectedVector.Length; i++) {
417        result += expectedVector[i].ToString().Length;
418      }
419
420      return Math.Min(result, Data.WorstResult);
421    }
422
423    private double WordStats(IPushInterpreter interpreter, Example example) {
424      if (string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty) {
425        return 0.0;
426      }
427
428      if (!string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty)
429        return Data.WorstResult;
430
431      var printStr = interpreter.PrintStack.ToString();
432      var distance = example.OutputPrint.LevenshteinDistance(printStr);
433
434      var statsError = 0.0;
435      long numberOfSentences;
436      var expectedNumberOfSentences = example.OutputInteger[0];
437      statsError += BenchmarkSuite.Problems.WordStats.GetNumberOfSentences(printStr, out numberOfSentences)
438        ? expectedNumberOfSentences.AbsoluteDiff(numberOfSentences)
439        : Data.WorstResult / 3.0;
440
441      double averageSentenceLength;
442      var expectedAverageSentenceLength = example.OutputFloat[0];
443      statsError += BenchmarkSuite.Problems.WordStats.GetAverageSentenceLength(printStr, out averageSentenceLength)
444        ? expectedAverageSentenceLength.AbsoluteDiff(averageSentenceLength)
445        : Data.WorstResult / 3.0;
446
447      var result = distance + statsError;
448      return Math.Min(result, Data.WorstResult);
449    }
450
451    private double Checksum(IPushInterpreter interpreter, Example example) {
452      if (!string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty)
453        return Data.WorstResult;
454
455      var printStr = interpreter.PrintStack.ToString();
456      var distance = example.OutputPrint.LevenshteinDistance(printStr);
457
458      var expectedLastCharIndex = example.OutputPrint.Length - 1;
459      var resultLastCharIndex = printStr.Length - 1;
460      var result = distance;
461
462      if (expectedLastCharIndex >= 0 && resultLastCharIndex >= 0) {
463        var expectedLastChar = example.OutputPrint[expectedLastCharIndex];
464        var resultLastChar = printStr[resultLastCharIndex];
465
466        result += expectedLastChar.AbsoluteDiff(resultLastChar);
467      }
468
469      return Math.Min(result, Data.WorstResult);
470    }
471
472    private double Syllables(IPushInterpreter interpreter, Example example) {
473      if (!string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty)
474        return Data.WorstResult;
475
476      var printStr = interpreter.PrintStack.ToString();
477      var distance = example.OutputPrint.LevenshteinDistance(printStr);
478
479      long numberOfSyllables;
480      var expectedNumberOfSyllables = example.OutputInteger[0];
481      var numberOfSyllablesError = BenchmarkSuite.Problems.Syllables.GetNumberOfSyllables(printStr, out numberOfSyllables)
482        ? expectedNumberOfSyllables.AbsoluteDiff(numberOfSyllables)
483        : Data.WorstResult / 2.0;
484
485      var result = distance + numberOfSyllablesError;
486      return Math.Min(result, Data.WorstResult);
487    }
488
489    private double Grade(IPushInterpreter interpreter, Example example) {
490      if (!string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty)
491        return Data.WorstResult;
492
493      var printStr = interpreter.PrintStack.ToString();
494      var distance = example.OutputPrint.LevenshteinDistance(printStr);
495
496      char grade;
497      var expectedGrade = example.OutputChar[0];
498      var gradeError = BenchmarkSuite.Problems.Grades.GetGrade(printStr, out grade)
499        ? expectedGrade.AbsoluteDiff(grade)
500        : char.MaxValue;
501
502      var result = distance + gradeError;
503      return Math.Min(result, Data.WorstResult);
504    }
505
506    private static double FloatDiffer(double a, double b, int digits, double worst) {
507      var result = Math.Round(a, digits) - Math.Round(b, digits);
508
509      // ReSharper disable once CompareOfFloatsByEqualityOperator
510      if (result == double.MinValue || double.IsPositiveInfinity(result) ||
511          double.IsNaN(result) ||
512          // ReSharper disable once CompareOfFloatsByEqualityOperator
513          result == double.MaxValue || double.IsNegativeInfinity(result))
514        return worst;
515
516      return Math.Abs(result);
517    }
518
519    private static double IntegerDiffer(long a, long b) {
520      var result = a - b;
521
522      return result == long.MinValue ? long.MaxValue : Math.Abs(result);
523    }
524
525    private static double BooleanDiffer(bool a, bool b) {
526      return a == b ? 0 : 1;
527    }
528
529    private static double StringDiffer(string a, string b) {
530      return a.LevenshteinDistance(b);
531    }
532
533    private static double CharDiffer(char a, char b) {
534      return IntegerDiffer(a, b);
535    }
536
537    private static double VectorDiffer<T>(IReadOnlyList<T> estimated, IReadOnlyList<T> outcome, Func<T, T, double> differ) {
538      var length = Math.Min(estimated.Count, outcome.Count);
539      var result = 0d;
540
541      for (var i = 0; i < length; i++) {
542        result += differ(estimated[i], outcome[i]);
543      }
544
545      if (estimated.Count > outcome.Count) {
546        var remainingLength = estimated.Count - length;
547        for (var i = 0; i < remainingLength; i++)
548          result += differ(estimated[i], default(T));
549      }
550
551      return result;
552    }
553
554    private static double GetPrintDiffer(string estimated, string printResult, double worstResult) {
555      var distance = estimated.LevenshteinDistance(printResult);
556
557      return Math.Min(distance, worstResult);
558    }
559
560    private static double GetPrintDiffer(string estimated, IPrintStack printStack, double worstResult) {
561      var printResult = printStack.ToString();
562      var distance = estimated.LevenshteinDistance(printResult);
563
564      return Math.Min(distance, worstResult);
565    }
566
567    private static double GetVectorDiff<T>(IReadOnlyList<IReadOnlyList<T>> estimated, IPushStack<IReadOnlyList<T>> resultStack, double worstResult, Func<IReadOnlyList<T>, IReadOnlyList<T>, double> differ)
568      where T : IComparable {
569      if (estimated.Count == 0) return 0d;
570      if (resultStack.IsEmpty && estimated.Count > 0) return worstResult;
571
572      var diff = 0d;
573      var comparableLength = Math.Min(estimated.Count, resultStack.Count);
574
575      if (!resultStack.IsEmpty) {
576
577        for (var i = 0; i < comparableLength && diff < worstResult; i++) {
578          diff += differ(estimated[i], resultStack[i]);
579        }
580      }
581
582      var emptyTArray = new T[0];
583      for (var i = comparableLength; i < estimated.Count - comparableLength && diff < worstResult; i++) {
584        diff += differ(estimated[i], emptyTArray);
585      }
586
587      return double.IsNaN(diff) || double.IsInfinity(diff)
588         ? worstResult
589         : Math.Min(diff, worstResult);
590    }
591
592    private static double GetDiff<T>(IReadOnlyList<T> estimated, IPushStack<T> resultStack, double worstResult, Func<T, T, double> differ)
593      where T : IComparable {
594      if (estimated.Count == 0) return 0d;
595      if (resultStack.IsEmpty && estimated.Count > 0) return worstResult;
596
597      var diff = 0d;
598      var comparableLength = Math.Min(estimated.Count, resultStack.Count);
599
600      if (!resultStack.IsEmpty) {
601        for (var i = 0; i < comparableLength && diff < worstResult; i++) {
602          diff += differ(estimated[i], resultStack[i]);
603        }
604      }
605
606      for (var i = comparableLength; i < estimated.Count - comparableLength && diff < worstResult; i++) {
607        diff += differ(estimated[i], default(T));
608      }
609
610      return double.IsNaN(diff) || double.IsInfinity(diff)
611        ? worstResult
612        : Math.Min(diff, worstResult);
613    }
614  }
615}
Note: See TracBrowser for help on using the repository browser.