Add support for maximum matrix sizes to TinySolver.

This change restructures the `TinySolver` template and its associated
adapters (`AutoDiff` and `CostFunction`) to make maximum sizing
attributes first-class parameters. This enables the entire `TinySolver`
stack to be used in restricted environments (e.g., small MCUs) without
dynamic memory allocation, even when the number of residuals or
parameters is only known at runtime (`Eigen::Dynamic`).

Specifically:
- Adds `kMaxResiduals` and `kMaxParameters` template parameters to
  `TinySolver`.
- Updated `TinySolverAutoDiffFunction` and
  `TinySolverCostFunctionAdapter` to support optional maximum size
  template parameters for their internal buffers.
- The new API maintains backward compatibility for existing users by
  defaulting to the sizes defined in the `Function`'s enums.
- This structure also supports reducing code bloat by allowing
  `TinySolver` to be instantiated with an abstract base class, using
  dynamic dispatch for cost function evaluation.

New test cases for `TinySolver` and its adapters verify the
zero-allocation behavior and the unified API flexibility.

Change-Id: Ic6f43984d384dbe71472b31c5ebd2b538d61f19d
This commit is contained in:
Pez Firoozfam
2026-03-23 20:35:24 +00:00
parent 41958f3fcc
commit 806af056fe
6 changed files with 153 additions and 31 deletions
+15 -7
View File
@@ -103,10 +103,8 @@ namespace ceres {
// solver.Solve(f, &x);
//
// WARNING: The cost function adapter is not thread safe.
template <typename CostFunctor,
int kNumResiduals,
int kNumParameters,
typename T = double>
template <typename CostFunctor, int kNumResiduals, int kNumParameters,
typename T = double, int kMaxResiduals = kNumResiduals>
class TinySolverAutoDiffFunction {
public:
// This class needs to have an Eigen aligned operator new as it contains
@@ -118,11 +116,17 @@ class TinySolverAutoDiffFunction {
Initialize<kNumResiduals>(cost_functor);
}
using Scalar = T;
enum {
NUM_PARAMETERS = kNumParameters,
NUM_RESIDUALS = kNumResiduals,
MAX_NUM_RESIDUALS = kMaxResiduals,
};
using Scalar = T;
using JacobianMatrix = typename Eigen::Matrix<Scalar,
NUM_RESIDUALS,
NUM_PARAMETERS,
0,
MAX_NUM_RESIDUALS>;
// This is similar to AutoDifferentiate(), but since there is only one
// parameter block it is easier to inline to avoid overhead.
@@ -151,7 +155,7 @@ class TinySolverAutoDiffFunction {
}
// Copy the jacobian out of the derivative part of the residual jets.
Eigen::Map<Eigen::Matrix<T, kNumResiduals, kNumParameters>> jacobian_matrix(
Eigen::Map<JacobianMatrix> jacobian_matrix(
jacobian, num_residuals_, kNumParameters);
for (int r = 0; r < num_residuals_; ++r) {
residuals[r] = jet_residuals_[r].a;
@@ -179,10 +183,14 @@ class TinySolverAutoDiffFunction {
// and jet_residuals_ are where the final cost and derivatives end up.
//
// Since this buffer is used for evaluation, the adapter is not thread safe.
static_assert(kNumParameters != Eigen::Dynamic);
using JetType = Jet<T, kNumParameters>;
using JetResidualVector =
Eigen::Matrix<JetType, kNumResiduals, 1, 0, kMaxResiduals, 1>;
mutable JetType jet_parameters_[kNumParameters];
// Eigen::Matrix serves as static or dynamic container.
mutable Eigen::Matrix<JetType, kNumResiduals, 1> jet_residuals_;
mutable JetResidualVector jet_residuals_;
template <int R>
void Initialize(const CostFunctor& function) {