repmatrix.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  1. from collections import defaultdict
  2. from operator import index as index_
  3. from sympy.core.expr import Expr
  4. from sympy.core.kind import Kind, NumberKind, UndefinedKind
  5. from sympy.core.numbers import Integer, Rational
  6. from sympy.core.sympify import _sympify, SympifyError
  7. from sympy.core.singleton import S
  8. from sympy.polys.domains import ZZ, QQ, EXRAW
  9. from sympy.polys.matrices import DomainMatrix
  10. from sympy.utilities.exceptions import sympy_deprecation_warning
  11. from sympy.utilities.iterables import is_sequence
  12. from sympy.utilities.misc import filldedent
  13. from .common import classof
  14. from .matrices import MatrixBase, MatrixKind, ShapeError
  15. class RepMatrix(MatrixBase):
  16. """Matrix implementation based on DomainMatrix as an internal representation.
  17. The RepMatrix class is a superclass for Matrix, ImmutableMatrix,
  18. SparseMatrix and ImmutableSparseMatrix which are the main usable matrix
  19. classes in SymPy. Most methods on this class are simply forwarded to
  20. DomainMatrix.
  21. """
  22. #
  23. # MatrixBase is the common superclass for all of the usable explicit matrix
  24. # classes in SymPy. The idea is that MatrixBase is an abstract class though
  25. # and that subclasses will implement the lower-level methods.
  26. #
  27. # RepMatrix is a subclass of MatrixBase that uses DomainMatrix as an
  28. # internal representation and delegates lower-level methods to
  29. # DomainMatrix. All of SymPy's standard explicit matrix classes subclass
  30. # RepMatrix and so use DomainMatrix internally.
  31. #
  32. # A RepMatrix uses an internal DomainMatrix with the domain set to ZZ, QQ
  33. # or EXRAW. The EXRAW domain is equivalent to the previous implementation
  34. # of Matrix that used Expr for the elements. The ZZ and QQ domains are used
  35. # when applicable just because they are compatible with the previous
  36. # implementation but are much more efficient. Other domains such as QQ[x]
  37. # are not used because they differ from Expr in some way (e.g. automatic
  38. # expansion of powers and products).
  39. #
  40. _rep: DomainMatrix
  41. def __eq__(self, other):
  42. # Skip sympify for mutable matrices...
  43. if not isinstance(other, RepMatrix):
  44. try:
  45. other = _sympify(other)
  46. except SympifyError:
  47. return NotImplemented
  48. if not isinstance(other, RepMatrix):
  49. return NotImplemented
  50. return self._rep.unify_eq(other._rep)
  51. @classmethod
  52. def _unify_element_sympy(cls, rep, element):
  53. domain = rep.domain
  54. element = _sympify(element)
  55. if domain != EXRAW:
  56. # The domain can only be ZZ, QQ or EXRAW
  57. if element.is_Integer:
  58. new_domain = domain
  59. elif element.is_Rational:
  60. new_domain = QQ
  61. else:
  62. new_domain = EXRAW
  63. # XXX: This converts the domain for all elements in the matrix
  64. # which can be slow. This happens e.g. if __setitem__ changes one
  65. # element to something that does not fit in the domain
  66. if new_domain != domain:
  67. rep = rep.convert_to(new_domain)
  68. domain = new_domain
  69. if domain != EXRAW:
  70. element = new_domain.from_sympy(element)
  71. if domain == EXRAW and not isinstance(element, Expr):
  72. sympy_deprecation_warning(
  73. """
  74. non-Expr objects in a Matrix is deprecated. Matrix represents
  75. a mathematical matrix. To represent a container of non-numeric
  76. entities, Use a list of lists, TableForm, NumPy array, or some
  77. other data structure instead.
  78. """,
  79. deprecated_since_version="1.9",
  80. active_deprecations_target="deprecated-non-expr-in-matrix",
  81. stacklevel=4,
  82. )
  83. return rep, element
  84. @classmethod
  85. def _dod_to_DomainMatrix(cls, rows, cols, dod, types):
  86. if not all(issubclass(typ, Expr) for typ in types):
  87. sympy_deprecation_warning(
  88. """
  89. non-Expr objects in a Matrix is deprecated. Matrix represents
  90. a mathematical matrix. To represent a container of non-numeric
  91. entities, Use a list of lists, TableForm, NumPy array, or some
  92. other data structure instead.
  93. """,
  94. deprecated_since_version="1.9",
  95. active_deprecations_target="deprecated-non-expr-in-matrix",
  96. stacklevel=6,
  97. )
  98. rep = DomainMatrix(dod, (rows, cols), EXRAW)
  99. if all(issubclass(typ, Rational) for typ in types):
  100. if all(issubclass(typ, Integer) for typ in types):
  101. rep = rep.convert_to(ZZ)
  102. else:
  103. rep = rep.convert_to(QQ)
  104. return rep
  105. @classmethod
  106. def _flat_list_to_DomainMatrix(cls, rows, cols, flat_list):
  107. elements_dod = defaultdict(dict)
  108. for n, element in enumerate(flat_list):
  109. if element != 0:
  110. i, j = divmod(n, cols)
  111. elements_dod[i][j] = element
  112. types = set(map(type, flat_list))
  113. rep = cls._dod_to_DomainMatrix(rows, cols, elements_dod, types)
  114. return rep
  115. @classmethod
  116. def _smat_to_DomainMatrix(cls, rows, cols, smat):
  117. elements_dod = defaultdict(dict)
  118. for (i, j), element in smat.items():
  119. if element != 0:
  120. elements_dod[i][j] = element
  121. types = set(map(type, smat.values()))
  122. rep = cls._dod_to_DomainMatrix(rows, cols, elements_dod, types)
  123. return rep
  124. def flat(self):
  125. return self._rep.to_sympy().to_list_flat()
  126. def _eval_tolist(self):
  127. return self._rep.to_sympy().to_list()
  128. def _eval_todok(self):
  129. return self._rep.to_sympy().to_dok()
  130. def _eval_values(self):
  131. return list(self.todok().values())
  132. def copy(self):
  133. return self._fromrep(self._rep.copy())
  134. @property
  135. def kind(self) -> MatrixKind:
  136. domain = self._rep.domain
  137. element_kind: Kind
  138. if domain in (ZZ, QQ):
  139. element_kind = NumberKind
  140. elif domain == EXRAW:
  141. kinds = set(e.kind for e in self.values())
  142. if len(kinds) == 1:
  143. [element_kind] = kinds
  144. else:
  145. element_kind = UndefinedKind
  146. else: # pragma: no cover
  147. raise RuntimeError("Domain should only be ZZ, QQ or EXRAW")
  148. return MatrixKind(element_kind)
  149. def _eval_has(self, *patterns):
  150. # if the matrix has any zeros, see if S.Zero
  151. # has the pattern. If _smat is full length,
  152. # the matrix has no zeros.
  153. zhas = False
  154. dok = self.todok()
  155. if len(dok) != self.rows*self.cols:
  156. zhas = S.Zero.has(*patterns)
  157. return zhas or any(value.has(*patterns) for value in dok.values())
  158. def _eval_is_Identity(self):
  159. if not all(self[i, i] == 1 for i in range(self.rows)):
  160. return False
  161. return len(self.todok()) == self.rows
  162. def _eval_is_symmetric(self, simpfunc):
  163. diff = (self - self.T).applyfunc(simpfunc)
  164. return len(diff.values()) == 0
  165. def _eval_transpose(self):
  166. """Returns the transposed SparseMatrix of this SparseMatrix.
  167. Examples
  168. ========
  169. >>> from sympy import SparseMatrix
  170. >>> a = SparseMatrix(((1, 2), (3, 4)))
  171. >>> a
  172. Matrix([
  173. [1, 2],
  174. [3, 4]])
  175. >>> a.T
  176. Matrix([
  177. [1, 3],
  178. [2, 4]])
  179. """
  180. return self._fromrep(self._rep.transpose())
  181. def _eval_col_join(self, other):
  182. return self._fromrep(self._rep.vstack(other._rep))
  183. def _eval_row_join(self, other):
  184. return self._fromrep(self._rep.hstack(other._rep))
  185. def _eval_extract(self, rowsList, colsList):
  186. return self._fromrep(self._rep.extract(rowsList, colsList))
  187. def __getitem__(self, key):
  188. return _getitem_RepMatrix(self, key)
  189. @classmethod
  190. def _eval_zeros(cls, rows, cols):
  191. rep = DomainMatrix.zeros((rows, cols), ZZ)
  192. return cls._fromrep(rep)
  193. @classmethod
  194. def _eval_eye(cls, rows, cols):
  195. rep = DomainMatrix.eye((rows, cols), ZZ)
  196. return cls._fromrep(rep)
  197. def _eval_add(self, other):
  198. return classof(self, other)._fromrep(self._rep + other._rep)
  199. def _eval_matrix_mul(self, other):
  200. return classof(self, other)._fromrep(self._rep * other._rep)
  201. def _eval_matrix_mul_elementwise(self, other):
  202. selfrep, otherrep = self._rep.unify(other._rep)
  203. newrep = selfrep.mul_elementwise(otherrep)
  204. return classof(self, other)._fromrep(newrep)
  205. def _eval_scalar_mul(self, other):
  206. rep, other = self._unify_element_sympy(self._rep, other)
  207. return self._fromrep(rep.scalarmul(other))
  208. def _eval_scalar_rmul(self, other):
  209. rep, other = self._unify_element_sympy(self._rep, other)
  210. return self._fromrep(rep.rscalarmul(other))
  211. def _eval_Abs(self):
  212. return self._fromrep(self._rep.applyfunc(abs))
  213. def _eval_conjugate(self):
  214. rep = self._rep
  215. domain = rep.domain
  216. if domain in (ZZ, QQ):
  217. return self.copy()
  218. else:
  219. return self._fromrep(rep.applyfunc(lambda e: e.conjugate()))
  220. def equals(self, other, failing_expression=False):
  221. """Applies ``equals`` to corresponding elements of the matrices,
  222. trying to prove that the elements are equivalent, returning True
  223. if they are, False if any pair is not, and None (or the first
  224. failing expression if failing_expression is True) if it cannot
  225. be decided if the expressions are equivalent or not. This is, in
  226. general, an expensive operation.
  227. Examples
  228. ========
  229. >>> from sympy import Matrix
  230. >>> from sympy.abc import x
  231. >>> A = Matrix([x*(x - 1), 0])
  232. >>> B = Matrix([x**2 - x, 0])
  233. >>> A == B
  234. False
  235. >>> A.simplify() == B.simplify()
  236. True
  237. >>> A.equals(B)
  238. True
  239. >>> A.equals(2)
  240. False
  241. See Also
  242. ========
  243. sympy.core.expr.Expr.equals
  244. """
  245. if self.shape != getattr(other, 'shape', None):
  246. return False
  247. rv = True
  248. for i in range(self.rows):
  249. for j in range(self.cols):
  250. ans = self[i, j].equals(other[i, j], failing_expression)
  251. if ans is False:
  252. return False
  253. elif ans is not True and rv is True:
  254. rv = ans
  255. return rv
  256. class MutableRepMatrix(RepMatrix):
  257. """Mutable matrix based on DomainMatrix as the internal representation"""
  258. #
  259. # MutableRepMatrix is a subclass of RepMatrix that adds/overrides methods
  260. # to make the instances mutable. MutableRepMatrix is a superclass for both
  261. # MutableDenseMatrix and MutableSparseMatrix.
  262. #
  263. is_zero = False
  264. def __new__(cls, *args, **kwargs):
  265. return cls._new(*args, **kwargs)
  266. @classmethod
  267. def _new(cls, *args, copy=True, **kwargs):
  268. if copy is False:
  269. # The input was rows, cols, [list].
  270. # It should be used directly without creating a copy.
  271. if len(args) != 3:
  272. raise TypeError("'copy=False' requires a matrix be initialized as rows,cols,[list]")
  273. rows, cols, flat_list = args
  274. else:
  275. rows, cols, flat_list = cls._handle_creation_inputs(*args, **kwargs)
  276. flat_list = list(flat_list) # create a shallow copy
  277. rep = cls._flat_list_to_DomainMatrix(rows, cols, flat_list)
  278. return cls._fromrep(rep)
  279. @classmethod
  280. def _fromrep(cls, rep):
  281. obj = super().__new__(cls)
  282. obj.rows, obj.cols = rep.shape
  283. obj._rep = rep
  284. return obj
  285. def copy(self):
  286. return self._fromrep(self._rep.copy())
  287. def as_mutable(self):
  288. return self.copy()
  289. def __setitem__(self, key, value):
  290. """
  291. Examples
  292. ========
  293. >>> from sympy import Matrix, I, zeros, ones
  294. >>> m = Matrix(((1, 2+I), (3, 4)))
  295. >>> m
  296. Matrix([
  297. [1, 2 + I],
  298. [3, 4]])
  299. >>> m[1, 0] = 9
  300. >>> m
  301. Matrix([
  302. [1, 2 + I],
  303. [9, 4]])
  304. >>> m[1, 0] = [[0, 1]]
  305. To replace row r you assign to position r*m where m
  306. is the number of columns:
  307. >>> M = zeros(4)
  308. >>> m = M.cols
  309. >>> M[3*m] = ones(1, m)*2; M
  310. Matrix([
  311. [0, 0, 0, 0],
  312. [0, 0, 0, 0],
  313. [0, 0, 0, 0],
  314. [2, 2, 2, 2]])
  315. And to replace column c you can assign to position c:
  316. >>> M[2] = ones(m, 1)*4; M
  317. Matrix([
  318. [0, 0, 4, 0],
  319. [0, 0, 4, 0],
  320. [0, 0, 4, 0],
  321. [2, 2, 4, 2]])
  322. """
  323. rv = self._setitem(key, value)
  324. if rv is not None:
  325. i, j, value = rv
  326. self._rep, value = self._unify_element_sympy(self._rep, value)
  327. self._rep.rep.setitem(i, j, value)
  328. def _eval_col_del(self, col):
  329. self._rep = DomainMatrix.hstack(self._rep[:,:col], self._rep[:,col+1:])
  330. self.cols -= 1
  331. def _eval_row_del(self, row):
  332. self._rep = DomainMatrix.vstack(self._rep[:row,:], self._rep[row+1:, :])
  333. self.rows -= 1
  334. def _eval_col_insert(self, col, other):
  335. other = self._new(other)
  336. return self.hstack(self[:,:col], other, self[:,col:])
  337. def _eval_row_insert(self, row, other):
  338. other = self._new(other)
  339. return self.vstack(self[:row,:], other, self[row:,:])
  340. def col_op(self, j, f):
  341. """In-place operation on col j using two-arg functor whose args are
  342. interpreted as (self[i, j], i).
  343. Examples
  344. ========
  345. >>> from sympy import eye
  346. >>> M = eye(3)
  347. >>> M.col_op(1, lambda v, i: v + 2*M[i, 0]); M
  348. Matrix([
  349. [1, 2, 0],
  350. [0, 1, 0],
  351. [0, 0, 1]])
  352. See Also
  353. ========
  354. col
  355. row_op
  356. """
  357. for i in range(self.rows):
  358. self[i, j] = f(self[i, j], i)
  359. def col_swap(self, i, j):
  360. """Swap the two given columns of the matrix in-place.
  361. Examples
  362. ========
  363. >>> from sympy import Matrix
  364. >>> M = Matrix([[1, 0], [1, 0]])
  365. >>> M
  366. Matrix([
  367. [1, 0],
  368. [1, 0]])
  369. >>> M.col_swap(0, 1)
  370. >>> M
  371. Matrix([
  372. [0, 1],
  373. [0, 1]])
  374. See Also
  375. ========
  376. col
  377. row_swap
  378. """
  379. for k in range(0, self.rows):
  380. self[k, i], self[k, j] = self[k, j], self[k, i]
  381. def row_op(self, i, f):
  382. """In-place operation on row ``i`` using two-arg functor whose args are
  383. interpreted as ``(self[i, j], j)``.
  384. Examples
  385. ========
  386. >>> from sympy import eye
  387. >>> M = eye(3)
  388. >>> M.row_op(1, lambda v, j: v + 2*M[0, j]); M
  389. Matrix([
  390. [1, 0, 0],
  391. [2, 1, 0],
  392. [0, 0, 1]])
  393. See Also
  394. ========
  395. row
  396. zip_row_op
  397. col_op
  398. """
  399. for j in range(self.cols):
  400. self[i, j] = f(self[i, j], j)
  401. def row_swap(self, i, j):
  402. """Swap the two given rows of the matrix in-place.
  403. Examples
  404. ========
  405. >>> from sympy import Matrix
  406. >>> M = Matrix([[0, 1], [1, 0]])
  407. >>> M
  408. Matrix([
  409. [0, 1],
  410. [1, 0]])
  411. >>> M.row_swap(0, 1)
  412. >>> M
  413. Matrix([
  414. [1, 0],
  415. [0, 1]])
  416. See Also
  417. ========
  418. row
  419. col_swap
  420. """
  421. for k in range(0, self.cols):
  422. self[i, k], self[j, k] = self[j, k], self[i, k]
  423. def zip_row_op(self, i, k, f):
  424. """In-place operation on row ``i`` using two-arg functor whose args are
  425. interpreted as ``(self[i, j], self[k, j])``.
  426. Examples
  427. ========
  428. >>> from sympy import eye
  429. >>> M = eye(3)
  430. >>> M.zip_row_op(1, 0, lambda v, u: v + 2*u); M
  431. Matrix([
  432. [1, 0, 0],
  433. [2, 1, 0],
  434. [0, 0, 1]])
  435. See Also
  436. ========
  437. row
  438. row_op
  439. col_op
  440. """
  441. for j in range(self.cols):
  442. self[i, j] = f(self[i, j], self[k, j])
  443. def copyin_list(self, key, value):
  444. """Copy in elements from a list.
  445. Parameters
  446. ==========
  447. key : slice
  448. The section of this matrix to replace.
  449. value : iterable
  450. The iterable to copy values from.
  451. Examples
  452. ========
  453. >>> from sympy import eye
  454. >>> I = eye(3)
  455. >>> I[:2, 0] = [1, 2] # col
  456. >>> I
  457. Matrix([
  458. [1, 0, 0],
  459. [2, 1, 0],
  460. [0, 0, 1]])
  461. >>> I[1, :2] = [[3, 4]]
  462. >>> I
  463. Matrix([
  464. [1, 0, 0],
  465. [3, 4, 0],
  466. [0, 0, 1]])
  467. See Also
  468. ========
  469. copyin_matrix
  470. """
  471. if not is_sequence(value):
  472. raise TypeError("`value` must be an ordered iterable, not %s." % type(value))
  473. return self.copyin_matrix(key, type(self)(value))
  474. def copyin_matrix(self, key, value):
  475. """Copy in values from a matrix into the given bounds.
  476. Parameters
  477. ==========
  478. key : slice
  479. The section of this matrix to replace.
  480. value : Matrix
  481. The matrix to copy values from.
  482. Examples
  483. ========
  484. >>> from sympy import Matrix, eye
  485. >>> M = Matrix([[0, 1], [2, 3], [4, 5]])
  486. >>> I = eye(3)
  487. >>> I[:3, :2] = M
  488. >>> I
  489. Matrix([
  490. [0, 1, 0],
  491. [2, 3, 0],
  492. [4, 5, 1]])
  493. >>> I[0, 1] = M
  494. >>> I
  495. Matrix([
  496. [0, 0, 1],
  497. [2, 2, 3],
  498. [4, 4, 5]])
  499. See Also
  500. ========
  501. copyin_list
  502. """
  503. rlo, rhi, clo, chi = self.key2bounds(key)
  504. shape = value.shape
  505. dr, dc = rhi - rlo, chi - clo
  506. if shape != (dr, dc):
  507. raise ShapeError(filldedent("The Matrix `value` doesn't have the "
  508. "same dimensions "
  509. "as the in sub-Matrix given by `key`."))
  510. for i in range(value.rows):
  511. for j in range(value.cols):
  512. self[i + rlo, j + clo] = value[i, j]
  513. def fill(self, value):
  514. """Fill self with the given value.
  515. Notes
  516. =====
  517. Unless many values are going to be deleted (i.e. set to zero)
  518. this will create a matrix that is slower than a dense matrix in
  519. operations.
  520. Examples
  521. ========
  522. >>> from sympy import SparseMatrix
  523. >>> M = SparseMatrix.zeros(3); M
  524. Matrix([
  525. [0, 0, 0],
  526. [0, 0, 0],
  527. [0, 0, 0]])
  528. >>> M.fill(1); M
  529. Matrix([
  530. [1, 1, 1],
  531. [1, 1, 1],
  532. [1, 1, 1]])
  533. See Also
  534. ========
  535. zeros
  536. ones
  537. """
  538. value = _sympify(value)
  539. if not value:
  540. self._rep = DomainMatrix.zeros(self.shape, EXRAW)
  541. else:
  542. elements_dod = {i: {j: value for j in range(self.cols)} for i in range(self.rows)}
  543. self._rep = DomainMatrix(elements_dod, self.shape, EXRAW)
  544. def _getitem_RepMatrix(self, key):
  545. """Return portion of self defined by key. If the key involves a slice
  546. then a list will be returned (if key is a single slice) or a matrix
  547. (if key was a tuple involving a slice).
  548. Examples
  549. ========
  550. >>> from sympy import Matrix, I
  551. >>> m = Matrix([
  552. ... [1, 2 + I],
  553. ... [3, 4 ]])
  554. If the key is a tuple that doesn't involve a slice then that element
  555. is returned:
  556. >>> m[1, 0]
  557. 3
  558. When a tuple key involves a slice, a matrix is returned. Here, the
  559. first column is selected (all rows, column 0):
  560. >>> m[:, 0]
  561. Matrix([
  562. [1],
  563. [3]])
  564. If the slice is not a tuple then it selects from the underlying
  565. list of elements that are arranged in row order and a list is
  566. returned if a slice is involved:
  567. >>> m[0]
  568. 1
  569. >>> m[::2]
  570. [1, 3]
  571. """
  572. if isinstance(key, tuple):
  573. i, j = key
  574. try:
  575. return self._rep.getitem_sympy(index_(i), index_(j))
  576. except (TypeError, IndexError):
  577. if (isinstance(i, Expr) and not i.is_number) or (isinstance(j, Expr) and not j.is_number):
  578. if ((j < 0) is True) or ((j >= self.shape[1]) is True) or\
  579. ((i < 0) is True) or ((i >= self.shape[0]) is True):
  580. raise ValueError("index out of boundary")
  581. from sympy.matrices.expressions.matexpr import MatrixElement
  582. return MatrixElement(self, i, j)
  583. if isinstance(i, slice):
  584. i = range(self.rows)[i]
  585. elif is_sequence(i):
  586. pass
  587. else:
  588. i = [i]
  589. if isinstance(j, slice):
  590. j = range(self.cols)[j]
  591. elif is_sequence(j):
  592. pass
  593. else:
  594. j = [j]
  595. return self.extract(i, j)
  596. else:
  597. # Index/slice like a flattened list
  598. rows, cols = self.shape
  599. # Raise the appropriate exception:
  600. if not rows * cols:
  601. return [][key]
  602. rep = self._rep.rep
  603. domain = rep.domain
  604. is_slice = isinstance(key, slice)
  605. if is_slice:
  606. values = [rep.getitem(*divmod(n, cols)) for n in range(rows * cols)[key]]
  607. else:
  608. values = [rep.getitem(*divmod(index_(key), cols))]
  609. if domain != EXRAW:
  610. to_sympy = domain.to_sympy
  611. values = [to_sympy(val) for val in values]
  612. if is_slice:
  613. return values
  614. else:
  615. return values[0]