/*-------------------------------------------------------------------------------------*/
/* 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 Directions.cpp
\brief Set of polling directions (implementation)
\author Sebastien Le Digabel
\date 2010-04-13
\see Directions.hpp
*/
#include "Directions.hpp"
/*-----------------------------------*/
/* static members initialization */
/*-----------------------------------*/
int NOMAD::Directions::_max_halton_seed = -1;
/*---------------------------------------------------------*/
/* constructor */
/*---------------------------------------------------------*/
/* the Halton seed will be automatically computed later */
/* if Parameters::_halton_seed==-1 */
/*---------------------------------------------------------*/
NOMAD::Directions::Directions
( int nc ,
const std::set & direction_types ,
const std::set & sec_poll_dir_types ,
int halton_seed ,
const NOMAD::Display & out )
: _nc ( nc ) ,
_direction_types ( direction_types ) ,
_sec_poll_dir_types ( sec_poll_dir_types ) ,
_is_binary ( false ) ,
_is_categorical ( false ) ,
_lt_initialized ( false ) ,
_primes ( NULL ) ,
_halton_seed ( halton_seed ) ,
_out ( out )
{
// check the directions:
if ( _direction_types.find ( NOMAD::NO_DIRECTION ) != _direction_types.end() )
_direction_types.clear();
if ( _sec_poll_dir_types.find ( NOMAD::NO_DIRECTION ) != _sec_poll_dir_types.end() )
_sec_poll_dir_types.clear();
// is_orthomads: true if at least one direction is of type Ortho-MADS:
_is_orthomads = NOMAD::dirs_have_orthomads ( _direction_types );
if ( !_is_orthomads )
_is_orthomads = NOMAD::dirs_have_orthomads ( _sec_poll_dir_types );
}
/*---------------------------------------------------------*/
/* destructor */
/*---------------------------------------------------------*/
NOMAD::Directions::~Directions ( void )
{
if ( _lt_initialized ) {
int n = 2 * NOMAD::L_LIMITS;
for ( int i = 0 ; i <= n ; ++i )
delete _bl[i];
}
delete [] _primes;
}
/*---------------------------------------------------------*/
/* LT-MADS initializations (private) */
/*---------------------------------------------------------*/
void NOMAD::Directions::lt_mads_init ( void )
{
int n = 2 * NOMAD::L_LIMITS;
for ( int i = 0 ; i <= n ; ++i ) {
_bl [i] = NULL;
_hat_i[i] = -1;
}
_lt_initialized = true;
}
/*------------------------------------------------------*/
/* static method for computing a Halton seed (static) */
/*------------------------------------------------------*/
int NOMAD::Directions::compute_halton_seed ( int n ) {
int * primes = new int [n];
NOMAD::construct_primes ( n , primes );
int halton_seed = primes[n-1];
delete [] primes;
if ( halton_seed > NOMAD::Directions::_max_halton_seed )
NOMAD::Directions::_max_halton_seed = halton_seed;
if ( halton_seed > NOMAD::Mesh::get_max_halton_index() )
NOMAD::Mesh::set_max_halton_index ( halton_seed );
return halton_seed;
}
/*---------------------------------------------------------*/
/* Ortho-MADS initializations (private) */
/*---------------------------------------------------------*/
void NOMAD::Directions::ortho_mads_init ( int halton_seed )
{
_is_orthomads = true;
if ( !_primes ) {
_primes = new int[_nc];
NOMAD::construct_primes ( _nc , _primes );
}
_halton_seed = ( halton_seed < 0 ) ? _primes[_nc-1] : halton_seed;
if ( _halton_seed > NOMAD::Directions::_max_halton_seed )
NOMAD::Directions::_max_halton_seed = _halton_seed;
#ifdef DEBUG
_out << std::endl << "Ortho-MADS Halton seed (t0) = "
<< _halton_seed << std::endl;
#endif
if ( halton_seed > NOMAD::Mesh::get_max_halton_index() )
NOMAD::Mesh::set_max_halton_index ( halton_seed );
}
/*---------------------------------------------------------*/
/* set_binary */
/*---------------------------------------------------------*/
void NOMAD::Directions::set_binary ( void )
{
_is_binary = true;
_is_categorical = false;
_is_orthomads = false;
_halton_seed = -1;
_direction_types.clear();
_direction_types.insert ( NOMAD::GPS_BINARY );
if ( !_sec_poll_dir_types.empty() ) {
_sec_poll_dir_types.clear();
_sec_poll_dir_types.insert ( NOMAD::GPS_BINARY );
}
}
/*---------------------------------------------------------*/
/* set_categorical */
/*---------------------------------------------------------*/
void NOMAD::Directions::set_categorical ( void )
{
_is_categorical = true;
_is_binary = false;
_is_orthomads = false;
_halton_seed = -1;
_direction_types.clear();
_sec_poll_dir_types.clear();
}
/*----------------------------------------------------------------------*/
/* compute binary directions when all groups of variables are binary */
/* (private) */
/*----------------------------------------------------------------------*/
void NOMAD::Directions::compute_binary_directions
( std::list & d ) const
{
// _GPS_BINARY_ n directions:
NOMAD::Direction * pd;
for ( int i = 0 ; i < _nc ; ++i ) {
d.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_BINARY ) );
pd = &(*(--d.end()));
(*pd)[i] = 1.0;
}
}
/*---------------------------------------------------------*/
/* get the directions for a given mesh */
/*---------------------------------------------------------*/
void NOMAD::Directions::compute ( std::list & 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::const_iterator it2 , end2;
/*-----------------------------------*/
/* loop on the types of directions */
/*-----------------------------------*/
const std::set & dir_types =
(poll == NOMAD::PRIMARY) ? _direction_types : _sec_poll_dir_types;
std::set::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 ::const_iterator end3;
std::list ::iterator it3;
std::list rem_cols;
std::vector rem_col_by_row ( _nc );
// creation of the 2n directions:
std::vector 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(_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(_nc-i)*(_nc-i+1));
(*pd)[k] = (cst * (j+1)) / sqrt(static_cast(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(_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(_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(_nc-i)*(_nc-i+1));
(*pd)[k] = (cst * (j+1)) / sqrt(static_cast(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(_nc-i)*(_nc-i+1));
// random perturbations:
NOMAD::Random_Pickup rp ( _nc );
std::vector done ( _nc );
bool chg_sgn;
std::list::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
}
/*----------------------------------------------------------------*/
/* get just one direction for a given mesh (used by VNS search) */
/*----------------------------------------------------------------*/
bool NOMAD::Directions::compute_one_direction ( NOMAD::Direction & dir,
int mesh_index,
int halton_index )
{
dir.clear();
// categorical variables: do nothing:
if ( _is_categorical )
return false;
/*-------------------------------*/
/* binary variables */
/* (we use a random direction) */
/*-------------------------------*/
if ( _is_binary ) {
dir.reset ( _nc , 0.0 );
dir.set_type ( NOMAD::GPS_BINARY );
dir[NOMAD::RNG::rand()%_nc] = (NOMAD::RNG::rand()%2) ? -1.0 : 1.0;
}
/*----------------*/
/* Ortho-MADS */
/*----------------*/
else if ( _is_orthomads ) {
if ( !_primes )
ortho_mads_init ( _halton_seed );
dir.reset ( _nc , 0.0 );
dir.set_type ( NOMAD::ORTHO_1 );
NOMAD::Double alpha_t_l;
if ( !compute_halton_dir ( halton_index , mesh_index , alpha_t_l , dir ) )
return false;
// }
}
/*-------------*/
/* LT-MADS 1 */
/*-------------*/
else {
if ( !_lt_initialized)
lt_mads_init();
int hat_i;
dir = *get_bl ( mesh_index , NOMAD::LT_1 , hat_i );
}
return true;
}
/*---------------------------------------------------------*/
/* compute the Halton direction q(t,l) (private) */
/*---------------------------------------------------------*/
bool NOMAD::Directions::compute_halton_dir ( int halton_index ,
int mesh_index ,
NOMAD::Double & alpha_t_l ,
NOMAD::Direction & halton_dir ) const
{
alpha_t_l.clear();
int i;
NOMAD::Double d , norm = 0.0;
NOMAD::Point b ( _nc );
for ( i = 0 ; i < _nc ; ++i ) {
d = Directions::get_phi ( halton_index , _primes[i] );
b[i] = 2*d - 1.0;
norm += b[i].pow2();
}
norm = norm.sqrt();
// desired squared norm for q:
NOMAD::direction_type hdt = halton_dir.get_type();
NOMAD::Double target = ( hdt == NOMAD::ORTHO_2N || hdt == NOMAD::ORTHO_NP1_QUAD || hdt == NOMAD::ORTHO_NP1_NEG ) ?
pow ( NOMAD::Mesh::get_mesh_update_basis() , abs(mesh_index) / 2.0 ) :
pow ( NOMAD::Mesh::get_mesh_update_basis() , abs(mesh_index) );
NOMAD::Double x = target.sqrt();
NOMAD::Double fx = eval_ortho_norm ( x , norm , b , halton_dir );
NOMAD::Double y = 1.0 , fy , delta_x , abs_dx , min , delta_min , diff , eps;
bool inc , possible , set_eps = false;
int cnt = 0;
while ( fx != target )
{
// safety test:
if ( ++cnt > 1000 )
{
#ifdef DEBUG
_out << std::endl << "Warning (" << "Directions.cpp" << ", " << __LINE__
<< "): could not compute Halton direction for (t="
<< halton_index << ", ell=" << mesh_index
<< ")" << std::endl << std::endl;
#endif
alpha_t_l.clear();
halton_dir.clear();
return false;
}
if ( set_eps )
{
eps = 1e-8;
set_eps = false;
}
else
eps = 0.0;
inc = ( fx < target );
possible = false;
min = 1e+20;
for ( i = 0 ; i < _nc ; ++i )
{
if ( b[i] != 0.0 )
{
if ( b[i] > 0.0 )
{
if ( inc )
diff = 0.5+eps;
else
diff = -0.5-eps;
}
else
{
if ( inc )
diff = -0.5-eps;
else
diff = 0.5+eps;
}
delta_x = norm * ( halton_dir[i] + diff) / b[i] - x;
y = x + delta_x;
if ( y > 0 )
{
abs_dx = delta_x.abs();
if ( abs_dx < min )
{
min = abs_dx;
delta_min = delta_x;
possible = true;
}
}
}
}
if ( !possible ) {
#ifdef DEBUG
_out << std::endl << "Warning (" << "Directions.cpp" << ", " << __LINE__
<< "): could not compute Halton direction for (t="
<< halton_index << ", ell=" << mesh_index << ")"
<< std::endl << std::endl;
#endif
alpha_t_l.clear();
halton_dir.clear();
return false;
}
y = x + delta_min;
fy = eval_ortho_norm ( y , norm , b , halton_dir );
if ( fx == fy ) {
set_eps = true;
continue;
}
if ( fy==target )
break;
if ( inc && fy > target && fx > 0 ) {
eval_ortho_norm ( x , norm , b , halton_dir );
break;
}
if ( !inc && fy < target && fy > 0 )
break;
x = y;
fx = fy;
}
alpha_t_l = y;
return true;
}
/*-----------------------------------------------------------------*/
/* compute the squared norm of normalized(2u_t-e) for Ortho-MADS */
/* (private) */
/*-----------------------------------------------------------------*/
NOMAD::Double NOMAD::Directions::eval_ortho_norm ( const NOMAD::Double & x ,
const NOMAD::Double & norm ,
const NOMAD::Point & b ,
NOMAD::Point & new_b ) const
{
NOMAD::Double fx = 0.0;
for ( int i = 0 ; i < _nc ; ++i ) {
new_b[i] = ( x * b[i] / norm ).round();
fx += new_b[i]*new_b[i];
}
return fx;
}
/*--------------------------------------------------------*/
/* get the expression of an integer t in inverse base p */
/* (private, static) */
/*--------------------------------------------------------*/
NOMAD::Double NOMAD::Directions::get_phi ( int t , int p )
{
int div;
int size = int ( ceil ( log(static_cast(t+1)) /
log(static_cast(p)) ) );
int ll = t;
NOMAD::Double d = 0.0;
for ( int i = 0 ; i < size ; ++i ) {
div = NOMAD::Double ( pow ( p , size-i-1.0 ) ).round();
d += ( ll / div ) * pow ( static_cast(p) , i-size );
ll = ll % div;
}
return d;
}
/*----------------------------------------------------------------*/
/* . Householder transformation to generate _nc directions from */
/* the Halton direction */
/* . compute also H[i+nc] = -H[i] (completion to 2n directions) */
/* . private method */
/*----------------------------------------------------------------*/
void NOMAD::Directions::householder ( const NOMAD::Direction & halton_dir ,
bool complete_to_2n ,
NOMAD::Direction ** H ) const
{
int i , j;
NOMAD::Double norm2 = halton_dir.squared_norm() , v , h2i;
for ( i = 0 ; i < _nc ; ++i ) {
h2i = 2 * halton_dir[i];
for ( j = 0 ; j < _nc ; ++j ) {
// H[i]:
(*H[i])[j] = v = (i==j) ? norm2 - h2i * halton_dir[j] : - h2i * halton_dir[j];
// -H[i]:
if ( complete_to_2n )
(*H[i+_nc])[j] = -v;
}
}
}
/*---------------------------------------------------------*/
/* get the LT-MADS b(l) direction (private) */
/*---------------------------------------------------------*/
const NOMAD::Direction * NOMAD::Directions::get_bl ( int mesh_index ,
NOMAD::direction_type dtype ,
int & hat_i )
{
NOMAD::Direction * bl = _bl [ mesh_index + NOMAD::L_LIMITS ];
hat_i = _hat_i [ mesh_index + NOMAD::L_LIMITS ];
if ( !bl ) {
hat_i = -1;
create_lt_direction ( mesh_index , dtype , -1 , hat_i , bl );
}
return bl;
}
/*---------------------------------------------------------*/
/* create a new LT-MADS direction (private) */
/*---------------------------------------------------------*/
/* (if hat_i == -1, a new b(l) direction */
/* is created and hat_i is set) */
/*---------------------------------------------------------*/
void NOMAD::Directions::create_lt_direction ( int mesh_index ,
NOMAD::direction_type dtype ,
int diag_i ,
int & hat_i ,
NOMAD::Direction *& dir )
{
int i_pow_tau =
static_cast
( ceil ( pow ( NOMAD::Mesh::get_mesh_update_basis() , abs(mesh_index) / 2.0 ) ) );
int j = diag_i+1;
// new b(l) direction:
if ( hat_i < 0 ) {
_hat_i [ mesh_index + NOMAD::L_LIMITS ] = diag_i = hat_i = NOMAD::RNG::rand()%_nc;
_bl [ mesh_index + NOMAD::L_LIMITS ] = dir
= new NOMAD::Direction ( _nc, 0.0, dtype );
j = 0;
}
(*dir)[diag_i] = (NOMAD::RNG::rand()%2) ? -i_pow_tau : i_pow_tau;
for ( int k = j ; k < _nc ; ++k )
if ( k != hat_i ) {
(*dir)[k] = NOMAD::RNG::rand()%i_pow_tau;
if ( NOMAD::RNG::rand()%2 && (*dir)[k] > 0.0 )
(*dir)[k] = -(*dir)[k];
}
#ifdef DEBUG
if ( j==0 )
_out << "new LT-MADS b(l) direction: b(" << mesh_index << ") = "
<< *dir << std::endl << std::endl;
#endif
}
/*---------------------------------------------------------*/
/* permute the coordinates of a direction (private) */
/*---------------------------------------------------------*/
void NOMAD::Directions::permute_coords ( NOMAD::Direction & dir ,
const int * permutation_vector ) const
{
NOMAD::Point tmp = dir;
for ( int i = 0 ; i < _nc ; ++i )
dir [ permutation_vector[i] ] = tmp[i];
}
/*---------------------------------------------------------*/
/* display */
/*---------------------------------------------------------*/
void NOMAD::Directions::display ( const NOMAD::Display & out ) const
{
out << "n : " << _nc << std::endl
<< "types : { ";
std::set::const_iterator it , end = _direction_types.end();
for ( it = _direction_types.begin() ; it != end ; ++it )
out << "[" << *it << "] ";
out << "}" << std::endl
<< "sec poll types: { ";
end = _sec_poll_dir_types.end();
for ( it = _sec_poll_dir_types.begin() ; it != end ; ++it )
out << "[" << *it << "] ";
out << "}" << std::endl;
if ( _is_orthomads )
{
out << "halton_seed : ";
if ( _halton_seed >= 0 )
out << _halton_seed;
else
out << "auto";
out << std::endl;
}
}
/*---------------------------------------------------------*/
/* comparison operator */
/*---------------------------------------------------------*/
bool NOMAD::Directions::operator < ( const NOMAD::Directions & d ) const
{
// number of variables:
if ( _nc < d._nc )
return true;
if ( d._nc < _nc )
return false;
// Halton seed:
if ( _halton_seed < d._halton_seed )
return true;
if ( d._halton_seed < _halton_seed )
return false;
// boolean variables:
if ( _is_binary != d._is_binary )
return _is_binary;
if ( _is_categorical != d._is_categorical )
return _is_categorical;
if ( _is_orthomads != d._is_orthomads )
return _is_orthomads;
// direction types:
size_t nd = _direction_types.size();
if ( nd < d._direction_types.size() )
return true;
if ( d._direction_types.size() < nd )
return false;
size_t ns = _sec_poll_dir_types.size();
if ( ns < d._sec_poll_dir_types.size() )
return true;
if ( d._sec_poll_dir_types.size() < ns )
return false;
std::set::const_iterator
it1 = _direction_types.begin() ,
it2 = d._direction_types.begin() ,
end = _direction_types.end();
while ( it1 != end ) {
if ( *it1 < *it2 )
return true;
if ( *it2 < *it1 )
return false;
++it1;
++it2;
}
it1 = _sec_poll_dir_types.begin();
it2 = d._sec_poll_dir_types.begin();
end = _sec_poll_dir_types.end();
while ( it1 != end ) {
if ( *it1 < *it2 )
return true;
if ( *it2 < *it1 )
return false;
++it1;
++it2;
}
return false;
}