Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PushGP/HeuristicLab.PushGP/HeuristicLab.Problems.ProgramSynthesis/Push/Evaluator/PushBenchmarkSuiteEvaluator.cs @ 15341

Last change on this file since 15341 was 15341, checked in by pkimmesw, 7 years ago

#2665 Testet Problems, Improved Performance

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