Changeset 14654


Ignore:
Timestamp:
02/08/17 22:49:12 (4 years ago)
Author:
abeham
Message:

#2634:

  • restructured code a little to be easier to understand
  • removed some redundancies
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.cs

    r14652 r14654  
    299299                           && r.Results.ContainsKey(table)
    300300                           && r.Visible
    301                          group r by selectedGroup == AllRuns ? AllRuns : r.Parameters[selectedGroup].ToString() into g
     301                         let key = selectedGroup == AllRuns ? AllRuns : r.Parameters[selectedGroup].ToString()
     302                         group r by key into g
    302303                         select Tuple.Create(g.Key, g.ToList()))) {
    303304        var pDict = problems.ToDictionary(r => r, _ => new List<IRun>());
     
    329330
    330331      var xAxisTitles = new HashSet<string>();
     332
     333      // hits describes the number of target hits at a certain time for a certain group
     334      var hits = new Dictionary<string, SortedList<double, int>>();
     335      // misses describes the number of target misses after a certain time for a certain group
     336      // for instance when a run ends, but has not achieved all targets, misses describes
     337      // how many targets have been left open at the point when the run ended
     338      var misses = new Dictionary<string, SortedList<double, int>>();
     339
     340      var aggregate = aggregateTargetsCheckBox.Checked;
     341      double minEff = double.MaxValue, maxEff = double.MinValue;
     342      var noRuns = 0;
     343      foreach (var group in groupedRuns) {
     344        SortedList<double, int> epdfHits = null, epdfMisses = null;
     345        if (aggregate) {
     346          hits[group.Key] = epdfHits = new SortedList<double, int>();
     347          misses[group.Key] = epdfMisses = new SortedList<double, int>();
     348        }
     349        foreach (var problem in group.Value) {
     350          var max = problem.Key.IsMaximization();
     351          var absTargets = GetAbsoluteTargets(problem.Key).ToArray();
     352          foreach (var run in problem.Value) {
     353            noRuns++;
     354            var resultsTable = (IndexedDataTable<double>)run.Results[table];
     355            xAxisTitles.Add(resultsTable.VisualProperties.XAxisTitle);
     356
     357            var efforts = absTargets.Select(t => GetEffortToHitTarget(resultsTable.Rows.First().Values, t, max)).ToArray();
     358            minEff = Math.Min(minEff, efforts.Min(x => x.Item2));
     359            maxEff = Math.Max(maxEff, efforts.Max(x => x.Item2));
     360            for (var idx = 0; idx < efforts.Length; idx++) {
     361              var e = efforts[idx];
     362              if (!aggregate) {
     363                var key = group.Key + "@" + (targetsAreRelative
     364                  ? (targets[idx] * 100).ToString(CultureInfo.CurrentCulture.NumberFormat) + "%"
     365                  : targets[idx].ToString(CultureInfo.CurrentCulture.NumberFormat));
     366                if (!hits.TryGetValue(key, out epdfHits))
     367                  hits[key] = epdfHits = new SortedList<double, int>();
     368                if (!misses.TryGetValue(key, out epdfMisses))
     369                  misses[key] = epdfMisses = new SortedList<double, int>();
     370              }
     371              var list = e.Item1 ? epdfHits : epdfMisses;
     372              int v;
     373              if (list.TryGetValue(e.Item2, out v))
     374                list[e.Item2] = v + 1;
     375              else list[e.Item2] = 1;
     376            }
     377          }
     378        }
     379      }
     380
     381      UpdateTargetChartAxisXBounds(minEff, maxEff);
     382
     383      DrawTargetsEcdf(hits, misses, noRuns);
     384
     385      if (targets.Length == 1) {
     386        if (targetsAreRelative)
     387          targetChart.ChartAreas[0].AxisY.Title = "Probability to be " + (targets[0] * 100) + "% worse than best";
     388        else targetChart.ChartAreas[0].AxisY.Title = "Probability to reach at least a fitness of " + targets[0];
     389      } else targetChart.ChartAreas[0].AxisY.Title = "Proportion of reached targets";
     390      targetChart.ChartAreas[0].AxisX.Title = string.Join(" / ", xAxisTitles);
     391      targetChart.ChartAreas[0].AxisX.IsLogarithmic = CanDisplayLogarithmic();
     392      targetChart.ChartAreas[0].CursorY.Interval = 0.05;
     393
     394      UpdateErtTables(groupedRuns);
     395    }
     396
     397    private void DrawTargetsEcdf(Dictionary<string, SortedList<double, int>> hits, Dictionary<string, SortedList<double, int>> misses, int noRuns) {
    331398      var colorCount = 0;
    332399      var lineStyleCount = 0;
    333 
    334       // if the group contains multiple different problem instances we want to use the
    335       // minimal maximal observed effort otherwise we run into situations where we don't
    336       // have data for a certain problem instance anymore this is a special case when
    337       // aggregating over multiple problem instances     
    338       var maxEfforts = new Dictionary<ProblemInstance, double>();
    339       double minEff = double.MaxValue, maxEff = double.MinValue;
    340       foreach (var group in groupedRuns) {
    341         foreach (var problem in group.Value) {
    342           double problemSpecificMaxEff;
    343           if (!maxEfforts.TryGetValue(problem.Key, out problemSpecificMaxEff)) {
    344             problemSpecificMaxEff = 0;
    345           }
    346           var max = problem.Key.IsMaximization();
    347           var absTargets = GetAbsoluteTargetsWorstToBest(max, problem.Key.BestKnownQuality);
    348           var worstTarget = absTargets.First();
    349           var bestTarget = absTargets.Last();
    350           foreach (var run in problem.Value) {
    351             var row = ((IndexedDataTable<double>)run.Results[table]).Rows.First().Values;
    352             var a = row.FirstOrDefault(x => max ? x.Item2 >= worstTarget : x.Item2 <= worstTarget);
    353             var b = row.FirstOrDefault(x => max ? x.Item2 >= bestTarget : x.Item2 <= bestTarget);
    354             var firstEff = (a == default(Tuple<double, double>)) ? row.Last().Item1 : a.Item1;
    355             var lastEff = (b == default(Tuple<double, double>)) ? row.Last().Item1 : b.Item1;
    356             if (minEff > firstEff) minEff = firstEff;
    357             if (maxEff < lastEff) maxEff = lastEff;
    358             if (problemSpecificMaxEff < lastEff) problemSpecificMaxEff = lastEff;
    359           }
    360           maxEfforts[problem.Key] = problemSpecificMaxEff;
    361         }
    362       }
    363       maxEff = Math.Min(maxEff, maxEfforts.Values.Min());
    364 
     400     
     401      var showMarkers = markerCheckBox.Checked;
     402      foreach (var list in hits) {
     403        var row = new Series(list.Key) {
     404          ChartType = SeriesChartType.StepLine,
     405          BorderWidth = 3,
     406          Color = colors[colorCount],
     407          BorderDashStyle = lineStyles[lineStyleCount],
     408        };
     409        var rowShade = new Series(list.Key + "-range") {
     410          IsVisibleInLegend = false,
     411          ChartType = SeriesChartType.Range,
     412          Color = Color.FromArgb(32, colors[colorCount]),
     413          YValuesPerPoint = 2
     414        };
     415
     416        var ecdf = 0.0;
     417        var missedecdf = 0.0;
     418        var iter = misses[list.Key].GetEnumerator();
     419        var moreMisses = iter.MoveNext();
     420        var totalTargets = noRuns;
     421        if (aggregateTargetsCheckBox.Checked) totalTargets *= targets.Length;
     422        var movingTargets = totalTargets;
     423        var labelPrinted = false;
     424        foreach (var h in list.Value) {
     425          var prevmissedecdf = missedecdf;
     426          while (moreMisses && iter.Current.Key <= h.Key) {
     427            if (!labelPrinted && row.Points.Count > 0) {
     428              var point = row.Points.Last();
     429              point.Label = row.Name;
     430              point.MarkerStyle = MarkerStyle.Cross;
     431              point.MarkerBorderWidth = 1;
     432              point.MarkerSize = 10;
     433              labelPrinted = true;
     434              rowShade.Points.Add(new DataPoint(point.XValue, new[] {ecdf / totalTargets, (ecdf + missedecdf) / totalTargets}));
     435            }
     436            missedecdf += iter.Current.Value;
     437            movingTargets -= iter.Current.Value;
     438            if (row.Points.Count > 0 && row.Points.Last().XValue == iter.Current.Key) {
     439              row.Points.Last().SetValueY(ecdf / movingTargets);
     440              row.Points.Last().Color = Color.FromArgb(255 - (int)Math.Floor(255 * (prevmissedecdf / totalTargets)), colors[colorCount]);
     441            } else {
     442              var dp = new DataPoint(iter.Current.Key, ecdf / movingTargets) {
     443                Color = Color.FromArgb(255 - (int)Math.Floor(255 * (prevmissedecdf / totalTargets)), colors[colorCount])
     444              };
     445              if (showMarkers) {
     446                dp.MarkerStyle = MarkerStyle.Circle;
     447                dp.MarkerBorderWidth = 1;
     448                dp.MarkerSize = 5;
     449              }
     450              row.Points.Add(dp);
     451              prevmissedecdf = missedecdf;
     452            }
     453            if (boundShadingCheckBox.Checked) {
     454              if (rowShade.Points.Count > 0 && rowShade.Points.Last().XValue == iter.Current.Key)
     455                rowShade.Points.Last().SetValueY(ecdf / totalTargets, (ecdf + missedecdf) / totalTargets);
     456              else rowShade.Points.Add(new DataPoint(iter.Current.Key, new[] {ecdf / totalTargets, (ecdf + missedecdf) / totalTargets}));
     457            }
     458            moreMisses = iter.MoveNext();
     459            if (!labelPrinted) {
     460              var point = row.Points.Last();
     461              point.Label = row.Name;
     462              point.MarkerStyle = MarkerStyle.Cross;
     463              point.MarkerBorderWidth = 1;
     464              point.MarkerSize = 10;
     465              labelPrinted = true;
     466            }
     467          }
     468          ecdf += h.Value;
     469          if (row.Points.Count > 0 && row.Points.Last().XValue == h.Key) {
     470            row.Points.Last().SetValueY(ecdf / movingTargets);
     471            row.Points.Last().Color = Color.FromArgb(255 - (int)Math.Floor(255 * (missedecdf / totalTargets)), colors[colorCount]);
     472          } else {
     473            var dp = new DataPoint(h.Key, ecdf / movingTargets) {
     474              Color = Color.FromArgb(255 - (int)Math.Floor(255 * (missedecdf / totalTargets)), colors[colorCount])
     475            };
     476            if (showMarkers) {
     477              dp.MarkerStyle = MarkerStyle.Circle;
     478              dp.MarkerBorderWidth = 1;
     479              dp.MarkerSize = 5;
     480            }
     481            row.Points.Add(dp);
     482          }
     483          if (missedecdf > 0 && boundShadingCheckBox.Checked) {
     484            if (rowShade.Points.Count > 0 && rowShade.Points.Last().XValue == h.Key)
     485              rowShade.Points.Last().SetValueY(ecdf / totalTargets, (ecdf + missedecdf) / totalTargets);
     486            else rowShade.Points.Add(new DataPoint(h.Key, new[] {ecdf / totalTargets, (ecdf + missedecdf) / totalTargets}));
     487          }
     488        }
     489
     490        while (moreMisses) {
     491          // if there are misses beyond the last hit we extend the shaded area
     492          missedecdf += iter.Current.Value;
     493          var dp = new DataPoint(iter.Current.Key, ecdf / movingTargets) {
     494            Color = Color.FromArgb(255 - (int)Math.Floor(255 * (missedecdf / totalTargets)), colors[colorCount])
     495          };
     496          if (showMarkers) {
     497            dp.MarkerStyle = MarkerStyle.Circle;
     498            dp.MarkerBorderWidth = 1;
     499            dp.MarkerSize = 5;
     500          }
     501          row.Points.Add(dp);
     502          if (boundShadingCheckBox.Checked) {
     503            rowShade.Points.Add(new DataPoint(iter.Current.Key, new[] {ecdf / totalTargets, (ecdf + missedecdf) / totalTargets}));
     504          }
     505          moreMisses = iter.MoveNext();
     506
     507          if (!labelPrinted && row.Points.Count > 0) {
     508            var point = row.Points.Last();
     509            point.Label = row.Name;
     510            point.MarkerStyle = MarkerStyle.Cross;
     511            point.MarkerBorderWidth = 1;
     512            point.MarkerSize = 10;
     513            labelPrinted = true;
     514          }
     515        }
     516
     517        if (!labelPrinted) {
     518          var point = row.Points.Last();
     519          point.Label = row.Name;
     520          point.MarkerStyle = MarkerStyle.Cross;
     521          point.MarkerBorderWidth = 1;
     522          point.MarkerSize = 10;
     523          rowShade.Points.Add(new DataPoint(point.XValue, new[] {ecdf / totalTargets, (ecdf + missedecdf) / totalTargets}));
     524          labelPrinted = true;
     525        }
     526
     527        ConfigureSeries(row);
     528        targetChart.Series.Add(rowShade);
     529        targetChart.Series.Add(row);
     530
     531        colorCount = (colorCount + 1) % colors.Length;
     532        if (colorCount == 0) lineStyleCount = (lineStyleCount + 1) % lineStyles.Length;
     533      }
     534    }
     535
     536    private void UpdateTargetChartAxisXBounds(double minEff, double maxEff) {
    365537      var minZeros = (int)Math.Floor(Math.Log10(minEff));
    366538      var maxZeros = (int)Math.Floor(Math.Log10(maxEff));
     
    375547      targetChart.ChartAreas[0].AxisX.Minimum = (double)axisMin;
    376548      targetChart.ChartAreas[0].AxisX.Maximum = (double)axisMax;
    377 
    378       foreach (var group in groupedRuns) {
    379         // hits describes the number of target hits at a certain time for a certain group
    380         var hits = new Dictionary<string, SortedList<double, int>>();
    381         // misses describes the number of target misses after a certain time for a certain group
    382         // for instance when a run ends, but has not achieved all targets, misses describes
    383         // how many targets have been left open at the point when the run ended
    384         var misses = new Dictionary<string, SortedList<double, int>>();
    385         var maxLength = 0.0;
    386 
    387         var noRuns = 0;
    388         foreach (var problem in group.Value) {
    389           foreach (var run in problem.Value) {
    390             var resultsTable = (IndexedDataTable<double>)run.Results[table];
    391             xAxisTitles.Add(resultsTable.VisualProperties.XAxisTitle);
    392 
    393             if (aggregateTargetsCheckBox.Checked) {
    394               var length = CalculateHitsForAllTargets(hits, misses, resultsTable.Rows.First(), problem.Key, group.Key, problem.Key.BestKnownQuality, maxEff);
    395               maxLength = Math.Max(length, maxLength);
    396             } else {
    397               CalculateHitsForEachTarget(hits, misses, resultsTable.Rows.First(), problem.Key, group.Key, problem.Key.BestKnownQuality, maxEff);
    398             }
    399             noRuns++;
    400           }
    401         }
    402         var showMarkers = markerCheckBox.Checked;
    403         foreach (var list in hits) {
    404           var row = new Series(list.Key) {
    405             ChartType = SeriesChartType.StepLine,
    406             BorderWidth = 3,
    407             Color = colors[colorCount],
    408             BorderDashStyle = lineStyles[lineStyleCount],
    409           };
    410           var rowShade = new Series(list.Key + "-range") {
    411             IsVisibleInLegend = false,
    412             ChartType = SeriesChartType.Range,
    413             Color = Color.FromArgb(32, colors[colorCount]),
    414             YValuesPerPoint = 2
    415           };
    416 
    417           var ecdf = 0.0;
    418           var missedecdf = 0.0;
    419           var iter = misses[list.Key].GetEnumerator();
    420           var moreMisses = iter.MoveNext();
    421           var totalTargets = noRuns;
    422           if (aggregateTargetsCheckBox.Checked) totalTargets *= targets.Length;
    423           var movingTargets = totalTargets;
    424           var labelPrinted = false;
    425           foreach (var h in list.Value) {
    426             var prevmissedecdf = missedecdf;
    427             while (moreMisses && iter.Current.Key <= h.Key) {
    428               if (!labelPrinted && row.Points.Count > 0) {
    429                 var point = row.Points.Last();
    430                 point.Label = row.Name;
    431                 point.MarkerStyle = MarkerStyle.Cross;
    432                 point.MarkerBorderWidth = 1;
    433                 point.MarkerSize = 10;
    434                 labelPrinted = true;
    435                 rowShade.Points.Add(new DataPoint(point.XValue, new[] { ecdf / totalTargets, (ecdf + missedecdf) / totalTargets }));
    436               }
    437               missedecdf += iter.Current.Value;
    438               movingTargets -= iter.Current.Value;
    439               if (row.Points.Count > 0 && row.Points.Last().XValue == iter.Current.Key) {
    440                 row.Points.Last().SetValueY(ecdf / movingTargets);
    441                 row.Points.Last().Color = Color.FromArgb(255 - (int)Math.Floor(255 * (prevmissedecdf / totalTargets)), colors[colorCount]);
    442               } else {
    443                 var dp = new DataPoint(iter.Current.Key, ecdf / movingTargets) {
    444                   Color = Color.FromArgb(255 - (int)Math.Floor(255 * (prevmissedecdf / totalTargets)), colors[colorCount])
    445                 };
    446                 if (showMarkers) {
    447                   dp.MarkerStyle = MarkerStyle.Circle;
    448                   dp.MarkerBorderWidth = 1;
    449                   dp.MarkerSize = 5;
    450                 }
    451                 row.Points.Add(dp);
    452                 prevmissedecdf = missedecdf;
    453               }
    454               if (boundShadingCheckBox.Checked) {
    455                 if (rowShade.Points.Count > 0 && rowShade.Points.Last().XValue == iter.Current.Key)
    456                   rowShade.Points.Last().SetValueY(ecdf / totalTargets, (ecdf + missedecdf) / totalTargets);
    457                 else rowShade.Points.Add(new DataPoint(iter.Current.Key, new[] { ecdf / totalTargets, (ecdf + missedecdf) / totalTargets }));
    458               }
    459               moreMisses = iter.MoveNext();
    460               if (!labelPrinted) {
    461                 var point = row.Points.Last();
    462                 point.Label = row.Name;
    463                 point.MarkerStyle = MarkerStyle.Cross;
    464                 point.MarkerBorderWidth = 1;
    465                 point.MarkerSize = 10;
    466                 labelPrinted = true;
    467               }
    468             }
    469             ecdf += h.Value;
    470             if (row.Points.Count > 0 && row.Points.Last().XValue == h.Key) {
    471               row.Points.Last().SetValueY(ecdf / movingTargets);
    472               row.Points.Last().Color = Color.FromArgb(255 - (int)Math.Floor(255 * (missedecdf / totalTargets)), colors[colorCount]);
    473             } else {
    474               var dp = new DataPoint(h.Key, ecdf / movingTargets) {
    475                 Color = Color.FromArgb(255 - (int)Math.Floor(255 * (missedecdf / totalTargets)), colors[colorCount])
    476               };
    477               if (showMarkers) {
    478                 dp.MarkerStyle = MarkerStyle.Circle;
    479                 dp.MarkerBorderWidth = 1;
    480                 dp.MarkerSize = 5;
    481               }
    482               row.Points.Add(dp);
    483             }
    484             if (missedecdf > 0 && boundShadingCheckBox.Checked) {
    485               if (rowShade.Points.Count > 0 && rowShade.Points.Last().XValue == h.Key)
    486                 rowShade.Points.Last().SetValueY(ecdf / totalTargets, (ecdf + missedecdf) / totalTargets);
    487               else rowShade.Points.Add(new DataPoint(h.Key, new[] { ecdf / totalTargets, (ecdf + missedecdf) / totalTargets }));
    488             }
    489           }
    490 
    491           if (!labelPrinted && row.Points.Count > 0) {
    492             var point = row.Points.Last();
    493             point.Label = row.Name;
    494             point.MarkerStyle = MarkerStyle.Cross;
    495             point.MarkerBorderWidth = 1;
    496             point.MarkerSize = 10;
    497             rowShade.Points.Add(new DataPoint(point.XValue, new[] { ecdf / totalTargets, (ecdf + missedecdf) / totalTargets }));
    498           }
    499 
    500           while (moreMisses) {
    501             // if there are misses beyond the last hit we extend the shaded area
    502             missedecdf += iter.Current.Value;
    503             //movingTargets -= iter.Current.Value;
    504             if (row.Points.Count > 0 && row.Points.Last().XValue == iter.Current.Key) {
    505               row.Points.Last().SetValueY(ecdf / movingTargets);
    506               row.Points.Last().Color = Color.FromArgb(255 - (int)Math.Floor(255 * (missedecdf / totalTargets)), colors[colorCount]);
    507             } else {
    508               var dp = new DataPoint(iter.Current.Key, ecdf / movingTargets) {
    509                 Color = Color.FromArgb(255 - (int)Math.Floor(255 * (missedecdf / totalTargets)), colors[colorCount])
    510               };
    511               if (showMarkers) {
    512                 dp.MarkerStyle = MarkerStyle.Circle;
    513                 dp.MarkerBorderWidth = 1;
    514                 dp.MarkerSize = 5;
    515               }
    516               row.Points.Add(dp);
    517             }
    518             if (boundShadingCheckBox.Checked) {
    519               if (rowShade.Points.Count > 0 && rowShade.Points.Last().XValue == iter.Current.Key)
    520                 rowShade.Points.Last().SetValueY(ecdf / totalTargets, (ecdf + missedecdf) / totalTargets);
    521               else rowShade.Points.Add(new DataPoint(iter.Current.Key, new[] { ecdf / totalTargets, (ecdf + missedecdf) / totalTargets }));
    522             }
    523             moreMisses = iter.MoveNext();
    524           }
    525 
    526           if (maxLength > 0 && (row.Points.Count == 0 || row.Points.Last().XValue < maxLength)) {
    527             var dp = new DataPoint(maxLength, ecdf / movingTargets) {
    528               Color = Color.FromArgb(255 - (int)Math.Floor(255 * (missedecdf / totalTargets)), colors[colorCount])
    529             };
    530             if (showMarkers) {
    531               dp.MarkerStyle = MarkerStyle.Circle;
    532               dp.MarkerBorderWidth = 1;
    533               dp.MarkerSize = 5;
    534             }
    535             row.Points.Add(dp);
    536           }
    537 
    538           ConfigureSeries(row);
    539           targetChart.Series.Add(rowShade);
    540           targetChart.Series.Add(row);
    541         }
    542         colorCount = (colorCount + 1) % colors.Length;
    543         if (colorCount == 0) lineStyleCount = (lineStyleCount + 1) % lineStyles.Length;
    544       }
    545 
    546       if (targets.Length == 1) {
    547         if (targetsAreRelative)
    548           targetChart.ChartAreas[0].AxisY.Title = "Probability to be " + (targets[0] * 100) + "% worse than best";
    549         else targetChart.ChartAreas[0].AxisY.Title = "Probability to reach at least a fitness of " + targets[0];
    550       } else targetChart.ChartAreas[0].AxisY.Title = "Proportion of reached targets";
    551       targetChart.ChartAreas[0].AxisX.Title = string.Join(" / ", xAxisTitles);
    552       targetChart.ChartAreas[0].AxisX.IsLogarithmic = CanDisplayLogarithmic();
    553       targetChart.ChartAreas[0].CursorY.Interval = 0.05;
    554       UpdateErtTables(groupedRuns);
    555     }
    556    
    557     private IEnumerable<double> GetAbsoluteTargets(bool maximization, double bestKnown) {
     549    }
     550
     551    private IEnumerable<double> GetAbsoluteTargets(ProblemInstance pInstance) {
    558552      if (!targetsAreRelative) return targets;
     553      var maximization = pInstance.IsMaximization();
     554      var bestKnown = pInstance.BestKnownQuality;
     555      if (double.IsNaN(bestKnown)) throw new ArgumentException("Problem instance does not have a defined best - known quality.");
    559556      IEnumerable<double> tmp = null;
    560557      if (bestKnown > 0) {
     
    569566    }
    570567
    571     private double[] GetAbsoluteTargetsWorstToBest(bool maximization, double bestKnown) {
    572       var absTargets = GetAbsoluteTargets(maximization, bestKnown);
    573       return maximization ? absTargets.OrderBy(x => x).ToArray() : absTargets.OrderByDescending(x => x).ToArray();
     568    private double[] GetAbsoluteTargetsWorstToBest(ProblemInstance pInstance) {
     569      if (double.IsNaN(pInstance.BestKnownQuality)) throw new ArgumentException("Problem instance does not have a defined best-known quality.");
     570      var absTargets = GetAbsoluteTargets(pInstance);
     571      return (pInstance.IsMaximization()
     572        ? absTargets.OrderBy(x => x) : absTargets.OrderByDescending(x => x)).ToArray();
    574573    }
    575574
    576575    private void GenerateDefaultTargets() {
    577       targets = new[] { 0.1, 0.05, 0.02, 0.01, 0 };
     576      targets = new[] { 0.1, 0.095, 0.09, 0.085, 0.08, 0.075, 0.07, 0.065, 0.06, 0.055, 0.05, 0.045, 0.04, 0.035, 0.03, 0.025, 0.02, 0.015, 0.01, 0.005, 0 };
    578577      suppressTargetsEvents = true;
    579578      targetsTextBox.Text = string.Join("% ; ", targets.Select(x => x * 100)) + "%";
     
    581580    }
    582581
    583     private void CalculateHitsForEachTarget(Dictionary<string, SortedList<double, int>> hits,
    584                                             Dictionary<string, SortedList<double, int>> misses,
    585                                             IndexedDataRow<double> row, ProblemInstance problem,
    586                                             string group, double bestTarget, double maxEffort) {
    587       var maximization = problem.IsMaximization();
    588       foreach (var t in targets.Zip(GetAbsoluteTargets(maximization, bestTarget), (rt, at) => Tuple.Create(at, rt))) {
    589         var l = t.Item1;
    590         var key = group + "_" + (targetsAreRelative ? (t.Item2 * 100) + "%_" + l : l.ToString());
    591         if (!hits.ContainsKey(key)) {
    592           hits.Add(key, new SortedList<double, int>());
    593           misses.Add(key, new SortedList<double, int>());
    594         }
    595         var hit = false;
    596         foreach (var v in row.Values) {
    597           if (v.Item1 > maxEffort) break;
    598           if (maximization && v.Item2 >= l || !maximization && v.Item2 <= l) {
    599             if (hits[key].ContainsKey(v.Item1))
    600               hits[key][v.Item1]++;
    601             else hits[key][v.Item1] = 1;
    602             hit = true;
    603             break;
    604           }
    605         }
    606         if (!hit) {
    607           var max = Math.Min(row.Values.Last().Item1, maxEffort);
    608           if (misses[key].ContainsKey(max))
    609             misses[key][max]++;
    610           else misses[key][max] = 1;
    611         }
    612       }
    613     }
    614 
    615     private double CalculateHitsForAllTargets(Dictionary<string, SortedList<double, int>> hits,
    616                                               Dictionary<string, SortedList<double, int>> misses,
    617                                               IndexedDataRow<double> row, ProblemInstance problem,
    618                                               string group, double bestTarget, double maxEffort) {
    619       var values = row.Values;
    620       if (!hits.ContainsKey(group)) {
    621         hits.Add(group, new SortedList<double, int>());
    622         misses.Add(group, new SortedList<double, int>());
    623       }
    624 
    625       var i = 0;
    626       var j = 0;
    627       var max = problem.IsMaximization();
    628       var absTargets = GetAbsoluteTargetsWorstToBest(max, bestTarget);
    629       while (i < absTargets.Length && j < values.Count) {
    630         var target = absTargets[i];
    631         var current = values[j];
    632         if (current.Item1 > maxEffort) break;
    633         if (problem.IsMaximization() && current.Item2 >= target
    634           || !problem.IsMaximization() && current.Item2 <= target) {
    635           if (hits[group].ContainsKey(current.Item1)) hits[group][current.Item1]++;
    636           else hits[group][current.Item1] = 1;
    637           i++;
    638         } else {
    639           j++;
    640         }
    641       }
    642       if (j == values.Count) j--;
    643       var effort = Math.Min(values[j].Item1, maxEffort);
    644       if (i < absTargets.Length) {
    645         if (misses[group].ContainsKey(effort))
    646           misses[group][effort] += absTargets.Length - i;
    647         else misses[group][effort] = absTargets.Length - i;
    648       }
    649       return effort;
     582    private Tuple<bool, double> GetEffortToHitTarget(
     583        IEnumerable<Tuple<double, double>> convergenceGraph,
     584        double absTarget, bool maximization) {
     585      var hit = false;
     586      var effort = double.NaN;
     587      foreach (var dent in convergenceGraph) {
     588        effort = dent.Item1;
     589        hit = maximization && dent.Item2 >= absTarget || !maximization && dent.Item2 <= absTarget;
     590        if (hit) break;
     591      }
     592      if (double.IsNaN(effort)) throw new ArgumentException("Convergence graph is empty.", "convergenceGraph");
     593      return Tuple.Create(hit, effort);
    650594    }
    651595
     
    664608        var max = problem.IsMaximization();
    665609        matrix[rowCount, 0] = problem.ToString();
    666         var absTargets = GetAbsoluteTargetsWorstToBest(max, problem.BestKnownQuality);
     610        var absTargets = GetAbsoluteTargetsWorstToBest(problem);
    667611        for (var i = 0; i < absTargets.Length; i++) {
    668612          matrix[rowCount, i + 1] = absTargets[i].ToString(CultureInfo.CurrentCulture.NumberFormat);
     
    756700      var min = runs.Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Select(y => y.Item1).Min()).Min();
    757701      var max = runs.Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Select(y => y.Item1).Max()).Max();
    758 
    759       var maxMagnitude = (int)Math.Ceiling(Math.Log10(max));
    760       var minMagnitude = (int)Math.Floor(Math.Log10(min));
    761       if (maxMagnitude - minMagnitude >= 3) {
    762         budgets = new double[maxMagnitude - minMagnitude];
    763         for (var i = minMagnitude; i < maxMagnitude; i++) {
    764           budgets[i - minMagnitude] = Math.Pow(10, i);
    765         }
    766       } else {
    767         var range = max - min;
    768         budgets = Enumerable.Range(0, 6).Select(x => min + (x / 5.0) * range).ToArray();
    769       }
     702      var points = 20;
     703      budgets = Enumerable.Range(1, points).Select(x => min + (x / (double)points) * (max - min)).ToArray();
    770704      suppressBudgetsEvents = true;
    771705      budgetsTextBox.Text = string.Join(" ; ", budgets);
     
    784718            if (prev == null && v.Item1 != b) break;
    785719            var tgt = ((prev == null || v.Item1 == b) ? v.Item2 : prev.Item2);
    786             var relTgt = CalculateRelativeDifference(max, problem.BestKnownQuality, tgt);
     720            var relTgt = CalculateRelativeDifference(max, problem.BestKnownQuality, tgt) + 1;
    787721            if (hits[key].ContainsKey(relTgt))
    788722              hits[key][relTgt] += 1.0 / (groupCount * problemCount);
     
    809743          if (prev != null || current.Item1 == budgets[i]) {
    810744            var tgt = (prev == null || current.Item1 == budgets[i]) ? current.Item2 : prev.Item2;
    811             var relTgt = CalculateRelativeDifference(max, problem.BestKnownQuality, tgt);
     745            var relTgt = CalculateRelativeDifference(max, problem.BestKnownQuality, tgt) + 1;
    812746            if (!hits[groupName].ContainsKey(relTgt)) hits[groupName][relTgt] = 0;
    813747            hits[groupName][relTgt] += 1.0 / (groupCount * problemCount * budgets.Length);
     
    820754      }
    821755      var lastTgt = values.Last().Item2;
    822       var lastRelTgt = CalculateRelativeDifference(max, problem.BestKnownQuality, lastTgt);
     756      var lastRelTgt = CalculateRelativeDifference(max, problem.BestKnownQuality, lastTgt) + 1;
    823757      if (i < budgets.Length && !hits[groupName].ContainsKey(lastRelTgt)) hits[groupName][lastRelTgt] = 0;
    824758      while (i < budgets.Length) {
     
    906840      if (!double.IsNaN(pd.BestKnownQuality)) {
    907841        var max = pd.IsMaximization();
    908         if (targetsAreRelative) targets = GetAbsoluteTargets(max, pd.BestKnownQuality).ToArray();
     842        if (targetsAreRelative) targets = GetAbsoluteTargets(pd).ToArray();
    909843        else {
    910844          // Rounding to 5 digits since it's certainly appropriate for this application
     
    960894      var table = (string)dataTableComboBox.SelectedItem;
    961895      if (string.IsNullOrEmpty(table)) return;
    962 
    963       var targetsPerProblem = problems.ToDictionary(x => x, x => x.BestKnownQuality);
    964 
     896     
    965897      foreach (var run in Content) {
    966898        if (!run.Results.ContainsKey(table)) continue;
     
    971903        var pd = new ProblemInstance(run);
    972904        var max = pd.IsMaximization();
    973         var absTargets = GetAbsoluteTargetsWorstToBest(max, targetsPerProblem[pd]);
     905        var absTargets = GetAbsoluteTargetsWorstToBest(problems.Single(x => x.Equals(pd)));
    974906        while (i < absTargets.Length && j < values.Count) {
    975907          var target = absTargets[i];
Note: See TracChangeset for help on using the changeset viewer.