update _ssmatrix and _check_shape for consistent usage · python-control/python-control@4fc70f7

@@ -44,7 +44,6 @@

44444545

from .exception import ControlSlycot, ControlArgument, ControlDimension, \

4646

slycot_check

47-

from .statesp import _ssmatrix

48474948

# Make sure we have access to the right slycot routines

5049

try:

@@ -151,12 +150,12 @@ def lyap(A, Q, C=None, E=None, method=None):

151150

m = 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

157156

if 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")

160159161160

if 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

172171

elif 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")

176175177176

if 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

185184

elif 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")

189188190189

if method == 'scipy':

191190

raise ControlArgument(

@@ -210,7 +209,7 @@ def lyap(A, Q, C=None, E=None, method=None):

210209

else:

211210

raise ControlArgument("Invalid set of input parameters")

212211213-

return _ssmatrix(X)

212+

return X

214213215214216215

def dlyap(A, Q, C=None, E=None, method=None):

@@ -281,12 +280,12 @@ def dlyap(A, Q, C=None, E=None, method=None):

281280

m = 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

287286

if 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")

290289291290

if 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

302301

elif 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")

306305307306

if method == 'scipy':

308307

raise ControlArgument(

@@ -314,8 +313,8 @@ def dlyap(A, Q, C=None, E=None, method=None):

314313

# Solve the generalized Lyapunov equation

315314

elif 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")

319318320319

if method == 'scipy':

321320

raise ControlArgument(

@@ -333,7 +332,7 @@ def dlyap(A, Q, C=None, E=None, method=None):

333332

else:

334333

raise 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,

407406

m = 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

416415

if 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,

423422

X = sp.linalg.solve_continuous_are(A, B, Q, R)

424423

K = np.linalg.solve(R, B.T @ X)

425424

E, _ = 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

429428

try:

@@ -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

454453

else:

@@ -457,8 +456,8 @@ def care(A, B, Q, R=None, S=None, E=None, stabilizing=True, method=None,

457456

E = 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

464463

if method == 'scipy':

@@ -469,7 +468,7 @@ def care(A, B, Q, R=None, S=None, E=None, stabilizing=True, method=None,

469468

X = sp.linalg.solve_continuous_are(A, B, Q, R, s=S, e=E)

470469

K = np.linalg.solve(R, B.T @ X @ E + S.T)

471470

eigs, _ = 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

475474

try:

@@ -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

498497499498

def 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,

564563

m = 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)

571570

if E is not None:

572-

_check_shape(_Es, E, n, n, square=True)

571+

_check_shape(E, n, n, square=True, name=_Es)

573572

if 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

577576

if method == 'scipy':

@@ -589,7 +588,7 @@ def dare(A, B, Q, R, S=None, E=None, stabilizing=True, method=None,

589588

else:

590589

L, _ = 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

595594

try:

@@ -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="??"):

636635

if square and M.shape[0] != M.shape[1]:

637636

raise ControlDimension("%s must be a square matrix" % name)

638637639638

if symmetric and not _is_symmetric(M):

640639

raise ControlArgument("%s must be a symmetric matrix" % name)

641640642641

if 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