Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-13, macos-latest, windows-latest]
os: [ubuntu-latest, macos-15-intel, macos-latest, windows-latest]

steps:
- uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
fail-fast: false

matrix:
os: [ubuntu-latest, macos-13, windows-latest]
os: [ubuntu-latest, macos-latest, windows-latest]

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
build/
.vscode/
__pycache__/
qoco_custom*/
qoco_custom*/
src/bindings.cpp
dist/
17 changes: 13 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,22 @@ include(FetchContent)
FetchContent_Declare(
qoco
GIT_REPOSITORY https://github.com/qoco-org/qoco.git
GIT_TAG bbab0db3899f19331c5c8e9d31d68bbbb68704ae
GIT_TAG d40cb8170b0e967be38ad0e1b134d9c51f5d636e
)

list(POP_BACK CMAKE_MESSAGE_INDENT)
FetchContent_MakeAvailable(qoco)

pybind11_add_module(qoco_ext src/bindings.cpp)
target_include_directories(qoco_ext INTERFACE ${qoco_SOURCE_DIR}/include)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/bindings.cpp.in
${CMAKE_CURRENT_SOURCE_DIR}/src/bindings.cpp)
pybind11_add_module(${QOCO_EXT_MODULE_NAME} src/bindings.cpp)
target_include_directories(${QOCO_EXT_MODULE_NAME} INTERFACE ${qoco_SOURCE_DIR}/include)
install(TARGETS ${QOCO_EXT_MODULE_NAME} DESTINATION . COMPONENT python)

if(${QOCO_ALGEBRA_BACKEND} STREQUAL "builtin")
target_link_libraries(qoco_ext PUBLIC pybind11::module qocostatic)
install(TARGETS qoco_ext DESTINATION . COMPONENT python)
elseif(${QOCO_ALGEBRA_BACKEND} STREQUAL "cuda")
enable_language(CUDA)
find_package(CUDA)
target_link_libraries(qoco_cuda PUBLIC pybind11::module qocostatic)
endif()
19 changes: 19 additions & 0 deletions Dockerfile.cuda-manylinux
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Base manylinux image with Python interpreters
FROM quay.io/pypa/manylinux_2_28_x86_64:2025.11.09-2

# Install prerequisites
RUN yum install -y wget tar bzip2 xz gzip make gcc gcc-c++ git

# Install CUDA Toolkit 13.1 and cuDSS 0.7.1
RUN wget https://developer.download.nvidia.com/compute/cuda/13.0.0/local_installers/cuda_13.0.0_580.65.06_linux.run && \
sh cuda_13.0.0_580.65.06_linux.run --silent --toolkit && \
rm cuda_13.0.0_580.65.06_linux.run && \
curl -O https://developer.download.nvidia.com/compute/cudss/0.7.1/local_installers/cudss-local-repo-rhel10-0.7.1-0.7.1-1.x86_64.rpm && \
rpm -i cudss-local-repo-rhel10-0.7.1-0.7.1-1.x86_64.rpm && \
dnf clean all && \
dnf -y install cudss

# Set CUDA environment variables
ENV PATH=/usr/local/cuda/bin:$PATH
ENV LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH
ENV CUDAToolkit_ROOT=/usr/local/cuda/bin
4 changes: 4 additions & 0 deletions backend/cuda/cibuildwheel.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[tool.cibuildwheel.linux]
skip = ["*-musllinux*"]
manylinux-x86_64-image = "mycuda-manylinux:latest"
environment = { CUDAToolkit_ROOT = "/usr/local/cuda/bin" }
22 changes: 22 additions & 0 deletions backend/cuda/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[build-system]
requires = ["scikit-build-core", "pybind11"]
build-backend = "scikit_build_core.build"

[project]
name = "qoco-cuda"
version = "0.1.0"
description = "QOCO: Quadratic Objective Conic Optimizer"
requires-python = ">=3.8"
authors = [{ name = "Govind M. Chari", email = "govindchari1@gmail.com" }]
dependencies = ["numpy>=1.7", "scipy>=0.13.2", "setuptools", "qoco>=0.2.0"]

[tool.scikit-build]
install.components = ["python"]

[tool.scikit-build.cmake.define]
QOCO_ALGEBRA_BACKEND = "cuda"
QOCO_EXT_MODULE_NAME = "qoco_cuda"

[project.urls]
Homepage = "https://github.com/qoco-org/qoco"
Issues = "https://github.com/qoco-org/qoco/issues"
3 changes: 3 additions & 0 deletions build_cuda_wheels.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
cp backend/cuda/pyproject.toml .
docker build -f Dockerfile.cuda-manylinux -t mycuda-manylinux:latest .
cibuildwheel --platform linux --output-dir dist --config-file backend/cuda/cibuildwheel.toml
10 changes: 9 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,20 @@ description = "QOCO: Quadratic Objective Conic Optimizer"
readme = "README.md"
requires-python = ">=3.8"
authors = [{ name = "Govind M. Chari", email = "govindchari1@gmail.com" }]
dependencies = ["jinja2", "numpy>=1.7", "qdldl", "scipy>=0.13.2", "setuptools"]
dependencies = ["numpy>=1.7", "scipy>=0.13.2", "setuptools"]
[project.optional-dependencies]
cuda = [
"qoco-cuda",
]

[tool.scikit-build]
install.components = ["python"]
wheel.install-dir = "qoco"

[tool.scikit-build.cmake.define]
QOCO_ALGEBRA_BACKEND = "builtin"
QOCO_EXT_MODULE_NAME = "qoco_ext"

[project.urls]
Homepage = "https://github.com/qoco-org/qoco"
Issues = "https://github.com/qoco-org/qoco/issues"
7 changes: 0 additions & 7 deletions requirements.txt

This file was deleted.

2 changes: 1 addition & 1 deletion src/bindings.cpp → src/bindings.cpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ QOCOInt PyQOCOSolver::update_settings(const QOCOSettings &new_settings)
return qoco_update_settings(this->_solver, &new_settings);
}

PYBIND11_MODULE(qoco_ext, m)
PYBIND11_MODULE(@QOCO_EXT_MODULE_NAME@, m)
{
// Enums.
py::enum_<qoco_solve_status>(m, "qoco_solve_status", py::module_local())
Expand Down
32 changes: 30 additions & 2 deletions src/qoco/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,32 @@
import numpy as np
from scipy import sparse
from types import SimpleNamespace
import time

ALGEBRAS = (
"cuda",
"builtin",
)

ALGEBRA_MODULES = {
"cuda": "qoco_cuda",
"builtin": "qoco.qoco_ext",
}


def algebra_available(algebra):
assert algebra in ALGEBRAS, f"Unknown algebra {algebra}"
module = ALGEBRA_MODULES[algebra]

try:
importlib.import_module(module)
except ImportError:
return False
else:
return True


def algebras_available():
return [algebra for algebra in ALGEBRAS if algebra_available(algebra)]


class QOCO:
Expand Down Expand Up @@ -41,7 +66,10 @@ def __init__(self, *args, **kwargs):
"QOCO_MAX_ITER",
]

self.ext = importlib.import_module("qoco.qoco_ext")
self.algebra = kwargs.pop("algebra") if "algebra" in kwargs else "builtin"
if not algebra_available(self.algebra):
raise RuntimeError(f"Algebra {self.algebra} not available")
self.ext = importlib.import_module(ALGEBRA_MODULES[self.algebra])
self._solver = None

def update_settings(self, **kwargs):
Expand Down