Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions interfaces/Python/cpp_classes/UnoSolverWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ namespace uno {
Logger::set_stream(std::cout);
}

// single entry point for the preset, used by both set_preset and set_option("preset", ...)
void UnoSolverWrapper::set_preset(std::string preset) {
this->validate_preset(preset);
this->user_options.set_string("preset", std::move(preset));
this->refresh_preset_options();
}

void UnoSolverWrapper::validate_preset(const std::string& preset) {
if (preset != "auto") {
Presets::from_string(preset); // throws on an unknown preset
Expand Down
1 change: 1 addition & 0 deletions interfaces/Python/cpp_classes/UnoSolverWrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ namespace uno {
UnoSolverWrapper();
~UnoSolverWrapper();

void set_preset(std::string preset);
void validate_preset(const std::string& preset);
void refresh_preset_options();

Expand Down
13 changes: 7 additions & 6 deletions interfaces/Python/python_modules/UnoSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,12 @@ namespace uno {
const auto type = Options::option_types.find(option_name);
if (type != Options::option_types.end()) { // key found
if (type->second == OptionType::STRING) { // correct type
solver.user_options.set_string(option_name, std::move(option_value));
if (option_name == "preset") { // the preset also determines the preset options
Comment thread
cvanaret marked this conversation as resolved.
Resolved
solver.set_preset(std::move(option_value));
}
else {
solver.user_options.set_string(option_name, std::move(option_value));
}
}
else { // incorrect type
throw py::type_error(option_name + " is not of type string");
Expand All @@ -82,11 +87,7 @@ namespace uno {

.def("set_logger_stream", &UnoSolverWrapper::set_logger_stream)

.def("set_preset", [](UnoSolverWrapper& solver, std::string preset_name) {
solver.validate_preset(preset_name);
solver.user_options.set_string("preset", std::move(preset_name));
solver.refresh_preset_options();
}, py::arg("preset_name"))
.def("set_preset", &UnoSolverWrapper::set_preset, py::arg("preset_name"))

.def("set_notify_acceptable_iterate_callback", [](UnoSolverWrapper& solver, NotifyAcceptableIterateCallback callback) {
solver.set_notify_acceptable_iterate_callback(std::move(callback));
Expand Down
41 changes: 41 additions & 0 deletions interfaces/Python/tests/test_solvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,44 @@ def test_hs001_without_constraints(solver, preset, option, subproblem_solver):
assert len(result.constraint_dual_solution) == 0
assert log.counts["hessian"] > 0 and log.counts["notify"] > 0
assert log.multiplier_sizes and all(size == 0 for size in log.multiplier_sizes)


PRESETS = ["filtersqp", "filterslp", "funnelsqp", "ipopt", "auto"]
Comment thread
cvanaret marked this conversation as resolved.
Resolved


@pytest.mark.parametrize("preset", PRESETS)
def test_preset_as_option(preset):
"""Setting the preset with set_option("preset", ...) selects the same method and solution as set_preset"""
results = {}
descriptions = {}
for setter in ("set_option", "set_preset"):
solver = unopy.UnoSolver()
solver.set_option("logger", "SILENT")
if setter == "set_option":
solver.set_option("preset", preset)
else:
solver.set_preset(preset)
results[setter] = solver.optimize(hs015())
descriptions[setter] = solver.get_method_description()
assert descriptions["set_option"] == descriptions["set_preset"]
assert results["set_option"].optimization_status == results["set_preset"].optimization_status
assert results["set_option"].number_iterations == results["set_preset"].number_iterations
assert np.array_equal(results["set_option"].primal_solution, results["set_preset"].primal_solution)


def test_preset_option_overrides_previous_preset(solver):
"""A preset set with set_option replaces a preset previously set with set_preset"""
solver.set_preset("filtersqp")
solver.set_option("preset", "ipopt")
solver.optimize(hs015())
assert "interior-point" in solver.get_method_description()


@pytest.mark.parametrize("setter", ["set_option", "set_preset"])
def test_unknown_preset_raises(solver, setter):
"""An unknown preset name is rejected when it is set, whether through set_option or set_preset"""
with pytest.raises(RuntimeError, match="Unknown preset"):
if setter == "set_option":
solver.set_option("preset", "not_a_preset")
else:
solver.set_preset("not_a_preset")
Loading