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 * <https://shark-ml.github.io/Shark/>
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
40namespace 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