MTerryJack commited on
Commit
45a9216
·
verified ·
1 Parent(s): 9896666

Add files using upload-large-folder tool

Browse files
.venv/lib/python3.13/site-packages/onnxruntime-1.24.1.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ uv
.venv/lib/python3.13/site-packages/onnxruntime-1.24.1.dist-info/METADATA ADDED
@@ -0,0 +1,216 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.4
2
+ Name: onnxruntime
3
+ Version: 1.24.1
4
+ Summary: ONNX Runtime is a runtime accelerator for Machine Learning models
5
+ Home-page: https://onnxruntime.ai
6
+ Download-URL: https://github.com/microsoft/onnxruntime/tags
7
+ Author: Microsoft Corporation
8
+ Author-email: onnxruntime@microsoft.com
9
+ License: MIT License
10
+ Keywords: onnx machine learning
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: POSIX :: Linux
15
+ Classifier: Operating System :: Microsoft :: Windows
16
+ Classifier: Operating System :: MacOS
17
+ Classifier: Topic :: Scientific/Engineering
18
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Classifier: Topic :: Software Development
21
+ Classifier: Topic :: Software Development :: Libraries
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Classifier: Programming Language :: Python
24
+ Classifier: Programming Language :: Python :: 3 :: Only
25
+ Classifier: Programming Language :: Python :: 3.11
26
+ Classifier: Programming Language :: Python :: 3.12
27
+ Classifier: Programming Language :: Python :: 3.13
28
+ Classifier: Programming Language :: Python :: 3.14
29
+ Requires-Python: >=3.10
30
+ Requires-Dist: flatbuffers
31
+ Requires-Dist: numpy>=1.21.6
32
+ Requires-Dist: packaging
33
+ Requires-Dist: protobuf
34
+ Requires-Dist: sympy
35
+ Dynamic: author
36
+ Dynamic: author-email
37
+ Dynamic: classifier
38
+ Dynamic: description
39
+ Dynamic: download-url
40
+ Dynamic: home-page
41
+ Dynamic: keywords
42
+ Dynamic: license
43
+ Dynamic: requires-dist
44
+ Dynamic: requires-python
45
+ Dynamic: summary
46
+
47
+ ONNX Runtime
48
+ ============
49
+
50
+ ONNX Runtime is a performance-focused scoring engine for Open Neural Network Exchange (ONNX) models.
51
+ For more information on ONNX Runtime, please see `aka.ms/onnxruntime <https://aka.ms/onnxruntime/>`_ or the `Github project <https://github.com/microsoft/onnxruntime/>`_.
52
+
53
+
54
+ Changes
55
+ -------
56
+
57
+ 1.24.1
58
+ ^^^^^^
59
+
60
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.24.1
61
+
62
+ 1.23.0
63
+ ^^^^^^
64
+
65
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.23.0
66
+
67
+ 1.22.0
68
+ ^^^^^^
69
+
70
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.22.0
71
+
72
+ 1.21.0
73
+ ^^^^^^
74
+
75
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.21.0
76
+
77
+ 1.20.0
78
+ ^^^^^^
79
+
80
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.20.0
81
+
82
+ 1.19.0
83
+ ^^^^^^
84
+
85
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.19.0
86
+
87
+ 1.18.0
88
+ ^^^^^^
89
+
90
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.18.0
91
+
92
+ 1.17.0
93
+ ^^^^^^
94
+
95
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.17.0
96
+
97
+ 1.16.0
98
+ ^^^^^^
99
+
100
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.16.0
101
+
102
+ 1.15.0
103
+ ^^^^^^
104
+
105
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.15.0
106
+
107
+ 1.14.0
108
+ ^^^^^^
109
+
110
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.14.0
111
+
112
+ 1.13.0
113
+ ^^^^^^
114
+
115
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.13.0
116
+
117
+ 1.12.0
118
+ ^^^^^^
119
+
120
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.12.0
121
+
122
+ 1.11.0
123
+ ^^^^^^
124
+
125
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.11.0
126
+
127
+ 1.10.0
128
+ ^^^^^^
129
+
130
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.10.0
131
+
132
+ 1.9.0
133
+ ^^^^^
134
+
135
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.9.0
136
+
137
+ 1.8.2
138
+ ^^^^^
139
+
140
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.8.2
141
+
142
+ 1.8.1
143
+ ^^^^^
144
+
145
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.8.1
146
+
147
+ 1.8.0
148
+ ^^^^^
149
+
150
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.8.0
151
+
152
+ 1.7.0
153
+ ^^^^^
154
+
155
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.7.0
156
+
157
+ 1.6.0
158
+ ^^^^^
159
+
160
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.6.0
161
+
162
+ 1.5.3
163
+ ^^^^^
164
+
165
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.5.3
166
+
167
+ 1.5.2
168
+ ^^^^^
169
+
170
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.5.2
171
+
172
+ 1.5.1
173
+ ^^^^^
174
+
175
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.5.1
176
+
177
+
178
+ 1.4.0
179
+ ^^^^^
180
+
181
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.4.0
182
+
183
+ 1.3.1
184
+ ^^^^^
185
+
186
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.3.1
187
+
188
+ 1.3.0
189
+ ^^^^^
190
+
191
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.3.0
192
+
193
+ 1.2.0
194
+ ^^^^^
195
+
196
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.2.0
197
+
198
+ 1.1.0
199
+ ^^^^^
200
+
201
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.1.0
202
+
203
+ 1.0.0
204
+ ^^^^^
205
+
206
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.0.0
207
+
208
+ 0.5.0
209
+ ^^^^^
210
+
211
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v0.5.0
212
+
213
+ 0.4.0
214
+ ^^^^^
215
+
216
+ Release Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v0.4.0
.venv/lib/python3.13/site-packages/onnxruntime-1.24.1.dist-info/REQUESTED ADDED
File without changes
.venv/lib/python3.13/site-packages/onnxruntime-1.24.1.dist-info/WHEEL ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (78.1.1)
3
+ Root-Is-Purelib: false
4
+ Tag: cp313-cp313-macosx_14_0_arm64
5
+ Generator: delocate 0.13.0
6
+
.venv/lib/python3.13/site-packages/pillow-12.1.1.dist-info/RECORD ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ PIL/.dylibs/libXau.6.dylib,sha256=nQNsVba7r1Hf9j6VseTE0wbv8AJvbJJLfTnE57UgW_I,70048
2
+ PIL/.dylibs/libavif.16.3.0.dylib,sha256=4cZljlxPfQW9gaz65FMKe-prEnHaMjQXyV6j_gM7qAA,2983120
3
+ PIL/.dylibs/libbrotlicommon.1.2.0.dylib,sha256=hRywsOFrlwqmtT-_NtqmKeYvEOOpBlN6x3LMfJDYImU,201184
4
+ PIL/.dylibs/libbrotlidec.1.2.0.dylib,sha256=gAdn1-QeiaM6nOjUvNLiTwHL1GNNG1bRmaTec9DjT5k,104560
5
+ PIL/.dylibs/libfreetype.6.dylib,sha256=VhPqCWIaAjaBNexBQpDUsq-Cus-r2IQER5VAuOzRyMg,1143856
6
+ PIL/.dylibs/libharfbuzz.0.dylib,sha256=0iKmnPcd-gN5C4r-dX-73ko7dOxjM4Ji97O53z1I7mA,1779344
7
+ PIL/.dylibs/libjpeg.62.4.0.dylib,sha256=Fw3hf4BpBUzue53v5pR4BSBhyDBorHOH8P5WgwMO_QQ,653536
8
+ PIL/.dylibs/liblcms2.2.dylib,sha256=4ZedQZXRu_W41ptCeasVbRRUblNll6UJQ0HseHvusY8,524672
9
+ PIL/.dylibs/liblzma.5.dylib,sha256=sHGyixFEX0fbSFGxhSQUh8Zdgzc5YogeBgZ1JtwbtP4,325120
10
+ PIL/.dylibs/libopenjp2.2.5.4.dylib,sha256=8pbJacrtOUY0Y8ryJSz0yFGQMC0HlTKEWqTkzU3Tjik,666432
11
+ PIL/.dylibs/libpng16.16.dylib,sha256=GT1Et1gmboSSlVeNlXc6qO6KpGmtFXoc_ebGHhtEizA,344368
12
+ PIL/.dylibs/libsharpyuv.0.dylib,sha256=jSgehjdhBEKurMj0wkcWZIlZfrdCGpSpMAU61Y_-PqI,86240
13
+ PIL/.dylibs/libtiff.6.dylib,sha256=uJrxnUQYeLN22SXjr0vdTEsIVWsT_zaba_VBRwQ8gZc,770432
14
+ PIL/.dylibs/libwebp.7.dylib,sha256=INkaleVsCQanf2TWSVafPc_91bEE7QXdEO6fCHfewsk,515712
15
+ PIL/.dylibs/libwebpdemux.2.dylib,sha256=VuLKpYe2YZn6ko9ZjfIyEF0XglvAu5pqK5a8qCfBcTI,69904
16
+ PIL/.dylibs/libwebpmux.3.dylib,sha256=1AaRf97STlBUw4GZ5rzBguBPjvfvr2JPlLal2V4mdJE,106368
17
+ PIL/.dylibs/libxcb.1.1.0.dylib,sha256=blpsZKejMqA0kMAV_qg4Grwgm8LgwmVkx4XBJGipxTk,277664
18
+ PIL/.dylibs/libz.1.3.1.zlib-ng.dylib,sha256=2YUI2M3Hjgnt6W3OBSVE5AikV_5lElzLU-5Y8NP1OhY,177344
19
+ PIL/AvifImagePlugin.py,sha256=sHaYxONtVEDZ24y8Ad7qRlixD4iIPC2ipH1W79-uPbE,9030
20
+ PIL/BdfFontFile.py,sha256=PhlZfIRmEfmorbhZZeSM5eebGo1Ei7fL-lR9XlfTZZA,3285
21
+ PIL/BlpImagePlugin.py,sha256=tQxeJbpiyvp3-zSLjeWAQr8YdLS_HoKWmuLDQwRQl4w,16568
22
+ PIL/BmpImagePlugin.py,sha256=64PB3YE8kEL8QrAuUMlWoEaByYJUTYV6OQA254Uj4Lc,19925
23
+ PIL/BufrStubImagePlugin.py,sha256=gMbELNwEghE_IM2Ov1NT4jy-96CTpEvyuj_mXmckL-c,1765
24
+ PIL/ContainerIO.py,sha256=wkBqL2GDAb5fh3wrtfTGUfqioJipCl-lg2GxbjQrTZw,4604
25
+ PIL/CurImagePlugin.py,sha256=-WEsgwQbA9rQzXB0HG0LK1V_qbuwHosPZ0T2IjfN8r0,1791
26
+ PIL/DcxImagePlugin.py,sha256=OlCv6yDI0LLZNbuUI7s69FI1DuArPyGxo3YCzQ1n8Hg,2180
27
+ PIL/DdsImagePlugin.py,sha256=JRhDGFhKXvolAiD_X4_nYQ3DARogu2hmE2AhZuGc02Q,18931
28
+ PIL/EpsImagePlugin.py,sha256=jnT9Y01VEOdnU0Q3ZncyeTM81WYPpPABXT2BOgKW-mY,16626
29
+ PIL/ExifTags.py,sha256=zW6kVikCosiyoCo7J7R62evD3hoxjKPchnVh8po7CZc,9931
30
+ PIL/FitsImagePlugin.py,sha256=-oDJnAH113CK5qPvwz9lL81fkV1gla_tNfqLcq8zKgo,4644
31
+ PIL/FliImagePlugin.py,sha256=4zxH8IXBX9DGi6dJRM6Y5NMdbA1d99x696mcGZHxHzI,4929
32
+ PIL/FontFile.py,sha256=St7MxO5Q-oakCLWn3ZrgrtaT3wSsmAarxm8AU-G8Moc,3577
33
+ PIL/FpxImagePlugin.py,sha256=NnHQj6Ze1LUXqIOi7WHCKBEBftAkJZJJ1quHEpZaE14,7363
34
+ PIL/FtexImagePlugin.py,sha256=ZS0WqBHtItNoi0W52A4REOGrDIfh40dCGDLruaXLRFE,3570
35
+ PIL/GbrImagePlugin.py,sha256=DYyvhekFB1sOQLEWPwYbf0CEfGdgdax1ci-3DuSeIgQ,3053
36
+ PIL/GdImageFile.py,sha256=LP4Uxv3Y2ivGZIyOVuGJarDDVS7zK6F1Q6SNl4wyGuQ,2788
37
+ PIL/GifImagePlugin.py,sha256=Bu5YTg7YwLgJIxcE0RiDGHIGTApmGZxXvWQn0dPs674,42304
38
+ PIL/GimpGradientFile.py,sha256=gqqUkDbKVFCtBxt5VAhPS0HtLZDYFI6KWEaUhhTNNE8,3982
39
+ PIL/GimpPaletteFile.py,sha256=hIHQ9LJ5ri0hy1e_vZYeD-n67UWdhEDlKc4vDxgaUdg,1860
40
+ PIL/GribStubImagePlugin.py,sha256=C9YNx1hxBgYvRFzcs1ZG-srEG_3A3DIWBgk1j-nbl8I,1794
41
+ PIL/Hdf5StubImagePlugin.py,sha256=4JirZFt94qjH73NsWJi83OP-cEUMKDTsIhWKrdNGvuc,1776
42
+ PIL/IcnsImagePlugin.py,sha256=l3JdNkYQVAMeiGpK_tem2vtDD11KtAJ64wQGsA0E-JQ,12440
43
+ PIL/IcoImagePlugin.py,sha256=UGzIDlQ02ZB-VJEsoyI7YWmTx26ZiB2EHJZ1qvB28JQ,13103
44
+ PIL/ImImagePlugin.py,sha256=8sBOAy7xlqP722sXWhnJn4VoBhTBzbZQTtfW_XsWefU,11602
45
+ PIL/Image.py,sha256=Pl7NzD6IAHSZAeYcgQi9PEkGPTukRPoLYrDBivAiAH8,148899
46
+ PIL/ImageChops.py,sha256=GEjlymcoDtA5OOeIxQVIX96BD-s6AXhb7TmSLYn2tUg,7946
47
+ PIL/ImageCms.py,sha256=IuCm3gXKpb5Eu1kn-TB8cD9XJLZEa8fpkEjzVqAIKNk,40676
48
+ PIL/ImageColor.py,sha256=IGA9C2umeED_EzS2Cvj6KsU0VutC9RstWIYPe8uDsVk,9441
49
+ PIL/ImageDraw.py,sha256=FMn0AK_gxxJBYB8afOGF2FUP2KJPFvUf3UZp_KrJz7A,36287
50
+ PIL/ImageDraw2.py,sha256=pdVMW7bVw3KwhXvRZh28Md4y-2xFfuo5fHcDnaYqVK4,7227
51
+ PIL/ImageEnhance.py,sha256=4Elhz_lyyxLmx0GkSHrwOAmNJ2TkqVQPHejzGihZUMI,3627
52
+ PIL/ImageFile.py,sha256=W5_QULZWeY7Kqz04cLujVu0kSBnKZu7liLCCqoXO-GM,29972
53
+ PIL/ImageFilter.py,sha256=MO1MBrbXDiX2IAGESdGm_0087bwmSZ_14ecAj28ojCY,18729
54
+ PIL/ImageFont.py,sha256=tsIwpnCjWl57_sMcAFTt84Ikpf14EPrW8_IJ9XQ7z7E,63253
55
+ PIL/ImageGrab.py,sha256=oaeBn7UHjtxKPXJ9OSXPUt3cG1I0j-4yesbfvh0p_TY,7750
56
+ PIL/ImageMath.py,sha256=RQl6cRXGuszba4KwtbIudin_8U65shpWrajr9gTn1rw,10369
57
+ PIL/ImageMode.py,sha256=aaZVHAiCEanOA2K1jN3DlW3NPKa8Dm5nIXTXErzyFms,2395
58
+ PIL/ImageMorph.py,sha256=otf5f9A-Y4Aosfl1E4YWEVatgDBInGp6xWBJfAJ0NRs,10356
59
+ PIL/ImageOps.py,sha256=bIcQFK_MtovfNSYTcOesp4So9OgsGrwt3cGsB7xlGRM,25567
60
+ PIL/ImagePalette.py,sha256=uPP_qWWSTWitlv4WdXucZF4n-2ZNsHjg4H36g-JpuxU,9092
61
+ PIL/ImagePath.py,sha256=5yUG5XCUil1KKTTA_8PgGhcmg-mnue-GK0FwTBlhjw4,371
62
+ PIL/ImageQt.py,sha256=PTt5TPyngWL-Vuvx_bwnH17EOBe3tE7l4huVmvGQP5Y,6684
63
+ PIL/ImageSequence.py,sha256=Mphgkr79scmYBgmi9ZguhDfVwHvpLSX5uZVHDZlrn0I,2253
64
+ PIL/ImageShow.py,sha256=Ju0_Db2B4_n3yKJV9sDsF7_HAgciEdXlq6I1Eiw1YTo,10106
65
+ PIL/ImageStat.py,sha256=FVTiYWGCciPW1QD61b7DYZlcDqR0dS6hsLjq-gcKcG4,5495
66
+ PIL/ImageText.py,sha256=E3EEmIlP1FG-zgy9YddETN1HKSIXaRJSrPJIC67aAxY,12120
67
+ PIL/ImageTk.py,sha256=b5SntckGXs0ECsI2MmdJg3CSX6AtELsWh0Ohxu41u_k,8132
68
+ PIL/ImageTransform.py,sha256=-qek7P3lzLddcXt9cWt5w_L11JGp2yY3AJtOfmJAkDc,3916
69
+ PIL/ImageWin.py,sha256=LT05w8_vTfRrC3n9S9pM0TNbXrzZLEJHlCJil7Xv80k,8085
70
+ PIL/ImtImagePlugin.py,sha256=SL5IrsHcblltxtX4v_HVFhYnR6haJ0AOd2NHhZKMImY,2665
71
+ PIL/IptcImagePlugin.py,sha256=AV5HTo7kHo20IuF1rd4OhQcbf3wt1rbRPwpI3cK0xw4,6579
72
+ PIL/Jpeg2KImagePlugin.py,sha256=DugpqlY-L54ZSbOOr1mux_fT1APy73e9715NQx_zL9E,14002
73
+ PIL/JpegImagePlugin.py,sha256=kWLRMNTVrfcHaIpZpcLsaLtxaefrenWdILZWwZfYEZ8,31543
74
+ PIL/JpegPresets.py,sha256=lnqWHo4DLIHIulcdHp0NJ7CWexHt8T3w51kIKlLfkIA,12379
75
+ PIL/McIdasImagePlugin.py,sha256=baOIkD-CIIeCgBFTf8kos928PKBuCUqYYa38u3WES_8,1877
76
+ PIL/MicImagePlugin.py,sha256=j91UizvL-zgXZgOcq_4oWBbSX6LPq1J9kNHkdITM1Qw,2599
77
+ PIL/MpegImagePlugin.py,sha256=g7BZd93kWpFi41SG_wKFoi0yEPsioI4kj45b2F-3Vrw,2010
78
+ PIL/MpoImagePlugin.py,sha256=xRCA2R2lSpT76pqDiQX0Es0yyaHj5d4gdN26eV7aInU,6792
79
+ PIL/MspImagePlugin.py,sha256=oxk_MLUDvzJ4JDuOZCHkmqOPXniG42PHOyNGwe60slY,5892
80
+ PIL/PSDraw.py,sha256=KMBGj3vXaFpblaIcA9KjFFTpdal41AQggY-UgzqoMkQ,6918
81
+ PIL/PaletteFile.py,sha256=suDdAL6VMljXw4oEn1vhTt4DQ4vbpIHGd3A4oxOgE6s,1216
82
+ PIL/PalmImagePlugin.py,sha256=WJ1b8I1xTSAXYDJhIpkVFCLu2LlpbiBD5d1Hr-m2l08,8748
83
+ PIL/PcdImagePlugin.py,sha256=-gnMUqQH0R-aljsd3nZS9eBI1j75ijWD_HZfadE3RsQ,1774
84
+ PIL/PcfFontFile.py,sha256=DqcyydQgP2vtiPFzj57KYHLuF2v-0oMTB-VkgYYHKhE,7223
85
+ PIL/PcxImagePlugin.py,sha256=1xAq6CdH34cOsOgTPi4Wu2SKQCdQiTLVyqaMkYQZUP4,6245
86
+ PIL/PdfImagePlugin.py,sha256=6lZLoQMVbAE-x1ESrv6PgGSyM9Ueck7e6E6ps-YQ-vI,9321
87
+ PIL/PdfParser.py,sha256=Hr3ImLDSIKwUF6OrQ1GjlAnGi6ZpGVLWhGfKhqQ_DRM,37996
88
+ PIL/PixarImagePlugin.py,sha256=l_4GwBd0mATnIXYJbwmmODU2vP7wewLu6BRviHCB2EI,1758
89
+ PIL/PngImagePlugin.py,sha256=XaVZDKJIf37Cp9tSZr74kYWFTVfV5PYZ9Qeo8pVbeqo,51721
90
+ PIL/PpmImagePlugin.py,sha256=vb5SP0IjQPzDRDE8jSPtcJv9K3Rh1LczAlt0Pg26i90,12391
91
+ PIL/PsdImagePlugin.py,sha256=Dxyb0AwhIk7ngpuOluaJz3HtlQtSUmylLJao9CPiCII,8720
92
+ PIL/QoiImagePlugin.py,sha256=o3IJbJYiG6Qz_evDAixeTferNaXOA7Rf0TsoNQeFaZ4,8607
93
+ PIL/SgiImagePlugin.py,sha256=3Ql89s8vycNWjcxJwMw28iksV9Yj2xWoKBQ6c5DHXBg,6389
94
+ PIL/SpiderImagePlugin.py,sha256=etb3Q-rKGtBg_rrVmBfh-poM2AODqibtA3yq5zoUTSc,10306
95
+ PIL/SunImagePlugin.py,sha256=Hdxkhk0pxpBGxYhPJfCDLwsYcO1KjxjtplNMFYibIvk,4589
96
+ PIL/TarIO.py,sha256=BqYUChCBb9F7Sh-uZ86iz1Dtoy2D0obNwGm65z1rdc0,1442
97
+ PIL/TgaImagePlugin.py,sha256=2vDsFTcBUBHw1V80wpVv4tgpLDbPr6yVHi6Fvaqf0HY,6980
98
+ PIL/TiffImagePlugin.py,sha256=cIQ48x3zmm5PFSG01wqweC8DJUhJxrX1R62c8Edw1Jg,85002
99
+ PIL/TiffTags.py,sha256=dm3qNQQkuaLKqzUTvnlGiUA8K3IizQOABvac_wjttF0,17206
100
+ PIL/WalImageFile.py,sha256=P6Ue6JZGAwBKE-JAIUP-oHCC4MPPc2jyqOScnAEKK3Y,5761
101
+ PIL/WebPImagePlugin.py,sha256=fCHqpMBM5CV2pr26GzLEuBm7V58Q_Z9YJ-9zxc2jA4M,9854
102
+ PIL/WmfImagePlugin.py,sha256=B2pMdJxRildCITQdb4XNAJXEwjitr2ZZVKVl2c-G1xY,5316
103
+ PIL/XVThumbImagePlugin.py,sha256=XghmnRm8Y_8j0O28XPbHRrmK7CrGVuR844gv1hfF5ug,2126
104
+ PIL/XbmImagePlugin.py,sha256=Fd6GVDEo73nyFICA3Z3w4LjkwoZWvhHB6rKCm5yVrho,2669
105
+ PIL/XpmImagePlugin.py,sha256=jtUKavJCYwIAsJaJwSx8vJsx1oTbCywfDxePENmA93w,4400
106
+ PIL/__init__.py,sha256=Q4KOEpR7S_Xsj30fvOsvR94xEpX4KUsVeUwaVP1fU80,2031
107
+ PIL/__main__.py,sha256=Lpj4vef8mI7jA1sRCUAoVYaeePD_Uc898xF5c7XLx1A,133
108
+ PIL/_avif.cpython-313-darwin.so,sha256=GowXJE1Wvzm6-0zzM5vK1sdibOS6B1bbVS2glWwu3Fs,73968
109
+ PIL/_avif.pyi,sha256=3fBxcSppJr6EOEcUojvflG3Eegg7lv2Qp0dNQQILrP4,63
110
+ PIL/_binary.py,sha256=pcM6AL04GxgmGeLfcH1V1BZHENwIrQH0uxhJ7r0HIL0,2550
111
+ PIL/_deprecate.py,sha256=KhyLVmQYVVww0rORbU24Te3t8fOt9G2LeM6fJGWbl0o,2034
112
+ PIL/_imaging.cpython-313-darwin.so,sha256=TrGLRFVdweDxh397MnuNhXRZNCc11GCJg3gryXtdb7Y,572144
113
+ PIL/_imaging.pyi,sha256=fT-TTGQS0kym1gv77gXTKQtJrAmO1NynS5LKBtG3G6M,893
114
+ PIL/_imagingcms.cpython-313-darwin.so,sha256=4UL7ZNmzOS1zG1uOu30c_ClLLunjH5JAP2HbzeK0gwg,98512
115
+ PIL/_imagingcms.pyi,sha256=ZZ8iIoi6EHWLvgAdfm1hPD5CQmxi75LiJl5x8yGxYoU,4433
116
+ PIL/_imagingft.cpython-313-darwin.so,sha256=BHIs6R0Kx4BUwfXNaRxqsjD89cELRkzULOCzdiAuOI4,117728
117
+ PIL/_imagingft.pyi,sha256=cYySzvcKBCiHPBsvttMie9AdfUcEsqZR-3256YQtz2Q,1833
118
+ PIL/_imagingmath.cpython-313-darwin.so,sha256=7dFu3iMmAmC2oLt6qmohGO8fZi4rkPjlYE873GaYmIg,55904
119
+ PIL/_imagingmath.pyi,sha256=3fBxcSppJr6EOEcUojvflG3Eegg7lv2Qp0dNQQILrP4,63
120
+ PIL/_imagingmorph.cpython-313-darwin.so,sha256=gSUB6Tq15YR8QTfKdLDSWka61dI6VDBRk-G05fJ6e0w,51440
121
+ PIL/_imagingmorph.pyi,sha256=3fBxcSppJr6EOEcUojvflG3Eegg7lv2Qp0dNQQILrP4,63
122
+ PIL/_imagingtk.cpython-313-darwin.so,sha256=hGQDcrQdtLldqMvt1BMtBVovVlVzIpR8zv-Y7KLSRUU,52720
123
+ PIL/_imagingtk.pyi,sha256=3fBxcSppJr6EOEcUojvflG3Eegg7lv2Qp0dNQQILrP4,63
124
+ PIL/_tkinter_finder.py,sha256=GIZ4stmFhUosmHKSrdxcjStiocDNfyJn7RBie2SWxU0,538
125
+ PIL/_typing.py,sha256=2z33ZUp9aQnkSqXzNR3Zn7l04d2W-oAj1OiZhiyFF68,919
126
+ PIL/_util.py,sha256=fxhWdrLARyc2PsMgN3m9_U1dY3oUKbV7mkoHcXgoeeA,684
127
+ PIL/_version.py,sha256=28QchbjtLhowcIycQ-2YvK356_LZtiCuh-r1ELBCsEQ,87
128
+ PIL/_webp.cpython-313-darwin.so,sha256=a7erFcORHzjmuZp0nZ0CUGxvyeyW1zdrO-pKmpK9BrI,76256
129
+ PIL/_webp.pyi,sha256=3fBxcSppJr6EOEcUojvflG3Eegg7lv2Qp0dNQQILrP4,63
130
+ PIL/features.py,sha256=FPkEhjtBaRSqpkgHNYduwxiFtycu4NjZKwEMWxtemPU,10775
131
+ PIL/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
132
+ PIL/report.py,sha256=4JY6-IU7sH1RKuRbOvy1fUt0dAoi79FX4tYJN3p1DT0,100
133
+ pillow-12.1.1.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
134
+ pillow-12.1.1.dist-info/METADATA,sha256=F_8fLSrbwe5hjpfxSagcqvTDKT1aaHIntiiRmecPLRc,8808
135
+ pillow-12.1.1.dist-info/RECORD,,
136
+ pillow-12.1.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
137
+ pillow-12.1.1.dist-info/WHEEL,sha256=MhISwTXlcxsZliAvBTu_MYP_gZvKB8bGPOh0ufmy-Yo,136
138
+ pillow-12.1.1.dist-info/licenses/LICENSE,sha256=MBeL96_5-NyCr-01CGzTeKkGTnf8tDgEhfOLXaM3cFI,68061
139
+ pillow-12.1.1.dist-info/top_level.txt,sha256=riZqrk-hyZqh5f1Z0Zwii3dKfxEsByhu9cU9IODF-NY,4
140
+ pillow-12.1.1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
.venv/lib/python3.13/site-packages/pillow-12.1.1.dist-info/REQUESTED ADDED
File without changes
.venv/lib/python3.13/site-packages/pillow-12.1.1.dist-info/zip-safe ADDED
@@ -0,0 +1 @@
 
 
1
+
.venv/lib/python3.13/site-packages/sympy/discrete/__init__.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """This module contains functions which operate on discrete sequences.
2
+
3
+ Transforms - ``fft``, ``ifft``, ``ntt``, ``intt``, ``fwht``, ``ifwht``,
4
+ ``mobius_transform``, ``inverse_mobius_transform``
5
+
6
+ Convolutions - ``convolution``, ``convolution_fft``, ``convolution_ntt``,
7
+ ``convolution_fwht``, ``convolution_subset``,
8
+ ``covering_product``, ``intersecting_product``
9
+ """
10
+
11
+ from .transforms import (fft, ifft, ntt, intt, fwht, ifwht,
12
+ mobius_transform, inverse_mobius_transform)
13
+ from .convolutions import convolution, covering_product, intersecting_product
14
+
15
+ __all__ = [
16
+ 'fft', 'ifft', 'ntt', 'intt', 'fwht', 'ifwht', 'mobius_transform',
17
+ 'inverse_mobius_transform',
18
+
19
+ 'convolution', 'covering_product', 'intersecting_product',
20
+ ]
.venv/lib/python3.13/site-packages/sympy/discrete/convolutions.py ADDED
@@ -0,0 +1,597 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Convolution (using **FFT**, **NTT**, **FWHT**), Subset Convolution,
3
+ Covering Product, Intersecting Product
4
+ """
5
+
6
+ from sympy.core import S, sympify, Rational
7
+ from sympy.core.function import expand_mul
8
+ from sympy.discrete.transforms import (
9
+ fft, ifft, ntt, intt, fwht, ifwht,
10
+ mobius_transform, inverse_mobius_transform)
11
+ from sympy.external.gmpy import MPZ, lcm
12
+ from sympy.utilities.iterables import iterable
13
+ from sympy.utilities.misc import as_int
14
+
15
+
16
+ def convolution(a, b, cycle=0, dps=None, prime=None, dyadic=None, subset=None):
17
+ """
18
+ Performs convolution by determining the type of desired
19
+ convolution using hints.
20
+
21
+ Exactly one of ``dps``, ``prime``, ``dyadic``, ``subset`` arguments
22
+ should be specified explicitly for identifying the type of convolution,
23
+ and the argument ``cycle`` can be specified optionally.
24
+
25
+ For the default arguments, linear convolution is performed using **FFT**.
26
+
27
+ Parameters
28
+ ==========
29
+
30
+ a, b : iterables
31
+ The sequences for which convolution is performed.
32
+ cycle : Integer
33
+ Specifies the length for doing cyclic convolution.
34
+ dps : Integer
35
+ Specifies the number of decimal digits for precision for
36
+ performing **FFT** on the sequence.
37
+ prime : Integer
38
+ Prime modulus of the form `(m 2^k + 1)` to be used for
39
+ performing **NTT** on the sequence.
40
+ dyadic : bool
41
+ Identifies the convolution type as dyadic (*bitwise-XOR*)
42
+ convolution, which is performed using **FWHT**.
43
+ subset : bool
44
+ Identifies the convolution type as subset convolution.
45
+
46
+ Examples
47
+ ========
48
+
49
+ >>> from sympy import convolution, symbols, S, I
50
+ >>> u, v, w, x, y, z = symbols('u v w x y z')
51
+
52
+ >>> convolution([1 + 2*I, 4 + 3*I], [S(5)/4, 6], dps=3)
53
+ [1.25 + 2.5*I, 11.0 + 15.8*I, 24.0 + 18.0*I]
54
+ >>> convolution([1, 2, 3], [4, 5, 6], cycle=3)
55
+ [31, 31, 28]
56
+
57
+ >>> convolution([111, 777], [888, 444], prime=19*2**10 + 1)
58
+ [1283, 19351, 14219]
59
+ >>> convolution([111, 777], [888, 444], prime=19*2**10 + 1, cycle=2)
60
+ [15502, 19351]
61
+
62
+ >>> convolution([u, v], [x, y, z], dyadic=True)
63
+ [u*x + v*y, u*y + v*x, u*z, v*z]
64
+ >>> convolution([u, v], [x, y, z], dyadic=True, cycle=2)
65
+ [u*x + u*z + v*y, u*y + v*x + v*z]
66
+
67
+ >>> convolution([u, v, w], [x, y, z], subset=True)
68
+ [u*x, u*y + v*x, u*z + w*x, v*z + w*y]
69
+ >>> convolution([u, v, w], [x, y, z], subset=True, cycle=3)
70
+ [u*x + v*z + w*y, u*y + v*x, u*z + w*x]
71
+
72
+ """
73
+
74
+ c = as_int(cycle)
75
+ if c < 0:
76
+ raise ValueError("The length for cyclic convolution "
77
+ "must be non-negative")
78
+
79
+ dyadic = True if dyadic else None
80
+ subset = True if subset else None
81
+ if sum(x is not None for x in (prime, dps, dyadic, subset)) > 1:
82
+ raise TypeError("Ambiguity in determining the type of convolution")
83
+
84
+ if prime is not None:
85
+ ls = convolution_ntt(a, b, prime=prime)
86
+ return ls if not c else [sum(ls[i::c]) % prime for i in range(c)]
87
+
88
+ if dyadic:
89
+ ls = convolution_fwht(a, b)
90
+ elif subset:
91
+ ls = convolution_subset(a, b)
92
+ else:
93
+ def loop(a):
94
+ dens = []
95
+ for i in a:
96
+ if isinstance(i, Rational) and i.q - 1:
97
+ dens.append(i.q)
98
+ elif not isinstance(i, int):
99
+ return
100
+ if dens:
101
+ l = lcm(*dens)
102
+ return [i*l if type(i) is int else i.p*(l//i.q) for i in a], l
103
+ # no lcm of den to deal with
104
+ return a, 1
105
+ ls = None
106
+ da = loop(a)
107
+ if da is not None:
108
+ db = loop(b)
109
+ if db is not None:
110
+ (ia, ma), (ib, mb) = da, db
111
+ den = ma*mb
112
+ ls = convolution_int(ia, ib)
113
+ if den != 1:
114
+ ls = [Rational(i, den) for i in ls]
115
+ if ls is None:
116
+ ls = convolution_fft(a, b, dps)
117
+
118
+ return ls if not c else [sum(ls[i::c]) for i in range(c)]
119
+
120
+
121
+ #----------------------------------------------------------------------------#
122
+ # #
123
+ # Convolution for Complex domain #
124
+ # #
125
+ #----------------------------------------------------------------------------#
126
+
127
+ def convolution_fft(a, b, dps=None):
128
+ """
129
+ Performs linear convolution using Fast Fourier Transform.
130
+
131
+ Parameters
132
+ ==========
133
+
134
+ a, b : iterables
135
+ The sequences for which convolution is performed.
136
+ dps : Integer
137
+ Specifies the number of decimal digits for precision.
138
+
139
+ Examples
140
+ ========
141
+
142
+ >>> from sympy import S, I
143
+ >>> from sympy.discrete.convolutions import convolution_fft
144
+
145
+ >>> convolution_fft([2, 3], [4, 5])
146
+ [8, 22, 15]
147
+ >>> convolution_fft([2, 5], [6, 7, 3])
148
+ [12, 44, 41, 15]
149
+ >>> convolution_fft([1 + 2*I, 4 + 3*I], [S(5)/4, 6])
150
+ [5/4 + 5*I/2, 11 + 63*I/4, 24 + 18*I]
151
+
152
+ References
153
+ ==========
154
+
155
+ .. [1] https://en.wikipedia.org/wiki/Convolution_theorem
156
+ .. [2] https://en.wikipedia.org/wiki/Discrete_Fourier_transform_(general%29
157
+
158
+ """
159
+
160
+ a, b = a[:], b[:]
161
+ n = m = len(a) + len(b) - 1 # convolution size
162
+
163
+ if n > 0 and n&(n - 1): # not a power of 2
164
+ n = 2**n.bit_length()
165
+
166
+ # padding with zeros
167
+ a += [S.Zero]*(n - len(a))
168
+ b += [S.Zero]*(n - len(b))
169
+
170
+ a, b = fft(a, dps), fft(b, dps)
171
+ a = [expand_mul(x*y) for x, y in zip(a, b)]
172
+ a = ifft(a, dps)[:m]
173
+
174
+ return a
175
+
176
+
177
+ #----------------------------------------------------------------------------#
178
+ # #
179
+ # Convolution for GF(p) #
180
+ # #
181
+ #----------------------------------------------------------------------------#
182
+
183
+ def convolution_ntt(a, b, prime):
184
+ """
185
+ Performs linear convolution using Number Theoretic Transform.
186
+
187
+ Parameters
188
+ ==========
189
+
190
+ a, b : iterables
191
+ The sequences for which convolution is performed.
192
+ prime : Integer
193
+ Prime modulus of the form `(m 2^k + 1)` to be used for performing
194
+ **NTT** on the sequence.
195
+
196
+ Examples
197
+ ========
198
+
199
+ >>> from sympy.discrete.convolutions import convolution_ntt
200
+ >>> convolution_ntt([2, 3], [4, 5], prime=19*2**10 + 1)
201
+ [8, 22, 15]
202
+ >>> convolution_ntt([2, 5], [6, 7, 3], prime=19*2**10 + 1)
203
+ [12, 44, 41, 15]
204
+ >>> convolution_ntt([333, 555], [222, 666], prime=19*2**10 + 1)
205
+ [15555, 14219, 19404]
206
+
207
+ References
208
+ ==========
209
+
210
+ .. [1] https://en.wikipedia.org/wiki/Convolution_theorem
211
+ .. [2] https://en.wikipedia.org/wiki/Discrete_Fourier_transform_(general%29
212
+
213
+ """
214
+
215
+ a, b, p = a[:], b[:], as_int(prime)
216
+ n = m = len(a) + len(b) - 1 # convolution size
217
+
218
+ if n > 0 and n&(n - 1): # not a power of 2
219
+ n = 2**n.bit_length()
220
+
221
+ # padding with zeros
222
+ a += [0]*(n - len(a))
223
+ b += [0]*(n - len(b))
224
+
225
+ a, b = ntt(a, p), ntt(b, p)
226
+ a = [x*y % p for x, y in zip(a, b)]
227
+ a = intt(a, p)[:m]
228
+
229
+ return a
230
+
231
+
232
+ #----------------------------------------------------------------------------#
233
+ # #
234
+ # Convolution for 2**n-group #
235
+ # #
236
+ #----------------------------------------------------------------------------#
237
+
238
+ def convolution_fwht(a, b):
239
+ """
240
+ Performs dyadic (*bitwise-XOR*) convolution using Fast Walsh Hadamard
241
+ Transform.
242
+
243
+ The convolution is automatically padded to the right with zeros, as the
244
+ *radix-2 FWHT* requires the number of sample points to be a power of 2.
245
+
246
+ Parameters
247
+ ==========
248
+
249
+ a, b : iterables
250
+ The sequences for which convolution is performed.
251
+
252
+ Examples
253
+ ========
254
+
255
+ >>> from sympy import symbols, S, I
256
+ >>> from sympy.discrete.convolutions import convolution_fwht
257
+
258
+ >>> u, v, x, y = symbols('u v x y')
259
+ >>> convolution_fwht([u, v], [x, y])
260
+ [u*x + v*y, u*y + v*x]
261
+
262
+ >>> convolution_fwht([2, 3], [4, 5])
263
+ [23, 22]
264
+ >>> convolution_fwht([2, 5 + 4*I, 7], [6*I, 7, 3 + 4*I])
265
+ [56 + 68*I, -10 + 30*I, 6 + 50*I, 48 + 32*I]
266
+
267
+ >>> convolution_fwht([S(33)/7, S(55)/6, S(7)/4], [S(2)/3, 5])
268
+ [2057/42, 1870/63, 7/6, 35/4]
269
+
270
+ References
271
+ ==========
272
+
273
+ .. [1] https://www.radioeng.cz/fulltexts/2002/02_03_40_42.pdf
274
+ .. [2] https://en.wikipedia.org/wiki/Hadamard_transform
275
+
276
+ """
277
+
278
+ if not a or not b:
279
+ return []
280
+
281
+ a, b = a[:], b[:]
282
+ n = max(len(a), len(b))
283
+
284
+ if n&(n - 1): # not a power of 2
285
+ n = 2**n.bit_length()
286
+
287
+ # padding with zeros
288
+ a += [S.Zero]*(n - len(a))
289
+ b += [S.Zero]*(n - len(b))
290
+
291
+ a, b = fwht(a), fwht(b)
292
+ a = [expand_mul(x*y) for x, y in zip(a, b)]
293
+ a = ifwht(a)
294
+
295
+ return a
296
+
297
+
298
+ #----------------------------------------------------------------------------#
299
+ # #
300
+ # Subset Convolution #
301
+ # #
302
+ #----------------------------------------------------------------------------#
303
+
304
+ def convolution_subset(a, b):
305
+ """
306
+ Performs Subset Convolution of given sequences.
307
+
308
+ The indices of each argument, considered as bit strings, correspond to
309
+ subsets of a finite set.
310
+
311
+ The sequence is automatically padded to the right with zeros, as the
312
+ definition of subset based on bitmasks (indices) requires the size of
313
+ sequence to be a power of 2.
314
+
315
+ Parameters
316
+ ==========
317
+
318
+ a, b : iterables
319
+ The sequences for which convolution is performed.
320
+
321
+ Examples
322
+ ========
323
+
324
+ >>> from sympy import symbols, S
325
+ >>> from sympy.discrete.convolutions import convolution_subset
326
+ >>> u, v, x, y, z = symbols('u v x y z')
327
+
328
+ >>> convolution_subset([u, v], [x, y])
329
+ [u*x, u*y + v*x]
330
+ >>> convolution_subset([u, v, x], [y, z])
331
+ [u*y, u*z + v*y, x*y, x*z]
332
+
333
+ >>> convolution_subset([1, S(2)/3], [3, 4])
334
+ [3, 6]
335
+ >>> convolution_subset([1, 3, S(5)/7], [7])
336
+ [7, 21, 5, 0]
337
+
338
+ References
339
+ ==========
340
+
341
+ .. [1] https://people.csail.mit.edu/rrw/presentations/subset-conv.pdf
342
+
343
+ """
344
+
345
+ if not a or not b:
346
+ return []
347
+
348
+ if not iterable(a) or not iterable(b):
349
+ raise TypeError("Expected a sequence of coefficients for convolution")
350
+
351
+ a = [sympify(arg) for arg in a]
352
+ b = [sympify(arg) for arg in b]
353
+ n = max(len(a), len(b))
354
+
355
+ if n&(n - 1): # not a power of 2
356
+ n = 2**n.bit_length()
357
+
358
+ # padding with zeros
359
+ a += [S.Zero]*(n - len(a))
360
+ b += [S.Zero]*(n - len(b))
361
+
362
+ c = [S.Zero]*n
363
+
364
+ for mask in range(n):
365
+ smask = mask
366
+ while smask > 0:
367
+ c[mask] += expand_mul(a[smask] * b[mask^smask])
368
+ smask = (smask - 1)&mask
369
+
370
+ c[mask] += expand_mul(a[smask] * b[mask^smask])
371
+
372
+ return c
373
+
374
+
375
+ #----------------------------------------------------------------------------#
376
+ # #
377
+ # Covering Product #
378
+ # #
379
+ #----------------------------------------------------------------------------#
380
+
381
+ def covering_product(a, b):
382
+ """
383
+ Returns the covering product of given sequences.
384
+
385
+ The indices of each argument, considered as bit strings, correspond to
386
+ subsets of a finite set.
387
+
388
+ The covering product of given sequences is a sequence which contains
389
+ the sum of products of the elements of the given sequences grouped by
390
+ the *bitwise-OR* of the corresponding indices.
391
+
392
+ The sequence is automatically padded to the right with zeros, as the
393
+ definition of subset based on bitmasks (indices) requires the size of
394
+ sequence to be a power of 2.
395
+
396
+ Parameters
397
+ ==========
398
+
399
+ a, b : iterables
400
+ The sequences for which covering product is to be obtained.
401
+
402
+ Examples
403
+ ========
404
+
405
+ >>> from sympy import symbols, S, I, covering_product
406
+ >>> u, v, x, y, z = symbols('u v x y z')
407
+
408
+ >>> covering_product([u, v], [x, y])
409
+ [u*x, u*y + v*x + v*y]
410
+ >>> covering_product([u, v, x], [y, z])
411
+ [u*y, u*z + v*y + v*z, x*y, x*z]
412
+
413
+ >>> covering_product([1, S(2)/3], [3, 4 + 5*I])
414
+ [3, 26/3 + 25*I/3]
415
+ >>> covering_product([1, 3, S(5)/7], [7, 8])
416
+ [7, 53, 5, 40/7]
417
+
418
+ References
419
+ ==========
420
+
421
+ .. [1] https://people.csail.mit.edu/rrw/presentations/subset-conv.pdf
422
+
423
+ """
424
+
425
+ if not a or not b:
426
+ return []
427
+
428
+ a, b = a[:], b[:]
429
+ n = max(len(a), len(b))
430
+
431
+ if n&(n - 1): # not a power of 2
432
+ n = 2**n.bit_length()
433
+
434
+ # padding with zeros
435
+ a += [S.Zero]*(n - len(a))
436
+ b += [S.Zero]*(n - len(b))
437
+
438
+ a, b = mobius_transform(a), mobius_transform(b)
439
+ a = [expand_mul(x*y) for x, y in zip(a, b)]
440
+ a = inverse_mobius_transform(a)
441
+
442
+ return a
443
+
444
+
445
+ #----------------------------------------------------------------------------#
446
+ # #
447
+ # Intersecting Product #
448
+ # #
449
+ #----------------------------------------------------------------------------#
450
+
451
+ def intersecting_product(a, b):
452
+ """
453
+ Returns the intersecting product of given sequences.
454
+
455
+ The indices of each argument, considered as bit strings, correspond to
456
+ subsets of a finite set.
457
+
458
+ The intersecting product of given sequences is the sequence which
459
+ contains the sum of products of the elements of the given sequences
460
+ grouped by the *bitwise-AND* of the corresponding indices.
461
+
462
+ The sequence is automatically padded to the right with zeros, as the
463
+ definition of subset based on bitmasks (indices) requires the size of
464
+ sequence to be a power of 2.
465
+
466
+ Parameters
467
+ ==========
468
+
469
+ a, b : iterables
470
+ The sequences for which intersecting product is to be obtained.
471
+
472
+ Examples
473
+ ========
474
+
475
+ >>> from sympy import symbols, S, I, intersecting_product
476
+ >>> u, v, x, y, z = symbols('u v x y z')
477
+
478
+ >>> intersecting_product([u, v], [x, y])
479
+ [u*x + u*y + v*x, v*y]
480
+ >>> intersecting_product([u, v, x], [y, z])
481
+ [u*y + u*z + v*y + x*y + x*z, v*z, 0, 0]
482
+
483
+ >>> intersecting_product([1, S(2)/3], [3, 4 + 5*I])
484
+ [9 + 5*I, 8/3 + 10*I/3]
485
+ >>> intersecting_product([1, 3, S(5)/7], [7, 8])
486
+ [327/7, 24, 0, 0]
487
+
488
+ References
489
+ ==========
490
+
491
+ .. [1] https://people.csail.mit.edu/rrw/presentations/subset-conv.pdf
492
+
493
+ """
494
+
495
+ if not a or not b:
496
+ return []
497
+
498
+ a, b = a[:], b[:]
499
+ n = max(len(a), len(b))
500
+
501
+ if n&(n - 1): # not a power of 2
502
+ n = 2**n.bit_length()
503
+
504
+ # padding with zeros
505
+ a += [S.Zero]*(n - len(a))
506
+ b += [S.Zero]*(n - len(b))
507
+
508
+ a, b = mobius_transform(a, subset=False), mobius_transform(b, subset=False)
509
+ a = [expand_mul(x*y) for x, y in zip(a, b)]
510
+ a = inverse_mobius_transform(a, subset=False)
511
+
512
+ return a
513
+
514
+
515
+ #----------------------------------------------------------------------------#
516
+ # #
517
+ # Integer Convolutions #
518
+ # #
519
+ #----------------------------------------------------------------------------#
520
+
521
+ def convolution_int(a, b):
522
+ """Return the convolution of two sequences as a list.
523
+
524
+ The iterables must consist solely of integers.
525
+
526
+ Parameters
527
+ ==========
528
+
529
+ a, b : Sequence
530
+ The sequences for which convolution is performed.
531
+
532
+ Explanation
533
+ ===========
534
+
535
+ This function performs the convolution of ``a`` and ``b`` by packing
536
+ each into a single integer, multiplying them together, and then
537
+ unpacking the result from the product. The intuition behind this is
538
+ that if we evaluate some polynomial [1]:
539
+
540
+ .. math ::
541
+ 1156x^6 + 3808x^5 + 8440x^4 + 14856x^3 + 16164x^2 + 14040x + 8100
542
+
543
+ at say $x = 10^5$ we obtain $1156038080844014856161641404008100$.
544
+ Note we can read of the coefficients for each term every five digits.
545
+ If the $x$ we chose to evaluate at is large enough, the same will hold
546
+ for the product.
547
+
548
+ The idea now is since big integer multiplication in libraries such
549
+ as GMP is highly optimised, this will be reasonably fast.
550
+
551
+ Examples
552
+ ========
553
+
554
+ >>> from sympy.discrete.convolutions import convolution_int
555
+
556
+ >>> convolution_int([2, 3], [4, 5])
557
+ [8, 22, 15]
558
+ >>> convolution_int([1, 1, -1], [1, 1])
559
+ [1, 2, 0, -1]
560
+
561
+ References
562
+ ==========
563
+
564
+ .. [1] Fateman, Richard J.
565
+ Can you save time in multiplying polynomials by encoding them as integers?
566
+ University of California, Berkeley, California (2004).
567
+ https://people.eecs.berkeley.edu/~fateman/papers/polysbyGMP.pdf
568
+ """
569
+ # An upper bound on the largest coefficient in p(x)q(x) is given by (1 + min(dp, dq))N(p)N(q)
570
+ # where dp = deg(p), dq = deg(q), N(f) denotes the coefficient of largest modulus in f [1]
571
+ B = max(abs(c) for c in a)*max(abs(c) for c in b)*(1 + min(len(a) - 1, len(b) - 1))
572
+ x, power = MPZ(1), 0
573
+ while x <= (2*B): # multiply by two for negative coefficients, see [1]
574
+ x <<= 1
575
+ power += 1
576
+
577
+ def to_integer(poly):
578
+ n, mul = MPZ(0), 0
579
+ for c in reversed(poly):
580
+ if c and not mul: mul = -1 if c < 0 else 1
581
+ n <<= power
582
+ n += mul*int(c)
583
+ return mul, n
584
+
585
+ # Perform packing and multiplication
586
+ (a_mul, a_packed), (b_mul, b_packed) = to_integer(a), to_integer(b)
587
+ result = a_packed * b_packed
588
+
589
+ # Perform unpacking
590
+ mul = a_mul * b_mul
591
+ mask, half, borrow, poly = x - 1, x >> 1, 0, []
592
+ while result or borrow:
593
+ coeff = (result & mask) + borrow
594
+ result >>= power
595
+ borrow = coeff >= half
596
+ poly.append(mul * int(coeff if coeff < half else coeff - x))
597
+ return poly or [0]
.venv/lib/python3.13/site-packages/sympy/discrete/recurrences.py ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Recurrences
3
+ """
4
+
5
+ from sympy.core import S, sympify
6
+ from sympy.utilities.iterables import iterable
7
+ from sympy.utilities.misc import as_int
8
+
9
+
10
+ def linrec(coeffs, init, n):
11
+ r"""
12
+ Evaluation of univariate linear recurrences of homogeneous type
13
+ having coefficients independent of the recurrence variable.
14
+
15
+ Parameters
16
+ ==========
17
+
18
+ coeffs : iterable
19
+ Coefficients of the recurrence
20
+ init : iterable
21
+ Initial values of the recurrence
22
+ n : Integer
23
+ Point of evaluation for the recurrence
24
+
25
+ Notes
26
+ =====
27
+
28
+ Let `y(n)` be the recurrence of given type, ``c`` be the sequence
29
+ of coefficients, ``b`` be the sequence of initial/base values of the
30
+ recurrence and ``k`` (equal to ``len(c)``) be the order of recurrence.
31
+ Then,
32
+
33
+ .. math :: y(n) = \begin{cases} b_n & 0 \le n < k \\
34
+ c_0 y(n-1) + c_1 y(n-2) + \cdots + c_{k-1} y(n-k) & n \ge k
35
+ \end{cases}
36
+
37
+ Let `x_0, x_1, \ldots, x_n` be a sequence and consider the transformation
38
+ that maps each polynomial `f(x)` to `T(f(x))` where each power `x^i` is
39
+ replaced by the corresponding value `x_i`. The sequence is then a solution
40
+ of the recurrence if and only if `T(x^i p(x)) = 0` for each `i \ge 0` where
41
+ `p(x) = x^k - c_0 x^(k-1) - \cdots - c_{k-1}` is the characteristic
42
+ polynomial.
43
+
44
+ Then `T(f(x)p(x)) = 0` for each polynomial `f(x)` (as it is a linear
45
+ combination of powers `x^i`). Now, if `x^n` is congruent to
46
+ `g(x) = a_0 x^0 + a_1 x^1 + \cdots + a_{k-1} x^{k-1}` modulo `p(x)`, then
47
+ `T(x^n) = x_n` is equal to
48
+ `T(g(x)) = a_0 x_0 + a_1 x_1 + \cdots + a_{k-1} x_{k-1}`.
49
+
50
+ Computation of `x^n`,
51
+ given `x^k = c_0 x^{k-1} + c_1 x^{k-2} + \cdots + c_{k-1}`
52
+ is performed using exponentiation by squaring (refer to [1_]) with
53
+ an additional reduction step performed to retain only first `k` powers
54
+ of `x` in the representation of `x^n`.
55
+
56
+ Examples
57
+ ========
58
+
59
+ >>> from sympy.discrete.recurrences import linrec
60
+ >>> from sympy.abc import x, y, z
61
+
62
+ >>> linrec(coeffs=[1, 1], init=[0, 1], n=10)
63
+ 55
64
+
65
+ >>> linrec(coeffs=[1, 1], init=[x, y], n=10)
66
+ 34*x + 55*y
67
+
68
+ >>> linrec(coeffs=[x, y], init=[0, 1], n=5)
69
+ x**2*y + x*(x**3 + 2*x*y) + y**2
70
+
71
+ >>> linrec(coeffs=[1, 2, 3, 0, 0, 4], init=[x, y, z], n=16)
72
+ 13576*x + 5676*y + 2356*z
73
+
74
+ References
75
+ ==========
76
+
77
+ .. [1] https://en.wikipedia.org/wiki/Exponentiation_by_squaring
78
+ .. [2] https://en.wikipedia.org/w/index.php?title=Modular_exponentiation&section=6#Matrices
79
+
80
+ See Also
81
+ ========
82
+
83
+ sympy.polys.agca.extensions.ExtensionElement.__pow__
84
+
85
+ """
86
+
87
+ if not coeffs:
88
+ return S.Zero
89
+
90
+ if not iterable(coeffs):
91
+ raise TypeError("Expected a sequence of coefficients for"
92
+ " the recurrence")
93
+
94
+ if not iterable(init):
95
+ raise TypeError("Expected a sequence of values for the initialization"
96
+ " of the recurrence")
97
+
98
+ n = as_int(n)
99
+ if n < 0:
100
+ raise ValueError("Point of evaluation of recurrence must be a "
101
+ "non-negative integer")
102
+
103
+ c = [sympify(arg) for arg in coeffs]
104
+ b = [sympify(arg) for arg in init]
105
+ k = len(c)
106
+
107
+ if len(b) > k:
108
+ raise TypeError("Count of initial values should not exceed the "
109
+ "order of the recurrence")
110
+ else:
111
+ b += [S.Zero]*(k - len(b)) # remaining initial values default to zero
112
+
113
+ if n < k:
114
+ return b[n]
115
+ terms = [u*v for u, v in zip(linrec_coeffs(c, n), b)]
116
+ return sum(terms[:-1], terms[-1])
117
+
118
+
119
+ def linrec_coeffs(c, n):
120
+ r"""
121
+ Compute the coefficients of n'th term in linear recursion
122
+ sequence defined by c.
123
+
124
+ `x^k = c_0 x^{k-1} + c_1 x^{k-2} + \cdots + c_{k-1}`.
125
+
126
+ It computes the coefficients by using binary exponentiation.
127
+ This function is used by `linrec` and `_eval_pow_by_cayley`.
128
+
129
+ Parameters
130
+ ==========
131
+
132
+ c = coefficients of the divisor polynomial
133
+ n = exponent of x, so dividend is x^n
134
+
135
+ """
136
+
137
+ k = len(c)
138
+
139
+ def _square_and_reduce(u, offset):
140
+ # squares `(u_0 + u_1 x + u_2 x^2 + \cdots + u_{k-1} x^k)` (and
141
+ # multiplies by `x` if offset is 1) and reduces the above result of
142
+ # length upto `2k` to `k` using the characteristic equation of the
143
+ # recurrence given by, `x^k = c_0 x^{k-1} + c_1 x^{k-2} + \cdots + c_{k-1}`
144
+
145
+ w = [S.Zero]*(2*len(u) - 1 + offset)
146
+ for i, p in enumerate(u):
147
+ for j, q in enumerate(u):
148
+ w[offset + i + j] += p*q
149
+
150
+ for j in range(len(w) - 1, k - 1, -1):
151
+ for i in range(k):
152
+ w[j - i - 1] += w[j]*c[i]
153
+
154
+ return w[:k]
155
+
156
+ def _final_coeffs(n):
157
+ # computes the final coefficient list - `cf` corresponding to the
158
+ # point at which recurrence is to be evalauted - `n`, such that,
159
+ # `y(n) = cf_0 y(k-1) + cf_1 y(k-2) + \cdots + cf_{k-1} y(0)`
160
+
161
+ if n < k:
162
+ return [S.Zero]*n + [S.One] + [S.Zero]*(k - n - 1)
163
+ else:
164
+ return _square_and_reduce(_final_coeffs(n // 2), n % 2)
165
+
166
+ return _final_coeffs(n)
.venv/lib/python3.13/site-packages/sympy/discrete/transforms.py ADDED
@@ -0,0 +1,425 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Discrete Fourier Transform, Number Theoretic Transform,
3
+ Walsh Hadamard Transform, Mobius Transform
4
+ """
5
+
6
+ from sympy.core import S, Symbol, sympify
7
+ from sympy.core.function import expand_mul
8
+ from sympy.core.numbers import pi, I
9
+ from sympy.functions.elementary.trigonometric import sin, cos
10
+ from sympy.ntheory import isprime, primitive_root
11
+ from sympy.utilities.iterables import ibin, iterable
12
+ from sympy.utilities.misc import as_int
13
+
14
+
15
+ #----------------------------------------------------------------------------#
16
+ # #
17
+ # Discrete Fourier Transform #
18
+ # #
19
+ #----------------------------------------------------------------------------#
20
+
21
+ def _fourier_transform(seq, dps, inverse=False):
22
+ """Utility function for the Discrete Fourier Transform"""
23
+
24
+ if not iterable(seq):
25
+ raise TypeError("Expected a sequence of numeric coefficients "
26
+ "for Fourier Transform")
27
+
28
+ a = [sympify(arg) for arg in seq]
29
+ if any(x.has(Symbol) for x in a):
30
+ raise ValueError("Expected non-symbolic coefficients")
31
+
32
+ n = len(a)
33
+ if n < 2:
34
+ return a
35
+
36
+ b = n.bit_length() - 1
37
+ if n&(n - 1): # not a power of 2
38
+ b += 1
39
+ n = 2**b
40
+
41
+ a += [S.Zero]*(n - len(a))
42
+ for i in range(1, n):
43
+ j = int(ibin(i, b, str=True)[::-1], 2)
44
+ if i < j:
45
+ a[i], a[j] = a[j], a[i]
46
+
47
+ ang = -2*pi/n if inverse else 2*pi/n
48
+
49
+ if dps is not None:
50
+ ang = ang.evalf(dps + 2)
51
+
52
+ w = [cos(ang*i) + I*sin(ang*i) for i in range(n // 2)]
53
+
54
+ h = 2
55
+ while h <= n:
56
+ hf, ut = h // 2, n // h
57
+ for i in range(0, n, h):
58
+ for j in range(hf):
59
+ u, v = a[i + j], expand_mul(a[i + j + hf]*w[ut * j])
60
+ a[i + j], a[i + j + hf] = u + v, u - v
61
+ h *= 2
62
+
63
+ if inverse:
64
+ a = [(x/n).evalf(dps) for x in a] if dps is not None \
65
+ else [x/n for x in a]
66
+
67
+ return a
68
+
69
+
70
+ def fft(seq, dps=None):
71
+ r"""
72
+ Performs the Discrete Fourier Transform (**DFT**) in the complex domain.
73
+
74
+ The sequence is automatically padded to the right with zeros, as the
75
+ *radix-2 FFT* requires the number of sample points to be a power of 2.
76
+
77
+ This method should be used with default arguments only for short sequences
78
+ as the complexity of expressions increases with the size of the sequence.
79
+
80
+ Parameters
81
+ ==========
82
+
83
+ seq : iterable
84
+ The sequence on which **DFT** is to be applied.
85
+ dps : Integer
86
+ Specifies the number of decimal digits for precision.
87
+
88
+ Examples
89
+ ========
90
+
91
+ >>> from sympy import fft, ifft
92
+
93
+ >>> fft([1, 2, 3, 4])
94
+ [10, -2 - 2*I, -2, -2 + 2*I]
95
+ >>> ifft(_)
96
+ [1, 2, 3, 4]
97
+
98
+ >>> ifft([1, 2, 3, 4])
99
+ [5/2, -1/2 + I/2, -1/2, -1/2 - I/2]
100
+ >>> fft(_)
101
+ [1, 2, 3, 4]
102
+
103
+ >>> ifft([1, 7, 3, 4], dps=15)
104
+ [3.75, -0.5 - 0.75*I, -1.75, -0.5 + 0.75*I]
105
+ >>> fft(_)
106
+ [1.0, 7.0, 3.0, 4.0]
107
+
108
+ References
109
+ ==========
110
+
111
+ .. [1] https://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm
112
+ .. [2] https://mathworld.wolfram.com/FastFourierTransform.html
113
+
114
+ """
115
+
116
+ return _fourier_transform(seq, dps=dps)
117
+
118
+
119
+ def ifft(seq, dps=None):
120
+ return _fourier_transform(seq, dps=dps, inverse=True)
121
+
122
+ ifft.__doc__ = fft.__doc__
123
+
124
+
125
+ #----------------------------------------------------------------------------#
126
+ # #
127
+ # Number Theoretic Transform #
128
+ # #
129
+ #----------------------------------------------------------------------------#
130
+
131
+ def _number_theoretic_transform(seq, prime, inverse=False):
132
+ """Utility function for the Number Theoretic Transform"""
133
+
134
+ if not iterable(seq):
135
+ raise TypeError("Expected a sequence of integer coefficients "
136
+ "for Number Theoretic Transform")
137
+
138
+ p = as_int(prime)
139
+ if not isprime(p):
140
+ raise ValueError("Expected prime modulus for "
141
+ "Number Theoretic Transform")
142
+
143
+ a = [as_int(x) % p for x in seq]
144
+
145
+ n = len(a)
146
+ if n < 1:
147
+ return a
148
+
149
+ b = n.bit_length() - 1
150
+ if n&(n - 1):
151
+ b += 1
152
+ n = 2**b
153
+
154
+ if (p - 1) % n:
155
+ raise ValueError("Expected prime modulus of the form (m*2**k + 1)")
156
+
157
+ a += [0]*(n - len(a))
158
+ for i in range(1, n):
159
+ j = int(ibin(i, b, str=True)[::-1], 2)
160
+ if i < j:
161
+ a[i], a[j] = a[j], a[i]
162
+
163
+ pr = primitive_root(p)
164
+
165
+ rt = pow(pr, (p - 1) // n, p)
166
+ if inverse:
167
+ rt = pow(rt, p - 2, p)
168
+
169
+ w = [1]*(n // 2)
170
+ for i in range(1, n // 2):
171
+ w[i] = w[i - 1]*rt % p
172
+
173
+ h = 2
174
+ while h <= n:
175
+ hf, ut = h // 2, n // h
176
+ for i in range(0, n, h):
177
+ for j in range(hf):
178
+ u, v = a[i + j], a[i + j + hf]*w[ut * j]
179
+ a[i + j], a[i + j + hf] = (u + v) % p, (u - v) % p
180
+ h *= 2
181
+
182
+ if inverse:
183
+ rv = pow(n, p - 2, p)
184
+ a = [x*rv % p for x in a]
185
+
186
+ return a
187
+
188
+
189
+ def ntt(seq, prime):
190
+ r"""
191
+ Performs the Number Theoretic Transform (**NTT**), which specializes the
192
+ Discrete Fourier Transform (**DFT**) over quotient ring `Z/pZ` for prime
193
+ `p` instead of complex numbers `C`.
194
+
195
+ The sequence is automatically padded to the right with zeros, as the
196
+ *radix-2 NTT* requires the number of sample points to be a power of 2.
197
+
198
+ Parameters
199
+ ==========
200
+
201
+ seq : iterable
202
+ The sequence on which **DFT** is to be applied.
203
+ prime : Integer
204
+ Prime modulus of the form `(m 2^k + 1)` to be used for performing
205
+ **NTT** on the sequence.
206
+
207
+ Examples
208
+ ========
209
+
210
+ >>> from sympy import ntt, intt
211
+ >>> ntt([1, 2, 3, 4], prime=3*2**8 + 1)
212
+ [10, 643, 767, 122]
213
+ >>> intt(_, 3*2**8 + 1)
214
+ [1, 2, 3, 4]
215
+ >>> intt([1, 2, 3, 4], prime=3*2**8 + 1)
216
+ [387, 415, 384, 353]
217
+ >>> ntt(_, prime=3*2**8 + 1)
218
+ [1, 2, 3, 4]
219
+
220
+ References
221
+ ==========
222
+
223
+ .. [1] http://www.apfloat.org/ntt.html
224
+ .. [2] https://mathworld.wolfram.com/NumberTheoreticTransform.html
225
+ .. [3] https://en.wikipedia.org/wiki/Discrete_Fourier_transform_(general%29
226
+
227
+ """
228
+
229
+ return _number_theoretic_transform(seq, prime=prime)
230
+
231
+
232
+ def intt(seq, prime):
233
+ return _number_theoretic_transform(seq, prime=prime, inverse=True)
234
+
235
+ intt.__doc__ = ntt.__doc__
236
+
237
+
238
+ #----------------------------------------------------------------------------#
239
+ # #
240
+ # Walsh Hadamard Transform #
241
+ # #
242
+ #----------------------------------------------------------------------------#
243
+
244
+ def _walsh_hadamard_transform(seq, inverse=False):
245
+ """Utility function for the Walsh Hadamard Transform"""
246
+
247
+ if not iterable(seq):
248
+ raise TypeError("Expected a sequence of coefficients "
249
+ "for Walsh Hadamard Transform")
250
+
251
+ a = [sympify(arg) for arg in seq]
252
+ n = len(a)
253
+ if n < 2:
254
+ return a
255
+
256
+ if n&(n - 1):
257
+ n = 2**n.bit_length()
258
+
259
+ a += [S.Zero]*(n - len(a))
260
+ h = 2
261
+ while h <= n:
262
+ hf = h // 2
263
+ for i in range(0, n, h):
264
+ for j in range(hf):
265
+ u, v = a[i + j], a[i + j + hf]
266
+ a[i + j], a[i + j + hf] = u + v, u - v
267
+ h *= 2
268
+
269
+ if inverse:
270
+ a = [x/n for x in a]
271
+
272
+ return a
273
+
274
+
275
+ def fwht(seq):
276
+ r"""
277
+ Performs the Walsh Hadamard Transform (**WHT**), and uses Hadamard
278
+ ordering for the sequence.
279
+
280
+ The sequence is automatically padded to the right with zeros, as the
281
+ *radix-2 FWHT* requires the number of sample points to be a power of 2.
282
+
283
+ Parameters
284
+ ==========
285
+
286
+ seq : iterable
287
+ The sequence on which WHT is to be applied.
288
+
289
+ Examples
290
+ ========
291
+
292
+ >>> from sympy import fwht, ifwht
293
+ >>> fwht([4, 2, 2, 0, 0, 2, -2, 0])
294
+ [8, 0, 8, 0, 8, 8, 0, 0]
295
+ >>> ifwht(_)
296
+ [4, 2, 2, 0, 0, 2, -2, 0]
297
+
298
+ >>> ifwht([19, -1, 11, -9, -7, 13, -15, 5])
299
+ [2, 0, 4, 0, 3, 10, 0, 0]
300
+ >>> fwht(_)
301
+ [19, -1, 11, -9, -7, 13, -15, 5]
302
+
303
+ References
304
+ ==========
305
+
306
+ .. [1] https://en.wikipedia.org/wiki/Hadamard_transform
307
+ .. [2] https://en.wikipedia.org/wiki/Fast_Walsh%E2%80%93Hadamard_transform
308
+
309
+ """
310
+
311
+ return _walsh_hadamard_transform(seq)
312
+
313
+
314
+ def ifwht(seq):
315
+ return _walsh_hadamard_transform(seq, inverse=True)
316
+
317
+ ifwht.__doc__ = fwht.__doc__
318
+
319
+
320
+ #----------------------------------------------------------------------------#
321
+ # #
322
+ # Mobius Transform for Subset Lattice #
323
+ # #
324
+ #----------------------------------------------------------------------------#
325
+
326
+ def _mobius_transform(seq, sgn, subset):
327
+ r"""Utility function for performing Mobius Transform using
328
+ Yate's Dynamic Programming method"""
329
+
330
+ if not iterable(seq):
331
+ raise TypeError("Expected a sequence of coefficients")
332
+
333
+ a = [sympify(arg) for arg in seq]
334
+
335
+ n = len(a)
336
+ if n < 2:
337
+ return a
338
+
339
+ if n&(n - 1):
340
+ n = 2**n.bit_length()
341
+
342
+ a += [S.Zero]*(n - len(a))
343
+
344
+ if subset:
345
+ i = 1
346
+ while i < n:
347
+ for j in range(n):
348
+ if j & i:
349
+ a[j] += sgn*a[j ^ i]
350
+ i *= 2
351
+
352
+ else:
353
+ i = 1
354
+ while i < n:
355
+ for j in range(n):
356
+ if j & i:
357
+ continue
358
+ a[j] += sgn*a[j ^ i]
359
+ i *= 2
360
+
361
+ return a
362
+
363
+
364
+ def mobius_transform(seq, subset=True):
365
+ r"""
366
+ Performs the Mobius Transform for subset lattice with indices of
367
+ sequence as bitmasks.
368
+
369
+ The indices of each argument, considered as bit strings, correspond
370
+ to subsets of a finite set.
371
+
372
+ The sequence is automatically padded to the right with zeros, as the
373
+ definition of subset/superset based on bitmasks (indices) requires
374
+ the size of sequence to be a power of 2.
375
+
376
+ Parameters
377
+ ==========
378
+
379
+ seq : iterable
380
+ The sequence on which Mobius Transform is to be applied.
381
+ subset : bool
382
+ Specifies if Mobius Transform is applied by enumerating subsets
383
+ or supersets of the given set.
384
+
385
+ Examples
386
+ ========
387
+
388
+ >>> from sympy import symbols
389
+ >>> from sympy import mobius_transform, inverse_mobius_transform
390
+ >>> x, y, z = symbols('x y z')
391
+
392
+ >>> mobius_transform([x, y, z])
393
+ [x, x + y, x + z, x + y + z]
394
+ >>> inverse_mobius_transform(_)
395
+ [x, y, z, 0]
396
+
397
+ >>> mobius_transform([x, y, z], subset=False)
398
+ [x + y + z, y, z, 0]
399
+ >>> inverse_mobius_transform(_, subset=False)
400
+ [x, y, z, 0]
401
+
402
+ >>> mobius_transform([1, 2, 3, 4])
403
+ [1, 3, 4, 10]
404
+ >>> inverse_mobius_transform(_)
405
+ [1, 2, 3, 4]
406
+ >>> mobius_transform([1, 2, 3, 4], subset=False)
407
+ [10, 6, 7, 4]
408
+ >>> inverse_mobius_transform(_, subset=False)
409
+ [1, 2, 3, 4]
410
+
411
+ References
412
+ ==========
413
+
414
+ .. [1] https://en.wikipedia.org/wiki/M%C3%B6bius_inversion_formula
415
+ .. [2] https://people.csail.mit.edu/rrw/presentations/subset-conv.pdf
416
+ .. [3] https://arxiv.org/pdf/1211.0189.pdf
417
+
418
+ """
419
+
420
+ return _mobius_transform(seq, sgn=+1, subset=subset)
421
+
422
+ def inverse_mobius_transform(seq, subset=True):
423
+ return _mobius_transform(seq, sgn=-1, subset=subset)
424
+
425
+ inverse_mobius_transform.__doc__ = mobius_transform.__doc__
.venv/lib/python3.13/site-packages/sympy/ntheory/modular.py ADDED
@@ -0,0 +1,291 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from math import prod
2
+
3
+ from sympy.external.gmpy import gcd, gcdext
4
+ from sympy.ntheory.primetest import isprime
5
+ from sympy.polys.domains import ZZ
6
+ from sympy.polys.galoistools import gf_crt, gf_crt1, gf_crt2
7
+ from sympy.utilities.misc import as_int
8
+
9
+
10
+ def symmetric_residue(a, m):
11
+ """Return the residual mod m such that it is within half of the modulus.
12
+
13
+ >>> from sympy.ntheory.modular import symmetric_residue
14
+ >>> symmetric_residue(1, 6)
15
+ 1
16
+ >>> symmetric_residue(4, 6)
17
+ -2
18
+ """
19
+ if a <= m // 2:
20
+ return a
21
+ return a - m
22
+
23
+
24
+ def crt(m, v, symmetric=False, check=True):
25
+ r"""Chinese Remainder Theorem.
26
+
27
+ The moduli in m are assumed to be pairwise coprime. The output
28
+ is then an integer f, such that f = v_i mod m_i for each pair out
29
+ of v and m. If ``symmetric`` is False a positive integer will be
30
+ returned, else \|f\| will be less than or equal to the LCM of the
31
+ moduli, and thus f may be negative.
32
+
33
+ If the moduli are not co-prime the correct result will be returned
34
+ if/when the test of the result is found to be incorrect. This result
35
+ will be None if there is no solution.
36
+
37
+ The keyword ``check`` can be set to False if it is known that the moduli
38
+ are coprime.
39
+
40
+ Examples
41
+ ========
42
+
43
+ As an example consider a set of residues ``U = [49, 76, 65]``
44
+ and a set of moduli ``M = [99, 97, 95]``. Then we have::
45
+
46
+ >>> from sympy.ntheory.modular import crt
47
+
48
+ >>> crt([99, 97, 95], [49, 76, 65])
49
+ (639985, 912285)
50
+
51
+ This is the correct result because::
52
+
53
+ >>> [639985 % m for m in [99, 97, 95]]
54
+ [49, 76, 65]
55
+
56
+ If the moduli are not co-prime, you may receive an incorrect result
57
+ if you use ``check=False``:
58
+
59
+ >>> crt([12, 6, 17], [3, 4, 2], check=False)
60
+ (954, 1224)
61
+ >>> [954 % m for m in [12, 6, 17]]
62
+ [6, 0, 2]
63
+ >>> crt([12, 6, 17], [3, 4, 2]) is None
64
+ True
65
+ >>> crt([3, 6], [2, 5])
66
+ (5, 6)
67
+
68
+ Note: the order of gf_crt's arguments is reversed relative to crt,
69
+ and that solve_congruence takes residue, modulus pairs.
70
+
71
+ Programmer's note: rather than checking that all pairs of moduli share
72
+ no GCD (an O(n**2) test) and rather than factoring all moduli and seeing
73
+ that there is no factor in common, a check that the result gives the
74
+ indicated residuals is performed -- an O(n) operation.
75
+
76
+ See Also
77
+ ========
78
+
79
+ solve_congruence
80
+ sympy.polys.galoistools.gf_crt : low level crt routine used by this routine
81
+ """
82
+ if check:
83
+ m = list(map(as_int, m))
84
+ v = list(map(as_int, v))
85
+
86
+ result = gf_crt(v, m, ZZ)
87
+ mm = prod(m)
88
+
89
+ if check:
90
+ if not all(v % m == result % m for v, m in zip(v, m)):
91
+ result = solve_congruence(*list(zip(v, m)),
92
+ check=False, symmetric=symmetric)
93
+ if result is None:
94
+ return result
95
+ result, mm = result
96
+
97
+ if symmetric:
98
+ return int(symmetric_residue(result, mm)), int(mm)
99
+ return int(result), int(mm)
100
+
101
+
102
+ def crt1(m):
103
+ """First part of Chinese Remainder Theorem, for multiple application.
104
+
105
+ Examples
106
+ ========
107
+
108
+ >>> from sympy.ntheory.modular import crt, crt1, crt2
109
+ >>> m = [99, 97, 95]
110
+ >>> v = [49, 76, 65]
111
+
112
+ The following two codes have the same result.
113
+
114
+ >>> crt(m, v)
115
+ (639985, 912285)
116
+
117
+ >>> mm, e, s = crt1(m)
118
+ >>> crt2(m, v, mm, e, s)
119
+ (639985, 912285)
120
+
121
+ However, it is faster when we want to fix ``m`` and
122
+ compute for multiple ``v``, i.e. the following cases:
123
+
124
+ >>> mm, e, s = crt1(m)
125
+ >>> vs = [[52, 21, 37], [19, 46, 76]]
126
+ >>> for v in vs:
127
+ ... print(crt2(m, v, mm, e, s))
128
+ (397042, 912285)
129
+ (803206, 912285)
130
+
131
+ See Also
132
+ ========
133
+
134
+ sympy.polys.galoistools.gf_crt1 : low level crt routine used by this routine
135
+ sympy.ntheory.modular.crt
136
+ sympy.ntheory.modular.crt2
137
+
138
+ """
139
+
140
+ return gf_crt1(m, ZZ)
141
+
142
+
143
+ def crt2(m, v, mm, e, s, symmetric=False):
144
+ """Second part of Chinese Remainder Theorem, for multiple application.
145
+
146
+ See ``crt1`` for usage.
147
+
148
+ Examples
149
+ ========
150
+
151
+ >>> from sympy.ntheory.modular import crt1, crt2
152
+ >>> mm, e, s = crt1([18, 42, 6])
153
+ >>> crt2([18, 42, 6], [0, 0, 0], mm, e, s)
154
+ (0, 4536)
155
+
156
+ See Also
157
+ ========
158
+
159
+ sympy.polys.galoistools.gf_crt2 : low level crt routine used by this routine
160
+ sympy.ntheory.modular.crt
161
+ sympy.ntheory.modular.crt1
162
+
163
+ """
164
+
165
+ result = gf_crt2(v, m, mm, e, s, ZZ)
166
+
167
+ if symmetric:
168
+ return int(symmetric_residue(result, mm)), int(mm)
169
+ return int(result), int(mm)
170
+
171
+
172
+ def solve_congruence(*remainder_modulus_pairs, **hint):
173
+ """Compute the integer ``n`` that has the residual ``ai`` when it is
174
+ divided by ``mi`` where the ``ai`` and ``mi`` are given as pairs to
175
+ this function: ((a1, m1), (a2, m2), ...). If there is no solution,
176
+ return None. Otherwise return ``n`` and its modulus.
177
+
178
+ The ``mi`` values need not be co-prime. If it is known that the moduli are
179
+ not co-prime then the hint ``check`` can be set to False (default=True) and
180
+ the check for a quicker solution via crt() (valid when the moduli are
181
+ co-prime) will be skipped.
182
+
183
+ If the hint ``symmetric`` is True (default is False), the value of ``n``
184
+ will be within 1/2 of the modulus, possibly negative.
185
+
186
+ Examples
187
+ ========
188
+
189
+ >>> from sympy.ntheory.modular import solve_congruence
190
+
191
+ What number is 2 mod 3, 3 mod 5 and 2 mod 7?
192
+
193
+ >>> solve_congruence((2, 3), (3, 5), (2, 7))
194
+ (23, 105)
195
+ >>> [23 % m for m in [3, 5, 7]]
196
+ [2, 3, 2]
197
+
198
+ If you prefer to work with all remainder in one list and
199
+ all moduli in another, send the arguments like this:
200
+
201
+ >>> solve_congruence(*zip((2, 3, 2), (3, 5, 7)))
202
+ (23, 105)
203
+
204
+ The moduli need not be co-prime; in this case there may or
205
+ may not be a solution:
206
+
207
+ >>> solve_congruence((2, 3), (4, 6)) is None
208
+ True
209
+
210
+ >>> solve_congruence((2, 3), (5, 6))
211
+ (5, 6)
212
+
213
+ The symmetric flag will make the result be within 1/2 of the modulus:
214
+
215
+ >>> solve_congruence((2, 3), (5, 6), symmetric=True)
216
+ (-1, 6)
217
+
218
+ See Also
219
+ ========
220
+
221
+ crt : high level routine implementing the Chinese Remainder Theorem
222
+
223
+ """
224
+ def combine(c1, c2):
225
+ """Return the tuple (a, m) which satisfies the requirement
226
+ that n = a + i*m satisfy n = a1 + j*m1 and n = a2 = k*m2.
227
+
228
+ References
229
+ ==========
230
+
231
+ .. [1] https://en.wikipedia.org/wiki/Method_of_successive_substitution
232
+ """
233
+ a1, m1 = c1
234
+ a2, m2 = c2
235
+ a, b, c = m1, a2 - a1, m2
236
+ g = gcd(a, b, c)
237
+ a, b, c = [i//g for i in [a, b, c]]
238
+ if a != 1:
239
+ g, inv_a, _ = gcdext(a, c)
240
+ if g != 1:
241
+ return None
242
+ b *= inv_a
243
+ a, m = a1 + m1*b, m1*c
244
+ return a, m
245
+
246
+ rm = remainder_modulus_pairs
247
+ symmetric = hint.get('symmetric', False)
248
+
249
+ if hint.get('check', True):
250
+ rm = [(as_int(r), as_int(m)) for r, m in rm]
251
+
252
+ # ignore redundant pairs but raise an error otherwise; also
253
+ # make sure that a unique set of bases is sent to gf_crt if
254
+ # they are all prime.
255
+ #
256
+ # The routine will work out less-trivial violations and
257
+ # return None, e.g. for the pairs (1,3) and (14,42) there
258
+ # is no answer because 14 mod 42 (having a gcd of 14) implies
259
+ # (14/2) mod (42/2), (14/7) mod (42/7) and (14/14) mod (42/14)
260
+ # which, being 0 mod 3, is inconsistent with 1 mod 3. But to
261
+ # preprocess the input beyond checking of another pair with 42
262
+ # or 3 as the modulus (for this example) is not necessary.
263
+ uniq = {}
264
+ for r, m in rm:
265
+ r %= m
266
+ if m in uniq:
267
+ if r != uniq[m]:
268
+ return None
269
+ continue
270
+ uniq[m] = r
271
+ rm = [(r, m) for m, r in uniq.items()]
272
+ del uniq
273
+
274
+ # if the moduli are co-prime, the crt will be significantly faster;
275
+ # checking all pairs for being co-prime gets to be slow but a prime
276
+ # test is a good trade-off
277
+ if all(isprime(m) for r, m in rm):
278
+ r, m = list(zip(*rm))
279
+ return crt(m, r, symmetric=symmetric, check=False)
280
+
281
+ rv = (0, 1)
282
+ for rmi in rm:
283
+ rv = combine(rv, rmi)
284
+ if rv is None:
285
+ break
286
+ n, m = rv
287
+ n = n % m
288
+ else:
289
+ if symmetric:
290
+ return symmetric_residue(n, m), m
291
+ return n, m
.venv/lib/python3.13/site-packages/sympy/printing/aesaracode.py ADDED
@@ -0,0 +1,563 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+ import math
3
+ from typing import Any
4
+
5
+ from sympy.external import import_module
6
+ from sympy.printing.printer import Printer
7
+ from sympy.utilities.exceptions import sympy_deprecation_warning
8
+ from sympy.utilities.iterables import is_sequence
9
+ import sympy
10
+ from functools import partial
11
+
12
+
13
+ aesara = import_module('aesara')
14
+
15
+ if aesara:
16
+ aes = aesara.scalar
17
+ aet = aesara.tensor
18
+ from aesara.tensor import nlinalg
19
+ from aesara.tensor.elemwise import Elemwise
20
+ from aesara.tensor.elemwise import DimShuffle
21
+
22
+ # `true_divide` replaced `true_div` in Aesara 2.8.11 (released 2023) to
23
+ # match NumPy
24
+ # XXX: Remove this when not needed to support older versions.
25
+ true_divide = getattr(aet, 'true_divide', None)
26
+ if true_divide is None:
27
+ true_divide = aet.true_div
28
+
29
+ mapping = {
30
+ sympy.Add: aet.add,
31
+ sympy.Mul: aet.mul,
32
+ sympy.Abs: aet.abs,
33
+ sympy.sign: aet.sgn,
34
+ sympy.ceiling: aet.ceil,
35
+ sympy.floor: aet.floor,
36
+ sympy.log: aet.log,
37
+ sympy.exp: aet.exp,
38
+ sympy.sqrt: aet.sqrt,
39
+ sympy.cos: aet.cos,
40
+ sympy.acos: aet.arccos,
41
+ sympy.sin: aet.sin,
42
+ sympy.asin: aet.arcsin,
43
+ sympy.tan: aet.tan,
44
+ sympy.atan: aet.arctan,
45
+ sympy.atan2: aet.arctan2,
46
+ sympy.cosh: aet.cosh,
47
+ sympy.acosh: aet.arccosh,
48
+ sympy.sinh: aet.sinh,
49
+ sympy.asinh: aet.arcsinh,
50
+ sympy.tanh: aet.tanh,
51
+ sympy.atanh: aet.arctanh,
52
+ sympy.re: aet.real,
53
+ sympy.im: aet.imag,
54
+ sympy.arg: aet.angle,
55
+ sympy.erf: aet.erf,
56
+ sympy.gamma: aet.gamma,
57
+ sympy.loggamma: aet.gammaln,
58
+ sympy.Pow: aet.pow,
59
+ sympy.Eq: aet.eq,
60
+ sympy.StrictGreaterThan: aet.gt,
61
+ sympy.StrictLessThan: aet.lt,
62
+ sympy.LessThan: aet.le,
63
+ sympy.GreaterThan: aet.ge,
64
+ sympy.And: aet.bitwise_and, # bitwise
65
+ sympy.Or: aet.bitwise_or, # bitwise
66
+ sympy.Not: aet.invert, # bitwise
67
+ sympy.Xor: aet.bitwise_xor, # bitwise
68
+ sympy.Max: aet.maximum, # Sympy accept >2 inputs, Aesara only 2
69
+ sympy.Min: aet.minimum, # Sympy accept >2 inputs, Aesara only 2
70
+ sympy.conjugate: aet.conj,
71
+ sympy.core.numbers.ImaginaryUnit: lambda:aet.complex(0,1),
72
+ # Matrices
73
+ sympy.MatAdd: Elemwise(aes.add),
74
+ sympy.HadamardProduct: Elemwise(aes.mul),
75
+ sympy.Trace: nlinalg.trace,
76
+ sympy.Determinant : nlinalg.det,
77
+ sympy.Inverse: nlinalg.matrix_inverse,
78
+ sympy.Transpose: DimShuffle((False, False), [1, 0]),
79
+ }
80
+
81
+
82
+ class AesaraPrinter(Printer):
83
+ """
84
+ .. deprecated:: 1.14.
85
+ The ``Aesara Code printing`` is deprecated.See its documentation for
86
+ more information. See :ref:`deprecated-aesaraprinter` for details.
87
+
88
+ Code printer which creates Aesara symbolic expression graphs.
89
+
90
+ Parameters
91
+ ==========
92
+
93
+ cache : dict
94
+ Cache dictionary to use. If None (default) will use
95
+ the global cache. To create a printer which does not depend on or alter
96
+ global state pass an empty dictionary. Note: the dictionary is not
97
+ copied on initialization of the printer and will be updated in-place,
98
+ so using the same dict object when creating multiple printers or making
99
+ multiple calls to :func:`.aesara_code` or :func:`.aesara_function` means
100
+ the cache is shared between all these applications.
101
+
102
+ Attributes
103
+ ==========
104
+
105
+ cache : dict
106
+ A cache of Aesara variables which have been created for SymPy
107
+ symbol-like objects (e.g. :class:`sympy.core.symbol.Symbol` or
108
+ :class:`sympy.matrices.expressions.MatrixSymbol`). This is used to
109
+ ensure that all references to a given symbol in an expression (or
110
+ multiple expressions) are printed as the same Aesara variable, which is
111
+ created only once. Symbols are differentiated only by name and type. The
112
+ format of the cache's contents should be considered opaque to the user.
113
+ """
114
+ printmethod = "_aesara"
115
+
116
+ def __init__(self, *args, **kwargs):
117
+ self.cache = kwargs.pop('cache', {})
118
+ super().__init__(*args, **kwargs)
119
+
120
+ def _get_key(self, s, name=None, dtype=None, broadcastable=None):
121
+ """ Get the cache key for a SymPy object.
122
+
123
+ Parameters
124
+ ==========
125
+
126
+ s : sympy.core.basic.Basic
127
+ SymPy object to get key for.
128
+
129
+ name : str
130
+ Name of object, if it does not have a ``name`` attribute.
131
+ """
132
+
133
+ if name is None:
134
+ name = s.name
135
+
136
+ return (name, type(s), s.args, dtype, broadcastable)
137
+
138
+ def _get_or_create(self, s, name=None, dtype=None, broadcastable=None):
139
+ """
140
+ Get the Aesara variable for a SymPy symbol from the cache, or create it
141
+ if it does not exist.
142
+ """
143
+
144
+ # Defaults
145
+ if name is None:
146
+ name = s.name
147
+ if dtype is None:
148
+ dtype = 'floatX'
149
+ if broadcastable is None:
150
+ broadcastable = ()
151
+
152
+ key = self._get_key(s, name, dtype=dtype, broadcastable=broadcastable)
153
+
154
+ if key in self.cache:
155
+ return self.cache[key]
156
+
157
+ value = aet.tensor(name=name, dtype=dtype, shape=broadcastable)
158
+ self.cache[key] = value
159
+ return value
160
+
161
+ def _print_Symbol(self, s, **kwargs):
162
+ dtype = kwargs.get('dtypes', {}).get(s)
163
+ bc = kwargs.get('broadcastables', {}).get(s)
164
+ return self._get_or_create(s, dtype=dtype, broadcastable=bc)
165
+
166
+ def _print_AppliedUndef(self, s, **kwargs):
167
+ name = str(type(s)) + '_' + str(s.args[0])
168
+ dtype = kwargs.get('dtypes', {}).get(s)
169
+ bc = kwargs.get('broadcastables', {}).get(s)
170
+ return self._get_or_create(s, name=name, dtype=dtype, broadcastable=bc)
171
+
172
+ def _print_Basic(self, expr, **kwargs):
173
+ op = mapping[type(expr)]
174
+ children = [self._print(arg, **kwargs) for arg in expr.args]
175
+ return op(*children)
176
+
177
+ def _print_Number(self, n, **kwargs):
178
+ # Integers already taken care of below, interpret as float
179
+ return float(n.evalf())
180
+
181
+ def _print_MatrixSymbol(self, X, **kwargs):
182
+ dtype = kwargs.get('dtypes', {}).get(X)
183
+ return self._get_or_create(X, dtype=dtype, broadcastable=(None, None))
184
+
185
+ def _print_DenseMatrix(self, X, **kwargs):
186
+ if not hasattr(aet, 'stacklists'):
187
+ raise NotImplementedError(
188
+ "Matrix translation not yet supported in this version of Aesara")
189
+
190
+ return aet.stacklists([
191
+ [self._print(arg, **kwargs) for arg in L]
192
+ for L in X.tolist()
193
+ ])
194
+
195
+ _print_ImmutableMatrix = _print_ImmutableDenseMatrix = _print_DenseMatrix
196
+
197
+ def _print_MatMul(self, expr, **kwargs):
198
+ children = [self._print(arg, **kwargs) for arg in expr.args]
199
+ result = children[0]
200
+ for child in children[1:]:
201
+ result = aet.dot(result, child)
202
+ return result
203
+
204
+ def _print_MatPow(self, expr, **kwargs):
205
+ children = [self._print(arg, **kwargs) for arg in expr.args]
206
+ result = 1
207
+ if isinstance(children[1], int) and children[1] > 0:
208
+ for i in range(children[1]):
209
+ result = aet.dot(result, children[0])
210
+ else:
211
+ raise NotImplementedError('''Only non-negative integer
212
+ powers of matrices can be handled by Aesara at the moment''')
213
+ return result
214
+
215
+ def _print_MatrixSlice(self, expr, **kwargs):
216
+ parent = self._print(expr.parent, **kwargs)
217
+ rowslice = self._print(slice(*expr.rowslice), **kwargs)
218
+ colslice = self._print(slice(*expr.colslice), **kwargs)
219
+ return parent[rowslice, colslice]
220
+
221
+ def _print_BlockMatrix(self, expr, **kwargs):
222
+ nrows, ncols = expr.blocks.shape
223
+ blocks = [[self._print(expr.blocks[r, c], **kwargs)
224
+ for c in range(ncols)]
225
+ for r in range(nrows)]
226
+ return aet.join(0, *[aet.join(1, *row) for row in blocks])
227
+
228
+
229
+ def _print_slice(self, expr, **kwargs):
230
+ return slice(*[self._print(i, **kwargs)
231
+ if isinstance(i, sympy.Basic) else i
232
+ for i in (expr.start, expr.stop, expr.step)])
233
+
234
+ def _print_Pi(self, expr, **kwargs):
235
+ return math.pi
236
+
237
+ def _print_Piecewise(self, expr, **kwargs):
238
+ import numpy as np
239
+ e, cond = expr.args[0].args # First condition and corresponding value
240
+
241
+ # Print conditional expression and value for first condition
242
+ p_cond = self._print(cond, **kwargs)
243
+ p_e = self._print(e, **kwargs)
244
+
245
+ # One condition only
246
+ if len(expr.args) == 1:
247
+ # Return value if condition else NaN
248
+ return aet.switch(p_cond, p_e, np.nan)
249
+
250
+ # Return value_1 if condition_1 else evaluate remaining conditions
251
+ p_remaining = self._print(sympy.Piecewise(*expr.args[1:]), **kwargs)
252
+ return aet.switch(p_cond, p_e, p_remaining)
253
+
254
+ def _print_Rational(self, expr, **kwargs):
255
+ return true_divide(self._print(expr.p, **kwargs),
256
+ self._print(expr.q, **kwargs))
257
+
258
+ def _print_Integer(self, expr, **kwargs):
259
+ return expr.p
260
+
261
+ def _print_factorial(self, expr, **kwargs):
262
+ return self._print(sympy.gamma(expr.args[0] + 1), **kwargs)
263
+
264
+ def _print_Derivative(self, deriv, **kwargs):
265
+ from aesara.gradient import Rop
266
+
267
+ rv = self._print(deriv.expr, **kwargs)
268
+ for var in deriv.variables:
269
+ var = self._print(var, **kwargs)
270
+ rv = Rop(rv, var, aet.ones_like(var))
271
+ return rv
272
+
273
+ def emptyPrinter(self, expr):
274
+ return expr
275
+
276
+ def doprint(self, expr, dtypes=None, broadcastables=None):
277
+ """ Convert a SymPy expression to a Aesara graph variable.
278
+
279
+ The ``dtypes`` and ``broadcastables`` arguments are used to specify the
280
+ data type, dimension, and broadcasting behavior of the Aesara variables
281
+ corresponding to the free symbols in ``expr``. Each is a mapping from
282
+ SymPy symbols to the value of the corresponding argument to
283
+ ``aesara.tensor.var.TensorVariable``.
284
+
285
+ See the corresponding `documentation page`__ for more information on
286
+ broadcasting in Aesara.
287
+
288
+
289
+ .. __: https://aesara.readthedocs.io/en/latest/reference/tensor/shapes.html#broadcasting
290
+
291
+ Parameters
292
+ ==========
293
+
294
+ expr : sympy.core.expr.Expr
295
+ SymPy expression to print.
296
+
297
+ dtypes : dict
298
+ Mapping from SymPy symbols to Aesara datatypes to use when creating
299
+ new Aesara variables for those symbols. Corresponds to the ``dtype``
300
+ argument to ``aesara.tensor.var.TensorVariable``. Defaults to ``'floatX'``
301
+ for symbols not included in the mapping.
302
+
303
+ broadcastables : dict
304
+ Mapping from SymPy symbols to the value of the ``broadcastable``
305
+ argument to ``aesara.tensor.var.TensorVariable`` to use when creating Aesara
306
+ variables for those symbols. Defaults to the empty tuple for symbols
307
+ not included in the mapping (resulting in a scalar).
308
+
309
+ Returns
310
+ =======
311
+
312
+ aesara.graph.basic.Variable
313
+ A variable corresponding to the expression's value in a Aesara
314
+ symbolic expression graph.
315
+
316
+ """
317
+ if dtypes is None:
318
+ dtypes = {}
319
+ if broadcastables is None:
320
+ broadcastables = {}
321
+
322
+ return self._print(expr, dtypes=dtypes, broadcastables=broadcastables)
323
+
324
+
325
+ global_cache: dict[Any, Any] = {}
326
+
327
+
328
+ def aesara_code(expr, cache=None, **kwargs):
329
+ """
330
+ Convert a SymPy expression into a Aesara graph variable.
331
+
332
+ Parameters
333
+ ==========
334
+
335
+ expr : sympy.core.expr.Expr
336
+ SymPy expression object to convert.
337
+
338
+ cache : dict
339
+ Cached Aesara variables (see :class:`AesaraPrinter.cache
340
+ <AesaraPrinter>`). Defaults to the module-level global cache.
341
+
342
+ dtypes : dict
343
+ Passed to :meth:`.AesaraPrinter.doprint`.
344
+
345
+ broadcastables : dict
346
+ Passed to :meth:`.AesaraPrinter.doprint`.
347
+
348
+ Returns
349
+ =======
350
+
351
+ aesara.graph.basic.Variable
352
+ A variable corresponding to the expression's value in a Aesara symbolic
353
+ expression graph.
354
+
355
+ """
356
+ sympy_deprecation_warning(
357
+ """
358
+ The aesara_code function is deprecated.
359
+ """,
360
+ deprecated_since_version="1.14",
361
+ active_deprecations_target='deprecated-aesaraprinter',
362
+ )
363
+
364
+ if not aesara:
365
+ raise ImportError("aesara is required for aesara_code")
366
+
367
+ if cache is None:
368
+ cache = global_cache
369
+
370
+ return AesaraPrinter(cache=cache, settings={}).doprint(expr, **kwargs)
371
+
372
+
373
+ def dim_handling(inputs, dim=None, dims=None, broadcastables=None):
374
+ r"""
375
+ Get value of ``broadcastables`` argument to :func:`.aesara_code` from
376
+ keyword arguments to :func:`.aesara_function`.
377
+
378
+ Included for backwards compatibility.
379
+
380
+ Parameters
381
+ ==========
382
+
383
+ inputs
384
+ Sequence of input symbols.
385
+
386
+ dim : int
387
+ Common number of dimensions for all inputs. Overrides other arguments
388
+ if given.
389
+
390
+ dims : dict
391
+ Mapping from input symbols to number of dimensions. Overrides
392
+ ``broadcastables`` argument if given.
393
+
394
+ broadcastables : dict
395
+ Explicit value of ``broadcastables`` argument to
396
+ :meth:`.AesaraPrinter.doprint`. If not None function will return this value unchanged.
397
+
398
+ Returns
399
+ =======
400
+ dict
401
+ Dictionary mapping elements of ``inputs`` to their "broadcastable"
402
+ values (tuple of ``bool``\ s).
403
+ """
404
+ if dim is not None:
405
+ return dict.fromkeys(inputs, (False,) * dim)
406
+
407
+ if dims is not None:
408
+ maxdim = max(dims.values())
409
+ return {
410
+ s: (False,) * d + (True,) * (maxdim - d)
411
+ for s, d in dims.items()
412
+ }
413
+
414
+ if broadcastables is not None:
415
+ return broadcastables
416
+
417
+ return {}
418
+
419
+
420
+ def aesara_function(inputs, outputs, scalar=False, *,
421
+ dim=None, dims=None, broadcastables=None, **kwargs):
422
+ """
423
+ Create a Aesara function from SymPy expressions.
424
+
425
+ The inputs and outputs are converted to Aesara variables using
426
+ :func:`.aesara_code` and then passed to ``aesara.function``.
427
+
428
+ Parameters
429
+ ==========
430
+
431
+ inputs
432
+ Sequence of symbols which constitute the inputs of the function.
433
+
434
+ outputs
435
+ Sequence of expressions which constitute the outputs(s) of the
436
+ function. The free symbols of each expression must be a subset of
437
+ ``inputs``.
438
+
439
+ scalar : bool
440
+ Convert 0-dimensional arrays in output to scalars. This will return a
441
+ Python wrapper function around the Aesara function object.
442
+
443
+ cache : dict
444
+ Cached Aesara variables (see :class:`AesaraPrinter.cache
445
+ <AesaraPrinter>`). Defaults to the module-level global cache.
446
+
447
+ dtypes : dict
448
+ Passed to :meth:`.AesaraPrinter.doprint`.
449
+
450
+ broadcastables : dict
451
+ Passed to :meth:`.AesaraPrinter.doprint`.
452
+
453
+ dims : dict
454
+ Alternative to ``broadcastables`` argument. Mapping from elements of
455
+ ``inputs`` to integers indicating the dimension of their associated
456
+ arrays/tensors. Overrides ``broadcastables`` argument if given.
457
+
458
+ dim : int
459
+ Another alternative to the ``broadcastables`` argument. Common number of
460
+ dimensions to use for all arrays/tensors.
461
+ ``aesara_function([x, y], [...], dim=2)`` is equivalent to using
462
+ ``broadcastables={x: (False, False), y: (False, False)}``.
463
+
464
+ Returns
465
+ =======
466
+ callable
467
+ A callable object which takes values of ``inputs`` as positional
468
+ arguments and returns an output array for each of the expressions
469
+ in ``outputs``. If ``outputs`` is a single expression the function will
470
+ return a Numpy array, if it is a list of multiple expressions the
471
+ function will return a list of arrays. See description of the ``squeeze``
472
+ argument above for the behavior when a single output is passed in a list.
473
+ The returned object will either be an instance of
474
+ ``aesara.compile.function.types.Function`` or a Python wrapper
475
+ function around one. In both cases, the returned value will have a
476
+ ``aesara_function`` attribute which points to the return value of
477
+ ``aesara.function``.
478
+
479
+ Examples
480
+ ========
481
+
482
+ >>> from sympy.abc import x, y, z
483
+ >>> from sympy.printing.aesaracode import aesara_function
484
+
485
+ A simple function with one input and one output:
486
+
487
+ >>> f1 = aesara_function([x], [x**2 - 1], scalar=True)
488
+ >>> f1(3)
489
+ 8.0
490
+
491
+ A function with multiple inputs and one output:
492
+
493
+ >>> f2 = aesara_function([x, y, z], [(x**z + y**z)**(1/z)], scalar=True)
494
+ >>> f2(3, 4, 2)
495
+ 5.0
496
+
497
+ A function with multiple inputs and multiple outputs:
498
+
499
+ >>> f3 = aesara_function([x, y], [x**2 + y**2, x**2 - y**2], scalar=True)
500
+ >>> f3(2, 3)
501
+ [13.0, -5.0]
502
+
503
+ See also
504
+ ========
505
+
506
+ dim_handling
507
+
508
+ """
509
+ sympy_deprecation_warning(
510
+ """
511
+ The aesara_function function is deprecated.
512
+ """,
513
+ deprecated_since_version="1.14",
514
+ active_deprecations_target='deprecated-aesaraprinter',
515
+ )
516
+
517
+ if not aesara:
518
+ raise ImportError("Aesara is required for aesara_function")
519
+
520
+ # Pop off non-aesara keyword args
521
+ cache = kwargs.pop('cache', {})
522
+ dtypes = kwargs.pop('dtypes', {})
523
+
524
+ broadcastables = dim_handling(
525
+ inputs, dim=dim, dims=dims, broadcastables=broadcastables,
526
+ )
527
+
528
+ # Print inputs/outputs
529
+ code = partial(aesara_code, cache=cache, dtypes=dtypes,
530
+ broadcastables=broadcastables)
531
+ tinputs = list(map(code, inputs))
532
+ toutputs = list(map(code, outputs))
533
+
534
+ #fix constant expressions as variables
535
+ toutputs = [output if isinstance(output, aesara.graph.basic.Variable) else aet.as_tensor_variable(output) for output in toutputs]
536
+
537
+ if len(toutputs) == 1:
538
+ toutputs = toutputs[0]
539
+
540
+ # Compile aesara func
541
+ func = aesara.function(tinputs, toutputs, **kwargs)
542
+
543
+ is_0d = [len(o.variable.broadcastable) == 0 for o in func.outputs]
544
+
545
+ # No wrapper required
546
+ if not scalar or not any(is_0d):
547
+ func.aesara_function = func
548
+ return func
549
+
550
+ # Create wrapper to convert 0-dimensional outputs to scalars
551
+ def wrapper(*args):
552
+ out = func(*args)
553
+ # out can be array(1.0) or [array(1.0), array(2.0)]
554
+
555
+ if is_sequence(out):
556
+ return [o[()] if is_0d[i] else o for i, o in enumerate(out)]
557
+ else:
558
+ return out[()]
559
+
560
+ wrapper.__wrapped__ = func
561
+ wrapper.__doc__ = func.__doc__
562
+ wrapper.aesara_function = func
563
+ return wrapper
.venv/lib/python3.13/site-packages/sympy/printing/cxx.py ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ C++ code printer
3
+ """
4
+
5
+ from itertools import chain
6
+ from sympy.codegen.ast import Type, none
7
+ from .codeprinter import requires
8
+ from .c import C89CodePrinter, C99CodePrinter
9
+
10
+ # These are defined in the other file so we can avoid importing sympy.codegen
11
+ # from the top-level 'import sympy'. Export them here as well.
12
+ from sympy.printing.codeprinter import cxxcode # noqa:F401
13
+
14
+ # from https://en.cppreference.com/w/cpp/keyword
15
+ reserved = {
16
+ 'C++98': [
17
+ 'and', 'and_eq', 'asm', 'auto', 'bitand', 'bitor', 'bool', 'break',
18
+ 'case', 'catch,', 'char', 'class', 'compl', 'const', 'const_cast',
19
+ 'continue', 'default', 'delete', 'do', 'double', 'dynamic_cast',
20
+ 'else', 'enum', 'explicit', 'export', 'extern', 'false', 'float',
21
+ 'for', 'friend', 'goto', 'if', 'inline', 'int', 'long', 'mutable',
22
+ 'namespace', 'new', 'not', 'not_eq', 'operator', 'or', 'or_eq',
23
+ 'private', 'protected', 'public', 'register', 'reinterpret_cast',
24
+ 'return', 'short', 'signed', 'sizeof', 'static', 'static_cast',
25
+ 'struct', 'switch', 'template', 'this', 'throw', 'true', 'try',
26
+ 'typedef', 'typeid', 'typename', 'union', 'unsigned', 'using',
27
+ 'virtual', 'void', 'volatile', 'wchar_t', 'while', 'xor', 'xor_eq'
28
+ ]
29
+ }
30
+
31
+ reserved['C++11'] = reserved['C++98'][:] + [
32
+ 'alignas', 'alignof', 'char16_t', 'char32_t', 'constexpr', 'decltype',
33
+ 'noexcept', 'nullptr', 'static_assert', 'thread_local'
34
+ ]
35
+ reserved['C++17'] = reserved['C++11'][:]
36
+ reserved['C++17'].remove('register')
37
+ # TM TS: atomic_cancel, atomic_commit, atomic_noexcept, synchronized
38
+ # concepts TS: concept, requires
39
+ # module TS: import, module
40
+
41
+
42
+ _math_functions = {
43
+ 'C++98': {
44
+ 'Mod': 'fmod',
45
+ 'ceiling': 'ceil',
46
+ },
47
+ 'C++11': {
48
+ 'gamma': 'tgamma',
49
+ },
50
+ 'C++17': {
51
+ 'beta': 'beta',
52
+ 'Ei': 'expint',
53
+ 'zeta': 'riemann_zeta',
54
+ }
55
+ }
56
+
57
+ # from https://en.cppreference.com/w/cpp/header/cmath
58
+ for k in ('Abs', 'exp', 'log', 'log10', 'sqrt', 'sin', 'cos', 'tan', # 'Pow'
59
+ 'asin', 'acos', 'atan', 'atan2', 'sinh', 'cosh', 'tanh', 'floor'):
60
+ _math_functions['C++98'][k] = k.lower()
61
+
62
+
63
+ for k in ('asinh', 'acosh', 'atanh', 'erf', 'erfc'):
64
+ _math_functions['C++11'][k] = k.lower()
65
+
66
+
67
+ def _attach_print_method(cls, sympy_name, func_name):
68
+ meth_name = '_print_%s' % sympy_name
69
+ if hasattr(cls, meth_name):
70
+ raise ValueError("Edit method (or subclass) instead of overwriting.")
71
+ def _print_method(self, expr):
72
+ return '{}{}({})'.format(self._ns, func_name, ', '.join(map(self._print, expr.args)))
73
+ _print_method.__doc__ = "Prints code for %s" % k
74
+ setattr(cls, meth_name, _print_method)
75
+
76
+
77
+ def _attach_print_methods(cls, cont):
78
+ for sympy_name, cxx_name in cont[cls.standard].items():
79
+ _attach_print_method(cls, sympy_name, cxx_name)
80
+
81
+
82
+ class _CXXCodePrinterBase:
83
+ printmethod = "_cxxcode"
84
+ language = 'C++'
85
+ _ns = 'std::' # namespace
86
+
87
+ def __init__(self, settings=None):
88
+ super().__init__(settings or {})
89
+
90
+ @requires(headers={'algorithm'})
91
+ def _print_Max(self, expr):
92
+ from sympy.functions.elementary.miscellaneous import Max
93
+ if len(expr.args) == 1:
94
+ return self._print(expr.args[0])
95
+ return "%smax(%s, %s)" % (self._ns, self._print(expr.args[0]),
96
+ self._print(Max(*expr.args[1:])))
97
+
98
+ @requires(headers={'algorithm'})
99
+ def _print_Min(self, expr):
100
+ from sympy.functions.elementary.miscellaneous import Min
101
+ if len(expr.args) == 1:
102
+ return self._print(expr.args[0])
103
+ return "%smin(%s, %s)" % (self._ns, self._print(expr.args[0]),
104
+ self._print(Min(*expr.args[1:])))
105
+
106
+ def _print_using(self, expr):
107
+ if expr.alias == none:
108
+ return 'using %s' % expr.type
109
+ else:
110
+ raise ValueError("C++98 does not support type aliases")
111
+
112
+ def _print_Raise(self, rs):
113
+ arg, = rs.args
114
+ return 'throw %s' % self._print(arg)
115
+
116
+ @requires(headers={'stdexcept'})
117
+ def _print_RuntimeError_(self, re):
118
+ message, = re.args
119
+ return "%sruntime_error(%s)" % (self._ns, self._print(message))
120
+
121
+
122
+ class CXX98CodePrinter(_CXXCodePrinterBase, C89CodePrinter):
123
+ standard = 'C++98'
124
+ reserved_words = set(reserved['C++98'])
125
+
126
+
127
+ # _attach_print_methods(CXX98CodePrinter, _math_functions)
128
+
129
+
130
+ class CXX11CodePrinter(_CXXCodePrinterBase, C99CodePrinter):
131
+ standard = 'C++11'
132
+ reserved_words = set(reserved['C++11'])
133
+ type_mappings = dict(chain(
134
+ CXX98CodePrinter.type_mappings.items(),
135
+ {
136
+ Type('int8'): ('int8_t', {'cstdint'}),
137
+ Type('int16'): ('int16_t', {'cstdint'}),
138
+ Type('int32'): ('int32_t', {'cstdint'}),
139
+ Type('int64'): ('int64_t', {'cstdint'}),
140
+ Type('uint8'): ('uint8_t', {'cstdint'}),
141
+ Type('uint16'): ('uint16_t', {'cstdint'}),
142
+ Type('uint32'): ('uint32_t', {'cstdint'}),
143
+ Type('uint64'): ('uint64_t', {'cstdint'}),
144
+ Type('complex64'): ('std::complex<float>', {'complex'}),
145
+ Type('complex128'): ('std::complex<double>', {'complex'}),
146
+ Type('bool'): ('bool', None),
147
+ }.items()
148
+ ))
149
+
150
+ def _print_using(self, expr):
151
+ if expr.alias == none:
152
+ return super()._print_using(expr)
153
+ else:
154
+ return 'using %(alias)s = %(type)s' % expr.kwargs(apply=self._print)
155
+
156
+ # _attach_print_methods(CXX11CodePrinter, _math_functions)
157
+
158
+
159
+ class CXX17CodePrinter(_CXXCodePrinterBase, C99CodePrinter):
160
+ standard = 'C++17'
161
+ reserved_words = set(reserved['C++17'])
162
+
163
+ _kf = dict(C99CodePrinter._kf, **_math_functions['C++17'])
164
+
165
+ def _print_beta(self, expr):
166
+ return self._print_math_func(expr)
167
+
168
+ def _print_Ei(self, expr):
169
+ return self._print_math_func(expr)
170
+
171
+ def _print_zeta(self, expr):
172
+ return self._print_math_func(expr)
173
+
174
+
175
+ # _attach_print_methods(CXX17CodePrinter, _math_functions)
176
+
177
+ cxx_code_printers = {
178
+ 'c++98': CXX98CodePrinter,
179
+ 'c++11': CXX11CodePrinter,
180
+ 'c++17': CXX17CodePrinter
181
+ }
.venv/lib/python3.13/site-packages/sympy/printing/glsl.py ADDED
@@ -0,0 +1,548 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from sympy.core import Basic, S
4
+ from sympy.core.function import Lambda
5
+ from sympy.core.numbers import equal_valued
6
+ from sympy.printing.codeprinter import CodePrinter
7
+ from sympy.printing.precedence import precedence
8
+ from functools import reduce
9
+
10
+ known_functions = {
11
+ 'Abs': 'abs',
12
+ 'sin': 'sin',
13
+ 'cos': 'cos',
14
+ 'tan': 'tan',
15
+ 'acos': 'acos',
16
+ 'asin': 'asin',
17
+ 'atan': 'atan',
18
+ 'atan2': 'atan',
19
+ 'ceiling': 'ceil',
20
+ 'floor': 'floor',
21
+ 'sign': 'sign',
22
+ 'exp': 'exp',
23
+ 'log': 'log',
24
+ 'add': 'add',
25
+ 'sub': 'sub',
26
+ 'mul': 'mul',
27
+ 'pow': 'pow'
28
+ }
29
+
30
+ class GLSLPrinter(CodePrinter):
31
+ """
32
+ Rudimentary, generic GLSL printing tools.
33
+
34
+ Additional settings:
35
+ 'use_operators': Boolean (should the printer use operators for +,-,*, or functions?)
36
+ """
37
+ _not_supported: set[Basic] = set()
38
+ printmethod = "_glsl"
39
+ language = "GLSL"
40
+
41
+ _default_settings = dict(CodePrinter._default_settings, **{
42
+ 'use_operators': True,
43
+ 'zero': 0,
44
+ 'mat_nested': False,
45
+ 'mat_separator': ',\n',
46
+ 'mat_transpose': False,
47
+ 'array_type': 'float',
48
+ 'glsl_types': True,
49
+
50
+ 'precision': 9,
51
+ 'user_functions': {},
52
+ 'contract': True,
53
+ })
54
+
55
+ def __init__(self, settings={}):
56
+ CodePrinter.__init__(self, settings)
57
+ self.known_functions = dict(known_functions)
58
+ userfuncs = settings.get('user_functions', {})
59
+ self.known_functions.update(userfuncs)
60
+
61
+ def _rate_index_position(self, p):
62
+ return p*5
63
+
64
+ def _get_statement(self, codestring):
65
+ return "%s;" % codestring
66
+
67
+ def _get_comment(self, text):
68
+ return "// {}".format(text)
69
+
70
+ def _declare_number_const(self, name, value):
71
+ return "float {} = {};".format(name, value)
72
+
73
+ def _format_code(self, lines):
74
+ return self.indent_code(lines)
75
+
76
+ def indent_code(self, code):
77
+ """Accepts a string of code or a list of code lines"""
78
+
79
+ if isinstance(code, str):
80
+ code_lines = self.indent_code(code.splitlines(True))
81
+ return ''.join(code_lines)
82
+
83
+ tab = " "
84
+ inc_token = ('{', '(', '{\n', '(\n')
85
+ dec_token = ('}', ')')
86
+
87
+ code = [line.lstrip(' \t') for line in code]
88
+
89
+ increase = [int(any(map(line.endswith, inc_token))) for line in code]
90
+ decrease = [int(any(map(line.startswith, dec_token))) for line in code]
91
+
92
+ pretty = []
93
+ level = 0
94
+ for n, line in enumerate(code):
95
+ if line in ('', '\n'):
96
+ pretty.append(line)
97
+ continue
98
+ level -= decrease[n]
99
+ pretty.append("%s%s" % (tab*level, line))
100
+ level += increase[n]
101
+ return pretty
102
+
103
+ def _print_MatrixBase(self, mat):
104
+ mat_separator = self._settings['mat_separator']
105
+ mat_transpose = self._settings['mat_transpose']
106
+ column_vector = (mat.rows == 1) if mat_transpose else (mat.cols == 1)
107
+ A = mat.transpose() if mat_transpose != column_vector else mat
108
+
109
+ glsl_types = self._settings['glsl_types']
110
+ array_type = self._settings['array_type']
111
+ array_size = A.cols*A.rows
112
+ array_constructor = "{}[{}]".format(array_type, array_size)
113
+
114
+ if A.cols == 1:
115
+ return self._print(A[0])
116
+ if A.rows <= 4 and A.cols <= 4 and glsl_types:
117
+ if A.rows == 1:
118
+ return "vec{}{}".format(
119
+ A.cols, A.table(self,rowstart='(',rowend=')')
120
+ )
121
+ elif A.rows == A.cols:
122
+ return "mat{}({})".format(
123
+ A.rows, A.table(self,rowsep=', ',
124
+ rowstart='',rowend='')
125
+ )
126
+ else:
127
+ return "mat{}x{}({})".format(
128
+ A.cols, A.rows,
129
+ A.table(self,rowsep=', ',
130
+ rowstart='',rowend='')
131
+ )
132
+ elif S.One in A.shape:
133
+ return "{}({})".format(
134
+ array_constructor,
135
+ A.table(self,rowsep=mat_separator,rowstart='',rowend='')
136
+ )
137
+ elif not self._settings['mat_nested']:
138
+ return "{}(\n{}\n) /* a {}x{} matrix */".format(
139
+ array_constructor,
140
+ A.table(self,rowsep=mat_separator,rowstart='',rowend=''),
141
+ A.rows, A.cols
142
+ )
143
+ elif self._settings['mat_nested']:
144
+ return "{}[{}][{}](\n{}\n)".format(
145
+ array_type, A.rows, A.cols,
146
+ A.table(self,rowsep=mat_separator,rowstart='float[](',rowend=')')
147
+ )
148
+
149
+ def _print_SparseRepMatrix(self, mat):
150
+ # do not allow sparse matrices to be made dense
151
+ return self._print_not_supported(mat)
152
+
153
+ def _traverse_matrix_indices(self, mat):
154
+ mat_transpose = self._settings['mat_transpose']
155
+ if mat_transpose:
156
+ rows,cols = mat.shape
157
+ else:
158
+ cols,rows = mat.shape
159
+ return ((i, j) for i in range(cols) for j in range(rows))
160
+
161
+ def _print_MatrixElement(self, expr):
162
+ # print('begin _print_MatrixElement')
163
+ nest = self._settings['mat_nested']
164
+ glsl_types = self._settings['glsl_types']
165
+ mat_transpose = self._settings['mat_transpose']
166
+ if mat_transpose:
167
+ cols,rows = expr.parent.shape
168
+ i,j = expr.j,expr.i
169
+ else:
170
+ rows,cols = expr.parent.shape
171
+ i,j = expr.i,expr.j
172
+ pnt = self._print(expr.parent)
173
+ if glsl_types and ((rows <= 4 and cols <=4) or nest):
174
+ return "{}[{}][{}]".format(pnt, i, j)
175
+ else:
176
+ return "{}[{}]".format(pnt, i + j*rows)
177
+
178
+ def _print_list(self, expr):
179
+ l = ', '.join(self._print(item) for item in expr)
180
+ glsl_types = self._settings['glsl_types']
181
+ array_type = self._settings['array_type']
182
+ array_size = len(expr)
183
+ array_constructor = '{}[{}]'.format(array_type, array_size)
184
+
185
+ if array_size <= 4 and glsl_types:
186
+ return 'vec{}({})'.format(array_size, l)
187
+ else:
188
+ return '{}({})'.format(array_constructor, l)
189
+
190
+ _print_tuple = _print_list
191
+ _print_Tuple = _print_list
192
+
193
+ def _get_loop_opening_ending(self, indices):
194
+ open_lines = []
195
+ close_lines = []
196
+ loopstart = "for (int %(varble)s=%(start)s; %(varble)s<%(end)s; %(varble)s++){"
197
+ for i in indices:
198
+ # GLSL arrays start at 0 and end at dimension-1
199
+ open_lines.append(loopstart % {
200
+ 'varble': self._print(i.label),
201
+ 'start': self._print(i.lower),
202
+ 'end': self._print(i.upper + 1)})
203
+ close_lines.append("}")
204
+ return open_lines, close_lines
205
+
206
+ def _print_Function_with_args(self, func, func_args):
207
+ if func in self.known_functions:
208
+ cond_func = self.known_functions[func]
209
+ func = None
210
+ if isinstance(cond_func, str):
211
+ func = cond_func
212
+ else:
213
+ for cond, func in cond_func:
214
+ if cond(func_args):
215
+ break
216
+ if func is not None:
217
+ try:
218
+ return func(*[self.parenthesize(item, 0) for item in func_args])
219
+ except TypeError:
220
+ return '{}({})'.format(func, self.stringify(func_args, ", "))
221
+ elif isinstance(func, Lambda):
222
+ # inlined function
223
+ return self._print(func(*func_args))
224
+ else:
225
+ return self._print_not_supported(func)
226
+
227
+ def _print_Piecewise(self, expr):
228
+ from sympy.codegen.ast import Assignment
229
+ if expr.args[-1].cond != True:
230
+ # We need the last conditional to be a True, otherwise the resulting
231
+ # function may not return a result.
232
+ raise ValueError("All Piecewise expressions must contain an "
233
+ "(expr, True) statement to be used as a default "
234
+ "condition. Without one, the generated "
235
+ "expression may not evaluate to anything under "
236
+ "some condition.")
237
+ lines = []
238
+ if expr.has(Assignment):
239
+ for i, (e, c) in enumerate(expr.args):
240
+ if i == 0:
241
+ lines.append("if (%s) {" % self._print(c))
242
+ elif i == len(expr.args) - 1 and c == True:
243
+ lines.append("else {")
244
+ else:
245
+ lines.append("else if (%s) {" % self._print(c))
246
+ code0 = self._print(e)
247
+ lines.append(code0)
248
+ lines.append("}")
249
+ return "\n".join(lines)
250
+ else:
251
+ # The piecewise was used in an expression, need to do inline
252
+ # operators. This has the downside that inline operators will
253
+ # not work for statements that span multiple lines (Matrix or
254
+ # Indexed expressions).
255
+ ecpairs = ["((%s) ? (\n%s\n)\n" % (self._print(c),
256
+ self._print(e))
257
+ for e, c in expr.args[:-1]]
258
+ last_line = ": (\n%s\n)" % self._print(expr.args[-1].expr)
259
+ return ": ".join(ecpairs) + last_line + " ".join([")"*len(ecpairs)])
260
+
261
+ def _print_Indexed(self, expr):
262
+ # calculate index for 1d array
263
+ dims = expr.shape
264
+ elem = S.Zero
265
+ offset = S.One
266
+ for i in reversed(range(expr.rank)):
267
+ elem += expr.indices[i]*offset
268
+ offset *= dims[i]
269
+ return "{}[{}]".format(
270
+ self._print(expr.base.label),
271
+ self._print(elem)
272
+ )
273
+
274
+ def _print_Pow(self, expr):
275
+ PREC = precedence(expr)
276
+ if equal_valued(expr.exp, -1):
277
+ return '1.0/%s' % (self.parenthesize(expr.base, PREC))
278
+ elif equal_valued(expr.exp, 0.5):
279
+ return 'sqrt(%s)' % self._print(expr.base)
280
+ else:
281
+ try:
282
+ e = self._print(float(expr.exp))
283
+ except TypeError:
284
+ e = self._print(expr.exp)
285
+ return self._print_Function_with_args('pow', (
286
+ self._print(expr.base),
287
+ e
288
+ ))
289
+
290
+ def _print_int(self, expr):
291
+ return str(float(expr))
292
+
293
+ def _print_Rational(self, expr):
294
+ return "{}.0/{}.0".format(expr.p, expr.q)
295
+
296
+ def _print_Relational(self, expr):
297
+ lhs_code = self._print(expr.lhs)
298
+ rhs_code = self._print(expr.rhs)
299
+ op = expr.rel_op
300
+ return "{} {} {}".format(lhs_code, op, rhs_code)
301
+
302
+ def _print_Add(self, expr, order=None):
303
+ if self._settings['use_operators']:
304
+ return CodePrinter._print_Add(self, expr, order=order)
305
+
306
+ terms = expr.as_ordered_terms()
307
+
308
+ def partition(p,l):
309
+ return reduce(lambda x, y: (x[0]+[y], x[1]) if p(y) else (x[0], x[1]+[y]), l, ([], []))
310
+ def add(a,b):
311
+ return self._print_Function_with_args('add', (a, b))
312
+ # return self.known_functions['add']+'(%s, %s)' % (a,b)
313
+ neg, pos = partition(lambda arg: arg.could_extract_minus_sign(), terms)
314
+ if pos:
315
+ s = pos = reduce(lambda a,b: add(a,b), (self._print(t) for t in pos))
316
+ else:
317
+ s = pos = self._print(self._settings['zero'])
318
+
319
+ if neg:
320
+ # sum the absolute values of the negative terms
321
+ neg = reduce(lambda a,b: add(a,b), (self._print(-n) for n in neg))
322
+ # then subtract them from the positive terms
323
+ s = self._print_Function_with_args('sub', (pos,neg))
324
+ # s = self.known_functions['sub']+'(%s, %s)' % (pos,neg)
325
+ return s
326
+
327
+ def _print_Mul(self, expr, **kwargs):
328
+ if self._settings['use_operators']:
329
+ return CodePrinter._print_Mul(self, expr, **kwargs)
330
+ terms = expr.as_ordered_factors()
331
+ def mul(a,b):
332
+ # return self.known_functions['mul']+'(%s, %s)' % (a,b)
333
+ return self._print_Function_with_args('mul', (a,b))
334
+
335
+ s = reduce(lambda a,b: mul(a,b), (self._print(t) for t in terms))
336
+ return s
337
+
338
+ def glsl_code(expr,assign_to=None,**settings):
339
+ """Converts an expr to a string of GLSL code
340
+
341
+ Parameters
342
+ ==========
343
+
344
+ expr : Expr
345
+ A SymPy expression to be converted.
346
+ assign_to : optional
347
+ When given, the argument is used for naming the variable or variables
348
+ to which the expression is assigned. Can be a string, ``Symbol``,
349
+ ``MatrixSymbol`` or ``Indexed`` type object. In cases where ``expr``
350
+ would be printed as an array, a list of string or ``Symbol`` objects
351
+ can also be passed.
352
+
353
+ This is helpful in case of line-wrapping, or for expressions that
354
+ generate multi-line statements. It can also be used to spread an array-like
355
+ expression into multiple assignments.
356
+ use_operators: bool, optional
357
+ If set to False, then *,/,+,- operators will be replaced with functions
358
+ mul, add, and sub, which must be implemented by the user, e.g. for
359
+ implementing non-standard rings or emulated quad/octal precision.
360
+ [default=True]
361
+ glsl_types: bool, optional
362
+ Set this argument to ``False`` in order to avoid using the ``vec`` and ``mat``
363
+ types. The printer will instead use arrays (or nested arrays).
364
+ [default=True]
365
+ mat_nested: bool, optional
366
+ GLSL version 4.3 and above support nested arrays (arrays of arrays). Set this to ``True``
367
+ to render matrices as nested arrays.
368
+ [default=False]
369
+ mat_separator: str, optional
370
+ By default, matrices are rendered with newlines using this separator,
371
+ making them easier to read, but less compact. By removing the newline
372
+ this option can be used to make them more vertically compact.
373
+ [default=',\n']
374
+ mat_transpose: bool, optional
375
+ GLSL's matrix multiplication implementation assumes column-major indexing.
376
+ By default, this printer ignores that convention. Setting this option to
377
+ ``True`` transposes all matrix output.
378
+ [default=False]
379
+ array_type: str, optional
380
+ The GLSL array constructor type.
381
+ [default='float']
382
+ precision : integer, optional
383
+ The precision for numbers such as pi [default=15].
384
+ user_functions : dict, optional
385
+ A dictionary where keys are ``FunctionClass`` instances and values are
386
+ their string representations. Alternatively, the dictionary value can
387
+ be a list of tuples i.e. [(argument_test, js_function_string)]. See
388
+ below for examples.
389
+ human : bool, optional
390
+ If True, the result is a single string that may contain some constant
391
+ declarations for the number symbols. If False, the same information is
392
+ returned in a tuple of (symbols_to_declare, not_supported_functions,
393
+ code_text). [default=True].
394
+ contract: bool, optional
395
+ If True, ``Indexed`` instances are assumed to obey tensor contraction
396
+ rules and the corresponding nested loops over indices are generated.
397
+ Setting contract=False will not generate loops, instead the user is
398
+ responsible to provide values for the indices in the code.
399
+ [default=True].
400
+
401
+ Examples
402
+ ========
403
+
404
+ >>> from sympy import glsl_code, symbols, Rational, sin, ceiling, Abs
405
+ >>> x, tau = symbols("x, tau")
406
+ >>> glsl_code((2*tau)**Rational(7, 2))
407
+ '8*sqrt(2)*pow(tau, 3.5)'
408
+ >>> glsl_code(sin(x), assign_to="float y")
409
+ 'float y = sin(x);'
410
+
411
+ Various GLSL types are supported:
412
+ >>> from sympy import Matrix, glsl_code
413
+ >>> glsl_code(Matrix([1,2,3]))
414
+ 'vec3(1, 2, 3)'
415
+
416
+ >>> glsl_code(Matrix([[1, 2],[3, 4]]))
417
+ 'mat2(1, 2, 3, 4)'
418
+
419
+ Pass ``mat_transpose = True`` to switch to column-major indexing:
420
+ >>> glsl_code(Matrix([[1, 2],[3, 4]]), mat_transpose = True)
421
+ 'mat2(1, 3, 2, 4)'
422
+
423
+ By default, larger matrices get collapsed into float arrays:
424
+ >>> print(glsl_code( Matrix([[1,2,3,4,5],[6,7,8,9,10]]) ))
425
+ float[10](
426
+ 1, 2, 3, 4, 5,
427
+ 6, 7, 8, 9, 10
428
+ ) /* a 2x5 matrix */
429
+
430
+ The type of array constructor used to print GLSL arrays can be controlled
431
+ via the ``array_type`` parameter:
432
+ >>> glsl_code(Matrix([1,2,3,4,5]), array_type='int')
433
+ 'int[5](1, 2, 3, 4, 5)'
434
+
435
+ Passing a list of strings or ``symbols`` to the ``assign_to`` parameter will yield
436
+ a multi-line assignment for each item in an array-like expression:
437
+ >>> x_struct_members = symbols('x.a x.b x.c x.d')
438
+ >>> print(glsl_code(Matrix([1,2,3,4]), assign_to=x_struct_members))
439
+ x.a = 1;
440
+ x.b = 2;
441
+ x.c = 3;
442
+ x.d = 4;
443
+
444
+ This could be useful in cases where it's desirable to modify members of a
445
+ GLSL ``Struct``. It could also be used to spread items from an array-like
446
+ expression into various miscellaneous assignments:
447
+ >>> misc_assignments = ('x[0]', 'x[1]', 'float y', 'float z')
448
+ >>> print(glsl_code(Matrix([1,2,3,4]), assign_to=misc_assignments))
449
+ x[0] = 1;
450
+ x[1] = 2;
451
+ float y = 3;
452
+ float z = 4;
453
+
454
+ Passing ``mat_nested = True`` instead prints out nested float arrays, which are
455
+ supported in GLSL 4.3 and above.
456
+ >>> mat = Matrix([
457
+ ... [ 0, 1, 2],
458
+ ... [ 3, 4, 5],
459
+ ... [ 6, 7, 8],
460
+ ... [ 9, 10, 11],
461
+ ... [12, 13, 14]])
462
+ >>> print(glsl_code( mat, mat_nested = True ))
463
+ float[5][3](
464
+ float[]( 0, 1, 2),
465
+ float[]( 3, 4, 5),
466
+ float[]( 6, 7, 8),
467
+ float[]( 9, 10, 11),
468
+ float[](12, 13, 14)
469
+ )
470
+
471
+
472
+
473
+ Custom printing can be defined for certain types by passing a dictionary of
474
+ "type" : "function" to the ``user_functions`` kwarg. Alternatively, the
475
+ dictionary value can be a list of tuples i.e. [(argument_test,
476
+ js_function_string)].
477
+
478
+ >>> custom_functions = {
479
+ ... "ceiling": "CEIL",
480
+ ... "Abs": [(lambda x: not x.is_integer, "fabs"),
481
+ ... (lambda x: x.is_integer, "ABS")]
482
+ ... }
483
+ >>> glsl_code(Abs(x) + ceiling(x), user_functions=custom_functions)
484
+ 'fabs(x) + CEIL(x)'
485
+
486
+ If further control is needed, addition, subtraction, multiplication and
487
+ division operators can be replaced with ``add``, ``sub``, and ``mul``
488
+ functions. This is done by passing ``use_operators = False``:
489
+
490
+ >>> x,y,z = symbols('x,y,z')
491
+ >>> glsl_code(x*(y+z), use_operators = False)
492
+ 'mul(x, add(y, z))'
493
+ >>> glsl_code(x*(y+z*(x-y)**z), use_operators = False)
494
+ 'mul(x, add(y, mul(z, pow(sub(x, y), z))))'
495
+
496
+ ``Piecewise`` expressions are converted into conditionals. If an
497
+ ``assign_to`` variable is provided an if statement is created, otherwise
498
+ the ternary operator is used. Note that if the ``Piecewise`` lacks a
499
+ default term, represented by ``(expr, True)`` then an error will be thrown.
500
+ This is to prevent generating an expression that may not evaluate to
501
+ anything.
502
+
503
+ >>> from sympy import Piecewise
504
+ >>> expr = Piecewise((x + 1, x > 0), (x, True))
505
+ >>> print(glsl_code(expr, tau))
506
+ if (x > 0) {
507
+ tau = x + 1;
508
+ }
509
+ else {
510
+ tau = x;
511
+ }
512
+
513
+ Support for loops is provided through ``Indexed`` types. With
514
+ ``contract=True`` these expressions will be turned into loops, whereas
515
+ ``contract=False`` will just print the assignment expression that should be
516
+ looped over:
517
+
518
+ >>> from sympy import Eq, IndexedBase, Idx
519
+ >>> len_y = 5
520
+ >>> y = IndexedBase('y', shape=(len_y,))
521
+ >>> t = IndexedBase('t', shape=(len_y,))
522
+ >>> Dy = IndexedBase('Dy', shape=(len_y-1,))
523
+ >>> i = Idx('i', len_y-1)
524
+ >>> e=Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i]))
525
+ >>> glsl_code(e.rhs, assign_to=e.lhs, contract=False)
526
+ 'Dy[i] = (y[i + 1] - y[i])/(t[i + 1] - t[i]);'
527
+
528
+ >>> from sympy import Matrix, MatrixSymbol
529
+ >>> mat = Matrix([x**2, Piecewise((x + 1, x > 0), (x, True)), sin(x)])
530
+ >>> A = MatrixSymbol('A', 3, 1)
531
+ >>> print(glsl_code(mat, A))
532
+ A[0][0] = pow(x, 2.0);
533
+ if (x > 0) {
534
+ A[1][0] = x + 1;
535
+ }
536
+ else {
537
+ A[1][0] = x;
538
+ }
539
+ A[2][0] = sin(x);
540
+ """
541
+ return GLSLPrinter(settings).doprint(expr,assign_to)
542
+
543
+ def print_glsl(expr, **settings):
544
+ """Prints the GLSL representation of the given expression.
545
+
546
+ See GLSLPrinter init function for settings.
547
+ """
548
+ print(glsl_code(expr, **settings))
.venv/lib/python3.13/site-packages/sympy/printing/gtk.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.printing.mathml import mathml
2
+ from sympy.utilities.mathml import c2p
3
+ import tempfile
4
+ import subprocess
5
+
6
+
7
+ def print_gtk(x, start_viewer=True):
8
+ """Print to Gtkmathview, a gtk widget capable of rendering MathML.
9
+
10
+ Needs libgtkmathview-bin"""
11
+ with tempfile.NamedTemporaryFile('w') as file:
12
+ file.write(c2p(mathml(x), simple=True))
13
+ file.flush()
14
+
15
+ if start_viewer:
16
+ subprocess.check_call(('mathmlviewer', file.name))
.venv/lib/python3.13/site-packages/sympy/printing/maple.py ADDED
@@ -0,0 +1,311 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Maple code printer
3
+
4
+ The MapleCodePrinter converts single SymPy expressions into single
5
+ Maple expressions, using the functions defined in the Maple objects where possible.
6
+
7
+
8
+ FIXME: This module is still under actively developed. Some functions may be not completed.
9
+ """
10
+
11
+ from sympy.core import S
12
+ from sympy.core.numbers import Integer, IntegerConstant, equal_valued
13
+ from sympy.printing.codeprinter import CodePrinter
14
+ from sympy.printing.precedence import precedence, PRECEDENCE
15
+
16
+ import sympy
17
+
18
+ _known_func_same_name = (
19
+ 'sin', 'cos', 'tan', 'sec', 'csc', 'cot', 'sinh', 'cosh', 'tanh', 'sech',
20
+ 'csch', 'coth', 'exp', 'floor', 'factorial', 'bernoulli', 'euler',
21
+ 'fibonacci', 'gcd', 'lcm', 'conjugate', 'Ci', 'Chi', 'Ei', 'Li', 'Si', 'Shi',
22
+ 'erf', 'erfc', 'harmonic', 'LambertW',
23
+ 'sqrt', # For automatic rewrites
24
+ )
25
+
26
+ known_functions = {
27
+ # SymPy -> Maple
28
+ 'Abs': 'abs',
29
+ 'log': 'ln',
30
+ 'asin': 'arcsin',
31
+ 'acos': 'arccos',
32
+ 'atan': 'arctan',
33
+ 'asec': 'arcsec',
34
+ 'acsc': 'arccsc',
35
+ 'acot': 'arccot',
36
+ 'asinh': 'arcsinh',
37
+ 'acosh': 'arccosh',
38
+ 'atanh': 'arctanh',
39
+ 'asech': 'arcsech',
40
+ 'acsch': 'arccsch',
41
+ 'acoth': 'arccoth',
42
+ 'ceiling': 'ceil',
43
+ 'Max' : 'max',
44
+ 'Min' : 'min',
45
+
46
+ 'factorial2': 'doublefactorial',
47
+ 'RisingFactorial': 'pochhammer',
48
+ 'besseli': 'BesselI',
49
+ 'besselj': 'BesselJ',
50
+ 'besselk': 'BesselK',
51
+ 'bessely': 'BesselY',
52
+ 'hankelh1': 'HankelH1',
53
+ 'hankelh2': 'HankelH2',
54
+ 'airyai': 'AiryAi',
55
+ 'airybi': 'AiryBi',
56
+ 'appellf1': 'AppellF1',
57
+ 'fresnelc': 'FresnelC',
58
+ 'fresnels': 'FresnelS',
59
+ 'lerchphi' : 'LerchPhi',
60
+ }
61
+
62
+ for _func in _known_func_same_name:
63
+ known_functions[_func] = _func
64
+
65
+ number_symbols = {
66
+ # SymPy -> Maple
67
+ S.Pi: 'Pi',
68
+ S.Exp1: 'exp(1)',
69
+ S.Catalan: 'Catalan',
70
+ S.EulerGamma: 'gamma',
71
+ S.GoldenRatio: '(1/2 + (1/2)*sqrt(5))'
72
+ }
73
+
74
+ spec_relational_ops = {
75
+ # SymPy -> Maple
76
+ '==': '=',
77
+ '!=': '<>'
78
+ }
79
+
80
+ not_supported_symbol = [
81
+ S.ComplexInfinity
82
+ ]
83
+
84
+ class MapleCodePrinter(CodePrinter):
85
+ """
86
+ Printer which converts a SymPy expression into a maple code.
87
+ """
88
+ printmethod = "_maple"
89
+ language = "maple"
90
+
91
+ _operators = {
92
+ 'and': 'and',
93
+ 'or': 'or',
94
+ 'not': 'not ',
95
+ }
96
+
97
+ _default_settings = dict(CodePrinter._default_settings, **{
98
+ 'inline': True,
99
+ 'allow_unknown_functions': True,
100
+ })
101
+
102
+ def __init__(self, settings=None):
103
+ if settings is None:
104
+ settings = {}
105
+ super().__init__(settings)
106
+ self.known_functions = dict(known_functions)
107
+ userfuncs = settings.get('user_functions', {})
108
+ self.known_functions.update(userfuncs)
109
+
110
+ def _get_statement(self, codestring):
111
+ return "%s;" % codestring
112
+
113
+ def _get_comment(self, text):
114
+ return "# {}".format(text)
115
+
116
+ def _declare_number_const(self, name, value):
117
+ return "{} := {};".format(name,
118
+ value.evalf(self._settings['precision']))
119
+
120
+ def _format_code(self, lines):
121
+ return lines
122
+
123
+ def _print_tuple(self, expr):
124
+ return self._print(list(expr))
125
+
126
+ def _print_Tuple(self, expr):
127
+ return self._print(list(expr))
128
+
129
+ def _print_Assignment(self, expr):
130
+ lhs = self._print(expr.lhs)
131
+ rhs = self._print(expr.rhs)
132
+ return "{lhs} := {rhs}".format(lhs=lhs, rhs=rhs)
133
+
134
+ def _print_Pow(self, expr, **kwargs):
135
+ PREC = precedence(expr)
136
+ if equal_valued(expr.exp, -1):
137
+ return '1/%s' % (self.parenthesize(expr.base, PREC))
138
+ elif equal_valued(expr.exp, 0.5):
139
+ return 'sqrt(%s)' % self._print(expr.base)
140
+ elif equal_valued(expr.exp, -0.5):
141
+ return '1/sqrt(%s)' % self._print(expr.base)
142
+ else:
143
+ return '{base}^{exp}'.format(
144
+ base=self.parenthesize(expr.base, PREC),
145
+ exp=self.parenthesize(expr.exp, PREC))
146
+
147
+ def _print_Piecewise(self, expr):
148
+ if (expr.args[-1].cond is not True) and (expr.args[-1].cond != S.BooleanTrue):
149
+ # We need the last conditional to be a True, otherwise the resulting
150
+ # function may not return a result.
151
+ raise ValueError("All Piecewise expressions must contain an "
152
+ "(expr, True) statement to be used as a default "
153
+ "condition. Without one, the generated "
154
+ "expression may not evaluate to anything under "
155
+ "some condition.")
156
+ _coup_list = [
157
+ ("{c}, {e}".format(c=self._print(c),
158
+ e=self._print(e)) if c is not True and c is not S.BooleanTrue else "{e}".format(
159
+ e=self._print(e)))
160
+ for e, c in expr.args]
161
+ _inbrace = ', '.join(_coup_list)
162
+ return 'piecewise({_inbrace})'.format(_inbrace=_inbrace)
163
+
164
+ def _print_Rational(self, expr):
165
+ p, q = int(expr.p), int(expr.q)
166
+ return "{p}/{q}".format(p=str(p), q=str(q))
167
+
168
+ def _print_Relational(self, expr):
169
+ PREC=precedence(expr)
170
+ lhs_code = self.parenthesize(expr.lhs, PREC)
171
+ rhs_code = self.parenthesize(expr.rhs, PREC)
172
+ op = expr.rel_op
173
+ if op in spec_relational_ops:
174
+ op = spec_relational_ops[op]
175
+ return "{lhs} {rel_op} {rhs}".format(lhs=lhs_code, rel_op=op, rhs=rhs_code)
176
+
177
+ def _print_NumberSymbol(self, expr):
178
+ return number_symbols[expr]
179
+
180
+ def _print_NegativeInfinity(self, expr):
181
+ return '-infinity'
182
+
183
+ def _print_Infinity(self, expr):
184
+ return 'infinity'
185
+
186
+ def _print_BooleanTrue(self, expr):
187
+ return "true"
188
+
189
+ def _print_BooleanFalse(self, expr):
190
+ return "false"
191
+
192
+ def _print_bool(self, expr):
193
+ return 'true' if expr else 'false'
194
+
195
+ def _print_NaN(self, expr):
196
+ return 'undefined'
197
+
198
+ def _get_matrix(self, expr, sparse=False):
199
+ if S.Zero in expr.shape:
200
+ _strM = 'Matrix([], storage = {storage})'.format(
201
+ storage='sparse' if sparse else 'rectangular')
202
+ else:
203
+ _strM = 'Matrix({list}, storage = {storage})'.format(
204
+ list=self._print(expr.tolist()),
205
+ storage='sparse' if sparse else 'rectangular')
206
+ return _strM
207
+
208
+ def _print_MatrixElement(self, expr):
209
+ return "{parent}[{i_maple}, {j_maple}]".format(
210
+ parent=self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True),
211
+ i_maple=self._print(expr.i + 1),
212
+ j_maple=self._print(expr.j + 1))
213
+
214
+ def _print_MatrixBase(self, expr):
215
+ return self._get_matrix(expr, sparse=False)
216
+
217
+ def _print_SparseRepMatrix(self, expr):
218
+ return self._get_matrix(expr, sparse=True)
219
+
220
+ def _print_Identity(self, expr):
221
+ if isinstance(expr.rows, (Integer, IntegerConstant)):
222
+ return self._print(sympy.SparseMatrix(expr))
223
+ else:
224
+ return "Matrix({var_size}, shape = identity)".format(var_size=self._print(expr.rows))
225
+
226
+ def _print_MatMul(self, expr):
227
+ PREC=precedence(expr)
228
+ _fact_list = list(expr.args)
229
+ _const = None
230
+ if not isinstance(_fact_list[0], (sympy.MatrixBase, sympy.MatrixExpr,
231
+ sympy.MatrixSlice, sympy.MatrixSymbol)):
232
+ _const, _fact_list = _fact_list[0], _fact_list[1:]
233
+
234
+ if _const is None or _const == 1:
235
+ return '.'.join(self.parenthesize(_m, PREC) for _m in _fact_list)
236
+ else:
237
+ return '{c}*{m}'.format(c=_const, m='.'.join(self.parenthesize(_m, PREC) for _m in _fact_list))
238
+
239
+ def _print_MatPow(self, expr):
240
+ # This function requires LinearAlgebra Function in Maple
241
+ return 'MatrixPower({A}, {n})'.format(A=self._print(expr.base), n=self._print(expr.exp))
242
+
243
+ def _print_HadamardProduct(self, expr):
244
+ PREC = precedence(expr)
245
+ _fact_list = list(expr.args)
246
+ return '*'.join(self.parenthesize(_m, PREC) for _m in _fact_list)
247
+
248
+ def _print_Derivative(self, expr):
249
+ _f, (_var, _order) = expr.args
250
+
251
+ if _order != 1:
252
+ _second_arg = '{var}${order}'.format(var=self._print(_var),
253
+ order=self._print(_order))
254
+ else:
255
+ _second_arg = '{var}'.format(var=self._print(_var))
256
+ return 'diff({func_expr}, {sec_arg})'.format(func_expr=self._print(_f), sec_arg=_second_arg)
257
+
258
+
259
+ def maple_code(expr, assign_to=None, **settings):
260
+ r"""Converts ``expr`` to a string of Maple code.
261
+
262
+ Parameters
263
+ ==========
264
+
265
+ expr : Expr
266
+ A SymPy expression to be converted.
267
+ assign_to : optional
268
+ When given, the argument is used as the name of the variable to which
269
+ the expression is assigned. Can be a string, ``Symbol``,
270
+ ``MatrixSymbol``, or ``Indexed`` type. This can be helpful for
271
+ expressions that generate multi-line statements.
272
+ precision : integer, optional
273
+ The precision for numbers such as pi [default=16].
274
+ user_functions : dict, optional
275
+ A dictionary where keys are ``FunctionClass`` instances and values are
276
+ their string representations. Alternatively, the dictionary value can
277
+ be a list of tuples i.e. [(argument_test, cfunction_string)]. See
278
+ below for examples.
279
+ human : bool, optional
280
+ If True, the result is a single string that may contain some constant
281
+ declarations for the number symbols. If False, the same information is
282
+ returned in a tuple of (symbols_to_declare, not_supported_functions,
283
+ code_text). [default=True].
284
+ contract: bool, optional
285
+ If True, ``Indexed`` instances are assumed to obey tensor contraction
286
+ rules and the corresponding nested loops over indices are generated.
287
+ Setting contract=False will not generate loops, instead the user is
288
+ responsible to provide values for the indices in the code.
289
+ [default=True].
290
+ inline: bool, optional
291
+ If True, we try to create single-statement code instead of multiple
292
+ statements. [default=True].
293
+
294
+ """
295
+ return MapleCodePrinter(settings).doprint(expr, assign_to)
296
+
297
+
298
+ def print_maple_code(expr, **settings):
299
+ """Prints the Maple representation of the given expression.
300
+
301
+ See :func:`maple_code` for the meaning of the optional arguments.
302
+
303
+ Examples
304
+ ========
305
+
306
+ >>> from sympy import print_maple_code, symbols
307
+ >>> x, y = symbols('x y')
308
+ >>> print_maple_code(x, assign_to=y)
309
+ y := x
310
+ """
311
+ print(maple_code(expr, **settings))
.venv/lib/python3.13/site-packages/sympy/printing/preview.py ADDED
@@ -0,0 +1,390 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from os.path import join
3
+ import shutil
4
+ import tempfile
5
+ from pathlib import Path
6
+
7
+ try:
8
+ from subprocess import STDOUT, CalledProcessError, check_output
9
+ except ImportError:
10
+ pass
11
+
12
+ from sympy.utilities.decorator import doctest_depends_on
13
+ from sympy.utilities.misc import debug
14
+ from .latex import latex
15
+
16
+ __doctest_requires__ = {('preview',): ['pyglet']}
17
+
18
+
19
+ def _check_output_no_window(*args, **kwargs):
20
+ # Avoid showing a cmd.exe window when running this
21
+ # on Windows
22
+ if os.name == 'nt':
23
+ creation_flag = 0x08000000 # CREATE_NO_WINDOW
24
+ else:
25
+ creation_flag = 0 # Default value
26
+ return check_output(*args, creationflags=creation_flag, **kwargs)
27
+
28
+
29
+ def system_default_viewer(fname, fmt):
30
+ """ Open fname with the default system viewer.
31
+
32
+ In practice, it is impossible for python to know when the system viewer is
33
+ done. For this reason, we ensure the passed file will not be deleted under
34
+ it, and this function does not attempt to block.
35
+ """
36
+ # copy to a new temporary file that will not be deleted
37
+ with tempfile.NamedTemporaryFile(prefix='sympy-preview-',
38
+ suffix=os.path.splitext(fname)[1],
39
+ delete=False) as temp_f:
40
+ with open(fname, 'rb') as f:
41
+ shutil.copyfileobj(f, temp_f)
42
+
43
+ import platform
44
+ if platform.system() == 'Darwin':
45
+ import subprocess
46
+ subprocess.call(('open', temp_f.name))
47
+ elif platform.system() == 'Windows':
48
+ os.startfile(temp_f.name)
49
+ else:
50
+ import subprocess
51
+ subprocess.call(('xdg-open', temp_f.name))
52
+
53
+
54
+ def pyglet_viewer(fname, fmt):
55
+ try:
56
+ from pyglet import window, image, gl
57
+ from pyglet.window import key
58
+ from pyglet.image.codecs import ImageDecodeException
59
+ except ImportError:
60
+ raise ImportError("pyglet is required for preview.\n visit https://pyglet.org/")
61
+
62
+ try:
63
+ img = image.load(fname)
64
+ except ImageDecodeException:
65
+ raise ValueError("pyglet preview does not work for '{}' files.".format(fmt))
66
+
67
+ offset = 25
68
+
69
+ config = gl.Config(double_buffer=False)
70
+ win = window.Window(
71
+ width=img.width + 2*offset,
72
+ height=img.height + 2*offset,
73
+ caption="SymPy",
74
+ resizable=False,
75
+ config=config
76
+ )
77
+
78
+ win.set_vsync(False)
79
+
80
+ try:
81
+ def on_close():
82
+ win.has_exit = True
83
+
84
+ win.on_close = on_close
85
+
86
+ def on_key_press(symbol, modifiers):
87
+ if symbol in [key.Q, key.ESCAPE]:
88
+ on_close()
89
+
90
+ win.on_key_press = on_key_press
91
+
92
+ def on_expose():
93
+ gl.glClearColor(1.0, 1.0, 1.0, 1.0)
94
+ gl.glClear(gl.GL_COLOR_BUFFER_BIT)
95
+
96
+ img.blit(
97
+ (win.width - img.width) / 2,
98
+ (win.height - img.height) / 2
99
+ )
100
+
101
+ win.on_expose = on_expose
102
+
103
+ while not win.has_exit:
104
+ win.dispatch_events()
105
+ win.flip()
106
+ except KeyboardInterrupt:
107
+ pass
108
+
109
+ win.close()
110
+
111
+
112
+ def _get_latex_main(expr, *, preamble=None, packages=(), extra_preamble=None,
113
+ euler=True, fontsize=None, **latex_settings):
114
+ """
115
+ Generate string of a LaTeX document rendering ``expr``.
116
+ """
117
+ if preamble is None:
118
+ actual_packages = packages + ("amsmath", "amsfonts")
119
+ if euler:
120
+ actual_packages += ("euler",)
121
+ package_includes = "\n" + "\n".join(["\\usepackage{%s}" % p
122
+ for p in actual_packages])
123
+ if extra_preamble:
124
+ package_includes += extra_preamble
125
+
126
+ if not fontsize:
127
+ fontsize = "12pt"
128
+ elif isinstance(fontsize, int):
129
+ fontsize = "{}pt".format(fontsize)
130
+ preamble = r"""\documentclass[varwidth,%s]{standalone}
131
+ %s
132
+
133
+ \begin{document}
134
+ """ % (fontsize, package_includes)
135
+ else:
136
+ if packages or extra_preamble:
137
+ raise ValueError("The \"packages\" or \"extra_preamble\" keywords"
138
+ "must not be set if a "
139
+ "custom LaTeX preamble was specified")
140
+
141
+ if isinstance(expr, str):
142
+ latex_string = expr
143
+ else:
144
+ latex_string = ('$\\displaystyle ' +
145
+ latex(expr, mode='plain', **latex_settings) +
146
+ '$')
147
+
148
+ return preamble + '\n' + latex_string + '\n\n' + r"\end{document}"
149
+
150
+
151
+ @doctest_depends_on(exe=('latex', 'dvipng'), modules=('pyglet',),
152
+ disable_viewers=('evince', 'gimp', 'superior-dvi-viewer'))
153
+ def preview(expr, output='png', viewer=None, euler=True, packages=(),
154
+ filename=None, outputbuffer=None, preamble=None, dvioptions=None,
155
+ outputTexFile=None, extra_preamble=None, fontsize=None,
156
+ **latex_settings):
157
+ r"""
158
+ View expression or LaTeX markup in PNG, DVI, PostScript or PDF form.
159
+
160
+ If the expr argument is an expression, it will be exported to LaTeX and
161
+ then compiled using the available TeX distribution. The first argument,
162
+ 'expr', may also be a LaTeX string. The function will then run the
163
+ appropriate viewer for the given output format or use the user defined
164
+ one. By default png output is generated.
165
+
166
+ By default pretty Euler fonts are used for typesetting (they were used to
167
+ typeset the well known "Concrete Mathematics" book). For that to work, you
168
+ need the 'eulervm.sty' LaTeX style (in Debian/Ubuntu, install the
169
+ texlive-fonts-extra package). If you prefer default AMS fonts or your
170
+ system lacks 'eulervm' LaTeX package then unset the 'euler' keyword
171
+ argument.
172
+
173
+ To use viewer auto-detection, lets say for 'png' output, issue
174
+
175
+ >>> from sympy import symbols, preview, Symbol
176
+ >>> x, y = symbols("x,y")
177
+
178
+ >>> preview(x + y, output='png')
179
+
180
+ This will choose 'pyglet' by default. To select a different one, do
181
+
182
+ >>> preview(x + y, output='png', viewer='gimp')
183
+
184
+ The 'png' format is considered special. For all other formats the rules
185
+ are slightly different. As an example we will take 'dvi' output format. If
186
+ you would run
187
+
188
+ >>> preview(x + y, output='dvi')
189
+
190
+ then 'view' will look for available 'dvi' viewers on your system
191
+ (predefined in the function, so it will try evince, first, then kdvi and
192
+ xdvi). If nothing is found, it will fall back to using a system file
193
+ association (via ``open`` and ``xdg-open``). To always use your system file
194
+ association without searching for the above readers, use
195
+
196
+ >>> from sympy.printing.preview import system_default_viewer
197
+ >>> preview(x + y, output='dvi', viewer=system_default_viewer)
198
+
199
+ If this still does not find the viewer you want, it can be set explicitly.
200
+
201
+ >>> preview(x + y, output='dvi', viewer='superior-dvi-viewer')
202
+
203
+ This will skip auto-detection and will run user specified
204
+ 'superior-dvi-viewer'. If ``view`` fails to find it on your system it will
205
+ gracefully raise an exception.
206
+
207
+ You may also enter ``'file'`` for the viewer argument. Doing so will cause
208
+ this function to return a file object in read-only mode, if ``filename``
209
+ is unset. However, if it was set, then 'preview' writes the generated
210
+ file to this filename instead.
211
+
212
+ There is also support for writing to a ``io.BytesIO`` like object, which
213
+ needs to be passed to the ``outputbuffer`` argument.
214
+
215
+ >>> from io import BytesIO
216
+ >>> obj = BytesIO()
217
+ >>> preview(x + y, output='png', viewer='BytesIO',
218
+ ... outputbuffer=obj)
219
+
220
+ The LaTeX preamble can be customized by setting the 'preamble' keyword
221
+ argument. This can be used, e.g., to set a different font size, use a
222
+ custom documentclass or import certain set of LaTeX packages.
223
+
224
+ >>> preamble = "\\documentclass[10pt]{article}\n" \
225
+ ... "\\usepackage{amsmath,amsfonts}\\begin{document}"
226
+ >>> preview(x + y, output='png', preamble=preamble)
227
+
228
+ It is also possible to use the standard preamble and provide additional
229
+ information to the preamble using the ``extra_preamble`` keyword argument.
230
+
231
+ >>> from sympy import sin
232
+ >>> extra_preamble = "\\renewcommand{\\sin}{\\cos}"
233
+ >>> preview(sin(x), output='png', extra_preamble=extra_preamble)
234
+
235
+ If the value of 'output' is different from 'dvi' then command line
236
+ options can be set ('dvioptions' argument) for the execution of the
237
+ 'dvi'+output conversion tool. These options have to be in the form of a
238
+ list of strings (see ``subprocess.Popen``).
239
+
240
+ Additional keyword args will be passed to the :func:`~sympy.printing.latex.latex` call,
241
+ e.g., the ``symbol_names`` flag.
242
+
243
+ >>> phidd = Symbol('phidd')
244
+ >>> preview(phidd, symbol_names={phidd: r'\ddot{\varphi}'})
245
+
246
+ For post-processing the generated TeX File can be written to a file by
247
+ passing the desired filename to the 'outputTexFile' keyword
248
+ argument. To write the TeX code to a file named
249
+ ``"sample.tex"`` and run the default png viewer to display the resulting
250
+ bitmap, do
251
+
252
+ >>> preview(x + y, outputTexFile="sample.tex")
253
+
254
+
255
+ """
256
+ # pyglet is the default for png
257
+ if viewer is None and output == "png":
258
+ try:
259
+ import pyglet # noqa: F401
260
+ except ImportError:
261
+ pass
262
+ else:
263
+ viewer = pyglet_viewer
264
+
265
+ # look up a known application
266
+ if viewer is None:
267
+ # sorted in order from most pretty to most ugly
268
+ # very discussable, but indeed 'gv' looks awful :)
269
+ candidates = {
270
+ "dvi": [ "evince", "okular", "kdvi", "xdvi" ],
271
+ "ps": [ "evince", "okular", "gsview", "gv" ],
272
+ "pdf": [ "evince", "okular", "kpdf", "acroread", "xpdf", "gv" ],
273
+ }
274
+
275
+ for candidate in candidates.get(output, []):
276
+ path = shutil.which(candidate)
277
+ if path is not None:
278
+ viewer = path
279
+ break
280
+
281
+ # otherwise, use the system default for file association
282
+ if viewer is None:
283
+ viewer = system_default_viewer
284
+
285
+ if viewer == "file":
286
+ if filename is None:
287
+ raise ValueError("filename has to be specified if viewer=\"file\"")
288
+ elif viewer == "BytesIO":
289
+ if outputbuffer is None:
290
+ raise ValueError("outputbuffer has to be a BytesIO "
291
+ "compatible object if viewer=\"BytesIO\"")
292
+ elif not callable(viewer) and not shutil.which(viewer):
293
+ raise OSError("Unrecognized viewer: %s" % viewer)
294
+
295
+ latex_main = _get_latex_main(expr, preamble=preamble, packages=packages,
296
+ euler=euler, extra_preamble=extra_preamble,
297
+ fontsize=fontsize, **latex_settings)
298
+
299
+ debug("Latex code:")
300
+ debug(latex_main)
301
+ with tempfile.TemporaryDirectory() as workdir:
302
+ Path(join(workdir, 'texput.tex')).write_text(latex_main, encoding='utf-8')
303
+
304
+ if outputTexFile is not None:
305
+ shutil.copyfile(join(workdir, 'texput.tex'), outputTexFile)
306
+
307
+ if not shutil.which('latex'):
308
+ raise RuntimeError("latex program is not installed")
309
+
310
+ try:
311
+ _check_output_no_window(
312
+ ['latex', '-halt-on-error', '-interaction=nonstopmode',
313
+ 'texput.tex'],
314
+ cwd=workdir,
315
+ stderr=STDOUT)
316
+ except CalledProcessError as e:
317
+ raise RuntimeError(
318
+ "'latex' exited abnormally with the following output:\n%s" %
319
+ e.output)
320
+
321
+ src = "texput.%s" % (output)
322
+
323
+ if output != "dvi":
324
+ # in order of preference
325
+ commandnames = {
326
+ "ps": ["dvips"],
327
+ "pdf": ["dvipdfmx", "dvipdfm", "dvipdf"],
328
+ "png": ["dvipng"],
329
+ "svg": ["dvisvgm"],
330
+ }
331
+ try:
332
+ cmd_variants = commandnames[output]
333
+ except KeyError:
334
+ raise ValueError("Invalid output format: %s" % output) from None
335
+
336
+ # find an appropriate command
337
+ for cmd_variant in cmd_variants:
338
+ cmd_path = shutil.which(cmd_variant)
339
+ if cmd_path:
340
+ cmd = [cmd_path]
341
+ break
342
+ else:
343
+ if len(cmd_variants) > 1:
344
+ raise RuntimeError("None of %s are installed" % ", ".join(cmd_variants))
345
+ else:
346
+ raise RuntimeError("%s is not installed" % cmd_variants[0])
347
+
348
+ defaultoptions = {
349
+ "dvipng": ["-T", "tight", "-z", "9", "--truecolor"],
350
+ "dvisvgm": ["--no-fonts"],
351
+ }
352
+
353
+ commandend = {
354
+ "dvips": ["-o", src, "texput.dvi"],
355
+ "dvipdf": ["texput.dvi", src],
356
+ "dvipdfm": ["-o", src, "texput.dvi"],
357
+ "dvipdfmx": ["-o", src, "texput.dvi"],
358
+ "dvipng": ["-o", src, "texput.dvi"],
359
+ "dvisvgm": ["-o", src, "texput.dvi"],
360
+ }
361
+
362
+ if dvioptions is not None:
363
+ cmd.extend(dvioptions)
364
+ else:
365
+ cmd.extend(defaultoptions.get(cmd_variant, []))
366
+ cmd.extend(commandend[cmd_variant])
367
+
368
+ try:
369
+ _check_output_no_window(cmd, cwd=workdir, stderr=STDOUT)
370
+ except CalledProcessError as e:
371
+ raise RuntimeError(
372
+ "'%s' exited abnormally with the following output:\n%s" %
373
+ (' '.join(cmd), e.output))
374
+
375
+
376
+ if viewer == "file":
377
+ shutil.move(join(workdir, src), filename)
378
+ elif viewer == "BytesIO":
379
+ s = Path(join(workdir, src)).read_bytes()
380
+ outputbuffer.write(s)
381
+ elif callable(viewer):
382
+ viewer(join(workdir, src), fmt=output)
383
+ else:
384
+ try:
385
+ _check_output_no_window(
386
+ [viewer, src], cwd=workdir, stderr=STDOUT)
387
+ except CalledProcessError as e:
388
+ raise RuntimeError(
389
+ "'%s %s' exited abnormally with the following output:\n%s" %
390
+ (viewer, src, e.output))
.venv/lib/python3.13/site-packages/sympy/printing/str.py ADDED
@@ -0,0 +1,1021 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ A Printer for generating readable representation of most SymPy classes.
3
+ """
4
+
5
+ from __future__ import annotations
6
+ from typing import Any
7
+
8
+ from sympy.core import S, Rational, Pow, Basic, Mul, Number
9
+ from sympy.core.mul import _keep_coeff
10
+ from sympy.core.numbers import Integer
11
+ from sympy.core.relational import Relational
12
+ from sympy.core.sorting import default_sort_key
13
+ from sympy.utilities.iterables import sift
14
+ from .precedence import precedence, PRECEDENCE
15
+ from .printer import Printer, print_function
16
+
17
+ from mpmath.libmp import prec_to_dps, to_str as mlib_to_str
18
+
19
+
20
+ class StrPrinter(Printer):
21
+ printmethod = "_sympystr"
22
+ _default_settings: dict[str, Any] = {
23
+ "order": None,
24
+ "full_prec": "auto",
25
+ "sympy_integers": False,
26
+ "abbrev": False,
27
+ "perm_cyclic": True,
28
+ "min": None,
29
+ "max": None,
30
+ "dps" : None
31
+ }
32
+
33
+ _relationals: dict[str, str] = {}
34
+
35
+ def parenthesize(self, item, level, strict=False):
36
+ if (precedence(item) < level) or ((not strict) and precedence(item) <= level):
37
+ return "(%s)" % self._print(item)
38
+ else:
39
+ return self._print(item)
40
+
41
+ def stringify(self, args, sep, level=0):
42
+ return sep.join([self.parenthesize(item, level) for item in args])
43
+
44
+ def emptyPrinter(self, expr):
45
+ if isinstance(expr, str):
46
+ return expr
47
+ elif isinstance(expr, Basic):
48
+ return repr(expr)
49
+ else:
50
+ return str(expr)
51
+
52
+ def _print_Add(self, expr, order=None):
53
+ terms = self._as_ordered_terms(expr, order=order)
54
+
55
+ prec = precedence(expr)
56
+ l = []
57
+ for term in terms:
58
+ t = self._print(term)
59
+ if t.startswith('-') and not term.is_Add:
60
+ sign = "-"
61
+ t = t[1:]
62
+ else:
63
+ sign = "+"
64
+ if precedence(term) < prec or term.is_Add:
65
+ l.extend([sign, "(%s)" % t])
66
+ else:
67
+ l.extend([sign, t])
68
+ sign = l.pop(0)
69
+ if sign == '+':
70
+ sign = ""
71
+ return sign + ' '.join(l)
72
+
73
+ def _print_BooleanTrue(self, expr):
74
+ return "True"
75
+
76
+ def _print_BooleanFalse(self, expr):
77
+ return "False"
78
+
79
+ def _print_Not(self, expr):
80
+ return '~%s' %(self.parenthesize(expr.args[0],PRECEDENCE["Not"]))
81
+
82
+ def _print_And(self, expr):
83
+ args = list(expr.args)
84
+ for j, i in enumerate(args):
85
+ if isinstance(i, Relational) and (
86
+ i.canonical.rhs is S.NegativeInfinity):
87
+ args.insert(0, args.pop(j))
88
+ return self.stringify(args, " & ", PRECEDENCE["BitwiseAnd"])
89
+
90
+ def _print_Or(self, expr):
91
+ return self.stringify(expr.args, " | ", PRECEDENCE["BitwiseOr"])
92
+
93
+ def _print_Xor(self, expr):
94
+ return self.stringify(expr.args, " ^ ", PRECEDENCE["BitwiseXor"])
95
+
96
+ def _print_AppliedPredicate(self, expr):
97
+ return '%s(%s)' % (
98
+ self._print(expr.function), self.stringify(expr.arguments, ", "))
99
+
100
+ def _print_Basic(self, expr):
101
+ l = [self._print(o) for o in expr.args]
102
+ return expr.__class__.__name__ + "(%s)" % ", ".join(l)
103
+
104
+ def _print_BlockMatrix(self, B):
105
+ if B.blocks.shape == (1, 1):
106
+ self._print(B.blocks[0, 0])
107
+ return self._print(B.blocks)
108
+
109
+ def _print_Catalan(self, expr):
110
+ return 'Catalan'
111
+
112
+ def _print_ComplexInfinity(self, expr):
113
+ return 'zoo'
114
+
115
+ def _print_ConditionSet(self, s):
116
+ args = tuple([self._print(i) for i in (s.sym, s.condition)])
117
+ if s.base_set is S.UniversalSet:
118
+ return 'ConditionSet(%s, %s)' % args
119
+ args += (self._print(s.base_set),)
120
+ return 'ConditionSet(%s, %s, %s)' % args
121
+
122
+ def _print_Derivative(self, expr):
123
+ dexpr = expr.expr
124
+ dvars = [i[0] if i[1] == 1 else i for i in expr.variable_count]
125
+ return 'Derivative(%s)' % ", ".join((self._print(arg) for arg in [dexpr] + dvars))
126
+
127
+ def _print_dict(self, d):
128
+ keys = sorted(d.keys(), key=default_sort_key)
129
+ items = []
130
+
131
+ for key in keys:
132
+ item = "%s: %s" % (self._print(key), self._print(d[key]))
133
+ items.append(item)
134
+
135
+ return "{%s}" % ", ".join(items)
136
+
137
+ def _print_Dict(self, expr):
138
+ return self._print_dict(expr)
139
+
140
+ def _print_RandomDomain(self, d):
141
+ if hasattr(d, 'as_boolean'):
142
+ return 'Domain: ' + self._print(d.as_boolean())
143
+ elif hasattr(d, 'set'):
144
+ return ('Domain: ' + self._print(d.symbols) + ' in ' +
145
+ self._print(d.set))
146
+ else:
147
+ return 'Domain on ' + self._print(d.symbols)
148
+
149
+ def _print_Dummy(self, expr):
150
+ return '_' + expr.name
151
+
152
+ def _print_EulerGamma(self, expr):
153
+ return 'EulerGamma'
154
+
155
+ def _print_Exp1(self, expr):
156
+ return 'E'
157
+
158
+ def _print_ExprCondPair(self, expr):
159
+ return '(%s, %s)' % (self._print(expr.expr), self._print(expr.cond))
160
+
161
+ def _print_Function(self, expr):
162
+ return expr.func.__name__ + "(%s)" % self.stringify(expr.args, ", ")
163
+
164
+ def _print_GoldenRatio(self, expr):
165
+ return 'GoldenRatio'
166
+
167
+ def _print_Heaviside(self, expr):
168
+ # Same as _print_Function but uses pargs to suppress default 1/2 for
169
+ # 2nd args
170
+ return expr.func.__name__ + "(%s)" % self.stringify(expr.pargs, ", ")
171
+
172
+ def _print_TribonacciConstant(self, expr):
173
+ return 'TribonacciConstant'
174
+
175
+ def _print_ImaginaryUnit(self, expr):
176
+ return 'I'
177
+
178
+ def _print_Infinity(self, expr):
179
+ return 'oo'
180
+
181
+ def _print_Integral(self, expr):
182
+ def _xab_tostr(xab):
183
+ if len(xab) == 1:
184
+ return self._print(xab[0])
185
+ else:
186
+ return self._print((xab[0],) + tuple(xab[1:]))
187
+ L = ', '.join([_xab_tostr(l) for l in expr.limits])
188
+ return 'Integral(%s, %s)' % (self._print(expr.function), L)
189
+
190
+ def _print_Interval(self, i):
191
+ fin = 'Interval{m}({a}, {b})'
192
+ a, b, l, r = i.args
193
+ if a.is_infinite and b.is_infinite:
194
+ m = ''
195
+ elif a.is_infinite and not r:
196
+ m = ''
197
+ elif b.is_infinite and not l:
198
+ m = ''
199
+ elif not l and not r:
200
+ m = ''
201
+ elif l and r:
202
+ m = '.open'
203
+ elif l:
204
+ m = '.Lopen'
205
+ else:
206
+ m = '.Ropen'
207
+ return fin.format(**{'a': a, 'b': b, 'm': m})
208
+
209
+ def _print_AccumulationBounds(self, i):
210
+ return "AccumBounds(%s, %s)" % (self._print(i.min),
211
+ self._print(i.max))
212
+
213
+ def _print_Inverse(self, I):
214
+ return "%s**(-1)" % self.parenthesize(I.arg, PRECEDENCE["Pow"])
215
+
216
+ def _print_Lambda(self, obj):
217
+ expr = obj.expr
218
+ sig = obj.signature
219
+ if len(sig) == 1 and sig[0].is_symbol:
220
+ sig = sig[0]
221
+ return "Lambda(%s, %s)" % (self._print(sig), self._print(expr))
222
+
223
+ def _print_LatticeOp(self, expr):
224
+ args = sorted(expr.args, key=default_sort_key)
225
+ return expr.func.__name__ + "(%s)" % ", ".join(self._print(arg) for arg in args)
226
+
227
+ def _print_Limit(self, expr):
228
+ e, z, z0, dir = expr.args
229
+ return "Limit(%s, %s, %s, dir='%s')" % tuple(map(self._print, (e, z, z0, dir)))
230
+
231
+
232
+ def _print_list(self, expr):
233
+ return "[%s]" % self.stringify(expr, ", ")
234
+
235
+ def _print_List(self, expr):
236
+ return self._print_list(expr)
237
+
238
+ def _print_MatrixBase(self, expr):
239
+ return expr._format_str(self)
240
+
241
+ def _print_MatrixElement(self, expr):
242
+ return self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) \
243
+ + '[%s, %s]' % (self._print(expr.i), self._print(expr.j))
244
+
245
+ def _print_MatrixSlice(self, expr):
246
+ def strslice(x, dim):
247
+ x = list(x)
248
+ if x[2] == 1:
249
+ del x[2]
250
+ if x[0] == 0:
251
+ x[0] = ''
252
+ if x[1] == dim:
253
+ x[1] = ''
254
+ return ':'.join((self._print(arg) for arg in x))
255
+ return (self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) + '[' +
256
+ strslice(expr.rowslice, expr.parent.rows) + ', ' +
257
+ strslice(expr.colslice, expr.parent.cols) + ']')
258
+
259
+ def _print_DeferredVector(self, expr):
260
+ return expr.name
261
+
262
+ def _print_Mul(self, expr):
263
+
264
+ prec = precedence(expr)
265
+
266
+ # Check for unevaluated Mul. In this case we need to make sure the
267
+ # identities are visible, multiple Rational factors are not combined
268
+ # etc so we display in a straight-forward form that fully preserves all
269
+ # args and their order.
270
+ args = expr.args
271
+ if args[0] is S.One or any(
272
+ isinstance(a, Number) or
273
+ a.is_Pow and all(ai.is_Integer for ai in a.args)
274
+ for a in args[1:]):
275
+ d, n = sift(args, lambda x:
276
+ isinstance(x, Pow) and bool(x.exp.as_coeff_Mul()[0] < 0),
277
+ binary=True)
278
+ for i, di in enumerate(d):
279
+ if di.exp.is_Number:
280
+ e = -di.exp
281
+ else:
282
+ dargs = list(di.exp.args)
283
+ dargs[0] = -dargs[0]
284
+ e = Mul._from_args(dargs)
285
+ d[i] = Pow(di.base, e, evaluate=False) if e - 1 else di.base
286
+
287
+ pre = []
288
+ # don't parenthesize first factor if negative
289
+ if n and not n[0].is_Add and n[0].could_extract_minus_sign():
290
+ pre = [self._print(n.pop(0))]
291
+
292
+ nfactors = pre + [self.parenthesize(a, prec, strict=False)
293
+ for a in n]
294
+ if not nfactors:
295
+ nfactors = ['1']
296
+
297
+ # don't parenthesize first of denominator unless singleton
298
+ if len(d) > 1 and d[0].could_extract_minus_sign():
299
+ pre = [self._print(d.pop(0))]
300
+ else:
301
+ pre = []
302
+ dfactors = pre + [self.parenthesize(a, prec, strict=False)
303
+ for a in d]
304
+
305
+ n = '*'.join(nfactors)
306
+ d = '*'.join(dfactors)
307
+ if len(dfactors) > 1:
308
+ return '%s/(%s)' % (n, d)
309
+ elif dfactors:
310
+ return '%s/%s' % (n, d)
311
+ return n
312
+
313
+ c, e = expr.as_coeff_Mul()
314
+ if c < 0:
315
+ expr = _keep_coeff(-c, e)
316
+ sign = "-"
317
+ else:
318
+ sign = ""
319
+
320
+ a = [] # items in the numerator
321
+ b = [] # items that are in the denominator (if any)
322
+
323
+ pow_paren = [] # Will collect all pow with more than one base element and exp = -1
324
+
325
+ if self.order not in ('old', 'none'):
326
+ args = expr.as_ordered_factors()
327
+ else:
328
+ # use make_args in case expr was something like -x -> x
329
+ args = Mul.make_args(expr)
330
+
331
+ # Gather args for numerator/denominator
332
+ def apow(i):
333
+ b, e = i.as_base_exp()
334
+ eargs = list(Mul.make_args(e))
335
+ if eargs[0] is S.NegativeOne:
336
+ eargs = eargs[1:]
337
+ else:
338
+ eargs[0] = -eargs[0]
339
+ e = Mul._from_args(eargs)
340
+ if isinstance(i, Pow):
341
+ return i.func(b, e, evaluate=False)
342
+ return i.func(e, evaluate=False)
343
+ for item in args:
344
+ if (item.is_commutative and
345
+ isinstance(item, Pow) and
346
+ bool(item.exp.as_coeff_Mul()[0] < 0)):
347
+ if item.exp is not S.NegativeOne:
348
+ b.append(apow(item))
349
+ else:
350
+ if (len(item.args[0].args) != 1 and
351
+ isinstance(item.base, (Mul, Pow))):
352
+ # To avoid situations like #14160
353
+ pow_paren.append(item)
354
+ b.append(item.base)
355
+ elif item.is_Rational and item is not S.Infinity:
356
+ if item.p != 1:
357
+ a.append(Rational(item.p))
358
+ if item.q != 1:
359
+ b.append(Rational(item.q))
360
+ else:
361
+ a.append(item)
362
+
363
+ a = a or [S.One]
364
+
365
+ a_str = [self.parenthesize(x, prec, strict=False) for x in a]
366
+ b_str = [self.parenthesize(x, prec, strict=False) for x in b]
367
+
368
+ # To parenthesize Pow with exp = -1 and having more than one Symbol
369
+ for item in pow_paren:
370
+ if item.base in b:
371
+ b_str[b.index(item.base)] = "(%s)" % b_str[b.index(item.base)]
372
+
373
+ if not b:
374
+ return sign + '*'.join(a_str)
375
+ elif len(b) == 1:
376
+ return sign + '*'.join(a_str) + "/" + b_str[0]
377
+ else:
378
+ return sign + '*'.join(a_str) + "/(%s)" % '*'.join(b_str)
379
+
380
+ def _print_MatMul(self, expr):
381
+ c, m = expr.as_coeff_mmul()
382
+
383
+ sign = ""
384
+ if c.is_number:
385
+ re, im = c.as_real_imag()
386
+ if im.is_zero and re.is_negative:
387
+ expr = _keep_coeff(-c, m)
388
+ sign = "-"
389
+ elif re.is_zero and im.is_negative:
390
+ expr = _keep_coeff(-c, m)
391
+ sign = "-"
392
+
393
+ return sign + '*'.join(
394
+ [self.parenthesize(arg, precedence(expr)) for arg in expr.args]
395
+ )
396
+
397
+ def _print_ElementwiseApplyFunction(self, expr):
398
+ return "{}.({})".format(
399
+ expr.function,
400
+ self._print(expr.expr),
401
+ )
402
+
403
+ def _print_NaN(self, expr):
404
+ return 'nan'
405
+
406
+ def _print_NegativeInfinity(self, expr):
407
+ return '-oo'
408
+
409
+ def _print_Order(self, expr):
410
+ if not expr.variables or all(p is S.Zero for p in expr.point):
411
+ if len(expr.variables) <= 1:
412
+ return 'O(%s)' % self._print(expr.expr)
413
+ else:
414
+ return 'O(%s)' % self.stringify((expr.expr,) + expr.variables, ', ', 0)
415
+ else:
416
+ return 'O(%s)' % self.stringify(expr.args, ', ', 0)
417
+
418
+ def _print_Ordinal(self, expr):
419
+ return expr.__str__()
420
+
421
+ def _print_Cycle(self, expr):
422
+ return expr.__str__()
423
+
424
+ def _print_Permutation(self, expr):
425
+ from sympy.combinatorics.permutations import Permutation, Cycle
426
+ from sympy.utilities.exceptions import sympy_deprecation_warning
427
+
428
+ perm_cyclic = Permutation.print_cyclic
429
+ if perm_cyclic is not None:
430
+ sympy_deprecation_warning(
431
+ f"""
432
+ Setting Permutation.print_cyclic is deprecated. Instead use
433
+ init_printing(perm_cyclic={perm_cyclic}).
434
+ """,
435
+ deprecated_since_version="1.6",
436
+ active_deprecations_target="deprecated-permutation-print_cyclic",
437
+ stacklevel=7,
438
+ )
439
+ else:
440
+ perm_cyclic = self._settings.get("perm_cyclic", True)
441
+
442
+ if perm_cyclic:
443
+ if not expr.size:
444
+ return '()'
445
+ # before taking Cycle notation, see if the last element is
446
+ # a singleton and move it to the head of the string
447
+ s = Cycle(expr)(expr.size - 1).__repr__()[len('Cycle'):]
448
+ last = s.rfind('(')
449
+ if not last == 0 and ',' not in s[last:]:
450
+ s = s[last:] + s[:last]
451
+ s = s.replace(',', '')
452
+ return s
453
+ else:
454
+ s = expr.support()
455
+ if not s:
456
+ if expr.size < 5:
457
+ return 'Permutation(%s)' % self._print(expr.array_form)
458
+ return 'Permutation([], size=%s)' % self._print(expr.size)
459
+ trim = self._print(expr.array_form[:s[-1] + 1]) + ', size=%s' % self._print(expr.size)
460
+ use = full = self._print(expr.array_form)
461
+ if len(trim) < len(full):
462
+ use = trim
463
+ return 'Permutation(%s)' % use
464
+
465
+ def _print_Subs(self, obj):
466
+ expr, old, new = obj.args
467
+ if len(obj.point) == 1:
468
+ old = old[0]
469
+ new = new[0]
470
+ return "Subs(%s, %s, %s)" % (
471
+ self._print(expr), self._print(old), self._print(new))
472
+
473
+ def _print_TensorIndex(self, expr):
474
+ return expr._print()
475
+
476
+ def _print_TensorHead(self, expr):
477
+ return expr._print()
478
+
479
+ def _print_Tensor(self, expr):
480
+ return expr._print()
481
+
482
+ def _print_TensMul(self, expr):
483
+ # prints expressions like "A(a)", "3*A(a)", "(1+x)*A(a)"
484
+ sign, args = expr._get_args_for_traditional_printer()
485
+ return sign + "*".join(
486
+ [self.parenthesize(arg, precedence(expr)) for arg in args]
487
+ )
488
+
489
+ def _print_TensAdd(self, expr):
490
+ return expr._print()
491
+
492
+ def _print_ArraySymbol(self, expr):
493
+ return self._print(expr.name)
494
+
495
+ def _print_ArrayElement(self, expr):
496
+ return "%s[%s]" % (
497
+ self.parenthesize(expr.name, PRECEDENCE["Func"], True), ", ".join([self._print(i) for i in expr.indices]))
498
+
499
+ def _print_PermutationGroup(self, expr):
500
+ p = [' %s' % self._print(a) for a in expr.args]
501
+ return 'PermutationGroup([\n%s])' % ',\n'.join(p)
502
+
503
+ def _print_Pi(self, expr):
504
+ return 'pi'
505
+
506
+ def _print_PolyRing(self, ring):
507
+ return "Polynomial ring in %s over %s with %s order" % \
508
+ (", ".join((self._print(rs) for rs in ring.symbols)),
509
+ self._print(ring.domain), self._print(ring.order))
510
+
511
+ def _print_FracField(self, field):
512
+ return "Rational function field in %s over %s with %s order" % \
513
+ (", ".join((self._print(fs) for fs in field.symbols)),
514
+ self._print(field.domain), self._print(field.order))
515
+
516
+ def _print_FreeGroupElement(self, elm):
517
+ return elm.__str__()
518
+
519
+ def _print_GaussianElement(self, poly):
520
+ return "(%s + %s*I)" % (poly.x, poly.y)
521
+
522
+ def _print_PolyElement(self, poly):
523
+ return poly.str(self, PRECEDENCE, "%s**%s", "*")
524
+
525
+ def _print_FracElement(self, frac):
526
+ if frac.denom == 1:
527
+ return self._print(frac.numer)
528
+ else:
529
+ numer = self.parenthesize(frac.numer, PRECEDENCE["Mul"], strict=True)
530
+ denom = self.parenthesize(frac.denom, PRECEDENCE["Atom"], strict=True)
531
+ return numer + "/" + denom
532
+
533
+ def _print_Poly(self, expr):
534
+ ATOM_PREC = PRECEDENCE["Atom"] - 1
535
+ terms, gens = [], [ self.parenthesize(s, ATOM_PREC) for s in expr.gens ]
536
+
537
+ for monom, coeff in expr.terms():
538
+ s_monom = []
539
+
540
+ for i, e in enumerate(monom):
541
+ if e > 0:
542
+ if e == 1:
543
+ s_monom.append(gens[i])
544
+ else:
545
+ s_monom.append(gens[i] + "**%d" % e)
546
+
547
+ s_monom = "*".join(s_monom)
548
+
549
+ if coeff.is_Add:
550
+ if s_monom:
551
+ s_coeff = "(" + self._print(coeff) + ")"
552
+ else:
553
+ s_coeff = self._print(coeff)
554
+ else:
555
+ if s_monom:
556
+ if coeff is S.One:
557
+ terms.extend(['+', s_monom])
558
+ continue
559
+
560
+ if coeff is S.NegativeOne:
561
+ terms.extend(['-', s_monom])
562
+ continue
563
+
564
+ s_coeff = self._print(coeff)
565
+
566
+ if not s_monom:
567
+ s_term = s_coeff
568
+ else:
569
+ s_term = s_coeff + "*" + s_monom
570
+
571
+ if s_term.startswith('-'):
572
+ terms.extend(['-', s_term[1:]])
573
+ else:
574
+ terms.extend(['+', s_term])
575
+
576
+ if terms[0] in ('-', '+'):
577
+ modifier = terms.pop(0)
578
+
579
+ if modifier == '-':
580
+ terms[0] = '-' + terms[0]
581
+
582
+ format = expr.__class__.__name__ + "(%s, %s"
583
+
584
+ from sympy.polys.polyerrors import PolynomialError
585
+
586
+ try:
587
+ format += ", modulus=%s" % expr.get_modulus()
588
+ except PolynomialError:
589
+ format += ", domain='%s'" % expr.get_domain()
590
+
591
+ format += ")"
592
+
593
+ for index, item in enumerate(gens):
594
+ if len(item) > 2 and (item[:1] == "(" and item[len(item) - 1:] == ")"):
595
+ gens[index] = item[1:len(item) - 1]
596
+
597
+ return format % (' '.join(terms), ', '.join(gens))
598
+
599
+ def _print_UniversalSet(self, p):
600
+ return 'UniversalSet'
601
+
602
+ def _print_AlgebraicNumber(self, expr):
603
+ if expr.is_aliased:
604
+ return self._print(expr.as_poly().as_expr())
605
+ else:
606
+ return self._print(expr.as_expr())
607
+
608
+ def _print_Pow(self, expr, rational=False):
609
+ """Printing helper function for ``Pow``
610
+
611
+ Parameters
612
+ ==========
613
+
614
+ rational : bool, optional
615
+ If ``True``, it will not attempt printing ``sqrt(x)`` or
616
+ ``x**S.Half`` as ``sqrt``, and will use ``x**(1/2)``
617
+ instead.
618
+
619
+ See examples for additional details
620
+
621
+ Examples
622
+ ========
623
+
624
+ >>> from sympy import sqrt, StrPrinter
625
+ >>> from sympy.abc import x
626
+
627
+ How ``rational`` keyword works with ``sqrt``:
628
+
629
+ >>> printer = StrPrinter()
630
+ >>> printer._print_Pow(sqrt(x), rational=True)
631
+ 'x**(1/2)'
632
+ >>> printer._print_Pow(sqrt(x), rational=False)
633
+ 'sqrt(x)'
634
+ >>> printer._print_Pow(1/sqrt(x), rational=True)
635
+ 'x**(-1/2)'
636
+ >>> printer._print_Pow(1/sqrt(x), rational=False)
637
+ '1/sqrt(x)'
638
+
639
+ Notes
640
+ =====
641
+
642
+ ``sqrt(x)`` is canonicalized as ``Pow(x, S.Half)`` in SymPy,
643
+ so there is no need of defining a separate printer for ``sqrt``.
644
+ Instead, it should be handled here as well.
645
+ """
646
+ PREC = precedence(expr)
647
+
648
+ if expr.exp is S.Half and not rational:
649
+ return "sqrt(%s)" % self._print(expr.base)
650
+
651
+ if expr.is_commutative:
652
+ if -expr.exp is S.Half and not rational:
653
+ # Note: Don't test "expr.exp == -S.Half" here, because that will
654
+ # match -0.5, which we don't want.
655
+ return "%s/sqrt(%s)" % tuple((self._print(arg) for arg in (S.One, expr.base)))
656
+ if expr.exp is -S.One:
657
+ # Similarly to the S.Half case, don't test with "==" here.
658
+ return '%s/%s' % (self._print(S.One),
659
+ self.parenthesize(expr.base, PREC, strict=False))
660
+
661
+ e = self.parenthesize(expr.exp, PREC, strict=False)
662
+ if self.printmethod == '_sympyrepr' and expr.exp.is_Rational and expr.exp.q != 1:
663
+ # the parenthesized exp should be '(Rational(a, b))' so strip parens,
664
+ # but just check to be sure.
665
+ if e.startswith('(Rational'):
666
+ return '%s**%s' % (self.parenthesize(expr.base, PREC, strict=False), e[1:-1])
667
+ return '%s**%s' % (self.parenthesize(expr.base, PREC, strict=False), e)
668
+
669
+ def _print_UnevaluatedExpr(self, expr):
670
+ return self._print(expr.args[0])
671
+
672
+ def _print_MatPow(self, expr):
673
+ PREC = precedence(expr)
674
+ return '%s**%s' % (self.parenthesize(expr.base, PREC, strict=False),
675
+ self.parenthesize(expr.exp, PREC, strict=False))
676
+
677
+ def _print_Integer(self, expr):
678
+ if self._settings.get("sympy_integers", False):
679
+ return "S(%s)" % (expr)
680
+ return str(expr.p)
681
+
682
+ def _print_Integers(self, expr):
683
+ return 'Integers'
684
+
685
+ def _print_Naturals(self, expr):
686
+ return 'Naturals'
687
+
688
+ def _print_Naturals0(self, expr):
689
+ return 'Naturals0'
690
+
691
+ def _print_Rationals(self, expr):
692
+ return 'Rationals'
693
+
694
+ def _print_Reals(self, expr):
695
+ return 'Reals'
696
+
697
+ def _print_Complexes(self, expr):
698
+ return 'Complexes'
699
+
700
+ def _print_EmptySet(self, expr):
701
+ return 'EmptySet'
702
+
703
+ def _print_EmptySequence(self, expr):
704
+ return 'EmptySequence'
705
+
706
+ def _print_int(self, expr):
707
+ return str(expr)
708
+
709
+ def _print_mpz(self, expr):
710
+ return str(expr)
711
+
712
+ def _print_Rational(self, expr):
713
+ if expr.q == 1:
714
+ return str(expr.p)
715
+ else:
716
+ if self._settings.get("sympy_integers", False):
717
+ return "S(%s)/%s" % (expr.p, expr.q)
718
+ return "%s/%s" % (expr.p, expr.q)
719
+
720
+ def _print_PythonRational(self, expr):
721
+ if expr.q == 1:
722
+ return str(expr.p)
723
+ else:
724
+ return "%d/%d" % (expr.p, expr.q)
725
+
726
+ def _print_Fraction(self, expr):
727
+ if expr.denominator == 1:
728
+ return str(expr.numerator)
729
+ else:
730
+ return "%s/%s" % (expr.numerator, expr.denominator)
731
+
732
+ def _print_mpq(self, expr):
733
+ if expr.denominator == 1:
734
+ return str(expr.numerator)
735
+ else:
736
+ return "%s/%s" % (expr.numerator, expr.denominator)
737
+
738
+ def _print_Float(self, expr):
739
+ prec = expr._prec
740
+ dps = self._settings.get('dps', None)
741
+ if dps is None:
742
+ dps = 0 if prec < 5 else prec_to_dps(expr._prec)
743
+ if self._settings["full_prec"] is True:
744
+ strip = False
745
+ elif self._settings["full_prec"] is False:
746
+ strip = True
747
+ elif self._settings["full_prec"] == "auto":
748
+ strip = self._print_level > 1
749
+ low = self._settings["min"] if "min" in self._settings else None
750
+ high = self._settings["max"] if "max" in self._settings else None
751
+ rv = mlib_to_str(expr._mpf_, dps, strip_zeros=strip, min_fixed=low, max_fixed=high)
752
+ if rv.startswith('-.0'):
753
+ rv = '-0.' + rv[3:]
754
+ elif rv.startswith('.0'):
755
+ rv = '0.' + rv[2:]
756
+ rv = rv.removeprefix('+') # e.g., +inf -> inf
757
+ return rv
758
+
759
+ def _print_Relational(self, expr):
760
+
761
+ charmap = {
762
+ "==": "Eq",
763
+ "!=": "Ne",
764
+ ":=": "Assignment",
765
+ '+=': "AddAugmentedAssignment",
766
+ "-=": "SubAugmentedAssignment",
767
+ "*=": "MulAugmentedAssignment",
768
+ "/=": "DivAugmentedAssignment",
769
+ "%=": "ModAugmentedAssignment",
770
+ }
771
+
772
+ if expr.rel_op in charmap:
773
+ return '%s(%s, %s)' % (charmap[expr.rel_op], self._print(expr.lhs),
774
+ self._print(expr.rhs))
775
+
776
+ return '%s %s %s' % (self.parenthesize(expr.lhs, precedence(expr)),
777
+ self._relationals.get(expr.rel_op) or expr.rel_op,
778
+ self.parenthesize(expr.rhs, precedence(expr)))
779
+
780
+ def _print_ComplexRootOf(self, expr):
781
+ return "CRootOf(%s, %d)" % (self._print_Add(expr.expr, order='lex'),
782
+ expr.index)
783
+
784
+ def _print_RootSum(self, expr):
785
+ args = [self._print_Add(expr.expr, order='lex')]
786
+
787
+ if expr.fun is not S.IdentityFunction:
788
+ args.append(self._print(expr.fun))
789
+
790
+ return "RootSum(%s)" % ", ".join(args)
791
+
792
+ def _print_GroebnerBasis(self, basis):
793
+ cls = basis.__class__.__name__
794
+
795
+ exprs = [self._print_Add(arg, order=basis.order) for arg in basis.exprs]
796
+ exprs = "[%s]" % ", ".join(exprs)
797
+
798
+ gens = [ self._print(gen) for gen in basis.gens ]
799
+ domain = "domain='%s'" % self._print(basis.domain)
800
+ order = "order='%s'" % self._print(basis.order)
801
+
802
+ args = [exprs] + gens + [domain, order]
803
+
804
+ return "%s(%s)" % (cls, ", ".join(args))
805
+
806
+ def _print_set(self, s):
807
+ items = sorted(s, key=default_sort_key)
808
+
809
+ args = ', '.join(self._print(item) for item in items)
810
+ if not args:
811
+ return "set()"
812
+ return '{%s}' % args
813
+
814
+ def _print_FiniteSet(self, s):
815
+ from sympy.sets.sets import FiniteSet
816
+ items = sorted(s, key=default_sort_key)
817
+
818
+ args = ', '.join(self._print(item) for item in items)
819
+ if any(item.has(FiniteSet) for item in items):
820
+ return 'FiniteSet({})'.format(args)
821
+ return '{{{}}}'.format(args)
822
+
823
+ def _print_Partition(self, s):
824
+ items = sorted(s, key=default_sort_key)
825
+
826
+ args = ', '.join(self._print(arg) for arg in items)
827
+ return 'Partition({})'.format(args)
828
+
829
+ def _print_frozenset(self, s):
830
+ if not s:
831
+ return "frozenset()"
832
+ return "frozenset(%s)" % self._print_set(s)
833
+
834
+ def _print_Sum(self, expr):
835
+ def _xab_tostr(xab):
836
+ if len(xab) == 1:
837
+ return self._print(xab[0])
838
+ else:
839
+ return self._print((xab[0],) + tuple(xab[1:]))
840
+ L = ', '.join([_xab_tostr(l) for l in expr.limits])
841
+ return 'Sum(%s, %s)' % (self._print(expr.function), L)
842
+
843
+ def _print_Symbol(self, expr):
844
+ return expr.name
845
+ _print_MatrixSymbol = _print_Symbol
846
+ _print_RandomSymbol = _print_Symbol
847
+
848
+ def _print_Identity(self, expr):
849
+ return "I"
850
+
851
+ def _print_ZeroMatrix(self, expr):
852
+ return "0"
853
+
854
+ def _print_OneMatrix(self, expr):
855
+ return "1"
856
+
857
+ def _print_Predicate(self, expr):
858
+ return "Q.%s" % expr.name
859
+
860
+ def _print_str(self, expr):
861
+ return str(expr)
862
+
863
+ def _print_tuple(self, expr):
864
+ if len(expr) == 1:
865
+ return "(%s,)" % self._print(expr[0])
866
+ else:
867
+ return "(%s)" % self.stringify(expr, ", ")
868
+
869
+ def _print_Tuple(self, expr):
870
+ return self._print_tuple(expr)
871
+
872
+ def _print_Transpose(self, T):
873
+ return "%s.T" % self.parenthesize(T.arg, PRECEDENCE["Pow"])
874
+
875
+ def _print_Uniform(self, expr):
876
+ return "Uniform(%s, %s)" % (self._print(expr.a), self._print(expr.b))
877
+
878
+ def _print_Quantity(self, expr):
879
+ if self._settings.get("abbrev", False):
880
+ return "%s" % expr.abbrev
881
+ return "%s" % expr.name
882
+
883
+ def _print_Quaternion(self, expr):
884
+ s = [self.parenthesize(i, PRECEDENCE["Mul"], strict=True) for i in expr.args]
885
+ a = [s[0]] + [i+"*"+j for i, j in zip(s[1:], "ijk")]
886
+ return " + ".join(a)
887
+
888
+ def _print_Dimension(self, expr):
889
+ return str(expr)
890
+
891
+ def _print_Wild(self, expr):
892
+ return expr.name + '_'
893
+
894
+ def _print_WildFunction(self, expr):
895
+ return expr.name + '_'
896
+
897
+ def _print_WildDot(self, expr):
898
+ return expr.name
899
+
900
+ def _print_WildPlus(self, expr):
901
+ return expr.name
902
+
903
+ def _print_WildStar(self, expr):
904
+ return expr.name
905
+
906
+ def _print_Zero(self, expr):
907
+ if self._settings.get("sympy_integers", False):
908
+ return "S(0)"
909
+ return self._print_Integer(Integer(0))
910
+
911
+ def _print_DMP(self, p):
912
+ cls = p.__class__.__name__
913
+ rep = self._print(p.to_list())
914
+ dom = self._print(p.dom)
915
+
916
+ return "%s(%s, %s)" % (cls, rep, dom)
917
+
918
+ def _print_DMF(self, expr):
919
+ cls = expr.__class__.__name__
920
+ num = self._print(expr.num)
921
+ den = self._print(expr.den)
922
+ dom = self._print(expr.dom)
923
+
924
+ return "%s(%s, %s, %s)" % (cls, num, den, dom)
925
+
926
+ def _print_Object(self, obj):
927
+ return 'Object("%s")' % obj.name
928
+
929
+ def _print_IdentityMorphism(self, morphism):
930
+ return 'IdentityMorphism(%s)' % morphism.domain
931
+
932
+ def _print_NamedMorphism(self, morphism):
933
+ return 'NamedMorphism(%s, %s, "%s")' % \
934
+ (morphism.domain, morphism.codomain, morphism.name)
935
+
936
+ def _print_Category(self, category):
937
+ return 'Category("%s")' % category.name
938
+
939
+ def _print_Manifold(self, manifold):
940
+ return manifold.name.name
941
+
942
+ def _print_Patch(self, patch):
943
+ return patch.name.name
944
+
945
+ def _print_CoordSystem(self, coords):
946
+ return coords.name.name
947
+
948
+ def _print_BaseScalarField(self, field):
949
+ return field._coord_sys.symbols[field._index].name
950
+
951
+ def _print_BaseVectorField(self, field):
952
+ return 'e_%s' % field._coord_sys.symbols[field._index].name
953
+
954
+ def _print_Differential(self, diff):
955
+ field = diff._form_field
956
+ if hasattr(field, '_coord_sys'):
957
+ return 'd%s' % field._coord_sys.symbols[field._index].name
958
+ else:
959
+ return 'd(%s)' % self._print(field)
960
+
961
+ def _print_Tr(self, expr):
962
+ #TODO : Handle indices
963
+ return "%s(%s)" % ("Tr", self._print(expr.args[0]))
964
+
965
+ def _print_Str(self, s):
966
+ return self._print(s.name)
967
+
968
+ def _print_AppliedBinaryRelation(self, expr):
969
+ rel = expr.function
970
+ return '%s(%s, %s)' % (self._print(rel),
971
+ self._print(expr.lhs),
972
+ self._print(expr.rhs))
973
+
974
+
975
+ @print_function(StrPrinter)
976
+ def sstr(expr, **settings):
977
+ """Returns the expression as a string.
978
+
979
+ For large expressions where speed is a concern, use the setting
980
+ order='none'. If abbrev=True setting is used then units are printed in
981
+ abbreviated form.
982
+
983
+ Examples
984
+ ========
985
+
986
+ >>> from sympy import symbols, Eq, sstr
987
+ >>> a, b = symbols('a b')
988
+ >>> sstr(Eq(a + b, 0))
989
+ 'Eq(a + b, 0)'
990
+ """
991
+
992
+ p = StrPrinter(settings)
993
+ s = p.doprint(expr)
994
+
995
+ return s
996
+
997
+
998
+ class StrReprPrinter(StrPrinter):
999
+ """(internal) -- see sstrrepr"""
1000
+
1001
+ def _print_str(self, s):
1002
+ return repr(s)
1003
+
1004
+ def _print_Str(self, s):
1005
+ # Str does not to be printed same as str here
1006
+ return "%s(%s)" % (s.__class__.__name__, self._print(s.name))
1007
+
1008
+ @print_function(StrReprPrinter)
1009
+ def sstrrepr(expr, **settings):
1010
+ """return expr in mixed str/repr form
1011
+
1012
+ i.e. strings are returned in repr form with quotes, and everything else
1013
+ is returned in str form.
1014
+
1015
+ This function could be useful for hooking into sys.displayhook
1016
+ """
1017
+
1018
+ p = StrReprPrinter(settings)
1019
+ s = p.doprint(expr)
1020
+
1021
+ return s
.venv/lib/python3.13/site-packages/sympy/printing/tree.py ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def pprint_nodes(subtrees):
2
+ """
3
+ Prettyprints systems of nodes.
4
+
5
+ Examples
6
+ ========
7
+
8
+ >>> from sympy.printing.tree import pprint_nodes
9
+ >>> print(pprint_nodes(["a", "b1\\nb2", "c"]))
10
+ +-a
11
+ +-b1
12
+ | b2
13
+ +-c
14
+
15
+ """
16
+ def indent(s, type=1):
17
+ x = s.split("\n")
18
+ r = "+-%s\n" % x[0]
19
+ for a in x[1:]:
20
+ if a == "":
21
+ continue
22
+ if type == 1:
23
+ r += "| %s\n" % a
24
+ else:
25
+ r += " %s\n" % a
26
+ return r
27
+ if not subtrees:
28
+ return ""
29
+ f = ""
30
+ for a in subtrees[:-1]:
31
+ f += indent(a)
32
+ f += indent(subtrees[-1], 2)
33
+ return f
34
+
35
+
36
+ def print_node(node, assumptions=True):
37
+ """
38
+ Returns information about the "node".
39
+
40
+ This includes class name, string representation and assumptions.
41
+
42
+ Parameters
43
+ ==========
44
+
45
+ assumptions : bool, optional
46
+ See the ``assumptions`` keyword in ``tree``
47
+ """
48
+ s = "%s: %s\n" % (node.__class__.__name__, str(node))
49
+
50
+ if assumptions:
51
+ d = node._assumptions
52
+ else:
53
+ d = None
54
+
55
+ if d:
56
+ for a in sorted(d):
57
+ v = d[a]
58
+ if v is None:
59
+ continue
60
+ s += "%s: %s\n" % (a, v)
61
+
62
+ return s
63
+
64
+
65
+ def tree(node, assumptions=True):
66
+ """
67
+ Returns a tree representation of "node" as a string.
68
+
69
+ It uses print_node() together with pprint_nodes() on node.args recursively.
70
+
71
+ Parameters
72
+ ==========
73
+
74
+ assumptions : bool, optional
75
+ The flag to decide whether to print out all the assumption data
76
+ (such as ``is_integer`, ``is_real``) associated with the
77
+ expression or not.
78
+
79
+ Enabling the flag makes the result verbose, and the printed
80
+ result may not be deterministic because of the randomness used
81
+ in backtracing the assumptions.
82
+
83
+ See Also
84
+ ========
85
+
86
+ print_tree
87
+
88
+ """
89
+ subtrees = []
90
+ for arg in node.args:
91
+ subtrees.append(tree(arg, assumptions=assumptions))
92
+ s = print_node(node, assumptions=assumptions) + pprint_nodes(subtrees)
93
+ return s
94
+
95
+
96
+ def print_tree(node, assumptions=True):
97
+ """
98
+ Prints a tree representation of "node".
99
+
100
+ Parameters
101
+ ==========
102
+
103
+ assumptions : bool, optional
104
+ The flag to decide whether to print out all the assumption data
105
+ (such as ``is_integer`, ``is_real``) associated with the
106
+ expression or not.
107
+
108
+ Enabling the flag makes the result verbose, and the printed
109
+ result may not be deterministic because of the randomness used
110
+ in backtracing the assumptions.
111
+
112
+ Examples
113
+ ========
114
+
115
+ >>> from sympy.printing import print_tree
116
+ >>> from sympy import Symbol
117
+ >>> x = Symbol('x', odd=True)
118
+ >>> y = Symbol('y', even=True)
119
+
120
+ Printing with full assumptions information:
121
+
122
+ >>> print_tree(y**x)
123
+ Pow: y**x
124
+ +-Symbol: y
125
+ | algebraic: True
126
+ | commutative: True
127
+ | complex: True
128
+ | even: True
129
+ | extended_real: True
130
+ | finite: True
131
+ | hermitian: True
132
+ | imaginary: False
133
+ | infinite: False
134
+ | integer: True
135
+ | irrational: False
136
+ | noninteger: False
137
+ | odd: False
138
+ | rational: True
139
+ | real: True
140
+ | transcendental: False
141
+ +-Symbol: x
142
+ algebraic: True
143
+ commutative: True
144
+ complex: True
145
+ even: False
146
+ extended_nonzero: True
147
+ extended_real: True
148
+ finite: True
149
+ hermitian: True
150
+ imaginary: False
151
+ infinite: False
152
+ integer: True
153
+ irrational: False
154
+ noninteger: False
155
+ nonzero: True
156
+ odd: True
157
+ rational: True
158
+ real: True
159
+ transcendental: False
160
+ zero: False
161
+
162
+ Hiding the assumptions:
163
+
164
+ >>> print_tree(y**x, assumptions=False)
165
+ Pow: y**x
166
+ +-Symbol: y
167
+ +-Symbol: x
168
+
169
+ See Also
170
+ ========
171
+
172
+ tree
173
+
174
+ """
175
+ print(tree(node, assumptions=assumptions))