Skip to main content

RerunObserver

Struct RerunObserver 

Source
pub struct RerunObserver { /* private fields */ }
Expand description

Rerun observer for real-time optimization visualization.

This observer logs comprehensive optimization data to Rerun for interactive visualization and debugging. It implements the OptObserver trait, enabling clean integration with any optimizer through the observer pattern.

§What Gets Visualized

  • Time series: Cost, gradient norm, damping (LM), step norm, step quality
  • Matrices: Sparse Hessian (downsampled heat map), gradient vector
  • Poses: SE2/SE3 manifold states updated each iteration
  • 3D Landmarks: Rn variables with dimension=3 visualized as point clouds
  • Status: Convergence information

§Observer Pattern Benefits

  • Decoupled from optimizer internals
  • Can be combined with other observers (CSV, metrics, etc.)
  • No #[cfg(feature = "visualization")] scattered through optimizer code
  • Easy to enable/disable without changing optimizer logic

§Performance

The observer is designed to have minimal overhead:

  • Matrix visualizations use downsampling (100×100 for Hessian)
  • Rerun logging is asynchronous
  • When disabled, is_enabled() returns false immediately
  • 3D landmarks are batch-logged as a single point cloud for efficiency

§Pose Convention Support

For bundle adjustment (BAL datasets), camera poses are stored as world-to-camera transforms (T_wc). Set invert_camera_poses = true to display cameras correctly by converting to camera-to-world (T_cw) convention for Rerun visualization.

Implementations§

Source§

impl RerunObserver

Source

pub fn new(enabled: bool) -> ObserverResult<Self>

Create a new Rerun observer.

§Arguments
  • enabled - Whether to enable visualization
§Returns

A new observer instance that spawns a Rerun viewer (or saves to file if viewer unavailable).

§Examples
use apex_solver::observers::RerunObserver;

let observer = RerunObserver::new(true)?;
Source

pub fn new_with_options( enabled: bool, save_path: Option<&str>, ) -> ObserverResult<Self>

Create a new Rerun observer with file save option.

§Arguments
  • enabled - Whether to enable visualization
  • save_path - Optional path to save recording to file instead of spawning viewer
§Examples
use apex_solver::observers::RerunObserver;

// Save to file
let observer = RerunObserver::new_with_options(true, Some("opt.rrd"))?;

// Spawn live viewer
let observer2 = RerunObserver::new_with_options(true, None)?;
Source

pub fn with_config( enabled: bool, save_path: Option<&str>, config: VisualizationConfig, ) -> ObserverResult<Self>

Create a new Rerun observer with full configuration.

This is the primary constructor for full control over visualization.

§Arguments
  • enabled - Whether to enable visualization
  • save_path - Optional path to save recording to file instead of spawning viewer
  • config - Visualization configuration
§Examples
use apex_solver::observers::{RerunObserver, VisualizationConfig};

let config = VisualizationConfig::new()
    .with_show_cameras(true)
    .with_show_landmarks(false)
    .with_camera_fov(0.8);

let observer = RerunObserver::with_config(true, None, config)?;
Source

pub fn new_for_bundle_adjustment( enabled: bool, save_path: Option<&str>, invert_camera_poses: bool, ) -> ObserverResult<Self>

Create a new Rerun observer configured for bundle adjustment.

This constructor is designed for bundle adjustment / structure-from-motion problems where camera poses are stored in world-to-camera convention (T_wc) but need to be displayed in camera-to-world convention (T_cw).

§Arguments
  • enabled - Whether to enable visualization
  • save_path - Optional path to save recording to file instead of spawning viewer
  • invert_camera_poses - If true, invert SE3 poses before logging (T_wc -> T_cw)
§Use Cases
  • Pose graph optimization: Use invert_camera_poses = false (poses are already T_cw)
  • Bundle adjustment (BAL): Use invert_camera_poses = true (BAL stores T_wc)
§Examples
use apex_solver::observers::RerunObserver;

// For bundle adjustment with BAL datasets (world-to-camera poses)
let observer = RerunObserver::new_for_bundle_adjustment(true, None, true)?;

// For pose graph optimization (camera-to-world poses)
let observer = RerunObserver::new_for_bundle_adjustment(true, None, false)?;
Source

pub fn config(&self) -> &VisualizationConfig

Get the current visualization configuration.

Source

pub fn is_enabled(&self) -> bool

Check if visualization is enabled and active.

Source

pub fn set_iteration_metrics( &self, cost: f64, gradient_norm: f64, damping: Option<f64>, step_norm: f64, step_quality: Option<f64>, )

Set iteration metrics for the next on_step call.

This method should be called by optimizers before notifying observers to provide context like cost, gradient norm, damping, etc.

§Arguments
  • cost - Current cost value
  • gradient_norm - L2 norm of gradient
  • damping - Current damping parameter (LM-specific, use None for GN/DogLeg)
  • step_norm - L2 norm of parameter update
  • step_quality - Step quality metric ρ (actual vs predicted reduction)
§Examples
observer.set_iteration_metrics(
    1.234,      // cost
    0.056,      // gradient_norm
    Some(0.01), // damping (LM only)
    0.023,      // step_norm
    Some(0.95), // step_quality
);
Source

pub fn set_matrix_data( &self, hessian: Option<SparseColMat<usize, f64>>, gradient: Option<Mat<f64>>, )

Set matrix data (Hessian and gradient) for visualization.

This should be called before on_step if you want to visualize matrices.

§Arguments
  • hessian - Optional sparse Hessian matrix (J^T J)
  • gradient - Optional gradient vector (J^T r)
Source

pub fn log_initial_graph(&self, graph: &Graph, scale: f32) -> ObserverResult<()>

Log the initial graph structure before optimization.

This should be called once before optimization starts to visualize the initial configuration.

§Arguments
  • graph - The graph structure loaded from G2O file
  • scale - Scale factor for visualization
Source

pub fn log_convergence(&self, status: &str) -> ObserverResult<()>

Log convergence status and final summary.

Call this after optimization completes.

§Arguments
  • status - Convergence status message
Source

pub fn log_initial_ba_state(&self, problem: &Problem) -> ObserverResult<()>

Log initial bundle adjustment state before optimization.

This method visualizes the initial camera poses and 3D landmarks before optimization begins, allowing comparison with optimized results.

§Arguments
  • problem - The optimization problem containing the initial variables
§Examples
use apex_solver::observers::RerunObserver;
use apex_solver::core::problem::Problem;

let observer = RerunObserver::new_for_bundle_adjustment(true, None, true)?;
let mut problem = Problem::new(apex_solver::linalg::JacobianMode::Sparse);
// ... add variables and factors ...

observer.log_initial_ba_state(&problem)?;

Trait Implementations§

Source§

impl Default for RerunObserver

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl OptObserver for RerunObserver

Source§

fn on_step( &self, values: &SlotMap<VarKey, Box<dyn ManifoldVariable>>, iteration: usize, )

Called at each optimization iteration.

This logs all visualization data to Rerun, including:

  • Time series plots (cost, gradient, damping, step quality)
  • Matrix visualizations (Hessian, gradient) if set via set_matrix_data
  • Manifold states (SE2/SE3 poses)

In InitialAndFinal mode, this method only logs scalar metrics (plots) during intermediate iterations. The full manifold state is logged at iteration 0 (initial) and in on_optimization_complete (final).

§Arguments
  • values - Current variable values (manifold states)
  • iteration - Current iteration number
Source§

fn on_optimization_complete( &self, values: &SlotMap<VarKey, Box<dyn ManifoldVariable>>, iterations: usize, )

Called when optimization completes.

In InitialAndFinal mode, this logs the final optimized state. In Iterative mode, the final state was already logged via on_step.

§Arguments
  • values - Final optimized variable values
  • iterations - Total number of iterations performed
Source§

fn set_iteration_metrics( &self, _cost: f64, _gradient_norm: f64, _damping: Option<f64>, _step_norm: f64, _step_quality: Option<f64>, )

Set iteration metrics for visualization and monitoring. Read more
Source§

fn set_matrix_data( &self, _hessian: Option<SparseColMat<usize, f64>>, _gradient: Option<Mat<f64>>, )

Set matrix data for advanced visualization. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Az for T

Source§

fn az<Dst>(self) -> Dst
where T: Cast<Dst>,

Casts the value.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> ByRef<T> for T

Source§

fn by_ref(&self) -> &T

Source§

impl<Src, Dst> CastFrom<Src> for Dst
where Src: Cast<Dst>,

Source§

fn cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CheckedAs for T

Source§

fn checked_as<Dst>(self) -> Option<Dst>
where T: CheckedCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> CheckedCastFrom<Src> for Dst
where Src: CheckedCast<Dst>,

Source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
Source§

impl<T> Conv for T

Source§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
Source§

impl<T> DistributionExt for T
where T: ?Sized,

Source§

fn rand<T>(&self, rng: &mut (impl Rng + ?Sized)) -> T
where Self: Distribution<T>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Imply<T> for U
where T: ?Sized, U: ?Sized,

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

impl<Src, Dst> LosslessTryInto<Dst> for Src
where Dst: LosslessTryFrom<Src>,

Source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
Source§

impl<Src, Dst> LossyInto<Dst> for Src
where Dst: LossyFrom<Src>,

Source§

fn lossy_into(self) -> Dst

Performs the conversion.
Source§

impl<T> OverflowingAs for T

Source§

fn overflowing_as<Dst>(self) -> (Dst, bool)
where T: OverflowingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dst
where Src: OverflowingCast<Dst>,

Source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
Source§

impl<T> Pipe for T
where T: ?Sized,

Source§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
Source§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> R
where R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
Source§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
Source§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows self, then passes self.as_ref() into the pipe function.
Source§

fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.as_mut() into the pipe function.
Source§

fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
Source§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<R, P> ReadPrimitive<R> for P
where R: Read + ReadEndian<P>, P: Default,

Source§

fn read_from_little_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_little_endian().
Source§

fn read_from_big_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_big_endian().
Source§

fn read_from_native_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_native_endian().
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> SaturatingAs for T

Source§

fn saturating_as<Dst>(self) -> Dst
where T: SaturatingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dst
where Src: SaturatingCast<Dst>,

Source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<T> StrictAs for T

Source§

fn strict_as<Dst>(self) -> Dst
where T: StrictCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> StrictCastFrom<Src> for Dst
where Src: StrictCast<Dst>,

Source§

fn strict_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

Source§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
Source§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
Source§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
Source§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
Source§

impl<T> Tap for T

Source§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
Source§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
Source§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
Source§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
Source§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
Source§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
Source§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
Source§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
Source§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
Source§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .tap_borrow() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Calls .tap_ref() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
Source§

impl<T> TryConv for T

Source§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> UnwrappedAs for T

Source§

fn unwrapped_as<Dst>(self) -> Dst
where T: UnwrappedCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dst
where Src: UnwrappedCast<Dst>,

Source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> WrappingAs for T

Source§

fn wrapping_as<Dst>(self) -> Dst
where T: WrappingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> WrappingCastFrom<Src> for Dst
where Src: WrappingCast<Dst>,

Source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.