|
41 | 41 | Author: Bjorn Olofsson
|
42 | 42 | """
|
43 | 43 |
|
44 |
| -from numpy import shape, size, array, asarray, copy, zeros, eye, dot |
| 44 | +from numpy import shape, size, asarray, copy, zeros, eye, dot, \ |
| 45 | + finfo, inexact, atleast_2d |
45 | 46 | from scipy.linalg import eigvals, solve_discrete_are, solve
|
46 | 47 | from .exception import ControlSlycot, ControlArgument
|
47 | 48 | from .statesp import _ssmatrix
|
@@ -122,7 +123,7 @@ def lyap(A, Q, C=None, E=None):
|
122 | 123 | if size(Q) > 1 and shape(Q)[0] != shape(Q)[1]:
|
123 | 124 | raise ControlArgument("Q must be a quadratic matrix.")
|
124 | 125 |
|
125 |
| - if not (asarray(Q) == asarray(Q).T).all(): |
| 126 | + if not _is_symmetric(Q): |
126 | 127 | raise ControlArgument("Q must be a symmetric matrix.")
|
127 | 128 |
|
128 | 129 | # Solve the Lyapunov equation by calling Slycot function sb03md
|
@@ -188,7 +189,7 @@ def lyap(A, Q, C=None, E=None):
|
188 | 189 | raise ControlArgument("E must be a square matrix with the same \
|
189 | 190 | dimension as A.")
|
190 | 191 |
|
191 |
| - if not (asarray(Q) == asarray(Q).T).all(): |
| 192 | + if not _is_symmetric(Q): |
192 | 193 | raise ControlArgument("Q must be a symmetric matrix.")
|
193 | 194 |
|
194 | 195 | # Make sure we have access to the write slicot routine
|
@@ -309,7 +310,7 @@ def dlyap(A,Q,C=None,E=None):
|
309 | 310 | if size(Q) > 1 and shape(Q)[0] != shape(Q)[1]:
|
310 | 311 | raise ControlArgument("Q must be a quadratic matrix.")
|
311 | 312 |
|
312 |
| - if not (asarray(Q) == asarray(Q).T).all(): |
| 313 | + if not _is_symmetric(Q): |
313 | 314 | raise ControlArgument("Q must be a symmetric matrix.")
|
314 | 315 |
|
315 | 316 | # Solve the Lyapunov equation by calling the Slycot function sb03md
|
@@ -371,7 +372,7 @@ def dlyap(A,Q,C=None,E=None):
|
371 | 372 | raise ControlArgument("E must be a square matrix with the same \
|
372 | 373 | dimension as A.")
|
373 | 374 |
|
374 |
| - if not (asarray(Q) == asarray(Q).T).all(): |
| 375 | + if not _is_symmetric(Q): |
375 | 376 | raise ControlArgument("Q must be a symmetric matrix.")
|
376 | 377 |
|
377 | 378 | # Solve the generalized Lyapunov equation by calling Slycot
|
@@ -500,10 +501,10 @@ def care(A, B, Q, R=None, S=None, E=None, stabilizing=True):
|
500 | 501 | size(B) == 1 and n > 1:
|
501 | 502 | raise ControlArgument("Incompatible dimensions of B matrix.")
|
502 | 503 |
|
503 |
| - if not (asarray(Q) == asarray(Q).T).all(): |
| 504 | + if not _is_symmetric(Q): |
504 | 505 | raise ControlArgument("Q must be a symmetric matrix.")
|
505 | 506 |
|
506 |
| - if not (asarray(R) == asarray(R).T).all(): |
| 507 | + if not _is_symmetric(R): |
507 | 508 | raise ControlArgument("R must be a symmetric matrix.")
|
508 | 509 |
|
509 | 510 | # Create back-up of arrays needed for later computations
|
@@ -603,10 +604,10 @@ def care(A, B, Q, R=None, S=None, E=None, stabilizing=True):
|
603 | 604 | size(S) == 1 and m > 1:
|
604 | 605 | raise ControlArgument("Incompatible dimensions of S matrix.")
|
605 | 606 |
|
606 |
| - if not (asarray(Q) == asarray(Q).T).all(): |
| 607 | + if not _is_symmetric(Q): |
607 | 608 | raise ControlArgument("Q must be a symmetric matrix.")
|
608 | 609 |
|
609 |
| - if not (asarray(R) == asarray(R).T).all(): |
| 610 | + if not _is_symmetric(R): |
610 | 611 | raise ControlArgument("R must be a symmetric matrix.")
|
611 | 612 |
|
612 | 613 | # Create back-up of arrays needed for later computations
|
@@ -775,10 +776,10 @@ def dare_old(A, B, Q, R, S=None, E=None, stabilizing=True):
|
775 | 776 | size(B) == 1 and n > 1:
|
776 | 777 | raise ControlArgument("Incompatible dimensions of B matrix.")
|
777 | 778 |
|
778 |
| - if not (asarray(Q) == asarray(Q).T).all(): |
| 779 | + if not _is_symmetric(Q): |
779 | 780 | raise ControlArgument("Q must be a symmetric matrix.")
|
780 | 781 |
|
781 |
| - if not (asarray(R) == asarray(R).T).all(): |
| 782 | + if not _is_symmetric(R): |
782 | 783 | raise ControlArgument("R must be a symmetric matrix.")
|
783 | 784 |
|
784 | 785 | # Create back-up of arrays needed for later computations
|
@@ -882,10 +883,10 @@ def dare_old(A, B, Q, R, S=None, E=None, stabilizing=True):
|
882 | 883 | size(S) == 1 and m > 1:
|
883 | 884 | raise ControlArgument("Incompatible dimensions of S matrix.")
|
884 | 885 |
|
885 |
| - if not (asarray(Q) == asarray(Q).T).all(): |
| 886 | + if not _is_symmetric(Q): |
886 | 887 | raise ControlArgument("Q must be a symmetric matrix.")
|
887 | 888 |
|
888 |
| - if not (asarray(R) == asarray(R).T).all(): |
| 889 | + if not _is_symmetric(R): |
889 | 890 | raise ControlArgument("R must be a symmetric matrix.")
|
890 | 891 |
|
891 | 892 | # Create back-up of arrays needed for later computations
|
@@ -960,3 +961,12 @@ def dare_old(A, B, Q, R, S=None, E=None, stabilizing=True):
|
960 | 961 | # Invalid set of input parameters
|
961 | 962 | else:
|
962 | 963 | raise ControlArgument("Invalid set of input parameters.")
|
| 964 | + |
| 965 | + |
| 966 | +def _is_symmetric(M): |
| 967 | + M = atleast_2d(M) |
| 968 | + if isinstance(M[0, 0], inexact): |
| 969 | + eps = finfo(M.dtype).eps |
| 970 | + return ((M - M.T) < eps).all() |
| 971 | + else: |
| 972 | + return (M == M.T).all() |
0 commit comments