public override EndCriteria.Type minimize(Problem P, EndCriteria endCriteria) { // Initializations double ftol = endCriteria.functionEpsilon(); int maxStationaryStateIterations_ = endCriteria.maxStationaryStateIterations(); EndCriteria.Type ecType = EndCriteria.Type.None; // reset end criteria P.reset(); // reset problem Vector x_ = P.currentValue(); // store the starting point int iterationNumber_ = 0; // dimension line search lineSearch_.searchDirection = new Vector(x_.size()); bool done = false; // function and squared norm of gradient values double fnew, fold, gold2; double fdiff; // classical initial value for line-search step double t = 1.0; // Set gradient g at the size of the optimization problem // search direction int sz = lineSearch_.searchDirection.size(); Vector prevGradient = new Vector(sz), d = new Vector(sz), sddiff = new Vector(sz), direction = new Vector(sz); // Initialize cost function, gradient prevGradient and search direction P.setFunctionValue(P.valueAndGradient(ref prevGradient, x_)); P.setGradientNormValue(Vector.DotProduct(prevGradient, prevGradient)); lineSearch_.searchDirection = prevGradient * -1; bool first_time = true; // Loop over iterations do { // Linesearch if (!first_time) { prevGradient = lineSearch_.lastGradient(); } t = (lineSearch_.value(P, ref ecType, endCriteria, t)); // don't throw: it can fail just because maxIterations exceeded 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 * Math.Abs(fnew - fold) / (Math.Abs(fnew) + Math.Abs(fold) + Const.QL_EPSILON); if (fdiff < ftol || endCriteria.checkMaxIterations(iterationNumber_, ref ecType)) { endCriteria.checkStationaryFunctionValue(0.0, 0.0, ref maxStationaryStateIterations_, ref ecType); endCriteria.checkMaxIterations(iterationNumber_, ref 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); }
//! computes the new search direction protected virtual Vector getUpdatedDirection(Problem P, double gold2, Vector gradient) { throw new NotImplementedException(); }
// LineSearchBasedMethod interface protected override Vector getUpdatedDirection(Problem P, double gold2, Vector oldGradient) { if (inverseHessian_.rows() == 0) { // first time in this update, we create needed structures inverseHessian_ = new Matrix(P.currentValue().size(), P.currentValue().size(), 0.0); for (int i = 0; i < P.currentValue().size(); ++i) { inverseHessian_[i, i] = 1.0; } } Vector diffGradient = new Vector(); Vector diffGradientWithHessianApplied = new Vector(P.currentValue().size(), 0.0); diffGradient = lineSearch_.lastGradient() - oldGradient; for (int i = 0; i < P.currentValue().size(); ++i) { for (int j = 0; j < P.currentValue().size(); ++j) { diffGradientWithHessianApplied[i] += inverseHessian_[i, j] * diffGradient[j]; } } double fac, fae, fad; double sumdg, sumxi; fac = fae = sumdg = sumxi = 0.0; for (int i = 0; i < P.currentValue().size(); ++i) { fac += diffGradient[i] * lineSearch_.searchDirection[i]; fae += diffGradient[i] * diffGradientWithHessianApplied[i]; sumdg += Math.Pow(diffGradient[i], 2.0); sumxi += Math.Pow(lineSearch_.searchDirection[i], 2.0); } if (fac > Math.Sqrt(1e-8 * sumdg * sumxi)) // skip update if fac not sufficiently positive { fac = 1.0 / fac; fad = 1.0 / fae; for (int i = 0; i < P.currentValue().size(); ++i) { diffGradient[i] = fac * lineSearch_.searchDirection[i] - fad * diffGradientWithHessianApplied[i]; } for (int i = 0; i < P.currentValue().size(); ++i) { for (int j = 0; j < P.currentValue().size(); ++j) { inverseHessian_[i, j] += fac * lineSearch_.searchDirection[i] * lineSearch_.searchDirection[j]; inverseHessian_[i, j] -= fad * diffGradientWithHessianApplied[i] * diffGradientWithHessianApplied[j]; inverseHessian_[i, j] += fae * diffGradient[i] * diffGradient[j]; } } } Vector direction = new Vector(P.currentValue().size()); for (int i = 0; i < P.currentValue().size(); ++i) { direction[i] = 0.0; for (int j = 0; j < P.currentValue().size(); ++j) { direction[i] -= inverseHessian_[i, j] * lineSearch_.lastGradient()[j]; } } return(direction); }
public override EndCriteria.Type minimize(Problem P, EndCriteria endCriteria) { EndCriteria.Type ecType = EndCriteria.Type.None; P.reset(); Vector x_ = P.currentValue(); currentProblem_ = P; initCostValues_ = P.costFunction().values(x_); int m = initCostValues_.size(); int n = x_.size(); if (useCostFunctionsJacobian_) { initJacobian_ = new Matrix(m, n); P.costFunction().jacobian(initJacobian_, x_); } Vector xx = new Vector(x_); Vector fvec = new Vector(m), diag = new Vector(n); int mode = 1; double factor = 1; int nprint = 0; int info = 0; int nfev = 0; Matrix fjac = new Matrix(m, n); int ldfjac = m; List <int> ipvt = new InitializedList <int>(n); Vector qtf = new Vector(n), wa1 = new Vector(n), wa2 = new Vector(n), wa3 = new Vector(n), wa4 = new Vector(m); // call lmdif to minimize the sum of the squares of m functions // in n variables by the Levenberg-Marquardt algorithm. Func <int, int, Vector, int, Matrix> j = null; if (useCostFunctionsJacobian_) { j = jacFcn; } // requirements; check here to get more detailed error messages. Utils.QL_REQUIRE(n > 0, () => "no variables given"); Utils.QL_REQUIRE(m >= n, () => $"less functions ({m}) than available variables ({n})"); Utils.QL_REQUIRE(endCriteria.functionEpsilon() >= 0.0, () => "negative f tolerance"); Utils.QL_REQUIRE(xtol_ >= 0.0, () => "negative x tolerance"); Utils.QL_REQUIRE(gtol_ >= 0.0, () => "negative g tolerance"); Utils.QL_REQUIRE(endCriteria.maxIterations() > 0, () => "null number of evaluations"); MINPACK.lmdif(m, n, xx, ref fvec, endCriteria.functionEpsilon(), xtol_, gtol_, endCriteria.maxIterations(), epsfcn_, diag, mode, factor, nprint, ref info, ref nfev, ref fjac, ldfjac, ref ipvt, ref qtf, wa1, wa2, wa3, wa4, fcn, j); info_ = info; // check requirements & endCriteria evaluation Utils.QL_REQUIRE(info != 0, () => "MINPACK: improper input parameters"); if (info != 6) { ecType = EndCriteria.Type.StationaryFunctionValue; } endCriteria.checkMaxIterations(nfev, ref ecType); Utils.QL_REQUIRE(info != 7, () => "MINPACK: xtol is too small. no further " + "improvement in the approximate " + "solution x is possible."); Utils.QL_REQUIRE(info != 8, () => "MINPACK: gtol is too small. fvec is " + "orthogonal to the columns of the " + "jacobian to machine precision."); // set problem x_ = new Vector(xx.GetRange(0, n)); P.setCurrentValue(x_); P.setFunctionValue(P.costFunction().value(x_)); return(ecType); }
public void compute() { if (vegaWeighted_) { double weightsSum = 0.0; for (int i = 0; i < times_.Count; i++) { double stdDev = Math.Sqrt(blackVols_[i] * blackVols_[i] * times_[i]); // when strike==forward, the blackFormulaStdDevDerivative becomes weights_[i] = new CumulativeNormalDistribution().derivative(.5 * stdDev); weightsSum += weights_[i]; } // weight normalization for (int i = 0; i < times_.Count; i++) { weights_[i] /= weightsSum; } } // there is nothing to optimize if (aIsFixed_ && bIsFixed_ && cIsFixed_ && dIsFixed_) { abcdEndCriteria_ = QLCore.EndCriteria.Type.None; return; } else { AbcdError costFunction = new AbcdError(this); transformation_ = new AbcdParametersTransformation(); Vector guess = new Vector(4); guess[0] = a_; guess[1] = b_; guess[2] = c_; guess[3] = d_; List <bool> parameterAreFixed = new InitializedList <bool>(4); parameterAreFixed[0] = aIsFixed_; parameterAreFixed[1] = bIsFixed_; parameterAreFixed[2] = cIsFixed_; parameterAreFixed[3] = dIsFixed_; Vector inversedTransformatedGuess = new Vector(transformation_.inverse(guess)); ProjectedCostFunction projectedAbcdCostFunction = new ProjectedCostFunction(costFunction, inversedTransformatedGuess, parameterAreFixed); Vector projectedGuess = new Vector(projectedAbcdCostFunction.project(inversedTransformatedGuess)); NoConstraint constraint = new NoConstraint(); Problem problem = new Problem(projectedAbcdCostFunction, constraint, projectedGuess); abcdEndCriteria_ = optMethod_.minimize(problem, endCriteria_); Vector projectedResult = new Vector(problem.currentValue()); Vector transfResult = new Vector(projectedAbcdCostFunction.include(projectedResult)); Vector result = transformation_.direct(transfResult); QLCore.AbcdMathFunction.validate(a_, b_, c_, d_); a_ = result[0]; b_ = result[1]; c_ = result[2]; d_ = result[3]; } }