Coverage for /usr/lib/python3/dist-packages/sympy/matrices/repmatrix.py: 37%

271 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

1from collections import defaultdict 

2 

3from operator import index as index_ 

4 

5from sympy.core.expr import Expr 

6from sympy.core.kind import Kind, NumberKind, UndefinedKind 

7from sympy.core.numbers import Integer, Rational 

8from sympy.core.sympify import _sympify, SympifyError 

9from sympy.core.singleton import S 

10from sympy.polys.domains import ZZ, QQ, EXRAW 

11from sympy.polys.matrices import DomainMatrix 

12from sympy.utilities.exceptions import sympy_deprecation_warning 

13from sympy.utilities.iterables import is_sequence 

14from sympy.utilities.misc import filldedent 

15 

16from .common import classof 

17from .matrices import MatrixBase, MatrixKind, ShapeError 

18 

19 

20class RepMatrix(MatrixBase): 

21 """Matrix implementation based on DomainMatrix as an internal representation. 

22 

23 The RepMatrix class is a superclass for Matrix, ImmutableMatrix, 

24 SparseMatrix and ImmutableSparseMatrix which are the main usable matrix 

25 classes in SymPy. Most methods on this class are simply forwarded to 

26 DomainMatrix. 

27 """ 

28 

29 # 

30 # MatrixBase is the common superclass for all of the usable explicit matrix 

31 # classes in SymPy. The idea is that MatrixBase is an abstract class though 

32 # and that subclasses will implement the lower-level methods. 

33 # 

34 # RepMatrix is a subclass of MatrixBase that uses DomainMatrix as an 

35 # internal representation and delegates lower-level methods to 

36 # DomainMatrix. All of SymPy's standard explicit matrix classes subclass 

37 # RepMatrix and so use DomainMatrix internally. 

38 # 

39 # A RepMatrix uses an internal DomainMatrix with the domain set to ZZ, QQ 

40 # or EXRAW. The EXRAW domain is equivalent to the previous implementation 

41 # of Matrix that used Expr for the elements. The ZZ and QQ domains are used 

42 # when applicable just because they are compatible with the previous 

43 # implementation but are much more efficient. Other domains such as QQ[x] 

44 # are not used because they differ from Expr in some way (e.g. automatic 

45 # expansion of powers and products). 

46 # 

47 

48 _rep: DomainMatrix 

49 

50 def __eq__(self, other): 

51 # Skip sympify for mutable matrices... 

52 if not isinstance(other, RepMatrix): 

53 try: 

54 other = _sympify(other) 

55 except SympifyError: 

56 return NotImplemented 

57 if not isinstance(other, RepMatrix): 

58 return NotImplemented 

59 

60 return self._rep.unify_eq(other._rep) 

61 

62 @classmethod 

63 def _unify_element_sympy(cls, rep, element): 

64 domain = rep.domain 

65 element = _sympify(element) 

66 

67 if domain != EXRAW: 

68 # The domain can only be ZZ, QQ or EXRAW 

69 if element.is_Integer: 

70 new_domain = domain 

71 elif element.is_Rational: 

72 new_domain = QQ 

73 else: 

74 new_domain = EXRAW 

75 

76 # XXX: This converts the domain for all elements in the matrix 

77 # which can be slow. This happens e.g. if __setitem__ changes one 

78 # element to something that does not fit in the domain 

79 if new_domain != domain: 

80 rep = rep.convert_to(new_domain) 

81 domain = new_domain 

82 

83 if domain != EXRAW: 

84 element = new_domain.from_sympy(element) 

85 

86 if domain == EXRAW and not isinstance(element, Expr): 

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=4, 

97 ) 

98 

99 return rep, element 

100 

101 @classmethod 

102 def _dod_to_DomainMatrix(cls, rows, cols, dod, types): 

103 

104 if not all(issubclass(typ, Expr) for typ in types): 

105 sympy_deprecation_warning( 

106 """ 

107 non-Expr objects in a Matrix is deprecated. Matrix represents 

108 a mathematical matrix. To represent a container of non-numeric 

109 entities, Use a list of lists, TableForm, NumPy array, or some 

110 other data structure instead. 

111 """, 

112 deprecated_since_version="1.9", 

113 active_deprecations_target="deprecated-non-expr-in-matrix", 

114 stacklevel=6, 

115 ) 

116 

117 rep = DomainMatrix(dod, (rows, cols), EXRAW) 

118 

119 if all(issubclass(typ, Rational) for typ in types): 

120 if all(issubclass(typ, Integer) for typ in types): 

121 rep = rep.convert_to(ZZ) 

122 else: 

123 rep = rep.convert_to(QQ) 

124 

125 return rep 

126 

127 @classmethod 

128 def _flat_list_to_DomainMatrix(cls, rows, cols, flat_list): 

129 

130 elements_dod = defaultdict(dict) 

131 for n, element in enumerate(flat_list): 

132 if element != 0: 

133 i, j = divmod(n, cols) 

134 elements_dod[i][j] = element 

135 

136 types = set(map(type, flat_list)) 

137 

138 rep = cls._dod_to_DomainMatrix(rows, cols, elements_dod, types) 

139 return rep 

140 

141 @classmethod 

142 def _smat_to_DomainMatrix(cls, rows, cols, smat): 

143 

144 elements_dod = defaultdict(dict) 

145 for (i, j), element in smat.items(): 

146 if element != 0: 

147 elements_dod[i][j] = element 

148 

149 types = set(map(type, smat.values())) 

150 

151 rep = cls._dod_to_DomainMatrix(rows, cols, elements_dod, types) 

152 return rep 

153 

154 def flat(self): 

155 return self._rep.to_sympy().to_list_flat() 

156 

157 def _eval_tolist(self): 

158 return self._rep.to_sympy().to_list() 

159 

160 def _eval_todok(self): 

161 return self._rep.to_sympy().to_dok() 

162 

163 def _eval_values(self): 

164 return list(self.todok().values()) 

165 

166 def copy(self): 

167 return self._fromrep(self._rep.copy()) 

168 

169 @property 

170 def kind(self) -> MatrixKind: 

171 domain = self._rep.domain 

172 element_kind: Kind 

173 if domain in (ZZ, QQ): 

174 element_kind = NumberKind 

175 elif domain == EXRAW: 

176 kinds = {e.kind for e in self.values()} 

177 if len(kinds) == 1: 

178 [element_kind] = kinds 

179 else: 

180 element_kind = UndefinedKind 

181 else: # pragma: no cover 

182 raise RuntimeError("Domain should only be ZZ, QQ or EXRAW") 

183 return MatrixKind(element_kind) 

184 

185 def _eval_has(self, *patterns): 

186 # if the matrix has any zeros, see if S.Zero 

187 # has the pattern. If _smat is full length, 

188 # the matrix has no zeros. 

189 zhas = False 

190 dok = self.todok() 

191 if len(dok) != self.rows*self.cols: 

192 zhas = S.Zero.has(*patterns) 

193 return zhas or any(value.has(*patterns) for value in dok.values()) 

194 

195 def _eval_is_Identity(self): 

196 if not all(self[i, i] == 1 for i in range(self.rows)): 

197 return False 

198 return len(self.todok()) == self.rows 

199 

200 def _eval_is_symmetric(self, simpfunc): 

201 diff = (self - self.T).applyfunc(simpfunc) 

202 return len(diff.values()) == 0 

203 

204 def _eval_transpose(self): 

205 """Returns the transposed SparseMatrix of this SparseMatrix. 

206 

207 Examples 

208 ======== 

209 

210 >>> from sympy import SparseMatrix 

211 >>> a = SparseMatrix(((1, 2), (3, 4))) 

212 >>> a 

213 Matrix([ 

214 [1, 2], 

215 [3, 4]]) 

216 >>> a.T 

217 Matrix([ 

218 [1, 3], 

219 [2, 4]]) 

220 """ 

221 return self._fromrep(self._rep.transpose()) 

222 

223 def _eval_col_join(self, other): 

224 return self._fromrep(self._rep.vstack(other._rep)) 

225 

226 def _eval_row_join(self, other): 

227 return self._fromrep(self._rep.hstack(other._rep)) 

228 

229 def _eval_extract(self, rowsList, colsList): 

230 return self._fromrep(self._rep.extract(rowsList, colsList)) 

231 

232 def __getitem__(self, key): 

233 return _getitem_RepMatrix(self, key) 

234 

235 @classmethod 

236 def _eval_zeros(cls, rows, cols): 

237 rep = DomainMatrix.zeros((rows, cols), ZZ) 

238 return cls._fromrep(rep) 

239 

240 @classmethod 

241 def _eval_eye(cls, rows, cols): 

242 rep = DomainMatrix.eye((rows, cols), ZZ) 

243 return cls._fromrep(rep) 

244 

245 def _eval_add(self, other): 

246 return classof(self, other)._fromrep(self._rep + other._rep) 

247 

248 def _eval_matrix_mul(self, other): 

249 return classof(self, other)._fromrep(self._rep * other._rep) 

250 

251 def _eval_matrix_mul_elementwise(self, other): 

252 selfrep, otherrep = self._rep.unify(other._rep) 

253 newrep = selfrep.mul_elementwise(otherrep) 

254 return classof(self, other)._fromrep(newrep) 

255 

256 def _eval_scalar_mul(self, other): 

257 rep, other = self._unify_element_sympy(self._rep, other) 

258 return self._fromrep(rep.scalarmul(other)) 

259 

260 def _eval_scalar_rmul(self, other): 

261 rep, other = self._unify_element_sympy(self._rep, other) 

262 return self._fromrep(rep.rscalarmul(other)) 

263 

264 def _eval_Abs(self): 

265 return self._fromrep(self._rep.applyfunc(abs)) 

266 

267 def _eval_conjugate(self): 

268 rep = self._rep 

269 domain = rep.domain 

270 if domain in (ZZ, QQ): 

271 return self.copy() 

272 else: 

273 return self._fromrep(rep.applyfunc(lambda e: e.conjugate())) 

274 

275 def equals(self, other, failing_expression=False): 

276 """Applies ``equals`` to corresponding elements of the matrices, 

277 trying to prove that the elements are equivalent, returning True 

278 if they are, False if any pair is not, and None (or the first 

279 failing expression if failing_expression is True) if it cannot 

280 be decided if the expressions are equivalent or not. This is, in 

281 general, an expensive operation. 

282 

283 Examples 

284 ======== 

285 

286 >>> from sympy import Matrix 

287 >>> from sympy.abc import x 

288 >>> A = Matrix([x*(x - 1), 0]) 

289 >>> B = Matrix([x**2 - x, 0]) 

290 >>> A == B 

291 False 

292 >>> A.simplify() == B.simplify() 

293 True 

294 >>> A.equals(B) 

295 True 

296 >>> A.equals(2) 

297 False 

298 

299 See Also 

300 ======== 

301 sympy.core.expr.Expr.equals 

302 """ 

303 if self.shape != getattr(other, 'shape', None): 

304 return False 

305 

306 rv = True 

307 for i in range(self.rows): 

308 for j in range(self.cols): 

309 ans = self[i, j].equals(other[i, j], failing_expression) 

310 if ans is False: 

311 return False 

312 elif ans is not True and rv is True: 

313 rv = ans 

314 return rv 

315 

316 

317class MutableRepMatrix(RepMatrix): 

318 """Mutable matrix based on DomainMatrix as the internal representation""" 

319 

320 # 

321 # MutableRepMatrix is a subclass of RepMatrix that adds/overrides methods 

322 # to make the instances mutable. MutableRepMatrix is a superclass for both 

323 # MutableDenseMatrix and MutableSparseMatrix. 

324 # 

325 

326 is_zero = False 

327 

328 def __new__(cls, *args, **kwargs): 

329 return cls._new(*args, **kwargs) 

330 

331 @classmethod 

332 def _new(cls, *args, copy=True, **kwargs): 

333 if copy is False: 

334 # The input was rows, cols, [list]. 

335 # It should be used directly without creating a copy. 

336 if len(args) != 3: 

337 raise TypeError("'copy=False' requires a matrix be initialized as rows,cols,[list]") 

338 rows, cols, flat_list = args 

339 else: 

340 rows, cols, flat_list = cls._handle_creation_inputs(*args, **kwargs) 

341 flat_list = list(flat_list) # create a shallow copy 

342 

343 rep = cls._flat_list_to_DomainMatrix(rows, cols, flat_list) 

344 

345 return cls._fromrep(rep) 

346 

347 @classmethod 

348 def _fromrep(cls, rep): 

349 obj = super().__new__(cls) 

350 obj.rows, obj.cols = rep.shape 

351 obj._rep = rep 

352 return obj 

353 

354 def copy(self): 

355 return self._fromrep(self._rep.copy()) 

356 

357 def as_mutable(self): 

358 return self.copy() 

359 

360 def __setitem__(self, key, value): 

361 """ 

362 

363 Examples 

364 ======== 

365 

366 >>> from sympy import Matrix, I, zeros, ones 

367 >>> m = Matrix(((1, 2+I), (3, 4))) 

368 >>> m 

369 Matrix([ 

370 [1, 2 + I], 

371 [3, 4]]) 

372 >>> m[1, 0] = 9 

373 >>> m 

374 Matrix([ 

375 [1, 2 + I], 

376 [9, 4]]) 

377 >>> m[1, 0] = [[0, 1]] 

378 

379 To replace row r you assign to position r*m where m 

380 is the number of columns: 

381 

382 >>> M = zeros(4) 

383 >>> m = M.cols 

384 >>> M[3*m] = ones(1, m)*2; M 

385 Matrix([ 

386 [0, 0, 0, 0], 

387 [0, 0, 0, 0], 

388 [0, 0, 0, 0], 

389 [2, 2, 2, 2]]) 

390 

391 And to replace column c you can assign to position c: 

392 

393 >>> M[2] = ones(m, 1)*4; M 

394 Matrix([ 

395 [0, 0, 4, 0], 

396 [0, 0, 4, 0], 

397 [0, 0, 4, 0], 

398 [2, 2, 4, 2]]) 

399 """ 

400 rv = self._setitem(key, value) 

401 if rv is not None: 

402 i, j, value = rv 

403 self._rep, value = self._unify_element_sympy(self._rep, value) 

404 self._rep.rep.setitem(i, j, value) 

405 

406 def _eval_col_del(self, col): 

407 self._rep = DomainMatrix.hstack(self._rep[:,:col], self._rep[:,col+1:]) 

408 self.cols -= 1 

409 

410 def _eval_row_del(self, row): 

411 self._rep = DomainMatrix.vstack(self._rep[:row,:], self._rep[row+1:, :]) 

412 self.rows -= 1 

413 

414 def _eval_col_insert(self, col, other): 

415 other = self._new(other) 

416 return self.hstack(self[:,:col], other, self[:,col:]) 

417 

418 def _eval_row_insert(self, row, other): 

419 other = self._new(other) 

420 return self.vstack(self[:row,:], other, self[row:,:]) 

421 

422 def col_op(self, j, f): 

423 """In-place operation on col j using two-arg functor whose args are 

424 interpreted as (self[i, j], i). 

425 

426 Examples 

427 ======== 

428 

429 >>> from sympy import eye 

430 >>> M = eye(3) 

431 >>> M.col_op(1, lambda v, i: v + 2*M[i, 0]); M 

432 Matrix([ 

433 [1, 2, 0], 

434 [0, 1, 0], 

435 [0, 0, 1]]) 

436 

437 See Also 

438 ======== 

439 col 

440 row_op 

441 """ 

442 for i in range(self.rows): 

443 self[i, j] = f(self[i, j], i) 

444 

445 def col_swap(self, i, j): 

446 """Swap the two given columns of the matrix in-place. 

447 

448 Examples 

449 ======== 

450 

451 >>> from sympy import Matrix 

452 >>> M = Matrix([[1, 0], [1, 0]]) 

453 >>> M 

454 Matrix([ 

455 [1, 0], 

456 [1, 0]]) 

457 >>> M.col_swap(0, 1) 

458 >>> M 

459 Matrix([ 

460 [0, 1], 

461 [0, 1]]) 

462 

463 See Also 

464 ======== 

465 

466 col 

467 row_swap 

468 """ 

469 for k in range(0, self.rows): 

470 self[k, i], self[k, j] = self[k, j], self[k, i] 

471 

472 def row_op(self, i, f): 

473 """In-place operation on row ``i`` using two-arg functor whose args are 

474 interpreted as ``(self[i, j], j)``. 

475 

476 Examples 

477 ======== 

478 

479 >>> from sympy import eye 

480 >>> M = eye(3) 

481 >>> M.row_op(1, lambda v, j: v + 2*M[0, j]); M 

482 Matrix([ 

483 [1, 0, 0], 

484 [2, 1, 0], 

485 [0, 0, 1]]) 

486 

487 See Also 

488 ======== 

489 row 

490 zip_row_op 

491 col_op 

492 

493 """ 

494 for j in range(self.cols): 

495 self[i, j] = f(self[i, j], j) 

496 

497 def row_swap(self, i, j): 

498 """Swap the two given rows of the matrix in-place. 

499 

500 Examples 

501 ======== 

502 

503 >>> from sympy import Matrix 

504 >>> M = Matrix([[0, 1], [1, 0]]) 

505 >>> M 

506 Matrix([ 

507 [0, 1], 

508 [1, 0]]) 

509 >>> M.row_swap(0, 1) 

510 >>> M 

511 Matrix([ 

512 [1, 0], 

513 [0, 1]]) 

514 

515 See Also 

516 ======== 

517 

518 row 

519 col_swap 

520 """ 

521 for k in range(0, self.cols): 

522 self[i, k], self[j, k] = self[j, k], self[i, k] 

523 

524 def zip_row_op(self, i, k, f): 

525 """In-place operation on row ``i`` using two-arg functor whose args are 

526 interpreted as ``(self[i, j], self[k, j])``. 

527 

528 Examples 

529 ======== 

530 

531 >>> from sympy import eye 

532 >>> M = eye(3) 

533 >>> M.zip_row_op(1, 0, lambda v, u: v + 2*u); M 

534 Matrix([ 

535 [1, 0, 0], 

536 [2, 1, 0], 

537 [0, 0, 1]]) 

538 

539 See Also 

540 ======== 

541 row 

542 row_op 

543 col_op 

544 

545 """ 

546 for j in range(self.cols): 

547 self[i, j] = f(self[i, j], self[k, j]) 

548 

549 def copyin_list(self, key, value): 

550 """Copy in elements from a list. 

551 

552 Parameters 

553 ========== 

554 

555 key : slice 

556 The section of this matrix to replace. 

557 value : iterable 

558 The iterable to copy values from. 

559 

560 Examples 

561 ======== 

562 

563 >>> from sympy import eye 

564 >>> I = eye(3) 

565 >>> I[:2, 0] = [1, 2] # col 

566 >>> I 

567 Matrix([ 

568 [1, 0, 0], 

569 [2, 1, 0], 

570 [0, 0, 1]]) 

571 >>> I[1, :2] = [[3, 4]] 

572 >>> I 

573 Matrix([ 

574 [1, 0, 0], 

575 [3, 4, 0], 

576 [0, 0, 1]]) 

577 

578 See Also 

579 ======== 

580 

581 copyin_matrix 

582 """ 

583 if not is_sequence(value): 

584 raise TypeError("`value` must be an ordered iterable, not %s." % type(value)) 

585 return self.copyin_matrix(key, type(self)(value)) 

586 

587 def copyin_matrix(self, key, value): 

588 """Copy in values from a matrix into the given bounds. 

589 

590 Parameters 

591 ========== 

592 

593 key : slice 

594 The section of this matrix to replace. 

595 value : Matrix 

596 The matrix to copy values from. 

597 

598 Examples 

599 ======== 

600 

601 >>> from sympy import Matrix, eye 

602 >>> M = Matrix([[0, 1], [2, 3], [4, 5]]) 

603 >>> I = eye(3) 

604 >>> I[:3, :2] = M 

605 >>> I 

606 Matrix([ 

607 [0, 1, 0], 

608 [2, 3, 0], 

609 [4, 5, 1]]) 

610 >>> I[0, 1] = M 

611 >>> I 

612 Matrix([ 

613 [0, 0, 1], 

614 [2, 2, 3], 

615 [4, 4, 5]]) 

616 

617 See Also 

618 ======== 

619 

620 copyin_list 

621 """ 

622 rlo, rhi, clo, chi = self.key2bounds(key) 

623 shape = value.shape 

624 dr, dc = rhi - rlo, chi - clo 

625 if shape != (dr, dc): 

626 raise ShapeError(filldedent("The Matrix `value` doesn't have the " 

627 "same dimensions " 

628 "as the in sub-Matrix given by `key`.")) 

629 

630 for i in range(value.rows): 

631 for j in range(value.cols): 

632 self[i + rlo, j + clo] = value[i, j] 

633 

634 def fill(self, value): 

635 """Fill self with the given value. 

636 

637 Notes 

638 ===== 

639 

640 Unless many values are going to be deleted (i.e. set to zero) 

641 this will create a matrix that is slower than a dense matrix in 

642 operations. 

643 

644 Examples 

645 ======== 

646 

647 >>> from sympy import SparseMatrix 

648 >>> M = SparseMatrix.zeros(3); M 

649 Matrix([ 

650 [0, 0, 0], 

651 [0, 0, 0], 

652 [0, 0, 0]]) 

653 >>> M.fill(1); M 

654 Matrix([ 

655 [1, 1, 1], 

656 [1, 1, 1], 

657 [1, 1, 1]]) 

658 

659 See Also 

660 ======== 

661 

662 zeros 

663 ones 

664 """ 

665 value = _sympify(value) 

666 if not value: 

667 self._rep = DomainMatrix.zeros(self.shape, EXRAW) 

668 else: 

669 elements_dod = {i: {j: value for j in range(self.cols)} for i in range(self.rows)} 

670 self._rep = DomainMatrix(elements_dod, self.shape, EXRAW) 

671 

672 

673def _getitem_RepMatrix(self, key): 

674 """Return portion of self defined by key. If the key involves a slice 

675 then a list will be returned (if key is a single slice) or a matrix 

676 (if key was a tuple involving a slice). 

677 

678 Examples 

679 ======== 

680 

681 >>> from sympy import Matrix, I 

682 >>> m = Matrix([ 

683 ... [1, 2 + I], 

684 ... [3, 4 ]]) 

685 

686 If the key is a tuple that does not involve a slice then that element 

687 is returned: 

688 

689 >>> m[1, 0] 

690 3 

691 

692 When a tuple key involves a slice, a matrix is returned. Here, the 

693 first column is selected (all rows, column 0): 

694 

695 >>> m[:, 0] 

696 Matrix([ 

697 [1], 

698 [3]]) 

699 

700 If the slice is not a tuple then it selects from the underlying 

701 list of elements that are arranged in row order and a list is 

702 returned if a slice is involved: 

703 

704 >>> m[0] 

705 1 

706 >>> m[::2] 

707 [1, 3] 

708 """ 

709 if isinstance(key, tuple): 

710 i, j = key 

711 try: 

712 return self._rep.getitem_sympy(index_(i), index_(j)) 

713 except (TypeError, IndexError): 

714 if (isinstance(i, Expr) and not i.is_number) or (isinstance(j, Expr) and not j.is_number): 

715 if ((j < 0) is True) or ((j >= self.shape[1]) is True) or\ 

716 ((i < 0) is True) or ((i >= self.shape[0]) is True): 

717 raise ValueError("index out of boundary") 

718 from sympy.matrices.expressions.matexpr import MatrixElement 

719 return MatrixElement(self, i, j) 

720 

721 if isinstance(i, slice): 

722 i = range(self.rows)[i] 

723 elif is_sequence(i): 

724 pass 

725 else: 

726 i = [i] 

727 if isinstance(j, slice): 

728 j = range(self.cols)[j] 

729 elif is_sequence(j): 

730 pass 

731 else: 

732 j = [j] 

733 return self.extract(i, j) 

734 

735 else: 

736 # Index/slice like a flattened list 

737 rows, cols = self.shape 

738 

739 # Raise the appropriate exception: 

740 if not rows * cols: 

741 return [][key] 

742 

743 rep = self._rep.rep 

744 domain = rep.domain 

745 is_slice = isinstance(key, slice) 

746 

747 if is_slice: 

748 values = [rep.getitem(*divmod(n, cols)) for n in range(rows * cols)[key]] 

749 else: 

750 values = [rep.getitem(*divmod(index_(key), cols))] 

751 

752 if domain != EXRAW: 

753 to_sympy = domain.to_sympy 

754 values = [to_sympy(val) for val in values] 

755 

756 if is_slice: 

757 return values 

758 else: 

759 return values[0]