From bfe46369fbdecc26cbb87371743c285433dec9ea Mon Sep 17 00:00:00 2001 From: darnstrom Date: Mon, 18 May 2026 22:53:10 +0200 Subject: [PATCH 01/14] Improve heuristic for selecting rho for DR-DAQP --- src/utils.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/utils.c b/src/utils.c index f626351..e796f31 100644 --- a/src/utils.c +++ b/src/utils.c @@ -472,19 +472,29 @@ int daqp_update_avi(DAQPAVI* avi, DAQPProblem* p){ // Setup matrices Hsym, Hs_rho, and H_rho, LU_H int i,j,disp; c_float val; + c_float min_diag = DAQP_INF; + c_float max_row_sum = 0.0; + c_float fro_norm_sq = 0.0; avi->rho = 0.0; for (i = 0, disp=0; i < n; i++) { + c_float row_sum = 0.0; for (j = 0; j < n; j++, disp++) { val = (p->H[disp] + p->H[j * n + i]) * 0.5; avi->Hsym[disp] = val; avi->Hs_rho[disp] = val; avi->H_rho[disp] = p->H[disp]; avi->LU_H[disp] = p->H[disp]; - avi->rho += p->H[disp] * p->H[disp]; + row_sum += (val < 0.0) ? -val : val; + fro_norm_sq += p->H[disp] * p->H[disp]; + if(i == j && val < min_diag) min_diag = val; } + if(row_sum > max_row_sum) max_row_sum = row_sum; } // Regularization - avi->rho = sqrt(avi->rho)/2; + if(min_diag > 0.0 && max_row_sum > 0.0) + avi->rho = sqrt(min_diag * max_row_sum); + else + avi->rho = sqrt(fro_norm_sq)/2; for(i=0,disp=0; iHs_rho[disp] += avi->rho; avi->H_rho[disp] += avi->rho; From a0ce56faeb360569201f8419784c52f8a1ca874a Mon Sep 17 00:00:00 2001 From: darnstrom Date: Tue, 19 May 2026 00:04:30 +0200 Subject: [PATCH 02/14] Add option for custom rho in avi --- docs/docs/settings.md | 1 + include/constants.h | 1 + include/types.h | 1 + include/utils.h | 2 +- interfaces/daqp-eigen/CMakeLists.txt | 2 + interfaces/daqp-eigen/daqp.cpp | 5 ++ interfaces/daqp-eigen/daqp.hpp | 1 + interfaces/daqp-eigen/tests/09_avi_rho.cpp | 68 +++++++++++++++++++++ interfaces/daqp-julia/src/types.jl | 1 + interfaces/daqp-julia/test/core_tests.jl | 5 +- interfaces/daqp-matlab/daqpmex.c | 7 +++ interfaces/daqp-matlab/test/core_test.m | 9 +++ interfaces/daqp-python/daqp.pxd | 2 + interfaces/daqp-python/daqp.pyx | 12 +++- interfaces/daqp-python/test/example_test.py | 5 +- src/api.c | 1 + src/avi.c | 43 +++++++++++++ src/utils.c | 42 +------------ 18 files changed, 160 insertions(+), 48 deletions(-) create mode 100644 interfaces/daqp-eigen/tests/09_avi_rho.cpp diff --git a/docs/docs/settings.md b/docs/docs/settings.md index d5bc7cd..adeb3ca 100644 --- a/docs/docs/settings.md +++ b/docs/docs/settings.md @@ -29,6 +29,7 @@ Table of contents | `eps_prox` | Regularization parameter used for proximal-point iterations | 1e-6| | `eta_prox` | Tolerance that determines if a fix-point has been reached during proximal-point iterations | 1e-6| | `rho_soft` | Weight used for soft constraints (higher enables more violations) | 1e-6| +| `rho_avi` | Regularization parameter for AVIs. `-1` means automatic selection | -1 | | `rel_subopt` | Allowed relative suboptimality in branch and bound | 0 | | `abs_subopt` | Allowed absolute suboptimality in branch and bound | 0 | | `sing_tol` | Tolerance for checking if the LDL' factorization is singular| 3.7e-11 | diff --git a/include/constants.h b/include/constants.h index 8b02018..fed80cd 100644 --- a/include/constants.h +++ b/include/constants.h @@ -22,6 +22,7 @@ extern "C" { #define DAQP_DEFAULT_ETA 1e-6 #define DAQP_DEFAULT_ITER_LIMIT 10000 #define DAQP_DEFAULT_RHO_SOFT 1e-6 +#define DAQP_DEFAULT_RHO_AVI (-1.0) #define DAQP_DEFAULT_REL_SUBOPT 0 #define DAQP_DEFAULT_ABS_SUBOPT 0 #define DAQP_DEFAULT_SING_TOL (3.7e-11) diff --git a/include/types.h b/include/types.h index 4855522..0efbcfb 100644 --- a/include/types.h +++ b/include/types.h @@ -64,6 +64,7 @@ typedef struct{ c_float eta_prox; c_float rho_soft; + c_float rho_avi; c_float rel_subopt; c_float abs_subopt; diff --git a/include/utils.h b/include/utils.h index b5fec10..e9b466b 100644 --- a/include/utils.h +++ b/include/utils.h @@ -17,7 +17,7 @@ void daqp_normalize_Rinv(DAQPWorkspace *work); int daqp_normalize_M(DAQPWorkspace *work); int daqp_check_unconstrained(DAQPWorkspace* work, const int mask); -int daqp_update_avi(DAQPAVI *avi, DAQPProblem *problem); +int daqp_update_avi(DAQPAVI *avi, DAQPProblem *problem, DAQPSettings *settings); int daqp_lu(c_float* A, int* P, int n); void daqp_lu_solve(c_float* LU, int* P, c_float* b, c_float* x, int n); diff --git a/interfaces/daqp-eigen/CMakeLists.txt b/interfaces/daqp-eigen/CMakeLists.txt index 76344cb..fd87af4 100644 --- a/interfaces/daqp-eigen/CMakeLists.txt +++ b/interfaces/daqp-eigen/CMakeLists.txt @@ -20,6 +20,7 @@ add_executable(05_warmstart tests/05_warmstart.cpp) add_executable(06_general_hessian tests/06_general_hessian.cpp) add_executable(07_symmetrize_hessian tests/07_symmetrize_hessian.cpp) add_executable(08_unconstrained_check tests/08_unconstrained_check.cpp) +add_executable(09_avi_rho tests/09_avi_rho.cpp) set(TARGETS 00_basic_qp @@ -31,6 +32,7 @@ set(TARGETS 06_general_hessian 07_symmetrize_hessian 08_unconstrained_check + 09_avi_rho ) foreach(TARGET ${TARGETS}) diff --git a/interfaces/daqp-eigen/daqp.cpp b/interfaces/daqp-eigen/daqp.cpp index bd13a51..9dffb4c 100644 --- a/interfaces/daqp-eigen/daqp.cpp +++ b/interfaces/daqp-eigen/daqp.cpp @@ -380,6 +380,11 @@ void DAQP::set_rho_soft(double val) { is_solved_ = false; } +void DAQP::set_rho_avi(double val) { + settings_.rho_avi = val; + is_solved_ = false; +} + void DAQP::set_rel_subopt(double val) { settings_.rel_subopt = val; is_solved_ = false; diff --git a/interfaces/daqp-eigen/daqp.hpp b/interfaces/daqp-eigen/daqp.hpp index 9579edd..494e5bc 100644 --- a/interfaces/daqp-eigen/daqp.hpp +++ b/interfaces/daqp-eigen/daqp.hpp @@ -101,6 +101,7 @@ class DAQP { void set_eps_prox(double val); void set_eta_prox(double val); void set_rho_soft(double val); + void set_rho_avi(double val); void set_rel_subopt(double val); void set_abs_subopt(double val); void set_sing_tol(double val); diff --git a/interfaces/daqp-eigen/tests/09_avi_rho.cpp b/interfaces/daqp-eigen/tests/09_avi_rho.cpp new file mode 100644 index 0000000..1696049 --- /dev/null +++ b/interfaces/daqp-eigen/tests/09_avi_rho.cpp @@ -0,0 +1,68 @@ +#include +#include "api.h" + +static double automatic_rho(const double* H, int n) { + double min_diag = DAQP_INF; + double max_row_sum = 0.0; + double fro_norm_sq = 0.0; + + for (int i = 0; i < n; ++i) { + double row_sum = 0.0; + for (int j = 0; j < n; ++j) { + const double hij = H[i * n + j]; + const double sym = 0.5 * (hij + H[j * n + i]); + row_sum += std::abs(sym); + fro_norm_sq += hij * hij; + if (i == j && sym < min_diag) + min_diag = sym; + } + if (row_sum > max_row_sum) + max_row_sum = row_sum; + } + + if (min_diag > 0.0 && max_row_sum > 0.0) + return std::sqrt(min_diag * max_row_sum); + return std::sqrt(fro_norm_sq) / 2.0; +} + +int main() { + constexpr int n = 2; + constexpr int m = 2; + constexpr int ms = 0; + + double H[4] = {1.0, 1.75, 0.0, 1.0}; + double f[2] = {2.0, 2.0}; + double A[4] = {1.0, 0.0, 0.0, 1.0}; + double bupper[2] = {1.0, 1.0}; + double blower[2] = {-1.0, -1.0}; + int sense[2] = {0, 0}; + DAQPProblem qp = {n, m, ms, H, f, A, bupper, blower, sense, nullptr, 0, 1}; + + DAQPWorkspace work = {0}; + int exitflag = setup_daqp(&qp, &work, nullptr); + if (exitflag < 0) + return 1; + + const double expected_auto = automatic_rho(H, n); + const double auto_tol = 1e-12 * (expected_auto > 1.0 ? expected_auto : 1.0); + const bool auto_ok = std::abs(work.avi->rho - expected_auto) <= auto_tol; + free_daqp_workspace(&work); + free_daqp_ldp(&work); + + DAQPSettings settings; + daqp_default_settings(&settings); + settings.rho_avi = 0.25; + + DAQPWorkspace work_override = {0}; + work_override.settings = &settings; + exitflag = setup_daqp(&qp, &work_override, nullptr); + if (exitflag < 0) + return 1; + + const bool override_ok = std::abs(work_override.avi->rho - settings.rho_avi) <= 1e-15; + work_override.settings = nullptr; + free_daqp_workspace(&work_override); + free_daqp_ldp(&work_override); + + return (auto_ok && override_ok) ? 0 : 1; +} diff --git a/interfaces/daqp-julia/src/types.jl b/interfaces/daqp-julia/src/types.jl index de679c5..04abe6b 100644 --- a/interfaces/daqp-julia/src/types.jl +++ b/interfaces/daqp-julia/src/types.jl @@ -93,6 +93,7 @@ struct DAQPSettings eta_prox::Cdouble rho_soft::Cdouble + rho_avi::Cdouble rel_subopt::Cdouble abs_subopt::Cdouble diff --git a/interfaces/daqp-julia/test/core_tests.jl b/interfaces/daqp-julia/test/core_tests.jl index 9a56d3d..3824bc3 100644 --- a/interfaces/daqp-julia/test/core_tests.jl +++ b/interfaces/daqp-julia/test/core_tests.jl @@ -136,9 +136,11 @@ end # Test access settings s = settings(d) @test s.primal_tol==1e-6 - settings(d,Dict(:primal_tol=>1e-5)) + @test s.rho_avi==-1 + settings(d,Dict(:primal_tol=>1e-5, :rho_avi=>0.25)) s = settings(d) @test s.primal_tol==1e-5 + @test s.rho_avi==0.25 # Update existing model with new problem xref,H,f,A,bupper,blower,sense = generate_test_QP(n,m,ms,nAct,kappa) @@ -509,4 +511,3 @@ end end @test tquad < 10*tsetup #Should be orders of magnitude faster end - diff --git a/interfaces/daqp-matlab/daqpmex.c b/interfaces/daqp-matlab/daqpmex.c index ea362bd..51ad8bc 100644 --- a/interfaces/daqp-matlab/daqpmex.c +++ b/interfaces/daqp-matlab/daqpmex.c @@ -24,6 +24,7 @@ const char* SETTINGS_FIELDS[] = { "eps_prox", "eta_prox", "rho_soft", + "rho_avi", "abs_subopt", "rel_subopt", "sing_tol", @@ -181,8 +182,11 @@ void mexFunction( int nlhs, mxArray *plhs[], mxSetField(s, 0, "eps_prox", mxCreateDoubleScalar(work->settings->eps_prox)); mxSetField(s, 0, "eta_prox", mxCreateDoubleScalar(work->settings->eta_prox)); mxSetField(s, 0, "rho_soft", mxCreateDoubleScalar(work->settings->rho_soft)); + mxSetField(s, 0, "rho_avi", mxCreateDoubleScalar(work->settings->rho_avi)); mxSetField(s, 0, "abs_subopt", mxCreateDoubleScalar(work->settings->abs_subopt)); mxSetField(s, 0, "rel_subopt", mxCreateDoubleScalar(work->settings->rel_subopt)); + mxSetField(s, 0, "sing_tol", mxCreateDoubleScalar(work->settings->sing_tol)); + mxSetField(s, 0, "refactor_tol", mxCreateDoubleScalar(work->settings->refactor_tol)); mxSetField(s, 0, "time_limit", mxCreateDoubleScalar(work->settings->time_limit)); plhs[0] = s; } @@ -200,8 +204,11 @@ void mexFunction( int nlhs, mxArray *plhs[], work->settings->eps_prox = (c_float)mxGetScalar(mxGetField(s, 0, "eps_prox")); work->settings->eta_prox= (c_float)mxGetScalar(mxGetField(s, 0, "eta_prox")); work->settings->rho_soft= (c_float)mxGetScalar(mxGetField(s, 0, "rho_soft")); + work->settings->rho_avi= (c_float)mxGetScalar(mxGetField(s, 0, "rho_avi")); work->settings->abs_subopt= (c_float)mxGetScalar(mxGetField(s, 0, "abs_subopt")); work->settings->rel_subopt= (c_float)mxGetScalar(mxGetField(s, 0, "rel_subopt")); + work->settings->sing_tol= (c_float)mxGetScalar(mxGetField(s, 0, "sing_tol")); + work->settings->refactor_tol= (c_float)mxGetScalar(mxGetField(s, 0, "refactor_tol")); work->settings->time_limit= (c_float)mxGetScalar(mxGetField(s, 0, "time_limit")); } else if (!strcmp("update", cmd)) { diff --git a/interfaces/daqp-matlab/test/core_test.m b/interfaces/daqp-matlab/test/core_test.m index ed8fe1a..c340869 100644 --- a/interfaces/daqp-matlab/test/core_test.m +++ b/interfaces/daqp-matlab/test/core_test.m @@ -63,6 +63,15 @@ function prox_random_feasible_QPs(testCase) fprintf('=============================================================\n') end + function settings_roundtrip(testCase) + d = daqp(); + s = d.settings(); + testCase.verifyEqual(s.rho_avi,-1); + d.settings('rho_avi',0.25); + s = d.settings(); + testCase.verifyEqual(s.rho_avi,0.25); + end + function random_feasible_LPs(testCase) % Test on randomly generated feasible LPs rng('default'); diff --git a/interfaces/daqp-python/daqp.pxd b/interfaces/daqp-python/daqp.pxd index 817b4e0..d109f3f 100644 --- a/interfaces/daqp-python/daqp.pxd +++ b/interfaces/daqp-python/daqp.pxd @@ -32,6 +32,7 @@ cdef extern from "types.h": double eta_prox; double rho_soft; + double rho_avi; double rel_subopt; double abs_subopt; @@ -98,6 +99,7 @@ cdef extern from "constants.h": cdef double DAQP_DEFAULT_ETA cdef int DAQP_DEFAULT_ITER_LIMIT cdef double DAQP_DEFAULT_RHO_SOFT + cdef double DAQP_DEFAULT_RHO_AVI cdef double DAQP_DEFAULT_REL_SUBOPT cdef double DAQP_DEFAULT_ABS_SUBOPT cdef double DAQP_DEFAULT_SING_TOL diff --git a/interfaces/daqp-python/daqp.pyx b/interfaces/daqp-python/daqp.pyx index d6a94f6..baa997e 100644 --- a/interfaces/daqp-python/daqp.pyx +++ b/interfaces/daqp-python/daqp.pyx @@ -73,6 +73,7 @@ def solve(double[:, :] H, double[:] f, double[:, :] A, iter_limit = DAQP_DEFAULT_ITER_LIMIT, fval_bound = DAQP_INF, eps_prox= DAQP_DEFAULT_EPS_PROX, eta_prox = DAQP_DEFAULT_ETA, rho_soft = DAQP_DEFAULT_RHO_SOFT, + rho_avi = DAQP_DEFAULT_RHO_AVI, rel_subopt = DAQP_DEFAULT_REL_SUBOPT, abs_subopt = DAQP_DEFAULT_ABS_SUBOPT, sing_tol = DAQP_DEFAULT_SING_TOL, refactor_tol = DAQP_DEFAULT_REFACTOR_TOL, time_limit = 0, @@ -123,6 +124,9 @@ def solve(double[:, :] H, double[:] f, double[:, :] A, Break points that define prioritized constraints is_avi: flag for interpreting the problem as an AVI (relevant for asymmetric H) + rho_avi: + Overrides the automatic AVI regularization parameter when positive. + The default ``-1`` keeps the automatic choice based on the Hessian. primal_start: Initial guess of primal iterate (used for warm starting). Sets the initial active set based on which constraints are nearly active at this iterate, and @@ -201,7 +205,7 @@ def solve(double[:, :] H, double[:] f, double[:, :] A, cdef DAQPProblem problem = [n, m, m-mA, H_ptr, f_ptr, A_ptr, bu_ptr, bl_ptr, sense_ptr, bp_ptr, nh, problem_type] cdef DAQPSettings settings = [primal_tol, dual_tol, zero_tol, pivot_tol, progress_tol, cycle_tol, iter_limit, fval_bound, - eps_prox, eta_prox, rho_soft, rel_subopt, abs_subopt, sing_tol, refactor_tol, + eps_prox, eta_prox, rho_soft, rho_avi, rel_subopt, abs_subopt, sing_tol, refactor_tol, time_limit] cdef DAQPResult res = [&x[0], lam_ptr, 0, 0, 0, 0, 0, 0, 0] @@ -582,8 +586,8 @@ cdef class Model: Available keys: ``primal_tol``, ``dual_tol``, ``zero_tol``, ``pivot_tol``, ``progress_tol``, ``cycle_tol``, ``iter_limit``, ``fval_bound``, ``eps_prox``, ``eta_prox``, ``rho_soft``, - ``rel_subopt``, ``abs_subopt``, ``sing_tol``, ``refactor_tol``, - ``time_limit``. + ``rho_avi``, ``rel_subopt``, ``abs_subopt``, ``sing_tol``, + ``refactor_tol``, ``time_limit``. """ if self._work.settings == NULL: return {} @@ -600,6 +604,7 @@ cdef class Model: 'eps_prox': s.eps_prox, 'eta_prox': s.eta_prox, 'rho_soft': s.rho_soft, + 'rho_avi': s.rho_avi, 'rel_subopt': s.rel_subopt, 'abs_subopt': s.abs_subopt, 'sing_tol': s.sing_tol, @@ -624,6 +629,7 @@ cdef class Model: if 'eps_prox' in new_settings: s.eps_prox = new_settings['eps_prox'] if 'eta_prox' in new_settings: s.eta_prox = new_settings['eta_prox'] if 'rho_soft' in new_settings: s.rho_soft = new_settings['rho_soft'] + if 'rho_avi' in new_settings: s.rho_avi = new_settings['rho_avi'] if 'rel_subopt' in new_settings: s.rel_subopt = new_settings['rel_subopt'] if 'abs_subopt' in new_settings: s.abs_subopt = new_settings['abs_subopt'] if 'sing_tol' in new_settings: s.sing_tol = new_settings['sing_tol'] diff --git a/interfaces/daqp-python/test/example_test.py b/interfaces/daqp-python/test/example_test.py index e786ff5..b58bced 100644 --- a/interfaces/daqp-python/test/example_test.py +++ b/interfaces/daqp-python/test/example_test.py @@ -190,15 +190,18 @@ def test_model_settings_get(self): self.assertIn('primal_tol', s) self.assertIn('eps_prox', s) self.assertIn('time_limit', s) + self.assertIn('rho_avi', s) self.assertEqual(s['time_limit'], 0.0) + self.assertEqual(s['rho_avi'], -1.0) def test_model_settings_set(self): """settings setter updates only the specified keys.""" d = daqp.Model() original_primal_tol = d.settings['primal_tol'] - d.settings = {'iter_limit': 42, 'time_limit': 5.0} + d.settings = {'iter_limit': 42, 'time_limit': 5.0, 'rho_avi': 0.25} self.assertEqual(d.settings['iter_limit'], 42) self.assertAlmostEqual(d.settings['time_limit'], 5.0) + self.assertAlmostEqual(d.settings['rho_avi'], 0.25) # Other settings should be unchanged self.assertAlmostEqual(d.settings['primal_tol'], original_primal_tol) diff --git a/src/api.c b/src/api.c index 8ef4754..3f8284d 100644 --- a/src/api.c +++ b/src/api.c @@ -477,6 +477,7 @@ void daqp_default_settings(DAQPSettings* settings){ settings->eta_prox = DAQP_DEFAULT_ETA; settings->rho_soft = DAQP_DEFAULT_RHO_SOFT; + settings->rho_avi = DAQP_DEFAULT_RHO_AVI; settings->rel_subopt = DAQP_DEFAULT_REL_SUBOPT; settings->abs_subopt = DAQP_DEFAULT_ABS_SUBOPT; diff --git a/src/avi.c b/src/avi.c index 1c70f8d..ffd5e3c 100644 --- a/src/avi.c +++ b/src/avi.c @@ -1,6 +1,7 @@ #include "avi.h" #include "daqp.h" #include "utils.h" +#include // Solve AVI int daqp_solve_avi(DAQPWorkspace *work) { @@ -218,3 +219,45 @@ int daqp_check_optimal_avi(DAQPWorkspace* work){ // All checks passed -> optimal KKT point found return 1; } + +int daqp_update_avi(DAQPAVI* avi, DAQPProblem* p, DAQPSettings* settings) { + const int n = p->n; + int i, j, disp; + c_float val; + c_float min_diag = DAQP_INF; + c_float max_row_sum = 0.0; + c_float fro_norm_sq = 0.0; + + avi->rho = 0.0; + for (i = 0, disp = 0; i < n; i++) { + c_float row_sum = 0.0; + for (j = 0; j < n; j++, disp++) { + val = (p->H[disp] + p->H[j * n + i]) * 0.5; + avi->Hsym[disp] = val; + avi->Hs_rho[disp] = val; + avi->H_rho[disp] = p->H[disp]; + avi->LU_H[disp] = p->H[disp]; + row_sum += (val < 0.0) ? -val : val; + fro_norm_sq += p->H[disp] * p->H[disp]; + if(i == j && val < min_diag) min_diag = val; + } + if(row_sum > max_row_sum) max_row_sum = row_sum; + } + + if(settings != NULL && settings->rho_avi > 0.0) + avi->rho = settings->rho_avi; + else if(min_diag > 0.0 && max_row_sum > 0.0) + avi->rho = sqrt(min_diag * max_row_sum); + else + avi->rho = sqrt(fro_norm_sq) / 2; + + for(i = 0, disp = 0; i < n; i++) { + avi->Hs_rho[disp] += avi->rho; + avi->H_rho[disp] += avi->rho; + disp += n + 1; + } + + daqp_lu(avi->LU_H, avi->P_H, n); + daqp_lu(avi->H_rho, avi->P_H2, n); + return 1; +} diff --git a/src/utils.c b/src/utils.c index e796f31..19719f9 100644 --- a/src/utils.c +++ b/src/utils.c @@ -41,7 +41,7 @@ int daqp_update_ldp(const int mask, DAQPWorkspace *work, DAQPProblem* qp){ if(work->avi == NULL) error_flag = daqp_update_Rinv(work, qp->H, qp->problem_type==2 ? 1 : 0); else{ - daqp_update_avi(work->avi,qp); + daqp_update_avi(work->avi, qp, work->settings); error_flag = daqp_update_Rinv(work, work->avi->Hs_rho,0); } if(error_flag<0) @@ -467,46 +467,6 @@ int daqp_check_unconstrained(DAQPWorkspace* work, const int mask){ return 1; } -int daqp_update_avi(DAQPAVI* avi, DAQPProblem* p){ - const int n = p->n; - // Setup matrices Hsym, Hs_rho, and H_rho, LU_H - int i,j,disp; - c_float val; - c_float min_diag = DAQP_INF; - c_float max_row_sum = 0.0; - c_float fro_norm_sq = 0.0; - avi->rho = 0.0; - for (i = 0, disp=0; i < n; i++) { - c_float row_sum = 0.0; - for (j = 0; j < n; j++, disp++) { - val = (p->H[disp] + p->H[j * n + i]) * 0.5; - avi->Hsym[disp] = val; - avi->Hs_rho[disp] = val; - avi->H_rho[disp] = p->H[disp]; - avi->LU_H[disp] = p->H[disp]; - row_sum += (val < 0.0) ? -val : val; - fro_norm_sq += p->H[disp] * p->H[disp]; - if(i == j && val < min_diag) min_diag = val; - } - if(row_sum > max_row_sum) max_row_sum = row_sum; - } - // Regularization - if(min_diag > 0.0 && max_row_sum > 0.0) - avi->rho = sqrt(min_diag * max_row_sum); - else - avi->rho = sqrt(fro_norm_sq)/2; - for(i=0,disp=0; iHs_rho[disp] += avi->rho; - avi->H_rho[disp] += avi->rho; - disp += n+1; - } - - // Factorize H and H_rho - daqp_lu(avi->LU_H, avi->P_H, n); - daqp_lu(avi->H_rho, avi->P_H2, n); - return 1; -} - int daqp_lu(c_float* A, int* P, int n) { c_float max_val,pA; for (int i = 0; i < n; i++) P[i] = i; // Initialize permutation vector From 33b3ec2a415043f8211a0d6656095f7d353ef0a9 Mon Sep 17 00:00:00 2001 From: darnstrom Date: Tue, 19 May 2026 00:05:24 +0200 Subject: [PATCH 03/14] Bump version --- CMakeLists.txt | 2 +- interfaces/daqp-python/setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d7c38d..cf5bddd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(daqp VERSION 0.8.4) +project(daqp VERSION 0.8.5) include(GNUInstallDirs) diff --git a/interfaces/daqp-python/setup.py b/interfaces/daqp-python/setup.py index f1ef628..bbb2ada 100644 --- a/interfaces/daqp-python/setup.py +++ b/interfaces/daqp-python/setup.py @@ -45,7 +45,7 @@ include_dirs=[str(csrc_dir / 'include')]) setup(name='daqp', - version='0.8.5', + version='0.8.6', description='DAQP: A dual active-set QP solver', url='http://github.com/darnstrom/daqp', author='Daniel Arnström', From 9c199ef9ac57aad68387c68a1e1cb57e0c105243 Mon Sep 17 00:00:00 2001 From: darnstrom Date: Tue, 19 May 2026 00:36:46 +0200 Subject: [PATCH 04/14] Make new rho_avi last field in setting struct --- docs/docs/settings.md | 2 +- include/types.h | 2 +- interfaces/daqp-eigen/daqp.hpp | 2 +- interfaces/daqp-julia/src/types.jl | 2 +- interfaces/daqp-matlab/daqpmex.c | 4 ++-- interfaces/daqp-python/daqp.pxd | 2 +- interfaces/daqp-python/daqp.pyx | 12 ++++++------ src/api.c | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/docs/settings.md b/docs/docs/settings.md index adeb3ca..421b6ce 100644 --- a/docs/docs/settings.md +++ b/docs/docs/settings.md @@ -29,12 +29,12 @@ Table of contents | `eps_prox` | Regularization parameter used for proximal-point iterations | 1e-6| | `eta_prox` | Tolerance that determines if a fix-point has been reached during proximal-point iterations | 1e-6| | `rho_soft` | Weight used for soft constraints (higher enables more violations) | 1e-6| -| `rho_avi` | Regularization parameter for AVIs. `-1` means automatic selection | -1 | | `rel_subopt` | Allowed relative suboptimality in branch and bound | 0 | | `abs_subopt` | Allowed absolute suboptimality in branch and bound | 0 | | `sing_tol` | Tolerance for checking if the LDL' factorization is singular| 3.7e-11 | | `refactor_tol` | Tolerance for refactoring the LDL' factorization before terminating | 1e-9 | | `time_limit` | Maximum wall-clock time in seconds before terminating (0 means no limit) | 0 | +| `rho_avi` | Regularization parameter for AVIs. `-1` means automatic selection | -1 | ## Exit flags diff --git a/include/types.h b/include/types.h index 0efbcfb..437d1bb 100644 --- a/include/types.h +++ b/include/types.h @@ -64,7 +64,6 @@ typedef struct{ c_float eta_prox; c_float rho_soft; - c_float rho_avi; c_float rel_subopt; c_float abs_subopt; @@ -72,6 +71,7 @@ typedef struct{ c_float sing_tol; c_float refactor_tol; c_float time_limit; + c_float rho_avi; }DAQPSettings; diff --git a/interfaces/daqp-eigen/daqp.hpp b/interfaces/daqp-eigen/daqp.hpp index 494e5bc..c291aaf 100644 --- a/interfaces/daqp-eigen/daqp.hpp +++ b/interfaces/daqp-eigen/daqp.hpp @@ -101,12 +101,12 @@ class DAQP { void set_eps_prox(double val); void set_eta_prox(double val); void set_rho_soft(double val); - void set_rho_avi(double val); void set_rel_subopt(double val); void set_abs_subopt(double val); void set_sing_tol(double val); void set_refactor_tol(double val); void set_time_limit(double val); + void set_rho_avi(double val); // Getters for result Eigen::VectorXd get_primal(); diff --git a/interfaces/daqp-julia/src/types.jl b/interfaces/daqp-julia/src/types.jl index 04abe6b..16f988a 100644 --- a/interfaces/daqp-julia/src/types.jl +++ b/interfaces/daqp-julia/src/types.jl @@ -93,7 +93,6 @@ struct DAQPSettings eta_prox::Cdouble rho_soft::Cdouble - rho_avi::Cdouble rel_subopt::Cdouble abs_subopt::Cdouble @@ -101,6 +100,7 @@ struct DAQPSettings sing_tol::Cdouble refactor_tol::Cdouble time_limit::Cdouble + rho_avi::Cdouble end function DAQPSettings() settings = Ref{DAQPBase.DAQPSettings}() diff --git a/interfaces/daqp-matlab/daqpmex.c b/interfaces/daqp-matlab/daqpmex.c index 51ad8bc..e44c8f5 100644 --- a/interfaces/daqp-matlab/daqpmex.c +++ b/interfaces/daqp-matlab/daqpmex.c @@ -24,12 +24,12 @@ const char* SETTINGS_FIELDS[] = { "eps_prox", "eta_prox", "rho_soft", - "rho_avi", "abs_subopt", "rel_subopt", "sing_tol", "refactor_tol", - "time_limit" + "time_limit", + "rho_avi" }; diff --git a/interfaces/daqp-python/daqp.pxd b/interfaces/daqp-python/daqp.pxd index d109f3f..8153fa3 100644 --- a/interfaces/daqp-python/daqp.pxd +++ b/interfaces/daqp-python/daqp.pxd @@ -32,7 +32,6 @@ cdef extern from "types.h": double eta_prox; double rho_soft; - double rho_avi; double rel_subopt; double abs_subopt; @@ -40,6 +39,7 @@ cdef extern from "types.h": double sing_tol; double refactor_tol; double time_limit; + double rho_avi; ctypedef struct DAQPWorkspace: int n diff --git a/interfaces/daqp-python/daqp.pyx b/interfaces/daqp-python/daqp.pyx index baa997e..d592891 100644 --- a/interfaces/daqp-python/daqp.pyx +++ b/interfaces/daqp-python/daqp.pyx @@ -205,8 +205,8 @@ def solve(double[:, :] H, double[:] f, double[:, :] A, cdef DAQPProblem problem = [n, m, m-mA, H_ptr, f_ptr, A_ptr, bu_ptr, bl_ptr, sense_ptr, bp_ptr, nh, problem_type] cdef DAQPSettings settings = [primal_tol, dual_tol, zero_tol, pivot_tol, progress_tol, cycle_tol, iter_limit, fval_bound, - eps_prox, eta_prox, rho_soft, rho_avi, rel_subopt, abs_subopt, sing_tol, refactor_tol, - time_limit] + eps_prox, eta_prox, rho_soft, rel_subopt, abs_subopt, sing_tol, refactor_tol, + time_limit, rho_avi] cdef DAQPResult res = [&x[0], lam_ptr, 0, 0, 0, 0, 0, 0, 0] if primal_start is None and dual_start is None: @@ -586,8 +586,8 @@ cdef class Model: Available keys: ``primal_tol``, ``dual_tol``, ``zero_tol``, ``pivot_tol``, ``progress_tol``, ``cycle_tol``, ``iter_limit``, ``fval_bound``, ``eps_prox``, ``eta_prox``, ``rho_soft``, - ``rho_avi``, ``rel_subopt``, ``abs_subopt``, ``sing_tol``, - ``refactor_tol``, ``time_limit``. + ``rel_subopt``, ``abs_subopt``, ``sing_tol``, ``refactor_tol``, + ``time_limit``, ``rho_avi``. """ if self._work.settings == NULL: return {} @@ -604,12 +604,12 @@ cdef class Model: 'eps_prox': s.eps_prox, 'eta_prox': s.eta_prox, 'rho_soft': s.rho_soft, - 'rho_avi': s.rho_avi, 'rel_subopt': s.rel_subopt, 'abs_subopt': s.abs_subopt, 'sing_tol': s.sing_tol, 'refactor_tol': s.refactor_tol, 'time_limit': s.time_limit, + 'rho_avi': s.rho_avi, } @settings.setter @@ -629,12 +629,12 @@ cdef class Model: if 'eps_prox' in new_settings: s.eps_prox = new_settings['eps_prox'] if 'eta_prox' in new_settings: s.eta_prox = new_settings['eta_prox'] if 'rho_soft' in new_settings: s.rho_soft = new_settings['rho_soft'] - if 'rho_avi' in new_settings: s.rho_avi = new_settings['rho_avi'] if 'rel_subopt' in new_settings: s.rel_subopt = new_settings['rel_subopt'] if 'abs_subopt' in new_settings: s.abs_subopt = new_settings['abs_subopt'] if 'sing_tol' in new_settings: s.sing_tol = new_settings['sing_tol'] if 'refactor_tol' in new_settings: s.refactor_tol = new_settings['refactor_tol'] if 'time_limit' in new_settings: s.time_limit = new_settings['time_limit'] + if 'rho_avi' in new_settings: s.rho_avi = new_settings['rho_avi'] @cython.boundscheck(False) diff --git a/src/api.c b/src/api.c index 3f8284d..502b11f 100644 --- a/src/api.c +++ b/src/api.c @@ -477,7 +477,6 @@ void daqp_default_settings(DAQPSettings* settings){ settings->eta_prox = DAQP_DEFAULT_ETA; settings->rho_soft = DAQP_DEFAULT_RHO_SOFT; - settings->rho_avi = DAQP_DEFAULT_RHO_AVI; settings->rel_subopt = DAQP_DEFAULT_REL_SUBOPT; settings->abs_subopt = DAQP_DEFAULT_ABS_SUBOPT; @@ -485,6 +484,7 @@ void daqp_default_settings(DAQPSettings* settings){ settings->sing_tol = DAQP_DEFAULT_SING_TOL; settings->refactor_tol = DAQP_DEFAULT_REFACTOR_TOL; settings->time_limit = 0; + settings->rho_avi = DAQP_DEFAULT_RHO_AVI; } /* Remove redundant constraints*/ From d061c01d069b360cdb522a9771e077c8b046e80c Mon Sep 17 00:00:00 2001 From: darnstrom Date: Tue, 19 May 2026 01:01:55 +0200 Subject: [PATCH 05/14] Revert "Make new rho_avi last field in setting struct" This reverts commit 9c199ef9ac57aad68387c68a1e1cb57e0c105243. --- docs/docs/settings.md | 2 +- include/types.h | 2 +- interfaces/daqp-eigen/daqp.hpp | 2 +- interfaces/daqp-julia/src/types.jl | 2 +- interfaces/daqp-matlab/daqpmex.c | 4 ++-- interfaces/daqp-python/daqp.pxd | 2 +- interfaces/daqp-python/daqp.pyx | 12 ++++++------ src/api.c | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/docs/settings.md b/docs/docs/settings.md index 421b6ce..adeb3ca 100644 --- a/docs/docs/settings.md +++ b/docs/docs/settings.md @@ -29,12 +29,12 @@ Table of contents | `eps_prox` | Regularization parameter used for proximal-point iterations | 1e-6| | `eta_prox` | Tolerance that determines if a fix-point has been reached during proximal-point iterations | 1e-6| | `rho_soft` | Weight used for soft constraints (higher enables more violations) | 1e-6| +| `rho_avi` | Regularization parameter for AVIs. `-1` means automatic selection | -1 | | `rel_subopt` | Allowed relative suboptimality in branch and bound | 0 | | `abs_subopt` | Allowed absolute suboptimality in branch and bound | 0 | | `sing_tol` | Tolerance for checking if the LDL' factorization is singular| 3.7e-11 | | `refactor_tol` | Tolerance for refactoring the LDL' factorization before terminating | 1e-9 | | `time_limit` | Maximum wall-clock time in seconds before terminating (0 means no limit) | 0 | -| `rho_avi` | Regularization parameter for AVIs. `-1` means automatic selection | -1 | ## Exit flags diff --git a/include/types.h b/include/types.h index 437d1bb..0efbcfb 100644 --- a/include/types.h +++ b/include/types.h @@ -64,6 +64,7 @@ typedef struct{ c_float eta_prox; c_float rho_soft; + c_float rho_avi; c_float rel_subopt; c_float abs_subopt; @@ -71,7 +72,6 @@ typedef struct{ c_float sing_tol; c_float refactor_tol; c_float time_limit; - c_float rho_avi; }DAQPSettings; diff --git a/interfaces/daqp-eigen/daqp.hpp b/interfaces/daqp-eigen/daqp.hpp index c291aaf..494e5bc 100644 --- a/interfaces/daqp-eigen/daqp.hpp +++ b/interfaces/daqp-eigen/daqp.hpp @@ -101,12 +101,12 @@ class DAQP { void set_eps_prox(double val); void set_eta_prox(double val); void set_rho_soft(double val); + void set_rho_avi(double val); void set_rel_subopt(double val); void set_abs_subopt(double val); void set_sing_tol(double val); void set_refactor_tol(double val); void set_time_limit(double val); - void set_rho_avi(double val); // Getters for result Eigen::VectorXd get_primal(); diff --git a/interfaces/daqp-julia/src/types.jl b/interfaces/daqp-julia/src/types.jl index 16f988a..04abe6b 100644 --- a/interfaces/daqp-julia/src/types.jl +++ b/interfaces/daqp-julia/src/types.jl @@ -93,6 +93,7 @@ struct DAQPSettings eta_prox::Cdouble rho_soft::Cdouble + rho_avi::Cdouble rel_subopt::Cdouble abs_subopt::Cdouble @@ -100,7 +101,6 @@ struct DAQPSettings sing_tol::Cdouble refactor_tol::Cdouble time_limit::Cdouble - rho_avi::Cdouble end function DAQPSettings() settings = Ref{DAQPBase.DAQPSettings}() diff --git a/interfaces/daqp-matlab/daqpmex.c b/interfaces/daqp-matlab/daqpmex.c index e44c8f5..51ad8bc 100644 --- a/interfaces/daqp-matlab/daqpmex.c +++ b/interfaces/daqp-matlab/daqpmex.c @@ -24,12 +24,12 @@ const char* SETTINGS_FIELDS[] = { "eps_prox", "eta_prox", "rho_soft", + "rho_avi", "abs_subopt", "rel_subopt", "sing_tol", "refactor_tol", - "time_limit", - "rho_avi" + "time_limit" }; diff --git a/interfaces/daqp-python/daqp.pxd b/interfaces/daqp-python/daqp.pxd index 8153fa3..d109f3f 100644 --- a/interfaces/daqp-python/daqp.pxd +++ b/interfaces/daqp-python/daqp.pxd @@ -32,6 +32,7 @@ cdef extern from "types.h": double eta_prox; double rho_soft; + double rho_avi; double rel_subopt; double abs_subopt; @@ -39,7 +40,6 @@ cdef extern from "types.h": double sing_tol; double refactor_tol; double time_limit; - double rho_avi; ctypedef struct DAQPWorkspace: int n diff --git a/interfaces/daqp-python/daqp.pyx b/interfaces/daqp-python/daqp.pyx index d592891..baa997e 100644 --- a/interfaces/daqp-python/daqp.pyx +++ b/interfaces/daqp-python/daqp.pyx @@ -205,8 +205,8 @@ def solve(double[:, :] H, double[:] f, double[:, :] A, cdef DAQPProblem problem = [n, m, m-mA, H_ptr, f_ptr, A_ptr, bu_ptr, bl_ptr, sense_ptr, bp_ptr, nh, problem_type] cdef DAQPSettings settings = [primal_tol, dual_tol, zero_tol, pivot_tol, progress_tol, cycle_tol, iter_limit, fval_bound, - eps_prox, eta_prox, rho_soft, rel_subopt, abs_subopt, sing_tol, refactor_tol, - time_limit, rho_avi] + eps_prox, eta_prox, rho_soft, rho_avi, rel_subopt, abs_subopt, sing_tol, refactor_tol, + time_limit] cdef DAQPResult res = [&x[0], lam_ptr, 0, 0, 0, 0, 0, 0, 0] if primal_start is None and dual_start is None: @@ -586,8 +586,8 @@ cdef class Model: Available keys: ``primal_tol``, ``dual_tol``, ``zero_tol``, ``pivot_tol``, ``progress_tol``, ``cycle_tol``, ``iter_limit``, ``fval_bound``, ``eps_prox``, ``eta_prox``, ``rho_soft``, - ``rel_subopt``, ``abs_subopt``, ``sing_tol``, ``refactor_tol``, - ``time_limit``, ``rho_avi``. + ``rho_avi``, ``rel_subopt``, ``abs_subopt``, ``sing_tol``, + ``refactor_tol``, ``time_limit``. """ if self._work.settings == NULL: return {} @@ -604,12 +604,12 @@ cdef class Model: 'eps_prox': s.eps_prox, 'eta_prox': s.eta_prox, 'rho_soft': s.rho_soft, + 'rho_avi': s.rho_avi, 'rel_subopt': s.rel_subopt, 'abs_subopt': s.abs_subopt, 'sing_tol': s.sing_tol, 'refactor_tol': s.refactor_tol, 'time_limit': s.time_limit, - 'rho_avi': s.rho_avi, } @settings.setter @@ -629,12 +629,12 @@ cdef class Model: if 'eps_prox' in new_settings: s.eps_prox = new_settings['eps_prox'] if 'eta_prox' in new_settings: s.eta_prox = new_settings['eta_prox'] if 'rho_soft' in new_settings: s.rho_soft = new_settings['rho_soft'] + if 'rho_avi' in new_settings: s.rho_avi = new_settings['rho_avi'] if 'rel_subopt' in new_settings: s.rel_subopt = new_settings['rel_subopt'] if 'abs_subopt' in new_settings: s.abs_subopt = new_settings['abs_subopt'] if 'sing_tol' in new_settings: s.sing_tol = new_settings['sing_tol'] if 'refactor_tol' in new_settings: s.refactor_tol = new_settings['refactor_tol'] if 'time_limit' in new_settings: s.time_limit = new_settings['time_limit'] - if 'rho_avi' in new_settings: s.rho_avi = new_settings['rho_avi'] @cython.boundscheck(False) diff --git a/src/api.c b/src/api.c index 502b11f..3f8284d 100644 --- a/src/api.c +++ b/src/api.c @@ -477,6 +477,7 @@ void daqp_default_settings(DAQPSettings* settings){ settings->eta_prox = DAQP_DEFAULT_ETA; settings->rho_soft = DAQP_DEFAULT_RHO_SOFT; + settings->rho_avi = DAQP_DEFAULT_RHO_AVI; settings->rel_subopt = DAQP_DEFAULT_REL_SUBOPT; settings->abs_subopt = DAQP_DEFAULT_ABS_SUBOPT; @@ -484,7 +485,6 @@ void daqp_default_settings(DAQPSettings* settings){ settings->sing_tol = DAQP_DEFAULT_SING_TOL; settings->refactor_tol = DAQP_DEFAULT_REFACTOR_TOL; settings->time_limit = 0; - settings->rho_avi = DAQP_DEFAULT_RHO_AVI; } /* Remove redundant constraints*/ From ee78cc20197c8991faf413ca642b222280bb8448 Mon Sep 17 00:00:00 2001 From: darnstrom Date: Tue, 19 May 2026 01:02:06 +0200 Subject: [PATCH 06/14] Revert "Bump version" This reverts commit 33b3ec2a415043f8211a0d6656095f7d353ef0a9. --- CMakeLists.txt | 2 +- interfaces/daqp-python/setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cf5bddd..0d7c38d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(daqp VERSION 0.8.5) +project(daqp VERSION 0.8.4) include(GNUInstallDirs) diff --git a/interfaces/daqp-python/setup.py b/interfaces/daqp-python/setup.py index bbb2ada..f1ef628 100644 --- a/interfaces/daqp-python/setup.py +++ b/interfaces/daqp-python/setup.py @@ -45,7 +45,7 @@ include_dirs=[str(csrc_dir / 'include')]) setup(name='daqp', - version='0.8.6', + version='0.8.5', description='DAQP: A dual active-set QP solver', url='http://github.com/darnstrom/daqp', author='Daniel Arnström', From 78bc371aff50f59f9860fef44f7185c048a4a837 Mon Sep 17 00:00:00 2001 From: darnstrom Date: Tue, 19 May 2026 01:02:16 +0200 Subject: [PATCH 07/14] Reapply "Bump version" This reverts commit ee78cc20197c8991faf413ca642b222280bb8448. --- CMakeLists.txt | 2 +- interfaces/daqp-python/setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d7c38d..cf5bddd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(daqp VERSION 0.8.4) +project(daqp VERSION 0.8.5) include(GNUInstallDirs) diff --git a/interfaces/daqp-python/setup.py b/interfaces/daqp-python/setup.py index f1ef628..bbb2ada 100644 --- a/interfaces/daqp-python/setup.py +++ b/interfaces/daqp-python/setup.py @@ -45,7 +45,7 @@ include_dirs=[str(csrc_dir / 'include')]) setup(name='daqp', - version='0.8.5', + version='0.8.6', description='DAQP: A dual active-set QP solver', url='http://github.com/darnstrom/daqp', author='Daniel Arnström', From 1b3c73ea6808acf7bef2abf17b4567bae06f643b Mon Sep 17 00:00:00 2001 From: darnstrom Date: Tue, 19 May 2026 01:03:08 +0200 Subject: [PATCH 08/14] Revert "Reapply "Bump version"" This reverts commit 78bc371aff50f59f9860fef44f7185c048a4a837. --- CMakeLists.txt | 2 +- interfaces/daqp-python/setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cf5bddd..0d7c38d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(daqp VERSION 0.8.5) +project(daqp VERSION 0.8.4) include(GNUInstallDirs) diff --git a/interfaces/daqp-python/setup.py b/interfaces/daqp-python/setup.py index bbb2ada..f1ef628 100644 --- a/interfaces/daqp-python/setup.py +++ b/interfaces/daqp-python/setup.py @@ -45,7 +45,7 @@ include_dirs=[str(csrc_dir / 'include')]) setup(name='daqp', - version='0.8.6', + version='0.8.5', description='DAQP: A dual active-set QP solver', url='http://github.com/darnstrom/daqp', author='Daniel Arnström', From a80d1f4017461cc1b507b2eaa8c9044b478ac219 Mon Sep 17 00:00:00 2001 From: darnstrom Date: Tue, 19 May 2026 01:03:10 +0200 Subject: [PATCH 09/14] Reapply "Bump version" This reverts commit ee78cc20197c8991faf413ca642b222280bb8448. --- CMakeLists.txt | 2 +- interfaces/daqp-python/setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d7c38d..cf5bddd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(daqp VERSION 0.8.4) +project(daqp VERSION 0.8.5) include(GNUInstallDirs) diff --git a/interfaces/daqp-python/setup.py b/interfaces/daqp-python/setup.py index f1ef628..bbb2ada 100644 --- a/interfaces/daqp-python/setup.py +++ b/interfaces/daqp-python/setup.py @@ -45,7 +45,7 @@ include_dirs=[str(csrc_dir / 'include')]) setup(name='daqp', - version='0.8.5', + version='0.8.6', description='DAQP: A dual active-set QP solver', url='http://github.com/darnstrom/daqp', author='Daniel Arnström', From daae6c9da56c1e5d604c4d2069ef2ddcc13d71d1 Mon Sep 17 00:00:00 2001 From: darnstrom Date: Tue, 19 May 2026 01:03:11 +0200 Subject: [PATCH 10/14] Reapply "Make new rho_avi last field in setting struct" This reverts commit d061c01d069b360cdb522a9771e077c8b046e80c. --- docs/docs/settings.md | 2 +- include/types.h | 2 +- interfaces/daqp-eigen/daqp.hpp | 2 +- interfaces/daqp-julia/src/types.jl | 2 +- interfaces/daqp-matlab/daqpmex.c | 4 ++-- interfaces/daqp-python/daqp.pxd | 2 +- interfaces/daqp-python/daqp.pyx | 12 ++++++------ src/api.c | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/docs/settings.md b/docs/docs/settings.md index adeb3ca..421b6ce 100644 --- a/docs/docs/settings.md +++ b/docs/docs/settings.md @@ -29,12 +29,12 @@ Table of contents | `eps_prox` | Regularization parameter used for proximal-point iterations | 1e-6| | `eta_prox` | Tolerance that determines if a fix-point has been reached during proximal-point iterations | 1e-6| | `rho_soft` | Weight used for soft constraints (higher enables more violations) | 1e-6| -| `rho_avi` | Regularization parameter for AVIs. `-1` means automatic selection | -1 | | `rel_subopt` | Allowed relative suboptimality in branch and bound | 0 | | `abs_subopt` | Allowed absolute suboptimality in branch and bound | 0 | | `sing_tol` | Tolerance for checking if the LDL' factorization is singular| 3.7e-11 | | `refactor_tol` | Tolerance for refactoring the LDL' factorization before terminating | 1e-9 | | `time_limit` | Maximum wall-clock time in seconds before terminating (0 means no limit) | 0 | +| `rho_avi` | Regularization parameter for AVIs. `-1` means automatic selection | -1 | ## Exit flags diff --git a/include/types.h b/include/types.h index 0efbcfb..437d1bb 100644 --- a/include/types.h +++ b/include/types.h @@ -64,7 +64,6 @@ typedef struct{ c_float eta_prox; c_float rho_soft; - c_float rho_avi; c_float rel_subopt; c_float abs_subopt; @@ -72,6 +71,7 @@ typedef struct{ c_float sing_tol; c_float refactor_tol; c_float time_limit; + c_float rho_avi; }DAQPSettings; diff --git a/interfaces/daqp-eigen/daqp.hpp b/interfaces/daqp-eigen/daqp.hpp index 494e5bc..c291aaf 100644 --- a/interfaces/daqp-eigen/daqp.hpp +++ b/interfaces/daqp-eigen/daqp.hpp @@ -101,12 +101,12 @@ class DAQP { void set_eps_prox(double val); void set_eta_prox(double val); void set_rho_soft(double val); - void set_rho_avi(double val); void set_rel_subopt(double val); void set_abs_subopt(double val); void set_sing_tol(double val); void set_refactor_tol(double val); void set_time_limit(double val); + void set_rho_avi(double val); // Getters for result Eigen::VectorXd get_primal(); diff --git a/interfaces/daqp-julia/src/types.jl b/interfaces/daqp-julia/src/types.jl index 04abe6b..16f988a 100644 --- a/interfaces/daqp-julia/src/types.jl +++ b/interfaces/daqp-julia/src/types.jl @@ -93,7 +93,6 @@ struct DAQPSettings eta_prox::Cdouble rho_soft::Cdouble - rho_avi::Cdouble rel_subopt::Cdouble abs_subopt::Cdouble @@ -101,6 +100,7 @@ struct DAQPSettings sing_tol::Cdouble refactor_tol::Cdouble time_limit::Cdouble + rho_avi::Cdouble end function DAQPSettings() settings = Ref{DAQPBase.DAQPSettings}() diff --git a/interfaces/daqp-matlab/daqpmex.c b/interfaces/daqp-matlab/daqpmex.c index 51ad8bc..e44c8f5 100644 --- a/interfaces/daqp-matlab/daqpmex.c +++ b/interfaces/daqp-matlab/daqpmex.c @@ -24,12 +24,12 @@ const char* SETTINGS_FIELDS[] = { "eps_prox", "eta_prox", "rho_soft", - "rho_avi", "abs_subopt", "rel_subopt", "sing_tol", "refactor_tol", - "time_limit" + "time_limit", + "rho_avi" }; diff --git a/interfaces/daqp-python/daqp.pxd b/interfaces/daqp-python/daqp.pxd index d109f3f..8153fa3 100644 --- a/interfaces/daqp-python/daqp.pxd +++ b/interfaces/daqp-python/daqp.pxd @@ -32,7 +32,6 @@ cdef extern from "types.h": double eta_prox; double rho_soft; - double rho_avi; double rel_subopt; double abs_subopt; @@ -40,6 +39,7 @@ cdef extern from "types.h": double sing_tol; double refactor_tol; double time_limit; + double rho_avi; ctypedef struct DAQPWorkspace: int n diff --git a/interfaces/daqp-python/daqp.pyx b/interfaces/daqp-python/daqp.pyx index baa997e..d592891 100644 --- a/interfaces/daqp-python/daqp.pyx +++ b/interfaces/daqp-python/daqp.pyx @@ -205,8 +205,8 @@ def solve(double[:, :] H, double[:] f, double[:, :] A, cdef DAQPProblem problem = [n, m, m-mA, H_ptr, f_ptr, A_ptr, bu_ptr, bl_ptr, sense_ptr, bp_ptr, nh, problem_type] cdef DAQPSettings settings = [primal_tol, dual_tol, zero_tol, pivot_tol, progress_tol, cycle_tol, iter_limit, fval_bound, - eps_prox, eta_prox, rho_soft, rho_avi, rel_subopt, abs_subopt, sing_tol, refactor_tol, - time_limit] + eps_prox, eta_prox, rho_soft, rel_subopt, abs_subopt, sing_tol, refactor_tol, + time_limit, rho_avi] cdef DAQPResult res = [&x[0], lam_ptr, 0, 0, 0, 0, 0, 0, 0] if primal_start is None and dual_start is None: @@ -586,8 +586,8 @@ cdef class Model: Available keys: ``primal_tol``, ``dual_tol``, ``zero_tol``, ``pivot_tol``, ``progress_tol``, ``cycle_tol``, ``iter_limit``, ``fval_bound``, ``eps_prox``, ``eta_prox``, ``rho_soft``, - ``rho_avi``, ``rel_subopt``, ``abs_subopt``, ``sing_tol``, - ``refactor_tol``, ``time_limit``. + ``rel_subopt``, ``abs_subopt``, ``sing_tol``, ``refactor_tol``, + ``time_limit``, ``rho_avi``. """ if self._work.settings == NULL: return {} @@ -604,12 +604,12 @@ cdef class Model: 'eps_prox': s.eps_prox, 'eta_prox': s.eta_prox, 'rho_soft': s.rho_soft, - 'rho_avi': s.rho_avi, 'rel_subopt': s.rel_subopt, 'abs_subopt': s.abs_subopt, 'sing_tol': s.sing_tol, 'refactor_tol': s.refactor_tol, 'time_limit': s.time_limit, + 'rho_avi': s.rho_avi, } @settings.setter @@ -629,12 +629,12 @@ cdef class Model: if 'eps_prox' in new_settings: s.eps_prox = new_settings['eps_prox'] if 'eta_prox' in new_settings: s.eta_prox = new_settings['eta_prox'] if 'rho_soft' in new_settings: s.rho_soft = new_settings['rho_soft'] - if 'rho_avi' in new_settings: s.rho_avi = new_settings['rho_avi'] if 'rel_subopt' in new_settings: s.rel_subopt = new_settings['rel_subopt'] if 'abs_subopt' in new_settings: s.abs_subopt = new_settings['abs_subopt'] if 'sing_tol' in new_settings: s.sing_tol = new_settings['sing_tol'] if 'refactor_tol' in new_settings: s.refactor_tol = new_settings['refactor_tol'] if 'time_limit' in new_settings: s.time_limit = new_settings['time_limit'] + if 'rho_avi' in new_settings: s.rho_avi = new_settings['rho_avi'] @cython.boundscheck(False) diff --git a/src/api.c b/src/api.c index 3f8284d..502b11f 100644 --- a/src/api.c +++ b/src/api.c @@ -477,7 +477,6 @@ void daqp_default_settings(DAQPSettings* settings){ settings->eta_prox = DAQP_DEFAULT_ETA; settings->rho_soft = DAQP_DEFAULT_RHO_SOFT; - settings->rho_avi = DAQP_DEFAULT_RHO_AVI; settings->rel_subopt = DAQP_DEFAULT_REL_SUBOPT; settings->abs_subopt = DAQP_DEFAULT_ABS_SUBOPT; @@ -485,6 +484,7 @@ void daqp_default_settings(DAQPSettings* settings){ settings->sing_tol = DAQP_DEFAULT_SING_TOL; settings->refactor_tol = DAQP_DEFAULT_REFACTOR_TOL; settings->time_limit = 0; + settings->rho_avi = DAQP_DEFAULT_RHO_AVI; } /* Remove redundant constraints*/ From 75de2cb780c296a77451a05db1acb086818e74e6 Mon Sep 17 00:00:00 2001 From: darnstrom Date: Tue, 19 May 2026 01:03:12 +0200 Subject: [PATCH 11/14] Revert "Make new rho_avi last field in setting struct" This reverts commit 9c199ef9ac57aad68387c68a1e1cb57e0c105243. --- docs/docs/settings.md | 2 +- include/types.h | 2 +- interfaces/daqp-eigen/daqp.hpp | 2 +- interfaces/daqp-julia/src/types.jl | 2 +- interfaces/daqp-matlab/daqpmex.c | 4 ++-- interfaces/daqp-python/daqp.pxd | 2 +- interfaces/daqp-python/daqp.pyx | 12 ++++++------ src/api.c | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/docs/settings.md b/docs/docs/settings.md index 421b6ce..adeb3ca 100644 --- a/docs/docs/settings.md +++ b/docs/docs/settings.md @@ -29,12 +29,12 @@ Table of contents | `eps_prox` | Regularization parameter used for proximal-point iterations | 1e-6| | `eta_prox` | Tolerance that determines if a fix-point has been reached during proximal-point iterations | 1e-6| | `rho_soft` | Weight used for soft constraints (higher enables more violations) | 1e-6| +| `rho_avi` | Regularization parameter for AVIs. `-1` means automatic selection | -1 | | `rel_subopt` | Allowed relative suboptimality in branch and bound | 0 | | `abs_subopt` | Allowed absolute suboptimality in branch and bound | 0 | | `sing_tol` | Tolerance for checking if the LDL' factorization is singular| 3.7e-11 | | `refactor_tol` | Tolerance for refactoring the LDL' factorization before terminating | 1e-9 | | `time_limit` | Maximum wall-clock time in seconds before terminating (0 means no limit) | 0 | -| `rho_avi` | Regularization parameter for AVIs. `-1` means automatic selection | -1 | ## Exit flags diff --git a/include/types.h b/include/types.h index 437d1bb..0efbcfb 100644 --- a/include/types.h +++ b/include/types.h @@ -64,6 +64,7 @@ typedef struct{ c_float eta_prox; c_float rho_soft; + c_float rho_avi; c_float rel_subopt; c_float abs_subopt; @@ -71,7 +72,6 @@ typedef struct{ c_float sing_tol; c_float refactor_tol; c_float time_limit; - c_float rho_avi; }DAQPSettings; diff --git a/interfaces/daqp-eigen/daqp.hpp b/interfaces/daqp-eigen/daqp.hpp index c291aaf..494e5bc 100644 --- a/interfaces/daqp-eigen/daqp.hpp +++ b/interfaces/daqp-eigen/daqp.hpp @@ -101,12 +101,12 @@ class DAQP { void set_eps_prox(double val); void set_eta_prox(double val); void set_rho_soft(double val); + void set_rho_avi(double val); void set_rel_subopt(double val); void set_abs_subopt(double val); void set_sing_tol(double val); void set_refactor_tol(double val); void set_time_limit(double val); - void set_rho_avi(double val); // Getters for result Eigen::VectorXd get_primal(); diff --git a/interfaces/daqp-julia/src/types.jl b/interfaces/daqp-julia/src/types.jl index 16f988a..04abe6b 100644 --- a/interfaces/daqp-julia/src/types.jl +++ b/interfaces/daqp-julia/src/types.jl @@ -93,6 +93,7 @@ struct DAQPSettings eta_prox::Cdouble rho_soft::Cdouble + rho_avi::Cdouble rel_subopt::Cdouble abs_subopt::Cdouble @@ -100,7 +101,6 @@ struct DAQPSettings sing_tol::Cdouble refactor_tol::Cdouble time_limit::Cdouble - rho_avi::Cdouble end function DAQPSettings() settings = Ref{DAQPBase.DAQPSettings}() diff --git a/interfaces/daqp-matlab/daqpmex.c b/interfaces/daqp-matlab/daqpmex.c index e44c8f5..51ad8bc 100644 --- a/interfaces/daqp-matlab/daqpmex.c +++ b/interfaces/daqp-matlab/daqpmex.c @@ -24,12 +24,12 @@ const char* SETTINGS_FIELDS[] = { "eps_prox", "eta_prox", "rho_soft", + "rho_avi", "abs_subopt", "rel_subopt", "sing_tol", "refactor_tol", - "time_limit", - "rho_avi" + "time_limit" }; diff --git a/interfaces/daqp-python/daqp.pxd b/interfaces/daqp-python/daqp.pxd index 8153fa3..d109f3f 100644 --- a/interfaces/daqp-python/daqp.pxd +++ b/interfaces/daqp-python/daqp.pxd @@ -32,6 +32,7 @@ cdef extern from "types.h": double eta_prox; double rho_soft; + double rho_avi; double rel_subopt; double abs_subopt; @@ -39,7 +40,6 @@ cdef extern from "types.h": double sing_tol; double refactor_tol; double time_limit; - double rho_avi; ctypedef struct DAQPWorkspace: int n diff --git a/interfaces/daqp-python/daqp.pyx b/interfaces/daqp-python/daqp.pyx index d592891..baa997e 100644 --- a/interfaces/daqp-python/daqp.pyx +++ b/interfaces/daqp-python/daqp.pyx @@ -205,8 +205,8 @@ def solve(double[:, :] H, double[:] f, double[:, :] A, cdef DAQPProblem problem = [n, m, m-mA, H_ptr, f_ptr, A_ptr, bu_ptr, bl_ptr, sense_ptr, bp_ptr, nh, problem_type] cdef DAQPSettings settings = [primal_tol, dual_tol, zero_tol, pivot_tol, progress_tol, cycle_tol, iter_limit, fval_bound, - eps_prox, eta_prox, rho_soft, rel_subopt, abs_subopt, sing_tol, refactor_tol, - time_limit, rho_avi] + eps_prox, eta_prox, rho_soft, rho_avi, rel_subopt, abs_subopt, sing_tol, refactor_tol, + time_limit] cdef DAQPResult res = [&x[0], lam_ptr, 0, 0, 0, 0, 0, 0, 0] if primal_start is None and dual_start is None: @@ -586,8 +586,8 @@ cdef class Model: Available keys: ``primal_tol``, ``dual_tol``, ``zero_tol``, ``pivot_tol``, ``progress_tol``, ``cycle_tol``, ``iter_limit``, ``fval_bound``, ``eps_prox``, ``eta_prox``, ``rho_soft``, - ``rel_subopt``, ``abs_subopt``, ``sing_tol``, ``refactor_tol``, - ``time_limit``, ``rho_avi``. + ``rho_avi``, ``rel_subopt``, ``abs_subopt``, ``sing_tol``, + ``refactor_tol``, ``time_limit``. """ if self._work.settings == NULL: return {} @@ -604,12 +604,12 @@ cdef class Model: 'eps_prox': s.eps_prox, 'eta_prox': s.eta_prox, 'rho_soft': s.rho_soft, + 'rho_avi': s.rho_avi, 'rel_subopt': s.rel_subopt, 'abs_subopt': s.abs_subopt, 'sing_tol': s.sing_tol, 'refactor_tol': s.refactor_tol, 'time_limit': s.time_limit, - 'rho_avi': s.rho_avi, } @settings.setter @@ -629,12 +629,12 @@ cdef class Model: if 'eps_prox' in new_settings: s.eps_prox = new_settings['eps_prox'] if 'eta_prox' in new_settings: s.eta_prox = new_settings['eta_prox'] if 'rho_soft' in new_settings: s.rho_soft = new_settings['rho_soft'] + if 'rho_avi' in new_settings: s.rho_avi = new_settings['rho_avi'] if 'rel_subopt' in new_settings: s.rel_subopt = new_settings['rel_subopt'] if 'abs_subopt' in new_settings: s.abs_subopt = new_settings['abs_subopt'] if 'sing_tol' in new_settings: s.sing_tol = new_settings['sing_tol'] if 'refactor_tol' in new_settings: s.refactor_tol = new_settings['refactor_tol'] if 'time_limit' in new_settings: s.time_limit = new_settings['time_limit'] - if 'rho_avi' in new_settings: s.rho_avi = new_settings['rho_avi'] @cython.boundscheck(False) diff --git a/src/api.c b/src/api.c index 502b11f..3f8284d 100644 --- a/src/api.c +++ b/src/api.c @@ -477,6 +477,7 @@ void daqp_default_settings(DAQPSettings* settings){ settings->eta_prox = DAQP_DEFAULT_ETA; settings->rho_soft = DAQP_DEFAULT_RHO_SOFT; + settings->rho_avi = DAQP_DEFAULT_RHO_AVI; settings->rel_subopt = DAQP_DEFAULT_REL_SUBOPT; settings->abs_subopt = DAQP_DEFAULT_ABS_SUBOPT; @@ -484,7 +485,6 @@ void daqp_default_settings(DAQPSettings* settings){ settings->sing_tol = DAQP_DEFAULT_SING_TOL; settings->refactor_tol = DAQP_DEFAULT_REFACTOR_TOL; settings->time_limit = 0; - settings->rho_avi = DAQP_DEFAULT_RHO_AVI; } /* Remove redundant constraints*/ From dab45244132198085fc37132c6f9198786a96412 Mon Sep 17 00:00:00 2001 From: darnstrom Date: Tue, 19 May 2026 01:03:14 +0200 Subject: [PATCH 12/14] Revert "Bump version" This reverts commit 33b3ec2a415043f8211a0d6656095f7d353ef0a9. --- CMakeLists.txt | 2 +- interfaces/daqp-python/setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cf5bddd..0d7c38d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(daqp VERSION 0.8.5) +project(daqp VERSION 0.8.4) include(GNUInstallDirs) diff --git a/interfaces/daqp-python/setup.py b/interfaces/daqp-python/setup.py index bbb2ada..f1ef628 100644 --- a/interfaces/daqp-python/setup.py +++ b/interfaces/daqp-python/setup.py @@ -45,7 +45,7 @@ include_dirs=[str(csrc_dir / 'include')]) setup(name='daqp', - version='0.8.6', + version='0.8.5', description='DAQP: A dual active-set QP solver', url='http://github.com/darnstrom/daqp', author='Daniel Arnström', From 5ca035dde793df5eb241b6f439597abe0c535e5f Mon Sep 17 00:00:00 2001 From: darnstrom Date: Tue, 19 May 2026 01:03:15 +0200 Subject: [PATCH 13/14] Revert "Add option for custom rho in avi" This reverts commit a0ce56faeb360569201f8419784c52f8a1ca874a. --- docs/docs/settings.md | 1 - include/constants.h | 1 - include/types.h | 1 - include/utils.h | 2 +- interfaces/daqp-eigen/CMakeLists.txt | 2 - interfaces/daqp-eigen/daqp.cpp | 5 -- interfaces/daqp-eigen/daqp.hpp | 1 - interfaces/daqp-eigen/tests/09_avi_rho.cpp | 68 --------------------- interfaces/daqp-julia/src/types.jl | 1 - interfaces/daqp-julia/test/core_tests.jl | 5 +- interfaces/daqp-matlab/daqpmex.c | 7 --- interfaces/daqp-matlab/test/core_test.m | 9 --- interfaces/daqp-python/daqp.pxd | 2 - interfaces/daqp-python/daqp.pyx | 12 +--- interfaces/daqp-python/test/example_test.py | 5 +- src/api.c | 1 - src/avi.c | 43 ------------- src/utils.c | 42 ++++++++++++- 18 files changed, 48 insertions(+), 160 deletions(-) delete mode 100644 interfaces/daqp-eigen/tests/09_avi_rho.cpp diff --git a/docs/docs/settings.md b/docs/docs/settings.md index adeb3ca..d5bc7cd 100644 --- a/docs/docs/settings.md +++ b/docs/docs/settings.md @@ -29,7 +29,6 @@ Table of contents | `eps_prox` | Regularization parameter used for proximal-point iterations | 1e-6| | `eta_prox` | Tolerance that determines if a fix-point has been reached during proximal-point iterations | 1e-6| | `rho_soft` | Weight used for soft constraints (higher enables more violations) | 1e-6| -| `rho_avi` | Regularization parameter for AVIs. `-1` means automatic selection | -1 | | `rel_subopt` | Allowed relative suboptimality in branch and bound | 0 | | `abs_subopt` | Allowed absolute suboptimality in branch and bound | 0 | | `sing_tol` | Tolerance for checking if the LDL' factorization is singular| 3.7e-11 | diff --git a/include/constants.h b/include/constants.h index fed80cd..8b02018 100644 --- a/include/constants.h +++ b/include/constants.h @@ -22,7 +22,6 @@ extern "C" { #define DAQP_DEFAULT_ETA 1e-6 #define DAQP_DEFAULT_ITER_LIMIT 10000 #define DAQP_DEFAULT_RHO_SOFT 1e-6 -#define DAQP_DEFAULT_RHO_AVI (-1.0) #define DAQP_DEFAULT_REL_SUBOPT 0 #define DAQP_DEFAULT_ABS_SUBOPT 0 #define DAQP_DEFAULT_SING_TOL (3.7e-11) diff --git a/include/types.h b/include/types.h index 0efbcfb..4855522 100644 --- a/include/types.h +++ b/include/types.h @@ -64,7 +64,6 @@ typedef struct{ c_float eta_prox; c_float rho_soft; - c_float rho_avi; c_float rel_subopt; c_float abs_subopt; diff --git a/include/utils.h b/include/utils.h index e9b466b..b5fec10 100644 --- a/include/utils.h +++ b/include/utils.h @@ -17,7 +17,7 @@ void daqp_normalize_Rinv(DAQPWorkspace *work); int daqp_normalize_M(DAQPWorkspace *work); int daqp_check_unconstrained(DAQPWorkspace* work, const int mask); -int daqp_update_avi(DAQPAVI *avi, DAQPProblem *problem, DAQPSettings *settings); +int daqp_update_avi(DAQPAVI *avi, DAQPProblem *problem); int daqp_lu(c_float* A, int* P, int n); void daqp_lu_solve(c_float* LU, int* P, c_float* b, c_float* x, int n); diff --git a/interfaces/daqp-eigen/CMakeLists.txt b/interfaces/daqp-eigen/CMakeLists.txt index fd87af4..76344cb 100644 --- a/interfaces/daqp-eigen/CMakeLists.txt +++ b/interfaces/daqp-eigen/CMakeLists.txt @@ -20,7 +20,6 @@ add_executable(05_warmstart tests/05_warmstart.cpp) add_executable(06_general_hessian tests/06_general_hessian.cpp) add_executable(07_symmetrize_hessian tests/07_symmetrize_hessian.cpp) add_executable(08_unconstrained_check tests/08_unconstrained_check.cpp) -add_executable(09_avi_rho tests/09_avi_rho.cpp) set(TARGETS 00_basic_qp @@ -32,7 +31,6 @@ set(TARGETS 06_general_hessian 07_symmetrize_hessian 08_unconstrained_check - 09_avi_rho ) foreach(TARGET ${TARGETS}) diff --git a/interfaces/daqp-eigen/daqp.cpp b/interfaces/daqp-eigen/daqp.cpp index 9dffb4c..bd13a51 100644 --- a/interfaces/daqp-eigen/daqp.cpp +++ b/interfaces/daqp-eigen/daqp.cpp @@ -380,11 +380,6 @@ void DAQP::set_rho_soft(double val) { is_solved_ = false; } -void DAQP::set_rho_avi(double val) { - settings_.rho_avi = val; - is_solved_ = false; -} - void DAQP::set_rel_subopt(double val) { settings_.rel_subopt = val; is_solved_ = false; diff --git a/interfaces/daqp-eigen/daqp.hpp b/interfaces/daqp-eigen/daqp.hpp index 494e5bc..9579edd 100644 --- a/interfaces/daqp-eigen/daqp.hpp +++ b/interfaces/daqp-eigen/daqp.hpp @@ -101,7 +101,6 @@ class DAQP { void set_eps_prox(double val); void set_eta_prox(double val); void set_rho_soft(double val); - void set_rho_avi(double val); void set_rel_subopt(double val); void set_abs_subopt(double val); void set_sing_tol(double val); diff --git a/interfaces/daqp-eigen/tests/09_avi_rho.cpp b/interfaces/daqp-eigen/tests/09_avi_rho.cpp deleted file mode 100644 index 1696049..0000000 --- a/interfaces/daqp-eigen/tests/09_avi_rho.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include "api.h" - -static double automatic_rho(const double* H, int n) { - double min_diag = DAQP_INF; - double max_row_sum = 0.0; - double fro_norm_sq = 0.0; - - for (int i = 0; i < n; ++i) { - double row_sum = 0.0; - for (int j = 0; j < n; ++j) { - const double hij = H[i * n + j]; - const double sym = 0.5 * (hij + H[j * n + i]); - row_sum += std::abs(sym); - fro_norm_sq += hij * hij; - if (i == j && sym < min_diag) - min_diag = sym; - } - if (row_sum > max_row_sum) - max_row_sum = row_sum; - } - - if (min_diag > 0.0 && max_row_sum > 0.0) - return std::sqrt(min_diag * max_row_sum); - return std::sqrt(fro_norm_sq) / 2.0; -} - -int main() { - constexpr int n = 2; - constexpr int m = 2; - constexpr int ms = 0; - - double H[4] = {1.0, 1.75, 0.0, 1.0}; - double f[2] = {2.0, 2.0}; - double A[4] = {1.0, 0.0, 0.0, 1.0}; - double bupper[2] = {1.0, 1.0}; - double blower[2] = {-1.0, -1.0}; - int sense[2] = {0, 0}; - DAQPProblem qp = {n, m, ms, H, f, A, bupper, blower, sense, nullptr, 0, 1}; - - DAQPWorkspace work = {0}; - int exitflag = setup_daqp(&qp, &work, nullptr); - if (exitflag < 0) - return 1; - - const double expected_auto = automatic_rho(H, n); - const double auto_tol = 1e-12 * (expected_auto > 1.0 ? expected_auto : 1.0); - const bool auto_ok = std::abs(work.avi->rho - expected_auto) <= auto_tol; - free_daqp_workspace(&work); - free_daqp_ldp(&work); - - DAQPSettings settings; - daqp_default_settings(&settings); - settings.rho_avi = 0.25; - - DAQPWorkspace work_override = {0}; - work_override.settings = &settings; - exitflag = setup_daqp(&qp, &work_override, nullptr); - if (exitflag < 0) - return 1; - - const bool override_ok = std::abs(work_override.avi->rho - settings.rho_avi) <= 1e-15; - work_override.settings = nullptr; - free_daqp_workspace(&work_override); - free_daqp_ldp(&work_override); - - return (auto_ok && override_ok) ? 0 : 1; -} diff --git a/interfaces/daqp-julia/src/types.jl b/interfaces/daqp-julia/src/types.jl index 04abe6b..de679c5 100644 --- a/interfaces/daqp-julia/src/types.jl +++ b/interfaces/daqp-julia/src/types.jl @@ -93,7 +93,6 @@ struct DAQPSettings eta_prox::Cdouble rho_soft::Cdouble - rho_avi::Cdouble rel_subopt::Cdouble abs_subopt::Cdouble diff --git a/interfaces/daqp-julia/test/core_tests.jl b/interfaces/daqp-julia/test/core_tests.jl index 3824bc3..9a56d3d 100644 --- a/interfaces/daqp-julia/test/core_tests.jl +++ b/interfaces/daqp-julia/test/core_tests.jl @@ -136,11 +136,9 @@ end # Test access settings s = settings(d) @test s.primal_tol==1e-6 - @test s.rho_avi==-1 - settings(d,Dict(:primal_tol=>1e-5, :rho_avi=>0.25)) + settings(d,Dict(:primal_tol=>1e-5)) s = settings(d) @test s.primal_tol==1e-5 - @test s.rho_avi==0.25 # Update existing model with new problem xref,H,f,A,bupper,blower,sense = generate_test_QP(n,m,ms,nAct,kappa) @@ -511,3 +509,4 @@ end end @test tquad < 10*tsetup #Should be orders of magnitude faster end + diff --git a/interfaces/daqp-matlab/daqpmex.c b/interfaces/daqp-matlab/daqpmex.c index 51ad8bc..ea362bd 100644 --- a/interfaces/daqp-matlab/daqpmex.c +++ b/interfaces/daqp-matlab/daqpmex.c @@ -24,7 +24,6 @@ const char* SETTINGS_FIELDS[] = { "eps_prox", "eta_prox", "rho_soft", - "rho_avi", "abs_subopt", "rel_subopt", "sing_tol", @@ -182,11 +181,8 @@ void mexFunction( int nlhs, mxArray *plhs[], mxSetField(s, 0, "eps_prox", mxCreateDoubleScalar(work->settings->eps_prox)); mxSetField(s, 0, "eta_prox", mxCreateDoubleScalar(work->settings->eta_prox)); mxSetField(s, 0, "rho_soft", mxCreateDoubleScalar(work->settings->rho_soft)); - mxSetField(s, 0, "rho_avi", mxCreateDoubleScalar(work->settings->rho_avi)); mxSetField(s, 0, "abs_subopt", mxCreateDoubleScalar(work->settings->abs_subopt)); mxSetField(s, 0, "rel_subopt", mxCreateDoubleScalar(work->settings->rel_subopt)); - mxSetField(s, 0, "sing_tol", mxCreateDoubleScalar(work->settings->sing_tol)); - mxSetField(s, 0, "refactor_tol", mxCreateDoubleScalar(work->settings->refactor_tol)); mxSetField(s, 0, "time_limit", mxCreateDoubleScalar(work->settings->time_limit)); plhs[0] = s; } @@ -204,11 +200,8 @@ void mexFunction( int nlhs, mxArray *plhs[], work->settings->eps_prox = (c_float)mxGetScalar(mxGetField(s, 0, "eps_prox")); work->settings->eta_prox= (c_float)mxGetScalar(mxGetField(s, 0, "eta_prox")); work->settings->rho_soft= (c_float)mxGetScalar(mxGetField(s, 0, "rho_soft")); - work->settings->rho_avi= (c_float)mxGetScalar(mxGetField(s, 0, "rho_avi")); work->settings->abs_subopt= (c_float)mxGetScalar(mxGetField(s, 0, "abs_subopt")); work->settings->rel_subopt= (c_float)mxGetScalar(mxGetField(s, 0, "rel_subopt")); - work->settings->sing_tol= (c_float)mxGetScalar(mxGetField(s, 0, "sing_tol")); - work->settings->refactor_tol= (c_float)mxGetScalar(mxGetField(s, 0, "refactor_tol")); work->settings->time_limit= (c_float)mxGetScalar(mxGetField(s, 0, "time_limit")); } else if (!strcmp("update", cmd)) { diff --git a/interfaces/daqp-matlab/test/core_test.m b/interfaces/daqp-matlab/test/core_test.m index c340869..ed8fe1a 100644 --- a/interfaces/daqp-matlab/test/core_test.m +++ b/interfaces/daqp-matlab/test/core_test.m @@ -63,15 +63,6 @@ function prox_random_feasible_QPs(testCase) fprintf('=============================================================\n') end - function settings_roundtrip(testCase) - d = daqp(); - s = d.settings(); - testCase.verifyEqual(s.rho_avi,-1); - d.settings('rho_avi',0.25); - s = d.settings(); - testCase.verifyEqual(s.rho_avi,0.25); - end - function random_feasible_LPs(testCase) % Test on randomly generated feasible LPs rng('default'); diff --git a/interfaces/daqp-python/daqp.pxd b/interfaces/daqp-python/daqp.pxd index d109f3f..817b4e0 100644 --- a/interfaces/daqp-python/daqp.pxd +++ b/interfaces/daqp-python/daqp.pxd @@ -32,7 +32,6 @@ cdef extern from "types.h": double eta_prox; double rho_soft; - double rho_avi; double rel_subopt; double abs_subopt; @@ -99,7 +98,6 @@ cdef extern from "constants.h": cdef double DAQP_DEFAULT_ETA cdef int DAQP_DEFAULT_ITER_LIMIT cdef double DAQP_DEFAULT_RHO_SOFT - cdef double DAQP_DEFAULT_RHO_AVI cdef double DAQP_DEFAULT_REL_SUBOPT cdef double DAQP_DEFAULT_ABS_SUBOPT cdef double DAQP_DEFAULT_SING_TOL diff --git a/interfaces/daqp-python/daqp.pyx b/interfaces/daqp-python/daqp.pyx index baa997e..d6a94f6 100644 --- a/interfaces/daqp-python/daqp.pyx +++ b/interfaces/daqp-python/daqp.pyx @@ -73,7 +73,6 @@ def solve(double[:, :] H, double[:] f, double[:, :] A, iter_limit = DAQP_DEFAULT_ITER_LIMIT, fval_bound = DAQP_INF, eps_prox= DAQP_DEFAULT_EPS_PROX, eta_prox = DAQP_DEFAULT_ETA, rho_soft = DAQP_DEFAULT_RHO_SOFT, - rho_avi = DAQP_DEFAULT_RHO_AVI, rel_subopt = DAQP_DEFAULT_REL_SUBOPT, abs_subopt = DAQP_DEFAULT_ABS_SUBOPT, sing_tol = DAQP_DEFAULT_SING_TOL, refactor_tol = DAQP_DEFAULT_REFACTOR_TOL, time_limit = 0, @@ -124,9 +123,6 @@ def solve(double[:, :] H, double[:] f, double[:, :] A, Break points that define prioritized constraints is_avi: flag for interpreting the problem as an AVI (relevant for asymmetric H) - rho_avi: - Overrides the automatic AVI regularization parameter when positive. - The default ``-1`` keeps the automatic choice based on the Hessian. primal_start: Initial guess of primal iterate (used for warm starting). Sets the initial active set based on which constraints are nearly active at this iterate, and @@ -205,7 +201,7 @@ def solve(double[:, :] H, double[:] f, double[:, :] A, cdef DAQPProblem problem = [n, m, m-mA, H_ptr, f_ptr, A_ptr, bu_ptr, bl_ptr, sense_ptr, bp_ptr, nh, problem_type] cdef DAQPSettings settings = [primal_tol, dual_tol, zero_tol, pivot_tol, progress_tol, cycle_tol, iter_limit, fval_bound, - eps_prox, eta_prox, rho_soft, rho_avi, rel_subopt, abs_subopt, sing_tol, refactor_tol, + eps_prox, eta_prox, rho_soft, rel_subopt, abs_subopt, sing_tol, refactor_tol, time_limit] cdef DAQPResult res = [&x[0], lam_ptr, 0, 0, 0, 0, 0, 0, 0] @@ -586,8 +582,8 @@ cdef class Model: Available keys: ``primal_tol``, ``dual_tol``, ``zero_tol``, ``pivot_tol``, ``progress_tol``, ``cycle_tol``, ``iter_limit``, ``fval_bound``, ``eps_prox``, ``eta_prox``, ``rho_soft``, - ``rho_avi``, ``rel_subopt``, ``abs_subopt``, ``sing_tol``, - ``refactor_tol``, ``time_limit``. + ``rel_subopt``, ``abs_subopt``, ``sing_tol``, ``refactor_tol``, + ``time_limit``. """ if self._work.settings == NULL: return {} @@ -604,7 +600,6 @@ cdef class Model: 'eps_prox': s.eps_prox, 'eta_prox': s.eta_prox, 'rho_soft': s.rho_soft, - 'rho_avi': s.rho_avi, 'rel_subopt': s.rel_subopt, 'abs_subopt': s.abs_subopt, 'sing_tol': s.sing_tol, @@ -629,7 +624,6 @@ cdef class Model: if 'eps_prox' in new_settings: s.eps_prox = new_settings['eps_prox'] if 'eta_prox' in new_settings: s.eta_prox = new_settings['eta_prox'] if 'rho_soft' in new_settings: s.rho_soft = new_settings['rho_soft'] - if 'rho_avi' in new_settings: s.rho_avi = new_settings['rho_avi'] if 'rel_subopt' in new_settings: s.rel_subopt = new_settings['rel_subopt'] if 'abs_subopt' in new_settings: s.abs_subopt = new_settings['abs_subopt'] if 'sing_tol' in new_settings: s.sing_tol = new_settings['sing_tol'] diff --git a/interfaces/daqp-python/test/example_test.py b/interfaces/daqp-python/test/example_test.py index b58bced..e786ff5 100644 --- a/interfaces/daqp-python/test/example_test.py +++ b/interfaces/daqp-python/test/example_test.py @@ -190,18 +190,15 @@ def test_model_settings_get(self): self.assertIn('primal_tol', s) self.assertIn('eps_prox', s) self.assertIn('time_limit', s) - self.assertIn('rho_avi', s) self.assertEqual(s['time_limit'], 0.0) - self.assertEqual(s['rho_avi'], -1.0) def test_model_settings_set(self): """settings setter updates only the specified keys.""" d = daqp.Model() original_primal_tol = d.settings['primal_tol'] - d.settings = {'iter_limit': 42, 'time_limit': 5.0, 'rho_avi': 0.25} + d.settings = {'iter_limit': 42, 'time_limit': 5.0} self.assertEqual(d.settings['iter_limit'], 42) self.assertAlmostEqual(d.settings['time_limit'], 5.0) - self.assertAlmostEqual(d.settings['rho_avi'], 0.25) # Other settings should be unchanged self.assertAlmostEqual(d.settings['primal_tol'], original_primal_tol) diff --git a/src/api.c b/src/api.c index 3f8284d..8ef4754 100644 --- a/src/api.c +++ b/src/api.c @@ -477,7 +477,6 @@ void daqp_default_settings(DAQPSettings* settings){ settings->eta_prox = DAQP_DEFAULT_ETA; settings->rho_soft = DAQP_DEFAULT_RHO_SOFT; - settings->rho_avi = DAQP_DEFAULT_RHO_AVI; settings->rel_subopt = DAQP_DEFAULT_REL_SUBOPT; settings->abs_subopt = DAQP_DEFAULT_ABS_SUBOPT; diff --git a/src/avi.c b/src/avi.c index ffd5e3c..1c70f8d 100644 --- a/src/avi.c +++ b/src/avi.c @@ -1,7 +1,6 @@ #include "avi.h" #include "daqp.h" #include "utils.h" -#include // Solve AVI int daqp_solve_avi(DAQPWorkspace *work) { @@ -219,45 +218,3 @@ int daqp_check_optimal_avi(DAQPWorkspace* work){ // All checks passed -> optimal KKT point found return 1; } - -int daqp_update_avi(DAQPAVI* avi, DAQPProblem* p, DAQPSettings* settings) { - const int n = p->n; - int i, j, disp; - c_float val; - c_float min_diag = DAQP_INF; - c_float max_row_sum = 0.0; - c_float fro_norm_sq = 0.0; - - avi->rho = 0.0; - for (i = 0, disp = 0; i < n; i++) { - c_float row_sum = 0.0; - for (j = 0; j < n; j++, disp++) { - val = (p->H[disp] + p->H[j * n + i]) * 0.5; - avi->Hsym[disp] = val; - avi->Hs_rho[disp] = val; - avi->H_rho[disp] = p->H[disp]; - avi->LU_H[disp] = p->H[disp]; - row_sum += (val < 0.0) ? -val : val; - fro_norm_sq += p->H[disp] * p->H[disp]; - if(i == j && val < min_diag) min_diag = val; - } - if(row_sum > max_row_sum) max_row_sum = row_sum; - } - - if(settings != NULL && settings->rho_avi > 0.0) - avi->rho = settings->rho_avi; - else if(min_diag > 0.0 && max_row_sum > 0.0) - avi->rho = sqrt(min_diag * max_row_sum); - else - avi->rho = sqrt(fro_norm_sq) / 2; - - for(i = 0, disp = 0; i < n; i++) { - avi->Hs_rho[disp] += avi->rho; - avi->H_rho[disp] += avi->rho; - disp += n + 1; - } - - daqp_lu(avi->LU_H, avi->P_H, n); - daqp_lu(avi->H_rho, avi->P_H2, n); - return 1; -} diff --git a/src/utils.c b/src/utils.c index 19719f9..e796f31 100644 --- a/src/utils.c +++ b/src/utils.c @@ -41,7 +41,7 @@ int daqp_update_ldp(const int mask, DAQPWorkspace *work, DAQPProblem* qp){ if(work->avi == NULL) error_flag = daqp_update_Rinv(work, qp->H, qp->problem_type==2 ? 1 : 0); else{ - daqp_update_avi(work->avi, qp, work->settings); + daqp_update_avi(work->avi,qp); error_flag = daqp_update_Rinv(work, work->avi->Hs_rho,0); } if(error_flag<0) @@ -467,6 +467,46 @@ int daqp_check_unconstrained(DAQPWorkspace* work, const int mask){ return 1; } +int daqp_update_avi(DAQPAVI* avi, DAQPProblem* p){ + const int n = p->n; + // Setup matrices Hsym, Hs_rho, and H_rho, LU_H + int i,j,disp; + c_float val; + c_float min_diag = DAQP_INF; + c_float max_row_sum = 0.0; + c_float fro_norm_sq = 0.0; + avi->rho = 0.0; + for (i = 0, disp=0; i < n; i++) { + c_float row_sum = 0.0; + for (j = 0; j < n; j++, disp++) { + val = (p->H[disp] + p->H[j * n + i]) * 0.5; + avi->Hsym[disp] = val; + avi->Hs_rho[disp] = val; + avi->H_rho[disp] = p->H[disp]; + avi->LU_H[disp] = p->H[disp]; + row_sum += (val < 0.0) ? -val : val; + fro_norm_sq += p->H[disp] * p->H[disp]; + if(i == j && val < min_diag) min_diag = val; + } + if(row_sum > max_row_sum) max_row_sum = row_sum; + } + // Regularization + if(min_diag > 0.0 && max_row_sum > 0.0) + avi->rho = sqrt(min_diag * max_row_sum); + else + avi->rho = sqrt(fro_norm_sq)/2; + for(i=0,disp=0; iHs_rho[disp] += avi->rho; + avi->H_rho[disp] += avi->rho; + disp += n+1; + } + + // Factorize H and H_rho + daqp_lu(avi->LU_H, avi->P_H, n); + daqp_lu(avi->H_rho, avi->P_H2, n); + return 1; +} + int daqp_lu(c_float* A, int* P, int n) { c_float max_val,pA; for (int i = 0; i < n; i++) P[i] = i; // Initialize permutation vector From ef946b73ca939e58f028c2e44f983e0c4f8c9bbe Mon Sep 17 00:00:00 2001 From: darnstrom Date: Tue, 19 May 2026 01:05:15 +0200 Subject: [PATCH 14/14] Bump version --- CMakeLists.txt | 2 +- interfaces/daqp-python/setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d7c38d..cf5bddd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(daqp VERSION 0.8.4) +project(daqp VERSION 0.8.5) include(GNUInstallDirs) diff --git a/interfaces/daqp-python/setup.py b/interfaces/daqp-python/setup.py index f1ef628..bbb2ada 100644 --- a/interfaces/daqp-python/setup.py +++ b/interfaces/daqp-python/setup.py @@ -45,7 +45,7 @@ include_dirs=[str(csrc_dir / 'include')]) setup(name='daqp', - version='0.8.5', + version='0.8.6', description='DAQP: A dual active-set QP solver', url='http://github.com/darnstrom/daqp', author='Daniel Arnström',