From 25f0a21cdff4e07ec066cb7b16503bb5d0247c26280aecfdead5923665389e6e Mon Sep 17 00:00:00 2001 From: Benjamin Greiner Date: Thu, 7 Nov 2019 14:46:46 +0000 Subject: [PATCH 1/5] add patch to fix the failing test on arm and other arches OBS-URL: https://build.opensuse.org/package/show/devel:languages:python:numeric/python-slycot?expand=0&rev=8 --- fix_t04ad_test.patch | 199 +++++++++++++++++++++++++++++++++++++++++++ python-slycot.spec | 2 + 2 files changed, 201 insertions(+) create mode 100644 fix_t04ad_test.patch 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}" From 7d125b83bd852c07ced4ab0dbc5588a3e86330fb79297c4bd5c3848ac94306cd Mon Sep 17 00:00:00 2001 From: Benjamin Greiner Date: Thu, 7 Nov 2019 14:54:22 +0000 Subject: [PATCH 2/5] OBS-URL: https://build.opensuse.org/package/show/devel:languages:python:numeric/python-slycot?expand=0&rev=9 --- python-slycot.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python-slycot.spec b/python-slycot.spec index 0d5fc3b..2978f40 100644 --- a/python-slycot.spec +++ b/python-slycot.spec @@ -50,7 +50,7 @@ Slycot is a wrapper for the SLICOT control and systems library. %prep %setup -q -n slycot-%{version} -%patch0 +%patch0 -p1 %build export CFLAGS="%{optflags}" From 7f3f3812491a7f89d213d0a0475a4ba4a8146a32ac21dd7c7c01a671874c682a Mon Sep 17 00:00:00 2001 From: Benjamin Greiner Date: Thu, 7 Nov 2019 17:05:49 +0000 Subject: [PATCH 3/5] another try at fixing the arm and powerpc unittest failures OBS-URL: https://build.opensuse.org/package/show/devel:languages:python:numeric/python-slycot?expand=0&rev=10 --- ...st.patch => 0001-enhance-test_td04ad.patch | 38 ++++++++++--------- python-slycot.spec | 2 +- 2 files changed, 21 insertions(+), 19 deletions(-) rename fix_t04ad_test.patch => 0001-enhance-test_td04ad.patch (88%) diff --git a/fix_t04ad_test.patch b/0001-enhance-test_td04ad.patch similarity index 88% rename from fix_t04ad_test.patch rename to 0001-enhance-test_td04ad.patch index 8c14b47..ca7fac1 100644 --- a/fix_t04ad_test.patch +++ b/0001-enhance-test_td04ad.patch @@ -1,4 +1,4 @@ -From bb66aa6b100855b6bf66c8383a54ee619d2865b6 Mon Sep 17 00:00:00 2001 +From a85f28154a1d826abb39594a408fb8355c4b8a85 Mon Sep 17 00:00:00 2001 From: Benjamin Greiner Date: Thu, 7 Nov 2019 15:40:57 +0100 Subject: [PATCH] enhance test_td04ad @@ -9,15 +9,15 @@ Subject: [PATCH] enhance test_td04ad fix some typos --- - slycot/tests/test_td04ad.py | 107 ++++++++++++++++++++++++++---------- + slycot/tests/test_td04ad.py | 106 ++++++++++++++++++++++++++---------- slycot/transform.py | 10 ++-- - 2 files changed, 82 insertions(+), 35 deletions(-) + 2 files changed, 81 insertions(+), 35 deletions(-) diff --git a/slycot/tests/test_td04ad.py b/slycot/tests/test_td04ad.py -index ab2aa3e..4e0bbd3 100644 +index ab2aa3e..91f381f 100644 --- a/slycot/tests/test_td04ad.py +++ b/slycot/tests/test_td04ad.py -@@ -9,12 +9,11 @@ +@@ -9,12 +9,11 @@ import unittest from slycot import transform import numpy as np @@ -32,7 +32,7 @@ index ab2aa3e..4e0bbd3 100644 # for octave: """ -@@ -26,40 +25,92 @@ def test_td04ad_case1(self): +@@ -26,40 +25,91 @@ class TestTf2SS(unittest.TestCase): [1.0, 0.4, 3.0], [ 1.0, 1.0 ]}; """ @@ -91,16 +91,15 @@ index ab2aa3e..4e0bbd3 100644 - - 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) ++ # the returned state space representation is not guaranteed to ++ # be of one form for all architectures, so we transform back ++ # to tf and check for equality then ++ _, _, _, _, _, dcoeff, ucoeff = transform.tb04ad( ++ nr, m, p, A, B, C, D) ++ _, _, _, _, _, dcoeffref, ucoeffref = transform.tb04ad( ++ nref, m, p, Aref, Bref, Cref, Dref) ++ np.testing.assert_array_almost_equal(dcoeff,dcoeffref) ++ np.testing.assert_array_almost_equal(ucoeff,ucoeffref) + + + def test_td04ad_r(self): @@ -148,7 +147,7 @@ index ab2aa3e..4e0bbd3 100644 def test_staticgain(self): """td04ad: Convert a transferfunction to SS with only static gain""" -@@ -146,9 +197,5 @@ def test_tfm2ss_6(self): +@@ -146,9 +196,5 @@ class TestTf2SS(unittest.TestCase): self.assertEqual(n, 0) np.testing.assert_array_almost_equal(D, np.array([[64]])) @@ -174,7 +173,7 @@ index 77b3171..52b3a7b 100644 ucoeff : rank-3 array, shape (p,m,max(index)+1) array of numerator coefficients -@@ -578,7 +578,7 @@ def error_handler(out, arg_list): +@@ -578,7 +578,7 @@ def tb05ad(n, m, p, jomega, A, B, C, job='NG'): 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]) @@ -197,3 +196,6 @@ index 77b3171..52b3a7b 100644 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 +-- +2.24.0 + diff --git a/python-slycot.spec b/python-slycot.spec index 2978f40..81bbb0a 100644 --- a/python-slycot.spec +++ b/python-slycot.spec @@ -25,7 +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 +Patch0: 0001-enhance-test_td04ad.patch BuildRequires: %{python_module coverage} BuildRequires: %{python_module devel} BuildRequires: %{python_module nose} From 67645550ec550e22df222bd253d276c156dc5ff62f6efa6fda06f8635cc111cc Mon Sep 17 00:00:00 2001 From: Benjamin Greiner Date: Fri, 8 Nov 2019 14:50:54 +0000 Subject: [PATCH 4/5] Accepting request 746641 from home:bnavigator:branches:devel:languages:python:numeric - fix td04ad ans sg03ad unittests to pass on all architectures OBS-URL: https://build.opensuse.org/request/show/746641 OBS-URL: https://build.opensuse.org/package/show/devel:languages:python:numeric/python-slycot?expand=0&rev=11 --- fix-test-sg03ad.patch | 74 +++++++ ...test_td04ad.patch => fix-test-td04ad.patch | 205 ++++++++++++++---- python-slycot.changes | 5 + python-slycot.spec | 4 +- 4 files changed, 240 insertions(+), 48 deletions(-) create mode 100644 fix-test-sg03ad.patch rename 0001-enhance-test_td04ad.patch => fix-test-td04ad.patch (55%) diff --git a/fix-test-sg03ad.patch b/fix-test-sg03ad.patch new file mode 100644 index 0000000..b2472b6 --- /dev/null +++ b/fix-test-sg03ad.patch @@ -0,0 +1,74 @@ +diff --git a/slycot/tests/test_sg03ad.py b/slycot/tests/test_sg03ad.py +index 7b498d6..bc4b043 100644 +--- a/slycot/tests/test_sg03ad.py ++++ b/slycot/tests/test_sg03ad.py +@@ -8,52 +8,50 @@ import unittest + from slycot import synthesis + import numpy as np + +-from numpy.testing import assert_raises, assert_almost_equal ++from numpy.testing import assert_almost_equal + + # test cases from + # http://www.qucosa.de/fileadmin/data/qucosa/documents/4168/data/b002.pdf + ++ + class test_sg03ad(unittest.TestCase): + + def test_sg03ad_a(self): + # Example 1 + n = 100 +- Xref = np.ones((n,n)) ++ Xref = np.ones((n, n)) + U = np.tril(Xref) + for t in range(0, 50, 10): +- A = 2.0**(-t) - np.eye(n) + np.diag(range(1,n+1)) + U.T +- E = np.eye(n) + 2**(-t)*U ++ A = 2.0**(-t) - np.eye(n) + np.diag(np.arange(1, n+1)) + U.T ++ E = np.eye(n) + 2.0**(-t)*U + Y = A.T.dot(Xref).dot(E) + E.T.dot(Xref).dot(A) +- Q = np.zeros((n,n)) +- Z = np.zeros((n,n)) ++ Q = np.zeros((n, n)) ++ Z = np.zeros((n, n)) + A, E, Q, Z, X, scale, sep, ferr, alphar, alphai, beta = \ + synthesis.sg03ad('C', 'B', 'N', 'N', 'L', n, A, E, Q, Z, Y) + assert_almost_equal(Xref, X) +- ++ + def test_sg03ad_3(self): + n = 3 + A = np.array([[3.0, 1.0, 1.0], + [1.0, 3.0, 0.0], + [1.0, 0.0, 2.0]]) + E = np.array([[1.0, 3.0, 0.0], +- [3.0, 2.0, 1.0], +- [1.0, 0.0, 1.0]]) ++ [3.0, 2.0, 1.0], ++ [1.0, 0.0, 1.0]]) + Y = np.array([[64.0, 73.0, 28.0], +- [73.0, 70.0, 25.0], +- [28.0, 25.0, 18.0]]) ++ [73.0, 70.0, 25.0], ++ [28.0, 25.0, 18.0]]) + Xref = np.array([[-2.0000, -1.0000, 0.0000], +- [-1.0000, -3.0000, -1.0000], +- [0.0000, -1.0000, -3.0000]]) +- Q = np.zeros((3,3)) +- Z = np.zeros((3,3)) ++ [-1.0000, -3.0000, -1.0000], ++ [0.0000, -1.0000, -3.0000]]) ++ Q = np.zeros((3, 3)) ++ Z = np.zeros((3, 3)) + A, E, Q, Z, X, scale, sep, ferr, alphar, alphai, beta = \ + synthesis.sg03ad('C', 'B', 'N', 'N', 'L', n, A, E, Q, Z, -Y) +- #print(A, E, Q, Z, X, scale, sep) ++ # print(A, E, Q, Z, X, scale, sep) + assert_almost_equal(X, Xref) + +-def suite(): +- return unittest.TestLoader().loadTestsFromTestCase(TestConvert) +- + + if __name__ == "__main__": + unittest.main() diff --git a/0001-enhance-test_td04ad.patch b/fix-test-td04ad.patch similarity index 55% rename from 0001-enhance-test_td04ad.patch rename to fix-test-td04ad.patch index ca7fac1..1a70446 100644 --- a/0001-enhance-test_td04ad.patch +++ b/fix-test-td04ad.patch @@ -1,23 +1,44 @@ -From a85f28154a1d826abb39594a408fb8355c4b8a85 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 | 106 ++++++++++++++++++++++++++---------- - slycot/transform.py | 10 ++-- - 2 files changed, 81 insertions(+), 35 deletions(-) - +diff --git a/slycot/tests/test.py b/slycot/tests/test.py +index ec0b072..eca7b38 100644 +--- a/slycot/tests/test.py ++++ b/slycot/tests/test.py +@@ -49,24 +49,6 @@ class Test(unittest.TestCase): + self.assertAlmostEqual(Ac[1][0], 1) + self.assertAlmostEqual(Ac[1][1], -3) + +- def test_td04ad_static(self): +- """Regression: td04ad (TFM -> SS transformation) for static TFM""" +- import numpy as np +- from itertools import product +- # 'C' fails on static TFs +- for nout,nin,rc in product(range(1,6),range(1,6),['R']): +- num = np.reshape(np.arange(nout*nin),(nout,nin,1)) +- if rc == 'R': +- den = np.reshape(np.arange(1,1+nout),(nout,1)) +- else: +- den = np.reshape(np.arange(1,1+nin),(nin,1)) +- index = np.tile([0],den.shape[0]) +- nr,a,b,c,d = transform.td04ad(rc,nin,nout,index,den,num) +- +- +-def suite(): +- return unittest.TestLoader().loadTestsFromTestCase(TestConvert) +- + + if __name__ == "__main__": + unittest.main() diff --git a/slycot/tests/test_td04ad.py b/slycot/tests/test_td04ad.py -index ab2aa3e..91f381f 100644 +index ab2aa3e..e442a96 100644 --- a/slycot/tests/test_td04ad.py +++ b/slycot/tests/test_td04ad.py -@@ -9,12 +9,11 @@ import unittest +@@ -3,19 +3,18 @@ + # test_td04ad.py - test suite for tf -> ss conversion + # RvP, 04 Jun 2018 + +-from __future__ import print_function ++from __future__ import print_function, division + + import unittest from slycot import transform import numpy as np @@ -27,20 +48,24 @@ index ab2aa3e..91f381f 100644 - 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,91 @@ class TestTf2SS(unittest.TestCase): + num = { [0.0, 0.0, 1.0 ], [ 1.0, 0.0 ]; +@@ -25,45 +24,96 @@ class TestTf2SS(unittest.TestCase): + [1.0, 0.4, 3.0], [ 1.0, 1.0 ]; [1.0, 0.4, 3.0], [ 1.0, 1.0 ]}; """ - +- - # common denominators for the inputs - n = 2 ++ m = 2 p = 3 -+ d = 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 ] ], @@ -49,7 +74,7 @@ index ab2aa3e..91f381f 100644 + [ [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 - @@ -61,15 +86,14 @@ index ab2aa3e..91f381f 100644 - [ [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], ++ [1, 0], + [0, 0] ]) + Cref = np.array([ [1, 0, 0.1], + [-1, -2.2, -0.8], @@ -77,7 +101,7 @@ index ab2aa3e..91f381f 100644 + 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]] @@ -88,8 +112,6 @@ index ab2aa3e..91f381f 100644 - 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) + # the returned state space representation is not guaranteed to + # be of one form for all architectures, so we transform back @@ -104,19 +126,20 @@ index ab2aa3e..91f381f 100644 + + def test_td04ad_r(self): + """td04ad: Convert with 'R' option""" -+ + +- resr = transform.td04ad('R', 2, 3, indr, denr, num) + """ 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]] ]) -+ ++ [[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], @@ -124,41 +147,129 @@ index ab2aa3e..91f381f 100644 + [-5.5541, 1.6872, -4.1620] ]) + Bref = np.array([ [-0.2000, -1.2500], + [ 0.0000, -0.6097], -+ [ 0.0000, 2.2217] ]) ++ [ 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] ++ 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) ++ 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 +196,5 @@ class TestTf2SS(unittest.TestCase): +- ++ + # 2 inputs, 3 outputs? columns share a denominator + num = np.array([ [ [1.0], [2.0] ], + [ [0.2], [4.3] ], +@@ -71,12 +121,12 @@ class TestTf2SS(unittest.TestCase): + p, m, d = num.shape + numc = np.zeros((max(1, m, p), max(1, m, p), d), dtype=float) + numc[:p,:m,:] = num +- ++ + # denc, columns share a common denominator + denc = np.array([ [ 1.0], [0.5] ]) + Dc = (num / denc).reshape((3,2)) + idxc = np.zeros((2,), dtype=int) +- ++ + # denr, rows share a common denominator + denr = np.array([ [1.0], [0.5], [3.0] ]) + idxr = np.zeros((3,), dtype=int) +@@ -84,21 +134,45 @@ class TestTf2SS(unittest.TestCase): + + # fails with: + # On entry to TB01XD parameter number 5 had an illegal value +- ++ + n, A, B, C, D = transform.td04ad('C', 2, 3, idxc, denc, numc) + #print('A=\n', A, '\nB=\n', B, '\nC=\n', C, '\nD=\n', D) + self.assertEqual(A.shape, (0,0)) + self.assertEqual(B.shape, (0,2)) + self.assertEqual(C.shape, (3,0)) + np.testing.assert_array_almost_equal(D, Dc) +- ++ + n, A, B, C, D = transform.td04ad('R', 2, 3, idxr, denr, num) + #print('A=\n', A, '\nB=\n', B, '\nC=\n', C, '\nD=\n', D) + self.assertEqual(A.shape, (0,0)) + self.assertEqual(B.shape, (0,2)) + self.assertEqual(C.shape, (3,0)) + np.testing.assert_array_almost_equal(D, Dr) +- ++ ++ def test_td04ad_static(self): ++ """Regression: td04ad (TFM -> SS transformation) for static TFM""" ++ from itertools import product ++ for nout, nin, rc in product(range(1, 6), range(1, 6), ['R', 'C']): ++ Dref = np.zeros((nout, nin)) ++ if rc == 'R': ++ num = np.reshape(np.arange(nout * nin), (nout, nin, 1)) ++ den = np.reshape(np.arange(1, 1 + nout), (nout, 1)) ++ index = np.repeat(0, nout) ++ Dref = num[:nout, :nin, 0] / np.broadcast_to(den, (nout, nin)) ++ else: ++ maxn = max(nout, nin) ++ num = np.zeros((maxn, maxn, 1)) ++ num[:nout, :nin, 0] = np.reshape( ++ np.arange(nout * nin), (nout, nin)) ++ den = np.reshape(np.arange(1, 1 + nin), (nin, 1)) ++ index = np.repeat(0, nin) ++ Dref = num[:nout, :nin, 0] / np.broadcast_to(den.T, (nout, nin)) ++ nr, A, B, C, D = transform.td04ad(rc, nin, nout, index, den, num) ++ np.testing.assert_equal(nr, 0) ++ for M in [A, B, C]: ++ np.testing.assert_equal(M, np.zeros_like(M)) ++ np.testing.assert_almost_equal(D, Dref) ++ + + def test_mixfeedthrough(self): + """Test case popping up from control testing""" +@@ -113,7 +187,7 @@ class TestTf2SS(unittest.TestCase): + idxc = np.array([ 1, 0 ]) + n, A, B, C, D = transform.td04ad('C', 2, 2, idxc, denc, numc) + np.testing.assert_array_almost_equal(D, np.array([[0, 0],[-0.1, 0]])) +- ++ + def test_toandfrom(self): + + A = np.array([[-3.0]]) +@@ -131,7 +205,7 @@ class TestTf2SS(unittest.TestCase): + np.testing.assert_array_almost_equal(A, At) + + def test_tfm2ss_6(self): +- """Python version of Fortran test program from ++ """Python version of Fortran test program from + -- Bug in TD04AD when ROWCOL='C' #6 + This bug was fixed in PR #27""" + m = 1 +@@ -145,10 +219,6 @@ class TestTf2SS(unittest.TestCase): + n, A, B, C, D = transform.td04ad('C', m, p, index, dcoeff, ucoeff) 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 +index 77b3171..f79e0ca 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): @@ -173,9 +284,12 @@ index 77b3171..52b3a7b 100644 ucoeff : rank-3 array, shape (p,m,max(index)+1) array of numerator coefficients -@@ -578,7 +578,7 @@ def tb05ad(n, m, p, jomega, A, B, C, job='NG'): +@@ -576,9 +576,9 @@ def tb05ad(n, m, p, jomega, A, B, C, job='NG'): + + 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]) +- """ nr,A,B,C,D = td04ad(m,p,index,dcoeff,ucoeff,[tol,ldwork]) ++ """ nr,A,B,C,D = td04ad(rowcol,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 @@ -196,6 +310,3 @@ index 77b3171..52b3a7b 100644 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 --- -2.24.0 - diff --git a/python-slycot.changes b/python-slycot.changes index 47f41f2..072500e 100644 --- a/python-slycot.changes +++ b/python-slycot.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Fri Nov 8 13:30:41 UTC 2019 - Benjamin Greiner + +- fix td04ad ans sg03ad unittests to pass on all architectures + ------------------------------------------------------------------- Sun Sep 22 16:42:44 UTC 2019 - Benjamin Greiner diff --git a/python-slycot.spec b/python-slycot.spec index 81bbb0a..0112718 100644 --- a/python-slycot.spec +++ b/python-slycot.spec @@ -25,7 +25,8 @@ 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: 0001-enhance-test_td04ad.patch +Patch0: fix-test-td04ad.patch +Patch1: fix-test-sg03ad.patch BuildRequires: %{python_module coverage} BuildRequires: %{python_module devel} BuildRequires: %{python_module nose} @@ -51,6 +52,7 @@ Slycot is a wrapper for the SLICOT control and systems library. %prep %setup -q -n slycot-%{version} %patch0 -p1 +%patch1 -p1 %build export CFLAGS="%{optflags}" From 0708d757e0d9b09b6e3bbc7bd1fb8bf9706e05e17beaf63d0b9657c2486572fd Mon Sep 17 00:00:00 2001 From: Benjamin Greiner Date: Fri, 8 Nov 2019 15:32:06 +0000 Subject: [PATCH 5/5] mention the patches so the bot is satisified OBS-URL: https://build.opensuse.org/package/show/devel:languages:python:numeric/python-slycot?expand=0&rev=12 --- python-slycot.changes | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python-slycot.changes b/python-slycot.changes index 072500e..87721a5 100644 --- a/python-slycot.changes +++ b/python-slycot.changes @@ -1,7 +1,9 @@ ------------------------------------------------------------------- Fri Nov 8 13:30:41 UTC 2019 - Benjamin Greiner -- fix td04ad ans sg03ad unittests to pass on all architectures +- fix unittests to pass on all architectures + * fix-test-sg03ad.patch see upstream PR#82 + * fix-test-td04ad.patch see upstream PR#83 ------------------------------------------------------------------- Sun Sep 22 16:42:44 UTC 2019 - Benjamin Greiner