-
Notifications
You must be signed in to change notification settings - Fork 67
Description
The SymEngine tests in SymPy CI were not running properly. I'm reenabling them in sympy/sympy#21992 but have found some possible regressions in SymEngine to do with the behaviour of ImmutableMatrix.
This is as expected:
$ USE_SYMENGINE=1 python
Python 3.9.0 (v3.9.0:9cf6752276, Oct 5 2020, 11:29:23)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from sympy.core.backend import Matrix, ImmutableMatrix, sin, cos
>>> M = Matrix([[sin(1)**2 + cos(1)**2 - 1]])
>>> M
[-1 + sin(1)**2 + cos(1)**2]
>>> print(M.simplify())
None
>>> M
[0]
However this is not expected:
>>> IM = ImmutableMatrix([[sin(1)**2 + cos(1)**2 - 1]])
>>> IM
[-1 + sin(1)**2 + cos(1)**2]
>>> print(IM.simplify())
None
>>> IM
[0]
It should not be possible to mutate the immutable matrix. SymPy's ImmutableMatrix class returns a simplified copy and does not mutate self:
>>> from sympy import ImmutableMatrix
>>> SIM = ImmutableMatrix([[sin(1)**2 + cos(1)**2 - 1]])
>>> SIM
Matrix([[-1 + cos(1)**2 + sin(1)**2]])
>>> print(SIM.simplify())
Matrix([[0]])
>>> SIM
Matrix([[-1 + cos(1)**2 + sin(1)**2]])
It would have been better if the mutable matrix method simplify
had a different name because it is inconsistent with almost all the other .simplify()
methods in SymPy. For compatibility though the SymEngine wrapper should match this behaviour.
This would have shown up in SymPy CI if the SymEngine tests were still running properly (I noticed this from the old Travis CI).
Another inconsistency is in binary operations that mix and match mutable and immutable matrices. With SymPy we have:
>>> from sympy import Matrix, ImmutableMatrix
>>> M1 = Matrix([[1]])
>>> M2 = ImmutableMatrix([[1]])
>>> for M in [M1, M2, M1+M2, M2+M1]: print(type(M))
...
<class 'sympy.matrices.dense.MutableDenseMatrix'>
<class 'sympy.matrices.immutable.ImmutableDenseMatrix'>
<class 'sympy.matrices.immutable.ImmutableDenseMatrix'>
<class 'sympy.matrices.immutable.ImmutableDenseMatrix'>
In other words all operations mixing mutable and immutable coerce to immutable. With SymEngine that instead gives:
>>> from sympy.core.backend import Matrix, ImmutableMatrix
>>> M1 = Matrix([[1]])
>>> M2 = ImmutableMatrix([[1]])
>>> for M in [M1, M2, M1+M2, M2+M1]: print(type(M))
...
<class 'symengine.lib.symengine_wrapper.MutableDenseMatrix'>
<class 'symengine.lib.symengine_wrapper.ImmutableDenseMatrix'>
<class 'symengine.lib.symengine_wrapper.MutableDenseMatrix'>
<class 'symengine.lib.symengine_wrapper.ImmutableDenseMatrix'>
So the type of M1+M2
does not match M2+M1
.