smooth_feedback
Control and estimation on Lie groups
Loading...
Searching...
No Matches
osqp.hpp
Go to the documentation of this file.
1// Copyright (C) 2022 Petter Nilsson, John B. Mains. MIT License.
2
3#pragma once
4
10#include <Eigen/Sparse>
11#include <osqp/osqp.h>
12
14
15namespace smooth::feedback {
16
29template<typename Problem>
30QPSolution<-1, -1, double> solve_qp_osqp(
31 const Problem & pbm,
32 const QPSolverParams & prm,
33 std::optional<std::reference_wrapper<const QPSolution<-1, -1, double>>> warmstart = {})
34{
35 // Covert to sparse matrices with OSQP indexing
36 Eigen::SparseMatrix<double, Eigen::ColMajor, c_int> P;
37 Eigen::SparseMatrix<double, Eigen::ColMajor, c_int> A;
38 if constexpr (std::is_base_of_v<Eigen::SparseMatrixBase<decltype(pbm.A)>, decltype(pbm.A)>) {
39 A = pbm.A;
40 P = pbm.P.template triangularView<Eigen::Upper>();
41 } else {
42 A = pbm.A.sparseView();
43 Eigen::MatrixXd Pup = pbm.P.template triangularView<Eigen::Upper>();
44 P = Pup.sparseView();
45 A.prune(1e-6);
46 P.prune(1e-6);
47 }
48 A.makeCompressed();
49 P.makeCompressed();
50
51 OSQPSettings * settings = (OSQPSettings *)c_malloc(sizeof(OSQPSettings));
52 osqp_set_default_settings(settings);
53
54 settings->verbose = prm.verbose;
55 settings->sigma = prm.sigma;
56 settings->alpha = prm.alpha;
57 settings->rho = prm.rho;
58 settings->eps_abs = prm.eps_abs;
59 settings->eps_rel = prm.eps_rel;
60 settings->eps_prim_inf = prm.eps_primal_inf;
61 settings->eps_dual_inf = prm.eps_dual_inf;
62 settings->scaling = prm.scaling;
63 settings->check_termination = prm.stop_check_iter;
64 settings->polish = prm.polish;
65 settings->polish_refine_iter = prm.polish_iter;
66 settings->delta = prm.delta;
67
68 settings->adaptive_rho = false;
69 settings->linsys_solver = QDLDL_SOLVER;
70 settings->scaled_termination = false;
71
72 if (prm.max_iter) {
73 settings->max_iter = prm.max_iter.value();
74 } else {
75 settings->max_iter = std::numeric_limits<c_int>::max();
76 }
77 if (prm.max_time) {
78 settings->time_limit = duration_cast<std::chrono::duration<double>>(prm.max_time.value()).count();
79 } else {
80 settings->time_limit = 0;
81 }
82
83 OSQPData * data = (OSQPData *)c_malloc(sizeof(OSQPData));
84 data->n = A.cols();
85 data->m = A.rows();
86 data->A = csc_matrix(A.rows(), A.cols(), A.nonZeros(), A.valuePtr(), A.innerIndexPtr(), A.outerIndexPtr());
87 data->q = const_cast<double *>(pbm.q.data());
88 data->P = csc_matrix(P.rows(), P.cols(), P.nonZeros(), P.valuePtr(), P.innerIndexPtr(), P.outerIndexPtr());
89 data->l = const_cast<double *>(pbm.l.data());
90 data->u = const_cast<double *>(pbm.u.data());
91
92 OSQPWorkspace * work;
93
94 QPSolution<-1, -1, double> ret;
95 ret.code = QPSolutionStatus::Unknown;
96
97 c_int error = osqp_setup(&work, data, settings);
98
99 if (warmstart) {
100 osqp_warm_start(work, warmstart.value().get().primal.data(), warmstart.value().get().dual.data());
101 settings->warm_start = 1;
102 } else {
103 settings->warm_start = 0;
104 }
105
106 if (!error) { error &= osqp_solve(work); }
107
108 if (!error) {
109 switch (work->info->status_val) {
110 case OSQP_SOLVED: {
111 ret.code = QPSolutionStatus::Optimal;
112 break;
113 }
114 case OSQP_PRIMAL_INFEASIBLE: {
115 ret.code = QPSolutionStatus::PrimalInfeasible;
116 break;
117 }
118 case OSQP_DUAL_INFEASIBLE: {
119 ret.code = QPSolutionStatus::DualInfeasible;
120 break;
121 }
122 case OSQP_MAX_ITER_REACHED: {
123 ret.code = QPSolutionStatus::MaxIterations;
124 break;
125 }
126 case OSQP_TIME_LIMIT_REACHED: {
127 ret.code = QPSolutionStatus::MaxTime;
128 break;
129 }
130 default: {
131 break;
132 }
133 }
134
135 ret.iter = work->info->iter;
136 ret.primal = Eigen::Map<const Eigen::Matrix<double, -1, 1>>(work->solution->x, data->n);
137 ret.dual = Eigen::Map<const Eigen::Matrix<double, -1, 1>>(work->solution->y, data->m);
138 ret.objective = work->info->obj_val;
139 }
140
141 osqp_cleanup(work);
142
143 c_free(data->A);
144 c_free(data->P);
145 c_free(data);
146 c_free(settings);
147
148 return ret;
149}
150
151} // namespace smooth::feedback
152
153#endif // SMOOTH__FEEDBACK__COMPAT__OSQP_HPP_
QPSolution<-1, -1, double > solve_qp_osqp(const Problem &pbm, const QPSolverParams &prm, std::optional< std::reference_wrapper< const QPSolution<-1, -1, double > > > warmstart={})
Solve a QuadraticProgram with the OSQP solver.
Definition: osqp.hpp:30
Quadratic Program solver.
Solver solution.
Definition: qp.hpp:97
Options for solve_qp.
Definition: qp_solver.hpp:30
float rho
first dual step size
Definition: qp_solver.hpp:37
uint32_t stop_check_iter
iterations between checking stopping criterion
Definition: qp_solver.hpp:60
std::optional< uint32_t > max_iter
max number of iterations (default no limit)
Definition: qp_solver.hpp:54
float alpha
relaxation parameter
Definition: qp_solver.hpp:35
float eps_dual_inf
threshold for dual infeasibility
Definition: qp_solver.hpp:51
std::optional< std::chrono::nanoseconds > max_time
max solution time (default no limit)
Definition: qp_solver.hpp:57
float eps_rel
relative threshold for convergence
Definition: qp_solver.hpp:47
bool verbose
print solver info to stdout
Definition: qp_solver.hpp:32
bool polish
run solution polishing (uses dynamic memory)
Definition: qp_solver.hpp:63
float eps_primal_inf
threshold for primal infeasibility
Definition: qp_solver.hpp:49
float eps_abs
absolute threshold for convergence
Definition: qp_solver.hpp:45
uint32_t polish_iter
number of iterations to refine polish
Definition: qp_solver.hpp:65
float delta
regularization parameter for polishing
Definition: qp_solver.hpp:67
float sigma
second dual step length
Definition: qp_solver.hpp:39