Changeset 15220


Ignore:
Timestamp:
07/12/17 21:59:49 (12 days ago)
Author:
abeham
Message:

#2634, #2744, #745: merged revisions 14102, 14647, 14652, 14654, 14734, 14737, 14775, 15048, 15125, 15126 to stable, reverted changes from revision 15153

Location:
stable
Files:
1 deleted
12 edited
13 copied

Legend:

Unmodified
Added
Removed
  • stable

  • stable/HeuristicLab 3.3.sln

    r15217 r15220  
    9494    {B94FFB82-43D4-40AB-9980-B03470ADF221} = {B94FFB82-43D4-40AB-9980-B03470ADF221}
    9595    {06D4A186-9319-48A0-BADE-A2058D462EEA} = {06D4A186-9319-48A0-BADE-A2058D462EEA}
     96    {4C7F6D8A-B279-4898-ACD6-7BE39111DEF9} = {4C7F6D8A-B279-4898-ACD6-7BE39111DEF9}
    9697    {5B9B9E8C-2706-43C2-80B8-A08341E431F7} = {5B9B9E8C-2706-43C2-80B8-A08341E431F7}
    9798    {997F018D-AEA2-4F21-9301-82FAF6A5612D} = {997F018D-AEA2-4F21-9301-82FAF6A5612D}
     
    448449EndProject
    449450Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Problems.BinPacking-3.3", "HeuristicLab.Problems.BinPacking\3.3\HeuristicLab.Problems.BinPacking-3.3.csproj", "{F8A55094-3CD5-4034-B0CA-5BD7FFB016D4}"
     451EndProject
     452Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Algorithms.DataAnalysis.Glmnet-3.4", "HeuristicLab.Algorithms.DataAnalysis.Glmnet\3.4\HeuristicLab.Algorithms.DataAnalysis.Glmnet-3.4.csproj", "{4C7F6D8A-B279-4898-ACD6-7BE39111DEF9}"
    450453EndProject
    451454Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Problems.Instances.DIMACS-3.3", "HeuristicLab.Problems.Instances.DIMACS\3.3\HeuristicLab.Problems.Instances.DIMACS-3.3.csproj", "{9943FF23-8619-459C-B84A-E7FBDCBA04E6}"
     
    21792182    {F8A55094-3CD5-4034-B0CA-5BD7FFB016D4}.Release|x86.ActiveCfg = Release|x86
    21802183    {F8A55094-3CD5-4034-B0CA-5BD7FFB016D4}.Release|x86.Build.0 = Release|x86
     2184    {4C7F6D8A-B279-4898-ACD6-7BE39111DEF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
     2185    {4C7F6D8A-B279-4898-ACD6-7BE39111DEF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
     2186    {4C7F6D8A-B279-4898-ACD6-7BE39111DEF9}.Debug|x64.ActiveCfg = Debug|x64
     2187    {4C7F6D8A-B279-4898-ACD6-7BE39111DEF9}.Debug|x64.Build.0 = Debug|x64
     2188    {4C7F6D8A-B279-4898-ACD6-7BE39111DEF9}.Debug|x86.ActiveCfg = Debug|x86
     2189    {4C7F6D8A-B279-4898-ACD6-7BE39111DEF9}.Debug|x86.Build.0 = Debug|x86
     2190    {4C7F6D8A-B279-4898-ACD6-7BE39111DEF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
     2191    {4C7F6D8A-B279-4898-ACD6-7BE39111DEF9}.Release|Any CPU.Build.0 = Release|Any CPU
     2192    {4C7F6D8A-B279-4898-ACD6-7BE39111DEF9}.Release|x64.ActiveCfg = Release|x64
     2193    {4C7F6D8A-B279-4898-ACD6-7BE39111DEF9}.Release|x64.Build.0 = Release|x64
     2194    {4C7F6D8A-B279-4898-ACD6-7BE39111DEF9}.Release|x86.ActiveCfg = Release|x86
     2195    {4C7F6D8A-B279-4898-ACD6-7BE39111DEF9}.Release|x86.Build.0 = Release|x86
    21812196    {9943FF23-8619-459C-B84A-E7FBDCBA04E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
    21822197    {9943FF23-8619-459C-B84A-E7FBDCBA04E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
  • stable/HeuristicLab.Analysis

  • stable/HeuristicLab.Analysis.Views

  • stable/HeuristicLab.Analysis.Views/3.3/GanttDataView.cs

    r14734 r15220  
    5050      Content.Rows.ItemsReplaced += GanttRowsOnChanged;
    5151      Content.Rows.CollectionReset += GanttRowsOnChanged;
     52      Content.CategoryColors.ItemsAdded += GanttCategoryColorsOnChanged;
     53      Content.CategoryColors.ItemsRemoved += GanttCategoryColorsOnChanged;
     54      Content.CategoryColors.ItemsReplaced += GanttCategoryColorsOnChanged;
     55      Content.CategoryColors.CollectionReset += GanttCategoryColorsOnChanged;
    5256      foreach (var row in Content.Rows)
    5357        RegisterGanttRowEvents(row);
     
    7377      Content.Rows.ItemsReplaced -= GanttRowsOnChanged;
    7478      Content.Rows.CollectionReset -= GanttRowsOnChanged;
     79      Content.CategoryColors.ItemsAdded -= GanttCategoryColorsOnChanged;
     80      Content.CategoryColors.ItemsRemoved -= GanttCategoryColorsOnChanged;
     81      Content.CategoryColors.ItemsReplaced -= GanttCategoryColorsOnChanged;
     82      Content.CategoryColors.CollectionReset -= GanttCategoryColorsOnChanged;
    7583      foreach (var row in Content.Rows)
    7684        DeregisterGanttRowEvents(row);
     
    121129     
    122130      ganttChart.Hide();
     131      ganttChart.Title = string.IsNullOrWhiteSpace(Content.Name) ? null : Content.Name;
    123132      foreach (var row in Content.Rows) {
    124133        foreach (var item in row.Items) {
     
    138147      UpdateVisualization();
    139148    }
    140 
    141149    private void GanttRowsOnRemoved(object sender, CollectionItemsChangedEventArgs<GanttRow> e) {
    142150      foreach (var row in e.Items)
    143151        DeregisterGanttRowEvents(row);
    144152
     153      UpdateVisualization();
     154    }
     155    private void GanttCategoryColorsOnChanged(object sender, EventArgs e) {
    145156      UpdateVisualization();
    146157    }
  • stable/HeuristicLab.Analysis.Views/3.3/HeuristicLab.Analysis.Views-3.3.csproj

    r15097 r15220  
    132132      <DependentUpon>DataTableView.cs</DependentUpon>
    133133    </Compile>
     134    <Compile Include="GanttDataView.cs">
     135      <SubType>UserControl</SubType>
     136    </Compile>
     137    <Compile Include="GanttDataView.Designer.cs">
     138      <DependentUpon>GanttDataView.cs</DependentUpon>
     139    </Compile>
     140    <Compile Include="IndexedDataTableView.cs">
     141      <SubType>UserControl</SubType>
     142    </Compile>
     143    <Compile Include="IndexedDataTableView.Designer.cs">
     144      <DependentUpon>IndexedDataTableView.cs</DependentUpon>
     145    </Compile>
    134146    <Compile Include="ScatterPlotView.cs">
    135147      <SubType>UserControl</SubType>
  • stable/HeuristicLab.Analysis.Views/3.3/IndexedDataTableView.cs

    r14102 r15220  
    158158      series.BorderColor = Color.Empty;
    159159
    160       if (row.VisualProperties.Color != Color.Empty)
    161         series.Color = row.VisualProperties.Color;
    162       else series.Color = Color.Empty;
     160      series.Color = row.VisualProperties.Color;
    163161      series.IsVisibleInLegend = row.VisualProperties.IsVisibleInLegend;
    164162
     
    561559      for (int i = 0; i < row.Values.Count; i++) {
    562560        var value = row.Values[i];
     561        if (IsInvalidValue(value.Item2)) continue;
    563562        var point = new DataPoint();
    564563        point.SetValueXY(value.Item1, value.Item2);
  • stable/HeuristicLab.Analysis/3.3/DataVisualization/GanttData.cs

    r14734 r15220  
    3434  [Item("Gantt Data", "Data of a Gantt visualization")]
    3535  [StorableClass]
    36   public class GanttData : Item {
     36  public class GanttData : NamedItem {
    3737
    3838    [Storable]
     
    5151      categoryColors = new ObservableDictionary<string, Color>(original.categoryColors);
    5252    }
    53     public GanttData() {
     53    public GanttData() : this("Gantt Data", "Data of a Gantt visualization") { }
     54    public GanttData(string name) : this(name, string.Empty) { }
     55    public GanttData(string name, string description) : base(name, description) {
    5456      rows = new NamedItemCollection<GanttRow>();
    5557      categoryColors = new ObservableDictionary<string, Color>();
    5658    }
    57     public GanttData(IEnumerable<GanttRow> rows) {
     59    public GanttData(IEnumerable<GanttRow> rows) : this("Gantt Data", rows) { }
     60    public GanttData(string name, IEnumerable<GanttRow> rows) : this(name, string.Empty, rows) { }
     61    public GanttData(string name, string description, IEnumerable<GanttRow> rows) : base(name, description) {
    5862      this.rows = new NamedItemCollection<GanttRow>(rows);
    5963      categoryColors = new ObservableDictionary<string, Color>();
     
    7882      items = cloner.Clone(original.items);
    7983    }
    80     public GanttRow() {
     84    public GanttRow() : this("Gantt Row", "Row of a Gantt chart") { }
     85    public GanttRow(string name) : this(name, string.Empty) { }
     86    public GanttRow(string name, string description) : base(name, description) {
    8187      items = new ItemList<GanttItem>();
    8288    }
    83     public GanttRow(IEnumerable<GanttItem> items) {
     89    public GanttRow(IEnumerable<GanttItem> items) : this("Gantt Row", items) { }
     90    public GanttRow(string name, IEnumerable<GanttItem> items) : this(name, string.Empty, items) { }
     91    public GanttRow(string name, string description, IEnumerable<GanttItem> items) : base(name, description) {
    8492      this.items = new ItemList<GanttItem>(items);
    8593    }
  • stable/HeuristicLab.Analysis/3.3/DataVisualization/IndexedDataRow.cs

    r14102 r15220  
    3030
    3131namespace HeuristicLab.Analysis {
    32   [Item("IndexedDataRow", "A data row that contains time series.")]
     32  [Item("IndexedDataRow", "A data row that contains a series of points.")]
    3333  [StorableClass]
    3434  public class IndexedDataRow<T> : NamedItem {
     
    105105      OnVisualPropertiesChanged();
    106106    }
     107    protected override void OnNameChanged() {
     108      base.OnNameChanged();
     109      VisualProperties.DisplayName = Name;
     110    }
    107111  }
    108112}
  • stable/HeuristicLab.Analysis/3.3/DataVisualization/IndexedDataTable.cs

    r14102 r15220  
    107107    public event EventHandler VisualPropertiesChanged;
    108108    protected virtual void OnVisualPropertiesChanged() {
    109       EventHandler handler = VisualPropertiesChanged;
     109      var handler = VisualPropertiesChanged;
    110110      if (handler != null) handler(this, EventArgs.Empty);
    111111    }
     
    115115    }
    116116
    117     protected virtual void RegisterRowsEvents() {
    118       rows.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedDataRow<T>>(rows_ItemsAdded);
    119       rows.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedDataRow<T>>(rows_ItemsRemoved);
    120       rows.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedDataRow<T>>(rows_ItemsReplaced);
    121       rows.CollectionReset += new CollectionItemsChangedEventHandler<IndexedDataRow<T>>(rows_CollectionReset);
    122     }
    123     private void rows_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedDataRow<T>> e) {
     117    private void RegisterRowsEvents() {
     118      rows.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedDataRow<T>>(RowsOnItemsAdded);
     119      rows.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedDataRow<T>>(RowsOnItemsRemoved);
     120      rows.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedDataRow<T>>(RowsOnItemsReplaced);
     121      rows.CollectionReset += new CollectionItemsChangedEventHandler<IndexedDataRow<T>>(RowsOnCollectionReset);
     122      foreach (var row in Rows) RegisterRowEvents(row);
     123    }
     124    protected virtual void RowsOnItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedDataRow<T>> e) {
    124125      foreach (var row in e.Items)
    125126        this.RegisterRowEvents(row);
     
    129130      this.OnReset();
    130131    }
    131     private void rows_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedDataRow<T>> e) {
     132    protected virtual void RowsOnItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedDataRow<T>> e) {
    132133      foreach (var row in e.Items)
    133134        this.DeregisterRowEvents(row);
     
    137138      this.OnReset();
    138139    }
    139     private void rows_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedDataRow<T>> e) {
     140    protected virtual void RowsOnItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedDataRow<T>> e) {
    140141      foreach (var row in e.OldItems)
    141142        this.DeregisterRowEvents(row);
     
    147148      this.OnReset();
    148149    }
    149     private void rows_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedDataRow<T>> e) {
     150    protected virtual void RowsOnCollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedDataRow<T>> e) {
    150151      foreach (var row in e.OldItems)
    151152        this.DeregisterRowEvents(row);
     
    159160    }
    160161
    161     protected virtual void RegisterRowEvents(IndexedDataRow<T> row) {
    162       row.Values.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<Tuple<T, double>>>(Values_ItemsAdded);
    163       row.Values.ItemsMoved += new CollectionItemsChangedEventHandler<IndexedItem<Tuple<T, double>>>(Values_ItemsMoved);
    164       row.Values.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<Tuple<T, double>>>(Values_ItemsRemoved);
    165       row.Values.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<Tuple<T, double>>>(Values_ItemsReplaced);
    166       row.Values.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<Tuple<T, double>>>(Values_CollectionReset);
    167     }
    168     protected virtual void DeregisterRowEvents(IndexedDataRow<T> row) {
    169       row.Values.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<Tuple<T, double>>>(Values_ItemsAdded);
    170       row.Values.ItemsMoved -= new CollectionItemsChangedEventHandler<IndexedItem<Tuple<T, double>>>(Values_ItemsMoved);
    171       row.Values.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<Tuple<T, double>>>(Values_ItemsRemoved);
    172       row.Values.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<Tuple<T, double>>>(Values_ItemsReplaced);
    173       row.Values.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<Tuple<T, double>>>(Values_CollectionReset);
    174     }
    175 
    176     private void Values_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<Tuple<T, double>>> e) {
    177       this.OnReset();
    178     }
    179     private void Values_ItemsMoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<Tuple<T, double>>> e) {
    180       this.OnReset();
    181     }
    182     private void Values_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<Tuple<T, double>>> e) {
    183       this.OnReset();
    184     }
    185     private void Values_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<Tuple<T, double>>> e) {
    186       this.OnReset();
    187     }
    188     private void Values_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<Tuple<T, double>>> e) {
     162    private void RegisterRowEvents(IndexedDataRow<T> row) {
     163      row.Values.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<Tuple<T, double>>>(ValuesOnItemsAdded);
     164      row.Values.ItemsMoved += new CollectionItemsChangedEventHandler<IndexedItem<Tuple<T, double>>>(ValuesOnItemsMoved);
     165      row.Values.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<Tuple<T, double>>>(ValuesOnItemsRemoved);
     166      row.Values.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<Tuple<T, double>>>(ValuesOnItemsReplaced);
     167      row.Values.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<Tuple<T, double>>>(ValuesOnCollectionReset);
     168    }
     169    private void DeregisterRowEvents(IndexedDataRow<T> row) {
     170      row.Values.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<Tuple<T, double>>>(ValuesOnItemsAdded);
     171      row.Values.ItemsMoved -= new CollectionItemsChangedEventHandler<IndexedItem<Tuple<T, double>>>(ValuesOnItemsMoved);
     172      row.Values.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<Tuple<T, double>>>(ValuesOnItemsRemoved);
     173      row.Values.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<Tuple<T, double>>>(ValuesOnItemsReplaced);
     174      row.Values.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<Tuple<T, double>>>(ValuesOnCollectionReset);
     175    }
     176
     177    protected virtual void ValuesOnItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<Tuple<T, double>>> e) {
     178      this.OnReset();
     179    }
     180    protected virtual void ValuesOnItemsMoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<Tuple<T, double>>> e) {
     181      this.OnReset();
     182    }
     183    protected virtual void ValuesOnItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<Tuple<T, double>>> e) {
     184      this.OnReset();
     185    }
     186    protected virtual void ValuesOnItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<Tuple<T, double>>> e) {
     187      this.OnReset();
     188    }
     189    protected virtual void ValuesOnCollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<Tuple<T, double>>> e) {
    189190      this.OnReset();
    190191    }
  • stable/HeuristicLab.Analysis/3.3/HeuristicLab.Analysis-3.3.csproj

    r12280 r15220  
    131131    <Compile Include="AlleleFrequencyAnalysis\AlleleFrequencyCollectionHistory.cs" />
    132132    <Compile Include="BestScopeSolutionAnalyzer.cs" />
     133    <Compile Include="DataVisualization\GanttData.cs" />
     134    <Compile Include="DataVisualization\IndexedDataRow.cs" />
     135    <Compile Include="DataVisualization\IndexedDataTable.cs" />
    133136    <Compile Include="DataVisualization\ScatterPlotDataRowVisualProperties.cs" />
    134137    <Compile Include="DataVisualization\ScatterPlotDataRow.cs" />
     
    154157    <Compile Include="QualityAnalysis\BestAverageWorstQualityCalculator.cs" />
    155158    <Compile Include="QualityAnalysis\BestQualityMemorizer.cs" />
     159    <Compile Include="QualityAnalysis\ExpectedRuntimeHelper.cs" />
    156160    <Compile Include="QualityAnalysis\QualityAnalyzer.cs" />
    157161    <Compile Include="QualityAnalysis\QualityDifferenceCalculator.cs" />
     
    159163    <Compile Include="Properties\AssemblyInfo.cs" />
    160164    <Compile Include="QualityAnalysis\QualityDistributionAnalyzer.cs" />
     165    <Compile Include="QualityAnalysis\QualityPerClockAnalyzer.cs" />
     166    <Compile Include="QualityAnalysis\QualityPerEvaluationsAnalyzer.cs" />
    161167    <Compile Include="QualityAnalysis\ScaledQualityDifferenceAnalyzer.cs" />
    162168    <Compile Include="Statistics\BonferroniHolm.cs" />
  • stable/HeuristicLab.Analysis/3.3/QualityAnalysis/ExpectedRuntimeHelper.cs

    r14102 r15220  
    3030      if (successful.Count > 0) {
    3131        var succAvg = successful.Average();
    32         var succDev = successful.StandardDeviation();
     32        var succDev = successful.StandardDeviation() + 1e-7;
    3333        successful.RemoveAll(x => x < succAvg - 2 * succDev);
    3434        unsuccessful.RemoveAll(x => x < succAvg - 2 * succDev);
     
    4646
    4747  public struct ErtCalculationResult {
    48     public int SuccessfulRuns;
    49     public int TotalRuns;
    50     public double ExpectedRuntime;
     48    public readonly int SuccessfulRuns;
     49    public readonly int TotalRuns;
     50    public readonly double ExpectedRuntime;
    5151
    5252    public ErtCalculationResult(int successful, int total, double ert) {
     
    5757
    5858    public override string ToString() {
    59       return SuccessfulRuns == 0 ? "\u221e" // infinity symbol
    60                                  : ExpectedRuntime.ToString("##,0.0", CultureInfo.CurrentCulture.NumberFormat);
     59      return ExpectedRuntime.ToString("##,0.0", CultureInfo.CurrentCulture.NumberFormat);
    6160    }
    6261  }
  • stable/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityPerClockAnalyzer.cs

    r14102 r15220  
    9191
    9292      if (values.Count == 0) {
    93         values.Add(newEntry);
    94         values.Add(Tuple.Create(runtimeSoFar, bestQuality)); // duplicate entry that will be replaced
     93        values.Add(newEntry); // record the first data
     94        values.Add(Tuple.Create(runtimeSoFar, bestQuality)); // last entry records max number of evaluations
    9595        return base.Apply();
    9696      }
     
    9898      var improvement = values.Last().Item2 != bestQuality;
    9999      if (improvement) {
    100         values[values.Count - 1] = newEntry;
    101         values.Add(Tuple.Create(runtimeSoFar, bestQuality)); // duplicate entry that will be replaced
     100        values[values.Count - 1] = newEntry; // record the improvement
     101        values.Add(Tuple.Create(runtimeSoFar, bestQuality)); // last entry records max number of evaluations
    102102      } else {
    103103        values[values.Count - 1] = Tuple.Create(runtimeSoFar, bestQuality);
  • stable/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityPerEvaluationsAnalyzer.cs

    r14102 r15220  
    8888      if (evalMoves != null) evaluations += evalMoves.Value * MoveCostPerSolutionParameter.ActualValue.Value;
    8989
    90       var dataTable = QualityPerEvaluationsParameter.ActualValue;
    91       var values = dataTable.Rows["First-hit Graph"].Values;
    92       if (evaluations == 0 || values.Count > 0 && evaluations < values.Last().Item1) evaluations = 1;
    93       var newEntry = Tuple.Create(evaluations, bestQuality);
     90      if (evaluations > 0) {
     91        var dataTable = QualityPerEvaluationsParameter.ActualValue;
     92        var values = dataTable.Rows["First-hit Graph"].Values;
    9493
    95       if (values.Count == 0) {
    96         values.Add(newEntry);
    97         values.Add(Tuple.Create(evaluations, bestQuality)); // duplicate entry that will be replaced
    98         return base.Apply();
    99       }
     94        var newEntry = Tuple.Create(evaluations, bestQuality);
    10095
    101       var improvement = values.Last().Item2 != bestQuality;
    102       if (improvement) {
    103         values[values.Count - 1] = newEntry;
    104         values.Add(Tuple.Create(evaluations, bestQuality)); // duplicate entry that will be replaced
    105       } else {
    106         values[values.Count - 1] = Tuple.Create(evaluations, bestQuality);
     96        if (values.Count == 0) {
     97          values.Add(newEntry); // record the first data
     98          values.Add(Tuple.Create(evaluations, bestQuality)); // last entry records max number of evaluations
     99          return base.Apply();
     100        }
     101
     102        var improvement = values.Last().Item2 != bestQuality;
     103        if (improvement) {
     104          values[values.Count - 1] = newEntry; // record the improvement
     105          values.Add(Tuple.Create(evaluations, bestQuality)); // last entry records max number of evaluations
     106        } else {
     107          values[values.Count - 1] = Tuple.Create(evaluations, bestQuality); // the last entry is updated
     108        }
    107109      }
    108110      return base.Apply();
  • stable/HeuristicLab.Common/3.3/HeuristicLab.Common-3.3.csproj

    r12740 r15220  
    131131    <Compile Include="Constants.cs" />
    132132    <Compile Include="ArrayExtensions.cs" />
     133    <Compile Include="Statistics\EmpiricalCumulativeDistributionFunction.cs" />
    133134    <Compile Include="ListExtensions.cs" />
    134135    <Compile Include="Point2D.cs" />
     
    139140    <Compile Include="DeepCloneable.cs" />
    140141    <Compile Include="Content\IContent.cs" />
    141     <Compile Include="EnumerableStatisticExtensions.cs" />
     142    <Compile Include="Statistics\EnumerableStatisticExtensions.cs" />
    142143    <Compile Include="IDeepCloneable.cs" />
    143144    <Compile Include="Plugin.cs" />
  • stable/HeuristicLab.Common/3.3/Point2D.cs

    r15097 r15220  
    5454    }
    5555
     56    public static Point2D<T> Create(T x, T y, object tag = null) {
     57      return new Point2D<T>(x, y, tag);
     58    }
     59
    5660    public static bool operator ==(Point2D<T> left, Point2D<T> right) {
    5761      return left.x.Equals(right.x) && left.y.Equals(right.y) && left.tag == right.tag;
  • stable/HeuristicLab.Optimization.Views

  • stable/HeuristicLab.Optimization.Views/3.3/HeuristicLab.Optimization.Views-3.3.csproj

    r15081 r15220  
    269269      <DependentUpon>RunCollectionEqualityConstraintView.cs</DependentUpon>
    270270    </Compile>
     271    <Compile Include="RunCollectionViews\RunCollectionRLDView.cs">
     272      <SubType>UserControl</SubType>
     273    </Compile>
     274    <Compile Include="RunCollectionViews\RunCollectionRLDView.Designer.cs">
     275      <DependentUpon>RunCollectionRLDView.cs</DependentUpon>
     276    </Compile>
    271277    <Compile Include="RunCollectionViews\RunCollectionTableView.cs">
    272278      <SubType>UserControl</SubType>
  • stable/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.Designer.cs

    r14102 r15220  
    4545    private void InitializeComponent() {
    4646      this.components = new System.ComponentModel.Container();
    47       System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
    48       System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
     47      System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea2 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
     48      System.Windows.Forms.DataVisualization.Charting.Legend legend2 = new System.Windows.Forms.DataVisualization.Charting.Legend();
    4949      this.dataTableComboBox = new System.Windows.Forms.ComboBox();
    5050      this.dataTableLabel = new System.Windows.Forms.Label();
     
    6464      this.tabControl = new System.Windows.Forms.TabControl();
    6565      this.byTargetTabPage = new System.Windows.Forms.TabPage();
     66      this.relativeOrAbsoluteComboBox = new System.Windows.Forms.ComboBox();
    6667      this.targetChart = new HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart();
     68      this.showLabelsCheckBox = new System.Windows.Forms.CheckBox();
     69      this.markerCheckBox = new System.Windows.Forms.CheckBox();
    6770      this.boundShadingCheckBox = new System.Windows.Forms.CheckBox();
    6871      this.byCostTabPage = new System.Windows.Forms.TabPage();
    6972      this.byCostViewHost = new HeuristicLab.MainForm.WindowsForms.ViewHost();
    7073      this.budgetLogScalingCheckBox = new System.Windows.Forms.CheckBox();
    71       this.eachOrAllBudgetsCheckBox = new System.Windows.Forms.CheckBox();
    7274      this.generateBudgetsButton = new System.Windows.Forms.Button();
    7375      this.byTableTabPage = new System.Windows.Forms.TabPage();
     
    143145      this.targetsTextBox.Location = new System.Drawing.Point(59, 8);
    144146      this.targetsTextBox.Name = "targetsTextBox";
    145       this.targetsTextBox.Size = new System.Drawing.Size(287, 20);
     147      this.targetsTextBox.Size = new System.Drawing.Size(204, 20);
    146148      this.targetsTextBox.TabIndex = 1;
    147149      this.toolTip.SetToolTip(this.targetsTextBox, "The order of the targets is important, first to-hit targets\r\nshould be given firs" +
     
    200202      this.budgetsTextBox.Location = new System.Drawing.Point(59, 8);
    201203      this.budgetsTextBox.Name = "budgetsTextBox";
    202       this.budgetsTextBox.Size = new System.Drawing.Size(326, 20);
     204      this.budgetsTextBox.Size = new System.Drawing.Size(391, 20);
    203205      this.budgetsTextBox.TabIndex = 6;
    204206      this.budgetsTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.budgetsTextBox_Validating);
     
    221223      this.aggregateTargetsCheckBox.Checked = true;
    222224      this.aggregateTargetsCheckBox.CheckState = System.Windows.Forms.CheckState.Checked;
    223       this.aggregateTargetsCheckBox.Location = new System.Drawing.Point(352, 10);
     225      this.aggregateTargetsCheckBox.Location = new System.Drawing.Point(374, 10);
    224226      this.aggregateTargetsCheckBox.Name = "aggregateTargetsCheckBox";
    225227      this.aggregateTargetsCheckBox.Size = new System.Drawing.Size(74, 17);
     
    245247      // byTargetTabPage
    246248      //
     249      this.byTargetTabPage.Controls.Add(this.relativeOrAbsoluteComboBox);
    247250      this.byTargetTabPage.Controls.Add(this.targetChart);
     251      this.byTargetTabPage.Controls.Add(this.showLabelsCheckBox);
     252      this.byTargetTabPage.Controls.Add(this.markerCheckBox);
    248253      this.byTargetTabPage.Controls.Add(this.boundShadingCheckBox);
    249254      this.byTargetTabPage.Controls.Add(this.targetLogScalingCheckBox);
     
    261266      this.byTargetTabPage.UseVisualStyleBackColor = true;
    262267      //
     268      // relativeOrAbsoluteComboBox
     269      //
     270      this.relativeOrAbsoluteComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
     271      this.relativeOrAbsoluteComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
     272      this.relativeOrAbsoluteComboBox.FormattingEnabled = true;
     273      this.relativeOrAbsoluteComboBox.Items.AddRange(new object[] {
     274            "relative",
     275            "absolute"});
     276      this.relativeOrAbsoluteComboBox.Location = new System.Drawing.Point(269, 8);
     277      this.relativeOrAbsoluteComboBox.Name = "relativeOrAbsoluteComboBox";
     278      this.relativeOrAbsoluteComboBox.Size = new System.Drawing.Size(99, 21);
     279      this.relativeOrAbsoluteComboBox.TabIndex = 8;
     280      this.relativeOrAbsoluteComboBox.SelectedIndexChanged += new System.EventHandler(this.relativeOrAbsoluteComboBox_SelectedIndexChanged);
     281      //
    263282      // targetChart
    264283      //
     
    266285            | System.Windows.Forms.AnchorStyles.Left)
    267286            | System.Windows.Forms.AnchorStyles.Right)));
    268       chartArea1.AxisX.IsStartedFromZero = false;
    269       chartArea1.AxisX.MinorGrid.Enabled = true;
    270       chartArea1.AxisX.MinorGrid.LineColor = System.Drawing.Color.WhiteSmoke;
    271       chartArea1.AxisX.MinorGrid.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
    272       chartArea1.AxisY.Maximum = 1D;
    273       chartArea1.AxisY.Minimum = 0D;
    274       chartArea1.AxisY.MinorGrid.Enabled = true;
    275       chartArea1.AxisY.MinorGrid.LineColor = System.Drawing.Color.WhiteSmoke;
    276       chartArea1.AxisY.MinorGrid.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
    277       chartArea1.Name = "ChartArea1";
    278       this.targetChart.ChartAreas.Add(chartArea1);
    279       legend1.Alignment = System.Drawing.StringAlignment.Center;
    280       legend1.Docking = System.Windows.Forms.DataVisualization.Charting.Docking.Top;
    281       legend1.Name = "Legend1";
    282       this.targetChart.Legends.Add(legend1);
     287      chartArea2.AxisX.IsStartedFromZero = false;
     288      chartArea2.AxisX.MinorGrid.Enabled = true;
     289      chartArea2.AxisX.MinorGrid.LineColor = System.Drawing.Color.WhiteSmoke;
     290      chartArea2.AxisX.MinorGrid.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
     291      chartArea2.AxisY.Maximum = 1D;
     292      chartArea2.AxisY.Minimum = 0D;
     293      chartArea2.AxisY.MinorGrid.Enabled = true;
     294      chartArea2.AxisY.MinorGrid.LineColor = System.Drawing.Color.WhiteSmoke;
     295      chartArea2.AxisY.MinorGrid.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
     296      chartArea2.Name = "ChartArea1";
     297      this.targetChart.ChartAreas.Add(chartArea2);
     298      legend2.Alignment = System.Drawing.StringAlignment.Center;
     299      legend2.Docking = System.Windows.Forms.DataVisualization.Charting.Docking.Top;
     300      legend2.Name = "Legend1";
     301      this.targetChart.Legends.Add(legend2);
    283302      this.targetChart.Location = new System.Drawing.Point(6, 34);
    284303      this.targetChart.Name = "targetChart";
     
    290309      this.targetChart.MouseDown += new System.Windows.Forms.MouseEventHandler(this.chart_MouseDown);
    291310      this.targetChart.MouseMove += new System.Windows.Forms.MouseEventHandler(this.chart_MouseMove);
     311      //
     312      // showLabelsCheckBox
     313      //
     314      this.showLabelsCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
     315      this.showLabelsCheckBox.AutoSize = true;
     316      this.showLabelsCheckBox.Checked = true;
     317      this.showLabelsCheckBox.CheckState = System.Windows.Forms.CheckState.Checked;
     318      this.showLabelsCheckBox.Location = new System.Drawing.Point(329, 364);
     319      this.showLabelsCheckBox.Name = "showLabelsCheckBox";
     320      this.showLabelsCheckBox.Size = new System.Drawing.Size(81, 17);
     321      this.showLabelsCheckBox.TabIndex = 6;
     322      this.showLabelsCheckBox.Text = "show labels";
     323      this.showLabelsCheckBox.UseVisualStyleBackColor = true;
     324      this.showLabelsCheckBox.CheckedChanged += new System.EventHandler(this.showLabelsCheckBox_CheckedChanged);
     325      //
     326      // markerCheckBox
     327      //
     328      this.markerCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
     329      this.markerCheckBox.AutoSize = true;
     330      this.markerCheckBox.Location = new System.Drawing.Point(229, 364);
     331      this.markerCheckBox.Name = "markerCheckBox";
     332      this.markerCheckBox.Size = new System.Drawing.Size(91, 17);
     333      this.markerCheckBox.TabIndex = 6;
     334      this.markerCheckBox.Text = "show markers";
     335      this.markerCheckBox.UseVisualStyleBackColor = true;
     336      this.markerCheckBox.CheckedChanged += new System.EventHandler(this.markerCheckBox_CheckedChanged);
    292337      //
    293338      // boundShadingCheckBox
     
    309354      this.byCostTabPage.Controls.Add(this.byCostViewHost);
    310355      this.byCostTabPage.Controls.Add(this.budgetLogScalingCheckBox);
    311       this.byCostTabPage.Controls.Add(this.eachOrAllBudgetsCheckBox);
    312356      this.byCostTabPage.Controls.Add(this.generateBudgetsButton);
    313357      this.byCostTabPage.Controls.Add(this.budgetsLabel);
     
    349393      this.budgetLogScalingCheckBox.UseVisualStyleBackColor = true;
    350394      this.budgetLogScalingCheckBox.CheckedChanged += new System.EventHandler(this.logScalingCheckBox_CheckedChanged);
    351       //
    352       // eachOrAllBudgetsCheckBox
    353       //
    354       this.eachOrAllBudgetsCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
    355       this.eachOrAllBudgetsCheckBox.AutoSize = true;
    356       this.eachOrAllBudgetsCheckBox.Location = new System.Drawing.Point(414, 10);
    357       this.eachOrAllBudgetsCheckBox.Name = "eachOrAllBudgetsCheckBox";
    358       this.eachOrAllBudgetsCheckBox.Size = new System.Drawing.Size(36, 17);
    359       this.eachOrAllBudgetsCheckBox.TabIndex = 10;
    360       this.eachOrAllBudgetsCheckBox.Text = "all";
    361       this.eachOrAllBudgetsCheckBox.UseVisualStyleBackColor = true;
    362       this.eachOrAllBudgetsCheckBox.CheckedChanged += new System.EventHandler(this.eachOrAllBudgetsCheckBox_CheckedChanged);
    363395      //
    364396      // generateBudgetsButton
     
    464496    private System.Windows.Forms.TabPage byCostTabPage;
    465497    private System.Windows.Forms.TabPage byTableTabPage;
    466     private System.Windows.Forms.CheckBox eachOrAllBudgetsCheckBox;
    467498    private System.Windows.Forms.Button generateBudgetsButton;
    468499    private System.Windows.Forms.CheckBox budgetLogScalingCheckBox;
     
    473504    private MainForm.WindowsForms.ViewHost byCostViewHost;
    474505    private System.Windows.Forms.CheckBox boundShadingCheckBox;
     506    private System.Windows.Forms.CheckBox markerCheckBox;
     507    private System.Windows.Forms.ComboBox relativeOrAbsoluteComboBox;
     508    private System.Windows.Forms.CheckBox showLabelsCheckBox;
    475509  }
    476510}
  • stable/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.cs

    r14102 r15220  
    11#region License Information
    22/* HeuristicLab
    3  * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
     3 * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
    44 *
    55 * This file is part of HeuristicLab.
     
    3030using HeuristicLab.Analysis;
    3131using HeuristicLab.Collections;
     32using HeuristicLab.Core;
    3233using HeuristicLab.Core.Views;
    3334using HeuristicLab.Data;
     
    4142    private List<Series> invisibleTargetSeries;
    4243
    43     private const string AllRuns = "All Runs";
     44    private const string AllInstances = "All Instances";
    4445
    4546    private static readonly Color[] colors = new[] {
     
    7980    private double[] targets;
    8081    private double[] budgets;
     82    private bool targetsAreRelative = true;
     83    private bool showLabelsInTargetChart = true;
     84    private readonly BindingList<ProblemInstance> problems;
    8185
    8286    private bool suppressUpdates;
     
    9397      targetChart.ChartAreas[0].CursorX.Interval = 1;
    9498      targetChart.SuppressExceptions = true;
    95       byCostDataTable = new IndexedDataTable<double>("ECDF by Cost", "A data table containing the ECDF of each of a number of groups.") {
     99      byCostDataTable = new IndexedDataTable<double>("ECDF by Cost", "A data table containing the ECDF of function values (relative to best-known).") {
    96100        VisualProperties = {
    97           YAxisTitle = "Proportion of unused budgets",
     101          YAxisTitle = "Proportion of runs",
    98102          YAxisMinimumFixedValue = 0,
    99103          YAxisMinimumAuto = false,
     
    103107      };
    104108      byCostViewHost.Content = byCostDataTable;
     109      suppressUpdates = true;
     110      relativeOrAbsoluteComboBox.SelectedItem = targetsAreRelative ? "relative" : "absolute";
     111      problems = new BindingList<ProblemInstance>();
     112      problemComboBox.DataSource = new BindingSource() { DataSource = problems };
     113      problemComboBox.DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
    105114      suppressUpdates = false;
    106115    }
     
    215224      var groupings = Content.ParameterNames.OrderBy(x => x).ToArray();
    216225      groupComboBox.Items.Clear();
    217       groupComboBox.Items.Add(AllRuns);
     226      groupComboBox.Items.Add(AllInstances);
    218227      groupComboBox.Items.AddRange(groupings);
    219228      if (selectedGroupItem != null && groupComboBox.Items.Contains(selectedGroupItem)) {
     
    223232      }
    224233
    225       var problems = new HashSet<ProblemDescription>();
    226       foreach (var run in Content) {
    227         problems.Add(new ProblemDescription(run));
    228       }
    229 
    230       var problemTypesDifferent = problems.Select(x => x.ProblemType).Where(x => !string.IsNullOrEmpty(x)).Distinct().Count() > 1;
    231       var problemNamesDifferent = problems.Select(x => x.ProblemName).Where(x => !string.IsNullOrEmpty(x)).Distinct().Count() > 1;
    232       var evaluatorDifferent = problems.Select(x => x.Evaluator).Where(x => !string.IsNullOrEmpty(x)).Distinct().Count() > 1;
    233       var maximizationDifferent = problems.Select(x => x.Maximization).Distinct().Count() > 1;
     234      var table = (string)dataTableComboBox.SelectedItem;
     235      var problemDict = CalculateBestTargetPerProblemInstance(table);
     236
     237      var problemTypesDifferent = problemDict.Keys.Select(x => x.ProblemType).Where(x => !string.IsNullOrEmpty(x)).Distinct().Count() > 1;
     238      var problemNamesDifferent = problemDict.Keys.Select(x => x.ProblemName).Where(x => !string.IsNullOrEmpty(x)).Distinct().Count() > 1;
     239      var evaluatorDifferent = problemDict.Keys.Select(x => x.Evaluator).Where(x => !string.IsNullOrEmpty(x)).Distinct().Count() > 1;
     240      var maximizationDifferent = problemDict.Keys.Select(x => x.Maximization).Distinct().Count() > 1;
    234241      var allEqual = !problemTypesDifferent && !problemNamesDifferent && !evaluatorDifferent && !maximizationDifferent;
    235242
    236       var selectedProblemItem = (ProblemDescription)problemComboBox.SelectedItem;
     243      var selectedProblemItem = (ProblemInstance)problemComboBox.SelectedItem;
     244      problemComboBox.DataSource = null;
    237245      problemComboBox.Items.Clear();
    238       problemComboBox.Items.Add(ProblemDescription.MatchAll);
    239       if (selectedProblemItem == null || selectedProblemItem == ProblemDescription.MatchAll)
    240         problemComboBox.SelectedIndex = 0;
    241       foreach (var prob in problems.OrderBy(x => x.ToString()).ToList()) {
    242         prob.DisplayProblemType = problemTypesDifferent;
    243         prob.DisplayProblemName = problemNamesDifferent || allEqual;
    244         prob.DisplayEvaluator = evaluatorDifferent;
    245         prob.DisplayMaximization = maximizationDifferent;
    246         problemComboBox.Items.Add(prob);
    247         if (prob.Equals(selectedProblemItem)) problemComboBox.SelectedItem = prob;
     246      problems.Clear();
     247      problems.Add(ProblemInstance.MatchAll);
     248      problemComboBox.DataSource = new BindingSource() { DataSource = problems };
     249      problemComboBox.DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
     250      if (problems[0].Equals(selectedProblemItem)) problemComboBox.SelectedItem = problems[0];
     251      foreach (var p in problemDict.ToList()) {
     252        p.Key.BestKnownQuality = p.Value;
     253        p.Key.DisplayProblemType = problemTypesDifferent;
     254        p.Key.DisplayProblemName = problemNamesDifferent || allEqual;
     255        p.Key.DisplayEvaluator = evaluatorDifferent;
     256        p.Key.DisplayMaximization = maximizationDifferent;
     257        problems.Add(p.Key);
     258        if (p.Key.Equals(selectedProblemItem)) problemComboBox.SelectedItem = p.Key;
    248259      }
    249260      SetEnabledStateOfControls();
     
    274285      addTargetsAsResultButton.Enabled = Content != null && targets != null && dataTableComboBox.SelectedIndex >= 0;
    275286      addBudgetsAsResultButton.Enabled = Content != null && budgets != null && dataTableComboBox.SelectedIndex >= 0;
    276     }
    277 
    278     private Dictionary<string, Dictionary<ProblemDescription, Tuple<double, List<IRun>>>> GroupRuns() {
    279       var groupedRuns = new Dictionary<string, Dictionary<ProblemDescription, Tuple<double, List<IRun>>>>();
    280 
     287      generateTargetsButton.Enabled = targets != null;
     288    }
     289
     290    private IEnumerable<AlgorithmInstance> GroupRuns() {
    281291      var table = (string)dataTableComboBox.SelectedItem;
    282       if (string.IsNullOrEmpty(table)) return groupedRuns;
     292      if (string.IsNullOrEmpty(table)) yield break;
    283293
    284294      var selectedGroup = (string)groupComboBox.SelectedItem;
    285       if (string.IsNullOrEmpty(selectedGroup)) return groupedRuns;
    286 
    287       var selectedProblem = (ProblemDescription)problemComboBox.SelectedItem;
    288       if (selectedProblem == null) return groupedRuns;
    289 
    290       var targetsPerProblem = CalculateBestTargetPerProblemInstance(table);
    291 
     295      if (string.IsNullOrEmpty(selectedGroup)) yield break;
     296
     297      var selectedProblem = (ProblemInstance)problemComboBox.SelectedItem;
     298      if (selectedProblem == null) yield break;
     299     
    292300      foreach (var x in (from r in Content
    293                          where (selectedGroup == AllRuns || r.Parameters.ContainsKey(selectedGroup))
     301                         where (selectedGroup == AllInstances || r.Parameters.ContainsKey(selectedGroup))
    294302                           && selectedProblem.Match(r)
    295303                           && r.Results.ContainsKey(table)
    296304                           && r.Visible
    297                          group r by selectedGroup == AllRuns ? AllRuns : r.Parameters[selectedGroup].ToString() into g
    298                          select Tuple.Create(g.Key, g.ToList()))) {
    299         var pDict = new Dictionary<ProblemDescription, Tuple<double, List<IRun>>>();
    300         foreach (var y in (from r in x.Item2
    301                            let pd = new ProblemDescription(r)
    302                            group r by pd into g
    303                            select Tuple.Create(g.Key, g.ToList()))) {
    304           pDict[y.Item1] = Tuple.Create(targetsPerProblem[y.Item1], y.Item2);
    305         }
    306         groupedRuns[x.Item1] = pDict;
    307       }
    308 
    309       return groupedRuns;
     305                         let key = selectedGroup == AllInstances ? AllInstances : r.Parameters[selectedGroup].ToString()
     306                         group r by key into g
     307                         select new AlgorithmInstance(g.Key, g, problems))) {
     308        yield return x;
     309      }
    310310    }
    311311
     
    316316      targetChart.Series.Clear();
    317317      invisibleTargetSeries.Clear();
    318 
     318     
    319319      var table = (string)dataTableComboBox.SelectedItem;
    320320      if (string.IsNullOrEmpty(table)) return;
     
    322322      if (targets == null) GenerateDefaultTargets();
    323323
    324       var groupedRuns = GroupRuns();
    325       if (groupedRuns.Count == 0) return;
     324      var algInstances = GroupRuns().ToList();
     325      if (algInstances.Count == 0) return;
    326326
    327327      var xAxisTitles = new HashSet<string>();
     328
     329      // hits describes the number of target hits at a certain time for a certain group
     330      var hits = new Dictionary<string, SortedList<double, int>>();
     331      // misses describes the number of target misses after a certain time for a certain group
     332      // for instance when a run ends, but has not achieved all targets, misses describes
     333      // how many targets have been left open at the point when the run ended
     334      var misses = new Dictionary<string, SortedList<double, int>>();
     335      var totalRuns = new Dictionary<string, int>();
     336
     337      var aggregate = aggregateTargetsCheckBox.Checked;
     338      double minEff = double.MaxValue, maxEff = double.MinValue;
     339      foreach (var alg in algInstances) {
     340        var noRuns = 0;
     341        SortedList<double, int> epdfHits = null, epdfMisses = null;
     342        if (aggregate) {
     343          hits[alg.Name] = epdfHits = new SortedList<double, int>();
     344          misses[alg.Name] = epdfMisses = new SortedList<double, int>();
     345        }
     346        foreach (var problem in alg.GetProblemInstances()) {
     347          var max = problem.IsMaximization();
     348          var absTargets = GetAbsoluteTargets(problem).ToArray();
     349          foreach (var run in alg.GetRuns(problem)) {
     350            noRuns++;
     351            var resultsTable = (IndexedDataTable<double>)run.Results[table];
     352            xAxisTitles.Add(resultsTable.VisualProperties.XAxisTitle);
     353
     354            var efforts = absTargets.Select(t => GetEffortToHitTarget(resultsTable.Rows.First().Values, t, max)).ToArray();
     355            minEff = Math.Min(minEff, efforts.Min(x => x.Item2));
     356            maxEff = Math.Max(maxEff, efforts.Max(x => x.Item2));
     357            for (var idx = 0; idx < efforts.Length; idx++) {
     358              var e = efforts[idx];
     359              if (!aggregate) {
     360                var key = alg.Name + "@" + (targetsAreRelative
     361                            ? (targets[idx] * 100).ToString(CultureInfo.CurrentCulture.NumberFormat) + "%"
     362                            : targets[idx].ToString(CultureInfo.CurrentCulture.NumberFormat));
     363                if (!hits.TryGetValue(key, out epdfHits))
     364                  hits[key] = epdfHits = new SortedList<double, int>();
     365                if (!misses.TryGetValue(key, out epdfMisses))
     366                  misses[key] = epdfMisses = new SortedList<double, int>();
     367                totalRuns[key] = noRuns;
     368              };
     369              var list = e.Item1 ? epdfHits : epdfMisses;
     370              int v;
     371              if (list.TryGetValue(e.Item2, out v))
     372                list[e.Item2] = v + 1;
     373              else list[e.Item2] = 1;
     374            }
     375          }
     376        }
     377        if (aggregate) totalRuns[alg.Name] = noRuns;
     378      }
     379
     380      UpdateTargetChartAxisXBounds(minEff, maxEff);
     381
     382      DrawTargetsEcdf(hits, misses, totalRuns);
     383
     384      if (targets.Length == 1) {
     385        if (targetsAreRelative)
     386          targetChart.ChartAreas[0].AxisY.Title = "Probability to be " + (targets[0] * 100) + "% worse than best";
     387        else targetChart.ChartAreas[0].AxisY.Title = "Probability to reach at least a fitness of " + targets[0];
     388      } else targetChart.ChartAreas[0].AxisY.Title = "Proportion of reached targets";
     389      targetChart.ChartAreas[0].AxisX.Title = string.Join(" / ", xAxisTitles);
     390      targetChart.ChartAreas[0].AxisX.IsLogarithmic = CanDisplayLogarithmic();
     391      targetChart.ChartAreas[0].CursorY.Interval = 0.05;
     392
     393      UpdateErtTables(algInstances);
     394    }
     395
     396    private void DrawTargetsEcdf(Dictionary<string, SortedList<double, int>> hits, Dictionary<string, SortedList<double, int>> misses, Dictionary<string, int> noRuns) {
    328397      var colorCount = 0;
    329398      var lineStyleCount = 0;
    330 
    331       // if the group contains multiple different problem instances we want to use the
    332       // minimal maximal observed effort otherwise we run into situations where we don't
    333       // have data for a certain problem instance anymore this is a special case when
    334       // aggregating over multiple problem instances     
    335       var maxEfforts = new Dictionary<ProblemDescription, double>();
    336       double minEff = double.MaxValue, maxEff = double.MinValue;
    337       foreach (var group in groupedRuns) {
    338         foreach (var problem in group.Value) {
    339           double problemSpecificMaxEff;
    340           if (!maxEfforts.TryGetValue(problem.Key, out problemSpecificMaxEff)) {
    341             problemSpecificMaxEff = 0;
    342           }
    343           var bestKnownTarget = problem.Value.Item1;
    344           var max = problem.Key.IsMaximization();
    345           var worstTarget = (max ? (1 - targets.Max()) : (1 + targets.Max())) * bestKnownTarget;
    346           var bestTarget = (max ? (1 - targets.Min()) : (1 + targets.Min())) * bestKnownTarget;
    347           foreach (var run in problem.Value.Item2) {
    348             var row = ((IndexedDataTable<double>)run.Results[table]).Rows.First().Values;
    349             var a = row.FirstOrDefault(x => max ? x.Item2 >= worstTarget : x.Item2 <= worstTarget);
    350             var b = row.FirstOrDefault(x => max ? x.Item2 >= bestTarget : x.Item2 <= bestTarget);
    351             var firstEff = (a == default(Tuple<double, double>)) ? row.Last().Item1 : a.Item1;
    352             var lastEff = (b == default(Tuple<double, double>)) ? row.Last().Item1 : b.Item1;
    353             if (minEff > firstEff) minEff = firstEff;
    354             if (maxEff < lastEff) maxEff = lastEff;
    355             if (problemSpecificMaxEff < lastEff) problemSpecificMaxEff = lastEff;
    356           }
    357           maxEfforts[problem.Key] = problemSpecificMaxEff;
    358         }
    359       }
    360       maxEff = Math.Min(maxEff, maxEfforts.Values.Min());
    361 
     399     
     400      var showMarkers = markerCheckBox.Checked;
     401      foreach (var list in hits) {
     402        var row = new Series(list.Key) {
     403          ChartType = SeriesChartType.StepLine,
     404          BorderWidth = 3,
     405          Color = colors[colorCount],
     406          BorderDashStyle = lineStyles[lineStyleCount],
     407        };
     408        var rowShade = new Series(list.Key + "-range") {
     409          IsVisibleInLegend = false,
     410          ChartType = SeriesChartType.Range,
     411          Color = Color.FromArgb(32, colors[colorCount]),
     412          YValuesPerPoint = 2
     413        };
     414
     415        var ecdf = 0.0;
     416        var missedecdf = 0.0;
     417        var iter = misses[list.Key].GetEnumerator();
     418        var moreMisses = iter.MoveNext();
     419        var totalTargets = noRuns[list.Key];
     420        if (aggregateTargetsCheckBox.Checked) totalTargets *= targets.Length;
     421        var movingTargets = totalTargets;
     422        var labelPrinted = false;
     423        foreach (var h in list.Value) {
     424          var prevmissedecdf = missedecdf;
     425          while (moreMisses && iter.Current.Key <= h.Key) {
     426            if (!labelPrinted && row.Points.Count > 0) {
     427              var point = row.Points.Last();
     428              if (showLabelsInTargetChart)
     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              if (showLabelsInTargetChart)
     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        while (moreMisses) {
     492          // if there are misses beyond the last hit we extend the shaded area
     493          missedecdf += iter.Current.Value;
     494          var dp = new DataPoint(iter.Current.Key, ecdf / movingTargets) {
     495            Color = Color.FromArgb(255 - (int)Math.Floor(255 * (missedecdf / totalTargets)), colors[colorCount])
     496          };
     497          if (showMarkers) {
     498            dp.MarkerStyle = MarkerStyle.Circle;
     499            dp.MarkerBorderWidth = 1;
     500            dp.MarkerSize = 5;
     501          }
     502          row.Points.Add(dp);
     503          if (boundShadingCheckBox.Checked) {
     504            rowShade.Points.Add(new DataPoint(iter.Current.Key, new[] {ecdf / totalTargets, (ecdf + missedecdf) / totalTargets}));
     505          }
     506          moreMisses = iter.MoveNext();
     507
     508          if (!labelPrinted && row.Points.Count > 0) {
     509            var point = row.Points.Last();
     510            if (showLabelsInTargetChart)
     511              point.Label = row.Name;
     512            point.MarkerStyle = MarkerStyle.Cross;
     513            point.MarkerBorderWidth = 1;
     514            point.MarkerSize = 10;
     515            labelPrinted = true;
     516          }
     517        }
     518
     519        if (!labelPrinted) {
     520          var point = row.Points.Last();
     521          if (showLabelsInTargetChart)
     522            point.Label = row.Name;
     523          point.MarkerStyle = MarkerStyle.Cross;
     524          point.MarkerBorderWidth = 1;
     525          point.MarkerSize = 10;
     526          rowShade.Points.Add(new DataPoint(point.XValue, new[] {ecdf / totalTargets, (ecdf + missedecdf) / totalTargets}));
     527          labelPrinted = true;
     528        }
     529
     530        ConfigureSeries(row);
     531        targetChart.Series.Add(rowShade);
     532        targetChart.Series.Add(row);
     533
     534        colorCount = (colorCount + 1) % colors.Length;
     535        if (colorCount == 0) lineStyleCount = (lineStyleCount + 1) % lineStyles.Length;
     536      }
     537    }
     538
     539    private void UpdateTargetChartAxisXBounds(double minEff, double maxEff) {
    362540      var minZeros = (int)Math.Floor(Math.Log10(minEff));
    363541      var maxZeros = (int)Math.Floor(Math.Log10(maxEff));
     
    372550      targetChart.ChartAreas[0].AxisX.Minimum = (double)axisMin;
    373551      targetChart.ChartAreas[0].AxisX.Maximum = (double)axisMax;
    374 
    375       foreach (var group in groupedRuns) {
    376         // hits describes the number of target hits at a certain time for a certain group
    377         var hits = new Dictionary<string, SortedList<double, int>>();
    378         // misses describes the number of target misses after a certain time for a certain group
    379         // for instance when a run ends, but has not achieved all targets, misses describes
    380         // how many targets have been left open at the point when the run ended
    381         var misses = new Dictionary<string, SortedList<double, int>>();
    382         var maxLength = 0.0;
    383 
    384         var noRuns = 0;
    385         foreach (var problem in group.Value) {
    386           foreach (var run in problem.Value.Item2) {
    387             var resultsTable = (IndexedDataTable<double>)run.Results[table];
    388             xAxisTitles.Add(resultsTable.VisualProperties.XAxisTitle);
    389 
    390             if (aggregateTargetsCheckBox.Checked) {
    391               var length = CalculateHitsForAllTargets(hits, misses, resultsTable.Rows.First(), problem.Key, group.Key, problem.Value.Item1, maxEff);
    392               maxLength = Math.Max(length, maxLength);
    393             } else {
    394               CalculateHitsForEachTarget(hits, misses, resultsTable.Rows.First(), problem.Key, group.Key, problem.Value.Item1, maxEff);
    395             }
    396             noRuns++;
    397           }
    398         }
    399         foreach (var list in hits) {
    400           var row = new Series(list.Key) {
    401             ChartType = SeriesChartType.StepLine,
    402             BorderWidth = 2,
    403             Color = colors[colorCount],
    404             BorderDashStyle = lineStyles[lineStyleCount],
    405           };
    406           var rowShade = new Series(list.Key + "-range") {
    407             IsVisibleInLegend = false,
    408             ChartType = SeriesChartType.Range,
    409             Color = Color.FromArgb(32, colors[colorCount])
    410           };
    411 
    412           var ecdf = 0.0;
    413           var missedecdf = 0.0;
    414           var iter = misses[list.Key].GetEnumerator();
    415           var moreMisses = iter.MoveNext();
    416           var totalTargets = noRuns;
    417           if (aggregateTargetsCheckBox.Checked) totalTargets *= targets.Length;
    418           var movingTargets = totalTargets;
    419           foreach (var h in list.Value) {
    420             while (moreMisses && iter.Current.Key <= h.Key) {
    421               missedecdf += iter.Current.Value;
    422               movingTargets -= iter.Current.Value;
    423               if (row.Points.Count > 0 && row.Points.Last().XValue == iter.Current.Key)
    424                 row.Points.Last().SetValueY(ecdf / movingTargets);
    425               else row.Points.AddXY(iter.Current.Key, ecdf / movingTargets);
    426               if (boundShadingCheckBox.Checked) {
    427                 if (rowShade.Points.Count > 0 && rowShade.Points.Last().XValue == iter.Current.Key)
    428                   rowShade.Points.Last().SetValueY(ecdf / totalTargets, (ecdf + missedecdf) / totalTargets);
    429                 else rowShade.Points.Add(new DataPoint(iter.Current.Key, new[] { ecdf / totalTargets, (ecdf + missedecdf) / totalTargets }));
    430               }
    431               moreMisses = iter.MoveNext();
    432             }
    433             ecdf += h.Value;
    434             if (row.Points.Count > 0 && row.Points.Last().XValue == h.Key)
    435               row.Points.Last().SetValueY(ecdf / movingTargets);
    436             else row.Points.AddXY(h.Key, ecdf / movingTargets);
    437             if (missedecdf > 0 && boundShadingCheckBox.Checked) {
    438               if (rowShade.Points.Count > 0 && rowShade.Points.Last().XValue == h.Key)
    439                 rowShade.Points.Last().SetValueY(ecdf / totalTargets, (ecdf + missedecdf) / totalTargets);
    440               else rowShade.Points.Add(new DataPoint(h.Key, new[] { ecdf / totalTargets, (ecdf + missedecdf) / totalTargets }));
    441             }
    442           }
    443 
    444           while (moreMisses) {
    445             // if there are misses beyond the last hit we extend the shaded area
    446             missedecdf += iter.Current.Value;
    447             //movingTargets -= iter.Current.Value;
    448             if (row.Points.Count > 0 && row.Points.Last().XValue == iter.Current.Key)
    449               row.Points.Last().SetValueY(ecdf / movingTargets);
    450             else row.Points.AddXY(iter.Current.Key, ecdf / movingTargets);
    451             if (boundShadingCheckBox.Checked) {
    452               if (rowShade.Points.Count > 0 && rowShade.Points.Last().XValue == iter.Current.Key)
    453                 rowShade.Points.Last().SetValueY(ecdf / totalTargets, (ecdf + missedecdf) / totalTargets);
    454               else rowShade.Points.Add(new DataPoint(iter.Current.Key, new[] { ecdf / totalTargets, (ecdf + missedecdf) / totalTargets }));
    455             }
    456             moreMisses = iter.MoveNext();
    457           }
    458 
    459           if (maxLength > 0 && (row.Points.Count == 0 || row.Points.Last().XValue < maxLength))
    460             row.Points.AddXY(maxLength, ecdf / movingTargets);
    461 
    462           if (row.Points.Count > 0) {
    463             var point = row.Points.Last();
    464             point.Label = row.Name;
    465             point.MarkerStyle = MarkerStyle.Cross;
    466             point.MarkerBorderWidth = 1;
    467           }
    468 
    469           ConfigureSeries(row);
    470           targetChart.Series.Add(rowShade);
    471           targetChart.Series.Add(row);
    472         }
    473         colorCount = (colorCount + 1) % colors.Length;
    474         if (colorCount == 0) lineStyleCount = (lineStyleCount + 1) % lineStyles.Length;
    475       }
    476 
    477       if (targets.Length == 1)
    478         targetChart.ChartAreas[0].AxisY.Title = "Probability to be " + (targets[0] * 100) + "% worse than best";
    479       else targetChart.ChartAreas[0].AxisY.Title = "Proportion of reached targets";
    480       targetChart.ChartAreas[0].AxisX.Title = string.Join(" / ", xAxisTitles);
    481       targetChart.ChartAreas[0].AxisX.IsLogarithmic = CanDisplayLogarithmic();
    482       targetChart.ChartAreas[0].CursorY.Interval = 0.05;
    483       UpdateErtTables(groupedRuns);
     552    }
     553
     554    private IEnumerable<double> GetAbsoluteTargets(ProblemInstance pInstance) {
     555      if (!targetsAreRelative) return targets;
     556      var maximization = pInstance.IsMaximization();
     557      var bestKnown = pInstance.BestKnownQuality;
     558      if (double.IsNaN(bestKnown)) throw new ArgumentException("Problem instance does not have a defined best - known quality.");
     559      IEnumerable<double> tmp = null;
     560      if (bestKnown > 0) {
     561        tmp = targets.Select(x => (maximization ? (1 - x) : (1 + x)) * bestKnown);
     562      } else if (bestKnown < 0) {
     563        tmp = targets.Select(x => (!maximization ? (1 - x) : (1 + x)) * bestKnown);
     564      } else {
     565        // relative to 0 is impossible
     566        tmp = targets;
     567      }
     568      return tmp;
     569    }
     570
     571    private double[] GetAbsoluteTargetsWorstToBest(ProblemInstance pInstance) {
     572      if (double.IsNaN(pInstance.BestKnownQuality)) throw new ArgumentException("Problem instance does not have a defined best-known quality.");
     573      var absTargets = GetAbsoluteTargets(pInstance);
     574      return (pInstance.IsMaximization()
     575        ? absTargets.OrderBy(x => x) : absTargets.OrderByDescending(x => x)).ToArray();
    484576    }
    485577
    486578    private void GenerateDefaultTargets() {
    487       targets = new[] { 0.1, 0.05, 0.02, 0.01, 0 };
    488       suppressTargetsEvents = true;
    489       targetsTextBox.Text = string.Join("% ; ", targets.Select(x => x * 100)) + "%";
    490       suppressTargetsEvents = false;
    491     }
    492 
    493     private void CalculateHitsForEachTarget(Dictionary<string, SortedList<double, int>> hits,
    494                                             Dictionary<string, SortedList<double, int>> misses,
    495                                             IndexedDataRow<double> row, ProblemDescription problem,
    496                                             string group, double bestTarget, double maxEffort) {
    497       foreach (var t in targets.Select(x => Tuple.Create((problem.IsMaximization() ? (1 - x) : (1 + x)) * bestTarget, x))) {
    498         var l = t.Item1;
    499         var key = group + "_" + (t.Item2 * 100) + "%_" + l;
    500         if (!hits.ContainsKey(key)) {
    501           hits.Add(key, new SortedList<double, int>());
    502           misses.Add(key, new SortedList<double, int>());
    503         }
    504         var hit = false;
    505         foreach (var v in row.Values) {
    506           if (v.Item1 > maxEffort) break;
    507           if (problem.IsMaximization() && v.Item2 >= l || !problem.IsMaximization() && v.Item2 <= l) {
    508             if (hits[key].ContainsKey(v.Item1))
    509               hits[key][v.Item1]++;
    510             else hits[key][v.Item1] = 1;
    511             hit = true;
    512             break;
    513           }
    514         }
    515         if (!hit) {
    516           var max = Math.Min(row.Values.Last().Item1, maxEffort);
    517           if (misses[key].ContainsKey(max))
    518             misses[key][max]++;
    519           else misses[key][max] = 1;
    520         }
    521       }
    522     }
    523 
    524     private double CalculateHitsForAllTargets(Dictionary<string, SortedList<double, int>> hits,
    525                                               Dictionary<string, SortedList<double, int>> misses,
    526                                               IndexedDataRow<double> row, ProblemDescription problem,
    527                                               string group, double bestTarget, double maxEffort) {
    528       var values = row.Values;
    529       if (!hits.ContainsKey(group)) {
    530         hits.Add(group, new SortedList<double, int>());
    531         misses.Add(group, new SortedList<double, int>());
    532       }
    533 
    534       var i = 0;
    535       var j = 0;
    536       while (i < targets.Length && j < values.Count) {
    537         var target = (problem.IsMaximization() ? (1 - targets[i]) : (1 + targets[i])) * bestTarget;
    538         var current = values[j];
    539         if (current.Item1 > maxEffort) break;
    540         if (problem.IsMaximization() && current.Item2 >= target
    541           || !problem.IsMaximization() && current.Item2 <= target) {
    542           if (hits[group].ContainsKey(current.Item1)) hits[group][current.Item1]++;
    543           else hits[group][current.Item1] = 1;
    544           i++;
    545         } else {
    546           j++;
    547         }
    548       }
    549       if (j == values.Count) j--;
    550       var effort = Math.Min(values[j].Item1, maxEffort);
    551       if (i < targets.Length) {
    552         if (misses[group].ContainsKey(effort))
    553           misses[group][effort] += targets.Length - i;
    554         else misses[group][effort] = targets.Length - i;
    555       }
    556       return effort;
    557     }
    558 
    559     private void UpdateErtTables(Dictionary<string, Dictionary<ProblemDescription, Tuple<double, List<IRun>>>> groupedRuns) {
     579      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 };
     580      SynchronizeTargetTextBox();
     581    }
     582
     583    private Tuple<bool, double> GetEffortToHitTarget(
     584        ObservableList<Tuple<double, double>> convergenceGraph,
     585        double absTarget, bool maximization) {
     586      if (convergenceGraph.Count == 0)
     587        throw new ArgumentException("Convergence graph is empty.", "convergenceGraph");
     588     
     589      var index = convergenceGraph.BinarySearch(Tuple.Create(0.0, absTarget), new TargetComparer(maximization));
     590      if (index >= 0) {
     591        return Tuple.Create(true, convergenceGraph[index].Item1);
     592      } else {
     593        index = ~index;
     594        if (index >= convergenceGraph.Count)
     595          return Tuple.Create(false, convergenceGraph.Last().Item1);
     596        return Tuple.Create(true, convergenceGraph[index].Item1);
     597      }
     598    }
     599
     600    private void UpdateErtTables(List<AlgorithmInstance> algorithmInstances) {
    560601      ertTableView.Content = null;
    561       var columns = 1 + targets.Length + 1;
    562       var matrix = new string[groupedRuns.Count * groupedRuns.Max(x => x.Value.Count) + groupedRuns.Max(x => x.Value.Count), columns];
     602      var columns = targets.Length + 1;
     603      var totalRows = algorithmInstances.Count * algorithmInstances.Max(x => x.GetNumberOfProblemInstances()) + algorithmInstances.Max(x => x.GetNumberOfProblemInstances());
     604      var matrix = new StringMatrix(totalRows, columns);
     605      var rowNames = new List<string>();
     606      matrix.ColumnNames = targets.Select(x => targetsAreRelative ? (100 * x).ToString() + "%" : x.ToString())
     607        .Concat(new[] { "#succ" }).ToList();
    563608      var rowCount = 0;
    564609
    565610      var tableName = (string)dataTableComboBox.SelectedItem;
    566611      if (string.IsNullOrEmpty(tableName)) return;
    567 
    568       var targetsPerProblem = CalculateBestTargetPerProblemInstance(tableName);
    569 
    570       var colNames = new string[columns];
    571       colNames[0] = colNames[colNames.Length - 1] = string.Empty;
    572       for (var i = 0; i < targets.Length; i++) {
    573         colNames[i + 1] = targets[i].ToString("0.0%");
    574       }
    575       var problems = groupedRuns.SelectMany(x => x.Value.Keys).Distinct().ToList();
     612     
     613      var problems = algorithmInstances.SelectMany(x => x.GetProblemInstances()).Distinct().ToList();
    576614
    577615      foreach (var problem in problems) {
    578         matrix[rowCount, 0] = problem.ToString();
    579         for (var i = 0; i < targets.Length; i++) {
    580           matrix[rowCount, i + 1] = (targetsPerProblem[problem] * (problem.IsMaximization() ? (1 - targets[i]) : (1 + targets[i]))).ToString(CultureInfo.CurrentCulture.NumberFormat);
    581         }
    582         matrix[rowCount, columns - 1] = "#succ";
     616        var max = problem.IsMaximization();
     617        rowNames.Add(problem.ToString());
     618        var absTargets = GetAbsoluteTargetsWorstToBest(problem);
     619        if (targetsAreRelative) {
     620          // print out the absolute target values
     621          for (var i = 0; i < absTargets.Length; i++) {
     622            matrix[rowCount, i] = absTargets[i].ToString("##,0.0", CultureInfo.CurrentCulture.NumberFormat);
     623          }
     624        }
    583625        rowCount++;
    584626
    585         foreach (var group in groupedRuns) {
    586           matrix[rowCount, 0] = group.Key;
    587           if (!group.Value.ContainsKey(problem)) {
     627        foreach (var alg in algorithmInstances) {
     628          rowNames.Add(alg.Name);
     629          var runs = alg.GetRuns(problem).ToList();
     630          if (runs.Count == 0) {
    588631            matrix[rowCount, columns - 1] = "N/A";
    589632            rowCount++;
    590633            continue;
    591634          }
    592           var runs = group.Value[problem].Item2;
    593           ErtCalculationResult result = default(ErtCalculationResult);
    594           for (var i = 0; i < targets.Length; i++) {
    595             result = ExpectedRuntimeHelper.CalculateErt(runs, tableName, (problem.IsMaximization() ? (1 - targets[i]) : (1 + targets[i])) * group.Value[problem].Item1, problem.IsMaximization());
    596             matrix[rowCount, i + 1] = result.ToString();
     635          var result = default(ErtCalculationResult);
     636          for (var i = 0; i < absTargets.Length; i++) {
     637            result = ExpectedRuntimeHelper.CalculateErt(runs, tableName, absTargets[i], max);
     638            matrix[rowCount, i] = result.ToString();
    597639          }
    598640          matrix[rowCount, columns - 1] = targets.Length > 0 ? result.SuccessfulRuns + "/" + result.TotalRuns : "-";
     
    600642        }
    601643      }
    602       ertTableView.Content = new StringMatrix(matrix) { ColumnNames = colNames };
     644      matrix.RowNames = rowNames;
     645      ertTableView.Content = matrix;
    603646      ertTableView.DataGridView.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
    604647    }
     
    616659      if (budgets == null) GenerateDefaultBudgets(table);
    617660
    618       var groupedRuns = GroupRuns();
    619       if (groupedRuns.Count == 0) return;
     661      var algInstances = GroupRuns().ToList();
     662      if (algInstances.Count == 0) return;
    620663
    621664      var colorCount = 0;
    622665      var lineStyleCount = 0;
    623 
    624       var targetsPerProblem = CalculateBestTargetPerProblemInstance((string)dataTableComboBox.SelectedItem);
    625 
    626       foreach (var group in groupedRuns) {
     666     
     667      foreach (var alg in algInstances) {
    627668        var hits = new Dictionary<string, SortedList<double, double>>();
    628669
    629         foreach (var problem in group.Value) {
    630           foreach (var run in problem.Value.Item2) {
     670        foreach (var problem in alg.GetProblemInstances()) {
     671          foreach (var run in alg.GetRuns(problem)) {
    631672            var resultsTable = (IndexedDataTable<double>)run.Results[table];
    632673
    633             if (eachOrAllBudgetsCheckBox.Checked) {
    634               CalculateHitsForEachBudget(hits, resultsTable.Rows.First(), group.Value.Count, problem.Key, group.Key, problem.Value.Item2.Count, targetsPerProblem[problem.Key]);
    635             } else {
    636               CalculateHitsForAllBudgets(hits, resultsTable.Rows.First(), group.Value.Count, problem.Key, group.Key, problem.Value.Item2.Count, targetsPerProblem[problem.Key]);
    637             }
     674            CalculateHitsForEachBudget(hits, resultsTable.Rows.First(), problem, alg.Name);
    638675          }
    639676        }
     
    651688
    652689          var total = 0.0;
     690          var count = list.Value.Count;
    653691          foreach (var h in list.Value) {
    654692            total += h.Value;
    655             row.Values.Add(Tuple.Create(h.Key, total));
     693            row.Values.Add(Tuple.Create(h.Key, total / (double)count));
    656694          }
    657695
     
    667705
    668706    private void GenerateDefaultBudgets(string table) {
    669       var runs = GroupRuns().SelectMany(x => x.Value.Values).SelectMany(x => x.Item2).ToList();
     707      var runs = Content;
    670708      var min = runs.Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Select(y => y.Item1).Min()).Min();
    671709      var max = runs.Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Select(y => y.Item1).Max()).Max();
    672 
    673       var maxMagnitude = (int)Math.Ceiling(Math.Log10(max));
    674       var minMagnitude = (int)Math.Floor(Math.Log10(min));
    675       if (maxMagnitude - minMagnitude >= 3) {
    676         budgets = new double[maxMagnitude - minMagnitude];
    677         for (var i = minMagnitude; i < maxMagnitude; i++) {
    678           budgets[i - minMagnitude] = Math.Pow(10, i);
    679         }
    680       } else {
    681         var range = max - min;
    682         budgets = Enumerable.Range(0, 6).Select(x => min + (x / 5.0) * range).ToArray();
    683       }
     710      var points = 3;
     711      budgets = Enumerable.Range(1, points).Select(x => min + (x / (double)points) * (max - min)).ToArray();
    684712      suppressBudgetsEvents = true;
    685713      budgetsTextBox.Text = string.Join(" ; ", budgets);
     
    687715    }
    688716
    689     private void CalculateHitsForEachBudget(Dictionary<string, SortedList<double, double>> hits, IndexedDataRow<double> row, int groupCount, ProblemDescription problem, string groupName, int problemCount, double bestTarget) {
     717    private void CalculateHitsForEachBudget(Dictionary<string, SortedList<double, double>> hits, IndexedDataRow<double> row, ProblemInstance problem, string groupName) {
     718      var max = problem.IsMaximization();
     719      var prevIndex = 0;
    690720      foreach (var b in budgets) {
    691721        var key = groupName + "-" + b;
     722        var index = row.Values.BinarySearch(prevIndex, row.Values.Count - prevIndex, Tuple.Create(b, 0.0), new CostComparer());
     723        if (index < 0) {
     724          index = ~index;
     725          if (index >= row.Values.Count) break; // the run wasn't long enough to use up budget b (or any subsequent larger one)
     726        }
    692727        if (!hits.ContainsKey(key)) hits.Add(key, new SortedList<double, double>());
    693         Tuple<double, double> prev = null;
    694         foreach (var v in row.Values) {
    695           if (v.Item1 >= b) {
    696             // the budget may be too low to achieve any target
    697             if (prev == null && v.Item1 != b) break;
    698             var tgt = ((prev == null || v.Item1 == b) ? v.Item2 : prev.Item2);
    699             tgt = problem.IsMaximization() ? bestTarget / tgt : tgt / bestTarget;
    700             if (hits[key].ContainsKey(tgt))
    701               hits[key][tgt] += 1.0 / (groupCount * problemCount);
    702             else hits[key][tgt] = 1.0 / (groupCount * problemCount);
    703             break;
    704           }
    705           prev = v;
    706         }
    707         if (hits[key].Count == 0) hits.Remove(key);
    708       }
    709     }
    710 
    711     private void CalculateHitsForAllBudgets(Dictionary<string, SortedList<double, double>> hits, IndexedDataRow<double> row, int groupCount, ProblemDescription problem, string groupName, int problemCount, double bestTarget) {
    712       var values = row.Values;
    713       if (!hits.ContainsKey(groupName)) hits.Add(groupName, new SortedList<double, double>());
    714 
    715       var i = 0;
    716       var j = 0;
    717       Tuple<double, double> prev = null;
    718       while (i < budgets.Length && j < values.Count) {
    719         var current = values[j];
    720         if (current.Item1 >= budgets[i]) {
    721           if (prev != null || current.Item1 == budgets[i]) {
    722             var tgt = (prev == null || current.Item1 == budgets[i]) ? current.Item2 : prev.Item2;
    723             tgt = problem.IsMaximization() ? bestTarget / tgt : tgt / bestTarget;
    724             if (!hits[groupName].ContainsKey(tgt)) hits[groupName][tgt] = 0;
    725             hits[groupName][tgt] += 1.0 / (groupCount * problemCount * budgets.Length);
    726           }
    727           i++;
    728         } else {
    729           j++;
    730           prev = current;
    731         }
    732       }
    733       var lastTgt = values.Last().Item2;
    734       lastTgt = problem.IsMaximization() ? bestTarget / lastTgt : lastTgt / bestTarget;
    735       if (i < budgets.Length && !hits[groupName].ContainsKey(lastTgt)) hits[groupName][lastTgt] = 0;
    736       while (i < budgets.Length) {
    737         hits[groupName][lastTgt] += 1.0 / (groupCount * problemCount * budgets.Length);
    738         i++;
     728        var v = row.Values[index];
     729        var relTgt = CalculateRelativeDifference(max, problem.BestKnownQuality, v.Item2) + 1;
     730        if (hits[key].ContainsKey(relTgt))
     731          hits[key][relTgt]++;
     732        else hits[key][relTgt] = 1.0;
     733        prevIndex = index;
    739734      }
    740735    }
     
    743738    private void UpdateCaption() {
    744739      Caption = Content != null ? Content.OptimizerName + " RLD View" : ViewAttribute.GetViewName(GetType());
     740    }
     741
     742    private void SynchronizeTargetTextBox() {
     743      if (InvokeRequired) Invoke((Action)SynchronizeTargetTextBox);
     744      else {
     745        suppressTargetsEvents = true;
     746        try {
     747          if (targetsAreRelative)
     748            targetsTextBox.Text = string.Join("% ; ", targets.Select(x => x * 100)) + "%";
     749          else targetsTextBox.Text = string.Join(" ; ", targets);
     750        } finally { suppressTargetsEvents = false; }
     751      }
    745752    }
    746753
     
    756763      if (dataTableComboBox.SelectedIndex >= 0)
    757764        GenerateDefaultBudgets((string)dataTableComboBox.SelectedItem);
     765      UpdateBestKnownQualities();
    758766      UpdateRuns();
    759767      SetEnabledStateOfControls();
     
    782790          return;
    783791        }
    784         targetList.Add(t / 100);
     792        if (targetsAreRelative)
     793          targetList.Add(t / 100);
     794        else targetList.Add(t);
    785795      }
    786796      if (targetList.Count == 0) {
     
    791801      e.Cancel = false;
    792802      errorProvider.SetError(targetsTextBox, null);
    793       targets = targetList.Select(x => (double)x).OrderByDescending(x => x).ToArray();
    794       suppressTargetsEvents = true;
    795       try { targetsTextBox.Text = string.Join("% ; ", targets.Select(x => x * 100)) + "%"; } finally { suppressTargetsEvents = false; }
    796 
     803      targets = targetsAreRelative ? targetList.Select(x => (double)x).OrderByDescending(x => x).ToArray() : targetList.Select(x => (double)x).ToArray();
     804
     805      SynchronizeTargetTextBox();
    797806      UpdateResultsByTarget();
    798807      SetEnabledStateOfControls();
     
    806815    }
    807816
     817    private void relativeOrAbsoluteComboBox_SelectedIndexChanged(object sender, EventArgs e) {
     818      if (suppressUpdates) return;
     819      var pd = (ProblemInstance)problemComboBox.SelectedItem;
     820      if (!double.IsNaN(pd.BestKnownQuality)) {
     821        var max = pd.IsMaximization();
     822        if (targetsAreRelative) targets = GetAbsoluteTargets(pd).ToArray();
     823        else {
     824          // Rounding to 5 digits since it's certainly appropriate for this application
     825          if (pd.BestKnownQuality > 0) {
     826            targets = targets.Select(x => Math.Round(max ? 1.0 - (x / pd.BestKnownQuality) : (x / pd.BestKnownQuality) - 1.0, 5)).ToArray();
     827          } else if (pd.BestKnownQuality < 0) {
     828            targets = targets.Select(x => Math.Round(!max ? 1.0 - (x / pd.BestKnownQuality) : (x / pd.BestKnownQuality) - 1.0, 5)).ToArray();
     829          }
     830        }
     831      }
     832      targetsAreRelative = (string)relativeOrAbsoluteComboBox.SelectedItem == "relative";
     833      SynchronizeTargetTextBox();
     834
     835      try {
     836        SuspendRepaint();
     837        UpdateResultsByTarget();
     838      } finally { ResumeRepaint(true); }
     839    }
     840
    808841    private void generateTargetsButton_Click(object sender, EventArgs e) {
    809       decimal max = 1, min = 0, count = 10;
    810       if (targets != null) {
    811         max = (decimal)targets.Max();
    812         min = (decimal)targets.Min();
    813         count = targets.Length;
    814       } else if (Content.Count > 0 && dataTableComboBox.SelectedIndex >= 0) {
    815         var table = (string)dataTableComboBox.SelectedItem;
    816         max = (decimal)Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Max(y => y.Item2)).Max();
    817         min = (decimal)Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Min(y => y.Item2)).Min();
    818         count = 6;
     842      if (targets == null) return;
     843      decimal max = 10, min = 0, count = 10;
     844      max = (decimal)targets.Max();
     845      min = (decimal)targets.Min();
     846      count = targets.Length - 1;
     847      if (targetsAreRelative) {
     848        max *= 100;
     849        min *= 100;
    819850      }
    820851      using (var dialog = new DefineArithmeticProgressionDialog(false, min, max, (max - min) / count)) {
    821852        if (dialog.ShowDialog() == DialogResult.OK) {
    822853          if (dialog.Values.Any()) {
    823             targets = dialog.Values.Select(x => (double)x).ToArray();
    824             suppressTargetsEvents = true;
    825             targetsTextBox.Text = string.Join("% ; ", targets);
    826             suppressTargetsEvents = false;
    827 
     854            targets = targetsAreRelative
     855              ? dialog.Values.OrderByDescending(x => x).Select(x => (double)x / 100.0).ToArray()
     856              : dialog.Values.Select(x => (double)x).ToArray();
     857
     858            SynchronizeTargetTextBox();
    828859            UpdateResultsByTarget();
    829860            SetEnabledStateOfControls();
     
    835866    private void addTargetsAsResultButton_Click(object sender, EventArgs e) {
    836867      var table = (string)dataTableComboBox.SelectedItem;
    837 
    838       var targetsPerProblem = CalculateBestTargetPerProblemInstance(table);
    839 
     868      if (string.IsNullOrEmpty(table)) return;
     869     
    840870      foreach (var run in Content) {
    841871        if (!run.Results.ContainsKey(table)) continue;
    842872        var resultsTable = (IndexedDataTable<double>)run.Results[table];
    843873        var values = resultsTable.Rows.First().Values;
    844         var i = 0;
    845         var j = 0;
    846         var pd = new ProblemDescription(run);
    847         while (i < targets.Length && j < values.Count) {
    848           var target = (pd.IsMaximization() ? (1 - targets[i]) : (1 + targets[i])) * targetsPerProblem[pd];
    849           var current = values[j];
    850           if (pd.IsMaximization() && current.Item2 >= target
    851               || !pd.IsMaximization() && current.Item2 <= target) {
    852             run.Results[table + ".Target" + target] = new DoubleValue(current.Item1);
    853             i++;
    854           } else {
    855             j++;
    856           }
    857         }
    858       }
     874        var pd = new ProblemInstance(run);
     875        pd = problems.Single(x => x.Equals(pd));
     876        var max = pd.IsMaximization();
     877        var absTargets = GetAbsoluteTargetsWorstToBest(pd);
     878
     879        var prevIndex = 0;
     880        for (var i = 0; i < absTargets.Length; i++) {
     881          var absTarget = absTargets[i];
     882          var index = values.BinarySearch(prevIndex, values.Count - prevIndex, Tuple.Create(0.0, absTarget), new TargetComparer(max));
     883          if (index < 0) {
     884            index = ~index;
     885            if (index >= values.Count) break; // the target (and subsequent ones) wasn't achieved
     886          }
     887          var target = targetsAreRelative ? (targets[i] * 100) : absTarget;
     888          run.Results[table + (targetsAreRelative ? ".RelTarget " : ".AbsTarget ") + target + (targetsAreRelative ? "%" : string.Empty)] = new DoubleValue(values[index].Item1);
     889          prevIndex = index;
     890        }
     891      }
     892    }
     893
     894    private void markerCheckBox_CheckedChanged(object sender, EventArgs e) {
     895      SuspendRepaint();
     896      try {
     897        UpdateResultsByTarget();
     898      } finally { ResumeRepaint(true); }
     899    }
     900
     901    private void showLabelsCheckBox_CheckedChanged(object sender, EventArgs e) {
     902      showLabelsInTargetChart = showLabelsCheckBox.Checked;
     903      SuspendRepaint();
     904      try {
     905        UpdateResultsByTarget();
     906      } finally { ResumeRepaint(true); }
    859907    }
    860908    #endregion
     
    869917        double b;
    870918        if (!double.TryParse(ts, out b)) {
    871           errorProvider.SetError(budgetsTextBox, "Not all targets can be parsed: " + ts);
     919          errorProvider.SetError(budgetsTextBox, "Not all budgets can be parsed: " + ts);
    872920          e.Cancel = true;
    873921          return;
     
    876924      }
    877925      if (budgetList.Count == 0) {
    878         errorProvider.SetError(budgetsTextBox, "Give at least one target value!");
     926        errorProvider.SetError(budgetsTextBox, "Give at least one budget value!");
    879927        e.Cancel = true;
    880928        return;
     
    882930      e.Cancel = false;
    883931      errorProvider.SetError(budgetsTextBox, null);
    884       budgets = budgetList.ToArray();
     932      budgets = budgetList.OrderBy(x => x).ToArray();
     933      try {
     934        suppressBudgetsEvents = true;
     935        budgetsTextBox.Text = string.Join(" ; ", budgets);
     936      } finally { suppressBudgetsEvents = false; }
    885937      UpdateResultsByCost();
    886938      SetEnabledStateOfControls();
    887     }
    888 
    889     private void eachOrAllBudgetsCheckBox_CheckedChanged(object sender, EventArgs e) {
    890       var each = eachOrAllBudgetsCheckBox.Checked;
    891       eachOrAllBudgetsCheckBox.Text = each ? "each" : "all";
    892       SuspendRepaint();
    893       try {
    894         UpdateResultsByCost();
    895       } finally { ResumeRepaint(true); }
    896939    }
    897940
     
    906949        min = (decimal)Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Min(y => y.Item1)).Min();
    907950        max = (decimal)Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Max(y => y.Item1)).Max();
    908         count = 6;
     951        count = 3;
    909952      }
    910953      using (var dialog = new DefineArithmeticProgressionDialog(false, min, max, (max - min) / count)) {
     
    913956            budgets = dialog.Values.OrderBy(x => x).Select(x => (double)x).ToArray();
    914957
    915             suppressBudgetsEvents = true;
    916             budgetsTextBox.Text = string.Join(" ; ", budgets);
    917             suppressBudgetsEvents = false;
     958            try {
     959              suppressBudgetsEvents = true;
     960              budgetsTextBox.Text = string.Join(" ; ", budgets);
     961            } finally { suppressBudgetsEvents = false; }
    918962
    919963            UpdateResultsByCost();
     
    926970    private void addBudgetsAsResultButton_Click(object sender, EventArgs e) {
    927971      var table = (string)dataTableComboBox.SelectedItem;
    928       var budgetStrings = budgetsTextBox.Text.Split(new[] { ';', '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries);
    929       if (budgetStrings.Length == 0) {
    930         MessageBox.Show("Define a number of budgets.");
    931         return;
    932       }
    933       var budgetList = new List<double>();
    934       foreach (var bs in budgetStrings) {
    935         double v;
    936         if (!double.TryParse(bs, out v)) {
    937           MessageBox.Show("Budgets must be a valid number: " + bs);
    938           return;
    939         }
    940         budgetList.Add(v);
    941       }
    942       budgetList.Sort();
    943972
    944973      foreach (var run in Content) {
     
    946975        var resultsTable = (IndexedDataTable<double>)run.Results[table];
    947976        var values = resultsTable.Rows.First().Values;
    948         var i = 0;
    949         var j = 0;
    950         Tuple<double, double> prev = null;
    951         while (i < budgetList.Count && j < values.Count) {
    952           var current = values[j];
    953           if (current.Item1 >= budgetList[i]) {
    954             if (prev != null || current.Item1 == budgetList[i]) {
    955               var tgt = (prev == null || current.Item1 == budgetList[i]) ? current.Item2 : prev.Item2;
    956               run.Results[table + ".Cost" + budgetList[i]] = new DoubleValue(tgt);
    957             }
    958             i++;
    959           } else {
    960             j++;
    961             prev = current;
    962           }
     977        var pd = new ProblemInstance(run);
     978        pd = problems.Single(x => x.Equals(pd));
     979
     980        var prevIndex = 0;
     981        foreach (var b in budgets) {
     982          var index = values.BinarySearch(prevIndex, values.Count - prevIndex, Tuple.Create(b, 0.0), new CostComparer());
     983          if (index < 0) {
     984            index = ~index;
     985            if (index >= values.Count) break; // the run wasn't long enough to use up budget b (or any subsequent larger one)
     986          }
     987          var v = values[index];
     988          var tgt = targetsAreRelative ? CalculateRelativeDifference(pd.IsMaximization(), pd.BestKnownQuality, v.Item2) : v.Item2;
     989          run.Results[table + (targetsAreRelative ? ".CostForRelTarget " : ".CostForAbsTarget ") + b] = new DoubleValue(tgt);
     990          prevIndex = index;
    963991        }
    964992      }
     
    967995
    968996    #region Helpers
    969     private Dictionary<ProblemDescription, double> CalculateBestTargetPerProblemInstance(string table) {
     997    private double CalculateRelativeDifference(bool maximization, double bestKnown, double fit) {
     998      if (bestKnown == 0) {
     999        // no relative difference with respect to bestKnown possible
     1000        return maximization ? -fit : fit;
     1001      }
     1002      var absDiff = (fit - bestKnown);
     1003      var relDiff = absDiff / bestKnown;
     1004      if (maximization) {
     1005        return bestKnown > 0 ? -relDiff : relDiff;
     1006      } else {
     1007        return bestKnown > 0 ? relDiff : -relDiff;
     1008      }
     1009    }
     1010
     1011    private Dictionary<ProblemInstance, double> CalculateBestTargetPerProblemInstance(string table) {
     1012      if (table == null) table = string.Empty;
    9701013      return (from r in Content
    9711014              where r.Visible
    972               let pd = new ProblemDescription(r)
     1015              let pd = new ProblemInstance(r)
    9731016              let target = r.Parameters.ContainsKey("BestKnownQuality")
    9741017                           && r.Parameters["BestKnownQuality"] is DoubleValue
    9751018                ? ((DoubleValue)r.Parameters["BestKnownQuality"]).Value
    976                 : ((IndexedDataTable<double>)r.Results[table]).Rows.First().Values.Last().Item2
     1019                : (r.Results.ContainsKey(table) && r.Results[table] is IndexedDataTable<double>
     1020                  ? ((IndexedDataTable<double>)r.Results[table]).Rows.First().Values.Last().Item2
     1021                  : double.NaN)
    9771022              group target by pd into g
    978               select new { Problem = g.Key, Target = g.Key.IsMaximization() ? g.Max() : g.Min() })
     1023              select new { Problem = g.Key, Target = g.Any(x => !double.IsNaN(x)) ? (g.Key.IsMaximization() ? g.Max() : g.Where(x => !double.IsNaN(x)).Min()) : double.NaN })
    9791024        .ToDictionary(x => x.Problem, x => x.Target);
    9801025    }
     
    9911036      } finally { ResumeRepaint(true); }
    9921037    }
     1038
     1039    private void UpdateBestKnownQualities() {
     1040      var table = (string)dataTableComboBox.SelectedItem;
     1041      if (string.IsNullOrEmpty(table)) return;
     1042
     1043      var targetsPerProblem = CalculateBestTargetPerProblemInstance(table);
     1044      foreach (var pd in problems) {
     1045        double bkq;
     1046        if (targetsPerProblem.TryGetValue(pd, out bkq))
     1047          pd.BestKnownQuality = bkq;
     1048        else pd.BestKnownQuality = double.NaN;
     1049      }
     1050    }
    9931051    #endregion
    9941052
    9951053    private void ConfigureSeries(Series series) {
    996       series.SmartLabelStyle.Enabled = true;
     1054      series.SmartLabelStyle.Enabled = showLabelsInTargetChart;
    9971055      series.SmartLabelStyle.AllowOutsidePlotArea = LabelOutsidePlotAreaStyle.No;
    9981056      series.SmartLabelStyle.CalloutLineAnchorCapStyle = LineAnchorCapStyle.None;
     
    10781136    }
    10791137
    1080     private class ProblemDescription {
     1138    private class AlgorithmInstance : INotifyPropertyChanged {
     1139      private string name;
     1140      public string Name {
     1141        get { return name; }
     1142        set {
     1143          if (name == value) return;
     1144          name = value;
     1145          OnPropertyChanged("Name");
     1146        }
     1147      }
     1148
     1149      private Dictionary<ProblemInstance, List<IRun>> performanceData;
     1150
     1151      public int GetNumberOfProblemInstances() {
     1152        return performanceData.Count;
     1153      }
     1154
     1155      public IEnumerable<ProblemInstance> GetProblemInstances() {
     1156        return performanceData.Keys;
     1157      }
     1158
     1159      public int GetNumberOfRuns(ProblemInstance p) {
     1160        if (p == ProblemInstance.MatchAll) return performanceData.Select(x => x.Value.Count).Sum();
     1161        List<IRun> runs;
     1162        if (performanceData.TryGetValue(p, out runs))
     1163          return runs.Count;
     1164
     1165        return 0;
     1166      }
     1167
     1168      public IEnumerable<IRun> GetRuns(ProblemInstance p) {
     1169        if (p == ProblemInstance.MatchAll) return performanceData.SelectMany(x => x.Value);
     1170        List<IRun> runs;
     1171        if (performanceData.TryGetValue(p, out runs))
     1172          return runs;
     1173
     1174        return Enumerable.Empty<IRun>();
     1175      }
     1176
     1177      public AlgorithmInstance(string name, IEnumerable<IRun> runs, IEnumerable<ProblemInstance> problems) {
     1178        this.name = name;
     1179
     1180        var pDict = problems.ToDictionary(r => r, _ => new List<IRun>());
     1181        foreach (var y in runs) {
     1182          var pd = new ProblemInstance(y);
     1183          List<IRun> l;
     1184          if (pDict.TryGetValue(pd, out l)) l.Add(y);
     1185        }
     1186        performanceData = pDict.Where(x => x.Value.Count > 0).ToDictionary(x => x.Key, x => x.Value);
     1187      }
     1188
     1189      public override bool Equals(object obj) {
     1190        var other = obj as AlgorithmInstance;
     1191        if (other == null) return false;
     1192        return name == other.name;
     1193      }
     1194
     1195      public override int GetHashCode() {
     1196        return name.GetHashCode();
     1197      }
     1198
     1199      public event PropertyChangedEventHandler PropertyChanged;
     1200      protected virtual void OnPropertyChanged(string propertyName = null) {
     1201        var handler = PropertyChanged;
     1202        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
     1203      }
     1204    }
     1205
     1206    private class ProblemInstance : INotifyPropertyChanged {
    10811207      private readonly bool matchAll;
    1082       public static readonly ProblemDescription MatchAll = new ProblemDescription() {
     1208      public static readonly ProblemInstance MatchAll = new ProblemInstance() {
    10831209        ProblemName = "All with Best-Known"
    10841210      };
    10851211
    1086       private ProblemDescription() {
     1212      private ProblemInstance() {
    10871213        ProblemType = string.Empty;
    10881214        ProblemName = string.Empty;
     
    10941220        DisplayMaximization = false;
    10951221        matchAll = true;
    1096       }
    1097 
    1098       public ProblemDescription(IRun run) {
     1222        BestKnownQuality = double.NaN;
     1223      }
     1224
     1225      public ProblemInstance(IRun run) {
    10991226        ProblemType = GetStringValueOrEmpty(run, "Problem Type");
    11001227        ProblemName = GetStringValueOrEmpty(run, "Problem Name");
     
    11061233        DisplayMaximization = !string.IsNullOrEmpty(Maximization);
    11071234        matchAll = false;
    1108       }
    1109 
    1110       public bool DisplayProblemType { get; set; }
    1111       public string ProblemType { get; set; }
    1112       public bool DisplayProblemName { get; set; }
    1113       public string ProblemName { get; set; }
    1114       public bool DisplayEvaluator { get; set; }
    1115       public string Evaluator { get; set; }
    1116       public bool DisplayMaximization { get; set; }
    1117       public string Maximization { get; set; }
     1235        BestKnownQuality = GetDoubleValueOrNaN(run, "BestKnownQuality");
     1236      }
     1237
     1238      private bool displayProblemType;
     1239      public bool DisplayProblemType {
     1240        get { return displayProblemType; }
     1241        set {
     1242          if (displayProblemType == value) return;
     1243          displayProblemType = value;
     1244          OnPropertyChanged("DisplayProblemType");
     1245        }
     1246      }
     1247      private string problemType;
     1248      public string ProblemType {
     1249        get { return problemType; }
     1250        set {
     1251          if (problemType == value) return;
     1252          problemType = value;
     1253          OnPropertyChanged("ProblemType");
     1254        }
     1255      }
     1256      private bool displayProblemName;
     1257      public bool DisplayProblemName {
     1258        get { return displayProblemName; }
     1259        set {
     1260          if (displayProblemName == value) return;
     1261          displayProblemName = value;
     1262          OnPropertyChanged("DisplayProblemName");
     1263        }
     1264      }
     1265      private string problemName;
     1266      public string ProblemName {
     1267        get { return problemName; }
     1268        set {
     1269          if (problemName == value) return;
     1270          problemName = value;
     1271          OnPropertyChanged("ProblemName");
     1272        }
     1273      }
     1274      private bool displayEvaluator;
     1275      public bool DisplayEvaluator {
     1276        get { return displayEvaluator; }
     1277        set {
     1278          if (displayEvaluator == value) return;
     1279          displayEvaluator = value;
     1280          OnPropertyChanged("DisplayEvaluator");
     1281        }
     1282      }
     1283      private string evaluator;
     1284      public string Evaluator {
     1285        get { return evaluator; }
     1286        set {
     1287          if (evaluator == value) return;
     1288          evaluator = value;
     1289          OnPropertyChanged("Evaluator");
     1290        }
     1291      }
     1292      private bool displayMaximization;
     1293      public bool DisplayMaximization {
     1294        get { return displayMaximization; }
     1295        set {
     1296          if (displayMaximization == value) return;
     1297          displayMaximization = value;
     1298          OnPropertyChanged("DisplayMaximization");
     1299        }
     1300      }
     1301      private string maximization;
     1302      public string Maximization {
     1303        get { return maximization; }
     1304        set {
     1305          if (maximization == value) return;
     1306          maximization = value;
     1307          OnPropertyChanged("Maximization");
     1308        }
     1309      }
     1310      private double bestKnownQuality;
     1311      public double BestKnownQuality {
     1312        get { return bestKnownQuality; }
     1313        set {
     1314          if (bestKnownQuality == value) return;
     1315          bestKnownQuality = value;
     1316          OnPropertyChanged("BestKnownQuality");
     1317        }
     1318      }
    11181319
    11191320      public bool IsMaximization() {
     
    11291330      }
    11301331
     1332      private double GetDoubleValueOrNaN(IRun run, string key) {
     1333        IItem param;
     1334        if (run.Parameters.TryGetValue(key, out param)) {
     1335          var dv = param as DoubleValue;
     1336          return dv != null ? dv.Value : double.NaN;
     1337        }
     1338        return double.NaN;
     1339      }
     1340
    11311341      private string GetStringValueOrEmpty(IRun run, string key) {
    1132         return run.Parameters.ContainsKey(key) ? ((StringValue)run.Parameters[key]).Value : string.Empty;
     1342        IItem param;
     1343        if (run.Parameters.TryGetValue(key, out param)) {
     1344          var sv = param as StringValue;
     1345          return sv != null ? sv.Value : string.Empty;
     1346        }
     1347        return string.Empty;
    11331348      }
    11341349
    11351350      private string GetMaximizationValueOrEmpty(IRun run, string key) {
    1136         return run.Parameters.ContainsKey(key) ? (((BoolValue)run.Parameters[key]).Value ? "MAX" : "MIN") : string.Empty;
     1351        IItem param;
     1352        if (run.Parameters.TryGetValue(key, out param)) {
     1353          var bv = param as BoolValue;
     1354          return bv != null ? (bv.Value ? "MAX" : "MIN") : string.Empty;
     1355        }
     1356        return string.Empty;
    11371357      }
    11381358
    11391359      public override bool Equals(object obj) {
    1140         var other = obj as ProblemDescription;
     1360        var other = obj as ProblemInstance;
    11411361        if (other == null) return false;
    11421362        return ProblemType == other.ProblemType
     
    11551375          (DisplayProblemName ? ProblemName : string.Empty),
    11561376          (DisplayEvaluator ? Evaluator : string.Empty),
    1157           (DisplayMaximization ? Maximization : string.Empty)}.Where(x => !string.IsNullOrEmpty(x)));
     1377          (DisplayMaximization ? Maximization : string.Empty),
     1378          !double.IsNaN(BestKnownQuality) ? BestKnownQuality.ToString(CultureInfo.CurrentCulture.NumberFormat) : string.Empty }.Where(x => !string.IsNullOrEmpty(x)));
     1379      }
     1380
     1381      public event PropertyChangedEventHandler PropertyChanged;
     1382      protected virtual void OnPropertyChanged(string propertyName = null) {
     1383        var handler = PropertyChanged;
     1384        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
     1385      }
     1386    }
     1387
     1388    private class CostComparer : Comparer<Tuple<double, double>> {
     1389      public override int Compare(Tuple<double, double> x, Tuple<double, double> y) {
     1390        return x.Item1.CompareTo(y.Item1);
     1391      }
     1392    }
     1393
     1394    private class TargetComparer : Comparer<Tuple<double, double>> {
     1395      public bool Maximization { get; private set; }
     1396      public TargetComparer(bool maximization) {
     1397        Maximization = maximization;
     1398      }
     1399
     1400      public override int Compare(Tuple<double, double> x, Tuple<double, double> y) {
     1401        return Maximization ? x.Item2.CompareTo(y.Item2) : y.Item2.CompareTo(x.Item2);
    11581402      }
    11591403    }
  • stable/HeuristicLab.Visualization.ChartControlsExtensions/3.3/GanttChart.Designer.cs

    r14186 r15220  
    4545    /// </summary>
    4646    private void InitializeComponent() {
     47      this.components = new System.ComponentModel.Container();
    4748      System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
    4849      System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
    4950      System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();
     51      System.Windows.Forms.DataVisualization.Charting.Title title1 = new System.Windows.Forms.DataVisualization.Charting.Title();
    5052      this.chart = new HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart();
    5153      ((System.ComponentModel.ISupportInitialize)(this.chart)).BeginInit();
     
    5456      // chart
    5557      //
    56       this.chart.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
    57                   | System.Windows.Forms.AnchorStyles.Left)
    58                   | System.Windows.Forms.AnchorStyles.Right)));
     58      this.chart.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
     59            | System.Windows.Forms.AnchorStyles.Left)
     60            | System.Windows.Forms.AnchorStyles.Right)));
    5961      chartArea1.AxisX.ScaleView.SmallScrollMinSizeType = System.Windows.Forms.DataVisualization.Charting.DateTimeIntervalType.Milliseconds;
    6062      chartArea1.AxisY.ScaleView.SmallScrollMinSizeType = System.Windows.Forms.DataVisualization.Charting.DateTimeIntervalType.Milliseconds;
     
    7981      this.chart.TabIndex = 0;
    8082      this.chart.Text = "chart";
     83      title1.Font = new System.Drawing.Font("Microsoft Sans Serif", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
     84      title1.Name = "Gantt Title";
     85      title1.Text = "Gantt Title";
     86      title1.Visible = false;
     87      this.chart.Titles.Add(title1);
    8188      //
    8289      // GanttChart
    8390      //
    84       this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
    8591      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
    8692      this.Controls.Add(this.chart);
  • stable/HeuristicLab.Visualization.ChartControlsExtensions/3.3/GanttChart.cs

    r14186 r15220  
    3232    private IDictionary<string, Color> categories = new Dictionary<string, Color>();
    3333    private IDictionary<string, int> rowNames = new Dictionary<string, int>();
     34
     35    public string Title {
     36      get { return chart.Titles[0].Text; }
     37      set {
     38        chart.Titles[0].Text = value ?? string.Empty;
     39        chart.Titles[0].Visible = value != null;
     40      }
     41    }
    3442
    3543    public GanttChart() {
Note: See TracChangeset for help on using the changeset viewer.