Coverage for /usr/lib/python3/dist-packages/sympy/printing/maple.py: 39%
121 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"""
2Maple code printer
4The MapleCodePrinter converts single SymPy expressions into single
5Maple expressions, using the functions defined in the Maple objects where possible.
8FIXME: This module is still under actively developed. Some functions may be not completed.
9"""
11from sympy.core import S
12from sympy.core.numbers import Integer, IntegerConstant, equal_valued
13from sympy.printing.codeprinter import CodePrinter
14from sympy.printing.precedence import precedence, PRECEDENCE
16import sympy
18_known_func_same_name = (
19 'sin', 'cos', 'tan', 'sec', 'csc', 'cot', 'sinh', 'cosh', 'tanh', 'sech',
20 'csch', 'coth', 'exp', 'floor', 'factorial', 'bernoulli', 'euler',
21 'fibonacci', 'gcd', 'lcm', 'conjugate', 'Ci', 'Chi', 'Ei', 'Li', 'Si', 'Shi',
22 'erf', 'erfc', 'harmonic', 'LambertW',
23 'sqrt', # For automatic rewrites
24)
26known_functions = {
27 # SymPy -> Maple
28 'Abs': 'abs',
29 'log': 'ln',
30 'asin': 'arcsin',
31 'acos': 'arccos',
32 'atan': 'arctan',
33 'asec': 'arcsec',
34 'acsc': 'arccsc',
35 'acot': 'arccot',
36 'asinh': 'arcsinh',
37 'acosh': 'arccosh',
38 'atanh': 'arctanh',
39 'asech': 'arcsech',
40 'acsch': 'arccsch',
41 'acoth': 'arccoth',
42 'ceiling': 'ceil',
43 'Max' : 'max',
44 'Min' : 'min',
46 'factorial2': 'doublefactorial',
47 'RisingFactorial': 'pochhammer',
48 'besseli': 'BesselI',
49 'besselj': 'BesselJ',
50 'besselk': 'BesselK',
51 'bessely': 'BesselY',
52 'hankelh1': 'HankelH1',
53 'hankelh2': 'HankelH2',
54 'airyai': 'AiryAi',
55 'airybi': 'AiryBi',
56 'appellf1': 'AppellF1',
57 'fresnelc': 'FresnelC',
58 'fresnels': 'FresnelS',
59 'lerchphi' : 'LerchPhi',
60}
62for _func in _known_func_same_name:
63 known_functions[_func] = _func
65number_symbols = {
66 # SymPy -> Maple
67 S.Pi: 'Pi',
68 S.Exp1: 'exp(1)',
69 S.Catalan: 'Catalan',
70 S.EulerGamma: 'gamma',
71 S.GoldenRatio: '(1/2 + (1/2)*sqrt(5))'
72}
74spec_relational_ops = {
75 # SymPy -> Maple
76 '==': '=',
77 '!=': '<>'
78}
80not_supported_symbol = [
81 S.ComplexInfinity
82]
84class MapleCodePrinter(CodePrinter):
85 """
86 Printer which converts a SymPy expression into a maple code.
87 """
88 printmethod = "_maple"
89 language = "maple"
91 _default_settings = {
92 'order': None,
93 'full_prec': 'auto',
94 'human': True,
95 'inline': True,
96 'allow_unknown_functions': True,
97 }
99 def __init__(self, settings=None):
100 if settings is None:
101 settings = {}
102 super().__init__(settings)
103 self.known_functions = dict(known_functions)
104 userfuncs = settings.get('user_functions', {})
105 self.known_functions.update(userfuncs)
107 def _get_statement(self, codestring):
108 return "%s;" % codestring
110 def _get_comment(self, text):
111 return "# {}".format(text)
113 def _declare_number_const(self, name, value):
114 return "{} := {};".format(name,
115 value.evalf(self._settings['precision']))
117 def _format_code(self, lines):
118 return lines
120 def _print_tuple(self, expr):
121 return self._print(list(expr))
123 def _print_Tuple(self, expr):
124 return self._print(list(expr))
126 def _print_Assignment(self, expr):
127 lhs = self._print(expr.lhs)
128 rhs = self._print(expr.rhs)
129 return "{lhs} := {rhs}".format(lhs=lhs, rhs=rhs)
131 def _print_Pow(self, expr, **kwargs):
132 PREC = precedence(expr)
133 if equal_valued(expr.exp, -1):
134 return '1/%s' % (self.parenthesize(expr.base, PREC))
135 elif equal_valued(expr.exp, 0.5):
136 return 'sqrt(%s)' % self._print(expr.base)
137 elif equal_valued(expr.exp, -0.5):
138 return '1/sqrt(%s)' % self._print(expr.base)
139 else:
140 return '{base}^{exp}'.format(
141 base=self.parenthesize(expr.base, PREC),
142 exp=self.parenthesize(expr.exp, PREC))
144 def _print_Piecewise(self, expr):
145 if (expr.args[-1].cond is not True) and (expr.args[-1].cond != S.BooleanTrue):
146 # We need the last conditional to be a True, otherwise the resulting
147 # function may not return a result.
148 raise ValueError("All Piecewise expressions must contain an "
149 "(expr, True) statement to be used as a default "
150 "condition. Without one, the generated "
151 "expression may not evaluate to anything under "
152 "some condition.")
153 _coup_list = [
154 ("{c}, {e}".format(c=self._print(c),
155 e=self._print(e)) if c is not True and c is not S.BooleanTrue else "{e}".format(
156 e=self._print(e)))
157 for e, c in expr.args]
158 _inbrace = ', '.join(_coup_list)
159 return 'piecewise({_inbrace})'.format(_inbrace=_inbrace)
161 def _print_Rational(self, expr):
162 p, q = int(expr.p), int(expr.q)
163 return "{p}/{q}".format(p=str(p), q=str(q))
165 def _print_Relational(self, expr):
166 PREC=precedence(expr)
167 lhs_code = self.parenthesize(expr.lhs, PREC)
168 rhs_code = self.parenthesize(expr.rhs, PREC)
169 op = expr.rel_op
170 if op in spec_relational_ops:
171 op = spec_relational_ops[op]
172 return "{lhs} {rel_op} {rhs}".format(lhs=lhs_code, rel_op=op, rhs=rhs_code)
174 def _print_NumberSymbol(self, expr):
175 return number_symbols[expr]
177 def _print_NegativeInfinity(self, expr):
178 return '-infinity'
180 def _print_Infinity(self, expr):
181 return 'infinity'
183 def _print_Idx(self, expr):
184 return self._print(expr.label)
186 def _print_BooleanTrue(self, expr):
187 return "true"
189 def _print_BooleanFalse(self, expr):
190 return "false"
192 def _print_bool(self, expr):
193 return 'true' if expr else 'false'
195 def _print_NaN(self, expr):
196 return 'undefined'
198 def _get_matrix(self, expr, sparse=False):
199 if S.Zero in expr.shape:
200 _strM = 'Matrix([], storage = {storage})'.format(
201 storage='sparse' if sparse else 'rectangular')
202 else:
203 _strM = 'Matrix({list}, storage = {storage})'.format(
204 list=self._print(expr.tolist()),
205 storage='sparse' if sparse else 'rectangular')
206 return _strM
208 def _print_MatrixElement(self, expr):
209 return "{parent}[{i_maple}, {j_maple}]".format(
210 parent=self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True),
211 i_maple=self._print(expr.i + 1),
212 j_maple=self._print(expr.j + 1))
214 def _print_MatrixBase(self, expr):
215 return self._get_matrix(expr, sparse=False)
217 def _print_SparseRepMatrix(self, expr):
218 return self._get_matrix(expr, sparse=True)
220 def _print_Identity(self, expr):
221 if isinstance(expr.rows, (Integer, IntegerConstant)):
222 return self._print(sympy.SparseMatrix(expr))
223 else:
224 return "Matrix({var_size}, shape = identity)".format(var_size=self._print(expr.rows))
226 def _print_MatMul(self, expr):
227 PREC=precedence(expr)
228 _fact_list = list(expr.args)
229 _const = None
230 if not isinstance(_fact_list[0], (sympy.MatrixBase, sympy.MatrixExpr,
231 sympy.MatrixSlice, sympy.MatrixSymbol)):
232 _const, _fact_list = _fact_list[0], _fact_list[1:]
234 if _const is None or _const == 1:
235 return '.'.join(self.parenthesize(_m, PREC) for _m in _fact_list)
236 else:
237 return '{c}*{m}'.format(c=_const, m='.'.join(self.parenthesize(_m, PREC) for _m in _fact_list))
239 def _print_MatPow(self, expr):
240 # This function requires LinearAlgebra Function in Maple
241 return 'MatrixPower({A}, {n})'.format(A=self._print(expr.base), n=self._print(expr.exp))
243 def _print_HadamardProduct(self, expr):
244 PREC = precedence(expr)
245 _fact_list = list(expr.args)
246 return '*'.join(self.parenthesize(_m, PREC) for _m in _fact_list)
248 def _print_Derivative(self, expr):
249 _f, (_var, _order) = expr.args
251 if _order != 1:
252 _second_arg = '{var}${order}'.format(var=self._print(_var),
253 order=self._print(_order))
254 else:
255 _second_arg = '{var}'.format(var=self._print(_var))
256 return 'diff({func_expr}, {sec_arg})'.format(func_expr=self._print(_f), sec_arg=_second_arg)
259def maple_code(expr, assign_to=None, **settings):
260 r"""Converts ``expr`` to a string of Maple code.
262 Parameters
263 ==========
265 expr : Expr
266 A SymPy expression to be converted.
267 assign_to : optional
268 When given, the argument is used as the name of the variable to which
269 the expression is assigned. Can be a string, ``Symbol``,
270 ``MatrixSymbol``, or ``Indexed`` type. This can be helpful for
271 expressions that generate multi-line statements.
272 precision : integer, optional
273 The precision for numbers such as pi [default=16].
274 user_functions : dict, optional
275 A dictionary where keys are ``FunctionClass`` instances and values are
276 their string representations. Alternatively, the dictionary value can
277 be a list of tuples i.e. [(argument_test, cfunction_string)]. See
278 below for examples.
279 human : bool, optional
280 If True, the result is a single string that may contain some constant
281 declarations for the number symbols. If False, the same information is
282 returned in a tuple of (symbols_to_declare, not_supported_functions,
283 code_text). [default=True].
284 contract: bool, optional
285 If True, ``Indexed`` instances are assumed to obey tensor contraction
286 rules and the corresponding nested loops over indices are generated.
287 Setting contract=False will not generate loops, instead the user is
288 responsible to provide values for the indices in the code.
289 [default=True].
290 inline: bool, optional
291 If True, we try to create single-statement code instead of multiple
292 statements. [default=True].
294 """
295 return MapleCodePrinter(settings).doprint(expr, assign_to)
298def print_maple_code(expr, **settings):
299 """Prints the Maple representation of the given expression.
301 See :func:`maple_code` for the meaning of the optional arguments.
303 Examples
304 ========
306 >>> from sympy import print_maple_code, symbols
307 >>> x, y = symbols('x y')
308 >>> print_maple_code(x, assign_to=y)
309 y := x
310 """
311 print(maple_code(expr, **settings))