Checking if a matrix is symmetric in Numpy
Asked Answered
M

6

50

I'm trying to make a function with the arguments (a,tol=1e-8) that returns a boolean value that tells the user whether or not the matrix is symmetric (symmetric matrix is equal to its transpose). So far I have:

def check_symmetric(a, tol=1e-8):
if np.transpose(a, axes=axes) == np.transpose(a, axes=axes):
    return True
def sqr(s):
    rows = len(s)
    for row in sq:
        if len(row) != rows:
            return False
    return True
if a != sqr(s):
    raise ValueError

although I keep getting an axes isn't defined message so I'm pretty sure that doesn't work at all...... the tests I'd like to pass are:

e = np.eye(4)
f = np.diag([1], k=3)
g = e[1:, :]

print(check_symmetric(e))
print(not check_symmetric(e + f))
print(check_symmetric(e + f * 1e-9))
print(not check_symmetric(e + f * 1e-9, 1e-10))
try:
    check_symmetric(g)
    print(False)
except ValueError:
    print(True)

Any help is appreciated, thanks!

Mineralogy answered 20/3, 2017 at 15:59 Comment(3)
Assuming your matrices are 2D only, you don't need an axes keyword. Also, you should keep one matrix untransposed and then check against the transpose of the matrix. At the moment, you are checking equality of two transposed matrices.Sparteine
Yesterday's question about symmetric matrix test: #42876582Envious
oh thanks for the link... although I started to get it sort of working even though my tests weren't quite right: def check_symmetric(a, tol=1e-8): if np.transpose(a.any()) == np.array(a.any()): return True def sqr(s): rows = len(s) for row in sq: if len(row) != rows: return False return True if a != sqr(s): raise ValueErrorMineralogy
N
112

You can simply compare it to its transpose using allclose

def check_symmetric(a, rtol=1e-05, atol=1e-08):
    return numpy.allclose(a, a.T, rtol=rtol, atol=atol)
Naga answered 20/3, 2017 at 20:52 Comment(1)
alternatively , check a-a.T<(tol*a.shape**2)Wiersma
D
24

The following function also solves the problem:

def check_symmetric(a, tol=1e-8):
    return np.all(np.abs(a-a.T) < tol)
Decuple answered 2/10, 2018 at 4:1 Comment(1)
This answer actually works also when the matrix elements are of a custom-type, in contrast to the 'allclose' of the accepted answer. This is the case for example with quaternionic matrices (cf. github.com/moble/quaternion)Pellucid
R
8

If you're not worried about the tot threshold

(a==a.T).all()

is the simplest solution. This works for N-dimensional (N>2) arrays as well.

Robalo answered 27/7, 2021 at 21:24 Comment(0)
R
5

This is an old post but I would recommend another method. Especially for sparse matrices, this can be hundreds of times faster.

def is_symmetric(A, tol=1e-8):
    return scipy.sparse.linalg.norm(A-A.T, scipy.Inf) < tol;

Or similar but you get the idea. Using a norm is a much more optimized calculation.

Rechaba answered 5/5, 2021 at 17:41 Comment(0)
D
3

If using SciPy is acceptable, you can use scipy.linalg.issymmetric() (as of v1.8.0), which also includes some input validation.

  • See implementation here.
  • A note regarding performance (from the docs; emphasis mine):

    When atol and/or rtol are set, then the comparison is performed by numpy.allclose and the tolerance values are passed to it. Otherwise, an exact comparison against zero is performed by internal functions. Hence performance can improve or degrade depending on the size and dtype of the array.

Doctrine answered 15/12, 2022 at 6:47 Comment(0)
S
1

Suppose we were not to consider tolerance e.i. consider integer matrices. We can use .all() in this code to check the corresponding matrix elements and .shape to find matrix dimensions so then we can write something like this:

def check_matrix(A:np.array):
    a, b = A.shape
    if a == b and (-1*np.transpose(A) == A).all():
        return -1
    if a == b and (np.transpose(A) == A).all():
        return 1
    return 0

Takes in a matrix first if statement checks if it's skew symmetrical, second, if it's symmetrical and if neither, returns 0. To adapt this code to floats, use .allclose(). I am aware the previous answer has a better and more concise code but I wanted to share this because answers have not used .shape, so it is unique. :)

Sawdust answered 15/11, 2023 at 22:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.