diff --git a/tools/PSD-MADS_library_mode/Cache_Server.cpp b/tools/PSD-MADS_library_mode/Cache_Server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b7842fba607e33f96583eacfc4587d9e9d83b631 --- /dev/null +++ b/tools/PSD-MADS_library_mode/Cache_Server.cpp @@ -0,0 +1,892 @@ +#include "Cache_Server.hpp" +using namespace std; +using namespace NOMAD; + +/*--------------------------*/ +/* tags and signal values */ +/*--------------------------*/ +const int Cache_Server::TAG_SIGNAL = 0; +const int Cache_Server::TAG_CACHE_HIT = 1; +const int Cache_Server::TAG_X1 = 2; +const int Cache_Server::TAG_X2 = 3; +const int Cache_Server::TAG_X3 = 4; +const int Cache_Server::TAG_X4 = 5; +const int Cache_Server::TAG_X5 = 6; +const int Cache_Server::TAG_X6 = 7; +const int Cache_Server::TAG_X7 = 8; +const int Cache_Server::TAG_BBOR = 9; +const int Cache_Server::TAG_BBOC = 10; +const int Cache_Server::TAG_NB_EP = 11; +const int Cache_Server::TAG_EP = 12; +const int Cache_Server::TAG_BF = 13; +char Cache_Server::STOP_SIGNAL = 'S'; +char Cache_Server::FIND_SIGNAL = 'F'; +char Cache_Server::INSERT_SIGNAL = 'I'; +char Cache_Server::NB_EP_SIGNAL = 'N'; +char Cache_Server::EP_SIGNAL = 'E'; +char Cache_Server::BF_SIGNAL = 'B'; + +/*-----------------------------------*/ +/* constructor */ +/*-----------------------------------*/ +Cache_Server::Cache_Server ( const Display & out , + int rank , + int np , + const Double & h_min , + int max_bbe , + bool allow_multiple_evals , + bool debug ) +: Cache ( out , TRUTH ) , +_rank ( rank ) , +_np ( np ) , +_debug ( debug ) , +_h_min ( h_min ) , +_max_bbe ( max_bbe ) , +_bf ( NULL ) , +_bi1 ( NULL ) , +_bi2 ( NULL ) , +_multiple_evals ( 0 ) , +_cache_hits ( 0 ) , +_cache_search_pts ( 0 ) , +_waited_pts ( NULL ) , +_clients_ext_pts ( NULL ) { + + // cache server: + if ( _rank == _np - 1 ) { + + _clients_ext_pts = new list<const Eval_Point*> [_np]; + + if ( !allow_multiple_evals ) { + _waited_pts = new Point * [_np]; + for ( int i = 0 ; i < _np ; ++i ) + _waited_pts[i] = NULL; + } + } +} + +/*-----------------------------------*/ +/* destructor */ +/*-----------------------------------*/ +Cache_Server::~Cache_Server ( void ) { + if ( _waited_pts ) { + for ( int i = 0 ; i < _np ; ++i ) + if ( _waited_pts[i] ) + delete _waited_pts; + delete [] _waited_pts; + } + + if ( _clients_ext_pts ) + delete [] _clients_ext_pts; +} + +/*-----------------------------------*/ +/* start the server (process np-1) */ +/*-----------------------------------*/ +void Cache_Server::start ( void ) { + + int npm1 = _np-1; + + if ( _rank != npm1 ) + return; + + MPI_Status status; + int nb_stops = 0; + int source; + char signal; + + /*-------------*/ + /* main loop */ + /*-------------*/ + while ( nb_stops != npm1 ) { + + MPI_Recv ( &signal , 1 , MPI_CHAR , MPI_ANY_SOURCE , + Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD , &status ); + + source = status.MPI_SOURCE; + + // stop signal: + // ------------ + if ( signal == Cache_Server::STOP_SIGNAL ) { + if ( _debug ) + _out << "CACHE SERVER: STOP SIGNAL FROM RANK " << source << endl; + ++nb_stops; + } + + // find signal: + // ------------ + else if ( signal == Cache_Server::FIND_SIGNAL ) { + if ( _debug ) + _out << "CACHE SERVER: FIND SIGNAL FROM RANK " << source << endl; + process_find_signal ( source ); + } + + // insert signal: + // -------------- + else if ( signal == Cache_Server::INSERT_SIGNAL ) { + if ( _debug ) { + _out << "CACHE SERVER: INSERT SIGNAL FROM RANK " + << source; + if ( source == 1 ) + _out << " (POLLSTER)"; + _out << endl; + } + process_insert_signal ( source ); + } + + // number of extern points signal: + // ------------------------------- + else if ( signal == Cache_Server::NB_EP_SIGNAL ) { + if ( _debug ) { + _out << "CACHE SERVER: NB EXTERN POINTS SIGNAL FROM RANK " + << source; + if ( source == 1 ) + _out << " (POLLSTER)"; + _out << endl; + } + int nb_client_extern_pts = _clients_ext_pts[source].size(); + MPI_Rsend ( &nb_client_extern_pts , 1 , MPI_INT , source , + Cache_Server::TAG_NB_EP , MPI_COMM_WORLD ); + } + + // extern point signal: + // -------------------- + else if ( signal == Cache_Server::EP_SIGNAL ) { + if ( _debug ) { + _out << "CACHE SERVER: EXTERN POINT SIGNAL FROM RANK " + << source; + if ( source == 1 ) + _out << " (POLLSTER)"; + _out << endl; + } + process_ep_signal ( source ); + } + + // best feasible point signal: + else if ( signal == Cache_Server::BF_SIGNAL ) { + if ( _debug ) { + _out << "CACHE SERVER: BEST FEASIBLE POINT SIGNAL FROM RANK " + << source; + if ( source == 1 ) + _out << " (POLLSTER)"; + } + process_bf_signal ( source ); + } + } +} + +/*---------------------------------*/ +/* stop the server (clients) */ +/*---------------------------------*/ +void Cache_Server::stop ( void ) const { + + int npm1 = _np-1; + + if ( _rank == npm1 ) + return; + + MPI_Send ( &Cache_Server::STOP_SIGNAL , 1 , MPI_CHAR , + npm1 , Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD ); +} + +/*----------------------------------------------*/ +/* process the best feasible point signal */ +/*----------------------------------------------*/ +void Cache_Server::process_bf_signal ( int source ) const { + + char pt_flag = (_bf) ? '1' : '0'; + + MPI_Rsend ( &pt_flag , 1 , MPI_CHAR , source , + Cache_Server::TAG_BF , MPI_COMM_WORLD ); + + if ( _bf ) { + int n = _bf->size(); + double * rtab = new double[n+2]; + for ( int i = 0 ; i < n ; ++i ) + rtab[i] = (*_bf)[i].value(); + rtab[n] = _bf->get_h().value(); + rtab[n+1] = _bf->get_f().value(); + + MPI_Send ( rtab , n+2 , MPI_DOUBLE , source , + Cache_Server::TAG_X7 , MPI_COMM_WORLD ); + + delete [] rtab; + } + +} + +/*---------------------------------------*/ +/* process the extern point signal */ +/*---------------------------------------*/ +void Cache_Server::process_ep_signal ( int source ) const { + + int nb_pt = ( _clients_ext_pts[source].size() > 0 ) ? 1 : 0; + + MPI_Rsend ( &nb_pt , 1 , MPI_INT , source , + Cache_Server::TAG_EP , MPI_COMM_WORLD ); + + // send and remove the extern point: + if ( nb_pt > 0 ) { + + const Eval_Point * x = *(_clients_ext_pts[source].begin()); + + ++_cache_search_pts; + + // send the point : + int i , n = x->size() , m = x->get_m(); + int itab[5]; + itab[0] = n; + itab[1] = m; + itab[2] = ( x->is_eval_ok() ) ? 1 : 0; + + if ( x->get_signature() && (x->get_signature()->get_mesh()->get_mesh_indices())[0].is_defined() ) + { + itab[3]=1; + itab[4]=static_cast<int>((x->get_signature()->get_mesh()->get_mesh_indices())[0].value()); + } + else + itab[3] = itab[4] = 0; + + double * rtab = new double[n+2*m]; + for ( i = 0 ; i < n ; ++i ) + rtab[i] = (*x)[i].value(); + + const Point & bbo = x->get_bb_outputs(); + + for ( i = 0 ; i < m ; ++i ) + if ( bbo[i].is_defined() ) { + rtab[2*i+n ] = 1.0; + rtab[2*i+n+1] = bbo[i].value(); + } + else + rtab[2*i+n] = rtab[2*i+n+1] = -1.0; + + MPI_Send ( itab , 5 , MPI_INT , source , + Cache_Server::TAG_X5 , MPI_COMM_WORLD ); + + MPI_Send ( rtab , n+2*m , MPI_DOUBLE , source , + Cache_Server::TAG_X6 , MPI_COMM_WORLD ); + + // remove the point: + _clients_ext_pts[source].pop_front(); + } +} + +/*-------------------------------*/ +/* process the find signal */ +/*-------------------------------*/ +void Cache_Server::process_find_signal ( int source ) const { + + MPI_Status status; + int i; + + // receive the point coordinates: + int itab[2]; + MPI_Recv ( itab , 2 , MPI_INT , source , + Cache_Server::TAG_X1 , MPI_COMM_WORLD , &status ); + + int n = itab[0]; + int m = itab[1]; + + double * rtab = new double[n]; + + MPI_Recv ( rtab , n , MPI_DOUBLE , source , + Cache_Server::TAG_X2 , MPI_COMM_WORLD , &status ); + + // create the Eval_Point to search: + Eval_Point * x = new Eval_Point ( n , m ); + + for ( i = 0 ; i < n ; ++i ) + (*x)[i] = rtab[i]; + + delete [] rtab; + + // search in cache, or stop the algorithm: + const Eval_Point * cache_x; + + if ( _max_bbe > 0 && size() >= _max_bbe ) { + Eval_Point * stop_point = new Eval_Point ( n , m ); + for ( i = 0 ; i < n ; ++i ) + (*stop_point)[i] = (*x)[i]; + stop_point->set_eval_status ( EVAL_FAIL ); + cache_x = stop_point; + } + else + cache_x = Cache::find ( *x ); + + // cache hit signal : + int cache_hit; + + // point in cache : + if ( cache_x ) { + + delete x; + + cache_hit = 1; + + ++_cache_hits; + + MPI_Rsend ( &cache_hit , 1 , MPI_INT , source , + Cache_Server::TAG_CACHE_HIT , MPI_COMM_WORLD ); + + // bb output values, defined values and eval_ok flag: + rtab = new double[m]; + char * ctab = new char [m+1]; + const Point & bbo = cache_x->get_bb_outputs(); + + for ( i = 0 ; i < m ; ++i ) { + if ( bbo[i].is_defined() ) { + rtab[i] = bbo[i].value(); + ctab[i] = '1'; + } + else { + rtab[i] = INF; + ctab[i] = '0'; + } + } + + ctab[m] = ( cache_x->is_eval_ok() ) ? '1' : '0'; + + MPI_Send ( rtab , m , MPI_DOUBLE , source , + Cache_Server::TAG_BBOR , MPI_COMM_WORLD ); + + MPI_Send ( ctab , m+1 , MPI_CHAR , source , + Cache_Server::TAG_BBOC , MPI_COMM_WORLD ); + + delete [] rtab; + delete [] ctab; + + // remove this point from _clients_ext_pts: + { + list<const Eval_Point *>::iterator + it = _clients_ext_pts[source].begin() , + end = _clients_ext_pts[source].end (); + while ( it != end ) { + if ( *it == cache_x ) { + _clients_ext_pts[source].erase(it); + break; + } + ++it; + } + } + } + + // point not in cache : + else { + + cache_hit = 0; + + // evaluation in progress ? + if ( _waited_pts ) { + + for ( i = 0 ; i < _np ; ++i ) + if ( _waited_pts[i] && *_waited_pts[i] == *x ) { + cache_hit = -1; + break; + } + + if ( cache_hit == 0 ) + _waited_pts[source] = x; + else + delete x; + } + else + delete x; + + MPI_Rsend ( &cache_hit , 1 , MPI_INT , source , + Cache_Server::TAG_CACHE_HIT , MPI_COMM_WORLD ); + } +} + +/*--------------------*/ +/* find a point */ +/*--------------------*/ +const Eval_Point * Cache_Server::find ( const Eval_Point & x ) const { + + int npm1 = _np-1; + + // server: + if ( _rank == npm1 ) + return Cache::find ( x ); + + // A. search in local cache: + const Eval_Point * cache_x = Cache::find ( x ); + if ( cache_x ) + return cache_x; + + // B. ask the server. + int i , n = x.size() , m = x.get_m(); + int itab[2]; + itab[0] = n; + itab[1] = m; + double * rtab = new double[n]; + for ( i = 0 ; i < n ; ++i ) + rtab[i] = x[i].value(); + + int cache_hit = -1; + MPI_Request req = MPI_REQUEST_NULL; + MPI_Status status; + + while ( cache_hit < 0 ) { + + // B1. send a request for cache_hit: + MPI_Irecv ( &cache_hit , 1 , MPI_INT , npm1 , + Cache_Server::TAG_CACHE_HIT , MPI_COMM_WORLD , &req ); + + // B2. send the find signal: + MPI_Send ( &Cache_Server::FIND_SIGNAL , 1 , MPI_CHAR , + npm1 , Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD ); + + // B3. send the point coordinates: + MPI_Send ( itab , 2 , MPI_INT , npm1 , + Cache_Server::TAG_X1 , MPI_COMM_WORLD ); + MPI_Send ( rtab , n , MPI_DOUBLE , npm1 , + Cache_Server::TAG_X2 , MPI_COMM_WORLD ); + + // B4. wait for the cache_hit request: + MPI_Wait ( &req , &status ); + + // cache hit possible values: + // + // -1: point is being evaluated by another process (wait) + // 0: point not in cache server + // 1: point in cache server + } + + delete [] rtab; + + // C. cache hit: receive the point outputs: + if ( cache_hit == 1 ) { + + // C.1. bb output values and eval status: + rtab = new double[m]; + MPI_Recv ( rtab , m , MPI_DOUBLE , npm1 , + Cache_Server::TAG_BBOR , MPI_COMM_WORLD , &status ); + + char * ctab = new char[m+1]; + MPI_Recv ( ctab , m+1 , MPI_CHAR , npm1 , + Cache_Server::TAG_BBOC , MPI_COMM_WORLD , &status ); + + Point bbo(m); + for ( i = 0 ; i < m ; ++i ) + if ( ctab[i]=='1' ) + bbo[i] = rtab[i]; + + delete [] rtab; + + // C.2. eval point construction: + Eval_Point * y = new Eval_Point ( n , m ); + y->set_bb_output ( bbo ); + for ( i = 0 ; i < n ; ++i ) + (*y)[i] = x[i]; + + y->set_eval_status ( (ctab[m]=='1') ? EVAL_OK : EVAL_FAIL ); + + y->set_current_run ( x.get_current_run() ); + + delete [] ctab; + + cache_x = y; + + + // C.3. insertion in local cache: + const_cast<Cache_Server*>(this)->Cache::insert ( *cache_x ); + } + + return cache_x; +} + +/*------------------------------------*/ +/* process the insertion signal */ +/*------------------------------------*/ +void Cache_Server::process_insert_signal ( int source ) { + + if ( _waited_pts && _waited_pts[source] ) { + delete _waited_pts[source]; + _waited_pts[source] = NULL; + } + + MPI_Status status; + + // receive the evaluation point: + int itab[7]; + MPI_Recv ( itab , 7 , MPI_INT , source , + Cache_Server::TAG_X3 , MPI_COMM_WORLD , &status ); + + int n = itab[0]; + int m = itab[1]; + + double * rtab = new double[n+2*m+2]; + + MPI_Recv ( rtab , n+2*m+2 , MPI_DOUBLE , source , + Cache_Server::TAG_X4 , MPI_COMM_WORLD , &status ); + + // create the Eval_Point to insert: + Eval_Point * x = new Eval_Point ( n , m ); + + int i; + for ( i = 0 ; i < n ; ++i ) + (*x)[i] = rtab[i]; + + for ( i = 0 ; i < m ; ++i ) + if ( rtab[2*i+n] > 0 ) + x->set_bb_output ( i , rtab[2*i+n+1] ); + + if ( itab[5] == 1 ) + x->set_f ( rtab[n+2*m ] ); + + if ( itab[6] == 1 ) + x->set_h ( rtab[n+2*m+1] ); + + delete [] rtab; + + x->set_eval_status ( ( itab[2] == 1 ) ? EVAL_OK : EVAL_FAIL ); + + // Eval_Point insertion in cache and multiple_evals detection: + const Eval_Point * cache_x = Cache::find ( *x ); + if ( cache_x ) { + ++_multiple_evals; + delete x; + x = const_cast<Eval_Point *>(cache_x); + } + else + Cache::insert ( *x ); + + // update the best points: + update_best_points ( *x , source ); +} + +/*--------------------*/ +/* insert a point */ +/*--------------------*/ +void Cache_Server::insert ( const NOMAD::Eval_Point & x ) { + + // insertion in local cache : + Cache::insert ( x ); + + int npm1 = _np-1; + if ( _rank == npm1 ) + return; + + // insert signal : + MPI_Send ( &Cache_Server::INSERT_SIGNAL , 1 , MPI_CHAR , + npm1 , Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD ); + + // send the point : + int i , n = x.size() , m = x.get_m(); + int itab[7]; + itab[0] = n; + itab[1] = m; + itab[2] = ( x.is_eval_ok() ) ? 1 : 0; + + if ( x.get_signature() && (x.get_signature()->get_mesh()->get_mesh_indices())[0].is_defined() ) + { + itab[3]=1; + itab[4]=static_cast<int>((x.get_signature()->get_mesh()->get_mesh_indices())[0].value()); + } + else + itab[3] = itab[4] = 0; + + double * rtab = new double[n+2*m+2]; + for ( i = 0 ; i < n ; ++i ) + rtab[i] = x[i].value(); + + const Point & bbo = x.get_bb_outputs(); + + for ( i = 0 ; i < m ; ++i ) + if ( bbo[i].is_defined() ) { + rtab[2*i+n ] = 1.0; + rtab[2*i+n+1] = bbo[i].value(); + } + else + rtab[2*i+n] = rtab[2*i+n+1] = -1.0; + + // f and h values: + if ( x.get_f().is_defined() ) { + itab[5 ] = 1; + rtab[n+2*m] = x.get_f().value(); + } + else { + itab[5 ] = 0; + rtab[n+2*m] = INF; + } + if ( x.get_h().is_defined() ) { + itab[6 ] = 1; + rtab[n+2*m+1] = x.get_h().value(); + } + else { + itab[6 ] = 0; + rtab[n+2*m+1] = INF; + } + + MPI_Send ( itab , 7 , MPI_INT , npm1 , + Cache_Server::TAG_X3 , MPI_COMM_WORLD ); + + MPI_Send ( rtab , n+2*m+2 , MPI_DOUBLE , npm1 , + Cache_Server::TAG_X4 , MPI_COMM_WORLD ); + + delete [] rtab; +} + +/*--------------------------------------*/ +/* get and remove an extern point */ +/*--------------------------------------*/ +const Eval_Point * Cache_Server::get_and_remove_extern_point ( void ) const { + + int npm1 = _np-1; + + if ( _rank == npm1 ) + return NULL; + + // extern point from the client: + // ----------------------------- + if ( Cache::get_nb_extern_points() > 0 ) + return Cache::get_and_remove_extern_point(); + + // extern point from the server: + // ----------------------------- + + int nb_pt; + + // send a request for an extern point: + MPI_Request req; + MPI_Irecv ( &nb_pt , 1 , MPI_INT , npm1 , + Cache_Server::TAG_EP , MPI_COMM_WORLD , &req ); + + // extern points signal : + MPI_Send ( &Cache_Server::EP_SIGNAL , 1 , MPI_CHAR , + npm1 , Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD ); + + // wait for the request: + MPI_Status status; + MPI_Wait ( &req , &status ); + + if ( nb_pt == 0 ) + return NULL; + + // receive the extern point: + int itab[5]; + MPI_Recv ( itab , 5 , MPI_INT , npm1 , + Cache_Server::TAG_X5 , MPI_COMM_WORLD , &status ); + + int n = itab[0]; + int m = itab[1]; + + double * rtab = new double[n+2*m]; + + MPI_Recv ( rtab , n+2*m , MPI_DOUBLE , npm1 , + Cache_Server::TAG_X6 , MPI_COMM_WORLD , &status ); + + // create the Eval_Point: + Eval_Point * x = new Eval_Point ( n , m ); + + int i; + for ( i = 0 ; i < n ; ++i ) + (*x)[i] = rtab[i]; + + for ( i = 0 ; i < m ; ++i ) + if ( rtab[2*i+n] > 0 ) + x->set_bb_output ( i , rtab[2*i+n+1] ); + + delete [] rtab; + + x->set_eval_status ( ( itab[2] == 1 ) ? EVAL_OK : EVAL_FAIL ); + + + // insert the point in local cache: + const Eval_Point * cache_x = Cache::find ( *x ); + if ( cache_x ) { + delete x; + return cache_x; + } + + x->set_current_run ( true ); + const_cast<Cache_Server*>(this)->Cache::insert ( *x ); + x->set_current_run ( false ); + + return x; +} + +/*---------------------------------------*/ +/* get the number of extern points */ +/*---------------------------------------*/ +int Cache_Server::get_nb_extern_points ( void ) const { + + int nb_client_extern_pts = Cache::get_nb_extern_points(); + int nb_server_extern_pts = 0; + int npm1 = _np-1; + + if ( _rank != npm1 ) { + + // send a request for the number of extern points: + MPI_Request req; + MPI_Irecv ( &nb_server_extern_pts , 1 , MPI_INT , npm1 , + Cache_Server::TAG_NB_EP , MPI_COMM_WORLD , &req ); + + // number of extern points signal : + MPI_Send ( &Cache_Server::NB_EP_SIGNAL , 1 , MPI_CHAR , + npm1 , Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD ); + + // wait for the request: + MPI_Status status; + MPI_Wait ( &req , &status ); + } + + return nb_client_extern_pts + nb_server_extern_pts; +} + +/*---------------------------------*/ +/* display the extern points */ +/*---------------------------------*/ +void Cache_Server::display_extern_pts ( const Display & out ) const { + + int npm1 = _np-1; + + // server: + // ------- + if ( _rank == npm1 ) { + + list<const Eval_Point*>::const_iterator it; + out << endl << open_block ("Clients extern points"); + + for ( int i = 0 ; i < npm1 ; ++i ) { + out.open_block ( "client #"+itos(i) ); + for ( it = _clients_ext_pts[i].begin() ; + it != _clients_ext_pts[i].end () ; + ++it ) { + out << "#" << (*it)->get_tag() << " ( "; + (*it)->Point::display ( out ); + out << " ) " << " [" + << (*it)->get_bb_outputs() << " ] f=" + << (*it)->get_f() << " h=" + << (*it)->get_h() << endl; + } + out.close_block(); + } + } + + // clients: + else { + + out << endl + << open_block ( "Process #" + itos(_rank) + ": extern points" ); + + out << "number of points = " + << get_nb_extern_points() << endl; + + const Eval_Point * extern_pt = get_and_remove_extern_point(); + + while ( extern_pt ) { + + out << "#" << extern_pt->get_tag() << " ( "; + extern_pt->Point::display ( out ); + out << " ) " << " [" + << extern_pt->get_bb_outputs() << " ] f=" + << extern_pt->get_f() << " h=" + << extern_pt->get_h() << endl; + + extern_pt = get_and_remove_extern_point(); + } + } + out << close_block() << endl; +} + +/*--------------------------------------*/ +/* update and display the best points */ +/*--------------------------------------*/ +void Cache_Server::update_best_points ( const Eval_Point & x , + int source ) { + const Double & f = x.get_f(); + const Double & h = x.get_h(); + + if ( !f.is_defined() || !h.is_defined() ) + return; + + int i; + bool add_x = false; + + // feasible: + if ( h <= _h_min ) { + + // new best feasible point: + if ( !_bf || f < _bf->get_f() ) { + _bf = &x; + add_x = true; + display_current_solution(); + } + } + + // infeasible: + else { + if ( !_bi1 || h < _bi1->get_h() ) { + _bi1 = &x; + add_x = true; + } + if ( !_bi2 || f < _bi2->get_f() ) { + _bi2 = &x; + add_x = true; + } + } + + if ( add_x ) + for ( i = 0 ; i < _np-1 ; ++i ) + if ( i != source ) + _clients_ext_pts[i].push_front ( &x ); +} + +/*-----------------------------------------*/ +/* display the current best solution */ +/*-----------------------------------------*/ +void Cache_Server::display_current_solution ( void ) const { + if ( _rank != _np-1 || !_bf ) + return; + if ( _debug ) + _out << "CACHE SERVER: CURRENT SOLUTION: \t"; + _out << _clock.get_real_time() << "\t" + << size() << "\t" << _bf->get_f() << endl; +} + +/*-------------------------------*/ +/* display the best points */ +/*-------------------------------*/ +void Cache_Server::display_best_points ( const Display & out ) const { + if ( _rank != _np-1 ) + return; + + // display the last solution: + display_current_solution(); + + // stats: + out << "evaluations: " << size() << endl + << "cache hits : " << _cache_hits << endl; + + // best feasible solution: + out << "best feasible solution: "; + if ( _bf ) { + out << "x=( "; + _bf->Point::display(out); + out << " )" + << " F(x)=[ " << _bf->get_bb_outputs() << " ] h=" + << _bf->get_h() << " f=" << _bf->get_f() << endl; + } + else { + + out << "NULL" << endl; + + // best infeasible solutions: + if ( _bi1 ) { + out << "best infeas. sol. #1 : x=( "; + _bi1->Point::display(out); + out << " )" + << " F(x)=[ " << _bi1->get_bb_outputs() << " ] h=" + << _bi1->get_h() << " f=" << _bi1->get_f() << endl; + } + + if ( _bi2 && _bi2 != _bi1 ) { + out << "best infeas. sol. #2 : x=( "; + _bi2->Point::display(out); + out << " )" + << " F(x)=[ " << _bi2->get_bb_outputs() << " ] h=" + << _bi2->get_h() << " f=" << _bi2->get_f() << endl; + } + } +} diff --git a/tools/PSD-MADS_library_mode/Cache_Server.hpp b/tools/PSD-MADS_library_mode/Cache_Server.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7de0e0f7f52bb8426b01cbeee93aa35f020ccd0f --- /dev/null +++ b/tools/PSD-MADS_library_mode/Cache_Server.hpp @@ -0,0 +1,120 @@ +#ifndef __CACHE_SERVER__ +#define __CACHE_SERVER__ + +#include "mpi.h" +#include "nomad.hpp" + +using namespace NOMAD; +using namespace std; + +// Cache server: +class Cache_Server : public Cache { + +private: + + int _rank; // process rank + int _np; // number of processes + + bool _debug; // debug display flag + + Clock _clock; // clock + + Double _h_min; // h_min (min feasibility) + int _max_bbe; // max number of bb evaluations + + const Eval_Point * _bf; // best points + const Eval_Point * _bi1; + const Eval_Point * _bi2; + + Eval_Point * _stop_point; // stopping point + + mutable int _multiple_evals; // number of multiple evaluations + mutable int _cache_hits; // number of cache hits + mutable int _cache_search_pts; // number of cache search points + + Point ** _waited_pts; // list of points beeing evaluated + list<const Eval_Point*> * _clients_ext_pts; // replaces _extern_pts + + // process the best feasible point signal: + void process_bf_signal ( int source ) const; + + // process the extern point signal: + void process_ep_signal ( int source ) const; + + // process the find signal: + void process_find_signal ( int source ) const; + + // process the insertion signal: + void process_insert_signal ( int source ); + + // update and display the best points: + void update_best_points ( const Eval_Point & x , int source ); + +public: + + static const int TAG_SIGNAL; + static const int TAG_CACHE_HIT; + static const int TAG_X1; + static const int TAG_X2; + static const int TAG_X3; + static const int TAG_X4; + static const int TAG_X5; + static const int TAG_X6; + static const int TAG_X7; + static const int TAG_BBOR; + static const int TAG_BBOC; + static const int TAG_NB_EP; + static const int TAG_EP; + static const int TAG_BF; + static char STOP_SIGNAL; + static char FIND_SIGNAL; + static char INSERT_SIGNAL; + static char NB_EP_SIGNAL; + static char EP_SIGNAL; + static char BF_SIGNAL; + + // Constructor: + Cache_Server ( const Display & out , + int rank , + int np , + const Double & h_min , + int max_bbe , + bool allow_multiple_evals , + bool debug ); + + // Destructor: + virtual ~Cache_Server ( void ); + + // Start the server: + void start ( void ); + + // Stop the server: + void stop ( void ) const; + + // Display the clients extern points: + void display_extern_pts ( void ) const { display_extern_pts(_out); } + void display_extern_pts ( const Display & out ) const; + + // Display the best points: + void display_best_points ( void ) const { display_best_points(_out); } + void display_best_points ( const Display & out ) const; + + // Display the current best solution: + void display_current_solution ( void ) const; + + // Find a point: + virtual const Eval_Point * find ( const Eval_Point & x ) const; + + // Insert a point: + virtual void insert ( const NOMAD::Eval_Point & x ); + + // Get the number of extern points: + virtual int get_nb_extern_points ( void ) const; + + // Get and remove an extern point: + virtual const Eval_Point * get_and_remove_extern_point ( void ) const; + +}; + + +#endif diff --git a/tools/PSD-MADS_library_mode/Master_Slaves.cpp b/tools/PSD-MADS_library_mode/Master_Slaves.cpp new file mode 100644 index 0000000000000000000000000000000000000000..86e4d1431c6bf6a1155b1b8c153d7a7c6011e24e --- /dev/null +++ b/tools/PSD-MADS_library_mode/Master_Slaves.cpp @@ -0,0 +1,807 @@ +#include "Master_Slaves.hpp" +using namespace std; +using namespace NOMAD; + +/*--------------------------*/ +/* tags and signal values */ +/*--------------------------*/ +const int Master_Slaves::TAG_SIGNAL = 100; +const int Master_Slaves::TAG_I1 = 101; +const int Master_Slaves::TAG_R1 = 102; +const int Master_Slaves::TAG_CSTOP = 103; +const int Master_Slaves::TAG_D1 = 105; +const int Master_Slaves::TAG_I2 = 106; +char Master_Slaves::STOP_SIGNAL = 'S'; +char Master_Slaves::OPTI_RES_SIGNAL = 'O'; +char Master_Slaves::OPTI_DATA_SIGNAL = 'D'; + +/*--------------------------------*/ +/* start the master (process 0) */ +/*--------------------------------*/ +void Master_Slaves::start ( void ) const { + + if ( _rank != 0 ) + return; + + MPI_Status status; + int source; + char signal; + int n = _p.get_dimension(); + int nb_stops = 0; + int pollster_mesh_index = 0; + bool stop_algo = false; + double * best_feasible = NULL; + + // the first best infeasible point is initialized with x0: + double * best_infeasible = new double [n+2]; + const Point * x0 = (_p.get_x0s())[0]; + for ( int i = 0 ; i < n ; ++i ) + best_infeasible[i] = (*x0)[i].value(); + best_infeasible[n ] = INF; + best_infeasible[n+1] = INF; + + /*-------------*/ + /* main loop */ + /*-------------*/ + while ( nb_stops != _np-2 ) { + + MPI_Recv ( &signal , 1 , MPI_CHAR , MPI_ANY_SOURCE , + Master_Slaves::TAG_SIGNAL , MPI_COMM_WORLD , &status ); + + source = status.MPI_SOURCE; + + // stop signal: + // ------------ + if ( signal == Master_Slaves::STOP_SIGNAL ) { + if ( _debug ) { + _p.out() << "MASTER: STOP SIGNAL FROM RANK " << source; + if ( source == 1 ) + _p.out() << " (POLLSTER)"; + _p.out() << endl; + } + ++nb_stops; + } + + // optimization data signal: + // ------------------------- + else if ( signal == Master_Slaves::OPTI_DATA_SIGNAL ) { + if ( _debug ) { + _p.out() << "MASTER: receive optimization data request from slave " + << source; + if ( source == 1 ) + _p.out() << " (POLLSTER)"; + _p.out() << endl; + } + + send_optimization_data ( pollster_mesh_index , + stop_algo , + best_feasible , + best_infeasible , + source ); + } + + // optimization result signal: + // --------------------------- + else if ( signal == Master_Slaves::OPTI_RES_SIGNAL ) { + if ( _debug ) { + _p.out() << "MASTER: receive optimization result from slave " + << source; + if ( source == 1 ) + _p.out() << " (POLLSTER)"; + _p.out() << endl; + } + + // pollster: + if ( source == 1 ) + receive_optimization_result ( pollster_mesh_index , + stop_algo , + best_feasible , + best_infeasible , + source ); + + // other slaves: + else { + int tmp1; + bool tmp2; + receive_optimization_result ( tmp1 , + tmp2 , + best_feasible , + best_infeasible , + source ); + } + } + } + + if ( best_feasible ) + delete [] best_feasible; + if ( best_infeasible ) + delete [] best_infeasible; +} + +/*------------------------------------------*/ +/* stop the master (processes 1 to _np-2) */ +/*------------------------------------------*/ +void Master_Slaves::stop ( void ) const { + if ( _rank == 0 || _rank == _np-1 ) + return; + + MPI_Send ( &Master_Slaves::STOP_SIGNAL , 1 , MPI_CHAR , + 0 , Master_Slaves::TAG_SIGNAL , MPI_COMM_WORLD ); +} + +/*----------------------------------------*/ +/* MADS run */ +/*----------------------------------------*/ +void Master_Slaves::mads_run ( Cache & cache ) { + + const Eval_Point * best_feasible = NULL; + const Eval_Point * best_infeasible = NULL; + Double old_f = INF; + bool stop_algo = false; + int run_index = 0; + int mesh_index = 0; + double default_eps = Double::get_epsilon(); + int n = _p.get_dimension(); + int * free_vars = new int [_ns]; + Point x0 ( n ) , delta_0 , delta_min; + + /*---------------------*/ + /* main loop */ + /*---------------------*/ + while ( !stop_algo ) { + + best_feasible = NULL; + best_infeasible = NULL; + + // Seed: + _p.set_SEED ( 99 * _rank + 20 * run_index ); + + // first run: + if ( run_index == 0 ) { + + // max number of evaluations for regular slaves: + if ( _rank != 1 ) + _p.set_MAX_BB_EVAL ( _bbe ); + + // display: + // p.set_DISPLAY_STATS ( "process #" + itos(_rank) + " BBE OBJ" ); + // p.set_DISPLAY_DEGREE ( FULL_DISPLAY ); + _p.set_DISPLAY_DEGREE ( NO_DISPLAY ); + } + + // force the parameters check: + _p.force_check_flag(); + + /*------------------*/ + /* pollster slave */ + /*------------------*/ + if ( _rank == 1 ) { + + stop_type stop_reason = UNKNOWN_STOP_REASON; + + _p.check(); // must do check to get a valid signature + _p.get_signature()->get_mesh()->set_mesh_indices( NOMAD::Point( n,mesh_index ) ); + delta_0=_p.get_signature()->get_mesh()->get_delta ( ); + + + + // we set a very small epsilon in order to accept + // very small initial mesh sizes: + Double::set_epsilon ( 1e-16 ); + + if ( !check_delta ( delta_0 ) ) + stop_algo = true; + + else { + + // first run: + if ( run_index == 0 ) { + + // directions: + { + bool use_orthomads = _p.has_orthomads_directions(); + _p.reset_directions ( ); + _p.set_DIRECTION_TYPE ( (use_orthomads) ? ORTHO_1 : LT_1 ); + } + + // cache search: + _p.set_CACHE_SEARCH ( true ); + _p.set_OPPORTUNISTIC_CACHE_SEARCH ( false ); + } + + // other runs: + else { + + // stop_algo may be set to 'false' here: + receive_optimization_data ( stop_algo , x0 , old_f ); + + // starting point: + _p.reset_X0(); + _p.set_X0 ( x0 ); + } + + if ( !stop_algo ) { + + // check the parameters: + _p.check(); + + _p.get_signature()->get_mesh()->set_min_mesh_sizes( delta_0 ); + + if ( mesh_index <= 0 ) + _p.get_signature()->get_mesh()->set_limit_mesh_index ( mesh_index ); + else + _p.get_signature()->get_mesh()->set_limit_mesh_index ( 0 ); + + + Double::set_epsilon ( default_eps ); + + Mads mads ( _p , &_ev , NULL , &cache , NULL ); + stop_reason = mads.run(); + best_feasible = mads.get_best_feasible(); + best_infeasible = mads.get_best_infeasible(); + + bool success = false; + + if ( best_feasible ) { + + success = (best_feasible->get_f() < old_f); + + if ( _debug ) + _p.out() << "POLLSTER: ELL=" + << mesh_index << " BBE=" + << mads.get_stats().get_bb_eval() + << " OLD_F=" << old_f << " NEW_F=" + << best_feasible->get_f() + << " SUCCESS=" << success << endl; + } + + // pollster mesh update: + if ( success ) + ++mesh_index; + else + --mesh_index; + + } + } + + send_optimization_result ( mesh_index , + stop_algo , + best_feasible , + best_infeasible , + stop_reason ); + } + + /*------------------*/ + /* regular slaves */ + /*------------------*/ + else { + + int i , j , pollster_mesh_index; + + receive_optimization_data ( stop_algo , + x0 , + old_f , + pollster_mesh_index , + free_vars ); + + if ( _debug ) { + _p.out() << "SLAVE #" << _rank + << ": OPTIM. DATA: [STOP=" << stop_algo + << "] [POLLSTER_MESH_INDEX=" << pollster_mesh_index + << "] [X0=" << x0 << " ] [f(X0)=" + << old_f << "] [FREE VARS= "; + for ( i = 0 ; i < _ns ; ++i ) + _p.out() << free_vars[i] << " "; + _p.out() << " ]" << endl; + } + + if ( !stop_algo ) { + + // starting point: + _p.reset_X0(); + _p.set_X0 ( x0 ); + + // mesh of the regular slave: + int ell_0 = 0; + if ( pollster_mesh_index > ell_0 ) + ell_0 = pollster_mesh_index; + + _p.check(); // Must do check to access signature + _p.get_signature()->get_mesh()->set_mesh_indices( NOMAD::Point( n,ell_0 ) ); + delta_0=_p.get_signature()->get_mesh()->get_delta(); + + _p.get_signature()->get_mesh()->set_mesh_indices( NOMAD::Point( n ,pollster_mesh_index ) ); + delta_min=_p.get_signature()->get_mesh()->get_delta(); + + + + Double::set_epsilon ( 1e-16 ); + if ( !check_delta ( delta_0 ) || !check_delta ( delta_min ) ) + stop_algo = true; + + else { + + // free variables: + { + _p.reset_fixed_variables(); + bool fix_var; + for ( i = 0 ; i < n ; ++i ) { + fix_var = true; + for ( j = 0 ; j < _ns ; ++j ) + if ( free_vars[j] == i ) { + fix_var = false; + break; + } + if ( fix_var ) + _p.set_FIXED_VARIABLE ( i ); + } + } + + // check the parameters: + _p.check(); + + // modify mesh termination criterions + _p.get_signature()->get_mesh()->set_mesh_indices( NOMAD::Point( n,ell_0 ) ); + + if ( pollster_mesh_index <=0 ) + _p.get_signature()->get_mesh()->set_limit_mesh_index( pollster_mesh_index ); + else + _p.get_signature()->get_mesh()->set_limit_mesh_index( 0 ); + + _p.get_signature()->get_mesh()->set_min_mesh_sizes( delta_min ); + _p.get_signature()->get_mesh()->set_delta_0 ( delta_0 ); + + + + Double::set_epsilon ( default_eps ); + + // MADS run: + Mads mads ( _p , &_ev , NULL , &cache , NULL ); + mads.run(); + best_feasible = mads.get_best_feasible(); + best_infeasible = mads.get_best_infeasible(); + + if ( _debug && best_feasible ) { + _p.out() << "RANK #" << _rank << ": POLLSTER_ELL=" + << pollster_mesh_index << " VARS = ["; + for ( i = 0 ; i < _ns ; ++i ) + _p.out() << free_vars[i] << " "; + _p.out() << " ] BBE=" << mads.get_stats().get_bb_eval() + << " OLD_F=" << old_f << " NEW_F=" + << best_feasible->get_f() + << " SUCCESS=" + << (best_feasible->get_f() < old_f) + << endl; + } + } + } + + { + int tmp1 = -1; + bool tmp2 = false; + stop_type tmp3 = UNKNOWN_STOP_REASON; + send_optimization_result ( tmp1 , + tmp2 , + best_feasible , + best_infeasible , + tmp3 ); + } + } + + // loop increment: + ++run_index; + } + + delete [] free_vars; +} + +/*----------------------------------------------------*/ +/* receive an optimization result from the pollster */ +/* POLLSTER --> MASTER */ +/*----------------------------------------------------*/ +void Master_Slaves::receive_optimization_result +( int & pollster_mesh_index , + bool & stop_algo , + double *& best_feasible , + double *& best_infeasible , + int source ) const { + + int itab[5]; + MPI_Status status; + + MPI_Recv ( itab , 5 , MPI_INT , source , + Master_Slaves::TAG_I1 , MPI_COMM_WORLD , &status ); + + pollster_mesh_index = itab[0]; + + // stop the algorithm ? + stop_algo = ( itab[4] == 1 ); + + if ( !stop_algo ) { + + stop_type stop_reason = static_cast<stop_type>(itab[1]); + + switch ( stop_reason ) { + case ERROR: + case UNKNOWN_STOP_REASON: + case CTRL_C: + case MESH_PREC_REACHED: + case X0_FAIL: + case P1_FAIL: + case L_MAX_REACHED: + case L_LIMITS_REACHED: + case MAX_TIME_REACHED: + case MAX_BB_EVAL_REACHED: + case MAX_SGTE_EVAL_REACHED: + case MAX_EVAL_REACHED: + case MAX_SIM_BB_EVAL_REACHED: + case MAX_ITER_REACHED: + case FEAS_REACHED: + case F_TARGET_REACHED: + case STAT_SUM_TARGET_REACHED: + case L_CURVE_TARGET_REACHED: + case MULTI_MAX_BB_REACHED: + case MULTI_NB_MADS_RUNS_REACHED: + case MULTI_STAGNATION: + case MULTI_NO_PARETO_PTS: + case MAX_CACHE_MEMORY_REACHED: + stop_algo = true; + default: + stop_algo = false; + } + } + + int i , nb_pts = 0; + if ( itab[2] == 1 ) + ++nb_pts; + if ( itab[3] == 1 ) + ++nb_pts; + + // itab[2] == 1 --> bf != NULL + // itab[3] == 1 --> bi != NULL + + if ( nb_pts > 0 ) { + + int n = _p.get_dimension(); + double * rtab = new double [(n+2)*nb_pts]; + + MPI_Recv ( rtab , (n+2)*nb_pts , MPI_DOUBLE , source , + Master_Slaves::TAG_R1 , MPI_COMM_WORLD , &status ); + + if ( nb_pts == 2 ) { + + // best feasible and infeasible updates: + bool update = false; + + if ( best_feasible ) { + Double old_f = best_feasible[n+1]; + Double new_f = rtab [n+1]; + if ( new_f < old_f ) + update = true; + } + else { + best_feasible = new double[n+2]; + update = true; + } + + if ( update ) { + for ( i = 0 ; i < n ; ++i ) + best_feasible[i] = rtab[i]; + best_feasible[n ] = rtab[n]; + best_feasible[n+1] = rtab[n+1]; + } + + update = false; + + if ( best_infeasible ) { + + Double old_h = best_infeasible[n]; + Double new_h = rtab [2*n+2]; + if ( new_h < old_h ) + update = true; + } + else { + best_infeasible = new double[n+2]; + update = true; + } + + if ( update ) { + int cur = n+2; + for ( i = 0 ; i < n ; ++i ) + best_infeasible[i] = rtab[cur++]; + best_infeasible[n ] = rtab[cur++]; + best_infeasible[n+1] = rtab[cur]; + } + delete [] rtab; + } + else { + + // best feasible update: + if ( itab[2] == 1 ) { + if ( best_feasible ) { + Double old_f = best_feasible[n+1]; + Double new_f = rtab [n+1]; + if ( new_f < old_f ) { + delete [] best_feasible; + best_feasible = rtab; + } + else + delete [] rtab; + } + else + best_feasible = rtab; + } + + // best infeasible update: + else { + if ( best_infeasible ) { + Double old_h = best_infeasible[n]; + Double new_h = rtab [n]; + if ( new_h < old_h ) { + delete [] best_infeasible; + best_infeasible = rtab; + } + else + delete [] rtab; + } + else + best_infeasible = rtab; + } + } + } +} + +/*---------------------------------------------*/ +/* send an optimization result to the master */ +/* POLLSTER --> MASTER */ +/*---------------------------------------------*/ +void Master_Slaves::send_optimization_result +( int pollster_mesh_index , + bool stop_algo , + const Eval_Point * bf , + const Eval_Point * bi , + stop_type st ) const { + + // send a signal to the master: + MPI_Send ( &Master_Slaves::OPTI_RES_SIGNAL , 1 , MPI_CHAR , + 0 , Master_Slaves::TAG_SIGNAL , MPI_COMM_WORLD ); + + // send the data: + int itab[5]; + + itab[0] = pollster_mesh_index; + itab[1] = static_cast<int>(st); + + int nb_pts = 0; + if ( bf ) { + ++nb_pts; + itab[2] = 1; + } + else + itab[2] = 0; + + if ( bi ) { + ++nb_pts; + itab[3] = 1; + } + else + itab[3] = 0; + + itab[4] = (stop_algo) ? 1 : 0; + + MPI_Send ( itab , 5 , MPI_INT , 0 , + Master_Slaves::TAG_I1 , MPI_COMM_WORLD ); + + if ( nb_pts > 0 ) { + + int n = _p.get_dimension(); + double * rtab = new double [(n+2)*nb_pts]; + + int i , cur = 0; + if ( bf ) { + for ( i = 0 ; i < n ; ++i ) + rtab[cur++] = (*bf)[i].value(); + rtab[cur++] = bf->get_h().value(); + rtab[cur++] = bf->get_f().value(); + } + + if ( bi ) { + for ( i = 0 ; i < n ; ++i ) + rtab[cur++] = (*bi)[i].value(); + rtab[cur++] = bi->get_h().value(); + rtab[cur ] = bi->get_f().value(); + } + + MPI_Send ( rtab , cur , MPI_DOUBLE , 0 , + Master_Slaves::TAG_R1 , MPI_COMM_WORLD ); + + delete [] rtab; + } +} + +/*---------------------------------------------*/ +/* receive optimization data from the master */ +/* MASTER --> REGULAR SLAVE */ +/*---------------------------------------------*/ +void Master_Slaves::receive_optimization_data +( bool & stop_algo , + Point & x0 , + Double & fx0 , + int & pollster_mesh_index , + int * free_vars ) const { + + // step 1/2: receive common pollster data: + receive_optimization_data ( stop_algo , x0 , fx0 ); + + int i; + + // step 2/2: receive additional data for regular slaves: + if ( !stop_algo ) { + + int * itab = new int [_ns+1]; + MPI_Status status; + + MPI_Recv ( itab , _ns+1 , MPI_INT , 0 , + Master_Slaves::TAG_I2 , MPI_COMM_WORLD , &status ); + + for ( i = 0 ; i < _ns ; ++i ) + free_vars[i] = itab[i]; + + pollster_mesh_index = itab[_ns]; + + delete [] itab; + } + else { + pollster_mesh_index = 1; + for ( i = 0 ; i < _ns ; ++i ) + free_vars[i] = -1; + } +} + +/*---------------------------------------------*/ +/* receive optimization data from the master */ +/* MASTER --> POLLSTER */ +/*---------------------------------------------*/ +void Master_Slaves::receive_optimization_data ( bool & stop_algo , + Point & x0 , + Double & fx0 ) const { + char c_stop; + MPI_Status status; + MPI_Request req = MPI_REQUEST_NULL; + int i , n = _p.get_dimension(); + + // send a request for c_stop: + MPI_Irecv ( &c_stop , 1 , MPI_CHAR , 0 , + Master_Slaves::TAG_CSTOP , MPI_COMM_WORLD , &req ); + + // send a signal to the master: + MPI_Send ( &Master_Slaves::OPTI_DATA_SIGNAL , 1 , MPI_CHAR , + 0 , Master_Slaves::TAG_SIGNAL , MPI_COMM_WORLD ); + + MPI_Wait ( &req , &status ); + + // stop: + if ( c_stop == '1' ) { + stop_algo = true; + x0.reset(); + } + + // continue: + else { + + stop_algo = false; + double * rtab = new double [n+2]; + + MPI_Recv ( rtab , n+2 , MPI_DOUBLE , 0 , + Master_Slaves::TAG_D1 , MPI_COMM_WORLD , &status ); + + for ( i = 0 ; i < n ; ++i ) + x0[i] = rtab[i]; + + Double h = rtab[n]; + fx0 = ( h <= _p.get_h_min() ) ? rtab[n+1] : INF; + + // get the best feasible point from the cache server: + { + char pt_flag; + int npm1 = _np-1; + MPI_Irecv ( &pt_flag , 1 , MPI_CHAR , npm1 , + Cache_Server::TAG_BF , MPI_COMM_WORLD , &req ); + + MPI_Send ( &Cache_Server::BF_SIGNAL , 1 , MPI_CHAR , + npm1 , Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD ); + + MPI_Wait ( &req , &status ); + + if ( pt_flag == '1' ) { + + MPI_Recv ( rtab , n+2 , MPI_DOUBLE , npm1 , + Cache_Server::TAG_X7 , MPI_COMM_WORLD , &status ); + + for ( i = 0 ; i < n ; ++i ) + x0[i] = rtab[i]; + + Double h = rtab[n]; + fx0 = ( h <= _p.get_h_min() ) ? rtab[n+1] : INF; + + } + } + delete [] rtab; + + // check the bounds: + const Point & lb = _p.get_lb(); + const Point & ub = _p.get_ub(); + + for ( i = 0 ; i < n ; ++i ) { + if ( lb[i].is_defined() && x0[i].value() < lb[i].value() ) + x0[i] = lb[i]; + if ( ub[i].is_defined() && x0[i].value() > ub[i].value() ) + x0[i] = ub[i]; + } + } +} + +/*-----------------------------------------------------*/ +/* send optimization data from the master to a slave */ +/* MASTER --> POLLSTER or MASTER --> SLAVE */ +/*-----------------------------------------------------*/ +void Master_Slaves::send_optimization_data +( int pollster_mesh_index , + bool stop_algo , + const double * best_feasible , + const double * best_infeasible , + int source ) const { + + char c_stop = (stop_algo) ? '1' : '0'; + + MPI_Rsend ( &c_stop , 1 , MPI_CHAR , source , + Master_Slaves::TAG_CSTOP , MPI_COMM_WORLD ); + + // continue: + if ( !stop_algo ) { + + int n = _p.get_dimension(); + + // data for pollster and regular slaves: + if ( best_feasible ) + MPI_Send ( const_cast<double*>(best_feasible) , n+2 , MPI_DOUBLE , + source , Master_Slaves::TAG_D1 , MPI_COMM_WORLD ); + else + MPI_Send ( const_cast<double*>(best_infeasible) , n+2 , MPI_DOUBLE , + source , Master_Slaves::TAG_D1 , MPI_COMM_WORLD ); + + // additional data for regular slaves: + if ( source != 1 ) { + + int * itab = new int [_ns+1]; + + // choose the free varables: + { + Random_Pickup rp ( n ); + + for ( int i = 0 ; i < _ns ; ++i ) + itab[i] = rp.pickup(); // index of the ith free variable + } + + itab[_ns] = pollster_mesh_index; + + MPI_Send ( itab , _ns+1 , MPI_INT , source , + Master_Slaves::TAG_I2 , MPI_COMM_WORLD ); + + delete [] itab; + } + } +} + +/*-----------------------------------------------*/ +/* check the initial mesh size values */ +/*-----------------------------------------------*/ +bool Master_Slaves::check_delta ( const Point & delta ) { + int n = delta.size(); + for ( int i = 0 ; i < n ; ++i ) + if ( delta[i].value() < Double::get_epsilon() || + delta[i].value() <= 0.0 ) + return false; + return true; +} + diff --git a/tools/PSD-MADS_library_mode/Master_Slaves.hpp b/tools/PSD-MADS_library_mode/Master_Slaves.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1fe11a6342bf9c6defa1d9606ea90eda674058a6 --- /dev/null +++ b/tools/PSD-MADS_library_mode/Master_Slaves.hpp @@ -0,0 +1,103 @@ +#ifndef __MASTER_SLAVES__ +#define __MASTER_SLAVES__ + +#include "Cache_Server.hpp" + +using namespace NOMAD; +using namespace std; + +// Cache server: +class Master_Slaves { + +private: + + int _rank; // process rank + int _np; // number of processes + + int _bbe; // max number of evaluations for each process + int _ns; // number of free variables for each process + + Parameters & _p; // parameters + bool _debug; // debug display flag + + Evaluator & _ev; // Evaluator + + static const int TAG_SIGNAL; + static const int TAG_I1; + static const int TAG_I2; + static const int TAG_R1; + static const int TAG_D1; + static const int TAG_CSTOP; + static char STOP_SIGNAL; + static char OPTI_RES_SIGNAL; + static char OPTI_DATA_SIGNAL; + + // Receive an optimization result from the pollster: + void receive_optimization_result ( int & pollster_mesh_index , + bool & stop_algo , + double *& best_feasible , + double *& best_infeasible , + int source ) const; + + // Send an optimization result to the master: + void send_optimization_result ( int pollster_mesh_index , + bool stop_algo , + const Eval_Point * bf , + const Eval_Point * bi , + stop_type st ) const; + + // Send optimization data from the master to a slave: + void send_optimization_data ( int pollster_mesh_index , + bool stop_algo , + const double * best_feasible , + const double * best_infeasible , + int source ) const; + + // Receive optimization data from the master: + void receive_optimization_data ( bool & stop_algo , + Point & x0 , + Double & fx0 ) const; + + void receive_optimization_data ( bool & stop_algo , + Point & x0 , + Double & fx0 , + int & pollster_mesh_index , + int * free_vars ) const; + + // Check the initial mesh size values: + static bool check_delta ( const Point & delta ); + +public: + + // Constructor: + Master_Slaves ( int rank , + int np , + int bbe , + int ns , + Parameters & p , + bool debug , + Evaluator &ev ) + : _rank ( rank ) , + _np ( np ) , + _bbe ( bbe ) , + _ns ( ns ) , + _p ( p ) , + _debug ( debug ) , + _ev ( ev ){} + + // Destructor: + virtual ~Master_Slaves ( void ) {} + + // Start the master: + void start ( void ) const; + + // Stop the master: + void stop ( void ) const; + + // MADS run: + void mads_run ( Cache & cache ); + +}; + + +#endif diff --git a/tools/PSD-MADS_library_mode/SJE001150.pdf b/tools/PSD-MADS_library_mode/SJE001150.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7e37cb8310e6c7847d45c1783d200b48c7d22894 Binary files /dev/null and b/tools/PSD-MADS_library_mode/SJE001150.pdf differ diff --git a/tools/PSD-MADS_library_mode/main.cpp b/tools/PSD-MADS_library_mode/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ae60bf0627cb5e6f3340c8855b0c935ea93082b --- /dev/null +++ b/tools/PSD-MADS_library_mode/main.cpp @@ -0,0 +1,189 @@ +/*-------------------------------------------------------------*/ +/* PSD-MADS */ +/*-------------------------------------------------------------*/ +/* */ +/* usage: */ +/* */ +/* "mpirun -np p psdmads param_file bbe ns" */ +/* with p > 2, bbe > 0, and 1 <= ns <= number of variables */ +/* . ns is the number of free variables for each process */ +/* . bbe is the max number of evaluations for each process */ +/* */ +/*-------------------------------------------------------------*/ +/* */ +/* processes: */ +/* */ +/* 0: master */ +/* 1: pollster slave (1 direction) */ +/* 2 to p-2: regular slaves (2ns directions) */ +/* p-1: cache server */ +/* */ +/*-------------------------------------------------------------*/ +/* See the user guide for other details and the description */ +/* of the algorithm */ +/*-------------------------------------------------------------*/ + +/*-----------------------------------------------------------*/ +#include "Master_Slaves.hpp" +using namespace std; +using namespace NOMAD; + +const bool DEBUG = false; + + + +/*---------------------------------------------------*/ +/* The evaluator for G2_50 problem */ +/*---------------------------------------------------*/ +class My_Evaluator : public NOMAD::Evaluator { +public: + My_Evaluator ( const NOMAD::Parameters & p ) : + NOMAD::Evaluator ( p ) {} + + ~My_Evaluator ( void ) {} + + bool eval_x ( NOMAD::Eval_Point & x , + const NOMAD::Double & h_max , + bool & count_eval ) const + { + + int N=50; + long double sum1 = 0.0 , sum2 = 0.0 , sum3 = 0.0 , prod1 = 1.0 , prod2 = 1.0, g1=0, g2=0; + long double Xi; + + for (int i = 0 ; i < N ; i++ ) + { + + Xi=x[i].value(); + + sum1 += pow ( cos(Xi) , 4 ); + sum2 += Xi; + sum3 += (i+1)*Xi*Xi; + prod1 *= pow ( cos(Xi) , 2 ); + prod2 *= Xi; + } + + + g1 = -prod2+0.75; + g2 = sum2 -7.5*N; + + long double z = - fabs ( ( sum1 - 2 * prod1 ) / sqrt(sum3) ); + + x.set_bb_output ( 0 , g1 ); // constraint 1 + x.set_bb_output ( 1 , g2 ); // constraint 2 + x.set_bb_output ( 2 , z ); // objective value + + + count_eval = true; // count a black-box evaluation + + + return true; // the evaluation succeeded + } + + +}; + + + +/*-----------------------------------*/ +/* main function */ +/*-----------------------------------*/ +int main ( int argc , char ** argv ) { + + // MPI initialization: + MPI_Init ( &argc , &argv ); + int rank , np; + MPI_Comm_rank ( MPI_COMM_WORLD, &rank ); + MPI_Comm_size ( MPI_COMM_WORLD, &np ); + + // check the arguments and the number of processes: + if ( np <= 2 || argc != 4 ) { + if ( rank == 0 ) + cerr << "usage: mpirun -np p " << argv[0] + << " param_file bbe ns, with p>2," + << " bbe>1, and 1<=ns<=n." + << endl; + MPI_Finalize(); + return 1; + } + + // display: + Display out ( cout ); + out.precision ( 16 ); + + // parameters: + NOMAD::Parameters p ( out ); + int bbe = atoi ( argv[2] ); + int ns = atoi ( argv[3] ); + + try { + + // read the parameters file: + p.read ( argv[1] ); + + // This option is needed to have the same mesh index for all variables + p.set_ANISOTROPIC_MESH ( false ); + + // check the parameters: + p.check(); + + + if ( ns < 1 || ns > p.get_dimension() ) + throw Exception ( __FILE__ , __LINE__ , + "Bad value for ns the number of free variables for each process" ); + + if ( p.get_nb_obj() > 1 ) + throw Exception ( __FILE__ , __LINE__ , + "PSD-MADS is not designed for multi-objective optimization" ); + } + catch ( exception & e ) { + if ( rank == 0 ) + cerr << "error with parameters" << endl; + MPI_Finalize(); + return 1; + } + + // custom evaluator creation: + My_Evaluator ev ( p ); + + // start the master: + Master_Slaves master_slaves ( rank , np , bbe , ns , p , DEBUG ,ev); + master_slaves.start(); + + // cache server: + Cache_Server cache ( out , + rank , + np , + p.get_h_min() , + p.get_max_bb_eval() , + false , // ALLOW_MULTIPLE_EVALS + DEBUG ); + + // start the cache server: + if ( rank == np-1 ) { + if ( !DEBUG ) + out << endl << "TIME\tBBE\tOBJ" << endl << endl; + cache.start(); + } + + // slaves: algorithm creation and execution: + if ( rank != 0 && rank != np-1 ) { + + // MADS run: + master_slaves.mads_run ( cache ); + + // stop the master: + master_slaves.stop(); + } + + // stop the cache server: + cache.stop(); + + // display the final solution: + if ( !DEBUG && rank == np-1 ) + cache.display_best_points ( out ); + + // MPI finalization: + MPI_Finalize(); + return 0; +} diff --git a/tools/PSD-MADS_library_mode/makefile b/tools/PSD-MADS_library_mode/makefile new file mode 100644 index 0000000000000000000000000000000000000000..ffc34f7c4f58310cf0fe1e68e004bc51e0806f10 --- /dev/null +++ b/tools/PSD-MADS_library_mode/makefile @@ -0,0 +1,51 @@ +EXE = psdmads.exe +COMPILATOR = mpic++ +SUNAME = $(shell uname) +OSS=$(findstring MINGW32,$(SUNAME)) +ifneq "$(strip $(OSS))" "" +COMPILATOR = g++ +endif + +COMPILATOR_OPTIONS = -ansi -O2 +L1 = $(NOMAD_HOME)/lib/nomad.a +LIBS = $(L1) -lm -lmpi +INCLUDE = -I$(NOMAD_HOME)/src -I. +COMPILE = $(COMPILATOR) $(COMPILATOR_OPTIONS) $(INCLUDE) -c +OBJS = main.o Cache_Server.o Master_Slaves.o + +ifndef NOMAD_HOME +define ECHO_NOMAD + @echo Please set NOMAD_HOME environment variable! + @false +endef +endif + +$(EXE): $(OBJS) $(L1) + $(ECHO_NOMAD) + $(COMPILATOR) -o $(EXE) $(OBJS) $(LIBS) $(COMPILATOR_OPTIONS) + +main.o: main.cpp Master_Slaves.o + $(COMPILE) main.cpp + +Master_Slaves.o: Master_Slaves.cpp Master_Slaves.hpp Cache_Server.o + $(ECHO_NOMAD) + $(COMPILE) Master_Slaves.cpp + +Cache_Server.o: Cache_Server.cpp Cache_Server.hpp + $(ECHO_NOMAD) + $(COMPILE) Cache_Server.cpp + +$(L1): ; + $(ECHO_NOMAD) + +clean: + @echo "cleaning obj files" + @rm -f $(OBJS) + +del: + @echo "cleaning trash files" + @rm -f core *~ + @echo "cleaning obj files" + @rm -f $(OBJS) + @echo "cleaning exe file" + @rm -f $(EXE) \ No newline at end of file diff --git a/tools/PSD-MADS_library_mode/param.txt b/tools/PSD-MADS_library_mode/param.txt new file mode 100644 index 0000000000000000000000000000000000000000..54cbfc23a0d81ef7c050abf5c15ce6881b9aba5a --- /dev/null +++ b/tools/PSD-MADS_library_mode/param.txt @@ -0,0 +1,10 @@ +DIMENSION 50 +BB_OUTPUT_TYPE PB PB OBJ +x0 x0.txt +LOWER_BOUND * 0 +UPPER_BOUND * 10 +max_bb_eval 5000 +DIRECTION_TYPE ORTHO 2N +display_stats time bbe obj +initial_mesh_size r0.2 +snap_to_bounds no diff --git a/tools/PSD-MADS_library_mode/x0.txt b/tools/PSD-MADS_library_mode/x0.txt new file mode 100644 index 0000000000000000000000000000000000000000..1f13319917ba2ff98ad507b08622efc5e9b93df4 --- /dev/null +++ b/tools/PSD-MADS_library_mode/x0.txt @@ -0,0 +1,50 @@ +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 +5.0 diff --git a/tools/PSD-MADS_library_mode/x_opt.txt b/tools/PSD-MADS_library_mode/x_opt.txt new file mode 100644 index 0000000000000000000000000000000000000000..9d904afd3ff6e04c74239c73af1546745b4401b5 --- /dev/null +++ b/tools/PSD-MADS_library_mode/x_opt.txt @@ -0,0 +1 @@ +6.4149169921875 6.2413330078125 6.3720703125 6.1068115234375 3.0206298828125 0.585693359375 0.435791015625 0.391357421875 3.0928955078125 3.171875 0.173583984375 3.1939697265625 2.92333984375 6.1531982421875 2.8271484375 0.27392578125 3.1434326171875 0.511474609375 0.1761474609375 2.9149169921875 0.27294921875 0.4522705078125 3.0953369140625 3.0416259765625 0.3453369140625 0.275390625 2.8414306640625 3.1175537109375 3.0628662109375 3.126953125 3.0113525390625 3.0687255859375 0.182861328125 2.9844970703125 0.2940673828125 0.161865234375 2.83740234375 2.681884765625 0.2615966796875 1.843994140625 0.2763671875 0.1839599609375 0.3106689453125 0.1778564453125 0.330810546875 0.3873291015625 0.313720703125 0.44140625 0.2330322265625 0.290283203125