00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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
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
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
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;
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
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
00258
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
00295
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
00313 return;
00314
00315
00316 updateCoordinateVectors(directions, lambdas, false);
00317
00318 prevVars = tmpVars;
00319 }
00320
00321 throw ModelInfeasible();
00322 }
00323
00324 }}}