update _ssmatrix and _check_shape for consistent usage · python-control/python-control@4fc70f7
@@ -44,7 +44,6 @@
44444545from .exception import ControlSlycot, ControlArgument, ControlDimension, \
4646slycot_check
47-from .statesp import _ssmatrix
48474948# Make sure we have access to the right slycot routines
5049try:
@@ -151,12 +150,12 @@ def lyap(A, Q, C=None, E=None, method=None):
151150m = Q.shape[0]
152151153152# Check to make sure input matrices are the right shape and type
154-_check_shape("A", A, n, n, square=True)
153+_check_shape(A, n, n, square=True, name="A")
155154156155# Solve standard Lyapunov equation
157156if C is None and E is None:
158157# Check to make sure input matrices are the right shape and type
159-_check_shape("Q", Q, n, n, square=True, symmetric=True)
158+_check_shape(Q, n, n, square=True, symmetric=True, name="Q")
160159161160if method == 'scipy':
162161# Solve the Lyapunov equation using SciPy
@@ -171,8 +170,8 @@ def lyap(A, Q, C=None, E=None, method=None):
171170# Solve the Sylvester equation
172171elif C is not None and E is None:
173172# Check to make sure input matrices are the right shape and type
174-_check_shape("Q", Q, m, m, square=True)
175-_check_shape("C", C, n, m)
173+_check_shape(Q, m, m, square=True, name="Q")
174+_check_shape(C, n, m, name="C")
176175177176if method == 'scipy':
178177# Solve the Sylvester equation using SciPy
@@ -184,8 +183,8 @@ def lyap(A, Q, C=None, E=None, method=None):
184183# Solve the generalized Lyapunov equation
185184elif C is None and E is not None:
186185# Check to make sure input matrices are the right shape and type
187-_check_shape("Q", Q, n, n, square=True, symmetric=True)
188-_check_shape("E", E, n, n, square=True)
186+_check_shape(Q, n, n, square=True, symmetric=True, name="Q")
187+_check_shape(E, n, n, square=True, name="E")
189188190189if method == 'scipy':
191190raise ControlArgument(
@@ -210,7 +209,7 @@ def lyap(A, Q, C=None, E=None, method=None):
210209else:
211210raise ControlArgument("Invalid set of input parameters")
212211213-return _ssmatrix(X)
212+return X
214213215214216215def dlyap(A, Q, C=None, E=None, method=None):
@@ -281,12 +280,12 @@ def dlyap(A, Q, C=None, E=None, method=None):
281280m = Q.shape[0]
282281283282# Check to make sure input matrices are the right shape and type
284-_check_shape("A", A, n, n, square=True)
283+_check_shape(A, n, n, square=True, name="A")
285284286285# Solve standard Lyapunov equation
287286if C is None and E is None:
288287# Check to make sure input matrices are the right shape and type
289-_check_shape("Q", Q, n, n, square=True, symmetric=True)
288+_check_shape(Q, n, n, square=True, symmetric=True, name="Q")
290289291290if method == 'scipy':
292291# Solve the Lyapunov equation using SciPy
@@ -301,8 +300,8 @@ def dlyap(A, Q, C=None, E=None, method=None):
301300# Solve the Sylvester equation
302301elif C is not None and E is None:
303302# Check to make sure input matrices are the right shape and type
304-_check_shape("Q", Q, m, m, square=True)
305-_check_shape("C", C, n, m)
303+_check_shape(Q, m, m, square=True, name="Q")
304+_check_shape(C, n, m, name="C")
306305307306if method == 'scipy':
308307raise ControlArgument(
@@ -314,8 +313,8 @@ def dlyap(A, Q, C=None, E=None, method=None):
314313# Solve the generalized Lyapunov equation
315314elif C is None and E is not None:
316315# Check to make sure input matrices are the right shape and type
317-_check_shape("Q", Q, n, n, square=True, symmetric=True)
318-_check_shape("E", E, n, n, square=True)
316+_check_shape(Q, n, n, square=True, symmetric=True, name="Q")
317+_check_shape(E, n, n, square=True, name="E")
319318320319if method == 'scipy':
321320raise ControlArgument(
@@ -333,7 +332,7 @@ def dlyap(A, Q, C=None, E=None, method=None):
333332else:
334333raise ControlArgument("Invalid set of input parameters")
335334336-return _ssmatrix(X)
335+return X
337336338337339338#
@@ -407,10 +406,10 @@ def care(A, B, Q, R=None, S=None, E=None, stabilizing=True, method=None,
407406m = B.shape[1]
408407409408# Check to make sure input matrices are the right shape and type
410-_check_shape(_As, A, n, n, square=True)
411-_check_shape(_Bs, B, n, m)
412-_check_shape(_Qs, Q, n, n, square=True, symmetric=True)
413-_check_shape(_Rs, R, m, m, square=True, symmetric=True)
409+_check_shape(A, n, n, square=True, name=_As)
410+_check_shape(B, n, m, name=_Bs)
411+_check_shape(Q, n, n, square=True, symmetric=True, name=_Qs)
412+_check_shape(R, m, m, square=True, symmetric=True, name=_Rs)
414413415414# Solve the standard algebraic Riccati equation
416415if S is None and E is None:
@@ -423,7 +422,7 @@ def care(A, B, Q, R=None, S=None, E=None, stabilizing=True, method=None,
423422X = sp.linalg.solve_continuous_are(A, B, Q, R)
424423K = np.linalg.solve(R, B.T @ X)
425424E, _ = np.linalg.eig(A - B @ K)
426-return _ssmatrix(X), E, _ssmatrix(K)
425+return X, E, K
427426428427# Make sure we can import required slycot routines
429428try:
@@ -448,7 +447,7 @@ def care(A, B, Q, R=None, S=None, E=None, stabilizing=True, method=None,
448447449448# Return the solution X, the closed-loop eigenvalues L and
450449# the gain matrix G
451-return _ssmatrix(X), w[:n], _ssmatrix(G)
450+return X, w[:n], G
452451453452# Solve the generalized algebraic Riccati equation
454453else:
@@ -457,8 +456,8 @@ def care(A, B, Q, R=None, S=None, E=None, stabilizing=True, method=None,
457456E = np.eye(A.shape[0]) if E is None else np.array(E, ndmin=2)
458457459458# Check to make sure input matrices are the right shape and type
460-_check_shape(_Es, E, n, n, square=True)
461-_check_shape(_Ss, S, n, m)
459+_check_shape(E, n, n, square=True, name=_Es)
460+_check_shape(S, n, m, name=_Ss)
462461463462# See if we should solve this using SciPy
464463if method == 'scipy':
@@ -469,7 +468,7 @@ def care(A, B, Q, R=None, S=None, E=None, stabilizing=True, method=None,
469468X = sp.linalg.solve_continuous_are(A, B, Q, R, s=S, e=E)
470469K = np.linalg.solve(R, B.T @ X @ E + S.T)
471470eigs, _ = sp.linalg.eig(A - B @ K, E)
472-return _ssmatrix(X), eigs, _ssmatrix(K)
471+return X, eigs, K
473472474473# Make sure we can find the required slycot routine
475474try:
@@ -494,7 +493,7 @@ def care(A, B, Q, R=None, S=None, E=None, stabilizing=True, method=None,
494493495494# Return the solution X, the closed-loop eigenvalues L and
496495# the gain matrix G
497-return _ssmatrix(X), L, _ssmatrix(G)
496+return X, L, G
498497499498def dare(A, B, Q, R, S=None, E=None, stabilizing=True, method=None,
500499_As="A", _Bs="B", _Qs="Q", _Rs="R", _Ss="S", _Es="E"):
@@ -564,14 +563,14 @@ def dare(A, B, Q, R, S=None, E=None, stabilizing=True, method=None,
564563m = B.shape[1]
565564566565# Check to make sure input matrices are the right shape and type
567-_check_shape(_As, A, n, n, square=True)
568-_check_shape(_Bs, B, n, m)
569-_check_shape(_Qs, Q, n, n, square=True, symmetric=True)
570-_check_shape(_Rs, R, m, m, square=True, symmetric=True)
566+_check_shape(A, n, n, square=True, name=_As)
567+_check_shape(B, n, m, name=_Bs)
568+_check_shape(Q, n, n, square=True, symmetric=True, name=_Qs)
569+_check_shape(R, m, m, square=True, symmetric=True, name=_Rs)
571570if E is not None:
572-_check_shape(_Es, E, n, n, square=True)
571+_check_shape(E, n, n, square=True, name=_Es)
573572if S is not None:
574-_check_shape(_Ss, S, n, m)
573+_check_shape(S, n, m, name=_Ss)
575574576575# Figure out how to solve the problem
577576if method == 'scipy':
@@ -589,7 +588,7 @@ def dare(A, B, Q, R, S=None, E=None, stabilizing=True, method=None,
589588else:
590589L, _ = sp.linalg.eig(A - B @ G, E)
591590592-return _ssmatrix(X), L, _ssmatrix(G)
591+return X, L, G
593592594593# Make sure we can import required slycot routine
595594try:
@@ -618,7 +617,7 @@ def dare(A, B, Q, R, S=None, E=None, stabilizing=True, method=None,
618617619618# Return the solution X, the closed-loop eigenvalues L and
620619# the gain matrix G
621-return _ssmatrix(X), L, _ssmatrix(G)
620+return X, L, G
622621623622624623# Utility function to decide on method to use
@@ -632,15 +631,17 @@ def _slycot_or_scipy(method):
632631633632634633# Utility function to check matrix dimensions
635-def _check_shape(name, M, n, m, square=False, symmetric=False):
634+def _check_shape(M, n, m, square=False, symmetric=False, name="??"):
636635if square and M.shape[0] != M.shape[1]:
637636raise ControlDimension("%s must be a square matrix" % name)
638637639638if symmetric and not _is_symmetric(M):
640639raise ControlArgument("%s must be a symmetric matrix" % name)
641640642641if M.shape[0] != n or M.shape[1] != m:
643-raise ControlDimension("Incompatible dimensions of %s matrix" % name)
642+raise ControlDimension(
643+f"Incompatible dimensions of {name} matrix; "
644+f"expected ({n}, {m}) but found {M.shape}")
644645645646646647# Utility function to check if a matrix is symmetric