From 372ad256c725376deaecc590a291cac05ce5e1f0 Mon Sep 17 00:00:00 2001 From: Charlie Vanaret Date: Mon, 11 Nov 2024 15:09:24 +0100 Subject: [PATCH 1/6] TR strategy: properly reset the duals AND the feasibility duals if TR constraints are active --- .../TrustRegionStrategy.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/uno/ingredients/globalization_mechanisms/TrustRegionStrategy.cpp b/uno/ingredients/globalization_mechanisms/TrustRegionStrategy.cpp index 9a2c24dc..5123fd45 100644 --- a/uno/ingredients/globalization_mechanisms/TrustRegionStrategy.cpp +++ b/uno/ingredients/globalization_mechanisms/TrustRegionStrategy.cpp @@ -107,17 +107,17 @@ namespace uno { void TrustRegionStrategy::reset_active_trust_region_multipliers(const Model& model, const Direction& direction, Iterate& trial_iterate) const { assert(0 < this->radius && "The trust-region radius should be positive"); - // set multipliers for bound constraints active at trust region to 0 (except if one of the original bounds is active) - for (size_t variable_index: direction.active_bounds.at_lower_bound) { - if (variable_index < model.number_variables && std::abs(direction.primals[variable_index] + this->radius) <= this->activity_tolerance && - this->activity_tolerance < std::abs(trial_iterate.primals[variable_index] - model.variable_lower_bound(variable_index))) { + // reset multipliers for bound constraints active at trust region (except if one of the original bounds is active) + for (size_t variable_index: Range(model.number_variables)) { + if (std::abs(direction.primals[variable_index] + this->radius) <= this->activity_tolerance && + this->activity_tolerance < std::abs(trial_iterate.primals[variable_index] - model.variable_lower_bound(variable_index))) { trial_iterate.multipliers.lower_bounds[variable_index] = 0.; + trial_iterate.feasibility_multipliers.lower_bounds[variable_index] = 0.; } - } - for (size_t variable_index: direction.active_bounds.at_upper_bound) { - if (variable_index < model.number_variables && std::abs(direction.primals[variable_index] - this->radius) <= this->activity_tolerance && - this->activity_tolerance < std::abs(model.variable_upper_bound(variable_index) - trial_iterate.primals[variable_index])) { + if (std::abs(direction.primals[variable_index] - this->radius) <= this->activity_tolerance && + this->activity_tolerance < std::abs(model.variable_upper_bound(variable_index) - trial_iterate.primals[variable_index])) { trial_iterate.multipliers.upper_bounds[variable_index] = 0.; + trial_iterate.feasibility_multipliers.upper_bounds[variable_index] = 0.; } } } From a58a6e51105209f68788c8007a5e9b0366914c3a Mon Sep 17 00:00:00 2001 From: Charlie Vanaret Date: Mon, 11 Nov 2024 15:46:30 +0100 Subject: [PATCH 2/6] Bug fix with WarmstartInformation in TrustRegionStrategy --- .../globalization_mechanisms/TrustRegionStrategy.cpp | 6 ++++-- uno/optimization/WarmstartInformation.cpp | 8 ++++++++ uno/optimization/WarmstartInformation.hpp | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/uno/ingredients/globalization_mechanisms/TrustRegionStrategy.cpp b/uno/ingredients/globalization_mechanisms/TrustRegionStrategy.cpp index 5123fd45..01b7285e 100644 --- a/uno/ingredients/globalization_mechanisms/TrustRegionStrategy.cpp +++ b/uno/ingredients/globalization_mechanisms/TrustRegionStrategy.cpp @@ -78,6 +78,9 @@ namespace uno { GlobalizationMechanism::assemble_trial_iterate(model, current_iterate, trial_iterate, this->direction, 1., 1.); this->reset_active_trust_region_multipliers(model, this->direction, trial_iterate); + // let the constraint relaxation strategy and the radius update rule determine which quantities change + warmstart_information.reset(); + is_acceptable = this->is_iterate_acceptable(statistics, current_iterate, trial_iterate, this->direction, warmstart_information); if (is_acceptable) { this->constraint_relaxation_strategy.set_dual_residuals_statistics(statistics, trial_iterate); @@ -86,8 +89,7 @@ namespace uno { } else { this->decrease_radius(this->direction.norm); - // after the first iteration, only the variable bounds are updated - warmstart_information.only_variable_bounds_changed(); + warmstart_information.variable_bounds_changed = true; } if (Logger::level == INFO) statistics.print_current_line(); } diff --git a/uno/optimization/WarmstartInformation.cpp b/uno/optimization/WarmstartInformation.cpp index b51e43c4..44957d1f 100644 --- a/uno/optimization/WarmstartInformation.cpp +++ b/uno/optimization/WarmstartInformation.cpp @@ -13,6 +13,14 @@ namespace uno { std::cout << "Problem: " << std::boolalpha << this->problem_changed << '\n'; } + void WarmstartInformation::reset() { + this->objective_changed = true; + this->constraints_changed = true; + this->constraint_bounds_changed = true; + this->variable_bounds_changed = true; + this->problem_changed = true; + } + void WarmstartInformation::set_cold_start() { this->objective_changed = true; this->constraints_changed = true; diff --git a/uno/optimization/WarmstartInformation.hpp b/uno/optimization/WarmstartInformation.hpp index 5158df76..f7e3b128 100644 --- a/uno/optimization/WarmstartInformation.hpp +++ b/uno/optimization/WarmstartInformation.hpp @@ -13,6 +13,7 @@ namespace uno { bool problem_changed{false}; void display() const; + void reset(); void set_cold_start(); void set_hot_start(); void only_objective_changed(); From d57ee9cf9d105d1547f8140eea7dd6a9d54b884f Mon Sep 17 00:00:00 2001 From: Charlie Vanaret Date: Tue, 12 Nov 2024 11:56:00 +0100 Subject: [PATCH 3/6] Preprocessing: fixed enforce_linear_constraints() in case the primal vector is longer than the direction --- uno/preprocessing/Preprocessing.cpp | 20 +++++++++++--------- uno/preprocessing/Preprocessing.hpp | 2 +- uno/solvers/BQPD/BQPDSolver.cpp | 2 +- uno/symbolic/VectorView.hpp | 9 +++++++++ 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/uno/preprocessing/Preprocessing.cpp b/uno/preprocessing/Preprocessing.cpp index c0e74f74..1fd658a4 100644 --- a/uno/preprocessing/Preprocessing.cpp +++ b/uno/preprocessing/Preprocessing.cpp @@ -85,13 +85,13 @@ namespace uno { return infeasible_linear_constraints; } - void Preprocessing::enforce_linear_constraints(const Model& model, Vector& x, Multipliers& multipliers, QPSolver& qp_solver) { + void Preprocessing::enforce_linear_constraints(const Model& model, Vector& primals, Multipliers& multipliers, QPSolver& qp_solver) { const auto& linear_constraints = model.get_linear_constraints(); INFO << "\nPreprocessing phase: the problem has " << linear_constraints.size() << " linear constraints\n"; if (not linear_constraints.empty()) { // evaluate the constraints std::vector constraints(model.number_constraints); - model.evaluate_constraints(x, constraints); + model.evaluate_constraints(primals, constraints); const size_t infeasible_linear_constraints = count_infeasible_linear_constraints(model, constraints); INFO << "There are " << infeasible_linear_constraints << " infeasible linear constraints at the initial point\n"; if (0 < infeasible_linear_constraints) { @@ -105,15 +105,15 @@ namespace uno { RectangularMatrix constraint_jacobian(linear_constraints.size(), model.number_variables); size_t linear_constraint_index = 0; for (size_t constraint_index: linear_constraints) { - model.evaluate_constraint_gradient(x, constraint_index, constraint_jacobian[linear_constraint_index]); + model.evaluate_constraint_gradient(primals, constraint_index, constraint_jacobian[linear_constraint_index]); linear_constraint_index++; } // variable bounds std::vector variables_lower_bounds(model.number_variables); std::vector variables_upper_bounds(model.number_variables); for (size_t variable_index: Range(model.number_variables)) { - variables_lower_bounds[variable_index] = model.variable_lower_bound(variable_index) - x[variable_index]; - variables_upper_bounds[variable_index] = model.variable_upper_bound(variable_index) - x[variable_index]; + variables_lower_bounds[variable_index] = model.variable_lower_bound(variable_index) - primals[variable_index]; + variables_upper_bounds[variable_index] = model.variable_upper_bound(variable_index) - primals[variable_index]; } // constraint bounds std::vector constraints_lower_bounds(linear_constraints.size()); @@ -137,15 +137,17 @@ namespace uno { } // take the step - x += direction.primals; - multipliers.lower_bounds += direction.multipliers.lower_bounds; - multipliers.upper_bounds += direction.multipliers.upper_bounds; + for (size_t variable_index: Range(model.number_variables)) { + primals[variable_index] += direction.primals[variable_index]; + multipliers.lower_bounds[variable_index] += direction.multipliers.lower_bounds[variable_index]; + multipliers.upper_bounds[variable_index] += direction.multipliers.upper_bounds[variable_index]; + } linear_constraint_index = 0; for (size_t constraint_index: linear_constraints) { multipliers.constraints[constraint_index] += direction.multipliers.constraints[linear_constraint_index]; linear_constraint_index++; } - DEBUG3 << "Linear feasible initial point: " << x << '\n'; + DEBUG3 << "Linear feasible initial point: " << view(primals, 0, model.number_variables) << '\n'; } } } diff --git a/uno/preprocessing/Preprocessing.hpp b/uno/preprocessing/Preprocessing.hpp index d0127979..96440452 100644 --- a/uno/preprocessing/Preprocessing.hpp +++ b/uno/preprocessing/Preprocessing.hpp @@ -25,7 +25,7 @@ namespace uno { static void compute_least_square_multipliers(const Model& model, SymmetricMatrix& matrix, Vector& rhs, DirectSymmetricIndefiniteLinearSolver& linear_solver, Iterate& current_iterate, Vector& multipliers, double multiplier_max_norm); - static void enforce_linear_constraints(const Model& model, Vector& x, Multipliers& multipliers, QPSolver& qp_solver); + static void enforce_linear_constraints(const Model& model, Vector& primals, Multipliers& multipliers, QPSolver& qp_solver); }; } // namespace diff --git a/uno/solvers/BQPD/BQPDSolver.cpp b/uno/solvers/BQPD/BQPDSolver.cpp index 6d54e4d2..71a9bf01 100644 --- a/uno/solvers/BQPD/BQPDSolver.cpp +++ b/uno/solvers/BQPD/BQPDSolver.cpp @@ -169,7 +169,7 @@ namespace uno { if (warmstart_information.problem_changed) { mode = BQPDMode::ACTIVE_SET_EQUALITIES; } - // if only the variable bounds changed, reuse the active set estimate and the Jacobian information + // if only the variable bounds changed, reuse the active set estimate and the Jacobian information else if (warmstart_information.variable_bounds_changed && not warmstart_information.objective_changed && not warmstart_information.constraints_changed && not warmstart_information.constraint_bounds_changed) { mode = BQPDMode::UNCHANGED_ACTIVE_SET_AND_JACOBIAN; diff --git a/uno/symbolic/VectorView.hpp b/uno/symbolic/VectorView.hpp index e87a363d..dcb87765 100644 --- a/uno/symbolic/VectorView.hpp +++ b/uno/symbolic/VectorView.hpp @@ -58,6 +58,15 @@ namespace uno { VectorView view(Expression&& expression, size_t start, size_t end) { return {std::forward(expression), start, end}; } + + template + std::ostream& operator<<(std::ostream& stream, const VectorView& view) { + for (size_t index: Range(view.size())) { + stream << view[index] << " "; + } + stream << '\n'; + return stream; + } } // namespace #endif //UNO_VECTORVIEW_H From b78271d271c8688e32479f0764bb2e23b12882fd Mon Sep 17 00:00:00 2001 From: Charlie Vanaret Date: Tue, 12 Nov 2024 11:59:04 +0100 Subject: [PATCH 4/6] Passed warmstart object around to properly handle the warmstart information --- .../ConstraintRelaxationStrategy.hpp | 2 +- .../FeasibilityRestoration.cpp | 19 +++++++------ .../FeasibilityRestoration.hpp | 2 +- .../l1Relaxation.cpp | 3 +- .../l1Relaxation.hpp | 2 +- .../BacktrackingLineSearch.cpp | 11 ++++---- .../BacktrackingLineSearch.hpp | 3 +- .../GlobalizationMechanism.hpp | 4 ++- .../TrustRegionStrategy.cpp | 14 ++++------ .../TrustRegionStrategy.hpp | 3 +- uno/optimization/WarmstartInformation.cpp | 28 +++++++------------ uno/optimization/WarmstartInformation.hpp | 7 ++--- 12 files changed, 47 insertions(+), 51 deletions(-) diff --git a/uno/ingredients/constraint_relaxation_strategies/ConstraintRelaxationStrategy.hpp b/uno/ingredients/constraint_relaxation_strategies/ConstraintRelaxationStrategy.hpp index 41c5a1ad..3c2d1eb5 100644 --- a/uno/ingredients/constraint_relaxation_strategies/ConstraintRelaxationStrategy.hpp +++ b/uno/ingredients/constraint_relaxation_strategies/ConstraintRelaxationStrategy.hpp @@ -46,7 +46,7 @@ namespace uno { void compute_feasible_direction(Statistics& statistics, Iterate& current_iterate, Direction& direction, const Vector& initial_point, WarmstartInformation& warmstart_information); [[nodiscard]] virtual bool solving_feasibility_problem() const = 0; - virtual void switch_to_feasibility_problem(Statistics& statistics, Iterate& current_iterate) = 0; + virtual void switch_to_feasibility_problem(Statistics& statistics, Iterate& current_iterate, WarmstartInformation& warmstart_information) = 0; // trial iterate acceptance [[nodiscard]] virtual bool is_iterate_acceptable(Statistics& statistics, Iterate& current_iterate, Iterate& trial_iterate, const Direction& direction, diff --git a/uno/ingredients/constraint_relaxation_strategies/FeasibilityRestoration.cpp b/uno/ingredients/constraint_relaxation_strategies/FeasibilityRestoration.cpp index 7633dcfc..01bd0529 100644 --- a/uno/ingredients/constraint_relaxation_strategies/FeasibilityRestoration.cpp +++ b/uno/ingredients/constraint_relaxation_strategies/FeasibilityRestoration.cpp @@ -71,17 +71,16 @@ namespace uno { // switch to the feasibility problem, starting from the current direction statistics.set("status", "infeas. subproblem"); DEBUG << "/!\\ The subproblem is infeasible\n"; - this->switch_to_feasibility_problem(statistics, current_iterate); - warmstart_information.set_cold_start(); + this->switch_to_feasibility_problem(statistics, current_iterate, warmstart_information); this->subproblem->set_initial_point(direction.primals); } else { + warmstart_information.no_changes(); return; } } catch (const UnstableRegularization&) { - this->switch_to_feasibility_problem(statistics, current_iterate); - warmstart_information.set_cold_start(); + this->switch_to_feasibility_problem(statistics, current_iterate, warmstart_information); } } @@ -99,7 +98,8 @@ namespace uno { } // precondition: this->current_phase == Phase::OPTIMALITY - void FeasibilityRestoration::switch_to_feasibility_problem(Statistics& statistics, Iterate& current_iterate) { + void FeasibilityRestoration::switch_to_feasibility_problem(Statistics& statistics, Iterate& current_iterate, + WarmstartInformation& warmstart_information) { DEBUG << "Switching from optimality to restoration phase\n"; this->current_phase = Phase::FEASIBILITY_RESTORATION; this->globalization_strategy->notify_switch_to_feasibility(current_iterate.progress); @@ -114,6 +114,7 @@ namespace uno { DEBUG2 << "Current iterate:\n" << current_iterate << '\n'; if (Logger::level == INFO) statistics.print_current_line(); + warmstart_information.whole_problem_changed(); } void FeasibilityRestoration::solve_subproblem(Statistics& statistics, const OptimizationProblem& problem, Iterate& current_iterate, @@ -142,7 +143,7 @@ namespace uno { this->subproblem->exit_feasibility_problem(this->optimality_problem, trial_iterate); // set a cold start in the subproblem solver - warmstart_information.set_cold_start(); + warmstart_information.whole_problem_changed(); } bool FeasibilityRestoration::is_iterate_acceptable(Statistics& statistics, Iterate& current_iterate, Iterate& trial_iterate, const Direction& direction, @@ -156,6 +157,9 @@ namespace uno { if (this->current_phase == Phase::FEASIBILITY_RESTORATION && this->can_switch_to_optimality_phase(current_iterate, trial_iterate, direction, step_length)) { this->switch_to_optimality_phase(current_iterate, trial_iterate, warmstart_information); } + else { + warmstart_information.no_changes(); + } bool accept_iterate = false; if (direction.norm == 0.) { @@ -170,9 +174,6 @@ namespace uno { accept_iterate = this->globalization_strategy->is_iterate_acceptable(statistics, current_iterate.progress, trial_iterate.progress, predicted_reduction, this->current_problem().get_objective_multiplier()); } - if (accept_iterate) { - // this->set_dual_residuals_statistics(statistics, trial_iterate); - } ConstraintRelaxationStrategy::set_progress_statistics(statistics, trial_iterate); return accept_iterate; } diff --git a/uno/ingredients/constraint_relaxation_strategies/FeasibilityRestoration.hpp b/uno/ingredients/constraint_relaxation_strategies/FeasibilityRestoration.hpp index 7cc2dc94..1a4381b7 100644 --- a/uno/ingredients/constraint_relaxation_strategies/FeasibilityRestoration.hpp +++ b/uno/ingredients/constraint_relaxation_strategies/FeasibilityRestoration.hpp @@ -25,7 +25,7 @@ namespace uno { // direction computation void compute_feasible_direction(Statistics& statistics, Iterate& current_iterate, Direction& direction, WarmstartInformation& warmstart_information) override; [[nodiscard]] bool solving_feasibility_problem() const override; - void switch_to_feasibility_problem(Statistics& statistics, Iterate& current_iterate) override; + void switch_to_feasibility_problem(Statistics& statistics, Iterate& current_iterate, WarmstartInformation& warmstart_information) override; // trial iterate acceptance [[nodiscard]] bool is_iterate_acceptable(Statistics& statistics, Iterate& current_iterate, Iterate& trial_iterate, const Direction& direction, diff --git a/uno/ingredients/constraint_relaxation_strategies/l1Relaxation.cpp b/uno/ingredients/constraint_relaxation_strategies/l1Relaxation.cpp index 6ac3c6b2..4bf09bed 100644 --- a/uno/ingredients/constraint_relaxation_strategies/l1Relaxation.cpp +++ b/uno/ingredients/constraint_relaxation_strategies/l1Relaxation.cpp @@ -79,7 +79,8 @@ namespace uno { return (this->penalty_parameter == 0.); } - void l1Relaxation::switch_to_feasibility_problem(Statistics& /*statistics*/, Iterate& /*current_iterate*/) { + void l1Relaxation::switch_to_feasibility_problem(Statistics& /*statistics*/, Iterate& /*current_iterate*/, + WarmstartInformation& /*warmstart_information*/) { throw std::runtime_error("l1Relaxation::switch_to_feasibility_problem is not implemented"); } diff --git a/uno/ingredients/constraint_relaxation_strategies/l1Relaxation.hpp b/uno/ingredients/constraint_relaxation_strategies/l1Relaxation.hpp index 0057001e..805a6bbc 100644 --- a/uno/ingredients/constraint_relaxation_strategies/l1Relaxation.hpp +++ b/uno/ingredients/constraint_relaxation_strategies/l1Relaxation.hpp @@ -32,7 +32,7 @@ namespace uno { void compute_feasible_direction(Statistics& statistics, Iterate& current_iterate, Direction& direction, WarmstartInformation& warmstart_information) override; [[nodiscard]] bool solving_feasibility_problem() const override; - void switch_to_feasibility_problem(Statistics& statistics, Iterate& current_iterate) override; + void switch_to_feasibility_problem(Statistics& statistics, Iterate& current_iterate, WarmstartInformation& warmstart_information) override; // trial iterate acceptance [[nodiscard]] bool is_iterate_acceptable(Statistics& statistics, Iterate& current_iterate, Iterate& trial_iterate, const Direction& direction, diff --git a/uno/ingredients/globalization_mechanisms/BacktrackingLineSearch.cpp b/uno/ingredients/globalization_mechanisms/BacktrackingLineSearch.cpp index 971fecb4..15d358f4 100644 --- a/uno/ingredients/globalization_mechanisms/BacktrackingLineSearch.cpp +++ b/uno/ingredients/globalization_mechanisms/BacktrackingLineSearch.cpp @@ -30,9 +30,8 @@ namespace uno { this->constraint_relaxation_strategy.initialize(statistics, initial_iterate, options); } - void BacktrackingLineSearch::compute_next_iterate(Statistics& statistics, const Model& model, Iterate& current_iterate, Iterate& trial_iterate) { - WarmstartInformation warmstart_information{}; - warmstart_information.set_hot_start(); + void BacktrackingLineSearch::compute_next_iterate(Statistics& statistics, const Model& model, Iterate& current_iterate, Iterate& trial_iterate, + WarmstartInformation& warmstart_information) { DEBUG2 << "Current iterate\n" << current_iterate << '\n'; this->constraint_relaxation_strategy.compute_feasible_direction(statistics, current_iterate, this->direction, warmstart_information); @@ -59,6 +58,9 @@ namespace uno { // scale or not the constraint dual direction with the LS step length this->scale_duals_with_step_length ? step_length : 1.); + // let the constraint relaxation strategy determine which quantities change + warmstart_information.no_changes(); + is_acceptable = this->constraint_relaxation_strategy.is_iterate_acceptable(statistics, current_iterate, trial_iterate, this->direction, step_length, warmstart_information); this->set_statistics(statistics, trial_iterate, this->direction, step_length, number_iterations); @@ -89,8 +91,7 @@ namespace uno { } // switch to solving the feasibility problem statistics.set("status", "small LS step length"); - this->constraint_relaxation_strategy.switch_to_feasibility_problem(statistics, current_iterate); - warmstart_information.set_cold_start(); + this->constraint_relaxation_strategy.switch_to_feasibility_problem(statistics, current_iterate, warmstart_information); this->constraint_relaxation_strategy.compute_feasible_direction(statistics, current_iterate, this->direction, this->direction.primals, warmstart_information); BacktrackingLineSearch::check_unboundedness(this->direction); diff --git a/uno/ingredients/globalization_mechanisms/BacktrackingLineSearch.hpp b/uno/ingredients/globalization_mechanisms/BacktrackingLineSearch.hpp index 4fa4865c..21884c02 100644 --- a/uno/ingredients/globalization_mechanisms/BacktrackingLineSearch.hpp +++ b/uno/ingredients/globalization_mechanisms/BacktrackingLineSearch.hpp @@ -15,7 +15,8 @@ namespace uno { BacktrackingLineSearch(ConstraintRelaxationStrategy& constraint_relaxation_strategy, const Options& options); void initialize(Statistics& statistics, Iterate& initial_iterate, const Options& options) override; - void compute_next_iterate(Statistics& statistics, const Model& model, Iterate& current_iterate, Iterate& trial_iterate) override; + void compute_next_iterate(Statistics& statistics, const Model& model, Iterate& current_iterate, Iterate& trial_iterate, + WarmstartInformation& warmstart_information) override; private: const double backtracking_ratio; diff --git a/uno/ingredients/globalization_mechanisms/GlobalizationMechanism.hpp b/uno/ingredients/globalization_mechanisms/GlobalizationMechanism.hpp index 0fb8af8e..538045c0 100644 --- a/uno/ingredients/globalization_mechanisms/GlobalizationMechanism.hpp +++ b/uno/ingredients/globalization_mechanisms/GlobalizationMechanism.hpp @@ -13,6 +13,7 @@ namespace uno { class Model; class Options; class Statistics; + class WarmstartInformation; class GlobalizationMechanism { public: @@ -20,7 +21,8 @@ namespace uno { virtual ~GlobalizationMechanism() = default; virtual void initialize(Statistics& statistics, Iterate& initial_iterate, const Options& options) = 0; - virtual void compute_next_iterate(Statistics& statistics, const Model& model, Iterate& current_iterate, Iterate& trial_iterate) = 0; + virtual void compute_next_iterate(Statistics& statistics, const Model& model, Iterate& current_iterate, Iterate& trial_iterate, + WarmstartInformation& warmstart_information) = 0; [[nodiscard]] size_t get_hessian_evaluation_count() const; [[nodiscard]] size_t get_number_subproblems_solved() const; diff --git a/uno/ingredients/globalization_mechanisms/TrustRegionStrategy.cpp b/uno/ingredients/globalization_mechanisms/TrustRegionStrategy.cpp index 01b7285e..b584cb76 100644 --- a/uno/ingredients/globalization_mechanisms/TrustRegionStrategy.cpp +++ b/uno/ingredients/globalization_mechanisms/TrustRegionStrategy.cpp @@ -38,9 +38,8 @@ namespace uno { this->constraint_relaxation_strategy.initialize(statistics, initial_iterate, options); } - void TrustRegionStrategy::compute_next_iterate(Statistics& statistics, const Model& model, Iterate& current_iterate, Iterate& trial_iterate) { - WarmstartInformation warmstart_information{}; - warmstart_information.set_hot_start(); + void TrustRegionStrategy::compute_next_iterate(Statistics& statistics, const Model& model, Iterate& current_iterate, Iterate& trial_iterate, + WarmstartInformation& warmstart_information) { DEBUG2 << "Current iterate\n" << current_iterate << '\n'; size_t number_iterations = 0; @@ -64,14 +63,14 @@ namespace uno { statistics.set("status", "unbounded subproblem"); if (Logger::level == INFO) statistics.print_current_line(); this->decrease_radius_aggressively(); - warmstart_information.set_cold_start(); + warmstart_information.whole_problem_changed(); } else if (this->direction.status == SubproblemStatus::ERROR) { this->set_statistics(statistics, this->direction); statistics.set("status", "solver error"); if (Logger::level == INFO) statistics.print_current_line(); this->decrease_radius(); - warmstart_information.set_cold_start(); + warmstart_information.whole_problem_changed(); } else { // take full primal-dual step @@ -79,7 +78,7 @@ namespace uno { this->reset_active_trust_region_multipliers(model, this->direction, trial_iterate); // let the constraint relaxation strategy and the radius update rule determine which quantities change - warmstart_information.reset(); + warmstart_information.no_changes(); is_acceptable = this->is_iterate_acceptable(statistics, current_iterate, trial_iterate, this->direction, warmstart_information); if (is_acceptable) { @@ -99,7 +98,7 @@ namespace uno { statistics.set("status", "eval. error"); if (Logger::level == INFO) statistics.print_current_line(); this->decrease_radius(); - warmstart_information.set_cold_start(); + warmstart_information.whole_problem_changed(); } if (not is_acceptable && this->radius < this->minimum_radius) { throw std::runtime_error("Small trust-region radius"); @@ -127,7 +126,6 @@ namespace uno { // the trial iterate is accepted by the constraint relaxation strategy or if the step is small and we cannot switch to solving the feasibility problem bool TrustRegionStrategy::is_iterate_acceptable(Statistics& statistics, Iterate& current_iterate, Iterate& trial_iterate, const Direction& direction, WarmstartInformation& warmstart_information) { - // direction.primal_dual_step_length is usually 1, can be lower if reduced by fraction-to-boundary rule bool accept_iterate = this->constraint_relaxation_strategy.is_iterate_acceptable(statistics, current_iterate, trial_iterate, direction, 1., warmstart_information); this->set_statistics(statistics, trial_iterate, direction); diff --git a/uno/ingredients/globalization_mechanisms/TrustRegionStrategy.hpp b/uno/ingredients/globalization_mechanisms/TrustRegionStrategy.hpp index 76c0a3c1..378408be 100644 --- a/uno/ingredients/globalization_mechanisms/TrustRegionStrategy.hpp +++ b/uno/ingredients/globalization_mechanisms/TrustRegionStrategy.hpp @@ -12,7 +12,8 @@ namespace uno { TrustRegionStrategy(ConstraintRelaxationStrategy& constraint_relaxation_strategy, const Options& options); void initialize(Statistics& statistics, Iterate& initial_iterate, const Options& options) override; - void compute_next_iterate(Statistics& statistics, const Model& model, Iterate& current_iterate, Iterate& trial_iterate) override; + void compute_next_iterate(Statistics& statistics, const Model& model, Iterate& current_iterate, Iterate& trial_iterate, + WarmstartInformation& warmstart_information) override; private: double radius; /*!< Current trust region radius */ diff --git a/uno/optimization/WarmstartInformation.cpp b/uno/optimization/WarmstartInformation.cpp index 44957d1f..c5e7bd52 100644 --- a/uno/optimization/WarmstartInformation.cpp +++ b/uno/optimization/WarmstartInformation.cpp @@ -13,28 +13,28 @@ namespace uno { std::cout << "Problem: " << std::boolalpha << this->problem_changed << '\n'; } - void WarmstartInformation::reset() { - this->objective_changed = true; - this->constraints_changed = true; - this->constraint_bounds_changed = true; - this->variable_bounds_changed = true; - this->problem_changed = true; + void WarmstartInformation::no_changes() { + this->objective_changed = false; + this->constraints_changed = false; + this->constraint_bounds_changed = false; + this->variable_bounds_changed = false; + this->problem_changed = false; } - void WarmstartInformation::set_cold_start() { + void WarmstartInformation::iterate_changed() { this->objective_changed = true; this->constraints_changed = true; this->constraint_bounds_changed = true; this->variable_bounds_changed = true; - this->problem_changed = true; + this->problem_changed = false; } - void WarmstartInformation::set_hot_start() { + void WarmstartInformation::whole_problem_changed() { this->objective_changed = true; this->constraints_changed = true; this->constraint_bounds_changed = true; this->variable_bounds_changed = true; - this->problem_changed = false; + this->problem_changed = true; } void WarmstartInformation::only_objective_changed() { @@ -44,12 +44,4 @@ namespace uno { this->variable_bounds_changed = false; this->problem_changed = false; } - - void WarmstartInformation::only_variable_bounds_changed() { - this->objective_changed = false; - this->constraints_changed = false; - this->constraint_bounds_changed = false; - this->variable_bounds_changed = true; - this->problem_changed = false; - } } // namespace \ No newline at end of file diff --git a/uno/optimization/WarmstartInformation.hpp b/uno/optimization/WarmstartInformation.hpp index f7e3b128..c7d474e4 100644 --- a/uno/optimization/WarmstartInformation.hpp +++ b/uno/optimization/WarmstartInformation.hpp @@ -13,11 +13,10 @@ namespace uno { bool problem_changed{false}; void display() const; - void reset(); - void set_cold_start(); - void set_hot_start(); + void no_changes(); + void iterate_changed(); + void whole_problem_changed(); void only_objective_changed(); - void only_variable_bounds_changed(); }; } // namespace From b4c056068cc470906835da996e554848e2da77d5 Mon Sep 17 00:00:00 2001 From: Charlie Vanaret Date: Tue, 12 Nov 2024 12:03:44 +0100 Subject: [PATCH 5/6] Removed warning in forward declaration --- .../globalization_mechanisms/GlobalizationMechanism.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uno/ingredients/globalization_mechanisms/GlobalizationMechanism.hpp b/uno/ingredients/globalization_mechanisms/GlobalizationMechanism.hpp index 538045c0..4a1d1c97 100644 --- a/uno/ingredients/globalization_mechanisms/GlobalizationMechanism.hpp +++ b/uno/ingredients/globalization_mechanisms/GlobalizationMechanism.hpp @@ -13,7 +13,7 @@ namespace uno { class Model; class Options; class Statistics; - class WarmstartInformation; + struct WarmstartInformation; class GlobalizationMechanism { public: From d58eb6a63a755a3c4375d906fbbf19e03e304162 Mon Sep 17 00:00:00 2001 From: Charlie Vanaret Date: Tue, 12 Nov 2024 12:07:08 +0100 Subject: [PATCH 6/6] Forgot to include Uno.cpp to commit because of WIP on this file --- uno/Uno.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/uno/Uno.cpp b/uno/Uno.cpp index 7e260551..04d71083 100644 --- a/uno/Uno.cpp +++ b/uno/Uno.cpp @@ -11,6 +11,7 @@ #include "linear_algebra/Vector.hpp" #include "model/Model.hpp" #include "optimization/Iterate.hpp" +#include "optimization/WarmstartInformation.hpp" #include "solvers/QPSolverFactory.hpp" #include "solvers/LPSolverFactory.hpp" #include "solvers/SymmetricIndefiniteLinearSolverFactory.hpp" @@ -32,11 +33,12 @@ namespace uno { void Uno::solve(const Model& model, Iterate& current_iterate, const Options& options) { Timer timer{}; Statistics statistics = Uno::create_statistics(model, options); + WarmstartInformation warmstart_information{}; + warmstart_information.whole_problem_changed(); try { // use the initial primal-dual point to initialize the strategies and generate the initial iterate this->initialize(statistics, current_iterate, options); - current_iterate.status = TerminationStatus::NOT_OPTIMAL; // allocate the trial iterate once and for all here Iterate trial_iterate(current_iterate); @@ -51,7 +53,8 @@ namespace uno { DEBUG << "### Outer iteration " << major_iterations << '\n'; // compute an acceptable iterate by solving a subproblem at the current point - this->globalization_mechanism.compute_next_iterate(statistics, model, current_iterate, trial_iterate); + warmstart_information.iterate_changed(); + this->globalization_mechanism.compute_next_iterate(statistics, model, current_iterate, trial_iterate, warmstart_information); termination = this->termination_criteria(trial_iterate.status, major_iterations, timer.get_duration()); // the trial iterate becomes the current iterate for the next iteration std::swap(current_iterate, trial_iterate); @@ -81,6 +84,7 @@ namespace uno { this->globalization_mechanism.initialize(statistics, current_iterate, options); options.print_used(); if (Logger::level == INFO) statistics.print_current_line(); + current_iterate.status = TerminationStatus::NOT_OPTIMAL; } Statistics Uno::create_statistics(const Model& model, const Options& options) {