source/numeric/rosenbrock.cxx

Go to the documentation of this file.
00001 /*************************************************************************
00002  *
00003  *  The Contents of this file are made available subject to
00004  *  the terms of GNU Lesser General Public License Version 2.1.
00005  *
00006  *
00007  *    GNU Lesser General Public License Version 2.1
00008  *    =============================================
00009  *    Copyright 2008 by Kohei Yoshida.
00010  *    1039 Kingsway Dr., Apex, NC 27502, USA
00011  *
00012  *    This library is free software; you can redistribute it and/or
00013  *    modify it under the terms of the GNU Lesser General Public
00014  *    License version 2.1, as published by the Free Software Foundation.
00015  *
00016  *    This library is distributed in the hope that it will be useful,
00017  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  *    Lesser General Public License for more details.
00020  *
00021  *    You should have received a copy of the GNU Lesser General Public
00022  *    License along with this library; if not, write to the Free Software
00023  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00024  *    MA  02111-1307  USA
00025  *
00026  ************************************************************************/
00027 
00028 #include "numeric/rosenbrock.hxx"
00029 #include "numeric/exception.hxx"
00030 #include "numeric/nlpmodel.hxx"
00031 #include "numeric/funcobj.hxx"
00032 #include "numeric/quadfitlinesearch.hxx"
00033 #include "numeric/matrix.hxx"
00034 #include "tool/global.hxx"
00035 
00036 #include <sstream>
00037 #include <cmath>
00038 #include <cassert>
00039 #include <vector>
00040 #include <stdio.h>
00041 
00042 using ::scsolver::vectorToMatrix;
00043 using namespace ::scsolver::numeric;
00044 using ::std::vector;
00045 
00046 namespace scsolver { namespace numeric { namespace nlp {
00047 
00048 typedef vector<double> CoordinateVector;
00049 
00050 Rosenbrock::Rosenbrock() :
00051     BaseAlgorithm(),
00052     m_maxIteration(10000)
00053 {
00054 }
00055 
00056 Rosenbrock::~Rosenbrock()
00057 {
00058 }
00059 
00060 static void debugPrint(const vector<double>& vars, const char* msg, bool debug, FILE* fs = stdout)
00061 {
00062     if (!debug)
00063         return;
00064 
00065     fprintf(fs, "%s: (", msg);
00066     size_t n = vars.size();
00067     for (size_t i = 0; i < n; ++i)
00068     {
00069         if (i > 0)
00070             fprintf(fs, ", ");
00071         fprintf(fs, "%g", vars[i]);
00072     }
00073     fprintf(fs, ")\n");
00074 }
00075 
00076 static void printCoordinateVectors(const vector<CoordinateVector>& cvectors, bool debug)
00077 {
00078     if (!debug)
00079         return;
00080 
00081     FILE* fs = stdout;
00082     fprintf(fs, "Coordinate vectors\n");
00083 
00084     vector<CoordinateVector>::const_iterator itrBeg = cvectors.begin(), itrEnd = cvectors.end();
00085     for (vector<CoordinateVector>::const_iterator itr = itrBeg; itr != itrEnd; ++itr)
00086     {
00087         size_t index = distance(itrBeg, itr);
00088         ::std::ostringstream os;
00089         os << "  d" << index;
00090         debugPrint(*itr, os.str().c_str(), debug, fs);
00091     }
00092 }
00093 
00094 static double calcDeltaDistance(const vector<double>& pt1, const vector<double>& pt2)
00095 {
00096     size_t n = pt1.size();
00097     if (n != pt2.size())
00098         throw Exception("size of the current point differs from the size of the previous point.");
00099 
00100     double dist = 0.0;
00101     for (size_t i = 0; i < n; ++i)
00102     {
00103         double one = pt2[i] - pt1[i];
00104         one *= one;
00105         dist += one;
00106     }
00107 
00108     dist = ::std::pow(dist, 1.0/static_cast<double>(n));
00109     return dist;
00110 }
00111 
00119 static double calcNorm(const Matrix& mx)
00120 {
00121     if (mx.rows() > 1 && mx.cols() > 1)
00122         Exception("cannot calculate the norm of a non-vector matrix.");
00123 
00124     if (mx.empty())
00125         Exception("cannot calculate the norm of an empty matrix.");
00126 
00127     size_t n = mx.cols();
00128     double norm = 0.0;
00129     for (size_t i = 0; i < n; ++i)
00130         norm += mx(0, i)*mx(0, i);
00131 
00132     norm = sqrt(norm);
00133     return norm;
00134 }
00135 
00142 static void updateCoordinateVectors(vector<CoordinateVector>& cvectors, const vector<double>& lambdas, bool debug=false)
00143 {
00144     if (debug)
00145         fprintf(stdout, "nlp::updateCoordinateVectors: --begin\n");
00146 
00147     // Assume that every matrix is a single row matrix unless stated otherwise.
00148 
00149     size_t n = cvectors.size();
00150     vector<Matrix> newVectors;
00151     newVectors.reserve(n);
00152     for (size_t j = 0; j < n; ++j)
00153     {
00154         if (debug)
00155             fprintf(stdout, "nlp::updateCoordinateVectors: Iteration %d (lambda = %g)\n", j, lambdas[j]);
00156 
00157         // First, calculate matrix a.
00158         Matrix a;
00159         if (lambdas[j] == 0)
00160             vectorToMatrix(cvectors[j], a);
00161         else
00162         {
00163             Matrix tmpa(1, n);
00164             for (size_t i = j; i < n; ++i)
00165             {
00166                 if (debug)
00167                     fprintf(stdout, "nlp::updateCoordinateVectors:     i = %d\n", i);
00168                 Matrix tmpd;
00169                 vectorToMatrix(cvectors[i], tmpd);
00170                 if (debug)
00171                 {
00172                     fprintf(stdout, "nlp::updateCoordinateVectors:       tmpd = ");
00173                     tmpd.print();
00174                 }
00175                 tmpa += lambdas[i] * tmpd;
00176             }
00177             a.swap(tmpa);
00178         }
00179 
00180         if (debug)
00181         {
00182             fprintf(stdout, "nlp::updateCoordinateVectors:   calculated a = ");
00183             a.print();
00184         }
00185 
00186         // Next, calculate matrix b.
00187         Matrix b = a;
00188         for (size_t i = 0; i < j; ++i)
00189         {
00190             if (debug)
00191                 fprintf(stdout, "nlp::updateCoordinateVectors:     i = %d\n", i);
00192             Matrix newd = newVectors[i];
00193             Matrix tmp = a * newd.trans() * newd; // row mx * col mx * row mx
00194             if (debug)
00195             {
00196                 fprintf(stdout, "nlp::updateCoordinateVectors:       tmp = ");
00197                 tmp.print();
00198             }
00199             b -= tmp;
00200         }
00201         if (debug)
00202         {
00203             fprintf(stdout, "nlp::updateCoordinateVectors:   calculated b = ");
00204             b.print();
00205         }
00206         double norm = calcNorm(b);
00207         Matrix newd = b/norm;
00208         newVectors.push_back(newd);
00209     }
00210 
00211     if (debug)
00212     {
00213         size_t n2 = newVectors.size();
00214         for (size_t i = 0; i < n2; ++i)
00215         {
00216             fprintf(stdout, "nlp::updateCoordinateVectors: new d%d = ", i);
00217             newVectors[i].print();
00218         }
00219     }
00220 
00221     // Now, update the coordinate vectors.
00222     assert(n == newVectors.size());
00223     for (size_t i = 0; i < n; ++i)
00224     {
00225         vector<double>& dest = cvectors[i];
00226         const Matrix& src  = newVectors[i];
00227         size_t colSize = src.cols();
00228         assert(colSize == dest.size());
00229         for (size_t j = 0; j < colSize; ++j)
00230             dest[j] = src(0, j);
00231     }
00232 
00233     if (debug)
00234         fprintf(stdout, "nlp::updateCoordinateVectors: --end\n");
00235 }
00236 
00237 void Rosenbrock::solve()
00238 {
00239     const double eps = 1.0e-6;
00240 
00241     bool debug = isDebug();
00242     Model& model = *getModel();
00243     if (debug)
00244         model.print();
00245     BaseFuncObj& F = *model.getFuncObject();
00246 
00247     vector<double> vars;
00248     model.getVars(vars);
00249     size_t varCount = vars.size();
00250     double fval = F(vars);
00251     if (debug)
00252     {
00253         debugPrint(vars, "initial vars", debug);
00254         printf("F(x) = %g\n", fval);
00255     }
00256 
00257     // Generate the initial coordinate vectors which are identical to the
00258     // coordinate axes.
00259     vector<CoordinateVector> directions;
00260     directions.reserve(varCount);
00261     for (size_t i = 0; i < varCount; ++i)
00262     {
00263         CoordinateVector vec(varCount, 0.0);
00264         vec[i] = 1.0;
00265         directions.push_back(vec);
00266     }
00267 
00268     vector<double> prevVars(vars);
00269     vector<double> lambdas(varCount);
00270     for (size_t i = 0; i < m_maxIteration; ++i)
00271     {
00272         if (debug)
00273         {
00274             fprintf(stdout, "ITERATION %d\n", i);
00275             printCoordinateVectors(directions, debug);
00276         }
00277 
00278         for (size_t j = 0; j < varCount; ++j)
00279         {
00280             if (debug)
00281                 fprintf(stdout, "  line search along d%d\n", j);
00282 
00283             try
00284             {
00285                 SingleVarFuncObj& singleFunc = F.getSingleVarFuncObjByRatio(directions[j]);
00286                 QuadFitLineSearch qfit;
00287                 qfit.setFuncObj(&singleFunc);
00288                 qfit.setDebug(false);
00289                 double res = qfit.solve();
00290                 lambdas[j] = res - prevVars[j];
00291             }
00292             catch (const ::std::exception& e)
00293             {
00294                 // Keep going even if the line search fails.  In this case, just
00295                 // use the last good position to calculate the lambda.
00296                 if (debug)
00297                     fprintf(stdout, "  line search failed: %s\n", e.what());
00298 
00299                 double res = F.getVar(j);
00300                 lambdas[j] = res - prevVars[j];
00301             }
00302         }
00303 
00304         const vector<double>& tmpVars = F.getVars();
00305         debugPrint(tmpVars, "  variables", debug);
00306         debugPrint(lambdas, "  lambdas", debug);
00307         double dist = calcDeltaDistance(prevVars, tmpVars);
00308         if (debug)
00309             fprintf(stdout, "  distance = %g\n", dist);
00310         
00311         if (dist < eps)
00312             // solution found
00313             return;
00314 
00315         // Construct a new set of coordinate vectors.
00316         updateCoordinateVectors(directions, lambdas, false);
00317         
00318         prevVars = tmpVars;
00319     }
00320 
00321     throw ModelInfeasible();
00322 }
00323 
00324 }}}

Generated on Mon Jul 28 09:13:20 2008 for scsolver by  doxygen 1.5.3