smcx 1.0.0__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.
- smcx-1.0.0/PKG-INFO +181 -0
- smcx-1.0.0/README.md +147 -0
- smcx-1.0.0/pyproject.toml +193 -0
- smcx-1.0.0/src/smcx/__init__.py +94 -0
- smcx-1.0.0/src/smcx/__main__.py +15 -0
- smcx-1.0.0/src/smcx/_utils.py +172 -0
- smcx-1.0.0/src/smcx/auxiliary.py +245 -0
- smcx-1.0.0/src/smcx/bootstrap.py +209 -0
- smcx-1.0.0/src/smcx/containers.py +188 -0
- smcx-1.0.0/src/smcx/diagnostics.py +765 -0
- smcx-1.0.0/src/smcx/exceptions.py +19 -0
- smcx-1.0.0/src/smcx/guided.py +205 -0
- smcx-1.0.0/src/smcx/liu_west.py +303 -0
- smcx-1.0.0/src/smcx/py.typed +0 -0
- smcx-1.0.0/src/smcx/resampling.py +148 -0
- smcx-1.0.0/src/smcx/simulate.py +80 -0
- smcx-1.0.0/src/smcx/smc2.py +312 -0
- smcx-1.0.0/src/smcx/tempering.py +241 -0
- smcx-1.0.0/src/smcx/types.py +15 -0
- smcx-1.0.0/src/smcx/weights.py +74 -0
smcx-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: smcx
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Sequential Monte Carlo for Apple silicon, built on MLX
|
|
5
|
+
Keywords: apple-silicon,particle-filter,sequential-monte-carlo,bayesian-inference,state-space-models,hidden-markov-models
|
|
6
|
+
Author: Michael Ellis
|
|
7
|
+
Author-email: Michael Ellis <michaelellis003@gmail.com>
|
|
8
|
+
License-Expression: Apache-2.0
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
13
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Dist: jax>=0.10,<0.11
|
|
22
|
+
Requires-Dist: jaxlib>=0.10,<0.11
|
|
23
|
+
Requires-Dist: jaxtyping>=0.3.7
|
|
24
|
+
Requires-Dist: numpy>=2.2.6
|
|
25
|
+
Requires-Dist: jax-mps>=0.10.9,<0.11 ; platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'metal'
|
|
26
|
+
Requires-Python: >=3.11
|
|
27
|
+
Project-URL: Homepage, https://github.com/michaelellis003/smcx
|
|
28
|
+
Project-URL: Repository, https://github.com/michaelellis003/smcx
|
|
29
|
+
Project-URL: Issues, https://github.com/michaelellis003/smcx/issues
|
|
30
|
+
Project-URL: Documentation, https://michaelellis003.github.io/smcx/
|
|
31
|
+
Project-URL: Changelog, https://github.com/michaelellis003/smcx/blob/main/CHANGELOG.md
|
|
32
|
+
Provides-Extra: metal
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# smcx
|
|
36
|
+
|
|
37
|
+
[](https://github.com/michaelellis003/smcx/actions/workflows/ci.yml)
|
|
38
|
+
[](https://pypi.org/project/smcx/)
|
|
39
|
+
[](LICENSE)
|
|
40
|
+
|
|
41
|
+
Sequential Monte Carlo in [JAX](https://github.com/jax-ml/jax): particle
|
|
42
|
+
filters, adaptive tempered SMC, and SMC² with a small, flat API. Runs on
|
|
43
|
+
CPU, CUDA, and TPU through stock JAX, and on Apple-silicon GPUs through
|
|
44
|
+
the optional [jax-mps](https://github.com/tillahoffmann/jax-mps) backend.
|
|
45
|
+
|
|
46
|
+
smcx succeeds [smcjax](https://github.com/michaelellis003/smcjax); all of
|
|
47
|
+
its functionality was ported forward and extended.
|
|
48
|
+
|
|
49
|
+
## Install
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install smcx # CPU / CUDA / TPU via your jax install
|
|
53
|
+
pip install "smcx[metal]" # + jax-mps for Apple-silicon GPUs
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## What's in the box
|
|
57
|
+
|
|
58
|
+
- **Filters**: `bootstrap_filter`, `guided_filter` (general g·f/q
|
|
59
|
+
proposal weights), `auxiliary_filter` (twisted potentials), and
|
|
60
|
+
`liu_west_filter` (joint state–parameter, labeled approximate).
|
|
61
|
+
- **Static targets**: `temper` — adaptive tempered SMC with an
|
|
62
|
+
ESS-bisection schedule and covariance-adapted random-walk moves.
|
|
63
|
+
- **Parameter inference**: `smc2` — nested SMC² with vmapped inner
|
|
64
|
+
filters and PMMH rejuvenation.
|
|
65
|
+
- **Resampling**: systematic, stratified, multinomial, and residual —
|
|
66
|
+
one contract, log-domain weights throughout, float32-safe query
|
|
67
|
+
grids.
|
|
68
|
+
- **Diagnostics**: ESS traces, quantile tail-ESS, Pareto-k
|
|
69
|
+
reliability, CRPS, cumulative log score, Bayes factors,
|
|
70
|
+
posterior-predictive sampling, and a one-call `diagnose` summary.
|
|
71
|
+
- `store_history=False` on every filter drops memory from O(T·N) to
|
|
72
|
+
O(N) with a bit-identical evidence estimate.
|
|
73
|
+
|
|
74
|
+
Every sampler is validated against exact references — Kalman oracles
|
|
75
|
+
for the filters, conjugate evidence for tempering, grid-integrated
|
|
76
|
+
posteriors for SMC² — with Monte-Carlo-calibrated gates, not loose
|
|
77
|
+
tolerances.
|
|
78
|
+
|
|
79
|
+
## Quick start
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
import jax.numpy as jnp
|
|
83
|
+
import jax.random as jr
|
|
84
|
+
|
|
85
|
+
import smcx
|
|
86
|
+
|
|
87
|
+
# A 1-D linear-Gaussian state-space model.
|
|
88
|
+
A, Q, R = 0.9, 0.5, 0.3
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def init(key, n):
|
|
92
|
+
return jr.normal(key, (n, 1))
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def transition(key, z):
|
|
96
|
+
return A * z + jnp.sqrt(Q) * jr.normal(key, z.shape)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def log_observation(y, z):
|
|
100
|
+
return -0.5 * (jnp.log(2 * jnp.pi * R) + (y[0] - z[0]) ** 2 / R)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
post = smcx.bootstrap_filter(
|
|
104
|
+
jr.key(0),
|
|
105
|
+
init,
|
|
106
|
+
transition,
|
|
107
|
+
log_observation,
|
|
108
|
+
emissions,
|
|
109
|
+
num_particles=10_000,
|
|
110
|
+
)
|
|
111
|
+
post.marginal_loglik # unbiased evidence estimate (log-domain)
|
|
112
|
+
smcx.diagnose(post) # ESS / diversity / Pareto-k health summary
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Callbacks are per-particle; smcx vmaps them internally. Everything
|
|
116
|
+
takes an explicit PRNG key, and posteriors are NamedTuples — ordinary
|
|
117
|
+
JAX pytrees.
|
|
118
|
+
|
|
119
|
+
## Apple silicon
|
|
120
|
+
|
|
121
|
+
The `[metal]` extra runs the same code on M-series GPUs via jax-mps.
|
|
122
|
+
Filter correctness on Metal is gate-verified in this repository's test
|
|
123
|
+
suite (`SMCX_TEST_PLATFORM=mps` runs it on the GPU), and several of the
|
|
124
|
+
performance fixes that make the backend fast for SMC-shaped workloads
|
|
125
|
+
were contributed upstream from this project (jax-mps #215, #216, #220).
|
|
126
|
+
Metal is float32-only; the suite runs float64 on CPU and float32 on
|
|
127
|
+
Metal automatically.
|
|
128
|
+
|
|
129
|
+
## Development
|
|
130
|
+
|
|
131
|
+
Requires Python 3.11+ and [uv](https://docs.astral.sh/uv/).
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
git clone https://github.com/michaelellis003/smcx.git
|
|
135
|
+
cd smcx
|
|
136
|
+
uv sync
|
|
137
|
+
uv run pre-commit install
|
|
138
|
+
uv run pre-commit install --hook-type commit-msg
|
|
139
|
+
uv run pre-commit install --hook-type pre-push
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
A `Makefile` covers common tasks:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
make test # lint + pytest
|
|
146
|
+
make lint # ruff check, format check, license headers, ty
|
|
147
|
+
make format # add license headers, ruff format, ruff fix
|
|
148
|
+
make docs # build docs
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Releases are automated: `python-semantic-release` reads conventional
|
|
152
|
+
commits on merge to main, bumps the version, tags, and publishes.
|
|
153
|
+
|
|
154
|
+
## Design notes
|
|
155
|
+
|
|
156
|
+
Decision records live in `docs/adr/` and dated evidence in
|
|
157
|
+
`docs/research/` — including the benchmark study that shaped the
|
|
158
|
+
architecture: a native-MLX implementation of this library was built,
|
|
159
|
+
measured against jax-mps on equal terms, and retired when the
|
|
160
|
+
measurements showed the compatibility path could be made equally fast
|
|
161
|
+
with fixes contributed upstream
|
|
162
|
+
(`docs/research/2026-07-16-jax-mps-internals.md`). The MLX
|
|
163
|
+
implementation remains in git history at the `mlx-final` tag.
|
|
164
|
+
|
|
165
|
+
## Acknowledgments
|
|
166
|
+
|
|
167
|
+
smcx's design draws on the SMC ecosystem:
|
|
168
|
+
[smcjax](https://github.com/michaelellis003/smcjax) (the predecessor
|
|
169
|
+
library), [particles](https://github.com/nchopin/particles) and Chopin &
|
|
170
|
+
Papaspiliopoulos's *An Introduction to Sequential Monte Carlo* (the
|
|
171
|
+
Feynman-Kac architecture),
|
|
172
|
+
[BlackJAX](https://github.com/blackjax-devs/blackjax) (the resampling
|
|
173
|
+
contract), [Dynamax](https://github.com/probml/dynamax) (container
|
|
174
|
+
conventions), TensorFlow Probability (criterion/trace hooks), and
|
|
175
|
+
design lessons from PyMC, FilterPy, pfilter, pyfilter, Stone Soup,
|
|
176
|
+
pomp, nimbleSMC, and ArviZ. See `CITATION.cff` for formal references
|
|
177
|
+
and `docs/research/licensing.md` for the full provenance record.
|
|
178
|
+
|
|
179
|
+
## License
|
|
180
|
+
|
|
181
|
+
Apache-2.0
|
smcx-1.0.0/README.md
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# smcx
|
|
2
|
+
|
|
3
|
+
[](https://github.com/michaelellis003/smcx/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/smcx/)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
Sequential Monte Carlo in [JAX](https://github.com/jax-ml/jax): particle
|
|
8
|
+
filters, adaptive tempered SMC, and SMC² with a small, flat API. Runs on
|
|
9
|
+
CPU, CUDA, and TPU through stock JAX, and on Apple-silicon GPUs through
|
|
10
|
+
the optional [jax-mps](https://github.com/tillahoffmann/jax-mps) backend.
|
|
11
|
+
|
|
12
|
+
smcx succeeds [smcjax](https://github.com/michaelellis003/smcjax); all of
|
|
13
|
+
its functionality was ported forward and extended.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install smcx # CPU / CUDA / TPU via your jax install
|
|
19
|
+
pip install "smcx[metal]" # + jax-mps for Apple-silicon GPUs
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## What's in the box
|
|
23
|
+
|
|
24
|
+
- **Filters**: `bootstrap_filter`, `guided_filter` (general g·f/q
|
|
25
|
+
proposal weights), `auxiliary_filter` (twisted potentials), and
|
|
26
|
+
`liu_west_filter` (joint state–parameter, labeled approximate).
|
|
27
|
+
- **Static targets**: `temper` — adaptive tempered SMC with an
|
|
28
|
+
ESS-bisection schedule and covariance-adapted random-walk moves.
|
|
29
|
+
- **Parameter inference**: `smc2` — nested SMC² with vmapped inner
|
|
30
|
+
filters and PMMH rejuvenation.
|
|
31
|
+
- **Resampling**: systematic, stratified, multinomial, and residual —
|
|
32
|
+
one contract, log-domain weights throughout, float32-safe query
|
|
33
|
+
grids.
|
|
34
|
+
- **Diagnostics**: ESS traces, quantile tail-ESS, Pareto-k
|
|
35
|
+
reliability, CRPS, cumulative log score, Bayes factors,
|
|
36
|
+
posterior-predictive sampling, and a one-call `diagnose` summary.
|
|
37
|
+
- `store_history=False` on every filter drops memory from O(T·N) to
|
|
38
|
+
O(N) with a bit-identical evidence estimate.
|
|
39
|
+
|
|
40
|
+
Every sampler is validated against exact references — Kalman oracles
|
|
41
|
+
for the filters, conjugate evidence for tempering, grid-integrated
|
|
42
|
+
posteriors for SMC² — with Monte-Carlo-calibrated gates, not loose
|
|
43
|
+
tolerances.
|
|
44
|
+
|
|
45
|
+
## Quick start
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
import jax.numpy as jnp
|
|
49
|
+
import jax.random as jr
|
|
50
|
+
|
|
51
|
+
import smcx
|
|
52
|
+
|
|
53
|
+
# A 1-D linear-Gaussian state-space model.
|
|
54
|
+
A, Q, R = 0.9, 0.5, 0.3
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def init(key, n):
|
|
58
|
+
return jr.normal(key, (n, 1))
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def transition(key, z):
|
|
62
|
+
return A * z + jnp.sqrt(Q) * jr.normal(key, z.shape)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def log_observation(y, z):
|
|
66
|
+
return -0.5 * (jnp.log(2 * jnp.pi * R) + (y[0] - z[0]) ** 2 / R)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
post = smcx.bootstrap_filter(
|
|
70
|
+
jr.key(0),
|
|
71
|
+
init,
|
|
72
|
+
transition,
|
|
73
|
+
log_observation,
|
|
74
|
+
emissions,
|
|
75
|
+
num_particles=10_000,
|
|
76
|
+
)
|
|
77
|
+
post.marginal_loglik # unbiased evidence estimate (log-domain)
|
|
78
|
+
smcx.diagnose(post) # ESS / diversity / Pareto-k health summary
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Callbacks are per-particle; smcx vmaps them internally. Everything
|
|
82
|
+
takes an explicit PRNG key, and posteriors are NamedTuples — ordinary
|
|
83
|
+
JAX pytrees.
|
|
84
|
+
|
|
85
|
+
## Apple silicon
|
|
86
|
+
|
|
87
|
+
The `[metal]` extra runs the same code on M-series GPUs via jax-mps.
|
|
88
|
+
Filter correctness on Metal is gate-verified in this repository's test
|
|
89
|
+
suite (`SMCX_TEST_PLATFORM=mps` runs it on the GPU), and several of the
|
|
90
|
+
performance fixes that make the backend fast for SMC-shaped workloads
|
|
91
|
+
were contributed upstream from this project (jax-mps #215, #216, #220).
|
|
92
|
+
Metal is float32-only; the suite runs float64 on CPU and float32 on
|
|
93
|
+
Metal automatically.
|
|
94
|
+
|
|
95
|
+
## Development
|
|
96
|
+
|
|
97
|
+
Requires Python 3.11+ and [uv](https://docs.astral.sh/uv/).
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
git clone https://github.com/michaelellis003/smcx.git
|
|
101
|
+
cd smcx
|
|
102
|
+
uv sync
|
|
103
|
+
uv run pre-commit install
|
|
104
|
+
uv run pre-commit install --hook-type commit-msg
|
|
105
|
+
uv run pre-commit install --hook-type pre-push
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
A `Makefile` covers common tasks:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
make test # lint + pytest
|
|
112
|
+
make lint # ruff check, format check, license headers, ty
|
|
113
|
+
make format # add license headers, ruff format, ruff fix
|
|
114
|
+
make docs # build docs
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Releases are automated: `python-semantic-release` reads conventional
|
|
118
|
+
commits on merge to main, bumps the version, tags, and publishes.
|
|
119
|
+
|
|
120
|
+
## Design notes
|
|
121
|
+
|
|
122
|
+
Decision records live in `docs/adr/` and dated evidence in
|
|
123
|
+
`docs/research/` — including the benchmark study that shaped the
|
|
124
|
+
architecture: a native-MLX implementation of this library was built,
|
|
125
|
+
measured against jax-mps on equal terms, and retired when the
|
|
126
|
+
measurements showed the compatibility path could be made equally fast
|
|
127
|
+
with fixes contributed upstream
|
|
128
|
+
(`docs/research/2026-07-16-jax-mps-internals.md`). The MLX
|
|
129
|
+
implementation remains in git history at the `mlx-final` tag.
|
|
130
|
+
|
|
131
|
+
## Acknowledgments
|
|
132
|
+
|
|
133
|
+
smcx's design draws on the SMC ecosystem:
|
|
134
|
+
[smcjax](https://github.com/michaelellis003/smcjax) (the predecessor
|
|
135
|
+
library), [particles](https://github.com/nchopin/particles) and Chopin &
|
|
136
|
+
Papaspiliopoulos's *An Introduction to Sequential Monte Carlo* (the
|
|
137
|
+
Feynman-Kac architecture),
|
|
138
|
+
[BlackJAX](https://github.com/blackjax-devs/blackjax) (the resampling
|
|
139
|
+
contract), [Dynamax](https://github.com/probml/dynamax) (container
|
|
140
|
+
conventions), TensorFlow Probability (criterion/trace hooks), and
|
|
141
|
+
design lessons from PyMC, FilterPy, pfilter, pyfilter, Stone Soup,
|
|
142
|
+
pomp, nimbleSMC, and ArviZ. See `CITATION.cff` for formal references
|
|
143
|
+
and `docs/research/licensing.md` for the full provenance record.
|
|
144
|
+
|
|
145
|
+
## License
|
|
146
|
+
|
|
147
|
+
Apache-2.0
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "smcx"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "Sequential Monte Carlo for Apple silicon, built on MLX"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Michael Ellis", email = "michaelellis003@gmail.com" }
|
|
8
|
+
]
|
|
9
|
+
license = "Apache-2.0"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
keywords = [
|
|
12
|
+
"apple-silicon",
|
|
13
|
+
"particle-filter",
|
|
14
|
+
"sequential-monte-carlo",
|
|
15
|
+
"bayesian-inference",
|
|
16
|
+
"state-space-models",
|
|
17
|
+
"hidden-markov-models",
|
|
18
|
+
]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 3 - Alpha",
|
|
21
|
+
"Intended Audience :: Science/Research",
|
|
22
|
+
"License :: OSI Approved :: Apache Software License",
|
|
23
|
+
"Operating System :: MacOS :: MacOS X",
|
|
24
|
+
"Operating System :: POSIX :: Linux",
|
|
25
|
+
"Programming Language :: Python :: 3",
|
|
26
|
+
"Programming Language :: Python :: 3.10",
|
|
27
|
+
"Programming Language :: Python :: 3.11",
|
|
28
|
+
"Programming Language :: Python :: 3.12",
|
|
29
|
+
"Programming Language :: Python :: 3.13",
|
|
30
|
+
"Topic :: Scientific/Engineering :: Mathematics",
|
|
31
|
+
"Typing :: Typed",
|
|
32
|
+
]
|
|
33
|
+
dependencies = [
|
|
34
|
+
"jax>=0.10,<0.11",
|
|
35
|
+
"jaxlib>=0.10,<0.11",
|
|
36
|
+
"jaxtyping>=0.3.7",
|
|
37
|
+
"numpy>=2.2.6",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.urls]
|
|
41
|
+
Homepage = "https://github.com/michaelellis003/smcx"
|
|
42
|
+
Repository = "https://github.com/michaelellis003/smcx"
|
|
43
|
+
Issues = "https://github.com/michaelellis003/smcx/issues"
|
|
44
|
+
Documentation = "https://michaelellis003.github.io/smcx/"
|
|
45
|
+
Changelog = "https://github.com/michaelellis003/smcx/blob/main/CHANGELOG.md"
|
|
46
|
+
|
|
47
|
+
[build-system]
|
|
48
|
+
requires = ["uv_build>=0.9.5,<0.12.0"]
|
|
49
|
+
build-backend = "uv_build"
|
|
50
|
+
|
|
51
|
+
[project.optional-dependencies]
|
|
52
|
+
# Apple-GPU acceleration via the jax-mps PJRT plugin (ADR-0018).
|
|
53
|
+
metal = [
|
|
54
|
+
# jax-mps only ships macOS-arm64 wheels; the marker keeps the
|
|
55
|
+
# extra resolvable (as a no-op) on other platforms, e.g. Linux CI.
|
|
56
|
+
"jax-mps>=0.10.9,<0.11; sys_platform == 'darwin' and platform_machine == 'arm64'",
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
[dependency-groups]
|
|
60
|
+
dev = [
|
|
61
|
+
"beartype>=0.22.9",
|
|
62
|
+
"dynamax>=1.0.2",
|
|
63
|
+
"hypothesis>=6.156.6",
|
|
64
|
+
"mkdocs-gen-files>=0.6.1",
|
|
65
|
+
"mkdocs-literate-nav>=0.6.3",
|
|
66
|
+
"mkdocs-material>=9.7.6",
|
|
67
|
+
"mkdocstrings[python]>=1.0.3",
|
|
68
|
+
"nanobind>=2.13.0",
|
|
69
|
+
"pre-commit>=4.5.1",
|
|
70
|
+
"properdocs>=1.6.7",
|
|
71
|
+
"pytest>=9.0.3",
|
|
72
|
+
"pytest-cov>=7.1.0",
|
|
73
|
+
"ruff>=0.15.9",
|
|
74
|
+
"ty>=0.0.29",
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
[tool.ruff]
|
|
78
|
+
# Target version enables modern syntax upgrades where possible
|
|
79
|
+
target-version = "py310"
|
|
80
|
+
preview = true
|
|
81
|
+
line-length = 80
|
|
82
|
+
indent-width = 4
|
|
83
|
+
# Generated mlx stubs (ADR-0007) are vendored artifacts, not code.
|
|
84
|
+
extend-exclude = ["typings"]
|
|
85
|
+
|
|
86
|
+
[tool.ruff.lint]
|
|
87
|
+
select = [
|
|
88
|
+
"E", "W", "F", "I", "D", # Core errors, warnings, isort, and docstrings
|
|
89
|
+
"N", # pep8-naming (Google style includes naming conventions)
|
|
90
|
+
"UP", # pyupgrade (modernizes syntax)
|
|
91
|
+
"B", # flake8-bugbear (catches design flaws/bugs)
|
|
92
|
+
"SIM", # flake8-simplify (cleans up messy logic)
|
|
93
|
+
"RUF", # Ruff's custom advanced rules
|
|
94
|
+
]
|
|
95
|
+
ignore = [
|
|
96
|
+
# jaxtyping uses string-shape annotations (e.g. Float[mx.array, " n"])
|
|
97
|
+
# which ruff parses as forward references and rejects (ADR-0007).
|
|
98
|
+
"F722",
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
[tool.ruff.lint.pydocstyle]
|
|
102
|
+
# Enforce Google-style docstrings
|
|
103
|
+
convention = "google"
|
|
104
|
+
|
|
105
|
+
[tool.ruff.lint.per-file-ignores]
|
|
106
|
+
# Tests use class-based grouping; method docstrings are noisy. LGSSM
|
|
107
|
+
# tests keep the literature's matrix notation (F, Q, H, R, P0).
|
|
108
|
+
"tests/*" = ["D102", "D103", "D104", "N806", "N803"]
|
|
109
|
+
# The version fallback try/except is standard packaging boilerplate.
|
|
110
|
+
"src/smcx/__init__.py" = ["RUF067"]
|
|
111
|
+
# Protocol stubs: the class docstring documents the contract.
|
|
112
|
+
"src/smcx/types.py" = ["D102"]
|
|
113
|
+
"src/smcx/containers.py" = ["D102"]
|
|
114
|
+
# Preserved research/verification scripts (see docs/research/*),
|
|
115
|
+
# not library code — exempt from library-grade lint.
|
|
116
|
+
"benchmarks/exploratory/*" = ["ALL"]
|
|
117
|
+
# Kill-test harness: maintained, protocol-critical code — full lint
|
|
118
|
+
# except docstrings on model closures/helpers.
|
|
119
|
+
"benchmarks/killtest/*" = ["D101", "D102", "D103"]
|
|
120
|
+
"benchmarks/smc2/bench_smc2.py" = ["D101", "D102", "D103"]
|
|
121
|
+
# particles_side follows the `particles` API: uppercase model
|
|
122
|
+
# methods (PX0/PX/PY) and a mutable default_params dict are required
|
|
123
|
+
# by StateSpaceModel, not smcx style.
|
|
124
|
+
"benchmarks/smc2/particles_side.py" = ["D101", "D102", "D103", "N802", "RUF012"]
|
|
125
|
+
# conftest installs the jaxtyping import hook before importing smcx,
|
|
126
|
+
# which forces module-level imports below code (smcjax convention).
|
|
127
|
+
"tests/conftest.py" = ["E402"]
|
|
128
|
+
|
|
129
|
+
[tool.ruff.format]
|
|
130
|
+
docstring-code-format = true
|
|
131
|
+
|
|
132
|
+
[tool.semantic_release]
|
|
133
|
+
version_toml = ["pyproject.toml:project.version"]
|
|
134
|
+
version_variables = ["src/smcx/__init__.py:__version__"]
|
|
135
|
+
commit_message = "chore(release): {version}"
|
|
136
|
+
# Stay 0.x on BREAKING CHANGE commits until stability is declared.
|
|
137
|
+
major_on_zero = false
|
|
138
|
+
|
|
139
|
+
[tool.semantic_release.changelog.default_templates]
|
|
140
|
+
changelog_file = "CHANGELOG.md"
|
|
141
|
+
|
|
142
|
+
[tool.semantic_release.remote]
|
|
143
|
+
type = "github"
|
|
144
|
+
|
|
145
|
+
[tool.semantic_release.publish]
|
|
146
|
+
upload_to_vcs_release = true
|
|
147
|
+
|
|
148
|
+
[tool.ty.src]
|
|
149
|
+
# Research scripts are lint/type-exempt artifacts; typings/ holds
|
|
150
|
+
# generated stubs (checked as a search path, not as source);
|
|
151
|
+
# killtest and the SMC² particles baseline span separate venvs
|
|
152
|
+
# (jax_side / particles_side import packages unresolvable here by
|
|
153
|
+
# construction). The native-vs-jax-mps JAX worker is the same case: it
|
|
154
|
+
# runs only inside the pinned `uv run --no-project` env, so jax and the
|
|
155
|
+
# jax_plugins.mps backend are unresolvable in the project environment.
|
|
156
|
+
# The MLX-era benchmark workers reference the pre-ADR-0018 API and the
|
|
157
|
+
# vendored MLX stubs; they are retained as historical harness code until
|
|
158
|
+
# the harness is re-aimed at the jax-mps backend (pivot spec, slice 7).
|
|
159
|
+
exclude = [
|
|
160
|
+
"benchmarks/exploratory/**",
|
|
161
|
+
"benchmarks/killtest/**",
|
|
162
|
+
"benchmarks/native_vs_jax_mps/jax_worker.py",
|
|
163
|
+
"benchmarks/native_vs_jax_mps/mlx_worker.py",
|
|
164
|
+
"benchmarks/smc2/**",
|
|
165
|
+
"typings/**",
|
|
166
|
+
]
|
|
167
|
+
|
|
168
|
+
[tool.ty.environment]
|
|
169
|
+
# Vendored mlx.core stubs (ADR-0007): upstream ships py.typed but no
|
|
170
|
+
# .pyi for the compiled extension. Regenerate on every mlx floor bump:
|
|
171
|
+
# uv run python -m nanobind.stubgen -m mlx.core -O typings/mlx
|
|
172
|
+
extra-paths = ["typings"]
|
|
173
|
+
|
|
174
|
+
[tool.pytest.ini_options]
|
|
175
|
+
minversion = "7.0"
|
|
176
|
+
addopts = "-ra -q"
|
|
177
|
+
testpaths = [
|
|
178
|
+
"tests",
|
|
179
|
+
]
|
|
180
|
+
|
|
181
|
+
[tool.coverage.run]
|
|
182
|
+
source = ["smcx"]
|
|
183
|
+
branch = true
|
|
184
|
+
|
|
185
|
+
[tool.coverage.report]
|
|
186
|
+
fail_under = 80
|
|
187
|
+
show_missing = true
|
|
188
|
+
exclude_lines = [
|
|
189
|
+
"pragma: no cover",
|
|
190
|
+
"if __name__ == .__main__.",
|
|
191
|
+
"if TYPE_CHECKING:",
|
|
192
|
+
"@overload",
|
|
193
|
+
]
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Copyright 2026 Michael Ellis
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
"""Sequential Monte Carlo and particle filtering in JAX."""
|
|
5
|
+
|
|
6
|
+
from importlib.metadata import PackageNotFoundError as _PackageNotFoundError
|
|
7
|
+
from importlib.metadata import version as _version
|
|
8
|
+
|
|
9
|
+
from smcx.auxiliary import auxiliary_filter
|
|
10
|
+
from smcx.bootstrap import bootstrap_filter
|
|
11
|
+
from smcx.containers import (
|
|
12
|
+
LiuWestPosterior,
|
|
13
|
+
ParticleFilterPosterior,
|
|
14
|
+
ParticleFilterResult,
|
|
15
|
+
ParticleState,
|
|
16
|
+
SMC2Posterior,
|
|
17
|
+
TemperedPosterior,
|
|
18
|
+
)
|
|
19
|
+
from smcx.diagnostics import (
|
|
20
|
+
crps,
|
|
21
|
+
cumulative_log_score,
|
|
22
|
+
diagnose,
|
|
23
|
+
log_bayes_factor,
|
|
24
|
+
log_ml_increments,
|
|
25
|
+
param_weighted_mean,
|
|
26
|
+
param_weighted_quantile,
|
|
27
|
+
pareto_k_diagnostic,
|
|
28
|
+
particle_diversity,
|
|
29
|
+
posterior_predictive_sample,
|
|
30
|
+
replicated_log_ml,
|
|
31
|
+
tail_ess,
|
|
32
|
+
weighted_mean,
|
|
33
|
+
weighted_quantile,
|
|
34
|
+
weighted_variance,
|
|
35
|
+
)
|
|
36
|
+
from smcx.exceptions import DegenerateWeightsError
|
|
37
|
+
from smcx.guided import guided_filter
|
|
38
|
+
from smcx.liu_west import liu_west_filter
|
|
39
|
+
from smcx.resampling import (
|
|
40
|
+
multinomial,
|
|
41
|
+
residual,
|
|
42
|
+
stratified,
|
|
43
|
+
systematic,
|
|
44
|
+
)
|
|
45
|
+
from smcx.simulate import simulate
|
|
46
|
+
from smcx.smc2 import smc2
|
|
47
|
+
from smcx.tempering import temper
|
|
48
|
+
from smcx.weights import ess, log_ess, log_normalize, normalize
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
__version__ = _version("smcx")
|
|
52
|
+
except _PackageNotFoundError:
|
|
53
|
+
__version__ = "1.0.0"
|
|
54
|
+
|
|
55
|
+
__all__ = [
|
|
56
|
+
"DegenerateWeightsError",
|
|
57
|
+
"LiuWestPosterior",
|
|
58
|
+
"ParticleFilterPosterior",
|
|
59
|
+
"ParticleFilterResult",
|
|
60
|
+
"ParticleState",
|
|
61
|
+
"SMC2Posterior",
|
|
62
|
+
"TemperedPosterior",
|
|
63
|
+
"__version__",
|
|
64
|
+
"auxiliary_filter",
|
|
65
|
+
"bootstrap_filter",
|
|
66
|
+
"crps",
|
|
67
|
+
"cumulative_log_score",
|
|
68
|
+
"diagnose",
|
|
69
|
+
"ess",
|
|
70
|
+
"guided_filter",
|
|
71
|
+
"liu_west_filter",
|
|
72
|
+
"log_bayes_factor",
|
|
73
|
+
"log_ess",
|
|
74
|
+
"log_ml_increments",
|
|
75
|
+
"log_normalize",
|
|
76
|
+
"multinomial",
|
|
77
|
+
"normalize",
|
|
78
|
+
"param_weighted_mean",
|
|
79
|
+
"param_weighted_quantile",
|
|
80
|
+
"pareto_k_diagnostic",
|
|
81
|
+
"particle_diversity",
|
|
82
|
+
"posterior_predictive_sample",
|
|
83
|
+
"replicated_log_ml",
|
|
84
|
+
"residual",
|
|
85
|
+
"simulate",
|
|
86
|
+
"smc2",
|
|
87
|
+
"stratified",
|
|
88
|
+
"systematic",
|
|
89
|
+
"tail_ess",
|
|
90
|
+
"temper",
|
|
91
|
+
"weighted_mean",
|
|
92
|
+
"weighted_quantile",
|
|
93
|
+
"weighted_variance",
|
|
94
|
+
]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copyright 2026 Michael Ellis
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
"""Allow running the package with ``python -m smcx``."""
|
|
5
|
+
|
|
6
|
+
from smcx import __version__
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def main() -> None:
|
|
10
|
+
"""Print package version."""
|
|
11
|
+
print(f"smcx {__version__}")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
if __name__ == "__main__":
|
|
15
|
+
main()
|