-
Notifications
You must be signed in to change notification settings - Fork 24
/
Copy pathUno.cpp
146 lines (128 loc) · 7.83 KB
/
Uno.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Copyright (c) 2018-2024 Charlie Vanaret
// Licensed under the MIT license. See LICENSE file in the project directory for details.
#include <cmath>
#include "Uno.hpp"
#include "ingredients/constraint_relaxation_strategies/ConstraintRelaxationStrategyFactory.hpp"
#include "ingredients/globalization_mechanisms/GlobalizationMechanism.hpp"
#include "ingredients/globalization_mechanisms/GlobalizationMechanismFactory.hpp"
#include "ingredients/globalization_strategies/GlobalizationStrategyFactory.hpp"
#include "ingredients/subproblems/SubproblemFactory.hpp"
#include "linear_algebra/Vector.hpp"
#include "model/Model.hpp"
#include "optimization/Iterate.hpp"
#include "solvers/QPSolverFactory.hpp"
#include "solvers/LPSolverFactory.hpp"
#include "solvers/SymmetricIndefiniteLinearSolverFactory.hpp"
#include "tools/Logger.hpp"
#include "options/Options.hpp"
#include "tools/Statistics.hpp"
#include "tools/Timer.hpp"
namespace uno {
Uno::Uno(GlobalizationMechanism& globalization_mechanism, const Options& options) :
globalization_mechanism(globalization_mechanism),
max_iterations(options.get_unsigned_int("max_iterations")),
time_limit(options.get_double("time_limit")),
print_solution(options.get_bool("print_solution")),
strategy_combination(Uno::get_strategy_combination(options)) { }
Level Logger::level = INFO;
void Uno::solve(const Model& model, Iterate& current_iterate, const Options& options) {
Timer timer{};
Statistics statistics = Uno::create_statistics(model, options);
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);
size_t major_iterations = 0;
try {
bool termination = false;
// check for termination
while (not termination) {
major_iterations++;
statistics.start_new_line();
statistics.set("iter", major_iterations);
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);
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);
}
}
catch (std::exception& exception) {
statistics.start_new_line();
statistics.set("status", exception.what());
if (Logger::level == INFO) statistics.print_current_line();
DEBUG << exception.what() << '\n';
}
if (Logger::level == INFO) statistics.print_footer();
Uno::postprocess_iterate(model, current_iterate, current_iterate.status);
Result result = this->create_result(model, current_iterate, major_iterations, timer);
this->print_optimization_summary(result);
}
catch (const std::exception& e) {
DISCRETE << "An error occurred at the initial iterate: " << e.what() << '\n';
}
}
void Uno::initialize(Statistics& statistics, Iterate& current_iterate, const Options& options) {
statistics.start_new_line();
statistics.set("iter", 0);
statistics.set("status", "initial point");
this->globalization_mechanism.initialize(statistics, current_iterate, options);
options.print_used();
if (Logger::level == INFO) statistics.print_current_line();
}
Statistics Uno::create_statistics(const Model& model, const Options& options) {
Statistics statistics(options);
statistics.add_column("iter", Statistics::int_width, options.get_int("statistics_major_column_order"));
statistics.add_column("step norm", Statistics::double_width - 3, options.get_int("statistics_step_norm_column_order"));
statistics.add_column("objective", Statistics::double_width - 4, options.get_int("statistics_objective_column_order"));
if (model.is_constrained()) {
statistics.add_column("primal feas.", Statistics::double_width - 2, options.get_int("statistics_primal_feasibility_column_order"));
}
statistics.add_column("stationarity", Statistics::double_width - 3, options.get_int("statistics_stationarity_column_order"));
statistics.add_column("complementarity", Statistics::double_width, options.get_int("statistics_complementarity_column_order"));
statistics.add_column("status", Statistics::string_width - 2, options.get_int("statistics_status_column_order"));
return statistics;
}
bool Uno::termination_criteria(TerminationStatus current_status, size_t iteration, double current_time) const {
return current_status != TerminationStatus::NOT_OPTIMAL || this->max_iterations <= iteration || this->time_limit <= current_time;
}
void Uno::postprocess_iterate(const Model& model, Iterate& iterate, TerminationStatus termination_status) {
// in case the objective was not yet evaluated, evaluate it
iterate.evaluate_objective(model);
model.postprocess_solution(iterate, termination_status);
DEBUG2 << "Final iterate:\n" << iterate;
}
Result Uno::create_result(const Model& model, Iterate& current_iterate, size_t major_iterations, const Timer& timer) {
const size_t number_subproblems_solved = this->globalization_mechanism.get_number_subproblems_solved();
const size_t number_hessian_evaluations = this->globalization_mechanism.get_hessian_evaluation_count();
return {std::move(current_iterate), model.number_variables, model.number_constraints, major_iterations, timer.get_duration(),
Iterate::number_eval_objective, Iterate::number_eval_constraints, Iterate::number_eval_objective_gradient,
Iterate::number_eval_jacobian, number_hessian_evaluations, number_subproblems_solved};
}
std::string Uno::current_version() {
return "1.1.0";
}
void Uno::print_available_strategies() {
std::cout << "Available strategies:\n";
std::cout << "- Constraint relaxation strategies: " << join(ConstraintRelaxationStrategyFactory::available_strategies(), ", ") << '\n';
std::cout << "- Globalization mechanisms: " << join(GlobalizationMechanismFactory::available_strategies(), ", ") << '\n';
std::cout << "- Globalization strategies: " << join(GlobalizationStrategyFactory::available_strategies(), ", ") << '\n';
std::cout << "- Subproblems: " << join(SubproblemFactory::available_strategies(), ", ") << '\n';
std::cout << "- QP solvers: " << join(QPSolverFactory::available_solvers(), ", ") << '\n';
std::cout << "- LP solvers: " << join(LPSolverFactory::available_solvers(), ", ") << '\n';
std::cout << "- Linear solvers: " << join(SymmetricIndefiniteLinearSolverFactory::available_solvers(), ", ") << '\n';
}
std::string Uno::get_strategy_combination(const Options& options) {
return options.get_string("globalization_mechanism") + " " + options.get_string("constraint_relaxation_strategy") + " " +
options.get_string("globalization_strategy") + " " + options.get_string("subproblem");
}
void Uno::print_optimization_summary(const Result& result) {
DISCRETE << "\nUno " << Uno::current_version() << " (" << this->strategy_combination << ")\n";
DISCRETE << Timer::get_current_date();
DISCRETE << "────────────────────────────────────────\n";
result.print(this->print_solution);
}
} // namespace