Starting with SuiteSparse version 7.4.0 CHOLMOD has support for single
precision matrices. This allows us to have single precision and mixed
precision solves when using the SUITE_SPARSE backend.
This CL also fixes sparse_cholesky_test which was completely broken for
single precision testing.
Sample performance on my Mac.
/usr/bin/time -l ./bin/bundle_adjuster --input=../../Downloads/problem-3068-310854-pre.txt
<SNIP>
Cost:
Initial 9.099334e+07
Final 4.161838e+06
Change 8.683150e+07
Minimizer iterations 6
Successful steps 4
Unsuccessful steps 2
Time (in seconds):
Preprocessor 2.528222
Residual only evaluation 0.142804 (5)
Jacobian & residual evaluation 0.424014 (4)
Linear solver 54.083396 (5)
Minimizer 54.895752
Postprocessor 0.024564
Total 57.448539
Termination: NO_CONVERGENCE (Maximum number of iterations reached. Number of iterations: 5.)
59.04 real 341.24 user 5.49 sys
5776375808 maximum resident set size
<SNIP>
616329634071 instructions retired
929475980510 cycles elapsed
5375034560 peak memory footprint
/usr/bin/time -l ./bin/bundle_adjuster --input=../../Downloads/problem-3068-310854-pre.txt -mixed_precision_solves
<SNIP>
Cost:
Initial 9.099334e+07
Final 4.148930e+06
Change 8.684441e+07
Minimizer iterations 6
Successful steps 4
Unsuccessful steps 2
Time (in seconds):
Preprocessor 2.580217
Residual only evaluation 0.144098 (5)
Jacobian & residual evaluation 0.396723 (4)
Linear solver 23.636074 (5)
Minimizer 24.427163
Postprocessor 0.023790
Total 27.031170
Termination: NO_CONVERGENCE (Maximum number of iterations reached. Number of iterations: 5.)
28.58 real 128.53 user 2.37 sys
4818386944 maximum resident set size
<SNIP>
395186936091 instructions retired
368802808856 cycles elapsed
4327029824 peak memory footprint
Change-Id: I1f137b0dd12da8da7f9ced338dd8f20f4bbdf99d
Replace WallTimeInSeconds with absl::Now and use
absl::Time and absl::Duration objects instead of doubles.
wall_time.h/cc -> event_logger.h/cc
Change-Id: I41279961368840fbdf6bb3456ffdbdf2f9bfb85b
Replace ceres::String* with their more modern and performant
absl strings library equivalent and delete our string
manipulation library.
Change-Id: Iecbdba9864e0abf329778f81fdc0708f78f7594f
1. Add abseil-cpp as a submodule. We are tracking the latest LTS
release, which is lts_2024_01_16.
2. Replace glog/gflags with absl::log and absl::flags.
3. Remove miniglog
4. Also take a whack at making the bazel build work with
abseil-cpp and gtest.
There are a number of TODOs in this CL that still need to be resolved.
Change-Id: I39355ed7d61375be4ebcbc8596d9cc70acc1c678
cuDSS could be used as an alternative for SuiteSparse and EigenSparse
in case if CUDA capable GPU is available.
Change-Id: I7a567093ce91363478118153e181134ed5804573
1. Add a version history
2. Update copyright years across the code base
3. Run format_all.sh
4. Update version strings from 2.1.0 to 2.2.0 in the docs and
elsewhere.
Change-Id: I46d8d479d54bd6002d532785e67342106e73c9ac
Benchmark for evaluation of residuals and evaluation of both residuals
and jacobian.
For each input file (in BAL format) specified on the command line two
sets of benchmarks are created for different number of threads.
BAL data is preloaded before starting benchmark.
Usage:
./bin/evaluation_benchmark [flags] input_1.txt ... input_N.txt
Change-Id: I543df65f483e3b186f52785b68bd5e2b3e3552a3
* Added GPU device and CUDA compute capability identification.
* Added GpuMemoryAvailable() to aid downstream optimizations based
on GPU memory availability.
Change-Id: I326dc1e4b7a6a7f5571b7e5479eb9aa300ad1075
* Added CudaCgnrSolver, a new CUDA-accelerated CGNR.
* To use CudaCgnrSolver, the user must select CGNR as the linear_solver
and CUDA_SPARSE as the sparse_linear_algebra_library.
* Updated ConjugateGradientSolver to work with an array of pointers to
scratch to support CudaVectors as scratch.
* Moved CUDA initialization to run in Solver::Solve as needed.
Some performance comparisons on an Ubuntu 20.04 desktop with an
Intel i9-9940X CPU @ 3.30GHz, and an nVidia Quadro RTX 6000,
all configurations run with 24 threads, and 10 iterations.
=================================================
CGNR + CUDA_SPARSE + IDENTITY Preconditioner
problem-1778-993923-pre.txt
=================================================
Cost:
Initial 2.563973e+08
Final 1.724755e+06
Change 2.546725e+08
Minimizer iterations 11
Successful steps 7
Unsuccessful steps 4
Time (in seconds):
Preprocessor 4.020158
Residual only evaluation 1.567092 (10)
Jacobian & residual evaluation 7.847130 (7)
Linear solver 31.688898 (10)
Minimizer 46.834987
Postprocessor 0.353974
Total 51.209120
=================================================
SPARSE_SCHUR (CPU) + SUITE_SPARSE + AMD
problem-1778-993923-pre.txt
=================================================
Cost:
Initial 2.563973e+08
Final 1.651617e+06
Change 2.547457e+08
Minimizer iterations 11
Successful steps 11
Unsuccessful steps 0
Time (in seconds):
Preprocessor 35.812003
Residual only evaluation 1.658980 (10)
Jacobian & residual evaluation 12.218799 (11)
Linear solver 76.409992 (10)
Minimizer 98.809773
Postprocessor 0.372712
Total 134.994489
=================================================
ITERATIVE_SCHUR (CPU) + JACOBI Preconditioner
problem-1778-993923-pre.txt
=================================================
Cost:
Initial 2.563973e+08
Final 1.684447e+06
Change 2.547128e+08
Minimizer iterations 11
Successful steps 8
Unsuccessful steps 3
Time (in seconds):
Preprocessor 15.331614
Residual only evaluation 1.606114 (10)
Jacobian & residual evaluation 8.502166 (8)
Linear solver 351.910080 (10)
Minimizer 368.797327
Postprocessor 0.363536
Total 384.492478
=================================================
CGNR + CUDA_SPARSE + IDENTITY Preconditioner
problem-13682-4456117-pre.txt
=================================================
Cost:
Initial 1.126372e+09
Final 2.269329e+07
Change 1.103678e+09
Minimizer iterations 11
Successful steps 7
Unsuccessful steps 4
Time (in seconds):
Preprocessor 19.140087
Residual only evaluation 8.721920 (10)
Jacobian & residual evaluation 41.955923 (7)
Linear solver 214.121861 (10)
Minimizer 296.636890
Postprocessor 1.971827
Total 317.748804
Change-Id: I3a09f31aa6903f661e91f595afd39d427583e856
Add an option to use schur power series expansion for initialization
of pcg solution in ITERATIVE_SCHUR linear solver.
Change-Id: Ifb8bce02bc5f5ceebc74f961eefd3f6dd2ffab4a
The code that verifies that the linear solver is configuration
specified by the user has grown into a rat's nest. This CL
attempts to bring some order to this madness.
Fixes https://github.com/ceres-solver/ceres-solver/issues/852
Change-Id: I3f34c0e27da13a6412117dee43ef2d9ec3835b64
These changes came about from testing the power bundle adjustment
integration CL.
1. Allow Solver::Options::max_linear_solver_iterations == 0.
2. Simplify the logic for when inverse(F'F) is computed.
3. norm_b -> norm_rhs in ConjugateGradientsSolver.
Change-Id: I50c19e1f24a4cc08ed60e3a3032b96b37bcada9f
On problem-744-543562-pre.txt
The time spent in linear solver on my M1 Pro is
eigen 81.550970
eigen+mixed 54.107383
LAPACK 47.078127
LAPACK+mixed 28.639868
Solution quality is unaffected.
The implementation of RefinedDenseCholesky and DenseIterativeRefiner
are straightforward ports of RefinedSparseCholesky and
SparseIterativeRefiner (formerly IterativeRefiner).
It maybe possible to refactor the SparseCholesky and DenseCholesky
interfaces so that this code duplication can be removed in the
future.
Change-Id: I921334224cb97629a60390f2add822de207f7923
With this change, the user can now choose between Approximate Minimum
Degree and Nested Dissection as a fill reducing algorithm when using
a sparse direct factorization based linear solver like SPARSE_NORMAL_CHOLESKY
or SPARSE_SCHUR.
Currenly only SUITE_SPARSE is supported. It requires that
SuiteSparse be compiled with Metis support enabled.
On most problems AMD is still the better choice, but in some cases
like the grid3D dataset from https://lucacarlone.mit.edu/datasets/
the solution time with AMD is 57s and with NESDIS 38 on my M1 Mac.
On some other problems at Google we have observed speedups of 10x,
there is also a corresponding decrease in the total amount of memory
used.
This patch is based on the original work done by NeroBurner in
https://ceres-solver-review.googlesource.com/c/ceres-solver/+/20580
1. Add a new enum to the public api LinearSolverOrderingType and
a setting Solver::Options::linear_solver_ordering_type.
2. TrustRegionPreprocessor had some complicated logic which determined
when linear solvers should reorder their matrices on their own and not
this has been refactored into a more readable function that lives
inside reorder_program.h/cc.
3. Plumbing in reorder_program.cc and trust_region_processor.cc to use
nested dissection.
4. Update bundle_adjuster.cc to use nested dissection.
Change-Id: I388b027934f86c58b4da2b65a4fa5204ea73bf40
Add logic for checking for availability of CUDA as the
dense linear algebra library before allowing the user
to use it.
Change-Id: I0ceafa1052632504b33685bc731366ef6933e518
Currently, the logic for exporting symbols is rather complicated: when
tests are enabled internal symbols are exported in addition to the
public symbols. Such logic causes several problems. (1) Test binaries
link against a Ceres build that is different from the final release
since fewer optimizations are applied if more symbols are exported. (2)
Also, some toolchains hide symbols by default breaking the existing
logic eventually causing linker errors.
Since internal symbols are not intended to be used outside of the
project, we can compile them into object files and use exactly the same
binary code both for the final build and the tests without relying on
conditionals.
By default, all symbols are now hidden unless annotated as public.
Internal symbols are explicitly marked as not being exported in case
users chose not to hide symbols by default.
Change-Id: I589dd10be2f6f438508783cf99d141af0120057b
Applied changes correspond to clang-tidy fixes
stemming from the modernize-use-equals-default check.
Change-Id: I254b0908a76d464131564b637cd0e42a6b03fb5a
VLOG_IF's evaluation order is ambiguous - does it mean
`if (cond) VLOG(lvl)` or `if (VLOG_IS_ON(lvl) && cond) LOG(INFO)`?
In particular, the way it works now is inconsistent with the way the
rest of the LOG macros evaluate their arguments.
Fixing this would be hard, and the macro's behavior would still surprise
some people. Replacing it with an if statement is simple, clear, and unambiguous.
Change-Id: I97a92d17a932c0a5344a1bf98d676308793ba877
- Change formatting standard to Cpp11. Main difference is not having
the space between two closing >> for nested templates. We don't
choose c++14, because older versions of clang-format (version 9
and earlier) don't know this value yet, and it doesn't make a
difference in the formatting.
- Apply clang-format to all (non generated) internal source files.
- Manually fix some code sections (clang-format on/off) and c-strings
- Exclude some embedded external files with very different formatting
(gtest/gmock)
- Add script to format all source files
Change-Id: Ic6cea41575ad6e37c9e136dbce176b0d505dc44d
https://github.com/ceres-solver/ceres-solver/issues/270
Detailed list of changes:
1. Add SUBSET to the PreconditionerType enum.
2. Add Solver::Options::residual_blocks_for_subset_preconditioner
3. Integrate SubsetPreconditioner into the CGNR solver.
4. Add the reordering logic needed for this to TrustRegionPreprocessor.
5. Expect CreateJacobianBlockTranspose to take the starting row block
so that we can work with subparts of the Jacobian matrix.
6. Extend the denoising example to use this preconditioner.
As an illustration of its performance, we consider the performance of
denoising -input ../data/ceres_noisy.pgm --foe_file ../data/5x5.foe
tl;dr
For the same cost,
SPARSE_NORMAL_CHOLESKY - 81s
CGNR + JACOBI - 718s
CGNR + SUBSET - 57s
SPARSE_NORMAL_CHOLESKY
======================
Cost:
Initial 2.317806e+05
Final 2.232323e+04
Change 2.094574e+05
Minimizer iterations 10
Successful steps 10
Unsuccessful steps 0
Time (in seconds):
Preprocessor 2.999746
Residual only evaluation 2.306811 (10)
Jacobian & residual evaluation 7.421727 (10)
Linear solver 65.517273 (10)
Minimizer 78.731011
Postprocessor 0.026079
Total 81.756836
Termination: CONVERGENCE (Function tolerance reached. |cost_change|/cost: 8.573046e-04 <= 1.000000e-03)
CGNR + JACOBI
=============
Cost:
Initial 2.317806e+05
Final 2.232344e+04
Change 2.094572e+05
Minimizer iterations 10
Successful steps 10
Unsuccessful steps 0
Time (in seconds):
Preprocessor 0.648814
Residual only evaluation 2.297607 (10)
Jacobian & residual evaluation 7.327886 (10)
Linear solver 699.601248 (10)
Minimizer 712.419493
Postprocessor 0.024014
Total 713.092321
Termination: CONVERGENCE (Function tolerance reached. |cost_change|/cost: 8.528538e-04 <= 1.000000e-03)
CGNR + SUBSET (random 20% residuals used for the preconditioner)
===============================================================
Cost:
Initial 2.317806e+05
Final 2.232327e+04
Change 2.094574e+05
Minimizer iterations 10
Successful steps 10
Unsuccessful steps 0
Time (in seconds):
Preprocessor 1.472743
Residual only evaluation 2.428315 (10)
Jacobian & residual evaluation 7.367796 (10)
Linear solver 42.585999 (10)
Minimizer 55.664459
Postprocessor 0.024098
Total 57.161301
Termination: CONVERGENCE (Function tolerance reached. |cost_change|/cost: 8.538277e-04 <= 1.000000e-03)
Change-Id: Ifb011408bd53edbb9439b0b7345649a38f999e18
- Accelerate currently does not support dynamic sparsity, whereas the
other sparse linear algebra libraries do (outstanding issue to update)
- Previously we preferred Accelerate to all but SuiteSparse if it was
available, which breaks the dynamic_sparsity_test if SuiteSparse is
*not* available (even if others are) as Accelerate does not support
dynamic sparsity.
Change-Id: Ibc2dd2f14f83cffbecca38097d02bb2188aaaa05
This change only affects the TRUST_REGION minimizer and has no effect
on the LINE_SEARCH minimizer.
This options controls the number of iterations that the line search
algorithm performs. The line search algorithm is as the name implies,
used in the LINE_SEARCH minimizer. It is also used by the TRUST_REGION
minimizer when solving bounds constrained optimization problems.
In some bounds constrained problems, it is enough to project each step
onto the bounds constraints and not perform the line search. This can
have a significant impact on runtime. Setting
Solver::Options::max_num_line_search_step_size_iterations = 0 enables
this functionality.
Changchang Wu (ccwu@google.com) came up with the idea for this
implementation.
https://github.com/ceres-solver/ceres-solver/issues/477
Change-Id: Ifbe0bc5c48eedb2c1231d43cd98e4be7316c0682
This method gives the user the ability to evaluate a given residual
block.
A couple of minor cleanups.
Problem::problem_impl_ -> Problem::impl_
NULL -> nullptr
https://github.com/ceres-solver/ceres-solver/issues/417
Change-Id: I6dd94762c475fa264c387b8c93d516f6e06fe832
When Solver::Options::check_gradients is true, Ceres internally
creates a new ProblemImpl object which wraps each CostFunction
in the user's problem with a GradientCheckingCostFunction.
Doing this also requires creating new ParameterBlock objects,
and when support for upper and lower bounds was added to Ceres,
CreateGradientCheckingProblemImpl should also have been updated
to create a problem with the same parameter bounds. As a result,
if check_gradients is enabled for a bounded problem, it constructs
an unconstrained problem and solves it.
This CL fixes this, by introducing Problem::GetParameterLowerBound,
and Problem::GetParameterUpperBound and using them to create a bounded
problem when checking gradients.
Thanks to @pbeeson for not only reporting this problem, but also
providing a small standalone reproduction which made debugging this
possible.
https://github.com/ceres-solver/ceres-solver/issues/379
Change-Id: Id18eb858a7009bf4fa452a21b925922d13f3249f
CLUSTER_JACOBI and CLUSTER_TRIDIAGONAL preconditioners require a sparse
Cholesky factorization library. Previously this code was hard coded to
use SuiteSparse. Once SparseCholesky abstraction was introduced, it
became possible to use it with Eigen or CXSParse.
Unfortunately the old code path that was enforcing the requirement
of SuiteSparse was not removed.
This change does the following:
1. Remove the SUITE_SPARSE restriction on CLUSTER_TRIDIAGONAL and
CLUSTER_JACOBI
2. Redo the checking code to be ifdef free and more general.
3. Add bundle adjustment tests to test these configurations.
Thanks to Bjorn Piltz for catching and reporting this bug.
Change-Id: I637791f6f8149694b6aa75f6a4b6417398cb9590
Also removed Solver::Summary::num_linear_solver_threads_given
and Solver::Summary::num_linear_solver_threads_used.
Change-Id: I559145ae2e7af597ea06ec03d386645a3a892e9f
Migrate all Option and Summary structs to use
inline member initialization syntax.
This reduces the amount of code, and collocates the
default values with the documentation for the corresponding
member variable.
Change-Id: I8e6b9ee3b31464699d678667f6166ace5fc137c9
This adds a callback mechanism to for users to get notified just
before jacobian and residual evaluations. This will enable
aggressive caching and sharing of compute between cost functions.
Change-Id: I67993726920218edf71ab9ae70c34c204756c71a
1. When Solver::Options::update_state_every_iteration = true,
the StateUpdatingCallback only updates the state on a
successful iteration. This works fine but will not work
if the user provides an EvaluationCallback, because
every call to Evaluator::Evaluate will change the state
visible to the user. This means that on unsuccessful
iterations when the user's IterationCallback is called
the state visible to the user would be the last evaluation
which did not lead to an improved cost. This CL forces
the StateUpdatingCallback to unconditionally update
the user visible state.
2. When the minimizer terminates, we update the user visible
state only if the solution is usable, otherwise the user's
state will remain the same. To maintain this invariant
we will now cache the user's state and make sure we
use it to reset it upon return if the solver is not
successful.
Change-Id: Ic1f8fa6cb10d2753130ea752c70ff3d6b2f1462f