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  * <http://shark-ml.org/>
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 
40 namespace 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] e Function object \f$f\f$to "project" elements of the set to \f$\mathbb{R}^n\f$.
77  /// \param [in] set 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$
78  /// \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$. .
79  template<typename Set, typename VectorType >
80  double operator()( Set const& points, VectorType const& refPoint){
81  std::size_t noPoints = points.size();
82 
83  if( noPoints == 0 )
84  return 0;
85 
86  // runtime (O.K: added static_cast to prevent warning on VC10)
87  boost::uint_fast64_t maxSamples=static_cast<boost::uint_fast64_t>( 12. * std::log( 1. / delta() ) / std::log( 2. ) * noPoints/sqr(epsilon()) );
88 
89  // calc separate volume of each box
90  VectorType vol( noPoints, 1. );
91  for( std::size_t p = 0; p != noPoints; ++p) {
92  //guard against points which are worse than the reference
94  min(refPoint - points[p] ) >= 0,
95  "HyperVolumeApproximator: points must be better than reference point"
96  );
97  //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
98  vol[p] = std::exp(sum(log(refPoint[ 0 ] - points[p] )));
99  }
100  //calculate total sum of volumes
101  double totalVolume = sum(vol);
102 
103  VectorType rndpoint( refPoint );
104  boost::uint_fast64_t samples_sofar=0;
105  boost::uint_fast64_t round=0;
106 
107  //we pick points randomly based on their volume
108  MultiNomialDistribution pointDist(vol);
109 
110  while (true)
111  {
112  // sample ROI based on its volume. the ROI is defined as the Area between the reference point and a point in the front.
113  auto point = points.begin() + pointDist(random::globalRng);
114 
115  // sample point in ROI
116  for( std::size_t i = 0; i < rndpoint.size(); i++ ){
117  rndpoint[i] = random::uni(random::globalRng,(*point )[i], refPoint[i]);
118  }
119 
120  while (true)
121  {
122  if (samples_sofar>=maxSamples) return maxSamples * totalVolume / noPoints / round;
123  auto candidate = points.begin() + random::discrete(random::globalRng, std::size_t(0), noPoints - 1);
124  samples_sofar++;
125  DominanceRelation rel = dominance(*candidate, rndpoint);
126  if (rel == LHS_DOMINATES_RHS || rel == EQUIVALENT) break;
127 
128  }
129 
130  round++;
131  }
132  }
133 
134 private:
135  double m_epsilon;
136  double m_delta;
137 };
138 }
139 
140 #endif // HYPERVOLUME_APPROXIMATOR_H