3939import pytest
4040from scipy .linalg import eigvals , solve
4141
42- import control as ct
4342from control .mateqn import lyap , dlyap , care , dare
44- from control .exception import ControlArgument , ControlDimension , slycot_check
43+ from control .exception import ControlArgument , ControlDimension
4544
4645
4746class TestMatrixEquations :
4847 """These are tests for the matrix equation solvers in mateqn.py"""
4948
50- def test_lyap (self ):
49+ @pytest .mark .parametrize ('method' ,
50+ ['scipy' ,
51+ pytest .param ('slycot' , marks = pytest .mark .slycot )])
52+ def test_lyap (self , method ):
5153 A = array ([[- 1 , 1 ], [- 1 , 0 ]])
5254 Q = array ([[1 , 0 ], [0 , 1 ]])
53- X = lyap (A , Q )
55+ X = lyap (A , Q , method = method )
5456 # print("The solution obtained is ", X)
5557 assert_array_almost_equal (A @ X + X @ A .T + Q , zeros ((2 ,2 )))
5658
5759 A = array ([[1 , 2 ], [- 3 , - 4 ]])
5860 Q = array ([[3 , 1 ], [1 , 1 ]])
59- X = lyap (A ,Q )
61+ X = lyap (A ,Q , method = method )
6062 # print("The solution obtained is ", X)
6163 assert_array_almost_equal (A @ X + X @ A .T + Q , zeros ((2 ,2 )))
6264
6365 # Compare methods
64- if slycot_check () :
66+ if method == 'slycot' :
6567 X_scipy = lyap (A , Q , method = 'scipy' )
66- X_slycot = lyap (A , Q , method = 'slycot' )
67- assert_array_almost_equal (X_scipy , X_slycot )
68+ assert_array_almost_equal (X_scipy , X )
6869
69- def test_lyap_sylvester (self ):
70+ @pytest .mark .parametrize ('method' ,
71+ ['scipy' ,
72+ pytest .param ('slycot' , marks = pytest .mark .slycot )])
73+ def test_lyap_sylvester (self , method ):
7074 A = 5
7175 B = array ([[4 , 3 ], [4 , 3 ]])
7276 C = array ([2 , 1 ])
73- X = lyap (A , B , C )
77+ X = lyap (A , B , C , method = method )
7478 # print("The solution obtained is ", X)
7579 assert_array_almost_equal (A * X + X @ B + C , zeros ((1 ,2 )))
7680
7781 A = array ([[2 , 1 ], [1 , 2 ]])
7882 B = array ([[1 , 2 ], [0.5 , 0.1 ]])
7983 C = array ([[1 , 0 ], [0 , 1 ]])
80- X = lyap (A , B , C )
84+ X = lyap (A , B , C , method = method )
8185 # print("The solution obtained is ", X)
8286 assert_array_almost_equal (A @ X + X @ B + C , zeros ((2 ,2 )))
8387
8488 # Compare methods
85- if slycot_check () :
89+ if method == 'slycot' :
8690 X_scipy = lyap (A , B , C , method = 'scipy' )
87- X_slycot = lyap (A , B , C , method = 'slycot' )
88- assert_array_almost_equal (X_scipy , X_slycot )
91+ assert_array_almost_equal (X_scipy , X )
8992
9093 @pytest .mark .slycot
9194 def test_lyap_g (self ):
@@ -101,19 +104,27 @@ def test_lyap_g(self):
101104 with pytest .raises (ControlArgument , match = "'scipy' not valid" ):
102105 X = lyap (A , Q , None , E , method = 'scipy' )
103106
104- def test_dlyap (self ):
107+ @pytest .mark .parametrize ('method' ,
108+ ['scipy' ,
109+ pytest .param ('slycot' , marks = pytest .mark .slycot )])
110+ def test_dlyap (self , method ):
105111 A = array ([[- 0.6 , 0 ],[- 0.1 , - 0.4 ]])
106112 Q = array ([[1 ,0 ],[0 ,1 ]])
107- X = dlyap (A ,Q )
113+ X = dlyap (A ,Q , method = method )
108114 # print("The solution obtained is ", X)
109115 assert_array_almost_equal (A @ X @ A .T - X + Q , zeros ((2 ,2 )))
110116
111117 A = array ([[- 0.6 , 0 ],[- 0.1 , - 0.4 ]])
112118 Q = array ([[3 , 1 ],[1 , 1 ]])
113- X = dlyap (A ,Q )
119+ X = dlyap (A ,Q , method = method )
114120 # print("The solution obtained is ", X)
115121 assert_array_almost_equal (A @ X @ A .T - X + Q , zeros ((2 ,2 )))
116122
123+ # Compare methods
124+ if method == 'slycot' :
125+ X_scipy = dlyap (A ,Q , method = 'scipy' )
126+ assert_array_almost_equal (X_scipy , X )
127+
117128 @pytest .mark .slycot
118129 def test_dlyap_g (self ):
119130 A = array ([[- 0.6 , 0 ],[- 0.1 , - 0.4 ]])
@@ -148,35 +159,40 @@ def test_dlyap_sylvester(self):
148159 with pytest .raises (ControlArgument , match = "'scipy' not valid" ):
149160 X = dlyap (A , B , C , method = 'scipy' )
150161
151- def test_care (self ):
162+ @pytest .mark .parametrize ('method' ,
163+ ['scipy' ,
164+ pytest .param ('slycot' , marks = pytest .mark .slycot )])
165+ def test_care (self , method ):
152166 A = array ([[- 2 , - 1 ],[- 1 , - 1 ]])
153167 Q = array ([[0 , 0 ],[0 , 1 ]])
154168 B = array ([[1 , 0 ],[0 , 4 ]])
155169
156- X , L , G = care (A , B , Q )
170+ X , L , G = care (A , B , Q , method = method )
157171 # print("The solution obtained is", X)
158172 M = A .T @ X + X @ A - X @ B @ B .T @ X + Q
159173 assert_array_almost_equal (M ,
160174 zeros ((2 ,2 )))
161175 assert_array_almost_equal (B .T @ X , G )
162176
163177 # Compare methods
164- if slycot_check () :
178+ if method == 'slycot' :
165179 X_scipy , L_scipy , G_scipy = care (A , B , Q , method = 'scipy' )
166- X_slycot , L_slycot , G_slycot = care (A , B , Q , method = 'slycot' )
167- assert_array_almost_equal (X_scipy , X_slycot )
168- assert_array_almost_equal (np .sort (L_scipy ), np .sort (L_slycot ))
169- assert_array_almost_equal (G_scipy , G_slycot )
170-
171- def test_care_g (self ):
180+ assert_array_almost_equal (X_scipy , X )
181+ assert_array_almost_equal (np .sort (L_scipy ), np .sort (L ))
182+ assert_array_almost_equal (G_scipy , G )
183+
184+ @pytest .mark .parametrize ('method' ,
185+ ['scipy' ,
186+ pytest .param ('slycot' , marks = pytest .mark .slycot )])
187+ def test_care_g (self , method ):
172188 A = array ([[- 2 , - 1 ],[- 1 , - 1 ]])
173189 Q = array ([[0 , 0 ],[0 , 1 ]])
174190 B = array ([[1 , 0 ],[0 , 4 ]])
175191 R = array ([[2 , 0 ],[0 , 1 ]])
176192 S = array ([[0 , 0 ],[0 , 0 ]])
177193 E = array ([[2 , 1 ],[1 , 2 ]])
178194
179- X ,L ,G = care (A ,B ,Q ,R ,S ,E )
195+ X ,L ,G = care (A ,B ,Q ,R ,S ,E , method = method )
180196 # print("The solution obtained is", X)
181197 Gref = solve (R , B .T @ X @ E + S .T )
182198 assert_array_almost_equal (Gref , G )
@@ -186,24 +202,25 @@ def test_care_g(self):
186202 zeros ((2 ,2 )))
187203
188204 # Compare methods
189- if slycot_check () :
205+ if method == 'slycot' :
190206 X_scipy , L_scipy , G_scipy = care (
191207 A , B , Q , R , S , E , method = 'scipy' )
192- X_slycot , L_slycot , G_slycot = care (
193- A , B , Q , R , S , E , method = 'slycot' )
194- assert_array_almost_equal (X_scipy , X_slycot )
195- assert_array_almost_equal (np .sort (L_scipy ), np .sort (L_slycot ))
196- assert_array_almost_equal (G_scipy , G_slycot )
197-
198- def test_care_g2 (self ):
208+ assert_array_almost_equal (X_scipy , X )
209+ assert_array_almost_equal (np .sort (L_scipy ), np .sort (L ))
210+ assert_array_almost_equal (G_scipy , G )
211+
212+ @pytest .mark .parametrize ('method' ,
213+ ['scipy' ,
214+ pytest .param ('slycot' , marks = pytest .mark .slycot )])
215+ def test_care_g2 (self , method ):
199216 A = array ([[- 2 , - 1 ],[- 1 , - 1 ]])
200217 Q = array ([[0 , 0 ],[0 , 1 ]])
201218 B = array ([[1 ],[0 ]])
202219 R = 1
203220 S = array ([[1 ],[0 ]])
204221 E = array ([[2 , 1 ],[1 , 2 ]])
205222
206- X ,L ,G = care (A ,B ,Q ,R ,S ,E )
223+ X ,L ,G = care (A ,B ,Q ,R ,S ,E , method = method )
207224 # print("The solution obtained is", X)
208225 Gref = 1 / R * (B .T @ X @ E + S .T )
209226 assert_array_almost_equal (
@@ -213,22 +230,23 @@ def test_care_g2(self):
213230 assert_array_almost_equal (Gref , G )
214231
215232 # Compare methods
216- if slycot_check () :
233+ if method == 'slycot' :
217234 X_scipy , L_scipy , G_scipy = care (
218235 A , B , Q , R , S , E , method = 'scipy' )
219- X_slycot , L_slycot , G_slycot = care (
220- A , B , Q , R , S , E , method = 'slycot' )
221- assert_array_almost_equal (X_scipy , X_slycot )
222- assert_array_almost_equal (L_scipy , L_slycot )
223- assert_array_almost_equal (G_scipy , G_slycot )
224-
225- def test_dare (self ):
236+ assert_array_almost_equal (X_scipy , X )
237+ assert_array_almost_equal (L_scipy , L )
238+ assert_array_almost_equal (G_scipy , G )
239+
240+ @pytest .mark .parametrize ('method' ,
241+ ['scipy' ,
242+ pytest .param ('slycot' , marks = pytest .mark .slycot )])
243+ def test_dare (self , method ):
226244 A = array ([[- 0.6 , 0 ],[- 0.1 , - 0.4 ]])
227245 Q = array ([[2 , 1 ],[1 , 0 ]])
228246 B = array ([[2 , 1 ],[0 , 1 ]])
229247 R = array ([[1 , 0 ],[0 , 1 ]])
230248
231- X , L , G = dare (A , B , Q , R )
249+ X , L , G = dare (A , B , Q , R , method = method )
232250 # print("The solution obtained is", X)
233251 Gref = solve (B .T @ X @ B + R , B .T @ X @ A )
234252 assert_array_almost_equal (Gref , G )
@@ -243,7 +261,7 @@ def test_dare(self):
243261 B = array ([[1 ],[0 ]])
244262 R = 2
245263
246- X , L , G = dare (A , B , Q , R )
264+ X , L , G = dare (A , B , Q , R , method = method )
247265 # print("The solution obtained is", X)
248266 AtXA = A .T @ X @ A
249267 AtXB = A .T @ X @ B
@@ -256,6 +274,7 @@ def test_dare(self):
256274 lam = eigvals (A - B @ G )
257275 assert_array_less (abs (lam ), 1.0 )
258276
277+ @pytest .mark .slycot
259278 def test_dare_compare (self ):
260279 A = np .array ([[- 0.6 , 0 ], [- 0.1 , - 0.4 ]])
261280 Q = np .array ([[2 , 1 ], [1 , 0 ]])
@@ -267,23 +286,24 @@ def test_dare_compare(self):
267286 # Solve via scipy
268287 X_scipy , L_scipy , G_scipy = dare (A , B , Q , R , method = 'scipy' )
269288
270- # Solve via slycot
271- if ct .slycot_check ():
272- X_slicot , L_slicot , G_slicot = dare (
273- A , B , Q , R , S , E , method = 'scipy' )
274- np .testing .assert_almost_equal (X_scipy , X_slicot )
275- np .testing .assert_almost_equal (L_scipy , L_slicot )
276- np .testing .assert_almost_equal (G_scipy , G_slicot )
289+ X_slicot , L_slicot , G_slicot = dare (
290+ A , B , Q , R , S , E , method = 'scipy' )
291+ np .testing .assert_almost_equal (X_scipy , X_slicot )
292+ np .testing .assert_almost_equal (L_scipy , L_slicot )
293+ np .testing .assert_almost_equal (G_scipy , G_slicot )
277294
278- def test_dare_g (self ):
295+ @pytest .mark .parametrize ('method' ,
296+ ['scipy' ,
297+ pytest .param ('slycot' , marks = pytest .mark .slycot )])
298+ def test_dare_g (self , method ):
279299 A = array ([[- 0.6 , 0 ],[- 0.1 , - 0.4 ]])
280300 Q = array ([[2 , 1 ],[1 , 3 ]])
281301 B = array ([[1 , 5 ],[2 , 4 ]])
282302 R = array ([[1 , 0 ],[0 , 1 ]])
283303 S = array ([[1 , 0 ],[2 , 0 ]])
284304 E = array ([[2 , 1 ],[1 , 2 ]])
285305
286- X , L , G = dare (A , B , Q , R , S , E )
306+ X , L , G = dare (A , B , Q , R , S , E , method = method )
287307 # print("The solution obtained is", X)
288308 Gref = solve (B .T @ X @ B + R , B .T @ X @ A + S .T )
289309 assert_array_almost_equal (Gref , G )
@@ -293,16 +313,26 @@ def test_dare_g(self):
293313 # check for stable closed loop
294314 lam = eigvals (A - B @ G , E )
295315 assert_array_less (abs (lam ), 1.0 )
296-
297- def test_dare_g2 (self ):
316+ # Compare methods
317+ if method == 'slycot' :
318+ X_scipy , L_scipy , G_scipy = dare (
319+ A , B , Q , R , S , E , method = 'scipy' )
320+ assert_array_almost_equal (X_scipy , X )
321+ assert_array_almost_equal (L_scipy , L )
322+ assert_array_almost_equal (G_scipy , G )
323+
324+ @pytest .mark .parametrize ('method' ,
325+ ['scipy' ,
326+ pytest .param ('slycot' , marks = pytest .mark .slycot )])
327+ def test_dare_g2 (self , method ):
298328 A = array ([[- 0.6 , 0 ], [- 0.1 , - 0.4 ]])
299329 Q = array ([[2 , 1 ], [1 , 3 ]])
300330 B = array ([[1 ], [2 ]])
301331 R = 1
302332 S = array ([[1 ], [2 ]])
303333 E = array ([[2 , 1 ], [1 , 2 ]])
304334
305- X , L , G = dare (A , B , Q , R , S , E )
335+ X , L , G = dare (A , B , Q , R , S , E , method = method )
306336 # print("The solution obtained is", X)
307337 AtXA = A .T @ X @ A
308338 AtXB = A .T @ X @ B
@@ -316,6 +346,13 @@ def test_dare_g2(self):
316346 lam = eigvals (A - B @ G , E )
317347 assert_array_less (abs (lam ), 1.0 )
318348
349+ if method == 'slycot' :
350+ X_scipy , L_scipy , G_scipy = dare (
351+ A , B , Q , R , S , E , method = 'scipy' )
352+ assert_array_almost_equal (X_scipy , X )
353+ assert_array_almost_equal (L_scipy , L )
354+ assert_array_almost_equal (G_scipy , G )
355+
319356 def test_raise (self ):
320357 """ Test exception raise for invalid inputs """
321358
0 commit comments