Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Analysis.AlgorithmBehavior/HeuristicLab.Analysis.AlgorithmBehavior.Analyzers/3.3/ConvexHullMeasures.cs @ 10429

Last change on this file since 10429 was 10301, checked in by ascheibe, 11 years ago

#1886 fixed hypercube volume calculation

File size: 8.9 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using Mehroz;
26using MIConvexHull;
27
28namespace HeuristicLab.Analysis.AlgorithmBehavior.Analyzers {
29  public static class ConvexHullMeasures {
30    //Calculates the volumne of a d-simplex
31    public static double CalculateSimplexVolume(List<double[]> simplex) {
32      int dim = simplex.First().Length;
33      double[,] diffs = new double[dim, dim];
34
35      for (int i = 1; i < simplex.Count; i++) {
36        for (int j = 0; j < dim; j++) {
37          diffs[j, i - 1] = simplex[i][j] - simplex[0][j];
38        }
39      }
40
41      double det = Math.Abs(alglib.rmatrixdet(diffs));
42      double result = det / dim.Fact();
43
44      return result;
45    }
46
47    public static Fraction CalculateSimplexVolumeBig(List<double[]> simplex) {
48      int dim = simplex.First().Length;
49      double[,] diffs = new double[dim, dim];
50
51      for (int i = 1; i < simplex.Count; i++) {
52        for (int j = 0; j < dim; j++) {
53          diffs[j, i - 1] = simplex[i][j] - simplex[0][j];
54        }
55      }
56
57      //calculate determinante from lu decomposition
58      int[] pivots = null;
59      alglib.rmatrixlu(ref diffs, dim, dim, out pivots);
60
61      Fraction det = 1;
62      for (int i = 0; i < dim; i++) {
63        det = det * diffs[i, i];
64      }
65
66      if (det < 0)
67        det = -1 * det;
68
69      Fraction result = det / dim.Fact();
70      return result;
71    }
72
73    //calculates the volume of a convex d-polytope
74    //decomposition based on delaunay triangulation
75    public static double CalculateVolume(List<double[]> convexHull) {
76      double volume = 0.0;
77
78      int dim = convexHull.First().Length;
79      if (dim > convexHull.Count)
80        throw new ArgumentException("Nr. of points for volume calculation must be greater than dimension", "convexHull");
81
82      ITriangulation<DefaultVertex, DefaultTriangulationCell<DefaultVertex>> triangulation = null;
83      try {
84        //Under certain circumstances MIConvexHull is not able to calculate the triangulation
85        triangulation = Triangulation.CreateDelaunay(ConvertToVertex(convexHull));
86      }
87      catch {
88        return double.NaN;
89      }
90      var simplices = ConvertFromTriangulation(triangulation);
91      foreach (var simplex in simplices) {
92        volume += CalculateSimplexVolume(simplex.ToList());
93      }
94
95      return volume;
96    }
97
98    public static Fraction CalculateVolumeBig(List<double[]> convexHull) {
99      Fraction volume = new Fraction(0.0);
100
101      int dim = convexHull.First().Length;
102      if (dim > convexHull.Count)
103        throw new ArgumentException("Nr. of points for volume calculation must be greater than dimension", "convexHull");
104
105      ITriangulation<DefaultVertex, DefaultTriangulationCell<DefaultVertex>> triangulation = null;
106      try {
107        //Under certain circumstances MIConvexHull is not able to calculate the triangulation
108        triangulation = Triangulation.CreateDelaunay(ConvertToVertex(convexHull));
109      }
110      catch {
111        return Fraction.NaN;
112      }
113      var simplices = ConvertFromTriangulation(triangulation);
114      foreach (var simplex in simplices) {
115        volume += CalculateSimplexVolumeBig(simplex.ToList());
116      }
117
118      return volume;
119    }
120
121    private static List<double[][]> ConvertFromTriangulation(ITriangulation<DefaultVertex, DefaultTriangulationCell<DefaultVertex>> triangulation) {
122      List<double[][]> results = new List<double[][]>();
123
124      foreach (var cell in triangulation.Cells) {
125        results.Add(cell.Vertices.Select(x => x.Position).ToArray());
126      }
127
128      return results;
129    }
130
131    private static List<DefaultVertex> ConvertToVertex(List<double[]> data) {
132      List<DefaultVertex> result = new List<DefaultVertex>();
133      for (int i = 0; i < data.Count(); i++) {
134        double[] d = data[i];
135        DefaultVertex vertex = new DefaultVertex();
136        vertex.Position = d;
137        result.Add(vertex);
138      }
139      return result;
140    }
141
142    public static double[] CalculateCentroids(List<double[]> convexHull) {
143      int n = convexHull.Count;
144      int dim = convexHull.First().Length;
145      double[] centroid = new double[dim];
146
147      for (int i = 0; i < dim; i++) {
148        for (int j = 0; j < n; j++) {
149          centroid[i] += convexHull[j][i];
150        }
151        centroid[i] /= n;
152      }
153      return centroid;
154    }
155
156    //measures to calculate: AVG, SUM, STD.DEV
157    public static double[] CalculateMovementDistances(List<double[]> centroids) {
158      double[] distances = new double[centroids.Count - 1];
159
160      // it is assumed that the centroids are sorted chronological
161      for (int i = 0; i < centroids.Count - 1; i++) {
162        distances[i] = centroids[i].EuclideanDistance(centroids[i + 1]);
163      }
164
165      return distances;
166    }
167
168    public static double CalculateOverallMovementDistances(List<double[]> centroids) {
169      // it is assumed that the centroids are sorted chronological
170      return centroids[0].EuclideanDistance(centroids[centroids.Count - 1]);
171    }
172
173    //calculate theta from two vectors (dot product)
174    public static double CalculateTheta(double[] a, double[] b) {
175      return Math.Acos(a.DotProduct(b) / (a.EuclideanNorm() * b.EuclideanNorm()));
176    }
177
178    //calculate theta using law of cosines
179    public static double CalculateTheta(double[] a, double[] b, double[] c) {
180      double ab = a.EuclideanDistance(b);
181      double bc = b.EuclideanDistance(c);
182      double ca = c.EuclideanDistance(a);
183
184      //return degrees
185      return Math.Acos((ab * ab + bc * bc - ca * ca) / (2 * ab * bc)) * 180.0 / Math.PI;
186    }
187
188    //measures to calculate: AVG, SUM, STD.DEV
189    public static double[] CalculateCentroidsMotion(List<double[]> centroids) {
190      double[] thetas = new double[centroids.Count - 2];
191
192      for (int i = 1; i < centroids.Count - 1; i++) {
193        thetas[i - 1] = CalculateTheta(centroids[i - 1], centroids[i], centroids[i + 1]);
194      }
195
196      return thetas;
197    }
198
199    public static double CalculateMaxDiameter(List<double[]> convexHull) {
200      double maxDist = double.MinValue;
201
202      for (int i = 0; i < convexHull.Count; i++) {
203        for (int j = 0; j < convexHull.Count; j++) {
204          if (i != j) {
205            double dist = convexHull[i].EuclideanDistance(convexHull[j]);
206            if (dist > maxDist)
207              maxDist = dist;
208          }
209        }
210      }
211      return maxDist;
212    }
213
214    private static List<double[]> GenerateHyperCube(double[] bounds, int dim) {
215      if (bounds.Length != 2)
216        throw new ArgumentException("Only bounds of length 2 are supported!", "bounds");
217
218      int numPoints = (int)Math.Pow(2, dim);
219
220      var hyperCube = new List<double[]>(numPoints);
221      var binaryVectors = new List<string>(numPoints);
222      for (int i = 0; i < numPoints; i++) {
223        string binary = Convert.ToString(i, 2);
224        binaryVectors.Add(binary);
225      }
226
227      for (int i = 0; i < numPoints; i++) {
228        for (int j = 0; j < dim - binaryVectors[i].Length; j++) {
229          //TODO: do this properly
230          binaryVectors[i] = "0" + binaryVectors[i];
231        }
232      }
233
234      foreach (var binaryVector in binaryVectors) {
235        double[] point = new double[dim];
236        for (int i = 0; i < binaryVector.Length; i++) {
237          if (binaryVector[i] == '0') {
238            point[i] = bounds[0];
239          } else {
240            point[i] = bounds[1];
241          }
242        }
243        hyperCube.Add(point);
244      }
245      return hyperCube;
246    }
247
248    public static double CalculateHypercubeVolume(double[] bounds, int dim) {
249      //this is not very smart...
250      //return CalculateVolume(GenerateHyperCube(bounds, dim));
251      double diff = bounds[1] - bounds[0];
252      return Math.Pow(diff, dim);
253    }
254
255    public static Fraction CalculateHypercubeVolumeBig(double[] bounds, int dim) {
256      double diff = bounds[1] - bounds[0];
257
258      Fraction volume = diff;
259      for (int i = 1; i < dim; i++) {
260        volume *= diff;
261      }
262      return volume;
263    }
264  }
265}
Note: See TracBrowser for help on using the repository browser.