/*-------------------------------------------------------------------------------------*/ /* 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 utils.cpp \brief Utility functions \author Sebastien Le Digabel \date 2010-03-23 \see utils.hpp */ #include "utils.hpp" /*---------------------------------------------------------------*/ /* construct the first n prime numbers */ /*---------------------------------------------------------------*/ void NOMAD::construct_primes ( int n , int * primes ) { bool is_prime; double kk; int i = 0 , k = 2 , j; while ( true ) { is_prime = true; kk = sqrt ( static_cast(k) ); for ( j = 2 ; j <= kk ; ++j ) if ( k%j==0 ) { is_prime = false; break; } if ( is_prime ) { primes[i++] = k; if ( i==n ) break; } ++k; } } /*--------------------------------------------*/ /* decompose a string (sentence) into words */ /*--------------------------------------------*/ void NOMAD::get_words ( const std::string & sentence , std::list & words ) { std::string s; std::istringstream in ( sentence ); while ( true ) { in >> s; if ( in.fail() ) break; words.push_back ( s ); } } /*---------------------------------------------------------------*/ /* get the pid (process id): used as random seed or unique tag */ /*---------------------------------------------------------------*/ int NOMAD::get_pid ( void ) { #ifdef _MSC_VER return _getpid(); #else return getpid(); #endif } /*---------------------------------------*/ /* called at the beginning of NOMAD */ /*---------------------------------------*/ void NOMAD::begin ( int argc , char ** argv ) { #ifdef USE_MPI MPI_Init ( &argc , &argv ); #endif } /*---------------------------------------*/ /* called at the end of NOMAD */ /*---------------------------------------*/ void NOMAD::end ( void ) { #ifdef USE_MPI MPI_Finalize(); #endif } /*-----------------------------------------------------------------*/ /* check if a file exists and is executable */ /*-----------------------------------------------------------------*/ bool NOMAD::check_exe_file ( const std::string & file_name ) { #ifdef WINDOWS // don't check on Windows: return true; #else return ( access ( file_name.c_str() , X_OK ) == 0 ); #endif } /*-----------------------------------------------------------------*/ /* check if a file exists and is readable */ /*-----------------------------------------------------------------*/ bool NOMAD::check_read_file ( const std::string & file_name ) { #ifdef _MSC_VER return ( _access ( file_name.c_str() , 4 ) == 0 ); #else return ( access ( file_name.c_str() , R_OK ) == 0 ); #endif } /*-----------------------------------------------------------------*/ /* NOMAD::itos */ /*-----------------------------------------------------------------*/ std::string NOMAD::itos ( int i ) { std::ostringstream oss; oss << i; return oss.str(); } /*-----------------------------------------------------------------*/ /* NOMAD::toupper - 1/2 */ /*-----------------------------------------------------------------*/ void NOMAD::toupper ( std::string & s ) { size_t ns = s.size(); for ( size_t i = 0 ; i < ns ; ++i ) s[i] = std::toupper(s[i]); } /*-----------------------------------------------------------------*/ /* NOMAD::toupper - 2/2 */ /*-----------------------------------------------------------------*/ void NOMAD::toupper ( std::list & ls ) { std::list::iterator it; std::list::const_iterator end = ls.end(); for ( it = ls.begin() ; it != end ; ++it ) NOMAD::toupper ( *it ); } /*-----------------------------------------------------------------*/ /* NOMAD::atoi */ /*-----------------------------------------------------------------*/ bool NOMAD::atoi ( const std::string & s , int & i ) { i = -1; if ( s.empty() ) return false; size_t n = s.size(); if ( s[0] == '-' ) { if ( n > 1 && s[1] == '-' ) return false; std::string ss = s; ss.erase(ss.begin()); if ( NOMAD::atoi ( ss , i ) ) { i = -i; return true; } return false; } for ( size_t k = 0 ; k < n ; ++k ) if ( !isdigit(s[k]) ) return false; i = std::atoi(s.c_str()); return true; } bool NOMAD::atoi ( char c , int & i ) { std::string s = "-"; s[0] = c; return NOMAD::atoi(s,i); } /*-------------------------------------------------------------------*/ /* if a NOMAD::bb_output_type variable corresponds to a constraint */ /*-------------------------------------------------------------------*/ bool NOMAD::bbot_is_constraint ( NOMAD::bb_output_type bbot ) { return ( bbot == NOMAD::EB || bbot == NOMAD::PB || bbot == NOMAD::PEB_P || bbot == NOMAD::PEB_E || bbot == NOMAD::FILTER ); } /*-----------------------------------------------------------------------*/ /* if a NOMAD::direction_type variable corresponds to a MADS direction */ /*-----------------------------------------------------------------------*/ bool NOMAD::dir_is_mads ( NOMAD::direction_type dt ) { return (dt == NOMAD::ORTHO_1 || dt == NOMAD::ORTHO_2 || dt == NOMAD::ORTHO_NP1_QUAD || dt == NOMAD::ORTHO_NP1_NEG || dt == NOMAD::DYN_ADDED || dt == NOMAD::ORTHO_2N || dt == NOMAD::LT_1 || dt == NOMAD::LT_2 || dt == NOMAD::LT_2N || dt == NOMAD::LT_NP1 ); } /*----------------------------------------------------------------------*/ /* if a NOMAD::direction_type variable corresponds to a GPS direction */ /*----------------------------------------------------------------------*/ bool NOMAD::dir_is_gps ( NOMAD::direction_type dt ) { return ( dt == NOMAD::GPS_BINARY || dt == NOMAD::GPS_2N_STATIC || dt == NOMAD::GPS_2N_RAND || dt == NOMAD::GPS_NP1_STATIC_UNIFORM || dt == NOMAD::GPS_NP1_STATIC || dt == NOMAD::GPS_NP1_RAND_UNIFORM || dt == NOMAD::GPS_NP1_RAND ); } /*--------------------------------------------------------------------------*/ /* if a NOMAD::direction_type variable corresponds to a LT-MADS direction */ /*--------------------------------------------------------------------------*/ bool NOMAD::dir_is_ltmads ( NOMAD::direction_type dt ) { return ( dt == NOMAD::LT_1 || dt == NOMAD::LT_2 || dt == NOMAD::LT_2N || dt == NOMAD::LT_NP1 ); } /*-------------------------------------------------------------------------*/ /* if a NOMAD::direction_type variable corresponds to a random direction */ /*-------------------------------------------------------------------------*/ bool NOMAD::dir_is_random ( NOMAD::direction_type dt ) { return ( dt == NOMAD::GPS_NP1_RAND || dt == NOMAD::GPS_NP1_RAND_UNIFORM || dt == NOMAD::GPS_2N_RAND || dt == NOMAD::LT_1 || dt == NOMAD::LT_2 || dt == NOMAD::LT_2N || dt == NOMAD::LT_NP1 ); } /*-----------------------------------------------------------------------------*/ /* if a NOMAD::direction_type variable corresponds to a Ortho-MADS direction */ /*-----------------------------------------------------------------------------*/ bool NOMAD::dir_is_orthomads ( NOMAD::direction_type dt ) { return (dt == NOMAD::ORTHO_1 || dt == NOMAD::ORTHO_2 || dt == NOMAD::ORTHO_NP1_QUAD || dt == NOMAD::ORTHO_NP1_NEG || dt == NOMAD::ORTHO_2N ); } /*---------------------------------------------------------------------*/ /* check if a set of directions includes one Ortho-MADS direction */ /* (true if at least one direction in the set is of type Ortho-MADS) */ /*---------------------------------------------------------------------*/ bool NOMAD::dirs_have_orthomads ( const std::set & dir_types ) { std::set::const_iterator it , end = dir_types.end(); for ( it = dir_types.begin() ; it != end ; ++it ) if ( NOMAD::dir_is_orthomads (*it) ) return true; return false; } /*---------------------------------------------------------------------*/ /* check if a set of directions includes one Ortho-MADS N+1 direction */ /* (true if at least one direction in the set is of type Ortho-MADS) */ /*---------------------------------------------------------------------*/ bool NOMAD::dirs_have_orthomads_np1( const std::set & dir_types ) { std::set::const_iterator it , end = dir_types.end(); for ( it = dir_types.begin() ; it != end ; ++it ) if ( (*it)==NOMAD::ORTHO_NP1_QUAD || (*it)==NOMAD::ORTHO_NP1_NEG) return true; return false; } /*---------------------------------------------------*/ /* returns true if one of the string of ls is in s */ /*---------------------------------------------------*/ bool NOMAD::string_find ( const std::string & s , const std::list & ls ) { std::list::const_iterator it , end = ls.end(); for ( it = ls.begin() ; it != end ; ++it ) if ( NOMAD::string_find ( s , *it ) ) return true; return false; } /*---------------------------------------------------*/ /* search a string into another string */ /*---------------------------------------------------*/ bool NOMAD::string_find ( const std::string & s1 , const std::string & s2 ) { return ( s1.find(s2) < s1.size() ); } /*--------------------------------------------------------------------------*/ /* returns true if one of the string in ls is an element of s */ /*--------------------------------------------------------------------------*/ bool NOMAD::string_match ( const std::string & s , const std::list & ls ) { std::list::const_iterator it , end = ls.end(); for ( it = ls.begin() ; it != end ; ++it ) if ( s.compare(*it) == 0 ) return true; return false; } /*-----------------------------------------------------------------*/ /* interpret a list of strings as a direction type */ /*-----------------------------------------------------------------*/ bool NOMAD::strings_to_direction_type ( const std::list & ls , NOMAD::direction_type & dt ) { dt = NOMAD::UNDEFINED_DIRECTION; if ( ls.empty() || ls.size() > 4 ) return false; std::list::const_iterator it = ls.begin() , end = ls.end(); std::string s = *it; NOMAD::toupper ( s ); // no direction: if ( s == "NONE" ) { dt = NOMAD::NO_DIRECTION; return true; } // Ortho-MADS with 1, 2, n+1 (plus QUAD or NEG), or 2n directions: if ( s == "ORTHO" ) { ++it; if ( it == end ) { dt = NOMAD::ORTHO_NP1_QUAD; // Default for ORTHO return true; } if ( *it == "1" ) { dt = NOMAD::ORTHO_1; return true; } if ( *it == "2" ) { dt = NOMAD::ORTHO_2; return true; } s = *it; NOMAD::toupper ( s ); if ( s == "2N" ) { dt = NOMAD::ORTHO_2N; return true; } if ( s == "N+1" ) { ++it; if (it==end) { dt = NOMAD::ORTHO_NP1_QUAD; // Default for ORTHO N+1 return true; } s = *it; NOMAD::toupper ( s ); if ( s=="QUAD" ) { dt= NOMAD::ORTHO_NP1_QUAD; return true; } if ( s=="NEG" ) { dt=NOMAD::ORTHO_NP1_NEG; return true; } } return false; } // LT-MADS with 1, 2 or 2n directions: if ( s == "LT" ) { ++it; if ( it == end ) { dt = NOMAD::LT_2N; return true; } if ( *it == "1" ) { dt = NOMAD::LT_1; return true; } if ( *it == "2" ) { dt = NOMAD::LT_2; return true; } s = *it; NOMAD::toupper ( s ); if ( s == "N+1" ) { dt = NOMAD::LT_NP1; return true; } if ( s == "2N" ) { dt = NOMAD::LT_2N; return true; } return false; } // GPS: if ( s == "GPS" ) { ++it; if ( it == end ) { dt = NOMAD::GPS_2N_STATIC; return true; } s = *it; NOMAD::toupper ( s ); // GPS for binary variables: if ( s == "BINARY" || s == "BIN" ) { dt = NOMAD::GPS_BINARY; return true; } // GPS, n+1 directions: if ( s == "N+1" ) { ++it; if ( it == end ) { dt = NOMAD::GPS_NP1_STATIC; return true; } s = *it; NOMAD::toupper ( s ); // GPS, n+1, static: if ( s == "STATIC" ) { ++it; if ( it == end ) { dt = NOMAD::GPS_NP1_STATIC; return true; } s = *it; NOMAD::toupper ( s ); if ( s == "UNIFORM" ) { dt = NOMAD::GPS_NP1_STATIC_UNIFORM; return true; } return false; } // GPS, n+1, random: if ( s == "RAND" || s == "RANDOM" ) { ++it; if ( it == end ) { dt = NOMAD::GPS_NP1_RAND; return true; } s = *it; NOMAD::toupper ( s ); if ( s == "UNIFORM" ) { dt = NOMAD::GPS_NP1_RAND_UNIFORM; return true; } return false; } return false; } // 2n directions: if ( s == "2N" ) { ++it; if ( it == end ) { dt = NOMAD::GPS_2N_STATIC; return true; } s = *it; NOMAD::toupper ( s ); if ( s == "STATIC" ) { dt = NOMAD::GPS_2N_STATIC; return true; } if ( s == "RAND" || s == "RANDOM" ) { dt = NOMAD::GPS_2N_RAND; return true; } return false; } return false; } return false; } /*---------------------------------------*/ /* convert a string into a hnorm_type */ /*---------------------------------------*/ bool NOMAD::string_to_hnorm_type ( const std::string & s , NOMAD::hnorm_type & hn ) { std::string ss = s; NOMAD::toupper(ss); if ( ss == "L1" ) { hn = NOMAD::L1; return true; } if ( ss == "L2" ) { hn = NOMAD::L2; return true; } if ( ss == "LINF" ) { hn = NOMAD::LINF; return true; } return false; } /*-----------------------------------------*/ /* convert a string into a TGP_mode_type */ /*-----------------------------------------*/ bool NOMAD::string_to_TGP_mode_type ( const std::string & s , NOMAD::TGP_mode_type & m ) { std::string ss = s; NOMAD::toupper(ss); if ( ss == "FAST" ) { m = NOMAD::TGP_FAST; return true; } if ( ss == "PRECISE" ) { m = NOMAD::TGP_PRECISE; return true; } if ( ss == "USER" ) { m = NOMAD::TGP_USER; return true; } return false; } /*--------------------------------------------------*/ /* convert a string into a multi_formulation_type */ /*--------------------------------------------------*/ bool NOMAD::string_to_multi_formulation_type ( const std::string & s , NOMAD::multi_formulation_type & mft ) { std::string ss = s; NOMAD::toupper(ss); if ( ss == "NORMALIZED" ) { mft = NOMAD::NORMALIZED; return true; } if ( ss == "PRODUCT" ) { mft = NOMAD::PRODUCT; return true; } if ( ss == "DIST_L1" ) { mft = NOMAD::DIST_L1; return true; } if ( ss == "DIST_L2" ) { mft = NOMAD::DIST_L2; return true; } if ( ss == "DIST_LINF" ) { mft = NOMAD::DIST_LINF; return true; } return false; } /*-------------------------------------------*/ /* convert a string into a bb_output_type */ /*-------------------------------------------*/ bool NOMAD::string_to_bb_output_type ( const std::string & s , NOMAD::bb_output_type & bbot ) { std::string ss = s; NOMAD::toupper(ss); if ( ss == "OBJ" ) { bbot = NOMAD::OBJ; return true; } if ( ss == "EB" ) { bbot = NOMAD::EB; return true; } if ( ss == "PB" || ss == "CSTR" ) { bbot = NOMAD::PB; return true; } if ( ss == "PEB" ) { bbot = NOMAD::PEB_P; return true; } if ( ss == "F" ) { bbot = NOMAD::FILTER; return true; } if ( ss == "STAT_AVG" ) { bbot = NOMAD::STAT_AVG; return true; } if ( ss == "STAT_SUM" ) { bbot = NOMAD::STAT_SUM; return true; } if ( ss == "CNT_EVAL" ) { bbot = NOMAD::CNT_EVAL; return true; } if ( ss == "NOTHING" || ss == "-" ) { bbot = NOMAD::UNDEFINED_BBO; return true; } return false; } /*-----------------------------------------------------------------*/ /* convert a string into a bb_input_type */ /*-----------------------------------------------------------------*/ bool NOMAD::string_to_bb_input_type ( const std::string & s , NOMAD::bb_input_type & bbit ) { std::string ss = s; NOMAD::toupper ( ss ); if ( ss=="R" || ss=="REAL" ) { bbit = NOMAD::CONTINUOUS; return true; } if ( ss=="C" || ss=="CAT" ) { bbit = NOMAD::CATEGORICAL; return true; } if ( ss=="B" || ss=="BIN" ) { bbit = NOMAD::BINARY; return true; } if ( ss=="I" || ss=="INT" ) { bbit = NOMAD::INTEGER; return true; } return false; } /*-----------------------------------------------------------------*/ /* convert a string into a model_type */ /*-----------------------------------------------------------------*/ bool NOMAD::string_to_model_type ( const std::string & s , NOMAD::model_type & mt ) { std::string ss = s; NOMAD::toupper ( ss ); if ( ss=="TGP" || ss=="TGP_MODEL" ) { mt = NOMAD::TGP_MODEL; return true; } if ( ss=="QUADRATIC" || ss=="QUADRATIC_MODEL" ) { mt = NOMAD::QUADRATIC_MODEL; return true; } mt = NOMAD::NO_MODEL; return false; } /*----------------------------------------------------------------------*/ /* convert a string in {"YES","NO","Y","N"} to a bool */ /* value of return: -1: error */ /* 0: bool=false */ /* 1: bool=true */ /*----------------------------------------------------------------------*/ int NOMAD::string_to_bool ( const std::string & ss ) { std::string s = ss; NOMAD::toupper ( s ); if ( s=="Y" || s=="YES" || s=="1" || s=="TRUE" ) return 1; if ( s=="N" || s=="NO" || s=="0" || s=="FALSE" ) return 0; return -1; } /*---------------------------------------------------*/ /* convert a string 'i-j' to the integers i and j */ /*---------------------------------------------------*/ bool NOMAD::string_to_index_range ( const std::string & s , int & i , int & j , int * n , bool check_order ) { if ( s.empty() ) return false; if ( s == "*" ) { if ( !n ) return false; i = 0; j = *n-1; return true; } if ( s[0] == '-' ) { size_t ns = s.size(); if ( ns > 1 && s[1] == '-' ) return false; std::string ss = s; ss.erase ( ss.begin() ); if ( NOMAD::string_to_index_range ( ss , i , j , n , false ) ) { i = -i; return true; } return false; } std::istringstream in (s); std::string s1; getline ( in , s1 , '-' ); if (in.fail()) return false; size_t k , n1 = s1.size(); if ( n1 >= s.size() - 1 ) { for ( k = 0 ; k < n1 ; ++k ) if (!isdigit(s1[k])) return false; if ( !NOMAD::atoi ( s1 , i ) ) return false; if ( n1 == s.size() ) { j = i; return true; } if (n) { j = *n-1; return true; } return false; } std::string s2; getline (in, s2); if (in.fail()) return false; size_t n2 = s2.size(); for ( k = 0 ; k < n2 ; ++k ) if ( !isdigit(s2[k]) ) return false; if ( !NOMAD::atoi ( s1, i ) || !NOMAD::atoi ( s2 , j ) ) return false; return !check_order || i <= j; } int NOMAD::get_rank(double ** M, int m, int n) { double * W = new double [n]; double ** V = new double *[n]; for (int i = 0 ; i < n ; ++i ) { V[i]=new double [n]; } std::string error_msg; NOMAD::SVD_decomposition ( error_msg , M , W , V , m , n ); for (int i=0;iNOMAD::SVD_EPS) rank++; } delete [] W; return rank; } /*--------------------------------------------------------------*/ /* SVD decomposition */ /* inspired and recoded from an old numerical recipes version */ /*--------------------------------------------------------------*/ /* */ /* M = U . W . V' */ /* */ /* M ( m x n ) */ /* U ( m x n ) */ /* W ( n x n ) */ /* V ( n x n ) */ /* */ /* U.U' = U'.U = I if m = n */ /* U'.U = I if m > m */ /* */ /* V.V' = V'.V = I */ /* */ /* W diagonal */ /* */ /* M is given as first argument and becomes U */ /* W is given as a size-n vector */ /* V is given, not V' */ /* */ /*--------------------------------------------------------------*/ bool NOMAD::SVD_decomposition ( std::string & error_msg , double ** M , double * W , double ** V , int m , int n , int max_mpn ) // default=1500 { error_msg.clear(); if ( max_mpn > 0 && m+n > max_mpn ) { error_msg = "SVD_decomposition() error: m+n > " + NOMAD::itos ( max_mpn ); return false; } double * rv1 = new double[n]; double scale = 0.0; double g = 0.0; double norm = 0.0; int nm1 = n - 1; bool flag; int i , j , k , l , its , jj , nm = 0; double s , f , h , tmp , c , x , y , z , absf , absg , absh; const int NITER = 30; // Initialization W and V for (i=0; i < n; ++i) { W[i]=0.0; for (j=0; j < n ; ++j) V[i][j]=0.0; } // Householder reduction to bidiagonal form: for ( i = 0 ; i < n ; ++i ) { l = i + 1; rv1[i] = scale * g; g = s = scale = 0.0; if ( i < m ) { for ( k = i ; k < m ; ++k ) scale += fabs ( M[k][i] ); if ( scale ) { for ( k = i ; k < m ; ++k ) { M[k][i] /= scale; s += M[k][i] * M[k][i]; } f = M[i][i]; g = ( f >= 0.0 ) ? -fabs(sqrt(s)) : fabs(sqrt(s)); h = f * g - s; M[i][i] = f - g; for ( j = l ; j < n ; ++j ) { for ( s = 0.0 , k = i ; k < m ; ++k ) s += M[k][i] * M[k][j]; f = s / h; for ( k = i ; k < m ; ++k ) M[k][j] += f * M[k][i]; } for ( k = i ; k < m ; ++k ) M[k][i] *= scale; } } W[i] = scale * g; g = s = scale = 0.0; if ( i < m && i != nm1 ) { for ( k = l ; k < n ; ++k ) scale += fabs ( M[i][k] ); if ( scale ) { for ( k = l ; k < n ; ++k ) { M[i][k] /= scale; s += M[i][k] * M[i][k]; } f = M[i][l]; g = ( f >= 0.0 ) ? -fabs(sqrt(s)) : fabs(sqrt(s)); h = f * g - s; M[i][l] = f - g; for ( k = l ; k < n ; ++k ) rv1[k] = M[i][k] / h; for ( j = l ; j < m ; ++j ) { for ( s=0.0,k=l ; k < n ; ++k ) s += M[j][k] * M[i][k]; for ( k=l ; k < n ; ++k ) M[j][k] += s * rv1[k]; } for ( k = l ; k < n ; ++k ) M[i][k] *= scale; } } tmp = fabs ( W[i] ) + fabs ( rv1[i] ); norm = ( norm > tmp ) ? norm : tmp; } // accumulation of right-hand transformations: for ( i = nm1 ; i >= 0 ; --i ) { if ( i < nm1 ) { if ( g ) { for ( j = l ; j < n ; ++j ) V[j][i] = ( M[i][j] / M[i][l] ) / g; for ( j = l ; j < n ; ++j ) { for ( s = 0.0 , k = l ; k < n ; ++k ) s += M[i][k] * V[k][j]; for ( k = l ; k < n ; ++k ) V[k][j] += s * V[k][i]; } } for ( j = l ; j < n ; ++j ) V[i][j] = V[j][i] = 0.0; } V[i][i] = 1.0; g = rv1[i]; l = i; } // accumulation of left-hand transformations: for ( i = ( ( m < n ) ? m : n ) - 1 ; i >= 0 ; --i ) { l = i + 1; g = W[i]; for ( j = l ; j < n ; ++j ) M[i][j] = 0.0; if ( g ) { g = 1.0 / g; for ( j = l ; j < n ; ++j ) { for ( s = 0.0 , k = l ; k < m ; ++k ) s += M[k][i] * M[k][j]; f = ( s / M[i][i] ) * g; for ( k = i ; k < m ; ++k ) M[k][j] += f * M[k][i]; } for ( j = i ; j < m ; ++j ) M[j][i] *= g; } else for ( j = i ; j < m ; ++j ) M[j][i] = 0.0; ++M[i][i]; } // diagonalization of the bidiagonal form: for ( k = nm1 ; k >= 0 ; --k ) { for ( its = 1 ; its <= NITER ; its++ ) { flag = true; for ( l = k ; l >= 0 ; l-- ) { nm = l - 1; if ( nm < 0 || fabs ( rv1[l]) + norm == norm ) { flag = false; break; } if ( fabs ( W[nm] ) + norm == norm ) break; } if ( flag ) { c = 0.0; s = 1.0; for ( i = l ; i <= k ; i++ ) { f = s * rv1[i]; rv1[i] = c * rv1[i]; if ( fabs(f) + norm == norm ) break; g = W[i]; absf = fabs(f); absg = fabs(g); h = ( absf > absg ) ? absf * sqrt ( 1.0 + pow ( absg/absf , 2.0 ) ) : ( ( absg==0 ) ? 0.0 : absg * sqrt ( 1.0 + pow ( absf/absg , 2.0 ) ) ); W[i] = h; h = 1.0 / h; c = g * h; s = -f * h; for ( j = 0 ; j < m ; ++j ) { y = M[j][nm]; z = M[j][ i]; M[j][nm] = y * c + z * s; M[j][ i] = z * c - y * s; } } } z = W[k]; if ( l == k) { if ( z < 0.0 ) { W[k] = -z; for ( j = 0 ; j < n ; j++ ) V[j][k] = -V[j][k]; } break; // this 'break' is always active if k==0 } if ( its == NITER ) { error_msg = "SVD_decomposition() error: no convergence in " + NOMAD::itos ( NITER ) + " iterations"; delete [] rv1; return false; } x = W[l]; nm = k - 1; y = W[nm]; g = rv1[nm]; h = rv1[k]; f = ( (y-z) * (y+z) + (g-h) * (g+h) ) / ( 2.0 * h * y ); absf = fabs(f); g = ( absf > 1.0 ) ? absf * sqrt ( 1.0 + pow ( 1.0/absf , 2.0 ) ) : sqrt ( 1.0 + pow ( absf , 2.0 ) ); f = ( (x-z) * (x+z) + h * ( ( y / ( f + ( (f >= 0)? fabs(g) : -fabs(g) ) ) ) - h ) ) / x; c = s = 1.0; for ( j = l ; j <= nm ; ++j ) { i = j + 1; g = rv1[i]; y = W[i]; h = s * g; g = c * g; absf = fabs(f); absh = fabs(h); z = ( absf > absh ) ? absf * sqrt ( 1.0 + pow ( absh/absf , 2.0 ) ) : ( ( absh==0 ) ? 0.0 : absh * sqrt ( 1.0 + pow ( absf/absh , 2.0 ) ) ); rv1[j] = z; c = f / z; s = h / z; f = x * c + g * s; g = g * c - x * s; h = y * s; y *= c; for ( jj = 0 ; jj < n ; ++jj ) { x = V[jj][j]; z = V[jj][i]; V[jj][j] = x * c + z * s; V[jj][i] = z * c - x * s; } absf = fabs(f); absh = fabs(h); z = ( absf > absh ) ? absf * sqrt ( 1.0 + pow ( absh/absf , 2.0 ) ) : ( ( absh==0 ) ? 0.0 : absh * sqrt ( 1.0 + pow ( absf/absh , 2.0 ) ) ); W[j] = z; if ( z ) { z = 1.0 / z; c = f * z; s = h * z; } f = c * g + s * y; x = c * y - s * g; for ( jj = 0 ; jj < m ; ++jj ) { y = M[jj][j]; z = M[jj][i]; M[jj][j] = y * c + z * s; M[jj][i] = z * c - y * s; } } rv1[l] = 0.0; rv1[k] = f; W [k] = x; } } delete [] rv1; return true; }