Skip to main content

RHEPLICANT

Documentation Status

A REPLICa of an ANTenna — a JAX + Equinox framework for building differentiable replicas of single-antenna radio telescopes: horns, dipoles, and dishes alike. Documentation: rheplicant.readthedocs.io

A RHEPLICANT twin is one pure function from sky and instrument parameters to raw data. Because every stage — foregrounds, ionosphere, beam, receiver reflections, gain drifts, digitisation — is differentiable, the same twin that simulates an observation also calibrates it: gradients, Bayesian posteriors, Fisher forecasts, and neural surrogates all run through the instrument model itself, with no re-implementation.

from rheplicant.radio import assemble, GlobalSignalOperator, ForegroundOperator, GainOperator

twin = assemble(GlobalSignalOperator(...), ForegroundOperator(...), GainOperator(...))
observation = twin(state)          # simulate — and differentiate, fit, sample

First deployed for RHINO (a horn antenna targeting the 21 cm global signal); the core is domain-agnostic by construction.

The name

RHEPLICANT is REPLICANT wearing RHINO's horn. REPLICANT is itself a portmanteau of REPLICa and ANTenna — a digital twin is a replica, and this one is of a radio antenna — the two words overlapping on their shared A. Slip an H in behind the first letter and R… becomes RH…, the mark of RHINO, the horn antenna the framework was first built for:

R E P L I C A            replica
            A N T         antenna
─────────────────
R E P L I C A N T        replicant
  + H  →  RH…            (for RHINO)
─────────────────
R H E P L I C A N T      rheplicant

One-line gloss: a differentiable replica of a radio antenna — first, of RHINO.

Philosophy

  1. Everything is an operator acting on a state. One contract — State in, State out — covers sky models, instrument effects, data processing, filters, even neural networks. If it transforms the scientific context, it is an operator; there is nothing else to learn.

  2. The twin is a differentiable function. Every physical parameter is a pytree leaf, so jit, grad, and vmap apply to the entire instrument. Systematics stop being nuisances you correct for and become parameters you infer, forecast, and marginalise.

  3. Composition is physics — and it is implicit in the signal path. Sequential effects chain (Pipeline), independent contributions add (SumOperator), switched paths select (SelectOperator). The canonical signal-path graph knows how elements connect, so assemble(*operators) builds the right composition from a set: provide only a sky and a beam, get exactly the beam-convolved sky — partial models come free.

  4. Purity everywhere. States are immutable (functional updates only), randomness is data flowing through the state (one seed reproduces an entire run), and operators have no hidden side effects. This is what makes the whole twin safe to transform.

  5. Forward models never contain inference. A single seam — build_forward_fn — turns any twin into f(params) -> prediction. Gradient and Adam calibrators, NumPyro posteriors, Fisher forecasts, and surrogate training all connect there; calibration never contaminates the instrument description.

  6. Interfaces first, physics second. Every operator ships as a trivial-but-runnable placeholder whose contract (shapes, PRNG consumption, linearity in calibration parameters) is real and tested. Real physics replaces function bodies, never interfaces — the native differentiable limTOD sky engine arrived exactly this way.

  7. Loud failure over silent wrongness. Structural validation at every boundary, trace-time (jit-safe) shape checks, provenance-tagged covariance matrices, assembly-time graph errors. In a framework built to chase 0.1 % systematics, a wrong number is worse than an exception.

  8. The core is domain-agnostic. rheplicant.core never imports the radio layer (a test enforces it). Radio astronomy is the first application, not the design center.

Install

pip install rheplicant
# or, for development:
git clone https://github.com/zzhang0123/rheplicant
cd rheplicant && uv sync          # extras: uv sync --extra numpyro

Requires Python ≥ 3.11, jax ≥ 0.5, equinox ≥ 0.13. Distribution and import name are the same: rheplicant.

Sixty seconds of RHEPLICANT

import jax, jax.numpy as jnp, equinox as eqx
from rheplicant import State, Coordinates
from rheplicant.radio import assemble, SkyOperator, GainOperator, NoiseOperator
from rheplicant.inference import build_forward_fn, GradientCalibrator

state = State(
    coords=Coordinates(time=jnp.linspace(0, 60, 128),
                       freq=jnp.linspace(60e6, 85e6, 32)),
    key=jax.random.key(0),
    meta={"telescope": "my-antenna"},
)

# 1. Simulate: provide operators; the signal-path graph composes them.
twin = assemble(
    SkyOperator(amplitude=jnp.array(1e3)),
    GainOperator(gain=jnp.array(1.1)),          # the truth to recover
    NoiseOperator(sigma=jnp.array(0.5)),
)
observed = eqx.filter_jit(twin)(state)

# 2. Calibrate: freeze everything except the gain, descend the gradient.
model = twin.replace_node("gain", GainOperator(gain=jnp.array(1.0)))
spec = jax.tree.map(lambda _: False, model)
spec = eqx.tree_at(lambda p: p["gain"].gain, spec, replace=True)
forward, params0 = build_forward_fn(model, state, filter_spec=spec)
params_fit, losses = GradientCalibrator(learning_rate=2e-7, n_steps=200).fit(
    forward, params0, observed.data
)
print(jax.tree.leaves(params_fit)[0])           # ~1.1

The same forward plugs into NUTS posteriors (to_numpyro_model), Fisher forecasts (fisher_information), and neural-surrogate training — see the guided tour.

What is in the box

  • CoreState (immutable pytree context), Pipeline / SumOperator / SelectOperator composition, SignalGraph + assemble (graph-guided auto-composition with lit/dim mermaid & HTML rendering).
  • Radio — a 29-node canonical signal-path graph covering every element of a single-antenna experiment: sky components, ionosphere, RFI, shared chromatic beam, noise-wave/reflection terms, CW tone and switched calibration loads, gain, thermal noise, EMI, ADC, flagging, averaging — plus a modular sky engine (limTOD bridge / projection matrices / m-mode / native differentiable limTOD) and linear analysis filters (sidereal, sky-space map-making, fringe-rate/delay).
  • Inference — gradient & Adam calibrators, NumPyro bridge with pytree priors and posterior predictive, Fisher / Cramér-Rao / delta-method uncertainty propagation, Monte Carlo pushforward, NeuralOperator surrogate stages, MomentRFI flagging bridge, masked likelihoods.

Documentation

Rendered docs: rheplicant.readthedocs.io (Sphinx + furo; build locally with uv run sphinx-build -b html docs docs/_build/html).

Document What it covers
Guided tour The complete API, top to bottom, with runnable snippets
Operator catalog Every operator: graph node, role, parameters
Architecture Design decisions D1–D13, element taxonomy, physics roadmap
Changelog What arrived when
examples/ Four end-to-end runnable demos

Status

The architecture and inference layer are complete and tested end-to-end (330+ tests, ~96 % coverage, jit+grad+vmap through the full twin; assembly is regression-tested bitwise against hand-built composition). Radio operator physics is deliberately placeholder pending ports from limTOD and friends — except the native differentiable sky engine, which is real. Conventions: degrees in public APIs, radians internally; strings in meta (static), numbers in coords/env/aux (traced); one seed reproduces a run.

No CI yet — run uv run pytest and uv run ruff check before pushing.

Developers and maintainers

  • Zheng Zhang
  • Phil Bull
  • Jordan Norris
  • Rashi Srivastava

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rheplicant-0.1.1.tar.gz (114.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rheplicant-0.1.1-py3-none-any.whl (87.6 kB view details)

Uploaded Python 3

File details

Details for the file rheplicant-0.1.1.tar.gz.

File metadata

  • Download URL: rheplicant-0.1.1.tar.gz
  • Upload date:
  • Size: 114.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for rheplicant-0.1.1.tar.gz
Algorithm Hash digest
SHA256 6cb94b028efb3139ef4f8b12c8e146f6566af31edf4f0c3c51a8fee90f6f5f5f
MD5 d9b9e9f39a24b686f980d84fcb4472d6
BLAKE2b-256 56d3602af2119d86327da0b5d322ed32552fadfd5a9400839a4ca11d0b5f9f4a

See more details on using hashes here.

Provenance

The following attestation bundles were made for rheplicant-0.1.1.tar.gz:

Publisher: publish.yml on zzhang0123/rheplicant

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rheplicant-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: rheplicant-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 87.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for rheplicant-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 bb4fa5df41f657afb7b51a64657fe6c095694d0f1fbd77e399bfbf342c7778de
MD5 0b017720fa0bb81ac50c0505e36765ab
BLAKE2b-256 e2586ec685beda57e97cee1e28b4b71ac076a29dc3c8bb01ec2df342cc3a1f62

See more details on using hashes here.

Provenance

The following attestation bundles were made for rheplicant-0.1.1-py3-none-any.whl:

Publisher: publish.yml on zzhang0123/rheplicant

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.2.0

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

This release

0.1.1 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page