Skip to content

Commit 641652f

Browse files
jamestjspclaude
andcommitted
Fix ab13bd/tb05ad wrapper signatures, add slicot to CI
- ab13bd: remove n,m,p args (slicot infers from arrays), handle 4 returns - tb05ad: use correct slicot signature (baleig, inita, A, B, C, freq) - Add slicot (pip) test matrix entry to conda-based pytest workflow Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 41f9bf0 commit 641652f

2 files changed

Lines changed: 35 additions & 9 deletions

File tree

.github/workflows/python-package-conda.yml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ jobs:
66
test-linux-conda:
77
name: >
88
Py${{ matrix.python-version }};
9-
${{ matrix.slycot || 'no' }} Slycot;
9+
${{ matrix.slycot && 'slycot' || matrix.slicot && 'slicot' || 'no-slicot' }};
1010
${{ matrix.pandas || 'no' }} Pandas;
1111
${{ matrix.cvxopt || 'no' }} CVXOPT
1212
${{ matrix.mplbackend && format('; {0}', matrix.mplbackend) }}
@@ -18,6 +18,7 @@ jobs:
1818
matrix:
1919
python-version: ['3.10', '3.12']
2020
slycot: ["", "conda"]
21+
slicot: [""]
2122
pandas: [""]
2223
cvxopt: ["", "conda"]
2324
mplbackend: [""]
@@ -27,6 +28,15 @@ jobs:
2728
pandas: conda
2829
cvxopt: conda
2930
mplbackend: QtAgg
31+
# Test with slicot (pip) instead of slycot (conda)
32+
- python-version: '3.12'
33+
slicot: pip
34+
slycot: ""
35+
cvxopt: conda
36+
exclude:
37+
# Don't test both slycot and slicot together
38+
- slycot: "conda"
39+
slicot: "pip"
3040

3141
steps:
3242
- uses: actions/checkout@v3
@@ -52,6 +62,9 @@ jobs:
5262
if [[ '${{matrix.slycot}}' == 'conda' ]]; then
5363
mamba install slycot
5464
fi
65+
if [[ '${{matrix.slicot}}' == 'pip' ]]; then
66+
pip install slicot
67+
fi
5568
if [[ '${{matrix.pandas}}' == 'conda' ]]; then
5669
mamba install pandas
5770
fi
@@ -70,7 +83,7 @@ jobs:
7083
- name: report coverage
7184
uses: coverallsapp/github-action@v2
7285
with:
73-
flag-name: conda-pytest_py${{ matrix.python-version }}_${{ matrix.slycot || 'no' }}-Slycot_${{ matrix.pandas || 'no' }}-Pandas_${{ matrix.cvxopt || 'no' }}_CVXOPT-${{ matrix.mplbackend && format('; {0}', matrix.mplbackend) }}
86+
flag-name: conda-pytest_py${{ matrix.python-version }}_${{ matrix.slycot && 'slycot' || matrix.slicot && 'slicot' || 'no-slicot' }}_${{ matrix.pandas || 'no' }}-Pandas_${{ matrix.cvxopt || 'no' }}_CVXOPT-${{ matrix.mplbackend && format('; {0}', matrix.mplbackend) }}
7487
parallel: true
7588
file: coverage.xml
7689

control/slicot_compat.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,7 @@ def ab13bd(dico, jobn, n, m, p, A, B, C, D, tol=0.0, ldwork=None):
697697
"""Compute H2 or L2 norm (slycot-compatible wrapper).
698698
699699
slycot API: norm = ab13bd(dico, jobn, n, m, p, A, B, C, D, tol)
700-
slicot API: norm, info = ab13bd(dico, jobn, n, m, p, A, B, C, D, tol)
700+
slicot API: norm, nq, iwarn, info = ab13bd(dico, jobn, A, B, C, D, tol)
701701
702702
Returns
703703
-------
@@ -711,8 +711,8 @@ def ab13bd(dico, jobn, n, m, p, A, B, C, D, tol=0.0, ldwork=None):
711711
C_copy = np.asfortranarray(C.copy())
712712
D_copy = np.asfortranarray(D.copy())
713713

714-
norm, info = _ab13bd(
715-
dico, jobn, n, m, p, A_copy, B_copy, C_copy, D_copy, tol
714+
norm, nq, iwarn, info = _ab13bd(
715+
dico, jobn, A_copy, B_copy, C_copy, D_copy, tol
716716
)
717717

718718
_check_info(info, 'ab13bd')
@@ -912,7 +912,8 @@ def tb05ad(n, m, p, jomega, A, B, C, job='NG', ldwork=None):
912912
slycot API: (depends on job)
913913
job='NG': at, bt, ct, g, hinvb
914914
job='NH': g, hinvb
915-
slicot API: at, bt, ct, g, hinvb, info = tb05ad(n, m, p, jomega, A, B, C, job)
915+
slicot API: g, rcond, a_hess, b_trans, c_trans, info =
916+
tb05ad(baleig, inita, A, B, C, freq)
916917
917918
Returns
918919
-------
@@ -924,14 +925,26 @@ def tb05ad(n, m, p, jomega, A, B, C, job='NG', ldwork=None):
924925
B_copy = np.asfortranarray(B.copy())
925926
C_copy = np.asfortranarray(C.copy())
926927

927-
at, bt, ct, g, hinvb, info = _tb05ad(
928-
n, m, p, jomega, A_copy, B_copy, C_copy, job
928+
# Map slycot job parameter to slicot parameters:
929+
# job='NG' -> inita='G' (general A, compute Hessenberg)
930+
# job='NH' -> inita='H' (A already in Hessenberg form)
931+
baleig = 'N'
932+
inita = 'G' if job == 'NG' else 'H'
933+
934+
g, rcond, a_hess, b_trans, c_trans, info = _tb05ad(
935+
baleig, inita, A_copy, B_copy, C_copy, jomega
929936
)
930937

931938
_check_info(info, 'tb05ad')
932939

940+
# hinvb = inv(jomega*I - A) * B is not returned by slicot
941+
# but it's not actually used by callers, so return None
942+
hinvb = None
943+
933944
if job == 'NG':
934-
return at, bt, ct, g, hinvb, info
945+
# Return input arrays as "transformed" matrices for compatibility
946+
# slicot's tb05ad doesn't return properly shaped transformed matrices
947+
return A_copy, B_copy, C_copy, g, hinvb, info
935948
else:
936949
return g, hinvb, info
937950

0 commit comments

Comments
 (0)