Skip to content

Commit

Permalink
Changed the command line interface of uno_ampl.cpp (./uno_ampl model.…
Browse files Browse the repository at this point in the history
…nl -AMPL [key=value ...]). It is now compatible with other AMPL-based solvers.
  • Loading branch information
cvanaret committed Oct 17, 2024
1 parent cab62f8 commit 0ccd578
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 147 deletions.
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,18 +93,19 @@ See the [INSTALL](INSTALL.md) file.

At the moment, Uno only reads models from [.nl files](https://en.wikipedia.org/wiki/Nl_(format)). A couple of CUTEst instances are available in the `/examples` directory.

To solve an AMPL model, type in the `build` directory: ```./uno_ampl path_to_file/file.nl```
To solve an AMPL model, type in the `build` directory: ```./uno_ampl model.nl -AMPL [key=value ...]```
where ```[key=value ...]``` is a list of options.

To use Uno with Julia/JuMP, a solution in the short term is to use the package [AmplNLWriter.jl](https://juliahub.com/ui/Packages/General/AmplNLWriter.jl) to dump JuMP models into .nl files.

### Combination of ingredients

To pick a globalization mechanism, use the argument (choose one of the possible options in brackets): ```-globalization_mechanism [LS|TR]```
To pick a constraint relaxation strategy, use the argument: ```-constraint_relaxation_strategy [feasibility_restoration|l1_relaxation]```
To pick a globalization strategy, use the argument: ```-globalization_strategy [l1_merit|fletcher_filter_method|waechter_filter_method|funnel_method]```
To pick a subproblem method, use the argument: ```-subproblem [QP|LP|primal_dual_interior_point]```
To pick a globalization mechanism, use the argument (choose one of the possible options in brackets): ```globalization_mechanism=[LS|TR]```
To pick a constraint relaxation strategy, use the argument: ```constraint_relaxation_strategy=[feasibility_restoration|l1_relaxation]```
To pick a globalization strategy, use the argument: ```globalization_strategy=[l1_merit|fletcher_filter_method|waechter_filter_method|funnel_method]```
To pick a subproblem method, use the argument: ```subproblem=[QP|LP|primal_dual_interior_point]```
The options can be combined in the same command line.

For an overview of the available strategies, type: ```./uno_ampl --strategies```

To pick a preset, use the argument: ```-preset [filtersqp|ipopt|byrd]```
To pick a preset, use the argument: ```preset=[filtersqp|ipopt|byrd]```
83 changes: 69 additions & 14 deletions bindings/AMPL/uno_ampl.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) 2018-2024 Charlie Vanaret
// Licensed under the MIT license. See LICENSE file in the project directory for details.

#include <string>
#include <stdexcept>
#include "ingredients/globalization_mechanisms/GlobalizationMechanism.hpp"
#include "ingredients/globalization_mechanisms/GlobalizationMechanismFactory.hpp"
#include "ingredients/constraint_relaxation_strategies/ConstraintRelaxationStrategy.hpp"
Expand Down Expand Up @@ -51,32 +53,85 @@ namespace uno {
ERROR << exception.what() << '\n';
}
}

// argv[0] is ./uno_ampl
// argv[1] is the model name
// argv[2] should be -AMPL
// argv[i] for i = 3..argc-1 are options
void get_command_line_options(Options& options, int argc, char* argv[]) {
static const std::string delimiter = "=";

// build the (name, value) map
for (int i = 3; i < 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 key = argument.substr(0, position);
const std::string value = argument.substr(position + 1);
if (key == "preset") {
options.find_preset(value);
}
else {
options[key] = value;
}
}
options.print(false);
}

void print_uno_instructions() {
std::cout << "Welcome in Uno 1.1.0\n";
std::cout << "To solve an AMPL model, type ./uno_ampl model.nl -AMPL [key=value ...]\n";
std::cout << "To choose a constraint relaxation strategy, use the argument constraint_relaxation_strategy="
"[feasibility_restoration|l1_relaxation]\n";
std::cout << "To choose a subproblem method, use the argument subproblem=[QP|LP|primal_dual_interior_point]\n";
std::cout << "To choose a globalization mechanism, use the argument globalization_mechanism=[LS|TR]\n";
std::cout << "To choose a globalization strategy, use the argument globalization_strategy="
"[l1_merit|fletcher_filter_method|waechter_filter_method]\n";
std::cout << "To choose a preset, use the argument preset=[filtersqp|ipopt|byrd]\n";
std::cout << "The options can be combined in the same command line.\n";
//std::cout << "Autocompletion is possible (see README).\n";
}
} // namespace

int main(int argc, char* argv[]) {
using namespace uno;

if (1 < argc) {
// get the default options
Options options = Options::get_default_options("uno.options");
// override them with the command line arguments
options.get_command_line_arguments(argc, argv);
Logger::set_logger(options.get_string("logger"));

if (std::string(argv[1]) == "-v") {
Uno::print_uno_version();
if (argc == 1) {
print_uno_instructions();
}
else if (argc == 2) {
if (std::string(argv[1]) == "--v") {
print_uno_instructions();
}
else if (std::string(argv[1]) == "--strategies") {
Uno::print_available_strategies();
}
else {
// run Uno on the .nl file (last command line argument)
std::string model_name = std::string(argv[argc - 1]);
run_uno_ampl(model_name, options);
throw std::runtime_error("The second command line argument should be -AMPL.");
}
}
else {
Uno::print_uno_version();
else if (argc >= 3) {
// get the default options
Options options = Options::get_default_options("uno.options");

// AMPL expects: ./uno_ampl model.nl -AMPL [key=value, ...]
// model name
std::string model_name = std::string(argv[1]);
std::cout << "Model " << model_name << '\n';

// -AMPL
if (std::string(argv[2]) != "-AMPL") {
throw std::runtime_error("The second command line argument should be -AMPL.");
}

// override them with the command line arguments
get_command_line_options(options, argc, argv);

// solve the model
Logger::set_logger(options.get_string("logger"));
run_uno_ampl(model_name, options);
}
return EXIT_SUCCESS;
}
13 changes: 0 additions & 13 deletions uno/Uno.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,19 +127,6 @@ namespace uno {
return result;
}

void Uno::print_uno_version() {
std::cout << "Welcome in Uno 1.0\n";
std::cout << "To solve an AMPL model, type ./uno_ampl path_to_file/file.nl\n";
std::cout << "To choose a constraint relaxation strategy, use the argument -constraint_relaxation_strategy "
"[feasibility_restoration|l1_relaxation]\n";
std::cout << "To choose a subproblem method, use the argument -subproblem [QP|LP|primal_dual_interior_point]\n";
std::cout << "To choose a globalization mechanism, use the argument -globalization_mechanism [LS|TR]\n";
std::cout << "To choose a globalization strategy, use the argument -globalization_strategy "
"[l1_merit|fletcher_filter_method|waechter_filter_method]\n";
std::cout << "To choose a preset, use the argument -preset [filtersqp|ipopt|byrd]\n";
std::cout << "The options can be combined in the same command line. Autocompletion is possible (see README).\n";
}

void Uno::print_available_strategies() {
std::cout << "Available strategies:\n";
std::cout << "- Constraint relaxation strategies: " << join(ConstraintRelaxationStrategyFactory::available_strategies(), ", ") << '\n';
Expand Down
1 change: 0 additions & 1 deletion uno/Uno.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ namespace uno {

[[nodiscard]] Result solve(const Model& model, Iterate& initial_iterate, const Options& options);

static void print_uno_version();
static void print_available_strategies();
static void print_strategy_combination(const Options& options);
static void print_optimization_summary(const Options& options, const Result& result);
Expand Down
1 change: 0 additions & 1 deletion uno/ingredients/subproblems/Subproblem.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
namespace uno {
// forward declarations
class Direction;
class HessianModel;
class Iterate;
class l1RelaxedProblem;
class Model;
Expand Down
195 changes: 85 additions & 110 deletions uno/tools/Options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include <fstream>
#include <sstream>
#include "Options.hpp"
#include "Logger.hpp"

namespace uno {
std::string& Options::operator[](const std::string& key) {
Expand Down Expand Up @@ -80,128 +79,104 @@ namespace uno {
}
}

void find_preset(const std::string& preset_name, Options& options) {
void Options::find_preset(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";
(*this)["constraint_relaxation_strategy"] = "feasibility_restoration";
(*this)["subproblem"] = "primal_dual_interior_point";
(*this)["globalization_mechanism"] = "LS";
(*this)["globalization_strategy"] = "waechter_filter_method";
(*this)["filter_type"] = "standard";
(*this)["filter_beta"] = "0.99999";
(*this)["filter_gamma"] = "1e-8";
(*this)["switching_delta"] = "1";
(*this)["filter_ubd"] = "1e4";
(*this)["filter_fact"] = "1e4";
(*this)["filter_switching_infeasibility_exponent"] = "1.1";
(*this)["armijo_decrease_fraction"] = "1e-8";
(*this)["LS_backtracking_ratio"] = "0.5";
(*this)["LS_min_step_length"] = "5e-7";
(*this)["barrier_tau_min"] = "0.99";
(*this)["barrier_damping_factor"] = "1e-5";
(*this)["l1_constraint_violation_coefficient"] = "1000.";
(*this)["progress_norm"] = "L1";
(*this)["residual_norm"] = "INF";
(*this)["scale_functions"] = "yes";
(*this)["sparse_format"] = "COO";
(*this)["tolerance"] = "1e-8";
(*this)["loose_tolerance"] = "1e-6";
(*this)["loose_tolerance_consecutive_iteration_threshold"] = "15";
(*this)["switch_to_optimality_requires_linearized_feasibility"] = "no";
(*this)["LS_scale_duals_with_step_length"] = "yes";
(*this)["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";
(*this)["constraint_relaxation_strategy"] = "feasibility_restoration";
(*this)["subproblem"] = "QP";
(*this)["globalization_mechanism"] = "TR";
(*this)["globalization_strategy"] = "fletcher_filter_method";
(*this)["filter_type"] = "standard";
(*this)["progress_norm"] = "L1";
(*this)["residual_norm"] = "L2";
(*this)["sparse_format"] = "CSC";
(*this)["TR_radius"] = "10";
(*this)["l1_constraint_violation_coefficient"] = "1.";
(*this)["enforce_linear_constraints"] = "yes";
(*this)["tolerance"] = "1e-6";
(*this)["loose_tolerance"] = "1e-6";
(*this)["TR_min_radius"] = "1e-8";
(*this)["switch_to_optimality_requires_linearized_feasibility"] = "yes";
(*this)["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";
(*this)["constraint_relaxation_strategy"] = "l1_relaxation";
(*this)["subproblem"] = "QP";
(*this)["globalization_mechanism"] = "LS";
(*this)["globalization_strategy"] = "l1_merit";
(*this)["l1_relaxation_initial_parameter"] = "1";
(*this)["LS_backtracking_ratio"] = "0.5";
(*this)["armijo_decrease_fraction"] = "1e-8";
(*this)["l1_relaxation_epsilon1"] = "0.1";
(*this)["l1_relaxation_epsilon2"] = "0.1";
(*this)["l1_constraint_violation_coefficient"] = "1.";
(*this)["tolerance"] = "1e-6";
(*this)["loose_tolerance"] = "1e-6";
(*this)["progress_norm"] = "L1";
(*this)["residual_norm"] = "L1";
(*this)["sparse_format"] = "CSC";
(*this)["LS_scale_duals_with_step_length"] = "no";
(*this)["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";
(*this)["constraint_relaxation_strategy"] = "feasibility_restoration";
(*this)["subproblem"] = "QP";
(*this)["globalization_mechanism"] = "TR";
(*this)["globalization_strategy"] = "funnel_method";
(*this)["progress_norm"] = "L1";
(*this)["residual_norm"] = "L2";
(*this)["sparse_format"] = "CSC";
(*this)["TR_radius"] = "10";
(*this)["l1_constraint_violation_coefficient"] = "1.";
(*this)["enforce_linear_constraints"] = "yes";
(*this)["tolerance"] = "1e-6";
(*this)["loose_tolerance"] = "1e-6";
(*this)["TR_min_radius"] = "1e-8";
(*this)["switch_to_optimality_requires_acceptance"] = "no";
(*this)["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";
(*this)["funnel_beta"] = "0.9999";
(*this)["funnel_gamma"] = "0.001";
(*this)["switching_delta"] = "0.999";
(*this)["funnel_kappa"] = "0.5";
(*this)["funnel_ubd"] = "1.0";
(*this)["funnel_fact"] = "1.5";
(*this)["funnel_switching_infeasibility_exponent"] = "2";
(*this)["funnel_update_strategy"] = "2";
}
else {
throw std::runtime_error("The preset " + preset_name + " is not known.");
}
}

void Options::get_command_line_arguments(int argc, char* argv[]) {
// build the (name, value) map
int i = 1;
while (i < argc - 1) {
std::string argument = std::string(argv[i]);
if (argument[0] == '-') {
if (i < argc - 1) {
// remove the '-'
const std::string name = argument.substr(1);
const std::string value = std::string(argv[i + 1]);
if (name == "preset") {
find_preset(value, *this);
}
else {
this->operator[](name) = value;
}
i += 2;
}
}
else {
WARNING << "Argument " << argument << " was ignored\n";
i++;
}
}
}

} // namespace
Loading

0 comments on commit 0ccd578

Please sign in to comment.