/*-----------------------------------------------------------*/ void NOMAD::LH_Search::values_for_var_i ( int p , const NOMAD::Double & delta , const NOMAD::Double & delta_max , const NOMAD::bb_input_type & bbit , const NOMAD::Double & lb , const NOMAD::Double & ub , NOMAD::Point & x ) const { // categorical variables have already been treated as fixed variables: if ( bbit == NOMAD::CATEGORICAL ) return; int i; NOMAD::Double v; NOMAD::Random_Pickup rp (p); bool rounding = ( bbit != NOMAD::CONTINUOUS ); bool lb_def = lb.is_defined(); bool ub_def = ub.is_defined(); double w = ( ( lb_def && ub_def ) ? ub.value()-lb.value() : 1.0 ) / p; // main loop: for ( i = 0 ; i < p ; ++i ) { // both bounds exist: if ( lb_def && ub_def ) v = lb + ( i + NOMAD::RNG::rand()/NOMAD::D_INT_MAX ) * w; // one of the bounds does not exist: else { // lb exists, and ub not: mapping [0;1] --> [lb;+INF[ if ( lb_def ) v = lb + 10 * delta_max * sqrt ( - log ( NOMAD::DEFAULT_EPSILON + ( i + NOMAD::RNG::rand()/NOMAD::D_INT_MAX ) * w ) ); // lb does not exist: else { // ub exists, and lb not: mapping [0;1] --> ]-INF;ub] if ( ub_def ) v = ub - delta_max * 10 * sqrt ( -log ( NOMAD::DEFAULT_EPSILON + ( i +NOMAD::RNG::rand()/NOMAD::D_INT_MAX ) * w ) ); // there are no bounds: mapping [0;1] --> ]-INF;+INF[ else v = (NOMAD::RNG::rand()%2 ? -1.0 : 1.0) * delta_max * 10 * sqrt ( - log ( NOMAD::DEFAULT_EPSILON + ( i + NOMAD::RNG::rand()/NOMAD::D_INT_MAX ) * w ) ); } } // rounding: if ( rounding ) v = v.round(); // projection to mesh (with ref=0): v.project_to_mesh ( 0.0 , delta , lb , ub ); // affectation + permutation: x[rp.pickup()] = v; } }
/*---------------------------------------------------------*/ void NOMAD::Directions::compute ( std::list<NOMAD::Direction> & dirs , NOMAD::poll_type poll , const NOMAD::Point & poll_center , int mesh_index , int halton_index , const NOMAD::Direction & feas_success_dir , const NOMAD::Direction & infeas_success_dir ) { dirs.clear(); // categorical variables: do nothing: if ( _is_categorical ) return; // binary variables: we use special directions: if ( _is_binary ) { compute_binary_directions ( dirs ); return; } NOMAD::Double pow_gps , cst; const NOMAD::Direction * bl; NOMAD::Direction * pd; int i , j , k , hat_i; std::list<NOMAD::Direction>::const_iterator it2 , end2; /*-----------------------------------*/ /* loop on the types of directions */ /*-----------------------------------*/ const std::set<NOMAD::direction_type> & dir_types = (poll == NOMAD::PRIMARY) ? _direction_types : _sec_poll_dir_types; std::set<NOMAD::direction_type>::const_iterator it , end = dir_types.end() ; for ( it = dir_types.begin() ; it != end ; ++it ) { if ( *it == NOMAD::UNDEFINED_DIRECTION || *it == NOMAD::NO_DIRECTION || *it == NOMAD::MODEL_SEARCH_DIR ) continue; /*--------------*/ /* Ortho-MADS */ /*--------------*/ if ( NOMAD::dir_is_orthomads (*it) ) { // Ortho-MADS initializations: if ( !_primes ) ortho_mads_init ( _halton_seed ); // halton index: if ( halton_index < 0 ) { int max_halton_index = NOMAD::Mesh::get_max_halton_index(); // mesh_index+ _halton_seed -> used to make sure that the sequence of strictly increasing mesh_index produces a non biased sequence of halton_index halton_index = ( mesh_index >= NOMAD::Mesh::get_max_mesh_index() ) ? mesh_index + _halton_seed : max_halton_index + 1; if ( halton_index > max_halton_index ) NOMAD::Mesh::set_max_halton_index ( halton_index ); } NOMAD::Direction halton_dir ( _nc , 0.0 , *it ); NOMAD::Double alpha_t_l; if ( compute_halton_dir ( halton_index , mesh_index , alpha_t_l , halton_dir ) ) { #ifdef DEBUG _out << std::endl << NOMAD::open_block ( "compute Ortho-MADS directions with" ) << "type = " << *it << std::endl << "Halton index (tk) = " << halton_index << std::endl << "mesh index (lk) = " << mesh_index << std::endl << "alpha (tk,lk) = " << alpha_t_l << std::endl << "Halton direction = ( "; halton_dir.NOMAD::Point::display ( _out , " " , -1 , -1 ); _out << " )" << std::endl << NOMAD::close_block(); #endif // Ortho-MADS 2n and n+1: // ---------------------- if ( *it == NOMAD::ORTHO_2N || *it == NOMAD::ORTHO_NP1_QUAD || *it == NOMAD::ORTHO_NP1_NEG ) { // creation of the 2n directions: // For ORTHO_NP1 the reduction from 2N to N+1 is done in MADS::POLL NOMAD::Direction ** H = new NOMAD::Direction * [2*_nc]; // Ordering D_k alternates Hk and -Hk instead of [H_k -H_k] for ( i = 0 ; i < _nc ; ++i ) { dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , *it ) ); H[i ] = &(*(--dirs.end())); dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , *it ) ); H[i+_nc] = &(*(--dirs.end())); } // Householder transformations on the 2n directions: householder ( halton_dir , true , // complete_to_2n = true H ); delete [] H; } // Ortho-MADS 1 or Ortho-MADS 2: // ----------------------------- else { dirs.push_back ( halton_dir ); if ( *it == NOMAD::ORTHO_2 ) dirs.push_back ( -halton_dir ); } } } /*-----------*/ /* LT-MADS */ /*-----------*/ else if ( NOMAD::dir_is_ltmads (*it) ) { if ( !_lt_initialized) lt_mads_init(); bl = get_bl ( mesh_index , *it , hat_i ); // LT-MADS 1 or LT-MADS 2: -b(l) and/or b(l): // ------------------------------------------ if ( *it == NOMAD::LT_1 || *it == NOMAD::LT_2 ) { dirs.push_back ( - *bl ); if ( *it == NOMAD::LT_2 ) dirs.push_back ( *bl ); } // LT-MADS 2n or LT-MADS n+1: // -------------------------- else { // row permutation vector: int * row_permutation_vector = new int [_nc]; row_permutation_vector[hat_i] = hat_i; NOMAD::Random_Pickup rp ( _nc ); for ( i = 0 ; i < _nc ; ++i ) if ( i != hat_i ) { j = rp.pickup(); if ( j == hat_i ) j = rp.pickup(); row_permutation_vector[i] = j; } rp.reset(); for ( j = 0 ; j < _nc ; ++j ) { i = rp.pickup(); if ( i != hat_i ) { dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , *it ) ); pd = &(*(--dirs.end())); create_lt_direction ( mesh_index , *it , i , hat_i , pd ); permute_coords ( *pd , row_permutation_vector ); } else dirs.push_back ( *bl ); // completion to maximal basis: if ( *it == NOMAD::LT_2N ) dirs.push_back ( NOMAD::Direction ( - *(--dirs.end()) , NOMAD::LT_2N ) ); } delete [] row_permutation_vector; // completion to minimal basis: if ( *it == NOMAD::LT_NP1 ) { dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::LT_NP1 ) ); pd = &(*(--dirs.end())); end2 = --dirs.end(); for ( it2 = dirs.begin() ; it2 != end2 ; ++it2 ) { for ( i = 0 ; i < _nc ; ++i ) (*pd)[i] -= (*it2)[i]; } } } } /*-------*/ /* GPS */ /*-------*/ else { // GPS for binary variables: should'nt be here: if ( *it == NOMAD::GPS_BINARY ) { #ifdef DEBUG _out << std::endl << "Warning (" << "Directions.cpp" << ", " << __LINE__ << "): tried to generate binary directions at the wrong place)" << std::endl << std::endl; #endif dirs.clear(); return; } // this value represents the non-zero values in GPS directions // (it is tau^{|ell_k|/2}, and it is such that Delta^m_k * pow_gps = Delta^p_k): if ( !pow_gps.is_defined() ) pow_gps = pow ( NOMAD::Mesh::get_mesh_update_basis() , abs(mesh_index) / 2.0 ); // GPS 2n, static: // --------------- if ( *it == NOMAD::GPS_2N_STATIC ) { for ( i = 0 ; i < _nc ; ++i ) { dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_2N_STATIC ) ); pd = &(*(--dirs.end())); (*pd)[i] = pow_gps; dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_2N_STATIC ) ); pd = &(*(--dirs.end())); (*pd)[i] = -pow_gps; } } // GPS 2n, random: // --------------- else if ( *it == NOMAD::GPS_2N_RAND ) { int v , cnt; std::list <int>::const_iterator end3; std::list <int>::iterator it3; std::list <int> rem_cols; std::vector<int> rem_col_by_row ( _nc ); // creation of the 2n directions: std::vector<NOMAD::Direction *> pdirs ( 2 * _nc ); for ( i = 0 ; i < _nc ; ++i ) { dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_2N_RAND ) ); pdirs[i] = &(*(--dirs.end())); (*pdirs[i])[i] = pow_gps; dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_2N_RAND ) ); pdirs[i+_nc] = &(*(--dirs.end())); (*pdirs[i+_nc])[i] = -pow_gps; rem_cols.push_back(i); rem_col_by_row[i] = i; } // random perturbations: for ( i = 1 ; i < _nc ; ++i ) { if ( rem_col_by_row[i] > 0 ) { v = NOMAD::RNG::rand()%3 - 1; // v in { -1 , 0 , 1 } if ( v ) { // we decide a (i,j) couple: k = NOMAD::RNG::rand()%(rem_col_by_row[i]); cnt = 0; end3 = rem_cols.end(); it3 = rem_cols.begin(); while ( cnt != k ) { ++it3; ++cnt; } j = *it3; // the perturbation: (*pdirs[i])[j] = (*pdirs[j+_nc])[i] = -v * pow_gps; (*pdirs[j])[i] = (*pdirs[i+_nc])[j] = v * pow_gps; // updates: rem_cols.erase(it3); it3 = rem_cols.begin(); while ( *it3 != i ) ++it3; rem_cols.erase(it3); for ( k = i+1 ; k < _nc ; ++k ) rem_col_by_row[k] -= j<k ? 2 : 1; } } } } // GPS n+1, static: // ---------------- else if ( *it == NOMAD::GPS_NP1_STATIC ) { // (n+1)^st direction: dirs.push_back ( NOMAD::Direction ( _nc , -pow_gps , NOMAD::GPS_NP1_STATIC ) ); // first n directions: for ( i = 0 ; i < _nc ; ++i ) { dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_STATIC ) ); pd = &(*(--dirs.end())); (*pd)[i] = pow_gps; } } // GPS n+1, random: // ---------------- else if ( *it == NOMAD::GPS_NP1_RAND ) { // (n+1)^st direction: dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_RAND ) ); NOMAD::Direction * pd1 = &(*(--dirs.end())); NOMAD::Double d; // first n directions: for ( i = 0 ; i < _nc ; ++i ) { dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_RAND ) ); pd = &(*(--dirs.end())); d = NOMAD::RNG::rand()%2 ? -pow_gps : pow_gps; (*pd )[i] = d; (*pd1)[i] = -d; } } // GPS n+1, static, uniform angles: // -------------------------------- else if ( *it == NOMAD::GPS_NP1_STATIC_UNIFORM ) { cst = pow_gps * sqrt(static_cast<double>(_nc)*(_nc+1))/_nc; // n first directions: for ( j = _nc-1 ; j >= 0 ; --j ) { dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_STATIC_UNIFORM ) ); pd = &(*(--dirs.end())); k = _nc-j-1; for ( i = 0 ; i < k ; ++i ) (*pd)[i] = -cst / sqrt(static_cast<double>(_nc-i)*(_nc-i+1)); (*pd)[k] = (cst * (j+1)) / sqrt(static_cast<double>(j+1)*(j+2)); } // (n+1)^st direction: dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_STATIC_UNIFORM ) ); pd = &(*(--dirs.end())); for ( i = 0 ; i < _nc ; ++i ) (*pd)[i] = -cst / sqrt(static_cast<double>(_nc-i)*(_nc-i+1)); } // GPS n+1, random, uniform angles: // -------------------------------- // (we apply the procedure defined in // "Pattern Search Methods for user-provided points: // application to molecular geometry problems", // by Alberto, Nogueira, Rocha and Vicente, // SIOPT 14-4, 1216-1236, 2004, doi:10.1137/S1052623400377955) else if ( *it == NOMAD::GPS_NP1_RAND_UNIFORM ) { cst = pow_gps * sqrt(static_cast<double>(_nc)*(_nc+1))/_nc; // n first directions: for ( j = _nc-1 ; j >= 0 ; --j ) { dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_STATIC_UNIFORM ) ); pd = &(*(--dirs.end())); k = _nc-j-1; for ( i = 0 ; i < k ; ++i ) (*pd)[i] = -cst / sqrt(static_cast<double>(_nc-i)*(_nc-i+1)); (*pd)[k] = (cst * (j+1)) / sqrt(static_cast<double>(j+1)*(j+2)); } // (n+1)^st direction: dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_STATIC_UNIFORM ) ); pd = &(*(--dirs.end())); for ( i = 0 ; i < _nc ; ++i ) (*pd)[i] = -cst / sqrt(static_cast<double>(_nc-i)*(_nc-i+1)); // random perturbations: NOMAD::Random_Pickup rp ( _nc ); std::vector<bool> done ( _nc ); bool chg_sgn; std::list<NOMAD::Direction>::iterator it; NOMAD::Double tmp; end2 = dirs.end(); for ( i = 0 ; i < _nc ; ++i ) done[i] = false; for ( i = 0 ; i < _nc ; ++i ) { k = rp.pickup(); if ( i != k && !done[i] ) { chg_sgn = ( NOMAD::RNG::rand()%2 != 0 ); for ( it = dirs.begin() ; it != end2 ; ++it ) { tmp = (*it)[i]; (*it)[i] = ( chg_sgn ? -1.0 : 1.0 ) * (*it)[k]; (*it)[k] = tmp; } done[i] = done[k] = true; } else if ( NOMAD::RNG::rand()%2 ) for ( it = dirs.begin() ; it != end2 ; ++it ) (*it)[i] = -(*it)[i]; } } } } // end of loop on the types of directions }