Changeset 15125


Ignore:
Timestamp:
07/06/17 01:30:45 (4 months ago)
Author:
abeham
Message:

#2634:

  • Improved performance slightly by using binary instead of linear search
  • Fixed target value ECDFs by removing aggregate option (only drawn for each budget separately)
  • Added utility class for calculating ECDFs in HeuristicLab.Common
  • Added option to hide labels
  • Improved add result methods
Location:
trunk/sources
Files:
3 added
1 deleted
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.Common/3.3/HeuristicLab.Common-3.3.csproj

    r12292 r15125  
    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" />
  • trunk/sources/HeuristicLab.Common/3.3/Point2D.cs

    r14860 r15125  
    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;
  • trunk/sources/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.Designer.cs

    r14652 r15125  
    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();
     
    6666      this.relativeOrAbsoluteComboBox = new System.Windows.Forms.ComboBox();
    6767      this.targetChart = new HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart();
     68      this.showLabelsCheckBox = new System.Windows.Forms.CheckBox();
    6869      this.markerCheckBox = new System.Windows.Forms.CheckBox();
    6970      this.boundShadingCheckBox = new System.Windows.Forms.CheckBox();
     
    7172      this.byCostViewHost = new HeuristicLab.MainForm.WindowsForms.ViewHost();
    7273      this.budgetLogScalingCheckBox = new System.Windows.Forms.CheckBox();
    73       this.aggregateBudgetsCheckBox = new System.Windows.Forms.CheckBox();
    7474      this.generateBudgetsButton = new System.Windows.Forms.Button();
    7575      this.byTableTabPage = new System.Windows.Forms.TabPage();
     
    202202      this.budgetsTextBox.Location = new System.Drawing.Point(59, 8);
    203203      this.budgetsTextBox.Name = "budgetsTextBox";
    204       this.budgetsTextBox.Size = new System.Drawing.Size(309, 20);
     204      this.budgetsTextBox.Size = new System.Drawing.Size(391, 20);
    205205      this.budgetsTextBox.TabIndex = 6;
    206206      this.budgetsTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.budgetsTextBox_Validating);
     
    249249      this.byTargetTabPage.Controls.Add(this.relativeOrAbsoluteComboBox);
    250250      this.byTargetTabPage.Controls.Add(this.targetChart);
     251      this.byTargetTabPage.Controls.Add(this.showLabelsCheckBox);
    251252      this.byTargetTabPage.Controls.Add(this.markerCheckBox);
    252253      this.byTargetTabPage.Controls.Add(this.boundShadingCheckBox);
     
    284285            | System.Windows.Forms.AnchorStyles.Left)
    285286            | System.Windows.Forms.AnchorStyles.Right)));
    286       chartArea1.AxisX.IsStartedFromZero = false;
    287       chartArea1.AxisX.MinorGrid.Enabled = true;
    288       chartArea1.AxisX.MinorGrid.LineColor = System.Drawing.Color.WhiteSmoke;
    289       chartArea1.AxisX.MinorGrid.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
    290       chartArea1.AxisY.Maximum = 1D;
    291       chartArea1.AxisY.Minimum = 0D;
    292       chartArea1.AxisY.MinorGrid.Enabled = true;
    293       chartArea1.AxisY.MinorGrid.LineColor = System.Drawing.Color.WhiteSmoke;
    294       chartArea1.AxisY.MinorGrid.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
    295       chartArea1.Name = "ChartArea1";
    296       this.targetChart.ChartAreas.Add(chartArea1);
    297       legend1.Alignment = System.Drawing.StringAlignment.Center;
    298       legend1.Docking = System.Windows.Forms.DataVisualization.Charting.Docking.Top;
    299       legend1.Name = "Legend1";
    300       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);
    301302      this.targetChart.Location = new System.Drawing.Point(6, 34);
    302303      this.targetChart.Name = "targetChart";
     
    308309      this.targetChart.MouseDown += new System.Windows.Forms.MouseEventHandler(this.chart_MouseDown);
    309310      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);
    310325      //
    311326      // markerCheckBox
     
    339354      this.byCostTabPage.Controls.Add(this.byCostViewHost);
    340355      this.byCostTabPage.Controls.Add(this.budgetLogScalingCheckBox);
    341       this.byCostTabPage.Controls.Add(this.aggregateBudgetsCheckBox);
    342356      this.byCostTabPage.Controls.Add(this.generateBudgetsButton);
    343357      this.byCostTabPage.Controls.Add(this.budgetsLabel);
     
    379393      this.budgetLogScalingCheckBox.UseVisualStyleBackColor = true;
    380394      this.budgetLogScalingCheckBox.CheckedChanged += new System.EventHandler(this.logScalingCheckBox_CheckedChanged);
    381       //
    382       // aggregateBudgetsCheckBox
    383       //
    384       this.aggregateBudgetsCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
    385       this.aggregateBudgetsCheckBox.AutoSize = true;
    386       this.aggregateBudgetsCheckBox.Checked = true;
    387       this.aggregateBudgetsCheckBox.CheckState = System.Windows.Forms.CheckState.Checked;
    388       this.aggregateBudgetsCheckBox.Location = new System.Drawing.Point(374, 10);
    389       this.aggregateBudgetsCheckBox.Name = "aggregateBudgetsCheckBox";
    390       this.aggregateBudgetsCheckBox.Size = new System.Drawing.Size(74, 17);
    391       this.aggregateBudgetsCheckBox.TabIndex = 10;
    392       this.aggregateBudgetsCheckBox.Text = "aggregate";
    393       this.aggregateBudgetsCheckBox.UseVisualStyleBackColor = true;
    394       this.aggregateBudgetsCheckBox.CheckedChanged += new System.EventHandler(this.aggregateBudgetsCheckBox_CheckedChanged);
    395395      //
    396396      // generateBudgetsButton
     
    496496    private System.Windows.Forms.TabPage byCostTabPage;
    497497    private System.Windows.Forms.TabPage byTableTabPage;
    498     private System.Windows.Forms.CheckBox aggregateBudgetsCheckBox;
    499498    private System.Windows.Forms.Button generateBudgetsButton;
    500499    private System.Windows.Forms.CheckBox budgetLogScalingCheckBox;
     
    507506    private System.Windows.Forms.CheckBox markerCheckBox;
    508507    private System.Windows.Forms.ComboBox relativeOrAbsoluteComboBox;
     508    private System.Windows.Forms.CheckBox showLabelsCheckBox;
    509509  }
    510510}
  • trunk/sources/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.cs

    r14775 r15125  
    8181    private double[] budgets;
    8282    private bool targetsAreRelative = true;
     83    private bool showLabelsInTargetChart = true;
    8384    private readonly BindingList<ProblemInstance> problems;
    8485
     
    9697      targetChart.ChartAreas[0].CursorX.Interval = 1;
    9798      targetChart.SuppressExceptions = true;
    98       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).") {
    99100        VisualProperties = {
    100           YAxisTitle = "Proportion of unused budgets",
     101          YAxisTitle = "Proportion of runs",
    101102          YAxisMinimumFixedValue = 0,
    102103          YAxisMinimumAuto = false,
     
    284285      addTargetsAsResultButton.Enabled = Content != null && targets != null && dataTableComboBox.SelectedIndex >= 0;
    285286      addBudgetsAsResultButton.Enabled = Content != null && budgets != null && dataTableComboBox.SelectedIndex >= 0;
     287      generateTargetsButton.Enabled = targets != null;
    286288    }
    287289
     
    314316      targetChart.Series.Clear();
    315317      invisibleTargetSeries.Clear();
    316 
     318     
    317319      var table = (string)dataTableComboBox.SelectedItem;
    318320      if (string.IsNullOrEmpty(table)) return;
     
    424426            if (!labelPrinted && row.Points.Count > 0) {
    425427              var point = row.Points.Last();
    426               point.Label = row.Name;
     428              if (showLabelsInTargetChart)
     429                point.Label = row.Name;
    427430              point.MarkerStyle = MarkerStyle.Cross;
    428431              point.MarkerBorderWidth = 1;
     
    456459            if (!labelPrinted) {
    457460              var point = row.Points.Last();
    458               point.Label = row.Name;
     461              if (showLabelsInTargetChart)
     462                point.Label = row.Name;
    459463              point.MarkerStyle = MarkerStyle.Cross;
    460464              point.MarkerBorderWidth = 1;
     
    504508          if (!labelPrinted && row.Points.Count > 0) {
    505509            var point = row.Points.Last();
    506             point.Label = row.Name;
     510            if (showLabelsInTargetChart)
     511              point.Label = row.Name;
    507512            point.MarkerStyle = MarkerStyle.Cross;
    508513            point.MarkerBorderWidth = 1;
     
    514519        if (!labelPrinted) {
    515520          var point = row.Points.Last();
    516           point.Label = row.Name;
     521          if (showLabelsInTargetChart)
     522            point.Label = row.Name;
    517523          point.MarkerStyle = MarkerStyle.Cross;
    518524          point.MarkerBorderWidth = 1;
     
    572578    private void GenerateDefaultTargets() {
    573579      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 };
    574       suppressTargetsEvents = true;
    575       targetsTextBox.Text = string.Join("% ; ", targets.Select(x => x * 100)) + "%";
    576       suppressTargetsEvents = false;
     580      SynchronizeTargetTextBox();
    577581    }
    578582
    579583    private Tuple<bool, double> GetEffortToHitTarget(
    580         IEnumerable<Tuple<double, double>> convergenceGraph,
     584        ObservableList<Tuple<double, double>> convergenceGraph,
    581585        double absTarget, bool maximization) {
    582       var hit = false;
    583       var effort = double.NaN;
    584       foreach (var dent in convergenceGraph) {
    585         effort = dent.Item1;
    586         hit = maximization && dent.Item2 >= absTarget || !maximization && dent.Item2 <= absTarget;
    587         if (hit) break;
    588       }
    589       if (double.IsNaN(effort)) throw new ArgumentException("Convergence graph is empty.", "convergenceGraph");
    590       return Tuple.Create(hit, effort);
     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      }
    591598    }
    592599
    593600    private void UpdateErtTables(List<AlgorithmInstance> algorithmInstances) {
    594601      ertTableView.Content = null;
    595       var columns = 1 + targets.Length + 1;
    596       var matrix = new string[algorithmInstances.Count * algorithmInstances.Max(x => x.GetNumberOfProblemInstances()) + algorithmInstances.Max(x => x.GetNumberOfProblemInstances()), 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();
    597608      var rowCount = 0;
    598609
     
    604615      foreach (var problem in problems) {
    605616        var max = problem.IsMaximization();
    606         matrix[rowCount, 0] = problem.ToString();
     617        rowNames.Add(problem.ToString());
    607618        var absTargets = GetAbsoluteTargetsWorstToBest(problem);
    608         for (var i = 0; i < absTargets.Length; i++) {
    609           matrix[rowCount, i + 1] = absTargets[i].ToString(CultureInfo.CurrentCulture.NumberFormat);
    610         }
    611         matrix[rowCount, columns - 1] = "#succ";
     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        }
    612625        rowCount++;
    613626
    614627        foreach (var alg in algorithmInstances) {
    615           matrix[rowCount, 0] = alg.Name;
     628          rowNames.Add(alg.Name);
    616629          var runs = alg.GetRuns(problem).ToList();
    617630          if (runs.Count == 0) {
     
    623636          for (var i = 0; i < absTargets.Length; i++) {
    624637            result = ExpectedRuntimeHelper.CalculateErt(runs, tableName, absTargets[i], max);
    625             matrix[rowCount, i + 1] = result.ToString();
     638            matrix[rowCount, i] = result.ToString();
    626639          }
    627640          matrix[rowCount, columns - 1] = targets.Length > 0 ? result.SuccessfulRuns + "/" + result.TotalRuns : "-";
     
    629642        }
    630643      }
    631       ertTableView.Content = new StringMatrix(matrix);
     644      matrix.RowNames = rowNames;
     645      ertTableView.Content = matrix;
    632646      ertTableView.DataGridView.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
    633647    }
     
    658672            var resultsTable = (IndexedDataTable<double>)run.Results[table];
    659673
    660             if (aggregateBudgetsCheckBox.Checked) {
    661               CalculateHitsForAllBudgets(hits, resultsTable.Rows.First(), alg.GetNumberOfProblemInstances(), problem, alg.Name, alg.GetNumberOfRuns(problem));
    662             } else {
    663               CalculateHitsForEachBudget(hits, resultsTable.Rows.First(), alg.GetNumberOfProblemInstances(), problem, alg.Name, alg.GetNumberOfRuns(problem));
    664             }
     674            CalculateHitsForEachBudget(hits, resultsTable.Rows.First(), problem, alg.Name);
    665675          }
    666676        }
     
    678688
    679689          var total = 0.0;
     690          var count = list.Value.Count;
    680691          foreach (var h in list.Value) {
    681692            total += h.Value;
    682             row.Values.Add(Tuple.Create(h.Key, total));
     693            row.Values.Add(Tuple.Create(h.Key, total / (double)count));
    683694          }
    684695
     
    697708      var min = runs.Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Select(y => y.Item1).Min()).Min();
    698709      var max = runs.Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Select(y => y.Item1).Max()).Max();
    699       var points = 20;
     710      var points = 3;
    700711      budgets = Enumerable.Range(1, points).Select(x => min + (x / (double)points) * (max - min)).ToArray();
    701712      suppressBudgetsEvents = true;
     
    704715    }
    705716
    706     private void CalculateHitsForEachBudget(Dictionary<string, SortedList<double, double>> hits, IndexedDataRow<double> row, int groupCount, ProblemInstance problem, string groupName, int problemCount) {
     717    private void CalculateHitsForEachBudget(Dictionary<string, SortedList<double, double>> hits, IndexedDataRow<double> row, ProblemInstance problem, string groupName) {
    707718      var max = problem.IsMaximization();
     719      var prevIndex = 0;
    708720      foreach (var b in budgets) {
    709721        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        }
    710727        if (!hits.ContainsKey(key)) hits.Add(key, new SortedList<double, double>());
    711         Tuple<double, double> prev = null;
    712         foreach (var v in row.Values) {
    713           if (v.Item1 >= b) {
    714             // the budget may be too low to achieve any target
    715             if (prev == null && v.Item1 != b) break;
    716             var tgt = ((prev == null || v.Item1 == b) ? v.Item2 : prev.Item2);
    717             var relTgt = CalculateRelativeDifference(max, problem.BestKnownQuality, tgt) + 1;
    718             if (hits[key].ContainsKey(relTgt))
    719               hits[key][relTgt] += 1.0 / (groupCount * problemCount);
    720             else hits[key][relTgt] = 1.0 / (groupCount * problemCount);
    721             break;
    722           }
    723           prev = v;
    724         }
    725         if (hits[key].Count == 0) hits.Remove(key);
    726       }
    727     }
    728 
    729     private void CalculateHitsForAllBudgets(Dictionary<string, SortedList<double, double>> hits, IndexedDataRow<double> row, int groupCount, ProblemInstance problem, string groupName, int problemCount) {
    730       var values = row.Values;
    731       if (!hits.ContainsKey(groupName)) hits.Add(groupName, new SortedList<double, double>());
    732 
    733       var i = 0;
    734       var j = 0;
    735       Tuple<double, double> prev = null;
    736       var max = problem.IsMaximization();
    737       while (i < budgets.Length && j < values.Count) {
    738         var current = values[j];
    739         if (current.Item1 >= budgets[i]) {
    740           if (prev != null || current.Item1 == budgets[i]) {
    741             var tgt = (prev == null || current.Item1 == budgets[i]) ? current.Item2 : prev.Item2;
    742             var relTgt = CalculateRelativeDifference(max, problem.BestKnownQuality, tgt) + 1;
    743             if (!hits[groupName].ContainsKey(relTgt)) hits[groupName][relTgt] = 0;
    744             hits[groupName][relTgt] += 1.0 / (groupCount * problemCount * budgets.Length);
    745           }
    746           i++;
    747         } else {
    748           j++;
    749           prev = current;
    750         }
    751       }
    752       var lastTgt = values.Last().Item2;
    753       var lastRelTgt = CalculateRelativeDifference(max, problem.BestKnownQuality, lastTgt) + 1;
    754       if (i < budgets.Length && !hits[groupName].ContainsKey(lastRelTgt)) hits[groupName][lastRelTgt] = 0;
    755       while (i < budgets.Length) {
    756         hits[groupName][lastRelTgt] += 1.0 / (groupCount * problemCount * budgets.Length);
    757         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;
    758734      }
    759735    }
     
    762738    private void UpdateCaption() {
    763739      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      }
    764752    }
    765753
     
    814802      errorProvider.SetError(targetsTextBox, null);
    815803      targets = targetsAreRelative ? targetList.Select(x => (double)x).OrderByDescending(x => x).ToArray() : targetList.Select(x => (double)x).ToArray();
    816       suppressTargetsEvents = true;
    817       try {
    818         if (targetsAreRelative)
    819           targetsTextBox.Text = string.Join("% ; ", targets.Select(x => x * 100)) + "%";
    820         else targetsTextBox.Text = string.Join(" ; ", targets);
    821       } finally { suppressTargetsEvents = false; }
    822 
     804
     805      SynchronizeTargetTextBox();
    823806      UpdateResultsByTarget();
    824807      SetEnabledStateOfControls();
     
    848831      }
    849832      targetsAreRelative = (string)relativeOrAbsoluteComboBox.SelectedItem == "relative";
    850       SuspendRepaint();
    851       suppressTargetsEvents = true;
     833      SynchronizeTargetTextBox();
     834
    852835      try {
    853         if (targetsAreRelative)
    854           targetsTextBox.Text = string.Join("% ; ", targets.Select(x => x * 100)) + "%";
    855         else targetsTextBox.Text = string.Join(" ; ", targets);
    856 
     836        SuspendRepaint();
    857837        UpdateResultsByTarget();
    858       } finally { suppressTargetsEvents = false; ResumeRepaint(true); }
     838      } finally { ResumeRepaint(true); }
    859839    }
    860840
    861841    private void generateTargetsButton_Click(object sender, EventArgs e) {
    862       decimal max = 1, min = 0, count = 10;
    863       if (targets != null) {
    864         max = (decimal)targets.Max();
    865         min = (decimal)targets.Min();
    866         count = targets.Length;
    867       } else if (Content.Count > 0 && dataTableComboBox.SelectedIndex >= 0) {
    868         var table = (string)dataTableComboBox.SelectedItem;
    869         max = (decimal)Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Max(y => y.Item2)).Max();
    870         min = (decimal)Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Min(y => y.Item2)).Min();
    871         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;
    872850      }
    873851      using (var dialog = new DefineArithmeticProgressionDialog(false, min, max, (max - min) / count)) {
    874852        if (dialog.ShowDialog() == DialogResult.OK) {
    875853          if (dialog.Values.Any()) {
    876             targets = dialog.Values.Select(x => (double)x).ToArray();
    877             suppressTargetsEvents = true;
    878             if (targetsAreRelative)
    879               targetsTextBox.Text = string.Join("% ; ", targets);
    880             else targetsTextBox.Text = string.Join(" ; ", targets);
    881             suppressTargetsEvents = false;
    882 
     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();
    883859            UpdateResultsByTarget();
    884860            SetEnabledStateOfControls();
     
    896872        var resultsTable = (IndexedDataTable<double>)run.Results[table];
    897873        var values = resultsTable.Rows.First().Values;
    898         var i = 0;
    899         var j = 0;
    900874        var pd = new ProblemInstance(run);
     875        pd = problems.Single(x => x.Equals(pd));
    901876        var max = pd.IsMaximization();
    902         var absTargets = GetAbsoluteTargetsWorstToBest(problems.Single(x => x.Equals(pd)));
    903         while (i < absTargets.Length && j < values.Count) {
    904           var target = absTargets[i];
    905           var current = values[j];
    906           if (max && current.Item2 >= target || !max && current.Item2 <= target) {
    907             run.Results[table + ".Target" + target] = new DoubleValue(current.Item1);
    908             i++;
    909           } else {
    910             j++;
    911           }
     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;
    912890        }
    913891      }
     
    915893
    916894    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;
    917903      SuspendRepaint();
    918904      try {
     
    931917        double b;
    932918        if (!double.TryParse(ts, out b)) {
    933           errorProvider.SetError(budgetsTextBox, "Not all targets can be parsed: " + ts);
     919          errorProvider.SetError(budgetsTextBox, "Not all budgets can be parsed: " + ts);
    934920          e.Cancel = true;
    935921          return;
     
    938924      }
    939925      if (budgetList.Count == 0) {
    940         errorProvider.SetError(budgetsTextBox, "Give at least one target value!");
     926        errorProvider.SetError(budgetsTextBox, "Give at least one budget value!");
    941927        e.Cancel = true;
    942928        return;
     
    944930      e.Cancel = false;
    945931      errorProvider.SetError(budgetsTextBox, null);
    946       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; }
    947937      UpdateResultsByCost();
    948938      SetEnabledStateOfControls();
    949     }
    950 
    951     private void aggregateBudgetsCheckBox_CheckedChanged(object sender, EventArgs e) {
    952       SuspendRepaint();
    953       try {
    954         UpdateResultsByCost();
    955       } finally { ResumeRepaint(true); }
    956939    }
    957940
     
    966949        min = (decimal)Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Min(y => y.Item1)).Min();
    967950        max = (decimal)Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Max(y => y.Item1)).Max();
    968         count = 6;
     951        count = 3;
    969952      }
    970953      using (var dialog = new DefineArithmeticProgressionDialog(false, min, max, (max - min) / count)) {
     
    973956            budgets = dialog.Values.OrderBy(x => x).Select(x => (double)x).ToArray();
    974957
    975             suppressBudgetsEvents = true;
    976             budgetsTextBox.Text = string.Join(" ; ", budgets);
    977             suppressBudgetsEvents = false;
     958            try {
     959              suppressBudgetsEvents = true;
     960              budgetsTextBox.Text = string.Join(" ; ", budgets);
     961            } finally { suppressBudgetsEvents = false; }
    978962
    979963            UpdateResultsByCost();
     
    986970    private void addBudgetsAsResultButton_Click(object sender, EventArgs e) {
    987971      var table = (string)dataTableComboBox.SelectedItem;
    988       var budgetStrings = budgetsTextBox.Text.Split(new[] { ';', '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries);
    989       if (budgetStrings.Length == 0) {
    990         MessageBox.Show("Define a number of budgets.");
    991         return;
    992       }
    993       var budgetList = new List<double>();
    994       foreach (var bs in budgetStrings) {
    995         double v;
    996         if (!double.TryParse(bs, out v)) {
    997           MessageBox.Show("Budgets must be a valid number: " + bs);
    998           return;
    999         }
    1000         budgetList.Add(v);
    1001       }
    1002       budgetList.Sort();
    1003972
    1004973      foreach (var run in Content) {
     
    1006975        var resultsTable = (IndexedDataTable<double>)run.Results[table];
    1007976        var values = resultsTable.Rows.First().Values;
    1008         var i = 0;
    1009         var j = 0;
    1010         Tuple<double, double> prev = null;
    1011         while (i < budgetList.Count && j < values.Count) {
    1012           var current = values[j];
    1013           if (current.Item1 >= budgetList[i]) {
    1014             if (prev != null || current.Item1 == budgetList[i]) {
    1015               var tgt = (prev == null || current.Item1 == budgetList[i]) ? current.Item2 : prev.Item2;
    1016               run.Results[table + ".Cost" + budgetList[i]] = new DoubleValue(tgt);
    1017             }
    1018             i++;
    1019           } else {
    1020             j++;
    1021             prev = current;
    1022           }
     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;
    1023991        }
    1024992      }
     
    10801048        else pd.BestKnownQuality = double.NaN;
    10811049      }
    1082       //problemComboBox.ResetBindings();
    10831050    }
    10841051    #endregion
    10851052
    10861053    private void ConfigureSeries(Series series) {
    1087       series.SmartLabelStyle.Enabled = true;
     1054      series.SmartLabelStyle.Enabled = showLabelsInTargetChart;
    10881055      series.SmartLabelStyle.AllowOutsidePlotArea = LabelOutsidePlotAreaStyle.No;
    10891056      series.SmartLabelStyle.CalloutLineAnchorCapStyle = LineAnchorCapStyle.None;
     
    14181385      }
    14191386    }
     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; }
     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);
     1402      }
     1403    }
    14201404  }
    14211405}
Note: See TracChangeset for help on using the changeset viewer.