From 39c1c0c58f8d8db6154b5ee7fe00a40e691292f0 Mon Sep 17 00:00:00 2001 From: Aurya Javeed Date: Tue, 28 Jul 2026 20:10:55 -0600 Subject: [PATCH 1/4] AL2 improvements --- ...ypeG_AugmentedLagrangianAlgorithm2_Def.hpp | 20 ++++++------------- .../ROL_AugmentedLagrangianObjective2.hpp | 4 ++-- .../ROL_AugmentedLagrangianPenalty.hpp | 5 ++++- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2_Def.hpp b/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2_Def.hpp index 783d83ae..f947e2e6 100644 --- a/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2_Def.hpp +++ b/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2_Def.hpp @@ -370,10 +370,9 @@ void AugmentedLagrangianAlgorithm2::run( Problem &problem, EExitStatus statusFlag; bool isSubproblemConverged = false; - Real penaltyParameter; bool isForcedUpdate = false; - - Real theta; + const Real oem2(1e-2); + Real penaltyParameter, reduction, theta; // ======================================================================== // STEP 3: Run algorithm @@ -460,21 +459,14 @@ void AugmentedLagrangianAlgorithm2::run( Problem &problem, else { theta = std::min(one/penaltyParameter,theta_); dualTolerances[i] *= std::pow(theta,betat_); - // dualTolerances[i] = std::max(dualTolerances[i],oem2*outerFeasTolerance_); // ROL convention } if (alobj->getScaling(i)*dualResiduals[i] <= nu*std::pow(penaltyParameter,gamma)) { - alobj->updateMultiplier(x,tol,i); - // outStream << "multiplier update" << std::endl; + state_->snorm += alobj->updateMultiplier(x,tol,i); } } - if (isUpdated_) { - epsilon_ = 0.9*epsilon_; - delta_ = 0.9*delta_; - } - else { - epsilon_ = 0.25*epsilon_; - delta_ = 0.25*delta_; - } + reduction = isUpdated_ ? Real(0.9) : Real(0.25); + epsilon_ = std::max(oem2*outerOptTolerance_, reduction*epsilon_); + delta_ = std::max(oem2*outerFeasTolerance_,reduction*delta_); alobj->reset(); diff --git a/src/algorithm/TypeG/augmentedlagrangian/ROL_AugmentedLagrangianObjective2.hpp b/src/algorithm/TypeG/augmentedlagrangian/ROL_AugmentedLagrangianObjective2.hpp index 2afc32db..39a86d89 100644 --- a/src/algorithm/TypeG/augmentedlagrangian/ROL_AugmentedLagrangianObjective2.hpp +++ b/src/algorithm/TypeG/augmentedlagrangian/ROL_AugmentedLagrangianObjective2.hpp @@ -146,8 +146,8 @@ class AugmentedLagrangianObjective2 : public Objective { pvec_[k]->setMultiplier(multiplier); } - void updateMultiplier( const Vector &x, Real &tol, const int k ) { - pvec_[k]->updateMultiplier(x,tol); + Real updateMultiplier( const Vector &x, Real &tol, const int k ) { + return pvec_[k]->updateMultiplier(x,tol); } // Return objective function value diff --git a/src/algorithm/TypeG/augmentedlagrangian/ROL_AugmentedLagrangianPenalty.hpp b/src/algorithm/TypeG/augmentedlagrangian/ROL_AugmentedLagrangianPenalty.hpp index c50b610b..d821edab 100644 --- a/src/algorithm/TypeG/augmentedlagrangian/ROL_AugmentedLagrangianPenalty.hpp +++ b/src/algorithm/TypeG/augmentedlagrangian/ROL_AugmentedLagrangianPenalty.hpp @@ -173,8 +173,11 @@ class AugmentedLagrangianPenalty : public Objective { multiplier_->set(multiplier); } - void updateMultiplier( const Vector &x, Real &tol ) { + Real updateMultiplier( const Vector &x, Real &tol ) { + multiplier_->axpy(Real(-1),*getDualVec(x,tol)); + Real multiplierUpdateNorm = multiplier_->norm(); multiplier_->set(*getDualVec(x,tol)); + return multiplierUpdateNorm; } // Return constraint value From e549b1c0dc95241ff76b2dd8427eedceb4c82128 Mon Sep 17 00:00:00 2001 From: Aurya Javeed Date: Wed, 29 Jul 2026 23:03:32 -0600 Subject: [PATCH 2/4] Subproblem tolerance lower bound --- ...OL_TypeG_AugmentedLagrangianAlgorithm2.hpp | 2 +- ...ypeG_AugmentedLagrangianAlgorithm2_Def.hpp | 31 ++++++++++--------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2.hpp b/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2.hpp index 1dbf61ac..89cdb4e1 100644 --- a/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2.hpp +++ b/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2.hpp @@ -41,6 +41,7 @@ class AugmentedLagrangianAlgorithm2 : public TypeG::Algorithm { bool useDefaultInitTol_; Real delta_; Real epsilon_; + Real subproblemTolFactor_; int maxit_; std::string subStep_; // Optimality tolerance update @@ -50,7 +51,6 @@ class AugmentedLagrangianAlgorithm2 : public TypeG::Algorithm { int verbosity_; bool printHeader_; // Outer tolerances - Real outerOptTolerance_; Real outerFeasTolerance_; Real outerStepTolerance_; diff --git a/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2_Def.hpp b/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2_Def.hpp index f947e2e6..bad95dfc 100644 --- a/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2_Def.hpp +++ b/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2_Def.hpp @@ -52,12 +52,13 @@ AugmentedLagrangianAlgorithm2::AugmentedLagrangianAlgorithm2( ParameterLis tau0_ = sublist.get("Initial Dual Feasibility Tolerance", one); // Subproblem information - useDefaultInitTol_ = sublist.get("Use Default Initial Subproblem Tolerances", false); - epsilon_ = sublist.get("Initial Optimality Tolerance", 1e-4); - delta_ = sublist.get("Initial Feasibility Tolerance", 1e-4); - maxit_ = sublist.get("Subproblem Iteration Limit", 1000); - bool print = sublist.get("Print Intermediate Optimization History", false); - subStep_ = sublist.get("Subproblem Step Type", "Trust Region"); + useDefaultInitTol_ = sublist.get("Use Default Initial Subproblem Tolerances", false); + epsilon_ = sublist.get("Initial Optimality Tolerance", 1e-4); + delta_ = sublist.get("Initial Feasibility Tolerance", 1e-4); + subproblemTolFactor_ = sublist.get("Subproblem Tolerance Lower Bound Factor", 1e-2); + maxit_ = sublist.get("Subproblem Iteration Limit", 1000); + bool print = sublist.get("Print Intermediate Optimization History", false); + subStep_ = sublist.get("Subproblem Step Type", "Trust Region"); list_.sublist("Step").set("Type",subStep_); list_.sublist("Status Test").set("Iteration Limit", maxit_); list_.sublist("Status Test").set("Use Relative Tolerances",false); @@ -99,8 +100,13 @@ void AugmentedLagrangianAlgorithm2::initialize( Vector outStream << "Warning: \"Use Relative Tolerances\" parameter is unsupported!" << std::endl; useRelTol_ = false; } + if (subproblemTolFactor_ >= Real(1)) { + outStream << "Warning: \"Subproblem Tolerance Lower Bound Factor\" is greater than or equal to 1! " + << "The lower bounds will not be tighter than the corresponding outer tolerances." + << std::endl; + } - const Real one(1), TOL(1.e-2); + const Real one(1); Real tol = std::sqrt(ROL_EPSILON()); // > TypeG::Algorithm::initialize(x,g,l,c); if (state_->iterateVec == nullPtr) { @@ -246,8 +252,8 @@ void AugmentedLagrangianAlgorithm2::initialize( Vector for (unsigned i = 0; i < numberPenalties; ++i) temp += alobj.getPenaltyParameter(i); temp = std::min(minPenaltyReciprocal_,1./temp); - epsilon_ = std::max(TOL*outerOptTolerance_, epsilon_*std::pow(temp,optDecreaseExponent_)); - delta_ = std::max(TOL*outerFeasTolerance_,delta_ *std::pow(temp,optDecreaseExponent_)); + epsilon_ = std::max(subproblemTolFactor_*outerOptTolerance_, epsilon_*std::pow(temp,optDecreaseExponent_)); + delta_ = std::max(subproblemTolFactor_*outerFeasTolerance_, delta_*std::pow(temp,optDecreaseExponent_)); } alobj.reset(); @@ -371,7 +377,6 @@ void AugmentedLagrangianAlgorithm2::run( Problem &problem, EExitStatus statusFlag; bool isSubproblemConverged = false; bool isForcedUpdate = false; - const Real oem2(1e-2); Real penaltyParameter, reduction, theta; // ======================================================================== @@ -445,14 +450,12 @@ void AugmentedLagrangianAlgorithm2::run( Problem &problem, isUpdated_ = false; for (unsigned i = 0; i < numberPenalties; ++i) { penaltyParameter = alobj->getPenaltyParameter(i); - // std::cout << "Dual Residuals " << i << ": " << dualResiduals[i] << " Scaling: " << alobj->getScaling(i) << " Tolerance: " << dualTolerances[i] << std::endl; if (isForcedUpdate || alobj->getScaling(i)*dualResiduals[i] > penaltyParameter*dualTolerances[i]) { penaltyParameter *= penalty_growthf_[i]; penaltyParameter = std::min(penaltyParameter,maxPenaltyParam_); state_->searchSize = std::max(state_->searchSize,penaltyParameter); theta = std::min(one/penaltyParameter,theta_); dualTolerances[i] = tau0_*std::pow(theta,alphat_); - // dualTolerances[i] = std::max(dualTolerances[i],oem2*outerFeasTolerance_); // ROL convention alobj->setPenaltyParameter(penaltyParameter,i); isUpdated_ = true; } @@ -465,8 +468,8 @@ void AugmentedLagrangianAlgorithm2::run( Problem &problem, } } reduction = isUpdated_ ? Real(0.9) : Real(0.25); - epsilon_ = std::max(oem2*outerOptTolerance_, reduction*epsilon_); - delta_ = std::max(oem2*outerFeasTolerance_,reduction*delta_); + epsilon_ = std::max(subproblemTolFactor_*outerOptTolerance_, reduction*epsilon_); + delta_ = std::max(subproblemTolFactor_*outerFeasTolerance_,reduction*delta_); alobj->reset(); From 68779947fb46ae641cd1e5c8b0ae1f2a25422e3f Mon Sep 17 00:00:00 2001 From: Aurya Javeed Date: Wed, 29 Jul 2026 23:05:19 -0600 Subject: [PATCH 3/4] Force AL2 to continue --- ...OL_TypeG_AugmentedLagrangianAlgorithm2.hpp | 1 + ...ypeG_AugmentedLagrangianAlgorithm2_Def.hpp | 31 +++++++++++++++---- test/algorithm/TypeG/test_05.cpp | 1 - 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2.hpp b/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2.hpp index 89cdb4e1..f3f14b0e 100644 --- a/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2.hpp +++ b/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2.hpp @@ -54,6 +54,7 @@ class AugmentedLagrangianAlgorithm2 : public TypeG::Algorithm { Real outerOptTolerance_; Real outerFeasTolerance_; Real outerStepTolerance_; + int outerIterationLimit_; bool useRelTol_; // Scaling information bool useDefaultScaling_; diff --git a/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2_Def.hpp b/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2_Def.hpp index bad95dfc..ae392390 100644 --- a/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2_Def.hpp +++ b/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2_Def.hpp @@ -30,7 +30,8 @@ inline Ptr> AlgorithmFactory( template AugmentedLagrangianAlgorithm2::AugmentedLagrangianAlgorithm2( ParameterList &list, const Ptr> &secant ) - : TypeG::Algorithm::Algorithm(), secant_(secant), list_(list), subproblemIter_(0) { + : TypeG::Algorithm::Algorithm(), secant_(secant), list_(list), + subproblemIter_(0), isUpdated_(false) { // Set status test status_->reset(); status_->add(makePtr>(list)); @@ -74,10 +75,11 @@ AugmentedLagrangianAlgorithm2::AugmentedLagrangianAlgorithm2( ParameterLis list_.sublist("General").set("Output Level",(print ? verbosity_ - 2 : 0)); // Outer iteration tolerances - outerFeasTolerance_ = list.sublist("Status Test").get("Constraint Tolerance", oem8); - outerOptTolerance_ = list.sublist("Status Test").get("Gradient Tolerance", oem8); - outerStepTolerance_ = list.sublist("Status Test").get("Step Tolerance", oem8); - useRelTol_ = list.sublist("Status Test").get("Use Relative Tolerances", false); + outerFeasTolerance_ = list.sublist("Status Test").get("Constraint Tolerance", oem8); + outerOptTolerance_ = list.sublist("Status Test").get("Gradient Tolerance", oem8); + outerStepTolerance_ = list.sublist("Status Test").get("Step Tolerance", oem8); + outerIterationLimit_ = list.sublist("Status Test").get("Iteration Limit", 100); + useRelTol_ = list.sublist("Status Test").get("Use Relative Tolerances", false); // Augmented Lagrangian parameters useDefaultScaling_ = sublist.get("Use Default Problem Scaling", true); @@ -383,7 +385,24 @@ void AugmentedLagrangianAlgorithm2::run( Problem &problem, // STEP 3: Run algorithm // ======================================================================== - while (status_->check(*state_)) { + while (true) { + bool continueAlgorithm = status_->check(*state_); + + // A zero primal-dual step does not indicate stagnation when the preceding + // iteration updated the penalty model. Solve the new subproblem before + // applying the step-tolerance stopping criterion. + if (!continueAlgorithm + && state_->statusFlag == EXITSTATUS_STEPTOL + && isUpdated_ + && state_->iter < outerIterationLimit_) { + continueAlgorithm = true; + state_->statusFlag = EXITSTATUS_LAST; + } + + if (!continueAlgorithm) { + break; + } + // Solve augmented Lagrangian subproblem list_.sublist("Status Test").set("Gradient Tolerance",epsilon_); list_.sublist("Status Test").set("Constraint Tolerance",delta_); diff --git a/test/algorithm/TypeG/test_05.cpp b/test/algorithm/TypeG/test_05.cpp index 73080c2d..ad6d0a42 100644 --- a/test/algorithm/TypeG/test_05.cpp +++ b/test/algorithm/TypeG/test_05.cpp @@ -59,7 +59,6 @@ int main(int argc, char *argv[]) { list.sublist("General").set("Output Level", 3); list.sublist("Status Test").set("Iteration Limit", 20); list.sublist("Status Test").set("Constraint Tolerance", 1.e-4); - list.sublist("Status Test").set("Step Tolerance", -1.); list.sublist("Step").set("Type", "Augmented Lagrangian 2"); list.sublist("Step").sublist("Augmented Lagrangian").set("Subproblem Iteration Limit", 100); list.sublist("Step").sublist("Augmented Lagrangian").set("Use Default Initial Penalty Parameter", false); From a22cb6c755f683215d9568f265b23a966d27996c Mon Sep 17 00:00:00 2001 From: Aurya Javeed Date: Thu, 30 Jul 2026 09:40:41 -0600 Subject: [PATCH 4/4] Continue AL2 when tolerances change --- .../ROL_TypeG_AugmentedLagrangianAlgorithm2_Def.hpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2_Def.hpp b/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2_Def.hpp index ae392390..7d546418 100644 --- a/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2_Def.hpp +++ b/src/algorithm/TypeG/ROL_TypeG_AugmentedLagrangianAlgorithm2_Def.hpp @@ -379,7 +379,8 @@ void AugmentedLagrangianAlgorithm2::run( Problem &problem, EExitStatus statusFlag; bool isSubproblemConverged = false; bool isForcedUpdate = false; - Real penaltyParameter, reduction, theta; + bool tolerancesUpdated = false; + Real penaltyParameter, reduction, theta, oldEpsilon, oldDelta; // ======================================================================== // STEP 3: Run algorithm @@ -393,7 +394,7 @@ void AugmentedLagrangianAlgorithm2::run( Problem &problem, // applying the step-tolerance stopping criterion. if (!continueAlgorithm && state_->statusFlag == EXITSTATUS_STEPTOL - && isUpdated_ + && (isUpdated_ || tolerancesUpdated) && state_->iter < outerIterationLimit_) { continueAlgorithm = true; state_->statusFlag = EXITSTATUS_LAST; @@ -486,9 +487,13 @@ void AugmentedLagrangianAlgorithm2::run( Problem &problem, state_->snorm += alobj->updateMultiplier(x,tol,i); } } + reduction = isUpdated_ ? Real(0.9) : Real(0.25); - epsilon_ = std::max(subproblemTolFactor_*outerOptTolerance_, reduction*epsilon_); - delta_ = std::max(subproblemTolFactor_*outerFeasTolerance_,reduction*delta_); + oldEpsilon = epsilon_; + oldDelta = delta_; + epsilon_ = std::max(subproblemTolFactor_*outerOptTolerance_, reduction*epsilon_); + delta_ = std::max(subproblemTolFactor_*outerFeasTolerance_,reduction*delta_); + tolerancesUpdated = epsilon_ < oldEpsilon || delta_ < oldDelta; alobj->reset();