Prophys, a differentiable, JAX-native DSL for spatial probability and risk models
Project description
prophys: probabilistic-physics modelling toolkit
A differentiable, JAX-native DSL for spatial probability and risk models.
Overview
prophys lets you describe an uncertainty structure (geometry, physics, distributions) as a symbolic Python model, and compiles it into a single differentiable JAX graph with log_prob, sample, expectation, tail-risk metrics, gradient-based calibration, and design optimization.
It is not a distribution library like NumPyro or Distrax. It is the layer above one. The distinguishing capability is that geometry, interpolated fields, physics surrogates, and probability live in the same differentiable graph: a pipeline route vertex, an emission abatement fraction, or a copula correlation can all be trained or optimized with the same jax.grad pass that evaluates the model.
It combines:
- A symbolic expression core (
Expr,Param,Input,RandomVariable) with NumPy-style operator overloading. Models are built with ordinary arithmetic and compile to purejax.numpy. - Differentiable geometry structures in shared coordinate frames:
PointList,LineList,Polygon/PolygonList(signed distance, containment, area),Polyhedron(3D halfspace volumes), rasterFields with bilinear interpolation, and evaluationGrids. - Transformations: linear/affine/polynomial, smoothable
PiecewiseLinear,Decay,Logisticdose-response, and interpolatedTableLookup1D/2Dcharacteristic curves. - Distributions: 12+ univariate families, circular (
VonMises,WrappedGaussian), multivariate Gaussian (Cholesky-parameterized), mixtures, empirical/KDE, and Gaussian copulas with always-valid learnable correlation. - Probabilistic inputs anywhere in the graph: a
RandomVariable(e.g. wind speed/direction) can feed the physics, not just the output noise. The compiled model marginalizes it by reparameterized Monte Carlo with gradients intact. - A training engine (Optax):
calibrateone attribute,finetunethe whole model jointly across attributes with shared parameters,fit_distributionfor standalone/multivariate distribution learning, withtrainable/frozenparameter control. - Design optimization with penalty constraints, where bounded parameters are constrained structurally (sigmoid/softplus bijectors) rather than by projection.
- A standardized export format (
ModelPackage): quantized PMF, histogram, or JAX-free sampler representations, JSON round-trippable, consumer-agnostic.
Installation
pip install prophys
Ships as a prebuilt binary wheel, including the compiled native core (prophys._core), so no Rust toolchain or compilation step is needed.
Free tier / licensing: model calls touching up to 250 structural objects (points, polygon vertices, segments, raster cells, ...) run without any license. This does not count Monte-Carlo sample counts, observation counts, or training iterations, only declared model structure. Larger models require a signed license (set via the PROPHYS_LICENSE environment variable). Contact RhineQC GmbH to obtain one.
With optional extras:
pip install "prophys[viz]" # matplotlib plotting helpers (prophys.plot)
pip install "prophys[geo]" # shapely/pyproj geodata import
pip install "prophys[inference]" # NumPyro bridge
Requirements: Python ≥ 3.11 (JAX and Optax install automatically as dependencies). Python 3.10 is not supported: jaxlib has not published a cp310 wheel since 0.9.0.
Quick Start
import jax
import jax.numpy as jnp
import optax
import prophys as prp
# Geometry in a shared frame: the pipeline route (optimizable) and a receptor
site = prp.Frame("site", units="m")
route = prp.Polyline(
prp.Param("route", shape=(4, 2), init=jnp.array([[0.0, 0.0], [300.0, 60.0], [650.0, -30.0], [900.0, 0.0]])),
site,
)
house = prp.Point(jnp.array([500.0, 250.0]), site)
# Physics: a leak can occur anywhere along the route, so its location is a
# continuous, reparameterized random variable pushed through the route's
# differentiable point_at(t), not a hand-picked set of candidate points
leak_frac = prp.RandomVariable("leak_frac", prp.Uniform(low=0.0, high=1.0))
leak_point = route.point_at(leak_frac)
# Gas dispersion from the leak to the house, then concentration -> a
# probability of health issues (dose-response curve)
distance = prp.norm(house.coords[0] - leak_point)
concentration = prp.Param("emission_rate", init=1.5) * prp.exp(-distance / 150.0)
health_risk = prp.PiecewiseLinear([0.0, 0.05, 0.2, 0.5], [0.0, 0.05, 0.3, 0.85], smooth=0.02)(concentration)
# Probabilistic attribute + standardized model object
incident = prp.UncertainAttribute("health_incident", prp.Bernoulli(prob=prp.clip(health_risk, 1e-4, 1 - 1e-4)))
model = prp.ProbabilityModel(incident)
compiled = model.compile(mode="opt", n_samples=200)
# Probability of a health incident, marginalized over every leak location
# along the route, with a gradient with respect to every vertex of the route
p_incident = compiled.expectation("health_incident")
grad_wrt_route = jax.grad(
lambda params: compiled.expectation("health_incident", params=params)
)(compiled.default_params())
# Calibrate against observations ...
result = prp.calibrate(compiled, "health_incident", observations, n_steps=300)
# ... or optimize the route itself, directly against the marginalized
# probability, with plain JAX/optax (prp.optimize is only a convenience
# wrapper around the same pattern, not required)
opt = optax.adam(0.05)
raw_params = compiled.default_params()
opt_state = opt.init(raw_params)
for _ in range(200):
loss, grads = jax.value_and_grad(
lambda params: compiled.expectation("health_incident", params=params)
)(raw_params)
updates, opt_state = opt.update(grads, opt_state)
raw_params = optax.apply_updates(raw_params, updates)
Uncertainty at the inputs, not just the output
wind_speed = prp.RandomVariable("v", prp.Weibull(scale=6.0, concentration=2.0))
wind_dir = prp.RandomVariable("phi", prp.VonMises(loc=prp.deg2rad(35.0), kappa=3.0))
# Any expression downstream of these is a random quantity. The compiled
# model marginalizes them via reparameterized Monte Carlo, inside one
# JAX trace, so gradients flow back through the marginalization.
Training the model
# Fit one attribute
prp.calibrate(compiled, "exposure", observations)
# Jointly train the entire model. Shared parameters pool information
# across every attribute's observations
prp.finetune(compiled, {"exposure": obs_e, "complaints": obs_c}, frozen=["emission_rate"])
# Learn a standalone (also multivariate) distribution from data
mvn = prp.MultivariateGaussian(
mean=prp.Param("mu", shape=(2,), init=jnp.zeros(2)),
cholesky=prp.Param("L", shape=(2, 2), init=jnp.eye(2)),
)
prp.fit_distribution(mvn, data)
Export
pkg = compiled.export() # quantized PMF / histogram / JAX-free sampler
pkg.save("model.json") # versioned, consumer-agnostic interchange format
Downstream consumers implement their own import against the documented ModelPackage shape. prophys carries no consumer-specific dependencies.
Examples
examples/gas_dispersion/: a complete community-health-risk model. Gaussian plume physics, wind as random inputs, terrain-corrected effective stack height, dose-response calibration, and constrained abatement optimization. Every primitive family appears once.
Documentation
Full docs are at docs.rhineqc.com/distribution/prophys, covering concepts (symbolic graphs, frames, eval/opt modes, marginalization), the full structure/distribution/transformation catalogs with plots, calibration and design optimization, a step-by-step worked example, and the export format specification.
License
prophys is proprietary software by RhineQC GmbH. It is intended for internal or explicitly licensed distribution.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file prophys-0.1.0-cp311-abi3-win_amd64.whl.
File metadata
- Download URL: prophys-0.1.0-cp311-abi3-win_amd64.whl
- Upload date:
- Size: 610.8 kB
- Tags: CPython 3.11+, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ddcd2083c8fb4374b4fd693b92ec3a557fa3309486f23f74903008ea914e24d1
|
|
| MD5 |
e1f4cbc4ba9b5d53e813edfa962a5111
|
|
| BLAKE2b-256 |
610e582c406bf03508981a2f22b4097b9609ac045b09748fa2005a06b8f904c2
|
File details
Details for the file prophys-0.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: prophys-0.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 675.7 kB
- Tags: CPython 3.11+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
69d9787f30d17cb134278d8558bb967dcce29db33f47d782ed4eb7fdc1796ebe
|
|
| MD5 |
d4f74d5c9a11b63be5b67ecaf73dc6e3
|
|
| BLAKE2b-256 |
f98f4f19ea3b517552886ff8fee721e3d9a5456b83881e33e811d87d5cd60a2e
|
File details
Details for the file prophys-0.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: prophys-0.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 620.3 kB
- Tags: CPython 3.11+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a0895b2d570a3bfddab4989aace09d157f6316a650142ff0a8c91a71f7edbaca
|
|
| MD5 |
f0ed923e9d473c545f30ed22acba22f8
|
|
| BLAKE2b-256 |
86001b342493c59d3aa6a98532ce1d1a64e9780d56e809b5545390b3727eef2a
|
File details
Details for the file prophys-0.1.0-cp311-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: prophys-0.1.0-cp311-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 591.1 kB
- Tags: CPython 3.11+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a61bd9ed57e2c429fc302c7fd90db1976d58b96673efd9d01316ff401036daf0
|
|
| MD5 |
f831e582e210dc540566aa7cdc7a6a1d
|
|
| BLAKE2b-256 |
a74cfce79f7fb28699bc55453380affd471d52101fb37355031ad48407bedb7e
|
File details
Details for the file prophys-0.1.0-cp311-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: prophys-0.1.0-cp311-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 623.1 kB
- Tags: CPython 3.11+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
447b562282cf873e591fc830fb9ed1393584680a65e879c6834dad78e6833197
|
|
| MD5 |
9e161eb939ed4432c4133a1934dccf30
|
|
| BLAKE2b-256 |
cdd81afa09a79312dd8a7393326e6be5d561bf5f075a2a73232893f4a7770943
|