Index: /branches/1614_GeneralizedQAP/HeuristicLab.Optimization.Views/3.3/HeuristicLab.Optimization.Views-3.3.csproj
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Optimization.Views/3.3/HeuristicLab.Optimization.Views-3.3.csproj	(revision 16732)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Optimization.Views/3.3/HeuristicLab.Optimization.Views-3.3.csproj	(revision 16733)
@@ -269,4 +269,10 @@
       <DependentUpon>RunCollectionEqualityConstraintView.cs</DependentUpon>
     </Compile>
+    <Compile Include="RunCollectionViews\RunCollectionSimpleRLDView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="RunCollectionViews\RunCollectionSimpleRLDView.Designer.cs">
+      <DependentUpon>RunCollectionSimpleRLDView.cs</DependentUpon>
+    </Compile>
     <Compile Include="RunCollectionViews\RunCollectionRLDView.cs">
       <SubType>UserControl</SubType>
@@ -444,4 +450,7 @@
     <EmbeddedResource Include="CreateNewSingleEncodingDialog.resx">
       <DependentUpon>CreateNewSingleEncodingDialog.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="RunCollectionViews\RunCollectionSimpleRLDView.resx">
+      <DependentUpon>RunCollectionSimpleRLDView.cs</DependentUpon>
     </EmbeddedResource>
   </ItemGroup>
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionSimpleRLDView.Designer.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionSimpleRLDView.Designer.cs	(revision 16733)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionSimpleRLDView.Designer.cs	(revision 16733)
@@ -0,0 +1,390 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+namespace HeuristicLab.Optimization.Views {
+  partial class RunCollectionSimpleRLDView {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      this.components = new System.ComponentModel.Container();
+      System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea2 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
+      System.Windows.Forms.DataVisualization.Charting.Legend legend2 = new System.Windows.Forms.DataVisualization.Charting.Legend();
+      this.dataTableComboBox = new System.Windows.Forms.ComboBox();
+      this.dataTableLabel = new System.Windows.Forms.Label();
+      this.groupLabel = new System.Windows.Forms.Label();
+      this.groupComboBox = new System.Windows.Forms.ComboBox();
+      this.targetLogScalingCheckBox = new System.Windows.Forms.CheckBox();
+      this.targetsTextBox = new System.Windows.Forms.TextBox();
+      this.targetsLabel = new System.Windows.Forms.Label();
+      this.errorProvider = new System.Windows.Forms.ErrorProvider(this.components);
+      this.addTargetsAsResultButton = new System.Windows.Forms.Button();
+      this.generateTargetsButton = new System.Windows.Forms.Button();
+      this.toolTip = new System.Windows.Forms.ToolTip(this.components);
+      this.aggregateTargetsCheckBox = new System.Windows.Forms.CheckBox();
+      this.tabControl = new System.Windows.Forms.TabControl();
+      this.byTargetTabPage = new System.Windows.Forms.TabPage();
+      this.relativeOrAbsoluteComboBox = new System.Windows.Forms.ComboBox();
+      this.targetChart = new HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart();
+      this.showLabelsCheckBox = new System.Windows.Forms.CheckBox();
+      this.markerCheckBox = new System.Windows.Forms.CheckBox();
+      this.byTableTabPage = new System.Windows.Forms.TabPage();
+      this.problemComboBox = new System.Windows.Forms.ComboBox();
+      this.problemLabel = new System.Windows.Forms.Label();
+      this.ertTextBox = new System.Windows.Forms.TextBox();
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
+      this.tabControl.SuspendLayout();
+      this.byTargetTabPage.SuspendLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.targetChart)).BeginInit();
+      this.byTableTabPage.SuspendLayout();
+      this.SuspendLayout();
+      // 
+      // dataTableComboBox
+      // 
+      this.dataTableComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.dataTableComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+      this.dataTableComboBox.FormattingEnabled = true;
+      this.dataTableComboBox.Location = new System.Drawing.Point(69, 57);
+      this.dataTableComboBox.Name = "dataTableComboBox";
+      this.dataTableComboBox.Size = new System.Drawing.Size(582, 21);
+      this.dataTableComboBox.TabIndex = 5;
+      this.dataTableComboBox.SelectedIndexChanged += new System.EventHandler(this.dataTableComboBox_SelectedIndexChanged);
+      // 
+      // dataTableLabel
+      // 
+      this.dataTableLabel.AutoSize = true;
+      this.dataTableLabel.Location = new System.Drawing.Point(3, 60);
+      this.dataTableLabel.Name = "dataTableLabel";
+      this.dataTableLabel.Size = new System.Drawing.Size(60, 13);
+      this.dataTableLabel.TabIndex = 4;
+      this.dataTableLabel.Text = "DataTable:";
+      // 
+      // groupLabel
+      // 
+      this.groupLabel.AutoSize = true;
+      this.groupLabel.Location = new System.Drawing.Point(3, 6);
+      this.groupLabel.Name = "groupLabel";
+      this.groupLabel.Size = new System.Drawing.Size(39, 13);
+      this.groupLabel.TabIndex = 0;
+      this.groupLabel.Text = "Group:";
+      // 
+      // groupComboBox
+      // 
+      this.groupComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.groupComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+      this.groupComboBox.FormattingEnabled = true;
+      this.groupComboBox.Location = new System.Drawing.Point(69, 3);
+      this.groupComboBox.Name = "groupComboBox";
+      this.groupComboBox.Size = new System.Drawing.Size(582, 21);
+      this.groupComboBox.TabIndex = 1;
+      this.groupComboBox.SelectedIndexChanged += new System.EventHandler(this.groupComboBox_SelectedIndexChanged);
+      // 
+      // targetLogScalingCheckBox
+      // 
+      this.targetLogScalingCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+      this.targetLogScalingCheckBox.AutoSize = true;
+      this.targetLogScalingCheckBox.Location = new System.Drawing.Point(9, 364);
+      this.targetLogScalingCheckBox.Name = "targetLogScalingCheckBox";
+      this.targetLogScalingCheckBox.Size = new System.Drawing.Size(112, 17);
+      this.targetLogScalingCheckBox.TabIndex = 6;
+      this.targetLogScalingCheckBox.Text = "logarithmic scaling";
+      this.targetLogScalingCheckBox.UseVisualStyleBackColor = true;
+      this.targetLogScalingCheckBox.CheckedChanged += new System.EventHandler(this.logScalingCheckBox_CheckedChanged);
+      // 
+      // targetsTextBox
+      // 
+      this.targetsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.targetsTextBox.Location = new System.Drawing.Point(59, 8);
+      this.targetsTextBox.Name = "targetsTextBox";
+      this.targetsTextBox.Size = new System.Drawing.Size(204, 20);
+      this.targetsTextBox.TabIndex = 1;
+      this.toolTip.SetToolTip(this.targetsTextBox, "The order of the targets is important, first to-hit targets\r\nshould be given firs" +
+        "t. The sequence should be monotonous.\r\n\r\nTargets should be separated by semicolo" +
+        "n, tab or space.");
+      this.targetsTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.targetsTextBox_Validating);
+      // 
+      // targetsLabel
+      // 
+      this.targetsLabel.AutoSize = true;
+      this.targetsLabel.Location = new System.Drawing.Point(6, 11);
+      this.targetsLabel.Name = "targetsLabel";
+      this.targetsLabel.Size = new System.Drawing.Size(46, 13);
+      this.targetsLabel.TabIndex = 0;
+      this.targetsLabel.Text = "Targets:";
+      // 
+      // errorProvider
+      // 
+      this.errorProvider.ContainerControl = this;
+      // 
+      // addTargetsAsResultButton
+      // 
+      this.addTargetsAsResultButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+      this.addTargetsAsResultButton.Location = new System.Drawing.Point(551, 6);
+      this.addTargetsAsResultButton.Name = "addTargetsAsResultButton";
+      this.addTargetsAsResultButton.Size = new System.Drawing.Size(89, 23);
+      this.addTargetsAsResultButton.TabIndex = 4;
+      this.addTargetsAsResultButton.Text = "Add as Result";
+      this.addTargetsAsResultButton.UseVisualStyleBackColor = true;
+      this.addTargetsAsResultButton.Click += new System.EventHandler(this.addTargetsAsResultButton_Click);
+      // 
+      // generateTargetsButton
+      // 
+      this.generateTargetsButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+      this.generateTargetsButton.Location = new System.Drawing.Point(456, 6);
+      this.generateTargetsButton.Name = "generateTargetsButton";
+      this.generateTargetsButton.Size = new System.Drawing.Size(89, 23);
+      this.generateTargetsButton.TabIndex = 3;
+      this.generateTargetsButton.Text = "Generate...";
+      this.generateTargetsButton.UseVisualStyleBackColor = true;
+      this.generateTargetsButton.Click += new System.EventHandler(this.generateTargetsButton_Click);
+      // 
+      // aggregateTargetsCheckBox
+      // 
+      this.aggregateTargetsCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+      this.aggregateTargetsCheckBox.AutoSize = true;
+      this.aggregateTargetsCheckBox.Checked = true;
+      this.aggregateTargetsCheckBox.CheckState = System.Windows.Forms.CheckState.Checked;
+      this.aggregateTargetsCheckBox.Location = new System.Drawing.Point(374, 10);
+      this.aggregateTargetsCheckBox.Name = "aggregateTargetsCheckBox";
+      this.aggregateTargetsCheckBox.Size = new System.Drawing.Size(74, 17);
+      this.aggregateTargetsCheckBox.TabIndex = 2;
+      this.aggregateTargetsCheckBox.Text = "aggregate";
+      this.aggregateTargetsCheckBox.UseVisualStyleBackColor = true;
+      this.aggregateTargetsCheckBox.CheckedChanged += new System.EventHandler(this.aggregateTargetsCheckBox_CheckedChanged);
+      // 
+      // tabControl
+      // 
+      this.tabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.tabControl.Controls.Add(this.byTargetTabPage);
+      this.tabControl.Controls.Add(this.byTableTabPage);
+      this.tabControl.Location = new System.Drawing.Point(0, 84);
+      this.tabControl.Name = "tabControl";
+      this.tabControl.SelectedIndex = 0;
+      this.tabControl.Size = new System.Drawing.Size(654, 413);
+      this.tabControl.TabIndex = 6;
+      // 
+      // byTargetTabPage
+      // 
+      this.byTargetTabPage.Controls.Add(this.relativeOrAbsoluteComboBox);
+      this.byTargetTabPage.Controls.Add(this.targetChart);
+      this.byTargetTabPage.Controls.Add(this.showLabelsCheckBox);
+      this.byTargetTabPage.Controls.Add(this.markerCheckBox);
+      this.byTargetTabPage.Controls.Add(this.targetLogScalingCheckBox);
+      this.byTargetTabPage.Controls.Add(this.targetsLabel);
+      this.byTargetTabPage.Controls.Add(this.aggregateTargetsCheckBox);
+      this.byTargetTabPage.Controls.Add(this.targetsTextBox);
+      this.byTargetTabPage.Controls.Add(this.generateTargetsButton);
+      this.byTargetTabPage.Controls.Add(this.addTargetsAsResultButton);
+      this.byTargetTabPage.Location = new System.Drawing.Point(4, 22);
+      this.byTargetTabPage.Name = "byTargetTabPage";
+      this.byTargetTabPage.Padding = new System.Windows.Forms.Padding(3);
+      this.byTargetTabPage.Size = new System.Drawing.Size(646, 387);
+      this.byTargetTabPage.TabIndex = 0;
+      this.byTargetTabPage.Text = "Performance by Target";
+      this.byTargetTabPage.UseVisualStyleBackColor = true;
+      // 
+      // relativeOrAbsoluteComboBox
+      // 
+      this.relativeOrAbsoluteComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+      this.relativeOrAbsoluteComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+      this.relativeOrAbsoluteComboBox.FormattingEnabled = true;
+      this.relativeOrAbsoluteComboBox.Items.AddRange(new object[] {
+            "relative",
+            "absolute"});
+      this.relativeOrAbsoluteComboBox.Location = new System.Drawing.Point(269, 8);
+      this.relativeOrAbsoluteComboBox.Name = "relativeOrAbsoluteComboBox";
+      this.relativeOrAbsoluteComboBox.Size = new System.Drawing.Size(99, 21);
+      this.relativeOrAbsoluteComboBox.TabIndex = 8;
+      this.relativeOrAbsoluteComboBox.SelectedIndexChanged += new System.EventHandler(this.relativeOrAbsoluteComboBox_SelectedIndexChanged);
+      // 
+      // targetChart
+      // 
+      this.targetChart.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      chartArea2.AxisX.IsStartedFromZero = false;
+      chartArea2.AxisX.MinorGrid.Enabled = true;
+      chartArea2.AxisX.MinorGrid.LineColor = System.Drawing.Color.WhiteSmoke;
+      chartArea2.AxisX.MinorGrid.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
+      chartArea2.AxisY.Maximum = 1D;
+      chartArea2.AxisY.Minimum = 0D;
+      chartArea2.AxisY.MinorGrid.Enabled = true;
+      chartArea2.AxisY.MinorGrid.LineColor = System.Drawing.Color.WhiteSmoke;
+      chartArea2.AxisY.MinorGrid.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
+      chartArea2.Name = "ChartArea1";
+      this.targetChart.ChartAreas.Add(chartArea2);
+      legend2.Alignment = System.Drawing.StringAlignment.Center;
+      legend2.Docking = System.Windows.Forms.DataVisualization.Charting.Docking.Top;
+      legend2.Name = "Legend1";
+      this.targetChart.Legends.Add(legend2);
+      this.targetChart.Location = new System.Drawing.Point(6, 34);
+      this.targetChart.Name = "targetChart";
+      this.targetChart.Size = new System.Drawing.Size(634, 324);
+      this.targetChart.SuppressExceptions = true;
+      this.targetChart.TabIndex = 7;
+      this.targetChart.Text = "enhancedChart1";
+      this.targetChart.CustomizeLegend += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.CustomizeLegendEventArgs>(this.chart_CustomizeLegend);
+      this.targetChart.MouseDown += new System.Windows.Forms.MouseEventHandler(this.chart_MouseDown);
+      this.targetChart.MouseMove += new System.Windows.Forms.MouseEventHandler(this.chart_MouseMove);
+      // 
+      // showLabelsCheckBox
+      // 
+      this.showLabelsCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+      this.showLabelsCheckBox.AutoSize = true;
+      this.showLabelsCheckBox.Checked = true;
+      this.showLabelsCheckBox.CheckState = System.Windows.Forms.CheckState.Checked;
+      this.showLabelsCheckBox.Location = new System.Drawing.Point(227, 364);
+      this.showLabelsCheckBox.Name = "showLabelsCheckBox";
+      this.showLabelsCheckBox.Size = new System.Drawing.Size(81, 17);
+      this.showLabelsCheckBox.TabIndex = 6;
+      this.showLabelsCheckBox.Text = "show labels";
+      this.showLabelsCheckBox.UseVisualStyleBackColor = true;
+      this.showLabelsCheckBox.CheckedChanged += new System.EventHandler(this.showLabelsCheckBox_CheckedChanged);
+      // 
+      // markerCheckBox
+      // 
+      this.markerCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+      this.markerCheckBox.AutoSize = true;
+      this.markerCheckBox.Location = new System.Drawing.Point(127, 364);
+      this.markerCheckBox.Name = "markerCheckBox";
+      this.markerCheckBox.Size = new System.Drawing.Size(91, 17);
+      this.markerCheckBox.TabIndex = 6;
+      this.markerCheckBox.Text = "show markers";
+      this.markerCheckBox.UseVisualStyleBackColor = true;
+      this.markerCheckBox.CheckedChanged += new System.EventHandler(this.markerCheckBox_CheckedChanged);
+      // 
+      // byTableTabPage
+      // 
+      this.byTableTabPage.Controls.Add(this.ertTextBox);
+      this.byTableTabPage.Location = new System.Drawing.Point(4, 22);
+      this.byTableTabPage.Name = "byTableTabPage";
+      this.byTableTabPage.Padding = new System.Windows.Forms.Padding(3);
+      this.byTableTabPage.Size = new System.Drawing.Size(646, 387);
+      this.byTableTabPage.TabIndex = 2;
+      this.byTableTabPage.Text = "Expected Runtime Tables";
+      this.byTableTabPage.UseVisualStyleBackColor = true;
+      // 
+      // problemComboBox
+      // 
+      this.problemComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.problemComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+      this.problemComboBox.FormattingEnabled = true;
+      this.problemComboBox.Location = new System.Drawing.Point(69, 30);
+      this.problemComboBox.Name = "problemComboBox";
+      this.problemComboBox.Size = new System.Drawing.Size(582, 21);
+      this.problemComboBox.TabIndex = 3;
+      this.problemComboBox.SelectedIndexChanged += new System.EventHandler(this.problemComboBox_SelectedIndexChanged);
+      // 
+      // problemLabel
+      // 
+      this.problemLabel.AutoSize = true;
+      this.problemLabel.Location = new System.Drawing.Point(3, 33);
+      this.problemLabel.Name = "problemLabel";
+      this.problemLabel.Size = new System.Drawing.Size(48, 13);
+      this.problemLabel.TabIndex = 2;
+      this.problemLabel.Text = "Problem:";
+      // 
+      // ertTextBox
+      // 
+      this.ertTextBox.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.ertTextBox.Font = new System.Drawing.Font("Courier New", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+      this.ertTextBox.Location = new System.Drawing.Point(3, 3);
+      this.ertTextBox.Multiline = true;
+      this.ertTextBox.Name = "ertTextBox";
+      this.ertTextBox.ReadOnly = true;
+      this.ertTextBox.Size = new System.Drawing.Size(640, 381);
+      this.ertTextBox.TabIndex = 0;
+      this.ertTextBox.WordWrap = false;
+      // 
+      // RunCollectionSimpleRLDView
+      // 
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
+      this.Controls.Add(this.tabControl);
+      this.Controls.Add(this.groupComboBox);
+      this.Controls.Add(this.groupLabel);
+      this.Controls.Add(this.problemLabel);
+      this.Controls.Add(this.dataTableLabel);
+      this.Controls.Add(this.problemComboBox);
+      this.Controls.Add(this.dataTableComboBox);
+      this.Name = "RunCollectionSimpleRLDView";
+      this.Size = new System.Drawing.Size(654, 497);
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit();
+      this.tabControl.ResumeLayout(false);
+      this.byTargetTabPage.ResumeLayout(false);
+      this.byTargetTabPage.PerformLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.targetChart)).EndInit();
+      this.byTableTabPage.ResumeLayout(false);
+      this.byTableTabPage.PerformLayout();
+      this.ResumeLayout(false);
+      this.PerformLayout();
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.ComboBox dataTableComboBox;
+    private System.Windows.Forms.Label dataTableLabel;
+    private System.Windows.Forms.Label groupLabel;
+    private System.Windows.Forms.ComboBox groupComboBox;
+    private System.Windows.Forms.CheckBox targetLogScalingCheckBox;
+    private System.Windows.Forms.TextBox targetsTextBox;
+    private System.Windows.Forms.Label targetsLabel;
+    protected System.Windows.Forms.ErrorProvider errorProvider;
+    private System.Windows.Forms.Button addTargetsAsResultButton;
+    private System.Windows.Forms.Button generateTargetsButton;
+    private System.Windows.Forms.ToolTip toolTip;
+    private System.Windows.Forms.CheckBox aggregateTargetsCheckBox;
+    private System.Windows.Forms.TabControl tabControl;
+    private System.Windows.Forms.TabPage byTargetTabPage;
+    private System.Windows.Forms.TabPage byTableTabPage;
+    private System.Windows.Forms.Label problemLabel;
+    private System.Windows.Forms.ComboBox problemComboBox;
+    private Visualization.ChartControlsExtensions.EnhancedChart targetChart;
+    private System.Windows.Forms.CheckBox markerCheckBox;
+    private System.Windows.Forms.ComboBox relativeOrAbsoluteComboBox;
+    private System.Windows.Forms.CheckBox showLabelsCheckBox;
+    private System.Windows.Forms.TextBox ertTextBox;
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionSimpleRLDView.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionSimpleRLDView.cs	(revision 16733)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionSimpleRLDView.cs	(revision 16733)
@@ -0,0 +1,1301 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using System.Windows.Forms.DataVisualization.Charting;
+using HeuristicLab.Analysis;
+using HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Core.Views;
+using HeuristicLab.Data;
+using HeuristicLab.MainForm;
+using HeuristicLab.MainForm.WindowsForms;
+
+namespace HeuristicLab.Optimization.Views {
+  [View("Simple Run-length Distribution View")]
+  [Content(typeof(RunCollection), false)]
+  public partial class RunCollectionSimpleRLDView : ItemView {
+    private List<Series> invisibleTargetSeries;
+
+    private const string AllInstances = "All Instances";
+
+    private static readonly Color[] colors = new[] {
+      Color.FromArgb(0x40, 0x6A, 0xB7),
+      Color.FromArgb(0xB1, 0x6D, 0x01),
+      Color.FromArgb(0x4E, 0x8A, 0x06),
+      Color.FromArgb(0x75, 0x50, 0x7B),
+      Color.FromArgb(0x72, 0x9F, 0xCF),
+      Color.FromArgb(0xA4, 0x00, 0x00),
+      Color.FromArgb(0xAD, 0x7F, 0xA8),
+      Color.FromArgb(0x29, 0x50, 0xCF),
+      Color.FromArgb(0x90, 0xB0, 0x60),
+      Color.FromArgb(0xF5, 0x89, 0x30),
+      Color.FromArgb(0x55, 0x57, 0x53),
+      Color.FromArgb(0xEF, 0x59, 0x59),
+      Color.FromArgb(0xED, 0xD4, 0x30),
+      Color.FromArgb(0x63, 0xC2, 0x16),
+    };
+    private static readonly ChartDashStyle[] lineStyles = new[] {
+      ChartDashStyle.Solid,
+      ChartDashStyle.Dash,
+      ChartDashStyle.DashDot,
+      ChartDashStyle.Dot
+    };
+    private static readonly DataRowVisualProperties.DataRowLineStyle[] hlLineStyles = new[] {
+      DataRowVisualProperties.DataRowLineStyle.Solid,
+      DataRowVisualProperties.DataRowLineStyle.Dash,
+      DataRowVisualProperties.DataRowLineStyle.DashDot,
+      DataRowVisualProperties.DataRowLineStyle.Dot
+    };
+
+    public new RunCollection Content {
+      get { return (RunCollection)base.Content; }
+      set { base.Content = value; }
+    }
+
+    private List<AlgorithmInstance> groups;
+
+    private double[] targets;
+    private bool targetsAreRelative = true;
+    private bool showLabelsInTargetChart = true;
+    private readonly BindingList<ProblemInstance> problems;
+
+    private bool updateInProgress;
+    private bool suppressContentEvents;
+
+    public RunCollectionSimpleRLDView() {
+      InitializeComponent();
+      invisibleTargetSeries = new List<Series>();
+
+      try {
+        updateInProgress = true;
+        targetChart.CustomizeAllChartAreas();
+        targetChart.ChartAreas[0].CursorX.Interval = 1;
+        targetChart.SuppressExceptions = true;
+
+        relativeOrAbsoluteComboBox.SelectedItem = targetsAreRelative ? "relative" : "absolute";
+        problems = new BindingList<ProblemInstance>();
+        problemComboBox.DataSource = new BindingSource() { DataSource = problems };
+        problemComboBox.DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
+      } finally { updateInProgress = false; }
+    }
+
+    #region Content events
+    protected override void RegisterContentEvents() {
+      base.RegisterContentEvents();
+      Content.ItemsAdded += Content_ItemsAdded;
+      Content.ItemsRemoved += Content_ItemsRemoved;
+      Content.CollectionReset += Content_CollectionReset;
+      Content.UpdateOfRunsInProgressChanged += Content_UpdateOfRunsInProgressChanged;
+      Content.OptimizerNameChanged += Content_AlgorithmNameChanged;
+    }
+    protected override void DeregisterContentEvents() {
+      Content.ItemsAdded -= Content_ItemsAdded;
+      Content.ItemsRemoved -= Content_ItemsRemoved;
+      Content.CollectionReset -= Content_CollectionReset;
+      Content.UpdateOfRunsInProgressChanged -= Content_UpdateOfRunsInProgressChanged;
+      Content.OptimizerNameChanged -= Content_AlgorithmNameChanged;
+      base.DeregisterContentEvents();
+    }
+
+    private void Content_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRun> e) {
+      foreach (var run in e.Items) RegisterRunEvents(run);
+      if (suppressContentEvents) return;
+      if (InvokeRequired) {
+        Invoke(new CollectionItemsChangedEventHandler<IRun>(Content_ItemsAdded), sender, e);
+        return;
+      }
+      if (updateInProgress) return;
+      try {
+        updateInProgress = true;
+        UpdateComboBoxes();
+        GroupRuns();
+      } finally { updateInProgress = false; }
+    }
+    private void Content_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRun> e) {
+      foreach (var run in e.Items) DeregisterRunEvents(run);
+      if (suppressContentEvents) return;
+      if (InvokeRequired) {
+        Invoke(new CollectionItemsChangedEventHandler<IRun>(Content_ItemsRemoved), sender, e);
+        return;
+      }
+      if (updateInProgress) return;
+      try {
+        updateInProgress = true;
+        UpdateComboBoxes();
+        GroupRuns();
+      } finally { updateInProgress = false; }
+    }
+    private void Content_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
+      foreach (var run in e.OldItems) DeregisterRunEvents(run);
+      foreach (var run in e.Items) RegisterRunEvents(run);
+      if (suppressContentEvents) return;
+      if (InvokeRequired) {
+        Invoke(new CollectionItemsChangedEventHandler<IRun>(Content_CollectionReset), sender, e);
+        return;
+      }
+      if (updateInProgress) return;
+      try {
+        updateInProgress = true;
+        UpdateComboBoxes();
+        GroupRuns();
+      } finally { updateInProgress = false; }
+    }
+    private void Content_AlgorithmNameChanged(object sender, EventArgs e) {
+      if (InvokeRequired)
+        Invoke(new EventHandler(Content_AlgorithmNameChanged), sender, e);
+      else UpdateCaption();
+    }
+    private void Content_UpdateOfRunsInProgressChanged(object sender, EventArgs e) {
+      if (InvokeRequired) {
+        Invoke(new EventHandler(Content_UpdateOfRunsInProgressChanged), sender, e);
+        return;
+      }
+      suppressContentEvents = Content.UpdateOfRunsInProgress;
+      if (!suppressContentEvents) {
+        if (updateInProgress) return;
+        try {
+          updateInProgress = true;
+          UpdateComboBoxes();
+          GroupRuns();
+        } finally { updateInProgress = false; }
+      }
+    }
+
+    private void RegisterRunEvents(IRun run) {
+      run.PropertyChanged += run_PropertyChanged;
+    }
+    private void DeregisterRunEvents(IRun run) {
+      run.PropertyChanged -= run_PropertyChanged;
+    }
+    private void run_PropertyChanged(object sender, PropertyChangedEventArgs e) {
+      if (suppressContentEvents) return;
+      if (InvokeRequired) {
+        Invoke((Action<object, PropertyChangedEventArgs>)run_PropertyChanged, sender, e);
+      } else {
+        if (e.PropertyName == "Visible") {
+          if (updateInProgress) return;
+          try {
+            updateInProgress = true;
+            UpdateRuns();
+          } finally { updateInProgress = false; }
+        }
+      }
+    }
+    #endregion
+
+    protected override void OnContentChanged() {
+      base.OnContentChanged();
+      dataTableComboBox.Items.Clear();
+      groupComboBox.Items.Clear();
+      targetChart.ChartAreas[0].AxisX.IsLogarithmic = false;
+      targetChart.Series.Clear();
+      invisibleTargetSeries.Clear();
+
+      UpdateCaption();
+      if (Content != null) {
+        try {
+          updateInProgress = true;
+          UpdateComboBoxes();
+          UpdateRuns();
+        } finally { updateInProgress = false; }
+      }
+    }
+
+
+    private void UpdateComboBoxes() {
+      var selectedGroupItem = (string)groupComboBox.SelectedItem;
+
+      var groupings = Content.ParameterNames.OrderBy(x => x).ToArray();
+      groupComboBox.Items.Clear();
+      groupComboBox.Items.Add(AllInstances);
+      groupComboBox.Items.AddRange(groupings);
+      if (selectedGroupItem != null && groupComboBox.Items.Contains(selectedGroupItem)) {
+        groupComboBox.SelectedItem = selectedGroupItem;
+      } else if (groupComboBox.Items.Count > 0) {
+        groupComboBox.SelectedItem = groupComboBox.Items[0];
+      }
+
+      string selectedDataTable = (string)dataTableComboBox.SelectedItem;
+
+      dataTableComboBox.Items.Clear();
+      var dataTables = (from run in Content
+                        from result in run.Results
+                        where result.Value is IndexedDataTable<double>
+                        select result.Key).Distinct().ToArray();
+
+      dataTableComboBox.Items.AddRange(dataTables);
+      if (selectedDataTable != null && dataTableComboBox.Items.Contains(selectedDataTable)) {
+        dataTableComboBox.SelectedItem = selectedDataTable;
+      } else if (dataTableComboBox.Items.Count > 0) {
+        dataTableComboBox.SelectedItem = dataTableComboBox.Items[0];
+      }
+
+      var selectedProblemItem = (ProblemInstance)problemComboBox.SelectedItem;
+      
+      UpdateProblemInstances();
+      
+      foreach (var p in problems) {
+        if (p.Equals(selectedProblemItem))
+          problemComboBox.SelectedItem = p;
+      }
+
+      if (selectedProblemItem == null && problems.Count > 1) problemComboBox.SelectedItem = problems[1];
+
+      SetEnabledStateOfControls();
+    }
+
+    protected override void SetEnabledStateOfControls() {
+      base.SetEnabledStateOfControls();
+      groupComboBox.Enabled = Content != null;
+      problemComboBox.Enabled = Content != null && problemComboBox.Items.Count > 1;
+      dataTableComboBox.Enabled = Content != null && dataTableComboBox.Items.Count > 1;
+      addTargetsAsResultButton.Enabled = Content != null && targets != null && dataTableComboBox.SelectedIndex >= 0;
+      generateTargetsButton.Enabled = targets != null;
+    }
+
+    private void GroupRuns() {
+      groups = new List<AlgorithmInstance>();
+
+      var table = (string)dataTableComboBox.SelectedItem;
+      if (string.IsNullOrEmpty(table)) return;
+
+      var selectedGroup = (string)groupComboBox.SelectedItem;
+      if (string.IsNullOrEmpty(selectedGroup)) return;
+
+      var selectedProblem = (ProblemInstance)problemComboBox.SelectedItem;
+      if (selectedProblem == null) return;
+
+      foreach (var alg in from r in Content
+                          where (selectedGroup == AllInstances || r.Parameters.ContainsKey(selectedGroup))
+                            && r.Visible
+                            && selectedProblem.Match(r)
+                          let key = selectedGroup == AllInstances
+                            ? AllInstances : r.Parameters[selectedGroup].ToString()
+                          group r by key into g
+                          select g) {
+        var trials = (from run in alg
+                     from pd in problems.Skip(1) // exclude artificial match all
+                     where pd.Match(run) && run.Results.ContainsKey(table)
+                     let cgraph = run.Results[table] as IndexedDataTable<double>
+                     where cgraph != null && cgraph.Rows.Count > 0
+                        && cgraph.Rows.First().Values.Count > 0
+                     group cgraph by pd into g
+                     select g).ToList();
+
+        if (trials.Count == 0) continue;
+        groups.Add(new AlgorithmInstance(alg.Key, trials));
+      }
+    }
+
+    private void UpdateProblemInstances() {
+      try {
+        problems.Clear();
+        var table = (string)dataTableComboBox.SelectedItem;
+        
+        var problemDict = CalculateBestTargetPerProblemInstance(table);
+
+        var problemTypesDifferent = problemDict.Keys.Select(x => x.ProblemType).Where(x => !string.IsNullOrEmpty(x)).Distinct().Count() > 1;
+        var problemNamesDifferent = problemDict.Keys.Select(x => x.ProblemName).Where(x => !string.IsNullOrEmpty(x)).Distinct().Count() > 1;
+        var evaluatorDifferent = problemDict.Keys.Select(x => x.Evaluator).Where(x => !string.IsNullOrEmpty(x)).Distinct().Count() > 1;
+        var maximizationDifferent = problemDict.Keys.Select(x => x.Maximization).Distinct().Count() > 1;
+        var allEqual = !problemTypesDifferent && !problemNamesDifferent && !evaluatorDifferent && !maximizationDifferent;
+
+        problems.Add(ProblemInstance.MatchAll);
+        foreach (var p in problemDict.OrderBy(x => x.Key.ProblemName, new NaturalStringComparer()).ToList()) {
+          p.Key.BestKnownQuality = p.Value;
+          p.Key.DisplayProblemType = problemTypesDifferent;
+          p.Key.DisplayProblemName = problemNamesDifferent || allEqual;
+          p.Key.DisplayEvaluator = evaluatorDifferent;
+          p.Key.DisplayMaximization = maximizationDifferent;
+          problems.Add(p.Key);
+        }
+      } finally { ((BindingSource)problemComboBox.DataSource).ResetBindings(false); }
+    }
+
+    #region Performance analysis by (multiple) target(s)
+    private void UpdateResultsByTarget() {
+      // necessary to reset log scale -> empty chart cannot use log scaling
+      targetChart.ChartAreas[0].AxisX.IsLogarithmic = false;
+      targetChart.Series.Clear();
+      invisibleTargetSeries.Clear();
+      
+      var table = (string)dataTableComboBox.SelectedItem;
+      if (string.IsNullOrEmpty(table)) return;
+
+      if (targets == null) GenerateDefaultTargets();
+      
+      if (groups.Count == 0) return;
+
+      var xAxisTitles = new HashSet<string>();
+
+      // hits describes the number of target hits at a certain time for a certain group
+      var hits = new Dictionary<string, SortedList<double, int>>();
+      var totalRuns = new Dictionary<string, Tuple<int, double>>();
+
+      var aggregate = aggregateTargetsCheckBox.Checked;
+      double minEff = double.MaxValue, maxEff = double.MinValue;
+      foreach (var alg in groups) {
+        var noRuns = 0;
+        SortedList<double, int> epdfHits = null;
+        if (aggregate) hits[alg.Name] = epdfHits = new SortedList<double, int>();
+
+        var maxRunLength = 0.0;
+        foreach (var problem in alg.GetCases().Where(x => x.Maximization.HasValue)) {
+          var max = problem.Maximization.Value;
+          var absTargets = GetAbsoluteTargets(problem).ToArray();
+          foreach (var run in alg.GetTrials(problem)) {
+            noRuns++;
+            xAxisTitles.Add(run.XAxisName);
+
+            var efforts = absTargets.Select(t => GetEffortToHitTarget(run, t, max)).ToArray();
+            minEff = Math.Min(minEff, efforts.Min(x => x.Item2));
+            maxEff = Math.Max(maxEff, efforts.Max(x => x.Item2));
+            for (var idx = 0; idx < efforts.Length; idx++) {
+              var e = efforts[idx];
+              if (!aggregate) {
+                var key = alg.Name + "@" + (targetsAreRelative
+                            ? (targets[idx] * 100).ToString(CultureInfo.CurrentCulture.NumberFormat) + "%"
+                            : targets[idx].ToString(CultureInfo.CurrentCulture.NumberFormat));
+                if (!hits.TryGetValue(key, out epdfHits))
+                  hits[key] = epdfHits = new SortedList<double, int>();
+                totalRuns[key] = Tuple.Create(noRuns, maxRunLength);
+              };
+              if (e.Item1) {
+                if (epdfHits.TryGetValue(e.Item2, out var v))
+                  epdfHits[e.Item2] = v + 1;
+                else epdfHits[e.Item2] = 1;
+              }
+              maxRunLength = Math.Max(maxRunLength, e.Item2);
+            }
+          }
+        }
+        if (aggregate) totalRuns[alg.Name] = Tuple.Create(noRuns, maxRunLength);
+      }
+
+      UpdateTargetChartAxisXBounds(minEff, maxEff);
+
+      DrawTargetsEcdf(hits, totalRuns);
+
+      if (targets.Length == 1) {
+        if (targetsAreRelative)
+          targetChart.ChartAreas[0].AxisY.Title = "Probability to be " + (targets[0] * 100) + "% worse than best";
+        else targetChart.ChartAreas[0].AxisY.Title = "Probability to reach at least a fitness of " + targets[0];
+      } else targetChart.ChartAreas[0].AxisY.Title = "Proportion of reached targets";
+      targetChart.ChartAreas[0].AxisX.Title = string.Join(" / ", xAxisTitles);
+      targetChart.ChartAreas[0].AxisX.IsLogarithmic = CanDisplayLogarithmic();
+      targetChart.ChartAreas[0].CursorY.Interval = 0.05;
+
+      UpdateErtTables();
+    }
+
+    private void DrawTargetsEcdf(Dictionary<string, SortedList<double, int>> hits, Dictionary<string, Tuple<int, double>> noRuns) {
+      var colorCount = 0;
+      var lineStyleCount = 0;
+      
+      var showMarkers = markerCheckBox.Checked;
+      foreach (var list in hits) {
+        var row = new Series(list.Key) {
+          ChartType = list.Value.Count > 1000 ? SeriesChartType.FastLine : SeriesChartType.StepLine,
+          BorderWidth = 3,
+          Color = colors[colorCount],
+          BorderDashStyle = lineStyles[lineStyleCount],
+        };
+        var lastPoint = new Series(list.Key + "-point") {
+          ChartType = SeriesChartType.Point,
+          IsVisibleInLegend = false,
+          BorderWidth = 3,
+          Color = colors[colorCount],
+          BorderDashStyle = lineStyles[lineStyleCount]
+        };
+
+        var ecdf = 0.0;
+        var totalTargets = noRuns[list.Key].Item1;
+        var maxRunLength = noRuns[list.Key].Item2;
+        if (aggregateTargetsCheckBox.Checked) totalTargets *= targets.Length;
+        foreach (var h in list.Value) {
+          ecdf += h.Value;
+          if (row.Points.Count > 0 && row.Points.Last().XValue == h.Key) {
+            row.Points.Last().SetValueY(ecdf / totalTargets);
+          } else {
+            var dp = new DataPoint(h.Key, ecdf / totalTargets);
+            if (showMarkers) {
+              dp.MarkerStyle = MarkerStyle.Circle;
+              dp.MarkerBorderWidth = 1;
+              dp.MarkerSize = 5;
+            }
+            row.Points.Add(dp);
+          }
+        }
+        
+        if (row.Points.Count == 0 || row.Points.Last().XValue < maxRunLength) {
+          var dp = new DataPoint(maxRunLength, ecdf / totalTargets);
+          if (showMarkers) {
+            dp.MarkerStyle = MarkerStyle.Circle;
+            dp.MarkerBorderWidth = 1;
+            dp.MarkerSize = 5;
+          }
+          row.Points.Add(dp);
+        }
+
+        var point = row.Points.Last();
+        var lp = new DataPoint(point.XValue, point.YValues[0]) {
+          Label = showLabelsInTargetChart ? row.Name : string.Empty,
+          MarkerStyle = MarkerStyle.Cross,
+          MarkerBorderWidth = 1,
+          MarkerSize = 10,
+        };
+        lastPoint.Points.Add(lp);
+
+        ConfigureSeries(row);
+        ConfigureSeries(lastPoint);
+        targetChart.Series.Add(row);
+        targetChart.Series.Add(lastPoint);
+
+        colorCount = (colorCount + 1) % colors.Length;
+        if (colorCount == 0) lineStyleCount = (lineStyleCount + 1) % lineStyles.Length;
+      }
+    }
+
+    private void UpdateTargetChartAxisXBounds(double minEff, double maxEff) {
+      var minZeros = (int)Math.Floor(Math.Log10(minEff));
+      var maxZeros = (int)Math.Floor(Math.Log10(maxEff));
+      var axisMin = (decimal)Math.Pow(10, minZeros);
+      var axisMax = (decimal)Math.Pow(10, maxZeros);
+      if (!targetLogScalingCheckBox.Checked) {
+        var minAdd = (decimal)Math.Pow(10, minZeros - 1) * 2;
+        var maxAdd = (decimal)Math.Pow(10, maxZeros - 1) * 2;
+        while (axisMin + minAdd < (decimal)minEff) axisMin += minAdd;
+        while (axisMax <= (decimal)maxEff) axisMax += maxAdd;
+      } else axisMax = (decimal)Math.Pow(10, (int)Math.Ceiling(Math.Log10(maxEff)));
+      targetChart.ChartAreas[0].AxisX.Minimum = (double)axisMin;
+      targetChart.ChartAreas[0].AxisX.Maximum = (double)axisMax;
+    }
+
+    private IEnumerable<double> GetAbsoluteTargets(ProblemInstance pInstance) {
+      if (!targetsAreRelative) return targets;
+      if (!pInstance.Maximization.HasValue) throw new ArgumentException("Problem doesn't specify if it is to be maximized or minimized.");
+
+      var maximization = pInstance.Maximization.Value;
+      var bestKnown = pInstance.BestKnownQuality;
+      if (double.IsNaN(bestKnown)) throw new ArgumentException("Problem instance does not have a defined best - known quality.");
+      IEnumerable<double> tmp = null;
+      if (bestKnown > 0) {
+        tmp = targets.Select(x => (maximization ? (1 - x) : (1 + x)) * bestKnown);
+      } else if (bestKnown < 0) {
+        tmp = targets.Select(x => (!maximization ? (1 - x) : (1 + x)) * bestKnown);
+      } else {
+        // relative to 0 is impossible
+        tmp = targets;
+      }
+      return tmp;
+    }
+
+    private double[] GetAbsoluteTargetsWorstToBest(ProblemInstance pInstance) {
+      if (targetsAreRelative && double.IsNaN(pInstance.BestKnownQuality)) throw new ArgumentException("Problem instance does not have a defined best-known quality.");
+      if (!pInstance.Maximization.HasValue) throw new ArgumentException("Problem doesn't specify if it is to be maximized or minimized.");
+      var absTargets = GetAbsoluteTargets(pInstance);
+      return (pInstance.Maximization.Value
+        ? absTargets.OrderBy(x => x) : absTargets.OrderByDescending(x => x)).ToArray();
+    }
+
+    private void GenerateDefaultTargets() {
+      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 };
+      SynchronizeTargetTextBox();
+    }
+
+    private Tuple<bool, double> GetEffortToHitTarget(
+        ConvergenceGraph cgraph,
+        double absTarget, bool maximization) {
+      if (cgraph.Points == 0)
+        throw new ArgumentException("Convergence graph is empty.", "convergenceGraph");
+      
+      var index = cgraph.BinarySearch(new ConvergenceGraphPoint(0.0, absTarget), new TargetComparer(maximization));
+      if (index >= 0) {
+        return Tuple.Create(true, cgraph[index].Runlength);
+      } else {
+        index = ~index;
+        if (index >= cgraph.Points)
+          return Tuple.Create(false, cgraph.Last().Runlength);
+        return Tuple.Create(true, cgraph[index].Runlength);
+      }
+    }
+
+    private void UpdateErtTables() {
+      ertTextBox.Text = string.Empty;
+      var tabular = new StringBuilder();
+      tabular.Append("\t");
+      tabular.AppendLine(string.Join("\t", targets.Select(x => targetsAreRelative ? (100 * x).ToString() + "%" : x.ToString())
+        .Concat(new[] { "#succ" }).ToList()));
+
+      var tableName = (string)dataTableComboBox.SelectedItem;
+      if (string.IsNullOrEmpty(tableName)) return;
+      
+      var problems = groups.SelectMany(x => x.GetCases()).Distinct().ToList();
+
+      foreach (var problem in problems.OrderBy(x => x.ProblemName, new NaturalStringComparer())) {
+        if (double.IsNaN(problem.BestKnownQuality) || !problem.Maximization.HasValue) continue;
+        tabular.Append(problem.ToString());
+        var max = problem.Maximization.Value;
+        var absTargets = GetAbsoluteTargetsWorstToBest(problem);
+        if (targetsAreRelative) {
+          // print out the absolute target values
+          for (var i = 0; i < absTargets.Length; i++) {
+            tabular.Append("\t");
+            tabular.Append(absTargets[i].ToString("##,0.0", CultureInfo.CurrentCulture.NumberFormat));
+          }
+          tabular.AppendLine();
+        }
+
+        foreach (var alg in groups) {
+          tabular.Append(alg.Name);
+          var runs = alg.GetTrials(problem).ToList();
+          if (runs.Count == 0) {
+            for (var i = 0; i < absTargets.Length; i++)
+              tabular.Append("\t");
+            tabular.AppendLine("\tN/A");
+            continue;
+          }
+          var result = default(ErtCalculationResult);
+          for (var i = 0; i < absTargets.Length; i++) {
+            result = ExpectedRuntimeHelper.CalculateErt(runs.Select(x => x.ToTuples()), absTargets[i], max);
+            tabular.Append("\t");
+            tabular.Append(result.ToString());
+          }
+          tabular.Append("\t");
+          tabular.AppendLine(targets.Length > 0 ? result.SuccessfulRuns + "/" + result.TotalRuns : "-");
+        }
+        tabular.AppendLine();
+      }
+      ertTextBox.Text = tabular.ToString();
+    }
+    #endregion
+    
+    private void UpdateCaption() {
+      Caption = Content != null ? Content.OptimizerName + " RLD View" : ViewAttribute.GetViewName(GetType());
+    }
+
+    private void SynchronizeTargetTextBox() {
+      if (InvokeRequired) Invoke((Action)SynchronizeTargetTextBox);
+      else {
+        if (targetsAreRelative)
+          targetsTextBox.Text = string.Join("% ; ", targets.Select(x => x * 100)) + "%";
+        else targetsTextBox.Text = string.Join(" ; ", targets);
+      }
+    }
+
+    private void groupComboBox_SelectedIndexChanged(object sender, EventArgs e) {
+      if (updateInProgress) return;
+      try {
+        updateInProgress = true;
+        UpdateRuns();
+        SetEnabledStateOfControls();
+      } finally { updateInProgress = false; }
+    }
+    private void problemComboBox_SelectedIndexChanged(object sender, EventArgs e) {
+      if (updateInProgress) return;
+      try {
+        updateInProgress = true;
+        UpdateRuns();
+        SetEnabledStateOfControls();
+      } finally { updateInProgress = false; }
+    }
+    private void dataTableComboBox_SelectedIndexChanged(object sender, EventArgs e) {
+      if (updateInProgress) return;
+      try {
+        updateInProgress = true;
+        UpdateBestKnownQualities();
+        UpdateRuns();
+        SetEnabledStateOfControls();
+      } finally { updateInProgress = false; }
+    }
+
+    private void logScalingCheckBox_CheckedChanged(object sender, EventArgs e) {
+      UpdateResultsByTarget();
+    }
+
+    #region Event handlers for target analysis
+    private void targetsTextBox_Validating(object sender, CancelEventArgs e) {
+      if (updateInProgress) return;
+      try {
+        updateInProgress = true;
+        var targetStrings = targetsTextBox.Text.Split(new[] { '%', ';', '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries);
+        var targetList = new List<decimal>();
+        foreach (var ts in targetStrings) {
+          decimal t;
+          if (!decimal.TryParse(ts, out t)) {
+            errorProvider.SetError(targetsTextBox, "Not all targets can be parsed: " + ts);
+            e.Cancel = true;
+            return;
+          }
+          if (targetsAreRelative)
+            targetList.Add(t / 100);
+          else targetList.Add(t);
+        }
+        if (targetList.Count == 0) {
+          errorProvider.SetError(targetsTextBox, "Give at least one target value!");
+          e.Cancel = true;
+          return;
+        }
+        e.Cancel = false;
+        errorProvider.SetError(targetsTextBox, null);
+        targets = targetsAreRelative ? targetList.Select(x => (double)x).OrderByDescending(x => x).ToArray() : targetList.Select(x => (double)x).ToArray();
+
+        SynchronizeTargetTextBox();
+        UpdateResultsByTarget();
+        SetEnabledStateOfControls();
+
+      } finally { updateInProgress = false; }
+    }
+
+    private void aggregateTargetsCheckBox_CheckedChanged(object sender, EventArgs e) {
+      if (updateInProgress) return;
+      try {
+        updateInProgress = true;
+        SuspendRepaint();
+        UpdateResultsByTarget();
+      } finally {
+        updateInProgress = false;
+        ResumeRepaint(true);
+      }
+    }
+
+    private void relativeOrAbsoluteComboBox_SelectedIndexChanged(object sender, EventArgs e) {
+      if (updateInProgress) return;
+      try {
+        updateInProgress = true;
+        var pd = (ProblemInstance)problemComboBox.SelectedItem;
+        if (!double.IsNaN(pd.BestKnownQuality) && pd.Maximization.HasValue) {
+          var max = pd.Maximization.Value;
+          if (targetsAreRelative) targets = GetAbsoluteTargets(pd).ToArray();
+          else {
+            // Rounding to 5 digits since it's certainly appropriate for this application
+            if (pd.BestKnownQuality > 0) {
+              targets = targets.Select(x => Math.Round(max ? 1.0 - (x / pd.BestKnownQuality) : (x / pd.BestKnownQuality) - 1.0, 5)).ToArray();
+            } else if (pd.BestKnownQuality < 0) {
+              targets = targets.Select(x => Math.Round(!max ? 1.0 - (x / pd.BestKnownQuality) : (x / pd.BestKnownQuality) - 1.0, 5)).ToArray();
+            }
+          }
+        }
+        targetsAreRelative = (string)relativeOrAbsoluteComboBox.SelectedItem == "relative";
+        SynchronizeTargetTextBox();
+        
+        SuspendRepaint();
+        UpdateResultsByTarget();
+      } finally {
+        updateInProgress = false;
+        ResumeRepaint(true);
+      }
+    }
+
+    private void generateTargetsButton_Click(object sender, EventArgs e) {
+      if (targets == null) return;
+      decimal max = 10, min = 0, count = 10;
+      max = (decimal)targets.Max();
+      min = (decimal)targets.Min();
+      count = targets.Length - 1;
+      if (targetsAreRelative) {
+        max *= 100;
+        min *= 100;
+      }
+      using (var dialog = new DefineArithmeticProgressionDialog(false, min, max, (max - min) / count)) {
+        if (dialog.ShowDialog() == DialogResult.OK) {
+          if (dialog.Values.Any()) {
+            targets = targetsAreRelative
+              ? dialog.Values.OrderByDescending(x => x).Select(x => (double)x / 100.0).ToArray()
+              : dialog.Values.Select(x => (double)x).ToArray();
+
+            try {
+              updateInProgress = true;
+              SynchronizeTargetTextBox();
+              UpdateResultsByTarget();
+              SetEnabledStateOfControls();
+            } finally { updateInProgress = false; }
+          }
+        }
+      }
+    }
+
+    private void addTargetsAsResultButton_Click(object sender, EventArgs e) {
+      var table = (string)dataTableComboBox.SelectedItem;
+      if (string.IsNullOrEmpty(table)) return;
+      
+      foreach (var run in Content) {
+        if (!run.Results.ContainsKey(table) || !(run.Results[table] is IndexedDataTable<double>)) continue;
+        var resultsTable = (IndexedDataTable<double>)run.Results[table];
+        var values = resultsTable.Rows.First().Values;
+        var pd = new ProblemInstance(run);
+        if (!pd.Maximization.HasValue) continue;
+        pd = problems.Single(x => x.Equals(pd));
+        if (targetsAreRelative && double.IsNaN(pd.BestKnownQuality)) continue;
+
+        var max = pd.Maximization.Value;
+        var absTargets = GetAbsoluteTargetsWorstToBest(pd);
+        var cgraph = new ConvergenceGraph(resultsTable, max);
+
+        var prevIndex = 0;
+        for (var i = 0; i < absTargets.Length; i++) {
+          var absTarget = absTargets[i];
+          var index = cgraph.BinarySearch(prevIndex, values.Count - prevIndex, new ConvergenceGraphPoint(0.0, absTarget), new TargetComparer(max));
+          if (index < 0) {
+            index = ~index;
+            if (index >= values.Count) break; // the target (and subsequent ones) wasn't achieved
+          }
+          var target = targetsAreRelative ? (targets[i] * 100) : absTarget;
+          run.Results[table + (targetsAreRelative ? ".RelTarget " : ".AbsTarget ") + target + (targetsAreRelative ? "%" : string.Empty)] = new DoubleValue(values[index].Item1);
+          prevIndex = index;
+        }
+      }
+    }
+
+    private void markerCheckBox_CheckedChanged(object sender, EventArgs e) {
+      try {
+        updateInProgress = true;
+        SuspendRepaint();
+        UpdateResultsByTarget();
+      } finally {
+        updateInProgress = false;
+        ResumeRepaint(true);
+      }
+    }
+
+    private void showLabelsCheckBox_CheckedChanged(object sender, EventArgs e) {
+      showLabelsInTargetChart = showLabelsCheckBox.Checked;
+      try {
+        updateInProgress = true;
+        SuspendRepaint();
+        UpdateResultsByTarget();
+      } finally {
+        updateInProgress = false;
+        ResumeRepaint(true);
+      }
+    }
+    #endregion
+    
+    #region Helpers
+    private double CalculateRelativeDifference(bool maximization, double bestKnown, double fit) {
+      if (bestKnown == 0) {
+        // no relative difference with respect to bestKnown possible
+        return maximization ? -fit : fit;
+      }
+      var absDiff = (fit - bestKnown);
+      var relDiff = absDiff / bestKnown;
+      if (maximization) {
+        return bestKnown > 0 ? -relDiff : relDiff;
+      } else {
+        return bestKnown > 0 ? relDiff : -relDiff;
+      }
+    }
+
+    private Dictionary<ProblemInstance, double> CalculateBestTargetPerProblemInstance(string table) {
+      if (table == null) table = string.Empty;
+      var dict = new Dictionary<ProblemInstance, double>();
+      foreach (var k in from r in Content where r.Visible let pd = new ProblemInstance(r) group r by pd into g select new { Problem = g.Key, Runs = g.ToList() }) {
+        var pd = k.Problem;
+        if (!pd.Maximization.HasValue) continue;
+        var values = GetQualityValues(k.Runs, table).ToList();
+        var target = double.NaN;
+        if (values.Count > 0) {
+          target = pd.Maximization.Value ? values.Max() : values.Min();
+        }
+        dict[pd] = target;
+      }
+      return dict;
+    }
+
+    private IEnumerable<double> GetQualityValues(List<IRun> runs, string table) {
+      foreach (var r in runs) {
+        IItem item;
+        if (r.Parameters.TryGetValue("BestKnownQuality", out item)) {
+          var dval = item as DoubleValue;
+          if (dval != null && !double.IsNaN(dval.Value))
+            yield return dval.Value;
+        }
+        if (r.Results.TryGetValue(table, out item)) {
+          var dt = item as IndexedDataTable<double>;
+          if (dt != null && dt.Rows.Count > 0 && dt.Rows.First().Values.Count > 0) {
+            var last = dt.Rows.First().Values.Last().Item2;
+            if (!double.IsNaN(last))
+              yield return Math.Round(last, 10);
+          }
+        }
+      }
+    }
+
+    private void UpdateRuns() {
+      if (InvokeRequired) {
+        Invoke((Action)UpdateRuns);
+        return;
+      }
+      SuspendRepaint();
+      try {
+        GroupRuns();
+        UpdateResultsByTarget();
+      } finally { ResumeRepaint(true); }
+    }
+
+    private void UpdateBestKnownQualities() {
+      var table = (string)dataTableComboBox.SelectedItem;
+      if (string.IsNullOrEmpty(table)) return;
+
+      var targetsPerProblem = CalculateBestTargetPerProblemInstance(table);
+      foreach (var pd in problems) {
+        double bkq;
+        if (targetsPerProblem.TryGetValue(pd, out bkq))
+          pd.BestKnownQuality = bkq;
+        else pd.BestKnownQuality = double.NaN;
+      }
+    }
+    #endregion
+
+    private void ConfigureSeries(Series series) {
+      series.SmartLabelStyle.Enabled = showLabelsInTargetChart;
+      series.SmartLabelStyle.AllowOutsidePlotArea = LabelOutsidePlotAreaStyle.No;
+      series.SmartLabelStyle.CalloutLineAnchorCapStyle = LineAnchorCapStyle.None;
+      series.SmartLabelStyle.CalloutLineColor = series.Color;
+      series.SmartLabelStyle.CalloutLineWidth = 2;
+      series.SmartLabelStyle.CalloutStyle = LabelCalloutStyle.Underlined;
+      series.SmartLabelStyle.IsOverlappedHidden = false;
+      series.SmartLabelStyle.MaxMovingDistance = 200;
+      series.ToolTip = series.LegendText + " X = #VALX, Y = #VALY";
+    }
+
+    private void chart_MouseDown(object sender, MouseEventArgs e) {
+      HitTestResult result = targetChart.HitTest(e.X, e.Y);
+      if (result.ChartElementType == ChartElementType.LegendItem) {
+        ToggleTargetChartSeriesVisible(result.Series);
+      }
+    }
+    private void chart_MouseMove(object sender, MouseEventArgs e) {
+      HitTestResult result = targetChart.HitTest(e.X, e.Y);
+      if (result.ChartElementType == ChartElementType.LegendItem)
+        this.Cursor = Cursors.Hand;
+      else
+        this.Cursor = Cursors.Default;
+    }
+    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
+      foreach (LegendItem legendItem in e.LegendItems) {
+        var series = targetChart.Series[legendItem.SeriesName];
+        if (series != null) {
+          bool seriesIsInvisible = invisibleTargetSeries.Any(x => x.Name == series.Name);
+          foreach (LegendCell cell in legendItem.Cells) {
+            cell.ForeColor = seriesIsInvisible ? Color.Gray : Color.Black;
+          }
+        }
+      }
+    }
+
+    private void ToggleTargetChartSeriesVisible(Series series) {
+      var indexList = invisibleTargetSeries.FindIndex(x => x.Name == series.Name);
+      var indexChart = targetChart.Series.IndexOf(series);
+      if (targetChart.Series.Count == 1) targetChart.ChartAreas[0].AxisX.IsLogarithmic = false;
+      targetChart.Series.RemoveAt(indexChart);
+      var s = indexList >= 0 ? invisibleTargetSeries[indexList] : new Series(series.Name) {
+        Color = series.Color,
+        ChartType = series.ChartType,
+        BorderWidth = series.BorderWidth,
+        BorderDashStyle = series.BorderDashStyle
+      };
+      if (indexList < 0) {
+        // hide
+        invisibleTargetSeries.Add(series);
+        var shadeSeries = targetChart.Series.FirstOrDefault(x => x.Name == series.Name + "-range");
+        if (shadeSeries != null) {
+          if (targetChart.Series.Count == 1) targetChart.ChartAreas[0].AxisX.IsLogarithmic = false;
+          targetChart.Series.Remove(shadeSeries);
+          invisibleTargetSeries.Add(shadeSeries);
+          indexChart--;
+        }
+      } else {
+        // show
+        invisibleTargetSeries.RemoveAt(indexList);
+        var shadeSeries = invisibleTargetSeries.FirstOrDefault(x => x.Name == series.Name + "-range");
+        if (shadeSeries != null) {
+          invisibleTargetSeries.Remove(shadeSeries);
+          InsertOrAddSeries(indexChart, shadeSeries);
+          indexChart++;
+        }
+      }
+      InsertOrAddSeries(indexChart, s);
+      targetChart.ChartAreas[0].AxisX.IsLogarithmic = CanDisplayLogarithmic();
+    }
+
+    private bool CanDisplayLogarithmic() {
+      return targetLogScalingCheckBox.Checked
+        && targetChart.Series.Count > 0 // must have a series
+        && targetChart.Series.Any(x => x.Points.Count > 0) // at least one series must have points
+        && targetChart.Series.All(s => s.Points.All(p => p.XValue > 0)); // all points must be positive
+    }
+
+    private void InsertOrAddSeries(int index, Series s) {
+      if (targetChart.Series.Count <= index)
+        targetChart.Series.Add(s);
+      else targetChart.Series.Insert(index, s);
+    }
+
+    #region Helper classes
+    private class AlgorithmInstance : INotifyPropertyChanged {
+      private string name;
+      public string Name {
+        get { return name; }
+        set {
+          if (name == value) return;
+          name = value;
+          OnPropertyChanged("Name");
+        }
+      }
+
+      private Dictionary<ProblemInstance, List<ConvergenceGraph>> performanceData;
+
+      public int GetNumberOfCases() {
+        return performanceData.Count;
+      }
+
+      public IEnumerable<ProblemInstance> GetCases() {
+        return performanceData.Keys;
+      }
+
+      public int GetNumberOfTrials(ProblemInstance p) {
+        if (p == ProblemInstance.MatchAll) return performanceData.Select(x => x.Value.Count).Sum();
+        List<ConvergenceGraph> trials;
+        if (performanceData.TryGetValue(p, out trials))
+          return trials.Count;
+
+        return 0;
+      }
+
+      public IEnumerable<ConvergenceGraph> GetTrials(ProblemInstance p) {
+        if (p == ProblemInstance.MatchAll) return performanceData.SelectMany(x => x.Value);
+        List<ConvergenceGraph> trials;
+        if (performanceData.TryGetValue(p, out trials))
+          return trials;
+
+        return Enumerable.Empty<ConvergenceGraph>();
+      }
+
+      public AlgorithmInstance(string name, IEnumerable<IGrouping<ProblemInstance, IndexedDataTable<double>>> trials) {
+        this.name = name;
+
+        performanceData = new Dictionary<ProblemInstance, List<ConvergenceGraph>>();
+        foreach (var t in trials) {
+          if (double.IsNaN(t.Key.BestKnownQuality) || !t.Key.Maximization.HasValue) continue;
+          performanceData[t.Key] = t.Select(c => new ConvergenceGraph(c, t.Key.Maximization.Value)).ToList();
+        }
+      }
+
+      public override bool Equals(object obj) {
+        var other = obj as AlgorithmInstance;
+        if (other == null) return false;
+        return name == other.name;
+      }
+
+      public override int GetHashCode() {
+        return name.GetHashCode();
+      }
+
+      public event PropertyChangedEventHandler PropertyChanged;
+      protected virtual void OnPropertyChanged(string propertyName = null) {
+        var handler = PropertyChanged;
+        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
+      }
+    }
+
+    private class ProblemInstance : INotifyPropertyChanged {
+      private readonly bool matchAll;
+      public static readonly ProblemInstance MatchAll = new ProblemInstance() {
+        ProblemName = "All with Best-Known"
+      };
+
+      private ProblemInstance() {
+        ProblemType = string.Empty;
+        ProblemName = string.Empty;
+        Evaluator = string.Empty;
+        Maximization = null;
+        DisplayProblemType = false;
+        DisplayProblemName = false;
+        DisplayEvaluator = false;
+        DisplayMaximization = false;
+        matchAll = true;
+        BestKnownQuality = double.NaN;
+      }
+
+      public ProblemInstance(IRun run) {
+        ProblemType = GetStringValueOrEmpty(run, "Problem Type");
+        ProblemName = GetStringValueOrEmpty(run, "Problem Name");
+        Evaluator = GetStringValueOrEmpty(run, "Evaluator");
+        Maximization = GetBoolValueOrEmpty(run, "Maximization");
+        DisplayProblemType = !string.IsNullOrEmpty(ProblemType);
+        DisplayProblemName = !string.IsNullOrEmpty(ProblemName);
+        DisplayEvaluator = !string.IsNullOrEmpty(Evaluator);
+        DisplayMaximization = Maximization.HasValue;
+        matchAll = false;
+        BestKnownQuality = GetDoubleValueOrNaN(run, "BestKnownQuality");
+      }
+
+      private bool displayProblemType;
+      public bool DisplayProblemType {
+        get { return displayProblemType; }
+        set {
+          if (displayProblemType == value) return;
+          displayProblemType = value;
+          OnPropertyChanged("DisplayProblemType");
+        }
+      }
+      private string problemType;
+      public string ProblemType {
+        get { return problemType; }
+        set {
+          if (problemType == value) return;
+          problemType = value;
+          OnPropertyChanged("ProblemType");
+        }
+      }
+      private bool displayProblemName;
+      public bool DisplayProblemName {
+        get { return displayProblemName; }
+        set {
+          if (displayProblemName == value) return;
+          displayProblemName = value;
+          OnPropertyChanged("DisplayProblemName");
+        }
+      }
+      private string problemName;
+      public string ProblemName {
+        get { return problemName; }
+        set {
+          if (problemName == value) return;
+          problemName = value;
+          OnPropertyChanged("ProblemName");
+        }
+      }
+      private bool displayEvaluator;
+      public bool DisplayEvaluator {
+        get { return displayEvaluator; }
+        set {
+          if (displayEvaluator == value) return;
+          displayEvaluator = value;
+          OnPropertyChanged("DisplayEvaluator");
+        }
+      }
+      private string evaluator;
+      public string Evaluator {
+        get { return evaluator; }
+        set {
+          if (evaluator == value) return;
+          evaluator = value;
+          OnPropertyChanged("Evaluator");
+        }
+      }
+      private bool displayMaximization;
+      public bool DisplayMaximization {
+        get { return displayMaximization; }
+        set {
+          if (displayMaximization == value) return;
+          displayMaximization = value;
+          OnPropertyChanged("DisplayMaximization");
+        }
+      }
+      private bool? maximization;
+      public bool? Maximization {
+        get { return maximization; }
+        set {
+          if (maximization == value) return;
+          maximization = value;
+          OnPropertyChanged("Maximization");
+        }
+      }
+      private double bestKnownQuality;
+      public double BestKnownQuality {
+        get { return bestKnownQuality; }
+        set {
+          if (bestKnownQuality == value) return;
+          bestKnownQuality = value;
+          OnPropertyChanged("BestKnownQuality");
+        }
+      }
+
+      public bool Match(IRun run) {
+        return matchAll ||
+               (GetStringValueOrEmpty(run, "Problem Type") == ProblemType
+               && GetStringValueOrEmpty(run, "Problem Name") == ProblemName
+               && GetStringValueOrEmpty(run, "Evaluator") == Evaluator
+               && GetBoolValueOrEmpty(run, "Maximization") == Maximization);
+      }
+
+      private double GetDoubleValueOrNaN(IRun run, string key) {
+        IItem param;
+        if (run.Parameters.TryGetValue(key, out param)) {
+          var dv = param as DoubleValue;
+          return dv != null ? dv.Value : double.NaN;
+        }
+        return double.NaN;
+      }
+
+      private string GetStringValueOrEmpty(IRun run, string key) {
+        IItem param;
+        if (run.Parameters.TryGetValue(key, out param)) {
+          var sv = param as StringValue;
+          return sv != null ? sv.Value : string.Empty;
+        }
+        return string.Empty;
+      }
+
+      private bool? GetBoolValueOrEmpty(IRun run, string key) {
+        IItem param;
+        if (run.Parameters.TryGetValue(key, out param)) {
+          var bv = param as BoolValue;
+          if (bv != null) return bv.Value;
+        }
+        return null;
+      }
+
+      public override bool Equals(object obj) {
+        var other = obj as ProblemInstance;
+        if (other == null) return false;
+        return ProblemType == other.ProblemType
+               && ProblemName == other.ProblemName
+               && Evaluator == other.Evaluator
+               && Maximization == other.Maximization;
+      }
+
+      public override int GetHashCode() {
+        return ProblemType.GetHashCode() ^ ProblemName.GetHashCode() ^ Evaluator.GetHashCode() ^ Maximization.GetHashCode();
+      }
+
+      public override string ToString() {
+        return string.Join("  --  ", new[] {
+          (DisplayProblemType ? ProblemType : string.Empty),
+          (DisplayProblemName ? ProblemName : string.Empty),
+          (DisplayEvaluator ? Evaluator : string.Empty),
+          (DisplayMaximization && Maximization.HasValue ? (Maximization.Value ? "MAX" : "MIN") : string.Empty),
+          !double.IsNaN(BestKnownQuality) ? BestKnownQuality.ToString(CultureInfo.CurrentCulture.NumberFormat) : string.Empty }.Where(x => !string.IsNullOrEmpty(x)));
+      }
+
+      public event PropertyChangedEventHandler PropertyChanged;
+      protected virtual void OnPropertyChanged(string propertyName = null) {
+        var handler = PropertyChanged;
+        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
+      }
+    }
+
+    private class CostComparer : Comparer<ConvergenceGraphPoint> {
+      public override int Compare(ConvergenceGraphPoint x, ConvergenceGraphPoint y) {
+        return x.Runlength.CompareTo(y.Runlength);
+      }
+    }
+
+    private class TargetComparer : Comparer<ConvergenceGraphPoint> {
+      public bool Maximization { get; private set; }
+      public TargetComparer(bool maximization) {
+        Maximization = maximization;
+      }
+
+      public override int Compare(ConvergenceGraphPoint x, ConvergenceGraphPoint y) {
+        return Maximization ? x.Quality.CompareTo(y.Quality) : y.Quality.CompareTo(x.Quality);
+      }
+    }
+
+    private class ConvergenceGraph : IEnumerable<ConvergenceGraphPoint> {
+      private List<ConvergenceGraphPoint> data;
+      private bool maximization;
+      private string xAxisLabel;
+
+      public string XAxisName { get { return xAxisLabel; } }
+
+      public int Points {
+        get { return data.Count; }
+      }
+
+      public double TotalRunlength {
+        get { return data.Last().Runlength; }
+      }
+
+      public double BestQuality {
+        get { return data.Last().Quality; }
+      }
+
+      public double QualityAt(double runlength) {
+        var point = data.SkipWhile(x => x.Runlength < runlength).FirstOrDefault();
+        if (point == null) return double.NaN;
+        return point.Quality;
+      }
+
+      public double RunlengthFor(double quality) {
+        var point = (maximization ? data.SkipWhile(x => x.Quality < quality) : data.SkipWhile(x => x.Quality > quality)).FirstOrDefault();
+        if (point == null) return double.NaN;
+        return point.Runlength;
+      }
+
+      public ConvergenceGraphPoint this[int point] {
+        get { return data[point]; }
+      }
+
+      public ConvergenceGraph(IndexedDataTable<double> table, bool maximization) {
+        data = table.Rows.First().Values.Select(x => new ConvergenceGraphPoint() { Runlength = x.Item1, Quality = x.Item2 }).ToList();
+        xAxisLabel = table.VisualProperties.XAxisTitle;
+        this.maximization = maximization;
+      }
+
+      public IEnumerator<ConvergenceGraphPoint> GetEnumerator() {
+        return data.GetEnumerator();
+      }
+
+      IEnumerator IEnumerable.GetEnumerator() {
+        return data.GetEnumerator();
+      }
+
+      public int BinarySearch(ConvergenceGraphPoint item, IComparer<ConvergenceGraphPoint> comparer) {
+        return data.BinarySearch(item, comparer);
+      }
+
+      public int BinarySearch(int index, int count, ConvergenceGraphPoint point, IComparer<ConvergenceGraphPoint> comparer) {
+        return data.BinarySearch(index, count, point, comparer);
+      }
+
+      public IEnumerable<Tuple<double, double>> ToTuples() {
+        return data.Select(x => Tuple.Create(x.Runlength, x.Quality));
+      }
+    }
+
+    private class ConvergenceGraphPoint {
+      public double Runlength { get; set; }
+      public double Quality { get; set; }
+
+      public ConvergenceGraphPoint() {
+
+      }
+      public ConvergenceGraphPoint(double runlength, double quality) {
+        Runlength = runlength;
+        Quality = quality;
+      }
+    }
+    #endregion
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionSimpleRLDView.resx
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionSimpleRLDView.resx	(revision 16733)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionSimpleRLDView.resx	(revision 16733)
@@ -0,0 +1,129 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>147, 17</value>
+  </metadata>
+  <metadata name="errorProvider.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </metadata>
+  <metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>147, 17</value>
+  </metadata>
+</root>
