EvolvingObjects
|
00001 /* 00002 * C++ification of Nikolaus Hansen's original C-source code for the 00003 * CMA-ES. These are the eigenvector calculations 00004 * 00005 * C++-ificiation performed by Maarten Keijzer (C) 2005. Licensed under 00006 * the LGPL. Original copyright of Nikolaus Hansen can be found below 00007 * 00008 * This algorithm is held almost completely intact. Some other datatypes are used, 00009 * but hardly any code has changed 00010 * 00011 */ 00012 00013 /* --------------------------------------------------------- */ 00014 /* --------------------------------------------------------- */ 00015 /* --- File: cmaes.c -------- Author: Nikolaus Hansen --- */ 00016 /* --------------------------------------------------------- */ 00017 /* 00018 * CMA-ES for non-linear function minimization. 00019 * 00020 * Copyright (C) 1996, 2003 Nikolaus Hansen. 00021 * e-mail: hansen@bionik.tu-berlin.de 00022 * 00023 * This library is free software; you can redistribute it and/or 00024 * modify it under the terms of the GNU Lesser General Public 00025 * License as published by the Free Software Foundation; either 00026 * version 2.1 of the License, or (at your option) any later 00027 * version (see http://www.gnu.org/copyleft/lesser.html). 00028 * 00029 * This library is distributed in the hope that it will be useful, 00030 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00031 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00032 * Lesser General Public License for more details. 00033 * 00034 * */ 00035 /* --- Changes : --- 00036 * 03/03/21: argument const double *rgFunVal of 00037 * cmaes_ReestimateDistribution() was treated incorrectly. 00038 * 03/03/29: restart via cmaes_resume_distribution() implemented. 00039 * 03/03/30: Always max std dev / largest axis is printed first. 00040 * 03/08/30: Damping is adjusted for large mueff. 00041 * 03/10/30: Damping is adjusted for large mueff always. 00042 * 04/04/22: Cumulation time and damping for step size adjusted. 00043 * No iniphase but conditional update of pc. 00044 * Version 2.23. 00045 * */ 00046 #include "eig.h" 00047 00048 using namespace std; 00049 00050 /* ========================================================= */ 00051 /* 00052 Householder Transformation einer symmetrischen Matrix 00053 auf tridiagonale Form. 00054 -> n : Dimension 00055 -> ma : symmetrische nxn-Matrix 00056 <- ma : Transformationsmatrix (ist orthogonal): 00057 Tridiag.-Matrix == <-ma * ->ma * (<-ma)^t 00058 <- diag : Diagonale der resultierenden Tridiagonalmatrix 00059 <- neben[0..n-1] : Nebendiagonale (==1..n-1) der res. Tridiagonalmatrix 00060 00061 */ 00062 static void 00063 Householder( int N, square_matrix& ma, valarray<double>& diag, double* neben) 00064 { 00065 double epsilon; 00066 int i, j, k; 00067 double h, sum, tmp, tmp2; 00068 00069 for (i = N-1; i > 0; --i) 00070 { 00071 h = 0.0; 00072 if (i == 1) 00073 neben[i] = ma[i][i-1]; 00074 else 00075 { 00076 for (k = i-1, epsilon = 0.0; k >= 0; --k) 00077 epsilon += fabs(ma[i][k]); 00078 00079 if (epsilon == 0.0) 00080 neben[i] = ma[i][i-1]; 00081 else 00082 { 00083 for(k = i-1, sum = 0.0; k >= 0; --k) 00084 { /* i-te Zeile von i-1 bis links normieren */ 00085 ma[i][k] /= epsilon; 00086 sum += ma[i][k]*ma[i][k]; 00087 } 00088 tmp = (ma[i][i-1] > 0) ? -sqrt(sum) : sqrt(sum); 00089 neben[i] = epsilon*tmp; 00090 h = sum - ma[i][i-1]*tmp; 00091 ma[i][i-1] -= tmp; 00092 for (j = 0, sum = 0.0; j < i; ++j) 00093 { 00094 ma[j][i] = ma[i][j]/h; 00095 tmp = 0.0; 00096 for (k = j; k >= 0; --k) 00097 tmp += ma[j][k]*ma[i][k]; 00098 for (k = j+1; k < i; ++k) 00099 tmp += ma[k][j]*ma[i][k]; 00100 neben[j] = tmp/h; 00101 sum += neben[j] * ma[i][j]; 00102 } /* for j */ 00103 sum /= 2.*h; 00104 for (j = 0; j < i; ++j) 00105 { 00106 neben[j] -= ma[i][j]*sum; 00107 tmp = ma[i][j]; 00108 tmp2 = neben[j]; 00109 for (k = j; k >= 0; --k) 00110 ma[j][k] -= (tmp*neben[k] + tmp2*ma[i][k]); 00111 } /* for j */ 00112 } /* else epsilon */ 00113 } /* else i == 1 */ 00114 diag[i] = h; 00115 } /* for i */ 00116 00117 diag[0] = 0.0; 00118 neben[0] = 0.0; 00119 00120 for (i = 0; i < N; ++i) 00121 { 00122 if(diag[i] != 0.0) 00123 for (j = 0; j < i; ++j) 00124 { 00125 for (k = i-1, tmp = 0.0; k >= 0; --k) 00126 tmp += ma[i][k] * ma[k][j]; 00127 for (k = i-1; k >= 0; --k) 00128 ma[k][j] -= tmp*ma[k][i]; 00129 } /* for j */ 00130 diag[i] = ma[i][i]; 00131 ma[i][i] = 1.0; 00132 for (k = i-1; k >= 0; --k) 00133 ma[k][i] = ma[i][k] = 0.0; 00134 } /* for i */ 00135 } 00136 00137 /* 00138 QL-Algorithmus mit implizitem Shift, zur Berechnung von Eigenwerten 00139 und -vektoren einer symmetrischen Tridiagonalmatrix. 00140 -> n : Dimension. 00141 -> diag : Diagonale der Tridiagonalmatrix. 00142 -> neben[0..n-1] : Nebendiagonale (==0..n-2), n-1. Eintrag beliebig 00143 -> mq : Matrix output von Householder() 00144 -> maxIt : maximale Zahl der Iterationen 00145 <- diag : Eigenwerte 00146 <- neben : Garbage 00147 <- mq : k-te Spalte ist normalisierter Eigenvektor zu diag[k] 00148 00149 */ 00150 00151 static int 00152 QLalgo( int N, valarray<double>& diag, square_matrix& mq, 00153 int maxIter, double* neben) 00154 { 00155 int i, j, k, kp1, l; 00156 double tmp, diff, cneben, c1, c2, p; 00157 int iter; 00158 00159 neben[N-1] = 0.0; 00160 for (i = 0, iter = 0; i < N && iter < maxIter; ++i) 00161 do /* while j != i */ 00162 { 00163 for (j = i; j < N-1; ++j) 00164 { 00165 tmp = fabs(diag[j]) + fabs(diag[j+1]); 00166 if (fabs(neben[j]) + tmp == tmp) 00167 break; 00168 } 00169 if (j != i) 00170 { 00171 if (++iter > maxIter) return maxIter-1; 00172 diff = (diag[i+1]-diag[i])/neben[i]/2.0; 00173 if (diff >= 0) 00174 diff = diag[j] - diag[i] + 00175 neben[i] / (diff + sqrt(diff * diff + 1.0)); 00176 else 00177 diff = diag[j] - diag[i] + 00178 neben[i] / (diff - sqrt(diff * diff + 1.0)); 00179 c2 = c1 = 1.0; 00180 p = 0.0; 00181 for (k = j-1; k >= i; --k) 00182 { 00183 kp1 = k + 1; 00184 tmp = c2 * neben[k]; 00185 cneben = c1 * neben[k]; 00186 if (fabs(tmp) >= fabs(diff)) 00187 { 00188 c1 = diff / tmp; 00189 c2 = 1. / sqrt(c1*c1 + 1.0); 00190 neben[kp1] = tmp / c2; 00191 c1 *= c2; 00192 } 00193 else 00194 { 00195 c2 = tmp / diff; 00196 c1 = 1. / sqrt(c2*c2 + 1.0); 00197 neben[kp1] = diff / c1; 00198 c2 *= c1; 00199 } /* else */ 00200 tmp = (diag[k] - diag[kp1] + p) * c2 + 2.0 * c1 * cneben; 00201 diag[kp1] += tmp * c2 - p; 00202 p = tmp * c2; 00203 diff = tmp * c1 - cneben; 00204 for (l = N-1; l >= 0; --l) /* TF-Matrix Q */ 00205 { 00206 tmp = mq[l][kp1]; 00207 mq[l][kp1] = c2 * mq[l][k] + c1 * tmp; 00208 mq[l][k] = c1 * mq[l][k] - c2 * tmp; 00209 } /* for l */ 00210 } /* for k */ 00211 diag[i] -= p; 00212 neben[i] = diff; 00213 neben[j] = 0.0; 00214 } /* if */ 00215 } while (j != i); 00216 return iter; 00217 } /* QLalgo() */ 00218 00219 /* ========================================================= */ 00220 /* 00221 Calculating eigenvalues and vectors. 00222 Input: 00223 N: dimension. 00224 C: lower_triangular NxN-matrix. 00225 niter: number of maximal iterations for QL-Algorithm. 00226 rgtmp: N+1-dimensional vector for temporal use. 00227 Output: 00228 diag: N eigenvalues. 00229 Q: Columns are normalized eigenvectors. 00230 return: number of iterations in QL-Algorithm. 00231 */ 00232 00233 namespace eo { 00234 int 00235 eig( int N, const lower_triangular_matrix& C, valarray<double>& diag, square_matrix& Q, 00236 int niter) 00237 { 00238 int ret; 00239 int i, j; 00240 00241 if (niter == 0) niter = 30*N; 00242 00243 for (i=0; i < N; ++i) 00244 { 00245 vector<double>::const_iterator row = C[i]; 00246 for (j = 0; j <= i; ++j) 00247 Q[i][j] = Q[j][i] = row[j]; 00248 } 00249 00250 double* rgtmp = new double[N+1]; 00251 Householder( N, Q, diag, rgtmp); 00252 ret = QLalgo( N, diag, Q, niter, rgtmp+1); 00253 delete [] rgtmp; 00254 00255 return ret; 00256 } 00257 00258 } // namespace eo