@@ -5988,4 +5988,81 @@ DOCTEST_TEST_CASE(
59885988 DOCTEST_CHECK (pri_res <= eps_abs);
59895989 DOCTEST_CHECK (dua_res <= eps_abs);
59905990 }
5991+ }
5992+
5993+ TEST_CASE (" ProxQP::sparse: init must be called before update" )
5994+ {
5995+ double sparsity_factor = 0.15 ;
5996+ T eps_abs = T (1e-9 );
5997+ utils::rand::set_seed (1 );
5998+ dense::isize dim = 10 ;
5999+
6000+ dense::isize n_eq (dim / 4 );
6001+ dense::isize n_in (dim / 4 );
6002+ T strong_convexity_factor (1 .e -2 );
6003+ ::proxsuite::proxqp::utils::rand::set_seed (1 );
6004+ proxqp::sparse::SparseModel<T> qp_random = utils::sparse_strongly_convex_qp (
6005+ dim, n_eq, n_in, sparsity_factor, strong_convexity_factor);
6006+
6007+ proxqp::sparse::QP<T, I> qp (qp_random.H .cast <bool >(),
6008+ qp_random.A .cast <bool >(),
6009+ qp_random.C .cast <bool >());
6010+ qp.settings .eps_abs = eps_abs;
6011+
6012+ T rho (1 .e -7 );
6013+ T mu_eq (1 .e -4 );
6014+ bool compute_preconditioner = true ;
6015+
6016+ qp.settings .eps_abs = eps_abs;
6017+ qp.settings .eps_rel = 0 ;
6018+ qp.settings .initial_guess = InitialGuessStatus::NO_INITIAL_GUESS;
6019+
6020+ // call update without init, update calls init internally
6021+ qp.update (qp_random.H ,
6022+ qp_random.g ,
6023+ qp_random.A ,
6024+ qp_random.b ,
6025+ qp_random.C ,
6026+ qp_random.l ,
6027+ qp_random.u ,
6028+ true );
6029+
6030+ qp.solve ();
6031+
6032+ T pri_res = std::max (
6033+ (qp_random.A * qp.results .x - qp_random.b ).lpNorm <Eigen::Infinity>(),
6034+ (helpers::positive_part (qp_random.C * qp.results .x - qp_random.u ) +
6035+ helpers::negative_part (qp_random.C * qp.results .x - qp_random.l ))
6036+ .lpNorm <Eigen::Infinity>());
6037+ T dua_res = (qp_random.H .selfadjointView <Eigen::Upper>() * qp.results .x +
6038+ qp_random.g + qp_random.A .transpose () * qp.results .y +
6039+ qp_random.C .transpose () * qp.results .z )
6040+ .lpNorm <Eigen::Infinity>();
6041+ DOCTEST_CHECK (pri_res <= eps_abs);
6042+ DOCTEST_CHECK (dua_res <= eps_abs);
6043+
6044+ qp_random.H = 2 * qp_random.H ; // keep same sparsity structure
6045+ qp_random.g = utils::rand::vector_rand<T>(dim);
6046+ qp.update (qp_random.H ,
6047+ qp_random.g ,
6048+ nullopt ,
6049+ nullopt ,
6050+ nullopt ,
6051+ nullopt ,
6052+ nullopt ,
6053+ true );
6054+
6055+ qp.solve ();
6056+
6057+ pri_res = std::max (
6058+ (qp_random.A * qp.results .x - qp_random.b ).lpNorm <Eigen::Infinity>(),
6059+ (helpers::positive_part (qp_random.C * qp.results .x - qp_random.u ) +
6060+ helpers::negative_part (qp_random.C * qp.results .x - qp_random.l ))
6061+ .lpNorm <Eigen::Infinity>());
6062+ dua_res = (qp_random.H .selfadjointView <Eigen::Upper>() * qp.results .x +
6063+ qp_random.g + qp_random.A .transpose () * qp.results .y +
6064+ qp_random.C .transpose () * qp.results .z )
6065+ .lpNorm <Eigen::Infinity>();
6066+ DOCTEST_CHECK (pri_res <= eps_abs);
6067+ DOCTEST_CHECK (dua_res <= eps_abs);
59916068}
0 commit comments