anhtld commited on
Commit
1a23920
·
verified ·
1 Parent(s): c0df866

Auto-sync: 2026-06-25 22:43:25 (part 16)

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/AUTHORS +1379 -0
  2. outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/INSTALLER +1 -0
  3. outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/LICENSE +153 -0
  4. outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/METADATA +34 -0
  5. outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/RECORD +0 -0
  6. outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/WHEEL +5 -0
  7. outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/entry_points.txt +2 -0
  8. outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/top_level.txt +2 -0
  9. outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_mathematica.py +287 -0
  10. outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_mathml.py +0 -0
  11. outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_numpy.py +381 -0
  12. outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_octave.py +515 -0
  13. outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_precedence.py +128 -0
  14. outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_preview.py +38 -0
  15. outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_pycode.py +493 -0
  16. outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_python.py +203 -0
  17. outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_rcode.py +476 -0
  18. outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_repr.py +382 -0
  19. outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_rust.py +363 -0
  20. outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_smtlib.py +553 -0
  21. outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_str.py +1206 -0
  22. outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_tableform.py +182 -0
  23. outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_tensorflow.py +493 -0
  24. outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_theanocode.py +639 -0
  25. outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_torch.py +531 -0
  26. outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_tree.py +196 -0
  27. outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/theanocode.py +571 -0
  28. outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tree.py +175 -0
  29. outputs/audit_venv/lib/python3.11/site-packages/sympy/release.py +1 -0
  30. outputs/audit_venv/lib/python3.11/site-packages/sympy/sandbox/__init__.py +8 -0
  31. outputs/audit_venv/lib/python3.11/site-packages/sympy/sandbox/indexed_integrals.py +72 -0
  32. outputs/audit_venv/lib/python3.11/site-packages/sympy/sandbox/tests/__init__.py +0 -0
  33. outputs/audit_venv/lib/python3.11/site-packages/sympy/sandbox/tests/test_indexed_integrals.py +25 -0
  34. outputs/audit_venv/lib/python3.11/site-packages/sympy/series/__init__.py +23 -0
  35. outputs/audit_venv/lib/python3.11/site-packages/sympy/series/acceleration.py +101 -0
  36. outputs/audit_venv/lib/python3.11/site-packages/sympy/series/approximants.py +103 -0
  37. outputs/audit_venv/lib/python3.11/site-packages/sympy/series/aseries.py +10 -0
  38. outputs/audit_venv/lib/python3.11/site-packages/sympy/series/benchmarks/__init__.py +0 -0
  39. outputs/audit_venv/lib/python3.11/site-packages/sympy/series/benchmarks/bench_limit.py +9 -0
  40. outputs/audit_venv/lib/python3.11/site-packages/sympy/series/benchmarks/bench_order.py +10 -0
  41. outputs/audit_venv/lib/python3.11/site-packages/sympy/series/formal.py +1863 -0
  42. outputs/audit_venv/lib/python3.11/site-packages/sympy/series/fourier.py +811 -0
  43. outputs/audit_venv/lib/python3.11/site-packages/sympy/series/gruntz.py +701 -0
  44. outputs/audit_venv/lib/python3.11/site-packages/sympy/series/kauers.py +51 -0
  45. outputs/audit_venv/lib/python3.11/site-packages/sympy/series/limits.py +394 -0
  46. outputs/audit_venv/lib/python3.11/site-packages/sympy/series/limitseq.py +257 -0
  47. outputs/audit_venv/lib/python3.11/site-packages/sympy/series/order.py +522 -0
  48. outputs/audit_venv/lib/python3.11/site-packages/sympy/series/residues.py +73 -0
  49. outputs/audit_venv/lib/python3.11/site-packages/sympy/series/sequences.py +1239 -0
  50. outputs/audit_venv/lib/python3.11/site-packages/sympy/series/series.py +63 -0
outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/AUTHORS ADDED
@@ -0,0 +1,1379 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ All people who contributed to SymPy by sending at least a patch or
2
+ more (in the order of the date of their first contribution), except
3
+ those who explicitly didn't want to be mentioned. People with a * next
4
+ to their names are not found in the metadata of the git history. This
5
+ file is generated automatically by running `./bin/authors_update.py`.
6
+
7
+ There are a total of 1371 authors.
8
+
9
+ Ondřej Čertík <ondrej@certik.cz>
10
+ Fabian Pedregosa <fabian@fseoane.net>
11
+ Jurjen N.E. Bos <jnebos@gmail.com>
12
+ Mateusz Paprocki <mattpap@gmail.com>
13
+ *Marc-Etienne M.Leveille <protonyc@gmail.com>
14
+ Brian Jorgensen <brian.jorgensen@gmail.com>
15
+ Jason Gedge <inferno1386@gmail.com>
16
+ Robert Schwarz <lethargo@googlemail.com>
17
+ Pearu Peterson <pearu.peterson@gmail.com>
18
+ Fredrik Johansson <fredrik.johansson@gmail.com>
19
+ Chris Wu <chris.wu@gmail.com>
20
+ *Ulrich Hecht <ulrich.hecht@gmail.com>
21
+ Goutham Lakshminarayan <dl.goutham@gmail.com>
22
+ David Lawrence <dmlawrence@gmail.com>
23
+ Jaroslaw Tworek <dev.jrx@gmail.com>
24
+ David Marek <h4wk.cz@gmail.com>
25
+ Bernhard R. Link <brlink@debian.org>
26
+ Andrej Tokarčík <androsis@gmail.com>
27
+ Or Dvory <gidesa@gmail.com>
28
+ Saroj Adhikari <adh.saroj@gmail.com>
29
+ Pauli Virtanen <pav@iki.fi>
30
+ Robert Kern <robert.kern@gmail.com>
31
+ James Aspnes <aspnes@cs.yale.edu>
32
+ Nimish Telang <ntelang@gmail.com>
33
+ Abderrahim Kitouni <a.kitouni@gmail.com>
34
+ Pan Peng <pengpanster@gmail.com>
35
+ Friedrich Hagedorn <friedrich_h@gmx.de>
36
+ Elrond der Elbenfuerst <elrond+sympy.org@samba-tng.org>
37
+ Rizgar Mella <rizgar.mella@gmail.com>
38
+ Felix Kaiser <felix.kaiser@fxkr.net>
39
+ Roberto Nobrega <rwnobrega@gmail.com>
40
+ David Roberts <dvdr18@gmail.com>
41
+ Sebastian Krämer <basti.kr@gmail.com>
42
+ Vinzent Steinberg <vinzent.steinberg@gmail.com>
43
+ Riccardo Gori <goriccardo@gmail.com>
44
+ Case Van Horsen <casevh@gmail.com>
45
+ Stepan Roucka <stepan@roucka.eu>
46
+ Ali Raza Syed <arsyed@gmail.com>
47
+ Stefano Maggiolo <s.maggiolo@gmail.com>
48
+ Robert Cimrman <cimrman3@ntc.zcu.cz>
49
+ Bastian Weber <bastian.weber@gmx-topmail.de>
50
+ Sebastian Krause <sebastian.krause@gmx.de>
51
+ Sebastian Kreft <skreft@gmail.com>
52
+ *Dan <coolg49964@gmail.com>
53
+ Alan Bromborsky <abrombo@verizon.net>
54
+ Boris Timokhin <qoqenator@gmail.com>
55
+ Robert <average.programmer@gmail.com>
56
+ Andy R. Terrel <aterrel@uchicago.edu>
57
+ Hubert Tsang <intsangity@gmail.com>
58
+ Konrad Meyer <konrad.meyer@gmail.com>
59
+ Henrik Johansson <henjo2006@gmail.com>
60
+ Priit Laes <plaes@plaes.org>
61
+ Freddie Witherden <freddie@witherden.org>
62
+ Brian E. Granger <ellisonbg@gmail.com>
63
+ Andrew Straw <strawman@astraw.com>
64
+ Kaifeng Zhu <cafeeee@gmail.com>
65
+ Ted Horst <ted.horst@earthlink.net>
66
+ Andrew Docherty <andrewd@maths.usyd.edu.au>
67
+ Akshay Srinivasan <akshaysrinivasan@gmail.com>
68
+ Aaron Meurer <asmeurer@gmail.com>
69
+ Barry Wardell <barry.wardell@gmail.com>
70
+ Tomasz Buchert <thinred@gmail.com>
71
+ Vinay Kumar <gnulinooks@gmail.com>
72
+ Johann Cohen-Tanugi <johann.cohentanugi@gmail.com>
73
+ Jochen Voss <voss@seehuhn.de>
74
+ Luke Peterson <hazelnusse@gmail.com>
75
+ Chris Smith <smichr@gmail.com>
76
+ Thomas Sidoti <TSidoti@gmail.com>
77
+ Florian Mickler <florian@mickler.org>
78
+ Nicolas Pourcelot <nicolas.pourcelot@gmail.com>
79
+ Ben Goodrich <goodrich.ben@gmail.com>
80
+ Toon Verstraelen <Toon.Verstraelen@UGent.be>
81
+ Ronan Lamy <ronan.lamy@gmail.com>
82
+ James Abbatiello <abbeyj@gmail.com>
83
+ Ryan Krauss <ryanlists@gmail.com>
84
+ Bill Flynn <wflynny@gmail.com>
85
+ Kevin Goodsell <kevin-opensource@omegacrash.net>
86
+ Jorn Baayen <jorn.baayen@gmail.com>
87
+ Eh Tan <tan2tan2@gmail.com>
88
+ Renato Coutinho <renato.coutinho@gmail.com>
89
+ Oscar Benjamin <oscar.j.benjamin@gmail.com>
90
+ Øyvind Jensen <jensen.oyvind@gmail.com>
91
+ Julio Idichekop Filho <idichekop@yahoo.com.br>
92
+ Łukasz Pankowski <lukpank@o2.pl>
93
+ *Chu-Ching Huang <cchuang@mail.cgu.edu.tw>
94
+ Fernando Perez <Fernando.Perez@berkeley.edu>
95
+ Raffaele De Feo <alberthilbert@gmail.com>
96
+ Christian Muise <christian.muise@gmail.com>
97
+ Matt Curry <mattjcurry@gmail.com>
98
+ Kazuo Thow <kazuo.thow@gmail.com>
99
+ Christian Schubert <chr.schubert@gmx.de>
100
+ Jezreel Ng <jezreel@gmail.com>
101
+ James Pearson <xiong.chiamiov@gmail.com>
102
+ Matthew Brett <matthew.brett@gmail.com>
103
+ Addison Cugini <ajcugini@gmail.com>
104
+ Nicholas J.S. Kinar <n.kinar@usask.ca>
105
+ Harold Erbin <harold.erbin@gmail.com>
106
+ Thomas Dixon <thom@thomdixon.org>
107
+ Cristóvão Sousa <crisjss@gmail.com>
108
+ Andre de Fortier Smit <freevryheid@gmail.com>
109
+ Mark Dewing <markdewing@gmail.com>
110
+ Alexey U. Gudchenko <proga@goodok.ru>
111
+ Gary Kerr <gary.kerr@blueyonder.co.uk>
112
+ Sherjil Ozair <sherjilozair@gmail.com>
113
+ Oleksandr Gituliar <gituliar@gmail.com>
114
+ Sean Vig <sean.v.775@gmail.com>
115
+ Prafullkumar P. Tale <hector1618@gmail.com>
116
+ Vladimir Perić <vlada.peric@gmail.com>
117
+ Tom Bachmann <e_mc_h2@web.de>
118
+ Yuri Karadzhov <yuri.karadzhov@gmail.com>
119
+ Vladimir Lagunov <werehuman@gmail.com>
120
+ Matthew Rocklin <mrocklin@cs.uchicago.edu>
121
+ Saptarshi Mandal <sapta.iitkgp@gmail.com>
122
+ Gilbert Gede <gilbertgede@gmail.com>
123
+ Anatolii Koval <weralwolf@gmail.com>
124
+ Tomo Lazovich <lazovich@gmail.com>
125
+ Pavel Fedotov <fedotovp@gmail.com>
126
+ Jack McCaffery <jpmccaffery@gmail.com>
127
+ Jeremias Yehdegho <j.yehdegho@gmail.com>
128
+ Kibeom Kim <kk1674@nyu.edu>
129
+ Gregory Ksionda <ksiondag846@gmail.com>
130
+ Tomáš Bambas <tomas.bambas@gmail.com>
131
+ Raymond Wong <rayman_407@yahoo.com>
132
+ Luca Weihs <astronomicalcuriosity@gmail.com>
133
+ Shai 'Deshe' Wyborski <shaide@cs.huji.ac.il>
134
+ Thomas Wiecki <thomas.wiecki@gmail.com>
135
+ Óscar Nájera <najera.oscar@gmail.com>
136
+ Mario Pernici <mario.pernici@gmail.com>
137
+ Benjamin McDonald <mcdonald.ben@gmail.com>
138
+ Sam Magura <samtheman132@gmail.com>
139
+ Stefan Krastanov <krastanov.stefan@gmail.com>
140
+ Bradley Froehle <brad.froehle@gmail.com>
141
+ Min Ragan-Kelley <benjaminrk@gmail.com>
142
+ Emma Hogan <ehogan@gemini.edu>
143
+ Nikhil Sarda <diff.operator@gmail.com>
144
+ Julien Rioux <julien.rioux@gmail.com>
145
+ Roberto Colistete, Jr. <roberto.colistete@gmail.com>
146
+ Raoul Bourquin <raoulb@bluewin.ch>
147
+ Gert-Ludwig Ingold <gert.ingold@physik.uni-augsburg.de>
148
+ Srinivas Vasudevan <srvasude@gmail.com>
149
+ Jason Moore <moorepants@gmail.com>
150
+ Miha Marolt <tloramus@gmail.com>
151
+ Tim Lahey <tim.lahey@gmail.com>
152
+ Luis Garcia <ppn.online@me.com>
153
+ Matt Rajca <matt.rajca@me.com>
154
+ David Li <l33tnerd.li@gmail.com>
155
+ Alexandr Gudulin <alexandr.gudulin@gmail.com>
156
+ Bilal Akhtar <bilalakhtar@ubuntu.com>
157
+ Grzegorz Świrski <sognat@gmail.com>
158
+ Matt Habel <habelinc@gmail.com>
159
+ David Ju <Sgtmook314@gmail.com>
160
+ Nichita Utiu <nikita.utiu+github@gmail.com>
161
+ Nikolay Lazarov <qwerqwerqwer@abv.bg>
162
+ Steve Anton <anxuiz.nx@gmail.com>
163
+ Imran Ahmed Manzoor <imran.manzoor31@gmail.com>
164
+ Ljubiša Moćić <3rdslasher@gmail.com>
165
+ Piotr Korgul <p.korgul@gmail.com>
166
+ Jim Zhang <Hyriodula@gmail.com>
167
+ Sam Sleight <samuel.sleight@gmail.com>
168
+ tborisova <ts.borisova3@gmail.com>
169
+ Chancellor Arkantos <Chancellor_Arkantos@hotmail.co.uk>
170
+ Stepan Simsa <simsa.st@gmail.com>
171
+ Tobias Lenz <t_lenz94@web.de>
172
+ Siddhanathan Shanmugam <siddhanathan@gmail.com>
173
+ Tiffany Zhu <bubble.wubble.303@gmail.com>
174
+ Tristan Hume <tris.hume@gmail.com>
175
+ Alexey Subach <alexey.subach@gmail.com>
176
+ Joan Creus <joan.creus.c@gmail.com>
177
+ Geoffry Song <goffrie@gmail.com>
178
+ Puneeth Chaganti <punchagan@gmail.com>
179
+ Marcin Kostrzewa <>
180
+ Natalia Nawara <fankalemura@gmail.com>
181
+ vishal <vishal.panjwani15@gmail.com>
182
+ Shruti Mangipudi <shruti2395@gmail.com>
183
+ Davy Mao <e_equals_mass_speed_light_squared@hotmail.com>
184
+ Swapnil Agarwal <swapnilag29@gmail.com>
185
+ Dhia Kennouche <kendhia@gmail.com>
186
+ jerryma1121 <jerryma1121@gmail.com>
187
+ Joachim Durchholz <jo@durchholz.org>
188
+ Martin Povišer <martin.povik@gmail.com>
189
+ Siddhant Jain <getsiddhant@gmail.com>
190
+ Kevin Hunter <hunteke@earlham.edu>
191
+ Michael Mayorov <marchael@kb.csu.ru>
192
+ Nathan Alison <nathan.f.alison@gmail.com>
193
+ Christian Bühler <christian@cbuehler.de>
194
+ Carsten Knoll <CarstenKnoll@gmx.de>
195
+ Bharath M R <catchmrbharath@gmail.com>
196
+ Matthias Toews <mat.toews@googlemail.com>
197
+ Sergiu Ivanov <unlimitedscolobb@gmail.com>
198
+ Jorge E. Cardona <jorgeecardona@gmail.com>
199
+ Sanket Agarwal <sanket@sanketagarwal.com>
200
+ Manoj Babu K. <manoj.babu2378@gmail.com>
201
+ Sai Nikhil <tsnlegend@gmail.com>
202
+ Aleksandar Makelov <amakelov@college.harvard.edu>
203
+ Sachin Irukula <sachin.irukula@gmail.com>
204
+ Raphael Michel <webmaster@raphaelmichel.de>
205
+ Ashwini Oruganti <ashwini.oruganti@gmail.com>
206
+ Andreas Klöckner <inform@tiker.net>
207
+ Prateek Papriwal <papriwalprateek@gmail.com>
208
+ Arpit Goyal <agmps18@gmail.com>
209
+ Angadh Nanjangud <angadh.n@gmail.com>
210
+ Comer Duncan <comer.duncan@gmail.com>
211
+ Jens H. Nielsen <jenshnielsen@gmail.com>
212
+ Joseph Dougherty <Github@JWDougherty.com>
213
+ Elliot Marshall <Marshall2389@gmail.com>
214
+ Guru Devanla <grdvnl@gmail.com>
215
+ George Waksman <waksman@gwax.com>
216
+ Alexandr Popov <alexandr.s.popov@gmail.com>
217
+ Tarun Gaba <tarun.gaba7@gmail.com>
218
+ Takafumi Arakaki <aka.tkf@gmail.com>
219
+ Saurabh Jha <saurabh.jhaa@gmail.com>
220
+ Rom le Clair <jacen.guardian@gmail.com>
221
+ Angus Griffith <16sn6uv@gmail.com>
222
+ Timothy Reluga <treluga@math.psu.edu>
223
+ Brian Stephanik <xoedusk@gmail.com>
224
+ Alexander Eberspächer <alex.eberspaecher@gmail.com>
225
+ Sachin Joglekar <srjoglekar246@gmail.com>
226
+ Tyler Pirtle <teeler@gmail.com>
227
+ Vasily Povalyaev <vapovalyaev@gmail.com>
228
+ Colleen Lee <colleenclee@gmail.com>
229
+ Matthew Hoff <mhoff14@gmail.com>
230
+ Niklas Thörne <notrupertthorne@gmail.com>
231
+ Huijun Mai <m.maihuijun@gmail.com>
232
+ Marek Šuppa <mr@shu.io>
233
+ Ramana Venkata <idlike2dream@gmail.com>
234
+ Prasoon Shukla <prasoon92.iitr@gmail.com>
235
+ Stefen Yin <zqyin@ucdavis.edu>
236
+ Thomas Hisch <t.hisch@gmail.com>
237
+ Madeleine Ball <mpball@gmail.com>
238
+ Mary Clark <mary.spriteling@gmail.com>
239
+ Rishabh Dixit <rishabhdixit11@gmail.com>
240
+ Manoj Kumar <manojkumarsivaraj334@gmail.com>
241
+ Akshit Agarwal <akshit.jiit@gmail.com>
242
+ CJ Carey <perimosocordiae@gmail.com>
243
+ Patrick Lacasse <patrick.m.lacasse@gmail.com>
244
+ Ananya H <ananyaha93@gmail.com>
245
+ Tarang Patel <tarangrockr@gmail.com>
246
+ Christopher Dembia <cld72@cornell.edu>
247
+ Benjamin Fishbein <fishbeinb@gmail.com>
248
+ Sean Ge <seange727@gmail.com>
249
+ Amit Jamadagni <bitsjamadagni@gmail.com>
250
+ Ankit Agrawal <aaaagrawal@iitb.ac.in>
251
+ Björn Dahlgren <bjodah@gmail.com>
252
+ Christophe Saint-Jean <christophe.saint-jean@univ-lr.fr>
253
+ Demian Wassermann <demian@bwh.harvard.edu>
254
+ Khagesh Patel <khageshpatel93@gmail.com>
255
+ Stephen Loo <shikil@yahoo.com>
256
+ hm <hacman0@gmail.com>
257
+ Patrick Poitras <acebulf@gmail.com>
258
+ Katja Sophie Hotz <katja.sophie.hotz@student.tuwien.ac.at>
259
+ Varun Joshi <joshi.142@osu.edu>
260
+ Chetna Gupta <cheta.gup@gmail.com>
261
+ Thilina Rathnayake <thilinarmtb@gmail.com>
262
+ Max Hutchinson <maxhutch@gmail.com>
263
+ Shravas K Rao <shravas@gmail.com>
264
+ Matthew Tadd <matt.tadd@gmail.com>
265
+ Alexander Hirzel <alex@hirzel.us>
266
+ Randy Heydon <randy.heydon@clockworklab.net>
267
+ Oliver Lee <oliverzlee@gmail.com>
268
+ Seshagiri Prabhu <seshagiriprabhu@gmail.com>
269
+ Pradyumna <pradyu1993@gmail.com>
270
+ Erik Welch <erik.n.welch@gmail.com>
271
+ Eric Nelson <eric.the.red.XLII@gmail.com>
272
+ Roland Puntaier <roland.puntaier@chello.at>
273
+ Chris Conley <chrisconley15@gmail.com>
274
+ Tim Swast <tswast@gmail.com>
275
+ Dmitry Batkovich <batya239@gmail.com>
276
+ Francesco Bonazzi <franz.bonazzi@gmail.com>
277
+ Yuriy Demidov <iurii.demidov@gmail.com>
278
+ Rick Muller <rpmuller@gmail.com>
279
+ Manish Gill <gill.manish90@gmail.com>
280
+ Markus Müller <markus.mueller.1.g@googlemail.com>
281
+ Amit Saha <amitsaha.in@gmail.com>
282
+ Jeremy <twobitlogic@gmail.com>
283
+ QuaBoo <kisonchristian@gmail.com>
284
+ Stefan van der Walt <stefan@sun.ac.za>
285
+ David Joyner <wdjoyner@gmail.com>
286
+ Lars Buitinck <larsmans@gmail.com>
287
+ Alkiviadis G. Akritas <akritas@uth.gr>
288
+ Vinit Ravishankar <vinit.ravishankar@gmail.com>
289
+ Michael Boyle <michael.oliver.boyle@gmail.com>
290
+ Heiner Kirchhoffer <Heiner.Kirchhoffer@gmail.com>
291
+ Pablo Puente <ppuedom@gmail.com>
292
+ James Fiedler <jrfiedler@gmail.com>
293
+ Harsh Gupta <mail@hargup.in>
294
+ Tuomas Airaksinen <tuomas.airaksinen@gmail.com>
295
+ Paul Strickland <p.e.strickland@gmail.com>
296
+ James Goppert <james.goppert@gmail.com>
297
+ rathmann <rathmann.os@gmail.com>
298
+ Avichal Dayal <avichal.dayal@gmail.com>
299
+ Paul Scott <paul.scott@nicta.com.au>
300
+ Shipra Banga <bangashipra@gmail.com>
301
+ Pramod Ch <pramodch14@gmail.com>
302
+ Akshay <akshaynukala95@gmail.com>
303
+ Buck Shlegeris <buck2@bruceh15.anu.edu.au>
304
+ Jonathan Miller <jdmiller93@gmail.com>
305
+ Edward Schembor <eschemb1@jhu.edu>
306
+ Rajath Shashidhara <rajaths.rajaths@gmail.com>
307
+ Zamrath Nizam <zamiguy_ni@yahoo.com>
308
+ Aditya Shah <adityashah30@gmail.com>
309
+ Rajat Aggarwal <rajataggarwal1975@gmail.com>
310
+ Sambuddha Basu <sammygamer@live.com>
311
+ Zeel Shah <kshah215@gmail.com>
312
+ Abhinav Chanda <abhinavchanda01@gmail.com>
313
+ Jim Crist <crist042@umn.edu>
314
+ Sudhanshu Mishra <mrsud94@gmail.com>
315
+ Anurag Sharma <anurags92@gmail.com>
316
+ Soumya Dipta Biswas <sdb1323@gmail.com>
317
+ Sushant Hiray <hiraysushant@gmail.com>
318
+ Ben Lucato <ben.lucato@gmail.com>
319
+ Kunal Arora <kunalarora.135@gmail.com>
320
+ Henry Gebhardt <hsggebhardt@gmail.com>
321
+ Dammina Sahabandu <dmsahabandu@gmail.com>
322
+ Manish Shukla <manish.shukla393@gmail>
323
+ Ralph Bean <rbean@redhat.com>
324
+ richierichrawr <richierichrawr@users.noreply.github.com>
325
+ John Connor <john.theman.connor@gmail.com>
326
+ Juan Luis Cano Rodríguez <juanlu001@gmail.com>
327
+ Sahil Shekhawat <sahilshekhawat01@gmail.com>
328
+ Kundan Kumar <kundankumar18581@gmail.com>
329
+ Stas Kelvich <stanconn@gmail.com>
330
+ sevaader <sevaader@gmail.com>
331
+ Dhruvesh Vijay Parikh <parikhdhruvesh1@gmail.com>
332
+ Venkatesh Halli <venkatesh.fatality@gmail.com>
333
+ Lennart Fricke <lennart@die-frickes.eu>
334
+ Vlad Seghete <vlad.seghete@gmail.com>
335
+ Shashank Agarwal <shashank.agarwal94@gmail.com>
336
+ carstimon <carstimon@gmail.com>
337
+ Pierre Haessig <pierre.haessig@crans.org>
338
+ Maciej Baranski <getrox.sc@gmail.com>
339
+ Benjamin Gudehus <hastebrot@gmail.com>
340
+ Faisal Anees <faisal.iiit@gmail.com>
341
+ Mark Shoulson <mark@kli.org>
342
+ Robert Johansson <jrjohansson@gmail.com>
343
+ Kalevi Suominen <jksuom@gmail.com>
344
+ Kaushik Varanasi <kaushik.varanasi1@gmail.com>
345
+ Fawaz Alazemi <Mba7eth@gmail.com>
346
+ Ambar Mehrotra <mehrotraambar@gmail.com>
347
+ David P. Sanders <dpsanders@gmail.com>
348
+ Peter Brady <petertbrady@gmail.com>
349
+ John V. Siratt <jvsiratt@gmail.com>
350
+ Sarwar Chahal <chahal.sarwar98@gmail.com>
351
+ Nathan Woods <charlesnwoods@gmail.com>
352
+ Colin B. Macdonald <cbm@m.fsf.org>
353
+ Marcus Näslund <naslundx@gmail.com>
354
+ Clemens Novak <clemens@familie-novak.net>
355
+ Mridul Seth <seth.mridul@gmail.com>
356
+ Craig A. Stoudt <craig.stoudt@gmail.com>
357
+ Raj <raj454raj@gmail.com>
358
+ Mihai A. Ionescu <ionescu.a.mihai@gmail.com>
359
+ immerrr <immerrr@gmail.com>
360
+ Chai Wah Wu <cwwuieee@gmail.com>
361
+ Leonid Blouvshtein <leonidbl91@gmail.com>
362
+ Peleg Michaeli <freepeleg@gmail.com>
363
+ ck Lux <lux.r.ck@gmail.com>
364
+ zsc347 <zsc347@gmail.com>
365
+ Hamish Dickson <hamish.dickson@gmail.com>
366
+ Michael Gallaspy <gallaspy.michael@gmail.com>
367
+ Roman Inflianskas <infroma@gmail.com>
368
+ Duane Nykamp <nykamp@umn.edu>
369
+ Ted Dokos <tdokos@gmail.com>
370
+ Sunny Aggarwal <sunnyaggarwal1994@gmail.com>
371
+ Victor Brebenar <v.brebenar@gmail.com>
372
+ Akshat Jain <akshat.jain@students.iiit.ac.in>
373
+ Shivam Vats <shivamvats.iitkgp@gmail.com>
374
+ Longqi Wang <iqgnol@gmail.com>
375
+ Juan Felipe Osorio <jfosorio@gmail.com>
376
+ Ray Cathcart <github@cathcart.us>
377
+ Lukas Zorich <lukas.zorich@gmail.com>
378
+ Eric Miller <emiller42@gmail.com>
379
+ Cody Herbst <cyherbst@gmail.com>
380
+ Nishith Shah <nishithshah.2211@gmail.com>
381
+ Amit Kumar <dtu.amit@gmail.com>
382
+ Yury G. Kudryashov <urkud.urkud@gmail.com>
383
+ Guillaume Gay <contact@damcb.com>
384
+ Mihir Wadwekar <m.mihirw@gmail.com>
385
+ Tuan Manh Lai <laituan245@gmail.com>
386
+ Asish Panda <asishrocks95@gmail.com>
387
+ Darshan Chaudhary <deathbullet@gmail.com>
388
+ Alec Kalinin <alec.kalinin@gmail.com>
389
+ Ralf Stephan <ralf@ark.in-berlin.de>
390
+ Aaditya Nair <aadityanair6494@gmail.com>
391
+ Jayesh Lahori <jlahori92@gmail.com>
392
+ Harshil Goel <harshil158@gmail.com>
393
+ Luv Agarwal <agarwal.iiit@gmail.com>
394
+ Jason Ly <jason.ly@gmail.com>
395
+ Lokesh Sharma <lokeshhsharma@gmail.com>
396
+ Sartaj Singh <singhsartaj94@gmail.com>
397
+ Chris Swierczewski <cswiercz@gmail.com>
398
+ Konstantin Togoi <konstantin.togoi@gmail.com>
399
+ Param Singh <paramsingh258@gmail.com>
400
+ Sumith Kulal <sumith1896@gmail.com>
401
+ Juha Remes <jremes@outlook.com>
402
+ Philippe Bouafia <philippe.bouafia@ensea.fr>
403
+ Peter Schmidt <peter@peterjs.com>
404
+ Jiaxing Liang <liangjiaxing57@gmail.com>
405
+ Lucas Jones <lucas@lucasjones.co.uk>
406
+ Gregory Ashton <gash789@gmail.com>
407
+ Jennifer White <jcrw122@googlemail.com>
408
+ Renato Orsino <renato.orsino@gmail.com>
409
+ Alistair Lynn <arplynn@gmail.com>
410
+ Govind Sahai <gsiitbhu@gmail.com>
411
+ Adam Bloomston <adam@glitterfram.es>
412
+ Kyle McDaniel <mcdanie5@illinois.edu>
413
+ Nguyen Truong Duy <truongduy134@yahoo.com>
414
+ Alex Lindsay <adlinds3@ncsu.edu>
415
+ Mathew Chong <mathewchong.dev@gmail.com>
416
+ Jason Siefken <siefkenj@gmail.com>
417
+ Gaurav Dhingra <gauravdhingra.gxyd@gmail.com>
418
+ Gao, Xiang <qasdfgtyuiop@gmail.com>
419
+ Kevin Ventullo <kevin.ventullo@gmail.com>
420
+ mao8 <thisisma08@gmail.com>
421
+ Isuru Fernando <isuruf@gmail.com>
422
+ Shivam Tyagi <shivam.tyagi.apm13@itbhu.ac.in>
423
+ Richard Otis <richard.otis@outlook.com>
424
+ Rich LaSota <rjlasota@gmail.com>
425
+ dustyrockpyle <dustyrockpyle@gmail.com>
426
+ Anton Akhmerov <anton.akhmerov@gmail.com>
427
+ Michael Zingale <michael.zingale@stonybrook.edu>
428
+ Chak-Pong Chung <chakpongchung@gmail.com>
429
+ David T <derDavidT@users.noreply.github.com>
430
+ Phil Ruffwind <rf@rufflewind.com>
431
+ Sebastian Koslowski <koslowski@kit.edu>
432
+ Kumar Krishna Agrawal <kumar.1994.14@gmail.com>
433
+ Dustin Gadal <Dustin.Gadal@gmail.com>
434
+ João Moura <operte@gmail.com>
435
+ Yu Kobayashi <yukoba@accelart.jp>
436
+ Shashank Kumar <shashank.kumar.apc13@iitbhu.ac.in>
437
+ Timothy Cyrus <tcyrus@users.noreply.github.com>
438
+ Devyani Kota <devyanikota@gmail.com>
439
+ Keval Shah <kevalshah_96@yahoo.co.in>
440
+ Dzhelil Rufat <drufat@caltech.edu>
441
+ Pastafarianist <mr.pastafarianist@gmail.com>
442
+ Sourav Singh <souravsingh@users.noreply.github.com>
443
+ Jacob Garber <jgarber1@ualberta.ca>
444
+ Vinay Singh <csvinay.d@gmail.com>
445
+ GolimarOurHero <metalera94@hotmail.com>
446
+ Prashant Tyagi <prashanttyagi221295@gmail.com>
447
+ Matthew Davis <davisml.md@gmail.com>
448
+ Tschijnmo TSCHAU <tschijnmotschau@gmail.com>
449
+ Alexander Bentkamp <bentkamp@gmail.com>
450
+ Jack Kemp <metaknightdrake-git@yahoo.co.uk>
451
+ Kshitij Saraogi <KshitijSaraogi@gmail.com>
452
+ Thomas Baruchel <baruchel@gmx.com>
453
+ Nicolás Guarín-Zapata <nicoguarin@gmail.com>
454
+ Jens Jørgen Mortensen <jj@smoerhul.dk>
455
+ Sampad Kumar Saha <sampadsaha5@gmail.com>
456
+ Eva Charlotte Mayer <eva-charlotte.mayer@posteo.de>
457
+ Laura Domine <temigo@gmx.com>
458
+ Justin Blythe <jblythe29@gmail.com>
459
+ Meghana Madhyastha <meghana.madhyastha@gmail.com>
460
+ Tanu Hari Dixit <tokencolour@gmail.com>
461
+ Shekhar Prasad Rajak <shekharrajak@live.com>
462
+ Aqnouch Mohammed <aqnouch.mohammed@gmail.com>
463
+ Arafat Dad Khan <arafat.da.khan@gmail.com>
464
+ Boris Atamanovskiy <shaomoron@gmail.com>
465
+ Sam Tygier <sam.tygier@hep.manchester.ac.uk>
466
+ Jai Luthra <me@jailuthra.in>
467
+ Guo Xingjian <Seeker1995@gmail.com>
468
+ Sandeep Veethu <sandeep.veethu@gmail.com>
469
+ Archit Verma <architv07@gmail.com>
470
+ Shubham Tibra <shubh.tibra@gmail.com>
471
+ Ashutosh Saboo <ashutosh.saboo96@gmail.com>
472
+ Michael S. Hansen <michael.hansen@nih.gov>
473
+ Anish Shah <shah.anish07@gmail.com>
474
+ Guillaume Jacquenot <guillaume.jacquenot@gmail.com>
475
+ Bhautik Mavani <mavanibhautik@gmail.com>
476
+ Michał Radwański <enedil.isildur@gmail.com>
477
+ Jerry Li <jerry@jerryli.ca>
478
+ Pablo Zubieta <pabloferz@yahoo.com.mx>
479
+ Shivam Agarwal <knowthyself2503@gmail.com>
480
+ Chaitanya Sai Alaparthi <achaitanyasai@gmail.com>
481
+ Arihant Parsoya <parsoyaarihant@gmail.com>
482
+ Ruslan Pisarev <rpisarev@cloudlinux.com>
483
+ Akash Trehan <akash.trehan123@gmail.com>
484
+ Nishant Nikhil <nishantiam@gmail.com>
485
+ Vladimir Poluhsin <vovapolu@gmail.com>
486
+ Akshay Nagar <awesomeay13@yahoo.com>
487
+ James Brandon Milam <jmilam343@gmail.com>
488
+ Abhinav Agarwal <abhinavagarwal1996@gmail.com>
489
+ Rishabh Daal <rishabhdaal@gmail.com>
490
+ Sanya Khurana <sanya@monica.in>
491
+ Aman Deep <amandeep1024@gmail.com>
492
+ Aravind Reddy <aravindreddy255@gmail.com>
493
+ Abhishek Verma <iamvermaabhishek@gmail.com>
494
+ Matthew Parnell <matt@parnmatt.co.uk>
495
+ Thomas Hickman <Thomas.Hickman42@gmail.com>
496
+ Akshay Siramdas <akshaysiramdas@gmail.com>
497
+ YiDing Jiang <yidinggjiangg@gmail.com>
498
+ Jatin Yadav <jatinyadav25@gmail.com>
499
+ Matthew Thomas <mnmt@users.noreply.github.com>
500
+ Rehas Sachdeva <aquannie@gmail.com>
501
+ Michael Mueller <michaeldmueller7@gmail.com>
502
+ Srajan Garg <srajan.garg@gmail.com>
503
+ Prabhjot Singh <prabhjot.nith@gmail.com>
504
+ Haruki Moriguchi <harukimoriguchi@gmail.com>
505
+ Tom Gijselinck <tomgijselinck@gmail.com>
506
+ Nitin Chaudhary <nitinmax1000@gmail.com>
507
+ Alex Argunov <sajkoooo@gmail.com>
508
+ Nathan Musoke <nathan.musoke@gmail.com>
509
+ Abhishek Garg <abhishekgarg119@gmail.com>
510
+ Dana Jacobsen <dana@acm.org>
511
+ Vasiliy Dommes <vasdommes@gmail.com>
512
+ Phillip Berndt <phillip.berndt@googlemail.com>
513
+ Haimo Zhang <zh.hammer.dev@gmail.com>
514
+ Anthony Scopatz <scopatz@gmail.com>
515
+ bluebrook <perl4logic@gmail.com>
516
+ Leonid Kovalev <leonidvkovalev@gmail.com>
517
+ Josh Burkart <jburkart@gmail.com>
518
+ Dimitra Konomi <t8130064@dias.aueb.gr>
519
+ Christina Zografou <t8130048@dias.aueb.gr>
520
+ Fiach Antaw <fiach.antaw+github@gmail.com>
521
+ Langston Barrett <langston.barrett@gmail.com>
522
+ Krit Karan <kritkaran.b13@iiits.in>
523
+ G. D. McBain <gdmcbain@protonmail.com>
524
+ Prempal Singh <prempal.42@gmail.com>
525
+ Gabriel Orisaka <orisaka@gmail.com>
526
+ Matthias Bussonnier <bussonniermatthias@gmail.com>
527
+ rahuldan <rahul02013@gmail.com>
528
+ Colin Marquardt <github@marquardt-home.de>
529
+ Andrew Taber <andrew.e.taber@gmail.com>
530
+ Yash Reddy <write2yashreddy@gmail.com>
531
+ Peter Stangl <peter.stangl@ph.tum.de>
532
+ elvis-sik <e.sikora@grad.ufsc.br>
533
+ Nikos Karagiannakis <nikoskaragiannakis@gmail.com>
534
+ Jainul Vaghasia <jainulvaghasia@gmail.com>
535
+ Dennis Meckel <meckel@datenschuppen.de>
536
+ Harshil Meena <harshil.7535@gmail.com>
537
+ Micky <mickydroch@gmail.com>
538
+ Nick Curtis <nicholas.curtis@uconn.edu>
539
+ Michele Zaffalon <michele.zaffalon@gmail.com>
540
+ Martha Giannoudovardi <maapxa@gmail.com>
541
+ Devang Kulshreshtha <devang.kulshreshtha.cse14@itbhu.ac.in>
542
+ Steph Papanik <spapanik21@gmail.com>
543
+ Mohammad Sadeq Dousti <msdousti@gmail.com>
544
+ Arif Ahmed <arif.ahmed.5.10.1995@gmail.com>
545
+ Abdullah Javed Nesar <abduljaved1994@gmail.com>
546
+ Lakshya Agrawal <zeeshan.lakshya@gmail.com>
547
+ shruti <shrutishrm512@gmail.com>
548
+ Rohit Rango <rohit.rango@gmail.com>
549
+ Hong Xu <hong@topbug.net>
550
+ Ivan Petuhov <ivan@ostrovok.ru>
551
+ Alsheh <alsheh@rpi.edu>
552
+ Marcel Stimberg <marcel.stimberg@ens.fr>
553
+ Alexey Pakhocmhik <cool.Bakov@yandex.ru>
554
+ Tommy Olofsson <tommy.olofsson.90@gmail.com>
555
+ Zulfikar <zulfikar97@gmail.com>
556
+ Blair Azzopardi <blairuk@gmail.com>
557
+ Danny Hermes <daniel.j.hermes@gmail.com>
558
+ Sergey Pestov <pestov-sa@yandex.ru>
559
+ Mohit Chandra <mohit.chandra@research.iiit.ac.in>
560
+ Karthik Chintapalli <karthik.chintapalli@students.iiit.ac.in>
561
+ Marcin Briański <marcin.brianski@student.uj.edu.pl>
562
+ andreo <andrey.torba@gmail.com>
563
+ Flamy Owl <flamyowl@protonmail.ch>
564
+ Yicong Guo <guoyicong100@gmail.com>
565
+ Varun Garg <varun.garg03@gmail.com>
566
+ Rishabh Madan <rishabhmadan96@gmail.com>
567
+ Aditya Kapoor <aditya.kapoor.apm12@itbhu.ac.in>
568
+ Karan Sharma <karan1276@gmail.com>
569
+ Vedant Rathore <vedantr1998@gmail.com>
570
+ Johan Blåbäck <johan_bluecreek@riseup.net>
571
+ Pranjal Tale <pranjaltale16@gmail.com>
572
+ Jason Tokayer <jason.tokayer@gmail.com>
573
+ Raghav Jajodia <jajodia.raghav@gmail.com>
574
+ Rajat Thakur <rajatthakur1997@gmail.com>
575
+ Dhruv Bhanushali <dhruv_b@live.com>
576
+ Anjul Kumar Tyagi <anjul.ten@gmail.com>
577
+ Barun Parruck <barun.parruck@gmail.com>
578
+ Bao Chau <chauquocbao0907@gmail.com>
579
+ Tanay Agrawal <tanay_agrawal@hotmail.com>
580
+ Ranjith Kumar <ranjith.dakshana2015@gmail.com>
581
+ Shikhar Makhija <shikharmakhija2@gmail.com>
582
+ Yathartha Joshi <yathartha32@gmail.com>
583
+ Valeriia Gladkova <valeriia.gladkova@gmail.com>
584
+ Sagar Bharadwaj <sagarbharadwaj50@gmail.com>
585
+ Daniel Mahler <dmahler@gmail.com>
586
+ Ka Yi <chua.kayi@yahoo.com.sg>
587
+ Rishat Iskhakov <iskhakov@frtk.ru>
588
+ Szymon Mieszczak <szymon.mieszczak@gmail.com>
589
+ Sachin Agarwal <sachinagarwal0499@gmail.com>
590
+ Priyank Patel <pspbot7@gmail.com>
591
+ Satya Prakash Dwibedi <akash581050@gmail.com>
592
+ tools4origins <tools4origins@gmail.com>
593
+ Nico Schlömer <nico.schloemer@gmail.com>
594
+ Fermi Paradox <FermiParadox@users.noreply.github.com>
595
+ Ekansh Purohit <purohit.e15@gmail.com>
596
+ Vedarth Sharma <vedarth.sharma@gmail.com>
597
+ Peeyush Kushwaha <peeyush.p97@gmail.com>
598
+ Jayjayyy <vfhsln8s3l4b87t4c3@byom.de>
599
+ Christopher J. Wright <cjwright4242gh@gmail.com>
600
+ Jakub Wilk <jwilk@jwilk.net>
601
+ Mauro Garavello <mauro.garavello@unimib.it>
602
+ Chris Tefer <ctefer@gmail.com>
603
+ Shikhar Jaiswal <jaiswalshikhar87@gmail.com>
604
+ Chiu-Hsiang Hsu <wdv4758h@gmail.com>
605
+ Carlos Cordoba <ccordoba12@gmail.com>
606
+ Fabian Ball <fabian.ball@kit.edu>
607
+ Yerniyaz <yerniyaz.nurgabylov@nu.edu.kz>
608
+ Christiano Anderson <canderson@riseup.net>
609
+ Robin Neatherway <robin.neatherway@gmail.com>
610
+ Thomas Hunt <thomashunt13@gmail.com>
611
+ Theodore Han <theodorehan@hotmail.com>
612
+ Duc-Minh Phan <alephvn@gmail.com>
613
+ Lejla Metohajrova <l.metohajrova@gmail.com>
614
+ Samyak Jain <samyak.jain2016a@vitstudent.ac.in>
615
+ Aditya Rohan <riyuzakiiitk@gmail.com>
616
+ Vincent Delecroix <vincent.delecroix@labri.fr>
617
+ Michael Sparapany <msparapa@purdue.edu>
618
+ Harsh Jain <harshjniitr@gmail.com>
619
+ Nathan Goldbaum <ngoldbau@illinois.edu>
620
+ latot <felipematas@yahoo.com>
621
+ Kenneth Lyons <ixjlyons@gmail.com>
622
+ Stan Schymanski <stan.schymanski@env.ethz.ch>
623
+ David Daly <david.daly12@kzoo.edu>
624
+ Ayush Shridhar <ayush.shridhar1999@gmail.com>
625
+ Javed Nissar <javednissar@gmail.com>
626
+ Jiri Kuncar <jiri.kuncar@gmail.com>
627
+ vedantc98 <vedantc98@gmail.com>
628
+ Rupesh Harode <rupeshharode@gmail.com>
629
+ Rob Zinkov <rob@zinkov.com>
630
+ James Harrop <ebc121@gmail.com>
631
+ James Taylor <user234683@tutanota.com>
632
+ Ishan Joshi <ishanaj98@gmail.com>
633
+ Marco Mancini <marco.mancini@obspm.fr>
634
+ Boris Ettinger <ettinger.boris@gmail.com>
635
+ Micah Fitch <micahscopes@gmail.com>
636
+ Daniel Wennberg <daniel.wennberg@gmail.com>
637
+ ylemkimon <ylemkimon@naver.com>
638
+ Akash Vaish <akash.9712@gmail.com>
639
+ Peter Enenkel <peter.enenkel+git@gmail.com>
640
+ Waldir Pimenta <waldyrious@gmail.com>
641
+ Jithin D. George <jithindgeorge93@gmail.com>
642
+ Lev Chelyadinov <leva181777@gmail.com>
643
+ Lucas Wiman <lucas.wiman@gmail.com>
644
+ Rhea Parekh <rheaparekh12@gmail.com>
645
+ James Cotton <peabody124@gmail.com>
646
+ Robert Pollak <robert.pollak@posteo.net>
647
+ anca-mc <anca-mc@users.noreply.github.com>
648
+ Sourav Ghosh <souravghosh2197@gmail.com>
649
+ Jonathan Allan <jjallan@users.noreply.github.com>
650
+ Nikhil Pappu <nkhlpappu@gmail.com>
651
+ Ethan Ward <etkewa@gmail.com>
652
+ Cezary Marczak <zeddq1@gmail.com>
653
+ dps7ud <dps7ud@virginia.edu>
654
+ Nilabja Bhattacharya <nilabja10201992@gmail.com>
655
+ Itay4 <31018228+Itay4@users.noreply.github.com>
656
+ Poom Chiarawongse <eight1911@gmail.com>
657
+ Yang Yang <wdscxsj@gmail.com>
658
+ Cavendish McKay <cmckay@tachycline.com>
659
+ Bradley Gannon <bradley.m.gannon@gmail.com>
660
+ B McG <bmcg0890@gmail.com>
661
+ Rob Drynkin <rob.drynkin@gmail.com>
662
+ Seth Ebner <murgrehk@gmail.com>
663
+ Akash Kundu <sk.sayakkundu1997@gmail.com>
664
+ Mark Jeromin <mark.jeromin@sysfrog.net>
665
+ Roberto Díaz Pérez <r.r.1994a@gmail.com>
666
+ Gleb Siroki <g.shiroki@gmail.com>
667
+ Segev Finer <segev208@gmail.com>
668
+ Alex Lubbock <code@alexlubbock.com>
669
+ Ayodeji Ige <ayodeji18@outlook.com>
670
+ Matthew Wardrop <matthew.wardrop@airbnb.com>
671
+ Hugo van Kemenade <hugovk@users.noreply.github.com>
672
+ Austin Palmer <ap4000@nyu.edu>
673
+ der-blaue-elefant <github@kklein.de>
674
+ Filip Gokstorp <filip@gokstorp.se>
675
+ Yuki Matsuda <yuki.matsuda.w@gmail.com>
676
+ Aaron Miller <acmiller273@gmail.com>
677
+ Salil Vishnu Kapur <salilvishnukapur@gmail.com>
678
+ Atharva Khare <khareatharva@gmail.com>
679
+ Shubham Maheshwari <rmaheshwari05@gmail.com>
680
+ Pavel Tkachenko <paveltkachenko@email.com>
681
+ Ashish Kumar Gaurav <ashishkg0022@gmail.com>
682
+ Rajeev Singh <rajs2010@gmail.com>
683
+ Keno Goertz <keno@goertz-berlin.com>
684
+ Lucas Gallindo <lgallindo@gmail.com>
685
+ Himanshu <hs80941@gmail.com>
686
+ David Menéndez Hurtado <david.menendez.hurtado@scilifelab.se>
687
+ Amit Manchanda <amitdelhi1995@gmail.com>
688
+ Rohit Jain <rohitjain3241@gmail.com>
689
+ Jonathan A. Gross <jarthurgross@gmail.com>
690
+ Unknown <kunda@scribus.net>
691
+ Sayan Goswami <Sayan98@users.noreply.github.com>
692
+ Subhash Saurabh <subhashsaurabh419@gmail.com>
693
+ Rastislav Rabatin <rastislav.rabatin@gmail.com>
694
+ Vishal <vishalg2235@gmail.com>
695
+ Jeremey Gluck <jeremygluck@yahoo.com>
696
+ Akshat Maheshwari <akshat14714@gmail.com>
697
+ symbolique <symbolique@users.noreply.github.com>
698
+ Saloni Jain <tosalonijain@gmail.com>
699
+ Arighna Chakrabarty <arighna.chakrabarty100@gmail.com>
700
+ Abhigyan Khaund <mail@abhigyan.xyz>
701
+ Jashanpreet Singh <jashansingh.4398@gmail.com>
702
+ Saurabh Agarwal <shourabh.agarwal@gmail.com>
703
+ luzpaz <luzpaz@users.noreply.github.com>
704
+ P. Sai Prasanth <psai.prasanth.min16@itbhu.ac.in>
705
+ Nirmal Sarswat <nirmalsarswat400@gmail.com>
706
+ Cristian Di Pietrantonio <cristiandipietrantonio@gmail.com>
707
+ Ravi charan <ravicharan.vsp@gmail.com>
708
+ Nityananda Gohain <nityanandagohain@gmail.com>
709
+ Cédric Travelletti <cedrictravelletti@gmail.com>
710
+ Nicholas Bollweg <nick.bollweg@gmail.com>
711
+ Himanshu Ladia <hladia199811@gmail.com>
712
+ Adwait Baokar <adwaitbaokar18@gmail.com>
713
+ Mihail Tarigradschi <m.tarigradschi@gmail.com>
714
+ Saketh <alurusaisaketh@gmail.com>
715
+ rushyam <rushyamsonu@gmail.com>
716
+ sfoo <sfoohei@gmail.com>
717
+ Rahil Hastu <rahilhastu@gmail.com>
718
+ Zach Raines <raineszm@gmail.com>
719
+ Sidhant Nagpal <sidhantnagpal97@gmail.com>
720
+ Gagandeep Singh <singh.23@iitj.ac.in>
721
+ Rishav Chakraborty <annonymousxyz@outlook.com>
722
+ Malkhan Singh <malkhansinghrathaur@gmail.com>
723
+ Joaquim Monserrat <qmonserrat@mailoo.org>
724
+ Mayank Singh <mayank.singh081997@gmail.com>
725
+ Rémy Léone <rleone@online.net>
726
+ Maxence Mayrand <35958639+maxencemayrand@users.noreply.github.com>
727
+ Nikoleta Glynatsi <GlynatsiNE@cardiff.ac.uk>
728
+ helo9 <helo9@users.noreply.github.com>
729
+ Ken Wakita <wakita@is.titech.ac.jp>
730
+ Carl Sandrock <carl.sandrock@up.ac.za>
731
+ Fredrik Eriksson <freeriks@student.chalmers.se>
732
+ Ian Swire <oversizedpenguin@gmail.com>
733
+ Bulat <daianovich@mail.ru>
734
+ Ehren Metcalfe <ehren.m@gmail.com>
735
+ Dmitry Savransky <dsavransky@gmail.com>
736
+ Kiyohito Yamazaki <kyamaz@openql.org>
737
+ Caley Finn <caleyreuben@gmail.com>
738
+ Zhi-Qiang Zhou <zzq_890709@hotmail.com>
739
+ Alexander Pozdneev <pozdneev@users.noreply.github.com>
740
+ Wes Turner <50891+westurner@users.noreply.github.com>
741
+ JMSS-Unknown <31131631+JMSS-Unknown@users.noreply.github.com>
742
+ Arshdeep Singh <singh.arshdeep1999@gmail.com>
743
+ cym1 <16437732+cym1@users.noreply.github.com>
744
+ Stewart Wadsworth <stewart.wadsworth@gmail.com>
745
+ Jared Lumpe <mjlumpe@gmail.com>
746
+ Avi Shrivastava <shrivastavaavi123@gmail.com>
747
+ ramvenkat98 <ramvenkat98@gmail.com>
748
+ Bilal Ahmed <b.ahmed0918@gmail.com>
749
+ Dimas Abreu Archanjo Dutra <dimasad@ufmg.br>
750
+ Yatna Verma <yatnavermaa@gmail.com>
751
+ S.Y. Lee <sylee957@gmail.com>
752
+ Miro Hrončok <miro@hroncok.cz>
753
+ Sudarshan Kamath <sudarshan.kamath97@gmail.com>
754
+ Ayushman Koul <ayushmankoul4570@gmail.com>
755
+ Robert Dougherty-Bliss <robert.w.bliss@gmail.com>
756
+ Andrey Grozin <A.G.Grozin@inp.nsk.su>
757
+ Bavish Kulur <bavishkulur@gmail.com>
758
+ Arun Singh <arunsin997@gmail.com>
759
+ sirnicolaf <43586954+sirnicolaf@users.noreply.github.com>
760
+ Zachariah Etienne <zachetie@gmail.com>
761
+ Prayush Dawda <35144226+iamprayush@users.noreply.github.com>
762
+ 2torus <boris.ettinger@gmail.com>
763
+ Faisal Riyaz <faisalriyaz011@gmail.com>
764
+ Martin Roelfs <u0114255@kuleuven.be>
765
+ SirJohnFranklin <sirjfu@googlemail.com>
766
+ Anthony Sottile <asottile@umich.edu>
767
+ ViacheslavP <public.viacheslav@gmail.com>
768
+ Safiya03 <safiyanesar@gmail.com>
769
+ Alexander Dunlap <alexander.dunlap@gmail.com>
770
+ Rohit Sharma <31184621+rohitx007@users.noreply.github.com>
771
+ Jonathan Warner <warnerjon12@gmail.com>
772
+ Mohit Balwani <mohitbalwani.ict17@gmail.com>
773
+ Marduk Bolaños <mardukbp@mac.com>
774
+ amsuhane <ayushsuhane99@iitkgp.ac.in>
775
+ Matthias Geier <Matthias.Geier@gmail.com>
776
+ klaasvanaarsen <44929042+klaasvanaarsen@users.noreply.github.com>
777
+ Shubham Kumar Jha <skjha832@gmail.com>
778
+ rationa-kunal <kunalgk1999@gmail.com>
779
+ Animesh Sinha <animeshsinha1309@gmail.com>
780
+ Gaurang Tandon <1gaurangtandon@gmail.com>
781
+ Matthew Craven <clyring@users.noreply.github.com>
782
+ Daniel Ingram <ingramds@appstate.edu>
783
+ Jogi Miglani <jmig5776@gmail.com>
784
+ Takumasa Nakamura <n.takumasa@gmail.com>
785
+ Ritu Raj Singh <RituRajSingh878@gmail.com>
786
+ Rajiv Ranjan Singh <rajivperfect007@gmail.com>
787
+ Vera Lozhkina <veralozhkina@gmail.com>
788
+ adhoc-king <46354827+adhoc-king@users.noreply.github.com>
789
+ Mikel Rouco <mikel.mrm@gmail.com>
790
+ Oscar Gustafsson <oscar.gustafsson@gmail.com>
791
+ damianos <damianos@semmle.com>
792
+ Supreet Agrawal <supreet11agrawal@gmail.com>
793
+ shiksha11 <shiksharawat01@gmail.com>
794
+ Martin Ueding <dev@martin-ueding.de>
795
+ sharma-kunal <kunalsharma6914@gmail.com>
796
+ Divyanshu Thakur <divyanshu@iiitmanipur.ac.in>
797
+ Susumu Ishizuka <susumu.ishizuka@kii.com>
798
+ Samnan Rahee <namanush.rsr.16@gmail.com>
799
+ Fredrik Andersson <fredrik.andersson@fcc.chalmers.se>
800
+ Bhavya Srivastava <bhavya17037@iiitd.ac.in>
801
+ Alpesh Jamgade <alpeshjamgade21@gmail.com>
802
+ Shubham Abhang <shubhamabhang77@gmail.com>
803
+ Vishesh Mangla <manglavishesh64@gmail.com>
804
+ Nicko van Someren <nicko@nicko.org>
805
+ dandiez <47832466+dandiez@users.noreply.github.com>
806
+ Frédéric Chapoton <fchapoton2@gmail.com>
807
+ jhanwar <f2015463@pilani.bits-pilani.ac.in>
808
+ Noumbissi valere Gille Geovan <noumbissivalere@gmail.com>
809
+ Salmista-94 <alejandrogroso@hotmail.com>
810
+ Shivani Kohli <shivanikohli.09@gmail.com>
811
+ Parker Berry <parkereberry@gmail.com>
812
+ Pragyan Mehrotra <pragyan18168@iiitd.ac.in>
813
+ Nabanita Dash <dashnabanita@gmail.com>
814
+ Gaetano Guerriero <x.guerriero@tin.it>
815
+ Ankit Raj Pandey <pandeyan@grinnell.edu>
816
+ Ritesh Kumar <ritesh99rakesh@gmail.com>
817
+ kangzhiq <709563092@qq.com>
818
+ Jun Lin <junlin0604@gmail.com>
819
+ Petr Kungurtsev <corwinat@gmail.com>
820
+ Anway De <anway1756@gmail.com>
821
+ znxftw <vishnu2101@gmail.com>
822
+ Denis Ivanenko <ivanenko@ucu.edu.ua>
823
+ Orestis Vaggelis <orestisvaggelis@mail.com>
824
+ Nikhil Maan <nikhilmaan22@gmail.com>
825
+ Abhinav Anand <abhinav.anand2807@gmail.com>
826
+ Qingsha Shi <googol.sqs@gmail.com>
827
+ Juan Barbosa <js.barbosa10@uniandes.edu.co>
828
+ Prionti Nasir <pdn3628@rit.edu>
829
+ Bharat Raghunathan <bharatraghunthan9767@gmail.com>
830
+ arooshiverma <av22@iitbbs.ac.in>
831
+ Christoph Gohle <ctg@mpq.mpg.de>
832
+ Charalampos Tsiagkalis <ctsiagkalis@uth.gr>
833
+ Daniel Sears <highpost@users.noreply.github.com>
834
+ Megan Ly <megan.ly@learnosity.com>
835
+ Sean P. Cornelius <spcornelius@gmail.com>
836
+ Erik R. Gomez <gomez@kth.se>
837
+ Riccardo Magliocchetti <riccardo.magliocchetti@gmail.com>
838
+ Henry Metlov <genrih.metlov@gmail.com>
839
+ pekochun <hamburg_hamburger2000@yahoo.co.jp>
840
+ Bendik Samseth <b.samseth@gmail.com>
841
+ Vighnesh Shenoy <vighneshq@gmail.com>
842
+ Versus Void <versusvoid@gmail.com>
843
+ Denys Rybalka <rybalka.denis@gmail.com>
844
+ Mark Dickinson <dickinsm@gmail.com>
845
+ Rimi <rimibis@umich.edu>
846
+ rimibis <33387803+rimibis@users.noreply.github.com>
847
+ Steven Lee <stevenlee123@protonmail.com>
848
+ Gilles Schintgen <gschintgen@hambier.lu>
849
+ Abhi58 <abhijithbharadwaj58@gmail.com>
850
+ Tomasz Pytel <tompytel@gmail.com>
851
+ Aadit Kamat <aadit.k12@gmail.com>
852
+ Samesh <samesh.lakhotia@gmail.com>
853
+ Velibor Zeli <velibor@mech.kth.se>
854
+ Gabriel Bernardino <gabriel.bernardino@upf.edu>
855
+ Joseph Redfern <joseph@redfern.me>
856
+ Evelyn King <evelyn.cameron.king@gmail.com>
857
+ Miguel Marco <mmarco@unizar.es>
858
+ David Hagen <david@drhagen.com>
859
+ Hannah Kari <hannah.kari@marquette.edu>
860
+ Soniya Nayak <soniyanayak51@gmail.com>
861
+ Harsh Agarwal <hagarwal9200@gmail.com>
862
+ Enric Florit <efz1005@gmail.com>
863
+ Yogesh Mishra <ymishra013@gmail.com>
864
+ Denis Rykov <rykovd@gmail.com>
865
+ Ivan Tkachenko <me@ratijas.tk>
866
+ Kenneth Emeka Odoh <kenneth.odoh@gmail.com>
867
+ Stephan Seitz <stephan.seitz@fau.de>
868
+ Yeshwanth N <yeshsurya@gmail.com>
869
+ Oscar Gerardo Lazo Arjona <oscar.lazoarjona@physics.ox.ac.uk>
870
+ Srinivasa Arun Yeragudipati <ysarun1999@gmail.com>
871
+ Kirtan Mali <kirtanmali555@gmail.com>
872
+ TitanSnow <sweeto@live.cn>
873
+ Pengning Chao <8857165+PengningChao@users.noreply.github.com>
874
+ Louis Abraham <louis.abraham@yahoo.fr>
875
+ Morten Olsen Lysgaard <morten@lysgaard.no>
876
+ Akash Nagaraj (akasnaga) <akasnaga@cisco.com>
877
+ Akash Nagaraj <grassknoted@gmail.com>
878
+ Lauren Glattly <laurenglattly@gmail.com>
879
+ Hou-Rui <houruinus@gmail.com>
880
+ George Korepanov <gkorepanov.gk@gmail.com>
881
+ dranknight09 <cbhaavan@gmail.com>
882
+ aditisingh2362 <aditisingh2362@gmail.com>
883
+ Gina <Dr-G@users.noreply.github.com>
884
+ gregmedlock <gmedlo@gmail.com>
885
+ Georgios Giapitzakis Tzintanos <giorgosgiapis@mail.com>
886
+ Eric Wieser <wieser.eric@gmail.com>
887
+ Bradley Dowling <34559056+btdow@users.noreply.github.com>
888
+ Maria Marginean <33810762+mmargin@users.noreply.github.com>
889
+ Akash Agrawall <akash.wanted@gmail.com>
890
+ jgulian <josephdgulian@gmail.com>
891
+ Sourav Goyal <souravgl0@gmail.com>
892
+ Zlatan Vasović <zlatanvasovic@gmail.com>
893
+ Alex Meiburg <timeroot.alex@gmail.com>
894
+ Smit Lunagariya <smitlunagariya.mat18@itbhu.ac.in>
895
+ Naman Gera <namangera15@gmail.com>
896
+ Julien Palard <julien@palard.fr>
897
+ Dhruv Mendiratta <dhruvmendiratta6@gmail.com>
898
+ erdOne <36414270+erdOne@users.noreply.github.com>
899
+ risubaba <risubhjain1010@gmail.com>
900
+ abhinav28071999 <41710346+abhinav28071999@users.noreply.github.com>
901
+ Jisoo Song <jeesoo9595@snu.ac.kr>
902
+ Jaime R <38530589+Jaime02@users.noreply.github.com>
903
+ Vikrant Malik <vikrantmalik051@gmail.com>
904
+ Hardik Saini <43683678+Guardianofgotham@users.noreply.github.com>
905
+ Abhishek <uchiha@pop-os.localdomain>
906
+ Johannes Hartung <joha2@gmx.net>
907
+ Milan Jolly <milan.cs16@iitp.ac.in>
908
+ faizan2700 <syedfaizan824@gmail.com>
909
+ mohit <39158356+mohitacecode@users.noreply.github.com>
910
+ Mohit Gupta <mohitgupta@gmail.com>
911
+ Psycho-Pirate <prakharsaxena.civ18@iitbhu.ac.in>
912
+ Chanakya-Ekbote <ca10@iitbbs.ac.in>
913
+ Rashmi Shehana <rashmi.watagedara@syscolabs.com>
914
+ Jonty16117 <jonty@DESKTOP-J1O6ANP.localdomain>
915
+ Anubhav Gupta <anubhav.gupta.cse19@itbhu.ac.in>
916
+ Michal Grňo <m93a.cz@gmail.com>
917
+ vezeli <37907135+vezeli@users.noreply.github.com>
918
+ Tim Gates <tim.gates@iress.com>
919
+ Sandeep Murthy <smurthy@protonmail.ch>
920
+ Neil <mistersheik@gmail.com>
921
+ V1krant <46847915+V1krant@users.noreply.github.com>
922
+ alejandro <amartinhernan@gmail.com>
923
+ Riyan Dhiman <Riyandhiman14@gmail.com>
924
+ sbt4104 <sthorat661@gmail.com>
925
+ Seth Troisi <sethtroisi@google.com>
926
+ Bhaskar Gupta <guptabhanu1999@gmail.com>
927
+ Smit Gajjar <smitgajjar.gs@gmail.com>
928
+ rbl <rlee@grove.co>
929
+ Ilya Pchelintsev <ilya.pchelintsev@outlook.com>
930
+ Omar Wagih <o.wagih.ow@gmail.com>
931
+ prshnt19 <prashant.rawat216@gmail.com>
932
+ Johan Guzman <jguzm022@ucr.edu>
933
+ Vasileios Kalos <kalosbasileios@gmail.com>
934
+ BasileiosKal <61801875+BasileiosKal@users.noreply.github.com>
935
+ Shubham Thorat <37049710+sbt4104@users.noreply.github.com>
936
+ Arpan Chattopadhyay <f20180319@pilani.bits-pilani.ac.in>
937
+ Ashutosh Hathidara <ashutoshhathidara98@gmail.com>
938
+ Moses Paul R <iammosespaulr@gmail.com>
939
+ Saanidhya vats <saanidhyavats@gmail.com>
940
+ tnzl <you@example.com>
941
+ Vatsal Srivastava <alstav.trivas.sava@gmail.com>
942
+ Jean-Luc Herren <jlh@gmx.ch>
943
+ Dhruv Kothari <dhruvkothari22@gmail.com>
944
+ seadavis <45022599+seadavis@users.noreply.github.com>
945
+ kamimura <kamimura@live.jp>
946
+ slacker404 <pchantza@gmail.com>
947
+ Jaime Resano <gemailpersonal02@gmail.com>
948
+ Ebrahim Byagowi <ebrahim@gnu.org>
949
+ wuyudi <wuyudi119@163.com>
950
+ Akira Kyle <ak@akirakyle.com>
951
+ Calvin Jay Ross <calvinjayross@gmail.com>
952
+ Martin Thoma <info@martin-thoma.de>
953
+ Thomas A Caswell <tcaswell@gmail.com>
954
+ Lagaras Stelios <stel.lag@hotmail.com>
955
+ Jerry James <loganjerry@gmail.com>
956
+ Jan Kruse <janckruse@t-online.de>
957
+ Nathan Taylor <pecan.pine@gmail.com>
958
+ Vaishnav Damani <vaishnavdamani3496@gmail.com>
959
+ Mohit Shah <mohitshah3111999@gmail.com>
960
+ Mathias Louboutin <mathias.louboutin@gmail.com>
961
+ Marijan Smetko <marijansmetko123@gmail.com>
962
+ Dave Witte Morris <Dave.Morris@uleth.ca>
963
+ soumi7 <soumibardhan10@gmail.com>
964
+ Zhongshi <zj495@nyu.edu>
965
+ Wes Galbraith <galbwe92@gmail.com>
966
+ KaustubhDamania <kaustubh.damania@gmail.com>
967
+ w495 <w495@yandex-team.ru>
968
+ Akhil Rajput <akh1lrjput@gmail.com>
969
+ Markus Mohrhard <markus.mohrhard@googlemail.com>
970
+ Benjamin Wolba <mail@benjaminwolba.com>
971
+ 彭于斌 <1931127624@qq.com>
972
+ Rudr Tiwari <rudrtiwari@gmail.com>
973
+ Aaryan Dewan <aaryandewan@yahoo.com>
974
+ Benedikt Placke <benedikt.placke@outlook.com>
975
+ Sneha Goddu <s.goddu@wustl.edu>
976
+ goddus <39923708+goddus@users.noreply.github.com>
977
+ Shivang Dubey <shivangdubey8@gmail.com>
978
+ Michael Greminger <michael.greminger@gmail.com>
979
+ Peter Cock <p.j.a.cock@googlemail.com>
980
+ Willem Melching <willem.melching@gmail.com>
981
+ Elias Basler <e.e.basler@protonmail.com>
982
+ Brandon David <brandon.david@zoho.com>
983
+ Abhay_Dhiman <abhaysdhimans@gmail.com>
984
+ Tasha Kim <jae_young_kim@brown.edu>
985
+ Ayush Malik <ayushmalik779@gmail.com>
986
+ Devesh Sawant <devesh47cool@gmail.com>
987
+ Wolfgang Stöcher <wolfgang@stoecher.com>
988
+ Sudeep Sidhu <sudeepmanilsidhu@gmail.com>
989
+ foice <foice.news@gmail.com>
990
+ Ben Payne <ben.is.located@gmail.com>
991
+ Muskan Kumar <31043527+muskanvk@users.noreply.github.com>
992
+ noam simcha finkelstein <noam.finkelstein@protonmail.com>
993
+ Garrett Folbe <gmfolbe@yahoo.com>
994
+ Islam Mansour <is3mansour@gmail.com>
995
+ Sayandip Halder <sayandiph4@gmail.com>
996
+ Shubham Agrawal <shubham.ag6845@gmail.com>
997
+ numbermaniac <5206120+numbermaniac@users.noreply.github.com>
998
+ Sakirul Alam <binarysakir@gmail.com>
999
+ Mohammed Bilal <r.mohammedbilal@gmail.com>
1000
+ Chris du Plessis <christopherjonduplessis@gmail.com>
1001
+ Coder-RG <rgoel1999@gmail.com>
1002
+ Ansh Mishra <anshmishra471@gmail.com>
1003
+ Alex Malins <github@alexmalins.com>
1004
+ Lorenzo Contento <lorenzo.contento@gmail.com>
1005
+ Naveen Sai <naveensaisreenivas@gmail.com>
1006
+ Shital Mule <shitalmule04@gmail.com>
1007
+ Amanda Dsouza <meezamanda@yahoo.com>
1008
+ Nijso Beishuizen <nijso@koolmees.numerically-related.com>
1009
+ Harry Zheng <harry@harryzheng.com>
1010
+ Felix Yan <felixonmars@archlinux.org>
1011
+ Constantin Mateescu <costica1234@me.com>
1012
+ Eva Tiwari <eva.tiwari@gmail.com>
1013
+ Aditya Kumar Sinha <adityakumar113141@gmail.com>
1014
+ Soumi Bardhan <51290447+Soumi7@users.noreply.github.com>
1015
+ Kaustubh Chaudhari <ckaustubhm06@gmail.com>
1016
+ Kristian Brünn <hello@kristianbrunn.com>
1017
+ Neel Gorasiya <mgorasiya1974@gmail.com>
1018
+ Akshat Sood <68052998+akshatsood2249@users.noreply.github.com>
1019
+ Jose M. Gomez <chemoki@gmail.com>
1020
+ Stefan Petrea <stefan@garage-coding.com>
1021
+ Praveen Sahu <povinsahu@gmail.com>
1022
+ Mark Bell <mark00bell@googlemail.com>
1023
+ AlexCQY <alex_chua@u.nus.edu>
1024
+ Fabian Froehlich <fabian@schaluck.com>
1025
+ Nikhil Gopalam <gopalamn@umich.edu>
1026
+ Kartik Sethi <kartiks31416@gmail.com>
1027
+ Muhammed Abdul Quadir Owais <quadirowais200@gmail.com>
1028
+ Harshit Yadav <harshityadav2k@gmail.com>
1029
+ Sidharth Mundhra <sidharthmundhra16@gmail.com>
1030
+ Suryam Arnav Kalra <suryamkalra35@gmail.com>
1031
+ Prince Gupta <codemastercpp@gmail.com>
1032
+ Kunal Singh <ksingh19136@gmail.com>
1033
+ Mayank Raj <mayank_1901cs35@iitp.ac.in>
1034
+ Achal Jain <2achaljain@gmail.com>
1035
+ Mario Maio <mario.maio@aruba.it>
1036
+ Aaron Stiff <69512633+AaronStiff@users.noreply.github.com>
1037
+ Wyatt Peak <wyattpeak@gmail.com>
1038
+ Bhaskar Joshi <bhaskar.joshi@research.iiit.ac.in>
1039
+ Aditya Jindal <jaditya8889@gmail.com>
1040
+ Vaibhav Bhat <vaibhav.bhat2097@gmail.com>
1041
+ Priyansh Rathi <techiepriyansh@gmail.com>
1042
+ Saket Kumar Singh <saketkumar1202@gmail.com>
1043
+ Yukai Chou <muzimuzhi@gmail.com>
1044
+ Qijia Liu <liumeo@pku.edu.cn>
1045
+ Paul Mandel <paulmandel@google.com>
1046
+ Nisarg Chaudhari <54911392+Nisarg-Chaudhari@users.noreply.github.com>
1047
+ Dominik Stańczak <stanczakdominik@gmail.com>
1048
+ Rodrigo Luger <rodluger@gmail.com>
1049
+ Marco Antônio Habitzreuter <mahabitzreuter@gmail.com>
1050
+ Ayush Bisht <bisht.ayush2001@gmail.com>
1051
+ Akshansh Bhatt <akshansh@tuta.io>
1052
+ Brandon T. Willard <brandonwillard@users.noreply.github.com>
1053
+ Thomas Aarholt <thomasaarholt@gmail.com>
1054
+ Hiren Chalodiya <hirenchalodiya99@gmail.com>
1055
+ Roland Dixon <rols121@gmail.com>
1056
+ dimasvq <dimas.vq.2020@bristol.ac.uk>
1057
+ Sagar231 <sagarfeb298@gmail.com>
1058
+ Michael Chu <michael02chu@gmail.com>
1059
+ Abby Ng <abigailjng@gmail.com>
1060
+ Angad Sandhu <55819847+angadsinghsandhu@users.noreply.github.com>
1061
+ Alexander Cockburn <alexander_cockburn12@hotmail.com>
1062
+ Yaser AlOsh <yaseralosh@outlook.com>
1063
+ Davide Sandonà <sandona.davide@gmail.com>
1064
+ Jonathan Gutow <gutow@uwosh.edu>
1065
+ Nihir Agarwal <f20180701@pilani.bits-pilani.ac.in>
1066
+ Lee Johnston <lee.johnston.100@gmail.com>
1067
+ Zach Carmichael <20629897+craymichael@users.noreply.github.com>
1068
+ Vijairam Ganesh Moorthy <vijairamg@gmail.com>
1069
+ Hanspeter Schmid <hanspeter.schmid@fhnw.ch>
1070
+ Ben Oostendorp <oostben@umich.edu>
1071
+ Nikita <nikita.student.cse19@itbhu.ac.in>
1072
+ Aman <amanmourya295@gmail.com>
1073
+ Shashank KS <shashankks0987@gmail.com>
1074
+ Aman Sharma <amansharma110603@gmail.com>
1075
+ Anup Parikh <parikhanupk@gmail.com>
1076
+ Lucy Mountain <lucymountain1@icloud.com>
1077
+ Miguel Torres Costa <miguelptcosta1995@gmail.com>
1078
+ Rikard Nordgren <rikard.nordgren@farmaci.uu.se>
1079
+ Arun sanganal <74652697+ArunSanganal@users.noreply.github.com>
1080
+ Kamlesh Joshi <72374645+kamleshjoshi8102@users.noreply.github.com>
1081
+ Joseph Rance <56409230+Joseph-Rance@users.noreply.github.com>
1082
+ Huangduirong <huangduirong@huawei.com>
1083
+ Nils Schulte <47043622+Schnilz@users.noreply.github.com>
1084
+ Matt Bogosian <matt@bogosian.net>
1085
+ Elisha Hollander <just4now666666@gmail.com>
1086
+ Aditya Ravuri <infprobscix@gmail.com>
1087
+ Mamidi Ratna Praneeth <praneethratna@gmail.com>
1088
+ Jeffrey Ryan <jeffaryan7@gmail.com>
1089
+ Jonathan Daniel <36337649+jond01@users.noreply.github.com>
1090
+ Robin Richard <raisin@ecomail.fr>
1091
+ Gautam Menghani <gum3ng@protonmail.com>
1092
+ Remco de Boer <29308176+redeboer@users.noreply.github.com>
1093
+ Sebastian East <sebastianeast@ymail.com>
1094
+ Evani Balasubramanyam <balasubramanyam.evani@gmail.com>
1095
+ Rahil Parikh <r.parikh@somaiya.edu>
1096
+ Jason Ross <jasonross1024@gmail.com>
1097
+ Joannah Nanjekye <joannah.nanjekye@ibm.com>
1098
+ Ayush Kumar <ayushk7102@gmail.com>
1099
+ Kshitij <kshitijparwani.mat18@itbhu.ac.in>
1100
+ Daniel Hyams <dhyams@gmail.com>
1101
+ alijosephine <alijosephine@gmail.com>
1102
+ Matthias Köppe <mkoeppe@math.ucdavis.edu>
1103
+ mohajain <mohajain99@gmail.com>
1104
+ Anibal M. Medina-Mardones <ammedmar@gmail.com>
1105
+ Travis Ens <ens.travis@gmail.com>
1106
+ Evgenia Karunus <lakesare@gmail.com>
1107
+ Risiraj Dey <risirajdey@gmail.com>
1108
+ lastcodestanding <rohang71604@gmail.com>
1109
+ Andrey Lekar <andrey_lekar@adoriasoft.com>
1110
+ Abbas Mohammed <42001049+iam-abbas@users.noreply.github.com>
1111
+ Anutosh Bhat <andersonbhat491@gmail.com>
1112
+ Steve Kieffer <sk@skieffer.info>
1113
+ Paul Spiering <paul@spiering.org>
1114
+ Pieter Gijsbers <p.gijsbers@tue.nl>
1115
+ Wang Ran (汪然) <wangr@smail.nju.edu.cn>
1116
+ naelsondouglas <naelson17@gmail.com>
1117
+ Aman Thakur <thakuraman22july@gmail.com>
1118
+ S. Hanko <suzy.hanko@gmail.com>
1119
+ Dennis Sweeney <sweeney.427@osu.edu>
1120
+ Gurpartap Singh <dhaliwal.gurpartap@gmail.com>
1121
+ Hampus Malmberg <hampus.malmberg88@gmail.com>
1122
+ scimax <max.kellermeier@hotmail.de>
1123
+ Nikhil Date <nikhil.s.date@gmail.com>
1124
+ Kuldeep Borkar Jr <kuldeepborkarjr765@gmail.com>
1125
+ AkuBrain <76952313+Franck2111@users.noreply.github.com>
1126
+ Leo Battle <leowbattle@gmail.com>
1127
+ Advait Pote <apote2050@gmail.com>
1128
+ Anurag Bhat <bhat.1@iitj.ac.in>
1129
+ Jeremy Monat <jemonat@calalum.org>
1130
+ Diane Tchuindjo <dtchuindjo@gmail.com>
1131
+ Tom Fryers <61272761+TomFryers@users.noreply.github.com>
1132
+ Zouhair <zouhair.mahboubi@gmail.com>
1133
+ zzj <29055749+zjzh@users.noreply.github.com>
1134
+ shubhayu09 <guptashubhayu601@gmail.com>
1135
+ Siddhant Jain <siddhantashoknagar@gmail.com>
1136
+ Tirthankar Mazumder <63574588+wermos@users.noreply.github.com>
1137
+ Sumit Kumar <mr.sumitkrr@gmail.com>
1138
+ Shivam Sagar <technoshivam12@gmail.com>
1139
+ Gaurav Jain <gjain369@gmail.com>
1140
+ Andrii Oriekhov <andriyorehov@gmail.com>
1141
+ Luis Talavera <luisfertalavera15@gmail.com>
1142
+ Arie Bovenberg <a.c.bovenberg@gmail.com>
1143
+ Carson McManus <carson.mcmanus1@gmail.com>
1144
+ Jack Schmidt <1107865+jackschmidt@users.noreply.github.com>
1145
+ Riley Britten <nrb1324@hotmail.com>
1146
+ Georges Khaznadar <georgesk@debian.org>
1147
+ Donald Wilson <donwilson1029@gmail.com>
1148
+ Timo Stienstra <timostienstra00@gmail.com>
1149
+ dispasha <dispasha@users.noreply.github.com>
1150
+ Saksham Alok <sakshamalok13@gmail.com>
1151
+ Varenyam Bhardwaj <varenyambhardwaj123@gmail.com>
1152
+ oittaa <8972248+oittaa@users.noreply.github.com>
1153
+ Omkaar <79257339+Pysics@users.noreply.github.com>
1154
+ Islem BOUZENIA <fi_bouzenia@esi.dz>
1155
+ extraymond <extraymond@gmail.com>
1156
+ Alexander Behrens <alex.git@gmx.net>
1157
+ user202729 <25191436+user202729@users.noreply.github.com>
1158
+ Pieter Eendebak <pieter.eendebak@gmail.com>
1159
+ Zaz Brown <zazbrown@zazbrown.com>
1160
+ ritikBhandari <ritikbhandari68@gmail.com>
1161
+ viocha <66580331+viocha@users.noreply.github.com>
1162
+ Arthur Ryman <arthur.ryman@gmail.com>
1163
+ Xiang Wu <hsiangwu@fb.com>
1164
+ tttc3 <T.Coxon2@lboro.ac.uk>
1165
+ Seth Poulsen <poulsenseth@yahoo.com>
1166
+ cocolato <haiizhu@outlook.com>
1167
+ Anton Golovanov <agolovanov256@gmail.com>
1168
+ Gareth Ma <grhkm21@gmail.com>
1169
+ Clément M.T. Robert <cr52@protonmail.com>
1170
+ Glenn Horton-Smith <glenn.hortonsmith@gmail.com>
1171
+ Karan <grgkaran03@gmail.com>
1172
+ Stefan Behnle <84378403+behnle@users.noreply.github.com>
1173
+ Shreyash Mishra <72146041+Shreyash-cyber@users.noreply.github.com>
1174
+ Arthur Milchior <arthur@milchior.fr>
1175
+ NotWearingPants <26556598+NotWearingPants@users.noreply.github.com>
1176
+ Ishan Pandhare <ishan9096137017@gmail.com>
1177
+ Carlos García Montoro <TrilceAC@gmail.com>
1178
+ Parcly Taxel <reddeloostw@gmail.com>
1179
+ Saicharan <saicharanhahaha@gmail.com>
1180
+ Kunal Sheth <kunal@kunalsheth.info>
1181
+ Biswadeep Purkayastha <98874428+metabiswadeep@users.noreply.github.com>
1182
+ Jyn Spring 琴春 <me@vx.st>
1183
+ Phil LeMaitre <phil_lemaitre@live.ca>
1184
+ Chris Kerr <chris.kerr@mykolab.ch>
1185
+ José Senart <jose.senart@gmail.com>
1186
+ Uwe L. Korn <uwelk@xhochy.com>
1187
+ ForeverHaibara <69423537+ForeverHaibara@users.noreply.github.com>
1188
+ Yves Tumushimire <yvestumushimire@gmail.com>
1189
+ wookie184 <wookie1840@gmail.com>
1190
+ Costor <pcs2009@web.de>
1191
+ Klaus Rettinghaus <klaus.rettinghaus@enote.com>
1192
+ Sam Brockie <sambrockie@icloud.com>
1193
+ Abhishek Patidar <1e9abhi1e10@gmail.com>
1194
+ Eric Demer <demer@mailbox.org>
1195
+ Pontus von Brömssen <pontus.vonbromssen+github@gmail.com>
1196
+ Victor Immanuel <chrollolucilfer1402@gmail.com>
1197
+ Evandro Bernardes <evbernardes@gmail.com>
1198
+ Michele Ceccacci <michelececcacci1@gmail.com>
1199
+ Ayush Aryan <ayush.aryan71@gmail.com>
1200
+ Kishore Gopalakrishnan <kishore96@gmail.com>
1201
+ Jan-Philipp Hoffmann <sonntagsgesicht@icloud.com>
1202
+ Daiki Takahashi <haru.td@gmail.com>
1203
+ Sayan Mitra <ee18b156@smail.iitm.ac.in>
1204
+ Aman Kumar Shukla <theprofessionalaman@gmail.com>
1205
+ Zoufiné Lauer-Baré <raszoufine@gmail.com>
1206
+ Charles Harris <erdos4d@gmail.com>
1207
+ Tejaswini Sanapathi <sastejaswini2002@gmail.com>
1208
+ Devansh <be19b002@smail.iitm.ac.in>
1209
+ Aaron Gokaslan <aaronGokaslan@gmail.com>
1210
+ Daan Koning (he/him) <daanolivierkoning@gmail.com>
1211
+ Steven Burns <royalstream@hotmail.com>
1212
+ Jay Patankar <patankarjays@gmail.com>
1213
+ Vivek Soni <sonisheela1977@gmail.com>
1214
+ Le Cong Minh Hieu <hieu.lecongminh@gmail.com>
1215
+ Sam Ritchie <sam@mentat.org>
1216
+ Maciej Skórski <maciej.skorski@gmail.com>
1217
+ Tilo Reneau-Cardoso <tiloreneau@gmail.com>
1218
+ Laurence Warne <laurencewarne@gmail.com>
1219
+ Lukas Molleman <Lukas.Molleman@gmail.com>
1220
+ Konstantinos Riganas <kostasriganas24@gmail.com>
1221
+ Grace Su <grace.duansu@gmail.com>
1222
+ Pedro Rosa <pedro_sxbr@usp.br>
1223
+ Abhinav Cillanki <abhinavcillanki@kgpian.iitkgp.ac.in>
1224
+ Baiyuan Qiu <1061688677@qq.com>
1225
+ Liwei Cai <cai.lw123@gmail.com>
1226
+ Daniel Weindl <daniel.weindl@helmholtz-muenchen.de>
1227
+ Isidora Araya <iarayaday@gmail.com>
1228
+ Seb Tiburzio <sebtiburzio@gmail.com>
1229
+ Victory Omole <vtomole2@gmail.com>
1230
+ Abhishek Chaudhary <ac5003@columbia.edu>
1231
+ Alexander Zhura <nice.zhura@list.ru>
1232
+ Shuai Zhou <shuaivzhou@berkeley.edu>
1233
+ Martin Manns <mmanns@gmx.net>
1234
+ John Möller <john.moller@outlook.com>
1235
+ zzc <1378113190@qq.com>
1236
+ Pablo Galindo Salgado <pablogsal@gmail.com>
1237
+ Johannes Kasimir <johannes.kasimir@math.lu.se>
1238
+ Theodore Dias <theodore.dias@hotmail.co.uk>
1239
+ Kaustubh <90597818+kaustubh-765@users.noreply.github.com>
1240
+ Idan Pazi <idan.kp@gmail.com>
1241
+ Bobby Palmer <bobbyp@umich.edu>
1242
+ Saikat Das <saikatdchhe@gmail.com>
1243
+ Suman mondal <smondal.qwerty@gmail.com>
1244
+ Taylan Sahin <info@taylansahin.net>
1245
+ Fabio Luporini <fabio@devitocodes.com>
1246
+ Oriel Malihi <orielmalihi1@gmail.com>
1247
+ Geetika Vadali <geetika.vadali4@gmail.com>
1248
+ Matthias Rettl <matthias.rettl@stud.unileoben.ac.at>
1249
+ Mikhail Remnev <maremnev@gmail.com>
1250
+ philwillnyc <56197213+philwillnyc@users.noreply.github.com>
1251
+ Raphael Lehner <raphael.lehner@gmail.com>
1252
+ Harry Mountain <harrymountain1@icloud.com>
1253
+ Bhavik Sachdev <b.sachdev1904@gmail.com>
1254
+ 袁野 (Yuan Ye) <yuanyelele@tutanota.com>
1255
+ fazledyn-or <ataf@openrefactory.com>
1256
+ mohammedouahman <simofun85@gmail.com>
1257
+ K. Kraus <laqueray@googlemail.com>
1258
+ Zac Hatfield-Dodds <zac.hatfield.dodds@gmail.com>
1259
+ platypus <platypus.computerchip@gmail.com>
1260
+ codecruisader <nnisarg55@gmail.com>
1261
+ James Whitehead <whiteheadj@gmail.com>
1262
+ atharvParlikar <atharvparlikar@gmail.com>
1263
+ Ivan Petukhov <satels@gmail.com>
1264
+ Augusto Borges <borges.augustoar@gmail.com>
1265
+ Han Wei Ang <ang.h.w@u.nus.edu>
1266
+ Congxu Yang <u7189828@anu.edu.au>
1267
+ Saicharan <62512681+saicharan2804@users.noreply.github.com>
1268
+ Arnab Nandi <arnabnandi2002@gmail.com>
1269
+ Harrison Oates <48871176+HarrisonOates@users.noreply.github.com>
1270
+ Corey Cerovsek <corey@cerovsek.com>
1271
+ Harsh Kasat <hkasat@waymore.io>
1272
+ omahs <73983677+omahs@users.noreply.github.com>
1273
+ Pascal Gitz <pascal.gitz@hotmail.ch>
1274
+ Ravindu-Hirimuthugoda <ravindu.18@cse.mrt.ac.lk>
1275
+ Sophia Pustova <tripplezzed@gmail.com>
1276
+ George Pittock <gpittock4@gmail.com>
1277
+ Warren Jacinto <warrenjacinto@gmail.com>
1278
+ Sachin Singh <sachinishu02@gmail.com>
1279
+ Zedmat <104870914+harshkasat@users.noreply.github.com>
1280
+ Soumendra Ganguly <soumendraganguly@gmail.com>
1281
+ Samith Karunathilake <55777141+samithkavishke@users.noreply.github.com>
1282
+ Viraj Vekaria <virajv5593@gmail.com>
1283
+ Shishir Kushwaha <kushwahashishir1112@gmail.com>
1284
+ Ankit Kumar Singh <ankitdiswar10@gmail.com>
1285
+ Abhishek Kumar <abhishek.nitdelhi@gmail.com>
1286
+ Mohak Malviya <mohakmalviya2000@gmail.com>
1287
+ Matthias Liesenfeld <116307294+maliesen@users.noreply.github.com>
1288
+ dodo <palumbododo@gmail.com>
1289
+ Mohamed Rezk <mohrizq895@gmail.com>
1290
+ Tommaso Vaccari <05-gesto-follemente@icloud.com>
1291
+ Alexis Schotte <alexis.schotte@gmail.com>
1292
+ Lauren Yim <31467609+cherryblossom000@users.noreply.github.com>
1293
+ Prey Patel <patel.prey@iitgn.ac.in>
1294
+ Riccardo Di Girolamo <riccardodigirolamo01@gmail.com>
1295
+ Abhishek kumar <kumar325571@gmail.com>
1296
+ Sam Lubelsky <sammy56lt@gmail.com>
1297
+ Henrique Soares <henrique.c.soares@tecnico.ulisboa.pt>
1298
+ Vladimir Sereda <voffch@gmail.com>
1299
+ Hwayeon Kang <hwayeonniii@gmail.com>
1300
+ Raj Sapale <raj4sapale4@gmail.com>
1301
+ Gerald Teschl <gerald.teschl@univie.ac.at>
1302
+ Richard Samuel <98638849+samuelard7@users.noreply.github.com>
1303
+ HeeJae Chang <hechang@microsoft.com>
1304
+ Nick Harder <nharder@umich.edu>
1305
+ Ethan DeGuire <ethandeguire@gmail.com>
1306
+ Lorenz Winkler <lorenz.winkler@tuwien.ac.at>
1307
+ Richard Rodenbusch <rrodenbusch@gmail.com>
1308
+ Zhenxu Zhu <xzdlj@outlook.com>
1309
+ Mark van Gelder <m.j.vangelder@student.tudelft.nl>
1310
+ Mark van Gelder <mvgmvgmvg@live.com>
1311
+ Ishan Pandhare <91841626+Ishanned@users.noreply.github.com>
1312
+ James A. Preiss <jamesalanpreiss@gmail.com>
1313
+ Emile Fourcini <emile.fourcin1@gmail.com>
1314
+ Alberto Jiménez Ruiz <Alberto.Jimenez@uclm.es>
1315
+ João Bravo <joaocgbravo@tecnico.ulisboa.pt>
1316
+ Dean Price <dean1357price1357@gmail.com>
1317
+ Edward Z. Yang <ezyang@mit.edu>
1318
+ James Titus <titusjames299@gmail.com>
1319
+ Zhuoyuan Li <zy.li@stu.pku.edu.cn>
1320
+ Hugo Kerstens <hugo@kerstens.me>
1321
+ Jan Jancar <johny@neuromancer.sk>
1322
+ Andrew Mosson <amosson@yahoo.com>
1323
+ Marek Madejski <marekmadejski@yandex.com>
1324
+ Gonzalo Tornaría <tornaria@cmat.edu.uy>
1325
+ Peter Stahlecker <peter.stahlecker@gmail.com>
1326
+ Jean-François B <2589111+jfbu@users.noreply.github.com>
1327
+ Zexuan Zhou (Bruce) <zzx498636727@gmail.com>
1328
+ George Frolov <gosha@fro.lv>
1329
+ Corbet Elkins <corbet286@gmail.com>
1330
+ Håkon Kvernmoen <haakon.kvernmoen@gmail.com>
1331
+ Muhammad Maaz <mmaaz6004@gmail.com>
1332
+ Shishir Kushwaha <138311586+shishir-11@users.noreply.github.com>
1333
+ Matt Wang <mattwang44@gmail.com>
1334
+ bharatAmeria <21001019007@jcboseust.ac.in>
1335
+ Amir Ebrahimi <github@aebrahimi.com>
1336
+ Steven Esquea <steven.esquea@irreverente.net>
1337
+ Rishabh Kamboj <111004091+VectorNd@users.noreply.github.com>
1338
+ Aasim Ali <aasim250205@gmail.com>
1339
+ Ivan A. Melnikov <iv@altlinux.org>
1340
+ Borek Saheli <boreksaheli@gmail.com>
1341
+ Guido Roncarolo <guido.roncarolo@gmail.com>
1342
+ Quek Zi Yao <ziyaoqzy2001@gmail.com>
1343
+ Roelof Rietbroek <r.rietbroek@utwente.nl>
1344
+ MostafaGalal1 <mostafag649.mg@gmail.com>
1345
+ Au Huishan <huishan_au@outlook.com>
1346
+ Kris Katterjohn <katterjohn@gmail.com>
1347
+ Shiyao Guo <mivikq@gmail.com>
1348
+ Rushabh Mehta <mehtarushabh2005@gmail.com>
1349
+ Temiloluwa Yusuf ytemiloluwa@gmail.com ytemiloluwa <ytemiloluwa@gmail.com>
1350
+ Davi Laerte <davilae011@gmail.com>
1351
+ Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
1352
+ Harshit Gupta <harshithigh2001@gmail.com>
1353
+ Praveen Perumal <ppraveen98841@gmail.com>
1354
+ Kevin McWhirter <klmcw@yahoo.com>
1355
+ Prayag V <v.prayag2005@gmail.com>
1356
+ Lucas Kletzander <lucas.kletzander@gmail.com>
1357
+ Pratyksh Gupta <pratykshgupta9999@gmail.com>
1358
+ Leonardo Mangani <leomangani4@gmail.com>
1359
+ Karan Anand <anandkarancompsci@gmail.com>
1360
+ Gagan Mishra <simonsimple305@gmail.com>
1361
+ Krishnav Bajoria <bajoriakrishnav@gmail.com>
1362
+ Matt Ord <matthew.ord1@gmail.com>
1363
+ Jatin Bhardwaj <bhardwajjatin093@gmail.com>
1364
+ Prashant Tandon <tandonprashant101@gmail.com>
1365
+ Paramjit Singh <paramjit1071@gmail.com>
1366
+ João Rodrigues <abcjoao@hotmail.com>
1367
+ Alejandro García Prada <114813960+AlexGarciaPrada@users.noreply.github.com>
1368
+ Matthew Treinish <mtreinish@kortar.org>
1369
+ Clayton Rabideau <claytonrabideau@gmail.com>
1370
+ Victoria Koval <bictoriakoval16@gmail.com>
1371
+ Voaides Negustor Robert <134785947+voaidesr@users.noreply.github.com>
1372
+ Ovsk Mendov <bbb23exposed@gmail.com>
1373
+ David Brooks <dave@bcs.co.nz>
1374
+ Nicholas Laustrup <124007393+nicklaustrup@users.noreply.github.com>
1375
+ Harikrishna Srinivasan <harikrishnasri3@gmail.com>
1376
+ Mathis Cros <mathis.cros@telecom-paris.fr>
1377
+ Arnav Mummineni <45217840+RCoder01@users.noreply.github.com>
1378
+ Thangaraju Sibiraj <85477603+t-sibiraj@users.noreply.github.com>
1379
+ KJaybhaye <krushnajaybhaye01@gmail.com>
outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/LICENSE ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2006-2023 SymPy Development Team
2
+
3
+ All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ a. Redistributions of source code must retain the above copyright notice,
9
+ this list of conditions and the following disclaimer.
10
+ b. Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in the
12
+ documentation and/or other materials provided with the distribution.
13
+ c. Neither the name of SymPy nor the names of its contributors
14
+ may be used to endorse or promote products derived from this software
15
+ without specific prior written permission.
16
+
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
22
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28
+ DAMAGE.
29
+
30
+ --------------------------------------------------------------------------------
31
+
32
+ Patches that were taken from the Diofant project (https://github.com/diofant/diofant)
33
+ are licensed as:
34
+
35
+ Copyright (c) 2006-2018 SymPy Development Team,
36
+ 2013-2023 Sergey B Kirpichev
37
+
38
+ All rights reserved.
39
+
40
+ Redistribution and use in source and binary forms, with or without
41
+ modification, are permitted provided that the following conditions are met:
42
+
43
+ a. Redistributions of source code must retain the above copyright notice,
44
+ this list of conditions and the following disclaimer.
45
+ b. Redistributions in binary form must reproduce the above copyright
46
+ notice, this list of conditions and the following disclaimer in the
47
+ documentation and/or other materials provided with the distribution.
48
+ c. Neither the name of Diofant or SymPy nor the names of its contributors
49
+ may be used to endorse or promote products derived from this software
50
+ without specific prior written permission.
51
+
52
+
53
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
54
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
57
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
59
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
60
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
63
+ DAMAGE.
64
+
65
+ --------------------------------------------------------------------------------
66
+
67
+ Submodules taken from the multipledispatch project (https://github.com/mrocklin/multipledispatch)
68
+ are licensed as:
69
+
70
+ Copyright (c) 2014 Matthew Rocklin
71
+
72
+ All rights reserved.
73
+
74
+ Redistribution and use in source and binary forms, with or without
75
+ modification, are permitted provided that the following conditions are met:
76
+
77
+ a. Redistributions of source code must retain the above copyright notice,
78
+ this list of conditions and the following disclaimer.
79
+ b. Redistributions in binary form must reproduce the above copyright
80
+ notice, this list of conditions and the following disclaimer in the
81
+ documentation and/or other materials provided with the distribution.
82
+ c. Neither the name of multipledispatch nor the names of its contributors
83
+ may be used to endorse or promote products derived from this software
84
+ without specific prior written permission.
85
+
86
+
87
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
88
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
89
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
90
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
91
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
92
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
93
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
94
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
95
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
96
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
97
+ DAMAGE.
98
+
99
+ --------------------------------------------------------------------------------
100
+
101
+ The files under the directory sympy/parsing/autolev/tests/pydy-example-repo
102
+ are directly copied from PyDy project and are licensed as:
103
+
104
+ Copyright (c) 2009-2023, PyDy Authors
105
+ All rights reserved.
106
+
107
+ Redistribution and use in source and binary forms, with or without
108
+ modification, are permitted provided that the following conditions are met:
109
+
110
+ * Redistributions of source code must retain the above copyright
111
+ notice, this list of conditions and the following disclaimer.
112
+ * Redistributions in binary form must reproduce the above copyright
113
+ notice, this list of conditions and the following disclaimer in the
114
+ documentation and/or other materials provided with the distribution.
115
+ * Neither the name of this project nor the names of its contributors may be
116
+ used to endorse or promote products derived from this software without
117
+ specific prior written permission.
118
+
119
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
120
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
121
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
122
+ DISCLAIMED. IN NO EVENT SHALL PYDY AUTHORS BE LIABLE FOR ANY DIRECT,
123
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
124
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
125
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
126
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
127
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
128
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
129
+
130
+ --------------------------------------------------------------------------------
131
+
132
+ The files under the directory sympy/parsing/latex
133
+ are directly copied from latex2sympy project and are licensed as:
134
+
135
+ Copyright 2016, latex2sympy
136
+
137
+ Permission is hereby granted, free of charge, to any person obtaining a copy
138
+ of this software and associated documentation files (the "Software"), to deal
139
+ in the Software without restriction, including without limitation the rights
140
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
141
+ copies of the Software, and to permit persons to whom the Software is
142
+ furnished to do so, subject to the following conditions:
143
+
144
+ The above copyright notice and this permission notice shall be included in all
145
+ copies or substantial portions of the Software.
146
+
147
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
148
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
149
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
150
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
151
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
152
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
153
+ SOFTWARE.
outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/METADATA ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.2
2
+ Name: sympy
3
+ Version: 1.14.0+computecanada
4
+ Summary: Computer algebra system (CAS) in Python
5
+ Description-Content-Type: text/markdown
6
+ Keywords: Math CAS
7
+ Classifier: License :: OSI Approved :: BSD License
8
+ Classifier: Operating System :: OS Independent
9
+ Classifier: Programming Language :: Python
10
+ Classifier: Topic :: Scientific/Engineering
11
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
12
+ Classifier: Topic :: Scientific/Engineering :: Physics
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3 :: Only
20
+ Classifier: Programming Language :: Python :: Implementation :: CPython
21
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
22
+ Author: SymPy development team
23
+ Author-email: sympy@googlegroups.com
24
+ Home-page: https://sympy.org
25
+ Project-URL: Source, https://github.com/sympy/sympy
26
+ Requires-Python: >=3.9
27
+ Requires-Dist: mpmath<1.4,>=1.1.0
28
+ Requires-Dist: pytest>=7.1.0; extra == "dev"
29
+ Requires-Dist: hypothesis>=6.70.0; extra == "dev"
30
+ Provides-Extra: dev
31
+ License-File: LICENSE
32
+ License-File: AUTHORS
33
+
34
+ BSD
outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/RECORD ADDED
The diff for this file is too large to render. See raw diff
 
outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/WHEEL ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: wheelfile 0.0.8
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/entry_points.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ [console_scripts]
2
+ isympy = isympy:main
outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/top_level.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ isympy
2
+ sympy
outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_mathematica.py ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core import (S, pi, oo, symbols, Function, Rational, Integer, Tuple,
2
+ Derivative, Eq, Ne, Le, Lt, Gt, Ge)
3
+ from sympy.integrals import Integral
4
+ from sympy.concrete import Sum
5
+ from sympy.functions import (exp, sin, cos, fresnelc, fresnels, conjugate, Max,
6
+ Min, gamma, polygamma, loggamma, erf, erfi, erfc,
7
+ erf2, expint, erfinv, erfcinv, Ei, Si, Ci, li,
8
+ Shi, Chi, uppergamma, beta, subfactorial, erf2inv,
9
+ factorial, factorial2, catalan, RisingFactorial,
10
+ FallingFactorial, harmonic, atan2, sec, acsc,
11
+ hermite, laguerre, assoc_laguerre, jacobi,
12
+ gegenbauer, chebyshevt, chebyshevu, legendre,
13
+ assoc_legendre, Li, LambertW)
14
+
15
+ from sympy.printing.mathematica import mathematica_code as mcode
16
+
17
+ x, y, z, w = symbols('x,y,z,w')
18
+ f = Function('f')
19
+
20
+
21
+ def test_Integer():
22
+ assert mcode(Integer(67)) == "67"
23
+ assert mcode(Integer(-1)) == "-1"
24
+
25
+
26
+ def test_Rational():
27
+ assert mcode(Rational(3, 7)) == "3/7"
28
+ assert mcode(Rational(18, 9)) == "2"
29
+ assert mcode(Rational(3, -7)) == "-3/7"
30
+ assert mcode(Rational(-3, -7)) == "3/7"
31
+ assert mcode(x + Rational(3, 7)) == "x + 3/7"
32
+ assert mcode(Rational(3, 7)*x) == "(3/7)*x"
33
+
34
+
35
+ def test_Relational():
36
+ assert mcode(Eq(x, y)) == "x == y"
37
+ assert mcode(Ne(x, y)) == "x != y"
38
+ assert mcode(Le(x, y)) == "x <= y"
39
+ assert mcode(Lt(x, y)) == "x < y"
40
+ assert mcode(Gt(x, y)) == "x > y"
41
+ assert mcode(Ge(x, y)) == "x >= y"
42
+
43
+
44
+ def test_Function():
45
+ assert mcode(f(x, y, z)) == "f[x, y, z]"
46
+ assert mcode(sin(x) ** cos(x)) == "Sin[x]^Cos[x]"
47
+ assert mcode(sec(x) * acsc(x)) == "ArcCsc[x]*Sec[x]"
48
+ assert mcode(atan2(y, x)) == "ArcTan[x, y]"
49
+ assert mcode(conjugate(x)) == "Conjugate[x]"
50
+ assert mcode(Max(x, y, z)*Min(y, z)) == "Max[x, y, z]*Min[y, z]"
51
+ assert mcode(fresnelc(x)) == "FresnelC[x]"
52
+ assert mcode(fresnels(x)) == "FresnelS[x]"
53
+ assert mcode(gamma(x)) == "Gamma[x]"
54
+ assert mcode(uppergamma(x, y)) == "Gamma[x, y]"
55
+ assert mcode(polygamma(x, y)) == "PolyGamma[x, y]"
56
+ assert mcode(loggamma(x)) == "LogGamma[x]"
57
+ assert mcode(erf(x)) == "Erf[x]"
58
+ assert mcode(erfc(x)) == "Erfc[x]"
59
+ assert mcode(erfi(x)) == "Erfi[x]"
60
+ assert mcode(erf2(x, y)) == "Erf[x, y]"
61
+ assert mcode(expint(x, y)) == "ExpIntegralE[x, y]"
62
+ assert mcode(erfcinv(x)) == "InverseErfc[x]"
63
+ assert mcode(erfinv(x)) == "InverseErf[x]"
64
+ assert mcode(erf2inv(x, y)) == "InverseErf[x, y]"
65
+ assert mcode(Ei(x)) == "ExpIntegralEi[x]"
66
+ assert mcode(Ci(x)) == "CosIntegral[x]"
67
+ assert mcode(li(x)) == "LogIntegral[x]"
68
+ assert mcode(Si(x)) == "SinIntegral[x]"
69
+ assert mcode(Shi(x)) == "SinhIntegral[x]"
70
+ assert mcode(Chi(x)) == "CoshIntegral[x]"
71
+ assert mcode(beta(x, y)) == "Beta[x, y]"
72
+ assert mcode(factorial(x)) == "Factorial[x]"
73
+ assert mcode(factorial2(x)) == "Factorial2[x]"
74
+ assert mcode(subfactorial(x)) == "Subfactorial[x]"
75
+ assert mcode(FallingFactorial(x, y)) == "FactorialPower[x, y]"
76
+ assert mcode(RisingFactorial(x, y)) == "Pochhammer[x, y]"
77
+ assert mcode(catalan(x)) == "CatalanNumber[x]"
78
+ assert mcode(harmonic(x)) == "HarmonicNumber[x]"
79
+ assert mcode(harmonic(x, y)) == "HarmonicNumber[x, y]"
80
+ assert mcode(Li(x)) == "LogIntegral[x] - LogIntegral[2]"
81
+ assert mcode(LambertW(x)) == "ProductLog[x]"
82
+ assert mcode(LambertW(x, -1)) == "ProductLog[-1, x]"
83
+ assert mcode(LambertW(x, y)) == "ProductLog[y, x]"
84
+
85
+
86
+ def test_special_polynomials():
87
+ assert mcode(hermite(x, y)) == "HermiteH[x, y]"
88
+ assert mcode(laguerre(x, y)) == "LaguerreL[x, y]"
89
+ assert mcode(assoc_laguerre(x, y, z)) == "LaguerreL[x, y, z]"
90
+ assert mcode(jacobi(x, y, z, w)) == "JacobiP[x, y, z, w]"
91
+ assert mcode(gegenbauer(x, y, z)) == "GegenbauerC[x, y, z]"
92
+ assert mcode(chebyshevt(x, y)) == "ChebyshevT[x, y]"
93
+ assert mcode(chebyshevu(x, y)) == "ChebyshevU[x, y]"
94
+ assert mcode(legendre(x, y)) == "LegendreP[x, y]"
95
+ assert mcode(assoc_legendre(x, y, z)) == "LegendreP[x, y, z]"
96
+
97
+
98
+ def test_Pow():
99
+ assert mcode(x**3) == "x^3"
100
+ assert mcode(x**(y**3)) == "x^(y^3)"
101
+ assert mcode(1/(f(x)*3.5)**(x - y**x)/(x**2 + y)) == \
102
+ "(3.5*f[x])^(-x + y^x)/(x^2 + y)"
103
+ assert mcode(x**-1.0) == 'x^(-1.0)'
104
+ assert mcode(x**Rational(2, 3)) == 'x^(2/3)'
105
+
106
+
107
+ def test_Mul():
108
+ A, B, C, D = symbols('A B C D', commutative=False)
109
+ assert mcode(x*y*z) == "x*y*z"
110
+ assert mcode(x*y*A) == "x*y*A"
111
+ assert mcode(x*y*A*B) == "x*y*A**B"
112
+ assert mcode(x*y*A*B*C) == "x*y*A**B**C"
113
+ assert mcode(x*A*B*(C + D)*A*y) == "x*y*A**B**(C + D)**A"
114
+
115
+
116
+ def test_constants():
117
+ assert mcode(S.Zero) == "0"
118
+ assert mcode(S.One) == "1"
119
+ assert mcode(S.NegativeOne) == "-1"
120
+ assert mcode(S.Half) == "1/2"
121
+ assert mcode(S.ImaginaryUnit) == "I"
122
+
123
+ assert mcode(oo) == "Infinity"
124
+ assert mcode(S.NegativeInfinity) == "-Infinity"
125
+ assert mcode(S.ComplexInfinity) == "ComplexInfinity"
126
+ assert mcode(S.NaN) == "Indeterminate"
127
+
128
+ assert mcode(S.Exp1) == "E"
129
+ assert mcode(pi) == "Pi"
130
+ assert mcode(S.GoldenRatio) == "GoldenRatio"
131
+ assert mcode(S.TribonacciConstant) == \
132
+ "(1/3 + (1/3)*(19 - 3*33^(1/2))^(1/3) + " \
133
+ "(1/3)*(3*33^(1/2) + 19)^(1/3))"
134
+ assert mcode(2*S.TribonacciConstant) == \
135
+ "2*(1/3 + (1/3)*(19 - 3*33^(1/2))^(1/3) + " \
136
+ "(1/3)*(3*33^(1/2) + 19)^(1/3))"
137
+ assert mcode(S.EulerGamma) == "EulerGamma"
138
+ assert mcode(S.Catalan) == "Catalan"
139
+
140
+
141
+ def test_containers():
142
+ assert mcode([1, 2, 3, [4, 5, [6, 7]], 8, [9, 10], 11]) == \
143
+ "{1, 2, 3, {4, 5, {6, 7}}, 8, {9, 10}, 11}"
144
+ assert mcode((1, 2, (3, 4))) == "{1, 2, {3, 4}}"
145
+ assert mcode([1]) == "{1}"
146
+ assert mcode((1,)) == "{1}"
147
+ assert mcode(Tuple(*[1, 2, 3])) == "{1, 2, 3}"
148
+
149
+
150
+ def test_matrices():
151
+ from sympy.matrices import MutableDenseMatrix, MutableSparseMatrix, \
152
+ ImmutableDenseMatrix, ImmutableSparseMatrix
153
+ A = MutableDenseMatrix(
154
+ [[1, -1, 0, 0],
155
+ [0, 1, -1, 0],
156
+ [0, 0, 1, -1],
157
+ [0, 0, 0, 1]]
158
+ )
159
+ B = MutableSparseMatrix(A)
160
+ C = ImmutableDenseMatrix(A)
161
+ D = ImmutableSparseMatrix(A)
162
+
163
+ assert mcode(C) == mcode(A) == \
164
+ "{{1, -1, 0, 0}, " \
165
+ "{0, 1, -1, 0}, " \
166
+ "{0, 0, 1, -1}, " \
167
+ "{0, 0, 0, 1}}"
168
+
169
+ assert mcode(D) == mcode(B) == \
170
+ "SparseArray[{" \
171
+ "{1, 1} -> 1, {1, 2} -> -1, {2, 2} -> 1, {2, 3} -> -1, " \
172
+ "{3, 3} -> 1, {3, 4} -> -1, {4, 4} -> 1" \
173
+ "}, {4, 4}]"
174
+
175
+ # Trivial cases of matrices
176
+ assert mcode(MutableDenseMatrix(0, 0, [])) == '{}'
177
+ assert mcode(MutableSparseMatrix(0, 0, [])) == 'SparseArray[{}, {0, 0}]'
178
+ assert mcode(MutableDenseMatrix(0, 3, [])) == '{}'
179
+ assert mcode(MutableSparseMatrix(0, 3, [])) == 'SparseArray[{}, {0, 3}]'
180
+ assert mcode(MutableDenseMatrix(3, 0, [])) == '{{}, {}, {}}'
181
+ assert mcode(MutableSparseMatrix(3, 0, [])) == 'SparseArray[{}, {3, 0}]'
182
+
183
+ def test_NDArray():
184
+ from sympy.tensor.array import (
185
+ MutableDenseNDimArray, ImmutableDenseNDimArray,
186
+ MutableSparseNDimArray, ImmutableSparseNDimArray)
187
+
188
+ example = MutableDenseNDimArray(
189
+ [[[1, 2, 3, 4],
190
+ [5, 6, 7, 8],
191
+ [9, 10, 11, 12]],
192
+ [[13, 14, 15, 16],
193
+ [17, 18, 19, 20],
194
+ [21, 22, 23, 24]]]
195
+ )
196
+
197
+ assert mcode(example) == \
198
+ "{{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}, " \
199
+ "{{13, 14, 15, 16}, {17, 18, 19, 20}, {21, 22, 23, 24}}}"
200
+
201
+ example = ImmutableDenseNDimArray(example)
202
+
203
+ assert mcode(example) == \
204
+ "{{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}, " \
205
+ "{{13, 14, 15, 16}, {17, 18, 19, 20}, {21, 22, 23, 24}}}"
206
+
207
+ example = MutableSparseNDimArray(example)
208
+
209
+ assert mcode(example) == \
210
+ "SparseArray[{" \
211
+ "{1, 1, 1} -> 1, {1, 1, 2} -> 2, {1, 1, 3} -> 3, " \
212
+ "{1, 1, 4} -> 4, {1, 2, 1} -> 5, {1, 2, 2} -> 6, " \
213
+ "{1, 2, 3} -> 7, {1, 2, 4} -> 8, {1, 3, 1} -> 9, " \
214
+ "{1, 3, 2} -> 10, {1, 3, 3} -> 11, {1, 3, 4} -> 12, " \
215
+ "{2, 1, 1} -> 13, {2, 1, 2} -> 14, {2, 1, 3} -> 15, " \
216
+ "{2, 1, 4} -> 16, {2, 2, 1} -> 17, {2, 2, 2} -> 18, " \
217
+ "{2, 2, 3} -> 19, {2, 2, 4} -> 20, {2, 3, 1} -> 21, " \
218
+ "{2, 3, 2} -> 22, {2, 3, 3} -> 23, {2, 3, 4} -> 24" \
219
+ "}, {2, 3, 4}]"
220
+
221
+ example = ImmutableSparseNDimArray(example)
222
+
223
+ assert mcode(example) == \
224
+ "SparseArray[{" \
225
+ "{1, 1, 1} -> 1, {1, 1, 2} -> 2, {1, 1, 3} -> 3, " \
226
+ "{1, 1, 4} -> 4, {1, 2, 1} -> 5, {1, 2, 2} -> 6, " \
227
+ "{1, 2, 3} -> 7, {1, 2, 4} -> 8, {1, 3, 1} -> 9, " \
228
+ "{1, 3, 2} -> 10, {1, 3, 3} -> 11, {1, 3, 4} -> 12, " \
229
+ "{2, 1, 1} -> 13, {2, 1, 2} -> 14, {2, 1, 3} -> 15, " \
230
+ "{2, 1, 4} -> 16, {2, 2, 1} -> 17, {2, 2, 2} -> 18, " \
231
+ "{2, 2, 3} -> 19, {2, 2, 4} -> 20, {2, 3, 1} -> 21, " \
232
+ "{2, 3, 2} -> 22, {2, 3, 3} -> 23, {2, 3, 4} -> 24" \
233
+ "}, {2, 3, 4}]"
234
+
235
+
236
+ def test_Integral():
237
+ assert mcode(Integral(sin(sin(x)), x)) == "Hold[Integrate[Sin[Sin[x]], x]]"
238
+ assert mcode(Integral(exp(-x**2 - y**2),
239
+ (x, -oo, oo),
240
+ (y, -oo, oo))) == \
241
+ "Hold[Integrate[Exp[-x^2 - y^2], {x, -Infinity, Infinity}, " \
242
+ "{y, -Infinity, Infinity}]]"
243
+
244
+
245
+ def test_Derivative():
246
+ assert mcode(Derivative(sin(x), x)) == "Hold[D[Sin[x], x]]"
247
+ assert mcode(Derivative(x, x)) == "Hold[D[x, x]]"
248
+ assert mcode(Derivative(sin(x)*y**4, x, 2)) == "Hold[D[y^4*Sin[x], {x, 2}]]"
249
+ assert mcode(Derivative(sin(x)*y**4, x, y, x)) == "Hold[D[y^4*Sin[x], x, y, x]]"
250
+ assert mcode(Derivative(sin(x)*y**4, x, y, 3, x)) == "Hold[D[y^4*Sin[x], x, {y, 3}, x]]"
251
+
252
+
253
+ def test_Sum():
254
+ assert mcode(Sum(sin(x), (x, 0, 10))) == "Hold[Sum[Sin[x], {x, 0, 10}]]"
255
+ assert mcode(Sum(exp(-x**2 - y**2),
256
+ (x, -oo, oo),
257
+ (y, -oo, oo))) == \
258
+ "Hold[Sum[Exp[-x^2 - y^2], {x, -Infinity, Infinity}, " \
259
+ "{y, -Infinity, Infinity}]]"
260
+
261
+
262
+ def test_comment():
263
+ from sympy.printing.mathematica import MCodePrinter
264
+ assert MCodePrinter()._get_comment("Hello World") == \
265
+ "(* Hello World *)"
266
+
267
+
268
+ def test_userfuncs():
269
+ # Dictionary mutation test
270
+ some_function = symbols("some_function", cls=Function)
271
+ my_user_functions = {"some_function": "SomeFunction"}
272
+ assert mcode(
273
+ some_function(z),
274
+ user_functions=my_user_functions) == \
275
+ 'SomeFunction[z]'
276
+ assert mcode(
277
+ some_function(z),
278
+ user_functions=my_user_functions) == \
279
+ 'SomeFunction[z]'
280
+
281
+ # List argument test
282
+ my_user_functions = \
283
+ {"some_function": [(lambda x: True, "SomeOtherFunction")]}
284
+ assert mcode(
285
+ some_function(z),
286
+ user_functions=my_user_functions) == \
287
+ 'SomeOtherFunction[z]'
outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_mathml.py ADDED
The diff for this file is too large to render. See raw diff
 
outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_numpy.py ADDED
@@ -0,0 +1,381 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.concrete.summations import Sum
2
+ from sympy.core.mod import Mod
3
+ from sympy.core.relational import (Equality, Unequality)
4
+ from sympy.core.symbol import Symbol
5
+ from sympy.functions.elementary.miscellaneous import sqrt
6
+ from sympy.functions.elementary.piecewise import Piecewise
7
+ from sympy.functions.special.gamma_functions import polygamma
8
+ from sympy.functions.special.error_functions import (Si, Ci)
9
+ from sympy.matrices import Matrix
10
+ from sympy.matrices.expressions.blockmatrix import BlockMatrix
11
+ from sympy.matrices.expressions.matexpr import MatrixSymbol
12
+ from sympy.matrices.expressions.special import Identity
13
+ from sympy.utilities.lambdify import lambdify
14
+ from sympy import symbols, Min, Max
15
+
16
+ from sympy.abc import x, i, j, a, b, c, d
17
+ from sympy.core import Pow
18
+ from sympy.codegen.matrix_nodes import MatrixSolve
19
+ from sympy.codegen.numpy_nodes import logaddexp, logaddexp2
20
+ from sympy.codegen.cfunctions import log1p, expm1, hypot, log10, exp2, log2, Sqrt
21
+ from sympy.tensor.array import Array
22
+ from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct, ArrayAdd, \
23
+ PermuteDims, ArrayDiagonal
24
+ from sympy.printing.numpy import NumPyPrinter, SciPyPrinter, _numpy_known_constants, \
25
+ _numpy_known_functions, _scipy_known_constants, _scipy_known_functions
26
+ from sympy.tensor.array.expressions.from_matrix_to_array import convert_matrix_to_array
27
+
28
+ from sympy.testing.pytest import skip, raises
29
+ from sympy.external import import_module
30
+
31
+ np = import_module('numpy')
32
+ jax = import_module('jax')
33
+
34
+ if np:
35
+ deafult_float_info = np.finfo(np.array([]).dtype)
36
+ NUMPY_DEFAULT_EPSILON = deafult_float_info.eps
37
+
38
+ def test_numpy_piecewise_regression():
39
+ """
40
+ NumPyPrinter needs to print Piecewise()'s choicelist as a list to avoid
41
+ breaking compatibility with numpy 1.8. This is not necessary in numpy 1.9+.
42
+ See gh-9747 and gh-9749 for details.
43
+ """
44
+ printer = NumPyPrinter()
45
+ p = Piecewise((1, x < 0), (0, True))
46
+ assert printer.doprint(p) == \
47
+ 'numpy.select([numpy.less(x, 0),True], [1,0], default=numpy.nan)'
48
+ assert printer.module_imports == {'numpy': {'select', 'less', 'nan'}}
49
+
50
+ def test_numpy_logaddexp():
51
+ lae = logaddexp(a, b)
52
+ assert NumPyPrinter().doprint(lae) == 'numpy.logaddexp(a, b)'
53
+ lae2 = logaddexp2(a, b)
54
+ assert NumPyPrinter().doprint(lae2) == 'numpy.logaddexp2(a, b)'
55
+
56
+
57
+ def test_sum():
58
+ if not np:
59
+ skip("NumPy not installed")
60
+
61
+ s = Sum(x ** i, (i, a, b))
62
+ f = lambdify((a, b, x), s, 'numpy')
63
+
64
+ a_, b_ = 0, 10
65
+ x_ = np.linspace(-1, +1, 10)
66
+ assert np.allclose(f(a_, b_, x_), sum(x_ ** i_ for i_ in range(a_, b_ + 1)))
67
+
68
+ s = Sum(i * x, (i, a, b))
69
+ f = lambdify((a, b, x), s, 'numpy')
70
+
71
+ a_, b_ = 0, 10
72
+ x_ = np.linspace(-1, +1, 10)
73
+ assert np.allclose(f(a_, b_, x_), sum(i_ * x_ for i_ in range(a_, b_ + 1)))
74
+
75
+
76
+ def test_multiple_sums():
77
+ if not np:
78
+ skip("NumPy not installed")
79
+
80
+ s = Sum((x + j) * i, (i, a, b), (j, c, d))
81
+ f = lambdify((a, b, c, d, x), s, 'numpy')
82
+
83
+ a_, b_ = 0, 10
84
+ c_, d_ = 11, 21
85
+ x_ = np.linspace(-1, +1, 10)
86
+ assert np.allclose(f(a_, b_, c_, d_, x_),
87
+ sum((x_ + j_) * i_ for i_ in range(a_, b_ + 1) for j_ in range(c_, d_ + 1)))
88
+
89
+
90
+ def test_codegen_einsum():
91
+ if not np:
92
+ skip("NumPy not installed")
93
+
94
+ M = MatrixSymbol("M", 2, 2)
95
+ N = MatrixSymbol("N", 2, 2)
96
+
97
+ cg = convert_matrix_to_array(M * N)
98
+ f = lambdify((M, N), cg, 'numpy')
99
+
100
+ ma = np.array([[1, 2], [3, 4]])
101
+ mb = np.array([[1,-2], [-1, 3]])
102
+ assert (f(ma, mb) == np.matmul(ma, mb)).all()
103
+
104
+
105
+ def test_codegen_extra():
106
+ if not np:
107
+ skip("NumPy not installed")
108
+
109
+ M = MatrixSymbol("M", 2, 2)
110
+ N = MatrixSymbol("N", 2, 2)
111
+ P = MatrixSymbol("P", 2, 2)
112
+ Q = MatrixSymbol("Q", 2, 2)
113
+ ma = np.array([[1, 2], [3, 4]])
114
+ mb = np.array([[1,-2], [-1, 3]])
115
+ mc = np.array([[2, 0], [1, 2]])
116
+ md = np.array([[1,-1], [4, 7]])
117
+
118
+ cg = ArrayTensorProduct(M, N)
119
+ f = lambdify((M, N), cg, 'numpy')
120
+ assert (f(ma, mb) == np.einsum(ma, [0, 1], mb, [2, 3])).all()
121
+
122
+ cg = ArrayAdd(M, N)
123
+ f = lambdify((M, N), cg, 'numpy')
124
+ assert (f(ma, mb) == ma+mb).all()
125
+
126
+ cg = ArrayAdd(M, N, P)
127
+ f = lambdify((M, N, P), cg, 'numpy')
128
+ assert (f(ma, mb, mc) == ma+mb+mc).all()
129
+
130
+ cg = ArrayAdd(M, N, P, Q)
131
+ f = lambdify((M, N, P, Q), cg, 'numpy')
132
+ assert (f(ma, mb, mc, md) == ma+mb+mc+md).all()
133
+
134
+ cg = PermuteDims(M, [1, 0])
135
+ f = lambdify((M,), cg, 'numpy')
136
+ assert (f(ma) == ma.T).all()
137
+
138
+ cg = PermuteDims(ArrayTensorProduct(M, N), [1, 2, 3, 0])
139
+ f = lambdify((M, N), cg, 'numpy')
140
+ assert (f(ma, mb) == np.transpose(np.einsum(ma, [0, 1], mb, [2, 3]), (1, 2, 3, 0))).all()
141
+
142
+ cg = ArrayDiagonal(ArrayTensorProduct(M, N), (1, 2))
143
+ f = lambdify((M, N), cg, 'numpy')
144
+ assert (f(ma, mb) == np.diagonal(np.einsum(ma, [0, 1], mb, [2, 3]), axis1=1, axis2=2)).all()
145
+
146
+
147
+ def test_relational():
148
+ if not np:
149
+ skip("NumPy not installed")
150
+
151
+ e = Equality(x, 1)
152
+
153
+ f = lambdify((x,), e)
154
+ x_ = np.array([0, 1, 2])
155
+ assert np.array_equal(f(x_), [False, True, False])
156
+
157
+ e = Unequality(x, 1)
158
+
159
+ f = lambdify((x,), e)
160
+ x_ = np.array([0, 1, 2])
161
+ assert np.array_equal(f(x_), [True, False, True])
162
+
163
+ e = (x < 1)
164
+
165
+ f = lambdify((x,), e)
166
+ x_ = np.array([0, 1, 2])
167
+ assert np.array_equal(f(x_), [True, False, False])
168
+
169
+ e = (x <= 1)
170
+
171
+ f = lambdify((x,), e)
172
+ x_ = np.array([0, 1, 2])
173
+ assert np.array_equal(f(x_), [True, True, False])
174
+
175
+ e = (x > 1)
176
+
177
+ f = lambdify((x,), e)
178
+ x_ = np.array([0, 1, 2])
179
+ assert np.array_equal(f(x_), [False, False, True])
180
+
181
+ e = (x >= 1)
182
+
183
+ f = lambdify((x,), e)
184
+ x_ = np.array([0, 1, 2])
185
+ assert np.array_equal(f(x_), [False, True, True])
186
+
187
+
188
+ def test_mod():
189
+ if not np:
190
+ skip("NumPy not installed")
191
+
192
+ e = Mod(a, b)
193
+ f = lambdify((a, b), e)
194
+
195
+ a_ = np.array([0, 1, 2, 3])
196
+ b_ = 2
197
+ assert np.array_equal(f(a_, b_), [0, 1, 0, 1])
198
+
199
+ a_ = np.array([0, 1, 2, 3])
200
+ b_ = np.array([2, 2, 2, 2])
201
+ assert np.array_equal(f(a_, b_), [0, 1, 0, 1])
202
+
203
+ a_ = np.array([2, 3, 4, 5])
204
+ b_ = np.array([2, 3, 4, 5])
205
+ assert np.array_equal(f(a_, b_), [0, 0, 0, 0])
206
+
207
+
208
+ def test_pow():
209
+ if not np:
210
+ skip('NumPy not installed')
211
+
212
+ expr = Pow(2, -1, evaluate=False)
213
+ f = lambdify([], expr, 'numpy')
214
+ assert f() == 0.5
215
+
216
+
217
+ def test_expm1():
218
+ if not np:
219
+ skip("NumPy not installed")
220
+
221
+ f = lambdify((a,), expm1(a), 'numpy')
222
+ assert abs(f(1e-10) - 1e-10 - 5e-21) <= 1e-10 * NUMPY_DEFAULT_EPSILON
223
+
224
+
225
+ def test_log1p():
226
+ if not np:
227
+ skip("NumPy not installed")
228
+
229
+ f = lambdify((a,), log1p(a), 'numpy')
230
+ assert abs(f(1e-99) - 1e-99) <= 1e-99 * NUMPY_DEFAULT_EPSILON
231
+
232
+ def test_hypot():
233
+ if not np:
234
+ skip("NumPy not installed")
235
+ assert abs(lambdify((a, b), hypot(a, b), 'numpy')(3, 4) - 5) <= NUMPY_DEFAULT_EPSILON
236
+
237
+ def test_log10():
238
+ if not np:
239
+ skip("NumPy not installed")
240
+ assert abs(lambdify((a,), log10(a), 'numpy')(100) - 2) <= NUMPY_DEFAULT_EPSILON
241
+
242
+
243
+ def test_exp2():
244
+ if not np:
245
+ skip("NumPy not installed")
246
+ assert abs(lambdify((a,), exp2(a), 'numpy')(5) - 32) <= NUMPY_DEFAULT_EPSILON
247
+
248
+
249
+ def test_log2():
250
+ if not np:
251
+ skip("NumPy not installed")
252
+ assert abs(lambdify((a,), log2(a), 'numpy')(256) - 8) <= NUMPY_DEFAULT_EPSILON
253
+
254
+
255
+ def test_Sqrt():
256
+ if not np:
257
+ skip("NumPy not installed")
258
+ assert abs(lambdify((a,), Sqrt(a), 'numpy')(4) - 2) <= NUMPY_DEFAULT_EPSILON
259
+
260
+
261
+ def test_sqrt():
262
+ if not np:
263
+ skip("NumPy not installed")
264
+ assert abs(lambdify((a,), sqrt(a), 'numpy')(4) - 2) <= NUMPY_DEFAULT_EPSILON
265
+
266
+
267
+ def test_matsolve():
268
+ if not np:
269
+ skip("NumPy not installed")
270
+
271
+ M = MatrixSymbol("M", 3, 3)
272
+ x = MatrixSymbol("x", 3, 1)
273
+
274
+ expr = M**(-1) * x + x
275
+ matsolve_expr = MatrixSolve(M, x) + x
276
+
277
+ f = lambdify((M, x), expr)
278
+ f_matsolve = lambdify((M, x), matsolve_expr)
279
+
280
+ m0 = np.array([[1, 2, 3], [3, 2, 5], [5, 6, 7]])
281
+ assert np.linalg.matrix_rank(m0) == 3
282
+
283
+ x0 = np.array([3, 4, 5])
284
+
285
+ assert np.allclose(f_matsolve(m0, x0), f(m0, x0))
286
+
287
+
288
+ def test_16857():
289
+ if not np:
290
+ skip("NumPy not installed")
291
+
292
+ a_1 = MatrixSymbol('a_1', 10, 3)
293
+ a_2 = MatrixSymbol('a_2', 10, 3)
294
+ a_3 = MatrixSymbol('a_3', 10, 3)
295
+ a_4 = MatrixSymbol('a_4', 10, 3)
296
+ A = BlockMatrix([[a_1, a_2], [a_3, a_4]])
297
+ assert A.shape == (20, 6)
298
+
299
+ printer = NumPyPrinter()
300
+ assert printer.doprint(A) == 'numpy.block([[a_1, a_2], [a_3, a_4]])'
301
+
302
+
303
+ def test_issue_17006():
304
+ if not np:
305
+ skip("NumPy not installed")
306
+
307
+ M = MatrixSymbol("M", 2, 2)
308
+
309
+ f = lambdify(M, M + Identity(2))
310
+ ma = np.array([[1, 2], [3, 4]])
311
+ mr = np.array([[2, 2], [3, 5]])
312
+
313
+ assert (f(ma) == mr).all()
314
+
315
+ from sympy.core.symbol import symbols
316
+ n = symbols('n', integer=True)
317
+ N = MatrixSymbol("M", n, n)
318
+ raises(NotImplementedError, lambda: lambdify(N, N + Identity(n)))
319
+
320
+ def test_jax_tuple_compatibility():
321
+ if not jax:
322
+ skip("Jax not installed")
323
+
324
+ x, y, z = symbols('x y z')
325
+ expr = Max(x, y, z) + Min(x, y, z)
326
+ func = lambdify((x, y, z), expr, 'jax')
327
+ input_tuple1, input_tuple2 = (1, 2, 3), (4, 5, 6)
328
+ input_array1, input_array2 = jax.numpy.asarray(input_tuple1), jax.numpy.asarray(input_tuple2)
329
+ assert np.allclose(func(*input_tuple1), func(*input_array1))
330
+ assert np.allclose(func(*input_tuple2), func(*input_array2))
331
+
332
+ def test_numpy_array():
333
+ p = NumPyPrinter()
334
+ assert p.doprint(Array([[1, 2], [3, 5]])) == 'numpy.array([[1, 2], [3, 5]])'
335
+ assert p.doprint(Array([1, 2])) == 'numpy.array([1, 2])'
336
+ assert p.doprint(Array([[[1, 2, 3]]])) == 'numpy.array([[[1, 2, 3]]])'
337
+ assert p.doprint(Array([], (0,))) == 'numpy.zeros((0,))'
338
+ assert p.doprint(Array([], (0, 0))) == 'numpy.zeros((0, 0))'
339
+ assert p.doprint(Array([], (0, 1))) == 'numpy.zeros((0, 1))'
340
+ assert p.doprint(Array([], (1, 0))) == 'numpy.zeros((1, 0))'
341
+ assert p.doprint(Array([1], ())) == 'numpy.array(1)'
342
+
343
+ def test_numpy_matrix():
344
+ p = NumPyPrinter()
345
+ assert p.doprint(Matrix([[1, 2], [3, 5]])) == 'numpy.array([[1, 2], [3, 5]])'
346
+ assert p.doprint(Matrix([1, 2])) == 'numpy.array([[1], [2]])'
347
+ assert p.doprint(Matrix(0, 0, [])) == 'numpy.zeros((0, 0))'
348
+ assert p.doprint(Matrix(0, 1, [])) == 'numpy.zeros((0, 1))'
349
+ assert p.doprint(Matrix(1, 0, [])) == 'numpy.zeros((1, 0))'
350
+
351
+ def test_numpy_known_funcs_consts():
352
+ assert _numpy_known_constants['NaN'] == 'numpy.nan'
353
+ assert _numpy_known_constants['EulerGamma'] == 'numpy.euler_gamma'
354
+
355
+ assert _numpy_known_functions['acos'] == 'numpy.arccos'
356
+ assert _numpy_known_functions['log'] == 'numpy.log'
357
+
358
+ def test_scipy_known_funcs_consts():
359
+ assert _scipy_known_constants['GoldenRatio'] == 'scipy.constants.golden_ratio'
360
+ assert _scipy_known_constants['Pi'] == 'scipy.constants.pi'
361
+
362
+ assert _scipy_known_functions['erf'] == 'scipy.special.erf'
363
+ assert _scipy_known_functions['factorial'] == 'scipy.special.factorial'
364
+
365
+ def test_numpy_print_methods():
366
+ prntr = NumPyPrinter()
367
+ assert hasattr(prntr, '_print_acos')
368
+ assert hasattr(prntr, '_print_log')
369
+
370
+ def test_scipy_print_methods():
371
+ prntr = SciPyPrinter()
372
+ assert hasattr(prntr, '_print_acos')
373
+ assert hasattr(prntr, '_print_log')
374
+ assert hasattr(prntr, '_print_erf')
375
+ assert hasattr(prntr, '_print_factorial')
376
+ assert hasattr(prntr, '_print_chebyshevt')
377
+ k = Symbol('k', integer=True, nonnegative=True)
378
+ x = Symbol('x', real=True)
379
+ assert prntr.doprint(polygamma(k, x)) == "scipy.special.polygamma(k, x)"
380
+ assert prntr.doprint(Si(x)) == "scipy.special.sici(x)[0]"
381
+ assert prntr.doprint(Ci(x)) == "scipy.special.sici(x)[1]"
outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_octave.py ADDED
@@ -0,0 +1,515 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core import (S, pi, oo, symbols, Function, Rational, Integer,
2
+ Tuple, Symbol, EulerGamma, GoldenRatio, Catalan,
3
+ Lambda, Mul, Pow, Mod, Eq, Ne, Le, Lt, Gt, Ge)
4
+ from sympy.codegen.matrix_nodes import MatrixSolve
5
+ from sympy.functions import (arg, atan2, bernoulli, beta, ceiling, chebyshevu,
6
+ chebyshevt, conjugate, DiracDelta, exp, expint,
7
+ factorial, floor, harmonic, Heaviside, im,
8
+ laguerre, LambertW, log, Max, Min, Piecewise,
9
+ polylog, re, RisingFactorial, sign, sinc, sqrt,
10
+ zeta, binomial, legendre, dirichlet_eta,
11
+ riemann_xi)
12
+ from sympy.functions import (sin, cos, tan, cot, sec, csc, asin, acos, acot,
13
+ atan, asec, acsc, sinh, cosh, tanh, coth, csch,
14
+ sech, asinh, acosh, atanh, acoth, asech, acsch)
15
+ from sympy.testing.pytest import raises, XFAIL
16
+ from sympy.utilities.lambdify import implemented_function
17
+ from sympy.matrices import (eye, Matrix, MatrixSymbol, Identity,
18
+ HadamardProduct, SparseMatrix, HadamardPower)
19
+ from sympy.functions.special.bessel import (jn, yn, besselj, bessely, besseli,
20
+ besselk, hankel1, hankel2, airyai,
21
+ airybi, airyaiprime, airybiprime)
22
+ from sympy.functions.special.gamma_functions import (gamma, lowergamma,
23
+ uppergamma, loggamma,
24
+ polygamma)
25
+ from sympy.functions.special.error_functions import (Chi, Ci, erf, erfc, erfi,
26
+ erfcinv, erfinv, fresnelc,
27
+ fresnels, li, Shi, Si, Li,
28
+ erf2, Ei)
29
+ from sympy.printing.octave import octave_code, octave_code as mcode
30
+
31
+ x, y, z = symbols('x,y,z')
32
+
33
+
34
+ def test_Integer():
35
+ assert mcode(Integer(67)) == "67"
36
+ assert mcode(Integer(-1)) == "-1"
37
+
38
+
39
+ def test_Rational():
40
+ assert mcode(Rational(3, 7)) == "3/7"
41
+ assert mcode(Rational(18, 9)) == "2"
42
+ assert mcode(Rational(3, -7)) == "-3/7"
43
+ assert mcode(Rational(-3, -7)) == "3/7"
44
+ assert mcode(x + Rational(3, 7)) == "x + 3/7"
45
+ assert mcode(Rational(3, 7)*x) == "3*x/7"
46
+
47
+
48
+ def test_Relational():
49
+ assert mcode(Eq(x, y)) == "x == y"
50
+ assert mcode(Ne(x, y)) == "x != y"
51
+ assert mcode(Le(x, y)) == "x <= y"
52
+ assert mcode(Lt(x, y)) == "x < y"
53
+ assert mcode(Gt(x, y)) == "x > y"
54
+ assert mcode(Ge(x, y)) == "x >= y"
55
+
56
+
57
+ def test_Function():
58
+ assert mcode(sin(x) ** cos(x)) == "sin(x).^cos(x)"
59
+ assert mcode(sign(x)) == "sign(x)"
60
+ assert mcode(exp(x)) == "exp(x)"
61
+ assert mcode(log(x)) == "log(x)"
62
+ assert mcode(factorial(x)) == "factorial(x)"
63
+ assert mcode(floor(x)) == "floor(x)"
64
+ assert mcode(atan2(y, x)) == "atan2(y, x)"
65
+ assert mcode(beta(x, y)) == 'beta(x, y)'
66
+ assert mcode(polylog(x, y)) == 'polylog(x, y)'
67
+ assert mcode(harmonic(x)) == 'harmonic(x)'
68
+ assert mcode(bernoulli(x)) == "bernoulli(x)"
69
+ assert mcode(bernoulli(x, y)) == "bernoulli(x, y)"
70
+ assert mcode(legendre(x, y)) == "legendre(x, y)"
71
+
72
+
73
+ def test_Function_change_name():
74
+ assert mcode(abs(x)) == "abs(x)"
75
+ assert mcode(ceiling(x)) == "ceil(x)"
76
+ assert mcode(arg(x)) == "angle(x)"
77
+ assert mcode(im(x)) == "imag(x)"
78
+ assert mcode(re(x)) == "real(x)"
79
+ assert mcode(conjugate(x)) == "conj(x)"
80
+ assert mcode(chebyshevt(y, x)) == "chebyshevT(y, x)"
81
+ assert mcode(chebyshevu(y, x)) == "chebyshevU(y, x)"
82
+ assert mcode(laguerre(x, y)) == "laguerreL(x, y)"
83
+ assert mcode(Chi(x)) == "coshint(x)"
84
+ assert mcode(Shi(x)) == "sinhint(x)"
85
+ assert mcode(Ci(x)) == "cosint(x)"
86
+ assert mcode(Si(x)) == "sinint(x)"
87
+ assert mcode(li(x)) == "logint(x)"
88
+ assert mcode(loggamma(x)) == "gammaln(x)"
89
+ assert mcode(polygamma(x, y)) == "psi(x, y)"
90
+ assert mcode(RisingFactorial(x, y)) == "pochhammer(x, y)"
91
+ assert mcode(DiracDelta(x)) == "dirac(x)"
92
+ assert mcode(DiracDelta(x, 3)) == "dirac(3, x)"
93
+ assert mcode(Heaviside(x)) == "heaviside(x, 1/2)"
94
+ assert mcode(Heaviside(x, y)) == "heaviside(x, y)"
95
+ assert mcode(binomial(x, y)) == "bincoeff(x, y)"
96
+ assert mcode(Mod(x, y)) == "mod(x, y)"
97
+
98
+
99
+ def test_minmax():
100
+ assert mcode(Max(x, y) + Min(x, y)) == "max(x, y) + min(x, y)"
101
+ assert mcode(Max(x, y, z)) == "max(x, max(y, z))"
102
+ assert mcode(Min(x, y, z)) == "min(x, min(y, z))"
103
+
104
+
105
+ def test_Pow():
106
+ assert mcode(x**3) == "x.^3"
107
+ assert mcode(x**(y**3)) == "x.^(y.^3)"
108
+ assert mcode(x**Rational(2, 3)) == 'x.^(2/3)'
109
+ g = implemented_function('g', Lambda(x, 2*x))
110
+ assert mcode(1/(g(x)*3.5)**(x - y**x)/(x**2 + y)) == \
111
+ "(3.5*2*x).^(-x + y.^x)./(x.^2 + y)"
112
+ # For issue 14160
113
+ assert mcode(Mul(-2, x, Pow(Mul(y,y,evaluate=False), -1, evaluate=False),
114
+ evaluate=False)) == '-2*x./(y.*y)'
115
+
116
+
117
+ def test_basic_ops():
118
+ assert mcode(x*y) == "x.*y"
119
+ assert mcode(x + y) == "x + y"
120
+ assert mcode(x - y) == "x - y"
121
+ assert mcode(-x) == "-x"
122
+
123
+
124
+ def test_1_over_x_and_sqrt():
125
+ # 1.0 and 0.5 would do something different in regular StrPrinter,
126
+ # but these are exact in IEEE floating point so no different here.
127
+ assert mcode(1/x) == '1./x'
128
+ assert mcode(x**-1) == mcode(x**-1.0) == '1./x'
129
+ assert mcode(1/sqrt(x)) == '1./sqrt(x)'
130
+ assert mcode(x**-S.Half) == mcode(x**-0.5) == '1./sqrt(x)'
131
+ assert mcode(sqrt(x)) == 'sqrt(x)'
132
+ assert mcode(x**S.Half) == mcode(x**0.5) == 'sqrt(x)'
133
+ assert mcode(1/pi) == '1/pi'
134
+ assert mcode(pi**-1) == mcode(pi**-1.0) == '1/pi'
135
+ assert mcode(pi**-0.5) == '1/sqrt(pi)'
136
+
137
+
138
+ def test_mix_number_mult_symbols():
139
+ assert mcode(3*x) == "3*x"
140
+ assert mcode(pi*x) == "pi*x"
141
+ assert mcode(3/x) == "3./x"
142
+ assert mcode(pi/x) == "pi./x"
143
+ assert mcode(x/3) == "x/3"
144
+ assert mcode(x/pi) == "x/pi"
145
+ assert mcode(x*y) == "x.*y"
146
+ assert mcode(3*x*y) == "3*x.*y"
147
+ assert mcode(3*pi*x*y) == "3*pi*x.*y"
148
+ assert mcode(x/y) == "x./y"
149
+ assert mcode(3*x/y) == "3*x./y"
150
+ assert mcode(x*y/z) == "x.*y./z"
151
+ assert mcode(x/y*z) == "x.*z./y"
152
+ assert mcode(1/x/y) == "1./(x.*y)"
153
+ assert mcode(2*pi*x/y/z) == "2*pi*x./(y.*z)"
154
+ assert mcode(3*pi/x) == "3*pi./x"
155
+ assert mcode(S(3)/5) == "3/5"
156
+ assert mcode(S(3)/5*x) == "3*x/5"
157
+ assert mcode(x/y/z) == "x./(y.*z)"
158
+ assert mcode((x+y)/z) == "(x + y)./z"
159
+ assert mcode((x+y)/(z+x)) == "(x + y)./(x + z)"
160
+ assert mcode((x+y)/EulerGamma) == "(x + y)/%s" % EulerGamma.evalf(17)
161
+ assert mcode(x/3/pi) == "x/(3*pi)"
162
+ assert mcode(S(3)/5*x*y/pi) == "3*x.*y/(5*pi)"
163
+
164
+
165
+ def test_mix_number_pow_symbols():
166
+ assert mcode(pi**3) == 'pi^3'
167
+ assert mcode(x**2) == 'x.^2'
168
+ assert mcode(x**(pi**3)) == 'x.^(pi^3)'
169
+ assert mcode(x**y) == 'x.^y'
170
+ assert mcode(x**(y**z)) == 'x.^(y.^z)'
171
+ assert mcode((x**y)**z) == '(x.^y).^z'
172
+
173
+
174
+ def test_imag():
175
+ I = S('I')
176
+ assert mcode(I) == "1i"
177
+ assert mcode(5*I) == "5i"
178
+ assert mcode((S(3)/2)*I) == "3*1i/2"
179
+ assert mcode(3+4*I) == "3 + 4i"
180
+ assert mcode(sqrt(3)*I) == "sqrt(3)*1i"
181
+
182
+
183
+ def test_constants():
184
+ assert mcode(pi) == "pi"
185
+ assert mcode(oo) == "inf"
186
+ assert mcode(-oo) == "-inf"
187
+ assert mcode(S.NegativeInfinity) == "-inf"
188
+ assert mcode(S.NaN) == "NaN"
189
+ assert mcode(S.Exp1) == "exp(1)"
190
+ assert mcode(exp(1)) == "exp(1)"
191
+
192
+
193
+ def test_constants_other():
194
+ assert mcode(2*GoldenRatio) == "2*(1+sqrt(5))/2"
195
+ assert mcode(2*Catalan) == "2*%s" % Catalan.evalf(17)
196
+ assert mcode(2*EulerGamma) == "2*%s" % EulerGamma.evalf(17)
197
+
198
+
199
+ def test_boolean():
200
+ assert mcode(x & y) == "x & y"
201
+ assert mcode(x | y) == "x | y"
202
+ assert mcode(~x) == "~x"
203
+ assert mcode(x & y & z) == "x & y & z"
204
+ assert mcode(x | y | z) == "x | y | z"
205
+ assert mcode((x & y) | z) == "z | x & y"
206
+ assert mcode((x | y) & z) == "z & (x | y)"
207
+
208
+
209
+ def test_KroneckerDelta():
210
+ from sympy.functions import KroneckerDelta
211
+ assert mcode(KroneckerDelta(x, y)) == "double(x == y)"
212
+ assert mcode(KroneckerDelta(x, y + 1)) == "double(x == (y + 1))"
213
+ assert mcode(KroneckerDelta(2**x, y)) == "double((2.^x) == y)"
214
+
215
+
216
+ def test_Matrices():
217
+ assert mcode(Matrix(1, 1, [10])) == "10"
218
+ A = Matrix([[1, sin(x/2), abs(x)],
219
+ [0, 1, pi],
220
+ [0, exp(1), ceiling(x)]])
221
+ expected = "[1 sin(x/2) abs(x); 0 1 pi; 0 exp(1) ceil(x)]"
222
+ assert mcode(A) == expected
223
+ # row and columns
224
+ assert mcode(A[:,0]) == "[1; 0; 0]"
225
+ assert mcode(A[0,:]) == "[1 sin(x/2) abs(x)]"
226
+ # empty matrices
227
+ assert mcode(Matrix(0, 0, [])) == '[]'
228
+ assert mcode(Matrix(0, 3, [])) == 'zeros(0, 3)'
229
+ # annoying to read but correct
230
+ assert mcode(Matrix([[x, x - y, -y]])) == "[x x - y -y]"
231
+
232
+
233
+ def test_vector_entries_hadamard():
234
+ # For a row or column, user might to use the other dimension
235
+ A = Matrix([[1, sin(2/x), 3*pi/x/5]])
236
+ assert mcode(A) == "[1 sin(2./x) 3*pi./(5*x)]"
237
+ assert mcode(A.T) == "[1; sin(2./x); 3*pi./(5*x)]"
238
+
239
+
240
+ @XFAIL
241
+ def test_Matrices_entries_not_hadamard():
242
+ # For Matrix with col >= 2, row >= 2, they need to be scalars
243
+ # FIXME: is it worth worrying about this? Its not wrong, just
244
+ # leave it user's responsibility to put scalar data for x.
245
+ A = Matrix([[1, sin(2/x), 3*pi/x/5], [1, 2, x*y]])
246
+ expected = ("[1 sin(2/x) 3*pi/(5*x);\n"
247
+ "1 2 x*y]") # <- we give x.*y
248
+ assert mcode(A) == expected
249
+
250
+
251
+ def test_MatrixSymbol():
252
+ n = Symbol('n', integer=True)
253
+ A = MatrixSymbol('A', n, n)
254
+ B = MatrixSymbol('B', n, n)
255
+ assert mcode(A*B) == "A*B"
256
+ assert mcode(B*A) == "B*A"
257
+ assert mcode(2*A*B) == "2*A*B"
258
+ assert mcode(B*2*A) == "2*B*A"
259
+ assert mcode(A*(B + 3*Identity(n))) == "A*(3*eye(n) + B)"
260
+ assert mcode(A**(x**2)) == "A^(x.^2)"
261
+ assert mcode(A**3) == "A^3"
262
+ assert mcode(A**S.Half) == "A^(1/2)"
263
+
264
+
265
+ def test_MatrixSolve():
266
+ n = Symbol('n', integer=True)
267
+ A = MatrixSymbol('A', n, n)
268
+ x = MatrixSymbol('x', n, 1)
269
+ assert mcode(MatrixSolve(A, x)) == "A \\ x"
270
+
271
+ def test_special_matrices():
272
+ assert mcode(6*Identity(3)) == "6*eye(3)"
273
+
274
+
275
+ def test_containers():
276
+ assert mcode([1, 2, 3, [4, 5, [6, 7]], 8, [9, 10], 11]) == \
277
+ "{1, 2, 3, {4, 5, {6, 7}}, 8, {9, 10}, 11}"
278
+ assert mcode((1, 2, (3, 4))) == "{1, 2, {3, 4}}"
279
+ assert mcode([1]) == "{1}"
280
+ assert mcode((1,)) == "{1}"
281
+ assert mcode(Tuple(*[1, 2, 3])) == "{1, 2, 3}"
282
+ assert mcode((1, x*y, (3, x**2))) == "{1, x.*y, {3, x.^2}}"
283
+ # scalar, matrix, empty matrix and empty list
284
+ assert mcode((1, eye(3), Matrix(0, 0, []), [])) == "{1, [1 0 0; 0 1 0; 0 0 1], [], {}}"
285
+
286
+
287
+ def test_octave_noninline():
288
+ source = mcode((x+y)/Catalan, assign_to='me', inline=False)
289
+ expected = (
290
+ "Catalan = %s;\n"
291
+ "me = (x + y)/Catalan;"
292
+ ) % Catalan.evalf(17)
293
+ assert source == expected
294
+
295
+
296
+ def test_octave_piecewise():
297
+ expr = Piecewise((x, x < 1), (x**2, True))
298
+ assert mcode(expr) == "((x < 1).*(x) + (~(x < 1)).*(x.^2))"
299
+ assert mcode(expr, assign_to="r") == (
300
+ "r = ((x < 1).*(x) + (~(x < 1)).*(x.^2));")
301
+ assert mcode(expr, assign_to="r", inline=False) == (
302
+ "if (x < 1)\n"
303
+ " r = x;\n"
304
+ "else\n"
305
+ " r = x.^2;\n"
306
+ "end")
307
+ expr = Piecewise((x**2, x < 1), (x**3, x < 2), (x**4, x < 3), (x**5, True))
308
+ expected = ("((x < 1).*(x.^2) + (~(x < 1)).*( ...\n"
309
+ "(x < 2).*(x.^3) + (~(x < 2)).*( ...\n"
310
+ "(x < 3).*(x.^4) + (~(x < 3)).*(x.^5))))")
311
+ assert mcode(expr) == expected
312
+ assert mcode(expr, assign_to="r") == "r = " + expected + ";"
313
+ assert mcode(expr, assign_to="r", inline=False) == (
314
+ "if (x < 1)\n"
315
+ " r = x.^2;\n"
316
+ "elseif (x < 2)\n"
317
+ " r = x.^3;\n"
318
+ "elseif (x < 3)\n"
319
+ " r = x.^4;\n"
320
+ "else\n"
321
+ " r = x.^5;\n"
322
+ "end")
323
+ # Check that Piecewise without a True (default) condition error
324
+ expr = Piecewise((x, x < 1), (x**2, x > 1), (sin(x), x > 0))
325
+ raises(ValueError, lambda: mcode(expr))
326
+
327
+
328
+ def test_octave_piecewise_times_const():
329
+ pw = Piecewise((x, x < 1), (x**2, True))
330
+ assert mcode(2*pw) == "2*((x < 1).*(x) + (~(x < 1)).*(x.^2))"
331
+ assert mcode(pw/x) == "((x < 1).*(x) + (~(x < 1)).*(x.^2))./x"
332
+ assert mcode(pw/(x*y)) == "((x < 1).*(x) + (~(x < 1)).*(x.^2))./(x.*y)"
333
+ assert mcode(pw/3) == "((x < 1).*(x) + (~(x < 1)).*(x.^2))/3"
334
+
335
+
336
+ def test_octave_matrix_assign_to():
337
+ A = Matrix([[1, 2, 3]])
338
+ assert mcode(A, assign_to='a') == "a = [1 2 3];"
339
+ A = Matrix([[1, 2], [3, 4]])
340
+ assert mcode(A, assign_to='A') == "A = [1 2; 3 4];"
341
+
342
+
343
+ def test_octave_matrix_assign_to_more():
344
+ # assigning to Symbol or MatrixSymbol requires lhs/rhs match
345
+ A = Matrix([[1, 2, 3]])
346
+ B = MatrixSymbol('B', 1, 3)
347
+ C = MatrixSymbol('C', 2, 3)
348
+ assert mcode(A, assign_to=B) == "B = [1 2 3];"
349
+ raises(ValueError, lambda: mcode(A, assign_to=x))
350
+ raises(ValueError, lambda: mcode(A, assign_to=C))
351
+
352
+
353
+ def test_octave_matrix_1x1():
354
+ A = Matrix([[3]])
355
+ B = MatrixSymbol('B', 1, 1)
356
+ C = MatrixSymbol('C', 1, 2)
357
+ assert mcode(A, assign_to=B) == "B = 3;"
358
+ # FIXME?
359
+ #assert mcode(A, assign_to=x) == "x = 3;"
360
+ raises(ValueError, lambda: mcode(A, assign_to=C))
361
+
362
+
363
+ def test_octave_matrix_elements():
364
+ A = Matrix([[x, 2, x*y]])
365
+ assert mcode(A[0, 0]**2 + A[0, 1] + A[0, 2]) == "x.^2 + x.*y + 2"
366
+ A = MatrixSymbol('AA', 1, 3)
367
+ assert mcode(A) == "AA"
368
+ assert mcode(A[0, 0]**2 + sin(A[0,1]) + A[0,2]) == \
369
+ "sin(AA(1, 2)) + AA(1, 1).^2 + AA(1, 3)"
370
+ assert mcode(sum(A)) == "AA(1, 1) + AA(1, 2) + AA(1, 3)"
371
+
372
+
373
+ def test_octave_boolean():
374
+ assert mcode(True) == "true"
375
+ assert mcode(S.true) == "true"
376
+ assert mcode(False) == "false"
377
+ assert mcode(S.false) == "false"
378
+
379
+
380
+ def test_octave_not_supported():
381
+ with raises(NotImplementedError):
382
+ mcode(S.ComplexInfinity)
383
+ f = Function('f')
384
+ assert mcode(f(x).diff(x), strict=False) == (
385
+ "% Not supported in Octave:\n"
386
+ "% Derivative\n"
387
+ "Derivative(f(x), x)"
388
+ )
389
+
390
+
391
+ def test_octave_not_supported_not_on_whitelist():
392
+ from sympy.functions.special.polynomials import assoc_laguerre
393
+ with raises(NotImplementedError):
394
+ mcode(assoc_laguerre(x, y, z))
395
+
396
+
397
+ def test_octave_expint():
398
+ assert mcode(expint(1, x)) == "expint(x)"
399
+ with raises(NotImplementedError):
400
+ mcode(expint(2, x))
401
+ assert mcode(expint(y, x), strict=False) == (
402
+ "% Not supported in Octave:\n"
403
+ "% expint\n"
404
+ "expint(y, x)"
405
+ )
406
+
407
+
408
+ def test_trick_indent_with_end_else_words():
409
+ # words starting with "end" or "else" do not confuse the indenter
410
+ t1 = S('endless')
411
+ t2 = S('elsewhere')
412
+ pw = Piecewise((t1, x < 0), (t2, x <= 1), (1, True))
413
+ assert mcode(pw, inline=False) == (
414
+ "if (x < 0)\n"
415
+ " endless\n"
416
+ "elseif (x <= 1)\n"
417
+ " elsewhere\n"
418
+ "else\n"
419
+ " 1\n"
420
+ "end")
421
+
422
+
423
+ def test_hadamard():
424
+ A = MatrixSymbol('A', 3, 3)
425
+ B = MatrixSymbol('B', 3, 3)
426
+ v = MatrixSymbol('v', 3, 1)
427
+ h = MatrixSymbol('h', 1, 3)
428
+ C = HadamardProduct(A, B)
429
+ n = Symbol('n')
430
+ assert mcode(C) == "A.*B"
431
+ assert mcode(C*v) == "(A.*B)*v"
432
+ assert mcode(h*C*v) == "h*(A.*B)*v"
433
+ assert mcode(C*A) == "(A.*B)*A"
434
+ # mixing Hadamard and scalar strange b/c we vectorize scalars
435
+ assert mcode(C*x*y) == "(x.*y)*(A.*B)"
436
+
437
+ # Testing HadamardPower:
438
+ assert mcode(HadamardPower(A, n)) == "A.**n"
439
+ assert mcode(HadamardPower(A, 1+n)) == "A.**(n + 1)"
440
+ assert mcode(HadamardPower(A*B.T, 1+n)) == "(A*B.T).**(n + 1)"
441
+
442
+
443
+ def test_sparse():
444
+ M = SparseMatrix(5, 6, {})
445
+ M[2, 2] = 10
446
+ M[1, 2] = 20
447
+ M[1, 3] = 22
448
+ M[0, 3] = 30
449
+ M[3, 0] = x*y
450
+ assert mcode(M) == (
451
+ "sparse([4 2 3 1 2], [1 3 3 4 4], [x.*y 20 10 30 22], 5, 6)"
452
+ )
453
+
454
+
455
+ def test_sinc():
456
+ assert mcode(sinc(x)) == 'sinc(x/pi)'
457
+ assert mcode(sinc(x + 3)) == 'sinc((x + 3)/pi)'
458
+ assert mcode(sinc(pi*(x + 3))) == 'sinc(x + 3)'
459
+
460
+
461
+ def test_trigfun():
462
+ for f in (sin, cos, tan, cot, sec, csc, asin, acos, acot, atan, asec, acsc,
463
+ sinh, cosh, tanh, coth, csch, sech, asinh, acosh, atanh, acoth,
464
+ asech, acsch):
465
+ assert octave_code(f(x) == f.__name__ + '(x)')
466
+
467
+
468
+ def test_specfun():
469
+ n = Symbol('n')
470
+ for f in [besselj, bessely, besseli, besselk]:
471
+ assert octave_code(f(n, x)) == f.__name__ + '(n, x)'
472
+ for f in (erfc, erfi, erf, erfinv, erfcinv, fresnelc, fresnels, gamma):
473
+ assert octave_code(f(x)) == f.__name__ + '(x)'
474
+ assert octave_code(hankel1(n, x)) == 'besselh(n, 1, x)'
475
+ assert octave_code(hankel2(n, x)) == 'besselh(n, 2, x)'
476
+ assert octave_code(airyai(x)) == 'airy(0, x)'
477
+ assert octave_code(airyaiprime(x)) == 'airy(1, x)'
478
+ assert octave_code(airybi(x)) == 'airy(2, x)'
479
+ assert octave_code(airybiprime(x)) == 'airy(3, x)'
480
+ assert octave_code(uppergamma(n, x)) == '(gammainc(x, n, \'upper\').*gamma(n))'
481
+ assert octave_code(lowergamma(n, x)) == '(gammainc(x, n).*gamma(n))'
482
+ assert octave_code(z**lowergamma(n, x)) == 'z.^(gammainc(x, n).*gamma(n))'
483
+ assert octave_code(jn(n, x)) == 'sqrt(2)*sqrt(pi)*sqrt(1./x).*besselj(n + 1/2, x)/2'
484
+ assert octave_code(yn(n, x)) == 'sqrt(2)*sqrt(pi)*sqrt(1./x).*bessely(n + 1/2, x)/2'
485
+ assert octave_code(LambertW(x)) == 'lambertw(x)'
486
+ assert octave_code(LambertW(x, n)) == 'lambertw(n, x)'
487
+
488
+ # Automatic rewrite
489
+ assert octave_code(Ei(x)) == '(logint(exp(x)))'
490
+ assert octave_code(dirichlet_eta(x)) == '(((x == 1).*(log(2)) + (~(x == 1)).*((1 - 2.^(1 - x)).*zeta(x))))'
491
+ assert octave_code(riemann_xi(x)) == '(pi.^(-x/2).*x.*(x - 1).*gamma(x/2).*zeta(x)/2)'
492
+
493
+
494
+ def test_MatrixElement_printing():
495
+ # test cases for issue #11821
496
+ A = MatrixSymbol("A", 1, 3)
497
+ B = MatrixSymbol("B", 1, 3)
498
+ C = MatrixSymbol("C", 1, 3)
499
+
500
+ assert mcode(A[0, 0]) == "A(1, 1)"
501
+ assert mcode(3 * A[0, 0]) == "3*A(1, 1)"
502
+
503
+ F = C[0, 0].subs(C, A - B)
504
+ assert mcode(F) == "(A - B)(1, 1)"
505
+
506
+
507
+ def test_zeta_printing_issue_14820():
508
+ assert octave_code(zeta(x)) == 'zeta(x)'
509
+ with raises(NotImplementedError):
510
+ octave_code(zeta(x, y))
511
+
512
+
513
+ def test_automatic_rewrite():
514
+ assert octave_code(Li(x)) == '(logint(x) - logint(2))'
515
+ assert octave_code(erf2(x, y)) == '(-erf(x) + erf(y))'
outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_precedence.py ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.concrete.products import Product
2
+ from sympy.concrete.summations import Sum
3
+ from sympy.core.function import Derivative, Function
4
+ from sympy.core.numbers import Integer, Rational, Float, oo
5
+ from sympy.core.relational import Rel
6
+ from sympy.core.symbol import symbols
7
+ from sympy.functions import sin
8
+ from sympy.integrals.integrals import Integral
9
+ from sympy.series.order import Order
10
+
11
+ from sympy.printing.precedence import precedence, PRECEDENCE
12
+
13
+ x, y = symbols("x,y")
14
+
15
+
16
+ def test_Add():
17
+ assert precedence(x + y) == PRECEDENCE["Add"]
18
+ assert precedence(x*y + 1) == PRECEDENCE["Add"]
19
+
20
+
21
+ def test_Function():
22
+ assert precedence(sin(x)) == PRECEDENCE["Func"]
23
+
24
+ def test_Derivative():
25
+ assert precedence(Derivative(x, y)) == PRECEDENCE["Atom"]
26
+
27
+ def test_Integral():
28
+ assert precedence(Integral(x, y)) == PRECEDENCE["Atom"]
29
+
30
+
31
+ def test_Mul():
32
+ assert precedence(x*y) == PRECEDENCE["Mul"]
33
+ assert precedence(-x*y) == PRECEDENCE["Add"]
34
+
35
+
36
+ def test_Number():
37
+ assert precedence(Integer(0)) == PRECEDENCE["Atom"]
38
+ assert precedence(Integer(1)) == PRECEDENCE["Atom"]
39
+ assert precedence(Integer(-1)) == PRECEDENCE["Add"]
40
+ assert precedence(Integer(10)) == PRECEDENCE["Atom"]
41
+ assert precedence(Rational(5, 2)) == PRECEDENCE["Mul"]
42
+ assert precedence(Rational(-5, 2)) == PRECEDENCE["Add"]
43
+ assert precedence(Float(5)) == PRECEDENCE["Atom"]
44
+ assert precedence(Float(-5)) == PRECEDENCE["Add"]
45
+ assert precedence(oo) == PRECEDENCE["Atom"]
46
+ assert precedence(-oo) == PRECEDENCE["Add"]
47
+
48
+
49
+ def test_Order():
50
+ assert precedence(Order(x)) == PRECEDENCE["Atom"]
51
+
52
+
53
+ def test_Pow():
54
+ assert precedence(x**y) == PRECEDENCE["Pow"]
55
+ assert precedence(-x**y) == PRECEDENCE["Add"]
56
+ assert precedence(x**-y) == PRECEDENCE["Pow"]
57
+
58
+
59
+ def test_Product():
60
+ assert precedence(Product(x, (x, y, y + 1))) == PRECEDENCE["Atom"]
61
+
62
+
63
+ def test_Relational():
64
+ assert precedence(Rel(x + y, y, "<")) == PRECEDENCE["Relational"]
65
+
66
+
67
+ def test_Sum():
68
+ assert precedence(Sum(x, (x, y, y + 1))) == PRECEDENCE["Atom"]
69
+
70
+
71
+ def test_Symbol():
72
+ assert precedence(x) == PRECEDENCE["Atom"]
73
+
74
+
75
+ def test_And_Or():
76
+ # precedence relations between logical operators, ...
77
+ assert precedence(x & y) > precedence(x | y)
78
+ assert precedence(~y) > precedence(x & y)
79
+ # ... and with other operators (cfr. other programming languages)
80
+ assert precedence(x + y) > precedence(x | y)
81
+ assert precedence(x + y) > precedence(x & y)
82
+ assert precedence(x*y) > precedence(x | y)
83
+ assert precedence(x*y) > precedence(x & y)
84
+ assert precedence(~y) > precedence(x*y)
85
+ assert precedence(~y) > precedence(x - y)
86
+ # double checks
87
+ assert precedence(x & y) == PRECEDENCE["And"]
88
+ assert precedence(x | y) == PRECEDENCE["Or"]
89
+ assert precedence(~y) == PRECEDENCE["Not"]
90
+
91
+
92
+ def test_custom_function_precedence_comparison():
93
+ """
94
+ Test cases for custom functions with different precedence values,
95
+ specifically handling:
96
+ 1. Functions with precedence < PRECEDENCE["Mul"] (50)
97
+ 2. Functions with precedence = Func (70)
98
+
99
+ Key distinction:
100
+ 1. Lower precedence functions (45) need parentheses: -2*(x F y)
101
+ 2. Higher precedence functions (70) don't: -2*x F y
102
+ """
103
+ class LowPrecedenceF(Function):
104
+ precedence = PRECEDENCE["Mul"] - 5
105
+ def _sympystr(self, printer):
106
+ return f"{printer._print(self.args[0])} F {printer._print(self.args[1])}"
107
+
108
+ class HighPrecedenceF(Function):
109
+ precedence = PRECEDENCE["Func"]
110
+ def _sympystr(self, printer):
111
+ return f"{printer._print(self.args[0])} F {printer._print(self.args[1])}"
112
+
113
+ def test_low_precedence():
114
+ expr1 = 2 * LowPrecedenceF(x, y)
115
+ assert str(expr1) == "2*(x F y)"
116
+
117
+ expr2 = -2 * LowPrecedenceF(x, y)
118
+ assert str(expr2) == "-2*(x F y)"
119
+
120
+ def test_high_precedence():
121
+ expr1 = 2 * HighPrecedenceF(x, y)
122
+ assert str(expr1) == "2*x F y"
123
+
124
+ expr2 = -2 * HighPrecedenceF(x, y)
125
+ assert str(expr2) == "-2*x F y"
126
+
127
+ test_low_precedence()
128
+ test_high_precedence()
outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_preview.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from sympy.core.relational import Eq
4
+ from sympy.core.symbol import Symbol
5
+ from sympy.functions.elementary.piecewise import Piecewise
6
+ from sympy.printing.preview import preview
7
+
8
+ from io import BytesIO
9
+
10
+
11
+ def test_preview():
12
+ x = Symbol('x')
13
+ obj = BytesIO()
14
+ try:
15
+ preview(x, output='png', viewer='BytesIO', outputbuffer=obj)
16
+ except RuntimeError:
17
+ pass # latex not installed on CI server
18
+
19
+
20
+ def test_preview_unicode_symbol():
21
+ # issue 9107
22
+ a = Symbol('α')
23
+ obj = BytesIO()
24
+ try:
25
+ preview(a, output='png', viewer='BytesIO', outputbuffer=obj)
26
+ except RuntimeError:
27
+ pass # latex not installed on CI server
28
+
29
+
30
+ def test_preview_latex_construct_in_expr():
31
+ # see PR 9801
32
+ x = Symbol('x')
33
+ pw = Piecewise((1, Eq(x, 0)), (0, True))
34
+ obj = BytesIO()
35
+ try:
36
+ preview(pw, output='png', viewer='BytesIO', outputbuffer=obj)
37
+ except RuntimeError:
38
+ pass # latex not installed on CI server
outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_pycode.py ADDED
@@ -0,0 +1,493 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy import Not
2
+ from sympy.codegen import Assignment
3
+ from sympy.codegen.ast import none
4
+ from sympy.codegen.cfunctions import expm1, log1p
5
+ from sympy.codegen.scipy_nodes import cosm1
6
+ from sympy.codegen.matrix_nodes import MatrixSolve
7
+ from sympy.core import Expr, Mod, symbols, Eq, Le, Gt, zoo, oo, Rational, Pow
8
+ from sympy.core.function import Derivative
9
+ from sympy.core.numbers import pi
10
+ from sympy.core.singleton import S
11
+ from sympy.functions import acos, KroneckerDelta, Piecewise, sign, sqrt, Min, Max, cot, acsch, asec, coth, sec, log, sin, cos, tan, asin, atan, sinh, cosh, tanh, asinh, acosh, atanh
12
+ from sympy.functions.elementary.trigonometric import atan2
13
+ from sympy.logic import And, Or
14
+ from sympy.matrices import SparseMatrix, MatrixSymbol, Identity
15
+ from sympy.printing.codeprinter import PrintMethodNotImplementedError
16
+ from sympy.printing.pycode import (
17
+ MpmathPrinter, CmathPrinter, PythonCodePrinter, pycode, SymPyPrinter
18
+ )
19
+ from sympy.printing.tensorflow import TensorflowPrinter
20
+ from sympy.printing.numpy import NumPyPrinter, SciPyPrinter
21
+ from sympy.testing.pytest import raises, skip
22
+ from sympy.tensor import IndexedBase, Idx
23
+ from sympy.tensor.array.expressions.array_expressions import ArraySymbol, ArrayDiagonal, ArrayContraction, ZeroArray, OneArray
24
+ from sympy.external import import_module
25
+ from sympy.functions.special.gamma_functions import loggamma
26
+
27
+
28
+
29
+ x, y, z = symbols('x y z')
30
+ p = IndexedBase("p")
31
+
32
+
33
+ def test_PythonCodePrinter():
34
+ prntr = PythonCodePrinter()
35
+
36
+ assert not prntr.module_imports
37
+
38
+ assert prntr.doprint(x**y) == 'x**y'
39
+ assert prntr.doprint(Mod(x, 2)) == 'x % 2'
40
+ assert prntr.doprint(-Mod(x, y)) == '-(x % y)'
41
+ assert prntr.doprint(Mod(-x, y)) == '(-x) % y'
42
+ assert prntr.doprint(And(x, y)) == 'x and y'
43
+ assert prntr.doprint(Or(x, y)) == 'x or y'
44
+ assert prntr.doprint(1/(x+y)) == '1/(x + y)'
45
+ assert prntr.doprint(Not(x)) == 'not x'
46
+ assert not prntr.module_imports
47
+
48
+ assert prntr.doprint(pi) == 'math.pi'
49
+ assert prntr.module_imports == {'math': {'pi'}}
50
+
51
+ assert prntr.doprint(x**Rational(1, 2)) == 'math.sqrt(x)'
52
+ assert prntr.doprint(sqrt(x)) == 'math.sqrt(x)'
53
+ assert prntr.module_imports == {'math': {'pi', 'sqrt'}}
54
+
55
+ assert prntr.doprint(acos(x)) == 'math.acos(x)'
56
+ assert prntr.doprint(cot(x)) == '(1/math.tan(x))'
57
+ assert prntr.doprint(coth(x)) == '((math.exp(x) + math.exp(-x))/(math.exp(x) - math.exp(-x)))'
58
+ assert prntr.doprint(asec(x)) == '(math.acos(1/x))'
59
+ assert prntr.doprint(acsch(x)) == '(math.log(math.sqrt(1 + x**(-2)) + 1/x))'
60
+
61
+ assert prntr.doprint(Assignment(x, 2)) == 'x = 2'
62
+ assert prntr.doprint(Piecewise((1, Eq(x, 0)),
63
+ (2, x>6))) == '((1) if (x == 0) else (2) if (x > 6) else None)'
64
+ assert prntr.doprint(Piecewise((2, Le(x, 0)),
65
+ (3, Gt(x, 0)), evaluate=False)) == '((2) if (x <= 0) else'\
66
+ ' (3) if (x > 0) else None)'
67
+ assert prntr.doprint(sign(x)) == '(0.0 if x == 0 else math.copysign(1, x))'
68
+ assert prntr.doprint(p[0, 1]) == 'p[0, 1]'
69
+ assert prntr.doprint(KroneckerDelta(x,y)) == '(1 if x == y else 0)'
70
+
71
+ assert prntr.doprint((2,3)) == "(2, 3)"
72
+ assert prntr.doprint([2,3]) == "[2, 3]"
73
+
74
+ assert prntr.doprint(Min(x, y)) == "min(x, y)"
75
+ assert prntr.doprint(Max(x, y)) == "max(x, y)"
76
+
77
+
78
+ def test_PythonCodePrinter_standard():
79
+ prntr = PythonCodePrinter()
80
+
81
+ assert prntr.standard == 'python3'
82
+
83
+ raises(ValueError, lambda: PythonCodePrinter({'standard':'python4'}))
84
+
85
+
86
+ def test_CmathPrinter():
87
+ p = CmathPrinter()
88
+
89
+ assert p.doprint(sqrt(x)) == 'cmath.sqrt(x)'
90
+ assert p.doprint(log(x)) == 'cmath.log(x)'
91
+
92
+ assert p.doprint(sin(x)) == 'cmath.sin(x)'
93
+ assert p.doprint(cos(x)) == 'cmath.cos(x)'
94
+ assert p.doprint(tan(x)) == 'cmath.tan(x)'
95
+
96
+ assert p.doprint(asin(x)) == 'cmath.asin(x)'
97
+ assert p.doprint(acos(x)) == 'cmath.acos(x)'
98
+ assert p.doprint(atan(x)) == 'cmath.atan(x)'
99
+
100
+ assert p.doprint(sinh(x)) == 'cmath.sinh(x)'
101
+ assert p.doprint(cosh(x)) == 'cmath.cosh(x)'
102
+ assert p.doprint(tanh(x)) == 'cmath.tanh(x)'
103
+
104
+ assert p.doprint(asinh(x)) == 'cmath.asinh(x)'
105
+ assert p.doprint(acosh(x)) == 'cmath.acosh(x)'
106
+ assert p.doprint(atanh(x)) == 'cmath.atanh(x)'
107
+
108
+
109
+ def test_MpmathPrinter():
110
+ p = MpmathPrinter()
111
+ assert p.doprint(sign(x)) == 'mpmath.sign(x)'
112
+ assert p.doprint(Rational(1, 2)) == 'mpmath.mpf(1)/mpmath.mpf(2)'
113
+
114
+ assert p.doprint(S.Exp1) == 'mpmath.e'
115
+ assert p.doprint(S.Pi) == 'mpmath.pi'
116
+ assert p.doprint(S.GoldenRatio) == 'mpmath.phi'
117
+ assert p.doprint(S.EulerGamma) == 'mpmath.euler'
118
+ assert p.doprint(S.NaN) == 'mpmath.nan'
119
+ assert p.doprint(S.Infinity) == 'mpmath.inf'
120
+ assert p.doprint(S.NegativeInfinity) == 'mpmath.ninf'
121
+ assert p.doprint(loggamma(x)) == 'mpmath.loggamma(x)'
122
+
123
+
124
+ def test_NumPyPrinter():
125
+ from sympy.core.function import Lambda
126
+ from sympy.matrices.expressions.adjoint import Adjoint
127
+ from sympy.matrices.expressions.diagonal import (DiagMatrix, DiagonalMatrix, DiagonalOf)
128
+ from sympy.matrices.expressions.funcmatrix import FunctionMatrix
129
+ from sympy.matrices.expressions.hadamard import HadamardProduct
130
+ from sympy.matrices.expressions.kronecker import KroneckerProduct
131
+ from sympy.matrices.expressions.special import (OneMatrix, ZeroMatrix)
132
+ from sympy.abc import a, b
133
+ p = NumPyPrinter()
134
+ assert p.doprint(sign(x)) == 'numpy.sign(x)'
135
+ A = MatrixSymbol("A", 2, 2)
136
+ B = MatrixSymbol("B", 2, 2)
137
+ C = MatrixSymbol("C", 1, 5)
138
+ D = MatrixSymbol("D", 3, 4)
139
+ assert p.doprint(A**(-1)) == "numpy.linalg.inv(A)"
140
+ assert p.doprint(A**5) == "numpy.linalg.matrix_power(A, 5)"
141
+ assert p.doprint(Identity(3)) == "numpy.eye(3)"
142
+
143
+ u = MatrixSymbol('x', 2, 1)
144
+ v = MatrixSymbol('y', 2, 1)
145
+ assert p.doprint(MatrixSolve(A, u)) == 'numpy.linalg.solve(A, x)'
146
+ assert p.doprint(MatrixSolve(A, u) + v) == 'numpy.linalg.solve(A, x) + y'
147
+
148
+ assert p.doprint(ZeroMatrix(2, 3)) == "numpy.zeros((2, 3))"
149
+ assert p.doprint(OneMatrix(2, 3)) == "numpy.ones((2, 3))"
150
+ assert p.doprint(FunctionMatrix(4, 5, Lambda((a, b), a + b))) == \
151
+ "numpy.fromfunction(lambda a, b: a + b, (4, 5))"
152
+ assert p.doprint(HadamardProduct(A, B)) == "numpy.multiply(A, B)"
153
+ assert p.doprint(KroneckerProduct(A, B)) == "numpy.kron(A, B)"
154
+ assert p.doprint(Adjoint(A)) == "numpy.conjugate(numpy.transpose(A))"
155
+ assert p.doprint(DiagonalOf(A)) == "numpy.reshape(numpy.diag(A), (-1, 1))"
156
+ assert p.doprint(DiagMatrix(C)) == "numpy.diagflat(C)"
157
+ assert p.doprint(DiagonalMatrix(D)) == "numpy.multiply(D, numpy.eye(3, 4))"
158
+
159
+ # Workaround for numpy negative integer power errors
160
+ assert p.doprint(x**-1) == 'x**(-1.0)'
161
+ assert p.doprint(x**-2) == 'x**(-2.0)'
162
+
163
+ expr = Pow(2, -1, evaluate=False)
164
+ assert p.doprint(expr) == "2**(-1.0)"
165
+
166
+ assert p.doprint(S.Exp1) == 'numpy.e'
167
+ assert p.doprint(S.Pi) == 'numpy.pi'
168
+ assert p.doprint(S.EulerGamma) == 'numpy.euler_gamma'
169
+ assert p.doprint(S.NaN) == 'numpy.nan'
170
+ assert p.doprint(S.Infinity) == 'numpy.inf'
171
+ assert p.doprint(S.NegativeInfinity) == '-numpy.inf'
172
+
173
+ # Function rewriting operator precedence fix
174
+ assert p.doprint(sec(x)**2) == '(numpy.cos(x)**(-1.0))**2'
175
+
176
+
177
+ def test_issue_18770():
178
+ numpy = import_module('numpy')
179
+ if not numpy:
180
+ skip("numpy not installed.")
181
+
182
+ from sympy.functions.elementary.miscellaneous import (Max, Min)
183
+ from sympy.utilities.lambdify import lambdify
184
+
185
+ expr1 = Min(0.1*x + 3, x + 1, 0.5*x + 1)
186
+ func = lambdify(x, expr1, "numpy")
187
+ assert (func(numpy.linspace(0, 3, 3)) == [1.0, 1.75, 2.5 ]).all()
188
+ assert func(4) == 3
189
+
190
+ expr1 = Max(x**2, x**3)
191
+ func = lambdify(x,expr1, "numpy")
192
+ assert (func(numpy.linspace(-1, 2, 4)) == [1, 0, 1, 8] ).all()
193
+ assert func(4) == 64
194
+
195
+
196
+ def test_SciPyPrinter():
197
+ p = SciPyPrinter()
198
+ expr = acos(x)
199
+ assert 'numpy' not in p.module_imports
200
+ assert p.doprint(expr) == 'numpy.arccos(x)'
201
+ assert 'numpy' in p.module_imports
202
+ assert not any(m.startswith('scipy') for m in p.module_imports)
203
+ smat = SparseMatrix(2, 5, {(0, 1): 3})
204
+ assert p.doprint(smat) == \
205
+ 'scipy.sparse.coo_matrix(([3], ([0], [1])), shape=(2, 5))'
206
+ assert 'scipy.sparse' in p.module_imports
207
+
208
+ assert p.doprint(S.GoldenRatio) == 'scipy.constants.golden_ratio'
209
+ assert p.doprint(S.Pi) == 'scipy.constants.pi'
210
+ assert p.doprint(S.Exp1) == 'numpy.e'
211
+
212
+
213
+ def test_pycode_reserved_words():
214
+ s1, s2 = symbols('if else')
215
+ raises(ValueError, lambda: pycode(s1 + s2, error_on_reserved=True))
216
+ py_str = pycode(s1 + s2)
217
+ assert py_str in ('else_ + if_', 'if_ + else_')
218
+
219
+
220
+ def test_issue_20762():
221
+ # Make sure pycode removes curly braces from subscripted variables
222
+ a_b, b, a_11 = symbols('a_{b} b a_{11}')
223
+ expr = a_b*b
224
+ assert pycode(expr) == 'a_b*b'
225
+ expr = a_11*b
226
+ assert pycode(expr) == 'a_11*b'
227
+
228
+
229
+ def test_sqrt():
230
+ prntr = PythonCodePrinter()
231
+ assert prntr._print_Pow(sqrt(x), rational=False) == 'math.sqrt(x)'
232
+ assert prntr._print_Pow(1/sqrt(x), rational=False) == '1/math.sqrt(x)'
233
+
234
+ prntr = PythonCodePrinter({'standard' : 'python3'})
235
+ assert prntr._print_Pow(sqrt(x), rational=True) == 'x**(1/2)'
236
+ assert prntr._print_Pow(1/sqrt(x), rational=True) == 'x**(-1/2)'
237
+
238
+ prntr = MpmathPrinter()
239
+ assert prntr._print_Pow(sqrt(x), rational=False) == 'mpmath.sqrt(x)'
240
+ assert prntr._print_Pow(sqrt(x), rational=True) == \
241
+ "x**(mpmath.mpf(1)/mpmath.mpf(2))"
242
+
243
+ prntr = NumPyPrinter()
244
+ assert prntr._print_Pow(sqrt(x), rational=False) == 'numpy.sqrt(x)'
245
+ assert prntr._print_Pow(sqrt(x), rational=True) == 'x**(1/2)'
246
+
247
+ prntr = SciPyPrinter()
248
+ assert prntr._print_Pow(sqrt(x), rational=False) == 'numpy.sqrt(x)'
249
+ assert prntr._print_Pow(sqrt(x), rational=True) == 'x**(1/2)'
250
+
251
+ prntr = SymPyPrinter()
252
+ assert prntr._print_Pow(sqrt(x), rational=False) == 'sympy.sqrt(x)'
253
+ assert prntr._print_Pow(sqrt(x), rational=True) == 'x**(1/2)'
254
+
255
+
256
+ def test_frac():
257
+ from sympy.functions.elementary.integers import frac
258
+
259
+ expr = frac(x)
260
+ prntr = NumPyPrinter()
261
+ assert prntr.doprint(expr) == 'numpy.mod(x, 1)'
262
+
263
+ prntr = SciPyPrinter()
264
+ assert prntr.doprint(expr) == 'numpy.mod(x, 1)'
265
+
266
+ prntr = PythonCodePrinter()
267
+ assert prntr.doprint(expr) == 'x % 1'
268
+
269
+ prntr = MpmathPrinter()
270
+ assert prntr.doprint(expr) == 'mpmath.frac(x)'
271
+
272
+ prntr = SymPyPrinter()
273
+ assert prntr.doprint(expr) == 'sympy.functions.elementary.integers.frac(x)'
274
+
275
+
276
+ class CustomPrintedObject(Expr):
277
+ def _numpycode(self, printer):
278
+ return 'numpy'
279
+
280
+ def _mpmathcode(self, printer):
281
+ return 'mpmath'
282
+
283
+
284
+ def test_printmethod():
285
+ obj = CustomPrintedObject()
286
+ assert NumPyPrinter().doprint(obj) == 'numpy'
287
+ assert MpmathPrinter().doprint(obj) == 'mpmath'
288
+
289
+
290
+ def test_codegen_ast_nodes():
291
+ assert pycode(none) == 'None'
292
+
293
+
294
+ def test_issue_14283():
295
+ prntr = PythonCodePrinter()
296
+
297
+ assert prntr.doprint(zoo) == "math.nan"
298
+ assert prntr.doprint(-oo) == "float('-inf')"
299
+
300
+
301
+ def test_NumPyPrinter_print_seq():
302
+ n = NumPyPrinter()
303
+
304
+ assert n._print_seq(range(2)) == '(0, 1,)'
305
+
306
+
307
+ def test_issue_16535_16536():
308
+ from sympy.functions.special.gamma_functions import (lowergamma, uppergamma)
309
+
310
+ a = symbols('a')
311
+ expr1 = lowergamma(a, x)
312
+ expr2 = uppergamma(a, x)
313
+
314
+ prntr = SciPyPrinter()
315
+ assert prntr.doprint(expr1) == 'scipy.special.gamma(a)*scipy.special.gammainc(a, x)'
316
+ assert prntr.doprint(expr2) == 'scipy.special.gamma(a)*scipy.special.gammaincc(a, x)'
317
+
318
+ p_numpy = NumPyPrinter()
319
+ p_pycode = PythonCodePrinter({'strict': False})
320
+
321
+ for expr in [expr1, expr2]:
322
+ with raises(NotImplementedError):
323
+ p_numpy.doprint(expr1)
324
+ assert "Not supported" in p_pycode.doprint(expr)
325
+
326
+
327
+ def test_Integral():
328
+ from sympy.functions.elementary.exponential import exp
329
+ from sympy.integrals.integrals import Integral
330
+
331
+ single = Integral(exp(-x), (x, 0, oo))
332
+ double = Integral(x**2*exp(x*y), (x, -z, z), (y, 0, z))
333
+ indefinite = Integral(x**2, x)
334
+ evaluateat = Integral(x**2, (x, 1))
335
+
336
+ prntr = SciPyPrinter()
337
+ assert prntr.doprint(single) == 'scipy.integrate.quad(lambda x: numpy.exp(-x), 0, numpy.inf)[0]'
338
+ assert prntr.doprint(double) == 'scipy.integrate.nquad(lambda x, y: x**2*numpy.exp(x*y), ((-z, z), (0, z)))[0]'
339
+ raises(NotImplementedError, lambda: prntr.doprint(indefinite))
340
+ raises(NotImplementedError, lambda: prntr.doprint(evaluateat))
341
+
342
+ prntr = MpmathPrinter()
343
+ assert prntr.doprint(single) == 'mpmath.quad(lambda x: mpmath.exp(-x), (0, mpmath.inf))'
344
+ assert prntr.doprint(double) == 'mpmath.quad(lambda x, y: x**2*mpmath.exp(x*y), (-z, z), (0, z))'
345
+ raises(NotImplementedError, lambda: prntr.doprint(indefinite))
346
+ raises(NotImplementedError, lambda: prntr.doprint(evaluateat))
347
+
348
+
349
+ def test_fresnel_integrals():
350
+ from sympy.functions.special.error_functions import (fresnelc, fresnels)
351
+
352
+ expr1 = fresnelc(x)
353
+ expr2 = fresnels(x)
354
+
355
+ prntr = SciPyPrinter()
356
+ assert prntr.doprint(expr1) == 'scipy.special.fresnel(x)[1]'
357
+ assert prntr.doprint(expr2) == 'scipy.special.fresnel(x)[0]'
358
+
359
+ p_numpy = NumPyPrinter()
360
+ p_pycode = PythonCodePrinter()
361
+ p_mpmath = MpmathPrinter()
362
+ for expr in [expr1, expr2]:
363
+ with raises(NotImplementedError):
364
+ p_numpy.doprint(expr)
365
+ with raises(NotImplementedError):
366
+ p_pycode.doprint(expr)
367
+
368
+ assert p_mpmath.doprint(expr1) == 'mpmath.fresnelc(x)'
369
+ assert p_mpmath.doprint(expr2) == 'mpmath.fresnels(x)'
370
+
371
+
372
+ def test_beta():
373
+ from sympy.functions.special.beta_functions import beta
374
+
375
+ expr = beta(x, y)
376
+
377
+ prntr = SciPyPrinter()
378
+ assert prntr.doprint(expr) == 'scipy.special.beta(x, y)'
379
+
380
+ prntr = NumPyPrinter()
381
+ assert prntr.doprint(expr) == '(math.gamma(x)*math.gamma(y)/math.gamma(x + y))'
382
+
383
+ prntr = PythonCodePrinter()
384
+ assert prntr.doprint(expr) == '(math.gamma(x)*math.gamma(y)/math.gamma(x + y))'
385
+
386
+ prntr = PythonCodePrinter({'allow_unknown_functions': True})
387
+ assert prntr.doprint(expr) == '(math.gamma(x)*math.gamma(y)/math.gamma(x + y))'
388
+
389
+ prntr = MpmathPrinter()
390
+ assert prntr.doprint(expr) == 'mpmath.beta(x, y)'
391
+
392
+ def test_airy():
393
+ from sympy.functions.special.bessel import (airyai, airybi)
394
+
395
+ expr1 = airyai(x)
396
+ expr2 = airybi(x)
397
+
398
+ prntr = SciPyPrinter()
399
+ assert prntr.doprint(expr1) == 'scipy.special.airy(x)[0]'
400
+ assert prntr.doprint(expr2) == 'scipy.special.airy(x)[2]'
401
+
402
+ prntr = NumPyPrinter({'strict': False})
403
+ assert "Not supported" in prntr.doprint(expr1)
404
+ assert "Not supported" in prntr.doprint(expr2)
405
+
406
+ prntr = PythonCodePrinter({'strict': False})
407
+ assert "Not supported" in prntr.doprint(expr1)
408
+ assert "Not supported" in prntr.doprint(expr2)
409
+
410
+ def test_airy_prime():
411
+ from sympy.functions.special.bessel import (airyaiprime, airybiprime)
412
+
413
+ expr1 = airyaiprime(x)
414
+ expr2 = airybiprime(x)
415
+
416
+ prntr = SciPyPrinter()
417
+ assert prntr.doprint(expr1) == 'scipy.special.airy(x)[1]'
418
+ assert prntr.doprint(expr2) == 'scipy.special.airy(x)[3]'
419
+
420
+ prntr = NumPyPrinter({'strict': False})
421
+ assert "Not supported" in prntr.doprint(expr1)
422
+ assert "Not supported" in prntr.doprint(expr2)
423
+
424
+ prntr = PythonCodePrinter({'strict': False})
425
+ assert "Not supported" in prntr.doprint(expr1)
426
+ assert "Not supported" in prntr.doprint(expr2)
427
+
428
+
429
+ def test_numerical_accuracy_functions():
430
+ prntr = SciPyPrinter()
431
+ assert prntr.doprint(expm1(x)) == 'numpy.expm1(x)'
432
+ assert prntr.doprint(log1p(x)) == 'numpy.log1p(x)'
433
+ assert prntr.doprint(cosm1(x)) == 'scipy.special.cosm1(x)'
434
+
435
+ def test_array_printer():
436
+ A = ArraySymbol('A', (4,4,6,6,6))
437
+ I = IndexedBase('I')
438
+ i,j,k = Idx('i', (0,1)), Idx('j', (2,3)), Idx('k', (4,5))
439
+
440
+ prntr = NumPyPrinter()
441
+ assert prntr.doprint(ZeroArray(5)) == 'numpy.zeros((5,))'
442
+ assert prntr.doprint(OneArray(5)) == 'numpy.ones((5,))'
443
+ assert prntr.doprint(ArrayContraction(A, [2,3])) == 'numpy.einsum("abccd->abd", A)'
444
+ assert prntr.doprint(I) == 'I'
445
+ assert prntr.doprint(ArrayDiagonal(A, [2,3,4])) == 'numpy.einsum("abccc->abc", A)'
446
+ assert prntr.doprint(ArrayDiagonal(A, [0,1], [2,3])) == 'numpy.einsum("aabbc->cab", A)'
447
+ assert prntr.doprint(ArrayContraction(A, [2], [3])) == 'numpy.einsum("abcde->abe", A)'
448
+ assert prntr.doprint(Assignment(I[i,j,k], I[i,j,k])) == 'I = I'
449
+
450
+ prntr = TensorflowPrinter()
451
+ assert prntr.doprint(ZeroArray(5)) == 'tensorflow.zeros((5,))'
452
+ assert prntr.doprint(OneArray(5)) == 'tensorflow.ones((5,))'
453
+ assert prntr.doprint(ArrayContraction(A, [2,3])) == 'tensorflow.linalg.einsum("abccd->abd", A)'
454
+ assert prntr.doprint(I) == 'I'
455
+ assert prntr.doprint(ArrayDiagonal(A, [2,3,4])) == 'tensorflow.linalg.einsum("abccc->abc", A)'
456
+ assert prntr.doprint(ArrayDiagonal(A, [0,1], [2,3])) == 'tensorflow.linalg.einsum("aabbc->cab", A)'
457
+ assert prntr.doprint(ArrayContraction(A, [2], [3])) == 'tensorflow.linalg.einsum("abcde->abe", A)'
458
+ assert prntr.doprint(Assignment(I[i,j,k], I[i,j,k])) == 'I = I'
459
+
460
+
461
+ def test_custom_Derivative_methods():
462
+ class MyPrinter(SciPyPrinter):
463
+ def _print_Derivative_cosm1(self, args, seq_orders):
464
+ arg, = args
465
+ order, = seq_orders
466
+ return 'my_custom_cosm1(%s, deriv_order=%d)' % (self._print(arg), order)
467
+
468
+ def _print_Derivative_atan2(self, args, seq_orders):
469
+ arg1, arg2 = args
470
+ ord1, ord2 = seq_orders
471
+ return 'my_custom_atan2(%s, %s, deriv1=%d, deriv2=%d)' % (
472
+ self._print(arg1), self._print(arg2), ord1, ord2
473
+ )
474
+
475
+ p = MyPrinter()
476
+ cosm1_1 = cosm1(x).diff(x, evaluate=False)
477
+ assert p.doprint(cosm1_1) == 'my_custom_cosm1(x, deriv_order=1)'
478
+ atan2_2_3 = atan2(x, y).diff(x, 2, y, 3, evaluate=False)
479
+ assert p.doprint(atan2_2_3) == 'my_custom_atan2(x, y, deriv1=2, deriv2=3)'
480
+
481
+ try:
482
+ p.doprint(expm1(x).diff(x, evaluate=False))
483
+ except PrintMethodNotImplementedError as e:
484
+ assert '_print_Derivative_expm1' in repr(e)
485
+ else:
486
+ assert False # should have thrown
487
+
488
+ try:
489
+ p.doprint(Derivative(cosm1(x**2),x))
490
+ except ValueError as e:
491
+ assert '_print_Derivative(' in repr(e)
492
+ else:
493
+ assert False # should have thrown
outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_python.py ADDED
@@ -0,0 +1,203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.function import (Derivative, Function)
2
+ from sympy.core.numbers import (I, Rational, oo, pi)
3
+ from sympy.core.relational import (Eq, Ge, Gt, Le, Lt, Ne)
4
+ from sympy.core.symbol import (Symbol, symbols)
5
+ from sympy.functions.elementary.complexes import (Abs, conjugate)
6
+ from sympy.functions.elementary.exponential import (exp, log)
7
+ from sympy.functions.elementary.miscellaneous import sqrt
8
+ from sympy.functions.elementary.trigonometric import sin
9
+ from sympy.integrals.integrals import Integral
10
+ from sympy.matrices.dense import Matrix
11
+ from sympy.series.limits import limit
12
+
13
+ from sympy.printing.python import python
14
+
15
+ from sympy.testing.pytest import raises, XFAIL
16
+
17
+ x, y = symbols('x,y')
18
+ th = Symbol('theta')
19
+ ph = Symbol('phi')
20
+
21
+
22
+ def test_python_basic():
23
+ # Simple numbers/symbols
24
+ assert python(-Rational(1)/2) == "e = Rational(-1, 2)"
25
+ assert python(-Rational(13)/22) == "e = Rational(-13, 22)"
26
+ assert python(oo) == "e = oo"
27
+
28
+ # Powers
29
+ assert python(x**2) == "x = Symbol(\'x\')\ne = x**2"
30
+ assert python(1/x) == "x = Symbol('x')\ne = 1/x"
31
+ assert python(y*x**-2) == "y = Symbol('y')\nx = Symbol('x')\ne = y/x**2"
32
+ assert python(
33
+ x**Rational(-5, 2)) == "x = Symbol('x')\ne = x**Rational(-5, 2)"
34
+
35
+ # Sums of terms
36
+ assert python(x**2 + x + 1) in [
37
+ "x = Symbol('x')\ne = 1 + x + x**2",
38
+ "x = Symbol('x')\ne = x + x**2 + 1",
39
+ "x = Symbol('x')\ne = x**2 + x + 1", ]
40
+ assert python(1 - x) in [
41
+ "x = Symbol('x')\ne = 1 - x",
42
+ "x = Symbol('x')\ne = -x + 1"]
43
+ assert python(1 - 2*x) in [
44
+ "x = Symbol('x')\ne = 1 - 2*x",
45
+ "x = Symbol('x')\ne = -2*x + 1"]
46
+ assert python(1 - Rational(3, 2)*y/x) in [
47
+ "y = Symbol('y')\nx = Symbol('x')\ne = 1 - 3/2*y/x",
48
+ "y = Symbol('y')\nx = Symbol('x')\ne = -3/2*y/x + 1",
49
+ "y = Symbol('y')\nx = Symbol('x')\ne = 1 - 3*y/(2*x)"]
50
+
51
+ # Multiplication
52
+ assert python(x/y) == "x = Symbol('x')\ny = Symbol('y')\ne = x/y"
53
+ assert python(-x/y) == "x = Symbol('x')\ny = Symbol('y')\ne = -x/y"
54
+ assert python((x + 2)/y) in [
55
+ "y = Symbol('y')\nx = Symbol('x')\ne = 1/y*(2 + x)",
56
+ "y = Symbol('y')\nx = Symbol('x')\ne = 1/y*(x + 2)",
57
+ "x = Symbol('x')\ny = Symbol('y')\ne = 1/y*(2 + x)",
58
+ "x = Symbol('x')\ny = Symbol('y')\ne = (2 + x)/y",
59
+ "x = Symbol('x')\ny = Symbol('y')\ne = (x + 2)/y"]
60
+ assert python((1 + x)*y) in [
61
+ "y = Symbol('y')\nx = Symbol('x')\ne = y*(1 + x)",
62
+ "y = Symbol('y')\nx = Symbol('x')\ne = y*(x + 1)", ]
63
+
64
+ # Check for proper placement of negative sign
65
+ assert python(-5*x/(x + 10)) == "x = Symbol('x')\ne = -5*x/(x + 10)"
66
+ assert python(1 - Rational(3, 2)*(x + 1)) in [
67
+ "x = Symbol('x')\ne = Rational(-3, 2)*x + Rational(-1, 2)",
68
+ "x = Symbol('x')\ne = -3*x/2 + Rational(-1, 2)",
69
+ "x = Symbol('x')\ne = -3*x/2 + Rational(-1, 2)"
70
+ ]
71
+
72
+
73
+ def test_python_keyword_symbol_name_escaping():
74
+ # Check for escaping of keywords
75
+ assert python(
76
+ 5*Symbol("lambda")) == "lambda_ = Symbol('lambda')\ne = 5*lambda_"
77
+ assert (python(5*Symbol("lambda") + 7*Symbol("lambda_")) ==
78
+ "lambda__ = Symbol('lambda')\nlambda_ = Symbol('lambda_')\ne = 7*lambda_ + 5*lambda__")
79
+ assert (python(5*Symbol("for") + Function("for_")(8)) ==
80
+ "for__ = Symbol('for')\nfor_ = Function('for_')\ne = 5*for__ + for_(8)")
81
+
82
+
83
+ def test_python_keyword_function_name_escaping():
84
+ assert python(
85
+ 5*Function("for")(8)) == "for_ = Function('for')\ne = 5*for_(8)"
86
+
87
+
88
+ def test_python_relational():
89
+ assert python(Eq(x, y)) == "x = Symbol('x')\ny = Symbol('y')\ne = Eq(x, y)"
90
+ assert python(Ge(x, y)) == "x = Symbol('x')\ny = Symbol('y')\ne = x >= y"
91
+ assert python(Le(x, y)) == "x = Symbol('x')\ny = Symbol('y')\ne = x <= y"
92
+ assert python(Gt(x, y)) == "x = Symbol('x')\ny = Symbol('y')\ne = x > y"
93
+ assert python(Lt(x, y)) == "x = Symbol('x')\ny = Symbol('y')\ne = x < y"
94
+ assert python(Ne(x/(y + 1), y**2)) in [
95
+ "x = Symbol('x')\ny = Symbol('y')\ne = Ne(x/(1 + y), y**2)",
96
+ "x = Symbol('x')\ny = Symbol('y')\ne = Ne(x/(y + 1), y**2)"]
97
+
98
+
99
+ def test_python_functions():
100
+ # Simple
101
+ assert python(2*x + exp(x)) in "x = Symbol('x')\ne = 2*x + exp(x)"
102
+ assert python(sqrt(2)) == 'e = sqrt(2)'
103
+ assert python(2**Rational(1, 3)) == 'e = 2**Rational(1, 3)'
104
+ assert python(sqrt(2 + pi)) == 'e = sqrt(2 + pi)'
105
+ assert python((2 + pi)**Rational(1, 3)) == 'e = (2 + pi)**Rational(1, 3)'
106
+ assert python(2**Rational(1, 4)) == 'e = 2**Rational(1, 4)'
107
+ assert python(Abs(x)) == "x = Symbol('x')\ne = Abs(x)"
108
+ assert python(
109
+ Abs(x/(x**2 + 1))) in ["x = Symbol('x')\ne = Abs(x/(1 + x**2))",
110
+ "x = Symbol('x')\ne = Abs(x/(x**2 + 1))"]
111
+
112
+ # Univariate/Multivariate functions
113
+ f = Function('f')
114
+ assert python(f(x)) == "x = Symbol('x')\nf = Function('f')\ne = f(x)"
115
+ assert python(f(x, y)) == "x = Symbol('x')\ny = Symbol('y')\nf = Function('f')\ne = f(x, y)"
116
+ assert python(f(x/(y + 1), y)) in [
117
+ "x = Symbol('x')\ny = Symbol('y')\nf = Function('f')\ne = f(x/(1 + y), y)",
118
+ "x = Symbol('x')\ny = Symbol('y')\nf = Function('f')\ne = f(x/(y + 1), y)"]
119
+
120
+ # Nesting of square roots
121
+ assert python(sqrt((sqrt(x + 1)) + 1)) in [
122
+ "x = Symbol('x')\ne = sqrt(1 + sqrt(1 + x))",
123
+ "x = Symbol('x')\ne = sqrt(sqrt(x + 1) + 1)"]
124
+
125
+ # Nesting of powers
126
+ assert python((((x + 1)**Rational(1, 3)) + 1)**Rational(1, 3)) in [
127
+ "x = Symbol('x')\ne = (1 + (1 + x)**Rational(1, 3))**Rational(1, 3)",
128
+ "x = Symbol('x')\ne = ((x + 1)**Rational(1, 3) + 1)**Rational(1, 3)"]
129
+
130
+ # Function powers
131
+ assert python(sin(x)**2) == "x = Symbol('x')\ne = sin(x)**2"
132
+
133
+
134
+ @XFAIL
135
+ def test_python_functions_conjugates():
136
+ a, b = map(Symbol, 'ab')
137
+ assert python( conjugate(a + b*I) ) == '_ _\na - I*b'
138
+ assert python( conjugate(exp(a + b*I)) ) == ' _ _\n a - I*b\ne '
139
+
140
+
141
+ def test_python_derivatives():
142
+ # Simple
143
+ f_1 = Derivative(log(x), x, evaluate=False)
144
+ assert python(f_1) == "x = Symbol('x')\ne = Derivative(log(x), x)"
145
+
146
+ f_2 = Derivative(log(x), x, evaluate=False) + x
147
+ assert python(f_2) == "x = Symbol('x')\ne = x + Derivative(log(x), x)"
148
+
149
+ # Multiple symbols
150
+ f_3 = Derivative(log(x) + x**2, x, y, evaluate=False)
151
+ assert python(f_3) == \
152
+ "x = Symbol('x')\ny = Symbol('y')\ne = Derivative(x**2 + log(x), x, y)"
153
+
154
+ f_4 = Derivative(2*x*y, y, x, evaluate=False) + x**2
155
+ assert python(f_4) in [
156
+ "x = Symbol('x')\ny = Symbol('y')\ne = x**2 + Derivative(2*x*y, y, x)",
157
+ "x = Symbol('x')\ny = Symbol('y')\ne = Derivative(2*x*y, y, x) + x**2"]
158
+
159
+
160
+ def test_python_integrals():
161
+ # Simple
162
+ f_1 = Integral(log(x), x)
163
+ assert python(f_1) == "x = Symbol('x')\ne = Integral(log(x), x)"
164
+
165
+ f_2 = Integral(x**2, x)
166
+ assert python(f_2) == "x = Symbol('x')\ne = Integral(x**2, x)"
167
+
168
+ # Double nesting of pow
169
+ f_3 = Integral(x**(2**x), x)
170
+ assert python(f_3) == "x = Symbol('x')\ne = Integral(x**(2**x), x)"
171
+
172
+ # Definite integrals
173
+ f_4 = Integral(x**2, (x, 1, 2))
174
+ assert python(f_4) == "x = Symbol('x')\ne = Integral(x**2, (x, 1, 2))"
175
+
176
+ f_5 = Integral(x**2, (x, Rational(1, 2), 10))
177
+ assert python(
178
+ f_5) == "x = Symbol('x')\ne = Integral(x**2, (x, Rational(1, 2), 10))"
179
+
180
+ # Nested integrals
181
+ f_6 = Integral(x**2*y**2, x, y)
182
+ assert python(f_6) == "x = Symbol('x')\ny = Symbol('y')\ne = Integral(x**2*y**2, x, y)"
183
+
184
+
185
+ def test_python_matrix():
186
+ p = python(Matrix([[x**2+1, 1], [y, x+y]]))
187
+ s = "x = Symbol('x')\ny = Symbol('y')\ne = MutableDenseMatrix([[x**2 + 1, 1], [y, x + y]])"
188
+ assert p == s
189
+
190
+ def test_python_limits():
191
+ assert python(limit(x, x, oo)) == 'e = oo'
192
+ assert python(limit(x**2, x, 0)) == 'e = 0'
193
+
194
+ def test_issue_20762():
195
+ # Make sure Python removes curly braces from subscripted variables
196
+ a_b = Symbol('a_{b}')
197
+ b = Symbol('b')
198
+ expr = a_b*b
199
+ assert python(expr) == "a_b = Symbol('a_{b}')\nb = Symbol('b')\ne = a_b*b"
200
+
201
+
202
+ def test_settings():
203
+ raises(TypeError, lambda: python(x, method="garbage"))
outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_rcode.py ADDED
@@ -0,0 +1,476 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core import (S, pi, oo, Symbol, symbols, Rational, Integer,
2
+ GoldenRatio, EulerGamma, Catalan, Lambda, Dummy)
3
+ from sympy.functions import (Piecewise, sin, cos, Abs, exp, ceiling, sqrt,
4
+ gamma, sign, Max, Min, factorial, beta)
5
+ from sympy.core.relational import (Eq, Ge, Gt, Le, Lt, Ne)
6
+ from sympy.sets import Range
7
+ from sympy.logic import ITE
8
+ from sympy.codegen import For, aug_assign, Assignment
9
+ from sympy.testing.pytest import raises
10
+ from sympy.printing.rcode import RCodePrinter
11
+ from sympy.utilities.lambdify import implemented_function
12
+ from sympy.tensor import IndexedBase, Idx
13
+ from sympy.matrices import Matrix, MatrixSymbol
14
+
15
+ from sympy.printing.rcode import rcode
16
+
17
+ x, y, z = symbols('x,y,z')
18
+
19
+
20
+ def test_printmethod():
21
+ class fabs(Abs):
22
+ def _rcode(self, printer):
23
+ return "abs(%s)" % printer._print(self.args[0])
24
+
25
+ assert rcode(fabs(x)) == "abs(x)"
26
+
27
+
28
+ def test_rcode_sqrt():
29
+ assert rcode(sqrt(x)) == "sqrt(x)"
30
+ assert rcode(x**0.5) == "sqrt(x)"
31
+ assert rcode(sqrt(x)) == "sqrt(x)"
32
+
33
+
34
+ def test_rcode_Pow():
35
+ assert rcode(x**3) == "x^3"
36
+ assert rcode(x**(y**3)) == "x^(y^3)"
37
+ g = implemented_function('g', Lambda(x, 2*x))
38
+ assert rcode(1/(g(x)*3.5)**(x - y**x)/(x**2 + y)) == \
39
+ "(3.5*2*x)^(-x + y^x)/(x^2 + y)"
40
+ assert rcode(x**-1.0) == '1.0/x'
41
+ assert rcode(x**Rational(2, 3)) == 'x^(2.0/3.0)'
42
+ _cond_cfunc = [(lambda base, exp: exp.is_integer, "dpowi"),
43
+ (lambda base, exp: not exp.is_integer, "pow")]
44
+ assert rcode(x**3, user_functions={'Pow': _cond_cfunc}) == 'dpowi(x, 3)'
45
+ assert rcode(x**3.2, user_functions={'Pow': _cond_cfunc}) == 'pow(x, 3.2)'
46
+
47
+
48
+ def test_rcode_Max():
49
+ # Test for gh-11926
50
+ assert rcode(Max(x,x*x),user_functions={"Max":"my_max", "Pow":"my_pow"}) == 'my_max(x, my_pow(x, 2))'
51
+
52
+
53
+ def test_rcode_constants_mathh():
54
+ assert rcode(exp(1)) == "exp(1)"
55
+ assert rcode(pi) == "pi"
56
+ assert rcode(oo) == "Inf"
57
+ assert rcode(-oo) == "-Inf"
58
+
59
+
60
+ def test_rcode_constants_other():
61
+ assert rcode(2*GoldenRatio) == "GoldenRatio = 1.61803398874989;\n2*GoldenRatio"
62
+ assert rcode(
63
+ 2*Catalan) == "Catalan = 0.915965594177219;\n2*Catalan"
64
+ assert rcode(2*EulerGamma) == "EulerGamma = 0.577215664901533;\n2*EulerGamma"
65
+
66
+
67
+ def test_rcode_Rational():
68
+ assert rcode(Rational(3, 7)) == "3.0/7.0"
69
+ assert rcode(Rational(18, 9)) == "2"
70
+ assert rcode(Rational(3, -7)) == "-3.0/7.0"
71
+ assert rcode(Rational(-3, -7)) == "3.0/7.0"
72
+ assert rcode(x + Rational(3, 7)) == "x + 3.0/7.0"
73
+ assert rcode(Rational(3, 7)*x) == "(3.0/7.0)*x"
74
+
75
+
76
+ def test_rcode_Integer():
77
+ assert rcode(Integer(67)) == "67"
78
+ assert rcode(Integer(-1)) == "-1"
79
+
80
+
81
+ def test_rcode_functions():
82
+ assert rcode(sin(x) ** cos(x)) == "sin(x)^cos(x)"
83
+ assert rcode(factorial(x) + gamma(y)) == "factorial(x) + gamma(y)"
84
+ assert rcode(beta(Min(x, y), Max(x, y))) == "beta(min(x, y), max(x, y))"
85
+
86
+
87
+ def test_rcode_inline_function():
88
+ x = symbols('x')
89
+ g = implemented_function('g', Lambda(x, 2*x))
90
+ assert rcode(g(x)) == "2*x"
91
+ g = implemented_function('g', Lambda(x, 2*x/Catalan))
92
+ assert rcode(
93
+ g(x)) == "Catalan = %s;\n2*x/Catalan" % Catalan.n()
94
+ A = IndexedBase('A')
95
+ i = Idx('i', symbols('n', integer=True))
96
+ g = implemented_function('g', Lambda(x, x*(1 + x)*(2 + x)))
97
+ res=rcode(g(A[i]), assign_to=A[i])
98
+ ref=(
99
+ "for (i in 1:n){\n"
100
+ " A[i] = (A[i] + 1)*(A[i] + 2)*A[i];\n"
101
+ "}"
102
+ )
103
+ assert res == ref
104
+
105
+
106
+ def test_rcode_exceptions():
107
+ assert rcode(ceiling(x)) == "ceiling(x)"
108
+ assert rcode(Abs(x)) == "abs(x)"
109
+ assert rcode(gamma(x)) == "gamma(x)"
110
+
111
+
112
+ def test_rcode_user_functions():
113
+ x = symbols('x', integer=False)
114
+ n = symbols('n', integer=True)
115
+ custom_functions = {
116
+ "ceiling": "myceil",
117
+ "Abs": [(lambda x: not x.is_integer, "fabs"), (lambda x: x.is_integer, "abs")],
118
+ }
119
+ assert rcode(ceiling(x), user_functions=custom_functions) == "myceil(x)"
120
+ assert rcode(Abs(x), user_functions=custom_functions) == "fabs(x)"
121
+ assert rcode(Abs(n), user_functions=custom_functions) == "abs(n)"
122
+
123
+
124
+ def test_rcode_boolean():
125
+ assert rcode(True) == "True"
126
+ assert rcode(S.true) == "True"
127
+ assert rcode(False) == "False"
128
+ assert rcode(S.false) == "False"
129
+ assert rcode(x & y) == "x & y"
130
+ assert rcode(x | y) == "x | y"
131
+ assert rcode(~x) == "!x"
132
+ assert rcode(x & y & z) == "x & y & z"
133
+ assert rcode(x | y | z) == "x | y | z"
134
+ assert rcode((x & y) | z) == "z | x & y"
135
+ assert rcode((x | y) & z) == "z & (x | y)"
136
+
137
+ def test_rcode_Relational():
138
+ assert rcode(Eq(x, y)) == "x == y"
139
+ assert rcode(Ne(x, y)) == "x != y"
140
+ assert rcode(Le(x, y)) == "x <= y"
141
+ assert rcode(Lt(x, y)) == "x < y"
142
+ assert rcode(Gt(x, y)) == "x > y"
143
+ assert rcode(Ge(x, y)) == "x >= y"
144
+
145
+
146
+ def test_rcode_Piecewise():
147
+ expr = Piecewise((x, x < 1), (x**2, True))
148
+ res=rcode(expr)
149
+ ref="ifelse(x < 1,x,x^2)"
150
+ assert res == ref
151
+ tau=Symbol("tau")
152
+ res=rcode(expr,tau)
153
+ ref="tau = ifelse(x < 1,x,x^2);"
154
+ assert res == ref
155
+
156
+ expr = 2*Piecewise((x, x < 1), (x**2, x<2), (x**3,True))
157
+ assert rcode(expr) == "2*ifelse(x < 1,x,ifelse(x < 2,x^2,x^3))"
158
+ res = rcode(expr, assign_to='c')
159
+ assert res == "c = 2*ifelse(x < 1,x,ifelse(x < 2,x^2,x^3));"
160
+
161
+ # Check that Piecewise without a True (default) condition error
162
+ #expr = Piecewise((x, x < 1), (x**2, x > 1), (sin(x), x > 0))
163
+ #raises(ValueError, lambda: rcode(expr))
164
+ expr = 2*Piecewise((x, x < 1), (x**2, x<2))
165
+ assert(rcode(expr))== "2*ifelse(x < 1,x,ifelse(x < 2,x^2,NA))"
166
+
167
+
168
+ def test_rcode_sinc():
169
+ from sympy.functions.elementary.trigonometric import sinc
170
+ expr = sinc(x)
171
+ res = rcode(expr)
172
+ ref = "(ifelse(x != 0,sin(x)/x,1))"
173
+ assert res == ref
174
+
175
+
176
+ def test_rcode_Piecewise_deep():
177
+ p = rcode(2*Piecewise((x, x < 1), (x + 1, x < 2), (x**2, True)))
178
+ assert p == "2*ifelse(x < 1,x,ifelse(x < 2,x + 1,x^2))"
179
+ expr = x*y*z + x**2 + y**2 + Piecewise((0, x < 0.5), (1, True)) + cos(z) - 1
180
+ p = rcode(expr)
181
+ ref="x^2 + x*y*z + y^2 + ifelse(x < 0.5,0,1) + cos(z) - 1"
182
+ assert p == ref
183
+
184
+ ref="c = x^2 + x*y*z + y^2 + ifelse(x < 0.5,0,1) + cos(z) - 1;"
185
+ p = rcode(expr, assign_to='c')
186
+ assert p == ref
187
+
188
+
189
+ def test_rcode_ITE():
190
+ expr = ITE(x < 1, y, z)
191
+ p = rcode(expr)
192
+ ref="ifelse(x < 1,y,z)"
193
+ assert p == ref
194
+
195
+
196
+ def test_rcode_settings():
197
+ raises(TypeError, lambda: rcode(sin(x), method="garbage"))
198
+
199
+
200
+ def test_rcode_Indexed():
201
+ n, m, o = symbols('n m o', integer=True)
202
+ i, j, k = Idx('i', n), Idx('j', m), Idx('k', o)
203
+ p = RCodePrinter()
204
+ p._not_r = set()
205
+
206
+ x = IndexedBase('x')[j]
207
+ assert p._print_Indexed(x) == 'x[j]'
208
+ A = IndexedBase('A')[i, j]
209
+ assert p._print_Indexed(A) == 'A[i, j]'
210
+ B = IndexedBase('B')[i, j, k]
211
+ assert p._print_Indexed(B) == 'B[i, j, k]'
212
+
213
+ assert p._not_r == set()
214
+
215
+ def test_rcode_Indexed_without_looking_for_contraction():
216
+ len_y = 5
217
+ y = IndexedBase('y', shape=(len_y,))
218
+ x = IndexedBase('x', shape=(len_y,))
219
+ Dy = IndexedBase('Dy', shape=(len_y-1,))
220
+ i = Idx('i', len_y-1)
221
+ e=Eq(Dy[i], (y[i+1]-y[i])/(x[i+1]-x[i]))
222
+ code0 = rcode(e.rhs, assign_to=e.lhs, contract=False)
223
+ assert code0 == 'Dy[i] = (y[%s] - y[i])/(x[%s] - x[i]);' % (i + 1, i + 1)
224
+
225
+
226
+ def test_rcode_loops_matrix_vector():
227
+ n, m = symbols('n m', integer=True)
228
+ A = IndexedBase('A')
229
+ x = IndexedBase('x')
230
+ y = IndexedBase('y')
231
+ i = Idx('i', m)
232
+ j = Idx('j', n)
233
+
234
+ s = (
235
+ 'for (i in 1:m){\n'
236
+ ' y[i] = 0;\n'
237
+ '}\n'
238
+ 'for (i in 1:m){\n'
239
+ ' for (j in 1:n){\n'
240
+ ' y[i] = A[i, j]*x[j] + y[i];\n'
241
+ ' }\n'
242
+ '}'
243
+ )
244
+ c = rcode(A[i, j]*x[j], assign_to=y[i])
245
+ assert c == s
246
+
247
+
248
+ def test_dummy_loops():
249
+ # the following line could also be
250
+ # [Dummy(s, integer=True) for s in 'im']
251
+ # or [Dummy(integer=True) for s in 'im']
252
+ i, m = symbols('i m', integer=True, cls=Dummy)
253
+ x = IndexedBase('x')
254
+ y = IndexedBase('y')
255
+ i = Idx(i, m)
256
+
257
+ expected = (
258
+ 'for (i_%(icount)i in 1:m_%(mcount)i){\n'
259
+ ' y[i_%(icount)i] = x[i_%(icount)i];\n'
260
+ '}'
261
+ ) % {'icount': i.label.dummy_index, 'mcount': m.dummy_index}
262
+ code = rcode(x[i], assign_to=y[i])
263
+ assert code == expected
264
+
265
+
266
+ def test_rcode_loops_add():
267
+ n, m = symbols('n m', integer=True)
268
+ A = IndexedBase('A')
269
+ x = IndexedBase('x')
270
+ y = IndexedBase('y')
271
+ z = IndexedBase('z')
272
+ i = Idx('i', m)
273
+ j = Idx('j', n)
274
+
275
+ s = (
276
+ 'for (i in 1:m){\n'
277
+ ' y[i] = x[i] + z[i];\n'
278
+ '}\n'
279
+ 'for (i in 1:m){\n'
280
+ ' for (j in 1:n){\n'
281
+ ' y[i] = A[i, j]*x[j] + y[i];\n'
282
+ ' }\n'
283
+ '}'
284
+ )
285
+ c = rcode(A[i, j]*x[j] + x[i] + z[i], assign_to=y[i])
286
+ assert c == s
287
+
288
+
289
+ def test_rcode_loops_multiple_contractions():
290
+ n, m, o, p = symbols('n m o p', integer=True)
291
+ a = IndexedBase('a')
292
+ b = IndexedBase('b')
293
+ y = IndexedBase('y')
294
+ i = Idx('i', m)
295
+ j = Idx('j', n)
296
+ k = Idx('k', o)
297
+ l = Idx('l', p)
298
+
299
+ s = (
300
+ 'for (i in 1:m){\n'
301
+ ' y[i] = 0;\n'
302
+ '}\n'
303
+ 'for (i in 1:m){\n'
304
+ ' for (j in 1:n){\n'
305
+ ' for (k in 1:o){\n'
306
+ ' for (l in 1:p){\n'
307
+ ' y[i] = a[i, j, k, l]*b[j, k, l] + y[i];\n'
308
+ ' }\n'
309
+ ' }\n'
310
+ ' }\n'
311
+ '}'
312
+ )
313
+ c = rcode(b[j, k, l]*a[i, j, k, l], assign_to=y[i])
314
+ assert c == s
315
+
316
+
317
+ def test_rcode_loops_addfactor():
318
+ n, m, o, p = symbols('n m o p', integer=True)
319
+ a = IndexedBase('a')
320
+ b = IndexedBase('b')
321
+ c = IndexedBase('c')
322
+ y = IndexedBase('y')
323
+ i = Idx('i', m)
324
+ j = Idx('j', n)
325
+ k = Idx('k', o)
326
+ l = Idx('l', p)
327
+
328
+ s = (
329
+ 'for (i in 1:m){\n'
330
+ ' y[i] = 0;\n'
331
+ '}\n'
332
+ 'for (i in 1:m){\n'
333
+ ' for (j in 1:n){\n'
334
+ ' for (k in 1:o){\n'
335
+ ' for (l in 1:p){\n'
336
+ ' y[i] = (a[i, j, k, l] + b[i, j, k, l])*c[j, k, l] + y[i];\n'
337
+ ' }\n'
338
+ ' }\n'
339
+ ' }\n'
340
+ '}'
341
+ )
342
+ c = rcode((a[i, j, k, l] + b[i, j, k, l])*c[j, k, l], assign_to=y[i])
343
+ assert c == s
344
+
345
+
346
+ def test_rcode_loops_multiple_terms():
347
+ n, m, o, p = symbols('n m o p', integer=True)
348
+ a = IndexedBase('a')
349
+ b = IndexedBase('b')
350
+ c = IndexedBase('c')
351
+ y = IndexedBase('y')
352
+ i = Idx('i', m)
353
+ j = Idx('j', n)
354
+ k = Idx('k', o)
355
+
356
+ s0 = (
357
+ 'for (i in 1:m){\n'
358
+ ' y[i] = 0;\n'
359
+ '}\n'
360
+ )
361
+ s1 = (
362
+ 'for (i in 1:m){\n'
363
+ ' for (j in 1:n){\n'
364
+ ' for (k in 1:o){\n'
365
+ ' y[i] = b[j]*b[k]*c[i, j, k] + y[i];\n'
366
+ ' }\n'
367
+ ' }\n'
368
+ '}\n'
369
+ )
370
+ s2 = (
371
+ 'for (i in 1:m){\n'
372
+ ' for (k in 1:o){\n'
373
+ ' y[i] = a[i, k]*b[k] + y[i];\n'
374
+ ' }\n'
375
+ '}\n'
376
+ )
377
+ s3 = (
378
+ 'for (i in 1:m){\n'
379
+ ' for (j in 1:n){\n'
380
+ ' y[i] = a[i, j]*b[j] + y[i];\n'
381
+ ' }\n'
382
+ '}\n'
383
+ )
384
+ c = rcode(
385
+ b[j]*a[i, j] + b[k]*a[i, k] + b[j]*b[k]*c[i, j, k], assign_to=y[i])
386
+
387
+ ref={}
388
+ ref[0] = s0 + s1 + s2 + s3[:-1]
389
+ ref[1] = s0 + s1 + s3 + s2[:-1]
390
+ ref[2] = s0 + s2 + s1 + s3[:-1]
391
+ ref[3] = s0 + s2 + s3 + s1[:-1]
392
+ ref[4] = s0 + s3 + s1 + s2[:-1]
393
+ ref[5] = s0 + s3 + s2 + s1[:-1]
394
+
395
+ assert (c == ref[0] or
396
+ c == ref[1] or
397
+ c == ref[2] or
398
+ c == ref[3] or
399
+ c == ref[4] or
400
+ c == ref[5])
401
+
402
+
403
+ def test_dereference_printing():
404
+ expr = x + y + sin(z) + z
405
+ assert rcode(expr, dereference=[z]) == "x + y + (*z) + sin((*z))"
406
+
407
+
408
+ def test_Matrix_printing():
409
+ # Test returning a Matrix
410
+ mat = Matrix([x*y, Piecewise((2 + x, y>0), (y, True)), sin(z)])
411
+ A = MatrixSymbol('A', 3, 1)
412
+ p = rcode(mat, A)
413
+ assert p == (
414
+ "A[0] = x*y;\n"
415
+ "A[1] = ifelse(y > 0,x + 2,y);\n"
416
+ "A[2] = sin(z);")
417
+ # Test using MatrixElements in expressions
418
+ expr = Piecewise((2*A[2, 0], x > 0), (A[2, 0], True)) + sin(A[1, 0]) + A[0, 0]
419
+ p = rcode(expr)
420
+ assert p == ("ifelse(x > 0,2*A[2],A[2]) + sin(A[1]) + A[0]")
421
+ # Test using MatrixElements in a Matrix
422
+ q = MatrixSymbol('q', 5, 1)
423
+ M = MatrixSymbol('M', 3, 3)
424
+ m = Matrix([[sin(q[1,0]), 0, cos(q[2,0])],
425
+ [q[1,0] + q[2,0], q[3, 0], 5],
426
+ [2*q[4, 0]/q[1,0], sqrt(q[0,0]) + 4, 0]])
427
+ assert rcode(m, M) == (
428
+ "M[0] = sin(q[1]);\n"
429
+ "M[1] = 0;\n"
430
+ "M[2] = cos(q[2]);\n"
431
+ "M[3] = q[1] + q[2];\n"
432
+ "M[4] = q[3];\n"
433
+ "M[5] = 5;\n"
434
+ "M[6] = 2*q[4]/q[1];\n"
435
+ "M[7] = sqrt(q[0]) + 4;\n"
436
+ "M[8] = 0;")
437
+
438
+
439
+ def test_rcode_sgn():
440
+
441
+ expr = sign(x) * y
442
+ assert rcode(expr) == 'y*sign(x)'
443
+ p = rcode(expr, 'z')
444
+ assert p == 'z = y*sign(x);'
445
+
446
+ p = rcode(sign(2 * x + x**2) * x + x**2)
447
+ assert p == "x^2 + x*sign(x^2 + 2*x)"
448
+
449
+ expr = sign(cos(x))
450
+ p = rcode(expr)
451
+ assert p == 'sign(cos(x))'
452
+
453
+ def test_rcode_Assignment():
454
+ assert rcode(Assignment(x, y + z)) == 'x = y + z;'
455
+ assert rcode(aug_assign(x, '+', y + z)) == 'x += y + z;'
456
+
457
+
458
+ def test_rcode_For():
459
+ f = For(x, Range(0, 10, 2), [aug_assign(y, '*', x)])
460
+ sol = rcode(f)
461
+ assert sol == ("for(x in seq(from=0, to=9, by=2){\n"
462
+ " y *= x;\n"
463
+ "}")
464
+
465
+
466
+ def test_MatrixElement_printing():
467
+ # test cases for issue #11821
468
+ A = MatrixSymbol("A", 1, 3)
469
+ B = MatrixSymbol("B", 1, 3)
470
+ C = MatrixSymbol("C", 1, 3)
471
+
472
+ assert(rcode(A[0, 0]) == "A[0]")
473
+ assert(rcode(3 * A[0, 0]) == "3*A[0]")
474
+
475
+ F = C[0, 0].subs(C, A - B)
476
+ assert(rcode(F) == "(A - B)[0]")
outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_repr.py ADDED
@@ -0,0 +1,382 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+ from typing import Any
3
+
4
+ from sympy.external.gmpy import GROUND_TYPES
5
+ from sympy.testing.pytest import raises, warns_deprecated_sympy
6
+ from sympy.assumptions.ask import Q
7
+ from sympy.core.function import (Function, WildFunction)
8
+ from sympy.core.numbers import (AlgebraicNumber, Float, Integer, Rational)
9
+ from sympy.core.singleton import S
10
+ from sympy.core.symbol import (Dummy, Symbol, Wild, symbols)
11
+ from sympy.core.sympify import sympify
12
+ from sympy.functions.elementary.complexes import Abs
13
+ from sympy.functions.elementary.miscellaneous import (root, sqrt)
14
+ from sympy.functions.elementary.trigonometric import sin
15
+ from sympy.functions.special.delta_functions import Heaviside
16
+ from sympy.logic.boolalg import (false, true)
17
+ from sympy.matrices.dense import (Matrix, ones)
18
+ from sympy.matrices.expressions.matexpr import MatrixSymbol
19
+ from sympy.matrices.immutable import ImmutableDenseMatrix
20
+ from sympy.combinatorics import Cycle, Permutation
21
+ from sympy.core.symbol import Str
22
+ from sympy.geometry import Point, Ellipse
23
+ from sympy.printing import srepr
24
+ from sympy.polys import ring, field, ZZ, QQ, lex, grlex, Poly
25
+ from sympy.polys.polyclasses import DMP
26
+ from sympy.polys.agca.extensions import FiniteExtension
27
+
28
+ x, y = symbols('x,y')
29
+
30
+ # eval(srepr(expr)) == expr has to succeed in the right environment. The right
31
+ # environment is the scope of "from sympy import *" for most cases.
32
+ ENV: dict[str, Any] = {"Str": Str}
33
+ exec("from sympy import *", ENV)
34
+
35
+
36
+ def sT(expr, string, import_stmt=None, **kwargs):
37
+ """
38
+ sT := sreprTest
39
+
40
+ Tests that srepr delivers the expected string and that
41
+ the condition eval(srepr(expr))==expr holds.
42
+ """
43
+ if import_stmt is None:
44
+ ENV2 = ENV
45
+ else:
46
+ ENV2 = ENV.copy()
47
+ exec(import_stmt, ENV2)
48
+
49
+ assert srepr(expr, **kwargs) == string
50
+ assert eval(string, ENV2) == expr
51
+
52
+
53
+ def test_printmethod():
54
+ class R(Abs):
55
+ def _sympyrepr(self, printer):
56
+ return "foo(%s)" % printer._print(self.args[0])
57
+ assert srepr(R(x)) == "foo(Symbol('x'))"
58
+
59
+
60
+ def test_Add():
61
+ sT(x + y, "Add(Symbol('x'), Symbol('y'))")
62
+ assert srepr(x**2 + 1, order='lex') == "Add(Pow(Symbol('x'), Integer(2)), Integer(1))"
63
+ assert srepr(x**2 + 1, order='old') == "Add(Integer(1), Pow(Symbol('x'), Integer(2)))"
64
+ assert srepr(sympify('x + 3 - 2', evaluate=False), order='none') == "Add(Symbol('x'), Integer(3), Mul(Integer(-1), Integer(2)))"
65
+
66
+
67
+ def test_more_than_255_args_issue_10259():
68
+ from sympy.core.add import Add
69
+ from sympy.core.mul import Mul
70
+ for op in (Add, Mul):
71
+ expr = op(*symbols('x:256'))
72
+ assert eval(srepr(expr)) == expr
73
+
74
+
75
+ def test_Function():
76
+ sT(Function("f")(x), "Function('f')(Symbol('x'))")
77
+ # test unapplied Function
78
+ sT(Function('f'), "Function('f')")
79
+
80
+ sT(sin(x), "sin(Symbol('x'))")
81
+ sT(sin, "sin")
82
+
83
+
84
+ def test_Heaviside():
85
+ sT(Heaviside(x), "Heaviside(Symbol('x'))")
86
+ sT(Heaviside(x, 1), "Heaviside(Symbol('x'), Integer(1))")
87
+
88
+
89
+ def test_Geometry():
90
+ sT(Point(0, 0), "Point2D(Integer(0), Integer(0))")
91
+ sT(Ellipse(Point(0, 0), 5, 1),
92
+ "Ellipse(Point2D(Integer(0), Integer(0)), Integer(5), Integer(1))")
93
+ # TODO more tests
94
+
95
+
96
+ def test_Singletons():
97
+ sT(S.Catalan, 'Catalan')
98
+ sT(S.ComplexInfinity, 'zoo')
99
+ sT(S.EulerGamma, 'EulerGamma')
100
+ sT(S.Exp1, 'E')
101
+ sT(S.GoldenRatio, 'GoldenRatio')
102
+ sT(S.TribonacciConstant, 'TribonacciConstant')
103
+ sT(S.Half, 'Rational(1, 2)')
104
+ sT(S.ImaginaryUnit, 'I')
105
+ sT(S.Infinity, 'oo')
106
+ sT(S.NaN, 'nan')
107
+ sT(S.NegativeInfinity, '-oo')
108
+ sT(S.NegativeOne, 'Integer(-1)')
109
+ sT(S.One, 'Integer(1)')
110
+ sT(S.Pi, 'pi')
111
+ sT(S.Zero, 'Integer(0)')
112
+ sT(S.Complexes, 'Complexes')
113
+ sT(S.EmptySequence, 'EmptySequence')
114
+ sT(S.EmptySet, 'EmptySet')
115
+ # sT(S.IdentityFunction, 'Lambda(_x, _x)')
116
+ sT(S.Naturals, 'Naturals')
117
+ sT(S.Naturals0, 'Naturals0')
118
+ sT(S.Rationals, 'Rationals')
119
+ sT(S.Reals, 'Reals')
120
+ sT(S.UniversalSet, 'UniversalSet')
121
+
122
+
123
+ def test_Integer():
124
+ sT(Integer(4), "Integer(4)")
125
+
126
+
127
+ def test_list():
128
+ sT([x, Integer(4)], "[Symbol('x'), Integer(4)]")
129
+
130
+
131
+ def test_Matrix():
132
+ for cls, name in [(Matrix, "MutableDenseMatrix"), (ImmutableDenseMatrix, "ImmutableDenseMatrix")]:
133
+ sT(cls([[x**+1, 1], [y, x + y]]),
134
+ "%s([[Symbol('x'), Integer(1)], [Symbol('y'), Add(Symbol('x'), Symbol('y'))]])" % name)
135
+
136
+ sT(cls(), "%s([])" % name)
137
+
138
+ sT(cls([[x**+1, 1], [y, x + y]]), "%s([[Symbol('x'), Integer(1)], [Symbol('y'), Add(Symbol('x'), Symbol('y'))]])" % name)
139
+
140
+
141
+ def test_empty_Matrix():
142
+ sT(ones(0, 3), "MutableDenseMatrix(0, 3, [])")
143
+ sT(ones(4, 0), "MutableDenseMatrix(4, 0, [])")
144
+ sT(ones(0, 0), "MutableDenseMatrix([])")
145
+
146
+
147
+ def test_Rational():
148
+ sT(Rational(1, 3), "Rational(1, 3)")
149
+ sT(Rational(-1, 3), "Rational(-1, 3)")
150
+
151
+
152
+ def test_Float():
153
+ sT(Float('1.23', dps=3), "Float('1.22998', precision=13)")
154
+ sT(Float('1.23456789', dps=9), "Float('1.23456788994', precision=33)")
155
+ sT(Float('1.234567890123456789', dps=19),
156
+ "Float('1.234567890123456789013', precision=66)")
157
+ sT(Float('0.60038617995049726', dps=15),
158
+ "Float('0.60038617995049726', precision=53)")
159
+
160
+ sT(Float('1.23', precision=13), "Float('1.22998', precision=13)")
161
+ sT(Float('1.23456789', precision=33),
162
+ "Float('1.23456788994', precision=33)")
163
+ sT(Float('1.234567890123456789', precision=66),
164
+ "Float('1.234567890123456789013', precision=66)")
165
+ sT(Float('0.60038617995049726', precision=53),
166
+ "Float('0.60038617995049726', precision=53)")
167
+
168
+ sT(Float('0.60038617995049726', 15),
169
+ "Float('0.60038617995049726', precision=53)")
170
+
171
+
172
+ def test_Symbol():
173
+ sT(x, "Symbol('x')")
174
+ sT(y, "Symbol('y')")
175
+ sT(Symbol('x', negative=True), "Symbol('x', negative=True)")
176
+
177
+
178
+ def test_Symbol_two_assumptions():
179
+ x = Symbol('x', negative=0, integer=1)
180
+ # order could vary
181
+ s1 = "Symbol('x', integer=True, negative=False)"
182
+ s2 = "Symbol('x', negative=False, integer=True)"
183
+ assert srepr(x) in (s1, s2)
184
+ assert eval(srepr(x), ENV) == x
185
+
186
+
187
+ def test_Symbol_no_special_commutative_treatment():
188
+ sT(Symbol('x'), "Symbol('x')")
189
+ sT(Symbol('x', commutative=False), "Symbol('x', commutative=False)")
190
+ sT(Symbol('x', commutative=0), "Symbol('x', commutative=False)")
191
+ sT(Symbol('x', commutative=True), "Symbol('x', commutative=True)")
192
+ sT(Symbol('x', commutative=1), "Symbol('x', commutative=True)")
193
+
194
+
195
+ def test_Wild():
196
+ sT(Wild('x', even=True), "Wild('x', even=True)")
197
+
198
+
199
+ def test_Dummy():
200
+ d = Dummy('d')
201
+ sT(d, "Dummy('d', dummy_index=%s)" % str(d.dummy_index))
202
+
203
+
204
+ def test_Dummy_assumption():
205
+ d = Dummy('d', nonzero=True)
206
+ assert d == eval(srepr(d))
207
+ s1 = "Dummy('d', dummy_index=%s, nonzero=True)" % str(d.dummy_index)
208
+ s2 = "Dummy('d', nonzero=True, dummy_index=%s)" % str(d.dummy_index)
209
+ assert srepr(d) in (s1, s2)
210
+
211
+
212
+ def test_Dummy_from_Symbol():
213
+ # should not get the full dictionary of assumptions
214
+ n = Symbol('n', integer=True)
215
+ d = n.as_dummy()
216
+ assert srepr(d
217
+ ) == "Dummy('n', dummy_index=%s)" % str(d.dummy_index)
218
+
219
+
220
+ def test_tuple():
221
+ sT((x,), "(Symbol('x'),)")
222
+ sT((x, y), "(Symbol('x'), Symbol('y'))")
223
+
224
+
225
+ def test_WildFunction():
226
+ sT(WildFunction('w'), "WildFunction('w')")
227
+
228
+
229
+ def test_settins():
230
+ raises(TypeError, lambda: srepr(x, method="garbage"))
231
+
232
+
233
+ def test_Mul():
234
+ sT(3*x**3*y, "Mul(Integer(3), Pow(Symbol('x'), Integer(3)), Symbol('y'))")
235
+ assert srepr(3*x**3*y, order='old') == "Mul(Integer(3), Symbol('y'), Pow(Symbol('x'), Integer(3)))"
236
+ assert srepr(sympify('(x+4)*2*x*7', evaluate=False), order='none') == "Mul(Add(Symbol('x'), Integer(4)), Integer(2), Symbol('x'), Integer(7))"
237
+
238
+
239
+ def test_AlgebraicNumber():
240
+ a = AlgebraicNumber(sqrt(2))
241
+ sT(a, "AlgebraicNumber(Pow(Integer(2), Rational(1, 2)), [Integer(1), Integer(0)])")
242
+ a = AlgebraicNumber(root(-2, 3))
243
+ sT(a, "AlgebraicNumber(Pow(Integer(-2), Rational(1, 3)), [Integer(1), Integer(0)])")
244
+
245
+
246
+ def test_PolyRing():
247
+ assert srepr(ring("x", ZZ, lex)[0]) == "PolyRing((Symbol('x'),), ZZ, lex)"
248
+ assert srepr(ring("x,y", QQ, grlex)[0]) == "PolyRing((Symbol('x'), Symbol('y')), QQ, grlex)"
249
+ assert srepr(ring("x,y,z", ZZ["t"], lex)[0]) == "PolyRing((Symbol('x'), Symbol('y'), Symbol('z')), ZZ[t], lex)"
250
+
251
+
252
+ def test_FracField():
253
+ assert srepr(field("x", ZZ, lex)[0]) == "FracField((Symbol('x'),), ZZ, lex)"
254
+ assert srepr(field("x,y", QQ, grlex)[0]) == "FracField((Symbol('x'), Symbol('y')), QQ, grlex)"
255
+ assert srepr(field("x,y,z", ZZ["t"], lex)[0]) == "FracField((Symbol('x'), Symbol('y'), Symbol('z')), ZZ[t], lex)"
256
+
257
+
258
+ def test_PolyElement():
259
+ R, x, y = ring("x,y", ZZ)
260
+ assert srepr(3*x**2*y + 1) == "PolyElement(PolyRing((Symbol('x'), Symbol('y')), ZZ, lex), [((2, 1), 3), ((0, 0), 1)])"
261
+
262
+
263
+ def test_FracElement():
264
+ F, x, y = field("x,y", ZZ)
265
+ assert srepr((3*x**2*y + 1)/(x - y**2)) == "FracElement(FracField((Symbol('x'), Symbol('y')), ZZ, lex), [((2, 1), 3), ((0, 0), 1)], [((1, 0), 1), ((0, 2), -1)])"
266
+
267
+
268
+ def test_FractionField():
269
+ assert srepr(QQ.frac_field(x)) == \
270
+ "FractionField(FracField((Symbol('x'),), QQ, lex))"
271
+ assert srepr(QQ.frac_field(x, y, order=grlex)) == \
272
+ "FractionField(FracField((Symbol('x'), Symbol('y')), QQ, grlex))"
273
+
274
+
275
+ def test_PolynomialRingBase():
276
+ assert srepr(ZZ.old_poly_ring(x)) == \
277
+ "GlobalPolynomialRing(ZZ, Symbol('x'))"
278
+ assert srepr(ZZ[x].old_poly_ring(y)) == \
279
+ "GlobalPolynomialRing(ZZ[x], Symbol('y'))"
280
+ assert srepr(QQ.frac_field(x).old_poly_ring(y)) == \
281
+ "GlobalPolynomialRing(FractionField(FracField((Symbol('x'),), QQ, lex)), Symbol('y'))"
282
+
283
+
284
+ def test_DMP():
285
+ p1 = DMP([1, 2], ZZ)
286
+ p2 = ZZ.old_poly_ring(x)([1, 2])
287
+ if GROUND_TYPES != 'flint':
288
+ assert srepr(p1) == "DMP_Python([1, 2], ZZ)"
289
+ assert srepr(p2) == "DMP_Python([1, 2], ZZ)"
290
+ else:
291
+ assert srepr(p1) == "DUP_Flint([1, 2], ZZ)"
292
+ assert srepr(p2) == "DUP_Flint([1, 2], ZZ)"
293
+
294
+
295
+ def test_FiniteExtension():
296
+ assert srepr(FiniteExtension(Poly(x**2 + 1, x))) == \
297
+ "FiniteExtension(Poly(x**2 + 1, x, domain='ZZ'))"
298
+
299
+
300
+ def test_ExtensionElement():
301
+ A = FiniteExtension(Poly(x**2 + 1, x))
302
+ if GROUND_TYPES != 'flint':
303
+ ans = "ExtElem(DMP_Python([1, 0], ZZ), FiniteExtension(Poly(x**2 + 1, x, domain='ZZ')))"
304
+ else:
305
+ ans = "ExtElem(DUP_Flint([1, 0], ZZ), FiniteExtension(Poly(x**2 + 1, x, domain='ZZ')))"
306
+ assert srepr(A.generator) == ans
307
+
308
+ def test_BooleanAtom():
309
+ assert srepr(true) == "true"
310
+ assert srepr(false) == "false"
311
+
312
+
313
+ def test_Integers():
314
+ sT(S.Integers, "Integers")
315
+
316
+
317
+ def test_Naturals():
318
+ sT(S.Naturals, "Naturals")
319
+
320
+
321
+ def test_Naturals0():
322
+ sT(S.Naturals0, "Naturals0")
323
+
324
+
325
+ def test_Reals():
326
+ sT(S.Reals, "Reals")
327
+
328
+
329
+ def test_matrix_expressions():
330
+ n = symbols('n', integer=True)
331
+ A = MatrixSymbol("A", n, n)
332
+ B = MatrixSymbol("B", n, n)
333
+ sT(A, "MatrixSymbol(Str('A'), Symbol('n', integer=True), Symbol('n', integer=True))")
334
+ sT(A*B, "MatMul(MatrixSymbol(Str('A'), Symbol('n', integer=True), Symbol('n', integer=True)), MatrixSymbol(Str('B'), Symbol('n', integer=True), Symbol('n', integer=True)))")
335
+ sT(A + B, "MatAdd(MatrixSymbol(Str('A'), Symbol('n', integer=True), Symbol('n', integer=True)), MatrixSymbol(Str('B'), Symbol('n', integer=True), Symbol('n', integer=True)))")
336
+
337
+
338
+ def test_Cycle():
339
+ # FIXME: sT fails because Cycle is not immutable and calling srepr(Cycle(1, 2))
340
+ # adds keys to the Cycle dict (GH-17661)
341
+ #import_stmt = "from sympy.combinatorics import Cycle"
342
+ #sT(Cycle(1, 2), "Cycle(1, 2)", import_stmt)
343
+ assert srepr(Cycle(1, 2)) == "Cycle(1, 2)"
344
+
345
+
346
+ def test_Permutation():
347
+ import_stmt = "from sympy.combinatorics import Permutation"
348
+ sT(Permutation(1, 2)(3, 4), "Permutation([0, 2, 1, 4, 3])", import_stmt, perm_cyclic=False)
349
+ sT(Permutation(1, 2)(3, 4), "Permutation(1, 2)(3, 4)", import_stmt, perm_cyclic=True)
350
+
351
+ with warns_deprecated_sympy():
352
+ old_print_cyclic = Permutation.print_cyclic
353
+ Permutation.print_cyclic = False
354
+ sT(Permutation(1, 2)(3, 4), "Permutation([0, 2, 1, 4, 3])", import_stmt)
355
+ Permutation.print_cyclic = old_print_cyclic
356
+
357
+ def test_dict():
358
+ from sympy.abc import x, y, z
359
+ d = {}
360
+ assert srepr(d) == "{}"
361
+ d = {x: y}
362
+ assert srepr(d) == "{Symbol('x'): Symbol('y')}"
363
+ d = {x: y, y: z}
364
+ assert srepr(d) in (
365
+ "{Symbol('x'): Symbol('y'), Symbol('y'): Symbol('z')}",
366
+ "{Symbol('y'): Symbol('z'), Symbol('x'): Symbol('y')}",
367
+ )
368
+ d = {x: {y: z}}
369
+ assert srepr(d) == "{Symbol('x'): {Symbol('y'): Symbol('z')}}"
370
+
371
+ def test_set():
372
+ from sympy.abc import x, y
373
+ s = set()
374
+ assert srepr(s) == "set()"
375
+ s = {x, y}
376
+ assert srepr(s) in ("{Symbol('x'), Symbol('y')}", "{Symbol('y'), Symbol('x')}")
377
+
378
+ def test_Predicate():
379
+ sT(Q.even, "Q.even")
380
+
381
+ def test_AppliedPredicate():
382
+ sT(Q.even(Symbol('z')), "AppliedPredicate(Q.even, Symbol('z'))")
outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_rust.py ADDED
@@ -0,0 +1,363 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core import (S, pi, oo, symbols, Rational, Integer,
2
+ GoldenRatio, EulerGamma, Catalan, Lambda, Dummy,
3
+ Eq, Ne, Le, Lt, Gt, Ge, Mod)
4
+ from sympy.functions import (Piecewise, sin, cos, Abs, exp, ceiling, sqrt,
5
+ sign, floor)
6
+ from sympy.logic import ITE
7
+ from sympy.testing.pytest import raises
8
+ from sympy.utilities.lambdify import implemented_function
9
+ from sympy.tensor import IndexedBase, Idx
10
+ from sympy.matrices import MatrixSymbol, SparseMatrix, Matrix
11
+
12
+ from sympy.printing.codeprinter import rust_code
13
+
14
+ x, y, z = symbols('x,y,z', integer=False, real=True)
15
+ k, m, n = symbols('k,m,n', integer=True)
16
+
17
+
18
+ def test_Integer():
19
+ assert rust_code(Integer(42)) == "42"
20
+ assert rust_code(Integer(-56)) == "-56"
21
+
22
+
23
+ def test_Relational():
24
+ assert rust_code(Eq(x, y)) == "x == y"
25
+ assert rust_code(Ne(x, y)) == "x != y"
26
+ assert rust_code(Le(x, y)) == "x <= y"
27
+ assert rust_code(Lt(x, y)) == "x < y"
28
+ assert rust_code(Gt(x, y)) == "x > y"
29
+ assert rust_code(Ge(x, y)) == "x >= y"
30
+
31
+
32
+ def test_Rational():
33
+ assert rust_code(Rational(3, 7)) == "3_f64/7.0"
34
+ assert rust_code(Rational(18, 9)) == "2"
35
+ assert rust_code(Rational(3, -7)) == "-3_f64/7.0"
36
+ assert rust_code(Rational(-3, -7)) == "3_f64/7.0"
37
+ assert rust_code(x + Rational(3, 7)) == "x + 3_f64/7.0"
38
+ assert rust_code(Rational(3, 7)*x) == "(3_f64/7.0)*x"
39
+
40
+
41
+ def test_basic_ops():
42
+ assert rust_code(x + y) == "x + y"
43
+ assert rust_code(x - y) == "x - y"
44
+ assert rust_code(x * y) == "x*y"
45
+ assert rust_code(x / y) == "x*y.recip()"
46
+ assert rust_code(-x) == "-x"
47
+ assert rust_code(2 * x) == "2.0*x"
48
+ assert rust_code(y + 2) == "y + 2.0"
49
+ assert rust_code(x + n) == "n as f64 + x"
50
+
51
+ def test_printmethod():
52
+ class fabs(Abs):
53
+ def _rust_code(self, printer):
54
+ return "%s.fabs()" % printer._print(self.args[0])
55
+ assert rust_code(fabs(x)) == "x.fabs()"
56
+ a = MatrixSymbol("a", 1, 3)
57
+ assert rust_code(a[0,0]) == 'a[0]'
58
+
59
+
60
+ def test_Functions():
61
+ assert rust_code(sin(x) ** cos(x)) == "x.sin().powf(x.cos())"
62
+ assert rust_code(abs(x)) == "x.abs()"
63
+ assert rust_code(ceiling(x)) == "x.ceil()"
64
+ assert rust_code(floor(x)) == "x.floor()"
65
+
66
+ # Automatic rewrite
67
+ assert rust_code(Mod(x, 3)) == 'x - 3.0*((1_f64/3.0)*x).floor()'
68
+
69
+
70
+ def test_Pow():
71
+ assert rust_code(1/x) == "x.recip()"
72
+ assert rust_code(x**-1) == rust_code(x**-1.0) == "x.recip()"
73
+ assert rust_code(sqrt(x)) == "x.sqrt()"
74
+ assert rust_code(x**S.Half) == rust_code(x**0.5) == "x.sqrt()"
75
+
76
+ assert rust_code(1/sqrt(x)) == "x.sqrt().recip()"
77
+ assert rust_code(x**-S.Half) == rust_code(x**-0.5) == "x.sqrt().recip()"
78
+
79
+ assert rust_code(1/pi) == "PI.recip()"
80
+ assert rust_code(pi**-1) == rust_code(pi**-1.0) == "PI.recip()"
81
+ assert rust_code(pi**-0.5) == "PI.sqrt().recip()"
82
+
83
+ assert rust_code(x**Rational(1, 3)) == "x.cbrt()"
84
+ assert rust_code(2**x) == "x.exp2()"
85
+ assert rust_code(exp(x)) == "x.exp()"
86
+ assert rust_code(x**3) == "x.powi(3)"
87
+ assert rust_code(x**(y**3)) == "x.powf(y.powi(3))"
88
+ assert rust_code(x**Rational(2, 3)) == "x.powf(2_f64/3.0)"
89
+
90
+ g = implemented_function('g', Lambda(x, 2*x))
91
+ assert rust_code(1/(g(x)*3.5)**(x - y**x)/(x**2 + y)) == \
92
+ "(3.5*2.0*x).powf(-x + y.powf(x))/(x.powi(2) + y)"
93
+ _cond_cfunc = [(lambda base, exp: exp.is_integer, "dpowi", 1),
94
+ (lambda base, exp: not exp.is_integer, "pow", 1)]
95
+ assert rust_code(x**3, user_functions={'Pow': _cond_cfunc}) == 'x.dpowi(3)'
96
+ assert rust_code(x**3.2, user_functions={'Pow': _cond_cfunc}) == 'x.pow(3.2)'
97
+
98
+
99
+ def test_constants():
100
+ assert rust_code(pi) == "PI"
101
+ assert rust_code(oo) == "INFINITY"
102
+ assert rust_code(S.Infinity) == "INFINITY"
103
+ assert rust_code(-oo) == "NEG_INFINITY"
104
+ assert rust_code(S.NegativeInfinity) == "NEG_INFINITY"
105
+ assert rust_code(S.NaN) == "NAN"
106
+ assert rust_code(exp(1)) == "E"
107
+ assert rust_code(S.Exp1) == "E"
108
+
109
+
110
+ def test_constants_other():
111
+ assert rust_code(2*GoldenRatio) == "const GoldenRatio: f64 = %s;\n2.0*GoldenRatio" % GoldenRatio.evalf(17)
112
+ assert rust_code(
113
+ 2*Catalan) == "const Catalan: f64 = %s;\n2.0*Catalan" % Catalan.evalf(17)
114
+ assert rust_code(2*EulerGamma) == "const EulerGamma: f64 = %s;\n2.0*EulerGamma" % EulerGamma.evalf(17)
115
+
116
+
117
+ def test_boolean():
118
+ assert rust_code(True) == "true"
119
+ assert rust_code(S.true) == "true"
120
+ assert rust_code(False) == "false"
121
+ assert rust_code(S.false) == "false"
122
+ assert rust_code(k & m) == "k && m"
123
+ assert rust_code(k | m) == "k || m"
124
+ assert rust_code(~k) == "!k"
125
+ assert rust_code(k & m & n) == "k && m && n"
126
+ assert rust_code(k | m | n) == "k || m || n"
127
+ assert rust_code((k & m) | n) == "n || k && m"
128
+ assert rust_code((k | m) & n) == "n && (k || m)"
129
+
130
+
131
+ def test_Piecewise():
132
+ expr = Piecewise((x, x < 1), (x + 2, True))
133
+ assert rust_code(expr) == (
134
+ "if (x < 1.0) {\n"
135
+ " x\n"
136
+ "} else {\n"
137
+ " x + 2.0\n"
138
+ "}")
139
+ assert rust_code(expr, assign_to="r") == (
140
+ "r = if (x < 1.0) {\n"
141
+ " x\n"
142
+ "} else {\n"
143
+ " x + 2.0\n"
144
+ "};")
145
+ assert rust_code(expr, assign_to="r", inline=True) == (
146
+ "r = if (x < 1.0) { x } else { x + 2.0 };")
147
+ expr = Piecewise((x, x < 1), (x + 1, x < 5), (x + 2, True))
148
+ assert rust_code(expr, inline=True) == (
149
+ "if (x < 1.0) { x } else if (x < 5.0) { x + 1.0 } else { x + 2.0 }")
150
+ assert rust_code(expr, assign_to="r", inline=True) == (
151
+ "r = if (x < 1.0) { x } else if (x < 5.0) { x + 1.0 } else { x + 2.0 };")
152
+ assert rust_code(expr, assign_to="r") == (
153
+ "r = if (x < 1.0) {\n"
154
+ " x\n"
155
+ "} else if (x < 5.0) {\n"
156
+ " x + 1.0\n"
157
+ "} else {\n"
158
+ " x + 2.0\n"
159
+ "};")
160
+ expr = 2*Piecewise((x, x < 1), (x + 1, x < 5), (x + 2, True))
161
+ assert rust_code(expr, inline=True) == (
162
+ "2.0*if (x < 1.0) { x } else if (x < 5.0) { x + 1.0 } else { x + 2.0 }")
163
+ expr = 2*Piecewise((x, x < 1), (x + 1, x < 5), (x + 2, True)) - 42
164
+ assert rust_code(expr, inline=True) == (
165
+ "2.0*if (x < 1.0) { x } else if (x < 5.0) { x + 1.0 } else { x + 2.0 } - 42.0")
166
+ # Check that Piecewise without a True (default) condition error
167
+ expr = Piecewise((x, x < 1), (x**2, x > 1), (sin(x), x > 0))
168
+ raises(ValueError, lambda: rust_code(expr))
169
+
170
+
171
+ def test_dereference_printing():
172
+ expr = x + y + sin(z) + z
173
+ assert rust_code(expr, dereference=[z]) == "x + y + (*z) + (*z).sin()"
174
+
175
+
176
+ def test_sign():
177
+ expr = sign(x) * y
178
+ assert rust_code(expr) == "y*(if (x == 0.0) { 0.0 } else { (x).signum() }) as f64"
179
+ assert rust_code(expr, assign_to='r') == "r = y*(if (x == 0.0) { 0.0 } else { (x).signum() }) as f64;"
180
+
181
+ expr = sign(x + y) + 42
182
+ assert rust_code(expr) == "(if (x + y == 0.0) { 0.0 } else { (x + y).signum() }) + 42"
183
+ assert rust_code(expr, assign_to='r') == "r = (if (x + y == 0.0) { 0.0 } else { (x + y).signum() }) + 42;"
184
+
185
+ expr = sign(cos(x))
186
+ assert rust_code(expr) == "(if (x.cos() == 0.0) { 0.0 } else { (x.cos()).signum() })"
187
+
188
+
189
+ def test_reserved_words():
190
+
191
+ x, y = symbols("x if")
192
+
193
+ expr = sin(y)
194
+ assert rust_code(expr) == "if_.sin()"
195
+ assert rust_code(expr, dereference=[y]) == "(*if_).sin()"
196
+ assert rust_code(expr, reserved_word_suffix='_unreserved') == "if_unreserved.sin()"
197
+
198
+ with raises(ValueError):
199
+ rust_code(expr, error_on_reserved=True)
200
+
201
+
202
+ def test_ITE():
203
+ ekpr = ITE(k < 1, m, n)
204
+ assert rust_code(ekpr) == (
205
+ "if (k < 1) {\n"
206
+ " m\n"
207
+ "} else {\n"
208
+ " n\n"
209
+ "}")
210
+
211
+
212
+ def test_Indexed():
213
+ n, m, o = symbols('n m o', integer=True)
214
+ i, j, k = Idx('i', n), Idx('j', m), Idx('k', o)
215
+
216
+ x = IndexedBase('x')[j]
217
+ assert rust_code(x) == "x[j]"
218
+
219
+ A = IndexedBase('A')[i, j]
220
+ assert rust_code(A) == "A[m*i + j]"
221
+
222
+ B = IndexedBase('B')[i, j, k]
223
+ assert rust_code(B) == "B[m*o*i + o*j + k]"
224
+
225
+
226
+ def test_dummy_loops():
227
+ i, m = symbols('i m', integer=True, cls=Dummy)
228
+ x = IndexedBase('x')
229
+ y = IndexedBase('y')
230
+ i = Idx(i, m)
231
+
232
+ assert rust_code(x[i], assign_to=y[i]) == (
233
+ "for i in 0..m {\n"
234
+ " y[i] = x[i];\n"
235
+ "}")
236
+
237
+
238
+ def test_loops():
239
+ m, n = symbols('m n', integer=True)
240
+ A = IndexedBase('A')
241
+ x = IndexedBase('x')
242
+ y = IndexedBase('y')
243
+ z = IndexedBase('z')
244
+ i = Idx('i', m)
245
+ j = Idx('j', n)
246
+
247
+ assert rust_code(A[i, j]*x[j], assign_to=y[i]) == (
248
+ "for i in 0..m {\n"
249
+ " y[i] = 0;\n"
250
+ "}\n"
251
+ "for i in 0..m {\n"
252
+ " for j in 0..n {\n"
253
+ " y[i] = A[n*i + j]*x[j] + y[i];\n"
254
+ " }\n"
255
+ "}")
256
+
257
+ assert rust_code(A[i, j]*x[j] + x[i] + z[i], assign_to=y[i]) == (
258
+ "for i in 0..m {\n"
259
+ " y[i] = x[i] + z[i];\n"
260
+ "}\n"
261
+ "for i in 0..m {\n"
262
+ " for j in 0..n {\n"
263
+ " y[i] = A[n*i + j]*x[j] + y[i];\n"
264
+ " }\n"
265
+ "}")
266
+
267
+
268
+ def test_loops_multiple_contractions():
269
+ n, m, o, p = symbols('n m o p', integer=True)
270
+ a = IndexedBase('a')
271
+ b = IndexedBase('b')
272
+ y = IndexedBase('y')
273
+ i = Idx('i', m)
274
+ j = Idx('j', n)
275
+ k = Idx('k', o)
276
+ l = Idx('l', p)
277
+
278
+ assert rust_code(b[j, k, l]*a[i, j, k, l], assign_to=y[i]) == (
279
+ "for i in 0..m {\n"
280
+ " y[i] = 0;\n"
281
+ "}\n"
282
+ "for i in 0..m {\n"
283
+ " for j in 0..n {\n"
284
+ " for k in 0..o {\n"
285
+ " for l in 0..p {\n"
286
+ " y[i] = a[%s]*b[%s] + y[i];\n" % (i*n*o*p + j*o*p + k*p + l, j*o*p + k*p + l) +\
287
+ " }\n"
288
+ " }\n"
289
+ " }\n"
290
+ "}")
291
+
292
+
293
+ def test_loops_addfactor():
294
+ m, n, o, p = symbols('m n o p', integer=True)
295
+ a = IndexedBase('a')
296
+ b = IndexedBase('b')
297
+ c = IndexedBase('c')
298
+ y = IndexedBase('y')
299
+ i = Idx('i', m)
300
+ j = Idx('j', n)
301
+ k = Idx('k', o)
302
+ l = Idx('l', p)
303
+
304
+ code = rust_code((a[i, j, k, l] + b[i, j, k, l])*c[j, k, l], assign_to=y[i])
305
+ assert code == (
306
+ "for i in 0..m {\n"
307
+ " y[i] = 0;\n"
308
+ "}\n"
309
+ "for i in 0..m {\n"
310
+ " for j in 0..n {\n"
311
+ " for k in 0..o {\n"
312
+ " for l in 0..p {\n"
313
+ " y[i] = (a[%s] + b[%s])*c[%s] + y[i];\n" % (i*n*o*p + j*o*p + k*p + l, i*n*o*p + j*o*p + k*p + l, j*o*p + k*p + l) +\
314
+ " }\n"
315
+ " }\n"
316
+ " }\n"
317
+ "}")
318
+
319
+
320
+ def test_settings():
321
+ raises(TypeError, lambda: rust_code(sin(x), method="garbage"))
322
+
323
+
324
+ def test_inline_function():
325
+ x = symbols('x')
326
+ g = implemented_function('g', Lambda(x, 2*x))
327
+ assert rust_code(g(x)) == "2*x"
328
+
329
+ g = implemented_function('g', Lambda(x, 2*x/Catalan))
330
+ assert rust_code(g(x)) == (
331
+ "const Catalan: f64 = %s;\n2.0*x/Catalan" % Catalan.evalf(17))
332
+
333
+ A = IndexedBase('A')
334
+ i = Idx('i', symbols('n', integer=True))
335
+ g = implemented_function('g', Lambda(x, x*(1 + x)*(2 + x)))
336
+ assert rust_code(g(A[i]), assign_to=A[i]) == (
337
+ "for i in 0..n {\n"
338
+ " A[i] = (A[i] + 1)*(A[i] + 2)*A[i];\n"
339
+ "}")
340
+
341
+
342
+ def test_user_functions():
343
+ x = symbols('x', integer=False)
344
+ n = symbols('n', integer=True)
345
+ custom_functions = {
346
+ "ceiling": "ceil",
347
+ "Abs": [(lambda x: not x.is_integer, "fabs", 4), (lambda x: x.is_integer, "abs", 4)],
348
+ }
349
+ assert rust_code(ceiling(x), user_functions=custom_functions) == "x.ceil()"
350
+ assert rust_code(Abs(x), user_functions=custom_functions) == "fabs(x)"
351
+ assert rust_code(Abs(n), user_functions=custom_functions) == "abs(n)"
352
+
353
+
354
+ def test_matrix():
355
+ assert rust_code(Matrix([1, 2, 3])) == '[1, 2, 3]'
356
+ with raises(ValueError):
357
+ rust_code(Matrix([[1, 2, 3]]))
358
+
359
+
360
+ def test_sparse_matrix():
361
+ # gh-15791
362
+ with raises(NotImplementedError):
363
+ rust_code(SparseMatrix([[1, 2, 3]]))
outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_smtlib.py ADDED
@@ -0,0 +1,553 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import contextlib
2
+ import itertools
3
+ import re
4
+ import typing
5
+ from enum import Enum
6
+ from typing import Callable
7
+
8
+ import sympy
9
+ from sympy import Add, Implies, sqrt
10
+ from sympy.core import Mul, Pow
11
+ from sympy.core import (S, pi, symbols, Function, Rational, Integer,
12
+ Symbol, Eq, Ne, Le, Lt, Gt, Ge)
13
+ from sympy.functions import Piecewise, exp, sin, cos
14
+ from sympy.assumptions.ask import Q
15
+ from sympy.printing.smtlib import smtlib_code
16
+ from sympy.testing.pytest import raises, Failed
17
+
18
+ x, y, z = symbols('x,y,z')
19
+
20
+
21
+ class _W(Enum):
22
+ DEFAULTING_TO_FLOAT = re.compile("Could not infer type of `.+`. Defaulting to float.", re.IGNORECASE)
23
+ WILL_NOT_DECLARE = re.compile("Non-Symbol/Function `.+` will not be declared.", re.IGNORECASE)
24
+ WILL_NOT_ASSERT = re.compile("Non-Boolean expression `.+` will not be asserted. Converting to SMTLib verbatim.", re.IGNORECASE)
25
+
26
+
27
+ @contextlib.contextmanager
28
+ def _check_warns(expected: typing.Iterable[_W]):
29
+ warns: typing.List[str] = []
30
+ log_warn = warns.append
31
+ yield log_warn
32
+
33
+ errors = []
34
+ for i, (w, e) in enumerate(itertools.zip_longest(warns, expected)):
35
+ if not e:
36
+ errors += [f"[{i}] Received unexpected warning `{w}`."]
37
+ elif not w:
38
+ errors += [f"[{i}] Did not receive expected warning `{e.name}`."]
39
+ elif not e.value.match(w):
40
+ errors += [f"[{i}] Warning `{w}` does not match expected {e.name}."]
41
+
42
+ if errors: raise Failed('\n'.join(errors))
43
+
44
+
45
+ def test_Integer():
46
+ with _check_warns([_W.WILL_NOT_ASSERT] * 2) as w:
47
+ assert smtlib_code(Integer(67), log_warn=w) == "67"
48
+ assert smtlib_code(Integer(-1), log_warn=w) == "-1"
49
+ with _check_warns([]) as w:
50
+ assert smtlib_code(Integer(67)) == "67"
51
+ assert smtlib_code(Integer(-1)) == "-1"
52
+
53
+
54
+ def test_Rational():
55
+ with _check_warns([_W.WILL_NOT_ASSERT] * 4) as w:
56
+ assert smtlib_code(Rational(3, 7), log_warn=w) == "(/ 3 7)"
57
+ assert smtlib_code(Rational(18, 9), log_warn=w) == "2"
58
+ assert smtlib_code(Rational(3, -7), log_warn=w) == "(/ -3 7)"
59
+ assert smtlib_code(Rational(-3, -7), log_warn=w) == "(/ 3 7)"
60
+
61
+ with _check_warns([_W.DEFAULTING_TO_FLOAT, _W.WILL_NOT_ASSERT] * 2) as w:
62
+ assert smtlib_code(x + Rational(3, 7), auto_declare=False, log_warn=w) == "(+ (/ 3 7) x)"
63
+ assert smtlib_code(Rational(3, 7) * x, log_warn=w) == "(declare-const x Real)\n" \
64
+ "(* (/ 3 7) x)"
65
+
66
+
67
+ def test_Relational():
68
+ with _check_warns([_W.DEFAULTING_TO_FLOAT] * 12) as w:
69
+ assert smtlib_code(Eq(x, y), auto_declare=False, log_warn=w) == "(assert (= x y))"
70
+ assert smtlib_code(Ne(x, y), auto_declare=False, log_warn=w) == "(assert (not (= x y)))"
71
+ assert smtlib_code(Le(x, y), auto_declare=False, log_warn=w) == "(assert (<= x y))"
72
+ assert smtlib_code(Lt(x, y), auto_declare=False, log_warn=w) == "(assert (< x y))"
73
+ assert smtlib_code(Gt(x, y), auto_declare=False, log_warn=w) == "(assert (> x y))"
74
+ assert smtlib_code(Ge(x, y), auto_declare=False, log_warn=w) == "(assert (>= x y))"
75
+
76
+
77
+ def test_AppliedBinaryRelation():
78
+ with _check_warns([_W.DEFAULTING_TO_FLOAT] * 12) as w:
79
+ assert smtlib_code(Q.eq(x, y), auto_declare=False, log_warn=w) == "(assert (= x y))"
80
+ assert smtlib_code(Q.ne(x, y), auto_declare=False, log_warn=w) == "(assert (not (= x y)))"
81
+ assert smtlib_code(Q.lt(x, y), auto_declare=False, log_warn=w) == "(assert (< x y))"
82
+ assert smtlib_code(Q.le(x, y), auto_declare=False, log_warn=w) == "(assert (<= x y))"
83
+ assert smtlib_code(Q.gt(x, y), auto_declare=False, log_warn=w) == "(assert (> x y))"
84
+ assert smtlib_code(Q.ge(x, y), auto_declare=False, log_warn=w) == "(assert (>= x y))"
85
+
86
+ raises(ValueError, lambda: smtlib_code(Q.complex(x), log_warn=w))
87
+
88
+
89
+ def test_AppliedPredicate():
90
+ with _check_warns([_W.DEFAULTING_TO_FLOAT] * 6) as w:
91
+ assert smtlib_code(Q.positive(x), auto_declare=False, log_warn=w) == "(assert (> x 0))"
92
+ assert smtlib_code(Q.negative(x), auto_declare=False, log_warn=w) == "(assert (< x 0))"
93
+ assert smtlib_code(Q.zero(x), auto_declare=False, log_warn=w) == "(assert (= x 0))"
94
+ assert smtlib_code(Q.nonpositive(x), auto_declare=False, log_warn=w) == "(assert (<= x 0))"
95
+ assert smtlib_code(Q.nonnegative(x), auto_declare=False, log_warn=w) == "(assert (>= x 0))"
96
+ assert smtlib_code(Q.nonzero(x), auto_declare=False, log_warn=w) == "(assert (not (= x 0)))"
97
+
98
+ def test_Function():
99
+ with _check_warns([_W.DEFAULTING_TO_FLOAT, _W.WILL_NOT_ASSERT]) as w:
100
+ assert smtlib_code(sin(x) ** cos(x), auto_declare=False, log_warn=w) == "(pow (sin x) (cos x))"
101
+
102
+ with _check_warns([_W.WILL_NOT_ASSERT]) as w:
103
+ assert smtlib_code(
104
+ abs(x),
105
+ symbol_table={x: int, y: bool},
106
+ known_types={int: "INTEGER_TYPE"},
107
+ known_functions={sympy.Abs: "ABSOLUTE_VALUE_OF"},
108
+ log_warn=w
109
+ ) == "(declare-const x INTEGER_TYPE)\n" \
110
+ "(ABSOLUTE_VALUE_OF x)"
111
+
112
+ my_fun1 = Function('f1')
113
+ with _check_warns([_W.WILL_NOT_ASSERT]) as w:
114
+ assert smtlib_code(
115
+ my_fun1(x),
116
+ symbol_table={my_fun1: Callable[[bool], float]},
117
+ log_warn=w
118
+ ) == "(declare-const x Bool)\n" \
119
+ "(declare-fun f1 (Bool) Real)\n" \
120
+ "(f1 x)"
121
+
122
+ with _check_warns([]) as w:
123
+ assert smtlib_code(
124
+ my_fun1(x),
125
+ symbol_table={my_fun1: Callable[[bool], bool]},
126
+ log_warn=w
127
+ ) == "(declare-const x Bool)\n" \
128
+ "(declare-fun f1 (Bool) Bool)\n" \
129
+ "(assert (f1 x))"
130
+
131
+ assert smtlib_code(
132
+ Eq(my_fun1(x, z), y),
133
+ symbol_table={my_fun1: Callable[[int, bool], bool]},
134
+ log_warn=w
135
+ ) == "(declare-const x Int)\n" \
136
+ "(declare-const y Bool)\n" \
137
+ "(declare-const z Bool)\n" \
138
+ "(declare-fun f1 (Int Bool) Bool)\n" \
139
+ "(assert (= (f1 x z) y))"
140
+
141
+ assert smtlib_code(
142
+ Eq(my_fun1(x, z), y),
143
+ symbol_table={my_fun1: Callable[[int, bool], bool]},
144
+ known_functions={my_fun1: "MY_KNOWN_FUN", Eq: '=='},
145
+ log_warn=w
146
+ ) == "(declare-const x Int)\n" \
147
+ "(declare-const y Bool)\n" \
148
+ "(declare-const z Bool)\n" \
149
+ "(assert (== (MY_KNOWN_FUN x z) y))"
150
+
151
+ with _check_warns([_W.DEFAULTING_TO_FLOAT] * 3) as w:
152
+ assert smtlib_code(
153
+ Eq(my_fun1(x, z), y),
154
+ known_functions={my_fun1: "MY_KNOWN_FUN", Eq: '=='},
155
+ log_warn=w
156
+ ) == "(declare-const x Real)\n" \
157
+ "(declare-const y Real)\n" \
158
+ "(declare-const z Real)\n" \
159
+ "(assert (== (MY_KNOWN_FUN x z) y))"
160
+
161
+
162
+ def test_Pow():
163
+ with _check_warns([_W.DEFAULTING_TO_FLOAT, _W.WILL_NOT_ASSERT]) as w:
164
+ assert smtlib_code(x ** 3, auto_declare=False, log_warn=w) == "(pow x 3)"
165
+ with _check_warns([_W.DEFAULTING_TO_FLOAT, _W.DEFAULTING_TO_FLOAT, _W.WILL_NOT_ASSERT]) as w:
166
+ assert smtlib_code(x ** (y ** 3), auto_declare=False, log_warn=w) == "(pow x (pow y 3))"
167
+ with _check_warns([_W.DEFAULTING_TO_FLOAT, _W.WILL_NOT_ASSERT]) as w:
168
+ assert smtlib_code(x ** Rational(2, 3), auto_declare=False, log_warn=w) == '(pow x (/ 2 3))'
169
+
170
+ a = Symbol('a', integer=True)
171
+ b = Symbol('b', real=True)
172
+ c = Symbol('c')
173
+
174
+ def g(x): return 2 * x
175
+
176
+ # if x=1, y=2, then expr=2.333...
177
+ expr = 1 / (g(a) * 3.5) ** (a - b ** a) / (a ** 2 + b)
178
+
179
+ with _check_warns([]) as w:
180
+ assert smtlib_code(
181
+ [
182
+ Eq(a < 2, c),
183
+ Eq(b > a, c),
184
+ c & True,
185
+ Eq(expr, 2 + Rational(1, 3))
186
+ ],
187
+ log_warn=w
188
+ ) == '(declare-const a Int)\n' \
189
+ '(declare-const b Real)\n' \
190
+ '(declare-const c Bool)\n' \
191
+ '(assert (= (< a 2) c))\n' \
192
+ '(assert (= (> b a) c))\n' \
193
+ '(assert c)\n' \
194
+ '(assert (= ' \
195
+ '(* (pow (* 7.0 a) (+ (pow b a) (* -1 a))) (pow (+ b (pow a 2)) -1)) ' \
196
+ '(/ 7 3)' \
197
+ '))'
198
+
199
+ with _check_warns([_W.DEFAULTING_TO_FLOAT, _W.WILL_NOT_ASSERT]) as w:
200
+ assert smtlib_code(
201
+ Mul(-2, c, Pow(Mul(b, b, evaluate=False), -1, evaluate=False), evaluate=False),
202
+ log_warn=w
203
+ ) == '(declare-const b Real)\n' \
204
+ '(declare-const c Real)\n' \
205
+ '(* -2 c (pow (* b b) -1))'
206
+
207
+
208
+ def test_basic_ops():
209
+ with _check_warns([_W.DEFAULTING_TO_FLOAT, _W.DEFAULTING_TO_FLOAT, _W.WILL_NOT_ASSERT]) as w:
210
+ assert smtlib_code(x * y, auto_declare=False, log_warn=w) == "(* x y)"
211
+
212
+ with _check_warns([_W.DEFAULTING_TO_FLOAT, _W.DEFAULTING_TO_FLOAT, _W.WILL_NOT_ASSERT]) as w:
213
+ assert smtlib_code(x + y, auto_declare=False, log_warn=w) == "(+ x y)"
214
+
215
+ # with _check_warns([_SmtlibWarnings.DEFAULTING_TO_FLOAT, _SmtlibWarnings.DEFAULTING_TO_FLOAT, _SmtlibWarnings.WILL_NOT_ASSERT]) as w:
216
+ # todo: implement re-write, currently does '(+ x (* -1 y))' instead
217
+ # assert smtlib_code(x - y, auto_declare=False, log_warn=w) == "(- x y)"
218
+
219
+ with _check_warns([_W.DEFAULTING_TO_FLOAT, _W.WILL_NOT_ASSERT]) as w:
220
+ assert smtlib_code(-x, auto_declare=False, log_warn=w) == "(* -1 x)"
221
+
222
+
223
+ def test_quantifier_extensions():
224
+ from sympy.logic.boolalg import Boolean
225
+ from sympy import Interval, Tuple, sympify
226
+
227
+ # start For-all quantifier class example
228
+ class ForAll(Boolean):
229
+ def _smtlib(self, printer):
230
+ bound_symbol_declarations = [
231
+ printer._s_expr(sym.name, [
232
+ printer._known_types[printer.symbol_table[sym]],
233
+ Interval(start, end)
234
+ ]) for sym, start, end in self.limits
235
+ ]
236
+ return printer._s_expr('forall', [
237
+ printer._s_expr('', bound_symbol_declarations),
238
+ self.function
239
+ ])
240
+
241
+ @property
242
+ def bound_symbols(self):
243
+ return {s for s, _, _ in self.limits}
244
+
245
+ @property
246
+ def free_symbols(self):
247
+ bound_symbol_names = {s.name for s in self.bound_symbols}
248
+ return {
249
+ s for s in self.function.free_symbols
250
+ if s.name not in bound_symbol_names
251
+ }
252
+
253
+ def __new__(cls, *args):
254
+ limits = [sympify(a) for a in args if isinstance(a, (tuple, Tuple))]
255
+ function = [sympify(a) for a in args if isinstance(a, Boolean)]
256
+ assert len(limits) + len(function) == len(args)
257
+ assert len(function) == 1
258
+ function = function[0]
259
+
260
+ if isinstance(function, ForAll): return ForAll.__new__(
261
+ ForAll, *(limits + function.limits), function.function
262
+ )
263
+ inst = Boolean.__new__(cls)
264
+ inst._args = tuple(limits + [function])
265
+ inst.limits = limits
266
+ inst.function = function
267
+ return inst
268
+
269
+ # end For-All Quantifier class example
270
+
271
+ f = Function('f')
272
+ with _check_warns([_W.DEFAULTING_TO_FLOAT]) as w:
273
+ assert smtlib_code(
274
+ ForAll((x, -42, +21), Eq(f(x), f(x))),
275
+ symbol_table={f: Callable[[float], float]},
276
+ log_warn=w
277
+ ) == '(assert (forall ( (x Real [-42, 21])) true))'
278
+
279
+ with _check_warns([_W.DEFAULTING_TO_FLOAT] * 2) as w:
280
+ assert smtlib_code(
281
+ ForAll(
282
+ (x, -42, +21), (y, -100, 3),
283
+ Implies(Eq(x, y), Eq(f(x), f(y)))
284
+ ),
285
+ symbol_table={f: Callable[[float], float]},
286
+ log_warn=w
287
+ ) == '(declare-fun f (Real) Real)\n' \
288
+ '(assert (' \
289
+ 'forall ( (x Real [-42, 21]) (y Real [-100, 3])) ' \
290
+ '(=> (= x y) (= (f x) (f y)))' \
291
+ '))'
292
+
293
+ a = Symbol('a', integer=True)
294
+ b = Symbol('b', real=True)
295
+ c = Symbol('c')
296
+
297
+ with _check_warns([]) as w:
298
+ assert smtlib_code(
299
+ ForAll(
300
+ (a, 2, 100), ForAll(
301
+ (b, 2, 100),
302
+ Implies(a < b, sqrt(a) < b) | c
303
+ )),
304
+ log_warn=w
305
+ ) == '(declare-const c Bool)\n' \
306
+ '(assert (forall ( (a Int [2, 100]) (b Real [2, 100])) ' \
307
+ '(or c (=> (< a b) (< (pow a (/ 1 2)) b)))' \
308
+ '))'
309
+
310
+
311
+ def test_mix_number_mult_symbols():
312
+ with _check_warns([_W.WILL_NOT_ASSERT]) as w:
313
+ assert smtlib_code(
314
+ 1 / pi,
315
+ known_constants={pi: "MY_PI"},
316
+ log_warn=w
317
+ ) == '(pow MY_PI -1)'
318
+
319
+ with _check_warns([_W.WILL_NOT_ASSERT]) as w:
320
+ assert smtlib_code(
321
+ [
322
+ Eq(pi, 3.14, evaluate=False),
323
+ 1 / pi,
324
+ ],
325
+ known_constants={pi: "MY_PI"},
326
+ log_warn=w
327
+ ) == '(assert (= MY_PI 3.14))\n' \
328
+ '(pow MY_PI -1)'
329
+
330
+ with _check_warns([_W.WILL_NOT_ASSERT]) as w:
331
+ assert smtlib_code(
332
+ Add(S.Zero, S.One, S.NegativeOne, S.Half,
333
+ S.Exp1, S.Pi, S.GoldenRatio, evaluate=False),
334
+ known_constants={
335
+ S.Pi: 'p', S.GoldenRatio: 'g',
336
+ S.Exp1: 'e'
337
+ },
338
+ known_functions={
339
+ Add: 'plus',
340
+ exp: 'exp'
341
+ },
342
+ precision=3,
343
+ log_warn=w
344
+ ) == '(plus 0 1 -1 (/ 1 2) (exp 1) p g)'
345
+
346
+ with _check_warns([_W.WILL_NOT_ASSERT]) as w:
347
+ assert smtlib_code(
348
+ Add(S.Zero, S.One, S.NegativeOne, S.Half,
349
+ S.Exp1, S.Pi, S.GoldenRatio, evaluate=False),
350
+ known_constants={
351
+ S.Pi: 'p'
352
+ },
353
+ known_functions={
354
+ Add: 'plus',
355
+ exp: 'exp'
356
+ },
357
+ precision=3,
358
+ log_warn=w
359
+ ) == '(plus 0 1 -1 (/ 1 2) (exp 1) p 1.62)'
360
+
361
+ with _check_warns([_W.WILL_NOT_ASSERT]) as w:
362
+ assert smtlib_code(
363
+ Add(S.Zero, S.One, S.NegativeOne, S.Half,
364
+ S.Exp1, S.Pi, S.GoldenRatio, evaluate=False),
365
+ known_functions={Add: 'plus'},
366
+ precision=3,
367
+ log_warn=w
368
+ ) == '(plus 0 1 -1 (/ 1 2) 2.72 3.14 1.62)'
369
+
370
+ with _check_warns([_W.WILL_NOT_ASSERT]) as w:
371
+ assert smtlib_code(
372
+ Add(S.Zero, S.One, S.NegativeOne, S.Half,
373
+ S.Exp1, S.Pi, S.GoldenRatio, evaluate=False),
374
+ known_constants={S.Exp1: 'e'},
375
+ known_functions={Add: 'plus'},
376
+ precision=3,
377
+ log_warn=w
378
+ ) == '(plus 0 1 -1 (/ 1 2) e 3.14 1.62)'
379
+
380
+
381
+ def test_boolean():
382
+ with _check_warns([]) as w:
383
+ assert smtlib_code(x & y, log_warn=w) == '(declare-const x Bool)\n' \
384
+ '(declare-const y Bool)\n' \
385
+ '(assert (and x y))'
386
+ assert smtlib_code(x | y, log_warn=w) == '(declare-const x Bool)\n' \
387
+ '(declare-const y Bool)\n' \
388
+ '(assert (or x y))'
389
+ assert smtlib_code(~x, log_warn=w) == '(declare-const x Bool)\n' \
390
+ '(assert (not x))'
391
+ assert smtlib_code(x & y & z, log_warn=w) == '(declare-const x Bool)\n' \
392
+ '(declare-const y Bool)\n' \
393
+ '(declare-const z Bool)\n' \
394
+ '(assert (and x y z))'
395
+
396
+ with _check_warns([_W.DEFAULTING_TO_FLOAT]) as w:
397
+ assert smtlib_code((x & ~y) | (z > 3), log_warn=w) == '(declare-const x Bool)\n' \
398
+ '(declare-const y Bool)\n' \
399
+ '(declare-const z Real)\n' \
400
+ '(assert (or (> z 3) (and x (not y))))'
401
+
402
+ f = Function('f')
403
+ g = Function('g')
404
+ h = Function('h')
405
+ with _check_warns([_W.DEFAULTING_TO_FLOAT]) as w:
406
+ assert smtlib_code(
407
+ [Gt(f(x), y),
408
+ Lt(y, g(z))],
409
+ symbol_table={
410
+ f: Callable[[bool], int], g: Callable[[bool], int],
411
+ }, log_warn=w
412
+ ) == '(declare-const x Bool)\n' \
413
+ '(declare-const y Real)\n' \
414
+ '(declare-const z Bool)\n' \
415
+ '(declare-fun f (Bool) Int)\n' \
416
+ '(declare-fun g (Bool) Int)\n' \
417
+ '(assert (> (f x) y))\n' \
418
+ '(assert (< y (g z)))'
419
+
420
+ with _check_warns([]) as w:
421
+ assert smtlib_code(
422
+ [Eq(f(x), y),
423
+ Lt(y, g(z))],
424
+ symbol_table={
425
+ f: Callable[[bool], int], g: Callable[[bool], int],
426
+ }, log_warn=w
427
+ ) == '(declare-const x Bool)\n' \
428
+ '(declare-const y Int)\n' \
429
+ '(declare-const z Bool)\n' \
430
+ '(declare-fun f (Bool) Int)\n' \
431
+ '(declare-fun g (Bool) Int)\n' \
432
+ '(assert (= (f x) y))\n' \
433
+ '(assert (< y (g z)))'
434
+
435
+ with _check_warns([]) as w:
436
+ assert smtlib_code(
437
+ [Eq(f(x), y),
438
+ Eq(g(f(x)), z),
439
+ Eq(h(g(f(x))), x)],
440
+ symbol_table={
441
+ f: Callable[[float], int],
442
+ g: Callable[[int], bool],
443
+ h: Callable[[bool], float]
444
+ },
445
+ log_warn=w
446
+ ) == '(declare-const x Real)\n' \
447
+ '(declare-const y Int)\n' \
448
+ '(declare-const z Bool)\n' \
449
+ '(declare-fun f (Real) Int)\n' \
450
+ '(declare-fun g (Int) Bool)\n' \
451
+ '(declare-fun h (Bool) Real)\n' \
452
+ '(assert (= (f x) y))\n' \
453
+ '(assert (= (g (f x)) z))\n' \
454
+ '(assert (= (h (g (f x))) x))'
455
+
456
+
457
+ # todo: make smtlib_code support arrays
458
+ # def test_containers():
459
+ # assert julia_code([1, 2, 3, [4, 5, [6, 7]], 8, [9, 10], 11]) == \
460
+ # "Any[1, 2, 3, Any[4, 5, Any[6, 7]], 8, Any[9, 10], 11]"
461
+ # assert julia_code((1, 2, (3, 4))) == "(1, 2, (3, 4))"
462
+ # assert julia_code([1]) == "Any[1]"
463
+ # assert julia_code((1,)) == "(1,)"
464
+ # assert julia_code(Tuple(*[1, 2, 3])) == "(1, 2, 3)"
465
+ # assert julia_code((1, x * y, (3, x ** 2))) == "(1, x .* y, (3, x .^ 2))"
466
+ # # scalar, matrix, empty matrix and empty list
467
+ # assert julia_code((1, eye(3), Matrix(0, 0, []), [])) == "(1, [1 0 0;\n0 1 0;\n0 0 1], zeros(0, 0), Any[])"
468
+
469
+ def test_smtlib_piecewise():
470
+ with _check_warns([_W.DEFAULTING_TO_FLOAT, _W.WILL_NOT_ASSERT]) as w:
471
+ assert smtlib_code(
472
+ Piecewise((x, x < 1),
473
+ (x ** 2, True)),
474
+ auto_declare=False,
475
+ log_warn=w
476
+ ) == '(ite (< x 1) x (pow x 2))'
477
+
478
+ with _check_warns([_W.DEFAULTING_TO_FLOAT, _W.WILL_NOT_ASSERT]) as w:
479
+ assert smtlib_code(
480
+ Piecewise((x ** 2, x < 1),
481
+ (x ** 3, x < 2),
482
+ (x ** 4, x < 3),
483
+ (x ** 5, True)),
484
+ auto_declare=False,
485
+ log_warn=w
486
+ ) == '(ite (< x 1) (pow x 2) ' \
487
+ '(ite (< x 2) (pow x 3) ' \
488
+ '(ite (< x 3) (pow x 4) ' \
489
+ '(pow x 5))))'
490
+
491
+ # Check that Piecewise without a True (default) condition error
492
+ expr = Piecewise((x, x < 1), (x ** 2, x > 1), (sin(x), x > 0))
493
+ with _check_warns([_W.DEFAULTING_TO_FLOAT, _W.WILL_NOT_ASSERT]) as w:
494
+ raises(AssertionError, lambda: smtlib_code(expr, log_warn=w))
495
+
496
+
497
+ def test_smtlib_piecewise_times_const():
498
+ pw = Piecewise((x, x < 1), (x ** 2, True))
499
+ with _check_warns([_W.DEFAULTING_TO_FLOAT, _W.WILL_NOT_ASSERT]) as w:
500
+ assert smtlib_code(2 * pw, log_warn=w) == '(declare-const x Real)\n(* 2 (ite (< x 1) x (pow x 2)))'
501
+ with _check_warns([_W.DEFAULTING_TO_FLOAT, _W.WILL_NOT_ASSERT]) as w:
502
+ assert smtlib_code(pw / x, log_warn=w) == '(declare-const x Real)\n(* (pow x -1) (ite (< x 1) x (pow x 2)))'
503
+ with _check_warns([_W.DEFAULTING_TO_FLOAT, _W.DEFAULTING_TO_FLOAT, _W.WILL_NOT_ASSERT]) as w:
504
+ assert smtlib_code(pw / (x * y), log_warn=w) == '(declare-const x Real)\n(declare-const y Real)\n(* (pow x -1) (pow y -1) (ite (< x 1) x (pow x 2)))'
505
+ with _check_warns([_W.DEFAULTING_TO_FLOAT, _W.WILL_NOT_ASSERT]) as w:
506
+ assert smtlib_code(pw / 3, log_warn=w) == '(declare-const x Real)\n(* (/ 1 3) (ite (< x 1) x (pow x 2)))'
507
+
508
+
509
+ # todo: make smtlib_code support arrays / matrices ?
510
+ # def test_smtlib_matrix_assign_to():
511
+ # A = Matrix([[1, 2, 3]])
512
+ # assert smtlib_code(A, assign_to='a') == "a = [1 2 3]"
513
+ # A = Matrix([[1, 2], [3, 4]])
514
+ # assert smtlib_code(A, assign_to='A') == "A = [1 2;\n3 4]"
515
+
516
+ # def test_julia_matrix_1x1():
517
+ # A = Matrix([[3]])
518
+ # B = MatrixSymbol('B', 1, 1)
519
+ # C = MatrixSymbol('C', 1, 2)
520
+ # assert julia_code(A, assign_to=B) == "B = [3]"
521
+ # raises(ValueError, lambda: julia_code(A, assign_to=C))
522
+
523
+ # def test_julia_matrix_elements():
524
+ # A = Matrix([[x, 2, x * y]])
525
+ # assert julia_code(A[0, 0] ** 2 + A[0, 1] + A[0, 2]) == "x .^ 2 + x .* y + 2"
526
+ # A = MatrixSymbol('AA', 1, 3)
527
+ # assert julia_code(A) == "AA"
528
+ # assert julia_code(A[0, 0] ** 2 + sin(A[0, 1]) + A[0, 2]) == \
529
+ # "sin(AA[1,2]) + AA[1,1] .^ 2 + AA[1,3]"
530
+ # assert julia_code(sum(A)) == "AA[1,1] + AA[1,2] + AA[1,3]"
531
+
532
+ def test_smtlib_boolean():
533
+ with _check_warns([]) as w:
534
+ assert smtlib_code(True, auto_assert=False, log_warn=w) == 'true'
535
+ assert smtlib_code(True, log_warn=w) == '(assert true)'
536
+ assert smtlib_code(S.true, log_warn=w) == '(assert true)'
537
+ assert smtlib_code(S.false, log_warn=w) == '(assert false)'
538
+ assert smtlib_code(False, log_warn=w) == '(assert false)'
539
+ assert smtlib_code(False, auto_assert=False, log_warn=w) == 'false'
540
+
541
+
542
+ def test_not_supported():
543
+ f = Function('f')
544
+ with _check_warns([_W.DEFAULTING_TO_FLOAT, _W.WILL_NOT_ASSERT]) as w:
545
+ raises(KeyError, lambda: smtlib_code(f(x).diff(x), symbol_table={f: Callable[[float], float]}, log_warn=w))
546
+ with _check_warns([_W.WILL_NOT_ASSERT]) as w:
547
+ raises(KeyError, lambda: smtlib_code(S.ComplexInfinity, log_warn=w))
548
+
549
+
550
+ def test_Float():
551
+ assert smtlib_code(0.0) == "0.0"
552
+ assert smtlib_code(0.000000000000000003) == '(* 3.0 (pow 10 -18))'
553
+ assert smtlib_code(5.3) == "5.3"
outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_str.py ADDED
@@ -0,0 +1,1206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy import MatAdd
2
+ from sympy.algebras.quaternion import Quaternion
3
+ from sympy.assumptions.ask import Q
4
+ from sympy.calculus.accumulationbounds import AccumBounds
5
+ from sympy.combinatorics.partitions import Partition
6
+ from sympy.concrete.summations import (Sum, summation)
7
+ from sympy.core.add import Add
8
+ from sympy.core.containers import (Dict, Tuple)
9
+ from sympy.core.expr import UnevaluatedExpr, Expr
10
+ from sympy.core.function import (Derivative, Function, Lambda, Subs, WildFunction)
11
+ from sympy.core.mul import Mul
12
+ from sympy.core import (Catalan, EulerGamma, GoldenRatio, TribonacciConstant)
13
+ from sympy.core.numbers import (E, Float, I, Integer, Rational, nan, oo, pi, zoo)
14
+ from sympy.core.parameters import _exp_is_pow
15
+ from sympy.core.power import Pow
16
+ from sympy.core.relational import (Eq, Rel, Ne)
17
+ from sympy.core.singleton import S
18
+ from sympy.core.symbol import (Dummy, Symbol, Wild, symbols)
19
+ from sympy.functions.combinatorial.factorials import (factorial, factorial2, subfactorial)
20
+ from sympy.functions.elementary.complexes import Abs
21
+ from sympy.functions.elementary.exponential import exp
22
+ from sympy.functions.elementary.miscellaneous import sqrt
23
+ from sympy.functions.elementary.trigonometric import (cos, sin)
24
+ from sympy.functions.special.delta_functions import Heaviside
25
+ from sympy.functions.special.zeta_functions import zeta
26
+ from sympy.integrals.integrals import Integral
27
+ from sympy.logic.boolalg import (Equivalent, false, true, Xor)
28
+ from sympy.matrices.dense import Matrix
29
+ from sympy.matrices.expressions.matexpr import MatrixSymbol
30
+ from sympy.matrices.expressions import Identity
31
+ from sympy.matrices.expressions.slice import MatrixSlice
32
+ from sympy.matrices import SparseMatrix
33
+ from sympy.polys.polytools import factor
34
+ from sympy.series.limits import Limit
35
+ from sympy.series.order import O
36
+ from sympy.sets.sets import (Complement, FiniteSet, Interval, SymmetricDifference)
37
+ from sympy.stats import (Covariance, Expectation, Probability, Variance)
38
+ from sympy.stats.rv import RandomSymbol
39
+ from sympy.external import import_module
40
+ from sympy.physics.control.lti import TransferFunction, Series, Parallel, \
41
+ Feedback, TransferFunctionMatrix, MIMOSeries, MIMOParallel, MIMOFeedback
42
+ from sympy.physics.units import second, joule
43
+ from sympy.polys import (Poly, rootof, RootSum, groebner, ring, field, ZZ, QQ,
44
+ ZZ_I, QQ_I, lex, grlex)
45
+ from sympy.geometry import Point, Circle, Polygon, Ellipse, Triangle
46
+ from sympy.tensor import NDimArray
47
+ from sympy.tensor.array.expressions.array_expressions import ArraySymbol, ArrayElement
48
+
49
+ from sympy.testing.pytest import raises, warns_deprecated_sympy
50
+
51
+ from sympy.printing import sstr, sstrrepr, StrPrinter
52
+ from sympy.physics.quantum.trace import Tr
53
+
54
+ x, y, z, w, t = symbols('x,y,z,w,t')
55
+ d = Dummy('d')
56
+
57
+
58
+ def test_printmethod():
59
+ class R(Abs):
60
+ def _sympystr(self, printer):
61
+ return "foo(%s)" % printer._print(self.args[0])
62
+ assert sstr(R(x)) == "foo(x)"
63
+
64
+ class R(Abs):
65
+ def _sympystr(self, printer):
66
+ return "foo"
67
+ assert sstr(R(x)) == "foo"
68
+
69
+
70
+ def test_Abs():
71
+ assert str(Abs(x)) == "Abs(x)"
72
+ assert str(Abs(Rational(1, 6))) == "1/6"
73
+ assert str(Abs(Rational(-1, 6))) == "1/6"
74
+
75
+
76
+ def test_Add():
77
+ assert str(x + y) == "x + y"
78
+ assert str(x + 1) == "x + 1"
79
+ assert str(x + x**2) == "x**2 + x"
80
+ assert str(Add(0, 1, evaluate=False)) == "0 + 1"
81
+ assert str(Add(0, 0, 1, evaluate=False)) == "0 + 0 + 1"
82
+ assert str(1.0*x) == "1.0*x"
83
+ assert str(5 + x + y + x*y + x**2 + y**2) == "x**2 + x*y + x + y**2 + y + 5"
84
+ assert str(1 + x + x**2/2 + x**3/3) == "x**3/3 + x**2/2 + x + 1"
85
+ assert str(2*x - 7*x**2 + 2 + 3*y) == "-7*x**2 + 2*x + 3*y + 2"
86
+ assert str(x - y) == "x - y"
87
+ assert str(2 - x) == "2 - x"
88
+ assert str(x - 2) == "x - 2"
89
+ assert str(x - y - z - w) == "-w + x - y - z"
90
+ assert str(x - z*y**2*z*w) == "-w*y**2*z**2 + x"
91
+ assert str(x - 1*y*x*y) == "-x*y**2 + x"
92
+ assert str(sin(x).series(x, 0, 15)) == "x - x**3/6 + x**5/120 - x**7/5040 + x**9/362880 - x**11/39916800 + x**13/6227020800 + O(x**15)"
93
+ assert str(Add(Add(-w, x, evaluate=False), Add(-y, z, evaluate=False), evaluate=False)) == "(-w + x) + (-y + z)"
94
+ assert str(Add(Add(-x, -y, evaluate=False), -z, evaluate=False)) == "-z + (-x - y)"
95
+ assert str(Add(Add(Add(-x, -y, evaluate=False), -z, evaluate=False), -t, evaluate=False)) == "-t + (-z + (-x - y))"
96
+
97
+
98
+ def test_Catalan():
99
+ assert str(Catalan) == "Catalan"
100
+
101
+
102
+ def test_ComplexInfinity():
103
+ assert str(zoo) == "zoo"
104
+
105
+
106
+ def test_Derivative():
107
+ assert str(Derivative(x, y)) == "Derivative(x, y)"
108
+ assert str(Derivative(x**2, x, evaluate=False)) == "Derivative(x**2, x)"
109
+ assert str(Derivative(
110
+ x**2/y, x, y, evaluate=False)) == "Derivative(x**2/y, x, y)"
111
+
112
+
113
+ def test_dict():
114
+ assert str({1: 1 + x}) == sstr({1: 1 + x}) == "{1: x + 1}"
115
+ assert str({1: x**2, 2: y*x}) in ("{1: x**2, 2: x*y}", "{2: x*y, 1: x**2}")
116
+ assert sstr({1: x**2, 2: y*x}) == "{1: x**2, 2: x*y}"
117
+
118
+
119
+ def test_Dict():
120
+ assert str(Dict({1: 1 + x})) == sstr({1: 1 + x}) == "{1: x + 1}"
121
+ assert str(Dict({1: x**2, 2: y*x})) in (
122
+ "{1: x**2, 2: x*y}", "{2: x*y, 1: x**2}")
123
+ assert sstr(Dict({1: x**2, 2: y*x})) == "{1: x**2, 2: x*y}"
124
+
125
+
126
+ def test_Dummy():
127
+ assert str(d) == "_d"
128
+ assert str(d + x) == "_d + x"
129
+
130
+
131
+ def test_EulerGamma():
132
+ assert str(EulerGamma) == "EulerGamma"
133
+
134
+
135
+ def test_Exp():
136
+ assert str(E) == "E"
137
+ with _exp_is_pow(True):
138
+ assert str(exp(x)) == "E**x"
139
+
140
+
141
+ def test_factorial():
142
+ n = Symbol('n', integer=True)
143
+ assert str(factorial(-2)) == "zoo"
144
+ assert str(factorial(0)) == "1"
145
+ assert str(factorial(7)) == "5040"
146
+ assert str(factorial(n)) == "factorial(n)"
147
+ assert str(factorial(2*n)) == "factorial(2*n)"
148
+ assert str(factorial(factorial(n))) == 'factorial(factorial(n))'
149
+ assert str(factorial(factorial2(n))) == 'factorial(factorial2(n))'
150
+ assert str(factorial2(factorial(n))) == 'factorial2(factorial(n))'
151
+ assert str(factorial2(factorial2(n))) == 'factorial2(factorial2(n))'
152
+ assert str(subfactorial(3)) == "2"
153
+ assert str(subfactorial(n)) == "subfactorial(n)"
154
+ assert str(subfactorial(2*n)) == "subfactorial(2*n)"
155
+
156
+
157
+ def test_Function():
158
+ f = Function('f')
159
+ fx = f(x)
160
+ w = WildFunction('w')
161
+ assert str(f) == "f"
162
+ assert str(fx) == "f(x)"
163
+ assert str(w) == "w_"
164
+
165
+
166
+ def test_Geometry():
167
+ assert sstr(Point(0, 0)) == 'Point2D(0, 0)'
168
+ assert sstr(Circle(Point(0, 0), 3)) == 'Circle(Point2D(0, 0), 3)'
169
+ assert sstr(Ellipse(Point(1, 2), 3, 4)) == 'Ellipse(Point2D(1, 2), 3, 4)'
170
+ assert sstr(Triangle(Point(1, 1), Point(7, 8), Point(0, -1))) == \
171
+ 'Triangle(Point2D(1, 1), Point2D(7, 8), Point2D(0, -1))'
172
+ assert sstr(Polygon(Point(5, 6), Point(-2, -3), Point(0, 0), Point(4, 7))) == \
173
+ 'Polygon(Point2D(5, 6), Point2D(-2, -3), Point2D(0, 0), Point2D(4, 7))'
174
+ assert sstr(Triangle(Point(0, 0), Point(1, 0), Point(0, 1)), sympy_integers=True) == \
175
+ 'Triangle(Point2D(S(0), S(0)), Point2D(S(1), S(0)), Point2D(S(0), S(1)))'
176
+ assert sstr(Ellipse(Point(1, 2), 3, 4), sympy_integers=True) == \
177
+ 'Ellipse(Point2D(S(1), S(2)), S(3), S(4))'
178
+
179
+
180
+ def test_GoldenRatio():
181
+ assert str(GoldenRatio) == "GoldenRatio"
182
+
183
+
184
+ def test_Heaviside():
185
+ assert str(Heaviside(x)) == str(Heaviside(x, S.Half)) == "Heaviside(x)"
186
+ assert str(Heaviside(x, 1)) == "Heaviside(x, 1)"
187
+
188
+
189
+ def test_TribonacciConstant():
190
+ assert str(TribonacciConstant) == "TribonacciConstant"
191
+
192
+
193
+ def test_ImaginaryUnit():
194
+ assert str(I) == "I"
195
+
196
+
197
+ def test_Infinity():
198
+ assert str(oo) == "oo"
199
+ assert str(oo*I) == "oo*I"
200
+
201
+
202
+ def test_Integer():
203
+ assert str(Integer(-1)) == "-1"
204
+ assert str(Integer(1)) == "1"
205
+ assert str(Integer(-3)) == "-3"
206
+ assert str(Integer(0)) == "0"
207
+ assert str(Integer(25)) == "25"
208
+
209
+
210
+ def test_Integral():
211
+ assert str(Integral(sin(x), y)) == "Integral(sin(x), y)"
212
+ assert str(Integral(sin(x), (y, 0, 1))) == "Integral(sin(x), (y, 0, 1))"
213
+
214
+
215
+ def test_Interval():
216
+ n = (S.NegativeInfinity, 1, 2, S.Infinity)
217
+ for i in range(len(n)):
218
+ for j in range(i + 1, len(n)):
219
+ for l in (True, False):
220
+ for r in (True, False):
221
+ ival = Interval(n[i], n[j], l, r)
222
+ assert S(str(ival)) == ival
223
+
224
+
225
+ def test_AccumBounds():
226
+ a = Symbol('a', real=True)
227
+ assert str(AccumBounds(0, a)) == "AccumBounds(0, a)"
228
+ assert str(AccumBounds(0, 1)) == "AccumBounds(0, 1)"
229
+
230
+
231
+ def test_Lambda():
232
+ assert str(Lambda(d, d**2)) == "Lambda(_d, _d**2)"
233
+ # issue 2908
234
+ assert str(Lambda((), 1)) == "Lambda((), 1)"
235
+ assert str(Lambda((), x)) == "Lambda((), x)"
236
+ assert str(Lambda((x, y), x+y)) == "Lambda((x, y), x + y)"
237
+ assert str(Lambda(((x, y),), x+y)) == "Lambda(((x, y),), x + y)"
238
+
239
+
240
+ def test_Limit():
241
+ assert str(Limit(sin(x)/x, x, y)) == "Limit(sin(x)/x, x, y, dir='+')"
242
+ assert str(Limit(1/x, x, 0)) == "Limit(1/x, x, 0, dir='+')"
243
+ assert str(
244
+ Limit(sin(x)/x, x, y, dir="-")) == "Limit(sin(x)/x, x, y, dir='-')"
245
+
246
+
247
+ def test_list():
248
+ assert str([x]) == sstr([x]) == "[x]"
249
+ assert str([x**2, x*y + 1]) == sstr([x**2, x*y + 1]) == "[x**2, x*y + 1]"
250
+ assert str([x**2, [y + x]]) == sstr([x**2, [y + x]]) == "[x**2, [x + y]]"
251
+
252
+
253
+ def test_Matrix_str():
254
+ M = Matrix([[x**+1, 1], [y, x + y]])
255
+ assert str(M) == "Matrix([[x, 1], [y, x + y]])"
256
+ assert sstr(M) == "Matrix([\n[x, 1],\n[y, x + y]])"
257
+ M = Matrix([[1]])
258
+ assert str(M) == sstr(M) == "Matrix([[1]])"
259
+ M = Matrix([[1, 2]])
260
+ assert str(M) == sstr(M) == "Matrix([[1, 2]])"
261
+ M = Matrix()
262
+ assert str(M) == sstr(M) == "Matrix(0, 0, [])"
263
+ M = Matrix(0, 1, lambda i, j: 0)
264
+ assert str(M) == sstr(M) == "Matrix(0, 1, [])"
265
+
266
+
267
+ def test_Mul():
268
+ assert str(x/y) == "x/y"
269
+ assert str(y/x) == "y/x"
270
+ assert str(x/y/z) == "x/(y*z)"
271
+ assert str((x + 1)/(y + 2)) == "(x + 1)/(y + 2)"
272
+ assert str(2*x/3) == '2*x/3'
273
+ assert str(-2*x/3) == '-2*x/3'
274
+ assert str(-1.0*x) == '-1.0*x'
275
+ assert str(1.0*x) == '1.0*x'
276
+ assert str(Mul(0, 1, evaluate=False)) == '0*1'
277
+ assert str(Mul(1, 0, evaluate=False)) == '1*0'
278
+ assert str(Mul(1, 1, evaluate=False)) == '1*1'
279
+ assert str(Mul(1, 1, 1, evaluate=False)) == '1*1*1'
280
+ assert str(Mul(1, 2, evaluate=False)) == '1*2'
281
+ assert str(Mul(1, S.Half, evaluate=False)) == '1*(1/2)'
282
+ assert str(Mul(1, 1, S.Half, evaluate=False)) == '1*1*(1/2)'
283
+ assert str(Mul(1, 1, 2, 3, x, evaluate=False)) == '1*1*2*3*x'
284
+ assert str(Mul(1, -1, evaluate=False)) == '1*(-1)'
285
+ assert str(Mul(-1, 1, evaluate=False)) == '-1*1'
286
+ assert str(Mul(4, 3, 2, 1, 0, y, x, evaluate=False)) == '4*3*2*1*0*y*x'
287
+ assert str(Mul(4, 3, 2, 1+z, 0, y, x, evaluate=False)) == '4*3*2*(z + 1)*0*y*x'
288
+ assert str(Mul(Rational(2, 3), Rational(5, 7), evaluate=False)) == '(2/3)*(5/7)'
289
+ # For issue 14160
290
+ assert str(Mul(-2, x, Pow(Mul(y,y,evaluate=False), -1, evaluate=False),
291
+ evaluate=False)) == '-2*x/(y*y)'
292
+ # issue 21537
293
+ assert str(Mul(x, Pow(1/y, -1, evaluate=False), evaluate=False)) == 'x/(1/y)'
294
+
295
+ # Issue 24108
296
+ from sympy.core.parameters import evaluate
297
+ with evaluate(False):
298
+ assert str(Mul(Pow(Integer(2), Integer(-1)), Add(Integer(-1), Mul(Integer(-1), Integer(1))))) == "(-1 - 1*1)/2"
299
+
300
+ class CustomClass1(Expr):
301
+ is_commutative = True
302
+
303
+ class CustomClass2(Expr):
304
+ is_commutative = True
305
+ cc1 = CustomClass1()
306
+ cc2 = CustomClass2()
307
+ assert str(Rational(2)*cc1) == '2*CustomClass1()'
308
+ assert str(cc1*Rational(2)) == '2*CustomClass1()'
309
+ assert str(cc1*Float("1.5")) == '1.5*CustomClass1()'
310
+ assert str(cc2*Rational(2)) == '2*CustomClass2()'
311
+ assert str(cc2*Rational(2)*cc1) == '2*CustomClass1()*CustomClass2()'
312
+ assert str(cc1*Rational(2)*cc2) == '2*CustomClass1()*CustomClass2()'
313
+
314
+
315
+ def test_NaN():
316
+ assert str(nan) == "nan"
317
+
318
+
319
+ def test_NegativeInfinity():
320
+ assert str(-oo) == "-oo"
321
+
322
+ def test_Order():
323
+ assert str(O(x)) == "O(x)"
324
+ assert str(O(x**2)) == "O(x**2)"
325
+ assert str(O(x*y)) == "O(x*y, x, y)"
326
+ assert str(O(x, x)) == "O(x)"
327
+ assert str(O(x, (x, 0))) == "O(x)"
328
+ assert str(O(x, (x, oo))) == "O(x, (x, oo))"
329
+ assert str(O(x, x, y)) == "O(x, x, y)"
330
+ assert str(O(x, x, y)) == "O(x, x, y)"
331
+ assert str(O(x, (x, oo), (y, oo))) == "O(x, (x, oo), (y, oo))"
332
+
333
+
334
+ def test_Permutation_Cycle():
335
+ from sympy.combinatorics import Permutation, Cycle
336
+
337
+ # general principle: economically, canonically show all moved elements
338
+ # and the size of the permutation.
339
+
340
+ for p, s in [
341
+ (Cycle(),
342
+ '()'),
343
+ (Cycle(2),
344
+ '(2)'),
345
+ (Cycle(2, 1),
346
+ '(1 2)'),
347
+ (Cycle(1, 2)(5)(6, 7)(10),
348
+ '(1 2)(6 7)(10)'),
349
+ (Cycle(3, 4)(1, 2)(3, 4),
350
+ '(1 2)(4)'),
351
+ ]:
352
+ assert sstr(p) == s
353
+
354
+ for p, s in [
355
+ (Permutation([]),
356
+ 'Permutation([])'),
357
+ (Permutation([], size=1),
358
+ 'Permutation([0])'),
359
+ (Permutation([], size=2),
360
+ 'Permutation([0, 1])'),
361
+ (Permutation([], size=10),
362
+ 'Permutation([], size=10)'),
363
+ (Permutation([1, 0, 2]),
364
+ 'Permutation([1, 0, 2])'),
365
+ (Permutation([1, 0, 2, 3, 4, 5]),
366
+ 'Permutation([1, 0], size=6)'),
367
+ (Permutation([1, 0, 2, 3, 4, 5], size=10),
368
+ 'Permutation([1, 0], size=10)'),
369
+ ]:
370
+ assert sstr(p, perm_cyclic=False) == s
371
+
372
+ for p, s in [
373
+ (Permutation([]),
374
+ '()'),
375
+ (Permutation([], size=1),
376
+ '(0)'),
377
+ (Permutation([], size=2),
378
+ '(1)'),
379
+ (Permutation([], size=10),
380
+ '(9)'),
381
+ (Permutation([1, 0, 2]),
382
+ '(2)(0 1)'),
383
+ (Permutation([1, 0, 2, 3, 4, 5]),
384
+ '(5)(0 1)'),
385
+ (Permutation([1, 0, 2, 3, 4, 5], size=10),
386
+ '(9)(0 1)'),
387
+ (Permutation([0, 1, 3, 2, 4, 5], size=10),
388
+ '(9)(2 3)'),
389
+ ]:
390
+ assert sstr(p) == s
391
+
392
+
393
+ with warns_deprecated_sympy():
394
+ old_print_cyclic = Permutation.print_cyclic
395
+ Permutation.print_cyclic = False
396
+ assert sstr(Permutation([1, 0, 2])) == 'Permutation([1, 0, 2])'
397
+ Permutation.print_cyclic = old_print_cyclic
398
+
399
+ def test_Pi():
400
+ assert str(pi) == "pi"
401
+
402
+
403
+ def test_Poly():
404
+ assert str(Poly(0, x)) == "Poly(0, x, domain='ZZ')"
405
+ assert str(Poly(1, x)) == "Poly(1, x, domain='ZZ')"
406
+ assert str(Poly(x, x)) == "Poly(x, x, domain='ZZ')"
407
+
408
+ assert str(Poly(2*x + 1, x)) == "Poly(2*x + 1, x, domain='ZZ')"
409
+ assert str(Poly(2*x - 1, x)) == "Poly(2*x - 1, x, domain='ZZ')"
410
+
411
+ assert str(Poly(-1, x)) == "Poly(-1, x, domain='ZZ')"
412
+ assert str(Poly(-x, x)) == "Poly(-x, x, domain='ZZ')"
413
+
414
+ assert str(Poly(-2*x + 1, x)) == "Poly(-2*x + 1, x, domain='ZZ')"
415
+ assert str(Poly(-2*x - 1, x)) == "Poly(-2*x - 1, x, domain='ZZ')"
416
+
417
+ assert str(Poly(x - 1, x)) == "Poly(x - 1, x, domain='ZZ')"
418
+ assert str(Poly(2*x + x**5, x)) == "Poly(x**5 + 2*x, x, domain='ZZ')"
419
+
420
+ assert str(Poly(3**(2*x), 3**x)) == "Poly((3**x)**2, 3**x, domain='ZZ')"
421
+ assert str(Poly((x**2)**x)) == "Poly(((x**2)**x), (x**2)**x, domain='ZZ')"
422
+
423
+ assert str(Poly((x + y)**3, (x + y), expand=False)
424
+ ) == "Poly((x + y)**3, x + y, domain='ZZ')"
425
+ assert str(Poly((x - 1)**2, (x - 1), expand=False)
426
+ ) == "Poly((x - 1)**2, x - 1, domain='ZZ')"
427
+
428
+ assert str(
429
+ Poly(x**2 + 1 + y, x)) == "Poly(x**2 + y + 1, x, domain='ZZ[y]')"
430
+ assert str(
431
+ Poly(x**2 - 1 + y, x)) == "Poly(x**2 + y - 1, x, domain='ZZ[y]')"
432
+
433
+ assert str(Poly(x**2 + I*x, x)) == "Poly(x**2 + I*x, x, domain='ZZ_I')"
434
+ assert str(Poly(x**2 - I*x, x)) == "Poly(x**2 - I*x, x, domain='ZZ_I')"
435
+
436
+ assert str(Poly(-x*y*z + x*y - 1, x, y, z)
437
+ ) == "Poly(-x*y*z + x*y - 1, x, y, z, domain='ZZ')"
438
+ assert str(Poly(-w*x**21*y**7*z + (1 + w)*z**3 - 2*x*z + 1, x, y, z)) == \
439
+ "Poly(-w*x**21*y**7*z - 2*x*z + (w + 1)*z**3 + 1, x, y, z, domain='ZZ[w]')"
440
+
441
+ assert str(Poly(x**2 + 1, x, modulus=2)) == "Poly(x**2 + 1, x, modulus=2)"
442
+ assert str(Poly(2*x**2 + 3*x + 4, x, modulus=17)) == "Poly(2*x**2 + 3*x + 4, x, modulus=17)"
443
+
444
+
445
+ def test_PolyRing():
446
+ assert str(ring("x", ZZ, lex)[0]) == "Polynomial ring in x over ZZ with lex order"
447
+ assert str(ring("x,y", QQ, grlex)[0]) == "Polynomial ring in x, y over QQ with grlex order"
448
+ assert str(ring("x,y,z", ZZ["t"], lex)[0]) == "Polynomial ring in x, y, z over ZZ[t] with lex order"
449
+
450
+
451
+ def test_FracField():
452
+ assert str(field("x", ZZ, lex)[0]) == "Rational function field in x over ZZ with lex order"
453
+ assert str(field("x,y", QQ, grlex)[0]) == "Rational function field in x, y over QQ with grlex order"
454
+ assert str(field("x,y,z", ZZ["t"], lex)[0]) == "Rational function field in x, y, z over ZZ[t] with lex order"
455
+
456
+
457
+ def test_PolyElement():
458
+ Ruv, u,v = ring("u,v", ZZ)
459
+ Rxyz, x,y,z = ring("x,y,z", Ruv)
460
+ Rx_zzi, xz = ring("x", ZZ_I)
461
+
462
+ assert str(x - x) == "0"
463
+ assert str(x - 1) == "x - 1"
464
+ assert str(x + 1) == "x + 1"
465
+ assert str(x**2) == "x**2"
466
+
467
+ assert str((u**2 + 3*u*v + 1)*x**2*y + u + 1) == "(u**2 + 3*u*v + 1)*x**2*y + u + 1"
468
+ assert str((u**2 + 3*u*v + 1)*x**2*y + (u + 1)*x) == "(u**2 + 3*u*v + 1)*x**2*y + (u + 1)*x"
469
+ assert str((u**2 + 3*u*v + 1)*x**2*y + (u + 1)*x + 1) == "(u**2 + 3*u*v + 1)*x**2*y + (u + 1)*x + 1"
470
+ assert str((-u**2 + 3*u*v - 1)*x**2*y - (u + 1)*x - 1) == "-(u**2 - 3*u*v + 1)*x**2*y - (u + 1)*x - 1"
471
+
472
+ assert str(-(v**2 + v + 1)*x + 3*u*v + 1) == "-(v**2 + v + 1)*x + 3*u*v + 1"
473
+ assert str(-(v**2 + v + 1)*x - 3*u*v + 1) == "-(v**2 + v + 1)*x - 3*u*v + 1"
474
+
475
+ assert str((1+I)*xz + 2) == "(1 + 1*I)*x + (2 + 0*I)"
476
+
477
+
478
+ def test_FracElement():
479
+ Fuv, u,v = field("u,v", ZZ)
480
+ Fxyzt, x,y,z,t = field("x,y,z,t", Fuv)
481
+ Rx_zzi, xz = field("x", QQ_I)
482
+ i = QQ_I(0, 1)
483
+
484
+ assert str(x - x) == "0"
485
+ assert str(x - 1) == "x - 1"
486
+ assert str(x + 1) == "x + 1"
487
+
488
+ assert str(x/3) == "x/3"
489
+ assert str(x/z) == "x/z"
490
+ assert str(x*y/z) == "x*y/z"
491
+ assert str(x/(z*t)) == "x/(z*t)"
492
+ assert str(x*y/(z*t)) == "x*y/(z*t)"
493
+
494
+ assert str((x - 1)/y) == "(x - 1)/y"
495
+ assert str((x + 1)/y) == "(x + 1)/y"
496
+ assert str((-x - 1)/y) == "(-x - 1)/y"
497
+ assert str((x + 1)/(y*z)) == "(x + 1)/(y*z)"
498
+ assert str(-y/(x + 1)) == "-y/(x + 1)"
499
+ assert str(y*z/(x + 1)) == "y*z/(x + 1)"
500
+
501
+ assert str(((u + 1)*x*y + 1)/((v - 1)*z - 1)) == "((u + 1)*x*y + 1)/((v - 1)*z - 1)"
502
+ assert str(((u + 1)*x*y + 1)/((v - 1)*z - t*u*v - 1)) == "((u + 1)*x*y + 1)/((v - 1)*z - u*v*t - 1)"
503
+
504
+ assert str((1+i)/xz) == "(1 + 1*I)/x"
505
+ assert str(((1+i)*xz - i)/xz) == "((1 + 1*I)*x + (0 + -1*I))/x"
506
+
507
+
508
+ def test_GaussianInteger():
509
+ assert str(ZZ_I(1, 0)) == "1"
510
+ assert str(ZZ_I(-1, 0)) == "-1"
511
+ assert str(ZZ_I(0, 1)) == "I"
512
+ assert str(ZZ_I(0, -1)) == "-I"
513
+ assert str(ZZ_I(0, 2)) == "2*I"
514
+ assert str(ZZ_I(0, -2)) == "-2*I"
515
+ assert str(ZZ_I(1, 1)) == "1 + I"
516
+ assert str(ZZ_I(-1, -1)) == "-1 - I"
517
+ assert str(ZZ_I(-1, -2)) == "-1 - 2*I"
518
+
519
+
520
+ def test_GaussianRational():
521
+ assert str(QQ_I(1, 0)) == "1"
522
+ assert str(QQ_I(QQ(2, 3), 0)) == "2/3"
523
+ assert str(QQ_I(0, QQ(2, 3))) == "2*I/3"
524
+ assert str(QQ_I(QQ(1, 2), QQ(-2, 3))) == "1/2 - 2*I/3"
525
+
526
+
527
+ def test_Pow():
528
+ assert str(x**-1) == "1/x"
529
+ assert str(x**-2) == "x**(-2)"
530
+ assert str(x**2) == "x**2"
531
+ assert str((x + y)**-1) == "1/(x + y)"
532
+ assert str((x + y)**-2) == "(x + y)**(-2)"
533
+ assert str((x + y)**2) == "(x + y)**2"
534
+ assert str((x + y)**(1 + x)) == "(x + y)**(x + 1)"
535
+ assert str(x**Rational(1, 3)) == "x**(1/3)"
536
+ assert str(1/x**Rational(1, 3)) == "x**(-1/3)"
537
+ assert str(sqrt(sqrt(x))) == "x**(1/4)"
538
+ # not the same as x**-1
539
+ assert str(x**-1.0) == 'x**(-1.0)'
540
+ # see issue #2860
541
+ assert str(Pow(S(2), -1.0, evaluate=False)) == '2**(-1.0)'
542
+
543
+
544
+ def test_sqrt():
545
+ assert str(sqrt(x)) == "sqrt(x)"
546
+ assert str(sqrt(x**2)) == "sqrt(x**2)"
547
+ assert str(1/sqrt(x)) == "1/sqrt(x)"
548
+ assert str(1/sqrt(x**2)) == "1/sqrt(x**2)"
549
+ assert str(y/sqrt(x)) == "y/sqrt(x)"
550
+ assert str(x**0.5) == "x**0.5"
551
+ assert str(1/x**0.5) == "x**(-0.5)"
552
+
553
+
554
+ def test_Rational():
555
+ n1 = Rational(1, 4)
556
+ n2 = Rational(1, 3)
557
+ n3 = Rational(2, 4)
558
+ n4 = Rational(2, -4)
559
+ n5 = Rational(0)
560
+ n7 = Rational(3)
561
+ n8 = Rational(-3)
562
+ assert str(n1*n2) == "1/12"
563
+ assert str(n1*n2) == "1/12"
564
+ assert str(n3) == "1/2"
565
+ assert str(n1*n3) == "1/8"
566
+ assert str(n1 + n3) == "3/4"
567
+ assert str(n1 + n2) == "7/12"
568
+ assert str(n1 + n4) == "-1/4"
569
+ assert str(n4*n4) == "1/4"
570
+ assert str(n4 + n2) == "-1/6"
571
+ assert str(n4 + n5) == "-1/2"
572
+ assert str(n4*n5) == "0"
573
+ assert str(n3 + n4) == "0"
574
+ assert str(n1**n7) == "1/64"
575
+ assert str(n2**n7) == "1/27"
576
+ assert str(n2**n8) == "27"
577
+ assert str(n7**n8) == "1/27"
578
+ assert str(Rational("-25")) == "-25"
579
+ assert str(Rational("1.25")) == "5/4"
580
+ assert str(Rational("-2.6e-2")) == "-13/500"
581
+ assert str(S("25/7")) == "25/7"
582
+ assert str(S("-123/569")) == "-123/569"
583
+ assert str(S("0.1[23]", rational=1)) == "61/495"
584
+ assert str(S("5.1[666]", rational=1)) == "31/6"
585
+ assert str(S("-5.1[666]", rational=1)) == "-31/6"
586
+ assert str(S("0.[9]", rational=1)) == "1"
587
+ assert str(S("-0.[9]", rational=1)) == "-1"
588
+
589
+ assert str(sqrt(Rational(1, 4))) == "1/2"
590
+ assert str(sqrt(Rational(1, 36))) == "1/6"
591
+
592
+ assert str((123**25) ** Rational(1, 25)) == "123"
593
+ assert str((123**25 + 1)**Rational(1, 25)) != "123"
594
+ assert str((123**25 - 1)**Rational(1, 25)) != "123"
595
+ assert str((123**25 - 1)**Rational(1, 25)) != "122"
596
+
597
+ assert str(sqrt(Rational(81, 36))**3) == "27/8"
598
+ assert str(1/sqrt(Rational(81, 36))**3) == "8/27"
599
+
600
+ assert str(sqrt(-4)) == str(2*I)
601
+ assert str(2**Rational(1, 10**10)) == "2**(1/10000000000)"
602
+
603
+ assert sstr(Rational(2, 3), sympy_integers=True) == "S(2)/3"
604
+ x = Symbol("x")
605
+ assert sstr(x**Rational(2, 3), sympy_integers=True) == "x**(S(2)/3)"
606
+ assert sstr(Eq(x, Rational(2, 3)), sympy_integers=True) == "Eq(x, S(2)/3)"
607
+ assert sstr(Limit(x, x, Rational(7, 2)), sympy_integers=True) == \
608
+ "Limit(x, x, S(7)/2, dir='+')"
609
+
610
+
611
+ def test_Float():
612
+ # NOTE dps is the whole number of decimal digits
613
+ assert str(Float('1.23', dps=1 + 2)) == '1.23'
614
+ assert str(Float('1.23456789', dps=1 + 8)) == '1.23456789'
615
+ assert str(
616
+ Float('1.234567890123456789', dps=1 + 18)) == '1.234567890123456789'
617
+ assert str(pi.evalf(1 + 2)) == '3.14'
618
+ assert str(pi.evalf(1 + 14)) == '3.14159265358979'
619
+ assert str(pi.evalf(1 + 64)) == ('3.141592653589793238462643383279'
620
+ '5028841971693993751058209749445923')
621
+ assert str(pi.round(-1)) == '0.0'
622
+ assert str((pi**400 - (pi**400).round(1)).n(2)) == '-0.e+88'
623
+ assert sstr(Float("100"), full_prec=False, min=-2, max=2) == '1.0e+2'
624
+ assert sstr(Float("100"), full_prec=False, min=-2, max=3) == '100.0'
625
+ assert sstr(Float("0.1"), full_prec=False, min=-2, max=3) == '0.1'
626
+ assert sstr(Float("0.099"), min=-2, max=3) == '9.90000000000000e-2'
627
+
628
+
629
+ def test_Relational():
630
+ assert str(Rel(x, y, "<")) == "x < y"
631
+ assert str(Rel(x + y, y, "==")) == "Eq(x + y, y)"
632
+ assert str(Rel(x, y, "!=")) == "Ne(x, y)"
633
+ assert str(Eq(x, 1) | Eq(x, 2)) == "Eq(x, 1) | Eq(x, 2)"
634
+ assert str(Ne(x, 1) & Ne(x, 2)) == "Ne(x, 1) & Ne(x, 2)"
635
+
636
+
637
+ def test_AppliedBinaryRelation():
638
+ assert str(Q.eq(x, y)) == "Q.eq(x, y)"
639
+ assert str(Q.ne(x, y)) == "Q.ne(x, y)"
640
+
641
+
642
+ def test_CRootOf():
643
+ assert str(rootof(x**5 + 2*x - 1, 0)) == "CRootOf(x**5 + 2*x - 1, 0)"
644
+
645
+
646
+ def test_RootSum():
647
+ f = x**5 + 2*x - 1
648
+
649
+ assert str(
650
+ RootSum(f, Lambda(z, z), auto=False)) == "RootSum(x**5 + 2*x - 1)"
651
+ assert str(RootSum(f, Lambda(
652
+ z, z**2), auto=False)) == "RootSum(x**5 + 2*x - 1, Lambda(z, z**2))"
653
+
654
+
655
+ def test_GroebnerBasis():
656
+ assert str(groebner(
657
+ [], x, y)) == "GroebnerBasis([], x, y, domain='ZZ', order='lex')"
658
+
659
+ F = [x**2 - 3*y - x + 1, y**2 - 2*x + y - 1]
660
+
661
+ assert str(groebner(F, order='grlex')) == \
662
+ "GroebnerBasis([x**2 - x - 3*y + 1, y**2 - 2*x + y - 1], x, y, domain='ZZ', order='grlex')"
663
+ assert str(groebner(F, order='lex')) == \
664
+ "GroebnerBasis([2*x - y**2 - y + 1, y**4 + 2*y**3 - 3*y**2 - 16*y + 7], x, y, domain='ZZ', order='lex')"
665
+
666
+ def test_set():
667
+ assert sstr(set()) == 'set()'
668
+ assert sstr(frozenset()) == 'frozenset()'
669
+
670
+ assert sstr({1}) == '{1}'
671
+ assert sstr(frozenset([1])) == 'frozenset({1})'
672
+ assert sstr({1, 2, 3}) == '{1, 2, 3}'
673
+ assert sstr(frozenset([1, 2, 3])) == 'frozenset({1, 2, 3})'
674
+
675
+ assert sstr(
676
+ {1, x, x**2, x**3, x**4}) == '{1, x, x**2, x**3, x**4}'
677
+ assert sstr(
678
+ frozenset([1, x, x**2, x**3, x**4])) == 'frozenset({1, x, x**2, x**3, x**4})'
679
+
680
+
681
+ def test_SparseMatrix():
682
+ M = SparseMatrix([[x**+1, 1], [y, x + y]])
683
+ assert str(M) == "Matrix([[x, 1], [y, x + y]])"
684
+ assert sstr(M) == "Matrix([\n[x, 1],\n[y, x + y]])"
685
+
686
+
687
+ def test_Sum():
688
+ assert str(summation(cos(3*z), (z, x, y))) == "Sum(cos(3*z), (z, x, y))"
689
+ assert str(Sum(x*y**2, (x, -2, 2), (y, -5, 5))) == \
690
+ "Sum(x*y**2, (x, -2, 2), (y, -5, 5))"
691
+
692
+
693
+ def test_Symbol():
694
+ assert str(y) == "y"
695
+ assert str(x) == "x"
696
+ e = x
697
+ assert str(e) == "x"
698
+
699
+
700
+ def test_tuple():
701
+ assert str((x,)) == sstr((x,)) == "(x,)"
702
+ assert str((x + y, 1 + x)) == sstr((x + y, 1 + x)) == "(x + y, x + 1)"
703
+ assert str((x + y, (
704
+ 1 + x, x**2))) == sstr((x + y, (1 + x, x**2))) == "(x + y, (x + 1, x**2))"
705
+
706
+
707
+ def test_Series_str():
708
+ tf1 = TransferFunction(x*y**2 - z, y**3 - t**3, y)
709
+ tf2 = TransferFunction(x - y, x + y, y)
710
+ tf3 = TransferFunction(t*x**2 - t**w*x + w, t - y, y)
711
+ assert str(Series(tf1, tf2)) == \
712
+ "Series(TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(x - y, x + y, y))"
713
+ assert str(Series(tf1, tf2, tf3)) == \
714
+ "Series(TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(x - y, x + y, y), TransferFunction(t*x**2 - t**w*x + w, t - y, y))"
715
+ assert str(Series(-tf2, tf1)) == \
716
+ "Series(TransferFunction(-x + y, x + y, y), TransferFunction(x*y**2 - z, -t**3 + y**3, y))"
717
+
718
+
719
+ def test_MIMOSeries_str():
720
+ tf1 = TransferFunction(x*y**2 - z, y**3 - t**3, y)
721
+ tf2 = TransferFunction(x - y, x + y, y)
722
+ tfm_1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]])
723
+ tfm_2 = TransferFunctionMatrix([[tf2, tf1], [tf1, tf2]])
724
+ assert str(MIMOSeries(tfm_1, tfm_2)) == \
725
+ "MIMOSeries(TransferFunctionMatrix(((TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(x - y, x + y, y)), "\
726
+ "(TransferFunction(x - y, x + y, y), TransferFunction(x*y**2 - z, -t**3 + y**3, y)))), "\
727
+ "TransferFunctionMatrix(((TransferFunction(x - y, x + y, y), TransferFunction(x*y**2 - z, -t**3 + y**3, y)), "\
728
+ "(TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(x - y, x + y, y)))))"
729
+
730
+
731
+ def test_TransferFunction_str():
732
+ tf1 = TransferFunction(x - 1, x + 1, x)
733
+ assert str(tf1) == "TransferFunction(x - 1, x + 1, x)"
734
+ tf2 = TransferFunction(x + 1, 2 - y, x)
735
+ assert str(tf2) == "TransferFunction(x + 1, 2 - y, x)"
736
+ tf3 = TransferFunction(y, y**2 + 2*y + 3, y)
737
+ assert str(tf3) == "TransferFunction(y, y**2 + 2*y + 3, y)"
738
+
739
+
740
+ def test_Parallel_str():
741
+ tf1 = TransferFunction(x*y**2 - z, y**3 - t**3, y)
742
+ tf2 = TransferFunction(x - y, x + y, y)
743
+ tf3 = TransferFunction(t*x**2 - t**w*x + w, t - y, y)
744
+ assert str(Parallel(tf1, tf2)) == \
745
+ "Parallel(TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(x - y, x + y, y))"
746
+ assert str(Parallel(tf1, tf2, tf3)) == \
747
+ "Parallel(TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(x - y, x + y, y), TransferFunction(t*x**2 - t**w*x + w, t - y, y))"
748
+ assert str(Parallel(-tf2, tf1)) == \
749
+ "Parallel(TransferFunction(-x + y, x + y, y), TransferFunction(x*y**2 - z, -t**3 + y**3, y))"
750
+
751
+
752
+ def test_MIMOParallel_str():
753
+ tf1 = TransferFunction(x*y**2 - z, y**3 - t**3, y)
754
+ tf2 = TransferFunction(x - y, x + y, y)
755
+ tfm_1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]])
756
+ tfm_2 = TransferFunctionMatrix([[tf2, tf1], [tf1, tf2]])
757
+ assert str(MIMOParallel(tfm_1, tfm_2)) == \
758
+ "MIMOParallel(TransferFunctionMatrix(((TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(x - y, x + y, y)), "\
759
+ "(TransferFunction(x - y, x + y, y), TransferFunction(x*y**2 - z, -t**3 + y**3, y)))), "\
760
+ "TransferFunctionMatrix(((TransferFunction(x - y, x + y, y), TransferFunction(x*y**2 - z, -t**3 + y**3, y)), "\
761
+ "(TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(x - y, x + y, y)))))"
762
+
763
+
764
+ def test_Feedback_str():
765
+ tf1 = TransferFunction(x*y**2 - z, y**3 - t**3, y)
766
+ tf2 = TransferFunction(x - y, x + y, y)
767
+ tf3 = TransferFunction(t*x**2 - t**w*x + w, t - y, y)
768
+ assert str(Feedback(tf1*tf2, tf3)) == \
769
+ "Feedback(Series(TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(x - y, x + y, y)), " \
770
+ "TransferFunction(t*x**2 - t**w*x + w, t - y, y), -1)"
771
+ assert str(Feedback(tf1, TransferFunction(1, 1, y), 1)) == \
772
+ "Feedback(TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(1, 1, y), 1)"
773
+
774
+
775
+ def test_MIMOFeedback_str():
776
+ tf1 = TransferFunction(x**2 - y**3, y - z, x)
777
+ tf2 = TransferFunction(y - x, z + y, x)
778
+ tfm_1 = TransferFunctionMatrix([[tf2, tf1], [tf1, tf2]])
779
+ tfm_2 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]])
780
+ assert (str(MIMOFeedback(tfm_1, tfm_2)) \
781
+ == "MIMOFeedback(TransferFunctionMatrix(((TransferFunction(-x + y, y + z, x), TransferFunction(x**2 - y**3, y - z, x))," \
782
+ " (TransferFunction(x**2 - y**3, y - z, x), TransferFunction(-x + y, y + z, x)))), " \
783
+ "TransferFunctionMatrix(((TransferFunction(x**2 - y**3, y - z, x), " \
784
+ "TransferFunction(-x + y, y + z, x)), (TransferFunction(-x + y, y + z, x), TransferFunction(x**2 - y**3, y - z, x)))), -1)")
785
+ assert (str(MIMOFeedback(tfm_1, tfm_2, 1)) \
786
+ == "MIMOFeedback(TransferFunctionMatrix(((TransferFunction(-x + y, y + z, x), TransferFunction(x**2 - y**3, y - z, x)), " \
787
+ "(TransferFunction(x**2 - y**3, y - z, x), TransferFunction(-x + y, y + z, x)))), " \
788
+ "TransferFunctionMatrix(((TransferFunction(x**2 - y**3, y - z, x), TransferFunction(-x + y, y + z, x)), "\
789
+ "(TransferFunction(-x + y, y + z, x), TransferFunction(x**2 - y**3, y - z, x)))), 1)")
790
+
791
+
792
+ def test_TransferFunctionMatrix_str():
793
+ tf1 = TransferFunction(x*y**2 - z, y**3 - t**3, y)
794
+ tf2 = TransferFunction(x - y, x + y, y)
795
+ tf3 = TransferFunction(t*x**2 - t**w*x + w, t - y, y)
796
+ assert str(TransferFunctionMatrix([[tf1], [tf2]])) == \
797
+ "TransferFunctionMatrix(((TransferFunction(x*y**2 - z, -t**3 + y**3, y),), (TransferFunction(x - y, x + y, y),)))"
798
+ assert str(TransferFunctionMatrix([[tf1, tf2], [tf3, tf2]])) == \
799
+ "TransferFunctionMatrix(((TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(x - y, x + y, y)), (TransferFunction(t*x**2 - t**w*x + w, t - y, y), TransferFunction(x - y, x + y, y))))"
800
+
801
+
802
+ def test_Quaternion_str_printer():
803
+ q = Quaternion(x, y, z, t)
804
+ assert str(q) == "x + y*i + z*j + t*k"
805
+ q = Quaternion(x,y,z,x*t)
806
+ assert str(q) == "x + y*i + z*j + t*x*k"
807
+ q = Quaternion(x,y,z,x+t)
808
+ assert str(q) == "x + y*i + z*j + (t + x)*k"
809
+
810
+
811
+ def test_Quantity_str():
812
+ assert sstr(second, abbrev=True) == "s"
813
+ assert sstr(joule, abbrev=True) == "J"
814
+ assert str(second) == "second"
815
+ assert str(joule) == "joule"
816
+
817
+
818
+ def test_wild_str():
819
+ # Check expressions containing Wild not causing infinite recursion
820
+ w = Wild('x')
821
+ assert str(w + 1) == 'x_ + 1'
822
+ assert str(exp(2**w) + 5) == 'exp(2**x_) + 5'
823
+ assert str(3*w + 1) == '3*x_ + 1'
824
+ assert str(1/w + 1) == '1 + 1/x_'
825
+ assert str(w**2 + 1) == 'x_**2 + 1'
826
+ assert str(1/(1 - w)) == '1/(1 - x_)'
827
+
828
+
829
+ def test_wild_matchpy():
830
+ from sympy.utilities.matchpy_connector import WildDot, WildPlus, WildStar
831
+
832
+ matchpy = import_module("matchpy")
833
+
834
+ if matchpy is None:
835
+ return
836
+
837
+ wd = WildDot('w_')
838
+ wp = WildPlus('w__')
839
+ ws = WildStar('w___')
840
+
841
+ assert str(wd) == 'w_'
842
+ assert str(wp) == 'w__'
843
+ assert str(ws) == 'w___'
844
+
845
+ assert str(wp/ws + 2**wd) == '2**w_ + w__/w___'
846
+ assert str(sin(wd)*cos(wp)*sqrt(ws)) == 'sqrt(w___)*sin(w_)*cos(w__)'
847
+
848
+
849
+ def test_zeta():
850
+ assert str(zeta(3)) == "zeta(3)"
851
+
852
+
853
+ def test_issue_3101():
854
+ e = x - y
855
+ a = str(e)
856
+ b = str(e)
857
+ assert a == b
858
+
859
+
860
+ def test_issue_3103():
861
+ e = -2*sqrt(x) - y/sqrt(x)/2
862
+ assert str(e) not in ["(-2)*x**1/2(-1/2)*x**(-1/2)*y",
863
+ "-2*x**1/2(-1/2)*x**(-1/2)*y", "-2*x**1/2-1/2*x**-1/2*w"]
864
+ assert str(e) == "-2*sqrt(x) - y/(2*sqrt(x))"
865
+
866
+
867
+ def test_issue_4021():
868
+ e = Integral(x, x) + 1
869
+ assert str(e) == 'Integral(x, x) + 1'
870
+
871
+
872
+ def test_sstrrepr():
873
+ assert sstr('abc') == 'abc'
874
+ assert sstrrepr('abc') == "'abc'"
875
+
876
+ e = ['a', 'b', 'c', x]
877
+ assert sstr(e) == "[a, b, c, x]"
878
+ assert sstrrepr(e) == "['a', 'b', 'c', x]"
879
+
880
+
881
+ def test_infinity():
882
+ assert sstr(oo*I) == "oo*I"
883
+
884
+
885
+ def test_full_prec():
886
+ assert sstr(S("0.3"), full_prec=True) == "0.300000000000000"
887
+ assert sstr(S("0.3"), full_prec="auto") == "0.300000000000000"
888
+ assert sstr(S("0.3"), full_prec=False) == "0.3"
889
+ assert sstr(S("0.3")*x, full_prec=True) in [
890
+ "0.300000000000000*x",
891
+ "x*0.300000000000000"
892
+ ]
893
+ assert sstr(S("0.3")*x, full_prec="auto") in [
894
+ "0.3*x",
895
+ "x*0.3"
896
+ ]
897
+ assert sstr(S("0.3")*x, full_prec=False) in [
898
+ "0.3*x",
899
+ "x*0.3"
900
+ ]
901
+
902
+
903
+ def test_noncommutative():
904
+ A, B, C = symbols('A,B,C', commutative=False)
905
+
906
+ assert sstr(A*B*C**-1) == "A*B*C**(-1)"
907
+ assert sstr(C**-1*A*B) == "C**(-1)*A*B"
908
+ assert sstr(A*C**-1*B) == "A*C**(-1)*B"
909
+ assert sstr(sqrt(A)) == "sqrt(A)"
910
+ assert sstr(1/sqrt(A)) == "A**(-1/2)"
911
+
912
+
913
+ def test_empty_printer():
914
+ str_printer = StrPrinter()
915
+ assert str_printer.emptyPrinter("foo") == "foo"
916
+ assert str_printer.emptyPrinter(x*y) == "x*y"
917
+ assert str_printer.emptyPrinter(32) == "32"
918
+
919
+ def test_decimal_printer():
920
+ dec_printer = StrPrinter(settings={"dps":3})
921
+ f = Function('f')
922
+ assert dec_printer.doprint(f(1.329294)) == "f(1.33)"
923
+
924
+
925
+ def test_settings():
926
+ raises(TypeError, lambda: sstr(S(4), method="garbage"))
927
+
928
+
929
+ def test_RandomDomain():
930
+ from sympy.stats import Normal, Die, Exponential, pspace, where
931
+ X = Normal('x1', 0, 1)
932
+ assert str(where(X > 0)) == "Domain: (0 < x1) & (x1 < oo)"
933
+
934
+ D = Die('d1', 6)
935
+ assert str(where(D > 4)) == "Domain: Eq(d1, 5) | Eq(d1, 6)"
936
+
937
+ A = Exponential('a', 1)
938
+ B = Exponential('b', 1)
939
+ assert str(pspace(Tuple(A, B)).domain) == "Domain: (0 <= a) & (0 <= b) & (a < oo) & (b < oo)"
940
+
941
+
942
+ def test_FiniteSet():
943
+ assert str(FiniteSet(*range(1, 51))) == (
944
+ '{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,'
945
+ ' 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,'
946
+ ' 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50}'
947
+ )
948
+ assert str(FiniteSet(*range(1, 6))) == '{1, 2, 3, 4, 5}'
949
+ assert str(FiniteSet(*[x*y, x**2])) == '{x**2, x*y}'
950
+ assert str(FiniteSet(FiniteSet(FiniteSet(x, y), 5), FiniteSet(x,y), 5)
951
+ ) == 'FiniteSet(5, FiniteSet(5, {x, y}), {x, y})'
952
+
953
+
954
+ def test_Partition():
955
+ assert str(Partition(FiniteSet(x, y), {z})) == 'Partition({z}, {x, y})'
956
+
957
+ def test_UniversalSet():
958
+ assert str(S.UniversalSet) == 'UniversalSet'
959
+
960
+
961
+ def test_PrettyPoly():
962
+ F = QQ.frac_field(x, y)
963
+ R = QQ[x, y]
964
+ assert sstr(F.convert(x/(x + y))) == sstr(x/(x + y))
965
+ assert sstr(R.convert(x + y)) == sstr(x + y)
966
+
967
+
968
+ def test_categories():
969
+ from sympy.categories import (Object, NamedMorphism,
970
+ IdentityMorphism, Category)
971
+
972
+ A = Object("A")
973
+ B = Object("B")
974
+
975
+ f = NamedMorphism(A, B, "f")
976
+ id_A = IdentityMorphism(A)
977
+
978
+ K = Category("K")
979
+
980
+ assert str(A) == 'Object("A")'
981
+ assert str(f) == 'NamedMorphism(Object("A"), Object("B"), "f")'
982
+ assert str(id_A) == 'IdentityMorphism(Object("A"))'
983
+
984
+ assert str(K) == 'Category("K")'
985
+
986
+
987
+ def test_Tr():
988
+ A, B = symbols('A B', commutative=False)
989
+ t = Tr(A*B)
990
+ assert str(t) == 'Tr(A*B)'
991
+
992
+
993
+ def test_issue_6387():
994
+ assert str(factor(-3.0*z + 3)) == '-3.0*(1.0*z - 1.0)'
995
+
996
+
997
+ def test_MatMul_MatAdd():
998
+ X, Y = MatrixSymbol("X", 2, 2), MatrixSymbol("Y", 2, 2)
999
+ assert str(2*(X + Y)) == "2*X + 2*Y"
1000
+
1001
+ assert str(I*X) == "I*X"
1002
+ assert str(-I*X) == "-I*X"
1003
+ assert str((1 + I)*X) == '(1 + I)*X'
1004
+ assert str(-(1 + I)*X) == '(-1 - I)*X'
1005
+ assert str(MatAdd(MatAdd(X, Y), MatAdd(X, Y))) == '(X + Y) + (X + Y)'
1006
+
1007
+
1008
+ def test_MatrixSlice():
1009
+ n = Symbol('n', integer=True)
1010
+ X = MatrixSymbol('X', n, n)
1011
+ Y = MatrixSymbol('Y', 10, 10)
1012
+ Z = MatrixSymbol('Z', 10, 10)
1013
+
1014
+ assert str(MatrixSlice(X, (None, None, None), (None, None, None))) == 'X[:, :]'
1015
+ assert str(X[x:x + 1, y:y + 1]) == 'X[x:x + 1, y:y + 1]'
1016
+ assert str(X[x:x + 1:2, y:y + 1:2]) == 'X[x:x + 1:2, y:y + 1:2]'
1017
+ assert str(X[:x, y:]) == 'X[:x, y:]'
1018
+ assert str(X[:x, y:]) == 'X[:x, y:]'
1019
+ assert str(X[x:, :y]) == 'X[x:, :y]'
1020
+ assert str(X[x:y, z:w]) == 'X[x:y, z:w]'
1021
+ assert str(X[x:y:t, w:t:x]) == 'X[x:y:t, w:t:x]'
1022
+ assert str(X[x::y, t::w]) == 'X[x::y, t::w]'
1023
+ assert str(X[:x:y, :t:w]) == 'X[:x:y, :t:w]'
1024
+ assert str(X[::x, ::y]) == 'X[::x, ::y]'
1025
+ assert str(MatrixSlice(X, (0, None, None), (0, None, None))) == 'X[:, :]'
1026
+ assert str(MatrixSlice(X, (None, n, None), (None, n, None))) == 'X[:, :]'
1027
+ assert str(MatrixSlice(X, (0, n, None), (0, n, None))) == 'X[:, :]'
1028
+ assert str(MatrixSlice(X, (0, n, 2), (0, n, 2))) == 'X[::2, ::2]'
1029
+ assert str(X[1:2:3, 4:5:6]) == 'X[1:2:3, 4:5:6]'
1030
+ assert str(X[1:3:5, 4:6:8]) == 'X[1:3:5, 4:6:8]'
1031
+ assert str(X[1:10:2]) == 'X[1:10:2, :]'
1032
+ assert str(Y[:5, 1:9:2]) == 'Y[:5, 1:9:2]'
1033
+ assert str(Y[:5, 1:10:2]) == 'Y[:5, 1::2]'
1034
+ assert str(Y[5, :5:2]) == 'Y[5:6, :5:2]'
1035
+ assert str(X[0:1, 0:1]) == 'X[:1, :1]'
1036
+ assert str(X[0:1:2, 0:1:2]) == 'X[:1:2, :1:2]'
1037
+ assert str((Y + Z)[2:, 2:]) == '(Y + Z)[2:, 2:]'
1038
+
1039
+ def test_true_false():
1040
+ assert str(true) == repr(true) == sstr(true) == "True"
1041
+ assert str(false) == repr(false) == sstr(false) == "False"
1042
+
1043
+ def test_Equivalent():
1044
+ assert str(Equivalent(y, x)) == "Equivalent(x, y)"
1045
+
1046
+ def test_Xor():
1047
+ assert str(Xor(y, x, evaluate=False)) == "x ^ y"
1048
+
1049
+ def test_Complement():
1050
+ assert str(Complement(S.Reals, S.Naturals)) == 'Complement(Reals, Naturals)'
1051
+
1052
+ def test_SymmetricDifference():
1053
+ assert str(SymmetricDifference(Interval(2, 3), Interval(3, 4),evaluate=False)) == \
1054
+ 'SymmetricDifference(Interval(2, 3), Interval(3, 4))'
1055
+
1056
+
1057
+ def test_UnevaluatedExpr():
1058
+ a, b = symbols("a b")
1059
+ expr1 = 2*UnevaluatedExpr(a+b)
1060
+ assert str(expr1) == "2*(a + b)"
1061
+
1062
+
1063
+ def test_MatrixElement_printing():
1064
+ # test cases for issue #11821
1065
+ A = MatrixSymbol("A", 1, 3)
1066
+ B = MatrixSymbol("B", 1, 3)
1067
+ C = MatrixSymbol("C", 1, 3)
1068
+
1069
+ assert(str(A[0, 0]) == "A[0, 0]")
1070
+ assert(str(3 * A[0, 0]) == "3*A[0, 0]")
1071
+
1072
+ F = C[0, 0].subs(C, A - B)
1073
+ assert str(F) == "(A - B)[0, 0]"
1074
+
1075
+
1076
+ def test_MatrixSymbol_printing():
1077
+ A = MatrixSymbol("A", 3, 3)
1078
+ B = MatrixSymbol("B", 3, 3)
1079
+
1080
+ assert str(A - A*B - B) == "A - A*B - B"
1081
+ assert str(A*B - (A+B)) == "-A + A*B - B"
1082
+ assert str(A**(-1)) == "A**(-1)"
1083
+ assert str(A**3) == "A**3"
1084
+
1085
+
1086
+ def test_MatrixExpressions():
1087
+ n = Symbol('n', integer=True)
1088
+ X = MatrixSymbol('X', n, n)
1089
+
1090
+ assert str(X) == "X"
1091
+
1092
+ # Apply function elementwise (`ElementwiseApplyFunc`):
1093
+
1094
+ expr = (X.T*X).applyfunc(sin)
1095
+ assert str(expr) == 'Lambda(_d, sin(_d)).(X.T*X)'
1096
+
1097
+ lamda = Lambda(x, 1/x)
1098
+ expr = (n*X).applyfunc(lamda)
1099
+ assert str(expr) == 'Lambda(x, 1/x).(n*X)'
1100
+
1101
+
1102
+ def test_Subs_printing():
1103
+ assert str(Subs(x, (x,), (1,))) == 'Subs(x, x, 1)'
1104
+ assert str(Subs(x + y, (x, y), (1, 2))) == 'Subs(x + y, (x, y), (1, 2))'
1105
+
1106
+
1107
+ def test_issue_15716():
1108
+ e = Integral(factorial(x), (x, -oo, oo))
1109
+ assert e.as_terms() == ([(e, ((1.0, 0.0), (1,), ()))], [e])
1110
+
1111
+
1112
+ def test_str_special_matrices():
1113
+ from sympy.matrices import Identity, ZeroMatrix, OneMatrix
1114
+ assert str(Identity(4)) == 'I'
1115
+ assert str(ZeroMatrix(2, 2)) == '0'
1116
+ assert str(OneMatrix(2, 2)) == '1'
1117
+
1118
+
1119
+ def test_issue_14567():
1120
+ assert factorial(Sum(-1, (x, 0, 0))) + y # doesn't raise an error
1121
+
1122
+
1123
+ def test_issue_21823():
1124
+ assert str(Partition([1, 2])) == 'Partition({1, 2})'
1125
+ assert str(Partition({1, 2})) == 'Partition({1, 2})'
1126
+
1127
+
1128
+ def test_issue_22689():
1129
+ assert str(Mul(Pow(x,-2, evaluate=False), Pow(3,-1,evaluate=False), evaluate=False)) == "1/(x**2*3)"
1130
+
1131
+
1132
+ def test_issue_21119_21460():
1133
+ ss = lambda x: str(S(x, evaluate=False))
1134
+ assert ss('4/2') == '4/2'
1135
+ assert ss('4/-2') == '4/(-2)'
1136
+ assert ss('-4/2') == '-4/2'
1137
+ assert ss('-4/-2') == '-4/(-2)'
1138
+ assert ss('-2*3/-1') == '-2*3/(-1)'
1139
+ assert ss('-2*3/-1/2') == '-2*3/(-1*2)'
1140
+ assert ss('4/2/1') == '4/(2*1)'
1141
+ assert ss('-2/-1/2') == '-2/(-1*2)'
1142
+ assert ss('2*3*4**(-2*3)') == '2*3/4**(2*3)'
1143
+ assert ss('2*3*1*4**(-2*3)') == '2*3*1/4**(2*3)'
1144
+
1145
+
1146
+ def test_Str():
1147
+ from sympy.core.symbol import Str
1148
+ assert str(Str('x')) == 'x'
1149
+ assert sstrrepr(Str('x')) == "Str('x')"
1150
+
1151
+
1152
+ def test_diffgeom():
1153
+ from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseScalarField
1154
+ x,y = symbols('x y', real=True)
1155
+ m = Manifold('M', 2)
1156
+ assert str(m) == "M"
1157
+ p = Patch('P', m)
1158
+ assert str(p) == "P"
1159
+ rect = CoordSystem('rect', p, [x, y])
1160
+ assert str(rect) == "rect"
1161
+ b = BaseScalarField(rect, 0)
1162
+ assert str(b) == "x"
1163
+
1164
+ def test_NDimArray():
1165
+ assert sstr(NDimArray(1.0), full_prec=True) == '1.00000000000000'
1166
+ assert sstr(NDimArray(1.0), full_prec=False) == '1.0'
1167
+ assert sstr(NDimArray([1.0, 2.0]), full_prec=True) == '[1.00000000000000, 2.00000000000000]'
1168
+ assert sstr(NDimArray([1.0, 2.0]), full_prec=False) == '[1.0, 2.0]'
1169
+ assert sstr(NDimArray([], (0,))) == 'ImmutableDenseNDimArray([], (0,))'
1170
+ assert sstr(NDimArray([], (0, 0))) == 'ImmutableDenseNDimArray([], (0, 0))'
1171
+ assert sstr(NDimArray([], (0, 1))) == 'ImmutableDenseNDimArray([], (0, 1))'
1172
+ assert sstr(NDimArray([], (1, 0))) == 'ImmutableDenseNDimArray([], (1, 0))'
1173
+
1174
+ def test_Predicate():
1175
+ assert sstr(Q.even) == 'Q.even'
1176
+
1177
+ def test_AppliedPredicate():
1178
+ assert sstr(Q.even(x)) == 'Q.even(x)'
1179
+
1180
+ def test_printing_str_array_expressions():
1181
+ assert sstr(ArraySymbol("A", (2, 3, 4))) == "A"
1182
+ assert sstr(ArrayElement("A", (2, 1/(1-x), 0))) == "A[2, 1/(1 - x), 0]"
1183
+ M = MatrixSymbol("M", 3, 3)
1184
+ N = MatrixSymbol("N", 3, 3)
1185
+ assert sstr(ArrayElement(M*N, [x, 0])) == "(M*N)[x, 0]"
1186
+
1187
+ def test_printing_stats():
1188
+ # issue 24132
1189
+ x = RandomSymbol("x")
1190
+ y = RandomSymbol("y")
1191
+ z1 = Probability(x > 0)*Identity(2)
1192
+ z2 = Expectation(x)*Identity(2)
1193
+ z3 = Variance(x)*Identity(2)
1194
+ z4 = Covariance(x, y) * Identity(2)
1195
+
1196
+ assert str(z1) == "Probability(x > 0)*I"
1197
+ assert str(z2) == "Expectation(x)*I"
1198
+ assert str(z3) == "Variance(x)*I"
1199
+ assert str(z4) == "Covariance(x, y)*I"
1200
+ assert z1.is_commutative == False
1201
+ assert z2.is_commutative == False
1202
+ assert z3.is_commutative == False
1203
+ assert z4.is_commutative == False
1204
+ assert z2._eval_is_commutative() == False
1205
+ assert z3._eval_is_commutative() == False
1206
+ assert z4._eval_is_commutative() == False
outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_tableform.py ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.singleton import S
2
+ from sympy.printing.tableform import TableForm
3
+ from sympy.printing.latex import latex
4
+ from sympy.abc import x
5
+ from sympy.functions.elementary.miscellaneous import sqrt
6
+ from sympy.functions.elementary.trigonometric import sin
7
+ from sympy.testing.pytest import raises
8
+
9
+ from textwrap import dedent
10
+
11
+
12
+ def test_TableForm():
13
+ s = str(TableForm([["a", "b"], ["c", "d"], ["e", 0]],
14
+ headings="automatic"))
15
+ assert s == (
16
+ ' | 1 2\n'
17
+ '-------\n'
18
+ '1 | a b\n'
19
+ '2 | c d\n'
20
+ '3 | e '
21
+ )
22
+ s = str(TableForm([["a", "b"], ["c", "d"], ["e", 0]],
23
+ headings="automatic", wipe_zeros=False))
24
+ assert s == dedent('''\
25
+ | 1 2
26
+ -------
27
+ 1 | a b
28
+ 2 | c d
29
+ 3 | e 0''')
30
+ s = str(TableForm([[x**2, "b"], ["c", x**2], ["e", "f"]],
31
+ headings=("automatic", None)))
32
+ assert s == (
33
+ '1 | x**2 b \n'
34
+ '2 | c x**2\n'
35
+ '3 | e f '
36
+ )
37
+ s = str(TableForm([["a", "b"], ["c", "d"], ["e", "f"]],
38
+ headings=(None, "automatic")))
39
+ assert s == dedent('''\
40
+ 1 2
41
+ ---
42
+ a b
43
+ c d
44
+ e f''')
45
+ s = str(TableForm([[5, 7], [4, 2], [10, 3]],
46
+ headings=[["Group A", "Group B", "Group C"], ["y1", "y2"]]))
47
+ assert s == (
48
+ ' | y1 y2\n'
49
+ '---------------\n'
50
+ 'Group A | 5 7 \n'
51
+ 'Group B | 4 2 \n'
52
+ 'Group C | 10 3 '
53
+ )
54
+ raises(
55
+ ValueError,
56
+ lambda:
57
+ TableForm(
58
+ [[5, 7], [4, 2], [10, 3]],
59
+ headings=[["Group A", "Group B", "Group C"], ["y1", "y2"]],
60
+ alignments="middle")
61
+ )
62
+ s = str(TableForm([[5, 7], [4, 2], [10, 3]],
63
+ headings=[["Group A", "Group B", "Group C"], ["y1", "y2"]],
64
+ alignments="right"))
65
+ assert s == dedent('''\
66
+ | y1 y2
67
+ ---------------
68
+ Group A | 5 7
69
+ Group B | 4 2
70
+ Group C | 10 3''')
71
+
72
+ # other alignment permutations
73
+ d = [[1, 100], [100, 1]]
74
+ s = TableForm(d, headings=(('xxx', 'x'), None), alignments='l')
75
+ assert str(s) == (
76
+ 'xxx | 1 100\n'
77
+ ' x | 100 1 '
78
+ )
79
+ s = TableForm(d, headings=(('xxx', 'x'), None), alignments='lr')
80
+ assert str(s) == dedent('''\
81
+ xxx | 1 100
82
+ x | 100 1''')
83
+ s = TableForm(d, headings=(('xxx', 'x'), None), alignments='clr')
84
+ assert str(s) == dedent('''\
85
+ xxx | 1 100
86
+ x | 100 1''')
87
+
88
+ s = TableForm(d, headings=(('xxx', 'x'), None))
89
+ assert str(s) == (
90
+ 'xxx | 1 100\n'
91
+ ' x | 100 1 '
92
+ )
93
+
94
+ raises(ValueError, lambda: TableForm(d, alignments='clr'))
95
+
96
+ #pad
97
+ s = str(TableForm([[None, "-", 2], [1]], pad='?'))
98
+ assert s == dedent('''\
99
+ ? - 2
100
+ 1 ? ?''')
101
+
102
+
103
+ def test_TableForm_latex():
104
+ s = latex(TableForm([[0, x**3], ["c", S.One/4], [sqrt(x), sin(x**2)]],
105
+ wipe_zeros=True, headings=("automatic", "automatic")))
106
+ assert s == (
107
+ '\\begin{tabular}{r l l}\n'
108
+ ' & 1 & 2 \\\\\n'
109
+ '\\hline\n'
110
+ '1 & & $x^{3}$ \\\\\n'
111
+ '2 & $c$ & $\\frac{1}{4}$ \\\\\n'
112
+ '3 & $\\sqrt{x}$ & $\\sin{\\left(x^{2} \\right)}$ \\\\\n'
113
+ '\\end{tabular}'
114
+ )
115
+ s = latex(TableForm([[0, x**3], ["c", S.One/4], [sqrt(x), sin(x**2)]],
116
+ wipe_zeros=True, headings=("automatic", "automatic"), alignments='l'))
117
+ assert s == (
118
+ '\\begin{tabular}{r l l}\n'
119
+ ' & 1 & 2 \\\\\n'
120
+ '\\hline\n'
121
+ '1 & & $x^{3}$ \\\\\n'
122
+ '2 & $c$ & $\\frac{1}{4}$ \\\\\n'
123
+ '3 & $\\sqrt{x}$ & $\\sin{\\left(x^{2} \\right)}$ \\\\\n'
124
+ '\\end{tabular}'
125
+ )
126
+ s = latex(TableForm([[0, x**3], ["c", S.One/4], [sqrt(x), sin(x**2)]],
127
+ wipe_zeros=True, headings=("automatic", "automatic"), alignments='l'*3))
128
+ assert s == (
129
+ '\\begin{tabular}{l l l}\n'
130
+ ' & 1 & 2 \\\\\n'
131
+ '\\hline\n'
132
+ '1 & & $x^{3}$ \\\\\n'
133
+ '2 & $c$ & $\\frac{1}{4}$ \\\\\n'
134
+ '3 & $\\sqrt{x}$ & $\\sin{\\left(x^{2} \\right)}$ \\\\\n'
135
+ '\\end{tabular}'
136
+ )
137
+ s = latex(TableForm([["a", x**3], ["c", S.One/4], [sqrt(x), sin(x**2)]],
138
+ headings=("automatic", "automatic")))
139
+ assert s == (
140
+ '\\begin{tabular}{r l l}\n'
141
+ ' & 1 & 2 \\\\\n'
142
+ '\\hline\n'
143
+ '1 & $a$ & $x^{3}$ \\\\\n'
144
+ '2 & $c$ & $\\frac{1}{4}$ \\\\\n'
145
+ '3 & $\\sqrt{x}$ & $\\sin{\\left(x^{2} \\right)}$ \\\\\n'
146
+ '\\end{tabular}'
147
+ )
148
+ s = latex(TableForm([["a", x**3], ["c", S.One/4], [sqrt(x), sin(x**2)]],
149
+ formats=['(%s)', None], headings=("automatic", "automatic")))
150
+ assert s == (
151
+ '\\begin{tabular}{r l l}\n'
152
+ ' & 1 & 2 \\\\\n'
153
+ '\\hline\n'
154
+ '1 & (a) & $x^{3}$ \\\\\n'
155
+ '2 & (c) & $\\frac{1}{4}$ \\\\\n'
156
+ '3 & (sqrt(x)) & $\\sin{\\left(x^{2} \\right)}$ \\\\\n'
157
+ '\\end{tabular}'
158
+ )
159
+
160
+ def neg_in_paren(x, i, j):
161
+ if i % 2:
162
+ return ('(%s)' if x < 0 else '%s') % x
163
+ else:
164
+ pass # use default print
165
+ s = latex(TableForm([[-1, 2], [-3, 4]],
166
+ formats=[neg_in_paren]*2, headings=("automatic", "automatic")))
167
+ assert s == (
168
+ '\\begin{tabular}{r l l}\n'
169
+ ' & 1 & 2 \\\\\n'
170
+ '\\hline\n'
171
+ '1 & -1 & 2 \\\\\n'
172
+ '2 & (-3) & 4 \\\\\n'
173
+ '\\end{tabular}'
174
+ )
175
+ s = latex(TableForm([["a", x**3], ["c", S.One/4], [sqrt(x), sin(x**2)]]))
176
+ assert s == (
177
+ '\\begin{tabular}{l l}\n'
178
+ '$a$ & $x^{3}$ \\\\\n'
179
+ '$c$ & $\\frac{1}{4}$ \\\\\n'
180
+ '$\\sqrt{x}$ & $\\sin{\\left(x^{2} \\right)}$ \\\\\n'
181
+ '\\end{tabular}'
182
+ )
outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_tensorflow.py ADDED
@@ -0,0 +1,493 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ from sympy.core.function import Derivative
3
+ from sympy.core.symbol import symbols
4
+ from sympy import Piecewise
5
+ from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct, ArrayAdd, \
6
+ PermuteDims, ArrayDiagonal
7
+ from sympy.core.relational import Eq, Ne, Ge, Gt, Le, Lt
8
+ from sympy.external import import_module
9
+ from sympy.functions import \
10
+ Abs, ceiling, exp, floor, sign, sin, asin, sqrt, cos, \
11
+ acos, tan, atan, atan2, cosh, acosh, sinh, asinh, tanh, atanh, \
12
+ re, im, arg, erf, loggamma, log
13
+ from sympy.codegen.cfunctions import isnan, isinf
14
+ from sympy.matrices import Matrix, MatrixBase, eye, randMatrix
15
+ from sympy.matrices.expressions import \
16
+ Determinant, HadamardProduct, Inverse, MatrixSymbol, Trace
17
+ from sympy.printing.tensorflow import tensorflow_code
18
+ from sympy.tensor.array.expressions.from_matrix_to_array import convert_matrix_to_array
19
+ from sympy.utilities.lambdify import lambdify
20
+ from sympy.testing.pytest import skip
21
+ from sympy.testing.pytest import XFAIL
22
+
23
+
24
+ tf = tensorflow = import_module("tensorflow")
25
+
26
+ if tensorflow:
27
+ # Hide Tensorflow warnings
28
+ import os
29
+ os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
30
+
31
+
32
+ M = MatrixSymbol("M", 3, 3)
33
+ N = MatrixSymbol("N", 3, 3)
34
+ P = MatrixSymbol("P", 3, 3)
35
+ Q = MatrixSymbol("Q", 3, 3)
36
+
37
+ x, y, z, t = symbols("x y z t")
38
+
39
+ if tf is not None:
40
+ llo = [list(range(i, i+3)) for i in range(0, 9, 3)]
41
+ m3x3 = tf.constant(llo)
42
+ m3x3sympy = Matrix(llo)
43
+
44
+
45
+ def _compare_tensorflow_matrix(variables, expr, use_float=False):
46
+ f = lambdify(variables, expr, 'tensorflow')
47
+ if not use_float:
48
+ random_matrices = [randMatrix(v.rows, v.cols) for v in variables]
49
+ else:
50
+ random_matrices = [randMatrix(v.rows, v.cols)/100. for v in variables]
51
+
52
+ graph = tf.Graph()
53
+ r = None
54
+ with graph.as_default():
55
+ random_variables = [eval(tensorflow_code(i)) for i in random_matrices]
56
+ session = tf.compat.v1.Session(graph=graph)
57
+ r = session.run(f(*random_variables))
58
+
59
+ e = expr.subs(dict(zip(variables, random_matrices)))
60
+ e = e.doit()
61
+ if e.is_Matrix:
62
+ if not isinstance(e, MatrixBase):
63
+ e = e.as_explicit()
64
+ e = e.tolist()
65
+
66
+ if not use_float:
67
+ assert (r == e).all()
68
+ else:
69
+ r = [i for row in r for i in row]
70
+ e = [i for row in e for i in row]
71
+ assert all(
72
+ abs(a-b) < 10**-(4-int(log(abs(a), 10))) for a, b in zip(r, e))
73
+
74
+
75
+ # Creating a custom inverse test.
76
+ # See https://github.com/sympy/sympy/issues/18469
77
+ def _compare_tensorflow_matrix_inverse(variables, expr, use_float=False):
78
+ f = lambdify(variables, expr, 'tensorflow')
79
+ if not use_float:
80
+ random_matrices = [eye(v.rows, v.cols)*4 for v in variables]
81
+ else:
82
+ random_matrices = [eye(v.rows, v.cols)*3.14 for v in variables]
83
+
84
+ graph = tf.Graph()
85
+ r = None
86
+ with graph.as_default():
87
+ random_variables = [eval(tensorflow_code(i)) for i in random_matrices]
88
+ session = tf.compat.v1.Session(graph=graph)
89
+ r = session.run(f(*random_variables))
90
+
91
+ e = expr.subs(dict(zip(variables, random_matrices)))
92
+ e = e.doit()
93
+ if e.is_Matrix:
94
+ if not isinstance(e, MatrixBase):
95
+ e = e.as_explicit()
96
+ e = e.tolist()
97
+
98
+ if not use_float:
99
+ assert (r == e).all()
100
+ else:
101
+ r = [i for row in r for i in row]
102
+ e = [i for row in e for i in row]
103
+ assert all(
104
+ abs(a-b) < 10**-(4-int(log(abs(a), 10))) for a, b in zip(r, e))
105
+
106
+
107
+ def _compare_tensorflow_matrix_scalar(variables, expr):
108
+ f = lambdify(variables, expr, 'tensorflow')
109
+ random_matrices = [
110
+ randMatrix(v.rows, v.cols).evalf() / 100 for v in variables]
111
+
112
+ graph = tf.Graph()
113
+ r = None
114
+ with graph.as_default():
115
+ random_variables = [eval(tensorflow_code(i)) for i in random_matrices]
116
+ session = tf.compat.v1.Session(graph=graph)
117
+ r = session.run(f(*random_variables))
118
+
119
+ e = expr.subs(dict(zip(variables, random_matrices)))
120
+ e = e.doit()
121
+ assert abs(r-e) < 10**-6
122
+
123
+
124
+ def _compare_tensorflow_scalar(
125
+ variables, expr, rng=lambda: random.randint(0, 10)):
126
+ f = lambdify(variables, expr, 'tensorflow')
127
+ rvs = [rng() for v in variables]
128
+
129
+ graph = tf.Graph()
130
+ r = None
131
+ with graph.as_default():
132
+ tf_rvs = [eval(tensorflow_code(i)) for i in rvs]
133
+ session = tf.compat.v1.Session(graph=graph)
134
+ r = session.run(f(*tf_rvs))
135
+
136
+ e = expr.subs(dict(zip(variables, rvs))).evalf().doit()
137
+ assert abs(r-e) < 10**-6
138
+
139
+
140
+ def _compare_tensorflow_relational(
141
+ variables, expr, rng=lambda: random.randint(0, 10)):
142
+ f = lambdify(variables, expr, 'tensorflow')
143
+ rvs = [rng() for v in variables]
144
+
145
+ graph = tf.Graph()
146
+ r = None
147
+ with graph.as_default():
148
+ tf_rvs = [eval(tensorflow_code(i)) for i in rvs]
149
+ session = tf.compat.v1.Session(graph=graph)
150
+ r = session.run(f(*tf_rvs))
151
+
152
+ e = expr.subs(dict(zip(variables, rvs))).doit()
153
+ assert r == e
154
+
155
+
156
+ def test_tensorflow_printing():
157
+ assert tensorflow_code(eye(3)) == \
158
+ "tensorflow.constant([[1, 0, 0], [0, 1, 0], [0, 0, 1]])"
159
+
160
+ expr = Matrix([[x, sin(y)], [exp(z), -t]])
161
+ assert tensorflow_code(expr) == \
162
+ "tensorflow.Variable(" \
163
+ "[[x, tensorflow.math.sin(y)]," \
164
+ " [tensorflow.math.exp(z), -t]])"
165
+
166
+
167
+ # This (random) test is XFAIL because it fails occasionally
168
+ # See https://github.com/sympy/sympy/issues/18469
169
+ @XFAIL
170
+ def test_tensorflow_math():
171
+ if not tf:
172
+ skip("TensorFlow not installed")
173
+
174
+ expr = Abs(x)
175
+ assert tensorflow_code(expr) == "tensorflow.math.abs(x)"
176
+ _compare_tensorflow_scalar((x,), expr)
177
+
178
+ expr = sign(x)
179
+ assert tensorflow_code(expr) == "tensorflow.math.sign(x)"
180
+ _compare_tensorflow_scalar((x,), expr)
181
+
182
+ expr = ceiling(x)
183
+ assert tensorflow_code(expr) == "tensorflow.math.ceil(x)"
184
+ _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
185
+
186
+ expr = floor(x)
187
+ assert tensorflow_code(expr) == "tensorflow.math.floor(x)"
188
+ _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
189
+
190
+ expr = exp(x)
191
+ assert tensorflow_code(expr) == "tensorflow.math.exp(x)"
192
+ _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
193
+
194
+ expr = sqrt(x)
195
+ assert tensorflow_code(expr) == "tensorflow.math.sqrt(x)"
196
+ _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
197
+
198
+ expr = x ** 4
199
+ assert tensorflow_code(expr) == "tensorflow.math.pow(x, 4)"
200
+ _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
201
+
202
+ expr = cos(x)
203
+ assert tensorflow_code(expr) == "tensorflow.math.cos(x)"
204
+ _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
205
+
206
+ expr = acos(x)
207
+ assert tensorflow_code(expr) == "tensorflow.math.acos(x)"
208
+ _compare_tensorflow_scalar((x,), expr, rng=lambda: random.uniform(0, 0.95))
209
+
210
+ expr = sin(x)
211
+ assert tensorflow_code(expr) == "tensorflow.math.sin(x)"
212
+ _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
213
+
214
+ expr = asin(x)
215
+ assert tensorflow_code(expr) == "tensorflow.math.asin(x)"
216
+ _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
217
+
218
+ expr = tan(x)
219
+ assert tensorflow_code(expr) == "tensorflow.math.tan(x)"
220
+ _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
221
+
222
+ expr = atan(x)
223
+ assert tensorflow_code(expr) == "tensorflow.math.atan(x)"
224
+ _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
225
+
226
+ expr = atan2(y, x)
227
+ assert tensorflow_code(expr) == "tensorflow.math.atan2(y, x)"
228
+ _compare_tensorflow_scalar((y, x), expr, rng=lambda: random.random())
229
+
230
+ expr = cosh(x)
231
+ assert tensorflow_code(expr) == "tensorflow.math.cosh(x)"
232
+ _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
233
+
234
+ expr = acosh(x)
235
+ assert tensorflow_code(expr) == "tensorflow.math.acosh(x)"
236
+ _compare_tensorflow_scalar((x,), expr, rng=lambda: random.uniform(1, 2))
237
+
238
+ expr = sinh(x)
239
+ assert tensorflow_code(expr) == "tensorflow.math.sinh(x)"
240
+ _compare_tensorflow_scalar((x,), expr, rng=lambda: random.uniform(1, 2))
241
+
242
+ expr = asinh(x)
243
+ assert tensorflow_code(expr) == "tensorflow.math.asinh(x)"
244
+ _compare_tensorflow_scalar((x,), expr, rng=lambda: random.uniform(1, 2))
245
+
246
+ expr = tanh(x)
247
+ assert tensorflow_code(expr) == "tensorflow.math.tanh(x)"
248
+ _compare_tensorflow_scalar((x,), expr, rng=lambda: random.uniform(1, 2))
249
+
250
+ expr = atanh(x)
251
+ assert tensorflow_code(expr) == "tensorflow.math.atanh(x)"
252
+ _compare_tensorflow_scalar(
253
+ (x,), expr, rng=lambda: random.uniform(-.5, .5))
254
+
255
+ expr = erf(x)
256
+ assert tensorflow_code(expr) == "tensorflow.math.erf(x)"
257
+ _compare_tensorflow_scalar(
258
+ (x,), expr, rng=lambda: random.random())
259
+
260
+ expr = loggamma(x)
261
+ assert tensorflow_code(expr) == "tensorflow.math.lgamma(x)"
262
+ _compare_tensorflow_scalar(
263
+ (x,), expr, rng=lambda: random.random())
264
+
265
+
266
+ def test_tensorflow_complexes():
267
+ assert tensorflow_code(re(x)) == "tensorflow.math.real(x)"
268
+ assert tensorflow_code(im(x)) == "tensorflow.math.imag(x)"
269
+ assert tensorflow_code(arg(x)) == "tensorflow.math.angle(x)"
270
+
271
+
272
+ def test_tensorflow_relational():
273
+ if not tf:
274
+ skip("TensorFlow not installed")
275
+
276
+ expr = Eq(x, y)
277
+ assert tensorflow_code(expr) == "tensorflow.math.equal(x, y)"
278
+ _compare_tensorflow_relational((x, y), expr)
279
+
280
+ expr = Ne(x, y)
281
+ assert tensorflow_code(expr) == "tensorflow.math.not_equal(x, y)"
282
+ _compare_tensorflow_relational((x, y), expr)
283
+
284
+ expr = Ge(x, y)
285
+ assert tensorflow_code(expr) == "tensorflow.math.greater_equal(x, y)"
286
+ _compare_tensorflow_relational((x, y), expr)
287
+
288
+ expr = Gt(x, y)
289
+ assert tensorflow_code(expr) == "tensorflow.math.greater(x, y)"
290
+ _compare_tensorflow_relational((x, y), expr)
291
+
292
+ expr = Le(x, y)
293
+ assert tensorflow_code(expr) == "tensorflow.math.less_equal(x, y)"
294
+ _compare_tensorflow_relational((x, y), expr)
295
+
296
+ expr = Lt(x, y)
297
+ assert tensorflow_code(expr) == "tensorflow.math.less(x, y)"
298
+ _compare_tensorflow_relational((x, y), expr)
299
+
300
+
301
+ # This (random) test is XFAIL because it fails occasionally
302
+ # See https://github.com/sympy/sympy/issues/18469
303
+ @XFAIL
304
+ def test_tensorflow_matrices():
305
+ if not tf:
306
+ skip("TensorFlow not installed")
307
+
308
+ expr = M
309
+ assert tensorflow_code(expr) == "M"
310
+ _compare_tensorflow_matrix((M,), expr)
311
+
312
+ expr = M + N
313
+ assert tensorflow_code(expr) == "tensorflow.math.add(M, N)"
314
+ _compare_tensorflow_matrix((M, N), expr)
315
+
316
+ expr = M * N
317
+ assert tensorflow_code(expr) == "tensorflow.linalg.matmul(M, N)"
318
+ _compare_tensorflow_matrix((M, N), expr)
319
+
320
+ expr = HadamardProduct(M, N)
321
+ assert tensorflow_code(expr) == "tensorflow.math.multiply(M, N)"
322
+ _compare_tensorflow_matrix((M, N), expr)
323
+
324
+ expr = M*N*P*Q
325
+ assert tensorflow_code(expr) == \
326
+ "tensorflow.linalg.matmul(" \
327
+ "tensorflow.linalg.matmul(" \
328
+ "tensorflow.linalg.matmul(M, N), P), Q)"
329
+ _compare_tensorflow_matrix((M, N, P, Q), expr)
330
+
331
+ expr = M**3
332
+ assert tensorflow_code(expr) == \
333
+ "tensorflow.linalg.matmul(tensorflow.linalg.matmul(M, M), M)"
334
+ _compare_tensorflow_matrix((M,), expr)
335
+
336
+ expr = Trace(M)
337
+ assert tensorflow_code(expr) == "tensorflow.linalg.trace(M)"
338
+ _compare_tensorflow_matrix((M,), expr)
339
+
340
+ expr = Determinant(M)
341
+ assert tensorflow_code(expr) == "tensorflow.linalg.det(M)"
342
+ _compare_tensorflow_matrix_scalar((M,), expr)
343
+
344
+ expr = Inverse(M)
345
+ assert tensorflow_code(expr) == "tensorflow.linalg.inv(M)"
346
+ _compare_tensorflow_matrix_inverse((M,), expr, use_float=True)
347
+
348
+ expr = M.T
349
+ assert tensorflow_code(expr, tensorflow_version='1.14') == \
350
+ "tensorflow.linalg.matrix_transpose(M)"
351
+ assert tensorflow_code(expr, tensorflow_version='1.13') == \
352
+ "tensorflow.matrix_transpose(M)"
353
+
354
+ _compare_tensorflow_matrix((M,), expr)
355
+
356
+
357
+ def test_codegen_einsum():
358
+ if not tf:
359
+ skip("TensorFlow not installed")
360
+
361
+ graph = tf.Graph()
362
+ with graph.as_default():
363
+ session = tf.compat.v1.Session(graph=graph)
364
+
365
+ M = MatrixSymbol("M", 2, 2)
366
+ N = MatrixSymbol("N", 2, 2)
367
+
368
+ cg = convert_matrix_to_array(M * N)
369
+ f = lambdify((M, N), cg, 'tensorflow')
370
+
371
+ ma = tf.constant([[1, 2], [3, 4]])
372
+ mb = tf.constant([[1,-2], [-1, 3]])
373
+ y = session.run(f(ma, mb))
374
+ c = session.run(tf.matmul(ma, mb))
375
+ assert (y == c).all()
376
+
377
+
378
+ def test_codegen_extra():
379
+ if not tf:
380
+ skip("TensorFlow not installed")
381
+
382
+ graph = tf.Graph()
383
+ with graph.as_default():
384
+ session = tf.compat.v1.Session()
385
+
386
+ M = MatrixSymbol("M", 2, 2)
387
+ N = MatrixSymbol("N", 2, 2)
388
+ P = MatrixSymbol("P", 2, 2)
389
+ Q = MatrixSymbol("Q", 2, 2)
390
+ ma = tf.constant([[1, 2], [3, 4]])
391
+ mb = tf.constant([[1,-2], [-1, 3]])
392
+ mc = tf.constant([[2, 0], [1, 2]])
393
+ md = tf.constant([[1,-1], [4, 7]])
394
+
395
+ cg = ArrayTensorProduct(M, N)
396
+ assert tensorflow_code(cg) == \
397
+ 'tensorflow.linalg.einsum("ab,cd", M, N)'
398
+ f = lambdify((M, N), cg, 'tensorflow')
399
+ y = session.run(f(ma, mb))
400
+ c = session.run(tf.einsum("ij,kl", ma, mb))
401
+ assert (y == c).all()
402
+
403
+ cg = ArrayAdd(M, N)
404
+ assert tensorflow_code(cg) == 'tensorflow.math.add(M, N)'
405
+ f = lambdify((M, N), cg, 'tensorflow')
406
+ y = session.run(f(ma, mb))
407
+ c = session.run(ma + mb)
408
+ assert (y == c).all()
409
+
410
+ cg = ArrayAdd(M, N, P)
411
+ assert tensorflow_code(cg) == \
412
+ 'tensorflow.math.add(tensorflow.math.add(M, N), P)'
413
+ f = lambdify((M, N, P), cg, 'tensorflow')
414
+ y = session.run(f(ma, mb, mc))
415
+ c = session.run(ma + mb + mc)
416
+ assert (y == c).all()
417
+
418
+ cg = ArrayAdd(M, N, P, Q)
419
+ assert tensorflow_code(cg) == \
420
+ 'tensorflow.math.add(' \
421
+ 'tensorflow.math.add(tensorflow.math.add(M, N), P), Q)'
422
+ f = lambdify((M, N, P, Q), cg, 'tensorflow')
423
+ y = session.run(f(ma, mb, mc, md))
424
+ c = session.run(ma + mb + mc + md)
425
+ assert (y == c).all()
426
+
427
+ cg = PermuteDims(M, [1, 0])
428
+ assert tensorflow_code(cg) == 'tensorflow.transpose(M, [1, 0])'
429
+ f = lambdify((M,), cg, 'tensorflow')
430
+ y = session.run(f(ma))
431
+ c = session.run(tf.transpose(ma))
432
+ assert (y == c).all()
433
+
434
+ cg = PermuteDims(ArrayTensorProduct(M, N), [1, 2, 3, 0])
435
+ assert tensorflow_code(cg) == \
436
+ 'tensorflow.transpose(' \
437
+ 'tensorflow.linalg.einsum("ab,cd", M, N), [1, 2, 3, 0])'
438
+ f = lambdify((M, N), cg, 'tensorflow')
439
+ y = session.run(f(ma, mb))
440
+ c = session.run(tf.transpose(tf.einsum("ab,cd", ma, mb), [1, 2, 3, 0]))
441
+ assert (y == c).all()
442
+
443
+ cg = ArrayDiagonal(ArrayTensorProduct(M, N), (1, 2))
444
+ assert tensorflow_code(cg) == \
445
+ 'tensorflow.linalg.einsum("ab,bc->acb", M, N)'
446
+ f = lambdify((M, N), cg, 'tensorflow')
447
+ y = session.run(f(ma, mb))
448
+ c = session.run(tf.einsum("ab,bc->acb", ma, mb))
449
+ assert (y == c).all()
450
+
451
+
452
+ def test_MatrixElement_printing():
453
+ A = MatrixSymbol("A", 1, 3)
454
+ B = MatrixSymbol("B", 1, 3)
455
+ C = MatrixSymbol("C", 1, 3)
456
+
457
+ assert tensorflow_code(A[0, 0]) == "A[0, 0]"
458
+ assert tensorflow_code(3 * A[0, 0]) == "3*A[0, 0]"
459
+
460
+ F = C[0, 0].subs(C, A - B)
461
+ assert tensorflow_code(F) == "(tensorflow.math.add((-1)*B, A))[0, 0]"
462
+
463
+
464
+ def test_tensorflow_Derivative():
465
+ expr = Derivative(sin(x), x)
466
+ assert tensorflow_code(expr) == \
467
+ "tensorflow.gradients(tensorflow.math.sin(x), x)[0]"
468
+
469
+ def test_tensorflow_isnan_isinf():
470
+ if not tf:
471
+ skip("TensorFlow not installed")
472
+
473
+ # Test for isnan
474
+ x = symbols("x")
475
+ # Return 0 if x is of nan value, and 1 otherwise
476
+ expression = Piecewise((0.0, isnan(x)), (1.0, True))
477
+ printed_code = tensorflow_code(expression)
478
+ expected_printed_code = "tensorflow.where(tensorflow.math.is_nan(x), 0.0, 1.0)"
479
+ assert tensorflow_code(expression) == expected_printed_code, f"Incorrect printed result {printed_code}, expected {expected_printed_code}"
480
+ for _input, _expected in [(float('nan'), 0.0), (float('inf'), 1.0), (float('-inf'), 1.0), (1.0, 1.0)]:
481
+ _output = lambdify((x), expression, modules="tensorflow")(x=tf.constant([_input]))
482
+ assert (_output == _expected).numpy().all()
483
+
484
+ # Test for isinf
485
+ x = symbols("x")
486
+ # Return 0 if x is of nan value, and 1 otherwise
487
+ expression = Piecewise((0.0, isinf(x)), (1.0, True))
488
+ printed_code = tensorflow_code(expression)
489
+ expected_printed_code = "tensorflow.where(tensorflow.math.is_inf(x), 0.0, 1.0)"
490
+ assert tensorflow_code(expression) == expected_printed_code, f"Incorrect printed result {printed_code}, expected {expected_printed_code}"
491
+ for _input, _expected in [(float('inf'), 0.0), (float('-inf'), 0.0), (float('nan'), 1.0), (1.0, 1.0)]:
492
+ _output = lambdify((x), expression, modules="tensorflow")(x=tf.constant([_input]))
493
+ assert (_output == _expected).numpy().all()
outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_theanocode.py ADDED
@@ -0,0 +1,639 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Important note on tests in this module - the Theano printing functions use a
3
+ global cache by default, which means that tests using it will modify global
4
+ state and thus not be independent from each other. Instead of using the "cache"
5
+ keyword argument each time, this module uses the theano_code_ and
6
+ theano_function_ functions defined below which default to using a new, empty
7
+ cache instead.
8
+ """
9
+
10
+ import logging
11
+
12
+ from sympy.external import import_module
13
+ from sympy.testing.pytest import raises, SKIP, warns_deprecated_sympy
14
+
15
+ theanologger = logging.getLogger('theano.configdefaults')
16
+ theanologger.setLevel(logging.CRITICAL)
17
+ theano = import_module('theano')
18
+ theanologger.setLevel(logging.WARNING)
19
+
20
+
21
+ if theano:
22
+ import numpy as np
23
+ ts = theano.scalar
24
+ tt = theano.tensor
25
+ xt, yt, zt = [tt.scalar(name, 'floatX') for name in 'xyz']
26
+ Xt, Yt, Zt = [tt.tensor('floatX', (False, False), name=n) for n in 'XYZ']
27
+ else:
28
+ #bin/test will not execute any tests now
29
+ disabled = True
30
+
31
+ import sympy as sy
32
+ from sympy.core.singleton import S
33
+ from sympy.abc import x, y, z, t
34
+ from sympy.printing.theanocode import (theano_code, dim_handling,
35
+ theano_function)
36
+
37
+
38
+ # Default set of matrix symbols for testing - make square so we can both
39
+ # multiply and perform elementwise operations between them.
40
+ X, Y, Z = [sy.MatrixSymbol(n, 4, 4) for n in 'XYZ']
41
+
42
+ # For testing AppliedUndef
43
+ f_t = sy.Function('f')(t)
44
+
45
+
46
+ def theano_code_(expr, **kwargs):
47
+ """ Wrapper for theano_code that uses a new, empty cache by default. """
48
+ kwargs.setdefault('cache', {})
49
+ with warns_deprecated_sympy():
50
+ return theano_code(expr, **kwargs)
51
+
52
+ def theano_function_(inputs, outputs, **kwargs):
53
+ """ Wrapper for theano_function that uses a new, empty cache by default. """
54
+ kwargs.setdefault('cache', {})
55
+ with warns_deprecated_sympy():
56
+ return theano_function(inputs, outputs, **kwargs)
57
+
58
+
59
+ def fgraph_of(*exprs):
60
+ """ Transform SymPy expressions into Theano Computation.
61
+
62
+ Parameters
63
+ ==========
64
+ exprs
65
+ SymPy expressions
66
+
67
+ Returns
68
+ =======
69
+ theano.gof.FunctionGraph
70
+ """
71
+ outs = list(map(theano_code_, exprs))
72
+ ins = theano.gof.graph.inputs(outs)
73
+ ins, outs = theano.gof.graph.clone(ins, outs)
74
+ return theano.gof.FunctionGraph(ins, outs)
75
+
76
+
77
+ def theano_simplify(fgraph):
78
+ """ Simplify a Theano Computation.
79
+
80
+ Parameters
81
+ ==========
82
+ fgraph : theano.gof.FunctionGraph
83
+
84
+ Returns
85
+ =======
86
+ theano.gof.FunctionGraph
87
+ """
88
+ mode = theano.compile.get_default_mode().excluding("fusion")
89
+ fgraph = fgraph.clone()
90
+ mode.optimizer.optimize(fgraph)
91
+ return fgraph
92
+
93
+
94
+ def theq(a, b):
95
+ """ Test two Theano objects for equality.
96
+
97
+ Also accepts numeric types and lists/tuples of supported types.
98
+
99
+ Note - debugprint() has a bug where it will accept numeric types but does
100
+ not respect the "file" argument and in this case and instead prints the number
101
+ to stdout and returns an empty string. This can lead to tests passing where
102
+ they should fail because any two numbers will always compare as equal. To
103
+ prevent this we treat numbers as a separate case.
104
+ """
105
+ numeric_types = (int, float, np.number)
106
+ a_is_num = isinstance(a, numeric_types)
107
+ b_is_num = isinstance(b, numeric_types)
108
+
109
+ # Compare numeric types using regular equality
110
+ if a_is_num or b_is_num:
111
+ if not (a_is_num and b_is_num):
112
+ return False
113
+
114
+ return a == b
115
+
116
+ # Compare sequences element-wise
117
+ a_is_seq = isinstance(a, (tuple, list))
118
+ b_is_seq = isinstance(b, (tuple, list))
119
+
120
+ if a_is_seq or b_is_seq:
121
+ if not (a_is_seq and b_is_seq) or type(a) != type(b):
122
+ return False
123
+
124
+ return list(map(theq, a)) == list(map(theq, b))
125
+
126
+ # Otherwise, assume debugprint() can handle it
127
+ astr = theano.printing.debugprint(a, file='str')
128
+ bstr = theano.printing.debugprint(b, file='str')
129
+
130
+ # Check for bug mentioned above
131
+ for argname, argval, argstr in [('a', a, astr), ('b', b, bstr)]:
132
+ if argstr == '':
133
+ raise TypeError(
134
+ 'theano.printing.debugprint(%s) returned empty string '
135
+ '(%s is instance of %r)'
136
+ % (argname, argname, type(argval))
137
+ )
138
+
139
+ return astr == bstr
140
+
141
+
142
+ def test_example_symbols():
143
+ """
144
+ Check that the example symbols in this module print to their Theano
145
+ equivalents, as many of the other tests depend on this.
146
+ """
147
+ assert theq(xt, theano_code_(x))
148
+ assert theq(yt, theano_code_(y))
149
+ assert theq(zt, theano_code_(z))
150
+ assert theq(Xt, theano_code_(X))
151
+ assert theq(Yt, theano_code_(Y))
152
+ assert theq(Zt, theano_code_(Z))
153
+
154
+
155
+ def test_Symbol():
156
+ """ Test printing a Symbol to a theano variable. """
157
+ xx = theano_code_(x)
158
+ assert isinstance(xx, (tt.TensorVariable, ts.ScalarVariable))
159
+ assert xx.broadcastable == ()
160
+ assert xx.name == x.name
161
+
162
+ xx2 = theano_code_(x, broadcastables={x: (False,)})
163
+ assert xx2.broadcastable == (False,)
164
+ assert xx2.name == x.name
165
+
166
+ def test_MatrixSymbol():
167
+ """ Test printing a MatrixSymbol to a theano variable. """
168
+ XX = theano_code_(X)
169
+ assert isinstance(XX, tt.TensorVariable)
170
+ assert XX.broadcastable == (False, False)
171
+
172
+ @SKIP # TODO - this is currently not checked but should be implemented
173
+ def test_MatrixSymbol_wrong_dims():
174
+ """ Test MatrixSymbol with invalid broadcastable. """
175
+ bcs = [(), (False,), (True,), (True, False), (False, True,), (True, True)]
176
+ for bc in bcs:
177
+ with raises(ValueError):
178
+ theano_code_(X, broadcastables={X: bc})
179
+
180
+ def test_AppliedUndef():
181
+ """ Test printing AppliedUndef instance, which works similarly to Symbol. """
182
+ ftt = theano_code_(f_t)
183
+ assert isinstance(ftt, tt.TensorVariable)
184
+ assert ftt.broadcastable == ()
185
+ assert ftt.name == 'f_t'
186
+
187
+
188
+ def test_add():
189
+ expr = x + y
190
+ comp = theano_code_(expr)
191
+ assert comp.owner.op == theano.tensor.add
192
+
193
+ def test_trig():
194
+ assert theq(theano_code_(sy.sin(x)), tt.sin(xt))
195
+ assert theq(theano_code_(sy.tan(x)), tt.tan(xt))
196
+
197
+ def test_many():
198
+ """ Test printing a complex expression with multiple symbols. """
199
+ expr = sy.exp(x**2 + sy.cos(y)) * sy.log(2*z)
200
+ comp = theano_code_(expr)
201
+ expected = tt.exp(xt**2 + tt.cos(yt)) * tt.log(2*zt)
202
+ assert theq(comp, expected)
203
+
204
+
205
+ def test_dtype():
206
+ """ Test specifying specific data types through the dtype argument. """
207
+ for dtype in ['float32', 'float64', 'int8', 'int16', 'int32', 'int64']:
208
+ assert theano_code_(x, dtypes={x: dtype}).type.dtype == dtype
209
+
210
+ # "floatX" type
211
+ assert theano_code_(x, dtypes={x: 'floatX'}).type.dtype in ('float32', 'float64')
212
+
213
+ # Type promotion
214
+ assert theano_code_(x + 1, dtypes={x: 'float32'}).type.dtype == 'float32'
215
+ assert theano_code_(x + y, dtypes={x: 'float64', y: 'float32'}).type.dtype == 'float64'
216
+
217
+
218
+ def test_broadcastables():
219
+ """ Test the "broadcastables" argument when printing symbol-like objects. """
220
+
221
+ # No restrictions on shape
222
+ for s in [x, f_t]:
223
+ for bc in [(), (False,), (True,), (False, False), (True, False)]:
224
+ assert theano_code_(s, broadcastables={s: bc}).broadcastable == bc
225
+
226
+ # TODO - matrix broadcasting?
227
+
228
+ def test_broadcasting():
229
+ """ Test "broadcastable" attribute after applying element-wise binary op. """
230
+
231
+ expr = x + y
232
+
233
+ cases = [
234
+ [(), (), ()],
235
+ [(False,), (False,), (False,)],
236
+ [(True,), (False,), (False,)],
237
+ [(False, True), (False, False), (False, False)],
238
+ [(True, False), (False, False), (False, False)],
239
+ ]
240
+
241
+ for bc1, bc2, bc3 in cases:
242
+ comp = theano_code_(expr, broadcastables={x: bc1, y: bc2})
243
+ assert comp.broadcastable == bc3
244
+
245
+
246
+ def test_MatMul():
247
+ expr = X*Y*Z
248
+ expr_t = theano_code_(expr)
249
+ assert isinstance(expr_t.owner.op, tt.Dot)
250
+ assert theq(expr_t, Xt.dot(Yt).dot(Zt))
251
+
252
+ def test_Transpose():
253
+ assert isinstance(theano_code_(X.T).owner.op, tt.DimShuffle)
254
+
255
+ def test_MatAdd():
256
+ expr = X+Y+Z
257
+ assert isinstance(theano_code_(expr).owner.op, tt.Elemwise)
258
+
259
+
260
+ def test_Rationals():
261
+ assert theq(theano_code_(sy.Integer(2) / 3), tt.true_div(2, 3))
262
+ assert theq(theano_code_(S.Half), tt.true_div(1, 2))
263
+
264
+ def test_Integers():
265
+ assert theano_code_(sy.Integer(3)) == 3
266
+
267
+ def test_factorial():
268
+ n = sy.Symbol('n')
269
+ assert theano_code_(sy.factorial(n))
270
+
271
+ def test_Derivative():
272
+ simp = lambda expr: theano_simplify(fgraph_of(expr))
273
+ assert theq(simp(theano_code_(sy.Derivative(sy.sin(x), x, evaluate=False))),
274
+ simp(theano.grad(tt.sin(xt), xt)))
275
+
276
+
277
+ def test_theano_function_simple():
278
+ """ Test theano_function() with single output. """
279
+ f = theano_function_([x, y], [x+y])
280
+ assert f(2, 3) == 5
281
+
282
+ def test_theano_function_multi():
283
+ """ Test theano_function() with multiple outputs. """
284
+ f = theano_function_([x, y], [x+y, x-y])
285
+ o1, o2 = f(2, 3)
286
+ assert o1 == 5
287
+ assert o2 == -1
288
+
289
+ def test_theano_function_numpy():
290
+ """ Test theano_function() vs Numpy implementation. """
291
+ f = theano_function_([x, y], [x+y], dim=1,
292
+ dtypes={x: 'float64', y: 'float64'})
293
+ assert np.linalg.norm(f([1, 2], [3, 4]) - np.asarray([4, 6])) < 1e-9
294
+
295
+ f = theano_function_([x, y], [x+y], dtypes={x: 'float64', y: 'float64'},
296
+ dim=1)
297
+ xx = np.arange(3).astype('float64')
298
+ yy = 2*np.arange(3).astype('float64')
299
+ assert np.linalg.norm(f(xx, yy) - 3*np.arange(3)) < 1e-9
300
+
301
+
302
+ def test_theano_function_matrix():
303
+ m = sy.Matrix([[x, y], [z, x + y + z]])
304
+ expected = np.array([[1.0, 2.0], [3.0, 1.0 + 2.0 + 3.0]])
305
+ f = theano_function_([x, y, z], [m])
306
+ np.testing.assert_allclose(f(1.0, 2.0, 3.0), expected)
307
+ f = theano_function_([x, y, z], [m], scalar=True)
308
+ np.testing.assert_allclose(f(1.0, 2.0, 3.0), expected)
309
+ f = theano_function_([x, y, z], [m, m])
310
+ assert isinstance(f(1.0, 2.0, 3.0), type([]))
311
+ np.testing.assert_allclose(f(1.0, 2.0, 3.0)[0], expected)
312
+ np.testing.assert_allclose(f(1.0, 2.0, 3.0)[1], expected)
313
+
314
+ def test_dim_handling():
315
+ assert dim_handling([x], dim=2) == {x: (False, False)}
316
+ assert dim_handling([x, y], dims={x: 1, y: 2}) == {x: (False, True),
317
+ y: (False, False)}
318
+ assert dim_handling([x], broadcastables={x: (False,)}) == {x: (False,)}
319
+
320
+ def test_theano_function_kwargs():
321
+ """
322
+ Test passing additional kwargs from theano_function() to theano.function().
323
+ """
324
+ import numpy as np
325
+ f = theano_function_([x, y, z], [x+y], dim=1, on_unused_input='ignore',
326
+ dtypes={x: 'float64', y: 'float64', z: 'float64'})
327
+ assert np.linalg.norm(f([1, 2], [3, 4], [0, 0]) - np.asarray([4, 6])) < 1e-9
328
+
329
+ f = theano_function_([x, y, z], [x+y],
330
+ dtypes={x: 'float64', y: 'float64', z: 'float64'},
331
+ dim=1, on_unused_input='ignore')
332
+ xx = np.arange(3).astype('float64')
333
+ yy = 2*np.arange(3).astype('float64')
334
+ zz = 2*np.arange(3).astype('float64')
335
+ assert np.linalg.norm(f(xx, yy, zz) - 3*np.arange(3)) < 1e-9
336
+
337
+ def test_theano_function_scalar():
338
+ """ Test the "scalar" argument to theano_function(). """
339
+
340
+ args = [
341
+ ([x, y], [x + y], None, [0]), # Single 0d output
342
+ ([X, Y], [X + Y], None, [2]), # Single 2d output
343
+ ([x, y], [x + y], {x: 0, y: 1}, [1]), # Single 1d output
344
+ ([x, y], [x + y, x - y], None, [0, 0]), # Two 0d outputs
345
+ ([x, y, X, Y], [x + y, X + Y], None, [0, 2]), # One 0d output, one 2d
346
+ ]
347
+
348
+ # Create and test functions with and without the scalar setting
349
+ for inputs, outputs, in_dims, out_dims in args:
350
+ for scalar in [False, True]:
351
+
352
+ f = theano_function_(inputs, outputs, dims=in_dims, scalar=scalar)
353
+
354
+ # Check the theano_function attribute is set whether wrapped or not
355
+ assert isinstance(f.theano_function, theano.compile.function_module.Function)
356
+
357
+ # Feed in inputs of the appropriate size and get outputs
358
+ in_values = [
359
+ np.ones([1 if bc else 5 for bc in i.type.broadcastable])
360
+ for i in f.theano_function.input_storage
361
+ ]
362
+ out_values = f(*in_values)
363
+ if not isinstance(out_values, list):
364
+ out_values = [out_values]
365
+
366
+ # Check output types and shapes
367
+ assert len(out_dims) == len(out_values)
368
+ for d, value in zip(out_dims, out_values):
369
+
370
+ if scalar and d == 0:
371
+ # Should have been converted to a scalar value
372
+ assert isinstance(value, np.number)
373
+
374
+ else:
375
+ # Otherwise should be an array
376
+ assert isinstance(value, np.ndarray)
377
+ assert value.ndim == d
378
+
379
+ def test_theano_function_bad_kwarg():
380
+ """
381
+ Passing an unknown keyword argument to theano_function() should raise an
382
+ exception.
383
+ """
384
+ raises(Exception, lambda : theano_function_([x], [x+1], foobar=3))
385
+
386
+
387
+ def test_slice():
388
+ assert theano_code_(slice(1, 2, 3)) == slice(1, 2, 3)
389
+
390
+ def theq_slice(s1, s2):
391
+ for attr in ['start', 'stop', 'step']:
392
+ a1 = getattr(s1, attr)
393
+ a2 = getattr(s2, attr)
394
+ if a1 is None or a2 is None:
395
+ if not (a1 is None or a2 is None):
396
+ return False
397
+ elif not theq(a1, a2):
398
+ return False
399
+ return True
400
+
401
+ dtypes = {x: 'int32', y: 'int32'}
402
+ assert theq_slice(theano_code_(slice(x, y), dtypes=dtypes), slice(xt, yt))
403
+ assert theq_slice(theano_code_(slice(1, x, 3), dtypes=dtypes), slice(1, xt, 3))
404
+
405
+ def test_MatrixSlice():
406
+ from theano import Constant
407
+
408
+ cache = {}
409
+
410
+ n = sy.Symbol('n', integer=True)
411
+ X = sy.MatrixSymbol('X', n, n)
412
+
413
+ Y = X[1:2:3, 4:5:6]
414
+ Yt = theano_code_(Y, cache=cache)
415
+
416
+ s = ts.Scalar('int64')
417
+ assert tuple(Yt.owner.op.idx_list) == (slice(s, s, s), slice(s, s, s))
418
+ assert Yt.owner.inputs[0] == theano_code_(X, cache=cache)
419
+ # == doesn't work in theano like it does in SymPy. You have to use
420
+ # equals.
421
+ assert all(Yt.owner.inputs[i].equals(Constant(s, i)) for i in range(1, 7))
422
+
423
+ k = sy.Symbol('k')
424
+ theano_code_(k, dtypes={k: 'int32'})
425
+ start, stop, step = 4, k, 2
426
+ Y = X[start:stop:step]
427
+ Yt = theano_code_(Y, dtypes={n: 'int32', k: 'int32'})
428
+ # assert Yt.owner.op.idx_list[0].stop == kt
429
+
430
+ def test_BlockMatrix():
431
+ n = sy.Symbol('n', integer=True)
432
+ A, B, C, D = [sy.MatrixSymbol(name, n, n) for name in 'ABCD']
433
+ At, Bt, Ct, Dt = map(theano_code_, (A, B, C, D))
434
+ Block = sy.BlockMatrix([[A, B], [C, D]])
435
+ Blockt = theano_code_(Block)
436
+ solutions = [tt.join(0, tt.join(1, At, Bt), tt.join(1, Ct, Dt)),
437
+ tt.join(1, tt.join(0, At, Ct), tt.join(0, Bt, Dt))]
438
+ assert any(theq(Blockt, solution) for solution in solutions)
439
+
440
+ @SKIP
441
+ def test_BlockMatrix_Inverse_execution():
442
+ k, n = 2, 4
443
+ dtype = 'float32'
444
+ A = sy.MatrixSymbol('A', n, k)
445
+ B = sy.MatrixSymbol('B', n, n)
446
+ inputs = A, B
447
+ output = B.I*A
448
+
449
+ cutsizes = {A: [(n//2, n//2), (k//2, k//2)],
450
+ B: [(n//2, n//2), (n//2, n//2)]}
451
+ cutinputs = [sy.blockcut(i, *cutsizes[i]) for i in inputs]
452
+ cutoutput = output.subs(dict(zip(inputs, cutinputs)))
453
+
454
+ dtypes = dict(zip(inputs, [dtype]*len(inputs)))
455
+ f = theano_function_(inputs, [output], dtypes=dtypes, cache={})
456
+ fblocked = theano_function_(inputs, [sy.block_collapse(cutoutput)],
457
+ dtypes=dtypes, cache={})
458
+
459
+ ninputs = [np.random.rand(*x.shape).astype(dtype) for x in inputs]
460
+ ninputs = [np.arange(n*k).reshape(A.shape).astype(dtype),
461
+ np.eye(n).astype(dtype)]
462
+ ninputs[1] += np.ones(B.shape)*1e-5
463
+
464
+ assert np.allclose(f(*ninputs), fblocked(*ninputs), rtol=1e-5)
465
+
466
+ def test_DenseMatrix():
467
+ t = sy.Symbol('theta')
468
+ for MatrixType in [sy.Matrix, sy.ImmutableMatrix]:
469
+ X = MatrixType([[sy.cos(t), -sy.sin(t)], [sy.sin(t), sy.cos(t)]])
470
+ tX = theano_code_(X)
471
+ assert isinstance(tX, tt.TensorVariable)
472
+ assert tX.owner.op == tt.join_
473
+
474
+
475
+ def test_cache_basic():
476
+ """ Test single symbol-like objects are cached when printed by themselves. """
477
+
478
+ # Pairs of objects which should be considered equivalent with respect to caching
479
+ pairs = [
480
+ (x, sy.Symbol('x')),
481
+ (X, sy.MatrixSymbol('X', *X.shape)),
482
+ (f_t, sy.Function('f')(sy.Symbol('t'))),
483
+ ]
484
+
485
+ for s1, s2 in pairs:
486
+ cache = {}
487
+ st = theano_code_(s1, cache=cache)
488
+
489
+ # Test hit with same instance
490
+ assert theano_code_(s1, cache=cache) is st
491
+
492
+ # Test miss with same instance but new cache
493
+ assert theano_code_(s1, cache={}) is not st
494
+
495
+ # Test hit with different but equivalent instance
496
+ assert theano_code_(s2, cache=cache) is st
497
+
498
+ def test_global_cache():
499
+ """ Test use of the global cache. """
500
+ from sympy.printing.theanocode import global_cache
501
+
502
+ backup = dict(global_cache)
503
+ try:
504
+ # Temporarily empty global cache
505
+ global_cache.clear()
506
+
507
+ for s in [x, X, f_t]:
508
+ with warns_deprecated_sympy():
509
+ st = theano_code(s)
510
+ assert theano_code(s) is st
511
+
512
+ finally:
513
+ # Restore global cache
514
+ global_cache.update(backup)
515
+
516
+ def test_cache_types_distinct():
517
+ """
518
+ Test that symbol-like objects of different types (Symbol, MatrixSymbol,
519
+ AppliedUndef) are distinguished by the cache even if they have the same
520
+ name.
521
+ """
522
+ symbols = [sy.Symbol('f_t'), sy.MatrixSymbol('f_t', 4, 4), f_t]
523
+
524
+ cache = {} # Single shared cache
525
+ printed = {}
526
+
527
+ for s in symbols:
528
+ st = theano_code_(s, cache=cache)
529
+ assert st not in printed.values()
530
+ printed[s] = st
531
+
532
+ # Check all printed objects are distinct
533
+ assert len(set(map(id, printed.values()))) == len(symbols)
534
+
535
+ # Check retrieving
536
+ for s, st in printed.items():
537
+ with warns_deprecated_sympy():
538
+ assert theano_code(s, cache=cache) is st
539
+
540
+ def test_symbols_are_created_once():
541
+ """
542
+ Test that a symbol is cached and reused when it appears in an expression
543
+ more than once.
544
+ """
545
+ expr = sy.Add(x, x, evaluate=False)
546
+ comp = theano_code_(expr)
547
+
548
+ assert theq(comp, xt + xt)
549
+ assert not theq(comp, xt + theano_code_(x))
550
+
551
+ def test_cache_complex():
552
+ """
553
+ Test caching on a complicated expression with multiple symbols appearing
554
+ multiple times.
555
+ """
556
+ expr = x ** 2 + (y - sy.exp(x)) * sy.sin(z - x * y)
557
+ symbol_names = {s.name for s in expr.free_symbols}
558
+ expr_t = theano_code_(expr)
559
+
560
+ # Iterate through variables in the Theano computational graph that the
561
+ # printed expression depends on
562
+ seen = set()
563
+ for v in theano.gof.graph.ancestors([expr_t]):
564
+ # Owner-less, non-constant variables should be our symbols
565
+ if v.owner is None and not isinstance(v, theano.gof.graph.Constant):
566
+ # Check it corresponds to a symbol and appears only once
567
+ assert v.name in symbol_names
568
+ assert v.name not in seen
569
+ seen.add(v.name)
570
+
571
+ # Check all were present
572
+ assert seen == symbol_names
573
+
574
+
575
+ def test_Piecewise():
576
+ # A piecewise linear
577
+ expr = sy.Piecewise((0, x<0), (x, x<2), (1, True)) # ___/III
578
+ result = theano_code_(expr)
579
+ assert result.owner.op == tt.switch
580
+
581
+ expected = tt.switch(xt<0, 0, tt.switch(xt<2, xt, 1))
582
+ assert theq(result, expected)
583
+
584
+ expr = sy.Piecewise((x, x < 0))
585
+ result = theano_code_(expr)
586
+ expected = tt.switch(xt < 0, xt, np.nan)
587
+ assert theq(result, expected)
588
+
589
+ expr = sy.Piecewise((0, sy.And(x>0, x<2)), \
590
+ (x, sy.Or(x>2, x<0)))
591
+ result = theano_code_(expr)
592
+ expected = tt.switch(tt.and_(xt>0,xt<2), 0, \
593
+ tt.switch(tt.or_(xt>2, xt<0), xt, np.nan))
594
+ assert theq(result, expected)
595
+
596
+
597
+ def test_Relationals():
598
+ assert theq(theano_code_(sy.Eq(x, y)), tt.eq(xt, yt))
599
+ # assert theq(theano_code_(sy.Ne(x, y)), tt.neq(xt, yt)) # TODO - implement
600
+ assert theq(theano_code_(x > y), xt > yt)
601
+ assert theq(theano_code_(x < y), xt < yt)
602
+ assert theq(theano_code_(x >= y), xt >= yt)
603
+ assert theq(theano_code_(x <= y), xt <= yt)
604
+
605
+
606
+ def test_complexfunctions():
607
+ with warns_deprecated_sympy():
608
+ xt, yt = theano_code_(x, dtypes={x:'complex128'}), theano_code_(y, dtypes={y: 'complex128'})
609
+ from sympy.functions.elementary.complexes import conjugate
610
+ from theano.tensor import as_tensor_variable as atv
611
+ from theano.tensor import complex as cplx
612
+ with warns_deprecated_sympy():
613
+ assert theq(theano_code_(y*conjugate(x)), yt*(xt.conj()))
614
+ assert theq(theano_code_((1+2j)*x), xt*(atv(1.0)+atv(2.0)*cplx(0,1)))
615
+
616
+
617
+ def test_constantfunctions():
618
+ with warns_deprecated_sympy():
619
+ tf = theano_function_([],[1+1j])
620
+ assert(tf()==1+1j)
621
+
622
+
623
+ def test_Exp1():
624
+ """
625
+ Test that exp(1) prints without error and evaluates close to SymPy's E
626
+ """
627
+ # sy.exp(1) should yield same instance of E as sy.E (singleton), but extra
628
+ # check added for sanity
629
+ e_a = sy.exp(1)
630
+ e_b = sy.E
631
+
632
+ np.testing.assert_allclose(float(e_a), np.e)
633
+ np.testing.assert_allclose(float(e_b), np.e)
634
+
635
+ e = theano_code_(e_a)
636
+ np.testing.assert_allclose(float(e_a), e.eval())
637
+
638
+ e = theano_code_(e_b)
639
+ np.testing.assert_allclose(float(e_b), e.eval())
outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_torch.py ADDED
@@ -0,0 +1,531 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ import math
3
+
4
+ from sympy import symbols, Derivative
5
+ from sympy.printing.pytorch import torch_code
6
+ from sympy import (eye, MatrixSymbol, Matrix)
7
+ from sympy.tensor.array import NDimArray
8
+ from sympy.tensor.array.expressions.array_expressions import (
9
+ ArrayTensorProduct, ArrayAdd,
10
+ PermuteDims, ArrayDiagonal, _CodegenArrayAbstract)
11
+ from sympy.utilities.lambdify import lambdify
12
+ from sympy.core.relational import Eq, Ne, Ge, Gt, Le, Lt
13
+ from sympy.functions import \
14
+ Abs, ceiling, exp, floor, sign, sin, asin, cos, \
15
+ acos, tan, atan, atan2, cosh, acosh, sinh, asinh, tanh, atanh, \
16
+ re, im, arg, erf, loggamma, sqrt
17
+ from sympy.testing.pytest import skip
18
+ from sympy.external import import_module
19
+ from sympy.matrices.expressions import \
20
+ Determinant, HadamardProduct, Inverse, Trace
21
+ from sympy.matrices import randMatrix
22
+ from sympy.matrices import Identity, ZeroMatrix, OneMatrix
23
+ from sympy import conjugate, I
24
+ from sympy import Heaviside, gamma, polygamma
25
+
26
+
27
+
28
+ torch = import_module("torch")
29
+
30
+ M = MatrixSymbol("M", 3, 3)
31
+ N = MatrixSymbol("N", 3, 3)
32
+ P = MatrixSymbol("P", 3, 3)
33
+ Q = MatrixSymbol("Q", 3, 3)
34
+
35
+ x, y, z, t = symbols("x y z t")
36
+
37
+ if torch is not None:
38
+ llo = [list(range(i, i + 3)) for i in range(0, 9, 3)]
39
+ m3x3 = torch.tensor(llo, dtype=torch.float64)
40
+ m3x3sympy = Matrix(llo)
41
+
42
+
43
+ def _compare_torch_matrix(variables, expr):
44
+ f = lambdify(variables, expr, 'torch')
45
+
46
+ random_matrices = [randMatrix(i.shape[0], i.shape[1]) for i in variables]
47
+ random_variables = [torch.tensor(i.tolist(), dtype=torch.float64) for i in random_matrices]
48
+ r = f(*random_variables)
49
+ e = expr.subs(dict(zip(variables, random_matrices))).doit()
50
+
51
+ if isinstance(e, _CodegenArrayAbstract):
52
+ e = e.doit()
53
+
54
+ if hasattr(e, 'is_number') and e.is_number:
55
+ if isinstance(r, torch.Tensor) and r.dim() == 0:
56
+ r = r.item()
57
+ e = float(e)
58
+ assert abs(r - e) < 1e-6
59
+ return
60
+
61
+ if e.is_Matrix or isinstance(e, NDimArray):
62
+ e = torch.tensor(e.tolist(), dtype=torch.float64)
63
+ assert torch.allclose(r, e, atol=1e-6)
64
+ else:
65
+ raise TypeError(f"Cannot compare {type(r)} with {type(e)}")
66
+
67
+
68
+ def _compare_torch_scalar(variables, expr, rng=lambda: random.uniform(-5, 5)):
69
+ f = lambdify(variables, expr, 'torch')
70
+ rvs = [rng() for v in variables]
71
+ t_rvs = [torch.tensor(i, dtype=torch.float64) for i in rvs]
72
+ r = f(*t_rvs)
73
+ if isinstance(r, torch.Tensor):
74
+ r = r.item()
75
+ e = expr.subs(dict(zip(variables, rvs))).doit()
76
+ assert abs(r - e) < 1e-6
77
+
78
+
79
+ def _compare_torch_relational(variables, expr, rng=lambda: random.randint(0, 10)):
80
+ f = lambdify(variables, expr, 'torch')
81
+ rvs = [rng() for v in variables]
82
+ t_rvs = [torch.tensor(i, dtype=torch.float64) for i in rvs]
83
+ r = f(*t_rvs)
84
+ e = bool(expr.subs(dict(zip(variables, rvs))).doit())
85
+ assert r.item() == e
86
+
87
+
88
+ def test_torch_math():
89
+ if not torch:
90
+ skip("PyTorch not installed")
91
+
92
+ expr = Abs(x)
93
+ assert torch_code(expr) == "torch.abs(x)"
94
+ f = lambdify(x, expr, 'torch')
95
+ ma = torch.tensor([[-1, 2, -3, -4]], dtype=torch.float64)
96
+ y_abs = f(ma)
97
+ c = torch.abs(ma)
98
+ assert torch.all(y_abs == c)
99
+
100
+ expr = sign(x)
101
+ assert torch_code(expr) == "torch.sign(x)"
102
+ _compare_torch_scalar((x,), expr, rng=lambda: random.uniform(-10, 10))
103
+
104
+ expr = ceiling(x)
105
+ assert torch_code(expr) == "torch.ceil(x)"
106
+ _compare_torch_scalar((x,), expr, rng=lambda: random.random())
107
+
108
+ expr = floor(x)
109
+ assert torch_code(expr) == "torch.floor(x)"
110
+ _compare_torch_scalar((x,), expr, rng=lambda: random.random())
111
+
112
+ expr = exp(x)
113
+ assert torch_code(expr) == "torch.exp(x)"
114
+ _compare_torch_scalar((x,), expr, rng=lambda: random.uniform(-2, 2))
115
+
116
+ expr = sqrt(x)
117
+ assert torch_code(expr) == "torch.sqrt(x)"
118
+ _compare_torch_scalar((x,), expr, rng=lambda: random.random())
119
+
120
+ expr = x ** 4
121
+ assert torch_code(expr) == "torch.pow(x, 4)"
122
+ _compare_torch_scalar((x,), expr, rng=lambda: random.random())
123
+
124
+ expr = cos(x)
125
+ assert torch_code(expr) == "torch.cos(x)"
126
+ _compare_torch_scalar((x,), expr, rng=lambda: random.random())
127
+
128
+ expr = acos(x)
129
+ assert torch_code(expr) == "torch.acos(x)"
130
+ _compare_torch_scalar((x,), expr, rng=lambda: random.uniform(-0.99, 0.99))
131
+
132
+ expr = sin(x)
133
+ assert torch_code(expr) == "torch.sin(x)"
134
+ _compare_torch_scalar((x,), expr, rng=lambda: random.random())
135
+
136
+ expr = asin(x)
137
+ assert torch_code(expr) == "torch.asin(x)"
138
+ _compare_torch_scalar((x,), expr, rng=lambda: random.uniform(-0.99, 0.99))
139
+
140
+ expr = tan(x)
141
+ assert torch_code(expr) == "torch.tan(x)"
142
+ _compare_torch_scalar((x,), expr, rng=lambda: random.uniform(-1.5, 1.5))
143
+
144
+ expr = atan(x)
145
+ assert torch_code(expr) == "torch.atan(x)"
146
+ _compare_torch_scalar((x,), expr, rng=lambda: random.uniform(-5, 5))
147
+
148
+ expr = atan2(y, x)
149
+ assert torch_code(expr) == "torch.atan2(y, x)"
150
+ _compare_torch_scalar((y, x), expr, rng=lambda: random.uniform(-5, 5))
151
+
152
+ expr = cosh(x)
153
+ assert torch_code(expr) == "torch.cosh(x)"
154
+ _compare_torch_scalar((x,), expr, rng=lambda: random.uniform(-2, 2))
155
+
156
+ expr = acosh(x)
157
+ assert torch_code(expr) == "torch.acosh(x)"
158
+ _compare_torch_scalar((x,), expr, rng=lambda: random.uniform(1.1, 5))
159
+
160
+ expr = sinh(x)
161
+ assert torch_code(expr) == "torch.sinh(x)"
162
+ _compare_torch_scalar((x,), expr, rng=lambda: random.uniform(-2, 2))
163
+
164
+ expr = asinh(x)
165
+ assert torch_code(expr) == "torch.asinh(x)"
166
+ _compare_torch_scalar((x,), expr, rng=lambda: random.uniform(-5, 5))
167
+
168
+ expr = tanh(x)
169
+ assert torch_code(expr) == "torch.tanh(x)"
170
+ _compare_torch_scalar((x,), expr, rng=lambda: random.uniform(-2, 2))
171
+
172
+ expr = atanh(x)
173
+ assert torch_code(expr) == "torch.atanh(x)"
174
+ _compare_torch_scalar((x,), expr, rng=lambda: random.uniform(-0.9, 0.9))
175
+
176
+ expr = erf(x)
177
+ assert torch_code(expr) == "torch.erf(x)"
178
+ _compare_torch_scalar((x,), expr, rng=lambda: random.uniform(-2, 2))
179
+
180
+ expr = loggamma(x)
181
+ assert torch_code(expr) == "torch.lgamma(x)"
182
+ _compare_torch_scalar((x,), expr, rng=lambda: random.uniform(0.5, 5))
183
+
184
+
185
+ def test_torch_complexes():
186
+ assert torch_code(re(x)) == "torch.real(x)"
187
+ assert torch_code(im(x)) == "torch.imag(x)"
188
+ assert torch_code(arg(x)) == "torch.angle(x)"
189
+
190
+
191
+ def test_torch_relational():
192
+ if not torch:
193
+ skip("PyTorch not installed")
194
+
195
+ expr = Eq(x, y)
196
+ assert torch_code(expr) == "torch.eq(x, y)"
197
+ _compare_torch_relational((x, y), expr)
198
+
199
+ expr = Ne(x, y)
200
+ assert torch_code(expr) == "torch.ne(x, y)"
201
+ _compare_torch_relational((x, y), expr)
202
+
203
+ expr = Ge(x, y)
204
+ assert torch_code(expr) == "torch.ge(x, y)"
205
+ _compare_torch_relational((x, y), expr)
206
+
207
+ expr = Gt(x, y)
208
+ assert torch_code(expr) == "torch.gt(x, y)"
209
+ _compare_torch_relational((x, y), expr)
210
+
211
+ expr = Le(x, y)
212
+ assert torch_code(expr) == "torch.le(x, y)"
213
+ _compare_torch_relational((x, y), expr)
214
+
215
+ expr = Lt(x, y)
216
+ assert torch_code(expr) == "torch.lt(x, y)"
217
+ _compare_torch_relational((x, y), expr)
218
+
219
+
220
+ def test_torch_matrix():
221
+ if torch is None:
222
+ skip("PyTorch not installed")
223
+
224
+ expr = M
225
+ assert torch_code(expr) == "M"
226
+ f = lambdify((M,), expr, "torch")
227
+ eye_mat = eye(3)
228
+ eye_tensor = torch.tensor(eye_mat.tolist(), dtype=torch.float64)
229
+ assert torch.allclose(f(eye_tensor), eye_tensor)
230
+
231
+ expr = M * N
232
+ assert torch_code(expr) == "torch.matmul(M, N)"
233
+ _compare_torch_matrix((M, N), expr)
234
+
235
+ expr = M ** 3
236
+ assert torch_code(expr) == "torch.mm(torch.mm(M, M), M)"
237
+ _compare_torch_matrix((M,), expr)
238
+
239
+ expr = M * N * P * Q
240
+ assert torch_code(expr) == "torch.matmul(torch.matmul(torch.matmul(M, N), P), Q)"
241
+ _compare_torch_matrix((M, N, P, Q), expr)
242
+
243
+ expr = Trace(M)
244
+ assert torch_code(expr) == "torch.trace(M)"
245
+ _compare_torch_matrix((M,), expr)
246
+
247
+ expr = Determinant(M)
248
+ assert torch_code(expr) == "torch.det(M)"
249
+ _compare_torch_matrix((M,), expr)
250
+
251
+ expr = HadamardProduct(M, N)
252
+ assert torch_code(expr) == "torch.mul(M, N)"
253
+ _compare_torch_matrix((M, N), expr)
254
+
255
+ expr = Inverse(M)
256
+ assert torch_code(expr) == "torch.linalg.inv(M)"
257
+
258
+ # For inverse, use a matrix that's guaranteed to be invertible
259
+ eye_mat = eye(3)
260
+ eye_tensor = torch.tensor(eye_mat.tolist(), dtype=torch.float64)
261
+ f = lambdify((M,), expr, "torch")
262
+ result = f(eye_tensor)
263
+ expected = torch.linalg.inv(eye_tensor)
264
+ assert torch.allclose(result, expected)
265
+
266
+
267
+ def test_torch_array_operations():
268
+ if not torch:
269
+ skip("PyTorch not installed")
270
+
271
+ M = MatrixSymbol("M", 2, 2)
272
+ N = MatrixSymbol("N", 2, 2)
273
+ P = MatrixSymbol("P", 2, 2)
274
+ Q = MatrixSymbol("Q", 2, 2)
275
+
276
+ ma = torch.tensor([[1., 2.], [3., 4.]], dtype=torch.float64)
277
+ mb = torch.tensor([[1., -2.], [-1., 3.]], dtype=torch.float64)
278
+ mc = torch.tensor([[2., 0.], [1., 2.]], dtype=torch.float64)
279
+ md = torch.tensor([[1., -1.], [4., 7.]], dtype=torch.float64)
280
+
281
+ cg = ArrayTensorProduct(M, N)
282
+ assert torch_code(cg) == 'torch.einsum("ab,cd", M, N)'
283
+ f = lambdify((M, N), cg, 'torch')
284
+ y = f(ma, mb)
285
+ c = torch.einsum("ij,kl", ma, mb)
286
+ assert torch.allclose(y, c)
287
+
288
+ cg = ArrayAdd(M, N)
289
+ assert torch_code(cg) == 'torch.add(M, N)'
290
+ f = lambdify((M, N), cg, 'torch')
291
+ y = f(ma, mb)
292
+ c = ma + mb
293
+ assert torch.allclose(y, c)
294
+
295
+ cg = ArrayAdd(M, N, P)
296
+ assert torch_code(cg) == 'torch.add(torch.add(M, N), P)'
297
+ f = lambdify((M, N, P), cg, 'torch')
298
+ y = f(ma, mb, mc)
299
+ c = ma + mb + mc
300
+ assert torch.allclose(y, c)
301
+
302
+ cg = ArrayAdd(M, N, P, Q)
303
+ assert torch_code(cg) == 'torch.add(torch.add(torch.add(M, N), P), Q)'
304
+ f = lambdify((M, N, P, Q), cg, 'torch')
305
+ y = f(ma, mb, mc, md)
306
+ c = ma + mb + mc + md
307
+ assert torch.allclose(y, c)
308
+
309
+ cg = PermuteDims(M, [1, 0])
310
+ assert torch_code(cg) == 'M.permute(1, 0)'
311
+ f = lambdify((M,), cg, 'torch')
312
+ y = f(ma)
313
+ c = ma.T
314
+ assert torch.allclose(y, c)
315
+
316
+ cg = PermuteDims(ArrayTensorProduct(M, N), [1, 2, 3, 0])
317
+ assert torch_code(cg) == 'torch.einsum("ab,cd", M, N).permute(1, 2, 3, 0)'
318
+ f = lambdify((M, N), cg, 'torch')
319
+ y = f(ma, mb)
320
+ c = torch.einsum("ab,cd", ma, mb).permute(1, 2, 3, 0)
321
+ assert torch.allclose(y, c)
322
+
323
+ cg = ArrayDiagonal(ArrayTensorProduct(M, N), (1, 2))
324
+ assert torch_code(cg) == 'torch.einsum("ab,bc->acb", M, N)'
325
+ f = lambdify((M, N), cg, 'torch')
326
+ y = f(ma, mb)
327
+ c = torch.einsum("ab,bc->acb", ma, mb)
328
+ assert torch.allclose(y, c)
329
+
330
+
331
+ def test_torch_derivative():
332
+ """Test derivative handling."""
333
+ expr = Derivative(sin(x), x)
334
+ assert torch_code(expr) == 'torch.autograd.grad(torch.sin(x), x)[0]'
335
+
336
+
337
+ def test_torch_printing_dtype():
338
+ if not torch:
339
+ skip("PyTorch not installed")
340
+
341
+ # matrix printing with default dtype
342
+ expr = Matrix([[x, sin(y)], [exp(z), -t]])
343
+ assert "dtype=torch.float64" in torch_code(expr)
344
+
345
+ # explicit dtype
346
+ assert "dtype=torch.float32" in torch_code(expr, dtype="torch.float32")
347
+
348
+ # with requires_grad
349
+ result = torch_code(expr, requires_grad=True)
350
+ assert "requires_grad=True" in result
351
+ assert "dtype=torch.float64" in result
352
+
353
+ # both
354
+ result = torch_code(expr, requires_grad=True, dtype="torch.float32")
355
+ assert "requires_grad=True" in result
356
+ assert "dtype=torch.float32" in result
357
+
358
+
359
+ def test_requires_grad():
360
+ if not torch:
361
+ skip("PyTorch not installed")
362
+
363
+ expr = sin(x) + cos(y)
364
+ f = lambdify([x, y], expr, 'torch')
365
+
366
+ # make sure the gradients flow
367
+ x_val = torch.tensor(1.0, requires_grad=True)
368
+ y_val = torch.tensor(2.0, requires_grad=True)
369
+ result = f(x_val, y_val)
370
+ assert result.requires_grad
371
+ result.backward()
372
+
373
+ # x_val.grad should be cos(x_val) which is close to cos(1.0)
374
+ assert abs(x_val.grad.item() - float(cos(1.0).evalf())) < 1e-6
375
+
376
+ # y_val.grad should be -sin(y_val) which is close to -sin(2.0)
377
+ assert abs(y_val.grad.item() - float(-sin(2.0).evalf())) < 1e-6
378
+
379
+
380
+ def test_torch_multi_variable_derivatives():
381
+ if not torch:
382
+ skip("PyTorch not installed")
383
+
384
+ x, y, z = symbols("x y z")
385
+
386
+ expr = Derivative(sin(x), x)
387
+ assert torch_code(expr) == "torch.autograd.grad(torch.sin(x), x)[0]"
388
+
389
+ expr = Derivative(sin(x), (x, 2))
390
+ assert torch_code(
391
+ expr) == "torch.autograd.grad(torch.autograd.grad(torch.sin(x), x, create_graph=True)[0], x, create_graph=True)[0]"
392
+
393
+ expr = Derivative(sin(x * y), x, y)
394
+ result = torch_code(expr)
395
+ expected = "torch.autograd.grad(torch.autograd.grad(torch.sin(x*y), x, create_graph=True)[0], y, create_graph=True)[0]"
396
+ normalized_result = result.replace(" ", "")
397
+ normalized_expected = expected.replace(" ", "")
398
+ assert normalized_result == normalized_expected
399
+
400
+ expr = Derivative(sin(x), x, x)
401
+ result = torch_code(expr)
402
+ expected = "torch.autograd.grad(torch.autograd.grad(torch.sin(x), x, create_graph=True)[0], x, create_graph=True)[0]"
403
+ assert result == expected
404
+
405
+ expr = Derivative(sin(x * y * z), x, (y, 2), z)
406
+ result = torch_code(expr)
407
+ expected = "torch.autograd.grad(torch.autograd.grad(torch.autograd.grad(torch.autograd.grad(torch.sin(x*y*z), x, create_graph=True)[0], y, create_graph=True)[0], y, create_graph=True)[0], z, create_graph=True)[0]"
408
+ normalized_result = result.replace(" ", "")
409
+ normalized_expected = expected.replace(" ", "")
410
+ assert normalized_result == normalized_expected
411
+
412
+
413
+ def test_torch_derivative_lambdify():
414
+ if not torch:
415
+ skip("PyTorch not installed")
416
+
417
+ x = symbols("x")
418
+ y = symbols("y")
419
+
420
+ expr = Derivative(x ** 2, x)
421
+ f = lambdify(x, expr, 'torch')
422
+ x_val = torch.tensor(2.0, requires_grad=True)
423
+ result = f(x_val)
424
+ assert torch.isclose(result, torch.tensor(4.0))
425
+
426
+ expr = Derivative(sin(x), (x, 2))
427
+ f = lambdify(x, expr, 'torch')
428
+ # Second derivative of sin(x) at x=0 is 0, not -1
429
+ x_val = torch.tensor(0.0, requires_grad=True)
430
+ result = f(x_val)
431
+ assert torch.isclose(result, torch.tensor(0.0), atol=1e-5)
432
+
433
+ x_val = torch.tensor(math.pi / 2, requires_grad=True)
434
+ result = f(x_val)
435
+ assert torch.isclose(result, torch.tensor(-1.0), atol=1e-5)
436
+
437
+ expr = Derivative(x * y ** 2, x, y)
438
+ f = lambdify((x, y), expr, 'torch')
439
+ x_val = torch.tensor(2.0, requires_grad=True)
440
+ y_val = torch.tensor(3.0, requires_grad=True)
441
+ result = f(x_val, y_val)
442
+ assert torch.isclose(result, torch.tensor(6.0))
443
+
444
+
445
+ def test_torch_special_matrices():
446
+ if not torch:
447
+ skip("PyTorch not installed")
448
+
449
+ expr = Identity(3)
450
+ assert torch_code(expr) == "torch.eye(3)"
451
+
452
+ n = symbols("n")
453
+ expr = Identity(n)
454
+ assert torch_code(expr) == "torch.eye(n, n)"
455
+
456
+ expr = ZeroMatrix(2, 3)
457
+ assert torch_code(expr) == "torch.zeros((2, 3))"
458
+
459
+ m, n = symbols("m n")
460
+ expr = ZeroMatrix(m, n)
461
+ assert torch_code(expr) == "torch.zeros((m, n))"
462
+
463
+ expr = OneMatrix(2, 3)
464
+ assert torch_code(expr) == "torch.ones((2, 3))"
465
+
466
+ expr = OneMatrix(m, n)
467
+ assert torch_code(expr) == "torch.ones((m, n))"
468
+
469
+
470
+ def test_torch_special_matrices_lambdify():
471
+ if not torch:
472
+ skip("PyTorch not installed")
473
+
474
+ expr = Identity(3)
475
+ f = lambdify([], expr, 'torch')
476
+ result = f()
477
+ expected = torch.eye(3)
478
+ assert torch.allclose(result, expected)
479
+
480
+ expr = ZeroMatrix(2, 3)
481
+ f = lambdify([], expr, 'torch')
482
+ result = f()
483
+ expected = torch.zeros((2, 3))
484
+ assert torch.allclose(result, expected)
485
+
486
+ expr = OneMatrix(2, 3)
487
+ f = lambdify([], expr, 'torch')
488
+ result = f()
489
+ expected = torch.ones((2, 3))
490
+ assert torch.allclose(result, expected)
491
+
492
+
493
+ def test_torch_complex_operations():
494
+ if not torch:
495
+ skip("PyTorch not installed")
496
+
497
+ expr = conjugate(x)
498
+ assert torch_code(expr) == "torch.conj(x)"
499
+
500
+ # SymPy distributes conjugate over addition and applies specific rules for each term
501
+ expr = conjugate(sin(x) + I * cos(y))
502
+ assert torch_code(expr) == "torch.sin(torch.conj(x)) - 1j*torch.cos(torch.conj(y))"
503
+
504
+ expr = I
505
+ assert torch_code(expr) == "1j"
506
+
507
+ expr = 2 * I + x
508
+ assert torch_code(expr) == "x + 2*1j"
509
+
510
+ expr = exp(I * x)
511
+ assert torch_code(expr) == "torch.exp(1j*x)"
512
+
513
+
514
+ def test_torch_special_functions():
515
+ if not torch:
516
+ skip("PyTorch not installed")
517
+
518
+ expr = Heaviside(x)
519
+ assert torch_code(expr) == "torch.heaviside(x, 1/2)"
520
+
521
+ expr = Heaviside(x, 0)
522
+ assert torch_code(expr) == "torch.heaviside(x, 0)"
523
+
524
+ expr = gamma(x)
525
+ assert torch_code(expr) == "torch.special.gamma(x)"
526
+
527
+ expr = polygamma(0, x) # Use polygamma instead of digamma because sympy will default to that anyway
528
+ assert torch_code(expr) == "torch.special.digamma(x)"
529
+
530
+ expr = gamma(sin(x))
531
+ assert torch_code(expr) == "torch.special.gamma(torch.sin(x))"
outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_tree.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.printing.tree import tree
2
+ from sympy.testing.pytest import XFAIL
3
+
4
+
5
+ # Remove this flag after making _assumptions cache deterministic.
6
+ @XFAIL
7
+ def test_print_tree_MatAdd():
8
+ from sympy.matrices.expressions import MatrixSymbol
9
+ A = MatrixSymbol('A', 3, 3)
10
+ B = MatrixSymbol('B', 3, 3)
11
+
12
+ test_str = [
13
+ 'MatAdd: A + B\n',
14
+ 'algebraic: False\n',
15
+ 'commutative: False\n',
16
+ 'complex: False\n',
17
+ 'composite: False\n',
18
+ 'even: False\n',
19
+ 'extended_negative: False\n',
20
+ 'extended_nonnegative: False\n',
21
+ 'extended_nonpositive: False\n',
22
+ 'extended_nonzero: False\n',
23
+ 'extended_positive: False\n',
24
+ 'extended_real: False\n',
25
+ 'imaginary: False\n',
26
+ 'integer: False\n',
27
+ 'irrational: False\n',
28
+ 'negative: False\n',
29
+ 'noninteger: False\n',
30
+ 'nonnegative: False\n',
31
+ 'nonpositive: False\n',
32
+ 'nonzero: False\n',
33
+ 'odd: False\n',
34
+ 'positive: False\n',
35
+ 'prime: False\n',
36
+ 'rational: False\n',
37
+ 'real: False\n',
38
+ 'transcendental: False\n',
39
+ 'zero: False\n',
40
+ '+-MatrixSymbol: A\n',
41
+ '| algebraic: False\n',
42
+ '| commutative: False\n',
43
+ '| complex: False\n',
44
+ '| composite: False\n',
45
+ '| even: False\n',
46
+ '| extended_negative: False\n',
47
+ '| extended_nonnegative: False\n',
48
+ '| extended_nonpositive: False\n',
49
+ '| extended_nonzero: False\n',
50
+ '| extended_positive: False\n',
51
+ '| extended_real: False\n',
52
+ '| imaginary: False\n',
53
+ '| integer: False\n',
54
+ '| irrational: False\n',
55
+ '| negative: False\n',
56
+ '| noninteger: False\n',
57
+ '| nonnegative: False\n',
58
+ '| nonpositive: False\n',
59
+ '| nonzero: False\n',
60
+ '| odd: False\n',
61
+ '| positive: False\n',
62
+ '| prime: False\n',
63
+ '| rational: False\n',
64
+ '| real: False\n',
65
+ '| transcendental: False\n',
66
+ '| zero: False\n',
67
+ '| +-Symbol: A\n',
68
+ '| | commutative: True\n',
69
+ '| +-Integer: 3\n',
70
+ '| | algebraic: True\n',
71
+ '| | commutative: True\n',
72
+ '| | complex: True\n',
73
+ '| | extended_negative: False\n',
74
+ '| | extended_nonnegative: True\n',
75
+ '| | extended_real: True\n',
76
+ '| | finite: True\n',
77
+ '| | hermitian: True\n',
78
+ '| | imaginary: False\n',
79
+ '| | infinite: False\n',
80
+ '| | integer: True\n',
81
+ '| | irrational: False\n',
82
+ '| | negative: False\n',
83
+ '| | noninteger: False\n',
84
+ '| | nonnegative: True\n',
85
+ '| | rational: True\n',
86
+ '| | real: True\n',
87
+ '| | transcendental: False\n',
88
+ '| +-Integer: 3\n',
89
+ '| algebraic: True\n',
90
+ '| commutative: True\n',
91
+ '| complex: True\n',
92
+ '| extended_negative: False\n',
93
+ '| extended_nonnegative: True\n',
94
+ '| extended_real: True\n',
95
+ '| finite: True\n',
96
+ '| hermitian: True\n',
97
+ '| imaginary: False\n',
98
+ '| infinite: False\n',
99
+ '| integer: True\n',
100
+ '| irrational: False\n',
101
+ '| negative: False\n',
102
+ '| noninteger: False\n',
103
+ '| nonnegative: True\n',
104
+ '| rational: True\n',
105
+ '| real: True\n',
106
+ '| transcendental: False\n',
107
+ '+-MatrixSymbol: B\n',
108
+ ' algebraic: False\n',
109
+ ' commutative: False\n',
110
+ ' complex: False\n',
111
+ ' composite: False\n',
112
+ ' even: False\n',
113
+ ' extended_negative: False\n',
114
+ ' extended_nonnegative: False\n',
115
+ ' extended_nonpositive: False\n',
116
+ ' extended_nonzero: False\n',
117
+ ' extended_positive: False\n',
118
+ ' extended_real: False\n',
119
+ ' imaginary: False\n',
120
+ ' integer: False\n',
121
+ ' irrational: False\n',
122
+ ' negative: False\n',
123
+ ' noninteger: False\n',
124
+ ' nonnegative: False\n',
125
+ ' nonpositive: False\n',
126
+ ' nonzero: False\n',
127
+ ' odd: False\n',
128
+ ' positive: False\n',
129
+ ' prime: False\n',
130
+ ' rational: False\n',
131
+ ' real: False\n',
132
+ ' transcendental: False\n',
133
+ ' zero: False\n',
134
+ ' +-Symbol: B\n',
135
+ ' | commutative: True\n',
136
+ ' +-Integer: 3\n',
137
+ ' | algebraic: True\n',
138
+ ' | commutative: True\n',
139
+ ' | complex: True\n',
140
+ ' | extended_negative: False\n',
141
+ ' | extended_nonnegative: True\n',
142
+ ' | extended_real: True\n',
143
+ ' | finite: True\n',
144
+ ' | hermitian: True\n',
145
+ ' | imaginary: False\n',
146
+ ' | infinite: False\n',
147
+ ' | integer: True\n',
148
+ ' | irrational: False\n',
149
+ ' | negative: False\n',
150
+ ' | noninteger: False\n',
151
+ ' | nonnegative: True\n',
152
+ ' | rational: True\n',
153
+ ' | real: True\n',
154
+ ' | transcendental: False\n',
155
+ ' +-Integer: 3\n',
156
+ ' algebraic: True\n',
157
+ ' commutative: True\n',
158
+ ' complex: True\n',
159
+ ' extended_negative: False\n',
160
+ ' extended_nonnegative: True\n',
161
+ ' extended_real: True\n',
162
+ ' finite: True\n',
163
+ ' hermitian: True\n',
164
+ ' imaginary: False\n',
165
+ ' infinite: False\n',
166
+ ' integer: True\n',
167
+ ' irrational: False\n',
168
+ ' negative: False\n',
169
+ ' noninteger: False\n',
170
+ ' nonnegative: True\n',
171
+ ' rational: True\n',
172
+ ' real: True\n',
173
+ ' transcendental: False\n'
174
+ ]
175
+
176
+ assert tree(A + B) == "".join(test_str)
177
+
178
+
179
+ def test_print_tree_MatAdd_noassumptions():
180
+ from sympy.matrices.expressions import MatrixSymbol
181
+ A = MatrixSymbol('A', 3, 3)
182
+ B = MatrixSymbol('B', 3, 3)
183
+
184
+ test_str = \
185
+ """MatAdd: A + B
186
+ +-MatrixSymbol: A
187
+ | +-Str: A
188
+ | +-Integer: 3
189
+ | +-Integer: 3
190
+ +-MatrixSymbol: B
191
+ +-Str: B
192
+ +-Integer: 3
193
+ +-Integer: 3
194
+ """
195
+
196
+ assert tree(A + B, assumptions=False) == test_str
outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/theanocode.py ADDED
@@ -0,0 +1,571 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ .. deprecated:: 1.8
3
+
4
+ ``sympy.printing.theanocode`` is deprecated. Theano has been renamed to
5
+ Aesara. Use ``sympy.printing.aesaracode`` instead. See
6
+ :ref:`theanocode-deprecated` for more information.
7
+
8
+ """
9
+ from __future__ import annotations
10
+ import math
11
+ from typing import Any
12
+
13
+ from sympy.external import import_module
14
+ from sympy.printing.printer import Printer
15
+ from sympy.utilities.iterables import is_sequence
16
+ import sympy
17
+ from functools import partial
18
+
19
+ from sympy.utilities.decorator import doctest_depends_on
20
+ from sympy.utilities.exceptions import sympy_deprecation_warning
21
+
22
+
23
+ __doctest_requires__ = {('theano_function',): ['theano']}
24
+
25
+
26
+ theano = import_module('theano')
27
+
28
+
29
+ if theano:
30
+ ts = theano.scalar
31
+ tt = theano.tensor
32
+ from theano.sandbox import linalg as tlinalg
33
+
34
+ mapping = {
35
+ sympy.Add: tt.add,
36
+ sympy.Mul: tt.mul,
37
+ sympy.Abs: tt.abs_,
38
+ sympy.sign: tt.sgn,
39
+ sympy.ceiling: tt.ceil,
40
+ sympy.floor: tt.floor,
41
+ sympy.log: tt.log,
42
+ sympy.exp: tt.exp,
43
+ sympy.sqrt: tt.sqrt,
44
+ sympy.cos: tt.cos,
45
+ sympy.acos: tt.arccos,
46
+ sympy.sin: tt.sin,
47
+ sympy.asin: tt.arcsin,
48
+ sympy.tan: tt.tan,
49
+ sympy.atan: tt.arctan,
50
+ sympy.atan2: tt.arctan2,
51
+ sympy.cosh: tt.cosh,
52
+ sympy.acosh: tt.arccosh,
53
+ sympy.sinh: tt.sinh,
54
+ sympy.asinh: tt.arcsinh,
55
+ sympy.tanh: tt.tanh,
56
+ sympy.atanh: tt.arctanh,
57
+ sympy.re: tt.real,
58
+ sympy.im: tt.imag,
59
+ sympy.arg: tt.angle,
60
+ sympy.erf: tt.erf,
61
+ sympy.gamma: tt.gamma,
62
+ sympy.loggamma: tt.gammaln,
63
+ sympy.Pow: tt.pow,
64
+ sympy.Eq: tt.eq,
65
+ sympy.StrictGreaterThan: tt.gt,
66
+ sympy.StrictLessThan: tt.lt,
67
+ sympy.LessThan: tt.le,
68
+ sympy.GreaterThan: tt.ge,
69
+ sympy.And: tt.and_,
70
+ sympy.Or: tt.or_,
71
+ sympy.Max: tt.maximum, # SymPy accept >2 inputs, Theano only 2
72
+ sympy.Min: tt.minimum, # SymPy accept >2 inputs, Theano only 2
73
+ sympy.conjugate: tt.conj,
74
+ sympy.core.numbers.ImaginaryUnit: lambda:tt.complex(0,1),
75
+ # Matrices
76
+ sympy.MatAdd: tt.Elemwise(ts.add),
77
+ sympy.HadamardProduct: tt.Elemwise(ts.mul),
78
+ sympy.Trace: tlinalg.trace,
79
+ sympy.Determinant : tlinalg.det,
80
+ sympy.Inverse: tlinalg.matrix_inverse,
81
+ sympy.Transpose: tt.DimShuffle((False, False), [1, 0]),
82
+ }
83
+
84
+
85
+ class TheanoPrinter(Printer):
86
+ """ Code printer which creates Theano symbolic expression graphs.
87
+
88
+ Parameters
89
+ ==========
90
+
91
+ cache : dict
92
+ Cache dictionary to use. If None (default) will use
93
+ the global cache. To create a printer which does not depend on or alter
94
+ global state pass an empty dictionary. Note: the dictionary is not
95
+ copied on initialization of the printer and will be updated in-place,
96
+ so using the same dict object when creating multiple printers or making
97
+ multiple calls to :func:`.theano_code` or :func:`.theano_function` means
98
+ the cache is shared between all these applications.
99
+
100
+ Attributes
101
+ ==========
102
+
103
+ cache : dict
104
+ A cache of Theano variables which have been created for SymPy
105
+ symbol-like objects (e.g. :class:`sympy.core.symbol.Symbol` or
106
+ :class:`sympy.matrices.expressions.MatrixSymbol`). This is used to
107
+ ensure that all references to a given symbol in an expression (or
108
+ multiple expressions) are printed as the same Theano variable, which is
109
+ created only once. Symbols are differentiated only by name and type. The
110
+ format of the cache's contents should be considered opaque to the user.
111
+ """
112
+ printmethod = "_theano"
113
+
114
+ def __init__(self, *args, **kwargs):
115
+ self.cache = kwargs.pop('cache', {})
116
+ super().__init__(*args, **kwargs)
117
+
118
+ def _get_key(self, s, name=None, dtype=None, broadcastable=None):
119
+ """ Get the cache key for a SymPy object.
120
+
121
+ Parameters
122
+ ==========
123
+
124
+ s : sympy.core.basic.Basic
125
+ SymPy object to get key for.
126
+
127
+ name : str
128
+ Name of object, if it does not have a ``name`` attribute.
129
+ """
130
+
131
+ if name is None:
132
+ name = s.name
133
+
134
+ return (name, type(s), s.args, dtype, broadcastable)
135
+
136
+ def _get_or_create(self, s, name=None, dtype=None, broadcastable=None):
137
+ """
138
+ Get the Theano variable for a SymPy symbol from the cache, or create it
139
+ if it does not exist.
140
+ """
141
+
142
+ # Defaults
143
+ if name is None:
144
+ name = s.name
145
+ if dtype is None:
146
+ dtype = 'floatX'
147
+ if broadcastable is None:
148
+ broadcastable = ()
149
+
150
+ key = self._get_key(s, name, dtype=dtype, broadcastable=broadcastable)
151
+
152
+ if key in self.cache:
153
+ return self.cache[key]
154
+
155
+ value = tt.tensor(name=name, dtype=dtype, broadcastable=broadcastable)
156
+ self.cache[key] = value
157
+ return value
158
+
159
+ def _print_Symbol(self, s, **kwargs):
160
+ dtype = kwargs.get('dtypes', {}).get(s)
161
+ bc = kwargs.get('broadcastables', {}).get(s)
162
+ return self._get_or_create(s, dtype=dtype, broadcastable=bc)
163
+
164
+ def _print_AppliedUndef(self, s, **kwargs):
165
+ name = str(type(s)) + '_' + str(s.args[0])
166
+ dtype = kwargs.get('dtypes', {}).get(s)
167
+ bc = kwargs.get('broadcastables', {}).get(s)
168
+ return self._get_or_create(s, name=name, dtype=dtype, broadcastable=bc)
169
+
170
+ def _print_Basic(self, expr, **kwargs):
171
+ op = mapping[type(expr)]
172
+ children = [self._print(arg, **kwargs) for arg in expr.args]
173
+ return op(*children)
174
+
175
+ def _print_Number(self, n, **kwargs):
176
+ # Integers already taken care of below, interpret as float
177
+ return float(n.evalf())
178
+
179
+ def _print_MatrixSymbol(self, X, **kwargs):
180
+ dtype = kwargs.get('dtypes', {}).get(X)
181
+ return self._get_or_create(X, dtype=dtype, broadcastable=(None, None))
182
+
183
+ def _print_DenseMatrix(self, X, **kwargs):
184
+ if not hasattr(tt, 'stacklists'):
185
+ raise NotImplementedError(
186
+ "Matrix translation not yet supported in this version of Theano")
187
+
188
+ return tt.stacklists([
189
+ [self._print(arg, **kwargs) for arg in L]
190
+ for L in X.tolist()
191
+ ])
192
+
193
+ _print_ImmutableMatrix = _print_ImmutableDenseMatrix = _print_DenseMatrix
194
+
195
+ def _print_MatMul(self, expr, **kwargs):
196
+ children = [self._print(arg, **kwargs) for arg in expr.args]
197
+ result = children[0]
198
+ for child in children[1:]:
199
+ result = tt.dot(result, child)
200
+ return result
201
+
202
+ def _print_MatPow(self, expr, **kwargs):
203
+ children = [self._print(arg, **kwargs) for arg in expr.args]
204
+ result = 1
205
+ if isinstance(children[1], int) and children[1] > 0:
206
+ for i in range(children[1]):
207
+ result = tt.dot(result, children[0])
208
+ else:
209
+ raise NotImplementedError('''Only non-negative integer
210
+ powers of matrices can be handled by Theano at the moment''')
211
+ return result
212
+
213
+ def _print_MatrixSlice(self, expr, **kwargs):
214
+ parent = self._print(expr.parent, **kwargs)
215
+ rowslice = self._print(slice(*expr.rowslice), **kwargs)
216
+ colslice = self._print(slice(*expr.colslice), **kwargs)
217
+ return parent[rowslice, colslice]
218
+
219
+ def _print_BlockMatrix(self, expr, **kwargs):
220
+ nrows, ncols = expr.blocks.shape
221
+ blocks = [[self._print(expr.blocks[r, c], **kwargs)
222
+ for c in range(ncols)]
223
+ for r in range(nrows)]
224
+ return tt.join(0, *[tt.join(1, *row) for row in blocks])
225
+
226
+
227
+ def _print_slice(self, expr, **kwargs):
228
+ return slice(*[self._print(i, **kwargs)
229
+ if isinstance(i, sympy.Basic) else i
230
+ for i in (expr.start, expr.stop, expr.step)])
231
+
232
+ def _print_Pi(self, expr, **kwargs):
233
+ return math.pi
234
+
235
+ def _print_Exp1(self, expr, **kwargs):
236
+ return ts.exp(1)
237
+
238
+ def _print_Piecewise(self, expr, **kwargs):
239
+ import numpy as np
240
+ e, cond = expr.args[0].args # First condition and corresponding value
241
+
242
+ # Print conditional expression and value for first condition
243
+ p_cond = self._print(cond, **kwargs)
244
+ p_e = self._print(e, **kwargs)
245
+
246
+ # One condition only
247
+ if len(expr.args) == 1:
248
+ # Return value if condition else NaN
249
+ return tt.switch(p_cond, p_e, np.nan)
250
+
251
+ # Return value_1 if condition_1 else evaluate remaining conditions
252
+ p_remaining = self._print(sympy.Piecewise(*expr.args[1:]), **kwargs)
253
+ return tt.switch(p_cond, p_e, p_remaining)
254
+
255
+ def _print_Rational(self, expr, **kwargs):
256
+ return tt.true_div(self._print(expr.p, **kwargs),
257
+ self._print(expr.q, **kwargs))
258
+
259
+ def _print_Integer(self, expr, **kwargs):
260
+ return expr.p
261
+
262
+ def _print_factorial(self, expr, **kwargs):
263
+ return self._print(sympy.gamma(expr.args[0] + 1), **kwargs)
264
+
265
+ def _print_Derivative(self, deriv, **kwargs):
266
+ rv = self._print(deriv.expr, **kwargs)
267
+ for var in deriv.variables:
268
+ var = self._print(var, **kwargs)
269
+ rv = tt.Rop(rv, var, tt.ones_like(var))
270
+ return rv
271
+
272
+ def emptyPrinter(self, expr):
273
+ return expr
274
+
275
+ def doprint(self, expr, dtypes=None, broadcastables=None):
276
+ """ Convert a SymPy expression to a Theano graph variable.
277
+
278
+ The ``dtypes`` and ``broadcastables`` arguments are used to specify the
279
+ data type, dimension, and broadcasting behavior of the Theano variables
280
+ corresponding to the free symbols in ``expr``. Each is a mapping from
281
+ SymPy symbols to the value of the corresponding argument to
282
+ ``theano.tensor.Tensor``.
283
+
284
+ See the corresponding `documentation page`__ for more information on
285
+ broadcasting in Theano.
286
+
287
+ .. __: http://deeplearning.net/software/theano/tutorial/broadcasting.html
288
+
289
+ Parameters
290
+ ==========
291
+
292
+ expr : sympy.core.expr.Expr
293
+ SymPy expression to print.
294
+
295
+ dtypes : dict
296
+ Mapping from SymPy symbols to Theano datatypes to use when creating
297
+ new Theano variables for those symbols. Corresponds to the ``dtype``
298
+ argument to ``theano.tensor.Tensor``. Defaults to ``'floatX'``
299
+ for symbols not included in the mapping.
300
+
301
+ broadcastables : dict
302
+ Mapping from SymPy symbols to the value of the ``broadcastable``
303
+ argument to ``theano.tensor.Tensor`` to use when creating Theano
304
+ variables for those symbols. Defaults to the empty tuple for symbols
305
+ not included in the mapping (resulting in a scalar).
306
+
307
+ Returns
308
+ =======
309
+
310
+ theano.gof.graph.Variable
311
+ A variable corresponding to the expression's value in a Theano
312
+ symbolic expression graph.
313
+
314
+ """
315
+ if dtypes is None:
316
+ dtypes = {}
317
+ if broadcastables is None:
318
+ broadcastables = {}
319
+
320
+ return self._print(expr, dtypes=dtypes, broadcastables=broadcastables)
321
+
322
+
323
+ global_cache: dict[Any, Any] = {}
324
+
325
+
326
+ def theano_code(expr, cache=None, **kwargs):
327
+ """
328
+ Convert a SymPy expression into a Theano graph variable.
329
+
330
+ .. deprecated:: 1.8
331
+
332
+ ``sympy.printing.theanocode`` is deprecated. Theano has been renamed to
333
+ Aesara. Use ``sympy.printing.aesaracode`` instead. See
334
+ :ref:`theanocode-deprecated` for more information.
335
+
336
+ Parameters
337
+ ==========
338
+
339
+ expr : sympy.core.expr.Expr
340
+ SymPy expression object to convert.
341
+
342
+ cache : dict
343
+ Cached Theano variables (see :class:`TheanoPrinter.cache
344
+ <TheanoPrinter>`). Defaults to the module-level global cache.
345
+
346
+ dtypes : dict
347
+ Passed to :meth:`.TheanoPrinter.doprint`.
348
+
349
+ broadcastables : dict
350
+ Passed to :meth:`.TheanoPrinter.doprint`.
351
+
352
+ Returns
353
+ =======
354
+
355
+ theano.gof.graph.Variable
356
+ A variable corresponding to the expression's value in a Theano symbolic
357
+ expression graph.
358
+
359
+ """
360
+ sympy_deprecation_warning(
361
+ """
362
+ sympy.printing.theanocode is deprecated. Theano has been renamed to
363
+ Aesara. Use sympy.printing.aesaracode instead.""",
364
+ deprecated_since_version="1.8",
365
+ active_deprecations_target='theanocode-deprecated')
366
+
367
+ if not theano:
368
+ raise ImportError("theano is required for theano_code")
369
+
370
+ if cache is None:
371
+ cache = global_cache
372
+
373
+ return TheanoPrinter(cache=cache, settings={}).doprint(expr, **kwargs)
374
+
375
+
376
+ def dim_handling(inputs, dim=None, dims=None, broadcastables=None):
377
+ r"""
378
+ Get value of ``broadcastables`` argument to :func:`.theano_code` from
379
+ keyword arguments to :func:`.theano_function`.
380
+
381
+ Included for backwards compatibility.
382
+
383
+ Parameters
384
+ ==========
385
+
386
+ inputs
387
+ Sequence of input symbols.
388
+
389
+ dim : int
390
+ Common number of dimensions for all inputs. Overrides other arguments
391
+ if given.
392
+
393
+ dims : dict
394
+ Mapping from input symbols to number of dimensions. Overrides
395
+ ``broadcastables`` argument if given.
396
+
397
+ broadcastables : dict
398
+ Explicit value of ``broadcastables`` argument to
399
+ :meth:`.TheanoPrinter.doprint`. If not None function will return this value unchanged.
400
+
401
+ Returns
402
+ =======
403
+ dict
404
+ Dictionary mapping elements of ``inputs`` to their "broadcastable"
405
+ values (tuple of ``bool``\ s).
406
+ """
407
+ if dim is not None:
408
+ return dict.fromkeys(inputs, (False,) * dim)
409
+
410
+ if dims is not None:
411
+ maxdim = max(dims.values())
412
+ return {
413
+ s: (False,) * d + (True,) * (maxdim - d)
414
+ for s, d in dims.items()
415
+ }
416
+
417
+ if broadcastables is not None:
418
+ return broadcastables
419
+
420
+ return {}
421
+
422
+
423
+ @doctest_depends_on(modules=('theano',))
424
+ def theano_function(inputs, outputs, scalar=False, *,
425
+ dim=None, dims=None, broadcastables=None, **kwargs):
426
+ """
427
+ Create a Theano function from SymPy expressions.
428
+
429
+ .. deprecated:: 1.8
430
+
431
+ ``sympy.printing.theanocode`` is deprecated. Theano has been renamed to
432
+ Aesara. Use ``sympy.printing.aesaracode`` instead. See
433
+ :ref:`theanocode-deprecated` for more information.
434
+
435
+ The inputs and outputs are converted to Theano variables using
436
+ :func:`.theano_code` and then passed to ``theano.function``.
437
+
438
+ Parameters
439
+ ==========
440
+
441
+ inputs
442
+ Sequence of symbols which constitute the inputs of the function.
443
+
444
+ outputs
445
+ Sequence of expressions which constitute the outputs(s) of the
446
+ function. The free symbols of each expression must be a subset of
447
+ ``inputs``.
448
+
449
+ scalar : bool
450
+ Convert 0-dimensional arrays in output to scalars. This will return a
451
+ Python wrapper function around the Theano function object.
452
+
453
+ cache : dict
454
+ Cached Theano variables (see :class:`TheanoPrinter.cache
455
+ <TheanoPrinter>`). Defaults to the module-level global cache.
456
+
457
+ dtypes : dict
458
+ Passed to :meth:`.TheanoPrinter.doprint`.
459
+
460
+ broadcastables : dict
461
+ Passed to :meth:`.TheanoPrinter.doprint`.
462
+
463
+ dims : dict
464
+ Alternative to ``broadcastables`` argument. Mapping from elements of
465
+ ``inputs`` to integers indicating the dimension of their associated
466
+ arrays/tensors. Overrides ``broadcastables`` argument if given.
467
+
468
+ dim : int
469
+ Another alternative to the ``broadcastables`` argument. Common number of
470
+ dimensions to use for all arrays/tensors.
471
+ ``theano_function([x, y], [...], dim=2)`` is equivalent to using
472
+ ``broadcastables={x: (False, False), y: (False, False)}``.
473
+
474
+ Returns
475
+ =======
476
+ callable
477
+ A callable object which takes values of ``inputs`` as positional
478
+ arguments and returns an output array for each of the expressions
479
+ in ``outputs``. If ``outputs`` is a single expression the function will
480
+ return a Numpy array, if it is a list of multiple expressions the
481
+ function will return a list of arrays. See description of the ``squeeze``
482
+ argument above for the behavior when a single output is passed in a list.
483
+ The returned object will either be an instance of
484
+ ``theano.compile.function_module.Function`` or a Python wrapper
485
+ function around one. In both cases, the returned value will have a
486
+ ``theano_function`` attribute which points to the return value of
487
+ ``theano.function``.
488
+
489
+ Examples
490
+ ========
491
+
492
+ >>> from sympy.abc import x, y, z
493
+ >>> from sympy.printing.theanocode import theano_function
494
+
495
+ A simple function with one input and one output:
496
+
497
+ >>> f1 = theano_function([x], [x**2 - 1], scalar=True)
498
+ >>> f1(3)
499
+ 8.0
500
+
501
+ A function with multiple inputs and one output:
502
+
503
+ >>> f2 = theano_function([x, y, z], [(x**z + y**z)**(1/z)], scalar=True)
504
+ >>> f2(3, 4, 2)
505
+ 5.0
506
+
507
+ A function with multiple inputs and multiple outputs:
508
+
509
+ >>> f3 = theano_function([x, y], [x**2 + y**2, x**2 - y**2], scalar=True)
510
+ >>> f3(2, 3)
511
+ [13.0, -5.0]
512
+
513
+ See also
514
+ ========
515
+
516
+ dim_handling
517
+
518
+ """
519
+ sympy_deprecation_warning(
520
+ """
521
+ sympy.printing.theanocode is deprecated. Theano has been renamed to Aesara. Use sympy.printing.aesaracode instead""",
522
+ deprecated_since_version="1.8",
523
+ active_deprecations_target='theanocode-deprecated')
524
+
525
+ if not theano:
526
+ raise ImportError("theano is required for theano_function")
527
+
528
+ # Pop off non-theano keyword args
529
+ cache = kwargs.pop('cache', {})
530
+ dtypes = kwargs.pop('dtypes', {})
531
+
532
+ broadcastables = dim_handling(
533
+ inputs, dim=dim, dims=dims, broadcastables=broadcastables,
534
+ )
535
+
536
+ # Print inputs/outputs
537
+ code = partial(theano_code, cache=cache, dtypes=dtypes,
538
+ broadcastables=broadcastables)
539
+ tinputs = list(map(code, inputs))
540
+ toutputs = list(map(code, outputs))
541
+
542
+ #fix constant expressions as variables
543
+ toutputs = [output if isinstance(output, theano.Variable) else tt.as_tensor_variable(output) for output in toutputs]
544
+
545
+ if len(toutputs) == 1:
546
+ toutputs = toutputs[0]
547
+
548
+ # Compile theano func
549
+ func = theano.function(tinputs, toutputs, **kwargs)
550
+
551
+ is_0d = [len(o.variable.broadcastable) == 0 for o in func.outputs]
552
+
553
+ # No wrapper required
554
+ if not scalar or not any(is_0d):
555
+ func.theano_function = func
556
+ return func
557
+
558
+ # Create wrapper to convert 0-dimensional outputs to scalars
559
+ def wrapper(*args):
560
+ out = func(*args)
561
+ # out can be array(1.0) or [array(1.0), array(2.0)]
562
+
563
+ if is_sequence(out):
564
+ return [o[()] if is_0d[i] else o for i, o in enumerate(out)]
565
+ else:
566
+ return out[()]
567
+
568
+ wrapper.__wrapped__ = func
569
+ wrapper.__doc__ = func.__doc__
570
+ wrapper.theano_function = func
571
+ return wrapper
outputs/audit_venv/lib/python3.11/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))
outputs/audit_venv/lib/python3.11/site-packages/sympy/release.py ADDED
@@ -0,0 +1 @@
 
 
1
+ __version__ = "1.14.0"
outputs/audit_venv/lib/python3.11/site-packages/sympy/sandbox/__init__.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Sandbox module of SymPy.
3
+
4
+ This module contains experimental code, use at your own risk!
5
+
6
+ There is no warranty that this code will still be located here in future
7
+ versions of SymPy.
8
+ """
outputs/audit_venv/lib/python3.11/site-packages/sympy/sandbox/indexed_integrals.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.tensor import Indexed
2
+ from sympy.core.containers import Tuple
3
+ from sympy.core.symbol import Dummy
4
+ from sympy.core.sympify import sympify
5
+ from sympy.integrals.integrals import Integral
6
+
7
+
8
+ class IndexedIntegral(Integral):
9
+ """
10
+ Experimental class to test integration by indexed variables.
11
+
12
+ Usage is analogue to ``Integral``, it simply adds awareness of
13
+ integration over indices.
14
+
15
+ Contraction of non-identical index symbols referring to the same
16
+ ``IndexedBase`` is not yet supported.
17
+
18
+ Examples
19
+ ========
20
+
21
+ >>> from sympy.sandbox.indexed_integrals import IndexedIntegral
22
+ >>> from sympy import IndexedBase, symbols
23
+ >>> A = IndexedBase('A')
24
+ >>> i, j = symbols('i j', integer=True)
25
+ >>> ii = IndexedIntegral(A[i], A[i])
26
+ >>> ii
27
+ Integral(_A[i], _A[i])
28
+ >>> ii.doit()
29
+ A[i]**2/2
30
+
31
+ If the indices are different, indexed objects are considered to be
32
+ different variables:
33
+
34
+ >>> i2 = IndexedIntegral(A[j], A[i])
35
+ >>> i2
36
+ Integral(A[j], _A[i])
37
+ >>> i2.doit()
38
+ A[i]*A[j]
39
+ """
40
+
41
+ def __new__(cls, function, *limits, **assumptions):
42
+ repl, limits = IndexedIntegral._indexed_process_limits(limits)
43
+ function = sympify(function)
44
+ function = function.xreplace(repl)
45
+ obj = Integral.__new__(cls, function, *limits, **assumptions)
46
+ obj._indexed_repl = repl
47
+ obj._indexed_reverse_repl = {val: key for key, val in repl.items()}
48
+ return obj
49
+
50
+ def doit(self):
51
+ res = super().doit()
52
+ return res.xreplace(self._indexed_reverse_repl)
53
+
54
+ @staticmethod
55
+ def _indexed_process_limits(limits):
56
+ repl = {}
57
+ newlimits = []
58
+ for i in limits:
59
+ if isinstance(i, (tuple, list, Tuple)):
60
+ v = i[0]
61
+ vrest = i[1:]
62
+ else:
63
+ v = i
64
+ vrest = ()
65
+ if isinstance(v, Indexed):
66
+ if v not in repl:
67
+ r = Dummy(str(v))
68
+ repl[v] = r
69
+ newlimits.append((r,)+vrest)
70
+ else:
71
+ newlimits.append(i)
72
+ return repl, newlimits
outputs/audit_venv/lib/python3.11/site-packages/sympy/sandbox/tests/__init__.py ADDED
File without changes
outputs/audit_venv/lib/python3.11/site-packages/sympy/sandbox/tests/test_indexed_integrals.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.sandbox.indexed_integrals import IndexedIntegral
2
+ from sympy.core.symbol import symbols
3
+ from sympy.functions.elementary.trigonometric import (cos, sin)
4
+ from sympy.tensor.indexed import (Idx, IndexedBase)
5
+
6
+
7
+ def test_indexed_integrals():
8
+ A = IndexedBase('A')
9
+ i, j = symbols('i j', integer=True)
10
+ a1, a2 = symbols('a1:3', cls=Idx)
11
+ assert isinstance(a1, Idx)
12
+
13
+ assert IndexedIntegral(1, A[i]).doit() == A[i]
14
+ assert IndexedIntegral(A[i], A[i]).doit() == A[i] ** 2 / 2
15
+ assert IndexedIntegral(A[j], A[i]).doit() == A[i] * A[j]
16
+ assert IndexedIntegral(A[i] * A[j], A[i]).doit() == A[i] ** 2 * A[j] / 2
17
+ assert IndexedIntegral(sin(A[i]), A[i]).doit() == -cos(A[i])
18
+ assert IndexedIntegral(sin(A[j]), A[i]).doit() == sin(A[j]) * A[i]
19
+
20
+ assert IndexedIntegral(1, A[a1]).doit() == A[a1]
21
+ assert IndexedIntegral(A[a1], A[a1]).doit() == A[a1] ** 2 / 2
22
+ assert IndexedIntegral(A[a2], A[a1]).doit() == A[a1] * A[a2]
23
+ assert IndexedIntegral(A[a1] * A[a2], A[a1]).doit() == A[a1] ** 2 * A[a2] / 2
24
+ assert IndexedIntegral(sin(A[a1]), A[a1]).doit() == -cos(A[a1])
25
+ assert IndexedIntegral(sin(A[a2]), A[a1]).doit() == sin(A[a2]) * A[a1]
outputs/audit_venv/lib/python3.11/site-packages/sympy/series/__init__.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """A module that handles series: find a limit, order the series etc.
2
+ """
3
+ from .order import Order
4
+ from .limits import limit, Limit
5
+ from .gruntz import gruntz
6
+ from .series import series
7
+ from .approximants import approximants
8
+ from .residues import residue
9
+ from .sequences import SeqPer, SeqFormula, sequence, SeqAdd, SeqMul
10
+ from .fourier import fourier_series
11
+ from .formal import fps
12
+ from .limitseq import difference_delta, limit_seq
13
+
14
+ from sympy.core.singleton import S
15
+ EmptySequence = S.EmptySequence
16
+
17
+ O = Order
18
+
19
+ __all__ = ['Order', 'O', 'limit', 'Limit', 'gruntz', 'series', 'approximants',
20
+ 'residue', 'EmptySequence', 'SeqPer', 'SeqFormula', 'sequence',
21
+ 'SeqAdd', 'SeqMul', 'fourier_series', 'fps', 'difference_delta',
22
+ 'limit_seq'
23
+ ]
outputs/audit_venv/lib/python3.11/site-packages/sympy/series/acceleration.py ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Convergence acceleration / extrapolation methods for series and
3
+ sequences.
4
+
5
+ References:
6
+ Carl M. Bender & Steven A. Orszag, "Advanced Mathematical Methods for
7
+ Scientists and Engineers: Asymptotic Methods and Perturbation Theory",
8
+ Springer 1999. (Shanks transformation: pp. 368-375, Richardson
9
+ extrapolation: pp. 375-377.)
10
+ """
11
+
12
+ from sympy.core.numbers import Integer
13
+ from sympy.core.singleton import S
14
+ from sympy.functions.combinatorial.factorials import factorial
15
+
16
+
17
+ def richardson(A, k, n, N):
18
+ """
19
+ Calculate an approximation for lim k->oo A(k) using Richardson
20
+ extrapolation with the terms A(n), A(n+1), ..., A(n+N+1).
21
+ Choosing N ~= 2*n often gives good results.
22
+
23
+ Examples
24
+ ========
25
+
26
+ A simple example is to calculate exp(1) using the limit definition.
27
+ This limit converges slowly; n = 100 only produces two accurate
28
+ digits:
29
+
30
+ >>> from sympy.abc import n
31
+ >>> e = (1 + 1/n)**n
32
+ >>> print(round(e.subs(n, 100).evalf(), 10))
33
+ 2.7048138294
34
+
35
+ Richardson extrapolation with 11 appropriately chosen terms gives
36
+ a value that is accurate to the indicated precision:
37
+
38
+ >>> from sympy import E
39
+ >>> from sympy.series.acceleration import richardson
40
+ >>> print(round(richardson(e, n, 10, 20).evalf(), 10))
41
+ 2.7182818285
42
+ >>> print(round(E.evalf(), 10))
43
+ 2.7182818285
44
+
45
+ Another useful application is to speed up convergence of series.
46
+ Computing 100 terms of the zeta(2) series 1/k**2 yields only
47
+ two accurate digits:
48
+
49
+ >>> from sympy.abc import k, n
50
+ >>> from sympy import Sum
51
+ >>> A = Sum(k**-2, (k, 1, n))
52
+ >>> print(round(A.subs(n, 100).evalf(), 10))
53
+ 1.6349839002
54
+
55
+ Richardson extrapolation performs much better:
56
+
57
+ >>> from sympy import pi
58
+ >>> print(round(richardson(A, n, 10, 20).evalf(), 10))
59
+ 1.6449340668
60
+ >>> print(round(((pi**2)/6).evalf(), 10)) # Exact value
61
+ 1.6449340668
62
+
63
+ """
64
+ s = S.Zero
65
+ for j in range(0, N + 1):
66
+ s += (A.subs(k, Integer(n + j)).doit() * (n + j)**N *
67
+ S.NegativeOne**(j + N) / (factorial(j) * factorial(N - j)))
68
+ return s
69
+
70
+
71
+ def shanks(A, k, n, m=1):
72
+ """
73
+ Calculate an approximation for lim k->oo A(k) using the n-term Shanks
74
+ transformation S(A)(n). With m > 1, calculate the m-fold recursive
75
+ Shanks transformation S(S(...S(A)...))(n).
76
+
77
+ The Shanks transformation is useful for summing Taylor series that
78
+ converge slowly near a pole or singularity, e.g. for log(2):
79
+
80
+ >>> from sympy.abc import k, n
81
+ >>> from sympy import Sum, Integer
82
+ >>> from sympy.series.acceleration import shanks
83
+ >>> A = Sum(Integer(-1)**(k+1) / k, (k, 1, n))
84
+ >>> print(round(A.subs(n, 100).doit().evalf(), 10))
85
+ 0.6881721793
86
+ >>> print(round(shanks(A, n, 25).evalf(), 10))
87
+ 0.6931396564
88
+ >>> print(round(shanks(A, n, 25, 5).evalf(), 10))
89
+ 0.6931471806
90
+
91
+ The correct value is 0.6931471805599453094172321215.
92
+ """
93
+ table = [A.subs(k, Integer(j)).doit() for j in range(n + m + 2)]
94
+ table2 = table.copy()
95
+
96
+ for i in range(1, m + 1):
97
+ for j in range(i, n + m + 1):
98
+ x, y, z = table[j - 1], table[j], table[j + 1]
99
+ table2[j] = (z*x - y**2) / (z + x - 2*y)
100
+ table = table2.copy()
101
+ return table[n]
outputs/audit_venv/lib/python3.11/site-packages/sympy/series/approximants.py ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.singleton import S
2
+ from sympy.core.symbol import Symbol
3
+ from sympy.polys.polytools import lcm
4
+ from sympy.utilities import public
5
+
6
+ @public
7
+ def approximants(l, X=Symbol('x'), simplify=False):
8
+ """
9
+ Return a generator for consecutive Pade approximants for a series.
10
+ It can also be used for computing the rational generating function of a
11
+ series when possible, since the last approximant returned by the generator
12
+ will be the generating function (if any).
13
+
14
+ Explanation
15
+ ===========
16
+
17
+ The input list can contain more complex expressions than integer or rational
18
+ numbers; symbols may also be involved in the computation. An example below
19
+ show how to compute the generating function of the whole Pascal triangle.
20
+
21
+ The generator can be asked to apply the sympy.simplify function on each
22
+ generated term, which will make the computation slower; however it may be
23
+ useful when symbols are involved in the expressions.
24
+
25
+ Examples
26
+ ========
27
+
28
+ >>> from sympy.series import approximants
29
+ >>> from sympy import lucas, fibonacci, symbols, binomial
30
+ >>> g = [lucas(k) for k in range(16)]
31
+ >>> [e for e in approximants(g)]
32
+ [2, -4/(x - 2), (5*x - 2)/(3*x - 1), (x - 2)/(x**2 + x - 1)]
33
+
34
+ >>> h = [fibonacci(k) for k in range(16)]
35
+ >>> [e for e in approximants(h)]
36
+ [x, -x/(x - 1), (x**2 - x)/(2*x - 1), -x/(x**2 + x - 1)]
37
+
38
+ >>> x, t = symbols("x,t")
39
+ >>> p=[sum(binomial(k,i)*x**i for i in range(k+1)) for k in range(16)]
40
+ >>> y = approximants(p, t)
41
+ >>> for k in range(3): print(next(y))
42
+ 1
43
+ (x + 1)/((-x - 1)*(t*(x + 1) + (x + 1)/(-x - 1)))
44
+ nan
45
+
46
+ >>> y = approximants(p, t, simplify=True)
47
+ >>> for k in range(3): print(next(y))
48
+ 1
49
+ -1/(t*(x + 1) - 1)
50
+ nan
51
+
52
+ See Also
53
+ ========
54
+
55
+ sympy.concrete.guess.guess_generating_function_rational
56
+ mpmath.pade
57
+ """
58
+ from sympy.simplify import simplify as simp
59
+ from sympy.simplify.radsimp import denom
60
+ p1, q1 = [S.One], [S.Zero]
61
+ p2, q2 = [S.Zero], [S.One]
62
+ while len(l):
63
+ b = 0
64
+ while l[b]==0:
65
+ b += 1
66
+ if b == len(l):
67
+ return
68
+ m = [S.One/l[b]]
69
+ for k in range(b+1, len(l)):
70
+ s = 0
71
+ for j in range(b, k):
72
+ s -= l[j+1] * m[b-j-1]
73
+ m.append(s/l[b])
74
+ l = m
75
+ a, l[0] = l[0], 0
76
+ p = [0] * max(len(p2), b+len(p1))
77
+ q = [0] * max(len(q2), b+len(q1))
78
+ for k in range(len(p2)):
79
+ p[k] = a*p2[k]
80
+ for k in range(b, b+len(p1)):
81
+ p[k] += p1[k-b]
82
+ for k in range(len(q2)):
83
+ q[k] = a*q2[k]
84
+ for k in range(b, b+len(q1)):
85
+ q[k] += q1[k-b]
86
+ while p[-1]==0: p.pop()
87
+ while q[-1]==0: q.pop()
88
+ p1, p2 = p2, p
89
+ q1, q2 = q2, q
90
+
91
+ # yield result
92
+ c = 1
93
+ for x in p:
94
+ c = lcm(c, denom(x))
95
+ for x in q:
96
+ c = lcm(c, denom(x))
97
+ out = ( sum(c*e*X**k for k, e in enumerate(p))
98
+ / sum(c*e*X**k for k, e in enumerate(q)) )
99
+ if simplify:
100
+ yield(simp(out))
101
+ else:
102
+ yield out
103
+ return
outputs/audit_venv/lib/python3.11/site-packages/sympy/series/aseries.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.sympify import sympify
2
+
3
+
4
+ def aseries(expr, x=None, n=6, bound=0, hir=False):
5
+ """
6
+ See the docstring of Expr.aseries() for complete details of this wrapper.
7
+
8
+ """
9
+ expr = sympify(expr)
10
+ return expr.aseries(x, n, bound, hir)
outputs/audit_venv/lib/python3.11/site-packages/sympy/series/benchmarks/__init__.py ADDED
File without changes
outputs/audit_venv/lib/python3.11/site-packages/sympy/series/benchmarks/bench_limit.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.numbers import oo
2
+ from sympy.core.symbol import Symbol
3
+ from sympy.series.limits import limit
4
+
5
+ x = Symbol('x')
6
+
7
+
8
+ def timeit_limit_1x():
9
+ limit(1/x, x, oo)
outputs/audit_venv/lib/python3.11/site-packages/sympy/series/benchmarks/bench_order.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.add import Add
2
+ from sympy.core.symbol import Symbol
3
+ from sympy.series.order import O
4
+
5
+ x = Symbol('x')
6
+ l = [x**i for i in range(1000)]
7
+ l.append(O(x**1001))
8
+
9
+ def timeit_order_1x():
10
+ Add(*l)
outputs/audit_venv/lib/python3.11/site-packages/sympy/series/formal.py ADDED
@@ -0,0 +1,1863 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Formal Power Series"""
2
+
3
+ from collections import defaultdict
4
+
5
+ from sympy.core.numbers import (nan, oo, zoo)
6
+ from sympy.core.add import Add
7
+ from sympy.core.expr import Expr
8
+ from sympy.core.function import Derivative, Function, expand
9
+ from sympy.core.mul import Mul
10
+ from sympy.core.numbers import Rational
11
+ from sympy.core.relational import Eq
12
+ from sympy.sets.sets import Interval
13
+ from sympy.core.singleton import S
14
+ from sympy.core.symbol import Wild, Dummy, symbols, Symbol
15
+ from sympy.core.sympify import sympify
16
+ from sympy.discrete.convolutions import convolution
17
+ from sympy.functions.combinatorial.factorials import binomial, factorial, rf
18
+ from sympy.functions.combinatorial.numbers import bell
19
+ from sympy.functions.elementary.integers import floor, frac, ceiling
20
+ from sympy.functions.elementary.miscellaneous import Min, Max
21
+ from sympy.functions.elementary.piecewise import Piecewise
22
+ from sympy.series.limits import Limit
23
+ from sympy.series.order import Order
24
+ from sympy.series.sequences import sequence
25
+ from sympy.series.series_class import SeriesBase
26
+ from sympy.utilities.iterables import iterable
27
+
28
+
29
+
30
+ def rational_algorithm(f, x, k, order=4, full=False):
31
+ """
32
+ Rational algorithm for computing
33
+ formula of coefficients of Formal Power Series
34
+ of a function.
35
+
36
+ Explanation
37
+ ===========
38
+
39
+ Applicable when f(x) or some derivative of f(x)
40
+ is a rational function in x.
41
+
42
+ :func:`rational_algorithm` uses :func:`~.apart` function for partial fraction
43
+ decomposition. :func:`~.apart` by default uses 'undetermined coefficients
44
+ method'. By setting ``full=True``, 'Bronstein's algorithm' can be used
45
+ instead.
46
+
47
+ Looks for derivative of a function up to 4'th order (by default).
48
+ This can be overridden using order option.
49
+
50
+ Parameters
51
+ ==========
52
+
53
+ x : Symbol
54
+ order : int, optional
55
+ Order of the derivative of ``f``, Default is 4.
56
+ full : bool
57
+
58
+ Returns
59
+ =======
60
+
61
+ formula : Expr
62
+ ind : Expr
63
+ Independent terms.
64
+ order : int
65
+ full : bool
66
+
67
+ Examples
68
+ ========
69
+
70
+ >>> from sympy import log, atan
71
+ >>> from sympy.series.formal import rational_algorithm as ra
72
+ >>> from sympy.abc import x, k
73
+
74
+ >>> ra(1 / (1 - x), x, k)
75
+ (1, 0, 0)
76
+ >>> ra(log(1 + x), x, k)
77
+ (-1/((-1)**k*k), 0, 1)
78
+
79
+ >>> ra(atan(x), x, k, full=True)
80
+ ((-I/(2*(-I)**k) + I/(2*I**k))/k, 0, 1)
81
+
82
+ Notes
83
+ =====
84
+
85
+ By setting ``full=True``, range of admissible functions to be solved using
86
+ ``rational_algorithm`` can be increased. This option should be used
87
+ carefully as it can significantly slow down the computation as ``doit`` is
88
+ performed on the :class:`~.RootSum` object returned by the :func:`~.apart`
89
+ function. Use ``full=False`` whenever possible.
90
+
91
+ See Also
92
+ ========
93
+
94
+ sympy.polys.partfrac.apart
95
+
96
+ References
97
+ ==========
98
+
99
+ .. [1] Formal Power Series - Dominik Gruntz, Wolfram Koepf
100
+ .. [2] Power Series in Computer Algebra - Wolfram Koepf
101
+
102
+ """
103
+ from sympy.polys import RootSum, apart
104
+ from sympy.integrals import integrate
105
+
106
+ diff = f
107
+ ds = [] # list of diff
108
+
109
+ for i in range(order + 1):
110
+ if i:
111
+ diff = diff.diff(x)
112
+
113
+ if diff.is_rational_function(x):
114
+ coeff, sep = S.Zero, S.Zero
115
+
116
+ terms = apart(diff, x, full=full)
117
+ if terms.has(RootSum):
118
+ terms = terms.doit()
119
+
120
+ for t in Add.make_args(terms):
121
+ num, den = t.as_numer_denom()
122
+ if not den.has(x):
123
+ sep += t
124
+ else:
125
+ if isinstance(den, Mul):
126
+ # m*(n*x - a)**j -> (n*x - a)**j
127
+ ind = den.as_independent(x)
128
+ den = ind[1]
129
+ num /= ind[0]
130
+
131
+ # (n*x - a)**j -> (x - b)
132
+ den, j = den.as_base_exp()
133
+ a, xterm = den.as_coeff_add(x)
134
+
135
+ # term -> m/x**n
136
+ if not a:
137
+ sep += t
138
+ continue
139
+
140
+ xc = xterm[0].coeff(x)
141
+ a /= -xc
142
+ num /= xc**j
143
+
144
+ ak = ((-1)**j * num *
145
+ binomial(j + k - 1, k).rewrite(factorial) /
146
+ a**(j + k))
147
+ coeff += ak
148
+
149
+ # Hacky, better way?
150
+ if coeff.is_zero:
151
+ return None
152
+ if (coeff.has(x) or coeff.has(zoo) or coeff.has(oo) or
153
+ coeff.has(nan)):
154
+ return None
155
+
156
+ for j in range(i):
157
+ coeff = (coeff / (k + j + 1))
158
+ sep = integrate(sep, x)
159
+ sep += (ds.pop() - sep).limit(x, 0) # constant of integration
160
+ return (coeff.subs(k, k - i), sep, i)
161
+
162
+ else:
163
+ ds.append(diff)
164
+
165
+ return None
166
+
167
+
168
+ def rational_independent(terms, x):
169
+ """
170
+ Returns a list of all the rationally independent terms.
171
+
172
+ Examples
173
+ ========
174
+
175
+ >>> from sympy import sin, cos
176
+ >>> from sympy.series.formal import rational_independent
177
+ >>> from sympy.abc import x
178
+
179
+ >>> rational_independent([cos(x), sin(x)], x)
180
+ [cos(x), sin(x)]
181
+ >>> rational_independent([x**2, sin(x), x*sin(x), x**3], x)
182
+ [x**3 + x**2, x*sin(x) + sin(x)]
183
+ """
184
+ if not terms:
185
+ return []
186
+
187
+ ind = terms[0:1]
188
+
189
+ for t in terms[1:]:
190
+ n = t.as_independent(x)[1]
191
+ for i, term in enumerate(ind):
192
+ d = term.as_independent(x)[1]
193
+ q = (n / d).cancel()
194
+ if q.is_rational_function(x):
195
+ ind[i] += t
196
+ break
197
+ else:
198
+ ind.append(t)
199
+ return ind
200
+
201
+
202
+ def simpleDE(f, x, g, order=4):
203
+ r"""
204
+ Generates simple DE.
205
+
206
+ Explanation
207
+ ===========
208
+
209
+ DE is of the form
210
+
211
+ .. math::
212
+ f^k(x) + \sum\limits_{j=0}^{k-1} A_j f^j(x) = 0
213
+
214
+ where :math:`A_j` should be rational function in x.
215
+
216
+ Generates DE's upto order 4 (default). DE's can also have free parameters.
217
+
218
+ By increasing order, higher order DE's can be found.
219
+
220
+ Yields a tuple of (DE, order).
221
+ """
222
+ from sympy.solvers.solveset import linsolve
223
+
224
+ a = symbols('a:%d' % (order))
225
+
226
+ def _makeDE(k):
227
+ eq = f.diff(x, k) + Add(*[a[i]*f.diff(x, i) for i in range(0, k)])
228
+ DE = g(x).diff(x, k) + Add(*[a[i]*g(x).diff(x, i) for i in range(0, k)])
229
+ return eq, DE
230
+
231
+ found = False
232
+ for k in range(1, order + 1):
233
+ eq, DE = _makeDE(k)
234
+ eq = eq.expand()
235
+ terms = eq.as_ordered_terms()
236
+ ind = rational_independent(terms, x)
237
+ if found or len(ind) == k:
238
+ sol = dict(zip(a, (i for s in linsolve(ind, a[:k]) for i in s)))
239
+ if sol:
240
+ found = True
241
+ DE = DE.subs(sol)
242
+ DE = DE.as_numer_denom()[0]
243
+ DE = DE.factor().as_coeff_mul(Derivative)[1][0]
244
+ yield DE.collect(Derivative(g(x))), k
245
+
246
+
247
+ def exp_re(DE, r, k):
248
+ """Converts a DE with constant coefficients (explike) into a RE.
249
+
250
+ Explanation
251
+ ===========
252
+
253
+ Performs the substitution:
254
+
255
+ .. math::
256
+ f^j(x) \\to r(k + j)
257
+
258
+ Normalises the terms so that lowest order of a term is always r(k).
259
+
260
+ Examples
261
+ ========
262
+
263
+ >>> from sympy import Function, Derivative
264
+ >>> from sympy.series.formal import exp_re
265
+ >>> from sympy.abc import x, k
266
+ >>> f, r = Function('f'), Function('r')
267
+
268
+ >>> exp_re(-f(x) + Derivative(f(x)), r, k)
269
+ -r(k) + r(k + 1)
270
+ >>> exp_re(Derivative(f(x), x) + Derivative(f(x), (x, 2)), r, k)
271
+ r(k) + r(k + 1)
272
+
273
+ See Also
274
+ ========
275
+
276
+ sympy.series.formal.hyper_re
277
+ """
278
+ RE = S.Zero
279
+
280
+ g = DE.atoms(Function).pop()
281
+
282
+ mini = None
283
+ for t in Add.make_args(DE):
284
+ coeff, d = t.as_independent(g)
285
+ if isinstance(d, Derivative):
286
+ j = d.derivative_count
287
+ else:
288
+ j = 0
289
+ if mini is None or j < mini:
290
+ mini = j
291
+ RE += coeff * r(k + j)
292
+ if mini:
293
+ RE = RE.subs(k, k - mini)
294
+ return RE
295
+
296
+
297
+ def hyper_re(DE, r, k):
298
+ """
299
+ Converts a DE into a RE.
300
+
301
+ Explanation
302
+ ===========
303
+
304
+ Performs the substitution:
305
+
306
+ .. math::
307
+ x^l f^j(x) \\to (k + 1 - l)_j . a_{k + j - l}
308
+
309
+ Normalises the terms so that lowest order of a term is always r(k).
310
+
311
+ Examples
312
+ ========
313
+
314
+ >>> from sympy import Function, Derivative
315
+ >>> from sympy.series.formal import hyper_re
316
+ >>> from sympy.abc import x, k
317
+ >>> f, r = Function('f'), Function('r')
318
+
319
+ >>> hyper_re(-f(x) + Derivative(f(x)), r, k)
320
+ (k + 1)*r(k + 1) - r(k)
321
+ >>> hyper_re(-x*f(x) + Derivative(f(x), (x, 2)), r, k)
322
+ (k + 2)*(k + 3)*r(k + 3) - r(k)
323
+
324
+ See Also
325
+ ========
326
+
327
+ sympy.series.formal.exp_re
328
+ """
329
+ RE = S.Zero
330
+
331
+ g = DE.atoms(Function).pop()
332
+ x = g.atoms(Symbol).pop()
333
+
334
+ mini = None
335
+ for t in Add.make_args(DE.expand()):
336
+ coeff, d = t.as_independent(g)
337
+ c, v = coeff.as_independent(x)
338
+ l = v.as_coeff_exponent(x)[1]
339
+ if isinstance(d, Derivative):
340
+ j = d.derivative_count
341
+ else:
342
+ j = 0
343
+ RE += c * rf(k + 1 - l, j) * r(k + j - l)
344
+ if mini is None or j - l < mini:
345
+ mini = j - l
346
+
347
+ RE = RE.subs(k, k - mini)
348
+
349
+ m = Wild('m')
350
+ return RE.collect(r(k + m))
351
+
352
+
353
+ def _transformation_a(f, x, P, Q, k, m, shift):
354
+ f *= x**(-shift)
355
+ P = P.subs(k, k + shift)
356
+ Q = Q.subs(k, k + shift)
357
+ return f, P, Q, m
358
+
359
+
360
+ def _transformation_c(f, x, P, Q, k, m, scale):
361
+ f = f.subs(x, x**scale)
362
+ P = P.subs(k, k / scale)
363
+ Q = Q.subs(k, k / scale)
364
+ m *= scale
365
+ return f, P, Q, m
366
+
367
+
368
+ def _transformation_e(f, x, P, Q, k, m):
369
+ f = f.diff(x)
370
+ P = P.subs(k, k + 1) * (k + m + 1)
371
+ Q = Q.subs(k, k + 1) * (k + 1)
372
+ return f, P, Q, m
373
+
374
+
375
+ def _apply_shift(sol, shift):
376
+ return [(res, cond + shift) for res, cond in sol]
377
+
378
+
379
+ def _apply_scale(sol, scale):
380
+ return [(res, cond / scale) for res, cond in sol]
381
+
382
+
383
+ def _apply_integrate(sol, x, k):
384
+ return [(res / ((cond + 1)*(cond.as_coeff_Add()[1].coeff(k))), cond + 1)
385
+ for res, cond in sol]
386
+
387
+
388
+ def _compute_formula(f, x, P, Q, k, m, k_max):
389
+ """Computes the formula for f."""
390
+ from sympy.polys import roots
391
+
392
+ sol = []
393
+ for i in range(k_max + 1, k_max + m + 1):
394
+ if (i < 0) == True:
395
+ continue
396
+ r = f.diff(x, i).limit(x, 0) / factorial(i)
397
+ if r.is_zero:
398
+ continue
399
+
400
+ kterm = m*k + i
401
+ res = r
402
+
403
+ p = P.subs(k, kterm)
404
+ q = Q.subs(k, kterm)
405
+ c1 = p.subs(k, 1/k).leadterm(k)[0]
406
+ c2 = q.subs(k, 1/k).leadterm(k)[0]
407
+ res *= (-c1 / c2)**k
408
+
409
+ res *= Mul(*[rf(-r, k)**mul for r, mul in roots(p, k).items()])
410
+ res /= Mul(*[rf(-r, k)**mul for r, mul in roots(q, k).items()])
411
+
412
+ sol.append((res, kterm))
413
+
414
+ return sol
415
+
416
+
417
+ def _rsolve_hypergeometric(f, x, P, Q, k, m):
418
+ """
419
+ Recursive wrapper to rsolve_hypergeometric.
420
+
421
+ Explanation
422
+ ===========
423
+
424
+ Returns a Tuple of (formula, series independent terms,
425
+ maximum power of x in independent terms) if successful
426
+ otherwise ``None``.
427
+
428
+ See :func:`rsolve_hypergeometric` for details.
429
+ """
430
+ from sympy.polys import lcm, roots
431
+ from sympy.integrals import integrate
432
+
433
+ # transformation - c
434
+ proots, qroots = roots(P, k), roots(Q, k)
435
+ all_roots = dict(proots)
436
+ all_roots.update(qroots)
437
+ scale = lcm([r.as_numer_denom()[1] for r, t in all_roots.items()
438
+ if r.is_rational])
439
+ f, P, Q, m = _transformation_c(f, x, P, Q, k, m, scale)
440
+
441
+ # transformation - a
442
+ qroots = roots(Q, k)
443
+ if qroots:
444
+ k_min = Min(*qroots.keys())
445
+ else:
446
+ k_min = S.Zero
447
+ shift = k_min + m
448
+ f, P, Q, m = _transformation_a(f, x, P, Q, k, m, shift)
449
+
450
+ l = (x*f).limit(x, 0)
451
+ if not isinstance(l, Limit) and l != 0: # Ideally should only be l != 0
452
+ return None
453
+
454
+ qroots = roots(Q, k)
455
+ if qroots:
456
+ k_max = Max(*qroots.keys())
457
+ else:
458
+ k_max = S.Zero
459
+
460
+ ind, mp = S.Zero, -oo
461
+ for i in range(k_max + m + 1):
462
+ r = f.diff(x, i).limit(x, 0) / factorial(i)
463
+ if r.is_finite is False:
464
+ old_f = f
465
+ f, P, Q, m = _transformation_a(f, x, P, Q, k, m, i)
466
+ f, P, Q, m = _transformation_e(f, x, P, Q, k, m)
467
+ sol, ind, mp = _rsolve_hypergeometric(f, x, P, Q, k, m)
468
+ sol = _apply_integrate(sol, x, k)
469
+ sol = _apply_shift(sol, i)
470
+ ind = integrate(ind, x)
471
+ ind += (old_f - ind).limit(x, 0) # constant of integration
472
+ mp += 1
473
+ return sol, ind, mp
474
+ elif r:
475
+ ind += r*x**(i + shift)
476
+ pow_x = Rational((i + shift), scale)
477
+ if pow_x > mp:
478
+ mp = pow_x # maximum power of x
479
+ ind = ind.subs(x, x**(1/scale))
480
+
481
+ sol = _compute_formula(f, x, P, Q, k, m, k_max)
482
+ sol = _apply_shift(sol, shift)
483
+ sol = _apply_scale(sol, scale)
484
+
485
+ return sol, ind, mp
486
+
487
+
488
+ def rsolve_hypergeometric(f, x, P, Q, k, m):
489
+ """
490
+ Solves RE of hypergeometric type.
491
+
492
+ Explanation
493
+ ===========
494
+
495
+ Attempts to solve RE of the form
496
+
497
+ Q(k)*a(k + m) - P(k)*a(k)
498
+
499
+ Transformations that preserve Hypergeometric type:
500
+
501
+ a. x**n*f(x): b(k + m) = R(k - n)*b(k)
502
+ b. f(A*x): b(k + m) = A**m*R(k)*b(k)
503
+ c. f(x**n): b(k + n*m) = R(k/n)*b(k)
504
+ d. f(x**(1/m)): b(k + 1) = R(k*m)*b(k)
505
+ e. f'(x): b(k + m) = ((k + m + 1)/(k + 1))*R(k + 1)*b(k)
506
+
507
+ Some of these transformations have been used to solve the RE.
508
+
509
+ Returns
510
+ =======
511
+
512
+ formula : Expr
513
+ ind : Expr
514
+ Independent terms.
515
+ order : int
516
+
517
+ Examples
518
+ ========
519
+
520
+ >>> from sympy import exp, ln, S
521
+ >>> from sympy.series.formal import rsolve_hypergeometric as rh
522
+ >>> from sympy.abc import x, k
523
+
524
+ >>> rh(exp(x), x, -S.One, (k + 1), k, 1)
525
+ (Piecewise((1/factorial(k), Eq(Mod(k, 1), 0)), (0, True)), 1, 1)
526
+
527
+ >>> rh(ln(1 + x), x, k**2, k*(k + 1), k, 1)
528
+ (Piecewise(((-1)**(k - 1)*factorial(k - 1)/RisingFactorial(2, k - 1),
529
+ Eq(Mod(k, 1), 0)), (0, True)), x, 2)
530
+
531
+ References
532
+ ==========
533
+
534
+ .. [1] Formal Power Series - Dominik Gruntz, Wolfram Koepf
535
+ .. [2] Power Series in Computer Algebra - Wolfram Koepf
536
+ """
537
+ result = _rsolve_hypergeometric(f, x, P, Q, k, m)
538
+
539
+ if result is None:
540
+ return None
541
+
542
+ sol_list, ind, mp = result
543
+
544
+ sol_dict = defaultdict(lambda: S.Zero)
545
+ for res, cond in sol_list:
546
+ j, mk = cond.as_coeff_Add()
547
+ c = mk.coeff(k)
548
+
549
+ if j.is_integer is False:
550
+ res *= x**frac(j)
551
+ j = floor(j)
552
+
553
+ res = res.subs(k, (k - j) / c)
554
+ cond = Eq(k % c, j % c)
555
+ sol_dict[cond] += res # Group together formula for same conditions
556
+
557
+ sol = [(res, cond) for cond, res in sol_dict.items()]
558
+ sol.append((S.Zero, True))
559
+ sol = Piecewise(*sol)
560
+
561
+ if mp is -oo:
562
+ s = S.Zero
563
+ elif mp.is_integer is False:
564
+ s = ceiling(mp)
565
+ else:
566
+ s = mp + 1
567
+
568
+ # save all the terms of
569
+ # form 1/x**k in ind
570
+ if s < 0:
571
+ ind += sum(sequence(sol * x**k, (k, s, -1)))
572
+ s = S.Zero
573
+
574
+ return (sol, ind, s)
575
+
576
+
577
+ def _solve_hyper_RE(f, x, RE, g, k):
578
+ """See docstring of :func:`rsolve_hypergeometric` for details."""
579
+ terms = Add.make_args(RE)
580
+
581
+ if len(terms) == 2:
582
+ gs = list(RE.atoms(Function))
583
+ P, Q = map(RE.coeff, gs)
584
+ m = gs[1].args[0] - gs[0].args[0]
585
+ if m < 0:
586
+ P, Q = Q, P
587
+ m = abs(m)
588
+ return rsolve_hypergeometric(f, x, P, Q, k, m)
589
+
590
+
591
+ def _solve_explike_DE(f, x, DE, g, k):
592
+ """Solves DE with constant coefficients."""
593
+ from sympy.solvers import rsolve
594
+
595
+ for t in Add.make_args(DE):
596
+ coeff, d = t.as_independent(g)
597
+ if coeff.free_symbols:
598
+ return
599
+
600
+ RE = exp_re(DE, g, k)
601
+
602
+ init = {}
603
+ for i in range(len(Add.make_args(RE))):
604
+ if i:
605
+ f = f.diff(x)
606
+ init[g(k).subs(k, i)] = f.limit(x, 0)
607
+
608
+ sol = rsolve(RE, g(k), init)
609
+
610
+ if sol:
611
+ return (sol / factorial(k), S.Zero, S.Zero)
612
+
613
+
614
+ def _solve_simple(f, x, DE, g, k):
615
+ """Converts DE into RE and solves using :func:`rsolve`."""
616
+ from sympy.solvers import rsolve
617
+
618
+ RE = hyper_re(DE, g, k)
619
+
620
+ init = {}
621
+ for i in range(len(Add.make_args(RE))):
622
+ if i:
623
+ f = f.diff(x)
624
+ init[g(k).subs(k, i)] = f.limit(x, 0) / factorial(i)
625
+
626
+ sol = rsolve(RE, g(k), init)
627
+
628
+ if sol:
629
+ return (sol, S.Zero, S.Zero)
630
+
631
+
632
+ def _transform_explike_DE(DE, g, x, order, syms):
633
+ """Converts DE with free parameters into DE with constant coefficients."""
634
+ from sympy.solvers.solveset import linsolve
635
+
636
+ eq = []
637
+ highest_coeff = DE.coeff(Derivative(g(x), x, order))
638
+ for i in range(order):
639
+ coeff = DE.coeff(Derivative(g(x), x, i))
640
+ coeff = (coeff / highest_coeff).expand().collect(x)
641
+ eq.extend(Add.make_args(coeff))
642
+ temp = []
643
+ for e in eq:
644
+ if e.has(x):
645
+ break
646
+ elif e.has(Symbol):
647
+ temp.append(e)
648
+ else:
649
+ eq = temp
650
+ if eq:
651
+ sol = dict(zip(syms, (i for s in linsolve(eq, list(syms)) for i in s)))
652
+ if sol:
653
+ DE = DE.subs(sol)
654
+ DE = DE.factor().as_coeff_mul(Derivative)[1][0]
655
+ DE = DE.collect(Derivative(g(x)))
656
+ return DE
657
+
658
+
659
+ def _transform_DE_RE(DE, g, k, order, syms):
660
+ """Converts DE with free parameters into RE of hypergeometric type."""
661
+ from sympy.solvers.solveset import linsolve
662
+
663
+ RE = hyper_re(DE, g, k)
664
+
665
+ eq = [RE.coeff(g(k + i)) for i in range(1, order)]
666
+ sol = dict(zip(syms, (i for s in linsolve(eq, list(syms)) for i in s)))
667
+ if sol:
668
+ m = Wild('m')
669
+ RE = RE.subs(sol)
670
+ RE = RE.factor().as_numer_denom()[0].collect(g(k + m))
671
+ RE = RE.as_coeff_mul(g)[1][0]
672
+ for i in range(order): # smallest order should be g(k)
673
+ if RE.coeff(g(k + i)) and i:
674
+ RE = RE.subs(k, k - i)
675
+ break
676
+ return RE
677
+
678
+
679
+ def solve_de(f, x, DE, order, g, k):
680
+ """
681
+ Solves the DE.
682
+
683
+ Explanation
684
+ ===========
685
+
686
+ Tries to solve DE by either converting into a RE containing two terms or
687
+ converting into a DE having constant coefficients.
688
+
689
+ Returns
690
+ =======
691
+
692
+ formula : Expr
693
+ ind : Expr
694
+ Independent terms.
695
+ order : int
696
+
697
+ Examples
698
+ ========
699
+
700
+ >>> from sympy import Derivative as D, Function
701
+ >>> from sympy import exp, ln
702
+ >>> from sympy.series.formal import solve_de
703
+ >>> from sympy.abc import x, k
704
+ >>> f = Function('f')
705
+
706
+ >>> solve_de(exp(x), x, D(f(x), x) - f(x), 1, f, k)
707
+ (Piecewise((1/factorial(k), Eq(Mod(k, 1), 0)), (0, True)), 1, 1)
708
+
709
+ >>> solve_de(ln(1 + x), x, (x + 1)*D(f(x), x, 2) + D(f(x)), 2, f, k)
710
+ (Piecewise(((-1)**(k - 1)*factorial(k - 1)/RisingFactorial(2, k - 1),
711
+ Eq(Mod(k, 1), 0)), (0, True)), x, 2)
712
+ """
713
+ sol = None
714
+ syms = DE.free_symbols.difference({g, x})
715
+
716
+ if syms:
717
+ RE = _transform_DE_RE(DE, g, k, order, syms)
718
+ else:
719
+ RE = hyper_re(DE, g, k)
720
+ if not RE.free_symbols.difference({k}):
721
+ sol = _solve_hyper_RE(f, x, RE, g, k)
722
+
723
+ if sol:
724
+ return sol
725
+
726
+ if syms:
727
+ DE = _transform_explike_DE(DE, g, x, order, syms)
728
+ if not DE.free_symbols.difference({x}):
729
+ sol = _solve_explike_DE(f, x, DE, g, k)
730
+
731
+ if sol:
732
+ return sol
733
+
734
+
735
+ def hyper_algorithm(f, x, k, order=4):
736
+ """
737
+ Hypergeometric algorithm for computing Formal Power Series.
738
+
739
+ Explanation
740
+ ===========
741
+
742
+ Steps:
743
+ * Generates DE
744
+ * Convert the DE into RE
745
+ * Solves the RE
746
+
747
+ Examples
748
+ ========
749
+
750
+ >>> from sympy import exp, ln
751
+ >>> from sympy.series.formal import hyper_algorithm
752
+
753
+ >>> from sympy.abc import x, k
754
+
755
+ >>> hyper_algorithm(exp(x), x, k)
756
+ (Piecewise((1/factorial(k), Eq(Mod(k, 1), 0)), (0, True)), 1, 1)
757
+
758
+ >>> hyper_algorithm(ln(1 + x), x, k)
759
+ (Piecewise(((-1)**(k - 1)*factorial(k - 1)/RisingFactorial(2, k - 1),
760
+ Eq(Mod(k, 1), 0)), (0, True)), x, 2)
761
+
762
+ See Also
763
+ ========
764
+
765
+ sympy.series.formal.simpleDE
766
+ sympy.series.formal.solve_de
767
+ """
768
+ g = Function('g')
769
+
770
+ des = [] # list of DE's
771
+ sol = None
772
+ for DE, i in simpleDE(f, x, g, order):
773
+ if DE is not None:
774
+ sol = solve_de(f, x, DE, i, g, k)
775
+ if sol:
776
+ return sol
777
+ if not DE.free_symbols.difference({x}):
778
+ des.append(DE)
779
+
780
+ # If nothing works
781
+ # Try plain rsolve
782
+ for DE in des:
783
+ sol = _solve_simple(f, x, DE, g, k)
784
+ if sol:
785
+ return sol
786
+
787
+
788
+ def _compute_fps(f, x, x0, dir, hyper, order, rational, full):
789
+ """Recursive wrapper to compute fps.
790
+
791
+ See :func:`compute_fps` for details.
792
+ """
793
+ if x0 in [S.Infinity, S.NegativeInfinity]:
794
+ dir = S.One if x0 is S.Infinity else -S.One
795
+ temp = f.subs(x, 1/x)
796
+ result = _compute_fps(temp, x, 0, dir, hyper, order, rational, full)
797
+ if result is None:
798
+ return None
799
+ return (result[0], result[1].subs(x, 1/x), result[2].subs(x, 1/x))
800
+ elif x0 or dir == -S.One:
801
+ if dir == -S.One:
802
+ rep = -x + x0
803
+ rep2 = -x
804
+ rep2b = x0
805
+ else:
806
+ rep = x + x0
807
+ rep2 = x
808
+ rep2b = -x0
809
+ temp = f.subs(x, rep)
810
+ result = _compute_fps(temp, x, 0, S.One, hyper, order, rational, full)
811
+ if result is None:
812
+ return None
813
+ return (result[0], result[1].subs(x, rep2 + rep2b),
814
+ result[2].subs(x, rep2 + rep2b))
815
+
816
+ if f.is_polynomial(x):
817
+ k = Dummy('k')
818
+ ak = sequence(Coeff(f, x, k), (k, 1, oo))
819
+ xk = sequence(x**k, (k, 0, oo))
820
+ ind = f.coeff(x, 0)
821
+ return ak, xk, ind
822
+
823
+ # Break instances of Add
824
+ # this allows application of different
825
+ # algorithms on different terms increasing the
826
+ # range of admissible functions.
827
+ if isinstance(f, Add):
828
+ result = False
829
+ ak = sequence(S.Zero, (0, oo))
830
+ ind, xk = S.Zero, None
831
+ for t in Add.make_args(f):
832
+ res = _compute_fps(t, x, 0, S.One, hyper, order, rational, full)
833
+ if res:
834
+ if not result:
835
+ result = True
836
+ xk = res[1]
837
+ if res[0].start > ak.start:
838
+ seq = ak
839
+ s, f = ak.start, res[0].start
840
+ else:
841
+ seq = res[0]
842
+ s, f = res[0].start, ak.start
843
+ save = Add(*[z[0]*z[1] for z in zip(seq[0:(f - s)], xk[s:f])])
844
+ ak += res[0]
845
+ ind += res[2] + save
846
+ else:
847
+ ind += t
848
+ if result:
849
+ return ak, xk, ind
850
+ return None
851
+
852
+ # The symbolic term - symb, if present, is being separated from the function
853
+ # Otherwise symb is being set to S.One
854
+ syms = f.free_symbols.difference({x})
855
+ (f, symb) = expand(f).as_independent(*syms)
856
+
857
+ result = None
858
+
859
+ # from here on it's x0=0 and dir=1 handling
860
+ k = Dummy('k')
861
+ if rational:
862
+ result = rational_algorithm(f, x, k, order, full)
863
+
864
+ if result is None and hyper:
865
+ result = hyper_algorithm(f, x, k, order)
866
+
867
+ if result is None:
868
+ return None
869
+
870
+ from sympy.simplify.powsimp import powsimp
871
+ if symb.is_zero:
872
+ symb = S.One
873
+ else:
874
+ symb = powsimp(symb)
875
+ ak = sequence(result[0], (k, result[2], oo))
876
+ xk_formula = powsimp(x**k * symb)
877
+ xk = sequence(xk_formula, (k, 0, oo))
878
+ ind = powsimp(result[1] * symb)
879
+
880
+ return ak, xk, ind
881
+
882
+
883
+ def compute_fps(f, x, x0=0, dir=1, hyper=True, order=4, rational=True,
884
+ full=False):
885
+ """
886
+ Computes the formula for Formal Power Series of a function.
887
+
888
+ Explanation
889
+ ===========
890
+
891
+ Tries to compute the formula by applying the following techniques
892
+ (in order):
893
+
894
+ * rational_algorithm
895
+ * Hypergeometric algorithm
896
+
897
+ Parameters
898
+ ==========
899
+
900
+ x : Symbol
901
+ x0 : number, optional
902
+ Point to perform series expansion about. Default is 0.
903
+ dir : {1, -1, '+', '-'}, optional
904
+ If dir is 1 or '+' the series is calculated from the right and
905
+ for -1 or '-' the series is calculated from the left. For smooth
906
+ functions this flag will not alter the results. Default is 1.
907
+ hyper : {True, False}, optional
908
+ Set hyper to False to skip the hypergeometric algorithm.
909
+ By default it is set to False.
910
+ order : int, optional
911
+ Order of the derivative of ``f``, Default is 4.
912
+ rational : {True, False}, optional
913
+ Set rational to False to skip rational algorithm. By default it is set
914
+ to True.
915
+ full : {True, False}, optional
916
+ Set full to True to increase the range of rational algorithm.
917
+ See :func:`rational_algorithm` for details. By default it is set to
918
+ False.
919
+
920
+ Returns
921
+ =======
922
+
923
+ ak : sequence
924
+ Sequence of coefficients.
925
+ xk : sequence
926
+ Sequence of powers of x.
927
+ ind : Expr
928
+ Independent terms.
929
+ mul : Pow
930
+ Common terms.
931
+
932
+ See Also
933
+ ========
934
+
935
+ sympy.series.formal.rational_algorithm
936
+ sympy.series.formal.hyper_algorithm
937
+ """
938
+ f = sympify(f)
939
+ x = sympify(x)
940
+
941
+ if not f.has(x):
942
+ return None
943
+
944
+ x0 = sympify(x0)
945
+
946
+ if dir == '+':
947
+ dir = S.One
948
+ elif dir == '-':
949
+ dir = -S.One
950
+ elif dir not in [S.One, -S.One]:
951
+ raise ValueError("Dir must be '+' or '-'")
952
+ else:
953
+ dir = sympify(dir)
954
+
955
+ return _compute_fps(f, x, x0, dir, hyper, order, rational, full)
956
+
957
+
958
+ class Coeff(Function):
959
+ """
960
+ Coeff(p, x, n) represents the nth coefficient of the polynomial p in x
961
+ """
962
+ @classmethod
963
+ def eval(cls, p, x, n):
964
+ if p.is_polynomial(x) and n.is_integer:
965
+ return p.coeff(x, n)
966
+
967
+
968
+ class FormalPowerSeries(SeriesBase):
969
+ """
970
+ Represents Formal Power Series of a function.
971
+
972
+ Explanation
973
+ ===========
974
+
975
+ No computation is performed. This class should only to be used to represent
976
+ a series. No checks are performed.
977
+
978
+ For computing a series use :func:`fps`.
979
+
980
+ See Also
981
+ ========
982
+
983
+ sympy.series.formal.fps
984
+ """
985
+ def __new__(cls, *args):
986
+ args = map(sympify, args)
987
+ return Expr.__new__(cls, *args)
988
+
989
+ def __init__(self, *args):
990
+ ak = args[4][0]
991
+ k = ak.variables[0]
992
+ self.ak_seq = sequence(ak.formula, (k, 1, oo))
993
+ self.fact_seq = sequence(factorial(k), (k, 1, oo))
994
+ self.bell_coeff_seq = self.ak_seq * self.fact_seq
995
+ self.sign_seq = sequence((-1, 1), (k, 1, oo))
996
+
997
+ @property
998
+ def function(self):
999
+ return self.args[0]
1000
+
1001
+ @property
1002
+ def x(self):
1003
+ return self.args[1]
1004
+
1005
+ @property
1006
+ def x0(self):
1007
+ return self.args[2]
1008
+
1009
+ @property
1010
+ def dir(self):
1011
+ return self.args[3]
1012
+
1013
+ @property
1014
+ def ak(self):
1015
+ return self.args[4][0]
1016
+
1017
+ @property
1018
+ def xk(self):
1019
+ return self.args[4][1]
1020
+
1021
+ @property
1022
+ def ind(self):
1023
+ return self.args[4][2]
1024
+
1025
+ @property
1026
+ def interval(self):
1027
+ return Interval(0, oo)
1028
+
1029
+ @property
1030
+ def start(self):
1031
+ return self.interval.inf
1032
+
1033
+ @property
1034
+ def stop(self):
1035
+ return self.interval.sup
1036
+
1037
+ @property
1038
+ def length(self):
1039
+ return oo
1040
+
1041
+ @property
1042
+ def infinite(self):
1043
+ """Returns an infinite representation of the series"""
1044
+ from sympy.concrete import Sum
1045
+ ak, xk = self.ak, self.xk
1046
+ k = ak.variables[0]
1047
+ inf_sum = Sum(ak.formula * xk.formula, (k, ak.start, ak.stop))
1048
+
1049
+ return self.ind + inf_sum
1050
+
1051
+ def _get_pow_x(self, term):
1052
+ """Returns the power of x in a term."""
1053
+ xterm, pow_x = term.as_independent(self.x)[1].as_base_exp()
1054
+ if not xterm.has(self.x):
1055
+ return S.Zero
1056
+ return pow_x
1057
+
1058
+ def polynomial(self, n=6):
1059
+ """
1060
+ Truncated series as polynomial.
1061
+
1062
+ Explanation
1063
+ ===========
1064
+
1065
+ Returns series expansion of ``f`` upto order ``O(x**n)``
1066
+ as a polynomial(without ``O`` term).
1067
+ """
1068
+ terms = []
1069
+ sym = self.free_symbols
1070
+ for i, t in enumerate(self):
1071
+ xp = self._get_pow_x(t)
1072
+ if xp.has(*sym):
1073
+ xp = xp.as_coeff_add(*sym)[0]
1074
+ if xp >= n:
1075
+ break
1076
+ elif xp.is_integer is True and i == n + 1:
1077
+ break
1078
+ elif t is not S.Zero:
1079
+ terms.append(t)
1080
+
1081
+ return Add(*terms)
1082
+
1083
+ def truncate(self, n=6):
1084
+ """
1085
+ Truncated series.
1086
+
1087
+ Explanation
1088
+ ===========
1089
+
1090
+ Returns truncated series expansion of f upto
1091
+ order ``O(x**n)``.
1092
+
1093
+ If n is ``None``, returns an infinite iterator.
1094
+ """
1095
+ if n is None:
1096
+ return iter(self)
1097
+
1098
+ x, x0 = self.x, self.x0
1099
+ pt_xk = self.xk.coeff(n)
1100
+ if x0 is S.NegativeInfinity:
1101
+ x0 = S.Infinity
1102
+
1103
+ return self.polynomial(n) + Order(pt_xk, (x, x0))
1104
+
1105
+ def zero_coeff(self):
1106
+ return self._eval_term(0)
1107
+
1108
+ def _eval_term(self, pt):
1109
+ try:
1110
+ pt_xk = self.xk.coeff(pt)
1111
+ pt_ak = self.ak.coeff(pt).simplify() # Simplify the coefficients
1112
+ except IndexError:
1113
+ term = S.Zero
1114
+ else:
1115
+ term = (pt_ak * pt_xk)
1116
+
1117
+ if self.ind:
1118
+ ind = S.Zero
1119
+ sym = self.free_symbols
1120
+ for t in Add.make_args(self.ind):
1121
+ pow_x = self._get_pow_x(t)
1122
+ if pow_x.has(*sym):
1123
+ pow_x = pow_x.as_coeff_add(*sym)[0]
1124
+ if pt == 0 and pow_x < 1:
1125
+ ind += t
1126
+ elif pow_x >= pt and pow_x < pt + 1:
1127
+ ind += t
1128
+ term += ind
1129
+
1130
+ return term.collect(self.x)
1131
+
1132
+ def _eval_subs(self, old, new):
1133
+ x = self.x
1134
+ if old.has(x):
1135
+ return self
1136
+
1137
+ def _eval_as_leading_term(self, x, logx, cdir):
1138
+ for t in self:
1139
+ if t is not S.Zero:
1140
+ return t
1141
+
1142
+ def _eval_derivative(self, x):
1143
+ f = self.function.diff(x)
1144
+ ind = self.ind.diff(x)
1145
+
1146
+ pow_xk = self._get_pow_x(self.xk.formula)
1147
+ ak = self.ak
1148
+ k = ak.variables[0]
1149
+ if ak.formula.has(x):
1150
+ form = []
1151
+ for e, c in ak.formula.args:
1152
+ temp = S.Zero
1153
+ for t in Add.make_args(e):
1154
+ pow_x = self._get_pow_x(t)
1155
+ temp += t * (pow_xk + pow_x)
1156
+ form.append((temp, c))
1157
+ form = Piecewise(*form)
1158
+ ak = sequence(form.subs(k, k + 1), (k, ak.start - 1, ak.stop))
1159
+ else:
1160
+ ak = sequence((ak.formula * pow_xk).subs(k, k + 1),
1161
+ (k, ak.start - 1, ak.stop))
1162
+
1163
+ return self.func(f, self.x, self.x0, self.dir, (ak, self.xk, ind))
1164
+
1165
+ def integrate(self, x=None, **kwargs):
1166
+ """
1167
+ Integrate Formal Power Series.
1168
+
1169
+ Examples
1170
+ ========
1171
+
1172
+ >>> from sympy import fps, sin, integrate
1173
+ >>> from sympy.abc import x
1174
+ >>> f = fps(sin(x))
1175
+ >>> f.integrate(x).truncate()
1176
+ -1 + x**2/2 - x**4/24 + O(x**6)
1177
+ >>> integrate(f, (x, 0, 1))
1178
+ 1 - cos(1)
1179
+ """
1180
+ from sympy.integrals import integrate
1181
+
1182
+ if x is None:
1183
+ x = self.x
1184
+ elif iterable(x):
1185
+ return integrate(self.function, x)
1186
+
1187
+ f = integrate(self.function, x)
1188
+ ind = integrate(self.ind, x)
1189
+ ind += (f - ind).limit(x, 0) # constant of integration
1190
+
1191
+ pow_xk = self._get_pow_x(self.xk.formula)
1192
+ ak = self.ak
1193
+ k = ak.variables[0]
1194
+ if ak.formula.has(x):
1195
+ form = []
1196
+ for e, c in ak.formula.args:
1197
+ temp = S.Zero
1198
+ for t in Add.make_args(e):
1199
+ pow_x = self._get_pow_x(t)
1200
+ temp += t / (pow_xk + pow_x + 1)
1201
+ form.append((temp, c))
1202
+ form = Piecewise(*form)
1203
+ ak = sequence(form.subs(k, k - 1), (k, ak.start + 1, ak.stop))
1204
+ else:
1205
+ ak = sequence((ak.formula / (pow_xk + 1)).subs(k, k - 1),
1206
+ (k, ak.start + 1, ak.stop))
1207
+
1208
+ return self.func(f, self.x, self.x0, self.dir, (ak, self.xk, ind))
1209
+
1210
+ def product(self, other, x=None, n=6):
1211
+ """
1212
+ Multiplies two Formal Power Series, using discrete convolution and
1213
+ return the truncated terms upto specified order.
1214
+
1215
+ Parameters
1216
+ ==========
1217
+
1218
+ n : Number, optional
1219
+ Specifies the order of the term up to which the polynomial should
1220
+ be truncated.
1221
+
1222
+ Examples
1223
+ ========
1224
+
1225
+ >>> from sympy import fps, sin, exp
1226
+ >>> from sympy.abc import x
1227
+ >>> f1 = fps(sin(x))
1228
+ >>> f2 = fps(exp(x))
1229
+
1230
+ >>> f1.product(f2, x).truncate(4)
1231
+ x + x**2 + x**3/3 + O(x**4)
1232
+
1233
+ See Also
1234
+ ========
1235
+
1236
+ sympy.discrete.convolutions
1237
+ sympy.series.formal.FormalPowerSeriesProduct
1238
+
1239
+ """
1240
+
1241
+ if n is None:
1242
+ return iter(self)
1243
+
1244
+ other = sympify(other)
1245
+
1246
+ if not isinstance(other, FormalPowerSeries):
1247
+ raise ValueError("Both series should be an instance of FormalPowerSeries"
1248
+ " class.")
1249
+
1250
+ if self.dir != other.dir:
1251
+ raise ValueError("Both series should be calculated from the"
1252
+ " same direction.")
1253
+ elif self.x0 != other.x0:
1254
+ raise ValueError("Both series should be calculated about the"
1255
+ " same point.")
1256
+
1257
+ elif self.x != other.x:
1258
+ raise ValueError("Both series should have the same symbol.")
1259
+
1260
+ return FormalPowerSeriesProduct(self, other)
1261
+
1262
+ def coeff_bell(self, n):
1263
+ r"""
1264
+ self.coeff_bell(n) returns a sequence of Bell polynomials of the second kind.
1265
+ Note that ``n`` should be a integer.
1266
+
1267
+ The second kind of Bell polynomials (are sometimes called "partial" Bell
1268
+ polynomials or incomplete Bell polynomials) are defined as
1269
+
1270
+ .. math::
1271
+ B_{n,k}(x_1, x_2,\dotsc x_{n-k+1}) =
1272
+ \sum_{j_1+j_2+j_2+\dotsb=k \atop j_1+2j_2+3j_2+\dotsb=n}
1273
+ \frac{n!}{j_1!j_2!\dotsb j_{n-k+1}!}
1274
+ \left(\frac{x_1}{1!} \right)^{j_1}
1275
+ \left(\frac{x_2}{2!} \right)^{j_2} \dotsb
1276
+ \left(\frac{x_{n-k+1}}{(n-k+1)!} \right) ^{j_{n-k+1}}.
1277
+
1278
+ * ``bell(n, k, (x1, x2, ...))`` gives Bell polynomials of the second kind,
1279
+ `B_{n,k}(x_1, x_2, \dotsc, x_{n-k+1})`.
1280
+
1281
+ See Also
1282
+ ========
1283
+
1284
+ sympy.functions.combinatorial.numbers.bell
1285
+
1286
+ """
1287
+
1288
+ inner_coeffs = [bell(n, j, tuple(self.bell_coeff_seq[:n-j+1])) for j in range(1, n+1)]
1289
+
1290
+ k = Dummy('k')
1291
+ return sequence(tuple(inner_coeffs), (k, 1, oo))
1292
+
1293
+ def compose(self, other, x=None, n=6):
1294
+ r"""
1295
+ Returns the truncated terms of the formal power series of the composed function,
1296
+ up to specified ``n``.
1297
+
1298
+ Explanation
1299
+ ===========
1300
+
1301
+ If ``f`` and ``g`` are two formal power series of two different functions,
1302
+ then the coefficient sequence ``ak`` of the composed formal power series `fp`
1303
+ will be as follows.
1304
+
1305
+ .. math::
1306
+ \sum\limits_{k=0}^{n} b_k B_{n,k}(x_1, x_2, \dotsc, x_{n-k+1})
1307
+
1308
+ Parameters
1309
+ ==========
1310
+
1311
+ n : Number, optional
1312
+ Specifies the order of the term up to which the polynomial should
1313
+ be truncated.
1314
+
1315
+ Examples
1316
+ ========
1317
+
1318
+ >>> from sympy import fps, sin, exp
1319
+ >>> from sympy.abc import x
1320
+ >>> f1 = fps(exp(x))
1321
+ >>> f2 = fps(sin(x))
1322
+
1323
+ >>> f1.compose(f2, x).truncate()
1324
+ 1 + x + x**2/2 - x**4/8 - x**5/15 + O(x**6)
1325
+
1326
+ >>> f1.compose(f2, x).truncate(8)
1327
+ 1 + x + x**2/2 - x**4/8 - x**5/15 - x**6/240 + x**7/90 + O(x**8)
1328
+
1329
+ See Also
1330
+ ========
1331
+
1332
+ sympy.functions.combinatorial.numbers.bell
1333
+ sympy.series.formal.FormalPowerSeriesCompose
1334
+
1335
+ References
1336
+ ==========
1337
+
1338
+ .. [1] Comtet, Louis: Advanced combinatorics; the art of finite and infinite expansions. Reidel, 1974.
1339
+
1340
+ """
1341
+
1342
+ if n is None:
1343
+ return iter(self)
1344
+
1345
+ other = sympify(other)
1346
+
1347
+ if not isinstance(other, FormalPowerSeries):
1348
+ raise ValueError("Both series should be an instance of FormalPowerSeries"
1349
+ " class.")
1350
+
1351
+ if self.dir != other.dir:
1352
+ raise ValueError("Both series should be calculated from the"
1353
+ " same direction.")
1354
+ elif self.x0 != other.x0:
1355
+ raise ValueError("Both series should be calculated about the"
1356
+ " same point.")
1357
+
1358
+ elif self.x != other.x:
1359
+ raise ValueError("Both series should have the same symbol.")
1360
+
1361
+ if other._eval_term(0).as_coeff_mul(other.x)[0] is not S.Zero:
1362
+ raise ValueError("The formal power series of the inner function should not have any "
1363
+ "constant coefficient term.")
1364
+
1365
+ return FormalPowerSeriesCompose(self, other)
1366
+
1367
+ def inverse(self, x=None, n=6):
1368
+ r"""
1369
+ Returns the truncated terms of the inverse of the formal power series,
1370
+ up to specified ``n``.
1371
+
1372
+ Explanation
1373
+ ===========
1374
+
1375
+ If ``f`` and ``g`` are two formal power series of two different functions,
1376
+ then the coefficient sequence ``ak`` of the composed formal power series ``fp``
1377
+ will be as follows.
1378
+
1379
+ .. math::
1380
+ \sum\limits_{k=0}^{n} (-1)^{k} x_0^{-k-1} B_{n,k}(x_1, x_2, \dotsc, x_{n-k+1})
1381
+
1382
+ Parameters
1383
+ ==========
1384
+
1385
+ n : Number, optional
1386
+ Specifies the order of the term up to which the polynomial should
1387
+ be truncated.
1388
+
1389
+ Examples
1390
+ ========
1391
+
1392
+ >>> from sympy import fps, exp, cos
1393
+ >>> from sympy.abc import x
1394
+ >>> f1 = fps(exp(x))
1395
+ >>> f2 = fps(cos(x))
1396
+
1397
+ >>> f1.inverse(x).truncate()
1398
+ 1 - x + x**2/2 - x**3/6 + x**4/24 - x**5/120 + O(x**6)
1399
+
1400
+ >>> f2.inverse(x).truncate(8)
1401
+ 1 + x**2/2 + 5*x**4/24 + 61*x**6/720 + O(x**8)
1402
+
1403
+ See Also
1404
+ ========
1405
+
1406
+ sympy.functions.combinatorial.numbers.bell
1407
+ sympy.series.formal.FormalPowerSeriesInverse
1408
+
1409
+ References
1410
+ ==========
1411
+
1412
+ .. [1] Comtet, Louis: Advanced combinatorics; the art of finite and infinite expansions. Reidel, 1974.
1413
+
1414
+ """
1415
+
1416
+ if n is None:
1417
+ return iter(self)
1418
+
1419
+ if self._eval_term(0).is_zero:
1420
+ raise ValueError("Constant coefficient should exist for an inverse of a formal"
1421
+ " power series to exist.")
1422
+
1423
+ return FormalPowerSeriesInverse(self)
1424
+
1425
+ def __add__(self, other):
1426
+ other = sympify(other)
1427
+
1428
+ if isinstance(other, FormalPowerSeries):
1429
+ if self.dir != other.dir:
1430
+ raise ValueError("Both series should be calculated from the"
1431
+ " same direction.")
1432
+ elif self.x0 != other.x0:
1433
+ raise ValueError("Both series should be calculated about the"
1434
+ " same point.")
1435
+
1436
+ x, y = self.x, other.x
1437
+ f = self.function + other.function.subs(y, x)
1438
+
1439
+ if self.x not in f.free_symbols:
1440
+ return f
1441
+
1442
+ ak = self.ak + other.ak
1443
+ if self.ak.start > other.ak.start:
1444
+ seq = other.ak
1445
+ s, e = other.ak.start, self.ak.start
1446
+ else:
1447
+ seq = self.ak
1448
+ s, e = self.ak.start, other.ak.start
1449
+ save = Add(*[z[0]*z[1] for z in zip(seq[0:(e - s)], self.xk[s:e])])
1450
+ ind = self.ind + other.ind + save
1451
+
1452
+ return self.func(f, x, self.x0, self.dir, (ak, self.xk, ind))
1453
+
1454
+ elif not other.has(self.x):
1455
+ f = self.function + other
1456
+ ind = self.ind + other
1457
+
1458
+ return self.func(f, self.x, self.x0, self.dir,
1459
+ (self.ak, self.xk, ind))
1460
+
1461
+ return Add(self, other)
1462
+
1463
+ def __radd__(self, other):
1464
+ return self.__add__(other)
1465
+
1466
+ def __neg__(self):
1467
+ return self.func(-self.function, self.x, self.x0, self.dir,
1468
+ (-self.ak, self.xk, -self.ind))
1469
+
1470
+ def __sub__(self, other):
1471
+ return self.__add__(-other)
1472
+
1473
+ def __rsub__(self, other):
1474
+ return (-self).__add__(other)
1475
+
1476
+ def __mul__(self, other):
1477
+ other = sympify(other)
1478
+
1479
+ if other.has(self.x):
1480
+ return Mul(self, other)
1481
+
1482
+ f = self.function * other
1483
+ ak = self.ak.coeff_mul(other)
1484
+ ind = self.ind * other
1485
+
1486
+ return self.func(f, self.x, self.x0, self.dir, (ak, self.xk, ind))
1487
+
1488
+ def __rmul__(self, other):
1489
+ return self.__mul__(other)
1490
+
1491
+
1492
+ class FiniteFormalPowerSeries(FormalPowerSeries):
1493
+ """Base Class for Product, Compose and Inverse classes"""
1494
+
1495
+ def __init__(self, *args):
1496
+ pass
1497
+
1498
+ @property
1499
+ def ffps(self):
1500
+ return self.args[0]
1501
+
1502
+ @property
1503
+ def gfps(self):
1504
+ return self.args[1]
1505
+
1506
+ @property
1507
+ def f(self):
1508
+ return self.ffps.function
1509
+
1510
+ @property
1511
+ def g(self):
1512
+ return self.gfps.function
1513
+
1514
+ @property
1515
+ def infinite(self):
1516
+ raise NotImplementedError("No infinite version for an object of"
1517
+ " FiniteFormalPowerSeries class.")
1518
+
1519
+ def _eval_terms(self, n):
1520
+ raise NotImplementedError("(%s)._eval_terms()" % self)
1521
+
1522
+ def _eval_term(self, pt):
1523
+ raise NotImplementedError("By the current logic, one can get terms"
1524
+ "upto a certain order, instead of getting term by term.")
1525
+
1526
+ def polynomial(self, n):
1527
+ return self._eval_terms(n)
1528
+
1529
+ def truncate(self, n=6):
1530
+ ffps = self.ffps
1531
+ pt_xk = ffps.xk.coeff(n)
1532
+ x, x0 = ffps.x, ffps.x0
1533
+
1534
+ return self.polynomial(n) + Order(pt_xk, (x, x0))
1535
+
1536
+ def _eval_derivative(self, x):
1537
+ raise NotImplementedError
1538
+
1539
+ def integrate(self, x):
1540
+ raise NotImplementedError
1541
+
1542
+
1543
+ class FormalPowerSeriesProduct(FiniteFormalPowerSeries):
1544
+ """Represents the product of two formal power series of two functions.
1545
+
1546
+ Explanation
1547
+ ===========
1548
+
1549
+ No computation is performed. Terms are calculated using a term by term logic,
1550
+ instead of a point by point logic.
1551
+
1552
+ There are two differences between a :obj:`FormalPowerSeries` object and a
1553
+ :obj:`FormalPowerSeriesProduct` object. The first argument contains the two
1554
+ functions involved in the product. Also, the coefficient sequence contains
1555
+ both the coefficient sequence of the formal power series of the involved functions.
1556
+
1557
+ See Also
1558
+ ========
1559
+
1560
+ sympy.series.formal.FormalPowerSeries
1561
+ sympy.series.formal.FiniteFormalPowerSeries
1562
+
1563
+ """
1564
+
1565
+ def __init__(self, *args):
1566
+ ffps, gfps = self.ffps, self.gfps
1567
+
1568
+ k = ffps.ak.variables[0]
1569
+ self.coeff1 = sequence(ffps.ak.formula, (k, 0, oo))
1570
+
1571
+ k = gfps.ak.variables[0]
1572
+ self.coeff2 = sequence(gfps.ak.formula, (k, 0, oo))
1573
+
1574
+ @property
1575
+ def function(self):
1576
+ """Function of the product of two formal power series."""
1577
+ return self.f * self.g
1578
+
1579
+ def _eval_terms(self, n):
1580
+ """
1581
+ Returns the first ``n`` terms of the product formal power series.
1582
+ Term by term logic is implemented here.
1583
+
1584
+ Examples
1585
+ ========
1586
+
1587
+ >>> from sympy import fps, sin, exp
1588
+ >>> from sympy.abc import x
1589
+ >>> f1 = fps(sin(x))
1590
+ >>> f2 = fps(exp(x))
1591
+ >>> fprod = f1.product(f2, x)
1592
+
1593
+ >>> fprod._eval_terms(4)
1594
+ x**3/3 + x**2 + x
1595
+
1596
+ See Also
1597
+ ========
1598
+
1599
+ sympy.series.formal.FormalPowerSeries.product
1600
+
1601
+ """
1602
+ coeff1, coeff2 = self.coeff1, self.coeff2
1603
+
1604
+ aks = convolution(coeff1[:n], coeff2[:n])
1605
+
1606
+ terms = []
1607
+ for i in range(0, n):
1608
+ terms.append(aks[i] * self.ffps.xk.coeff(i))
1609
+
1610
+ return Add(*terms)
1611
+
1612
+
1613
+ class FormalPowerSeriesCompose(FiniteFormalPowerSeries):
1614
+ """
1615
+ Represents the composed formal power series of two functions.
1616
+
1617
+ Explanation
1618
+ ===========
1619
+
1620
+ No computation is performed. Terms are calculated using a term by term logic,
1621
+ instead of a point by point logic.
1622
+
1623
+ There are two differences between a :obj:`FormalPowerSeries` object and a
1624
+ :obj:`FormalPowerSeriesCompose` object. The first argument contains the outer
1625
+ function and the inner function involved in the omposition. Also, the
1626
+ coefficient sequence contains the generic sequence which is to be multiplied
1627
+ by a custom ``bell_seq`` finite sequence. The finite terms will then be added up to
1628
+ get the final terms.
1629
+
1630
+ See Also
1631
+ ========
1632
+
1633
+ sympy.series.formal.FormalPowerSeries
1634
+ sympy.series.formal.FiniteFormalPowerSeries
1635
+
1636
+ """
1637
+
1638
+ @property
1639
+ def function(self):
1640
+ """Function for the composed formal power series."""
1641
+ f, g, x = self.f, self.g, self.ffps.x
1642
+ return f.subs(x, g)
1643
+
1644
+ def _eval_terms(self, n):
1645
+ """
1646
+ Returns the first `n` terms of the composed formal power series.
1647
+ Term by term logic is implemented here.
1648
+
1649
+ Explanation
1650
+ ===========
1651
+
1652
+ The coefficient sequence of the :obj:`FormalPowerSeriesCompose` object is the generic sequence.
1653
+ It is multiplied by ``bell_seq`` to get a sequence, whose terms are added up to get
1654
+ the final terms for the polynomial.
1655
+
1656
+ Examples
1657
+ ========
1658
+
1659
+ >>> from sympy import fps, sin, exp
1660
+ >>> from sympy.abc import x
1661
+ >>> f1 = fps(exp(x))
1662
+ >>> f2 = fps(sin(x))
1663
+ >>> fcomp = f1.compose(f2, x)
1664
+
1665
+ >>> fcomp._eval_terms(6)
1666
+ -x**5/15 - x**4/8 + x**2/2 + x + 1
1667
+
1668
+ >>> fcomp._eval_terms(8)
1669
+ x**7/90 - x**6/240 - x**5/15 - x**4/8 + x**2/2 + x + 1
1670
+
1671
+ See Also
1672
+ ========
1673
+
1674
+ sympy.series.formal.FormalPowerSeries.compose
1675
+ sympy.series.formal.FormalPowerSeries.coeff_bell
1676
+
1677
+ """
1678
+
1679
+ ffps, gfps = self.ffps, self.gfps
1680
+ terms = [ffps.zero_coeff()]
1681
+
1682
+ for i in range(1, n):
1683
+ bell_seq = gfps.coeff_bell(i)
1684
+ seq = (ffps.bell_coeff_seq * bell_seq)
1685
+ terms.append(Add(*(seq[:i])) / ffps.fact_seq[i-1] * ffps.xk.coeff(i))
1686
+
1687
+ return Add(*terms)
1688
+
1689
+
1690
+ class FormalPowerSeriesInverse(FiniteFormalPowerSeries):
1691
+ """
1692
+ Represents the Inverse of a formal power series.
1693
+
1694
+ Explanation
1695
+ ===========
1696
+
1697
+ No computation is performed. Terms are calculated using a term by term logic,
1698
+ instead of a point by point logic.
1699
+
1700
+ There is a single difference between a :obj:`FormalPowerSeries` object and a
1701
+ :obj:`FormalPowerSeriesInverse` object. The coefficient sequence contains the
1702
+ generic sequence which is to be multiplied by a custom ``bell_seq`` finite sequence.
1703
+ The finite terms will then be added up to get the final terms.
1704
+
1705
+ See Also
1706
+ ========
1707
+
1708
+ sympy.series.formal.FormalPowerSeries
1709
+ sympy.series.formal.FiniteFormalPowerSeries
1710
+
1711
+ """
1712
+ def __init__(self, *args):
1713
+ ffps = self.ffps
1714
+ k = ffps.xk.variables[0]
1715
+
1716
+ inv = ffps.zero_coeff()
1717
+ inv_seq = sequence(inv ** (-(k + 1)), (k, 1, oo))
1718
+ self.aux_seq = ffps.sign_seq * ffps.fact_seq * inv_seq
1719
+
1720
+ @property
1721
+ def function(self):
1722
+ """Function for the inverse of a formal power series."""
1723
+ f = self.f
1724
+ return 1 / f
1725
+
1726
+ @property
1727
+ def g(self):
1728
+ raise ValueError("Only one function is considered while performing"
1729
+ "inverse of a formal power series.")
1730
+
1731
+ @property
1732
+ def gfps(self):
1733
+ raise ValueError("Only one function is considered while performing"
1734
+ "inverse of a formal power series.")
1735
+
1736
+ def _eval_terms(self, n):
1737
+ """
1738
+ Returns the first ``n`` terms of the composed formal power series.
1739
+ Term by term logic is implemented here.
1740
+
1741
+ Explanation
1742
+ ===========
1743
+
1744
+ The coefficient sequence of the `FormalPowerSeriesInverse` object is the generic sequence.
1745
+ It is multiplied by ``bell_seq`` to get a sequence, whose terms are added up to get
1746
+ the final terms for the polynomial.
1747
+
1748
+ Examples
1749
+ ========
1750
+
1751
+ >>> from sympy import fps, exp, cos
1752
+ >>> from sympy.abc import x
1753
+ >>> f1 = fps(exp(x))
1754
+ >>> f2 = fps(cos(x))
1755
+ >>> finv1, finv2 = f1.inverse(), f2.inverse()
1756
+
1757
+ >>> finv1._eval_terms(6)
1758
+ -x**5/120 + x**4/24 - x**3/6 + x**2/2 - x + 1
1759
+
1760
+ >>> finv2._eval_terms(8)
1761
+ 61*x**6/720 + 5*x**4/24 + x**2/2 + 1
1762
+
1763
+ See Also
1764
+ ========
1765
+
1766
+ sympy.series.formal.FormalPowerSeries.inverse
1767
+ sympy.series.formal.FormalPowerSeries.coeff_bell
1768
+
1769
+ """
1770
+ ffps = self.ffps
1771
+ terms = [ffps.zero_coeff()]
1772
+
1773
+ for i in range(1, n):
1774
+ bell_seq = ffps.coeff_bell(i)
1775
+ seq = (self.aux_seq * bell_seq)
1776
+ terms.append(Add(*(seq[:i])) / ffps.fact_seq[i-1] * ffps.xk.coeff(i))
1777
+
1778
+ return Add(*terms)
1779
+
1780
+
1781
+ def fps(f, x=None, x0=0, dir=1, hyper=True, order=4, rational=True, full=False):
1782
+ """
1783
+ Generates Formal Power Series of ``f``.
1784
+
1785
+ Explanation
1786
+ ===========
1787
+
1788
+ Returns the formal series expansion of ``f`` around ``x = x0``
1789
+ with respect to ``x`` in the form of a ``FormalPowerSeries`` object.
1790
+
1791
+ Formal Power Series is represented using an explicit formula
1792
+ computed using different algorithms.
1793
+
1794
+ See :func:`compute_fps` for the more details regarding the computation
1795
+ of formula.
1796
+
1797
+ Parameters
1798
+ ==========
1799
+
1800
+ x : Symbol, optional
1801
+ If x is None and ``f`` is univariate, the univariate symbols will be
1802
+ supplied, otherwise an error will be raised.
1803
+ x0 : number, optional
1804
+ Point to perform series expansion about. Default is 0.
1805
+ dir : {1, -1, '+', '-'}, optional
1806
+ If dir is 1 or '+' the series is calculated from the right and
1807
+ for -1 or '-' the series is calculated from the left. For smooth
1808
+ functions this flag will not alter the results. Default is 1.
1809
+ hyper : {True, False}, optional
1810
+ Set hyper to False to skip the hypergeometric algorithm.
1811
+ By default it is set to False.
1812
+ order : int, optional
1813
+ Order of the derivative of ``f``, Default is 4.
1814
+ rational : {True, False}, optional
1815
+ Set rational to False to skip rational algorithm. By default it is set
1816
+ to True.
1817
+ full : {True, False}, optional
1818
+ Set full to True to increase the range of rational algorithm.
1819
+ See :func:`rational_algorithm` for details. By default it is set to
1820
+ False.
1821
+
1822
+ Examples
1823
+ ========
1824
+
1825
+ >>> from sympy import fps, ln, atan, sin
1826
+ >>> from sympy.abc import x, n
1827
+
1828
+ Rational Functions
1829
+
1830
+ >>> fps(ln(1 + x)).truncate()
1831
+ x - x**2/2 + x**3/3 - x**4/4 + x**5/5 + O(x**6)
1832
+
1833
+ >>> fps(atan(x), full=True).truncate()
1834
+ x - x**3/3 + x**5/5 + O(x**6)
1835
+
1836
+ Symbolic Functions
1837
+
1838
+ >>> fps(x**n*sin(x**2), x).truncate(8)
1839
+ -x**(n + 6)/6 + x**(n + 2) + O(x**(n + 8))
1840
+
1841
+ See Also
1842
+ ========
1843
+
1844
+ sympy.series.formal.FormalPowerSeries
1845
+ sympy.series.formal.compute_fps
1846
+ """
1847
+ f = sympify(f)
1848
+
1849
+ if x is None:
1850
+ free = f.free_symbols
1851
+ if len(free) == 1:
1852
+ x = free.pop()
1853
+ elif not free:
1854
+ return f
1855
+ else:
1856
+ raise NotImplementedError("multivariate formal power series")
1857
+
1858
+ result = compute_fps(f, x, x0, dir, hyper, order, rational, full)
1859
+
1860
+ if result is None:
1861
+ return f
1862
+
1863
+ return FormalPowerSeries(f, x, x0, dir, result)
outputs/audit_venv/lib/python3.11/site-packages/sympy/series/fourier.py ADDED
@@ -0,0 +1,811 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Fourier Series"""
2
+
3
+ from sympy.core.numbers import (oo, pi)
4
+ from sympy.core.symbol import Wild
5
+ from sympy.core.expr import Expr
6
+ from sympy.core.add import Add
7
+ from sympy.core.containers import Tuple
8
+ from sympy.core.singleton import S
9
+ from sympy.core.symbol import Dummy, Symbol
10
+ from sympy.core.sympify import sympify
11
+ from sympy.functions.elementary.trigonometric import sin, cos, sinc
12
+ from sympy.series.series_class import SeriesBase
13
+ from sympy.series.sequences import SeqFormula
14
+ from sympy.sets.sets import Interval
15
+ from sympy.utilities.iterables import is_sequence
16
+
17
+
18
+ __doctest_requires__ = {('fourier_series',): ['matplotlib']}
19
+
20
+
21
+ def fourier_cos_seq(func, limits, n):
22
+ """Returns the cos sequence in a Fourier series"""
23
+ from sympy.integrals import integrate
24
+ x, L = limits[0], limits[2] - limits[1]
25
+ cos_term = cos(2*n*pi*x / L)
26
+ formula = 2 * cos_term * integrate(func * cos_term, limits) / L
27
+ a0 = formula.subs(n, S.Zero) / 2
28
+ return a0, SeqFormula(2 * cos_term * integrate(func * cos_term, limits)
29
+ / L, (n, 1, oo))
30
+
31
+
32
+ def fourier_sin_seq(func, limits, n):
33
+ """Returns the sin sequence in a Fourier series"""
34
+ from sympy.integrals import integrate
35
+ x, L = limits[0], limits[2] - limits[1]
36
+ sin_term = sin(2*n*pi*x / L)
37
+ return SeqFormula(2 * sin_term * integrate(func * sin_term, limits)
38
+ / L, (n, 1, oo))
39
+
40
+
41
+ def _process_limits(func, limits):
42
+ """
43
+ Limits should be of the form (x, start, stop).
44
+ x should be a symbol. Both start and stop should be bounded.
45
+
46
+ Explanation
47
+ ===========
48
+
49
+ * If x is not given, x is determined from func.
50
+ * If limits is None. Limit of the form (x, -pi, pi) is returned.
51
+
52
+ Examples
53
+ ========
54
+
55
+ >>> from sympy.series.fourier import _process_limits as pari
56
+ >>> from sympy.abc import x
57
+ >>> pari(x**2, (x, -2, 2))
58
+ (x, -2, 2)
59
+ >>> pari(x**2, (-2, 2))
60
+ (x, -2, 2)
61
+ >>> pari(x**2, None)
62
+ (x, -pi, pi)
63
+ """
64
+ def _find_x(func):
65
+ free = func.free_symbols
66
+ if len(free) == 1:
67
+ return free.pop()
68
+ elif not free:
69
+ return Dummy('k')
70
+ else:
71
+ raise ValueError(
72
+ " specify dummy variables for %s. If the function contains"
73
+ " more than one free symbol, a dummy variable should be"
74
+ " supplied explicitly e.g. FourierSeries(m*n**2, (n, -pi, pi))"
75
+ % func)
76
+
77
+ x, start, stop = None, None, None
78
+ if limits is None:
79
+ x, start, stop = _find_x(func), -pi, pi
80
+ if is_sequence(limits, Tuple):
81
+ if len(limits) == 3:
82
+ x, start, stop = limits
83
+ elif len(limits) == 2:
84
+ x = _find_x(func)
85
+ start, stop = limits
86
+
87
+ if not isinstance(x, Symbol) or start is None or stop is None:
88
+ raise ValueError('Invalid limits given: %s' % str(limits))
89
+
90
+ unbounded = [S.NegativeInfinity, S.Infinity]
91
+ if start in unbounded or stop in unbounded:
92
+ raise ValueError("Both the start and end value should be bounded")
93
+
94
+ return sympify((x, start, stop))
95
+
96
+
97
+ def finite_check(f, x, L):
98
+
99
+ def check_fx(exprs, x):
100
+ return x not in exprs.free_symbols
101
+
102
+ def check_sincos(_expr, x, L):
103
+ if isinstance(_expr, (sin, cos)):
104
+ sincos_args = _expr.args[0]
105
+
106
+ if sincos_args.match(a*(pi/L)*x + b) is not None:
107
+ return True
108
+ else:
109
+ return False
110
+
111
+ from sympy.simplify.fu import TR2, TR1, sincos_to_sum
112
+ _expr = sincos_to_sum(TR2(TR1(f)))
113
+ add_coeff = _expr.as_coeff_add()
114
+
115
+ a = Wild('a', properties=[lambda k: k.is_Integer, lambda k: k != S.Zero, ])
116
+ b = Wild('b', properties=[lambda k: x not in k.free_symbols, ])
117
+
118
+ for s in add_coeff[1]:
119
+ mul_coeffs = s.as_coeff_mul()[1]
120
+ for t in mul_coeffs:
121
+ if not (check_fx(t, x) or check_sincos(t, x, L)):
122
+ return False, f
123
+
124
+ return True, _expr
125
+
126
+
127
+ class FourierSeries(SeriesBase):
128
+ r"""Represents Fourier sine/cosine series.
129
+
130
+ Explanation
131
+ ===========
132
+
133
+ This class only represents a fourier series.
134
+ No computation is performed.
135
+
136
+ For how to compute Fourier series, see the :func:`fourier_series`
137
+ docstring.
138
+
139
+ See Also
140
+ ========
141
+
142
+ sympy.series.fourier.fourier_series
143
+ """
144
+ def __new__(cls, *args):
145
+ args = map(sympify, args)
146
+ return Expr.__new__(cls, *args)
147
+
148
+ @property
149
+ def function(self):
150
+ return self.args[0]
151
+
152
+ @property
153
+ def x(self):
154
+ return self.args[1][0]
155
+
156
+ @property
157
+ def period(self):
158
+ return (self.args[1][1], self.args[1][2])
159
+
160
+ @property
161
+ def a0(self):
162
+ return self.args[2][0]
163
+
164
+ @property
165
+ def an(self):
166
+ return self.args[2][1]
167
+
168
+ @property
169
+ def bn(self):
170
+ return self.args[2][2]
171
+
172
+ @property
173
+ def interval(self):
174
+ return Interval(0, oo)
175
+
176
+ @property
177
+ def start(self):
178
+ return self.interval.inf
179
+
180
+ @property
181
+ def stop(self):
182
+ return self.interval.sup
183
+
184
+ @property
185
+ def length(self):
186
+ return oo
187
+
188
+ @property
189
+ def L(self):
190
+ return abs(self.period[1] - self.period[0]) / 2
191
+
192
+ def _eval_subs(self, old, new):
193
+ x = self.x
194
+ if old.has(x):
195
+ return self
196
+
197
+ def truncate(self, n=3):
198
+ """
199
+ Return the first n nonzero terms of the series.
200
+
201
+ If ``n`` is None return an iterator.
202
+
203
+ Parameters
204
+ ==========
205
+
206
+ n : int or None
207
+ Amount of non-zero terms in approximation or None.
208
+
209
+ Returns
210
+ =======
211
+
212
+ Expr or iterator :
213
+ Approximation of function expanded into Fourier series.
214
+
215
+ Examples
216
+ ========
217
+
218
+ >>> from sympy import fourier_series, pi
219
+ >>> from sympy.abc import x
220
+ >>> s = fourier_series(x, (x, -pi, pi))
221
+ >>> s.truncate(4)
222
+ 2*sin(x) - sin(2*x) + 2*sin(3*x)/3 - sin(4*x)/2
223
+
224
+ See Also
225
+ ========
226
+
227
+ sympy.series.fourier.FourierSeries.sigma_approximation
228
+ """
229
+ if n is None:
230
+ return iter(self)
231
+
232
+ terms = []
233
+ for t in self:
234
+ if len(terms) == n:
235
+ break
236
+ if t is not S.Zero:
237
+ terms.append(t)
238
+
239
+ return Add(*terms)
240
+
241
+ def sigma_approximation(self, n=3):
242
+ r"""
243
+ Return :math:`\sigma`-approximation of Fourier series with respect
244
+ to order n.
245
+
246
+ Explanation
247
+ ===========
248
+
249
+ Sigma approximation adjusts a Fourier summation to eliminate the Gibbs
250
+ phenomenon which would otherwise occur at discontinuities.
251
+ A sigma-approximated summation for a Fourier series of a T-periodical
252
+ function can be written as
253
+
254
+ .. math::
255
+ s(\theta) = \frac{1}{2} a_0 + \sum _{k=1}^{m-1}
256
+ \operatorname{sinc} \Bigl( \frac{k}{m} \Bigr) \cdot
257
+ \left[ a_k \cos \Bigl( \frac{2\pi k}{T} \theta \Bigr)
258
+ + b_k \sin \Bigl( \frac{2\pi k}{T} \theta \Bigr) \right],
259
+
260
+ where :math:`a_0, a_k, b_k, k=1,\ldots,{m-1}` are standard Fourier
261
+ series coefficients and
262
+ :math:`\operatorname{sinc} \Bigl( \frac{k}{m} \Bigr)` is a Lanczos
263
+ :math:`\sigma` factor (expressed in terms of normalized
264
+ :math:`\operatorname{sinc}` function).
265
+
266
+ Parameters
267
+ ==========
268
+
269
+ n : int
270
+ Highest order of the terms taken into account in approximation.
271
+
272
+ Returns
273
+ =======
274
+
275
+ Expr :
276
+ Sigma approximation of function expanded into Fourier series.
277
+
278
+ Examples
279
+ ========
280
+
281
+ >>> from sympy import fourier_series, pi
282
+ >>> from sympy.abc import x
283
+ >>> s = fourier_series(x, (x, -pi, pi))
284
+ >>> s.sigma_approximation(4)
285
+ 2*sin(x)*sinc(pi/4) - 2*sin(2*x)/pi + 2*sin(3*x)*sinc(3*pi/4)/3
286
+
287
+ See Also
288
+ ========
289
+
290
+ sympy.series.fourier.FourierSeries.truncate
291
+
292
+ Notes
293
+ =====
294
+
295
+ The behaviour of
296
+ :meth:`~sympy.series.fourier.FourierSeries.sigma_approximation`
297
+ is different from :meth:`~sympy.series.fourier.FourierSeries.truncate`
298
+ - it takes all nonzero terms of degree smaller than n, rather than
299
+ first n nonzero ones.
300
+
301
+ References
302
+ ==========
303
+
304
+ .. [1] https://en.wikipedia.org/wiki/Gibbs_phenomenon
305
+ .. [2] https://en.wikipedia.org/wiki/Sigma_approximation
306
+ """
307
+ terms = [sinc(pi * i / n) * t for i, t in enumerate(self[:n])
308
+ if t is not S.Zero]
309
+ return Add(*terms)
310
+
311
+ def shift(self, s):
312
+ """
313
+ Shift the function by a term independent of x.
314
+
315
+ Explanation
316
+ ===========
317
+
318
+ f(x) -> f(x) + s
319
+
320
+ This is fast, if Fourier series of f(x) is already
321
+ computed.
322
+
323
+ Examples
324
+ ========
325
+
326
+ >>> from sympy import fourier_series, pi
327
+ >>> from sympy.abc import x
328
+ >>> s = fourier_series(x**2, (x, -pi, pi))
329
+ >>> s.shift(1).truncate()
330
+ -4*cos(x) + cos(2*x) + 1 + pi**2/3
331
+ """
332
+ s, x = sympify(s), self.x
333
+
334
+ if x in s.free_symbols:
335
+ raise ValueError("'%s' should be independent of %s" % (s, x))
336
+
337
+ a0 = self.a0 + s
338
+ sfunc = self.function + s
339
+
340
+ return self.func(sfunc, self.args[1], (a0, self.an, self.bn))
341
+
342
+ def shiftx(self, s):
343
+ """
344
+ Shift x by a term independent of x.
345
+
346
+ Explanation
347
+ ===========
348
+
349
+ f(x) -> f(x + s)
350
+
351
+ This is fast, if Fourier series of f(x) is already
352
+ computed.
353
+
354
+ Examples
355
+ ========
356
+
357
+ >>> from sympy import fourier_series, pi
358
+ >>> from sympy.abc import x
359
+ >>> s = fourier_series(x**2, (x, -pi, pi))
360
+ >>> s.shiftx(1).truncate()
361
+ -4*cos(x + 1) + cos(2*x + 2) + pi**2/3
362
+ """
363
+ s, x = sympify(s), self.x
364
+
365
+ if x in s.free_symbols:
366
+ raise ValueError("'%s' should be independent of %s" % (s, x))
367
+
368
+ an = self.an.subs(x, x + s)
369
+ bn = self.bn.subs(x, x + s)
370
+ sfunc = self.function.subs(x, x + s)
371
+
372
+ return self.func(sfunc, self.args[1], (self.a0, an, bn))
373
+
374
+ def scale(self, s):
375
+ """
376
+ Scale the function by a term independent of x.
377
+
378
+ Explanation
379
+ ===========
380
+
381
+ f(x) -> s * f(x)
382
+
383
+ This is fast, if Fourier series of f(x) is already
384
+ computed.
385
+
386
+ Examples
387
+ ========
388
+
389
+ >>> from sympy import fourier_series, pi
390
+ >>> from sympy.abc import x
391
+ >>> s = fourier_series(x**2, (x, -pi, pi))
392
+ >>> s.scale(2).truncate()
393
+ -8*cos(x) + 2*cos(2*x) + 2*pi**2/3
394
+ """
395
+ s, x = sympify(s), self.x
396
+
397
+ if x in s.free_symbols:
398
+ raise ValueError("'%s' should be independent of %s" % (s, x))
399
+
400
+ an = self.an.coeff_mul(s)
401
+ bn = self.bn.coeff_mul(s)
402
+ a0 = self.a0 * s
403
+ sfunc = self.args[0] * s
404
+
405
+ return self.func(sfunc, self.args[1], (a0, an, bn))
406
+
407
+ def scalex(self, s):
408
+ """
409
+ Scale x by a term independent of x.
410
+
411
+ Explanation
412
+ ===========
413
+
414
+ f(x) -> f(s*x)
415
+
416
+ This is fast, if Fourier series of f(x) is already
417
+ computed.
418
+
419
+ Examples
420
+ ========
421
+
422
+ >>> from sympy import fourier_series, pi
423
+ >>> from sympy.abc import x
424
+ >>> s = fourier_series(x**2, (x, -pi, pi))
425
+ >>> s.scalex(2).truncate()
426
+ -4*cos(2*x) + cos(4*x) + pi**2/3
427
+ """
428
+ s, x = sympify(s), self.x
429
+
430
+ if x in s.free_symbols:
431
+ raise ValueError("'%s' should be independent of %s" % (s, x))
432
+
433
+ an = self.an.subs(x, x * s)
434
+ bn = self.bn.subs(x, x * s)
435
+ sfunc = self.function.subs(x, x * s)
436
+
437
+ return self.func(sfunc, self.args[1], (self.a0, an, bn))
438
+
439
+ def _eval_as_leading_term(self, x, logx, cdir):
440
+ for t in self:
441
+ if t is not S.Zero:
442
+ return t
443
+
444
+ def _eval_term(self, pt):
445
+ if pt == 0:
446
+ return self.a0
447
+ return self.an.coeff(pt) + self.bn.coeff(pt)
448
+
449
+ def __neg__(self):
450
+ return self.scale(-1)
451
+
452
+ def __add__(self, other):
453
+ if isinstance(other, FourierSeries):
454
+ if self.period != other.period:
455
+ raise ValueError("Both the series should have same periods")
456
+
457
+ x, y = self.x, other.x
458
+ function = self.function + other.function.subs(y, x)
459
+
460
+ if self.x not in function.free_symbols:
461
+ return function
462
+
463
+ an = self.an + other.an
464
+ bn = self.bn + other.bn
465
+ a0 = self.a0 + other.a0
466
+
467
+ return self.func(function, self.args[1], (a0, an, bn))
468
+
469
+ return Add(self, other)
470
+
471
+ def __sub__(self, other):
472
+ return self.__add__(-other)
473
+
474
+
475
+ class FiniteFourierSeries(FourierSeries):
476
+ r"""Represents Finite Fourier sine/cosine series.
477
+
478
+ For how to compute Fourier series, see the :func:`fourier_series`
479
+ docstring.
480
+
481
+ Parameters
482
+ ==========
483
+
484
+ f : Expr
485
+ Expression for finding fourier_series
486
+
487
+ limits : ( x, start, stop)
488
+ x is the independent variable for the expression f
489
+ (start, stop) is the period of the fourier series
490
+
491
+ exprs: (a0, an, bn) or Expr
492
+ a0 is the constant term a0 of the fourier series
493
+ an is a dictionary of coefficients of cos terms
494
+ an[k] = coefficient of cos(pi*(k/L)*x)
495
+ bn is a dictionary of coefficients of sin terms
496
+ bn[k] = coefficient of sin(pi*(k/L)*x)
497
+
498
+ or exprs can be an expression to be converted to fourier form
499
+
500
+ Methods
501
+ =======
502
+
503
+ This class is an extension of FourierSeries class.
504
+ Please refer to sympy.series.fourier.FourierSeries for
505
+ further information.
506
+
507
+ See Also
508
+ ========
509
+
510
+ sympy.series.fourier.FourierSeries
511
+ sympy.series.fourier.fourier_series
512
+ """
513
+
514
+ def __new__(cls, f, limits, exprs):
515
+ f = sympify(f)
516
+ limits = sympify(limits)
517
+ exprs = sympify(exprs)
518
+
519
+ if not (isinstance(exprs, Tuple) and len(exprs) == 3): # exprs is not of form (a0, an, bn)
520
+ # Converts the expression to fourier form
521
+ c, e = exprs.as_coeff_add()
522
+ from sympy.simplify.fu import TR10
523
+ rexpr = c + Add(*[TR10(i) for i in e])
524
+ a0, exp_ls = rexpr.expand(trig=False, power_base=False, power_exp=False, log=False).as_coeff_add()
525
+
526
+ x = limits[0]
527
+ L = abs(limits[2] - limits[1]) / 2
528
+
529
+ a = Wild('a', properties=[lambda k: k.is_Integer, lambda k: k is not S.Zero, ])
530
+ b = Wild('b', properties=[lambda k: x not in k.free_symbols, ])
531
+
532
+ an = {}
533
+ bn = {}
534
+
535
+ # separates the coefficients of sin and cos terms in dictionaries an, and bn
536
+ for p in exp_ls:
537
+ t = p.match(b * cos(a * (pi / L) * x))
538
+ q = p.match(b * sin(a * (pi / L) * x))
539
+ if t:
540
+ an[t[a]] = t[b] + an.get(t[a], S.Zero)
541
+ elif q:
542
+ bn[q[a]] = q[b] + bn.get(q[a], S.Zero)
543
+ else:
544
+ a0 += p
545
+
546
+ exprs = Tuple(a0, an, bn)
547
+
548
+ return Expr.__new__(cls, f, limits, exprs)
549
+
550
+ @property
551
+ def interval(self):
552
+ _length = 1 if self.a0 else 0
553
+ _length += max(set(self.an.keys()).union(set(self.bn.keys()))) + 1
554
+ return Interval(0, _length)
555
+
556
+ @property
557
+ def length(self):
558
+ return self.stop - self.start
559
+
560
+ def shiftx(self, s):
561
+ s, x = sympify(s), self.x
562
+
563
+ if x in s.free_symbols:
564
+ raise ValueError("'%s' should be independent of %s" % (s, x))
565
+
566
+ _expr = self.truncate().subs(x, x + s)
567
+ sfunc = self.function.subs(x, x + s)
568
+
569
+ return self.func(sfunc, self.args[1], _expr)
570
+
571
+ def scale(self, s):
572
+ s, x = sympify(s), self.x
573
+
574
+ if x in s.free_symbols:
575
+ raise ValueError("'%s' should be independent of %s" % (s, x))
576
+
577
+ _expr = self.truncate() * s
578
+ sfunc = self.function * s
579
+
580
+ return self.func(sfunc, self.args[1], _expr)
581
+
582
+ def scalex(self, s):
583
+ s, x = sympify(s), self.x
584
+
585
+ if x in s.free_symbols:
586
+ raise ValueError("'%s' should be independent of %s" % (s, x))
587
+
588
+ _expr = self.truncate().subs(x, x * s)
589
+ sfunc = self.function.subs(x, x * s)
590
+
591
+ return self.func(sfunc, self.args[1], _expr)
592
+
593
+ def _eval_term(self, pt):
594
+ if pt == 0:
595
+ return self.a0
596
+
597
+ _term = self.an.get(pt, S.Zero) * cos(pt * (pi / self.L) * self.x) \
598
+ + self.bn.get(pt, S.Zero) * sin(pt * (pi / self.L) * self.x)
599
+ return _term
600
+
601
+ def __add__(self, other):
602
+ if isinstance(other, FourierSeries):
603
+ return other.__add__(fourier_series(self.function, self.args[1],\
604
+ finite=False))
605
+ elif isinstance(other, FiniteFourierSeries):
606
+ if self.period != other.period:
607
+ raise ValueError("Both the series should have same periods")
608
+
609
+ x, y = self.x, other.x
610
+ function = self.function + other.function.subs(y, x)
611
+
612
+ if self.x not in function.free_symbols:
613
+ return function
614
+
615
+ return fourier_series(function, limits=self.args[1])
616
+
617
+
618
+ def fourier_series(f, limits=None, finite=True):
619
+ r"""Computes the Fourier trigonometric series expansion.
620
+
621
+ Explanation
622
+ ===========
623
+
624
+ Fourier trigonometric series of $f(x)$ over the interval $(a, b)$
625
+ is defined as:
626
+
627
+ .. math::
628
+ \frac{a_0}{2} + \sum_{n=1}^{\infty}
629
+ (a_n \cos(\frac{2n \pi x}{L}) + b_n \sin(\frac{2n \pi x}{L}))
630
+
631
+ where the coefficients are:
632
+
633
+ .. math::
634
+ L = b - a
635
+
636
+ .. math::
637
+ a_0 = \frac{2}{L} \int_{a}^{b}{f(x) dx}
638
+
639
+ .. math::
640
+ a_n = \frac{2}{L} \int_{a}^{b}{f(x) \cos(\frac{2n \pi x}{L}) dx}
641
+
642
+ .. math::
643
+ b_n = \frac{2}{L} \int_{a}^{b}{f(x) \sin(\frac{2n \pi x}{L}) dx}
644
+
645
+ The condition whether the function $f(x)$ given should be periodic
646
+ or not is more than necessary, because it is sufficient to consider
647
+ the series to be converging to $f(x)$ only in the given interval,
648
+ not throughout the whole real line.
649
+
650
+ This also brings a lot of ease for the computation because
651
+ you do not have to make $f(x)$ artificially periodic by
652
+ wrapping it with piecewise, modulo operations,
653
+ but you can shape the function to look like the desired periodic
654
+ function only in the interval $(a, b)$, and the computed series will
655
+ automatically become the series of the periodic version of $f(x)$.
656
+
657
+ This property is illustrated in the examples section below.
658
+
659
+ Parameters
660
+ ==========
661
+
662
+ limits : (sym, start, end), optional
663
+ *sym* denotes the symbol the series is computed with respect to.
664
+
665
+ *start* and *end* denotes the start and the end of the interval
666
+ where the fourier series converges to the given function.
667
+
668
+ Default range is specified as $-\pi$ and $\pi$.
669
+
670
+ Returns
671
+ =======
672
+
673
+ FourierSeries
674
+ A symbolic object representing the Fourier trigonometric series.
675
+
676
+ Examples
677
+ ========
678
+
679
+ Computing the Fourier series of $f(x) = x^2$:
680
+
681
+ >>> from sympy import fourier_series, pi
682
+ >>> from sympy.abc import x
683
+ >>> f = x**2
684
+ >>> s = fourier_series(f, (x, -pi, pi))
685
+ >>> s1 = s.truncate(n=3)
686
+ >>> s1
687
+ -4*cos(x) + cos(2*x) + pi**2/3
688
+
689
+ Shifting of the Fourier series:
690
+
691
+ >>> s.shift(1).truncate()
692
+ -4*cos(x) + cos(2*x) + 1 + pi**2/3
693
+ >>> s.shiftx(1).truncate()
694
+ -4*cos(x + 1) + cos(2*x + 2) + pi**2/3
695
+
696
+ Scaling of the Fourier series:
697
+
698
+ >>> s.scale(2).truncate()
699
+ -8*cos(x) + 2*cos(2*x) + 2*pi**2/3
700
+ >>> s.scalex(2).truncate()
701
+ -4*cos(2*x) + cos(4*x) + pi**2/3
702
+
703
+ Computing the Fourier series of $f(x) = x$:
704
+
705
+ This illustrates how truncating to the higher order gives better
706
+ convergence.
707
+
708
+ .. plot::
709
+ :context: reset
710
+ :format: doctest
711
+ :include-source: True
712
+
713
+ >>> from sympy import fourier_series, pi, plot
714
+ >>> from sympy.abc import x
715
+ >>> f = x
716
+ >>> s = fourier_series(f, (x, -pi, pi))
717
+ >>> s1 = s.truncate(n = 3)
718
+ >>> s2 = s.truncate(n = 5)
719
+ >>> s3 = s.truncate(n = 7)
720
+ >>> p = plot(f, s1, s2, s3, (x, -pi, pi), show=False, legend=True)
721
+
722
+ >>> p[0].line_color = (0, 0, 0)
723
+ >>> p[0].label = 'x'
724
+ >>> p[1].line_color = (0.7, 0.7, 0.7)
725
+ >>> p[1].label = 'n=3'
726
+ >>> p[2].line_color = (0.5, 0.5, 0.5)
727
+ >>> p[2].label = 'n=5'
728
+ >>> p[3].line_color = (0.3, 0.3, 0.3)
729
+ >>> p[3].label = 'n=7'
730
+
731
+ >>> p.show()
732
+
733
+ This illustrates how the series converges to different sawtooth
734
+ waves if the different ranges are specified.
735
+
736
+ .. plot::
737
+ :context: close-figs
738
+ :format: doctest
739
+ :include-source: True
740
+
741
+ >>> s1 = fourier_series(x, (x, -1, 1)).truncate(10)
742
+ >>> s2 = fourier_series(x, (x, -pi, pi)).truncate(10)
743
+ >>> s3 = fourier_series(x, (x, 0, 1)).truncate(10)
744
+ >>> p = plot(x, s1, s2, s3, (x, -5, 5), show=False, legend=True)
745
+
746
+ >>> p[0].line_color = (0, 0, 0)
747
+ >>> p[0].label = 'x'
748
+ >>> p[1].line_color = (0.7, 0.7, 0.7)
749
+ >>> p[1].label = '[-1, 1]'
750
+ >>> p[2].line_color = (0.5, 0.5, 0.5)
751
+ >>> p[2].label = '[-pi, pi]'
752
+ >>> p[3].line_color = (0.3, 0.3, 0.3)
753
+ >>> p[3].label = '[0, 1]'
754
+
755
+ >>> p.show()
756
+
757
+ Notes
758
+ =====
759
+
760
+ Computing Fourier series can be slow
761
+ due to the integration required in computing
762
+ an, bn.
763
+
764
+ It is faster to compute Fourier series of a function
765
+ by using shifting and scaling on an already
766
+ computed Fourier series rather than computing
767
+ again.
768
+
769
+ e.g. If the Fourier series of ``x**2`` is known
770
+ the Fourier series of ``x**2 - 1`` can be found by shifting by ``-1``.
771
+
772
+ See Also
773
+ ========
774
+
775
+ sympy.series.fourier.FourierSeries
776
+
777
+ References
778
+ ==========
779
+
780
+ .. [1] https://mathworld.wolfram.com/FourierSeries.html
781
+ """
782
+ f = sympify(f)
783
+
784
+ limits = _process_limits(f, limits)
785
+ x = limits[0]
786
+
787
+ if x not in f.free_symbols:
788
+ return f
789
+
790
+ if finite:
791
+ L = abs(limits[2] - limits[1]) / 2
792
+ is_finite, res_f = finite_check(f, x, L)
793
+ if is_finite:
794
+ return FiniteFourierSeries(f, limits, res_f)
795
+
796
+ n = Dummy('n')
797
+ center = (limits[1] + limits[2]) / 2
798
+ if center.is_zero:
799
+ neg_f = f.subs(x, -x)
800
+ if f == neg_f:
801
+ a0, an = fourier_cos_seq(f, limits, n)
802
+ bn = SeqFormula(0, (1, oo))
803
+ return FourierSeries(f, limits, (a0, an, bn))
804
+ elif f == -neg_f:
805
+ a0 = S.Zero
806
+ an = SeqFormula(0, (1, oo))
807
+ bn = fourier_sin_seq(f, limits, n)
808
+ return FourierSeries(f, limits, (a0, an, bn))
809
+ a0, an = fourier_cos_seq(f, limits, n)
810
+ bn = fourier_sin_seq(f, limits, n)
811
+ return FourierSeries(f, limits, (a0, an, bn))
outputs/audit_venv/lib/python3.11/site-packages/sympy/series/gruntz.py ADDED
@@ -0,0 +1,701 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Limits
3
+ ======
4
+
5
+ Implemented according to the PhD thesis
6
+ https://www.cybertester.com/data/gruntz.pdf, which contains very thorough
7
+ descriptions of the algorithm including many examples. We summarize here
8
+ the gist of it.
9
+
10
+ All functions are sorted according to how rapidly varying they are at
11
+ infinity using the following rules. Any two functions f and g can be
12
+ compared using the properties of L:
13
+
14
+ L=lim log|f(x)| / log|g(x)| (for x -> oo)
15
+
16
+ We define >, < ~ according to::
17
+
18
+ 1. f > g .... L=+-oo
19
+
20
+ we say that:
21
+ - f is greater than any power of g
22
+ - f is more rapidly varying than g
23
+ - f goes to infinity/zero faster than g
24
+
25
+ 2. f < g .... L=0
26
+
27
+ we say that:
28
+ - f is lower than any power of g
29
+
30
+ 3. f ~ g .... L!=0, +-oo
31
+
32
+ we say that:
33
+ - both f and g are bounded from above and below by suitable integral
34
+ powers of the other
35
+
36
+ Examples
37
+ ========
38
+ ::
39
+ 2 < x < exp(x) < exp(x**2) < exp(exp(x))
40
+ 2 ~ 3 ~ -5
41
+ x ~ x**2 ~ x**3 ~ 1/x ~ x**m ~ -x
42
+ exp(x) ~ exp(-x) ~ exp(2x) ~ exp(x)**2 ~ exp(x+exp(-x))
43
+ f ~ 1/f
44
+
45
+ So we can divide all the functions into comparability classes (x and x^2
46
+ belong to one class, exp(x) and exp(-x) belong to some other class). In
47
+ principle, we could compare any two functions, but in our algorithm, we
48
+ do not compare anything below the class 2~3~-5 (for example log(x) is
49
+ below this), so we set 2~3~-5 as the lowest comparability class.
50
+
51
+ Given the function f, we find the list of most rapidly varying (mrv set)
52
+ subexpressions of it. This list belongs to the same comparability class.
53
+ Let's say it is {exp(x), exp(2x)}. Using the rule f ~ 1/f we find an
54
+ element "w" (either from the list or a new one) from the same
55
+ comparability class which goes to zero at infinity. In our example we
56
+ set w=exp(-x) (but we could also set w=exp(-2x) or w=exp(-3x) ...). We
57
+ rewrite the mrv set using w, in our case {1/w, 1/w^2}, and substitute it
58
+ into f. Then we expand f into a series in w::
59
+
60
+ f = c0*w^e0 + c1*w^e1 + ... + O(w^en), where e0<e1<...<en, c0!=0
61
+
62
+ but for x->oo, lim f = lim c0*w^e0, because all the other terms go to zero,
63
+ because w goes to zero faster than the ci and ei. So::
64
+
65
+ for e0>0, lim f = 0
66
+ for e0<0, lim f = +-oo (the sign depends on the sign of c0)
67
+ for e0=0, lim f = lim c0
68
+
69
+ We need to recursively compute limits at several places of the algorithm, but
70
+ as is shown in the PhD thesis, it always finishes.
71
+
72
+ Important functions from the implementation:
73
+
74
+ compare(a, b, x) compares "a" and "b" by computing the limit L.
75
+ mrv(e, x) returns list of most rapidly varying (mrv) subexpressions of "e"
76
+ rewrite(e, Omega, x, wsym) rewrites "e" in terms of w
77
+ leadterm(f, x) returns the lowest power term in the series of f
78
+ mrv_leadterm(e, x) returns the lead term (c0, e0) for e
79
+ limitinf(e, x) computes lim e (for x->oo)
80
+ limit(e, z, z0) computes any limit by converting it to the case x->oo
81
+
82
+ All the functions are really simple and straightforward except
83
+ rewrite(), which is the most difficult/complex part of the algorithm.
84
+ When the algorithm fails, the bugs are usually in the series expansion
85
+ (i.e. in SymPy) or in rewrite.
86
+
87
+ This code is almost exact rewrite of the Maple code inside the Gruntz
88
+ thesis.
89
+
90
+ Debugging
91
+ ---------
92
+
93
+ Because the gruntz algorithm is highly recursive, it's difficult to
94
+ figure out what went wrong inside a debugger. Instead, turn on nice
95
+ debug prints by defining the environment variable SYMPY_DEBUG. For
96
+ example:
97
+
98
+ [user@localhost]: SYMPY_DEBUG=True ./bin/isympy
99
+
100
+ In [1]: limit(sin(x)/x, x, 0)
101
+ limitinf(_x*sin(1/_x), _x) = 1
102
+ +-mrv_leadterm(_x*sin(1/_x), _x) = (1, 0)
103
+ | +-mrv(_x*sin(1/_x), _x) = set([_x])
104
+ | | +-mrv(_x, _x) = set([_x])
105
+ | | +-mrv(sin(1/_x), _x) = set([_x])
106
+ | | +-mrv(1/_x, _x) = set([_x])
107
+ | | +-mrv(_x, _x) = set([_x])
108
+ | +-mrv_leadterm(exp(_x)*sin(exp(-_x)), _x, set([exp(_x)])) = (1, 0)
109
+ | +-rewrite(exp(_x)*sin(exp(-_x)), set([exp(_x)]), _x, _w) = (1/_w*sin(_w), -_x)
110
+ | +-sign(_x, _x) = 1
111
+ | +-mrv_leadterm(1, _x) = (1, 0)
112
+ +-sign(0, _x) = 0
113
+ +-limitinf(1, _x) = 1
114
+
115
+ And check manually which line is wrong. Then go to the source code and
116
+ debug this function to figure out the exact problem.
117
+
118
+ """
119
+ from functools import reduce
120
+
121
+ from sympy.core import Basic, S, Mul, PoleError
122
+ from sympy.core.cache import cacheit
123
+ from sympy.core.function import AppliedUndef
124
+ from sympy.core.intfunc import ilcm
125
+ from sympy.core.numbers import I, oo
126
+ from sympy.core.symbol import Dummy, Wild
127
+ from sympy.core.traversal import bottom_up
128
+
129
+ from sympy.functions import log, exp, sign as _sign
130
+ from sympy.series.order import Order
131
+ from sympy.utilities.misc import debug_decorator as debug
132
+ from sympy.utilities.timeutils import timethis
133
+
134
+ timeit = timethis('gruntz')
135
+
136
+
137
+ def compare(a, b, x):
138
+ """Returns "<" if a<b, "=" for a == b, ">" for a>b"""
139
+ # log(exp(...)) must always be simplified here for termination
140
+ la, lb = log(a), log(b)
141
+ if isinstance(a, Basic) and (isinstance(a, exp) or (a.is_Pow and a.base == S.Exp1)):
142
+ la = a.exp
143
+ if isinstance(b, Basic) and (isinstance(b, exp) or (b.is_Pow and b.base == S.Exp1)):
144
+ lb = b.exp
145
+
146
+ c = limitinf(la/lb, x)
147
+ if c == 0:
148
+ return "<"
149
+ elif c.is_infinite:
150
+ return ">"
151
+ else:
152
+ return "="
153
+
154
+
155
+ class SubsSet(dict):
156
+ """
157
+ Stores (expr, dummy) pairs, and how to rewrite expr-s.
158
+
159
+ Explanation
160
+ ===========
161
+
162
+ The gruntz algorithm needs to rewrite certain expressions in term of a new
163
+ variable w. We cannot use subs, because it is just too smart for us. For
164
+ example::
165
+
166
+ > Omega=[exp(exp(_p - exp(-_p))/(1 - 1/_p)), exp(exp(_p))]
167
+ > O2=[exp(-exp(_p) + exp(-exp(-_p))*exp(_p)/(1 - 1/_p))/_w, 1/_w]
168
+ > e = exp(exp(_p - exp(-_p))/(1 - 1/_p)) - exp(exp(_p))
169
+ > e.subs(Omega[0],O2[0]).subs(Omega[1],O2[1])
170
+ -1/w + exp(exp(p)*exp(-exp(-p))/(1 - 1/p))
171
+
172
+ is really not what we want!
173
+
174
+ So we do it the hard way and keep track of all the things we potentially
175
+ want to substitute by dummy variables. Consider the expression::
176
+
177
+ exp(x - exp(-x)) + exp(x) + x.
178
+
179
+ The mrv set is {exp(x), exp(-x), exp(x - exp(-x))}.
180
+ We introduce corresponding dummy variables d1, d2, d3 and rewrite::
181
+
182
+ d3 + d1 + x.
183
+
184
+ This class first of all keeps track of the mapping expr->variable, i.e.
185
+ will at this stage be a dictionary::
186
+
187
+ {exp(x): d1, exp(-x): d2, exp(x - exp(-x)): d3}.
188
+
189
+ [It turns out to be more convenient this way round.]
190
+ But sometimes expressions in the mrv set have other expressions from the
191
+ mrv set as subexpressions, and we need to keep track of that as well. In
192
+ this case, d3 is really exp(x - d2), so rewrites at this stage is::
193
+
194
+ {d3: exp(x-d2)}.
195
+
196
+ The function rewrite uses all this information to correctly rewrite our
197
+ expression in terms of w. In this case w can be chosen to be exp(-x),
198
+ i.e. d2. The correct rewriting then is::
199
+
200
+ exp(-w)/w + 1/w + x.
201
+ """
202
+ def __init__(self):
203
+ self.rewrites = {}
204
+
205
+ def __repr__(self):
206
+ return super().__repr__() + ', ' + self.rewrites.__repr__()
207
+
208
+ def __getitem__(self, key):
209
+ if key not in self:
210
+ self[key] = Dummy()
211
+ return dict.__getitem__(self, key)
212
+
213
+ def do_subs(self, e):
214
+ """Substitute the variables with expressions"""
215
+ for expr, var in self.items():
216
+ e = e.xreplace({var: expr})
217
+ return e
218
+
219
+ def meets(self, s2):
220
+ """Tell whether or not self and s2 have non-empty intersection"""
221
+ return set(self.keys()).intersection(list(s2.keys())) != set()
222
+
223
+ def union(self, s2, exps=None):
224
+ """Compute the union of self and s2, adjusting exps"""
225
+ res = self.copy()
226
+ tr = {}
227
+ for expr, var in s2.items():
228
+ if expr in self:
229
+ if exps:
230
+ exps = exps.xreplace({var: res[expr]})
231
+ tr[var] = res[expr]
232
+ else:
233
+ res[expr] = var
234
+ for var, rewr in s2.rewrites.items():
235
+ res.rewrites[var] = rewr.xreplace(tr)
236
+ return res, exps
237
+
238
+ def copy(self):
239
+ """Create a shallow copy of SubsSet"""
240
+ r = SubsSet()
241
+ r.rewrites = self.rewrites.copy()
242
+ for expr, var in self.items():
243
+ r[expr] = var
244
+ return r
245
+
246
+
247
+ @debug
248
+ def mrv(e, x):
249
+ """Returns a SubsSet of most rapidly varying (mrv) subexpressions of 'e',
250
+ and e rewritten in terms of these"""
251
+ from sympy.simplify.powsimp import powsimp
252
+ e = powsimp(e, deep=True, combine='exp')
253
+ if not isinstance(e, Basic):
254
+ raise TypeError("e should be an instance of Basic")
255
+ if not e.has(x):
256
+ return SubsSet(), e
257
+ elif e == x:
258
+ s = SubsSet()
259
+ return s, s[x]
260
+ elif e.is_Mul or e.is_Add:
261
+ i, d = e.as_independent(x) # throw away x-independent terms
262
+ if d.func != e.func:
263
+ s, expr = mrv(d, x)
264
+ return s, e.func(i, expr)
265
+ a, b = d.as_two_terms()
266
+ s1, e1 = mrv(a, x)
267
+ s2, e2 = mrv(b, x)
268
+ return mrv_max1(s1, s2, e.func(i, e1, e2), x)
269
+ elif e.is_Pow and e.base != S.Exp1:
270
+ e1 = S.One
271
+ while e.is_Pow:
272
+ b1 = e.base
273
+ e1 *= e.exp
274
+ e = b1
275
+ if b1 == 1:
276
+ return SubsSet(), b1
277
+ if e1.has(x):
278
+ return mrv(exp(e1*log(b1)), x)
279
+ else:
280
+ s, expr = mrv(b1, x)
281
+ return s, expr**e1
282
+ elif isinstance(e, log):
283
+ s, expr = mrv(e.args[0], x)
284
+ return s, log(expr)
285
+ elif isinstance(e, exp) or (e.is_Pow and e.base == S.Exp1):
286
+ # We know from the theory of this algorithm that exp(log(...)) may always
287
+ # be simplified here, and doing so is vital for termination.
288
+ if isinstance(e.exp, log):
289
+ return mrv(e.exp.args[0], x)
290
+ # if a product has an infinite factor the result will be
291
+ # infinite if there is no zero, otherwise NaN; here, we
292
+ # consider the result infinite if any factor is infinite
293
+ li = limitinf(e.exp, x)
294
+ if any(_.is_infinite for _ in Mul.make_args(li)):
295
+ s1 = SubsSet()
296
+ e1 = s1[e]
297
+ s2, e2 = mrv(e.exp, x)
298
+ su = s1.union(s2)[0]
299
+ su.rewrites[e1] = exp(e2)
300
+ return mrv_max3(s1, e1, s2, exp(e2), su, e1, x)
301
+ else:
302
+ s, expr = mrv(e.exp, x)
303
+ return s, exp(expr)
304
+ elif isinstance(e, AppliedUndef):
305
+ raise ValueError("MRV set computation for UndefinedFunction is not allowed")
306
+ elif e.is_Function:
307
+ l = [mrv(a, x) for a in e.args]
308
+ l2 = [s for (s, _) in l if s != SubsSet()]
309
+ if len(l2) != 1:
310
+ # e.g. something like BesselJ(x, x)
311
+ raise NotImplementedError("MRV set computation for functions in"
312
+ " several variables not implemented.")
313
+ s, ss = l2[0], SubsSet()
314
+ args = [ss.do_subs(x[1]) for x in l]
315
+ return s, e.func(*args)
316
+ elif e.is_Derivative:
317
+ raise NotImplementedError("MRV set computation for derivatives"
318
+ " not implemented yet.")
319
+ raise NotImplementedError(
320
+ "Don't know how to calculate the mrv of '%s'" % e)
321
+
322
+
323
+ def mrv_max3(f, expsf, g, expsg, union, expsboth, x):
324
+ """
325
+ Computes the maximum of two sets of expressions f and g, which
326
+ are in the same comparability class, i.e. max() compares (two elements of)
327
+ f and g and returns either (f, expsf) [if f is larger], (g, expsg)
328
+ [if g is larger] or (union, expsboth) [if f, g are of the same class].
329
+ """
330
+ if not isinstance(f, SubsSet):
331
+ raise TypeError("f should be an instance of SubsSet")
332
+ if not isinstance(g, SubsSet):
333
+ raise TypeError("g should be an instance of SubsSet")
334
+ if f == SubsSet():
335
+ return g, expsg
336
+ elif g == SubsSet():
337
+ return f, expsf
338
+ elif f.meets(g):
339
+ return union, expsboth
340
+
341
+ c = compare(list(f.keys())[0], list(g.keys())[0], x)
342
+ if c == ">":
343
+ return f, expsf
344
+ elif c == "<":
345
+ return g, expsg
346
+ else:
347
+ if c != "=":
348
+ raise ValueError("c should be =")
349
+ return union, expsboth
350
+
351
+
352
+ def mrv_max1(f, g, exps, x):
353
+ """Computes the maximum of two sets of expressions f and g, which
354
+ are in the same comparability class, i.e. mrv_max1() compares (two elements of)
355
+ f and g and returns the set, which is in the higher comparability class
356
+ of the union of both, if they have the same order of variation.
357
+ Also returns exps, with the appropriate substitutions made.
358
+ """
359
+ u, b = f.union(g, exps)
360
+ return mrv_max3(f, g.do_subs(exps), g, f.do_subs(exps),
361
+ u, b, x)
362
+
363
+
364
+ @debug
365
+ @cacheit
366
+ @timeit
367
+ def sign(e, x):
368
+ """
369
+ Returns a sign of an expression e(x) for x->oo.
370
+
371
+ ::
372
+
373
+ e > 0 for x sufficiently large ... 1
374
+ e == 0 for x sufficiently large ... 0
375
+ e < 0 for x sufficiently large ... -1
376
+
377
+ The result of this function is currently undefined if e changes sign
378
+ arbitrarily often for arbitrarily large x (e.g. sin(x)).
379
+
380
+ Note that this returns zero only if e is *constantly* zero
381
+ for x sufficiently large. [If e is constant, of course, this is just
382
+ the same thing as the sign of e.]
383
+ """
384
+ if not isinstance(e, Basic):
385
+ raise TypeError("e should be an instance of Basic")
386
+
387
+ if e.is_positive:
388
+ return 1
389
+ elif e.is_negative:
390
+ return -1
391
+ elif e.is_zero:
392
+ return 0
393
+
394
+ elif not e.has(x):
395
+ from sympy.simplify import logcombine
396
+ e = logcombine(e)
397
+ return _sign(e)
398
+ elif e == x:
399
+ return 1
400
+ elif e.is_Mul:
401
+ a, b = e.as_two_terms()
402
+ sa = sign(a, x)
403
+ if not sa:
404
+ return 0
405
+ return sa * sign(b, x)
406
+ elif isinstance(e, exp):
407
+ return 1
408
+ elif e.is_Pow:
409
+ if e.base == S.Exp1:
410
+ return 1
411
+ s = sign(e.base, x)
412
+ if s == 1:
413
+ return 1
414
+ if e.exp.is_Integer:
415
+ return s**e.exp
416
+ elif isinstance(e, log) and e.args[0].is_positive:
417
+ return sign(e.args[0] - 1, x)
418
+
419
+ # if all else fails, do it the hard way
420
+ c0, e0 = mrv_leadterm(e, x)
421
+ return sign(c0, x)
422
+
423
+
424
+ @debug
425
+ @timeit
426
+ @cacheit
427
+ def limitinf(e, x):
428
+ """Limit e(x) for x-> oo."""
429
+ # rewrite e in terms of tractable functions only
430
+
431
+ old = e
432
+ if not e.has(x):
433
+ return e # e is a constant
434
+ from sympy.simplify.powsimp import powdenest
435
+ from sympy.calculus.util import AccumBounds
436
+ if e.has(Order):
437
+ e = e.expand().removeO()
438
+ if not x.is_positive or x.is_integer:
439
+ # We make sure that x.is_positive is True and x.is_integer is None
440
+ # so we get all the correct mathematical behavior from the expression.
441
+ # We need a fresh variable.
442
+ p = Dummy('p', positive=True)
443
+ e = e.subs(x, p)
444
+ x = p
445
+ e = e.rewrite('tractable', deep=True, limitvar=x)
446
+ e = powdenest(e)
447
+ if isinstance(e, AccumBounds):
448
+ if mrv_leadterm(e.min, x) != mrv_leadterm(e.max, x):
449
+ raise NotImplementedError
450
+ c0, e0 = mrv_leadterm(e.min, x)
451
+ else:
452
+ c0, e0 = mrv_leadterm(e, x)
453
+ sig = sign(e0, x)
454
+ if sig == 1:
455
+ return S.Zero # e0>0: lim f = 0
456
+ elif sig == -1: # e0<0: lim f = +-oo (the sign depends on the sign of c0)
457
+ if c0.match(I*Wild("a", exclude=[I])):
458
+ return c0*oo
459
+ s = sign(c0, x)
460
+ # the leading term shouldn't be 0:
461
+ if s == 0:
462
+ raise ValueError("Leading term should not be 0")
463
+ return s*oo
464
+ elif sig == 0:
465
+ if c0 == old:
466
+ c0 = c0.cancel()
467
+ return limitinf(c0, x) # e0=0: lim f = lim c0
468
+ else:
469
+ raise ValueError("{} could not be evaluated".format(sig))
470
+
471
+
472
+ def moveup2(s, x):
473
+ r = SubsSet()
474
+ for expr, var in s.items():
475
+ r[expr.xreplace({x: exp(x)})] = var
476
+ for var, expr in s.rewrites.items():
477
+ r.rewrites[var] = s.rewrites[var].xreplace({x: exp(x)})
478
+ return r
479
+
480
+
481
+ def moveup(l, x):
482
+ return [e.xreplace({x: exp(x)}) for e in l]
483
+
484
+
485
+ @debug
486
+ @timeit
487
+ @cacheit
488
+ def mrv_leadterm(e, x):
489
+ """Returns (c0, e0) for e."""
490
+ Omega = SubsSet()
491
+ if not e.has(x):
492
+ return (e, S.Zero)
493
+ if Omega == SubsSet():
494
+ Omega, exps = mrv(e, x)
495
+ if not Omega:
496
+ # e really does not depend on x after simplification
497
+ return exps, S.Zero
498
+ if x in Omega:
499
+ # move the whole omega up (exponentiate each term):
500
+ Omega_up = moveup2(Omega, x)
501
+ exps_up = moveup([exps], x)[0]
502
+ # NOTE: there is no need to move this down!
503
+ Omega = Omega_up
504
+ exps = exps_up
505
+ #
506
+ # The positive dummy, w, is used here so log(w*2) etc. will expand;
507
+ # a unique dummy is needed in this algorithm
508
+ #
509
+ # For limits of complex functions, the algorithm would have to be
510
+ # improved, or just find limits of Re and Im components separately.
511
+ #
512
+ w = Dummy("w", positive=True)
513
+ f, logw = rewrite(exps, Omega, x, w)
514
+
515
+ # Ensure expressions of the form exp(log(...)) don't get simplified automatically in the previous steps.
516
+ # see: https://github.com/sympy/sympy/issues/15323#issuecomment-478639399
517
+ f = f.replace(lambda f: f.is_Pow and f.has(x), lambda f: exp(log(f.base)*f.exp))
518
+
519
+ try:
520
+ lt = f.leadterm(w, logx=logw)
521
+ except (NotImplementedError, PoleError, ValueError):
522
+ n0 = 1
523
+ _series = Order(1)
524
+ incr = S.One
525
+ while _series.is_Order:
526
+ _series = f._eval_nseries(w, n=n0+incr, logx=logw)
527
+ incr *= 2
528
+ series = _series.expand().removeO()
529
+ try:
530
+ lt = series.leadterm(w, logx=logw)
531
+ except (NotImplementedError, PoleError, ValueError):
532
+ lt = f.as_coeff_exponent(w)
533
+ if lt[0].has(w):
534
+ base = f.as_base_exp()[0].as_coeff_exponent(w)
535
+ ex = f.as_base_exp()[1]
536
+ lt = (base[0]**ex, base[1]*ex)
537
+ return (lt[0].subs(log(w), logw), lt[1])
538
+
539
+
540
+ def build_expression_tree(Omega, rewrites):
541
+ r""" Helper function for rewrite.
542
+
543
+ We need to sort Omega (mrv set) so that we replace an expression before
544
+ we replace any expression in terms of which it has to be rewritten::
545
+
546
+ e1 ---> e2 ---> e3
547
+ \
548
+ -> e4
549
+
550
+ Here we can do e1, e2, e3, e4 or e1, e2, e4, e3.
551
+ To do this we assemble the nodes into a tree, and sort them by height.
552
+
553
+ This function builds the tree, rewrites then sorts the nodes.
554
+ """
555
+ class Node:
556
+ def __init__(self):
557
+ self.before = []
558
+ self.expr = None
559
+ self.var = None
560
+ def ht(self):
561
+ return reduce(lambda x, y: x + y,
562
+ [x.ht() for x in self.before], 1)
563
+ nodes = {}
564
+ for expr, v in Omega:
565
+ n = Node()
566
+ n.var = v
567
+ n.expr = expr
568
+ nodes[v] = n
569
+ for _, v in Omega:
570
+ if v in rewrites:
571
+ n = nodes[v]
572
+ r = rewrites[v]
573
+ for _, v2 in Omega:
574
+ if r.has(v2):
575
+ n.before.append(nodes[v2])
576
+
577
+ return nodes
578
+
579
+
580
+ @debug
581
+ @timeit
582
+ def rewrite(e, Omega, x, wsym):
583
+ """e(x) ... the function
584
+ Omega ... the mrv set
585
+ wsym ... the symbol which is going to be used for w
586
+
587
+ Returns the rewritten e in terms of w and log(w). See test_rewrite1()
588
+ for examples and correct results.
589
+ """
590
+
591
+ from sympy import AccumBounds
592
+ if not isinstance(Omega, SubsSet):
593
+ raise TypeError("Omega should be an instance of SubsSet")
594
+ if len(Omega) == 0:
595
+ raise ValueError("Length cannot be 0")
596
+ # all items in Omega must be exponentials
597
+ for t in Omega.keys():
598
+ if not isinstance(t, exp):
599
+ raise ValueError("Value should be exp")
600
+ rewrites = Omega.rewrites
601
+ Omega = list(Omega.items())
602
+
603
+ nodes = build_expression_tree(Omega, rewrites)
604
+ Omega.sort(key=lambda x: nodes[x[1]].ht(), reverse=True)
605
+
606
+ # make sure we know the sign of each exp() term; after the loop,
607
+ # g is going to be the "w" - the simplest one in the mrv set
608
+ for g, _ in Omega:
609
+ sig = sign(g.exp, x)
610
+ if sig != 1 and sig != -1 and not sig.has(AccumBounds):
611
+ raise NotImplementedError('Result depends on the sign of %s' % sig)
612
+ if sig == 1:
613
+ wsym = 1/wsym # if g goes to oo, substitute 1/w
614
+ # O2 is a list, which results by rewriting each item in Omega using "w"
615
+ O2 = []
616
+ denominators = []
617
+ for f, var in Omega:
618
+ c = limitinf(f.exp/g.exp, x)
619
+ if c.is_Rational:
620
+ denominators.append(c.q)
621
+ arg = f.exp
622
+ if var in rewrites:
623
+ if not isinstance(rewrites[var], exp):
624
+ raise ValueError("Value should be exp")
625
+ arg = rewrites[var].args[0]
626
+ O2.append((var, exp((arg - c*g.exp))*wsym**c))
627
+
628
+ # Remember that Omega contains subexpressions of "e". So now we find
629
+ # them in "e" and substitute them for our rewriting, stored in O2
630
+
631
+ # the following powsimp is necessary to automatically combine exponentials,
632
+ # so that the .xreplace() below succeeds:
633
+ # TODO this should not be necessary
634
+ from sympy.simplify.powsimp import powsimp
635
+ f = powsimp(e, deep=True, combine='exp')
636
+ for a, b in O2:
637
+ f = f.xreplace({a: b})
638
+
639
+ for _, var in Omega:
640
+ assert not f.has(var)
641
+
642
+ # finally compute the logarithm of w (logw).
643
+ logw = g.exp
644
+ if sig == 1:
645
+ logw = -logw # log(w)->log(1/w)=-log(w)
646
+
647
+ # Some parts of SymPy have difficulty computing series expansions with
648
+ # non-integral exponents. The following heuristic improves the situation:
649
+ exponent = reduce(ilcm, denominators, 1)
650
+ f = f.subs({wsym: wsym**exponent})
651
+ logw /= exponent
652
+
653
+ # bottom_up function is required for a specific case - when f is
654
+ # -exp(p/(p + 1)) + exp(-p**2/(p + 1) + p). No current simplification
655
+ # methods reduce this to 0 while not expanding polynomials.
656
+ f = bottom_up(f, lambda w: getattr(w, 'normal', lambda: w)())
657
+
658
+ return f, logw
659
+
660
+
661
+ def gruntz(e, z, z0, dir="+"):
662
+ """
663
+ Compute the limit of e(z) at the point z0 using the Gruntz algorithm.
664
+
665
+ Explanation
666
+ ===========
667
+
668
+ ``z0`` can be any expression, including oo and -oo.
669
+
670
+ For ``dir="+"`` (default) it calculates the limit from the right
671
+ (z->z0+) and for ``dir="-"`` the limit from the left (z->z0-). For infinite z0
672
+ (oo or -oo), the dir argument does not matter.
673
+
674
+ This algorithm is fully described in the module docstring in the gruntz.py
675
+ file. It relies heavily on the series expansion. Most frequently, gruntz()
676
+ is only used if the faster limit() function (which uses heuristics) fails.
677
+ """
678
+ if not z.is_symbol:
679
+ raise NotImplementedError("Second argument must be a Symbol")
680
+
681
+ # convert all limits to the limit z->oo; sign of z is handled in limitinf
682
+ r = None
683
+ if z0 in (oo, I*oo):
684
+ e0 = e
685
+ elif z0 in (-oo, -I*oo):
686
+ e0 = e.subs(z, -z)
687
+ else:
688
+ if str(dir) == "-":
689
+ e0 = e.subs(z, z0 - 1/z)
690
+ elif str(dir) == "+":
691
+ e0 = e.subs(z, z0 + 1/z)
692
+ else:
693
+ raise NotImplementedError("dir must be '+' or '-'")
694
+
695
+ r = limitinf(e0, z)
696
+
697
+ # This is a bit of a heuristic for nice results... we always rewrite
698
+ # tractable functions in terms of familiar intractable ones.
699
+ # It might be nicer to rewrite the exactly to what they were initially,
700
+ # but that would take some work to implement.
701
+ return r.rewrite('intractable', deep=True)
outputs/audit_venv/lib/python3.11/site-packages/sympy/series/kauers.py ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def finite_diff(expression, variable, increment=1):
2
+ """
3
+ Takes as input a polynomial expression and the variable used to construct
4
+ it and returns the difference between function's value when the input is
5
+ incremented to 1 and the original function value. If you want an increment
6
+ other than one supply it as a third argument.
7
+
8
+ Examples
9
+ ========
10
+
11
+ >>> from sympy.abc import x, y, z
12
+ >>> from sympy.series.kauers import finite_diff
13
+ >>> finite_diff(x**2, x)
14
+ 2*x + 1
15
+ >>> finite_diff(y**3 + 2*y**2 + 3*y + 4, y)
16
+ 3*y**2 + 7*y + 6
17
+ >>> finite_diff(x**2 + 3*x + 8, x, 2)
18
+ 4*x + 10
19
+ >>> finite_diff(z**3 + 8*z, z, 3)
20
+ 9*z**2 + 27*z + 51
21
+ """
22
+ expression = expression.expand()
23
+ expression2 = expression.subs(variable, variable + increment)
24
+ expression2 = expression2.expand()
25
+ return expression2 - expression
26
+
27
+ def finite_diff_kauers(sum):
28
+ """
29
+ Takes as input a Sum instance and returns the difference between the sum
30
+ with the upper index incremented by 1 and the original sum. For example,
31
+ if S(n) is a sum, then finite_diff_kauers will return S(n + 1) - S(n).
32
+
33
+ Examples
34
+ ========
35
+
36
+ >>> from sympy.series.kauers import finite_diff_kauers
37
+ >>> from sympy import Sum
38
+ >>> from sympy.abc import x, y, m, n, k
39
+ >>> finite_diff_kauers(Sum(k, (k, 1, n)))
40
+ n + 1
41
+ >>> finite_diff_kauers(Sum(1/k, (k, 1, n)))
42
+ 1/(n + 1)
43
+ >>> finite_diff_kauers(Sum((x*y**2), (x, 1, n), (y, 1, m)))
44
+ (m + 1)**2*(n + 1)
45
+ >>> finite_diff_kauers(Sum((x*y), (x, 1, m), (y, 1, n)))
46
+ (m + 1)*(n + 1)
47
+ """
48
+ function = sum.function
49
+ for l in sum.limits:
50
+ function = function.subs(l[0], l[- 1] + 1)
51
+ return function
outputs/audit_venv/lib/python3.11/site-packages/sympy/series/limits.py ADDED
@@ -0,0 +1,394 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.calculus.accumulationbounds import AccumBounds
2
+ from sympy.core import S, Symbol, Add, sympify, Expr, PoleError, Mul
3
+ from sympy.core.exprtools import factor_terms
4
+ from sympy.core.numbers import Float, _illegal
5
+ from sympy.core.function import AppliedUndef
6
+ from sympy.core.symbol import Dummy
7
+ from sympy.functions.combinatorial.factorials import factorial
8
+ from sympy.functions.elementary.complexes import (Abs, sign, arg, re)
9
+ from sympy.functions.elementary.exponential import (exp, log)
10
+ from sympy.functions.special.gamma_functions import gamma
11
+ from sympy.polys import PolynomialError, factor
12
+ from sympy.series.order import Order
13
+ from .gruntz import gruntz
14
+
15
+ def limit(e, z, z0, dir="+"):
16
+ """Computes the limit of ``e(z)`` at the point ``z0``.
17
+
18
+ Parameters
19
+ ==========
20
+
21
+ e : expression, the limit of which is to be taken
22
+
23
+ z : symbol representing the variable in the limit.
24
+ Other symbols are treated as constants. Multivariate limits
25
+ are not supported.
26
+
27
+ z0 : the value toward which ``z`` tends. Can be any expression,
28
+ including ``oo`` and ``-oo``.
29
+
30
+ dir : string, optional (default: "+")
31
+ The limit is bi-directional if ``dir="+-"``, from the right
32
+ (z->z0+) if ``dir="+"``, and from the left (z->z0-) if
33
+ ``dir="-"``. For infinite ``z0`` (``oo`` or ``-oo``), the ``dir``
34
+ argument is determined from the direction of the infinity
35
+ (i.e., ``dir="-"`` for ``oo``).
36
+
37
+ Examples
38
+ ========
39
+
40
+ >>> from sympy import limit, sin, oo
41
+ >>> from sympy.abc import x
42
+ >>> limit(sin(x)/x, x, 0)
43
+ 1
44
+ >>> limit(1/x, x, 0) # default dir='+'
45
+ oo
46
+ >>> limit(1/x, x, 0, dir="-")
47
+ -oo
48
+ >>> limit(1/x, x, 0, dir='+-')
49
+ zoo
50
+ >>> limit(1/x, x, oo)
51
+ 0
52
+
53
+ Notes
54
+ =====
55
+
56
+ First we try some heuristics for easy and frequent cases like "x", "1/x",
57
+ "x**2" and similar, so that it's fast. For all other cases, we use the
58
+ Gruntz algorithm (see the gruntz() function).
59
+
60
+ See Also
61
+ ========
62
+
63
+ limit_seq : returns the limit of a sequence.
64
+ """
65
+
66
+ return Limit(e, z, z0, dir).doit(deep=False)
67
+
68
+
69
+ def heuristics(e, z, z0, dir):
70
+ """Computes the limit of an expression term-wise.
71
+ Parameters are the same as for the ``limit`` function.
72
+ Works with the arguments of expression ``e`` one by one, computing
73
+ the limit of each and then combining the results. This approach
74
+ works only for simple limits, but it is fast.
75
+ """
76
+
77
+ rv = None
78
+ if z0 is S.Infinity:
79
+ rv = limit(e.subs(z, 1/z), z, S.Zero, "+")
80
+ if isinstance(rv, Limit):
81
+ return
82
+ elif (e.is_Mul or e.is_Add or e.is_Pow or (e.is_Function and not isinstance(e, AppliedUndef))):
83
+ r = []
84
+ from sympy.simplify.simplify import together
85
+ for a in e.args:
86
+ l = limit(a, z, z0, dir)
87
+ if l.has(S.Infinity) and l.is_finite is None:
88
+ if isinstance(e, Add):
89
+ m = factor_terms(e)
90
+ if not isinstance(m, Mul): # try together
91
+ m = together(m)
92
+ if not isinstance(m, Mul): # try factor if the previous methods failed
93
+ m = factor(e)
94
+ if isinstance(m, Mul):
95
+ return heuristics(m, z, z0, dir)
96
+ return
97
+ return
98
+ elif isinstance(l, Limit):
99
+ return
100
+ elif l is S.NaN:
101
+ return
102
+ else:
103
+ r.append(l)
104
+ if r:
105
+ rv = e.func(*r)
106
+ if rv is S.NaN and e.is_Mul and any(isinstance(rr, AccumBounds) for rr in r):
107
+ r2 = []
108
+ e2 = []
109
+ for ii, rval in enumerate(r):
110
+ if isinstance(rval, AccumBounds):
111
+ r2.append(rval)
112
+ else:
113
+ e2.append(e.args[ii])
114
+
115
+ if len(e2) > 0:
116
+ e3 = Mul(*e2).simplify()
117
+ l = limit(e3, z, z0, dir)
118
+ rv = l * Mul(*r2)
119
+
120
+ if rv is S.NaN:
121
+ try:
122
+ from sympy.simplify.ratsimp import ratsimp
123
+ rat_e = ratsimp(e)
124
+ except PolynomialError:
125
+ return
126
+ if rat_e is S.NaN or rat_e == e:
127
+ return
128
+ return limit(rat_e, z, z0, dir)
129
+ return rv
130
+
131
+
132
+ class Limit(Expr):
133
+ """Represents an unevaluated limit.
134
+
135
+ Examples
136
+ ========
137
+
138
+ >>> from sympy import Limit, sin
139
+ >>> from sympy.abc import x
140
+ >>> Limit(sin(x)/x, x, 0)
141
+ Limit(sin(x)/x, x, 0, dir='+')
142
+ >>> Limit(1/x, x, 0, dir="-")
143
+ Limit(1/x, x, 0, dir='-')
144
+
145
+ """
146
+
147
+ def __new__(cls, e, z, z0, dir="+"):
148
+ e = sympify(e)
149
+ z = sympify(z)
150
+ z0 = sympify(z0)
151
+
152
+ if z0 in (S.Infinity, S.ImaginaryUnit*S.Infinity):
153
+ dir = "-"
154
+ elif z0 in (S.NegativeInfinity, S.ImaginaryUnit*S.NegativeInfinity):
155
+ dir = "+"
156
+
157
+ if(z0.has(z)):
158
+ raise NotImplementedError("Limits approaching a variable point are"
159
+ " not supported (%s -> %s)" % (z, z0))
160
+ if isinstance(dir, str):
161
+ dir = Symbol(dir)
162
+ elif not isinstance(dir, Symbol):
163
+ raise TypeError("direction must be of type basestring or "
164
+ "Symbol, not %s" % type(dir))
165
+ if str(dir) not in ('+', '-', '+-'):
166
+ raise ValueError("direction must be one of '+', '-' "
167
+ "or '+-', not %s" % dir)
168
+
169
+ obj = Expr.__new__(cls)
170
+ obj._args = (e, z, z0, dir)
171
+ return obj
172
+
173
+
174
+ @property
175
+ def free_symbols(self):
176
+ e = self.args[0]
177
+ isyms = e.free_symbols
178
+ isyms.difference_update(self.args[1].free_symbols)
179
+ isyms.update(self.args[2].free_symbols)
180
+ return isyms
181
+
182
+
183
+ def pow_heuristics(self, e):
184
+ _, z, z0, _ = self.args
185
+ b1, e1 = e.base, e.exp
186
+ if not b1.has(z):
187
+ res = limit(e1*log(b1), z, z0)
188
+ return exp(res)
189
+
190
+ ex_lim = limit(e1, z, z0)
191
+ base_lim = limit(b1, z, z0)
192
+
193
+ if base_lim is S.One:
194
+ if ex_lim in (S.Infinity, S.NegativeInfinity):
195
+ res = limit(e1*(b1 - 1), z, z0)
196
+ return exp(res)
197
+ if base_lim is S.NegativeInfinity and ex_lim is S.Infinity:
198
+ return S.ComplexInfinity
199
+
200
+
201
+ def doit(self, **hints):
202
+ """Evaluates the limit.
203
+
204
+ Parameters
205
+ ==========
206
+
207
+ deep : bool, optional (default: True)
208
+ Invoke the ``doit`` method of the expressions involved before
209
+ taking the limit.
210
+
211
+ hints : optional keyword arguments
212
+ To be passed to ``doit`` methods; only used if deep is True.
213
+ """
214
+
215
+ e, z, z0, dir = self.args
216
+
217
+ if str(dir) == '+-':
218
+ r = limit(e, z, z0, dir='+')
219
+ l = limit(e, z, z0, dir='-')
220
+ if isinstance(r, Limit) and isinstance(l, Limit):
221
+ if r.args[0] == l.args[0]:
222
+ return self
223
+ if r == l:
224
+ return l
225
+ if r.is_infinite and l.is_infinite:
226
+ return S.ComplexInfinity
227
+ raise ValueError("The limit does not exist since "
228
+ "left hand limit = %s and right hand limit = %s"
229
+ % (l, r))
230
+
231
+ if z0 is S.ComplexInfinity:
232
+ raise NotImplementedError("Limits at complex "
233
+ "infinity are not implemented")
234
+
235
+ if z0.is_infinite:
236
+ cdir = sign(z0)
237
+ cdir = cdir/abs(cdir)
238
+ e = e.subs(z, cdir*z)
239
+ dir = "-"
240
+ z0 = S.Infinity
241
+
242
+ if hints.get('deep', True):
243
+ e = e.doit(**hints)
244
+ z = z.doit(**hints)
245
+ z0 = z0.doit(**hints)
246
+
247
+ if e == z:
248
+ return z0
249
+
250
+ if not e.has(z):
251
+ return e
252
+
253
+ if z0 is S.NaN:
254
+ return S.NaN
255
+
256
+ if e.has(*_illegal):
257
+ return self
258
+
259
+ if e.is_Order:
260
+ return Order(limit(e.expr, z, z0), *e.args[1:])
261
+
262
+ cdir = S.Zero
263
+ if str(dir) == "+":
264
+ cdir = S.One
265
+ elif str(dir) == "-":
266
+ cdir = S.NegativeOne
267
+
268
+ def set_signs(expr):
269
+ if not expr.args:
270
+ return expr
271
+ newargs = tuple(set_signs(arg) for arg in expr.args)
272
+ if newargs != expr.args:
273
+ expr = expr.func(*newargs)
274
+ abs_flag = isinstance(expr, Abs)
275
+ arg_flag = isinstance(expr, arg)
276
+ sign_flag = isinstance(expr, sign)
277
+ if abs_flag or sign_flag or arg_flag:
278
+ try:
279
+ sig = limit(expr.args[0], z, z0, dir)
280
+ if sig.is_zero:
281
+ sig = limit(1/expr.args[0], z, z0, dir)
282
+ except NotImplementedError:
283
+ return expr
284
+ else:
285
+ if sig.is_extended_real:
286
+ if (sig < 0) == True:
287
+ return (-expr.args[0] if abs_flag else
288
+ S.NegativeOne if sign_flag else S.Pi)
289
+ elif (sig > 0) == True:
290
+ return (expr.args[0] if abs_flag else
291
+ S.One if sign_flag else S.Zero)
292
+ return expr
293
+
294
+ if e.has(Float):
295
+ # Convert floats like 0.5 to exact SymPy numbers like S.Half, to
296
+ # prevent rounding errors which can lead to unexpected execution
297
+ # of conditional blocks that work on comparisons
298
+ # Also see comments in https://github.com/sympy/sympy/issues/19453
299
+ from sympy.simplify.simplify import nsimplify
300
+ e = nsimplify(e)
301
+ e = set_signs(e)
302
+
303
+
304
+ if e.is_meromorphic(z, z0):
305
+ if z0 is S.Infinity:
306
+ newe = e.subs(z, 1/z)
307
+ # cdir changes sign as oo- should become 0+
308
+ cdir = -cdir
309
+ else:
310
+ newe = e.subs(z, z + z0)
311
+ try:
312
+ coeff, ex = newe.leadterm(z, cdir=cdir)
313
+ except ValueError:
314
+ pass
315
+ else:
316
+ if ex > 0:
317
+ return S.Zero
318
+ elif ex == 0:
319
+ return coeff
320
+ if cdir == 1 or not(int(ex) & 1):
321
+ return S.Infinity*sign(coeff)
322
+ elif cdir == -1:
323
+ return S.NegativeInfinity*sign(coeff)
324
+ else:
325
+ return S.ComplexInfinity
326
+
327
+ if z0 is S.Infinity:
328
+ if e.is_Mul:
329
+ e = factor_terms(e)
330
+ dummy = Dummy('z', positive=z.is_positive, negative=z.is_negative, real=z.is_real)
331
+ newe = e.subs(z, 1/dummy)
332
+ # cdir changes sign as oo- should become 0+
333
+ cdir = -cdir
334
+ newz = dummy
335
+ else:
336
+ newe = e.subs(z, z + z0)
337
+ newz = z
338
+ try:
339
+ coeff, ex = newe.leadterm(newz, cdir=cdir)
340
+ except (ValueError, NotImplementedError, PoleError):
341
+ # The NotImplementedError catching is for custom functions
342
+ from sympy.simplify.powsimp import powsimp
343
+ e = powsimp(e)
344
+ if e.is_Pow:
345
+ r = self.pow_heuristics(e)
346
+ if r is not None:
347
+ return r
348
+ try:
349
+ coeff = newe.as_leading_term(newz, cdir=cdir)
350
+ if coeff != newe and (coeff.has(exp) or coeff.has(S.Exp1)):
351
+ return gruntz(coeff, newz, 0, "-" if re(cdir).is_negative else "+")
352
+ except (ValueError, NotImplementedError, PoleError):
353
+ pass
354
+ else:
355
+ if isinstance(coeff, AccumBounds) and ex == S.Zero:
356
+ return coeff
357
+ if coeff.has(S.Infinity, S.NegativeInfinity, S.ComplexInfinity, S.NaN):
358
+ return self
359
+ if not coeff.has(newz):
360
+ if ex.is_positive:
361
+ return S.Zero
362
+ elif ex == 0:
363
+ return coeff
364
+ elif ex.is_negative:
365
+ if cdir == 1:
366
+ return S.Infinity*sign(coeff)
367
+ elif cdir == -1:
368
+ return S.NegativeInfinity*sign(coeff)*S.NegativeOne**(S.One + ex)
369
+ else:
370
+ return S.ComplexInfinity
371
+ else:
372
+ raise NotImplementedError("Not sure of sign of %s" % ex)
373
+
374
+ # gruntz fails on factorials but works with the gamma function
375
+ # If no factorial term is present, e should remain unchanged.
376
+ # factorial is defined to be zero for negative inputs (which
377
+ # differs from gamma) so only rewrite for non-negative z0.
378
+ if z0.is_extended_nonnegative:
379
+ e = e.rewrite(factorial, gamma)
380
+
381
+ l = None
382
+
383
+ try:
384
+ r = gruntz(e, z, z0, dir)
385
+ if r is S.NaN or l is S.NaN:
386
+ raise PoleError()
387
+ except (PoleError, ValueError):
388
+ if l is not None:
389
+ raise
390
+ r = heuristics(e, z, z0, dir)
391
+ if r is None:
392
+ return self
393
+
394
+ return r
outputs/audit_venv/lib/python3.11/site-packages/sympy/series/limitseq.py ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Limits of sequences"""
2
+
3
+ from sympy.calculus.accumulationbounds import AccumulationBounds
4
+ from sympy.core.add import Add
5
+ from sympy.core.function import PoleError
6
+ from sympy.core.power import Pow
7
+ from sympy.core.singleton import S
8
+ from sympy.core.symbol import Dummy
9
+ from sympy.core.sympify import sympify
10
+ from sympy.functions.combinatorial.numbers import fibonacci
11
+ from sympy.functions.combinatorial.factorials import factorial, subfactorial
12
+ from sympy.functions.special.gamma_functions import gamma
13
+ from sympy.functions.elementary.complexes import Abs
14
+ from sympy.functions.elementary.miscellaneous import Max, Min
15
+ from sympy.functions.elementary.trigonometric import cos, sin
16
+ from sympy.series.limits import Limit
17
+
18
+
19
+ def difference_delta(expr, n=None, step=1):
20
+ """Difference Operator.
21
+
22
+ Explanation
23
+ ===========
24
+
25
+ Discrete analog of differential operator. Given a sequence x[n],
26
+ returns the sequence x[n + step] - x[n].
27
+
28
+ Examples
29
+ ========
30
+
31
+ >>> from sympy import difference_delta as dd
32
+ >>> from sympy.abc import n
33
+ >>> dd(n*(n + 1), n)
34
+ 2*n + 2
35
+ >>> dd(n*(n + 1), n, 2)
36
+ 4*n + 6
37
+
38
+ References
39
+ ==========
40
+
41
+ .. [1] https://reference.wolfram.com/language/ref/DifferenceDelta.html
42
+ """
43
+ expr = sympify(expr)
44
+
45
+ if n is None:
46
+ f = expr.free_symbols
47
+ if len(f) == 1:
48
+ n = f.pop()
49
+ elif len(f) == 0:
50
+ return S.Zero
51
+ else:
52
+ raise ValueError("Since there is more than one variable in the"
53
+ " expression, a variable must be supplied to"
54
+ " take the difference of %s" % expr)
55
+ step = sympify(step)
56
+ if step.is_number is False or step.is_finite is False:
57
+ raise ValueError("Step should be a finite number.")
58
+
59
+ if hasattr(expr, '_eval_difference_delta'):
60
+ result = expr._eval_difference_delta(n, step)
61
+ if result:
62
+ return result
63
+
64
+ return expr.subs(n, n + step) - expr
65
+
66
+
67
+ def dominant(expr, n):
68
+ """Finds the dominant term in a sum, that is a term that dominates
69
+ every other term.
70
+
71
+ Explanation
72
+ ===========
73
+
74
+ If limit(a/b, n, oo) is oo then a dominates b.
75
+ If limit(a/b, n, oo) is 0 then b dominates a.
76
+ Otherwise, a and b are comparable.
77
+
78
+ If there is no unique dominant term, then returns ``None``.
79
+
80
+ Examples
81
+ ========
82
+
83
+ >>> from sympy import Sum
84
+ >>> from sympy.series.limitseq import dominant
85
+ >>> from sympy.abc import n, k
86
+ >>> dominant(5*n**3 + 4*n**2 + n + 1, n)
87
+ 5*n**3
88
+ >>> dominant(2**n + Sum(k, (k, 0, n)), n)
89
+ 2**n
90
+
91
+ See Also
92
+ ========
93
+
94
+ sympy.series.limitseq.dominant
95
+ """
96
+ terms = Add.make_args(expr.expand(func=True))
97
+ term0 = terms[-1]
98
+ comp = [term0] # comparable terms
99
+ for t in terms[:-1]:
100
+ r = term0/t
101
+ e = r.gammasimp()
102
+ if e == r:
103
+ e = r.factor()
104
+ l = limit_seq(e, n)
105
+ if l is None:
106
+ return None
107
+ elif l.is_zero:
108
+ term0 = t
109
+ comp = [term0]
110
+ elif l not in [S.Infinity, S.NegativeInfinity]:
111
+ comp.append(t)
112
+ if len(comp) > 1:
113
+ return None
114
+ return term0
115
+
116
+
117
+ def _limit_inf(expr, n):
118
+ try:
119
+ return Limit(expr, n, S.Infinity).doit(deep=False)
120
+ except (NotImplementedError, PoleError):
121
+ return None
122
+
123
+
124
+ def _limit_seq(expr, n, trials):
125
+ from sympy.concrete.summations import Sum
126
+
127
+ for i in range(trials):
128
+ if not expr.has(Sum):
129
+ result = _limit_inf(expr, n)
130
+ if result is not None:
131
+ return result
132
+
133
+ num, den = expr.as_numer_denom()
134
+ if not den.has(n) or not num.has(n):
135
+ result = _limit_inf(expr.doit(), n)
136
+ if result is not None:
137
+ return result
138
+ return None
139
+
140
+ num, den = (difference_delta(t.expand(), n) for t in [num, den])
141
+ expr = (num / den).gammasimp()
142
+
143
+ if not expr.has(Sum):
144
+ result = _limit_inf(expr, n)
145
+ if result is not None:
146
+ return result
147
+
148
+ num, den = expr.as_numer_denom()
149
+
150
+ num = dominant(num, n)
151
+ if num is None:
152
+ return None
153
+
154
+ den = dominant(den, n)
155
+ if den is None:
156
+ return None
157
+
158
+ expr = (num / den).gammasimp()
159
+
160
+
161
+ def limit_seq(expr, n=None, trials=5):
162
+ """Finds the limit of a sequence as index ``n`` tends to infinity.
163
+
164
+ Parameters
165
+ ==========
166
+
167
+ expr : Expr
168
+ SymPy expression for the ``n-th`` term of the sequence
169
+ n : Symbol, optional
170
+ The index of the sequence, an integer that tends to positive
171
+ infinity. If None, inferred from the expression unless it has
172
+ multiple symbols.
173
+ trials: int, optional
174
+ The algorithm is highly recursive. ``trials`` is a safeguard from
175
+ infinite recursion in case the limit is not easily computed by the
176
+ algorithm. Try increasing ``trials`` if the algorithm returns ``None``.
177
+
178
+ Admissible Terms
179
+ ================
180
+
181
+ The algorithm is designed for sequences built from rational functions,
182
+ indefinite sums, and indefinite products over an indeterminate n. Terms of
183
+ alternating sign are also allowed, but more complex oscillatory behavior is
184
+ not supported.
185
+
186
+ Examples
187
+ ========
188
+
189
+ >>> from sympy import limit_seq, Sum, binomial
190
+ >>> from sympy.abc import n, k, m
191
+ >>> limit_seq((5*n**3 + 3*n**2 + 4) / (3*n**3 + 4*n - 5), n)
192
+ 5/3
193
+ >>> limit_seq(binomial(2*n, n) / Sum(binomial(2*k, k), (k, 1, n)), n)
194
+ 3/4
195
+ >>> limit_seq(Sum(k**2 * Sum(2**m/m, (m, 1, k)), (k, 1, n)) / (2**n*n), n)
196
+ 4
197
+
198
+ See Also
199
+ ========
200
+
201
+ sympy.series.limitseq.dominant
202
+
203
+ References
204
+ ==========
205
+
206
+ .. [1] Computing Limits of Sequences - Manuel Kauers
207
+ """
208
+
209
+ from sympy.concrete.summations import Sum
210
+ if n is None:
211
+ free = expr.free_symbols
212
+ if len(free) == 1:
213
+ n = free.pop()
214
+ elif not free:
215
+ return expr
216
+ else:
217
+ raise ValueError("Expression has more than one variable. "
218
+ "Please specify a variable.")
219
+ elif n not in expr.free_symbols:
220
+ return expr
221
+
222
+ expr = expr.rewrite(fibonacci, S.GoldenRatio)
223
+ expr = expr.rewrite(factorial, subfactorial, gamma)
224
+ n_ = Dummy("n", integer=True, positive=True)
225
+ n1 = Dummy("n", odd=True, positive=True)
226
+ n2 = Dummy("n", even=True, positive=True)
227
+
228
+ # If there is a negative term raised to a power involving n, or a
229
+ # trigonometric function, then consider even and odd n separately.
230
+ powers = (p.as_base_exp() for p in expr.atoms(Pow))
231
+ if (any(b.is_negative and e.has(n) for b, e in powers) or
232
+ expr.has(cos, sin)):
233
+ L1 = _limit_seq(expr.xreplace({n: n1}), n1, trials)
234
+ if L1 is not None:
235
+ L2 = _limit_seq(expr.xreplace({n: n2}), n2, trials)
236
+ if L1 != L2:
237
+ if L1.is_comparable and L2.is_comparable:
238
+ return AccumulationBounds(Min(L1, L2), Max(L1, L2))
239
+ else:
240
+ return None
241
+ else:
242
+ L1 = _limit_seq(expr.xreplace({n: n_}), n_, trials)
243
+ if L1 is not None:
244
+ return L1
245
+ else:
246
+ if expr.is_Add:
247
+ limits = [limit_seq(term, n, trials) for term in expr.args]
248
+ if any(result is None for result in limits):
249
+ return None
250
+ else:
251
+ return Add(*limits)
252
+ # Maybe the absolute value is easier to deal with (though not if
253
+ # it has a Sum). If it tends to 0, the limit is 0.
254
+ elif not expr.has(Sum):
255
+ lim = _limit_seq(Abs(expr.xreplace({n: n_})), n_, trials)
256
+ if lim is not None and lim.is_zero:
257
+ return S.Zero
outputs/audit_venv/lib/python3.11/site-packages/sympy/series/order.py ADDED
@@ -0,0 +1,522 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core import S, sympify, Expr, Dummy, Add, Mul
2
+ from sympy.core.cache import cacheit
3
+ from sympy.core.containers import Tuple
4
+ from sympy.core.function import Function, PoleError, expand_power_base, expand_log
5
+ from sympy.core.sorting import default_sort_key
6
+ from sympy.functions.elementary.exponential import exp, log
7
+ from sympy.sets.sets import Complement
8
+ from sympy.utilities.iterables import uniq, is_sequence
9
+
10
+
11
+ class Order(Expr):
12
+ r""" Represents the limiting behavior of some function.
13
+
14
+ Explanation
15
+ ===========
16
+
17
+ The order of a function characterizes the function based on the limiting
18
+ behavior of the function as it goes to some limit. Only taking the limit
19
+ point to be a number is currently supported. This is expressed in
20
+ big O notation [1]_.
21
+
22
+ The formal definition for the order of a function `g(x)` about a point `a`
23
+ is such that `g(x) = O(f(x))` as `x \rightarrow a` if and only if there
24
+ exists a `\delta > 0` and an `M > 0` such that `|g(x)| \leq M|f(x)|` for
25
+ `|x-a| < \delta`. This is equivalent to `\limsup_{x \rightarrow a}
26
+ |g(x)/f(x)| < \infty`.
27
+
28
+ Let's illustrate it on the following example by taking the expansion of
29
+ `\sin(x)` about 0:
30
+
31
+ .. math ::
32
+ \sin(x) = x - x^3/3! + O(x^5)
33
+
34
+ where in this case `O(x^5) = x^5/5! - x^7/7! + \cdots`. By the definition
35
+ of `O`, there is a `\delta > 0` and an `M` such that:
36
+
37
+ .. math ::
38
+ |x^5/5! - x^7/7! + ....| <= M|x^5| \text{ for } |x| < \delta
39
+
40
+ or by the alternate definition:
41
+
42
+ .. math ::
43
+ \lim_{x \rightarrow 0} | (x^5/5! - x^7/7! + ....) / x^5| < \infty
44
+
45
+ which surely is true, because
46
+
47
+ .. math ::
48
+ \lim_{x \rightarrow 0} | (x^5/5! - x^7/7! + ....) / x^5| = 1/5!
49
+
50
+
51
+ As it is usually used, the order of a function can be intuitively thought
52
+ of representing all terms of powers greater than the one specified. For
53
+ example, `O(x^3)` corresponds to any terms proportional to `x^3,
54
+ x^4,\ldots` and any higher power. For a polynomial, this leaves terms
55
+ proportional to `x^2`, `x` and constants.
56
+
57
+ Examples
58
+ ========
59
+
60
+ >>> from sympy import O, oo, cos, pi
61
+ >>> from sympy.abc import x, y
62
+
63
+ >>> O(x + x**2)
64
+ O(x)
65
+ >>> O(x + x**2, (x, 0))
66
+ O(x)
67
+ >>> O(x + x**2, (x, oo))
68
+ O(x**2, (x, oo))
69
+
70
+ >>> O(1 + x*y)
71
+ O(1, x, y)
72
+ >>> O(1 + x*y, (x, 0), (y, 0))
73
+ O(1, x, y)
74
+ >>> O(1 + x*y, (x, oo), (y, oo))
75
+ O(x*y, (x, oo), (y, oo))
76
+
77
+ >>> O(1) in O(1, x)
78
+ True
79
+ >>> O(1, x) in O(1)
80
+ False
81
+ >>> O(x) in O(1, x)
82
+ True
83
+ >>> O(x**2) in O(x)
84
+ True
85
+
86
+ >>> O(x)*x
87
+ O(x**2)
88
+ >>> O(x) - O(x)
89
+ O(x)
90
+ >>> O(cos(x))
91
+ O(1)
92
+ >>> O(cos(x), (x, pi/2))
93
+ O(x - pi/2, (x, pi/2))
94
+
95
+ References
96
+ ==========
97
+
98
+ .. [1] `Big O notation <https://en.wikipedia.org/wiki/Big_O_notation>`_
99
+
100
+ Notes
101
+ =====
102
+
103
+ In ``O(f(x), x)`` the expression ``f(x)`` is assumed to have a leading
104
+ term. ``O(f(x), x)`` is automatically transformed to
105
+ ``O(f(x).as_leading_term(x),x)``.
106
+
107
+ ``O(expr*f(x), x)`` is ``O(f(x), x)``
108
+
109
+ ``O(expr, x)`` is ``O(1)``
110
+
111
+ ``O(0, x)`` is 0.
112
+
113
+ Multivariate O is also supported:
114
+
115
+ ``O(f(x, y), x, y)`` is transformed to
116
+ ``O(f(x, y).as_leading_term(x,y).as_leading_term(y), x, y)``
117
+
118
+ In the multivariate case, it is assumed the limits w.r.t. the various
119
+ symbols commute.
120
+
121
+ If no symbols are passed then all symbols in the expression are used
122
+ and the limit point is assumed to be zero.
123
+
124
+ """
125
+
126
+ is_Order = True
127
+
128
+ __slots__ = ()
129
+
130
+ @cacheit
131
+ def __new__(cls, expr, *args, **kwargs):
132
+ expr = sympify(expr)
133
+
134
+ if not args:
135
+ if expr.is_Order:
136
+ variables = expr.variables
137
+ point = expr.point
138
+ else:
139
+ variables = list(expr.free_symbols)
140
+ point = [S.Zero]*len(variables)
141
+ else:
142
+ args = list(args if is_sequence(args) else [args])
143
+ variables, point = [], []
144
+ if is_sequence(args[0]):
145
+ for a in args:
146
+ v, p = list(map(sympify, a))
147
+ variables.append(v)
148
+ point.append(p)
149
+ else:
150
+ variables = list(map(sympify, args))
151
+ point = [S.Zero]*len(variables)
152
+
153
+ if not all(v.is_symbol for v in variables):
154
+ raise TypeError('Variables are not symbols, got %s' % variables)
155
+
156
+ if len(list(uniq(variables))) != len(variables):
157
+ raise ValueError('Variables are supposed to be unique symbols, got %s' % variables)
158
+
159
+ if expr.is_Order:
160
+ expr_vp = dict(expr.args[1:])
161
+ new_vp = dict(expr_vp)
162
+ vp = dict(zip(variables, point))
163
+ for v, p in vp.items():
164
+ if v in new_vp.keys():
165
+ if p != new_vp[v]:
166
+ raise NotImplementedError(
167
+ "Mixing Order at different points is not supported.")
168
+ else:
169
+ new_vp[v] = p
170
+ if set(expr_vp.keys()) == set(new_vp.keys()):
171
+ return expr
172
+ else:
173
+ variables = list(new_vp.keys())
174
+ point = [new_vp[v] for v in variables]
175
+
176
+ if expr is S.NaN:
177
+ return S.NaN
178
+
179
+ if any(x in p.free_symbols for x in variables for p in point):
180
+ raise ValueError('Got %s as a point.' % point)
181
+
182
+ if variables:
183
+ if any(p != point[0] for p in point):
184
+ raise NotImplementedError(
185
+ "Multivariable orders at different points are not supported.")
186
+ if point[0] in (S.Infinity, S.Infinity*S.ImaginaryUnit):
187
+ s = {k: 1/Dummy() for k in variables}
188
+ rs = {1/v: 1/k for k, v in s.items()}
189
+ ps = [S.Zero for p in point]
190
+ elif point[0] in (S.NegativeInfinity, S.NegativeInfinity*S.ImaginaryUnit):
191
+ s = {k: -1/Dummy() for k in variables}
192
+ rs = {-1/v: -1/k for k, v in s.items()}
193
+ ps = [S.Zero for p in point]
194
+ elif point[0] is not S.Zero:
195
+ s = {k: Dummy() + point[0] for k in variables}
196
+ rs = {(v - point[0]).together(): k - point[0] for k, v in s.items()}
197
+ ps = [S.Zero for p in point]
198
+ else:
199
+ s = ()
200
+ rs = ()
201
+ ps = list(point)
202
+
203
+ expr = expr.subs(s)
204
+
205
+ if expr.is_Add:
206
+ expr = expr.factor()
207
+
208
+ if s:
209
+ args = tuple([r[0] for r in rs.items()])
210
+ else:
211
+ args = tuple(variables)
212
+
213
+ if len(variables) > 1:
214
+ # XXX: better way? We need this expand() to
215
+ # workaround e.g: expr = x*(x + y).
216
+ # (x*(x + y)).as_leading_term(x, y) currently returns
217
+ # x*y (wrong order term!). That's why we want to deal with
218
+ # expand()'ed expr (handled in "if expr.is_Add" branch below).
219
+ expr = expr.expand()
220
+
221
+ old_expr = None
222
+ while old_expr != expr:
223
+ old_expr = expr
224
+ if expr.is_Add:
225
+ lst = expr.extract_leading_order(args)
226
+ expr = Add(*[f.expr for (e, f) in lst])
227
+
228
+ elif expr:
229
+ try:
230
+ expr = expr.as_leading_term(*args)
231
+ except PoleError:
232
+ if isinstance(expr, Function) or\
233
+ all(isinstance(arg, Function) for arg in expr.args):
234
+ # It is not possible to simplify an expression
235
+ # containing only functions (which raise error on
236
+ # call to leading term) further
237
+ pass
238
+ else:
239
+ orders = []
240
+ pts = tuple(zip(args, ps))
241
+ for arg in expr.args:
242
+ try:
243
+ lt = arg.as_leading_term(*args)
244
+ except PoleError:
245
+ lt = arg
246
+ if lt not in args:
247
+ order = Order(lt)
248
+ else:
249
+ order = Order(lt, *pts)
250
+ orders.append(order)
251
+ if expr.is_Add:
252
+ new_expr = Order(Add(*orders), *pts)
253
+ if new_expr.is_Add:
254
+ new_expr = Order(Add(*[a.expr for a in new_expr.args]), *pts)
255
+ expr = new_expr.expr
256
+ elif expr.is_Mul:
257
+ expr = Mul(*[a.expr for a in orders])
258
+ elif expr.is_Pow:
259
+ e = expr.exp
260
+ b = expr.base
261
+ expr = exp(e * log(b))
262
+
263
+ # It would probably be better to handle this somewhere
264
+ # else. This is needed for a testcase in which there is a
265
+ # symbol with the assumptions zero=True.
266
+ if expr.is_zero:
267
+ expr = S.Zero
268
+ else:
269
+ expr = expr.as_independent(*args, as_Add=False)[1]
270
+
271
+ expr = expand_power_base(expr)
272
+ expr = expand_log(expr)
273
+
274
+ if len(args) == 1:
275
+ # The definition of O(f(x)) symbol explicitly stated that
276
+ # the argument of f(x) is irrelevant. That's why we can
277
+ # combine some power exponents (only "on top" of the
278
+ # expression tree for f(x)), e.g.:
279
+ # x**p * (-x)**q -> x**(p+q) for real p, q.
280
+ x = args[0]
281
+ margs = list(Mul.make_args(
282
+ expr.as_independent(x, as_Add=False)[1]))
283
+
284
+ for i, t in enumerate(margs):
285
+ if t.is_Pow:
286
+ b, q = t.args
287
+ if b in (x, -x) and q.is_real and not q.has(x):
288
+ margs[i] = x**q
289
+ elif b.is_Pow and not b.exp.has(x):
290
+ b, r = b.args
291
+ if b in (x, -x) and r.is_real:
292
+ margs[i] = x**(r*q)
293
+ elif b.is_Mul and b.args[0] is S.NegativeOne:
294
+ b = -b
295
+ if b.is_Pow and not b.exp.has(x):
296
+ b, r = b.args
297
+ if b in (x, -x) and r.is_real:
298
+ margs[i] = x**(r*q)
299
+
300
+ expr = Mul(*margs)
301
+
302
+ expr = expr.subs(rs)
303
+
304
+ if expr.is_Order:
305
+ expr = expr.expr
306
+
307
+ if not expr.has(*variables) and not expr.is_zero:
308
+ expr = S.One
309
+
310
+ # create Order instance:
311
+ vp = dict(zip(variables, point))
312
+ variables.sort(key=default_sort_key)
313
+ point = [vp[v] for v in variables]
314
+ args = (expr,) + Tuple(*zip(variables, point))
315
+ obj = Expr.__new__(cls, *args)
316
+ return obj
317
+
318
+ def _eval_nseries(self, x, n, logx, cdir=0):
319
+ return self
320
+
321
+ @property
322
+ def expr(self):
323
+ return self.args[0]
324
+
325
+ @property
326
+ def variables(self):
327
+ if self.args[1:]:
328
+ return tuple(x[0] for x in self.args[1:])
329
+ else:
330
+ return ()
331
+
332
+ @property
333
+ def point(self):
334
+ if self.args[1:]:
335
+ return tuple(x[1] for x in self.args[1:])
336
+ else:
337
+ return ()
338
+
339
+ @property
340
+ def free_symbols(self):
341
+ return self.expr.free_symbols | set(self.variables)
342
+
343
+ def _eval_power(b, e):
344
+ if e.is_Number and e.is_nonnegative:
345
+ return b.func(b.expr ** e, *b.args[1:])
346
+ if e == O(1):
347
+ return b
348
+ return
349
+
350
+ def as_expr_variables(self, order_symbols):
351
+ if order_symbols is None:
352
+ order_symbols = self.args[1:]
353
+ else:
354
+ if (not all(o[1] == order_symbols[0][1] for o in order_symbols) and
355
+ not all(p == self.point[0] for p in self.point)): # pragma: no cover
356
+ raise NotImplementedError('Order at points other than 0 '
357
+ 'or oo not supported, got %s as a point.' % self.point)
358
+ if order_symbols and order_symbols[0][1] != self.point[0]:
359
+ raise NotImplementedError(
360
+ "Multiplying Order at different points is not supported.")
361
+ order_symbols = dict(order_symbols)
362
+ for s, p in dict(self.args[1:]).items():
363
+ if s not in order_symbols.keys():
364
+ order_symbols[s] = p
365
+ order_symbols = sorted(order_symbols.items(), key=lambda x: default_sort_key(x[0]))
366
+ return self.expr, tuple(order_symbols)
367
+
368
+ def removeO(self):
369
+ return S.Zero
370
+
371
+ def getO(self):
372
+ return self
373
+
374
+ @cacheit
375
+ def contains(self, expr):
376
+ r"""
377
+ Return True if expr belongs to Order(self.expr, \*self.variables).
378
+ Return False if self belongs to expr.
379
+ Return None if the inclusion relation cannot be determined
380
+ (e.g. when self and expr have different symbols).
381
+ """
382
+ expr = sympify(expr)
383
+ if expr.is_zero:
384
+ return True
385
+ if expr is S.NaN:
386
+ return False
387
+ point = self.point[0] if self.point else S.Zero
388
+ if expr.is_Order:
389
+ if (any(p != point for p in expr.point) or
390
+ any(p != point for p in self.point)):
391
+ return None
392
+ if expr.expr == self.expr:
393
+ # O(1) + O(1), O(1) + O(1, x), etc.
394
+ return all(x in self.args[1:] for x in expr.args[1:])
395
+ if expr.expr.is_Add:
396
+ return all(self.contains(x) for x in expr.expr.args)
397
+ if self.expr.is_Add and point.is_zero:
398
+ return any(self.func(x, *self.args[1:]).contains(expr)
399
+ for x in self.expr.args)
400
+ if self.variables and expr.variables:
401
+ common_symbols = tuple(
402
+ [s for s in self.variables if s in expr.variables])
403
+ elif self.variables:
404
+ common_symbols = self.variables
405
+ else:
406
+ common_symbols = expr.variables
407
+ if not common_symbols:
408
+ return None
409
+ if (self.expr.is_Pow and len(self.variables) == 1
410
+ and self.variables == expr.variables):
411
+ symbol = self.variables[0]
412
+ other = expr.expr.as_independent(symbol, as_Add=False)[1]
413
+ if (other.is_Pow and other.base == symbol and
414
+ self.expr.base == symbol):
415
+ if point.is_zero:
416
+ rv = (self.expr.exp - other.exp).is_nonpositive
417
+ if point.is_infinite:
418
+ rv = (self.expr.exp - other.exp).is_nonnegative
419
+ if rv is not None:
420
+ return rv
421
+
422
+ from sympy.simplify.powsimp import powsimp
423
+ r = None
424
+ ratio = self.expr/expr.expr
425
+ ratio = powsimp(ratio, deep=True, combine='exp')
426
+ for s in common_symbols:
427
+ from sympy.series.limits import Limit
428
+ l = Limit(ratio, s, point).doit(heuristics=False)
429
+ if not isinstance(l, Limit):
430
+ l = l != 0
431
+ else:
432
+ l = None
433
+ if r is None:
434
+ r = l
435
+ else:
436
+ if r != l:
437
+ return
438
+ return r
439
+
440
+ if self.expr.is_Pow and len(self.variables) == 1:
441
+ symbol = self.variables[0]
442
+ other = expr.as_independent(symbol, as_Add=False)[1]
443
+ if (other.is_Pow and other.base == symbol and
444
+ self.expr.base == symbol):
445
+ if point.is_zero:
446
+ rv = (self.expr.exp - other.exp).is_nonpositive
447
+ if point.is_infinite:
448
+ rv = (self.expr.exp - other.exp).is_nonnegative
449
+ if rv is not None:
450
+ return rv
451
+
452
+ obj = self.func(expr, *self.args[1:])
453
+ return self.contains(obj)
454
+
455
+ def __contains__(self, other):
456
+ result = self.contains(other)
457
+ if result is None:
458
+ raise TypeError('contains did not evaluate to a bool')
459
+ return result
460
+
461
+ def _eval_subs(self, old, new):
462
+ if old in self.variables:
463
+ newexpr = self.expr.subs(old, new)
464
+ i = self.variables.index(old)
465
+ newvars = list(self.variables)
466
+ newpt = list(self.point)
467
+ if new.is_symbol:
468
+ newvars[i] = new
469
+ else:
470
+ syms = new.free_symbols
471
+ if len(syms) == 1 or old in syms:
472
+ if old in syms:
473
+ var = self.variables[i]
474
+ else:
475
+ var = syms.pop()
476
+ # First, try to substitute self.point in the "new"
477
+ # expr to see if this is a fixed point.
478
+ # E.g. O(y).subs(y, sin(x))
479
+ from sympy import limit
480
+ if new.has(Order) and limit(new.getO().expr, var, new.getO().point[0]) == self.point[i]:
481
+ point = new.getO().point[0]
482
+ return Order(newexpr, *zip([var], [point]))
483
+ else:
484
+ point = new.subs(var, self.point[i])
485
+ if point != self.point[i]:
486
+ from sympy.solvers.solveset import solveset
487
+ d = Dummy()
488
+ sol = solveset(old - new.subs(var, d), d)
489
+ if isinstance(sol, Complement):
490
+ e1 = sol.args[0]
491
+ e2 = sol.args[1]
492
+ sol = set(e1) - set(e2)
493
+ res = [dict(zip((d, ), sol))]
494
+ point = d.subs(res[0]).limit(old, self.point[i])
495
+ newvars[i] = var
496
+ newpt[i] = point
497
+ elif old not in syms:
498
+ del newvars[i], newpt[i]
499
+ if not syms and new == self.point[i]:
500
+ newvars.extend(syms)
501
+ newpt.extend([S.Zero]*len(syms))
502
+ else:
503
+ return
504
+ return Order(newexpr, *zip(newvars, newpt))
505
+
506
+ def _eval_conjugate(self):
507
+ expr = self.expr._eval_conjugate()
508
+ if expr is not None:
509
+ return self.func(expr, *self.args[1:])
510
+
511
+ def _eval_derivative(self, x):
512
+ return self.func(self.expr.diff(x), *self.args[1:]) or self
513
+
514
+ def _eval_transpose(self):
515
+ expr = self.expr._eval_transpose()
516
+ if expr is not None:
517
+ return self.func(expr, *self.args[1:])
518
+
519
+ def __neg__(self):
520
+ return self
521
+
522
+ O = Order
outputs/audit_venv/lib/python3.11/site-packages/sympy/series/residues.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ This module implements the Residue function and related tools for working
3
+ with residues.
4
+ """
5
+
6
+ from sympy.core.mul import Mul
7
+ from sympy.core.singleton import S
8
+ from sympy.core.sympify import sympify
9
+ from sympy.utilities.timeutils import timethis
10
+
11
+
12
+ @timethis('residue')
13
+ def residue(expr, x, x0):
14
+ """
15
+ Finds the residue of ``expr`` at the point x=x0.
16
+
17
+ The residue is defined as the coefficient of ``1/(x-x0)`` in the power series
18
+ expansion about ``x=x0``.
19
+
20
+ Examples
21
+ ========
22
+
23
+ >>> from sympy import Symbol, residue, sin
24
+ >>> x = Symbol("x")
25
+ >>> residue(1/x, x, 0)
26
+ 1
27
+ >>> residue(1/x**2, x, 0)
28
+ 0
29
+ >>> residue(2/sin(x), x, 0)
30
+ 2
31
+
32
+ This function is essential for the Residue Theorem [1].
33
+
34
+ References
35
+ ==========
36
+
37
+ .. [1] https://en.wikipedia.org/wiki/Residue_theorem
38
+ """
39
+ # The current implementation uses series expansion to
40
+ # calculate it. A more general implementation is explained in
41
+ # the section 5.6 of the Bronstein's book {M. Bronstein:
42
+ # Symbolic Integration I, Springer Verlag (2005)}. For purely
43
+ # rational functions, the algorithm is much easier. See
44
+ # sections 2.4, 2.5, and 2.7 (this section actually gives an
45
+ # algorithm for computing any Laurent series coefficient for
46
+ # a rational function). The theory in section 2.4 will help to
47
+ # understand why the resultant works in the general algorithm.
48
+ # For the definition of a resultant, see section 1.4 (and any
49
+ # previous sections for more review).
50
+
51
+ from sympy.series.order import Order
52
+ from sympy.simplify.radsimp import collect
53
+ expr = sympify(expr)
54
+ if x0 != 0:
55
+ expr = expr.subs(x, x + x0)
56
+ for n in (0, 1, 2, 4, 8, 16, 32):
57
+ s = expr.nseries(x, n=n)
58
+ if not s.has(Order) or s.getn() >= 0:
59
+ break
60
+ s = collect(s.removeO(), x)
61
+ if s.is_Add:
62
+ args = s.args
63
+ else:
64
+ args = [s]
65
+ res = S.Zero
66
+ for arg in args:
67
+ c, m = arg.as_coeff_mul(x)
68
+ m = Mul(*m)
69
+ if not (m in (S.One, x) or (m.is_Pow and m.exp.is_Integer)):
70
+ raise NotImplementedError('term of unexpected form: %s' % m)
71
+ if m == 1/x:
72
+ res += c
73
+ return res
outputs/audit_venv/lib/python3.11/site-packages/sympy/series/sequences.py ADDED
@@ -0,0 +1,1239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.basic import Basic
2
+ from sympy.core.cache import cacheit
3
+ from sympy.core.containers import Tuple
4
+ from sympy.core.decorators import call_highest_priority
5
+ from sympy.core.parameters import global_parameters
6
+ from sympy.core.function import AppliedUndef, expand
7
+ from sympy.core.mul import Mul
8
+ from sympy.core.numbers import Integer
9
+ from sympy.core.relational import Eq
10
+ from sympy.core.singleton import S, Singleton
11
+ from sympy.core.sorting import ordered
12
+ from sympy.core.symbol import Dummy, Symbol, Wild
13
+ from sympy.core.sympify import sympify
14
+ from sympy.matrices import Matrix
15
+ from sympy.polys import lcm, factor
16
+ from sympy.sets.sets import Interval, Intersection
17
+ from sympy.tensor.indexed import Idx
18
+ from sympy.utilities.iterables import flatten, is_sequence, iterable
19
+
20
+
21
+ ###############################################################################
22
+ # SEQUENCES #
23
+ ###############################################################################
24
+
25
+
26
+ class SeqBase(Basic):
27
+ """Base class for sequences"""
28
+
29
+ is_commutative = True
30
+ _op_priority = 15
31
+
32
+ @staticmethod
33
+ def _start_key(expr):
34
+ """Return start (if possible) else S.Infinity.
35
+
36
+ adapted from Set._infimum_key
37
+ """
38
+ try:
39
+ start = expr.start
40
+ except NotImplementedError:
41
+ start = S.Infinity
42
+ return start
43
+
44
+ def _intersect_interval(self, other):
45
+ """Returns start and stop.
46
+
47
+ Takes intersection over the two intervals.
48
+ """
49
+ interval = Intersection(self.interval, other.interval)
50
+ return interval.inf, interval.sup
51
+
52
+ @property
53
+ def gen(self):
54
+ """Returns the generator for the sequence"""
55
+ raise NotImplementedError("(%s).gen" % self)
56
+
57
+ @property
58
+ def interval(self):
59
+ """The interval on which the sequence is defined"""
60
+ raise NotImplementedError("(%s).interval" % self)
61
+
62
+ @property
63
+ def start(self):
64
+ """The starting point of the sequence. This point is included"""
65
+ raise NotImplementedError("(%s).start" % self)
66
+
67
+ @property
68
+ def stop(self):
69
+ """The ending point of the sequence. This point is included"""
70
+ raise NotImplementedError("(%s).stop" % self)
71
+
72
+ @property
73
+ def length(self):
74
+ """Length of the sequence"""
75
+ raise NotImplementedError("(%s).length" % self)
76
+
77
+ @property
78
+ def variables(self):
79
+ """Returns a tuple of variables that are bounded"""
80
+ return ()
81
+
82
+ @property
83
+ def free_symbols(self):
84
+ """
85
+ This method returns the symbols in the object, excluding those
86
+ that take on a specific value (i.e. the dummy symbols).
87
+
88
+ Examples
89
+ ========
90
+
91
+ >>> from sympy import SeqFormula
92
+ >>> from sympy.abc import n, m
93
+ >>> SeqFormula(m*n**2, (n, 0, 5)).free_symbols
94
+ {m}
95
+ """
96
+ return ({j for i in self.args for j in i.free_symbols
97
+ .difference(self.variables)})
98
+
99
+ @cacheit
100
+ def coeff(self, pt):
101
+ """Returns the coefficient at point pt"""
102
+ if pt < self.start or pt > self.stop:
103
+ raise IndexError("Index %s out of bounds %s" % (pt, self.interval))
104
+ return self._eval_coeff(pt)
105
+
106
+ def _eval_coeff(self, pt):
107
+ raise NotImplementedError("The _eval_coeff method should be added to"
108
+ "%s to return coefficient so it is available"
109
+ "when coeff calls it."
110
+ % self.func)
111
+
112
+ def _ith_point(self, i):
113
+ """Returns the i'th point of a sequence.
114
+
115
+ Explanation
116
+ ===========
117
+
118
+ If start point is negative infinity, point is returned from the end.
119
+ Assumes the first point to be indexed zero.
120
+
121
+ Examples
122
+ =========
123
+
124
+ >>> from sympy import oo
125
+ >>> from sympy.series.sequences import SeqPer
126
+
127
+ bounded
128
+
129
+ >>> SeqPer((1, 2, 3), (-10, 10))._ith_point(0)
130
+ -10
131
+ >>> SeqPer((1, 2, 3), (-10, 10))._ith_point(5)
132
+ -5
133
+
134
+ End is at infinity
135
+
136
+ >>> SeqPer((1, 2, 3), (0, oo))._ith_point(5)
137
+ 5
138
+
139
+ Starts at negative infinity
140
+
141
+ >>> SeqPer((1, 2, 3), (-oo, 0))._ith_point(5)
142
+ -5
143
+ """
144
+ if self.start is S.NegativeInfinity:
145
+ initial = self.stop
146
+ else:
147
+ initial = self.start
148
+
149
+ if self.start is S.NegativeInfinity:
150
+ step = -1
151
+ else:
152
+ step = 1
153
+
154
+ return initial + i*step
155
+
156
+ def _add(self, other):
157
+ """
158
+ Should only be used internally.
159
+
160
+ Explanation
161
+ ===========
162
+
163
+ self._add(other) returns a new, term-wise added sequence if self
164
+ knows how to add with other, otherwise it returns ``None``.
165
+
166
+ ``other`` should only be a sequence object.
167
+
168
+ Used within :class:`SeqAdd` class.
169
+ """
170
+ return None
171
+
172
+ def _mul(self, other):
173
+ """
174
+ Should only be used internally.
175
+
176
+ Explanation
177
+ ===========
178
+
179
+ self._mul(other) returns a new, term-wise multiplied sequence if self
180
+ knows how to multiply with other, otherwise it returns ``None``.
181
+
182
+ ``other`` should only be a sequence object.
183
+
184
+ Used within :class:`SeqMul` class.
185
+ """
186
+ return None
187
+
188
+ def coeff_mul(self, other):
189
+ """
190
+ Should be used when ``other`` is not a sequence. Should be
191
+ defined to define custom behaviour.
192
+
193
+ Examples
194
+ ========
195
+
196
+ >>> from sympy import SeqFormula
197
+ >>> from sympy.abc import n
198
+ >>> SeqFormula(n**2).coeff_mul(2)
199
+ SeqFormula(2*n**2, (n, 0, oo))
200
+
201
+ Notes
202
+ =====
203
+
204
+ '*' defines multiplication of sequences with sequences only.
205
+ """
206
+ return Mul(self, other)
207
+
208
+ def __add__(self, other):
209
+ """Returns the term-wise addition of 'self' and 'other'.
210
+
211
+ ``other`` should be a sequence.
212
+
213
+ Examples
214
+ ========
215
+
216
+ >>> from sympy import SeqFormula
217
+ >>> from sympy.abc import n
218
+ >>> SeqFormula(n**2) + SeqFormula(n**3)
219
+ SeqFormula(n**3 + n**2, (n, 0, oo))
220
+ """
221
+ if not isinstance(other, SeqBase):
222
+ raise TypeError('cannot add sequence and %s' % type(other))
223
+ return SeqAdd(self, other)
224
+
225
+ @call_highest_priority('__add__')
226
+ def __radd__(self, other):
227
+ return self + other
228
+
229
+ def __sub__(self, other):
230
+ """Returns the term-wise subtraction of ``self`` and ``other``.
231
+
232
+ ``other`` should be a sequence.
233
+
234
+ Examples
235
+ ========
236
+
237
+ >>> from sympy import SeqFormula
238
+ >>> from sympy.abc import n
239
+ >>> SeqFormula(n**2) - (SeqFormula(n))
240
+ SeqFormula(n**2 - n, (n, 0, oo))
241
+ """
242
+ if not isinstance(other, SeqBase):
243
+ raise TypeError('cannot subtract sequence and %s' % type(other))
244
+ return SeqAdd(self, -other)
245
+
246
+ @call_highest_priority('__sub__')
247
+ def __rsub__(self, other):
248
+ return (-self) + other
249
+
250
+ def __neg__(self):
251
+ """Negates the sequence.
252
+
253
+ Examples
254
+ ========
255
+
256
+ >>> from sympy import SeqFormula
257
+ >>> from sympy.abc import n
258
+ >>> -SeqFormula(n**2)
259
+ SeqFormula(-n**2, (n, 0, oo))
260
+ """
261
+ return self.coeff_mul(-1)
262
+
263
+ def __mul__(self, other):
264
+ """Returns the term-wise multiplication of 'self' and 'other'.
265
+
266
+ ``other`` should be a sequence. For ``other`` not being a
267
+ sequence see :func:`coeff_mul` method.
268
+
269
+ Examples
270
+ ========
271
+
272
+ >>> from sympy import SeqFormula
273
+ >>> from sympy.abc import n
274
+ >>> SeqFormula(n**2) * (SeqFormula(n))
275
+ SeqFormula(n**3, (n, 0, oo))
276
+ """
277
+ if not isinstance(other, SeqBase):
278
+ raise TypeError('cannot multiply sequence and %s' % type(other))
279
+ return SeqMul(self, other)
280
+
281
+ @call_highest_priority('__mul__')
282
+ def __rmul__(self, other):
283
+ return self * other
284
+
285
+ def __iter__(self):
286
+ for i in range(self.length):
287
+ pt = self._ith_point(i)
288
+ yield self.coeff(pt)
289
+
290
+ def __getitem__(self, index):
291
+ if isinstance(index, int):
292
+ index = self._ith_point(index)
293
+ return self.coeff(index)
294
+ elif isinstance(index, slice):
295
+ start, stop = index.start, index.stop
296
+ if start is None:
297
+ start = 0
298
+ if stop is None:
299
+ stop = self.length
300
+ return [self.coeff(self._ith_point(i)) for i in
301
+ range(start, stop, index.step or 1)]
302
+
303
+ def find_linear_recurrence(self,n,d=None,gfvar=None):
304
+ r"""
305
+ Finds the shortest linear recurrence that satisfies the first n
306
+ terms of sequence of order `\leq` ``n/2`` if possible.
307
+ If ``d`` is specified, find shortest linear recurrence of order
308
+ `\leq` min(d, n/2) if possible.
309
+ Returns list of coefficients ``[b(1), b(2), ...]`` corresponding to the
310
+ recurrence relation ``x(n) = b(1)*x(n-1) + b(2)*x(n-2) + ...``
311
+ Returns ``[]`` if no recurrence is found.
312
+ If gfvar is specified, also returns ordinary generating function as a
313
+ function of gfvar.
314
+
315
+ Examples
316
+ ========
317
+
318
+ >>> from sympy import sequence, sqrt, oo, lucas
319
+ >>> from sympy.abc import n, x, y
320
+ >>> sequence(n**2).find_linear_recurrence(10, 2)
321
+ []
322
+ >>> sequence(n**2).find_linear_recurrence(10)
323
+ [3, -3, 1]
324
+ >>> sequence(2**n).find_linear_recurrence(10)
325
+ [2]
326
+ >>> sequence(23*n**4+91*n**2).find_linear_recurrence(10)
327
+ [5, -10, 10, -5, 1]
328
+ >>> sequence(sqrt(5)*(((1 + sqrt(5))/2)**n - (-(1 + sqrt(5))/2)**(-n))/5).find_linear_recurrence(10)
329
+ [1, 1]
330
+ >>> sequence(x+y*(-2)**(-n), (n, 0, oo)).find_linear_recurrence(30)
331
+ [1/2, 1/2]
332
+ >>> sequence(3*5**n + 12).find_linear_recurrence(20,gfvar=x)
333
+ ([6, -5], 3*(5 - 21*x)/((x - 1)*(5*x - 1)))
334
+ >>> sequence(lucas(n)).find_linear_recurrence(15,gfvar=x)
335
+ ([1, 1], (x - 2)/(x**2 + x - 1))
336
+ """
337
+ from sympy.simplify import simplify
338
+ x = [simplify(expand(t)) for t in self[:n]]
339
+ lx = len(x)
340
+ if d is None:
341
+ r = lx//2
342
+ else:
343
+ r = min(d,lx//2)
344
+ coeffs = []
345
+ for l in range(1, r+1):
346
+ l2 = 2*l
347
+ mlist = []
348
+ for k in range(l):
349
+ mlist.append(x[k:k+l])
350
+ m = Matrix(mlist)
351
+ if m.det() != 0:
352
+ y = simplify(m.LUsolve(Matrix(x[l:l2])))
353
+ if lx == l2:
354
+ coeffs = flatten(y[::-1])
355
+ break
356
+ mlist = []
357
+ for k in range(l,lx-l):
358
+ mlist.append(x[k:k+l])
359
+ m = Matrix(mlist)
360
+ if m*y == Matrix(x[l2:]):
361
+ coeffs = flatten(y[::-1])
362
+ break
363
+ if gfvar is None:
364
+ return coeffs
365
+ else:
366
+ l = len(coeffs)
367
+ if l == 0:
368
+ return [], None
369
+ else:
370
+ n, d = x[l-1]*gfvar**(l-1), 1 - coeffs[l-1]*gfvar**l
371
+ for i in range(l-1):
372
+ n += x[i]*gfvar**i
373
+ for j in range(l-i-1):
374
+ n -= coeffs[i]*x[j]*gfvar**(i+j+1)
375
+ d -= coeffs[i]*gfvar**(i+1)
376
+ return coeffs, simplify(factor(n)/factor(d))
377
+
378
+ class EmptySequence(SeqBase, metaclass=Singleton):
379
+ """Represents an empty sequence.
380
+
381
+ The empty sequence is also available as a singleton as
382
+ ``S.EmptySequence``.
383
+
384
+ Examples
385
+ ========
386
+
387
+ >>> from sympy import EmptySequence, SeqPer
388
+ >>> from sympy.abc import x
389
+ >>> EmptySequence
390
+ EmptySequence
391
+ >>> SeqPer((1, 2), (x, 0, 10)) + EmptySequence
392
+ SeqPer((1, 2), (x, 0, 10))
393
+ >>> SeqPer((1, 2)) * EmptySequence
394
+ EmptySequence
395
+ >>> EmptySequence.coeff_mul(-1)
396
+ EmptySequence
397
+ """
398
+
399
+ @property
400
+ def interval(self):
401
+ return S.EmptySet
402
+
403
+ @property
404
+ def length(self):
405
+ return S.Zero
406
+
407
+ def coeff_mul(self, coeff):
408
+ """See docstring of SeqBase.coeff_mul"""
409
+ return self
410
+
411
+ def __iter__(self):
412
+ return iter([])
413
+
414
+
415
+ class SeqExpr(SeqBase):
416
+ """Sequence expression class.
417
+
418
+ Various sequences should inherit from this class.
419
+
420
+ Examples
421
+ ========
422
+
423
+ >>> from sympy.series.sequences import SeqExpr
424
+ >>> from sympy.abc import x
425
+ >>> from sympy import Tuple
426
+ >>> s = SeqExpr(Tuple(1, 2, 3), Tuple(x, 0, 10))
427
+ >>> s.gen
428
+ (1, 2, 3)
429
+ >>> s.interval
430
+ Interval(0, 10)
431
+ >>> s.length
432
+ 11
433
+
434
+ See Also
435
+ ========
436
+
437
+ sympy.series.sequences.SeqPer
438
+ sympy.series.sequences.SeqFormula
439
+ """
440
+
441
+ @property
442
+ def gen(self):
443
+ return self.args[0]
444
+
445
+ @property
446
+ def interval(self):
447
+ return Interval(self.args[1][1], self.args[1][2])
448
+
449
+ @property
450
+ def start(self):
451
+ return self.interval.inf
452
+
453
+ @property
454
+ def stop(self):
455
+ return self.interval.sup
456
+
457
+ @property
458
+ def length(self):
459
+ return self.stop - self.start + 1
460
+
461
+ @property
462
+ def variables(self):
463
+ return (self.args[1][0],)
464
+
465
+
466
+ class SeqPer(SeqExpr):
467
+ """
468
+ Represents a periodic sequence.
469
+
470
+ The elements are repeated after a given period.
471
+
472
+ Examples
473
+ ========
474
+
475
+ >>> from sympy import SeqPer, oo
476
+ >>> from sympy.abc import k
477
+
478
+ >>> s = SeqPer((1, 2, 3), (0, 5))
479
+ >>> s.periodical
480
+ (1, 2, 3)
481
+ >>> s.period
482
+ 3
483
+
484
+ For value at a particular point
485
+
486
+ >>> s.coeff(3)
487
+ 1
488
+
489
+ supports slicing
490
+
491
+ >>> s[:]
492
+ [1, 2, 3, 1, 2, 3]
493
+
494
+ iterable
495
+
496
+ >>> list(s)
497
+ [1, 2, 3, 1, 2, 3]
498
+
499
+ sequence starts from negative infinity
500
+
501
+ >>> SeqPer((1, 2, 3), (-oo, 0))[0:6]
502
+ [1, 2, 3, 1, 2, 3]
503
+
504
+ Periodic formulas
505
+
506
+ >>> SeqPer((k, k**2, k**3), (k, 0, oo))[0:6]
507
+ [0, 1, 8, 3, 16, 125]
508
+
509
+ See Also
510
+ ========
511
+
512
+ sympy.series.sequences.SeqFormula
513
+ """
514
+
515
+ def __new__(cls, periodical, limits=None):
516
+ periodical = sympify(periodical)
517
+
518
+ def _find_x(periodical):
519
+ free = periodical.free_symbols
520
+ if len(periodical.free_symbols) == 1:
521
+ return free.pop()
522
+ else:
523
+ return Dummy('k')
524
+
525
+ x, start, stop = None, None, None
526
+ if limits is None:
527
+ x, start, stop = _find_x(periodical), 0, S.Infinity
528
+ if is_sequence(limits, Tuple):
529
+ if len(limits) == 3:
530
+ x, start, stop = limits
531
+ elif len(limits) == 2:
532
+ x = _find_x(periodical)
533
+ start, stop = limits
534
+
535
+ if not isinstance(x, (Symbol, Idx)) or start is None or stop is None:
536
+ raise ValueError('Invalid limits given: %s' % str(limits))
537
+
538
+ if start is S.NegativeInfinity and stop is S.Infinity:
539
+ raise ValueError("Both the start and end value"
540
+ "cannot be unbounded")
541
+
542
+ limits = sympify((x, start, stop))
543
+
544
+ if is_sequence(periodical, Tuple):
545
+ periodical = sympify(tuple(flatten(periodical)))
546
+ else:
547
+ raise ValueError("invalid period %s should be something "
548
+ "like e.g (1, 2) " % periodical)
549
+
550
+ if Interval(limits[1], limits[2]) is S.EmptySet:
551
+ return S.EmptySequence
552
+
553
+ return Basic.__new__(cls, periodical, limits)
554
+
555
+ @property
556
+ def period(self):
557
+ return len(self.gen)
558
+
559
+ @property
560
+ def periodical(self):
561
+ return self.gen
562
+
563
+ def _eval_coeff(self, pt):
564
+ if self.start is S.NegativeInfinity:
565
+ idx = (self.stop - pt) % self.period
566
+ else:
567
+ idx = (pt - self.start) % self.period
568
+ return self.periodical[idx].subs(self.variables[0], pt)
569
+
570
+ def _add(self, other):
571
+ """See docstring of SeqBase._add"""
572
+ if isinstance(other, SeqPer):
573
+ per1, lper1 = self.periodical, self.period
574
+ per2, lper2 = other.periodical, other.period
575
+
576
+ per_length = lcm(lper1, lper2)
577
+
578
+ new_per = []
579
+ for x in range(per_length):
580
+ ele1 = per1[x % lper1]
581
+ ele2 = per2[x % lper2]
582
+ new_per.append(ele1 + ele2)
583
+
584
+ start, stop = self._intersect_interval(other)
585
+ return SeqPer(new_per, (self.variables[0], start, stop))
586
+
587
+ def _mul(self, other):
588
+ """See docstring of SeqBase._mul"""
589
+ if isinstance(other, SeqPer):
590
+ per1, lper1 = self.periodical, self.period
591
+ per2, lper2 = other.periodical, other.period
592
+
593
+ per_length = lcm(lper1, lper2)
594
+
595
+ new_per = []
596
+ for x in range(per_length):
597
+ ele1 = per1[x % lper1]
598
+ ele2 = per2[x % lper2]
599
+ new_per.append(ele1 * ele2)
600
+
601
+ start, stop = self._intersect_interval(other)
602
+ return SeqPer(new_per, (self.variables[0], start, stop))
603
+
604
+ def coeff_mul(self, coeff):
605
+ """See docstring of SeqBase.coeff_mul"""
606
+ coeff = sympify(coeff)
607
+ per = [x * coeff for x in self.periodical]
608
+ return SeqPer(per, self.args[1])
609
+
610
+
611
+ class SeqFormula(SeqExpr):
612
+ """
613
+ Represents sequence based on a formula.
614
+
615
+ Elements are generated using a formula.
616
+
617
+ Examples
618
+ ========
619
+
620
+ >>> from sympy import SeqFormula, oo, Symbol
621
+ >>> n = Symbol('n')
622
+ >>> s = SeqFormula(n**2, (n, 0, 5))
623
+ >>> s.formula
624
+ n**2
625
+
626
+ For value at a particular point
627
+
628
+ >>> s.coeff(3)
629
+ 9
630
+
631
+ supports slicing
632
+
633
+ >>> s[:]
634
+ [0, 1, 4, 9, 16, 25]
635
+
636
+ iterable
637
+
638
+ >>> list(s)
639
+ [0, 1, 4, 9, 16, 25]
640
+
641
+ sequence starts from negative infinity
642
+
643
+ >>> SeqFormula(n**2, (-oo, 0))[0:6]
644
+ [0, 1, 4, 9, 16, 25]
645
+
646
+ See Also
647
+ ========
648
+
649
+ sympy.series.sequences.SeqPer
650
+ """
651
+
652
+ def __new__(cls, formula, limits=None):
653
+ formula = sympify(formula)
654
+
655
+ def _find_x(formula):
656
+ free = formula.free_symbols
657
+ if len(free) == 1:
658
+ return free.pop()
659
+ elif not free:
660
+ return Dummy('k')
661
+ else:
662
+ raise ValueError(
663
+ " specify dummy variables for %s. If the formula contains"
664
+ " more than one free symbol, a dummy variable should be"
665
+ " supplied explicitly e.g., SeqFormula(m*n**2, (n, 0, 5))"
666
+ % formula)
667
+
668
+ x, start, stop = None, None, None
669
+ if limits is None:
670
+ x, start, stop = _find_x(formula), 0, S.Infinity
671
+ if is_sequence(limits, Tuple):
672
+ if len(limits) == 3:
673
+ x, start, stop = limits
674
+ elif len(limits) == 2:
675
+ x = _find_x(formula)
676
+ start, stop = limits
677
+
678
+ if not isinstance(x, (Symbol, Idx)) or start is None or stop is None:
679
+ raise ValueError('Invalid limits given: %s' % str(limits))
680
+
681
+ if start is S.NegativeInfinity and stop is S.Infinity:
682
+ raise ValueError("Both the start and end value "
683
+ "cannot be unbounded")
684
+ limits = sympify((x, start, stop))
685
+
686
+ if Interval(limits[1], limits[2]) is S.EmptySet:
687
+ return S.EmptySequence
688
+
689
+ return Basic.__new__(cls, formula, limits)
690
+
691
+ @property
692
+ def formula(self):
693
+ return self.gen
694
+
695
+ def _eval_coeff(self, pt):
696
+ d = self.variables[0]
697
+ return self.formula.subs(d, pt)
698
+
699
+ def _add(self, other):
700
+ """See docstring of SeqBase._add"""
701
+ if isinstance(other, SeqFormula):
702
+ form1, v1 = self.formula, self.variables[0]
703
+ form2, v2 = other.formula, other.variables[0]
704
+ formula = form1 + form2.subs(v2, v1)
705
+ start, stop = self._intersect_interval(other)
706
+ return SeqFormula(formula, (v1, start, stop))
707
+
708
+ def _mul(self, other):
709
+ """See docstring of SeqBase._mul"""
710
+ if isinstance(other, SeqFormula):
711
+ form1, v1 = self.formula, self.variables[0]
712
+ form2, v2 = other.formula, other.variables[0]
713
+ formula = form1 * form2.subs(v2, v1)
714
+ start, stop = self._intersect_interval(other)
715
+ return SeqFormula(formula, (v1, start, stop))
716
+
717
+ def coeff_mul(self, coeff):
718
+ """See docstring of SeqBase.coeff_mul"""
719
+ coeff = sympify(coeff)
720
+ formula = self.formula * coeff
721
+ return SeqFormula(formula, self.args[1])
722
+
723
+ def expand(self, *args, **kwargs):
724
+ return SeqFormula(expand(self.formula, *args, **kwargs), self.args[1])
725
+
726
+ class RecursiveSeq(SeqBase):
727
+ """
728
+ A finite degree recursive sequence.
729
+
730
+ Explanation
731
+ ===========
732
+
733
+ That is, a sequence a(n) that depends on a fixed, finite number of its
734
+ previous values. The general form is
735
+
736
+ a(n) = f(a(n - 1), a(n - 2), ..., a(n - d))
737
+
738
+ for some fixed, positive integer d, where f is some function defined by a
739
+ SymPy expression.
740
+
741
+ Parameters
742
+ ==========
743
+
744
+ recurrence : SymPy expression defining recurrence
745
+ This is *not* an equality, only the expression that the nth term is
746
+ equal to. For example, if :code:`a(n) = f(a(n - 1), ..., a(n - d))`,
747
+ then the expression should be :code:`f(a(n - 1), ..., a(n - d))`.
748
+
749
+ yn : applied undefined function
750
+ Represents the nth term of the sequence as e.g. :code:`y(n)` where
751
+ :code:`y` is an undefined function and `n` is the sequence index.
752
+
753
+ n : symbolic argument
754
+ The name of the variable that the recurrence is in, e.g., :code:`n` if
755
+ the recurrence function is :code:`y(n)`.
756
+
757
+ initial : iterable with length equal to the degree of the recurrence
758
+ The initial values of the recurrence.
759
+
760
+ start : start value of sequence (inclusive)
761
+
762
+ Examples
763
+ ========
764
+
765
+ >>> from sympy import Function, symbols
766
+ >>> from sympy.series.sequences import RecursiveSeq
767
+ >>> y = Function("y")
768
+ >>> n = symbols("n")
769
+ >>> fib = RecursiveSeq(y(n - 1) + y(n - 2), y(n), n, [0, 1])
770
+
771
+ >>> fib.coeff(3) # Value at a particular point
772
+ 2
773
+
774
+ >>> fib[:6] # supports slicing
775
+ [0, 1, 1, 2, 3, 5]
776
+
777
+ >>> fib.recurrence # inspect recurrence
778
+ Eq(y(n), y(n - 2) + y(n - 1))
779
+
780
+ >>> fib.degree # automatically determine degree
781
+ 2
782
+
783
+ >>> for x in zip(range(10), fib): # supports iteration
784
+ ... print(x)
785
+ (0, 0)
786
+ (1, 1)
787
+ (2, 1)
788
+ (3, 2)
789
+ (4, 3)
790
+ (5, 5)
791
+ (6, 8)
792
+ (7, 13)
793
+ (8, 21)
794
+ (9, 34)
795
+
796
+ See Also
797
+ ========
798
+
799
+ sympy.series.sequences.SeqFormula
800
+
801
+ """
802
+
803
+ def __new__(cls, recurrence, yn, n, initial=None, start=0):
804
+ if not isinstance(yn, AppliedUndef):
805
+ raise TypeError("recurrence sequence must be an applied undefined function"
806
+ ", found `{}`".format(yn))
807
+
808
+ if not isinstance(n, Basic) or not n.is_symbol:
809
+ raise TypeError("recurrence variable must be a symbol"
810
+ ", found `{}`".format(n))
811
+
812
+ if yn.args != (n,):
813
+ raise TypeError("recurrence sequence does not match symbol")
814
+
815
+ y = yn.func
816
+
817
+ k = Wild("k", exclude=(n,))
818
+ degree = 0
819
+
820
+ # Find all applications of y in the recurrence and check that:
821
+ # 1. The function y is only being used with a single argument; and
822
+ # 2. All arguments are n + k for constant negative integers k.
823
+
824
+ prev_ys = recurrence.find(y)
825
+ for prev_y in prev_ys:
826
+ if len(prev_y.args) != 1:
827
+ raise TypeError("Recurrence should be in a single variable")
828
+
829
+ shift = prev_y.args[0].match(n + k)[k]
830
+ if not (shift.is_constant() and shift.is_integer and shift < 0):
831
+ raise TypeError("Recurrence should have constant,"
832
+ " negative, integer shifts"
833
+ " (found {})".format(prev_y))
834
+
835
+ if -shift > degree:
836
+ degree = -shift
837
+
838
+ if not initial:
839
+ initial = [Dummy("c_{}".format(k)) for k in range(degree)]
840
+
841
+ if len(initial) != degree:
842
+ raise ValueError("Number of initial terms must equal degree")
843
+
844
+ degree = Integer(degree)
845
+ start = sympify(start)
846
+
847
+ initial = Tuple(*(sympify(x) for x in initial))
848
+
849
+ seq = Basic.__new__(cls, recurrence, yn, n, initial, start)
850
+
851
+ seq.cache = {y(start + k): init for k, init in enumerate(initial)}
852
+ seq.degree = degree
853
+
854
+ return seq
855
+
856
+ @property
857
+ def _recurrence(self):
858
+ """Equation defining recurrence."""
859
+ return self.args[0]
860
+
861
+ @property
862
+ def recurrence(self):
863
+ """Equation defining recurrence."""
864
+ return Eq(self.yn, self.args[0])
865
+
866
+ @property
867
+ def yn(self):
868
+ """Applied function representing the nth term"""
869
+ return self.args[1]
870
+
871
+ @property
872
+ def y(self):
873
+ """Undefined function for the nth term of the sequence"""
874
+ return self.yn.func
875
+
876
+ @property
877
+ def n(self):
878
+ """Sequence index symbol"""
879
+ return self.args[2]
880
+
881
+ @property
882
+ def initial(self):
883
+ """The initial values of the sequence"""
884
+ return self.args[3]
885
+
886
+ @property
887
+ def start(self):
888
+ """The starting point of the sequence. This point is included"""
889
+ return self.args[4]
890
+
891
+ @property
892
+ def stop(self):
893
+ """The ending point of the sequence. (oo)"""
894
+ return S.Infinity
895
+
896
+ @property
897
+ def interval(self):
898
+ """Interval on which sequence is defined."""
899
+ return (self.start, S.Infinity)
900
+
901
+ def _eval_coeff(self, index):
902
+ if index - self.start < len(self.cache):
903
+ return self.cache[self.y(index)]
904
+
905
+ for current in range(len(self.cache), index + 1):
906
+ # Use xreplace over subs for performance.
907
+ # See issue #10697.
908
+ seq_index = self.start + current
909
+ current_recurrence = self._recurrence.xreplace({self.n: seq_index})
910
+ new_term = current_recurrence.xreplace(self.cache)
911
+
912
+ self.cache[self.y(seq_index)] = new_term
913
+
914
+ return self.cache[self.y(self.start + current)]
915
+
916
+ def __iter__(self):
917
+ index = self.start
918
+ while True:
919
+ yield self._eval_coeff(index)
920
+ index += 1
921
+
922
+
923
+ def sequence(seq, limits=None):
924
+ """
925
+ Returns appropriate sequence object.
926
+
927
+ Explanation
928
+ ===========
929
+
930
+ If ``seq`` is a SymPy sequence, returns :class:`SeqPer` object
931
+ otherwise returns :class:`SeqFormula` object.
932
+
933
+ Examples
934
+ ========
935
+
936
+ >>> from sympy import sequence
937
+ >>> from sympy.abc import n
938
+ >>> sequence(n**2, (n, 0, 5))
939
+ SeqFormula(n**2, (n, 0, 5))
940
+ >>> sequence((1, 2, 3), (n, 0, 5))
941
+ SeqPer((1, 2, 3), (n, 0, 5))
942
+
943
+ See Also
944
+ ========
945
+
946
+ sympy.series.sequences.SeqPer
947
+ sympy.series.sequences.SeqFormula
948
+ """
949
+ seq = sympify(seq)
950
+
951
+ if is_sequence(seq, Tuple):
952
+ return SeqPer(seq, limits)
953
+ else:
954
+ return SeqFormula(seq, limits)
955
+
956
+
957
+ ###############################################################################
958
+ # OPERATIONS #
959
+ ###############################################################################
960
+
961
+
962
+ class SeqExprOp(SeqBase):
963
+ """
964
+ Base class for operations on sequences.
965
+
966
+ Examples
967
+ ========
968
+
969
+ >>> from sympy.series.sequences import SeqExprOp, sequence
970
+ >>> from sympy.abc import n
971
+ >>> s1 = sequence(n**2, (n, 0, 10))
972
+ >>> s2 = sequence((1, 2, 3), (n, 5, 10))
973
+ >>> s = SeqExprOp(s1, s2)
974
+ >>> s.gen
975
+ (n**2, (1, 2, 3))
976
+ >>> s.interval
977
+ Interval(5, 10)
978
+ >>> s.length
979
+ 6
980
+
981
+ See Also
982
+ ========
983
+
984
+ sympy.series.sequences.SeqAdd
985
+ sympy.series.sequences.SeqMul
986
+ """
987
+ @property
988
+ def gen(self):
989
+ """Generator for the sequence.
990
+
991
+ returns a tuple of generators of all the argument sequences.
992
+ """
993
+ return tuple(a.gen for a in self.args)
994
+
995
+ @property
996
+ def interval(self):
997
+ """Sequence is defined on the intersection
998
+ of all the intervals of respective sequences
999
+ """
1000
+ return Intersection(*(a.interval for a in self.args))
1001
+
1002
+ @property
1003
+ def start(self):
1004
+ return self.interval.inf
1005
+
1006
+ @property
1007
+ def stop(self):
1008
+ return self.interval.sup
1009
+
1010
+ @property
1011
+ def variables(self):
1012
+ """Cumulative of all the bound variables"""
1013
+ return tuple(flatten([a.variables for a in self.args]))
1014
+
1015
+ @property
1016
+ def length(self):
1017
+ return self.stop - self.start + 1
1018
+
1019
+
1020
+ class SeqAdd(SeqExprOp):
1021
+ """Represents term-wise addition of sequences.
1022
+
1023
+ Rules:
1024
+ * The interval on which sequence is defined is the intersection
1025
+ of respective intervals of sequences.
1026
+ * Anything + :class:`EmptySequence` remains unchanged.
1027
+ * Other rules are defined in ``_add`` methods of sequence classes.
1028
+
1029
+ Examples
1030
+ ========
1031
+
1032
+ >>> from sympy import EmptySequence, oo, SeqAdd, SeqPer, SeqFormula
1033
+ >>> from sympy.abc import n
1034
+ >>> SeqAdd(SeqPer((1, 2), (n, 0, oo)), EmptySequence)
1035
+ SeqPer((1, 2), (n, 0, oo))
1036
+ >>> SeqAdd(SeqPer((1, 2), (n, 0, 5)), SeqPer((1, 2), (n, 6, 10)))
1037
+ EmptySequence
1038
+ >>> SeqAdd(SeqPer((1, 2), (n, 0, oo)), SeqFormula(n**2, (n, 0, oo)))
1039
+ SeqAdd(SeqFormula(n**2, (n, 0, oo)), SeqPer((1, 2), (n, 0, oo)))
1040
+ >>> SeqAdd(SeqFormula(n**3), SeqFormula(n**2))
1041
+ SeqFormula(n**3 + n**2, (n, 0, oo))
1042
+
1043
+ See Also
1044
+ ========
1045
+
1046
+ sympy.series.sequences.SeqMul
1047
+ """
1048
+
1049
+ def __new__(cls, *args, **kwargs):
1050
+ evaluate = kwargs.get('evaluate', global_parameters.evaluate)
1051
+
1052
+ # flatten inputs
1053
+ args = list(args)
1054
+
1055
+ # adapted from sympy.sets.sets.Union
1056
+ def _flatten(arg):
1057
+ if isinstance(arg, SeqBase):
1058
+ if isinstance(arg, SeqAdd):
1059
+ return sum(map(_flatten, arg.args), [])
1060
+ else:
1061
+ return [arg]
1062
+ if iterable(arg):
1063
+ return sum(map(_flatten, arg), [])
1064
+ raise TypeError("Input must be Sequences or "
1065
+ " iterables of Sequences")
1066
+ args = _flatten(args)
1067
+
1068
+ args = [a for a in args if a is not S.EmptySequence]
1069
+
1070
+ # Addition of no sequences is EmptySequence
1071
+ if not args:
1072
+ return S.EmptySequence
1073
+
1074
+ if Intersection(*(a.interval for a in args)) is S.EmptySet:
1075
+ return S.EmptySequence
1076
+
1077
+ # reduce using known rules
1078
+ if evaluate:
1079
+ return SeqAdd.reduce(args)
1080
+
1081
+ args = list(ordered(args, SeqBase._start_key))
1082
+
1083
+ return Basic.__new__(cls, *args)
1084
+
1085
+ @staticmethod
1086
+ def reduce(args):
1087
+ """Simplify :class:`SeqAdd` using known rules.
1088
+
1089
+ Iterates through all pairs and ask the constituent
1090
+ sequences if they can simplify themselves with any other constituent.
1091
+
1092
+ Notes
1093
+ =====
1094
+
1095
+ adapted from ``Union.reduce``
1096
+
1097
+ """
1098
+ new_args = True
1099
+ while new_args:
1100
+ for id1, s in enumerate(args):
1101
+ new_args = False
1102
+ for id2, t in enumerate(args):
1103
+ if id1 == id2:
1104
+ continue
1105
+ new_seq = s._add(t)
1106
+ # This returns None if s does not know how to add
1107
+ # with t. Returns the newly added sequence otherwise
1108
+ if new_seq is not None:
1109
+ new_args = [a for a in args if a not in (s, t)]
1110
+ new_args.append(new_seq)
1111
+ break
1112
+ if new_args:
1113
+ args = new_args
1114
+ break
1115
+
1116
+ if len(args) == 1:
1117
+ return args.pop()
1118
+ else:
1119
+ return SeqAdd(args, evaluate=False)
1120
+
1121
+ def _eval_coeff(self, pt):
1122
+ """adds up the coefficients of all the sequences at point pt"""
1123
+ return sum(a.coeff(pt) for a in self.args)
1124
+
1125
+
1126
+ class SeqMul(SeqExprOp):
1127
+ r"""Represents term-wise multiplication of sequences.
1128
+
1129
+ Explanation
1130
+ ===========
1131
+
1132
+ Handles multiplication of sequences only. For multiplication
1133
+ with other objects see :func:`SeqBase.coeff_mul`.
1134
+
1135
+ Rules:
1136
+ * The interval on which sequence is defined is the intersection
1137
+ of respective intervals of sequences.
1138
+ * Anything \* :class:`EmptySequence` returns :class:`EmptySequence`.
1139
+ * Other rules are defined in ``_mul`` methods of sequence classes.
1140
+
1141
+ Examples
1142
+ ========
1143
+
1144
+ >>> from sympy import EmptySequence, oo, SeqMul, SeqPer, SeqFormula
1145
+ >>> from sympy.abc import n
1146
+ >>> SeqMul(SeqPer((1, 2), (n, 0, oo)), EmptySequence)
1147
+ EmptySequence
1148
+ >>> SeqMul(SeqPer((1, 2), (n, 0, 5)), SeqPer((1, 2), (n, 6, 10)))
1149
+ EmptySequence
1150
+ >>> SeqMul(SeqPer((1, 2), (n, 0, oo)), SeqFormula(n**2))
1151
+ SeqMul(SeqFormula(n**2, (n, 0, oo)), SeqPer((1, 2), (n, 0, oo)))
1152
+ >>> SeqMul(SeqFormula(n**3), SeqFormula(n**2))
1153
+ SeqFormula(n**5, (n, 0, oo))
1154
+
1155
+ See Also
1156
+ ========
1157
+
1158
+ sympy.series.sequences.SeqAdd
1159
+ """
1160
+
1161
+ def __new__(cls, *args, **kwargs):
1162
+ evaluate = kwargs.get('evaluate', global_parameters.evaluate)
1163
+
1164
+ # flatten inputs
1165
+ args = list(args)
1166
+
1167
+ # adapted from sympy.sets.sets.Union
1168
+ def _flatten(arg):
1169
+ if isinstance(arg, SeqBase):
1170
+ if isinstance(arg, SeqMul):
1171
+ return sum(map(_flatten, arg.args), [])
1172
+ else:
1173
+ return [arg]
1174
+ elif iterable(arg):
1175
+ return sum(map(_flatten, arg), [])
1176
+ raise TypeError("Input must be Sequences or "
1177
+ " iterables of Sequences")
1178
+ args = _flatten(args)
1179
+
1180
+ # Multiplication of no sequences is EmptySequence
1181
+ if not args:
1182
+ return S.EmptySequence
1183
+
1184
+ if Intersection(*(a.interval for a in args)) is S.EmptySet:
1185
+ return S.EmptySequence
1186
+
1187
+ # reduce using known rules
1188
+ if evaluate:
1189
+ return SeqMul.reduce(args)
1190
+
1191
+ args = list(ordered(args, SeqBase._start_key))
1192
+
1193
+ return Basic.__new__(cls, *args)
1194
+
1195
+ @staticmethod
1196
+ def reduce(args):
1197
+ """Simplify a :class:`SeqMul` using known rules.
1198
+
1199
+ Explanation
1200
+ ===========
1201
+
1202
+ Iterates through all pairs and ask the constituent
1203
+ sequences if they can simplify themselves with any other constituent.
1204
+
1205
+ Notes
1206
+ =====
1207
+
1208
+ adapted from ``Union.reduce``
1209
+
1210
+ """
1211
+ new_args = True
1212
+ while new_args:
1213
+ for id1, s in enumerate(args):
1214
+ new_args = False
1215
+ for id2, t in enumerate(args):
1216
+ if id1 == id2:
1217
+ continue
1218
+ new_seq = s._mul(t)
1219
+ # This returns None if s does not know how to multiply
1220
+ # with t. Returns the newly multiplied sequence otherwise
1221
+ if new_seq is not None:
1222
+ new_args = [a for a in args if a not in (s, t)]
1223
+ new_args.append(new_seq)
1224
+ break
1225
+ if new_args:
1226
+ args = new_args
1227
+ break
1228
+
1229
+ if len(args) == 1:
1230
+ return args.pop()
1231
+ else:
1232
+ return SeqMul(args, evaluate=False)
1233
+
1234
+ def _eval_coeff(self, pt):
1235
+ """multiplies the coefficients of all the sequences at point pt"""
1236
+ val = 1
1237
+ for a in self.args:
1238
+ val *= a.coeff(pt)
1239
+ return val
outputs/audit_venv/lib/python3.11/site-packages/sympy/series/series.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.sympify import sympify
2
+
3
+
4
+ def series(expr, x=None, x0=0, n=6, dir="+"):
5
+ """Series expansion of expr around point `x = x0`.
6
+
7
+ Parameters
8
+ ==========
9
+
10
+ expr : Expression
11
+ The expression whose series is to be expanded.
12
+
13
+ x : Symbol
14
+ It is the variable of the expression to be calculated.
15
+
16
+ x0 : Value
17
+ The value around which ``x`` is calculated. Can be any value
18
+ from ``-oo`` to ``oo``.
19
+
20
+ n : Value
21
+ The number of terms upto which the series is to be expanded.
22
+
23
+ dir : String, optional
24
+ The series-expansion can be bi-directional. If ``dir="+"``,
25
+ then (x->x0+). If ``dir="-"``, then (x->x0-). For infinite
26
+ ``x0`` (``oo`` or ``-oo``), the ``dir`` argument is determined
27
+ from the direction of the infinity (i.e., ``dir="-"`` for
28
+ ``oo``).
29
+
30
+ Examples
31
+ ========
32
+
33
+ >>> from sympy import series, tan, oo
34
+ >>> from sympy.abc import x
35
+ >>> f = tan(x)
36
+ >>> series(f, x, 2, 6, "+")
37
+ tan(2) + (1 + tan(2)**2)*(x - 2) + (x - 2)**2*(tan(2)**3 + tan(2)) +
38
+ (x - 2)**3*(1/3 + 4*tan(2)**2/3 + tan(2)**4) + (x - 2)**4*(tan(2)**5 +
39
+ 5*tan(2)**3/3 + 2*tan(2)/3) + (x - 2)**5*(2/15 + 17*tan(2)**2/15 +
40
+ 2*tan(2)**4 + tan(2)**6) + O((x - 2)**6, (x, 2))
41
+
42
+ >>> series(f, x, 2, 3, "-")
43
+ tan(2) + (2 - x)*(-tan(2)**2 - 1) + (2 - x)**2*(tan(2)**3 + tan(2))
44
+ + O((x - 2)**3, (x, 2))
45
+
46
+ >>> series(f, x, 2, oo, "+")
47
+ Traceback (most recent call last):
48
+ ...
49
+ TypeError: 'Infinity' object cannot be interpreted as an integer
50
+
51
+ Returns
52
+ =======
53
+
54
+ Expr
55
+ Series expansion of the expression about x0
56
+
57
+ See Also
58
+ ========
59
+
60
+ sympy.core.expr.Expr.series: See the docstring of Expr.series() for complete details of this wrapper.
61
+ """
62
+ expr = sympify(expr)
63
+ return expr.series(x, x0, n, dir)