Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
implement remaining dunder methods for StateSpace
  • Loading branch information
murrayrm committed Jun 8, 2019
commit d93ea5edf35c32fc293a229561192d34adaaaab8
13 changes: 12 additions & 1 deletion control/statesp.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,18 +167,29 @@ def __mul__(self, other):
product = np.dot(self, other)
return product if np.isrealobj(product) else np.asarray(product)

return NotImplemented
raise NotImplementedError("Unknown object for StateSpaceMatrix "
"multiplication.")

def __rmul__(self, other):
"""Multiply or scale state-space matrices"""
# return np.matrix.__rmul__(self, other) # legacy
product = np.dot(other, self)
return product if np.isrealobj(product) else np.asarray(product)

def __imul__(self, other):
return self.__mul__(other)

def __pow__(self, n):
"""Raise a (square) matrix to the (integer) power `n`"""
return np.linalg.matrix_power(self, n)

def __rpow__(self, other):
raise NotImplementedError("StateSpaceMatrix powers are not "
"implemented.")

def __ipow__(self, n):
return self.__pow__(n)

def __getitem__(self, index):
"""Get elements of a state-space matrix and return matrix"""
# return np.matrix.__getitem__(self, index) # legacy
Expand Down
40 changes: 38 additions & 2 deletions control/tests/ssmatrix_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def test_mul(self):
self.assertEqual(CmRm.shape, (2, 2))
np.testing.assert_array_equal(CmRm, np.dot(Cm, Rm))

def test_multiple_other(self):
def test_multiply_other(self):
"""Make sure that certain operations preserve StateSpaceMatrix type"""
M = ct.StateSpaceMatrix([[1, 1], [1, 1]])
Mint = M * 5
Expand Down Expand Up @@ -129,7 +129,30 @@ def test_multiple_other(self):
Mcomplex = np.array([[1j, 0], [0, 1j]]) * M
self.assertFalse(isinstance(Mcomplex, ct.StateSpaceMatrix))

def test_power(self):
def test_imul(self):
# Make sure that multiplying two matrices gives a matrix
M1 = ct.StateSpaceMatrix([[1, 1], [1, -1]])
M2 = ct.StateSpaceMatrix([[1, 2], [2, 1]])
Mprod = M1; Mprod *= M2
self.assertTrue(isinstance(Mprod, ct.StateSpaceMatrix))
self.assertEqual(Mprod.shape, (2, 2))
np.testing.assert_array_equal(Mprod, np.dot(M1, M2))

# Matrix times a (state-space) column vector gives a column vector
Cm = ct.StateSpaceMatrix([[1], [2]])
MCm = M1; MCm *= Cm
self.assertTrue(isinstance(MCm, ct.StateSpaceMatrix))
self.assertEqual(MCm.shape, (2, 1))
np.testing.assert_array_equal(MCm, np.dot(M1, Cm))

# Matrix times a (ndarray) column vector gives a column vector
Ca = np.array([[1], [2]])
MCa = M1; MCa *= Ca
self.assertTrue(isinstance(MCa, ct.StateSpaceMatrix))
self.assertEqual(MCa.shape, (2, 1))
np.testing.assert_array_equal(MCa, np.dot(M1, Ca))

def test_pow(self):
"""Test matrix exponential"""
# Generate cases that should work
M = ct.ssmatrix([[1, 1], [-1, 2]])
Expand All @@ -142,6 +165,19 @@ def test_power(self):
self.assertRaises(TypeError, lambda: M**0.5)
self.assertRaises(np.linalg.LinAlgError, lambda: M[0, :]**2)

def test_ipow(self):
"""Test matrix exponential"""
# Generate cases that should work
M = ct.ssmatrix([[1, 1], [-1, 2]])
M0 = M; M0 **= 0
M1 = M; M1 **= 1
M2 = M; M2 **= 2
M3 = M; M3 **= 3
np.testing.assert_array_almost_equal(M0, np.eye(2))
np.testing.assert_array_almost_equal(M1, M)
np.testing.assert_array_almost_equal(M2, np.dot(M, M))
np.testing.assert_array_almost_equal(M3, M*M*M)

def test_getitem(self):
M = ct.StateSpaceMatrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

Expand Down