HypervolumeCalculator3D.h
Go to the documentation of this file.
1 /*!
2  *
3  *
4  * \brief Implementation of the exact hypervolume calculation in 3 dimensions.
5  *
6  *
7  * \author T. Glasmachers
8  * \date 2016-2017
9  *
10  *
11  * \par Copyright 1995-2017 Shark Development Team
12  *
13  * <BR><HR>
14  * This file is part of Shark.
15  * <http://shark-ml.org/>
16  *
17  * Shark is free software: you can redistribute it and/or modify
18  * it under the terms of the GNU Lesser General Public License as published
19  * by the Free Software Foundation, either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * Shark is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25  * GNU Lesser General Public License for more details.
26  *
27  * You should have received a copy of the GNU Lesser General Public License
28  * along with Shark. If not, see <http://www.gnu.org/licenses/>.
29  *
30  */
31 #ifndef SHARK_ALGORITHMS_DIRECTSEARCH_HYPERVOLUMECALCULATOR_3D_H
32 #define SHARK_ALGORITHMS_DIRECTSEARCH_HYPERVOLUMECALCULATOR_3D_H
33 
34 #include <shark/LinAlg/Base.h>
35 
36 #include <algorithm>
37 #include <vector>
38 #include <map>
39 
40 namespace shark {
41 /// \brief Implementation of the exact hypervolume calculation in 3 dimensions.
42 ///
43 /// M. T. M. Emmerich and C. M. Fonseca.
44 /// Computing hypervolume contributions in low dimensions: Asymptotically optimal algorithm and complexity results.
45 /// In: Evolutionary Multi-Criterion Optimization (EMO) 2011.
46 /// Vol. 6576 of Lecture Notes in Computer Science, pp. 121--135, Berlin: Springer, 2011.
48  /// \brief Executes the algorithm.
49  /// \param [in] points The set of points for which to compute the volume
50  /// \param [in] refPoint The reference point \f$\vec{r} \in \mathbb{R}^3\f$ for the hypervolume calculation, needs to fulfill: \f$ \forall s \in S: s \preceq \vec{r}\f$.
51  template<typename Set, typename VectorType >
52  double operator()( Set const& points, VectorType const& refPoint){
53  if (points.empty()) return 0.0;
54  SIZE_CHECK(points.begin()->size() == 3);
55  SIZE_CHECK(refPoint.size() == 3);
56 
57  std::vector<VectorType> set;
58  for (std::size_t i=0; i<points.size(); i++)
59  {
60  VectorType const& p = points[i];
61  if (p[0] < refPoint[0] && p[1] < refPoint[1] && p[2] < refPoint[2]) set.push_back(p);
62  }
63  if (set.empty()) return 0.0;
64  std::sort(set.begin(), set.end(),
65  [] (VectorType const& x, VectorType const& y)
66  { return (x[2] < y[2]); }
67  );
68 
69  // add the first point
70  std::map<double, double> front2D;
71  VectorType const& x0 = set[0];
72  front2D[x0[0]] = x0[1];
73  double prev_x2 = x0[2];
74  double area = (refPoint[0] - x0[0]) * (refPoint[1] - x0[1]);
75  double volume = 0.0;
76 
77  // process further points
78  for (size_t i=1; i<set.size(); i++)
79  {
80  assert(! front2D.empty());
81  assert(area > 0.0);
82 
83  VectorType const& x = set[i];
84 
85  // check whether x is dominated and find "top" coordinate
86  double t = refPoint[1];
87  std::map<double, double>::iterator right = front2D.lower_bound(x[0]);
88  std::map<double, double>::iterator left = right;
89  if (right == front2D.end())
90  {
91  --left;
92  t = left->second;
93  }
94  else
95  {
96  if (right->first == x[0])
97  {
98  t = left->second;
99  }
100  else if (left != front2D.begin())
101  {
102  --left;
103  t = left->second;
104  }
105  }
106  if (x[1] >= t) continue; // x is dominated
107 
108  // add chunk to volume
109  volume += area * (x[2] - prev_x2);
110 
111  // remove dominated points and corresponding areas
112  while (right != front2D.end() && right->second >= x[1])
113  {
114  std::map<double, double>::iterator tmp = right;
115  ++right;
116  const double r = (right == front2D.end()) ? refPoint[0] : right->first;
117  area -= (r - tmp->first) * (t - tmp->second);
118  front2D.erase(tmp);
119  }
120 
121  // add the new point
122  const double r = (right == front2D.end()) ? refPoint[0] : right->first;
123  area += (r - x[0]) * (t - x[1]);
124  front2D[x[0]] = x[1];
125 
126  // volume is processed up to here:
127  prev_x2 = x[2];
128  }
129 
130  // add trailing chunk to volume
131  volume += area * (refPoint[2] - prev_x2);
132 
133  // return the result
134  return volume;
135  }
136 };
137 
138 }
139 #endif