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
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1"""
2Python code printers
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
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}
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}
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)))
72def _print_known_const(self, expr):
73 known = self.known_constants[expr.__class__.__name__]
74 return self._module_format(known)
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 )
99 def __init__(self, settings=None):
100 super().__init__(settings)
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
111 self.module_imports = defaultdict(set)
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', {}))
119 def _declare_number_const(self, name, value):
120 return "%s = %s" % (name, value)
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])
127 if self._settings['fully_qualified_modules']:
128 return fqn
129 else:
130 return fqn.split('(')[0].split('[')[0].split('.')[-1]
132 def _format_code(self, lines):
133 return lines
135 def _get_statement(self, codestring):
136 return "{}".format(codestring)
138 def _get_comment(self, text):
139 return " # {}".format(text)
141 def _expand_fold_binary_op(self, op, args):
142 """
143 This method expands a fold on binary operations.
145 ``functools.reduce`` is an example of a folded operation.
147 For example, the expression
149 `A + B + C + D`
151 is folded into
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 )
164 def _expand_reduce_binary_op(self, op, args):
165 """
166 This method expands a reductin on binary operations.
168 Notice: this is NOT the same as ``functools.reduce``.
170 For example, the expression
172 `A + B + C + D`
174 is reduced into:
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 )
189 def _print_NaN(self, expr):
190 return "float('nan')"
192 def _print_Infinity(self, expr):
193 return "float('inf')"
195 def _print_NegativeInfinity(self, expr):
196 return "float('-inf')"
198 def _print_ComplexInfinity(self, expr):
199 return self._print_NaN(expr)
201 def _print_Mod(self, expr):
202 PREC = precedence(expr)
203 return ('{} % {}'.format(*(self.parenthesize(x, PREC) for x in expr.args)))
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)
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)
244 def _print_ITE(self, expr):
245 from sympy.functions.elementary.piecewise import Piecewise
246 return self._print(expr.rewrite(Piecewise))
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))
259 def _print_ImaginaryUnit(self, expr):
260 return '1j'
262 def _print_KroneckerDelta(self, expr):
263 a, b = expr.args
265 return '(1 if {a} == {b} else 0)'.format(
266 a = self._print(a),
267 b = self._print(b)
268 )
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()))
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)
285 def _indent_codestring(self, codestring):
286 return '\n'.join([self.tab + line for line in codestring.split('\n')])
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 )
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 )
303 def _print_Declaration(self, decl):
304 return '%s = %s' % (
305 self._print(decl.variable.symbol),
306 self._print(decl.variable.value)
307 )
309 def _print_Return(self, ret):
310 arg, = ret.args
311 return 'return %s' % self._print(arg)
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)
321 return 'print(%s)' % print_args
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)
331 def _print_NoneToken(self, arg):
332 return 'None'
334 def _hprint_Pow(self, expr, rational=False, sqrt='math.sqrt'):
335 """Printing helper function for ``Pow``
337 Notes
338 =====
340 This preprocesses the ``sqrt`` as math formatter and prints division
342 Examples
343 ========
345 >>> from sympy import sqrt
346 >>> from sympy.printing.pycode import PythonCodePrinter
347 >>> from sympy.abc import x
349 Python code printer automatically looks up ``math.sqrt``.
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)'
365 Using sqrt from numpy or mpmath
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)'
372 See Also
373 ========
375 sympy.printing.str.StrPrinter._print_Pow
376 """
377 PREC = precedence(expr)
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)
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}"
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)
401class ArrayPrinter:
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
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
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")
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 )
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
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)]
473 contraction_string, letters_free, letters_dum = self._get_einsum_string(ranks, contraction_indices)
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 )
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 )
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 )
511 def _print_ArrayAdd(self, expr):
512 return self._expand_fold_binary_op(self._module + "." + self._add, expr.args)
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 )
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 )
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 )
533 def _print_IndexedBase(self, expr):
534 return self._print_ArraySymbol(expr)
537class PythonCodePrinter(AbstractPythonCodePrinter):
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]))
543 def _print_Not(self, expr):
544 PREC = precedence(expr)
545 return self._operators['not'] + self.parenthesize(expr.args[0], PREC)
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]))
552 def _print_Pow(self, expr, rational=False):
553 return self._hprint_Pow(expr, rational=rational)
555 def _print_Rational(self, expr):
556 return '{}/{}'.format(expr.p, expr.q)
558 def _print_Half(self, expr):
559 return self._print_Rational(expr)
561 def _print_frac(self, expr):
562 return self._print_Mod(Mod(expr.args[0], 1))
564 def _print_Symbol(self, expr):
566 name = super()._print_Symbol(expr)
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
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
585for k in PythonCodePrinter._kf:
586 setattr(PythonCodePrinter, '_print_%s' % k, _print_known_func)
588for k in _known_constants_math:
589 setattr(PythonCodePrinter, '_print_%s' % k, _print_known_const)
592def pycode(expr, **settings):
593 """ Converts an expr to a string of Python code
595 Parameters
596 ==========
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.
607 Examples
608 ========
610 >>> from sympy import pycode, tan, Symbol
611 >>> pycode(tan(Symbol('x')) + 1)
612 'math.tan(x) + 1'
614 """
615 return PythonCodePrinter(settings).doprint(expr)
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}
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
665class MpmathPrinter(PythonCodePrinter):
666 """
667 Lambda printer for mpmath which maintains precision for floats
668 """
669 printmethod = "_mpmathcode"
671 language = "Python with mpmath"
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()}
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.
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)
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 )
696 def _print_Half(self, e):
697 return self._print_Rational(e)
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'))
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]))
712 def _print_log2(self, e):
713 return '{0}({1})/{0}(2)'.format(
714 self._module_format('mpmath.log'), self._print(e.args[0]))
716 def _print_log1p(self, e):
717 return '{}({})'.format(
718 self._module_format('mpmath.log1p'), self._print(e.args[0]))
720 def _print_Pow(self, expr, rational=False):
721 return self._hprint_Pow(expr, rational=rational, sqrt='mpmath.sqrt')
723 def _print_Integral(self, e):
724 integration_vars, limits = _unpack_integral_limits(e)
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))
733for k in MpmathPrinter._kf:
734 setattr(MpmathPrinter, '_print_%s' % k, _print_known_func)
736for k in _known_constants_mpmath:
737 setattr(MpmathPrinter, '_print_%s' % k, _print_known_const)
740class SymPyPrinter(AbstractPythonCodePrinter):
742 language = "Python with SymPy"
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)))
749 def _print_Pow(self, expr, rational=False):
750 return self._hprint_Pow(expr, rational=rational, sqrt='sympy.sqrt')