Coverage for /usr/lib/python3/dist-packages/sympy/printing/pycode.py: 38%

342 statements  

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

1""" 

2Python code printers 

3 

4This module contains Python code printers for plain Python as well as NumPy & SciPy enabled code. 

5""" 

6from collections import defaultdict 

7from itertools import chain 

8from sympy.core import S 

9from sympy.core.mod import Mod 

10from .precedence import precedence 

11from .codeprinter import CodePrinter 

12 

13_kw = { 

14 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 

15 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 

16 'is', 'lambda', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 

17 'with', 'yield', 'None', 'False', 'nonlocal', 'True' 

18} 

19 

20_known_functions = { 

21 'Abs': 'abs', 

22 'Min': 'min', 

23 'Max': 'max', 

24} 

25_known_functions_math = { 

26 'acos': 'acos', 

27 'acosh': 'acosh', 

28 'asin': 'asin', 

29 'asinh': 'asinh', 

30 'atan': 'atan', 

31 'atan2': 'atan2', 

32 'atanh': 'atanh', 

33 'ceiling': 'ceil', 

34 'cos': 'cos', 

35 'cosh': 'cosh', 

36 'erf': 'erf', 

37 'erfc': 'erfc', 

38 'exp': 'exp', 

39 'expm1': 'expm1', 

40 'factorial': 'factorial', 

41 'floor': 'floor', 

42 'gamma': 'gamma', 

43 'hypot': 'hypot', 

44 'loggamma': 'lgamma', 

45 'log': 'log', 

46 'ln': 'log', 

47 'log10': 'log10', 

48 'log1p': 'log1p', 

49 'log2': 'log2', 

50 'sin': 'sin', 

51 'sinh': 'sinh', 

52 'Sqrt': 'sqrt', 

53 'tan': 'tan', 

54 'tanh': 'tanh' 

55} # Not used from ``math``: [copysign isclose isfinite isinf isnan ldexp frexp pow modf 

56# radians trunc fmod fsum gcd degrees fabs] 

57_known_constants_math = { 

58 'Exp1': 'e', 

59 'Pi': 'pi', 

60 'E': 'e', 

61 'Infinity': 'inf', 

62 'NaN': 'nan', 

63 'ComplexInfinity': 'nan' 

64} 

65 

66def _print_known_func(self, expr): 

67 known = self.known_functions[expr.__class__.__name__] 

68 return '{name}({args})'.format(name=self._module_format(known), 

69 args=', '.join((self._print(arg) for arg in expr.args))) 

70 

71 

72def _print_known_const(self, expr): 

73 known = self.known_constants[expr.__class__.__name__] 

74 return self._module_format(known) 

75 

76 

77class AbstractPythonCodePrinter(CodePrinter): 

78 printmethod = "_pythoncode" 

79 language = "Python" 

80 reserved_words = _kw 

81 modules = None # initialized to a set in __init__ 

82 tab = ' ' 

83 _kf = dict(chain( 

84 _known_functions.items(), 

85 [(k, 'math.' + v) for k, v in _known_functions_math.items()] 

86 )) 

87 _kc = {k: 'math.'+v for k, v in _known_constants_math.items()} 

88 _operators = {'and': 'and', 'or': 'or', 'not': 'not'} 

89 _default_settings = dict( 

90 CodePrinter._default_settings, 

91 user_functions={}, 

92 precision=17, 

93 inline=True, 

94 fully_qualified_modules=True, 

95 contract=False, 

96 standard='python3', 

97 ) 

98 

99 def __init__(self, settings=None): 

100 super().__init__(settings) 

101 

102 # Python standard handler 

103 std = self._settings['standard'] 

104 if std is None: 

105 import sys 

106 std = 'python{}'.format(sys.version_info.major) 

107 if std != 'python3': 

108 raise ValueError('Only Python 3 is supported.') 

109 self.standard = std 

110 

111 self.module_imports = defaultdict(set) 

112 

113 # Known functions and constants handler 

114 self.known_functions = dict(self._kf, **(settings or {}).get( 

115 'user_functions', {})) 

116 self.known_constants = dict(self._kc, **(settings or {}).get( 

117 'user_constants', {})) 

118 

119 def _declare_number_const(self, name, value): 

120 return "%s = %s" % (name, value) 

121 

122 def _module_format(self, fqn, register=True): 

123 parts = fqn.split('.') 

124 if register and len(parts) > 1: 

125 self.module_imports['.'.join(parts[:-1])].add(parts[-1]) 

126 

127 if self._settings['fully_qualified_modules']: 

128 return fqn 

129 else: 

130 return fqn.split('(')[0].split('[')[0].split('.')[-1] 

131 

132 def _format_code(self, lines): 

133 return lines 

134 

135 def _get_statement(self, codestring): 

136 return "{}".format(codestring) 

137 

138 def _get_comment(self, text): 

139 return " # {}".format(text) 

140 

141 def _expand_fold_binary_op(self, op, args): 

142 """ 

143 This method expands a fold on binary operations. 

144 

145 ``functools.reduce`` is an example of a folded operation. 

146 

147 For example, the expression 

148 

149 `A + B + C + D` 

150 

151 is folded into 

152 

153 `((A + B) + C) + D` 

154 """ 

155 if len(args) == 1: 

156 return self._print(args[0]) 

157 else: 

158 return "%s(%s, %s)" % ( 

159 self._module_format(op), 

160 self._expand_fold_binary_op(op, args[:-1]), 

161 self._print(args[-1]), 

162 ) 

163 

164 def _expand_reduce_binary_op(self, op, args): 

165 """ 

166 This method expands a reductin on binary operations. 

167 

168 Notice: this is NOT the same as ``functools.reduce``. 

169 

170 For example, the expression 

171 

172 `A + B + C + D` 

173 

174 is reduced into: 

175 

176 `(A + B) + (C + D)` 

177 """ 

178 if len(args) == 1: 

179 return self._print(args[0]) 

180 else: 

181 N = len(args) 

182 Nhalf = N // 2 

183 return "%s(%s, %s)" % ( 

184 self._module_format(op), 

185 self._expand_reduce_binary_op(args[:Nhalf]), 

186 self._expand_reduce_binary_op(args[Nhalf:]), 

187 ) 

188 

189 def _print_NaN(self, expr): 

190 return "float('nan')" 

191 

192 def _print_Infinity(self, expr): 

193 return "float('inf')" 

194 

195 def _print_NegativeInfinity(self, expr): 

196 return "float('-inf')" 

197 

198 def _print_ComplexInfinity(self, expr): 

199 return self._print_NaN(expr) 

200 

201 def _print_Mod(self, expr): 

202 PREC = precedence(expr) 

203 return ('{} % {}'.format(*(self.parenthesize(x, PREC) for x in expr.args))) 

204 

205 def _print_Piecewise(self, expr): 

206 result = [] 

207 i = 0 

208 for arg in expr.args: 

209 e = arg.expr 

210 c = arg.cond 

211 if i == 0: 

212 result.append('(') 

213 result.append('(') 

214 result.append(self._print(e)) 

215 result.append(')') 

216 result.append(' if ') 

217 result.append(self._print(c)) 

218 result.append(' else ') 

219 i += 1 

220 result = result[:-1] 

221 if result[-1] == 'True': 

222 result = result[:-2] 

223 result.append(')') 

224 else: 

225 result.append(' else None)') 

226 return ''.join(result) 

227 

228 def _print_Relational(self, expr): 

229 "Relational printer for Equality and Unequality" 

230 op = { 

231 '==' :'equal', 

232 '!=' :'not_equal', 

233 '<' :'less', 

234 '<=' :'less_equal', 

235 '>' :'greater', 

236 '>=' :'greater_equal', 

237 } 

238 if expr.rel_op in op: 

239 lhs = self._print(expr.lhs) 

240 rhs = self._print(expr.rhs) 

241 return '({lhs} {op} {rhs})'.format(op=expr.rel_op, lhs=lhs, rhs=rhs) 

242 return super()._print_Relational(expr) 

243 

244 def _print_ITE(self, expr): 

245 from sympy.functions.elementary.piecewise import Piecewise 

246 return self._print(expr.rewrite(Piecewise)) 

247 

248 def _print_Sum(self, expr): 

249 loops = ( 

250 'for {i} in range({a}, {b}+1)'.format( 

251 i=self._print(i), 

252 a=self._print(a), 

253 b=self._print(b)) 

254 for i, a, b in expr.limits) 

255 return '(builtins.sum({function} {loops}))'.format( 

256 function=self._print(expr.function), 

257 loops=' '.join(loops)) 

258 

259 def _print_ImaginaryUnit(self, expr): 

260 return '1j' 

261 

262 def _print_KroneckerDelta(self, expr): 

263 a, b = expr.args 

264 

265 return '(1 if {a} == {b} else 0)'.format( 

266 a = self._print(a), 

267 b = self._print(b) 

268 ) 

269 

270 def _print_MatrixBase(self, expr): 

271 name = expr.__class__.__name__ 

272 func = self.known_functions.get(name, name) 

273 return "%s(%s)" % (func, self._print(expr.tolist())) 

274 

275 _print_SparseRepMatrix = \ 

276 _print_MutableSparseMatrix = \ 

277 _print_ImmutableSparseMatrix = \ 

278 _print_Matrix = \ 

279 _print_DenseMatrix = \ 

280 _print_MutableDenseMatrix = \ 

281 _print_ImmutableMatrix = \ 

282 _print_ImmutableDenseMatrix = \ 

283 lambda self, expr: self._print_MatrixBase(expr) 

284 

285 def _indent_codestring(self, codestring): 

286 return '\n'.join([self.tab + line for line in codestring.split('\n')]) 

287 

288 def _print_FunctionDefinition(self, fd): 

289 body = '\n'.join((self._print(arg) for arg in fd.body)) 

290 return "def {name}({parameters}):\n{body}".format( 

291 name=self._print(fd.name), 

292 parameters=', '.join([self._print(var.symbol) for var in fd.parameters]), 

293 body=self._indent_codestring(body) 

294 ) 

295 

296 def _print_While(self, whl): 

297 body = '\n'.join((self._print(arg) for arg in whl.body)) 

298 return "while {cond}:\n{body}".format( 

299 cond=self._print(whl.condition), 

300 body=self._indent_codestring(body) 

301 ) 

302 

303 def _print_Declaration(self, decl): 

304 return '%s = %s' % ( 

305 self._print(decl.variable.symbol), 

306 self._print(decl.variable.value) 

307 ) 

308 

309 def _print_Return(self, ret): 

310 arg, = ret.args 

311 return 'return %s' % self._print(arg) 

312 

313 def _print_Print(self, prnt): 

314 print_args = ', '.join((self._print(arg) for arg in prnt.print_args)) 

315 if prnt.format_string != None: # Must be '!= None', cannot be 'is not None' 

316 print_args = '{} % ({})'.format( 

317 self._print(prnt.format_string), print_args) 

318 if prnt.file != None: # Must be '!= None', cannot be 'is not None' 

319 print_args += ', file=%s' % self._print(prnt.file) 

320 

321 return 'print(%s)' % print_args 

322 

323 def _print_Stream(self, strm): 

324 if str(strm.name) == 'stdout': 

325 return self._module_format('sys.stdout') 

326 elif str(strm.name) == 'stderr': 

327 return self._module_format('sys.stderr') 

328 else: 

329 return self._print(strm.name) 

330 

331 def _print_NoneToken(self, arg): 

332 return 'None' 

333 

334 def _hprint_Pow(self, expr, rational=False, sqrt='math.sqrt'): 

335 """Printing helper function for ``Pow`` 

336 

337 Notes 

338 ===== 

339 

340 This preprocesses the ``sqrt`` as math formatter and prints division 

341 

342 Examples 

343 ======== 

344 

345 >>> from sympy import sqrt 

346 >>> from sympy.printing.pycode import PythonCodePrinter 

347 >>> from sympy.abc import x 

348 

349 Python code printer automatically looks up ``math.sqrt``. 

350 

351 >>> printer = PythonCodePrinter() 

352 >>> printer._hprint_Pow(sqrt(x), rational=True) 

353 'x**(1/2)' 

354 >>> printer._hprint_Pow(sqrt(x), rational=False) 

355 'math.sqrt(x)' 

356 >>> printer._hprint_Pow(1/sqrt(x), rational=True) 

357 'x**(-1/2)' 

358 >>> printer._hprint_Pow(1/sqrt(x), rational=False) 

359 '1/math.sqrt(x)' 

360 >>> printer._hprint_Pow(1/x, rational=False) 

361 '1/x' 

362 >>> printer._hprint_Pow(1/x, rational=True) 

363 'x**(-1)' 

364 

365 Using sqrt from numpy or mpmath 

366 

367 >>> printer._hprint_Pow(sqrt(x), sqrt='numpy.sqrt') 

368 'numpy.sqrt(x)' 

369 >>> printer._hprint_Pow(sqrt(x), sqrt='mpmath.sqrt') 

370 'mpmath.sqrt(x)' 

371 

372 See Also 

373 ======== 

374 

375 sympy.printing.str.StrPrinter._print_Pow 

376 """ 

377 PREC = precedence(expr) 

378 

379 if expr.exp == S.Half and not rational: 

380 func = self._module_format(sqrt) 

381 arg = self._print(expr.base) 

382 return '{func}({arg})'.format(func=func, arg=arg) 

383 

384 if expr.is_commutative and not rational: 

385 if -expr.exp is S.Half: 

386 func = self._module_format(sqrt) 

387 num = self._print(S.One) 

388 arg = self._print(expr.base) 

389 return f"{num}/{func}({arg})" 

390 if expr.exp is S.NegativeOne: 

391 num = self._print(S.One) 

392 arg = self.parenthesize(expr.base, PREC, strict=False) 

393 return f"{num}/{arg}" 

394 

395 

396 base_str = self.parenthesize(expr.base, PREC, strict=False) 

397 exp_str = self.parenthesize(expr.exp, PREC, strict=False) 

398 return "{}**{}".format(base_str, exp_str) 

399 

400 

401class ArrayPrinter: 

402 

403 def _arrayify(self, indexed): 

404 from sympy.tensor.array.expressions.from_indexed_to_array import convert_indexed_to_array 

405 try: 

406 return convert_indexed_to_array(indexed) 

407 except Exception: 

408 return indexed 

409 

410 def _get_einsum_string(self, subranks, contraction_indices): 

411 letters = self._get_letter_generator_for_einsum() 

412 contraction_string = "" 

413 counter = 0 

414 d = {j: min(i) for i in contraction_indices for j in i} 

415 indices = [] 

416 for rank_arg in subranks: 

417 lindices = [] 

418 for i in range(rank_arg): 

419 if counter in d: 

420 lindices.append(d[counter]) 

421 else: 

422 lindices.append(counter) 

423 counter += 1 

424 indices.append(lindices) 

425 mapping = {} 

426 letters_free = [] 

427 letters_dum = [] 

428 for i in indices: 

429 for j in i: 

430 if j not in mapping: 

431 l = next(letters) 

432 mapping[j] = l 

433 else: 

434 l = mapping[j] 

435 contraction_string += l 

436 if j in d: 

437 if l not in letters_dum: 

438 letters_dum.append(l) 

439 else: 

440 letters_free.append(l) 

441 contraction_string += "," 

442 contraction_string = contraction_string[:-1] 

443 return contraction_string, letters_free, letters_dum 

444 

445 def _get_letter_generator_for_einsum(self): 

446 for i in range(97, 123): 

447 yield chr(i) 

448 for i in range(65, 91): 

449 yield chr(i) 

450 raise ValueError("out of letters") 

451 

452 def _print_ArrayTensorProduct(self, expr): 

453 letters = self._get_letter_generator_for_einsum() 

454 contraction_string = ",".join(["".join([next(letters) for j in range(i)]) for i in expr.subranks]) 

455 return '%s("%s", %s)' % ( 

456 self._module_format(self._module + "." + self._einsum), 

457 contraction_string, 

458 ", ".join([self._print(arg) for arg in expr.args]) 

459 ) 

460 

461 def _print_ArrayContraction(self, expr): 

462 from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct 

463 base = expr.expr 

464 contraction_indices = expr.contraction_indices 

465 

466 if isinstance(base, ArrayTensorProduct): 

467 elems = ",".join(["%s" % (self._print(arg)) for arg in base.args]) 

468 ranks = base.subranks 

469 else: 

470 elems = self._print(base) 

471 ranks = [len(base.shape)] 

472 

473 contraction_string, letters_free, letters_dum = self._get_einsum_string(ranks, contraction_indices) 

474 

475 if not contraction_indices: 

476 return self._print(base) 

477 if isinstance(base, ArrayTensorProduct): 

478 elems = ",".join(["%s" % (self._print(arg)) for arg in base.args]) 

479 else: 

480 elems = self._print(base) 

481 return "%s(\"%s\", %s)" % ( 

482 self._module_format(self._module + "." + self._einsum), 

483 "{}->{}".format(contraction_string, "".join(sorted(letters_free))), 

484 elems, 

485 ) 

486 

487 def _print_ArrayDiagonal(self, expr): 

488 from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct 

489 diagonal_indices = list(expr.diagonal_indices) 

490 if isinstance(expr.expr, ArrayTensorProduct): 

491 subranks = expr.expr.subranks 

492 elems = expr.expr.args 

493 else: 

494 subranks = expr.subranks 

495 elems = [expr.expr] 

496 diagonal_string, letters_free, letters_dum = self._get_einsum_string(subranks, diagonal_indices) 

497 elems = [self._print(i) for i in elems] 

498 return '%s("%s", %s)' % ( 

499 self._module_format(self._module + "." + self._einsum), 

500 "{}->{}".format(diagonal_string, "".join(letters_free+letters_dum)), 

501 ", ".join(elems) 

502 ) 

503 

504 def _print_PermuteDims(self, expr): 

505 return "%s(%s, %s)" % ( 

506 self._module_format(self._module + "." + self._transpose), 

507 self._print(expr.expr), 

508 self._print(expr.permutation.array_form), 

509 ) 

510 

511 def _print_ArrayAdd(self, expr): 

512 return self._expand_fold_binary_op(self._module + "." + self._add, expr.args) 

513 

514 def _print_OneArray(self, expr): 

515 return "%s((%s,))" % ( 

516 self._module_format(self._module+ "." + self._ones), 

517 ','.join(map(self._print,expr.args)) 

518 ) 

519 

520 def _print_ZeroArray(self, expr): 

521 return "%s((%s,))" % ( 

522 self._module_format(self._module+ "." + self._zeros), 

523 ','.join(map(self._print,expr.args)) 

524 ) 

525 

526 def _print_Assignment(self, expr): 

527 #XXX: maybe this needs to happen at a higher level e.g. at _print or 

528 #doprint? 

529 lhs = self._print(self._arrayify(expr.lhs)) 

530 rhs = self._print(self._arrayify(expr.rhs)) 

531 return "%s = %s" % ( lhs, rhs ) 

532 

533 def _print_IndexedBase(self, expr): 

534 return self._print_ArraySymbol(expr) 

535 

536 

537class PythonCodePrinter(AbstractPythonCodePrinter): 

538 

539 def _print_sign(self, e): 

540 return '(0.0 if {e} == 0 else {f}(1, {e}))'.format( 

541 f=self._module_format('math.copysign'), e=self._print(e.args[0])) 

542 

543 def _print_Not(self, expr): 

544 PREC = precedence(expr) 

545 return self._operators['not'] + self.parenthesize(expr.args[0], PREC) 

546 

547 def _print_Indexed(self, expr): 

548 base = expr.args[0] 

549 index = expr.args[1:] 

550 return "{}[{}]".format(str(base), ", ".join([self._print(ind) for ind in index])) 

551 

552 def _print_Pow(self, expr, rational=False): 

553 return self._hprint_Pow(expr, rational=rational) 

554 

555 def _print_Rational(self, expr): 

556 return '{}/{}'.format(expr.p, expr.q) 

557 

558 def _print_Half(self, expr): 

559 return self._print_Rational(expr) 

560 

561 def _print_frac(self, expr): 

562 return self._print_Mod(Mod(expr.args[0], 1)) 

563 

564 def _print_Symbol(self, expr): 

565 

566 name = super()._print_Symbol(expr) 

567 

568 if name in self.reserved_words: 

569 if self._settings['error_on_reserved']: 

570 msg = ('This expression includes the symbol "{}" which is a ' 

571 'reserved keyword in this language.') 

572 raise ValueError(msg.format(name)) 

573 return name + self._settings['reserved_word_suffix'] 

574 elif '{' in name: # Remove curly braces from subscripted variables 

575 return name.replace('{', '').replace('}', '') 

576 else: 

577 return name 

578 

579 _print_lowergamma = CodePrinter._print_not_supported 

580 _print_uppergamma = CodePrinter._print_not_supported 

581 _print_fresnelc = CodePrinter._print_not_supported 

582 _print_fresnels = CodePrinter._print_not_supported 

583 

584 

585for k in PythonCodePrinter._kf: 

586 setattr(PythonCodePrinter, '_print_%s' % k, _print_known_func) 

587 

588for k in _known_constants_math: 

589 setattr(PythonCodePrinter, '_print_%s' % k, _print_known_const) 

590 

591 

592def pycode(expr, **settings): 

593 """ Converts an expr to a string of Python code 

594 

595 Parameters 

596 ========== 

597 

598 expr : Expr 

599 A SymPy expression. 

600 fully_qualified_modules : bool 

601 Whether or not to write out full module names of functions 

602 (``math.sin`` vs. ``sin``). default: ``True``. 

603 standard : str or None, optional 

604 Only 'python3' (default) is supported. 

605 This parameter may be removed in the future. 

606 

607 Examples 

608 ======== 

609 

610 >>> from sympy import pycode, tan, Symbol 

611 >>> pycode(tan(Symbol('x')) + 1) 

612 'math.tan(x) + 1' 

613 

614 """ 

615 return PythonCodePrinter(settings).doprint(expr) 

616 

617 

618_not_in_mpmath = 'log1p log2'.split() 

619_in_mpmath = [(k, v) for k, v in _known_functions_math.items() if k not in _not_in_mpmath] 

620_known_functions_mpmath = dict(_in_mpmath, **{ 

621 'beta': 'beta', 

622 'frac': 'frac', 

623 'fresnelc': 'fresnelc', 

624 'fresnels': 'fresnels', 

625 'sign': 'sign', 

626 'loggamma': 'loggamma', 

627 'hyper': 'hyper', 

628 'meijerg': 'meijerg', 

629 'besselj': 'besselj', 

630 'bessely': 'bessely', 

631 'besseli': 'besseli', 

632 'besselk': 'besselk', 

633}) 

634_known_constants_mpmath = { 

635 'Exp1': 'e', 

636 'Pi': 'pi', 

637 'GoldenRatio': 'phi', 

638 'EulerGamma': 'euler', 

639 'Catalan': 'catalan', 

640 'NaN': 'nan', 

641 'Infinity': 'inf', 

642 'NegativeInfinity': 'ninf' 

643} 

644 

645 

646def _unpack_integral_limits(integral_expr): 

647 """ helper function for _print_Integral that 

648 - accepts an Integral expression 

649 - returns a tuple of 

650 - a list variables of integration 

651 - a list of tuples of the upper and lower limits of integration 

652 """ 

653 integration_vars = [] 

654 limits = [] 

655 for integration_range in integral_expr.limits: 

656 if len(integration_range) == 3: 

657 integration_var, lower_limit, upper_limit = integration_range 

658 else: 

659 raise NotImplementedError("Only definite integrals are supported") 

660 integration_vars.append(integration_var) 

661 limits.append((lower_limit, upper_limit)) 

662 return integration_vars, limits 

663 

664 

665class MpmathPrinter(PythonCodePrinter): 

666 """ 

667 Lambda printer for mpmath which maintains precision for floats 

668 """ 

669 printmethod = "_mpmathcode" 

670 

671 language = "Python with mpmath" 

672 

673 _kf = dict(chain( 

674 _known_functions.items(), 

675 [(k, 'mpmath.' + v) for k, v in _known_functions_mpmath.items()] 

676 )) 

677 _kc = {k: 'mpmath.'+v for k, v in _known_constants_mpmath.items()} 

678 

679 def _print_Float(self, e): 

680 # XXX: This does not handle setting mpmath.mp.dps. It is assumed that 

681 # the caller of the lambdified function will have set it to sufficient 

682 # precision to match the Floats in the expression. 

683 

684 # Remove 'mpz' if gmpy is installed. 

685 args = str(tuple(map(int, e._mpf_))) 

686 return '{func}({args})'.format(func=self._module_format('mpmath.mpf'), args=args) 

687 

688 

689 def _print_Rational(self, e): 

690 return "{func}({p})/{func}({q})".format( 

691 func=self._module_format('mpmath.mpf'), 

692 q=self._print(e.q), 

693 p=self._print(e.p) 

694 ) 

695 

696 def _print_Half(self, e): 

697 return self._print_Rational(e) 

698 

699 def _print_uppergamma(self, e): 

700 return "{}({}, {}, {})".format( 

701 self._module_format('mpmath.gammainc'), 

702 self._print(e.args[0]), 

703 self._print(e.args[1]), 

704 self._module_format('mpmath.inf')) 

705 

706 def _print_lowergamma(self, e): 

707 return "{}({}, 0, {})".format( 

708 self._module_format('mpmath.gammainc'), 

709 self._print(e.args[0]), 

710 self._print(e.args[1])) 

711 

712 def _print_log2(self, e): 

713 return '{0}({1})/{0}(2)'.format( 

714 self._module_format('mpmath.log'), self._print(e.args[0])) 

715 

716 def _print_log1p(self, e): 

717 return '{}({})'.format( 

718 self._module_format('mpmath.log1p'), self._print(e.args[0])) 

719 

720 def _print_Pow(self, expr, rational=False): 

721 return self._hprint_Pow(expr, rational=rational, sqrt='mpmath.sqrt') 

722 

723 def _print_Integral(self, e): 

724 integration_vars, limits = _unpack_integral_limits(e) 

725 

726 return "{}(lambda {}: {}, {})".format( 

727 self._module_format("mpmath.quad"), 

728 ", ".join(map(self._print, integration_vars)), 

729 self._print(e.args[0]), 

730 ", ".join("(%s, %s)" % tuple(map(self._print, l)) for l in limits)) 

731 

732 

733for k in MpmathPrinter._kf: 

734 setattr(MpmathPrinter, '_print_%s' % k, _print_known_func) 

735 

736for k in _known_constants_mpmath: 

737 setattr(MpmathPrinter, '_print_%s' % k, _print_known_const) 

738 

739 

740class SymPyPrinter(AbstractPythonCodePrinter): 

741 

742 language = "Python with SymPy" 

743 

744 def _print_Function(self, expr): 

745 mod = expr.func.__module__ or '' 

746 return '%s(%s)' % (self._module_format(mod + ('.' if mod else '') + expr.func.__name__), 

747 ', '.join((self._print(arg) for arg in expr.args))) 

748 

749 def _print_Pow(self, expr, rational=False): 

750 return self._hprint_Pow(expr, rational=rational, sqrt='sympy.sqrt')