diff --git a/.github/workflows/build_cuda_windows.yml b/.github/workflows/build_cuda_windows.yml index b4f887ed..c0dd6020 100644 --- a/.github/workflows/build_cuda_windows.yml +++ b/.github/workflows/build_cuda_windows.yml @@ -51,7 +51,7 @@ jobs: del %TEMP%\cuda.exe - name: Build wheels - uses: pypa/cibuildwheel@v2.23 + uses: pypa/cibuildwheel@v3.3.1 with: package-dir: backend/cuda config-file: backend/cuda/cibuildwheel.toml diff --git a/backend/cuda/cibuildwheel.toml b/backend/cuda/cibuildwheel.toml index f8b0b453..ced222b6 100644 --- a/backend/cuda/cibuildwheel.toml +++ b/backend/cuda/cibuildwheel.toml @@ -1,6 +1,6 @@ [tool.cibuildwheel] build = "cp3*" -skip = ["cp313t-*", "cp314t-*", "*-win32", "*-manylinux_i686", "*-musllinux_*"] +skip = ["cp314t-win_amd64", "*-win32", "*-manylinux_i686", "*-musllinux_*"] build-verbosity = 1 before-build = "rm -rf {package}/osqp_sources/build" repair-wheel-command = "" diff --git a/backend/mkl/cibuildwheel.toml b/backend/mkl/cibuildwheel.toml index c70c14cb..681ca99e 100644 --- a/backend/mkl/cibuildwheel.toml +++ b/backend/mkl/cibuildwheel.toml @@ -1,6 +1,6 @@ [tool.cibuildwheel] build = "cp3*" -skip = ["cp313t-*", "cp314t-*", "*-win32", "*-manylinux_i686", "*-musllinux_*"] +skip = ["cp314t-win_amd64", "*-win32", "*-manylinux_i686", "*-musllinux_*"] build-verbosity = 1 before-build = "rm -rf {package}/osqp_sources/build" @@ -19,7 +19,7 @@ before-all = [ "wget -q https://registrationcenter-download.intel.com/akdlm/IRC_NAS/cd013e6c-49c4-488b-8b86-25df6693a9b7/m_BaseKit_p_2023.2.0.49398.dmg", "hdiutil attach -noverify -noautofsck m_BaseKit_p_2023.2.0.49398.dmg", "sudo /Volumes/m_BaseKit_p_2023.2.0.49398/bootstrapper.app/Contents/MacOS/bootstrapper --silent --eula accept --components intel.oneapi.mac.mkl.devel", - "pip install 'cmake==3.18.4'" + "pip install cmake" ] environment = { MKL_ROOT = "/opt/intel/oneapi/mkl/latest" } repair-wheel-command = "" diff --git a/cibuildwheel.toml b/cibuildwheel.toml index 3661c8bf..e80ad134 100644 --- a/cibuildwheel.toml +++ b/cibuildwheel.toml @@ -1,6 +1,6 @@ [tool.cibuildwheel] build = "cp3*" -skip = ["cp313t-*", "cp314t-*", "*-win32", "*-manylinux_i686", "*-musllinux_*"] +skip = ["cp314t-win_amd64", "*-win32", "*-manylinux_i686", "*-musllinux_*"] build-verbosity = 1 before-build = "rm -rf {package}/osqp_sources/build" # Install CPU-only version of torch beforehand since that allows cibuildwheel @@ -18,6 +18,14 @@ before-test = 'pip install scipy --prefer-binary' test-groups = ["test-no-nn"] test-command = "python -m pytest -s {project}/src/osqp/tests --continue-on-collection-errors --ignore={project}/src/osqp/tests/nn_test.py" +[[tool.cibuildwheel.overrides]] +# Free-threaded Python: torch support is experimental and not available +# on all platforms, so skip the nn tests. +select = "cp313t-* cp314t-*" +before-test = 'pip install scipy --prefer-binary' +test-groups = ["test-no-nn"] +test-command = "python -m pytest -s {project}/src/osqp/tests --continue-on-collection-errors --ignore={project}/src/osqp/tests/nn_test.py" + [tool.cibuildwheel.pyodide] build = "cp312-pyodide_wasm32" before-test = "" diff --git a/pyproject.toml b/pyproject.toml index 29fae926..4cf3c55c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["scikit-build-core", "pybind11"] +requires = ["scikit-build-core", "pybind11>=2.13"] build-backend = "scikit_build_core.build" [project] diff --git a/src/bindings.cpp.in b/src/bindings.cpp.in index 6666690e..1add93f6 100644 --- a/src/bindings.cpp.in +++ b/src/bindings.cpp.in @@ -176,18 +176,18 @@ OSQPInfo* PyOSQPSolver::get_info() { } OSQPInt PyOSQPSolver::warm_start(py::object x, py::object y) { - OSQPFloat* _x; - OSQPFloat* _y; + OSQPFloat* _x = NULL; + OSQPFloat* _y = NULL; - if (x.is_none()) { - _x = NULL; - } else { - _x = (OSQPFloat *)py::array_t(x).data(); + py::array_t _x_arr, _y_arr; + + if (!x.is_none()) { + _x_arr = py::array_t(x); + _x = (OSQPFloat *)_x_arr.data(); } - if (y.is_none()) { - _y = NULL; - } else { - _y = (OSQPFloat *)py::array_t(y).data(); + if (!y.is_none()) { + _y_arr = py::array_t(y); + _y = (OSQPFloat *)_y_arr.data(); } return osqp_warm_start(this->_solver, _x, _y); @@ -214,93 +214,83 @@ OSQPInt PyOSQPSolver::update_rho(OSQPFloat rho_new) { } OSQPInt PyOSQPSolver::update_data_vec(py::object q, py::object l, py::object u) { - OSQPFloat* _q; - OSQPFloat* _l; - OSQPFloat* _u; + OSQPFloat* _q = NULL; + OSQPFloat* _l = NULL; + OSQPFloat* _u = NULL; - if (q.is_none()) { - _q = NULL; - } else { - _q = (OSQPFloat *)py::array_t(q).data(); + py::array_t _q_arr, _l_arr, _u_arr; + + if (!q.is_none()) { + _q_arr = py::array_t(q); + _q = (OSQPFloat *)_q_arr.data(); } - if (l.is_none()) { - _l = NULL; - } else { - _l = (OSQPFloat *)py::array_t(l).data(); + if (!l.is_none()) { + _l_arr = py::array_t(l); + _l = (OSQPFloat *)_l_arr.data(); } - if (u.is_none()) { - _u = NULL; - } else { - _u = (OSQPFloat *)py::array_t(u).data(); + if (!u.is_none()) { + _u_arr = py::array_t(u); + _u = (OSQPFloat *)_u_arr.data(); } return osqp_update_data_vec(this->_solver, _q, _l, _u); } OSQPInt PyOSQPSolver::update_data_mat(py::object P_x, py::object P_i, py::object A_x, py::object A_i) { - OSQPFloat* _P_x; - OSQPInt* _P_i; + OSQPFloat* _P_x = NULL; + OSQPInt* _P_i = NULL; OSQPInt _P_n = 0; - OSQPFloat* _A_x; - OSQPInt* _A_i; + OSQPFloat* _A_x = NULL; + OSQPInt* _A_i = NULL; OSQPInt _A_n = 0; - if (P_x.is_none()) { - _P_x = NULL; - } else { - auto _P_x_array = py::array_t(P_x); - _P_x = (OSQPFloat *)_P_x_array.data(); - _P_n = _P_x_array.size(); + py::array_t _P_x_arr, _A_x_arr; + py::array_t _P_i_arr, _A_i_arr; + + if (!P_x.is_none()) { + _P_x_arr = py::array_t(P_x); + _P_x = (OSQPFloat *)_P_x_arr.data(); + _P_n = _P_x_arr.size(); } - if (P_i.is_none()) { - _P_i = NULL; - } else { - auto _P_i_array = py::array_t(P_i); - _P_i = (OSQPInt *)_P_i_array.data(); - _P_n = _P_i_array.size(); + if (!P_i.is_none()) { + _P_i_arr = py::array_t(P_i); + _P_i = (OSQPInt *)_P_i_arr.data(); + _P_n = _P_i_arr.size(); } - if (A_x.is_none()) { - _A_x = NULL; - } else { - auto _A_x_array = py::array_t(A_x); - _A_x = (OSQPFloat *)_A_x_array.data(); - _A_n = _A_x_array.size(); + if (!A_x.is_none()) { + _A_x_arr = py::array_t(A_x); + _A_x = (OSQPFloat *)_A_x_arr.data(); + _A_n = _A_x_arr.size(); } - if (A_i.is_none()) { - _A_i = NULL; - } else { - auto _A_i_array = py::array_t(A_i); - _A_i = (OSQPInt *)_A_i_array.data(); - _A_n = _A_i_array.size(); + if (!A_i.is_none()) { + _A_i_arr = py::array_t(A_i); + _A_i = (OSQPInt *)_A_i_arr.data(); + _A_n = _A_i_arr.size(); } return osqp_update_data_mat(this->_solver, _P_x, _P_i, _P_n, _A_x, _A_i, _A_n); } OSQPInt PyOSQPSolver::adjoint_derivative_compute(const py::object dx, const py::object dy) { - OSQPFloat* _dx; - OSQPFloat* _dy; + OSQPFloat* _dx = NULL; + OSQPFloat* _dy = NULL; - if (dx.is_none()) { - _dx = NULL; - } else { - auto _dx_array = py::array_t(dx); - _dx = (OSQPFloat *)_dx_array.data(); - } + py::array_t _dx_arr, _dy_arr; - if (dy.is_none()) { - _dy = NULL; - } else { - auto _dy_array = py::array_t(dy); - _dy = (OSQPFloat *)_dy_array.data(); + if (!dx.is_none()) { + _dx_arr = py::array_t(dx); + _dx = (OSQPFloat *)_dx_arr.data(); } + if (!dy.is_none()) { + _dy_arr = py::array_t(dy); + _dy = (OSQPFloat *)_dy_arr.data(); + } return osqp_adjoint_derivative_compute(this->_solver, _dx, _dy); - } OSQPInt PyOSQPSolver::adjoint_derivative_get_mat(CSC& dP, CSC& dA) { @@ -311,9 +301,10 @@ OSQPInt PyOSQPSolver::adjoint_derivative_get_mat(CSC& dP, CSC& dA) { } OSQPInt PyOSQPSolver::adjoint_derivative_get_vec(py::object dq, py::object dl, py::object du) { - OSQPFloat* _dq = (OSQPFloat *)py::array_t(dq).data(); - OSQPFloat* _dl = (OSQPFloat *)py::array_t(dl).data(); - OSQPFloat* _du = (OSQPFloat *)py::array_t(du).data(); + py::array_t _dq_arr(dq), _dl_arr(dl), _du_arr(du); + OSQPFloat* _dq = (OSQPFloat *)_dq_arr.data(); + OSQPFloat* _dl = (OSQPFloat *)_dl_arr.data(); + OSQPFloat* _du = (OSQPFloat *)_du_arr.data(); return osqp_adjoint_derivative_get_vec(this->_solver, _dq, _dl, _du); } diff --git a/src/osqp/codegen/pywrapper/bindings.cpp.jinja b/src/osqp/codegen/pywrapper/bindings.cpp.jinja index b8b54d15..99aa21e3 100644 --- a/src/osqp/codegen/pywrapper/bindings.cpp.jinja +++ b/src/osqp/codegen/pywrapper/bindings.cpp.jinja @@ -28,24 +28,23 @@ py::tuple solve() { } OSQPInt update_data_vec(py::object q, py::object l, py::object u) { - OSQPFloat* _q; - OSQPFloat* _l; - OSQPFloat* _u; - - if (q.is_none()) { - _q = NULL; - } else { - _q = (OSQPFloat *)py::array_t(q).data(); + OSQPFloat* _q = NULL; + OSQPFloat* _l = NULL; + OSQPFloat* _u = NULL; + + py::array_t _q_arr, _l_arr, _u_arr; + + if (!q.is_none()) { + _q_arr = py::array_t(q); + _q = (OSQPFloat *)_q_arr.data(); } - if (l.is_none()) { - _l = NULL; - } else { - _l = (OSQPFloat *)py::array_t(l).data(); + if (!l.is_none()) { + _l_arr = py::array_t(l); + _l = (OSQPFloat *)_l_arr.data(); } - if (u.is_none()) { - _u = NULL; - } else { - _u = (OSQPFloat *)py::array_t(u).data(); + if (!u.is_none()) { + _u_arr = py::array_t(u); + _u = (OSQPFloat *)_u_arr.data(); } return osqp_update_data_vec(&{{prefix}}solver, _q, _l, _u); @@ -53,43 +52,38 @@ OSQPInt update_data_vec(py::object q, py::object l, py::object u) { #if OSQP_EMBEDDED_MODE == 2 OSQPInt update_data_mat(py::object P_x, py::object P_i, py::object A_x, py::object A_i) { - OSQPFloat* _P_x; - OSQPInt* _P_i; + OSQPFloat* _P_x = NULL; + OSQPInt* _P_i = NULL; OSQPInt _P_n = 0; - OSQPFloat* _A_x; - OSQPInt* _A_i; + OSQPFloat* _A_x = NULL; + OSQPInt* _A_i = NULL; OSQPInt _A_n = 0; - if (P_x.is_none()) { - _P_x = NULL; - } else { - auto _P_x_array = py::array_t(P_x); - _P_x = (OSQPFloat *)_P_x_array.data(); - _P_n = _P_x_array.size(); + py::array_t _P_x_arr, _A_x_arr; + py::array_t _P_i_arr, _A_i_arr; + + if (!P_x.is_none()) { + _P_x_arr = py::array_t(P_x); + _P_x = (OSQPFloat *)_P_x_arr.data(); + _P_n = _P_x_arr.size(); } - if (P_i.is_none()) { - _P_i = NULL; - } else { - auto _P_i_array = py::array_t(P_i); - _P_i = (OSQPInt *)_P_i_array.data(); - _P_n = _P_i_array.size(); + if (!P_i.is_none()) { + _P_i_arr = py::array_t(P_i); + _P_i = (OSQPInt *)_P_i_arr.data(); + _P_n = _P_i_arr.size(); } - if (A_x.is_none()) { - _A_x = NULL; - } else { - auto _A_x_array = py::array_t(A_x); - _A_x = (OSQPFloat *)_A_x_array.data(); - _A_n = _A_x_array.size(); + if (!A_x.is_none()) { + _A_x_arr = py::array_t(A_x); + _A_x = (OSQPFloat *)_A_x_arr.data(); + _A_n = _A_x_arr.size(); } - if (A_i.is_none()) { - _A_i = NULL; - } else { - auto _A_i_array = py::array_t(A_i); - _A_i = (OSQPInt *)_A_i_array.data(); - _A_n = _A_i_array.size(); + if (!A_i.is_none()) { + _A_i_arr = py::array_t(A_i); + _A_i = (OSQPInt *)_A_i_arr.data(); + _A_n = _A_i_arr.size(); } return osqp_update_data_mat(&{{prefix}}solver, _P_x, _P_i, _P_n, _A_x, _A_i, _A_n); diff --git a/src/osqp/codegen/pywrapper/setup.py.jinja b/src/osqp/codegen/pywrapper/setup.py.jinja index 9b321e15..d025f5aa 100644 --- a/src/osqp/codegen/pywrapper/setup.py.jinja +++ b/src/osqp/codegen/pywrapper/setup.py.jinja @@ -21,6 +21,9 @@ class CmdCMakeBuild(build_ext): cmake_args = [ f'-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}', f'-DPYTHON_EXECUTABLE={sys.executable}', + f'-DPython_EXECUTABLE={sys.executable}', + f'-DPython3_EXECUTABLE={sys.executable}', + '-DPYBIND11_FINDPYTHON=NEW', ] build_args = []