Skip to content

Commit 41f9bf0

Browse files
jamestjspclaude
andcommitted
Install slicot in CI workflows, add slycot fallback
- Update doctest.yml and install_examples.yml to install slicot via pip - Modify slicot_compat.py to fall back to slycot if slicot unavailable - Update slicot_check() to detect either package Addresses PR review comments: install slicot in workflows and support both slicot and slycot for backwards compatibility. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 2185695 commit 41f9bf0

File tree

4 files changed

+51
-12
lines changed

4 files changed

+51
-12
lines changed

.github/workflows/doctest.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ jobs:
2727
- name: Install full dependencies
2828
shell: bash -l {0}
2929
run: |
30-
mamba install cvxopt pandas slycot
30+
mamba install cvxopt pandas
31+
pip install slicot
3132
3233
- name: Run doctest
3334
shell: bash -l {0}

.github/workflows/install_examples.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ jobs:
2020
--quiet --yes \
2121
python=3.12 pip \
2222
numpy matplotlib scipy \
23-
slycot pmw jupyter \
23+
pmw jupyter \
2424
ipython!=9.0
25+
conda run -n control-examples-env pip install slicot
2526
2627
- name: Install from source
2728
run: |

control/exception.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,21 @@ class ControlNotImplemented(NotImplementedError):
4747
"""Functionality is not yet implemented."""
4848
pass
4949

50-
# Utility function to see if slicot is installed
50+
# Utility function to see if slicot or slycot is installed
5151
slicot_installed = None
5252
def slicot_check():
53-
"""Return True if slicot is installed, otherwise False."""
53+
"""Return True if slicot or slycot is installed, otherwise False."""
5454
global slicot_installed
5555
if slicot_installed is None:
5656
try:
5757
import slicot # noqa: F401
5858
slicot_installed = True
59-
except:
60-
slicot_installed = False
59+
except ImportError:
60+
try:
61+
import slycot # noqa: F401
62+
slicot_installed = True
63+
except ImportError:
64+
slicot_installed = False
6165
return slicot_installed
6266

6367

control/slicot_compat.py

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,37 @@
1-
# slicot_compat.py - compatibility wrappers for slicot package
1+
# slicot_compat.py - compatibility wrappers for slicot/slycot packages
22
#
33
# This module provides wrappers around the slicot package functions to match
4-
# the API used by the older slycot package. This allows python-control to
5-
# use slicot (C11 translation with Python bindings) as a drop-in replacement.
4+
# the API used by the older slycot package. It also supports falling back to
5+
# slycot if slicot is not installed.
66

7-
"""Compatibility layer for slicot package.
7+
"""Compatibility layer for slicot/slycot packages.
88
99
This module wraps slicot functions to match the slycot API, minimizing changes
10-
to existing code in python-control.
10+
to existing code in python-control. If slicot is not installed, it falls back
11+
to using slycot directly.
1112
"""
1213

13-
import slicot # noqa: F401 - import at top level so ImportError is raised early
1414
import numpy as np
1515

1616
from .exception import ControlArgument
1717

18+
# Try to import slicot first (preferred), fall back to slycot
19+
_use_slicot = False
20+
_use_slycot = False
21+
22+
try:
23+
import slicot # noqa: F401
24+
_use_slicot = True
25+
except ImportError:
26+
try:
27+
import slycot # noqa: F401
28+
_use_slycot = True
29+
except ImportError:
30+
pass
31+
32+
if not _use_slicot and not _use_slycot:
33+
raise ImportError("Neither slicot nor slycot is installed")
34+
1835
__all__ = [
1936
'SlicotResultWarning', 'SlicotArithmeticError',
2037
'sb03md', 'sb03od', 'sb04md', 'sb04qd', 'sg03ad',
@@ -1087,3 +1104,19 @@ def mb03rd(n, A, X, pmax=1.0, tol=0.0, ldwork=None):
10871104
w = wr + 1j * wi
10881105

10891106
return Aout, Xout, blsize[:nblcks], w
1107+
1108+
1109+
# If using slycot (not slicot), overwrite with direct imports from slycot
1110+
if _use_slycot and not _use_slicot:
1111+
from slycot import ( # noqa: F811
1112+
sb03md, sb03od, sb04md, sb04qd, sg03ad,
1113+
sb02md, sb02mt, sg02ad, sb01bd,
1114+
sb10ad, sb10hd, ab08nd,
1115+
ab09ad, ab09md, ab09nd,
1116+
ab13bd, ab13dd, ab13md,
1117+
tb01pd, tb04ad, tb05ad, td04ad, mb03rd,
1118+
)
1119+
from slycot.exceptions import ( # noqa: F811
1120+
SlycotResultWarning as SlicotResultWarning,
1121+
SlycotArithmeticError as SlicotArithmeticError,
1122+
)

0 commit comments

Comments
 (0)