/*-------------------------------------------------------------------------------------*/
/* 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 Barrier.cpp
\brief Barrier for constraints handling (implementation)
\author Sebastien Le Digabel
\date 2010-04-12
\see Barrier.hpp
*/
#include "Barrier.hpp"
/*---------------------------------------------------------*/
/* reset the barrier */
/*---------------------------------------------------------*/
void NOMAD::Barrier::reset ( void )
{
_prefilter.clear();
_filter.clear();
_h_max = _p.get_h_max_0();
_best_feasible = NULL;
_ref = NULL;
_rho_leaps = 0;
_poll_center = NULL;
_sec_poll_center = NULL;
if ( _peb_changes > 0 )
_p.reset_PEB_changes();
_peb_changes = 0;
_peb_filter_reset = 0;
_peb_lop.clear();
_all_inserted.clear();
_one_eval_succ = _success = NOMAD::UNSUCCESSFUL;
}
/*---------------------------------------------------------*/
/* display */
/*---------------------------------------------------------*/
void NOMAD::Barrier::display ( const Display & out ) const
{
if ( _eval_type == NOMAD::SGTE )
out << "surrogate barrier" << std::endl;
if ( _p.get_barrier_type() == NOMAD::EB )
out << "extreme barrier (EB)" << std::endl;
else {
out << "type : "
<< ( (_p.get_barrier_type()==NOMAD::FILTER) ? "filter" : "progressive" )
<< std::endl
<< "h_norm : " << _p.get_h_norm() << std::endl
<< "h_min : " << _p.get_h_min() << std::endl
<< "h_max : " << _h_max << std::endl;
if ( _p.get_barrier_type()==NOMAD::PB || _p.get_barrier_type()==NOMAD::PEB_P ) {
out << "poll center trigger rho : " << _p.get_rho() << std::endl
<< "number of trigger leaps : " << _rho_leaps << std::endl;
if ( _p.get_barrier_type()==NOMAD::PEB_P )
out << "number of PEB changes : " << _peb_changes << std::endl
<< "number of PEB filter resets: " << _peb_filter_reset << std::endl;
}
if ( out.get_gen_dd() == NOMAD::FULL_DISPLAY )
out << "number of pre-filter points: " << static_cast(_prefilter.size())
<< std::endl;
out << NOMAD::open_block ( "list of filter points ("
+ NOMAD::itos ( _filter.size() )
+ ")" )
<< std::endl;
std::set::const_iterator end = _filter.end() , it;
for ( it = _filter.begin() ; it != end ; ++it )
out << *it->get_point() << std::endl;
out.close_block();
}
#ifdef DEBUG
out << NOMAD::open_block ( "list of inserted points ("
+ NOMAD::itos ( _all_inserted.size() )
+ ")" )
<< std::endl;
std::list::const_iterator it2 , end2 = _all_inserted.end();
for ( it2 = _all_inserted.begin() ; it2 != end2 ; ++it2 )
out << **it2 << std::endl;
out.close_block();
#endif
}
/*------------------------------------------------------------*/
/* barrier update: invoked by Evaluator_Control::eval_lop() */
/*------------------------------------------------------------*/
void NOMAD::Barrier::update_and_reset_success ( void )
{
if ( ( _p.get_barrier_type() == NOMAD::PB || _p.get_barrier_type() == NOMAD::PEB_P ) &&
_success != NOMAD::UNSUCCESSFUL ) {
if ( _success == NOMAD::PARTIAL_SUCCESS ) {
if ( _filter.empty() )
throw Barrier::Update_Error ( "Barrier.cpp" , __LINE__ ,
"filter empty after a partial success" );
std::set::const_iterator it = _filter.end();
--it;
while ( true ) {
if ( it->get_point()->get_h().value() < _h_max.value() ) {
set_h_max ( it->get_point()->get_h() );
break;
}
if ( it == _filter.begin() )
throw Barrier::Update_Error ( "Barrier.cpp" , __LINE__ ,
"could not find a filter point with h < h_max after a partial success" );
--it;
}
}
_ref = get_best_infeasible();
if ( _ref )
set_h_max ( _ref->get_h() );
}
// reset success types:
_one_eval_succ = _success = NOMAD::UNSUCCESSFUL;
}
/*---------------------------------------------------------*/
/* insertion of an Eval_Point in the barrier */
/*---------------------------------------------------------*/
void NOMAD::Barrier::insert ( const NOMAD::Eval_Point & x )
{
// we compare the eval types (_SGTE_ or _TRUTH_) of x and *this:
if ( x.get_eval_type() != _eval_type )
throw Barrier::Insert_Error ( "Barrier.cpp" , __LINE__ ,
"insertion of an Eval_Point into the bad Barrier object" );
// basic check:
if ( !x.is_eval_ok() ) {
_one_eval_succ = NOMAD::UNSUCCESSFUL;
return;
}
// pre-filter: if tag(x) is already in the pre-filter,
// then return _UNSUCCESSFUL_:
size_t size_before = _prefilter.size();
_prefilter.insert ( x.get_tag() );
if ( _prefilter.size() == size_before ) {
_one_eval_succ = NOMAD::UNSUCCESSFUL;
return;
}
// insertion in _all_inserted:
_all_inserted.push_back ( &x );
// other checks:
const NOMAD::Double & h = x.get_h();
if ( !x.is_EB_ok () ||
!x.get_f().is_defined () ||
!h.is_defined () ||
h.value() > _h_max.value() ) {
_one_eval_succ = NOMAD::UNSUCCESSFUL;
return;
}
// insert_feasible or insert_infeasible:
_one_eval_succ = ( x.is_feasible ( _p.get_h_min() ) ) ?
insert_feasible ( x ) : insert_infeasible(x);
if ( _one_eval_succ > _success )
_success = _one_eval_succ;
}
/*---------------------------------------------------------*/
/* update the barrier from another barrier */
/* (used by VNS search) */
/*---------------------------------------------------------*/
void NOMAD::Barrier::insert ( const Barrier & b )
{
_one_eval_succ = _success = NOMAD::UNSUCCESSFUL;
NOMAD::Eval_Point * modifiable_x;
std::list::const_iterator it , end = b._all_inserted.end();
for ( it = b._all_inserted.begin() ; it != end ; ++it ) {
modifiable_x = &NOMAD::Cache::get_modifiable_point ( **it );
modifiable_x->set_direction ( NULL );
modifiable_x->set_mesh_index ( NULL );
modifiable_x->set_poll_center_type ( NOMAD::UNDEFINED_POLL_CENTER_TYPE );
modifiable_x->set_user_eval_priority ( NOMAD::Double() );
modifiable_x->set_rand_eval_priority ( NOMAD::Double() );
insert ( **it );
if ( _one_eval_succ > _success )
_success = _one_eval_succ;
}
}
/*---------------------------------------------------------*/
/* insertion of a feasible point (private) */
/*---------------------------------------------------------*/
NOMAD::success_type NOMAD::Barrier::insert_feasible ( const NOMAD::Eval_Point & x )
{
if ( !_best_feasible || ( x.get_f().value() < _best_feasible->get_f().value() ) ) {
_best_feasible = &x;
return NOMAD::FULL_SUCCESS;
}
return NOMAD::UNSUCCESSFUL;
}
/*---------------------------------------------------------*/
/* filter insertion (private) */
/*---------------------------------------------------------*/
void NOMAD::Barrier::filter_insertion ( const NOMAD::Eval_Point & x , bool & insert )
{
if ( _filter.empty() ) {
_filter.insert (&x);
insert = true;
}
else {
insert = false;
std::set::iterator it = _filter.begin();
while ( it != _filter.end() ) {
if ( x < *(it->get_point()) ) {
_filter.erase(it++);
insert = true;
continue;
}
++it;
}
if ( !insert ) {
insert = true;
std::set::iterator end = _filter.end();
for ( it = _filter.begin() ; it != end ; ++it ) {
if ( *(it->get_point()) < x ) {
insert = false;
break;
}
}
}
if ( insert )
_filter.insert (&x);
}
}
/*---------------------------------------------------------*/
/* insertion of an infeasible point (private) */
/*---------------------------------------------------------*/
NOMAD::success_type NOMAD::Barrier::insert_infeasible ( const NOMAD::Eval_Point & x )
{
const NOMAD::Eval_Point * old_bi = get_best_infeasible();
// filter insertion:
// -----------------
bool insert;
filter_insertion ( x , insert );
// filter:
// -------
if ( _p.get_barrier_type() == NOMAD::FILTER ) {
const NOMAD::Eval_Point * bi = get_best_infeasible();
if ( !bi )
return NOMAD::UNSUCCESSFUL;
if ( old_bi ) {
if ( bi->get_h().value() < old_bi->get_h().value() )
return NOMAD::FULL_SUCCESS;
if ( insert )
return NOMAD::PARTIAL_SUCCESS;
return NOMAD::UNSUCCESSFUL;
}
return NOMAD::FULL_SUCCESS;
}
// progressive barrier:
// --------------------
// with PEB constraints, we remember all points that we tried to insert:
if ( _p.get_barrier_type() == NOMAD::PEB_P )
_peb_lop.push_back ( &x );
// first infeasible successes are considered as partial successes
// (improving iterations)
if ( !_ref )
return NOMAD::PARTIAL_SUCCESS;
double hx = x.get_h().value();
double fx = x.get_f().value();
double hr = _ref->get_h().value();
double fr = _ref->get_f().value();
// failure:
if ( hx > hr || ( hx == hr && fx >= fr ) )
return NOMAD::UNSUCCESSFUL;
// partial success:
if ( fx > fr )
return NOMAD::PARTIAL_SUCCESS;
// full success:
return NOMAD::FULL_SUCCESS;
}
/*---------------------------------------------------------*/
/* get_best_infeasible() */
/*---------------------------------------------------------*/
const NOMAD::Eval_Point * NOMAD::Barrier::get_best_infeasible ( void ) const
{
if ( _filter.empty() || _p.get_barrier_type() == NOMAD::EB )
return NULL;
if ( _p.get_barrier_type() == NOMAD::FILTER )
return _filter.begin()->get_point(); // original
return (--_filter.end())->get_point(); // original
}
/*---------------------------------------------------------*/
/* get_best_infeasible_min_viol() */
/*---------------------------------------------------------*/
const NOMAD::Eval_Point * NOMAD::Barrier::get_best_infeasible_min_viol ( void ) const
{
if ( _filter.empty() || _p.get_barrier_type() == NOMAD::EB )
return NULL;
if ( _p.get_barrier_type() == NOMAD::FILTER )
return (--_filter.end())->get_point();
return _filter.begin()->get_point();
}
/*---------------------------------------------------------*/
/* poll center selection */
/*---------------------------------------------------------*/
void NOMAD::Barrier::select_poll_center ( NOMAD::success_type last_it_success )
{
const NOMAD::Eval_Point * best_infeasible = get_best_infeasible();
_sec_poll_center = NULL;
if ( !_best_feasible && !best_infeasible ) {
_poll_center = NULL;
return;
}
if ( !best_infeasible ) {
_poll_center = _best_feasible;
return;
}
if ( !_best_feasible ) {
_poll_center = best_infeasible;
return;
}
// filter:
if ( _p.get_barrier_type() == NOMAD::FILTER ) {
if ( !_poll_center ) {
_poll_center = _best_feasible;
return;
}
// switch:
if ( last_it_success == NOMAD::UNSUCCESSFUL )
_poll_center = ( _poll_center==best_infeasible ) ?
_best_feasible : best_infeasible;
return;
}
// progressive barrier:
if ( _p.get_barrier_type() == NOMAD::PB || _p.get_barrier_type() == NOMAD::PEB_P ) {
const NOMAD::Point * last_poll_center = _poll_center;
if ( best_infeasible->get_f() < (_best_feasible->get_f() - _p.get_rho()) ) {
_poll_center = best_infeasible;
_sec_poll_center = _best_feasible;
}
else {
_poll_center = _best_feasible;
_sec_poll_center = best_infeasible;
}
if ( _poll_center != last_poll_center )
++_rho_leaps;
}
}
/*---------------------------------------------------------*/
/* change the value of _h_max (private) */
/*---------------------------------------------------------*/
void NOMAD::Barrier::set_h_max ( const NOMAD::Double & h_max )
{
// _h_max update:
_h_max = h_max;
// we remove all filter points x such that h(x) > h_max:
if ( !_filter.empty() ) {
if ( _filter.begin()->get_point()->get_h().value() > _h_max.value() ) {
_filter.clear();
return;
}
std::set::iterator it = _filter.end();
do
--it;
while ( it != _filter.begin() &&
it->get_point()->get_h().value() > _h_max.value() );
++it;
_filter.erase ( it , _filter.end() );
}
}
/*--------------------------------------------------------*/
/* check the PEB constraints to change eventually their */
/* status from _PEB_P_ to _PEB_E_ */
/*--------------------------------------------------------*/
void NOMAD::Barrier::check_PEB_constraints ( const NOMAD::Eval_Point & x , bool display )
{
const NOMAD::Double & h_min = _p.get_h_min();
const std::vector & bbot = _p.get_bb_output_type();
const NOMAD::Point & bbo = x.get_bb_outputs();
int nb = static_cast(bbot.size());
std::list ks;
for ( int k = 0 ; k < nb ; ++k ) {
if ( bbot[k] == NOMAD::PEB_P && bbo[k] <= h_min ) {
if ( display )
_p.out() << std::endl
<< "change status of blackbox output " << k
<< " from progressive barrier constraint to extreme barrier constraint"
<< std::endl;
++_peb_changes;
_p.change_PEB_constraint_status (k);
ks.push_back(k);
}
}
// at least one constraint changed status, so we have to update the filter
// and remove all points that have their h value changed to infinity
// (it can add new dominant points from the list _peb_lop):
if ( !ks.empty() ) {
std::list::const_iterator it_k , end_k = ks.end() , begin_k = ks.begin();
// we inspect the filter points if some have to be removed; if so,
// all filter candidates (stored in _peb_lop) will be re-inserted
// into the filter:
bool reset_filter = false;
std::set::const_iterator end = _filter.end() , it;
for ( it = _filter.begin() ; it != end ; ++it ) {
const NOMAD::Point & bbo_cur = it->get_point()->get_bb_outputs();
for ( it_k = begin_k ; it_k != end_k ; ++it_k )
if ( bbo_cur[*it_k] > h_min ) {
reset_filter = true;
break;
}
if ( reset_filter )
break;
}
if ( reset_filter ) {
if ( display )
_p.out() << std::endl << "PEB change of status: filter reset" << std::endl;
++_peb_filter_reset;
_filter.clear();
bool insert;
std::list::const_iterator end2 = _peb_lop.end ();
std::list::iterator it2 = _peb_lop.begin();
while ( it2 != end2 ) {
insert = true;
const NOMAD::Point & bbo_cur = (*it2)->get_bb_outputs();
for ( it_k = begin_k ; it_k != end_k ; ++it_k )
if ( bbo_cur[*it_k] > h_min ) {
insert = false;
break;
}
// if insert==true: this point is potentially a new filter point:
if ( insert ) {
filter_insertion ( **it2 , insert );
++it2;
}
// if insert==false: it means that the current filter point
// has to be removed from filter and from _peb_lop, and
// in addition, its h is put to INF:
else {
NOMAD::Cache::get_modifiable_point ( **it2 ).set_h ( NOMAD::Double() );
_peb_lop.erase(it2++);
}
}
}
}
}