Free cookie consent management tool by TermsFeed Policy Generator

source: addons/HeuristicLab.PushGP/HeuristicLab.Problems.ProgramSynthesis/Push/Evaluator/PushBenchmarkSuiteEvaluator.cs @ 16958

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

#2665 Solution Cleanup

File size: 24.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        case ProblemType.MedianIntegerError: return MedianIntegerError(interpreter, example);
152
153        // boolean error
154        case ProblemType.MirrorImage:
155        case ProblemType.SuperAnagrams:
156        case ProblemType.CompareStringLengths: return GetDiff(example.OutputBoolean, interpreter.BooleanStack, Data.WorstResult, BooleanDiffer);
157
158        // float error
159        case ProblemType.VectorAverage: return GetDiff(example.OutputFloat, interpreter.FloatStack, Data.WorstResult, (a, b) => FloatDiffer(a, b, example.OutputFloatPrecision, Data.WorstResult));
160
161        // integer error
162        case ProblemType.LastIndexOfZero:
163        case ProblemType.CountOdds:
164        case ProblemType.SumOfSquares:
165        case ProblemType.ScrabbleScore:
166        case ProblemType.CollatzNumbers: return GetDiff(example.OutputInteger, interpreter.IntegerStack, Data.WorstResult, IntegerDiffer);
167
168        // levenshtein distance + integer error
169        case ProblemType.ReplaceSpaceWithNewline:
170          return GetPrintDiffer(example.OutputPrint, interpreter.PrintStack, Data.WorstResult)
171               + GetDiff(example.OutputInteger, interpreter.IntegerStack, Data.WorstResult, IntegerDiffer);
172
173        // printed levenshtein distance
174        case ProblemType.ForLoopIndex:
175        case ProblemType.DoubleLetters:
176        case ProblemType.StringLengthsBackwards:
177        case ProblemType.PigLatin:
178        case ProblemType.Digits:
179        case ProblemType.SmallOrLarge: return GetPrintDiffer(example.OutputPrint, interpreter.PrintStack, Data.WorstResult);
180      }
181
182      return Default(interpreter, example);
183    }
184
185    private double Default(IPushInterpreter interpreter, Example example) {
186      var integerDiff = GetDiff(example.OutputInteger, interpreter.IntegerStack, Data.WorstResult, IntegerDiffer);
187      var floatDiff = GetDiff(example.OutputFloat, interpreter.FloatStack, Data.WorstResult, (a, b) => FloatDiffer(a, b, example.OutputFloatPrecision, Data.WorstResult));
188      var booleanDiff = GetDiff(example.OutputBoolean, interpreter.BooleanStack, Data.WorstResult, BooleanDiffer);
189      var stringDiff = GetDiff(example.OutputString, interpreter.StringStack, Data.WorstResult, StringDiffer);
190      var charDiff = GetDiff(example.OutputChar, interpreter.CharStack, Data.WorstResult, CharDiffer);
191      var printDiff = GetPrintDiffer(example.OutputPrint, interpreter.PrintStack, Data.WorstResult);
192      var integerVectorDiff = GetVectorDiff(example.OutputIntegerVector, interpreter.IntegerVectorStack, Data.WorstResult, (a, b) => VectorDiffer(a, b, IntegerDiffer));
193      var floatVectorDiff = GetVectorDiff(example.OutputFloatVector, interpreter.FloatVectorStack, Data.WorstResult, (a, b) => VectorDiffer(a, b, (x, y) => FloatDiffer(x, y, example.OutputFloatVectorPrecision, Data.WorstResult)));
194      var stringVectorDiff = GetVectorDiff(example.OutputStringVector, interpreter.StringVectorStack, Data.WorstResult, (a, b) => VectorDiffer(a, b, StringDiffer));
195
196      var result =
197          integerDiff
198        + floatDiff
199        + booleanDiff
200        + stringDiff
201        + charDiff
202        + printDiff
203        + integerVectorDiff
204        + floatVectorDiff
205        + stringVectorDiff;
206
207      return result;
208    }
209
210    private double PrintedStringRight(IPushInterpreter interpreter, Example example) {
211      return interpreter.PrintStack.IsEmpty ||
212             !interpreter.PrintStack.ToString().Equals(example.OutputPrint)
213             ? 1
214             : 0;
215    }
216
217    private double MedianIntegerError(IPushInterpreter interpreter, Example example) {
218      var printResult = interpreter.PrintStack.ToString();
219
220      long result;
221      if (long.TryParse(printResult, out result)) {
222        var diff = result.AbsoluteDiff(example.OutputInteger[0]);
223
224        return Math.Min(Data.WorstResult, diff);
225      }
226
227      return Data.WorstResult;
228    }
229
230    private double NumberIo(IPushInterpreter interpreter, Example example) {
231      if (!string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty)
232        return Data.WorstResult;
233
234      var printResult = interpreter.PrintStack.ToString();
235
236      double value;
237      if (double.TryParse(printResult, NumberStyles.Number | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out value)) {
238        var diff = example.OutputFloat[0].AbsoluteDiff(value);
239        diff = Math.Min(diff, Data.WorstResult);
240
241        return diff;
242      }
243
244      var penaltyError = Data.WorstResult / 4.0d;
245      var levenshteinDistance = GetPrintDiffer(
246        example.OutputPrint,
247        printResult,
248        Data.WorstResult);
249
250      var result = levenshteinDistance + penaltyError;
251      return Math.Min(result, Data.WorstResult);
252    }
253
254    private double StringDifferences(IPushInterpreter interpreter, Example example) {
255      if (string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty) {
256        return 0.0;
257      }
258
259      if (!string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty) {
260        return Data.WorstResult;
261      }
262
263      var printResult = interpreter.PrintStack.ToString();
264      var distance = example.OutputPrint.LevenshteinDistance(printResult);
265
266      var lineCountWithCorrectFormat = interpreter.PrintStack
267        .AsStrings()
268        .Count(line => {
269          var parts = line.Split(' ');
270
271          if (parts.Length != 3)
272            return false;
273
274          var part0 = parts[0].Trim();
275          if (part0.Length == 0 || !part0.IsNumeric())
276            return false;
277
278          var part1 = parts[1].Trim();
279          if (part1.Length != 1)
280            return false;
281
282          var part2 = parts[2].Trim();
283          if (part2.Length != 1)
284            return false;
285
286          return true;
287        });
288
289      var lineCountWithInvalidFormat = example.OutputPrintLineCount - lineCountWithCorrectFormat;
290      lineCountWithInvalidFormat = Math.Min(lineCountWithInvalidFormat, example.OutputPrintLineCount);
291
292      var result = distance + lineCountWithInvalidFormat;
293      return Math.Min(result, Data.WorstResult);
294    }
295
296    private double EvenSquares(IPushInterpreter interpreter, Example example) {
297      if (string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty) {
298        return 0.0;
299      }
300
301      if (!string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty) {
302        return Data.WorstResult;
303      }
304
305      var printResult = interpreter.PrintStack.ToString();
306      var distance = example.OutputPrint.LevenshteinDistance(printResult);
307
308      var printLines = interpreter.PrintStack.AsStrings().ToArray();
309
310      var lineCountWithInvalidFormat = printLines
311        .Take(example.OutputPrintLineCount)
312        .Count(line => !line.IsNumeric());
313
314      var compareLength = Math.Min(printLines.Length, example.OutputPrintLineCount);
315      var integerError = 0L;
316
317      for (var i = 0; i < compareLength; i++) {
318        long value;
319        if (long.TryParse(printLines[i], out value)) {
320          integerError += value.AbsoluteDiff(example.OutputIntegerVector[0][i]);
321        }
322      }
323
324      var result = distance + lineCountWithInvalidFormat + integerError / compareLength;
325      return Math.Min(result, Data.WorstResult);
326    }
327
328    private double WallisPi(IPushInterpreter interpreter, Example example) {
329      if (interpreter.FloatStack.IsEmpty)
330        return Data.WorstResult;
331
332      var floatDiff = GetDiff(example.OutputFloat, interpreter.FloatStack, Data.WorstResult, (a, b) => FloatDiffer(a, b, example.OutputFloatPrecision, Data.WorstResult));
333      var expectedStr = example.OutputFloat[0].ToString(Data.FloatStringFormat, CultureInfo.CurrentCulture);
334      var resultStr = interpreter.FloatStack.TopOrDefault.ToString(Data.FloatStringFormat, CultureInfo.CurrentCulture);
335      var distance = expectedStr.LevenshteinDistance(resultStr);
336
337      var result = floatDiff + distance;
338      return Math.Min(result, Data.WorstResult);
339    }
340
341    private double VectorsSummed(IPushInterpreter interpreter, Example example) {
342      if (interpreter.IntegerVectorStack.IsEmpty && example.OutputIntegerVector.Length > 0)
343        return Data.WorstResult;
344
345      var resultVector = interpreter.IntegerVectorStack[0];
346      var expectedVector = example.OutputIntegerVector[0];
347      var comparableLength = Math.Min(resultVector.Count, expectedVector.Length);
348
349      // add penalty if length does not match
350      //var result = expectedVector.Length > 0
351      //  ? (expectedVector.Length - comparableLength) * (Data.WorstResult / expectedVector.Length)
352      //  : 0;
353
354      if (comparableLength == 0) {
355        return Data.WorstResult;
356      }
357
358      var result = 0d;
359
360      for (var i = 0; i < comparableLength; i++) {
361        result += resultVector[i].AbsoluteDiff(expectedVector[i]);
362      }
363
364      for (var i = comparableLength; i < expectedVector.Length; i++) {
365        result += expectedVector[i];
366      }
367
368      return Math.Min(result, Data.WorstResult);
369    }
370
371    private double XWordLines(IPushInterpreter interpreter, Example example) {
372      if (string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty) {
373        return 0.0;
374      }
375
376      if (!string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty)
377        return Data.WorstResult;
378
379      var estimatedWordsPerLineCount = example.InputInteger[0];
380      var estimatedWordCount = example.OutputInteger[0];
381      var estimatedLastWordCount = estimatedWordCount - estimatedWordsPerLineCount * Math.Max(0, example.OutputPrintLineCount - 1);
382      var printResult = interpreter.PrintStack.ToString();
383      var distance = example.OutputPrint.LevenshteinDistance(printResult);
384      var lineCount = interpreter.PrintStack.Count;
385      var lineCountError = example.OutputPrintLineCount.AbsoluteDiff(lineCount);
386      var totalWordsPerLineError = 0L;
387
388      for (var i = 0; i < interpreter.PrintStack.Lines.Count - 1; i++) {
389        totalWordsPerLineError += interpreter.PrintStack.Lines[i].Split(' ').Length.AbsoluteDiff(estimatedWordsPerLineCount);
390      }
391
392      // last line
393      var lastLine = interpreter.PrintStack.Lines[interpreter.PrintStack.Lines.Count - 1];
394      totalWordsPerLineError += lastLine.Split(' ').Length.AbsoluteDiff(estimatedLastWordCount);
395
396      var result = distance + lineCountError + totalWordsPerLineError;
397      return Math.Min(result, Data.WorstResult);
398    }
399
400    private double NegativeToZero(IPushInterpreter interpreter, Example example) {
401      if (interpreter.IntegerVectorStack.IsEmpty && example.OutputIntegerVector.Length > 0)
402        return Data.WorstResult;
403
404      var resultVector = interpreter.IntegerVectorStack.Top;
405      var expectedVector = example.OutputIntegerVector[0];
406      var comparableLength = Math.Min(resultVector.Count, expectedVector.Length);
407
408      // add penalty if length does not match
409      //var result = expectedVector.Length > 0
410      //  ? (expectedVector.Length - comparableLength) * (Data.WorstResult / expectedVector.Length)
411      //  : 0;
412
413      if (comparableLength == 0) {
414        return Data.WorstResult;
415      }
416
417      var result = 0d;
418
419      for (var i = 0; i < comparableLength; i++) {
420        var expectedStr = expectedVector[i].ToString();
421        var resultStr = resultVector[i].ToString();
422
423        result += expectedStr.LevenshteinDistance(resultStr);
424      }
425
426      for (var i = comparableLength; i < expectedVector.Length; i++) {
427        result += expectedVector[i].ToString().Length;
428      }
429
430      return Math.Min(result, Data.WorstResult);
431    }
432
433    private double WordStats(IPushInterpreter interpreter, Example example) {
434      if (string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty) {
435        return 0.0;
436      }
437
438      if (!string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty)
439        return Data.WorstResult;
440
441      var printStr = interpreter.PrintStack.ToString();
442      var distance = example.OutputPrint.LevenshteinDistance(printStr);
443
444      var statsError = 0.0;
445      long numberOfSentences;
446      var expectedNumberOfSentences = example.OutputInteger[0];
447      statsError += BenchmarkSuite.Problems.WordStats.GetNumberOfSentences(printStr, out numberOfSentences)
448        ? expectedNumberOfSentences.AbsoluteDiff(numberOfSentences)
449        : Data.WorstResult / 3.0;
450
451      double averageSentenceLength;
452      var expectedAverageSentenceLength = example.OutputFloat[0];
453      statsError += BenchmarkSuite.Problems.WordStats.GetAverageSentenceLength(printStr, out averageSentenceLength)
454        ? expectedAverageSentenceLength.AbsoluteDiff(averageSentenceLength)
455        : Data.WorstResult / 3.0;
456
457      var result = distance + statsError;
458      return Math.Min(result, Data.WorstResult);
459    }
460
461    private double Checksum(IPushInterpreter interpreter, Example example) {
462      if (!string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty)
463        return Data.WorstResult;
464
465      var printStr = interpreter.PrintStack.ToString();
466      var distance = example.OutputPrint.LevenshteinDistance(printStr);
467
468      var expectedLastCharIndex = example.OutputPrint.Length - 1;
469      var resultLastCharIndex = printStr.Length - 1;
470      var result = distance;
471
472      if (expectedLastCharIndex >= 0 && resultLastCharIndex >= 0) {
473        var expectedLastChar = example.OutputPrint[expectedLastCharIndex];
474        var resultLastChar = printStr[resultLastCharIndex];
475
476        result += expectedLastChar.AbsoluteDiff(resultLastChar);
477      }
478
479      return Math.Min(result, Data.WorstResult);
480    }
481
482    private double Syllables(IPushInterpreter interpreter, Example example) {
483      if (!string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty)
484        return Data.WorstResult;
485
486      var printStr = interpreter.PrintStack.ToString();
487      var distance = example.OutputPrint.LevenshteinDistance(printStr);
488
489      long numberOfSyllables;
490      var expectedNumberOfSyllables = example.OutputInteger[0];
491      var numberOfSyllablesError = BenchmarkSuite.Problems.Syllables.GetNumberOfSyllables(printStr, out numberOfSyllables)
492        ? expectedNumberOfSyllables.AbsoluteDiff(numberOfSyllables)
493        : Data.WorstResult / 2.0;
494
495      var result = distance + numberOfSyllablesError;
496      return Math.Min(result, Data.WorstResult);
497    }
498
499    private double Grade(IPushInterpreter interpreter, Example example) {
500      if (!string.IsNullOrEmpty(example.OutputPrint) && interpreter.PrintStack.IsEmpty)
501        return Data.WorstResult;
502
503      var printStr = interpreter.PrintStack.ToString();
504      var distance = example.OutputPrint.LevenshteinDistance(printStr);
505
506      char grade;
507      var expectedGrade = example.OutputChar[0];
508      var gradeError = BenchmarkSuite.Problems.Grades.GetGrade(printStr, out grade)
509        ? expectedGrade.AbsoluteDiff(grade)
510        : char.MaxValue;
511
512      var result = distance + gradeError;
513      return Math.Min(result, Data.WorstResult);
514    }
515
516    private static double FloatDiffer(double a, double b, int digits, double worst) {
517      var result = Math.Round(a, digits) - Math.Round(b, digits);
518
519      // ReSharper disable once CompareOfFloatsByEqualityOperator
520      if (result == double.MinValue || double.IsPositiveInfinity(result) ||
521          double.IsNaN(result) ||
522          // ReSharper disable once CompareOfFloatsByEqualityOperator
523          result == double.MaxValue || double.IsNegativeInfinity(result))
524        return worst;
525
526      return Math.Abs(result);
527    }
528
529    private static double IntegerDiffer(long a, long b) {
530      var result = a - b;
531
532      return result == long.MinValue ? long.MaxValue : Math.Abs(result);
533    }
534
535    private static double BooleanDiffer(bool a, bool b) {
536      return a == b ? 0 : 1;
537    }
538
539    private static double StringDiffer(string a, string b) {
540      return a.LevenshteinDistance(b);
541    }
542
543    private static double CharDiffer(char a, char b) {
544      return IntegerDiffer(a, b);
545    }
546
547    private static double VectorDiffer<T>(IReadOnlyList<T> estimated, IReadOnlyList<T> outcome, Func<T, T, double> differ) {
548      var length = Math.Min(estimated.Count, outcome.Count);
549      var result = 0d;
550
551      for (var i = 0; i < length; i++) {
552        result += differ(estimated[i], outcome[i]);
553      }
554
555      if (estimated.Count > outcome.Count) {
556        var remainingLength = estimated.Count - length;
557        for (var i = 0; i < remainingLength; i++)
558          result += differ(estimated[i], default(T));
559      }
560
561      return result;
562    }
563
564    private static double GetPrintDiffer(string estimated, string printResult, double worstResult) {
565      var distance = estimated.LevenshteinDistance(printResult);
566
567      return Math.Min(distance, worstResult);
568    }
569
570    private static double GetPrintDiffer(string estimated, IPrintStack printStack, double worstResult) {
571      var printResult = printStack.ToString();
572      var distance = estimated.LevenshteinDistance(printResult);
573
574      return Math.Min(distance, worstResult);
575    }
576
577    private static double GetVectorDiff<T>(IReadOnlyList<IReadOnlyList<T>> estimated, IPushStack<IReadOnlyList<T>> resultStack, double worstResult, Func<IReadOnlyList<T>, IReadOnlyList<T>, double> differ)
578      where T : IComparable {
579      if (estimated.Count == 0) return 0d;
580      if (resultStack.IsEmpty && estimated.Count > 0) return worstResult;
581
582      var diff = 0d;
583      var comparableLength = Math.Min(estimated.Count, resultStack.Count);
584
585      if (!resultStack.IsEmpty) {
586
587        for (var i = 0; i < comparableLength && diff < worstResult; i++) {
588          diff += differ(estimated[i], resultStack[i]);
589        }
590      }
591
592      var emptyTArray = new T[0];
593      for (var i = comparableLength; i < estimated.Count - comparableLength && diff < worstResult; i++) {
594        diff += differ(estimated[i], emptyTArray);
595      }
596
597      return double.IsNaN(diff) || double.IsInfinity(diff)
598         ? worstResult
599         : Math.Min(diff, worstResult);
600    }
601
602    private static double GetDiff<T>(IReadOnlyList<T> estimated, IPushStack<T> resultStack, double worstResult, Func<T, T, double> differ)
603      where T : IComparable {
604      if (estimated.Count == 0) return 0d;
605      if (resultStack.IsEmpty && estimated.Count > 0) return worstResult;
606
607      var diff = 0d;
608      var comparableLength = Math.Min(estimated.Count, resultStack.Count);
609
610      if (!resultStack.IsEmpty) {
611        for (var i = 0; i < comparableLength && diff < worstResult; i++) {
612          diff += differ(estimated[i], resultStack[i]);
613        }
614      }
615
616      for (var i = comparableLength; i < estimated.Count - comparableLength && diff < worstResult; i++) {
617        diff += differ(estimated[i], default(T));
618      }
619
620      return double.IsNaN(diff) || double.IsInfinity(diff)
621        ? worstResult
622        : Math.Min(diff, worstResult);
623    }
624  }
625}
Note: See TracBrowser for help on using the repository browser.