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/hookejeeves.hxx"
00029 #include "numeric/exception.hxx"
00030 #include "numeric/nlpmodel.hxx"
00031 #include "numeric/funcobj.hxx"
00032 #include "numeric/quadfitlinesearch.hxx"
00033
00034 #include <cmath>
00035 #include <stdio.h>
00036
00037 using namespace ::scsolver::numeric;
00038 using ::std::vector;
00039
00040 namespace scsolver { namespace numeric { namespace nlp {
00041
00042 HookeJeeves::HookeJeeves() :
00043 BaseAlgorithm(),
00044 m_maxIteration(10000)
00045 {
00046 }
00047
00048 HookeJeeves::~HookeJeeves()
00049 {
00050 }
00051
00052 static void debugPrint(const vector<double>& vars, const char* msg, bool debug)
00053 {
00054 if (!debug)
00055 return;
00056
00057 FILE* fs = stdout;
00058 fprintf(fs, "%s: (", msg);
00059 size_t n = vars.size();
00060 for (size_t i = 0; i < n; ++i)
00061 {
00062 if (i > 0)
00063 fprintf(fs, ", ");
00064 fprintf(fs, "%g", vars[i]);
00065 }
00066 fprintf(fs, ")\n");
00067 }
00068
00069 static double calcDeltaDistance(const vector<double>& pt1, const vector<double>& pt2)
00070 {
00071 size_t n = pt1.size();
00072 if (n != pt2.size())
00073 throw Exception("size of the current point differs from the size of the previous point.");
00074
00075 double dist = 0.0;
00076 for (size_t i = 0; i < n; ++i)
00077 {
00078 double one = pt2[i] - pt1[i];
00079 one *= one;
00080 dist += one;
00081 }
00082
00083 dist = ::std::pow(dist, 1.0/static_cast<double>(n));
00084 return dist;
00085 }
00086
00087 static void getPatternSearchVector(const vector<double>& pt1, const vector<double>& pt2,
00088 vector<double>& vec)
00089 {
00090 using ::scsolver::numeric::Exception;
00091
00092 size_t n = pt1.size();
00093 if (n != pt2.size())
00094 throw Exception("size of the current point differs from the size of the previous point.");
00095
00096 vector<double> tmp(n);
00097 for (size_t i = 0; i < n; ++i)
00098 tmp[i] = pt2[i] - pt1[i];
00099 vec.swap(tmp);
00100 }
00101
00102 void HookeJeeves::solve()
00103 {
00104 const double eps = 1.0e-6;
00105 bool debug = isDebug();
00106 Model& model = *getModel();
00107 model.print();
00108 BaseFuncObj& F = *model.getFuncObject();
00109
00110 vector<double> vars;
00111 model.getVars(vars);
00112 double fval = F(vars);
00113 if (debug)
00114 {
00115 debugPrint(vars, "initial vars", debug);
00116 printf("F(x) = %g\n", fval);
00117 }
00118
00119
00120 size_t varCount = vars.size();
00121 vector<double> prevVars(vars);
00122 for (size_t i = 0; i < m_maxIteration; ++i)
00123 {
00124 if (debug)
00125 printf("ITERATION %d\n", i);
00126
00127 for (size_t varIndex = 0; varIndex < varCount; ++varIndex)
00128 {
00129 SingleVarFuncObj& rSingleFuncObj = F.getSingleVarFuncObj(varIndex);
00130 QuadFitLineSearch qfit(&rSingleFuncObj);
00131 qfit.setGoal(GOAL_MINIMIZE);
00132 qfit.setDebug(false);
00133 double res = qfit.solve();
00134 F.setVar(varIndex, res);
00135 }
00136 const vector<double>& tmpVars = F.getVars();
00137 debugPrint(tmpVars, " after the iteration", debug);
00138 if (debug)
00139 {
00140 printf(" F(x) = %g\n", F.eval());
00141 }
00142
00143 double dist = calcDeltaDistance(prevVars, tmpVars);
00144 if (debug)
00145 printf(" distance = %g\n", dist);
00146
00147 if (dist < eps)
00148 return;
00149
00150 vector<double> vec;
00151 getPatternSearchVector(prevVars, tmpVars, vec);
00152 debugPrint(vec, "pattern search vector", debug);
00153 SingleVarFuncObj& rSingleFuncObj = F.getSingleVarFuncObjByRatio(vec);
00154 QuadFitLineSearch qfit(&rSingleFuncObj);
00155 qfit.setGoal(GOAL_MINIMIZE);
00156 qfit.setDebug(false);
00157 qfit.solve();
00158 const vector<double>& tmpVars2 = F.getVars();
00159 debugPrint(tmpVars2, "end of pattern search", debug);
00160
00161 prevVars = tmpVars2;
00162 }
00163
00164 throw ModelInfeasible();
00165 }
00166
00167 }}}