ZhengyangZhang commited on
Commit
a6f43e4
·
verified ·
1 Parent(s): 849e4fa

Add files using upload-large-folder tool

Browse files
Files changed (50) hide show
  1. lib/python3.12/site-packages/sympy/interactive/__init__.py +8 -0
  2. lib/python3.12/site-packages/sympy/interactive/__pycache__/__init__.cpython-312.pyc +0 -0
  3. lib/python3.12/site-packages/sympy/interactive/__pycache__/printing.cpython-312.pyc +0 -0
  4. lib/python3.12/site-packages/sympy/interactive/__pycache__/session.cpython-312.pyc +0 -0
  5. lib/python3.12/site-packages/sympy/interactive/__pycache__/traversal.cpython-312.pyc +0 -0
  6. lib/python3.12/site-packages/sympy/interactive/printing.py +562 -0
  7. lib/python3.12/site-packages/sympy/interactive/session.py +463 -0
  8. lib/python3.12/site-packages/sympy/interactive/tests/__init__.py +0 -0
  9. lib/python3.12/site-packages/sympy/interactive/tests/__pycache__/__init__.cpython-312.pyc +0 -0
  10. lib/python3.12/site-packages/sympy/interactive/tests/__pycache__/test_interactive.cpython-312.pyc +0 -0
  11. lib/python3.12/site-packages/sympy/interactive/tests/__pycache__/test_ipython.cpython-312.pyc +0 -0
  12. lib/python3.12/site-packages/sympy/interactive/tests/test_interactive.py +10 -0
  13. lib/python3.12/site-packages/sympy/interactive/tests/test_ipython.py +278 -0
  14. lib/python3.12/site-packages/sympy/interactive/traversal.py +95 -0
  15. lib/python3.12/site-packages/sympy/plotting/__pycache__/__init__.cpython-312.pyc +0 -0
  16. lib/python3.12/site-packages/sympy/plotting/__pycache__/experimental_lambdify.cpython-312.pyc +0 -0
  17. lib/python3.12/site-packages/sympy/plotting/__pycache__/plot.cpython-312.pyc +0 -0
  18. lib/python3.12/site-packages/sympy/plotting/__pycache__/plot_implicit.cpython-312.pyc +0 -0
  19. lib/python3.12/site-packages/sympy/plotting/__pycache__/plotgrid.cpython-312.pyc +0 -0
  20. lib/python3.12/site-packages/sympy/plotting/__pycache__/textplot.cpython-312.pyc +0 -0
  21. lib/python3.12/site-packages/sympy/plotting/__pycache__/utils.cpython-312.pyc +0 -0
  22. lib/python3.12/site-packages/sympy/plotting/intervalmath/__init__.py +12 -0
  23. lib/python3.12/site-packages/sympy/plotting/intervalmath/__pycache__/__init__.cpython-312.pyc +0 -0
  24. lib/python3.12/site-packages/sympy/plotting/intervalmath/__pycache__/interval_arithmetic.cpython-312.pyc +0 -0
  25. lib/python3.12/site-packages/sympy/plotting/intervalmath/__pycache__/interval_membership.cpython-312.pyc +0 -0
  26. lib/python3.12/site-packages/sympy/plotting/intervalmath/__pycache__/lib_interval.cpython-312.pyc +0 -0
  27. lib/python3.12/site-packages/sympy/plotting/intervalmath/interval_arithmetic.py +413 -0
  28. lib/python3.12/site-packages/sympy/plotting/intervalmath/interval_membership.py +78 -0
  29. lib/python3.12/site-packages/sympy/plotting/intervalmath/lib_interval.py +452 -0
  30. lib/python3.12/site-packages/sympy/plotting/intervalmath/tests/__init__.py +0 -0
  31. lib/python3.12/site-packages/sympy/plotting/intervalmath/tests/__pycache__/__init__.cpython-312.pyc +0 -0
  32. lib/python3.12/site-packages/sympy/plotting/intervalmath/tests/__pycache__/test_interval_functions.cpython-312.pyc +0 -0
  33. lib/python3.12/site-packages/sympy/plotting/intervalmath/tests/__pycache__/test_interval_membership.cpython-312.pyc +0 -0
  34. lib/python3.12/site-packages/sympy/plotting/intervalmath/tests/__pycache__/test_intervalmath.cpython-312.pyc +0 -0
  35. lib/python3.12/site-packages/sympy/plotting/intervalmath/tests/test_interval_functions.py +415 -0
  36. lib/python3.12/site-packages/sympy/plotting/intervalmath/tests/test_interval_membership.py +150 -0
  37. lib/python3.12/site-packages/sympy/plotting/intervalmath/tests/test_intervalmath.py +213 -0
  38. lib/python3.12/site-packages/sympy/plotting/pygletplot/__pycache__/__init__.cpython-312.pyc +0 -0
  39. lib/python3.12/site-packages/sympy/plotting/pygletplot/__pycache__/managed_window.cpython-312.pyc +0 -0
  40. lib/python3.12/site-packages/sympy/plotting/pygletplot/__pycache__/plot_curve.cpython-312.pyc +0 -0
  41. lib/python3.12/site-packages/sympy/plotting/pygletplot/__pycache__/plot_mode.cpython-312.pyc +0 -0
  42. lib/python3.12/site-packages/sympy/plotting/pygletplot/__pycache__/plot_mode_base.cpython-312.pyc +0 -0
  43. lib/python3.12/site-packages/sympy/plotting/pygletplot/__pycache__/plot_object.cpython-312.pyc +0 -0
  44. lib/python3.12/site-packages/sympy/plotting/pygletplot/__pycache__/plot_rotation.cpython-312.pyc +0 -0
  45. lib/python3.12/site-packages/sympy/plotting/pygletplot/__pycache__/plot_surface.cpython-312.pyc +0 -0
  46. lib/python3.12/site-packages/sympy/plotting/pygletplot/__pycache__/util.cpython-312.pyc +0 -0
  47. lib/python3.12/site-packages/sympy/printing/codeprinter.py +888 -0
  48. lib/python3.12/site-packages/sympy/printing/octave.py +715 -0
  49. lib/python3.12/site-packages/sympy/printing/printer.py +396 -0
  50. lib/python3.12/site-packages/sympy/printing/rcode.py +405 -0
lib/python3.12/site-packages/sympy/interactive/__init__.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ """Helper module for setting up interactive SymPy sessions. """
2
+
3
+ from .printing import init_printing
4
+ from .session import init_session
5
+ from .traversal import interactive_traversal
6
+
7
+
8
+ __all__ = ['init_printing', 'init_session', 'interactive_traversal']
lib/python3.12/site-packages/sympy/interactive/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (463 Bytes). View file
 
lib/python3.12/site-packages/sympy/interactive/__pycache__/printing.cpython-312.pyc ADDED
Binary file (22.8 kB). View file
 
lib/python3.12/site-packages/sympy/interactive/__pycache__/session.cpython-312.pyc ADDED
Binary file (15.6 kB). View file
 
lib/python3.12/site-packages/sympy/interactive/__pycache__/traversal.cpython-312.pyc ADDED
Binary file (3.87 kB). View file
 
lib/python3.12/site-packages/sympy/interactive/printing.py ADDED
@@ -0,0 +1,562 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Tools for setting up printing in interactive sessions. """
2
+
3
+ from sympy.external.importtools import version_tuple
4
+ from io import BytesIO
5
+
6
+ from sympy.printing.latex import latex as default_latex
7
+ from sympy.printing.preview import preview
8
+ from sympy.utilities.misc import debug
9
+ from sympy.printing.defaults import Printable
10
+
11
+
12
+ def _init_python_printing(stringify_func, **settings):
13
+ """Setup printing in Python interactive session. """
14
+ import sys
15
+ import builtins
16
+
17
+ def _displayhook(arg):
18
+ """Python's pretty-printer display hook.
19
+
20
+ This function was adapted from:
21
+
22
+ https://www.python.org/dev/peps/pep-0217/
23
+
24
+ """
25
+ if arg is not None:
26
+ builtins._ = None
27
+ print(stringify_func(arg, **settings))
28
+ builtins._ = arg
29
+
30
+ sys.displayhook = _displayhook
31
+
32
+
33
+ def _init_ipython_printing(ip, stringify_func, use_latex, euler, forecolor,
34
+ backcolor, fontsize, latex_mode, print_builtin,
35
+ latex_printer, scale, **settings):
36
+ """Setup printing in IPython interactive session. """
37
+ try:
38
+ from IPython.lib.latextools import latex_to_png
39
+ except ImportError:
40
+ pass
41
+
42
+ # Guess best font color if none was given based on the ip.colors string.
43
+ # From the IPython documentation:
44
+ # It has four case-insensitive values: 'nocolor', 'neutral', 'linux',
45
+ # 'lightbg'. The default is neutral, which should be legible on either
46
+ # dark or light terminal backgrounds. linux is optimised for dark
47
+ # backgrounds and lightbg for light ones.
48
+ if forecolor is None:
49
+ color = ip.colors.lower()
50
+ if color == 'lightbg':
51
+ forecolor = 'Black'
52
+ elif color == 'linux':
53
+ forecolor = 'White'
54
+ else:
55
+ # No idea, go with gray.
56
+ forecolor = 'Gray'
57
+ debug("init_printing: Automatic foreground color:", forecolor)
58
+
59
+ if use_latex == "svg":
60
+ extra_preamble = "\n\\special{color %s}" % forecolor
61
+ else:
62
+ extra_preamble = ""
63
+
64
+ imagesize = 'tight'
65
+ offset = "0cm,0cm"
66
+ resolution = round(150*scale)
67
+ dvi = r"-T %s -D %d -bg %s -fg %s -O %s" % (
68
+ imagesize, resolution, backcolor, forecolor, offset)
69
+ dvioptions = dvi.split()
70
+
71
+ svg_scale = 150/72*scale
72
+ dvioptions_svg = ["--no-fonts", "--scale={}".format(svg_scale)]
73
+
74
+ debug("init_printing: DVIOPTIONS:", dvioptions)
75
+ debug("init_printing: DVIOPTIONS_SVG:", dvioptions_svg)
76
+
77
+ latex = latex_printer or default_latex
78
+
79
+ def _print_plain(arg, p, cycle):
80
+ """caller for pretty, for use in IPython 0.11"""
81
+ if _can_print(arg):
82
+ p.text(stringify_func(arg))
83
+ else:
84
+ p.text(IPython.lib.pretty.pretty(arg))
85
+
86
+ def _preview_wrapper(o):
87
+ exprbuffer = BytesIO()
88
+ try:
89
+ preview(o, output='png', viewer='BytesIO', euler=euler,
90
+ outputbuffer=exprbuffer, extra_preamble=extra_preamble,
91
+ dvioptions=dvioptions, fontsize=fontsize)
92
+ except Exception as e:
93
+ # IPython swallows exceptions
94
+ debug("png printing:", "_preview_wrapper exception raised:",
95
+ repr(e))
96
+ raise
97
+ return exprbuffer.getvalue()
98
+
99
+ def _svg_wrapper(o):
100
+ exprbuffer = BytesIO()
101
+ try:
102
+ preview(o, output='svg', viewer='BytesIO', euler=euler,
103
+ outputbuffer=exprbuffer, extra_preamble=extra_preamble,
104
+ dvioptions=dvioptions_svg, fontsize=fontsize)
105
+ except Exception as e:
106
+ # IPython swallows exceptions
107
+ debug("svg printing:", "_preview_wrapper exception raised:",
108
+ repr(e))
109
+ raise
110
+ return exprbuffer.getvalue().decode('utf-8')
111
+
112
+ def _matplotlib_wrapper(o):
113
+ # mathtext can't render some LaTeX commands. For example, it can't
114
+ # render any LaTeX environments such as array or matrix. So here we
115
+ # ensure that if mathtext fails to render, we return None.
116
+ try:
117
+ try:
118
+ return latex_to_png(o, color=forecolor, scale=scale)
119
+ except TypeError: # Old IPython version without color and scale
120
+ return latex_to_png(o)
121
+ except ValueError as e:
122
+ debug('matplotlib exception caught:', repr(e))
123
+ return None
124
+
125
+
126
+ # Hook methods for builtin SymPy printers
127
+ printing_hooks = ('_latex', '_sympystr', '_pretty', '_sympyrepr')
128
+
129
+
130
+ def _can_print(o):
131
+ """Return True if type o can be printed with one of the SymPy printers.
132
+
133
+ If o is a container type, this is True if and only if every element of
134
+ o can be printed in this way.
135
+ """
136
+
137
+ try:
138
+ # If you're adding another type, make sure you add it to printable_types
139
+ # later in this file as well
140
+
141
+ builtin_types = (list, tuple, set, frozenset)
142
+ if isinstance(o, builtin_types):
143
+ # If the object is a custom subclass with a custom str or
144
+ # repr, use that instead.
145
+ if (type(o).__str__ not in (i.__str__ for i in builtin_types) or
146
+ type(o).__repr__ not in (i.__repr__ for i in builtin_types)):
147
+ return False
148
+ return all(_can_print(i) for i in o)
149
+ elif isinstance(o, dict):
150
+ return all(_can_print(i) and _can_print(o[i]) for i in o)
151
+ elif isinstance(o, bool):
152
+ return False
153
+ elif isinstance(o, Printable):
154
+ # types known to SymPy
155
+ return True
156
+ elif any(hasattr(o, hook) for hook in printing_hooks):
157
+ # types which add support themselves
158
+ return True
159
+ elif isinstance(o, (float, int)) and print_builtin:
160
+ return True
161
+ return False
162
+ except RuntimeError:
163
+ return False
164
+ # This is in case maximum recursion depth is reached.
165
+ # Since RecursionError is for versions of Python 3.5+
166
+ # so this is to guard against RecursionError for older versions.
167
+
168
+ def _print_latex_png(o):
169
+ """
170
+ A function that returns a png rendered by an external latex
171
+ distribution, falling back to matplotlib rendering
172
+ """
173
+ if _can_print(o):
174
+ s = latex(o, mode=latex_mode, **settings)
175
+ if latex_mode == 'plain':
176
+ s = '$\\displaystyle %s$' % s
177
+ try:
178
+ return _preview_wrapper(s)
179
+ except RuntimeError as e:
180
+ debug('preview failed with:', repr(e),
181
+ ' Falling back to matplotlib backend')
182
+ if latex_mode != 'inline':
183
+ s = latex(o, mode='inline', **settings)
184
+ return _matplotlib_wrapper(s)
185
+
186
+ def _print_latex_svg(o):
187
+ """
188
+ A function that returns a svg rendered by an external latex
189
+ distribution, no fallback available.
190
+ """
191
+ if _can_print(o):
192
+ s = latex(o, mode=latex_mode, **settings)
193
+ if latex_mode == 'plain':
194
+ s = '$\\displaystyle %s$' % s
195
+ try:
196
+ return _svg_wrapper(s)
197
+ except RuntimeError as e:
198
+ debug('preview failed with:', repr(e),
199
+ ' No fallback available.')
200
+
201
+ def _print_latex_matplotlib(o):
202
+ """
203
+ A function that returns a png rendered by mathtext
204
+ """
205
+ if _can_print(o):
206
+ s = latex(o, mode='inline', **settings)
207
+ return _matplotlib_wrapper(s)
208
+
209
+ def _print_latex_text(o):
210
+ """
211
+ A function to generate the latex representation of SymPy expressions.
212
+ """
213
+ if _can_print(o):
214
+ s = latex(o, mode=latex_mode, **settings)
215
+ if latex_mode == 'plain':
216
+ return '$\\displaystyle %s$' % s
217
+ return s
218
+
219
+ def _result_display(self, arg):
220
+ """IPython's pretty-printer display hook, for use in IPython 0.10
221
+
222
+ This function was adapted from:
223
+
224
+ ipython/IPython/hooks.py:155
225
+
226
+ """
227
+ if self.rc.pprint:
228
+ out = stringify_func(arg)
229
+
230
+ if '\n' in out:
231
+ print()
232
+
233
+ print(out)
234
+ else:
235
+ print(repr(arg))
236
+
237
+ import IPython
238
+ if version_tuple(IPython.__version__) >= version_tuple('0.11'):
239
+
240
+ # Printable is our own type, so we handle it with methods instead of
241
+ # the approach required by builtin types. This allows downstream
242
+ # packages to override the methods in their own subclasses of Printable,
243
+ # which avoids the effects of gh-16002.
244
+ printable_types = [float, tuple, list, set, frozenset, dict, int]
245
+
246
+ plaintext_formatter = ip.display_formatter.formatters['text/plain']
247
+
248
+ # Exception to the rule above: IPython has better dispatching rules
249
+ # for plaintext printing (xref ipython/ipython#8938), and we can't
250
+ # use `_repr_pretty_` without hitting a recursion error in _print_plain.
251
+ for cls in printable_types + [Printable]:
252
+ plaintext_formatter.for_type(cls, _print_plain)
253
+
254
+ svg_formatter = ip.display_formatter.formatters['image/svg+xml']
255
+ if use_latex in ('svg', ):
256
+ debug("init_printing: using svg formatter")
257
+ for cls in printable_types:
258
+ svg_formatter.for_type(cls, _print_latex_svg)
259
+ Printable._repr_svg_ = _print_latex_svg
260
+ else:
261
+ debug("init_printing: not using any svg formatter")
262
+ for cls in printable_types:
263
+ # Better way to set this, but currently does not work in IPython
264
+ #png_formatter.for_type(cls, None)
265
+ if cls in svg_formatter.type_printers:
266
+ svg_formatter.type_printers.pop(cls)
267
+ Printable._repr_svg_ = Printable._repr_disabled
268
+
269
+ png_formatter = ip.display_formatter.formatters['image/png']
270
+ if use_latex in (True, 'png'):
271
+ debug("init_printing: using png formatter")
272
+ for cls in printable_types:
273
+ png_formatter.for_type(cls, _print_latex_png)
274
+ Printable._repr_png_ = _print_latex_png
275
+ elif use_latex == 'matplotlib':
276
+ debug("init_printing: using matplotlib formatter")
277
+ for cls in printable_types:
278
+ png_formatter.for_type(cls, _print_latex_matplotlib)
279
+ Printable._repr_png_ = _print_latex_matplotlib
280
+ else:
281
+ debug("init_printing: not using any png formatter")
282
+ for cls in printable_types:
283
+ # Better way to set this, but currently does not work in IPython
284
+ #png_formatter.for_type(cls, None)
285
+ if cls in png_formatter.type_printers:
286
+ png_formatter.type_printers.pop(cls)
287
+ Printable._repr_png_ = Printable._repr_disabled
288
+
289
+ latex_formatter = ip.display_formatter.formatters['text/latex']
290
+ if use_latex in (True, 'mathjax'):
291
+ debug("init_printing: using mathjax formatter")
292
+ for cls in printable_types:
293
+ latex_formatter.for_type(cls, _print_latex_text)
294
+ Printable._repr_latex_ = _print_latex_text
295
+ else:
296
+ debug("init_printing: not using text/latex formatter")
297
+ for cls in printable_types:
298
+ # Better way to set this, but currently does not work in IPython
299
+ #latex_formatter.for_type(cls, None)
300
+ if cls in latex_formatter.type_printers:
301
+ latex_formatter.type_printers.pop(cls)
302
+ Printable._repr_latex_ = Printable._repr_disabled
303
+
304
+ else:
305
+ ip.set_hook('result_display', _result_display)
306
+
307
+ def _is_ipython(shell):
308
+ """Is a shell instance an IPython shell?"""
309
+ # shortcut, so we don't import IPython if we don't have to
310
+ from sys import modules
311
+ if 'IPython' not in modules:
312
+ return False
313
+ try:
314
+ from IPython.core.interactiveshell import InteractiveShell
315
+ except ImportError:
316
+ # IPython < 0.11
317
+ try:
318
+ from IPython.iplib import InteractiveShell
319
+ except ImportError:
320
+ # Reaching this points means IPython has changed in a backward-incompatible way
321
+ # that we don't know about. Warn?
322
+ return False
323
+ return isinstance(shell, InteractiveShell)
324
+
325
+ # Used by the doctester to override the default for no_global
326
+ NO_GLOBAL = False
327
+
328
+ def init_printing(pretty_print=True, order=None, use_unicode=None,
329
+ use_latex=None, wrap_line=None, num_columns=None,
330
+ no_global=False, ip=None, euler=False, forecolor=None,
331
+ backcolor='Transparent', fontsize='10pt',
332
+ latex_mode='plain', print_builtin=True,
333
+ str_printer=None, pretty_printer=None,
334
+ latex_printer=None, scale=1.0, **settings):
335
+ r"""
336
+ Initializes pretty-printer depending on the environment.
337
+
338
+ Parameters
339
+ ==========
340
+
341
+ pretty_print : bool, default=True
342
+ If ``True``, use :func:`~.pretty_print` to stringify or the provided pretty
343
+ printer; if ``False``, use :func:`~.sstrrepr` to stringify or the provided string
344
+ printer.
345
+ order : string or None, default='lex'
346
+ There are a few different settings for this parameter:
347
+ ``'lex'`` (default), which is lexographic order;
348
+ ``'grlex'``, which is graded lexographic order;
349
+ ``'grevlex'``, which is reversed graded lexographic order;
350
+ ``'old'``, which is used for compatibility reasons and for long expressions;
351
+ ``None``, which sets it to lex.
352
+ use_unicode : bool or None, default=None
353
+ If ``True``, use unicode characters;
354
+ if ``False``, do not use unicode characters;
355
+ if ``None``, make a guess based on the environment.
356
+ use_latex : string, bool, or None, default=None
357
+ If ``True``, use default LaTeX rendering in GUI interfaces (png and
358
+ mathjax);
359
+ if ``False``, do not use LaTeX rendering;
360
+ if ``None``, make a guess based on the environment;
361
+ if ``'png'``, enable LaTeX rendering with an external LaTeX compiler,
362
+ falling back to matplotlib if external compilation fails;
363
+ if ``'matplotlib'``, enable LaTeX rendering with matplotlib;
364
+ if ``'mathjax'``, enable LaTeX text generation, for example MathJax
365
+ rendering in IPython notebook or text rendering in LaTeX documents;
366
+ if ``'svg'``, enable LaTeX rendering with an external latex compiler,
367
+ no fallback
368
+ wrap_line : bool
369
+ If True, lines will wrap at the end; if False, they will not wrap
370
+ but continue as one line. This is only relevant if ``pretty_print`` is
371
+ True.
372
+ num_columns : int or None, default=None
373
+ If ``int``, number of columns before wrapping is set to num_columns; if
374
+ ``None``, number of columns before wrapping is set to terminal width.
375
+ This is only relevant if ``pretty_print`` is ``True``.
376
+ no_global : bool, default=False
377
+ If ``True``, the settings become system wide;
378
+ if ``False``, use just for this console/session.
379
+ ip : An interactive console
380
+ This can either be an instance of IPython,
381
+ or a class that derives from code.InteractiveConsole.
382
+ euler : bool, optional, default=False
383
+ Loads the euler package in the LaTeX preamble for handwritten style
384
+ fonts (https://www.ctan.org/pkg/euler).
385
+ forecolor : string or None, optional, default=None
386
+ DVI setting for foreground color. ``None`` means that either ``'Black'``,
387
+ ``'White'``, or ``'Gray'`` will be selected based on a guess of the IPython
388
+ terminal color setting. See notes.
389
+ backcolor : string, optional, default='Transparent'
390
+ DVI setting for background color. See notes.
391
+ fontsize : string or int, optional, default='10pt'
392
+ A font size to pass to the LaTeX documentclass function in the
393
+ preamble. Note that the options are limited by the documentclass.
394
+ Consider using scale instead.
395
+ latex_mode : string, optional, default='plain'
396
+ The mode used in the LaTeX printer. Can be one of:
397
+ ``{'inline'|'plain'|'equation'|'equation*'}``.
398
+ print_builtin : boolean, optional, default=True
399
+ If ``True`` then floats and integers will be printed. If ``False`` the
400
+ printer will only print SymPy types.
401
+ str_printer : function, optional, default=None
402
+ A custom string printer function. This should mimic
403
+ :func:`~.sstrrepr()`.
404
+ pretty_printer : function, optional, default=None
405
+ A custom pretty printer. This should mimic :func:`~.pretty()`.
406
+ latex_printer : function, optional, default=None
407
+ A custom LaTeX printer. This should mimic :func:`~.latex()`.
408
+ scale : float, optional, default=1.0
409
+ Scale the LaTeX output when using the ``'png'`` or ``'svg'`` backends.
410
+ Useful for high dpi screens.
411
+ settings :
412
+ Any additional settings for the ``latex`` and ``pretty`` commands can
413
+ be used to fine-tune the output.
414
+
415
+ Examples
416
+ ========
417
+
418
+ >>> from sympy.interactive import init_printing
419
+ >>> from sympy import Symbol, sqrt
420
+ >>> from sympy.abc import x, y
421
+ >>> sqrt(5)
422
+ sqrt(5)
423
+ >>> init_printing(pretty_print=True) # doctest: +SKIP
424
+ >>> sqrt(5) # doctest: +SKIP
425
+ ___
426
+ \/ 5
427
+ >>> theta = Symbol('theta') # doctest: +SKIP
428
+ >>> init_printing(use_unicode=True) # doctest: +SKIP
429
+ >>> theta # doctest: +SKIP
430
+ \u03b8
431
+ >>> init_printing(use_unicode=False) # doctest: +SKIP
432
+ >>> theta # doctest: +SKIP
433
+ theta
434
+ >>> init_printing(order='lex') # doctest: +SKIP
435
+ >>> str(y + x + y**2 + x**2) # doctest: +SKIP
436
+ x**2 + x + y**2 + y
437
+ >>> init_printing(order='grlex') # doctest: +SKIP
438
+ >>> str(y + x + y**2 + x**2) # doctest: +SKIP
439
+ x**2 + x + y**2 + y
440
+ >>> init_printing(order='grevlex') # doctest: +SKIP
441
+ >>> str(y * x**2 + x * y**2) # doctest: +SKIP
442
+ x**2*y + x*y**2
443
+ >>> init_printing(order='old') # doctest: +SKIP
444
+ >>> str(x**2 + y**2 + x + y) # doctest: +SKIP
445
+ x**2 + x + y**2 + y
446
+ >>> init_printing(num_columns=10) # doctest: +SKIP
447
+ >>> x**2 + x + y**2 + y # doctest: +SKIP
448
+ x + y +
449
+ x**2 + y**2
450
+
451
+ Notes
452
+ =====
453
+
454
+ The foreground and background colors can be selected when using ``'png'`` or
455
+ ``'svg'`` LaTeX rendering. Note that before the ``init_printing`` command is
456
+ executed, the LaTeX rendering is handled by the IPython console and not SymPy.
457
+
458
+ The colors can be selected among the 68 standard colors known to ``dvips``,
459
+ for a list see [1]_. In addition, the background color can be
460
+ set to ``'Transparent'`` (which is the default value).
461
+
462
+ When using the ``'Auto'`` foreground color, the guess is based on the
463
+ ``colors`` variable in the IPython console, see [2]_. Hence, if
464
+ that variable is set correctly in your IPython console, there is a high
465
+ chance that the output will be readable, although manual settings may be
466
+ needed.
467
+
468
+
469
+ References
470
+ ==========
471
+
472
+ .. [1] https://en.wikibooks.org/wiki/LaTeX/Colors#The_68_standard_colors_known_to_dvips
473
+
474
+ .. [2] https://ipython.readthedocs.io/en/stable/config/details.html#terminal-colors
475
+
476
+ See Also
477
+ ========
478
+
479
+ sympy.printing.latex
480
+ sympy.printing.pretty
481
+
482
+ """
483
+ import sys
484
+ from sympy.printing.printer import Printer
485
+
486
+ if pretty_print:
487
+ if pretty_printer is not None:
488
+ stringify_func = pretty_printer
489
+ else:
490
+ from sympy.printing import pretty as stringify_func
491
+ else:
492
+ if str_printer is not None:
493
+ stringify_func = str_printer
494
+ else:
495
+ from sympy.printing import sstrrepr as stringify_func
496
+
497
+ # Even if ip is not passed, double check that not in IPython shell
498
+ in_ipython = False
499
+ if ip is None:
500
+ try:
501
+ ip = get_ipython()
502
+ except NameError:
503
+ pass
504
+ else:
505
+ in_ipython = (ip is not None)
506
+
507
+ if ip and not in_ipython:
508
+ in_ipython = _is_ipython(ip)
509
+
510
+ if in_ipython and pretty_print:
511
+ try:
512
+ import IPython
513
+ # IPython 1.0 deprecates the frontend module, so we import directly
514
+ # from the terminal module to prevent a deprecation message from being
515
+ # shown.
516
+ if version_tuple(IPython.__version__) >= version_tuple('1.0'):
517
+ from IPython.terminal.interactiveshell import TerminalInteractiveShell
518
+ else:
519
+ from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
520
+ from code import InteractiveConsole
521
+ except ImportError:
522
+ pass
523
+ else:
524
+ # This will be True if we are in the qtconsole or notebook
525
+ if not isinstance(ip, (InteractiveConsole, TerminalInteractiveShell)) \
526
+ and 'ipython-console' not in ''.join(sys.argv):
527
+ if use_unicode is None:
528
+ debug("init_printing: Setting use_unicode to True")
529
+ use_unicode = True
530
+ if use_latex is None:
531
+ debug("init_printing: Setting use_latex to True")
532
+ use_latex = True
533
+
534
+ if not NO_GLOBAL and not no_global:
535
+ Printer.set_global_settings(order=order, use_unicode=use_unicode,
536
+ wrap_line=wrap_line, num_columns=num_columns)
537
+ else:
538
+ _stringify_func = stringify_func
539
+
540
+ if pretty_print:
541
+ stringify_func = lambda expr, **settings: \
542
+ _stringify_func(expr, order=order,
543
+ use_unicode=use_unicode,
544
+ wrap_line=wrap_line,
545
+ num_columns=num_columns,
546
+ **settings)
547
+ else:
548
+ stringify_func = \
549
+ lambda expr, **settings: _stringify_func(
550
+ expr, order=order, **settings)
551
+
552
+ if in_ipython:
553
+ mode_in_settings = settings.pop("mode", None)
554
+ if mode_in_settings:
555
+ debug("init_printing: Mode is not able to be set due to internals"
556
+ "of IPython printing")
557
+ _init_ipython_printing(ip, stringify_func, use_latex, euler,
558
+ forecolor, backcolor, fontsize, latex_mode,
559
+ print_builtin, latex_printer, scale,
560
+ **settings)
561
+ else:
562
+ _init_python_printing(stringify_func, **settings)
lib/python3.12/site-packages/sympy/interactive/session.py ADDED
@@ -0,0 +1,463 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Tools for setting up interactive sessions. """
2
+
3
+ from sympy.external.gmpy import GROUND_TYPES
4
+ from sympy.external.importtools import version_tuple
5
+
6
+ from sympy.interactive.printing import init_printing
7
+
8
+ from sympy.utilities.misc import ARCH
9
+
10
+ preexec_source = """\
11
+ from sympy import *
12
+ x, y, z, t = symbols('x y z t')
13
+ k, m, n = symbols('k m n', integer=True)
14
+ f, g, h = symbols('f g h', cls=Function)
15
+ init_printing()
16
+ """
17
+
18
+ verbose_message = """\
19
+ These commands were executed:
20
+ %(source)s
21
+ Documentation can be found at https://docs.sympy.org/%(version)s
22
+ """
23
+
24
+ no_ipython = """\
25
+ Could not locate IPython. Having IPython installed is greatly recommended.
26
+ See http://ipython.scipy.org for more details. If you use Debian/Ubuntu,
27
+ just install the 'ipython' package and start isympy again.
28
+ """
29
+
30
+
31
+ def _make_message(ipython=True, quiet=False, source=None):
32
+ """Create a banner for an interactive session. """
33
+ from sympy import __version__ as sympy_version
34
+ from sympy import SYMPY_DEBUG
35
+
36
+ import sys
37
+ import os
38
+
39
+ if quiet:
40
+ return ""
41
+
42
+ python_version = "%d.%d.%d" % sys.version_info[:3]
43
+
44
+ if ipython:
45
+ shell_name = "IPython"
46
+ else:
47
+ shell_name = "Python"
48
+
49
+ info = ['ground types: %s' % GROUND_TYPES]
50
+
51
+ cache = os.getenv('SYMPY_USE_CACHE')
52
+
53
+ if cache is not None and cache.lower() == 'no':
54
+ info.append('cache: off')
55
+
56
+ if SYMPY_DEBUG:
57
+ info.append('debugging: on')
58
+
59
+ args = shell_name, sympy_version, python_version, ARCH, ', '.join(info)
60
+ message = "%s console for SymPy %s (Python %s-%s) (%s)\n" % args
61
+
62
+ if source is None:
63
+ source = preexec_source
64
+
65
+ _source = ""
66
+
67
+ for line in source.split('\n')[:-1]:
68
+ if not line:
69
+ _source += '\n'
70
+ else:
71
+ _source += '>>> ' + line + '\n'
72
+
73
+ doc_version = sympy_version
74
+ if 'dev' in doc_version:
75
+ doc_version = "dev"
76
+ else:
77
+ doc_version = "%s/" % doc_version
78
+
79
+ message += '\n' + verbose_message % {'source': _source,
80
+ 'version': doc_version}
81
+
82
+ return message
83
+
84
+
85
+ def int_to_Integer(s):
86
+ """
87
+ Wrap integer literals with Integer.
88
+
89
+ This is based on the decistmt example from
90
+ https://docs.python.org/3/library/tokenize.html.
91
+
92
+ Only integer literals are converted. Float literals are left alone.
93
+
94
+ Examples
95
+ ========
96
+
97
+ >>> from sympy import Integer # noqa: F401
98
+ >>> from sympy.interactive.session import int_to_Integer
99
+ >>> s = '1.2 + 1/2 - 0x12 + a1'
100
+ >>> int_to_Integer(s)
101
+ '1.2 +Integer (1 )/Integer (2 )-Integer (0x12 )+a1 '
102
+ >>> s = 'print (1/2)'
103
+ >>> int_to_Integer(s)
104
+ 'print (Integer (1 )/Integer (2 ))'
105
+ >>> exec(s)
106
+ 0.5
107
+ >>> exec(int_to_Integer(s))
108
+ 1/2
109
+ """
110
+ from tokenize import generate_tokens, untokenize, NUMBER, NAME, OP
111
+ from io import StringIO
112
+
113
+ def _is_int(num):
114
+ """
115
+ Returns true if string value num (with token NUMBER) represents an integer.
116
+ """
117
+ # XXX: Is there something in the standard library that will do this?
118
+ if '.' in num or 'j' in num.lower() or 'e' in num.lower():
119
+ return False
120
+ return True
121
+
122
+ result = []
123
+ g = generate_tokens(StringIO(s).readline) # tokenize the string
124
+ for toknum, tokval, _, _, _ in g:
125
+ if toknum == NUMBER and _is_int(tokval): # replace NUMBER tokens
126
+ result.extend([
127
+ (NAME, 'Integer'),
128
+ (OP, '('),
129
+ (NUMBER, tokval),
130
+ (OP, ')')
131
+ ])
132
+ else:
133
+ result.append((toknum, tokval))
134
+ return untokenize(result)
135
+
136
+
137
+ def enable_automatic_int_sympification(shell):
138
+ """
139
+ Allow IPython to automatically convert integer literals to Integer.
140
+ """
141
+ import ast
142
+ old_run_cell = shell.run_cell
143
+
144
+ def my_run_cell(cell, *args, **kwargs):
145
+ try:
146
+ # Check the cell for syntax errors. This way, the syntax error
147
+ # will show the original input, not the transformed input. The
148
+ # downside here is that IPython magic like %timeit will not work
149
+ # with transformed input (but on the other hand, IPython magic
150
+ # that doesn't expect transformed input will continue to work).
151
+ ast.parse(cell)
152
+ except SyntaxError:
153
+ pass
154
+ else:
155
+ cell = int_to_Integer(cell)
156
+ return old_run_cell(cell, *args, **kwargs)
157
+
158
+ shell.run_cell = my_run_cell
159
+
160
+
161
+ def enable_automatic_symbols(shell):
162
+ """Allow IPython to automatically create symbols (``isympy -a``). """
163
+ # XXX: This should perhaps use tokenize, like int_to_Integer() above.
164
+ # This would avoid re-executing the code, which can lead to subtle
165
+ # issues. For example:
166
+ #
167
+ # In [1]: a = 1
168
+ #
169
+ # In [2]: for i in range(10):
170
+ # ...: a += 1
171
+ # ...:
172
+ #
173
+ # In [3]: a
174
+ # Out[3]: 11
175
+ #
176
+ # In [4]: a = 1
177
+ #
178
+ # In [5]: for i in range(10):
179
+ # ...: a += 1
180
+ # ...: print b
181
+ # ...:
182
+ # b
183
+ # b
184
+ # b
185
+ # b
186
+ # b
187
+ # b
188
+ # b
189
+ # b
190
+ # b
191
+ # b
192
+ #
193
+ # In [6]: a
194
+ # Out[6]: 12
195
+ #
196
+ # Note how the for loop is executed again because `b` was not defined, but `a`
197
+ # was already incremented once, so the result is that it is incremented
198
+ # multiple times.
199
+
200
+ import re
201
+ re_nameerror = re.compile(
202
+ "name '(?P<symbol>[A-Za-z_][A-Za-z0-9_]*)' is not defined")
203
+
204
+ def _handler(self, etype, value, tb, tb_offset=None):
205
+ """Handle :exc:`NameError` exception and allow injection of missing symbols. """
206
+ if etype is NameError and tb.tb_next and not tb.tb_next.tb_next:
207
+ match = re_nameerror.match(str(value))
208
+
209
+ if match is not None:
210
+ # XXX: Make sure Symbol is in scope. Otherwise you'll get infinite recursion.
211
+ self.run_cell("%(symbol)s = Symbol('%(symbol)s')" %
212
+ {'symbol': match.group("symbol")}, store_history=False)
213
+
214
+ try:
215
+ code = self.user_ns['In'][-1]
216
+ except (KeyError, IndexError):
217
+ pass
218
+ else:
219
+ self.run_cell(code, store_history=False)
220
+ return None
221
+ finally:
222
+ self.run_cell("del %s" % match.group("symbol"),
223
+ store_history=False)
224
+
225
+ stb = self.InteractiveTB.structured_traceback(
226
+ etype, value, tb, tb_offset=tb_offset)
227
+ self._showtraceback(etype, value, stb)
228
+
229
+ shell.set_custom_exc((NameError,), _handler)
230
+
231
+
232
+ def init_ipython_session(shell=None, argv=[], auto_symbols=False, auto_int_to_Integer=False):
233
+ """Construct new IPython session. """
234
+ import IPython
235
+
236
+ if version_tuple(IPython.__version__) >= version_tuple('0.11'):
237
+ if not shell:
238
+ # use an app to parse the command line, and init config
239
+ # IPython 1.0 deprecates the frontend module, so we import directly
240
+ # from the terminal module to prevent a deprecation message from being
241
+ # shown.
242
+ if version_tuple(IPython.__version__) >= version_tuple('1.0'):
243
+ from IPython.terminal import ipapp
244
+ else:
245
+ from IPython.frontend.terminal import ipapp
246
+ app = ipapp.TerminalIPythonApp()
247
+
248
+ # don't draw IPython banner during initialization:
249
+ app.display_banner = False
250
+ app.initialize(argv)
251
+
252
+ shell = app.shell
253
+
254
+ if auto_symbols:
255
+ enable_automatic_symbols(shell)
256
+ if auto_int_to_Integer:
257
+ enable_automatic_int_sympification(shell)
258
+
259
+ return shell
260
+ else:
261
+ from IPython.Shell import make_IPython
262
+ return make_IPython(argv)
263
+
264
+
265
+ def init_python_session():
266
+ """Construct new Python session. """
267
+ from code import InteractiveConsole
268
+
269
+ class SymPyConsole(InteractiveConsole):
270
+ """An interactive console with readline support. """
271
+
272
+ def __init__(self):
273
+ ns_locals = {}
274
+ InteractiveConsole.__init__(self, locals=ns_locals)
275
+ try:
276
+ import rlcompleter
277
+ import readline
278
+ except ImportError:
279
+ pass
280
+ else:
281
+ import os
282
+ import atexit
283
+
284
+ readline.set_completer(rlcompleter.Completer(ns_locals).complete)
285
+ readline.parse_and_bind('tab: complete')
286
+
287
+ if hasattr(readline, 'read_history_file'):
288
+ history = os.path.expanduser('~/.sympy-history')
289
+
290
+ try:
291
+ readline.read_history_file(history)
292
+ except OSError:
293
+ pass
294
+
295
+ atexit.register(readline.write_history_file, history)
296
+
297
+ return SymPyConsole()
298
+
299
+
300
+ def init_session(ipython=None, pretty_print=True, order=None,
301
+ use_unicode=None, use_latex=None, quiet=False, auto_symbols=False,
302
+ auto_int_to_Integer=False, str_printer=None, pretty_printer=None,
303
+ latex_printer=None, argv=[]):
304
+ """
305
+ Initialize an embedded IPython or Python session. The IPython session is
306
+ initiated with the --pylab option, without the numpy imports, so that
307
+ matplotlib plotting can be interactive.
308
+
309
+ Parameters
310
+ ==========
311
+
312
+ pretty_print: boolean
313
+ If True, use pretty_print to stringify;
314
+ if False, use sstrrepr to stringify.
315
+ order: string or None
316
+ There are a few different settings for this parameter:
317
+ lex (default), which is lexographic order;
318
+ grlex, which is graded lexographic order;
319
+ grevlex, which is reversed graded lexographic order;
320
+ old, which is used for compatibility reasons and for long expressions;
321
+ None, which sets it to lex.
322
+ use_unicode: boolean or None
323
+ If True, use unicode characters;
324
+ if False, do not use unicode characters.
325
+ use_latex: boolean or None
326
+ If True, use latex rendering if IPython GUI's;
327
+ if False, do not use latex rendering.
328
+ quiet: boolean
329
+ If True, init_session will not print messages regarding its status;
330
+ if False, init_session will print messages regarding its status.
331
+ auto_symbols: boolean
332
+ If True, IPython will automatically create symbols for you.
333
+ If False, it will not.
334
+ The default is False.
335
+ auto_int_to_Integer: boolean
336
+ If True, IPython will automatically wrap int literals with Integer, so
337
+ that things like 1/2 give Rational(1, 2).
338
+ If False, it will not.
339
+ The default is False.
340
+ ipython: boolean or None
341
+ If True, printing will initialize for an IPython console;
342
+ if False, printing will initialize for a normal console;
343
+ The default is None, which automatically determines whether we are in
344
+ an ipython instance or not.
345
+ str_printer: function, optional, default=None
346
+ A custom string printer function. This should mimic
347
+ sympy.printing.sstrrepr().
348
+ pretty_printer: function, optional, default=None
349
+ A custom pretty printer. This should mimic sympy.printing.pretty().
350
+ latex_printer: function, optional, default=None
351
+ A custom LaTeX printer. This should mimic sympy.printing.latex()
352
+ This should mimic sympy.printing.latex().
353
+ argv: list of arguments for IPython
354
+ See sympy.bin.isympy for options that can be used to initialize IPython.
355
+
356
+ See Also
357
+ ========
358
+
359
+ sympy.interactive.printing.init_printing: for examples and the rest of the parameters.
360
+
361
+
362
+ Examples
363
+ ========
364
+
365
+ >>> from sympy import init_session, Symbol, sin, sqrt
366
+ >>> sin(x) #doctest: +SKIP
367
+ NameError: name 'x' is not defined
368
+ >>> init_session() #doctest: +SKIP
369
+ >>> sin(x) #doctest: +SKIP
370
+ sin(x)
371
+ >>> sqrt(5) #doctest: +SKIP
372
+ ___
373
+ \\/ 5
374
+ >>> init_session(pretty_print=False) #doctest: +SKIP
375
+ >>> sqrt(5) #doctest: +SKIP
376
+ sqrt(5)
377
+ >>> y + x + y**2 + x**2 #doctest: +SKIP
378
+ x**2 + x + y**2 + y
379
+ >>> init_session(order='grlex') #doctest: +SKIP
380
+ >>> y + x + y**2 + x**2 #doctest: +SKIP
381
+ x**2 + y**2 + x + y
382
+ >>> init_session(order='grevlex') #doctest: +SKIP
383
+ >>> y * x**2 + x * y**2 #doctest: +SKIP
384
+ x**2*y + x*y**2
385
+ >>> init_session(order='old') #doctest: +SKIP
386
+ >>> x**2 + y**2 + x + y #doctest: +SKIP
387
+ x + y + x**2 + y**2
388
+ >>> theta = Symbol('theta') #doctest: +SKIP
389
+ >>> theta #doctest: +SKIP
390
+ theta
391
+ >>> init_session(use_unicode=True) #doctest: +SKIP
392
+ >>> theta # doctest: +SKIP
393
+ \u03b8
394
+ """
395
+ import sys
396
+
397
+ in_ipython = False
398
+
399
+ if ipython is not False:
400
+ try:
401
+ import IPython
402
+ except ImportError:
403
+ if ipython is True:
404
+ raise RuntimeError("IPython is not available on this system")
405
+ ip = None
406
+ else:
407
+ try:
408
+ from IPython import get_ipython
409
+ ip = get_ipython()
410
+ except ImportError:
411
+ ip = None
412
+ in_ipython = bool(ip)
413
+ if ipython is None:
414
+ ipython = in_ipython
415
+
416
+ if ipython is False:
417
+ ip = init_python_session()
418
+ mainloop = ip.interact
419
+ else:
420
+ ip = init_ipython_session(ip, argv=argv, auto_symbols=auto_symbols,
421
+ auto_int_to_Integer=auto_int_to_Integer)
422
+
423
+ if version_tuple(IPython.__version__) >= version_tuple('0.11'):
424
+ # runsource is gone, use run_cell instead, which doesn't
425
+ # take a symbol arg. The second arg is `store_history`,
426
+ # and False means don't add the line to IPython's history.
427
+ ip.runsource = lambda src, symbol='exec': ip.run_cell(src, False)
428
+
429
+ # Enable interactive plotting using pylab.
430
+ try:
431
+ ip.enable_pylab(import_all=False)
432
+ except Exception:
433
+ # Causes an import error if matplotlib is not installed.
434
+ # Causes other errors (depending on the backend) if there
435
+ # is no display, or if there is some problem in the
436
+ # backend, so we have a bare "except Exception" here
437
+ pass
438
+ if not in_ipython:
439
+ mainloop = ip.mainloop
440
+
441
+ if auto_symbols and (not ipython or version_tuple(IPython.__version__) < version_tuple('0.11')):
442
+ raise RuntimeError("automatic construction of symbols is possible only in IPython 0.11 or above")
443
+ if auto_int_to_Integer and (not ipython or version_tuple(IPython.__version__) < version_tuple('0.11')):
444
+ raise RuntimeError("automatic int to Integer transformation is possible only in IPython 0.11 or above")
445
+
446
+ _preexec_source = preexec_source
447
+
448
+ ip.runsource(_preexec_source, symbol='exec')
449
+ init_printing(pretty_print=pretty_print, order=order,
450
+ use_unicode=use_unicode, use_latex=use_latex, ip=ip,
451
+ str_printer=str_printer, pretty_printer=pretty_printer,
452
+ latex_printer=latex_printer)
453
+
454
+ message = _make_message(ipython, quiet, _preexec_source)
455
+
456
+ if not in_ipython:
457
+ print(message)
458
+ mainloop()
459
+ sys.exit('Exiting ...')
460
+ else:
461
+ print(message)
462
+ import atexit
463
+ atexit.register(lambda: print("Exiting ...\n"))
lib/python3.12/site-packages/sympy/interactive/tests/__init__.py ADDED
File without changes
lib/python3.12/site-packages/sympy/interactive/tests/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (202 Bytes). View file
 
lib/python3.12/site-packages/sympy/interactive/tests/__pycache__/test_interactive.cpython-312.pyc ADDED
Binary file (889 Bytes). View file
 
lib/python3.12/site-packages/sympy/interactive/tests/__pycache__/test_ipython.cpython-312.pyc ADDED
Binary file (13 kB). View file
 
lib/python3.12/site-packages/sympy/interactive/tests/test_interactive.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.interactive.session import int_to_Integer
2
+
3
+
4
+ def test_int_to_Integer():
5
+ assert int_to_Integer("1 + 2.2 + 0x3 + 40") == \
6
+ 'Integer (1 )+2.2 +Integer (0x3 )+Integer (40 )'
7
+ assert int_to_Integer("0b101") == 'Integer (0b101 )'
8
+ assert int_to_Integer("ab1 + 1 + '1 + 2'") == "ab1 +Integer (1 )+'1 + 2'"
9
+ assert int_to_Integer("(2 + \n3)") == '(Integer (2 )+\nInteger (3 ))'
10
+ assert int_to_Integer("2 + 2.0 + 2j + 2e-10") == 'Integer (2 )+2.0 +2j +2e-10 '
lib/python3.12/site-packages/sympy/interactive/tests/test_ipython.py ADDED
@@ -0,0 +1,278 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Tests of tools for setting up interactive IPython sessions. """
2
+
3
+ from sympy.interactive.session import (init_ipython_session,
4
+ enable_automatic_symbols, enable_automatic_int_sympification)
5
+
6
+ from sympy.core import Symbol, Rational, Integer
7
+ from sympy.external import import_module
8
+ from sympy.testing.pytest import raises
9
+
10
+ # TODO: The code below could be made more granular with something like:
11
+ #
12
+ # @requires('IPython', version=">=0.11")
13
+ # def test_automatic_symbols(ipython):
14
+
15
+ ipython = import_module("IPython", min_module_version="0.11")
16
+
17
+ if not ipython:
18
+ #bin/test will not execute any tests now
19
+ disabled = True
20
+
21
+ # WARNING: These tests will modify the existing IPython environment. IPython
22
+ # uses a single instance for its interpreter, so there is no way to isolate
23
+ # the test from another IPython session. It also means that if this test is
24
+ # run twice in the same Python session it will fail. This isn't usually a
25
+ # problem because the test suite is run in a subprocess by default, but if the
26
+ # tests are run with subprocess=False it can pollute the current IPython
27
+ # session. See the discussion in issue #15149.
28
+
29
+ def test_automatic_symbols():
30
+ # NOTE: Because of the way the hook works, you have to use run_cell(code,
31
+ # True). This means that the code must have no Out, or it will be printed
32
+ # during the tests.
33
+ app = init_ipython_session()
34
+ app.run_cell("from sympy import *")
35
+
36
+ enable_automatic_symbols(app)
37
+
38
+ symbol = "verylongsymbolname"
39
+ assert symbol not in app.user_ns
40
+ app.run_cell("a = %s" % symbol, True)
41
+ assert symbol not in app.user_ns
42
+ app.run_cell("a = type(%s)" % symbol, True)
43
+ assert app.user_ns['a'] == Symbol
44
+ app.run_cell("%s = Symbol('%s')" % (symbol, symbol), True)
45
+ assert symbol in app.user_ns
46
+
47
+ # Check that built-in names aren't overridden
48
+ app.run_cell("a = all == __builtin__.all", True)
49
+ assert "all" not in app.user_ns
50
+ assert app.user_ns['a'] is True
51
+
52
+ # Check that SymPy names aren't overridden
53
+ app.run_cell("import sympy")
54
+ app.run_cell("a = factorial == sympy.factorial", True)
55
+ assert app.user_ns['a'] is True
56
+
57
+
58
+ def test_int_to_Integer():
59
+ # XXX: Warning, don't test with == here. 0.5 == Rational(1, 2) is True!
60
+ app = init_ipython_session()
61
+ app.run_cell("from sympy import Integer")
62
+ app.run_cell("a = 1")
63
+ assert isinstance(app.user_ns['a'], int)
64
+
65
+ enable_automatic_int_sympification(app)
66
+ app.run_cell("a = 1/2")
67
+ assert isinstance(app.user_ns['a'], Rational)
68
+ app.run_cell("a = 1")
69
+ assert isinstance(app.user_ns['a'], Integer)
70
+ app.run_cell("a = int(1)")
71
+ assert isinstance(app.user_ns['a'], int)
72
+ app.run_cell("a = (1/\n2)")
73
+ assert app.user_ns['a'] == Rational(1, 2)
74
+ # TODO: How can we test that the output of a SyntaxError is the original
75
+ # input, not the transformed input?
76
+
77
+
78
+ def test_ipythonprinting():
79
+ # Initialize and setup IPython session
80
+ app = init_ipython_session()
81
+ app.run_cell("ip = get_ipython()")
82
+ app.run_cell("inst = ip.instance()")
83
+ app.run_cell("format = inst.display_formatter.format")
84
+ app.run_cell("from sympy import Symbol")
85
+
86
+ # Printing without printing extension
87
+ app.run_cell("a = format(Symbol('pi'))")
88
+ app.run_cell("a2 = format(Symbol('pi')**2)")
89
+ # Deal with API change starting at IPython 1.0
90
+ if int(ipython.__version__.split(".")[0]) < 1:
91
+ assert app.user_ns['a']['text/plain'] == "pi"
92
+ assert app.user_ns['a2']['text/plain'] == "pi**2"
93
+ else:
94
+ assert app.user_ns['a'][0]['text/plain'] == "pi"
95
+ assert app.user_ns['a2'][0]['text/plain'] == "pi**2"
96
+
97
+ # Load printing extension
98
+ app.run_cell("from sympy import init_printing")
99
+ app.run_cell("init_printing()")
100
+ # Printing with printing extension
101
+ app.run_cell("a = format(Symbol('pi'))")
102
+ app.run_cell("a2 = format(Symbol('pi')**2)")
103
+ # Deal with API change starting at IPython 1.0
104
+ if int(ipython.__version__.split(".")[0]) < 1:
105
+ assert app.user_ns['a']['text/plain'] in ('\N{GREEK SMALL LETTER PI}', 'pi')
106
+ assert app.user_ns['a2']['text/plain'] in (' 2\n\N{GREEK SMALL LETTER PI} ', ' 2\npi ')
107
+ else:
108
+ assert app.user_ns['a'][0]['text/plain'] in ('\N{GREEK SMALL LETTER PI}', 'pi')
109
+ assert app.user_ns['a2'][0]['text/plain'] in (' 2\n\N{GREEK SMALL LETTER PI} ', ' 2\npi ')
110
+
111
+
112
+ def test_print_builtin_option():
113
+ # Initialize and setup IPython session
114
+ app = init_ipython_session()
115
+ app.run_cell("ip = get_ipython()")
116
+ app.run_cell("inst = ip.instance()")
117
+ app.run_cell("format = inst.display_formatter.format")
118
+ app.run_cell("from sympy import Symbol")
119
+ app.run_cell("from sympy import init_printing")
120
+
121
+ app.run_cell("a = format({Symbol('pi'): 3.14, Symbol('n_i'): 3})")
122
+ # Deal with API change starting at IPython 1.0
123
+ if int(ipython.__version__.split(".")[0]) < 1:
124
+ text = app.user_ns['a']['text/plain']
125
+ raises(KeyError, lambda: app.user_ns['a']['text/latex'])
126
+ else:
127
+ text = app.user_ns['a'][0]['text/plain']
128
+ raises(KeyError, lambda: app.user_ns['a'][0]['text/latex'])
129
+ # XXX: How can we make this ignore the terminal width? This test fails if
130
+ # the terminal is too narrow.
131
+ assert text in ("{pi: 3.14, n_i: 3}",
132
+ '{n\N{LATIN SUBSCRIPT SMALL LETTER I}: 3, \N{GREEK SMALL LETTER PI}: 3.14}',
133
+ "{n_i: 3, pi: 3.14}",
134
+ '{\N{GREEK SMALL LETTER PI}: 3.14, n\N{LATIN SUBSCRIPT SMALL LETTER I}: 3}')
135
+
136
+ # If we enable the default printing, then the dictionary's should render
137
+ # as a LaTeX version of the whole dict: ${\pi: 3.14, n_i: 3}$
138
+ app.run_cell("inst.display_formatter.formatters['text/latex'].enabled = True")
139
+ app.run_cell("init_printing(use_latex=True)")
140
+ app.run_cell("a = format({Symbol('pi'): 3.14, Symbol('n_i'): 3})")
141
+ # Deal with API change starting at IPython 1.0
142
+ if int(ipython.__version__.split(".")[0]) < 1:
143
+ text = app.user_ns['a']['text/plain']
144
+ latex = app.user_ns['a']['text/latex']
145
+ else:
146
+ text = app.user_ns['a'][0]['text/plain']
147
+ latex = app.user_ns['a'][0]['text/latex']
148
+ assert text in ("{pi: 3.14, n_i: 3}",
149
+ '{n\N{LATIN SUBSCRIPT SMALL LETTER I}: 3, \N{GREEK SMALL LETTER PI}: 3.14}',
150
+ "{n_i: 3, pi: 3.14}",
151
+ '{\N{GREEK SMALL LETTER PI}: 3.14, n\N{LATIN SUBSCRIPT SMALL LETTER I}: 3}')
152
+ assert latex == r'$\displaystyle \left\{ n_{i} : 3, \ \pi : 3.14\right\}$'
153
+
154
+ # Objects with an _latex overload should also be handled by our tuple
155
+ # printer.
156
+ app.run_cell("""\
157
+ class WithOverload:
158
+ def _latex(self, printer):
159
+ return r"\\LaTeX"
160
+ """)
161
+ app.run_cell("a = format((WithOverload(),))")
162
+ # Deal with API change starting at IPython 1.0
163
+ if int(ipython.__version__.split(".")[0]) < 1:
164
+ latex = app.user_ns['a']['text/latex']
165
+ else:
166
+ latex = app.user_ns['a'][0]['text/latex']
167
+ assert latex == r'$\displaystyle \left( \LaTeX,\right)$'
168
+
169
+ app.run_cell("inst.display_formatter.formatters['text/latex'].enabled = True")
170
+ app.run_cell("init_printing(use_latex=True, print_builtin=False)")
171
+ app.run_cell("a = format({Symbol('pi'): 3.14, Symbol('n_i'): 3})")
172
+ # Deal with API change starting at IPython 1.0
173
+ if int(ipython.__version__.split(".")[0]) < 1:
174
+ text = app.user_ns['a']['text/plain']
175
+ raises(KeyError, lambda: app.user_ns['a']['text/latex'])
176
+ else:
177
+ text = app.user_ns['a'][0]['text/plain']
178
+ raises(KeyError, lambda: app.user_ns['a'][0]['text/latex'])
179
+ # Note : In Python 3 we have one text type: str which holds Unicode data
180
+ # and two byte types bytes and bytearray.
181
+ # Python 3.3.3 + IPython 0.13.2 gives: '{n_i: 3, pi: 3.14}'
182
+ # Python 3.3.3 + IPython 1.1.0 gives: '{n_i: 3, pi: 3.14}'
183
+ assert text in ("{pi: 3.14, n_i: 3}", "{n_i: 3, pi: 3.14}")
184
+
185
+
186
+ def test_builtin_containers():
187
+ # Initialize and setup IPython session
188
+ app = init_ipython_session()
189
+ app.run_cell("ip = get_ipython()")
190
+ app.run_cell("inst = ip.instance()")
191
+ app.run_cell("format = inst.display_formatter.format")
192
+ app.run_cell("inst.display_formatter.formatters['text/latex'].enabled = True")
193
+ app.run_cell("from sympy import init_printing, Matrix")
194
+ app.run_cell('init_printing(use_latex=True, use_unicode=False)')
195
+
196
+ # Make sure containers that shouldn't pretty print don't.
197
+ app.run_cell('a = format((True, False))')
198
+ app.run_cell('import sys')
199
+ app.run_cell('b = format(sys.flags)')
200
+ app.run_cell('c = format((Matrix([1, 2]),))')
201
+ # Deal with API change starting at IPython 1.0
202
+ if int(ipython.__version__.split(".")[0]) < 1:
203
+ assert app.user_ns['a']['text/plain'] == '(True, False)'
204
+ assert 'text/latex' not in app.user_ns['a']
205
+ assert app.user_ns['b']['text/plain'][:10] == 'sys.flags('
206
+ assert 'text/latex' not in app.user_ns['b']
207
+ assert app.user_ns['c']['text/plain'] == \
208
+ """\
209
+ [1] \n\
210
+ ([ ],)
211
+ [2] \
212
+ """
213
+ assert app.user_ns['c']['text/latex'] == '$\\displaystyle \\left( \\left[\\begin{matrix}1\\\\2\\end{matrix}\\right],\\right)$'
214
+ else:
215
+ assert app.user_ns['a'][0]['text/plain'] == '(True, False)'
216
+ assert 'text/latex' not in app.user_ns['a'][0]
217
+ assert app.user_ns['b'][0]['text/plain'][:10] == 'sys.flags('
218
+ assert 'text/latex' not in app.user_ns['b'][0]
219
+ assert app.user_ns['c'][0]['text/plain'] == \
220
+ """\
221
+ [1] \n\
222
+ ([ ],)
223
+ [2] \
224
+ """
225
+ assert app.user_ns['c'][0]['text/latex'] == '$\\displaystyle \\left( \\left[\\begin{matrix}1\\\\2\\end{matrix}\\right],\\right)$'
226
+
227
+ def test_matplotlib_bad_latex():
228
+ # Initialize and setup IPython session
229
+ app = init_ipython_session()
230
+ app.run_cell("import IPython")
231
+ app.run_cell("ip = get_ipython()")
232
+ app.run_cell("inst = ip.instance()")
233
+ app.run_cell("format = inst.display_formatter.format")
234
+ app.run_cell("from sympy import init_printing, Matrix")
235
+ app.run_cell("init_printing(use_latex='matplotlib')")
236
+
237
+ # The png formatter is not enabled by default in this context
238
+ app.run_cell("inst.display_formatter.formatters['image/png'].enabled = True")
239
+
240
+ # Make sure no warnings are raised by IPython
241
+ app.run_cell("import warnings")
242
+ # IPython.core.formatters.FormatterWarning was introduced in IPython 2.0
243
+ if int(ipython.__version__.split(".")[0]) < 2:
244
+ app.run_cell("warnings.simplefilter('error')")
245
+ else:
246
+ app.run_cell("warnings.simplefilter('error', IPython.core.formatters.FormatterWarning)")
247
+
248
+ # This should not raise an exception
249
+ app.run_cell("a = format(Matrix([1, 2, 3]))")
250
+
251
+ # issue 9799
252
+ app.run_cell("from sympy import Piecewise, Symbol, Eq")
253
+ app.run_cell("x = Symbol('x'); pw = format(Piecewise((1, Eq(x, 0)), (0, True)))")
254
+
255
+
256
+ def test_override_repr_latex():
257
+ # Initialize and setup IPython session
258
+ app = init_ipython_session()
259
+ app.run_cell("import IPython")
260
+ app.run_cell("ip = get_ipython()")
261
+ app.run_cell("inst = ip.instance()")
262
+ app.run_cell("format = inst.display_formatter.format")
263
+ app.run_cell("inst.display_formatter.formatters['text/latex'].enabled = True")
264
+ app.run_cell("from sympy import init_printing")
265
+ app.run_cell("from sympy import Symbol")
266
+ app.run_cell("init_printing(use_latex=True)")
267
+ app.run_cell("""\
268
+ class SymbolWithOverload(Symbol):
269
+ def _repr_latex_(self):
270
+ return r"Hello " + super()._repr_latex_() + " world"
271
+ """)
272
+ app.run_cell("a = format(SymbolWithOverload('s'))")
273
+
274
+ if int(ipython.__version__.split(".")[0]) < 1:
275
+ latex = app.user_ns['a']['text/latex']
276
+ else:
277
+ latex = app.user_ns['a'][0]['text/latex']
278
+ assert latex == r'Hello $\displaystyle s$ world'
lib/python3.12/site-packages/sympy/interactive/traversal.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.basic import Basic
2
+ from sympy.printing import pprint
3
+
4
+ import random
5
+
6
+ def interactive_traversal(expr):
7
+ """Traverse a tree asking a user which branch to choose. """
8
+
9
+ RED, BRED = '\033[0;31m', '\033[1;31m'
10
+ GREEN, BGREEN = '\033[0;32m', '\033[1;32m'
11
+ YELLOW, BYELLOW = '\033[0;33m', '\033[1;33m' # noqa
12
+ BLUE, BBLUE = '\033[0;34m', '\033[1;34m' # noqa
13
+ MAGENTA, BMAGENTA = '\033[0;35m', '\033[1;35m'# noqa
14
+ CYAN, BCYAN = '\033[0;36m', '\033[1;36m' # noqa
15
+ END = '\033[0m'
16
+
17
+ def cprint(*args):
18
+ print("".join(map(str, args)) + END)
19
+
20
+ def _interactive_traversal(expr, stage):
21
+ if stage > 0:
22
+ print()
23
+
24
+ cprint("Current expression (stage ", BYELLOW, stage, END, "):")
25
+ print(BCYAN)
26
+ pprint(expr)
27
+ print(END)
28
+
29
+ if isinstance(expr, Basic):
30
+ if expr.is_Add:
31
+ args = expr.as_ordered_terms()
32
+ elif expr.is_Mul:
33
+ args = expr.as_ordered_factors()
34
+ else:
35
+ args = expr.args
36
+ elif hasattr(expr, "__iter__"):
37
+ args = list(expr)
38
+ else:
39
+ return expr
40
+
41
+ n_args = len(args)
42
+
43
+ if not n_args:
44
+ return expr
45
+
46
+ for i, arg in enumerate(args):
47
+ cprint(GREEN, "[", BGREEN, i, GREEN, "] ", BLUE, type(arg), END)
48
+ pprint(arg)
49
+ print()
50
+
51
+ if n_args == 1:
52
+ choices = '0'
53
+ else:
54
+ choices = '0-%d' % (n_args - 1)
55
+
56
+ try:
57
+ choice = input("Your choice [%s,f,l,r,d,?]: " % choices)
58
+ except EOFError:
59
+ result = expr
60
+ print()
61
+ else:
62
+ if choice == '?':
63
+ cprint(RED, "%s - select subexpression with the given index" %
64
+ choices)
65
+ cprint(RED, "f - select the first subexpression")
66
+ cprint(RED, "l - select the last subexpression")
67
+ cprint(RED, "r - select a random subexpression")
68
+ cprint(RED, "d - done\n")
69
+
70
+ result = _interactive_traversal(expr, stage)
71
+ elif choice in ('d', ''):
72
+ result = expr
73
+ elif choice == 'f':
74
+ result = _interactive_traversal(args[0], stage + 1)
75
+ elif choice == 'l':
76
+ result = _interactive_traversal(args[-1], stage + 1)
77
+ elif choice == 'r':
78
+ result = _interactive_traversal(random.choice(args), stage + 1)
79
+ else:
80
+ try:
81
+ choice = int(choice)
82
+ except ValueError:
83
+ cprint(BRED,
84
+ "Choice must be a number in %s range\n" % choices)
85
+ result = _interactive_traversal(expr, stage)
86
+ else:
87
+ if choice < 0 or choice >= n_args:
88
+ cprint(BRED, "Choice must be in %s range\n" % choices)
89
+ result = _interactive_traversal(expr, stage)
90
+ else:
91
+ result = _interactive_traversal(args[choice], stage + 1)
92
+
93
+ return result
94
+
95
+ return _interactive_traversal(expr, 0)
lib/python3.12/site-packages/sympy/plotting/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (630 Bytes). View file
 
lib/python3.12/site-packages/sympy/plotting/__pycache__/experimental_lambdify.cpython-312.pyc ADDED
Binary file (20.6 kB). View file
 
lib/python3.12/site-packages/sympy/plotting/__pycache__/plot.cpython-312.pyc ADDED
Binary file (43.7 kB). View file
 
lib/python3.12/site-packages/sympy/plotting/__pycache__/plot_implicit.cpython-312.pyc ADDED
Binary file (8.51 kB). View file
 
lib/python3.12/site-packages/sympy/plotting/__pycache__/plotgrid.cpython-312.pyc ADDED
Binary file (8.34 kB). View file
 
lib/python3.12/site-packages/sympy/plotting/__pycache__/textplot.cpython-312.pyc ADDED
Binary file (7.05 kB). View file
 
lib/python3.12/site-packages/sympy/plotting/__pycache__/utils.cpython-312.pyc ADDED
Binary file (14.4 kB). View file
 
lib/python3.12/site-packages/sympy/plotting/intervalmath/__init__.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .interval_arithmetic import interval
2
+ from .lib_interval import (Abs, exp, log, log10, sin, cos, tan, sqrt,
3
+ imin, imax, sinh, cosh, tanh, acosh, asinh, atanh,
4
+ asin, acos, atan, ceil, floor, And, Or)
5
+
6
+ __all__ = [
7
+ 'interval',
8
+
9
+ 'Abs', 'exp', 'log', 'log10', 'sin', 'cos', 'tan', 'sqrt', 'imin', 'imax',
10
+ 'sinh', 'cosh', 'tanh', 'acosh', 'asinh', 'atanh', 'asin', 'acos', 'atan',
11
+ 'ceil', 'floor', 'And', 'Or',
12
+ ]
lib/python3.12/site-packages/sympy/plotting/intervalmath/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (814 Bytes). View file
 
lib/python3.12/site-packages/sympy/plotting/intervalmath/__pycache__/interval_arithmetic.cpython-312.pyc ADDED
Binary file (19.1 kB). View file
 
lib/python3.12/site-packages/sympy/plotting/intervalmath/__pycache__/interval_membership.cpython-312.pyc ADDED
Binary file (4.03 kB). View file
 
lib/python3.12/site-packages/sympy/plotting/intervalmath/__pycache__/lib_interval.cpython-312.pyc ADDED
Binary file (22.7 kB). View file
 
lib/python3.12/site-packages/sympy/plotting/intervalmath/interval_arithmetic.py ADDED
@@ -0,0 +1,413 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Interval Arithmetic for plotting.
3
+ This module does not implement interval arithmetic accurately and
4
+ hence cannot be used for purposes other than plotting. If you want
5
+ to use interval arithmetic, use mpmath's interval arithmetic.
6
+
7
+ The module implements interval arithmetic using numpy and
8
+ python floating points. The rounding up and down is not handled
9
+ and hence this is not an accurate implementation of interval
10
+ arithmetic.
11
+
12
+ The module uses numpy for speed which cannot be achieved with mpmath.
13
+ """
14
+
15
+ # Q: Why use numpy? Why not simply use mpmath's interval arithmetic?
16
+ # A: mpmath's interval arithmetic simulates a floating point unit
17
+ # and hence is slow, while numpy evaluations are orders of magnitude
18
+ # faster.
19
+
20
+ # Q: Why create a separate class for intervals? Why not use SymPy's
21
+ # Interval Sets?
22
+ # A: The functionalities that will be required for plotting is quite
23
+ # different from what Interval Sets implement.
24
+
25
+ # Q: Why is rounding up and down according to IEEE754 not handled?
26
+ # A: It is not possible to do it in both numpy and python. An external
27
+ # library has to used, which defeats the whole purpose i.e., speed. Also
28
+ # rounding is handled for very few functions in those libraries.
29
+
30
+ # Q Will my plots be affected?
31
+ # A It will not affect most of the plots. The interval arithmetic
32
+ # module based suffers the same problems as that of floating point
33
+ # arithmetic.
34
+
35
+ from sympy.core.numbers import int_valued
36
+ from sympy.core.logic import fuzzy_and
37
+ from sympy.simplify.simplify import nsimplify
38
+
39
+ from .interval_membership import intervalMembership
40
+
41
+
42
+ class interval:
43
+ """ Represents an interval containing floating points as start and
44
+ end of the interval
45
+ The is_valid variable tracks whether the interval obtained as the
46
+ result of the function is in the domain and is continuous.
47
+ - True: Represents the interval result of a function is continuous and
48
+ in the domain of the function.
49
+ - False: The interval argument of the function was not in the domain of
50
+ the function, hence the is_valid of the result interval is False
51
+ - None: The function was not continuous over the interval or
52
+ the function's argument interval is partly in the domain of the
53
+ function
54
+
55
+ A comparison between an interval and a real number, or a
56
+ comparison between two intervals may return ``intervalMembership``
57
+ of two 3-valued logic values.
58
+ """
59
+
60
+ def __init__(self, *args, is_valid=True, **kwargs):
61
+ self.is_valid = is_valid
62
+ if len(args) == 1:
63
+ if isinstance(args[0], interval):
64
+ self.start, self.end = args[0].start, args[0].end
65
+ else:
66
+ self.start = float(args[0])
67
+ self.end = float(args[0])
68
+ elif len(args) == 2:
69
+ if args[0] < args[1]:
70
+ self.start = float(args[0])
71
+ self.end = float(args[1])
72
+ else:
73
+ self.start = float(args[1])
74
+ self.end = float(args[0])
75
+
76
+ else:
77
+ raise ValueError("interval takes a maximum of two float values "
78
+ "as arguments")
79
+
80
+ @property
81
+ def mid(self):
82
+ return (self.start + self.end) / 2.0
83
+
84
+ @property
85
+ def width(self):
86
+ return self.end - self.start
87
+
88
+ def __repr__(self):
89
+ return "interval(%f, %f)" % (self.start, self.end)
90
+
91
+ def __str__(self):
92
+ return "[%f, %f]" % (self.start, self.end)
93
+
94
+ def __lt__(self, other):
95
+ if isinstance(other, (int, float)):
96
+ if self.end < other:
97
+ return intervalMembership(True, self.is_valid)
98
+ elif self.start > other:
99
+ return intervalMembership(False, self.is_valid)
100
+ else:
101
+ return intervalMembership(None, self.is_valid)
102
+
103
+ elif isinstance(other, interval):
104
+ valid = fuzzy_and([self.is_valid, other.is_valid])
105
+ if self.end < other. start:
106
+ return intervalMembership(True, valid)
107
+ if self.start > other.end:
108
+ return intervalMembership(False, valid)
109
+ return intervalMembership(None, valid)
110
+ else:
111
+ return NotImplemented
112
+
113
+ def __gt__(self, other):
114
+ if isinstance(other, (int, float)):
115
+ if self.start > other:
116
+ return intervalMembership(True, self.is_valid)
117
+ elif self.end < other:
118
+ return intervalMembership(False, self.is_valid)
119
+ else:
120
+ return intervalMembership(None, self.is_valid)
121
+ elif isinstance(other, interval):
122
+ return other.__lt__(self)
123
+ else:
124
+ return NotImplemented
125
+
126
+ def __eq__(self, other):
127
+ if isinstance(other, (int, float)):
128
+ if self.start == other and self.end == other:
129
+ return intervalMembership(True, self.is_valid)
130
+ if other in self:
131
+ return intervalMembership(None, self.is_valid)
132
+ else:
133
+ return intervalMembership(False, self.is_valid)
134
+
135
+ if isinstance(other, interval):
136
+ valid = fuzzy_and([self.is_valid, other.is_valid])
137
+ if self.start == other.start and self.end == other.end:
138
+ return intervalMembership(True, valid)
139
+ elif self.__lt__(other)[0] is not None:
140
+ return intervalMembership(False, valid)
141
+ else:
142
+ return intervalMembership(None, valid)
143
+ else:
144
+ return NotImplemented
145
+
146
+ def __ne__(self, other):
147
+ if isinstance(other, (int, float)):
148
+ if self.start == other and self.end == other:
149
+ return intervalMembership(False, self.is_valid)
150
+ if other in self:
151
+ return intervalMembership(None, self.is_valid)
152
+ else:
153
+ return intervalMembership(True, self.is_valid)
154
+
155
+ if isinstance(other, interval):
156
+ valid = fuzzy_and([self.is_valid, other.is_valid])
157
+ if self.start == other.start and self.end == other.end:
158
+ return intervalMembership(False, valid)
159
+ if not self.__lt__(other)[0] is None:
160
+ return intervalMembership(True, valid)
161
+ return intervalMembership(None, valid)
162
+ else:
163
+ return NotImplemented
164
+
165
+ def __le__(self, other):
166
+ if isinstance(other, (int, float)):
167
+ if self.end <= other:
168
+ return intervalMembership(True, self.is_valid)
169
+ if self.start > other:
170
+ return intervalMembership(False, self.is_valid)
171
+ else:
172
+ return intervalMembership(None, self.is_valid)
173
+
174
+ if isinstance(other, interval):
175
+ valid = fuzzy_and([self.is_valid, other.is_valid])
176
+ if self.end <= other.start:
177
+ return intervalMembership(True, valid)
178
+ if self.start > other.end:
179
+ return intervalMembership(False, valid)
180
+ return intervalMembership(None, valid)
181
+ else:
182
+ return NotImplemented
183
+
184
+ def __ge__(self, other):
185
+ if isinstance(other, (int, float)):
186
+ if self.start >= other:
187
+ return intervalMembership(True, self.is_valid)
188
+ elif self.end < other:
189
+ return intervalMembership(False, self.is_valid)
190
+ else:
191
+ return intervalMembership(None, self.is_valid)
192
+ elif isinstance(other, interval):
193
+ return other.__le__(self)
194
+
195
+ def __add__(self, other):
196
+ if isinstance(other, (int, float)):
197
+ if self.is_valid:
198
+ return interval(self.start + other, self.end + other)
199
+ else:
200
+ start = self.start + other
201
+ end = self.end + other
202
+ return interval(start, end, is_valid=self.is_valid)
203
+
204
+ elif isinstance(other, interval):
205
+ start = self.start + other.start
206
+ end = self.end + other.end
207
+ valid = fuzzy_and([self.is_valid, other.is_valid])
208
+ return interval(start, end, is_valid=valid)
209
+ else:
210
+ return NotImplemented
211
+
212
+ __radd__ = __add__
213
+
214
+ def __sub__(self, other):
215
+ if isinstance(other, (int, float)):
216
+ start = self.start - other
217
+ end = self.end - other
218
+ return interval(start, end, is_valid=self.is_valid)
219
+
220
+ elif isinstance(other, interval):
221
+ start = self.start - other.end
222
+ end = self.end - other.start
223
+ valid = fuzzy_and([self.is_valid, other.is_valid])
224
+ return interval(start, end, is_valid=valid)
225
+ else:
226
+ return NotImplemented
227
+
228
+ def __rsub__(self, other):
229
+ if isinstance(other, (int, float)):
230
+ start = other - self.end
231
+ end = other - self.start
232
+ return interval(start, end, is_valid=self.is_valid)
233
+ elif isinstance(other, interval):
234
+ return other.__sub__(self)
235
+ else:
236
+ return NotImplemented
237
+
238
+ def __neg__(self):
239
+ if self.is_valid:
240
+ return interval(-self.end, -self.start)
241
+ else:
242
+ return interval(-self.end, -self.start, is_valid=self.is_valid)
243
+
244
+ def __mul__(self, other):
245
+ if isinstance(other, interval):
246
+ if self.is_valid is False or other.is_valid is False:
247
+ return interval(-float('inf'), float('inf'), is_valid=False)
248
+ elif self.is_valid is None or other.is_valid is None:
249
+ return interval(-float('inf'), float('inf'), is_valid=None)
250
+ else:
251
+ inters = []
252
+ inters.append(self.start * other.start)
253
+ inters.append(self.end * other.start)
254
+ inters.append(self.start * other.end)
255
+ inters.append(self.end * other.end)
256
+ start = min(inters)
257
+ end = max(inters)
258
+ return interval(start, end)
259
+ elif isinstance(other, (int, float)):
260
+ return interval(self.start*other, self.end*other, is_valid=self.is_valid)
261
+ else:
262
+ return NotImplemented
263
+
264
+ __rmul__ = __mul__
265
+
266
+ def __contains__(self, other):
267
+ if isinstance(other, (int, float)):
268
+ return self.start <= other and self.end >= other
269
+ else:
270
+ return self.start <= other.start and other.end <= self.end
271
+
272
+ def __rtruediv__(self, other):
273
+ if isinstance(other, (int, float)):
274
+ other = interval(other)
275
+ return other.__truediv__(self)
276
+ elif isinstance(other, interval):
277
+ return other.__truediv__(self)
278
+ else:
279
+ return NotImplemented
280
+
281
+ def __truediv__(self, other):
282
+ # Both None and False are handled
283
+ if not self.is_valid:
284
+ # Don't divide as the value is not valid
285
+ return interval(-float('inf'), float('inf'), is_valid=self.is_valid)
286
+ if isinstance(other, (int, float)):
287
+ if other == 0:
288
+ # Divide by zero encountered. valid nowhere
289
+ return interval(-float('inf'), float('inf'), is_valid=False)
290
+ else:
291
+ return interval(self.start / other, self.end / other)
292
+
293
+ elif isinstance(other, interval):
294
+ if other.is_valid is False or self.is_valid is False:
295
+ return interval(-float('inf'), float('inf'), is_valid=False)
296
+ elif other.is_valid is None or self.is_valid is None:
297
+ return interval(-float('inf'), float('inf'), is_valid=None)
298
+ else:
299
+ # denominator contains both signs, i.e. being divided by zero
300
+ # return the whole real line with is_valid = None
301
+ if 0 in other:
302
+ return interval(-float('inf'), float('inf'), is_valid=None)
303
+
304
+ # denominator negative
305
+ this = self
306
+ if other.end < 0:
307
+ this = -this
308
+ other = -other
309
+
310
+ # denominator positive
311
+ inters = []
312
+ inters.append(this.start / other.start)
313
+ inters.append(this.end / other.start)
314
+ inters.append(this.start / other.end)
315
+ inters.append(this.end / other.end)
316
+ start = max(inters)
317
+ end = min(inters)
318
+ return interval(start, end)
319
+ else:
320
+ return NotImplemented
321
+
322
+ def __pow__(self, other):
323
+ # Implements only power to an integer.
324
+ from .lib_interval import exp, log
325
+ if not self.is_valid:
326
+ return self
327
+ if isinstance(other, interval):
328
+ return exp(other * log(self))
329
+ elif isinstance(other, (float, int)):
330
+ if other < 0:
331
+ return 1 / self.__pow__(abs(other))
332
+ else:
333
+ if int_valued(other):
334
+ return _pow_int(self, other)
335
+ else:
336
+ return _pow_float(self, other)
337
+ else:
338
+ return NotImplemented
339
+
340
+ def __rpow__(self, other):
341
+ if isinstance(other, (float, int)):
342
+ if not self.is_valid:
343
+ #Don't do anything
344
+ return self
345
+ elif other < 0:
346
+ if self.width > 0:
347
+ return interval(-float('inf'), float('inf'), is_valid=False)
348
+ else:
349
+ power_rational = nsimplify(self.start)
350
+ num, denom = power_rational.as_numer_denom()
351
+ if denom % 2 == 0:
352
+ return interval(-float('inf'), float('inf'),
353
+ is_valid=False)
354
+ else:
355
+ start = -abs(other)**self.start
356
+ end = start
357
+ return interval(start, end)
358
+ else:
359
+ return interval(other**self.start, other**self.end)
360
+ elif isinstance(other, interval):
361
+ return other.__pow__(self)
362
+ else:
363
+ return NotImplemented
364
+
365
+ def __hash__(self):
366
+ return hash((self.is_valid, self.start, self.end))
367
+
368
+
369
+ def _pow_float(inter, power):
370
+ """Evaluates an interval raised to a floating point."""
371
+ power_rational = nsimplify(power)
372
+ num, denom = power_rational.as_numer_denom()
373
+ if num % 2 == 0:
374
+ start = abs(inter.start)**power
375
+ end = abs(inter.end)**power
376
+ if start < 0:
377
+ ret = interval(0, max(start, end))
378
+ else:
379
+ ret = interval(start, end)
380
+ return ret
381
+ elif denom % 2 == 0:
382
+ if inter.end < 0:
383
+ return interval(-float('inf'), float('inf'), is_valid=False)
384
+ elif inter.start < 0:
385
+ return interval(0, inter.end**power, is_valid=None)
386
+ else:
387
+ return interval(inter.start**power, inter.end**power)
388
+ else:
389
+ if inter.start < 0:
390
+ start = -abs(inter.start)**power
391
+ else:
392
+ start = inter.start**power
393
+
394
+ if inter.end < 0:
395
+ end = -abs(inter.end)**power
396
+ else:
397
+ end = inter.end**power
398
+
399
+ return interval(start, end, is_valid=inter.is_valid)
400
+
401
+
402
+ def _pow_int(inter, power):
403
+ """Evaluates an interval raised to an integer power"""
404
+ power = int(power)
405
+ if power & 1:
406
+ return interval(inter.start**power, inter.end**power)
407
+ else:
408
+ if inter.start < 0 and inter.end > 0:
409
+ start = 0
410
+ end = max(inter.start**power, inter.end**power)
411
+ return interval(start, end)
412
+ else:
413
+ return interval(inter.start**power, inter.end**power)
lib/python3.12/site-packages/sympy/plotting/intervalmath/interval_membership.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.logic import fuzzy_and, fuzzy_or, fuzzy_not, fuzzy_xor
2
+
3
+
4
+ class intervalMembership:
5
+ """Represents a boolean expression returned by the comparison of
6
+ the interval object.
7
+
8
+ Parameters
9
+ ==========
10
+
11
+ (a, b) : (bool, bool)
12
+ The first value determines the comparison as follows:
13
+ - True: If the comparison is True throughout the intervals.
14
+ - False: If the comparison is False throughout the intervals.
15
+ - None: If the comparison is True for some part of the intervals.
16
+
17
+ The second value is determined as follows:
18
+ - True: If both the intervals in comparison are valid.
19
+ - False: If at least one of the intervals is False, else
20
+ - None
21
+ """
22
+ def __init__(self, a, b):
23
+ self._wrapped = (a, b)
24
+
25
+ def __getitem__(self, i):
26
+ try:
27
+ return self._wrapped[i]
28
+ except IndexError:
29
+ raise IndexError(
30
+ "{} must be a valid indexing for the 2-tuple."
31
+ .format(i))
32
+
33
+ def __len__(self):
34
+ return 2
35
+
36
+ def __iter__(self):
37
+ return iter(self._wrapped)
38
+
39
+ def __str__(self):
40
+ return "intervalMembership({}, {})".format(*self)
41
+ __repr__ = __str__
42
+
43
+ def __and__(self, other):
44
+ if not isinstance(other, intervalMembership):
45
+ raise ValueError(
46
+ "The comparison is not supported for {}.".format(other))
47
+
48
+ a1, b1 = self
49
+ a2, b2 = other
50
+ return intervalMembership(fuzzy_and([a1, a2]), fuzzy_and([b1, b2]))
51
+
52
+ def __or__(self, other):
53
+ if not isinstance(other, intervalMembership):
54
+ raise ValueError(
55
+ "The comparison is not supported for {}.".format(other))
56
+
57
+ a1, b1 = self
58
+ a2, b2 = other
59
+ return intervalMembership(fuzzy_or([a1, a2]), fuzzy_and([b1, b2]))
60
+
61
+ def __invert__(self):
62
+ a, b = self
63
+ return intervalMembership(fuzzy_not(a), b)
64
+
65
+ def __xor__(self, other):
66
+ if not isinstance(other, intervalMembership):
67
+ raise ValueError(
68
+ "The comparison is not supported for {}.".format(other))
69
+
70
+ a1, b1 = self
71
+ a2, b2 = other
72
+ return intervalMembership(fuzzy_xor([a1, a2]), fuzzy_and([b1, b2]))
73
+
74
+ def __eq__(self, other):
75
+ return self._wrapped == other
76
+
77
+ def __ne__(self, other):
78
+ return self._wrapped != other
lib/python3.12/site-packages/sympy/plotting/intervalmath/lib_interval.py ADDED
@@ -0,0 +1,452 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ The module contains implemented functions for interval arithmetic."""
2
+ from functools import reduce
3
+
4
+ from sympy.plotting.intervalmath import interval
5
+ from sympy.external import import_module
6
+
7
+
8
+ def Abs(x):
9
+ if isinstance(x, (int, float)):
10
+ return interval(abs(x))
11
+ elif isinstance(x, interval):
12
+ if x.start < 0 and x.end > 0:
13
+ return interval(0, max(abs(x.start), abs(x.end)), is_valid=x.is_valid)
14
+ else:
15
+ return interval(abs(x.start), abs(x.end))
16
+ else:
17
+ raise NotImplementedError
18
+
19
+ #Monotonic
20
+
21
+
22
+ def exp(x):
23
+ """evaluates the exponential of an interval"""
24
+ np = import_module('numpy')
25
+ if isinstance(x, (int, float)):
26
+ return interval(np.exp(x), np.exp(x))
27
+ elif isinstance(x, interval):
28
+ return interval(np.exp(x.start), np.exp(x.end), is_valid=x.is_valid)
29
+ else:
30
+ raise NotImplementedError
31
+
32
+
33
+ #Monotonic
34
+ def log(x):
35
+ """evaluates the natural logarithm of an interval"""
36
+ np = import_module('numpy')
37
+ if isinstance(x, (int, float)):
38
+ if x <= 0:
39
+ return interval(-np.inf, np.inf, is_valid=False)
40
+ else:
41
+ return interval(np.log(x))
42
+ elif isinstance(x, interval):
43
+ if not x.is_valid:
44
+ return interval(-np.inf, np.inf, is_valid=x.is_valid)
45
+ elif x.end <= 0:
46
+ return interval(-np.inf, np.inf, is_valid=False)
47
+ elif x.start <= 0:
48
+ return interval(-np.inf, np.inf, is_valid=None)
49
+
50
+ return interval(np.log(x.start), np.log(x.end))
51
+ else:
52
+ raise NotImplementedError
53
+
54
+
55
+ #Monotonic
56
+ def log10(x):
57
+ """evaluates the logarithm to the base 10 of an interval"""
58
+ np = import_module('numpy')
59
+ if isinstance(x, (int, float)):
60
+ if x <= 0:
61
+ return interval(-np.inf, np.inf, is_valid=False)
62
+ else:
63
+ return interval(np.log10(x))
64
+ elif isinstance(x, interval):
65
+ if not x.is_valid:
66
+ return interval(-np.inf, np.inf, is_valid=x.is_valid)
67
+ elif x.end <= 0:
68
+ return interval(-np.inf, np.inf, is_valid=False)
69
+ elif x.start <= 0:
70
+ return interval(-np.inf, np.inf, is_valid=None)
71
+ return interval(np.log10(x.start), np.log10(x.end))
72
+ else:
73
+ raise NotImplementedError
74
+
75
+
76
+ #Monotonic
77
+ def atan(x):
78
+ """evaluates the tan inverse of an interval"""
79
+ np = import_module('numpy')
80
+ if isinstance(x, (int, float)):
81
+ return interval(np.arctan(x))
82
+ elif isinstance(x, interval):
83
+ start = np.arctan(x.start)
84
+ end = np.arctan(x.end)
85
+ return interval(start, end, is_valid=x.is_valid)
86
+ else:
87
+ raise NotImplementedError
88
+
89
+
90
+ #periodic
91
+ def sin(x):
92
+ """evaluates the sine of an interval"""
93
+ np = import_module('numpy')
94
+ if isinstance(x, (int, float)):
95
+ return interval(np.sin(x))
96
+ elif isinstance(x, interval):
97
+ if not x.is_valid:
98
+ return interval(-1, 1, is_valid=x.is_valid)
99
+ na, __ = divmod(x.start, np.pi / 2.0)
100
+ nb, __ = divmod(x.end, np.pi / 2.0)
101
+ start = min(np.sin(x.start), np.sin(x.end))
102
+ end = max(np.sin(x.start), np.sin(x.end))
103
+ if nb - na > 4:
104
+ return interval(-1, 1, is_valid=x.is_valid)
105
+ elif na == nb:
106
+ return interval(start, end, is_valid=x.is_valid)
107
+ else:
108
+ if (na - 1) // 4 != (nb - 1) // 4:
109
+ #sin has max
110
+ end = 1
111
+ if (na - 3) // 4 != (nb - 3) // 4:
112
+ #sin has min
113
+ start = -1
114
+ return interval(start, end)
115
+ else:
116
+ raise NotImplementedError
117
+
118
+
119
+ #periodic
120
+ def cos(x):
121
+ """Evaluates the cos of an interval"""
122
+ np = import_module('numpy')
123
+ if isinstance(x, (int, float)):
124
+ return interval(np.sin(x))
125
+ elif isinstance(x, interval):
126
+ if not (np.isfinite(x.start) and np.isfinite(x.end)):
127
+ return interval(-1, 1, is_valid=x.is_valid)
128
+ na, __ = divmod(x.start, np.pi / 2.0)
129
+ nb, __ = divmod(x.end, np.pi / 2.0)
130
+ start = min(np.cos(x.start), np.cos(x.end))
131
+ end = max(np.cos(x.start), np.cos(x.end))
132
+ if nb - na > 4:
133
+ #differ more than 2*pi
134
+ return interval(-1, 1, is_valid=x.is_valid)
135
+ elif na == nb:
136
+ #in the same quadarant
137
+ return interval(start, end, is_valid=x.is_valid)
138
+ else:
139
+ if (na) // 4 != (nb) // 4:
140
+ #cos has max
141
+ end = 1
142
+ if (na - 2) // 4 != (nb - 2) // 4:
143
+ #cos has min
144
+ start = -1
145
+ return interval(start, end, is_valid=x.is_valid)
146
+ else:
147
+ raise NotImplementedError
148
+
149
+
150
+ def tan(x):
151
+ """Evaluates the tan of an interval"""
152
+ return sin(x) / cos(x)
153
+
154
+
155
+ #Monotonic
156
+ def sqrt(x):
157
+ """Evaluates the square root of an interval"""
158
+ np = import_module('numpy')
159
+ if isinstance(x, (int, float)):
160
+ if x > 0:
161
+ return interval(np.sqrt(x))
162
+ else:
163
+ return interval(-np.inf, np.inf, is_valid=False)
164
+ elif isinstance(x, interval):
165
+ #Outside the domain
166
+ if x.end < 0:
167
+ return interval(-np.inf, np.inf, is_valid=False)
168
+ #Partially outside the domain
169
+ elif x.start < 0:
170
+ return interval(-np.inf, np.inf, is_valid=None)
171
+ else:
172
+ return interval(np.sqrt(x.start), np.sqrt(x.end),
173
+ is_valid=x.is_valid)
174
+ else:
175
+ raise NotImplementedError
176
+
177
+
178
+ def imin(*args):
179
+ """Evaluates the minimum of a list of intervals"""
180
+ np = import_module('numpy')
181
+ if not all(isinstance(arg, (int, float, interval)) for arg in args):
182
+ return NotImplementedError
183
+ else:
184
+ new_args = [a for a in args if isinstance(a, (int, float))
185
+ or a.is_valid]
186
+ if len(new_args) == 0:
187
+ if all(a.is_valid is False for a in args):
188
+ return interval(-np.inf, np.inf, is_valid=False)
189
+ else:
190
+ return interval(-np.inf, np.inf, is_valid=None)
191
+ start_array = [a if isinstance(a, (int, float)) else a.start
192
+ for a in new_args]
193
+
194
+ end_array = [a if isinstance(a, (int, float)) else a.end
195
+ for a in new_args]
196
+ return interval(min(start_array), min(end_array))
197
+
198
+
199
+ def imax(*args):
200
+ """Evaluates the maximum of a list of intervals"""
201
+ np = import_module('numpy')
202
+ if not all(isinstance(arg, (int, float, interval)) for arg in args):
203
+ return NotImplementedError
204
+ else:
205
+ new_args = [a for a in args if isinstance(a, (int, float))
206
+ or a.is_valid]
207
+ if len(new_args) == 0:
208
+ if all(a.is_valid is False for a in args):
209
+ return interval(-np.inf, np.inf, is_valid=False)
210
+ else:
211
+ return interval(-np.inf, np.inf, is_valid=None)
212
+ start_array = [a if isinstance(a, (int, float)) else a.start
213
+ for a in new_args]
214
+
215
+ end_array = [a if isinstance(a, (int, float)) else a.end
216
+ for a in new_args]
217
+
218
+ return interval(max(start_array), max(end_array))
219
+
220
+
221
+ #Monotonic
222
+ def sinh(x):
223
+ """Evaluates the hyperbolic sine of an interval"""
224
+ np = import_module('numpy')
225
+ if isinstance(x, (int, float)):
226
+ return interval(np.sinh(x), np.sinh(x))
227
+ elif isinstance(x, interval):
228
+ return interval(np.sinh(x.start), np.sinh(x.end), is_valid=x.is_valid)
229
+ else:
230
+ raise NotImplementedError
231
+
232
+
233
+ def cosh(x):
234
+ """Evaluates the hyperbolic cos of an interval"""
235
+ np = import_module('numpy')
236
+ if isinstance(x, (int, float)):
237
+ return interval(np.cosh(x), np.cosh(x))
238
+ elif isinstance(x, interval):
239
+ #both signs
240
+ if x.start < 0 and x.end > 0:
241
+ end = max(np.cosh(x.start), np.cosh(x.end))
242
+ return interval(1, end, is_valid=x.is_valid)
243
+ else:
244
+ #Monotonic
245
+ start = np.cosh(x.start)
246
+ end = np.cosh(x.end)
247
+ return interval(start, end, is_valid=x.is_valid)
248
+ else:
249
+ raise NotImplementedError
250
+
251
+
252
+ #Monotonic
253
+ def tanh(x):
254
+ """Evaluates the hyperbolic tan of an interval"""
255
+ np = import_module('numpy')
256
+ if isinstance(x, (int, float)):
257
+ return interval(np.tanh(x), np.tanh(x))
258
+ elif isinstance(x, interval):
259
+ return interval(np.tanh(x.start), np.tanh(x.end), is_valid=x.is_valid)
260
+ else:
261
+ raise NotImplementedError
262
+
263
+
264
+ def asin(x):
265
+ """Evaluates the inverse sine of an interval"""
266
+ np = import_module('numpy')
267
+ if isinstance(x, (int, float)):
268
+ #Outside the domain
269
+ if abs(x) > 1:
270
+ return interval(-np.inf, np.inf, is_valid=False)
271
+ else:
272
+ return interval(np.arcsin(x), np.arcsin(x))
273
+ elif isinstance(x, interval):
274
+ #Outside the domain
275
+ if x.is_valid is False or x.start > 1 or x.end < -1:
276
+ return interval(-np.inf, np.inf, is_valid=False)
277
+ #Partially outside the domain
278
+ elif x.start < -1 or x.end > 1:
279
+ return interval(-np.inf, np.inf, is_valid=None)
280
+ else:
281
+ start = np.arcsin(x.start)
282
+ end = np.arcsin(x.end)
283
+ return interval(start, end, is_valid=x.is_valid)
284
+
285
+
286
+ def acos(x):
287
+ """Evaluates the inverse cos of an interval"""
288
+ np = import_module('numpy')
289
+ if isinstance(x, (int, float)):
290
+ if abs(x) > 1:
291
+ #Outside the domain
292
+ return interval(-np.inf, np.inf, is_valid=False)
293
+ else:
294
+ return interval(np.arccos(x), np.arccos(x))
295
+ elif isinstance(x, interval):
296
+ #Outside the domain
297
+ if x.is_valid is False or x.start > 1 or x.end < -1:
298
+ return interval(-np.inf, np.inf, is_valid=False)
299
+ #Partially outside the domain
300
+ elif x.start < -1 or x.end > 1:
301
+ return interval(-np.inf, np.inf, is_valid=None)
302
+ else:
303
+ start = np.arccos(x.start)
304
+ end = np.arccos(x.end)
305
+ return interval(start, end, is_valid=x.is_valid)
306
+
307
+
308
+ def ceil(x):
309
+ """Evaluates the ceiling of an interval"""
310
+ np = import_module('numpy')
311
+ if isinstance(x, (int, float)):
312
+ return interval(np.ceil(x))
313
+ elif isinstance(x, interval):
314
+ if x.is_valid is False:
315
+ return interval(-np.inf, np.inf, is_valid=False)
316
+ else:
317
+ start = np.ceil(x.start)
318
+ end = np.ceil(x.end)
319
+ #Continuous over the interval
320
+ if start == end:
321
+ return interval(start, end, is_valid=x.is_valid)
322
+ else:
323
+ #Not continuous over the interval
324
+ return interval(start, end, is_valid=None)
325
+ else:
326
+ return NotImplementedError
327
+
328
+
329
+ def floor(x):
330
+ """Evaluates the floor of an interval"""
331
+ np = import_module('numpy')
332
+ if isinstance(x, (int, float)):
333
+ return interval(np.floor(x))
334
+ elif isinstance(x, interval):
335
+ if x.is_valid is False:
336
+ return interval(-np.inf, np.inf, is_valid=False)
337
+ else:
338
+ start = np.floor(x.start)
339
+ end = np.floor(x.end)
340
+ #continuous over the argument
341
+ if start == end:
342
+ return interval(start, end, is_valid=x.is_valid)
343
+ else:
344
+ #not continuous over the interval
345
+ return interval(start, end, is_valid=None)
346
+ else:
347
+ return NotImplementedError
348
+
349
+
350
+ def acosh(x):
351
+ """Evaluates the inverse hyperbolic cosine of an interval"""
352
+ np = import_module('numpy')
353
+ if isinstance(x, (int, float)):
354
+ #Outside the domain
355
+ if x < 1:
356
+ return interval(-np.inf, np.inf, is_valid=False)
357
+ else:
358
+ return interval(np.arccosh(x))
359
+ elif isinstance(x, interval):
360
+ #Outside the domain
361
+ if x.end < 1:
362
+ return interval(-np.inf, np.inf, is_valid=False)
363
+ #Partly outside the domain
364
+ elif x.start < 1:
365
+ return interval(-np.inf, np.inf, is_valid=None)
366
+ else:
367
+ start = np.arccosh(x.start)
368
+ end = np.arccosh(x.end)
369
+ return interval(start, end, is_valid=x.is_valid)
370
+ else:
371
+ return NotImplementedError
372
+
373
+
374
+ #Monotonic
375
+ def asinh(x):
376
+ """Evaluates the inverse hyperbolic sine of an interval"""
377
+ np = import_module('numpy')
378
+ if isinstance(x, (int, float)):
379
+ return interval(np.arcsinh(x))
380
+ elif isinstance(x, interval):
381
+ start = np.arcsinh(x.start)
382
+ end = np.arcsinh(x.end)
383
+ return interval(start, end, is_valid=x.is_valid)
384
+ else:
385
+ return NotImplementedError
386
+
387
+
388
+ def atanh(x):
389
+ """Evaluates the inverse hyperbolic tangent of an interval"""
390
+ np = import_module('numpy')
391
+ if isinstance(x, (int, float)):
392
+ #Outside the domain
393
+ if abs(x) >= 1:
394
+ return interval(-np.inf, np.inf, is_valid=False)
395
+ else:
396
+ return interval(np.arctanh(x))
397
+ elif isinstance(x, interval):
398
+ #outside the domain
399
+ if x.is_valid is False or x.start >= 1 or x.end <= -1:
400
+ return interval(-np.inf, np.inf, is_valid=False)
401
+ #partly outside the domain
402
+ elif x.start <= -1 or x.end >= 1:
403
+ return interval(-np.inf, np.inf, is_valid=None)
404
+ else:
405
+ start = np.arctanh(x.start)
406
+ end = np.arctanh(x.end)
407
+ return interval(start, end, is_valid=x.is_valid)
408
+ else:
409
+ return NotImplementedError
410
+
411
+
412
+ #Three valued logic for interval plotting.
413
+
414
+ def And(*args):
415
+ """Defines the three valued ``And`` behaviour for a 2-tuple of
416
+ three valued logic values"""
417
+ def reduce_and(cmp_intervala, cmp_intervalb):
418
+ if cmp_intervala[0] is False or cmp_intervalb[0] is False:
419
+ first = False
420
+ elif cmp_intervala[0] is None or cmp_intervalb[0] is None:
421
+ first = None
422
+ else:
423
+ first = True
424
+ if cmp_intervala[1] is False or cmp_intervalb[1] is False:
425
+ second = False
426
+ elif cmp_intervala[1] is None or cmp_intervalb[1] is None:
427
+ second = None
428
+ else:
429
+ second = True
430
+ return (first, second)
431
+ return reduce(reduce_and, args)
432
+
433
+
434
+ def Or(*args):
435
+ """Defines the three valued ``Or`` behaviour for a 2-tuple of
436
+ three valued logic values"""
437
+ def reduce_or(cmp_intervala, cmp_intervalb):
438
+ if cmp_intervala[0] is True or cmp_intervalb[0] is True:
439
+ first = True
440
+ elif cmp_intervala[0] is None or cmp_intervalb[0] is None:
441
+ first = None
442
+ else:
443
+ first = False
444
+
445
+ if cmp_intervala[1] is True or cmp_intervalb[1] is True:
446
+ second = True
447
+ elif cmp_intervala[1] is None or cmp_intervalb[1] is None:
448
+ second = None
449
+ else:
450
+ second = False
451
+ return (first, second)
452
+ return reduce(reduce_or, args)
lib/python3.12/site-packages/sympy/plotting/intervalmath/tests/__init__.py ADDED
File without changes
lib/python3.12/site-packages/sympy/plotting/intervalmath/tests/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (212 Bytes). View file
 
lib/python3.12/site-packages/sympy/plotting/intervalmath/tests/__pycache__/test_interval_functions.cpython-312.pyc ADDED
Binary file (23.8 kB). View file
 
lib/python3.12/site-packages/sympy/plotting/intervalmath/tests/__pycache__/test_interval_membership.cpython-312.pyc ADDED
Binary file (6.44 kB). View file
 
lib/python3.12/site-packages/sympy/plotting/intervalmath/tests/__pycache__/test_intervalmath.cpython-312.pyc ADDED
Binary file (14 kB). View file
 
lib/python3.12/site-packages/sympy/plotting/intervalmath/tests/test_interval_functions.py ADDED
@@ -0,0 +1,415 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.external import import_module
2
+ from sympy.plotting.intervalmath import (
3
+ Abs, acos, acosh, And, asin, asinh, atan, atanh, ceil, cos, cosh,
4
+ exp, floor, imax, imin, interval, log, log10, Or, sin, sinh, sqrt,
5
+ tan, tanh,
6
+ )
7
+
8
+ np = import_module('numpy')
9
+ if not np:
10
+ disabled = True
11
+
12
+
13
+ #requires Numpy. Hence included in interval_functions
14
+
15
+
16
+ def test_interval_pow():
17
+ a = 2**interval(1, 2) == interval(2, 4)
18
+ assert a == (True, True)
19
+ a = interval(1, 2)**interval(1, 2) == interval(1, 4)
20
+ assert a == (True, True)
21
+ a = interval(-1, 1)**interval(0.5, 2)
22
+ assert a.is_valid is None
23
+ a = interval(-2, -1) ** interval(1, 2)
24
+ assert a.is_valid is False
25
+ a = interval(-2, -1) ** (1.0 / 2)
26
+ assert a.is_valid is False
27
+ a = interval(-1, 1)**(1.0 / 2)
28
+ assert a.is_valid is None
29
+ a = interval(-1, 1)**(1.0 / 3) == interval(-1, 1)
30
+ assert a == (True, True)
31
+ a = interval(-1, 1)**2 == interval(0, 1)
32
+ assert a == (True, True)
33
+ a = interval(-1, 1) ** (1.0 / 29) == interval(-1, 1)
34
+ assert a == (True, True)
35
+ a = -2**interval(1, 1) == interval(-2, -2)
36
+ assert a == (True, True)
37
+
38
+ a = interval(1, 2, is_valid=False)**2
39
+ assert a.is_valid is False
40
+
41
+ a = (-3)**interval(1, 2)
42
+ assert a.is_valid is False
43
+ a = (-4)**interval(0.5, 0.5)
44
+ assert a.is_valid is False
45
+ assert ((-3)**interval(1, 1) == interval(-3, -3)) == (True, True)
46
+
47
+ a = interval(8, 64)**(2.0 / 3)
48
+ assert abs(a.start - 4) < 1e-10 # eps
49
+ assert abs(a.end - 16) < 1e-10
50
+ a = interval(-8, 64)**(2.0 / 3)
51
+ assert abs(a.start - 4) < 1e-10 # eps
52
+ assert abs(a.end - 16) < 1e-10
53
+
54
+
55
+ def test_exp():
56
+ a = exp(interval(-np.inf, 0))
57
+ assert a.start == np.exp(-np.inf)
58
+ assert a.end == np.exp(0)
59
+ a = exp(interval(1, 2))
60
+ assert a.start == np.exp(1)
61
+ assert a.end == np.exp(2)
62
+ a = exp(1)
63
+ assert a.start == np.exp(1)
64
+ assert a.end == np.exp(1)
65
+
66
+
67
+ def test_log():
68
+ a = log(interval(1, 2))
69
+ assert a.start == 0
70
+ assert a.end == np.log(2)
71
+ a = log(interval(-1, 1))
72
+ assert a.is_valid is None
73
+ a = log(interval(-3, -1))
74
+ assert a.is_valid is False
75
+ a = log(-3)
76
+ assert a.is_valid is False
77
+ a = log(2)
78
+ assert a.start == np.log(2)
79
+ assert a.end == np.log(2)
80
+
81
+
82
+ def test_log10():
83
+ a = log10(interval(1, 2))
84
+ assert a.start == 0
85
+ assert a.end == np.log10(2)
86
+ a = log10(interval(-1, 1))
87
+ assert a.is_valid is None
88
+ a = log10(interval(-3, -1))
89
+ assert a.is_valid is False
90
+ a = log10(-3)
91
+ assert a.is_valid is False
92
+ a = log10(2)
93
+ assert a.start == np.log10(2)
94
+ assert a.end == np.log10(2)
95
+
96
+
97
+ def test_atan():
98
+ a = atan(interval(0, 1))
99
+ assert a.start == np.arctan(0)
100
+ assert a.end == np.arctan(1)
101
+ a = atan(1)
102
+ assert a.start == np.arctan(1)
103
+ assert a.end == np.arctan(1)
104
+
105
+
106
+ def test_sin():
107
+ a = sin(interval(0, np.pi / 4))
108
+ assert a.start == np.sin(0)
109
+ assert a.end == np.sin(np.pi / 4)
110
+
111
+ a = sin(interval(-np.pi / 4, np.pi / 4))
112
+ assert a.start == np.sin(-np.pi / 4)
113
+ assert a.end == np.sin(np.pi / 4)
114
+
115
+ a = sin(interval(np.pi / 4, 3 * np.pi / 4))
116
+ assert a.start == np.sin(np.pi / 4)
117
+ assert a.end == 1
118
+
119
+ a = sin(interval(7 * np.pi / 6, 7 * np.pi / 4))
120
+ assert a.start == -1
121
+ assert a.end == np.sin(7 * np.pi / 6)
122
+
123
+ a = sin(interval(0, 3 * np.pi))
124
+ assert a.start == -1
125
+ assert a.end == 1
126
+
127
+ a = sin(interval(np.pi / 3, 7 * np.pi / 4))
128
+ assert a.start == -1
129
+ assert a.end == 1
130
+
131
+ a = sin(np.pi / 4)
132
+ assert a.start == np.sin(np.pi / 4)
133
+ assert a.end == np.sin(np.pi / 4)
134
+
135
+ a = sin(interval(1, 2, is_valid=False))
136
+ assert a.is_valid is False
137
+
138
+
139
+ def test_cos():
140
+ a = cos(interval(0, np.pi / 4))
141
+ assert a.start == np.cos(np.pi / 4)
142
+ assert a.end == 1
143
+
144
+ a = cos(interval(-np.pi / 4, np.pi / 4))
145
+ assert a.start == np.cos(-np.pi / 4)
146
+ assert a.end == 1
147
+
148
+ a = cos(interval(np.pi / 4, 3 * np.pi / 4))
149
+ assert a.start == np.cos(3 * np.pi / 4)
150
+ assert a.end == np.cos(np.pi / 4)
151
+
152
+ a = cos(interval(3 * np.pi / 4, 5 * np.pi / 4))
153
+ assert a.start == -1
154
+ assert a.end == np.cos(3 * np.pi / 4)
155
+
156
+ a = cos(interval(0, 3 * np.pi))
157
+ assert a.start == -1
158
+ assert a.end == 1
159
+
160
+ a = cos(interval(- np.pi / 3, 5 * np.pi / 4))
161
+ assert a.start == -1
162
+ assert a.end == 1
163
+
164
+ a = cos(interval(1, 2, is_valid=False))
165
+ assert a.is_valid is False
166
+
167
+
168
+ def test_tan():
169
+ a = tan(interval(0, np.pi / 4))
170
+ assert a.start == 0
171
+ # must match lib_interval definition of tan:
172
+ assert a.end == np.sin(np.pi / 4)/np.cos(np.pi / 4)
173
+
174
+ a = tan(interval(np.pi / 4, 3 * np.pi / 4))
175
+ #discontinuity
176
+ assert a.is_valid is None
177
+
178
+
179
+ def test_sqrt():
180
+ a = sqrt(interval(1, 4))
181
+ assert a.start == 1
182
+ assert a.end == 2
183
+
184
+ a = sqrt(interval(0.01, 1))
185
+ assert a.start == np.sqrt(0.01)
186
+ assert a.end == 1
187
+
188
+ a = sqrt(interval(-1, 1))
189
+ assert a.is_valid is None
190
+
191
+ a = sqrt(interval(-3, -1))
192
+ assert a.is_valid is False
193
+
194
+ a = sqrt(4)
195
+ assert (a == interval(2, 2)) == (True, True)
196
+
197
+ a = sqrt(-3)
198
+ assert a.is_valid is False
199
+
200
+
201
+ def test_imin():
202
+ a = imin(interval(1, 3), interval(2, 5), interval(-1, 3))
203
+ assert a.start == -1
204
+ assert a.end == 3
205
+
206
+ a = imin(-2, interval(1, 4))
207
+ assert a.start == -2
208
+ assert a.end == -2
209
+
210
+ a = imin(5, interval(3, 4), interval(-2, 2, is_valid=False))
211
+ assert a.start == 3
212
+ assert a.end == 4
213
+
214
+
215
+ def test_imax():
216
+ a = imax(interval(-2, 2), interval(2, 7), interval(-3, 9))
217
+ assert a.start == 2
218
+ assert a.end == 9
219
+
220
+ a = imax(8, interval(1, 4))
221
+ assert a.start == 8
222
+ assert a.end == 8
223
+
224
+ a = imax(interval(1, 2), interval(3, 4), interval(-2, 2, is_valid=False))
225
+ assert a.start == 3
226
+ assert a.end == 4
227
+
228
+
229
+ def test_sinh():
230
+ a = sinh(interval(-1, 1))
231
+ assert a.start == np.sinh(-1)
232
+ assert a.end == np.sinh(1)
233
+
234
+ a = sinh(1)
235
+ assert a.start == np.sinh(1)
236
+ assert a.end == np.sinh(1)
237
+
238
+
239
+ def test_cosh():
240
+ a = cosh(interval(1, 2))
241
+ assert a.start == np.cosh(1)
242
+ assert a.end == np.cosh(2)
243
+ a = cosh(interval(-2, -1))
244
+ assert a.start == np.cosh(-1)
245
+ assert a.end == np.cosh(-2)
246
+
247
+ a = cosh(interval(-2, 1))
248
+ assert a.start == 1
249
+ assert a.end == np.cosh(-2)
250
+
251
+ a = cosh(1)
252
+ assert a.start == np.cosh(1)
253
+ assert a.end == np.cosh(1)
254
+
255
+
256
+ def test_tanh():
257
+ a = tanh(interval(-3, 3))
258
+ assert a.start == np.tanh(-3)
259
+ assert a.end == np.tanh(3)
260
+
261
+ a = tanh(3)
262
+ assert a.start == np.tanh(3)
263
+ assert a.end == np.tanh(3)
264
+
265
+
266
+ def test_asin():
267
+ a = asin(interval(-0.5, 0.5))
268
+ assert a.start == np.arcsin(-0.5)
269
+ assert a.end == np.arcsin(0.5)
270
+
271
+ a = asin(interval(-1.5, 1.5))
272
+ assert a.is_valid is None
273
+ a = asin(interval(-2, -1.5))
274
+ assert a.is_valid is False
275
+
276
+ a = asin(interval(0, 2))
277
+ assert a.is_valid is None
278
+
279
+ a = asin(interval(2, 5))
280
+ assert a.is_valid is False
281
+
282
+ a = asin(0.5)
283
+ assert a.start == np.arcsin(0.5)
284
+ assert a.end == np.arcsin(0.5)
285
+
286
+ a = asin(1.5)
287
+ assert a.is_valid is False
288
+
289
+
290
+ def test_acos():
291
+ a = acos(interval(-0.5, 0.5))
292
+ assert a.start == np.arccos(0.5)
293
+ assert a.end == np.arccos(-0.5)
294
+
295
+ a = acos(interval(-1.5, 1.5))
296
+ assert a.is_valid is None
297
+ a = acos(interval(-2, -1.5))
298
+ assert a.is_valid is False
299
+
300
+ a = acos(interval(0, 2))
301
+ assert a.is_valid is None
302
+
303
+ a = acos(interval(2, 5))
304
+ assert a.is_valid is False
305
+
306
+ a = acos(0.5)
307
+ assert a.start == np.arccos(0.5)
308
+ assert a.end == np.arccos(0.5)
309
+
310
+ a = acos(1.5)
311
+ assert a.is_valid is False
312
+
313
+
314
+ def test_ceil():
315
+ a = ceil(interval(0.2, 0.5))
316
+ assert a.start == 1
317
+ assert a.end == 1
318
+
319
+ a = ceil(interval(0.5, 1.5))
320
+ assert a.start == 1
321
+ assert a.end == 2
322
+ assert a.is_valid is None
323
+
324
+ a = ceil(interval(-5, 5))
325
+ assert a.is_valid is None
326
+
327
+ a = ceil(5.4)
328
+ assert a.start == 6
329
+ assert a.end == 6
330
+
331
+
332
+ def test_floor():
333
+ a = floor(interval(0.2, 0.5))
334
+ assert a.start == 0
335
+ assert a.end == 0
336
+
337
+ a = floor(interval(0.5, 1.5))
338
+ assert a.start == 0
339
+ assert a.end == 1
340
+ assert a.is_valid is None
341
+
342
+ a = floor(interval(-5, 5))
343
+ assert a.is_valid is None
344
+
345
+ a = floor(5.4)
346
+ assert a.start == 5
347
+ assert a.end == 5
348
+
349
+
350
+ def test_asinh():
351
+ a = asinh(interval(1, 2))
352
+ assert a.start == np.arcsinh(1)
353
+ assert a.end == np.arcsinh(2)
354
+
355
+ a = asinh(0.5)
356
+ assert a.start == np.arcsinh(0.5)
357
+ assert a.end == np.arcsinh(0.5)
358
+
359
+
360
+ def test_acosh():
361
+ a = acosh(interval(3, 5))
362
+ assert a.start == np.arccosh(3)
363
+ assert a.end == np.arccosh(5)
364
+
365
+ a = acosh(interval(0, 3))
366
+ assert a.is_valid is None
367
+ a = acosh(interval(-3, 0.5))
368
+ assert a.is_valid is False
369
+
370
+ a = acosh(0.5)
371
+ assert a.is_valid is False
372
+
373
+ a = acosh(2)
374
+ assert a.start == np.arccosh(2)
375
+ assert a.end == np.arccosh(2)
376
+
377
+
378
+ def test_atanh():
379
+ a = atanh(interval(-0.5, 0.5))
380
+ assert a.start == np.arctanh(-0.5)
381
+ assert a.end == np.arctanh(0.5)
382
+
383
+ a = atanh(interval(0, 3))
384
+ assert a.is_valid is None
385
+
386
+ a = atanh(interval(-3, -2))
387
+ assert a.is_valid is False
388
+
389
+ a = atanh(0.5)
390
+ assert a.start == np.arctanh(0.5)
391
+ assert a.end == np.arctanh(0.5)
392
+
393
+ a = atanh(1.5)
394
+ assert a.is_valid is False
395
+
396
+
397
+ def test_Abs():
398
+ assert (Abs(interval(-0.5, 0.5)) == interval(0, 0.5)) == (True, True)
399
+ assert (Abs(interval(-3, -2)) == interval(2, 3)) == (True, True)
400
+ assert (Abs(-3) == interval(3, 3)) == (True, True)
401
+
402
+
403
+ def test_And():
404
+ args = [(True, True), (True, False), (True, None)]
405
+ assert And(*args) == (True, False)
406
+
407
+ args = [(False, True), (None, None), (True, True)]
408
+ assert And(*args) == (False, None)
409
+
410
+
411
+ def test_Or():
412
+ args = [(True, True), (True, False), (False, None)]
413
+ assert Or(*args) == (True, True)
414
+ args = [(None, None), (False, None), (False, False)]
415
+ assert Or(*args) == (None, None)
lib/python3.12/site-packages/sympy/plotting/intervalmath/tests/test_interval_membership.py ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.symbol import Symbol
2
+ from sympy.plotting.intervalmath import interval
3
+ from sympy.plotting.intervalmath.interval_membership import intervalMembership
4
+ from sympy.plotting.experimental_lambdify import experimental_lambdify
5
+ from sympy.testing.pytest import raises
6
+
7
+
8
+ def test_creation():
9
+ assert intervalMembership(True, True)
10
+ raises(TypeError, lambda: intervalMembership(True))
11
+ raises(TypeError, lambda: intervalMembership(True, True, True))
12
+
13
+
14
+ def test_getitem():
15
+ a = intervalMembership(True, False)
16
+ assert a[0] is True
17
+ assert a[1] is False
18
+ raises(IndexError, lambda: a[2])
19
+
20
+
21
+ def test_str():
22
+ a = intervalMembership(True, False)
23
+ assert str(a) == 'intervalMembership(True, False)'
24
+ assert repr(a) == 'intervalMembership(True, False)'
25
+
26
+
27
+ def test_equivalence():
28
+ a = intervalMembership(True, True)
29
+ b = intervalMembership(True, False)
30
+ assert (a == b) is False
31
+ assert (a != b) is True
32
+
33
+ a = intervalMembership(True, False)
34
+ b = intervalMembership(True, False)
35
+ assert (a == b) is True
36
+ assert (a != b) is False
37
+
38
+
39
+ def test_not():
40
+ x = Symbol('x')
41
+
42
+ r1 = x > -1
43
+ r2 = x <= -1
44
+
45
+ i = interval
46
+
47
+ f1 = experimental_lambdify((x,), r1)
48
+ f2 = experimental_lambdify((x,), r2)
49
+
50
+ tt = i(-0.1, 0.1, is_valid=True)
51
+ tn = i(-0.1, 0.1, is_valid=None)
52
+ tf = i(-0.1, 0.1, is_valid=False)
53
+
54
+ assert f1(tt) == ~f2(tt)
55
+ assert f1(tn) == ~f2(tn)
56
+ assert f1(tf) == ~f2(tf)
57
+
58
+ nt = i(0.9, 1.1, is_valid=True)
59
+ nn = i(0.9, 1.1, is_valid=None)
60
+ nf = i(0.9, 1.1, is_valid=False)
61
+
62
+ assert f1(nt) == ~f2(nt)
63
+ assert f1(nn) == ~f2(nn)
64
+ assert f1(nf) == ~f2(nf)
65
+
66
+ ft = i(1.9, 2.1, is_valid=True)
67
+ fn = i(1.9, 2.1, is_valid=None)
68
+ ff = i(1.9, 2.1, is_valid=False)
69
+
70
+ assert f1(ft) == ~f2(ft)
71
+ assert f1(fn) == ~f2(fn)
72
+ assert f1(ff) == ~f2(ff)
73
+
74
+
75
+ def test_boolean():
76
+ # There can be 9*9 test cases in full mapping of the cartesian product.
77
+ # But we only consider 3*3 cases for simplicity.
78
+ s = [
79
+ intervalMembership(False, False),
80
+ intervalMembership(None, None),
81
+ intervalMembership(True, True)
82
+ ]
83
+
84
+ # Reduced tests for 'And'
85
+ a1 = [
86
+ intervalMembership(False, False),
87
+ intervalMembership(False, False),
88
+ intervalMembership(False, False),
89
+ intervalMembership(False, False),
90
+ intervalMembership(None, None),
91
+ intervalMembership(None, None),
92
+ intervalMembership(False, False),
93
+ intervalMembership(None, None),
94
+ intervalMembership(True, True)
95
+ ]
96
+ a1_iter = iter(a1)
97
+ for i in range(len(s)):
98
+ for j in range(len(s)):
99
+ assert s[i] & s[j] == next(a1_iter)
100
+
101
+ # Reduced tests for 'Or'
102
+ a1 = [
103
+ intervalMembership(False, False),
104
+ intervalMembership(None, False),
105
+ intervalMembership(True, False),
106
+ intervalMembership(None, False),
107
+ intervalMembership(None, None),
108
+ intervalMembership(True, None),
109
+ intervalMembership(True, False),
110
+ intervalMembership(True, None),
111
+ intervalMembership(True, True)
112
+ ]
113
+ a1_iter = iter(a1)
114
+ for i in range(len(s)):
115
+ for j in range(len(s)):
116
+ assert s[i] | s[j] == next(a1_iter)
117
+
118
+ # Reduced tests for 'Xor'
119
+ a1 = [
120
+ intervalMembership(False, False),
121
+ intervalMembership(None, False),
122
+ intervalMembership(True, False),
123
+ intervalMembership(None, False),
124
+ intervalMembership(None, None),
125
+ intervalMembership(None, None),
126
+ intervalMembership(True, False),
127
+ intervalMembership(None, None),
128
+ intervalMembership(False, True)
129
+ ]
130
+ a1_iter = iter(a1)
131
+ for i in range(len(s)):
132
+ for j in range(len(s)):
133
+ assert s[i] ^ s[j] == next(a1_iter)
134
+
135
+ # Reduced tests for 'Not'
136
+ a1 = [
137
+ intervalMembership(True, False),
138
+ intervalMembership(None, None),
139
+ intervalMembership(False, True)
140
+ ]
141
+ a1_iter = iter(a1)
142
+ for i in range(len(s)):
143
+ assert ~s[i] == next(a1_iter)
144
+
145
+
146
+ def test_boolean_errors():
147
+ a = intervalMembership(True, True)
148
+ raises(ValueError, lambda: a & 1)
149
+ raises(ValueError, lambda: a | 1)
150
+ raises(ValueError, lambda: a ^ 1)
lib/python3.12/site-packages/sympy/plotting/intervalmath/tests/test_intervalmath.py ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.plotting.intervalmath import interval
2
+ from sympy.testing.pytest import raises
3
+
4
+
5
+ def test_interval():
6
+ assert (interval(1, 1) == interval(1, 1, is_valid=True)) == (True, True)
7
+ assert (interval(1, 1) == interval(1, 1, is_valid=False)) == (True, False)
8
+ assert (interval(1, 1) == interval(1, 1, is_valid=None)) == (True, None)
9
+ assert (interval(1, 1.5) == interval(1, 2)) == (None, True)
10
+ assert (interval(0, 1) == interval(2, 3)) == (False, True)
11
+ assert (interval(0, 1) == interval(1, 2)) == (None, True)
12
+ assert (interval(1, 2) != interval(1, 2)) == (False, True)
13
+ assert (interval(1, 3) != interval(2, 3)) == (None, True)
14
+ assert (interval(1, 3) != interval(-5, -3)) == (True, True)
15
+ assert (
16
+ interval(1, 3, is_valid=False) != interval(-5, -3)) == (True, False)
17
+ assert (interval(1, 3, is_valid=None) != interval(-5, 3)) == (None, None)
18
+ assert (interval(4, 4) != 4) == (False, True)
19
+ assert (interval(1, 1) == 1) == (True, True)
20
+ assert (interval(1, 3, is_valid=False) == interval(1, 3)) == (True, False)
21
+ assert (interval(1, 3, is_valid=None) == interval(1, 3)) == (True, None)
22
+ inter = interval(-5, 5)
23
+ assert (interval(inter) == interval(-5, 5)) == (True, True)
24
+ assert inter.width == 10
25
+ assert 0 in inter
26
+ assert -5 in inter
27
+ assert 5 in inter
28
+ assert interval(0, 3) in inter
29
+ assert interval(-6, 2) not in inter
30
+ assert -5.05 not in inter
31
+ assert 5.3 not in inter
32
+ interb = interval(-float('inf'), float('inf'))
33
+ assert 0 in inter
34
+ assert inter in interb
35
+ assert interval(0, float('inf')) in interb
36
+ assert interval(-float('inf'), 5) in interb
37
+ assert interval(-1e50, 1e50) in interb
38
+ assert (
39
+ -interval(-1, -2, is_valid=False) == interval(1, 2)) == (True, False)
40
+ raises(ValueError, lambda: interval(1, 2, 3))
41
+
42
+
43
+ def test_interval_add():
44
+ assert (interval(1, 2) + interval(2, 3) == interval(3, 5)) == (True, True)
45
+ assert (1 + interval(1, 2) == interval(2, 3)) == (True, True)
46
+ assert (interval(1, 2) + 1 == interval(2, 3)) == (True, True)
47
+ compare = (1 + interval(0, float('inf')) == interval(1, float('inf')))
48
+ assert compare == (True, True)
49
+ a = 1 + interval(2, 5, is_valid=False)
50
+ assert a.is_valid is False
51
+ a = 1 + interval(2, 5, is_valid=None)
52
+ assert a.is_valid is None
53
+ a = interval(2, 5, is_valid=False) + interval(3, 5, is_valid=None)
54
+ assert a.is_valid is False
55
+ a = interval(3, 5) + interval(-1, 1, is_valid=None)
56
+ assert a.is_valid is None
57
+ a = interval(2, 5, is_valid=False) + 1
58
+ assert a.is_valid is False
59
+
60
+
61
+ def test_interval_sub():
62
+ assert (interval(1, 2) - interval(1, 5) == interval(-4, 1)) == (True, True)
63
+ assert (interval(1, 2) - 1 == interval(0, 1)) == (True, True)
64
+ assert (1 - interval(1, 2) == interval(-1, 0)) == (True, True)
65
+ a = 1 - interval(1, 2, is_valid=False)
66
+ assert a.is_valid is False
67
+ a = interval(1, 4, is_valid=None) - 1
68
+ assert a.is_valid is None
69
+ a = interval(1, 3, is_valid=False) - interval(1, 3)
70
+ assert a.is_valid is False
71
+ a = interval(1, 3, is_valid=None) - interval(1, 3)
72
+ assert a.is_valid is None
73
+
74
+
75
+ def test_interval_inequality():
76
+ assert (interval(1, 2) < interval(3, 4)) == (True, True)
77
+ assert (interval(1, 2) < interval(2, 4)) == (None, True)
78
+ assert (interval(1, 2) < interval(-2, 0)) == (False, True)
79
+ assert (interval(1, 2) <= interval(2, 4)) == (True, True)
80
+ assert (interval(1, 2) <= interval(1.5, 6)) == (None, True)
81
+ assert (interval(2, 3) <= interval(1, 2)) == (None, True)
82
+ assert (interval(2, 3) <= interval(1, 1.5)) == (False, True)
83
+ assert (
84
+ interval(1, 2, is_valid=False) <= interval(-2, 0)) == (False, False)
85
+ assert (interval(1, 2, is_valid=None) <= interval(-2, 0)) == (False, None)
86
+ assert (interval(1, 2) <= 1.5) == (None, True)
87
+ assert (interval(1, 2) <= 3) == (True, True)
88
+ assert (interval(1, 2) <= 0) == (False, True)
89
+ assert (interval(5, 8) > interval(2, 3)) == (True, True)
90
+ assert (interval(2, 5) > interval(1, 3)) == (None, True)
91
+ assert (interval(2, 3) > interval(3.1, 5)) == (False, True)
92
+
93
+ assert (interval(-1, 1) == 0) == (None, True)
94
+ assert (interval(-1, 1) == 2) == (False, True)
95
+ assert (interval(-1, 1) != 0) == (None, True)
96
+ assert (interval(-1, 1) != 2) == (True, True)
97
+
98
+ assert (interval(3, 5) > 2) == (True, True)
99
+ assert (interval(3, 5) < 2) == (False, True)
100
+ assert (interval(1, 5) < 2) == (None, True)
101
+ assert (interval(1, 5) > 2) == (None, True)
102
+ assert (interval(0, 1) > 2) == (False, True)
103
+ assert (interval(1, 2) >= interval(0, 1)) == (True, True)
104
+ assert (interval(1, 2) >= interval(0, 1.5)) == (None, True)
105
+ assert (interval(1, 2) >= interval(3, 4)) == (False, True)
106
+ assert (interval(1, 2) >= 0) == (True, True)
107
+ assert (interval(1, 2) >= 1.2) == (None, True)
108
+ assert (interval(1, 2) >= 3) == (False, True)
109
+ assert (2 > interval(0, 1)) == (True, True)
110
+ a = interval(-1, 1, is_valid=False) < interval(2, 5, is_valid=None)
111
+ assert a == (True, False)
112
+ a = interval(-1, 1, is_valid=None) < interval(2, 5, is_valid=False)
113
+ assert a == (True, False)
114
+ a = interval(-1, 1, is_valid=None) < interval(2, 5, is_valid=None)
115
+ assert a == (True, None)
116
+ a = interval(-1, 1, is_valid=False) > interval(-5, -2, is_valid=None)
117
+ assert a == (True, False)
118
+ a = interval(-1, 1, is_valid=None) > interval(-5, -2, is_valid=False)
119
+ assert a == (True, False)
120
+ a = interval(-1, 1, is_valid=None) > interval(-5, -2, is_valid=None)
121
+ assert a == (True, None)
122
+
123
+
124
+ def test_interval_mul():
125
+ assert (
126
+ interval(1, 5) * interval(2, 10) == interval(2, 50)) == (True, True)
127
+ a = interval(-1, 1) * interval(2, 10) == interval(-10, 10)
128
+ assert a == (True, True)
129
+
130
+ a = interval(-1, 1) * interval(-5, 3) == interval(-5, 5)
131
+ assert a == (True, True)
132
+
133
+ assert (interval(1, 3) * 2 == interval(2, 6)) == (True, True)
134
+ assert (3 * interval(-1, 2) == interval(-3, 6)) == (True, True)
135
+
136
+ a = 3 * interval(1, 2, is_valid=False)
137
+ assert a.is_valid is False
138
+
139
+ a = 3 * interval(1, 2, is_valid=None)
140
+ assert a.is_valid is None
141
+
142
+ a = interval(1, 5, is_valid=False) * interval(1, 2, is_valid=None)
143
+ assert a.is_valid is False
144
+
145
+
146
+ def test_interval_div():
147
+ div = interval(1, 2, is_valid=False) / 3
148
+ assert div == interval(-float('inf'), float('inf'), is_valid=False)
149
+
150
+ div = interval(1, 2, is_valid=None) / 3
151
+ assert div == interval(-float('inf'), float('inf'), is_valid=None)
152
+
153
+ div = 3 / interval(1, 2, is_valid=None)
154
+ assert div == interval(-float('inf'), float('inf'), is_valid=None)
155
+ a = interval(1, 2) / 0
156
+ assert a.is_valid is False
157
+ a = interval(0.5, 1) / interval(-1, 0)
158
+ assert a.is_valid is None
159
+ a = interval(0, 1) / interval(0, 1)
160
+ assert a.is_valid is None
161
+
162
+ a = interval(-1, 1) / interval(-1, 1)
163
+ assert a.is_valid is None
164
+
165
+ a = interval(-1, 2) / interval(0.5, 1) == interval(-2.0, 4.0)
166
+ assert a == (True, True)
167
+ a = interval(0, 1) / interval(0.5, 1) == interval(0.0, 2.0)
168
+ assert a == (True, True)
169
+ a = interval(-1, 0) / interval(0.5, 1) == interval(-2.0, 0.0)
170
+ assert a == (True, True)
171
+ a = interval(-0.5, -0.25) / interval(0.5, 1) == interval(-1.0, -0.25)
172
+ assert a == (True, True)
173
+ a = interval(0.5, 1) / interval(0.5, 1) == interval(0.5, 2.0)
174
+ assert a == (True, True)
175
+ a = interval(0.5, 4) / interval(0.5, 1) == interval(0.5, 8.0)
176
+ assert a == (True, True)
177
+ a = interval(-1, -0.5) / interval(0.5, 1) == interval(-2.0, -0.5)
178
+ assert a == (True, True)
179
+ a = interval(-4, -0.5) / interval(0.5, 1) == interval(-8.0, -0.5)
180
+ assert a == (True, True)
181
+ a = interval(-1, 2) / interval(-2, -0.5) == interval(-4.0, 2.0)
182
+ assert a == (True, True)
183
+ a = interval(0, 1) / interval(-2, -0.5) == interval(-2.0, 0.0)
184
+ assert a == (True, True)
185
+ a = interval(-1, 0) / interval(-2, -0.5) == interval(0.0, 2.0)
186
+ assert a == (True, True)
187
+ a = interval(-0.5, -0.25) / interval(-2, -0.5) == interval(0.125, 1.0)
188
+ assert a == (True, True)
189
+ a = interval(0.5, 1) / interval(-2, -0.5) == interval(-2.0, -0.25)
190
+ assert a == (True, True)
191
+ a = interval(0.5, 4) / interval(-2, -0.5) == interval(-8.0, -0.25)
192
+ assert a == (True, True)
193
+ a = interval(-1, -0.5) / interval(-2, -0.5) == interval(0.25, 2.0)
194
+ assert a == (True, True)
195
+ a = interval(-4, -0.5) / interval(-2, -0.5) == interval(0.25, 8.0)
196
+ assert a == (True, True)
197
+ a = interval(-5, 5, is_valid=False) / 2
198
+ assert a.is_valid is False
199
+
200
+ def test_hashable():
201
+ '''
202
+ test that interval objects are hashable.
203
+ this is required in order to be able to put them into the cache, which
204
+ appears to be necessary for plotting in py3k. For details, see:
205
+
206
+ https://github.com/sympy/sympy/pull/2101
207
+ https://github.com/sympy/sympy/issues/6533
208
+ '''
209
+ hash(interval(1, 1))
210
+ hash(interval(1, 1, is_valid=True))
211
+ hash(interval(-4, -0.5))
212
+ hash(interval(-2, -0.5))
213
+ hash(interval(0.25, 8.0))
lib/python3.12/site-packages/sympy/plotting/pygletplot/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (4.06 kB). View file
 
lib/python3.12/site-packages/sympy/plotting/pygletplot/__pycache__/managed_window.cpython-312.pyc ADDED
Binary file (4.63 kB). View file
 
lib/python3.12/site-packages/sympy/plotting/pygletplot/__pycache__/plot_curve.cpython-312.pyc ADDED
Binary file (5.04 kB). View file
 
lib/python3.12/site-packages/sympy/plotting/pygletplot/__pycache__/plot_mode.cpython-312.pyc ADDED
Binary file (14.7 kB). View file
 
lib/python3.12/site-packages/sympy/plotting/pygletplot/__pycache__/plot_mode_base.cpython-312.pyc ADDED
Binary file (17 kB). View file
 
lib/python3.12/site-packages/sympy/plotting/pygletplot/__pycache__/plot_object.cpython-312.pyc ADDED
Binary file (895 Bytes). View file
 
lib/python3.12/site-packages/sympy/plotting/pygletplot/__pycache__/plot_rotation.cpython-312.pyc ADDED
Binary file (3.28 kB). View file
 
lib/python3.12/site-packages/sympy/plotting/pygletplot/__pycache__/plot_surface.cpython-312.pyc ADDED
Binary file (6.07 kB). View file
 
lib/python3.12/site-packages/sympy/plotting/pygletplot/__pycache__/util.cpython-312.pyc ADDED
Binary file (9.73 kB). View file
 
lib/python3.12/site-packages/sympy/printing/codeprinter.py ADDED
@@ -0,0 +1,888 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+ from typing import Any
3
+
4
+ from functools import wraps
5
+
6
+ from sympy.core import Add, Mul, Pow, S, sympify, Float
7
+ from sympy.core.basic import Basic
8
+ from sympy.core.expr import UnevaluatedExpr
9
+ from sympy.core.function import Lambda
10
+ from sympy.core.mul import _keep_coeff
11
+ from sympy.core.sorting import default_sort_key
12
+ from sympy.core.symbol import Symbol
13
+ from sympy.functions.elementary.complexes import re
14
+ from sympy.printing.str import StrPrinter
15
+ from sympy.printing.precedence import precedence, PRECEDENCE
16
+
17
+
18
+ class requires:
19
+ """ Decorator for registering requirements on print methods. """
20
+ def __init__(self, **kwargs):
21
+ self._req = kwargs
22
+
23
+ def __call__(self, method):
24
+ def _method_wrapper(self_, *args, **kwargs):
25
+ for k, v in self._req.items():
26
+ getattr(self_, k).update(v)
27
+ return method(self_, *args, **kwargs)
28
+ return wraps(method)(_method_wrapper)
29
+
30
+
31
+ class AssignmentError(Exception):
32
+ """
33
+ Raised if an assignment variable for a loop is missing.
34
+ """
35
+ pass
36
+
37
+ class PrintMethodNotImplementedError(NotImplementedError):
38
+ """
39
+ Raised if a _print_* method is missing in the Printer.
40
+ """
41
+ pass
42
+
43
+ def _convert_python_lists(arg):
44
+ if isinstance(arg, list):
45
+ from sympy.codegen.abstract_nodes import List
46
+ return List(*(_convert_python_lists(e) for e in arg))
47
+ elif isinstance(arg, tuple):
48
+ return tuple(_convert_python_lists(e) for e in arg)
49
+ else:
50
+ return arg
51
+
52
+
53
+ class CodePrinter(StrPrinter):
54
+ """
55
+ The base class for code-printing subclasses.
56
+ """
57
+
58
+ _operators = {
59
+ 'and': '&&',
60
+ 'or': '||',
61
+ 'not': '!',
62
+ }
63
+
64
+ _default_settings: dict[str, Any] = {
65
+ 'order': None,
66
+ 'full_prec': 'auto',
67
+ 'error_on_reserved': False,
68
+ 'reserved_word_suffix': '_',
69
+ 'human': True,
70
+ 'inline': False,
71
+ 'allow_unknown_functions': False,
72
+ 'strict': None # True or False; None => True if human == True
73
+ }
74
+
75
+ # Functions which are "simple" to rewrite to other functions that
76
+ # may be supported
77
+ # function_to_rewrite : (function_to_rewrite_to, iterable_with_other_functions_required)
78
+ _rewriteable_functions = {
79
+ 'cot': ('tan', []),
80
+ 'csc': ('sin', []),
81
+ 'sec': ('cos', []),
82
+ 'acot': ('atan', []),
83
+ 'acsc': ('asin', []),
84
+ 'asec': ('acos', []),
85
+ 'coth': ('exp', []),
86
+ 'csch': ('exp', []),
87
+ 'sech': ('exp', []),
88
+ 'acoth': ('log', []),
89
+ 'acsch': ('log', []),
90
+ 'asech': ('log', []),
91
+ 'catalan': ('gamma', []),
92
+ 'fibonacci': ('sqrt', []),
93
+ 'lucas': ('sqrt', []),
94
+ 'beta': ('gamma', []),
95
+ 'sinc': ('sin', ['Piecewise']),
96
+ 'Mod': ('floor', []),
97
+ 'factorial': ('gamma', []),
98
+ 'factorial2': ('gamma', ['Piecewise']),
99
+ 'subfactorial': ('uppergamma', []),
100
+ 'RisingFactorial': ('gamma', ['Piecewise']),
101
+ 'FallingFactorial': ('gamma', ['Piecewise']),
102
+ 'binomial': ('gamma', []),
103
+ 'frac': ('floor', []),
104
+ 'Max': ('Piecewise', []),
105
+ 'Min': ('Piecewise', []),
106
+ 'Heaviside': ('Piecewise', []),
107
+ 'erf2': ('erf', []),
108
+ 'erfc': ('erf', []),
109
+ 'Li': ('li', []),
110
+ 'Ei': ('li', []),
111
+ 'dirichlet_eta': ('zeta', []),
112
+ 'riemann_xi': ('zeta', ['gamma']),
113
+ 'SingularityFunction': ('Piecewise', []),
114
+ }
115
+
116
+ def __init__(self, settings=None):
117
+ super().__init__(settings=settings)
118
+ if self._settings.get('strict', True) == None:
119
+ # for backwards compatibility, human=False need not to throw:
120
+ self._settings['strict'] = self._settings.get('human', True) == True
121
+ if not hasattr(self, 'reserved_words'):
122
+ self.reserved_words = set()
123
+
124
+ def _handle_UnevaluatedExpr(self, expr):
125
+ return expr.replace(re, lambda arg: arg if isinstance(
126
+ arg, UnevaluatedExpr) and arg.args[0].is_real else re(arg))
127
+
128
+ def doprint(self, expr, assign_to=None):
129
+ """
130
+ Print the expression as code.
131
+
132
+ Parameters
133
+ ----------
134
+ expr : Expression
135
+ The expression to be printed.
136
+
137
+ assign_to : Symbol, string, MatrixSymbol, list of strings or Symbols (optional)
138
+ If provided, the printed code will set the expression to a variable or multiple variables
139
+ with the name or names given in ``assign_to``.
140
+ """
141
+ from sympy.matrices.expressions.matexpr import MatrixSymbol
142
+ from sympy.codegen.ast import CodeBlock, Assignment
143
+
144
+ def _handle_assign_to(expr, assign_to):
145
+ if assign_to is None:
146
+ return sympify(expr)
147
+ if isinstance(assign_to, (list, tuple)):
148
+ if len(expr) != len(assign_to):
149
+ raise ValueError('Failed to assign an expression of length {} to {} variables'.format(len(expr), len(assign_to)))
150
+ return CodeBlock(*[_handle_assign_to(lhs, rhs) for lhs, rhs in zip(expr, assign_to)])
151
+ if isinstance(assign_to, str):
152
+ if expr.is_Matrix:
153
+ assign_to = MatrixSymbol(assign_to, *expr.shape)
154
+ else:
155
+ assign_to = Symbol(assign_to)
156
+ elif not isinstance(assign_to, Basic):
157
+ raise TypeError("{} cannot assign to object of type {}".format(
158
+ type(self).__name__, type(assign_to)))
159
+ return Assignment(assign_to, expr)
160
+
161
+ expr = _convert_python_lists(expr)
162
+ expr = _handle_assign_to(expr, assign_to)
163
+
164
+ # Remove re(...) nodes due to UnevaluatedExpr.is_real always is None:
165
+ expr = self._handle_UnevaluatedExpr(expr)
166
+
167
+ # keep a set of expressions that are not strictly translatable to Code
168
+ # and number constants that must be declared and initialized
169
+ self._not_supported = set()
170
+ self._number_symbols = set()
171
+
172
+ lines = self._print(expr).splitlines()
173
+
174
+ # format the output
175
+ if self._settings["human"]:
176
+ frontlines = []
177
+ if self._not_supported:
178
+ frontlines.append(self._get_comment(
179
+ "Not supported in {}:".format(self.language)))
180
+ for expr in sorted(self._not_supported, key=str):
181
+ frontlines.append(self._get_comment(type(expr).__name__))
182
+ for name, value in sorted(self._number_symbols, key=str):
183
+ frontlines.append(self._declare_number_const(name, value))
184
+ lines = frontlines + lines
185
+ lines = self._format_code(lines)
186
+ result = "\n".join(lines)
187
+ else:
188
+ lines = self._format_code(lines)
189
+ num_syms = {(k, self._print(v)) for k, v in self._number_symbols}
190
+ result = (num_syms, self._not_supported, "\n".join(lines))
191
+ self._not_supported = set()
192
+ self._number_symbols = set()
193
+ return result
194
+
195
+ def _doprint_loops(self, expr, assign_to=None):
196
+ # Here we print an expression that contains Indexed objects, they
197
+ # correspond to arrays in the generated code. The low-level implementation
198
+ # involves looping over array elements and possibly storing results in temporary
199
+ # variables or accumulate it in the assign_to object.
200
+
201
+ if self._settings.get('contract', True):
202
+ from sympy.tensor import get_contraction_structure
203
+ # Setup loops over non-dummy indices -- all terms need these
204
+ indices = self._get_expression_indices(expr, assign_to)
205
+ # Setup loops over dummy indices -- each term needs separate treatment
206
+ dummies = get_contraction_structure(expr)
207
+ else:
208
+ indices = []
209
+ dummies = {None: (expr,)}
210
+ openloop, closeloop = self._get_loop_opening_ending(indices)
211
+
212
+ # terms with no summations first
213
+ if None in dummies:
214
+ text = StrPrinter.doprint(self, Add(*dummies[None]))
215
+ else:
216
+ # If all terms have summations we must initialize array to Zero
217
+ text = StrPrinter.doprint(self, 0)
218
+
219
+ # skip redundant assignments (where lhs == rhs)
220
+ lhs_printed = self._print(assign_to)
221
+ lines = []
222
+ if text != lhs_printed:
223
+ lines.extend(openloop)
224
+ if assign_to is not None:
225
+ text = self._get_statement("%s = %s" % (lhs_printed, text))
226
+ lines.append(text)
227
+ lines.extend(closeloop)
228
+
229
+ # then terms with summations
230
+ for d in dummies:
231
+ if isinstance(d, tuple):
232
+ indices = self._sort_optimized(d, expr)
233
+ openloop_d, closeloop_d = self._get_loop_opening_ending(
234
+ indices)
235
+
236
+ for term in dummies[d]:
237
+ if term in dummies and not ([list(f.keys()) for f in dummies[term]]
238
+ == [[None] for f in dummies[term]]):
239
+ # If one factor in the term has it's own internal
240
+ # contractions, those must be computed first.
241
+ # (temporary variables?)
242
+ raise NotImplementedError(
243
+ "FIXME: no support for contractions in factor yet")
244
+ else:
245
+
246
+ # We need the lhs expression as an accumulator for
247
+ # the loops, i.e
248
+ #
249
+ # for (int d=0; d < dim; d++){
250
+ # lhs[] = lhs[] + term[][d]
251
+ # } ^.................. the accumulator
252
+ #
253
+ # We check if the expression already contains the
254
+ # lhs, and raise an exception if it does, as that
255
+ # syntax is currently undefined. FIXME: What would be
256
+ # a good interpretation?
257
+ if assign_to is None:
258
+ raise AssignmentError(
259
+ "need assignment variable for loops")
260
+ if term.has(assign_to):
261
+ raise ValueError("FIXME: lhs present in rhs,\
262
+ this is undefined in CodePrinter")
263
+
264
+ lines.extend(openloop)
265
+ lines.extend(openloop_d)
266
+ text = "%s = %s" % (lhs_printed, StrPrinter.doprint(
267
+ self, assign_to + term))
268
+ lines.append(self._get_statement(text))
269
+ lines.extend(closeloop_d)
270
+ lines.extend(closeloop)
271
+
272
+ return "\n".join(lines)
273
+
274
+ def _get_expression_indices(self, expr, assign_to):
275
+ from sympy.tensor import get_indices
276
+ rinds, junk = get_indices(expr)
277
+ linds, junk = get_indices(assign_to)
278
+
279
+ # support broadcast of scalar
280
+ if linds and not rinds:
281
+ rinds = linds
282
+ if rinds != linds:
283
+ raise ValueError("lhs indices must match non-dummy"
284
+ " rhs indices in %s" % expr)
285
+
286
+ return self._sort_optimized(rinds, assign_to)
287
+
288
+ def _sort_optimized(self, indices, expr):
289
+
290
+ from sympy.tensor.indexed import Indexed
291
+
292
+ if not indices:
293
+ return []
294
+
295
+ # determine optimized loop order by giving a score to each index
296
+ # the index with the highest score are put in the innermost loop.
297
+ score_table = {}
298
+ for i in indices:
299
+ score_table[i] = 0
300
+
301
+ arrays = expr.atoms(Indexed)
302
+ for arr in arrays:
303
+ for p, ind in enumerate(arr.indices):
304
+ try:
305
+ score_table[ind] += self._rate_index_position(p)
306
+ except KeyError:
307
+ pass
308
+
309
+ return sorted(indices, key=lambda x: score_table[x])
310
+
311
+ def _rate_index_position(self, p):
312
+ """function to calculate score based on position among indices
313
+
314
+ This method is used to sort loops in an optimized order, see
315
+ CodePrinter._sort_optimized()
316
+ """
317
+ raise NotImplementedError("This function must be implemented by "
318
+ "subclass of CodePrinter.")
319
+
320
+ def _get_statement(self, codestring):
321
+ """Formats a codestring with the proper line ending."""
322
+ raise NotImplementedError("This function must be implemented by "
323
+ "subclass of CodePrinter.")
324
+
325
+ def _get_comment(self, text):
326
+ """Formats a text string as a comment."""
327
+ raise NotImplementedError("This function must be implemented by "
328
+ "subclass of CodePrinter.")
329
+
330
+ def _declare_number_const(self, name, value):
331
+ """Declare a numeric constant at the top of a function"""
332
+ raise NotImplementedError("This function must be implemented by "
333
+ "subclass of CodePrinter.")
334
+
335
+ def _format_code(self, lines):
336
+ """Take in a list of lines of code, and format them accordingly.
337
+
338
+ This may include indenting, wrapping long lines, etc..."""
339
+ raise NotImplementedError("This function must be implemented by "
340
+ "subclass of CodePrinter.")
341
+
342
+ def _get_loop_opening_ending(self, indices):
343
+ """Returns a tuple (open_lines, close_lines) containing lists
344
+ of codelines"""
345
+ raise NotImplementedError("This function must be implemented by "
346
+ "subclass of CodePrinter.")
347
+
348
+ def _print_Dummy(self, expr):
349
+ if expr.name.startswith('Dummy_'):
350
+ return '_' + expr.name
351
+ else:
352
+ return '%s_%d' % (expr.name, expr.dummy_index)
353
+
354
+ def _print_CodeBlock(self, expr):
355
+ return '\n'.join([self._print(i) for i in expr.args])
356
+
357
+ def _print_String(self, string):
358
+ return str(string)
359
+
360
+ def _print_QuotedString(self, arg):
361
+ return '"%s"' % arg.text
362
+
363
+ def _print_Comment(self, string):
364
+ return self._get_comment(str(string))
365
+
366
+ def _print_Assignment(self, expr):
367
+ from sympy.codegen.ast import Assignment
368
+ from sympy.functions.elementary.piecewise import Piecewise
369
+ from sympy.matrices.expressions.matexpr import MatrixSymbol
370
+ from sympy.tensor.indexed import IndexedBase
371
+ lhs = expr.lhs
372
+ rhs = expr.rhs
373
+ # We special case assignments that take multiple lines
374
+ if isinstance(expr.rhs, Piecewise):
375
+ # Here we modify Piecewise so each expression is now
376
+ # an Assignment, and then continue on the print.
377
+ expressions = []
378
+ conditions = []
379
+ for (e, c) in rhs.args:
380
+ expressions.append(Assignment(lhs, e))
381
+ conditions.append(c)
382
+ temp = Piecewise(*zip(expressions, conditions))
383
+ return self._print(temp)
384
+ elif isinstance(lhs, MatrixSymbol):
385
+ # Here we form an Assignment for each element in the array,
386
+ # printing each one.
387
+ lines = []
388
+ for (i, j) in self._traverse_matrix_indices(lhs):
389
+ temp = Assignment(lhs[i, j], rhs[i, j])
390
+ code0 = self._print(temp)
391
+ lines.append(code0)
392
+ return "\n".join(lines)
393
+ elif self._settings.get("contract", False) and (lhs.has(IndexedBase) or
394
+ rhs.has(IndexedBase)):
395
+ # Here we check if there is looping to be done, and if so
396
+ # print the required loops.
397
+ return self._doprint_loops(rhs, lhs)
398
+ else:
399
+ lhs_code = self._print(lhs)
400
+ rhs_code = self._print(rhs)
401
+ return self._get_statement("%s = %s" % (lhs_code, rhs_code))
402
+
403
+ def _print_AugmentedAssignment(self, expr):
404
+ lhs_code = self._print(expr.lhs)
405
+ rhs_code = self._print(expr.rhs)
406
+ return self._get_statement("{} {} {}".format(
407
+ *(self._print(arg) for arg in [lhs_code, expr.op, rhs_code])))
408
+
409
+ def _print_FunctionCall(self, expr):
410
+ return '%s(%s)' % (
411
+ expr.name,
412
+ ', '.join((self._print(arg) for arg in expr.function_args)))
413
+
414
+ def _print_Variable(self, expr):
415
+ return self._print(expr.symbol)
416
+
417
+ def _print_Symbol(self, expr):
418
+
419
+ name = super()._print_Symbol(expr)
420
+
421
+ if name in self.reserved_words:
422
+ if self._settings['error_on_reserved']:
423
+ msg = ('This expression includes the symbol "{}" which is a '
424
+ 'reserved keyword in this language.')
425
+ raise ValueError(msg.format(name))
426
+ return name + self._settings['reserved_word_suffix']
427
+ else:
428
+ return name
429
+
430
+ def _can_print(self, name):
431
+ """ Check if function ``name`` is either a known function or has its own
432
+ printing method. Used to check if rewriting is possible."""
433
+ return name in self.known_functions or getattr(self, '_print_{}'.format(name), False)
434
+
435
+ def _print_Function(self, expr):
436
+ if expr.func.__name__ in self.known_functions:
437
+ cond_func = self.known_functions[expr.func.__name__]
438
+ if isinstance(cond_func, str):
439
+ return "%s(%s)" % (cond_func, self.stringify(expr.args, ", "))
440
+ else:
441
+ for cond, func in cond_func:
442
+ if cond(*expr.args):
443
+ break
444
+ if func is not None:
445
+ try:
446
+ return func(*[self.parenthesize(item, 0) for item in expr.args])
447
+ except TypeError:
448
+ return "%s(%s)" % (func, self.stringify(expr.args, ", "))
449
+ elif hasattr(expr, '_imp_') and isinstance(expr._imp_, Lambda):
450
+ # inlined function
451
+ return self._print(expr._imp_(*expr.args))
452
+ elif expr.func.__name__ in self._rewriteable_functions:
453
+ # Simple rewrite to supported function possible
454
+ target_f, required_fs = self._rewriteable_functions[expr.func.__name__]
455
+ if self._can_print(target_f) and all(self._can_print(f) for f in required_fs):
456
+ return '(' + self._print(expr.rewrite(target_f)) + ')'
457
+
458
+ if expr.is_Function and self._settings.get('allow_unknown_functions', False):
459
+ return '%s(%s)' % (self._print(expr.func), ', '.join(map(self._print, expr.args)))
460
+ else:
461
+ return self._print_not_supported(expr)
462
+
463
+ _print_Expr = _print_Function
464
+
465
+ # Don't inherit the str-printer method for Heaviside to the code printers
466
+ _print_Heaviside = None
467
+
468
+ def _print_NumberSymbol(self, expr):
469
+ if self._settings.get("inline", False):
470
+ return self._print(Float(expr.evalf(self._settings["precision"])))
471
+ else:
472
+ # A Number symbol that is not implemented here or with _printmethod
473
+ # is registered and evaluated
474
+ self._number_symbols.add((expr,
475
+ Float(expr.evalf(self._settings["precision"]))))
476
+ return str(expr)
477
+
478
+ def _print_Catalan(self, expr):
479
+ return self._print_NumberSymbol(expr)
480
+ def _print_EulerGamma(self, expr):
481
+ return self._print_NumberSymbol(expr)
482
+ def _print_GoldenRatio(self, expr):
483
+ return self._print_NumberSymbol(expr)
484
+ def _print_TribonacciConstant(self, expr):
485
+ return self._print_NumberSymbol(expr)
486
+ def _print_Exp1(self, expr):
487
+ return self._print_NumberSymbol(expr)
488
+ def _print_Pi(self, expr):
489
+ return self._print_NumberSymbol(expr)
490
+
491
+ def _print_And(self, expr):
492
+ PREC = precedence(expr)
493
+ return (" %s " % self._operators['and']).join(self.parenthesize(a, PREC)
494
+ for a in sorted(expr.args, key=default_sort_key))
495
+
496
+ def _print_Or(self, expr):
497
+ PREC = precedence(expr)
498
+ return (" %s " % self._operators['or']).join(self.parenthesize(a, PREC)
499
+ for a in sorted(expr.args, key=default_sort_key))
500
+
501
+ def _print_Xor(self, expr):
502
+ if self._operators.get('xor') is None:
503
+ return self._print(expr.to_nnf())
504
+ PREC = precedence(expr)
505
+ return (" %s " % self._operators['xor']).join(self.parenthesize(a, PREC)
506
+ for a in expr.args)
507
+
508
+ def _print_Equivalent(self, expr):
509
+ if self._operators.get('equivalent') is None:
510
+ return self._print(expr.to_nnf())
511
+ PREC = precedence(expr)
512
+ return (" %s " % self._operators['equivalent']).join(self.parenthesize(a, PREC)
513
+ for a in expr.args)
514
+
515
+ def _print_Not(self, expr):
516
+ PREC = precedence(expr)
517
+ return self._operators['not'] + self.parenthesize(expr.args[0], PREC)
518
+
519
+ def _print_BooleanFunction(self, expr):
520
+ return self._print(expr.to_nnf())
521
+
522
+ def _print_Mul(self, expr):
523
+
524
+ prec = precedence(expr)
525
+
526
+ c, e = expr.as_coeff_Mul()
527
+ if c < 0:
528
+ expr = _keep_coeff(-c, e)
529
+ sign = "-"
530
+ else:
531
+ sign = ""
532
+
533
+ a = [] # items in the numerator
534
+ b = [] # items that are in the denominator (if any)
535
+
536
+ pow_paren = [] # Will collect all pow with more than one base element and exp = -1
537
+
538
+ if self.order not in ('old', 'none'):
539
+ args = expr.as_ordered_factors()
540
+ else:
541
+ # use make_args in case expr was something like -x -> x
542
+ args = Mul.make_args(expr)
543
+
544
+ # Gather args for numerator/denominator
545
+ for item in args:
546
+ if item.is_commutative and item.is_Pow and item.exp.is_Rational and item.exp.is_negative:
547
+ if item.exp != -1:
548
+ b.append(Pow(item.base, -item.exp, evaluate=False))
549
+ else:
550
+ if len(item.args[0].args) != 1 and isinstance(item.base, Mul): # To avoid situations like #14160
551
+ pow_paren.append(item)
552
+ b.append(Pow(item.base, -item.exp))
553
+ else:
554
+ a.append(item)
555
+
556
+ a = a or [S.One]
557
+
558
+ if len(a) == 1 and sign == "-":
559
+ # Unary minus does not have a SymPy class, and hence there's no
560
+ # precedence weight associated with it, Python's unary minus has
561
+ # an operator precedence between multiplication and exponentiation,
562
+ # so we use this to compute a weight.
563
+ a_str = [self.parenthesize(a[0], 0.5*(PRECEDENCE["Pow"]+PRECEDENCE["Mul"]))]
564
+ else:
565
+ a_str = [self.parenthesize(x, prec) for x in a]
566
+ b_str = [self.parenthesize(x, prec) for x in b]
567
+
568
+ # To parenthesize Pow with exp = -1 and having more than one Symbol
569
+ for item in pow_paren:
570
+ if item.base in b:
571
+ b_str[b.index(item.base)] = "(%s)" % b_str[b.index(item.base)]
572
+
573
+ if not b:
574
+ return sign + '*'.join(a_str)
575
+ elif len(b) == 1:
576
+ return sign + '*'.join(a_str) + "/" + b_str[0]
577
+ else:
578
+ return sign + '*'.join(a_str) + "/(%s)" % '*'.join(b_str)
579
+
580
+ def _print_not_supported(self, expr):
581
+ if self._settings.get('strict', False):
582
+ raise PrintMethodNotImplementedError("Unsupported by %s: %s" % (str(type(self)), str(type(expr))) + \
583
+ "\nSet the printer option 'strict' to False in order to generate partially printed code.")
584
+ try:
585
+ self._not_supported.add(expr)
586
+ except TypeError:
587
+ # not hashable
588
+ pass
589
+ return self.emptyPrinter(expr)
590
+
591
+ # The following can not be simply translated into C or Fortran
592
+ _print_Basic = _print_not_supported
593
+ _print_ComplexInfinity = _print_not_supported
594
+ _print_Derivative = _print_not_supported
595
+ _print_ExprCondPair = _print_not_supported
596
+ _print_GeometryEntity = _print_not_supported
597
+ _print_Infinity = _print_not_supported
598
+ _print_Integral = _print_not_supported
599
+ _print_Interval = _print_not_supported
600
+ _print_AccumulationBounds = _print_not_supported
601
+ _print_Limit = _print_not_supported
602
+ _print_MatrixBase = _print_not_supported
603
+ _print_DeferredVector = _print_not_supported
604
+ _print_NaN = _print_not_supported
605
+ _print_NegativeInfinity = _print_not_supported
606
+ _print_Order = _print_not_supported
607
+ _print_RootOf = _print_not_supported
608
+ _print_RootsOf = _print_not_supported
609
+ _print_RootSum = _print_not_supported
610
+ _print_Uniform = _print_not_supported
611
+ _print_Unit = _print_not_supported
612
+ _print_Wild = _print_not_supported
613
+ _print_WildFunction = _print_not_supported
614
+ _print_Relational = _print_not_supported
615
+
616
+
617
+ # Code printer functions. These are included in this file so that they can be
618
+ # imported in the top-level __init__.py without importing the sympy.codegen
619
+ # module.
620
+
621
+ def ccode(expr, assign_to=None, standard='c99', **settings):
622
+ """Converts an expr to a string of c code
623
+
624
+ Parameters
625
+ ==========
626
+
627
+ expr : Expr
628
+ A SymPy expression to be converted.
629
+ assign_to : optional
630
+ When given, the argument is used as the name of the variable to which
631
+ the expression is assigned. Can be a string, ``Symbol``,
632
+ ``MatrixSymbol``, or ``Indexed`` type. This is helpful in case of
633
+ line-wrapping, or for expressions that generate multi-line statements.
634
+ standard : str, optional
635
+ String specifying the standard. If your compiler supports a more modern
636
+ standard you may set this to 'c99' to allow the printer to use more math
637
+ functions. [default='c89'].
638
+ precision : integer, optional
639
+ The precision for numbers such as pi [default=17].
640
+ user_functions : dict, optional
641
+ A dictionary where the keys are string representations of either
642
+ ``FunctionClass`` or ``UndefinedFunction`` instances and the values
643
+ are their desired C string representations. Alternatively, the
644
+ dictionary value can be a list of tuples i.e. [(argument_test,
645
+ cfunction_string)] or [(argument_test, cfunction_formater)]. See below
646
+ for examples.
647
+ dereference : iterable, optional
648
+ An iterable of symbols that should be dereferenced in the printed code
649
+ expression. These would be values passed by address to the function.
650
+ For example, if ``dereference=[a]``, the resulting code would print
651
+ ``(*a)`` instead of ``a``.
652
+ human : bool, optional
653
+ If True, the result is a single string that may contain some constant
654
+ declarations for the number symbols. If False, the same information is
655
+ returned in a tuple of (symbols_to_declare, not_supported_functions,
656
+ code_text). [default=True].
657
+ contract: bool, optional
658
+ If True, ``Indexed`` instances are assumed to obey tensor contraction
659
+ rules and the corresponding nested loops over indices are generated.
660
+ Setting contract=False will not generate loops, instead the user is
661
+ responsible to provide values for the indices in the code.
662
+ [default=True].
663
+
664
+ Examples
665
+ ========
666
+
667
+ >>> from sympy import ccode, symbols, Rational, sin, ceiling, Abs, Function
668
+ >>> x, tau = symbols("x, tau")
669
+ >>> expr = (2*tau)**Rational(7, 2)
670
+ >>> ccode(expr)
671
+ '8*M_SQRT2*pow(tau, 7.0/2.0)'
672
+ >>> ccode(expr, math_macros={})
673
+ '8*sqrt(2)*pow(tau, 7.0/2.0)'
674
+ >>> ccode(sin(x), assign_to="s")
675
+ 's = sin(x);'
676
+ >>> from sympy.codegen.ast import real, float80
677
+ >>> ccode(expr, type_aliases={real: float80})
678
+ '8*M_SQRT2l*powl(tau, 7.0L/2.0L)'
679
+
680
+ Simple custom printing can be defined for certain types by passing a
681
+ dictionary of {"type" : "function"} to the ``user_functions`` kwarg.
682
+ Alternatively, the dictionary value can be a list of tuples i.e.
683
+ [(argument_test, cfunction_string)].
684
+
685
+ >>> custom_functions = {
686
+ ... "ceiling": "CEIL",
687
+ ... "Abs": [(lambda x: not x.is_integer, "fabs"),
688
+ ... (lambda x: x.is_integer, "ABS")],
689
+ ... "func": "f"
690
+ ... }
691
+ >>> func = Function('func')
692
+ >>> ccode(func(Abs(x) + ceiling(x)), standard='C89', user_functions=custom_functions)
693
+ 'f(fabs(x) + CEIL(x))'
694
+
695
+ or if the C-function takes a subset of the original arguments:
696
+
697
+ >>> ccode(2**x + 3**x, standard='C99', user_functions={'Pow': [
698
+ ... (lambda b, e: b == 2, lambda b, e: 'exp2(%s)' % e),
699
+ ... (lambda b, e: b != 2, 'pow')]})
700
+ 'exp2(x) + pow(3, x)'
701
+
702
+ ``Piecewise`` expressions are converted into conditionals. If an
703
+ ``assign_to`` variable is provided an if statement is created, otherwise
704
+ the ternary operator is used. Note that if the ``Piecewise`` lacks a
705
+ default term, represented by ``(expr, True)`` then an error will be thrown.
706
+ This is to prevent generating an expression that may not evaluate to
707
+ anything.
708
+
709
+ >>> from sympy import Piecewise
710
+ >>> expr = Piecewise((x + 1, x > 0), (x, True))
711
+ >>> print(ccode(expr, tau, standard='C89'))
712
+ if (x > 0) {
713
+ tau = x + 1;
714
+ }
715
+ else {
716
+ tau = x;
717
+ }
718
+
719
+ Support for loops is provided through ``Indexed`` types. With
720
+ ``contract=True`` these expressions will be turned into loops, whereas
721
+ ``contract=False`` will just print the assignment expression that should be
722
+ looped over:
723
+
724
+ >>> from sympy import Eq, IndexedBase, Idx
725
+ >>> len_y = 5
726
+ >>> y = IndexedBase('y', shape=(len_y,))
727
+ >>> t = IndexedBase('t', shape=(len_y,))
728
+ >>> Dy = IndexedBase('Dy', shape=(len_y-1,))
729
+ >>> i = Idx('i', len_y-1)
730
+ >>> e=Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i]))
731
+ >>> ccode(e.rhs, assign_to=e.lhs, contract=False, standard='C89')
732
+ 'Dy[i] = (y[i + 1] - y[i])/(t[i + 1] - t[i]);'
733
+
734
+ Matrices are also supported, but a ``MatrixSymbol`` of the same dimensions
735
+ must be provided to ``assign_to``. Note that any expression that can be
736
+ generated normally can also exist inside a Matrix:
737
+
738
+ >>> from sympy import Matrix, MatrixSymbol
739
+ >>> mat = Matrix([x**2, Piecewise((x + 1, x > 0), (x, True)), sin(x)])
740
+ >>> A = MatrixSymbol('A', 3, 1)
741
+ >>> print(ccode(mat, A, standard='C89'))
742
+ A[0] = pow(x, 2);
743
+ if (x > 0) {
744
+ A[1] = x + 1;
745
+ }
746
+ else {
747
+ A[1] = x;
748
+ }
749
+ A[2] = sin(x);
750
+ """
751
+ from sympy.printing.c import c_code_printers
752
+ return c_code_printers[standard.lower()](settings).doprint(expr, assign_to)
753
+
754
+ def print_ccode(expr, **settings):
755
+ """Prints C representation of the given expression."""
756
+ print(ccode(expr, **settings))
757
+
758
+ def fcode(expr, assign_to=None, **settings):
759
+ """Converts an expr to a string of fortran code
760
+
761
+ Parameters
762
+ ==========
763
+
764
+ expr : Expr
765
+ A SymPy expression to be converted.
766
+ assign_to : optional
767
+ When given, the argument is used as the name of the variable to which
768
+ the expression is assigned. Can be a string, ``Symbol``,
769
+ ``MatrixSymbol``, or ``Indexed`` type. This is helpful in case of
770
+ line-wrapping, or for expressions that generate multi-line statements.
771
+ precision : integer, optional
772
+ DEPRECATED. Use type_mappings instead. The precision for numbers such
773
+ as pi [default=17].
774
+ user_functions : dict, optional
775
+ A dictionary where keys are ``FunctionClass`` instances and values are
776
+ their string representations. Alternatively, the dictionary value can
777
+ be a list of tuples i.e. [(argument_test, cfunction_string)]. See below
778
+ for examples.
779
+ human : bool, optional
780
+ If True, the result is a single string that may contain some constant
781
+ declarations for the number symbols. If False, the same information is
782
+ returned in a tuple of (symbols_to_declare, not_supported_functions,
783
+ code_text). [default=True].
784
+ contract: bool, optional
785
+ If True, ``Indexed`` instances are assumed to obey tensor contraction
786
+ rules and the corresponding nested loops over indices are generated.
787
+ Setting contract=False will not generate loops, instead the user is
788
+ responsible to provide values for the indices in the code.
789
+ [default=True].
790
+ source_format : optional
791
+ The source format can be either 'fixed' or 'free'. [default='fixed']
792
+ standard : integer, optional
793
+ The Fortran standard to be followed. This is specified as an integer.
794
+ Acceptable standards are 66, 77, 90, 95, 2003, and 2008. Default is 77.
795
+ Note that currently the only distinction internally is between
796
+ standards before 95, and those 95 and after. This may change later as
797
+ more features are added.
798
+ name_mangling : bool, optional
799
+ If True, then the variables that would become identical in
800
+ case-insensitive Fortran are mangled by appending different number
801
+ of ``_`` at the end. If False, SymPy Will not interfere with naming of
802
+ variables. [default=True]
803
+
804
+ Examples
805
+ ========
806
+
807
+ >>> from sympy import fcode, symbols, Rational, sin, ceiling, floor
808
+ >>> x, tau = symbols("x, tau")
809
+ >>> fcode((2*tau)**Rational(7, 2))
810
+ ' 8*sqrt(2.0d0)*tau**(7.0d0/2.0d0)'
811
+ >>> fcode(sin(x), assign_to="s")
812
+ ' s = sin(x)'
813
+
814
+ Custom printing can be defined for certain types by passing a dictionary of
815
+ "type" : "function" to the ``user_functions`` kwarg. Alternatively, the
816
+ dictionary value can be a list of tuples i.e. [(argument_test,
817
+ cfunction_string)].
818
+
819
+ >>> custom_functions = {
820
+ ... "ceiling": "CEIL",
821
+ ... "floor": [(lambda x: not x.is_integer, "FLOOR1"),
822
+ ... (lambda x: x.is_integer, "FLOOR2")]
823
+ ... }
824
+ >>> fcode(floor(x) + ceiling(x), user_functions=custom_functions)
825
+ ' CEIL(x) + FLOOR1(x)'
826
+
827
+ ``Piecewise`` expressions are converted into conditionals. If an
828
+ ``assign_to`` variable is provided an if statement is created, otherwise
829
+ the ternary operator is used. Note that if the ``Piecewise`` lacks a
830
+ default term, represented by ``(expr, True)`` then an error will be thrown.
831
+ This is to prevent generating an expression that may not evaluate to
832
+ anything.
833
+
834
+ >>> from sympy import Piecewise
835
+ >>> expr = Piecewise((x + 1, x > 0), (x, True))
836
+ >>> print(fcode(expr, tau))
837
+ if (x > 0) then
838
+ tau = x + 1
839
+ else
840
+ tau = x
841
+ end if
842
+
843
+ Support for loops is provided through ``Indexed`` types. With
844
+ ``contract=True`` these expressions will be turned into loops, whereas
845
+ ``contract=False`` will just print the assignment expression that should be
846
+ looped over:
847
+
848
+ >>> from sympy import Eq, IndexedBase, Idx
849
+ >>> len_y = 5
850
+ >>> y = IndexedBase('y', shape=(len_y,))
851
+ >>> t = IndexedBase('t', shape=(len_y,))
852
+ >>> Dy = IndexedBase('Dy', shape=(len_y-1,))
853
+ >>> i = Idx('i', len_y-1)
854
+ >>> e=Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i]))
855
+ >>> fcode(e.rhs, assign_to=e.lhs, contract=False)
856
+ ' Dy(i) = (y(i + 1) - y(i))/(t(i + 1) - t(i))'
857
+
858
+ Matrices are also supported, but a ``MatrixSymbol`` of the same dimensions
859
+ must be provided to ``assign_to``. Note that any expression that can be
860
+ generated normally can also exist inside a Matrix:
861
+
862
+ >>> from sympy import Matrix, MatrixSymbol
863
+ >>> mat = Matrix([x**2, Piecewise((x + 1, x > 0), (x, True)), sin(x)])
864
+ >>> A = MatrixSymbol('A', 3, 1)
865
+ >>> print(fcode(mat, A))
866
+ A(1, 1) = x**2
867
+ if (x > 0) then
868
+ A(2, 1) = x + 1
869
+ else
870
+ A(2, 1) = x
871
+ end if
872
+ A(3, 1) = sin(x)
873
+ """
874
+ from sympy.printing.fortran import FCodePrinter
875
+ return FCodePrinter(settings).doprint(expr, assign_to)
876
+
877
+
878
+ def print_fcode(expr, **settings):
879
+ """Prints the Fortran representation of the given expression.
880
+
881
+ See fcode for the meaning of the optional arguments.
882
+ """
883
+ print(fcode(expr, **settings))
884
+
885
+ def cxxcode(expr, assign_to=None, standard='c++11', **settings):
886
+ """ C++ equivalent of :func:`~.ccode`. """
887
+ from sympy.printing.cxx import cxx_code_printers
888
+ return cxx_code_printers[standard.lower()](settings).doprint(expr, assign_to)
lib/python3.12/site-packages/sympy/printing/octave.py ADDED
@@ -0,0 +1,715 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Octave (and Matlab) code printer
3
+
4
+ The `OctaveCodePrinter` converts SymPy expressions into Octave expressions.
5
+ It uses a subset of the Octave language for Matlab compatibility.
6
+
7
+ A complete code generator, which uses `octave_code` extensively, can be found
8
+ in `sympy.utilities.codegen`. The `codegen` module can be used to generate
9
+ complete source code files.
10
+
11
+ """
12
+
13
+ from __future__ import annotations
14
+ from typing import Any
15
+
16
+ from sympy.core import Mul, Pow, S, Rational
17
+ from sympy.core.mul import _keep_coeff
18
+ from sympy.core.numbers import equal_valued
19
+ from sympy.printing.codeprinter import CodePrinter
20
+ from sympy.printing.precedence import precedence, PRECEDENCE
21
+ from re import search
22
+
23
+ # List of known functions. First, those that have the same name in
24
+ # SymPy and Octave. This is almost certainly incomplete!
25
+ known_fcns_src1 = ["sin", "cos", "tan", "cot", "sec", "csc",
26
+ "asin", "acos", "acot", "atan", "atan2", "asec", "acsc",
27
+ "sinh", "cosh", "tanh", "coth", "csch", "sech",
28
+ "asinh", "acosh", "atanh", "acoth", "asech", "acsch",
29
+ "erfc", "erfi", "erf", "erfinv", "erfcinv",
30
+ "besseli", "besselj", "besselk", "bessely",
31
+ "bernoulli", "beta", "euler", "exp", "factorial", "floor",
32
+ "fresnelc", "fresnels", "gamma", "harmonic", "log",
33
+ "polylog", "sign", "zeta", "legendre"]
34
+
35
+ # These functions have different names ("SymPy": "Octave"), more
36
+ # generally a mapping to (argument_conditions, octave_function).
37
+ known_fcns_src2 = {
38
+ "Abs": "abs",
39
+ "arg": "angle", # arg/angle ok in Octave but only angle in Matlab
40
+ "binomial": "bincoeff",
41
+ "ceiling": "ceil",
42
+ "chebyshevu": "chebyshevU",
43
+ "chebyshevt": "chebyshevT",
44
+ "Chi": "coshint",
45
+ "Ci": "cosint",
46
+ "conjugate": "conj",
47
+ "DiracDelta": "dirac",
48
+ "Heaviside": "heaviside",
49
+ "im": "imag",
50
+ "laguerre": "laguerreL",
51
+ "LambertW": "lambertw",
52
+ "li": "logint",
53
+ "loggamma": "gammaln",
54
+ "Max": "max",
55
+ "Min": "min",
56
+ "Mod": "mod",
57
+ "polygamma": "psi",
58
+ "re": "real",
59
+ "RisingFactorial": "pochhammer",
60
+ "Shi": "sinhint",
61
+ "Si": "sinint",
62
+ }
63
+
64
+
65
+ class OctaveCodePrinter(CodePrinter):
66
+ """
67
+ A printer to convert expressions to strings of Octave/Matlab code.
68
+ """
69
+ printmethod = "_octave"
70
+ language = "Octave"
71
+
72
+ _operators = {
73
+ 'and': '&',
74
+ 'or': '|',
75
+ 'not': '~',
76
+ }
77
+
78
+ _default_settings: dict[str, Any] = dict(CodePrinter._default_settings, **{
79
+ 'precision': 17,
80
+ 'user_functions': {},
81
+ 'contract': True,
82
+ 'inline': True,
83
+ })
84
+ # Note: contract is for expressing tensors as loops (if True), or just
85
+ # assignment (if False). FIXME: this should be looked a more carefully
86
+ # for Octave.
87
+
88
+
89
+ def __init__(self, settings={}):
90
+ super().__init__(settings)
91
+ self.known_functions = dict(zip(known_fcns_src1, known_fcns_src1))
92
+ self.known_functions.update(dict(known_fcns_src2))
93
+ userfuncs = settings.get('user_functions', {})
94
+ self.known_functions.update(userfuncs)
95
+
96
+
97
+ def _rate_index_position(self, p):
98
+ return p*5
99
+
100
+
101
+ def _get_statement(self, codestring):
102
+ return "%s;" % codestring
103
+
104
+
105
+ def _get_comment(self, text):
106
+ return "% {}".format(text)
107
+
108
+
109
+ def _declare_number_const(self, name, value):
110
+ return "{} = {};".format(name, value)
111
+
112
+
113
+ def _format_code(self, lines):
114
+ return self.indent_code(lines)
115
+
116
+
117
+ def _traverse_matrix_indices(self, mat):
118
+ # Octave uses Fortran order (column-major)
119
+ rows, cols = mat.shape
120
+ return ((i, j) for j in range(cols) for i in range(rows))
121
+
122
+
123
+ def _get_loop_opening_ending(self, indices):
124
+ open_lines = []
125
+ close_lines = []
126
+ for i in indices:
127
+ # Octave arrays start at 1 and end at dimension
128
+ var, start, stop = map(self._print,
129
+ [i.label, i.lower + 1, i.upper + 1])
130
+ open_lines.append("for %s = %s:%s" % (var, start, stop))
131
+ close_lines.append("end")
132
+ return open_lines, close_lines
133
+
134
+
135
+ def _print_Mul(self, expr):
136
+ # print complex numbers nicely in Octave
137
+ if (expr.is_number and expr.is_imaginary and
138
+ (S.ImaginaryUnit*expr).is_Integer):
139
+ return "%si" % self._print(-S.ImaginaryUnit*expr)
140
+
141
+ # cribbed from str.py
142
+ prec = precedence(expr)
143
+
144
+ c, e = expr.as_coeff_Mul()
145
+ if c < 0:
146
+ expr = _keep_coeff(-c, e)
147
+ sign = "-"
148
+ else:
149
+ sign = ""
150
+
151
+ a = [] # items in the numerator
152
+ b = [] # items that are in the denominator (if any)
153
+
154
+ pow_paren = [] # Will collect all pow with more than one base element and exp = -1
155
+
156
+ if self.order not in ('old', 'none'):
157
+ args = expr.as_ordered_factors()
158
+ else:
159
+ # use make_args in case expr was something like -x -> x
160
+ args = Mul.make_args(expr)
161
+
162
+ # Gather args for numerator/denominator
163
+ for item in args:
164
+ if (item.is_commutative and item.is_Pow and item.exp.is_Rational
165
+ and item.exp.is_negative):
166
+ if item.exp != -1:
167
+ b.append(Pow(item.base, -item.exp, evaluate=False))
168
+ else:
169
+ if len(item.args[0].args) != 1 and isinstance(item.base, Mul): # To avoid situations like #14160
170
+ pow_paren.append(item)
171
+ b.append(Pow(item.base, -item.exp))
172
+ elif item.is_Rational and item is not S.Infinity:
173
+ if item.p != 1:
174
+ a.append(Rational(item.p))
175
+ if item.q != 1:
176
+ b.append(Rational(item.q))
177
+ else:
178
+ a.append(item)
179
+
180
+ a = a or [S.One]
181
+
182
+ a_str = [self.parenthesize(x, prec) for x in a]
183
+ b_str = [self.parenthesize(x, prec) for x in b]
184
+
185
+ # To parenthesize Pow with exp = -1 and having more than one Symbol
186
+ for item in pow_paren:
187
+ if item.base in b:
188
+ b_str[b.index(item.base)] = "(%s)" % b_str[b.index(item.base)]
189
+
190
+ # from here it differs from str.py to deal with "*" and ".*"
191
+ def multjoin(a, a_str):
192
+ # here we probably are assuming the constants will come first
193
+ r = a_str[0]
194
+ for i in range(1, len(a)):
195
+ mulsym = '*' if a[i-1].is_number else '.*'
196
+ r = r + mulsym + a_str[i]
197
+ return r
198
+
199
+ if not b:
200
+ return sign + multjoin(a, a_str)
201
+ elif len(b) == 1:
202
+ divsym = '/' if b[0].is_number else './'
203
+ return sign + multjoin(a, a_str) + divsym + b_str[0]
204
+ else:
205
+ divsym = '/' if all(bi.is_number for bi in b) else './'
206
+ return (sign + multjoin(a, a_str) +
207
+ divsym + "(%s)" % multjoin(b, b_str))
208
+
209
+ def _print_Relational(self, expr):
210
+ lhs_code = self._print(expr.lhs)
211
+ rhs_code = self._print(expr.rhs)
212
+ op = expr.rel_op
213
+ return "{} {} {}".format(lhs_code, op, rhs_code)
214
+
215
+ def _print_Pow(self, expr):
216
+ powsymbol = '^' if all(x.is_number for x in expr.args) else '.^'
217
+
218
+ PREC = precedence(expr)
219
+
220
+ if equal_valued(expr.exp, 0.5):
221
+ return "sqrt(%s)" % self._print(expr.base)
222
+
223
+ if expr.is_commutative:
224
+ if equal_valued(expr.exp, -0.5):
225
+ sym = '/' if expr.base.is_number else './'
226
+ return "1" + sym + "sqrt(%s)" % self._print(expr.base)
227
+ if equal_valued(expr.exp, -1):
228
+ sym = '/' if expr.base.is_number else './'
229
+ return "1" + sym + "%s" % self.parenthesize(expr.base, PREC)
230
+
231
+ return '%s%s%s' % (self.parenthesize(expr.base, PREC), powsymbol,
232
+ self.parenthesize(expr.exp, PREC))
233
+
234
+
235
+ def _print_MatPow(self, expr):
236
+ PREC = precedence(expr)
237
+ return '%s^%s' % (self.parenthesize(expr.base, PREC),
238
+ self.parenthesize(expr.exp, PREC))
239
+
240
+ def _print_MatrixSolve(self, expr):
241
+ PREC = precedence(expr)
242
+ return "%s \\ %s" % (self.parenthesize(expr.matrix, PREC),
243
+ self.parenthesize(expr.vector, PREC))
244
+
245
+ def _print_Pi(self, expr):
246
+ return 'pi'
247
+
248
+
249
+ def _print_ImaginaryUnit(self, expr):
250
+ return "1i"
251
+
252
+
253
+ def _print_Exp1(self, expr):
254
+ return "exp(1)"
255
+
256
+
257
+ def _print_GoldenRatio(self, expr):
258
+ # FIXME: how to do better, e.g., for octave_code(2*GoldenRatio)?
259
+ #return self._print((1+sqrt(S(5)))/2)
260
+ return "(1+sqrt(5))/2"
261
+
262
+
263
+ def _print_Assignment(self, expr):
264
+ from sympy.codegen.ast import Assignment
265
+ from sympy.functions.elementary.piecewise import Piecewise
266
+ from sympy.tensor.indexed import IndexedBase
267
+ # Copied from codeprinter, but remove special MatrixSymbol treatment
268
+ lhs = expr.lhs
269
+ rhs = expr.rhs
270
+ # We special case assignments that take multiple lines
271
+ if not self._settings["inline"] and isinstance(expr.rhs, Piecewise):
272
+ # Here we modify Piecewise so each expression is now
273
+ # an Assignment, and then continue on the print.
274
+ expressions = []
275
+ conditions = []
276
+ for (e, c) in rhs.args:
277
+ expressions.append(Assignment(lhs, e))
278
+ conditions.append(c)
279
+ temp = Piecewise(*zip(expressions, conditions))
280
+ return self._print(temp)
281
+ if self._settings["contract"] and (lhs.has(IndexedBase) or
282
+ rhs.has(IndexedBase)):
283
+ # Here we check if there is looping to be done, and if so
284
+ # print the required loops.
285
+ return self._doprint_loops(rhs, lhs)
286
+ else:
287
+ lhs_code = self._print(lhs)
288
+ rhs_code = self._print(rhs)
289
+ return self._get_statement("%s = %s" % (lhs_code, rhs_code))
290
+
291
+
292
+ def _print_Infinity(self, expr):
293
+ return 'inf'
294
+
295
+
296
+ def _print_NegativeInfinity(self, expr):
297
+ return '-inf'
298
+
299
+
300
+ def _print_NaN(self, expr):
301
+ return 'NaN'
302
+
303
+
304
+ def _print_list(self, expr):
305
+ return '{' + ', '.join(self._print(a) for a in expr) + '}'
306
+ _print_tuple = _print_list
307
+ _print_Tuple = _print_list
308
+ _print_List = _print_list
309
+
310
+
311
+ def _print_BooleanTrue(self, expr):
312
+ return "true"
313
+
314
+
315
+ def _print_BooleanFalse(self, expr):
316
+ return "false"
317
+
318
+
319
+ def _print_bool(self, expr):
320
+ return str(expr).lower()
321
+
322
+
323
+ # Could generate quadrature code for definite Integrals?
324
+ #_print_Integral = _print_not_supported
325
+
326
+
327
+ def _print_MatrixBase(self, A):
328
+ # Handle zero dimensions:
329
+ if (A.rows, A.cols) == (0, 0):
330
+ return '[]'
331
+ elif S.Zero in A.shape:
332
+ return 'zeros(%s, %s)' % (A.rows, A.cols)
333
+ elif (A.rows, A.cols) == (1, 1):
334
+ # Octave does not distinguish between scalars and 1x1 matrices
335
+ return self._print(A[0, 0])
336
+ return "[%s]" % "; ".join(" ".join([self._print(a) for a in A[r, :]])
337
+ for r in range(A.rows))
338
+
339
+
340
+ def _print_SparseRepMatrix(self, A):
341
+ from sympy.matrices import Matrix
342
+ L = A.col_list();
343
+ # make row vectors of the indices and entries
344
+ I = Matrix([[k[0] + 1 for k in L]])
345
+ J = Matrix([[k[1] + 1 for k in L]])
346
+ AIJ = Matrix([[k[2] for k in L]])
347
+ return "sparse(%s, %s, %s, %s, %s)" % (self._print(I), self._print(J),
348
+ self._print(AIJ), A.rows, A.cols)
349
+
350
+
351
+ def _print_MatrixElement(self, expr):
352
+ return self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) \
353
+ + '(%s, %s)' % (expr.i + 1, expr.j + 1)
354
+
355
+
356
+ def _print_MatrixSlice(self, expr):
357
+ def strslice(x, lim):
358
+ l = x[0] + 1
359
+ h = x[1]
360
+ step = x[2]
361
+ lstr = self._print(l)
362
+ hstr = 'end' if h == lim else self._print(h)
363
+ if step == 1:
364
+ if l == 1 and h == lim:
365
+ return ':'
366
+ if l == h:
367
+ return lstr
368
+ else:
369
+ return lstr + ':' + hstr
370
+ else:
371
+ return ':'.join((lstr, self._print(step), hstr))
372
+ return (self._print(expr.parent) + '(' +
373
+ strslice(expr.rowslice, expr.parent.shape[0]) + ', ' +
374
+ strslice(expr.colslice, expr.parent.shape[1]) + ')')
375
+
376
+
377
+ def _print_Indexed(self, expr):
378
+ inds = [ self._print(i) for i in expr.indices ]
379
+ return "%s(%s)" % (self._print(expr.base.label), ", ".join(inds))
380
+
381
+
382
+ def _print_Idx(self, expr):
383
+ return self._print(expr.label)
384
+
385
+
386
+ def _print_KroneckerDelta(self, expr):
387
+ prec = PRECEDENCE["Pow"]
388
+ return "double(%s == %s)" % tuple(self.parenthesize(x, prec)
389
+ for x in expr.args)
390
+
391
+ def _print_HadamardProduct(self, expr):
392
+ return '.*'.join([self.parenthesize(arg, precedence(expr))
393
+ for arg in expr.args])
394
+
395
+ def _print_HadamardPower(self, expr):
396
+ PREC = precedence(expr)
397
+ return '.**'.join([
398
+ self.parenthesize(expr.base, PREC),
399
+ self.parenthesize(expr.exp, PREC)
400
+ ])
401
+
402
+ def _print_Identity(self, expr):
403
+ shape = expr.shape
404
+ if len(shape) == 2 and shape[0] == shape[1]:
405
+ shape = [shape[0]]
406
+ s = ", ".join(self._print(n) for n in shape)
407
+ return "eye(" + s + ")"
408
+
409
+ def _print_lowergamma(self, expr):
410
+ # Octave implements regularized incomplete gamma function
411
+ return "(gammainc({1}, {0}).*gamma({0}))".format(
412
+ self._print(expr.args[0]), self._print(expr.args[1]))
413
+
414
+
415
+ def _print_uppergamma(self, expr):
416
+ return "(gammainc({1}, {0}, 'upper').*gamma({0}))".format(
417
+ self._print(expr.args[0]), self._print(expr.args[1]))
418
+
419
+
420
+ def _print_sinc(self, expr):
421
+ #Note: Divide by pi because Octave implements normalized sinc function.
422
+ return "sinc(%s)" % self._print(expr.args[0]/S.Pi)
423
+
424
+
425
+ def _print_hankel1(self, expr):
426
+ return "besselh(%s, 1, %s)" % (self._print(expr.order),
427
+ self._print(expr.argument))
428
+
429
+
430
+ def _print_hankel2(self, expr):
431
+ return "besselh(%s, 2, %s)" % (self._print(expr.order),
432
+ self._print(expr.argument))
433
+
434
+
435
+ # Note: as of 2015, Octave doesn't have spherical Bessel functions
436
+ def _print_jn(self, expr):
437
+ from sympy.functions import sqrt, besselj
438
+ x = expr.argument
439
+ expr2 = sqrt(S.Pi/(2*x))*besselj(expr.order + S.Half, x)
440
+ return self._print(expr2)
441
+
442
+
443
+ def _print_yn(self, expr):
444
+ from sympy.functions import sqrt, bessely
445
+ x = expr.argument
446
+ expr2 = sqrt(S.Pi/(2*x))*bessely(expr.order + S.Half, x)
447
+ return self._print(expr2)
448
+
449
+
450
+ def _print_airyai(self, expr):
451
+ return "airy(0, %s)" % self._print(expr.args[0])
452
+
453
+
454
+ def _print_airyaiprime(self, expr):
455
+ return "airy(1, %s)" % self._print(expr.args[0])
456
+
457
+
458
+ def _print_airybi(self, expr):
459
+ return "airy(2, %s)" % self._print(expr.args[0])
460
+
461
+
462
+ def _print_airybiprime(self, expr):
463
+ return "airy(3, %s)" % self._print(expr.args[0])
464
+
465
+
466
+ def _print_expint(self, expr):
467
+ mu, x = expr.args
468
+ if mu != 1:
469
+ return self._print_not_supported(expr)
470
+ return "expint(%s)" % self._print(x)
471
+
472
+
473
+ def _one_or_two_reversed_args(self, expr):
474
+ assert len(expr.args) <= 2
475
+ return '{name}({args})'.format(
476
+ name=self.known_functions[expr.__class__.__name__],
477
+ args=", ".join([self._print(x) for x in reversed(expr.args)])
478
+ )
479
+
480
+
481
+ _print_DiracDelta = _print_LambertW = _one_or_two_reversed_args
482
+
483
+
484
+ def _nested_binary_math_func(self, expr):
485
+ return '{name}({arg1}, {arg2})'.format(
486
+ name=self.known_functions[expr.__class__.__name__],
487
+ arg1=self._print(expr.args[0]),
488
+ arg2=self._print(expr.func(*expr.args[1:]))
489
+ )
490
+
491
+ _print_Max = _print_Min = _nested_binary_math_func
492
+
493
+
494
+ def _print_Piecewise(self, expr):
495
+ if expr.args[-1].cond != True:
496
+ # We need the last conditional to be a True, otherwise the resulting
497
+ # function may not return a result.
498
+ raise ValueError("All Piecewise expressions must contain an "
499
+ "(expr, True) statement to be used as a default "
500
+ "condition. Without one, the generated "
501
+ "expression may not evaluate to anything under "
502
+ "some condition.")
503
+ lines = []
504
+ if self._settings["inline"]:
505
+ # Express each (cond, expr) pair in a nested Horner form:
506
+ # (condition) .* (expr) + (not cond) .* (<others>)
507
+ # Expressions that result in multiple statements won't work here.
508
+ ecpairs = ["({0}).*({1}) + (~({0})).*(".format
509
+ (self._print(c), self._print(e))
510
+ for e, c in expr.args[:-1]]
511
+ elast = "%s" % self._print(expr.args[-1].expr)
512
+ pw = " ...\n".join(ecpairs) + elast + ")"*len(ecpairs)
513
+ # Note: current need these outer brackets for 2*pw. Would be
514
+ # nicer to teach parenthesize() to do this for us when needed!
515
+ return "(" + pw + ")"
516
+ else:
517
+ for i, (e, c) in enumerate(expr.args):
518
+ if i == 0:
519
+ lines.append("if (%s)" % self._print(c))
520
+ elif i == len(expr.args) - 1 and c == True:
521
+ lines.append("else")
522
+ else:
523
+ lines.append("elseif (%s)" % self._print(c))
524
+ code0 = self._print(e)
525
+ lines.append(code0)
526
+ if i == len(expr.args) - 1:
527
+ lines.append("end")
528
+ return "\n".join(lines)
529
+
530
+
531
+ def _print_zeta(self, expr):
532
+ if len(expr.args) == 1:
533
+ return "zeta(%s)" % self._print(expr.args[0])
534
+ else:
535
+ # Matlab two argument zeta is not equivalent to SymPy's
536
+ return self._print_not_supported(expr)
537
+
538
+
539
+ def indent_code(self, code):
540
+ """Accepts a string of code or a list of code lines"""
541
+
542
+ # code mostly copied from ccode
543
+ if isinstance(code, str):
544
+ code_lines = self.indent_code(code.splitlines(True))
545
+ return ''.join(code_lines)
546
+
547
+ tab = " "
548
+ inc_regex = ('^function ', '^if ', '^elseif ', '^else$', '^for ')
549
+ dec_regex = ('^end$', '^elseif ', '^else$')
550
+
551
+ # pre-strip left-space from the code
552
+ code = [ line.lstrip(' \t') for line in code ]
553
+
554
+ increase = [ int(any(search(re, line) for re in inc_regex))
555
+ for line in code ]
556
+ decrease = [ int(any(search(re, line) for re in dec_regex))
557
+ for line in code ]
558
+
559
+ pretty = []
560
+ level = 0
561
+ for n, line in enumerate(code):
562
+ if line in ('', '\n'):
563
+ pretty.append(line)
564
+ continue
565
+ level -= decrease[n]
566
+ pretty.append("%s%s" % (tab*level, line))
567
+ level += increase[n]
568
+ return pretty
569
+
570
+
571
+ def octave_code(expr, assign_to=None, **settings):
572
+ r"""Converts `expr` to a string of Octave (or Matlab) code.
573
+
574
+ The string uses a subset of the Octave language for Matlab compatibility.
575
+
576
+ Parameters
577
+ ==========
578
+
579
+ expr : Expr
580
+ A SymPy expression to be converted.
581
+ assign_to : optional
582
+ When given, the argument is used as the name of the variable to which
583
+ the expression is assigned. Can be a string, ``Symbol``,
584
+ ``MatrixSymbol``, or ``Indexed`` type. This can be helpful for
585
+ expressions that generate multi-line statements.
586
+ precision : integer, optional
587
+ The precision for numbers such as pi [default=16].
588
+ user_functions : dict, optional
589
+ A dictionary where keys are ``FunctionClass`` instances and values are
590
+ their string representations. Alternatively, the dictionary value can
591
+ be a list of tuples i.e. [(argument_test, cfunction_string)]. See
592
+ below for examples.
593
+ human : bool, optional
594
+ If True, the result is a single string that may contain some constant
595
+ declarations for the number symbols. If False, the same information is
596
+ returned in a tuple of (symbols_to_declare, not_supported_functions,
597
+ code_text). [default=True].
598
+ contract: bool, optional
599
+ If True, ``Indexed`` instances are assumed to obey tensor contraction
600
+ rules and the corresponding nested loops over indices are generated.
601
+ Setting contract=False will not generate loops, instead the user is
602
+ responsible to provide values for the indices in the code.
603
+ [default=True].
604
+ inline: bool, optional
605
+ If True, we try to create single-statement code instead of multiple
606
+ statements. [default=True].
607
+
608
+ Examples
609
+ ========
610
+
611
+ >>> from sympy import octave_code, symbols, sin, pi
612
+ >>> x = symbols('x')
613
+ >>> octave_code(sin(x).series(x).removeO())
614
+ 'x.^5/120 - x.^3/6 + x'
615
+
616
+ >>> from sympy import Rational, ceiling
617
+ >>> x, y, tau = symbols("x, y, tau")
618
+ >>> octave_code((2*tau)**Rational(7, 2))
619
+ '8*sqrt(2)*tau.^(7/2)'
620
+
621
+ Note that element-wise (Hadamard) operations are used by default between
622
+ symbols. This is because its very common in Octave to write "vectorized"
623
+ code. It is harmless if the values are scalars.
624
+
625
+ >>> octave_code(sin(pi*x*y), assign_to="s")
626
+ 's = sin(pi*x.*y);'
627
+
628
+ If you need a matrix product "*" or matrix power "^", you can specify the
629
+ symbol as a ``MatrixSymbol``.
630
+
631
+ >>> from sympy import Symbol, MatrixSymbol
632
+ >>> n = Symbol('n', integer=True, positive=True)
633
+ >>> A = MatrixSymbol('A', n, n)
634
+ >>> octave_code(3*pi*A**3)
635
+ '(3*pi)*A^3'
636
+
637
+ This class uses several rules to decide which symbol to use a product.
638
+ Pure numbers use "*", Symbols use ".*" and MatrixSymbols use "*".
639
+ A HadamardProduct can be used to specify componentwise multiplication ".*"
640
+ of two MatrixSymbols. There is currently there is no easy way to specify
641
+ scalar symbols, so sometimes the code might have some minor cosmetic
642
+ issues. For example, suppose x and y are scalars and A is a Matrix, then
643
+ while a human programmer might write "(x^2*y)*A^3", we generate:
644
+
645
+ >>> octave_code(x**2*y*A**3)
646
+ '(x.^2.*y)*A^3'
647
+
648
+ Matrices are supported using Octave inline notation. When using
649
+ ``assign_to`` with matrices, the name can be specified either as a string
650
+ or as a ``MatrixSymbol``. The dimensions must align in the latter case.
651
+
652
+ >>> from sympy import Matrix, MatrixSymbol
653
+ >>> mat = Matrix([[x**2, sin(x), ceiling(x)]])
654
+ >>> octave_code(mat, assign_to='A')
655
+ 'A = [x.^2 sin(x) ceil(x)];'
656
+
657
+ ``Piecewise`` expressions are implemented with logical masking by default.
658
+ Alternatively, you can pass "inline=False" to use if-else conditionals.
659
+ Note that if the ``Piecewise`` lacks a default term, represented by
660
+ ``(expr, True)`` then an error will be thrown. This is to prevent
661
+ generating an expression that may not evaluate to anything.
662
+
663
+ >>> from sympy import Piecewise
664
+ >>> pw = Piecewise((x + 1, x > 0), (x, True))
665
+ >>> octave_code(pw, assign_to=tau)
666
+ 'tau = ((x > 0).*(x + 1) + (~(x > 0)).*(x));'
667
+
668
+ Note that any expression that can be generated normally can also exist
669
+ inside a Matrix:
670
+
671
+ >>> mat = Matrix([[x**2, pw, sin(x)]])
672
+ >>> octave_code(mat, assign_to='A')
673
+ 'A = [x.^2 ((x > 0).*(x + 1) + (~(x > 0)).*(x)) sin(x)];'
674
+
675
+ Custom printing can be defined for certain types by passing a dictionary of
676
+ "type" : "function" to the ``user_functions`` kwarg. Alternatively, the
677
+ dictionary value can be a list of tuples i.e., [(argument_test,
678
+ cfunction_string)]. This can be used to call a custom Octave function.
679
+
680
+ >>> from sympy import Function
681
+ >>> f = Function('f')
682
+ >>> g = Function('g')
683
+ >>> custom_functions = {
684
+ ... "f": "existing_octave_fcn",
685
+ ... "g": [(lambda x: x.is_Matrix, "my_mat_fcn"),
686
+ ... (lambda x: not x.is_Matrix, "my_fcn")]
687
+ ... }
688
+ >>> mat = Matrix([[1, x]])
689
+ >>> octave_code(f(x) + g(x) + g(mat), user_functions=custom_functions)
690
+ 'existing_octave_fcn(x) + my_fcn(x) + my_mat_fcn([1 x])'
691
+
692
+ Support for loops is provided through ``Indexed`` types. With
693
+ ``contract=True`` these expressions will be turned into loops, whereas
694
+ ``contract=False`` will just print the assignment expression that should be
695
+ looped over:
696
+
697
+ >>> from sympy import Eq, IndexedBase, Idx
698
+ >>> len_y = 5
699
+ >>> y = IndexedBase('y', shape=(len_y,))
700
+ >>> t = IndexedBase('t', shape=(len_y,))
701
+ >>> Dy = IndexedBase('Dy', shape=(len_y-1,))
702
+ >>> i = Idx('i', len_y-1)
703
+ >>> e = Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i]))
704
+ >>> octave_code(e.rhs, assign_to=e.lhs, contract=False)
705
+ 'Dy(i) = (y(i + 1) - y(i))./(t(i + 1) - t(i));'
706
+ """
707
+ return OctaveCodePrinter(settings).doprint(expr, assign_to)
708
+
709
+
710
+ def print_octave_code(expr, **settings):
711
+ """Prints the Octave (or Matlab) representation of the given expression.
712
+
713
+ See `octave_code` for the meaning of the optional arguments.
714
+ """
715
+ print(octave_code(expr, **settings))
lib/python3.12/site-packages/sympy/printing/printer.py ADDED
@@ -0,0 +1,396 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Printing subsystem driver
2
+
3
+ SymPy's printing system works the following way: Any expression can be
4
+ passed to a designated Printer who then is responsible to return an
5
+ adequate representation of that expression.
6
+
7
+ **The basic concept is the following:**
8
+
9
+ 1. Let the object print itself if it knows how.
10
+ 2. Take the best fitting method defined in the printer.
11
+ 3. As fall-back use the emptyPrinter method for the printer.
12
+
13
+ Which Method is Responsible for Printing?
14
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15
+
16
+ The whole printing process is started by calling ``.doprint(expr)`` on the printer
17
+ which you want to use. This method looks for an appropriate method which can
18
+ print the given expression in the given style that the printer defines.
19
+ While looking for the method, it follows these steps:
20
+
21
+ 1. **Let the object print itself if it knows how.**
22
+
23
+ The printer looks for a specific method in every object. The name of that method
24
+ depends on the specific printer and is defined under ``Printer.printmethod``.
25
+ For example, StrPrinter calls ``_sympystr`` and LatexPrinter calls ``_latex``.
26
+ Look at the documentation of the printer that you want to use.
27
+ The name of the method is specified there.
28
+
29
+ This was the original way of doing printing in sympy. Every class had
30
+ its own latex, mathml, str and repr methods, but it turned out that it
31
+ is hard to produce a high quality printer, if all the methods are spread
32
+ out that far. Therefore all printing code was combined into the different
33
+ printers, which works great for built-in SymPy objects, but not that
34
+ good for user defined classes where it is inconvenient to patch the
35
+ printers.
36
+
37
+ 2. **Take the best fitting method defined in the printer.**
38
+
39
+ The printer loops through expr classes (class + its bases), and tries
40
+ to dispatch the work to ``_print_<EXPR_CLASS>``
41
+
42
+ e.g., suppose we have the following class hierarchy::
43
+
44
+ Basic
45
+ |
46
+ Atom
47
+ |
48
+ Number
49
+ |
50
+ Rational
51
+
52
+ then, for ``expr=Rational(...)``, the Printer will try
53
+ to call printer methods in the order as shown in the figure below::
54
+
55
+ p._print(expr)
56
+ |
57
+ |-- p._print_Rational(expr)
58
+ |
59
+ |-- p._print_Number(expr)
60
+ |
61
+ |-- p._print_Atom(expr)
62
+ |
63
+ `-- p._print_Basic(expr)
64
+
65
+ if ``._print_Rational`` method exists in the printer, then it is called,
66
+ and the result is returned back. Otherwise, the printer tries to call
67
+ ``._print_Number`` and so on.
68
+
69
+ 3. **As a fall-back use the emptyPrinter method for the printer.**
70
+
71
+ As fall-back ``self.emptyPrinter`` will be called with the expression. If
72
+ not defined in the Printer subclass this will be the same as ``str(expr)``.
73
+
74
+ .. _printer_example:
75
+
76
+ Example of Custom Printer
77
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
78
+
79
+ In the example below, we have a printer which prints the derivative of a function
80
+ in a shorter form.
81
+
82
+ .. code-block:: python
83
+
84
+ from sympy.core.symbol import Symbol
85
+ from sympy.printing.latex import LatexPrinter, print_latex
86
+ from sympy.core.function import UndefinedFunction, Function
87
+
88
+
89
+ class MyLatexPrinter(LatexPrinter):
90
+ \"\"\"Print derivative of a function of symbols in a shorter form.
91
+ \"\"\"
92
+ def _print_Derivative(self, expr):
93
+ function, *vars = expr.args
94
+ if not isinstance(type(function), UndefinedFunction) or \\
95
+ not all(isinstance(i, Symbol) for i in vars):
96
+ return super()._print_Derivative(expr)
97
+
98
+ # If you want the printer to work correctly for nested
99
+ # expressions then use self._print() instead of str() or latex().
100
+ # See the example of nested modulo below in the custom printing
101
+ # method section.
102
+ return "{}_{{{}}}".format(
103
+ self._print(Symbol(function.func.__name__)),
104
+ ''.join(self._print(i) for i in vars))
105
+
106
+
107
+ def print_my_latex(expr):
108
+ \"\"\" Most of the printers define their own wrappers for print().
109
+ These wrappers usually take printer settings. Our printer does not have
110
+ any settings.
111
+ \"\"\"
112
+ print(MyLatexPrinter().doprint(expr))
113
+
114
+
115
+ y = Symbol("y")
116
+ x = Symbol("x")
117
+ f = Function("f")
118
+ expr = f(x, y).diff(x, y)
119
+
120
+ # Print the expression using the normal latex printer and our custom
121
+ # printer.
122
+ print_latex(expr)
123
+ print_my_latex(expr)
124
+
125
+ The output of the code above is::
126
+
127
+ \\frac{\\partial^{2}}{\\partial x\\partial y} f{\\left(x,y \\right)}
128
+ f_{xy}
129
+
130
+ .. _printer_method_example:
131
+
132
+ Example of Custom Printing Method
133
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
134
+
135
+ In the example below, the latex printing of the modulo operator is modified.
136
+ This is done by overriding the method ``_latex`` of ``Mod``.
137
+
138
+ >>> from sympy import Symbol, Mod, Integer, print_latex
139
+
140
+ >>> # Always use printer._print()
141
+ >>> class ModOp(Mod):
142
+ ... def _latex(self, printer):
143
+ ... a, b = [printer._print(i) for i in self.args]
144
+ ... return r"\\operatorname{Mod}{\\left(%s, %s\\right)}" % (a, b)
145
+
146
+ Comparing the output of our custom operator to the builtin one:
147
+
148
+ >>> x = Symbol('x')
149
+ >>> m = Symbol('m')
150
+ >>> print_latex(Mod(x, m))
151
+ x \\bmod m
152
+ >>> print_latex(ModOp(x, m))
153
+ \\operatorname{Mod}{\\left(x, m\\right)}
154
+
155
+ Common mistakes
156
+ ~~~~~~~~~~~~~~~
157
+ It's important to always use ``self._print(obj)`` to print subcomponents of
158
+ an expression when customizing a printer. Mistakes include:
159
+
160
+ 1. Using ``self.doprint(obj)`` instead:
161
+
162
+ >>> # This example does not work properly, as only the outermost call may use
163
+ >>> # doprint.
164
+ >>> class ModOpModeWrong(Mod):
165
+ ... def _latex(self, printer):
166
+ ... a, b = [printer.doprint(i) for i in self.args]
167
+ ... return r"\\operatorname{Mod}{\\left(%s, %s\\right)}" % (a, b)
168
+
169
+ This fails when the ``mode`` argument is passed to the printer:
170
+
171
+ >>> print_latex(ModOp(x, m), mode='inline') # ok
172
+ $\\operatorname{Mod}{\\left(x, m\\right)}$
173
+ >>> print_latex(ModOpModeWrong(x, m), mode='inline') # bad
174
+ $\\operatorname{Mod}{\\left($x$, $m$\\right)}$
175
+
176
+ 2. Using ``str(obj)`` instead:
177
+
178
+ >>> class ModOpNestedWrong(Mod):
179
+ ... def _latex(self, printer):
180
+ ... a, b = [str(i) for i in self.args]
181
+ ... return r"\\operatorname{Mod}{\\left(%s, %s\\right)}" % (a, b)
182
+
183
+ This fails on nested objects:
184
+
185
+ >>> # Nested modulo.
186
+ >>> print_latex(ModOp(ModOp(x, m), Integer(7))) # ok
187
+ \\operatorname{Mod}{\\left(\\operatorname{Mod}{\\left(x, m\\right)}, 7\\right)}
188
+ >>> print_latex(ModOpNestedWrong(ModOpNestedWrong(x, m), Integer(7))) # bad
189
+ \\operatorname{Mod}{\\left(ModOpNestedWrong(x, m), 7\\right)}
190
+
191
+ 3. Using ``LatexPrinter()._print(obj)`` instead.
192
+
193
+ >>> from sympy.printing.latex import LatexPrinter
194
+ >>> class ModOpSettingsWrong(Mod):
195
+ ... def _latex(self, printer):
196
+ ... a, b = [LatexPrinter()._print(i) for i in self.args]
197
+ ... return r"\\operatorname{Mod}{\\left(%s, %s\\right)}" % (a, b)
198
+
199
+ This causes all the settings to be discarded in the subobjects. As an
200
+ example, the ``full_prec`` setting which shows floats to full precision is
201
+ ignored:
202
+
203
+ >>> from sympy import Float
204
+ >>> print_latex(ModOp(Float(1) * x, m), full_prec=True) # ok
205
+ \\operatorname{Mod}{\\left(1.00000000000000 x, m\\right)}
206
+ >>> print_latex(ModOpSettingsWrong(Float(1) * x, m), full_prec=True) # bad
207
+ \\operatorname{Mod}{\\left(1.0 x, m\\right)}
208
+
209
+ """
210
+
211
+ from __future__ import annotations
212
+ import sys
213
+ from typing import Any, Type
214
+ import inspect
215
+ from contextlib import contextmanager
216
+ from functools import cmp_to_key, update_wrapper
217
+
218
+ from sympy.core.add import Add
219
+ from sympy.core.basic import Basic
220
+
221
+ from sympy.core.function import AppliedUndef, UndefinedFunction, Function
222
+
223
+
224
+
225
+ @contextmanager
226
+ def printer_context(printer, **kwargs):
227
+ original = printer._context.copy()
228
+ try:
229
+ printer._context.update(kwargs)
230
+ yield
231
+ finally:
232
+ printer._context = original
233
+
234
+
235
+ class Printer:
236
+ """ Generic printer
237
+
238
+ Its job is to provide infrastructure for implementing new printers easily.
239
+
240
+ If you want to define your custom Printer or your custom printing method
241
+ for your custom class then see the example above: printer_example_ .
242
+ """
243
+
244
+ _global_settings: dict[str, Any] = {}
245
+
246
+ _default_settings: dict[str, Any] = {}
247
+
248
+ printmethod = None # type: str
249
+
250
+ @classmethod
251
+ def _get_initial_settings(cls):
252
+ settings = cls._default_settings.copy()
253
+ for key, val in cls._global_settings.items():
254
+ if key in cls._default_settings:
255
+ settings[key] = val
256
+ return settings
257
+
258
+ def __init__(self, settings=None):
259
+ self._str = str
260
+
261
+ self._settings = self._get_initial_settings()
262
+ self._context = {} # mutable during printing
263
+
264
+ if settings is not None:
265
+ self._settings.update(settings)
266
+
267
+ if len(self._settings) > len(self._default_settings):
268
+ for key in self._settings:
269
+ if key not in self._default_settings:
270
+ raise TypeError("Unknown setting '%s'." % key)
271
+
272
+ # _print_level is the number of times self._print() was recursively
273
+ # called. See StrPrinter._print_Float() for an example of usage
274
+ self._print_level = 0
275
+
276
+ @classmethod
277
+ def set_global_settings(cls, **settings):
278
+ """Set system-wide printing settings. """
279
+ for key, val in settings.items():
280
+ if val is not None:
281
+ cls._global_settings[key] = val
282
+
283
+ @property
284
+ def order(self):
285
+ if 'order' in self._settings:
286
+ return self._settings['order']
287
+ else:
288
+ raise AttributeError("No order defined.")
289
+
290
+ def doprint(self, expr):
291
+ """Returns printer's representation for expr (as a string)"""
292
+ return self._str(self._print(expr))
293
+
294
+ def _print(self, expr, **kwargs) -> str:
295
+ """Internal dispatcher
296
+
297
+ Tries the following concepts to print an expression:
298
+ 1. Let the object print itself if it knows how.
299
+ 2. Take the best fitting method defined in the printer.
300
+ 3. As fall-back use the emptyPrinter method for the printer.
301
+ """
302
+ self._print_level += 1
303
+ try:
304
+ # If the printer defines a name for a printing method
305
+ # (Printer.printmethod) and the object knows for itself how it
306
+ # should be printed, use that method.
307
+ if self.printmethod and hasattr(expr, self.printmethod):
308
+ if not (isinstance(expr, type) and issubclass(expr, Basic)):
309
+ return getattr(expr, self.printmethod)(self, **kwargs)
310
+
311
+ # See if the class of expr is known, or if one of its super
312
+ # classes is known, and use that print function
313
+ # Exception: ignore the subclasses of Undefined, so that, e.g.,
314
+ # Function('gamma') does not get dispatched to _print_gamma
315
+ classes = type(expr).__mro__
316
+ if AppliedUndef in classes:
317
+ classes = classes[classes.index(AppliedUndef):]
318
+ if UndefinedFunction in classes:
319
+ classes = classes[classes.index(UndefinedFunction):]
320
+ # Another exception: if someone subclasses a known function, e.g.,
321
+ # gamma, and changes the name, then ignore _print_gamma
322
+ if Function in classes:
323
+ i = classes.index(Function)
324
+ classes = tuple(c for c in classes[:i] if \
325
+ c.__name__ == classes[0].__name__ or \
326
+ c.__name__.endswith("Base")) + classes[i:]
327
+ for cls in classes:
328
+ printmethodname = '_print_' + cls.__name__
329
+ printmethod = getattr(self, printmethodname, None)
330
+ if printmethod is not None:
331
+ return printmethod(expr, **kwargs)
332
+ # Unknown object, fall back to the emptyPrinter.
333
+ return self.emptyPrinter(expr)
334
+ finally:
335
+ self._print_level -= 1
336
+
337
+ def emptyPrinter(self, expr):
338
+ return str(expr)
339
+
340
+ def _as_ordered_terms(self, expr, order=None):
341
+ """A compatibility function for ordering terms in Add. """
342
+ order = order or self.order
343
+
344
+ if order == 'old':
345
+ return sorted(Add.make_args(expr), key=cmp_to_key(Basic._compare_pretty))
346
+ elif order == 'none':
347
+ return list(expr.args)
348
+ else:
349
+ return expr.as_ordered_terms(order=order)
350
+
351
+
352
+ class _PrintFunction:
353
+ """
354
+ Function wrapper to replace ``**settings`` in the signature with printer defaults
355
+ """
356
+ def __init__(self, f, print_cls: Type[Printer]):
357
+ # find all the non-setting arguments
358
+ params = list(inspect.signature(f).parameters.values())
359
+ assert params.pop(-1).kind == inspect.Parameter.VAR_KEYWORD
360
+ self.__other_params = params
361
+
362
+ self.__print_cls = print_cls
363
+ update_wrapper(self, f)
364
+
365
+ def __reduce__(self):
366
+ # Since this is used as a decorator, it replaces the original function.
367
+ # The default pickling will try to pickle self.__wrapped__ and fail
368
+ # because the wrapped function can't be retrieved by name.
369
+ return self.__wrapped__.__qualname__
370
+
371
+ def __call__(self, *args, **kwargs):
372
+ return self.__wrapped__(*args, **kwargs)
373
+
374
+ @property
375
+ def __signature__(self) -> inspect.Signature:
376
+ settings = self.__print_cls._get_initial_settings()
377
+ return inspect.Signature(
378
+ parameters=self.__other_params + [
379
+ inspect.Parameter(k, inspect.Parameter.KEYWORD_ONLY, default=v)
380
+ for k, v in settings.items()
381
+ ],
382
+ return_annotation=self.__wrapped__.__annotations__.get('return', inspect.Signature.empty) # type:ignore
383
+ )
384
+
385
+
386
+ def print_function(print_cls):
387
+ """ A decorator to replace kwargs with the printer settings in __signature__ """
388
+ def decorator(f):
389
+ if sys.version_info < (3, 9):
390
+ # We have to create a subclass so that `help` actually shows the docstring in older Python versions.
391
+ # IPython and Sphinx do not need this, only a raw Python console.
392
+ cls = type(f'{f.__qualname__}_PrintFunction', (_PrintFunction,), {"__doc__": f.__doc__})
393
+ else:
394
+ cls = _PrintFunction
395
+ return cls(f, print_cls)
396
+ return decorator
lib/python3.12/site-packages/sympy/printing/rcode.py ADDED
@@ -0,0 +1,405 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ R code printer
3
+
4
+ The RCodePrinter converts single SymPy expressions into single R expressions,
5
+ using the functions defined in math.h where possible.
6
+
7
+
8
+
9
+ """
10
+
11
+ from __future__ import annotations
12
+ from typing import Any
13
+
14
+ from sympy.core.numbers import equal_valued
15
+ from sympy.printing.codeprinter import CodePrinter
16
+ from sympy.printing.precedence import precedence, PRECEDENCE
17
+ from sympy.sets.fancysets import Range
18
+
19
+ # dictionary mapping SymPy function to (argument_conditions, C_function).
20
+ # Used in RCodePrinter._print_Function(self)
21
+ known_functions = {
22
+ #"Abs": [(lambda x: not x.is_integer, "fabs")],
23
+ "Abs": "abs",
24
+ "sin": "sin",
25
+ "cos": "cos",
26
+ "tan": "tan",
27
+ "asin": "asin",
28
+ "acos": "acos",
29
+ "atan": "atan",
30
+ "atan2": "atan2",
31
+ "exp": "exp",
32
+ "log": "log",
33
+ "erf": "erf",
34
+ "sinh": "sinh",
35
+ "cosh": "cosh",
36
+ "tanh": "tanh",
37
+ "asinh": "asinh",
38
+ "acosh": "acosh",
39
+ "atanh": "atanh",
40
+ "floor": "floor",
41
+ "ceiling": "ceiling",
42
+ "sign": "sign",
43
+ "Max": "max",
44
+ "Min": "min",
45
+ "factorial": "factorial",
46
+ "gamma": "gamma",
47
+ "digamma": "digamma",
48
+ "trigamma": "trigamma",
49
+ "beta": "beta",
50
+ "sqrt": "sqrt", # To enable automatic rewrite
51
+ }
52
+
53
+ # These are the core reserved words in the R language. Taken from:
54
+ # https://cran.r-project.org/doc/manuals/r-release/R-lang.html#Reserved-words
55
+
56
+ reserved_words = ['if',
57
+ 'else',
58
+ 'repeat',
59
+ 'while',
60
+ 'function',
61
+ 'for',
62
+ 'in',
63
+ 'next',
64
+ 'break',
65
+ 'TRUE',
66
+ 'FALSE',
67
+ 'NULL',
68
+ 'Inf',
69
+ 'NaN',
70
+ 'NA',
71
+ 'NA_integer_',
72
+ 'NA_real_',
73
+ 'NA_complex_',
74
+ 'NA_character_',
75
+ 'volatile']
76
+
77
+
78
+ class RCodePrinter(CodePrinter):
79
+ """A printer to convert SymPy expressions to strings of R code"""
80
+ printmethod = "_rcode"
81
+ language = "R"
82
+
83
+ _default_settings: dict[str, Any] = dict(CodePrinter._default_settings, **{
84
+ 'precision': 15,
85
+ 'user_functions': {},
86
+ 'contract': True,
87
+ 'dereference': set(),
88
+ })
89
+ _operators = {
90
+ 'and': '&',
91
+ 'or': '|',
92
+ 'not': '!',
93
+ }
94
+
95
+ _relationals: dict[str, str] = {}
96
+
97
+ def __init__(self, settings={}):
98
+ CodePrinter.__init__(self, settings)
99
+ self.known_functions = dict(known_functions)
100
+ userfuncs = settings.get('user_functions', {})
101
+ self.known_functions.update(userfuncs)
102
+ self._dereference = set(settings.get('dereference', []))
103
+ self.reserved_words = set(reserved_words)
104
+
105
+ def _rate_index_position(self, p):
106
+ return p*5
107
+
108
+ def _get_statement(self, codestring):
109
+ return "%s;" % codestring
110
+
111
+ def _get_comment(self, text):
112
+ return "// {}".format(text)
113
+
114
+ def _declare_number_const(self, name, value):
115
+ return "{} = {};".format(name, value)
116
+
117
+ def _format_code(self, lines):
118
+ return self.indent_code(lines)
119
+
120
+ def _traverse_matrix_indices(self, mat):
121
+ rows, cols = mat.shape
122
+ return ((i, j) for i in range(rows) for j in range(cols))
123
+
124
+ def _get_loop_opening_ending(self, indices):
125
+ """Returns a tuple (open_lines, close_lines) containing lists of codelines
126
+ """
127
+ open_lines = []
128
+ close_lines = []
129
+ loopstart = "for (%(var)s in %(start)s:%(end)s){"
130
+ for i in indices:
131
+ # R arrays start at 1 and end at dimension
132
+ open_lines.append(loopstart % {
133
+ 'var': self._print(i.label),
134
+ 'start': self._print(i.lower+1),
135
+ 'end': self._print(i.upper + 1)})
136
+ close_lines.append("}")
137
+ return open_lines, close_lines
138
+
139
+ def _print_Pow(self, expr):
140
+ if "Pow" in self.known_functions:
141
+ return self._print_Function(expr)
142
+ PREC = precedence(expr)
143
+ if equal_valued(expr.exp, -1):
144
+ return '1.0/%s' % (self.parenthesize(expr.base, PREC))
145
+ elif equal_valued(expr.exp, 0.5):
146
+ return 'sqrt(%s)' % self._print(expr.base)
147
+ else:
148
+ return '%s^%s' % (self.parenthesize(expr.base, PREC),
149
+ self.parenthesize(expr.exp, PREC))
150
+
151
+
152
+ def _print_Rational(self, expr):
153
+ p, q = int(expr.p), int(expr.q)
154
+ return '%d.0/%d.0' % (p, q)
155
+
156
+ def _print_Indexed(self, expr):
157
+ inds = [ self._print(i) for i in expr.indices ]
158
+ return "%s[%s]" % (self._print(expr.base.label), ", ".join(inds))
159
+
160
+ def _print_Idx(self, expr):
161
+ return self._print(expr.label)
162
+
163
+ def _print_Exp1(self, expr):
164
+ return "exp(1)"
165
+
166
+ def _print_Pi(self, expr):
167
+ return 'pi'
168
+
169
+ def _print_Infinity(self, expr):
170
+ return 'Inf'
171
+
172
+ def _print_NegativeInfinity(self, expr):
173
+ return '-Inf'
174
+
175
+ def _print_Assignment(self, expr):
176
+ from sympy.codegen.ast import Assignment
177
+
178
+ from sympy.matrices.expressions.matexpr import MatrixSymbol
179
+ from sympy.tensor.indexed import IndexedBase
180
+ lhs = expr.lhs
181
+ rhs = expr.rhs
182
+ # We special case assignments that take multiple lines
183
+ #if isinstance(expr.rhs, Piecewise):
184
+ # from sympy.functions.elementary.piecewise import Piecewise
185
+ # # Here we modify Piecewise so each expression is now
186
+ # # an Assignment, and then continue on the print.
187
+ # expressions = []
188
+ # conditions = []
189
+ # for (e, c) in rhs.args:
190
+ # expressions.append(Assignment(lhs, e))
191
+ # conditions.append(c)
192
+ # temp = Piecewise(*zip(expressions, conditions))
193
+ # return self._print(temp)
194
+ #elif isinstance(lhs, MatrixSymbol):
195
+ if isinstance(lhs, MatrixSymbol):
196
+ # Here we form an Assignment for each element in the array,
197
+ # printing each one.
198
+ lines = []
199
+ for (i, j) in self._traverse_matrix_indices(lhs):
200
+ temp = Assignment(lhs[i, j], rhs[i, j])
201
+ code0 = self._print(temp)
202
+ lines.append(code0)
203
+ return "\n".join(lines)
204
+ elif self._settings["contract"] and (lhs.has(IndexedBase) or
205
+ rhs.has(IndexedBase)):
206
+ # Here we check if there is looping to be done, and if so
207
+ # print the required loops.
208
+ return self._doprint_loops(rhs, lhs)
209
+ else:
210
+ lhs_code = self._print(lhs)
211
+ rhs_code = self._print(rhs)
212
+ return self._get_statement("%s = %s" % (lhs_code, rhs_code))
213
+
214
+ def _print_Piecewise(self, expr):
215
+ # This method is called only for inline if constructs
216
+ # Top level piecewise is handled in doprint()
217
+ if expr.args[-1].cond == True:
218
+ last_line = "%s" % self._print(expr.args[-1].expr)
219
+ else:
220
+ last_line = "ifelse(%s,%s,NA)" % (self._print(expr.args[-1].cond), self._print(expr.args[-1].expr))
221
+ code=last_line
222
+ for e, c in reversed(expr.args[:-1]):
223
+ code= "ifelse(%s,%s," % (self._print(c), self._print(e))+code+")"
224
+ return(code)
225
+
226
+ def _print_ITE(self, expr):
227
+ from sympy.functions import Piecewise
228
+ return self._print(expr.rewrite(Piecewise))
229
+
230
+ def _print_MatrixElement(self, expr):
231
+ return "{}[{}]".format(self.parenthesize(expr.parent, PRECEDENCE["Atom"],
232
+ strict=True), expr.j + expr.i*expr.parent.shape[1])
233
+
234
+ def _print_Symbol(self, expr):
235
+ name = super()._print_Symbol(expr)
236
+ if expr in self._dereference:
237
+ return '(*{})'.format(name)
238
+ else:
239
+ return name
240
+
241
+ def _print_Relational(self, expr):
242
+ lhs_code = self._print(expr.lhs)
243
+ rhs_code = self._print(expr.rhs)
244
+ op = expr.rel_op
245
+ return "{} {} {}".format(lhs_code, op, rhs_code)
246
+
247
+ def _print_AugmentedAssignment(self, expr):
248
+ lhs_code = self._print(expr.lhs)
249
+ op = expr.op
250
+ rhs_code = self._print(expr.rhs)
251
+ return "{} {} {};".format(lhs_code, op, rhs_code)
252
+
253
+ def _print_For(self, expr):
254
+ target = self._print(expr.target)
255
+ if isinstance(expr.iterable, Range):
256
+ start, stop, step = expr.iterable.args
257
+ else:
258
+ raise NotImplementedError("Only iterable currently supported is Range")
259
+ body = self._print(expr.body)
260
+ return 'for({target} in seq(from={start}, to={stop}, by={step}){{\n{body}\n}}'.format(target=target, start=start,
261
+ stop=stop-1, step=step, body=body)
262
+
263
+
264
+ def indent_code(self, code):
265
+ """Accepts a string of code or a list of code lines"""
266
+
267
+ if isinstance(code, str):
268
+ code_lines = self.indent_code(code.splitlines(True))
269
+ return ''.join(code_lines)
270
+
271
+ tab = " "
272
+ inc_token = ('{', '(', '{\n', '(\n')
273
+ dec_token = ('}', ')')
274
+
275
+ code = [ line.lstrip(' \t') for line in code ]
276
+
277
+ increase = [ int(any(map(line.endswith, inc_token))) for line in code ]
278
+ decrease = [ int(any(map(line.startswith, dec_token)))
279
+ for line in code ]
280
+
281
+ pretty = []
282
+ level = 0
283
+ for n, line in enumerate(code):
284
+ if line in ('', '\n'):
285
+ pretty.append(line)
286
+ continue
287
+ level -= decrease[n]
288
+ pretty.append("%s%s" % (tab*level, line))
289
+ level += increase[n]
290
+ return pretty
291
+
292
+
293
+ def rcode(expr, assign_to=None, **settings):
294
+ """Converts an expr to a string of r code
295
+
296
+ Parameters
297
+ ==========
298
+
299
+ expr : Expr
300
+ A SymPy expression to be converted.
301
+ assign_to : optional
302
+ When given, the argument is used as the name of the variable to which
303
+ the expression is assigned. Can be a string, ``Symbol``,
304
+ ``MatrixSymbol``, or ``Indexed`` type. This is helpful in case of
305
+ line-wrapping, or for expressions that generate multi-line statements.
306
+ precision : integer, optional
307
+ The precision for numbers such as pi [default=15].
308
+ user_functions : dict, optional
309
+ A dictionary where the keys are string representations of either
310
+ ``FunctionClass`` or ``UndefinedFunction`` instances and the values
311
+ are their desired R string representations. Alternatively, the
312
+ dictionary value can be a list of tuples i.e. [(argument_test,
313
+ rfunction_string)] or [(argument_test, rfunction_formater)]. See below
314
+ for examples.
315
+ human : bool, optional
316
+ If True, the result is a single string that may contain some constant
317
+ declarations for the number symbols. If False, the same information is
318
+ returned in a tuple of (symbols_to_declare, not_supported_functions,
319
+ code_text). [default=True].
320
+ contract: bool, optional
321
+ If True, ``Indexed`` instances are assumed to obey tensor contraction
322
+ rules and the corresponding nested loops over indices are generated.
323
+ Setting contract=False will not generate loops, instead the user is
324
+ responsible to provide values for the indices in the code.
325
+ [default=True].
326
+
327
+ Examples
328
+ ========
329
+
330
+ >>> from sympy import rcode, symbols, Rational, sin, ceiling, Abs, Function
331
+ >>> x, tau = symbols("x, tau")
332
+ >>> rcode((2*tau)**Rational(7, 2))
333
+ '8*sqrt(2)*tau^(7.0/2.0)'
334
+ >>> rcode(sin(x), assign_to="s")
335
+ 's = sin(x);'
336
+
337
+ Simple custom printing can be defined for certain types by passing a
338
+ dictionary of {"type" : "function"} to the ``user_functions`` kwarg.
339
+ Alternatively, the dictionary value can be a list of tuples i.e.
340
+ [(argument_test, cfunction_string)].
341
+
342
+ >>> custom_functions = {
343
+ ... "ceiling": "CEIL",
344
+ ... "Abs": [(lambda x: not x.is_integer, "fabs"),
345
+ ... (lambda x: x.is_integer, "ABS")],
346
+ ... "func": "f"
347
+ ... }
348
+ >>> func = Function('func')
349
+ >>> rcode(func(Abs(x) + ceiling(x)), user_functions=custom_functions)
350
+ 'f(fabs(x) + CEIL(x))'
351
+
352
+ or if the R-function takes a subset of the original arguments:
353
+
354
+ >>> rcode(2**x + 3**x, user_functions={'Pow': [
355
+ ... (lambda b, e: b == 2, lambda b, e: 'exp2(%s)' % e),
356
+ ... (lambda b, e: b != 2, 'pow')]})
357
+ 'exp2(x) + pow(3, x)'
358
+
359
+ ``Piecewise`` expressions are converted into conditionals. If an
360
+ ``assign_to`` variable is provided an if statement is created, otherwise
361
+ the ternary operator is used. Note that if the ``Piecewise`` lacks a
362
+ default term, represented by ``(expr, True)`` then an error will be thrown.
363
+ This is to prevent generating an expression that may not evaluate to
364
+ anything.
365
+
366
+ >>> from sympy import Piecewise
367
+ >>> expr = Piecewise((x + 1, x > 0), (x, True))
368
+ >>> print(rcode(expr, assign_to=tau))
369
+ tau = ifelse(x > 0,x + 1,x);
370
+
371
+ Support for loops is provided through ``Indexed`` types. With
372
+ ``contract=True`` these expressions will be turned into loops, whereas
373
+ ``contract=False`` will just print the assignment expression that should be
374
+ looped over:
375
+
376
+ >>> from sympy import Eq, IndexedBase, Idx
377
+ >>> len_y = 5
378
+ >>> y = IndexedBase('y', shape=(len_y,))
379
+ >>> t = IndexedBase('t', shape=(len_y,))
380
+ >>> Dy = IndexedBase('Dy', shape=(len_y-1,))
381
+ >>> i = Idx('i', len_y-1)
382
+ >>> e=Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i]))
383
+ >>> rcode(e.rhs, assign_to=e.lhs, contract=False)
384
+ 'Dy[i] = (y[i + 1] - y[i])/(t[i + 1] - t[i]);'
385
+
386
+ Matrices are also supported, but a ``MatrixSymbol`` of the same dimensions
387
+ must be provided to ``assign_to``. Note that any expression that can be
388
+ generated normally can also exist inside a Matrix:
389
+
390
+ >>> from sympy import Matrix, MatrixSymbol
391
+ >>> mat = Matrix([x**2, Piecewise((x + 1, x > 0), (x, True)), sin(x)])
392
+ >>> A = MatrixSymbol('A', 3, 1)
393
+ >>> print(rcode(mat, A))
394
+ A[0] = x^2;
395
+ A[1] = ifelse(x > 0,x + 1,x);
396
+ A[2] = sin(x);
397
+
398
+ """
399
+
400
+ return RCodePrinter(settings).doprint(expr, assign_to)
401
+
402
+
403
+ def print_rcode(expr, **settings):
404
+ """Prints R representation of the given expression."""
405
+ print(rcode(expr, **settings))