Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 0 additions & 86 deletions .github/workflows/static-analysis.yml

This file was deleted.

5 changes: 1 addition & 4 deletions benchmarks/baselines/basic_regressions-linux-py313.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
"name": "linear_kalman",
"iterations": 200,
"max_elapsed_seconds": 30.0,
"final_estimate": [
200.0,
1.0
]
"final_estimate": [200.0, 1.0]
}
]
}
5 changes: 1 addition & 4 deletions benchmarks/baselines/basic_regressions.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
{
"name": "linear_kalman",
"iterations": 200,
"final_estimate": [
200.0,
1.0
]
"final_estimate": [200.0, 1.0]
}
]
}
12 changes: 6 additions & 6 deletions docs/backend-contracts.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
PyRecEst has a dynamic backend facade, so backend support needs executable
contracts in addition to prose documentation.

| Contract surface | Check |
|------------------|-------|
| Facade metadata | Every declared unsupported or partial function must exist on the active facade module. |
| Public API matrix | Every API row must name NumPy, PyTorch, JAX, and explanatory notes. |
| Portable examples | Core examples should run under each backend they claim to support. |
| Unsupported paths | Unsupported backend paths should raise clear backend-named errors. |
| Contract surface | Check |
|-------------------|----------------------------------------------------------------------------------------|
| Facade metadata | Every declared unsupported or partial function must exist on the active facade module. |
| Public API matrix | Every API row must name NumPy, PyTorch, JAX, and explanatory notes. |
| Portable examples | Core examples should run under each backend they claim to support. |
| Unsupported paths | Unsupported backend paths should raise clear backend-named errors. |

When adding a backend-specific restriction, update
`src/pyrecest/_backend/capabilities.py`, the backend API matrix, and a focused
Expand Down
28 changes: 14 additions & 14 deletions docs/public-api-registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,18 @@ mapped to the same implementation module as their canonical form. New examples
and documentation should use the canonical spelling.

<!-- public-api-registry:start -->
| API | Module | Category | Backend contract | Notes |
|-----|--------|----------|------------------|-------|
| `BackendFacade` | `pyrecest.backend` | backend-specific | `BackendFacade` | Facade names are importable across backends, with bridged or unsupported functions documented in the backend matrix. |
| `DistributionConversion` | `pyrecest.distributions.conversion` | backend-specific | `DistributionConversion` | Euclidean Gaussian/particle routes are portable; grid, Fourier, and manifold routes are route-specific. |
| `EuclideanParticleFilter` | `pyrecest.filters` | backend-specific | `EuclideanParticleFilter` | Particle behavior depends on sampler and resampling support in the active backend. |
| `EvaluationUtilities` | `pyrecest.evaluation` | backend-specific | `EvaluationUtilities` | Plotting, assignment, summaries, and result helpers are only partly backend-portable. |
| `GaussianDistribution` | `pyrecest.distributions` | stable | `GaussianDistribution` | Basic construction, moment access, and portable operations are part of the core distribution API. |
| `KalmanFilter` | `pyrecest.filters` | stable | `KalmanFilter` | Linear Gaussian filtering is part of the portable baseline. |
| `LinearDiracDistribution` | `pyrecest.distributions` | stable | `LinearDiracDistribution` | Core particle-style representation used by conversion and filtering workflows. |
| `MultiBernoulliTracker` | `pyrecest.filters` | backend-specific | `MultiBernoulliTracker` | Tracking workflows rely on assignment and measurement-set utilities with NumPy-oriented paths. |
| `PointSetRegistration` | `pyrecest.utils` | backend-specific | `PointSetRegistration` | Registration helpers may bridge through NumPy/SciPy and are not guaranteed differentiable. |
| `SphericalHarmonicsEOTTracker` | `pyrecest.filters` | backend-specific | `SphericalHarmonicsEOTTracker` | Depends on spherical-harmonics and SciPy-adjacent functionality. |
| `UKFOnManifolds` | `pyrecest.filters` | backend-specific | `UKFOnManifolds` | Current predict/update paths explicitly exclude JAX. |
| `UnscentedKalmanFilter` | `pyrecest.filters` | backend-specific | `UnscentedKalmanFilter` | Portable for backend-compatible model functions; advanced paths may bridge through NumPy/SciPy. |
| API | Module | Category | Backend contract | Notes |
|--------------------------------|-------------------------------------|------------------|--------------------------------|----------------------------------------------------------------------------------------------------------------------|
| `BackendFacade` | `pyrecest.backend` | backend-specific | `BackendFacade` | Facade names are importable across backends, with bridged or unsupported functions documented in the backend matrix. |
| `DistributionConversion` | `pyrecest.distributions.conversion` | backend-specific | `DistributionConversion` | Euclidean Gaussian/particle routes are portable; grid, Fourier, and manifold routes are route-specific. |
| `EuclideanParticleFilter` | `pyrecest.filters` | backend-specific | `EuclideanParticleFilter` | Particle behavior depends on sampler and resampling support in the active backend. |
| `EvaluationUtilities` | `pyrecest.evaluation` | backend-specific | `EvaluationUtilities` | Plotting, assignment, summaries, and result helpers are only partly backend-portable. |
| `GaussianDistribution` | `pyrecest.distributions` | stable | `GaussianDistribution` | Basic construction, moment access, and portable operations are part of the core distribution API. |
| `KalmanFilter` | `pyrecest.filters` | stable | `KalmanFilter` | Linear Gaussian filtering is part of the portable baseline. |
| `LinearDiracDistribution` | `pyrecest.distributions` | stable | `LinearDiracDistribution` | Core particle-style representation used by conversion and filtering workflows. |
| `MultiBernoulliTracker` | `pyrecest.filters` | backend-specific | `MultiBernoulliTracker` | Tracking workflows rely on assignment and measurement-set utilities with NumPy-oriented paths. |
| `PointSetRegistration` | `pyrecest.utils` | backend-specific | `PointSetRegistration` | Registration helpers may bridge through NumPy/SciPy and are not guaranteed differentiable. |
| `SphericalHarmonicsEOTTracker` | `pyrecest.filters` | backend-specific | `SphericalHarmonicsEOTTracker` | Depends on spherical-harmonics and SciPy-adjacent functionality. |
| `UKFOnManifolds` | `pyrecest.filters` | backend-specific | `UKFOnManifolds` | Current predict/update paths explicitly exclude JAX. |
| `UnscentedKalmanFilter` | `pyrecest.filters` | backend-specific | `UnscentedKalmanFilter` | Portable for backend-compatible model functions; advanced paths may bridge through NumPy/SciPy. |
<!-- public-api-registry:end -->
16 changes: 8 additions & 8 deletions docs/quality-gates.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ should be safe to require on every pull request.

Recommended required checks for protected branches are:

| Check | Purpose |
|-------|---------|
| `Static analysis` | Runs the static baseline, compile checks, and generated-doc checks. |
| `Test workflow / docs` | Builds documentation with `mkdocs build --strict`. |
| `Test workflow / package` | Builds distributions, installs the wheel, and runs smoke examples. |
| `Test workflow / test` | Runs the backend matrix for NumPy, PyTorch, and JAX. |
| `CodeQL` | Scans the Python codebase for security issues. |
| `Dependency review` | Fails pull requests that introduce high-severity dependency advisories. |
| Check | Purpose |
|---------------------------|-------------------------------------------------------------------------|
| `Static analysis` | Runs the static baseline, compile checks, and generated-doc checks. |
| `Test workflow / docs` | Builds documentation with `mkdocs build --strict`. |
| `Test workflow / package` | Builds distributions, installs the wheel, and runs smoke examples. |
| `Test workflow / test` | Runs the backend matrix for NumPy, PyTorch, and JAX. |
| `CodeQL` | Scans the Python codebase for security issues. |
| `Dependency review` | Fails pull requests that introduce high-severity dependency advisories. |

Scheduled jobs may run larger or slower matrices, but the required checks should
remain small enough that contributors can iterate quickly.
Expand Down
32 changes: 16 additions & 16 deletions docs/scientific-validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,25 @@ intentionally deterministic and has a documented golden output.

## Validation Layers

| Layer | Purpose | Examples |
|-------|---------|----------|
| API smoke tests | Confirm public entry points exist and have stable capabilities. | Protocol capability matrices, import checks, CLI smoke tests. |
| Deterministic algebraic checks | Verify identities that should hold without randomness. | Gaussian multiplication, Kalman covariance symmetry, normalized innovation squared consistency. |
| Numerical invariant checks | Catch invalid estimates even when exact values are not known. | Positive semidefinite covariances, nonnegative probabilities, normalized weights, unit-norm directional states. |
| Monte Carlo checks | Verify statistical behavior across repeated randomized runs. | NEES/NIS coverage, sampling moment convergence, resampling effective sample size behavior. |
| Scenario regression checks | Preserve known behavior for complete workflows. | Scenario zoo expected outputs, benchmark regressions, tracker association edge cases. |
| Layer | Purpose | Examples |
|--------------------------------|-----------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------|
| API smoke tests | Confirm public entry points exist and have stable capabilities. | Protocol capability matrices, import checks, CLI smoke tests. |
| Deterministic algebraic checks | Verify identities that should hold without randomness. | Gaussian multiplication, Kalman covariance symmetry, normalized innovation squared consistency. |
| Numerical invariant checks | Catch invalid estimates even when exact values are not known. | Positive semidefinite covariances, nonnegative probabilities, normalized weights, unit-norm directional states. |
| Monte Carlo checks | Verify statistical behavior across repeated randomized runs. | NEES/NIS coverage, sampling moment convergence, resampling effective sample size behavior. |
| Scenario regression checks | Preserve known behavior for complete workflows. | Scenario zoo expected outputs, benchmark regressions, tracker association edge cases. |

## Core Invariants

| Component | Invariant |
|-----------|-----------|
| Probability distributions | Densities integrate or sum to one on their manifold. |
| Circular and toroidal distributions | Wrapping by the period preserves density. |
| Hyperspherical distributions | Samples and support points remain unit norm. |
| Gaussian filters | Covariances stay symmetric positive definite after updates. |
| Particle filters | Weights remain finite, non-negative, and normalized after resampling. |
| Representation conversion | Moment-matching routes preserve mean/covariance within tolerance. |
| Trackers | Cardinality, association, and gating diagnostics remain internally consistent. |
| Component | Invariant |
|-------------------------------------|--------------------------------------------------------------------------------|
| Probability distributions | Densities integrate or sum to one on their manifold. |
| Circular and toroidal distributions | Wrapping by the period preserves density. |
| Hyperspherical distributions | Samples and support points remain unit norm. |
| Gaussian filters | Covariances stay symmetric positive definite after updates. |
| Particle filters | Weights remain finite, non-negative, and normalized after resampling. |
| Representation conversion | Moment-matching routes preserve mean/covariance within tolerance. |
| Trackers | Cardinality, association, and gating diagnostics remain internally consistent. |

When a change affects a Kalman-style Gaussian estimator, check at least:

Expand Down
14 changes: 7 additions & 7 deletions docs/tutorials/backend-portable-workflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@ unless the API is intentionally backend-specific.
Backend differences usually appear first as shape, dtype, or scalar-conversion
issues. Prefer explicit one-dimensional vectors and two-dimensional matrices:

| Quantity | Recommended shape |
|----------|-------------------|
| State mean | `(n,)` |
| State covariance | `(n, n)` |
| Measurement vector | `(m,)` |
| Measurement matrix | `(m, n)` |
| Measurement covariance | `(m, m)` |
| Quantity | Recommended shape |
|------------------------|-------------------|
| State mean | `(n,)` |
| State covariance | `(n, n)` |
| Measurement vector | `(m,)` |
| Measurement matrix | `(m, n)` |
| Measurement covariance | `(m, m)` |

For a one-dimensional measurement, use `array([z])` rather than a scalar and
`array([[r]])` rather than `array([r])`.
Expand Down
11 changes: 8 additions & 3 deletions scripts/audit_install_footprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ def _dependency_name(raw_name: str) -> str:

def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("pyproject", nargs="?", type=Path, default=Path("pyproject.toml"))
parser.add_argument(
"pyproject", nargs="?", type=Path, default=Path("pyproject.toml")
)
parser.add_argument(
"--fail-on-heavy-defaults",
action="store_true",
Expand All @@ -42,7 +44,9 @@ def main() -> int:

print("Default dependencies:")
for name in sorted(default_names):
note = HEAVY_DEFAULT_DEPENDENCIES.get(name.replace("-", "_")) or HEAVY_DEFAULT_DEPENDENCIES.get(name)
note = HEAVY_DEFAULT_DEPENDENCIES.get(
name.replace("-", "_")
) or HEAVY_DEFAULT_DEPENDENCIES.get(name)
suffix = f" # candidate extra: {note}" if note else ""
print(f"- {name}{suffix}")

Expand All @@ -58,7 +62,8 @@ def main() -> int:
)
if heavy_defaults and args.fail_on_heavy_defaults:
print(
"Heavy dependencies remain in the default install: " + ", ".join(heavy_defaults),
"Heavy dependencies remain in the default install: "
+ ", ".join(heavy_defaults),
file=sys.stderr,
)
return 1
Expand Down
Loading
Loading