diff --git a/scs/scsobject.h b/scs/scsobject.h index ba2a66c..725b35a 100644 --- a/scs/scsobject.h +++ b/scs/scsobject.h @@ -490,6 +490,7 @@ static int SCS_init(SCS *self, PyObject *args, PyObject *kwargs) { "acceleration_type_1", "acceleration_regularization", "acceleration_relaxation", + "acceleration_trust_factor", "write_data_filename", "log_csv_filename", NULL}; @@ -499,15 +500,15 @@ static int SCS_init(SCS *self, PyObject *args, PyObject *kwargs) { on Windows where sizeof(long) < sizeof(long long) (LLP64 model). */ #ifdef DLONG #ifdef SFLOAT - char *argparse_string = "(LL)O!O!O!OOOO!O!O!|O!O!O!LfffffffLLLffzz"; + char *argparse_string = "(LL)O!O!O!OOOO!O!O!|O!O!O!LfffffffLLLfffzz"; #else - char *argparse_string = "(LL)O!O!O!OOOO!O!O!|O!O!O!LdddddddLLLddzz"; + char *argparse_string = "(LL)O!O!O!OOOO!O!O!|O!O!O!LdddddddLLLdddzz"; #endif #else #ifdef SFLOAT - char *argparse_string = "(ii)O!O!O!OOOO!O!O!|O!O!O!ifffffffiiiffzz"; + char *argparse_string = "(ii)O!O!O!OOOO!O!O!|O!O!O!ifffffffiiifffzz"; #else - char *argparse_string = "(ii)O!O!O!OOOO!O!O!|O!O!O!idddddddiiiddzz"; + char *argparse_string = "(ii)O!O!O!OOOO!O!O!|O!O!O!idddddddiiidddzz"; #endif #endif @@ -547,6 +548,7 @@ static int SCS_init(SCS *self, PyObject *args, PyObject *kwargs) { &(stgs->acceleration_type_1), &(stgs->acceleration_regularization), &(stgs->acceleration_relaxation), + &(stgs->acceleration_trust_factor), &(stgs->write_data_filename), &(stgs->log_csv_filename))) { /* PyArg_ParseTupleAndKeywords already set an informative TypeError @@ -835,6 +837,16 @@ static int SCS_init(SCS *self, PyObject *args, PyObject *kwargs) { free_py_scs_data(d, k, stgs, &ps); return finish_with_error("acceleration_relaxation must be in [0, 2]"); } + /* acceleration_trust_factor: INFINITY (default) disables; positive + * finite values turn on the trust-region + adaptive-r mode in aa. + * NaN and non-positive values are rejected. */ + if (isnan((double)stgs->acceleration_trust_factor) || + stgs->acceleration_trust_factor <= 0) { + free_py_scs_data(d, k, stgs, &ps); + return finish_with_error( + "acceleration_trust_factor must be positive (math.inf for no cap, " + "the default)"); + } if (!isfinite((double)stgs->scale) || stgs->scale <= 0) { free_py_scs_data(d, k, stgs, &ps); return finish_with_error("scale must be a positive finite number"); diff --git a/scs_source b/scs_source index 0600ef3..a8deb1b 160000 --- a/scs_source +++ b/scs_source @@ -1 +1 @@ -Subproject commit 0600ef36307a2c038a790f3c9560b197fd3edc7a +Subproject commit a8deb1b13f0802ad623da70f5137e240dcc66cf2 diff --git a/test/test_scs_coverage.py b/test/test_scs_coverage.py index b14f3f0..d837a56 100644 --- a/test/test_scs_coverage.py +++ b/test/test_scs_coverage.py @@ -2779,6 +2779,32 @@ def test_acceleration_regularization_zero_allowed(): assert sol["info"]["status"] in ("solved", "solved_inaccurate") +def test_acceleration_trust_factor_default_inf(): + """Default acceleration_trust_factor is +inf (no cap, current behavior).""" + solver = scs.SCS(_make_data(), _CONE, verbose=False) + sol = solver.solve() + assert sol["info"]["status"] in ("solved", "solved_inaccurate") + + +@pytest.mark.parametrize("trust_factor", [0.5, 1.0, 2.0, 10.0, float("inf")]) +def test_acceleration_trust_factor_in_range(trust_factor): + """Positive finite values enable trust-region + adaptive r; inf disables.""" + solver = scs.SCS( + _make_data(), _CONE, + acceleration_trust_factor=trust_factor, + verbose=False, + ) + sol = solver.solve() + assert sol["info"]["status"] in ("solved", "solved_inaccurate") + + +@pytest.mark.parametrize("bad", [-1.0, 0.0, float("nan")]) +def test_acceleration_trust_factor_invalid_rejected(bad): + with pytest.raises(ValueError, match="acceleration_trust_factor"): + scs.SCS(_make_data(), _CONE, + acceleration_trust_factor=bad, verbose=False) + + # =========================================================================== # 73. Power cone with different exponents # ===========================================================================