immutable.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. from mpmath.matrices.matrices import _matrix
  2. from sympy.core import Basic, Dict, Tuple
  3. from sympy.core.numbers import Integer
  4. from sympy.core.cache import cacheit
  5. from sympy.core.sympify import _sympy_converter as sympify_converter, _sympify
  6. from sympy.matrices.dense import DenseMatrix
  7. from sympy.matrices.expressions import MatrixExpr
  8. from sympy.matrices.matrices import MatrixBase
  9. from sympy.matrices.repmatrix import RepMatrix
  10. from sympy.matrices.sparse import SparseRepMatrix
  11. from sympy.multipledispatch import dispatch
  12. def sympify_matrix(arg):
  13. return arg.as_immutable()
  14. sympify_converter[MatrixBase] = sympify_matrix
  15. def sympify_mpmath_matrix(arg):
  16. mat = [_sympify(x) for x in arg]
  17. return ImmutableDenseMatrix(arg.rows, arg.cols, mat)
  18. sympify_converter[_matrix] = sympify_mpmath_matrix
  19. class ImmutableRepMatrix(RepMatrix, MatrixExpr): # type: ignore
  20. """Immutable matrix based on RepMatrix
  21. Uses DomainMAtrix as the internal representation.
  22. """
  23. #
  24. # This is a subclass of RepMatrix that adds/overrides some methods to make
  25. # the instances Basic and immutable. ImmutableRepMatrix is a superclass for
  26. # both ImmutableDenseMatrix and ImmutableSparseMatrix.
  27. #
  28. def __new__(cls, *args, **kwargs):
  29. return cls._new(*args, **kwargs)
  30. __hash__ = MatrixExpr.__hash__
  31. def copy(self):
  32. return self
  33. @property
  34. def cols(self):
  35. return self._cols
  36. @property
  37. def rows(self):
  38. return self._rows
  39. @property
  40. def shape(self):
  41. return self._rows, self._cols
  42. def as_immutable(self):
  43. return self
  44. def _entry(self, i, j, **kwargs):
  45. return self[i, j]
  46. def __setitem__(self, *args):
  47. raise TypeError("Cannot set values of {}".format(self.__class__))
  48. def is_diagonalizable(self, reals_only=False, **kwargs):
  49. return super().is_diagonalizable(
  50. reals_only=reals_only, **kwargs)
  51. is_diagonalizable.__doc__ = SparseRepMatrix.is_diagonalizable.__doc__
  52. is_diagonalizable = cacheit(is_diagonalizable)
  53. class ImmutableDenseMatrix(DenseMatrix, ImmutableRepMatrix): # type: ignore
  54. """Create an immutable version of a matrix.
  55. Examples
  56. ========
  57. >>> from sympy import eye, ImmutableMatrix
  58. >>> ImmutableMatrix(eye(3))
  59. Matrix([
  60. [1, 0, 0],
  61. [0, 1, 0],
  62. [0, 0, 1]])
  63. >>> _[0, 0] = 42
  64. Traceback (most recent call last):
  65. ...
  66. TypeError: Cannot set values of ImmutableDenseMatrix
  67. """
  68. # MatrixExpr is set as NotIterable, but we want explicit matrices to be
  69. # iterable
  70. _iterable = True
  71. _class_priority = 8
  72. _op_priority = 10.001
  73. @classmethod
  74. def _new(cls, *args, **kwargs):
  75. if len(args) == 1 and isinstance(args[0], ImmutableDenseMatrix):
  76. return args[0]
  77. if kwargs.get('copy', True) is False:
  78. if len(args) != 3:
  79. raise TypeError("'copy=False' requires a matrix be initialized as rows,cols,[list]")
  80. rows, cols, flat_list = args
  81. else:
  82. rows, cols, flat_list = cls._handle_creation_inputs(*args, **kwargs)
  83. flat_list = list(flat_list) # create a shallow copy
  84. rep = cls._flat_list_to_DomainMatrix(rows, cols, flat_list)
  85. return cls._fromrep(rep)
  86. @classmethod
  87. def _fromrep(cls, rep):
  88. rows, cols = rep.shape
  89. flat_list = rep.to_sympy().to_list_flat()
  90. obj = Basic.__new__(cls,
  91. Integer(rows),
  92. Integer(cols),
  93. Tuple(*flat_list, sympify=False))
  94. obj._rows = rows
  95. obj._cols = cols
  96. obj._rep = rep
  97. return obj
  98. # make sure ImmutableDenseMatrix is aliased as ImmutableMatrix
  99. ImmutableMatrix = ImmutableDenseMatrix
  100. class ImmutableSparseMatrix(SparseRepMatrix, ImmutableRepMatrix): # type:ignore
  101. """Create an immutable version of a sparse matrix.
  102. Examples
  103. ========
  104. >>> from sympy import eye, ImmutableSparseMatrix
  105. >>> ImmutableSparseMatrix(1, 1, {})
  106. Matrix([[0]])
  107. >>> ImmutableSparseMatrix(eye(3))
  108. Matrix([
  109. [1, 0, 0],
  110. [0, 1, 0],
  111. [0, 0, 1]])
  112. >>> _[0, 0] = 42
  113. Traceback (most recent call last):
  114. ...
  115. TypeError: Cannot set values of ImmutableSparseMatrix
  116. >>> _.shape
  117. (3, 3)
  118. """
  119. is_Matrix = True
  120. _class_priority = 9
  121. @classmethod
  122. def _new(cls, *args, **kwargs):
  123. rows, cols, smat = cls._handle_creation_inputs(*args, **kwargs)
  124. rep = cls._smat_to_DomainMatrix(rows, cols, smat)
  125. return cls._fromrep(rep)
  126. @classmethod
  127. def _fromrep(cls, rep):
  128. rows, cols = rep.shape
  129. smat = rep.to_sympy().to_dok()
  130. obj = Basic.__new__(cls, Integer(rows), Integer(cols), Dict(smat))
  131. obj._rows = rows
  132. obj._cols = cols
  133. obj._rep = rep
  134. return obj
  135. @dispatch(ImmutableDenseMatrix, ImmutableDenseMatrix)
  136. def _eval_is_eq(lhs, rhs): # noqa:F811
  137. """Helper method for Equality with matrices.sympy.
  138. Relational automatically converts matrices to ImmutableDenseMatrix
  139. instances, so this method only applies here. Returns True if the
  140. matrices are definitively the same, False if they are definitively
  141. different, and None if undetermined (e.g. if they contain Symbols).
  142. Returning None triggers default handling of Equalities.
  143. """
  144. if lhs.shape != rhs.shape:
  145. return False
  146. return (lhs - rhs).is_zero_matrix