Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Inconsistent behaviour of ImmutableMatrix #363

@oscarbenjamin

Description

@oscarbenjamin

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions