26 #include "bf_approx.h"
28 namespace pagmo {
namespace util {
namespace hv_algorithm {
43 bf_approx::bf_approx(
const bool use_exact,
const unsigned int trivial_subcase_size,
const double eps,
const double delta,
const double delta_multiplier,
const double alpha,
const double initial_delta_coeff,
const double gamma)
44 : m_use_exact(use_exact), m_trivial_subcase_size(trivial_subcase_size), m_eps(eps), m_delta(delta), m_delta_multiplier(delta_multiplier), m_alpha(alpha), m_initial_delta_coeff(initial_delta_coeff), m_gamma(gamma) { }
46 double bf_approx::lc_end_condition(
unsigned int idx,
unsigned int LC, std::vector<double> &approx_volume, std::vector<double> &point_delta)
48 return (approx_volume[LC] + point_delta[LC]) / (approx_volume[idx] - point_delta[idx]);
50 double bf_approx::gc_end_condition(
unsigned int idx,
unsigned int GC, std::vector<double> &approx_volume, std::vector<double> &point_delta)
52 return (approx_volume[idx] + point_delta[idx]) / (approx_volume[GC] - point_delta[GC]);
54 bool bf_approx::lc_erase_condition(
unsigned int idx,
unsigned int LC, std::vector<double> &approx_volume, std::vector<double> &point_delta)
56 return (approx_volume[idx] - point_delta[idx]) > (approx_volume[LC] + point_delta[LC]);
58 bool bf_approx::gc_erase_condition(
unsigned int idx,
unsigned int GC, std::vector<double> &approx_volume, std::vector<double> &point_delta)
60 return (approx_volume[idx] + point_delta[idx]) < (approx_volume[GC] - point_delta[GC]);
74 return approx_extreme_contributor(points, r_point, LEAST,
base::cmp_least, lc_erase_condition, lc_end_condition);
88 return approx_extreme_contributor(points, r_point, GREATEST,
base::cmp_greatest, gc_erase_condition, gc_end_condition);
113 unsigned int bf_approx::approx_extreme_contributor(std::vector<fitness_vector> &points,
const fitness_vector &r_point, extreme_contrib_type ec_type,
bool (*cmp_func)(
double,
double),
114 bool (*erase_condition)(
unsigned int,
unsigned int, std::vector<double> &, std::vector<double> &),
double (*end_condition)(
unsigned int,
unsigned int, std::vector<double> &, std::vector<double> &))
const
116 m_no_samples = std::vector<unsigned long long>(points.size(), 0);
117 m_no_succ_samples = std::vector<unsigned long long>(points.size(), 0);
118 m_no_ops = std::vector<unsigned long long>(points.size(), 1);
119 m_point_set = std::vector<unsigned int>(points.size(), 0);
120 m_box_volume = std::vector<double>(points.size(), 0.0);
121 m_approx_volume = std::vector<double>(points.size(), 0.0);
122 m_point_delta = std::vector<double>(points.size(), 0.0);
123 m_boxes = std::vector<fitness_vector>(points.size());
124 m_box_points = std::vector<std::vector<unsigned int> >(points.size());
127 const double log_factor = log (2. * points.size() * (1. + m_gamma) / (m_delta * m_gamma) );
130 unsigned int round_no = 0;
133 double r_delta = 0.0;
135 bool stop_condition =
false;
141 for(
unsigned int i = 0 ; i < m_point_set.size() ; ++i) {
149 for(std::vector<fitness_vector>::size_type idx = 0 ; idx < points.size() ; ++idx) {
150 m_boxes[idx] = compute_bounding_box(points, r_point, idx);
152 r_delta = std::max(r_delta, m_box_volume[idx]);
154 for(std::vector<fitness_vector>::size_type idx2 = 0 ; idx2 < points.size() ; ++idx2) {
158 int op = point_in_box(points[idx2], points[idx], m_boxes[idx]);
160 m_box_points[idx].push_back(idx2);
161 }
else if (ec_type == LEAST) {
178 r_delta *= m_initial_delta_coeff;
182 r_delta *= m_delta_multiplier;
185 for(
unsigned int _i = 0 ; _i < m_point_set.size() ; ++_i) {
186 unsigned int idx = m_point_set[_i];
187 sampling_round(points, r_delta , round_no, idx, log_factor);
191 sampling_round(points, m_alpha * r_delta , round_no, EC, log_factor);
194 for(
unsigned int _i = 0 ; _i < m_point_set.size() ; ++_i) {
195 unsigned int idx = m_point_set[_i];
196 if(cmp_func(m_approx_volume[idx], m_approx_volume[EC])) {
202 std::vector<unsigned int>::iterator it = m_point_set.begin();
203 while(it != m_point_set.end()) {
204 unsigned int idx = *it;
205 if ((idx != EC) && erase_condition(idx, EC, m_approx_volume, m_point_delta)) {
206 it = m_point_set.erase(it);
214 stop_condition =
false;
215 if (m_point_set.size() <= 1) {
216 stop_condition =
true;
218 stop_condition =
true;
219 for(
unsigned int _i = 0 ; _i < m_point_set.size() ; ++_i) {
220 unsigned int idx = m_point_set[_i];
224 double d = end_condition(idx, EC, m_approx_volume, m_point_delta);
225 if( d <= 0 || d > 1 + m_eps ) {
226 stop_condition =
false;
231 }
while (!stop_condition);
237 void bf_approx::sampling_round(
const std::vector<fitness_vector> &points,
const double delta,
const unsigned int round,
const unsigned int idx,
const double log_factor)
const
241 if (m_no_ops[idx] == 0) {
246 if ( m_box_points[idx].size() <= m_trivial_subcase_size || static_cast<double>(m_no_ops[idx]) >=
hypervolume::get_expected_operations(m_box_points[idx].size(), points[0].size()) ) {
247 const std::vector<unsigned int> &bp = m_box_points[idx];
248 if (bp.size() == 0) {
249 m_approx_volume[idx] = m_box_volume[idx];
252 int f_dim = points[0].size();
256 std::vector<fitness_vector> sub_front(bp.size(),
fitness_vector(f_dim, 0.0));
258 for(
unsigned int p_idx = 0 ; p_idx < sub_front.size() ; ++p_idx) {
259 for(
unsigned int d_idx = 0 ; d_idx < sub_front[0].size() ; ++d_idx) {
260 sub_front[p_idx][d_idx] = std::max( p[d_idx], points[bp[p_idx]][d_idx] );
265 hypervolume hv_obj = hypervolume(sub_front,
false);
266 hv_obj.set_copy_points(
false);
267 double hv = hv_obj.compute(refpoint);
268 m_approx_volume[idx] = m_box_volume[idx] - hv;
271 m_point_delta[idx] = 0.0;
278 double tmp = m_box_volume[idx] / delta;
279 double required_no_samples = 0.5 * ( (1. + m_gamma) * log( round ) + log_factor ) * tmp * tmp;
281 while(m_no_samples[idx] < required_no_samples) {
283 if (sample_successful(points, idx)) {
284 ++m_no_succ_samples[idx];
288 m_approx_volume[idx] =
static_cast<double>(m_no_succ_samples[idx]) / static_cast<double>(m_no_samples[idx]) * m_box_volume[idx];
289 m_point_delta[idx] = compute_point_delta(round, idx, log_factor) * m_box_volume[idx];
293 bool bf_approx::sample_successful(
const std::vector<fitness_vector> &points,
const unsigned int idx)
const
298 for(
unsigned int i = 0 ; i < lb.size() ; ++ i) {
299 rnd_p[i] = lb[i] + m_drng()*(ub[i]-lb[i]);
302 for(
unsigned int i = 0 ; i < m_box_points[idx].size() ; ++i) {
308 bool dominates =
true;
311 m_no_ops[idx] += box_p.size() + 1;
312 for(
unsigned int d_idx = 0 ; d_idx < box_p.size() ; ++d_idx) {
313 if(rnd_p[d_idx] < box_p[d_idx]) {
331 double bf_approx::compute_point_delta(
const unsigned int round_no,
const unsigned int idx,
const double log_factor)
const
334 0.5 * ((1. + m_gamma) * log(static_cast<double>(round_no)) + log_factor)
335 / (static_cast<double>(m_no_samples[idx]))
354 }
else if (cmp_a_p == 1) {
373 fitness_vector bf_approx::compute_bounding_box(
const std::vector<fitness_vector> &points,
const fitness_vector &r_point,
const unsigned int p_idx)
const
382 unsigned int f_dim = r_point.size();
383 for(std::vector<fitness_vector>::size_type idx = 0 ; idx < points.size(); ++idx) {
387 for(fitness_vector::size_type f_idx = 0; f_idx < f_dim; ++f_idx) {
388 if (points[idx][f_idx] >= p[f_idx]) {
389 if (worse_dim_idx != -1) {
393 worse_dim_idx = f_idx;
396 if (worse_dim_idx != -1){
397 z[worse_dim_idx] = std::min(z[worse_dim_idx], points[idx][worse_dim_idx]);
430 pagmo_throw(value_error,
"This algorithm can just approximate extreme contributions but not the hypervolume itself.");
443 return "Bringmann-Friedrich approximation method";
Bringmann-Friedrich approximation method.
static bool cmp_least(const double, const double)
Comparison method for the least contributor.
static double volume_between(const fitness_vector &, const fitness_vector &, unsigned int=0)
Compute volume between two points.
void assert_minimisation(const std::vector< fitness_vector > &, const fitness_vector &) const
Assert that reference point dominates every other point from the set.
static int dom_cmp(double *, double *, unsigned int)
Dominance comparison method.
static bool cmp_greatest(const double, const double)
Comparison method for the least contributor.
void verify_before_compute(const std::vector< fitness_vector > &, const fitness_vector &) const
Verify before compute method.
bf_approx(const bool use_exact=true, const unsigned int trivial_subcase_size=1, const double eps=1e-2, const double delta=1e-6, const double delta_multiplier=0.775, const double m_alpha=0.2, const double initial_delta_coeff=0.1, const double gamma=0.25)
Constructor.
double compute(std::vector< fitness_vector > &, const fitness_vector &) const
Compute hypervolume.
static double get_expected_operations(const unsigned int n, const unsigned int d)
Get expected numer of operations.
std::vector< double > fitness_vector
Fitness vector type.
unsigned int least_contributor(std::vector< fitness_vector > &, const fitness_vector &) const
Least contributor method.
boost::shared_ptr< base > base_ptr
Base hypervolume algorithm class.
unsigned int greatest_contributor(std::vector< fitness_vector > &, const fitness_vector &) const
Greatest contributor method.
std::string get_name() const
Algorithm name.
base_ptr clone() const
Clone method.