Auto-sync: 2026-06-25 22:43:25 (part 16)
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/AUTHORS +1379 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/INSTALLER +1 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/LICENSE +153 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/METADATA +34 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/RECORD +0 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/WHEEL +5 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/entry_points.txt +2 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy-1.14.0+computecanada.dist-info/top_level.txt +2 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_mathematica.py +287 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_mathml.py +0 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_numpy.py +381 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_octave.py +515 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_precedence.py +128 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_preview.py +38 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_pycode.py +493 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_python.py +203 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_rcode.py +476 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_repr.py +382 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_rust.py +363 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_smtlib.py +553 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_str.py +1206 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_tableform.py +182 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_tensorflow.py +493 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_theanocode.py +639 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_torch.py +531 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tests/test_tree.py +196 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/theanocode.py +571 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/printing/tree.py +175 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/release.py +1 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/sandbox/__init__.py +8 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/sandbox/indexed_integrals.py +72 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/sandbox/tests/__init__.py +0 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/sandbox/tests/test_indexed_integrals.py +25 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/series/__init__.py +23 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/series/acceleration.py +101 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/series/approximants.py +103 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/series/aseries.py +10 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/series/benchmarks/__init__.py +0 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/series/benchmarks/bench_limit.py +9 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/series/benchmarks/bench_order.py +10 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/series/formal.py +1863 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/series/fourier.py +811 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/series/gruntz.py +701 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/series/kauers.py +51 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/series/limits.py +394 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/series/limitseq.py +257 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/series/order.py +522 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/series/residues.py +73 -0
- outputs/audit_venv/lib/python3.11/site-packages/sympy/series/sequences.py +1239 -0
- 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)
|