EndCriteria::Type DifferentialEvolution::minimize(Problem& p, const EndCriteria& endCriteria) { EndCriteria::Type ecType; upperBound_ = p.constraint().upperBound(p.currentValue()); lowerBound_ = p.constraint().lowerBound(p.currentValue()); currGenSizeWeights_ = Array(configuration().populationMembers, configuration().stepsizeWeight); currGenCrossover_ = Array(configuration().populationMembers, configuration().crossoverProbability); std::vector<Candidate> population(configuration().populationMembers, Candidate(p.currentValue().size())); fillInitialPopulation(population, p); std::partial_sort(population.begin(), population.begin() + 1, population.end(), sort_by_cost()); bestMemberEver_ = population.front(); Real fxOld = population.front().cost; Size iteration = 0, stationaryPointIteration = 0; // main loop - calculate consecutive emerging populations while (!endCriteria.checkMaxIterations(iteration++, ecType)) { calculateNextGeneration(population, p.costFunction()); std::partial_sort(population.begin(), population.begin() + 1, population.end(), sort_by_cost()); if (population.front().cost < bestMemberEver_.cost) bestMemberEver_ = population.front(); Real fxNew = population.front().cost; if (endCriteria.checkStationaryFunctionValue(fxOld, fxNew, stationaryPointIteration, ecType)) break; fxOld = fxNew; }; p.setCurrentValue(bestMemberEver_.values); p.setFunctionValue(bestMemberEver_.cost); return ecType; }
Real GoldsteinLineSearch::operator()(Problem& P, EndCriteria::Type& ecType, const EndCriteria& endCriteria, const Real t_ini) { Constraint& constraint = P.constraint(); succeed_=true; bool maxIter = false; Real /*qtold,*/ t = t_ini; // see below, this is never used ? Size loopNumber = 0; Real q0 = P.functionValue(); Real qp0 = P.gradientNormValue(); Real tl = 0.0; Real tr = 0.0; qt_ = q0; qpt_ = (gradient_.empty()) ? qp0 : -DotProduct(gradient_,searchDirection_); // Initialize gradient gradient_ = Array(P.currentValue().size()); // Compute new point xtd_ = P.currentValue(); t = update(xtd_, searchDirection_, t, constraint); // Compute function value at the new point qt_ = P.value (xtd_); while ((qt_ - q0) < -beta_*t*qpt_ || (qt_ - q0) > -alpha_*t*qpt_) { if ((qt_ - q0) > -alpha_*t*qpt_) tr = t; else tl = t; ++loopNumber; // calculate the new step if (close_enough(tr, 0.0)) t *= extrapolation_; else t = (tl + tr) / 2.0; // Store old value of the function // qtold = qt_; // this is never used ? // New point value xtd_ = P.currentValue(); t = update(xtd_, searchDirection_, t, constraint); // Compute function value at the new point qt_ = P.value (xtd_); P.gradient (gradient_, xtd_); // and it squared norm maxIter = endCriteria.checkMaxIterations(loopNumber, ecType); if (maxIter) break; } if (maxIter) succeed_ = false; // Compute new gradient P.gradient(gradient_, xtd_); // and it squared norm qpt_ = DotProduct(gradient_, gradient_); // Return new step value return t; }
EndCriteria::Type LevenbergMarquardt::minimize(Problem& P, const EndCriteria& endCriteria) { EndCriteria::Type ecType = EndCriteria::None; P.reset(); Array x_ = P.currentValue(); currentProblem_ = &P; initCostValues_ = P.costFunction().values(x_); int m = initCostValues_.size(); int n = x_.size(); boost::scoped_array<double> xx(new double[n]); std::copy(x_.begin(), x_.end(), xx.get()); boost::scoped_array<double> fvec(new double[m]); boost::scoped_array<double> diag(new double[n]); int mode = 1; double factor = 1; int nprint = 0; int info = 0; int nfev =0; boost::scoped_array<double> fjac(new double[m*n]); int ldfjac = m; boost::scoped_array<int> ipvt(new int[n]); boost::scoped_array<double> qtf(new double[n]); boost::scoped_array<double> wa1(new double[n]); boost::scoped_array<double> wa2(new double[n]); boost::scoped_array<double> wa3(new double[n]); boost::scoped_array<double> wa4(new double[m]); // requirements; check here to get more detailed error messages. QL_REQUIRE(n > 0, "no variables given"); QL_REQUIRE(m >= n, "less functions (" << m << ") than available variables (" << n << ")"); QL_REQUIRE(endCriteria.functionEpsilon() >= 0.0, "negative f tolerance"); QL_REQUIRE(xtol_ >= 0.0, "negative x tolerance"); QL_REQUIRE(gtol_ >= 0.0, "negative g tolerance"); QL_REQUIRE(endCriteria.maxIterations() > 0, "null number of evaluations"); // call lmdif to minimize the sum of the squares of m functions // in n variables by the Levenberg-Marquardt algorithm. MINPACK::LmdifCostFunction lmdifCostFunction = boost::bind(&LevenbergMarquardt::fcn, this, _1, _2, _3, _4, _5); MINPACK::lmdif(m, n, xx.get(), fvec.get(), static_cast<double>(endCriteria.functionEpsilon()), static_cast<double>(xtol_), static_cast<double>(gtol_), static_cast<int>(endCriteria.maxIterations()), static_cast<double>(epsfcn_), diag.get(), mode, factor, nprint, &info, &nfev, fjac.get(), ldfjac, ipvt.get(), qtf.get(), wa1.get(), wa2.get(), wa3.get(), wa4.get(), lmdifCostFunction); info_ = info; // check requirements & endCriteria evaluation QL_REQUIRE(info != 0, "MINPACK: improper input parameters"); //QL_REQUIRE(info != 6, "MINPACK: ftol is too small. no further " // "reduction in the sum of squares " // "is possible."); if (info != 6) ecType = QuantLib::EndCriteria::StationaryFunctionValue; //QL_REQUIRE(info != 5, "MINPACK: number of calls to fcn has " // "reached or exceeded maxfev."); endCriteria.checkMaxIterations(nfev, ecType); QL_REQUIRE(info != 7, "MINPACK: xtol is too small. no further " "improvement in the approximate " "solution x is possible."); QL_REQUIRE(info != 8, "MINPACK: gtol is too small. fvec is " "orthogonal to the columns of the " "jacobian to machine precision."); // set problem std::copy(xx.get(), xx.get()+n, x_.begin()); P.setCurrentValue(x_); P.setFunctionValue(P.costFunction().value(x_)); return ecType; }
EndCriteria::Type Simplex::minimize(Problem& P, const EndCriteria& endCriteria) { // set up of the problem //Real ftol = endCriteria.functionEpsilon(); // end criteria on f(x) (see Numerical Recipes in C++, p.410) Real xtol = endCriteria.rootEpsilon(); // end criteria on x (see GSL v. 1.9, http://www.gnu.org/software/gsl/) Size maxStationaryStateIterations_ = endCriteria.maxStationaryStateIterations(); EndCriteria::Type ecType = EndCriteria::None; P.reset(); Array x_ = P.currentValue(); Integer iterationNumber_=0; // Initialize vertices of the simplex bool end = false; Size n = x_.size(), i; vertices_ = std::vector<Array>(n+1, x_); for (i=0; i<n; i++) { Array direction(n, 0.0); direction[i] = 1.0; P.constraint().update(vertices_[i+1], direction, lambda_); } // Initialize function values at the vertices of the simplex values_ = Array(n+1, 0.0); for (i=0; i<=n; i++) values_[i] = P.value(vertices_[i]); // Loop looking for minimum do { sum_ = Array(n, 0.0); Size i; for (i=0; i<=n; i++) sum_ += vertices_[i]; // Determine the best (iLowest), worst (iHighest) // and 2nd worst (iNextHighest) vertices Size iLowest = 0; Size iHighest, iNextHighest; if (values_[0]<values_[1]) { iHighest = 1; iNextHighest = 0; } else { iHighest = 0; iNextHighest = 1; } for (i=1;i<=n; i++) { if (values_[i]>values_[iHighest]) { iNextHighest = iHighest; iHighest = i; } else { if ((values_[i]>values_[iNextHighest]) && i!=iHighest) iNextHighest = i; } if (values_[i]<values_[iLowest]) iLowest = i; } // Now compute accuracy, update iteration number and check end criteria //// Numerical Recipes exit strategy on fx (see NR in C++, p.410) //Real low = values_[iLowest]; //Real high = values_[iHighest]; //Real rtol = 2.0*std::fabs(high - low)/ // (std::fabs(high) + std::fabs(low) + QL_EPSILON); //++iterationNumber_; //if (rtol < ftol || // endCriteria.checkMaxIterations(iterationNumber_, ecType)) { // GSL exit strategy on x (see GSL v. 1.9, http://www.gnu.org/software/gsl Real simplexSize = computeSimplexSize(vertices_); ++iterationNumber_; if (simplexSize < xtol || endCriteria.checkMaxIterations(iterationNumber_, ecType)) { endCriteria.checkStationaryPoint(0.0, 0.0, maxStationaryStateIterations_, ecType); // PC this is probably not meant like this ? Use separate counter ? endCriteria.checkMaxIterations(iterationNumber_, ecType); x_ = vertices_[iLowest]; Real low = values_[iLowest]; P.setFunctionValue(low); P.setCurrentValue(x_); return ecType; } // If end criteria is not met, continue Real factor = -1.0; Real vTry = extrapolate(P, iHighest, factor); if ((vTry <= values_[iLowest]) && (factor == -1.0)) { factor = 2.0; extrapolate(P, iHighest, factor); } else if (std::fabs(factor) > QL_EPSILON) { if (vTry >= values_[iNextHighest]) { Real vSave = values_[iHighest]; factor = 0.5; vTry = extrapolate(P, iHighest, factor); if (vTry >= vSave && std::fabs(factor) > QL_EPSILON) { for (Size i=0; i<=n; i++) { if (i!=iLowest) { #if defined(QL_ARRAY_EXPRESSIONS) vertices_[i] = 0.5*(vertices_[i] + vertices_[iLowest]); #else vertices_[i] += vertices_[iLowest]; vertices_[i] *= 0.5; #endif values_[i] = P.value(vertices_[i]); } } } } } // If can't extrapolate given the constraints, exit if (std::fabs(factor) <= QL_EPSILON) { x_ = vertices_[iLowest]; Real low = values_[iLowest]; P.setFunctionValue(low); P.setCurrentValue(x_); return EndCriteria::StationaryFunctionValue; } } while (end == false); QL_FAIL("optimization failed: unexpected behaviour"); }
EndCriteria::Type LineSearchBasedMethod::minimize(Problem& P, const EndCriteria& endCriteria) { // Initializations Real ftol = endCriteria.functionEpsilon(); Size maxStationaryStateIterations_ = endCriteria.maxStationaryStateIterations(); EndCriteria::Type ecType = EndCriteria::None; // reset end criteria P.reset(); // reset problem Array x_ = P.currentValue(); // store the starting point Size iterationNumber_ = 0; // dimension line search lineSearch_->searchDirection() = Array(x_.size()); bool done = false; // function and squared norm of gradient values; Real fnew, fold, gold2; Real fdiff; // classical initial value for line-search step Real t = 1.0; // Set gradient g at the size of the optimization problem // search direction Size sz = lineSearch_->searchDirection().size(); Array prevGradient(sz), d(sz), sddiff(sz), direction(sz); // Initialize cost function, gradient prevGradient and search direction P.setFunctionValue(P.valueAndGradient(prevGradient, x_)); P.setGradientNormValue(DotProduct(prevGradient, prevGradient)); lineSearch_->searchDirection() = -prevGradient; bool first_time = true; // Loop over iterations do { // Linesearch if (!first_time) prevGradient = lineSearch_->lastGradient(); t = (*lineSearch_)(P, ecType, endCriteria, t); // don't throw: it can fail just because maxIterations exceeded //QL_REQUIRE(lineSearch_->succeed(), "line-search failed!"); if (lineSearch_->succeed()) { // Updates // New point x_ = lineSearch_->lastX(); // New function value fold = P.functionValue(); P.setFunctionValue(lineSearch_->lastFunctionValue()); // New gradient and search direction vectors // orthogonalization coef gold2 = P.gradientNormValue(); P.setGradientNormValue(lineSearch_->lastGradientNorm2()); // conjugate gradient search direction direction = getUpdatedDirection(P, gold2, prevGradient); sddiff = direction - lineSearch_->searchDirection(); lineSearch_->searchDirection() = direction; // Now compute accuracy and check end criteria // Numerical Recipes exit strategy on fx (see NR in C++, p.423) fnew = P.functionValue(); fdiff = 2.0*std::fabs(fnew-fold) / (std::fabs(fnew) + std::fabs(fold) + QL_EPSILON); if (fdiff < ftol || endCriteria.checkMaxIterations(iterationNumber_, ecType)) { endCriteria.checkStationaryFunctionValue(0.0, 0.0, maxStationaryStateIterations_, ecType); endCriteria.checkMaxIterations(iterationNumber_, ecType); return ecType; } P.setCurrentValue(x_); // update problem current value ++iterationNumber_; // Increase iteration number first_time = false; } else { done = true; } } while (!done); P.setCurrentValue(x_); return ecType; }