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

1""" 

2Maple code printer 

3 

4The MapleCodePrinter converts single SymPy expressions into single 

5Maple expressions, using the functions defined in the Maple objects where possible. 

6 

7 

8FIXME: This module is still under actively developed. Some functions may be not completed. 

9""" 

10 

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 

15 

16import sympy 

17 

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) 

25 

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', 

45 

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} 

61 

62for _func in _known_func_same_name: 

63 known_functions[_func] = _func 

64 

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} 

73 

74spec_relational_ops = { 

75 # SymPy -> Maple 

76 '==': '=', 

77 '!=': '<>' 

78} 

79 

80not_supported_symbol = [ 

81 S.ComplexInfinity 

82] 

83 

84class MapleCodePrinter(CodePrinter): 

85 """ 

86 Printer which converts a SymPy expression into a maple code. 

87 """ 

88 printmethod = "_maple" 

89 language = "maple" 

90 

91 _default_settings = { 

92 'order': None, 

93 'full_prec': 'auto', 

94 'human': True, 

95 'inline': True, 

96 'allow_unknown_functions': True, 

97 } 

98 

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) 

106 

107 def _get_statement(self, codestring): 

108 return "%s;" % codestring 

109 

110 def _get_comment(self, text): 

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

112 

113 def _declare_number_const(self, name, value): 

114 return "{} := {};".format(name, 

115 value.evalf(self._settings['precision'])) 

116 

117 def _format_code(self, lines): 

118 return lines 

119 

120 def _print_tuple(self, expr): 

121 return self._print(list(expr)) 

122 

123 def _print_Tuple(self, expr): 

124 return self._print(list(expr)) 

125 

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) 

130 

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)) 

143 

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) 

160 

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)) 

164 

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) 

173 

174 def _print_NumberSymbol(self, expr): 

175 return number_symbols[expr] 

176 

177 def _print_NegativeInfinity(self, expr): 

178 return '-infinity' 

179 

180 def _print_Infinity(self, expr): 

181 return 'infinity' 

182 

183 def _print_Idx(self, expr): 

184 return self._print(expr.label) 

185 

186 def _print_BooleanTrue(self, expr): 

187 return "true" 

188 

189 def _print_BooleanFalse(self, expr): 

190 return "false" 

191 

192 def _print_bool(self, expr): 

193 return 'true' if expr else 'false' 

194 

195 def _print_NaN(self, expr): 

196 return 'undefined' 

197 

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 

207 

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)) 

213 

214 def _print_MatrixBase(self, expr): 

215 return self._get_matrix(expr, sparse=False) 

216 

217 def _print_SparseRepMatrix(self, expr): 

218 return self._get_matrix(expr, sparse=True) 

219 

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)) 

225 

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:] 

233 

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)) 

238 

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)) 

242 

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) 

247 

248 def _print_Derivative(self, expr): 

249 _f, (_var, _order) = expr.args 

250 

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) 

257 

258 

259def maple_code(expr, assign_to=None, **settings): 

260 r"""Converts ``expr`` to a string of Maple code. 

261 

262 Parameters 

263 ========== 

264 

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]. 

293 

294 """ 

295 return MapleCodePrinter(settings).doprint(expr, assign_to) 

296 

297 

298def print_maple_code(expr, **settings): 

299 """Prints the Maple representation of the given expression. 

300 

301 See :func:`maple_code` for the meaning of the optional arguments. 

302 

303 Examples 

304 ======== 

305 

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))