double minimize() { double ICM = Double.PositiveInfinity; double minPenalty = Double.PositiveInfinity; double minValue = Double.PositiveInfinity; double penalty; double currentValue; bool minFeasible = false; int noProgressCounter = 0; int maxCount = 20; iterations = 0; // magic parameters from Birgin & Martinez const double tau = 0.5, gam = 10; const double lam_min = -1e20; const double lam_max = 1e20; const double mu_max = 1e20; const double nu_max = 1e20; double[] currentSolution = (double[])Solution.Clone(); lambda = new double[equalityConstraints.Length]; mu = new double[lesserThanConstraints.Length]; nu = new double[greaterThanConstraints.Length]; rho = 1; // Starting rho suggested by B & M if (lambda.Length > 0 || mu.Length > 0 || nu.Length > 0) { double con2 = 0; penalty = 0; // Evaluate function functionEvaluations++; currentValue = dualSolver.Function(currentSolution); bool feasible = true; // For each equality constraint for (int i = 0; i < equalityConstraints.Length; i++) { double c = equalityConstraints[i].Function(currentSolution) - equalityConstraints[i].Value; penalty += Math.Abs(c); feasible = feasible && Math.Abs(c) <= equalityConstraints[i].Tolerance; con2 += c * c; } // For each "lesser than" inequality constraint for (int i = 0; i < lesserThanConstraints.Length; ++i) { double c = lesserThanConstraints[i].Function(currentSolution) - lesserThanConstraints[i].Value; penalty += c > 0 ? c : 0; feasible = feasible && c <= lesserThanConstraints[i].Tolerance; if (c > 0) { con2 += c * c; } } // For each "greater than" inequality constraint for (int i = 0; i < greaterThanConstraints.Length; ++i) { double c = -greaterThanConstraints[i].Function(currentSolution) + greaterThanConstraints[i].Value; penalty += c > 0 ? c : 0; feasible = feasible && c <= greaterThanConstraints[i].Tolerance; if (c > 0) { con2 += c * c; } } minValue = currentValue; minPenalty = penalty; minFeasible = feasible; double num = 2.0 * Math.Abs(minValue); if (num < 1e-300) { rho = rhoMin; } else if (con2 < 1e-300) { rho = rhoMax; } else { rho = num / con2; if (rho < rhoMin) { rho = rhoMin; } else if (rho > rhoMax) { rho = rhoMax; } } System.Diagnostics.Debug.Assert(!Double.IsNaN(rho)); } while (true) { double prevICM = ICM; try { // Minimize the dual problem using current solution currentValue = dualSolver.Minimize(currentSolution); } catch (LineSearchFailedException) { } catch (NotFiniteNumberException) { } // Retrieve the solution found currentSolution = dualSolver.Solution; // Evaluate function functionEvaluations++; currentValue = dualSolver.Function(currentSolution); ICM = 0; penalty = 0; bool feasible = true; // Update lambdas for (int i = 0; i < equalityConstraints.Length; i++) { double c = equalityConstraints[i].Function(currentSolution) - equalityConstraints[i].Value; double newLambda = lambda[i] + rho * c; penalty += Math.Abs(c); feasible = feasible && Math.Abs(c) <= equalityConstraints[i].Tolerance; ICM = Math.Max(ICM, Math.Abs(c)); lambda[i] = Math.Min(Math.Max(lam_min, newLambda), lam_max); } // Update mus for (int i = 0; i < lesserThanConstraints.Length; i++) { double c = lesserThanConstraints[i].Function(currentSolution) - lesserThanConstraints[i].Value; double newMu = mu[i] + rho * c; penalty += c > 0 ? c : 0; feasible = feasible && c <= lesserThanConstraints[i].Tolerance; ICM = Math.Max(ICM, Math.Abs(Math.Max(c, -mu[i] / rho))); mu[i] = Math.Min(Math.Max(0.0, newMu), mu_max); } // Update nus for (int i = 0; i < greaterThanConstraints.Length; i++) { double c = -greaterThanConstraints[i].Function(currentSolution) + greaterThanConstraints[i].Value; double newNu = nu[i] + rho * c; penalty += c > 0 ? c : 0; feasible = feasible && c <= greaterThanConstraints[i].Tolerance; ICM = Math.Max(ICM, Math.Abs(Math.Max(c, -nu[i] / rho))); nu[i] = Math.Min(Math.Max(0.0, newNu), nu_max); } // Update rho if (ICM > tau * prevICM) { rho *= gam; } // Check if we should stop if ( (feasible && (!minFeasible || penalty < minPenalty || currentValue < minValue) ) || (!minFeasible && penalty < minPenalty) ) { if (feasible) { if (relstop(minValue, currentValue, ftol_rel, ftol_abs)) { return(minValue); } bool xtolreach = true; for (int i = 0; i < currentSolution.Length; i++) { if (!relstop(Solution[i], currentSolution[i], xtol_rel, 0)) { xtolreach = false; } } if (xtolreach) { return(minValue); } } minValue = currentValue; minPenalty = penalty; minFeasible = feasible; // Save the current solution for (int i = 0; i < Solution.Length; i++) { Solution[i] = currentSolution[i]; } noProgressCounter = 0; } else { if (ICM == 0) { return(minValue); } noProgressCounter++; if (noProgressCounter > maxCount) { return(minValue); } } // Go to next iteration iterations++; if (maxEvaluations > 0 && functionEvaluations >= maxEvaluations) { return(minValue); } } }
private AugmentedLagrangianStatus optimize() { double ICM = Double.PositiveInfinity; double minPenalty = Double.PositiveInfinity; double minValue = Double.PositiveInfinity; double penalty; double currentValue; bool minFeasible = false; int noProgressCounter = 0; int maxCount = 100; iterations = 0; // magic parameters from Birgin & Martinez const double tau = 0.5, gam = 10; const double lam_min = -1e20; const double lam_max = 1e20; const double mu_max = 1e20; const double nu_max = 1e20; double[] currentSolution = Solution.Copy(); Array.Clear(lambda, 0, lambda.Length); Array.Clear(mu, 0, mu.Length); Array.Clear(nu, 0, nu.Length); rho = 1; // Starting rho suggested by B & M if (lambda.Length > 0 || mu.Length > 0 || nu.Length > 0) { double con2 = 0; penalty = 0; // Evaluate function functionEvaluations++; currentValue = dualSolver.Function(currentSolution); bool feasible = true; // For each equality constraint for (int i = 0; i < equalityConstraints.Length; i++) { double actual = equalityConstraints[i].Function(currentSolution); double c = actual - equalityConstraints[i].Value; penalty += Math.Abs(c); con2 += c * c; feasible = feasible && Math.Abs(c) <= equalityConstraints[i].Tolerance; } // For each "lesser than" inequality constraint for (int i = 0; i < lesserThanConstraints.Length; i++) { double actual = lesserThanConstraints[i].Function(currentSolution); double c = actual - lesserThanConstraints[i].Value; if (c > 0) { penalty += c; con2 += c * c; } feasible = feasible && c <= lesserThanConstraints[i].Tolerance; } // For each "greater than" inequality constraint for (int i = 0; i < greaterThanConstraints.Length; i++) { double actual = greaterThanConstraints[i].Function(currentSolution); double c = greaterThanConstraints[i].Value - actual; if (c > 0) { penalty += c; con2 += c * c; } feasible = feasible && c <= greaterThanConstraints[i].Tolerance; } minValue = currentValue; minPenalty = penalty; minFeasible = feasible; double num = 2.0 * Math.Abs(minValue); if (num < 1e-300) { rho = rhoMin; } else if (con2 < 1e-300) { rho = rhoMax; } else { rho = num / con2; if (rho < rhoMin) { rho = rhoMin; } else if (rho > rhoMax) { rho = rhoMax; } } Accord.Diagnostics.Debug.Assert(!Double.IsNaN(rho)); } while (true) { if (Token.IsCancellationRequested) { return(AugmentedLagrangianStatus.Cancelled); } double prevICM = ICM; // Minimize the dual problem using current solution for (int i = 0; i < dualSolver.Solution.Length; i++) { dualSolver.Solution[i] = currentSolution[i]; } dualSolver.Minimize(); // Retrieve the solution found for (int i = 0; i < currentSolution.Length; i++) { if (!Double.IsNaN(dualSolver.Solution[i])) { currentSolution[i] = dualSolver.Solution[i]; } } // Evaluate function functionEvaluations++; currentValue = dualSolver.Function(currentSolution); ICM = 0; penalty = 0; bool feasible = true; // Update lambdas for (int i = 0; i < equalityConstraints.Length; i++) { double actual = equalityConstraints[i].Function(currentSolution); double c = actual - equalityConstraints[i].Value; double newLambda = lambda[i] + rho * c; penalty += Math.Abs(c); feasible = feasible && Math.Abs(c) <= equalityConstraints[i].Tolerance; ICM = Math.Max(ICM, Math.Abs(c)); lambda[i] = Math.Min(Math.Max(lam_min, newLambda), lam_max); } // Update mus for (int i = 0; i < lesserThanConstraints.Length; i++) { double actual = lesserThanConstraints[i].Function(currentSolution); double c = actual - lesserThanConstraints[i].Value; double newMu = mu[i] + rho * c; penalty += c > 0 ? c : 0; feasible = feasible && c <= lesserThanConstraints[i].Tolerance; ICM = Math.Max(ICM, Math.Abs(Math.Max(c, -mu[i] / rho))); mu[i] = Math.Min(Math.Max(0.0, newMu), mu_max); } // Update nus for (int i = 0; i < greaterThanConstraints.Length; i++) { double actual = greaterThanConstraints[i].Function(currentSolution); double c = greaterThanConstraints[i].Value - actual; double newNu = nu[i] + rho * c; penalty += c > 0 ? c : 0; feasible = feasible && c <= greaterThanConstraints[i].Tolerance; ICM = Math.Max(ICM, Math.Abs(Math.Max(c, -nu[i] / rho))); nu[i] = Math.Min(Math.Max(0.0, newNu), nu_max); } // Update rho if (ICM > tau * prevICM) { rho *= gam; } // Check if we should stop bool a = !minFeasible || penalty < minPenalty || currentValue < minValue; bool b = !minFeasible && penalty < minPenalty; if ((feasible && a) || b) { AugmentedLagrangianStatus?r = null; if (feasible) { if (relstop(minValue, currentValue, ftol_rel, ftol_abs)) { r = AugmentedLagrangianStatus.Converged; } if (xtolreach(currentSolution, xtol_rel, 0)) { r = AugmentedLagrangianStatus.Converged; } } minValue = currentValue; minPenalty = penalty; minFeasible = feasible; // Save the current solution for (int i = 0; i < Solution.Length; i++) { Solution[i] = currentSolution[i]; } if (r.HasValue) { return(r.Value); } noProgressCounter = 0; } else { if (ICM == 0) { return(AugmentedLagrangianStatus.Converged); } noProgressCounter++; if (noProgressCounter > maxCount) { return(AugmentedLagrangianStatus.NoProgress); } } // Go to next iteration iterations++; if (maxEvaluations > 0 && functionEvaluations >= maxEvaluations) { return(AugmentedLagrangianStatus.MaxEvaluations); } } }