Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 10279 was 10279, checked in by ascheibe, 10 years ago

#1886 added calculation of the ratio between the convex hull volume and the max. hypercube volume

File size: 6.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 MIConvexHull;
26
27namespace HeuristicLab.Analysis.AlgorithmBehavior.Analyzers {
28  public static class ConvexHullMeasures {
29    //Calculates the volumne of a d-simplex
30    public static double CalculateSimplexVolume(List<double[]> simplex) {
31      int dim = simplex.First().Length;
32      double[,] diffs = new double[dim, dim];
33
34      for (int i = 1; i < simplex.Count; i++) {
35        for (int j = 0; j < dim; j++) {
36          diffs[j, i - 1] = simplex[i][j] - simplex[0][j];
37        }
38      }
39
40      double det = Math.Abs(alglib.rmatrixdet(diffs));
41      double result = det / dim.Fact();
42
43      return result;
44    }
45
46    //calculates the volume of a convex d-polytope
47    //decomposition based on delaunay triangulation
48    public static double CalculateVolume(List<double[]> convexHull) {
49      double volume = 0.0;
50
51      int dim = convexHull.First().Length;
52      if (dim > convexHull.Count)
53        throw new ArgumentException("Nr. of points for volume calculation must be greater than dimension", "convexHull");
54
55      ITriangulation<DefaultVertex, DefaultTriangulationCell<DefaultVertex>> triangulation = null;
56      try {
57        //Under certain circumstances MIConvexHull is not able to calculate the triangulation
58        triangulation = Triangulation.CreateDelaunay(ConvertToVertex(convexHull));
59      }
60      catch {
61        return double.NaN;
62      }
63      var simplices = ConvertFromTriangulation(triangulation);
64      foreach (var simplex in simplices) {
65        volume += CalculateSimplexVolume(simplex.ToList());
66      }
67
68      return volume;
69    }
70
71    private static List<double[][]> ConvertFromTriangulation(ITriangulation<DefaultVertex, DefaultTriangulationCell<DefaultVertex>> triangulation) {
72      List<double[][]> results = new List<double[][]>();
73
74      foreach (var cell in triangulation.Cells) {
75        results.Add(cell.Vertices.Select(x => x.Position).ToArray());
76      }
77
78      return results;
79    }
80
81    private static List<DefaultVertex> ConvertToVertex(List<double[]> data) {
82      List<DefaultVertex> result = new List<DefaultVertex>();
83      for (int i = 0; i < data.Count(); i++) {
84        double[] d = data[i];
85        DefaultVertex vertex = new DefaultVertex();
86        vertex.Position = d;
87        result.Add(vertex);
88      }
89      return result;
90    }
91
92    public static double[] CalculateCentroids(List<double[]> convexHull) {
93      int n = convexHull.Count;
94      int dim = convexHull.First().Length;
95      double[] centroid = new double[dim];
96
97      for (int i = 0; i < dim; i++) {
98        for (int j = 0; j < n; j++) {
99          centroid[i] += convexHull[j][i];
100        }
101        centroid[i] /= n;
102      }
103      return centroid;
104    }
105
106    //measures to calculate: AVG, SUM, STD.DEV
107    public static double[] CalculateMovementDistances(List<double[]> centroids) {
108      double[] distances = new double[centroids.Count - 1];
109
110      // it is assumed that the centroids are sorted chronological
111      for (int i = 0; i < centroids.Count - 1; i++) {
112        distances[i] = centroids[i].EuclideanDistance(centroids[i + 1]);
113      }
114
115      return distances;
116    }
117
118    public static double CalculateOverallMovementDistances(List<double[]> centroids) {
119      // it is assumed that the centroids are sorted chronological
120      return centroids[0].EuclideanDistance(centroids[centroids.Count - 1]);
121    }
122
123    //calculate theta from two vectors (dot product)
124    public static double CalculateTheta(double[] a, double[] b) {
125      return Math.Acos(a.DotProduct(b) / (a.EuclideanNorm() * b.EuclideanNorm()));
126    }
127
128    //calculate theta using law of cosines
129    public static double CalculateTheta(double[] a, double[] b, double[] c) {
130      double ab = a.EuclideanDistance(b);
131      double bc = b.EuclideanDistance(c);
132      double ca = c.EuclideanDistance(a);
133
134      //return degrees
135      return Math.Acos((ab * ab + bc * bc - ca * ca) / (2 * ab * bc)) * 180.0 / Math.PI;
136    }
137
138    //measures to calculate: AVG, SUM, STD.DEV
139    public static double[] CalculateCentroidsMotion(List<double[]> centroids) {
140      double[] thetas = new double[centroids.Count - 2];
141
142      for (int i = 1; i < centroids.Count - 1; i++) {
143        thetas[i - 1] = CalculateTheta(centroids[i - 1], centroids[i], centroids[i + 1]);
144      }
145
146      return thetas;
147    }
148
149    public static double CalculateMaxDiameter(List<double[]> convexHull) {
150      double maxDist = double.MinValue;
151
152      for (int i = 0; i < convexHull.Count; i++) {
153        for (int j = 0; j < convexHull.Count; j++) {
154          if (i != j) {
155            double dist = convexHull[i].EuclideanDistance(convexHull[j]);
156            if (dist > maxDist)
157              maxDist = dist;
158          }
159        }
160      }
161      return maxDist;
162    }
163
164    private static List<double[]> GenerateHyperCube(double[] bounds, int dim) {
165      if (bounds.Length != 2)
166        throw new ArgumentException("Only bounds of length 2 are supported!", "bounds");
167
168      int numPoints = (int)Math.Pow(2, dim);
169
170      var hyperCube = new List<double[]>(numPoints);
171      var binaryVectors = new List<string>(numPoints);
172      for (int i = 0; i < numPoints; i++) {
173        string binary = Convert.ToString(i, 2);
174        binaryVectors.Add(binary);
175      }
176
177      for (int i = 0; i < numPoints; i++) {
178        for (int j = 0; j < dim - binaryVectors[i].Length; j++) {
179          //TODO: do this properly
180          binaryVectors[i] = "0" + binaryVectors[i];
181        }
182      }
183
184      foreach (var binaryVector in binaryVectors) {
185        double[] point = new double[dim];
186        for (int i = 0; i < binaryVector.Length; i++) {
187          if (binaryVector[i] == '0') {
188            point[i] = bounds[0];
189          } else {
190            point[i] = bounds[1];
191          }
192        }
193        hyperCube.Add(point);
194      }
195      return hyperCube;
196    }
197
198    public static double CalculateHypercubeVolume(double[] bounds, int dim) {
199      return CalculateVolume(GenerateHyperCube(bounds, dim));
200    }
201  }
202}
Note: See TracBrowser for help on using the repository browser.