EvolvingObjects
eig.cpp
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
 All Classes Namespaces Files Functions Variables Typedefs Friends