Program Listing for File wrapper.hpp
↰ Return to documentation for file (include/proxsuite/proxqp/dense/wrapper.hpp)
//
// Copyright (c) 2022 INRIA
//
#ifndef PROXSUITE_PROXQP_DENSE_WRAPPER_HPP
#define PROXSUITE_PROXQP_DENSE_WRAPPER_HPP
#include <proxsuite/proxqp/sparse/wrapper.hpp>
#include <proxsuite/proxqp/dense/solver.hpp>
#include <proxsuite/proxqp/dense/helpers.hpp>
#include <proxsuite/proxqp/dense/preconditioner/ruiz.hpp>
#include <chrono>
namespace proxsuite {
namespace proxqp {
namespace dense {
template<typename T>
DenseBackend
dense_backend_choice(DenseBackend _dense_backend,
isize dim,
isize n_eq,
isize n_in,
bool box_constraints)
{
if (_dense_backend == DenseBackend::Automatic) {
isize n_constraints(n_in);
if (box_constraints) {
n_constraints += dim;
}
T threshold(1.5);
T frequence(0.2);
T PrimalDualLDLTCost =
0.5 * std::pow(T(n_eq) / T(dim), 2) +
0.17 * (std::pow(T(n_eq) / T(dim), 3) +
std::pow(T(n_constraints) / T(dim), 3)) +
frequence * std::pow(T(n_eq + n_constraints) / T(dim), 2) / T(dim);
T PrimalLDLTCost =
threshold *
((0.5 * T(n_eq) + T(n_constraints)) / T(dim) + frequence / T(dim));
bool choice = PrimalDualLDLTCost > PrimalLDLTCost;
if (choice) {
return DenseBackend::PrimalLDLT;
} else {
return DenseBackend::PrimalDualLDLT;
}
} else {
return _dense_backend;
}
}
template<typename T>
struct QP
{
private:
// structure of the problem
// not supposed to change
DenseBackend dense_backend;
bool box_constraints;
HessianType hessian_type;
public:
Results<T> results;
Settings<T> settings;
Model<T> model;
Workspace<T> work;
preconditioner::RuizEquilibration<T> ruiz;
QP(isize _dim,
isize _n_eq,
isize _n_in,
bool _box_constraints,
proxsuite::proxqp::HessianType _hessian_type,
DenseBackend _dense_backend)
: dense_backend(dense_backend_choice<T>(_dense_backend,
_dim,
_n_eq,
_n_in,
_box_constraints))
, box_constraints(_box_constraints)
, hessian_type(_hessian_type)
, results(_dim, _n_eq, _n_in, _box_constraints, dense_backend)
, settings(dense_backend)
, model(_dim, _n_eq, _n_in, _box_constraints)
, work(_dim, _n_eq, _n_in, _box_constraints, dense_backend)
, ruiz(preconditioner::RuizEquilibration<T>{ _dim,
_n_eq,
_n_in,
_box_constraints })
{
work.timer.stop();
}
QP(isize _dim,
isize _n_eq,
isize _n_in,
bool _box_constraints,
DenseBackend _dense_backend,
proxsuite::proxqp::HessianType _hessian_type)
: dense_backend(dense_backend_choice<T>(_dense_backend,
_dim,
_n_eq,
_n_in,
_box_constraints))
, box_constraints(_box_constraints)
, hessian_type(_hessian_type)
, results(_dim, _n_eq, _n_in, _box_constraints, dense_backend)
, settings(dense_backend)
, model(_dim, _n_eq, _n_in, _box_constraints)
, work(_dim, _n_eq, _n_in, _box_constraints, dense_backend)
, ruiz(preconditioner::RuizEquilibration<T>{ _dim,
_n_eq,
_n_in,
_box_constraints })
{
work.timer.stop();
}
QP(isize _dim,
isize _n_eq,
isize _n_in,
bool _box_constraints,
proxsuite::proxqp::HessianType _hessian_type)
: dense_backend(dense_backend_choice<T>(DenseBackend::Automatic,
_dim,
_n_eq,
_n_in,
_box_constraints))
, box_constraints(_box_constraints)
, hessian_type(_hessian_type)
, results(_dim, _n_eq, _n_in, _box_constraints, dense_backend)
, settings(dense_backend)
, model(_dim, _n_eq, _n_in, _box_constraints)
, work(_dim, _n_eq, _n_in, _box_constraints, dense_backend)
, ruiz(preconditioner::RuizEquilibration<T>{ _dim,
_n_eq,
_n_in,
_box_constraints })
{
work.timer.stop();
}
QP(isize _dim,
isize _n_eq,
isize _n_in,
bool _box_constraints,
DenseBackend _dense_backend)
: dense_backend(dense_backend_choice<T>(_dense_backend,
_dim,
_n_eq,
_n_in,
_box_constraints))
, box_constraints(_box_constraints)
, hessian_type(HessianType::Dense)
, results(_dim, _n_eq, _n_in, _box_constraints, dense_backend)
, settings(dense_backend)
, model(_dim, _n_eq, _n_in, _box_constraints)
, work(_dim, _n_eq, _n_in, _box_constraints, dense_backend)
, ruiz(preconditioner::RuizEquilibration<T>{ _dim,
_n_eq,
_n_in,
_box_constraints })
{
work.timer.stop();
}
QP(isize _dim, isize _n_eq, isize _n_in, bool _box_constraints)
: dense_backend(dense_backend_choice<T>(DenseBackend::Automatic,
_dim,
_n_eq,
_n_in,
_box_constraints))
, box_constraints(_box_constraints)
, hessian_type(proxsuite::proxqp::HessianType::Dense)
, results(_dim, _n_eq, _n_in, _box_constraints, dense_backend)
, settings(dense_backend)
, model(_dim, _n_eq, _n_in, _box_constraints)
, work(_dim, _n_eq, _n_in, _box_constraints, dense_backend)
, ruiz(preconditioner::RuizEquilibration<T>{ _dim,
_n_eq,
_n_in,
_box_constraints })
{
work.timer.stop();
}
QP(isize _dim,
isize _n_eq,
isize _n_in,
proxsuite::proxqp::HessianType _hessian_type)
: dense_backend(dense_backend_choice<T>(DenseBackend::Automatic,
_dim,
_n_eq,
_n_in,
false))
, box_constraints(false)
, hessian_type(_hessian_type)
, results(_dim, _n_eq, _n_in, false, dense_backend)
, settings(dense_backend)
, model(_dim, _n_eq, _n_in, false)
, work(_dim, _n_eq, _n_in, false, dense_backend)
, ruiz(preconditioner::RuizEquilibration<T>{ _dim, _n_eq, _n_in, false })
{
work.timer.stop();
}
QP(isize _dim, isize _n_eq, isize _n_in)
: dense_backend(dense_backend_choice<T>(DenseBackend::Automatic,
_dim,
_n_eq,
_n_in,
false))
, box_constraints(false)
, hessian_type(proxsuite::proxqp::HessianType::Dense)
, results(_dim, _n_eq, _n_in, false, dense_backend)
, settings(dense_backend)
, model(_dim, _n_eq, _n_in, false)
, work(_dim, _n_eq, _n_in, false, dense_backend)
, ruiz(preconditioner::RuizEquilibration<T>{ _dim, _n_eq, _n_in, false })
{
work.timer.stop();
}
bool is_box_constrained() const { return box_constraints; };
DenseBackend which_dense_backend() const { return dense_backend; };
HessianType which_hessian_type() const { return hessian_type; };
void init(optional<MatRef<T>> H,
optional<VecRef<T>> g,
optional<MatRef<T>> A,
optional<VecRef<T>> b,
optional<MatRef<T>> C,
optional<VecRef<T>> l,
optional<VecRef<T>> u,
bool compute_preconditioner = true,
optional<T> rho = nullopt,
optional<T> mu_eq = nullopt,
optional<T> mu_in = nullopt,
optional<T> manual_minimal_H_eigenvalue = nullopt)
{
PROXSUITE_THROW_PRETTY(
box_constraints == true,
std::invalid_argument,
"wrong model setup: the QP object is designed with box "
"constraints, but is initialized without lower or upper box "
"inequalities.");
// dense case
if (settings.compute_timings) {
work.timer.stop();
work.timer.start();
}
settings.compute_preconditioner = compute_preconditioner;
// check the model is valid
if (g != nullopt && g.value().size() != 0) {
PROXSUITE_CHECK_ARGUMENT_SIZE(
g.value().size(),
model.dim,
"the dimension wrt the primal variable x variable for initializing g "
"is not valid.");
} else {
g.reset();
}
if (b != nullopt && b.value().size() != 0) {
PROXSUITE_CHECK_ARGUMENT_SIZE(
b.value().size(),
model.n_eq,
"the dimension wrt equality constrained variables for initializing b "
"is not valid.");
} else {
b.reset();
}
if (u != nullopt && u.value().size() != 0) {
PROXSUITE_CHECK_ARGUMENT_SIZE(
u.value().size(),
model.n_in,
"the dimension wrt inequality constrained variables for initializing u "
"is not valid.");
} else {
u.reset();
}
if (l != nullopt && l.value().size() != 0) {
PROXSUITE_CHECK_ARGUMENT_SIZE(
l.value().size(),
model.n_in,
"the dimension wrt inequality constrained variables for initializing l "
"is not valid.");
} else {
l.reset();
}
if (H != nullopt && H.value().size() != 0) {
PROXSUITE_CHECK_ARGUMENT_SIZE(
H.value().rows(),
model.dim,
"the row dimension for initializing H is not valid.");
PROXSUITE_CHECK_ARGUMENT_SIZE(
H.value().cols(),
model.dim,
"the column dimension for initializing H is not valid.");
} else {
H.reset();
}
if (A != nullopt && A.value().size() != 0) {
PROXSUITE_CHECK_ARGUMENT_SIZE(
A.value().rows(),
model.n_eq,
"the row dimension for initializing A is not valid.");
PROXSUITE_CHECK_ARGUMENT_SIZE(
A.value().cols(),
model.dim,
"the column dimension for initializing A is not valid.");
} else {
A.reset();
}
if (C != nullopt && C.value().size() != 0) {
PROXSUITE_CHECK_ARGUMENT_SIZE(
C.value().rows(),
model.n_in,
"the row dimension for initializing C is not valid.");
PROXSUITE_CHECK_ARGUMENT_SIZE(
C.value().cols(),
model.dim,
"the column dimension for initializing C is not valid.");
} else {
C.reset();
}
if (settings.initial_guess ==
InitialGuessStatus::WARM_START_WITH_PREVIOUS_RESULT) {
work.refactorize =
true; // necessary for the first solve (then refactorize only if there
// is an update of the matrices)
} else {
work.refactorize = false;
}
work.proximal_parameter_update = false;
if (settings.compute_timings) {
work.timer.stop();
work.timer.start();
}
PreconditionerStatus preconditioner_status;
if (compute_preconditioner) {
preconditioner_status = proxsuite::proxqp::PreconditionerStatus::EXECUTE;
} else {
preconditioner_status = proxsuite::proxqp::PreconditionerStatus::IDENTITY;
}
proxsuite::proxqp::dense::update_proximal_parameters(
settings, results, work, rho, mu_eq, mu_in);
proxsuite::proxqp::dense::
update_default_rho_with_minimal_Hessian_eigen_value(
manual_minimal_H_eigenvalue, results, settings);
typedef optional<VecRef<T>> optional_VecRef;
proxsuite::proxqp::dense::setup(H,
g,
A,
b,
C,
l,
u,
optional_VecRef(nullopt),
optional_VecRef(nullopt),
settings,
model,
work,
results,
box_constraints,
ruiz,
preconditioner_status,
hessian_type);
work.is_initialized = true;
if (settings.compute_timings) {
results.info.setup_time = work.timer.elapsed().user; // in microseconds
}
};
void init(optional<MatRef<T>> H,
optional<VecRef<T>> g,
optional<MatRef<T>> A,
optional<VecRef<T>> b,
optional<MatRef<T>> C,
optional<VecRef<T>> l,
optional<VecRef<T>> u,
optional<VecRef<T>> l_box,
optional<VecRef<T>> u_box,
bool compute_preconditioner = true,
optional<T> rho = nullopt,
optional<T> mu_eq = nullopt,
optional<T> mu_in = nullopt,
optional<T> manual_minimal_H_eigenvalue = nullopt)
{
// dense case
if (settings.compute_timings) {
work.timer.stop();
work.timer.start();
}
settings.compute_preconditioner = compute_preconditioner;
PROXSUITE_THROW_PRETTY(
box_constraints == false && (l_box != nullopt || u_box != nullopt),
std::invalid_argument,
"wrong model setup: the QP object is designed without box "
"constraints, but is initialized with lower or upper box inequalities.");
if (l_box != nullopt && l_box.value().size() != 0) {
PROXSUITE_CHECK_ARGUMENT_SIZE(l_box.value().size(),
model.dim,
"the dimension wrt the primal variable x "
"variable for initializing l_box "
"is not valid.");
} else {
l_box.reset();
}
if (u_box != nullopt && u_box.value().size() != 0) {
PROXSUITE_CHECK_ARGUMENT_SIZE(u_box.value().size(),
model.dim,
"the dimension wrt the primal variable x "
"variable for initializing u_box "
"is not valid.");
} else {
l_box.reset();
}
// check the model is valid
if (g != nullopt && g.value().size() != 0) {
PROXSUITE_CHECK_ARGUMENT_SIZE(
g.value().size(),
model.dim,
"the dimension wrt the primal variable x variable for initializing g "
"is not valid.");
} else {
g.reset();
}
if (b != nullopt && b.value().size() != 0) {
PROXSUITE_CHECK_ARGUMENT_SIZE(
b.value().size(),
model.n_eq,
"the dimension wrt equality constrained variables for initializing b "
"is not valid.");
} else {
b.reset();
}
if (u != nullopt && u.value().size() != 0) {
PROXSUITE_CHECK_ARGUMENT_SIZE(
u.value().size(),
model.n_in,
"the dimension wrt inequality constrained variables for initializing u "
"is not valid.");
} else {
u.reset();
}
if (u_box != nullopt && u_box.value().size() != 0) {
PROXSUITE_CHECK_ARGUMENT_SIZE(
u_box.value().size(),
model.dim,
"the dimension wrt box inequality constrained variables for "
"initializing u_box "
"is not valid.");
} else {
u_box.reset();
}
if (l != nullopt && l.value().size() != 0) {
PROXSUITE_CHECK_ARGUMENT_SIZE(
l.value().size(),
model.n_in,
"the dimension wrt inequality constrained variables for initializing l "
"is not valid.");
} else {
l.reset();
}
if (l_box != nullopt && l_box.value().size() != 0) {
PROXSUITE_CHECK_ARGUMENT_SIZE(
l_box.value().size(),
model.dim,
"the dimension wrt box inequality constrained variables for "
"initializing l_box "
"is not valid.");
} else {
l_box.reset();
}
if (H != nullopt && H.value().size() != 0) {
PROXSUITE_CHECK_ARGUMENT_SIZE(
H.value().rows(),
model.dim,
"the row dimension for initializing H is not valid.");
PROXSUITE_CHECK_ARGUMENT_SIZE(
H.value().cols(),
model.dim,
"the column dimension for initializing H is not valid.");
} else {
H.reset();
}
if (A != nullopt && A.value().size() != 0) {
PROXSUITE_CHECK_ARGUMENT_SIZE(
A.value().rows(),
model.n_eq,
"the row dimension for initializing A is not valid.");
PROXSUITE_CHECK_ARGUMENT_SIZE(
A.value().cols(),
model.dim,
"the column dimension for initializing A is not valid.");
} else {
A.reset();
}
if (C != nullopt && C.value().size() != 0) {
PROXSUITE_CHECK_ARGUMENT_SIZE(
C.value().rows(),
model.n_in,
"the row dimension for initializing C is not valid.");
PROXSUITE_CHECK_ARGUMENT_SIZE(
C.value().cols(),
model.dim,
"the column dimension for initializing C is not valid.");
} else {
C.reset();
}
if (settings.initial_guess ==
InitialGuessStatus::WARM_START_WITH_PREVIOUS_RESULT) {
work.refactorize =
true; // necessary for the first solve (then refactorize only if there
// is an update of the matrices)
} else {
work.refactorize = false;
}
work.proximal_parameter_update = false;
if (settings.compute_timings) {
work.timer.stop();
work.timer.start();
}
PreconditionerStatus preconditioner_status;
if (compute_preconditioner) {
preconditioner_status = proxsuite::proxqp::PreconditionerStatus::EXECUTE;
} else {
preconditioner_status = proxsuite::proxqp::PreconditionerStatus::IDENTITY;
}
proxsuite::proxqp::dense::update_proximal_parameters(
settings, results, work, rho, mu_eq, mu_in);
proxsuite::proxqp::dense::
update_default_rho_with_minimal_Hessian_eigen_value(
manual_minimal_H_eigenvalue, results, settings);
proxsuite::proxqp::dense::setup(H,
g,
A,
b,
C,
l,
u,
l_box,
u_box,
settings,
model,
work,
results,
box_constraints,
ruiz,
preconditioner_status,
hessian_type);
work.is_initialized = true;
if (settings.compute_timings) {
results.info.setup_time = work.timer.elapsed().user; // in microseconds
}
};
void update(optional<MatRef<T>> H,
optional<VecRef<T>> g,
optional<MatRef<T>> A,
optional<VecRef<T>> b,
optional<MatRef<T>> C,
optional<VecRef<T>> l,
optional<VecRef<T>> u,
bool update_preconditioner = false,
optional<T> rho = nullopt,
optional<T> mu_eq = nullopt,
optional<T> mu_in = nullopt,
optional<T> manual_minimal_H_eigenvalue = nullopt)
{
PROXSUITE_THROW_PRETTY(
box_constraints == true,
std::invalid_argument,
"wrong model setup: the QP object is designed without box "
"constraints, but the update does not include lower or upper box "
"inequalities.");
settings.update_preconditioner = update_preconditioner;
if (!work.is_initialized) {
init(H, g, A, b, C, l, u, update_preconditioner, rho, mu_eq, mu_in);
return;
}
// dense case
work.refactorize = false;
work.proximal_parameter_update = false;
if (settings.compute_timings) {
work.timer.stop();
work.timer.start();
}
PreconditionerStatus preconditioner_status;
if (update_preconditioner) {
preconditioner_status = proxsuite::proxqp::PreconditionerStatus::EXECUTE;
} else {
preconditioner_status = proxsuite::proxqp::PreconditionerStatus::KEEP;
}
const bool matrix_update =
!(H == nullopt && g == nullopt && A == nullopt && b == nullopt &&
C == nullopt && u == nullopt && l == nullopt);
if (matrix_update) {
typedef optional<VecRef<T>> optional_VecRef;
proxsuite::proxqp::dense::update(H,
g,
A,
b,
C,
l,
u,
optional_VecRef(nullopt),
optional_VecRef(nullopt),
model,
work,
box_constraints);
}
proxsuite::proxqp::dense::update_proximal_parameters(
settings, results, work, rho, mu_eq, mu_in);
proxsuite::proxqp::dense::
update_default_rho_with_minimal_Hessian_eigen_value(
manual_minimal_H_eigenvalue, results, settings);
typedef optional<MatRef<T>> optional_MatRef;
typedef optional<VecRef<T>> optional_VecRef;
proxsuite::proxqp::dense::setup(/* avoid double assignation */
optional_MatRef(nullopt),
optional_VecRef(nullopt),
optional_MatRef(nullopt),
optional_VecRef(nullopt),
optional_MatRef(nullopt),
optional_VecRef(nullopt),
optional_VecRef(nullopt),
optional_VecRef(nullopt),
optional_VecRef(nullopt),
settings,
model,
work,
results,
box_constraints,
ruiz,
preconditioner_status,
hessian_type);
if (settings.compute_timings) {
results.info.setup_time = work.timer.elapsed().user; // in microseconds
}
};
void update(optional<MatRef<T>> H,
optional<VecRef<T>> g,
optional<MatRef<T>> A,
optional<VecRef<T>> b,
optional<MatRef<T>> C,
optional<VecRef<T>> l,
optional<VecRef<T>> u,
optional<VecRef<T>> l_box,
optional<VecRef<T>> u_box,
bool update_preconditioner = false,
optional<T> rho = nullopt,
optional<T> mu_eq = nullopt,
optional<T> mu_in = nullopt,
optional<T> manual_minimal_H_eigenvalue = nullopt)
{
PROXSUITE_THROW_PRETTY(
box_constraints == false && (l_box != nullopt || u_box != nullopt),
std::invalid_argument,
"wrong model setup: the QP object is designed without box "
"constraints, but the update includes lower or upper box inequalities.");
settings.update_preconditioner = update_preconditioner;
if (!work.is_initialized) {
init(H,
g,
A,
b,
C,
l,
u,
l_box,
u_box,
update_preconditioner,
rho,
mu_eq,
mu_in);
return;
}
// dense case
work.refactorize = false;
work.proximal_parameter_update = false;
if (settings.compute_timings) {
work.timer.stop();
work.timer.start();
}
PreconditionerStatus preconditioner_status;
if (update_preconditioner) {
preconditioner_status = proxsuite::proxqp::PreconditionerStatus::EXECUTE;
} else {
preconditioner_status = proxsuite::proxqp::PreconditionerStatus::KEEP;
}
const bool matrix_update =
!(H == nullopt && g == nullopt && A == nullopt && b == nullopt &&
C == nullopt && u == nullopt && l == nullopt && u_box == nullopt &&
l_box == nullopt);
if (matrix_update) {
proxsuite::proxqp::dense::update(
H, g, A, b, C, l, u, l_box, u_box, model, work, box_constraints);
}
proxsuite::proxqp::dense::update_proximal_parameters(
settings, results, work, rho, mu_eq, mu_in);
proxsuite::proxqp::dense::
update_default_rho_with_minimal_Hessian_eigen_value(
manual_minimal_H_eigenvalue, results, settings);
typedef optional<MatRef<T>> optional_MatRef;
typedef optional<VecRef<T>> optional_VecRef;
proxsuite::proxqp::dense::setup(/* avoid double assignation */
optional_MatRef(nullopt),
optional_VecRef(nullopt),
optional_MatRef(nullopt),
optional_VecRef(nullopt),
optional_MatRef(nullopt),
optional_VecRef(nullopt),
optional_VecRef(nullopt),
optional_VecRef(nullopt),
optional_VecRef(nullopt),
settings,
model,
work,
results,
box_constraints,
ruiz,
preconditioner_status,
hessian_type);
if (settings.compute_timings) {
results.info.setup_time = work.timer.elapsed().user; // in microseconds
}
};
void solve()
{
qp_solve( //
settings,
model,
results,
work,
box_constraints,
dense_backend,
hessian_type,
ruiz);
};
void solve(optional<VecRef<T>> x,
optional<VecRef<T>> y,
optional<VecRef<T>> z)
{
proxsuite::proxqp::dense::warm_start(x, y, z, results, settings, model);
qp_solve( //
settings,
model,
results,
work,
box_constraints,
dense_backend,
hessian_type,
ruiz);
};
void cleanup()
{
results.cleanup(settings);
work.cleanup(box_constraints);
}
};
template<typename T>
proxqp::Results<T>
solve(
optional<MatRef<T>> H,
optional<VecRef<T>> g,
optional<MatRef<T>> A,
optional<VecRef<T>> b,
optional<MatRef<T>> C,
optional<VecRef<T>> l,
optional<VecRef<T>> u,
optional<VecRef<T>> x = nullopt,
optional<VecRef<T>> y = nullopt,
optional<VecRef<T>> z = nullopt,
optional<T> eps_abs = nullopt,
optional<T> eps_rel = nullopt,
optional<T> rho = nullopt,
optional<T> mu_eq = nullopt,
optional<T> mu_in = nullopt,
optional<bool> verbose = nullopt,
bool compute_preconditioner = true,
bool compute_timings = false,
optional<isize> max_iter = nullopt,
proxsuite::proxqp::InitialGuessStatus initial_guess =
proxsuite::proxqp::InitialGuessStatus::EQUALITY_CONSTRAINED_INITIAL_GUESS,
bool check_duality_gap = false,
optional<T> eps_duality_gap_abs = nullopt,
optional<T> eps_duality_gap_rel = nullopt,
bool primal_infeasibility_solving = false,
optional<T> manual_minimal_H_eigenvalue = nullopt)
{
isize n(0);
isize n_eq(0);
isize n_in(0);
if (H != nullopt) {
n = H.value().rows();
}
if (A != nullopt) {
n_eq = A.value().rows();
}
if (C != nullopt) {
n_in = C.value().rows();
}
QP<T> Qp(n, n_eq, n_in, false, DenseBackend::PrimalDualLDLT);
Qp.settings.initial_guess = initial_guess;
Qp.settings.check_duality_gap = check_duality_gap;
if (eps_abs != nullopt) {
Qp.settings.eps_abs = eps_abs.value();
}
if (eps_rel != nullopt) {
Qp.settings.eps_rel = eps_rel.value();
}
if (verbose != nullopt) {
Qp.settings.verbose = verbose.value();
}
if (max_iter != nullopt) {
Qp.settings.max_iter = max_iter.value();
}
if (eps_duality_gap_abs != nullopt) {
Qp.settings.eps_duality_gap_abs = eps_duality_gap_abs.value();
}
if (eps_duality_gap_rel != nullopt) {
Qp.settings.eps_duality_gap_rel = eps_duality_gap_rel.value();
}
Qp.settings.compute_timings = compute_timings;
Qp.settings.primal_infeasibility_solving = primal_infeasibility_solving;
if (manual_minimal_H_eigenvalue != nullopt) {
Qp.init(H,
g,
A,
b,
C,
l,
u,
compute_preconditioner,
rho,
mu_eq,
mu_in,
manual_minimal_H_eigenvalue.value());
} else {
Qp.init(
H, g, A, b, C, l, u, compute_preconditioner, rho, mu_eq, mu_in, nullopt);
}
Qp.solve(x, y, z);
return Qp.results;
}
template<typename T>
proxqp::Results<T>
solve(
optional<MatRef<T>> H,
optional<VecRef<T>> g,
optional<MatRef<T>> A,
optional<VecRef<T>> b,
optional<MatRef<T>> C,
optional<VecRef<T>> l,
optional<VecRef<T>> u,
optional<VecRef<T>> l_box,
optional<VecRef<T>> u_box,
optional<VecRef<T>> x = nullopt,
optional<VecRef<T>> y = nullopt,
optional<VecRef<T>> z = nullopt,
optional<T> eps_abs = nullopt,
optional<T> eps_rel = nullopt,
optional<T> rho = nullopt,
optional<T> mu_eq = nullopt,
optional<T> mu_in = nullopt,
optional<bool> verbose = nullopt,
bool compute_preconditioner = true,
bool compute_timings = false,
optional<isize> max_iter = nullopt,
proxsuite::proxqp::InitialGuessStatus initial_guess =
proxsuite::proxqp::InitialGuessStatus::EQUALITY_CONSTRAINED_INITIAL_GUESS,
bool check_duality_gap = false,
optional<T> eps_duality_gap_abs = nullopt,
optional<T> eps_duality_gap_rel = nullopt,
bool primal_infeasibility_solving = false,
optional<T> manual_minimal_H_eigenvalue = nullopt)
{
isize n(0);
isize n_eq(0);
isize n_in(0);
if (H != nullopt) {
n = H.value().rows();
}
if (A != nullopt) {
n_eq = A.value().rows();
}
if (C != nullopt) {
n_in = C.value().rows();
}
QP<T> Qp(n, n_eq, n_in, true, DenseBackend::PrimalDualLDLT);
Qp.settings.initial_guess = initial_guess;
Qp.settings.check_duality_gap = check_duality_gap;
if (eps_abs != nullopt) {
Qp.settings.eps_abs = eps_abs.value();
}
if (eps_rel != nullopt) {
Qp.settings.eps_rel = eps_rel.value();
}
if (verbose != nullopt) {
Qp.settings.verbose = verbose.value();
}
if (max_iter != nullopt) {
Qp.settings.max_iter = max_iter.value();
}
if (eps_duality_gap_abs != nullopt) {
Qp.settings.eps_duality_gap_abs = eps_duality_gap_abs.value();
}
if (eps_duality_gap_rel != nullopt) {
Qp.settings.eps_duality_gap_rel = eps_duality_gap_rel.value();
}
Qp.settings.compute_timings = compute_timings;
Qp.settings.primal_infeasibility_solving = primal_infeasibility_solving;
if (manual_minimal_H_eigenvalue != nullopt) {
Qp.init(H,
g,
A,
b,
C,
l,
u,
l_box,
u_box,
compute_preconditioner,
rho,
mu_eq,
mu_in,
manual_minimal_H_eigenvalue.value());
} else {
Qp.init(H,
g,
A,
b,
C,
l,
u,
l_box,
u_box,
compute_preconditioner,
rho,
mu_eq,
mu_in,
nullopt);
}
Qp.solve(x, y, z);
return Qp.results;
}
template<typename T>
bool
operator==(const QP<T>& qp1, const QP<T>& qp2)
{
bool value = qp1.model == qp2.model && qp1.settings == qp2.settings &&
qp1.results == qp2.results &&
qp1.is_box_constrained() == qp2.is_box_constrained();
return value;
}
template<typename T>
bool
operator!=(const QP<T>& qp1, const QP<T>& qp2)
{
return !(qp1 == qp2);
}
template<typename T>
struct BatchQP
{
std::vector<QP<T>> qp_vector;
dense::isize m_size;
explicit BatchQP(size_t batch_size)
{
if (qp_vector.max_size() != batch_size) {
qp_vector.clear();
qp_vector.reserve(batch_size);
}
m_size = 0;
}
QP<T>& init_qp_in_place(dense::isize dim,
dense::isize n_eq,
dense::isize n_in)
{
qp_vector.emplace_back(dim, n_eq, n_in);
auto& qp = qp_vector.back();
m_size++;
return qp;
};
void insert(const QP<T>& qp) { qp_vector.emplace_back(qp); };
QP<T>& get(isize i) { return qp_vector.at(size_t(i)); };
const QP<T>& get(isize i) const { return qp_vector.at(size_t(i)); };
QP<T>& operator[](isize i) { return get(i); };
const QP<T>& operator[](isize i) const { return get(i); };
dense::isize size() { return m_size; };
};
} // namespace dense
} // namespace proxqp
} // namespace proxsuite
#endif /* end of include guard PROXSUITE_PROXQP_DENSE_WRAPPER_HPP */