Skip to content

Commit 2692780

Browse files
committed
Clarabel on macOS and Linux
1 parent 94d3ad1 commit 2692780

File tree

9 files changed

+56
-12
lines changed

9 files changed

+56
-12
lines changed

.github/workflows/CI.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,19 @@ jobs:
3737
- name: Install dependencies (Linux)
3838
if: runner.os == 'Linux'
3939
run: |
40+
sudo apt install libeigen3-dev
4041
python setup.py install
4142
4243
- name: Install dependencies (macOS)
4344
if: runner.os == 'macOS'
4445
run: |
46+
brew install eigen
4547
python setup.py install
4648
4749
- name: Install dependencies (Windows)
4850
if: runner.os == 'Windows'
4951
run: |
52+
vcpkg install eigen3:x64-windows
5053
python setup.py install
5154
5255
- name: Test with pytest (Linux)
@@ -68,4 +71,4 @@ jobs:
6871
run: |
6972
pip install pytest
7073
cd tests
71-
pytest
74+
pytest test_E2E_LP.py::test test_E2E_QP.py::test test_E2E_QP.py::test_OSQP_verbose test_E2E_SOCP.py::test

MANIFEST.in

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,30 @@ include cvxpygen/solvers/ecos/external/ldl/src/*.c
2323
include cvxpygen/solvers/ecos/external/ldl/include/*.h
2424
include cvxpygen/solvers/ecos/external/SuiteSparse_config/*
2525
include cvxpygen/solvers/ecos/ecos_bb/*
26+
include cvxpygen/solvers/Clarabel.cpp/*
27+
include cvxpygen/solvers/Clarabel.cpp/include/Clarabel
28+
include cvxpygen/solvers/Clarabel.cpp/include/c/*.h
29+
include cvxpygen/solvers/Clarabel.cpp/rust_wrapper/*
30+
include cvxpygen/solvers/Clarabel.cpp/rust_wrapper/src/*.rs
31+
include cvxpygen/solvers/Clarabel.cpp/rust_wrapper/src/solver/*.rs
32+
include cvxpygen/solvers/Clarabel.cpp/rust_wrapper/src/solver/implementations/*.rs
33+
include cvxpygen/solvers/Clarabel.cpp/rust_wrapper/src/solver/implementations/default/*.rs
34+
include cvxpygen/solvers/Clarabel.cpp/rust_wrapper/src/utils/*.rs
35+
include cvxpygen/solvers/Clarabel.cpp/Clarabel.rs/*.toml
36+
include cvxpygen/solvers/Clarabel.cpp/Clarabel.rs/src/*.rs
37+
include cvxpygen/solvers/Clarabel.cpp/Clarabel.rs/src/algebra/*.rs
38+
include cvxpygen/solvers/Clarabel.cpp/Clarabel.rs/src/algebra/csc/*.rs
39+
include cvxpygen/solvers/Clarabel.cpp/Clarabel.rs/src/algebra/dense/*.rs
40+
include cvxpygen/solvers/Clarabel.cpp/Clarabel.rs/src/algebra/densesym3x3/*.rs
41+
include cvxpygen/solvers/Clarabel.cpp/Clarabel.rs/src/qdldl/*.rs
42+
include cvxpygen/solvers/Clarabel.cpp/Clarabel.rs/src/solver/*.rs
43+
include cvxpygen/solvers/Clarabel.cpp/Clarabel.rs/src/solver/core/*.rs
44+
include cvxpygen/solvers/Clarabel.cpp/Clarabel.rs/src/solver/core/cones/*.rs
45+
include cvxpygen/solvers/Clarabel.cpp/Clarabel.rs/src/solver/core/kktsolvers/*.rs
46+
include cvxpygen/solvers/Clarabel.cpp/Clarabel.rs/src/solver/core/kktsolvers/direct/*.rs
47+
include cvxpygen/solvers/Clarabel.cpp/Clarabel.rs/src/solver/core/kktsolvers/direct/quasidef/*.rs
48+
include cvxpygen/solvers/Clarabel.cpp/Clarabel.rs/src/solver/core/kktsolvers/direct/quasidef/ldlsolvers/*.rs
49+
include cvxpygen/solvers/Clarabel.cpp/Clarabel.rs/src/solver/implementations/*.rs
50+
include cvxpygen/solvers/Clarabel.cpp/Clarabel.rs/src/solver/implementations/default/*.rs
51+
include cvxpygen/solvers/Clarabel.cpp/Clarabel.rs/src/solver/utils/*.rs
52+
include cvxpygen/solvers/Clarabel.cpp/Clarabel.rs/src/timers/*.rs

cvxpygen/solvers.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,15 @@
1818

1919

2020
def get_interface_class(solver_name: str) -> "SolverInterface":
21+
if system() == 'Windows' and solver_name.upper() == 'CLARABEL':
22+
raise ValueError(f'Clarabel solver currently unsupported on Windows.')
2123
mapping = {
2224
'OSQP': (OSQPInterface, OSQP),
2325
'SCS': (SCSInterface, SCS),
2426
'ECOS': (ECOSInterface, ECOS),
2527
'CLARABEL': (ClarabelInterface, CLARABEL),
26-
'Clarabel': (ClarabelInterface, CLARABEL)
2728
}
28-
interface = mapping.get(solver_name, None)
29+
interface = mapping.get(solver_name.upper(), None)
2930
if interface is None:
3031
raise ValueError(f'Unsupported solver: {solver_name}.')
3132
return interface[0], interface[1]
@@ -957,8 +958,10 @@ def generate_code(self, code_dir, solver_code_dir, cvxpygen_directory,
957958
# adjust paths in Clarabel.cpp/rust_wrapper/CMakeLists.txt
958959
with open(os.path.join(code_dir, 'c', 'solver_code', 'rust_wrapper', 'CMakeLists.txt'), 'r') as f:
959960
cmake_data = f.read()
961+
cmake_data = cmake_data.replace('${CMAKE_SOURCE_DIR}/', '${CMAKE_SOURCE_DIR}/solver_code/')
962+
cmake_data = cmake_data.replace('/libclarabel_c.lib', '/clarabel_c.lib') # until fixed on Clarabel side
960963
with open(os.path.join(code_dir, 'c', 'solver_code', 'rust_wrapper', 'CMakeLists.txt'), 'w') as f:
961-
f.write(cmake_data.replace('${CMAKE_SOURCE_DIR}/', '${CMAKE_SOURCE_DIR}/solver_code/'))
964+
f.write(cmake_data)
962965

963966
# adjust Clarabel
964967
with open(os.path.join(code_dir, 'c', 'solver_code', 'include', 'Clarabel'), 'r') as f:

cvxpygen/template/README.html

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,7 @@ <h3>File Contents</h3>
127127
</dd>
128128
<dd>
129129
where <code>&lt;setting_name&gt;</code> and <code>&lt;setting_type&gt;</code> are
130-
the name and type of the solver setting to be updated, respectively. With the chosen
131-
numerical solver $CPGSOLVERNAME, you can update these settings:
132-
$CPGSETTINGSLIST
133-
.
130+
the name and type of the solver setting to be updated, respectively.
134131
</dd>
135132
<dt><code>c/src/cpg_workspace.c</code> contains the static allocation of the C variables declared in <code>include/cpg_workspace.h</code>.</dt>
136133
<dt><code>c/src/cpg_solve.c</code> contains the definition of functions declared in <code>include/cpg_solve.h</code>.</dt>

cvxpygen/template/setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ def __str__(self):
3030
# Add parameters to cmake_args and define_macros
3131
cmake_args = ['-DCMAKE_POSITION_INDEPENDENT_CODE=ON', '-Wno-dev']
3232
if system() == 'Windows':
33+
cmake_args.append('-DCMAKE_PREFIX_PATH=C:/vcpkg/packages/eigen3_x64-windows/share/eigen3')
3334
# try to find installation of Visual Studio and set as CMake generator, otherwise let CMake choose default generator
3435
vs_versions = []
3536
vswhere_exe = 'C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\vswhere.exe'

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ def readme():
3939
include_package_data=True,
4040
install_requires=[
4141
'cmake >= 3.5',
42-
'cvxpy >= 1.3',
42+
'cvxpy >= 1.3, < 1.4',
4343
'pybind11 >= 2.8',
4444
'osqp >= 0.6.2, < 1.0.0',
45+
'clarabel >= 0.6.0',
4546
'scipy >= 1.1.0',
4647
'numpy >= 1.15',
4748
],

tests/test_E2E_LP.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def get_primal_vec(prob, name):
9999
N_RAND = 2
100100

101101
name_solver_style_seed = [['network', 'resource'],
102-
['ECOS', 'CLARABEL'],
102+
['ECOS'],
103103
['loops'],
104104
list(np.arange(N_RAND))]
105105

@@ -145,3 +145,7 @@ def test(name, solver, style, seed):
145145
assert np.linalg.norm(dual_cg - dual_py, 2) / dual_py_norm < 0.1
146146
else:
147147
assert np.linalg.norm(dual_cg, 2) < 1e-3
148+
149+
150+
def test_clarabel():
151+
test('network', 'CLARABEL', 'loops', 0)

tests/test_E2E_QP.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ def get_primal_vec(prob, name):
175175
N_RAND = 2
176176

177177
name_solver_style_seed = [['actuator', 'MPC', 'portfolio'],
178-
['OSQP', 'SCS', 'CLARABEL'],
178+
['OSQP', 'SCS'],
179179
['loops'],
180180
list(np.arange(N_RAND))]
181181

@@ -251,3 +251,7 @@ def test_OSQP_verbose():
251251
assert 'optimal objective' in verbose_output.getvalue()
252252

253253
sys.stdout = sys.__stdout__
254+
255+
256+
def test_clarabel():
257+
test('actuator', 'CLARABEL', 'loops', 0)

tests/test_E2E_SOCP.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def get_primal_vec(prob, name):
7575
N_RAND = 2
7676

7777
name_solver_style_seed = [['ADP'],
78-
['SCS', 'ECOS', 'CLARABEL'],
78+
['SCS', 'ECOS'],
7979
['unroll', 'loops'],
8080
list(np.arange(N_RAND))]
8181

@@ -120,3 +120,7 @@ def test(name, solver, style, seed):
120120
assert np.linalg.norm(dual_cg - dual_py, 2) / dual_py_norm < 0.1
121121
else:
122122
assert np.linalg.norm(dual_cg, 2) < 1e-3
123+
124+
125+
def test_clarabel():
126+
test('ADP', 'CLARABEL', 'loops', 0)

0 commit comments

Comments
 (0)