# eig.cpp

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