8#ifndef PROXSUITE_PROXQP_DENSE_HELPERS_HPP
9#define PROXSUITE_PROXQP_DENSE_HELPERS_HPP
18#include <Eigen/Eigenvalues>
31 const Eigen::MatrixBase<VecIn1>& dw,
32 const Eigen::MatrixBase<VecIn2>& rhs,
33 const Eigen::MatrixBase<VecIn3>& err_v,
34 T power_iteration_accuracy,
35 isize nb_power_iteration)
37 auto& dw_cc = dw.const_cast_derived();
38 auto& rhs_cc = rhs.const_cast_derived();
39 auto& err_v_cc = err_v.const_cast_derived();
44 rhs_cc.array() += 1. / std::sqrt(dim);
46 dw_cc.noalias() = H.template selfadjointView<Eigen::Lower>() * rhs_cc;
48 for (isize i = 0; i < nb_power_iteration; i++) {
50 rhs_cc = dw_cc / dw_cc.norm();
51 dw_cc.noalias() = (H.template selfadjointView<Eigen::Lower>() * rhs_cc);
55 err_v_cc = dw_cc - eig * rhs_cc;
56 T err = proxsuite::proxqp::dense::infty_norm(err_v_cc);
59 if (err <= power_iteration_accuracy) {
72 const Eigen::MatrixBase<MatIn>& H,
73 const Eigen::MatrixBase<VecIn1>& dw,
74 const Eigen::MatrixBase<VecIn2>& rhs,
75 const Eigen::MatrixBase<VecIn3>& err_v,
77 T power_iteration_accuracy,
78 isize nb_power_iteration)
83 auto& dw_cc = dw.const_cast_derived();
84 auto& rhs_cc = rhs.const_cast_derived();
85 auto& err_v_cc = err_v.const_cast_derived();
89 rhs_cc.array() += 1. / std::sqrt(dim);
92 -(H.template selfadjointView<Eigen::Lower>() * rhs_cc);
93 dw_cc += max_eigen_value * rhs_cc;
95 for (isize i = 0; i < nb_power_iteration; i++) {
97 rhs_cc = dw_cc / dw_cc.norm();
98 dw_cc.noalias() = -(H.template selfadjointView<Eigen::Lower>() * rhs_cc);
99 dw_cc += max_eigen_value * rhs_cc;
101 eig = rhs_cc.dot(dw_cc);
103 err_v_cc = dw_cc - eig * rhs_cc;
104 T err = proxsuite::proxqp::dense::infty_norm(err_v_cc);
107 if (err <= power_iteration_accuracy) {
111 T minimal_eigenvalue = max_eigen_value - eig;
112 return minimal_eigenvalue;
123template<
typename T,
typename MatIn>
126 const Eigen::MatrixBase<MatIn>& H,
128 T power_iteration_accuracy,
129 isize nb_power_iteration)
132 (!H.isApprox(H.transpose(), std::numeric_limits<T>::epsilon())),
133 std::invalid_argument,
134 "H is not symmetric.");
139 "H has a number of rows different of the number of columns.");
141 isize dim = H.rows();
143 switch (estimate_method_option) {
149 H, dw, rhs, err, power_iteration_accuracy, nb_power_iteration);
155 dominant_eigen_value,
156 power_iteration_accuracy,
158 res = std::min(min_eigenvalue, dominant_eigen_value);
161 Eigen::SelfAdjointEigenSolver<Mat<T>> es(H, Eigen::EigenvaluesOnly);
162 res = T(es.eigenvalues()[0]);
181 if (manual_minimal_H_eigenvalue !=
nullopt) {
183 manual_minimal_H_eigenvalue.
value();
184 results.
info.minimal_H_eigenvalue_estimate =
187 settings.
default_rho += std::abs(results.
info.minimal_H_eigenvalue_estimate);
204 const isize n_constraints,
210 qpwork.
rhs.setZero();
224 qpresults.
x = qpwork.
dw_aug.head(qpmodel.
dim);
227 qpwork.
rhs.setZero();
252 switch (hessian_type) {
257 qpwork.
kkt.topLeftCorner(qpmodel.
dim, qpmodel.
dim).setZero();
263 qpwork.
kkt.topLeftCorner(qpmodel.
dim, qpmodel.
dim).diagonal().array() +=
265 switch (dense_backend) {
267 qpwork.
kkt.block(0, qpmodel.
dim, qpmodel.
dim, qpmodel.
n_eq) =
269 qpwork.
kkt.block(qpmodel.
dim, 0, qpmodel.
n_eq, qpmodel.
dim) =
271 qpwork.
kkt.bottomRightCorner(qpmodel.
n_eq, qpmodel.
n_eq).setZero();
272 qpwork.
kkt.diagonal()
273 .segment(qpmodel.
dim, qpmodel.
n_eq)
274 .setConstant(-qpresults.
info.mu_eq);
275 qpwork.
ldl.factorize(qpwork.
kkt.transpose(), stack);
278 qpwork.
kkt.noalias() += qpresults.
info.mu_eq_inv *
280 qpwork.
ldl.factorize(qpwork.
kkt.transpose(), stack);
302 const bool box_constraints,
305 bool execute_preconditioner)
321 execute_preconditioner,
351 qpwork, qpsettings, qpmodel, qpresults);
385 const bool box_constraints)
391 "the dimension wrt the primal variable x "
392 "variable for updating g is not valid.");
397 "the dimension wrt equality constrained "
398 "variables for updating b is not valid.");
403 "the dimension wrt inequality constrained "
404 "variables for updating u is not valid.");
409 "the dimension wrt inequality constrained "
410 "variables for updating l is not valid.");
416 "the row dimension for updating H is not valid.");
420 "the column dimension for updating H is not valid.");
426 "the row dimension for updating A is not valid.");
430 "the column dimension for updating A is not valid.");
436 "the row dimension for updating C is not valid.");
440 "the column dimension for updating C is not valid.");
445 model.
g = g.value().eval();
448 model.
b = b.value().eval();
451 model.
u = u.value().eval();
454 model.
l = l.value().eval();
456 if (u_box !=
nullopt && box_constraints) {
457 model.
u_box = u_box.value();
461 if (l_box !=
nullopt && box_constraints) {
462 model.
l_box = l_box.value();
479 assert(model.
is_valid(box_constraints));
516 const bool box_constraints,
529 qpwork.
cleanup(box_constraints);
539 qpwork.
cleanup(box_constraints);
548 qpwork.
cleanup(box_constraints);
559 qpwork.
cleanup(box_constraints);
564 qpwork.
cleanup(box_constraints);
574 qpmodel.
H = H.value();
577 qpmodel.
g = g.value();
581 qpmodel.
A = A.value();
586 qpmodel.
b = b.value();
591 qpmodel.
C = C.value();
596 qpmodel.
u = u.value();
601 qpmodel.
l = l.value();
605 qpmodel.
u_box = u_box.value();
610 qpmodel.
l_box = l_box.value();
613 assert(qpmodel.
is_valid(box_constraints));
614 switch (hessian_type) {
629 (qpmodel.
u.array() <= T(1.E20))
631 Eigen::Matrix<T, Eigen::Dynamic, 1>::Zero(qpmodel.
n_in).array() +
634 (qpmodel.
l.array() >= T(-1.E20))
636 Eigen::Matrix<T, Eigen::Dynamic, 1>::Zero(qpmodel.
n_in).array() -
638 if (box_constraints) {
640 (qpmodel.
u_box.array() <= T(1.E20))
641 .select(qpmodel.
u_box,
642 Eigen::Matrix<T, Eigen::Dynamic, 1>::Zero(qpmodel.
dim).array() +
645 (qpmodel.
l_box.array() >= T(-1.E20))
646 .select(qpmodel.
l_box,
647 Eigen::Matrix<T, Eigen::Dynamic, 1>::Zero(qpmodel.
dim).array() -
652 switch (preconditioner_status) {
655 qpwork, qpsettings, box_constraints, hessian_type, ruiz,
true);
659 qpwork, qpsettings, box_constraints, hessian_type, ruiz,
false);
664 qpwork, qpsettings, box_constraints, hessian_type, ruiz,
false);
696 results.
info.mu_eq_inv = T(1) / results.
info.mu_eq;
702 results.
info.mu_in_inv = T(1) / results.
info.mu_in;
734 "the dimension wrt primal variable x for warm start is not valid.");
740 "the dimension wrt equality constrained "
741 "variables for warm start is not valid.");
748 "the dimension wrt inequality constrained variables for warm start "
753 results.
x = x_wm.value().eval();
757 results.
y = y_wm.value().eval();
761 results.
z = z_wm.value().eval();
TL_OPTIONAL_11_CONSTEXPR T & value() &
#define PROXSUITE_CHECK_ARGUMENT_SIZE(size, expected_size, message)
#define PROXSUITE_THROW_PRETTY(condition, exception, message)
void setup_factorization(Workspace< T > &qpwork, const Model< T > &qpmodel, Results< T > &qpresults, const DenseBackend &dense_backend, const HessianType &hessian_type)
void warm_start(optional< VecRef< T > > x_wm, optional< VecRef< T > > y_wm, optional< VecRef< T > > z_wm, Results< T > &results, Settings< T > &settings, Model< T > &model)
void initial_guess(Workspace< T > &qpwork, Settings< T > &qpsettings, Model< T > &qpmodel, Results< T > &qpresults)
void iterative_solve_with_permut_fact(const Settings< T > &qpsettings, const Model< T > &qpmodel, Results< T > &qpresults, Workspace< T > &qpwork, const isize n_constraints, const DenseBackend &dense_backend, const HessianType &hessian_type, T eps, isize inner_pb_dim)
void setup_equilibration(Workspace< T > &qpwork, const Settings< T > &qpsettings, const bool box_constraints, const HessianType hessian_type, preconditioner::RuizEquilibration< T > &ruiz, bool execute_preconditioner)
Eigen::Ref< Mat< T, l > const > MatRef
T estimate_minimal_eigen_value_of_symmetric_matrix(const Eigen::MatrixBase< MatIn > &H, EigenValueEstimateMethodOption estimate_method_option, T power_iteration_accuracy, isize nb_power_iteration)
void update_proximal_parameters(Settings< T > &settings, Results< T > &results, Workspace< T > &work, optional< T > rho_new, optional< T > mu_eq_new, optional< T > mu_in_new)
void update_default_rho_with_minimal_Hessian_eigen_value(optional< T > manual_minimal_H_eigenvalue, Results< T > &results, Settings< T > &settings)
Eigen::Matrix< T, DYN, 1 > Vec
void setup(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, Settings< T > &qpsettings, Model< T > &qpmodel, Workspace< T > &qpwork, Results< T > &qpresults, const bool box_constraints, preconditioner::RuizEquilibration< T > &ruiz, PreconditionerStatus preconditioner_status, const HessianType hessian_type)
T power_iteration(const Eigen::MatrixBase< MatIn > &H, const Eigen::MatrixBase< VecIn1 > &dw, const Eigen::MatrixBase< VecIn2 > &rhs, const Eigen::MatrixBase< VecIn3 > &err_v, T power_iteration_accuracy, isize nb_power_iteration)
T min_eigen_value_via_modified_power_iteration(const Eigen::MatrixBase< MatIn > &H, const Eigen::MatrixBase< VecIn1 > &dw, const Eigen::MatrixBase< VecIn2 > &rhs, const Eigen::MatrixBase< VecIn3 > &err_v, T max_eigen_value, T power_iteration_accuracy, isize nb_power_iteration)
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, Model< T > &model, Workspace< T > &work, const bool box_constraints)
void compute_equality_constrained_initial_guess(Workspace< T > &qpwork, const Settings< T > &qpsettings, const Model< T > &qpmodel, const isize n_constraints, const DenseBackend &dense_backend, const HessianType &hessian_type, Results< T > &qpresults)
Eigen::Ref< Vec< T > const > VecRef
@ COLD_START_WITH_PREVIOUS_RESULT
@ EQUALITY_CONSTRAINED_INITIAL_GUESS
@ WARM_START_WITH_PREVIOUS_RESULT
EigenValueEstimateMethodOption
constexpr nullopt_t nullopt
VEG_NODISCARD VEG_INLINE auto as_mut() VEG_NOEXCEPT -> SliceMut< T >
This class stores all the results of PROXQP solvers with sparse and dense backends.
void cold_start(optional< Settings< T > > settings=nullopt)
void cleanup(optional< Settings< T > > settings=nullopt)
void cleanup_statistics()
void cleanup_all_except_prox_parameters()
This class defines the settings of PROXQP solvers with sparse and dense backends.
T default_H_eigenvalue_estimate
bool primal_infeasibility_solving
isize preconditioner_max_iter
InitialGuessStatus initial_guess
T preconditioner_accuracy
This class stores the model of the QP problem.
bool is_valid(const bool box_constraints)
This class defines the workspace of the dense solver.
proxsuite::linalg::veg::Vec< unsigned char > ldl_stack
void cleanup(const bool box_constraints)
bool proximal_parameter_update
proxsuite::linalg::dense::Ldlt< T > ldl
void scale_qp_in_place(QpViewBoxMut< T > qp, bool execute_preconditioner, bool preconditioning_for_infeasible_problems, const isize max_iter, const T epsilon, const HessianType &HessianType, const bool box_constraints, proxsuite::linalg::veg::dynstack::DynStackMut stack)