/*-------------------------------------------------------------------------------------*/
/* 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 Quad_Model.cpp
\brief Quadratic regression or MFN interpolation model (implementation)
\author Sebastien Le Digabel
\date 2010-08-31
\see Quad_Model.hpp
*/
#include "Quad_Model.hpp"
/*-----------------------------------------------------------*/
/* constructor */
/*-----------------------------------------------------------*/
NOMAD::Quad_Model::Quad_Model
( const NOMAD::Display & out ,
const std::vector & bbot ,
const NOMAD::Cache & cache ,
const NOMAD::Signature & signature )
: _out ( out ) ,
_bbot ( bbot ) ,
_interpolation_type ( NOMAD::UNDEFINED_INTERPOLATION_TYPE ) ,
_n ( signature.get_n() ) ,
_nfree ( _n ) ,
_fixed_vars ( new bool [_n] ) ,
_index ( NULL ) ,
_alpha ( NULL ) ,
_cache ( cache ) ,
_signature ( signature ) ,
_error_flag ( true )
{
for ( int i = 0 ; i < _n ; ++i )
_fixed_vars[i] = false;
init_alpha();
}
/*-----------------------------------------------------------*/
/* destructor */
/*-----------------------------------------------------------*/
NOMAD::Quad_Model::~Quad_Model ( void )
{
int m = static_cast ( _bbot.size() );
for ( int i = 0 ; i < m ; ++i )
delete _alpha[i];
delete [] _alpha;
delete [] _fixed_vars;
delete [] _index;
// clear the interpolation set Y:
for ( size_t k = 0 ; k < _Y.size() ; ++k )
delete _Y[k];
}
/*-----------------------------------------------------------*/
/* initialize alpha, the model parameters (private) */
/*-----------------------------------------------------------*/
void NOMAD::Quad_Model::init_alpha ( void )
{
_n_alpha = ( _nfree + 1 ) * ( _nfree + 2 ) / 2;
int i , m = static_cast ( _bbot.size() );
// initialize _alpha:
// ------------------
if ( _alpha ) {
for ( i = 0 ; i < m ; ++i )
delete _alpha[i];
delete [] _alpha;
}
_alpha = new NOMAD::Point * [m];
for ( i = 0 ; i < m ; ++i )
_alpha[i] = ( _bbot[i] == NOMAD::OBJ || NOMAD::bbot_is_constraint(_bbot[i]) ) ?
new NOMAD::Point ( _n_alpha ) : NULL;
// initialize _index:
// ------------------
// example: with 3 variables (X,Y,Z) with Y fixed.
// --------
// the problem is reduced to the two variables x=X and y=Z,
// and _index is corresponds to:
//
// 0 1 0 1 : index[0] = 0
// 1 X 1 x : index[1] = 1
// 2 Y 2 y : index[2] = 3
// 3 Z 3 .5 x^2 : index[3] = 4
// 4 .5 X^2 4 .5 y^2 : index[4] = 6
// 5 .5 Y^2 5 xy : index[5] = 8
// 6 .5 Z^2
// 7 XY
// 8 XZ
// 9 YZ
//
// If there are no fixed variables, index is of size (n+1)(n+2)/2
// with index[i] = i.
delete [] _index;
_index = new int [_n_alpha];
int nm1 = _n - 1;
int c1 = 2*_n + 1;
int c2 = 1;
int k1 , k2;
_index[0] = 0;
for ( i = 0 ; i < _n ; ++i ) {
if ( !_fixed_vars[i] ) {
_index[c2 ] = i+1;
_index[c2+_nfree] = i+1+_n;
++c2;
}
}
c2 += _nfree;
for ( k1 = 0 ; k1 < nm1 ; ++k1 )
for ( k2 = k1+1 ; k2 < _n ; ++k2 ) {
if ( !_fixed_vars[k1] && !_fixed_vars[k2] )
_index[c2++] = c1;
++c1;
}
}
/*---------------------------------------------------------*/
/* check evaluation point outputs before the integration */
/* into an interpolation set (private) */
/*---------------------------------------------------------*/
bool NOMAD::Quad_Model::check_outputs ( const NOMAD::Point & bbo , int m ) const {
if ( bbo.size() != m )
return false;
for ( int i = 0 ; i < m ; ++i )
if ( !bbo[i].is_defined() || bbo[i].value() > NOMAD::MODEL_MAX_OUTPUT )
return false;
return true;
}
/*-----------------------------------------------------------*/
/* construct the interpolation set Y */
/*-----------------------------------------------------------*/
void NOMAD::Quad_Model::construct_Y ( const NOMAD::Point & center ,
const NOMAD::Point & interpolation_radius ,
int max_Y_size )
{
_error_flag = true;
if ( center.size() != _n ||
interpolation_radius.size() != _n ||
!center.is_complete() ||
!interpolation_radius.is_complete() )
return;
_error_flag = false;
_center = center;
int m = static_cast ( _bbot.size() );
// browse the cache:
const NOMAD::Eval_Point * cur = _cache.begin();
while ( cur )
{
if ( cur->get_eval_status() == NOMAD::EVAL_OK &&
cur->get_n () == _n &&
_signature.is_compatible (*cur) )
{
const NOMAD::Point & bbo = cur->get_bb_outputs();
if ( check_outputs ( bbo , m ) ) {
// the center point has been found
// (it is put in first position):
if ( _center == *cur ) {
_Y.push_back ( new NOMAD::Eval_Point ( *cur ) );
int nYm1 = get_nY() - 1;
if ( nYm1 > 0 ) {
NOMAD::Eval_Point * tmp = _Y[0];
_Y[0 ] = _Y[nYm1];
_Y[nYm1] = tmp;
}
}
// other points must within the interpolation radius:
else if ( is_within_radius ( *cur , interpolation_radius ) )
_Y.push_back ( new NOMAD::Eval_Point ( *cur ) );
}
}
cur = _cache.next();
}
// respect the limit on the number of points:
if ( get_nY() > max_Y_size )
reduce_Y ( center , max_Y_size );
}
/*-----------------------------------------------------------------*/
/* reduce the number of interpolation points */
/*-----------------------------------------------------------------*/
void NOMAD::Quad_Model::reduce_Y ( const NOMAD::Point & center ,
int max_Y_size )
{
int nY = get_nY();
if ( nY <= max_Y_size )
return;
std::multiset Ys;
for ( int k = 0 ; k < nY ; ++k )
Ys.insert ( NOMAD::Model_Sorted_Point ( _Y[k] , center ) );
_Y.clear();
std::multiset::const_iterator it , end = Ys.end();
for ( it = Ys.begin() ; it != end ; ++it ) {
if ( get_nY() < max_Y_size )
_Y.push_back ( static_cast ( it->get_point() ) );
else
delete it->get_point();
}
}
/*-----------------------------------------------------------*/
/* check if an unscaled point is in B(center,radius) for a */
/* given radius (private) */
/*-----------------------------------------------------------*/
bool NOMAD::Quad_Model::is_within_radius ( const NOMAD::Point & x ,
const NOMAD::Point & radius ) const
{
if ( x.size() != _n || radius.size() != _n )
return false;
for ( int i = 0 ; i < _n ; ++i )
if ( !x[i].is_defined() ||
!radius[i].is_defined() ||
radius[i] < ( x[i] - _center[i]).abs() )
return false;
return true;
}
/*------------------------------------------------------*/
/* check if a scaled point is inside the trust radius */
/*------------------------------------------------------*/
bool NOMAD::Quad_Model::is_within_trust_radius ( const NOMAD::Point & x ) const
{
// check that all scaled coordinates are in [-1;1] and
// that fixed variables are equal to zero:
for ( int i = 0 ; i < _n ; ++i )
if ( !_ref [i].is_defined() ||
!_scaling[i].is_defined() ||
! x[i].is_defined() ||
x[i].abs() > 1.0 ||
( _fixed_vars[i] && x[i] != 0.0 ) )
return false;
return true;
}
/*--------------------------------------------------------------*/
/* . define scaling to put all coordinates centered in [-r;r] */
/* . looks also for fixed variables */
/*--------------------------------------------------------------*/
void NOMAD::Quad_Model::define_scaling ( const NOMAD::Double & r )
{
if ( _error_flag || _Y.empty() ) {
_error_flag = true;
return;
}
int i , k;
int nY = get_nY();
NOMAD::Point min(_n) , max(_n);
NOMAD::Double tmp;
// The parameters defining the scaling with rotation (see define_scaling_by_direction) are cleared.
// Only the parameters for the basic scaling are set
_dirP.clear();
_epsilon.clear();
_delta_m.clear();
_scaling.clear();
_ref.clear ();
_ref.reset ( _n );
_scaling.reset ( _n );
// compute the reference (center of Y):
for ( k = 0 ; k < nY ; ++k )
{
if ( !_Y[k] || _n != _Y[k]->size() )
{
_error_flag = true;
return;
}
for ( i = 0 ; i < _n ; ++i )
{
tmp = (*_Y[k])[i];
if ( !min[i].is_defined() || tmp < min[i] )
min[i] = tmp;
if ( !max[i].is_defined() || tmp > max[i] )
max[i] = tmp;
}
}
for ( i = 0 ; i < _n ; ++i )
_ref[i] = ( min[i] + max[i] ) / 2.0;
#ifdef MODEL_STATS
_Yw = NOMAD::Double();
for ( i = 0 ; i < _n ; ++i )
{
tmp = max[i]-min[i];
if ( !_Yw.is_defined() || tmp > _Yw )
_Yw = tmp;
}
#endif
#ifdef DEBUG
_out << std::endl
<< "define_scaling(): reference = ( " << _ref << " )" << std::endl;
#endif
// compute the scaling (and detect fixed variables):
for ( k = 0 ; k < nY ; ++k ) {
for ( i = 0 ; i < _n ; ++i ) {
tmp = ( (*_Y[k])[i] - _ref[i] ).abs();
if ( !_scaling[i].is_defined() || _scaling[i] < tmp )
_scaling[i] = tmp;
}
}
_nfree = _n;
for ( i = 0 ; i < _n ; ++i )
{
if ( _scaling[i] == 0.0 )
{
_scaling [i] = 0.0;
_fixed_vars[i] = true;
--_nfree;
if ( _nfree == 0 )
{
_scaling.clear();
_ref.clear();
_error_flag = true;
return;
}
}
else
_scaling[i] *= 1.0/r; // all coordinates in [-r;r]
}
if ( _nfree < _n )
init_alpha();
for ( k = 0 ; k < nY ; ++k )
{
if ( !scale ( *_Y[k] ) )
{
_scaling.clear();
_error_flag = true;
return;
}
}
#ifdef DEBUG
_out << "define_scaling(): scaling = ( " << _scaling << " )" << std::endl;
#endif
_error_flag = false;
}
/*-------------------------------------------------------------------*/
/* . Scaling with rotation based on a set of directions. */
/* See paper: */
/* Reducing the number of function evaluations in */
/* Mesh Adaptive Direct Search algorithms, Audet, Ianni, */
/* LeDigabel, Tribes, 2012 */
/* . looks also for fixed variables */
/*-------------------------------------------------------------------*/
void NOMAD::Quad_Model::define_scaling_by_directions ( const std::list & dirs, const NOMAD::Point & delta_m, const NOMAD::Double & epsilon )
{
if ( _error_flag || _Y.empty() ) {
_error_flag = true;
return;
}
int i , k;
int nY = get_nY();
NOMAD::Point min(_n) , max(_n);
NOMAD::Double tmp;
// The parameters defining the basic scaling (see define_scaling) are cleared.
// Only the parameters for the direction scaling are set
_scaling.clear();
_ref.clear ();
// For direction scaling
if (static_cast (dirs.size())!=_n || static_cast(delta_m.size()) != _n || epsilon<=0.0 || epsilon>=1)
{
_error_flag = true;
return;
}
_delta_m=delta_m;
// Get D' from dirs (scaling with delta_m
std::list::const_iterator itDir;
for (itDir=dirs.begin(); itDir != dirs.end(); itDir++)
{
NOMAD::Direction dir_i(_n,0.0,itDir->get_type());
dir_i.set_index(itDir->get_index());
for ( int i = 0 ; i < _n ; ++i )
{
if (_delta_m[i]<=0.0)
{
_error_flag=true;
return;
}
dir_i[i]=(*itDir)[i]/_delta_m[i];
}
_dirP.push_back(dir_i);
}
_epsilon=epsilon;
// compute the min and the max:
for ( k = 0 ; k < nY ; ++k )
{
if ( !_Y[k] || _n != _Y[k]->size() )
{
_error_flag = true;
return;
}
for ( i = 0 ; i < _n ; ++i )
{
tmp = (*_Y[k])[i];
if ( !min[i].is_defined() || tmp < min[i] )
min[i] = tmp;
if ( !max[i].is_defined() || tmp > max[i] )
max[i] = tmp;
}
}
#ifdef MODEL_STATS
_Yw = NOMAD::Double();
for ( i = 0 ; i < _n ; ++i )
{
tmp = max[i]-min[i];
if ( !_Yw.is_defined() || tmp > _Yw )
_Yw = tmp;
}
#endif
// Detect fixed variables:
_nfree = _n;
for ( i = 0 ; i < _n ; ++i )
{
bool fixed_var_i=true;
for ( k = 0 ; k < nY ; ++k )
{
if ( ( (*_Y[k])[i] - _center[i] ).abs() > 0.0 )
{
fixed_var_i=false;
break;
}
}
_fixed_vars[i]=fixed_var_i;
if (fixed_var_i)
--_nfree;
if ( _nfree == 0 )
{
_scaling.clear();
_ref.clear();
_dirP.clear();
_error_flag = true;
return;
}
}
if ( _nfree < _n )
init_alpha();
// Perform scaling of Y
for ( k = 0 ; k < nY ; ++k )
{
if ( !scale ( *_Y[k] ) )
{
_scaling.clear();
_dirP.clear();
_error_flag = true;
return;
}
}
#ifdef DEBUG
_out << "define_scaling_by_direction(): " << std::endl;
for ( itDir = _dirP.begin() ; itDir != _dirP.end() ; ++itDir )
{
_out << "dirPrime ";
_out.display_int_w ( (*itDir).get_index() , _dirP.size() );
_out << " : " << *itDir << std::endl;
}
#endif
_error_flag = false;
}
/*--------------------------------------------------------------*/
/* scale a point */
/*--------------------------------------------------------------*/
bool NOMAD::Quad_Model::scale ( NOMAD::Point & x ) const
{
if ( _error_flag || _n != x.size() )
return false;
if (_dirP.size()==0)
{
// Scale without rotation
for ( int i = 0 ; i < _n ; ++i )
{
if ( !_ref [i].is_defined() ||
!_scaling[i].is_defined() ||
! x[i].is_defined() )
return false;
x[i] -= _ref[i];
if ( _scaling[i] != 0 )
x[i] /= _scaling[i];
}
}
else
{
if (! _epsilon.is_defined() || !_delta_m.is_complete())
return false;
// Scale with rotation based on direction and center (see paper Reducing the number of function evaluations in Mesh Adaptive Direct Search algorithms, Audet, Ianni, LeDigabel, Tribes, 2012
// T(y)=(D')^-1*(center-x)/delta_m/(1-epsilon) - epsilon*1/(1-epsilon)
// (D')^-1=(D')^T/normCol^2
NOMAD::Point temp(_n,0.0);
double normCol2=0.0;
std::list::const_iterator itDir=_dirP.begin();
for ( int i = 0 ; i < _n ; ++i )
{
normCol2+=pow((*itDir)[i].value(),2);
if (_delta_m[i] !=0.0)
temp[i]=(_center[i]-x[i])/_delta_m[i]/(1-_epsilon);
else
return false;
x[i]=0.0;
}
int j=0;
for (itDir=_dirP.begin(); itDir != _dirP.end(); itDir++,j++)
{
for ( int i = 0 ; i < _n ; ++i )
{
x[j]+=temp[i]*(*itDir)[i]/normCol2;
}
x[j]-=_epsilon/(1.0-_epsilon);
}
}
return true;
}
/*-----------------------------------------------------------*/
/* unscale a point */
/*-----------------------------------------------------------*/
bool NOMAD::Quad_Model::unscale ( NOMAD::Point & x ) const
{
if ( _error_flag || _n != x.size() )
return false;
if (_dirP.size()==0)
{
// Scale without rotation
for ( int i = 0 ; i < _n ; ++i )
{
if ( !_ref [i].is_defined() ||
!_scaling[i].is_defined() ||
! x[i].is_defined() )
return false;
x[i] *= _scaling[i];
x[i] += _ref [i];
}
}
else
{
if (! _epsilon.is_defined() || !_delta_m.is_complete())
return false;
// UnScale with rotation see paper Reducing the number of function evaluations in Mesh Adaptive Direct Search algorithms, Audet, Ianni, LeDigabel, Tribes, 2012
//T^−1(x) = center+ _delta_m Dp ((ε−1)x−ε1)
NOMAD::Point temp(_n,0.0);
for ( int i = 0 ; i < _n ; ++i )
{
temp[i]=(x[i]*(_epsilon-1.0)-_epsilon)*_delta_m[i];
x[i]=0.0;
}
std::list::const_iterator itDir;
int j=0;
for (itDir=_dirP.begin(); itDir != _dirP.end(); itDir++,j++)
{
for (int i=0 ; i< _n ; i++)
{
x[i]+=temp[j]*(*itDir)[i];
}
}
for ( int i = 0 ; i < _n ; ++i )
{
x[i]+=_center[i];
}
}
return true;
}
/*-----------------------------------------------------------*/
/* unscale the slope at a point */
/*-----------------------------------------------------------*/
bool NOMAD::Quad_Model::unscale_grad ( NOMAD::Point & x ) const
{
if ( _error_flag || _n != x.size() )
return false;
for ( int i = 0 ; i < _n ; ++i )
{
if (!_scaling[i].is_defined() || !x[i].is_defined() )
return false;
x[i] *= _scaling[i];
}
return true;
}
/*------------------------------------------------------------------*/
/* compute the element (i,j) of the interpolation matrix M(phi,Y) */
/* (private) */
/*------------------------------------------------------------------*/
double NOMAD::Quad_Model::compute_M ( int i , int j ) const {
if ( _error_flag )
return 0.0;
if ( j == 0 )
return 1.0;
if ( j <= _nfree )
return (*_Y[i])[_index[j]-1].value();
if ( j <= 2 * _nfree )
return 0.5 * pow ( (*_Y[i])[_index[j-_nfree]-1].value() , 2.0 );
int nm1 = _nfree - 1;
int jm2n , dec , r , i1 , i2;
jm2n = j - 2 * _nfree;
dec = nm1;
r = jm2n;
i1 = -1;
while ( r > 0 ) {
r -= dec;
++i1;
--dec;
}
i2 = r + nm1;
return (*_Y[i])[_index[i1+1]-1].value() * (*_Y[i])[_index[i2+1]-1].value();
}
/*-----------------------------------------------------------*/
/* construct m models (one by output) */
/*-----------------------------------------------------------*/
void NOMAD::Quad_Model::construct ( bool use_WP ,
double eps ,
int max_mpn ,
int max_Y_size )
{
if ( _error_flag )
return;
int p1 = get_nY();
// MFN interpolation:
if ( p1 < _n_alpha ) {
_interpolation_type = NOMAD::MFN;
_error_flag = !construct_MFN_model ( eps , max_mpn , max_Y_size );
}
else {
_error_flag = true;
// well-poised regression:
if ( use_WP && p1 > _n_alpha ) {
_interpolation_type = NOMAD::WP_REGRESSION;
_error_flag = !construct_WP_model ( max_Y_size );
}
// regression:
if ( _error_flag ) {
_interpolation_type = NOMAD::REGRESSION;
_error_flag = !construct_regression_model ( eps , max_mpn , max_Y_size );
}
}
}
/*---------------------------------------------------------------*/
/* find interpolation point with max Lagrange polynomial value */
/*---------------------------------------------------------------*/
/* . ji = argmax |li(x)| for x in Y */
/* . used in construct_WP_model() */
/* . private */
/*---------------------------------------------------------------*/
int NOMAD::Quad_Model::find_max_lix
( const NOMAD::Point & li ,
const std::vector & Y ,
int i1 ,
int i2 ,
NOMAD::Double & max_lix ) const
{
max_lix = -1.0;
int ji = -1;
NOMAD::Double tmp;
for ( int j = i1 ; j <= i2 ; ++j ) {
tmp = eval ( *Y[j] , li );
if ( tmp.is_defined() ) {
tmp = tmp.abs();
if ( tmp > max_lix ) {
max_lix = tmp;
ji = j;
}
}
}
if ( ji < 0 )
max_lix.clear();
return ji;
}
/*-----------------------------------------------------------*/
/* construct well-poised (WP) model (private) */
/*-----------------------------------------------------------*/
bool NOMAD::Quad_Model::construct_WP_model ( int max_Y_size )
{
#ifdef DEBUG
_out << std::endl
<< NOMAD::open_block ( "NOMAD::Quad_Model::construct_WP_model()" );
#endif
// check the set Y:
if ( !check_Y() )
return false;
int i , j , k , p1 = get_nY();
// the number of points (p+1) must be in [1+(n+1)(n+2)/2;MS_MAX_Y_SIZE]:
if ( p1 <= _n_alpha || p1 > max_Y_size ) {
#ifdef DEBUG
_out << std::endl
<< "NOMAD::Quad_Model::construct_WP_model(): "
<< "(p+1) not in [1+(n+1)(n+2)/2;" << max_Y_size << "]"
<< std::endl << NOMAD::close_block() << std::endl;
#endif
return false;
}
// Lagrange polynomials:
std::vector l;
for ( i = 0 ; i < _n_alpha ; ++i ) {
l.push_back ( new NOMAD::Point ( _n_alpha ) );
for ( j = 0 ; j < _n_alpha ; ++j )
(*l[i])[j] = (i==j) ? 1.0 : 0.0;
}
// creation of sets Y1 and Y2; Y2 contains all available points
// of _Y and Y1 will be the 'well-poised' set with n_alpha points:
std::vector Y1 , Y2 = _Y;
int iy2 , ny2m1 = p1-1;
NOMAD::Double max_lix , liyi , ljyi;
// we init Y1 with the first point of Y:
Y1.push_back ( Y2[0] );
Y2[0] = Y2[ny2m1];
Y2.resize ( ny2m1 );
// use algo 6.2 p.95 of the DFO book in order to construct Lagrange polynomials:
// -----------------------------------------------------------------------------
for ( i = 0 ; i < _n_alpha ; ++i ) {
// 1. point selection (select a point in Y2: Y2[iy2]):
// -------------------
if ( i > 0 ) {
ny2m1 = static_cast(Y2.size())-1;
iy2 = find_max_lix ( *l[i] , Y2 , 0 , ny2m1 , max_lix );
if ( iy2 < 0 ) {
#ifdef DEBUG
_out << std::endl
<< "NOMAD::Quad_Model::construct_WP_model(): "
<< "cannot find candidate in Y"
<< std::endl << NOMAD::close_block() << std::endl;
#endif
for ( i = 0 ; i < _n_alpha ; ++i )
delete l[i];
return false;
}
// add Y2[iy2] in Y1:
Y1.push_back ( Y2[iy2] );
Y2[iy2] = Y2[ny2m1];
Y2.resize (ny2m1);
}
// 2. normalization:
// -----------------
liyi = eval ( *Y1[i] , *l[i] );
if ( liyi.abs().value() < 1e-15 ) {
#ifdef DEBUG
_out << std::endl
<< "NOMAD::Quad_Model::construct_WP_model(): set Y is not poised"
<< std::endl << NOMAD::close_block() << std::endl;
#endif
for ( i = 0 ; i < _n_alpha ; ++i )
delete l[i];
return false;
}
for ( k = 0 ; k < _n_alpha ; ++k ) {
(*l[i])[k] /= liyi;
if ( (*l[i])[k].abs().value() < 1e-15 )
(*l[i])[k] = 0.0;
}
// 3. orthogonalization:
// ---------------------
for ( j = 0 ; j < _n_alpha ; ++j )
if ( j != i ) {
ljyi = eval ( *Y1[i] , *l[j] );
for ( k = 0 ; k < _n_alpha ; ++k ) {
(*l[j])[k] = (*l[j])[k] - ljyi * (*l[i])[k];
if ( (*l[j])[k].abs().value() < 1e-15 )
(*l[j])[k] = 0.0;
}
}
}
#ifdef DEBUG
display_lagrange_polynomials ( l , Y1 );
#endif
// compute alpha:
// --------------
int m = static_cast ( _bbot.size() );
for ( i = 0 ; i < m ; ++i )
if ( _alpha[i] ) {
for ( j = 0 ; j < _n_alpha ; ++j ) {
(*_alpha[i])[j] = 0.0;
for ( k = 0 ; k < _n_alpha ; ++k )
(*_alpha[i])[j] += Y1[k]->get_bb_outputs()[i] * (*l[k])[j];
}
}
// poisedness improvement using algorithm 6.3 page 95:
// ---------------------------------------------------
// old alpha:
NOMAD::Point ** old_alpha = new NOMAD::Point * [m] , ** tmp_alpha;
for ( i = 0 ; i < m ; ++i )
old_alpha[i] = ( _alpha[i] ) ?
new NOMAD::Point ( _n_alpha ) : NULL;
int ik;
NOMAD::Double ljyk , lkyk , lix , new_rel_err ,
cur_rel_err = compute_max_rel_err();
if ( cur_rel_err.is_defined() && cur_rel_err.value() > 1e-15 ) {
for ( int niter = 0 ; niter < 10 ; ++niter ) {
ny2m1 = static_cast(Y2.size())-1;
if ( ny2m1 < 0 )
break;
max_lix = -1.0;
iy2 = -1;
ik = -1;
for ( i = 0 ; i < _n_alpha ; ++i ) {
j = find_max_lix ( *l[i] , Y2 , 0 , ny2m1 , lix );
if ( j >= 0 && lix > max_lix ) {
max_lix = lix;
iy2 = j;
ik = i;
}
}
if ( ik < 0 )
break;
// set Y1[ik] = Y2[iy2]:
Y1[ik ] = Y2[iy2];
Y2[iy2] = Y2[ny2m1];
Y2.resize ( ny2m1 );
lkyk = eval ( *Y1[ik] , *l[ik] );
if ( lkyk.abs() <= 1e-15 )
break;
// update Lagrange polynomials:
// ----------------------------
// normalization and orthogonalization:
for ( i = 0 ; i < _n_alpha ; ++i )
(*l[ik])[i] /= lkyk;
for ( j = 0 ; j < _n_alpha ; ++j ) {
if ( j != ik ) {
ljyk = eval ( *Y1[ik] , *l[j] );
for ( i = 0 ; i < _n_alpha ; ++i )
(*l[j])[i] = (*l[j])[i] - ljyk * (*l[ik])[i];
}
}
// save old alpha and compute new one:
for ( i = 0 ; i < m ; ++i )
if ( _alpha[i] ) {
*(old_alpha[i]) = *(_alpha[i]);
for ( j = 0 ; j < _n_alpha ; ++j ) {
(*_alpha[i])[j] = 0.0;
for ( k = 0 ; k < _n_alpha ; ++k )
(*_alpha[i])[j] += Y1[k]->get_bb_outputs()[i] * (*l[k])[j];
}
}
// compute new error:
new_rel_err = compute_max_rel_err();
// if no better error, restore old alpha and exit loop:
if ( !new_rel_err.is_defined() || new_rel_err >= cur_rel_err ) {
tmp_alpha = _alpha;
_alpha = old_alpha;
old_alpha = tmp_alpha;
break;
}
cur_rel_err = new_rel_err;
}
}
for ( i = 0 ; i < m ; ++i )
delete old_alpha[i];
delete [] old_alpha;
for ( i = 0 ; i < _n_alpha ; ++i )
delete l[i];
#ifdef DEBUG
_out.close_block();
#endif
return true;
}
/*-----------------------------------------------------------*/
/* construct regression model (private) */
/*-----------------------------------------------------------*/
bool NOMAD::Quad_Model::construct_regression_model ( double eps ,
int max_mpn ,
int max_Y_size )
{
#ifdef DEBUG
_out << std::endl
<< NOMAD::open_block ( "NOMAD::Quad_Model::construct_regression_model()" );
#endif
_error_flag = false;
// check the set Y:
if ( !check_Y() )
return false;
int p1 = get_nY();
// the number of points (p+1) must be in [(n+1)(n+2)/2;MS_MAX_Y_SIZE]:
if ( p1 < _n_alpha || p1 > max_Y_size ) {
#ifdef DEBUG
_out << std::endl
<< "NOMAD::Quad_Model::construct_regression_model(): "
<< "(p+1) not in [(n+1)(n+2)/2;"
<< max_Y_size << "]"
<< std::endl << NOMAD::close_block() << std::endl;
#endif
return false;
}
// for this procedure, the number of points is limited to 500
// (because of the SVD decomposition):
if ( p1 > 500 ) {
reduce_Y ( NOMAD::Point ( _n , 0.0 ) , 500 );
p1 = 500;
}
// construct the matrix F=M'M (_n_alpha,_n_alpha):
// -----------------------------------------------
int i , j , k;
double ** F = new double *[_n_alpha];
double ** M = new double *[p1];
for ( i = 0 ; i < p1 ; ++i ) {
M[i] = new double[_n_alpha];
for ( j = 0 ; j < _n_alpha ; ++j )
M[i][j] = compute_M ( i , j );
}
for ( i = 0 ; i < _n_alpha ; ++i ) {
F[i] = new double[_n_alpha];
for ( j = 0 ; j <= i ; ++j ) {
F[i][j] = 0.0;
for ( k = 0 ; k < p1 ; ++k )
F[i][j] += M[k][i] * M[k][j];
if ( i != j )
F[j][i] = F[i][j];
}
}
#ifdef DEBUG
_out << std::endl << "F=";
for ( i = 0 ; i < _n_alpha ; ++i ) {
_out << "\t";
for ( j = 0 ; j < _n_alpha ; ++j )
_out << std::setw(12) << F[i][j] << " ";
_out << std::endl;
}
#endif
bool error = false;
// SVD decomposition of the F matrix (F=U.W.V'):
// ---------------------------------------------
// (F will be transformed in U)
double * W = new double [_n_alpha];
double ** V = new double *[_n_alpha];
for ( i = 0 ; i < _n_alpha ; ++i )
V[i] = new double[_n_alpha];
std::string error_msg;
if ( NOMAD::SVD_decomposition ( error_msg , F , W , V , _n_alpha , _n_alpha , max_mpn ) ) {
// compute condition number:
compute_cond ( W , _n_alpha , eps );
#ifdef DEBUG
_out << std::endl << "F=";
for ( i = 0 ; i < _n_alpha ; ++i ) {
_out << "\t";
for ( j = 0 ; j < _n_alpha ; ++j )
_out << std::setw(12) << F[i][j] << " ";
_out << std::endl;
}
_out << std::endl << "W=\t";
for ( i = 0 ; i < _n_alpha ; ++i )
_out << std::setw(12) << W[i] << " ";
_out << std::endl << std::endl << "cond=" << _cond << std::endl;
_out << std::endl << "V=";
for ( i = 0 ; i < _n_alpha ; ++i ) {
_out << "\t";
for ( j = 0 ; j < _n_alpha ; ++j )
_out << std::setw(12) << V[i][j] << " ";
_out << std::endl;
}
#endif
}
else {
#ifdef DEBUG
_out << std::endl << "NOMAD::Quad_Model::construct_regression_model(): "
<< "SVD decomposition (" << error_msg << ")"
<< std::endl << NOMAD::close_block() << std::endl;
#endif
error = true;
_cond.clear();
}
// resolution of system F.alpha = M'.f(Y):
// ---------------------------------------
if ( !error ) {
int m = static_cast ( _bbot.size() );
for ( i = 0 ; i < m ; ++i )
if ( _alpha[i] )
solve_regression_system ( M , F , W , V , i , *_alpha[i] , eps );
}
// free memory:
for ( i = 0 ; i < _n_alpha ; ++i ) {
delete [] F[i];
delete [] V[i];
}
for ( i = 0 ; i < p1 ; ++i )
delete [] M[i];
delete [] M;
delete [] F;
delete [] V;
delete [] W;
#ifdef DEBUG
_out.close_block();
#endif
return !error;
}
/*-------------------------------------------------------------*/
/* compute condition number (private) */
/*-------------------------------------------------------------*/
void NOMAD::Quad_Model::compute_cond ( const double * W , int n , double eps )
{
double min = NOMAD::INF;
double max = -min;
for ( int i = 0 ; i < n ; ++i ) {
if ( W[i] < min )
min = W[i];
if ( W[i] > max )
max = W[i];
}
if ( min < eps )
min = eps;
_cond = max / min;
}
/*-------------------------------------------------------------*/
/* resolution of system F.alpha = M'.f(Y) for the regression */
/* (private) */
/*-------------------------------------------------------------*/
void NOMAD::Quad_Model::solve_regression_system ( double ** M ,
double ** F ,
double * W ,
double ** V ,
int bbo_index ,
NOMAD::Point & alpha ,
double eps ) const
{
// resize the alpha vector:
if ( alpha.size() != _n_alpha )
alpha.reset ( _n_alpha , 0.0 );
double * alpha_tmp = new double [_n_alpha];
int i , k , p1 = get_nY();
// solve the system:
for ( i = 0 ; i < _n_alpha ; ++i ) {
alpha_tmp[i] = 0.0;
for ( k = 0 ; k < p1 ; ++k )
alpha_tmp[i] += M[k][i] * ( _Y[k]->get_bb_outputs()[bbo_index].value() );
}
double * alpha_tmp2 = new double [_n_alpha];
// some W values will be zero (or near zero);
// each value that is smaller than eps is ignored
for ( i = 0 ; i < _n_alpha ; ++i ) {
alpha_tmp2[i] = 0.0;
for ( k = 0 ; k < _n_alpha ; ++k )
if ( W[i] > eps )
alpha_tmp2[i] += F[k][i] * alpha_tmp[k] / W[i];
}
delete [] alpha_tmp;
for ( i = 0 ; i < _n_alpha ; ++i ) {
alpha[i] = 0.0;
for ( k = 0 ; k < _n_alpha ; ++k )
alpha[i] += V[i][k] * alpha_tmp2[k];
}
delete [] alpha_tmp2;
}
/*----------------------------------------------------------*/
/* construct Minimum Frobenius Norm (MFN) model (private) */
/*----------------------------------------------------------*/
bool NOMAD::Quad_Model::construct_MFN_model ( double eps ,
int max_mpn ,
int max_Y_size )
{
#ifdef DEBUG
_out << std::endl
<< NOMAD::open_block ( "NOMAD::Quad_Model::construct_MFN_model()" );
#endif
// check the set Y:
if ( !check_Y() )
return false;
int p1 = get_nY();
// the number of points (p+1) must be in [n+1;(n+1)(n+2)/2-1]:
if ( p1 <= _nfree || p1 >= _n_alpha ) {
#ifdef DEBUG
_out << std::endl
<< "NOMAD::Quad_Model::construct_MFN_model(): "
<< "(p+1) not in [n+1;(n+1)(n+2)/2-1]"
<< std::endl << NOMAD::close_block() << std::endl;
#endif
return false;
}
// for this procedure, the number of points is limited to 250
// (because of the SVD decomposition):
if ( p1 > 250 ) {
reduce_Y ( NOMAD::Point ( _n , 0.0 ) , 250 );
p1 = 250;
}
// construct the matrix F (4 parts):
// ---------------------------------
// [ 1 | 2 ]
// [ --+-- ]
// [ 3 | 4 ]
int i , j , k;
int np1 = _nfree + 1;
int nF = np1 + p1;
double ** F = new double *[nF];
double ** M = new double *[p1];
for ( i = 0 ; i < nF ; ++i )
F[i] = new double[nF];
// 1/4: MQ.MQ' (p+1,p+1):
{
for ( i = 0 ; i < p1 ; ++i ) {
M[i] = new double[_n_alpha];
for ( j = 0 ; j < _n_alpha ; ++j )
M[i][j] = compute_M ( i , j );
for ( j = 0 ; j <= i ; ++j ) {
F[i][j] = 0.0;
for ( k = np1 ; k < _n_alpha ; ++k )
F[i][j] += M[i][k] * M[j][k];
if ( i != j )
F[j][i] = F[i][j];
}
}
}
// 2/4: ML (p+1,n+1):
for ( i = 0 ; i < p1 ; ++i ) {
F[i][p1] = 1.0;
for ( j = p1+1 ; j < nF ; ++j )
F[i][j] = M[i][j-p1];
}
// 3/4: ML' (n+1,p+1):
for ( j = 0 ; j < p1 ; ++j ) {
F[p1][j] = 1.0;
for ( i = p1+1 ; i < nF ; ++i )
F[i][j] = M[j][i-p1];
}
// 4/4: 0 (n+1,n+1):
for ( i = p1 ; i < nF ; ++i )
for ( j = p1 ; j < nF ; ++j )
F[i][j] = 0.0;
#ifdef DEBUG
_out << std::endl << "F=";
for ( i = 0 ; i < nF ; ++i ) {
_out << "\t";
for ( j = 0 ; j < nF ; ++j )
_out << std::setw(12) << F[i][j] << " ";
_out << std::endl;
}
#endif
for ( i = 0 ; i < p1 ; ++i )
delete [] M[i];
delete [] M;
bool error = false;
// SVD decomposition of the F matrix (F = U.W.V'):
// -----------------------------------------------
// (F will be transformed in U)
double * W = new double [nF];
double ** V = new double *[nF];
for ( i = 0 ; i < nF ; ++i )
V[i] = new double[nF];
std::string error_msg;
if ( NOMAD::SVD_decomposition ( error_msg , F , W , V , nF , nF , max_mpn ) ) {
// compute condition number:
compute_cond ( W , nF , eps );
#ifdef DEBUG
_out << std::endl << "F=";
for ( i = 0 ; i < nF ; ++i ) {
_out << "\t";
for ( j = 0 ; j < nF ; ++j )
_out << std::setw(12) << F[i][j] << " ";
_out << std::endl;
}
_out << std::endl << "W=\t";
for ( i = 0 ; i < nF ; ++i )
_out << std::setw(12) << W[i] << " ";
_out << std::endl << std::endl << "cond=" << _cond << std::endl;
_out << std::endl << "V=";
for ( i = 0 ; i < nF ; ++i ) {
_out << "\t";
for ( j = 0 ; j < nF ; ++j )
_out << std::setw(12) << V[i][j] << " ";
_out << std::endl;
}
#endif
}
else {
#ifdef DEBUG
_out << std::endl << "NOMAD::Quad_Model::construct_MFN_model(): "
<< "SVD decomposition (" << error_msg << ")"
<< std::endl << std::endl;
#endif
error = true;
_cond.clear();
}
// resolution of system F.[mu alpha_L]'=[f(Y) 0]' :
// ------------------------------------------------
if ( !error ) {
int m = static_cast ( _bbot.size() );
for ( i = 0 ; i < m ; ++i )
if ( _alpha[i] )
solve_MFN_system ( F , W , V , i , *_alpha[i] , eps );
}
// free memory:
for ( i = 0 ; i < nF ; ++i ) {
delete [] F[i];
delete [] V[i];
}
delete [] F;
delete [] V;
delete [] W;
#ifdef DEBUG
_out.close_block();
#endif
return !error;
}
/*--------------------------------------------------*/
/* resolution of system F.[mu alpha_L]'=[f(Y) 0]' */
/* for MFN interpolation (private) */
/*--------------------------------------------------*/
void NOMAD::Quad_Model::solve_MFN_system ( double ** F ,
double * W ,
double ** V ,
int bbo_index ,
NOMAD::Point & alpha ,
double eps ) const
{
// resize the alpha vector:
if ( alpha.size() != _n_alpha )
alpha.reset ( _n_alpha , 0.0 );
int i , k , k1 , k2 ,
np1 = _nfree + 1 ,
nm1 = _nfree - 1 ,
p1 = get_nY() ,
nF = np1 + p1;
// step 1/2: find alpha_L and mu:
// ---------
double * alpha_tmp = new double [np1];
double * mu_tmp = new double [ p1];
double * mu = new double [ p1];
// if F is singular, some W values will be zero (or near zero);
// each value that is smaller than eps is ignored:
for ( i = 0 ; i < p1 ; ++i ) {
mu_tmp[i] = 0.0;
if ( W[i] > eps )
for ( k = 0 ; k < p1 ; ++k )
mu_tmp[i] += F[k][i] *
( _Y[k]->get_bb_outputs()[bbo_index].value() ) / W[i];
}
for ( i = p1 ; i < nF ; ++i ) {
alpha_tmp[i-p1] = 0.0;
if ( W[i] > eps )
for ( k = 0 ; k < p1 ; ++k )
alpha_tmp[i-p1] += F[k][i] *
( _Y[k]->get_bb_outputs()[bbo_index].value() ) / W[i];
}
for ( i = 0 ; i < p1 ; ++i ) {
mu[i] = 0.0;
for ( k = 0 ; k < p1 ; ++k )
mu[i] += V[i][k] * mu_tmp[k];
for ( k = p1 ; k < nF ; ++k )
mu[i] += V[i][k] * alpha_tmp[k-p1];
}
for ( i = p1 ; i < nF ; ++i ) {
alpha[i-p1] = 0.0;
for ( k = 0 ; k < p1 ; ++k )
alpha[i-p1] += V[i][k] * mu_tmp[k];
for ( k = p1 ; k < nF ; ++k )
alpha[i-p1] += V[i][k] * alpha_tmp[k-p1];
}
delete [] alpha_tmp;
delete [] mu_tmp;
#ifdef DEBUG
_out << std::endl << "output #" << bbo_index << ": mu=\t";
for ( i = 0 ; i < p1 ; ++i )
_out << std::setw(12) << mu[i] << " ";
_out << std::endl;
#endif
// step 2/2: find alpha_Q:
// ---------
for ( i = 0 ; i < _nfree ; ++i ) {
alpha[i+np1] = 0.0;
for ( k = 0 ; k < p1 ; ++k )
alpha[i+np1] += mu[k] * pow ( (*_Y[k])[i].value() , 2.0 ) / 2.0;
}
for ( k1 = 0 ; k1 < nm1 ; ++k1 )
for ( k2 = k1+1 ; k2 < _nfree ; ++k2 ) {
alpha[i+np1] = 0.0;
for ( k = 0 ; k < p1 ; ++k )
alpha[i+np1] += mu[k] * (*_Y[k])[k1].value() * (*_Y[k])[k2].value();
++i;
}
delete [] mu;
}
/*-----------------------------------------------------------*/
/* check the interpolation set Y (private) */
/*-----------------------------------------------------------*/
bool NOMAD::Quad_Model::check_Y ( void ) const
{
if ( _Y.empty() ) {
#ifdef DEBUG
_out << std::endl << "NOMAD::Quad_Model::check_Y(): set Y is empty"
<< std::endl << std::endl;
#endif
return false;
}
int nY = get_nY();
int m = static_cast ( _bbot.size() );
for ( int k = 0 ; k < nY ; ++k ) {
if ( _Y[k] == NULL ) {
#ifdef DEBUG
_out << std::endl
<< "NOMAD::Quad_Model::check_Y(): NULL pointer in the set Y"
<< std::endl << std::endl;
#endif
return false;
}
if ( _Y[k]->get_eval_status() != NOMAD::EVAL_OK ) {
#ifdef DEBUG
_out << std::endl
<< "NOMAD::Quad_Model::check_Y(): a point in Y failed to evaluate"
<< std::endl << std::endl;
#endif
return false;
}
const NOMAD::Point & bbo = _Y[k]->get_bb_outputs();
if ( !bbo.is_complete() ) {
#ifdef DEBUG
_out << std::endl
<< "NOMAD::Quad_Model::check_Y(): some bb outputs in Y are not defined"
<< std::endl << std::endl;
#endif
return false;
}
if ( bbo.size() != m ) {
#ifdef DEBUG
_out << std::endl
<< "NOMAD::Quad_Model::check_Y(): "
<< "bb outputs in Y do not have the same dimension"
<< std::endl << std::endl;
#endif
return false;
}
if ( _Y[k]->size() != _n ) {
#ifdef DEBUG
_out << std::endl
<< "NOMAD::Quad_Model::check_Y(): "
<< "points in Y do not have the same dimension"
<< std::endl << std::endl;
#endif
return false;
}
}
return true;
}
/*----------------------------------------------------*/
/* check if the model is ready for evaluations */
/*----------------------------------------------------*/
bool NOMAD::Quad_Model::check ( void ) const
{
if ( !_alpha )
return false;
int nalpha = (_nfree+1)*(_nfree+2)/2;
int i , m = static_cast ( _bbot.size() );
for ( int bbo_index = 0 ; bbo_index < m ; ++bbo_index ) {
if ( _alpha[bbo_index] ) {
if ( _alpha[bbo_index]->size() != nalpha )
return false;
for ( i = 0 ; i < nalpha ; ++i )
if ( !(*_alpha[bbo_index])[i].is_defined() )
return false;
}
}
return true;
}
/*--------------------------------------------------------------------------*/
/* evaluate a model at a given point */
/*--------------------------------------------------------------------------*/
/* . the method assumes that x.size()==_n, alpha.is_complete(), and */
/* alpha.size()==(_nfree+1)*(_nfree+2)/2 */
/* . a more efficient version is used in Quad_Model_Evaluator::eval_x() ) */
/*--------------------------------------------------------------------------*/
NOMAD::Double NOMAD::Quad_Model::eval ( const NOMAD::Point & x ,
const NOMAD::Point & alpha ) const
{
int i , j , k = 1 , nm1 = _n-1;
NOMAD::Double z = alpha[0];
for ( i = 0 ; i < _n ; ++i ) {
if ( !_fixed_vars[i] ) {
z += x[i] * ( alpha[k] + 0.5 * alpha[k+_nfree] * x[i] );
++k;
}
}
k += _nfree;
for ( i = 0 ; i < nm1 ; ++i )
if ( !_fixed_vars[i] )
for ( j = i+1 ; j < _n ; ++j )
if ( !_fixed_vars[j] )
z += alpha[k++] * x[i] * x[j];
return z;
}
/*----------------------------------------------------------------*/
/* compute model h and f values at a point */
/*----------------------------------------------------------------*/
void NOMAD::Quad_Model::eval_hf ( const NOMAD::Point & x ,
const NOMAD::Double & h_min ,
NOMAD::hnorm_type h_norm ,
NOMAD::Double & h ,
NOMAD::Double & f ) const
{
f.clear();
h = 0.0;
int m = static_cast(_bbot.size());
NOMAD::Double bboi;
for ( int i = 0 ; i < m ; ++i ) {
if ( _alpha[i] ) {
bboi = eval ( x , *_alpha[i] );
if ( bboi.is_defined() ) {
if ( _bbot[i] == NOMAD::EB || _bbot[i] == NOMAD::PEB_E ) {
if ( bboi > h_min ) {
h.clear();
return;
}
}
else if ( ( _bbot[i] == NOMAD::FILTER ||
_bbot[i] == NOMAD::PB ||
_bbot[i] == NOMAD::PEB_P ) ) {
if ( bboi > h_min ) {
switch ( h_norm ) {
case NOMAD::L1:
h += bboi;
break;
case NOMAD::L2:
h += bboi * bboi;
break;
case NOMAD::LINF:
if ( bboi > h )
h = bboi;
break;
}
}
}
else if ( _bbot[i] == NOMAD::OBJ )
f = bboi;
}
}
}
if ( h_norm == NOMAD::L2 )
h = h.sqrt();
}
/*-----------------------------------------------------*/
/* compute the maximal relative error of a model for */
/* the interpolation set (private) */
/*-----------------------------------------------------*/
NOMAD::Double NOMAD::Quad_Model::compute_max_rel_err ( void ) const
{
NOMAD::Double truth_value , model_value , rel_err , max_rel_err;
int k , nY = get_nY() , m = static_cast ( _bbot.size() );
for ( int bbo_index = 0 ; bbo_index < m ; ++bbo_index ) {
if ( _alpha[bbo_index] ) {
for ( k = 0 ; k < nY ; ++k ) {
if ( _Y[k] && _Y[k]->get_eval_status() == NOMAD::EVAL_OK ) {
truth_value = _Y[k]->get_bb_outputs()[bbo_index];
if ( truth_value.is_defined() ) {
model_value = eval ( *_Y[k] , *_alpha[bbo_index] );
if ( model_value.is_defined() ) {
if ( truth_value.abs() != 0.0 ) {
rel_err = (truth_value-model_value).abs() / truth_value.abs();
if ( !max_rel_err.is_defined() || rel_err > max_rel_err )
max_rel_err = rel_err;
}
}
}
}
}
}
}
return max_rel_err;
}
/*---------------------------------------------*/
/* compute the cumulated error of a model */
/* for the points of the interpolation set Y */
/* and for one output in particular */
/* (private) */
/*---------------------------------------------*/
void NOMAD::Quad_Model::compute_model_error ( int bbo_index ,
NOMAD::Double & error ,
NOMAD::Double & min_rel_err ,
NOMAD::Double & max_rel_err ,
NOMAD::Double & avg_rel_err ) const
{
NOMAD::Double truth_value , model_value , rel_err;
int nY = get_nY() , cnt = 0;
bool chk = true;
max_rel_err.clear();
min_rel_err.clear();
avg_rel_err = error = 0.0;
#ifdef DEBUG
std::ostringstream msg;
msg << "output #" << bbo_index;
_out.open_block ( msg.str() );
#endif
for ( int k = 0 ; k < nY ; ++k )
if ( _Y[k] && _Y[k]->get_eval_status() == NOMAD::EVAL_OK )
{
truth_value = _Y[k]->get_bb_outputs()[bbo_index];
if ( truth_value.is_defined() )
{
model_value = eval ( *_Y[k] , *_alpha[bbo_index] );
if ( model_value.is_defined() )
{
rel_err.clear();
if ( truth_value.abs() != 0.0 )
rel_err = (truth_value-model_value).abs() / truth_value.abs();
else
{
if (truth_value.abs()==model_value.abs())
rel_err=0.0;
else
rel_err=NOMAD::INF;
}
if ( !max_rel_err.is_defined() || rel_err > max_rel_err )
max_rel_err = rel_err;
if ( !min_rel_err.is_defined() || rel_err < min_rel_err )
min_rel_err = rel_err;
avg_rel_err += rel_err;
++cnt;
#ifdef DEBUG
_out << "Y[" << k << "]= ( ";
_Y[k]->NOMAD::Point::display ( _out );
_out << " )" << " f=" << truth_value
<< " m=" << model_value << " error^2="
<< ( model_value - truth_value ).pow2()
<< " rel_err=" << rel_err
<< std::endl;
#endif
error += ( model_value - truth_value ).pow2();
}
else
{
chk = false;
break;
}
}
else
{
chk = false;
break;
}
}
#ifdef DEBUG
_out.close_block();
#endif
if ( chk)
{ // Case where chk is true (at least one model_value and the corresponding thruth value were defined => cnt != 0)
error = error.sqrt();
avg_rel_err = avg_rel_err / cnt;
}
else
{
error.clear();
min_rel_err.clear();
max_rel_err.clear();
avg_rel_err.clear();
}
}
/*-----------------------------------------------------------*/
/* display the model coefficients */
/*-----------------------------------------------------------*/
void NOMAD::Quad_Model::display_model_coeffs ( const NOMAD::Display & out ) const
{
if ( _error_flag ) {
out << "model coefficients: could not be constructed" << std::endl;
return;
}
int m = static_cast ( _bbot.size() );
out << NOMAD::open_block ( "model coefficients" );
for ( int i = 0 ; i < m ; ++i ) {
out << "output #";
out.display_int_w ( i , m );
out << ": ";
if ( _alpha[i] ) {
out<< "[ ";
_alpha[i]->display ( out , " " , 6 );
out << " ]";
}
else
out << "NULL";
out << std::endl;
}
out.close_block();
}
/*-----------------------------------------------------------*/
/* display the interpolation set Y */
/*-----------------------------------------------------------*/
void NOMAD::Quad_Model::display_Y ( const NOMAD::Display & out ,
const std::string & title ) const
{
out << NOMAD::open_block ( title );
int nY = get_nY();
for ( int k = 0 ; k < nY ; ++k ) {
out << "#";
out.display_int_w ( k , nY );
out << ": ";
if ( _Y[k] ) {
out << "( ";
_Y[k]->NOMAD::Point::display ( out , " " , 12 );
out << " ) bbo=[ ";
_Y[k]->get_bb_outputs().display ( out , " " , 12 );
out << " ]";
}
else
out << "NULL";
out << std::endl;
}
out.close_block();
}
/*-------------------------------------------------------*/
/* display cumulated error on the interpolation points */
/*-------------------------------------------------------*/
void NOMAD::Quad_Model::display_Y_error ( const NOMAD::Display & out ) const
{
if ( _error_flag )
{
out << "model error on the interpolation set: cannot be computed"
<< std::endl;
return;
}
int i ;
int index = -1;
int m = static_cast ( _bbot.size() );
for ( i = 0 ; i < m ; ++i )
if ( _alpha[i] )
{
if ( index >= 0 )
{
index = -1;
break;
}
else
index = i;
}
NOMAD::Double error , min_rel_err , max_rel_err , avg_rel_err;
// only one output:
if ( index >= 0 )
{
compute_model_error ( index , error , min_rel_err , max_rel_err , avg_rel_err );
out << "model errors on the interpolation set: error="
<< error << " min_rel_err=" << min_rel_err
<< " max_rel_err=" << max_rel_err << " avg_rel_err=" << avg_rel_err
<< std::endl;
}
// several outputs:
else {
out.open_block ( "model error on the interpolation set" );
NOMAD::Double error_i , min_rel_err_i , max_rel_err_i , avg_rel_err_i;
error = avg_rel_err = 0.0;
min_rel_err.clear();
max_rel_err.clear();
int cnt = 0;
for ( i = 0 ; i < m ; ++i )
if ( _alpha[i] )
{
++cnt;
compute_model_error ( i ,
error_i ,
min_rel_err_i ,
max_rel_err_i ,
avg_rel_err_i );
if (error_i.is_defined())
error += error_i;
if (avg_rel_err_i.is_defined())
avg_rel_err += avg_rel_err_i;
if ( !min_rel_err.is_defined() || min_rel_err_i < min_rel_err )
min_rel_err = min_rel_err_i;
if ( !max_rel_err.is_defined() || max_rel_err_i > max_rel_err )
max_rel_err = max_rel_err_i;
out << "output #" << i << ": error=" << error_i
<< " min_rel_err=" << min_rel_err_i << " max_rel_err="
<< max_rel_err_i << " avg_rel_err=" << avg_rel_err_i << std::endl;
}
out << std::endl << "global: error=" << error
<< " min_rel_err=" << min_rel_err
<< " max_rel_err=" << max_rel_err
<< " avg_rel_err=" << avg_rel_err / cnt
<< std::endl << NOMAD::close_block();
}
}
/*-----------------------------------------------*/
/* display Lagrange polynomials (private) */
/*-----------------------------------------------*/
void NOMAD::Quad_Model::display_lagrange_polynomials
( const std::vector & l ,
const std::vector & Y ) const
{
int i , j , nY = static_cast ( Y.size() );
// display Lagrange polynomials:
_out << std::endl << NOMAD::open_block ( "Lagrange polynomials" );
for ( i = 0 ; i < _n_alpha ; ++i ) {
_out << "l[";
_out.display_int_w ( i , _n_alpha );
_out << "] = [ ";
l[i]->NOMAD::Point::display ( _out , " " , 14 , -1 );
_out << "]" << std::endl;
}
_out.close_block();
// display current set Y:
_out << std::endl << NOMAD::open_block ( "current set Y" );
for ( i = 0 ; i < nY ; ++i ) {
_out << "Y[";
_out.display_int_w ( i , nY );
_out << "] = ";
if ( Y[i] ) {
_out << "( ";
Y[i]->NOMAD::Point::display ( _out , " " , 6 , -1 );
_out << " )";
}
else
_out << "NULL";
_out << std::endl;
}
_out.close_block();
// display l(Y): should be the identity matrix:
NOMAD::Double tmp , err = 0.0;
_out << std::endl << NOMAD::open_block ( "l(Y)" );
for ( i = 0 ; i < _n_alpha ; ++i ) {
_out << "l[";
_out.display_int_w ( i , _n_alpha );
_out << "]: ";
for ( j = 0 ; j < _n_alpha ; ++j ) {
tmp.clear();
if ( j < nY && Y[j] ) {
tmp = eval ( *Y[j] , *l[i] );
err += (i==j) ? (tmp-1.0).abs() : tmp.abs();
}
tmp.display ( _out , "%6.3f" );
_out << " ";
}
_out << std::endl;
}
_out << std::endl << "error (with identity) = "
<< err << std::endl << NOMAD::close_block() << std::endl;
}