Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[solvers] Add missing unit tests for options handling #21939

Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 3 additions & 1 deletion solvers/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ drake_cc_library(
"//common/symbolic:expression",
],
implementation_deps = [
"//solvers:decision_variable",
":decision_variable",
],
)

Expand Down Expand Up @@ -1338,6 +1338,7 @@ drake_cc_googletest(
":semidefinite_program_examples",
":sos_examples",
"//common/test_utilities:eigen_matrix_compare",
"//common/test_utilities:expect_throws_message",
],
)

Expand Down Expand Up @@ -1621,6 +1622,7 @@ drake_cc_googletest(
":optimization_examples",
":quadratic_program_examples",
"//common/test_utilities:eigen_matrix_compare",
"//common/test_utilities:expect_throws_message",
],
)

Expand Down
13 changes: 13 additions & 0 deletions solvers/test/csdp_solver_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <gtest/gtest.h>

#include "drake/common/test_utilities/eigen_matrix_compare.h"
#include "drake/common/test_utilities/expect_throws_message.h"
#include "drake/solvers/test/csdp_test_examples.h"
#include "drake/solvers/test/linear_program_examples.h"
#include "drake/solvers/test/second_order_cone_program_examples.h"
Expand Down Expand Up @@ -515,6 +516,18 @@ TEST_F(TrivialSDP1, SolveVerbose) {
}
}

// This is a code coverage test of reporting malformed options.
TEST_F(TrivialSDP1, UnknownRemoveFreeVariableMethod) {
UnivariateNonnegative1 example;
CsdpSolver solver;
SolverOptions options;
options.SetOption(solver.id(), "drake::RemoveFreeVariableMethod", 222);
if (solver.available()) {
DRAKE_EXPECT_THROWS_MESSAGE(solver.Solve(example.prog(), {}, options),
".*unknown.*RemoveFreeVariableMethod.*");
}
}

// Confirm that setting solver options has an effect on the solve.
TEST_F(TrivialSDP1, SolverOptionsPropagation) {
CsdpSolver solver;
Expand Down
49 changes: 40 additions & 9 deletions solvers/test/mosek_solver_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ GTEST_TEST(MosekTest, TestLogging) {
}

GTEST_TEST(MosekTest, SolverOptionsTest) {
// We test that passing solver options change the behavior of
// We test that passing solver options changes the behavior of
// MosekSolver::Solve().
MathematicalProgram prog;
auto x = prog.NewContinuousVariables<2>();
Expand All @@ -311,17 +311,27 @@ GTEST_TEST(MosekTest, SolverOptionsTest) {
prog.AddConstraint(x(1) >= 0);
prog.AddLinearCost(1E5 * x(0) + x(1));

MosekSolver mosek_solver;
SolverOptions solver_options;
solver_options.SetOption(MosekSolver::id(), "MSK_DPAR_DATA_TOL_C_HUGE", 1E3);
MathematicalProgramResult result;
MosekSolver mosek_solver;

// Set a string option, to at least make sure nothing crashes. Unfortunately,
// there is no MOSEK string option that affects the output or logging, so we
// cannot actually test that the option is propagated correctly.
solver_options.SetOption(MosekSolver::id(), "MSK_SPAR_BAS_SOL_FILE_NAME",
"/tmp/mosek.bas");

// Solve with 1e3 => failed.
solver_options.SetOption(MosekSolver::id(), "MSK_DPAR_DATA_TOL_C_HUGE", 1E3);
mosek_solver.Solve(prog, {}, solver_options, &result);
EXPECT_FALSE(result.is_success());
// This response code is defined in
// https://docs.mosek.com/10.1/capi/response-codes.html#mosek.rescode
const int MSK_RES_ERR_HUGE_C{1375};
EXPECT_EQ(result.get_solver_details<MosekSolver>().rescode,
MSK_RES_ERR_HUGE_C);

// Solve with 1e6 => success.
solver_options.SetOption(MosekSolver::id(), "MSK_DPAR_DATA_TOL_C_HUGE", 1E6);
mosek_solver.Solve(prog, {}, solver_options, &result);
EXPECT_TRUE(result.is_success());
Expand All @@ -332,14 +342,35 @@ GTEST_TEST(MosekSolver, SolverOptionsErrorTest) {
MathematicalProgram prog;
auto x = prog.NewContinuousVariables<2>();
prog.AddLinearConstraint(x(0) + x(1) >= 0);

MathematicalProgramResult result;
MosekSolver mosek_solver;
SolverOptions solver_options;
solver_options.SetOption(MosekSolver::id(), "non-existing options", 42);
DRAKE_EXPECT_THROWS_MESSAGE(
mosek_solver.Solve(prog, {}, solver_options, &result),
".*cannot set Mosek option \'non-existing options\' to value \'42\'.*");

// Test `int`.
{
SolverOptions solver_options;
solver_options.SetOption(MosekSolver::id(), "no_such_option", 42);
DRAKE_EXPECT_THROWS_MESSAGE(
mosek_solver.Solve(prog, {}, solver_options, &result),
".*cannot set Mosek option \'no_such_option\' to value \'42\'.*");
}

// Test `double`.
{
SolverOptions solver_options;
solver_options.SetOption(MosekSolver::id(), "no_such_option", 0.5);
DRAKE_EXPECT_THROWS_MESSAGE(
mosek_solver.Solve(prog, {}, solver_options, &result),
".*cannot set Mosek option \'no_such_option\' to value \'0.5\'.*");
}

// Test `string`.
{
SolverOptions solver_options;
solver_options.SetOption(MosekSolver::id(), "no_such_option", "foo");
DRAKE_EXPECT_THROWS_MESSAGE(
mosek_solver.Solve(prog, {}, solver_options, &result),
".*cannot set Mosek option \'no_such_option\' to value \'foo\'.*");
}
}

GTEST_TEST(MosekTest, Write) {
Expand Down
7 changes: 7 additions & 0 deletions solvers/test/nlopt_solver_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <gtest/gtest.h>

#include "drake/common/test_utilities/expect_throws_message.h"
#include "drake/solvers/mathematical_program.h"
#include "drake/solvers/test/linear_program_examples.h"
#include "drake/solvers/test/mathematical_program_test_util.h"
Expand Down Expand Up @@ -55,6 +56,12 @@ GTEST_TEST(NloptSolverTest, SetAlgorithm) {
const auto result =
solver.Solve(prog, Eigen::VectorXd::Ones(2), solver_options);
ASSERT_TRUE(result.is_success());

solver_options.SetOption(solver.id(), NloptSolver::AlgorithmName(),
"FOO_BAR");
DRAKE_EXPECT_THROWS_MESSAGE(
solver.Solve(prog, Eigen::VectorXd::Ones(2), solver_options),
".*Unknown.*algorithm.*");
}

TEST_F(QuadraticEqualityConstrainedProgram1, Test) {
Expand Down
13 changes: 7 additions & 6 deletions solvers/test/snopt_solver_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -547,26 +547,27 @@ GTEST_TEST(SnoptSolverTest, EckhardtDualSolution) {
GTEST_TEST(SnoptSolverTest, BadIntegerParameter) {
SnoptSolver solver;
MathematicalProgram prog;
prog.SetSolverOption(solver.solver_id(), "not an option", 15);
prog.SetSolverOption(solver.solver_id(), "not_an_option", 15);
DRAKE_EXPECT_THROWS_MESSAGE(
solver.Solve(prog),
"Error setting Snopt integer parameter not an option");
"Error setting Snopt integer parameter not_an_option");
}

GTEST_TEST(SnoptSolverTest, BadDoubleParameter) {
SnoptSolver solver;
MathematicalProgram prog;
prog.SetSolverOption(solver.solver_id(), "not an option", 15.0);
prog.SetSolverOption(solver.solver_id(), "not_an_option", 15.1);
DRAKE_EXPECT_THROWS_MESSAGE(
solver.Solve(prog), "Error setting Snopt double parameter not an option");
solver.Solve(prog),
"Error setting Snopt double parameter not_an_option");
}

GTEST_TEST(SnoptSolverTest, BadStringParameter) {
SnoptSolver solver;
MathematicalProgram prog;
prog.SetSolverOption(solver.solver_id(), "not an option", "test");
prog.SetSolverOption(solver.solver_id(), "not_an_option", "test");
DRAKE_EXPECT_THROWS_MESSAGE(
solver.Solve(prog), "Error setting Snopt string parameter not an option");
solver.Solve(prog), "Error setting Snopt string parameter not_an_option");
}

GTEST_TEST(SnoptSolverTest, TestNonconvexQP) {
Expand Down