pub struct Corrector { /* private fields */ }Expand description
Corrector for applying robust loss functions via residual and Jacobian adjustment.
This struct holds the precomputed scaling factors needed to transform a robust loss problem into an equivalent reweighted least squares problem. It is instantiated once per residual block during each iteration of the optimizer.
§Fields
sqrt_rho1: √(ρ’(s)) - Square root of the first derivative, used for residual scalingresidual_scaling: √(ρ’(s)) - Same as sqrt_rho1, stored separately for clarityalpha_sq_norm: α² = ρ’‘(s) / ρ’(s) - Ratio of second to first derivative, used for Jacobian correction
where s = ||r||² is the squared norm of the residual.
Implementations§
Source§impl Corrector
impl Corrector
Sourcepub fn new(loss_function: &dyn LossFunction, sq_norm: f64) -> Self
pub fn new(loss_function: &dyn LossFunction, sq_norm: f64) -> Self
Create a new Corrector by evaluating the loss function at the given squared norm.
§Arguments
loss_function- The robust loss function ρ(s)sq_norm- The squared norm of the residual:s = ||r||²
§Returns
A Corrector instance with precomputed scaling factors
§Example
use apex_solver::core::corrector::Corrector;
use apex_solver::core::loss_functions::{LossFunction, HuberLoss};
use nalgebra::DVector;
let loss = HuberLoss::new(1.0)?;
let residual = DVector::from_vec(vec![1.0, 2.0, 3.0]);
let squared_norm = residual.dot(&residual); // 14.0
let corrector = Corrector::new(&loss, squared_norm);
// corrector is now ready to apply correctionsSourcepub fn correct_jacobian(
&self,
residual: &DVector<f64>,
jacobian: &mut DMatrix<f64>,
)
pub fn correct_jacobian( &self, residual: &DVector<f64>, jacobian: &mut DMatrix<f64>, )
Apply correction to the Jacobian matrix.
Transforms the Jacobian J into J̃ according to the Ceres Solver corrector algorithm:
J̃ = √(ρ'(s)) · (J - α²·r·r^T·J)where:
√(ρ'(s))scales the Jacobian by the loss function weightαis computed by solving the quadratic equation: 0.5·α² - α - (ρ’‘/ρ’)·s = 0- The subtractive term
α²·r·r^T·Jis a rank-1 curvature correction
§Arguments
residual- The original residual vectorrjacobian- Mutable reference to the Jacobian matrix (modified in-place)
§Implementation Notes
The correction is applied in-place for efficiency. The algorithm:
- Scales all Jacobian entries by
√(ρ'(s)) - Adds the outer product correction:
α · (J^T r) · r^T / ||r||
§Example
use apex_solver::core::corrector::Corrector;
use apex_solver::core::loss_functions::{LossFunction, HuberLoss};
use nalgebra::{DVector, DMatrix};
let loss = HuberLoss::new(1.0)?;
let residual = DVector::from_vec(vec![2.0, 1.0]);
let squared_norm = residual.dot(&residual);
let corrector = Corrector::new(&loss, squared_norm);
let mut jacobian = DMatrix::from_row_slice(2, 3, &[
1.0, 0.0, 1.0,
0.0, 1.0, 1.0,
]);
corrector.correct_jacobian(&residual, &mut jacobian);
// jacobian is now corrected to account for the robust lossSourcepub fn correct_residuals(&self, residual: &mut DVector<f64>)
pub fn correct_residuals(&self, residual: &mut DVector<f64>)
Apply correction to the residual vector.
Transforms the residual r into r̃ by scaling:
r̃ = √(ρ'(s)) · rThis ensures that ||r̃||² ≈ ρ(||r||²), i.e., the squared norm of the corrected
residual approximates the robust cost.
§Arguments
residual- Mutable reference to the residual vector (modified in-place)
§Example
use apex_solver::core::corrector::Corrector;
use apex_solver::core::loss_functions::{LossFunction, HuberLoss};
use nalgebra::DVector;
let loss = HuberLoss::new(1.0)?;
let mut residual = DVector::from_vec(vec![2.0, 3.0, 1.0]);
let squared_norm = residual.dot(&residual);
let corrector = Corrector::new(&loss, squared_norm);
corrector.correct_residuals(&mut residual);
// Outlier residuals are scaled downSourcepub fn correct_residual_in_place(&self, residual: &mut [f64])
pub fn correct_residual_in_place(&self, residual: &mut [f64])
In-place residual correction over a flat slice. Equivalent to
correct_residuals but does not require a DVector wrapper.
Sourcepub fn correct_jacobian_in_place(
&self,
residual: &[f64],
jac: &mut [f64],
rows: usize,
cols: usize,
)
pub fn correct_jacobian_in_place( &self, residual: &[f64], jac: &mut [f64], rows: usize, cols: usize, )
In-place Jacobian correction over a column-major (rows × cols) buffer.
jac.len() == rows * cols, residual.len() == rows. The math is
identical to Corrector::correct_jacobian but operates directly on
flat memory — no DVector/DMatrix allocation or copy.
Formula: J̃ = √ρ₁ · (J − α²·r·rᵀ·J)
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Corrector
impl RefUnwindSafe for Corrector
impl Send for Corrector
impl Sync for Corrector
impl Unpin for Corrector
impl UnsafeUnpin for Corrector
impl UnwindSafe for Corrector
Blanket Implementations§
impl<T> Allocation for T
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CheckedAs for T
impl<T> CheckedAs for T
Source§fn checked_as<Dst>(self) -> Option<Dst>where
T: CheckedCast<Dst>,
fn checked_as<Dst>(self) -> Option<Dst>where
T: CheckedCast<Dst>,
Source§impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere
Src: CheckedCast<Dst>,
impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere
Src: CheckedCast<Dst>,
Source§fn checked_cast_from(src: Src) -> Option<Dst>
fn checked_cast_from(src: Src) -> Option<Dst>
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> DistributionExt for Twhere
T: ?Sized,
impl<T> DistributionExt for Twhere
T: ?Sized,
impl<T, U> Imply<T> for U
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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 moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::RequestSource§impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere
Dst: LosslessTryFrom<Src>,
impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere
Dst: LosslessTryFrom<Src>,
Source§fn lossless_try_into(self) -> Option<Dst>
fn lossless_try_into(self) -> Option<Dst>
Source§impl<Src, Dst> LossyInto<Dst> for Srcwhere
Dst: LossyFrom<Src>,
impl<Src, Dst> LossyInto<Dst> for Srcwhere
Dst: LossyFrom<Src>,
Source§fn lossy_into(self) -> Dst
fn lossy_into(self) -> Dst
Source§impl<T> OverflowingAs for T
impl<T> OverflowingAs for T
Source§fn overflowing_as<Dst>(self) -> (Dst, bool)where
T: OverflowingCast<Dst>,
fn overflowing_as<Dst>(self) -> (Dst, bool)where
T: OverflowingCast<Dst>,
Source§impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere
Src: OverflowingCast<Dst>,
impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere
Src: OverflowingCast<Dst>,
Source§fn overflowing_cast_from(src: Src) -> (Dst, bool)
fn overflowing_cast_from(src: Src) -> (Dst, bool)
Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
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
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
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
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.Source§impl<T> Pointable for T
impl<T> Pointable for T
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T> SaturatingAs for T
impl<T> SaturatingAs for T
Source§fn saturating_as<Dst>(self) -> Dstwhere
T: SaturatingCast<Dst>,
fn saturating_as<Dst>(self) -> Dstwhere
T: SaturatingCast<Dst>,
Source§impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere
Src: SaturatingCast<Dst>,
impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere
Src: SaturatingCast<Dst>,
Source§fn saturating_cast_from(src: Src) -> Dst
fn saturating_cast_from(src: Src) -> Dst
Source§impl<T> StrictAs for T
impl<T> StrictAs for T
Source§fn strict_as<Dst>(self) -> Dstwhere
T: StrictCast<Dst>,
fn strict_as<Dst>(self) -> Dstwhere
T: StrictCast<Dst>,
Source§impl<Src, Dst> StrictCastFrom<Src> for Dstwhere
Src: StrictCast<Dst>,
impl<Src, Dst> StrictCastFrom<Src> for Dstwhere
Src: StrictCast<Dst>,
Source§fn strict_cast_from(src: Src) -> Dst
fn strict_cast_from(src: Src) -> Dst
Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.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
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.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
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.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
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.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
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.