saddlepoint-expansions 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. saddlepoint_expansions-0.2.1/.github/workflows/ci.yml +55 -0
  2. saddlepoint_expansions-0.2.1/.github/workflows/publish.yml +42 -0
  3. saddlepoint_expansions-0.2.1/.gitignore +8 -0
  4. saddlepoint_expansions-0.2.1/LICENSE +21 -0
  5. saddlepoint_expansions-0.2.1/PKG-INFO +134 -0
  6. saddlepoint_expansions-0.2.1/README.md +84 -0
  7. saddlepoint_expansions-0.2.1/docs/api.md +58 -0
  8. saddlepoint_expansions-0.2.1/docs/conf.py +28 -0
  9. saddlepoint_expansions-0.2.1/docs/guide.md +185 -0
  10. saddlepoint_expansions-0.2.1/docs/index.md +60 -0
  11. saddlepoint_expansions-0.2.1/pyproject.toml +45 -0
  12. saddlepoint_expansions-0.2.1/src/saddlepoint_expansions/__init__.py +41 -0
  13. saddlepoint_expansions-0.2.1/src/saddlepoint_expansions/api.py +185 -0
  14. saddlepoint_expansions-0.2.1/src/saddlepoint_expansions/bivariate.py +332 -0
  15. saddlepoint_expansions-0.2.1/src/saddlepoint_expansions/cgf.py +265 -0
  16. saddlepoint_expansions-0.2.1/src/saddlepoint_expansions/cgfs.py +266 -0
  17. saddlepoint_expansions-0.2.1/src/saddlepoint_expansions/multivariate.py +636 -0
  18. saddlepoint_expansions-0.2.1/src/saddlepoint_expansions/normal.py +43 -0
  19. saddlepoint_expansions-0.2.1/src/saddlepoint_expansions/ratios.py +134 -0
  20. saddlepoint_expansions-0.2.1/src/saddlepoint_expansions/studentized.py +502 -0
  21. saddlepoint_expansions-0.2.1/src/saddlepoint_expansions/taylor.py +527 -0
  22. saddlepoint_expansions-0.2.1/src/saddlepoint_expansions/univariate.py +131 -0
  23. saddlepoint_expansions-0.2.1/src/saddlepoint_expansions/util.py +193 -0
  24. saddlepoint_expansions-0.2.1/tests/_dickey_fuller.py +124 -0
  25. saddlepoint_expansions-0.2.1/tests/reference_values.csv +410 -0
  26. saddlepoint_expansions-0.2.1/tests/test_against_julia.py +274 -0
  27. saddlepoint_expansions-0.2.1/tests/test_api.py +201 -0
  28. saddlepoint_expansions-0.2.1/tests/test_studentized.py +100 -0
  29. saddlepoint_expansions-0.2.1/tests/test_taylor.py +126 -0
@@ -0,0 +1,55 @@
1
+ name: CI
2
+ on:
3
+ push:
4
+ branches: [main]
5
+ tags: ['*']
6
+ pull_request:
7
+ workflow_dispatch:
8
+ concurrency:
9
+ group: ${{ github.workflow }}-${{ github.ref }}
10
+ cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}
11
+ jobs:
12
+ test:
13
+ name: Python ${{ matrix.python-version }} - ${{ matrix.os }}
14
+ runs-on: ${{ matrix.os }}
15
+ timeout-minutes: 40
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ os: [ubuntu-latest]
20
+ python-version: ['3.10', '3.13']
21
+ include:
22
+ - os: macos-latest
23
+ python-version: '3.12'
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ - uses: actions/setup-python@v5
27
+ with:
28
+ python-version: ${{ matrix.python-version }}
29
+ cache: pip
30
+ - name: Install
31
+ run: python -m pip install --upgrade pip && python -m pip install -e ".[test]"
32
+ - name: Test
33
+ run: pytest -q
34
+ docs:
35
+ name: Documentation
36
+ runs-on: ubuntu-latest
37
+ permissions:
38
+ contents: write
39
+ steps:
40
+ - uses: actions/checkout@v4
41
+ - uses: actions/setup-python@v5
42
+ with:
43
+ python-version: '3.12'
44
+ cache: pip
45
+ - name: Install
46
+ run: python -m pip install --upgrade pip && python -m pip install -e ".[docs]"
47
+ - name: Build
48
+ run: sphinx-build -W --keep-going -b html docs docs/_build/html
49
+ - name: Deploy
50
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
51
+ uses: peaceiris/actions-gh-pages@v4
52
+ with:
53
+ github_token: ${{ secrets.GITHUB_TOKEN }}
54
+ publish_dir: docs/_build/html
55
+ force_orphan: true
@@ -0,0 +1,42 @@
1
+ name: Publish to PyPI
2
+ # Trusted publishing: PyPI accepts the upload on the strength of this workflow's identity
3
+ # (repository s-broda/saddlepoint-expansions, file publish.yml, environment pypi), so no token is
4
+ # stored anywhere. Set up once on pypi.org under Publishing, as a pending publisher for the
5
+ # project name saddlepoint-expansions. Runs when a GitHub release is published, or by hand.
6
+ on:
7
+ release:
8
+ types: [published]
9
+ workflow_dispatch:
10
+ jobs:
11
+ build:
12
+ name: Build sdist and wheel
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: '3.12'
19
+ - name: Build
20
+ run: |
21
+ python -m pip install --upgrade build twine
22
+ python -m build
23
+ python -m twine check dist/*
24
+ - uses: actions/upload-artifact@v4
25
+ with:
26
+ name: dist
27
+ path: dist/
28
+ publish:
29
+ name: Upload to PyPI
30
+ needs: build
31
+ runs-on: ubuntu-latest
32
+ environment:
33
+ name: pypi
34
+ url: https://pypi.org/project/saddlepoint-expansions/
35
+ permissions:
36
+ id-token: write
37
+ steps:
38
+ - uses: actions/download-artifact@v4
39
+ with:
40
+ name: dist
41
+ path: dist/
42
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,8 @@
1
+ __pycache__/
2
+ *.pyc
3
+ *.egg-info/
4
+ build/
5
+ dist/
6
+ docs/_build/
7
+ .pytest_cache/
8
+ .DS_Store
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Simon A. Broda and Raymond Kan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,134 @@
1
+ Metadata-Version: 2.5
2
+ Name: saddlepoint-expansions
3
+ Version: 0.2.1
4
+ Summary: Saddlepoint expansions of any order for multivariate tail probabilities and densities, from the cumulant generating function
5
+ Project-URL: Repository, https://github.com/s-broda/saddlepoint-expansions
6
+ Project-URL: Documentation, https://s-broda.github.io/saddlepoint-expansions/
7
+ Author: Simon A. Broda, Raymond Kan
8
+ License: MIT License
9
+
10
+ Copyright (c) 2026 Simon A. Broda and Raymond Kan
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of this software and associated documentation files (the "Software"), to deal
14
+ in the Software without restriction, including without limitation the rights
15
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the Software is
17
+ furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all
20
+ copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ SOFTWARE.
29
+ License-File: LICENSE
30
+ Keywords: Taylor-mode automatic differentiation,asymptotic expansion,orthant probability,saddlepoint approximation,tail probability
31
+ Classifier: Development Status :: 3 - Alpha
32
+ Classifier: Intended Audience :: Science/Research
33
+ Classifier: License :: OSI Approved :: MIT License
34
+ Classifier: Programming Language :: Python :: 3
35
+ Classifier: Programming Language :: Python :: 3.10
36
+ Classifier: Programming Language :: Python :: 3.11
37
+ Classifier: Programming Language :: Python :: 3.12
38
+ Classifier: Programming Language :: Python :: 3.13
39
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
40
+ Requires-Python: >=3.10
41
+ Requires-Dist: numpy>=1.24
42
+ Requires-Dist: scipy>=1.10
43
+ Provides-Extra: docs
44
+ Requires-Dist: furo; extra == 'docs'
45
+ Requires-Dist: myst-parser; extra == 'docs'
46
+ Requires-Dist: sphinx>=7; extra == 'docs'
47
+ Provides-Extra: test
48
+ Requires-Dist: pytest>=7; extra == 'test'
49
+ Description-Content-Type: text/markdown
50
+
51
+ # saddlepoint-expansions
52
+
53
+ [![CI](https://github.com/s-broda/saddlepoint-expansions/actions/workflows/ci.yml/badge.svg)](https://github.com/s-broda/saddlepoint-expansions/actions/workflows/ci.yml)
54
+ [![Documentation](https://img.shields.io/badge/docs-latest-blue.svg)](https://s-broda.github.io/saddlepoint-expansions/)
55
+
56
+ Saddlepoint expansions of any order for tail probabilities and densities of random vectors,
57
+ from the cumulant generating function alone. Python port of the Julia package
58
+ [SaddlepointExpansions.jl](https://github.com/s-broda/SaddlepointExpansions.jl).
59
+
60
+ The package implements the expansions of Broda and Kan, *Uniform saddlepoint expansions for
61
+ multivariate tail probabilities*: the orthant probability `P(X ≥ x)` of a random vector in any
62
+ dimension (first-order term: Kolassa 2003), its density, and the density and distribution
63
+ function of a ratio, with the univariate expansions of Daniels and of Hauschildt and Robinson as
64
+ the one-dimensional case; and those of Bao, Broda and Kan, *Inversion formulas and saddlepoint
65
+ expansions for Studentized means*, for the density and distribution function of `X/sqrt(Y)`
66
+ (`studentized_density`, `studentized_tailprob`, `studentized_quantile`). The expansion of order `M` has relative error `O(n^-M)`, uniformly for
67
+ saddlepoints in the closed positive orthant; saddlepoints with negative components are handled
68
+ by inclusion-exclusion.
69
+
70
+ The cumulant generating function is supplied as an ordinary Python function written with numpy.
71
+ All its derivatives are generated by Taylor-mode automatic differentiation, with a small
72
+ truncated-polynomial algebra included in the package (no dependency beyond numpy and scipy),
73
+ directly in the whitened coordinates in which the expansions are evaluated.
74
+
75
+ ```python
76
+ import numpy as np
77
+ from saddlepoint_expansions import CGF, sample_mean, tailprob, density
78
+
79
+ # X = (U0 + U1, U0 + U2), U_i independent unit exponentials; the mean of n = 5 observations
80
+ K = CGF(lambda t: -np.log(1 - t[0]) - np.log(1 - t[1]) - np.log(1 - t[0] - t[1]), 2,
81
+ domain=lambda t: t[0] < 1 and t[1] < 1 and t[0] + t[1] < 1)
82
+ Kn = sample_mean(K, 5)
83
+
84
+ tailprob(Kn, [3.0, 3.0], order=4)["F"] # P(X̄₁ ≥ 3, X̄₂ ≥ 3), orders 1 to 4; exact 0.02215196
85
+ density(Kn, [3.0, 3.0], order=4)["f"] # the joint density
86
+ tailprob(Kn, [3.0, 3.0], lower=True)["F"] # P(X̄₁ ≤ 3, X̄₂ ≤ 3)
87
+ ```
88
+
89
+ A library of cumulant generating functions (normal, gamma, noncentral chi-squared, quadratic
90
+ forms in normal variables, Wishart diagonals, sums of exponentials) and transformations
91
+ (reflection, marginals, linear combinations, sample means, independent sums) is included, and
92
+ the lower-level derivative interface (`spa_bi`, `spa_mv`, `spa_orthant`, ...) remains available
93
+ for models with closed-form derivatives. A `CGF` can also carry its Taylor polynomials in closed
94
+ form (`quadratic_forms_cgf` does, by the trace recursion of the paper), and `ratio_density` and
95
+ `ratio_tailprob` handle vectors of ratios.
96
+
97
+ ## Installation
98
+
99
+ ```
100
+ pip install git+https://github.com/s-broda/saddlepoint-expansions
101
+ ```
102
+
103
+ Python 3.10 or later, numpy and scipy.
104
+
105
+ ## Differences from the Julia package
106
+
107
+ Everything is in double precision. The Julia package also runs in arbitrary precision
108
+ (`BigFloat`), uses an exact recursion for the orthant integrals in that case, and repeats
109
+ densities in three or more dimensions, and the Studentized-mean density, in higher precision when
110
+ the terms cancel strongly; here the cancellation indicator (`info["kappa_pdf"]`, `info["kappa"]`)
111
+ is reported instead. The
112
+ Julia package is the reference implementation: the test suite of this package compares every
113
+ function with values computed by it (`tests/reference_values.csv`, written by
114
+ `test/reference_values.jl` of the Julia package and shared with the MATLAB counterpart).
115
+
116
+ ## Documentation and tests
117
+
118
+ ```
119
+ pip install -e ".[docs,test]"
120
+ sphinx-build -b html docs docs/_build/html
121
+ pytest
122
+ ```
123
+
124
+ ## Citation
125
+
126
+ > Broda, S. A. and Kan, R. Uniform saddlepoint expansions for multivariate tail probabilities.
127
+
128
+ and, for the Studentized-mean functions,
129
+
130
+ > Bao, Y., Broda, S. A. and Kan, R. Inversion formulas and saddlepoint expansions for Studentized means.
131
+
132
+ ## License
133
+
134
+ MIT; see `LICENSE`.
@@ -0,0 +1,84 @@
1
+ # saddlepoint-expansions
2
+
3
+ [![CI](https://github.com/s-broda/saddlepoint-expansions/actions/workflows/ci.yml/badge.svg)](https://github.com/s-broda/saddlepoint-expansions/actions/workflows/ci.yml)
4
+ [![Documentation](https://img.shields.io/badge/docs-latest-blue.svg)](https://s-broda.github.io/saddlepoint-expansions/)
5
+
6
+ Saddlepoint expansions of any order for tail probabilities and densities of random vectors,
7
+ from the cumulant generating function alone. Python port of the Julia package
8
+ [SaddlepointExpansions.jl](https://github.com/s-broda/SaddlepointExpansions.jl).
9
+
10
+ The package implements the expansions of Broda and Kan, *Uniform saddlepoint expansions for
11
+ multivariate tail probabilities*: the orthant probability `P(X ≥ x)` of a random vector in any
12
+ dimension (first-order term: Kolassa 2003), its density, and the density and distribution
13
+ function of a ratio, with the univariate expansions of Daniels and of Hauschildt and Robinson as
14
+ the one-dimensional case; and those of Bao, Broda and Kan, *Inversion formulas and saddlepoint
15
+ expansions for Studentized means*, for the density and distribution function of `X/sqrt(Y)`
16
+ (`studentized_density`, `studentized_tailprob`, `studentized_quantile`). The expansion of order `M` has relative error `O(n^-M)`, uniformly for
17
+ saddlepoints in the closed positive orthant; saddlepoints with negative components are handled
18
+ by inclusion-exclusion.
19
+
20
+ The cumulant generating function is supplied as an ordinary Python function written with numpy.
21
+ All its derivatives are generated by Taylor-mode automatic differentiation, with a small
22
+ truncated-polynomial algebra included in the package (no dependency beyond numpy and scipy),
23
+ directly in the whitened coordinates in which the expansions are evaluated.
24
+
25
+ ```python
26
+ import numpy as np
27
+ from saddlepoint_expansions import CGF, sample_mean, tailprob, density
28
+
29
+ # X = (U0 + U1, U0 + U2), U_i independent unit exponentials; the mean of n = 5 observations
30
+ K = CGF(lambda t: -np.log(1 - t[0]) - np.log(1 - t[1]) - np.log(1 - t[0] - t[1]), 2,
31
+ domain=lambda t: t[0] < 1 and t[1] < 1 and t[0] + t[1] < 1)
32
+ Kn = sample_mean(K, 5)
33
+
34
+ tailprob(Kn, [3.0, 3.0], order=4)["F"] # P(X̄₁ ≥ 3, X̄₂ ≥ 3), orders 1 to 4; exact 0.02215196
35
+ density(Kn, [3.0, 3.0], order=4)["f"] # the joint density
36
+ tailprob(Kn, [3.0, 3.0], lower=True)["F"] # P(X̄₁ ≤ 3, X̄₂ ≤ 3)
37
+ ```
38
+
39
+ A library of cumulant generating functions (normal, gamma, noncentral chi-squared, quadratic
40
+ forms in normal variables, Wishart diagonals, sums of exponentials) and transformations
41
+ (reflection, marginals, linear combinations, sample means, independent sums) is included, and
42
+ the lower-level derivative interface (`spa_bi`, `spa_mv`, `spa_orthant`, ...) remains available
43
+ for models with closed-form derivatives. A `CGF` can also carry its Taylor polynomials in closed
44
+ form (`quadratic_forms_cgf` does, by the trace recursion of the paper), and `ratio_density` and
45
+ `ratio_tailprob` handle vectors of ratios.
46
+
47
+ ## Installation
48
+
49
+ ```
50
+ pip install git+https://github.com/s-broda/saddlepoint-expansions
51
+ ```
52
+
53
+ Python 3.10 or later, numpy and scipy.
54
+
55
+ ## Differences from the Julia package
56
+
57
+ Everything is in double precision. The Julia package also runs in arbitrary precision
58
+ (`BigFloat`), uses an exact recursion for the orthant integrals in that case, and repeats
59
+ densities in three or more dimensions, and the Studentized-mean density, in higher precision when
60
+ the terms cancel strongly; here the cancellation indicator (`info["kappa_pdf"]`, `info["kappa"]`)
61
+ is reported instead. The
62
+ Julia package is the reference implementation: the test suite of this package compares every
63
+ function with values computed by it (`tests/reference_values.csv`, written by
64
+ `test/reference_values.jl` of the Julia package and shared with the MATLAB counterpart).
65
+
66
+ ## Documentation and tests
67
+
68
+ ```
69
+ pip install -e ".[docs,test]"
70
+ sphinx-build -b html docs docs/_build/html
71
+ pytest
72
+ ```
73
+
74
+ ## Citation
75
+
76
+ > Broda, S. A. and Kan, R. Uniform saddlepoint expansions for multivariate tail probabilities.
77
+
78
+ and, for the Studentized-mean functions,
79
+
80
+ > Bao, Y., Broda, S. A. and Kan, R. Inversion formulas and saddlepoint expansions for Studentized means.
81
+
82
+ ## License
83
+
84
+ MIT; see `LICENSE`.
@@ -0,0 +1,58 @@
1
+ # API reference
2
+
3
+ ## Cumulant generating functions and the high-level interface
4
+
5
+ ```{eval-rst}
6
+ .. autoclass:: saddlepoint_expansions.CGF
7
+ :members: __add__
8
+
9
+ .. autofunction:: saddlepoint_expansions.derivatives
10
+ .. autofunction:: saddlepoint_expansions.saddlepoint
11
+ .. autofunction:: saddlepoint_expansions.tailprob
12
+ .. autofunction:: saddlepoint_expansions.density
13
+ .. autofunction:: saddlepoint_expansions.ratio_density
14
+ .. autofunction:: saddlepoint_expansions.ratio_tailprob
15
+ .. autofunction:: saddlepoint_expansions.studentized_density
16
+ .. autofunction:: saddlepoint_expansions.studentized_tailprob
17
+ .. autofunction:: saddlepoint_expansions.studentized_quantile
18
+ .. autofunction:: saddlepoint_expansions.studentized_saddlepoint
19
+ .. autofunction:: saddlepoint_expansions.studentized_locus
20
+ .. autofunction:: saddlepoint_expansions.reflect
21
+ .. autofunction:: saddlepoint_expansions.marginal
22
+ .. autofunction:: saddlepoint_expansions.linear_combination
23
+ .. autofunction:: saddlepoint_expansions.sample_mean
24
+ .. autofunction:: saddlepoint_expansions.shift
25
+ ```
26
+
27
+ ## Library of cumulant generating functions
28
+
29
+ ```{eval-rst}
30
+ .. automodule:: saddlepoint_expansions.cgfs
31
+ :members:
32
+ ```
33
+
34
+ ## The derivative interface
35
+
36
+ ```{eval-rst}
37
+ .. autofunction:: saddlepoint_expansions.spa_saddle
38
+ .. autofunction:: saddlepoint_expansions.spa_uni
39
+ .. autofunction:: saddlepoint_expansions.spa_ratio_pdf
40
+ .. autofunction:: saddlepoint_expansions.spa_bi
41
+ .. autofunction:: saddlepoint_expansions.spa_bi_at
42
+ .. autofunction:: saddlepoint_expansions.spa_orthant2
43
+ .. autofunction:: saddlepoint_expansions.spa_mv
44
+ .. autofunction:: saddlepoint_expansions.spa_mv_at
45
+ .. autofunction:: saddlepoint_expansions.spa_orthant
46
+ .. autofunction:: saddlepoint_expansions.orthant2
47
+ .. autofunction:: saddlepoint_expansions.orthant3
48
+ .. autofunction:: saddlepoint_expansions.kfun
49
+ .. autofunction:: saddlepoint_expansions.kwhite
50
+ .. autofunction:: saddlepoint_expansions.ratio_mv
51
+ ```
52
+
53
+ ## The Taylor algebra
54
+
55
+ ```{eval-rst}
56
+ .. automodule:: saddlepoint_expansions.taylor
57
+ :members: TPoly, Algebra, get_algebra, variables, from_coefficients, sincu, sinhc, DomainError
58
+ ```
@@ -0,0 +1,28 @@
1
+ import os
2
+ import sys
3
+
4
+ sys.path.insert(0, os.path.abspath("../src"))
5
+
6
+ project = "saddlepoint-expansions"
7
+ author = "Simon A. Broda and Raymond Kan"
8
+ copyright = "2026, Simon A. Broda and Raymond Kan"
9
+ release = "0.1.0"
10
+
11
+ extensions = [
12
+ "sphinx.ext.autodoc",
13
+ "sphinx.ext.napoleon",
14
+ "sphinx.ext.mathjax",
15
+ "sphinx.ext.intersphinx",
16
+ "myst_parser",
17
+ ]
18
+ myst_enable_extensions = ["dollarmath", "amsmath"]
19
+ autodoc_member_order = "bysource"
20
+ autodoc_typehints = "none"
21
+ intersphinx_mapping = {
22
+ "python": ("https://docs.python.org/3", None),
23
+ "numpy": ("https://numpy.org/doc/stable/", None),
24
+ }
25
+ html_theme = "furo"
26
+ html_title = "saddlepoint-expansions"
27
+ source_suffix = {".rst": "restructuredtext", ".md": "markdown"}
28
+ exclude_patterns = ["_build"]
@@ -0,0 +1,185 @@
1
+ # Guide
2
+
3
+ ## Cumulant generating functions
4
+
5
+ A {class}`~saddlepoint_expansions.CGF` wraps a Python function `K(t)` of a numpy vector `t` of
6
+ length $d$ (also for $d = 1$, where you write `t[0]`), together with the dimension and,
7
+ optionally, a predicate describing the domain:
8
+
9
+ ```python
10
+ K = CGF(lambda t: -3*np.log(1 - t[0]) - 2*np.log(1 - 2*t[1]), 2,
11
+ domain=lambda t: t[0] < 1 and t[1] < 1/2)
12
+ ```
13
+
14
+ The function is evaluated on vectors of truncated multivariate Taylor polynomials
15
+ ({class}`~saddlepoint_expansions.taylor.TPoly`) to generate its derivatives, so it must be
16
+ written generically: arithmetic, `np.exp`, `np.log`, `np.sqrt`, powers, `np.sum`, products
17
+ with constant matrices and vectors (`A @ t`), `np.sin`, `np.cos`, `np.tan`, `np.sinh`,
18
+ `np.cosh`, `np.tanh`, `np.arctan` all work, and {func}`~saddlepoint_expansions.sinhc` and
19
+ {func}`~saddlepoint_expansions.sincu` give $\sinh(x)/x$ and $\sin(x)/x$ with their removable
20
+ singularity at zero (write `np.log(sinhc(t[0]))` for the uniform distribution, not
21
+ `np.log(np.sinh(t[0])/t[0])`, which is $0/0$ at the origin where the saddlepoint iteration starts); `math.log`, `float(...)` and calls into
22
+ numerical libraries that require floats do not. For determinants and inverses of matrices that
23
+ depend on `t`, write the factorization in generic arithmetic as
24
+ {func}`~saddlepoint_expansions.quadratic_forms_cgf` does, or use that constructor.
25
+
26
+ Outside its domain, `K` may raise a {class}`~saddlepoint_expansions.DomainError` (`np.log` and
27
+ `np.sqrt` of a polynomial with a negative constant term do this automatically) or return a
28
+ non-finite value. When the formula is finite outside the true domain, as with $1/(1-t)$, the
29
+ `domain` predicate is needed; it is also cheaper than an exception.
30
+
31
+ Transformations: {func}`~saddlepoint_expansions.reflect` (sign changes),
32
+ {func}`~saddlepoint_expansions.marginal`, {func}`~saddlepoint_expansions.linear_combination`
33
+ ($Y = B'X$), {func}`~saddlepoint_expansions.sample_mean` ($nK(t/n)$),
34
+ {func}`~saddlepoint_expansions.shift` ($X + c$), and `K1 + K2` for the sum of independent
35
+ vectors. The library: {func}`~saddlepoint_expansions.normal_cgf`,
36
+ {func}`~saddlepoint_expansions.gamma_cgf`, {func}`~saddlepoint_expansions.ncx2_cgf`,
37
+ {func}`~saddlepoint_expansions.exponential_sums_cgf`,
38
+ {func}`~saddlepoint_expansions.quadratic_forms_cgf`,
39
+ {func}`~saddlepoint_expansions.wishart_diag_cgf`,
40
+ {func}`~saddlepoint_expansions.common_component_cgf`, {func}`~saddlepoint_expansions.uniform_cgf`.
41
+
42
+ ## Tail probabilities
43
+
44
+ {func}`~saddlepoint_expansions.tailprob`` (K, x, order=M)` returns the expansions of orders
45
+ $1, \dots, M$ of $P(X \ge x)$ in `F`, with the saddlepoint `tau`, a `status` string and the
46
+ full result of the underlying routine in `info`. The expansion of order $M$ keeps the terms of
47
+ orders $n^{-m/2}$, $m \le 2M - 1$, and has relative error $O(n^{-M})$; in practice each order
48
+ gains one to two digits at moderate sample sizes, and the first order is accurate to a few
49
+ percent.
50
+
51
+ `lower=True` gives $P(X \le x)$ and `signs` a mixed corner, e.g. `signs=[1, -1]` for
52
+ $P(X_1 \ge x_1, X_2 \le x_2)$. When the saddlepoint has negative components, the expansion is
53
+ applied through the inclusion-exclusion identity of the paper, which preserves the relative
54
+ error bound. In three dimensions the orthant integrals are computed by Gauss quadrature and in
55
+ four or more by randomized quasi-Monte Carlo (`info["err"]` is then a standard error); keyword
56
+ arguments are passed on to {func}`~saddlepoint_expansions.spa_mv` (`nG`, `nqmc`, ...) and, for
57
+ $d = 2$, to {func}`~saddlepoint_expansions.spa_orthant2` (`nG`, `logscale` for probabilities
58
+ below the double-precision range, ...). For $d = 1$, `x` may be a scalar.
59
+
60
+ ## Densities
61
+
62
+ {func}`~saddlepoint_expansions.density`` (K, x, order=M)` returns the expansions of orders
63
+ $1, \dots, M$ of the density (the terms $m \le M-1$ of the expansion in powers of $n^{-1}$,
64
+ relative error $O(n^{-M})$); a finite sum of Hermite polynomials, no integration, any
65
+ dimension. In three or more dimensions the terms can cancel strongly at high orders; check
66
+ `info["kappa_pdf"]`, the ratio of the sum of the absolute terms to the sum (about $\log_{10}$
67
+ of it digits are lost). The Julia package repeats such computations in higher precision; this
68
+ package works in double precision.
69
+
70
+ ## Ratios
71
+
72
+ For a bivariate `K` with a positive denominator $X_2 > 0$:
73
+ {func}`~saddlepoint_expansions.ratio_density`` (K, r)` is the Rice expansion of the density of
74
+ $X_1/X_2$ at $r$ through the saddlepoint of $K_W(s) = K(s, -rs)$, and
75
+ {func}`~saddlepoint_expansions.ratio_tailprob`` (K, r, lower=...)` is the univariate expansion
76
+ for $W = X_1 - rX_2$ at $0$. Example, the noncentral $F$ with $Q_1 \sim \chi^2_m(\lambda)$ and
77
+ $Q_2 \sim \chi^2_n$:
78
+
79
+ ```python
80
+ K = CGF(lambda t: ncx2_cgf(m, lam)(t[:1]) + ncx2_cgf(n)(t[1:]), 2,
81
+ domain=lambda t: t[0] < 0.5 and t[1] < 0.5)
82
+ c = f*m/n
83
+ ratio_tailprob(K, c, lower=True)["F"] # P(F <= f), orders 1..3
84
+ ratio_density(K, c)["f"] * (m/n) # density of F at f
85
+ ```
86
+
87
+ *Several ratios.* With a vector `r` of length $d$, `K` is the cgf of $(X_1, \dots, X_d, Y_1, \dots, Y_d)$,
88
+ or of $(X_1, \dots, X_d, Y)$ for a common denominator, and `ratio_density` returns the joint density
89
+ of $(X_1/Y_1, \dots, X_d/Y_d)$ at `r` (Theorem 4 with the amplitude expansion of Corollary 1 of
90
+ the paper, every Taylor coefficient from one polynomial of $K(s, -r \circ s + \tau)$), while
91
+ `ratio_tailprob` returns the orthant probability $P(R \ge r)$ with `lower` and `signs` as in
92
+ `tailprob`. The sample autocorrelations at lags one and two, for example, are two ratios of
93
+ quadratic forms with a common denominator:
94
+
95
+ ```python
96
+ N = 50; Mc = np.eye(N) - np.ones((N, N))/N
97
+ A = lambda j: (np.diag(np.ones(N - j), j) + np.diag(np.ones(N - j), -j))/2
98
+ K = quadratic_forms_cgf([Mc @ A(1) @ Mc, Mc @ A(2) @ Mc, Mc])
99
+ ratio_density(K, [-1, -1]/np.sqrt(N), order=5)["f"]
100
+ ```
101
+
102
+ ## Studentized means
103
+
104
+ For $Q = X/\sqrt{Y}$ with $Y > 0$, with `K` the joint cumulant generating function of $(X, Y)$,
105
+ the expansions of Bao, Broda and Kan, *Inversion formulas and saddlepoint expansions for
106
+ Studentized means*:
107
+
108
+ ```python
109
+ studentized_density(K, q, order=3) # density of X/sqrt(Y) at q, orders 1..3
110
+ studentized_tailprob(K, q, order=3) # P(X/sqrt(Y) >= q); lower=True for P(X/sqrt(Y) <= q)
111
+ studentized_quantile(K, 0.05, order=3) # the q with P(X/sqrt(Y) <= q) = 0.05 under the expansion
112
+ ```
113
+
114
+ Unlike a ratio, $X - q\sqrt{Y}$ is not linear in $(X, Y)$, and the inversion is a double
115
+ integral with a kernel in $s$ and $t$. The saddlepoint $(\hat s, \hat t, \hat v)$ solves
116
+ $K_s = qv$, $K_t = v^2$, $qs + 2tv = 0$ ({func}`~saddlepoint_expansions.studentized_saddlepoint`);
117
+ the density is the bivariate amplitude expansion about it, and the distribution function is a
118
+ Hauschildt-Robinson type expansion in $s$ after the $t$-integral is expanded by Laplace's method,
119
+ all Taylor coefficients being generated from the Taylor polynomial of `K` at the saddlepoint by
120
+ Newton's method and composition on power series. `order=M` keeps the terms $m \le M - 1$ of the
121
+ density and $m \le 2M - 1$ of the distribution function (relative error $O(n^{-M})$);
122
+ `info["Fp"]` holds every half-order. The saddlepoints for all $q$ lie on the curve
123
+ $sK_s + 2tK_t = 0$ ({func}`~saddlepoint_expansions.studentized_locus`), which is how
124
+ `studentized_quantile` searches: along the curve each $\hat s$ gives its $q$ and its distribution
125
+ function directly, so that no saddlepoint equation is solved for a trial $q$.
126
+
127
+ The noncentral $t$ distribution, for example, with $X \sim N(\mu, 1)$ and
128
+ $Y \sim \chi^2_\nu/\nu$ independent, $n$ pairs: $\bar X/\sqrt{\bar Y} = T/\sqrt{n}$, $T$
129
+ noncentral $t$ with $n\nu$ degrees of freedom and noncentrality $\sqrt{n}\mu$:
130
+
131
+ ```python
132
+ K = sample_mean(CGF(lambda t: mu*t[0] + t[0]**2/2 - nu/2*np.log(1 - 2*t[1]/nu), 2,
133
+ domain=lambda t: t[1] < nu/2), n)
134
+ studentized_tailprob(K, x/np.sqrt(n), lower=True)["F"] # P(T <= x)
135
+ ```
136
+
137
+ The terms of high order of the density cancel by many orders of magnitude where $|\hat t|$ is
138
+ large; `info["kappa"]` is the cancellation indicator, and in double precision the terms beyond
139
+ the fourth are often unreliable there (the Julia package repeats the computation in higher
140
+ precision; here `status` reports `"coefficients inaccurate"`). The Taylor algebra carries complex
141
+ coefficients for these expansions (the Hessian of the exponent is indefinite where $\hat t < 0$).
142
+
143
+ ## Closed-form Taylor polynomials
144
+
145
+ Automatic differentiation is the default, but a `CGF` can carry its Taylor polynomials in closed
146
+ form through the argument `taylor`, a function `taylor(t, N, M)` returning the polynomial of
147
+ degree `N` of $K(t + Mv)$ as a {class}`~saddlepoint_expansions.taylor.TPoly` (built from a
148
+ coefficient table with {func}`~saddlepoint_expansions.taylor.from_coefficients`), or `None`
149
+ outside the domain. {func}`~saddlepoint_expansions.quadratic_forms_cgf` uses this with the trace
150
+ recursion of the paper evaluated directly in the whitened directions, which makes large matrices
151
+ cheap, and the transformations carry the option along; pass `closedform=False` to differentiate
152
+ the generic formula instead. Comparisons between polynomials, or with numbers, compare the
153
+ constant terms, so a cgf written with an `if` on its argument can be differentiated.
154
+
155
+ ## Derivatives and the saddlepoint
156
+
157
+ {func}`~saddlepoint_expansions.derivatives`` (K, t, N)` returns all derivatives
158
+ $K^{(\nu)}(t)$, $|\nu| \le N$, as a dict keyed by the multi-index, and
159
+ {func}`~saddlepoint_expansions.saddlepoint`` (K, x)` solves $K'(\tau) = x$ by Newton's method
160
+ with backtracking. The derivatives at the saddlepoint are generated once, to the degree $2M + 1$
161
+ needed by order $M$, and the whitened coefficients (of $K_Y(u) = K(L^{-T}u)$,
162
+ $K''(\tau) = LL'$) are generated by differentiating the composed function directly, which keeps
163
+ them as accurate as the original ones.
164
+
165
+ ## The derivative interface
166
+
167
+ The engine can be used with derivatives supplied by the user, as `Kfun(nu, t)` returning the
168
+ derivative of multi-index order `nu` (a tuple) at `t`, NaN outside the domain:
169
+ {func}`~saddlepoint_expansions.spa_saddle`, {func}`~saddlepoint_expansions.spa_uni`,
170
+ {func}`~saddlepoint_expansions.spa_ratio_pdf`, {func}`~saddlepoint_expansions.spa_bi`,
171
+ {func}`~saddlepoint_expansions.spa_bi_at`, {func}`~saddlepoint_expansions.spa_orthant2`,
172
+ {func}`~saddlepoint_expansions.spa_mv`, {func}`~saddlepoint_expansions.spa_mv_at`,
173
+ {func}`~saddlepoint_expansions.spa_orthant`. These follow the Julia package and the MATLAB
174
+ programs of the paper. {func}`~saddlepoint_expansions.kfun` and
175
+ {func}`~saddlepoint_expansions.kwhite` turn a `CGF` into the functions they take.
176
+
177
+ ## The Taylor algebra
178
+
179
+ {mod}`saddlepoint_expansions.taylor` is a self-contained implementation of truncated
180
+ multivariate Taylor polynomials: `variables(d, N)` returns the $d$ variables of degree $N$ as
181
+ an object array, and any generic function evaluated on them returns a
182
+ {class}`~saddlepoint_expansions.taylor.TPoly` whose `coeff(nu)` is $f^{(\nu)}(0)/\nu!$ and
183
+ `derivative(nu)` is $f^{(\nu)}(0)$. Products use precomputed index tables and `np.bincount`; a
184
+ product of two polynomials of degree 12 in three variables takes about 0.1 ms, an `exp` or `log`
185
+ about 1 ms.