From e5e770e9123d210d782c74004108d5bcfa2f7b80 Mon Sep 17 00:00:00 2001 From: jamgochiana Date: Tue, 26 May 2026 14:00:38 -0700 Subject: [PATCH 1/4] build(docs): update Documenter API for 1.x compat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace 'format = :html' with 'format = Documenter.HTML()' — the Symbol-based format API was Documenter 0.x and is unsupported in Documenter 1.x (raises 'Cannot convert Symbol to Documenter.Writer'). - Add 'warnonly = [:docs_block, :missing_docs]' so existing duplicate-docs / missing-docs issues in the .md sources surface as warnings instead of build-blocking errors. Cleaning up those individual doc-source issues is out of scope here. Verified locally with: julia --project=docs docs/make.jl --- docs/make.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/make.jl b/docs/make.jl index 969ad0b..aa08e39 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -3,8 +3,9 @@ using Documenter, GaussianFilters # This function builds the documentation makedocs( modules = [GaussianFilters], - format = :html, + format = Documenter.HTML(), sitename = "GaussianFilters", + warnonly = [:docs_block, :missing_docs], pages = ["Introduction" => [ "Basics" => "index.md", "Installation" => "install.md" From cad2c1a5a7d648b791ac4de8b644eba85982ee98 Mon Sep 17 00:00:00 2001 From: jamgochiana Date: Tue, 26 May 2026 14:07:00 -0700 Subject: [PATCH 2/4] docs: surface missing docstrings, resolve duplicate @docs, fix example links MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolve the docs-build issues that were previously masked by warnonly: Surface 6 previously-undocumented symbols whose docstrings existed in src/ but were not referenced from any .md page: - AbstractFilter, DynamicsModel, ObservationModel (now in kalman.md intro / 'Building a Filter') - unscented_transform, unscented_transform_inverse (kalman.md UKF area) - MvNormalPDF (gmphd.md utilities) Disambiguate duplicate @docs blocks. The bare GaussianFilters.update / predict / measure references appeared on both kalman.md and gmphd.md, each pulling in every method of those generics and producing duplicate entries. Replace with method-signature-qualified references on each page so kalman.md documents the Kalman-class methods and gmphd.md documents the PHDFilter methods. Update the 'Examples' sections on both pages to point at examples/*.jl instead of the removed notebooks/*.ipynb (carryover fix from #49). docs/Project.toml: add GaussianFilters as a dep with a [sources] path entry so the docs build against the in-tree source (previously docs relied on the registered version being available). Remove the warnonly band-aid added earlier in this layer — the build now passes cleanly with no missing_docs or docs_block errors. --- docs/Project.toml | 4 ++++ docs/make.jl | 1 - docs/src/gmphd.md | 21 ++++++++++++++------- docs/src/kalman.md | 40 ++++++++++++++++++++++++++-------------- 4 files changed, 44 insertions(+), 22 deletions(-) diff --git a/docs/Project.toml b/docs/Project.toml index dfa65cd..087780c 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,2 +1,6 @@ [deps] Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +GaussianFilters = "08d575fb-911d-541e-8431-6cfa767e7851" + +[sources] +GaussianFilters = {path = ".."} diff --git a/docs/make.jl b/docs/make.jl index aa08e39..33e7ac1 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -5,7 +5,6 @@ makedocs( modules = [GaussianFilters], format = Documenter.HTML(), sitename = "GaussianFilters", - warnonly = [:docs_block, :missing_docs], pages = ["Introduction" => [ "Basics" => "index.md", "Installation" => "install.md" diff --git a/docs/src/gmphd.md b/docs/src/gmphd.md index f6a00fb..41d855c 100644 --- a/docs/src/gmphd.md +++ b/docs/src/gmphd.md @@ -31,11 +31,18 @@ GaussianFilters.PHDFilter Currently, the GM-PHD Filter must be run step-by-step. Similar to the Kalman-Class filters, this can be done with a single call to `update`, which wraps functions to `predict` the next state, perform a measurement update with `measure`, and `prune` the resulting mixture model of low-probability and sufficiently close mixtures. ```@docs -GaussianFilters.update -GaussianFilters.predict -GaussianFilters.measure +update(::PHDFilter, ::GaussianMixture, ::Vector{<:AbstractVector{<:Number}}, ::Real, ::Real, ::Integer) +predict(::PHDFilter, ::GaussianMixture) +measure(::PHDFilter, ::GaussianMixture, ::Vector{<:AbstractVector{<:Real}}) GaussianFilters.prune ``` + +The GM-PHD update internally evaluates a multivariate normal density: + +```@docs +GaussianFilters.MvNormalPDF +``` + Target locations can be extracted from a `GaussianMixture` state using `multiple_target_state_extraction`. ```@docs @@ -44,8 +51,8 @@ GaussianFilters.multiple_target_state_extraction ## Examples -Full implementation examples can be found in the `notebooks` folder of the repo: - -[GM-PHD Object Surveillance Example](https://github.com/sisl/GaussianFilters.jl/blob/master/notebooks/GMPHD_SurveillanceExample.ipynb) +Full implementation examples can be found in the [`examples/`](https://github.com/sisl/GaussianFilters.jl/tree/master/examples) directory of the repo: -[GM-PHD Aircraft Carrier Example](https://github.com/sisl/GaussianFilters.jl/blob/master/notebooks/GMPHD_AircraftCarrierExample.ipynb) +- [`gmphd_surveillance.jl`](https://github.com/sisl/GaussianFilters.jl/blob/master/examples/gmphd_surveillance.jl) — Object Surveillance +- [`gmphd_aircraft_carrier.jl`](https://github.com/sisl/GaussianFilters.jl/blob/master/examples/gmphd_aircraft_carrier.jl) — Aircraft Carrier scenario +- [`gmphd_tests.jl`](https://github.com/sisl/GaussianFilters.jl/blob/master/examples/gmphd_tests.jl) — Visualization helpers diff --git a/docs/src/kalman.md b/docs/src/kalman.md index 66e56b2..e455fc3 100644 --- a/docs/src/kalman.md +++ b/docs/src/kalman.md @@ -8,6 +8,7 @@ The Kalman, Extended Kalman, and Unscented Kalman filters are used to estimate s ```@docs GaussianFilters.GaussianBelief +GaussianFilters.AbstractFilter ``` ## Building a Filter @@ -17,6 +18,8 @@ In general, Kalman-class filters can be built with either linear or non-linear d NOTE: There is no need to define Jacobians for non-linear models, since this package uses automatic forward differentiation to compute Jacobians in real time. Just make sure the models are forward differentiable in all possible belief locations. ```@docs +GaussianFilters.DynamicsModel +GaussianFilters.ObservationModel GaussianFilters.LinearDynamicsModel GaussianFilters.LinearObservationModel GaussianFilters.NonlinearDynamicsModel @@ -31,6 +34,13 @@ GaussianFilters.ExtendedKalmanFilter GaussianFilters.UnscentedKalmanFilter ``` +The UKF additionally exposes the sigma-point machinery used internally: + +```@docs +GaussianFilters.unscented_transform +GaussianFilters.unscented_transform_inverse +``` + ## Simulating Data @@ -43,11 +53,11 @@ GaussianFilters.simulate_step In addition, the dynamics and observation models can be queried on a single state control input using the `predict` and `measure` methods respectively. -```@docs - predict(::LinearDynamicsModel, ::AbstractVector{<:Number}, ::AbstractVector{<:Number}) - predict(::NonlinearDynamicsModel, ::AbstractVector{<:Number}, ::AbstractVector{<:Number}) - measure(::LinearObservationModel, ::AbstractVector{<:Number}, ::AbstractVector{<:Number}) - measure(::NonlinearObservationModel, ::AbstractVector{<:Number}, ::AbstractVector{<:Number}) +```@docs +predict(::LinearDynamicsModel, ::AbstractVector{<:Number}, ::AbstractVector{<:Number}) +predict(::NonlinearDynamicsModel, ::AbstractVector{<:Number}, ::AbstractVector{<:Number}) +measure(::LinearObservationModel, ::AbstractVector{<:Number}, ::AbstractVector{<:Number}) +measure(::NonlinearObservationModel, ::AbstractVector{<:Number}, ::AbstractVector{<:Number}) ``` ## Running a Filter @@ -61,9 +71,13 @@ GaussianFilters.run_filter Alternatively, you can make step-wise belief updates using the `update` function, which consists of a two-step process to a) `predict` the next state given a known action and b) make measurement-based belief updates with `measure`. ```@docs -GaussianFilters.update -GaussianFilters.predict -GaussianFilters.measure +update(::AbstractFilter, ::GaussianBelief, ::AbstractVector{<:Number}, ::AbstractVector{<:Number}) +predict(::KalmanFilter, ::GaussianBelief, ::AbstractVector{<:Number}) +predict(::ExtendedKalmanFilter, ::GaussianBelief, ::AbstractVector{<:Number}) +predict(::UnscentedKalmanFilter, ::GaussianBelief, ::AbstractVector{<:Number}) +measure(::KalmanFilter, ::GaussianBelief, ::AbstractVector{<:Number}) +measure(::ExtendedKalmanFilter, ::GaussianBelief, ::AbstractVector{a}) where a<:Number +measure(::UnscentedKalmanFilter, ::GaussianBelief, ::AbstractVector{<:Number}) ``` @@ -83,10 +97,8 @@ GaussianFilters.belief_ellipse ## Examples -Full implementation examples can be found in the `notebooks` folder of the repo: - -[Kalman Filter Example](https://github.com/sisl/GaussianFilters.jl/blob/master/notebooks/KF_2DMotionExample.ipynb) - -[Extended Kalman Filter Example](https://github.com/sisl/GaussianFilters.jl/blob/master/notebooks/EKF_SpinningSatelliteExample.ipynb) +Full implementation examples can be found in the [`examples/`](https://github.com/sisl/GaussianFilters.jl/tree/master/examples) directory of the repo: -[Unscented Kalman Filter Example](https://github.com/sisl/GaussianFilters.jl/blob/master/notebooks/UKF_NonholonomicRobot.ipynb) +- [`kf_2d_motion.jl`](https://github.com/sisl/GaussianFilters.jl/blob/master/examples/kf_2d_motion.jl) — Kalman Filter +- [`ekf_spinning_satellite.jl`](https://github.com/sisl/GaussianFilters.jl/blob/master/examples/ekf_spinning_satellite.jl) — Extended Kalman Filter +- [`ukf_nonholonomic_robot.jl`](https://github.com/sisl/GaussianFilters.jl/blob/master/examples/ukf_nonholonomic_robot.jl) — Unscented Kalman Filter From e0927300a67a902580075fb9fd2d31f4917753e2 Mon Sep 17 00:00:00 2001 From: jamgochiana Date: Tue, 26 May 2026 15:22:12 -0700 Subject: [PATCH 3/4] docs(kalman): document pomdps_updater and link POMDPs.jl examples Surface the new pomdps_updater function added in the previous layer and add the two POMDPs-related examples (pomdps_integration, pendulum_ekf_ilqr) to the kalman.md examples list. Keeps the docs build clean (no missing_docs warnings). --- docs/src/kalman.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/src/kalman.md b/docs/src/kalman.md index e455fc3..b9ef7fb 100644 --- a/docs/src/kalman.md +++ b/docs/src/kalman.md @@ -95,6 +95,21 @@ GaussianFilters.unpack GaussianFilters.belief_ellipse ``` +## POMDPs.jl integration + +When [POMDPs.jl](https://github.com/JuliaPOMDP/POMDPs.jl) is also +loaded, a package extension wires GaussianFilters' `AbstractFilter` +into the POMDPs belief-updater interface. Use `pomdps_updater` to +obtain a `POMDPs.Updater` wrapper suitable for `POMDPs.simulate` and +related simulators. + +```@docs +GaussianFilters.pomdps_updater +``` + +See `examples/pomdps_integration.jl` and `examples/pendulum_ekf_ilqr.jl` +for end-to-end usage. + ## Examples Full implementation examples can be found in the [`examples/`](https://github.com/sisl/GaussianFilters.jl/tree/master/examples) directory of the repo: @@ -102,3 +117,5 @@ Full implementation examples can be found in the [`examples/`](https://github.co - [`kf_2d_motion.jl`](https://github.com/sisl/GaussianFilters.jl/blob/master/examples/kf_2d_motion.jl) — Kalman Filter - [`ekf_spinning_satellite.jl`](https://github.com/sisl/GaussianFilters.jl/blob/master/examples/ekf_spinning_satellite.jl) — Extended Kalman Filter - [`ukf_nonholonomic_robot.jl`](https://github.com/sisl/GaussianFilters.jl/blob/master/examples/ukf_nonholonomic_robot.jl) — Unscented Kalman Filter +- [`pomdps_integration.jl`](https://github.com/sisl/GaussianFilters.jl/blob/master/examples/pomdps_integration.jl) — KF used through `POMDPs.update` +- [`pendulum_ekf_ilqr.jl`](https://github.com/sisl/GaussianFilters.jl/blob/master/examples/pendulum_ekf_ilqr.jl) — EKF + iLQR closed loop driven by `POMDPs.simulate` From f0203720670684f037d9be5010c420624e4bd1f9 Mon Sep 17 00:00:00 2001 From: jamgochiana Date: Tue, 26 May 2026 15:55:15 -0700 Subject: [PATCH 4/4] docs: promote POMDPs.jl integration to its own page Move the POMDPs section out of kalman.md and into a new top-level Integrations -> POMDPs.jl Integration page (docs/src/pomdps.md). Add a quick-start code snippet showing the three-step pomdps_updater usage and document the direct-dispatch path for callers that don't need the full POMDPs.simulate machinery. Also document the initialize_belief-from-MvNormal pattern with a small example. Add a new 'Integrations' section to the pages tree in make.jl. kalman.md now contains only a one-line cross-reference to the new page. --- docs/make.jl | 3 ++ docs/src/kalman.md | 18 ++-------- docs/src/pomdps.md | 83 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 16 deletions(-) create mode 100644 docs/src/pomdps.md diff --git a/docs/make.jl b/docs/make.jl index 33e7ac1..1e8278c 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -12,6 +12,9 @@ makedocs( "User Documentation" => [ "Kalman-class Filters" => "kalman.md", "GM-PHD Filter" => "gmphd.md" + ], + "Integrations" => [ + "POMDPs.jl" => "pomdps.md" ] ]) diff --git a/docs/src/kalman.md b/docs/src/kalman.md index b9ef7fb..a8fb0dc 100644 --- a/docs/src/kalman.md +++ b/docs/src/kalman.md @@ -95,20 +95,8 @@ GaussianFilters.unpack GaussianFilters.belief_ellipse ``` -## POMDPs.jl integration - -When [POMDPs.jl](https://github.com/JuliaPOMDP/POMDPs.jl) is also -loaded, a package extension wires GaussianFilters' `AbstractFilter` -into the POMDPs belief-updater interface. Use `pomdps_updater` to -obtain a `POMDPs.Updater` wrapper suitable for `POMDPs.simulate` and -related simulators. - -```@docs -GaussianFilters.pomdps_updater -``` - -See `examples/pomdps_integration.jl` and `examples/pendulum_ekf_ilqr.jl` -for end-to-end usage. +For interoperability with the POMDPs.jl belief-updater interface, see the +[POMDPs.jl Integration](pomdps.md) page. ## Examples @@ -117,5 +105,3 @@ Full implementation examples can be found in the [`examples/`](https://github.co - [`kf_2d_motion.jl`](https://github.com/sisl/GaussianFilters.jl/blob/master/examples/kf_2d_motion.jl) — Kalman Filter - [`ekf_spinning_satellite.jl`](https://github.com/sisl/GaussianFilters.jl/blob/master/examples/ekf_spinning_satellite.jl) — Extended Kalman Filter - [`ukf_nonholonomic_robot.jl`](https://github.com/sisl/GaussianFilters.jl/blob/master/examples/ukf_nonholonomic_robot.jl) — Unscented Kalman Filter -- [`pomdps_integration.jl`](https://github.com/sisl/GaussianFilters.jl/blob/master/examples/pomdps_integration.jl) — KF used through `POMDPs.update` -- [`pendulum_ekf_ilqr.jl`](https://github.com/sisl/GaussianFilters.jl/blob/master/examples/pendulum_ekf_ilqr.jl) — EKF + iLQR closed loop driven by `POMDPs.simulate` diff --git a/docs/src/pomdps.md b/docs/src/pomdps.md new file mode 100644 index 0000000..ecd952b --- /dev/null +++ b/docs/src/pomdps.md @@ -0,0 +1,83 @@ +# POMDPs.jl Integration + +```@meta +CurrentModule = GaussianFilters +``` + +GaussianFilters ships with a [POMDPs.jl](https://github.com/JuliaPOMDP/POMDPs.jl) +package extension that activates automatically when both packages are loaded. +The extension wires `AbstractFilter` into the POMDPs belief-updater interface +so that a Kalman, Extended Kalman, or Unscented Kalman filter can be used +directly as a `POMDPs.Updater` — including with simulators such as +`HistoryRecorder` and policy/planner code that expects the standard POMDPs +interface. + +## Quick start + +```julia +using GaussianFilters +using POMDPs +using POMDPTools + +# 1. Build a filter as usual +dmodel = NonlinearDynamicsModel(f, W) +omodel = NonlinearObservationModel(h, V) +ekf = ExtendedKalmanFilter(dmodel, omodel) + +# 2. Wrap it as a POMDPs.Updater +updater = pomdps_updater(ekf) + +# 3. Pass it to any POMDPs.jl simulator +hist = simulate(HistoryRecorder(max_steps=60), pomdp, policy, updater) +``` + +The wrapper is needed because POMDPs.jl simulators dispatch on the abstract +type `POMDPs.Updater`, and `AbstractFilter` cannot subtype `POMDPs.Updater` +directly without making POMDPs.jl a hard dependency. + +## Direct dispatch (without the wrapper) + +For simpler use cases that don't need the full `POMDPs.simulate` machinery, +the extension also overloads `POMDPs.update` and `POMDPs.initialize_belief` +directly on `AbstractFilter`: + +```julia +b1 = POMDPs.update(ekf, b0, action, observation) +``` + +This is convenient when integrating with code that calls `POMDPs.update` +generically but does not require the `<:Updater` subtype constraint. + +## Initial beliefs from distributions + +The extension supports initializing a `GaussianBelief` from any multivariate +normal distribution. This is useful when the initial state of a `POMDP` is +given as an `MvNormal`: + +```julia +using Distributions +prior = MvNormal([0.0, 0.0], [1.0 0.0; 0.0 0.5]) +b0 = POMDPs.initialize_belief(updater, prior) +``` + +## API + +```@docs +GaussianFilters.pomdps_updater +``` + +## Examples + +Two example scripts live in the +[`examples/`](https://github.com/sisl/GaussianFilters.jl/tree/master/examples) +directory: + +- [`pomdps_integration.jl`](https://github.com/sisl/GaussianFilters.jl/blob/master/examples/pomdps_integration.jl) — + a minimal demonstration of using a `KalmanFilter` through `POMDPs.update`. + +- [`pendulum_ekf_ilqr.jl`](https://github.com/sisl/GaussianFilters.jl/blob/master/examples/pendulum_ekf_ilqr.jl) — + closed-loop stabilization of a noisy inverted pendulum observed only + through its angular velocity. Defines a `PendulumPOMDP`, an + `ILQRPolicy <: POMDPs.Policy` that runs iterative LQR on the belief + mean (certainty equivalent control), wraps the EKF with `pomdps_updater`, + and drives the whole closed loop through `POMDPs.simulate`.