diff --git a/fix_t04ad_test.patch b/fix_t04ad_test.patch new file mode 100644 index 0000000..8c14b47 --- /dev/null +++ b/fix_t04ad_test.patch @@ -0,0 +1,199 @@ +From bb66aa6b100855b6bf66c8383a54ee619d2865b6 Mon Sep 17 00:00:00 2001 +From: Benjamin Greiner +Date: Thu, 7 Nov 2019 15:40:57 +0100 +Subject: [PATCH] enhance test_td04ad + +* test the 'R' option of TD04AD according to the documentation example +* consider the order of states in the resulting SS when comparing to ref. + - this fixes build errors on ARM and other arches + +fix some typos +--- + slycot/tests/test_td04ad.py | 107 ++++++++++++++++++++++++++---------- + slycot/transform.py | 10 ++-- + 2 files changed, 82 insertions(+), 35 deletions(-) + +diff --git a/slycot/tests/test_td04ad.py b/slycot/tests/test_td04ad.py +index ab2aa3e..4e0bbd3 100644 +--- a/slycot/tests/test_td04ad.py ++++ b/slycot/tests/test_td04ad.py +@@ -9,12 +9,11 @@ + from slycot import transform + import numpy as np + +-from numpy.testing import assert_raises, assert_almost_equal + + class TestTf2SS(unittest.TestCase): + +- def test_td04ad_case1(self): +- """td04ad: Convert with both 'C' and 'R' options""" ++ def test_td04ad_c(self): ++ """td04ad: Convert with 'C' option""" + + # for octave: + """ +@@ -26,40 +25,92 @@ def test_td04ad_case1(self): + [1.0, 0.4, 3.0], [ 1.0, 1.0 ]}; + """ + +- # common denominators for the inputs +- n = 2 + m = 2 + p = 3 ++ d = 3 + num = np.array([ +- [ [0.0, 0.0, 1.0 ], [ 1.0, 0.0, 0.0 ] ], +- [ [3.0, -1.0, 1.0 ], [ 0.0, 1.0, 0.0 ] ], +- [ [0.0, 0.0, 1.0], [ 0.0, 2.0, 0.0 ] ] ]) +- p, m, d = num.shape ++ [ [0.0, 0.0, 1.0], [1.0, 0.0, 0.0] ], ++ [ [3.0, -1.0, 1.0], [0.0, 1.0, 0.0] ], ++ [ [0.0, 0.0, 1.0], [0.0, 2.0, 0.0] ] ]) ++ + numc = np.zeros((max(1, m, p), max(1, m, p), d), dtype=float) + numc[:p,:m,:] = num +- + denc = np.array( + [ [1.0, 0.4, 3.0], [ 1.0, 1.0, 0.0 ] ]) + indc = np.array( + [ 2, 1 ], dtype=int) +- denr = np.array( +- [ [1.0, 0.4, 3.0], [ 1.0, 1.0, 0.0 ], [1.0, 0.0, 0.0] ]) +- indr = np.array( +- [ 2, 1, 0 ], dtype=int) +- +- n, A, B, C, D = transform.td04ad('C', 2, 3, indc, denc, numc) ++ ++ nref = 3 ++ Aref = np.array([ [-1, 0, 0], ++ [ 0, -0.4, -0.3], ++ [ 0, 10, 0] ]) ++ Bref = np.array([ [0, -1], ++ [1, 0], ++ [0, 0] ]) ++ Cref = np.array([ [1, 0, 0.1], ++ [-1, -2.2, -0.8], ++ [-2, 0, 0.1] ]) ++ Dref = np.array([ [0, 1], ++ [3, 0], ++ [0, 0] ]) ++ ++ nr, A, B, C, D = transform.td04ad('C', m, p, indc, denc, numc) + #print('A=\n', A, '\nB=\n', B, '\nC=\n', C, '\nD=\n', D) +- Ac = [ [-1, 0, 0], [ 0, -0.4, -0.3], [ 0, 10, 0]] +- Bc = [ [0, -1] ,[ 1 , 0], [ 0, 0]] +- Cc = [ [1, 0, 0.1], [-1, -2.2, -0.8], [ -2, 0, 0.1] ] +- Dc = [ [0, 1], [ 3, 0], [ 0, 0]] +- np.testing.assert_array_almost_equal(A, Ac) +- np.testing.assert_array_almost_equal(B, Bc) +- np.testing.assert_array_almost_equal(C, Cc) +- np.testing.assert_array_almost_equal(D, Dc) +- +- resr = transform.td04ad('R', 2, 3, indr, denr, num) ++ np.testing.assert_equal(nref, nr) ++ # order of states is not guaranteed, so we reorder the reference ++ rindex = np.argsort(np.diag(A)) ++ Arref = Aref[rindex, :][:, rindex] ++ Brref = Bref[rindex, :] ++ Crref = Cref[:, rindex] ++ Drref = Dref ++ np.testing.assert_array_almost_equal(A, Arref) ++ np.testing.assert_array_almost_equal(B, Brref) ++ np.testing.assert_array_almost_equal(C, Crref) ++ np.testing.assert_array_almost_equal(D, Drref) ++ ++ ++ def test_td04ad_r(self): ++ """td04ad: Convert with 'R' option""" ++ ++ """ example program from ++ http://slicot.org/objects/software/shared/doc/TD04AD.html""" ++ ++ m = 2 ++ p = 2 ++ rowcol = 'R' ++ index = [3, 3] ++ dcoeff = np.array([ [1.0, 6.0, 11.0, 6.0], [1.0, 6.0, 11.0, 6.0] ]) ++ ++ ucoeff = np.array([ [[1.0, 6.0, 12.0, 7.0], [0.0, 1.0, 4.0, 3.0]], ++ [[0.0, 0.0, 1.0, 1.0], [1.0, 8.0, 20.0, 15.0]] ]) ++ ++ nref = 3 ++ ++ Aref = np.array([ [ 0.5000, -0.8028, 0.9387], ++ [ 4.4047, -2.3380, 2.5076], ++ [-5.5541, 1.6872, -4.1620] ]) ++ Bref = np.array([ [-0.2000, -1.2500], ++ [ 0.0000, -0.6097], ++ [ 0.0000, 2.2217] ]) ++ Cref = np.array([ [0.0000, -0.8679, 0.2119], ++ [0.0000, 0.0000, 0.9002] ]) ++ Dref = np.array([ [1.0000, 0.0000], ++ [0.0000, 1.0000] ]) ++ ++ nr, A, B, C, D = transform.td04ad(rowcol, m, p, index, dcoeff, ucoeff) + #print('A=\n', A, '\nB=\n', B, '\nC=\n', C, '\nD=\n', D) ++ np.testing.assert_equal(nref, nr) ++ # order of states is not guaranteed, so we reorder the reference ++ rindex = np.flip(np.argsort(np.diag(A))) ++ Arref = Aref[rindex, :][:, rindex] ++ Brref = Bref[rindex, :] ++ Crref = Cref[:, rindex] ++ Drref = Dref ++ np.testing.assert_array_almost_equal(A, Arref,decimal=4) ++ np.testing.assert_array_almost_equal(B, Brref,decimal=4) ++ np.testing.assert_array_almost_equal(C, Crref,decimal=4) ++ np.testing.assert_array_almost_equal(D, Drref,decimal=4) ++ + + def test_staticgain(self): + """td04ad: Convert a transferfunction to SS with only static gain""" +@@ -146,9 +197,5 @@ def test_tfm2ss_6(self): + self.assertEqual(n, 0) + np.testing.assert_array_almost_equal(D, np.array([[64]])) + +-def suite(): +- return unittest.TestLoader().loadTestsFromTestCase(TestTF2SS) +- +- + if __name__ == "__main__": + unittest.main() +diff --git a/slycot/transform.py b/slycot/transform.py +index 77b3171..52b3a7b 100644 +--- a/slycot/transform.py ++++ b/slycot/transform.py +@@ -288,9 +288,9 @@ def tb04ad(n,m,p,A,B,C,D,tol1=0.0,tol2=0.0,ldwork=None): + Cr : rank-2 array, shape (p,nr) + output matri of the controllable subsystem + index : rank-1 array, shape (p) +- array of orders of the denomenator polynomials ++ array of orders of the denominator polynomials + dcoeff : rank-2 array, shape (p,max(index)+1) +- array of denomenator coefficients ++ array of denominator coefficients + ucoeff : rank-3 array, shape (p,m,max(index)+1) + array of numerator coefficients + +@@ -578,7 +578,7 @@ def error_handler(out, arg_list): + def td04ad(rowcol,m,p,index,dcoeff,ucoeff,tol=0.0,ldwork=None): + """ nr,A,B,C,D = td04ad(m,p,index,dcoeff,ucoeff,[tol,ldwork]) + +- Convert a tranfer function or matrix of transfer functions to ++ Convert a transfer function or matrix of transfer functions to + a minimum state space realization. + + Required arguments +@@ -592,11 +592,11 @@ def td04ad(rowcol,m,p,index,dcoeff,ucoeff,tol=0.0,ldwork=None): + p : integer + output dimension + index : rank-1 array, shape (p) or (m) +- array of orders of the denomenator polynomials. Different ++ array of orders of the denominator polynomials. Different + shapes corresponding to rowcol=='R' and rowcol=='C' + respectively. + dcoeff : rank-2 array, shape (p,max(index)+1) or (m,max(index)+1) +- array of denomenator coefficients. Different shapes ++ array of denominator coefficients. Different shapes + corresponding to rowcol=='R' and rowcol=='C' respectively. + ucoeff : rank-3 array, shape (p,m,max(index)+1) or (max(p,m),max(p,m),max(index)+1) + array of numerator coefficients. Different shapes diff --git a/python-slycot.spec b/python-slycot.spec index ae485b0..0d5fc3b 100644 --- a/python-slycot.spec +++ b/python-slycot.spec @@ -25,6 +25,7 @@ License: GPL-2.0-only Group: Development/Languages/Python URL: https://github.com/python-control/Slycot Source: https://files.pythonhosted.org/packages/source/s/slycot/slycot-%{version}.tar.gz +Patch0: fix_t04ad_test.patch BuildRequires: %{python_module coverage} BuildRequires: %{python_module devel} BuildRequires: %{python_module nose} @@ -49,6 +50,7 @@ Slycot is a wrapper for the SLICOT control and systems library. %prep %setup -q -n slycot-%{version} +%patch0 %build export CFLAGS="%{optflags}"