HypervolumeApproximator.h
Go to the documentation of this file.
1/*!
2 *
3 *
4 * \brief Determine the volume of the union of objects by an FPRAS
5 *
6 *
7 *
8 * \author T.Voss
9 * \date 2010-2011
10 *
11 *
12 * \par Copyright 1995-2017 Shark Development Team
13 *
14 * <BR><HR>
15 * This file is part of Shark.
16 * <https://shark-ml.github.io/Shark/>
17 *
18 * Shark is free software: you can redistribute it and/or modify
19 * it under the terms of the GNU Lesser General Public License as published
20 * by the Free Software Foundation, either version 3 of the License, or
21 * (at your option) any later version.
22 *
23 * Shark is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU Lesser General Public License for more details.
27 *
28 * You should have received a copy of the GNU Lesser General Public License
29 * along with Shark. If not, see <http://www.gnu.org/licenses/>.
30 *
31 */
32#ifndef HYPERVOLUME_APPROXIMATOR_H
33#define HYPERVOLUME_APPROXIMATOR_H
34
37
38#include <shark/LinAlg/Base.h>
39
40namespace shark {
41
42/// \brief Implements an FPRAS for approximating the volume of a set of high-dimensional objects.
43/// The algorithm is described in
44///
45/// Bringmann, Karl, and Tobias Friedrich.
46/// "Approximating the volume of unions and intersections of high-dimensional geometric objects."
47/// Algorithms and Computation. Springer Berlin Heidelberg, 2008. 436-447.
48///
49/// The algorithm computes an approximation of the true Volume V, V' that fulfills
50/// \f[ P((1-epsilon)V < V' <(1+epsilon)V') < 1-\delta \f]
51///
53
54 template<typename Archive>
55 void serialize( Archive & archive, const unsigned int version ) {
56 archive & BOOST_SERIALIZATION_NVP(m_epsilon);
57 archive & BOOST_SERIALIZATION_NVP(m_delta);
58 }
59
60 double epsilon()const{
61 return m_epsilon;
62 }
63 double& epsilon(){
64 return m_epsilon;
65 }
66
67 double delta()const{
68 return m_delta;
69 }
70
71 double& delta(){
72 return m_delta;
73 }
74
75 /// \brief Executes the algorithm.
76 /// \param [in] points The set \f$S\f$ of points for which the following assumption needs to hold: \f$\forall s \in S: \lnot \exists s' \in S: f( s' ) \preceq f( s ) \f$
77 /// \param [in] refPoint The reference point \f$\vec{r} \in \mathbb{R}^n\f$ for the hypervolume calculation, needs to fulfill: \f$ \forall s \in S: s \preceq \vec{r}\f$. .
78 template<typename Set, typename VectorType >
79 double operator()( Set const& points, VectorType const& refPoint){
80 std::size_t noPoints = points.size();
81
82 if( noPoints == 0 )
83 return 0;
84
85 // runtime (O.K: added static_cast to prevent warning on VC10)
86 boost::uint_fast64_t maxSamples=static_cast<boost::uint_fast64_t>( 12. * std::log( 1. / delta() ) / std::log( 2. ) * noPoints/sqr(epsilon()) );
87
88 // calc separate volume of each box
89 VectorType vol( noPoints, 1. );
90 for( std::size_t p = 0; p != noPoints; ++p) {
91 //guard against points which are worse than the reference
93 min(refPoint - points[p] ) >= 0,
94 "HyperVolumeApproximator: points must be better than reference point"
95 );
96 //taking the sum of logs instead of their product is numerically more stable in large dimensions were intermediate volumes can become very small or large
97 vol[p] = std::exp(sum(log(refPoint[ 0 ] - points[p] )));
98 }
99 //calculate total sum of volumes
100 double totalVolume = sum(vol);
101
102 VectorType rndpoint( refPoint );
103 boost::uint_fast64_t samples_sofar=0;
104 boost::uint_fast64_t round=0;
105
106 //we pick points randomly based on their volume
107 MultiNomialDistribution pointDist(vol);
108
109 while (true)
110 {
111 // sample ROI based on its volume. the ROI is defined as the Area between the reference point and a point in the front.
112 auto point = points.begin() + pointDist(random::globalRng);
113
114 // sample point in ROI
115 for( std::size_t i = 0; i < rndpoint.size(); i++ ){
116 rndpoint[i] = random::uni(random::globalRng,(*point )[i], refPoint[i]);
117 }
118
119 while (true)
120 {
121 if (samples_sofar>=maxSamples) return maxSamples * totalVolume / noPoints / round;
122 auto candidate = points.begin() + random::discrete(random::globalRng, std::size_t(0), noPoints - 1);
123 samples_sofar++;
124 DominanceRelation rel = dominance(*candidate, rndpoint);
125 if (rel == LHS_DOMINATES_RHS || rel == EQUIVALENT) break;
126
127 }
128
129 round++;
130 }
131 }
132
133private:
134 double m_epsilon;
135 double m_delta;
136};
137}
138
139#endif // HYPERVOLUME_APPROXIMATOR_H