Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Migrating from 1.4

1.5.0 changes the public API. Code written against 1.4.0 will not compile until you make the edits below. Full detail in the changelog.

1. PriorFactor is a tangent-space anchor

PriorFactor now anchors in the manifold’s tangent space, , and is generic over the manifold — no quaternion double-cover ambiguity, no dropped rotation–translation coupling, correct SE(2) angle wrap. The old ambient parameter-space factor is renamed EuclideanPriorFactor and is restricted to Rn variables at registration (anything else returns a DimensionMismatch error). Struct-literal construction is gone:

#![allow(unused)]
fn main() {
// 1.4.0 — ambient
problem.add_residual_block(&[k], Box::new(PriorFactor { data: pose7 }), loss);

// 1.5.0 — tangent anchor on SE(3)
problem.add_residual_block(&[k], Box::new(PriorFactor::<SE3>::new(prior_pose)), loss);
}

For the old behaviour on an Rn variable, use EuclideanPriorFactor::new(data).

2. Feature flags: rosbag, download, cli

apex-io’s rosbag feature is now opt-in (it was built unconditionally). Depending on apex-io no longer compiles rusqlite (bundled SQLite), mcap, zstd, lz4_flex, serde_norway, byteorder, hex. Bag I/O users must opt in:

apex-io = { version = "0.4", features = ["rosbag"] }
# via the solver crate:
apex-solver = { version = "1.5", features = ["rosbag"] }

download (dataset fetching) stays on by default; --no-default-features disables it, in which case the ensure_*_dataset helpers only serve already-downloaded files. clap is behind the default-on cli feature in both crates; the apex-solver bins/examples likewise require cli. The bag_* binaries need --features rosbag, download_datasets needs --features download.

3. LinearSolver::solve_augmented_equation takes &Damping

The augmented system is now with — Ceres’ LevenbergMarquardtStrategy. Custom LinearSolver implementations must update the signature:

#![allow(unused)]
fn main() {
// 1.4.0
solver.solve_augmented_equation(&residuals, &jacobian, lambda)?;

// 1.5.0 — same numerics as the old uniform λI
solver.solve_augmented_equation(&residuals, &jacobian, &Damping::identity(lambda))?;
}

4. Schur solver renames

The Schur solvers were consolidated around explicit/implicit names mirroring Ceres. Old names are gone outright — no deprecated aliases:

1.4.01.5.0
SparseSchurComplementSolverExplicitSparseSchur
IterativeSchurSolverImplicitSparseSchur
—ExplicitDenseSchur (new)
SchurVariantExplicitSchurVariant (Sparse, Iterative, Chunked)
LinearSolverType::SparseSchurComplementLinearSolverType::ExplicitSparseSchur

SchurPartition, EliminatedBlocks, SchurOrdering and SchurPreconditioner moved to the top-level src/linalg/schur/ module (previously under src/linalg/sparse/). LinearSolverType gained ImplicitSparseSchur and ExplicitDenseSchur discriminants; the old SchurVariant::Iterative special-case is gone.

5. for_bundle_adjustment selects ImplicitSparseSchur

LevenbergMarquardtConfig::for_bundle_adjustment now selects the matrix-free implicit Schur solver instead of ExplicitSparseSchur — 2.2× faster across the four BAL datasets. The step is inexact by construction; restore the exact reduced solve with:

#![allow(unused)]
fn main() {
config.with_linear_solver_type(LinearSolverType::ExplicitSparseSchur)
}

Numerics changed everywhere else too: Levenberg-Marquardt now damps with from (was from ), and step acceptance in both LM and Dog Leg is gated on min_relative_decrease. Iterates change on every problem. To restore the old behaviour:

#![allow(unused)]
fn main() {
LevenbergMarquardtConfig::new().with_diagonal_bounds(1.0, 1.0).with_damping(1e-3)
}