Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +3 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/Cython/Compiler/__pycache__/ExprNodes.cpython-311.pyc +3 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/filelock-3.13.1.dist-info/INSTALLER +1 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/filelock-3.13.1.dist-info/METADATA +56 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/filelock-3.13.1.dist-info/RECORD +22 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/filelock-3.13.1.dist-info/WHEEL +4 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/filelock-3.13.1.dist-info/licenses/LICENSE +24 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/__pycache__/__init__.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/__pycache__/ctx_base.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/__pycache__/ctx_fp.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/__pycache__/ctx_iv.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/__pycache__/ctx_mp_python.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/__pycache__/identification.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/__pycache__/math2.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/__pycache__/rational.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/__pycache__/usertools.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/__pycache__/visualization.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/calculus/__pycache__/__init__.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/calculus/__pycache__/calculus.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/calculus/__pycache__/inverselaplace.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/calculus/__pycache__/odes.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/calculus/__pycache__/optimization.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/calculus/__pycache__/polynomials.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/calculus/inverselaplace.py +973 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/__pycache__/__init__.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/__pycache__/bessel.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/__pycache__/elliptic.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/__pycache__/factorials.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/__pycache__/functions.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/__pycache__/hypergeometric.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/__pycache__/orthogonal.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/__pycache__/rszeta.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/__pycache__/zeta.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/__pycache__/zetazeros.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/orthogonal.py +493 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/matrices/__pycache__/__init__.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/matrices/__pycache__/eigen.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/matrices/__pycache__/eigen_symmetric.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/matrices/__pycache__/linalg.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/matrices/__pycache__/matrices.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/matrices/eigen_symmetric.py +1807 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/tests/__pycache__/test_elliptic.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/packaging-24.2.dist-info/LICENSE.APACHE +177 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/packaging-24.2.dist-info/LICENSE.BSD +23 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/packaging-24.2.dist-info/REQUESTED +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/packaging-24.2.dist-info/WHEEL +4 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-311.pyc +3 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_emoji_codes.cpython-311.pyc +3 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/pybind11/__init__.py +19 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/pybind11/__main__.py +86 -0
.gitattributes
CHANGED
|
@@ -48,3 +48,6 @@ tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/__pyc
|
|
| 48 |
tuning-competition-baseline/.venv/lib/python3.11/site-packages/Cython/Compiler/__pycache__/Optimize.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
| 49 |
tuning-competition-baseline/.venv/lib/python3.11/site-packages/Cython/Tempita/_tempita.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 50 |
tuning-competition-baseline/.venv/lib/python3.11/site-packages/Cython/Plex/Transitions.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
tuning-competition-baseline/.venv/lib/python3.11/site-packages/Cython/Compiler/__pycache__/Optimize.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
| 49 |
tuning-competition-baseline/.venv/lib/python3.11/site-packages/Cython/Tempita/_tempita.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 50 |
tuning-competition-baseline/.venv/lib/python3.11/site-packages/Cython/Plex/Transitions.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 51 |
+
tuning-competition-baseline/.venv/lib/python3.11/site-packages/Cython/Compiler/__pycache__/ExprNodes.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
| 52 |
+
tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
| 53 |
+
tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_emoji_codes.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/Cython/Compiler/__pycache__/ExprNodes.cpython-311.pyc
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4d0a7505b29dcf29db8e842581f65690f6434ea73c26f359db97d5eda40cdff9
|
| 3 |
+
size 759350
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/filelock-3.13.1.dist-info/INSTALLER
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
pip
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/filelock-3.13.1.dist-info/METADATA
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.1
|
| 2 |
+
Name: filelock
|
| 3 |
+
Version: 3.13.1
|
| 4 |
+
Summary: A platform independent file lock.
|
| 5 |
+
Project-URL: Documentation, https://py-filelock.readthedocs.io
|
| 6 |
+
Project-URL: Homepage, https://github.com/tox-dev/py-filelock
|
| 7 |
+
Project-URL: Source, https://github.com/tox-dev/py-filelock
|
| 8 |
+
Project-URL: Tracker, https://github.com/tox-dev/py-filelock/issues
|
| 9 |
+
Maintainer-email: Bernát Gábor <gaborjbernat@gmail.com>
|
| 10 |
+
License-Expression: Unlicense
|
| 11 |
+
License-File: LICENSE
|
| 12 |
+
Keywords: application,cache,directory,log,user
|
| 13 |
+
Classifier: Development Status :: 5 - Production/Stable
|
| 14 |
+
Classifier: Intended Audience :: Developers
|
| 15 |
+
Classifier: License :: OSI Approved :: The Unlicense (Unlicense)
|
| 16 |
+
Classifier: Operating System :: OS Independent
|
| 17 |
+
Classifier: Programming Language :: Python
|
| 18 |
+
Classifier: Programming Language :: Python :: 3 :: Only
|
| 19 |
+
Classifier: Programming Language :: Python :: 3.8
|
| 20 |
+
Classifier: Programming Language :: Python :: 3.9
|
| 21 |
+
Classifier: Programming Language :: Python :: 3.10
|
| 22 |
+
Classifier: Programming Language :: Python :: 3.11
|
| 23 |
+
Classifier: Programming Language :: Python :: 3.12
|
| 24 |
+
Classifier: Topic :: Internet
|
| 25 |
+
Classifier: Topic :: Software Development :: Libraries
|
| 26 |
+
Classifier: Topic :: System
|
| 27 |
+
Requires-Python: >=3.8
|
| 28 |
+
Provides-Extra: docs
|
| 29 |
+
Requires-Dist: furo>=2023.9.10; extra == 'docs'
|
| 30 |
+
Requires-Dist: sphinx-autodoc-typehints!=1.23.4,>=1.24; extra == 'docs'
|
| 31 |
+
Requires-Dist: sphinx>=7.2.6; extra == 'docs'
|
| 32 |
+
Provides-Extra: testing
|
| 33 |
+
Requires-Dist: covdefaults>=2.3; extra == 'testing'
|
| 34 |
+
Requires-Dist: coverage>=7.3.2; extra == 'testing'
|
| 35 |
+
Requires-Dist: diff-cover>=8; extra == 'testing'
|
| 36 |
+
Requires-Dist: pytest-cov>=4.1; extra == 'testing'
|
| 37 |
+
Requires-Dist: pytest-mock>=3.12; extra == 'testing'
|
| 38 |
+
Requires-Dist: pytest-timeout>=2.2; extra == 'testing'
|
| 39 |
+
Requires-Dist: pytest>=7.4.3; extra == 'testing'
|
| 40 |
+
Provides-Extra: typing
|
| 41 |
+
Requires-Dist: typing-extensions>=4.8; python_version < '3.11' and extra == 'typing'
|
| 42 |
+
Description-Content-Type: text/markdown
|
| 43 |
+
|
| 44 |
+
# filelock
|
| 45 |
+
|
| 46 |
+
[](https://pypi.org/project/filelock/)
|
| 47 |
+
[](https://pypi.org/project/filelock/)
|
| 49 |
+
[](https://py-filelock.readthedocs.io/en/latest/?badge=latest)
|
| 51 |
+
[](https://github.com/psf/black)
|
| 53 |
+
[](https://pepy.tech/project/filelock)
|
| 54 |
+
[](https://github.com/tox-dev/py-filelock/actions/workflows/check.yml)
|
| 55 |
+
|
| 56 |
+
For more information checkout the [official documentation](https://py-filelock.readthedocs.io/en/latest/index.html).
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/filelock-3.13.1.dist-info/RECORD
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
filelock-3.13.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
| 2 |
+
filelock-3.13.1.dist-info/METADATA,sha256=gi7LyG-dEuOBZC32wie-OOG0OkPZHABsn9rXvxuQlcA,2784
|
| 3 |
+
filelock-3.13.1.dist-info/RECORD,,
|
| 4 |
+
filelock-3.13.1.dist-info/WHEEL,sha256=9QBuHhg6FNW7lppboF2vKVbCGTVzsFykgRQjjlajrhA,87
|
| 5 |
+
filelock-3.13.1.dist-info/licenses/LICENSE,sha256=iNm062BXnBkew5HKBMFhMFctfu3EqG2qWL8oxuFMm80,1210
|
| 6 |
+
filelock/__init__.py,sha256=wAVZ_9_-3Y14xzzupRk5BTTRewFJekR2vf9oIx4M750,1213
|
| 7 |
+
filelock/__pycache__/__init__.cpython-311.pyc,,
|
| 8 |
+
filelock/__pycache__/_api.cpython-311.pyc,,
|
| 9 |
+
filelock/__pycache__/_error.cpython-311.pyc,,
|
| 10 |
+
filelock/__pycache__/_soft.cpython-311.pyc,,
|
| 11 |
+
filelock/__pycache__/_unix.cpython-311.pyc,,
|
| 12 |
+
filelock/__pycache__/_util.cpython-311.pyc,,
|
| 13 |
+
filelock/__pycache__/_windows.cpython-311.pyc,,
|
| 14 |
+
filelock/__pycache__/version.cpython-311.pyc,,
|
| 15 |
+
filelock/_api.py,sha256=UsVWPEOOgFH1pR_6WMk2b5hWZ7nWhUPT5GZX9WuYaC8,11860
|
| 16 |
+
filelock/_error.py,sha256=-5jMcjTu60YAvAO1UbqDD1GIEjVkwr8xCFwDBtMeYDg,787
|
| 17 |
+
filelock/_soft.py,sha256=haqtc_TB_KJbYv2a8iuEAclKuM4fMG1vTcp28sK919c,1711
|
| 18 |
+
filelock/_unix.py,sha256=ViG38PgJsIhT3xaArugvw0TPP6VWoP2VJj7FEIWypkg,2157
|
| 19 |
+
filelock/_util.py,sha256=dBDlIj1dHL_juXX0Qqq6bZtyE53YZTN8GFhtyTV043o,1708
|
| 20 |
+
filelock/_windows.py,sha256=eMKL8dZKrgekf5VYVGR14an29JGEInRtUO8ui9ABywg,2177
|
| 21 |
+
filelock/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 22 |
+
filelock/version.py,sha256=fmajg3X8ZdOn-UpUewARwK5cfYf4wP4Xa0DcHjigFYo,413
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/filelock-3.13.1.dist-info/WHEEL
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Wheel-Version: 1.0
|
| 2 |
+
Generator: hatchling 1.18.0
|
| 3 |
+
Root-Is-Purelib: true
|
| 4 |
+
Tag: py3-none-any
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/filelock-3.13.1.dist-info/licenses/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
This is free and unencumbered software released into the public domain.
|
| 2 |
+
|
| 3 |
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
| 4 |
+
distribute this software, either in source code form or as a compiled
|
| 5 |
+
binary, for any purpose, commercial or non-commercial, and by any
|
| 6 |
+
means.
|
| 7 |
+
|
| 8 |
+
In jurisdictions that recognize copyright laws, the author or authors
|
| 9 |
+
of this software dedicate any and all copyright interest in the
|
| 10 |
+
software to the public domain. We make this dedication for the benefit
|
| 11 |
+
of the public at large and to the detriment of our heirs and
|
| 12 |
+
successors. We intend this dedication to be an overt act of
|
| 13 |
+
relinquishment in perpetuity of all present and future rights to this
|
| 14 |
+
software under copyright law.
|
| 15 |
+
|
| 16 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
| 17 |
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
| 18 |
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
| 19 |
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
| 20 |
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
| 21 |
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
| 22 |
+
OTHER DEALINGS IN THE SOFTWARE.
|
| 23 |
+
|
| 24 |
+
For more information, please refer to <http://unlicense.org>
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (14.7 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/__pycache__/ctx_base.cpython-311.pyc
ADDED
|
Binary file (24.4 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/__pycache__/ctx_fp.cpython-311.pyc
ADDED
|
Binary file (13 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/__pycache__/ctx_iv.cpython-311.pyc
ADDED
|
Binary file (38.7 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/__pycache__/ctx_mp_python.cpython-311.pyc
ADDED
|
Binary file (61.1 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/__pycache__/identification.cpython-311.pyc
ADDED
|
Binary file (41.3 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/__pycache__/math2.cpython-311.pyc
ADDED
|
Binary file (28.5 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/__pycache__/rational.cpython-311.pyc
ADDED
|
Binary file (10.4 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/__pycache__/usertools.cpython-311.pyc
ADDED
|
Binary file (4.94 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/__pycache__/visualization.cpython-311.pyc
ADDED
|
Binary file (17.1 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/calculus/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (471 Bytes). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/calculus/__pycache__/calculus.cpython-311.pyc
ADDED
|
Binary file (658 Bytes). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/calculus/__pycache__/inverselaplace.cpython-311.pyc
ADDED
|
Binary file (41.7 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/calculus/__pycache__/odes.cpython-311.pyc
ADDED
|
Binary file (13.3 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/calculus/__pycache__/optimization.cpython-311.pyc
ADDED
|
Binary file (42.8 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/calculus/__pycache__/polynomials.cpython-311.pyc
ADDED
|
Binary file (10.9 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/calculus/inverselaplace.py
ADDED
|
@@ -0,0 +1,973 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# contributed to mpmath by Kristopher L. Kuhlman, February 2017
|
| 2 |
+
# contributed to mpmath by Guillermo Navas-Palencia, February 2022
|
| 3 |
+
|
| 4 |
+
class InverseLaplaceTransform(object):
|
| 5 |
+
r"""
|
| 6 |
+
Inverse Laplace transform methods are implemented using this
|
| 7 |
+
class, in order to simplify the code and provide a common
|
| 8 |
+
infrastructure.
|
| 9 |
+
|
| 10 |
+
Implement a custom inverse Laplace transform algorithm by
|
| 11 |
+
subclassing :class:`InverseLaplaceTransform` and implementing the
|
| 12 |
+
appropriate methods. The subclass can then be used by
|
| 13 |
+
:func:`~mpmath.invertlaplace` by passing it as the *method*
|
| 14 |
+
argument.
|
| 15 |
+
"""
|
| 16 |
+
|
| 17 |
+
def __init__(self, ctx):
|
| 18 |
+
self.ctx = ctx
|
| 19 |
+
|
| 20 |
+
def calc_laplace_parameter(self, t, **kwargs):
|
| 21 |
+
r"""
|
| 22 |
+
Determine the vector of Laplace parameter values needed for an
|
| 23 |
+
algorithm, this will depend on the choice of algorithm (de
|
| 24 |
+
Hoog is default), the algorithm-specific parameters passed (or
|
| 25 |
+
default ones), and desired time.
|
| 26 |
+
"""
|
| 27 |
+
raise NotImplementedError
|
| 28 |
+
|
| 29 |
+
def calc_time_domain_solution(self, fp):
|
| 30 |
+
r"""
|
| 31 |
+
Compute the time domain solution, after computing the
|
| 32 |
+
Laplace-space function evaluations at the abscissa required
|
| 33 |
+
for the algorithm. Abscissa computed for one algorithm are
|
| 34 |
+
typically not useful for another algorithm.
|
| 35 |
+
"""
|
| 36 |
+
raise NotImplementedError
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
class FixedTalbot(InverseLaplaceTransform):
|
| 40 |
+
|
| 41 |
+
def calc_laplace_parameter(self, t, **kwargs):
|
| 42 |
+
r"""The "fixed" Talbot method deforms the Bromwich contour towards
|
| 43 |
+
`-\infty` in the shape of a parabola. Traditionally the Talbot
|
| 44 |
+
algorithm has adjustable parameters, but the "fixed" version
|
| 45 |
+
does not. The `r` parameter could be passed in as a parameter,
|
| 46 |
+
if you want to override the default given by (Abate & Valko,
|
| 47 |
+
2004).
|
| 48 |
+
|
| 49 |
+
The Laplace parameter is sampled along a parabola opening
|
| 50 |
+
along the negative imaginary axis, with the base of the
|
| 51 |
+
parabola along the real axis at
|
| 52 |
+
`p=\frac{r}{t_\mathrm{max}}`. As the number of terms used in
|
| 53 |
+
the approximation (degree) grows, the abscissa required for
|
| 54 |
+
function evaluation tend towards `-\infty`, requiring high
|
| 55 |
+
precision to prevent overflow. If any poles, branch cuts or
|
| 56 |
+
other singularities exist such that the deformed Bromwich
|
| 57 |
+
contour lies to the left of the singularity, the method will
|
| 58 |
+
fail.
|
| 59 |
+
|
| 60 |
+
**Optional arguments**
|
| 61 |
+
|
| 62 |
+
:class:`~mpmath.calculus.inverselaplace.FixedTalbot.calc_laplace_parameter`
|
| 63 |
+
recognizes the following keywords
|
| 64 |
+
|
| 65 |
+
*tmax*
|
| 66 |
+
maximum time associated with vector of times
|
| 67 |
+
(typically just the time requested)
|
| 68 |
+
*degree*
|
| 69 |
+
integer order of approximation (M = number of terms)
|
| 70 |
+
*r*
|
| 71 |
+
abscissa for `p_0` (otherwise computed using rule
|
| 72 |
+
of thumb `2M/5`)
|
| 73 |
+
|
| 74 |
+
The working precision will be increased according to a rule of
|
| 75 |
+
thumb. If 'degree' is not specified, the working precision and
|
| 76 |
+
degree are chosen to hopefully achieve the dps of the calling
|
| 77 |
+
context. If 'degree' is specified, the working precision is
|
| 78 |
+
chosen to achieve maximum resulting precision for the
|
| 79 |
+
specified degree.
|
| 80 |
+
|
| 81 |
+
.. math ::
|
| 82 |
+
|
| 83 |
+
p_0=\frac{r}{t}
|
| 84 |
+
|
| 85 |
+
.. math ::
|
| 86 |
+
|
| 87 |
+
p_i=\frac{i r \pi}{Mt_\mathrm{max}}\left[\cot\left(
|
| 88 |
+
\frac{i\pi}{M}\right) + j \right] \qquad 1\le i <M
|
| 89 |
+
|
| 90 |
+
where `j=\sqrt{-1}`, `r=2M/5`, and `t_\mathrm{max}` is the
|
| 91 |
+
maximum specified time.
|
| 92 |
+
|
| 93 |
+
"""
|
| 94 |
+
|
| 95 |
+
# required
|
| 96 |
+
# ------------------------------
|
| 97 |
+
# time of desired approximation
|
| 98 |
+
self.t = self.ctx.convert(t)
|
| 99 |
+
|
| 100 |
+
# optional
|
| 101 |
+
# ------------------------------
|
| 102 |
+
# maximum time desired (used for scaling) default is requested
|
| 103 |
+
# time.
|
| 104 |
+
self.tmax = self.ctx.convert(kwargs.get('tmax', self.t))
|
| 105 |
+
|
| 106 |
+
# empirical relationships used here based on a linear fit of
|
| 107 |
+
# requested and delivered dps for exponentially decaying time
|
| 108 |
+
# functions for requested dps up to 512.
|
| 109 |
+
|
| 110 |
+
if 'degree' in kwargs:
|
| 111 |
+
self.degree = kwargs['degree']
|
| 112 |
+
self.dps_goal = self.degree
|
| 113 |
+
else:
|
| 114 |
+
self.dps_goal = int(1.72*self.ctx.dps)
|
| 115 |
+
self.degree = max(12, int(1.38*self.dps_goal))
|
| 116 |
+
|
| 117 |
+
M = self.degree
|
| 118 |
+
|
| 119 |
+
# this is adjusting the dps of the calling context hopefully
|
| 120 |
+
# the caller doesn't monkey around with it between calling
|
| 121 |
+
# this routine and calc_time_domain_solution()
|
| 122 |
+
self.dps_orig = self.ctx.dps
|
| 123 |
+
self.ctx.dps = self.dps_goal
|
| 124 |
+
|
| 125 |
+
# Abate & Valko rule of thumb for r parameter
|
| 126 |
+
self.r = kwargs.get('r', self.ctx.fraction(2, 5)*M)
|
| 127 |
+
|
| 128 |
+
self.theta = self.ctx.linspace(0.0, self.ctx.pi, M+1)
|
| 129 |
+
|
| 130 |
+
self.cot_theta = self.ctx.matrix(M, 1)
|
| 131 |
+
self.cot_theta[0] = 0 # not used
|
| 132 |
+
|
| 133 |
+
# all but time-dependent part of p
|
| 134 |
+
self.delta = self.ctx.matrix(M, 1)
|
| 135 |
+
self.delta[0] = self.r
|
| 136 |
+
|
| 137 |
+
for i in range(1, M):
|
| 138 |
+
self.cot_theta[i] = self.ctx.cot(self.theta[i])
|
| 139 |
+
self.delta[i] = self.r*self.theta[i]*(self.cot_theta[i] + 1j)
|
| 140 |
+
|
| 141 |
+
self.p = self.ctx.matrix(M, 1)
|
| 142 |
+
self.p = self.delta/self.tmax
|
| 143 |
+
|
| 144 |
+
# NB: p is complex (mpc)
|
| 145 |
+
|
| 146 |
+
def calc_time_domain_solution(self, fp, t, manual_prec=False):
|
| 147 |
+
r"""The fixed Talbot time-domain solution is computed from the
|
| 148 |
+
Laplace-space function evaluations using
|
| 149 |
+
|
| 150 |
+
.. math ::
|
| 151 |
+
|
| 152 |
+
f(t,M)=\frac{2}{5t}\sum_{k=0}^{M-1}\Re \left[
|
| 153 |
+
\gamma_k \bar{f}(p_k)\right]
|
| 154 |
+
|
| 155 |
+
where
|
| 156 |
+
|
| 157 |
+
.. math ::
|
| 158 |
+
|
| 159 |
+
\gamma_0 = \frac{1}{2}e^{r}\bar{f}(p_0)
|
| 160 |
+
|
| 161 |
+
.. math ::
|
| 162 |
+
|
| 163 |
+
\gamma_k = e^{tp_k}\left\lbrace 1 + \frac{jk\pi}{M}\left[1 +
|
| 164 |
+
\cot \left( \frac{k \pi}{M} \right)^2 \right] - j\cot\left(
|
| 165 |
+
\frac{k \pi}{M}\right)\right \rbrace \qquad 1\le k<M.
|
| 166 |
+
|
| 167 |
+
Again, `j=\sqrt{-1}`.
|
| 168 |
+
|
| 169 |
+
Before calling this function, call
|
| 170 |
+
:class:`~mpmath.calculus.inverselaplace.FixedTalbot.calc_laplace_parameter`
|
| 171 |
+
to set the parameters and compute the required coefficients.
|
| 172 |
+
|
| 173 |
+
**References**
|
| 174 |
+
|
| 175 |
+
1. Abate, J., P. Valko (2004). Multi-precision Laplace
|
| 176 |
+
transform inversion. *International Journal for Numerical
|
| 177 |
+
Methods in Engineering* 60:979-993,
|
| 178 |
+
http://dx.doi.org/10.1002/nme.995
|
| 179 |
+
2. Talbot, A. (1979). The accurate numerical inversion of
|
| 180 |
+
Laplace transforms. *IMA Journal of Applied Mathematics*
|
| 181 |
+
23(1):97, http://dx.doi.org/10.1093/imamat/23.1.97
|
| 182 |
+
"""
|
| 183 |
+
|
| 184 |
+
# required
|
| 185 |
+
# ------------------------------
|
| 186 |
+
self.t = self.ctx.convert(t)
|
| 187 |
+
|
| 188 |
+
# assume fp was computed from p matrix returned from
|
| 189 |
+
# calc_laplace_parameter(), so is already a list or matrix of
|
| 190 |
+
# mpmath 'mpc' types
|
| 191 |
+
|
| 192 |
+
# these were computed in previous call to
|
| 193 |
+
# calc_laplace_parameter()
|
| 194 |
+
theta = self.theta
|
| 195 |
+
delta = self.delta
|
| 196 |
+
M = self.degree
|
| 197 |
+
p = self.p
|
| 198 |
+
r = self.r
|
| 199 |
+
|
| 200 |
+
ans = self.ctx.matrix(M, 1)
|
| 201 |
+
ans[0] = self.ctx.exp(delta[0])*fp[0]/2
|
| 202 |
+
|
| 203 |
+
for i in range(1, M):
|
| 204 |
+
ans[i] = self.ctx.exp(delta[i])*fp[i]*(
|
| 205 |
+
1 + 1j*theta[i]*(1 + self.cot_theta[i]**2) -
|
| 206 |
+
1j*self.cot_theta[i])
|
| 207 |
+
|
| 208 |
+
result = self.ctx.fraction(2, 5)*self.ctx.fsum(ans)/self.t
|
| 209 |
+
|
| 210 |
+
# setting dps back to value when calc_laplace_parameter was
|
| 211 |
+
# called, unless flag is set.
|
| 212 |
+
if not manual_prec:
|
| 213 |
+
self.ctx.dps = self.dps_orig
|
| 214 |
+
|
| 215 |
+
return result.real
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
# ****************************************
|
| 219 |
+
|
| 220 |
+
class Stehfest(InverseLaplaceTransform):
|
| 221 |
+
|
| 222 |
+
def calc_laplace_parameter(self, t, **kwargs):
|
| 223 |
+
r"""
|
| 224 |
+
The Gaver-Stehfest method is a discrete approximation of the
|
| 225 |
+
Widder-Post inversion algorithm, rather than a direct
|
| 226 |
+
approximation of the Bromwich contour integral.
|
| 227 |
+
|
| 228 |
+
The method abscissa along the real axis, and therefore has
|
| 229 |
+
issues inverting oscillatory functions (which have poles in
|
| 230 |
+
pairs away from the real axis).
|
| 231 |
+
|
| 232 |
+
The working precision will be increased according to a rule of
|
| 233 |
+
thumb. If 'degree' is not specified, the working precision and
|
| 234 |
+
degree are chosen to hopefully achieve the dps of the calling
|
| 235 |
+
context. If 'degree' is specified, the working precision is
|
| 236 |
+
chosen to achieve maximum resulting precision for the
|
| 237 |
+
specified degree.
|
| 238 |
+
|
| 239 |
+
.. math ::
|
| 240 |
+
|
| 241 |
+
p_k = \frac{k \log 2}{t} \qquad 1 \le k \le M
|
| 242 |
+
"""
|
| 243 |
+
|
| 244 |
+
# required
|
| 245 |
+
# ------------------------------
|
| 246 |
+
# time of desired approximation
|
| 247 |
+
self.t = self.ctx.convert(t)
|
| 248 |
+
|
| 249 |
+
# optional
|
| 250 |
+
# ------------------------------
|
| 251 |
+
|
| 252 |
+
# empirical relationships used here based on a linear fit of
|
| 253 |
+
# requested and delivered dps for exponentially decaying time
|
| 254 |
+
# functions for requested dps up to 512.
|
| 255 |
+
|
| 256 |
+
if 'degree' in kwargs:
|
| 257 |
+
self.degree = kwargs['degree']
|
| 258 |
+
self.dps_goal = int(1.38*self.degree)
|
| 259 |
+
else:
|
| 260 |
+
self.dps_goal = int(2.93*self.ctx.dps)
|
| 261 |
+
self.degree = max(16, self.dps_goal)
|
| 262 |
+
|
| 263 |
+
# _coeff routine requires even degree
|
| 264 |
+
if self.degree % 2 > 0:
|
| 265 |
+
self.degree += 1
|
| 266 |
+
|
| 267 |
+
M = self.degree
|
| 268 |
+
|
| 269 |
+
# this is adjusting the dps of the calling context
|
| 270 |
+
# hopefully the caller doesn't monkey around with it
|
| 271 |
+
# between calling this routine and calc_time_domain_solution()
|
| 272 |
+
self.dps_orig = self.ctx.dps
|
| 273 |
+
self.ctx.dps = self.dps_goal
|
| 274 |
+
|
| 275 |
+
self.V = self._coeff()
|
| 276 |
+
self.p = self.ctx.matrix(self.ctx.arange(1, M+1))*self.ctx.ln2/self.t
|
| 277 |
+
|
| 278 |
+
# NB: p is real (mpf)
|
| 279 |
+
|
| 280 |
+
def _coeff(self):
|
| 281 |
+
r"""Salzer summation weights (aka, "Stehfest coefficients")
|
| 282 |
+
only depend on the approximation order (M) and the precision"""
|
| 283 |
+
|
| 284 |
+
M = self.degree
|
| 285 |
+
M2 = int(M/2) # checked earlier that M is even
|
| 286 |
+
|
| 287 |
+
V = self.ctx.matrix(M, 1)
|
| 288 |
+
|
| 289 |
+
# Salzer summation weights
|
| 290 |
+
# get very large in magnitude and oscillate in sign,
|
| 291 |
+
# if the precision is not high enough, there will be
|
| 292 |
+
# catastrophic cancellation
|
| 293 |
+
for k in range(1, M+1):
|
| 294 |
+
z = self.ctx.matrix(min(k, M2)+1, 1)
|
| 295 |
+
for j in range(int((k+1)/2), min(k, M2)+1):
|
| 296 |
+
z[j] = (self.ctx.power(j, M2)*self.ctx.fac(2*j)/
|
| 297 |
+
(self.ctx.fac(M2-j)*self.ctx.fac(j)*
|
| 298 |
+
self.ctx.fac(j-1)*self.ctx.fac(k-j)*
|
| 299 |
+
self.ctx.fac(2*j-k)))
|
| 300 |
+
V[k-1] = self.ctx.power(-1, k+M2)*self.ctx.fsum(z)
|
| 301 |
+
|
| 302 |
+
return V
|
| 303 |
+
|
| 304 |
+
def calc_time_domain_solution(self, fp, t, manual_prec=False):
|
| 305 |
+
r"""Compute time-domain Stehfest algorithm solution.
|
| 306 |
+
|
| 307 |
+
.. math ::
|
| 308 |
+
|
| 309 |
+
f(t,M) = \frac{\log 2}{t} \sum_{k=1}^{M} V_k \bar{f}\left(
|
| 310 |
+
p_k \right)
|
| 311 |
+
|
| 312 |
+
where
|
| 313 |
+
|
| 314 |
+
.. math ::
|
| 315 |
+
|
| 316 |
+
V_k = (-1)^{k + N/2} \sum^{\min(k,N/2)}_{i=\lfloor(k+1)/2 \rfloor}
|
| 317 |
+
\frac{i^{\frac{N}{2}}(2i)!}{\left(\frac{N}{2}-i \right)! \, i! \,
|
| 318 |
+
\left(i-1 \right)! \, \left(k-i\right)! \, \left(2i-k \right)!}
|
| 319 |
+
|
| 320 |
+
As the degree increases, the abscissa (`p_k`) only increase
|
| 321 |
+
linearly towards `\infty`, but the Stehfest coefficients
|
| 322 |
+
(`V_k`) alternate in sign and increase rapidly in sign,
|
| 323 |
+
requiring high precision to prevent overflow or loss of
|
| 324 |
+
significance when evaluating the sum.
|
| 325 |
+
|
| 326 |
+
**References**
|
| 327 |
+
|
| 328 |
+
1. Widder, D. (1941). *The Laplace Transform*. Princeton.
|
| 329 |
+
2. Stehfest, H. (1970). Algorithm 368: numerical inversion of
|
| 330 |
+
Laplace transforms. *Communications of the ACM* 13(1):47-49,
|
| 331 |
+
http://dx.doi.org/10.1145/361953.361969
|
| 332 |
+
|
| 333 |
+
"""
|
| 334 |
+
|
| 335 |
+
# required
|
| 336 |
+
self.t = self.ctx.convert(t)
|
| 337 |
+
|
| 338 |
+
# assume fp was computed from p matrix returned from
|
| 339 |
+
# calc_laplace_parameter(), so is already
|
| 340 |
+
# a list or matrix of mpmath 'mpf' types
|
| 341 |
+
|
| 342 |
+
result = self.ctx.fdot(self.V, fp)*self.ctx.ln2/self.t
|
| 343 |
+
|
| 344 |
+
# setting dps back to value when calc_laplace_parameter was called
|
| 345 |
+
if not manual_prec:
|
| 346 |
+
self.ctx.dps = self.dps_orig
|
| 347 |
+
|
| 348 |
+
# ignore any small imaginary part
|
| 349 |
+
return result.real
|
| 350 |
+
|
| 351 |
+
|
| 352 |
+
# ****************************************
|
| 353 |
+
|
| 354 |
+
class deHoog(InverseLaplaceTransform):
|
| 355 |
+
|
| 356 |
+
def calc_laplace_parameter(self, t, **kwargs):
|
| 357 |
+
r"""the de Hoog, Knight & Stokes algorithm is an
|
| 358 |
+
accelerated form of the Fourier series numerical
|
| 359 |
+
inverse Laplace transform algorithms.
|
| 360 |
+
|
| 361 |
+
.. math ::
|
| 362 |
+
|
| 363 |
+
p_k = \gamma + \frac{jk}{T} \qquad 0 \le k < 2M+1
|
| 364 |
+
|
| 365 |
+
where
|
| 366 |
+
|
| 367 |
+
.. math ::
|
| 368 |
+
|
| 369 |
+
\gamma = \alpha - \frac{\log \mathrm{tol}}{2T},
|
| 370 |
+
|
| 371 |
+
`j=\sqrt{-1}`, `T = 2t_\mathrm{max}` is a scaled time,
|
| 372 |
+
`\alpha=10^{-\mathrm{dps\_goal}}` is the real part of the
|
| 373 |
+
rightmost pole or singularity, which is chosen based on the
|
| 374 |
+
desired accuracy (assuming the rightmost singularity is 0),
|
| 375 |
+
and `\mathrm{tol}=10\alpha` is the desired tolerance, which is
|
| 376 |
+
chosen in relation to `\alpha`.`
|
| 377 |
+
|
| 378 |
+
When increasing the degree, the abscissa increase towards
|
| 379 |
+
`j\infty`, but more slowly than the fixed Talbot
|
| 380 |
+
algorithm. The de Hoog et al. algorithm typically does better
|
| 381 |
+
with oscillatory functions of time, and less well-behaved
|
| 382 |
+
functions. The method tends to be slower than the Talbot and
|
| 383 |
+
Stehfest algorithsm, especially so at very high precision
|
| 384 |
+
(e.g., `>500` digits precision).
|
| 385 |
+
|
| 386 |
+
"""
|
| 387 |
+
|
| 388 |
+
# required
|
| 389 |
+
# ------------------------------
|
| 390 |
+
self.t = self.ctx.convert(t)
|
| 391 |
+
|
| 392 |
+
# optional
|
| 393 |
+
# ------------------------------
|
| 394 |
+
self.tmax = kwargs.get('tmax', self.t)
|
| 395 |
+
|
| 396 |
+
# empirical relationships used here based on a linear fit of
|
| 397 |
+
# requested and delivered dps for exponentially decaying time
|
| 398 |
+
# functions for requested dps up to 512.
|
| 399 |
+
|
| 400 |
+
if 'degree' in kwargs:
|
| 401 |
+
self.degree = kwargs['degree']
|
| 402 |
+
self.dps_goal = int(1.38*self.degree)
|
| 403 |
+
else:
|
| 404 |
+
self.dps_goal = int(self.ctx.dps*1.36)
|
| 405 |
+
self.degree = max(10, self.dps_goal)
|
| 406 |
+
|
| 407 |
+
# 2*M+1 terms in approximation
|
| 408 |
+
M = self.degree
|
| 409 |
+
|
| 410 |
+
# adjust alpha component of abscissa of convergence for higher
|
| 411 |
+
# precision
|
| 412 |
+
tmp = self.ctx.power(10.0, -self.dps_goal)
|
| 413 |
+
self.alpha = self.ctx.convert(kwargs.get('alpha', tmp))
|
| 414 |
+
|
| 415 |
+
# desired tolerance (here simply related to alpha)
|
| 416 |
+
self.tol = self.ctx.convert(kwargs.get('tol', self.alpha*10.0))
|
| 417 |
+
self.np = 2*self.degree+1 # number of terms in approximation
|
| 418 |
+
|
| 419 |
+
# this is adjusting the dps of the calling context
|
| 420 |
+
# hopefully the caller doesn't monkey around with it
|
| 421 |
+
# between calling this routine and calc_time_domain_solution()
|
| 422 |
+
self.dps_orig = self.ctx.dps
|
| 423 |
+
self.ctx.dps = self.dps_goal
|
| 424 |
+
|
| 425 |
+
# scaling factor (likely tun-able, but 2 is typical)
|
| 426 |
+
self.scale = kwargs.get('scale', 2)
|
| 427 |
+
self.T = self.ctx.convert(kwargs.get('T', self.scale*self.tmax))
|
| 428 |
+
|
| 429 |
+
self.p = self.ctx.matrix(2*M+1, 1)
|
| 430 |
+
self.gamma = self.alpha - self.ctx.log(self.tol)/(self.scale*self.T)
|
| 431 |
+
self.p = (self.gamma + self.ctx.pi*
|
| 432 |
+
self.ctx.matrix(self.ctx.arange(self.np))/self.T*1j)
|
| 433 |
+
|
| 434 |
+
# NB: p is complex (mpc)
|
| 435 |
+
|
| 436 |
+
def calc_time_domain_solution(self, fp, t, manual_prec=False):
|
| 437 |
+
r"""Calculate time-domain solution for
|
| 438 |
+
de Hoog, Knight & Stokes algorithm.
|
| 439 |
+
|
| 440 |
+
The un-accelerated Fourier series approach is:
|
| 441 |
+
|
| 442 |
+
.. math ::
|
| 443 |
+
|
| 444 |
+
f(t,2M+1) = \frac{e^{\gamma t}}{T} \sum_{k=0}^{2M}{}^{'}
|
| 445 |
+
\Re\left[\bar{f}\left( p_k \right)
|
| 446 |
+
e^{i\pi t/T} \right],
|
| 447 |
+
|
| 448 |
+
where the prime on the summation indicates the first term is halved.
|
| 449 |
+
|
| 450 |
+
This simplistic approach requires so many function evaluations
|
| 451 |
+
that it is not practical. Non-linear acceleration is
|
| 452 |
+
accomplished via Pade-approximation and an analytic expression
|
| 453 |
+
for the remainder of the continued fraction. See the original
|
| 454 |
+
paper (reference 2 below) a detailed description of the
|
| 455 |
+
numerical approach.
|
| 456 |
+
|
| 457 |
+
**References**
|
| 458 |
+
|
| 459 |
+
1. Davies, B. (2005). *Integral Transforms and their
|
| 460 |
+
Applications*, Third Edition. Springer.
|
| 461 |
+
2. de Hoog, F., J. Knight, A. Stokes (1982). An improved
|
| 462 |
+
method for numerical inversion of Laplace transforms. *SIAM
|
| 463 |
+
Journal of Scientific and Statistical Computing* 3:357-366,
|
| 464 |
+
http://dx.doi.org/10.1137/0903022
|
| 465 |
+
|
| 466 |
+
"""
|
| 467 |
+
|
| 468 |
+
M = self.degree
|
| 469 |
+
np = self.np
|
| 470 |
+
T = self.T
|
| 471 |
+
|
| 472 |
+
self.t = self.ctx.convert(t)
|
| 473 |
+
|
| 474 |
+
# would it be useful to try re-using
|
| 475 |
+
# space between e&q and A&B?
|
| 476 |
+
e = self.ctx.zeros(np, M+1)
|
| 477 |
+
q = self.ctx.matrix(2*M, M)
|
| 478 |
+
d = self.ctx.matrix(np, 1)
|
| 479 |
+
A = self.ctx.zeros(np+1, 1)
|
| 480 |
+
B = self.ctx.ones(np+1, 1)
|
| 481 |
+
|
| 482 |
+
# initialize Q-D table
|
| 483 |
+
e[:, 0] = 0.0 + 0j
|
| 484 |
+
q[0, 0] = fp[1]/(fp[0]/2)
|
| 485 |
+
for i in range(1, 2*M):
|
| 486 |
+
q[i, 0] = fp[i+1]/fp[i]
|
| 487 |
+
|
| 488 |
+
# rhombus rule for filling triangular Q-D table (e & q)
|
| 489 |
+
for r in range(1, M+1):
|
| 490 |
+
# start with e, column 1, 0:2*M-2
|
| 491 |
+
mr = 2*(M-r) + 1
|
| 492 |
+
e[0:mr, r] = q[1:mr+1, r-1] - q[0:mr, r-1] + e[1:mr+1, r-1]
|
| 493 |
+
if not r == M:
|
| 494 |
+
rq = r+1
|
| 495 |
+
mr = 2*(M-rq)+1 + 2
|
| 496 |
+
for i in range(mr):
|
| 497 |
+
q[i, rq-1] = q[i+1, rq-2]*e[i+1, rq-1]/e[i, rq-1]
|
| 498 |
+
|
| 499 |
+
# build up continued fraction coefficients (d)
|
| 500 |
+
d[0] = fp[0]/2
|
| 501 |
+
for r in range(1, M+1):
|
| 502 |
+
d[2*r-1] = -q[0, r-1] # even terms
|
| 503 |
+
d[2*r] = -e[0, r] # odd terms
|
| 504 |
+
|
| 505 |
+
# seed A and B for recurrence
|
| 506 |
+
A[0] = 0.0 + 0.0j
|
| 507 |
+
A[1] = d[0]
|
| 508 |
+
B[0:2] = 1.0 + 0.0j
|
| 509 |
+
|
| 510 |
+
# base of the power series
|
| 511 |
+
z = self.ctx.expjpi(self.t/T) # i*pi is already in fcn
|
| 512 |
+
|
| 513 |
+
# coefficients of Pade approximation (A & B)
|
| 514 |
+
# using recurrence for all but last term
|
| 515 |
+
for i in range(1, 2*M):
|
| 516 |
+
A[i+1] = A[i] + d[i]*A[i-1]*z
|
| 517 |
+
B[i+1] = B[i] + d[i]*B[i-1]*z
|
| 518 |
+
|
| 519 |
+
# "improved remainder" to continued fraction
|
| 520 |
+
brem = (1 + (d[2*M-1] - d[2*M])*z)/2
|
| 521 |
+
# powm1(x,y) computes x^y - 1 more accurately near zero
|
| 522 |
+
rem = brem*self.ctx.powm1(1 + d[2*M]*z/brem,
|
| 523 |
+
self.ctx.fraction(1, 2))
|
| 524 |
+
|
| 525 |
+
# last term of recurrence using new remainder
|
| 526 |
+
A[np] = A[2*M] + rem*A[2*M-1]
|
| 527 |
+
B[np] = B[2*M] + rem*B[2*M-1]
|
| 528 |
+
|
| 529 |
+
# diagonal Pade approximation
|
| 530 |
+
# F=A/B represents accelerated trapezoid rule
|
| 531 |
+
result = self.ctx.exp(self.gamma*self.t)/T*(A[np]/B[np]).real
|
| 532 |
+
|
| 533 |
+
# setting dps back to value when calc_laplace_parameter was called
|
| 534 |
+
if not manual_prec:
|
| 535 |
+
self.ctx.dps = self.dps_orig
|
| 536 |
+
|
| 537 |
+
return result
|
| 538 |
+
|
| 539 |
+
|
| 540 |
+
# ****************************************
|
| 541 |
+
|
| 542 |
+
class Cohen(InverseLaplaceTransform):
|
| 543 |
+
|
| 544 |
+
def calc_laplace_parameter(self, t, **kwargs):
|
| 545 |
+
r"""The Cohen algorithm accelerates the convergence of the nearly
|
| 546 |
+
alternating series resulting from the application of the trapezoidal
|
| 547 |
+
rule to the Bromwich contour inversion integral.
|
| 548 |
+
|
| 549 |
+
.. math ::
|
| 550 |
+
|
| 551 |
+
p_k = \frac{\gamma}{2 t} + \frac{\pi i k}{t} \qquad 0 \le k < M
|
| 552 |
+
|
| 553 |
+
where
|
| 554 |
+
|
| 555 |
+
.. math ::
|
| 556 |
+
|
| 557 |
+
\gamma = \frac{2}{3} (d + \log(10) + \log(2 t)),
|
| 558 |
+
|
| 559 |
+
`d = \mathrm{dps\_goal}`, which is chosen based on the desired
|
| 560 |
+
accuracy using the method developed in [1] to improve numerical
|
| 561 |
+
stability. The Cohen algorithm shows robustness similar to the de Hoog
|
| 562 |
+
et al. algorithm, but it is faster than the fixed Talbot algorithm.
|
| 563 |
+
|
| 564 |
+
**Optional arguments**
|
| 565 |
+
|
| 566 |
+
*degree*
|
| 567 |
+
integer order of the approximation (M = number of terms)
|
| 568 |
+
*alpha*
|
| 569 |
+
abscissa for `p_0` (controls the discretization error)
|
| 570 |
+
|
| 571 |
+
The working precision will be increased according to a rule of
|
| 572 |
+
thumb. If 'degree' is not specified, the working precision and
|
| 573 |
+
degree are chosen to hopefully achieve the dps of the calling
|
| 574 |
+
context. If 'degree' is specified, the working precision is
|
| 575 |
+
chosen to achieve maximum resulting precision for the
|
| 576 |
+
specified degree.
|
| 577 |
+
|
| 578 |
+
**References**
|
| 579 |
+
|
| 580 |
+
1. P. Glasserman, J. Ruiz-Mata (2006). Computing the credit loss
|
| 581 |
+
distribution in the Gaussian copula model: a comparison of methods.
|
| 582 |
+
*Journal of Credit Risk* 2(4):33-66, 10.21314/JCR.2006.057
|
| 583 |
+
|
| 584 |
+
"""
|
| 585 |
+
self.t = self.ctx.convert(t)
|
| 586 |
+
|
| 587 |
+
if 'degree' in kwargs:
|
| 588 |
+
self.degree = kwargs['degree']
|
| 589 |
+
self.dps_goal = int(1.5 * self.degree)
|
| 590 |
+
else:
|
| 591 |
+
self.dps_goal = int(self.ctx.dps * 1.74)
|
| 592 |
+
self.degree = max(22, int(1.31 * self.dps_goal))
|
| 593 |
+
|
| 594 |
+
M = self.degree + 1
|
| 595 |
+
|
| 596 |
+
# this is adjusting the dps of the calling context hopefully
|
| 597 |
+
# the caller doesn't monkey around with it between calling
|
| 598 |
+
# this routine and calc_time_domain_solution()
|
| 599 |
+
self.dps_orig = self.ctx.dps
|
| 600 |
+
self.ctx.dps = self.dps_goal
|
| 601 |
+
|
| 602 |
+
ttwo = 2 * self.t
|
| 603 |
+
tmp = self.ctx.dps * self.ctx.log(10) + self.ctx.log(ttwo)
|
| 604 |
+
tmp = self.ctx.fraction(2, 3) * tmp
|
| 605 |
+
self.alpha = self.ctx.convert(kwargs.get('alpha', tmp))
|
| 606 |
+
|
| 607 |
+
# all but time-dependent part of p
|
| 608 |
+
a_t = self.alpha / ttwo
|
| 609 |
+
p_t = self.ctx.pi * 1j / self.t
|
| 610 |
+
|
| 611 |
+
self.p = self.ctx.matrix(M, 1)
|
| 612 |
+
self.p[0] = a_t
|
| 613 |
+
|
| 614 |
+
for i in range(1, M):
|
| 615 |
+
self.p[i] = a_t + i * p_t
|
| 616 |
+
|
| 617 |
+
def calc_time_domain_solution(self, fp, t, manual_prec=False):
|
| 618 |
+
r"""Calculate time-domain solution for Cohen algorithm.
|
| 619 |
+
|
| 620 |
+
The accelerated nearly alternating series is:
|
| 621 |
+
|
| 622 |
+
.. math ::
|
| 623 |
+
|
| 624 |
+
f(t, M) = \frac{e^{\gamma / 2}}{t} \left[\frac{1}{2}
|
| 625 |
+
\Re\left(\bar{f}\left(\frac{\gamma}{2t}\right) \right) -
|
| 626 |
+
\sum_{k=0}^{M-1}\frac{c_{M,k}}{d_M}\Re\left(\bar{f}
|
| 627 |
+
\left(\frac{\gamma + 2(k+1) \pi i}{2t}\right)\right)\right],
|
| 628 |
+
|
| 629 |
+
where coefficients `\frac{c_{M, k}}{d_M}` are described in [1].
|
| 630 |
+
|
| 631 |
+
1. H. Cohen, F. Rodriguez Villegas, D. Zagier (2000). Convergence
|
| 632 |
+
acceleration of alternating series. *Experiment. Math* 9(1):3-12
|
| 633 |
+
|
| 634 |
+
"""
|
| 635 |
+
self.t = self.ctx.convert(t)
|
| 636 |
+
|
| 637 |
+
n = self.degree
|
| 638 |
+
M = n + 1
|
| 639 |
+
|
| 640 |
+
A = self.ctx.matrix(M, 1)
|
| 641 |
+
for i in range(M):
|
| 642 |
+
A[i] = fp[i].real
|
| 643 |
+
|
| 644 |
+
d = (3 + self.ctx.sqrt(8)) ** n
|
| 645 |
+
d = (d + 1 / d) / 2
|
| 646 |
+
b = -self.ctx.one
|
| 647 |
+
c = -d
|
| 648 |
+
s = 0
|
| 649 |
+
|
| 650 |
+
for k in range(n):
|
| 651 |
+
c = b - c
|
| 652 |
+
s = s + c * A[k + 1]
|
| 653 |
+
b = 2 * (k + n) * (k - n) * b / ((2 * k + 1) * (k + self.ctx.one))
|
| 654 |
+
|
| 655 |
+
result = self.ctx.exp(self.alpha / 2) / self.t * (A[0] / 2 - s / d)
|
| 656 |
+
|
| 657 |
+
# setting dps back to value when calc_laplace_parameter was
|
| 658 |
+
# called, unless flag is set.
|
| 659 |
+
if not manual_prec:
|
| 660 |
+
self.ctx.dps = self.dps_orig
|
| 661 |
+
|
| 662 |
+
return result
|
| 663 |
+
|
| 664 |
+
|
| 665 |
+
# ****************************************
|
| 666 |
+
|
| 667 |
+
class LaplaceTransformInversionMethods(object):
|
| 668 |
+
def __init__(ctx, *args, **kwargs):
|
| 669 |
+
ctx._fixed_talbot = FixedTalbot(ctx)
|
| 670 |
+
ctx._stehfest = Stehfest(ctx)
|
| 671 |
+
ctx._de_hoog = deHoog(ctx)
|
| 672 |
+
ctx._cohen = Cohen(ctx)
|
| 673 |
+
|
| 674 |
+
def invertlaplace(ctx, f, t, **kwargs):
|
| 675 |
+
r"""Computes the numerical inverse Laplace transform for a
|
| 676 |
+
Laplace-space function at a given time. The function being
|
| 677 |
+
evaluated is assumed to be a real-valued function of time.
|
| 678 |
+
|
| 679 |
+
The user must supply a Laplace-space function `\bar{f}(p)`,
|
| 680 |
+
and a desired time at which to estimate the time-domain
|
| 681 |
+
solution `f(t)`.
|
| 682 |
+
|
| 683 |
+
A few basic examples of Laplace-space functions with known
|
| 684 |
+
inverses (see references [1,2]) :
|
| 685 |
+
|
| 686 |
+
.. math ::
|
| 687 |
+
|
| 688 |
+
\mathcal{L}\left\lbrace f(t) \right\rbrace=\bar{f}(p)
|
| 689 |
+
|
| 690 |
+
.. math ::
|
| 691 |
+
|
| 692 |
+
\mathcal{L}^{-1}\left\lbrace \bar{f}(p) \right\rbrace = f(t)
|
| 693 |
+
|
| 694 |
+
.. math ::
|
| 695 |
+
|
| 696 |
+
\bar{f}(p) = \frac{1}{(p+1)^2}
|
| 697 |
+
|
| 698 |
+
.. math ::
|
| 699 |
+
|
| 700 |
+
f(t) = t e^{-t}
|
| 701 |
+
|
| 702 |
+
>>> from mpmath import *
|
| 703 |
+
>>> mp.dps = 15; mp.pretty = True
|
| 704 |
+
>>> tt = [0.001, 0.01, 0.1, 1, 10]
|
| 705 |
+
>>> fp = lambda p: 1/(p+1)**2
|
| 706 |
+
>>> ft = lambda t: t*exp(-t)
|
| 707 |
+
>>> ft(tt[0]),ft(tt[0])-invertlaplace(fp,tt[0],method='talbot')
|
| 708 |
+
(0.000999000499833375, 8.57923043561212e-20)
|
| 709 |
+
>>> ft(tt[1]),ft(tt[1])-invertlaplace(fp,tt[1],method='talbot')
|
| 710 |
+
(0.00990049833749168, 3.27007646698047e-19)
|
| 711 |
+
>>> ft(tt[2]),ft(tt[2])-invertlaplace(fp,tt[2],method='talbot')
|
| 712 |
+
(0.090483741803596, -1.75215800052168e-18)
|
| 713 |
+
>>> ft(tt[3]),ft(tt[3])-invertlaplace(fp,tt[3],method='talbot')
|
| 714 |
+
(0.367879441171442, 1.2428864009344e-17)
|
| 715 |
+
>>> ft(tt[4]),ft(tt[4])-invertlaplace(fp,tt[4],method='talbot')
|
| 716 |
+
(0.000453999297624849, 4.04513489306658e-20)
|
| 717 |
+
|
| 718 |
+
The methods also work for higher precision:
|
| 719 |
+
|
| 720 |
+
>>> mp.dps = 100; mp.pretty = True
|
| 721 |
+
>>> nstr(ft(tt[0]),15),nstr(ft(tt[0])-invertlaplace(fp,tt[0],method='talbot'),15)
|
| 722 |
+
('0.000999000499833375', '-4.96868310693356e-105')
|
| 723 |
+
>>> nstr(ft(tt[1]),15),nstr(ft(tt[1])-invertlaplace(fp,tt[1],method='talbot'),15)
|
| 724 |
+
('0.00990049833749168', '1.23032291513122e-104')
|
| 725 |
+
|
| 726 |
+
.. math ::
|
| 727 |
+
|
| 728 |
+
\bar{f}(p) = \frac{1}{p^2+1}
|
| 729 |
+
|
| 730 |
+
.. math ::
|
| 731 |
+
|
| 732 |
+
f(t) = \mathrm{J}_0(t)
|
| 733 |
+
|
| 734 |
+
>>> mp.dps = 15; mp.pretty = True
|
| 735 |
+
>>> fp = lambda p: 1/sqrt(p*p + 1)
|
| 736 |
+
>>> ft = lambda t: besselj(0,t)
|
| 737 |
+
>>> ft(tt[0]),ft(tt[0])-invertlaplace(fp,tt[0],method='dehoog')
|
| 738 |
+
(0.999999750000016, -6.09717765032273e-18)
|
| 739 |
+
>>> ft(tt[1]),ft(tt[1])-invertlaplace(fp,tt[1],method='dehoog')
|
| 740 |
+
(0.99997500015625, -5.61756281076169e-17)
|
| 741 |
+
|
| 742 |
+
.. math ::
|
| 743 |
+
|
| 744 |
+
\bar{f}(p) = \frac{\log p}{p}
|
| 745 |
+
|
| 746 |
+
.. math ::
|
| 747 |
+
|
| 748 |
+
f(t) = -\gamma -\log t
|
| 749 |
+
|
| 750 |
+
>>> mp.dps = 15; mp.pretty = True
|
| 751 |
+
>>> fp = lambda p: log(p)/p
|
| 752 |
+
>>> ft = lambda t: -euler-log(t)
|
| 753 |
+
>>> ft(tt[0]),ft(tt[0])-invertlaplace(fp,tt[0],method='stehfest')
|
| 754 |
+
(6.3305396140806, -1.92126634837863e-16)
|
| 755 |
+
>>> ft(tt[1]),ft(tt[1])-invertlaplace(fp,tt[1],method='stehfest')
|
| 756 |
+
(4.02795452108656, -4.81486093200704e-16)
|
| 757 |
+
|
| 758 |
+
**Options**
|
| 759 |
+
|
| 760 |
+
:func:`~mpmath.invertlaplace` recognizes the following optional
|
| 761 |
+
keywords valid for all methods:
|
| 762 |
+
|
| 763 |
+
*method*
|
| 764 |
+
Chooses numerical inverse Laplace transform algorithm
|
| 765 |
+
(described below).
|
| 766 |
+
*degree*
|
| 767 |
+
Number of terms used in the approximation
|
| 768 |
+
|
| 769 |
+
**Algorithms**
|
| 770 |
+
|
| 771 |
+
Mpmath implements four numerical inverse Laplace transform
|
| 772 |
+
algorithms, attributed to: Talbot, Stehfest, and de Hoog,
|
| 773 |
+
Knight and Stokes. These can be selected by using
|
| 774 |
+
*method='talbot'*, *method='stehfest'*, *method='dehoog'* or
|
| 775 |
+
*method='cohen'* or by passing the classes *method=FixedTalbot*,
|
| 776 |
+
*method=Stehfest*, *method=deHoog*, or *method=Cohen*. The functions
|
| 777 |
+
:func:`~mpmath.invlaptalbot`, :func:`~mpmath.invlapstehfest`,
|
| 778 |
+
:func:`~mpmath.invlapdehoog`, and :func:`~mpmath.invlapcohen`
|
| 779 |
+
are also available as shortcuts.
|
| 780 |
+
|
| 781 |
+
All four algorithms implement a heuristic balance between the
|
| 782 |
+
requested precision and the precision used internally for the
|
| 783 |
+
calculations. This has been tuned for a typical exponentially
|
| 784 |
+
decaying function and precision up to few hundred decimal
|
| 785 |
+
digits.
|
| 786 |
+
|
| 787 |
+
The Laplace transform converts the variable time (i.e., along
|
| 788 |
+
a line) into a parameter given by the right half of the
|
| 789 |
+
complex `p`-plane. Singularities, poles, and branch cuts in
|
| 790 |
+
the complex `p`-plane contain all the information regarding
|
| 791 |
+
the time behavior of the corresponding function. Any numerical
|
| 792 |
+
method must therefore sample `p`-plane "close enough" to the
|
| 793 |
+
singularities to accurately characterize them, while not
|
| 794 |
+
getting too close to have catastrophic cancellation, overflow,
|
| 795 |
+
or underflow issues. Most significantly, if one or more of the
|
| 796 |
+
singularities in the `p`-plane is not on the left side of the
|
| 797 |
+
Bromwich contour, its effects will be left out of the computed
|
| 798 |
+
solution, and the answer will be completely wrong.
|
| 799 |
+
|
| 800 |
+
*Talbot*
|
| 801 |
+
|
| 802 |
+
The fixed Talbot method is high accuracy and fast, but the
|
| 803 |
+
method can catastrophically fail for certain classes of time-domain
|
| 804 |
+
behavior, including a Heaviside step function for positive
|
| 805 |
+
time (e.g., `H(t-2)`), or some oscillatory behaviors. The
|
| 806 |
+
Talbot method usually has adjustable parameters, but the
|
| 807 |
+
"fixed" variety implemented here does not. This method
|
| 808 |
+
deforms the Bromwich integral contour in the shape of a
|
| 809 |
+
parabola towards `-\infty`, which leads to problems
|
| 810 |
+
when the solution has a decaying exponential in it (e.g., a
|
| 811 |
+
Heaviside step function is equivalent to multiplying by a
|
| 812 |
+
decaying exponential in Laplace space).
|
| 813 |
+
|
| 814 |
+
*Stehfest*
|
| 815 |
+
|
| 816 |
+
The Stehfest algorithm only uses abscissa along the real axis
|
| 817 |
+
of the complex `p`-plane to estimate the time-domain
|
| 818 |
+
function. Oscillatory time-domain functions have poles away
|
| 819 |
+
from the real axis, so this method does not work well with
|
| 820 |
+
oscillatory functions, especially high-frequency ones. This
|
| 821 |
+
method also depends on summation of terms in a series that
|
| 822 |
+
grows very large, and will have catastrophic cancellation
|
| 823 |
+
during summation if the working precision is too low.
|
| 824 |
+
|
| 825 |
+
*de Hoog et al.*
|
| 826 |
+
|
| 827 |
+
The de Hoog, Knight, and Stokes method is essentially a
|
| 828 |
+
Fourier-series quadrature-type approximation to the Bromwich
|
| 829 |
+
contour integral, with non-linear series acceleration and an
|
| 830 |
+
analytical expression for the remainder term. This method is
|
| 831 |
+
typically one of the most robust. This method also involves the
|
| 832 |
+
greatest amount of overhead, so it is typically the slowest of the
|
| 833 |
+
four methods at high precision.
|
| 834 |
+
|
| 835 |
+
*Cohen*
|
| 836 |
+
|
| 837 |
+
The Cohen method is a trapezoidal rule approximation to the Bromwich
|
| 838 |
+
contour integral, with linear acceleration for alternating
|
| 839 |
+
series. This method is as robust as the de Hoog et al method and the
|
| 840 |
+
fastest of the four methods at high precision, and is therefore the
|
| 841 |
+
default method.
|
| 842 |
+
|
| 843 |
+
**Singularities**
|
| 844 |
+
|
| 845 |
+
All numerical inverse Laplace transform methods have problems
|
| 846 |
+
at large time when the Laplace-space function has poles,
|
| 847 |
+
singularities, or branch cuts to the right of the origin in
|
| 848 |
+
the complex plane. For simple poles in `\bar{f}(p)` at the
|
| 849 |
+
`p`-plane origin, the time function is constant in time (e.g.,
|
| 850 |
+
`\mathcal{L}\left\lbrace 1 \right\rbrace=1/p` has a pole at
|
| 851 |
+
`p=0`). A pole in `\bar{f}(p)` to the left of the origin is a
|
| 852 |
+
decreasing function of time (e.g., `\mathcal{L}\left\lbrace
|
| 853 |
+
e^{-t/2} \right\rbrace=1/(p+1/2)` has a pole at `p=-1/2`), and
|
| 854 |
+
a pole to the right of the origin leads to an increasing
|
| 855 |
+
function in time (e.g., `\mathcal{L}\left\lbrace t e^{t/4}
|
| 856 |
+
\right\rbrace = 1/(p-1/4)^2` has a pole at `p=1/4`). When
|
| 857 |
+
singularities occur off the real `p` axis, the time-domain
|
| 858 |
+
function is oscillatory. For example `\mathcal{L}\left\lbrace
|
| 859 |
+
\mathrm{J}_0(t) \right\rbrace=1/\sqrt{p^2+1}` has a branch cut
|
| 860 |
+
starting at `p=j=\sqrt{-1}` and is a decaying oscillatory
|
| 861 |
+
function, This range of behaviors is illustrated in Duffy [3]
|
| 862 |
+
Figure 4.10.4, p. 228.
|
| 863 |
+
|
| 864 |
+
In general as `p \rightarrow \infty` `t \rightarrow 0` and
|
| 865 |
+
vice-versa. All numerical inverse Laplace transform methods
|
| 866 |
+
require their abscissa to shift closer to the origin for
|
| 867 |
+
larger times. If the abscissa shift left of the rightmost
|
| 868 |
+
singularity in the Laplace domain, the answer will be
|
| 869 |
+
completely wrong (the effect of singularities to the right of
|
| 870 |
+
the Bromwich contour are not included in the results).
|
| 871 |
+
|
| 872 |
+
For example, the following exponentially growing function has
|
| 873 |
+
a pole at `p=3`:
|
| 874 |
+
|
| 875 |
+
.. math ::
|
| 876 |
+
|
| 877 |
+
\bar{f}(p)=\frac{1}{p^2-9}
|
| 878 |
+
|
| 879 |
+
.. math ::
|
| 880 |
+
|
| 881 |
+
f(t)=\frac{1}{3}\sinh 3t
|
| 882 |
+
|
| 883 |
+
>>> mp.dps = 15; mp.pretty = True
|
| 884 |
+
>>> fp = lambda p: 1/(p*p-9)
|
| 885 |
+
>>> ft = lambda t: sinh(3*t)/3
|
| 886 |
+
>>> tt = [0.01,0.1,1.0,10.0]
|
| 887 |
+
>>> ft(tt[0]),invertlaplace(fp,tt[0],method='talbot')
|
| 888 |
+
(0.0100015000675014, 0.0100015000675014)
|
| 889 |
+
>>> ft(tt[1]),invertlaplace(fp,tt[1],method='talbot')
|
| 890 |
+
(0.101506764482381, 0.101506764482381)
|
| 891 |
+
>>> ft(tt[2]),invertlaplace(fp,tt[2],method='talbot')
|
| 892 |
+
(3.33929164246997, 3.33929164246997)
|
| 893 |
+
>>> ft(tt[3]),invertlaplace(fp,tt[3],method='talbot')
|
| 894 |
+
(1781079096920.74, -1.61331069624091e-14)
|
| 895 |
+
|
| 896 |
+
**References**
|
| 897 |
+
|
| 898 |
+
1. [DLMF]_ section 1.14 (http://dlmf.nist.gov/1.14T4)
|
| 899 |
+
2. Cohen, A.M. (2007). Numerical Methods for Laplace Transform
|
| 900 |
+
Inversion, Springer.
|
| 901 |
+
3. Duffy, D.G. (1998). Advanced Engineering Mathematics, CRC Press.
|
| 902 |
+
|
| 903 |
+
**Numerical Inverse Laplace Transform Reviews**
|
| 904 |
+
|
| 905 |
+
1. Bellman, R., R.E. Kalaba, J.A. Lockett (1966). *Numerical
|
| 906 |
+
inversion of the Laplace transform: Applications to Biology,
|
| 907 |
+
Economics, Engineering, and Physics*. Elsevier.
|
| 908 |
+
2. Davies, B., B. Martin (1979). Numerical inversion of the
|
| 909 |
+
Laplace transform: a survey and comparison of methods. *Journal
|
| 910 |
+
of Computational Physics* 33:1-32,
|
| 911 |
+
http://dx.doi.org/10.1016/0021-9991(79)90025-1
|
| 912 |
+
3. Duffy, D.G. (1993). On the numerical inversion of Laplace
|
| 913 |
+
transforms: Comparison of three new methods on characteristic
|
| 914 |
+
problems from applications. *ACM Transactions on Mathematical
|
| 915 |
+
Software* 19(3):333-359, http://dx.doi.org/10.1145/155743.155788
|
| 916 |
+
4. Kuhlman, K.L., (2013). Review of Inverse Laplace Transform
|
| 917 |
+
Algorithms for Laplace-Space Numerical Approaches, *Numerical
|
| 918 |
+
Algorithms*, 63(2):339-355.
|
| 919 |
+
http://dx.doi.org/10.1007/s11075-012-9625-3
|
| 920 |
+
|
| 921 |
+
"""
|
| 922 |
+
|
| 923 |
+
rule = kwargs.get('method', 'cohen')
|
| 924 |
+
if type(rule) is str:
|
| 925 |
+
lrule = rule.lower()
|
| 926 |
+
if lrule == 'talbot':
|
| 927 |
+
rule = ctx._fixed_talbot
|
| 928 |
+
elif lrule == 'stehfest':
|
| 929 |
+
rule = ctx._stehfest
|
| 930 |
+
elif lrule == 'dehoog':
|
| 931 |
+
rule = ctx._de_hoog
|
| 932 |
+
elif rule == 'cohen':
|
| 933 |
+
rule = ctx._cohen
|
| 934 |
+
else:
|
| 935 |
+
raise ValueError("unknown invlap algorithm: %s" % rule)
|
| 936 |
+
else:
|
| 937 |
+
rule = rule(ctx)
|
| 938 |
+
|
| 939 |
+
# determine the vector of Laplace-space parameter
|
| 940 |
+
# needed for the requested method and desired time
|
| 941 |
+
rule.calc_laplace_parameter(t, **kwargs)
|
| 942 |
+
|
| 943 |
+
# compute the Laplace-space function evalutations
|
| 944 |
+
# at the required abscissa.
|
| 945 |
+
fp = [f(p) for p in rule.p]
|
| 946 |
+
|
| 947 |
+
# compute the time-domain solution from the
|
| 948 |
+
# Laplace-space function evaluations
|
| 949 |
+
return rule.calc_time_domain_solution(fp, t)
|
| 950 |
+
|
| 951 |
+
# shortcuts for the above function for specific methods
|
| 952 |
+
def invlaptalbot(ctx, *args, **kwargs):
|
| 953 |
+
kwargs['method'] = 'talbot'
|
| 954 |
+
return ctx.invertlaplace(*args, **kwargs)
|
| 955 |
+
|
| 956 |
+
def invlapstehfest(ctx, *args, **kwargs):
|
| 957 |
+
kwargs['method'] = 'stehfest'
|
| 958 |
+
return ctx.invertlaplace(*args, **kwargs)
|
| 959 |
+
|
| 960 |
+
def invlapdehoog(ctx, *args, **kwargs):
|
| 961 |
+
kwargs['method'] = 'dehoog'
|
| 962 |
+
return ctx.invertlaplace(*args, **kwargs)
|
| 963 |
+
|
| 964 |
+
def invlapcohen(ctx, *args, **kwargs):
|
| 965 |
+
kwargs['method'] = 'cohen'
|
| 966 |
+
return ctx.invertlaplace(*args, **kwargs)
|
| 967 |
+
|
| 968 |
+
|
| 969 |
+
# ****************************************
|
| 970 |
+
|
| 971 |
+
if __name__ == '__main__':
|
| 972 |
+
import doctest
|
| 973 |
+
doctest.testmod()
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (834 Bytes). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/__pycache__/bessel.cpython-311.pyc
ADDED
|
Binary file (63.1 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/__pycache__/elliptic.cpython-311.pyc
ADDED
|
Binary file (57.8 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/__pycache__/factorials.cpython-311.pyc
ADDED
|
Binary file (10.9 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/__pycache__/functions.cpython-311.pyc
ADDED
|
Binary file (33.4 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/__pycache__/hypergeometric.cpython-311.pyc
ADDED
|
Binary file (76.8 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/__pycache__/orthogonal.cpython-311.pyc
ADDED
|
Binary file (25.8 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/__pycache__/rszeta.cpython-311.pyc
ADDED
|
Binary file (73.9 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/__pycache__/zeta.cpython-311.pyc
ADDED
|
Binary file (64.2 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/__pycache__/zetazeros.cpython-311.pyc
ADDED
|
Binary file (45.8 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/functions/orthogonal.py
ADDED
|
@@ -0,0 +1,493 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .functions import defun, defun_wrapped
|
| 2 |
+
|
| 3 |
+
def _hermite_param(ctx, n, z, parabolic_cylinder):
|
| 4 |
+
"""
|
| 5 |
+
Combined calculation of the Hermite polynomial H_n(z) (and its
|
| 6 |
+
generalization to complex n) and the parabolic cylinder
|
| 7 |
+
function D.
|
| 8 |
+
"""
|
| 9 |
+
n, ntyp = ctx._convert_param(n)
|
| 10 |
+
z = ctx.convert(z)
|
| 11 |
+
q = -ctx.mpq_1_2
|
| 12 |
+
# For re(z) > 0, 2F0 -- http://functions.wolfram.com/
|
| 13 |
+
# HypergeometricFunctions/HermiteHGeneral/06/02/0009/
|
| 14 |
+
# Otherwise, there is a reflection formula
|
| 15 |
+
# 2F0 + http://functions.wolfram.com/HypergeometricFunctions/
|
| 16 |
+
# HermiteHGeneral/16/01/01/0006/
|
| 17 |
+
#
|
| 18 |
+
# TODO:
|
| 19 |
+
# An alternative would be to use
|
| 20 |
+
# http://functions.wolfram.com/HypergeometricFunctions/
|
| 21 |
+
# HermiteHGeneral/06/02/0006/
|
| 22 |
+
#
|
| 23 |
+
# Also, the 1F1 expansion
|
| 24 |
+
# http://functions.wolfram.com/HypergeometricFunctions/
|
| 25 |
+
# HermiteHGeneral/26/01/02/0001/
|
| 26 |
+
# should probably be used for tiny z
|
| 27 |
+
if not z:
|
| 28 |
+
T1 = [2, ctx.pi], [n, 0.5], [], [q*(n-1)], [], [], 0
|
| 29 |
+
if parabolic_cylinder:
|
| 30 |
+
T1[1][0] += q*n
|
| 31 |
+
return T1,
|
| 32 |
+
can_use_2f0 = ctx.isnpint(-n) or ctx.re(z) > 0 or \
|
| 33 |
+
(ctx.re(z) == 0 and ctx.im(z) > 0)
|
| 34 |
+
expprec = ctx.prec*4 + 20
|
| 35 |
+
if parabolic_cylinder:
|
| 36 |
+
u = ctx.fmul(ctx.fmul(z,z,prec=expprec), -0.25, exact=True)
|
| 37 |
+
w = ctx.fmul(z, ctx.sqrt(0.5,prec=expprec), prec=expprec)
|
| 38 |
+
else:
|
| 39 |
+
w = z
|
| 40 |
+
w2 = ctx.fmul(w, w, prec=expprec)
|
| 41 |
+
rw2 = ctx.fdiv(1, w2, prec=expprec)
|
| 42 |
+
nrw2 = ctx.fneg(rw2, exact=True)
|
| 43 |
+
nw = ctx.fneg(w, exact=True)
|
| 44 |
+
if can_use_2f0:
|
| 45 |
+
T1 = [2, w], [n, n], [], [], [q*n, q*(n-1)], [], nrw2
|
| 46 |
+
terms = [T1]
|
| 47 |
+
else:
|
| 48 |
+
T1 = [2, nw], [n, n], [], [], [q*n, q*(n-1)], [], nrw2
|
| 49 |
+
T2 = [2, ctx.pi, nw], [n+2, 0.5, 1], [], [q*n], [q*(n-1)], [1-q], w2
|
| 50 |
+
terms = [T1,T2]
|
| 51 |
+
# Multiply by prefactor for D_n
|
| 52 |
+
if parabolic_cylinder:
|
| 53 |
+
expu = ctx.exp(u)
|
| 54 |
+
for i in range(len(terms)):
|
| 55 |
+
terms[i][1][0] += q*n
|
| 56 |
+
terms[i][0].append(expu)
|
| 57 |
+
terms[i][1].append(1)
|
| 58 |
+
return tuple(terms)
|
| 59 |
+
|
| 60 |
+
@defun
|
| 61 |
+
def hermite(ctx, n, z, **kwargs):
|
| 62 |
+
return ctx.hypercomb(lambda: _hermite_param(ctx, n, z, 0), [], **kwargs)
|
| 63 |
+
|
| 64 |
+
@defun
|
| 65 |
+
def pcfd(ctx, n, z, **kwargs):
|
| 66 |
+
r"""
|
| 67 |
+
Gives the parabolic cylinder function in Whittaker's notation
|
| 68 |
+
`D_n(z) = U(-n-1/2, z)` (see :func:`~mpmath.pcfu`).
|
| 69 |
+
It solves the differential equation
|
| 70 |
+
|
| 71 |
+
.. math ::
|
| 72 |
+
|
| 73 |
+
y'' + \left(n + \frac{1}{2} - \frac{1}{4} z^2\right) y = 0.
|
| 74 |
+
|
| 75 |
+
and can be represented in terms of Hermite polynomials
|
| 76 |
+
(see :func:`~mpmath.hermite`) as
|
| 77 |
+
|
| 78 |
+
.. math ::
|
| 79 |
+
|
| 80 |
+
D_n(z) = 2^{-n/2} e^{-z^2/4} H_n\left(\frac{z}{\sqrt{2}}\right).
|
| 81 |
+
|
| 82 |
+
**Plots**
|
| 83 |
+
|
| 84 |
+
.. literalinclude :: /plots/pcfd.py
|
| 85 |
+
.. image :: /plots/pcfd.png
|
| 86 |
+
|
| 87 |
+
**Examples**
|
| 88 |
+
|
| 89 |
+
>>> from mpmath import *
|
| 90 |
+
>>> mp.dps = 25; mp.pretty = True
|
| 91 |
+
>>> pcfd(0,0); pcfd(1,0); pcfd(2,0); pcfd(3,0)
|
| 92 |
+
1.0
|
| 93 |
+
0.0
|
| 94 |
+
-1.0
|
| 95 |
+
0.0
|
| 96 |
+
>>> pcfd(4,0); pcfd(-3,0)
|
| 97 |
+
3.0
|
| 98 |
+
0.6266570686577501256039413
|
| 99 |
+
>>> pcfd('1/2', 2+3j)
|
| 100 |
+
(-5.363331161232920734849056 - 3.858877821790010714163487j)
|
| 101 |
+
>>> pcfd(2, -10)
|
| 102 |
+
1.374906442631438038871515e-9
|
| 103 |
+
|
| 104 |
+
Verifying the differential equation::
|
| 105 |
+
|
| 106 |
+
>>> n = mpf(2.5)
|
| 107 |
+
>>> y = lambda z: pcfd(n,z)
|
| 108 |
+
>>> z = 1.75
|
| 109 |
+
>>> chop(diff(y,z,2) + (n+0.5-0.25*z**2)*y(z))
|
| 110 |
+
0.0
|
| 111 |
+
|
| 112 |
+
Rational Taylor series expansion when `n` is an integer::
|
| 113 |
+
|
| 114 |
+
>>> taylor(lambda z: pcfd(5,z), 0, 7)
|
| 115 |
+
[0.0, 15.0, 0.0, -13.75, 0.0, 3.96875, 0.0, -0.6015625]
|
| 116 |
+
|
| 117 |
+
"""
|
| 118 |
+
return ctx.hypercomb(lambda: _hermite_param(ctx, n, z, 1), [], **kwargs)
|
| 119 |
+
|
| 120 |
+
@defun
|
| 121 |
+
def pcfu(ctx, a, z, **kwargs):
|
| 122 |
+
r"""
|
| 123 |
+
Gives the parabolic cylinder function `U(a,z)`, which may be
|
| 124 |
+
defined for `\Re(z) > 0` in terms of the confluent
|
| 125 |
+
U-function (see :func:`~mpmath.hyperu`) by
|
| 126 |
+
|
| 127 |
+
.. math ::
|
| 128 |
+
|
| 129 |
+
U(a,z) = 2^{-\frac{1}{4}-\frac{a}{2}} e^{-\frac{1}{4} z^2}
|
| 130 |
+
U\left(\frac{a}{2}+\frac{1}{4},
|
| 131 |
+
\frac{1}{2}, \frac{1}{2}z^2\right)
|
| 132 |
+
|
| 133 |
+
or, for arbitrary `z`,
|
| 134 |
+
|
| 135 |
+
.. math ::
|
| 136 |
+
|
| 137 |
+
e^{-\frac{1}{4}z^2} U(a,z) =
|
| 138 |
+
U(a,0) \,_1F_1\left(-\tfrac{a}{2}+\tfrac{1}{4};
|
| 139 |
+
\tfrac{1}{2}; -\tfrac{1}{2}z^2\right) +
|
| 140 |
+
U'(a,0) z \,_1F_1\left(-\tfrac{a}{2}+\tfrac{3}{4};
|
| 141 |
+
\tfrac{3}{2}; -\tfrac{1}{2}z^2\right).
|
| 142 |
+
|
| 143 |
+
**Examples**
|
| 144 |
+
|
| 145 |
+
Connection to other functions::
|
| 146 |
+
|
| 147 |
+
>>> from mpmath import *
|
| 148 |
+
>>> mp.dps = 25; mp.pretty = True
|
| 149 |
+
>>> z = mpf(3)
|
| 150 |
+
>>> pcfu(0.5,z)
|
| 151 |
+
0.03210358129311151450551963
|
| 152 |
+
>>> sqrt(pi/2)*exp(z**2/4)*erfc(z/sqrt(2))
|
| 153 |
+
0.03210358129311151450551963
|
| 154 |
+
>>> pcfu(0.5,-z)
|
| 155 |
+
23.75012332835297233711255
|
| 156 |
+
>>> sqrt(pi/2)*exp(z**2/4)*erfc(-z/sqrt(2))
|
| 157 |
+
23.75012332835297233711255
|
| 158 |
+
>>> pcfu(0.5,-z)
|
| 159 |
+
23.75012332835297233711255
|
| 160 |
+
>>> sqrt(pi/2)*exp(z**2/4)*erfc(-z/sqrt(2))
|
| 161 |
+
23.75012332835297233711255
|
| 162 |
+
|
| 163 |
+
"""
|
| 164 |
+
n, _ = ctx._convert_param(a)
|
| 165 |
+
return ctx.pcfd(-n-ctx.mpq_1_2, z)
|
| 166 |
+
|
| 167 |
+
@defun
|
| 168 |
+
def pcfv(ctx, a, z, **kwargs):
|
| 169 |
+
r"""
|
| 170 |
+
Gives the parabolic cylinder function `V(a,z)`, which can be
|
| 171 |
+
represented in terms of :func:`~mpmath.pcfu` as
|
| 172 |
+
|
| 173 |
+
.. math ::
|
| 174 |
+
|
| 175 |
+
V(a,z) = \frac{\Gamma(a+\tfrac{1}{2}) (U(a,-z)-\sin(\pi a) U(a,z)}{\pi}.
|
| 176 |
+
|
| 177 |
+
**Examples**
|
| 178 |
+
|
| 179 |
+
Wronskian relation between `U` and `V`::
|
| 180 |
+
|
| 181 |
+
>>> from mpmath import *
|
| 182 |
+
>>> mp.dps = 25; mp.pretty = True
|
| 183 |
+
>>> a, z = 2, 3
|
| 184 |
+
>>> pcfu(a,z)*diff(pcfv,(a,z),(0,1))-diff(pcfu,(a,z),(0,1))*pcfv(a,z)
|
| 185 |
+
0.7978845608028653558798921
|
| 186 |
+
>>> sqrt(2/pi)
|
| 187 |
+
0.7978845608028653558798921
|
| 188 |
+
>>> a, z = 2.5, 3
|
| 189 |
+
>>> pcfu(a,z)*diff(pcfv,(a,z),(0,1))-diff(pcfu,(a,z),(0,1))*pcfv(a,z)
|
| 190 |
+
0.7978845608028653558798921
|
| 191 |
+
>>> a, z = 0.25, -1
|
| 192 |
+
>>> pcfu(a,z)*diff(pcfv,(a,z),(0,1))-diff(pcfu,(a,z),(0,1))*pcfv(a,z)
|
| 193 |
+
0.7978845608028653558798921
|
| 194 |
+
>>> a, z = 2+1j, 2+3j
|
| 195 |
+
>>> chop(pcfu(a,z)*diff(pcfv,(a,z),(0,1))-diff(pcfu,(a,z),(0,1))*pcfv(a,z))
|
| 196 |
+
0.7978845608028653558798921
|
| 197 |
+
|
| 198 |
+
"""
|
| 199 |
+
n, ntype = ctx._convert_param(a)
|
| 200 |
+
z = ctx.convert(z)
|
| 201 |
+
q = ctx.mpq_1_2
|
| 202 |
+
r = ctx.mpq_1_4
|
| 203 |
+
if ntype == 'Q' and ctx.isint(n*2):
|
| 204 |
+
# Faster for half-integers
|
| 205 |
+
def h():
|
| 206 |
+
jz = ctx.fmul(z, -1j, exact=True)
|
| 207 |
+
T1terms = _hermite_param(ctx, -n-q, z, 1)
|
| 208 |
+
T2terms = _hermite_param(ctx, n-q, jz, 1)
|
| 209 |
+
for T in T1terms:
|
| 210 |
+
T[0].append(1j)
|
| 211 |
+
T[1].append(1)
|
| 212 |
+
T[3].append(q-n)
|
| 213 |
+
u = ctx.expjpi((q*n-r)) * ctx.sqrt(2/ctx.pi)
|
| 214 |
+
for T in T2terms:
|
| 215 |
+
T[0].append(u)
|
| 216 |
+
T[1].append(1)
|
| 217 |
+
return T1terms + T2terms
|
| 218 |
+
v = ctx.hypercomb(h, [], **kwargs)
|
| 219 |
+
if ctx._is_real_type(n) and ctx._is_real_type(z):
|
| 220 |
+
v = ctx._re(v)
|
| 221 |
+
return v
|
| 222 |
+
else:
|
| 223 |
+
def h(n):
|
| 224 |
+
w = ctx.square_exp_arg(z, -0.25)
|
| 225 |
+
u = ctx.square_exp_arg(z, 0.5)
|
| 226 |
+
e = ctx.exp(w)
|
| 227 |
+
l = [ctx.pi, q, ctx.exp(w)]
|
| 228 |
+
Y1 = l, [-q, n*q+r, 1], [r-q*n], [], [q*n+r], [q], u
|
| 229 |
+
Y2 = l + [z], [-q, n*q-r, 1, 1], [1-r-q*n], [], [q*n+1-r], [1+q], u
|
| 230 |
+
c, s = ctx.cospi_sinpi(r+q*n)
|
| 231 |
+
Y1[0].append(s)
|
| 232 |
+
Y2[0].append(c)
|
| 233 |
+
for Y in (Y1, Y2):
|
| 234 |
+
Y[1].append(1)
|
| 235 |
+
Y[3].append(q-n)
|
| 236 |
+
return Y1, Y2
|
| 237 |
+
return ctx.hypercomb(h, [n], **kwargs)
|
| 238 |
+
|
| 239 |
+
|
| 240 |
+
@defun
|
| 241 |
+
def pcfw(ctx, a, z, **kwargs):
|
| 242 |
+
r"""
|
| 243 |
+
Gives the parabolic cylinder function `W(a,z)` defined in (DLMF 12.14).
|
| 244 |
+
|
| 245 |
+
**Examples**
|
| 246 |
+
|
| 247 |
+
Value at the origin::
|
| 248 |
+
|
| 249 |
+
>>> from mpmath import *
|
| 250 |
+
>>> mp.dps = 25; mp.pretty = True
|
| 251 |
+
>>> a = mpf(0.25)
|
| 252 |
+
>>> pcfw(a,0)
|
| 253 |
+
0.9722833245718180765617104
|
| 254 |
+
>>> power(2,-0.75)*sqrt(abs(gamma(0.25+0.5j*a)/gamma(0.75+0.5j*a)))
|
| 255 |
+
0.9722833245718180765617104
|
| 256 |
+
>>> diff(pcfw,(a,0),(0,1))
|
| 257 |
+
-0.5142533944210078966003624
|
| 258 |
+
>>> -power(2,-0.25)*sqrt(abs(gamma(0.75+0.5j*a)/gamma(0.25+0.5j*a)))
|
| 259 |
+
-0.5142533944210078966003624
|
| 260 |
+
|
| 261 |
+
"""
|
| 262 |
+
n, _ = ctx._convert_param(a)
|
| 263 |
+
z = ctx.convert(z)
|
| 264 |
+
def terms():
|
| 265 |
+
phi2 = ctx.arg(ctx.gamma(0.5 + ctx.j*n))
|
| 266 |
+
phi2 = (ctx.loggamma(0.5+ctx.j*n) - ctx.loggamma(0.5-ctx.j*n))/2j
|
| 267 |
+
rho = ctx.pi/8 + 0.5*phi2
|
| 268 |
+
# XXX: cancellation computing k
|
| 269 |
+
k = ctx.sqrt(1 + ctx.exp(2*ctx.pi*n)) - ctx.exp(ctx.pi*n)
|
| 270 |
+
C = ctx.sqrt(k/2) * ctx.exp(0.25*ctx.pi*n)
|
| 271 |
+
yield C * ctx.expj(rho) * ctx.pcfu(ctx.j*n, z*ctx.expjpi(-0.25))
|
| 272 |
+
yield C * ctx.expj(-rho) * ctx.pcfu(-ctx.j*n, z*ctx.expjpi(0.25))
|
| 273 |
+
v = ctx.sum_accurately(terms)
|
| 274 |
+
if ctx._is_real_type(n) and ctx._is_real_type(z):
|
| 275 |
+
v = ctx._re(v)
|
| 276 |
+
return v
|
| 277 |
+
|
| 278 |
+
"""
|
| 279 |
+
Even/odd PCFs. Useful?
|
| 280 |
+
|
| 281 |
+
@defun
|
| 282 |
+
def pcfy1(ctx, a, z, **kwargs):
|
| 283 |
+
a, _ = ctx._convert_param(n)
|
| 284 |
+
z = ctx.convert(z)
|
| 285 |
+
def h():
|
| 286 |
+
w = ctx.square_exp_arg(z)
|
| 287 |
+
w1 = ctx.fmul(w, -0.25, exact=True)
|
| 288 |
+
w2 = ctx.fmul(w, 0.5, exact=True)
|
| 289 |
+
e = ctx.exp(w1)
|
| 290 |
+
return [e], [1], [], [], [ctx.mpq_1_2*a+ctx.mpq_1_4], [ctx.mpq_1_2], w2
|
| 291 |
+
return ctx.hypercomb(h, [], **kwargs)
|
| 292 |
+
|
| 293 |
+
@defun
|
| 294 |
+
def pcfy2(ctx, a, z, **kwargs):
|
| 295 |
+
a, _ = ctx._convert_param(n)
|
| 296 |
+
z = ctx.convert(z)
|
| 297 |
+
def h():
|
| 298 |
+
w = ctx.square_exp_arg(z)
|
| 299 |
+
w1 = ctx.fmul(w, -0.25, exact=True)
|
| 300 |
+
w2 = ctx.fmul(w, 0.5, exact=True)
|
| 301 |
+
e = ctx.exp(w1)
|
| 302 |
+
return [e, z], [1, 1], [], [], [ctx.mpq_1_2*a+ctx.mpq_3_4], \
|
| 303 |
+
[ctx.mpq_3_2], w2
|
| 304 |
+
return ctx.hypercomb(h, [], **kwargs)
|
| 305 |
+
"""
|
| 306 |
+
|
| 307 |
+
@defun_wrapped
|
| 308 |
+
def gegenbauer(ctx, n, a, z, **kwargs):
|
| 309 |
+
# Special cases: a+0.5, a*2 poles
|
| 310 |
+
if ctx.isnpint(a):
|
| 311 |
+
return 0*(z+n)
|
| 312 |
+
if ctx.isnpint(a+0.5):
|
| 313 |
+
# TODO: something else is required here
|
| 314 |
+
# E.g.: gegenbauer(-2, -0.5, 3) == -12
|
| 315 |
+
if ctx.isnpint(n+1):
|
| 316 |
+
raise NotImplementedError("Gegenbauer function with two limits")
|
| 317 |
+
def h(a):
|
| 318 |
+
a2 = 2*a
|
| 319 |
+
T = [], [], [n+a2], [n+1, a2], [-n, n+a2], [a+0.5], 0.5*(1-z)
|
| 320 |
+
return [T]
|
| 321 |
+
return ctx.hypercomb(h, [a], **kwargs)
|
| 322 |
+
def h(n):
|
| 323 |
+
a2 = 2*a
|
| 324 |
+
T = [], [], [n+a2], [n+1, a2], [-n, n+a2], [a+0.5], 0.5*(1-z)
|
| 325 |
+
return [T]
|
| 326 |
+
return ctx.hypercomb(h, [n], **kwargs)
|
| 327 |
+
|
| 328 |
+
@defun_wrapped
|
| 329 |
+
def jacobi(ctx, n, a, b, x, **kwargs):
|
| 330 |
+
if not ctx.isnpint(a):
|
| 331 |
+
def h(n):
|
| 332 |
+
return (([], [], [a+n+1], [n+1, a+1], [-n, a+b+n+1], [a+1], (1-x)*0.5),)
|
| 333 |
+
return ctx.hypercomb(h, [n], **kwargs)
|
| 334 |
+
if not ctx.isint(b):
|
| 335 |
+
def h(n, a):
|
| 336 |
+
return (([], [], [-b], [n+1, -b-n], [-n, a+b+n+1], [b+1], (x+1)*0.5),)
|
| 337 |
+
return ctx.hypercomb(h, [n, a], **kwargs)
|
| 338 |
+
# XXX: determine appropriate limit
|
| 339 |
+
return ctx.binomial(n+a,n) * ctx.hyp2f1(-n,1+n+a+b,a+1,(1-x)/2, **kwargs)
|
| 340 |
+
|
| 341 |
+
@defun_wrapped
|
| 342 |
+
def laguerre(ctx, n, a, z, **kwargs):
|
| 343 |
+
# XXX: limits, poles
|
| 344 |
+
#if ctx.isnpint(n):
|
| 345 |
+
# return 0*(a+z)
|
| 346 |
+
def h(a):
|
| 347 |
+
return (([], [], [a+n+1], [a+1, n+1], [-n], [a+1], z),)
|
| 348 |
+
return ctx.hypercomb(h, [a], **kwargs)
|
| 349 |
+
|
| 350 |
+
@defun_wrapped
|
| 351 |
+
def legendre(ctx, n, x, **kwargs):
|
| 352 |
+
if ctx.isint(n):
|
| 353 |
+
n = int(n)
|
| 354 |
+
# Accuracy near zeros
|
| 355 |
+
if (n + (n < 0)) & 1:
|
| 356 |
+
if not x:
|
| 357 |
+
return x
|
| 358 |
+
mag = ctx.mag(x)
|
| 359 |
+
if mag < -2*ctx.prec-10:
|
| 360 |
+
return x
|
| 361 |
+
if mag < -5:
|
| 362 |
+
ctx.prec += -mag
|
| 363 |
+
return ctx.hyp2f1(-n,n+1,1,(1-x)/2, **kwargs)
|
| 364 |
+
|
| 365 |
+
@defun
|
| 366 |
+
def legenp(ctx, n, m, z, type=2, **kwargs):
|
| 367 |
+
# Legendre function, 1st kind
|
| 368 |
+
n = ctx.convert(n)
|
| 369 |
+
m = ctx.convert(m)
|
| 370 |
+
# Faster
|
| 371 |
+
if not m:
|
| 372 |
+
return ctx.legendre(n, z, **kwargs)
|
| 373 |
+
# TODO: correct evaluation at singularities
|
| 374 |
+
if type == 2:
|
| 375 |
+
def h(n,m):
|
| 376 |
+
g = m*0.5
|
| 377 |
+
T = [1+z, 1-z], [g, -g], [], [1-m], [-n, n+1], [1-m], 0.5*(1-z)
|
| 378 |
+
return (T,)
|
| 379 |
+
return ctx.hypercomb(h, [n,m], **kwargs)
|
| 380 |
+
if type == 3:
|
| 381 |
+
def h(n,m):
|
| 382 |
+
g = m*0.5
|
| 383 |
+
T = [z+1, z-1], [g, -g], [], [1-m], [-n, n+1], [1-m], 0.5*(1-z)
|
| 384 |
+
return (T,)
|
| 385 |
+
return ctx.hypercomb(h, [n,m], **kwargs)
|
| 386 |
+
raise ValueError("requires type=2 or type=3")
|
| 387 |
+
|
| 388 |
+
@defun
|
| 389 |
+
def legenq(ctx, n, m, z, type=2, **kwargs):
|
| 390 |
+
# Legendre function, 2nd kind
|
| 391 |
+
n = ctx.convert(n)
|
| 392 |
+
m = ctx.convert(m)
|
| 393 |
+
z = ctx.convert(z)
|
| 394 |
+
if z in (1, -1):
|
| 395 |
+
#if ctx.isint(m):
|
| 396 |
+
# return ctx.nan
|
| 397 |
+
#return ctx.inf # unsigned
|
| 398 |
+
return ctx.nan
|
| 399 |
+
if type == 2:
|
| 400 |
+
def h(n, m):
|
| 401 |
+
cos, sin = ctx.cospi_sinpi(m)
|
| 402 |
+
s = 2 * sin / ctx.pi
|
| 403 |
+
c = cos
|
| 404 |
+
a = 1+z
|
| 405 |
+
b = 1-z
|
| 406 |
+
u = m/2
|
| 407 |
+
w = (1-z)/2
|
| 408 |
+
T1 = [s, c, a, b], [-1, 1, u, -u], [], [1-m], \
|
| 409 |
+
[-n, n+1], [1-m], w
|
| 410 |
+
T2 = [-s, a, b], [-1, -u, u], [n+m+1], [n-m+1, m+1], \
|
| 411 |
+
[-n, n+1], [m+1], w
|
| 412 |
+
return T1, T2
|
| 413 |
+
return ctx.hypercomb(h, [n, m], **kwargs)
|
| 414 |
+
if type == 3:
|
| 415 |
+
# The following is faster when there only is a single series
|
| 416 |
+
# Note: not valid for -1 < z < 0 (?)
|
| 417 |
+
if abs(z) > 1:
|
| 418 |
+
def h(n, m):
|
| 419 |
+
T1 = [ctx.expjpi(m), 2, ctx.pi, z, z-1, z+1], \
|
| 420 |
+
[1, -n-1, 0.5, -n-m-1, 0.5*m, 0.5*m], \
|
| 421 |
+
[n+m+1], [n+1.5], \
|
| 422 |
+
[0.5*(2+n+m), 0.5*(1+n+m)], [n+1.5], z**(-2)
|
| 423 |
+
return [T1]
|
| 424 |
+
return ctx.hypercomb(h, [n, m], **kwargs)
|
| 425 |
+
else:
|
| 426 |
+
# not valid for 1 < z < inf ?
|
| 427 |
+
def h(n, m):
|
| 428 |
+
s = 2 * ctx.sinpi(m) / ctx.pi
|
| 429 |
+
c = ctx.expjpi(m)
|
| 430 |
+
a = 1+z
|
| 431 |
+
b = z-1
|
| 432 |
+
u = m/2
|
| 433 |
+
w = (1-z)/2
|
| 434 |
+
T1 = [s, c, a, b], [-1, 1, u, -u], [], [1-m], \
|
| 435 |
+
[-n, n+1], [1-m], w
|
| 436 |
+
T2 = [-s, c, a, b], [-1, 1, -u, u], [n+m+1], [n-m+1, m+1], \
|
| 437 |
+
[-n, n+1], [m+1], w
|
| 438 |
+
return T1, T2
|
| 439 |
+
return ctx.hypercomb(h, [n, m], **kwargs)
|
| 440 |
+
raise ValueError("requires type=2 or type=3")
|
| 441 |
+
|
| 442 |
+
@defun_wrapped
|
| 443 |
+
def chebyt(ctx, n, x, **kwargs):
|
| 444 |
+
if (not x) and ctx.isint(n) and int(ctx._re(n)) % 2 == 1:
|
| 445 |
+
return x * 0
|
| 446 |
+
return ctx.hyp2f1(-n,n,(1,2),(1-x)/2, **kwargs)
|
| 447 |
+
|
| 448 |
+
@defun_wrapped
|
| 449 |
+
def chebyu(ctx, n, x, **kwargs):
|
| 450 |
+
if (not x) and ctx.isint(n) and int(ctx._re(n)) % 2 == 1:
|
| 451 |
+
return x * 0
|
| 452 |
+
return (n+1) * ctx.hyp2f1(-n, n+2, (3,2), (1-x)/2, **kwargs)
|
| 453 |
+
|
| 454 |
+
@defun
|
| 455 |
+
def spherharm(ctx, l, m, theta, phi, **kwargs):
|
| 456 |
+
l = ctx.convert(l)
|
| 457 |
+
m = ctx.convert(m)
|
| 458 |
+
theta = ctx.convert(theta)
|
| 459 |
+
phi = ctx.convert(phi)
|
| 460 |
+
l_isint = ctx.isint(l)
|
| 461 |
+
l_natural = l_isint and l >= 0
|
| 462 |
+
m_isint = ctx.isint(m)
|
| 463 |
+
if l_isint and l < 0 and m_isint:
|
| 464 |
+
return ctx.spherharm(-(l+1), m, theta, phi, **kwargs)
|
| 465 |
+
if theta == 0 and m_isint and m < 0:
|
| 466 |
+
return ctx.zero * 1j
|
| 467 |
+
if l_natural and m_isint:
|
| 468 |
+
if abs(m) > l:
|
| 469 |
+
return ctx.zero * 1j
|
| 470 |
+
# http://functions.wolfram.com/Polynomials/
|
| 471 |
+
# SphericalHarmonicY/26/01/02/0004/
|
| 472 |
+
def h(l,m):
|
| 473 |
+
absm = abs(m)
|
| 474 |
+
C = [-1, ctx.expj(m*phi),
|
| 475 |
+
(2*l+1)*ctx.fac(l+absm)/ctx.pi/ctx.fac(l-absm),
|
| 476 |
+
ctx.sin(theta)**2,
|
| 477 |
+
ctx.fac(absm), 2]
|
| 478 |
+
P = [0.5*m*(ctx.sign(m)+1), 1, 0.5, 0.5*absm, -1, -absm-1]
|
| 479 |
+
return ((C, P, [], [], [absm-l, l+absm+1], [absm+1],
|
| 480 |
+
ctx.sin(0.5*theta)**2),)
|
| 481 |
+
else:
|
| 482 |
+
# http://functions.wolfram.com/HypergeometricFunctions/
|
| 483 |
+
# SphericalHarmonicYGeneral/26/01/02/0001/
|
| 484 |
+
def h(l,m):
|
| 485 |
+
if ctx.isnpint(l-m+1) or ctx.isnpint(l+m+1) or ctx.isnpint(1-m):
|
| 486 |
+
return (([0], [-1], [], [], [], [], 0),)
|
| 487 |
+
cos, sin = ctx.cos_sin(0.5*theta)
|
| 488 |
+
C = [0.5*ctx.expj(m*phi), (2*l+1)/ctx.pi,
|
| 489 |
+
ctx.gamma(l-m+1), ctx.gamma(l+m+1),
|
| 490 |
+
cos**2, sin**2]
|
| 491 |
+
P = [1, 0.5, 0.5, -0.5, 0.5*m, -0.5*m]
|
| 492 |
+
return ((C, P, [], [1-m], [-l,l+1], [1-m], sin**2),)
|
| 493 |
+
return ctx.hypercomb(h, [l,m], **kwargs)
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/matrices/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (314 Bytes). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/matrices/__pycache__/eigen.cpython-311.pyc
ADDED
|
Binary file (31 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/matrices/__pycache__/eigen_symmetric.cpython-311.pyc
ADDED
|
Binary file (70 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/matrices/__pycache__/linalg.cpython-311.pyc
ADDED
|
Binary file (40.1 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/matrices/__pycache__/matrices.cpython-311.pyc
ADDED
|
Binary file (44.8 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/matrices/eigen_symmetric.py
ADDED
|
@@ -0,0 +1,1807 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/python
|
| 2 |
+
# -*- coding: utf-8 -*-
|
| 3 |
+
|
| 4 |
+
##################################################################################################
|
| 5 |
+
# module for the symmetric eigenvalue problem
|
| 6 |
+
# Copyright 2013 Timo Hartmann (thartmann15 at gmail.com)
|
| 7 |
+
#
|
| 8 |
+
# todo:
|
| 9 |
+
# - implement balancing
|
| 10 |
+
#
|
| 11 |
+
##################################################################################################
|
| 12 |
+
|
| 13 |
+
"""
|
| 14 |
+
The symmetric eigenvalue problem.
|
| 15 |
+
---------------------------------
|
| 16 |
+
|
| 17 |
+
This file contains routines for the symmetric eigenvalue problem.
|
| 18 |
+
|
| 19 |
+
high level routines:
|
| 20 |
+
|
| 21 |
+
eigsy : real symmetric (ordinary) eigenvalue problem
|
| 22 |
+
eighe : complex hermitian (ordinary) eigenvalue problem
|
| 23 |
+
eigh : unified interface for eigsy and eighe
|
| 24 |
+
svd_r : singular value decomposition for real matrices
|
| 25 |
+
svd_c : singular value decomposition for complex matrices
|
| 26 |
+
svd : unified interface for svd_r and svd_c
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
low level routines:
|
| 30 |
+
|
| 31 |
+
r_sy_tridiag : reduction of real symmetric matrix to real symmetric tridiagonal matrix
|
| 32 |
+
c_he_tridiag_0 : reduction of complex hermitian matrix to real symmetric tridiagonal matrix
|
| 33 |
+
c_he_tridiag_1 : auxiliary routine to c_he_tridiag_0
|
| 34 |
+
c_he_tridiag_2 : auxiliary routine to c_he_tridiag_0
|
| 35 |
+
tridiag_eigen : solves the real symmetric tridiagonal matrix eigenvalue problem
|
| 36 |
+
svd_r_raw : raw singular value decomposition for real matrices
|
| 37 |
+
svd_c_raw : raw singular value decomposition for complex matrices
|
| 38 |
+
"""
|
| 39 |
+
|
| 40 |
+
from ..libmp.backend import xrange
|
| 41 |
+
from .eigen import defun
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def r_sy_tridiag(ctx, A, D, E, calc_ev = True):
|
| 45 |
+
"""
|
| 46 |
+
This routine transforms a real symmetric matrix A to a real symmetric
|
| 47 |
+
tridiagonal matrix T using an orthogonal similarity transformation:
|
| 48 |
+
Q' * A * Q = T (here ' denotes the matrix transpose).
|
| 49 |
+
The orthogonal matrix Q is build up from Householder reflectors.
|
| 50 |
+
|
| 51 |
+
parameters:
|
| 52 |
+
A (input/output) On input, A contains the real symmetric matrix of
|
| 53 |
+
dimension (n,n). On output, if calc_ev is true, A contains the
|
| 54 |
+
orthogonal matrix Q, otherwise A is destroyed.
|
| 55 |
+
|
| 56 |
+
D (output) real array of length n, contains the diagonal elements
|
| 57 |
+
of the tridiagonal matrix
|
| 58 |
+
|
| 59 |
+
E (output) real array of length n, contains the offdiagonal elements
|
| 60 |
+
of the tridiagonal matrix in E[0:(n-1)] where is the dimension of
|
| 61 |
+
the matrix A. E[n-1] is undefined.
|
| 62 |
+
|
| 63 |
+
calc_ev (input) If calc_ev is true, this routine explicitly calculates the
|
| 64 |
+
orthogonal matrix Q which is then returned in A. If calc_ev is
|
| 65 |
+
false, Q is not explicitly calculated resulting in a shorter run time.
|
| 66 |
+
|
| 67 |
+
This routine is a python translation of the fortran routine tred2.f in the
|
| 68 |
+
software library EISPACK (see netlib.org) which itself is based on the algol
|
| 69 |
+
procedure tred2 described in:
|
| 70 |
+
- Num. Math. 11, p.181-195 (1968) by Martin, Reinsch and Wilkonson
|
| 71 |
+
- Handbook for auto. comp., Vol II, Linear Algebra, p.212-226 (1971)
|
| 72 |
+
|
| 73 |
+
For a good introduction to Householder reflections, see also
|
| 74 |
+
Stoer, Bulirsch - Introduction to Numerical Analysis.
|
| 75 |
+
"""
|
| 76 |
+
|
| 77 |
+
# note : the vector v of the i-th houshoulder reflector is stored in a[(i+1):,i]
|
| 78 |
+
# whereas v/<v,v> is stored in a[i,(i+1):]
|
| 79 |
+
|
| 80 |
+
n = A.rows
|
| 81 |
+
for i in xrange(n - 1, 0, -1):
|
| 82 |
+
# scale the vector
|
| 83 |
+
|
| 84 |
+
scale = 0
|
| 85 |
+
for k in xrange(0, i):
|
| 86 |
+
scale += abs(A[k,i])
|
| 87 |
+
|
| 88 |
+
scale_inv = 0
|
| 89 |
+
if scale != 0:
|
| 90 |
+
scale_inv = 1/scale
|
| 91 |
+
|
| 92 |
+
# sadly there are floating point numbers not equal to zero whose reciprocal is infinity
|
| 93 |
+
|
| 94 |
+
if i == 1 or scale == 0 or ctx.isinf(scale_inv):
|
| 95 |
+
E[i] = A[i-1,i] # nothing to do
|
| 96 |
+
D[i] = 0
|
| 97 |
+
continue
|
| 98 |
+
|
| 99 |
+
# calculate parameters for housholder transformation
|
| 100 |
+
|
| 101 |
+
H = 0
|
| 102 |
+
for k in xrange(0, i):
|
| 103 |
+
A[k,i] *= scale_inv
|
| 104 |
+
H += A[k,i] * A[k,i]
|
| 105 |
+
|
| 106 |
+
F = A[i-1,i]
|
| 107 |
+
G = ctx.sqrt(H)
|
| 108 |
+
if F > 0:
|
| 109 |
+
G = -G
|
| 110 |
+
E[i] = scale * G
|
| 111 |
+
H -= F * G
|
| 112 |
+
A[i-1,i] = F - G
|
| 113 |
+
F = 0
|
| 114 |
+
|
| 115 |
+
# apply housholder transformation
|
| 116 |
+
|
| 117 |
+
for j in xrange(0, i):
|
| 118 |
+
if calc_ev:
|
| 119 |
+
A[i,j] = A[j,i] / H
|
| 120 |
+
|
| 121 |
+
G = 0 # calculate A*U
|
| 122 |
+
for k in xrange(0, j + 1):
|
| 123 |
+
G += A[k,j] * A[k,i]
|
| 124 |
+
for k in xrange(j + 1, i):
|
| 125 |
+
G += A[j,k] * A[k,i]
|
| 126 |
+
|
| 127 |
+
E[j] = G / H # calculate P
|
| 128 |
+
F += E[j] * A[j,i]
|
| 129 |
+
|
| 130 |
+
HH = F / (2 * H)
|
| 131 |
+
|
| 132 |
+
for j in xrange(0, i): # calculate reduced A
|
| 133 |
+
F = A[j,i]
|
| 134 |
+
G = E[j] - HH * F # calculate Q
|
| 135 |
+
E[j] = G
|
| 136 |
+
|
| 137 |
+
for k in xrange(0, j + 1):
|
| 138 |
+
A[k,j] -= F * E[k] + G * A[k,i]
|
| 139 |
+
|
| 140 |
+
D[i] = H
|
| 141 |
+
|
| 142 |
+
for i in xrange(1, n): # better for compatibility
|
| 143 |
+
E[i-1] = E[i]
|
| 144 |
+
E[n-1] = 0
|
| 145 |
+
|
| 146 |
+
if calc_ev:
|
| 147 |
+
D[0] = 0
|
| 148 |
+
for i in xrange(0, n):
|
| 149 |
+
if D[i] != 0:
|
| 150 |
+
for j in xrange(0, i): # accumulate transformation matrices
|
| 151 |
+
G = 0
|
| 152 |
+
for k in xrange(0, i):
|
| 153 |
+
G += A[i,k] * A[k,j]
|
| 154 |
+
for k in xrange(0, i):
|
| 155 |
+
A[k,j] -= G * A[k,i]
|
| 156 |
+
|
| 157 |
+
D[i] = A[i,i]
|
| 158 |
+
A[i,i] = 1
|
| 159 |
+
|
| 160 |
+
for j in xrange(0, i):
|
| 161 |
+
A[j,i] = A[i,j] = 0
|
| 162 |
+
else:
|
| 163 |
+
for i in xrange(0, n):
|
| 164 |
+
D[i] = A[i,i]
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
def c_he_tridiag_0(ctx, A, D, E, T):
|
| 171 |
+
"""
|
| 172 |
+
This routine transforms a complex hermitian matrix A to a real symmetric
|
| 173 |
+
tridiagonal matrix T using an unitary similarity transformation:
|
| 174 |
+
Q' * A * Q = T (here ' denotes the hermitian matrix transpose,
|
| 175 |
+
i.e. transposition und conjugation).
|
| 176 |
+
The unitary matrix Q is build up from Householder reflectors and
|
| 177 |
+
an unitary diagonal matrix.
|
| 178 |
+
|
| 179 |
+
parameters:
|
| 180 |
+
A (input/output) On input, A contains the complex hermitian matrix
|
| 181 |
+
of dimension (n,n). On output, A contains the unitary matrix Q
|
| 182 |
+
in compressed form.
|
| 183 |
+
|
| 184 |
+
D (output) real array of length n, contains the diagonal elements
|
| 185 |
+
of the tridiagonal matrix.
|
| 186 |
+
|
| 187 |
+
E (output) real array of length n, contains the offdiagonal elements
|
| 188 |
+
of the tridiagonal matrix in E[0:(n-1)] where is the dimension of
|
| 189 |
+
the matrix A. E[n-1] is undefined.
|
| 190 |
+
|
| 191 |
+
T (output) complex array of length n, contains a unitary diagonal
|
| 192 |
+
matrix.
|
| 193 |
+
|
| 194 |
+
This routine is a python translation (in slightly modified form) of the fortran
|
| 195 |
+
routine htridi.f in the software library EISPACK (see netlib.org) which itself
|
| 196 |
+
is a complex version of the algol procedure tred1 described in:
|
| 197 |
+
- Num. Math. 11, p.181-195 (1968) by Martin, Reinsch and Wilkonson
|
| 198 |
+
- Handbook for auto. comp., Vol II, Linear Algebra, p.212-226 (1971)
|
| 199 |
+
|
| 200 |
+
For a good introduction to Householder reflections, see also
|
| 201 |
+
Stoer, Bulirsch - Introduction to Numerical Analysis.
|
| 202 |
+
"""
|
| 203 |
+
|
| 204 |
+
n = A.rows
|
| 205 |
+
T[n-1] = 1
|
| 206 |
+
for i in xrange(n - 1, 0, -1):
|
| 207 |
+
|
| 208 |
+
# scale the vector
|
| 209 |
+
|
| 210 |
+
scale = 0
|
| 211 |
+
for k in xrange(0, i):
|
| 212 |
+
scale += abs(ctx.re(A[k,i])) + abs(ctx.im(A[k,i]))
|
| 213 |
+
|
| 214 |
+
scale_inv = 0
|
| 215 |
+
if scale != 0:
|
| 216 |
+
scale_inv = 1 / scale
|
| 217 |
+
|
| 218 |
+
# sadly there are floating point numbers not equal to zero whose reciprocal is infinity
|
| 219 |
+
|
| 220 |
+
if scale == 0 or ctx.isinf(scale_inv):
|
| 221 |
+
E[i] = 0
|
| 222 |
+
D[i] = 0
|
| 223 |
+
T[i-1] = 1
|
| 224 |
+
continue
|
| 225 |
+
|
| 226 |
+
if i == 1:
|
| 227 |
+
F = A[i-1,i]
|
| 228 |
+
f = abs(F)
|
| 229 |
+
E[i] = f
|
| 230 |
+
D[i] = 0
|
| 231 |
+
if f != 0:
|
| 232 |
+
T[i-1] = T[i] * F / f
|
| 233 |
+
else:
|
| 234 |
+
T[i-1] = T[i]
|
| 235 |
+
continue
|
| 236 |
+
|
| 237 |
+
# calculate parameters for housholder transformation
|
| 238 |
+
|
| 239 |
+
H = 0
|
| 240 |
+
for k in xrange(0, i):
|
| 241 |
+
A[k,i] *= scale_inv
|
| 242 |
+
rr = ctx.re(A[k,i])
|
| 243 |
+
ii = ctx.im(A[k,i])
|
| 244 |
+
H += rr * rr + ii * ii
|
| 245 |
+
|
| 246 |
+
F = A[i-1,i]
|
| 247 |
+
f = abs(F)
|
| 248 |
+
G = ctx.sqrt(H)
|
| 249 |
+
H += G * f
|
| 250 |
+
E[i] = scale * G
|
| 251 |
+
if f != 0:
|
| 252 |
+
F = F / f
|
| 253 |
+
TZ = - T[i] * F # T[i-1]=-T[i]*F, but we need T[i-1] as temporary storage
|
| 254 |
+
G *= F
|
| 255 |
+
else:
|
| 256 |
+
TZ = -T[i] # T[i-1]=-T[i]
|
| 257 |
+
A[i-1,i] += G
|
| 258 |
+
F = 0
|
| 259 |
+
|
| 260 |
+
# apply housholder transformation
|
| 261 |
+
|
| 262 |
+
for j in xrange(0, i):
|
| 263 |
+
A[i,j] = A[j,i] / H
|
| 264 |
+
|
| 265 |
+
G = 0 # calculate A*U
|
| 266 |
+
for k in xrange(0, j + 1):
|
| 267 |
+
G += ctx.conj(A[k,j]) * A[k,i]
|
| 268 |
+
for k in xrange(j + 1, i):
|
| 269 |
+
G += A[j,k] * A[k,i]
|
| 270 |
+
|
| 271 |
+
T[j] = G / H # calculate P
|
| 272 |
+
F += ctx.conj(T[j]) * A[j,i]
|
| 273 |
+
|
| 274 |
+
HH = F / (2 * H)
|
| 275 |
+
|
| 276 |
+
for j in xrange(0, i): # calculate reduced A
|
| 277 |
+
F = A[j,i]
|
| 278 |
+
G = T[j] - HH * F # calculate Q
|
| 279 |
+
T[j] = G
|
| 280 |
+
|
| 281 |
+
for k in xrange(0, j + 1):
|
| 282 |
+
A[k,j] -= ctx.conj(F) * T[k] + ctx.conj(G) * A[k,i]
|
| 283 |
+
# as we use the lower left part for storage
|
| 284 |
+
# we have to use the transpose of the normal formula
|
| 285 |
+
|
| 286 |
+
T[i-1] = TZ
|
| 287 |
+
D[i] = H
|
| 288 |
+
|
| 289 |
+
for i in xrange(1, n): # better for compatibility
|
| 290 |
+
E[i-1] = E[i]
|
| 291 |
+
E[n-1] = 0
|
| 292 |
+
|
| 293 |
+
D[0] = 0
|
| 294 |
+
for i in xrange(0, n):
|
| 295 |
+
zw = D[i]
|
| 296 |
+
D[i] = ctx.re(A[i,i])
|
| 297 |
+
A[i,i] = zw
|
| 298 |
+
|
| 299 |
+
|
| 300 |
+
|
| 301 |
+
|
| 302 |
+
|
| 303 |
+
|
| 304 |
+
|
| 305 |
+
def c_he_tridiag_1(ctx, A, T):
|
| 306 |
+
"""
|
| 307 |
+
This routine forms the unitary matrix Q described in c_he_tridiag_0.
|
| 308 |
+
|
| 309 |
+
parameters:
|
| 310 |
+
A (input/output) On input, A is the same matrix as delivered by
|
| 311 |
+
c_he_tridiag_0. On output, A is set to Q.
|
| 312 |
+
|
| 313 |
+
T (input) On input, T is the same array as delivered by c_he_tridiag_0.
|
| 314 |
+
|
| 315 |
+
"""
|
| 316 |
+
|
| 317 |
+
n = A.rows
|
| 318 |
+
|
| 319 |
+
for i in xrange(0, n):
|
| 320 |
+
if A[i,i] != 0:
|
| 321 |
+
for j in xrange(0, i):
|
| 322 |
+
G = 0
|
| 323 |
+
for k in xrange(0, i):
|
| 324 |
+
G += ctx.conj(A[i,k]) * A[k,j]
|
| 325 |
+
for k in xrange(0, i):
|
| 326 |
+
A[k,j] -= G * A[k,i]
|
| 327 |
+
|
| 328 |
+
A[i,i] = 1
|
| 329 |
+
|
| 330 |
+
for j in xrange(0, i):
|
| 331 |
+
A[j,i] = A[i,j] = 0
|
| 332 |
+
|
| 333 |
+
for i in xrange(0, n):
|
| 334 |
+
for k in xrange(0, n):
|
| 335 |
+
A[i,k] *= T[k]
|
| 336 |
+
|
| 337 |
+
|
| 338 |
+
|
| 339 |
+
|
| 340 |
+
def c_he_tridiag_2(ctx, A, T, B):
|
| 341 |
+
"""
|
| 342 |
+
This routine applied the unitary matrix Q described in c_he_tridiag_0
|
| 343 |
+
onto the the matrix B, i.e. it forms Q*B.
|
| 344 |
+
|
| 345 |
+
parameters:
|
| 346 |
+
A (input) On input, A is the same matrix as delivered by c_he_tridiag_0.
|
| 347 |
+
|
| 348 |
+
T (input) On input, T is the same array as delivered by c_he_tridiag_0.
|
| 349 |
+
|
| 350 |
+
B (input/output) On input, B is a complex matrix. On output B is replaced
|
| 351 |
+
by Q*B.
|
| 352 |
+
|
| 353 |
+
This routine is a python translation of the fortran routine htribk.f in the
|
| 354 |
+
software library EISPACK (see netlib.org). See c_he_tridiag_0 for more
|
| 355 |
+
references.
|
| 356 |
+
"""
|
| 357 |
+
|
| 358 |
+
n = A.rows
|
| 359 |
+
|
| 360 |
+
for i in xrange(0, n):
|
| 361 |
+
for k in xrange(0, n):
|
| 362 |
+
B[k,i] *= T[k]
|
| 363 |
+
|
| 364 |
+
for i in xrange(0, n):
|
| 365 |
+
if A[i,i] != 0:
|
| 366 |
+
for j in xrange(0, n):
|
| 367 |
+
G = 0
|
| 368 |
+
for k in xrange(0, i):
|
| 369 |
+
G += ctx.conj(A[i,k]) * B[k,j]
|
| 370 |
+
for k in xrange(0, i):
|
| 371 |
+
B[k,j] -= G * A[k,i]
|
| 372 |
+
|
| 373 |
+
|
| 374 |
+
|
| 375 |
+
|
| 376 |
+
|
| 377 |
+
def tridiag_eigen(ctx, d, e, z = False):
|
| 378 |
+
"""
|
| 379 |
+
This subroutine find the eigenvalues and the first components of the
|
| 380 |
+
eigenvectors of a real symmetric tridiagonal matrix using the implicit
|
| 381 |
+
QL method.
|
| 382 |
+
|
| 383 |
+
parameters:
|
| 384 |
+
|
| 385 |
+
d (input/output) real array of length n. on input, d contains the diagonal
|
| 386 |
+
elements of the input matrix. on output, d contains the eigenvalues in
|
| 387 |
+
ascending order.
|
| 388 |
+
|
| 389 |
+
e (input) real array of length n. on input, e contains the offdiagonal
|
| 390 |
+
elements of the input matrix in e[0:(n-1)]. On output, e has been
|
| 391 |
+
destroyed.
|
| 392 |
+
|
| 393 |
+
z (input/output) If z is equal to False, no eigenvectors will be computed.
|
| 394 |
+
Otherwise on input z should have the format z[0:m,0:n] (i.e. a real or
|
| 395 |
+
complex matrix of dimension (m,n) ). On output this matrix will be
|
| 396 |
+
multiplied by the matrix of the eigenvectors (i.e. the columns of this
|
| 397 |
+
matrix are the eigenvectors): z --> z*EV
|
| 398 |
+
That means if z[i,j]={1 if j==j; 0 otherwise} on input, then on output
|
| 399 |
+
z will contain the first m components of the eigenvectors. That means
|
| 400 |
+
if m is equal to n, the i-th eigenvector will be z[:,i].
|
| 401 |
+
|
| 402 |
+
This routine is a python translation (in slightly modified form) of the
|
| 403 |
+
fortran routine imtql2.f in the software library EISPACK (see netlib.org)
|
| 404 |
+
which itself is based on the algol procudure imtql2 desribed in:
|
| 405 |
+
- num. math. 12, p. 377-383(1968) by matrin and wilkinson
|
| 406 |
+
- modified in num. math. 15, p. 450(1970) by dubrulle
|
| 407 |
+
- handbook for auto. comp., vol. II-linear algebra, p. 241-248 (1971)
|
| 408 |
+
See also the routine gaussq.f in netlog.org or acm algorithm 726.
|
| 409 |
+
"""
|
| 410 |
+
|
| 411 |
+
n = len(d)
|
| 412 |
+
e[n-1] = 0
|
| 413 |
+
iterlim = 2 * ctx.dps
|
| 414 |
+
|
| 415 |
+
for l in xrange(n):
|
| 416 |
+
j = 0
|
| 417 |
+
while 1:
|
| 418 |
+
m = l
|
| 419 |
+
while 1:
|
| 420 |
+
# look for a small subdiagonal element
|
| 421 |
+
if m + 1 == n:
|
| 422 |
+
break
|
| 423 |
+
if abs(e[m]) <= ctx.eps * (abs(d[m]) + abs(d[m + 1])):
|
| 424 |
+
break
|
| 425 |
+
m = m + 1
|
| 426 |
+
if m == l:
|
| 427 |
+
break
|
| 428 |
+
|
| 429 |
+
if j >= iterlim:
|
| 430 |
+
raise RuntimeError("tridiag_eigen: no convergence to an eigenvalue after %d iterations" % iterlim)
|
| 431 |
+
|
| 432 |
+
j += 1
|
| 433 |
+
|
| 434 |
+
# form shift
|
| 435 |
+
|
| 436 |
+
p = d[l]
|
| 437 |
+
g = (d[l + 1] - p) / (2 * e[l])
|
| 438 |
+
r = ctx.hypot(g, 1)
|
| 439 |
+
|
| 440 |
+
if g < 0:
|
| 441 |
+
s = g - r
|
| 442 |
+
else:
|
| 443 |
+
s = g + r
|
| 444 |
+
|
| 445 |
+
g = d[m] - p + e[l] / s
|
| 446 |
+
|
| 447 |
+
s, c, p = 1, 1, 0
|
| 448 |
+
|
| 449 |
+
for i in xrange(m - 1, l - 1, -1):
|
| 450 |
+
f = s * e[i]
|
| 451 |
+
b = c * e[i]
|
| 452 |
+
if abs(f) > abs(g): # this here is a slight improvement also used in gaussq.f or acm algorithm 726.
|
| 453 |
+
c = g / f
|
| 454 |
+
r = ctx.hypot(c, 1)
|
| 455 |
+
e[i + 1] = f * r
|
| 456 |
+
s = 1 / r
|
| 457 |
+
c = c * s
|
| 458 |
+
else:
|
| 459 |
+
s = f / g
|
| 460 |
+
r = ctx.hypot(s, 1)
|
| 461 |
+
e[i + 1] = g * r
|
| 462 |
+
c = 1 / r
|
| 463 |
+
s = s * c
|
| 464 |
+
g = d[i + 1] - p
|
| 465 |
+
r = (d[i] - g) * s + 2 * c * b
|
| 466 |
+
p = s * r
|
| 467 |
+
d[i + 1] = g + p
|
| 468 |
+
g = c * r - b
|
| 469 |
+
|
| 470 |
+
if not isinstance(z, bool):
|
| 471 |
+
# calculate eigenvectors
|
| 472 |
+
for w in xrange(z.rows):
|
| 473 |
+
f = z[w,i+1]
|
| 474 |
+
z[w,i+1] = s * z[w,i] + c * f
|
| 475 |
+
z[w,i ] = c * z[w,i] - s * f
|
| 476 |
+
|
| 477 |
+
d[l] = d[l] - p
|
| 478 |
+
e[l] = g
|
| 479 |
+
e[m] = 0
|
| 480 |
+
|
| 481 |
+
for ii in xrange(1, n):
|
| 482 |
+
# sort eigenvalues and eigenvectors (bubble-sort)
|
| 483 |
+
i = ii - 1
|
| 484 |
+
k = i
|
| 485 |
+
p = d[i]
|
| 486 |
+
for j in xrange(ii, n):
|
| 487 |
+
if d[j] >= p:
|
| 488 |
+
continue
|
| 489 |
+
k = j
|
| 490 |
+
p = d[k]
|
| 491 |
+
if k == i:
|
| 492 |
+
continue
|
| 493 |
+
d[k] = d[i]
|
| 494 |
+
d[i] = p
|
| 495 |
+
|
| 496 |
+
if not isinstance(z, bool):
|
| 497 |
+
for w in xrange(z.rows):
|
| 498 |
+
p = z[w,i]
|
| 499 |
+
z[w,i] = z[w,k]
|
| 500 |
+
z[w,k] = p
|
| 501 |
+
|
| 502 |
+
########################################################################################
|
| 503 |
+
|
| 504 |
+
@defun
|
| 505 |
+
def eigsy(ctx, A, eigvals_only = False, overwrite_a = False):
|
| 506 |
+
"""
|
| 507 |
+
This routine solves the (ordinary) eigenvalue problem for a real symmetric
|
| 508 |
+
square matrix A. Given A, an orthogonal matrix Q is calculated which
|
| 509 |
+
diagonalizes A:
|
| 510 |
+
|
| 511 |
+
Q' A Q = diag(E) and Q Q' = Q' Q = 1
|
| 512 |
+
|
| 513 |
+
Here diag(E) is a diagonal matrix whose diagonal is E.
|
| 514 |
+
' denotes the transpose.
|
| 515 |
+
|
| 516 |
+
The columns of Q are the eigenvectors of A and E contains the eigenvalues:
|
| 517 |
+
|
| 518 |
+
A Q[:,i] = E[i] Q[:,i]
|
| 519 |
+
|
| 520 |
+
|
| 521 |
+
input:
|
| 522 |
+
|
| 523 |
+
A: real matrix of format (n,n) which is symmetric
|
| 524 |
+
(i.e. A=A' or A[i,j]=A[j,i])
|
| 525 |
+
|
| 526 |
+
eigvals_only: if true, calculates only the eigenvalues E.
|
| 527 |
+
if false, calculates both eigenvectors and eigenvalues.
|
| 528 |
+
|
| 529 |
+
overwrite_a: if true, allows modification of A which may improve
|
| 530 |
+
performance. if false, A is not modified.
|
| 531 |
+
|
| 532 |
+
output:
|
| 533 |
+
|
| 534 |
+
E: vector of format (n). contains the eigenvalues of A in ascending order.
|
| 535 |
+
|
| 536 |
+
Q: orthogonal matrix of format (n,n). contains the eigenvectors
|
| 537 |
+
of A as columns.
|
| 538 |
+
|
| 539 |
+
return value:
|
| 540 |
+
|
| 541 |
+
E if eigvals_only is true
|
| 542 |
+
(E, Q) if eigvals_only is false
|
| 543 |
+
|
| 544 |
+
example:
|
| 545 |
+
>>> from mpmath import mp
|
| 546 |
+
>>> A = mp.matrix([[3, 2], [2, 0]])
|
| 547 |
+
>>> E = mp.eigsy(A, eigvals_only = True)
|
| 548 |
+
>>> print(E)
|
| 549 |
+
[-1.0]
|
| 550 |
+
[ 4.0]
|
| 551 |
+
|
| 552 |
+
>>> A = mp.matrix([[1, 2], [2, 3]])
|
| 553 |
+
>>> E, Q = mp.eigsy(A)
|
| 554 |
+
>>> print(mp.chop(A * Q[:,0] - E[0] * Q[:,0]))
|
| 555 |
+
[0.0]
|
| 556 |
+
[0.0]
|
| 557 |
+
|
| 558 |
+
see also: eighe, eigh, eig
|
| 559 |
+
"""
|
| 560 |
+
|
| 561 |
+
if not overwrite_a:
|
| 562 |
+
A = A.copy()
|
| 563 |
+
|
| 564 |
+
d = ctx.zeros(A.rows, 1)
|
| 565 |
+
e = ctx.zeros(A.rows, 1)
|
| 566 |
+
|
| 567 |
+
if eigvals_only:
|
| 568 |
+
r_sy_tridiag(ctx, A, d, e, calc_ev = False)
|
| 569 |
+
tridiag_eigen(ctx, d, e, False)
|
| 570 |
+
return d
|
| 571 |
+
else:
|
| 572 |
+
r_sy_tridiag(ctx, A, d, e, calc_ev = True)
|
| 573 |
+
tridiag_eigen(ctx, d, e, A)
|
| 574 |
+
return (d, A)
|
| 575 |
+
|
| 576 |
+
|
| 577 |
+
@defun
|
| 578 |
+
def eighe(ctx, A, eigvals_only = False, overwrite_a = False):
|
| 579 |
+
"""
|
| 580 |
+
This routine solves the (ordinary) eigenvalue problem for a complex
|
| 581 |
+
hermitian square matrix A. Given A, an unitary matrix Q is calculated which
|
| 582 |
+
diagonalizes A:
|
| 583 |
+
|
| 584 |
+
Q' A Q = diag(E) and Q Q' = Q' Q = 1
|
| 585 |
+
|
| 586 |
+
Here diag(E) a is diagonal matrix whose diagonal is E.
|
| 587 |
+
' denotes the hermitian transpose (i.e. ordinary transposition and
|
| 588 |
+
complex conjugation).
|
| 589 |
+
|
| 590 |
+
The columns of Q are the eigenvectors of A and E contains the eigenvalues:
|
| 591 |
+
|
| 592 |
+
A Q[:,i] = E[i] Q[:,i]
|
| 593 |
+
|
| 594 |
+
|
| 595 |
+
input:
|
| 596 |
+
|
| 597 |
+
A: complex matrix of format (n,n) which is hermitian
|
| 598 |
+
(i.e. A=A' or A[i,j]=conj(A[j,i]))
|
| 599 |
+
|
| 600 |
+
eigvals_only: if true, calculates only the eigenvalues E.
|
| 601 |
+
if false, calculates both eigenvectors and eigenvalues.
|
| 602 |
+
|
| 603 |
+
overwrite_a: if true, allows modification of A which may improve
|
| 604 |
+
performance. if false, A is not modified.
|
| 605 |
+
|
| 606 |
+
output:
|
| 607 |
+
|
| 608 |
+
E: vector of format (n). contains the eigenvalues of A in ascending order.
|
| 609 |
+
|
| 610 |
+
Q: unitary matrix of format (n,n). contains the eigenvectors
|
| 611 |
+
of A as columns.
|
| 612 |
+
|
| 613 |
+
return value:
|
| 614 |
+
|
| 615 |
+
E if eigvals_only is true
|
| 616 |
+
(E, Q) if eigvals_only is false
|
| 617 |
+
|
| 618 |
+
example:
|
| 619 |
+
>>> from mpmath import mp
|
| 620 |
+
>>> A = mp.matrix([[1, -3 - 1j], [-3 + 1j, -2]])
|
| 621 |
+
>>> E = mp.eighe(A, eigvals_only = True)
|
| 622 |
+
>>> print(E)
|
| 623 |
+
[-4.0]
|
| 624 |
+
[ 3.0]
|
| 625 |
+
|
| 626 |
+
>>> A = mp.matrix([[1, 2 + 5j], [2 - 5j, 3]])
|
| 627 |
+
>>> E, Q = mp.eighe(A)
|
| 628 |
+
>>> print(mp.chop(A * Q[:,0] - E[0] * Q[:,0]))
|
| 629 |
+
[0.0]
|
| 630 |
+
[0.0]
|
| 631 |
+
|
| 632 |
+
see also: eigsy, eigh, eig
|
| 633 |
+
"""
|
| 634 |
+
|
| 635 |
+
if not overwrite_a:
|
| 636 |
+
A = A.copy()
|
| 637 |
+
|
| 638 |
+
d = ctx.zeros(A.rows, 1)
|
| 639 |
+
e = ctx.zeros(A.rows, 1)
|
| 640 |
+
t = ctx.zeros(A.rows, 1)
|
| 641 |
+
|
| 642 |
+
if eigvals_only:
|
| 643 |
+
c_he_tridiag_0(ctx, A, d, e, t)
|
| 644 |
+
tridiag_eigen(ctx, d, e, False)
|
| 645 |
+
return d
|
| 646 |
+
else:
|
| 647 |
+
c_he_tridiag_0(ctx, A, d, e, t)
|
| 648 |
+
B = ctx.eye(A.rows)
|
| 649 |
+
tridiag_eigen(ctx, d, e, B)
|
| 650 |
+
c_he_tridiag_2(ctx, A, t, B)
|
| 651 |
+
return (d, B)
|
| 652 |
+
|
| 653 |
+
@defun
|
| 654 |
+
def eigh(ctx, A, eigvals_only = False, overwrite_a = False):
|
| 655 |
+
"""
|
| 656 |
+
"eigh" is a unified interface for "eigsy" and "eighe". Depending on
|
| 657 |
+
whether A is real or complex the appropriate function is called.
|
| 658 |
+
|
| 659 |
+
This routine solves the (ordinary) eigenvalue problem for a real symmetric
|
| 660 |
+
or complex hermitian square matrix A. Given A, an orthogonal (A real) or
|
| 661 |
+
unitary (A complex) matrix Q is calculated which diagonalizes A:
|
| 662 |
+
|
| 663 |
+
Q' A Q = diag(E) and Q Q' = Q' Q = 1
|
| 664 |
+
|
| 665 |
+
Here diag(E) a is diagonal matrix whose diagonal is E.
|
| 666 |
+
' denotes the hermitian transpose (i.e. ordinary transposition and
|
| 667 |
+
complex conjugation).
|
| 668 |
+
|
| 669 |
+
The columns of Q are the eigenvectors of A and E contains the eigenvalues:
|
| 670 |
+
|
| 671 |
+
A Q[:,i] = E[i] Q[:,i]
|
| 672 |
+
|
| 673 |
+
input:
|
| 674 |
+
|
| 675 |
+
A: a real or complex square matrix of format (n,n) which is symmetric
|
| 676 |
+
(i.e. A[i,j]=A[j,i]) or hermitian (i.e. A[i,j]=conj(A[j,i])).
|
| 677 |
+
|
| 678 |
+
eigvals_only: if true, calculates only the eigenvalues E.
|
| 679 |
+
if false, calculates both eigenvectors and eigenvalues.
|
| 680 |
+
|
| 681 |
+
overwrite_a: if true, allows modification of A which may improve
|
| 682 |
+
performance. if false, A is not modified.
|
| 683 |
+
|
| 684 |
+
output:
|
| 685 |
+
|
| 686 |
+
E: vector of format (n). contains the eigenvalues of A in ascending order.
|
| 687 |
+
|
| 688 |
+
Q: an orthogonal or unitary matrix of format (n,n). contains the
|
| 689 |
+
eigenvectors of A as columns.
|
| 690 |
+
|
| 691 |
+
return value:
|
| 692 |
+
|
| 693 |
+
E if eigvals_only is true
|
| 694 |
+
(E, Q) if eigvals_only is false
|
| 695 |
+
|
| 696 |
+
example:
|
| 697 |
+
>>> from mpmath import mp
|
| 698 |
+
>>> A = mp.matrix([[3, 2], [2, 0]])
|
| 699 |
+
>>> E = mp.eigh(A, eigvals_only = True)
|
| 700 |
+
>>> print(E)
|
| 701 |
+
[-1.0]
|
| 702 |
+
[ 4.0]
|
| 703 |
+
|
| 704 |
+
>>> A = mp.matrix([[1, 2], [2, 3]])
|
| 705 |
+
>>> E, Q = mp.eigh(A)
|
| 706 |
+
>>> print(mp.chop(A * Q[:,0] - E[0] * Q[:,0]))
|
| 707 |
+
[0.0]
|
| 708 |
+
[0.0]
|
| 709 |
+
|
| 710 |
+
>>> A = mp.matrix([[1, 2 + 5j], [2 - 5j, 3]])
|
| 711 |
+
>>> E, Q = mp.eigh(A)
|
| 712 |
+
>>> print(mp.chop(A * Q[:,0] - E[0] * Q[:,0]))
|
| 713 |
+
[0.0]
|
| 714 |
+
[0.0]
|
| 715 |
+
|
| 716 |
+
see also: eigsy, eighe, eig
|
| 717 |
+
"""
|
| 718 |
+
|
| 719 |
+
iscomplex = any(type(x) is ctx.mpc for x in A)
|
| 720 |
+
|
| 721 |
+
if iscomplex:
|
| 722 |
+
return ctx.eighe(A, eigvals_only = eigvals_only, overwrite_a = overwrite_a)
|
| 723 |
+
else:
|
| 724 |
+
return ctx.eigsy(A, eigvals_only = eigvals_only, overwrite_a = overwrite_a)
|
| 725 |
+
|
| 726 |
+
|
| 727 |
+
@defun
|
| 728 |
+
def gauss_quadrature(ctx, n, qtype = "legendre", alpha = 0, beta = 0):
|
| 729 |
+
"""
|
| 730 |
+
This routine calulates gaussian quadrature rules for different
|
| 731 |
+
families of orthogonal polynomials. Let (a, b) be an interval,
|
| 732 |
+
W(x) a positive weight function and n a positive integer.
|
| 733 |
+
Then the purpose of this routine is to calculate pairs (x_k, w_k)
|
| 734 |
+
for k=0, 1, 2, ... (n-1) which give
|
| 735 |
+
|
| 736 |
+
int(W(x) * F(x), x = a..b) = sum(w_k * F(x_k),k = 0..(n-1))
|
| 737 |
+
|
| 738 |
+
exact for all polynomials F(x) of degree (strictly) less than 2*n. For all
|
| 739 |
+
integrable functions F(x) the sum is a (more or less) good approximation to
|
| 740 |
+
the integral. The x_k are called nodes (which are the zeros of the
|
| 741 |
+
related orthogonal polynomials) and the w_k are called the weights.
|
| 742 |
+
|
| 743 |
+
parameters
|
| 744 |
+
n (input) The degree of the quadrature rule, i.e. its number of
|
| 745 |
+
nodes.
|
| 746 |
+
|
| 747 |
+
qtype (input) The family of orthogonal polynmomials for which to
|
| 748 |
+
compute the quadrature rule. See the list below.
|
| 749 |
+
|
| 750 |
+
alpha (input) real number, used as parameter for some orthogonal
|
| 751 |
+
polynomials
|
| 752 |
+
|
| 753 |
+
beta (input) real number, used as parameter for some orthogonal
|
| 754 |
+
polynomials.
|
| 755 |
+
|
| 756 |
+
return value
|
| 757 |
+
|
| 758 |
+
(X, W) a pair of two real arrays where x_k = X[k] and w_k = W[k].
|
| 759 |
+
|
| 760 |
+
|
| 761 |
+
orthogonal polynomials:
|
| 762 |
+
|
| 763 |
+
qtype polynomial
|
| 764 |
+
----- ----------
|
| 765 |
+
|
| 766 |
+
"legendre" Legendre polynomials, W(x)=1 on the interval (-1, +1)
|
| 767 |
+
"legendre01" shifted Legendre polynomials, W(x)=1 on the interval (0, +1)
|
| 768 |
+
"hermite" Hermite polynomials, W(x)=exp(-x*x) on (-infinity,+infinity)
|
| 769 |
+
"laguerre" Laguerre polynomials, W(x)=exp(-x) on (0,+infinity)
|
| 770 |
+
"glaguerre" generalized Laguerre polynomials, W(x)=exp(-x)*x**alpha
|
| 771 |
+
on (0, +infinity)
|
| 772 |
+
"chebyshev1" Chebyshev polynomials of the first kind, W(x)=1/sqrt(1-x*x)
|
| 773 |
+
on (-1, +1)
|
| 774 |
+
"chebyshev2" Chebyshev polynomials of the second kind, W(x)=sqrt(1-x*x)
|
| 775 |
+
on (-1, +1)
|
| 776 |
+
"jacobi" Jacobi polynomials, W(x)=(1-x)**alpha * (1+x)**beta on (-1, +1)
|
| 777 |
+
with alpha>-1 and beta>-1
|
| 778 |
+
|
| 779 |
+
examples:
|
| 780 |
+
>>> from mpmath import mp
|
| 781 |
+
>>> f = lambda x: x**8 + 2 * x**6 - 3 * x**4 + 5 * x**2 - 7
|
| 782 |
+
>>> X, W = mp.gauss_quadrature(5, "hermite")
|
| 783 |
+
>>> A = mp.fdot([(f(x), w) for x, w in zip(X, W)])
|
| 784 |
+
>>> B = mp.sqrt(mp.pi) * 57 / 16
|
| 785 |
+
>>> C = mp.quad(lambda x: mp.exp(- x * x) * f(x), [-mp.inf, +mp.inf])
|
| 786 |
+
>>> mp.nprint((mp.chop(A-B, tol = 1e-10), mp.chop(A-C, tol = 1e-10)))
|
| 787 |
+
(0.0, 0.0)
|
| 788 |
+
|
| 789 |
+
>>> f = lambda x: x**5 - 2 * x**4 + 3 * x**3 - 5 * x**2 + 7 * x - 11
|
| 790 |
+
>>> X, W = mp.gauss_quadrature(3, "laguerre")
|
| 791 |
+
>>> A = mp.fdot([(f(x), w) for x, w in zip(X, W)])
|
| 792 |
+
>>> B = 76
|
| 793 |
+
>>> C = mp.quad(lambda x: mp.exp(-x) * f(x), [0, +mp.inf])
|
| 794 |
+
>>> mp.nprint(mp.chop(A-B, tol = 1e-10), mp.chop(A-C, tol = 1e-10))
|
| 795 |
+
.0
|
| 796 |
+
|
| 797 |
+
# orthogonality of the chebyshev polynomials:
|
| 798 |
+
>>> f = lambda x: mp.chebyt(3, x) * mp.chebyt(2, x)
|
| 799 |
+
>>> X, W = mp.gauss_quadrature(3, "chebyshev1")
|
| 800 |
+
>>> A = mp.fdot([(f(x), w) for x, w in zip(X, W)])
|
| 801 |
+
>>> print(mp.chop(A, tol = 1e-10))
|
| 802 |
+
0.0
|
| 803 |
+
|
| 804 |
+
references:
|
| 805 |
+
- golub and welsch, "calculations of gaussian quadrature rules", mathematics of
|
| 806 |
+
computation 23, p. 221-230 (1969)
|
| 807 |
+
- golub, "some modified matrix eigenvalue problems", siam review 15, p. 318-334 (1973)
|
| 808 |
+
- stroud and secrest, "gaussian quadrature formulas", prentice-hall (1966)
|
| 809 |
+
|
| 810 |
+
See also the routine gaussq.f in netlog.org or ACM Transactions on
|
| 811 |
+
Mathematical Software algorithm 726.
|
| 812 |
+
"""
|
| 813 |
+
|
| 814 |
+
d = ctx.zeros(n, 1)
|
| 815 |
+
e = ctx.zeros(n, 1)
|
| 816 |
+
z = ctx.zeros(1, n)
|
| 817 |
+
|
| 818 |
+
z[0,0] = 1
|
| 819 |
+
|
| 820 |
+
if qtype == "legendre":
|
| 821 |
+
# legendre on the range -1 +1 , abramowitz, table 25.4, p.916
|
| 822 |
+
w = 2
|
| 823 |
+
for i in xrange(n):
|
| 824 |
+
j = i + 1
|
| 825 |
+
e[i] = ctx.sqrt(j * j / (4 * j * j - ctx.mpf(1)))
|
| 826 |
+
elif qtype == "legendre01":
|
| 827 |
+
# legendre shifted to 0 1 , abramowitz, table 25.8, p.921
|
| 828 |
+
w = 1
|
| 829 |
+
for i in xrange(n):
|
| 830 |
+
d[i] = 1 / ctx.mpf(2)
|
| 831 |
+
j = i + 1
|
| 832 |
+
e[i] = ctx.sqrt(j * j / (16 * j * j - ctx.mpf(4)))
|
| 833 |
+
elif qtype == "hermite":
|
| 834 |
+
# hermite on the range -inf +inf , abramowitz, table 25.10,p.924
|
| 835 |
+
w = ctx.sqrt(ctx.pi)
|
| 836 |
+
for i in xrange(n):
|
| 837 |
+
j = i + 1
|
| 838 |
+
e[i] = ctx.sqrt(j / ctx.mpf(2))
|
| 839 |
+
elif qtype == "laguerre":
|
| 840 |
+
# laguerre on the range 0 +inf , abramowitz, table 25.9, p. 923
|
| 841 |
+
w = 1
|
| 842 |
+
for i in xrange(n):
|
| 843 |
+
j = i + 1
|
| 844 |
+
d[i] = 2 * j - 1
|
| 845 |
+
e[i] = j
|
| 846 |
+
elif qtype=="chebyshev1":
|
| 847 |
+
# chebyshev polynimials of the first kind
|
| 848 |
+
w = ctx.pi
|
| 849 |
+
for i in xrange(n):
|
| 850 |
+
e[i] = 1 / ctx.mpf(2)
|
| 851 |
+
e[0] = ctx.sqrt(1 / ctx.mpf(2))
|
| 852 |
+
elif qtype == "chebyshev2":
|
| 853 |
+
# chebyshev polynimials of the second kind
|
| 854 |
+
w = ctx.pi / 2
|
| 855 |
+
for i in xrange(n):
|
| 856 |
+
e[i] = 1 / ctx.mpf(2)
|
| 857 |
+
elif qtype == "glaguerre":
|
| 858 |
+
# generalized laguerre on the range 0 +inf
|
| 859 |
+
w = ctx.gamma(1 + alpha)
|
| 860 |
+
for i in xrange(n):
|
| 861 |
+
j = i + 1
|
| 862 |
+
d[i] = 2 * j - 1 + alpha
|
| 863 |
+
e[i] = ctx.sqrt(j * (j + alpha))
|
| 864 |
+
elif qtype == "jacobi":
|
| 865 |
+
# jacobi polynomials
|
| 866 |
+
alpha = ctx.mpf(alpha)
|
| 867 |
+
beta = ctx.mpf(beta)
|
| 868 |
+
ab = alpha + beta
|
| 869 |
+
abi = ab + 2
|
| 870 |
+
w = (2**(ab+1)) * ctx.gamma(alpha + 1) * ctx.gamma(beta + 1) / ctx.gamma(abi)
|
| 871 |
+
d[0] = (beta - alpha) / abi
|
| 872 |
+
e[0] = ctx.sqrt(4 * (1 + alpha) * (1 + beta) / ((abi + 1) * (abi * abi)))
|
| 873 |
+
a2b2 = beta * beta - alpha * alpha
|
| 874 |
+
for i in xrange(1, n):
|
| 875 |
+
j = i + 1
|
| 876 |
+
abi = 2 * j + ab
|
| 877 |
+
d[i] = a2b2 / ((abi - 2) * abi)
|
| 878 |
+
e[i] = ctx.sqrt(4 * j * (j + alpha) * (j + beta) * (j + ab) / ((abi * abi - 1) * abi * abi))
|
| 879 |
+
elif isinstance(qtype, str):
|
| 880 |
+
raise ValueError("unknown quadrature rule \"%s\"" % qtype)
|
| 881 |
+
elif not isinstance(qtype, str):
|
| 882 |
+
w = qtype(d, e)
|
| 883 |
+
else:
|
| 884 |
+
assert 0
|
| 885 |
+
|
| 886 |
+
tridiag_eigen(ctx, d, e, z)
|
| 887 |
+
|
| 888 |
+
for i in xrange(len(z)):
|
| 889 |
+
z[i] *= z[i]
|
| 890 |
+
|
| 891 |
+
z = z.transpose()
|
| 892 |
+
return (d, w * z)
|
| 893 |
+
|
| 894 |
+
##################################################################################################
|
| 895 |
+
##################################################################################################
|
| 896 |
+
##################################################################################################
|
| 897 |
+
|
| 898 |
+
def svd_r_raw(ctx, A, V = False, calc_u = False):
|
| 899 |
+
"""
|
| 900 |
+
This routine computes the singular value decomposition of a matrix A.
|
| 901 |
+
Given A, two orthogonal matrices U and V are calculated such that
|
| 902 |
+
|
| 903 |
+
A = U S V
|
| 904 |
+
|
| 905 |
+
where S is a suitable shaped matrix whose off-diagonal elements are zero.
|
| 906 |
+
The diagonal elements of S are the singular values of A, i.e. the
|
| 907 |
+
squareroots of the eigenvalues of A' A or A A'. Here ' denotes the transpose.
|
| 908 |
+
Householder bidiagonalization and a variant of the QR algorithm is used.
|
| 909 |
+
|
| 910 |
+
overview of the matrices :
|
| 911 |
+
|
| 912 |
+
A : m*n A gets replaced by U
|
| 913 |
+
U : m*n U replaces A. If n>m then only the first m*m block of U is
|
| 914 |
+
non-zero. column-orthogonal: U' U = B
|
| 915 |
+
here B is a n*n matrix whose first min(m,n) diagonal
|
| 916 |
+
elements are 1 and all other elements are zero.
|
| 917 |
+
S : n*n diagonal matrix, only the diagonal elements are stored in
|
| 918 |
+
the array S. only the first min(m,n) diagonal elements are non-zero.
|
| 919 |
+
V : n*n orthogonal: V V' = V' V = 1
|
| 920 |
+
|
| 921 |
+
parameters:
|
| 922 |
+
A (input/output) On input, A contains a real matrix of shape m*n.
|
| 923 |
+
On output, if calc_u is true A contains the column-orthogonal
|
| 924 |
+
matrix U; otherwise A is simply used as workspace and thus destroyed.
|
| 925 |
+
|
| 926 |
+
V (input/output) if false, the matrix V is not calculated. otherwise
|
| 927 |
+
V must be a matrix of shape n*n.
|
| 928 |
+
|
| 929 |
+
calc_u (input) If true, the matrix U is calculated and replaces A.
|
| 930 |
+
if false, U is not calculated and A is simply destroyed
|
| 931 |
+
|
| 932 |
+
return value:
|
| 933 |
+
S an array of length n containing the singular values of A sorted by
|
| 934 |
+
decreasing magnitude. only the first min(m,n) elements are non-zero.
|
| 935 |
+
|
| 936 |
+
This routine is a python translation of the fortran routine svd.f in the
|
| 937 |
+
software library EISPACK (see netlib.org) which itself is based on the
|
| 938 |
+
algol procedure svd described in:
|
| 939 |
+
- num. math. 14, 403-420(1970) by golub and reinsch.
|
| 940 |
+
- wilkinson/reinsch: handbook for auto. comp., vol ii-linear algebra, 134-151(1971).
|
| 941 |
+
|
| 942 |
+
"""
|
| 943 |
+
|
| 944 |
+
m, n = A.rows, A.cols
|
| 945 |
+
|
| 946 |
+
S = ctx.zeros(n, 1)
|
| 947 |
+
|
| 948 |
+
# work is a temporary array of size n
|
| 949 |
+
work = ctx.zeros(n, 1)
|
| 950 |
+
|
| 951 |
+
g = scale = anorm = 0
|
| 952 |
+
maxits = 3 * ctx.dps
|
| 953 |
+
|
| 954 |
+
for i in xrange(n): # householder reduction to bidiagonal form
|
| 955 |
+
work[i] = scale*g
|
| 956 |
+
g = s = scale = 0
|
| 957 |
+
if i < m:
|
| 958 |
+
for k in xrange(i, m):
|
| 959 |
+
scale += ctx.fabs(A[k,i])
|
| 960 |
+
if scale != 0:
|
| 961 |
+
for k in xrange(i, m):
|
| 962 |
+
A[k,i] /= scale
|
| 963 |
+
s += A[k,i] * A[k,i]
|
| 964 |
+
f = A[i,i]
|
| 965 |
+
g = -ctx.sqrt(s)
|
| 966 |
+
if f < 0:
|
| 967 |
+
g = -g
|
| 968 |
+
h = f * g - s
|
| 969 |
+
A[i,i] = f - g
|
| 970 |
+
for j in xrange(i+1, n):
|
| 971 |
+
s = 0
|
| 972 |
+
for k in xrange(i, m):
|
| 973 |
+
s += A[k,i] * A[k,j]
|
| 974 |
+
f = s / h
|
| 975 |
+
for k in xrange(i, m):
|
| 976 |
+
A[k,j] += f * A[k,i]
|
| 977 |
+
for k in xrange(i,m):
|
| 978 |
+
A[k,i] *= scale
|
| 979 |
+
|
| 980 |
+
S[i] = scale * g
|
| 981 |
+
g = s = scale = 0
|
| 982 |
+
|
| 983 |
+
if i < m and i != n - 1:
|
| 984 |
+
for k in xrange(i+1, n):
|
| 985 |
+
scale += ctx.fabs(A[i,k])
|
| 986 |
+
if scale:
|
| 987 |
+
for k in xrange(i+1, n):
|
| 988 |
+
A[i,k] /= scale
|
| 989 |
+
s += A[i,k] * A[i,k]
|
| 990 |
+
f = A[i,i+1]
|
| 991 |
+
g = -ctx.sqrt(s)
|
| 992 |
+
if f < 0:
|
| 993 |
+
g = -g
|
| 994 |
+
h = f * g - s
|
| 995 |
+
A[i,i+1] = f - g
|
| 996 |
+
|
| 997 |
+
for k in xrange(i+1, n):
|
| 998 |
+
work[k] = A[i,k] / h
|
| 999 |
+
|
| 1000 |
+
for j in xrange(i+1, m):
|
| 1001 |
+
s = 0
|
| 1002 |
+
for k in xrange(i+1, n):
|
| 1003 |
+
s += A[j,k] * A[i,k]
|
| 1004 |
+
for k in xrange(i+1, n):
|
| 1005 |
+
A[j,k] += s * work[k]
|
| 1006 |
+
|
| 1007 |
+
for k in xrange(i+1, n):
|
| 1008 |
+
A[i,k] *= scale
|
| 1009 |
+
|
| 1010 |
+
anorm = max(anorm, ctx.fabs(S[i]) + ctx.fabs(work[i]))
|
| 1011 |
+
|
| 1012 |
+
if not isinstance(V, bool):
|
| 1013 |
+
for i in xrange(n-2, -1, -1): # accumulation of right hand transformations
|
| 1014 |
+
V[i+1,i+1] = 1
|
| 1015 |
+
|
| 1016 |
+
if work[i+1] != 0:
|
| 1017 |
+
for j in xrange(i+1, n):
|
| 1018 |
+
V[i,j] = (A[i,j] / A[i,i+1]) / work[i+1]
|
| 1019 |
+
for j in xrange(i+1, n):
|
| 1020 |
+
s = 0
|
| 1021 |
+
for k in xrange(i+1, n):
|
| 1022 |
+
s += A[i,k] * V[j,k]
|
| 1023 |
+
for k in xrange(i+1, n):
|
| 1024 |
+
V[j,k] += s * V[i,k]
|
| 1025 |
+
|
| 1026 |
+
for j in xrange(i+1, n):
|
| 1027 |
+
V[j,i] = V[i,j] = 0
|
| 1028 |
+
|
| 1029 |
+
V[0,0] = 1
|
| 1030 |
+
|
| 1031 |
+
if m<n : minnm = m
|
| 1032 |
+
else : minnm = n
|
| 1033 |
+
|
| 1034 |
+
if calc_u:
|
| 1035 |
+
for i in xrange(minnm-1, -1, -1): # accumulation of left hand transformations
|
| 1036 |
+
g = S[i]
|
| 1037 |
+
for j in xrange(i+1, n):
|
| 1038 |
+
A[i,j] = 0
|
| 1039 |
+
if g != 0:
|
| 1040 |
+
g = 1 / g
|
| 1041 |
+
for j in xrange(i+1, n):
|
| 1042 |
+
s = 0
|
| 1043 |
+
for k in xrange(i+1, m):
|
| 1044 |
+
s += A[k,i] * A[k,j]
|
| 1045 |
+
f = (s / A[i,i]) * g
|
| 1046 |
+
for k in xrange(i, m):
|
| 1047 |
+
A[k,j] += f * A[k,i]
|
| 1048 |
+
for j in xrange(i, m):
|
| 1049 |
+
A[j,i] *= g
|
| 1050 |
+
else:
|
| 1051 |
+
for j in xrange(i, m):
|
| 1052 |
+
A[j,i] = 0
|
| 1053 |
+
A[i,i] += 1
|
| 1054 |
+
|
| 1055 |
+
for k in xrange(n - 1, -1, -1):
|
| 1056 |
+
# diagonalization of the bidiagonal form:
|
| 1057 |
+
# loop over singular values, and over allowed itations
|
| 1058 |
+
|
| 1059 |
+
its = 0
|
| 1060 |
+
while 1:
|
| 1061 |
+
its += 1
|
| 1062 |
+
flag = True
|
| 1063 |
+
|
| 1064 |
+
for l in xrange(k, -1, -1):
|
| 1065 |
+
nm = l-1
|
| 1066 |
+
|
| 1067 |
+
if ctx.fabs(work[l]) + anorm == anorm:
|
| 1068 |
+
flag = False
|
| 1069 |
+
break
|
| 1070 |
+
|
| 1071 |
+
if ctx.fabs(S[nm]) + anorm == anorm:
|
| 1072 |
+
break
|
| 1073 |
+
|
| 1074 |
+
if flag:
|
| 1075 |
+
c = 0
|
| 1076 |
+
s = 1
|
| 1077 |
+
for i in xrange(l, k + 1):
|
| 1078 |
+
f = s * work[i]
|
| 1079 |
+
work[i] *= c
|
| 1080 |
+
if ctx.fabs(f) + anorm == anorm:
|
| 1081 |
+
break
|
| 1082 |
+
g = S[i]
|
| 1083 |
+
h = ctx.hypot(f, g)
|
| 1084 |
+
S[i] = h
|
| 1085 |
+
h = 1 / h
|
| 1086 |
+
c = g * h
|
| 1087 |
+
s = - f * h
|
| 1088 |
+
|
| 1089 |
+
if calc_u:
|
| 1090 |
+
for j in xrange(m):
|
| 1091 |
+
y = A[j,nm]
|
| 1092 |
+
z = A[j,i]
|
| 1093 |
+
A[j,nm] = y * c + z * s
|
| 1094 |
+
A[j,i] = z * c - y * s
|
| 1095 |
+
|
| 1096 |
+
z = S[k]
|
| 1097 |
+
|
| 1098 |
+
if l == k: # convergence
|
| 1099 |
+
if z < 0: # singular value is made nonnegative
|
| 1100 |
+
S[k] = -z
|
| 1101 |
+
if not isinstance(V, bool):
|
| 1102 |
+
for j in xrange(n):
|
| 1103 |
+
V[k,j] = -V[k,j]
|
| 1104 |
+
break
|
| 1105 |
+
|
| 1106 |
+
if its >= maxits:
|
| 1107 |
+
raise RuntimeError("svd: no convergence to an eigenvalue after %d iterations" % its)
|
| 1108 |
+
|
| 1109 |
+
x = S[l] # shift from bottom 2 by 2 minor
|
| 1110 |
+
nm = k-1
|
| 1111 |
+
y = S[nm]
|
| 1112 |
+
g = work[nm]
|
| 1113 |
+
h = work[k]
|
| 1114 |
+
f = ((y - z) * (y + z) + (g - h) * (g + h))/(2 * h * y)
|
| 1115 |
+
g = ctx.hypot(f, 1)
|
| 1116 |
+
if f >= 0: f = ((x - z) * (x + z) + h * ((y / (f + g)) - h)) / x
|
| 1117 |
+
else: f = ((x - z) * (x + z) + h * ((y / (f - g)) - h)) / x
|
| 1118 |
+
|
| 1119 |
+
c = s = 1 # next qt transformation
|
| 1120 |
+
|
| 1121 |
+
for j in xrange(l, nm + 1):
|
| 1122 |
+
g = work[j+1]
|
| 1123 |
+
y = S[j+1]
|
| 1124 |
+
h = s * g
|
| 1125 |
+
g = c * g
|
| 1126 |
+
z = ctx.hypot(f, h)
|
| 1127 |
+
work[j] = z
|
| 1128 |
+
c = f / z
|
| 1129 |
+
s = h / z
|
| 1130 |
+
f = x * c + g * s
|
| 1131 |
+
g = g * c - x * s
|
| 1132 |
+
h = y * s
|
| 1133 |
+
y *= c
|
| 1134 |
+
if not isinstance(V, bool):
|
| 1135 |
+
for jj in xrange(n):
|
| 1136 |
+
x = V[j ,jj]
|
| 1137 |
+
z = V[j+1,jj]
|
| 1138 |
+
V[j ,jj]= x * c + z * s
|
| 1139 |
+
V[j+1 ,jj]= z * c - x * s
|
| 1140 |
+
z = ctx.hypot(f, h)
|
| 1141 |
+
S[j] = z
|
| 1142 |
+
if z != 0: # rotation can be arbitray if z=0
|
| 1143 |
+
z = 1 / z
|
| 1144 |
+
c = f * z
|
| 1145 |
+
s = h * z
|
| 1146 |
+
f = c * g + s * y
|
| 1147 |
+
x = c * y - s * g
|
| 1148 |
+
|
| 1149 |
+
if calc_u:
|
| 1150 |
+
for jj in xrange(m):
|
| 1151 |
+
y = A[jj,j ]
|
| 1152 |
+
z = A[jj,j+1]
|
| 1153 |
+
A[jj,j ] = y * c + z * s
|
| 1154 |
+
A[jj,j+1 ] = z * c - y * s
|
| 1155 |
+
|
| 1156 |
+
work[l] = 0
|
| 1157 |
+
work[k] = f
|
| 1158 |
+
S[k] = x
|
| 1159 |
+
|
| 1160 |
+
##########################
|
| 1161 |
+
|
| 1162 |
+
# Sort singular values into decreasing order (bubble-sort)
|
| 1163 |
+
|
| 1164 |
+
for i in xrange(n):
|
| 1165 |
+
imax = i
|
| 1166 |
+
s = ctx.fabs(S[i]) # s is the current maximal element
|
| 1167 |
+
|
| 1168 |
+
for j in xrange(i + 1, n):
|
| 1169 |
+
c = ctx.fabs(S[j])
|
| 1170 |
+
if c > s:
|
| 1171 |
+
s = c
|
| 1172 |
+
imax = j
|
| 1173 |
+
|
| 1174 |
+
if imax != i:
|
| 1175 |
+
# swap singular values
|
| 1176 |
+
|
| 1177 |
+
z = S[i]
|
| 1178 |
+
S[i] = S[imax]
|
| 1179 |
+
S[imax] = z
|
| 1180 |
+
|
| 1181 |
+
if calc_u:
|
| 1182 |
+
for j in xrange(m):
|
| 1183 |
+
z = A[j,i]
|
| 1184 |
+
A[j,i] = A[j,imax]
|
| 1185 |
+
A[j,imax] = z
|
| 1186 |
+
|
| 1187 |
+
if not isinstance(V, bool):
|
| 1188 |
+
for j in xrange(n):
|
| 1189 |
+
z = V[i,j]
|
| 1190 |
+
V[i,j] = V[imax,j]
|
| 1191 |
+
V[imax,j] = z
|
| 1192 |
+
|
| 1193 |
+
return S
|
| 1194 |
+
|
| 1195 |
+
#######################
|
| 1196 |
+
|
| 1197 |
+
def svd_c_raw(ctx, A, V = False, calc_u = False):
|
| 1198 |
+
"""
|
| 1199 |
+
This routine computes the singular value decomposition of a matrix A.
|
| 1200 |
+
Given A, two unitary matrices U and V are calculated such that
|
| 1201 |
+
|
| 1202 |
+
A = U S V
|
| 1203 |
+
|
| 1204 |
+
where S is a suitable shaped matrix whose off-diagonal elements are zero.
|
| 1205 |
+
The diagonal elements of S are the singular values of A, i.e. the
|
| 1206 |
+
squareroots of the eigenvalues of A' A or A A'. Here ' denotes the hermitian
|
| 1207 |
+
transpose (i.e. transposition and conjugation). Householder bidiagonalization
|
| 1208 |
+
and a variant of the QR algorithm is used.
|
| 1209 |
+
|
| 1210 |
+
overview of the matrices :
|
| 1211 |
+
|
| 1212 |
+
A : m*n A gets replaced by U
|
| 1213 |
+
U : m*n U replaces A. If n>m then only the first m*m block of U is
|
| 1214 |
+
non-zero. column-unitary: U' U = B
|
| 1215 |
+
here B is a n*n matrix whose first min(m,n) diagonal
|
| 1216 |
+
elements are 1 and all other elements are zero.
|
| 1217 |
+
S : n*n diagonal matrix, only the diagonal elements are stored in
|
| 1218 |
+
the array S. only the first min(m,n) diagonal elements are non-zero.
|
| 1219 |
+
V : n*n unitary: V V' = V' V = 1
|
| 1220 |
+
|
| 1221 |
+
parameters:
|
| 1222 |
+
A (input/output) On input, A contains a complex matrix of shape m*n.
|
| 1223 |
+
On output, if calc_u is true A contains the column-unitary
|
| 1224 |
+
matrix U; otherwise A is simply used as workspace and thus destroyed.
|
| 1225 |
+
|
| 1226 |
+
V (input/output) if false, the matrix V is not calculated. otherwise
|
| 1227 |
+
V must be a matrix of shape n*n.
|
| 1228 |
+
|
| 1229 |
+
calc_u (input) If true, the matrix U is calculated and replaces A.
|
| 1230 |
+
if false, U is not calculated and A is simply destroyed
|
| 1231 |
+
|
| 1232 |
+
return value:
|
| 1233 |
+
S an array of length n containing the singular values of A sorted by
|
| 1234 |
+
decreasing magnitude. only the first min(m,n) elements are non-zero.
|
| 1235 |
+
|
| 1236 |
+
This routine is a python translation of the fortran routine svd.f in the
|
| 1237 |
+
software library EISPACK (see netlib.org) which itself is based on the
|
| 1238 |
+
algol procedure svd described in:
|
| 1239 |
+
- num. math. 14, 403-420(1970) by golub and reinsch.
|
| 1240 |
+
- wilkinson/reinsch: handbook for auto. comp., vol ii-linear algebra, 134-151(1971).
|
| 1241 |
+
|
| 1242 |
+
"""
|
| 1243 |
+
|
| 1244 |
+
m, n = A.rows, A.cols
|
| 1245 |
+
|
| 1246 |
+
S = ctx.zeros(n, 1)
|
| 1247 |
+
|
| 1248 |
+
# work is a temporary array of size n
|
| 1249 |
+
work = ctx.zeros(n, 1)
|
| 1250 |
+
lbeta = ctx.zeros(n, 1)
|
| 1251 |
+
rbeta = ctx.zeros(n, 1)
|
| 1252 |
+
dwork = ctx.zeros(n, 1)
|
| 1253 |
+
|
| 1254 |
+
g = scale = anorm = 0
|
| 1255 |
+
maxits = 3 * ctx.dps
|
| 1256 |
+
|
| 1257 |
+
for i in xrange(n): # householder reduction to bidiagonal form
|
| 1258 |
+
dwork[i] = scale * g # dwork are the side-diagonal elements
|
| 1259 |
+
g = s = scale = 0
|
| 1260 |
+
if i < m:
|
| 1261 |
+
for k in xrange(i, m):
|
| 1262 |
+
scale += ctx.fabs(ctx.re(A[k,i])) + ctx.fabs(ctx.im(A[k,i]))
|
| 1263 |
+
if scale != 0:
|
| 1264 |
+
for k in xrange(i, m):
|
| 1265 |
+
A[k,i] /= scale
|
| 1266 |
+
ar = ctx.re(A[k,i])
|
| 1267 |
+
ai = ctx.im(A[k,i])
|
| 1268 |
+
s += ar * ar + ai * ai
|
| 1269 |
+
f = A[i,i]
|
| 1270 |
+
g = -ctx.sqrt(s)
|
| 1271 |
+
if ctx.re(f) < 0:
|
| 1272 |
+
beta = -g - ctx.conj(f)
|
| 1273 |
+
g = -g
|
| 1274 |
+
else:
|
| 1275 |
+
beta = -g + ctx.conj(f)
|
| 1276 |
+
beta /= ctx.conj(beta)
|
| 1277 |
+
beta += 1
|
| 1278 |
+
h = 2 * (ctx.re(f) * g - s)
|
| 1279 |
+
A[i,i] = f - g
|
| 1280 |
+
beta /= h
|
| 1281 |
+
lbeta[i] = (beta / scale) / scale
|
| 1282 |
+
for j in xrange(i+1, n):
|
| 1283 |
+
s = 0
|
| 1284 |
+
for k in xrange(i, m):
|
| 1285 |
+
s += ctx.conj(A[k,i]) * A[k,j]
|
| 1286 |
+
f = beta * s
|
| 1287 |
+
for k in xrange(i, m):
|
| 1288 |
+
A[k,j] += f * A[k,i]
|
| 1289 |
+
for k in xrange(i, m):
|
| 1290 |
+
A[k,i] *= scale
|
| 1291 |
+
|
| 1292 |
+
S[i] = scale * g # S are the diagonal elements
|
| 1293 |
+
g = s = scale = 0
|
| 1294 |
+
|
| 1295 |
+
if i < m and i != n - 1:
|
| 1296 |
+
for k in xrange(i+1, n):
|
| 1297 |
+
scale += ctx.fabs(ctx.re(A[i,k])) + ctx.fabs(ctx.im(A[i,k]))
|
| 1298 |
+
if scale:
|
| 1299 |
+
for k in xrange(i+1, n):
|
| 1300 |
+
A[i,k] /= scale
|
| 1301 |
+
ar = ctx.re(A[i,k])
|
| 1302 |
+
ai = ctx.im(A[i,k])
|
| 1303 |
+
s += ar * ar + ai * ai
|
| 1304 |
+
f = A[i,i+1]
|
| 1305 |
+
g = -ctx.sqrt(s)
|
| 1306 |
+
if ctx.re(f) < 0:
|
| 1307 |
+
beta = -g - ctx.conj(f)
|
| 1308 |
+
g = -g
|
| 1309 |
+
else:
|
| 1310 |
+
beta = -g + ctx.conj(f)
|
| 1311 |
+
|
| 1312 |
+
beta /= ctx.conj(beta)
|
| 1313 |
+
beta += 1
|
| 1314 |
+
|
| 1315 |
+
h = 2 * (ctx.re(f) * g - s)
|
| 1316 |
+
A[i,i+1] = f - g
|
| 1317 |
+
|
| 1318 |
+
beta /= h
|
| 1319 |
+
rbeta[i] = (beta / scale) / scale
|
| 1320 |
+
|
| 1321 |
+
for k in xrange(i+1, n):
|
| 1322 |
+
work[k] = A[i, k]
|
| 1323 |
+
|
| 1324 |
+
for j in xrange(i+1, m):
|
| 1325 |
+
s = 0
|
| 1326 |
+
for k in xrange(i+1, n):
|
| 1327 |
+
s += ctx.conj(A[i,k]) * A[j,k]
|
| 1328 |
+
f = s * beta
|
| 1329 |
+
for k in xrange(i+1,n):
|
| 1330 |
+
A[j,k] += f * work[k]
|
| 1331 |
+
|
| 1332 |
+
for k in xrange(i+1, n):
|
| 1333 |
+
A[i,k] *= scale
|
| 1334 |
+
|
| 1335 |
+
anorm = max(anorm,ctx.fabs(S[i]) + ctx.fabs(dwork[i]))
|
| 1336 |
+
|
| 1337 |
+
if not isinstance(V, bool):
|
| 1338 |
+
for i in xrange(n-2, -1, -1): # accumulation of right hand transformations
|
| 1339 |
+
V[i+1,i+1] = 1
|
| 1340 |
+
|
| 1341 |
+
if dwork[i+1] != 0:
|
| 1342 |
+
f = ctx.conj(rbeta[i])
|
| 1343 |
+
for j in xrange(i+1, n):
|
| 1344 |
+
V[i,j] = A[i,j] * f
|
| 1345 |
+
for j in xrange(i+1, n):
|
| 1346 |
+
s = 0
|
| 1347 |
+
for k in xrange(i+1, n):
|
| 1348 |
+
s += ctx.conj(A[i,k]) * V[j,k]
|
| 1349 |
+
for k in xrange(i+1, n):
|
| 1350 |
+
V[j,k] += s * V[i,k]
|
| 1351 |
+
|
| 1352 |
+
for j in xrange(i+1,n):
|
| 1353 |
+
V[j,i] = V[i,j] = 0
|
| 1354 |
+
|
| 1355 |
+
V[0,0] = 1
|
| 1356 |
+
|
| 1357 |
+
if m < n : minnm = m
|
| 1358 |
+
else : minnm = n
|
| 1359 |
+
|
| 1360 |
+
if calc_u:
|
| 1361 |
+
for i in xrange(minnm-1, -1, -1): # accumulation of left hand transformations
|
| 1362 |
+
g = S[i]
|
| 1363 |
+
for j in xrange(i+1, n):
|
| 1364 |
+
A[i,j] = 0
|
| 1365 |
+
if g != 0:
|
| 1366 |
+
g = 1 / g
|
| 1367 |
+
for j in xrange(i+1, n):
|
| 1368 |
+
s = 0
|
| 1369 |
+
for k in xrange(i+1, m):
|
| 1370 |
+
s += ctx.conj(A[k,i]) * A[k,j]
|
| 1371 |
+
f = s * ctx.conj(lbeta[i])
|
| 1372 |
+
for k in xrange(i, m):
|
| 1373 |
+
A[k,j] += f * A[k,i]
|
| 1374 |
+
for j in xrange(i, m):
|
| 1375 |
+
A[j,i] *= g
|
| 1376 |
+
else:
|
| 1377 |
+
for j in xrange(i, m):
|
| 1378 |
+
A[j,i] = 0
|
| 1379 |
+
A[i,i] += 1
|
| 1380 |
+
|
| 1381 |
+
for k in xrange(n-1, -1, -1):
|
| 1382 |
+
# diagonalization of the bidiagonal form:
|
| 1383 |
+
# loop over singular values, and over allowed itations
|
| 1384 |
+
|
| 1385 |
+
its = 0
|
| 1386 |
+
while 1:
|
| 1387 |
+
its += 1
|
| 1388 |
+
flag = True
|
| 1389 |
+
|
| 1390 |
+
for l in xrange(k, -1, -1):
|
| 1391 |
+
nm = l - 1
|
| 1392 |
+
|
| 1393 |
+
if ctx.fabs(dwork[l]) + anorm == anorm:
|
| 1394 |
+
flag = False
|
| 1395 |
+
break
|
| 1396 |
+
|
| 1397 |
+
if ctx.fabs(S[nm]) + anorm == anorm:
|
| 1398 |
+
break
|
| 1399 |
+
|
| 1400 |
+
if flag:
|
| 1401 |
+
c = 0
|
| 1402 |
+
s = 1
|
| 1403 |
+
for i in xrange(l, k+1):
|
| 1404 |
+
f = s * dwork[i]
|
| 1405 |
+
dwork[i] *= c
|
| 1406 |
+
if ctx.fabs(f) + anorm == anorm:
|
| 1407 |
+
break
|
| 1408 |
+
g = S[i]
|
| 1409 |
+
h = ctx.hypot(f, g)
|
| 1410 |
+
S[i] = h
|
| 1411 |
+
h = 1 / h
|
| 1412 |
+
c = g * h
|
| 1413 |
+
s = -f * h
|
| 1414 |
+
|
| 1415 |
+
if calc_u:
|
| 1416 |
+
for j in xrange(m):
|
| 1417 |
+
y = A[j,nm]
|
| 1418 |
+
z = A[j,i]
|
| 1419 |
+
A[j,nm]= y * c + z * s
|
| 1420 |
+
A[j,i] = z * c - y * s
|
| 1421 |
+
|
| 1422 |
+
z = S[k]
|
| 1423 |
+
|
| 1424 |
+
if l == k: # convergence
|
| 1425 |
+
if z < 0: # singular value is made nonnegative
|
| 1426 |
+
S[k] = -z
|
| 1427 |
+
if not isinstance(V, bool):
|
| 1428 |
+
for j in xrange(n):
|
| 1429 |
+
V[k,j] = -V[k,j]
|
| 1430 |
+
break
|
| 1431 |
+
|
| 1432 |
+
if its >= maxits:
|
| 1433 |
+
raise RuntimeError("svd: no convergence to an eigenvalue after %d iterations" % its)
|
| 1434 |
+
|
| 1435 |
+
x = S[l] # shift from bottom 2 by 2 minor
|
| 1436 |
+
nm = k-1
|
| 1437 |
+
y = S[nm]
|
| 1438 |
+
g = dwork[nm]
|
| 1439 |
+
h = dwork[k]
|
| 1440 |
+
f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2 * h * y)
|
| 1441 |
+
g = ctx.hypot(f, 1)
|
| 1442 |
+
if f >=0: f = (( x - z) *( x + z) + h *((y / (f + g)) - h)) / x
|
| 1443 |
+
else: f = (( x - z) *( x + z) + h *((y / (f - g)) - h)) / x
|
| 1444 |
+
|
| 1445 |
+
c = s = 1 # next qt transformation
|
| 1446 |
+
|
| 1447 |
+
for j in xrange(l, nm + 1):
|
| 1448 |
+
g = dwork[j+1]
|
| 1449 |
+
y = S[j+1]
|
| 1450 |
+
h = s * g
|
| 1451 |
+
g = c * g
|
| 1452 |
+
z = ctx.hypot(f, h)
|
| 1453 |
+
dwork[j] = z
|
| 1454 |
+
c = f / z
|
| 1455 |
+
s = h / z
|
| 1456 |
+
f = x * c + g * s
|
| 1457 |
+
g = g * c - x * s
|
| 1458 |
+
h = y * s
|
| 1459 |
+
y *= c
|
| 1460 |
+
if not isinstance(V, bool):
|
| 1461 |
+
for jj in xrange(n):
|
| 1462 |
+
x = V[j ,jj]
|
| 1463 |
+
z = V[j+1,jj]
|
| 1464 |
+
V[j ,jj]= x * c + z * s
|
| 1465 |
+
V[j+1,jj ]= z * c - x * s
|
| 1466 |
+
z = ctx.hypot(f, h)
|
| 1467 |
+
S[j] = z
|
| 1468 |
+
if z != 0: # rotation can be arbitray if z=0
|
| 1469 |
+
z = 1 / z
|
| 1470 |
+
c = f * z
|
| 1471 |
+
s = h * z
|
| 1472 |
+
f = c * g + s * y
|
| 1473 |
+
x = c * y - s * g
|
| 1474 |
+
if calc_u:
|
| 1475 |
+
for jj in xrange(m):
|
| 1476 |
+
y = A[jj,j ]
|
| 1477 |
+
z = A[jj,j+1]
|
| 1478 |
+
A[jj,j ]= y * c + z * s
|
| 1479 |
+
A[jj,j+1 ]= z * c - y * s
|
| 1480 |
+
|
| 1481 |
+
dwork[l] = 0
|
| 1482 |
+
dwork[k] = f
|
| 1483 |
+
S[k] = x
|
| 1484 |
+
|
| 1485 |
+
##########################
|
| 1486 |
+
|
| 1487 |
+
# Sort singular values into decreasing order (bubble-sort)
|
| 1488 |
+
|
| 1489 |
+
for i in xrange(n):
|
| 1490 |
+
imax = i
|
| 1491 |
+
s = ctx.fabs(S[i]) # s is the current maximal element
|
| 1492 |
+
|
| 1493 |
+
for j in xrange(i + 1, n):
|
| 1494 |
+
c = ctx.fabs(S[j])
|
| 1495 |
+
if c > s:
|
| 1496 |
+
s = c
|
| 1497 |
+
imax = j
|
| 1498 |
+
|
| 1499 |
+
if imax != i:
|
| 1500 |
+
# swap singular values
|
| 1501 |
+
|
| 1502 |
+
z = S[i]
|
| 1503 |
+
S[i] = S[imax]
|
| 1504 |
+
S[imax] = z
|
| 1505 |
+
|
| 1506 |
+
if calc_u:
|
| 1507 |
+
for j in xrange(m):
|
| 1508 |
+
z = A[j,i]
|
| 1509 |
+
A[j,i] = A[j,imax]
|
| 1510 |
+
A[j,imax] = z
|
| 1511 |
+
|
| 1512 |
+
if not isinstance(V, bool):
|
| 1513 |
+
for j in xrange(n):
|
| 1514 |
+
z = V[i,j]
|
| 1515 |
+
V[i,j] = V[imax,j]
|
| 1516 |
+
V[imax,j] = z
|
| 1517 |
+
|
| 1518 |
+
return S
|
| 1519 |
+
|
| 1520 |
+
##################################################################################################
|
| 1521 |
+
|
| 1522 |
+
@defun
|
| 1523 |
+
def svd_r(ctx, A, full_matrices = False, compute_uv = True, overwrite_a = False):
|
| 1524 |
+
"""
|
| 1525 |
+
This routine computes the singular value decomposition of a matrix A.
|
| 1526 |
+
Given A, two orthogonal matrices U and V are calculated such that
|
| 1527 |
+
|
| 1528 |
+
A = U S V and U' U = 1 and V V' = 1
|
| 1529 |
+
|
| 1530 |
+
where S is a suitable shaped matrix whose off-diagonal elements are zero.
|
| 1531 |
+
Here ' denotes the transpose. The diagonal elements of S are the singular
|
| 1532 |
+
values of A, i.e. the squareroots of the eigenvalues of A' A or A A'.
|
| 1533 |
+
|
| 1534 |
+
input:
|
| 1535 |
+
A : a real matrix of shape (m, n)
|
| 1536 |
+
full_matrices : if true, U and V are of shape (m, m) and (n, n).
|
| 1537 |
+
if false, U and V are of shape (m, min(m, n)) and (min(m, n), n).
|
| 1538 |
+
compute_uv : if true, U and V are calculated. if false, only S is calculated.
|
| 1539 |
+
overwrite_a : if true, allows modification of A which may improve
|
| 1540 |
+
performance. if false, A is not modified.
|
| 1541 |
+
|
| 1542 |
+
output:
|
| 1543 |
+
U : an orthogonal matrix: U' U = 1. if full_matrices is true, U is of
|
| 1544 |
+
shape (m, m). ortherwise it is of shape (m, min(m, n)).
|
| 1545 |
+
|
| 1546 |
+
S : an array of length min(m, n) containing the singular values of A sorted by
|
| 1547 |
+
decreasing magnitude.
|
| 1548 |
+
|
| 1549 |
+
V : an orthogonal matrix: V V' = 1. if full_matrices is true, V is of
|
| 1550 |
+
shape (n, n). ortherwise it is of shape (min(m, n), n).
|
| 1551 |
+
|
| 1552 |
+
return value:
|
| 1553 |
+
|
| 1554 |
+
S if compute_uv is false
|
| 1555 |
+
(U, S, V) if compute_uv is true
|
| 1556 |
+
|
| 1557 |
+
overview of the matrices:
|
| 1558 |
+
|
| 1559 |
+
full_matrices true:
|
| 1560 |
+
A : m*n
|
| 1561 |
+
U : m*m U' U = 1
|
| 1562 |
+
S as matrix : m*n
|
| 1563 |
+
V : n*n V V' = 1
|
| 1564 |
+
|
| 1565 |
+
full_matrices false:
|
| 1566 |
+
A : m*n
|
| 1567 |
+
U : m*min(n,m) U' U = 1
|
| 1568 |
+
S as matrix : min(m,n)*min(m,n)
|
| 1569 |
+
V : min(m,n)*n V V' = 1
|
| 1570 |
+
|
| 1571 |
+
examples:
|
| 1572 |
+
|
| 1573 |
+
>>> from mpmath import mp
|
| 1574 |
+
>>> A = mp.matrix([[2, -2, -1], [3, 4, -2], [-2, -2, 0]])
|
| 1575 |
+
>>> S = mp.svd_r(A, compute_uv = False)
|
| 1576 |
+
>>> print(S)
|
| 1577 |
+
[6.0]
|
| 1578 |
+
[3.0]
|
| 1579 |
+
[1.0]
|
| 1580 |
+
|
| 1581 |
+
>>> U, S, V = mp.svd_r(A)
|
| 1582 |
+
>>> print(mp.chop(A - U * mp.diag(S) * V))
|
| 1583 |
+
[0.0 0.0 0.0]
|
| 1584 |
+
[0.0 0.0 0.0]
|
| 1585 |
+
[0.0 0.0 0.0]
|
| 1586 |
+
|
| 1587 |
+
|
| 1588 |
+
see also: svd, svd_c
|
| 1589 |
+
"""
|
| 1590 |
+
|
| 1591 |
+
m, n = A.rows, A.cols
|
| 1592 |
+
|
| 1593 |
+
if not compute_uv:
|
| 1594 |
+
if not overwrite_a:
|
| 1595 |
+
A = A.copy()
|
| 1596 |
+
S = svd_r_raw(ctx, A, V = False, calc_u = False)
|
| 1597 |
+
S = S[:min(m,n)]
|
| 1598 |
+
return S
|
| 1599 |
+
|
| 1600 |
+
if full_matrices and n < m:
|
| 1601 |
+
V = ctx.zeros(m, m)
|
| 1602 |
+
A0 = ctx.zeros(m, m)
|
| 1603 |
+
A0[:,:n] = A
|
| 1604 |
+
S = svd_r_raw(ctx, A0, V, calc_u = True)
|
| 1605 |
+
|
| 1606 |
+
S = S[:n]
|
| 1607 |
+
V = V[:n,:n]
|
| 1608 |
+
|
| 1609 |
+
return (A0, S, V)
|
| 1610 |
+
else:
|
| 1611 |
+
if not overwrite_a:
|
| 1612 |
+
A = A.copy()
|
| 1613 |
+
V = ctx.zeros(n, n)
|
| 1614 |
+
S = svd_r_raw(ctx, A, V, calc_u = True)
|
| 1615 |
+
|
| 1616 |
+
if n > m:
|
| 1617 |
+
if full_matrices == False:
|
| 1618 |
+
V = V[:m,:]
|
| 1619 |
+
|
| 1620 |
+
S = S[:m]
|
| 1621 |
+
A = A[:,:m]
|
| 1622 |
+
|
| 1623 |
+
return (A, S, V)
|
| 1624 |
+
|
| 1625 |
+
##############################
|
| 1626 |
+
|
| 1627 |
+
@defun
|
| 1628 |
+
def svd_c(ctx, A, full_matrices = False, compute_uv = True, overwrite_a = False):
|
| 1629 |
+
"""
|
| 1630 |
+
This routine computes the singular value decomposition of a matrix A.
|
| 1631 |
+
Given A, two unitary matrices U and V are calculated such that
|
| 1632 |
+
|
| 1633 |
+
A = U S V and U' U = 1 and V V' = 1
|
| 1634 |
+
|
| 1635 |
+
where S is a suitable shaped matrix whose off-diagonal elements are zero.
|
| 1636 |
+
Here ' denotes the hermitian transpose (i.e. transposition and complex
|
| 1637 |
+
conjugation). The diagonal elements of S are the singular values of A,
|
| 1638 |
+
i.e. the squareroots of the eigenvalues of A' A or A A'.
|
| 1639 |
+
|
| 1640 |
+
input:
|
| 1641 |
+
A : a complex matrix of shape (m, n)
|
| 1642 |
+
full_matrices : if true, U and V are of shape (m, m) and (n, n).
|
| 1643 |
+
if false, U and V are of shape (m, min(m, n)) and (min(m, n), n).
|
| 1644 |
+
compute_uv : if true, U and V are calculated. if false, only S is calculated.
|
| 1645 |
+
overwrite_a : if true, allows modification of A which may improve
|
| 1646 |
+
performance. if false, A is not modified.
|
| 1647 |
+
|
| 1648 |
+
output:
|
| 1649 |
+
U : an unitary matrix: U' U = 1. if full_matrices is true, U is of
|
| 1650 |
+
shape (m, m). ortherwise it is of shape (m, min(m, n)).
|
| 1651 |
+
|
| 1652 |
+
S : an array of length min(m, n) containing the singular values of A sorted by
|
| 1653 |
+
decreasing magnitude.
|
| 1654 |
+
|
| 1655 |
+
V : an unitary matrix: V V' = 1. if full_matrices is true, V is of
|
| 1656 |
+
shape (n, n). ortherwise it is of shape (min(m, n), n).
|
| 1657 |
+
|
| 1658 |
+
return value:
|
| 1659 |
+
|
| 1660 |
+
S if compute_uv is false
|
| 1661 |
+
(U, S, V) if compute_uv is true
|
| 1662 |
+
|
| 1663 |
+
overview of the matrices:
|
| 1664 |
+
|
| 1665 |
+
full_matrices true:
|
| 1666 |
+
A : m*n
|
| 1667 |
+
U : m*m U' U = 1
|
| 1668 |
+
S as matrix : m*n
|
| 1669 |
+
V : n*n V V' = 1
|
| 1670 |
+
|
| 1671 |
+
full_matrices false:
|
| 1672 |
+
A : m*n
|
| 1673 |
+
U : m*min(n,m) U' U = 1
|
| 1674 |
+
S as matrix : min(m,n)*min(m,n)
|
| 1675 |
+
V : min(m,n)*n V V' = 1
|
| 1676 |
+
|
| 1677 |
+
example:
|
| 1678 |
+
>>> from mpmath import mp
|
| 1679 |
+
>>> A = mp.matrix([[-2j, -1-3j, -2+2j], [2-2j, -1-3j, 1], [-3+1j,-2j,0]])
|
| 1680 |
+
>>> S = mp.svd_c(A, compute_uv = False)
|
| 1681 |
+
>>> print(mp.chop(S - mp.matrix([mp.sqrt(34), mp.sqrt(15), mp.sqrt(6)])))
|
| 1682 |
+
[0.0]
|
| 1683 |
+
[0.0]
|
| 1684 |
+
[0.0]
|
| 1685 |
+
|
| 1686 |
+
>>> U, S, V = mp.svd_c(A)
|
| 1687 |
+
>>> print(mp.chop(A - U * mp.diag(S) * V))
|
| 1688 |
+
[0.0 0.0 0.0]
|
| 1689 |
+
[0.0 0.0 0.0]
|
| 1690 |
+
[0.0 0.0 0.0]
|
| 1691 |
+
|
| 1692 |
+
see also: svd, svd_r
|
| 1693 |
+
"""
|
| 1694 |
+
|
| 1695 |
+
m, n = A.rows, A.cols
|
| 1696 |
+
|
| 1697 |
+
if not compute_uv:
|
| 1698 |
+
if not overwrite_a:
|
| 1699 |
+
A = A.copy()
|
| 1700 |
+
S = svd_c_raw(ctx, A, V = False, calc_u = False)
|
| 1701 |
+
S = S[:min(m,n)]
|
| 1702 |
+
return S
|
| 1703 |
+
|
| 1704 |
+
if full_matrices and n < m:
|
| 1705 |
+
V = ctx.zeros(m, m)
|
| 1706 |
+
A0 = ctx.zeros(m, m)
|
| 1707 |
+
A0[:,:n] = A
|
| 1708 |
+
S = svd_c_raw(ctx, A0, V, calc_u = True)
|
| 1709 |
+
|
| 1710 |
+
S = S[:n]
|
| 1711 |
+
V = V[:n,:n]
|
| 1712 |
+
|
| 1713 |
+
return (A0, S, V)
|
| 1714 |
+
else:
|
| 1715 |
+
if not overwrite_a:
|
| 1716 |
+
A = A.copy()
|
| 1717 |
+
V = ctx.zeros(n, n)
|
| 1718 |
+
S = svd_c_raw(ctx, A, V, calc_u = True)
|
| 1719 |
+
|
| 1720 |
+
if n > m:
|
| 1721 |
+
if full_matrices == False:
|
| 1722 |
+
V = V[:m,:]
|
| 1723 |
+
|
| 1724 |
+
S = S[:m]
|
| 1725 |
+
A = A[:,:m]
|
| 1726 |
+
|
| 1727 |
+
return (A, S, V)
|
| 1728 |
+
|
| 1729 |
+
@defun
|
| 1730 |
+
def svd(ctx, A, full_matrices = False, compute_uv = True, overwrite_a = False):
|
| 1731 |
+
"""
|
| 1732 |
+
"svd" is a unified interface for "svd_r" and "svd_c". Depending on
|
| 1733 |
+
whether A is real or complex the appropriate function is called.
|
| 1734 |
+
|
| 1735 |
+
This routine computes the singular value decomposition of a matrix A.
|
| 1736 |
+
Given A, two orthogonal (A real) or unitary (A complex) matrices U and V
|
| 1737 |
+
are calculated such that
|
| 1738 |
+
|
| 1739 |
+
A = U S V and U' U = 1 and V V' = 1
|
| 1740 |
+
|
| 1741 |
+
where S is a suitable shaped matrix whose off-diagonal elements are zero.
|
| 1742 |
+
Here ' denotes the hermitian transpose (i.e. transposition and complex
|
| 1743 |
+
conjugation). The diagonal elements of S are the singular values of A,
|
| 1744 |
+
i.e. the squareroots of the eigenvalues of A' A or A A'.
|
| 1745 |
+
|
| 1746 |
+
input:
|
| 1747 |
+
A : a real or complex matrix of shape (m, n)
|
| 1748 |
+
full_matrices : if true, U and V are of shape (m, m) and (n, n).
|
| 1749 |
+
if false, U and V are of shape (m, min(m, n)) and (min(m, n), n).
|
| 1750 |
+
compute_uv : if true, U and V are calculated. if false, only S is calculated.
|
| 1751 |
+
overwrite_a : if true, allows modification of A which may improve
|
| 1752 |
+
performance. if false, A is not modified.
|
| 1753 |
+
|
| 1754 |
+
output:
|
| 1755 |
+
U : an orthogonal or unitary matrix: U' U = 1. if full_matrices is true, U is of
|
| 1756 |
+
shape (m, m). ortherwise it is of shape (m, min(m, n)).
|
| 1757 |
+
|
| 1758 |
+
S : an array of length min(m, n) containing the singular values of A sorted by
|
| 1759 |
+
decreasing magnitude.
|
| 1760 |
+
|
| 1761 |
+
V : an orthogonal or unitary matrix: V V' = 1. if full_matrices is true, V is of
|
| 1762 |
+
shape (n, n). ortherwise it is of shape (min(m, n), n).
|
| 1763 |
+
|
| 1764 |
+
return value:
|
| 1765 |
+
|
| 1766 |
+
S if compute_uv is false
|
| 1767 |
+
(U, S, V) if compute_uv is true
|
| 1768 |
+
|
| 1769 |
+
overview of the matrices:
|
| 1770 |
+
|
| 1771 |
+
full_matrices true:
|
| 1772 |
+
A : m*n
|
| 1773 |
+
U : m*m U' U = 1
|
| 1774 |
+
S as matrix : m*n
|
| 1775 |
+
V : n*n V V' = 1
|
| 1776 |
+
|
| 1777 |
+
full_matrices false:
|
| 1778 |
+
A : m*n
|
| 1779 |
+
U : m*min(n,m) U' U = 1
|
| 1780 |
+
S as matrix : min(m,n)*min(m,n)
|
| 1781 |
+
V : min(m,n)*n V V' = 1
|
| 1782 |
+
|
| 1783 |
+
examples:
|
| 1784 |
+
|
| 1785 |
+
>>> from mpmath import mp
|
| 1786 |
+
>>> A = mp.matrix([[2, -2, -1], [3, 4, -2], [-2, -2, 0]])
|
| 1787 |
+
>>> S = mp.svd(A, compute_uv = False)
|
| 1788 |
+
>>> print(S)
|
| 1789 |
+
[6.0]
|
| 1790 |
+
[3.0]
|
| 1791 |
+
[1.0]
|
| 1792 |
+
|
| 1793 |
+
>>> U, S, V = mp.svd(A)
|
| 1794 |
+
>>> print(mp.chop(A - U * mp.diag(S) * V))
|
| 1795 |
+
[0.0 0.0 0.0]
|
| 1796 |
+
[0.0 0.0 0.0]
|
| 1797 |
+
[0.0 0.0 0.0]
|
| 1798 |
+
|
| 1799 |
+
see also: svd_r, svd_c
|
| 1800 |
+
"""
|
| 1801 |
+
|
| 1802 |
+
iscomplex = any(type(x) is ctx.mpc for x in A)
|
| 1803 |
+
|
| 1804 |
+
if iscomplex:
|
| 1805 |
+
return ctx.svd_c(A, full_matrices = full_matrices, compute_uv = compute_uv, overwrite_a = overwrite_a)
|
| 1806 |
+
else:
|
| 1807 |
+
return ctx.svd_r(A, full_matrices = full_matrices, compute_uv = compute_uv, overwrite_a = overwrite_a)
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/tests/__pycache__/test_elliptic.cpython-311.pyc
ADDED
|
Binary file (46.2 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/packaging-24.2.dist-info/LICENSE.APACHE
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
Apache License
|
| 3 |
+
Version 2.0, January 2004
|
| 4 |
+
http://www.apache.org/licenses/
|
| 5 |
+
|
| 6 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 7 |
+
|
| 8 |
+
1. Definitions.
|
| 9 |
+
|
| 10 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 11 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 12 |
+
|
| 13 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 14 |
+
the copyright owner that is granting the License.
|
| 15 |
+
|
| 16 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 17 |
+
other entities that control, are controlled by, or are under common
|
| 18 |
+
control with that entity. For the purposes of this definition,
|
| 19 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 20 |
+
direction or management of such entity, whether by contract or
|
| 21 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 22 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 23 |
+
|
| 24 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 25 |
+
exercising permissions granted by this License.
|
| 26 |
+
|
| 27 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 28 |
+
including but not limited to software source code, documentation
|
| 29 |
+
source, and configuration files.
|
| 30 |
+
|
| 31 |
+
"Object" form shall mean any form resulting from mechanical
|
| 32 |
+
transformation or translation of a Source form, including but
|
| 33 |
+
not limited to compiled object code, generated documentation,
|
| 34 |
+
and conversions to other media types.
|
| 35 |
+
|
| 36 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 37 |
+
Object form, made available under the License, as indicated by a
|
| 38 |
+
copyright notice that is included in or attached to the work
|
| 39 |
+
(an example is provided in the Appendix below).
|
| 40 |
+
|
| 41 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 42 |
+
form, that is based on (or derived from) the Work and for which the
|
| 43 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 44 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 45 |
+
of this License, Derivative Works shall not include works that remain
|
| 46 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 47 |
+
the Work and Derivative Works thereof.
|
| 48 |
+
|
| 49 |
+
"Contribution" shall mean any work of authorship, including
|
| 50 |
+
the original version of the Work and any modifications or additions
|
| 51 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 52 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 53 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 54 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 55 |
+
means any form of electronic, verbal, or written communication sent
|
| 56 |
+
to the Licensor or its representatives, including but not limited to
|
| 57 |
+
communication on electronic mailing lists, source code control systems,
|
| 58 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 59 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 60 |
+
excluding communication that is conspicuously marked or otherwise
|
| 61 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 62 |
+
|
| 63 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 64 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 65 |
+
subsequently incorporated within the Work.
|
| 66 |
+
|
| 67 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 68 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 69 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 70 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 71 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 72 |
+
Work and such Derivative Works in Source or Object form.
|
| 73 |
+
|
| 74 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 75 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 76 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 77 |
+
(except as stated in this section) patent license to make, have made,
|
| 78 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 79 |
+
where such license applies only to those patent claims licensable
|
| 80 |
+
by such Contributor that are necessarily infringed by their
|
| 81 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 82 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 83 |
+
institute patent litigation against any entity (including a
|
| 84 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 85 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 86 |
+
or contributory patent infringement, then any patent licenses
|
| 87 |
+
granted to You under this License for that Work shall terminate
|
| 88 |
+
as of the date such litigation is filed.
|
| 89 |
+
|
| 90 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 91 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 92 |
+
modifications, and in Source or Object form, provided that You
|
| 93 |
+
meet the following conditions:
|
| 94 |
+
|
| 95 |
+
(a) You must give any other recipients of the Work or
|
| 96 |
+
Derivative Works a copy of this License; and
|
| 97 |
+
|
| 98 |
+
(b) You must cause any modified files to carry prominent notices
|
| 99 |
+
stating that You changed the files; and
|
| 100 |
+
|
| 101 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 102 |
+
that You distribute, all copyright, patent, trademark, and
|
| 103 |
+
attribution notices from the Source form of the Work,
|
| 104 |
+
excluding those notices that do not pertain to any part of
|
| 105 |
+
the Derivative Works; and
|
| 106 |
+
|
| 107 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 108 |
+
distribution, then any Derivative Works that You distribute must
|
| 109 |
+
include a readable copy of the attribution notices contained
|
| 110 |
+
within such NOTICE file, excluding those notices that do not
|
| 111 |
+
pertain to any part of the Derivative Works, in at least one
|
| 112 |
+
of the following places: within a NOTICE text file distributed
|
| 113 |
+
as part of the Derivative Works; within the Source form or
|
| 114 |
+
documentation, if provided along with the Derivative Works; or,
|
| 115 |
+
within a display generated by the Derivative Works, if and
|
| 116 |
+
wherever such third-party notices normally appear. The contents
|
| 117 |
+
of the NOTICE file are for informational purposes only and
|
| 118 |
+
do not modify the License. You may add Your own attribution
|
| 119 |
+
notices within Derivative Works that You distribute, alongside
|
| 120 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 121 |
+
that such additional attribution notices cannot be construed
|
| 122 |
+
as modifying the License.
|
| 123 |
+
|
| 124 |
+
You may add Your own copyright statement to Your modifications and
|
| 125 |
+
may provide additional or different license terms and conditions
|
| 126 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 127 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 128 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 129 |
+
the conditions stated in this License.
|
| 130 |
+
|
| 131 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 132 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 133 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 134 |
+
this License, without any additional terms or conditions.
|
| 135 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 136 |
+
the terms of any separate license agreement you may have executed
|
| 137 |
+
with Licensor regarding such Contributions.
|
| 138 |
+
|
| 139 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 140 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 141 |
+
except as required for reasonable and customary use in describing the
|
| 142 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 143 |
+
|
| 144 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 145 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 146 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 147 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 148 |
+
implied, including, without limitation, any warranties or conditions
|
| 149 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 150 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 151 |
+
appropriateness of using or redistributing the Work and assume any
|
| 152 |
+
risks associated with Your exercise of permissions under this License.
|
| 153 |
+
|
| 154 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 155 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 156 |
+
unless required by applicable law (such as deliberate and grossly
|
| 157 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 158 |
+
liable to You for damages, including any direct, indirect, special,
|
| 159 |
+
incidental, or consequential damages of any character arising as a
|
| 160 |
+
result of this License or out of the use or inability to use the
|
| 161 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 162 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 163 |
+
other commercial damages or losses), even if such Contributor
|
| 164 |
+
has been advised of the possibility of such damages.
|
| 165 |
+
|
| 166 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 167 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 168 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 169 |
+
or other liability obligations and/or rights consistent with this
|
| 170 |
+
License. However, in accepting such obligations, You may act only
|
| 171 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 172 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 173 |
+
defend, and hold each Contributor harmless for any liability
|
| 174 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 175 |
+
of your accepting any such warranty or additional liability.
|
| 176 |
+
|
| 177 |
+
END OF TERMS AND CONDITIONS
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/packaging-24.2.dist-info/LICENSE.BSD
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Copyright (c) Donald Stufft and individual contributors.
|
| 2 |
+
All rights reserved.
|
| 3 |
+
|
| 4 |
+
Redistribution and use in source and binary forms, with or without
|
| 5 |
+
modification, are permitted provided that the following conditions are met:
|
| 6 |
+
|
| 7 |
+
1. Redistributions of source code must retain the above copyright notice,
|
| 8 |
+
this list of conditions and the following disclaimer.
|
| 9 |
+
|
| 10 |
+
2. 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 |
+
|
| 14 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
| 15 |
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
| 16 |
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 17 |
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 18 |
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 19 |
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 20 |
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 21 |
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 22 |
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 23 |
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/packaging-24.2.dist-info/REQUESTED
ADDED
|
File without changes
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/packaging-24.2.dist-info/WHEEL
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Wheel-Version: 1.0
|
| 2 |
+
Generator: flit 3.10.1
|
| 3 |
+
Root-Is-Purelib: true
|
| 4 |
+
Tag: py3-none-any
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-311.pyc
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:41c236e9b167a346f261473ba48db901f00476843b03f377600d8c045836aacd
|
| 3 |
+
size 163197
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_emoji_codes.cpython-311.pyc
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:23e69f8f33ae5e21ea90c0254f3b9874d5c2ff6a1a59cffa1496ea60619d0702
|
| 3 |
+
size 208544
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/pybind11/__init__.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import sys
|
| 4 |
+
|
| 5 |
+
if sys.version_info < (3, 7): # noqa: UP036
|
| 6 |
+
msg = "pybind11 does not support Python < 3.7. v2.12 was the last release supporting Python 3.6."
|
| 7 |
+
raise ImportError(msg)
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
from ._version import __version__, version_info
|
| 11 |
+
from .commands import get_cmake_dir, get_include, get_pkgconfig_dir
|
| 12 |
+
|
| 13 |
+
__all__ = (
|
| 14 |
+
"version_info",
|
| 15 |
+
"__version__",
|
| 16 |
+
"get_include",
|
| 17 |
+
"get_cmake_dir",
|
| 18 |
+
"get_pkgconfig_dir",
|
| 19 |
+
)
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/pybind11/__main__.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# pylint: disable=missing-function-docstring
|
| 2 |
+
from __future__ import annotations
|
| 3 |
+
|
| 4 |
+
import argparse
|
| 5 |
+
import re
|
| 6 |
+
import sys
|
| 7 |
+
import sysconfig
|
| 8 |
+
|
| 9 |
+
from ._version import __version__
|
| 10 |
+
from .commands import get_cmake_dir, get_include, get_pkgconfig_dir
|
| 11 |
+
|
| 12 |
+
# This is the conditional used for os.path being posixpath
|
| 13 |
+
if "posix" in sys.builtin_module_names:
|
| 14 |
+
from shlex import quote
|
| 15 |
+
elif "nt" in sys.builtin_module_names:
|
| 16 |
+
# See https://github.com/mesonbuild/meson/blob/db22551ed9d2dd7889abea01cc1c7bba02bf1c75/mesonbuild/utils/universal.py#L1092-L1121
|
| 17 |
+
# and the original documents:
|
| 18 |
+
# https://docs.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments and
|
| 19 |
+
# https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
|
| 20 |
+
UNSAFE = re.compile("[ \t\n\r]")
|
| 21 |
+
|
| 22 |
+
def quote(s: str) -> str:
|
| 23 |
+
if s and not UNSAFE.search(s):
|
| 24 |
+
return s
|
| 25 |
+
|
| 26 |
+
# Paths cannot contain a '"' on Windows, so we don't need to worry
|
| 27 |
+
# about nuanced counting here.
|
| 28 |
+
return f'"{s}\\"' if s.endswith("\\") else f'"{s}"'
|
| 29 |
+
else:
|
| 30 |
+
|
| 31 |
+
def quote(s: str) -> str:
|
| 32 |
+
return s
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def print_includes() -> None:
|
| 36 |
+
dirs = [
|
| 37 |
+
sysconfig.get_path("include"),
|
| 38 |
+
sysconfig.get_path("platinclude"),
|
| 39 |
+
get_include(),
|
| 40 |
+
]
|
| 41 |
+
|
| 42 |
+
# Make unique but preserve order
|
| 43 |
+
unique_dirs = []
|
| 44 |
+
for d in dirs:
|
| 45 |
+
if d and d not in unique_dirs:
|
| 46 |
+
unique_dirs.append(d)
|
| 47 |
+
|
| 48 |
+
print(" ".join(quote(f"-I{d}") for d in unique_dirs))
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def main() -> None:
|
| 52 |
+
parser = argparse.ArgumentParser()
|
| 53 |
+
parser.add_argument(
|
| 54 |
+
"--version",
|
| 55 |
+
action="version",
|
| 56 |
+
version=__version__,
|
| 57 |
+
help="Print the version and exit.",
|
| 58 |
+
)
|
| 59 |
+
parser.add_argument(
|
| 60 |
+
"--includes",
|
| 61 |
+
action="store_true",
|
| 62 |
+
help="Include flags for both pybind11 and Python headers.",
|
| 63 |
+
)
|
| 64 |
+
parser.add_argument(
|
| 65 |
+
"--cmakedir",
|
| 66 |
+
action="store_true",
|
| 67 |
+
help="Print the CMake module directory, ideal for setting -Dpybind11_ROOT in CMake.",
|
| 68 |
+
)
|
| 69 |
+
parser.add_argument(
|
| 70 |
+
"--pkgconfigdir",
|
| 71 |
+
action="store_true",
|
| 72 |
+
help="Print the pkgconfig directory, ideal for setting $PKG_CONFIG_PATH.",
|
| 73 |
+
)
|
| 74 |
+
args = parser.parse_args()
|
| 75 |
+
if not sys.argv[1:]:
|
| 76 |
+
parser.print_help()
|
| 77 |
+
if args.includes:
|
| 78 |
+
print_includes()
|
| 79 |
+
if args.cmakedir:
|
| 80 |
+
print(quote(get_cmake_dir()))
|
| 81 |
+
if args.pkgconfigdir:
|
| 82 |
+
print(quote(get_pkgconfig_dir()))
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
if __name__ == "__main__":
|
| 86 |
+
main()
|