Skip to content

Commit

Permalink
Add ClarabelSolver to ChooseBestSolver. (RobotLocomotion#20587)
Browse files Browse the repository at this point in the history
  • Loading branch information
hongkai-dai authored and RussTedrake committed Dec 27, 2023
1 parent 24164af commit 26129cf
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 15 deletions.
2 changes: 2 additions & 0 deletions solvers/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ drake_cc_library(
":solver_interface",
],
deps = [
":clarabel_solver",
":clp_solver",
":csdp_solver",
":equality_constrained_qp_solver",
Expand Down Expand Up @@ -1850,6 +1851,7 @@ drake_cc_googletest(
name = "choose_best_solver_test",
deps = [
":choose_best_solver",
":clarabel_solver",
":clp_solver",
":csdp_solver",
":equality_constrained_qp_solver",
Expand Down
26 changes: 21 additions & 5 deletions solvers/choose_best_solver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "drake/common/drake_assert.h"
#include "drake/common/never_destroyed.h"
#include "drake/solvers/clarabel_solver.h"
#include "drake/solvers/clp_solver.h"
#include "drake/solvers/csdp_solver.h"
#include "drake/solvers/equality_constrained_qp_solver.h"
Expand Down Expand Up @@ -71,7 +72,8 @@ class StaticSolverInterface {
};

// The list of all solvers compiled in Drake.
constexpr std::array<StaticSolverInterface, 12> kKnownSolvers{
constexpr std::array<StaticSolverInterface, 13> kKnownSolvers{
StaticSolverInterface::Make<ClarabelSolver>(),
StaticSolverInterface::Make<ClpSolver>(),
StaticSolverInterface::Make<CsdpSolver>(),
StaticSolverInterface::Make<EqualityConstrainedQPSolver>(),
Expand Down Expand Up @@ -159,7 +161,9 @@ void GetAvailableSolversHelper(
// faster than Mosek (as of 07-26-2021), but the difference is not
// significant.
// Clp is slower than Gurobi and Mosek (with the barrier method).
GurobiSolver, MosekSolver, ClpSolver,
// Clarabel is also a very good open-source solver. I found that
// Clarabel is slightly less accurate than Clp.
GurobiSolver, MosekSolver, ClpSolver, ClarabelSolver,
// Dispreferred (generic nonlinear solvers).
// I generally find SNOPT faster than IPOPT. Nlopt is less reliable.
SnoptSolver, IpoptSolver, NloptSolver,
Expand All @@ -182,6 +186,9 @@ void GetAvailableSolversHelper(
// slightly faster than Gurobi. In practice, I find their performance
// comparable, so the order between these two can be switched.
MosekSolver, GurobiSolver,
// Clarabel is an open-source QP solver with relatively good accuracy.
// (But might not be as fast as OSQP).
ClarabelSolver,
// Dispreferred (ADMM, low accuracy).
// Although both OSQP and SCS use ADMM, I find OSQP to be more
// accurate than SCS. Oftentime I find OSQP generates solution with
Expand All @@ -202,6 +209,8 @@ void GetAvailableSolversHelper(
// According to http://plato.asu.edu/ftp/socp.html, Mosek is slightly
// faster than Gurobi for SOCP, but the difference is small.
MosekSolver, GurobiSolver,
// ClarabelSolver is a good open-source convex solver.
ClarabelSolver,
// Dispreferred (cannot handle free variables).
CsdpSolver,
// Dispreferred (ADMM, low accuracy).
Expand All @@ -218,6 +227,8 @@ void GetAvailableSolversHelper(
AddSolversIfAvailable<
// Preferred solvers.
MosekSolver,
// Clarabel is a good open-source convex solver. Preferred.
ClarabelSolver,
// Dispreferred (cannot handle free variables).
CsdpSolver,
// Dispreferred (ADMM, low accuracy).
Expand All @@ -242,6 +253,8 @@ void GetAvailableSolversHelper(
AddSolversIfAvailable<
// Preferred solver.
MosekSolver,
// Open-source preferred solver.
ClarabelSolver,
// Dispreferred solver, low accuracy (with ADMM method).
ScsSolver>(result);
return;
Expand All @@ -264,6 +277,8 @@ void GetAvailableSolversHelper(
// I don't know if Mosek is better than Gurobi for this type of
// programs.
MosekSolver, GurobiSolver,
// Open-source preferred solver.
ClarabelSolver,
// Dispreferred solver (ADMM, low accuracy).
ScsSolver>(result);
return;
Expand Down Expand Up @@ -292,9 +307,10 @@ void GetAvailableSolversHelper(
// order, drawn from all of the partial orders given throughout the
// other case statements shown above.
AddSolversIfAvailable<LinearSystemSolver, EqualityConstrainedQPSolver,
MosekSolver, GurobiSolver, OsqpSolver, ClpSolver,
MobyLCPSolver<double>, SnoptSolver, IpoptSolver,
NloptSolver, CsdpSolver, ScsSolver>(result);
MosekSolver, GurobiSolver, ClarabelSolver,
OsqpSolver, ClpSolver, MobyLCPSolver<double>,
SnoptSolver, IpoptSolver, NloptSolver, CsdpSolver,
ScsSolver>(result);
}
return;
}
Expand Down
3 changes: 1 addition & 2 deletions solvers/mathematical_program_doxygen.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,7 @@
* details). These heuristics can make the problem expensive to solve or
* poorly conditioned.
*
* ▣ Drake's support on Clarabel is experimental. Some Clarabel's features (such
* as positive semidfinite constraints) are not supported by Drake yet.
* ▣ Drake's support on Clarabel is experimental. It is not enabled by default.
*
* △ These solvers are not accurate. They implement ADMM algorithm, which
* converges quickly to a low-accuracy solution, and requires many iterations to
Expand Down
25 changes: 17 additions & 8 deletions solvers/test/choose_best_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/expect_throws_message.h"
#include "drake/solvers/clarabel_solver.h"
#include "drake/solvers/clp_solver.h"
#include "drake/solvers/csdp_solver.h"
#include "drake/solvers/equality_constrained_qp_solver.h"
Expand All @@ -25,6 +26,7 @@ class ChooseBestSolverTest : public ::testing::Test {
ChooseBestSolverTest()
: prog_{},
x_{prog_.NewContinuousVariables<3>()},
clarabel_solver_{std::make_unique<ClarabelSolver>()},
clp_solver_{std::make_unique<ClpSolver>()},
linear_system_solver_{std::make_unique<LinearSystemSolver>()},
equality_constrained_qp_solver_{
Expand Down Expand Up @@ -83,6 +85,7 @@ class ChooseBestSolverTest : public ::testing::Test {
protected:
MathematicalProgram prog_;
VectorDecisionVariable<3> x_;
std::unique_ptr<ClarabelSolver> clarabel_solver_;
std::unique_ptr<ClpSolver> clp_solver_;
std::unique_ptr<LinearSystemSolver> linear_system_solver_;
std::unique_ptr<EqualityConstrainedQPSolver> equality_constrained_qp_solver_;
Expand Down Expand Up @@ -153,29 +156,33 @@ TEST_F(ChooseBestSolverTest, LPsolver) {
prog_.AddLinearConstraint(x_(0) + 2 * x_(1) >= 1);
prog_.AddLinearCost(x_(0) + x_(1));
CheckBestSolver({gurobi_solver_.get(), mosek_solver_.get(), clp_solver_.get(),
snopt_solver_.get(), ipopt_solver_.get(),
nlopt_solver_.get(), csdp_solver_.get(), scs_solver_.get()});
clarabel_solver_.get(), snopt_solver_.get(),
ipopt_solver_.get(), nlopt_solver_.get(), csdp_solver_.get(),
scs_solver_.get()});
CheckGetAvailableSolvers(prog_);
}

TEST_F(ChooseBestSolverTest, QPsolver) {
prog_.AddLinearConstraint(x_(0) + x_(1) >= 1);
prog_.AddQuadraticCost(x_(0) * x_(0));
CheckBestSolver({mosek_solver_.get(), gurobi_solver_.get(),
osqp_solver_.get(), snopt_solver_.get(), ipopt_solver_.get(),
clarabel_solver_.get(), osqp_solver_.get(),
snopt_solver_.get(), ipopt_solver_.get(),
nlopt_solver_.get(), scs_solver_.get()});
CheckGetAvailableSolvers(prog_);
}

TEST_F(ChooseBestSolverTest, LorentzCone) {
prog_.AddLorentzConeConstraint(x_.cast<symbolic::Expression>());
CheckBestSolver({mosek_solver_.get(), gurobi_solver_.get(),
csdp_solver_.get(), scs_solver_.get(), snopt_solver_.get(),
ipopt_solver_.get(), nlopt_solver_.get()});
clarabel_solver_.get(), csdp_solver_.get(),
scs_solver_.get(), snopt_solver_.get(), ipopt_solver_.get(),
nlopt_solver_.get()});
prog_.AddRotatedLorentzConeConstraint(x_.cast<symbolic::Expression>());
CheckBestSolver({mosek_solver_.get(), gurobi_solver_.get(),
csdp_solver_.get(), scs_solver_.get(), snopt_solver_.get(),
ipopt_solver_.get(), nlopt_solver_.get()});
clarabel_solver_.get(), csdp_solver_.get(),
scs_solver_.get(), snopt_solver_.get(), ipopt_solver_.get(),
nlopt_solver_.get()});

prog_.AddPolynomialCost(pow(x_(0), 3));
CheckBestSolver(
Expand All @@ -196,7 +203,8 @@ TEST_F(ChooseBestSolverTest, LinearComplementarityConstraint) {
TEST_F(ChooseBestSolverTest, PositiveSemidefiniteConstraint) {
prog_.AddPositiveSemidefiniteConstraint(
(Matrix2<symbolic::Variable>() << x_(0), x_(1), x_(1), x_(2)).finished());
CheckBestSolver({mosek_solver_.get(), csdp_solver_.get(), scs_solver_.get()});
CheckBestSolver({mosek_solver_.get(), clarabel_solver_.get(),
csdp_solver_.get(), scs_solver_.get()});
CheckGetAvailableSolvers(prog_);
}

Expand Down Expand Up @@ -257,6 +265,7 @@ TEST_F(ChooseBestSolverTest, MakeSolver) {
CheckMakeSolver(*equality_constrained_qp_solver_);
CheckMakeSolver(*mosek_solver_);
CheckMakeSolver(*gurobi_solver_);
CheckMakeSolver(*clarabel_solver_);
CheckMakeSolver(*osqp_solver_);
CheckMakeSolver(*moby_lcp_solver_);
CheckMakeSolver(*snopt_solver_);
Expand Down

0 comments on commit 26129cf

Please sign in to comment.