Up till now ITERATIVE_SCHUR evaluates matrix-vector products
between the Schur complement and a vector implicitly by exploiting
the algebraic expression for the Schur complement.
This cost of this evaluation scales with the number of non-zeros
in the Jacobian.
For small to medium sized problems there is a sweet spot where
computing the Schur complement is cheap enough that it is much
more efficient to explicitly compute it and use it for evaluating
the matrix-vector products.
This changes implements support for an explicit Schur complement
in ITERATIVE_SCHUR in combination with the SCHUR_JACOBI preconditioner.
API wise a new bool Solver::Options::use_explicit_schur_complement
has been added.
The implementation extends the SparseSchurComplementSolver to use
Conjugate Gradients.
Example speedup:
use_explicit_schur_complement = false
Time (in seconds):
Preprocessor 0.585
Residual evaluation 0.319
Jacobian evaluation 1.590
Linear solver 25.685
Minimizer 27.990
Postprocessor 0.010
Total 28.585
use_explicit_schur_complement = true
Time (in seconds):
Preprocessor 0.638
Residual evaluation 0.318
Jacobian evaluation 1.507
Linear solver 5.930
Minimizer 8.144
Postprocessor 0.010
Total 8.791
Which indicates an end-to-end speedup of more than 3x, with the linear
solver being sped up by > 4x.
The idea to explore this optimization was inspired by the recent paper:
Mining structure fragments for smart bundle adjustment
L. Carlone, P. Alcantarilla, H. Chiu, K. Zsolt, F. Dellaert
British Machine Vision Conference, 2014
which uses a more complicated algorithm to compute parts of the
Schur complement to speed up the matrix-vector product.
Change-Id: I95324af0ab351faa1600f5204039a1d2a64ae61d
The line search minimizer in Ceres does not require that the
problems that is solving is a sum of squares. Over the past
year there have been multiple requests to expose this algorithm
on its own so that it can be used to solve unconstrained
non-linear minimization problems on its own.
With this change, a new optimization problem called
GradientProblem is introduced which is basically a thin
wrapper around a user defined functor that evaluates cost
and gradients (FirstOrderFunction) and an optional LocalParameterization.
Corresponding to it, a GradientProblemSolver and its associated
options and summary structs are introduced too.
An example that uses the new API to find the minimum of Rosenbrock's
function is also added.
Change-Id: I42bf687540da25de991e9bdb00e321239244e8b4
Add an example application of homography matrix estimation
from a 2D euclidean correspondences which is done in two
steps:
- Coarse algebraic estimation
- Fine refinement using Ceres minimizer
Nothing terribly exciting apart from an example of how to
use user callbacks.
User callback is used here to stop minimizer when average
of symmetric geometric distance becomes good enough.
This might be arguable whether it's the best way to go
(in some cases you would want to stop minimizer when
maximal symmetric distance is lower than a threshold) but
for a callback usage example it's good enough to stick
to current logic.
Change-Id: I60c8559cb10b001a0eb64ab71920c08bd68455b8
- Previously we passed all compile options to Ceres via add_definitions
in CMake. This was fine for private definitions (used only by Ceres)
but required additional work for public definitions to ensure they
were correctly propagated to clients via CMake using
target_compile_definitions() (>= 2.8.11) or add_definitions().
- A drawback to these approaches is that they did not work for chained
dependencies on Ceres, as in if in the users project B <- A <- Ceres,
then although the required Ceres public compile definitions would
be used when compiling A, they would not be propagated to B.
- This patch replaces the addition of compile definitions via
add_definitions() with an autogenerated config.h header which
is installed with Ceres and defines all of the enabled Ceres compile
options.
- This removes the need for the user to propagate any compile
definitions in their projects, and additionally allows post-install
inspect of the options with which Ceres was compiled.
Change-Id: Idbdb6abdad0eb31e7540370e301afe87a07f2260
1. Update version history.
2. Minor changes to the tutorial to reflect the bounds constrained
problem.
3. Added static factory methods to the SnavelyReprojectionError.
4. Removed relative gradient tolerance from types.h as it is
not true anymore.
Change-Id: I8de386e5278a008c84ef2d3290d2c4351417a9f1
As pointed out by Jim Roseborough, this is the Marsaglia Polar
method and not the Box-Muller method.
Change-Id: Id5332bcd4b4c23a3885cc296729b44eaa5edd0a8
The standard sparse normal Cholesky solver assumes a fixed
sparsity pattern which is useful for a large number of problems
presented to Ceres. However, some problems are symbolically dense
but numerically sparse i.e. each residual is a function of a
large number of parameters but at any given state the residual
only depends on a sparse subset of them. For these class of
problems it is faster to re-analyse the sparsity pattern of the
jacobian at each iteration of the non-linear optimisation instead
of including all of the zero entries in the step computation.
The proposed solution adds the dynamic_sparsity option which can
be used with SPARSE_NORMAL_CHOLESKY. A
DynamicCompressedRowSparseMatrix type (which extends
CompressedRowSparseMatrix) has been introduced which allows
dynamic addition and removal of elements. A Finalize method is
provided which then consolidates the matrix so that it can be
used in place of a regular CompressedRowSparseMatrix. An
associated jacobian writer has also been provided.
Changes that were required to make this extension were adding the
SetMaxNumNonZeros method to CompressedRowSparseMatrix and adding
a JacobianFinalizer template parameter to the ProgramEvaluator.
Change-Id: Ia5a8a9523fdae8d5b027bc35e70b4611ec2a8d01
Solver::Options::linear_solver_ordering and
Solver::Options::inner_iteration_ordering
were bare pointers even though Solver::Options took ownership of these
objects.
This lead to buggy user code and the inability to copy Solver::Options
objects around.
With this change, these naked pointers have been replaced by a
shared_ptr object which will managed the lifetime of these objects. This
also leads to simplification of the lifetime handling of these objects
inside the solver.
The Android.mk and Application.mk files have also been updated
to use a newer NDK revision which ships with LLVM's libc++.
Change-Id: I25161fb3ddf737be0b3e5dfd8e7a0039b22548cd
1. Rename SolverTerminationType to TerminationType.
2. Consolidate the enum as
a. CONVERGENCE - subsumes FUNCTION_TOLERANCE, PARAMETER_TOLERANCE and GRADIENT_TOLERANCE
b. NO_CONVERGENCE
c. FAILURE - captures all kinds of failures including DID_NOT_RUN.
d. USER_SUCCESS
e. USER_FAILURE
3. Solver::Summary::error is renamed to be Solver::Summary::message, to both
reduce confusion as well as capture its true meaning.
Change-Id: I27a382e66e67f5a4750d0ee914d941f6b53c326d
I had to fix the following things to make Ceres compile in 2013:
* Not link to 'm' (GNU math library).
* Excplicitly convert an std::ostream to bool.
* Include <algorithm> for std::max.
Change-Id: I3ff65413baf8711364360d46dd71fd553fa63e72
The original visibility based preconditioning paper and
implementation only used the canonical views algorithm.
This algorithm for large dense graphs can be particularly
expensive. As its worst case complexity is cubic in size
of the graph.
Further, for many uses the SCHUR_JACOBI preconditioner
was both effective enough while being cheap. It however
suffers from a fatal flaw. If the camera parameter blocks
are split between two or more parameter blocks, e.g,
extrinsics and intrinsics. The preconditioner because
it is block diagonal will not capture the interactions
between them.
Using CLUSTER_JACOBI or CLUSTER_TRIDIAGONAL will fix
this problem but as mentioned above this can be quite
expensive depending on the problem.
This change extends the visibility based preconditioner
to allow for multiple clustering algorithms. And adds
a simple thresholded single linkage clustering algorithm
which allows you to construct versions of CLUSTER_JACOBI
and CLUSTER_TRIDIAGONAL preconditioners that are cheap
to construct and are more effective than SCHUR_JACOBI.
Currently the constants controlling the threshold above
which edges are considered in the single linkage algorithm
are not exposed. This would be done in a future change.
Change-Id: I7ddc36790943f24b19c7f08b10694ae9a822f5c9
- Any pure-C program #including <math.h> will need to link against
libm, some compilers will let an indirect link slide (via Ceres in
this case) but some won't.
Change-Id: I6890702fa0d2c3fbb747f0f81fc3fa3631839de4
- Adding FindPackage scripts for all of Ceres dependencies.
- Moving depend.cmake contents to CeresConfig.cmake and cleaning up
search for Ceres & required dependencies, no longer push Ceres
options into client.
- Fixing uninstall to remove ceres include root directory.
- Fixing main CMakeLists to install miniglog header if enabled.
- Making miniglog library shared/static with Ceres library.
Change-Id: If926bebd11720230c5136597ccba672394ed9777
1. When a LAPACK implementation is present, then
DENSE_QR, DENSE_NORMAL_CHOLESKY and DENSE_SCHUR
can use it for doing dense linear algebra operations.
2. The user can switch dense linear algebra libraries
by setting Solver::Options::dense_linear_algebra_library_type.
3. Solver::Options::sparse_linear_algebra_library is now
Solver::Options::sparse_linear_algebra_library_type to be consistent
with all the other enums in Solver::Options.
4. Updated documentation as well as Solver::Summary::FullReport
to reflect these changes.
Change-Id: I5ab930bc15e90906b648bc399b551e6bd5d6498f
This extends the C API to support loss functions. Both
user-supplied cost functions as well as the stock Ceres cost
functions (Cauchy, Huber, etc) are supported. In addition, this
adds a simple unit test for the C API.
Supporting loss functions required changing the signature of the
ceres_add_residual_block() function to also take a thunk for the
loss function.
Change-Id: Iefa58cf709adbb8f24588e5eb6aed9aef46b6d73
fix compilation error on Ubuntu 12.0
In file included from /usr/include/fcntl.h:252:0,
from /home/ajg23/src/ceres-solver/examples/libmv_bundle_adjuster.cc:91:
/home/ajg23/src/ceres-solver/examples/libmv_bundle_adjuster.cc: In member function ‘T {anonymous}::EndianAwareFileReader::Read() const [with T = unsigned char]’:
/home/ajg23/src/ceres-solver/examples/libmv_bundle_adjuster.cc:300:5: error: ignoring return value of ‘ssize_t read(int, void*, size_t)’, declared with attribute warn_unused_result [-Werror=unused-result]
Change-Id: Ib23ca19778761bbfe0d77bcf32a2181ce6db1a12
1. Further tightening of the Covariance documentation.
2. Documented minimizer progress output.
3. Lint cleanup from William Rucklidge.
4. Updated version history.
Change-Id: I8bc28484675d4edf89a7c050b6379dbac6c39e91
Add example application which is based on bundle
adjustment code from Libmv library, which is heavily
used in Blender.
Apart from bundle adjustment code this commit also
contains real-life optimization problems from VFX
pipeline. This files are created from production
files of Tears of Steel movie.
New code is placed to examples, and could be used
either as an example implementation of BA or for
timing investigation of problems appearing in VFX.
Problems for this application are placed to
data/libmv-ba-problems.
Usage:
./libmv_bundle_adjuster --input=/path/to/problem_file.bin
There's also optional flag --refine_intrinsics which
declares explicitly whether intrinscis shall be
refined or not. If this flag is not passed, refinement
will happen for problems stored in image space.
Structure of problem files is described in header
comment of libmv_bundle_adjuster.cc.
Change-Id: I51202848c75dcd7612b707609e5ff3708e01b625
- In C you're not allowed to define variables in the middle
of the block. This was violated in curve_fitting.c by
calling ceres_init() in the beginning of main() and declaring
variables later.
- Also ifdef-ed suitesparse stuff in covariance estimation module.
This solves compilation error when you don't have suitesparse
compiled/installed.
Change-Id: I22b543c09ea01f55e127079daade99a0b781f789
This introduces a simple C API for a subset of Ceres. This opens the door to
using languages like Python to call Ceres, since it is much easier to bind to C
than it is to bind to C++. It will mean giving up the native Ceres autodiff.
The implementation in this patch does not attempt to do everything but is only
just enough to get started. Subsequent patches will increase the surface area
of Ceres that is covered by the C API.
Change-Id: Ic51804bac6865e1a2e476553248aabc91dff3409
Sparse Cholesky factorization algorithms use a fill-reducing
ordering to permute the columns of the Jacobian matrix. There
are two ways of doing this.
1. Compute the Jacobian matrix in some order and then have the
factorization algorithm permute the columns of the Jacobian.
2. Compute the Jacobian with its columns already permuted.
The first option incurs a significant memory penalty. The
factorization algorithm has to make a copy of the permuted
Jacobian matrix.
Starting with this change Ceres pre-permutes the columns of the
Jacobian matrix and generally speaking, there is no performance
penalty for doing so.
In some rare cases, it is worth using a more complicated
reordering algorithm which has slightly better runtime
performance at the expense of an extra copy of the Jacobian
matrix. Setting Solver::Options::use_postordering to true
enables this tradeoff.
This change also removes Solver::Options::use_block_amd
as an option. All matrices are ordered using their block
structure. The ability to order them by their scalar
sparsity structure has been removed.
Here is what performance on looks like on some BAL problems.
Memory
======
HEAD pre-ordering
16-22106 137957376.0 113516544.0
49-7776 56688640.0 46628864.0
245-198739 1718005760.0 1383550976.0
257-65132 387715072.0 319512576.0
356-226730 2014826496.0 1626087424.0
744-543562 4903358464.0 3957878784.0
1024-110968 968626176.0 822071296.0
Time
====
HEAD pre-ordering
16-22106 3.8 3.7
49-7776 1.9 1.8
245-198739 82.6 81.9
257-65132 14.0 13.4
356-226730 98.8 95.8
744-543562 325.2 301.6
1024-110968 42.1 37.1
Change-Id: I6b2e25f3fed7310f88905386a7898ac94d37467e
1. Quicker starting point.
2. Better discussion of derivatives.
3. Better hyperlinking to code and class documentation.
4. New robust estimation example.
5. Better naming of example code.
6. Removed dependency on gflags in all the core examples covered
in the tutorial.
Change-Id: Ibf3c7fe946fa2b4d22f8916a9366df267d34ca26