From 0b68f170037644410c227f528dc40720c5bdc432 Mon Sep 17 00:00:00 2001 From: Charlie Vanaret Date: Wed, 23 Oct 2024 18:14:27 +0200 Subject: [PATCH] Moved default options to own class + improved the message errors in solver factories --- CMakeLists.txt | 1 + bindings/AMPL/AMPLModel.cpp | 4 +- bindings/AMPL/uno_ampl.cpp | 9 +- uno/Uno.cpp | 20 +- .../ConstraintRelaxationStrategy.cpp | 2 +- .../ConstraintRelaxationStrategyFactory.cpp | 2 +- .../FeasibilityRestoration.cpp | 2 +- .../l1Relaxation.cpp | 4 +- .../BacktrackingLineSearch.cpp | 2 +- .../GlobalizationMechanism.cpp | 2 +- .../GlobalizationMechanismFactory.cpp | 2 +- .../TrustRegionStrategy.cpp | 2 +- .../GlobalizationStrategy.cpp | 2 +- .../l1MeritFunction.cpp | 2 +- .../switching_methods/SwitchingMethod.cpp | 2 +- .../filter_methods/FilterMethod.cpp | 2 +- .../filter_methods/FletcherFilterMethod.cpp | 2 +- .../filter_methods/WaechterFilterMethod.cpp | 2 +- .../filter_methods/filters/Filter.cpp | 2 +- .../filter_methods/filters/FilterFactory.cpp | 2 +- .../filters/NonmonotoneFilter.cpp | 2 +- .../funnel_methods/Funnel.cpp | 4 +- .../funnel_methods/FunnelMethod.cpp | 2 +- .../hessian_models/ConvexifiedHessian.cpp | 5 +- .../hessian_models/ExactHessian.cpp | 2 +- .../hessian_models/ZeroHessian.cpp | 2 +- .../subproblems/SubproblemFactory.cpp | 2 +- .../InequalityConstrainedMethod.cpp | 2 +- .../LPSubproblem.cpp | 5 +- .../QPSubproblem.cpp | 5 +- .../BarrierParameterUpdateStrategy.cpp | 2 +- .../PrimalDualInteriorPointSubproblem.cpp | 11 +- .../SymmetricIndefiniteLinearSystem.hpp | 2 +- uno/linear_algebra/Vector.hpp | 12 + uno/model/BoundRelaxedModel.hpp | 2 +- uno/model/ModelFactory.cpp | 2 +- uno/model/ScaledModel.hpp | 2 +- uno/options/DefaultOptions.cpp | 220 +++++++++ uno/options/DefaultOptions.hpp | 16 + uno/options/Options.cpp | 234 +++++++++ uno/{tools => options}/Options.hpp | 3 +- uno/preprocessing/Preprocessing.cpp | 5 +- uno/solvers/BQPD/BQPDSolver.cpp | 2 +- uno/solvers/LPSolverFactory.hpp | 32 +- uno/solvers/QPSolverFactory.hpp | 33 +- ...SymmetricIndefiniteLinearSolverFactory.hpp | 34 +- uno/symbolic/Range.hpp | 4 +- uno/symbolic/VectorView.hpp | 2 +- uno/tools/Options.cpp | 450 ------------------ uno/tools/Statistics.cpp | 2 +- 50 files changed, 612 insertions(+), 557 deletions(-) create mode 100644 uno/options/DefaultOptions.cpp create mode 100644 uno/options/DefaultOptions.hpp create mode 100644 uno/options/Options.cpp rename uno/{tools => options}/Options.hpp (93%) delete mode 100644 uno/tools/Options.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b8c9829b..96ef24e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,7 @@ file(GLOB UNO_SOURCE_FILES uno/ingredients/subproblems/interior_point_methods/*.cpp uno/model/*.cpp uno/optimization/*.cpp + uno/options/*.cpp uno/preprocessing/*.cpp uno/tools/*.cpp ) diff --git a/bindings/AMPL/AMPLModel.cpp b/bindings/AMPL/AMPLModel.cpp index ec8d8aad..82904b5a 100644 --- a/bindings/AMPL/AMPLModel.cpp +++ b/bindings/AMPL/AMPLModel.cpp @@ -10,7 +10,7 @@ #include "optimization/Iterate.hpp" #include "tools/Logger.hpp" #include "tools/Infinity.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" #include "symbolic/Concatenation.hpp" namespace uno { @@ -22,7 +22,7 @@ namespace uno { int n_discrete = asl->i.nbv_ + asl->i.niv_ + asl->i.nlvbi_ + asl->i.nlvci_ + asl->i.nlvoi_; if (0 < n_discrete) { - throw std::runtime_error("Error: " + std::to_string(n_discrete) + " variables are discrete, which Uno cannot handle."); + throw std::runtime_error("Error: " + std::to_string(n_discrete) + " variables are discrete, which Uno cannot handle"); // asl->i.need_nl_ = 0; } diff --git a/bindings/AMPL/uno_ampl.cpp b/bindings/AMPL/uno_ampl.cpp index 4ba13bc5..53ca2c4e 100644 --- a/bindings/AMPL/uno_ampl.cpp +++ b/bindings/AMPL/uno_ampl.cpp @@ -10,8 +10,9 @@ #include "AMPLModel.hpp" #include "Uno.hpp" #include "model/ModelFactory.hpp" +#include "options/Options.hpp" +#include "options/DefaultOptions.hpp" #include "tools/Logger.hpp" -#include "tools/Options.hpp" /* size_t memory_allocation_amount = 0; @@ -83,11 +84,11 @@ int main(int argc, char* argv[]) { Uno::print_available_strategies(); } else { - throw std::runtime_error("The second command line argument should be -AMPL."); + throw std::runtime_error("The second command line argument should be -AMPL"); } } else if (argc >= 3) { - Options options = Options::get_default(); + Options options = DefaultOptions::load(); // AMPL expects: ./uno_ampl model.nl -AMPL [option_name=option_value, ...] // model name @@ -95,7 +96,7 @@ int main(int argc, char* argv[]) { // -AMPL if (std::string(argv[2]) != "-AMPL") { - throw std::runtime_error("The second command line argument should be -AMPL."); + throw std::runtime_error("The second command line argument should be -AMPL"); } // overwrite the default options with the command line arguments diff --git a/uno/Uno.cpp b/uno/Uno.cpp index ce304a1b..abf3bdf5 100644 --- a/uno/Uno.cpp +++ b/uno/Uno.cpp @@ -8,13 +8,14 @@ #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 "tools/Options.hpp" +#include "options/Options.hpp" #include "tools/Statistics.hpp" #include "tools/Timer.hpp" @@ -24,7 +25,7 @@ namespace uno { max_iterations(options.get_unsigned_int("max_iterations")), time_limit(options.get_double("time_limit")), print_solution(options.get_bool("print_solution")), - strategy_combination(this->get_strategy_combination(options)) { } + strategy_combination(Uno::get_strategy_combination(options)) { } Level Logger::level = INFO; @@ -61,7 +62,7 @@ namespace uno { statistics.start_new_line(); statistics.set("status", exception.what()); if (Logger::level == INFO) statistics.print_current_line(); - DEBUG << exception.what(); + DEBUG << exception.what() << '\n'; } if (Logger::level == INFO) statistics.print_footer(); @@ -79,7 +80,7 @@ namespace uno { if (Logger::level == INFO) statistics.print_current_line(); } catch (const std::exception& e) { - DISCRETE << RED << "An error occurred at the initial iterate: " << e.what() << RESET; + DISCRETE << RED << "An error occurred at the initial iterate: " << e.what() << RESET << '\n'; throw; } } @@ -117,17 +118,6 @@ namespace uno { Iterate::number_eval_jacobian, number_hessian_evaluations, number_subproblems_solved}; } - std::string join(const std::vector& vector, const std::string& separator) { - std::string result{}; - if (not vector.empty()) { - result = vector[0]; - for (size_t variable_index: Range(1, vector.size())) { - result += separator + vector[variable_index]; - } - } - return result; - } - void Uno::print_available_strategies() { std::cout << "Available strategies:\n"; std::cout << "- Constraint relaxation strategies: " << join(ConstraintRelaxationStrategyFactory::available_strategies(), ", ") << '\n'; diff --git a/uno/ingredients/constraint_relaxation_strategies/ConstraintRelaxationStrategy.cpp b/uno/ingredients/constraint_relaxation_strategies/ConstraintRelaxationStrategy.cpp index 93778d75..38545965 100644 --- a/uno/ingredients/constraint_relaxation_strategies/ConstraintRelaxationStrategy.cpp +++ b/uno/ingredients/constraint_relaxation_strategies/ConstraintRelaxationStrategy.cpp @@ -14,7 +14,7 @@ #include "reformulation/OptimizationProblem.hpp" #include "symbolic/VectorView.hpp" #include "symbolic/Expression.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" #include "tools/Statistics.hpp" namespace uno { diff --git a/uno/ingredients/constraint_relaxation_strategies/ConstraintRelaxationStrategyFactory.cpp b/uno/ingredients/constraint_relaxation_strategies/ConstraintRelaxationStrategyFactory.cpp index 41b0b1d8..1369bb5c 100644 --- a/uno/ingredients/constraint_relaxation_strategies/ConstraintRelaxationStrategyFactory.cpp +++ b/uno/ingredients/constraint_relaxation_strategies/ConstraintRelaxationStrategyFactory.cpp @@ -5,7 +5,7 @@ #include "ConstraintRelaxationStrategyFactory.hpp" #include "FeasibilityRestoration.hpp" #include "l1Relaxation.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" namespace uno { std::unique_ptr ConstraintRelaxationStrategyFactory::create(const Model& model, const Options& options) { diff --git a/uno/ingredients/constraint_relaxation_strategies/FeasibilityRestoration.cpp b/uno/ingredients/constraint_relaxation_strategies/FeasibilityRestoration.cpp index b7560ccd..a66c095a 100644 --- a/uno/ingredients/constraint_relaxation_strategies/FeasibilityRestoration.cpp +++ b/uno/ingredients/constraint_relaxation_strategies/FeasibilityRestoration.cpp @@ -11,7 +11,7 @@ #include "optimization/Iterate.hpp" #include "optimization/WarmstartInformation.hpp" #include "symbolic/VectorView.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" namespace uno { FeasibilityRestoration::FeasibilityRestoration(const Model& model, const Options& options) : diff --git a/uno/ingredients/constraint_relaxation_strategies/l1Relaxation.cpp b/uno/ingredients/constraint_relaxation_strategies/l1Relaxation.cpp index 50411e93..ef19172d 100644 --- a/uno/ingredients/constraint_relaxation_strategies/l1Relaxation.cpp +++ b/uno/ingredients/constraint_relaxation_strategies/l1Relaxation.cpp @@ -9,7 +9,7 @@ #include "optimization/Iterate.hpp" #include "optimization/WarmstartInformation.hpp" #include "symbolic/VectorView.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" #include "tools/Statistics.hpp" /* @@ -80,7 +80,7 @@ namespace uno { } void l1Relaxation::switch_to_feasibility_problem(Statistics& /*statistics*/, Iterate& /*current_iterate*/) { - throw std::runtime_error("l1Relaxation::switch_to_feasibility_problem is not implemented\n"); + throw std::runtime_error("l1Relaxation::switch_to_feasibility_problem is not implemented"); } // use Byrd's steering rules to update the penalty parameter and compute a descent direction diff --git a/uno/ingredients/globalization_mechanisms/BacktrackingLineSearch.cpp b/uno/ingredients/globalization_mechanisms/BacktrackingLineSearch.cpp index 4d28a764..9ca339b4 100644 --- a/uno/ingredients/globalization_mechanisms/BacktrackingLineSearch.cpp +++ b/uno/ingredients/globalization_mechanisms/BacktrackingLineSearch.cpp @@ -9,7 +9,7 @@ #include "optimization/Iterate.hpp" #include "optimization/WarmstartInformation.hpp" #include "tools/Logger.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" #include "tools/Statistics.hpp" namespace uno { diff --git a/uno/ingredients/globalization_mechanisms/GlobalizationMechanism.cpp b/uno/ingredients/globalization_mechanisms/GlobalizationMechanism.cpp index 354dab69..0c3adbcb 100644 --- a/uno/ingredients/globalization_mechanisms/GlobalizationMechanism.cpp +++ b/uno/ingredients/globalization_mechanisms/GlobalizationMechanism.cpp @@ -6,7 +6,7 @@ #include "model/Model.hpp" #include "optimization/Iterate.hpp" #include "symbolic/Expression.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" namespace uno { GlobalizationMechanism::GlobalizationMechanism(ConstraintRelaxationStrategy& constraint_relaxation_strategy) : diff --git a/uno/ingredients/globalization_mechanisms/GlobalizationMechanismFactory.cpp b/uno/ingredients/globalization_mechanisms/GlobalizationMechanismFactory.cpp index b1f80223..b045bff9 100644 --- a/uno/ingredients/globalization_mechanisms/GlobalizationMechanismFactory.cpp +++ b/uno/ingredients/globalization_mechanisms/GlobalizationMechanismFactory.cpp @@ -7,7 +7,7 @@ #include "ingredients/constraint_relaxation_strategies/ConstraintRelaxationStrategy.hpp" #include "ingredients/globalization_mechanisms/TrustRegionStrategy.hpp" #include "ingredients/globalization_mechanisms/BacktrackingLineSearch.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" namespace uno { std::unique_ptr GlobalizationMechanismFactory::create( diff --git a/uno/ingredients/globalization_mechanisms/TrustRegionStrategy.cpp b/uno/ingredients/globalization_mechanisms/TrustRegionStrategy.cpp index 3c5ba6cf..e3f8f672 100644 --- a/uno/ingredients/globalization_mechanisms/TrustRegionStrategy.cpp +++ b/uno/ingredients/globalization_mechanisms/TrustRegionStrategy.cpp @@ -10,7 +10,7 @@ #include "optimization/Iterate.hpp" #include "optimization/WarmstartInformation.hpp" #include "tools/Logger.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" #include "tools/Statistics.hpp" namespace uno { diff --git a/uno/ingredients/globalization_strategies/GlobalizationStrategy.cpp b/uno/ingredients/globalization_strategies/GlobalizationStrategy.cpp index cf70708e..98e1d4bd 100644 --- a/uno/ingredients/globalization_strategies/GlobalizationStrategy.cpp +++ b/uno/ingredients/globalization_strategies/GlobalizationStrategy.cpp @@ -3,7 +3,7 @@ #include #include "GlobalizationStrategy.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" namespace uno { GlobalizationStrategy::GlobalizationStrategy(const Options& options): diff --git a/uno/ingredients/globalization_strategies/l1MeritFunction.cpp b/uno/ingredients/globalization_strategies/l1MeritFunction.cpp index 6be8a3ed..508e8fea 100644 --- a/uno/ingredients/globalization_strategies/l1MeritFunction.cpp +++ b/uno/ingredients/globalization_strategies/l1MeritFunction.cpp @@ -4,7 +4,7 @@ #include "l1MeritFunction.hpp" #include "ProgressMeasures.hpp" #include "tools/Logger.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" #include "tools/Statistics.hpp" namespace uno { diff --git a/uno/ingredients/globalization_strategies/switching_methods/SwitchingMethod.cpp b/uno/ingredients/globalization_strategies/switching_methods/SwitchingMethod.cpp index 645480d1..c400c507 100644 --- a/uno/ingredients/globalization_strategies/switching_methods/SwitchingMethod.cpp +++ b/uno/ingredients/globalization_strategies/switching_methods/SwitchingMethod.cpp @@ -6,7 +6,7 @@ #include "../ProgressMeasures.hpp" #include "optimization/Iterate.hpp" #include "tools/Logger.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" #include "tools/Statistics.hpp" namespace uno { diff --git a/uno/ingredients/globalization_strategies/switching_methods/filter_methods/FilterMethod.cpp b/uno/ingredients/globalization_strategies/switching_methods/filter_methods/FilterMethod.cpp index 93cdc85a..01df1aca 100644 --- a/uno/ingredients/globalization_strategies/switching_methods/filter_methods/FilterMethod.cpp +++ b/uno/ingredients/globalization_strategies/switching_methods/filter_methods/FilterMethod.cpp @@ -5,7 +5,7 @@ #include "filters/Filter.hpp" #include "filters/FilterFactory.hpp" #include "optimization/Iterate.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" #include "tools/Statistics.hpp" namespace uno { diff --git a/uno/ingredients/globalization_strategies/switching_methods/filter_methods/FletcherFilterMethod.cpp b/uno/ingredients/globalization_strategies/switching_methods/filter_methods/FletcherFilterMethod.cpp index 18789625..b62e045d 100644 --- a/uno/ingredients/globalization_strategies/switching_methods/filter_methods/FletcherFilterMethod.cpp +++ b/uno/ingredients/globalization_strategies/switching_methods/filter_methods/FletcherFilterMethod.cpp @@ -6,7 +6,7 @@ #include "ingredients/globalization_strategies/ProgressMeasures.hpp" #include "optimization/Iterate.hpp" #include "tools/Logger.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" #include "tools/Statistics.hpp" namespace uno { diff --git a/uno/ingredients/globalization_strategies/switching_methods/filter_methods/WaechterFilterMethod.cpp b/uno/ingredients/globalization_strategies/switching_methods/filter_methods/WaechterFilterMethod.cpp index 46e0da9d..54454d05 100644 --- a/uno/ingredients/globalization_strategies/switching_methods/filter_methods/WaechterFilterMethod.cpp +++ b/uno/ingredients/globalization_strategies/switching_methods/filter_methods/WaechterFilterMethod.cpp @@ -6,7 +6,7 @@ #include "ingredients/globalization_strategies/ProgressMeasures.hpp" #include "optimization/Iterate.hpp" #include "tools/Logger.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" #include "tools/Statistics.hpp" namespace uno { diff --git a/uno/ingredients/globalization_strategies/switching_methods/filter_methods/filters/Filter.cpp b/uno/ingredients/globalization_strategies/switching_methods/filter_methods/filters/Filter.cpp index 894bbb3d..b1001aab 100644 --- a/uno/ingredients/globalization_strategies/switching_methods/filter_methods/filters/Filter.cpp +++ b/uno/ingredients/globalization_strategies/switching_methods/filter_methods/filters/Filter.cpp @@ -8,7 +8,7 @@ #include "Filter.hpp" #include "symbolic/Range.hpp" #include "tools/Logger.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" namespace uno { Filter::Filter(const Options& options) : diff --git a/uno/ingredients/globalization_strategies/switching_methods/filter_methods/filters/FilterFactory.cpp b/uno/ingredients/globalization_strategies/switching_methods/filter_methods/filters/FilterFactory.cpp index 15f8b3e2..5a194e4f 100644 --- a/uno/ingredients/globalization_strategies/switching_methods/filter_methods/filters/FilterFactory.cpp +++ b/uno/ingredients/globalization_strategies/switching_methods/filter_methods/filters/FilterFactory.cpp @@ -4,7 +4,7 @@ #include #include "FilterFactory.hpp" #include "NonmonotoneFilter.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" namespace uno { // FilterFactory class diff --git a/uno/ingredients/globalization_strategies/switching_methods/filter_methods/filters/NonmonotoneFilter.cpp b/uno/ingredients/globalization_strategies/switching_methods/filter_methods/filters/NonmonotoneFilter.cpp index fb9c4ad2..02e33232 100644 --- a/uno/ingredients/globalization_strategies/switching_methods/filter_methods/filters/NonmonotoneFilter.cpp +++ b/uno/ingredients/globalization_strategies/switching_methods/filter_methods/filters/NonmonotoneFilter.cpp @@ -4,7 +4,7 @@ #include "NonmonotoneFilter.hpp" #include "symbolic/Range.hpp" #include "tools/Logger.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" namespace uno { NonmonotoneFilter::NonmonotoneFilter(const Options& options) : diff --git a/uno/ingredients/globalization_strategies/switching_methods/funnel_methods/Funnel.cpp b/uno/ingredients/globalization_strategies/switching_methods/funnel_methods/Funnel.cpp index 9fa5e919..a5943ba0 100644 --- a/uno/ingredients/globalization_strategies/switching_methods/funnel_methods/Funnel.cpp +++ b/uno/ingredients/globalization_strategies/switching_methods/funnel_methods/Funnel.cpp @@ -3,7 +3,7 @@ #include "Funnel.hpp" #include "tools/Logger.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" namespace uno { Funnel::Funnel(const Options& options): @@ -48,7 +48,7 @@ namespace uno { this->width = this->margin * this->width; } else { - throw std::runtime_error("Funnel update strategy " + std::to_string(this->update_strategy) + " is unknown."); + throw std::runtime_error("Funnel update strategy " + std::to_string(this->update_strategy) + " is unknown"); } DEBUG << "\t\tNew funnel parameter is: " << this->width << '\n'; } diff --git a/uno/ingredients/globalization_strategies/switching_methods/funnel_methods/FunnelMethod.cpp b/uno/ingredients/globalization_strategies/switching_methods/funnel_methods/FunnelMethod.cpp index 4a047e83..a2b70d9d 100644 --- a/uno/ingredients/globalization_strategies/switching_methods/funnel_methods/FunnelMethod.cpp +++ b/uno/ingredients/globalization_strategies/switching_methods/funnel_methods/FunnelMethod.cpp @@ -4,7 +4,7 @@ #include "FunnelMethod.hpp" #include "../../ProgressMeasures.hpp" #include "optimization/Iterate.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" #include "tools/Logger.hpp" #include "tools/Statistics.hpp" diff --git a/uno/ingredients/hessian_models/ConvexifiedHessian.cpp b/uno/ingredients/hessian_models/ConvexifiedHessian.cpp index a792755a..e0f16d4f 100644 --- a/uno/ingredients/hessian_models/ConvexifiedHessian.cpp +++ b/uno/ingredients/hessian_models/ConvexifiedHessian.cpp @@ -6,14 +6,14 @@ #include "solvers/DirectSymmetricIndefiniteLinearSolver.hpp" #include "solvers/SymmetricIndefiniteLinearSolverFactory.hpp" #include "tools/Logger.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" #include "tools/Statistics.hpp" namespace uno { ConvexifiedHessian::ConvexifiedHessian(size_t dimension, size_t maximum_number_nonzeros, const Options& options): HessianModel(dimension, maximum_number_nonzeros, options.get_string("sparse_format"), /* use_regularization = */true), // inertia-based convexification needs a linear solver - linear_solver(SymmetricIndefiniteLinearSolverFactory::create(options.get_string("linear_solver"), dimension, maximum_number_nonzeros)), + linear_solver(SymmetricIndefiniteLinearSolverFactory::create(dimension, maximum_number_nonzeros, options)), regularization_initial_value(options.get_double("regularization_initial_value")), regularization_increase_factor(options.get_double("regularization_increase_factor")) { } @@ -50,7 +50,6 @@ namespace uno { symbolic_factorization_performed = true; } this->linear_solver->do_numerical_factorization(hessian); - if (this->linear_solver->rank() == number_original_variables && this->linear_solver->number_negative_eigenvalues() == 0) { good_inertia = true; DEBUG << "Factorization was a success\n"; diff --git a/uno/ingredients/hessian_models/ExactHessian.cpp b/uno/ingredients/hessian_models/ExactHessian.cpp index ad729f32..16886885 100644 --- a/uno/ingredients/hessian_models/ExactHessian.cpp +++ b/uno/ingredients/hessian_models/ExactHessian.cpp @@ -3,7 +3,7 @@ #include "ExactHessian.hpp" #include "reformulation/OptimizationProblem.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" namespace uno { // exact Hessian diff --git a/uno/ingredients/hessian_models/ZeroHessian.cpp b/uno/ingredients/hessian_models/ZeroHessian.cpp index 09a692c2..ab4e80ae 100644 --- a/uno/ingredients/hessian_models/ZeroHessian.cpp +++ b/uno/ingredients/hessian_models/ZeroHessian.cpp @@ -3,7 +3,7 @@ #include "ZeroHessian.hpp" #include "reformulation/OptimizationProblem.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" namespace uno { ZeroHessian::ZeroHessian(size_t dimension, const Options& options) : diff --git a/uno/ingredients/subproblems/SubproblemFactory.cpp b/uno/ingredients/subproblems/SubproblemFactory.cpp index b666484c..9820c522 100644 --- a/uno/ingredients/subproblems/SubproblemFactory.cpp +++ b/uno/ingredients/subproblems/SubproblemFactory.cpp @@ -9,7 +9,7 @@ #include "ingredients/subproblems/interior_point_methods/PrimalDualInteriorPointSubproblem.hpp" #include "solvers/QPSolverFactory.hpp" #include "solvers/SymmetricIndefiniteLinearSolverFactory.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" namespace uno { std::unique_ptr SubproblemFactory::create(size_t number_variables, size_t number_constraints, size_t number_objective_gradient_nonzeros, diff --git a/uno/ingredients/subproblems/inequality_constrained_methods/InequalityConstrainedMethod.cpp b/uno/ingredients/subproblems/inequality_constrained_methods/InequalityConstrainedMethod.cpp index 514bae8d..d2fc14a2 100644 --- a/uno/ingredients/subproblems/inequality_constrained_methods/InequalityConstrainedMethod.cpp +++ b/uno/ingredients/subproblems/inequality_constrained_methods/InequalityConstrainedMethod.cpp @@ -5,7 +5,7 @@ #include "ingredients/subproblems/Direction.hpp" #include "linear_algebra/Vector.hpp" #include "reformulation/l1RelaxedProblem.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" #include "symbolic/VectorView.hpp" namespace uno { diff --git a/uno/ingredients/subproblems/inequality_constrained_methods/LPSubproblem.cpp b/uno/ingredients/subproblems/inequality_constrained_methods/LPSubproblem.cpp index af138a39..87648434 100644 --- a/uno/ingredients/subproblems/inequality_constrained_methods/LPSubproblem.cpp +++ b/uno/ingredients/subproblems/inequality_constrained_methods/LPSubproblem.cpp @@ -3,18 +3,17 @@ #include "LPSubproblem.hpp" #include "ingredients/subproblems/Direction.hpp" -#include "linear_algebra/COOSparseStorage.hpp" #include "optimization/WarmstartInformation.hpp" #include "reformulation/OptimizationProblem.hpp" #include "solvers/LPSolver.hpp" #include "solvers/LPSolverFactory.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" namespace uno { LPSubproblem::LPSubproblem(size_t number_variables, size_t number_constraints, size_t number_objective_gradient_nonzeros, size_t number_jacobian_nonzeros, const Options& options) : InequalityConstrainedMethod("zero", number_variables, number_constraints, 0, false, options), - solver(LPSolverFactory::create(options.get_string("LP_solver"), number_variables, number_constraints, + solver(LPSolverFactory::create(number_variables, number_constraints, number_objective_gradient_nonzeros, number_jacobian_nonzeros, options)), zero_hessian(SymmetricMatrix::zero(number_variables)) { } diff --git a/uno/ingredients/subproblems/inequality_constrained_methods/QPSubproblem.cpp b/uno/ingredients/subproblems/inequality_constrained_methods/QPSubproblem.cpp index 837068fa..e3f3b1d1 100644 --- a/uno/ingredients/subproblems/inequality_constrained_methods/QPSubproblem.cpp +++ b/uno/ingredients/subproblems/inequality_constrained_methods/QPSubproblem.cpp @@ -12,7 +12,7 @@ #include "solvers/DirectSymmetricIndefiniteLinearSolver.hpp" #include "solvers/QPSolver.hpp" #include "solvers/QPSolverFactory.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" #include "tools/Statistics.hpp" namespace uno { @@ -23,8 +23,7 @@ namespace uno { use_regularization(options.get_string("globalization_mechanism") != "TR" || options.get_bool("convexify_QP")), enforce_linear_constraints_at_initial_iterate(options.get_bool("enforce_linear_constraints")), // maximum number of Hessian nonzeros = number nonzeros + possible diagonal inertia correction - solver(QPSolverFactory::create(options.get_string("QP_solver"), number_variables, number_constraints, - number_objective_gradient_nonzeros, number_jacobian_nonzeros, + solver(QPSolverFactory::create(number_variables, number_constraints, number_objective_gradient_nonzeros, number_jacobian_nonzeros, // if the QP solver is used during preprocessing, we need to allocate the Hessian with at least number_variables elements std::max(this->enforce_linear_constraints_at_initial_iterate ? number_variables : 0, hessian_model->hessian.capacity()), options)) { diff --git a/uno/ingredients/subproblems/interior_point_methods/BarrierParameterUpdateStrategy.cpp b/uno/ingredients/subproblems/interior_point_methods/BarrierParameterUpdateStrategy.cpp index f1b8256b..7cb67a6d 100644 --- a/uno/ingredients/subproblems/interior_point_methods/BarrierParameterUpdateStrategy.cpp +++ b/uno/ingredients/subproblems/interior_point_methods/BarrierParameterUpdateStrategy.cpp @@ -8,7 +8,7 @@ #include "reformulation/OptimizationProblem.hpp" #include "symbolic/VectorExpression.hpp" #include "tools/Logger.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" namespace uno { BarrierParameterUpdateStrategy::BarrierParameterUpdateStrategy(const Options& options): diff --git a/uno/ingredients/subproblems/interior_point_methods/PrimalDualInteriorPointSubproblem.cpp b/uno/ingredients/subproblems/interior_point_methods/PrimalDualInteriorPointSubproblem.cpp index 309b7544..cf67f14b 100644 --- a/uno/ingredients/subproblems/interior_point_methods/PrimalDualInteriorPointSubproblem.cpp +++ b/uno/ingredients/subproblems/interior_point_methods/PrimalDualInteriorPointSubproblem.cpp @@ -27,11 +27,12 @@ namespace uno { + number_jacobian_nonzeros /* Jacobian */, true, /* use regularization */ options), - linear_solver(SymmetricIndefiniteLinearSolverFactory::create(options.get_string("linear_solver"), number_variables + number_constraints, + linear_solver(SymmetricIndefiniteLinearSolverFactory::create(number_variables + number_constraints, number_hessian_nonzeros + number_variables + number_constraints /* regularization */ + 2 * number_variables /* diagonal barrier terms */ - + number_jacobian_nonzeros /* Jacobian */)), + + number_jacobian_nonzeros, /* Jacobian */ + options)), barrier_parameter_update_strategy(options), previous_barrier_parameter(options.get_double("barrier_initial_parameter")), default_multiplier(options.get_double("barrier_default_multiplier")), @@ -55,7 +56,7 @@ namespace uno { inline void PrimalDualInteriorPointSubproblem::generate_initial_iterate(const OptimizationProblem& problem, Iterate& initial_iterate) { if (problem.has_inequality_constraints()) { - throw std::runtime_error("The problem has inequality constraints. Create an instance of HomogeneousEqualityConstrainedModel.\n"); + throw std::runtime_error("The problem has inequality constraints. Create an instance of HomogeneousEqualityConstrainedModel"); } // TODO: enforce linear constraints at initial point @@ -172,10 +173,10 @@ namespace uno { void PrimalDualInteriorPointSubproblem::solve(Statistics& statistics, const OptimizationProblem& problem, Iterate& current_iterate, const Multipliers& current_multipliers, Direction& direction, const WarmstartInformation& warmstart_information) { if (problem.has_inequality_constraints()) { - throw std::runtime_error("The problem has inequality constraints. Create an instance of HomogeneousEqualityConstrainedModel."); + throw std::runtime_error("The problem has inequality constraints. Create an instance of HomogeneousEqualityConstrainedModel"); } if (is_finite(this->trust_region_radius)) { - throw std::runtime_error("The interior-point subproblem has a trust region. This is not implemented yet."); + throw std::runtime_error("The interior-point subproblem has a trust region. This is not implemented yet"); } // possibly update the barrier parameter diff --git a/uno/linear_algebra/SymmetricIndefiniteLinearSystem.hpp b/uno/linear_algebra/SymmetricIndefiniteLinearSystem.hpp index c88fe154..e920e919 100644 --- a/uno/linear_algebra/SymmetricIndefiniteLinearSystem.hpp +++ b/uno/linear_algebra/SymmetricIndefiniteLinearSystem.hpp @@ -10,7 +10,7 @@ #include "RectangularMatrix.hpp" #include "model/Model.hpp" #include "solvers/DirectSymmetricIndefiniteLinearSolver.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" #include "tools/Statistics.hpp" namespace uno { diff --git a/uno/linear_algebra/Vector.hpp b/uno/linear_algebra/Vector.hpp index 79b8c36a..7a5d7f6c 100644 --- a/uno/linear_algebra/Vector.hpp +++ b/uno/linear_algebra/Vector.hpp @@ -124,6 +124,18 @@ namespace uno { result[index] -= expression[index]; } } + + template + std::string join(const Container& vector, const std::string& separator) { + std::string result{}; + if (not vector.empty()) { + result = vector[0]; + for (size_t variable_index: Range(1, vector.size())) { + result += separator + vector[variable_index]; + } + } + return result; + } } // namespace #endif // UNO_VECTOR_H diff --git a/uno/model/BoundRelaxedModel.hpp b/uno/model/BoundRelaxedModel.hpp index 81186021..14bccea1 100644 --- a/uno/model/BoundRelaxedModel.hpp +++ b/uno/model/BoundRelaxedModel.hpp @@ -6,7 +6,7 @@ #include "Model.hpp" #include "optimization/Iterate.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" namespace uno { class BoundRelaxedModel: public Model { diff --git a/uno/model/ModelFactory.cpp b/uno/model/ModelFactory.cpp index b8b1e7c6..d59bdcb5 100644 --- a/uno/model/ModelFactory.cpp +++ b/uno/model/ModelFactory.cpp @@ -6,7 +6,7 @@ #include "ScaledModel.hpp" #include "BoundRelaxedModel.hpp" #include "optimization/Iterate.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" namespace uno { // note: ownership of the pointer is transferred diff --git a/uno/model/ScaledModel.hpp b/uno/model/ScaledModel.hpp index 0673afe9..5a5a7a6d 100644 --- a/uno/model/ScaledModel.hpp +++ b/uno/model/ScaledModel.hpp @@ -7,7 +7,7 @@ #include "Model.hpp" #include "optimization/Iterate.hpp" #include "preprocessing/Scaling.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" namespace uno { class ScaledModel: public Model { diff --git a/uno/options/DefaultOptions.cpp b/uno/options/DefaultOptions.cpp new file mode 100644 index 00000000..7d5d1e19 --- /dev/null +++ b/uno/options/DefaultOptions.cpp @@ -0,0 +1,220 @@ +// Copyright (c) 2024 Charlie Vanaret +// Licensed under the MIT license. See LICENSE file in the project directory for details. + +#include "DefaultOptions.hpp" +#include "solvers/QPSolverFactory.hpp" +#include "solvers/LPSolverFactory.hpp" +#include "solvers/SymmetricIndefiniteLinearSolverFactory.hpp" + +namespace uno { + Options DefaultOptions::load() { + Options options(true); + /** termination **/ + // (tight) tolerance + options["tolerance"] = "1e-8"; + // loose tolerance used if tight tolerance cannot be reached + options["loose_tolerance"] = "1e-6"; + // number of iterations during which the loose tolerance is monitored + options["loose_tolerance_consecutive_iteration_threshold"] = "15"; + // maximum outer iterations + options["max_iterations"] = "2000"; + // CPU time limit (in seconds) + options["time_limit"] = "inf"; + // print optimal solution (yes|no) + options["print_solution"] = "yes"; + // threshold on objective to declare unbounded NLP + options["unbounded_objective_threshold"] = "-1e20"; + // enforce linear constraints at the initial point (yes|no) + options["enforce_linear_constraints"] = "no"; + + /** statistics table **/ + options["statistics_print_header_every_iterations"] = "15"; + options["statistics_major_column_order"] = "1"; + options["statistics_minor_column_order"] = "2"; + options["statistics_penalty_parameter_column_order"] = "5"; + options["statistics_barrier_parameter_column_order"] = "8"; + options["statistics_SOC_column_order"] = "9"; + options["statistics_TR_radius_column_order"] = "10"; + options["statistics_LS_step_length_column_order"] = "10"; + options["statistics_restoration_phase_column_order"] = "20"; + options["statistics_regularization_column_order"] = "21"; + options["statistics_funnel_width_column_order"] = "25"; + options["statistics_step_norm_column_order"] = "31"; + options["statistics_objective_column_order"] = "100"; + options["statistics_primal_feasibility_column_order"] = "101"; + options["statistics_dual_feasibility_column_order"] = "102"; + options["statistics_stationarity_column_order"] = "104"; + options["statistics_complementarity_column_order"] = "105"; + options["statistics_status_column_order"] = "200"; + + /** main options **/ + // logging level (SILENT|DISCRETE|WARNING|INFO|DEBUG|DEBUG2|DEBUG3) + options["logger"] = "INFO"; + // Hessian model (exact|zero) + options["hessian_model"] = "exact"; + // sparse matrix format (COO|CSC) + options["sparse_format"] = "COO"; + // scale the functions (yes|no) + options["scale_functions"] = "no"; + options["function_scaling_threshold"] = "100"; + // factor scaling + options["function_scaling_factor"] = "100"; + // scale the errors with respect to the current point (yes|no) + options["scale_residuals"] = "yes"; + // norm of the progress measures (L1|L2|INF) + options["progress_norm"] = "L1"; + // norm of the primal-dual residuals (L1|L2|INF) + options["residual_norm"] = "INF"; + options["residual_scaling_threshold"] = "100."; + options["protect_actual_reduction_against_roundoff"] = "no"; + + /** globalization strategy options **/ + options["armijo_decrease_fraction"] = "1e-4"; + options["armijo_tolerance"] = "1e-9"; + + /** switching method options **/ + options["switching_delta"] = "0.999"; + options["switching_infeasibility_exponent"] = "2"; + + /** filter method options **/ + // filter type (standard|nonmonotone) + options["filter_type"] = "standard"; + options["filter_beta"] = "0.999"; + options["filter_gamma"] = "0.001"; + options["filter_ubd"] = "1e2"; + options["filter_fact"] = "1.25"; + options["filter_capacity"] = "50"; + // used by Waechter filter method + options["filter_sufficient_infeasibility_decrease_factor"] = "0.9"; + // nonmonotone filter strategy + options["nonmonotone_filter_number_dominated_entries"] = "3"; + + /** funnel options **/ + options["funnel_kappa"] = "0.5"; + options["funnel_beta"] = "0.9999"; + options["funnel_gamma"] = "0.001"; + options["funnel_ubd"] = "1.0"; + options["funnel_fact"] = "1.5"; + options["funnel_update_strategy"] = "1"; + options["funnel_require_acceptance_wrt_current_iterate"] = "no"; + + /** line search options */ + // backtracking ratio + options["LS_backtracking_ratio"] = "0.5"; + // minimum step length + options["LS_min_step_length"] = "1e-12"; + // use the primal-dual and dual step lengths to scale the dual directions when assembling the trial iterate + options["LS_scale_duals_with_step_length"] = "yes"; + + /** regularization options **/ + // regularization failure threshold + options["regularization_failure_threshold"] = "1e40"; + // Hessian regularization: initial value + options["regularization_initial_value"] = "1e-4"; + options["regularization_increase_factor"] = "2"; + // regularization of augmented system + options["primal_regularization_initial_factor"] = "1e-4"; + options["dual_regularization_fraction"] = "1e-8"; + options["primal_regularization_lb"] = "1e-20"; + options["primal_regularization_decrease_factor"] = "3."; + options["primal_regularization_fast_increase_factor"] = "100."; + options["primal_regularization_slow_increase_factor"] = "8."; + options["threshold_unsuccessful_attempts"] = "8"; + + /** trust region options **/ + // initial trust region radius + options["TR_radius"] = "10."; + // TR radius increase factor + options["TR_increase_factor"] = "2"; + // TR radius decrease factor + options["TR_decrease_factor"] = "2"; + // TR aggressive radius decrease factor + options["TR_aggressive_decrease_factor"] = "4"; + // tolerance in TR constraint activity + options["TR_activity_tolerance"] = "1e-6"; + // minimum TR radius + options["TR_min_radius"] = "1e-7"; + // threshold below which the TR radius is reset + options["TR_radius_reset_threshold"] = "1e-4"; + // force QP convexification when in a trust-region setting + options["convexify_QP"] = "false"; + + /** constraint relaxation options **/ + // l1 relaxation options // + // initial value of the penalty parameter + options["l1_relaxation_initial_parameter"] = "1."; + // use a fixed parameter (yes|no) + options["l1_relaxation_fixed_parameter"] = "no"; + // decrease (multiplicative) factor of penalty parameter + options["l1_relaxation_decrease_factor"] = "10."; + // epsilon constants in Byrd's article + options["l1_relaxation_epsilon1"] = "0.1"; + options["l1_relaxation_epsilon2"] = "0.1"; + options["l1_relaxation_residual_small_threshold"] = "1e-12"; + // coefficient of constraint violation + options["l1_constraint_violation_coefficient"] = "1"; + // threshold for determining if duals have a zero norm + options["l1_small_duals_threshold"] = "1e-10"; + + /** feasibility restoration options **/ + // test linearized feasibility when switching back to the optimality phase + options["switch_to_optimality_requires_linearized_feasibility"] = "yes"; + + /** barrier subproblem options **/ + options["barrier_initial_parameter"] = "0.1"; + options["barrier_default_multiplier"] = "1"; + // Ipopt parameters + options["barrier_tau_min"] = "0.99"; + options["barrier_k_sigma"] = "1e10"; + options["barrier_smax"] = "100"; + options["barrier_k_mu"] = "0.2"; + options["barrier_theta_mu"] = "1.5"; + options["barrier_k_epsilon"] = "10"; + options["barrier_update_fraction"] = "10"; + options["barrier_regularization_exponent"] = "0.25"; + options["barrier_small_direction_factor"] = "10."; + options["barrier_push_variable_to_interior_k1"] = "1e-2"; + options["barrier_push_variable_to_interior_k2"] = "1e-2"; + options["barrier_damping_factor"] = "1e-5"; + options["least_square_multiplier_max_norm"] = "1e3"; + + /** BQPD options **/ + options["BQPD_print_subproblem"] = "no"; + options["BQPD_kmax"] = "500"; + + /** AMPL options **/ + options["AMPL_write_solution_to_file"] = "yes"; + + /** solvers: check the available solvers **/ + // QP solver + const auto QP_solvers = QPSolverFactory::available_solvers(); + if (not QP_solvers.empty()) { + options["QP_solver"] = QP_solvers[0]; + //options.is_default["QP_solver"] = false; + } + // LP solver + const auto LP_solvers = LPSolverFactory::available_solvers(); + if (not LP_solvers.empty()) { + options["LP_solver"] = LP_solvers[0]; + //options.is_default["LP_solver"] = false; + } + // linear solver + const auto linear_solvers = SymmetricIndefiniteLinearSolverFactory::available_solvers(); + if (not linear_solvers.empty()) { + options["linear_solver"] = linear_solvers[0]; + //options.is_default["linear_solver"] = false; + } + + /** ingredients **/ + // default constraint relaxation strategy (feasibility_restoration|l1_relaxation) + options["constraint_relaxation_strategy"] = "feasibility_restoration"; + // default subproblem (QP|LP|primal_dual_interior_point) + options["subproblem"] = "QP"; + // default globalization strategy (l1_merit|fletcher_filter_method|waechter_filter_method) + options["globalization_strategy"] = "fletcher_filter_method"; + // default globalization mechanism (TR|LS) + options["globalization_mechanism"] = "TR"; + + return options; + } +} // namespace \ No newline at end of file diff --git a/uno/options/DefaultOptions.hpp b/uno/options/DefaultOptions.hpp new file mode 100644 index 00000000..c88fa6a7 --- /dev/null +++ b/uno/options/DefaultOptions.hpp @@ -0,0 +1,16 @@ +// Copyright (c) 2024 Charlie Vanaret +// Licensed under the MIT license. See LICENSE file in the project directory for details. + +#ifndef UNO_DEFAULTOPTIONS_H +#define UNO_DEFAULTOPTIONS_H + +#include "Options.hpp" + +namespace uno { + class DefaultOptions { + public: + [[nodiscard]] static Options load(); + }; +} // namespace + +#endif // UNO_DEFAULTOPTIONS_H \ No newline at end of file diff --git a/uno/options/Options.cpp b/uno/options/Options.cpp new file mode 100644 index 00000000..f6fb4009 --- /dev/null +++ b/uno/options/Options.cpp @@ -0,0 +1,234 @@ +// Copyright (c) 2018-2024 Charlie Vanaret +// Licensed under the MIT license. See LICENSE file in the project directory for details. + +#include +#include +#include "Options.hpp" +#include "tools/Logger.hpp" + +namespace uno { + Options::Options(bool are_default_options): are_default_options(are_default_options) { } + + size_t Options::size() const { + return this->options.size(); + } + + // setter + std::string& Options::operator[](const std::string& option_name) { + this->is_default[option_name] = this->are_default_options; + return this->options[option_name]; + } + + // getter + const std::string& Options::at(const std::string& option_name) const { + try { + const std::string& option_value = this->options.at(option_name); + this->used[option_name] = true; + return option_value; + } + catch(const std::out_of_range&) { + throw std::out_of_range("The option with name " + option_name + " was not found"); + } + } + + const std::string& Options::get_string(const std::string& option_name) const { + return this->at(option_name); + } + + double Options::get_double(const std::string& option_name) const { + const std::string& entry = this->at(option_name); + return std::stod(entry); + } + + int Options::get_int(const std::string& option_name) const { + const std::string& entry = this->at(option_name); + return std::stoi(entry); + } + + size_t Options::get_unsigned_int(const std::string& option_name) const { + const std::string& entry = this->at(option_name); + return std::stoul(entry); + } + + bool Options::get_bool(const std::string& option_name) const { + const std::string& entry = this->at(option_name); + return entry == "yes"; + } + + // argv[i] for i = 3..argc-1 are overwriting options + Options Options::get_command_line_options(int argc, char* argv[]) { + static const std::string delimiter = "="; + Options overwriting_options(false); + + // build the (name, value) map + for (size_t i = 3; i < static_cast(argc); i++) { + const std::string argument = std::string(argv[i]); + size_t position = argument.find_first_of(delimiter); + if (position == std::string::npos) { + throw std::runtime_error("The option " + argument + " does not contain the delimiter " + delimiter); + } + const std::string option_name = argument.substr(0, position); + const std::string option_value = argument.substr(position + 1); + if (option_name == "preset") { + Options::set_preset(overwriting_options, option_value); + } + else if (option_name == "option_file") { + Options::overwrite_with_option_file(overwriting_options, option_value); + } + else { + overwriting_options[option_name] = option_value; + } + } + return overwriting_options; + } + + void Options::overwrite_with_option_file(Options& options, const std::string& file_name) { + std::ifstream file; + file.open(file_name); + if (!file) { + throw std::invalid_argument("The option file " + file_name + " was not found"); + } + else { + std::string option_name, option_value; + std::string line; + while (std::getline(file, line)) { + if (not line.empty() && line.find('#') != 0) { + std::istringstream iss; + iss.str(line); + iss >> option_name >> option_value; + options[option_name] = option_value; + } + } + file.close(); + } + } + + void Options::set_preset(Options& options, const std::string& preset_name) { + // shortcuts for state-of-the-art combinations + if (preset_name == "ipopt") { + options["constraint_relaxation_strategy"] = "feasibility_restoration"; + options["subproblem"] = "primal_dual_interior_point"; + options["globalization_mechanism"] = "LS"; + options["globalization_strategy"] = "waechter_filter_method"; + options["filter_type"] = "standard"; + options["filter_beta"] = "0.99999"; + options["filter_gamma"] = "1e-8"; + options["switching_delta"] = "1"; + options["filter_ubd"] = "1e4"; + options["filter_fact"] = "1e4"; + options["filter_switching_infeasibility_exponent"] = "1.1"; + options["armijo_decrease_fraction"] = "1e-8"; + options["LS_backtracking_ratio"] = "0.5"; + options["LS_min_step_length"] = "5e-7"; + options["barrier_tau_min"] = "0.99"; + options["barrier_damping_factor"] = "1e-5"; + options["l1_constraint_violation_coefficient"] = "1000."; + options["progress_norm"] = "L1"; + options["residual_norm"] = "INF"; + options["scale_functions"] = "yes"; + options["sparse_format"] = "COO"; + options["tolerance"] = "1e-8"; + options["loose_tolerance"] = "1e-6"; + options["loose_tolerance_consecutive_iteration_threshold"] = "15"; + options["switch_to_optimality_requires_linearized_feasibility"] = "no"; + options["LS_scale_duals_with_step_length"] = "yes"; + options["protect_actual_reduction_against_roundoff"] = "yes"; + } + else if (preset_name == "filtersqp") { + options["constraint_relaxation_strategy"] = "feasibility_restoration"; + options["subproblem"] = "QP"; + options["globalization_mechanism"] = "TR"; + options["globalization_strategy"] = "fletcher_filter_method"; + options["filter_type"] = "standard"; + options["progress_norm"] = "L1"; + options["residual_norm"] = "L2"; + options["sparse_format"] = "CSC"; + options["TR_radius"] = "10"; + options["l1_constraint_violation_coefficient"] = "1."; + options["enforce_linear_constraints"] = "yes"; + options["tolerance"] = "1e-6"; + options["loose_tolerance"] = "1e-6"; + options["TR_min_radius"] = "1e-8"; + options["switch_to_optimality_requires_linearized_feasibility"] = "yes"; + options["protect_actual_reduction_against_roundoff"] = "no"; + } + else if (preset_name == "byrd") { + options["constraint_relaxation_strategy"] = "l1_relaxation"; + options["subproblem"] = "QP"; + options["globalization_mechanism"] = "LS"; + options["globalization_strategy"] = "l1_merit"; + options["l1_relaxation_initial_parameter"] = "1"; + options["LS_backtracking_ratio"] = "0.5"; + options["armijo_decrease_fraction"] = "1e-8"; + options["l1_relaxation_epsilon1"] = "0.1"; + options["l1_relaxation_epsilon2"] = "0.1"; + options["l1_constraint_violation_coefficient"] = "1."; + options["tolerance"] = "1e-6"; + options["loose_tolerance"] = "1e-6"; + options["progress_norm"] = "L1"; + options["residual_norm"] = "L1"; + options["sparse_format"] = "CSC"; + options["LS_scale_duals_with_step_length"] = "no"; + options["protect_actual_reduction_against_roundoff"] = "no"; + } + else if (preset_name == "funnelsqp") { + options["constraint_relaxation_strategy"] = "feasibility_restoration"; + options["subproblem"] = "QP"; + options["globalization_mechanism"] = "TR"; + options["globalization_strategy"] = "funnel_method"; + options["progress_norm"] = "L1"; + options["residual_norm"] = "L2"; + options["sparse_format"] = "CSC"; + options["TR_radius"] = "10"; + options["l1_constraint_violation_coefficient"] = "1."; + options["enforce_linear_constraints"] = "yes"; + options["tolerance"] = "1e-6"; + options["loose_tolerance"] = "1e-6"; + options["TR_min_radius"] = "1e-8"; + options["switch_to_optimality_requires_acceptance"] = "no"; + options["switch_to_optimality_requires_linearized_feasibility"] = "yes"; + + options["funnel_beta"] = "0.9999"; + options["funnel_gamma"] = "0.001"; + options["switching_delta"] = "0.999"; + options["funnel_kappa"] = "0.5"; + options["funnel_ubd"] = "1.0"; + options["funnel_fact"] = "1.5"; + options["funnel_switching_infeasibility_exponent"] = "2"; + options["funnel_update_strategy"] = "2"; + } + else { + throw std::runtime_error("The preset " + preset_name + " is not known"); + } + } + + void Options::overwrite_with(const Options& overwriting_options) { + for (const auto& [option_name, option_value]: overwriting_options) { + (*this)[option_name] = option_value; + this->is_default[option_name] = overwriting_options.is_default[option_name]; + } + } + + void Options::print_used() const { + size_t number_used_options = 0; + std::string option_list{}; + for (const auto& [option_name, option_value]: this->options) { + if (not this->is_default[option_name] && this->used[option_name]) { + number_used_options++; + option_list.append("- ").append(option_name).append(" = ").append(option_value).append("\n"); + } + } + // print the overwritten options + if (number_used_options > 0) { + DISCRETE << "Used overwritten options:\n" << option_list << '\n'; + } + } + + std::map::const_iterator Options::begin() const { + return this->options.begin(); + } + + std::map::const_iterator Options::end() const { + return this->options.end(); + } +} // namespace diff --git a/uno/tools/Options.hpp b/uno/options/Options.hpp similarity index 93% rename from uno/tools/Options.hpp rename to uno/options/Options.hpp index d274e2b4..13d99db8 100644 --- a/uno/tools/Options.hpp +++ b/uno/options/Options.hpp @@ -21,8 +21,7 @@ namespace uno { [[nodiscard]] size_t get_unsigned_int(const std::string& option_name) const; [[nodiscard]] bool get_bool(const std::string& option_name) const; - static Options get_default(); - static Options get_command_line_options(int argc, char* argv[]); + [[nodiscard]] static Options get_command_line_options(int argc, char* argv[]); static void overwrite_with_option_file(Options& options, const std::string& file_name); static void set_preset(Options& options, const std::string& preset_name); void overwrite_with(const Options& overwriting_options); diff --git a/uno/preprocessing/Preprocessing.cpp b/uno/preprocessing/Preprocessing.cpp index 2b09e419..0d3b5766 100644 --- a/uno/preprocessing/Preprocessing.cpp +++ b/uno/preprocessing/Preprocessing.cpp @@ -132,7 +132,7 @@ namespace uno { qp_solver.solve_QP(model.number_variables, linear_constraints.size(), variables_lower_bounds, variables_upper_bounds, constraints_lower_bounds, constraints_upper_bounds, linear_objective, constraint_jacobian, hessian, d0, direction, warmstart_information); if (direction.status == SubproblemStatus::INFEASIBLE) { - throw std::runtime_error("Linear constraints cannot be satisfied at the initial point."); + throw std::runtime_error("Linear constraints cannot be satisfied at the initial point"); } // take the step @@ -143,8 +143,7 @@ namespace uno { const size_t constraint_index = linear_constraints[linear_constraint_index]; multipliers.constraints[constraint_index] += direction.multipliers.constraints[linear_constraint_index]; } - DEBUG3 << "Linear feasible initial point: "; print_vector(DEBUG3, x); - DEBUG3 << '\n'; + DEBUG3 << "Linear feasible initial point: " << x << '\n'; } } } diff --git a/uno/solvers/BQPD/BQPDSolver.cpp b/uno/solvers/BQPD/BQPDSolver.cpp index b4436f89..3382b61c 100644 --- a/uno/solvers/BQPD/BQPDSolver.cpp +++ b/uno/solvers/BQPD/BQPDSolver.cpp @@ -11,7 +11,7 @@ #include "optimization/WarmstartInformation.hpp" #include "tools/Infinity.hpp" #include "tools/Logger.hpp" -#include "tools/Options.hpp" +#include "options/Options.hpp" namespace uno { #define BIG 1e30 diff --git a/uno/solvers/LPSolverFactory.hpp b/uno/solvers/LPSolverFactory.hpp index f062e809..7bd2ea57 100644 --- a/uno/solvers/LPSolverFactory.hpp +++ b/uno/solvers/LPSolverFactory.hpp @@ -5,6 +5,8 @@ #define UNO_LPSOLVERFACTORY_H #include +#include +#include "options/Options.hpp" #include "solvers/LPSolver.hpp" #ifdef HAS_BQPD @@ -12,21 +14,29 @@ #endif namespace uno { - // forward declaration - class Options; - class LPSolverFactory { public: - static std::unique_ptr create([[maybe_unused]] const std::string& LP_solver_name, [[maybe_unused]] size_t number_variables, - [[maybe_unused]] size_t number_constraints, [[maybe_unused]] size_t number_objective_gradient_nonzeros, - [[maybe_unused]] size_t number_jacobian_nonzeros, [[maybe_unused]] const Options& options) { + static std::unique_ptr create([[maybe_unused]] size_t number_variables, [[maybe_unused]] size_t number_constraints, + [[maybe_unused]] size_t number_objective_gradient_nonzeros, [[maybe_unused]] size_t number_jacobian_nonzeros, + [[maybe_unused]] const Options& options) { + try { + [[maybe_unused]] const std::string& LP_solver_name = options.get_string("LP_solver"); #ifdef HAS_BQPD - if (LP_solver_name == "BQPD") { - return std::make_unique(number_variables, number_constraints, number_objective_gradient_nonzeros, - number_jacobian_nonzeros, 0, BQPDProblemType::LP, options); - } + if (LP_solver_name == "BQPD") { + return std::make_unique(number_variables, number_constraints, number_objective_gradient_nonzeros, + number_jacobian_nonzeros, 0, BQPDProblemType::LP, options); + } #endif - throw std::invalid_argument("LP solver not found"); + std::string message = "The LP solver "; + message.append(LP_solver_name).append(" is unknown").append("\n").append("The following values are available: ") + .append(join(LPSolverFactory::available_solvers(), ", ")); + throw std::invalid_argument(message); + } + catch (const std::out_of_range& exception) { + std::string message = exception.what(); + message.append("\n").append("The following values are available: ").append(join(LPSolverFactory::available_solvers(), ", ")); + throw std::out_of_range(message); + } } // return the list of available LP solvers diff --git a/uno/solvers/QPSolverFactory.hpp b/uno/solvers/QPSolverFactory.hpp index 2673c7ec..2daac92a 100644 --- a/uno/solvers/QPSolverFactory.hpp +++ b/uno/solvers/QPSolverFactory.hpp @@ -4,8 +4,9 @@ #ifndef UNO_QPSOLVERFACTORY_H #define UNO_QPSOLVERFACTORY_H -#include #include +#include +#include "options/Options.hpp" #include "solvers/QPSolver.hpp" #ifdef HAS_BQPD @@ -13,22 +14,30 @@ #endif namespace uno { - // forward declaration - class Options; - class QPSolverFactory { public: // create a QP solver - static std::unique_ptr create([[maybe_unused]] const std::string& QP_solver_name, [[maybe_unused]] size_t number_variables, - [[maybe_unused]] size_t number_constraints, [[maybe_unused]] size_t number_objective_gradient_nonzeros, - [[maybe_unused]] size_t number_jacobian_nonzeros, [[maybe_unused]] size_t number_hessian_nonzeros, [[maybe_unused]] const Options& options) { + static std::unique_ptr create([[maybe_unused]] size_t number_variables, [[maybe_unused]] size_t number_constraints, + [[maybe_unused]] size_t number_objective_gradient_nonzeros, [[maybe_unused]] size_t number_jacobian_nonzeros, + [[maybe_unused]] size_t number_hessian_nonzeros, [[maybe_unused]] const Options& options) { + try { + [[maybe_unused]] const std::string& QP_solver_name = options.get_string("QP_solver"); #ifdef HAS_BQPD - if (QP_solver_name == "BQPD") { - return std::make_unique(number_variables, number_constraints, number_objective_gradient_nonzeros, number_jacobian_nonzeros, - number_hessian_nonzeros, BQPDProblemType::QP, options); - } + if (QP_solver_name == "BQPD") { + return std::make_unique(number_variables, number_constraints, number_objective_gradient_nonzeros, number_jacobian_nonzeros, + number_hessian_nonzeros, BQPDProblemType::QP, options); + } #endif - throw std::invalid_argument("QP solver name is unknown"); + std::string message = "The QP solver "; + message.append(QP_solver_name).append(" is unknown").append("\n").append("The following values are available: ") + .append(join(QPSolverFactory::available_solvers(), ", ")); + throw std::invalid_argument(message); + } + catch (const std::out_of_range& exception) { + std::string message = exception.what(); + message.append("\n").append("The following values are available: ").append(join(QPSolverFactory::available_solvers(), ", ")); + throw std::out_of_range(message); + } } // return the list of available QP solvers diff --git a/uno/solvers/SymmetricIndefiniteLinearSolverFactory.hpp b/uno/solvers/SymmetricIndefiniteLinearSolverFactory.hpp index 9950815f..888965b8 100644 --- a/uno/solvers/SymmetricIndefiniteLinearSolverFactory.hpp +++ b/uno/solvers/SymmetricIndefiniteLinearSolverFactory.hpp @@ -5,7 +5,11 @@ #define UNO_LINEARSOLVERFACTORY_H #include +#include +#include #include "DirectSymmetricIndefiniteLinearSolver.hpp" +#include "options/Options.hpp" +#include "tools/Logger.hpp" #ifdef HAS_MA57 #include "solvers/MA57/MA57Solver.hpp" @@ -18,19 +22,31 @@ namespace uno { class SymmetricIndefiniteLinearSolverFactory { public: - static std::unique_ptr> create([[maybe_unused]] const std::string& linear_solver_name, - [[maybe_unused]] size_t dimension, [[maybe_unused]] size_t number_nonzeros) { + static std::unique_ptr> create([[maybe_unused]] size_t dimension, + [[maybe_unused]] size_t number_nonzeros, const Options& options) { + try { + [[maybe_unused]] const std::string& linear_solver_name = options.get_string("linear_solver"); #ifdef HAS_MA57 - if (linear_solver_name == "MA57") { - return std::make_unique(dimension, number_nonzeros); - } + if (linear_solver_name == "MA57") { + return std::make_unique(dimension, number_nonzeros); + } #endif #ifdef HAS_MUMPS - if (linear_solver_name == "MUMPS") { - return std::make_unique(dimension, number_nonzeros); - } + if (linear_solver_name == "MUMPS") { + return std::make_unique(dimension, number_nonzeros); + } #endif - throw std::invalid_argument("Linear solver name is unknown"); + std::string message = "The linear solver "; + message.append(linear_solver_name).append(" is unknown").append("\n").append("The following values are available: ") + .append(join(SymmetricIndefiniteLinearSolverFactory::available_solvers(), ", ")); + throw std::invalid_argument(message); + } + catch (const std::out_of_range& exception) { + std::string message = exception.what(); + message.append("\n").append("The following values are available: ") + .append(join(SymmetricIndefiniteLinearSolverFactory::available_solvers(), ", ")); + throw std::out_of_range(message); + } } // return the list of available solvers diff --git a/uno/symbolic/Range.hpp b/uno/symbolic/Range.hpp index 437d6868..b241fc0b 100644 --- a/uno/symbolic/Range.hpp +++ b/uno/symbolic/Range.hpp @@ -41,10 +41,10 @@ namespace uno { template inline Range::Range(size_t start_value, size_t end_value): Collection(), start_value(start_value), end_value(end_value) { if (direction == FORWARD && end_value < start_value) { - throw std::runtime_error("Forward range: end index is smaller than start index\n"); + throw std::runtime_error("Forward range: end index is smaller than start index"); } else if (direction == BACKWARD && end_value > start_value) { - throw std::runtime_error("Backward range: end index is larger than start index\n"); + throw std::runtime_error("Backward range: end index is larger than start index"); } } diff --git a/uno/symbolic/VectorView.hpp b/uno/symbolic/VectorView.hpp index c55a0bba..e87a363d 100644 --- a/uno/symbolic/VectorView.hpp +++ b/uno/symbolic/VectorView.hpp @@ -35,7 +35,7 @@ namespace uno { VectorView(Expression&& expression, size_t start, size_t end): expression(std::forward(expression)), start(start), end(std::min(end, expression.size())) { if (end < start) { - throw std::runtime_error("The view ends before its starting point."); + throw std::runtime_error("The view ends before its starting point"); } } diff --git a/uno/tools/Options.cpp b/uno/tools/Options.cpp deleted file mode 100644 index 156db11e..00000000 --- a/uno/tools/Options.cpp +++ /dev/null @@ -1,450 +0,0 @@ -// Copyright (c) 2018-2024 Charlie Vanaret -// Licensed under the MIT license. See LICENSE file in the project directory for details. - -#include -#include -#include -#include "solvers/QPSolverFactory.hpp" -#include "solvers/LPSolverFactory.hpp" -#include "solvers/SymmetricIndefiniteLinearSolverFactory.hpp" -#include "Options.hpp" -#include "Logger.hpp" - -namespace uno { - Options::Options(bool are_default_options): are_default_options(are_default_options) { } - - size_t Options::size() const { - return this->options.size(); - } - - // setter - std::string& Options::operator[](const std::string& option_name) { - this->is_default[option_name] = this->are_default_options; - return this->options[option_name]; - } - - // getter - const std::string& Options::at(const std::string& option_name) const { - try { - const std::string& option_value = this->options.at(option_name); - this->used[option_name] = true; - return option_value; - } - catch(const std::out_of_range&) { - throw std::out_of_range("The option " + option_name + " was not found"); - } - } - - const std::string& Options::get_string(const std::string& option_name) const { - return this->at(option_name); - } - - double Options::get_double(const std::string& option_name) const { - const std::string& entry = this->at(option_name); - return std::stod(entry); - } - - int Options::get_int(const std::string& option_name) const { - const std::string& entry = this->at(option_name); - return std::stoi(entry); - } - - size_t Options::get_unsigned_int(const std::string& option_name) const { - const std::string& entry = this->at(option_name); - return std::stoul(entry); - } - - bool Options::get_bool(const std::string& option_name) const { - const std::string& entry = this->at(option_name); - return entry == "yes"; - } - - Options Options::get_default() { - Options options(true); - /** termination **/ - // (tight) tolerance - options["tolerance"] = "1e-8"; - // loose tolerance used if tight tolerance cannot be reached - options["loose_tolerance"] = "1e-6"; - // number of iterations during which the loose tolerance is monitored - options["loose_tolerance_consecutive_iteration_threshold"] = "15"; - // maximum outer iterations - options["max_iterations"] = "2000"; - // CPU time limit (in seconds) - options["time_limit"] = "inf"; - // print optimal solution (yes|no) - options["print_solution"] = "yes"; - // threshold on objective to declare unbounded NLP - options["unbounded_objective_threshold"] = "-1e20"; - // enforce linear constraints at the initial point (yes|no) - options["enforce_linear_constraints"] = "no"; - - /** statistics table **/ - options["statistics_print_header_every_iterations"] = "15"; - options["statistics_major_column_order"] = "1"; - options["statistics_minor_column_order"] = "2"; - options["statistics_penalty_parameter_column_order"] = "5"; - options["statistics_barrier_parameter_column_order"] = "8"; - options["statistics_SOC_column_order"] = "9"; - options["statistics_TR_radius_column_order"] = "10"; - options["statistics_LS_step_length_column_order"] = "10"; - options["statistics_restoration_phase_column_order"] = "20"; - options["statistics_regularization_column_order"] = "21"; - options["statistics_funnel_width_column_order"] = "25"; - options["statistics_step_norm_column_order"] = "31"; - options["statistics_objective_column_order"] = "100"; - options["statistics_primal_feasibility_column_order"] = "101"; - options["statistics_dual_feasibility_column_order"] = "102"; - options["statistics_stationarity_column_order"] = "104"; - options["statistics_complementarity_column_order"] = "105"; - options["statistics_status_column_order"] = "200"; - - /** main options **/ - // logging level (SILENT|DISCRETE|WARNING|INFO|DEBUG|DEBUG2|DEBUG3) - options["logger"] = "INFO"; - // Hessian model (exact|zero) - options["hessian_model"] = "exact"; - // sparse matrix format (COO|CSC) - options["sparse_format"] = "COO"; - // scale the functions (yes|no) - options["scale_functions"] = "no"; - options["function_scaling_threshold"] = "100"; - // factor scaling - options["function_scaling_factor"] = "100"; - // scale the errors with respect to the current point (yes|no) - options["scale_residuals"] = "yes"; - // norm of the progress measures (L1|L2|INF) - options["progress_norm"] = "L1"; - // norm of the primal-dual residuals (L1|L2|INF) - options["residual_norm"] = "INF"; - options["residual_scaling_threshold"] = "100."; - options["protect_actual_reduction_against_roundoff"] = "no"; - - /** globalization strategy options **/ - options["armijo_decrease_fraction"] = "1e-4"; - options["armijo_tolerance"] = "1e-9"; - - /** switching method options **/ - options["switching_delta"] = "0.999"; - options["switching_infeasibility_exponent"] = "2"; - - /** filter method options **/ - // filter type (standard|nonmonotone) - options["filter_type"] = "standard"; - options["filter_beta"] = "0.999"; - options["filter_gamma"] = "0.001"; - options["filter_ubd"] = "1e2"; - options["filter_fact"] = "1.25"; - options["filter_capacity"] = "50"; - // used by Waechter filter method - options["filter_sufficient_infeasibility_decrease_factor"] = "0.9"; - // nonmonotone filter strategy - options["nonmonotone_filter_number_dominated_entries"] = "3"; - - /** funnel options **/ - options["funnel_kappa"] = "0.5"; - options["funnel_beta"] = "0.9999"; - options["funnel_gamma"] = "0.001"; - options["funnel_ubd"] = "1.0"; - options["funnel_fact"] = "1.5"; - options["funnel_update_strategy"] = "1"; - options["funnel_require_acceptance_wrt_current_iterate"] = "no"; - - /** line search options */ - // backtracking ratio - options["LS_backtracking_ratio"] = "0.5"; - // minimum step length - options["LS_min_step_length"] = "1e-12"; - // use the primal-dual and dual step lengths to scale the dual directions when assembling the trial iterate - options["LS_scale_duals_with_step_length"] = "yes"; - - /** regularization options **/ - // regularization failure threshold - options["regularization_failure_threshold"] = "1e40"; - // Hessian regularization: initial value - options["regularization_initial_value"] = "1e-4"; - options["regularization_increase_factor"] = "2"; - // regularization of augmented system - options["primal_regularization_initial_factor"] = "1e-4"; - options["dual_regularization_fraction"] = "1e-8"; - options["primal_regularization_lb"] = "1e-20"; - options["primal_regularization_decrease_factor"] = "3."; - options["primal_regularization_fast_increase_factor"] = "100."; - options["primal_regularization_slow_increase_factor"] = "8."; - options["threshold_unsuccessful_attempts"] = "8"; - - /** trust region options **/ - // initial trust region radius - options["TR_radius"] = "10."; - // TR radius increase factor - options["TR_increase_factor"] = "2"; - // TR radius decrease factor - options["TR_decrease_factor"] = "2"; - // TR aggressive radius decrease factor - options["TR_aggressive_decrease_factor"] = "4"; - // tolerance in TR constraint activity - options["TR_activity_tolerance"] = "1e-6"; - // minimum TR radius - options["TR_min_radius"] = "1e-7"; - // threshold below which the TR radius is reset - options["TR_radius_reset_threshold"] = "1e-4"; - // force QP convexification when in a trust-region setting - options["convexify_QP"] = "false"; - - /** constraint relaxation options **/ - // l1 relaxation options // - // initial value of the penalty parameter - options["l1_relaxation_initial_parameter"] = "1."; - // use a fixed parameter (yes|no) - options["l1_relaxation_fixed_parameter"] = "no"; - // decrease (multiplicative) factor of penalty parameter - options["l1_relaxation_decrease_factor"] = "10."; - // epsilon constants in Byrd's article - options["l1_relaxation_epsilon1"] = "0.1"; - options["l1_relaxation_epsilon2"] = "0.1"; - options["l1_relaxation_residual_small_threshold"] = "1e-12"; - // coefficient of constraint violation - options["l1_constraint_violation_coefficient"] = "1"; - // threshold for determining if duals have a zero norm - options["l1_small_duals_threshold"] = "1e-10"; - - /** feasibility restoration options **/ - // test linearized feasibility when switching back to the optimality phase - options["switch_to_optimality_requires_linearized_feasibility"] = "yes"; - - /** barrier subproblem options **/ - options["barrier_initial_parameter"] = "0.1"; - options["barrier_default_multiplier"] = "1"; - // Ipopt parameters - options["barrier_tau_min"] = "0.99"; - options["barrier_k_sigma"] = "1e10"; - options["barrier_smax"] = "100"; - options["barrier_k_mu"] = "0.2"; - options["barrier_theta_mu"] = "1.5"; - options["barrier_k_epsilon"] = "10"; - options["barrier_update_fraction"] = "10"; - options["barrier_regularization_exponent"] = "0.25"; - options["barrier_small_direction_factor"] = "10."; - options["barrier_push_variable_to_interior_k1"] = "1e-2"; - options["barrier_push_variable_to_interior_k2"] = "1e-2"; - options["barrier_damping_factor"] = "1e-5"; - options["least_square_multiplier_max_norm"] = "1e3"; - - /** BQPD options **/ - options["BQPD_print_subproblem"] = "no"; - options["BQPD_kmax"] = "500"; - - /** AMPL options **/ - options["AMPL_write_solution_to_file"] = "yes"; - - /** solvers: check the available solvers **/ - // QP solver - const auto QP_solvers = QPSolverFactory::available_solvers(); - if (not QP_solvers.empty()) { - options["QP_solver"] = QP_solvers[0]; - options.is_default["QP_solver"] = false; - } - // LP solver - const auto LP_solvers = LPSolverFactory::available_solvers(); - if (not LP_solvers.empty()) { - options["LP_solver"] = LP_solvers[0]; - options.is_default["LP_solver"] = false; - } - // linear solver - const auto linear_solvers = SymmetricIndefiniteLinearSolverFactory::available_solvers(); - if (not linear_solvers.empty()) { - options["linear_solver"] = linear_solvers[0]; - options.is_default["linear_solver"] = false; - } - - /** ingredients **/ - // default constraint relaxation strategy (feasibility_restoration|l1_relaxation) - options["constraint_relaxation_strategy"] = "feasibility_restoration"; - // default subproblem (QP|LP|primal_dual_interior_point) - options["subproblem"] = "QP"; - // default globalization strategy (l1_merit|fletcher_filter_method|waechter_filter_method) - options["globalization_strategy"] = "fletcher_filter_method"; - // default globalization mechanism (TR|LS) - options["globalization_mechanism"] = "TR"; - - return options; - } - - // argv[i] for i = 3..argc-1 are overwriting options - Options Options::get_command_line_options(int argc, char* argv[]) { - static const std::string delimiter = "="; - Options overwriting_options(false); - - // build the (name, value) map - for (size_t i = 3; i < static_cast(argc); i++) { - const std::string argument = std::string(argv[i]); - size_t position = argument.find_first_of(delimiter); - if (position == std::string::npos) { - throw std::runtime_error("The option " + argument + " does not contain the delimiter " + delimiter + "."); - } - const std::string option_name = argument.substr(0, position); - const std::string option_value = argument.substr(position + 1); - if (option_name == "preset") { - Options::set_preset(overwriting_options, option_value); - } - else if (option_name == "option_file") { - Options::overwrite_with_option_file(overwriting_options, option_value); - } - else { - overwriting_options[option_name] = option_value; - } - } - return overwriting_options; - } - - void Options::overwrite_with_option_file(Options& options, const std::string& file_name) { - std::ifstream file; - file.open(file_name); - if (!file) { - throw std::invalid_argument("The option file " + file_name + " was not found"); - } - else { - // register the default options - std::string option_name, option_value; - std::string line; - while (std::getline(file, line)) { - if (not line.empty() && line.find('#') != 0) { - std::istringstream iss; - iss.str(line); - iss >> option_name >> option_value; - options[option_name] = option_value; - } - } - file.close(); - } - } - - void Options::set_preset(Options& options, const std::string& preset_name) { - // shortcuts for state-of-the-art combinations - if (preset_name == "ipopt") { - options["constraint_relaxation_strategy"] = "feasibility_restoration"; - options["subproblem"] = "primal_dual_interior_point"; - options["globalization_mechanism"] = "LS"; - options["globalization_strategy"] = "waechter_filter_method"; - options["filter_type"] = "standard"; - options["filter_beta"] = "0.99999"; - options["filter_gamma"] = "1e-8"; - options["switching_delta"] = "1"; - options["filter_ubd"] = "1e4"; - options["filter_fact"] = "1e4"; - options["filter_switching_infeasibility_exponent"] = "1.1"; - options["armijo_decrease_fraction"] = "1e-8"; - options["LS_backtracking_ratio"] = "0.5"; - options["LS_min_step_length"] = "5e-7"; - options["barrier_tau_min"] = "0.99"; - options["barrier_damping_factor"] = "1e-5"; - options["l1_constraint_violation_coefficient"] = "1000."; - options["progress_norm"] = "L1"; - options["residual_norm"] = "INF"; - options["scale_functions"] = "yes"; - options["sparse_format"] = "COO"; - options["tolerance"] = "1e-8"; - options["loose_tolerance"] = "1e-6"; - options["loose_tolerance_consecutive_iteration_threshold"] = "15"; - options["switch_to_optimality_requires_linearized_feasibility"] = "no"; - options["LS_scale_duals_with_step_length"] = "yes"; - options["protect_actual_reduction_against_roundoff"] = "yes"; - } - else if (preset_name == "filtersqp") { - options["constraint_relaxation_strategy"] = "feasibility_restoration"; - options["subproblem"] = "QP"; - options["globalization_mechanism"] = "TR"; - options["globalization_strategy"] = "fletcher_filter_method"; - options["filter_type"] = "standard"; - options["progress_norm"] = "L1"; - options["residual_norm"] = "L2"; - options["sparse_format"] = "CSC"; - options["TR_radius"] = "10"; - options["l1_constraint_violation_coefficient"] = "1."; - options["enforce_linear_constraints"] = "yes"; - options["tolerance"] = "1e-6"; - options["loose_tolerance"] = "1e-6"; - options["TR_min_radius"] = "1e-8"; - options["switch_to_optimality_requires_linearized_feasibility"] = "yes"; - options["protect_actual_reduction_against_roundoff"] = "no"; - } - else if (preset_name == "byrd") { - options["constraint_relaxation_strategy"] = "l1_relaxation"; - options["subproblem"] = "QP"; - options["globalization_mechanism"] = "LS"; - options["globalization_strategy"] = "l1_merit"; - options["l1_relaxation_initial_parameter"] = "1"; - options["LS_backtracking_ratio"] = "0.5"; - options["armijo_decrease_fraction"] = "1e-8"; - options["l1_relaxation_epsilon1"] = "0.1"; - options["l1_relaxation_epsilon2"] = "0.1"; - options["l1_constraint_violation_coefficient"] = "1."; - options["tolerance"] = "1e-6"; - options["loose_tolerance"] = "1e-6"; - options["progress_norm"] = "L1"; - options["residual_norm"] = "L1"; - options["sparse_format"] = "CSC"; - options["LS_scale_duals_with_step_length"] = "no"; - options["protect_actual_reduction_against_roundoff"] = "no"; - } - else if (preset_name == "funnelsqp") { - options["constraint_relaxation_strategy"] = "feasibility_restoration"; - options["subproblem"] = "QP"; - options["globalization_mechanism"] = "TR"; - options["globalization_strategy"] = "funnel_method"; - options["progress_norm"] = "L1"; - options["residual_norm"] = "L2"; - options["sparse_format"] = "CSC"; - options["TR_radius"] = "10"; - options["l1_constraint_violation_coefficient"] = "1."; - options["enforce_linear_constraints"] = "yes"; - options["tolerance"] = "1e-6"; - options["loose_tolerance"] = "1e-6"; - options["TR_min_radius"] = "1e-8"; - options["switch_to_optimality_requires_acceptance"] = "no"; - options["switch_to_optimality_requires_linearized_feasibility"] = "yes"; - - options["funnel_beta"] = "0.9999"; - options["funnel_gamma"] = "0.001"; - options["switching_delta"] = "0.999"; - options["funnel_kappa"] = "0.5"; - options["funnel_ubd"] = "1.0"; - options["funnel_fact"] = "1.5"; - options["funnel_switching_infeasibility_exponent"] = "2"; - options["funnel_update_strategy"] = "2"; - } - else { - throw std::runtime_error("The preset " + preset_name + " is not known."); - } - } - - void Options::overwrite_with(const Options& overwriting_options) { - for (const auto& [option_name, option_value]: overwriting_options) { - (*this)[option_name] = option_value; - this->is_default[option_name] = overwriting_options.is_default[option_name]; - } - } - - void Options::print_used() const { - size_t number_used_options = 0; - std::string option_list{}; - for (const auto& [option_name, option_value]: this->options) { - if (not this->is_default[option_name] && this->used[option_name]) { - number_used_options++; - option_list.append("- ").append(option_name).append(" = ").append(option_value).append("\n"); - } - } - // print the overwritten options - if (number_used_options > 0) { - DISCRETE << "Used overwritten options:\n" << option_list << '\n'; - } - } - - std::map::const_iterator Options::begin() const { - return this->options.begin(); - } - - std::map::const_iterator Options::end() const { - return this->options.end(); - } -} // namespace diff --git a/uno/tools/Statistics.cpp b/uno/tools/Statistics.cpp index 5e37bf89..3c1ae43a 100644 --- a/uno/tools/Statistics.cpp +++ b/uno/tools/Statistics.cpp @@ -5,7 +5,7 @@ #include #include #include "Statistics.hpp" -#include "Options.hpp" +#include "options/Options.hpp" namespace uno { // TODO move this to the option file