Index: unk/sources/HeuristicLab.Common/3.3/EnumerableStatisticExtensions.cs
===================================================================
--- /trunk/sources/HeuristicLab.Common/3.3/EnumerableStatisticExtensions.cs (revision 15124)
+++ (revision )
@@ -1,239 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2016 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 .
- */
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics.Contracts;
-using System.Linq;
-
-namespace HeuristicLab.Common {
- public static class EnumerableStatisticExtensions {
- ///
- /// Calculates the median element of the enumeration.
- ///
- ///
- ///
- public static double Median(this IEnumerable values) {
- // See unit tests for comparison with naive implementation
- return Quantile(values, 0.5);
- }
-
- ///
- /// Calculates the alpha-quantile element of the enumeration.
- ///
- ///
- ///
- public static double Quantile(this IEnumerable values, double alpha) {
- // See unit tests for comparison with naive implementation
- double[] valuesArr = values.ToArray();
- int n = valuesArr.Length;
- if (n == 0) throw new InvalidOperationException("Enumeration contains no elements.");
-
- // "When N is even, statistics books define the median as the arithmetic mean of the elements k = N/2
- // and k = N/2 + 1 (that is, N/2 from the bottom and N/2 from the top).
- // If you accept such pedantry, you must perform two separate selections to find these elements."
-
- // return the element at Math.Ceiling (if n*alpha is fractional) or the average of two elements if n*alpha is integer.
- var pos = n * alpha;
- Contract.Assert(pos >= 0);
- Contract.Assert(pos < n);
- bool isInteger = Math.Round(pos).IsAlmost(pos);
- if (isInteger) {
- return 0.5 * (Select((int)pos - 1, valuesArr) + Select((int)pos, valuesArr));
- } else {
- return Select((int)Math.Ceiling(pos) - 1, valuesArr);
- }
- }
-
- // Numerical Recipes in C++, §8.5 Selecting the Mth Largest, O(n)
- // Given k in [0..n-1] returns an array value from array arr[0..n-1] such that k array values are
- // less than or equal to the one returned. The input array will be rearranged to have this value in
- // location arr[k], with all smaller elements moved to arr[0..k-1] (in arbitrary order) and all
- // larger elements in arr[k+1..n-1] (also in arbitrary order).
- //
- // Could be changed to Select where T is IComparable but in this case is significantly slower for double values
- private static double Select(int k, double[] arr) {
- Contract.Assert(arr.GetLowerBound(0) == 0);
- Contract.Assert(k >= 0 && k < arr.Length);
- int i, ir, j, l, mid, n = arr.Length;
- double a;
- l = 0;
- ir = n - 1;
- for (; ; ) {
- if (ir <= l + 1) {
- // Active partition contains 1 or 2 elements.
- if (ir == l + 1 && arr[ir] < arr[l]) {
- // if (ir == l + 1 && arr[ir].CompareTo(arr[l]) < 0) {
- // Case of 2 elements.
- // SWAP(arr[l], arr[ir]);
- double temp = arr[l];
- arr[l] = arr[ir];
- arr[ir] = temp;
- }
- return arr[k];
- } else {
- mid = (l + ir) >> 1; // Choose median of left, center, and right elements
- {
- // SWAP(arr[mid], arr[l + 1]); // as partitioning element a. Also
- double temp = arr[mid];
- arr[mid] = arr[l + 1];
- arr[l + 1] = temp;
- }
-
- if (arr[l] > arr[ir]) {
- // if (arr[l].CompareTo(arr[ir]) > 0) { // rearrange so that arr[l] arr[ir] <= arr[l+1],
- // SWAP(arr[l], arr[ir]); . arr[ir] >= arr[l+1]
- double temp = arr[l];
- arr[l] = arr[ir];
- arr[ir] = temp;
- }
-
- if (arr[l + 1] > arr[ir]) {
- // if (arr[l + 1].CompareTo(arr[ir]) > 0) {
- // SWAP(arr[l + 1], arr[ir]);
- double temp = arr[l + 1];
- arr[l + 1] = arr[ir];
- arr[ir] = temp;
- }
- if (arr[l] > arr[l + 1]) {
- //if (arr[l].CompareTo(arr[l + 1]) > 0) {
- // SWAP(arr[l], arr[l + 1]);
- double temp = arr[l];
- arr[l] = arr[l + 1];
- arr[l + 1] = temp;
-
- }
- i = l + 1; // Initialize pointers for partitioning.
- j = ir;
- a = arr[l + 1]; // Partitioning element.
- for (; ; ) { // Beginning of innermost loop.
- do i++; while (arr[i] < a /* arr[i].CompareTo(a) < 0 */); // Scan up to find element > a.
- do j--; while (arr[j] > a /* arr[j].CompareTo(a) > 0 */); // Scan down to find element < a.
- if (j < i) break; // Pointers crossed. Partitioning complete.
- {
- // SWAP(arr[i], arr[j]);
- double temp = arr[i];
- arr[i] = arr[j];
- arr[j] = temp;
- }
- } // End of innermost loop.
- arr[l + 1] = arr[j]; // Insert partitioning element.
- arr[j] = a;
- if (j >= k) ir = j - 1; // Keep active the partition that contains the
- if (j <= k) l = i; // kth element.
- }
- }
- }
-
- ///
- /// Calculates the range (max - min) of the enumeration.
- ///
- ///
- ///
- public static double Range(this IEnumerable values) {
- double min = double.PositiveInfinity;
- double max = double.NegativeInfinity;
- int i = 0;
- foreach (var e in values) {
- if (min > e) min = e;
- if (max < e) max = e;
- i++;
- }
- if (i < 1) throw new ArgumentException("The enumerable must contain at least two elements", "values");
- return max - min;
- }
-
-
- ///
- /// Calculates the sample standard deviation of values.
- ///
- ///
- ///
- public static double StandardDeviation(this IEnumerable values) {
- return Math.Sqrt(Variance(values));
- }
-
- ///
- /// Calculates the population standard deviation of values.
- ///
- ///
- ///
- public static double StandardDeviationPop(this IEnumerable values) {
- return Math.Sqrt(VariancePop(values));
- }
-
- ///
- /// Calculates the sample variance of values. (sum (x - x_mean)² / (n-1))
- ///
- ///
- ///
- public static double Variance(this IEnumerable values) {
- return Variance(values, true);
- }
-
- ///
- /// Calculates the population variance of values. (sum (x - x_mean)² / n)
- ///
- ///
- ///
- public static double VariancePop(this IEnumerable values) {
- return Variance(values, false);
- }
-
- private static double Variance(IEnumerable values, bool sampleVariance) {
- int m_n = 0;
- double m_oldM = 0.0;
- double m_newM = 0.0;
- double m_oldS = 0.0;
- double m_newS = 0.0;
- foreach (double x in values) {
- m_n++;
- if (m_n == 1) {
- m_oldM = m_newM = x;
- m_oldS = 0.0;
- } else {
- m_newM = m_oldM + (x - m_oldM) / m_n;
- m_newS = m_oldS + (x - m_oldM) * (x - m_newM);
-
- // set up for next iteration
- m_oldM = m_newM;
- m_oldS = m_newS;
- }
- }
-
- if (m_n == 0) return double.NaN;
- if (m_n == 1) return 0.0;
-
- if (sampleVariance) return m_newS / (m_n - 1);
- else return m_newS / m_n;
- }
-
- public static IEnumerable LimitToRange(this IEnumerable values, double min, double max) {
- if (min > max) throw new ArgumentException(string.Format("Minimum {0} is larger than maximum {1}.", min, max));
- foreach (var x in values) {
- if (double.IsNaN(x)) yield return (max + min) / 2.0;
- else if (x < min) yield return min;
- else if (x > max) yield return max;
- else yield return x;
- }
- }
- }
-}
Index: /trunk/sources/HeuristicLab.Common/3.3/HeuristicLab.Common-3.3.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Common/3.3/HeuristicLab.Common-3.3.csproj (revision 15124)
+++ /trunk/sources/HeuristicLab.Common/3.3/HeuristicLab.Common-3.3.csproj (revision 15125)
@@ -131,4 +131,5 @@
+
@@ -139,5 +140,5 @@
-
+
Index: /trunk/sources/HeuristicLab.Common/3.3/Point2D.cs
===================================================================
--- /trunk/sources/HeuristicLab.Common/3.3/Point2D.cs (revision 15124)
+++ /trunk/sources/HeuristicLab.Common/3.3/Point2D.cs (revision 15125)
@@ -54,4 +54,8 @@
}
+ public static Point2D Create(T x, T y, object tag = null) {
+ return new Point2D(x, y, tag);
+ }
+
public static bool operator ==(Point2D left, Point2D right) {
return left.x.Equals(right.x) && left.y.Equals(right.y) && left.tag == right.tag;
Index: /trunk/sources/HeuristicLab.Common/3.3/Statistics/EmpiricalCumulativeDistributionFunction.cs
===================================================================
--- /trunk/sources/HeuristicLab.Common/3.3/Statistics/EmpiricalCumulativeDistributionFunction.cs (revision 15125)
+++ /trunk/sources/HeuristicLab.Common/3.3/Statistics/EmpiricalCumulativeDistributionFunction.cs (revision 15125)
@@ -0,0 +1,130 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 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 .
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.Common {
+ public class EmpiricalCumulativeDistributionFunction {
+ private static readonly AbscissaComparer abscissaComparer = new AbscissaComparer();
+ private static readonly OrdinateComparer ordinateComparer = new OrdinateComparer();
+
+ private List> ecdf;
+ public IEnumerable> SupportingPoints {
+ get { return ecdf; }
+ }
+
+ public EmpiricalCumulativeDistributionFunction(IList sample) {
+ ecdf = new List>();
+
+ var len = sample.Count;
+ var cumulative = 0;
+ var localcumulative = 0;
+ var prev = double.NaN;
+ foreach (var p in sample.OrderBy(x => x)) {
+ if (double.IsNaN(p) || double.IsInfinity(p)) continue;
+ if (!double.IsNaN(prev) && prev < p) {
+ cumulative += localcumulative;
+ localcumulative = 0;
+ ecdf.Add(Point2D.Create(prev, cumulative / (double)len));
+ }
+ prev = p;
+ localcumulative++;
+ }
+ if (!double.IsNaN(prev)) {
+ cumulative += localcumulative;
+ ecdf.Add(Point2D.Create(prev, cumulative / (double)len));
+ }
+ }
+ public EmpiricalCumulativeDistributionFunction(IEnumerable> ecdf) {
+ this.ecdf = new List>();
+ var prev = Point2D.Empty;
+ foreach (var point in ecdf) {
+ if (point.Y < 0 || point.Y > 1 || double.IsNaN(point.X) || double.IsInfinity(point.X)
+ || point.IsEmpty || (!prev.IsEmpty && (point.X <= prev.X || point.Y <= prev.Y)))
+ throw new ArgumentException("Invalid supporting points of a cumulative distribution function. Must be strictly monotonically increasing in both X and Y with X in R and Y in [0;1].", "ecdf");
+
+ this.ecdf.Add(point);
+ prev = point;
+ }
+ }
+
+ public double Evaluate(double x) {
+ if (ecdf.Count == 0) return double.NaN;
+ if (x < ecdf[0].X) return 0;
+ var last = ecdf[ecdf.Count - 1];
+ if (x >= last.X) return last.Y;
+
+ var index = ecdf.BinarySearch(Point2D.Create(x, 0), abscissaComparer);
+ if (index >= 0) return ecdf[index].Y;
+ return ecdf[~index - 1].Y;
+ }
+
+ public double InterpolateLinear(double x) {
+ if (ecdf.Count == 0) return double.NaN;
+ if (x < ecdf[0].X) return 0;
+ var last = ecdf[ecdf.Count - 1];
+ if (x >= last.X) return last.Y;
+
+ var index = ecdf.BinarySearch(Point2D.Create(x, 0), abscissaComparer);
+ if (index >= 0) return ecdf[index].Y;
+ var prev = ecdf[~index - 1];
+ var next = ecdf[~index];
+ return prev.Y + (next.Y - prev.Y) * ((x - prev.X) / (next.X - prev.X));
+ }
+
+ public double InterpolateNearest(double x) {
+ if (ecdf.Count == 0) return double.NaN;
+ if (x < ecdf[0].X) return 0;
+ var last = ecdf[ecdf.Count - 1];
+ if (x >= last.X) return last.Y;
+
+ var index = ecdf.BinarySearch(Point2D.Create(x, 0), abscissaComparer);
+ if (index >= 0) return ecdf[index].Y;
+ var prev = ecdf[~index - 1];
+ var next = ecdf[~index];
+ if (x - prev.X < next.X - x) return prev.Y;
+ return next.Y;
+ }
+
+ public double Inverse(double y) {
+ if (ecdf.Count == 0) return double.NaN;
+ if (y < 0 || y > 1) throw new ArgumentException("parameter must be in interval [0;1]", "y");
+ if (ecdf[ecdf.Count - 1].Y < y) return double.PositiveInfinity;
+ var index = ecdf.BinarySearch(Point2D.Create(0, y), ordinateComparer);
+ if (index >= 0) return ecdf[index].X;
+ return ecdf[Math.Max(~index - 1, 0)].X;
+ }
+
+ private class AbscissaComparer : Comparer> {
+ public override int Compare(Point2D x, Point2D y) {
+ return x.X.CompareTo(y.X);
+ }
+ }
+
+ private class OrdinateComparer : Comparer> {
+ public override int Compare(Point2D x, Point2D y) {
+ return x.Y.CompareTo(y.Y);
+ }
+ }
+ }
+}
Index: /trunk/sources/HeuristicLab.Common/3.3/Statistics/EnumerableStatisticExtensions.cs
===================================================================
--- /trunk/sources/HeuristicLab.Common/3.3/Statistics/EnumerableStatisticExtensions.cs (revision 15125)
+++ /trunk/sources/HeuristicLab.Common/3.3/Statistics/EnumerableStatisticExtensions.cs (revision 15125)
@@ -0,0 +1,239 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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 .
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Linq;
+
+namespace HeuristicLab.Common {
+ public static class EnumerableStatisticExtensions {
+ ///
+ /// Calculates the median element of the enumeration.
+ ///
+ ///
+ ///
+ public static double Median(this IEnumerable values) {
+ // See unit tests for comparison with naive implementation
+ return Quantile(values, 0.5);
+ }
+
+ ///
+ /// Calculates the alpha-quantile element of the enumeration.
+ ///
+ ///
+ ///
+ public static double Quantile(this IEnumerable values, double alpha) {
+ // See unit tests for comparison with naive implementation
+ double[] valuesArr = values.ToArray();
+ int n = valuesArr.Length;
+ if (n == 0) throw new InvalidOperationException("Enumeration contains no elements.");
+
+ // "When N is even, statistics books define the median as the arithmetic mean of the elements k = N/2
+ // and k = N/2 + 1 (that is, N/2 from the bottom and N/2 from the top).
+ // If you accept such pedantry, you must perform two separate selections to find these elements."
+
+ // return the element at Math.Ceiling (if n*alpha is fractional) or the average of two elements if n*alpha is integer.
+ var pos = n * alpha;
+ Contract.Assert(pos >= 0);
+ Contract.Assert(pos < n);
+ bool isInteger = Math.Round(pos).IsAlmost(pos);
+ if (isInteger) {
+ return 0.5 * (Select((int)pos - 1, valuesArr) + Select((int)pos, valuesArr));
+ } else {
+ return Select((int)Math.Ceiling(pos) - 1, valuesArr);
+ }
+ }
+
+ // Numerical Recipes in C++, §8.5 Selecting the Mth Largest, O(n)
+ // Given k in [0..n-1] returns an array value from array arr[0..n-1] such that k array values are
+ // less than or equal to the one returned. The input array will be rearranged to have this value in
+ // location arr[k], with all smaller elements moved to arr[0..k-1] (in arbitrary order) and all
+ // larger elements in arr[k+1..n-1] (also in arbitrary order).
+ //
+ // Could be changed to Select where T is IComparable but in this case is significantly slower for double values
+ private static double Select(int k, double[] arr) {
+ Contract.Assert(arr.GetLowerBound(0) == 0);
+ Contract.Assert(k >= 0 && k < arr.Length);
+ int i, ir, j, l, mid, n = arr.Length;
+ double a;
+ l = 0;
+ ir = n - 1;
+ for (; ; ) {
+ if (ir <= l + 1) {
+ // Active partition contains 1 or 2 elements.
+ if (ir == l + 1 && arr[ir] < arr[l]) {
+ // if (ir == l + 1 && arr[ir].CompareTo(arr[l]) < 0) {
+ // Case of 2 elements.
+ // SWAP(arr[l], arr[ir]);
+ double temp = arr[l];
+ arr[l] = arr[ir];
+ arr[ir] = temp;
+ }
+ return arr[k];
+ } else {
+ mid = (l + ir) >> 1; // Choose median of left, center, and right elements
+ {
+ // SWAP(arr[mid], arr[l + 1]); // as partitioning element a. Also
+ double temp = arr[mid];
+ arr[mid] = arr[l + 1];
+ arr[l + 1] = temp;
+ }
+
+ if (arr[l] > arr[ir]) {
+ // if (arr[l].CompareTo(arr[ir]) > 0) { // rearrange so that arr[l] arr[ir] <= arr[l+1],
+ // SWAP(arr[l], arr[ir]); . arr[ir] >= arr[l+1]
+ double temp = arr[l];
+ arr[l] = arr[ir];
+ arr[ir] = temp;
+ }
+
+ if (arr[l + 1] > arr[ir]) {
+ // if (arr[l + 1].CompareTo(arr[ir]) > 0) {
+ // SWAP(arr[l + 1], arr[ir]);
+ double temp = arr[l + 1];
+ arr[l + 1] = arr[ir];
+ arr[ir] = temp;
+ }
+ if (arr[l] > arr[l + 1]) {
+ //if (arr[l].CompareTo(arr[l + 1]) > 0) {
+ // SWAP(arr[l], arr[l + 1]);
+ double temp = arr[l];
+ arr[l] = arr[l + 1];
+ arr[l + 1] = temp;
+
+ }
+ i = l + 1; // Initialize pointers for partitioning.
+ j = ir;
+ a = arr[l + 1]; // Partitioning element.
+ for (; ; ) { // Beginning of innermost loop.
+ do i++; while (arr[i] < a /* arr[i].CompareTo(a) < 0 */); // Scan up to find element > a.
+ do j--; while (arr[j] > a /* arr[j].CompareTo(a) > 0 */); // Scan down to find element < a.
+ if (j < i) break; // Pointers crossed. Partitioning complete.
+ {
+ // SWAP(arr[i], arr[j]);
+ double temp = arr[i];
+ arr[i] = arr[j];
+ arr[j] = temp;
+ }
+ } // End of innermost loop.
+ arr[l + 1] = arr[j]; // Insert partitioning element.
+ arr[j] = a;
+ if (j >= k) ir = j - 1; // Keep active the partition that contains the
+ if (j <= k) l = i; // kth element.
+ }
+ }
+ }
+
+ ///
+ /// Calculates the range (max - min) of the enumeration.
+ ///
+ ///
+ ///
+ public static double Range(this IEnumerable values) {
+ double min = double.PositiveInfinity;
+ double max = double.NegativeInfinity;
+ int i = 0;
+ foreach (var e in values) {
+ if (min > e) min = e;
+ if (max < e) max = e;
+ i++;
+ }
+ if (i < 1) throw new ArgumentException("The enumerable must contain at least two elements", "values");
+ return max - min;
+ }
+
+
+ ///
+ /// Calculates the sample standard deviation of values.
+ ///
+ ///
+ ///
+ public static double StandardDeviation(this IEnumerable values) {
+ return Math.Sqrt(Variance(values));
+ }
+
+ ///
+ /// Calculates the population standard deviation of values.
+ ///
+ ///
+ ///
+ public static double StandardDeviationPop(this IEnumerable values) {
+ return Math.Sqrt(VariancePop(values));
+ }
+
+ ///
+ /// Calculates the sample variance of values. (sum (x - x_mean)² / (n-1))
+ ///
+ ///
+ ///
+ public static double Variance(this IEnumerable values) {
+ return Variance(values, true);
+ }
+
+ ///
+ /// Calculates the population variance of values. (sum (x - x_mean)² / n)
+ ///
+ ///
+ ///
+ public static double VariancePop(this IEnumerable values) {
+ return Variance(values, false);
+ }
+
+ private static double Variance(IEnumerable values, bool sampleVariance) {
+ int m_n = 0;
+ double m_oldM = 0.0;
+ double m_newM = 0.0;
+ double m_oldS = 0.0;
+ double m_newS = 0.0;
+ foreach (double x in values) {
+ m_n++;
+ if (m_n == 1) {
+ m_oldM = m_newM = x;
+ m_oldS = 0.0;
+ } else {
+ m_newM = m_oldM + (x - m_oldM) / m_n;
+ m_newS = m_oldS + (x - m_oldM) * (x - m_newM);
+
+ // set up for next iteration
+ m_oldM = m_newM;
+ m_oldS = m_newS;
+ }
+ }
+
+ if (m_n == 0) return double.NaN;
+ if (m_n == 1) return 0.0;
+
+ if (sampleVariance) return m_newS / (m_n - 1);
+ else return m_newS / m_n;
+ }
+
+ public static IEnumerable LimitToRange(this IEnumerable values, double min, double max) {
+ if (min > max) throw new ArgumentException(string.Format("Minimum {0} is larger than maximum {1}.", min, max));
+ foreach (var x in values) {
+ if (double.IsNaN(x)) yield return (max + min) / 2.0;
+ else if (x < min) yield return min;
+ else if (x > max) yield return max;
+ else yield return x;
+ }
+ }
+ }
+}
Index: /trunk/sources/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.Designer.cs (revision 15124)
+++ /trunk/sources/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.Designer.cs (revision 15125)
@@ -45,6 +45,6 @@
private void InitializeComponent() {
this.components = new System.ComponentModel.Container();
- System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
- System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
+ 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();
@@ -66,4 +66,5 @@
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.boundShadingCheckBox = new System.Windows.Forms.CheckBox();
@@ -71,5 +72,4 @@
this.byCostViewHost = new HeuristicLab.MainForm.WindowsForms.ViewHost();
this.budgetLogScalingCheckBox = new System.Windows.Forms.CheckBox();
- this.aggregateBudgetsCheckBox = new System.Windows.Forms.CheckBox();
this.generateBudgetsButton = new System.Windows.Forms.Button();
this.byTableTabPage = new System.Windows.Forms.TabPage();
@@ -202,5 +202,5 @@
this.budgetsTextBox.Location = new System.Drawing.Point(59, 8);
this.budgetsTextBox.Name = "budgetsTextBox";
- this.budgetsTextBox.Size = new System.Drawing.Size(309, 20);
+ this.budgetsTextBox.Size = new System.Drawing.Size(391, 20);
this.budgetsTextBox.TabIndex = 6;
this.budgetsTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.budgetsTextBox_Validating);
@@ -249,4 +249,5 @@
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.boundShadingCheckBox);
@@ -284,19 +285,19 @@
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
- chartArea1.AxisX.IsStartedFromZero = false;
- chartArea1.AxisX.MinorGrid.Enabled = true;
- chartArea1.AxisX.MinorGrid.LineColor = System.Drawing.Color.WhiteSmoke;
- chartArea1.AxisX.MinorGrid.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
- chartArea1.AxisY.Maximum = 1D;
- chartArea1.AxisY.Minimum = 0D;
- chartArea1.AxisY.MinorGrid.Enabled = true;
- chartArea1.AxisY.MinorGrid.LineColor = System.Drawing.Color.WhiteSmoke;
- chartArea1.AxisY.MinorGrid.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
- chartArea1.Name = "ChartArea1";
- this.targetChart.ChartAreas.Add(chartArea1);
- legend1.Alignment = System.Drawing.StringAlignment.Center;
- legend1.Docking = System.Windows.Forms.DataVisualization.Charting.Docking.Top;
- legend1.Name = "Legend1";
- this.targetChart.Legends.Add(legend1);
+ 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";
@@ -308,4 +309,18 @@
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(329, 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
@@ -339,5 +354,4 @@
this.byCostTabPage.Controls.Add(this.byCostViewHost);
this.byCostTabPage.Controls.Add(this.budgetLogScalingCheckBox);
- this.byCostTabPage.Controls.Add(this.aggregateBudgetsCheckBox);
this.byCostTabPage.Controls.Add(this.generateBudgetsButton);
this.byCostTabPage.Controls.Add(this.budgetsLabel);
@@ -379,18 +393,4 @@
this.budgetLogScalingCheckBox.UseVisualStyleBackColor = true;
this.budgetLogScalingCheckBox.CheckedChanged += new System.EventHandler(this.logScalingCheckBox_CheckedChanged);
- //
- // aggregateBudgetsCheckBox
- //
- this.aggregateBudgetsCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.aggregateBudgetsCheckBox.AutoSize = true;
- this.aggregateBudgetsCheckBox.Checked = true;
- this.aggregateBudgetsCheckBox.CheckState = System.Windows.Forms.CheckState.Checked;
- this.aggregateBudgetsCheckBox.Location = new System.Drawing.Point(374, 10);
- this.aggregateBudgetsCheckBox.Name = "aggregateBudgetsCheckBox";
- this.aggregateBudgetsCheckBox.Size = new System.Drawing.Size(74, 17);
- this.aggregateBudgetsCheckBox.TabIndex = 10;
- this.aggregateBudgetsCheckBox.Text = "aggregate";
- this.aggregateBudgetsCheckBox.UseVisualStyleBackColor = true;
- this.aggregateBudgetsCheckBox.CheckedChanged += new System.EventHandler(this.aggregateBudgetsCheckBox_CheckedChanged);
//
// generateBudgetsButton
@@ -496,5 +496,4 @@
private System.Windows.Forms.TabPage byCostTabPage;
private System.Windows.Forms.TabPage byTableTabPage;
- private System.Windows.Forms.CheckBox aggregateBudgetsCheckBox;
private System.Windows.Forms.Button generateBudgetsButton;
private System.Windows.Forms.CheckBox budgetLogScalingCheckBox;
@@ -507,4 +506,5 @@
private System.Windows.Forms.CheckBox markerCheckBox;
private System.Windows.Forms.ComboBox relativeOrAbsoluteComboBox;
+ private System.Windows.Forms.CheckBox showLabelsCheckBox;
}
}
Index: /trunk/sources/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.cs (revision 15124)
+++ /trunk/sources/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.cs (revision 15125)
@@ -81,4 +81,5 @@
private double[] budgets;
private bool targetsAreRelative = true;
+ private bool showLabelsInTargetChart = true;
private readonly BindingList problems;
@@ -96,7 +97,7 @@
targetChart.ChartAreas[0].CursorX.Interval = 1;
targetChart.SuppressExceptions = true;
- byCostDataTable = new IndexedDataTable("ECDF by Cost", "A data table containing the ECDF of each of a number of groups.") {
+ byCostDataTable = new IndexedDataTable("ECDF by Cost", "A data table containing the ECDF of function values (relative to best-known).") {
VisualProperties = {
- YAxisTitle = "Proportion of unused budgets",
+ YAxisTitle = "Proportion of runs",
YAxisMinimumFixedValue = 0,
YAxisMinimumAuto = false,
@@ -284,4 +285,5 @@
addTargetsAsResultButton.Enabled = Content != null && targets != null && dataTableComboBox.SelectedIndex >= 0;
addBudgetsAsResultButton.Enabled = Content != null && budgets != null && dataTableComboBox.SelectedIndex >= 0;
+ generateTargetsButton.Enabled = targets != null;
}
@@ -314,5 +316,5 @@
targetChart.Series.Clear();
invisibleTargetSeries.Clear();
-
+
var table = (string)dataTableComboBox.SelectedItem;
if (string.IsNullOrEmpty(table)) return;
@@ -424,5 +426,6 @@
if (!labelPrinted && row.Points.Count > 0) {
var point = row.Points.Last();
- point.Label = row.Name;
+ if (showLabelsInTargetChart)
+ point.Label = row.Name;
point.MarkerStyle = MarkerStyle.Cross;
point.MarkerBorderWidth = 1;
@@ -456,5 +459,6 @@
if (!labelPrinted) {
var point = row.Points.Last();
- point.Label = row.Name;
+ if (showLabelsInTargetChart)
+ point.Label = row.Name;
point.MarkerStyle = MarkerStyle.Cross;
point.MarkerBorderWidth = 1;
@@ -504,5 +508,6 @@
if (!labelPrinted && row.Points.Count > 0) {
var point = row.Points.Last();
- point.Label = row.Name;
+ if (showLabelsInTargetChart)
+ point.Label = row.Name;
point.MarkerStyle = MarkerStyle.Cross;
point.MarkerBorderWidth = 1;
@@ -514,5 +519,6 @@
if (!labelPrinted) {
var point = row.Points.Last();
- point.Label = row.Name;
+ if (showLabelsInTargetChart)
+ point.Label = row.Name;
point.MarkerStyle = MarkerStyle.Cross;
point.MarkerBorderWidth = 1;
@@ -572,27 +578,32 @@
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 };
- suppressTargetsEvents = true;
- targetsTextBox.Text = string.Join("% ; ", targets.Select(x => x * 100)) + "%";
- suppressTargetsEvents = false;
+ SynchronizeTargetTextBox();
}
private Tuple GetEffortToHitTarget(
- IEnumerable> convergenceGraph,
+ ObservableList> convergenceGraph,
double absTarget, bool maximization) {
- var hit = false;
- var effort = double.NaN;
- foreach (var dent in convergenceGraph) {
- effort = dent.Item1;
- hit = maximization && dent.Item2 >= absTarget || !maximization && dent.Item2 <= absTarget;
- if (hit) break;
- }
- if (double.IsNaN(effort)) throw new ArgumentException("Convergence graph is empty.", "convergenceGraph");
- return Tuple.Create(hit, effort);
+ if (convergenceGraph.Count == 0)
+ throw new ArgumentException("Convergence graph is empty.", "convergenceGraph");
+
+ var index = convergenceGraph.BinarySearch(Tuple.Create(0.0, absTarget), new TargetComparer(maximization));
+ if (index >= 0) {
+ return Tuple.Create(true, convergenceGraph[index].Item1);
+ } else {
+ index = ~index;
+ if (index >= convergenceGraph.Count)
+ return Tuple.Create(false, convergenceGraph.Last().Item1);
+ return Tuple.Create(true, convergenceGraph[index].Item1);
+ }
}
private void UpdateErtTables(List algorithmInstances) {
ertTableView.Content = null;
- var columns = 1 + targets.Length + 1;
- var matrix = new string[algorithmInstances.Count * algorithmInstances.Max(x => x.GetNumberOfProblemInstances()) + algorithmInstances.Max(x => x.GetNumberOfProblemInstances()), columns];
+ var columns = targets.Length + 1;
+ var totalRows = algorithmInstances.Count * algorithmInstances.Max(x => x.GetNumberOfProblemInstances()) + algorithmInstances.Max(x => x.GetNumberOfProblemInstances());
+ var matrix = new StringMatrix(totalRows, columns);
+ var rowNames = new List();
+ matrix.ColumnNames = targets.Select(x => targetsAreRelative ? (100 * x).ToString() + "%" : x.ToString())
+ .Concat(new[] { "#succ" }).ToList();
var rowCount = 0;
@@ -604,14 +615,16 @@
foreach (var problem in problems) {
var max = problem.IsMaximization();
- matrix[rowCount, 0] = problem.ToString();
+ rowNames.Add(problem.ToString());
var absTargets = GetAbsoluteTargetsWorstToBest(problem);
- for (var i = 0; i < absTargets.Length; i++) {
- matrix[rowCount, i + 1] = absTargets[i].ToString(CultureInfo.CurrentCulture.NumberFormat);
- }
- matrix[rowCount, columns - 1] = "#succ";
+ if (targetsAreRelative) {
+ // print out the absolute target values
+ for (var i = 0; i < absTargets.Length; i++) {
+ matrix[rowCount, i] = absTargets[i].ToString("##,0.0", CultureInfo.CurrentCulture.NumberFormat);
+ }
+ }
rowCount++;
foreach (var alg in algorithmInstances) {
- matrix[rowCount, 0] = alg.Name;
+ rowNames.Add(alg.Name);
var runs = alg.GetRuns(problem).ToList();
if (runs.Count == 0) {
@@ -623,5 +636,5 @@
for (var i = 0; i < absTargets.Length; i++) {
result = ExpectedRuntimeHelper.CalculateErt(runs, tableName, absTargets[i], max);
- matrix[rowCount, i + 1] = result.ToString();
+ matrix[rowCount, i] = result.ToString();
}
matrix[rowCount, columns - 1] = targets.Length > 0 ? result.SuccessfulRuns + "/" + result.TotalRuns : "-";
@@ -629,5 +642,6 @@
}
}
- ertTableView.Content = new StringMatrix(matrix);
+ matrix.RowNames = rowNames;
+ ertTableView.Content = matrix;
ertTableView.DataGridView.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
}
@@ -658,9 +672,5 @@
var resultsTable = (IndexedDataTable)run.Results[table];
- if (aggregateBudgetsCheckBox.Checked) {
- CalculateHitsForAllBudgets(hits, resultsTable.Rows.First(), alg.GetNumberOfProblemInstances(), problem, alg.Name, alg.GetNumberOfRuns(problem));
- } else {
- CalculateHitsForEachBudget(hits, resultsTable.Rows.First(), alg.GetNumberOfProblemInstances(), problem, alg.Name, alg.GetNumberOfRuns(problem));
- }
+ CalculateHitsForEachBudget(hits, resultsTable.Rows.First(), problem, alg.Name);
}
}
@@ -678,7 +688,8 @@
var total = 0.0;
+ var count = list.Value.Count;
foreach (var h in list.Value) {
total += h.Value;
- row.Values.Add(Tuple.Create(h.Key, total));
+ row.Values.Add(Tuple.Create(h.Key, total / (double)count));
}
@@ -697,5 +708,5 @@
var min = runs.Select(x => ((IndexedDataTable)x.Results[table]).Rows.First().Values.Select(y => y.Item1).Min()).Min();
var max = runs.Select(x => ((IndexedDataTable)x.Results[table]).Rows.First().Values.Select(y => y.Item1).Max()).Max();
- var points = 20;
+ var points = 3;
budgets = Enumerable.Range(1, points).Select(x => min + (x / (double)points) * (max - min)).ToArray();
suppressBudgetsEvents = true;
@@ -704,56 +715,21 @@
}
- private void CalculateHitsForEachBudget(Dictionary> hits, IndexedDataRow row, int groupCount, ProblemInstance problem, string groupName, int problemCount) {
+ private void CalculateHitsForEachBudget(Dictionary> hits, IndexedDataRow row, ProblemInstance problem, string groupName) {
var max = problem.IsMaximization();
+ var prevIndex = 0;
foreach (var b in budgets) {
var key = groupName + "-" + b;
+ var index = row.Values.BinarySearch(prevIndex, row.Values.Count - prevIndex, Tuple.Create(b, 0.0), new CostComparer());
+ if (index < 0) {
+ index = ~index;
+ if (index >= row.Values.Count) break; // the run wasn't long enough to use up budget b (or any subsequent larger one)
+ }
if (!hits.ContainsKey(key)) hits.Add(key, new SortedList());
- Tuple prev = null;
- foreach (var v in row.Values) {
- if (v.Item1 >= b) {
- // the budget may be too low to achieve any target
- if (prev == null && v.Item1 != b) break;
- var tgt = ((prev == null || v.Item1 == b) ? v.Item2 : prev.Item2);
- var relTgt = CalculateRelativeDifference(max, problem.BestKnownQuality, tgt) + 1;
- if (hits[key].ContainsKey(relTgt))
- hits[key][relTgt] += 1.0 / (groupCount * problemCount);
- else hits[key][relTgt] = 1.0 / (groupCount * problemCount);
- break;
- }
- prev = v;
- }
- if (hits[key].Count == 0) hits.Remove(key);
- }
- }
-
- private void CalculateHitsForAllBudgets(Dictionary> hits, IndexedDataRow row, int groupCount, ProblemInstance problem, string groupName, int problemCount) {
- var values = row.Values;
- if (!hits.ContainsKey(groupName)) hits.Add(groupName, new SortedList());
-
- var i = 0;
- var j = 0;
- Tuple prev = null;
- var max = problem.IsMaximization();
- while (i < budgets.Length && j < values.Count) {
- var current = values[j];
- if (current.Item1 >= budgets[i]) {
- if (prev != null || current.Item1 == budgets[i]) {
- var tgt = (prev == null || current.Item1 == budgets[i]) ? current.Item2 : prev.Item2;
- var relTgt = CalculateRelativeDifference(max, problem.BestKnownQuality, tgt) + 1;
- if (!hits[groupName].ContainsKey(relTgt)) hits[groupName][relTgt] = 0;
- hits[groupName][relTgt] += 1.0 / (groupCount * problemCount * budgets.Length);
- }
- i++;
- } else {
- j++;
- prev = current;
- }
- }
- var lastTgt = values.Last().Item2;
- var lastRelTgt = CalculateRelativeDifference(max, problem.BestKnownQuality, lastTgt) + 1;
- if (i < budgets.Length && !hits[groupName].ContainsKey(lastRelTgt)) hits[groupName][lastRelTgt] = 0;
- while (i < budgets.Length) {
- hits[groupName][lastRelTgt] += 1.0 / (groupCount * problemCount * budgets.Length);
- i++;
+ var v = row.Values[index];
+ var relTgt = CalculateRelativeDifference(max, problem.BestKnownQuality, v.Item2) + 1;
+ if (hits[key].ContainsKey(relTgt))
+ hits[key][relTgt]++;
+ else hits[key][relTgt] = 1.0;
+ prevIndex = index;
}
}
@@ -762,4 +738,16 @@
private void UpdateCaption() {
Caption = Content != null ? Content.OptimizerName + " RLD View" : ViewAttribute.GetViewName(GetType());
+ }
+
+ private void SynchronizeTargetTextBox() {
+ if (InvokeRequired) Invoke((Action)SynchronizeTargetTextBox);
+ else {
+ suppressTargetsEvents = true;
+ try {
+ if (targetsAreRelative)
+ targetsTextBox.Text = string.Join("% ; ", targets.Select(x => x * 100)) + "%";
+ else targetsTextBox.Text = string.Join(" ; ", targets);
+ } finally { suppressTargetsEvents = false; }
+ }
}
@@ -814,11 +802,6 @@
errorProvider.SetError(targetsTextBox, null);
targets = targetsAreRelative ? targetList.Select(x => (double)x).OrderByDescending(x => x).ToArray() : targetList.Select(x => (double)x).ToArray();
- suppressTargetsEvents = true;
- try {
- if (targetsAreRelative)
- targetsTextBox.Text = string.Join("% ; ", targets.Select(x => x * 100)) + "%";
- else targetsTextBox.Text = string.Join(" ; ", targets);
- } finally { suppressTargetsEvents = false; }
-
+
+ SynchronizeTargetTextBox();
UpdateResultsByTarget();
SetEnabledStateOfControls();
@@ -848,37 +831,30 @@
}
targetsAreRelative = (string)relativeOrAbsoluteComboBox.SelectedItem == "relative";
- SuspendRepaint();
- suppressTargetsEvents = true;
+ SynchronizeTargetTextBox();
+
try {
- if (targetsAreRelative)
- targetsTextBox.Text = string.Join("% ; ", targets.Select(x => x * 100)) + "%";
- else targetsTextBox.Text = string.Join(" ; ", targets);
-
+ SuspendRepaint();
UpdateResultsByTarget();
- } finally { suppressTargetsEvents = false; ResumeRepaint(true); }
+ } finally { ResumeRepaint(true); }
}
private void generateTargetsButton_Click(object sender, EventArgs e) {
- decimal max = 1, min = 0, count = 10;
- if (targets != null) {
- max = (decimal)targets.Max();
- min = (decimal)targets.Min();
- count = targets.Length;
- } else if (Content.Count > 0 && dataTableComboBox.SelectedIndex >= 0) {
- var table = (string)dataTableComboBox.SelectedItem;
- max = (decimal)Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable)x.Results[table]).Rows.First().Values.Max(y => y.Item2)).Max();
- min = (decimal)Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable)x.Results[table]).Rows.First().Values.Min(y => y.Item2)).Min();
- count = 6;
+ 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 = dialog.Values.Select(x => (double)x).ToArray();
- suppressTargetsEvents = true;
- if (targetsAreRelative)
- targetsTextBox.Text = string.Join("% ; ", targets);
- else targetsTextBox.Text = string.Join(" ; ", targets);
- suppressTargetsEvents = false;
-
+ targets = targetsAreRelative
+ ? dialog.Values.OrderByDescending(x => x).Select(x => (double)x / 100.0).ToArray()
+ : dialog.Values.Select(x => (double)x).ToArray();
+
+ SynchronizeTargetTextBox();
UpdateResultsByTarget();
SetEnabledStateOfControls();
@@ -896,18 +872,20 @@
var resultsTable = (IndexedDataTable)run.Results[table];
var values = resultsTable.Rows.First().Values;
- var i = 0;
- var j = 0;
var pd = new ProblemInstance(run);
+ pd = problems.Single(x => x.Equals(pd));
var max = pd.IsMaximization();
- var absTargets = GetAbsoluteTargetsWorstToBest(problems.Single(x => x.Equals(pd)));
- while (i < absTargets.Length && j < values.Count) {
- var target = absTargets[i];
- var current = values[j];
- if (max && current.Item2 >= target || !max && current.Item2 <= target) {
- run.Results[table + ".Target" + target] = new DoubleValue(current.Item1);
- i++;
- } else {
- j++;
- }
+ var absTargets = GetAbsoluteTargetsWorstToBest(pd);
+
+ var prevIndex = 0;
+ for (var i = 0; i < absTargets.Length; i++) {
+ var absTarget = absTargets[i];
+ var index = values.BinarySearch(prevIndex, values.Count - prevIndex, Tuple.Create(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;
}
}
@@ -915,4 +893,12 @@
private void markerCheckBox_CheckedChanged(object sender, EventArgs e) {
+ SuspendRepaint();
+ try {
+ UpdateResultsByTarget();
+ } finally { ResumeRepaint(true); }
+ }
+
+ private void showLabelsCheckBox_CheckedChanged(object sender, EventArgs e) {
+ showLabelsInTargetChart = showLabelsCheckBox.Checked;
SuspendRepaint();
try {
@@ -931,5 +917,5 @@
double b;
if (!double.TryParse(ts, out b)) {
- errorProvider.SetError(budgetsTextBox, "Not all targets can be parsed: " + ts);
+ errorProvider.SetError(budgetsTextBox, "Not all budgets can be parsed: " + ts);
e.Cancel = true;
return;
@@ -938,5 +924,5 @@
}
if (budgetList.Count == 0) {
- errorProvider.SetError(budgetsTextBox, "Give at least one target value!");
+ errorProvider.SetError(budgetsTextBox, "Give at least one budget value!");
e.Cancel = true;
return;
@@ -944,14 +930,11 @@
e.Cancel = false;
errorProvider.SetError(budgetsTextBox, null);
- budgets = budgetList.ToArray();
+ budgets = budgetList.OrderBy(x => x).ToArray();
+ try {
+ suppressBudgetsEvents = true;
+ budgetsTextBox.Text = string.Join(" ; ", budgets);
+ } finally { suppressBudgetsEvents = false; }
UpdateResultsByCost();
SetEnabledStateOfControls();
- }
-
- private void aggregateBudgetsCheckBox_CheckedChanged(object sender, EventArgs e) {
- SuspendRepaint();
- try {
- UpdateResultsByCost();
- } finally { ResumeRepaint(true); }
}
@@ -966,5 +949,5 @@
min = (decimal)Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable)x.Results[table]).Rows.First().Values.Min(y => y.Item1)).Min();
max = (decimal)Content.Where(x => x.Results.ContainsKey(table)).Select(x => ((IndexedDataTable)x.Results[table]).Rows.First().Values.Max(y => y.Item1)).Max();
- count = 6;
+ count = 3;
}
using (var dialog = new DefineArithmeticProgressionDialog(false, min, max, (max - min) / count)) {
@@ -973,7 +956,8 @@
budgets = dialog.Values.OrderBy(x => x).Select(x => (double)x).ToArray();
- suppressBudgetsEvents = true;
- budgetsTextBox.Text = string.Join(" ; ", budgets);
- suppressBudgetsEvents = false;
+ try {
+ suppressBudgetsEvents = true;
+ budgetsTextBox.Text = string.Join(" ; ", budgets);
+ } finally { suppressBudgetsEvents = false; }
UpdateResultsByCost();
@@ -986,19 +970,4 @@
private void addBudgetsAsResultButton_Click(object sender, EventArgs e) {
var table = (string)dataTableComboBox.SelectedItem;
- var budgetStrings = budgetsTextBox.Text.Split(new[] { ';', '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries);
- if (budgetStrings.Length == 0) {
- MessageBox.Show("Define a number of budgets.");
- return;
- }
- var budgetList = new List();
- foreach (var bs in budgetStrings) {
- double v;
- if (!double.TryParse(bs, out v)) {
- MessageBox.Show("Budgets must be a valid number: " + bs);
- return;
- }
- budgetList.Add(v);
- }
- budgetList.Sort();
foreach (var run in Content) {
@@ -1006,19 +975,18 @@
var resultsTable = (IndexedDataTable)run.Results[table];
var values = resultsTable.Rows.First().Values;
- var i = 0;
- var j = 0;
- Tuple prev = null;
- while (i < budgetList.Count && j < values.Count) {
- var current = values[j];
- if (current.Item1 >= budgetList[i]) {
- if (prev != null || current.Item1 == budgetList[i]) {
- var tgt = (prev == null || current.Item1 == budgetList[i]) ? current.Item2 : prev.Item2;
- run.Results[table + ".Cost" + budgetList[i]] = new DoubleValue(tgt);
- }
- i++;
- } else {
- j++;
- prev = current;
- }
+ var pd = new ProblemInstance(run);
+ pd = problems.Single(x => x.Equals(pd));
+
+ var prevIndex = 0;
+ foreach (var b in budgets) {
+ var index = values.BinarySearch(prevIndex, values.Count - prevIndex, Tuple.Create(b, 0.0), new CostComparer());
+ if (index < 0) {
+ index = ~index;
+ if (index >= values.Count) break; // the run wasn't long enough to use up budget b (or any subsequent larger one)
+ }
+ var v = values[index];
+ var tgt = targetsAreRelative ? CalculateRelativeDifference(pd.IsMaximization(), pd.BestKnownQuality, v.Item2) : v.Item2;
+ run.Results[table + (targetsAreRelative ? ".CostForRelTarget " : ".CostForAbsTarget ") + b] = new DoubleValue(tgt);
+ prevIndex = index;
}
}
@@ -1080,10 +1048,9 @@
else pd.BestKnownQuality = double.NaN;
}
- //problemComboBox.ResetBindings();
}
#endregion
private void ConfigureSeries(Series series) {
- series.SmartLabelStyle.Enabled = true;
+ series.SmartLabelStyle.Enabled = showLabelsInTargetChart;
series.SmartLabelStyle.AllowOutsidePlotArea = LabelOutsidePlotAreaStyle.No;
series.SmartLabelStyle.CalloutLineAnchorCapStyle = LineAnchorCapStyle.None;
@@ -1418,4 +1385,21 @@
}
}
+
+ private class CostComparer : Comparer> {
+ public override int Compare(Tuple x, Tuple y) {
+ return x.Item1.CompareTo(y.Item1);
+ }
+ }
+
+ private class TargetComparer : Comparer> {
+ public bool Maximization { get; }
+ public TargetComparer(bool maximization) {
+ Maximization = maximization;
+ }
+
+ public override int Compare(Tuple x, Tuple y) {
+ return Maximization ? x.Item2.CompareTo(y.Item2) : y.Item2.CompareTo(x.Item2);
+ }
+ }
}
}