diff --git a/scs/scsobject.h b/scs/scsobject.h index 9111e1a2..cac0ffbf 100644 --- a/scs/scsobject.h +++ b/scs/scsobject.h @@ -235,6 +235,9 @@ static void free_py_scs_data(ScsData *d, ScsCone *k, ScsSettings *stgs, if (k->s) { scs_free(k->s); } + if (k->cs) { + scs_free(k->cs); + } if (k->p) { scs_free(k->p); } @@ -400,7 +403,8 @@ static int SCS_init(SCS *self, PyObject *args, PyObject *kwargs) { d->A = A; /* set P if passed in */ - if ((void *)!Py_IsNone(Px) && (void *)!Py_IsNone(Pi) && (void *)!Py_IsNone(Pp)) { + if (!Py_IsNone((PyObject *)Px) && !Py_IsNone((PyObject *)Pi) && + !Py_IsNone((PyObject *)Pp)) { if (!PyArray_ISFLOAT(Px) || PyArray_NDIM(Px) != 1) { free_py_scs_data(d, k, stgs, &ps); return finish_with_error("Px must be a numpy array of floats"); @@ -497,6 +501,10 @@ static int SCS_init(SCS *self, PyObject *args, PyObject *kwargs) { free_py_scs_data(d, k, stgs, &ps); return finish_with_error("Failed to parse cone field s"); } + if (get_cone_arr_dim("cs", &(k->cs), &(k->cssize), cone) < 0) { + free_py_scs_data(d, k, stgs, &ps); + return finish_with_error("Failed to parse cone field cs"); + } if (get_cone_float_arr("p", &(k->p), &(k->psize), cone) < 0) { free_py_scs_data(d, k, stgs, &ps); return finish_with_error("failed to parse cone field p"); @@ -607,17 +615,17 @@ static PyObject *SCS_solve(SCS *self, PyObject *args) { if (_warm_start) { /* If any of these of missing, we use the values in sol */ - if ((void *)!Py_IsNone(warm_x)) { + if (!Py_IsNone((PyObject *)warm_x)) { if (get_warm_start(self->sol->x, self->n, warm_x) < 0) { return none_with_error("Unable to parse x warm-start"); } } - if ((void *)!Py_IsNone(warm_y)) { + if (!Py_IsNone((PyObject *)warm_y)) { if (get_warm_start(self->sol->y, self->m, warm_y) < 0) { return none_with_error("Unable to parse y warm-start"); } } - if ((void *)!Py_IsNone(warm_s)) { + if (!Py_IsNone((PyObject *)warm_s)) { if (get_warm_start(self->sol->s, self->m, warm_s) < 0) { return none_with_error("Unable to parse s warm-start"); } @@ -729,7 +737,7 @@ PyObject *SCS_update(SCS *self, PyObject *args) { return none_with_error("Error parsing inputs"); } /* set c */ - if ((void *)!Py_IsNone(c_new)) { + if (!Py_IsNone((PyObject *)c_new)) { if (!PyArray_ISFLOAT(c_new) || PyArray_NDIM(c_new) != 1) { return none_with_error( "c_new must be a dense numpy array with one dimension"); @@ -741,7 +749,7 @@ PyObject *SCS_update(SCS *self, PyObject *args) { c = (scs_float *)PyArray_DATA(c_new); } /* set b */ - if ((void *)!Py_IsNone(b_new)) { + if (!Py_IsNone((PyObject *)b_new)) { if (!PyArray_ISFLOAT(b_new) || PyArray_NDIM(b_new) != 1) { return none_with_error( "b must be a dense numpy array with one dimension"); diff --git a/scs_source b/scs_source index 3bb04691..4e6a2f05 160000 --- a/scs_source +++ b/scs_source @@ -1 +1 @@ -Subproject commit 3bb046910ef5f0bd248f76c140d274cdbf6d2a2b +Subproject commit 4e6a2f0587c6fd423243798f2a29dbf68529ea5a diff --git a/test/gen_random_cone_prob.py b/test/gen_random_cone_prob.py index a22a852b..b1707b23 100644 --- a/test/gen_random_cone_prob.py +++ b/test/gen_random_cone_prob.py @@ -250,14 +250,14 @@ def project_exp_bisection(v): x = np.copy(v) ub, lb = get_rho_ub(v) - for iter in range(0, 100): + for iter in range(0, 200): rho = (ub + lb) / 2 g, x = calc_grad(v, rho, x) if g > 0: lb = rho else: ub = rho - if ub - lb < 1e-6: + if ub - lb < 1e-9: break return x diff --git a/test/test_mix_sd_csd_cone.py b/test/test_mix_sd_csd_cone.py new file mode 100644 index 00000000..aaf6bbbe --- /dev/null +++ b/test/test_mix_sd_csd_cone.py @@ -0,0 +1,25 @@ +import numpy as np +import scs +import scipy +import pytest + +def gen_feasible(m, n, p_scale = 0.1): + P = p_scale * scipy.sparse.eye(n, format="csc") + A = scipy.sparse.random(m, n, density=0.05, format="csc") + c = np.random.randn(n) + b = np.random.randn(m) + + return (P, A, b, c) + + +@pytest.mark.parametrize("use_indirect", [False, True]) +def test_mix_sd_csd_cones(use_indirect): + seed = 1234 + np.random.seed(seed) + cone = dict(z=1, l=2, s=[3, 4], cs=[5, 4]) + m = int(cone['z'] + cone['l'] + sum([j * (j+1) / 2 for j in cone['s']]) + sum([j * j for j in cone['cs']])) + n = m + (P, A, b, c) = gen_feasible(m, n) + probdata = dict(P=P, A=A, b=b, c=c) + sol = scs.solve(probdata, cone, use_indirect=use_indirect) + np.testing.assert_equal(sol['info']['status'], 'solved') diff --git a/test/test_solve_random_cone_prob.py b/test/test_solve_random_cone_prob.py index 68b3420d..7049e7c8 100644 --- a/test/test_solve_random_cone_prob.py +++ b/test/test_solve_random_cone_prob.py @@ -42,7 +42,7 @@ def import_error(msg): "p": [-0.25, 0.5, 0.75, -0.33], } m = tools.get_scs_cone_dims(K) -params = {"verbose": True, "eps_abs": 1e-5, "eps_rel": 1e-5, "eps_infeas": 1e-5} +params = {"verbose": True, "eps_abs": 1e-7, "eps_rel": 1e-7, "eps_infeas": 1e-7} @pytest.mark.parametrize("use_indirect,gpu", flags) diff --git a/test/test_solve_random_cone_prob_cudss.py b/test/test_solve_random_cone_prob_cudss.py index afeb9749..aa8fc23b 100644 --- a/test/test_solve_random_cone_prob_cudss.py +++ b/test/test_solve_random_cone_prob_cudss.py @@ -34,7 +34,7 @@ def import_error(msg): "p": [-0.25, 0.5, 0.75, -0.33], } m = tools.get_scs_cone_dims(K) -params = {"verbose": True, "eps_abs": 1e-5, "eps_rel": 1e-5, "eps_infeas": 1e-5} +params = {"verbose": True, "eps_abs": 1e-7, "eps_rel": 1e-7, "eps_infeas": 1e-7} try: diff --git a/test/test_solve_random_cone_prob_mkl.py b/test/test_solve_random_cone_prob_mkl.py index 9285d931..5275a7a1 100644 --- a/test/test_solve_random_cone_prob_mkl.py +++ b/test/test_solve_random_cone_prob_mkl.py @@ -34,7 +34,7 @@ def import_error(msg): "p": [-0.25, 0.5, 0.75, -0.33], } m = tools.get_scs_cone_dims(K) -params = {"verbose": True, "eps_abs": 1e-5, "eps_rel": 1e-5, "eps_infeas": 1e-5} +params = {"verbose": True, "eps_abs": 1e-7, "eps_rel": 1e-7, "eps_infeas": 1e-7} try: