SymPy Matrix argument not comparable

Viewed 55

I'm using SymPy to perform some operations and stumbled upon this:

If I declare the following matrix and try to get it's 2-norm (largest sing. value):

from sympy import Matrix

Matrix([[4, 1, 0, 0], [1, 4, 1, 0], [0, 1, 4, 1], [0, 0, 1, 4]]) # declare matrix
print(x.norm(2)) # print it's 2-norm

I get the expected result:

sqrt(9*sqrt(5)/2 + 43/2)

But, when I declare a seemingly equivalent matrix and try to get it's 2-norm, I get an error:

from sympy import Matrix

x = Matrix([[7, -13, -3, -1, 0], [-2, 4, 2, 0, 0], [5, -9, -2, 0, 1]]) # declare matrix
print(x.norm(2))  # print it's 2-norm

Error:

Traceback (most recent call last):
  File "main.py", line 29, in <module>
    print(x.norm(2))
  File "venv/lib/python3.9/site-packages/sympy/matrices/matrices.py", line 1984, in norm
    return Max(*self.singular_values())
  File "venv/lib/python3.9/site-packages/sympy/functions/elementary/miscellaneous.py", line 391, in __new__
    args = frozenset(cls._new_args_filter(args))
  File "venv/lib/python3.9/site-packages/sympy/functions/elementary/miscellaneous.py", line 564, in _new_args_filter
    raise ValueError("The argument '%s' is not comparable." % arg)
ValueError: The argument 'sqrt(121 + 43127/(3*(1723619 + 2*sqrt(199009527)*I/9)**(1/3)) + (1723619 + 2*sqrt(199009527)*I/9)**(1/3))' is not comparable.

I read the source code and learned that is not comparable means that an object can be computed to a real number or already is a real number. I don't see how that matrix can be computed to a real number (it's a matrix).

Can anyone explain why am I getting this error with one matrix but not with the other?

Thanks!

1 Answers

As you can see from the traceback, it tries to compute the maximum of the singular values:

Max(*self.singular_values())

In your case, you can visualize the singular values by executing x.singular_values() (the output is quite long, so I'm not going to paste it here.

However, some of those singular values are complex numbers, hence they can't be compared. The function Max expects real numbers! As an example, you can execute:

Max(5 + I, 3)
# ValueError: The argument '5 + I' is not comparable.

Edit:

As Oscar pointed out in the comment, the imaginary part is really small. Hence, we can convert the singular values to numerical data types, discard the imaginary parts if they are lower than a threshold and proceed with the formula:

x = Matrix([[7, -13, -3, -1, 0], [-2, 4, 2, 0, 0], [5, -9, -2, 0, 1]]) # declare matrix
sv = [complex(t) for t in x.singular_values()]
# discard imaginary components if they are lower than a threshold
threshold = 1e-08
sv = [t.real if t.imag < threshold else t for t in sv]
max(sv)
# out: 18.99465957621187
Related