/*-------------------------------------------------------------------------------------*/
/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */
/* */
/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */
/* Charles Audet - Ecole Polytechnique, Montreal */
/* Gilles Couture - Ecole Polytechnique, Montreal */
/* John Dennis - Rice University, Houston */
/* Sebastien Le Digabel - Ecole Polytechnique, Montreal */
/* Christophe Tribes - Ecole Polytechnique, Montreal */
/* */
/* funded in part by AFOSR and Exxon Mobil */
/* */
/* Author: Sebastien Le Digabel */
/* */
/* Contact information: */
/* Ecole Polytechnique de Montreal - GERAD */
/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */
/* e-mail: nomad@gerad.ca */
/* phone : 1-514-340-6053 #6928 */
/* fax : 1-514-340-5665 */
/* */
/* This program is free software: you can redistribute it and/or modify it under the */
/* terms of the GNU Lesser General Public License as published by the Free Software */
/* Foundation, either version 3 of the License, or (at your option) any later */
/* version. */
/* */
/* This program is distributed in the hope that it will be useful, but WITHOUT ANY */
/* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A */
/* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public License along */
/* with this program. If not, see . */
/* */
/* You can find information on the NOMAD software at www.gerad.ca/nomad */
/*-------------------------------------------------------------------------------------*/
/**
\file Pareto_Front.cpp
\brief Pareto front (implementation)
\author Sebastien Le Digabel
\date 2010-04-09
\see Pareto_Front.hpp
*/
#include "Pareto_Front.hpp"
/*------------------------------------------------------*/
/* insertion of a point */
/* (returns true if the point is a new Pareto point) */
/*------------------------------------------------------*/
bool NOMAD::Pareto_Front::insert ( const NOMAD::Eval_Point & x )
{
NOMAD::Pareto_Point pp ( &x );
if ( _pareto_pts.empty() ) {
_pareto_pts.insert (pp);
return true;
}
bool insert = false;
std::set::iterator it = _pareto_pts.begin();
while ( it != _pareto_pts.end() ) {
if ( pp.dominates (*it) ) {
_pareto_pts.erase(it++);
insert = true;
continue;
}
++it;
}
if ( !insert ) {
insert = true;
std::set::iterator end = _pareto_pts.end();
for ( it = _pareto_pts.begin() ; it != end ; ++it ) {
if ( it->dominates (pp) ) {
insert = false;
break;
}
}
}
if ( insert ) {
_pareto_pts.insert ( pp );
return true;
}
return false;
}
/*-------------------------------------------------------*/
/* get the point that minimizes f2(x) */
/* (this is simply the last point of the Pareto front) */
/*-------------------------------------------------------*/
const NOMAD::Eval_Point * NOMAD::Pareto_Front::get_best_f2 ( void ) const
{
if ( _pareto_pts.empty() )
return NULL;
std::set::const_iterator it = _pareto_pts.end();
--it;
return it->get_element();
}
/*------------------------------------------------------*/
/* get the reference point */
/*------------------------------------------------------*/
NOMAD::Point * NOMAD::Pareto_Front::get_ref ( const NOMAD::Pareto_Point *& xj ,
NOMAD::Double & delta_j ) const
{
xj = NULL;
delta_j.clear();
int p = static_cast(_pareto_pts.size());
// no points in the front:
if ( p == 0 )
return NULL;
// just one point in the front:
if ( p == 1 ) {
xj = &(*_pareto_pts.begin());
delta_j = 1.0 / ( xj->get_w() + 1 ); // delta=1.0
return NULL;
}
std::set::const_iterator it = _pareto_pts.begin();
NOMAD::Point * ref = new NOMAD::Point ( 2 );
NOMAD::Double f1xm1; // f_1 ( x_{j-1} )
NOMAD::Double f1x; // f_1 ( x_j )
NOMAD::Double f1xp1; // f_1 ( x_{j+1} )
NOMAD::Double f2xm1; // f_2 ( x_{j-1} )
NOMAD::Double f2x; // f_2 ( x_j )
NOMAD::Double f2xp1; // f_2 ( x_{j+1} )
// two points in the front:
if ( p == 2 ) {
f1xm1 = it->get_f1();
f2xm1 = it->get_f2();
++it;
xj = &(*it);
f1x = xj->get_f1();
f2x = xj->get_f2();
delta_j = ( (f1x-f1xm1).pow2() + (f2x-f2xm1).pow2() ) / ( xj->get_w() + 1.0 );
const_cast(xj)->update_w();
(*ref)[0] = f1x;
(*ref)[1] = f2xm1;
return ref;
}
// more than two points in the front:
std::set::const_iterator end = _pareto_pts.end();
const NOMAD::Pareto_Point * prev , * cur , * next;
NOMAD::Double delta;
prev = &(*it);
++it;
while ( true ) {
cur = &(*it);
++it;
if ( it == end )
break;
next = &(*it);
f1xm1 = prev->get_f1();
f2xm1 = prev->get_f2();
f1x = cur->get_f1();
f2x = cur->get_f2();
f1xp1 = next->get_f1();
f2xp1 = next->get_f2();
delta = ( (f1x-f1xm1).pow2() + (f2x-f2xm1).pow2() +
(f1x-f1xp1).pow2() + (f2x-f2xp1).pow2() ) / ( cur->get_w() + 1.0 );
if ( !delta_j.is_defined() || delta > delta_j ) {
xj = cur;
delta_j = delta;
(*ref)[0] = f1xp1;
(*ref)[1] = f2xm1;
}
prev = cur;
}
const_cast(xj)->update_w();
return ref;
}
/*------------------------------------------------------*/
/* compute delta and surf */
/*------------------------------------------------------*/
void NOMAD::Pareto_Front::get_delta_surf ( NOMAD::Double & delta_j ,
NOMAD::Double & surf ,
const NOMAD::Point & f_bounds ) const
{
bool def = f_bounds.is_complete();
NOMAD::Double f1_min , f1_max , f2_min , f2_max;
if ( def ) {
if ( f_bounds.size() == 4 ) {
f1_min = f_bounds[0];
f1_max = f_bounds[1];
f2_min = f_bounds[2];
f2_max = f_bounds[3];
if ( f1_min >= f1_max || f2_min >= f2_max ) {
f1_min.clear();
f1_max.clear();
f2_min.clear();
f2_max.clear();
def = false;
}
}
else
def = false;
}
delta_j.clear();
surf.clear();
int p = static_cast ( _pareto_pts.size() );
// no point in the front:
if ( p == 0 ) {
if ( def )
surf = 1.0;
return;
}
const NOMAD::Pareto_Point * xj;
NOMAD::Double f1x; // f_1 ( x_j )
NOMAD::Double f2x; // f_2 ( x_j )
NOMAD::Double surf_frame = (def) ?
( f2_max - f2_min ) * ( f1_max - f1_min )
: NOMAD::Double();
// just one point in the front:
if ( p == 1 ) {
xj = &(*_pareto_pts.begin());
delta_j = 1.0 / ( xj->get_w() + 1 ); // delta=1.0
f1x = xj->get_f1();
f2x = xj->get_f2();
if ( !def || f1x > f1_max || f1x < f1_min || f2x > f2_max || f2x < f2_min )
return;
surf = ( ( f2_max - f2_min ) * ( f1x - f1_min )
+ ( f2x - f2_min ) * ( f1_max - f1x ) ) / surf_frame;
return;
}
std::set::const_iterator it = _pareto_pts.begin();
NOMAD::Double f1xm1; // f_1 ( x_{j-1} )
NOMAD::Double f1xp1; // f_1 ( x_{j+1} )
NOMAD::Double f2xm1; // f_2 ( x_{j-1} )
NOMAD::Double f2xp1; // f_2 ( x_{j+1} )
// two points in the front:
if ( p == 2 ) {
f1xm1 = it->get_f1();
f2xm1 = it->get_f2();
if ( def && ( f1xm1 < f1_min ||
f1xm1 > f1_max ||
f2xm1 < f2_min ||
f2xm1 > f2_max ) )
def = false;
++it;
xj = &(*it);
f1x = xj->get_f1();
f2x = xj->get_f2();
if ( def && ( f1x < f1_min ||
f1x > f1_max ||
f2x < f2_min ||
f2x > f2_max ) )
def = false;
delta_j = ( (f1x-f1xm1).pow2() + (f2x-f2xm1).pow2() ) / ( xj->get_w() + 1.0 );
if ( def )
surf = ( ( f2xm1 - f2_min ) * ( f1x - f1xm1 )
+ ( f2_max - f2_min ) * ( f1xm1 - f1_min )
+ ( f2x - f2_min ) * ( f1_max - f1x ) ) / surf_frame;
return;
}
// more than two points in the front:
std::set::const_iterator end = _pareto_pts.end();
const NOMAD::Pareto_Point * prev , * cur , * next;
NOMAD::Double delta;
prev = &(*it);
f1xm1 = prev->get_f1();
f2xm1 = prev->get_f2();
++it;
cur = &(*it);
f1x = cur->get_f1();
if ( def && ( f1xm1 < f1_min ||
f1xm1 > f1_max ||
f2xm1 < f2_min ||
f2xm1 > f2_max ||
f1x < f1_min ||
f1x > f1_max ) )
def = false;
if ( def )
surf = ( f2xm1 - f2_min ) * ( f1x - f1xm1 )
+ ( f2_max - f2_min ) * ( f1xm1 - f1_min );
while ( true ) {
cur = &(*it);
++it;
if ( it == end )
break;
next = &(*it);
f1xm1 = prev->get_f1();
f2xm1 = prev->get_f2();
f1x = cur->get_f1();
f2x = cur->get_f2();
f1xp1 = next->get_f1();
f2xp1 = next->get_f2();
if ( def &&
( f1xm1 < f1_min || f1xm1 > f1_max || f2xm1 < f2_min || f2xm1 > f2_max ||
f1x < f1_min || f1x > f1_max || f2x < f2_min || f2x > f2_max ||
f1xp1 < f1_min || f1xp1 > f1_max || f2xp1 < f2_min || f2xp1 > f2_max ) )
def = false;
delta = ( (f1x-f1xm1).pow2() + (f2x-f2xm1).pow2() +
(f1x-f1xp1).pow2() + (f2x-f2xp1).pow2() ) / ( cur->get_w() + 1.0 );
if ( !delta_j.is_defined() || delta > delta_j )
delta_j = delta;
if ( def )
surf += ( f2x - f2_min ) * ( f1xp1 - f1x );
prev = cur;
}
if ( def ) {
surf += ( f2xp1 - f2_min ) * ( f1_max - f1xp1 );
surf = surf / surf_frame;
}
else
surf.clear();
}
/*------------------------------------------------------*/
/* display the Pareto points */
/*------------------------------------------------------*/
void NOMAD::Pareto_Front::display ( const NOMAD::Display & out ) const
{
size_t nb = _pareto_pts.size();
int cnt = 0;
std::set::const_iterator it , end = _pareto_pts.end();
for ( it = _pareto_pts.begin() ; it != end ; ++it ) {
out << "#";
out.display_int_w ( cnt++ , static_cast(nb) );
out << " ";
it->display ( out );
out << std::endl;
}
}
/*------------------------------------------------------------------*/
/* . begin() and next() methods, to browse the front */
/* */
/* . example: */
/* */
/* const Eval_Point * cur = pareto_front.begin(); */
/* while (cur) { */
/* ... */
/* cur = pareto_front.next(); */
/* } */
/*------------------------------------------------------------------*/
// begin():
// --------
const NOMAD::Eval_Point * NOMAD::Pareto_Front::begin ( void ) const
{
if ( _pareto_pts.empty() )
return NULL;
_it = _pareto_pts.begin();
return _it->get_element();
}
// next(): (supposes that begin() has been called)
// -------
const NOMAD::Eval_Point * NOMAD::Pareto_Front::next ( void ) const
{
if ( _pareto_pts.empty() )
return NULL;
++_it;
if ( _it == _pareto_pts.end() )
return NULL;
return _it->get_element();
}