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(); 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. 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); info_ = info; // check requirements & endCriteria evaluation if(info == 0) throw new ApplicationException("MINPACK: improper input parameters"); //if(info == 6) throw new ApplicationException("MINPACK: ftol is too small. no further " + // "reduction in the sum of squares is possible."); if (info != 6) ecType = EndCriteria.Type.StationaryFunctionValue; //QL_REQUIRE(info != 5, "MINPACK: number of calls to fcn has reached or exceeded maxfev."); endCriteria.checkMaxIterations(nfev, ref ecType); if(info == 7) throw new ApplicationException("MINPACK: xtol is too small. no further " + "improvement in the approximate " + "solution x is possible."); if(info == 8) throw new ApplicationException("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; }
//! minimize the optimization problem P public override EndCriteria.Type minimize(Problem P, EndCriteria endCriteria) { EndCriteria.Type ecType = EndCriteria.Type.None; P.reset(); Vector x_ = P.currentValue(); int iterationNumber_ = 0; int stationaryStateIterationNumber_ = 0; lineSearch_.searchDirection = new Vector(x_.Count); bool end; // function and squared norm of gradient values; double normdiff; // classical initial value for line-search step double t = 1.0; // Set gold at the size of the optimization problem search direction Vector gold = new Vector(lineSearch_.searchDirection.Count); Vector gdiff = new Vector(lineSearch_.searchDirection.Count); P.setFunctionValue(P.valueAndGradient(gold, x_)); lineSearch_.searchDirection = gold*-1.0; P.setGradientNormValue(Vector.DotProduct(gold, gold)); normdiff = Math.Sqrt(P.gradientNormValue()); do { // Linesearch t = lineSearch_.value(P, ref ecType, endCriteria, t); if (!(lineSearch_.succeed())) throw new ApplicationException("line-search failed!"); // End criteria // FIXME: it's never been used! ??? // , normdiff end = endCriteria.value(iterationNumber_, ref stationaryStateIterationNumber_, true, P.functionValue(), Math.Sqrt(P.gradientNormValue()), lineSearch_.lastFunctionValue(), Math.Sqrt(lineSearch_.lastGradientNorm2()), ref ecType); // Updates // New point x_ = lineSearch_.lastX(); // New function value P.setFunctionValue(lineSearch_.lastFunctionValue()); // New gradient and search direction vectors gdiff = gold - lineSearch_.lastGradient(); normdiff = Math.Sqrt(Vector.DotProduct(gdiff, gdiff)); gold = lineSearch_.lastGradient(); lineSearch_.searchDirection = gold*-1.0; // New gradient squared norm P.setGradientNormValue(lineSearch_.lastGradientNorm2()); // Increase interation number ++iterationNumber_; } while (end == false); P.setCurrentValue(x_); return ecType; }
//! Perform line search public override double value(Problem P, ref EndCriteria.Type ecType, EndCriteria endCriteria, double t_ini) { //OptimizationMethod& method = P.method(); Constraint constraint = P.constraint(); succeed_ = true; bool maxIter = false; double qtold; double t = t_ini; int loopNumber = 0; double q0 = P.functionValue(); double qp0 = P.gradientNormValue(); qt_ = q0; qpt_ = (gradient_.Count == 0) ? qp0 : -Vector.DotProduct(gradient_, searchDirection_); // Initialize gradient gradient_ = new Vector(P.currentValue().Count); // Compute new point xtd_ = (Vector)P.currentValue().Clone(); t = update(ref xtd_, searchDirection_, t, constraint); // Compute function value at the new point qt_ = P.value(xtd_); // Enter in the loop if the criterion is not satisfied if ((qt_ - q0) > -alpha_ * t * qpt_) { do { loopNumber++; // Decrease step t *= beta_; // Store old value of the function qtold = qt_; // New point value xtd_ = P.currentValue(); t = update(ref 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, ref ecType); } while ((((qt_ - q0) > (-alpha_ * t * qpt_)) || ((qtold - q0) <= (-alpha_ * t * qpt_ / beta_))) && (!maxIter)); } if (maxIter) succeed_ = false; // Compute new gradient P.gradient(gradient_, xtd_); // and it squared norm qpt_ = Vector.DotProduct(gradient_, gradient_); // Return new step value return t; }
public void nestedOptimizationTest() { //("Testing nested optimizations..."); OptimizationBasedCostFunction optimizationBasedCostFunction = new OptimizationBasedCostFunction(); NoConstraint constraint = new NoConstraint(); Vector initialValues = new Vector(1, 0.0); Problem problem = new Problem(optimizationBasedCostFunction, constraint, initialValues); LevenbergMarquardt optimizationMethod = new LevenbergMarquardt(); //Simplex optimizationMethod(0.1); //ConjugateGradient optimizationMethod; //SteepestDescent optimizationMethod; EndCriteria endCriteria = new EndCriteria(1000, 100, 1e-5, 1e-5, 1e-5); optimizationMethod.minimize(problem, endCriteria); }
// Optimization function for hypersphere and lower-diagonal algorithm private static Matrix hypersphereOptimize(Matrix targetMatrix, Matrix currentRoot, bool lowerDiagonal) { int i,j,k,size = targetMatrix.rows(); Matrix result = new Matrix(currentRoot); Vector variance = new Vector(size); for (i=0; i<size; i++){ variance[i]=Math.Sqrt(targetMatrix[i,i]); } if (lowerDiagonal) { Matrix approxMatrix = result*Matrix.transpose(result); result = MatrixUtilities.CholeskyDecomposition(approxMatrix, true); for (i=0; i<size; i++) { for (j=0; j<size; j++) { result[i,j]/=Math.Sqrt(approxMatrix[i,i]); } } } else { for (i=0; i<size; i++) { for (j=0; j<size; j++) { result[i,j]/=variance[i]; } } } ConjugateGradient optimize = new ConjugateGradient(); EndCriteria endCriteria = new EndCriteria(100, 10, 1e-8, 1e-8, 1e-8); HypersphereCostFunction costFunction = new HypersphereCostFunction(targetMatrix, variance, lowerDiagonal); NoConstraint constraint = new NoConstraint(); // hypersphere vector optimization if (lowerDiagonal) { Vector theta = new Vector(size * (size-1)/2); const double eps=1e-16; for (i=1; i<size; i++) { for (j=0; j<i; j++) { theta[i*(i-1)/2+j]=result[i,j]; if (theta[i*(i-1)/2+j]>1-eps) theta[i*(i-1)/2+j]=1-eps; if (theta[i*(i-1)/2+j]<-1+eps) theta[i*(i-1)/2+j]=-1+eps; for (k=0; k<j; k++) { theta[i*(i-1)/2+j] /= Math.Sin(theta[i*(i-1)/2+k]); if (theta[i*(i-1)/2+j]>1-eps) theta[i*(i-1)/2+j]=1-eps; if (theta[i*(i-1)/2+j]<-1+eps) theta[i*(i-1)/2+j]=-1+eps; } theta[i*(i-1)/2+j] = Math.Acos(theta[i*(i-1)/2+j]); if (j==i-1) { if (result[i,i]<0) theta[i*(i-1)/2+j]=-theta[i*(i-1)/2+j]; } } } Problem p = new Problem(costFunction, constraint, theta); optimize.minimize(p, endCriteria); theta = p.currentValue(); result.fill(1); for (i=0; i<size; i++) { for (k=0; k<size; k++) { if (k>i) { result[i,k]=0; } else { for (j=0; j<=k; j++) { if (j == k && k!=i) result[i,k] *= Math.Cos(theta[i*(i-1)/2+j]); else if (j!=i) result[i,k] *= Math.Sin(theta[i*(i-1)/2+j]); } } } } } else { Vector theta = new Vector(size * (size-1)); const double eps=1e-16; for (i=0; i<size; i++) { for (j=0; j<size-1; j++) { theta[j*size+i]=result[i,j]; if (theta[j*size+i]>1-eps) theta[j*size+i]=1-eps; if (theta[j*size+i]<-1+eps) theta[j*size+i]=-1+eps; for (k=0;k<j;k++) { theta[j*size+i] /= Math.Sin(theta[k*size+i]); if (theta[j*size+i]>1-eps) theta[j*size+i]=1-eps; if (theta[j*size+i]<-1+eps) theta[j*size+i]=-1+eps; } theta[j*size+i] = Math.Acos(theta[j*size+i]); if (j==size-2) { if (result[i,j+1]<0) theta[j*size+i]=-theta[j*size+i]; } } } Problem p = new Problem(costFunction, constraint, theta); optimize.minimize(p, endCriteria); theta=p.currentValue(); result.fill(1); for (i = 0; i < size; i++) { for (k=0; k<size; k++) { for (j=0; j<=k; j++) { if (j == k && k!=size-1) result[i,k] *= Math.Cos(theta[j*size+i]); else if (j!=size-1) result[i,k] *= Math.Sin(theta[j*size+i]); } } } } for (i=0; i<size; i++) { for (j=0; j<size; j++) { result[i,j]*=variance[i]; } } return result; }
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_ = QLNet.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); QLNet.AbcdMathFunction.validate(a_, b_, c_, d_); a_ = result[0]; b_ = result[1]; c_ = result[2]; d_ = result[3]; } }
public override EndCriteria.Type minimize(Problem P, EndCriteria endCriteria) { // set up of the problem //double ftol = endCriteria.functionEpsilon(); // end criteria on f(x) (see Numerical Recipes in C++, p.410) double xtol = endCriteria.rootEpsilon(); // end criteria on x (see GSL v. 1.9, http://www.gnu.org/software/gsl/) int maxStationaryStateIterations_ = endCriteria.maxStationaryStateIterations(); EndCriteria.Type ecType = EndCriteria.Type.None; P.reset(); Vector x_ = P.currentValue(); int iterationNumber_ = 0; // Initialize vertices of the simplex bool end = false; int n = x_.Count; vertices_ = new InitializedList<Vector>(n + 1, x_); for (int i = 0; i < n; i++) { Vector direction = new Vector(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_ = new Vector(n + 1, 0.0); for (int i = 0; i <= n; i++) values_[i] = P.value(vertices_[i]); // Loop looking for minimum do { sum_ = new Vector(n, 0.0); for (int i = 0; i <= n; i++) sum_ += vertices_[i]; // Determine the best (iLowest), worst (iHighest) // and 2nd worst (iNextHighest) vertices int iLowest = 0; int iHighest; int iNextHighest; if (values_[0] < values_[1]) { iHighest = 1; iNextHighest = 0; } else { iHighest = 0; iNextHighest = 1; } for (int 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) //double low = values_[iLowest]; //double high = values_[iHighest]; //double 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 double simplexSize = Utils.computeSimplexSize(vertices_); ++iterationNumber_; if (simplexSize < xtol || endCriteria.checkMaxIterations(iterationNumber_, ref ecType)) { endCriteria.checkStationaryPoint(0.0, 0.0, ref maxStationaryStateIterations_, ref ecType); endCriteria.checkMaxIterations(iterationNumber_, ref ecType); x_ = vertices_[iLowest]; double low = values_[iLowest]; P.setFunctionValue(low); P.setCurrentValue(x_); return ecType; } // If end criteria is not met, continue double factor = -1.0; double vTry = extrapolate(ref P, iHighest, ref factor); if ((vTry <= values_[iLowest]) && (factor == -1.0)) { factor = 2.0; extrapolate(ref P, iHighest, ref factor); } else if (Math.Abs(factor) > Const.QL_Epsilon) { if (vTry >= values_[iNextHighest]) { double vSave = values_[iHighest]; factor = 0.5; vTry = extrapolate(ref P, iHighest, ref factor); if (vTry >= vSave && Math.Abs(factor) > Const.QL_Epsilon) { for (int i = 0; i <= n; i++) { if (i != iLowest) { #if 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 (Math.Abs(factor) <= Const.QL_Epsilon) { x_ = vertices_[iLowest]; double low = values_[iLowest]; P.setFunctionValue(low); P.setCurrentValue(x_); return EndCriteria.Type.StationaryFunctionValue; } } while (end == false); throw new ApplicationException("optimization failed: unexpected behaviour"); }
//! minimize the optimization problem P public abstract EndCriteria.Type minimize(Problem P, EndCriteria endCriteria);
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); P.setCurrentValue(x_); // update problem current value 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); } ++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(); }
//! Perform line search public abstract double value(Problem P, ref EndCriteria.Type ecType, EndCriteria NamelessParameter3, double t_ini); // initial value of line-search step
//! solve the optimization problem P 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; // stationaryStateIterationNumber_=0 lineSearch_.searchDirection = new Vector(x_.Count); // dimension line search bool done = false; // function and squared norm of gradient values; double fnew; double fold; double gold2; double c; double fdiff; double normdiff; // 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.Count; Vector g = new Vector(sz); Vector d = new Vector(sz); Vector sddiff = new Vector(sz); // Initialize cost function, gradient g and search direction P.setFunctionValue(P.valueAndGradient(g, x_)); P.setGradientNormValue(Vector.DotProduct(g, g)); lineSearch_.searchDirection = g * -1.0; // Loop over iterations do { // Linesearch t = lineSearch_.value(P, ref ecType, endCriteria, t); // don't throw: it can fail just because maxIterations exceeded //QL_REQUIRE(lineSearch_->succeed(), "line-search failed!"); if (lineSearch_.succeed()) { // Updates d = lineSearch_.searchDirection; // New point x_ = lineSearch_.lastX(); // New function value fold = P.functionValue(); P.setFunctionValue(lineSearch_.lastFunctionValue()); // New gradient and search direction vectors g = lineSearch_.lastGradient(); // orthogonalization coef gold2 = P.gradientNormValue(); P.setGradientNormValue(lineSearch_.lastGradientNorm2()); c = P.gradientNormValue() / gold2; // conjugate gradient search direction sddiff = ((g * -1.0) + c * d) - lineSearch_.searchDirection; normdiff = Math.Sqrt(Vector.DotProduct(sddiff, sddiff)); lineSearch_.searchDirection = (g * -1.0) + c * d; // 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) + Double.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); } //done = endCriteria(iterationNumber_, // stationaryStateIterationNumber_, // true, //FIXME: it should be in the problem // fold, // std::sqrt(gold2), // P.functionValue(), // std::sqrt(P.gradientNormValue()), // ecType); P.setCurrentValue(x_); // update problem current value ++iterationNumber_; // Increase iteration number } else { done = true; } } while (!done); P.setCurrentValue(x_); return(ecType); }
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(); 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. 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); info_ = info; // check requirements & endCriteria evaluation if (info == 0) { throw new ApplicationException("MINPACK: improper input parameters"); } //if(info == 6) throw new ApplicationException("MINPACK: ftol is too small. no further " + // "reduction in the sum of squares is possible."); if (info != 6) { ecType = EndCriteria.Type.StationaryFunctionValue; } //QL_REQUIRE(info != 5, "MINPACK: number of calls to fcn has reached or exceeded maxfev."); endCriteria.checkMaxIterations(nfev, ref ecType); if (info == 7) { throw new ApplicationException("MINPACK: xtol is too small. no further " + "improvement in the approximate " + "solution x is possible."); } if (info == 8) { throw new ApplicationException("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); }
// Optimization function for hypersphere and lower-diagonal algorithm private static Matrix hypersphereOptimize(Matrix targetMatrix, Matrix currentRoot, bool lowerDiagonal) { int i, j, k, size = targetMatrix.rows(); Matrix result = new Matrix(currentRoot); Vector variance = new Vector(size); for (i = 0; i < size; i++) { variance[i] = Math.Sqrt(targetMatrix[i, i]); } if (lowerDiagonal) { Matrix approxMatrix = result * Matrix.transpose(result); result = MatrixUtilities.CholeskyDecomposition(approxMatrix, true); for (i = 0; i < size; i++) { for (j = 0; j < size; j++) { result[i, j] /= Math.Sqrt(approxMatrix[i, i]); } } } else { for (i = 0; i < size; i++) { for (j = 0; j < size; j++) { result[i, j] /= variance[i]; } } } ConjugateGradient optimize = new ConjugateGradient(); EndCriteria endCriteria = new EndCriteria(100, 10, 1e-8, 1e-8, 1e-8); HypersphereCostFunction costFunction = new HypersphereCostFunction(targetMatrix, variance, lowerDiagonal); NoConstraint constraint = new NoConstraint(); // hypersphere vector optimization if (lowerDiagonal) { Vector theta = new Vector(size * (size - 1) / 2); const double eps = 1e-16; for (i = 1; i < size; i++) { for (j = 0; j < i; j++) { theta[i * (i - 1) / 2 + j] = result[i, j]; if (theta[i * (i - 1) / 2 + j] > 1 - eps) { theta[i * (i - 1) / 2 + j] = 1 - eps; } if (theta[i * (i - 1) / 2 + j] < -1 + eps) { theta[i * (i - 1) / 2 + j] = -1 + eps; } for (k = 0; k < j; k++) { theta[i * (i - 1) / 2 + j] /= Math.Sin(theta[i * (i - 1) / 2 + k]); if (theta[i * (i - 1) / 2 + j] > 1 - eps) { theta[i * (i - 1) / 2 + j] = 1 - eps; } if (theta[i * (i - 1) / 2 + j] < -1 + eps) { theta[i * (i - 1) / 2 + j] = -1 + eps; } } theta[i * (i - 1) / 2 + j] = Math.Acos(theta[i * (i - 1) / 2 + j]); if (j == i - 1) { if (result[i, i] < 0) { theta[i * (i - 1) / 2 + j] = -theta[i * (i - 1) / 2 + j]; } } } } Problem p = new Problem(costFunction, constraint, theta); optimize.minimize(p, endCriteria); theta = p.currentValue(); result.fill(1); for (i = 0; i < size; i++) { for (k = 0; k < size; k++) { if (k > i) { result[i, k] = 0; } else { for (j = 0; j <= k; j++) { if (j == k && k != i) { result[i, k] *= Math.Cos(theta[i * (i - 1) / 2 + j]); } else if (j != i) { result[i, k] *= Math.Sin(theta[i * (i - 1) / 2 + j]); } } } } } } else { Vector theta = new Vector(size * (size - 1)); const double eps = 1e-16; for (i = 0; i < size; i++) { for (j = 0; j < size - 1; j++) { theta[j * size + i] = result[i, j]; if (theta[j * size + i] > 1 - eps) { theta[j * size + i] = 1 - eps; } if (theta[j * size + i] < -1 + eps) { theta[j * size + i] = -1 + eps; } for (k = 0; k < j; k++) { theta[j * size + i] /= Math.Sin(theta[k * size + i]); if (theta[j * size + i] > 1 - eps) { theta[j * size + i] = 1 - eps; } if (theta[j * size + i] < -1 + eps) { theta[j * size + i] = -1 + eps; } } theta[j * size + i] = Math.Acos(theta[j * size + i]); if (j == size - 2) { if (result[i, j + 1] < 0) { theta[j * size + i] = -theta[j * size + i]; } } } } Problem p = new Problem(costFunction, constraint, theta); optimize.minimize(p, endCriteria); theta = p.currentValue(); result.fill(1); for (i = 0; i < size; i++) { for (k = 0; k < size; k++) { for (j = 0; j <= k; j++) { if (j == k && k != size - 1) { result[i, k] *= Math.Cos(theta[j * size + i]); } else if (j != size - 1) { result[i, k] *= Math.Sin(theta[j * size + i]); } } } } } for (i = 0; i < size; i++) { for (j = 0; j < size; j++) { result[i, j] *= variance[i]; } } return(result); }
//! solve the optimization problem P 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; // stationaryStateIterationNumber_=0 lineSearch_.searchDirection = new Vector(x_.Count); // dimension line search bool done = false; // function and squared norm of gradient values; double fnew; double fold; double gold2; double c; double fdiff; double normdiff; // 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.Count; Vector g = new Vector(sz); Vector d = new Vector(sz); Vector sddiff = new Vector(sz); // Initialize cost function, gradient g and search direction P.setFunctionValue(P.valueAndGradient(g, x_)); P.setGradientNormValue(Vector.DotProduct(g, g)); lineSearch_.searchDirection = g * -1.0; // Loop over iterations do { // Linesearch t = lineSearch_.value(P, ref ecType, endCriteria, t); // don't throw: it can fail just because maxIterations exceeded //QL_REQUIRE(lineSearch_->succeed(), "line-search failed!"); if (lineSearch_.succeed()) { // Updates d = lineSearch_.searchDirection; // New point x_ = lineSearch_.lastX(); // New function value fold = P.functionValue(); P.setFunctionValue(lineSearch_.lastFunctionValue()); // New gradient and search direction vectors g = lineSearch_.lastGradient(); // orthogonalization coef gold2 = P.gradientNormValue(); P.setGradientNormValue(lineSearch_.lastGradientNorm2()); c = P.gradientNormValue() / gold2; // conjugate gradient search direction sddiff = ((g*-1.0) + c * d) - lineSearch_.searchDirection; normdiff = Math.Sqrt(Vector.DotProduct(sddiff, sddiff)); lineSearch_.searchDirection = (g*-1.0) + c * d; // 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) + Double.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; } //done = endCriteria(iterationNumber_, // stationaryStateIterationNumber_, // true, //FIXME: it should be in the problem // fold, // std::sqrt(gold2), // P.functionValue(), // std::sqrt(P.gradientNormValue()), // ecType); P.setCurrentValue(x_); // update problem current value ++iterationNumber_; // Increase iteration number } else { done =true; } } while (!done); P.setCurrentValue(x_); return ecType; }
public void calculate() { validCurve_ = false; int nInsts = ts_.instruments_.Count, i; // ensure rate helpers are sorted ts_.instruments_.Sort((x, y) => x.latestDate().CompareTo(y.latestDate())); // check that there is no instruments with the same maturity for (i = 1; i < nInsts; ++i) { Date m1 = ts_.instruments_[i - 1].latestDate(), m2 = ts_.instruments_[i].latestDate(); if (m1 == m2) { throw new ArgumentException("two instruments have the same maturity (" + m1 + ")"); } } // check that there is no instruments with invalid quote if ((i = ts_.instruments_.FindIndex(x => !x.quoteIsValid())) != -1) { throw new ArgumentException("instrument " + i + " (maturity: " + ts_.instruments_[i].latestDate() + ") has an invalid quote"); } // setup instruments and register with them ts_.instruments_.ForEach(j => ts_.setTermStructure(j)); // set initial guess only if the current curve cannot be used as guess if (validCurve_) { if (ts_.data_.Count != nInsts + 1) { throw new ArgumentException("dimension mismatch: expected " + nInsts + 1 + ", actual " + ts_.data_.Count); } } else { ts_.data_ = new InitializedList <double>(nInsts + 1); ts_.data_[0] = ts_.initialValue(); } // calculate dates and times ts_.dates_ = new InitializedList <Date>(nInsts + 1); ts_.times_ = new InitializedList <double>(nInsts + 1); ts_.dates_[0] = ts_.initialDate(); ts_.times_[0] = ts_.timeFromReference(ts_.dates_[0]); for (i = 0; i < nInsts; ++i) { ts_.dates_[i + 1] = ts_.instruments_[i].latestDate(); ts_.times_[i + 1] = ts_.timeFromReference(ts_.dates_[i + 1]); if (!validCurve_) { ts_.data_[i + 1] = ts_.data_[i]; } } LevenbergMarquardt solver = new LevenbergMarquardt(ts_.accuracy_, ts_.accuracy_, ts_.accuracy_); EndCriteria endCriteria = new EndCriteria(100, 10, 0.00, ts_.accuracy_, 0.00); PositiveConstraint posConstraint = new PositiveConstraint(); NoConstraint noConstraint = new NoConstraint(); Constraint solverConstraint = forcePositive_ ? (Constraint)posConstraint : (Constraint)noConstraint; // now start the bootstrapping. int iInst = localisation_ - 1; int dataAdjust = (ts_.interpolator_ as ConvexMonotone).dataSizeAdjustment; do { int initialDataPt = iInst + 1 - localisation_ + dataAdjust; Vector startArray = new Vector(localisation_ + 1 - dataAdjust); for (int j = 0; j < startArray.size() - 1; ++j) { startArray[j] = ts_.data_[initialDataPt + j]; } // here we are extending the interpolation a point at a // time... but the local interpolator can make an // approximation for the final localisation period. // e.g. if the localisation is 2, then the first section // of the curve will be solved using the first 2 // instruments... with the local interpolator making // suitable boundary conditions. ts_.interpolation_ = (ts_.interpolator_ as ConvexMonotone).localInterpolate(ts_.times_, iInst + 2, ts_.data_, localisation_, ts_.interpolation_ as ConvexMonotoneInterpolation, nInsts + 1); if (iInst >= localisation_) { startArray[localisation_ - dataAdjust] = ts_.guess(iInst, ts_, false, 0); } else { startArray[localisation_ - dataAdjust] = ts_.data_[0]; } var currentCost = new PenaltyFunction <T, U>(ts_, initialDataPt, ts_.instruments_, iInst - localisation_ + 1, iInst + 1); Problem toSolve = new Problem(currentCost, solverConstraint, startArray); EndCriteria.Type endType = solver.minimize(toSolve, endCriteria); // check the end criteria if (!(endType == EndCriteria.Type.StationaryFunctionAccuracy || endType == EndCriteria.Type.StationaryFunctionValue)) { throw new ApplicationException("Unable to strip yieldcurve to required accuracy "); } ++iInst; } while (iInst < nInsts); validCurve_ = true; }
private double extrapolate(ref Problem P, int iHighest, ref double factor) { Vector pTry; do { int dimensions = values_.Count - 1; double factor1 = (1.0 - factor) / dimensions; double factor2 = factor1 - factor; // #if QL_ARRAY_EXPRESSIONS pTry = sum_ * factor1 - vertices_[iHighest] * factor2; //#else // // composite expressions fail to compile with gcc 3.4 on windows // pTry = sum_ * factor1; // pTry -= vertices_[iHighest] * factor2; //#endif factor *= 0.5; } while (!P.constraint().test(pTry) && Math.Abs(factor) > Const.QL_Epsilon); if (Math.Abs(factor) <= Const.QL_Epsilon) { return values_[iHighest]; } factor *= 2.0; double vTry = P.value(pTry); if (vTry < values_[iHighest]) { values_[iHighest] = vTry; //#if QL_ARRAY_EXPRESSIONS sum_ += pTry - vertices_[iHighest]; //#else // sum_ += pTry; // sum_ -= vertices_[iHighest]; //#endif vertices_[iHighest] = pTry; } return vTry; }
public override void update() { coeff_.updateModelInstance(); // we should also check that y contains positive values only // we must update weights if it is vegaWeighted if (vegaWeighted_) { coeff_.weights_.Clear(); double weightsSum = 0.0; for (int i = 0; i < xBegin_.Count; i++) { double stdDev = Math.Sqrt((yBegin_[i]) * (yBegin_[i]) * coeff_.t_); coeff_.weights_.Add(coeff_.model_.weight(xBegin_[i], forward_, stdDev, coeff_.addParams_)); weightsSum += coeff_.weights_.Last(); } // weight normalization for (int i = 0; i < coeff_.weights_.Count; i++) { coeff_.weights_[i] /= weightsSum; } } // there is nothing to optimize if (coeff_.paramIsFixed_.Aggregate((a, b) => b && a)) { coeff_.error_ = interpolationError(); coeff_.maxError_ = interpolationMaxError(); coeff_.XABREndCriteria_ = EndCriteria.Type.None; return; } XABRError costFunction = new XABRError(this); Vector guess = new Vector(coeff_.model_.dimension()); for (int i = 0; i < guess.size(); ++i) { guess[i] = coeff_.params_[i].GetValueOrDefault(); } int iterations = 0; int freeParameters = 0; double bestError = double.MaxValue; Vector bestParameters = new Vector(); for (int i = 0; i < coeff_.model_.dimension(); ++i) { if (!coeff_.paramIsFixed_[i]) { ++freeParameters; } } HaltonRsg halton = new HaltonRsg(freeParameters, 42); EndCriteria.Type tmpEndCriteria; double tmpInterpolationError; do { if (iterations > 0) { Sample <List <double> > s = halton.nextSequence(); coeff_.model_.guess(guess, coeff_.paramIsFixed_, forward_, coeff_.t_, s.value, coeff_.addParams_); for (int i = 0; i < coeff_.paramIsFixed_.Count; ++i) { if (coeff_.paramIsFixed_[i]) { guess[i] = coeff_.params_[i].GetValueOrDefault(); } } } Vector inversedTransformatedGuess = new Vector(coeff_.model_.inverse(guess, coeff_.paramIsFixed_, coeff_.params_, forward_)); ProjectedCostFunction rainedXABRError = new ProjectedCostFunction(costFunction, inversedTransformatedGuess, coeff_.paramIsFixed_); Vector projectedGuess = new Vector(rainedXABRError.project(inversedTransformatedGuess)); constraint_.config(rainedXABRError, coeff_, forward_); Problem problem = new Problem(rainedXABRError, constraint_, projectedGuess); tmpEndCriteria = optMethod_.minimize(problem, endCriteria_); Vector projectedResult = new Vector(problem.currentValue()); Vector transfResult = new Vector(rainedXABRError.include(projectedResult)); Vector result = coeff_.model_.direct(transfResult, coeff_.paramIsFixed_, coeff_.params_, forward_); tmpInterpolationError = useMaxError_ ? interpolationMaxError() : interpolationError(); if (tmpInterpolationError < bestError) { bestError = tmpInterpolationError; bestParameters = result; coeff_.XABREndCriteria_ = tmpEndCriteria; } }while (++iterations < maxGuesses_ && tmpInterpolationError > errorAccept_); for (int i = 0; i < bestParameters.size(); ++i) { coeff_.params_[i] = bestParameters[i]; } coeff_.error_ = interpolationError(); coeff_.maxError_ = interpolationMaxError(); }
public override Vector values(Vector x) { // dummy nested optimization Vector coefficients = new Vector(3, 1.0); OneDimensionalPolynomialDegreeN oneDimensionalPolynomialDegreeN = new OneDimensionalPolynomialDegreeN(coefficients); NoConstraint constraint = new NoConstraint(); Vector initialValues = new Vector(1, 100.0); Problem problem = new Problem(oneDimensionalPolynomialDegreeN, constraint, initialValues); LevenbergMarquardt optimizationMethod = new LevenbergMarquardt(); //Simplex optimizationMethod(0.1); //ConjugateGradient optimizationMethod; //SteepestDescent optimizationMethod; EndCriteria endCriteria = new EndCriteria(1000, 100, 1e-5, 1e-5, 1e-5); optimizationMethod.minimize(problem, endCriteria); // return dummy result Vector dummy = new Vector(1,0); return dummy; }
//! Perform line search public abstract double value(Problem P, ref EndCriteria.Type ecType, EndCriteria NamelessParameter3, double t_ini);
public void OptimizersTest() { //("Testing optimizers..."); setup(); // Loop over problems (currently there is only 1 problem) for (int i=0; i<costFunctions_.Count; ++i) { Problem problem = new Problem(costFunctions_[i], constraints_[i], initialValues_[i]); Vector initialValues = problem.currentValue(); // Loop over optimizers for (int j = 0; j < (optimizationMethods_[i]).Count; ++j) { double rootEpsilon = endCriterias_[i].rootEpsilon(); int endCriteriaTests = 1; // Loop over rootEpsilon for(int k=0; k<endCriteriaTests; ++k) { problem.setCurrentValue(initialValues); EndCriteria endCriteria = new EndCriteria(endCriterias_[i].maxIterations(), endCriterias_[i].maxStationaryStateIterations(), rootEpsilon, endCriterias_[i].functionEpsilon(), endCriterias_[i].gradientNormEpsilon()); rootEpsilon *= .1; EndCriteria.Type endCriteriaResult = optimizationMethods_[i][j].optimizationMethod.minimize(problem, endCriteria); Vector xMinCalculated = problem.currentValue(); Vector yMinCalculated = problem.values(xMinCalculated); // Check optimization results vs known solution if (endCriteriaResult==EndCriteria.Type.None || endCriteriaResult==EndCriteria.Type.MaxIterations || endCriteriaResult==EndCriteria.Type.Unknown) Assert.Fail("function evaluations: " + problem.functionEvaluation() + " gradient evaluations: " + problem.gradientEvaluation() + " x expected: " + xMinExpected_[i] + " x calculated: " + xMinCalculated + " x difference: " + (xMinExpected_[i]- xMinCalculated) + " rootEpsilon: " + endCriteria.rootEpsilon() + " y expected: " + yMinExpected_[i] + " y calculated: " + yMinCalculated + " y difference: " + (yMinExpected_[i]- yMinCalculated) + " functionEpsilon: " + endCriteria.functionEpsilon() + " endCriteriaResult: " + endCriteriaResult); } } } }
//! Solve least square problem using numerix solver public Vector perform(ref LeastSquareProblem lsProblem) { double eps = accuracy_; // wrap the least square problem in an optimization function LeastSquareFunction lsf = new LeastSquareFunction(lsProblem); // define optimization problem Problem P = new Problem(lsf, c_, initialValue_); // minimize EndCriteria ec = new EndCriteria(maxIterations_, Math.Min((int)(maxIterations_ / 2), (int)(100)), eps, eps, eps); exitFlag_ = (int)om_.minimize(P, ec); // summarize results of minimization // nbIterations_ = om_->iterationNumber(); results_ = P.currentValue(); resnorm_ = P.functionValue(); bestAccuracy_ = P.functionValue(); return results_; }
//! Calibrate to a set of market instruments (caps/swaptions) /*! An additional constraint can be passed which must be satisfied in addition to the constraints of the model. */ //public void calibrate(List<CalibrationHelper> instruments, OptimizationMethod method, EndCriteria endCriteria, // Constraint constraint = new Constraint(), List<double> weights = new List<double>()) { public void calibrate(List<CalibrationHelper> instruments, OptimizationMethod method, EndCriteria endCriteria, Constraint additionalConstraint, List<double> weights) { if (!(weights.Count == 0 || weights.Count == instruments.Count)) throw new ApplicationException("mismatch between number of instruments and weights"); Constraint c; if (additionalConstraint.empty()) c = constraint_; else c = new CompositeConstraint(constraint_,additionalConstraint); List<double> w = weights.Count == 0 ? new InitializedList<double>(instruments.Count, 1.0): weights; CalibrationFunction f = new CalibrationFunction(this, instruments, w); Problem prob = new Problem(f, c, parameters()); shortRateEndCriteria_ = method.minimize(prob, endCriteria); Vector result = new Vector(prob.currentValue()); setParams(result); // recheck Vector shortRateProblemValues_ = prob.values(result); notifyObservers(); }
public override EndCriteria.Type minimize(Problem P, EndCriteria endCriteria) { // set up of the problem //double ftol = endCriteria.functionEpsilon(); // end criteria on f(x) (see Numerical Recipes in C++, p.410) double xtol = endCriteria.rootEpsilon(); // end criteria on x (see GSL v. 1.9, http://www.gnu.org/software/gsl/) int maxStationaryStateIterations_ = endCriteria.maxStationaryStateIterations(); EndCriteria.Type ecType = EndCriteria.Type.None; P.reset(); Vector x_ = P.currentValue(); int iterationNumber_ = 0; // Initialize vertices of the simplex bool end = false; int n = x_.Count; vertices_ = new InitializedList <Vector>(n + 1, x_); for (int i = 0; i < n; i++) { Vector direction = new Vector(n, 0.0); Vector vertice = vertices_[i + 1]; direction[i] = 1.0; P.constraint().update(ref vertice, direction, lambda_); vertices_[i + 1] = vertice; } // Initialize function values at the vertices of the simplex values_ = new Vector(n + 1, 0.0); for (int i = 0; i <= n; i++) { values_[i] = P.value(vertices_[i]); } // Loop looking for minimum do { sum_ = new Vector(n, 0.0); for (int i = 0; i <= n; i++) { sum_ += vertices_[i]; } // Determine the best (iLowest), worst (iHighest) // and 2nd worst (iNextHighest) vertices int iLowest = 0; int iHighest; int iNextHighest; if (values_[0] < values_[1]) { iHighest = 1; iNextHighest = 0; } else { iHighest = 0; iNextHighest = 1; } for (int 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) //double low = values_[iLowest]; //double high = values_[iHighest]; //double 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 double simplexSize = Utils.computeSimplexSize(vertices_); ++iterationNumber_; if (simplexSize < xtol || endCriteria.checkMaxIterations(iterationNumber_, ref ecType)) { endCriteria.checkStationaryPoint(0.0, 0.0, ref maxStationaryStateIterations_, ref ecType); endCriteria.checkMaxIterations(iterationNumber_, ref ecType); x_ = vertices_[iLowest]; double low = values_[iLowest]; P.setFunctionValue(low); P.setCurrentValue(x_); return(ecType); } // If end criteria is not met, continue double factor = -1.0; double vTry = extrapolate(ref P, iHighest, ref factor); if ((vTry <= values_[iLowest]) && (factor == -1.0)) { factor = 2.0; extrapolate(ref P, iHighest, ref factor); } else if (Math.Abs(factor) > Const.QL_EPSILON) { if (vTry >= values_[iNextHighest]) { double vSave = values_[iHighest]; factor = 0.5; vTry = extrapolate(ref P, iHighest, ref factor); if (vTry >= vSave && Math.Abs(factor) > Const.QL_EPSILON) { for (int i = 0; i <= n; i++) { if (i != iLowest) { #if 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 (Math.Abs(factor) <= Const.QL_EPSILON) { x_ = vertices_[iLowest]; double low = values_[iLowest]; P.setFunctionValue(low); P.setCurrentValue(x_); return(EndCriteria.Type.StationaryFunctionValue); } } while (end == false); throw new ApplicationException("optimization failed: unexpected behaviour"); }