Add support for removing parameter and residual blocks.
This adds support for removing parameter and residual blocks.
There are two modes of operation: in the first, removals of
paremeter blocks are expensive, since each remove requires
scanning all residual blocks to find ones that depend on the
removed parameter. In the other, extra memory is sacrificed to
maintain a list of the residuals a parameter block depends on,
removing the need to scan. In both cases, removing residual blocks
is fast.
As a caveat, any removals destroys the ordering of the parameters,
so the residuals or jacobian returned from Solver::Solve() is
meaningless. There is some debate on the best way to handle this;
the details remain for a future change.
This also adds some overhead, even in the case that fast removals
are not requested:
- 1 int32 to each residual, to track its position in the program.
- 1 pointer to each parameter, to store the dependent residuals.
Change-Id: I71dcac8656679329a15ee7fc12c0df07030c12af
diff --git a/include/ceres/problem.h b/include/ceres/problem.h
index a8645c6..f0ed1b0 100644
--- a/include/ceres/problem.h
+++ b/include/ceres/problem.h
@@ -59,10 +59,9 @@
class ResidualBlock;
} // namespace internal
-// A ResidualBlockId is a handle clients can use to delete residual
-// blocks after creating them. They are opaque for any purposes other
-// than that.
-typedef const internal::ResidualBlock* ResidualBlockId;
+// A ResidualBlockId is an opaque handle clients can use to remove residual
+// blocks from a Problem after adding them.
+typedef internal::ResidualBlock* ResidualBlockId;
// A class to represent non-linear least squares problems. Such
// problems have a cost function that is a sum of error terms (known
@@ -123,6 +122,7 @@
: cost_function_ownership(TAKE_OWNERSHIP),
loss_function_ownership(TAKE_OWNERSHIP),
local_parameterization_ownership(TAKE_OWNERSHIP),
+ enable_fast_parameter_block_removal(false),
disable_all_safety_checks(false) {}
// These flags control whether the Problem object owns the cost
@@ -136,15 +136,26 @@
Ownership loss_function_ownership;
Ownership local_parameterization_ownership;
- // By default, Ceres performs a variety of safety checks when
- // constructing the problem. There is a small but measurable
- // performance penalty to these checks ~5%. If you are sure of
- // your problem construction, and 5% of the problem construction
+ // If true, trades memory for a faster RemoveParameterBlock() operation.
+ //
+ // RemoveParameterBlock() takes time proportional to the size of the entire
+ // Problem. If you only remove parameter blocks from the Problem
+ // occassionaly, this may be acceptable. However, if you are modifying the
+ // Problem frequently, and have memory to spare, then flip this switch to
+ // make RemoveParameterBlock() take time proportional to the number of
+ // residual blocks that depend on it. The increase in memory usage is an
+ // additonal hash set per parameter block containing all the residuals that
+ // depend on the parameter block.
+ bool enable_fast_parameter_block_removal;
+
+ // By default, Ceres performs a variety of safety checks when constructing
+ // the problem. There is a small but measurable performance penalty to
+ // these checks, typically around 5% of construction time. If you are sure
+ // your problem construction is correct, and 5% of the problem construction
// time is truly an overhead you want to avoid, then you can set
// disable_all_safety_checks to true.
//
- // WARNING:
- // Do not set this to true, unless you are absolutely sure of what
+ // WARNING: Do not set this to true, unless you are absolutely sure of what
// you are doing.
bool disable_all_safety_checks;
};
@@ -257,6 +268,33 @@
int size,
LocalParameterization* local_parameterization);
+ // Remove a parameter block from the problem. The parameterization of the
+ // parameter block, if it exists, will persist until the deletion of the
+ // problem (similar to cost/loss functions in residual block removal). Any
+ // residual blocks that depend on the parameter are also removed, as
+ // described above in RemoveResidualBlock().
+ //
+ // If Problem::Options::enable_fast_parameter_block_removal is true, then the
+ // removal is fast (almost constant time). Otherwise, removing a parameter
+ // block will incur a scan of the entire Problem object.
+ //
+ // WARNING: Removing a residual or parameter block will destroy the implicit
+ // ordering, rendering the jacobian or residuals returned from the solver
+ // uninterpretable. If you depend on the evaluated jacobian, do not use
+ // remove! This may change in a future release.
+ void RemoveParameterBlock(double* values);
+
+ // Remove a residual block from the problem. Any parameters that the residual
+ // block depends on are not removed. The cost and loss functions for the
+ // residual block will not get deleted immediately; won't happen until the
+ // problem itself is deleted.
+ //
+ // WARNING: Removing a residual or parameter block will destroy the implicit
+ // ordering, rendering the jacobian or residuals returned from the solver
+ // uninterpretable. If you depend on the evaluated jacobian, do not use
+ // remove! This may change in a future release.
+ void RemoveResidualBlock(ResidualBlockId residual_block);
+
// Hold the indicated parameter block constant during optimization.
void SetParameterBlockConstant(double* values);