Skip to content

Commit 19cc79a

Browse files
committed
replace np.dot with @ matmul operator where applicable
1 parent 12f9014 commit 19cc79a

File tree

10 files changed

+72
-89
lines changed

10 files changed

+72
-89
lines changed

control/flatsys/flatsys.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -462,8 +462,7 @@ def traj_const(null_coeffs):
462462
for type, fun, lb, ub in traj_constraints:
463463
if type == sp.optimize.LinearConstraint:
464464
# `fun` is A matrix associated with polytope...
465-
values.append(
466-
np.dot(fun, np.hstack([states, inputs])))
465+
values.append(fun @ np.hstack([states, inputs]))
467466
elif type == sp.optimize.NonlinearConstraint:
468467
values.append(fun(states, inputs))
469468
else:

control/flatsys/linflat.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ def __init__(self, linsys, inputs=None, outputs=None, states=None,
110110

111111
# Compute the flat output variable z = C x
112112
Cfz = np.zeros(np.shape(linsys.C)); Cfz[0, 0] = 1
113-
self.Cf = np.dot(Cfz, Tr)
113+
self.Cf = Cfz @ Tr
114114

115115
# Compute the flat flag from the state (and input)
116116
def forward(self, x, u):
@@ -122,11 +122,11 @@ def forward(self, x, u):
122122
x = np.reshape(x, (-1, 1))
123123
u = np.reshape(u, (1, -1))
124124
zflag = [np.zeros(self.nstates + 1)]
125-
zflag[0][0] = np.dot(self.Cf, x)
125+
zflag[0][0] = self.Cf @ x
126126
H = self.Cf # initial state transformation
127127
for i in range(1, self.nstates + 1):
128-
zflag[0][i] = np.dot(H, np.dot(self.A, x) + np.dot(self.B, u))
129-
H = np.dot(H, self.A) # derivative for next iteration
128+
zflag[0][i] = H @ (self.A @ x + self.B @ u)
129+
H = H @ self.A # derivative for next iteration
130130
return zflag
131131

132132
# Compute state and input from flat flag
@@ -137,6 +137,6 @@ def reverse(self, zflag):
137137
138138
"""
139139
z = zflag[0][0:-1]
140-
x = np.dot(self.Tinv, z)
141-
u = zflag[0][-1] - np.dot(self.F, z)
140+
x = self.Tinv @ z
141+
u = zflag[0][-1] - self.F @ z
142142
return np.reshape(x, self.nstates), np.reshape(u, self.ninputs)

control/frdata.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -542,13 +542,9 @@ def feedback(self, other=1, sign=-1):
542542
# TODO: is there a reason to use linalg.solve instead of linalg.inv?
543543
# https://github.com/python-control/python-control/pull/314#discussion_r294075154
544544
for k, w in enumerate(other.omega):
545-
fresp[:, :, k] = np.dot(
546-
self.fresp[:, :, k],
547-
linalg.solve(
548-
eye(self.ninputs)
549-
+ np.dot(other.fresp[:, :, k], self.fresp[:, :, k]),
550-
eye(self.ninputs))
551-
)
545+
fresp[:, :, k] = self.fresp[:, :, k] @ linalg.solve(
546+
eye(self.ninputs) + other.fresp[:, :, k] @ self.fresp[:, :, k],
547+
eye(self.ninputs))
552548

553549
return FRD(fresp, other.omega, smooth=(self.ifunc is not None))
554550

control/iosys.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -843,14 +843,14 @@ def _update_params(self, params={}, warning=True):
843843

844844
def _rhs(self, t, x, u):
845845
# Convert input to column vector and then change output to 1D array
846-
xdot = np.dot(self.A, np.reshape(x, (-1, 1))) \
847-
+ np.dot(self.B, np.reshape(u, (-1, 1)))
846+
xdot = self.A @ np.reshape(x, (-1, 1)) \
847+
+ self.B @ np.reshape(u, (-1, 1))
848848
return np.array(xdot).reshape((-1,))
849849

850850
def _out(self, t, x, u):
851851
# Convert input to column vector and then change output to 1D array
852-
y = np.dot(self.C, np.reshape(x, (-1, 1))) \
853-
+ np.dot(self.D, np.reshape(u, (-1, 1)))
852+
y = self.C @ np.reshape(x, (-1, 1)) \
853+
+ self.D @ np.reshape(u, (-1, 1))
854854
return np.array(y).reshape((-1,))
855855

856856

@@ -1197,7 +1197,7 @@ def _out(self, t, x, u):
11971197
ulist, ylist = self._compute_static_io(t, x, u)
11981198

11991199
# Make the full set of subsystem outputs to system output
1200-
return np.dot(self.output_map, ylist)
1200+
return self.output_map @ ylist
12011201

12021202
def _compute_static_io(self, t, x, u):
12031203
# Figure out the total number of inputs and outputs
@@ -1239,7 +1239,7 @@ def _compute_static_io(self, t, x, u):
12391239
output_index += sys.noutputs
12401240

12411241
# Compute inputs based on connection map
1242-
new_ulist = np.dot(self.connect_map, ylist[:noutputs]) \
1242+
new_ulist = self.connect_map @ ylist[:noutputs] \
12431243
+ np.dot(self.input_map, u)
12441244

12451245
# Check to see if any of the inputs changed

control/modelsimp.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def hsvd(sys):
9393

9494
Wc = gram(sys, 'c')
9595
Wo = gram(sys, 'o')
96-
WoWc = np.dot(Wo, Wc)
96+
WoWc = Wo @ Wc
9797
w, v = np.linalg.eig(WoWc)
9898

9999
hsv = np.sqrt(w)
@@ -192,10 +192,10 @@ def modred(sys, ELIM, method='matchdc'):
192192
A22I_A21 = A22I_A21_B2[:, :A21.shape[1]]
193193
A22I_B2 = A22I_A21_B2[:, A21.shape[1]:]
194194

195-
Ar = A11 - np.dot(A12, A22I_A21)
196-
Br = B1 - np.dot(A12, A22I_B2)
197-
Cr = C1 - np.dot(C2, A22I_A21)
198-
Dr = sys.D - np.dot(C2, A22I_B2)
195+
Ar = A11 - A12 @ A22I_A21
196+
Br = B1 - A12 @ A22I_B2
197+
Cr = C1 - C2 @ A22I_A21
198+
Dr = sys.D - C2 @ A22I_B2
199199
elif method == 'truncate':
200200
# if truncate, simply discard state x2
201201
Ar = A11

control/optimal.py

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -387,33 +387,29 @@ def _constraint_function(self, coeffs):
387387
# Evaluate the constraint function along the trajectory
388388
value = []
389389
for i, t in enumerate(self.timepts):
390-
for type, fun, lb, ub in self.trajectory_constraints:
390+
for ctype, fun, lb, ub in self.trajectory_constraints:
391391
if np.all(lb == ub):
392392
# Skip equality constraints
393393
continue
394-
elif type == opt.LinearConstraint:
394+
elif ctype == opt.LinearConstraint:
395395
# `fun` is the A matrix associated with the polytope...
396-
value.append(
397-
np.dot(fun, np.hstack([states[:, i], inputs[:, i]])))
398-
elif type == opt.NonlinearConstraint:
396+
value.append(fun @ np.hstack([states[:, i], inputs[:, i]]))
397+
elif ctype == opt.NonlinearConstraint:
399398
value.append(fun(states[:, i], inputs[:, i]))
400399
else:
401-
raise TypeError("unknown constraint type %s" %
402-
constraint[0])
400+
raise TypeError(f"unknown constraint type {ctype}")
403401

404402
# Evaluate the terminal constraint functions
405-
for type, fun, lb, ub in self.terminal_constraints:
403+
for ctype, fun, lb, ub in self.terminal_constraints:
406404
if np.all(lb == ub):
407405
# Skip equality constraints
408406
continue
409-
elif type == opt.LinearConstraint:
410-
value.append(
411-
np.dot(fun, np.hstack([states[:, i], inputs[:, i]])))
412-
elif type == opt.NonlinearConstraint:
407+
elif ctype == opt.LinearConstraint:
408+
value.append(fun @ np.hstack([states[:, i], inputs[:, i]]))
409+
elif ctype == opt.NonlinearConstraint:
413410
value.append(fun(states[:, i], inputs[:, i]))
414411
else:
415-
raise TypeError("unknown constraint type %s" %
416-
constraint[0])
412+
raise TypeError(f"unknown constraint type {ctype}")
417413

418414
# Update statistics
419415
self.constraint_evaluations += 1
@@ -475,33 +471,29 @@ def _eqconst_function(self, coeffs):
475471
# Evaluate the constraint function along the trajectory
476472
value = []
477473
for i, t in enumerate(self.timepts):
478-
for type, fun, lb, ub in self.trajectory_constraints:
474+
for ctype, fun, lb, ub in self.trajectory_constraints:
479475
if np.any(lb != ub):
480476
# Skip inequality constraints
481477
continue
482-
elif type == opt.LinearConstraint:
478+
elif ctype == opt.LinearConstraint:
483479
# `fun` is the A matrix associated with the polytope...
484-
value.append(
485-
np.dot(fun, np.hstack([states[:, i], inputs[:, i]])))
486-
elif type == opt.NonlinearConstraint:
480+
value.append(fun @ np.hstack([states[:, i], inputs[:, i]]))
481+
elif ctype == opt.NonlinearConstraint:
487482
value.append(fun(states[:, i], inputs[:, i]))
488483
else:
489-
raise TypeError("unknown constraint type %s" %
490-
constraint[0])
484+
raise TypeError(f"unknown constraint type {ctype}")
491485

492486
# Evaluate the terminal constraint functions
493-
for type, fun, lb, ub in self.terminal_constraints:
487+
for ctype, fun, lb, ub in self.terminal_constraints:
494488
if np.any(lb != ub):
495489
# Skip inequality constraints
496490
continue
497-
elif type == opt.LinearConstraint:
498-
value.append(
499-
np.dot(fun, np.hstack([states[:, i], inputs[:, i]])))
500-
elif type == opt.NonlinearConstraint:
491+
elif ctype == opt.LinearConstraint:
492+
value.append(fun @ np.hstack([states[:, i], inputs[:, i]]))
493+
elif ctype == opt.NonlinearConstraint:
501494
value.append(fun(states[:, i], inputs[:, i]))
502495
else:
503-
raise TypeError("unknown constraint type %s" %
504-
constraint[0])
496+
raise TypeError("unknown constraint type {ctype}")
505497

506498
# Update statistics
507499
self.eqconst_evaluations += 1

control/statefbk.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -393,8 +393,7 @@ def lqe(*args, **keywords):
393393
N.shape[0] != ninputs or N.shape[1] != noutputs):
394394
raise ControlDimension("incorrect covariance matrix dimensions")
395395

396-
# P, E, LT = care(A.T, C.T, G @ Q @ G.T, R)
397-
P, E, LT = care(A.T, C.T, np.dot(np.dot(G, Q), G.T), R)
396+
P, E, LT = care(A.T, C.T, G @ Q @ G.T, R)
398397
return _ssmatrix(LT.T), _ssmatrix(P), E
399398

400399

@@ -439,7 +438,7 @@ def acker(A, B, poles):
439438
n = np.size(p)
440439
pmat = p[n-1] * np.linalg.matrix_power(a, 0)
441440
for i in np.arange(1, n):
442-
pmat = pmat + np.dot(p[n-i-1], np.linalg.matrix_power(a, i))
441+
pmat = pmat + p[n-i-1] * np.linalg.matrix_power(a, i)
443442
K = np.linalg.solve(ct, pmat)
444443

445444
K = K[-1][:] # Extract the last row
@@ -556,7 +555,7 @@ def lqr(*args, **keywords):
556555

557556
# Now compute the return value
558557
# We assume that R is positive definite and, hence, invertible
559-
K = np.linalg.solve(R, np.dot(B.T, X) + N.T)
558+
K = np.linalg.solve(R, B.T @ X + N.T)
560559
S = X
561560
E = w[0:nstates]
562561

@@ -594,7 +593,7 @@ def ctrb(A, B):
594593

595594
# Construct the controllability matrix
596595
ctrb = np.hstack(
597-
[bmat] + [np.dot(np.linalg.matrix_power(amat, i), bmat)
596+
[bmat] + [np.linalg.matrix_power(amat, i) @ bmat
598597
for i in range(1, n)])
599598
return _ssmatrix(ctrb)
600599

@@ -628,7 +627,7 @@ def obsv(A, C):
628627
n = np.shape(amat)[0]
629628

630629
# Construct the observability matrix
631-
obsv = np.vstack([cmat] + [np.dot(cmat, np.linalg.matrix_power(amat, i))
630+
obsv = np.vstack([cmat] + [cmat @ np.linalg.matrix_power(amat, i)
632631
for i in range(1, n)])
633632
return _ssmatrix(obsv)
634633

@@ -701,10 +700,10 @@ def gram(sys, type):
701700
raise ControlSlycot("can't find slycot module 'sb03md'")
702701
if type == 'c':
703702
tra = 'T'
704-
C = -np.dot(sys.B, sys.B.transpose())
703+
C = -sys.B @ sys.B.T
705704
elif type == 'o':
706705
tra = 'N'
707-
C = -np.dot(sys.C.transpose(), sys.C)
706+
C = -sys.C.T @ sys.C
708707
n = sys.nstates
709708
U = np.zeros((n, n))
710709
A = np.array(sys.A) # convert to NumPy array for slycot

control/statesp.py

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -712,11 +712,11 @@ def __mul__(self, other):
712712
(concatenate((other.A,
713713
zeros((other.A.shape[0], self.A.shape[1]))),
714714
axis=1),
715-
concatenate((np.dot(self.B, other.C), self.A), axis=1)),
715+
concatenate((self.B @ other.C, self.A), axis=1)),
716716
axis=0)
717-
B = concatenate((other.B, np.dot(self.B, other.D)), axis=0)
718-
C = concatenate((np.dot(self.D, other.C), self.C), axis=1)
719-
D = np.dot(self.D, other.D)
717+
B = concatenate((other.B, self.B @ other.D), axis=0)
718+
C = concatenate((self.D @ other.C, self.C), axis=1)
719+
D = self.D @ other.D
720720

721721
return StateSpace(A, B, C, D, dt)
722722

@@ -741,8 +741,8 @@ def __rmul__(self, other):
741741
# try to treat this as a matrix
742742
try:
743743
X = _ssmatrix(other)
744-
C = np.dot(X, self.C)
745-
D = np.dot(X, self.D)
744+
C = X @ self.C
745+
D = X @ self.D
746746
return StateSpace(self.A, self.B, C, D, self.dt)
747747

748748
except Exception as e:
@@ -915,10 +915,8 @@ def horner(self, x, warn_infinite=True):
915915
# TODO: can this be vectorized?
916916
for idx, x_idx in enumerate(x_arr):
917917
try:
918-
out[:, :, idx] = np.dot(
919-
self.C,
920-
solve(x_idx * eye(self.nstates) - self.A, self.B)) \
921-
+ self.D
918+
xr = solve(x_idx * eye(self.nstates) - self.A, self.B)
919+
out[:, :, idx] = self.C @ xr + self.D
922920
except LinAlgError:
923921
# Issue a warning messsage, for consistency with xferfcn
924922
if warn_infinite:
@@ -1019,7 +1017,7 @@ def feedback(self, other=1, sign=-1):
10191017
C2 = other.C
10201018
D2 = other.D
10211019

1022-
F = eye(self.ninputs) - sign * np.dot(D2, D1)
1020+
F = eye(self.ninputs) - sign * D2 @ D1
10231021
if matrix_rank(F) != self.ninputs:
10241022
raise ValueError(
10251023
"I - sign * D2 * D1 is singular to working precision.")
@@ -1033,20 +1031,20 @@ def feedback(self, other=1, sign=-1):
10331031
E_D2 = E_D2_C2[:, :other.ninputs]
10341032
E_C2 = E_D2_C2[:, other.ninputs:]
10351033

1036-
T1 = eye(self.noutputs) + sign * np.dot(D1, E_D2)
1037-
T2 = eye(self.ninputs) + sign * np.dot(E_D2, D1)
1034+
T1 = eye(self.noutputs) + sign * D1 @ E_D2
1035+
T2 = eye(self.ninputs) + sign * E_D2 @ D1
10381036

10391037
A = concatenate(
10401038
(concatenate(
1041-
(A1 + sign * np.dot(np.dot(B1, E_D2), C1),
1042-
sign * np.dot(B1, E_C2)), axis=1),
1039+
(A1 + sign * B1 @ E_D2 @ C1,
1040+
sign * B1 @ E_C2), axis=1),
10431041
concatenate(
1044-
(np.dot(B2, np.dot(T1, C1)),
1045-
A2 + sign * np.dot(np.dot(B2, D1), E_C2)), axis=1)),
1042+
(B2 @ T1 @ C1,
1043+
A2 + sign * B2 @ D1 @ E_C2), axis=1)),
10461044
axis=0)
1047-
B = concatenate((np.dot(B1, T2), np.dot(np.dot(B2, D1), T2)), axis=0)
1048-
C = concatenate((np.dot(T1, C1), sign * np.dot(D1, E_C2)), axis=1)
1049-
D = np.dot(D1, T2)
1045+
B = concatenate((B1 @ T2, B2 @ D1 @ T2), axis=0)
1046+
C = concatenate((T1 @ C1, sign * D1 @ E_C2), axis=1)
1047+
D = D1 @ T2
10501048

10511049
return StateSpace(A, B, C, D, dt)
10521050

control/timeresp.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -997,16 +997,15 @@ def forced_response(sys, T=None, U=0., X0=0., transpose=False,
997997
# Separate out the discrete and continuous time cases
998998
if isctime(sys, strict=True):
999999
# Solve the differential equation, copied from scipy.signal.ltisys.
1000-
dot = np.dot # Faster and shorter code
10011000

10021001
# Faster algorithm if U is zero
10031002
# (if not None, it was converted to array above)
10041003
if U is None or np.all(U == 0):
10051004
# Solve using matrix exponential
10061005
expAdt = sp.linalg.expm(A * dt)
10071006
for i in range(1, n_steps):
1008-
xout[:, i] = dot(expAdt, xout[:, i-1])
1009-
yout = dot(C, xout)
1007+
xout[:, i] = expAdt @ xout[:, i-1]
1008+
yout = C @ xout
10101009

10111010
# General algorithm that interpolates U in between output points
10121011
else:
@@ -1034,9 +1033,9 @@ def forced_response(sys, T=None, U=0., X0=0., transpose=False,
10341033
Bd0 = expM[:n_states, n_states:n_states + n_inputs] - Bd1
10351034

10361035
for i in range(1, n_steps):
1037-
xout[:, i] = (dot(Ad, xout[:, i-1]) + dot(Bd0, U[:, i-1]) +
1038-
dot(Bd1, U[:, i]))
1039-
yout = dot(C, xout) + dot(D, U)
1036+
xout[:, i] = (Ad @ xout[:, i-1]
1037+
+ Bd0 @ U[:, i-1] + Bd1 @ U[:, i])
1038+
yout = C @ xout + D @ U
10401039
tout = T
10411040

10421041
else:

examples/slycot-import-test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,6 @@
3939
dico = 'D' # Discrete system
4040
_, _, _, _, _, K, _ = sb01bd(n, m, npp, alpha, A, B, w, dico, tol=0.0, ldwork=None)
4141
print("[slycot] K = ", K)
42-
print("[slycot] eigs = ", np.linalg.eig(A + np.dot(B, K))[0])
42+
print("[slycot] eigs = ", np.linalg.eig(A + B @ K)[0])
4343
else:
4444
print("Slycot is not installed.")

0 commit comments

Comments
 (0)