Update Ceres to latest upstream version
authorSergey Sharybin <sergey.vfx@gmail.com>
Wed, 24 Sep 2014 11:10:02 +0000 (17:10 +0600)
committerSergey Sharybin <sergey.vfx@gmail.com>
Thu, 25 Sep 2014 07:04:17 +0000 (13:04 +0600)
As usual brings fixes and speed improvements.

92 files changed:
extern/libmv/third_party/ceres/CMakeLists.txt
extern/libmv/third_party/ceres/ChangeLog
extern/libmv/third_party/ceres/bundle.sh
extern/libmv/third_party/ceres/files.txt
extern/libmv/third_party/ceres/include/ceres/c_api.h
extern/libmv/third_party/ceres/include/ceres/ceres.h
extern/libmv/third_party/ceres/include/ceres/conditioned_cost_function.h
extern/libmv/third_party/ceres/include/ceres/cost_function.h
extern/libmv/third_party/ceres/include/ceres/cost_function_to_functor.h
extern/libmv/third_party/ceres/include/ceres/covariance.h
extern/libmv/third_party/ceres/include/ceres/crs_matrix.h
extern/libmv/third_party/ceres/include/ceres/gradient_problem.h [new file with mode: 0644]
extern/libmv/third_party/ceres/include/ceres/gradient_problem_solver.h [new file with mode: 0644]
extern/libmv/third_party/ceres/include/ceres/internal/disable_warnings.h [new file with mode: 0644]
extern/libmv/third_party/ceres/include/ceres/internal/numeric_diff.h
extern/libmv/third_party/ceres/include/ceres/internal/reenable_warnings.h [new file with mode: 0644]
extern/libmv/third_party/ceres/include/ceres/iteration_callback.h
extern/libmv/third_party/ceres/include/ceres/jet.h
extern/libmv/third_party/ceres/include/ceres/local_parameterization.h
extern/libmv/third_party/ceres/include/ceres/loss_function.h
extern/libmv/third_party/ceres/include/ceres/normal_prior.h
extern/libmv/third_party/ceres/include/ceres/numeric_diff_functor.h [deleted file]
extern/libmv/third_party/ceres/include/ceres/ordered_groups.h
extern/libmv/third_party/ceres/include/ceres/problem.h
extern/libmv/third_party/ceres/include/ceres/solver.h
extern/libmv/third_party/ceres/include/ceres/types.h
extern/libmv/third_party/ceres/include/ceres/version.h [new file with mode: 0644]
extern/libmv/third_party/ceres/internal/ceres/CMakeLists.txt [deleted file]
extern/libmv/third_party/ceres/internal/ceres/array_utils.cc
extern/libmv/third_party/ceres/internal/ceres/array_utils.h
extern/libmv/third_party/ceres/internal/ceres/callbacks.cc [new file with mode: 0644]
extern/libmv/third_party/ceres/internal/ceres/callbacks.h [new file with mode: 0644]
extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.cc
extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.h
extern/libmv/third_party/ceres/internal/ceres/conjugate_gradients_solver.cc
extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.cc
extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.h
extern/libmv/third_party/ceres/internal/ceres/covariance_impl.cc
extern/libmv/third_party/ceres/internal/ceres/covariance_impl.h
extern/libmv/third_party/ceres/internal/ceres/cxsparse.h
extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.cc
extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc
extern/libmv/third_party/ceres/internal/ceres/gradient_problem.cc [new file with mode: 0644]
extern/libmv/third_party/ceres/internal/ceres/gradient_problem_evaluator.h [new file with mode: 0644]
extern/libmv/third_party/ceres/internal/ceres/gradient_problem_solver.cc [new file with mode: 0644]
extern/libmv/third_party/ceres/internal/ceres/graph.h
extern/libmv/third_party/ceres/internal/ceres/graph_algorithms.h
extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc
extern/libmv/third_party/ceres/internal/ceres/line_search_direction.cc
extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.cc
extern/libmv/third_party/ceres/internal/ceres/line_search_preprocessor.cc [new file with mode: 0644]
extern/libmv/third_party/ceres/internal/ceres/line_search_preprocessor.h [new file with mode: 0644]
extern/libmv/third_party/ceres/internal/ceres/linear_solver.cc
extern/libmv/third_party/ceres/internal/ceres/linear_solver.h
extern/libmv/third_party/ceres/internal/ceres/local_parameterization.cc
extern/libmv/third_party/ceres/internal/ceres/loss_function.cc
extern/libmv/third_party/ceres/internal/ceres/minimizer.cc
extern/libmv/third_party/ceres/internal/ceres/minimizer.h
extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.cc
extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.h
extern/libmv/third_party/ceres/internal/ceres/preconditioner.cc
extern/libmv/third_party/ceres/internal/ceres/preconditioner.h
extern/libmv/third_party/ceres/internal/ceres/preprocessor.cc [new file with mode: 0644]
extern/libmv/third_party/ceres/internal/ceres/preprocessor.h [new file with mode: 0644]
extern/libmv/third_party/ceres/internal/ceres/problem.cc
extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc
extern/libmv/third_party/ceres/internal/ceres/problem_impl.h
extern/libmv/third_party/ceres/internal/ceres/program.cc
extern/libmv/third_party/ceres/internal/ceres/program.h
extern/libmv/third_party/ceres/internal/ceres/reorder_program.cc [new file with mode: 0644]
extern/libmv/third_party/ceres/internal/ceres/reorder_program.h [new file with mode: 0644]
extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc
extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h
extern/libmv/third_party/ceres/internal/ceres/single_linkage_clustering.cc
extern/libmv/third_party/ceres/internal/ceres/single_linkage_clustering.h
extern/libmv/third_party/ceres/internal/ceres/small_blas.h
extern/libmv/third_party/ceres/internal/ceres/solver.cc
extern/libmv/third_party/ceres/internal/ceres/solver_impl.cc [deleted file]
extern/libmv/third_party/ceres/internal/ceres/solver_impl.h [deleted file]
extern/libmv/third_party/ceres/internal/ceres/solver_utils.cc [new file with mode: 0644]
extern/libmv/third_party/ceres/internal/ceres/solver_utils.h [new file with mode: 0644]
extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc
extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h
extern/libmv/third_party/ceres/internal/ceres/suitesparse.h
extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc
extern/libmv/third_party/ceres/internal/ceres/trust_region_preprocessor.cc [new file with mode: 0644]
extern/libmv/third_party/ceres/internal/ceres/trust_region_preprocessor.h [new file with mode: 0644]
extern/libmv/third_party/ceres/internal/ceres/types.cc
extern/libmv/third_party/ceres/internal/ceres/visibility.cc
extern/libmv/third_party/ceres/internal/ceres/visibility.h
extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc
extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h

index 8e80352370e46b0bdb129ca926976c784dae93d5..a349d3fca2695cd56b96e9f66a9a2d21072a01a2 100644 (file)
@@ -51,6 +51,7 @@ set(SRC
        internal/ceres/block_random_access_sparse_matrix.cc
        internal/ceres/block_sparse_matrix.cc
        internal/ceres/block_structure.cc
+       internal/ceres/callbacks.cc
        internal/ceres/canonical_views_clustering.cc
        internal/ceres/c_api.cc
        internal/ceres/cgnr_solver.cc
@@ -76,6 +77,8 @@ set(SRC
        internal/ceres/generated/partitioned_matrix_view_d_d_d.cc
        internal/ceres/generated/schur_eliminator_d_d_d.cc
        internal/ceres/gradient_checking_cost_function.cc
+       internal/ceres/gradient_problem.cc
+       internal/ceres/gradient_problem_solver.cc
        internal/ceres/implicit_schur_complement.cc
        internal/ceres/incomplete_lq_factorization.cc
        internal/ceres/iterative_schur_complement_solver.cc
@@ -87,6 +90,7 @@ set(SRC
        internal/ceres/line_search.cc
        internal/ceres/line_search_direction.cc
        internal/ceres/line_search_minimizer.cc
+       internal/ceres/line_search_preprocessor.cc
        internal/ceres/local_parameterization.cc
        internal/ceres/loss_function.cc
        internal/ceres/low_rank_inverse_hessian.cc
@@ -96,9 +100,11 @@ set(SRC
        internal/ceres/partitioned_matrix_view.cc
        internal/ceres/polynomial.cc
        internal/ceres/preconditioner.cc
+       internal/ceres/preprocessor.cc
        internal/ceres/problem.cc
        internal/ceres/problem_impl.cc
        internal/ceres/program.cc
+       internal/ceres/reorder_program.cc
        internal/ceres/residual_block.cc
        internal/ceres/residual_block_utils.cc
        internal/ceres/schur_complement_solver.cc
@@ -107,7 +113,7 @@ set(SRC
        internal/ceres/scratch_evaluate_preparer.cc
        internal/ceres/single_linkage_clustering.cc
        internal/ceres/solver.cc
-       internal/ceres/solver_impl.cc
+       internal/ceres/solver_utils.cc
        internal/ceres/sparse_matrix.cc
        internal/ceres/sparse_normal_cholesky_solver.cc
        internal/ceres/split.cc
@@ -115,6 +121,7 @@ set(SRC
        internal/ceres/suitesparse.cc
        internal/ceres/triplet_sparse_matrix.cc
        internal/ceres/trust_region_minimizer.cc
+       internal/ceres/trust_region_preprocessor.cc
        internal/ceres/trust_region_strategy.cc
        internal/ceres/types.cc
        internal/ceres/visibility_based_preconditioner.cc
@@ -134,13 +141,17 @@ set(SRC
        include/ceres/dynamic_numeric_diff_cost_function.h
        include/ceres/fpclassify.h
        include/ceres/gradient_checker.h
+       include/ceres/gradient_problem.h
+       include/ceres/gradient_problem_solver.h
        include/ceres/internal/autodiff.h
+       include/ceres/internal/disable_warnings.h
        include/ceres/internal/eigen.h
        include/ceres/internal/fixed_array.h
        include/ceres/internal/macros.h
        include/ceres/internal/manual_constructor.h
        include/ceres/internal/numeric_diff.h
        include/ceres/internal/port.h
+       include/ceres/internal/reenable_warnings.h
        include/ceres/internal/scoped_ptr.h
        include/ceres/internal/variadic_evaluate.h
        include/ceres/iteration_callback.h
@@ -149,13 +160,13 @@ set(SRC
        include/ceres/loss_function.h
        include/ceres/normal_prior.h
        include/ceres/numeric_diff_cost_function.h
-       include/ceres/numeric_diff_functor.h
        include/ceres/ordered_groups.h
        include/ceres/problem.h
        include/ceres/rotation.h
        include/ceres/sized_cost_function.h
        include/ceres/solver.h
        include/ceres/types.h
+       include/ceres/version.h
        internal/ceres/array_utils.h
        internal/ceres/blas.h
        internal/ceres/block_evaluate_preparer.h
@@ -167,6 +178,7 @@ set(SRC
        internal/ceres/block_random_access_sparse_matrix.h
        internal/ceres/block_sparse_matrix.h
        internal/ceres/block_structure.h
+       internal/ceres/callbacks.h
        internal/ceres/canonical_views_clustering.h
        internal/ceres/casts.h
        internal/ceres/cgnr_linear_operator.h
@@ -193,6 +205,7 @@ set(SRC
        internal/ceres/execution_summary.h
        internal/ceres/file.h
        internal/ceres/gradient_checking_cost_function.h
+       internal/ceres/gradient_problem_evaluator.h
        internal/ceres/graph_algorithms.h
        internal/ceres/graph.h
        internal/ceres/implicit_schur_complement.h
@@ -207,6 +220,7 @@ set(SRC
        internal/ceres/line_search_direction.h
        internal/ceres/line_search.h
        internal/ceres/line_search_minimizer.h
+       internal/ceres/line_search_preprocessor.h
        internal/ceres/low_rank_inverse_hessian.h
        internal/ceres/map_util.h
        internal/ceres/minimizer.h
@@ -217,10 +231,12 @@ set(SRC
        internal/ceres/partitioned_matrix_view_impl.h
        internal/ceres/polynomial.h
        internal/ceres/preconditioner.h
+       internal/ceres/preprocessor.h
        internal/ceres/problem_impl.h
        internal/ceres/program_evaluator.h
        internal/ceres/program.h
        internal/ceres/random.h
+       internal/ceres/reorder_program.h
        internal/ceres/residual_block.h
        internal/ceres/residual_block_utils.h
        internal/ceres/schur_complement_solver.h
@@ -230,7 +246,7 @@ set(SRC
        internal/ceres/scratch_evaluate_preparer.h
        internal/ceres/single_linkage_clustering.h
        internal/ceres/small_blas.h
-       internal/ceres/solver_impl.h
+       internal/ceres/solver_utils.h
        internal/ceres/sparse_matrix.h
        internal/ceres/sparse_normal_cholesky_solver.h
        internal/ceres/split.h
@@ -239,6 +255,7 @@ set(SRC
        internal/ceres/suitesparse.h
        internal/ceres/triplet_sparse_matrix.h
        internal/ceres/trust_region_minimizer.h
+       internal/ceres/trust_region_preprocessor.h
        internal/ceres/trust_region_strategy.h
        internal/ceres/visibility_based_preconditioner.h
        internal/ceres/visibility.h
index c9f5b3426bc1e40f9b4ce2de6af72450350147b2..cd168a44b356b480051fdfa9abe64422cf082bdd 100644 (file)
-commit 8c62487e437b91d3d354cd1ae8957e43fe540732
+commit d3ecd18625ba260e0d00912a305a448b566acc59
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Fri May 16 09:44:18 2014 -0700
+Date:   Tue Sep 23 10:12:42 2014 -0700
 
-    Preparations for 1.9.0 release.
+    Add an explicit include for local_parameterization.h
     
-    Version bump.
-    minor docs update.
+    Thanks to cooordz for reporting this.
     
-    Change-Id: I2fbe20ba4af6b2e186fe244c96ce6d6464fe0469
+    Change-Id: I7d345404e362a94ff1eb433ad6b9dcc4960ba76d
 
-commit 0831275a78ab65e4c95979598cb35c54d03d3185
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Fri May 16 08:17:54 2014 -0700
+commit 5dd76869cf45122c79579423f09e0de08cf04092
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date:   Fri Sep 19 16:08:25 2014 +0100
 
-    Documentation update.
+    Fix unused-function warning with Eigen < 3.2.2.
     
-    1. Update iOS build instructions.
-    2. Update version history.
+    - CreateBlockJacobian() is only ever used when Eigen >= 3.2.2 is
+      detected, but was previously defined whenever CERES_USE_EIGEN_SPARSE
+      was defined with no check on the Eigen version.
+    - This resulted in an unused-function compile warning that became an
+      error due to -Werror, preventing compilation when using Eigen < 3.2.2.
     
-    Change-Id: I49d62e86ecff39190b50c050cb12eef4e2773357
+    Change-Id: I24628ff329f14b087ece66bf2626bdc0de4ba224
 
-commit c7c7458625996a20203f1366d11bd701e5fb621b
-Author: Jack Feng <jackfengji@gmail.com>
-Date:   Mon May 12 10:23:56 2014 +0800
+commit 820cb7b14831aa03eca1e8186000cebfdf0a42f3
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date:   Wed Sep 17 09:46:08 2014 -0700
 
-    add support for building for ios
+    Add solver_utils.cc to Android.mk
     
-    use ios-cmake to build for ios
-    
-    Change-Id: I6b17c33339f3121322a4004d79629b22a62f7a94
+    Change-Id: I358522971711280f4362a1fa39b1568160e21e63
 
-commit 36c2ce87d13b9b7123bd0473b8b45fb3b6ae4271
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date:   Mon Jan 13 21:18:08 2014 +0600
+commit 092b94970a073f8b47179d96160226fc19095898
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date:   Fri Sep 5 11:56:29 2014 -0700
 
-    Libmv 2D homography estimation example application
+    Add GradientProblem and GradientProblemSolver.
     
-    Add an example application of homography matrix estimation
-    from a 2D euclidean correspondences which is done in two
-    steps:
+    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.
     
-    - Coarse algebraic estimation
-    - Fine refinement using Ceres minimizer
+    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.
     
-    Nothing terribly exciting apart from an example of how to
-    use user callbacks.
+    Corresponding to it, a GradientProblemSolver and its associated
+    options and summary structs are introduced too.
     
-    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.
+    An example that uses the new API to find the minimum of Rosenbrock's
+    function is also added.
     
-    Change-Id: I60c8559cb10b001a0eb64ab71920c08bd68455b8
+    Change-Id: I42bf687540da25de991e9bdb00e321239244e8b4
 
-commit d99a3a961e4a6ff7218d0ab749da57cf1a1677bd
-Author: Björn Piltz <bjornpiltz@gmail.com>
-Date:   Wed May 7 14:59:12 2014 +0200
+commit 6c45d6b891aac01489b478a021f99081c61792cb
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date:   Thu Sep 11 07:48:30 2014 -0700
 
-    Separate PUBLIC and PRIVATE library dependencies
-    Do not propagate 3d party libs through
-    IMPORTED_LINK_INTERFACE_LIBRARIES_[DEBUG/RELEASE] mechanism
-    when building shared libraries. SuiteSparse, lapack & co
-    are considered private. Glog still gets propagated since
-    it is part of the public interface. See documentation of
-    TARGET_LINK_LIBRARIES().
+    Add more inspection methods to Problem.
+    
+    Problem::GetCostFunctionForResidualBlock
+    Problem::GetLossFunctionForResidualBlock
+    
+    are added, so that users do not have to maintain this mapping
+    outside the Problem.
     
-    Change-Id: If0563b0c705b102876f5190e9a86694d10f79283
+    Change-Id: I38356dfa094b2c7eec90651dafeaf3a33c5f5f56
 
-commit 1c089e8453583876f417b214f76a5863d7694986
+commit 6ad9b8e2ae66c9009441d0f9304486ec8dfa9a6a
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Tue May 13 16:58:25 2014 -0700
+Date:   Tue Sep 9 14:29:28 2014 -0700
 
-    Notational fix in modeling.rst by William Rucklidge.
+    Ignore row/column blocks structure when using dynamic sparsity
     
-    Change-Id: Iffa127541380fcc32da13fe4ac474692e1e3d0ec
+    The row/column blocks can be huge when using dynamic sparsity. This
+    can result in very large memory usage when augmenting the jacobian
+    with the LM diagonal.
+    
+    Thanks to Mingsong Dou for reporting this.
+    
+    Change-Id: I6aa140ceefa98389ae17958f89ca76e0c76f95b8
 
-commit 082d9e2a1b43b26a81157a6c711de0ff34c40ba4
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Mon May 12 20:41:27 2014 -0700
+commit 7e43460d42e20be1ba13121655dbbfd0d1c751ae
+Author: Martin Baeuml <baeuml@gmail.com>
+Date:   Mon Sep 8 16:49:06 2014 +0200
 
-    Add iOS.cmake from the ios-cmake project.
+    Fix a few typos in the documentation.
     
-    URL: https://github.com/cristeab/ios-cmake
-    Commit: 86dc085f0d5ed955cd58e2657cc3efc7c1aabbc8
-    
-    Change-Id: I8fe6023d4cb6655b5a724e8b695fdae87ce3b685
+    Change-Id: I541db56b2b81ae758e233ce850d78c3cbb4b6fa3
 
-commit a97056c9752fe7223c8560da58862ecb1fd241ad
+commit 1aef66eeae7042902655a11b0d6a1a32900abb7b
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Tue May 13 16:45:36 2014 -0700
+Date:   Sun Sep 7 21:18:44 2014 -0700
 
-    Various documentation fixes from William Rucklidge.
+    Remove errant space.
     
-    Change-Id: I102e98f41f4b5fe2a84d1224d5ed7517fdfdb022
+    Change-Id: Iedc06960417a9b938d57f623b4beb87a98e3d081
 
-commit 2f8fb218f0a08102231ace07ef02b34b4aad7336
-Author: Alex Stewart <alexs.mac@gmail.com>
-Date:   Tue May 13 20:57:39 2014 +0100
+commit 89080ab153a33008782759187fa8e9af7d2f83f1
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date:   Sat Sep 6 21:13:48 2014 -0700
 
-    Adding function to update CMake cache variables and preserve help.
+    Add LocalParameterization::MultiplyByJacobian.
     
-    - Previously we were replicating the same two lines to update a cache
-      variable whilst preserving its help string.
-    - This commit adds a function which wraps up this common operation into
-      a single line.
+    This is needed to efficiently support LocalParameterization objects
+    in GradientProblemSolver.
     
-    Change-Id: Ic78a5adf5d59262bbbcec1e353ded7620391e862
+    Change-Id: Ic7b715b8be694b099dc95d6707a67474297533e6
 
-commit 8f4dcb25f1be74a8c12c0f9eeb67b6b0755563f5
+commit d76da16f49d419ae3664ca1bdc2286c1ea78ebed
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Tue Apr 29 21:40:57 2014 -0700
+Date:   Sun Sep 7 18:42:49 2014 -0700
 
-    Documentation update.
+    Move some routines to solver_utils.h/cc
     
-    Update modeling.rst and solving.rst to reflect
-    changes to the API.
+    This moves a couple of routines from solver.cc into solver_utils.h/cc
+    so that they can also be used by the upcoming GradientProblemSolver.
     
-    Change-Id: Id1a8adfed1486f08e5fd67c5af2d29708a26490c
+    Change-Id: I627b32ad3dc639422aacde78a8e391459d947e99
 
-commit d48e7050225730f61eaef851def5b43bc439e991
-Author: Alex Stewart <alexs.mac@gmail.com>
-Date:   Sat May 10 08:58:58 2014 +0100
+commit cbf03ac292a0c0e9e6b7fcc1b08b67e95965922f
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date:   Sat Sep 6 21:07:08 2014 -0700
 
-    Configure config.h and include it from the build directory.
-    
-    - Previously we overwrote the default (empty) config.h in the source
-      tree with a configured config.h, generated using the current compile
-      options.
-    - This was undesirable as it could lead to inadvertant commits of the
-      generated config.h.
+    Make LineSearchMinimizer consistent with TrustRegionMinimizer.
     
-    - This patch moves the default config.h to <src>/config/ceres/internal,
-      separate from the other headers, thus if Ceres is compiled without
-      CMake this directory will now also have to be included.  This
-      directory is _not_ added to the CMake include directories for Ceres
-      (thus the default config.h is never used when compiling with CMake).
-    - When using CMake, the generated config.h is now placed in
-      <build>/config/ceres/internal, which is in turn added to the include
-      directories for Ceres when it is compiled, and the resulting config.h
-      is copied to ceres/internal when installed.
+    Change the logic for how IterationSummary objects are added to
+    Summary::iterations to match the one in TrustRegionMinimizer.
     
-    Change-Id: Ib1ba45e66e383ade2ebb08603af9165c1df616f2
+    Change-Id: I57851ad8294e58f83b9115cca9c24695d86ee92a
 
-commit 11c496164ffe9809306945c2b81276efcd51533d
+commit f04c32319751e1efd610acd3699bca0a6dd6c6d1
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Fri May 9 16:27:03 2014 -0700
+Date:   Sat Sep 6 21:05:41 2014 -0700
 
-    Fix 80cols violation in local_parameterization.h
+    Fix some obsolete documentation in CostFunction::Evaluate
     
-    Change-Id: I07f59baa9e4aba7c5ae028f0c144ea9ad153d49a
+    Change-Id: I1d7ee5c596fbf6a4d886dce5b989c8eb18af2dce
 
-commit af3154422b63b7792ecd23b00ca1a0c003764dae
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Fri May 9 05:45:03 2014 -0700
+commit 9263547c02a1807532b159c217e7acd124d3db10
+Author: Johannes Schönberger <hannesschoenberger@gmail.com>
+Date:   Sat Sep 6 17:26:15 2014 -0400
 
-    Add Alex Stewart as a maintainer.
+    Fix CG solver options for ITERATIVE_SCHUR, which did not copy min_num_iterations
     
-    Update contributing.rst to mention Alex
-    as one of the people who can be added
-    as a reviewer.
+    Change-Id: If31bc53b49ec20426fd438b79b8fa1f69d11e861
+
+commit b41f048256d1a8184cbe874b5a96dffa7fa4630d
+Author: Martin Baeuml <baeuml@gmail.com>
+Date:   Fri Sep 5 15:03:32 2014 +0200
+
+    Remove obsolete include of numeric_diff_functor.h.
     
-    Change-Id: I30ff3e635e8c419e11e8f20394aaea5f284a10d5
+    numeric_diff_functor.h was removed and does not exist anymore.
+    
+    Change-Id: I07bf04bf81142551e867b95b83a0653e11cad54c
 
-commit ea765850685f1ff0431da5212656378fc20d3673
-Author: Alex Stewart <alexs.mac@gmail.com>
-Date:   Wed May 7 20:46:17 2014 +0100
-
-    Adding autogenerated Ceres config.h to #define Ceres compile options.
-    
-    - 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
-
-commit cbf955474acf8f275b272da6ff5acd3a629cc806
-Author: Björn Piltz <bjornpiltz@gmail.com>
-Date:   Wed May 7 17:10:15 2014 +0200
+commit b7fb6056a717cc3c372cfb7115c527ee8bc05ddb
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date:   Wed Sep 3 11:19:02 2014 -0700
 
-    Fixes swapped verboselevel and condition.
+    Remove NumericDiffFunctor.
+    
+    Its API was broken, and its implementation was an unnecessary
+    layer of abstraction over CostFunctionToFunctor.
     
-    Change-Id: I296d86e6bbf415be4bfd19d6a0fe0963e3d36d74
+    Change-Id: I18fc261fc6a3620b51a9eeb4dde0af03d753af69
 
-commit 3209b045744ea31f38d74bd9e9c8f88e605e7f76
-Author: Björn Piltz <bjornpiltz@gmail.com>
-Date:   Wed May 7 17:02:27 2014 +0200
+commit 175fa8ff09049110a8509409f60cee5fd52cdbe6
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date:   Tue Sep 2 06:49:08 2014 -0700
 
-    Fixed warning : 'va_copy' : macro redefinition
-    MSVC 2013 has got va_copy
-    Compare
-    http://msdn.microsoft.com/en-us/library/kb57fad8(v=vs.110).aspx
-    and
-    http://msdn.microsoft.com/en-us/library/kb57fad8.aspx.
+    CostFunctionToFunctor allows dynamic number of residuals.
+    
+    The code itself was perfectly capable of handling residuals, but there
+    was an overly strict runtime check that had to be removed.
     
-    Change-Id: If0937c76e8d250cde4b343844f3d35c980bf0921
+    Thanks to Domink Reitzle for reporting this.
+    
+    Change-Id: I6a6d000a7c5203dd5945a61b4caeda1b8aeb09c9
 
-commit 1df2f0f5d704f0cc458cf707e2602d495979e3c6
-Author: Björn Piltz <bjornpiltz@gmail.com>
-Date:   Wed May 7 11:10:30 2014 +0200
+commit 70ace0d5a5601901288974fcf27919754260cf0e
+Author: Johannes Schönberger <hannesschoenberger@gmail.com>
+Date:   Sat Aug 30 15:52:34 2014 -0400
 
-    Removed MSVC warnings
-    These are warnings which show up when using Ceres.
+    Fix max. linear solver iterations in ConjugateGradientsSolver
     
-    Change-Id: Id1f382f46b8a60743f0b12535b5b3cdf46f988e0
+    Change-Id: Ice0cef46441dbc1c121eeb42113667a46c96936f
 
-commit eca7e1c635581834c858794e09c1e876323b7775
+commit c5d8d0680250f5eb554577d30d28fc805b03fab9
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Tue May 6 10:16:19 2014 -0700
+Date:   Fri Aug 29 20:31:19 2014 -0700
 
-    Remove BlockRandomAccessCRSMatrix.
+    Fix a unused function error with Eigen version 3.2.1 or less.
     
-    It is not used anywhere.
+    Thanks to Johannes Schoenberger  for reporting this.
     
-    Change-Id: I2a8ebbdacf788582f21266825ead3f76646da29e
+    Change-Id: Ie17d28f2a68734a978a8c95007724bc4055de43a
 
-commit 7088a08f5d9e04e75a5a4c3823ef7927e13ff0e4
+commit 0e1cc2a55488e4cf381833baaa3531c02ce9d69e
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Mon May 5 09:02:05 2014 -0700
+Date:   Fri Aug 29 09:16:56 2014 -0700
 
-    Fix some 80col violations and reflow the comments in cmake.in file.
+    Fix the build on Eigen version 3.2.1 and older.
     
-    Change-Id: I4c65c89b794845aeef69159a03350c727e2ee812
+    Change-Id: I18f5cb5d42113737d7b8f78a67acee28bd5b3e08
 
-commit 95cce0834d5a2d72568e6d2be968a51c244c2787
+commit 5f96c62b56222f27e606f2246a8a16b6942af8d1
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Mon May 5 08:54:50 2014 -0700
+Date:   Thu Aug 28 23:06:17 2014 -0700
 
-    Remove some errant tabs.
+    Add Block AMD ordering for SPARSE_SCHUR + EIGEN_SPARSE.
+    
+    Ordering routines for the Schur complement when using EIGEN_SPARSE.
+    Also integration into SchurComplementSolver.
     
-    Change-Id: Ie1f7051e99bcb15ad068711b68a9d8f317b12ed7
+    Part of this CL is also a refactoring of the block jacobian matrix
+    construction.
+    
+    Change-Id: I11d665cc7d4867c64190e6fed1118f4d2e13d59b
 
-commit a536ae76dfa2dbe2bc487900b98cf6c15276c649
+commit 7344626c04d19ca1dc4871c377c4422c744b1bca
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Sun May 4 21:18:42 2014 -0700
+Date:   Thu Aug 28 22:03:09 2014 -0700
 
-    Lazily initialize the bounds arrays in ParameterBlock.
-    
-    Problems that do not use bounds do not have to pay the
-    price of storing bounds constraints.
+    Let EIGEN_SPARSE + SPARSE_NORMAL_CHOLESKY use block AMD.
     
-    Also replace the raw pointer access to the upper and
-    lower bounds arrays with accessors which hides the
-    lazy initialization from the user.
+    Modify SparseNormalCholeskySolver to use a pre-ordered Jacobian
+    matrix.
     
-    Change-Id: I0325a35de9c29f853559f891e32e7c777686e537
+    Change-Id: Ib4d725d7a2d7bb94ea76dbb3a9b172784dbc8ea0
 
-commit 633b50b7af9841607c07133f585e131fba7de177
+commit 9f7032369ea4e432f0fb507cb6d2209741ee6946
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Fri May 2 22:46:20 2014 -0700
+Date:   Thu Aug 28 21:46:43 2014 -0700
 
-    Add the (2,4,8) template specialization.
+    Block AMD for SparseNormalCholesky + EIGEN_SPARSE.
     
-    Change-Id: I058bcebdd1725031d573404133b184d6f27dc005
+    This is just the reordering routine. The integration with
+    SparseNormalCholesky shall happen in a subsequent CL.
+    
+    Change-Id: I39ddc32aa66b11c368faf75404850fa0ae0d2b3a
 
-commit 5ffe06019a6c741ee7edc940ffeeceaaeabfa05d
-Author: Alex Stewart <alexs.mac@gmail.com>
-Date:   Thu May 1 12:06:46 2014 +0100
+commit b9331cd4077100d645be22a912d5743eeda72878
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date:   Thu Aug 28 14:42:27 2014 -0700
 
-    Export Ceres compile definitions to targets compiled against Ceres.
+    Cleanup reorder_program.cc
     
-    - Previously all Ceres compile definitions were private to Ceres, that
-      is they were not exported to users via the CMake export mechanism.
-    - Now that we use compile definitions in public (installed) Ceres
-      headers, we need to export the Ceres compile definitions.
-    - If we did not do this, then the client's code 'see's' a different
-      version of the Ceres headers to those which were in fact compiled,
-      or in the case of shared_ptr, may not find the required header.
+    Program::SetParameterOffsetsAndIndex() was being called willy nilly.
+    Now the invariant is that any function that actually reorders the
+    program, updates the offsets and indices.
     
-    - This patch makes use of the new, in CMake 2.8.11, function:
-      target_compile_definitions() to export all of the Ceres compile
-      definitions using CMake's export functionality.
-    - For CMake versions < 2.8.11, we have to use the blunter instrument of
-      calling add_definitions() in CeresConfig.cmake (invoked by a call to
-      find_package(Ceres)).  This is messy because it ends up adding the
-      Ceres compile definitions to any target declared in the user's code
-      after the call to find_package(Ceres).  Although this should do no
-      harm as all of our defines are prefaced with CERES_, so any
-      unintentional name clashes are unlikely.
+    Also the logic around handling EIGEN_SPARSE has been simplified in
+    anticipation of the block AMD code that is forthcoming.
     
-    Change-Id: I5dea80949190eaf4fb08ea4ac568ce28c32dd4e0
+    Last but not the least, num_eliminate_blocks, which is a rather
+    cryptic name to begin with has been replaced by the more meaningful
+    size_of_first_elimination_group.
+    
+    Change-Id: I77e684f699a93b53e76aa406d64f40f8704df813
 
-commit 0e811b0881f1f21df0ae04fd745ae4ba5189cac1
+commit 79491a3f4a3939a3cce4644da7a998b7782b963a
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Thu May 1 07:54:12 2014 -0700
+Date:   Thu Aug 28 13:57:50 2014 -0700
 
-    Fix a bug in Minimizer::RunCallbacks.
+    Solver::FullReport now reports build config.
+    
+    The header of Summary::FullReport now looks like
     
-    Solver::Summary::message was not being updated when the solver
-    terminated because of a user's iteration callback indicating
-    success or failure.
+    Solver Summary (v 1.10.0-suitesparse-cxsparse-lapack-no_openmp)
     
-    Thanks to Sergey Sharybin for reporting this.
+                                         Original                  Reduced
+    Parameter blocks                        22122                    22122
+    Parameters                              66462                    66462
+    Residual blocks                         83718                    83718
+    Residual                               167436                   167436
     
-    Change-Id: I27e6e5eed086920ddf765461b0159417ac79d7b3
+    Change-Id: Id1b81bbf90ba412d19e2dd3687eeb9d372b72c1b
 
-commit 31b503792611d2119bb1acb3528fc8d58c5bd029
+commit 48068c753e91d77f6c96ef2d529a27ef8ee3947c
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Wed Apr 30 15:02:38 2014 -0700
+Date:   Thu Aug 28 13:03:40 2014 -0700
 
     Lint cleanup from William Rucklidge.
     
-    Change-Id: If545f114c1a2b07edd660a3c71ecfc16ffa25e43
+    Change-Id: Ie0e0aa58440be7a4f67dcd633dbb6f1bb0c051a8
 
-commit 15c1210a8bdf3e936b4ef600d75f0fbb70878fb5
+commit 6a51b135e6298e8ba44a58cc2b54a170ab61a82f
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Tue Apr 29 08:12:19 2014 -0700
+Date:   Thu Aug 28 10:48:29 2014 -0700
 
-    Lint cleanup from Jim Roseborough.
+    Fix solver_test.cc
+    
+    When Eigen is not installed, Solver::IsValid was not detecting
+    it correctly.
     
-    Change-Id: I53f4e0d020602443b397387b8c5908f25649403d
+    Change-Id: Id285a84d829a9e20bc5de663adfca66ac31e08f3
 
-commit b1668067f1c97520d5d28eecf2c11d2afc1b01b3
+commit 62a8d64453ee41dae56710a4eead3fadf2fe1a4e
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Tue Apr 29 08:12:19 2014 -0700
+Date:   Wed Aug 27 22:54:00 2014 -0700
 
-    Variety of changes to documentation and example code.
+    Expand check for lack of a sparse linear algebra library.
     
-    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.
+    The LinearSolver factory was creating a NULL linear solver
+    if only Eigen's sparse linear algebra backend was available.
     
-    Change-Id: I8de386e5278a008c84ef2d3290d2c4351417a9f1
+    Thanks to Michael Samples and Domink Reitzle for reporting this.
+    
+    Change-Id: I35e3a6c0fd0da2a31934adb5dfe4cad29577cc73
 
-commit 658407dacc351a999206980fbb3265099e50e7a3
+commit 12eb389b4ec4113a2260c1a192a1d3f8d1b6a2d3
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Mon Apr 28 13:25:17 2014 -0700
+Date:   Wed Aug 27 22:18:33 2014 -0700
 
-    Add missing template specializations to the NDK build.
+    Fix Eigen Row/ColMajor bug in NumericDiffCostFunction.
+    
+    If the parameter block size is 1, asking Eigen to create
+    a row-major matrix triggers a compile time error. Previously
+    we were handling the case where the number of rows in the
+    jacobian block was known statically, but the problem is present
+    when the nummber of rows is dynamic.
+    
+    This CL fixes this problem.
     
-    Change-Id: I42bb6c3bd47648050298472af80333aa900e79bf
+    Thanks to Dominik Reitzle for reporting this.
+    
+    Change-Id: I99c3eec3558e66ebf4efa51c4dee8ce292ffe0c1
 
-commit 5d7eed87b47871bc882af765188fa4fbca976855
-Author: Björn Piltz <bjornpiltz@gmail.com>
-Date:   Wed Apr 23 22:13:37 2014 +0200
+commit 6c25185bb1643d8d0f3d8e1a7b82a058156aa869
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date:   Thu Aug 28 16:07:51 2014 +0100
 
-    Suppport for MSVC DLLs.
+    Fix crash in Covariance if # threads > 1 requested without OpenMP.
+    
+    - Previously if options.num_threads > 1 was given to Covariance compiled
+      without OpenMP, a CHECK() would be triggered in program_evalutor.
     
-    Change-Id: Ibbcc4ba4e59f5bbf1cb91fe81c7d3b9042d03493
+    Change-Id: Iaade4f5ed5326b0c59a7014c750c41ee026e1124
 
-commit c830820a5c2be0d0cecb0822f2cff8b4ffe88f36
+commit 6f89d850fb4ace0104abccf467c4fe37ad378b79
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Mon Apr 28 10:28:24 2014 -0700
+Date:   Wed Aug 27 11:51:50 2014 -0700
 
-    Add missing files to Android.mk
+    Further build breakage fixes.
+    
+    1. Allow the minimum number of linear solver iterations to be zero.
+    2. Fix conjugate gradients solver's iteration loop to be sane again.
     
-    Change-Id: Ibdf577c592bcde0fe5c2ce343ed8e9028b82af8f
+    Change-Id: I8594815fec940c2b30e28eb58ec5d8baacf13dae
 
-commit ceb7a3beaad140762b499f9a306fd7230715941a
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date:   Mon Apr 28 13:50:09 2014 +0600
+commit dd596d0f0d6d08951efc2c11a639b546db2080c6
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date:   Wed Aug 27 11:26:50 2014 -0700
 
-    Fix compilation error when using G++ compiler
+    Fix the broken build.
     
-    This compiler defines shared_ptr in std::tr1 namespace, but
-    for this <tr1/memory> is to be included. Further, this compiler
-    also does have <memory> header which confused previous shared
-    pointer check.
+    Change-Id: I083cf1cca1bf4cca956193022d450364e73f833a
+
+commit d906afae22b05b9b9a9a2657924f4c0bf1a9b5ea
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date:   Mon Aug 25 22:32:38 2014 -0700
+
+    A number of bug fixes.
     
-    Simplified logic around defines now, so currently we've got:
-    - CERES_TR1_MEMORY_HEADER defined if <tr1/memory> is to be
-      used for shared_ptr, otherwise <memory> is to be used.
-    - CERES_TR1_SHARED_PTR defined if shared_ptr is defined in
-      std::tr1 namespace, otherwise it's defined in std namespace.
+    1. Fix a build breakage in graph_test.
+    2. Respect Solver::Options::min_num_linear_solver_iterations in
+       conjugate_gradients_solver.cc
     
-    All the shared_ptr checks are now moved to own file FindSharedPtr
-    which simplifies main CMakeLists.
+    Thanks to Johannes Schönberger for reporting these.
     
-    Change-Id: I558a74793baaa0bd088801910a356be4ef17c31b
+    Change-Id: Ib32e3929bf5d92dd576ae5b53d4d88797095136e
 
-commit 02db9414fb6739857a37e268500083a0546cd0a3
+commit dab955928c6d0942d6acc5b5f1c4c11260d0767d
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Mon Apr 28 08:32:51 2014 -0700
+Date:   Sun Aug 17 13:14:50 2014 -0700
 
-    Fix the documentation for RandNormal.
+    Add an unweighted graph.
+    
+    Rename Graph -> WeightedGraph.
+    Add a new Graph class, which is cheaper to construct and
+    work with if the weights are not needed.
     
-    As pointed out by Jim Roseborough, this is the Marsaglia Polar
-    method and not the Box-Muller method.
+    This cuts down the cost of building the Hessian graph
+    significantly.
     
-    Change-Id: Id5332bcd4b4c23a3885cc296729b44eaa5edd0a8
+    Change-Id: Id0cfc81dd2c0bb5ff8f63a1b55aa133c53c0c869
 
-commit 32530788d08c53f8d2c8a5f9bd61aa60a23d6e03
-Author: Richard Stebbing <richie.stebbing@gmail.com>
-Date:   Sat Apr 26 07:42:23 2014 +0100
+commit a0c282adbd268c2ad82551fab31fe1cf8d0c4282
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date:   Sun Aug 24 22:19:03 2014 -0700
 
-    Add dynamic_sparsity option.
+    Add EIGEN_STRONG_INLINE annotation to jet.h
     
-    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.
+    This improves performance when using MSVC on Windows. On GCC
+    there will be no effect.
     
-    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.
+    Change-Id: I555a81ff6823c2855d64773073f75af50c48d716
+
+commit 20de0a7793c574e964350a623446136889f74632
+Author: Björn Piltz <bjornpiltz@gmail.com>
+Date:   Mon Aug 25 17:05:54 2014 +0200
+
+    Fixed Malformed regex
     
-    Changes that were required to make this extension were adding the
-    SetMaxNumNonZeros method to CompressedRowSparseMatrix and adding
-    a JacobianFinalizer template parameter to the ProgramEvaluator.
+    I got the following error with MSVC:
+    Syntax error at index 9 in simple regular expression "NumGroups()": '(' is unsupported.
     
-    Change-Id: Ia5a8a9523fdae8d5b027bc35e70b4611ec2a8d01
+    Change-Id: Id1952831d81d3eb5d73bbed8c311914c4c8ab51f
 
-commit 2569076ff0bf8ffb3938da8b5df7edc4883aa053
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Fri Apr 25 23:54:48 2014 -0700
+commit ccf8aea988269841d84d746e52164d5056c67a10
+Author: Björn Piltz <bjornpiltz@gmail.com>
+Date:   Mon Aug 25 16:16:01 2014 +0200
 
-    More NDK fixes.
+    Fixed MSVC error C2124: divide or mod by zero
     
-    Fix variable names in port.h and fix fpclassify when
-    using gnustl. This was tested by switching to gnustl
-    in the JNI build.
+    Alternatively, if quiet_NaN is not available on all platforms a workaround would be:
+        volatile double zero = 0.0;
+        double x = 1.0/zero;
+    The 'volatile' is needed to shut up "warning C4723: potential divide by 0".
     
-    Thanks to Carlos Hernandez for suggesting the gnustl fixes.
-    
-    Change-Id: I690b73caf495ccc79061f45288e416da1604cc72
+    Change-Id: If2bbdab8540595aa2e0079e1eb6b6fed6d4a6ef7
 
-commit e55596f8860a09b12b5e1f949237f15357c1ac59
+commit 8de27be218d42b282d7f15867733ad07058b0887
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Fri Apr 25 16:17:19 2014 -0700
+Date:   Tue Aug 19 08:22:40 2014 -0700
 
-    Change the defaults for shared_ptr.
-    
-    By default shared_ptr is now assumed to be
-    in the standard <memory> header and in the
-    std namespace.
+    Fix a bug in TrustRegionPreprocessor
     
-    Previously the way the ifdefs were structured if the appropriate
-    variable was not defined, it would default to <t1/memory>.
+    TrustRegionPreprocessor was not setting Minimizer::Options::is_constrained.
+    This meant that the line search for bounds constraints was not being
+    invoked for bounds constrained problems.
     
-    The new defaults are more future proof.
+    And some minor lint cleanup.
     
-    Change-Id: If457806191196be2b6425b8289ea7a3488a27445
+    Change-Id: I18852cfaf1b33fd90b7d8c196f2063c128126658
 
-commit bb05be341b8436f611e4b69954a529edcca5b577
+commit 1745dd615b3897a3ef9896acfdba67eee1739bf4
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Sun Apr 13 14:22:19 2014 -0700
+Date:   Thu Jun 5 21:30:13 2014 -0700
 
-    Solver::Options uses shared_ptr to handle ownership.
+    Refactor SolverImpl.
     
-    Solver::Options::linear_solver_ordering and
-    Solver::Options::inner_iteration_ordering
-    were bare pointers even though Solver::Options took ownership of these
-    objects.
+    Replace SolverImpl with
     
-    This lead to buggy user code and the inability to copy Solver::Options
-    objects around.
+     a. A minimizer specific preprocessor class.
+     b. A generic Solve function inside solver.cc
+     c. Presummarize and Postsummarize functions to handle
+        updates to the summary object.
     
-    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 existing SolverImpl class was a mixture of the above three
+    things and was increasingly complicated code to follow. This change,
+    breaks it into its three separate constituents, with the aims of
+    better separation of concerns and thus better testability and
+    reliability.
     
-    The Android.mk and Application.mk files have also been updated
-    to use a newer NDK revision which ships with LLVM's libc++.
+    The call to Solver::Solve() now consists of
     
-    Change-Id: I25161fb3ddf737be0b3e5dfd8e7a0039b22548cd
-
-commit 8e0991381ea3a2baddea017cd07b333f0c5de595
-Author: Joydeep Biswas <joydeep.biswas@gmail.com>
-Date:   Tue Apr 22 10:40:47 2014 -0400
-
-    Added a simplified robotics example for DynamicAutoDiffCostFunction.
+    1. Presummarize - summarize the given state of the problem and solver
+       options.
+    2. Preprocess - Setup everything that is needed to call the minimizer.
+       This includes, removing redundant parameter and residual blocks,
+       setting up the reordering for the linear solver, creating the
+       linear solver, evaluator, inner iteration minimizer etc.
+    3. Minimize.
+    4. Post summarize - summarize the result of the preprocessing and the
+       solve.
     
-    Change-Id: I9520e0a9a8d9743285c5114523fbafa6ffa5b0bd
+    Change-Id: I80f35cfc9f2cbf78f1df4aceace27075779d8a3a
 
-commit cc9d3bba1008066e51502cabd956985c6bdedfe8
+commit bd90384226a7f8629467f72fc410a9e8086a2dff
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Fri Apr 18 22:58:09 2014 -0700
+Date:   Mon Aug 18 11:27:06 2014 -0700
 
-    Remove a comment from conf.py
+    Lint comments from William Rucklidge.
+    
+    Also some minor refactoring of the trust_region_preprocessor_test.cc
     
-    Change-Id: I675f7e8fc5dd2143eab74901bc7241e02e37285f
+    Change-Id: Ica28002254c95722faf93a7ef35bf3deab557f0b
 
-commit c4cd29dd7c80ade5b3ac7a1f6ee7df22c8869ab5
+commit 3150321db4a0cb1bb4894961a030d95dacae3591
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Wed Apr 16 23:40:12 2014 -0700
+Date:   Tue Aug 12 22:46:51 2014 -0700
 
-    Merge landing page with introduction.
-    
-    The existing introduction was a bit redundant and also
-    was not really an introduction. Also updated the build
-    instructions to reflect the new reality on Mac OSX.
+    Preprocessor for the LineSearchMinimizer.
     
-    Also updated the beginning of the tutorial to be a bit
-    gentler and updated the history to be more consistent
-    
-    Change-Id: Ife38c1949252cf9f4c6301856957f2d38365f313
+    Change-Id: Ieb5dfe1c0b96ef323c1130edd0c3a8a8b2c644cc
 
-commit 46ccfb376ac52ac159f9187e0f7384ef68c1cbdd
+commit f7da411ef0d0067e269629887d64cdb769368800
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Sat Apr 12 21:56:51 2014 -0700
+Date:   Thu Aug 7 14:30:33 2014 -0700
 
-    Cleanup block_structure.h/cc
+    Preprocessor for the TrustRegionMinimizer.
     
-    1. Remove obsolete Proto conversion functions.
-    2. Fix a strict weak ordering bug.
+    1. Base class for preprocessors.
+    2. A preprocessor for problems that will be solved using
+       the trust region minimizer.
+    3. Added sanity tests to the program reordering options
+       for Schur type linear solvers.
+    4. Tests for the TrustRegionPreprocessor.
     
-    Change-Id: I1ce6d4b06e29cf475df1d5bd37c79f66f20f8d93
+    Change-Id: I88cd926f0053bbbf2bd6b11e03ec55b8bf473cf1
 
-commit 7d489fdb073937ac05c0693c1902fbcb9eeb7dfc
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Mon Apr 7 11:14:51 2014 -0700
+commit 54893ba523106e38ab06eb72fb5d8748685c7797
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date:   Mon Aug 11 19:04:18 2014 +0100
 
-    Refactor the landing page to be a bit more compact.
-    
-    Also minor changes to the introduction.
+    Add missing #include of <limits> for loss functions.
     
-    Change-Id: Iaa71f576b95c869f075d6837dbb60ba4bb608ee7
+    Change-Id: Id632451429e03031a1533a9be795270debc70706
 
-commit 406ac7816730c15425db20d994ac0d60d932ab6c
-Author: Keir Mierle <mierle@gmail.com>
-Date:   Mon Apr 7 08:36:07 2014 +0000
+commit 4a2a888905fd1ce7203e45df15762d52740bb240
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date:   Thu Aug 7 11:48:03 2014 -0700
 
-    Rework Ceres documentation as new website
+    Change ownership of pointers in Minimizer::Options.
     
-    This reworks the Ceres Sphinx documentation such that it can
-    function as the main Ceres website, now hosted at
-    ceres-solver.org. This also changes to the theme sphinx_rtd_theme
-    used by Read The Docs; this theme has strong mobile support and is
-    well enough designed.
+    This is a intermediate change to clean things up
+    in preparation for a broader refactoring of the SolverImpl.
     
-    Change-Id: I63232d985859a6dac94ff58f08bf81eb2b9e7f99
-
-commit 3e60a998ac970da659d590bac2ff892ee619aa1b
-Author: Richard Bowen <rsbowen@google.com>
-Date:   Tue Apr 1 16:22:49 2014 -0700
-
-    Added support and tests: row and column blocks for sparse matrix
-    transpose.
+    Essentially we are replacing raw pointers in Minimizer::Options
+    with shared_ptr objects. For now this only makes things a bit
+    more complicated looking inside solver_impl.cc, but going
+    forward this will lead to considerable simplifications in
+    tracking ownership of various pointers.
     
-    Change-Id: Ife641b08a9e86826478521a405f21ba60667f0e8
+    Change-Id: I21db8fc6763c29b0d15e834d7c968a0f514042a0
 
-commit 5ecb1c3f1dfde6e8ed4b493eafef7b43dad19e72
+commit 0d4e3bd664d442b700fee2895c7a8ac37717dc08
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Tue Apr 1 09:20:35 2014 -0700
+Date:   Thu Aug 7 12:19:10 2014 -0700
 
-    Add Problem::IsParameterBlockPresent.
+    GradientCheckingProblem's parameter blocks are initialized correctly.
+    
+    Ensure that when a new problem object is constructed for validing
+    gradients, the parameter blocks have their data pointers point to
+    the user's parameter blocks.
     
-    This allows the user to query the Problem to see if a
-    parameter block is already present or not.
+    We used to do this inside solver_impl.cc, but doing this at
+    construction is the right thing to do.
     
-    Change-Id: If786f6c008cc644f3398597901d718d12a6d865d
+    Change-Id: I3bfdc89bb0027c8d67cde937e8f2fa385d89c30c
 
-commit 75e2232b29ff2ea42c8406c9d45b138a7e7a0048
+commit cfb36463f9c1f806121779d651c7105ad899bb20
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Fri Mar 28 11:21:02 2014 -0700
+Date:   Tue Aug 5 14:42:33 2014 -0700
 
-    Fix spacing in building.rst
+    Small fixes from William Rucklidge.
     
-    Change-Id: I4c68d732c80d7ff2bdbc812bf0b7c7fb98c43957
+    Change-Id: I0be52f0f1e53cedccffe4807dc664a2f3fb4a8e4
 
-commit b555b489b8447434294a8a6676272289140d6a1d
-Author: Richard Bowen <rsbowen@google.com>
-Date:   Thu Mar 27 15:51:28 2014 -0700
+commit 9a41132a0523af407b53644c07900f86aa6fceac
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date:   Mon Aug 4 22:45:53 2014 -0700
 
-    Changes documentation to reflect changes in output format.
+    Small changes from Jim Roseborough.
     
-    Change-Id: Ic0ba234283e791edcad29aec067905dcb2130813
+    Change-Id: Ic8b19ea5c5f4f8fd782eb4420b30514153087d18
 
-commit 1cfb600bfc3be8342f85f155b2b219a595ee58da
+commit a521fc3afc11425b46992388a83ef07017d02ac9
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Wed Mar 26 12:55:11 2014 -0700
+Date:   Fri Aug 1 08:27:35 2014 -0700
 
-    Add the (2,4,9) template specialization for PartitionedMatrixView
-    and SchurEliminator.
+    Simplify, cleanup and instrument SchurComplementSolver.
+    
+    The instrumentation revealed that EIGEN_SPARSE can be upto
+    an order of magnitude slower than CX_SPARSE on some bundle
+    adjustment problems.
+    
+    The problem comes down to the quality of AMD ordering that
+    CXSparse/Eigen implements. It does particularly badly
+    on the Schur complement. In the CXSparse implementation
+    we got around this by considering the block sparsity structure
+    and computing the AMD ordering on it and lifting it to the
+    full matrix.
     
-    Also update the comment inside generate_partitioned_matrix_view_specializations.py
+    This is currently not possible with the release version of
+    Eigen, as the support for using preordered/natural orderings
+    is in the master branch but has not been released yet.
     
-    Change-Id: I99a7ab4256091b1da48553da3076e5996a5757ed
+    Change-Id: I25588d3e723e50606f327db5759f174f58439e29
 
-commit 195e49351b386ffc23020d406883eaa6511e29b3
-Author: Alex Stewart <alexs.mac@gmail.com>
-Date:   Wed Mar 26 11:36:11 2014 +0000
+commit b43e73a03485f0fd0fe514e356ad8925731d3a81
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date:   Fri Aug 1 12:09:09 2014 -0700
 
-    Check validity of residual block before removal in RemoveResidualBlock.
+    Simplify the Eigen code in SparseNormalCholeskySolver.
     
-    - Breaking change: Problem::Options::enable_fast_parameter_block_removal
-      is now Problem::Options::enable_fast_removal, as it now controls
-      the behaviour for both parameter and residual blocks.
+    Simplifying some of the template handling, and remove the use
+    of SelfAdjointView as it is not needed. The solver itself takes
+    an argument for where the data is actually stored.
     
-    - Previously we did not check that the specified residual block to
-      remove in RemoveResidualBlock actually represented a valid residual
-      for the problem.
-    - This meant that Ceres would die unexpectedly if the user passed an
-      uninitialised residual_block, or more likely attempted to remove a
-      residual block that had already been removed automatically after
-      the user removed a parameter block upon on which it was dependent.
-    - RemoveResidualBlock now verifies the validity of the given
-      residual_block to remove.  Either by checking against a hash set of
-      all residuals maintained in ProblemImpl iff enable_fast_removal
-      is enabled.  Or by a full scan of the residual blocks if not.
+    The performance of SparseNormalCholesky with EIGEN_SPARSE
+    seems to be on par with CX_SPARSE.
     
-    Change-Id: I9ab178e2f68a74135f0a8e20905b16405c77a62b
+    Change-Id: I69e22a144b447c052b6cbe59ef1aa33eae2dd9e3
 
-commit 74762b60332d4a1c08ec5aef75ec718da9d305a2
-Author: Alex Stewart <alexs.mac@gmail.com>
-Date:   Thu Mar 20 14:50:25 2014 +0000
+commit 031598295c6b2f061c171b9b2338919f41b7eb0b
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date:   Thu Jul 17 14:35:18 2014 -0700
 
-    Allow construction of an AutoDiffLocalParameterization with a functor.
+    Enable Eigen as sparse linear algebra library.
+    
+    SPARSE_NORMAL_CHOLESKY and SPARSE_SCHUR can now be used
+    with EIGEN_SPARSE as the backend.
+    
+    The performance is not as good as CXSparse. This needs to be
+    investigated. Is it because the quality of AMD ordering that
+    we are computing is not as good as the one for CXSparse? This
+    could be because we are working with the scalar matrix instead
+    of the block matrix.
+    
+    Also, the upper/lower triangular story is not completely clear.
+    Both of these issues will be benchmarked and tackled in the
+    near future.
+    
+    Also included in this change is a bunch of cleanup to the
+    SparseNormalCholeskySolver and SparseSchurComplementSolver
+    classes around the use of the of defines used to conditionally
+    compile out parts of the code.
     
-    - Previously AutoDiffLocalParameterization would internally instantiate
-      a functor instance whenever one was required.  This prohibits the
-      user passing arguments to the constructor of the functor.
-    - Now AutoDiffLocalParameterization can take over ownership of an
-      allocated functor which the user created.  This mimics the behaviour
-      of AutoDiffCostFunction.
+    The system_test has been updated to test EIGEN_SPARSE also.
     
-    Change-Id: I264e1face44ca5d5e71cc20c77cc7654d3f74cc0
+    Change-Id: I46a57e9c4c97782696879e0b15cfc7a93fe5496a
 
-commit 4f603fb0d82317a53fa9d96abe6a97b2e69bff36
+commit 1b17145adf6aa0072db2989ad799e90313970ab3
 Author: Sameer Agarwal <sameeragarwal@google.com>
-Date:   Wed Mar 19 17:16:43 2014 -0700
+Date:   Wed Jul 30 10:14:15 2014 -0700
 
-    Grammer fixes from William Rucklidge.
+    Make canned loss functions more robust.
+    
+    The loss functions that ship with ceres can sometimes
+    generate a zero first derivative if the residual is too
+    large.
+    
+    In such cases Corrector fails with an ugly undebuggable
+    crash. This CL is the first in a series of fixes to
+    take care of this.
+    
+    We clamp the values of rho' from below by
+    numeric_limits<double>::min().
+    
+    Also included here is some minor cleanup where the constants
+    are treated as doubles rather than integers.
+    
+    Thanks to Pierre Moulon for reporting this problem.
     
-    Change-Id: Ia40df7a1d141eb2552694510453d1431bb0c8dce
+    Change-Id: I3aaf375303ecc2659bbf6fb56a812e7dc3a41106
index ec17ae24e307495bcbe9f0d13964078fee87a192..89b32416e229acf4c3ff8805b3d5e4b9a8fc5134 100755 (executable)
@@ -46,7 +46,7 @@ rm -rf $tmp
 sources=`find ./include ./internal -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | sed -r 's/^\.\//\t/' | \
   grep -v -E 'schur_eliminator_[0-9]_[0-9d]_[0-9d].cc' | \
   grep -v -E 'partitioned_matrix_view_[0-9]_[0-9d]_[0-9d].cc' | sort -d`
-generated_sources=`find ./include ./internal -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | sed -r 's/^\.\//#\t\t/' | \
+generated_sources=`find ./include ./internal -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | sed -r 's/^\.\//\t\t/' | \
   grep -E 'schur_eliminator_[0-9]_[0-9d]_[0-9d].cc|partitioned_matrix_view_[0-9]_[0-9d]_[0-9d].cc' | sort -d`
 headers=`find ./include ./internal -type f -iname '*.h' | sed -r 's/^\.\//\t/' | sort -d`
 
@@ -138,11 +138,11 @@ ${sources}
 ${headers}
 )
 
-#if(TRUE)
-#      list(APPEND SRC
+if(TRUE)
+       list(APPEND SRC
 ${generated_sources}
-#      )
-#endif()
+       )
+endif()
 
 if(WIN32)
        list(APPEND INC
index 164681d4d34b50f631016ae0ec5a7a3d957b26b4..d1bd69672c86a3da13c3eda90527ebdd48fb0545 100644 (file)
@@ -11,13 +11,17 @@ include/ceres/dynamic_autodiff_cost_function.h
 include/ceres/dynamic_numeric_diff_cost_function.h
 include/ceres/fpclassify.h
 include/ceres/gradient_checker.h
+include/ceres/gradient_problem.h
+include/ceres/gradient_problem_solver.h
 include/ceres/internal/autodiff.h
+include/ceres/internal/disable_warnings.h
 include/ceres/internal/eigen.h
 include/ceres/internal/fixed_array.h
 include/ceres/internal/macros.h
 include/ceres/internal/manual_constructor.h
 include/ceres/internal/numeric_diff.h
 include/ceres/internal/port.h
+include/ceres/internal/reenable_warnings.h
 include/ceres/internal/scoped_ptr.h
 include/ceres/internal/variadic_evaluate.h
 include/ceres/iteration_callback.h
@@ -26,13 +30,13 @@ include/ceres/local_parameterization.h
 include/ceres/loss_function.h
 include/ceres/normal_prior.h
 include/ceres/numeric_diff_cost_function.h
-include/ceres/numeric_diff_functor.h
 include/ceres/ordered_groups.h
 include/ceres/problem.h
 include/ceres/rotation.h
 include/ceres/sized_cost_function.h
 include/ceres/solver.h
 include/ceres/types.h
+include/ceres/version.h
 internal/ceres/array_utils.cc
 internal/ceres/array_utils.h
 internal/ceres/blas.cc
@@ -55,6 +59,8 @@ internal/ceres/block_sparse_matrix.cc
 internal/ceres/block_sparse_matrix.h
 internal/ceres/block_structure.cc
 internal/ceres/block_structure.h
+internal/ceres/callbacks.cc
+internal/ceres/callbacks.h
 internal/ceres/canonical_views_clustering.cc
 internal/ceres/canonical_views_clustering.h
 internal/ceres/c_api.cc
@@ -62,7 +68,6 @@ internal/ceres/casts.h
 internal/ceres/cgnr_linear_operator.h
 internal/ceres/cgnr_solver.cc
 internal/ceres/cgnr_solver.h
-internal/ceres/CMakeLists.txt
 internal/ceres/collections_port.h
 internal/ceres/compressed_col_sparse_matrix_utils.cc
 internal/ceres/compressed_col_sparse_matrix_utils.h
@@ -145,6 +150,9 @@ internal/ceres/generate_eliminator_specialization.py
 internal/ceres/generate_partitioned_matrix_view_specializations.py
 internal/ceres/gradient_checking_cost_function.cc
 internal/ceres/gradient_checking_cost_function.h
+internal/ceres/gradient_problem.cc
+internal/ceres/gradient_problem_evaluator.h
+internal/ceres/gradient_problem_solver.cc
 internal/ceres/graph_algorithms.h
 internal/ceres/graph.h
 internal/ceres/implicit_schur_complement.cc
@@ -170,6 +178,8 @@ internal/ceres/line_search_direction.h
 internal/ceres/line_search.h
 internal/ceres/line_search_minimizer.cc
 internal/ceres/line_search_minimizer.h
+internal/ceres/line_search_preprocessor.cc
+internal/ceres/line_search_preprocessor.h
 internal/ceres/local_parameterization.cc
 internal/ceres/loss_function.cc
 internal/ceres/low_rank_inverse_hessian.cc
@@ -189,6 +199,8 @@ internal/ceres/polynomial.cc
 internal/ceres/polynomial.h
 internal/ceres/preconditioner.cc
 internal/ceres/preconditioner.h
+internal/ceres/preprocessor.cc
+internal/ceres/preprocessor.h
 internal/ceres/problem.cc
 internal/ceres/problem_impl.cc
 internal/ceres/problem_impl.h
@@ -196,6 +208,8 @@ internal/ceres/program.cc
 internal/ceres/program_evaluator.h
 internal/ceres/program.h
 internal/ceres/random.h
+internal/ceres/reorder_program.cc
+internal/ceres/reorder_program.h
 internal/ceres/residual_block.cc
 internal/ceres/residual_block.h
 internal/ceres/residual_block_utils.cc
@@ -213,8 +227,8 @@ internal/ceres/single_linkage_clustering.cc
 internal/ceres/single_linkage_clustering.h
 internal/ceres/small_blas.h
 internal/ceres/solver.cc
-internal/ceres/solver_impl.cc
-internal/ceres/solver_impl.h
+internal/ceres/solver_utils.cc
+internal/ceres/solver_utils.h
 internal/ceres/sparse_matrix.cc
 internal/ceres/sparse_matrix.h
 internal/ceres/sparse_normal_cholesky_solver.cc
@@ -230,6 +244,8 @@ internal/ceres/triplet_sparse_matrix.cc
 internal/ceres/triplet_sparse_matrix.h
 internal/ceres/trust_region_minimizer.cc
 internal/ceres/trust_region_minimizer.h
+internal/ceres/trust_region_preprocessor.cc
+internal/ceres/trust_region_preprocessor.h
 internal/ceres/trust_region_strategy.cc
 internal/ceres/trust_region_strategy.h
 internal/ceres/types.cc
index 632542e9bdd752a7ec9a46f186e655ea92679d33..71f41fd226b7f41b9c05eac9f6575ffb265ca3b5 100644 (file)
@@ -39,6 +39,7 @@
 #define CERES_PUBLIC_C_API_H_
 
 #include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -140,4 +141,6 @@ CERES_EXPORT void ceres_solve(ceres_problem_t* problem);
 }
 #endif
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  /* CERES_PUBLIC_C_API_H_ */
index acb402c542d9cecb675cd2b40322257b8dbfb8c0..7c8981e29945a03fe7441a426fe94a6d7ba3ad1e 100644 (file)
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
+// Copyright 2014 Google Inc. All rights reserved.
 // http://code.google.com/p/ceres-solver/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,9 +34,6 @@
 #ifndef CERES_PUBLIC_CERES_H_
 #define CERES_PUBLIC_CERES_H_
 
-#define CERES_VERSION 1.9.0
-#define CERES_ABI_VERSION 1.9.0
-
 #include "ceres/autodiff_cost_function.h"
 #include "ceres/autodiff_local_parameterization.h"
 #include "ceres/cost_function.h"
 #include "ceres/crs_matrix.h"
 #include "ceres/dynamic_autodiff_cost_function.h"
 #include "ceres/dynamic_numeric_diff_cost_function.h"
+#include "ceres/gradient_problem.h"
+#include "ceres/gradient_problem_solver.h"
 #include "ceres/iteration_callback.h"
 #include "ceres/jet.h"
 #include "ceres/local_parameterization.h"
 #include "ceres/loss_function.h"
 #include "ceres/numeric_diff_cost_function.h"
-#include "ceres/numeric_diff_functor.h"
 #include "ceres/ordered_groups.h"
 #include "ceres/problem.h"
 #include "ceres/sized_cost_function.h"
 #include "ceres/solver.h"
 #include "ceres/types.h"
+#include "ceres/version.h"
 
 #endif  // CERES_PUBLIC_CERES_H_
index 2a12ba6fe372621796a9da28ca3f18b4a5c822b4..3f0087c781566368fdf4e1d14b460d9f3beb84b0 100644 (file)
@@ -39,6 +39,7 @@
 #include "ceres/cost_function.h"
 #include "ceres/internal/scoped_ptr.h"
 #include "ceres/types.h"
+#include "ceres/internal/disable_warnings.h"
 
 namespace ceres {
 
@@ -93,5 +94,6 @@ class CERES_EXPORT ConditionedCostFunction : public CostFunction {
 
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_PUBLIC_CONDITIONED_COST_FUNCTION_H_
index fee3e73c111aaf4b707cbf3a9ca6e8ade2327477..fe8fc07d2ce3d461ca5a7c70e03d04c03d673273 100644 (file)
@@ -48,6 +48,7 @@
 #include "ceres/internal/macros.h"
 #include "ceres/internal/port.h"
 #include "ceres/types.h"
+#include "ceres/internal/disable_warnings.h"
 
 namespace ceres {
 
@@ -105,8 +106,7 @@ class CERES_EXPORT CostFunction {
   // the constraints, then returning false whenever the constraints
   // are not satisfied will prevent the solver from moving into the
   // infeasible region. This is not a very sophisticated mechanism for
-  // enforcing constraints, but is often good enough for things like
-  // non-negativity constraints.
+  // enforcing constraints, but is often good enough.
   //
   // Note that it is important that the initial values of the
   // parameter block must be feasible, otherwise the solver will
@@ -142,4 +142,6 @@ class CERES_EXPORT CostFunction {
 
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_PUBLIC_COST_FUNCTION_H_
index 0d01f772a3bd0d2ac9c9d657cdf18b3e514ec27c..b4a516e0ab1f4b596e04e3655f1d991324ff5671 100644 (file)
@@ -107,9 +107,7 @@ class CostFunctionToFunctor {
   explicit CostFunctionToFunctor(CostFunction* cost_function)
   : cost_function_(cost_function) {
     CHECK_NOTNULL(cost_function);
-
-    CHECK_GE(kNumResiduals, 0);
-    CHECK_EQ(cost_function->num_residuals(), kNumResiduals);
+    CHECK(kNumResiduals > 0 || kNumResiduals == DYNAMIC);
 
     // This block breaks the 80 column rule to keep it somewhat readable.
     CHECK((!N1 && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
index b6e9a6ae39283fcaf5a3dd1a486caa002ff57ce0..35fde4de05ddba17e3a5b2084fd4d3dcd79589b3 100644 (file)
@@ -36,6 +36,7 @@
 #include "ceres/internal/port.h"
 #include "ceres/internal/scoped_ptr.h"
 #include "ceres/types.h"
+#include "ceres/internal/disable_warnings.h"
 
 namespace ceres {
 
@@ -201,9 +202,9 @@ class CERES_EXPORT Covariance {
   struct CERES_EXPORT Options {
     Options()
 #ifndef CERES_NO_SUITESPARSE
-        : algorithm_type(SPARSE_QR),
+        : algorithm_type(SUITE_SPARSE_QR),
 #else
-        : algorithm_type(DENSE_SVD),
+        : algorithm_type(EIGEN_SPARSE_QR),
 #endif
           min_reciprocal_condition_number(1e-14),
           null_space_rank(0),
@@ -228,47 +229,22 @@ class CERES_EXPORT Covariance {
     //    for small to moderate sized problems. It can handle
     //    full-rank as well as rank deficient Jacobians.
     //
-    // 2. SPARSE_CHOLESKY uses the CHOLMOD sparse Cholesky
-    //    factorization library to compute the decomposition :
-    //
-    //      R'R = J'J
-    //
-    //    and then
-    //
-    //      [J'J]^-1  = [R'R]^-1
-    //
-    //    It a fast algorithm for sparse matrices that should be used
-    //    when the Jacobian matrix J is well conditioned. For
-    //    ill-conditioned matrices, this algorithm can fail
-    //    unpredictabily. This is because Cholesky factorization is
-    //    not a rank-revealing factorization, i.e., it cannot reliably
-    //    detect when the matrix being factorized is not of full
-    //    rank. SuiteSparse/CHOLMOD supplies a heuristic for checking
-    //    if the matrix is rank deficient (cholmod_rcond), but it is
-    //    only a heuristic and can have both false positive and false
-    //    negatives.
-    //
-    //    Recent versions of SuiteSparse (>= 4.2.0) provide a much
-    //    more efficient method for solving for rows of the covariance
-    //    matrix. Therefore, if you are doing SPARSE_CHOLESKY, we
-    //    strongly recommend using a recent version of SuiteSparse.
-    //
-    // 3. SPARSE_QR uses the SuiteSparseQR sparse QR factorization
-    //    library to compute the decomposition
+    // 2. EIGEN_SPARSE_QR uses the sparse QR factorization algorithm
+    //    in Eigen to compute the decomposition
     //
     //      Q * R = J
     //
     //    [J'J]^-1 = [R*R']^-1
     //
-    //    It is a moderately fast algorithm for sparse matrices, which
-    //    at the price of more time and memory than the
-    //    SPARSE_CHOLESKY algorithm is numerically better behaved and
-    //    is rank revealing, i.e., it can reliably detect when the
-    //    Jacobian matrix is rank deficient.
+    //    It is a moderately fast algorithm for sparse matrices.
     //
-    // Neither SPARSE_CHOLESKY or SPARSE_QR are capable of computing
-    // the covariance if the Jacobian is rank deficient.
-
+    // 3. SUITE_SPARSE_QR uses the SuiteSparseQR sparse QR
+    //    factorization algorithm. It uses dense linear algebra and is
+    //    multi threaded, so for large sparse sparse matrices it is
+    //    significantly faster than EIGEN_SPARSE_QR.
+    //
+    // Neither EIGEN_SPARSE_QR not SUITE_SPARSE_QR are capable of
+    // computing the covariance if the Jacobian is rank deficient.
     CovarianceAlgorithmType algorithm_type;
 
     // If the Jacobian matrix is near singular, then inverting J'J
@@ -294,29 +270,13 @@ class CERES_EXPORT Covariance {
     //    where min_sigma and max_sigma are the minimum and maxiumum
     //    singular values of J respectively.
     //
-    // 2. SPARSE_CHOLESKY
-    //
-    //      cholmod_rcond < min_reciprocal_conditioner_number
-    //
-    //    Here cholmod_rcond is a crude estimate of the reciprocal
-    //    condition number of J'J by using the maximum and minimum
-    //    diagonal entries of the Cholesky factor R. There are no
-    //    theoretical guarantees associated with this test. It can
-    //    give false positives and negatives. Use at your own
-    //    risk. The default value of min_reciprocal_condition_number
-    //    has been set to a conservative value, and sometimes the
-    //    Covariance::Compute may return false even if it is possible
-    //    to estimate the covariance reliably. In such cases, the user
-    //    should exercise their judgement before lowering the value of
-    //    min_reciprocal_condition_number.
-    //
-    // 3. SPARSE_QR
+    // 2. SUITE_SPARSE_QR and EIGEN_SPARSE_QR
     //
     //      rank(J) < num_col(J)
     //
     //   Here rank(J) is the estimate of the rank of J returned by the
-    //   SuiteSparseQR algorithm. It is a fairly reliable indication
-    //   of rank deficiency.
+    //   sparse QR factorization algorithm. It is a fairly reliable
+    //   indication of rank deficiency.
     //
     double min_reciprocal_condition_number;
 
@@ -351,8 +311,8 @@ class CERES_EXPORT Covariance {
     //
     //   lambda_i / lambda_max < min_reciprocal_condition_number.
     //
-    // This option has no effect on the SPARSE_CHOLESKY or SPARSE_QR
-    // algorithms.
+    // This option has no effect on the SUITE_SPARSE_QR and
+    // EIGEN_SPARSE_QR algorithms.
     int null_space_rank;
 
     int num_threads;
@@ -419,4 +379,6 @@ class CERES_EXPORT Covariance {
 
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_PUBLIC_COVARIANCE_H_
index 687c9586dfd5979ea00e247f28b4fdab860c77e3..d2d62894194df8058c54f793ae844c89ca5fab71 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <vector>
 #include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
 
 namespace ceres {
 
@@ -80,4 +81,6 @@ struct CERES_EXPORT CRSMatrix {
 
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_PUBLIC_CRS_MATRIX_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/gradient_problem.h b/extern/libmv/third_party/ceres/include/ceres/gradient_problem.h
new file mode 100644 (file)
index 0000000..55a8be1
--- /dev/null
@@ -0,0 +1,127 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2014 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_PUBLIC_GRADIENT_PROBLEM_H_
+#define CERES_PUBLIC_GRADIENT_PROBLEM_H_
+
+#include "ceres/internal/macros.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/local_parameterization.h"
+
+namespace ceres {
+
+class FirstOrderFunction;
+
+// Instances of GradientProblem represent general non-linear
+// optimization problems that must be solved using just the value of
+// the objective function and its gradient. Unlike the Problem class,
+// which can only be used to model non-linear least squares problems,
+// instances of GradientProblem not restricted in the form of the
+// objective function.
+//
+// Structurally GradientProblem is a composition of a
+// FirstOrderFunction and optionally a LocalParameterization.
+//
+// The FirstOrderFunction is responsible for evaluating the cost and
+// gradient of the objective function.
+//
+// The LocalParameterization is responsible for going back and forth
+// between the ambient space and the local tangent space. (See
+// local_parameterization.h for more details). When a
+// LocalParameterization is not provided, then the tangent space is
+// assumed to coincide with the ambient Euclidean space that the
+// gradient vector lives in.
+//
+// Example usage:
+//
+// The following demonstrate the problem construction for Rosenbrock's function
+//
+//   f(x,y) = (1-x)^2 + 100(y - x^2)^2;
+//
+// class Rosenbrock : public ceres::FirstOrderFunction {
+//  public:
+//   virtual ~Rosenbrock() {}
+//
+//   virtual bool Evaluate(const double* parameters,
+//                         double* cost,
+//                         double* gradient) const {
+//     const double x = parameters[0];
+//     const double y = parameters[1];
+//
+//     cost[0] = (1.0 - x) * (1.0 - x) + 100.0 * (y - x * x) * (y - x * x);
+//     if (gradient != NULL) {
+//       gradient[0] = -2.0 * (1.0 - x) - 200.0 * (y - x * x) * 2.0 * x;
+//       gradient[1] = 200.0 * (y - x * x);
+//     }
+//     return true;
+//   };
+//
+//   virtual int NumParameters() const { return 2; };
+// };
+//
+// ceres::GradientProblem problem(new Rosenbrock());
+class CERES_EXPORT GradientProblem {
+ public:
+  // Takes ownership of the function.
+  explicit GradientProblem(FirstOrderFunction* function);
+
+  // Takes ownership of the function and the parameterization.
+  GradientProblem(FirstOrderFunction* function,
+                  LocalParameterization* parameterization);
+
+  int NumParameters() const;
+  int NumLocalParameters() const;
+
+  // This call is not thread safe.
+  bool Evaluate(const double* parameters, double* cost, double* gradient) const;
+  bool Plus(const double* x, const double* delta, double* x_plus_delta) const;
+
+ private:
+  internal::scoped_ptr<FirstOrderFunction> function_;
+  internal::scoped_ptr<LocalParameterization> parameterization_;
+  internal::scoped_array<double> scratch_;
+};
+
+// A FirstOrderFunction object implements the evaluation of a function
+// and its gradient.
+class CERES_EXPORT FirstOrderFunction {
+ public:
+  virtual ~FirstOrderFunction() {}
+  // cost is never NULL. gradient may be null.
+  virtual bool Evaluate(const double* const parameters,
+                        double* cost,
+                        double* gradient) const = 0;
+  virtual int NumParameters() const = 0;
+};
+
+}  // namespace ceres
+
+#endif  // CERES_PUBLIC_GRADIENT_PROBLEM_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/gradient_problem_solver.h b/extern/libmv/third_party/ceres/include/ceres/gradient_problem_solver.h
new file mode 100644 (file)
index 0000000..484d88e
--- /dev/null
@@ -0,0 +1,365 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2014 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_PUBLIC_GRADIENT_PROBLEM_SOLVER_H_
+#define CERES_PUBLIC_GRADIENT_PROBLEM_SOLVER_H_
+
+#include <cmath>
+#include <string>
+#include <vector>
+#include "ceres/internal/macros.h"
+#include "ceres/internal/port.h"
+#include "ceres/iteration_callback.h"
+#include "ceres/types.h"
+#include "ceres/internal/disable_warnings.h"
+
+namespace ceres {
+
+class GradientProblem;
+
+class CERES_EXPORT GradientProblemSolver {
+ public:
+  virtual ~GradientProblemSolver();
+
+  // The options structure contains, not surprisingly, options that control how
+  // the solver operates. The defaults should be suitable for a wide range of
+  // problems; however, better performance is often obtainable with tweaking.
+  //
+  // The constants are defined inside types.h
+  struct CERES_EXPORT Options {
+    // Default constructor that sets up a generic sparse problem.
+    Options() {
+      line_search_direction_type = LBFGS;
+      line_search_type = WOLFE;
+      nonlinear_conjugate_gradient_type = FLETCHER_REEVES;
+      max_lbfgs_rank = 20;
+      use_approximate_eigenvalue_bfgs_scaling = false;
+      line_search_interpolation_type = CUBIC;
+      min_line_search_step_size = 1e-9;
+      line_search_sufficient_function_decrease = 1e-4;
+      max_line_search_step_contraction = 1e-3;
+      min_line_search_step_contraction = 0.6;
+      max_num_line_search_step_size_iterations = 20;
+      max_num_line_search_direction_restarts = 5;
+      line_search_sufficient_curvature_decrease = 0.9;
+      max_line_search_step_expansion = 10.0;
+      max_num_iterations = 50;
+      max_solver_time_in_seconds = 1e9;
+      num_threads = 1;
+      function_tolerance = 1e-6;
+      gradient_tolerance = 1e-10;
+      logging_type = PER_MINIMIZER_ITERATION;
+      minimizer_progress_to_stdout = false;
+    }
+
+    // Returns true if the options struct has a valid
+    // configuration. Returns false otherwise, and fills in *error
+    // with a message describing the problem.
+    bool IsValid(string* error) const;
+
+    // Minimizer options ----------------------------------------
+    LineSearchDirectionType line_search_direction_type;
+    LineSearchType line_search_type;
+    NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
+
+    // The LBFGS hessian approximation is a low rank approximation to
+    // the inverse of the Hessian matrix. The rank of the
+    // approximation determines (linearly) the space and time
+    // complexity of using the approximation. Higher the rank, the
+    // better is the quality of the approximation. The increase in
+    // quality is however is bounded for a number of reasons.
+    //
+    // 1. The method only uses secant information and not actual
+    // derivatives.
+    //
+    // 2. The Hessian approximation is constrained to be positive
+    // definite.
+    //
+    // So increasing this rank to a large number will cost time and
+    // space complexity without the corresponding increase in solution
+    // quality. There are no hard and fast rules for choosing the
+    // maximum rank. The best choice usually requires some problem
+    // specific experimentation.
+    //
+    // For more theoretical and implementation details of the LBFGS
+    // method, please see:
+    //
+    // Nocedal, J. (1980). "Updating Quasi-Newton Matrices with
+    // Limited Storage". Mathematics of Computation 35 (151): 773–782.
+    int max_lbfgs_rank;
+
+    // As part of the (L)BFGS update step (BFGS) / right-multiply step (L-BFGS),
+    // the initial inverse Hessian approximation is taken to be the Identity.
+    // However, Oren showed that using instead I * \gamma, where \gamma is
+    // chosen to approximate an eigenvalue of the true inverse Hessian can
+    // result in improved convergence in a wide variety of cases. Setting
+    // use_approximate_eigenvalue_bfgs_scaling to true enables this scaling.
+    //
+    // It is important to note that approximate eigenvalue scaling does not
+    // always improve convergence, and that it can in fact significantly degrade
+    // performance for certain classes of problem, which is why it is disabled
+    // by default.  In particular it can degrade performance when the
+    // sensitivity of the problem to different parameters varies significantly,
+    // as in this case a single scalar factor fails to capture this variation
+    // and detrimentally downscales parts of the jacobian approximation which
+    // correspond to low-sensitivity parameters. It can also reduce the
+    // robustness of the solution to errors in the jacobians.
+    //
+    // Oren S.S., Self-scaling variable metric (SSVM) algorithms
+    // Part II: Implementation and experiments, Management Science,
+    // 20(5), 863-874, 1974.
+    bool use_approximate_eigenvalue_bfgs_scaling;
+
+    // Degree of the polynomial used to approximate the objective
+    // function. Valid values are BISECTION, QUADRATIC and CUBIC.
+    //
+    // BISECTION corresponds to pure backtracking search with no
+    // interpolation.
+    LineSearchInterpolationType line_search_interpolation_type;
+
+    // If during the line search, the step_size falls below this
+    // value, it is truncated to zero.
+    double min_line_search_step_size;
+
+    // Line search parameters.
+
+    // Solving the line search problem exactly is computationally
+    // prohibitive. Fortunately, line search based optimization
+    // algorithms can still guarantee convergence if instead of an
+    // exact solution, the line search algorithm returns a solution
+    // which decreases the value of the objective function
+    // sufficiently. More precisely, we are looking for a step_size
+    // s.t.
+    //
+    //   f(step_size) <= f(0) + sufficient_decrease * f'(0) * step_size
+    //
+    double line_search_sufficient_function_decrease;
+
+    // In each iteration of the line search,
+    //
+    //  new_step_size >= max_line_search_step_contraction * step_size
+    //
+    // Note that by definition, for contraction:
+    //
+    //  0 < max_step_contraction < min_step_contraction < 1
+    //
+    double max_line_search_step_contraction;
+
+    // In each iteration of the line search,
+    //
+    //  new_step_size <= min_line_search_step_contraction * step_size
+    //
+    // Note that by definition, for contraction:
+    //
+    //  0 < max_step_contraction < min_step_contraction < 1
+    //
+    double min_line_search_step_contraction;
+
+    // Maximum number of trial step size iterations during each line search,
+    // if a step size satisfying the search conditions cannot be found within
+    // this number of trials, the line search will terminate.
+    int max_num_line_search_step_size_iterations;
+
+    // Maximum number of restarts of the line search direction algorithm before
+    // terminating the optimization. Restarts of the line search direction
+    // algorithm occur when the current algorithm fails to produce a new descent
+    // direction. This typically indicates a numerical failure, or a breakdown
+    // in the validity of the approximations used.
+    int max_num_line_search_direction_restarts;
+
+    // The strong Wolfe conditions consist of the Armijo sufficient
+    // decrease condition, and an additional requirement that the
+    // step-size be chosen s.t. the _magnitude_ ('strong' Wolfe
+    // conditions) of the gradient along the search direction
+    // decreases sufficiently. Precisely, this second condition
+    // is that we seek a step_size s.t.
+    //
+    //   |f'(step_size)| <= sufficient_curvature_decrease * |f'(0)|
+    //
+    // Where f() is the line search objective and f'() is the derivative
+    // of f w.r.t step_size (d f / d step_size).
+    double line_search_sufficient_curvature_decrease;
+
+    // During the bracketing phase of the Wolfe search, the step size is
+    // increased until either a point satisfying the Wolfe conditions is
+    // found, or an upper bound for a bracket containing a point satisfying
+    // the conditions is found.  Precisely, at each iteration of the
+    // expansion:
+    //
+    //   new_step_size <= max_step_expansion * step_size.
+    //
+    // By definition for expansion, max_step_expansion > 1.0.
+    double max_line_search_step_expansion;
+
+    // Maximum number of iterations for the minimizer to run for.
+    int max_num_iterations;
+
+    // Maximum time for which the minimizer should run for.
+    double max_solver_time_in_seconds;
+
+    // Number of threads used by Ceres for evaluating the cost and
+    // jacobians.
+    int num_threads;
+
+    // Minimizer terminates when
+    //
+    //   (new_cost - old_cost) < function_tolerance * old_cost;
+    //
+    double function_tolerance;
+
+    // Minimizer terminates when
+    //
+    //   max_i |x - Project(Plus(x, -g(x))| < gradient_tolerance
+    //
+    // This value should typically be 1e-4 * function_tolerance.
+    double gradient_tolerance;
+
+    // Logging options ---------------------------------------------------------
+
+    LoggingType logging_type;
+
+    // By default the Minimizer progress is logged to VLOG(1), which
+    // is sent to STDERR depending on the vlog level. If this flag is
+    // set to true, and logging_type is not SILENT, the logging output
+    // is sent to STDOUT.
+    bool minimizer_progress_to_stdout;
+
+    // If true, the user's parameter blocks are updated at the end of
+    // every Minimizer iteration, otherwise they are updated when the
+    // Minimizer terminates. This is useful if, for example, the user
+    // wishes to visualize the state of the optimization every
+    // iteration.
+    bool update_state_every_iteration;
+
+    // Callbacks that are executed at the end of each iteration of the
+    // Minimizer. An iteration may terminate midway, either due to
+    // numerical failures or because one of the convergence tests has
+    // been satisfied. In this case none of the callbacks are
+    // executed.
+
+    // Callbacks are executed in the order that they are specified in
+    // this vector. By default, parameter blocks are updated only at
+    // the end of the optimization, i.e when the Minimizer
+    // terminates. This behaviour is controlled by
+    // update_state_every_variable. If the user wishes to have access
+    // to the update parameter blocks when his/her callbacks are
+    // executed, then set update_state_every_iteration to true.
+    //
+    // The solver does NOT take ownership of these pointers.
+    vector<IterationCallback*> callbacks;
+  };
+
+  struct CERES_EXPORT Summary {
+    Summary();
+
+    // A brief one line description of the state of the solver after
+    // termination.
+    string BriefReport() const;
+
+    // A full multiline description of the state of the solver after
+    // termination.
+    string FullReport() const;
+
+    bool IsSolutionUsable() const;
+
+    // Minimizer summary -------------------------------------------------
+    TerminationType termination_type;
+
+    // Reason why the solver terminated.
+    string message;
+
+    // Cost of the problem (value of the objective function) before
+    // the optimization.
+    double initial_cost;
+
+    // Cost of the problem (value of the objective function) after the
+    // optimization.
+    double final_cost;
+
+    // IterationSummary for each minimizer iteration in order.
+    vector<IterationSummary> iterations;
+
+    // Sum total of all time spent inside Ceres when Solve is called.
+    double total_time_in_seconds;
+
+    // Time (in seconds) spent evaluating the residual vector.
+    double cost_evaluation_time_in_seconds;
+
+    // Time (in seconds) spent evaluating the jacobian matrix.
+    double gradient_evaluation_time_in_seconds;
+
+    // Number of parameters in the probem.
+    int num_parameters;
+
+    // Dimension of the tangent space of the problem.
+    int num_local_parameters;
+
+    // Type of line search direction used.
+    LineSearchDirectionType line_search_direction_type;
+
+    // Type of the line search algorithm used.
+    LineSearchType line_search_type;
+
+    //  When performing line search, the degree of the polynomial used
+    //  to approximate the objective function.
+    LineSearchInterpolationType line_search_interpolation_type;
+
+    // If the line search direction is NONLINEAR_CONJUGATE_GRADIENT,
+    // then this indicates the particular variant of non-linear
+    // conjugate gradient used.
+    NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
+
+    // If the type of the line search direction is LBFGS, then this
+    // indicates the rank of the Hessian approximation.
+    int max_lbfgs_rank;
+  };
+
+  // Once a least squares problem has been built, this function takes
+  // the problem and optimizes it based on the values of the options
+  // parameters. Upon return, a detailed summary of the work performed
+  // by the preprocessor, the non-linear minmizer and the linear
+  // solver are reported in the summary object.
+  virtual void Solve(const GradientProblemSolver::Options& options,
+                     const GradientProblem& problem,
+                     double* parameters,
+                     GradientProblemSolver::Summary* summary);
+};
+
+// Helper function which avoids going through the interface.
+CERES_EXPORT void Solve(const GradientProblemSolver::Options& options,
+                        const GradientProblem& problem,
+                        double* parameters,
+                        GradientProblemSolver::Summary* summary);
+
+}  // namespace ceres
+
+#include "ceres/internal/reenable_warnings.h"
+
+#endif  // CERES_PUBLIC_GRADIENT_PROBLEM_SOLVER_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/disable_warnings.h b/extern/libmv/third_party/ceres/include/ceres/internal/disable_warnings.h
new file mode 100644 (file)
index 0000000..78924de
--- /dev/null
@@ -0,0 +1,44 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2014 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// This file has the sole purpose to silence warnings when including Ceres.
+
+// This is not your usual header guard. The macro CERES_WARNINGS_DISABLED
+// shows up again in reenable_warnings.h.
+#ifndef CERES_WARNINGS_DISABLED
+#define CERES_WARNINGS_DISABLED
+
+#ifdef _MSC_VER
+#pragma warning( push )
+// Disable the warning C4251 which is trigerred by stl classes in
+// Ceres' public interface. To quote MSDN: "C4251 can be ignored "
+// "if you are deriving from a type in the Standard C++ Library"
+#pragma warning( disable : 4251 )
+#endif
+
+#endif  // CERES_WARNINGS_DISABLED
index 5048348564a617ff2d597bff2eccb25071159905..3b264b45af3442827677392e2b18969e71caea01 100644 (file)
@@ -103,14 +103,17 @@ struct NumericDiff {
 
     typedef Matrix<double, kNumResiduals, 1> ResidualVector;
     typedef Matrix<double, kParameterBlockSize, 1> ParameterVector;
+
+    // The convoluted reasoning for choosing the Row/Column major
+    // ordering of the matrix is an artifact of the restrictions in
+    // Eigen that prevent it from creating RowMajor matrices with a
+    // single column. In these cases, we ask for a ColMajor matrix.
     typedef Matrix<double,
                    kNumResiduals,
                    kParameterBlockSize,
-                   (kParameterBlockSize == 1 &&
-                    kNumResiduals > 1) ? ColMajor : RowMajor>
+                   (kParameterBlockSize == 1) ? ColMajor : RowMajor>
         JacobianMatrix;
 
-
     Map<JacobianMatrix> parameter_jacobian(jacobian,
                                            NUM_RESIDUALS,
                                            kParameterBlockSize);
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/reenable_warnings.h b/extern/libmv/third_party/ceres/include/ceres/internal/reenable_warnings.h
new file mode 100644 (file)
index 0000000..1f477d8
--- /dev/null
@@ -0,0 +1,38 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2014 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+// This is not your usual header guard. See disable_warnings.h
+#ifdef CERES_WARNINGS_DISABLED
+#undef CERES_WARNINGS_DISABLED
+
+#ifdef _MSC_VER
+#pragma warning( pop )
+#endif
+
+#endif  // CERES_WARNINGS_DISABLED
index 5eca392da36aba7cc7859d82d0e84a9e89ede0ba..237ada6e0c9996b5aced519f4dcf06620885c9f5 100644 (file)
@@ -36,6 +36,7 @@
 #define CERES_PUBLIC_ITERATION_CALLBACK_H_
 
 #include "ceres/types.h"
+#include "ceres/internal/disable_warnings.h"
 
 namespace ceres {
 
@@ -219,4 +220,6 @@ class CERES_EXPORT IterationCallback {
 
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_PUBLIC_ITERATION_CALLBACK_H_
index 81f96c70f73df5ed06c7bd58f35f95f376fd0282..74ce1e9dd53ce8c7ba1167b29be062d35543c31c 100644 (file)
 #include <cmath>
 #include <iosfwd>
 #include <iostream>  // NOLINT
+#include <limits>
 #include <string>
 
 #include "Eigen/Core"
@@ -197,10 +198,8 @@ struct Jet {
   // to be passed in without being fully evaluated until
   // they are assigned to v
   template<typename Derived>
-  Jet(const T& value, const Eigen::DenseBase<Derived> &vIn)
-    : a(value),
-      v(vIn)
-  {
+  EIGEN_STRONG_INLINE Jet(const T& a, const Eigen::DenseBase<Derived> &v)
+      : a(a), v(v) {
   }
 
   // Compound operators
@@ -649,7 +648,9 @@ struct NumTraits<ceres::Jet<T, N> > {
     return ceres::Jet<T, N>(1e-12);
   }
 
-  static inline Real epsilon() { return Real(std::numeric_limits<T>::epsilon()); }
+  static inline Real epsilon() {
+    return Real(std::numeric_limits<T>::epsilon());
+  }
 
   enum {
     IsComplex = 0,
index ecac5ba3ce039329c289303e08563d50eff568c3..656c4d466625314c5f94c55a9d3894f2d94bc682 100644 (file)
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
+// Copyright 2014 Google Inc. All rights reserved.
 // http://code.google.com/p/ceres-solver/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,7 @@
 
 #include <vector>
 #include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
 
 namespace ceres {
 
@@ -109,7 +110,7 @@ namespace ceres {
 // Jacobian which is needed to compute the Jacobian of f w.r.t delta.
 class CERES_EXPORT LocalParameterization {
  public:
-  virtual ~LocalParameterization() {}
+  virtual ~LocalParameterization();
 
   // Generalization of the addition operation,
   //
@@ -121,8 +122,23 @@ class CERES_EXPORT LocalParameterization {
                     double* x_plus_delta) const = 0;
 
   // The jacobian of Plus(x, delta) w.r.t delta at delta = 0.
+  //
+  // jacobian is a row-major GlobalSize() x LocalSize() matrix.
   virtual bool ComputeJacobian(const double* x, double* jacobian) const = 0;
 
+  // local_matrix = global_matrix * jacobian
+  //
+  // global_matrix is a num_rows x GlobalSize  row major matrix.
+  // local_matrix is a num_rows x LocalSize row major matrix.
+  // jacobian(x) is the matrix returned by ComputeJacobian at x.
+  //
+  // This is only used by GradientProblem. For most normal uses, it is
+  // okay to use the default implementation.
+  virtual bool MultiplyByJacobian(const double* x,
+                                  const int num_rows,
+                                  const double* global_matrix,
+                                  double* local_matrix) const;
+
   // Size of x.
   virtual int GlobalSize() const = 0;
 
@@ -142,6 +158,10 @@ class CERES_EXPORT IdentityParameterization : public LocalParameterization {
                     double* x_plus_delta) const;
   virtual bool ComputeJacobian(const double* x,
                                double* jacobian) const;
+  virtual bool MultiplyByJacobian(const double* x,
+                                  const int num_cols,
+                                  const double* global_matrix,
+                                  double* local_matrix) const;
   virtual int GlobalSize() const { return size_; }
   virtual int LocalSize() const { return size_; }
 
@@ -160,6 +180,10 @@ class CERES_EXPORT SubsetParameterization : public LocalParameterization {
                     double* x_plus_delta) const;
   virtual bool ComputeJacobian(const double* x,
                                double* jacobian) const;
+  virtual bool MultiplyByJacobian(const double* x,
+                                  const int num_cols,
+                                  const double* global_matrix,
+                                  double* local_matrix) const;
   virtual int GlobalSize() const {
     return static_cast<int>(constancy_mask_.size());
   }
@@ -188,4 +212,6 @@ class CERES_EXPORT QuaternionParameterization : public LocalParameterization {
 
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_PUBLIC_LOCAL_PARAMETERIZATION_H_
index 5b6bf68e70043132c661ea7a0a7a81b151c237ec..2c585009990d9e556e92ea0e9d326a4777b1995c 100644 (file)
 #ifndef CERES_PUBLIC_LOSS_FUNCTION_H_
 #define CERES_PUBLIC_LOSS_FUNCTION_H_
 
+#include "glog/logging.h"
 #include "ceres/internal/macros.h"
 #include "ceres/internal/scoped_ptr.h"
 #include "ceres/types.h"
-#include "glog/logging.h"
+#include "ceres/internal/disable_warnings.h"
 
 namespace ceres {
 
@@ -395,4 +396,6 @@ class CERES_EXPORT LossFunctionWrapper : public LossFunction {
 
 }  // namespace ceres
 
+#include "ceres/internal/disable_warnings.h"
+
 #endif  // CERES_PUBLIC_LOSS_FUNCTION_H_
index 530e65253bb9111a367923c1a9919e2a66f13d5b..df6650545309dc9211d35b60c1574c07fd1ed0bf 100644 (file)
@@ -36,6 +36,7 @@
 
 #include "ceres/cost_function.h"
 #include "ceres/internal/eigen.h"
+#include "ceres/internal/disable_warnings.h"
 
 namespace ceres {
 
@@ -72,4 +73,6 @@ class CERES_EXPORT NormalPrior: public CostFunction {
 
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_PUBLIC_NORMAL_PRIOR_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/numeric_diff_functor.h b/extern/libmv/third_party/ceres/include/ceres/numeric_diff_functor.h
deleted file mode 100644 (file)
index a29eb97..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-//   this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-//   this list of conditions and the following disclaimer in the documentation
-//   and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-//   used to endorse or promote products derived from this software without
-//   specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// A wrapper class that takes a variadic functor evaluating a
-// function, numerically differentiates it and makes it available as a
-// templated functor so that it can be easily used as part of Ceres'
-// automatic differentiation framework.
-//
-// For example:
-//
-// For example, let us assume that
-//
-//  struct IntrinsicProjection
-//    IntrinsicProjection(const double* observations);
-//    bool operator()(const double* calibration,
-//                    const double* point,
-//                    double* residuals);
-//  };
-//
-// is a functor that implements the projection of a point in its local
-// coordinate system onto its image plane and subtracts it from the
-// observed point projection.
-//
-// Now we would like to compose the action of this functor with the
-// action of camera extrinsics, i.e., rotation and translation, which
-// is given by the following templated function
-//
-//   template<typename T>
-//   void RotateAndTranslatePoint(const T* rotation,
-//                                const T* translation,
-//                                const T* point,
-//                                T* result);
-//
-// To compose the extrinsics and intrinsics, we can construct a
-// CameraProjection functor as follows.
-//
-// struct CameraProjection {
-//    typedef NumericDiffFunctor<IntrinsicProjection, CENTRAL, 2, 5, 3>
-//       IntrinsicProjectionFunctor;
-//
-//   CameraProjection(double* observation) {
-//     intrinsic_projection_.reset(
-//         new IntrinsicProjectionFunctor(observation)) {
-//   }
-//
-//   template <typename T>
-//   bool operator()(const T* rotation,
-//                   const T* translation,
-//                   const T* intrinsics,
-//                   const T* point,
-//                   T* residuals) const {
-//     T transformed_point[3];
-//     RotateAndTranslatePoint(rotation, translation, point, transformed_point);
-//     return (*intrinsic_projection_)(intrinsics, transformed_point, residual);
-//   }
-//
-//  private:
-//   scoped_ptr<IntrinsicProjectionFunctor> intrinsic_projection_;
-// };
-//
-// Here, we made the choice of using CENTRAL differences to compute
-// the jacobian of IntrinsicProjection.
-//
-// Now, we are ready to construct an automatically differentiated cost
-// function as
-//
-// CostFunction* cost_function =
-//    new AutoDiffCostFunction<CameraProjection, 2, 3, 3, 5>(
-//        new CameraProjection(observations));
-//
-// cost_function now seamlessly integrates automatic differentiation
-// of RotateAndTranslatePoint with a numerically differentiated
-// version of IntrinsicProjection.
-
-#ifndef CERES_PUBLIC_NUMERIC_DIFF_FUNCTOR_H_
-#define CERES_PUBLIC_NUMERIC_DIFF_FUNCTOR_H_
-
-#include "ceres/numeric_diff_cost_function.h"
-#include "ceres/types.h"
-#include "ceres/cost_function_to_functor.h"
-
-namespace ceres {
-
-template<typename Functor,
-         NumericDiffMethod kMethod = CENTRAL,
-         int kNumResiduals = 0,
-         int N0 = 0, int N1 = 0 , int N2 = 0, int N3 = 0, int N4 = 0,
-         int N5 = 0, int N6 = 0 , int N7 = 0, int N8 = 0, int N9 = 0>
-class NumericDiffFunctor {
- public:
-  // relative_step_size controls the step size used by the numeric
-  // differentiation process.
-  explicit NumericDiffFunctor(double relative_step_size = 1e-6)
-      : functor_(
-          new NumericDiffCostFunction<Functor,
-                                      kMethod,
-                                      kNumResiduals,
-                                      N0, N1, N2, N3, N4,
-                                      N5, N6, N7, N8, N9>(new Functor,
-                                                          TAKE_OWNERSHIP,
-                                                          kNumResiduals,
-                                                          relative_step_size)) {
-  }
-
-  NumericDiffFunctor(Functor* functor, double relative_step_size = 1e-6)
-      : functor_(new NumericDiffCostFunction<Functor,
-                                             kMethod,
-                                             kNumResiduals,
-                                             N0, N1, N2, N3, N4,
-                                             N5, N6, N7, N8, N9>(
-                                                 functor,
-                                                 TAKE_OWNERSHIP,
-                                                 kNumResiduals,
-                                                 relative_step_size)) {
-  }
-
-  bool operator()(const double* x0, double* residuals) const {
-    return functor_(x0, residuals);
-  }
-
-  bool operator()(const double* x0,
-                  const double* x1,
-                  double* residuals) const {
-    return functor_(x0, x1, residuals);
-  }
-
-  bool operator()(const double* x0,
-                  const double* x1,
-                  const double* x2,
-                  double* residuals) const {
-    return functor_(x0, x1, x2, residuals);
-  }
-
-  bool operator()(const double* x0,
-                  const double* x1,
-                  const double* x2,
-                  const double* x3,
-                  double* residuals) const {
-    return functor_(x0, x1, x2, x3, residuals);
-  }
-
-  bool operator()(const double* x0,
-                  const double* x1,
-                  const double* x2,
-                  const double* x3,
-                  const double* x4,
-                  double* residuals) const {
-    return functor_(x0, x1, x2, x3, x4, residuals);
-  }
-
-  bool operator()(const double* x0,
-                  const double* x1,
-                  const double* x2,
-                  const double* x3,
-                  const double* x4,
-                  const double* x5,
-                  double* residuals) const {
-    return functor_(x0, x1, x2, x3, x4, x5, residuals);
-  }
-
-  bool operator()(const double* x0,
-                  const double* x1,
-                  const double* x2,
-                  const double* x3,
-                  const double* x4,
-                  const double* x5,
-                  const double* x6,
-                  double* residuals) const {
-    return functor_(x0, x1, x2, x3, x4, x5, x6, residuals);
-  }
-
-  bool operator()(const double* x0,
-                  const double* x1,
-                  const double* x2,
-                  const double* x3,
-                  const double* x4,
-                  const double* x5,
-                  const double* x6,
-                  const double* x7,
-                  double* residuals) const {
-    return functor_(x0, x1, x2, x3, x4, x5, x6, x7, residuals);
-  }
-
-  bool operator()(const double* x0,
-                  const double* x1,
-                  const double* x2,
-                  const double* x3,
-                  const double* x4,
-                  const double* x5,
-                  const double* x6,
-                  const double* x7,
-                  const double* x8,
-                  double* residuals) const {
-    return functor_(x0, x1, x2, x3, x4, x5, x6, x7, x8, residuals);
-  }
-
-  bool operator()(const double* x0,
-                  const double* x1,
-                  const double* x2,
-                  const double* x3,
-                  const double* x4,
-                  const double* x5,
-                  const double* x6,
-                  const double* x7,
-                  const double* x8,
-                  const double* x9,
-                  double* residuals) const {
-    return functor_(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, residuals);
-  }
-
-  template <typename T>
-  bool operator()(const T* x0, T* residuals) const {
-    return functor_(x0, residuals);
-  }
-
-  template <typename T>
-  bool operator()(const T* x0,
-                  const T* x1,
-                  T* residuals) const {
-    return functor_(x0, x1, residuals);
-  }
-
-  template <typename T>
-  bool operator()(const T* x0,
-                  const T* x1,
-                  const T* x2,
-                  T* residuals) const {
-    return functor_(x0, x1, x2, residuals);
-  }
-
-  template <typename T>
-  bool operator()(const T* x0,
-                  const T* x1,
-                  const T* x2,
-                  const T* x3,
-                  T* residuals) const {
-    return functor_(x0, x1, x2, x3, residuals);
-  }
-
-  template <typename T>
-  bool operator()(const T* x0,
-                  const T* x1,
-                  const T* x2,
-                  const T* x3,
-                  const T* x4,
-                  T* residuals) const {
-    return functor_(x0, x1, x2, x3, x4, residuals);
-  }
-
-  template <typename T>
-  bool operator()(const T* x0,
-                  const T* x1,
-                  const T* x2,
-                  const T* x3,
-                  const T* x4,
-                  const T* x5,
-                  T* residuals) const {
-    return functor_(x0, x1, x2, x3, x4, x5, residuals);
-  }
-
-  template <typename T>
-  bool operator()(const T* x0,
-                  const T* x1,
-                  const T* x2,
-                  const T* x3,
-                  const T* x4,
-                  const T* x5,
-                  const T* x6,
-                  T* residuals) const {
-    return functor_(x0, x1, x2, x3, x4, x5, x6, residuals);
-  }
-
-  template <typename T>
-  bool operator()(const T* x0,
-                  const T* x1,
-                  const T* x2,
-                  const T* x3,
-                  const T* x4,
-                  const T* x5,
-                  const T* x6,
-                  const T* x7,
-                  T* residuals) const {
-    return functor_(x0, x1, x2, x3, x4, x5, x6, x7, residuals);
-  }
-
-  template <typename T>
-  bool operator()(const T* x0,
-                  const T* x1,
-                  const T* x2,
-                  const T* x3,
-                  const T* x4,
-                  const T* x5,
-                  const T* x6,
-                  const T* x7,
-                  const T* x8,
-                  T* residuals) const {
-    return functor_(x0, x1, x2, x3, x4, x5, x6, x7, x8, residuals);
-  }
-
-  template <typename T>
-  bool operator()(const T* x0,
-                  const T* x1,
-                  const T* x2,
-                  const T* x3,
-                  const T* x4,
-                  const T* x5,
-                  const T* x6,
-                  const T* x7,
-                  const T* x8,
-                  const T* x9,
-                  T* residuals) const {
-    return functor_(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, residuals);
-  }
-
-
- private:
-  CostFunctionToFunctor<kNumResiduals,
-                        N0, N1, N2, N3, N4,
-                        N5, N6, N7, N8, N9> functor_;
-};
-
-}  // namespace ceres
-
-#endif  // CERES_PUBLIC_NUMERIC_DIFF_FUNCTOR_H_
index dff859d7b82bfd777ddd5bb7aeffb922dff015c2..c316d712e97638211a4a31233fba83a56509b927 100644 (file)
@@ -33,7 +33,9 @@
 
 #include <map>
 #include <set>
+#include <vector>
 #include "ceres/internal/port.h"
+#include "glog/logging.h"
 
 namespace ceres {
 
@@ -103,6 +105,20 @@ class OrderedGroups {
     return true;
   }
 
+  // Bulk remove elements. The return value indicates the number of
+  // elements successfully removed.
+  int Remove(const vector<T>& elements) {
+    if (NumElements() == 0 || elements.size() == 0) {
+      return 0;
+    }
+
+    int num_removed = 0;
+    for (int i = 0; i < elements.size(); ++i) {
+      num_removed += Remove(elements[i]);
+    }
+    return num_removed;
+  }
+
   // Reverse the order of the groups in place.
   void Reverse() {
     typename map<int, set<T> >::reverse_iterator it =
@@ -156,10 +172,22 @@ class OrderedGroups {
     return group_to_elements_.size();
   }
 
+  // The first group with one or more elements. Calling this when
+  // there are no groups with non-zero elements will result in a
+  // crash.
+  int MinNonZeroGroup() const {
+    CHECK_NE(NumGroups(), 0);
+    return group_to_elements_.begin()->first;
+  }
+
   const map<int, set<T> >& group_to_elements() const {
     return group_to_elements_;
   }
 
+  const map<T, int>& element_to_group() const {
+    return element_to_group_;
+  }
+
  private:
   map<int, set<T> > group_to_elements_;
   map<T, int> element_to_group_;
index 5881677a8157e5681f7423f48f07f3f0b34c7a43..f75ede3a5c67cb47f6ffa03e53315b93c845c545 100644 (file)
 #include <set>
 #include <vector>
 
+#include "glog/logging.h"
 #include "ceres/internal/macros.h"
 #include "ceres/internal/port.h"
 #include "ceres/internal/scoped_ptr.h"
 #include "ceres/types.h"
-#include "glog/logging.h"
+#include "ceres/internal/disable_warnings.h"
 
 
 namespace ceres {
@@ -367,6 +368,15 @@ class CERES_EXPORT Problem {
       const ResidualBlockId residual_block,
       vector<double*>* parameter_blocks) const;
 
+  // Get the CostFunction for the given residual block.
+  const CostFunction* GetCostFunctionForResidualBlock(
+      const ResidualBlockId residual_block) const;
+
+  // Get the LossFunction for the given residual block. Returns NULL
+  // if no loss function is associated with this residual block.
+  const LossFunction* GetLossFunctionForResidualBlock(
+      const ResidualBlockId residual_block) const;
+
   // Get all the residual blocks that depend on the given parameter block.
   //
   // If Problem::Options::enable_fast_removal is true, then
@@ -466,4 +476,6 @@ class CERES_EXPORT Problem {
 
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_PUBLIC_PROBLEM_H_
index fc70073ec8971f5dede12296ed19d32d7f1ff6ad..0af34cacef284b506aaf47d8ee12657ab4002b11 100644 (file)
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
+// Copyright 2014 Google Inc. All rights reserved.
 // http://code.google.com/p/ceres-solver/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,6 +40,7 @@
 #include "ceres/iteration_callback.h"
 #include "ceres/ordered_groups.h"
 #include "ceres/types.h"
+#include "ceres/internal/disable_warnings.h"
 
 namespace ceres {
 
@@ -91,7 +92,7 @@ class CERES_EXPORT Solver {
       gradient_tolerance = 1e-10;
       parameter_tolerance = 1e-8;
 
-#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE)
+#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE) && !defined(CERES_ENABLE_LGPL_CODE)
       linear_solver_type = DENSE_QR;
 #else
       linear_solver_type = SPARSE_NORMAL_CHOLESKY;
@@ -100,16 +101,26 @@ class CERES_EXPORT Solver {
       preconditioner_type = JACOBI;
       visibility_clustering_type = CANONICAL_VIEWS;
       dense_linear_algebra_library_type = EIGEN;
+
+      // Choose a default sparse linear algebra library in the order:
+      //
+      //   SUITE_SPARSE > CX_SPARSE > EIGEN_SPARSE
+#if !defined(CERES_NO_SUITESPARSE)
       sparse_linear_algebra_library_type = SUITE_SPARSE;
-#if defined(CERES_NO_SUITESPARSE) && !defined(CERES_NO_CXSPARSE)
+#else
+  #if !defined(CERES_NO_CXSPARSE)
       sparse_linear_algebra_library_type = CX_SPARSE;
+  #else
+    #if defined(CERES_USE_EIGEN_SPARSE)
+      sparse_linear_algebra_library_type = EIGEN_SPARSE;
+    #endif
+  #endif
 #endif
 
-
       num_linear_solver_threads = 1;
       use_postordering = false;
       dynamic_sparsity = false;
-      min_linear_solver_iterations = 1;
+      min_linear_solver_iterations = 0;
       max_linear_solver_iterations = 500;
       eta = 1e-1;
       jacobi_scaling = true;
@@ -125,6 +136,11 @@ class CERES_EXPORT Solver {
       update_state_every_iteration = false;
     }
 
+    // Returns true if the options struct has a valid
+    // configuration. Returns false otherwise, and fills in *error
+    // with a message describing the problem.
+    bool IsValid(string* error) const;
+
     // Minimizer options ----------------------------------------
 
     // Ceres supports the two major families of optimization strategies -
@@ -707,10 +723,6 @@ class CERES_EXPORT Solver {
     //
     // The solver does NOT take ownership of these pointers.
     vector<IterationCallback*> callbacks;
-
-    // If non-empty, a summary of the execution of the solver is
-    // recorded to this file.
-    string solver_log;
   };
 
   struct CERES_EXPORT Summary {
@@ -898,9 +910,15 @@ class CERES_EXPORT Solver {
     // parameter blocks.
     vector<int> inner_iteration_ordering_used;
 
-    //  Type of preconditioner used for solving the trust region
-    //  step. Only meaningful when an iterative linear solver is used.
-    PreconditionerType preconditioner_type;
+    // Type of the preconditioner requested by the user.
+    PreconditionerType preconditioner_type_given;
+
+    // Type of the preconditioner actually used. This may be different
+    // from linear_solver_type_given if Ceres determines that the
+    // problem structure is not compatible with the linear solver
+    // requested or if the linear solver requested by the user is not
+    // available.
+    PreconditionerType preconditioner_type_used;
 
     // Type of clustering algorithm used for visibility based
     // preconditioning. Only meaningful when the preconditioner_type
@@ -957,4 +975,6 @@ CERES_EXPORT void Solve(const Solver::Options& options,
 
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_PUBLIC_SOLVER_H_
index ff31d4530dbe8c5ba614d85b97d894d572f072b2..a07c8933e649548308743482fd8459f630823733 100644 (file)
@@ -40,6 +40,7 @@
 #include <string>
 
 #include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
 
 namespace ceres {
 
@@ -149,8 +150,14 @@ enum SparseLinearAlgebraLibraryType {
   // minimum degree ordering.
   SUITE_SPARSE,
 
-  // A lightweight replacment for SuiteSparse.
-  CX_SPARSE
+  // A lightweight replacment for SuiteSparse, which does not require
+  // a LAPACK/BLAS implementation. Consequently, its performance is
+  // also a bit lower than SuiteSparse.
+  CX_SPARSE,
+
+  // Eigen's sparse linear algebra routines. In particular Ceres uses
+  // the Simplicial LDLT routines.
+  EIGEN_SPARSE
 };
 
 enum DenseLinearAlgebraLibraryType {
@@ -246,7 +253,7 @@ enum LineSearchDirectionType {
 // details see Numerical Optimization by Nocedal & Wright.
 enum NonlinearConjugateGradientType {
   FLETCHER_REEVES,
-  POLAK_RIBIRERE,
+  POLAK_RIBIERE,
   HESTENES_STIEFEL,
 };
 
@@ -398,8 +405,8 @@ enum LineSearchInterpolationType {
 
 enum CovarianceAlgorithmType {
   DENSE_SVD,
-  SPARSE_CHOLESKY,
-  SPARSE_QR
+  SUITE_SPARSE_QR,
+  EIGEN_SPARSE_QR
 };
 
 CERES_EXPORT const char* LinearSolverTypeToString(
@@ -475,4 +482,6 @@ CERES_EXPORT bool IsDenseLinearAlgebraLibraryTypeAvailable(
 
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_PUBLIC_TYPES_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/version.h b/extern/libmv/third_party/ceres/include/ceres/version.h
new file mode 100644 (file)
index 0000000..370b08a
--- /dev/null
@@ -0,0 +1,49 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2014 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mierle@gmail.com (Keir Mierle)
+
+#ifndef CERES_PUBLIC_VERSION_H_
+#define CERES_PUBLIC_VERSION_H_
+
+#define CERES_VERSION_MAJOR 1
+#define CERES_VERSION_MINOR 10
+#define CERES_VERSION_REVISION 0
+#define CERES_VERSION_ABI 1
+
+// Classic CPP stringifcation; the extra level of indirection allows the
+// preprocessor to expand the macro before being converted to a string.
+#define CERES_TO_STRING_HELPER(x) #x
+#define CERES_TO_STRING(x) CERES_TO_STRING_HELPER(x)
+
+// The Ceres version as a string; for example "1.9.0".
+#define CERES_VERSION_STRING CERES_TO_STRING(CERES_VERSION_MAJOR) "." \
+                             CERES_TO_STRING(CERES_VERSION_MINOR) "." \
+                             CERES_TO_STRING(CERES_VERSION_REVISION)
+
+#endif  // CERES_PUBLIC_VERSION_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/CMakeLists.txt b/extern/libmv/third_party/ceres/internal/ceres/CMakeLists.txt
deleted file mode 100644 (file)
index 1dd4090..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-# Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-# http://code.google.com/p/ceres-solver/
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# * Redistributions of source code must retain the above copyright notice,
-#   this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright notice,
-#   this list of conditions and the following disclaimer in the documentation
-#   and/or other materials provided with the distribution.
-# * Neither the name of Google Inc. nor the names of its contributors may be
-#   used to endorse or promote products derived from this software without
-#   specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# Author: keir@google.com (Keir Mierle)
-
-SET(CERES_INTERNAL_SRC
-    array_utils.cc
-    blas.cc
-    block_evaluate_preparer.cc
-    block_jacobi_preconditioner.cc
-    block_jacobian_writer.cc
-    block_random_access_dense_matrix.cc
-    block_random_access_diagonal_matrix.cc
-    block_random_access_matrix.cc
-    block_random_access_sparse_matrix.cc
-    block_sparse_matrix.cc
-    block_structure.cc
-    c_api.cc
-    canonical_views_clustering.cc
-    cgnr_solver.cc
-    compressed_col_sparse_matrix_utils.cc
-    compressed_row_jacobian_writer.cc
-    compressed_row_sparse_matrix.cc
-    conditioned_cost_function.cc
-    conjugate_gradients_solver.cc
-    coordinate_descent_minimizer.cc
-    corrector.cc
-    covariance.cc
-    covariance_impl.cc
-    cxsparse.cc
-    dense_normal_cholesky_solver.cc
-    dense_qr_solver.cc
-    dense_sparse_matrix.cc
-    detect_structure.cc
-    dogleg_strategy.cc
-    dynamic_compressed_row_jacobian_writer.cc
-    dynamic_compressed_row_sparse_matrix.cc
-    evaluator.cc
-    file.cc
-    gradient_checking_cost_function.cc
-    implicit_schur_complement.cc
-    incomplete_lq_factorization.cc
-    iterative_schur_complement_solver.cc
-    levenberg_marquardt_strategy.cc
-    lapack.cc
-    line_search.cc
-    line_search_direction.cc
-    line_search_minimizer.cc
-    linear_least_squares_problems.cc
-    linear_operator.cc
-    linear_solver.cc
-    local_parameterization.cc
-    loss_function.cc
-    low_rank_inverse_hessian.cc
-    minimizer.cc
-    normal_prior.cc
-    parameter_block_ordering.cc
-    partitioned_matrix_view.cc
-    polynomial.cc
-    preconditioner.cc
-    problem.cc
-    problem_impl.cc
-    program.cc
-    residual_block.cc
-    residual_block_utils.cc
-    schur_complement_solver.cc
-    schur_eliminator.cc
-    schur_jacobi_preconditioner.cc
-    scratch_evaluate_preparer.cc
-    single_linkage_clustering.cc
-    solver.cc
-    solver_impl.cc
-    sparse_matrix.cc
-    sparse_normal_cholesky_solver.cc
-    split.cc
-    stringprintf.cc
-    suitesparse.cc
-    triplet_sparse_matrix.cc
-    trust_region_minimizer.cc
-    trust_region_strategy.cc
-    types.cc
-    visibility.cc
-    visibility_based_preconditioner.cc
-    wall_time.cc
-)
-
-# Heuristic for determining LIB_SUFFIX. FHS recommends that 64-bit systems
-# install native libraries to lib64 rather than lib. Most distros seem to
-# follow this convention with a couple notable exceptions (Debian-based and
-# Arch-based distros) which we try to detect here.
-IF (CMAKE_SYSTEM_NAME MATCHES "Linux" AND
-    NOT DEFINED LIB_SUFFIX AND
-    NOT CMAKE_CROSSCOMPILING AND
-    CMAKE_SIZEOF_VOID_P EQUAL "8" AND
-    NOT EXISTS "/etc/debian_version" AND
-    NOT EXISTS "/etc/arch-release")
-  SET(LIB_SUFFIX "64")
-ENDIF ()
-
-# Also depend on the header files so that they appear in IDEs.
-FILE(GLOB CERES_INTERNAL_HDRS *.h)
-
-# Include the specialized schur solvers.
-IF (SCHUR_SPECIALIZATIONS)
-  FILE(GLOB CERES_INTERNAL_SCHUR_FILES generated/*.cc)
-ELSE (SCHUR_SPECIALIZATIONS)
-  # Only the fully dynamic solver. The build is much faster this way.
-  FILE(GLOB CERES_INTERNAL_SCHUR_FILES generated/*_d_d_d.cc)
-ENDIF (SCHUR_SPECIALIZATIONS)
-
-# Primarily for Android, but optionally for others, use the minimal internal
-# Glog implementation.
-IF (MINIGLOG)
-  ADD_LIBRARY(miniglog STATIC miniglog/glog/logging.cc)
-  INSTALL(TARGETS miniglog
-          EXPORT  CeresExport
-          RUNTIME DESTINATION bin
-          LIBRARY DESTINATION lib${LIB_SUFFIX}
-          ARCHIVE DESTINATION lib${LIB_SUFFIX})
-ENDIF (MINIGLOG)
-
-SET(CERES_LIBRARY_PUBLIC_DEPENDENCIES ${GLOG_LIBRARIES})
-
-IF (SUITESPARSE AND SUITESPARSE_FOUND)
-  LIST(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ${SUITESPARSE_LIBRARIES})
-ENDIF (SUITESPARSE AND SUITESPARSE_FOUND)
-
-IF (CXSPARSE AND CXSPARSE_FOUND)
-  LIST(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ${CXSPARSE_LIBRARIES})
-ENDIF (CXSPARSE AND CXSPARSE_FOUND)
-
-IF (BLAS_FOUND AND LAPACK_FOUND)
-  LIST(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ${LAPACK_LIBRARIES})
-  LIST(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ${BLAS_LIBRARIES})
-ENDIF (BLAS_FOUND AND LAPACK_FOUND)
-
-IF (OPENMP_FOUND)
-  IF (NOT MSVC)
-    LIST(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES gomp)
-    LIST(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ${CMAKE_THREAD_LIBS_INIT})
-  ENDIF (NOT MSVC)
-ENDIF (OPENMP_FOUND)
-
-SET(CERES_LIBRARY_SOURCE
-    ${CERES_INTERNAL_SRC}
-    ${CERES_INTERNAL_HDRS}
-    ${CERES_INTERNAL_SCHUR_FILES})
-
-ADD_LIBRARY(ceres ${CERES_LIBRARY_SOURCE})
-SET_TARGET_PROPERTIES(ceres PROPERTIES
-  VERSION ${CERES_VERSION}
-  SOVERSION ${CERES_VERSION_MAJOR}
-)
-
-IF (BUILD_SHARED_LIBS)
-  # When building a shared library, mark all external libraries as
-  # PRIVATE so they don't show up as a dependency.
-  TARGET_LINK_LIBRARIES(ceres
-        LINK_PUBLIC ${CERES_LIBRARY_PUBLIC_DEPENDENCIES}
-        LINK_PRIVATE ${CERES_LIBRARY_PRIVATE_DEPENDENCIES})
-ELSE (BUILD_SHARED_LIBS)
-  # When building a static library, all external libraries are
-  # PUBLIC(default) since the user needs to link to them.
-  # They will be listed in CeresTargets.cmake.
-  SET(CERES_LIBRARY_DEPENDENCIES
-        ${CERES_LIBRARY_PUBLIC_DEPENDENCIES}
-        ${CERES_LIBRARY_PRIVATE_DEPENDENCIES})
-  TARGET_LINK_LIBRARIES(ceres ${CERES_LIBRARY_DEPENDENCIES})
-ENDIF (BUILD_SHARED_LIBS)
-
-INSTALL(TARGETS ceres
-        EXPORT  CeresExport
-        RUNTIME DESTINATION bin
-        LIBRARY DESTINATION lib${LIB_SUFFIX}
-        ARCHIVE DESTINATION lib${LIB_SUFFIX})
-
-IF (BUILD_TESTING AND GFLAGS)
-  ADD_LIBRARY(gtest gmock_gtest_all.cc gmock_main.cc)
-  ADD_LIBRARY(test_util
-              evaluator_test_utils.cc
-              numeric_diff_test_utils.cc
-              test_util.cc)
-
-  TARGET_LINK_LIBRARIES(gtest ${GFLAGS_LIBRARIES} ${GLOG_LIBRARIES})
-  TARGET_LINK_LIBRARIES(test_util ceres gtest ${GLOG_LIBRARIES})
-
-  MACRO (CERES_TEST NAME)
-    ADD_EXECUTABLE(${NAME}_test ${NAME}_test.cc)
-    TARGET_LINK_LIBRARIES(${NAME}_test test_util ceres gtest)
-    ADD_TEST(NAME ${NAME}_test
-             COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${NAME}_test
-             --test_srcdir
-             ${CMAKE_SOURCE_DIR}/data)
-  ENDMACRO (CERES_TEST)
-
-  CERES_TEST(array_utils)
-  CERES_TEST(autodiff)
-  CERES_TEST(autodiff_cost_function)
-  CERES_TEST(autodiff_local_parameterization)
-  CERES_TEST(block_random_access_dense_matrix)
-  CERES_TEST(block_random_access_diagonal_matrix)
-  CERES_TEST(block_random_access_sparse_matrix)
-  CERES_TEST(block_sparse_matrix)
-  CERES_TEST(c_api)
-  CERES_TEST(canonical_views_clustering)
-  CERES_TEST(compressed_row_sparse_matrix)
-  CERES_TEST(conditioned_cost_function)
-  CERES_TEST(corrector)
-  CERES_TEST(cost_function_to_functor)
-  CERES_TEST(covariance)
-  CERES_TEST(dense_sparse_matrix)
-  CERES_TEST(dynamic_autodiff_cost_function)
-  CERES_TEST(dynamic_compressed_row_sparse_matrix)
-  CERES_TEST(dynamic_numeric_diff_cost_function)
-  CERES_TEST(evaluator)
-  CERES_TEST(gradient_checker)
-  CERES_TEST(gradient_checking_cost_function)
-  CERES_TEST(graph)
-  CERES_TEST(graph_algorithms)
-  CERES_TEST(implicit_schur_complement)
-  CERES_TEST(incomplete_lq_factorization)
-  CERES_TEST(iterative_schur_complement_solver)
-  CERES_TEST(jet)
-  CERES_TEST(levenberg_marquardt_strategy)
-  CERES_TEST(dogleg_strategy)
-  CERES_TEST(local_parameterization)
-  CERES_TEST(loss_function)
-  CERES_TEST(minimizer)
-  CERES_TEST(normal_prior)
-  CERES_TEST(numeric_diff_cost_function)
-  CERES_TEST(numeric_diff_functor)
-  CERES_TEST(ordered_groups)
-  CERES_TEST(parameter_block)
-  CERES_TEST(parameter_block_ordering)
-  CERES_TEST(partitioned_matrix_view)
-  CERES_TEST(polynomial)
-  CERES_TEST(problem)
-  CERES_TEST(residual_block)
-  CERES_TEST(residual_block_utils)
-  CERES_TEST(rotation)
-  CERES_TEST(schur_complement_solver)
-  CERES_TEST(schur_eliminator)
-  CERES_TEST(single_linkage_clustering)
-  CERES_TEST(small_blas)
-  CERES_TEST(solver_impl)
-
-  # TODO(sameeragarwal): This test should ultimately be made
-  # independent of SuiteSparse.
-  IF (SUITESPARSE AND SUITESPARSE_FOUND)
-    CERES_TEST(compressed_col_sparse_matrix_utils)
-  ENDIF (SUITESPARSE AND SUITESPARSE_FOUND)
-
-  CERES_TEST(symmetric_linear_solver)
-  CERES_TEST(triplet_sparse_matrix)
-  CERES_TEST(trust_region_minimizer)
-  CERES_TEST(unsymmetric_linear_solver)
-  CERES_TEST(visibility)
-  CERES_TEST(visibility_based_preconditioner)
-
-  # Put the large end to end test last.
-  CERES_TEST(system)
-ENDIF (BUILD_TESTING AND GFLAGS)
index 3eea042d5111d24df89d328694c950aaf9b6642f..205ddaf27c9d452d93ffe0834b6a0b099f518b05 100644 (file)
 
 #include "ceres/array_utils.h"
 
+#include <algorithm>
 #include <cmath>
 #include <cstddef>
 #include <string>
-
+#include <vector>
 #include "ceres/fpclassify.h"
 #include "ceres/stringprintf.h"
 
@@ -94,5 +95,19 @@ void AppendArrayToString(const int size, const double* x, string* result) {
   }
 }
 
+void MapValuesToContiguousRange(const int size, int* array) {
+  std::vector<int> unique_values(array, array + size);
+  std::sort(unique_values.begin(), unique_values.end());
+  unique_values.erase(std::unique(unique_values.begin(),
+                                  unique_values.end()),
+                      unique_values.end());
+
+  for (int i = 0; i < size; ++i) {
+    array[i] = std::lower_bound(unique_values.begin(),
+                                unique_values.end(),
+                                array[i]) - unique_values.begin();
+  }
+}
+
 }  // namespace internal
 }  // namespace ceres
index 34fda6fd47511053d6f45e44fefdbcb243cca064..7f56947066b62e7c6e1d04d1588479b67b1db59e 100644 (file)
@@ -67,6 +67,21 @@ void AppendArrayToString(const int size, const double* x, string* result);
 
 extern const double kImpossibleValue;
 
+// This routine takes an array of integer values, sorts and uniques
+// them and then maps each value in the array to its position in the
+// sorted+uniqued array. By doing this, if there are are k unique
+// values in the array, each value is replaced by an integer in the
+// range [0, k-1], while preserving their relative order.
+//
+// For example
+//
+// [1 0 3 5 0 1 5]
+//
+// gets mapped to
+//
+// [1 0 2 3 0 1 3]
+void MapValuesToContiguousRange(int size, int* array);
+
 }  // namespace internal
 }  // namespace ceres
 
diff --git a/extern/libmv/third_party/ceres/internal/ceres/callbacks.cc b/extern/libmv/third_party/ceres/internal/ceres/callbacks.cc
new file mode 100644 (file)
index 0000000..d223633
--- /dev/null
@@ -0,0 +1,109 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2014 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include <iostream>  // NO LINT
+#include "ceres/callbacks.h"
+#include "ceres/program.h"
+#include "ceres/stringprintf.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+StateUpdatingCallback::StateUpdatingCallback(Program* program,
+                                             double* parameters)
+    : program_(program), parameters_(parameters) {}
+
+StateUpdatingCallback::~StateUpdatingCallback() {}
+
+CallbackReturnType StateUpdatingCallback::operator()(
+    const IterationSummary& summary) {
+  if (summary.step_is_successful) {
+    program_->StateVectorToParameterBlocks(parameters_);
+    program_->CopyParameterBlockStateToUserState();
+  }
+  return SOLVER_CONTINUE;
+}
+
+LoggingCallback::LoggingCallback(const MinimizerType minimizer_type,
+                                 const bool log_to_stdout)
+    : minimizer_type(minimizer_type),
+      log_to_stdout_(log_to_stdout) {}
+
+LoggingCallback::~LoggingCallback() {}
+
+CallbackReturnType LoggingCallback::operator()(
+    const IterationSummary& summary) {
+  string output;
+  if (minimizer_type == LINE_SEARCH) {
+    const char* kReportRowFormat =
+        "% 4d: f:% 8e d:% 3.2e g:% 3.2e h:% 3.2e "
+        "s:% 3.2e e:% 3d it:% 3.2e tt:% 3.2e";
+    output = StringPrintf(kReportRowFormat,
+                          summary.iteration,
+                          summary.cost,
+                          summary.cost_change,
+                          summary.gradient_max_norm,
+                          summary.step_norm,
+                          summary.step_size,
+                          summary.line_search_function_evaluations,
+                          summary.iteration_time_in_seconds,
+                          summary.cumulative_time_in_seconds);
+  } else if (minimizer_type == TRUST_REGION) {
+    if (summary.iteration == 0) {
+      output = "iter      cost      cost_change  |gradient|   |step|    tr_ratio  tr_radius  ls_iter  iter_time  total_time\n";
+    }
+    const char* kReportRowFormat =
+        "% 4d % 8e   % 3.2e   % 3.2e  % 3.2e  % 3.2e % 3.2e     % 3d   % 3.2e   % 3.2e";
+    output += StringPrintf(kReportRowFormat,
+                          summary.iteration,
+                          summary.cost,
+                          summary.cost_change,
+                          summary.gradient_max_norm,
+                          summary.step_norm,
+                          summary.relative_decrease,
+                          summary.trust_region_radius,
+                          summary.linear_solver_iterations,
+                          summary.iteration_time_in_seconds,
+                          summary.cumulative_time_in_seconds);
+  } else {
+    LOG(FATAL) << "Unknown minimizer type.";
+  }
+
+  if (log_to_stdout_) {
+    cout << output << endl;
+  } else {
+    VLOG(1) << output;
+  }
+  return SOLVER_CONTINUE;
+}
+
+}  // namespace internal
+}  // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/callbacks.h b/extern/libmv/third_party/ceres/internal/ceres/callbacks.h
new file mode 100644 (file)
index 0000000..93704df
--- /dev/null
@@ -0,0 +1,71 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2014 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_CALLBACKS_H_
+#define CERES_INTERNAL_CALLBACKS_H_
+
+#include <string>
+#include "ceres/iteration_callback.h"
+#include "ceres/internal/port.h"
+
+namespace ceres {
+namespace internal {
+
+class Program;
+
+// Callback for updating the externally visible state of parameter
+// blocks.
+class StateUpdatingCallback : public IterationCallback {
+ public:
+  StateUpdatingCallback(Program* program, double* parameters);
+  virtual ~StateUpdatingCallback();
+  virtual CallbackReturnType operator()(const IterationSummary& summary);
+ private:
+  Program* program_;
+  double* parameters_;
+};
+
+// Callback for logging the state of the minimizer to STDERR or
+// STDOUT depending on the user's preferences and logging level.
+class LoggingCallback : public IterationCallback {
+ public:
+  LoggingCallback(MinimizerType minimizer_type, bool log_to_stdout);
+  virtual ~LoggingCallback();
+  virtual CallbackReturnType operator()(const IterationSummary& summary);
+
+ private:
+  const MinimizerType minimizer_type;
+  const bool log_to_stdout_;
+};
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_INTERNAL_CALLBACKS_H_
index 2f032e6580a819483deef07488738d180a5d459a..9bbab4b237718af78eb868755165b381453a324d 100644 (file)
@@ -61,7 +61,7 @@ class CanonicalViewsClustering {
   // vertices may not be assigned to any cluster. In this case they
   // are assigned to a cluster with id = kInvalidClusterId.
   void ComputeClustering(const CanonicalViewsClusteringOptions& options,
-                         const Graph<int>& graph,
+                         const WeightedGraph<int>& graph,
                          vector<int>* centers,
                          IntMap* membership);
 
@@ -74,7 +74,7 @@ class CanonicalViewsClustering {
                                 IntMap* membership) const;
 
   CanonicalViewsClusteringOptions options_;
-  const Graph<int>* graph_;
+  const WeightedGraph<int>* graph_;
   // Maps a view to its representative canonical view (its cluster
   // center).
   IntMap view_to_canonical_view_;
@@ -85,7 +85,7 @@ class CanonicalViewsClustering {
 
 void ComputeCanonicalViewsClustering(
     const CanonicalViewsClusteringOptions& options,
-    const Graph<int>& graph,
+    const WeightedGraph<int>& graph,
     vector<int>* centers,
     IntMap* membership) {
   time_t start_time = time(NULL);
@@ -98,7 +98,7 @@ void ComputeCanonicalViewsClustering(
 // Implementation of CanonicalViewsClustering
 void CanonicalViewsClustering::ComputeClustering(
     const CanonicalViewsClusteringOptions& options,
-    const Graph<int>& graph,
+    const WeightedGraph<int>& graph,
     vector<int>* centers,
     IntMap* membership) {
   options_ = options;
@@ -150,7 +150,7 @@ void CanonicalViewsClustering::FindValidViews(
   for (IntSet::const_iterator view = views.begin();
        view != views.end();
        ++view) {
-    if (graph_->VertexWeight(*view) != Graph<int>::InvalidWeight()) {
+    if (graph_->VertexWeight(*view) != WeightedGraph<int>::InvalidWeight()) {
       valid_views->insert(*view);
     }
   }
index 1b4c4ee059f227cd11aab26c2a2099a25df8d53b..d3fa57258317bb23a335b2cbb4ccb22cea04912b 100644 (file)
@@ -101,7 +101,7 @@ struct CanonicalViewsClusteringOptions;
 // cluster. In this case they are assigned to a cluster with id = -1;
 void ComputeCanonicalViewsClustering(
     const CanonicalViewsClusteringOptions& options,
-    const Graph<int>& graph,
+    const WeightedGraph<int>& graph,
     vector<int>* centers,
     HashMap<int, int>* membership);
 
index 524cb8ad988ac265720adb84692ccbf8ad58f788..3071a0918e4ae11b1ff9153ca5bfc9ce8b8a9cb7 100644 (file)
@@ -101,7 +101,7 @@ LinearSolver::Summary ConjugateGradientsSolver::Solve(
   A->RightMultiply(x, tmp.data());
   r = bref - tmp;
   double norm_r = r.norm();
-  if (norm_r <= tol_r) {
+  if (options_.min_num_iterations == 0 && norm_r <= tol_r) {
     summary.termination_type = LINEAR_SOLVER_SUCCESS;
     summary.message =
         StringPrintf("Convergence. |r| = %e <= %e.", norm_r, tol_r);
@@ -113,9 +113,8 @@ LinearSolver::Summary ConjugateGradientsSolver::Solve(
   // Initial value of the quadratic model Q = x'Ax - 2 * b'x.
   double Q0 = -1.0 * xref.dot(bref + r);
 
-  for (summary.num_iterations = 1;
-       summary.num_iterations < options_.max_num_iterations;
-       ++summary.num_iterations) {
+  for (summary.num_iterations = 1;; ++summary.num_iterations) {
+
     // Apply preconditioner
     if (per_solve_options.preconditioner != NULL) {
       z.setZero();
@@ -207,7 +206,8 @@ LinearSolver::Summary ConjugateGradientsSolver::Solve(
     //   124(1-2), 45-59, 2000.
     //
     const double zeta = summary.num_iterations * (Q1 - Q0) / Q1;
-    if (zeta < per_solve_options.q_tolerance) {
+    if (zeta < per_solve_options.q_tolerance &&
+        summary.num_iterations >= options_.min_num_iterations) {
       summary.termination_type = LINEAR_SOLVER_SUCCESS;
       summary.message =
           StringPrintf("Convergence: zeta = %e < %e",
@@ -219,12 +219,17 @@ LinearSolver::Summary ConjugateGradientsSolver::Solve(
 
     // Residual based termination.
     norm_r = r. norm();
-    if (norm_r <= tol_r) {
+    if (norm_r <= tol_r &&
+        summary.num_iterations >= options_.min_num_iterations) {
       summary.termination_type = LINEAR_SOLVER_SUCCESS;
       summary.message =
           StringPrintf("Convergence. |r| = %e <= %e.", norm_r, tol_r);
       break;
     }
+
+    if (summary.num_iterations >= options_.max_num_iterations) {
+      break;
+    }
   }
 
   return summary;
index bfe93c49826a213ad94a7d68d49abffbcdc84320..1d55458bb69da730900239c2999169f3acce862f 100644 (file)
 #include "ceres/evaluator.h"
 #include "ceres/linear_solver.h"
 #include "ceres/minimizer.h"
-#include "ceres/ordered_groups.h"
 #include "ceres/parameter_block.h"
+#include "ceres/parameter_block_ordering.h"
 #include "ceres/problem_impl.h"
 #include "ceres/program.h"
 #include "ceres/residual_block.h"
 #include "ceres/solver.h"
-#include "ceres/solver_impl.h"
 #include "ceres/trust_region_minimizer.h"
 #include "ceres/trust_region_strategy.h"
+#include "ceres/parameter_block_ordering.h"
 
 namespace ceres {
 namespace internal {
@@ -210,28 +210,54 @@ void CoordinateDescentMinimizer::Solve(Program* program,
   summary->final_cost = 0.0;
   string error;
 
-  scoped_ptr<Evaluator> evaluator(
-      Evaluator::Create(evaluator_options_, program,  &error));
-  CHECK_NOTNULL(evaluator.get());
-
-  scoped_ptr<SparseMatrix> jacobian(evaluator->CreateJacobian());
-  CHECK_NOTNULL(jacobian.get());
+  Minimizer::Options minimizer_options;
+  minimizer_options.evaluator.reset(
+      CHECK_NOTNULL(Evaluator::Create(evaluator_options_, program,  &error)));
+  minimizer_options.jacobian.reset(
+      CHECK_NOTNULL(minimizer_options.evaluator->CreateJacobian()));
 
   TrustRegionStrategy::Options trs_options;
   trs_options.linear_solver = linear_solver;
-
-  scoped_ptr<TrustRegionStrategy>trust_region_strategy(
+  minimizer_options.trust_region_strategy.reset(
       CHECK_NOTNULL(TrustRegionStrategy::Create(trs_options)));
-
-  Minimizer::Options minimizer_options;
-  minimizer_options.evaluator = evaluator.get();
-  minimizer_options.jacobian = jacobian.get();
-  minimizer_options.trust_region_strategy = trust_region_strategy.get();
   minimizer_options.is_silent = true;
 
   TrustRegionMinimizer minimizer;
   minimizer.Minimize(minimizer_options, parameter, summary);
 }
 
+bool CoordinateDescentMinimizer::IsOrderingValid(
+    const Program& program,
+    const ParameterBlockOrdering& ordering,
+    string* message) {
+  const map<int, set<double*> >& group_to_elements =
+      ordering.group_to_elements();
+
+  // Verify that each group is an independent set
+  map<int, set<double*> >::const_iterator it = group_to_elements.begin();
+  for ( ; it != group_to_elements.end(); ++it) {
+    if (!program.IsParameterBlockSetIndependent(it->second)) {
+      *message =
+          StringPrintf("The user-provided "
+                       "parameter_blocks_for_inner_iterations does not "
+                       "form an independent set. Group Id: %d", it->first);
+      return false;
+    }
+  }
+  return true;
+}
+
+// Find a recursive decomposition of the Hessian matrix as a set
+// of independent sets of decreasing size and invert it. This
+// seems to work better in practice, i.e., Cameras before
+// points.
+ParameterBlockOrdering* CoordinateDescentMinimizer::CreateOrdering(
+    const Program& program) {
+  scoped_ptr<ParameterBlockOrdering> ordering(new ParameterBlockOrdering);
+  ComputeRecursiveIndependentSetOrdering(program, ordering.get());
+  ordering->Reverse();
+  return ordering.release();
+}
+
 }  // namespace internal
 }  // namespace ceres
index 424acda94aefdb7e9a1436097d8d46dd3b08c9bd..c1f8ffcd02af5559c586c5bc2dd1517f82850cf2 100644 (file)
 #include "ceres/evaluator.h"
 #include "ceres/minimizer.h"
 #include "ceres/problem_impl.h"
-#include "ceres/program.h"
 #include "ceres/solver.h"
 
 namespace ceres {
 namespace internal {
 
+class Program;
+class LinearSolver;
+
 // Given a Program, and a ParameterBlockOrdering which partitions
 // (non-exhaustively) the Hessian matrix into independent sets,
 // perform coordinate descent on the parameter blocks in the
@@ -66,6 +68,17 @@ class CoordinateDescentMinimizer : public Minimizer {
                         double* parameters,
                         Solver::Summary* summary);
 
+  // Verify that each group in the ordering forms an independent set.
+  static bool IsOrderingValid(const Program& program,
+                              const ParameterBlockOrdering& ordering,
+                              string* message);
+
+  // Find a recursive decomposition of the Hessian matrix as a set
+  // of independent sets of decreasing size and invert it. This
+  // seems to work better in practice, i.e., Cameras before
+  // points.
+  static ParameterBlockOrdering* CreateOrdering(const Program& program);
+
  private:
   void Solve(Program* program,
              LinearSolver* linear_solver,
index 75c80bf5687b47ee39d7651b20ef8cd994337566..cfbfb445343b9efda4812f5535b35e559ee0ba51 100644 (file)
 #include <cstdlib>
 #include <utility>
 #include <vector>
+#include "Eigen/SparseCore"
+
+// Suppress unused local variable warning from Eigen Ordering.h #included by
+// SparseQR in Eigen 3.2.0. This was fixed in Eigen 3.2.1, but 3.2.0 is still
+// widely used (Ubuntu 14.04), and Ceres won't compile otherwise due to -Werror.
+#if defined(_MSC_VER)
+#pragma warning( push )
+#pragma warning( disable : 4189 )
+#else
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#endif
+#include "Eigen/SparseQR"
+#if defined(_MSC_VER)
+#pragma warning( pop )
+#else
+#pragma GCC diagnostic pop
+#endif
+
 #include "Eigen/SVD"
 #include "ceres/compressed_col_sparse_matrix_utils.h"
 #include "ceres/compressed_row_sparse_matrix.h"
 
 namespace ceres {
 namespace internal {
-namespace {
-
-// Per thread storage for SuiteSparse.
-#ifndef CERES_NO_SUITESPARSE
-
-struct PerThreadContext {
-  explicit PerThreadContext(int num_rows)
-      : solution(NULL),
-        solution_set(NULL),
-        y_workspace(NULL),
-        e_workspace(NULL),
-        rhs(NULL) {
-    rhs = ss.CreateDenseVector(NULL, num_rows, num_rows);
-  }
-
-  ~PerThreadContext() {
-    ss.Free(solution);
-    ss.Free(solution_set);
-    ss.Free(y_workspace);
-    ss.Free(e_workspace);
-    ss.Free(rhs);
-  }
-
-  cholmod_dense* solution;
-  cholmod_sparse* solution_set;
-  cholmod_dense* y_workspace;
-  cholmod_dense* e_workspace;
-  cholmod_dense* rhs;
-  SuiteSparse ss;
-};
-
-#endif
-
-}  // namespace
 
 typedef vector<pair<const double*, const double*> > CovarianceBlocks;
 
@@ -94,8 +79,17 @@ CovarianceImpl::CovarianceImpl(const Covariance::Options& options)
     : options_(options),
       is_computed_(false),
       is_valid_(false) {
-  evaluate_options_.num_threads = options.num_threads;
-  evaluate_options_.apply_loss_function = options.apply_loss_function;
+#ifndef CERES_USE_OPENMP
+  if (options_.num_threads > 1) {
+    LOG(WARNING)
+        << "OpenMP support is not compiled into this binary; "
+        << "only options.num_threads = 1 is supported. Switching "
+        << "to single threaded mode.";
+    options_.num_threads = 1;
+  }
+#endif
+  evaluate_options_.num_threads = options_.num_threads;
+  evaluate_options_.apply_loss_function = options_.apply_loss_function;
 }
 
 CovarianceImpl::~CovarianceImpl() {
@@ -396,11 +390,15 @@ bool CovarianceImpl::ComputeCovarianceValues() {
     case DENSE_SVD:
       return ComputeCovarianceValuesUsingDenseSVD();
 #ifndef CERES_NO_SUITESPARSE
-    case SPARSE_CHOLESKY:
-      return ComputeCovarianceValuesUsingSparseCholesky();
-    case SPARSE_QR:
-      return ComputeCovarianceValuesUsingSparseQR();
+    case SUITE_SPARSE_QR:
+      return ComputeCovarianceValuesUsingSuiteSparseQR();
+#else
+      LOG(ERROR) << "SuiteSparse is required to use the "
+                 << "SUITE_SPARSE_QR algorithm.";
+      return false;
 #endif
+    case EIGEN_SPARSE_QR:
+      return ComputeCovarianceValuesUsingEigenSparseQR();
     default:
       LOG(ERROR) << "Unsupported covariance estimation algorithm type: "
                  << CovarianceAlgorithmTypeToString(options_.algorithm_type);
@@ -409,197 +407,7 @@ bool CovarianceImpl::ComputeCovarianceValues() {
   return false;
 }
 
-bool CovarianceImpl::ComputeCovarianceValuesUsingSparseCholesky() {
-  EventLogger event_logger(
-      "CovarianceImpl::ComputeCovarianceValuesUsingSparseCholesky");
-#ifndef CERES_NO_SUITESPARSE
-  if (covariance_matrix_.get() == NULL) {
-    // Nothing to do, all zeros covariance matrix.
-    return true;
-  }
-
-  SuiteSparse ss;
-
-  CRSMatrix jacobian;
-  problem_->Evaluate(evaluate_options_, NULL, NULL, NULL, &jacobian);
-
-  event_logger.AddEvent("Evaluate");
-  // m is a transposed view of the Jacobian.
-  cholmod_sparse cholmod_jacobian_view;
-  cholmod_jacobian_view.nrow = jacobian.num_cols;
-  cholmod_jacobian_view.ncol = jacobian.num_rows;
-  cholmod_jacobian_view.nzmax = jacobian.values.size();
-  cholmod_jacobian_view.nz = NULL;
-  cholmod_jacobian_view.p = reinterpret_cast<void*>(&jacobian.rows[0]);
-  cholmod_jacobian_view.i = reinterpret_cast<void*>(&jacobian.cols[0]);
-  cholmod_jacobian_view.x = reinterpret_cast<void*>(&jacobian.values[0]);
-  cholmod_jacobian_view.z = NULL;
-  cholmod_jacobian_view.stype = 0;  // Matrix is not symmetric.
-  cholmod_jacobian_view.itype = CHOLMOD_INT;
-  cholmod_jacobian_view.xtype = CHOLMOD_REAL;
-  cholmod_jacobian_view.dtype = CHOLMOD_DOUBLE;
-  cholmod_jacobian_view.sorted = 1;
-  cholmod_jacobian_view.packed = 1;
-
-  string message;
-  cholmod_factor* factor = ss.AnalyzeCholesky(&cholmod_jacobian_view, &message);
-  event_logger.AddEvent("Symbolic Factorization");
-  if (factor == NULL) {
-    LOG(ERROR) << "Covariance estimation failed. "
-               << "CHOLMOD symbolic cholesky factorization returned with: "
-               << message;
-    return false;
-  }
-
-  LinearSolverTerminationType termination_type =
-      ss.Cholesky(&cholmod_jacobian_view, factor, &message);
-  event_logger.AddEvent("Numeric Factorization");
-  if (termination_type != LINEAR_SOLVER_SUCCESS) {
-    LOG(ERROR) << "Covariance estimation failed. "
-               << "CHOLMOD numeric cholesky factorization returned with: "
-               << message;
-    ss.Free(factor);
-    return false;
-  }
-
-  const double reciprocal_condition_number =
-      cholmod_rcond(factor, ss.mutable_cc());
-
-  if (reciprocal_condition_number <
-      options_.min_reciprocal_condition_number) {
-    LOG(ERROR) << "Cholesky factorization of J'J is not reliable. "
-               << "Reciprocal condition number: "
-               << reciprocal_condition_number << " "
-               << "min_reciprocal_condition_number: "
-               << options_.min_reciprocal_condition_number;
-    ss.Free(factor);
-    return false;
-  }
-
-  const int num_rows = covariance_matrix_->num_rows();
-  const int* rows = covariance_matrix_->rows();
-  const int* cols = covariance_matrix_->cols();
-  double* values = covariance_matrix_->mutable_values();
-
-  // The following loop exploits the fact that the i^th column of A^{-1}
-  // is given by the solution to the linear system
-  //
-  //  A x = e_i
-  //
-  // where e_i is a vector with e(i) = 1 and all other entries zero.
-  //
-  // Since the covariance matrix is symmetric, the i^th row and column
-  // are equal.
-  //
-  // The ifdef separates two different version of SuiteSparse. Newer
-  // versions of SuiteSparse have the cholmod_solve2 function which
-  // re-uses memory across calls.
-#if (SUITESPARSE_VERSION < 4002)
-  cholmod_dense* rhs = ss.CreateDenseVector(NULL, num_rows, num_rows);
-  double* rhs_x = reinterpret_cast<double*>(rhs->x);
-
-  for (int r = 0; r < num_rows; ++r) {
-    int row_begin = rows[r];
-    int row_end = rows[r + 1];
-    if (row_end == row_begin) {
-      continue;
-    }
-
-    rhs_x[r] = 1.0;
-    cholmod_dense* solution = ss.Solve(factor, rhs, &message);
-    double* solution_x = reinterpret_cast<double*>(solution->x);
-    for (int idx = row_begin; idx < row_end; ++idx) {
-      const int c = cols[idx];
-      values[idx] = solution_x[c];
-    }
-    ss.Free(solution);
-    rhs_x[r] = 0.0;
-  }
-
-  ss.Free(rhs);
-#else  // SUITESPARSE_VERSION < 4002
-
-  const int num_threads = options_.num_threads;
-  vector<PerThreadContext*> contexts(num_threads);
-  for (int i = 0; i < num_threads; ++i) {
-    contexts[i] = new PerThreadContext(num_rows);
-  }
-
-  // The first call to cholmod_solve2 is not thread safe, since it
-  // changes the factorization from supernodal to simplicial etc.
-  {
-    PerThreadContext* context = contexts[0];
-    double* context_rhs_x =  reinterpret_cast<double*>(context->rhs->x);
-    context_rhs_x[0] = 1.0;
-    cholmod_solve2(CHOLMOD_A,
-                   factor,
-                   context->rhs,
-                   NULL,
-                   &context->solution,
-                   &context->solution_set,
-                   &context->y_workspace,
-                   &context->e_workspace,
-                   context->ss.mutable_cc());
-    context_rhs_x[0] = 0.0;
-  }
-
-#pragma omp parallel for num_threads(num_threads) schedule(dynamic)
-  for (int r = 0; r < num_rows; ++r) {
-    int row_begin = rows[r];
-    int row_end = rows[r + 1];
-    if (row_end == row_begin) {
-      continue;
-    }
-
-#  ifdef CERES_USE_OPENMP
-    int thread_id = omp_get_thread_num();
-#  else
-    int thread_id = 0;
-#  endif
-
-    PerThreadContext* context = contexts[thread_id];
-    double* context_rhs_x =  reinterpret_cast<double*>(context->rhs->x);
-    context_rhs_x[r] = 1.0;
-
-    // TODO(sameeragarwal) There should be a more efficient way
-    // involving the use of Bset but I am unable to make it work right
-    // now.
-    cholmod_solve2(CHOLMOD_A,
-                   factor,
-                   context->rhs,
-                   NULL,
-                   &context->solution,
-                   &context->solution_set,
-                   &context->y_workspace,
-                   &context->e_workspace,
-                   context->ss.mutable_cc());
-
-    double* solution_x = reinterpret_cast<double*>(context->solution->x);
-    for (int idx = row_begin; idx < row_end; ++idx) {
-      const int c = cols[idx];
-      values[idx] = solution_x[c];
-    }
-    context_rhs_x[r] = 0.0;
-  }
-
-  for (int i = 0; i < num_threads; ++i) {
-    delete contexts[i];
-  }
-
-#endif  // SUITESPARSE_VERSION < 4002
-
-  ss.Free(factor);
-  event_logger.AddEvent("Inversion");
-  return true;
-
-#else  // CERES_NO_SUITESPARSE
-
-  return false;
-
-#endif  // CERES_NO_SUITESPARSE
-};
-
-bool CovarianceImpl::ComputeCovarianceValuesUsingSparseQR() {
+bool CovarianceImpl::ComputeCovarianceValuesUsingSuiteSparseQR() {
   EventLogger event_logger(
       "CovarianceImpl::ComputeCovarianceValuesUsingSparseQR");
 
@@ -851,7 +659,102 @@ bool CovarianceImpl::ComputeCovarianceValuesUsingDenseSVD() {
   }
   event_logger.AddEvent("CopyToCovarianceMatrix");
   return true;
-};
+}
+
+bool CovarianceImpl::ComputeCovarianceValuesUsingEigenSparseQR() {
+  EventLogger event_logger(
+      "CovarianceImpl::ComputeCovarianceValuesUsingEigenSparseQR");
+  if (covariance_matrix_.get() == NULL) {
+    // Nothing to do, all zeros covariance matrix.
+    return true;
+  }
+
+  CRSMatrix jacobian;
+  problem_->Evaluate(evaluate_options_, NULL, NULL, NULL, &jacobian);
+  event_logger.AddEvent("Evaluate");
+
+  typedef Eigen::SparseMatrix<double, Eigen::ColMajor> EigenSparseMatrix;
+
+  // Convert the matrix to column major order as required by SparseQR.
+  EigenSparseMatrix sparse_jacobian =
+      Eigen::MappedSparseMatrix<double, Eigen::RowMajor>(
+          jacobian.num_rows, jacobian.num_cols,
+          static_cast<int>(jacobian.values.size()),
+          jacobian.rows.data(), jacobian.cols.data(), jacobian.values.data());
+  event_logger.AddEvent("ConvertToSparseMatrix");
+
+  Eigen::SparseQR<EigenSparseMatrix, Eigen::COLAMDOrdering<int> >
+      qr_solver(sparse_jacobian);
+  event_logger.AddEvent("QRDecomposition");
+
+  if(qr_solver.info() != Eigen::Success) {
+    LOG(ERROR) << "Eigen::SparseQR decomposition failed.";
+    return false;
+  }
+
+  if (qr_solver.rank() < jacobian.num_cols) {
+    LOG(ERROR) << "Jacobian matrix is rank deficient. "
+               << "Number of columns: " << jacobian.num_cols
+               << " rank: " << qr_solver.rank();
+    return false;
+  }
+
+  const int* rows = covariance_matrix_->rows();
+  const int* cols = covariance_matrix_->cols();
+  double* values = covariance_matrix_->mutable_values();
+
+  // Compute the inverse column permutation used by QR factorization.
+  Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic> inverse_permutation =
+      qr_solver.colsPermutation().inverse();
+
+  // The following loop exploits the fact that the i^th column of A^{-1}
+  // is given by the solution to the linear system
+  //
+  //  A x = e_i
+  //
+  // where e_i is a vector with e(i) = 1 and all other entries zero.
+  //
+  // Since the covariance matrix is symmetric, the i^th row and column
+  // are equal.
+  const int num_cols = jacobian.num_cols;
+  const int num_threads = options_.num_threads;
+  scoped_array<double> workspace(new double[num_threads * num_cols]);
+
+#pragma omp parallel for num_threads(num_threads) schedule(dynamic)
+  for (int r = 0; r < num_cols; ++r) {
+    const int row_begin = rows[r];
+    const int row_end = rows[r + 1];
+    if (row_end == row_begin) {
+      continue;
+    }
+
+#  ifdef CERES_USE_OPENMP
+    int thread_id = omp_get_thread_num();
+#  else
+    int thread_id = 0;
+#  endif
+
+    double* solution = workspace.get() + thread_id * num_cols;
+    SolveRTRWithSparseRHS<int>(
+        num_cols,
+        qr_solver.matrixR().innerIndexPtr(),
+        qr_solver.matrixR().outerIndexPtr(),
+        &qr_solver.matrixR().data().value(0),
+        inverse_permutation.indices().coeff(r),
+        solution);
+
+    // Assign the values of the computed covariance using the
+    // inverse permutation used in the QR factorization.
+    for (int idx = row_begin; idx < row_end; ++idx) {
+     const int c = cols[idx];
+     values[idx] = solution[inverse_permutation.indices().coeff(c)];
+    }
+  }
+
+  event_logger.AddEvent("Inverse");
+
+  return true;
+}
 
 }  // namespace internal
 }  // namespace ceres
index 0e7e21730793a88b7f95b8ef284bfd362c8ee712..135f4a1d62475b03fbecaf07907186120245eb3a 100644 (file)
@@ -64,9 +64,9 @@ class CovarianceImpl {
       ProblemImpl* problem);
 
   bool ComputeCovarianceValues();
-  bool ComputeCovarianceValuesUsingSparseCholesky();
-  bool ComputeCovarianceValuesUsingSparseQR();
   bool ComputeCovarianceValuesUsingDenseSVD();
+  bool ComputeCovarianceValuesUsingSuiteSparseQR();
+  bool ComputeCovarianceValuesUsingEigenSparseQR();
 
   const CompressedRowSparseMatrix* covariance_matrix() const {
     return covariance_matrix_.get();
index 1fed82f7866bfbfae56ae9a592ab3388f5cbb4de..5868401b9613b6dbacf07c184351590b18ea7f97 100644 (file)
@@ -38,7 +38,6 @@
 
 #include <vector>
 #include "cs.h"
-#include "ceres/internal/port.h"
 
 namespace ceres {
 namespace internal {
@@ -130,9 +129,13 @@ class CXSparse {
 
 #else  // CERES_NO_CXSPARSE
 
-class CXSparse {};
 typedef void cs_dis;
 
+class CXSparse {
+ public:
+  void Free(void*) {};
+
+};
 #endif  // CERES_NO_CXSPARSE
 
 #endif  // CERES_INTERNAL_CXSPARSE_H_
index 2f01617749d8a10cc39adaf53640709b2b6cc963..b46cb797ff2d26759e9e9323c803a72197bc9d45 100644 (file)
@@ -54,8 +54,15 @@ SparseMatrix* DynamicCompressedRowJacobianWriter::CreateJacobian() const {
                                            num_effective_parameters,
                                            0);
 
-  CompressedRowJacobianWriter::PopulateJacobianRowAndColumnBlockVectors(
-      program_, jacobian);
+  vector<int>* row_blocks = jacobian->mutable_row_blocks();
+  for (int i = 0; i < jacobian->num_rows(); ++i) {
+    row_blocks->push_back(1);
+  }
+
+  vector<int>* col_blocks = jacobian->mutable_col_blocks();
+  for (int i = 0; i < jacobian->num_cols(); ++i) {
+    col_blocks->push_back(1);
+  }
 
   return jacobian;
 }
index bca22e6de03587709f6263bd177a0ef47ce3e263..3272848a499955d98d9907d770b91332881d75d8 100644 (file)
@@ -310,6 +310,17 @@ ProblemImpl* CreateGradientCheckingProblemImpl(ProblemImpl* problem_impl,
         parameter_blocks);
   }
 
+  // Normally, when a problem is given to the solver, we guarantee
+  // that the state pointers for each parameter block point to the
+  // user provided data. Since we are creating this new problem from a
+  // problem given to us at an arbitrary stage of the solve, we cannot
+  // depend on this being the case, so we explicitly call
+  // SetParameterBlockStatePtrsToUserStatePtrs to ensure that this is
+  // the case.
+  gradient_checking_problem_impl
+      ->mutable_program()
+      ->SetParameterBlockStatePtrsToUserStatePtrs();
+
   return gradient_checking_problem_impl;
 }
 
diff --git a/extern/libmv/third_party/ceres/internal/ceres/gradient_problem.cc b/extern/libmv/third_party/ceres/internal/ceres/gradient_problem.cc
new file mode 100644 (file)
index 0000000..8f9a842
--- /dev/null
@@ -0,0 +1,81 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2014 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/gradient_problem.h"
+#include "ceres/local_parameterization.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+GradientProblem::GradientProblem(FirstOrderFunction* function)
+    : function_(function),
+      parameterization_(
+          new IdentityParameterization(function_->NumParameters())),
+      scratch_(new double[function_->NumParameters()]) {
+}
+
+GradientProblem::GradientProblem(FirstOrderFunction* function,
+                                 LocalParameterization* parameterization)
+      : function_(function),
+        parameterization_(parameterization),
+        scratch_(new double[function_->NumParameters()]) {
+  CHECK_EQ(function_->NumParameters(), parameterization_->GlobalSize());
+}
+
+int GradientProblem::NumParameters() const {
+  return function_->NumParameters();
+}
+
+int GradientProblem::NumLocalParameters() const {
+  return parameterization_->LocalSize();
+}
+
+
+bool GradientProblem::Evaluate(const double* parameters,
+                               double* cost,
+                               double* gradient) const {
+  if (gradient == NULL) {
+    return function_->Evaluate(parameters, cost, NULL);
+  }
+
+  return (function_->Evaluate(parameters, cost, scratch_.get()) &&
+          parameterization_->MultiplyByJacobian(parameters,
+                                                1,
+                                                scratch_.get(),
+                                                gradient));
+}
+
+bool GradientProblem::Plus(const double* x,
+                           const double* delta,
+                           double* x_plus_delta) const {
+  return parameterization_->Plus(x, delta, x_plus_delta);
+}
+
+}  // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/gradient_problem_evaluator.h b/extern/libmv/third_party/ceres/internal/ceres/gradient_problem_evaluator.h
new file mode 100644 (file)
index 0000000..20053de
--- /dev/null
@@ -0,0 +1,98 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2013 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_GRADIENT_PROBLEM_EVALUATOR_H_
+#define CERES_INTERNAL_GRADIENT_PROBLEM_EVALUATOR_H_
+
+#include <map>
+#include <string>
+
+#include "ceres/evaluator.h"
+#include "ceres/execution_summary.h"
+#include "ceres/gradient_problem.h"
+#include "ceres/internal/port.h"
+#include "ceres/wall_time.h"
+
+namespace ceres {
+namespace internal {
+
+class GradientProblemEvaluator : public Evaluator {
+ public:
+  explicit GradientProblemEvaluator(const GradientProblem& problem)
+      : problem_(problem) {}
+  virtual ~GradientProblemEvaluator() {}
+  virtual SparseMatrix* CreateJacobian() const { return NULL; }
+  virtual bool Evaluate(const EvaluateOptions& evaluate_options,
+                        const double* state,
+                        double* cost,
+                        double* residuals,
+                        double* gradient,
+                        SparseMatrix* jacobian) {
+    CHECK(jacobian == NULL);
+    ScopedExecutionTimer total_timer("Evaluator::Total", &execution_summary_);
+    ScopedExecutionTimer call_type_timer(
+        gradient == NULL ? "Evaluator::Cost" : "Evaluator::Gradient",
+        &execution_summary_);
+    return problem_.Evaluate(state, cost, gradient);
+  }
+
+  virtual bool Plus(const double* state,
+                    const double* delta,
+                    double* state_plus_delta) const {
+    return problem_.Plus(state, delta, state_plus_delta);
+  }
+
+  virtual int NumParameters() const {
+    return problem_.NumParameters();
+  }
+
+  virtual int NumEffectiveParameters()  const {
+    return problem_.NumLocalParameters();
+  }
+
+  virtual int NumResiduals() const { return 1; }
+
+  virtual map<string, int> CallStatistics() const {
+    return execution_summary_.calls();
+  }
+
+  virtual map<string, double> TimeStatistics() const {
+    return execution_summary_.times();
+  }
+
+ private:
+  const GradientProblem& problem_;
+  ::ceres::internal::ExecutionSummary execution_summary_;
+};
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_INTERNAL_GRADIENT_PROBLEM_EVALUATOR_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/gradient_problem_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/gradient_problem_solver.cc
new file mode 100644 (file)
index 0000000..4024f4c
--- /dev/null
@@ -0,0 +1,270 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2014 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/gradient_problem_solver.h"
+
+#include "ceres/callbacks.h"
+#include "ceres/gradient_problem.h"
+#include "ceres/gradient_problem_evaluator.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/port.h"
+#include "ceres/map_util.h"
+#include "ceres/minimizer.h"
+#include "ceres/solver.h"
+#include "ceres/solver_utils.h"
+#include "ceres/stringprintf.h"
+#include "ceres/types.h"
+#include "ceres/wall_time.h"
+
+namespace ceres {
+using internal::StringPrintf;
+using internal::StringAppendF;
+
+namespace {
+
+Solver::Options GradientProblemSolverOptionsToSolverOptions(
+    const GradientProblemSolver::Options& options) {
+#define COPY_OPTION(x) solver_options.x = options.x
+
+  Solver::Options solver_options;
+  solver_options.minimizer_type = LINE_SEARCH;
+  COPY_OPTION(line_search_direction_type);
+  COPY_OPTION(line_search_type);
+  COPY_OPTION(nonlinear_conjugate_gradient_type);
+  COPY_OPTION(max_lbfgs_rank);
+  COPY_OPTION(use_approximate_eigenvalue_bfgs_scaling);
+  COPY_OPTION(line_search_interpolation_type);
+  COPY_OPTION(min_line_search_step_size);
+  COPY_OPTION(line_search_sufficient_function_decrease);
+  COPY_OPTION(max_line_search_step_contraction);
+  COPY_OPTION(min_line_search_step_contraction);
+  COPY_OPTION(max_num_line_search_step_size_iterations);
+  COPY_OPTION(max_num_line_search_direction_restarts);
+  COPY_OPTION(line_search_sufficient_curvature_decrease);
+  COPY_OPTION(max_line_search_step_expansion);
+  COPY_OPTION(max_num_iterations);
+  COPY_OPTION(max_solver_time_in_seconds);
+  COPY_OPTION(function_tolerance);
+  COPY_OPTION(gradient_tolerance);
+  COPY_OPTION(logging_type);
+  COPY_OPTION(minimizer_progress_to_stdout);
+  COPY_OPTION(callbacks);
+  return solver_options;
+#undef COPY_OPTION
+}
+
+
+}  // namespace
+
+GradientProblemSolver::~GradientProblemSolver() {
+}
+
+void GradientProblemSolver::Solve(const GradientProblemSolver::Options& options,
+                                  const GradientProblem& problem,
+                                  double* parameters_ptr,
+                                  GradientProblemSolver::Summary* summary) {
+  using internal::scoped_ptr;
+  using internal::WallTimeInSeconds;
+  using internal::Minimizer;
+  using internal::GradientProblemEvaluator;
+  using internal::LoggingCallback;
+  using internal::SetSummaryFinalCost;
+
+  double start_time = WallTimeInSeconds();
+  Solver::Options solver_options =
+      GradientProblemSolverOptionsToSolverOptions(options);
+
+  *CHECK_NOTNULL(summary) = Summary();
+  summary->num_parameters                    = problem.NumParameters();
+  summary->num_local_parameters              = problem.NumLocalParameters();
+  summary->line_search_direction_type        = options.line_search_direction_type;         //  NOLINT
+  summary->line_search_interpolation_type    = options.line_search_interpolation_type;     //  NOLINT
+  summary->line_search_type                  = options.line_search_type;
+  summary->max_lbfgs_rank                    = options.max_lbfgs_rank;
+  summary->nonlinear_conjugate_gradient_type = options.nonlinear_conjugate_gradient_type;  //  NOLINT
+
+  // Check validity
+  if (!solver_options.IsValid(&summary->message)) {
+    LOG(ERROR) << "Terminating: " << summary->message;
+    return;
+  }
+
+  // Assuming that the parameter blocks in the program have been
+  Minimizer::Options minimizer_options;
+  minimizer_options = Minimizer::Options(solver_options);
+  minimizer_options.evaluator.reset(new GradientProblemEvaluator(problem));
+
+  scoped_ptr<IterationCallback> logging_callback;
+  if (options.logging_type != SILENT) {
+    logging_callback.reset(
+        new LoggingCallback(LINE_SEARCH, options.minimizer_progress_to_stdout));
+    minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
+                                       logging_callback.get());
+  }
+
+  scoped_ptr<Minimizer> minimizer(Minimizer::Create(LINE_SEARCH));
+  Vector solution(problem.NumParameters());
+  VectorRef parameters(parameters_ptr, problem.NumParameters());
+  solution = parameters;
+
+  Solver::Summary solver_summary;
+  solver_summary.fixed_cost = 0.0;
+  solver_summary.preprocessor_time_in_seconds = 0.0;
+  solver_summary.postprocessor_time_in_seconds = 0.0;
+
+  minimizer->Minimize(minimizer_options, solution.data(), &solver_summary);
+
+  summary->termination_type = solver_summary.termination_type;
+  summary->message          = solver_summary.message;
+  summary->initial_cost     = solver_summary.initial_cost;
+  summary->final_cost       = solver_summary.final_cost;
+  summary->iterations       = solver_summary.iterations;
+
+  if (summary->IsSolutionUsable()) {
+    parameters = solution;
+    SetSummaryFinalCost(summary);
+  }
+
+  const map<string, double>& evaluator_time_statistics =
+       minimizer_options.evaluator->TimeStatistics();
+  summary->cost_evaluation_time_in_seconds =
+      FindWithDefault(evaluator_time_statistics, "Evaluator::Residual", 0.0);
+  summary->gradient_evaluation_time_in_seconds =
+      FindWithDefault(evaluator_time_statistics, "Evaluator::Jacobian", 0.0);
+
+  summary->total_time_in_seconds = WallTimeInSeconds() - start_time;
+}
+
+// Invalid values for most fields, to ensure that we are not
+// accidentally reporting default values.
+GradientProblemSolver::Summary::Summary()
+    : termination_type(FAILURE),
+      message("ceres::GradientProblemSolve was not called."),
+      initial_cost(-1.0),
+      final_cost(-1.0),
+      total_time_in_seconds(-1.0),
+      cost_evaluation_time_in_seconds(-1.0),
+      gradient_evaluation_time_in_seconds(-1.0),
+      num_parameters(-1),
+      num_local_parameters(-1),
+      line_search_direction_type(LBFGS),
+      line_search_type(ARMIJO),
+      line_search_interpolation_type(BISECTION),
+      nonlinear_conjugate_gradient_type(FLETCHER_REEVES),
+      max_lbfgs_rank(-1) {
+}
+
+bool GradientProblemSolver::Summary::IsSolutionUsable() const {
+  return internal::IsSolutionUsable(*this);
+}
+
+string GradientProblemSolver::Summary::BriefReport() const {
+  return StringPrintf("Ceres GradientProblemSolver Report: "
+                      "Iterations: %d, "
+                      "Initial cost: %e, "
+                      "Final cost: %e, "
+                      "Termination: %s",
+                      static_cast<int>(iterations.size()),
+                      initial_cost,
+                      final_cost,
+                      TerminationTypeToString(termination_type));
+};
+
+string GradientProblemSolver::Summary::FullReport() const {
+  using internal::VersionString;
+
+  string report = string("\nSolver Summary (v " + VersionString() + ")\n\n");
+
+  StringAppendF(&report, "Parameters          % 25d\n", num_parameters);
+  if (num_local_parameters != num_parameters) {
+    StringAppendF(&report, "Local parameters    % 25d\n",
+                  num_local_parameters);
+  }
+
+  string line_search_direction_string;
+  if (line_search_direction_type == LBFGS) {
+    line_search_direction_string = StringPrintf("LBFGS (%d)", max_lbfgs_rank);
+  } else if (line_search_direction_type == NONLINEAR_CONJUGATE_GRADIENT) {
+    line_search_direction_string =
+        NonlinearConjugateGradientTypeToString(
+            nonlinear_conjugate_gradient_type);
+  } else {
+    line_search_direction_string =
+        LineSearchDirectionTypeToString(line_search_direction_type);
+  }
+
+  StringAppendF(&report, "Line search direction     %19s\n",
+                line_search_direction_string.c_str());
+
+  const string line_search_type_string =
+      StringPrintf("%s %s",
+                   LineSearchInterpolationTypeToString(
+                       line_search_interpolation_type),
+                   LineSearchTypeToString(line_search_type));
+  StringAppendF(&report, "Line search type          %19s\n",
+                line_search_type_string.c_str());
+  StringAppendF(&report, "\n");
+
+  StringAppendF(&report, "\nCost:\n");
+  StringAppendF(&report, "Initial        % 30e\n", initial_cost);
+  if (termination_type != FAILURE &&
+      termination_type != USER_FAILURE) {
+    StringAppendF(&report, "Final          % 30e\n", final_cost);
+    StringAppendF(&report, "Change         % 30e\n",
+                  initial_cost - final_cost);
+  }
+
+  StringAppendF(&report, "\nMinimizer iterations         % 16d\n",
+                static_cast<int>(iterations.size()));
+
+  StringAppendF(&report, "\nTime (in seconds):\n");
+
+  StringAppendF(&report, "\n  Cost evaluation     %23.3f\n",
+                cost_evaluation_time_in_seconds);
+  StringAppendF(&report, "  Gradient evaluation %23.3f\n",
+                gradient_evaluation_time_in_seconds);
+
+  StringAppendF(&report, "Total               %25.3f\n\n",
+                total_time_in_seconds);
+
+  StringAppendF(&report, "Termination:        %25s (%s)\n",
+                TerminationTypeToString(termination_type), message.c_str());
+  return report;
+};
+
+void Solve(const GradientProblemSolver::Options& options,
+           const GradientProblem& problem,
+           double* parameters,
+           GradientProblemSolver::Summary* summary) {
+  GradientProblemSolver solver;
+  solver.Solve(options, problem, parameters, summary);
+}
+
+}  // namespace ceres
index 5f92d4d4df2dc2a7266c3902ee2000eed39770ea..f639d15323d1d56378d075ed8f719fc6baf862e7 100644 (file)
 namespace ceres {
 namespace internal {
 
-// A weighted undirected graph templated over the vertex ids. Vertex
-// should be hashable and comparable.
+// A unweighted undirected graph templated over the vertex ids. Vertex
+// should be hashable.
 template <typename Vertex>
 class Graph {
  public:
   Graph() {}
 
+  // Add a vertex.
+  void AddVertex(const Vertex& vertex) {
+    if (vertices_.insert(vertex).second) {
+      edges_[vertex] = HashSet<Vertex>();
+    }
+  }
+
+  bool RemoveVertex(const Vertex& vertex) {
+    if (vertices_.find(vertex) == vertices_.end()) {
+      return false;
+    }
+
+    vertices_.erase(vertex);
+    const HashSet<Vertex>& sinks = edges_[vertex];
+    for (typename HashSet<Vertex>::const_iterator it = sinks.begin();
+         it != sinks.end(); ++it) {
+      edges_[*it].erase(vertex);
+    }
+
+    edges_.erase(vertex);
+    return true;
+  }
+
+  // Add an edge between the vertex1 and vertex2. Calling AddEdge on a
+  // pair of vertices which do not exist in the graph yet will result
+  // in undefined behavior.
+  //
+  // It is legal to call this method repeatedly for the same set of
+  // vertices.
+  void AddEdge(const Vertex& vertex1, const Vertex& vertex2) {
+    DCHECK(vertices_.find(vertex1) != vertices_.end());
+    DCHECK(vertices_.find(vertex2) != vertices_.end());
+
+    if (edges_[vertex1].insert(vertex2).second) {
+      edges_[vertex2].insert(vertex1);
+    }
+  }
+
+  // Calling Neighbors on a vertex not in the graph will result in
+  // undefined behaviour.
+  const HashSet<Vertex>& Neighbors(const Vertex& vertex) const {
+    return FindOrDie(edges_, vertex);
+  }
+
+  const HashSet<Vertex>& vertices() const {
+    return vertices_;
+  }
+
+ private:
+  HashSet<Vertex> vertices_;
+  HashMap<Vertex, HashSet<Vertex> > edges_;
+
+  CERES_DISALLOW_COPY_AND_ASSIGN(Graph);
+};
+
+// A weighted undirected graph templated over the vertex ids. Vertex
+// should be hashable and comparable.
+template <typename Vertex>
+class WeightedGraph {
+ public:
+  WeightedGraph() {}
+
   // Add a weighted vertex. If the vertex already exists in the graph,
   // its weight is set to the new weight.
   void AddVertex(const Vertex& vertex, double weight) {
@@ -152,7 +214,7 @@ class Graph {
   HashMap<Vertex, HashSet<Vertex> > edges_;
   HashMap<pair<Vertex, Vertex>, double> edge_weights_;
 
-  CERES_DISALLOW_COPY_AND_ASSIGN(Graph);
+  CERES_DISALLOW_COPY_AND_ASSIGN(WeightedGraph);
 };
 
 }  // namespace internal
index ca3a2fe1a88d5a3798d67e9e6da408f113bfba27..fb75e2f45f2ace1a7bd97fbb1d13ce3d13d56b17 100644 (file)
@@ -38,6 +38,7 @@
 #include <utility>
 #include "ceres/collections_port.h"
 #include "ceres/graph.h"
+#include "ceres/wall_time.h"
 #include "glog/logging.h"
 
 namespace ceres {
@@ -270,11 +271,11 @@ Vertex FindConnectedComponent(const Vertex& vertex,
 // spanning forest, or a collection of linear paths that span the
 // graph G.
 template <typename Vertex>
-Graph<Vertex>*
-Degree2MaximumSpanningForest(const Graph<Vertex>& graph) {
+WeightedGraph<Vertex>*
+Degree2MaximumSpanningForest(const WeightedGraph<Vertex>& graph) {
   // Array of edges sorted in decreasing order of their weights.
   vector<pair<double, pair<Vertex, Vertex> > > weighted_edges;
-  Graph<Vertex>* forest = new Graph<Vertex>();
+  WeightedGraph<Vertex>* forest = new WeightedGraph<Vertex>();
 
   // Disjoint-set to keep track of the connected components in the
   // maximum spanning tree.
index 6de410bf80fbe255cbb9a547a9423db7f61cc217..0cf08fef5f7d43b5722d1979a8c624b32bb820ed 100644 (file)
@@ -101,6 +101,7 @@ LinearSolver::Summary IterativeSchurComplementSolver::SolveImpl(
   // complement matrix with the block diagonal of the matrix F'F as
   // the preconditioner.
   LinearSolver::Options cg_options;
+  cg_options.min_num_iterations = options_.min_num_iterations;
   cg_options.max_num_iterations = options_.max_num_iterations;
   ConjugateGradientsSolver cg_solver(cg_options);
   LinearSolver::PerSolveOptions cg_per_solve_options;
index e04c65b63be370fd992f65cca8e6e090356d256d..dddcecdb1963305b45e1c437a6084602eacd8509 100644 (file)
@@ -65,7 +65,7 @@ class NonlinearConjugateGradient : public LineSearchDirection {
       case FLETCHER_REEVES:
         beta = current.gradient_squared_norm / previous.gradient_squared_norm;
         break;
-      case POLAK_RIBIRERE:
+      case POLAK_RIBIERE:
         gradient_change = current.gradient - previous.gradient;
         beta = (current.gradient.dot(gradient_change) /
                 previous.gradient_squared_norm);
index ae77a73805c9cca5f2b3309812298301423bb18e..ad28ffb137d94a816d80d6444a393099be7f437a 100644 (file)
@@ -103,7 +103,7 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
   double start_time = WallTimeInSeconds();
   double iteration_start_time =  start_time;
 
-  Evaluator* evaluator = CHECK_NOTNULL(options.evaluator);
+  Evaluator* evaluator = CHECK_NOTNULL(options.evaluator.get());
   const int num_parameters = evaluator->NumParameters();
   const int num_effective_parameters = evaluator->NumEffectiveParameters();
 
@@ -375,7 +375,6 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
         WallTimeInSeconds() - start_time
         + summary->preprocessor_time_in_seconds;
 
-    summary->iterations.push_back(iteration_summary);
     ++summary->num_successful_steps;
 
     if (iteration_summary.gradient_max_norm <= options.gradient_tolerance) {
@@ -401,6 +400,8 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
       VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
       break;
     }
+
+    summary->iterations.push_back(iteration_summary);
   }
 }
 
diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search_preprocessor.cc b/extern/libmv/third_party/ceres/internal/ceres/line_search_preprocessor.cc
new file mode 100644 (file)
index 0000000..bf17dee
--- /dev/null
@@ -0,0 +1,106 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2014 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/line_search_preprocessor.h"
+
+#include <numeric>
+#include <string>
+#include "ceres/evaluator.h"
+#include "ceres/minimizer.h"
+#include "ceres/problem_impl.h"
+#include "ceres/program.h"
+#include "ceres/wall_time.h"
+
+namespace ceres {
+namespace internal {
+namespace {
+
+bool IsProgramValid(const Program& program, string* error) {
+  if (program.IsBoundsConstrained()) {
+    *error = "LINE_SEARCH Minimizer does not support bounds.";
+    return false;
+  }
+  return program.ParameterBlocksAreFinite(error);
+}
+
+bool SetupEvaluator(PreprocessedProblem* pp) {
+  pp->evaluator_options = Evaluator::Options();
+  // This ensures that we get a Block Jacobian Evaluator without any
+  // requirement on orderings.
+  pp->evaluator_options.linear_solver_type = CGNR;
+  pp->evaluator_options.num_eliminate_blocks = 0;
+  pp->evaluator_options.num_threads = pp->options.num_threads;
+  pp->evaluator.reset(Evaluator::Create(pp->evaluator_options,
+                                        pp->reduced_program.get(),
+                                        &pp->error));
+  return (pp->evaluator.get() != NULL);
+}
+
+}  // namespace
+
+LineSearchPreprocessor::~LineSearchPreprocessor() {
+}
+
+bool LineSearchPreprocessor::Preprocess(const Solver::Options& options,
+                                        ProblemImpl* problem,
+                                        PreprocessedProblem* pp) {
+  CHECK_NOTNULL(pp);
+  pp->options = options;
+  ChangeNumThreadsIfNeeded(&pp->options);
+
+  pp->problem = problem;
+  Program* program = problem->mutable_program();
+  if (!IsProgramValid(*program, &pp->error)) {
+    return false;
+  }
+
+  pp->reduced_program.reset(
+      program->CreateReducedProgram(&pp->removed_parameter_blocks,
+                                    &pp->fixed_cost,
+                                    &pp->error));
+
+  if (pp->reduced_program.get() == NULL) {
+    return false;
+  }
+
+  if (pp->reduced_program->NumParameterBlocks() == 0) {
+    return true;
+  }
+
+  if (!SetupEvaluator(pp)) {
+    return false;
+  }
+
+  SetupCommonMinimizerOptions(pp);
+  return true;
+}
+
+}  // namespace internal
+}  // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search_preprocessor.h b/extern/libmv/third_party/ceres/internal/ceres/line_search_preprocessor.h
new file mode 100644 (file)
index 0000000..54b968b
--- /dev/null
@@ -0,0 +1,50 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2014 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_LINE_SEARCH_PREPROCESSOR_H_
+#define CERES_INTERNAL_LINE_SEARCH_PREPROCESSOR_H_
+
+#include "ceres/preprocessor.h"
+
+namespace ceres {
+namespace internal {
+
+class LineSearchPreprocessor : public Preprocessor {
+ public:
+  virtual ~LineSearchPreprocessor();
+  virtual bool Preprocess(const Solver::Options& options,
+                          ProblemImpl* problem,
+                          PreprocessedProblem* preprocessed_problem);
+};
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_INTERNAL_LINE_SEARCH_PREPROCESSOR_H_
index 08c3ba110d058d340a6f8315092fd5e06eed2463..d905ec2e1fdd362210aba9dd2de2a4beb6dcca03 100644 (file)
@@ -45,26 +45,48 @@ namespace internal {
 LinearSolver::~LinearSolver() {
 }
 
+LinearSolverType LinearSolver::LinearSolverForZeroEBlocks(
+    LinearSolverType linear_solver_type) {
+  if (!IsSchurType(linear_solver_type)) {
+    return linear_solver_type;
+  }
+
+  if (linear_solver_type == SPARSE_SCHUR) {
+    return SPARSE_NORMAL_CHOLESKY;
+  }
+
+  if (linear_solver_type == DENSE_SCHUR) {
+    // TODO(sameeragarwal): This is probably not a great choice.
+    // Ideally, we should have a DENSE_NORMAL_CHOLESKY, that can take
+    // a BlockSparseMatrix as input.
+    return DENSE_QR;
+  }
+
+  if (linear_solver_type == ITERATIVE_SCHUR) {
+    return CGNR;
+  }
+
+  return linear_solver_type;
+}
+
 LinearSolver* LinearSolver::Create(const LinearSolver::Options& options) {
   switch (options.type) {
     case CGNR:
       return new CgnrSolver(options);
 
     case SPARSE_NORMAL_CHOLESKY:
-#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE)
-      LOG(WARNING) << "SPARSE_NORMAL_CHOLESKY is not available. Please "
-                   << "build Ceres with SuiteSparse or CXSparse. "
-                   << "Returning NULL.";
+#if defined(CERES_NO_SUITESPARSE) &&              \
+    defined(CERES_NO_CXSPARSE) &&                 \
+   !defined(CERES_USE_EIGEN_SPARSE)
       return NULL;
 #else
       return new SparseNormalCholeskySolver(options);
 #endif
 
     case SPARSE_SCHUR:
-#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE)
-      LOG(WARNING) << "SPARSE_SCHUR is not available. Please "
-                   << "build Ceres with SuiteSparse or CXSparse. "
-                   << "Returning NULL.";
+#if defined(CERES_NO_SUITESPARSE) &&                 \
+    defined(CERES_NO_CXSPARSE) &&                    \
+   !defined(CERES_USE_EIGEN_SPARSE)
       return NULL;
 #else
       return new SparseSchurComplementSolver(options);
index f091bc5b187572078a6ef61dbc33793c1e84b50a..58b9044b8f99f642066406f7086e5622a1f96eb2 100644 (file)
@@ -274,6 +274,14 @@ class LinearSolver {
     string message;
   };
 
+  // If the optimization problem is such that there are no remaining
+  // e-blocks, a Schur type linear solver cannot be used. If the
+  // linear solver is of Schur type, this function implements a policy
+  // to select an alternate nearest linear solver to the one selected
+  // by the user. The input linear_solver_type is returned otherwise.
+  static LinearSolverType LinearSolverForZeroEBlocks(
+      LinearSolverType linear_solver_type);
+
   virtual ~LinearSolver();
 
   // Solve Ax = b.
index 26e7f4908a4e7c40acaa80d48a718b16d1c7490b..a4832c574435d851c4cb57d29d8b95d87eb0ea3a 100644 (file)
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
+// Copyright 2014 Google Inc. All rights reserved.
 // http://code.google.com/p/ceres-solver/
 //
 // Redistribution and use in source and binary forms, with or without
 
 namespace ceres {
 
+LocalParameterization::~LocalParameterization() {
+}
+
+bool LocalParameterization::MultiplyByJacobian(const double* x,
+                                               const int num_rows,
+                                               const double* global_matrix,
+                                               double* local_matrix) const {
+  Matrix jacobian(GlobalSize(), LocalSize());
+  if (!ComputeJacobian(x, jacobian.data())) {
+    return false;
+  }
+
+  MatrixRef(local_matrix, num_rows, LocalSize()) =
+      ConstMatrixRef(global_matrix, num_rows, GlobalSize()) * jacobian;
+  return true;
+}
+
 IdentityParameterization::IdentityParameterization(const int size)
     : size_(size) {
   CHECK_GT(size, 0);
@@ -55,6 +72,16 @@ bool IdentityParameterization::ComputeJacobian(const double* x,
   return true;
 }
 
+bool IdentityParameterization::MultiplyByJacobian(const double* x,
+                                                  const int num_cols,
+                                                  const double* global_matrix,
+                                                  double* local_matrix) const {
+  std::copy(global_matrix,
+            global_matrix + num_cols * GlobalSize(),
+            local_matrix);
+  return true;
+}
+
 SubsetParameterization::SubsetParameterization(
     int size,
     const vector<int>& constant_parameters)
@@ -108,6 +135,21 @@ bool SubsetParameterization::ComputeJacobian(const double* x,
   return true;
 }
 
+bool SubsetParameterization::MultiplyByJacobian(const double* x,
+                                               const int num_rows,
+                                               const double* global_matrix,
+                                               double* local_matrix) const {
+  for (int row = 0; row < num_rows; ++row) {
+    for (int col = 0, j = 0; col < constancy_mask_.size(); ++col) {
+      if (!constancy_mask_[col]) {
+        local_matrix[row * LocalSize() + j++] =
+            global_matrix[row * GlobalSize() + col];
+      }
+    }
+  }
+  return true;
+}
+
 bool QuaternionParameterization::Plus(const double* x,
                                       const double* delta,
                                       double* x_plus_delta) const {
index b948f289f21b6a923cc40e8fd29bc2a27aa06cba..62b545be12f29749fd4e7e80da294ea65392ce82 100644 (file)
 
 #include <cmath>
 #include <cstddef>
+#include <limits>
 
 namespace ceres {
 
 void TrivialLoss::Evaluate(double s, double rho[3]) const {
   rho[0] = s;
-  rho[1] = 1;
-  rho[2] = 0;
+  rho[1] = 1.0;
+  rho[2] = 0.0;
 }
 
 void HuberLoss::Evaluate(double s, double rho[3]) const {
@@ -48,32 +49,32 @@ void HuberLoss::Evaluate(double s, double rho[3]) const {
     // Outlier region.
     // 'r' is always positive.
     const double r = sqrt(s);
-    rho[0] = 2 * a_ * r - b_;
-    rho[1] = a_ / r;
-    rho[2] = - rho[1] / (2 * s);
+    rho[0] = 2.0 * a_ * r - b_;
+    rho[1] = std::max(std::numeric_limits<double>::min(), a_ / r);
+    rho[2] = - rho[1] / (2.0 * s);
   } else {
     // Inlier region.
     rho[0] = s;
-    rho[1] = 1;
-    rho[2] = 0;
+    rho[1] = 1.0;
+    rho[2] = 0.0;
   }
 }
 
 void SoftLOneLoss::Evaluate(double s, double rho[3]) const {
-  const double sum = 1 + s * c_;
+  const double sum = 1.0 + s * c_;
   const double tmp = sqrt(sum);
   // 'sum' and 'tmp' are always positive, assuming that 's' is.
-  rho[0] = 2 * b_ * (tmp - 1);
-  rho[1] = 1 / tmp;
-  rho[2] = - (c_ * rho[1]) / (2 * sum);
+  rho[0] = 2.0 * b_ * (tmp - 1.0);
+  rho[1] = std::max(std::numeric_limits<double>::min(), 1.0 / tmp);
+  rho[2] = - (c_ * rho[1]) / (2.0 * sum);
 }
 
 void CauchyLoss::Evaluate(double s, double rho[3]) const {
-  const double sum = 1 + s * c_;
-  const double inv = 1 / sum;
+  const double sum = 1.0 + s * c_;
+  const double inv = 1.0 / sum;
   // 'sum' and 'inv' are always positive, assuming that 's' is.
   rho[0] = b_ * log(sum);
-  rho[1] = inv;
+  rho[1] = std::max(std::numeric_limits<double>::min(), inv);
   rho[2] = - c_ * (inv * inv);
 }
 
@@ -82,8 +83,8 @@ void ArctanLoss::Evaluate(double s, double rho[3]) const {
   const double inv = 1 / sum;
   // 'sum' and 'inv' are always positive.
   rho[0] = a_ * atan2(s, a_);
-  rho[1] = inv;
-  rho[2] = -2 * s * b_ * (inv * inv);
+  rho[1] = std::max(std::numeric_limits<double>::min(), inv);
+  rho[2] = -2.0 * s * b_ * (inv * inv);
 }
 
 TolerantLoss::TolerantLoss(double a, double b)
@@ -108,7 +109,7 @@ void TolerantLoss::Evaluate(double s, double rho[3]) const {
   } else {
     const double e_x = exp(x);
     rho[0] = b_ * log(1.0 + e_x) - c_;
-    rho[1] = e_x / (1.0 + e_x);
+    rho[1] = std::max(std::numeric_limits<double>::min(), e_x / (1.0 + e_x));
     rho[2] = 0.5 / (b_ * (1.0 + cosh(x)));
   }
 }
index 6c3b68dbbc2fdabaa43a55a714a6589988c89a71..558921b8441977f051b8a2dd36209633f65cedf9 100644 (file)
 //
 // Author: sameeragarwal@google.com (Sameer Agarwal)
 
+#include "ceres/line_search_minimizer.h"
 #include "ceres/minimizer.h"
+#include "ceres/trust_region_minimizer.h"
 #include "ceres/types.h"
 #include "glog/logging.h"
 
 namespace ceres {
 namespace internal {
 
+Minimizer* Minimizer::Create(MinimizerType minimizer_type) {
+  if (minimizer_type == TRUST_REGION) {
+    return new TrustRegionMinimizer;
+  }
+
+  if (minimizer_type == LINE_SEARCH) {
+    return new LineSearchMinimizer;
+  }
+
+  LOG(FATAL) << "Unknown minimizer_type: " << minimizer_type;
+  return NULL;
+}
+
+
 Minimizer::~Minimizer() {}
 
 bool Minimizer::RunCallbacks(const Minimizer::Options& options,
index f1da3f704fa305fea2dde74555230bffb665e1c3..dabf07e583a722aa00b332d339a7452217d85a9a 100644 (file)
@@ -41,9 +41,10 @@ namespace ceres {
 namespace internal {
 
 class Evaluator;
-class LinearSolver;
 class SparseMatrix;
 class TrustRegionStrategy;
+class CoordinateDescentMinimizer;
+class LinearSolver;
 
 // Interface for non-linear least squares solvers.
 class Minimizer {
@@ -107,14 +108,10 @@ class Minimizer {
           options.line_search_sufficient_curvature_decrease;
       max_line_search_step_expansion =
           options.max_line_search_step_expansion;
-      is_silent = (options.logging_type == SILENT);
-      evaluator = NULL;
-      trust_region_strategy = NULL;
-      jacobian = NULL;
-      callbacks = options.callbacks;
-      inner_iteration_minimizer = NULL;
       inner_iteration_tolerance = options.inner_iteration_tolerance;
+      is_silent = (options.logging_type == SILENT);
       is_constrained = false;
+      callbacks = options.callbacks;
     }
 
     int max_num_iterations;
@@ -154,10 +151,14 @@ class Minimizer {
     int max_num_line_search_direction_restarts;
     double line_search_sufficient_curvature_decrease;
     double max_line_search_step_expansion;
+    double inner_iteration_tolerance;
 
     // If true, then all logging is disabled.
     bool is_silent;
 
+    // Use a bounds constrained optimization algorithm.
+    bool is_constrained;
+
     // List of callbacks that are executed by the Minimizer at the end
     // of each iteration.
     //
@@ -165,27 +166,23 @@ class Minimizer {
     vector<IterationCallback*> callbacks;
 
     // Object responsible for evaluating the cost, residuals and
-    // Jacobian matrix. The Options struct does not own this pointer.
-    Evaluator* evaluator;
+    // Jacobian matrix.
+    shared_ptr<Evaluator> evaluator;
 
     // Object responsible for actually computing the trust region
-    // step, and sizing the trust region radius. The Options struct
-    // does not own this pointer.
-    TrustRegionStrategy* trust_region_strategy;
+    // step, and sizing the trust region radius.
+    shared_ptr<TrustRegionStrategy> trust_region_strategy;
 
     // Object holding the Jacobian matrix. It is assumed that the
     // sparsity structure of the matrix has already been initialized
     // and will remain constant for the life time of the
-    // optimization. The Options struct does not own this pointer.
-    SparseMatrix* jacobian;
+    // optimization.
+    shared_ptr<SparseMatrix> jacobian;
 
-    Minimizer* inner_iteration_minimizer;
-    double inner_iteration_tolerance;
-
-    // Use a bounds constrained optimization algorithm.
-    bool is_constrained;
+    shared_ptr<CoordinateDescentMinimizer> inner_iteration_minimizer;
   };
 
+  static Minimizer* Create(MinimizerType minimizer_type);
   static bool RunCallbacks(const Options& options,
                            const IterationSummary& iteration_summary,
                            Solver::Summary* summary);
index 190715bee4388bf2fa97e12945f20a23f4f69f5e..1525de90d6090fab6fd7be61611dfdec16811f15 100644 (file)
@@ -37,6 +37,7 @@
 #include "ceres/parameter_block.h"
 #include "ceres/program.h"
 #include "ceres/residual_block.h"
+#include "ceres/wall_time.h"
 #include "glog/logging.h"
 
 namespace ceres {
@@ -45,8 +46,10 @@ namespace internal {
 int ComputeStableSchurOrdering(const Program& program,
                          vector<ParameterBlock*>* ordering) {
   CHECK_NOTNULL(ordering)->clear();
-
+  EventLogger event_logger("ComputeStableSchurOrdering");
   scoped_ptr<Graph< ParameterBlock*> > graph(CreateHessianGraph(program));
+  event_logger.AddEvent("CreateHessianGraph");
+
   const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
   const HashSet<ParameterBlock*>& vertices = graph->vertices();
   for (int i = 0; i < parameter_blocks.size(); ++i) {
@@ -54,8 +57,10 @@ int ComputeStableSchurOrdering(const Program& program,
       ordering->push_back(parameter_blocks[i]);
     }
   }
+  event_logger.AddEvent("Preordering");
 
   int independent_set_size = StableIndependentSetOrdering(*graph, ordering);
+  event_logger.AddEvent("StableIndependentSet");
 
   // Add the excluded blocks to back of the ordering vector.
   for (int i = 0; i < parameter_blocks.size(); ++i) {
@@ -64,6 +69,7 @@ int ComputeStableSchurOrdering(const Program& program,
       ordering->push_back(parameter_block);
     }
   }
+  event_logger.AddEvent("ConstantParameterBlocks");
 
   return independent_set_size;
 }
@@ -109,8 +115,7 @@ void ComputeRecursiveIndependentSetOrdering(const Program& program,
   }
 }
 
-Graph<ParameterBlock*>*
-CreateHessianGraph(const Program& program) {
+Graph<ParameterBlock*>* CreateHessianGraph(const Program& program) {
   Graph<ParameterBlock*>* graph = CHECK_NOTNULL(new Graph<ParameterBlock*>);
   const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
   for (int i = 0; i < parameter_blocks.size(); ++i) {
@@ -144,5 +149,21 @@ CreateHessianGraph(const Program& program) {
   return graph;
 }
 
+void OrderingToGroupSizes(const ParameterBlockOrdering* ordering,
+                          vector<int>* group_sizes) {
+  CHECK_NOTNULL(group_sizes)->clear();
+  if (ordering == NULL) {
+    return;
+  }
+
+  const map<int, set<double*> >& group_to_elements =
+      ordering->group_to_elements();
+  for (map<int, set<double*> >::const_iterator it = group_to_elements.begin();
+       it != group_to_elements.end();
+       ++it) {
+    group_sizes->push_back(it->second.size());
+  }
+}
+
 }  // namespace internal
 }  // namespace ceres
index 4675cb8dc7c61534ceee1aaf7de416a835e26c60..5de99511138030dc775c88e403f10d64b1d351e6 100644 (file)
@@ -78,6 +78,11 @@ void ComputeRecursiveIndependentSetOrdering(const Program& program,
 // parameter blocks, if they co-occur in a residual block.
 Graph<ParameterBlock*>* CreateHessianGraph(const Program& program);
 
+// Iterate over each of the groups in order of their priority and fill
+// summary with their sizes.
+void OrderingToGroupSizes(const ParameterBlockOrdering* ordering,
+                          vector<int>* group_sizes);
+
 }  // namespace internal
 }  // namespace ceres
 
index 505a47d3d619c46fa027dae05a213b6bcf80f4bb..062347fccc19a5a19488c592a194aba78548908c 100644 (file)
@@ -37,6 +37,16 @@ namespace internal {
 Preconditioner::~Preconditioner() {
 }
 
+PreconditionerType Preconditioner::PreconditionerForZeroEBlocks(
+    PreconditionerType preconditioner_type) {
+  if (preconditioner_type == SCHUR_JACOBI ||
+      preconditioner_type == CLUSTER_JACOBI ||
+      preconditioner_type == CLUSTER_TRIDIAGONAL) {
+    return JACOBI;
+  }
+  return preconditioner_type;
+}
+
 SparseMatrixPreconditionerWrapper::SparseMatrixPreconditionerWrapper(
     const SparseMatrix* matrix)
     : matrix_(CHECK_NOTNULL(matrix)) {
index 21cbc00b54272baaaf2b6868ee30d7c8e480dac5..e8d5994269a72edeacdba1ab8daee6e03da864d1 100644 (file)
@@ -36,6 +36,7 @@
 #include "ceres/compressed_row_sparse_matrix.h"
 #include "ceres/linear_operator.h"
 #include "ceres/sparse_matrix.h"
+#include "ceres/types.h"
 
 namespace ceres {
 namespace internal {
@@ -95,6 +96,14 @@ class Preconditioner : public LinearOperator {
     int f_block_size;
   };
 
+  // If the optimization problem is such that there are no remaining
+  // e-blocks, ITERATIVE_SCHUR with a Schur type preconditioner cannot
+  // be used. This function returns JACOBI if a preconditioner for
+  // ITERATIVE_SCHUR is used. The input preconditioner_type is
+  // returned otherwise.
+  static PreconditionerType PreconditionerForZeroEBlocks(
+      PreconditionerType preconditioner_type);
+
   virtual ~Preconditioner();
 
   // Update the numerical value of the preconditioner for the linear
diff --git a/extern/libmv/third_party/ceres/internal/ceres/preprocessor.cc b/extern/libmv/third_party/ceres/internal/ceres/preprocessor.cc
new file mode 100644 (file)
index 0000000..318c5e2
--- /dev/null
@@ -0,0 +1,113 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2014 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/callbacks.h"
+#include "ceres/gradient_checking_cost_function.h"
+#include "ceres/line_search_preprocessor.h"
+#include "ceres/preprocessor.h"
+#include "ceres/problem_impl.h"
+#include "ceres/solver.h"
+#include "ceres/trust_region_preprocessor.h"
+
+namespace ceres {
+namespace internal {
+
+Preprocessor* Preprocessor::Create(MinimizerType minimizer_type) {
+  if (minimizer_type == TRUST_REGION) {
+    return new TrustRegionPreprocessor;
+  }
+
+  if (minimizer_type == LINE_SEARCH) {
+    return new LineSearchPreprocessor;
+  }
+
+  LOG(FATAL) << "Unknown minimizer_type: " << minimizer_type;
+  return NULL;
+}
+
+Preprocessor::~Preprocessor() {
+}
+
+void ChangeNumThreadsIfNeeded(Solver::Options* options) {
+#ifndef CERES_USE_OPENMP
+  if (options->num_threads > 1) {
+    LOG(WARNING)
+        << "OpenMP support is not compiled into this binary; "
+        << "only options.num_threads = 1 is supported. Switching "
+        << "to single threaded mode.";
+    options->num_threads = 1;
+  }
+
+  // Only the Trust Region solver currently uses a linear solver.
+  if (options->minimizer_type == TRUST_REGION &&
+      options->num_linear_solver_threads > 1) {
+    LOG(WARNING)
+        << "OpenMP support is not compiled into this binary; "
+        << "only options.num_linear_solver_threads=1 is supported. Switching "
+        << "to single threaded mode.";
+    options->num_linear_solver_threads = 1;
+  }
+#endif  // CERES_USE_OPENMP
+}
+
+void SetupCommonMinimizerOptions(PreprocessedProblem* pp) {
+  const Solver::Options& options = pp->options;
+  Program* program = pp->reduced_program.get();
+
+  // Assuming that the parameter blocks in the program have been
+  // reordered as needed, extract them into a contiguous vector.
+  pp->reduced_parameters.resize(program->NumParameters());
+  double* reduced_parameters = pp->reduced_parameters.data();
+  program->ParameterBlocksToStateVector(reduced_parameters);
+
+  Minimizer::Options& minimizer_options = pp->minimizer_options;
+  minimizer_options = Minimizer::Options(options);
+  minimizer_options.evaluator = pp->evaluator;
+
+  if (options.logging_type != SILENT) {
+    pp->logging_callback.reset(
+        new LoggingCallback(options.minimizer_type,
+                            options.minimizer_progress_to_stdout));
+    minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
+                                       pp->logging_callback.get());
+  }
+
+  if (options.update_state_every_iteration) {
+    pp->state_updating_callback.reset(
+      new StateUpdatingCallback(program, reduced_parameters));
+    // This must get pushed to the front of the callbacks so that it
+    // is run before any of the user callbacks.
+    minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
+                                       pp->state_updating_callback.get());
+  }
+}
+
+}  // namespace internal
+}  // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/preprocessor.h b/extern/libmv/third_party/ceres/internal/ceres/preprocessor.h
new file mode 100644 (file)
index 0000000..b4ca5b1
--- /dev/null
@@ -0,0 +1,119 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2014 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_PREPROCESSOR_H_
+#define CERES_INTERNAL_PREPROCESSOR_H_
+
+#include "ceres/coordinate_descent_minimizer.h"
+#include "ceres/evaluator.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/iteration_callback.h"
+#include "ceres/linear_solver.h"
+#include "ceres/minimizer.h"
+#include "ceres/problem_impl.h"
+#include "ceres/program.h"
+#include "ceres/solver.h"
+
+namespace ceres {
+namespace internal {
+
+struct PreprocessedProblem;
+
+// Given a Problem object and a Solver::Options object indicating the
+// configuration of the solver, the job of the Preprocessor is to
+// analyze the Problem and perform the setup needed to solve it using
+// the desired Minimization algorithm. The setup involves removing
+// redundancies in the input problem (inactive parameter and residual
+// blocks), finding fill reducing orderings as needed, configuring and
+// creating various objects needed by the Minimizer to solve the
+// problem such as an evaluator, a linear solver etc.
+//
+// Each Minimizer (LineSearchMinimizer and TrustRegionMinimizer) comes
+// with a corresponding Preprocessor (LineSearchPreprocessor and
+// TrustRegionPreprocessor) that knows about its needs and performs
+// the preprocessing needed.
+//
+// The output of the Preprocessor is stored in a PreprocessedProblem
+// object.
+class Preprocessor {
+public:
+  // Factory.
+  static Preprocessor* Create(MinimizerType minimizer_type);
+  virtual ~Preprocessor();
+  virtual bool Preprocess(const Solver::Options& options,
+                          ProblemImpl* problem,
+                          PreprocessedProblem* pp) = 0;
+};
+
+// A PreprocessedProblem is the result of running the Preprocessor on
+// a Problem and Solver::Options object.
+struct PreprocessedProblem {
+  PreprocessedProblem()
+      : fixed_cost(0.0) {
+  }
+
+  string error;
+  Solver::Options options;
+  LinearSolver::Options linear_solver_options;
+  Evaluator::Options evaluator_options;
+  Minimizer::Options minimizer_options;
+
+  ProblemImpl* problem;
+  scoped_ptr<ProblemImpl> gradient_checking_problem;
+  scoped_ptr<Program> reduced_program;
+  scoped_ptr<LinearSolver> linear_solver;
+  scoped_ptr<IterationCallback> logging_callback;
+  scoped_ptr<IterationCallback> state_updating_callback;
+
+  shared_ptr<Evaluator> evaluator;
+  shared_ptr<CoordinateDescentMinimizer> inner_iteration_minimizer;
+
+  vector<double*> removed_parameter_blocks;
+  Vector reduced_parameters;
+  double fixed_cost;
+};
+
+// Common functions used by various preprocessors.
+
+// If OpenMP support is not available and user has requested more than
+// one thread, then set the *_num_threads options as needed to 1.
+void ChangeNumThreadsIfNeeded(Solver::Options* options);
+
+// Extract the effective parameter vector from the preprocessed
+// problem and setup bits of the Minimizer::Options object that are
+// common to all Preprocessors.
+void SetupCommonMinimizerOptions(PreprocessedProblem* pp);
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_INTERNAL_PREPROCESSOR_H_
index 674694dd506b978373a4d53bebf871485c64816c..bbfaa98769fb1aa0c93c4b0956e6f998c609b7aa 100644 (file)
@@ -251,6 +251,16 @@ void Problem::GetParameterBlocksForResidualBlock(
                                                     parameter_blocks);
 }
 
+const CostFunction* Problem::GetCostFunctionForResidualBlock(
+    const ResidualBlockId residual_block) const {
+  return problem_impl_->GetCostFunctionForResidualBlock(residual_block);
+}
+
+const LossFunction* Problem::GetLossFunctionForResidualBlock(
+    const ResidualBlockId residual_block) const {
+  return problem_impl_->GetLossFunctionForResidualBlock(residual_block);
+}
+
 void Problem::GetResidualBlocksForParameterBlock(
     const double* values,
     vector<ResidualBlockId>* residual_blocks) const {
index 7c86efb49214b369d1bf12a9c2529afd091f001b..67cac94d6acf4efc3d06147d7dcb7be5cf4e2e39 100644 (file)
@@ -823,6 +823,16 @@ void ProblemImpl::GetParameterBlocksForResidualBlock(
   }
 }
 
+const CostFunction* ProblemImpl::GetCostFunctionForResidualBlock(
+    const ResidualBlockId residual_block) const {
+  return residual_block->cost_function();
+}
+
+const LossFunction* ProblemImpl::GetLossFunctionForResidualBlock(
+    const ResidualBlockId residual_block) const {
+  return residual_block->loss_function();
+}
+
 void ProblemImpl::GetResidualBlocksForParameterBlock(
     const double* values,
     vector<ResidualBlockId>* residual_blocks) const {
index 7b5547bd95af88e576322c54c22c0b6db2d4303a..3d84de83c5a6b92f70f8a6800328a4dd69384f3f 100644 (file)
@@ -157,6 +157,11 @@ class ProblemImpl {
       const ResidualBlockId residual_block,
       vector<double*>* parameter_blocks) const;
 
+  const CostFunction* GetCostFunctionForResidualBlock(
+      const ResidualBlockId residual_block) const;
+  const LossFunction* GetLossFunctionForResidualBlock(
+      const ResidualBlockId residual_block) const;
+
   void GetResidualBlocksForParameterBlock(
       const double* values,
       vector<ResidualBlockId>* residual_blocks) const;
index 9e5c51bd696818d98dc2a2a677172c185b403243..1d0a1573e3bc96cbb01dc2db131c0e7af9239336 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <map>
 #include <vector>
+#include "ceres/array_utils.h"
 #include "ceres/casts.h"
 #include "ceres/compressed_row_sparse_matrix.h"
 #include "ceres/cost_function.h"
@@ -44,6 +45,7 @@
 #include "ceres/problem.h"
 #include "ceres/residual_block.h"
 #include "ceres/stl_util.h"
+#include "ceres/triplet_sparse_matrix.h"
 
 namespace ceres {
 namespace internal {
@@ -170,6 +172,259 @@ bool Program::IsValid() const {
   return true;
 }
 
+bool Program::ParameterBlocksAreFinite(string* message) const {
+  CHECK_NOTNULL(message);
+  for (int i = 0; i < parameter_blocks_.size(); ++i) {
+    const ParameterBlock* parameter_block = parameter_blocks_[i];
+    const double* array = parameter_block->user_state();
+    const int size = parameter_block->Size();
+    const int invalid_index = FindInvalidValue(size, array);
+    if (invalid_index != size) {
+      *message = StringPrintf(
+          "ParameterBlock: %p with size %d has at least one invalid value.\n"
+          "First invalid value is at index: %d.\n"
+          "Parameter block values: ",
+          array, size, invalid_index);
+      AppendArrayToString(size, array, message);
+      return false;
+    }
+  }
+  return true;
+}
+
+bool Program::IsBoundsConstrained() const {
+  for (int i = 0; i < parameter_blocks_.size(); ++i) {
+    const ParameterBlock* parameter_block = parameter_blocks_[i];
+    if (parameter_block->IsConstant()) {
+      continue;
+    }
+    const int size = parameter_block->Size();
+    for (int j = 0; j < size; ++j) {
+      const double lower_bound = parameter_block->LowerBoundForParameter(j);
+      const double upper_bound = parameter_block->UpperBoundForParameter(j);
+      if (lower_bound > -std::numeric_limits<double>::max() ||
+          upper_bound < std::numeric_limits<double>::max()) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+bool Program::IsFeasible(string* message) const {
+  CHECK_NOTNULL(message);
+  for (int i = 0; i < parameter_blocks_.size(); ++i) {
+    const ParameterBlock* parameter_block = parameter_blocks_[i];
+    const double* parameters = parameter_block->user_state();
+    const int size = parameter_block->Size();
+    if (parameter_block->IsConstant()) {
+      // Constant parameter blocks must start in the feasible region
+      // to ultimately produce a feasible solution, since Ceres cannot
+      // change them.
+      for (int j = 0; j < size; ++j) {
+        const double lower_bound = parameter_block->LowerBoundForParameter(j);
+        const double upper_bound = parameter_block->UpperBoundForParameter(j);
+        if (parameters[j] < lower_bound || parameters[j] > upper_bound) {
+          *message = StringPrintf(
+              "ParameterBlock: %p with size %d has at least one infeasible "
+              "value."
+              "\nFirst infeasible value is at index: %d."
+              "\nLower bound: %e, value: %e, upper bound: %e"
+              "\nParameter block values: ",
+              parameters, size, j, lower_bound, parameters[j], upper_bound);
+          AppendArrayToString(size, parameters, message);
+          return false;
+        }
+      }
+    } else {
+      // Variable parameter blocks must have non-empty feasible
+      // regions, otherwise there is no way to produce a feasible
+      // solution.
+      for (int j = 0; j < size; ++j) {
+        const double lower_bound = parameter_block->LowerBoundForParameter(j);
+        const double upper_bound = parameter_block->UpperBoundForParameter(j);
+        if (lower_bound >= upper_bound) {
+          *message = StringPrintf(
+              "ParameterBlock: %p with size %d has at least one infeasible "
+              "bound."
+              "\nFirst infeasible bound is at index: %d."
+              "\nLower bound: %e, upper bound: %e"
+              "\nParameter block values: ",
+              parameters, size, j, lower_bound, upper_bound);
+          AppendArrayToString(size, parameters, message);
+          return false;
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
+Program* Program::CreateReducedProgram(vector<double*>* removed_parameter_blocks,
+                                       double* fixed_cost,
+                                       string* error) const {
+  CHECK_NOTNULL(removed_parameter_blocks);
+  CHECK_NOTNULL(fixed_cost);
+  CHECK_NOTNULL(error);
+
+  scoped_ptr<Program> reduced_program(new Program(*this));
+  if (!reduced_program->RemoveFixedBlocks(removed_parameter_blocks,
+                                          fixed_cost,
+                                          error)) {
+    return NULL;
+  }
+
+  reduced_program->SetParameterOffsetsAndIndex();
+  return reduced_program.release();
+}
+
+bool Program::RemoveFixedBlocks(vector<double*>* removed_parameter_blocks,
+                                double* fixed_cost,
+                                string* error) {
+  CHECK_NOTNULL(removed_parameter_blocks);
+  CHECK_NOTNULL(fixed_cost);
+  CHECK_NOTNULL(error);
+
+  scoped_array<double> residual_block_evaluate_scratch;
+  residual_block_evaluate_scratch.reset(
+      new double[MaxScratchDoublesNeededForEvaluate()]);
+  *fixed_cost = 0.0;
+
+  // Mark all the parameters as unused. Abuse the index member of the
+  // parameter blocks for the marking.
+  for (int i = 0; i < parameter_blocks_.size(); ++i) {
+    parameter_blocks_[i]->set_index(-1);
+  }
+
+  // Filter out residual that have all-constant parameters, and mark
+  // all the parameter blocks that appear in residuals.
+  int num_active_residual_blocks = 0;
+  for (int i = 0; i < residual_blocks_.size(); ++i) {
+    ResidualBlock* residual_block = residual_blocks_[i];
+    int num_parameter_blocks = residual_block->NumParameterBlocks();
+
+    // Determine if the residual block is fixed, and also mark varying
+    // parameters that appear in the residual block.
+    bool all_constant = true;
+    for (int k = 0; k < num_parameter_blocks; k++) {
+      ParameterBlock* parameter_block = residual_block->parameter_blocks()[k];
+      if (!parameter_block->IsConstant()) {
+        all_constant = false;
+        parameter_block->set_index(1);
+      }
+    }
+
+    if (!all_constant) {
+      residual_blocks_[num_active_residual_blocks++] = residual_block;
+      continue;
+    }
+
+    // The residual is constant and will be removed, so its cost is
+    // added to the variable fixed_cost.
+    double cost = 0.0;
+    if (!residual_block->Evaluate(true,
+                                  &cost,
+                                  NULL,
+                                  NULL,
+                                  residual_block_evaluate_scratch.get())) {
+      *error = StringPrintf("Evaluation of the residual %d failed during "
+                            "removal of fixed residual blocks.", i);
+      return false;
+    }
+    *fixed_cost += cost;
+  }
+  residual_blocks_.resize(num_active_residual_blocks);
+
+  // Filter out unused or fixed parameter blocks.
+  int num_active_parameter_blocks = 0;
+  removed_parameter_blocks->clear();
+  for (int i = 0; i < parameter_blocks_.size(); ++i) {
+    ParameterBlock* parameter_block = parameter_blocks_[i];
+    if (parameter_block->index() == -1) {
+      removed_parameter_blocks->push_back(parameter_block->mutable_user_state());
+    } else {
+      parameter_blocks_[num_active_parameter_blocks++] = parameter_block;
+    }
+  }
+  parameter_blocks_.resize(num_active_parameter_blocks);
+
+  if (!(((NumResidualBlocks() == 0) &&
+         (NumParameterBlocks() == 0)) ||
+        ((NumResidualBlocks() != 0) &&
+         (NumParameterBlocks() != 0)))) {
+    *error =  "Congratulations, you found a bug in Ceres. Please report it.";
+    return false;
+  }
+
+  return true;
+}
+
+bool Program::IsParameterBlockSetIndependent(const set<double*>& independent_set) const {
+  // Loop over each residual block and ensure that no two parameter
+  // blocks in the same residual block are part of
+  // parameter_block_ptrs as that would violate the assumption that it
+  // is an independent set in the Hessian matrix.
+  for (vector<ResidualBlock*>::const_iterator it = residual_blocks_.begin();
+       it != residual_blocks_.end();
+       ++it) {
+    ParameterBlock* const* parameter_blocks = (*it)->parameter_blocks();
+    const int num_parameter_blocks = (*it)->NumParameterBlocks();
+    int count = 0;
+    for (int i = 0; i < num_parameter_blocks; ++i) {
+      count += independent_set.count(
+          parameter_blocks[i]->mutable_user_state());
+    }
+    if (count > 1) {
+      return false;
+    }
+  }
+  return true;
+}
+
+TripletSparseMatrix* Program::CreateJacobianBlockSparsityTranspose() const {
+  // Matrix to store the block sparsity structure of the Jacobian.
+  TripletSparseMatrix* tsm =
+      new TripletSparseMatrix(NumParameterBlocks(),
+                              NumResidualBlocks(),
+                              10 * NumResidualBlocks());
+  int num_nonzeros = 0;
+  int* rows = tsm->mutable_rows();
+  int* cols = tsm->mutable_cols();
+  double* values = tsm->mutable_values();
+
+  for (int c = 0; c < residual_blocks_.size(); ++c) {
+    const ResidualBlock* residual_block = residual_blocks_[c];
+    const int num_parameter_blocks = residual_block->NumParameterBlocks();
+    ParameterBlock* const* parameter_blocks =
+        residual_block->parameter_blocks();
+
+    for (int j = 0; j < num_parameter_blocks; ++j) {
+      if (parameter_blocks[j]->IsConstant()) {
+        continue;
+      }
+
+      // Re-size the matrix if needed.
+      if (num_nonzeros >= tsm->max_num_nonzeros()) {
+        tsm->set_num_nonzeros(num_nonzeros);
+        tsm->Reserve(2 * num_nonzeros);
+        rows = tsm->mutable_rows();
+        cols = tsm->mutable_cols();
+        values = tsm->mutable_values();
+      }
+
+      const int r = parameter_blocks[j]->index();
+      rows[num_nonzeros] = r;
+      cols[num_nonzeros] = c;
+      values[num_nonzeros] = 1.0;
+      ++num_nonzeros;
+    }
+  }
+
+  tsm->set_num_nonzeros(num_nonzeros);
+  return tsm;
+}
+
 int Program::NumResidualBlocks() const {
   return residual_blocks_.size();
 }
index 4288f609cf8b7a7a230a1572f2b53edf818c5044..c7b22c4d24436574c1c581f7bd60190ab6079e78 100644 (file)
@@ -31,6 +31,7 @@
 #ifndef CERES_INTERNAL_PROGRAM_H_
 #define CERES_INTERNAL_PROGRAM_H_
 
+#include <set>
 #include <string>
 #include <vector>
 #include "ceres/internal/port.h"
@@ -41,6 +42,7 @@ namespace internal {
 class ParameterBlock;
 class ProblemImpl;
 class ResidualBlock;
+class TripletSparseMatrix;
 
 // A nonlinear least squares optimization problem. This is different from the
 // similarly-named "Problem" object, which offers a mutation interface for
@@ -103,6 +105,47 @@ class Program {
   // offsets) are correct.
   bool IsValid() const;
 
+  bool ParameterBlocksAreFinite(string* message) const;
+
+  // Returns true if the program has any non-constant parameter blocks
+  // which have non-trivial bounds constraints.
+  bool IsBoundsConstrained() const;
+
+  // Returns false, if the program has any constant parameter blocks
+  // which are not feasible, or any variable parameter blocks which
+  // have a lower bound greater than or equal to the upper bound.
+  bool IsFeasible(string* message) const;
+
+  // Loop over each residual block and ensure that no two parameter
+  // blocks in the same residual block are part of
+  // parameter_blocks as that would violate the assumption that it
+  // is an independent set in the Hessian matrix.
+  bool IsParameterBlockSetIndependent(const set<double*>& independent_set) const;
+
+  // Create a TripletSparseMatrix which contains the zero-one
+  // structure corresponding to the block sparsity of the transpose of
+  // the Jacobian matrix.
+  //
+  // Caller owns the result.
+  TripletSparseMatrix* CreateJacobianBlockSparsityTranspose() const;
+
+  // Create a copy of this program and removes constant parameter
+  // blocks and residual blocks with no varying parameter blocks while
+  // preserving their relative order.
+  //
+  // removed_parameter_blocks on exit will contain the list of
+  // parameter blocks that were removed.
+  //
+  // fixed_cost will be equal to the sum of the costs of the residual
+  // blocks that were removed.
+  //
+  // If there was a problem, then the function will return a NULL
+  // pointer and error will contain a human readable description of
+  // the problem.
+  Program* CreateReducedProgram(vector<double*>* removed_parameter_blocks,
+                                double* fixed_cost,
+                                string* error) const;
+
   // See problem.h for what these do.
   int NumParameterBlocks() const;
   int NumParameters() const;
@@ -120,6 +163,21 @@ class Program {
   string ToString() const;
 
  private:
+  // Remove constant parameter blocks and residual blocks with no
+  // varying parameter blocks while preserving their relative order.
+  //
+  // removed_parameter_blocks on exit will contain the list of
+  // parameter blocks that were removed.
+  //
+  // fixed_cost will be equal to the sum of the costs of the residual
+  // blocks that were removed.
+  //
+  // If there was a problem, then the function will return false and
+  // error will contain a human readable description of the problem.
+  bool RemoveFixedBlocks(vector<double*>* removed_parameter_blocks,
+                         double* fixed_cost,
+                         string* message);
+
   // The Program does not own the ParameterBlock or ResidualBlock objects.
   vector<ParameterBlock*> parameter_blocks_;
   vector<ResidualBlock*> residual_blocks_;
diff --git a/extern/libmv/third_party/ceres/internal/ceres/reorder_program.cc b/extern/libmv/third_party/ceres/internal/ceres/reorder_program.cc
new file mode 100644 (file)
index 0000000..aa3d4ce
--- /dev/null
@@ -0,0 +1,578 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2014 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/reorder_program.h"
+
+#include <algorithm>
+#include <numeric>
+#include <vector>
+
+#include "ceres/cxsparse.h"
+#include "ceres/internal/port.h"
+#include "ceres/ordered_groups.h"
+#include "ceres/parameter_block.h"
+#include "ceres/parameter_block_ordering.h"
+#include "ceres/problem_impl.h"
+#include "ceres/program.h"
+#include "ceres/residual_block.h"
+#include "ceres/solver.h"
+#include "ceres/suitesparse.h"
+#include "ceres/triplet_sparse_matrix.h"
+#include "ceres/types.h"
+#include "Eigen/SparseCore"
+
+#ifdef CERES_USE_EIGEN_SPARSE
+#include "Eigen/OrderingMethods"
+#endif
+
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+namespace {
+
+// Find the minimum index of any parameter block to the given
+// residual.  Parameter blocks that have indices greater than
+// size_of_first_elimination_group are considered to have an index
+// equal to size_of_first_elimination_group.
+static int MinParameterBlock(const ResidualBlock* residual_block,
+                             int size_of_first_elimination_group) {
+  int min_parameter_block_position = size_of_first_elimination_group;
+  for (int i = 0; i < residual_block->NumParameterBlocks(); ++i) {
+    ParameterBlock* parameter_block = residual_block->parameter_blocks()[i];
+    if (!parameter_block->IsConstant()) {
+      CHECK_NE(parameter_block->index(), -1)
+          << "Did you forget to call Program::SetParameterOffsetsAndIndex()? "
+          << "This is a Ceres bug; please contact the developers!";
+      min_parameter_block_position = std::min(parameter_block->index(),
+                                              min_parameter_block_position);
+    }
+  }
+  return min_parameter_block_position;
+}
+
+#if EIGEN_VERSION_AT_LEAST(3, 2, 2) && defined(CERES_USE_EIGEN_SPARSE)
+Eigen::SparseMatrix<int> CreateBlockJacobian(
+    const TripletSparseMatrix& block_jacobian_transpose) {
+  typedef Eigen::SparseMatrix<int> SparseMatrix;
+  typedef Eigen::Triplet<int> Triplet;
+
+  const int* rows = block_jacobian_transpose.rows();
+  const int* cols = block_jacobian_transpose.cols();
+  int num_nonzeros = block_jacobian_transpose.num_nonzeros();
+  std::vector<Triplet> triplets;
+  triplets.reserve(num_nonzeros);
+  for (int i = 0; i < num_nonzeros; ++i) {
+    triplets.push_back(Triplet(cols[i], rows[i], 1));
+  }
+
+  SparseMatrix block_jacobian(block_jacobian_transpose.num_cols(),
+                              block_jacobian_transpose.num_rows());
+  block_jacobian.setFromTriplets(triplets.begin(), triplets.end());
+  return block_jacobian;
+}
+#endif
+
+void OrderingForSparseNormalCholeskyUsingSuiteSparse(
+    const TripletSparseMatrix& tsm_block_jacobian_transpose,
+    const vector<ParameterBlock*>& parameter_blocks,
+    const ParameterBlockOrdering& parameter_block_ordering,
+    int* ordering) {
+#ifdef CERES_NO_SUITESPARSE
+  LOG(FATAL) << "Congratulations, you found a Ceres bug! "
+             << "Please report this error to the developers.";
+#else
+  SuiteSparse ss;
+  cholmod_sparse* block_jacobian_transpose =
+      ss.CreateSparseMatrix(
+          const_cast<TripletSparseMatrix*>(&tsm_block_jacobian_transpose));
+
+  // No CAMD or the user did not supply a useful ordering, then just
+  // use regular AMD.
+  if (parameter_block_ordering.NumGroups() <= 1 ||
+      !SuiteSparse::IsConstrainedApproximateMinimumDegreeOrderingAvailable()) {
+    ss.ApproximateMinimumDegreeOrdering(block_jacobian_transpose, &ordering[0]);
+  } else {
+    vector<int> constraints;
+    for (int i = 0; i < parameter_blocks.size(); ++i) {
+      constraints.push_back(
+          parameter_block_ordering.GroupId(
+              parameter_blocks[i]->mutable_user_state()));
+    }
+    ss.ConstrainedApproximateMinimumDegreeOrdering(block_jacobian_transpose,
+                                                   &constraints[0],
+                                                   ordering);
+  }
+
+  ss.Free(block_jacobian_transpose);
+#endif  // CERES_NO_SUITESPARSE
+}
+
+void OrderingForSparseNormalCholeskyUsingCXSparse(
+    const TripletSparseMatrix& tsm_block_jacobian_transpose,
+    int* ordering) {
+#ifdef CERES_NO_CXSPARSE
+  LOG(FATAL) << "Congratulations, you found a Ceres bug! "
+             << "Please report this error to the developers.";
+#else  // CERES_NO_CXSPARSE
+  // CXSparse works with J'J instead of J'. So compute the block
+  // sparsity for J'J and compute an approximate minimum degree
+  // ordering.
+  CXSparse cxsparse;
+  cs_di* block_jacobian_transpose;
+  block_jacobian_transpose =
+      cxsparse.CreateSparseMatrix(
+            const_cast<TripletSparseMatrix*>(&tsm_block_jacobian_transpose));
+  cs_di* block_jacobian = cxsparse.TransposeMatrix(block_jacobian_transpose);
+  cs_di* block_hessian =
+      cxsparse.MatrixMatrixMultiply(block_jacobian_transpose, block_jacobian);
+  cxsparse.Free(block_jacobian);
+  cxsparse.Free(block_jacobian_transpose);
+
+  cxsparse.ApproximateMinimumDegreeOrdering(block_hessian, ordering);
+  cxsparse.Free(block_hessian);
+#endif  // CERES_NO_CXSPARSE
+}
+
+
+#if EIGEN_VERSION_AT_LEAST(3, 2, 2)
+void OrderingForSparseNormalCholeskyUsingEigenSparse(
+    const TripletSparseMatrix& tsm_block_jacobian_transpose,
+    int* ordering) {
+#ifndef CERES_USE_EIGEN_SPARSE
+  LOG(FATAL) <<
+      "SPARSE_NORMAL_CHOLESKY cannot be used with EIGEN_SPARSE "
+      "because Ceres was not built with support for "
+      "Eigen's SimplicialLDLT decomposition. "
+      "This requires enabling building with -DEIGENSPARSE=ON.";
+#else
+
+  // This conversion from a TripletSparseMatrix to a Eigen::Triplet
+  // matrix is unfortunate, but unavoidable for now. It is not a
+  // significant performance penalty in the grand scheme of
+  // things. The right thing to do here would be to get a compressed
+  // row sparse matrix representation of the jacobian and go from
+  // there. But that is a project for another day.
+  typedef Eigen::SparseMatrix<int> SparseMatrix;
+
+  const SparseMatrix block_jacobian =
+      CreateBlockJacobian(tsm_block_jacobian_transpose);
+  const SparseMatrix block_hessian =
+      block_jacobian.transpose() * block_jacobian;
+
+  Eigen::AMDOrdering<int> amd_ordering;
+  Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic, int> perm;
+  amd_ordering(block_hessian, perm);
+  for (int i = 0; i < block_hessian.rows(); ++i) {
+    ordering[i] = perm.indices()[i];
+  }
+#endif  // CERES_USE_EIGEN_SPARSE
+}
+#endif
+
+}  // namespace
+
+bool ApplyOrdering(const ProblemImpl::ParameterMap& parameter_map,
+                   const ParameterBlockOrdering& ordering,
+                   Program* program,
+                   string* error) {
+  const int num_parameter_blocks =  program->NumParameterBlocks();
+  if (ordering.NumElements() != num_parameter_blocks) {
+    *error = StringPrintf("User specified ordering does not have the same "
+                          "number of parameters as the problem. The problem"
+                          "has %d blocks while the ordering has %d blocks.",
+                          num_parameter_blocks,
+                          ordering.NumElements());
+    return false;
+  }
+
+  vector<ParameterBlock*>* parameter_blocks =
+      program->mutable_parameter_blocks();
+  parameter_blocks->clear();
+
+  const map<int, set<double*> >& groups =
+      ordering.group_to_elements();
+
+  for (map<int, set<double*> >::const_iterator group_it = groups.begin();
+       group_it != groups.end();
+       ++group_it) {
+    const set<double*>& group = group_it->second;
+    for (set<double*>::const_iterator parameter_block_ptr_it = group.begin();
+         parameter_block_ptr_it != group.end();
+         ++parameter_block_ptr_it) {
+      ProblemImpl::ParameterMap::const_iterator parameter_block_it =
+          parameter_map.find(*parameter_block_ptr_it);
+      if (parameter_block_it == parameter_map.end()) {
+        *error = StringPrintf("User specified ordering contains a pointer "
+                              "to a double that is not a parameter block in "
+                              "the problem. The invalid double is in group: %d",
+                              group_it->first);
+        return false;
+      }
+      parameter_blocks->push_back(parameter_block_it->second);
+    }
+  }
+  return true;
+}
+
+bool LexicographicallyOrderResidualBlocks(
+    const int size_of_first_elimination_group,
+    Program* program,
+    string* error) {
+  CHECK_GE(size_of_first_elimination_group, 1)
+      << "Congratulations, you found a Ceres bug! Please report this error "
+      << "to the developers.";
+
+  // Create a histogram of the number of residuals for each E block. There is an
+  // extra bucket at the end to catch all non-eliminated F blocks.
+  vector<int> residual_blocks_per_e_block(size_of_first_elimination_group + 1);
+  vector<ResidualBlock*>* residual_blocks = program->mutable_residual_blocks();
+  vector<int> min_position_per_residual(residual_blocks->size());
+  for (int i = 0; i < residual_blocks->size(); ++i) {
+    ResidualBlock* residual_block = (*residual_blocks)[i];
+    int position = MinParameterBlock(residual_block,
+                                     size_of_first_elimination_group);
+    min_position_per_residual[i] = position;
+    DCHECK_LE(position, size_of_first_elimination_group);
+    residual_blocks_per_e_block[position]++;
+  }
+
+  // Run a cumulative sum on the histogram, to obtain offsets to the start of
+  // each histogram bucket (where each bucket is for the residuals for that
+  // E-block).
+  vector<int> offsets(size_of_first_elimination_group + 1);
+  std::partial_sum(residual_blocks_per_e_block.begin(),
+                   residual_blocks_per_e_block.end(),
+                   offsets.begin());
+  CHECK_EQ(offsets.back(), residual_blocks->size())
+      << "Congratulations, you found a Ceres bug! Please report this error "
+      << "to the developers.";
+
+  CHECK(find(residual_blocks_per_e_block.begin(),
+             residual_blocks_per_e_block.end() - 1, 0) !=
+        residual_blocks_per_e_block.end())
+      << "Congratulations, you found a Ceres bug! Please report this error "
+      << "to the developers.";
+
+  // Fill in each bucket with the residual blocks for its corresponding E block.
+  // Each bucket is individually filled from the back of the bucket to the front
+  // of the bucket. The filling order among the buckets is dictated by the
+  // residual blocks. This loop uses the offsets as counters; subtracting one
+  // from each offset as a residual block is placed in the bucket. When the
+  // filling is finished, the offset pointerts should have shifted down one
+  // entry (this is verified below).
+  vector<ResidualBlock*> reordered_residual_blocks(
+      (*residual_blocks).size(), static_cast<ResidualBlock*>(NULL));
+  for (int i = 0; i < residual_blocks->size(); ++i) {
+    int bucket = min_position_per_residual[i];
+
+    // Decrement the cursor, which should now point at the next empty position.
+    offsets[bucket]--;
+
+    // Sanity.
+    CHECK(reordered_residual_blocks[offsets[bucket]] == NULL)
+        << "Congratulations, you found a Ceres bug! Please report this error "
+        << "to the developers.";
+
+    reordered_residual_blocks[offsets[bucket]] = (*residual_blocks)[i];
+  }
+
+  // Sanity check #1: The difference in bucket offsets should match the
+  // histogram sizes.
+  for (int i = 0; i < size_of_first_elimination_group; ++i) {
+    CHECK_EQ(residual_blocks_per_e_block[i], offsets[i + 1] - offsets[i])
+        << "Congratulations, you found a Ceres bug! Please report this error "
+        << "to the developers.";
+  }
+  // Sanity check #2: No NULL's left behind.
+  for (int i = 0; i < reordered_residual_blocks.size(); ++i) {
+    CHECK(reordered_residual_blocks[i] != NULL)
+        << "Congratulations, you found a Ceres bug! Please report this error "
+        << "to the developers.";
+  }
+
+  // Now that the residuals are collected by E block, swap them in place.
+  swap(*program->mutable_residual_blocks(), reordered_residual_blocks);
+  return true;
+}
+
+// Pre-order the columns corresponding to the schur complement if
+// possible.
+void MaybeReorderSchurComplementColumnsUsingSuiteSparse(
+    const ParameterBlockOrdering& parameter_block_ordering,
+    Program* program) {
+#ifndef CERES_NO_SUITESPARSE
+  SuiteSparse ss;
+  if (!SuiteSparse::IsConstrainedApproximateMinimumDegreeOrderingAvailable()) {
+    return;
+  }
+
+  vector<int> constraints;
+  vector<ParameterBlock*>& parameter_blocks =
+      *(program->mutable_parameter_blocks());
+
+  for (int i = 0; i < parameter_blocks.size(); ++i) {
+    constraints.push_back(
+        parameter_block_ordering.GroupId(
+            parameter_blocks[i]->mutable_user_state()));
+  }
+
+  // Renumber the entries of constraints to be contiguous integers
+  // as camd requires that the group ids be in the range [0,
+  // parameter_blocks.size() - 1].
+  MapValuesToContiguousRange(constraints.size(), &constraints[0]);
+
+  // Compute a block sparse presentation of J'.
+  scoped_ptr<TripletSparseMatrix> tsm_block_jacobian_transpose(
+      program->CreateJacobianBlockSparsityTranspose());
+
+  cholmod_sparse* block_jacobian_transpose =
+      ss.CreateSparseMatrix(tsm_block_jacobian_transpose.get());
+
+  vector<int> ordering(parameter_blocks.size(), 0);
+  ss.ConstrainedApproximateMinimumDegreeOrdering(block_jacobian_transpose,
+                                                 &constraints[0],
+                                                 &ordering[0]);
+  ss.Free(block_jacobian_transpose);
+
+  const vector<ParameterBlock*> parameter_blocks_copy(parameter_blocks);
+  for (int i = 0; i < program->NumParameterBlocks(); ++i) {
+    parameter_blocks[i] = parameter_blocks_copy[ordering[i]];
+  }
+
+  program->SetParameterOffsetsAndIndex();
+#endif
+}
+
+void MaybeReorderSchurComplementColumnsUsingEigen(
+    const int size_of_first_elimination_group,
+    const ProblemImpl::ParameterMap& parameter_map,
+    Program* program) {
+#if !EIGEN_VERSION_AT_LEAST(3, 2, 2) || !defined(CERES_USE_EIGEN_SPARSE)
+  return;
+#else
+
+  scoped_ptr<TripletSparseMatrix> tsm_block_jacobian_transpose(
+      program->CreateJacobianBlockSparsityTranspose());
+
+  typedef Eigen::SparseMatrix<int> SparseMatrix;
+  const SparseMatrix block_jacobian =
+      CreateBlockJacobian(*tsm_block_jacobian_transpose);
+  const int num_rows = block_jacobian.rows();
+  const int num_cols = block_jacobian.cols();
+
+  // Vertically partition the jacobian in parameter blocks of type E
+  // and F.
+  const SparseMatrix E =
+      block_jacobian.block(0,
+                           0,
+                           num_rows,
+                           size_of_first_elimination_group);
+  const SparseMatrix F =
+      block_jacobian.block(0,
+                           size_of_first_elimination_group,
+                           num_rows,
+                           num_cols - size_of_first_elimination_group);
+
+  // Block sparsity pattern of the schur complement.
+  const SparseMatrix block_schur_complement =
+      F.transpose() * F - F.transpose() * E * E.transpose() * F;
+
+  Eigen::AMDOrdering<int> amd_ordering;
+  Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic, int> perm;
+  amd_ordering(block_schur_complement, perm);
+
+  const vector<ParameterBlock*>& parameter_blocks = program->parameter_blocks();
+  vector<ParameterBlock*> ordering(num_cols);
+
+  // The ordering of the first size_of_first_elimination_group does
+  // not matter, so we preserve the existing ordering.
+  for (int i = 0; i < size_of_first_elimination_group; ++i) {
+    ordering[i] = parameter_blocks[i];
+  }
+
+  // For the rest of the blocks, use the ordering computed using AMD.
+  for (int i = 0; i < block_schur_complement.cols(); ++i) {
+    ordering[size_of_first_elimination_group + i] =
+        parameter_blocks[size_of_first_elimination_group + perm.indices()[i]];
+  }
+
+  swap(*program->mutable_parameter_blocks(), ordering);
+  program->SetParameterOffsetsAndIndex();
+#endif
+}
+
+bool ReorderProgramForSchurTypeLinearSolver(
+    const LinearSolverType linear_solver_type,
+    const SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
+    const ProblemImpl::ParameterMap& parameter_map,
+    ParameterBlockOrdering* parameter_block_ordering,
+    Program* program,
+    string* error) {
+  if (parameter_block_ordering->NumElements() !=
+      program->NumParameterBlocks()) {
+    *error = StringPrintf(
+        "The program has %d parameter blocks, but the parameter block "
+        "ordering has %d parameter blocks.",
+        program->NumParameterBlocks(),
+        parameter_block_ordering->NumElements());
+    return false;
+  }
+
+  if (parameter_block_ordering->NumGroups() == 1) {
+    // If the user supplied an parameter_block_ordering with just one
+    // group, it is equivalent to the user supplying NULL as an
+    // parameter_block_ordering. Ceres is completely free to choose the
+    // parameter block ordering as it sees fit. For Schur type solvers,
+    // this means that the user wishes for Ceres to identify the
+    // e_blocks, which we do by computing a maximal independent set.
+    vector<ParameterBlock*> schur_ordering;
+    const int size_of_first_elimination_group =
+        ComputeStableSchurOrdering(*program, &schur_ordering);
+
+    CHECK_EQ(schur_ordering.size(), program->NumParameterBlocks())
+        << "Congratulations, you found a Ceres bug! Please report this error "
+        << "to the developers.";
+
+    // Update the parameter_block_ordering object.
+    for (int i = 0; i < schur_ordering.size(); ++i) {
+      double* parameter_block = schur_ordering[i]->mutable_user_state();
+      const int group_id = (i < size_of_first_elimination_group) ? 0 : 1;
+      parameter_block_ordering->AddElementToGroup(parameter_block, group_id);
+    }
+
+    // We could call ApplyOrdering but this is cheaper and
+    // simpler.
+    swap(*program->mutable_parameter_blocks(), schur_ordering);
+  } else {
+    // The user provided an ordering with more than one elimination
+    // group.
+
+    // Verify that the first elimination group is an independent set.
+    const set<double*>& first_elimination_group =
+        parameter_block_ordering
+        ->group_to_elements()
+        .begin()
+        ->second;
+    if (!program->IsParameterBlockSetIndependent(first_elimination_group)) {
+      *error =
+          StringPrintf("The first elimination group in the parameter block "
+                       "ordering of size %zd is not an independent set",
+                       first_elimination_group.size());
+      return false;
+    }
+
+    if (!ApplyOrdering(parameter_map,
+                       *parameter_block_ordering,
+                       program,
+                       error)) {
+      return false;
+    }
+  }
+
+  program->SetParameterOffsetsAndIndex();
+
+  const int size_of_first_elimination_group =
+      parameter_block_ordering->group_to_elements().begin()->second.size();
+
+  if (linear_solver_type == SPARSE_SCHUR) {
+    if (sparse_linear_algebra_library_type == SUITE_SPARSE) {
+      MaybeReorderSchurComplementColumnsUsingSuiteSparse(
+          *parameter_block_ordering,
+          program);
+    } else if (sparse_linear_algebra_library_type == EIGEN_SPARSE) {
+      MaybeReorderSchurComplementColumnsUsingEigen(
+          size_of_first_elimination_group,
+          parameter_map,
+          program);
+    }
+  }
+
+  // Schur type solvers also require that their residual blocks be
+  // lexicographically ordered.
+  if (!LexicographicallyOrderResidualBlocks(size_of_first_elimination_group,
+                                            program,
+                                            error)) {
+    return false;
+  }
+
+  return true;
+}
+
+bool ReorderProgramForSparseNormalCholesky(
+    const SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
+    const ParameterBlockOrdering& parameter_block_ordering,
+    Program* program,
+    string* error) {
+  // Compute a block sparse presentation of J'.
+  scoped_ptr<TripletSparseMatrix> tsm_block_jacobian_transpose(
+      program->CreateJacobianBlockSparsityTranspose());
+
+  vector<int> ordering(program->NumParameterBlocks(), 0);
+  vector<ParameterBlock*>& parameter_blocks =
+      *(program->mutable_parameter_blocks());
+
+  if (sparse_linear_algebra_library_type == SUITE_SPARSE) {
+    OrderingForSparseNormalCholeskyUsingSuiteSparse(
+        *tsm_block_jacobian_transpose,
+        parameter_blocks,
+        parameter_block_ordering,
+        &ordering[0]);
+  } else if (sparse_linear_algebra_library_type == CX_SPARSE) {
+    OrderingForSparseNormalCholeskyUsingCXSparse(
+        *tsm_block_jacobian_transpose,
+        &ordering[0]);
+  } else if (sparse_linear_algebra_library_type == EIGEN_SPARSE) {
+#if EIGEN_VERSION_AT_LEAST(3, 2, 2)
+       OrderingForSparseNormalCholeskyUsingEigenSparse(
+        *tsm_block_jacobian_transpose,
+        &ordering[0]);
+#else
+    // For Eigen versions less than 3.2.2, there is nothing to do as
+    // older versions of Eigen do not expose a method for doing
+    // symbolic analysis on pre-ordered matrices, so a block
+    // pre-ordering is a bit pointless.
+
+    return true;
+#endif
+  }
+
+  // Apply ordering.
+  const vector<ParameterBlock*> parameter_blocks_copy(parameter_blocks);
+  for (int i = 0; i < program->NumParameterBlocks(); ++i) {
+    parameter_blocks[i] = parameter_blocks_copy[ordering[i]];
+  }
+
+  program->SetParameterOffsetsAndIndex();
+  return true;
+}
+
+}  // namespace internal
+}  // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/reorder_program.h b/extern/libmv/third_party/ceres/internal/ceres/reorder_program.h
new file mode 100644 (file)
index 0000000..0474c1f
--- /dev/null
@@ -0,0 +1,101 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2014 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_REORDER_PROGRAM_H_
+#define CERES_INTERNAL_REORDER_PROGRAM_H_
+
+#include <string>
+#include "ceres/internal/port.h"
+#include "ceres/parameter_block_ordering.h"
+#include "ceres/problem_impl.h"
+#include "ceres/types.h"
+
+namespace ceres {
+namespace internal {
+
+class Program;
+
+// Reorder the parameter blocks in program using the ordering
+bool ApplyOrdering(const ProblemImpl::ParameterMap& parameter_map,
+                   const ParameterBlockOrdering& ordering,
+                   Program* program,
+                   string* error);
+
+// Reorder the residuals for program, if necessary, so that the residuals
+// involving each E block occur together. This is a necessary condition for the
+// Schur eliminator, which works on these "row blocks" in the jacobian.
+bool LexicographicallyOrderResidualBlocks(int size_of_first_elimination_group,
+                                          Program* program,
+                                          string* error);
+
+// Schur type solvers require that all parameter blocks eliminated
+// by the Schur eliminator occur before others and the residuals be
+// sorted in lexicographic order of their parameter blocks.
+//
+// If the parameter_block_ordering only contains one elimination
+// group then a maximal independent set is computed and used as the
+// first elimination group, otherwise the user's ordering is used.
+//
+// If the linear solver type is SPARSE_SCHUR and support for
+// constrained fill-reducing ordering is available in the sparse
+// linear algebra library (SuiteSparse version >= 4.2.0) then
+// columns of the schur complement matrix are ordered to reduce the
+// fill-in the Cholesky factorization.
+//
+// Upon return, ordering contains the parameter block ordering that
+// was used to order the program.
+bool ReorderProgramForSchurTypeLinearSolver(
+    LinearSolverType linear_solver_type,
+    SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
+    const ProblemImpl::ParameterMap& parameter_map,
+    ParameterBlockOrdering* parameter_block_ordering,
+    Program* program,
+    string* error);
+
+// Sparse cholesky factorization routines when doing the sparse
+// cholesky factorization of the Jacobian matrix, reorders its
+// columns to reduce the fill-in. Compute this permutation and
+// re-order the parameter blocks.
+//
+// When using SuiteSparse, if the parameter_block_ordering contains
+// more than one elimination group and support for constrained
+// fill-reducing ordering is available in the sparse linear algebra
+// library (SuiteSparse version >= 4.2.0) then the fill reducing
+// ordering will take it into account, otherwise it will be ignored.
+bool ReorderProgramForSparseNormalCholesky(
+    SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
+    const ParameterBlockOrdering& parameter_block_ordering,
+    Program* program,
+    string* error);
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_INTERNAL_REORDER_PROGRAM_
index d3eef5d43286039a338a2d05acd07252b3ebecb0..d2aa168c807063ffe684122a72f84d63b8c4cf47 100644 (file)
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
+// Copyright 2014 Google Inc. All rights reserved.
 // http://code.google.com/p/ceres-solver/
 //
 // Redistribution and use in source and binary forms, with or without
 //
 // Author: sameeragarwal@google.com (Sameer Agarwal)
 
+#include "ceres/internal/port.h"
+
 #include <algorithm>
 #include <ctime>
 #include <set>
 #include <vector>
 
-#include "Eigen/Dense"
 #include "ceres/block_random_access_dense_matrix.h"
 #include "ceres/block_random_access_matrix.h"
 #include "ceres/block_random_access_sparse_matrix.h"
@@ -42,7 +43,6 @@
 #include "ceres/cxsparse.h"
 #include "ceres/detect_structure.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
 #include "ceres/internal/scoped_ptr.h"
 #include "ceres/lapack.h"
 #include "ceres/linear_solver.h"
@@ -51,6 +51,8 @@
 #include "ceres/triplet_sparse_matrix.h"
 #include "ceres/types.h"
 #include "ceres/wall_time.h"
+#include "Eigen/Dense"
+#include "Eigen/SparseCore"
 
 namespace ceres {
 namespace internal {
@@ -138,7 +140,8 @@ DenseSchurComplementSolver::SolveReducedLinearSystem(double* solution) {
         .llt();
     if (llt.info() != Eigen::Success) {
       summary.termination_type = LINEAR_SOLVER_FAILURE;
-      summary.message = "Eigen LLT decomposition failed.";
+      summary.message =
+          "Eigen failure. Unable to perform dense Cholesky factorization.";
       return summary;
     }
 
@@ -155,8 +158,6 @@ DenseSchurComplementSolver::SolveReducedLinearSystem(double* solution) {
   return summary;
 }
 
-#if !defined(CERES_NO_SUITESPARSE) || !defined(CERES_NO_CXSPARE)
-
 SparseSchurComplementSolver::SparseSchurComplementSolver(
     const LinearSolver::Options& options)
     : SchurComplementSolver(options),
@@ -165,19 +166,15 @@ SparseSchurComplementSolver::SparseSchurComplementSolver(
 }
 
 SparseSchurComplementSolver::~SparseSchurComplementSolver() {
-#ifndef CERES_NO_SUITESPARSE
   if (factor_ != NULL) {
     ss_.Free(factor_);
     factor_ = NULL;
   }
-#endif  // CERES_NO_SUITESPARSE
 
-#ifndef CERES_NO_CXSPARSE
   if (cxsparse_factor_ != NULL) {
     cxsparse_.Free(cxsparse_factor_);
     cxsparse_factor_ = NULL;
   }
-#endif  // CERES_NO_CXSPARSE
 }
 
 // Determine the non-zero blocks in the Schur Complement matrix, and
@@ -258,6 +255,8 @@ SparseSchurComplementSolver::SolveReducedLinearSystem(double* solution) {
       return SolveReducedLinearSystemUsingSuiteSparse(solution);
     case CX_SPARSE:
       return SolveReducedLinearSystemUsingCXSparse(solution);
+    case EIGEN_SPARSE:
+      return SolveReducedLinearSystemUsingEigen(solution);
     default:
       LOG(FATAL) << "Unknown sparse linear algebra library : "
                  << options().sparse_linear_algebra_library_type;
@@ -266,13 +265,23 @@ SparseSchurComplementSolver::SolveReducedLinearSystem(double* solution) {
   return LinearSolver::Summary();
 }
 
-#ifndef CERES_NO_SUITESPARSE
 // Solve the system Sx = r, assuming that the matrix S is stored in a
 // BlockRandomAccessSparseMatrix.  The linear system is solved using
 // CHOLMOD's sparse cholesky factorization routines.
 LinearSolver::Summary
 SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse(
     double* solution) {
+#ifdef CERES_NO_SUITESPARSE
+
+  LinearSolver::Summary summary;
+  summary.num_iterations = 0;
+  summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+  summary.message = "Ceres was not built with SuiteSparse support. "
+      "Therefore, SPARSE_SCHUR cannot be used with SUITE_SPARSE";
+  return summary;
+
+#else
+
   LinearSolver::Summary summary;
   summary.num_iterations = 0;
   summary.termination_type = LINEAR_SOLVER_SUCCESS;
@@ -326,6 +335,8 @@ SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse(
   if (factor_ == NULL) {
     ss_.Free(cholmod_lhs);
     summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+    // No need to set message as it has already been set by the
+    // symbolic analysis routines above.
     return summary;
   }
 
@@ -335,6 +346,8 @@ SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse(
   ss_.Free(cholmod_lhs);
 
   if (summary.termination_type != LINEAR_SOLVER_SUCCESS) {
+    // No need to set message as it has already been set by the
+    // numeric factorization routine above.
     return summary;
   }
 
@@ -346,6 +359,8 @@ SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse(
   ss_.Free(cholmod_rhs);
 
   if (cholmod_solution == NULL) {
+    summary.message =
+        "SuiteSparse failure. Unable to perform triangular solve.";
     summary.termination_type = LINEAR_SOLVER_FAILURE;
     return summary;
   }
@@ -354,23 +369,26 @@ SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse(
       = VectorRef(static_cast<double*>(cholmod_solution->x), num_rows);
   ss_.Free(cholmod_solution);
   return summary;
-}
-#else
-LinearSolver::Summary
-SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse(
-    double* solution) {
-  LOG(FATAL) << "No SuiteSparse support in Ceres.";
-  return LinearSolver::Summary();
-}
 #endif  // CERES_NO_SUITESPARSE
+}
 
-#ifndef CERES_NO_CXSPARSE
 // Solve the system Sx = r, assuming that the matrix S is stored in a
 // BlockRandomAccessSparseMatrix.  The linear system is solved using
 // CXSparse's sparse cholesky factorization routines.
 LinearSolver::Summary
 SparseSchurComplementSolver::SolveReducedLinearSystemUsingCXSparse(
     double* solution) {
+#ifdef CERES_NO_CXSPARSE
+
+  LinearSolver::Summary summary;
+  summary.num_iterations = 0;
+  summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+  summary.message = "Ceres was not built with CXSparse support. "
+      "Therefore, SPARSE_SCHUR cannot be used with CX_SPARSE";
+  return summary;
+
+#else
+
   LinearSolver::Summary summary;
   summary.num_iterations = 0;
   summary.termination_type = LINEAR_SOLVER_SUCCESS;
@@ -407,16 +425,94 @@ SparseSchurComplementSolver::SolveReducedLinearSystemUsingCXSparse(
 
   cxsparse_.Free(lhs);
   return summary;
+#endif  // CERES_NO_CXPARSE
 }
-#else
+
+// Solve the system Sx = r, assuming that the matrix S is stored in a
+// BlockRandomAccessSparseMatrix.  The linear system is solved using
+// Eigen's sparse cholesky factorization routines.
 LinearSolver::Summary
-SparseSchurComplementSolver::SolveReducedLinearSystemUsingCXSparse(
+SparseSchurComplementSolver::SolveReducedLinearSystemUsingEigen(
     double* solution) {
-  LOG(FATAL) << "No CXSparse support in Ceres.";
-  return LinearSolver::Summary();
+#ifndef CERES_USE_EIGEN_SPARSE
+
+  LinearSolver::Summary summary;
+  summary.num_iterations = 0;
+  summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+  summary.message =
+      "SPARSE_SCHUR cannot be used with EIGEN_SPARSE. "
+      "Ceres was not built with support for "
+      "Eigen's SimplicialLDLT decomposition. "
+      "This requires enabling building with -DEIGENSPARSE=ON.";
+  return summary;
+
+#else
+  EventLogger event_logger("SchurComplementSolver::EigenSolve");
+  LinearSolver::Summary summary;
+  summary.num_iterations = 0;
+  summary.termination_type = LINEAR_SOLVER_SUCCESS;
+  summary.message = "Success.";
+
+  // Extract the TripletSparseMatrix that is used for actually storing S.
+  TripletSparseMatrix* tsm =
+      const_cast<TripletSparseMatrix*>(
+          down_cast<const BlockRandomAccessSparseMatrix*>(lhs())->matrix());
+  const int num_rows = tsm->num_rows();
+
+  // The case where there are no f blocks, and the system is block
+  // diagonal.
+  if (num_rows == 0) {
+    return summary;
+  }
+
+  // This is an upper triangular matrix.
+  CompressedRowSparseMatrix crsm(*tsm);
+  // Map this to a column major, lower triangular matrix.
+  Eigen::MappedSparseMatrix<double, Eigen::ColMajor> eigen_lhs(
+      crsm.num_rows(),
+      crsm.num_rows(),
+      crsm.num_nonzeros(),
+      crsm.mutable_rows(),
+      crsm.mutable_cols(),
+      crsm.mutable_values());
+  event_logger.AddEvent("ToCompressedRowSparseMatrix");
+
+  // Compute symbolic factorization if one does not exist.
+  if (simplicial_ldlt_.get() == NULL) {
+    simplicial_ldlt_.reset(new SimplicialLDLT);
+    // This ordering is quite bad. The scalar ordering produced by the
+    // AMD algorithm is quite bad and can be an order of magnitude
+    // worse than the one computed using the block version of the
+    // algorithm.
+    simplicial_ldlt_->analyzePattern(eigen_lhs);
+    event_logger.AddEvent("Analysis");
+    if (simplicial_ldlt_->info() != Eigen::Success) {
+      summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+      summary.message =
+          "Eigen failure. Unable to find symbolic factorization.";
+      return summary;
+    }
+  }
+
+  simplicial_ldlt_->factorize(eigen_lhs);
+  event_logger.AddEvent("Factorize");
+  if (simplicial_ldlt_->info() != Eigen::Success) {
+    summary.termination_type = LINEAR_SOLVER_FAILURE;
+    summary.message = "Eigen failure. Unable to find numeric factoriztion.";
+    return summary;
+  }
+
+  VectorRef(solution, num_rows) =
+      simplicial_ldlt_->solve(ConstVectorRef(rhs(), num_rows));
+  event_logger.AddEvent("Solve");
+  if (simplicial_ldlt_->info() != Eigen::Success) {
+    summary.termination_type = LINEAR_SOLVER_FAILURE;
+    summary.message = "Eigen failure. Unable to do triangular solve.";
+  }
+
+  return summary;
+#endif  // CERES_USE_EIGEN_SPARSE
 }
-#endif  // CERES_NO_CXPARSE
 
-#endif  // !defined(CERES_NO_SUITESPARSE) || !defined(CERES_NO_CXSPARE)
 }  // namespace internal
 }  // namespace ceres
index a9978518b17b73e1e502d741091e738879fa04d3..1b431dc534036fdfa6343822208d09d78a1b75f0 100644 (file)
@@ -35,6 +35,8 @@
 #include <utility>
 #include <vector>
 
+#include "ceres/internal/port.h"
+
 #include "ceres/block_random_access_matrix.h"
 #include "ceres/block_sparse_matrix.h"
 #include "ceres/block_structure.h"
 #include "ceres/internal/scoped_ptr.h"
 #include "ceres/types.h"
 
+#ifdef CERES_USE_EIGEN_SPARSE
+#include "Eigen/SparseCholesky"
+#include "Eigen/OrderingMethods"
+#endif
+
 namespace ceres {
 namespace internal {
 
@@ -153,7 +160,6 @@ class DenseSchurComplementSolver : public SchurComplementSolver {
   CERES_DISALLOW_COPY_AND_ASSIGN(DenseSchurComplementSolver);
 };
 
-#if !defined(CERES_NO_SUITESPARSE) || !defined(CERES_NO_CXSPARE)
 // Sparse Cholesky factorization based solver.
 class SparseSchurComplementSolver : public SchurComplementSolver {
  public:
@@ -168,6 +174,8 @@ class SparseSchurComplementSolver : public SchurComplementSolver {
       double* solution);
   LinearSolver::Summary SolveReducedLinearSystemUsingCXSparse(
       double* solution);
+  LinearSolver::Summary SolveReducedLinearSystemUsingEigen(
+      double* solution);
 
   // Size of the blocks in the Schur complement.
   vector<int> blocks_;
@@ -180,10 +188,27 @@ class SparseSchurComplementSolver : public SchurComplementSolver {
   CXSparse cxsparse_;
   // Cached factorization
   cs_dis* cxsparse_factor_;
+
+#ifdef CERES_USE_EIGEN_SPARSE
+
+  // The preprocessor gymnastics here are dealing with the fact that
+  // before version 3.2.2, Eigen did not support a third template
+  // parameter to specify the ordering.
+#if EIGEN_VERSION_AT_LEAST(3,2,2)
+  typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>, Eigen::Lower,
+                                Eigen::NaturalOrdering<int> >
+  SimplicialLDLT;
+#else
+  typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>, Eigen::Lower>
+  SimplicialLDLT;
+#endif
+
+  scoped_ptr<SimplicialLDLT> simplicial_ldlt_;
+#endif
+
   CERES_DISALLOW_COPY_AND_ASSIGN(SparseSchurComplementSolver);
 };
 
-#endif  // !defined(CERES_NO_SUITESPARSE) || !defined(CERES_NO_CXSPARE)
 }  // namespace internal
 }  // namespace ceres
 
index 0a8b20cfe299971694a440cffd1d39cf48731889..f0f7e0e1e06a1c07bf82322185cbf94077f7886d 100644 (file)
@@ -44,7 +44,7 @@ namespace internal {
 
 int ComputeSingleLinkageClustering(
     const SingleLinkageClusteringOptions& options,
-    const Graph<int>& graph,
+    const WeightedGraph<int>& graph,
     HashMap<int, int>* membership) {
   CHECK_NOTNULL(membership)->clear();
 
index e6fdeabea6129ef5894ede6755e25ffbeccd63eb..79c4da114c230af2ade26f8c963604efffa67451 100644 (file)
@@ -64,7 +64,7 @@ struct SingleLinkageClusteringOptions {
 // identified by the algorithm.
 int ComputeSingleLinkageClustering(
     const SingleLinkageClusteringOptions& options,
-    const Graph<int>& graph,
+    const WeightedGraph<int>& graph,
     HashMap<int, int>* membership);
 
 }  // namespace internal
index 26228e49306a12e25dbf1b907b4f3fff91e7e250..5639664b9251f689554bebc9faa55566b44b921b 100644 (file)
 namespace ceres {
 namespace internal {
 
-// Remove the ".noalias()" annotation from the matrix matrix
-// mutliplies to produce a correct build with the Android NDK,
-// including versions 6, 7, 8, and 8b, when built with STLPort and the
-// non-standalone toolchain (i.e. ndk-build). This appears to be a
-// compiler bug; if the workaround is not in place, the line
-//
-//   block.noalias() -= A * B;
-//
-// gets compiled to
-//
-//   block.noalias() += A * B;
-//
-// which breaks schur elimination. Introducing a temporary by removing the
-// .noalias() annotation causes the issue to disappear. Tracking this
-// issue down was tricky, since the test suite doesn't run when built with
-// the non-standalone toolchain.
-//
-// TODO(keir): Make a reproduction case for this and send it upstream.
-#ifdef CERES_WORK_AROUND_ANDROID_NDK_COMPILER_BUG
-#define CERES_MAYBE_NOALIAS
-#else
-#define CERES_MAYBE_NOALIAS .noalias()
-#endif
-
 // The following three macros are used to share code and reduce
 // template junk across the various GEMM variants.
 #define CERES_GEMM_BEGIN(name)                                          \
@@ -168,11 +144,11 @@ CERES_GEMM_BEGIN(MatrixMatrixMultiplyEigen) {
     block(Cref, start_row_c, start_col_c, num_row_a, num_col_b);
 
   if (kOperation > 0) {
-    block CERES_MAYBE_NOALIAS += Aref * Bref;
+    block.noalias() += Aref * Bref;
   } else if (kOperation < 0) {
-    block CERES_MAYBE_NOALIAS -= Aref * Bref;
+    block.noalias() -= Aref * Bref;
   } else {
-    block CERES_MAYBE_NOALIAS = Aref * Bref;
+    block.noalias() = Aref * Bref;
   }
 }
 
@@ -228,11 +204,11 @@ CERES_GEMM_BEGIN(MatrixTransposeMatrixMultiplyEigen) {
                                               start_row_c, start_col_c,
                                               num_col_a, num_col_b);
   if (kOperation > 0) {
-    block CERES_MAYBE_NOALIAS += Aref.transpose() * Bref;
+    block.noalias() += Aref.transpose() * Bref;
   } else if (kOperation < 0) {
-    block CERES_MAYBE_NOALIAS -= Aref.transpose() * Bref;
+    block.noalias() -= Aref.transpose() * Bref;
   } else {
-    block CERES_MAYBE_NOALIAS = Aref.transpose() * Bref;
+    block.noalias() = Aref.transpose() * Bref;
   }
 }
 
@@ -394,8 +370,6 @@ inline void MatrixTransposeVectorMultiply(const double* A,
 #endif  // CERES_NO_CUSTOM_BLAS
 }
 
-
-#undef CERES_MAYBE_NOALIAS
 #undef CERES_GEMM_BEGIN
 #undef CERES_GEMM_EIGEN_HEADER
 #undef CERES_GEMM_NAIVE_HEADER
index 53a9b4b7220d3633c3417fd7a72ed74b08b9c5b3..f90045baac9f522ef19fe08c11d3822b81eeda26 100644 (file)
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
+// Copyright 2014 Google Inc. All rights reserved.
 // http://code.google.com/p/ceres-solver/
 //
 // Redistribution and use in source and binary forms, with or without
 
 #include "ceres/solver.h"
 
+#include <algorithm>
+#include <sstream>   // NOLINT
 #include <vector>
+#include "ceres/gradient_checking_cost_function.h"
+#include "ceres/internal/port.h"
+#include "ceres/parameter_block_ordering.h"
+#include "ceres/preprocessor.h"
 #include "ceres/problem.h"
 #include "ceres/problem_impl.h"
 #include "ceres/program.h"
-#include "ceres/solver_impl.h"
+#include "ceres/solver_utils.h"
 #include "ceres/stringprintf.h"
+#include "ceres/types.h"
 #include "ceres/wall_time.h"
 
 namespace ceres {
 namespace {
 
+#define OPTION_OP(x, y, OP)                                             \
+  if (!(options.x OP y)) {                                              \
+    std::stringstream ss;                                               \
+    ss << "Invalid configuration. ";                                    \
+    ss << string("Solver::Options::" #x " = ") << options.x << ". ";    \
+    ss << "Violated constraint: ";                                      \
+    ss << string("Solver::Options::" #x " " #OP " "#y);                 \
+    *error = ss.str();                                                  \
+    return false;                                                       \
+  }
+
+#define OPTION_OP_OPTION(x, y, OP)                                      \
+  if (!(options.x OP options.y)) {                                      \
+    std::stringstream ss;                                               \
+    ss << "Invalid configuration. ";                                    \
+    ss << string("Solver::Options::" #x " = ") << options.x << ". ";    \
+    ss << string("Solver::Options::" #y " = ") << options.y << ". ";    \
+    ss << "Violated constraint: ";                                      \
+    ss << string("Solver::Options::" #x);                               \
+    ss << string(#OP " Solver::Options::" #y ".");                      \
+    *error = ss.str();                                                  \
+    return false;                                                       \
+  }
+
+#define OPTION_GE(x, y) OPTION_OP(x, y, >=);
+#define OPTION_GT(x, y) OPTION_OP(x, y, >);
+#define OPTION_LE(x, y) OPTION_OP(x, y, <=);
+#define OPTION_LT(x, y) OPTION_OP(x, y, <);
+#define OPTION_LE_OPTION(x, y) OPTION_OP_OPTION(x, y, <=)
+#define OPTION_LT_OPTION(x, y) OPTION_OP_OPTION(x, y, <)
+
+bool CommonOptionsAreValid(const Solver::Options& options, string* error) {
+  OPTION_GE(max_num_iterations, 0);
+  OPTION_GE(max_solver_time_in_seconds, 0.0);
+  OPTION_GE(function_tolerance, 0.0);
+  OPTION_GE(gradient_tolerance, 0.0);
+  OPTION_GE(parameter_tolerance, 0.0);
+  OPTION_GT(num_threads, 0);
+  OPTION_GT(num_linear_solver_threads, 0);
+  if (options.check_gradients) {
+    OPTION_GT(gradient_check_relative_precision, 0.0);
+    OPTION_GT(numeric_derivative_relative_step_size, 0.0);
+  }
+  return true;
+}
+
+bool TrustRegionOptionsAreValid(const Solver::Options& options, string* error) {
+  OPTION_GT(initial_trust_region_radius, 0.0);
+  OPTION_GT(min_trust_region_radius, 0.0);
+  OPTION_GT(max_trust_region_radius, 0.0);
+  OPTION_LE_OPTION(min_trust_region_radius, max_trust_region_radius);
+  OPTION_LE_OPTION(min_trust_region_radius, initial_trust_region_radius);
+  OPTION_LE_OPTION(initial_trust_region_radius, max_trust_region_radius);
+  OPTION_GE(min_relative_decrease, 0.0);
+  OPTION_GE(min_lm_diagonal, 0.0);
+  OPTION_GE(max_lm_diagonal, 0.0);
+  OPTION_LE_OPTION(min_lm_diagonal, max_lm_diagonal);
+  OPTION_GE(max_num_consecutive_invalid_steps, 0);
+  OPTION_GT(eta, 0.0);
+  OPTION_GE(min_linear_solver_iterations, 0);
+  OPTION_GE(max_linear_solver_iterations, 1);
+  OPTION_LE_OPTION(min_linear_solver_iterations, max_linear_solver_iterations);
+
+  if (options.use_inner_iterations) {
+    OPTION_GE(inner_iteration_tolerance, 0.0);
+  }
+
+  if (options.use_nonmonotonic_steps) {
+    OPTION_GT(max_consecutive_nonmonotonic_steps, 0);
+  }
+
+  if (options.preconditioner_type == CLUSTER_JACOBI &&
+      options.sparse_linear_algebra_library_type != SUITE_SPARSE) {
+    *error =  "CLUSTER_JACOBI requires "
+        "Solver::Options::sparse_linear_algebra_library_type to be "
+        "SUITE_SPARSE";
+    return false;
+  }
+
+  if (options.preconditioner_type == CLUSTER_TRIDIAGONAL &&
+      options.sparse_linear_algebra_library_type != SUITE_SPARSE) {
+    *error =  "CLUSTER_TRIDIAGONAL requires "
+        "Solver::Options::sparse_linear_algebra_library_type to be "
+        "SUITE_SPARSE";
+    return false;
+  }
+
+#ifdef CERES_NO_LAPACK
+  if (options.dense_linear_algebra_library_type == LAPACK) {
+    if (options.linear_solver_type == DENSE_NORMAL_CHOLESKY) {
+      *error = "Can't use DENSE_NORMAL_CHOLESKY with LAPACK because "
+          "LAPACK was not enabled when Ceres was built.";
+      return false;
+    }
+
+    if (options.linear_solver_type == DENSE_QR) {
+      *error = "Can't use DENSE_QR with LAPACK because "
+          "LAPACK was not enabled when Ceres was built.";
+      return false;
+    }
+
+    if (options.linear_solver_type == DENSE_SCHUR) {
+      *error = "Can't use DENSE_SCHUR with LAPACK because "
+          "LAPACK was not enabled when Ceres was built.";
+      return false;
+    }
+  }
+#endif
+
+#ifdef CERES_NO_SUITESPARSE
+  if (options.sparse_linear_algebra_library_type == SUITE_SPARSE) {
+    if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY) {
+      *error = "Can't use SPARSE_NORMAL_CHOLESKY with SUITESPARSE because "
+             "SuiteSparse was not enabled when Ceres was built.";
+      return false;
+    }
+
+    if (options.linear_solver_type == SPARSE_SCHUR) {
+      *error = "Can't use SPARSE_SCHUR with SUITESPARSE because "
+          "SuiteSparse was not enabled when Ceres was built.";
+      return false;
+    }
+
+    if (options.preconditioner_type == CLUSTER_JACOBI) {
+      *error =  "CLUSTER_JACOBI preconditioner not supported. "
+          "SuiteSparse was not enabled when Ceres was built.";
+      return false;
+    }
+
+    if (options.preconditioner_type == CLUSTER_TRIDIAGONAL) {
+      *error =  "CLUSTER_TRIDIAGONAL preconditioner not supported. "
+          "SuiteSparse was not enabled when Ceres was built.";
+    return false;
+    }
+  }
+#endif
+
+#ifdef CERES_NO_CXSPARSE
+  if (options.sparse_linear_algebra_library_type == CX_SPARSE) {
+    if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY) {
+      *error = "Can't use SPARSE_NORMAL_CHOLESKY with CX_SPARSE because "
+             "CXSparse was not enabled when Ceres was built.";
+      return false;
+    }
+
+    if (options.linear_solver_type == SPARSE_SCHUR) {
+      *error = "Can't use SPARSE_SCHUR with CX_SPARSE because "
+          "CXSparse was not enabled when Ceres was built.";
+      return false;
+    }
+  }
+#endif
+
+#ifndef CERES_USE_EIGEN_SPARSE
+  if (options.sparse_linear_algebra_library_type == EIGEN_SPARSE) {
+    if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY) {
+      *error = "Can't use SPARSE_NORMAL_CHOLESKY with EIGEN_SPARSE because "
+          "Eigen's sparse linear algebra was not enabled when Ceres was "
+          "built.";
+      return false;
+    }
+
+    if (options.linear_solver_type == SPARSE_SCHUR) {
+      *error = "Can't use SPARSE_SCHUR with EIGEN_SPARSE because "
+          "Eigen's sparse linear algebra was not enabled when Ceres was "
+          "built.";
+      return false;
+    }
+  }
+#endif
+
+  if (options.trust_region_strategy_type == DOGLEG) {
+    if (options.linear_solver_type == ITERATIVE_SCHUR ||
+        options.linear_solver_type == CGNR) {
+      *error = "DOGLEG only supports exact factorization based linear "
+          "solvers. If you want to use an iterative solver please "
+          "use LEVENBERG_MARQUARDT as the trust_region_strategy_type";
+      return false;
+    }
+  }
+
+  if (options.trust_region_minimizer_iterations_to_dump.size() > 0 &&
+      options.trust_region_problem_dump_format_type != CONSOLE &&
+      options.trust_region_problem_dump_directory.empty()) {
+    *error = "Solver::Options::trust_region_problem_dump_directory is empty.";
+    return false;
+  }
+
+  if (options.dynamic_sparsity &&
+      options.linear_solver_type != SPARSE_NORMAL_CHOLESKY) {
+    *error = "Dynamic sparsity is only supported with SPARSE_NORMAL_CHOLESKY.";
+    return false;
+  }
+
+  return true;
+}
+
+bool LineSearchOptionsAreValid(const Solver::Options& options, string* error) {
+  OPTION_GT(max_lbfgs_rank, 0);
+  OPTION_GT(min_line_search_step_size, 0.0);
+  OPTION_GT(max_line_search_step_contraction, 0.0);
+  OPTION_LT(max_line_search_step_contraction, 1.0);
+  OPTION_LT_OPTION(max_line_search_step_contraction,
+                   min_line_search_step_contraction);
+  OPTION_LE(min_line_search_step_contraction, 1.0);
+  OPTION_GT(max_num_line_search_step_size_iterations, 0);
+  OPTION_GT(line_search_sufficient_function_decrease, 0.0);
+  OPTION_LT_OPTION(line_search_sufficient_function_decrease,
+                   line_search_sufficient_curvature_decrease);
+  OPTION_LT(line_search_sufficient_curvature_decrease, 1.0);
+  OPTION_GT(max_line_search_step_expansion, 1.0);
+
+  if ((options.line_search_direction_type == ceres::BFGS ||
+       options.line_search_direction_type == ceres::LBFGS) &&
+      options.line_search_type != ceres::WOLFE) {
+    *error =
+        string("Invalid configuration: Solver::Options::line_search_type = ")
+        + string(LineSearchTypeToString(options.line_search_type))
+        + string(". When using (L)BFGS, "
+                 "Solver::Options::line_search_type must be set to WOLFE.");
+    return false;
+  }
+
+  // Warn user if they have requested BISECTION interpolation, but constraints
+  // on max/min step size change during line search prevent bisection scaling
+  // from occurring. Warn only, as this is likely a user mistake, but one which
+  // does not prevent us from continuing.
+  LOG_IF(WARNING,
+         (options.line_search_interpolation_type == ceres::BISECTION &&
+          (options.max_line_search_step_contraction > 0.5 ||
+           options.min_line_search_step_contraction < 0.5)))
+      << "Line search interpolation type is BISECTION, but specified "
+      << "max_line_search_step_contraction: "
+      << options.max_line_search_step_contraction << ", and "
+      << "min_line_search_step_contraction: "
+      << options.min_line_search_step_contraction
+      << ", prevent bisection (0.5) scaling, continuing with solve regardless.";
+
+  return true;
+}
+
+#undef OPTION_OP
+#undef OPTION_OP_OPTION
+#undef OPTION_GT
+#undef OPTION_GE
+#undef OPTION_LE
+#undef OPTION_LT
+#undef OPTION_LE_OPTION
+#undef OPTION_LT_OPTION
+
 void StringifyOrdering(const vector<int>& ordering, string* report) {
   if (ordering.size() == 0) {
     internal::StringAppendF(report, "AUTOMATIC");
@@ -54,19 +311,211 @@ void StringifyOrdering(const vector<int>& ordering, string* report) {
   internal::StringAppendF(report, "%d", ordering.back());
 }
 
+void SummarizeGivenProgram(const internal::Program& program,
+                           Solver::Summary* summary) {
+  summary->num_parameter_blocks     = program.NumParameterBlocks();
+  summary->num_parameters           = program.NumParameters();
+  summary->num_effective_parameters = program.NumEffectiveParameters();
+  summary->num_residual_blocks      = program.NumResidualBlocks();
+  summary->num_residuals            = program.NumResiduals();
+}
+
+void SummarizeReducedProgram(const internal::Program& program,
+                             Solver::Summary* summary) {
+  summary->num_parameter_blocks_reduced     = program.NumParameterBlocks();
+  summary->num_parameters_reduced           = program.NumParameters();
+  summary->num_effective_parameters_reduced = program.NumEffectiveParameters();
+  summary->num_residual_blocks_reduced      = program.NumResidualBlocks();
+  summary->num_residuals_reduced            = program.NumResiduals();
+}
+
+void PreSolveSummarize(const Solver::Options& options,
+                       const internal::ProblemImpl* problem,
+                       Solver::Summary* summary) {
+  SummarizeGivenProgram(problem->program(), summary);
+  internal::OrderingToGroupSizes(options.linear_solver_ordering.get(),
+                                 &(summary->linear_solver_ordering_given));
+  internal::OrderingToGroupSizes(options.inner_iteration_ordering.get(),
+                                 &(summary->inner_iteration_ordering_given));
+
+  summary->dense_linear_algebra_library_type  = options.dense_linear_algebra_library_type;  //  NOLINT
+  summary->dogleg_type                        = options.dogleg_type;
+  summary->inner_iteration_time_in_seconds    = 0.0;
+  summary->inner_iterations_given             = options.use_inner_iterations;
+  summary->line_search_direction_type         = options.line_search_direction_type;         //  NOLINT
+  summary->line_search_interpolation_type     = options.line_search_interpolation_type;     //  NOLINT
+  summary->line_search_type                   = options.line_search_type;
+  summary->linear_solver_type_given           = options.linear_solver_type;
+  summary->max_lbfgs_rank                     = options.max_lbfgs_rank;
+  summary->minimizer_type                     = options.minimizer_type;
+  summary->nonlinear_conjugate_gradient_type  = options.nonlinear_conjugate_gradient_type;  //  NOLINT
+  summary->num_linear_solver_threads_given    = options.num_linear_solver_threads;          //  NOLINT
+  summary->num_threads_given                  = options.num_threads;
+  summary->preconditioner_type_given          = options.preconditioner_type;
+  summary->sparse_linear_algebra_library_type = options.sparse_linear_algebra_library_type; //  NOLINT
+  summary->trust_region_strategy_type         = options.trust_region_strategy_type;         //  NOLINT
+  summary->visibility_clustering_type         = options.visibility_clustering_type;         //  NOLINT
+}
+
+void PostSolveSummarize(const internal::PreprocessedProblem& pp,
+                        Solver::Summary* summary) {
+  internal::OrderingToGroupSizes(pp.options.linear_solver_ordering.get(),
+                                 &(summary->linear_solver_ordering_used));
+  internal::OrderingToGroupSizes(pp.options.inner_iteration_ordering.get(),
+                                 &(summary->inner_iteration_ordering_used));
+
+  summary->inner_iterations_used          = pp.inner_iteration_minimizer.get() != NULL;     // NOLINT
+  summary->linear_solver_type_used        = pp.options.linear_solver_type;
+  summary->num_linear_solver_threads_used = pp.options.num_linear_solver_threads;           // NOLINT
+  summary->num_threads_used               = pp.options.num_threads;
+  summary->preconditioner_type_used       = pp.options.preconditioner_type;                 // NOLINT
+
+  internal::SetSummaryFinalCost(summary);
+