Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/extern
diff options
context:
space:
mode:
authorTamito Kajiyama <rd6t-kjym@asahi-net.or.jp>2013-03-03 19:07:49 +0400
committerTamito Kajiyama <rd6t-kjym@asahi-net.or.jp>2013-03-03 19:07:49 +0400
commit66a2b848972d47a033f617a40f9a9044756d1d32 (patch)
treebf30f5bc13e9c0b4f52aacead676a2c07cbb331a /extern
parent0c5dfc8a639b04e1767852121b9dee7cd5bb050f (diff)
parent4774357b594c5cd5a38b21df131b539a197c101b (diff)
Merged changes in the trunk up to revision 54992.
Resolved conflicts: release/scripts/startup/bl_ui/space_view3d.py
Diffstat (limited to 'extern')
-rwxr-xr-xextern/carve/bundle.sh2
-rw-r--r--extern/carve/files.txt174
-rw-r--r--extern/carve/include/carve/csg_triangulator.hpp2
-rw-r--r--extern/carve/include/carve/geom3d.hpp19
-rw-r--r--extern/carve/include/carve/geom_impl.hpp2
-rw-r--r--extern/carve/include/carve/input.hpp81
-rw-r--r--extern/carve/include/carve/mesh.hpp38
-rw-r--r--extern/carve/include/carve/mesh_impl.hpp59
-rw-r--r--extern/carve/lib/intersect.cpp4
-rw-r--r--extern/carve/lib/intersect_face_division.cpp3
-rw-r--r--extern/carve/lib/mesh.cpp36
-rw-r--r--extern/carve/lib/polyhedron.cpp2
-rw-r--r--extern/carve/patches/series1
-rw-r--r--extern/carve/patches/strict_flags.patch22
-rw-r--r--extern/libmv/CMakeLists.txt18
-rw-r--r--extern/libmv/ChangeLog430
-rw-r--r--extern/libmv/SConscript6
-rwxr-xr-xextern/libmv/bundle.sh7
-rw-r--r--extern/libmv/files.txt22
-rw-r--r--extern/libmv/libmv-capi.cpp466
-rw-r--r--extern/libmv/libmv-capi.h89
-rw-r--r--extern/libmv/libmv/multiview/euclidean_resection.cc4
-rw-r--r--extern/libmv/libmv/multiview/fundamental.cc4
-rw-r--r--extern/libmv/libmv/multiview/homography.cc15
-rw-r--r--extern/libmv/libmv/multiview/homography.h8
-rw-r--r--extern/libmv/libmv/multiview/panography.h181
-rw-r--r--extern/libmv/libmv/simple_pipeline/bundle.cc453
-rw-r--r--extern/libmv/libmv/simple_pipeline/bundle.h12
-rw-r--r--extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc24
-rw-r--r--extern/libmv/libmv/simple_pipeline/camera_intrinsics.h31
-rw-r--r--extern/libmv/libmv/simple_pipeline/intersect.cc80
-rw-r--r--extern/libmv/libmv/simple_pipeline/modal_solver.cc180
-rw-r--r--extern/libmv/libmv/simple_pipeline/pipeline.cc2
-rw-r--r--extern/libmv/libmv/simple_pipeline/rigid_registration.cc182
-rw-r--r--extern/libmv/libmv/simple_pipeline/rigid_registration.h68
-rw-r--r--extern/libmv/patches/series1
-rw-r--r--extern/libmv/patches/v3d_verbosity.patch12
-rw-r--r--extern/libmv/third_party/ceres/CMakeLists.txt40
-rw-r--r--extern/libmv/third_party/ceres/ChangeLog730
-rw-r--r--extern/libmv/third_party/ceres/SConscript4
-rwxr-xr-xextern/libmv/third_party/ceres/bundle.sh16
-rw-r--r--extern/libmv/third_party/ceres/files.txt33
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/autodiff_cost_function.h71
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/ceres.h8
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/cost_function_to_functor.h752
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/crs_matrix.h32
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/dynamic_autodiff_cost_function.h215
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/fpclassify.h2
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/gradient_checker.h222
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/autodiff.h158
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/fixed_array.h6
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/macros.h12
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/manual_constructor.h29
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/numeric_diff.h199
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/scoped_ptr.h15
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/variadic_evaluate.h182
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/iteration_callback.h43
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/numeric_diff_cost_function.h374
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/numeric_diff_functor.h346
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/ordered_groups.h176
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/problem.h156
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/rotation.h196
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/sized_cost_function.h30
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/solver.h313
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/types.h110
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/array_utils.h2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc20
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.h29
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.h6
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.cc34
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h15
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/collections_port.h2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc3
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h9
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.cc236
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.h88
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/corrector.cc17
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc10
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/cxsparse.h5
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dense_jacobian_writer.h11
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc13
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.cc29
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.h2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.cc16
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.h1
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc18
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h4
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/evaluator.h17
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/execution_summary.h90
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/file.cc3
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc4
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/graph.h25
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/graph_algorithms.h4
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc64
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.h12
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h5
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/line_search.cc211
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/line_search.h212
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/line_search_direction.cc145
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/line_search_direction.h (renamed from extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.h)55
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.cc283
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.h77
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.cc72
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.h2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/linear_solver.h56
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.cc109
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.h99
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/map_util.h1
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/minimizer.cc67
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/minimizer.h24
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/mutex.h6
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/parameter_block.h61
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.cc (renamed from extern/libmv/third_party/ceres/internal/ceres/schur_ordering.cc)29
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.h (renamed from extern/libmv/third_party/ceres/internal/ceres/schur_ordering.h)16
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/polynomial.cc (renamed from extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.cc)141
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/polynomial.h134
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/preconditioner.cc63
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/preconditioner.h148
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/problem.cc64
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc567
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/problem_impl.h62
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h28
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/residual_block.cc6
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/residual_block.h21
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.cc4
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc49
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h6
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/schur_eliminator_impl.h2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.cc145
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.h110
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/solver.cc331
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/solver_impl.cc1029
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/solver_impl.h95
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc36
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/split.cc3
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/split.h2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/stl_util.h16
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc3
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/stringprintf.h6
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc7
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/suitesparse.h4
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc3
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc238
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.h12
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.cc32
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.h2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/types.cc208
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/visibility.cc3
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/visibility.h2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc73
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h79
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/wall_time.cc96
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/wall_time.h88
-rw-r--r--extern/libmv/third_party/ceres/patches/collections_port.h.mingw.patch13
-rw-r--r--extern/libmv/third_party/ceres/patches/msvc_glog_fix.patch50
-rw-r--r--extern/libmv/third_party/ceres/patches/no_previous_declaration_fix.patch199
-rw-r--r--extern/libmv/third_party/ceres/patches/series3
-rw-r--r--extern/libmv/third_party/ldl/CMakeLists.txt5
-rw-r--r--extern/libmv/third_party/ldl/Doc/ChangeLog39
-rw-r--r--extern/libmv/third_party/ldl/Doc/lesser.txt504
-rw-r--r--extern/libmv/third_party/ldl/Include/ldl.h104
-rw-r--r--extern/libmv/third_party/ldl/README.libmv10
-rw-r--r--extern/libmv/third_party/ldl/README.txt136
-rw-r--r--extern/libmv/third_party/ldl/Source/ldl.c507
-rw-r--r--extern/libmv/third_party/ssba/COPYING.TXT165
-rw-r--r--extern/libmv/third_party/ssba/Geometry/v3d_cameramatrix.h204
-rw-r--r--extern/libmv/third_party/ssba/Geometry/v3d_distortion.h97
-rw-r--r--extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.cpp405
-rw-r--r--extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.h352
-rw-r--r--extern/libmv/third_party/ssba/Math/v3d_linear.h923
-rw-r--r--extern/libmv/third_party/ssba/Math/v3d_linear_utils.h391
-rw-r--r--extern/libmv/third_party/ssba/Math/v3d_mathutilities.h59
-rw-r--r--extern/libmv/third_party/ssba/Math/v3d_optimization.cpp955
-rw-r--r--extern/libmv/third_party/ssba/Math/v3d_optimization.h273
-rw-r--r--extern/libmv/third_party/ssba/README.TXT92
-rw-r--r--extern/libmv/third_party/ssba/README.libmv23
-rw-r--r--extern/lzo/minilzo/COPYING29
-rw-r--r--extern/lzo/minilzo/README.LZO27
-rw-r--r--extern/lzo/minilzo/lzoconf.h79
-rw-r--r--extern/lzo/minilzo/lzodefs.h179
-rw-r--r--extern/lzo/minilzo/minilzo.c1195
-rw-r--r--extern/lzo/minilzo/minilzo.h8
185 files changed, 11295 insertions, 9184 deletions
diff --git a/extern/carve/bundle.sh b/extern/carve/bundle.sh
index 63d32a5993d..c80bf645077 100755
--- a/extern/carve/bundle.sh
+++ b/extern/carve/bundle.sh
@@ -91,7 +91,7 @@ if(WITH_BOOST)
-DCARVE_SYSTEM_BOOST
)
- list(APPEND INC
+ list(APPEND INC_SYS
\${BOOST_INCLUDE_DIR}
)
endif()
diff --git a/extern/carve/files.txt b/extern/carve/files.txt
index c3cb9275950..1084c7f5c41 100644
--- a/extern/carve/files.txt
+++ b/extern/carve/files.txt
@@ -1,107 +1,109 @@
-include/carve/polyhedron_decl.hpp
-include/carve/geom2d.hpp
-include/carve/exact.hpp
-include/carve/triangulator_impl.hpp
-include/carve/collection.hpp
-include/carve/pointset.hpp
-include/carve/djset.hpp
-include/carve/kd_node.hpp
-include/carve/polyline.hpp
-include/carve/polyline_iter.hpp
-include/carve/geom3d.hpp
-include/carve/edge_decl.hpp
-include/carve/face_decl.hpp
+include/carve/vertex_impl.hpp
include/carve/aabb_impl.hpp
-include/carve/colour.hpp
+include/carve/csg.hpp
include/carve/pointset_iter.hpp
-include/carve/polyline_decl.hpp
-include/carve/rescale.hpp
-include/carve/mesh_impl.hpp
-include/carve/classification.hpp
-include/carve/util.hpp
-include/carve/triangulator.hpp
-include/carve/polyhedron_base.hpp
-include/carve/rtree.hpp
-include/carve/math.hpp
-include/carve/math_constants.hpp
-include/carve/octree_decl.hpp
-include/carve/input.hpp
-include/carve/mesh_ops.hpp
include/carve/debug_hooks.hpp
-include/carve/mesh_simplify.hpp
-include/carve/interpolator.hpp
-include/carve/poly_decl.hpp
-include/carve/csg.hpp
include/carve/mesh.hpp
-include/carve/carve.hpp
-include/carve/gnu_cxx.h
-include/carve/polyhedron_impl.hpp
-include/carve/poly_impl.hpp
-include/carve/aabb.hpp
+include/carve/triangulator_impl.hpp
+include/carve/edge_decl.hpp
+include/carve/collection/unordered.hpp
+include/carve/collection/unordered/tr1_impl.hpp
+include/carve/collection/unordered/fallback_impl.hpp
+include/carve/collection/unordered/std_impl.hpp
+include/carve/collection/unordered/vcpp_impl.hpp
+include/carve/collection/unordered/libstdcpp_impl.hpp
+include/carve/collection/unordered/boost_impl.hpp
include/carve/convex_hull.hpp
-include/carve/vertex_decl.hpp
+include/carve/geom.hpp
+include/carve/collection_types.hpp
+include/carve/cbrt.h
+include/carve/util.hpp
+include/carve/iobj.hpp
+include/carve/polyline_decl.hpp
+include/carve/polyline_impl.hpp
include/carve/win32.h
include/carve/edge_impl.hpp
-include/carve/tag.hpp
-include/carve/tree.hpp
-include/carve/heap.hpp
+include/carve/carve.hpp
+include/carve/polyline.hpp
+include/carve/config.h
+include/carve/face_decl.hpp
include/carve/matrix.hpp
-include/carve/poly.hpp
-include/carve/vector.hpp
-include/carve/intersection.hpp
-include/carve/faceloop.hpp
+include/carve/classification.hpp
include/carve/geom_impl.hpp
-include/carve/octree_impl.hpp
-include/carve/spacetree.hpp
-include/carve/collection/unordered/std_impl.hpp
-include/carve/collection/unordered/tr1_impl.hpp
-include/carve/collection/unordered/libstdcpp_impl.hpp
-include/carve/collection/unordered/boost_impl.hpp
-include/carve/collection/unordered/vcpp_impl.hpp
-include/carve/collection/unordered/fallback_impl.hpp
-include/carve/collection/unordered.hpp
+include/carve/faceloop.hpp
+include/carve/mesh_ops.hpp
+include/carve/tree.hpp
+include/carve/geom2d.hpp
include/carve/face_impl.hpp
+include/carve/polyhedron_decl.hpp
+include/carve/interpolator.hpp
+include/carve/poly_decl.hpp
+include/carve/mesh_impl.hpp
+include/carve/gnu_cxx.h
+include/carve/mesh_simplify.hpp
+include/carve/triangulator.hpp
include/carve/pointset_impl.hpp
-include/carve/cbrt.h
+include/carve/rtree.hpp
+include/carve/math_constants.hpp
+include/carve/vector.hpp
+include/carve/octree_impl.hpp
+include/carve/pointset.hpp
+include/carve/math.hpp
+include/carve/intersection.hpp
+include/carve/colour.hpp
+include/carve/kd_node.hpp
+include/carve/input.hpp
+include/carve/geom3d.hpp
+include/carve/exact.hpp
+include/carve/rescale.hpp
+include/carve/polyhedron_base.hpp
+include/carve/heap.hpp
+include/carve/spacetree.hpp
+include/carve/polyhedron_impl.hpp
include/carve/vcpp_config.h
-include/carve/geom.hpp
-include/carve/vertex_impl.hpp
-include/carve/polyline_impl.hpp
-include/carve/pointset_decl.hpp
-include/carve/timing.hpp
+include/carve/aabb.hpp
+include/carve/polyline_iter.hpp
+include/carve/djset.hpp
+include/carve/vertex_decl.hpp
include/carve/csg_triangulator.hpp
-include/carve/iobj.hpp
-include/carve/collection_types.hpp
-lib/carve.cpp
-lib/mesh.cpp
-lib/intersect_group.cpp
-lib/intersect_classify_common.hpp
-lib/intersect_classify_edge.cpp
-lib/intersect_classify_group.cpp
+include/carve/poly.hpp
+include/carve/external/boost/random.hpp
+include/carve/timing.hpp
+include/carve/octree_decl.hpp
+include/carve/pointset_decl.hpp
+include/carve/tag.hpp
+include/carve/collection.hpp
+include/carve/poly_impl.hpp
+lib/intersection.cpp
+lib/intersect.cpp
+lib/triangulator.cpp
+lib/intersect_debug.hpp
+lib/csg_collector.hpp
lib/csg_data.hpp
+lib/convex_hull.cpp
+lib/intersect_classify_common.hpp
+lib/intersect_common.hpp
lib/polyhedron.cpp
-lib/csg_collector.hpp
-lib/geom3d.cpp
lib/polyline.cpp
-lib/csg_collector.cpp
-lib/triangulator.cpp
-lib/intersect_face_division.cpp
-lib/intersect_half_classify_group.cpp
-lib/edge.cpp
-lib/math.cpp
+lib/pointset.cpp
lib/geom2d.cpp
+lib/math.cpp
+lib/intersect_half_classify_group.cpp
+lib/intersect_face_division.cpp
lib/tag.cpp
-lib/intersection.cpp
-lib/convex_hull.cpp
-lib/intersect_common.hpp
-lib/intersect_classify_common_impl.hpp
-lib/csg.cpp
-lib/intersect.cpp
+lib/aabb.cpp
+lib/intersect_classify_group.cpp
lib/csg_detail.hpp
-lib/face.cpp
-lib/pointset.cpp
+lib/mesh.cpp
lib/timing.cpp
-lib/octree.cpp
-lib/aabb.cpp
-lib/intersect_debug.hpp
+lib/geom3d.cpp
+lib/intersect_group.cpp
+lib/carve.cpp
+lib/intersect_classify_edge.cpp
+lib/csg.cpp
+lib/face.cpp
+lib/csg_collector.cpp
lib/intersect_debug.cpp
+lib/edge.cpp
+lib/intersect_classify_common_impl.hpp
+lib/octree.cpp
diff --git a/extern/carve/include/carve/csg_triangulator.hpp b/extern/carve/include/carve/csg_triangulator.hpp
index 740585571bf..5a40439271e 100644
--- a/extern/carve/include/carve/csg_triangulator.hpp
+++ b/extern/carve/include/carve/csg_triangulator.hpp
@@ -174,7 +174,7 @@ namespace carve {
double scoreQuad(edge_map_t::iterator i, edge_map_t &edge_map) {
if (!(*i).second.first || !(*i).second.second) return -1;
- return 0;
+ return -1;
}
carve::mesh::MeshSet<3>::face_t *mergeQuad(edge_map_t::iterator i, edge_map_t &edge_map) {
diff --git a/extern/carve/include/carve/geom3d.hpp b/extern/carve/include/carve/geom3d.hpp
index 90d0672b81e..faeb565b922 100644
--- a/extern/carve/include/carve/geom3d.hpp
+++ b/extern/carve/include/carve/geom3d.hpp
@@ -206,9 +206,22 @@ namespace carve {
* * +1, if a is ordered after b around, rotating about direction.
*/
inline int compareAngles(const Vector &direction, const Vector &base, const Vector &a, const Vector &b) {
- const double d1 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, a, b);
- const double d2 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, base, a);
- const double d3 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, base, b);
+ // double d1 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, a, b);
+ // double d2 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, base, a);
+ // double d3 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, base, b);
+
+#if defined(CARVE_USE_EXACT_PREDICATES)
+ // which is equivalent to the following (which eliminates a
+ // vector subtraction):
+ double d1 = carve::geom3d::orient3d(direction, b, a, carve::geom::VECTOR(0,0,0));
+ double d2 = carve::geom3d::orient3d(direction, a, base, carve::geom::VECTOR(0,0,0));
+ double d3 = carve::geom3d::orient3d(direction, b, base, carve::geom::VECTOR(0,0,0));
+#else
+ // dotcross = a . (b x c)
+ double d1 = carve::geom::dotcross(direction, b, a );
+ double d2 = carve::geom::dotcross(direction, a, base);
+ double d3 = carve::geom::dotcross(direction, b, base);
+#endif
// CASE: a and b are coplanar wrt. direction.
if (d1 == 0.0) {
diff --git a/extern/carve/include/carve/geom_impl.hpp b/extern/carve/include/carve/geom_impl.hpp
index 4463ba2bd88..044655b6c07 100644
--- a/extern/carve/include/carve/geom_impl.hpp
+++ b/extern/carve/include/carve/geom_impl.hpp
@@ -396,7 +396,7 @@ namespace carve {
// Compute a . (b x c)
return
(a.x * b.y * c.z + a.y * b.z * c.x + a.z * b.x * c.y) -
- (a.x * b.z * c.y + a.y * b.x * c.z + a.z * b.y * c.x);
+ (a.x * c.y * b.z + a.y * c.z * b.x + a.z * c.x * b.y);
}
diff --git a/extern/carve/include/carve/input.hpp b/extern/carve/include/carve/input.hpp
index a8bc8137d6c..4223955c0fd 100644
--- a/extern/carve/include/carve/input.hpp
+++ b/extern/carve/include/carve/input.hpp
@@ -17,6 +17,9 @@
#pragma once
+#include <map>
+#include <string>
+
#include <carve/carve.hpp>
#include <carve/poly.hpp>
#include <carve/mesh.hpp>
@@ -28,6 +31,50 @@
namespace carve {
namespace input {
+ typedef std::map<std::string, std::string> Options;
+
+ static inline Options opts() {
+ return Options();
+ }
+
+ static inline Options opts(const char **kv) {
+ Options r;
+ for (size_t i = 0; kv[i] != NULL; i += 2) {
+ r[kv[i]] = kv[i+1];
+ }
+ return r;
+ }
+
+ static inline Options opts(const std::string &k1, const std::string &v1) {
+ Options r;
+ r[k1] = v1;
+ return r;
+ }
+
+ static inline Options opts(const std::string &k1, const std::string &v1,
+ const std::string &k2, const std::string &v2) {
+ Options r;
+ r[k1] = v1;
+ r[k2] = v2;
+ return r;
+ }
+
+ static inline Options opts(const std::string &k1, const std::string &v1,
+ const std::string &k2, const std::string &v2,
+ const std::string &k3, const std::string &v3) {
+ Options r;
+ r[k1] = v1;
+ r[k2] = v2;
+ r[k3] = v3;
+ return r;
+ }
+
+ static inline bool _bool(const std::string &str, bool _default = false) {
+ if (str == "true") return true;
+ if (str == "false") return false;
+ return _default;
+ }
+
struct Data {
Data() {
}
@@ -126,12 +173,18 @@ namespace carve {
faceCount = 0;
}
- carve::poly::Polyhedron *create() const {
+ carve::poly::Polyhedron *create(const Options &options) const {
return new carve::poly::Polyhedron(points, faceCount, faceIndices);
}
- carve::mesh::MeshSet<3> *createMesh() const {
- return new carve::mesh::MeshSet<3>(points, faceCount, faceIndices);
+ carve::mesh::MeshSet<3> *createMesh(const Options &options) const {
+ Options::const_iterator i;
+ carve::mesh::MeshOptions opts;
+ i = options.find("avoid_cavities");
+ if (i != options.end()) {
+ opts.avoid_cavities(_bool((*i).second));
+ }
+ return new carve::mesh::MeshSet<3>(points, faceCount, faceIndices, opts);
}
};
@@ -159,7 +212,7 @@ namespace carve {
polylines.back().second.push_back(idx);
}
- carve::line::PolylineSet *create() const {
+ carve::line::PolylineSet *create(const Options &options) const {
carve::line::PolylineSet *p = new carve::line::PolylineSet(points);
for (std::list<polyline_data_t>::const_iterator i = polylines.begin();
@@ -181,7 +234,7 @@ namespace carve {
virtual ~PointSetData() {
}
- carve::point::PointSet *create() const {
+ carve::point::PointSet *create(const Options &options) const {
carve::point::PointSet *p = new carve::point::PointSet(points);
return p;
}
@@ -214,37 +267,37 @@ namespace carve {
}
template<typename T>
- static inline T *create(Data *d) {
+ static inline T *create(Data *d, const Options &options = Options()) {
return NULL;
}
};
template<>
- inline carve::mesh::MeshSet<3> *Input::create(Data *d) {
+ inline carve::mesh::MeshSet<3> *Input::create(Data *d, const Options &options) {
PolyhedronData *p = dynamic_cast<PolyhedronData *>(d);
if (p == NULL) return NULL;
- return p->createMesh();
+ return p->createMesh(options);
}
template<>
- inline carve::poly::Polyhedron *Input::create(Data *d) {
+ inline carve::poly::Polyhedron *Input::create(Data *d, const Options &options) {
PolyhedronData *p = dynamic_cast<PolyhedronData *>(d);
if (p == NULL) return NULL;
- return p->create();
+ return p->create(options);
}
template<>
- inline carve::line::PolylineSet *Input::create(Data *d) {
+ inline carve::line::PolylineSet *Input::create(Data *d, const Options &options) {
PolylineSetData *p = dynamic_cast<PolylineSetData *>(d);
if (p == NULL) return NULL;
- return p->create();
+ return p->create(options);
}
template<>
- inline carve::point::PointSet *Input::create(Data *d) {
+ inline carve::point::PointSet *Input::create(Data *d, const Options &options) {
PointSetData *p = dynamic_cast<PointSetData *>(d);
if (p == NULL) return NULL;
- return p->create();
+ return p->create(options);
}
}
diff --git a/extern/carve/include/carve/mesh.hpp b/extern/carve/include/carve/mesh.hpp
index d4170e55133..202337b64d3 100644
--- a/extern/carve/include/carve/mesh.hpp
+++ b/extern/carve/include/carve/mesh.hpp
@@ -464,8 +464,27 @@ namespace carve {
+ struct MeshOptions {
+ bool opt_avoid_cavities;
+
+ MeshOptions() :
+ opt_avoid_cavities(false) {
+ }
+
+ MeshOptions &avoid_cavities(bool val) {
+ opt_avoid_cavities = val;
+ return *this;
+ }
+ };
+
+
+
namespace detail {
class FaceStitcher {
+ FaceStitcher();
+ FaceStitcher(const FaceStitcher &);
+ FaceStitcher &operator=(const FaceStitcher &);
+
typedef Vertex<3> vertex_t;
typedef Edge<3> edge_t;
typedef Face<3> face_t;
@@ -475,6 +494,8 @@ namespace carve {
typedef std::unordered_map<vpair_t, edgelist_t, carve::mesh::hash_vertex_pair> edge_map_t;
typedef std::unordered_map<const vertex_t *, std::set<const vertex_t *> > edge_graph_t;
+ MeshOptions opts;
+
edge_map_t edges;
edge_map_t complex_edges;
@@ -570,6 +591,8 @@ namespace carve {
void build(iter_t begin, iter_t end, std::vector<Mesh<3> *> &meshes);
public:
+ FaceStitcher(const MeshOptions &_opts);
+
template<typename iter_t>
void create(iter_t begin, iter_t end, std::vector<Mesh<3> *> &meshes);
};
@@ -623,7 +646,7 @@ namespace carve {
~Mesh();
template<typename iter_t>
- static void create(iter_t begin, iter_t end, std::vector<Mesh<ndim> *> &meshes);
+ static void create(iter_t begin, iter_t end, std::vector<Mesh<ndim> *> &meshes, const MeshOptions &opts);
aabb_t getAABB() const {
return aabb_t(faces.begin(), faces.end());
@@ -692,7 +715,7 @@ namespace carve {
MeshSet &operator=(const MeshSet &);
template<typename iter_t>
- void _init_from_faces(iter_t begin, iter_t end);
+ void _init_from_faces(iter_t begin, iter_t end, const MeshOptions &opts);
public:
typedef Vertex<ndim> vertex_t;
@@ -781,13 +804,16 @@ namespace carve {
MeshSet(const std::vector<typename vertex_t::vector_t> &points,
size_t n_faces,
- const std::vector<int> &face_indices);
+ const std::vector<int> &face_indices,
+ const MeshOptions &opts = MeshOptions());
// Construct a mesh set from a set of disconnected faces. Takes
// posession of the face pointers.
- MeshSet(std::vector<face_t *> &faces);
+ MeshSet(std::vector<face_t *> &faces,
+ const MeshOptions &opts = MeshOptions());
- MeshSet(std::list<face_t *> &faces);
+ MeshSet(std::list<face_t *> &faces,
+ const MeshOptions &opts = MeshOptions());
MeshSet(std::vector<vertex_t> &_vertex_storage,
std::vector<mesh_t *> &_meshes);
@@ -817,6 +843,8 @@ namespace carve {
void collectVertices();
void canonicalize();
+
+ void separateMeshes();
};
diff --git a/extern/carve/include/carve/mesh_impl.hpp b/extern/carve/include/carve/mesh_impl.hpp
index d55df8c8130..56fb6788b62 100644
--- a/extern/carve/include/carve/mesh_impl.hpp
+++ b/extern/carve/include/carve/mesh_impl.hpp
@@ -676,7 +676,7 @@ namespace carve {
template<unsigned ndim>
template<typename iter_t>
- void Mesh<ndim>::create(iter_t begin, iter_t end, std::vector<Mesh<ndim> *> &meshes) {
+ void Mesh<ndim>::create(iter_t begin, iter_t end, std::vector<Mesh<ndim> *> &meshes, const MeshOptions &opts) {
meshes.clear();
}
@@ -684,15 +684,15 @@ namespace carve {
template<>
template<typename iter_t>
- void Mesh<3>::create(iter_t begin, iter_t end, std::vector<Mesh<3> *> &meshes) {
- detail::FaceStitcher().create(begin, end, meshes);
+ void Mesh<3>::create(iter_t begin, iter_t end, std::vector<Mesh<3> *> &meshes, const MeshOptions &opts) {
+ detail::FaceStitcher(opts).create(begin, end, meshes);
}
template<unsigned ndim>
template<typename iter_t>
- void MeshSet<ndim>::_init_from_faces(iter_t begin, iter_t end) {
+ void MeshSet<ndim>::_init_from_faces(iter_t begin, iter_t end, const MeshOptions &opts) {
typedef std::unordered_map<const vertex_t *, size_t> map_t;
map_t vmap;
@@ -723,7 +723,7 @@ namespace carve {
} while (e != f->edge);
}
- mesh_t::create(begin, end, meshes);
+ mesh_t::create(begin, end, meshes, opts);
for (size_t i = 0; i < meshes.size(); ++i) {
meshes[i]->meshset = this;
@@ -735,7 +735,8 @@ namespace carve {
template<unsigned ndim>
MeshSet<ndim>::MeshSet(const std::vector<typename MeshSet<ndim>::vertex_t::vector_t> &points,
size_t n_faces,
- const std::vector<int> &face_indices) {
+ const std::vector<int> &face_indices,
+ const MeshOptions &opts) {
vertex_storage.reserve(points.size());
std::vector<face_t *> faces;
faces.reserve(n_faces);
@@ -755,7 +756,7 @@ namespace carve {
faces.push_back(new face_t(v.begin(), v.end()));
}
CARVE_ASSERT(p == face_indices.size());
- mesh_t::create(faces.begin(), faces.end(), meshes);
+ mesh_t::create(faces.begin(), faces.end(), meshes, opts);
for (size_t i = 0; i < meshes.size(); ++i) {
meshes[i]->meshset = this;
@@ -765,15 +766,15 @@ namespace carve {
template<unsigned ndim>
- MeshSet<ndim>::MeshSet(std::vector<face_t *> &faces) {
- _init_from_faces(faces.begin(), faces.end());
+ MeshSet<ndim>::MeshSet(std::vector<face_t *> &faces, const MeshOptions &opts) {
+ _init_from_faces(faces.begin(), faces.end(), opts);
}
template<unsigned ndim>
- MeshSet<ndim>::MeshSet(std::list<face_t *> &faces) {
- _init_from_faces(faces.begin(), faces.end());
+ MeshSet<ndim>::MeshSet(std::list<face_t *> &faces, const MeshOptions &opts) {
+ _init_from_faces(faces.begin(), faces.end(), opts);
}
@@ -1010,5 +1011,41 @@ namespace carve {
vertex_storage.swap(vout);
}
+
+
+ template<unsigned ndim>
+ void MeshSet<ndim>::separateMeshes() {
+ size_t n;
+ typedef std::unordered_map<std::pair<mesh_t *, vertex_t *>, vertex_t *> vmap_t;
+ vmap_t vmap;
+ typename vmap_t::iterator vmap_iter;
+
+ for (face_iter i = faceBegin(); i != faceEnd(); ++i) {
+ face_t *f = *i;
+ for (typename face_t::edge_iter_t j = f->begin(); j != f->end(); ++j) {
+ edge_t &e = *j;
+ vmap[std::make_pair(f->mesh, e.vert)] = e.vert;
+ }
+ }
+
+ std::vector<vertex_t> vout;
+ vout.reserve(vmap.size());
+
+ for (n = 0, vmap_iter = vmap.begin(); vmap_iter != vmap.end(); ++vmap_iter, ++n) {
+ vout.push_back(*(*vmap_iter).second);
+ (*vmap_iter).second = & vout.back();
+ }
+
+ for (face_iter i = faceBegin(); i != faceEnd(); ++i) {
+ face_t *f = *i;
+ for (typename face_t::edge_iter_t j = f->begin(); j != f->end(); ++j) {
+ edge_t &e = *j;
+ e.vert = vmap[std::make_pair(f->mesh, e.vert)];
+ }
+ }
+
+ vertex_storage.swap(vout);
+ }
+
}
}
diff --git a/extern/carve/lib/intersect.cpp b/extern/carve/lib/intersect.cpp
index b92dbcfe24c..b468e4addc7 100644
--- a/extern/carve/lib/intersect.cpp
+++ b/extern/carve/lib/intersect.cpp
@@ -1320,8 +1320,8 @@ void carve::csg::CSG::calc(meshset_t *a,
}
#endif
- checkFaceLoopIntegrity(a_face_loops);
- checkFaceLoopIntegrity(b_face_loops);
+ // checkFaceLoopIntegrity(a_face_loops);
+ // checkFaceLoopIntegrity(b_face_loops);
#if defined(CARVE_DEBUG)
std::cerr << "classify" << std::endl;
diff --git a/extern/carve/lib/intersect_face_division.cpp b/extern/carve/lib/intersect_face_division.cpp
index c5d5d8c5152..3b771bc8f3e 100644
--- a/extern/carve/lib/intersect_face_division.cpp
+++ b/extern/carve/lib/intersect_face_division.cpp
@@ -1110,8 +1110,7 @@ namespace {
}
// copy up to the end of the path.
- if (pos < e1_1)
- std::copy(base_loop.begin() + pos, base_loop.begin() + e1_1, std::back_inserter(out));
+ std::copy(base_loop.begin() + pos, base_loop.begin() + e1_1, std::back_inserter(out));
CARVE_ASSERT(base_loop[e1_1] == p1.back());
std::copy(p1.rbegin(), p1.rend() - 1, std::back_inserter(out));
diff --git a/extern/carve/lib/mesh.cpp b/extern/carve/lib/mesh.cpp
index 55ab893c10a..ae91b385d44 100644
--- a/extern/carve/lib/mesh.cpp
+++ b/extern/carve/lib/mesh.cpp
@@ -243,15 +243,20 @@ namespace carve {
bool FaceStitcher::EdgeOrderData::Cmp::operator()(const EdgeOrderData &a, const EdgeOrderData &b) const {
int v = carve::geom3d::compareAngles(edge_dir, base_dir, a.face_dir, b.face_dir);
- double da = carve::geom3d::antiClockwiseAngle(base_dir, a.face_dir, edge_dir);
- double db = carve::geom3d::antiClockwiseAngle(base_dir, b.face_dir, edge_dir);
- int v0 = v;
- v = 0;
- if (da < db) v = -1;
- if (db < da) v = +1;
- if (v0 != v) {
- std::cerr << "v0= " << v0 << " v= " << v << " da= " << da << " db= " << db << " " << edge_dir << " " << base_dir << " " << a.face_dir << b.face_dir << std::endl;
+
+#if defined(CARVE_DEBUG)
+ {
+ double da = carve::geom3d::antiClockwiseAngle(base_dir, a.face_dir, edge_dir);
+ double db = carve::geom3d::antiClockwiseAngle(base_dir, b.face_dir, edge_dir);
+ int v_cmp = 0;
+ if (da < db) v_cmp = -1;
+ if (db < da) v_cmp = +1;
+ if (v_cmp != v) {
+ std::cerr << "v= " << v << " v_cmp= " << v_cmp << " da= " << da << " db= " << db << " edge_dir=" << edge_dir << " base_dir=" << base_dir << " a=" << a.face_dir << " b=" << b.face_dir << std::endl;
+ }
}
+#endif
+
if (v < 0) return true;
if (v == 0) {
if (a.is_reversed && !b.is_reversed) return true;
@@ -327,9 +332,14 @@ namespace carve {
CARVE_ASSERT(erev[0][i]->v2() == erev[j][i]->v2());
}
- std::sort(result[i].begin(),
- result[i].end(),
- EdgeOrderData::Cmp(base->v2()->v - base->v1()->v, result[i][0].face_dir));
+ geom::vector<3> sort_dir;
+ if (opts.opt_avoid_cavities) {
+ sort_dir = base->v1()->v - base->v2()->v;
+ } else {
+ sort_dir = base->v2()->v - base->v1()->v;
+ }
+
+ std::sort(result[i].begin(), result[i].end(), EdgeOrderData::Cmp(sort_dir, result[i][0].face_dir));
}
}
@@ -751,11 +761,15 @@ namespace carve {
}
}
}
+
+ FaceStitcher::FaceStitcher(const MeshOptions &_opts) : opts(_opts) {
+ }
}
}
+
// construct a MeshSet from a Polyhedron, maintaining on the
// connectivity information in the Polyhedron.
mesh::MeshSet<3> *meshFromPolyhedron(const poly::Polyhedron *poly, int manifold_id) {
diff --git a/extern/carve/lib/polyhedron.cpp b/extern/carve/lib/polyhedron.cpp
index 93e667ffaf7..43d08b81bfd 100644
--- a/extern/carve/lib/polyhedron.cpp
+++ b/extern/carve/lib/polyhedron.cpp
@@ -233,7 +233,7 @@ namespace carve {
}
std::vector<mesh::Mesh<3> *> meshes;
- mesh::Mesh<3>::create(mesh_faces.begin(), mesh_faces.end(), meshes);
+ mesh::Mesh<3>::create(mesh_faces.begin(), mesh_faces.end(), meshes, mesh::MeshOptions());
mesh::MeshSet<3> *meshset = new mesh::MeshSet<3>(vertex_storage, meshes);
manifold_is_closed.resize(meshset->meshes.size());
diff --git a/extern/carve/patches/series b/extern/carve/patches/series
index 585d90659bd..0b1f731805e 100644
--- a/extern/carve/patches/series
+++ b/extern/carve/patches/series
@@ -1,4 +1,3 @@
-strict_flags.patch
includes.patch
win32.patch
mesh_iterator.patch
diff --git a/extern/carve/patches/strict_flags.patch b/extern/carve/patches/strict_flags.patch
deleted file mode 100644
index c1046b78c5f..00000000000
--- a/extern/carve/patches/strict_flags.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-diff -r 47dfdaff1dd5 include/carve/csg_triangulator.hpp
---- a/include/carve/csg_triangulator.hpp Thu Jan 12 15:49:04 2012 -0500
-+++ b/include/carve/csg_triangulator.hpp Fri Jan 13 03:13:32 2012 +0600
-@@ -174,6 +174,7 @@
-
- double scoreQuad(edge_map_t::iterator i, edge_map_t &edge_map) {
- if (!(*i).second.first || !(*i).second.second) return -1;
-+ return 0;
- }
-
- carve::mesh::MeshSet<3>::face_t *mergeQuad(edge_map_t::iterator i, edge_map_t &edge_map) {
-diff -r 47dfdaff1dd5 lib/selfintersect.cpp
---- a/lib/selfintersect.cpp Thu Jan 12 15:49:04 2012 -0500
-+++ b/lib/selfintersect.cpp Fri Jan 13 03:13:32 2012 +0600
-@@ -465,6 +465,7 @@
-
- // returns true if no intersection, based upon edge^a_i and edge^b_j separating axis.
- bool sat_edge(const vec3 tri_a[3], const vec3 tri_b[3], unsigned i, unsigned j) {
-+ return false;
- }
-
-
diff --git a/extern/libmv/CMakeLists.txt b/extern/libmv/CMakeLists.txt
index 0fc90fdd9b9..a4910d94a37 100644
--- a/extern/libmv/CMakeLists.txt
+++ b/extern/libmv/CMakeLists.txt
@@ -28,14 +28,11 @@
set(INC
.
- ../colamd/Include
third_party/ceres/include
)
set(INC_SYS
../Eigen3
- third_party/ssba
- third_party/ldl/Include
${PNG_INCLUDE_DIR}
${ZLIB_INCLUDE_DIRS}
)
@@ -62,7 +59,6 @@ set(SRC
libmv/simple_pipeline/pipeline.cc
libmv/simple_pipeline/reconstruction.cc
libmv/simple_pipeline/resect.cc
- libmv/simple_pipeline/rigid_registration.cc
libmv/simple_pipeline/tracks.cc
libmv/tracking/brute_region_tracker.cc
libmv/tracking/esm_region_tracker.cc
@@ -83,9 +79,6 @@ set(SRC
third_party/gflags/gflags.cc
third_party/gflags/gflags_completions.cc
third_party/gflags/gflags_reporting.cc
- third_party/ldl/Source/ldl.c
- third_party/ssba/Geometry/v3d_metricbundle.cpp
- third_party/ssba/Math/v3d_optimization.cpp
libmv-capi.h
libmv/base/id_generator.h
@@ -105,6 +98,7 @@ set(SRC
libmv/multiview/homography.h
libmv/multiview/homography_parameterization.h
libmv/multiview/nviewtriangulation.h
+ libmv/multiview/panography.h
libmv/multiview/projection.h
libmv/multiview/resection.h
libmv/multiview/triangulation.h
@@ -123,7 +117,6 @@ set(SRC
libmv/simple_pipeline/pipeline.h
libmv/simple_pipeline/reconstruction.h
libmv/simple_pipeline/resect.h
- libmv/simple_pipeline/rigid_registration.h
libmv/simple_pipeline/tracks.h
libmv/tracking/brute_region_tracker.h
libmv/tracking/esm_region_tracker.h
@@ -143,16 +136,8 @@ set(SRC
third_party/gflags/gflags/gflags.h
third_party/gflags/mutex.h
third_party/gflags/util.h
- third_party/ldl/Include/ldl.h
third_party/msinttypes/inttypes.h
third_party/msinttypes/stdint.h
- third_party/ssba/Geometry/v3d_cameramatrix.h
- third_party/ssba/Geometry/v3d_distortion.h
- third_party/ssba/Geometry/v3d_metricbundle.h
- third_party/ssba/Math/v3d_linear.h
- third_party/ssba/Math/v3d_linear_utils.h
- third_party/ssba/Math/v3d_mathutilities.h
- third_party/ssba/Math/v3d_optimization.h
)
if(WIN32)
@@ -230,7 +215,6 @@ else()
endif()
add_definitions(
- -DV3DLIB_ENABLE_SUITESPARSE
-DGOOGLE_GLOG_DLL_DECL=
)
diff --git a/extern/libmv/ChangeLog b/extern/libmv/ChangeLog
index c52d5456c32..a4f25f83a1c 100644
--- a/extern/libmv/ChangeLog
+++ b/extern/libmv/ChangeLog
@@ -1,3 +1,256 @@
+commit 473996468a4e67e7c860169181a4ff31ce9b8c80
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Fri Mar 1 17:44:54 2013 +0600
+
+ Fixed incorrect order of arguments passing
+ to EXPECT_EQ in keyframe selection tests.
+
+commit d38ebb74693fdf5b8f0fecf62a3d8c9c53b0b84a
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Fri Mar 1 17:40:38 2013 +0600
+
+ Modal (aka tripod) solver rework
+
+ Several major things are done in this commit:
+
+ - First of all, logic of modal solver was changed.
+ We do not rely on only minimizer to take care of
+ guessing rotation for frame, but we're using
+ analytical rotation computation for point clouds
+ to obtain initial rotation.
+
+ Then this rotation is being refined using Ceres
+ minimizer and now instead of minimizing average
+ distance between points of point of two clouds,
+ minimization of reprojection error of point
+ cloud onto frame happens.
+
+ This gives quite a bit of precision improvement.
+
+ - Second bigger improvement here is using bundle
+ adjustment for a result of first step when we're
+ only estimating rotation between neighbor images
+ and reprojecting markers.
+
+ This averages error across the image sequence
+ avoiding error accumulation. Also, this will
+ tweak bundles themselves a bit for better match.
+
+ - And last bigger improvement here is support of
+ camera intrinsics refirenment.
+
+ This allowed to significantly improve solution
+ for real-life footage and results after such
+ refining are much more usable than it were before.
+
+ Thanks to Keir for the help and code review!
+
+commit 5d6c2e7a27bdd1a1b23bf289d70a9b8f62514c9a
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Fri Mar 1 17:37:35 2013 +0600
+
+ Increase verbosity level for reprojected markers info
+
+ This information is useful, but in cases when you, say,
+ working on a bundler it's annoying to scroll all the
+ information up.
+
+commit ac252bb1250b3028b9c94736b644e7ab4e7b14b8
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Fri Mar 1 17:36:19 2013 +0600
+
+ Move radial distortion code to own templated function
+
+ This shall not lead to any functional changes, just
+ avoids radial distortion code duplicated in camera
+ intrinsics and bundling code.
+
+ For fancier bundle adjustment support of different
+ distortion models this is not actually enough and
+ would need to make some bigger changes, but this
+ changes makes code a bit easier to maintain already.
+
+commit c253b794612dd529e1d3a9bd7a7c41c32c9a9abb
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Fri Mar 1 17:33:27 2013 +0600
+
+ Use threaded cost function, jacobian and linear solver
+ computation, so bundling is as fast as it could be with
+ current parameter block structure.
+
+commit 931fe37a10212b91b525d4f6eb753990a338b471
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Fri Mar 1 17:29:21 2013 +0600
+
+ Fixed comment for euclidean bundling,
+ which is now supports raidal bundling independently
+ from other intrinsics.
+
+commit 217d8e6edc3de1a853fb84275d2d2dd898e7529c
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Tue Feb 26 18:19:01 2013 +0600
+
+ Allow K1,K2 refirement combination
+
+ It is now possible to refine only radial distortion
+ with new Ceres based bundler and this new combination
+ is already used in Blender.
+
+commit d8850addc944d400f7a9c358396c437d9e4acc70
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Tue Feb 26 18:17:09 2013 +0600
+
+ Switch euclidean intersection code to use Ceres
+
+ Would not expect any significant changes in solver
+ behavior, but it could be more accurate in some cases.
+
+ Switching projective intersection to ceres is marked
+ as a TODO for now.
+
+commit 6990b7946ec96b3cb2dcfc8a1beaaba9538b0802
+Author: Keir Mierle <mierle@gmail.com>
+Date: Mon Feb 25 20:00:48 2013 +0000
+
+ Switch motion tracker bundle adjustment to Ceres.
+
+ Patch originally written by me, then finished by Sergey. Big
+ thanks to Sergey for troopering through and fixing the many issues
+ with my original (not compilable) patch.
+
+ The Ceres implementation uses 2 parameter blocks for each camera
+ (1 for rotation and 1 for translation), 1 parameter block for
+ common intrinsics (focal length etc) and 1 parameter block for
+ each track (e.g. bundle or 3D point).
+
+ We turn on some fancy optimizer options to get better performance,
+ in particular:
+
+ options.preconditioner_type = ceres::SCHUR_JACOBI;
+ options.linear_solver_type = ceres::ITERATIVE_SCHUR;
+ options.use_inner_iterations = true;
+ options.use_nonmonotonic_steps = true;
+ options.max_num_iterations = 100;
+
+ Special thanks to Sameer Agarwal of Ceres fame for splitting out
+ the SCHUR_JACOBI preconditioner so that it didn't depend on
+ CHOLMOD. Previously we could not use that preconditioner in
+ Blender because CHOLMOD is too large of a dependency for Blender.
+
+ BundleIntrinsicsLogMessage:
+ - Moved bunch of if(foo) LG << "bar" into this function, to make
+ EuclideanBundleCommonIntrinsics a little bit easier to follow.
+
+ EuclideanBundle:
+ - Fix RMSE logging.
+
+commit 1696342954614b54133780d74d6ee0fbcbe224f0
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Tue Feb 26 18:10:33 2013 +0600
+
+ Upgrade ceres to latest upstream version
+
+ This is needed because of some features of new Ceres
+ for further development.
+
+commit 575336f794841ada90aacd783285014081b8318c
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Mon Jan 7 15:58:40 2013 +0600
+
+ Fixed for keyframe selection
+
+ - Calculate residuals for GRIC in pixel space rather than
+ in normalized space.
+
+ This seems to be how it's intended to be used.
+
+ Algebraic H and F will still use normalized coordinates which
+ are more stable, after this matrices are converted to pixel
+ space and Ceres refinement happens in pixel space.
+
+ - Standard deviation calculation was wrong in GRIC. It shouldn't
+ be deviation of residuals, but as per Torr it should be deviation
+ of measurement error, which is constant (in our case 0.1)
+
+ Not sure if using squared cost function is correct for GRIC,
+ but cost function is indeed squared and in most papers cost
+ function is used for GRIC. After some further tests we could
+ switch GRIC residuals to non-squared distance.
+
+ - Bring back rho part of GRIC, in unit tests it doesn't make
+ sense whether it's enabled or not, lets see how it'll behave
+ in real-life footage.
+
+ - Added one more unit test based on elevator scene and manual
+ keyframe selection.
+
+commit 24117f3c3fc5531beb6497d79bb6f1780a998081
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Sun Jan 6 19:07:06 2013 +0600
+
+ Added test for keyframe selection based on manual selection
+
+ Additional changes:
+
+ - Reduce minimal correspondence to match real-world manually
+ tracked footage
+
+ - Returned back squares to SymmetricEpipolarDistance and
+ SymmetricGeometricDistance -- this is actually a cost
+ functions, not distances and they shall be squared.
+
+commit 770eb0293b881c4c419c587a6cdb062c47ab6e44
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Fri Dec 21 00:43:30 2012 +0600
+
+ Improvements for keyframe selection
+
+ - Changed main keyframe selection cycle, so in cases there're no
+ more next keyframes for current keyframe could be found in the
+ image sequence, current keyframe would be moved forward and
+ search continues.
+
+ This helps in cases when there's poor motion in the beginning
+ of the sequence, then markers becomes occluded. There could be
+ good keyframes in the middle of the shot still.
+
+ - Extended keyframe_selection_test with real world cases.
+
+ - Moved correspondences constraint to the top, so no H/F estimation
+ happens if there's bad correspondence. Makes algorithm go a bit
+ faster.
+
+ Strangely, but using non-squared distances makes neighbor frames
+ test fail, using squared distances makes this tests pass.
+
+ However, using non-squared distances seems to be working better
+ in real tests i've been doing. So this requires more investigation/
+
+commit 7415c62fbda36c5bd1c291bc94d535a66da896d0
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Thu Dec 20 18:46:09 2012 +0600
+
+ Cosmetic change to correspondences reports in keyframe selection
+
+commit ceaf80c987ec0338e7e83965bc808411453eb755
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Thu Dec 20 18:08:03 2012 +0600
+
+ Various fixes:
+
+ - That was a typo in symmetric geometric cost functor, which
+ computed inverse distance in a wrong way.
+
+ - Fixed compilation of unit tests
+
+ - Added simple test for keyframe selection. Currently only
+ covers case that neighbor frames with only translation
+ (homography should be better than fundamental) are not
+ considered a keyframes.
+
+ Still need to be investigated why it only works if tracks
+ are in pixel space and why doesn't work in normalized space.
+
commit cfabdfe48df2add3d1f30cf4370efd0b31990ab0
Author: Sergey Sharybin <sergey.vfx@gmail.com>
Date: Thu Dec 20 05:46:53 2012 +0600
@@ -545,180 +798,3 @@ Date: Thu Apr 12 13:56:02 2012 +0600
It projects markers onto sphere and uses rigid registration of rotation to
find rotation angles which makes bundles from previous and current frame be
as closest as it's possible.
-
-commit fa3842e472e3b9c789e47bf6d8f592aa40a84f16
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Thu Apr 12 12:32:48 2012 +0600
-
- implementation of some basic algorithms for point cloud orientation:
-
- - Implementation of rigid registration algorithm which searches transformation
- form one point cloud to another assuming that points in this clouds are
- already paired (points with the same index in different clouds belongs to
- the same pair) which minimizes average distance between points in pairs.
-
- Algorithm uses Levenberg-Marquardt solver to find such transformation.
-
- Supports registration of rotation-scale-transform (which is probably most
- common usage) and rotation only (which might be useful for basic modal
- tripod solver).
-
- - Implementation of Iterative-Point-Clouds algorithm which searches
- transformation from one arbitrary point cloud to another making
- points as closest to each other as possible.
-
- This algorithm doesn't require points be initially paired, but for
- good result clouds should have rough initial orientation. If they're
- arbitrary oriented from the very beginning, algorithm might fail
- producing good resold.
-
- Iteration is based on building pairs of closest to each other points
- and registering rigid transformation between them which incrementally
- constructs final result.
-
- TODO: building pairs might be speedup a lot using data structures like
- AABB trees, K-D trees or so.
-
-commit 9618d9a1d48bb3c28da605d9027f57a74f462785
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Wed Apr 11 14:17:14 2012 +0600
-
- Added configuration file for glog to compile smooth on Hurd platform.
-
- Patch by Pino Toscano <pino@debian.org>, thanks!
-
-commit 63b2bd20237c8599fa73ce42556e4fb99b9f7cca
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Thu Mar 22 17:03:34 2012 +0600
-
- Trackers refactoring:
- - Deduplicate pattern sampling used in esm and lmicklt trackers
- and move SamplePattern to image/sample.h
- - Move computation of Pearson product-moment correlation into
- own function in new file image/correlation.h so all trackers
- can use it to check final correlation.
- - Remove SAD tracker. It's almost the same as brute tracker,
- with only two differences:
- 1. It does brute search of affine transformation which in some cases
- helps to track rotating features
- 2. It didn't use common tracker api which probably gave some speed
- advantage, but lead to a real headache to use it together with
- other trackers leading to duplicated code in 3d-party software.
-
-commit 9fe49c32e990f28c83f2bbb1d18057aed8879af7
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Mon Mar 12 09:36:15 2012 +0600
-
- Code cleanup: convert line endings to Unix style (native on my platform) so it
- wouldn't confuse other versioning systems used for project where libmv is bundled to,
-
- Also change mode to +x for glog's windows-related script.
-
-commit fe74ae2b53769389b0ed9d7e604c8e60be81077d
-Author: Sergey I. Sharybin <g.ulairi@gmail.com>
-Date: Sun Mar 11 20:34:15 2012 +0600
-
- Replace "third_party/glog/src/glog/logging.h" with <glog/logging.h>
-
- It was needed because of how build systems is setup in Blender but think
- this will be helpful change for other applications too because it makes
- it's easier to move libraries around and even use libraries installed
- on the operation system.
-
-commit 37fc726701479f2d321d6af878fa93f3176278d5
-Author: Sergey I. Sharybin <g.ulairi@gmail.com>
-Date: Sun Mar 11 19:27:41 2012 +0600
-
- Upgrade gflags and glog libraries - stage 2 (final)
-
- Changes to upstream code which are needed to make libmv compile smooth on all platforms
-
- * Replace <gflags/gflags.h> with "third_party/gflags/gflags/gflags.h" which is easier
- to setup things in libmv and also helps with setting up building libmv into
- external applications.
- * Replace "glog/logging.h" and "glog/logging.h" with <glog/logging.h> and <glog/logging.h>
- which is needed on Windows platform because otherwise files like logging.cc will be using
- relative path which points to headers used by linux instead of headers need to be used
- on Windows.
- * Replace _asm int 3 with __debugbreak(). Such assembler code is obsolete and doesn't work
- with 64bit versions of MSVC compilers.
- * Do not use stacktrace for MinGW and FreeBSD because it leads into issues accessing
- some specific data on this platforms.
- * Define HAVE_LIB_GFLAGS for Windows builds.
- * Do not define __declspec(dllimport) for MinGW platforms.
- * Setup proper includes and datatypes for int32, uint32, int64 and uint64 for MinGW
- * Do not define va_copy for MinGW platforms (it's already defined there).
- * Patch localtime_r to be working fine with MinGW, disable strerror_r for MinGW because
- of lack of needed functions.
-
-commit 8ed07abfa49d1e0511752021c972e0715e5a1383
-Author: Sergey I. Sharybin <g.ulairi@gmail.com>
-Date: Sun Mar 11 19:06:33 2012 +0600
-
- Upgrade gflags and glog libraries - stage 1
-
- This commit copies sources from latest original release of gflags and glog
- over currently bundled versions of this libraries without any modifications.
-
- This revision can't b compiled, all needed changes to make new libraries working
- fine will be done with next commit to make it clear which changes were necessary
- for easier bundling further newer version and extract patches and put them to
- gflags/glog upstream repo.
-
- Such upgrade of libraries is needed to make it able to compile libmv
- with clang compilers. Currently used versions:
-
- - gflags is version 2.0
- - glog is version 0.3.2
-
-commit 75b9af405964ff2c7d3f0a44500e27e63b37c91b
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Feb 17 23:29:11 2012 +0600
-
- _USE_MATH_DEFINES is needed to define constants like M_E when building with msvc
- Occasionally was removed, but now added comment about this so hopefully it
- wouldn't removed again.
-
-commit f85b1232a9b929f69443b5eed6e7a39908cd6551
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Feb 17 21:34:40 2012 +0600
-
- Picky edit: corrected mode for ssba readme file.
-
-commit f8c2b223f01551fd81a85f6d5221646165147035
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Feb 17 21:32:05 2012 +0600
-
- Picky edits: corrected EOL
-
-commit 3f2a4205ec5adadcdfa306b161c705c868a7be93
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Feb 17 21:30:07 2012 +0600
-
- Fixed incorrect access to ucontext on linux. Caused by incorrect merge conflict resolve.
-
-commit d360a21a5aa125cf9e83dd26b302508688ff7007
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Feb 17 20:54:13 2012 +0600
-
- More Windows -> Unix EOL conversions
-
-commit 18aeda58bec9556140ba617724e31ada6f5b67c0
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Feb 17 20:15:42 2012 +0600
-
- Looks like this debug output was removed accidentally.
-
-commit 189dc0cacdee3c1eab68c43263ecb038ed244c09
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Feb 17 20:11:56 2012 +0600
-
- Made V3D verbose again by default
-
-commit 8b3422d3eec5e450d76243886bf07fb0a3e83a81
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Feb 17 20:08:01 2012 +0600
-
- SAD tracker now can deal with pattern size any size,
- Very quick implementation came from Blender before Hybrid tracker was added.
- Better to be replaced with brute tracker.
diff --git a/extern/libmv/SConscript b/extern/libmv/SConscript
index 8fd8c566e4d..d0015db42d7 100644
--- a/extern/libmv/SConscript
+++ b/extern/libmv/SConscript
@@ -11,7 +11,6 @@ Import('env')
defs = []
-defs.append('V3DLIB_ENABLE_SUITESPARSE')
defs.append('GOOGLE_GLOG_DLL_DECL=')
src = env.Glob("*.cpp")
@@ -22,9 +21,6 @@ src += env.Glob('libmv/simple_pipeline/*.cc')
src += env.Glob('libmv/tracking/*.cc')
src += env.Glob('third_party/fast/*.c')
src += env.Glob('third_party/gflags/*.cc')
-src += env.Glob('third_party/ldl/Source/*.c')
-src += env.Glob('third_party/ssba/Geometry/*.cpp')
-src += env.Glob('third_party/ssba/Math/*.cpp')
incs = '. ../Eigen3 third_party/ceres/include'
incs += ' ' + env['BF_PNG_INC']
@@ -41,8 +37,6 @@ else:
src += env.Glob("third_party/glog/src/*.cc")
incs += ' ./third_party/glog/src'
-incs += ' ./third_party/ssba ./third_party/ldl/Include ../colamd/Include'
-
env.BlenderLib ( libname = 'extern_libmv', sources=src, includes=Split(incs), defines=defs, libtype=['extern', 'player'], priority=[20,137] )
SConscript(['third_party/SConscript'])
diff --git a/extern/libmv/bundle.sh b/extern/libmv/bundle.sh
index 53487cf020e..a9edfde55bf 100755
--- a/extern/libmv/bundle.sh
+++ b/extern/libmv/bundle.sh
@@ -124,14 +124,11 @@ cat > CMakeLists.txt << EOF
set(INC
.
- ../colamd/Include
third_party/ceres/include
)
set(INC_SYS
../Eigen3
- third_party/ssba
- third_party/ldl/Include
\${PNG_INCLUDE_DIR}
\${ZLIB_INCLUDE_DIRS}
)
@@ -197,7 +194,6 @@ ${third_glog_headers}
endif()
add_definitions(
- -DV3DLIB_ENABLE_SUITESPARSE
-DGOOGLE_GLOG_DLL_DECL=
)
@@ -220,7 +216,6 @@ Import('env')
defs = []
-defs.append('V3DLIB_ENABLE_SUITESPARSE')
defs.append('GOOGLE_GLOG_DLL_DECL=')
src = env.Glob("*.cpp")
@@ -241,8 +236,6 @@ else:
src += env.Glob("third_party/glog/src/*.cc")
incs += ' ./third_party/glog/src'
-incs += ' ./third_party/ssba ./third_party/ldl/Include ../colamd/Include'
-
env.BlenderLib ( libname = 'extern_libmv', sources=src, includes=Split(incs), defines=defs, libtype=['extern', 'player'], priority=[20,137] )
SConscript(['third_party/SConscript'])
diff --git a/extern/libmv/files.txt b/extern/libmv/files.txt
index 22c5226adbe..16afdb36371 100644
--- a/extern/libmv/files.txt
+++ b/extern/libmv/files.txt
@@ -21,6 +21,7 @@ libmv/multiview/homography.cc
libmv/multiview/homography.h
libmv/multiview/homography_parameterization.h
libmv/multiview/nviewtriangulation.h
+libmv/multiview/panography.h
libmv/multiview/projection.cc
libmv/multiview/projection.h
libmv/multiview/resection.h
@@ -53,8 +54,6 @@ libmv/simple_pipeline/reconstruction.cc
libmv/simple_pipeline/reconstruction.h
libmv/simple_pipeline/resect.cc
libmv/simple_pipeline/resect.h
-libmv/simple_pipeline/rigid_registration.cc
-libmv/simple_pipeline/rigid_registration.h
libmv/simple_pipeline/tracks.cc
libmv/simple_pipeline/tracks.h
libmv/tracking/brute_region_tracker.cc
@@ -142,25 +141,6 @@ third_party/glog/src/windows/glog/vlog_is_on.h
third_party/glog/src/windows/port.cc
third_party/glog/src/windows/port.h
third_party/glog/src/windows/preprocess.sh
-third_party/ldl/CMakeLists.txt
-third_party/ldl/Doc/ChangeLog
-third_party/ldl/Doc/lesser.txt
-third_party/ldl/Include/ldl.h
-third_party/ldl/README.libmv
-third_party/ldl/README.txt
-third_party/ldl/Source/ldl.c
third_party/msinttypes/inttypes.h
third_party/msinttypes/README.libmv
third_party/msinttypes/stdint.h
-third_party/ssba/COPYING.TXT
-third_party/ssba/Geometry/v3d_cameramatrix.h
-third_party/ssba/Geometry/v3d_distortion.h
-third_party/ssba/Geometry/v3d_metricbundle.cpp
-third_party/ssba/Geometry/v3d_metricbundle.h
-third_party/ssba/Math/v3d_linear.h
-third_party/ssba/Math/v3d_linear_utils.h
-third_party/ssba/Math/v3d_mathutilities.h
-third_party/ssba/Math/v3d_optimization.cpp
-third_party/ssba/Math/v3d_optimization.h
-third_party/ssba/README.libmv
-third_party/ssba/README.TXT
diff --git a/extern/libmv/libmv-capi.cpp b/extern/libmv/libmv-capi.cpp
index 8e483abd386..a85c3268b16 100644
--- a/extern/libmv/libmv-capi.cpp
+++ b/extern/libmv/libmv-capi.cpp
@@ -34,21 +34,8 @@
#include "libmv-capi.h"
-#include "third_party/gflags/gflags/gflags.h"
-#include "glog/logging.h"
#include "libmv/logging/logging.h"
-#include "Math/v3d_optimization.h"
-
-#include "libmv/numeric/numeric.h"
-
-#include "libmv/tracking/esm_region_tracker.h"
-#include "libmv/tracking/brute_region_tracker.h"
-#include "libmv/tracking/hybrid_region_tracker.h"
-#include "libmv/tracking/klt_region_tracker.h"
-#include "libmv/tracking/trklt_region_tracker.h"
-#include "libmv/tracking/lmicklt_region_tracker.h"
-#include "libmv/tracking/pyramid_region_tracker.h"
#include "libmv/tracking/track_region.h"
#include "libmv/simple_pipeline/callbacks.h"
@@ -58,7 +45,6 @@
#include "libmv/simple_pipeline/detect.h"
#include "libmv/simple_pipeline/pipeline.h"
#include "libmv/simple_pipeline/camera_intrinsics.h"
-#include "libmv/simple_pipeline/rigid_registration.h"
#include "libmv/simple_pipeline/modal_solver.h"
#include <stdlib.h>
@@ -96,7 +82,6 @@ void libmv_initLogging(const char *argv0)
google::SetCommandLineOption("v", "0");
google::SetCommandLineOption("stderrthreshold", "7");
google::SetCommandLineOption("minloglevel", "7");
- V3D::optimizerVerbosenessLevel = 0;
}
void libmv_startDebugLogging(void)
@@ -105,7 +90,6 @@ void libmv_startDebugLogging(void)
google::SetCommandLineOption("v", "2");
google::SetCommandLineOption("stderrthreshold", "1");
google::SetCommandLineOption("minloglevel", "0");
- V3D::optimizerVerbosenessLevel = 1;
}
void libmv_setLoggingVerbosity(int verbosity)
@@ -114,54 +98,9 @@ void libmv_setLoggingVerbosity(int verbosity)
snprintf(val, sizeof(val), "%d", verbosity);
google::SetCommandLineOption("v", val);
- V3D::optimizerVerbosenessLevel = verbosity;
-}
-
-/* ************ RegionTracker ************ */
-
-libmv_RegionTracker *libmv_pyramidRegionTrackerNew(int max_iterations, int pyramid_level, int half_window_size, double minimum_correlation)
-{
- libmv::EsmRegionTracker *esm_region_tracker = new libmv::EsmRegionTracker;
- esm_region_tracker->half_window_size = half_window_size;
- esm_region_tracker->max_iterations = max_iterations;
- esm_region_tracker->min_determinant = 1e-4;
- esm_region_tracker->minimum_correlation = minimum_correlation;
-
- libmv::PyramidRegionTracker *pyramid_region_tracker =
- new libmv::PyramidRegionTracker(esm_region_tracker, pyramid_level);
-
- return (libmv_RegionTracker *)pyramid_region_tracker;
-}
-
-libmv_RegionTracker *libmv_hybridRegionTrackerNew(int max_iterations, int half_window_size, double minimum_correlation)
-{
- libmv::EsmRegionTracker *esm_region_tracker = new libmv::EsmRegionTracker;
- esm_region_tracker->half_window_size = half_window_size;
- esm_region_tracker->max_iterations = max_iterations;
- esm_region_tracker->min_determinant = 1e-4;
- esm_region_tracker->minimum_correlation = minimum_correlation;
-
- libmv::BruteRegionTracker *brute_region_tracker = new libmv::BruteRegionTracker;
- brute_region_tracker->half_window_size = half_window_size;
-
- /* do not use correlation check for brute checker itself,
- * this check will happen in esm tracker */
- brute_region_tracker->minimum_correlation = 0.0;
-
- libmv::HybridRegionTracker *hybrid_region_tracker =
- new libmv::HybridRegionTracker(brute_region_tracker, esm_region_tracker);
-
- return (libmv_RegionTracker *)hybrid_region_tracker;
}
-libmv_RegionTracker *libmv_bruteRegionTrackerNew(int half_window_size, double minimum_correlation)
-{
- libmv::BruteRegionTracker *brute_region_tracker = new libmv::BruteRegionTracker;
- brute_region_tracker->half_window_size = half_window_size;
- brute_region_tracker->minimum_correlation = minimum_correlation;
-
- return (libmv_RegionTracker *)brute_region_tracker;
-}
+/* ************ Utility ************ */
static void floatBufToImage(const float *buf, int width, int height, int channels, libmv::FloatImage *image)
{
@@ -303,7 +242,7 @@ static void saveBytesImage(const char *prefix, unsigned char *data, int width, i
}
{
- static int a= 0;
+ static int a = 0;
char buf[128];
snprintf(buf, sizeof(buf), "%s_%02d.png", prefix, ++a);
savePNGImage(row_pointers, width, height, 8, PNG_COLOR_TYPE_RGBA, buf);
@@ -316,43 +255,6 @@ static void saveBytesImage(const char *prefix, unsigned char *data, int width, i
}
#endif
-int libmv_regionTrackerTrack(libmv_RegionTracker *libmv_tracker, const float *ima1, const float *ima2,
- int width, int height, double x1, double y1, double *x2, double *y2)
-{
- libmv::RegionTracker *region_tracker = (libmv::RegionTracker *)libmv_tracker;
- libmv::FloatImage old_patch, new_patch;
-
- floatBufToImage(ima1, width, height, 1, &old_patch);
- floatBufToImage(ima2, width, height, 1, &new_patch);
-
-#if !defined(DUMP_FAILURE) && !defined(DUMP_ALWAYS)
- return region_tracker->Track(old_patch, new_patch, x1, y1, x2, y2);
-#else
- {
- /* double sx2 = *x2, sy2 = *y2; */
- int result = region_tracker->Track(old_patch, new_patch, x1, y1, x2, y2);
-
-#if defined(DUMP_ALWAYS)
- {
-#else
- if (!result) {
-#endif
- saveImage("old_patch", old_patch, x1, y1);
- saveImage("new_patch", new_patch, *x2, *y2);
- }
-
- return result;
- }
-#endif
-}
-
-void libmv_regionTrackerDestroy(libmv_RegionTracker *libmv_tracker)
-{
- libmv::RegionTracker *region_tracker= (libmv::RegionTracker *)libmv_tracker;
-
- delete region_tracker;
-}
-
/* ************ Planar tracker ************ */
/* TrackRegion (new planar tracker) */
@@ -523,12 +425,15 @@ int libmv_refineParametersAreValid(int parameters) {
LIBMV_REFINE_RADIAL_DISTORTION_K1 |
LIBMV_REFINE_RADIAL_DISTORTION_K2)) ||
(parameters == (LIBMV_REFINE_FOCAL_LENGTH |
- LIBMV_REFINE_RADIAL_DISTORTION_K1));
+ LIBMV_REFINE_RADIAL_DISTORTION_K1)) ||
+ (parameters == (LIBMV_REFINE_RADIAL_DISTORTION_K1 |
+ LIBMV_REFINE_RADIAL_DISTORTION_K2));
}
static void libmv_solveRefineIntrinsics(libmv::Tracks *tracks, libmv::CameraIntrinsics *intrinsics,
libmv::EuclideanReconstruction *reconstruction, int refine_intrinsics,
- reconstruct_progress_update_cb progress_update_callback, void *callback_customdata)
+ reconstruct_progress_update_cb progress_update_callback, void *callback_customdata,
+ int bundle_constraints = libmv::BUNDLE_NO_CONSTRAINTS)
{
/* only a few combinations are supported but trust the caller */
int libmv_refine_flags = 0;
@@ -549,43 +454,84 @@ static void libmv_solveRefineIntrinsics(libmv::Tracks *tracks, libmv::CameraIntr
progress_update_callback(callback_customdata, 1.0, "Refining solution");
libmv::EuclideanBundleCommonIntrinsics(*(libmv::Tracks *)tracks, libmv_refine_flags,
- reconstruction, intrinsics);
+ reconstruction, intrinsics, bundle_constraints);
}
-libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyframe1, int keyframe2,
- int refine_intrinsics, double focal_length, double principal_x, double principal_y,
- double k1, double k2, double k3, struct libmv_reconstructionOptions *options,
- reconstruct_progress_update_cb progress_update_callback, void *callback_customdata)
+static void cameraIntrinsicsFromOptions(libmv::CameraIntrinsics *camera_intrinsics,
+ libmv_cameraIntrinsicsOptions *camera_intrinsics_options)
+{
+ camera_intrinsics->SetFocalLength(camera_intrinsics_options->focal_length,
+ camera_intrinsics_options->focal_length);
+
+ camera_intrinsics->SetPrincipalPoint(camera_intrinsics_options->principal_point_x,
+ camera_intrinsics_options->principal_point_y);
+
+ camera_intrinsics->SetRadialDistortion(camera_intrinsics_options->k1,
+ camera_intrinsics_options->k2,
+ camera_intrinsics_options->k3);
+
+ camera_intrinsics->SetImageSize(camera_intrinsics_options->image_width,
+ camera_intrinsics_options->image_height);
+}
+
+static libmv::Tracks getNormalizedTracks(libmv::Tracks *tracks, libmv::CameraIntrinsics *camera_intrinsics)
+{
+ libmv::vector<libmv::Marker> markers = tracks->AllMarkers();
+
+ for (int i = 0; i < markers.size(); ++i) {
+ camera_intrinsics->InvertIntrinsics(markers[i].x, markers[i].y,
+ &(markers[i].x), &(markers[i].y));
+ }
+
+ return libmv::Tracks(markers);
+}
+
+static void finishReconstruction(libmv::Tracks *tracks, libmv::CameraIntrinsics *camera_intrinsics,
+ libmv_Reconstruction *libmv_reconstruction,
+ reconstruct_progress_update_cb progress_update_callback,
+ void *callback_customdata)
+{
+ libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
+
+ /* reprojection error calculation */
+ progress_update_callback(callback_customdata, 1.0, "Finishing solution");
+ libmv_reconstruction->tracks = *tracks;
+ libmv_reconstruction->error = libmv::EuclideanReprojectionError(*tracks, *reconstruction, *camera_intrinsics);
+}
+
+libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *libmv_tracks,
+ libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options,
+ libmv_reconstructionOptions *libmv_reconstruction_options,
+ reconstruct_progress_update_cb progress_update_callback,
+ void *callback_customdata)
{
- /* Invert the camera intrinsics. */
- libmv::vector<libmv::Marker> markers = ((libmv::Tracks*)tracks)->AllMarkers();
libmv_Reconstruction *libmv_reconstruction = new libmv_Reconstruction();
+
+ libmv::Tracks *tracks = ((libmv::Tracks *) libmv_tracks);
libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
- libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics;
- libmv::ReconstructionOptions reconstruction_options;
+ libmv::CameraIntrinsics *camera_intrinsics = &libmv_reconstruction->intrinsics;
ReconstructUpdateCallback update_callback =
ReconstructUpdateCallback(progress_update_callback, callback_customdata);
- intrinsics->SetFocalLength(focal_length, focal_length);
- intrinsics->SetPrincipalPoint(principal_x, principal_y);
- intrinsics->SetRadialDistortion(k1, k2, k3);
+ cameraIntrinsicsFromOptions(camera_intrinsics, libmv_camera_intrinsics_options);
- reconstruction_options.success_threshold = options->success_threshold;
- reconstruction_options.use_fallback_reconstruction = options->use_fallback_reconstruction;
+ /* Invert the camera intrinsics */
+ libmv::Tracks normalized_tracks = getNormalizedTracks(tracks, camera_intrinsics);
- for (int i = 0; i < markers.size(); ++i) {
- intrinsics->InvertIntrinsics(markers[i].x,
- markers[i].y,
- &(markers[i].x),
- &(markers[i].y));
- }
+ /* actual reconstruction */
+ libmv::ReconstructionOptions reconstruction_options;
+ reconstruction_options.success_threshold = libmv_reconstruction_options->success_threshold;
+ reconstruction_options.use_fallback_reconstruction = libmv_reconstruction_options->use_fallback_reconstruction;
- libmv::Tracks normalized_tracks(markers);
+ int keyframe1 = libmv_reconstruction_options->keyframe1,
+ keyframe2 = libmv_reconstruction_options->keyframe2;
LG << "frames to init from: " << keyframe1 << " " << keyframe2;
+
libmv::vector<libmv::Marker> keyframe_markers =
normalized_tracks.MarkersForTracksInBothImages(keyframe1, keyframe2);
+
LG << "number of markers for init: " << keyframe_markers.size();
update_callback.invoke(0, "Initial reconstruction");
@@ -595,49 +541,61 @@ libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyfra
libmv::EuclideanCompleteReconstruction(reconstruction_options, normalized_tracks,
reconstruction, &update_callback);
- if (refine_intrinsics) {
- libmv_solveRefineIntrinsics((libmv::Tracks *)tracks, intrinsics, reconstruction,
- refine_intrinsics, progress_update_callback, callback_customdata);
+ /* refinement */
+ if (libmv_reconstruction_options->refine_intrinsics) {
+ libmv_solveRefineIntrinsics((libmv::Tracks *)tracks, camera_intrinsics, reconstruction,
+ libmv_reconstruction_options->refine_intrinsics,
+ progress_update_callback, callback_customdata);
}
- progress_update_callback(callback_customdata, 1.0, "Finishing solution");
- libmv_reconstruction->tracks = *(libmv::Tracks *)tracks;
- libmv_reconstruction->error = libmv::EuclideanReprojectionError(*(libmv::Tracks *)tracks, *reconstruction, *intrinsics);
+ /* finish reconstruction */
+ finishReconstruction(tracks, camera_intrinsics, libmv_reconstruction,
+ progress_update_callback, callback_customdata);
return (libmv_Reconstruction *)libmv_reconstruction;
}
-struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *tracks, double focal_length,
- double principal_x, double principal_y, double k1, double k2, double k3,
- reconstruct_progress_update_cb progress_update_callback, void *callback_customdata)
+struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *libmv_tracks,
+ libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options,
+ libmv_reconstructionOptions *libmv_reconstruction_options,
+ reconstruct_progress_update_cb progress_update_callback,
+ void *callback_customdata)
{
- /* Invert the camera intrinsics. */
- libmv::vector<libmv::Marker> markers = ((libmv::Tracks*)tracks)->AllMarkers();
libmv_Reconstruction *libmv_reconstruction = new libmv_Reconstruction();
+
+ libmv::Tracks *tracks = ((libmv::Tracks *) libmv_tracks);
libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
- libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics;
+ libmv::CameraIntrinsics *camera_intrinsics = &libmv_reconstruction->intrinsics;
ReconstructUpdateCallback update_callback =
ReconstructUpdateCallback(progress_update_callback, callback_customdata);
- intrinsics->SetFocalLength(focal_length, focal_length);
- intrinsics->SetPrincipalPoint(principal_x, principal_y);
- intrinsics->SetRadialDistortion(k1, k2, k3);
-
- for (int i = 0; i < markers.size(); ++i) {
- intrinsics->InvertIntrinsics(markers[i].x,
- markers[i].y,
- &(markers[i].x),
- &(markers[i].y));
- }
+ cameraIntrinsicsFromOptions(camera_intrinsics, libmv_camera_intrinsics_options);
- libmv::Tracks normalized_tracks(markers);
+ /* Invert the camera intrinsics. */
+ libmv::Tracks normalized_tracks = getNormalizedTracks(tracks, camera_intrinsics);
+ /* Actual reconstruction. */
libmv::ModalSolver(normalized_tracks, reconstruction, &update_callback);
- progress_update_callback(callback_customdata, 1.0, "Finishing solution");
- libmv_reconstruction->tracks = *(libmv::Tracks *)tracks;
- libmv_reconstruction->error = libmv::EuclideanReprojectionError(*(libmv::Tracks *)tracks, *reconstruction, *intrinsics);
+ libmv::CameraIntrinsics empty_intrinsics;
+ libmv::EuclideanBundleCommonIntrinsics(normalized_tracks,
+ libmv::BUNDLE_NO_INTRINSICS,
+ reconstruction,
+ &empty_intrinsics,
+ libmv::BUNDLE_NO_TRANSLATION);
+
+ /* Refinement. */
+ if (libmv_reconstruction_options->refine_intrinsics) {
+ libmv_solveRefineIntrinsics((libmv::Tracks *)tracks, camera_intrinsics, reconstruction,
+ libmv_reconstruction_options->refine_intrinsics,
+ progress_update_callback, callback_customdata,
+ libmv::BUNDLE_NO_TRANSLATION);
+ }
+
+ /* Finish reconstruction. */
+ finishReconstruction(tracks, camera_intrinsics, libmv_reconstruction,
+ progress_update_callback, callback_customdata);
return (libmv_Reconstruction *)libmv_reconstruction;
}
@@ -863,17 +821,13 @@ struct libmv_CameraIntrinsics *libmv_ReconstructionExtractIntrinsics(struct libm
return (struct libmv_CameraIntrinsics *)&libmv_Reconstruction->intrinsics;
}
-struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsNew(double focal_length, double principal_x, double principal_y,
- double k1, double k2, double k3, int width, int height)
+struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsNew(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options)
{
- libmv::CameraIntrinsics *intrinsics= new libmv::CameraIntrinsics();
+ libmv::CameraIntrinsics *camera_intrinsics = new libmv::CameraIntrinsics();
- intrinsics->SetFocalLength(focal_length, focal_length);
- intrinsics->SetPrincipalPoint(principal_x, principal_y);
- intrinsics->SetRadialDistortion(k1, k2, k3);
- intrinsics->SetImageSize(width, height);
+ cameraIntrinsicsFromOptions(camera_intrinsics, libmv_camera_intrinsics_options);
- return (struct libmv_CameraIntrinsics *) intrinsics;
+ return (struct libmv_CameraIntrinsics *) camera_intrinsics;
}
struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsCopy(struct libmv_CameraIntrinsics *libmvIntrinsics)
@@ -891,40 +845,63 @@ void libmv_CameraIntrinsicsDestroy(struct libmv_CameraIntrinsics *libmvIntrinsic
delete intrinsics;
}
-void libmv_CameraIntrinsicsUpdate(struct libmv_CameraIntrinsics *libmvIntrinsics, double focal_length,
- double principal_x, double principal_y, double k1, double k2, double k3, int width, int height)
+void libmv_CameraIntrinsicsUpdate(struct libmv_CameraIntrinsics *libmv_intrinsics,
+ libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options)
{
- libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
+ libmv::CameraIntrinsics *camera_intrinsics = (libmv::CameraIntrinsics *) libmv_intrinsics;
+
+ double focal_length = libmv_camera_intrinsics_options->focal_length;
+ double principal_x = libmv_camera_intrinsics_options->principal_point_x;
+ double principal_y = libmv_camera_intrinsics_options->principal_point_y;
+ double k1 = libmv_camera_intrinsics_options->k1;
+ double k2 = libmv_camera_intrinsics_options->k2;
+ double k3 = libmv_camera_intrinsics_options->k3;
+ int image_width = libmv_camera_intrinsics_options->image_width;
+ int image_height = libmv_camera_intrinsics_options->image_height;
- if (intrinsics->focal_length() != focal_length)
- intrinsics->SetFocalLength(focal_length, focal_length);
+ /* try avoid unnecessary updates so pre-computed distortion grids are not freed */
- if (intrinsics->principal_point_x() != principal_x || intrinsics->principal_point_y() != principal_y)
- intrinsics->SetPrincipalPoint(principal_x, principal_y);
+ if (camera_intrinsics->focal_length() != focal_length)
+ camera_intrinsics->SetFocalLength(focal_length, focal_length);
- if (intrinsics->k1() != k1 || intrinsics->k2() != k2 || intrinsics->k3() != k3)
- intrinsics->SetRadialDistortion(k1, k2, k3);
+ if (camera_intrinsics->principal_point_x() != principal_x ||
+ camera_intrinsics->principal_point_y() != principal_y)
+ {
+ camera_intrinsics->SetPrincipalPoint(principal_x, principal_y);
+ }
- if (intrinsics->image_width() != width || intrinsics->image_height() != height)
- intrinsics->SetImageSize(width, height);
+ if (camera_intrinsics->k1() != k1 ||
+ camera_intrinsics->k2() != k2 ||
+ camera_intrinsics->k3() != k3)
+ {
+ camera_intrinsics->SetRadialDistortion(k1, k2, k3);
+ }
+
+ if (camera_intrinsics->image_width() != image_width ||
+ camera_intrinsics->image_height() != image_height)
+ {
+ camera_intrinsics->SetImageSize(image_width, image_height);
+ }
}
-void libmv_CameraIntrinsicsExtract(struct libmv_CameraIntrinsics *libmvIntrinsics, double *focal_length,
- double *principal_x, double *principal_y, double *k1, double *k2, double *k3, int *width, int *height) {
- libmv::CameraIntrinsics *intrinsics= (libmv::CameraIntrinsics *) libmvIntrinsics;
- *focal_length = intrinsics->focal_length();
- *principal_x = intrinsics->principal_point_x();
- *principal_y = intrinsics->principal_point_y();
- *k1 = intrinsics->k1();
- *k2 = intrinsics->k2();
+void libmv_CameraIntrinsicsExtract(struct libmv_CameraIntrinsics *libmv_intrinsics, double *focal_length,
+ double *principal_x, double *principal_y, double *k1, double *k2, double *k3, int *width, int *height)
+{
+ libmv::CameraIntrinsics *camera_intrinsics = (libmv::CameraIntrinsics *) libmv_intrinsics;
+
+ *focal_length = camera_intrinsics->focal_length();
+ *principal_x = camera_intrinsics->principal_point_x();
+ *principal_y = camera_intrinsics->principal_point_y();
+ *k1 = camera_intrinsics->k1();
+ *k2 = camera_intrinsics->k2();
}
-void libmv_CameraIntrinsicsUndistortByte(struct libmv_CameraIntrinsics *libmvIntrinsics,
+void libmv_CameraIntrinsicsUndistortByte(struct libmv_CameraIntrinsics *libmv_intrinsics,
unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels)
{
- libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
+ libmv::CameraIntrinsics *camera_intrinsics = (libmv::CameraIntrinsics *) libmv_intrinsics;
- intrinsics->Undistort(src, dst, width, height, overscan, channels);
+ camera_intrinsics->Undistort(src, dst, width, height, overscan, channels);
}
void libmv_CameraIntrinsicsUndistortFloat(struct libmv_CameraIntrinsics *libmvIntrinsics,
@@ -950,139 +927,32 @@ void libmv_CameraIntrinsicsDistortFloat(struct libmv_CameraIntrinsics *libmvIntr
intrinsics->Distort(src, dst, width, height, overscan, channels);
}
-/* ************ distortion ************ */
-
-void libmv_undistortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
- unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels)
-{
- libmv::CameraIntrinsics intrinsics;
-
- intrinsics.SetFocalLength(focal_length, focal_length);
- intrinsics.SetPrincipalPoint(principal_x, principal_y);
- intrinsics.SetRadialDistortion(k1, k2, k3);
-
- intrinsics.Undistort(src, dst, width, height, overscan, channels);
-}
-
-void libmv_undistortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
- float *src, float *dst, int width, int height, float overscan, int channels)
-{
- libmv::CameraIntrinsics intrinsics;
-
- intrinsics.SetFocalLength(focal_length, focal_length);
- intrinsics.SetPrincipalPoint(principal_x, principal_y);
- intrinsics.SetRadialDistortion(k1, k2, k3);
-
- intrinsics.Undistort(src, dst, width, height, overscan, channels);
-}
-
-void libmv_distortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
- unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels)
-{
- libmv::CameraIntrinsics intrinsics;
-
- intrinsics.SetFocalLength(focal_length, focal_length);
- intrinsics.SetPrincipalPoint(principal_x, principal_y);
- intrinsics.SetRadialDistortion(k1, k2, k3);
-
- intrinsics.Distort(src, dst, width, height, overscan, channels);
-}
-
-void libmv_distortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
- float *src, float *dst, int width, int height, float overscan, int channels)
-{
- libmv::CameraIntrinsics intrinsics;
-
- intrinsics.SetFocalLength(focal_length, focal_length);
- intrinsics.SetPrincipalPoint(principal_x, principal_y);
- intrinsics.SetRadialDistortion(k1, k2, k3);
-
- intrinsics.Distort(src, dst, width, height, overscan, channels);
-}
-
/* ************ utils ************ */
-void libmv_applyCameraIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
- double x, double y, double *x1, double *y1)
+void libmv_applyCameraIntrinsics(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options,
+ double x, double y, double *x1, double *y1)
{
- libmv::CameraIntrinsics intrinsics;
+ libmv::CameraIntrinsics camera_intrinsics;
- intrinsics.SetFocalLength(focal_length, focal_length);
- intrinsics.SetPrincipalPoint(principal_x, principal_y);
- intrinsics.SetRadialDistortion(k1, k2, k3);
+ cameraIntrinsicsFromOptions(&camera_intrinsics, libmv_camera_intrinsics_options);
- if(focal_length) {
+ if (libmv_camera_intrinsics_options->focal_length) {
/* do a lens undistortion if focal length is non-zero only */
- intrinsics.ApplyIntrinsics(x, y, x1, y1);
+ camera_intrinsics.ApplyIntrinsics(x, y, x1, y1);
}
}
-void libmv_InvertIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
- double x, double y, double *x1, double *y1)
+void libmv_InvertIntrinsics(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options,
+ double x, double y, double *x1, double *y1)
{
- libmv::CameraIntrinsics intrinsics;
+ libmv::CameraIntrinsics camera_intrinsics;
- intrinsics.SetFocalLength(focal_length, focal_length);
- intrinsics.SetPrincipalPoint(principal_x, principal_y);
- intrinsics.SetRadialDistortion(k1, k2, k3);
+ cameraIntrinsicsFromOptions(&camera_intrinsics, libmv_camera_intrinsics_options);
- if(focal_length) {
+ if (libmv_camera_intrinsics_options->focal_length) {
/* do a lens distortion if focal length is non-zero only */
- intrinsics.InvertIntrinsics(x, y, x1, y1);
+ camera_intrinsics.InvertIntrinsics(x, y, x1, y1);
}
}
-
-/* ************ point clouds ************ */
-
-static void libmvTransformToMat4(libmv::Mat3 &R, libmv::Vec3 &S, libmv::Vec3 &t, double M[4][4])
-{
- for (int j = 0; j < 3; ++j)
- for (int k = 0; k < 3; ++k)
- M[j][k] = R(k, j) * S(j);
-
- for (int i = 0; i < 3; ++i) {
- M[3][0] = t(0);
- M[3][1] = t(1);
- M[3][2] = t(2);
-
- M[0][3] = M[1][3] = M[2][3] = 0;
- }
-
- M[3][3] = 1.0;
-}
-
-void libmv_rigidRegistration(float (*reference_points)[3], float (*points)[3], int total_points,
- int use_scale, int use_translation, double M[4][4])
-{
- libmv::Mat3 R;
- libmv::Vec3 S;
- libmv::Vec3 t;
- libmv::vector<libmv::Vec3> reference_points_vector, points_vector;
-
- for (int i = 0; i < total_points; i++) {
- reference_points_vector.push_back(libmv::Vec3(reference_points[i][0],
- reference_points[i][1],
- reference_points[i][2]));
-
- points_vector.push_back(libmv::Vec3(points[i][0],
- points[i][1],
- points[i][2]));
- }
-
- if (use_scale && use_translation) {
- libmv::RigidRegistration(reference_points_vector, points_vector, R, S, t);
- }
- else if (use_translation) {
- S = libmv::Vec3(1.0, 1.0, 1.0);
- libmv::RigidRegistration(reference_points_vector, points_vector, R, t);
- }
- else {
- S = libmv::Vec3(1.0, 1.0, 1.0);
- t = libmv::Vec3::Zero();
- libmv::RigidRegistration(reference_points_vector, points_vector, R);
- }
-
- libmvTransformToMat4(R, S, t, M);
-}
diff --git a/extern/libmv/libmv-capi.h b/extern/libmv/libmv-capi.h
index e5885e7addf..c90322c56c5 100644
--- a/extern/libmv/libmv-capi.h
+++ b/extern/libmv/libmv-capi.h
@@ -31,7 +31,6 @@
extern "C" {
#endif
-struct libmv_RegionTracker;
struct libmv_Tracks;
struct libmv_Reconstruction;
struct libmv_Features;
@@ -42,14 +41,6 @@ void libmv_initLogging(const char *argv0);
void libmv_startDebugLogging(void);
void libmv_setLoggingVerbosity(int verbosity);
-/* RegionTracker */
-struct libmv_RegionTracker *libmv_pyramidRegionTrackerNew(int max_iterations, int pyramid_level, int half_window_size, double minimum_correlation);
-struct libmv_RegionTracker *libmv_hybridRegionTrackerNew(int max_iterations, int half_window_size, double minimum_correlation);
-struct libmv_RegionTracker *libmv_bruteRegionTrackerNew(int half_window_size, double minimum_correlation);
-int libmv_regionTrackerTrack(struct libmv_RegionTracker *libmv_tracker, const float *ima1, const float *ima2,
- int width, int height, double x1, double y1, double *x2, double *y2);
-void libmv_regionTrackerDestroy(struct libmv_RegionTracker *libmv_tracker);
-
/* TrackRegion (new planar tracker) */
struct libmv_trackRegionOptions {
int motion_model;
@@ -86,28 +77,42 @@ void libmv_tracksInsert(struct libmv_Tracks *libmv_tracks, int image, int track,
void libmv_tracksDestroy(struct libmv_Tracks *libmv_tracks);
/* Reconstruction solver */
-#define LIBMV_REFINE_FOCAL_LENGTH (1<<0)
-#define LIBMV_REFINE_PRINCIPAL_POINT (1<<1)
-#define LIBMV_REFINE_RADIAL_DISTORTION_K1 (1<<2)
-#define LIBMV_REFINE_RADIAL_DISTORTION_K2 (1<<4)
-/* TODO: make keyframes/distortion model a part of options? */
-struct libmv_reconstructionOptions {
+#define LIBMV_REFINE_FOCAL_LENGTH (1 << 0)
+#define LIBMV_REFINE_PRINCIPAL_POINT (1 << 1)
+#define LIBMV_REFINE_RADIAL_DISTORTION_K1 (1 << 2)
+#define LIBMV_REFINE_RADIAL_DISTORTION_K2 (1 << 4)
+
+typedef struct libmv_cameraIntrinsicsOptions {
+ double focal_length;
+ double principal_point_x, principal_point_y;
+ double k1, k2, k3;
+ double p1, p2;
+ int image_width, image_height;
+} libmv_cameraIntrinsicsOptions;
+
+typedef struct libmv_reconstructionOptions {
+ int keyframe1, keyframe2;
+ int refine_intrinsics;
+
double success_threshold;
int use_fallback_reconstruction;
-};
+} libmv_reconstructionOptions;
typedef void (*reconstruct_progress_update_cb) (void *customdata, double progress, const char *message);
int libmv_refineParametersAreValid(int parameters);
-struct libmv_Reconstruction *libmv_solveReconstruction(struct libmv_Tracks *tracks, int keyframe1, int keyframe2,
- int refine_intrinsics, double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
- struct libmv_reconstructionOptions *options, reconstruct_progress_update_cb progress_update_callback,
+struct libmv_Reconstruction *libmv_solveReconstruction(struct libmv_Tracks *libmv_tracks,
+ libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options,
+ libmv_reconstructionOptions *libmv_reconstruction_options,
+ reconstruct_progress_update_cb progress_update_callback,
+ void *callback_customdata);
+struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *libmv_tracks,
+ libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options,
+ libmv_reconstructionOptions *libmv_reconstruction_options,
+ reconstruct_progress_update_cb progress_update_callback,
void *callback_customdata);
-struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *tracks, double focal_length,
- double principal_x, double principal_y, double k1, double k2, double k3,
- reconstruct_progress_update_cb progress_update_callback, void *callback_customdata);
int libmv_reporojectionPointForTrack(struct libmv_Reconstruction *libmv_reconstruction, int track, double pos[3]);
double libmv_reporojectionErrorForTrack(struct libmv_Reconstruction *libmv_reconstruction, int track);
double libmv_reporojectionErrorForImage(struct libmv_Reconstruction *libmv_reconstruction, int image);
@@ -127,52 +132,36 @@ void libmv_destroyFeatures(struct libmv_Features *libmv_features);
/* camera intrinsics */
struct libmv_CameraIntrinsics *libmv_ReconstructionExtractIntrinsics(struct libmv_Reconstruction *libmv_Reconstruction);
-struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsNew(double focal_length, double principal_x, double principal_y,
- double k1, double k2, double k3, int width, int height);
+struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsNew(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options);
-struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsCopy(struct libmv_CameraIntrinsics *libmvIntrinsics);
+struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsCopy(struct libmv_CameraIntrinsics *libmv_intrinsics);
-void libmv_CameraIntrinsicsDestroy(struct libmv_CameraIntrinsics *libmvIntrinsics);
+void libmv_CameraIntrinsicsDestroy(struct libmv_CameraIntrinsics *libmv_intrinsics);
-void libmv_CameraIntrinsicsUpdate(struct libmv_CameraIntrinsics *libmvIntrinsics, double focal_length,
- double principal_x, double principal_y, double k1, double k2, double k3, int width, int height);
+void libmv_CameraIntrinsicsUpdate(struct libmv_CameraIntrinsics *libmv_intrinsics,
+ libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options);
-void libmv_CameraIntrinsicsExtract(struct libmv_CameraIntrinsics *libmvIntrinsics, double *focal_length,
+void libmv_CameraIntrinsicsExtract(struct libmv_CameraIntrinsics *libmv_intrinsics, double *focal_length,
double *principal_x, double *principal_y, double *k1, double *k2, double *k3, int *width, int *height);
-void libmv_CameraIntrinsicsUndistortByte(struct libmv_CameraIntrinsics *libmvIntrinsics,
+void libmv_CameraIntrinsicsUndistortByte(struct libmv_CameraIntrinsics *libmv_intrinsics,
unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels);
-void libmv_CameraIntrinsicsUndistortFloat(struct libmv_CameraIntrinsics *libmvIntrinsics,
+void libmv_CameraIntrinsicsUndistortFloat(struct libmv_CameraIntrinsics *libmv_intrinsics,
float *src, float *dst, int width, int height, float overscan, int channels);
-void libmv_CameraIntrinsicsDistortByte(struct libmv_CameraIntrinsics *libmvIntrinsics,
+void libmv_CameraIntrinsicsDistortByte(struct libmv_CameraIntrinsics *libmv_intrinsics,
unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels);
-void libmv_CameraIntrinsicsDistortFloat(struct libmv_CameraIntrinsics *libmvIntrinsics,
- float *src, float *dst, int width, int height, float overscan, int channels);
-
-/* dsitortion */
-void libmv_undistortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
- unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels);
-void libmv_undistortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
- float *src, float *dst, int width, int height, float overscan, int channels);
-
-void libmv_distortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
- unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels);
-void libmv_distortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+void libmv_CameraIntrinsicsDistortFloat(struct libmv_CameraIntrinsics *libmv_intrinsics,
float *src, float *dst, int width, int height, float overscan, int channels);
/* utils */
-void libmv_applyCameraIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+void libmv_applyCameraIntrinsics(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options,
double x, double y, double *x1, double *y1);
-void libmv_InvertIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+void libmv_InvertIntrinsics(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options,
double x, double y, double *x1, double *y1);
-/* point clouds */
-void libmv_rigidRegistration(float (*reference_points)[3], float (*points)[3], int total_points,
- int use_scale, int use_translation, double M[4][4]);
-
#ifdef __cplusplus
}
#endif
diff --git a/extern/libmv/libmv/multiview/euclidean_resection.cc b/extern/libmv/libmv/multiview/euclidean_resection.cc
index 2605bf04622..062c8b9067c 100644
--- a/extern/libmv/libmv/multiview/euclidean_resection.cc
+++ b/extern/libmv/libmv/multiview/euclidean_resection.cc
@@ -653,8 +653,8 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera,
// Finally, with all three solutions, select the (R, t) with the best RMSE.
VLOG(2) << "RMSE for solution 0: " << rmse(0);
- VLOG(2) << "RMSE for solution 1: " << rmse(0);
- VLOG(2) << "RMSE for solution 2: " << rmse(0);
+ VLOG(2) << "RMSE for solution 1: " << rmse(1);
+ VLOG(2) << "RMSE for solution 2: " << rmse(2);
size_t n = 0;
if (rmse(1) < rmse(0)) {
n = 1;
diff --git a/extern/libmv/libmv/multiview/fundamental.cc b/extern/libmv/libmv/multiview/fundamental.cc
index 12a611c748f..80f155e804d 100644
--- a/extern/libmv/libmv/multiview/fundamental.cc
+++ b/extern/libmv/libmv/multiview/fundamental.cc
@@ -254,8 +254,8 @@ double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) {
Vec3 Ft_y = F.transpose() * y;
double y_F_x = y.dot(F_x);
- return y_F_x * ( 1 / F_x.head<2>().norm()
- + 1 / Ft_y.head<2>().norm());
+ return Square(y_F_x) * ( 1 / F_x.head<2>().squaredNorm()
+ + 1 / Ft_y.head<2>().squaredNorm());
}
// HZ 9.6 pag 257 (formula 9.12)
diff --git a/extern/libmv/libmv/multiview/homography.cc b/extern/libmv/libmv/multiview/homography.cc
index b5c483998d8..538c62598c0 100644
--- a/extern/libmv/libmv/multiview/homography.cc
+++ b/extern/libmv/libmv/multiview/homography.cc
@@ -264,4 +264,19 @@ bool Homography3DFromCorrespondencesLinear(const Mat &x1,
return false;
}
}
+
+double SymmetricGeometricDistance(Mat3 &H, Vec2 &x1, Vec2 &x2) {
+ Vec3 x(x1(0), x1(1), 1.0);
+ Vec3 y(x2(0), x2(1), 1.0);
+
+ Vec3 H_x = H * x;
+ Vec3 Hinv_y = H.inverse() * y;
+
+ H_x /= H_x(2);
+ Hinv_y /= Hinv_y(2);
+
+ return (H_x.head<2>() - y.head<2>()).squaredNorm() +
+ (Hinv_y.head<2>() - x.head<2>()).squaredNorm();
+}
+
} // namespace libmv
diff --git a/extern/libmv/libmv/multiview/homography.h b/extern/libmv/libmv/multiview/homography.h
index 786fd3df8ca..a295c4366b6 100644
--- a/extern/libmv/libmv/multiview/homography.h
+++ b/extern/libmv/libmv/multiview/homography.h
@@ -79,6 +79,14 @@ bool Homography3DFromCorrespondencesLinear(const Mat &x1,
Mat4 *H,
double expected_precision =
EigenDouble::dummy_precision());
+
+/**
+ * Calculate symmetric geometric cost:
+ *
+ * D(H * x1, x2)^2 + D(H^-1 * x2, x1)
+ */
+double SymmetricGeometricDistance(Mat3 &H, Vec2 &x1, Vec2 &x2);
+
} // namespace libmv
#endif // LIBMV_MULTIVIEW_HOMOGRAPHY_H_
diff --git a/extern/libmv/libmv/multiview/panography.h b/extern/libmv/libmv/multiview/panography.h
new file mode 100644
index 00000000000..6f01beb0ffd
--- /dev/null
+++ b/extern/libmv/libmv/multiview/panography.h
@@ -0,0 +1,181 @@
+// Copyright (c) 2009 libmv authors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//
+
+#ifndef LIBMV_MULTIVIEW_PANOGRAPHY_H
+#define LIBMV_MULTIVIEW_PANOGRAPHY_H
+
+#include "libmv/numeric/numeric.h"
+#include "libmv/numeric/poly.h"
+#include "libmv/base/vector.h"
+
+namespace libmv {
+
+static bool Build_Minimal2Point_PolynomialFactor(
+ const Mat & x1, const Mat & x2,
+ double * P) //P must be a double[4]
+{
+ assert(2 == x1.rows());
+ assert(2 == x1.cols());
+ assert(x1.rows() == x2.rows());
+ assert(x1.cols() == x2.cols());
+
+ // Setup the variable of the input problem:
+ Vec xx1 = (x1.col(0)).transpose();
+ Vec yx1 = (x1.col(1)).transpose();
+
+ double a12 = xx1.dot(yx1);
+ Vec xx2 = (x2.col(0)).transpose();
+ Vec yx2 = (x2.col(1)).transpose();
+ double b12 = xx2.dot(yx2);
+
+ double a1 = xx1.squaredNorm();
+ double a2 = yx1.squaredNorm();
+
+ double b1 = xx2.squaredNorm();
+ double b2 = yx2.squaredNorm();
+
+ // Build the 3rd degre polynomial in F^2.
+ //
+ // f^6 * p + f^4 * q + f^2* r + s = 0;
+ //
+ // Coefficients in ascending powers of alpha, i.e. P[N]*x^N.
+ // Run panography_coeffs.py to get the below coefficients.
+ P[0] = b1*b2*a12*a12-a1*a2*b12*b12;
+ P[1] = -2*a1*a2*b12+2*a12*b1*b2+b1*a12*a12+b2*a12*a12-a1*b12*b12-a2*b12*b12;
+ P[2] = b1*b2-a1*a2-2*a1*b12-2*a2*b12+2*a12*b1+2*a12*b2+a12*a12-b12*b12;
+ P[3] = b1+b2-2*b12-a1-a2+2*a12;
+
+ // If P[3] equal to 0 we get ill conditionned data
+ return (P[3] != 0.0);
+}
+
+// This implements a minimal solution (2 points) for panoramic stitching:
+//
+// http://www.cs.ubc.ca/~mbrown/minimal/minimal.html
+//
+// [1] M. Brown and R. Hartley and D. Nister. Minimal Solutions for Panoramic
+// Stitching. CVPR07.
+//
+// The 2-point algorithm solves for the rotation of the camera with a single
+// focal length (4 degrees of freedom).
+//
+// Compute from 1 to 3 possible focal lenght for 2 point correspondences.
+// Suppose that the cameras share the same optical center and focal lengths:
+//
+// Image 1 => H*x = x' => Image 2
+// x (u1j) x' (u2j)
+// a (u11) a' (u21)
+// b (u12) b' (u22)
+//
+// The return values are 1 to 3 possible values for the focal lengths such
+// that:
+//
+// [f 0 0]
+// K = [0 f 0]
+// [0 0 1]
+//
+static void F_FromCorrespondance_2points(const Mat &x1, const Mat &x2,
+ vector<double> *fs) {
+
+ // Build Polynomial factor to get squared focal value.
+ double P[4];
+ Build_Minimal2Point_PolynomialFactor(x1, x2, &P[0]);
+
+ // Solve it by using F = f^2 and a Cubic polynomial solver
+ //
+ // F^3 * p + F^2 * q + F^1 * r + s = 0
+ //
+ double roots[3];
+ int num_roots = SolveCubicPolynomial(P, roots);
+ for (int i = 0; i < num_roots; ++i) {
+ if (roots[i] > 0.0) {
+ fs->push_back(sqrt(roots[i]));
+ }
+ }
+}
+
+// Compute the 3x3 rotation matrix that fits two 3D point clouds in the least
+// square sense. The method is from:
+//
+// K. Arun,T. Huand and D. Blostein. Least-squares fitting of 2 3-D point
+// sets. IEEE Transactions on Pattern Analysis and Machine Intelligence,
+// 9:698-700, 1987.
+//
+// Given the calibration matrices K1, K2 solve for the rotation from
+// corresponding image rays.
+//
+// R = min || X2 - R * x1 ||.
+//
+// In case of panography, which is for a camera that shares the same camera
+// center,
+//
+// H = K2 * R * K1.inverse();
+//
+// For the full explanation, see Section 8, Solving for Rotation from [1].
+//
+// Parameters:
+//
+// x1 : Point cloud A (3D coords)
+// x2 : Point cloud B (3D coords)
+//
+// [f 0 0]
+// K1 = [0 f 0]
+// [0 0 1]
+//
+// K2 (the same form as K1, but may have different f)
+//
+// Returns: A rotation matrix that minimizes
+//
+// R = arg min || X2 - R * x1 ||
+//
+static void GetR_FixedCameraCenter(const Mat &x1, const Mat &x2,
+ const double focal,
+ Mat3 *R) {
+ assert(3 == x1.rows());
+ assert(2 <= x1.cols());
+ assert(x1.rows() == x2.rows());
+ assert(x1.cols() == x2.cols());
+
+ // Build simplified K matrix
+ Mat3 K( Mat3::Identity() * 1.0/focal );
+ K(2,2)= 1.0;
+
+ // Build the correlation matrix; equation (22) in [1].
+ Mat3 C = Mat3::Zero();
+ for(int i = 0; i < x1.cols(); ++i) {
+ Mat r1i = (K * x1.col(i)).normalized();
+ Mat r2i = (K * x2.col(i)).normalized();
+ C += r2i * r1i.transpose();
+ }
+
+ // Solve for rotation. Equations (24) and (25) in [1].
+ Eigen::JacobiSVD<Mat> svd(C, Eigen::ComputeThinU | Eigen::ComputeThinV);
+ Mat3 scale = Mat3::Identity();
+ scale(2,2) = ((svd.matrixU() * svd.matrixV().transpose()).determinant() > 0.0)
+ ? 1.0
+ : -1.0;
+
+ (*R) = svd.matrixU() * scale * svd.matrixV().transpose();
+}
+
+} // namespace libmv
+
+#endif // LIBMV_MULTIVIEW_PANOGRAPHY_H
diff --git a/extern/libmv/libmv/simple_pipeline/bundle.cc b/extern/libmv/libmv/simple_pipeline/bundle.cc
index d382cd5a4fc..3e36a78c9df 100644
--- a/extern/libmv/libmv/simple_pipeline/bundle.cc
+++ b/extern/libmv/libmv/simple_pipeline/bundle.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 libmv authors.
+// Copyright (c) 2011, 2012, 2013 libmv authors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
@@ -18,10 +18,11 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
-#define V3DLIB_ENABLE_SUITESPARSE 1
-
#include <map>
+#include "ceres/ceres.h"
+#include "ceres/rotation.h"
+#include "libmv/base/scoped_ptr.h"
#include "libmv/base/vector.h"
#include "libmv/logging/logging.h"
#include "libmv/multiview/fundamental.h"
@@ -31,218 +32,340 @@
#include "libmv/simple_pipeline/bundle.h"
#include "libmv/simple_pipeline/reconstruction.h"
#include "libmv/simple_pipeline/tracks.h"
-#include "third_party/ssba/Geometry/v3d_cameramatrix.h"
-#include "third_party/ssba/Geometry/v3d_metricbundle.h"
-#include "third_party/ssba/Math/v3d_linear.h"
-#include "third_party/ssba/Math/v3d_linear_utils.h"
+
+#ifdef _OPENMP
+# include <omp.h>
+#endif
namespace libmv {
-void EuclideanBundle(const Tracks &tracks,
- EuclideanReconstruction *reconstruction) {
- CameraIntrinsics intrinsics;
- EuclideanBundleCommonIntrinsics(tracks,
- BUNDLE_NO_INTRINSICS,
- reconstruction,
- &intrinsics);
-}
+// The intrinsics need to get combined into a single parameter block; use these
+// enums to index instead of numeric constants.
+enum {
+ OFFSET_FOCAL_LENGTH,
+ OFFSET_PRINCIPAL_POINT_X,
+ OFFSET_PRINCIPAL_POINT_Y,
+ OFFSET_K1,
+ OFFSET_K2,
+ OFFSET_K3,
+ OFFSET_P1,
+ OFFSET_P2,
+};
-void EuclideanBundleCommonIntrinsics(const Tracks &tracks,
- int bundle_intrinsics,
- EuclideanReconstruction *reconstruction,
- CameraIntrinsics *intrinsics) {
- LG << "Original intrinsics: " << *intrinsics;
- vector<Marker> markers = tracks.AllMarkers();
+namespace {
- // "index" in this context is the index that V3D's optimizer will see. The
- // V3D index must be dense in that the cameras are numbered 0...n-1, which is
- // not the case for the "image" numbering that arises from the tracks
- // structure. The complicated mapping is necessary to convert between the two
- // representations.
- std::map<EuclideanCamera *, int> camera_to_index;
- std::map<EuclideanPoint *, int> point_to_index;
- vector<EuclideanCamera *> index_to_camera;
- vector<EuclideanPoint *> index_to_point;
- int num_cameras = 0;
- int num_points = 0;
- for (int i = 0; i < markers.size(); ++i) {
- const Marker &marker = markers[i];
- EuclideanCamera *camera = reconstruction->CameraForImage(marker.image);
- EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
- if (camera && point) {
- if (camera_to_index.find(camera) == camera_to_index.end()) {
- camera_to_index[camera] = num_cameras;
- index_to_camera.push_back(camera);
- num_cameras++;
- }
- if (point_to_index.find(point) == point_to_index.end()) {
- point_to_index[point] = num_points;
- index_to_point.push_back(point);
- num_points++;
- }
- }
- }
+struct OpenCVReprojectionError {
+ OpenCVReprojectionError(double observed_x, double observed_y)
+ : observed_x(observed_x), observed_y(observed_y) {}
- // Convert libmv's K matrix to V3d's K matrix.
- V3D::Matrix3x3d v3d_K;
- for (int i = 0; i < 3; ++i) {
- for (int j = 0; j < 3; ++j) {
- v3d_K[i][j] = intrinsics->K()(i, j);
+ template <typename T>
+ bool operator()(const T* const intrinsics,
+ const T* const R, // Rotation 3x3 column-major.
+ const T* const t, // Translation 3x1.
+ const T* const X, // Point coordinates 3x1.
+ T* residuals) const {
+ // Unpack the intrinsics.
+ const T& focal_length = intrinsics[OFFSET_FOCAL_LENGTH];
+ const T& principal_point_x = intrinsics[OFFSET_PRINCIPAL_POINT_X];
+ const T& principal_point_y = intrinsics[OFFSET_PRINCIPAL_POINT_Y];
+ const T& k1 = intrinsics[OFFSET_K1];
+ const T& k2 = intrinsics[OFFSET_K2];
+ const T& k3 = intrinsics[OFFSET_K3];
+ const T& p1 = intrinsics[OFFSET_P1];
+ const T& p2 = intrinsics[OFFSET_P2];
+
+ // Compute projective coordinates: x = RX + t.
+ T x[3];
+ x[0] = R[0]*X[0] + R[3]*X[1] + R[6]*X[2] + t[0];
+ x[1] = R[1]*X[0] + R[4]*X[1] + R[7]*X[2] + t[1];
+ x[2] = R[2]*X[0] + R[5]*X[1] + R[8]*X[2] + t[2];
+
+ // Compute normalized coordinates: x /= x[2].
+ T xn = x[0] / x[2];
+ T yn = x[1] / x[2];
+
+ T predicted_x, predicted_y;
+
+ // EuclideanBundle uses empty intrinsics, which breaks undistortion code;
+ // so use an implied focal length of 1.0 if the focal length is exactly
+ // zero.
+ // TODO(keir): Figure out a better way to do this.
+ if (focal_length != T(0)) {
+ // Apply distortion to the normalized points to get (xd, yd).
+ // TODO(keir): Do early bailouts for zero distortion; these are expensive
+ // jet operations.
+
+ ApplyRadialDistortionCameraIntrinsics(focal_length,
+ focal_length,
+ principal_point_x,
+ principal_point_y,
+ k1, k2, k3,
+ p1, p2,
+ xn, yn,
+ &predicted_x,
+ &predicted_y);
+ } else {
+ predicted_x = xn;
+ predicted_y = yn;
}
+
+ // The error is the difference between the predicted and observed position.
+ residuals[0] = predicted_x - T(observed_x);
+ residuals[1] = predicted_y - T(observed_y);
+
+ return true;
}
- // Convert libmv's distortion to v3d distortion.
- V3D::StdDistortionFunction v3d_distortion;
- v3d_distortion.k1 = intrinsics->k1();
- v3d_distortion.k2 = intrinsics->k2();
- v3d_distortion.p1 = intrinsics->p1();
- v3d_distortion.p2 = intrinsics->p2();
-
- // Convert libmv's cameras to V3D's cameras.
- std::vector<V3D::CameraMatrix> v3d_cameras(index_to_camera.size());
- for (int k = 0; k < index_to_camera.size(); ++k) {
- V3D::Matrix3x3d R;
- V3D::Vector3d t;
-
- // Libmv's rotation matrix type.
- const Mat3 &R_libmv = index_to_camera[k]->R;
- const Vec3 &t_libmv = index_to_camera[k]->t;
-
- for (int i = 0; i < 3; ++i) {
- for (int j = 0; j < 3; ++j) {
- R[i][j] = R_libmv(i, j);
- }
- t[i] = t_libmv(i);
- }
- v3d_cameras[k].setIntrinsic(v3d_K);
- v3d_cameras[k].setRotation(R);
- v3d_cameras[k].setTranslation(t);
+ double observed_x;
+ double observed_y;
+};
+
+// TODO(keir): Get rid of the parameterization! Ceres will work much faster if
+// the rotation block is angle-axis and also the translation is merged into a
+// single parameter block.
+struct RotationMatrixPlus {
+ template<typename T>
+ bool operator()(const T* R_array, // Rotation 3x3 col-major.
+ const T* delta, // Angle-axis delta
+ T* R_plus_delta_array) const {
+ T angle_axis[3];
+
+ ceres::RotationMatrixToAngleAxis(R_array, angle_axis);
+
+ angle_axis[0] += delta[0];
+ angle_axis[1] += delta[1];
+ angle_axis[2] += delta[2];
+
+ ceres::AngleAxisToRotationMatrix(angle_axis, R_plus_delta_array);
+
+ return true;
}
- LG << "Number of cameras: " << index_to_camera.size();
-
- // Convert libmv's points to V3D's points.
- std::vector<V3D::Vector3d> v3d_points(index_to_point.size());
- for (int i = 0; i < index_to_point.size(); i++) {
- v3d_points[i][0] = index_to_point[i]->X(0);
- v3d_points[i][1] = index_to_point[i]->X(1);
- v3d_points[i][2] = index_to_point[i]->X(2);
+};
+
+// TODO(sergey): would be nice to have this in Ceres upstream
+template<typename PlusFunctor, int kGlobalSize, int kLocalSize>
+class AutodiffParameterization : public ceres::LocalParameterization {
+ public:
+ AutodiffParameterization(const PlusFunctor &plus_functor)
+ : plus_functor_(plus_functor) {}
+
+ virtual ~AutodiffParameterization() {}
+
+ virtual bool Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const {
+ return plus_functor_(x, delta, x_plus_delta);
}
- LG << "Number of points: " << index_to_point.size();
- // Convert libmv's measurements to v3d measurements.
- int num_residuals = 0;
- std::vector<V3D::Vector2d> v3d_measurements;
- std::vector<int> v3d_camera_for_measurement;
- std::vector<int> v3d_point_for_measurement;
- for (int i = 0; i < markers.size(); ++i) {
- EuclideanCamera *camera = reconstruction->CameraForImage(markers[i].image);
- EuclideanPoint *point = reconstruction->PointForTrack(markers[i].track);
- if (!camera || !point) {
- continue;
- }
- V3D::Vector2d v3d_point;
- v3d_point[0] = markers[i].x;
- v3d_point[1] = markers[i].y;
- v3d_measurements.push_back(v3d_point);
- v3d_camera_for_measurement.push_back(camera_to_index[camera]);
- v3d_point_for_measurement.push_back(point_to_index[point]);
- num_residuals++;
+ virtual bool ComputeJacobian(const double* x, double* jacobian) const {
+ double zero_delta[kLocalSize] = { 0.0 };
+ double x_plus_delta[kGlobalSize];
+ const double* parameters[2] = { x, zero_delta };
+ double* jacobians_array[2] = { NULL, jacobian };
+
+ Plus(x, zero_delta, x_plus_delta);
+
+ return ceres::internal::AutoDiff<PlusFunctor,
+ double,
+ kGlobalSize, kLocalSize>
+ ::Differentiate(plus_functor_,
+ parameters,
+ kGlobalSize,
+ x_plus_delta,
+ jacobians_array);
+
+ return true;
}
- LG << "Number of residuals: " << num_residuals;
-
- // Convert from libmv's specification for which intrinsics to bundle to V3D's.
- int v3d_bundle_intrinsics;
+
+ virtual int GlobalSize() const { return kGlobalSize; }
+ virtual int LocalSize() const { return kLocalSize; }
+
+ private:
+ const PlusFunctor &plus_functor_;
+};
+
+void BundleIntrinsicsLogMessage(int bundle_intrinsics) {
if (bundle_intrinsics == BUNDLE_NO_INTRINSICS) {
LG << "Bundling only camera positions.";
- v3d_bundle_intrinsics = V3D::FULL_BUNDLE_METRIC;
} else if (bundle_intrinsics == BUNDLE_FOCAL_LENGTH) {
LG << "Bundling f.";
- v3d_bundle_intrinsics = V3D::FULL_BUNDLE_FOCAL_LENGTH;
} else if (bundle_intrinsics == (BUNDLE_FOCAL_LENGTH |
BUNDLE_PRINCIPAL_POINT)) {
LG << "Bundling f, px, py.";
- v3d_bundle_intrinsics = V3D::FULL_BUNDLE_FOCAL_LENGTH_PP;
} else if (bundle_intrinsics == (BUNDLE_FOCAL_LENGTH |
BUNDLE_PRINCIPAL_POINT |
BUNDLE_RADIAL)) {
LG << "Bundling f, px, py, k1, k2.";
- v3d_bundle_intrinsics = V3D::FULL_BUNDLE_RADIAL;
} else if (bundle_intrinsics == (BUNDLE_FOCAL_LENGTH |
BUNDLE_PRINCIPAL_POINT |
BUNDLE_RADIAL |
BUNDLE_TANGENTIAL)) {
LG << "Bundling f, px, py, k1, k2, p1, p2.";
- v3d_bundle_intrinsics = V3D::FULL_BUNDLE_RADIAL_TANGENTIAL;
} else if (bundle_intrinsics == (BUNDLE_FOCAL_LENGTH |
BUNDLE_RADIAL |
BUNDLE_TANGENTIAL)) {
LG << "Bundling f, px, py, k1, k2, p1, p2.";
- v3d_bundle_intrinsics = V3D::FULL_BUNDLE_RADIAL_TANGENTIAL;
} else if (bundle_intrinsics == (BUNDLE_FOCAL_LENGTH |
BUNDLE_RADIAL)) {
LG << "Bundling f, k1, k2.";
- v3d_bundle_intrinsics = V3D::FULL_BUNDLE_FOCAL_AND_RADIAL;
} else if (bundle_intrinsics == (BUNDLE_FOCAL_LENGTH |
BUNDLE_RADIAL_K1)) {
LG << "Bundling f, k1.";
- v3d_bundle_intrinsics = V3D::FULL_BUNDLE_FOCAL_AND_RADIAL_K1;
+ } else if (bundle_intrinsics == (BUNDLE_RADIAL_K1 |
+ BUNDLE_RADIAL_K2)) {
+ LG << "Bundling k1, k2.";
} else {
LOG(FATAL) << "Unsupported bundle combination.";
}
+}
- // Ignore any outliers; assume supervised tracking.
- double v3d_inlier_threshold = 500000.0;
-
- // Finally, run the bundle adjustment.
- V3D::CommonInternalsMetricBundleOptimizer opt(v3d_bundle_intrinsics,
- v3d_inlier_threshold,
- v3d_K,
- v3d_distortion,
- v3d_cameras,
- v3d_points,
- v3d_measurements,
- v3d_camera_for_measurement,
- v3d_point_for_measurement);
- opt.maxIterations = 500;
- opt.minimize();
- if (opt.status == V3D::LEVENBERG_OPTIMIZER_TIMEOUT) {
- LG << "Bundle status: Timed out.";
- } else if (opt.status == V3D::LEVENBERG_OPTIMIZER_SMALL_UPDATE) {
- LG << "Bundle status: Small update.";
- } else if (opt.status == V3D::LEVENBERG_OPTIMIZER_CONVERGED) {
- LG << "Bundle status: Converged.";
- }
+} // namespace
- // Convert V3D's K matrix back to libmv's K matrix.
- Mat3 K;
- for (int i = 0; i < 3; ++i) {
- for (int j = 0; j < 3; ++j) {
- K(i, j) = v3d_K[i][j];
+void EuclideanBundle(const Tracks &tracks,
+ EuclideanReconstruction *reconstruction) {
+ CameraIntrinsics intrinsics;
+ EuclideanBundleCommonIntrinsics(tracks,
+ BUNDLE_NO_INTRINSICS,
+ reconstruction,
+ &intrinsics);
+}
+
+void EuclideanBundleCommonIntrinsics(const Tracks &tracks,
+ int bundle_intrinsics,
+ EuclideanReconstruction *reconstruction,
+ CameraIntrinsics *intrinsics,
+ int bundle_constraints) {
+ LG << "Original intrinsics: " << *intrinsics;
+ vector<Marker> markers = tracks.AllMarkers();
+
+ ceres::Problem::Options problem_options;
+ problem_options.local_parameterization_ownership =
+ ceres::DO_NOT_TAKE_OWNERSHIP;
+
+ ceres::Problem problem(problem_options);
+
+ // Residual blocks with 10 parameters are unwieldly with Ceres, so pack the
+ // intrinsics into a single block and rely on local parameterizations to
+ // control which intrinsics are allowed to vary.
+ double ceres_intrinsics[8];
+ ceres_intrinsics[OFFSET_FOCAL_LENGTH] = intrinsics->focal_length();
+ ceres_intrinsics[OFFSET_PRINCIPAL_POINT_X] = intrinsics->principal_point_x();
+ ceres_intrinsics[OFFSET_PRINCIPAL_POINT_Y] = intrinsics->principal_point_y();
+ ceres_intrinsics[OFFSET_K1] = intrinsics->k1();
+ ceres_intrinsics[OFFSET_K2] = intrinsics->k2();
+ ceres_intrinsics[OFFSET_K3] = intrinsics->k3();
+ ceres_intrinsics[OFFSET_P1] = intrinsics->p1();
+ ceres_intrinsics[OFFSET_P2] = intrinsics->p2();
+
+ RotationMatrixPlus rotation_matrix_plus;
+ AutodiffParameterization<RotationMatrixPlus, 9, 3>
+ rotation_parameterization(rotation_matrix_plus);
+
+ int num_residuals = 0;
+ for (int i = 0; i < markers.size(); ++i) {
+ const Marker &marker = markers[i];
+ EuclideanCamera *camera = reconstruction->CameraForImage(marker.image);
+ EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
+ if (!camera || !point) {
+ continue;
}
- }
- intrinsics->SetK(K);
-
- // Convert V3D's distortion back to libmv's distortion.
- intrinsics->SetRadialDistortion(v3d_distortion.k1, v3d_distortion.k2, 0.0);
- intrinsics->SetTangentialDistortion(v3d_distortion.p1, v3d_distortion.p2);
-
- // Convert V3D's cameras back to libmv's cameras.
- for (int k = 0; k < num_cameras; k++) {
- V3D::Matrix3x4d const Rt = v3d_cameras[k].getOrientation();
- for (int i = 0; i < 3; ++i) {
- for (int j = 0; j < 3; ++j) {
- index_to_camera[k]->R(i, j) = Rt[i][j];
- }
- index_to_camera[k]->t(i) = Rt[i][3];
+
+ problem.AddResidualBlock(new ceres::AutoDiffCostFunction<
+ OpenCVReprojectionError, 2, 8, 9, 3, 3>(
+ new OpenCVReprojectionError(
+ marker.x,
+ marker.y)),
+ NULL,
+ ceres_intrinsics,
+ &camera->R(0, 0),
+ &camera->t(0),
+ &point->X(0));
+
+ // It's fine if the parameterization for one camera is set repeatedly.
+ problem.SetParameterization(&camera->R(0, 0),
+ &rotation_parameterization);
+
+ if (bundle_constraints & BUNDLE_NO_TRANSLATION) {
+ problem.SetParameterBlockConstant(&camera->t(0));
}
+
+ num_residuals++;
}
+ LG << "Number of residuals: " << num_residuals;
+
+ if(!num_residuals) {
+ LG << "Skipping running minimizer with zero residuals";
+ return;
+ }
+
+ BundleIntrinsicsLogMessage(bundle_intrinsics);
+
+ scoped_ptr<ceres::SubsetParameterization>
+ subset_parameterization(NULL);
+
+ if (bundle_intrinsics == BUNDLE_NO_INTRINSICS) {
+ // No camera intrinsics are refining,
+ // set the whole parameter block as constant for best performance
+ problem.SetParameterBlockConstant(ceres_intrinsics);
+ } else {
+ // Set intrinsics not being bundles as constant
- // Convert V3D's points back to libmv's points.
- for (int k = 0; k < num_points; k++) {
- for (int i = 0; i < 3; ++i) {
- index_to_point[k]->X(i) = v3d_points[k][i];
+ std::vector<int> constant_intrinsics;
+#define MAYBE_SET_CONSTANT(bundle_enum, offset) \
+ if (!(bundle_intrinsics & bundle_enum)) { \
+ constant_intrinsics.push_back(offset); \
}
+ MAYBE_SET_CONSTANT(BUNDLE_FOCAL_LENGTH, OFFSET_FOCAL_LENGTH);
+ MAYBE_SET_CONSTANT(BUNDLE_PRINCIPAL_POINT, OFFSET_PRINCIPAL_POINT_X);
+ MAYBE_SET_CONSTANT(BUNDLE_PRINCIPAL_POINT, OFFSET_PRINCIPAL_POINT_Y);
+ MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K1, OFFSET_K1);
+ MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K2, OFFSET_K2);
+ MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P1, OFFSET_P1);
+ MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P2, OFFSET_P2);
+#undef MAYBE_SET_CONSTANT
+
+ // Always set K3 constant, it's not used at the moment.
+ constant_intrinsics.push_back(OFFSET_K3);
+
+ subset_parameterization.reset(
+ new ceres::SubsetParameterization(8, constant_intrinsics));
+
+ problem.SetParameterization(ceres_intrinsics, subset_parameterization.get());
}
+
+ ceres::Solver::Options options;
+ options.use_nonmonotonic_steps = true;
+ options.preconditioner_type = ceres::SCHUR_JACOBI;
+ options.linear_solver_type = ceres::ITERATIVE_SCHUR;
+ options.use_inner_iterations = true;
+ options.max_num_iterations = 100;
+
+#ifdef _OPENMP
+ options.num_threads = omp_get_max_threads();
+ options.num_linear_solver_threads = omp_get_max_threads();
+#endif
+
+ ceres::Solver::Summary summary;
+ ceres::Solve(options, &problem, &summary);
+
+ LG << "Final report:\n" << summary.FullReport();
+
+ // Copy intrinsics back.
+ if (bundle_intrinsics != BUNDLE_NO_INTRINSICS) {
+ intrinsics->SetFocalLength(ceres_intrinsics[OFFSET_FOCAL_LENGTH],
+ ceres_intrinsics[OFFSET_FOCAL_LENGTH]);
+
+ intrinsics->SetPrincipalPoint(ceres_intrinsics[OFFSET_PRINCIPAL_POINT_X],
+ ceres_intrinsics[OFFSET_PRINCIPAL_POINT_Y]);
+
+ intrinsics->SetRadialDistortion(ceres_intrinsics[OFFSET_K1],
+ ceres_intrinsics[OFFSET_K2],
+ ceres_intrinsics[OFFSET_K3]);
+
+ intrinsics->SetTangentialDistortion(ceres_intrinsics[OFFSET_P1],
+ ceres_intrinsics[OFFSET_P2]);
+ }
+
LG << "Final intrinsics: " << *intrinsics;
}
diff --git a/extern/libmv/libmv/simple_pipeline/bundle.h b/extern/libmv/libmv/simple_pipeline/bundle.h
index 55657cb2d92..573bcf4cc21 100644
--- a/extern/libmv/libmv/simple_pipeline/bundle.h
+++ b/extern/libmv/libmv/simple_pipeline/bundle.h
@@ -67,6 +67,11 @@ void EuclideanBundle(const Tracks &tracks,
BUNDLE_FOCAL_LENGTH | BUNDLE_PRINCIPAL_POINT
BUNDLE_FOCAL_LENGTH | BUNDLE_PRINCIPAL_POINT | BUNDLE_RADIAL
BUNDLE_FOCAL_LENGTH | BUNDLE_PRINCIPAL_POINT | BUNDLE_RADIAL | BUNDLE_TANGENTIAL
+ BUNDLE_RADIAL
+
+ Constraints denotes which blocks to keep constant during bundling.
+ For example it is useful to keep camera translations constant
+ when bundling tripod motions.
\note This assumes an outlier-free set of markers.
@@ -83,10 +88,15 @@ enum BundleIntrinsics {
BUNDLE_TANGENTIAL_P2 = 32,
BUNDLE_TANGENTIAL = 48,
};
+enum BundleConstraints {
+ BUNDLE_NO_CONSTRAINTS = 0,
+ BUNDLE_NO_TRANSLATION = 1,
+};
void EuclideanBundleCommonIntrinsics(const Tracks &tracks,
int bundle_intrinsics,
EuclideanReconstruction *reconstruction,
- CameraIntrinsics *intrinsics);
+ CameraIntrinsics *intrinsics,
+ int bundle_constraints = BUNDLE_NO_CONSTRAINTS);
/*!
Refine camera poses and 3D coordinates using bundle adjustment.
diff --git a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
index 6319846a079..658f65c1367 100644
--- a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
+++ b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
@@ -124,20 +124,16 @@ void CameraIntrinsics::ApplyIntrinsics(double normalized_x,
double normalized_y,
double *image_x,
double *image_y) const {
- double x = normalized_x;
- double y = normalized_y;
-
- // Apply distortion to the normalized points to get (xd, yd).
- double r2 = x*x + y*y;
- double r4 = r2 * r2;
- double r6 = r4 * r2;
- double r_coeff = (1 + k1_*r2 + k2_*r4 + k3_*r6);
- double xd = x * r_coeff + 2*p1_*x*y + p2_*(r2 + 2*x*x);
- double yd = y * r_coeff + 2*p2_*x*y + p1_*(r2 + 2*y*y);
-
- // Apply focal length and principal point to get the final image coordinates.
- *image_x = focal_length_x() * xd + principal_point_x();
- *image_y = focal_length_y() * yd + principal_point_y();
+ ApplyRadialDistortionCameraIntrinsics(focal_length_x(),
+ focal_length_y(),
+ principal_point_x(),
+ principal_point_y(),
+ k1(), k2(), k3(),
+ p1(), p2(),
+ normalized_x,
+ normalized_y,
+ image_x,
+ image_y);
}
struct InvertIntrinsicsCostFunction {
diff --git a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h
index e0556674ad5..b51b28a4bfb 100644
--- a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h
+++ b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h
@@ -159,6 +159,37 @@ class CameraIntrinsics {
std::ostream& operator <<(std::ostream &os,
const CameraIntrinsics &intrinsics);
+// Apply camera intrinsics to the normalized point to get image coordinates.
+// This applies the radial lens distortion to a point which is in normalized
+// camera coordinates (i.e. the principal point is at (0, 0)) to get image
+// coordinates in pixels. Templated for use with autodifferentiation.
+template <typename T>
+inline void ApplyRadialDistortionCameraIntrinsics(T focal_length_x,
+ T focal_length_y,
+ T principal_point_x,
+ T principal_point_y,
+ T k1, T k2, T k3,
+ T p1, T p2,
+ T normalized_x,
+ T normalized_y,
+ T *image_x,
+ T *image_y) {
+ T x = normalized_x;
+ T y = normalized_y;
+
+ // Apply distortion to the normalized points to get (xd, yd).
+ T r2 = x*x + y*y;
+ T r4 = r2 * r2;
+ T r6 = r4 * r2;
+ T r_coeff = (T(1) + k1*r2 + k2*r4 + k3*r6);
+ T xd = x * r_coeff + T(2)*p1*x*y + p2*(r2 + T(2)*x*x);
+ T yd = y * r_coeff + T(2)*p2*x*y + p1*(r2 + T(2)*y*y);
+
+ // Apply focal length and principal point to get the final image coordinates.
+ *image_x = focal_length_x * xd + principal_point_x;
+ *image_y = focal_length_y * yd + principal_point_y;
+}
+
} // namespace libmv
#endif // LIBMV_SIMPLE_PIPELINE_CAMERA_INTRINSICS_H_
diff --git a/extern/libmv/libmv/simple_pipeline/intersect.cc b/extern/libmv/libmv/simple_pipeline/intersect.cc
index 0c2f744dc1c..660b4b21ece 100644
--- a/extern/libmv/libmv/simple_pipeline/intersect.cc
+++ b/extern/libmv/libmv/simple_pipeline/intersect.cc
@@ -18,6 +18,8 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
+#include "libmv/simple_pipeline/intersect.h"
+
#include "libmv/base/vector.h"
#include "libmv/logging/logging.h"
#include "libmv/multiview/projection.h"
@@ -26,39 +28,41 @@
#include "libmv/multiview/projection.h"
#include "libmv/numeric/numeric.h"
#include "libmv/numeric/levenberg_marquardt.h"
-#include "libmv/simple_pipeline/intersect.h"
#include "libmv/simple_pipeline/reconstruction.h"
#include "libmv/simple_pipeline/tracks.h"
+#include "ceres/ceres.h"
+
namespace libmv {
namespace {
-struct EuclideanIntersectCostFunction {
+class EuclideanIntersectCostFunctor {
public:
- typedef Vec FMatrixType;
- typedef Vec3 XMatrixType;
+ EuclideanIntersectCostFunctor(const Marker &marker,
+ const EuclideanCamera &camera)
+ : marker_(marker), camera_(camera) {}
- EuclideanIntersectCostFunction(const vector<Marker> &markers,
- const EuclideanReconstruction &reconstruction)
- : markers(markers),
- reconstruction(reconstruction) {}
+ template<typename T>
+ bool operator()(const T *X, T *residuals) const {
+ typedef Eigen::Matrix<T, 3, 3> Mat3;
+ typedef Eigen::Matrix<T, 3, 1> Vec3;
- Vec operator()(const Vec3 &X) const {
- Vec residuals(2 * markers.size());
- residuals.setZero();
- for (int i = 0; i < markers.size(); ++i) {
- const EuclideanCamera &camera =
- *reconstruction.CameraForImage(markers[i].image);
- Vec3 projected = camera.R * X + camera.t;
- projected /= projected(2);
- residuals[2*i + 0] = projected(0) - markers[i].x;
- residuals[2*i + 1] = projected(1) - markers[i].y;
- }
- return residuals;
+ Vec3 x(X);
+ Mat3 R(camera_.R.cast<T>());
+ Vec3 t(camera_.t.cast<T>());
+
+ Vec3 projected = R * x + t;
+ projected /= projected(2);
+
+ residuals[0] = projected(0) - T(marker_.x);
+ residuals[1] = projected(1) - T(marker_.y);
+
+ return true;
}
- const vector<Marker> &markers;
- const EuclideanReconstruction &reconstruction;
+
+ const Marker &marker_;
+ const EuclideanCamera &camera_;
};
} // namespace
@@ -95,13 +99,35 @@ bool EuclideanIntersect(const vector<Marker> &markers,
Xp /= Xp(3);
Vec3 X = Xp.head<3>();
- typedef LevenbergMarquardt<EuclideanIntersectCostFunction> Solver;
+ ceres::Problem problem;
- EuclideanIntersectCostFunction triangulate_cost(markers, *reconstruction);
- Solver::SolverParameters params;
- Solver solver(triangulate_cost);
+ for (int i = 0; i < markers.size(); ++i) {
+ const Marker &marker = markers[i];
+ const EuclideanCamera &camera =
+ *reconstruction->CameraForImage(marker.image);
+
+ problem.AddResidualBlock(
+ new ceres::AutoDiffCostFunction<
+ EuclideanIntersectCostFunctor,
+ 2, /* num_residuals */
+ 3>(new EuclideanIntersectCostFunctor(marker, camera)),
+ NULL,
+ &X(0));
+ }
- Solver::Results results = solver.minimize(params, &X);
+ // Configure the solve.
+ ceres::Solver::Options solver_options;
+ solver_options.linear_solver_type = ceres::DENSE_NORMAL_CHOLESKY;
+ solver_options.max_num_iterations = 50;
+ solver_options.update_state_every_iteration = true;
+ solver_options.parameter_tolerance = 1e-16;
+ solver_options.function_tolerance = 1e-16;
+
+ // Run the solve.
+ ceres::Solver::Summary summary;
+ ceres::Solve(solver_options, &problem, &summary);
+
+ VLOG(1) << "Summary:\n" << summary.FullReport();
// Try projecting the point; make sure it's in front of everyone.
for (int i = 0; i < cameras.size(); ++i) {
diff --git a/extern/libmv/libmv/simple_pipeline/modal_solver.cc b/extern/libmv/libmv/simple_pipeline/modal_solver.cc
index bb49b30dbce..169c53bb601 100644
--- a/extern/libmv/libmv/simple_pipeline/modal_solver.cc
+++ b/extern/libmv/libmv/simple_pipeline/modal_solver.cc
@@ -18,11 +18,14 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
+#include "libmv/simple_pipeline/modal_solver.h"
+
#include <cstdio>
+#include "ceres/ceres.h"
+#include "ceres/rotation.h"
#include "libmv/logging/logging.h"
-#include "libmv/simple_pipeline/modal_solver.h"
-#include "libmv/simple_pipeline/rigid_registration.h"
+#include "libmv/multiview/panography.h"
#ifdef _MSC_VER
# define snprintf _snprintf
@@ -30,7 +33,8 @@
namespace libmv {
-static void ProjectMarkerOnSphere(Marker &marker, Vec3 &X) {
+namespace {
+void ProjectMarkerOnSphere(Marker &marker, Vec3 &X) {
X(0) = marker.x;
X(1) = marker.y;
X(2) = 1.0;
@@ -38,18 +42,60 @@ static void ProjectMarkerOnSphere(Marker &marker, Vec3 &X) {
X *= 5.0 / X.norm();
}
-static void ModalSolverLogProress(ProgressUpdateCallback *update_callback,
- double progress)
+void ModalSolverLogProress(ProgressUpdateCallback *update_callback,
+ double progress)
{
if (update_callback) {
char message[256];
- snprintf(message, sizeof(message), "Solving progress %d%%", (int)(progress * 100));
+ snprintf(message, sizeof(message), "Solving progress %d%%",
+ (int)(progress * 100));
update_callback->invoke(progress, message);
}
}
+struct ModalReprojectionError {
+ ModalReprojectionError(double observed_x, double observed_y, Vec3 &bundle)
+ : observed_x(observed_x), observed_y(observed_y), bundle(bundle) { }
+
+ template <typename T>
+ bool operator()(const T* quaternion, // Rotation quaternion
+ T* residuals) const {
+
+ T R[9];
+ ceres::QuaternionToRotation(quaternion, R);
+
+ // Convert bundle position from double to T.
+ T X[3];
+ X[0] = T(bundle(0));
+ X[1] = T(bundle(1));
+ X[2] = T(bundle(2));
+
+ // Compute projective coordinates: x = RX.
+ T x[3];
+ x[0] = R[0]*X[0] + R[3]*X[1] + R[6]*X[2];
+ x[1] = R[1]*X[0] + R[4]*X[1] + R[7]*X[2];
+ x[2] = R[2]*X[0] + R[5]*X[1] + R[8]*X[2];
+
+ // Compute normalized coordinates: x /= x[2].
+ T xn = x[0] / x[2];
+ T yn = x[1] / x[2];
+
+ // The error is the difference between reprojected
+ // and observed marker position.
+ residuals[0] = xn - T(observed_x);
+ residuals[1] = yn - T(observed_y);
+
+ return true;
+ }
+
+ double observed_x;
+ double observed_y;
+ Vec3 bundle;
+};
+} // namespace
+
void ModalSolver(Tracks &tracks,
EuclideanReconstruction *reconstruction,
ProgressUpdateCallback *update_callback) {
@@ -59,58 +105,132 @@ void ModalSolver(Tracks &tracks,
LG << "Max image: " << max_image;
LG << "Max track: " << max_track;
- Mat3 R = Mat3::Identity();
+ // For minimization we're using quaternions.
+ Vec3 zero_rotation = Vec3::Zero();
+ Vec4 quaternion;
+ ceres::AngleAxisToQuaternion(&zero_rotation(0), &quaternion(0));
for (int image = 0; image <= max_image; ++image) {
vector<Marker> all_markers = tracks.MarkersInImage(image);
ModalSolverLogProress(update_callback, (float) image / max_image);
- // Skip empty frames without doing anything
+ // Skip empty images without doing anything.
if (all_markers.size() == 0) {
- LG << "Skipping frame: " << image;
+ LG << "Skipping image: " << image;
continue;
}
- vector<Vec3> points, reference_points;
+ // STEP 1: Estimate rotation analytically.
+ Mat3 current_R;
+ ceres::QuaternionToRotation(&quaternion(0), &current_R(0, 0));
+
+ // Construct point cloud for current and previous images,
+ // using markers appear at current image for which we know
+ // 3D positions.
+ Mat x1, x2;
+ for (int i = 0; i < all_markers.size(); ++i) {
+ Marker &marker = all_markers[i];
+ EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
+ if (point) {
+ Vec3 X;
+ ProjectMarkerOnSphere(marker, X);
- // Cnstruct pairs of markers from current and previous image,
- // to reproject them and find rigid transformation between
- // previous and current image
- for (int track = 0; track <= max_track; ++track) {
- EuclideanPoint *point = reconstruction->PointForTrack(track);
+ int last_column = x1.cols();
+ x1.conservativeResize(3, last_column + 1);
+ x2.conservativeResize(3, last_column + 1);
- if (point) {
- Marker marker = tracks.MarkerInImageForTrack(image, track);
+ x1.col(last_column) = current_R * point->X;
+ x2.col(last_column) = X;
+ }
+ }
- if (marker.image == image) {
- Vec3 X;
+ if (x1.cols() >= 2) {
+ Mat3 delta_R;
- LG << "Use track " << track << " for rigid registration between image " <<
- image - 1 << " and " << image;
+ // Compute delta rotation matrix for two point clouds.
+ // Could be a bit confusing at first glance, but order
+ // of clouds is indeed so.
+ GetR_FixedCameraCenter(x2, x1, 1.0, &delta_R);
- ProjectMarkerOnSphere(marker, X);
+ // Convert delta rotation form matrix to final image
+ // rotation stored in a quaternion
+ Vec3 delta_angle_axis;
+ ceres::RotationMatrixToAngleAxis(&delta_R(0, 0), &delta_angle_axis(0));
- points.push_back(point->X);
- reference_points.push_back(X);
- }
+ Vec3 current_angle_axis;
+ ceres::QuaternionToAngleAxis(&quaternion(0), &current_angle_axis(0));
+
+ Vec3 angle_axis = current_angle_axis + delta_angle_axis;
+
+ ceres::AngleAxisToQuaternion(&angle_axis(0), &quaternion(0));
+
+ LG << "Analytically computed quaternion "
+ << quaternion.transpose();
+ }
+
+ // STEP 2: Refine rotation with Ceres.
+ ceres::Problem problem;
+
+ ceres::LocalParameterization* quaternion_parameterization =
+ new ceres::QuaternionParameterization;
+
+ int num_residuals = 0;
+ for (int i = 0; i < all_markers.size(); ++i) {
+ Marker &marker = all_markers[i];
+ EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
+
+ if (point) {
+ problem.AddResidualBlock(new ceres::AutoDiffCostFunction<
+ ModalReprojectionError,
+ 2, /* num_residuals */
+ 4>(new ModalReprojectionError(marker.x, marker.y,
+ point->X)),
+ NULL,
+ &quaternion(0));
+ num_residuals++;
+
+ problem.SetParameterization(&quaternion(0),
+ quaternion_parameterization);
}
}
- if (points.size()) {
- // Find rigid delta transformation to current image
- RigidRegistration(reference_points, points, R);
+ LG << "Number of residuals: " << num_residuals;
+
+ if (num_residuals) {
+ // Configure the solve.
+ ceres::Solver::Options solver_options;
+ solver_options.linear_solver_type = ceres::DENSE_NORMAL_CHOLESKY;
+ solver_options.max_num_iterations = 50;
+ solver_options.update_state_every_iteration = true;
+ solver_options.gradient_tolerance = 1e-36;
+ solver_options.parameter_tolerance = 1e-36;
+ solver_options.function_tolerance = 1e-36;
+
+ // Run the solve.
+ ceres::Solver::Summary summary;
+ ceres::Solve(solver_options, &problem, &summary);
+
+ LG << "Summary:\n" << summary.FullReport();
+ LG << "Refined quaternion " << quaternion.transpose();
}
+ // Convert quaternion to rotation matrix.
+ Mat3 R;
+ ceres::QuaternionToRotation(&quaternion(0), &R(0, 0));
reconstruction->InsertCamera(image, R, Vec3::Zero());
- // Review if there's new tracks for which position might be reconstructed
+ // STEP 3: reproject all new markers appeared at image
+
+ // Check if there're new markers appeared on current image
+ // and reproject them on sphere to obtain 3D position/
for (int track = 0; track <= max_track; ++track) {
if (!reconstruction->PointForTrack(track)) {
Marker marker = tracks.MarkerInImageForTrack(image, track);
if (marker.image == image) {
- // New track appeared on this image, project it's position onto sphere
+ // New track appeared on this image,
+ // project it's position onto sphere.
LG << "Projecting track " << track << " at image " << image;
diff --git a/extern/libmv/libmv/simple_pipeline/pipeline.cc b/extern/libmv/libmv/simple_pipeline/pipeline.cc
index efceda5c455..463738e42bb 100644
--- a/extern/libmv/libmv/simple_pipeline/pipeline.cc
+++ b/extern/libmv/libmv/simple_pipeline/pipeline.cc
@@ -300,7 +300,7 @@ double InternalReprojectionError(const Tracks &image_tracks,
ex,
ey,
sqrt(ex*ex + ey*ey));
- LG << line;
+ VLOG(1) << line;
total_error += sqrt(ex*ex + ey*ey);
}
diff --git a/extern/libmv/libmv/simple_pipeline/rigid_registration.cc b/extern/libmv/libmv/simple_pipeline/rigid_registration.cc
deleted file mode 100644
index f7cb1e66e7d..00000000000
--- a/extern/libmv/libmv/simple_pipeline/rigid_registration.cc
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright (c) 2012 libmv authors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-// IN THE SOFTWARE.
-
-#include "libmv/simple_pipeline/rigid_registration.h"
-#include "libmv/numeric/levenberg_marquardt.h"
-
-namespace libmv {
-
-template<class RigidTransformation>
-struct RigidRegistrationCostFunction {
- public:
- typedef Vec FMatrixType;
- typedef RigidTransformation XMatrixType;
-
- RigidRegistrationCostFunction(const vector<Vec3> &reference_points,
- const vector<Vec3> &points):
- reference_points_(reference_points),
- points_(points) {}
-
- Vec CalculateResiduals(const Mat3 &R,
- const Vec3 &S,
- const Vec3 &t) const {
- Vec residuals(points_.size());
- residuals.setZero();
-
- // Convert scale vector to matrix
- Mat3 SMat = Mat3::Identity();
- SMat(0, 0) *= S(0);
- SMat(1, 1) *= S(1);
- SMat(2, 2) *= S(2);
-
- for (int i = 0; i < points_.size(); i++) {
- Vec3 transformed_point = R * SMat * points_[i] + t;
-
- double norm = (transformed_point - reference_points_[i]).norm();
-
- residuals(i) = norm * norm;
- }
-
- return residuals;
- }
-
- Vec operator()(const Vec9 &RSt) const {
- Mat3 R = RotationFromEulerVector(RSt.head<3>());
- Vec3 S = RSt.segment<3>(3);
- Vec3 t = RSt.tail<3>();
-
- return CalculateResiduals(R, S, t);
- }
-
- Vec operator()(const Vec3 &euler) const {
- Mat3 R = RotationFromEulerVector(euler);
-
- return CalculateResiduals(R, Vec3(1.0, 1.0, 1.0), Vec3::Zero());
- }
-
- Vec operator()(const Vec6 &Rt) const {
- Mat3 R = RotationFromEulerVector(Rt.head<3>());
- Vec3 t = Rt.tail<3>();
-
- return CalculateResiduals(R, Vec3(1.0, 1.0, 1.0), t);
- }
-
- private:
- vector<Vec3> reference_points_;
- vector<Vec3> points_;
-};
-
-static double RigidRegistrationError(const vector<Vec3> &reference_points,
- const vector<Vec3> &points,
- const Mat3 &R,
- const Vec3 &S,
- const Vec3 &t) {
- double error = 0.0;
-
- Mat3 SMat = Mat3::Identity();
- SMat(0, 0) *= S(0);
- SMat(1, 1) *= S(1);
- SMat(2, 2) *= S(2);
-
- for (int i = 0; i < points.size(); i++) {
- Vec3 new_point = R * SMat * points[i] + t;
-
- double norm = (new_point - reference_points[i]).norm();
- error += norm * norm;
- }
- error /= points.size();
-
- return error;
-}
-
-double RigidRegistration(const vector<Vec3> &reference_points,
- const vector<Vec3> &points,
- Mat3 &R,
- Vec3 &S,
- Vec3 &t) {
- typedef LevenbergMarquardt<RigidRegistrationCostFunction <Vec9> > Solver;
-
- RigidRegistrationCostFunction<Vec9> rigidregistration_cost(reference_points, points);
- Solver solver(rigidregistration_cost);
-
- Vec9 RSt = Vec9::Zero();
-
- RSt(3) = RSt(4) = RSt(5) = 1.0;
-
- Solver::SolverParameters params;
- /*Solver::Results results = */ solver.minimize(params, &RSt);
- /* TODO(sergey): better error handling here */
-
- LG << "Rigid registration completed, rotation is:" << RSt.head<3>().transpose()
- << ", scale is " << RSt.segment<3>(3).transpose()
- << ", translation is " << RSt.tail<3>().transpose();
-
- // Decompose individual rotation and translation
- R = RotationFromEulerVector(RSt.head<3>());
- S = RSt.segment<3>(3);
- t = RSt.tail<3>();
-
- return RigidRegistrationError(reference_points, points, R, S, t);
-}
-
-double RigidRegistration(const vector<Vec3> &reference_points,
- const vector<Vec3> &points,
- Mat3 &R,
- Vec3 &t) {
- typedef LevenbergMarquardt<RigidRegistrationCostFunction <Vec6> > Solver;
-
- RigidRegistrationCostFunction<Vec6> rigidregistration_cost(reference_points, points);
- Solver solver(rigidregistration_cost);
-
- Vec6 Rt = Vec6::Zero();
- Solver::SolverParameters params;
- /*Solver::Results results = */solver.minimize(params, &Rt);
- /* TODO(sergey): better error handling here */
-
- LG << "Rigid registration completed, rotation is:" << Rt.head<3>().transpose()
- << ", translation is " << Rt.tail<3>().transpose();
-
- R = RotationFromEulerVector(Rt.head<3>());
- t = Rt.tail<3>();
-
- return RigidRegistrationError(reference_points, points, R, Vec3(1.0, 1.0, 1.0), t);
-}
-
-double RigidRegistration(const vector<Vec3> &reference_points,
- const vector<Vec3> &points,
- Mat3 &R) {
- typedef LevenbergMarquardt<RigidRegistrationCostFunction <Vec3> > Solver;
-
- RigidRegistrationCostFunction<Vec3> rigidregistration_cost(reference_points, points);
- Solver solver(rigidregistration_cost);
-
- Vec3 euler = Vec3::Zero();
- Solver::SolverParameters params;
- /*Solver::Results results = */solver.minimize(params, &euler);
- /* TODO(sergey): better error handling here */
-
- LG << "Rigid registration completed, rotation is:" << euler.transpose();
-
- R = RotationFromEulerVector(euler);
-
- return RigidRegistrationError(reference_points, points, R, Vec3(1.0, 1.0, 1.0), Vec3::Zero());
-}
-
-} // namespace libmv
diff --git a/extern/libmv/libmv/simple_pipeline/rigid_registration.h b/extern/libmv/libmv/simple_pipeline/rigid_registration.h
deleted file mode 100644
index 21ea57af507..00000000000
--- a/extern/libmv/libmv/simple_pipeline/rigid_registration.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) 2012 libmv authors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-// IN THE SOFTWARE.
-
-#ifndef LIBMV_SIMPLE_PIPELINE_RIGID_REGISTRATION_H_
-#define LIBMV_SIMPLE_PIPELINE_RIGID_REGISTRATION_H_
-
-#include "libmv/base/vector.h"
-#include "libmv/numeric/numeric.h"
-
-namespace libmv {
-
-/*!
- Searched for an affine transformation of rigid 3D object defined by it's
- vertices positions from it's current state called points to it's desired
- state called reference points.
-
- Returns rotation matrix, per-component scale vector and translation which
- transforms points to the mot close state to reference_points.
-
- Return value is an average squared distance between reference state
- and transformed one.
-
- Minimzation of distance between point pairs is used to register such a
- rigid transformation and algorithm assumes that pairs of points are
- defined by point's index in a vector, so points with the same index
- belongs to the same pair.
- */
-double RigidRegistration(const vector<Vec3> &reference_points,
- const vector<Vec3> &points,
- Mat3 &R,
- Vec3 &S,
- Vec3 &t);
-
-/*!
- * Same as RigidRegistration but provides registration of rotation and translation only
- */
-double RigidRegistration(const vector<Vec3> &reference_points,
- const vector<Vec3> &points,
- Mat3 &R,
- Vec3 &t);
-
-/*!
- * Same as RigidRegistration but provides registration of rotation only
- */
-double RigidRegistration(const vector<Vec3> &reference_points,
- const vector<Vec3> &points,
- Mat3 &R);
-
-} // namespace libmv
-
-#endif // LIBMV_SIMPLE_PIPELINE_RIGID_REGISTRATION_H_
diff --git a/extern/libmv/patches/series b/extern/libmv/patches/series
index 1db7983fdd0..e69de29bb2d 100644
--- a/extern/libmv/patches/series
+++ b/extern/libmv/patches/series
@@ -1 +0,0 @@
-v3d_verbosity.patch
diff --git a/extern/libmv/patches/v3d_verbosity.patch b/extern/libmv/patches/v3d_verbosity.patch
deleted file mode 100644
index f5c6afbd0b5..00000000000
--- a/extern/libmv/patches/v3d_verbosity.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff --git a/src/libmv/simple_pipeline/bundle.cc b/src/libmv/simple_pipeline/bundle.cc
-index fa0b6cc..d382cd5 100644
---- a/src/libmv/simple_pipeline/bundle.cc
-+++ b/src/libmv/simple_pipeline/bundle.cc
-@@ -194,7 +194,6 @@ void EuclideanBundleCommonIntrinsics(const Tracks &tracks,
- double v3d_inlier_threshold = 500000.0;
-
- // Finally, run the bundle adjustment.
-- V3D::optimizerVerbosenessLevel = 1;
- V3D::CommonInternalsMetricBundleOptimizer opt(v3d_bundle_intrinsics,
- v3d_inlier_threshold,
- v3d_K,
diff --git a/extern/libmv/third_party/ceres/CMakeLists.txt b/extern/libmv/third_party/ceres/CMakeLists.txt
index f0c0a4b269f..b71fe1d5cdb 100644
--- a/extern/libmv/third_party/ceres/CMakeLists.txt
+++ b/extern/libmv/third_party/ceres/CMakeLists.txt
@@ -54,6 +54,7 @@ set(SRC
internal/ceres/compressed_row_sparse_matrix.cc
internal/ceres/conditioned_cost_function.cc
internal/ceres/conjugate_gradients_solver.cc
+ internal/ceres/coordinate_descent_minimizer.cc
internal/ceres/corrector.cc
internal/ceres/cxsparse.cc
internal/ceres/dense_normal_cholesky_solver.cc
@@ -71,11 +72,18 @@ set(SRC
internal/ceres/linear_least_squares_problems.cc
internal/ceres/linear_operator.cc
internal/ceres/linear_solver.cc
+ internal/ceres/line_search.cc
+ internal/ceres/line_search_direction.cc
+ internal/ceres/line_search_minimizer.cc
internal/ceres/local_parameterization.cc
internal/ceres/loss_function.cc
+ internal/ceres/low_rank_inverse_hessian.cc
+ internal/ceres/minimizer.cc
internal/ceres/normal_prior.cc
+ internal/ceres/parameter_block_ordering.cc
internal/ceres/partitioned_matrix_view.cc
- internal/ceres/polynomial_solver.cc
+ internal/ceres/polynomial.cc
+ internal/ceres/preconditioner.cc
internal/ceres/problem.cc
internal/ceres/problem_impl.cc
internal/ceres/program.cc
@@ -84,7 +92,7 @@ set(SRC
internal/ceres/runtime_numeric_diff_cost_function.cc
internal/ceres/schur_complement_solver.cc
internal/ceres/schur_eliminator.cc
- internal/ceres/schur_ordering.cc
+ internal/ceres/schur_jacobi_preconditioner.cc
internal/ceres/scratch_evaluate_preparer.cc
internal/ceres/solver.cc
internal/ceres/solver_impl.cc
@@ -99,26 +107,34 @@ set(SRC
internal/ceres/types.cc
internal/ceres/visibility_based_preconditioner.cc
internal/ceres/visibility.cc
+ internal/ceres/wall_time.cc
include/ceres/autodiff_cost_function.h
include/ceres/ceres.h
include/ceres/conditioned_cost_function.h
include/ceres/cost_function.h
+ include/ceres/cost_function_to_functor.h
include/ceres/crs_matrix.h
+ include/ceres/dynamic_autodiff_cost_function.h
include/ceres/fpclassify.h
+ include/ceres/gradient_checker.h
include/ceres/internal/autodiff.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/scoped_ptr.h
+ include/ceres/internal/variadic_evaluate.h
include/ceres/iteration_callback.h
include/ceres/jet.h
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
@@ -141,6 +157,7 @@ set(SRC
internal/ceres/compressed_row_jacobian_writer.h
internal/ceres/compressed_row_sparse_matrix.h
internal/ceres/conjugate_gradients_solver.h
+ internal/ceres/coordinate_descent_minimizer.h
internal/ceres/corrector.h
internal/ceres/cxsparse.h
internal/ceres/dense_jacobian_writer.h
@@ -150,6 +167,7 @@ set(SRC
internal/ceres/detect_structure.h
internal/ceres/dogleg_strategy.h
internal/ceres/evaluator.h
+ internal/ceres/execution_summary.h
internal/ceres/file.h
internal/ceres/gradient_checking_cost_function.h
internal/ceres/graph_algorithms.h
@@ -161,13 +179,19 @@ set(SRC
internal/ceres/linear_least_squares_problems.h
internal/ceres/linear_operator.h
internal/ceres/linear_solver.h
+ internal/ceres/line_search_direction.h
+ internal/ceres/line_search.h
+ internal/ceres/line_search_minimizer.h
+ internal/ceres/low_rank_inverse_hessian.h
internal/ceres/map_util.h
internal/ceres/matrix_proto.h
internal/ceres/minimizer.h
internal/ceres/mutex.h
internal/ceres/parameter_block.h
+ internal/ceres/parameter_block_ordering.h
internal/ceres/partitioned_matrix_view.h
- internal/ceres/polynomial_solver.h
+ internal/ceres/polynomial.h
+ internal/ceres/preconditioner.h
internal/ceres/problem_impl.h
internal/ceres/program_evaluator.h
internal/ceres/program.h
@@ -178,7 +202,7 @@ set(SRC
internal/ceres/schur_complement_solver.h
internal/ceres/schur_eliminator.h
internal/ceres/schur_eliminator_impl.h
- internal/ceres/schur_ordering.h
+ internal/ceres/schur_jacobi_preconditioner.h
internal/ceres/scratch_evaluate_preparer.h
internal/ceres/solver_impl.h
internal/ceres/sparse_matrix.h
@@ -192,6 +216,7 @@ set(SRC
internal/ceres/trust_region_strategy.h
internal/ceres/visibility_based_preconditioner.h
internal/ceres/visibility.h
+ internal/ceres/wall_time.h
)
#if(FALSE)
@@ -236,8 +261,15 @@ add_definitions(
-DCERES_NO_CXSPARSE
-DCERES_NO_PROTOCOL_BUFFERS
-DCERES_RESTRICT_SCHUR_SPECIALIZATION
+ -DCERES_HAVE_RWLOCK
)
+if(WITH_OPENMP)
+ add_definitions(
+ -DCERES_USE_OPENMP
+ )
+endif()
+
if(MSVC10)
add_definitions(
-D"CERES_HASH_NAMESPACE_START=namespace std {"
diff --git a/extern/libmv/third_party/ceres/ChangeLog b/extern/libmv/third_party/ceres/ChangeLog
index 8b84328cf98..ebfb771be02 100644
--- a/extern/libmv/third_party/ceres/ChangeLog
+++ b/extern/libmv/third_party/ceres/ChangeLog
@@ -1,524 +1,572 @@
-commit 552f9f85bba89f00ca307bc18fbda1dff23bd0e4
+commit d2a5195b512164fec286c6a52b40d7766977caa3
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Fri Aug 31 07:27:22 2012 -0700
+Date: Sun Feb 24 15:09:17 2013 -0800
- Various minor bug fixes to the solver logic.
+ Version history update.
- 1. CostFunction returning false is handled better.
- If only the cost is being evaluated, it is possible to
- use the false value as an infinite value signal/outside
- a region of validity. This allows a weak form of constraint
- handling. Useful for example in handling infinities.
+ Change-Id: I477ec05a78ca4cd735a525253c9b6adfa3bddea7
+
+commit 2160c5b757c44206c6face6ca62d381f1db7a291
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Sun Feb 24 14:15:45 2013 -0800
+
+ Minor release script fixes.
- 2. Changed the way how the slop around zero when model_cost
- is larger than the current cost. Relative instead of absolute
- tolerances are used. The same logic is propagated how the
- corresponding clamping of the model_cost is done.
+ Change-Id: Ifd0a7f4f584c85d4d9574eca46094b372a8d7aff
+
+commit b53c9667f508c125b8aa833e7a063fa44ef8a98e
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Mon Feb 25 01:14:26 2013 +0600
+
+ Solve No Previous Prototype GCC warning
- 3. Fixed a minor indexing bug in nist.cc.
+ In some cases there were missing includes of own
+ header files from implementation files.
- 4. Some minor logging fixes to nist.cc to make it more
- compatible with the rest of ceres.
+ In other cases moved function which are only used
+ within single file into an anonymous namespace.
- Together these changes, take the successful solve count from
- 41/54 to 46/54 and eliminate all NUMERICAL_FAILURE problems.
+ Change-Id: I2c6b411bcfbc521e2a5f21265dc8e009a548b1c8
+
+commit 267ccc45a3e875bf87832a8ad615be690b4926d3
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Mon Feb 25 01:04:16 2013 +0600
+
+ Fix for MinGW build on Windows
- Change-Id: If94170ea4731af5b243805c0200963dd31aa94a7
+ GG_LONGLONG and GG_ULONGLONG shall use LL and ULL suffixes,
+ since MinGW is actuall a GCC compiler.
+
+ Solved by checking whether compilation happens with MinGW
+ or not using standard MinGW's __MINGW32__ and __MINGW64__
+ definitions.
+
+ Change-Id: I789b34f6342a56ba42f4b280f7242700022ab7a1
-commit 0b776b5cc9634d3b88d623905b96006f7647ce3e
+commit 509f68cfe3fd13b794c4e67ff38c761407c858cf
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Aug 30 15:26:17 2012 -0700
+Date: Wed Feb 20 01:39:03 2013 -0800
- Update docs.
+ Problem::Evaluate implementation.
+
+ 1. Add Problem::Evaluate and tests.
+ 2. Remove Solver::Summary::initial/final_*
+ 3. Remove Solver::Options::return_* members.
+ 4. Various cpplint cleanups.
- Change-Id: I69d50bcd37aed3bea2190ca614f023e83172901b
+ Change-Id: I4266de53489896f72d9c6798c5efde6748d68a47
-commit 2d7176ad7c8fb7238ca8abd6de73415d95877494
-Author: Petter Strandmark <petter.strandmark@gmail.com>
-Date: Thu Aug 30 19:51:24 2012 -0700
+commit d4a0bf86d688d1b68e00ff302858de5a4e0d9727
+Author: Keir Mierle <mierle@gmail.com>
+Date: Sun Feb 24 10:35:44 2013 -0800
- max_consecutive_nonmonotonic_steps should be int
+ Fix threading build on Windows.
+
+ On Windows, including the "windows.h" header defines an enormous number of
+ symbols; some of which are macros with common names. In particular, "ERROR" and
+ "min" and "max" get defined. This causes clashes when user code references
+ these names in a context other than the intended use in windows.h.
+
+ To deal with this, the Microsoft engineers added the ability to control the
+ definition of these symbols by adding extra defines. In particular, including
+ windows.h in the following way
- Found via Visual Studio warning.
+ #define NOGDI
+ #define NOMINMAX
- Change-Id: Id2cd7de562dfc8cd35df5d5f5220dd2d7350eb2c
+ will reduce the number of macros defined. This way they will not conflict with
+ other uses in Ceres. For example, numeric_limits<double>::max() is impossible
+ to call without defining NOMINMAX.
+
+ Change-Id: I166f5d3bb6dc0e2e4b2ebf800fb19e49206f7874
-commit 1a89bcc94e88933f89b20427a45bc40cdd23c056
+commit beb4505311011130a7e54632137b0fbb5824cc9b
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Aug 30 15:26:17 2012 -0700
+Date: Fri Feb 22 13:37:01 2013 -0800
- Better reporting on the NIST problems.
+ Minor fixes
+
+ Based on William Rucklidge's review, including
+ a nasty bug in parameter block removal.
- Change-Id: I7cf774ec3242c0612dbe52fc233c3fc6cff3f031
+ Change-Id: I3a692e589f600ff560ecae9fa85bb0b76063d403
-commit ea11704857a1e4a735e096896e4d775d83981499
+commit 9a88bd7c4b40e2a1e0cd9b0dc09a3517c467e04e
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Aug 29 18:18:48 2012 -0700
+Date: Tue Feb 19 13:09:12 2013 -0800
- Basic harness for testing NIST problems.
+ Minor bug fixes
- Change-Id: I5baaa24dbf0506ceedf4a9be4ed17c84974d71a1
+ Change-Id: I94e4521adf76a6c77db954c4a8955168e9d37b55
-commit 98bf14d2b95386c2c4a6c29154637943dae4c36c
+commit 956ed7e8f2054623615e6ae3601055d613897f26
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Aug 30 10:26:44 2012 -0700
+Date: Tue Feb 19 07:06:15 2013 -0800
- Miscellaneous fixes.
+ Various minor fixes.
+
+ 1. Unused variable warnings and fixes.
+ 2. Minor documentation update.
- Change-Id: I521e11f2d20bf24960bbc6b5dab4ec8bb1503d23
+ Change-Id: I815588a5806df1030a7c8750f4fb594c503f8998
-commit 1e3cbd9a4442cdd8fda43a7fb452f19dac8c74af
-Author: Petter Strandmark <strandmark@google.com>
-Date: Wed Aug 29 09:39:56 2012 -0700
+commit 3e2c4ef9ad35e94198f4f3367b99fd91e26996a1
+Author: Keir Mierle <mierle@gmail.com>
+Date: Sun Feb 17 12:37:55 2013 -0800
- Caching the symbolic Cholesky factorization when using CXSparse
-
- Average factorization times for bundle adjustment test problem:
- SuiteSparse: 0.2794 s.
- CXSparse: 0.4039 s.
- CXSparse cached: 0.2399 s.
+ Add adapters for column/row-major matrices to rotation.h
- CXSparse will still be slower, though, because it has to compute
- the transpose and J^T * J.
+ This patch introduces a matrix wrapper (MatrixAdapter) that allows to
+ transparently pass pointers to row-major or column-major matrices
+ to the conversion functions.
- Change-Id: If9cdaa3dd520bee84b56e5fd4953b56a93db6bde
+ Change-Id: I7f1683a8722088cffcc542f593ce7eb46fca109b
-commit 8b64140878ccd1e183d3715c38942a81fdecefde
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Aug 29 05:41:22 2012 -0700
+commit 04938efe4bedec112083c5ceb227ba004f96bd01
+Author: Keir Mierle <mierle@gmail.com>
+Date: Sun Feb 17 12:37:55 2013 -0800
- Documentation update
+ Add support for removing parameter and residual blocks.
- Change-Id: I271a0422e7f6f42bcfd1dc6b5dc10c7a18f6a179
-
-commit a5353acd85a9fd19370b3d74035d87b0f0bac230
-Author: Petter Strandmark <petter.strandmark@gmail.com>
-Date: Tue Aug 28 18:16:41 2012 -0700
-
- Adding gflags include to test_util.cc
+ This adds support for removing parameter and residual blocks.
+ There are two modes of operation: in the first, removals of
+ paremeter blocks are expensive, since each remove requires
+ scanning all residual blocks to find ones that depend on the
+ removed parameter. In the other, extra memory is sacrificed to
+ maintain a list of the residuals a parameter block depends on,
+ removing the need to scan. In both cases, removing residual blocks
+ is fast.
- test_util seems to need gflags.
+ As a caveat, any removals destroys the ordering of the parameters,
+ so the residuals or jacobian returned from Solver::Solve() is
+ meaningless. There is some debate on the best way to handle this;
+ the details remain for a future change.
- Change-Id: I0c4757960f8ac69ad599c138aea58e3c88a4ea28
-
-commit 87ca1b2ba28ec512752bbcf5fc994ce1434eb765
-Author: Petter Strandmark <petter.strandmark@gmail.com>
-Date: Tue Aug 28 18:05:20 2012 -0700
-
- Changing random.h to use cstdlib for Windows compability.
+ This also adds some overhead, even in the case that fast removals
+ are not requested:
- As discussed with Sameer today.
+ - 1 int32 to each residual, to track its position in the program.
+ - 1 pointer to each parameter, to store the dependent residuals.
- Change-Id: If3d0284830c6591c71cc77b8400cafb45c0da61f
+ Change-Id: I71dcac8656679329a15ee7fc12c0df07030c12af
-commit aeb00a07323808a0a1816e733ad18a87d5109ea3
-Author: Petter Strandmark <strandmark@google.com>
-Date: Mon Aug 27 22:22:57 2012 -0700
+commit fa21df8cd969bb257b87c9ef7c0147d8d5ea8725
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Mon Feb 18 08:48:52 2013 -0800
- Removing gomp for Visual Studio
+ Add script for building documentation.
+
+ Update make_release
- Linking currently fails in Visual Studio due to a missing library
- "gomp.lib". This is not needed in Visual Studio. OpenMP works
- without it.
+ Minor documentation fixes.
- Change-Id: I39e204a8dd4f1b7425df7d4b222d86a8bb961432
+ Change-Id: I1248ec3f58be66b5929aee6f2aa392c15d53ed83
-commit 6f362464ba99b800494d2f15c27768a342ddaa68
-Author: Markus Moll <markus.moll@esat.kuleuven.be>
-Date: Tue Aug 28 01:03:38 2012 +0200
+commit 290b975d1d4eba44205bbeb0fa6b3ce8a6fa4a0c
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Sun Feb 17 16:50:37 2013 -0800
- Add some tests for DoglegStrategy.
+ Preconditioner refactoring.
- Not necessarily a complete set.
+ 1. Added a Preconditioner interface.
+ 2. SCHUR_JACOBI is now its own class and is independent of
+ SuiteSparse.
- Change-Id: I14eb3a38c6fe976c8212f3934655411b6d1e0aa4
+ Change-Id: Id912ab19cf3736e61d1b90ddaf5bfba33e877ec4
-commit 122cf836a6dc9726489ce2fbecc6143bddc1caaf
+commit d010de543530001fa917501a13ba02879c8ea52f
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Fri Aug 24 16:28:27 2012 -0700
+Date: Fri Feb 15 14:26:56 2013 -0800
- Documentation update.
+ Solver::Summary::FullReport() supports line search now.
- Change-Id: I0a3c5ae4bc981a8f5bdd5a8905f923dc5f09a024
+ Change-Id: Ib08d300198b85d9732cfb5785af4235ca4bd5226
-commit 69081719f73da8de2935774a42d237837a91952a
-Author: Keir Mierle <mierle@gmail.com>
-Date: Mon Aug 27 13:28:56 2012 -0700
+commit fbbea464d1c9575d8224220d3e61f92d93fe9739
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Fri Feb 15 11:25:03 2013 -0800
- Remove unnecessary overload for hash<>
+ Update documentation.
- The overload for pointers in hash tables was applied in normal
- usage of schur_ordering.cc. However, the tests did not include the
- overload since they only included collections_port.h. As a result,
- the routines in schur_ordering.cc were using a different hash
- function than that inside the tests.
-
- The fix is to remove the specialization. If this breaks one of the
- compiler configurations, we will find a workaround at that time.
-
- Change-Id: Idbf60415d5e2aec0c865b514ad0c577d21b91405
+ Change-Id: Idb03741fab9facbbbda85d5a82723f0b4c1c6c60
-commit 1762420b6ed76b1c4d30b913b2cac1927b666534
+commit 8e1f83c4c457fb7238eb342eab744c5570b73c4d
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Aug 22 10:01:31 2012 -0700
+Date: Fri Feb 15 08:35:40 2013 -0800
- Update changelog.
+ Speed up Problem construction and destruction.
- Change-Id: Idf5af69d5a9dbe35f58e30a8afcbfcd29bb7ebfe
+ Change-Id: I3147b0b60eedf40f8453d5a39ff04a572c445a2f
-commit 976ab7aca908309b8282cb40bc080ca859136854
-Author: Keir Mierle <mierle@gmail.com>
-Date: Thu Aug 23 18:21:36 2012 -0700
+commit efb47f39c31f0ef1bb9c015c8c0d114153df6379
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Thu Feb 14 19:44:11 2013 -0800
- Remove Google-era vestigial unit test.
+ Documentation update
- Change-Id: Ia7a295a5c759a17c1675a3055d287d3e40e9e0fe
+ Change-Id: I0fec43bff4fe0ea6cd2d2a8b34dac2330a517da0
-commit 6ad6257de0e2152ac5e77dc003758de45187d6ea
-Author: Keir Mierle <mierle@gmail.com>
-Date: Wed Aug 22 11:10:31 2012 -0700
+commit be418a336cae5672111e0f6989e6d8d6c1fa24a6
+Author: Markus Moll <markus.moll@esat.kuleuven.be>
+Date: Fri Feb 15 17:19:28 2013 +0100
- Add a workaround for an Android NDK compiler bug.
-
- On certain NDK build configurations, one of the innermost
- parts of the Schur eliminator would get compiled
- incorrectly. The compiler changed a -= to a +=.
+ Fix evaluation of initial cost and corresponding test
- The normal Ceres unit tests caught the problem; however,
- since it is not possible to build the tests with the NDK
- (only with the standalone toolchain) this was difficult to
- track down. Finding the issue involved pasting the schur
- eliminator unit test inside of solver_impl.cc and other such
- hacks.
+ Commit f102a68e411d11b4864e17b69a2d781e9c2692ad seems to have introduced
+ a bug in both solver_impl.cc and solver_impl_test.cc
+ solver_impl_test showed 3 errors, where two were due to ceres NOT
+ failing when the test expected that, and one was due to the initial cost
+ being wrong (-1 instead of 0.5)
+ Ceres now does not attempt to evaluate the initial cost if
+ options.return_initial_xxx is not set. It therefore did not fail in
+ the tests.
+ It also seems that the CERES_EVALUATE macro erroneously always sets
+ final_cost, even when called with 'initial' as argument.
- Change-Id: Ie91bb545d74fe39f0c8cbd1a6eb69ee4d8b25fb2
+ Change-Id: Ia3c3eeb476e7023a3f80b201124010d6c67e9824
-commit aecb2dc92b4aa7f3bf77a1ac918e62953602392b
+commit 974513a41ff1ddc671d3dc6aa09ce708bbe447da
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Aug 22 10:08:17 2012 -0700
+Date: Tue Feb 12 14:22:40 2013 -0800
- Fix relative path bug in bibtex call.
+ Bug fix in DynamicAutoDiffCostFunction
+
+ Add handling of constant parameter blocks.
- Change-Id: I0d31786564320a6831259bcdf4c75a6b665c43ad
+ Change-Id: I8b2ea79f47e190604fc4bed27705798240689f71
-commit 1e2892009e591804df6286caebd5c960e7e3b099
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Tue Aug 21 18:00:54 2012 -0700
+commit 3130b3cea4028c71d9ae18b7465d7627f29fef7d
+Author: Keir Mierle <mierle@gmail.com>
+Date: Mon Feb 11 19:39:29 2013 -0800
- Update Summary::FullReport to report dogleg type.
+ Add support for dynamic autodiff
- Change-Id: I0b4be8d7486c1c4b36b299693b3fe8b0d3426537
+ Change-Id: I17d573696172ab691a9653db99a620e4bc1bd0d0
-commit 295ade1122a86b83e1ea605d5ca394f315874717
+commit c58e6dc3ea550302c8151003b17e9bc2a1acc316
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Aug 22 06:51:22 2012 -0700
+Date: Mon Feb 11 16:41:06 2013 -0800
- Fix Eigen3 Row/Column Major storage issue.
-
- Eigen3 does not allow column vectors to be stored in row-major
- format. NumericDiffCostFunction by default stores its Jacobian
- matrices in row-major format. This works fine if the residual
- contains more than one variable. But if the residual block
- depends on one variable and has more than one residuals, the
- resulting Jacobian matrix is a column matrix in row-major format
- resulting in a compile time error.
+ More refined event logging in solver_impl.cc
- The fix is to check the template parameters and switch to column-major
- storage as needed.
-
- Thanks to Lena Gieseke for reporting this.
-
- Change-Id: Icc51c5b38e1f3609e0e1ecb3c4e4a02aecd72c3b
+ Change-Id: Ie3061c921c006d2600d16185c690f52ccf816f68
-commit 9ad27e8e9fb1bbd2054e2f6ae37623e01428f1c0
-Author: Arnaud Gelas <arnaudgelas@gmail.com>
-Date: Tue Aug 21 09:56:30 2012 +0200
+commit f102a68e411d11b4864e17b69a2d781e9c2692ad
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Mon Feb 11 15:08:40 2013 -0800
- Add one uninstall target to remove all installed files
+ Remove extraneous initial and final evals.
- Change-Id: Ifcf89a6c27b25f28403d95a50e29c093a525298f
+ Change-Id: I80ed87435f399cbf452c68be7ea1e7139696aa4a
-commit 0c3a748ee49e04fe334f8f5a433649d18003d550
-Author: Markus Moll <markus.moll@esat.kuleuven.be>
-Date: Tue Aug 21 14:44:59 2012 +0200
+commit 0593747ee09e21a9c0a2b604d51e21a6cdd21315
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Mon Feb 11 13:57:12 2013 -0800
- Allow equal lower and upper bound for diagonal scaling.
+ Fix a memory leak in cxsparse.cc
- This way, setting the lower and upper bound both to 1.0, one can disable
- the automatic trust region scaling.
+ Thanks to Alexander Mordvintsev for reporting it.
- Change-Id: Ifa317a6911b813a89c1cf7fdfde25af603705319
+ Change-Id: Ia872be42ce80209e46722fc16a928496cf97e256
-commit 3d644b76adefac6475b91dc53c3ae5e01c4f4d66
-Author: Arnaud Gelas <arnaudgelas@gmail.com>
-Date: Thu Aug 16 17:33:21 2012 +0200
+commit 0abfb8f46f534b05413bb4d64b960d6fd0a9befb
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Mon Feb 11 13:40:04 2013 -0800
- Install headers, libraries and pdf
+ Delete the tex documentation.
- Headers are installed in ${CMAKE_INSTALL_PREFIX}/include/ceres
- Libraries are installed in ${CMAKE_INSTALL_PREFIX}/lib
- pdf is installed in ${CMAKE_INSTALL_PREFIX}/share/ceres/docs
-
- Change-Id: Ic175f2c2f5fa86820a1e8c64c2ed171f4a302a68
+ Change-Id: I15c78a8b33c5fd94941238814ac023a8fb251a20
-commit d2fb5adea4d8c2aeb43c4289c6976798a54d3cf1
-Author: Arnaud Gelas <arnaudgelas@gmail.com>
-Date: Fri Aug 17 10:11:02 2012 +0200
+commit 085cd4a6641c404334d17e5ea38f9e5b68a06ba7
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Wed Feb 6 14:31:07 2013 -0800
- Configure gerrit hook at CMake time
+ Rewrite of the tutorial.
- If the source directory is a clone, at CMake time the commit-msg hook gets
- downloaded and installed in the right location.
+ 1. Quicker starting point.
+ 2. Better discussion of derivatives.
+ 3. Better hyperlinking to code and class documentation.
+ 4. New robust estimation example.
+ 5. Better naming of example code.
+ 6. Removed dependency on gflags in all the core examples covered
+ in the tutorial.
- Change-Id: I5fee17d050ca22d8b92a49fdcc2a1cd6659f209b
+ Change-Id: Ibf3c7fe946fa2b4d22f8916a9366df267d34ca26
-commit 73166098fc4b1072adc30321c666188a3909c43c
-Author: Arnaud Gelas <arnaudgelas@gmail.com>
-Date: Mon Aug 20 15:40:41 2012 +0200
+commit c0fdc9753909fc37fed2cb5e0fcc02fc65789d68
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Wed Feb 6 14:31:07 2013 -0800
- Add one CMake option to build the examples.
+ Update nist.cc to better evaluate results.
- Currently the examples are always built. For external projects, it is useful
- not to compile the examples.
+ Ceres beats Minpack and HBN handily.
- Change-Id: I41d3bde19c7e742818e60f78222d39c43992ca8b
+ Change-Id: I7df8a47b753202ed0b53ab128ce48466bf9f8083
-commit 86d4f1ba41ef14eb1b6b61a7936af83387b35eb2
-Author: Keir Mierle <mierle@gmail.com>
-Date: Mon Aug 20 11:52:04 2012 -0700
+commit d91b671798125fd4889914d92a29cf0f7a5fef21
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Wed Feb 6 01:08:40 2013 -0800
- Add missing return statement.
+ More small changes
+ More small changes to the docs.
- Change-Id: I5eaf718318e27040e3c97e32ee46cf0a11176a37
-
-commit 51eb229da34187a4e8ce73ed9cc0e731998bb2be
-Author: Keir Mierle <mierle@gmail.com>
-Date: Mon Aug 20 11:46:12 2012 -0700
-
- Add Program::ToString() to aid debugging.
+ 1. Better landing page.
+ 2. Minor tweaks to the side bar.
+ 3. Reference to more example code.
+ 4. Local MathJax references.
- Change-Id: I0ab37ed2fe0947ca87a152919d4e7dc9b56dedc6
+ Change-Id: I39b9436dc2803732a875bbbee7f15802c4934031
-commit bcc7100635e2047dc2b77df19a4ded8a6ab4d4b9
-Author: Keir Mierle <mierle@gmail.com>
-Date: Mon Aug 20 11:45:04 2012 -0700
+commit 42a84b87fa5cc34551244a3b2b6a3e1f13a29514
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Fri Feb 1 12:22:53 2013 -0800
- Ignore minted.sty.
+ Expand reporting of timing information.
- Change-Id: I2467a6f801812b9007b51bf14b00757f026e4322
+ 1. Add an ExecutionSummary object to record execution
+ information about Ceres objects.
+ 2. Add an EventLogger object to log events in a function call.
+ 3. Add a ScopedExecutionTimer object to log times in ExecutionSummary.
+ 4. Instrument ProgramEvaluator and all the linear solvers
+ to report their timing statistics.
+ 5. Connect the timing statistics to Summary::FullReport.
+ 6. Add high precision timer on unix systems using
+ gettimeofday() call.
+ 7. Various minor clean ups all around.
+
+ Change-Id: I5e09804b730b09535484124be7dbc1c58eccd1d4
-commit 9705a736dd3d6fbead0d8a6ff77102c69bbcdc08
-Author: Keir Mierle <mierle@gmail.com>
-Date: Mon Aug 20 11:24:05 2012 -0700
+commit 08c891fcb6ea1bf66e6d4619273765a644605dfc
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Mon Feb 4 20:18:58 2013 -0800
- Add ParameterBlock::ToString() to aid debugging.
+ Various small changes.
- Change-Id: Id3f5cb27b855c536dd65a986f345bd8eb2799dfa
+ 1. Compact build instructions.
+ 2. Lots of small edits by Simon Fuhrmann.
+
+ Change-Id: I8c0c67922021041dcf7f4ecdb6c6e6dd2e2fd7e5
-commit 0c714a70e6123ceb68e5cfcd3cfbee0d09deb1db
+commit e2e857ad6be322e9cf750d4b11ccf10800e57d96
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Mon Aug 20 11:18:16 2012 -0700
+Date: Mon Feb 4 19:40:45 2013 -0800
- Fix blanks before private in loss_function.h
+ Sidebar has global table of contents.
- Change-Id: I068bed6431bc7c9b7958af391655df61499000b2
+ Change-Id: I7fe9053868a4660b0db8d7607ee618fc30ddaefd
-commit 51cf7cbe3bac45c6807c2703a2fc3175d76a1b47
-Author: Markus Moll <markus.moll@esat.kuleuven.be>
-Date: Mon Aug 20 20:10:20 2012 +0200
+commit b9182147d96f865673c2756ced4cbb127ca082a3
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Mon Feb 4 17:55:25 2013 -0800
- Add the two-dimensional subspace search to DoglegStrategy
+ Change the theme to be closer to ReadTheDocs.org
- Change-Id: I5163744c100cdf07dd93343d0734ffe0e80364f3
+ Change-Id: I61a76f5b5e5c292b54fdf51b66940ce80bd1cd5f
-commit ad1f7b772e559a911ac3a3b078b0aee1836fe785
+commit 3d87b72c895835bbfc10965d50dc96608632114d
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Mon Aug 20 11:10:34 2012 -0700
+Date: Sat Feb 2 00:49:31 2013 -0800
- Add ArcTanLoss, TolerantLoss and ComposedLossFunction.
+ Convert documentation from LaTeX to Sphinx.
- Based on work by James Roseborough.
+ A live version of the doc can be found at
- Change-Id: Idc4e0b099028f67702bfc7fe3e43dbd96b6f9256
+ http://homes.cs.washington.edu/~sagarwal/ceres-solver/
+
+ As it stands, the documentation has better hyperlinking
+ and coverage than the latex documentation now.
+
+ Change-Id: I7ede3aa83b9b9ef25104caf331e5727b4f5beae5
-commit 05292bf8fc5208b86b4a13544615b584f6efa936
+commit 71c8058478311ff9b3087360827e048dec5dd69a
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Mon Aug 20 07:40:45 2012 -0700
+Date: Thu Jan 31 17:33:01 2013 -0800
- Add a TrustRegionStrategy::Summary object.
+ Remove ExecutionSummary from Evaluator and LinearSolver
- Change-Id: I7caee35a3408ee4a0ec16ba407410d822929340d
+ Change-Id: If4dbaf516a8b14e0a79e1a2116ce66a99ed4a592
-commit b12b906c4d21c3949f0dce62c4c0d083c8edecf1
-Author: Arnaud Gelas <arnaudgelas@gmail.com>
-Date: Wed Aug 15 16:27:38 2012 +0200
+commit fa1c31eee33051d6483bc90fa7b66c3664b23bf3
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Tue Jan 29 17:24:54 2013 -0800
- Add one option to generate the PDF from CMake at build time
+ Correct the documentation for crs_matrix.h
- Make sure pygmentize is installed
+ Thanks to Joydeep Biswas for reporting this.
- Change-Id: I068ba45c33a8e96acc906a464b12d10d58b3e231
+ Change-Id: Iae5fc2274644aab40f2f922a671f65da15ae71fc
-commit b9f15a59361c609ffc4a328aea9be3d265b5da81
+commit bdd87c03ed1cbac62990bf79aa6faed0a132bba9
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Sat Aug 18 13:06:19 2012 -0700
+Date: Tue Jan 29 16:24:31 2013 -0800
- Add a dense Cholesky factorization based linear solver.
+ Add an ExecutionSummary object that the Evaluator and LinearSolver can use to
+ report execution statistics of all kinds.
- For problems with a small number of variables, but a large
- number of residuals, it is sometimes beneficial to use the
- Cholesky factorization on the normal equations, instead of
- the dense QR factorization of the Jacobian, even though it
- is numerically the better thing to do.
+ Currently a single map which maps arbitrary strings to doubles is supported,
+ which allows for precise timing information to be communicated.
- Change-Id: I3506b006195754018deec964e6e190b7e8c9ac8f
+ Change-Id: Ibd930aca5c9e6cae89bcfeffe9b13e2887644881
-commit b3fa009435acf476cd373052e62988f6437970b1
-Author: Arnaud Gelas <arnaudgelas@gmail.com>
-Date: Fri Aug 17 10:31:41 2012 +0200
+commit a2fd9ca8beb5aa11fcc5d2b32e23f161edc93d28
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Tue Jan 29 16:02:41 2013 -0800
- Set CMAKE_*_OUTPUT_DIRECTORY
-
- Gather
- * all executables in ${CMAKE_BINARY_DIR}/bin
- * all libraries (static and dynamic) in ${CMAKE_BINARY_DIR}/lib
+ Fix Android.mk
- Change-Id: Ibc2fa1adfb6f0aea65d66d570259b79546bf3b07
+ Change-Id: I1093c2731283890d1f3792bf8e6741f448f1465d
-commit 1b8a4d5d11671ed83cf6077e363dd95333f08ef8
+commit 977be7cac37316524038fa0168cc5994a5654acd
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Fri Aug 17 16:49:11 2012 -0700
+Date: Sat Jan 26 16:01:54 2013 -0800
- Fix a minor bug in detect_structure logging.
+ Add support for reporting linear solver and inner iteration
+ orderings.
- Change-Id: I117f7745e4c67595b3ff9244cde82b5b5b34ee4b
+ Change-Id: I0588a4285e0925ce689e47bd48ddcc61ce596a1f
-commit 31c1e784ab2cb9294c6e05414cf06aae2b3766de
-Author: Keir Mierle <mierle@gmail.com>
-Date: Fri Aug 17 16:16:32 2012 -0700
+commit 146b9acb4d5570da311fedb5222ad65fe12f233c
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Mon Jan 21 16:16:58 2013 -0800
- Minor cleanups.
+ Update include/ceres.h to export headers.
+ Update the ABI version.
- Change-Id: Ida4866997deeaa1bc2cebd6b69313a05ac82e457
+ Change-Id: I5c1c4f110cddc816bbb5a737634f55b4cbea98e1
-commit e83f7879a8b21c6976e116958caf35bcdcf41cb0
+commit e837aeaf9e63936d745519fa53c726a2ca9d5822
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Fri Aug 17 15:34:42 2012 -0700
+Date: Mon Jan 21 13:05:01 2013 -0800
- Fix SuiteSparse3 UFConfig.h detection really.
+ Documentation update.
- Change-Id: Id187102e755b7d778dff4363f22f9a4697ed12dd
+ Change-Id: Ica8681f4bb58c60349d0dae453c652f2522eebf6
-commit 96f25dc57658d296ee6b6633818b4f1e51d7d587
+commit 2f0d7249ccedac8183e6e5a9cb45ca7c51bb6b41
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Fri Aug 17 15:34:42 2012 -0700
+Date: Fri Jan 18 13:11:32 2013 -0800
- Fix SuiteSparse3 UFConfig.h detection.
+ NumericDiffFunctor.
- Change-Id: Ia59aefdb0ad7f713f76ed79692f2db4fa2821e5b
-
-commit c497bd6cd9aa944f518aa491d3bc645851ff9594
-Author: Markus Moll <markus.moll@esat.kuleuven.be>
-Date: Fri Aug 17 14:40:13 2012 +0200
-
- Add UFconfig and/or SuiteSparse_config test to CMakeLists.txt
+ 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.
- SuiteSparse 4 requires linking to libsuitesparseconfig.a.
- Both SuiteSparse 3 and SuiteSparse 4 require an additional header
- (either UFconfig.h or SuiteSparse_config.h) that is not found if it is
- in a separate path. Therefore, add explicit checks.
+ The tests for NumericDiffCostFunction and NumericDiffFunctor have
+ a lot of stuff that is common, so refactor them to reduce code.
- Change-Id: I699902b5db4f1b7f17134b5a54f9aa681445e294
+ Change-Id: I83b01e58b05e575fb2530d15cbd611928298646a
-commit 383c04f4236d92801c7c674892814362dedf7ad6
+commit 2fc0ed6143ad499d6dc82d621ff5ec69170beb52
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Fri Aug 17 10:14:04 2012 -0700
+Date: Tue Jan 15 11:34:10 2013 -0800
- Fix QuaternionToAngleAxis to ensure rotations are between -pi and pi.
+ Change NumericDiffCostFunction to accept variadic functors.
+
+ The interface for NumericDiffCostFunction and AutoDiffCostFunction
+ are not comparable. They both accept variadic functors.
- Thanks to Guoxuan Zhang for reporting this.
+ The change is backward compatible, as it still supports numeric
+ differentiation of CostFunction objects.
- Change-Id: I2831ca3a04d5dc6467849c290461adbe23faaea3
+ Some refactoring of documentation and code in auto_diff_cost_function
+ and its relatives was also done to make things consistent.
+
+ Change-Id: Ib5f230a1d4a85738eb187803b9c1cd7166bb3b92
-commit dd2b17d7dd9750801ba4720bdece2062e59b7ae3
+commit 9c5acce674e3ec1ba08509123ff519f106cc4348
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Aug 16 19:34:57 2012 -0700
+Date: Sun Jan 13 22:14:12 2013 -0800
- CERES_DONT_HAVE_PROTOCOL_BUFFERS -> CERES_NO_PROTOCOL_BUFFERS.
+ Add CostFunctionToFunctor.
+
+ CostFunctionToFunctor wraps a CostFunction, and makes it available
+ as a templated functor that can be called from other templated
+ functors. This is useful for when one wants to mix automatic,
+ numeric and analytic differentiated functions.
+
+ Also a bug fix in autodiff.h
- Change-Id: I6c9f50e4c006faf4e75a8f417455db18357f3187
+ Change-Id: If8ba281a89fda976ef2ce10a5844a74c4ac7b84a
-commit 8b4cb7aa2c74a0da62c638b2023566aa242af995
+commit c89ea4b9de588e2e2e82c54cd1c30cddb11454c5
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Aug 16 19:26:55 2012 -0700
+Date: Wed Jan 9 16:09:35 2013 -0800
- Fix sparse linear algebra library logging in Summary::FullReport.
+ Minor corrections based on Jim Roseborough's comments
- Change-Id: Id2c902dc86c00954fde7749c7b4a67dd94215a31
+ Change-Id: I4a8c7a454ddf038a3ed2567c101f9aee582044bf
-commit 47d26bcd3b38b5ff53b34768c33b499d47b26bd0
-Author: Markus Moll <markus.moll@esat.kuleuven.be>
-Date: Thu Aug 16 00:23:38 2012 +0200
+commit 00c8a061929b912bda3cfd4615fb8688c246c969
+Author: Keir Mierle <mierle@gmail.com>
+Date: Sat Dec 1 13:22:59 2012 -0800
- Do not implicitly negate the step in the TrustRegionMinimizer.
-
- In the TrustRegionMinimizer, the step is currently implicitly negated.
- This is done so that the linearized residual is |r - J*step|^2, which
- corresponds to J*step = r, so neither J nor r have to be modified.
- However, it leads to the rather unintuitive situation that the strategy
- returns a step in positive gradient direction, which you would expect to
- increase the function value. One way is to rename the "step" parameter in
- the strategy to "negative_step" and document it.
- This patch instead moves the negation inside the strategy, just around
- the linear solver call, so that it is done in a local context and easier
- to document.
+ Fix bug in DenseSparseMatrix::ToDenseMatrix().
- Change-Id: Idb258149a01f61c64e22128ea221c5a30cd89c89
+ Change-Id: I74a1a03149d74fbc4268ec3ce9d20e09746a7227
-commit 51da590c8457e6664f76fe9813425a0c71351497
-Author: Markus Moll <markus.moll@esat.kuleuven.be>
-Date: Fri Aug 17 12:56:09 2012 +0200
+commit bcac4de5b75cae210c5557c81239222176d2709a
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Fri Nov 30 23:11:26 2012 -0800
- Remove tmp file
+ Speedup corrector.cc
+
+ Add a specialization for the common case where the residual block
+ outputs exactly one residual.
- Change-Id: I07496fafae7b0c5c12cc26ae336e0db3b5592735
+ The matrix routines used by Corrector can be then specialized to
+ a scalar and be made considerably faster.
+
+ For denoising upto 400% speedup is observed.
+
+ Change-Id: I8e3f24b8ba41caa8e62ad97c5f5e96ab6ea47150
-commit 7006a1f2b1701b8d89b8d1525fc0101943802221
+commit 9883fc396b2913fbc597afa795c39d365229c299
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Aug 16 18:04:22 2012 -0700
+Date: Fri Nov 30 12:32:43 2012 -0800
- Correct example code in Powell's function example.
+ Refactoring of the LineSearchMinimizer.
- Thanks to Petter Strandmark for pointing this out.
+ 1. New LineSearchDirection interface, factory and instances.
+ 2. Cleanup of LineSearchMinimizer to use the State and Direction objects.
+ 3. LBFGS -> LowRankInverseHessian.
+ 4. Refactoring of the RunCallbacks function and share it across
+ LineSearchMinimizer and TrustRegionMinimizer.
- Change-Id: I967632235dccdb481396e94904bb911c9a1efe1e
+ Change-Id: I19354afc6f5d6567b28918710c2012dc30ef8f32
-commit 57a44b27bc6fc95b4e70fdc25c25c9925a2072a0
-Author: Keir Mierle <mierle@gmail.com>
-Date: Thu Aug 16 17:04:50 2012 -0700
+commit 2293cb5bc96a5b317ed4ca52aa3494cadecbc07c
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Thu Nov 29 16:00:18 2012 -0800
- Remove unnecessary flags in NDK build.
+ Add missing documentation to solver.h
- Change-Id: Ib5b4d0b7f2d898671252734978c789b8171d96a8
+ Change-Id: I86e7c4f1f6cc1e15d5eb2cf23e73c32d94d458c1
-commit f21bee247251a8b2e836c215a84c4668c31d75cd
-Author: Keir Mierle <mierle@gmail.com>
-Date: Thu Aug 16 16:27:10 2012 -0700
+commit aed99615c017839df09c98f518dcc0a59a9819ec
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Thu Nov 29 10:33:19 2012 -0800
- Fix for fpclassify.h NDK porting work.
+ Expose lbfgs rank in solver.h
- Change-Id: I69df1b4caf2941ed96a53e35e43ec54073f84f59
+ Change-Id: Ibc184b1a2f94a4057fa6569d539ca3a55d6d6098
-commit 8ceb02cb75b66602de44a35e413225386cb21c27
-Author: Keir Mierle <mierle@gmail.com>
-Date: Thu Aug 16 14:23:47 2012 -0700
+commit 1afd498f50ef520868c18a0f26b55409d8471ceb
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Thu Nov 29 10:28:11 2012 -0800
- Add Android NDK build files.
+ String to and from enum conversion routines.
+
+ Update types.h/cc with stringication and unstringication
+ routines for the newly introduced enums.
- This adds a Android.mk build that builds a Ceres static library
- suitable for embetting in larger Android applications. This is
- useful when needing to build Ceres without GPL'd components, since
- the standalone toolchain (needed for the CMake Android build) does
- not work with STLPort.
+ Change-Id: I0fe2842b5b1c75ba351f4ab87ec9fa60af2f9ed2
+
+commit 3e8d192f2871bcf6d5f248c119c8a6eef19186d3
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Wed Nov 28 17:20:22 2012 -0800
+
+ Add a rough implementation of LBFGS.
- Change-Id: I8d857237f6f82658741017d161b2e31d9a20e5a7
+ Change-Id: I2bc816adfe0c02773a23035ea31de3cddc1322a4
diff --git a/extern/libmv/third_party/ceres/SConscript b/extern/libmv/third_party/ceres/SConscript
index 6d0d2cd5c40..6e490cfd5cf 100644
--- a/extern/libmv/third_party/ceres/SConscript
+++ b/extern/libmv/third_party/ceres/SConscript
@@ -23,6 +23,10 @@ defs.append('CERES_NO_SUITESPARSE')
defs.append('CERES_NO_CXSPARSE')
defs.append('CERES_NO_PROTOCOL_BUFFERS')
defs.append('CERES_RESTRICT_SCHUR_SPECIALIZATION')
+defs.append('CERES_HAVE_RWLOCK')
+
+if env['WITH_BF_OPENMP']:
+ defs.append('CERES_USE_OPENMP')
if 'Mac OS X 10.5' in env['MACOSX_SDK_CHECK']:
defs.append('CERES_NO_TR1')
diff --git a/extern/libmv/third_party/ceres/bundle.sh b/extern/libmv/third_party/ceres/bundle.sh
index 76630bc0626..65af263f7c4 100755
--- a/extern/libmv/third_party/ceres/bundle.sh
+++ b/extern/libmv/third_party/ceres/bundle.sh
@@ -9,7 +9,8 @@ fi
repo="https://ceres-solver.googlesource.com/ceres-solver"
branch="master"
-tag="1.3.0"
+#tag="1.4.0"
+tag=""
tmp=`mktemp -d`
checkout="$tmp/ceres"
@@ -120,7 +121,7 @@ set(INC
include
internal
../gflags
- ../..
+ ../../
)
set(INC_SYS
@@ -161,8 +162,15 @@ add_definitions(
-DCERES_NO_CXSPARSE
-DCERES_NO_PROTOCOL_BUFFERS
-DCERES_RESTRICT_SCHUR_SPECIALIZATION
+ -DCERES_HAVE_RWLOCK
)
+if(WITH_OPENMP)
+ add_definitions(
+ -DCERES_USE_OPENMP
+ )
+endif()
+
if(MSVC10)
add_definitions(
-D"CERES_HASH_NAMESPACE_START=namespace std {"
@@ -212,6 +220,10 @@ defs.append('CERES_NO_SUITESPARSE')
defs.append('CERES_NO_CXSPARSE')
defs.append('CERES_NO_PROTOCOL_BUFFERS')
defs.append('CERES_RESTRICT_SCHUR_SPECIALIZATION')
+defs.append('CERES_HAVE_RWLOCK')
+
+if env['WITH_BF_OPENMP']:
+ defs.append('CERES_USE_OPENMP')
if 'Mac OS X 10.5' in env['MACOSX_SDK_CHECK']:
defs.append('CERES_NO_TR1')
diff --git a/extern/libmv/third_party/ceres/files.txt b/extern/libmv/third_party/ceres/files.txt
index 55083572977..8f4b7b97b50 100644
--- a/extern/libmv/third_party/ceres/files.txt
+++ b/extern/libmv/third_party/ceres/files.txt
@@ -2,21 +2,28 @@ include/ceres/autodiff_cost_function.h
include/ceres/ceres.h
include/ceres/conditioned_cost_function.h
include/ceres/cost_function.h
+include/ceres/cost_function_to_functor.h
include/ceres/crs_matrix.h
+include/ceres/dynamic_autodiff_cost_function.h
include/ceres/fpclassify.h
+include/ceres/gradient_checker.h
include/ceres/internal/autodiff.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/scoped_ptr.h
+include/ceres/internal/variadic_evaluate.h
include/ceres/iteration_callback.h
include/ceres/jet.h
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
@@ -54,6 +61,8 @@ internal/ceres/compressed_row_sparse_matrix.h
internal/ceres/conditioned_cost_function.cc
internal/ceres/conjugate_gradients_solver.cc
internal/ceres/conjugate_gradients_solver.h
+internal/ceres/coordinate_descent_minimizer.cc
+internal/ceres/coordinate_descent_minimizer.h
internal/ceres/corrector.cc
internal/ceres/corrector.h
internal/ceres/cxsparse.cc
@@ -71,6 +80,7 @@ internal/ceres/dogleg_strategy.cc
internal/ceres/dogleg_strategy.h
internal/ceres/evaluator.cc
internal/ceres/evaluator.h
+internal/ceres/execution_summary.h
internal/ceres/file.cc
internal/ceres/file.h
internal/ceres/generated/schur_eliminator_2_2_2.cc
@@ -107,18 +117,31 @@ internal/ceres/linear_operator.cc
internal/ceres/linear_operator.h
internal/ceres/linear_solver.cc
internal/ceres/linear_solver.h
+internal/ceres/line_search.cc
+internal/ceres/line_search_direction.cc
+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/local_parameterization.cc
internal/ceres/loss_function.cc
+internal/ceres/low_rank_inverse_hessian.cc
+internal/ceres/low_rank_inverse_hessian.h
internal/ceres/map_util.h
internal/ceres/matrix_proto.h
+internal/ceres/minimizer.cc
internal/ceres/minimizer.h
internal/ceres/mutex.h
internal/ceres/normal_prior.cc
internal/ceres/parameter_block.h
+internal/ceres/parameter_block_ordering.cc
+internal/ceres/parameter_block_ordering.h
internal/ceres/partitioned_matrix_view.cc
internal/ceres/partitioned_matrix_view.h
-internal/ceres/polynomial_solver.cc
-internal/ceres/polynomial_solver.h
+internal/ceres/polynomial.cc
+internal/ceres/polynomial.h
+internal/ceres/preconditioner.cc
+internal/ceres/preconditioner.h
internal/ceres/problem.cc
internal/ceres/problem_impl.cc
internal/ceres/problem_impl.h
@@ -137,8 +160,8 @@ internal/ceres/schur_complement_solver.h
internal/ceres/schur_eliminator.cc
internal/ceres/schur_eliminator.h
internal/ceres/schur_eliminator_impl.h
-internal/ceres/schur_ordering.cc
-internal/ceres/schur_ordering.h
+internal/ceres/schur_jacobi_preconditioner.cc
+internal/ceres/schur_jacobi_preconditioner.h
internal/ceres/scratch_evaluate_preparer.cc
internal/ceres/scratch_evaluate_preparer.h
internal/ceres/solver.cc
@@ -166,3 +189,5 @@ internal/ceres/visibility_based_preconditioner.cc
internal/ceres/visibility_based_preconditioner.h
internal/ceres/visibility.cc
internal/ceres/visibility.h
+internal/ceres/wall_time.cc
+internal/ceres/wall_time.h
diff --git a/extern/libmv/third_party/ceres/include/ceres/autodiff_cost_function.h b/extern/libmv/third_party/ceres/include/ceres/autodiff_cost_function.h
index da9ee2c7993..e758d3a2bd5 100644
--- a/extern/libmv/third_party/ceres/include/ceres/autodiff_cost_function.h
+++ b/extern/libmv/third_party/ceres/include/ceres/autodiff_cost_function.h
@@ -28,10 +28,10 @@
//
// Author: sameeragarwal@google.com (Sameer Agarwal)
//
-// Helpers for making CostFunctions as needed by the least squares framework,
-// with Jacobians computed via automatic differentiation. For more information
-// on automatic differentation, see the wikipedia article at
-// http://en.wikipedia.org/wiki/Automatic_differentiation
+// Create CostFunctions as needed by the least squares framework, with
+// Jacobians computed via automatic differentiation. For more
+// information on automatic differentation, see the wikipedia article
+// at http://en.wikipedia.org/wiki/Automatic_differentiation
//
// To get an auto differentiated cost function, you must define a class with a
// templated operator() (a functor) that computes the cost function in terms of
@@ -57,8 +57,8 @@
// To write an auto-differentiable cost function for the above model, first
// define the object
//
-// class MyScalarCostFunction {
-// MyScalarCostFunction(double k): k_(k) {}
+// class MyScalarCostFunctor {
+// MyScalarCostFunctor(double k): k_(k) {}
//
// template <typename T>
// bool operator()(const T* const x , const T* const y, T* e) const {
@@ -80,32 +80,32 @@
// it can be constructed as follows.
//
// CostFunction* cost_function
-// = new AutoDiffCostFunction<MyScalarCostFunction, 1, 2, 2>(
-// new MyScalarCostFunction(1.0)); ^ ^ ^
-// | | |
-// Dimension of residual ------+ | |
-// Dimension of x ----------------+ |
-// Dimension of y -------------------+
+// = new AutoDiffCostFunction<MyScalarCostFunctor, 1, 2, 2>(
+// new MyScalarCostFunctor(1.0)); ^ ^ ^
+// | | |
+// Dimension of residual -----+ | |
+// Dimension of x ---------------+ |
+// Dimension of y ------------------+
//
// In this example, there is usually an instance for each measumerent of k.
//
// In the instantiation above, the template parameters following
-// "MyScalarCostFunction", "1, 2, 2", describe the functor as computing a
+// "MyScalarCostFunctor", "1, 2, 2", describe the functor as computing a
// 1-dimensional output from two arguments, both 2-dimensional.
//
// The autodiff cost function also supports cost functions with a
// runtime-determined number of residuals. For example:
//
// CostFunction* cost_function
-// = new AutoDiffCostFunction<MyScalarCostFunction, DYNAMIC, 2, 2>(
-// new CostFunctionWithDynamicNumResiduals(1.0), ^ ^ ^
-// runtime_number_of_residuals); <----+ | | |
-// | | | |
-// | | | |
-// Actual number of residuals ------+ | | |
-// Indicate dynamic number of residuals ---------+ | |
-// Dimension of x -------------------------------------+ |
-// Dimension of y ----------------------------------------+
+// = new AutoDiffCostFunction<MyScalarCostFunctor, DYNAMIC, 2, 2>(
+// new CostFunctorWithDynamicNumResiduals(1.0), ^ ^ ^
+// runtime_number_of_residuals); <----+ | | |
+// | | | |
+// | | | |
+// Actual number of residuals ------+ | | |
+// Indicate dynamic number of residuals --------+ | |
+// Dimension of x ------------------------------------+ |
+// Dimension of y ---------------------------------------+
//
// The framework can currently accommodate cost functions of up to 6 independent
// variables, and there is no limit on the dimensionality of each of them.
@@ -119,7 +119,7 @@
// functions is to get the sizing wrong. In particular, there is a tendency to
// set the template parameters to (dimension of residual, number of parameters)
// instead of passing a dimension parameter for *every parameter*. In the
-// example above, that would be <MyScalarCostFunction, 1, 2>, which is missing
+// example above, that would be <MyScalarCostFunctor, 1, 2>, which is missing
// the last '2' argument. Please be careful when setting the size parameters.
#ifndef CERES_PUBLIC_AUTODIFF_COST_FUNCTION_H_
@@ -154,16 +154,21 @@ template <typename CostFunctor,
int N2 = 0, // Number of parameters in block 2.
int N3 = 0, // Number of parameters in block 3.
int N4 = 0, // Number of parameters in block 4.
- int N5 = 0> // Number of parameters in block 5.
-class AutoDiffCostFunction :
- public SizedCostFunction<M, N0, N1, N2, N3, N4, N5> {
+ int N5 = 0, // Number of parameters in block 5.
+ int N6 = 0, // Number of parameters in block 6.
+ int N7 = 0, // Number of parameters in block 7.
+ int N8 = 0, // Number of parameters in block 8.
+ int N9 = 0> // Number of parameters in block 9.
+class AutoDiffCostFunction : public SizedCostFunction<M,
+ N0, N1, N2, N3, N4,
+ N5, N6, N7, N8, N9> {
public:
// Takes ownership of functor. Uses the template-provided value for the
// number of residuals ("M").
explicit AutoDiffCostFunction(CostFunctor* functor)
: functor_(functor) {
CHECK_NE(M, DYNAMIC) << "Can't run the fixed-size constructor if the "
- << "number of residuals is set to ceres::DYNAMIC.";
+ << "number of residuals is set to ceres::DYNAMIC.";
}
// Takes ownership of functor. Ignores the template-provided number of
@@ -174,8 +179,9 @@ class AutoDiffCostFunction :
AutoDiffCostFunction(CostFunctor* functor, int num_residuals)
: functor_(functor) {
CHECK_EQ(M, DYNAMIC) << "Can't run the dynamic-size constructor if the "
- << "number of residuals is not ceres::DYNAMIC.";
- SizedCostFunction<M, N0, N1, N2, N3, N4, N5>::set_num_residuals(num_residuals);
+ << "number of residuals is not ceres::DYNAMIC.";
+ SizedCostFunction<M, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>
+ ::set_num_residuals(num_residuals);
}
virtual ~AutoDiffCostFunction() {}
@@ -190,14 +196,15 @@ class AutoDiffCostFunction :
double** jacobians) const {
if (!jacobians) {
return internal::VariadicEvaluate<
- CostFunctor, double, N0, N1, N2, N3, N4, N5>
+ CostFunctor, double, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>
::Call(*functor_, parameters, residuals);
}
return internal::AutoDiff<CostFunctor, double,
- N0, N1, N2, N3, N4, N5>::Differentiate(
+ N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>::Differentiate(
*functor_,
parameters,
- SizedCostFunction<M, N0, N1, N2, N3, N4, N5>::num_residuals(),
+ SizedCostFunction<M, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>
+ ::num_residuals(),
residuals,
jacobians);
}
diff --git a/extern/libmv/third_party/ceres/include/ceres/ceres.h b/extern/libmv/third_party/ceres/include/ceres/ceres.h
index 22aaf8ff21a..7878806aa45 100644
--- a/extern/libmv/third_party/ceres/include/ceres/ceres.h
+++ b/extern/libmv/third_party/ceres/include/ceres/ceres.h
@@ -34,12 +34,20 @@
#ifndef CERES_PUBLIC_CERES_H_
#define CERES_PUBLIC_CERES_H_
+#define CERES_VERSION 1.5.0
+#define CERES_ABI_VERSION 1.5.0
+
#include "ceres/autodiff_cost_function.h"
#include "ceres/cost_function.h"
+#include "ceres/cost_function_to_functor.h"
+#include "ceres/crs_matrix.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"
diff --git a/extern/libmv/third_party/ceres/include/ceres/cost_function_to_functor.h b/extern/libmv/third_party/ceres/include/ceres/cost_function_to_functor.h
new file mode 100644
index 00000000000..b30ecd06983
--- /dev/null
+++ b/extern/libmv/third_party/ceres/include/ceres/cost_function_to_functor.h
@@ -0,0 +1,752 @@
+// 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)
+//
+// CostFunctionToFunctor is an adapter class that allows users to use
+// CostFunction objects in templated functors which are to be used for
+// automatic differentiation. This allows the user to seamlessly mix
+// analytic, numeric and automatic differentiation.
+//
+// For example, let us assume that
+//
+// class IntrinsicProjection : public SizedCostFunction<2, 5, 3> {
+// public:
+// IntrinsicProjection(const double* observations);
+// virtual bool Evaluate(double const* const* parameters,
+// double* residuals,
+// double** jacobians) const;
+// };
+//
+// is a cost function that implements the projection of a point in its
+// local coordinate system onto its image plane and subtracts it from
+// the observed point projection. It can compute its residual and
+// either via analytic or numerical differentiation can compute its
+// jacobians.
+//
+// Now we would like to compose the action of this CostFunction with
+// the action of camera extrinsics, i.e., rotation and
+// translation. Say we have a templated function
+//
+// template<typename T>
+// void RotateAndTranslatePoint(const T* rotation,
+// const T* translation,
+// const T* point,
+// T* result);
+//
+// Then we can now do the following,
+//
+// struct CameraProjection {
+// CameraProjection(double* observation) {
+// intrinsic_projection_.reset(
+// new CostFunctionToFunctor<2, 5, 3>(
+// new IntrinsicProjection(observation_)));
+// }
+// template <typename T>
+// bool operator(const T* rotation,
+// const T* translation,
+// const T* intrinsics,
+// const T* point,
+// T* residual) const {
+// T transformed_point[3];
+// RotateAndTranslatePoint(rotation, translation, point, transformed_point);
+//
+// // Note that we call intrinsic_projection_, just like it was
+// // any other templated functor.
+//
+// return (*intrinsic_projection_)(intrinsics, transformed_point, residual);
+// }
+//
+// private:
+// scoped_ptr<CostFunctionToFunctor<2,5,3> > intrinsic_projection_;
+// };
+
+#ifndef CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_
+#define CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_
+
+#include <numeric>
+#include <vector>
+
+#include "ceres/cost_function.h"
+#include "ceres/internal/fixed_array.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+
+namespace ceres {
+
+template <int kNumResiduals,
+ int N0, 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 CostFunctionToFunctor {
+ public:
+ explicit CostFunctionToFunctor(CostFunction* cost_function)
+ : cost_function_(cost_function) {
+ CHECK_NOTNULL(cost_function);
+
+ CHECK_GE(kNumResiduals, 0);
+ CHECK_EQ(cost_function->num_residuals(), kNumResiduals);
+
+ // This block breaks the 80 column rule to keep it somewhat readable.
+ CHECK((!N1 && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && (N9 > 0)))
+ << "Zero block cannot precede a non-zero block. Block sizes are "
+ << "(ignore trailing 0s): " << N0 << ", " << N1 << ", " << N2 << ", "
+ << N3 << ", " << N4 << ", " << N5 << ", " << N6 << ", " << N7 << ", "
+ << N8 << ", " << N9;
+
+ const vector<int16>& parameter_block_sizes =
+ cost_function->parameter_block_sizes();
+ const int num_parameter_blocks =
+ (N0 > 0) + (N1 > 0) + (N2 > 0) + (N3 > 0) + (N4 > 0) +
+ (N5 > 0) + (N6 > 0) + (N7 > 0) + (N8 > 0) + (N9 > 0);
+ CHECK_EQ(parameter_block_sizes.size(), num_parameter_blocks);
+
+ CHECK_EQ(N0, parameter_block_sizes[0]);
+ if (parameter_block_sizes.size() > 1) CHECK_EQ(N1, parameter_block_sizes[1]); // NOLINT
+ if (parameter_block_sizes.size() > 2) CHECK_EQ(N2, parameter_block_sizes[2]); // NOLINT
+ if (parameter_block_sizes.size() > 3) CHECK_EQ(N3, parameter_block_sizes[3]); // NOLINT
+ if (parameter_block_sizes.size() > 4) CHECK_EQ(N4, parameter_block_sizes[4]); // NOLINT
+ if (parameter_block_sizes.size() > 5) CHECK_EQ(N5, parameter_block_sizes[5]); // NOLINT
+ if (parameter_block_sizes.size() > 6) CHECK_EQ(N6, parameter_block_sizes[6]); // NOLINT
+ if (parameter_block_sizes.size() > 7) CHECK_EQ(N7, parameter_block_sizes[7]); // NOLINT
+ if (parameter_block_sizes.size() > 8) CHECK_EQ(N8, parameter_block_sizes[8]); // NOLINT
+ if (parameter_block_sizes.size() > 9) CHECK_EQ(N9, parameter_block_sizes[9]); // NOLINT
+
+ CHECK_EQ(accumulate(parameter_block_sizes.begin(),
+ parameter_block_sizes.end(), 0),
+ N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9);
+ }
+
+ bool operator()(const double* x0, double* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_EQ(N1, 0);
+ CHECK_EQ(N2, 0);
+ CHECK_EQ(N3, 0);
+ CHECK_EQ(N4, 0);
+ CHECK_EQ(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+
+ return cost_function_->Evaluate(&x0, residuals, NULL);
+ }
+
+ bool operator()(const double* x0,
+ const double* x1,
+ double* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_EQ(N2, 0);
+ CHECK_EQ(N3, 0);
+ CHECK_EQ(N4, 0);
+ CHECK_EQ(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const double*> parameter_blocks(2);
+ parameter_blocks[0] = x0;
+ parameter_blocks[1] = x1;
+ return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL);
+ }
+
+ bool operator()(const double* x0,
+ const double* x1,
+ const double* x2,
+ double* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_EQ(N3, 0);
+ CHECK_EQ(N4, 0);
+ CHECK_EQ(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const double*> parameter_blocks(3);
+ parameter_blocks[0] = x0;
+ parameter_blocks[1] = x1;
+ parameter_blocks[2] = x2;
+ return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL);
+ }
+
+ bool operator()(const double* x0,
+ const double* x1,
+ const double* x2,
+ const double* x3,
+ double* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_EQ(N4, 0);
+ CHECK_EQ(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const double*> parameter_blocks(4);
+ parameter_blocks[0] = x0;
+ parameter_blocks[1] = x1;
+ parameter_blocks[2] = x2;
+ parameter_blocks[3] = x3;
+ return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL);
+ }
+
+ bool operator()(const double* x0,
+ const double* x1,
+ const double* x2,
+ const double* x3,
+ const double* x4,
+ double* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_EQ(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const double*> parameter_blocks(5);
+ parameter_blocks[0] = x0;
+ parameter_blocks[1] = x1;
+ parameter_blocks[2] = x2;
+ parameter_blocks[3] = x3;
+ parameter_blocks[4] = x4;
+ return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL);
+ }
+
+ bool operator()(const double* x0,
+ const double* x1,
+ const double* x2,
+ const double* x3,
+ const double* x4,
+ const double* x5,
+ double* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_NE(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const double*> parameter_blocks(6);
+ parameter_blocks[0] = x0;
+ parameter_blocks[1] = x1;
+ parameter_blocks[2] = x2;
+ parameter_blocks[3] = x3;
+ parameter_blocks[4] = x4;
+ parameter_blocks[5] = x5;
+ return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL);
+ }
+
+ 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 {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_NE(N5, 0);
+ CHECK_NE(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const double*> parameter_blocks(7);
+ parameter_blocks[0] = x0;
+ parameter_blocks[1] = x1;
+ parameter_blocks[2] = x2;
+ parameter_blocks[3] = x3;
+ parameter_blocks[4] = x4;
+ parameter_blocks[5] = x5;
+ parameter_blocks[6] = x6;
+ return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL);
+ }
+
+ 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 {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_NE(N5, 0);
+ CHECK_NE(N6, 0);
+ CHECK_NE(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const double*> parameter_blocks(8);
+ parameter_blocks[0] = x0;
+ parameter_blocks[1] = x1;
+ parameter_blocks[2] = x2;
+ parameter_blocks[3] = x3;
+ parameter_blocks[4] = x4;
+ parameter_blocks[5] = x5;
+ parameter_blocks[6] = x6;
+ parameter_blocks[7] = x7;
+ return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL);
+ }
+
+ 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 {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_NE(N5, 0);
+ CHECK_NE(N6, 0);
+ CHECK_NE(N7, 0);
+ CHECK_NE(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const double*> parameter_blocks(9);
+ parameter_blocks[0] = x0;
+ parameter_blocks[1] = x1;
+ parameter_blocks[2] = x2;
+ parameter_blocks[3] = x3;
+ parameter_blocks[4] = x4;
+ parameter_blocks[5] = x5;
+ parameter_blocks[6] = x6;
+ parameter_blocks[7] = x7;
+ parameter_blocks[8] = x8;
+ return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL);
+ }
+
+ 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 {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_NE(N5, 0);
+ CHECK_NE(N6, 0);
+ CHECK_NE(N7, 0);
+ CHECK_NE(N8, 0);
+ CHECK_NE(N9, 0);
+ internal::FixedArray<const double*> parameter_blocks(10);
+ parameter_blocks[0] = x0;
+ parameter_blocks[1] = x1;
+ parameter_blocks[2] = x2;
+ parameter_blocks[3] = x3;
+ parameter_blocks[4] = x4;
+ parameter_blocks[5] = x5;
+ parameter_blocks[6] = x6;
+ parameter_blocks[7] = x7;
+ parameter_blocks[8] = x8;
+ parameter_blocks[9] = x9;
+ return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL);
+ }
+
+ template <typename JetT>
+ bool operator()(const JetT* x0, JetT* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_EQ(N1, 0);
+ CHECK_EQ(N2, 0);
+ CHECK_EQ(N3, 0);
+ CHECK_EQ(N4, 0);
+ CHECK_EQ(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ return EvaluateWithJets(&x0, residuals);
+ }
+
+ template <typename JetT>
+ bool operator()(const JetT* x0,
+ const JetT* x1,
+ JetT* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_EQ(N2, 0);
+ CHECK_EQ(N3, 0);
+ CHECK_EQ(N4, 0);
+ CHECK_EQ(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const JetT*> jets(2);
+ jets[0] = x0;
+ jets[1] = x1;
+ return EvaluateWithJets(jets.get(), residuals);
+ }
+
+ template <typename JetT>
+ bool operator()(const JetT* x0,
+ const JetT* x1,
+ const JetT* x2,
+ JetT* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_EQ(N3, 0);
+ CHECK_EQ(N4, 0);
+ CHECK_EQ(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const JetT*> jets(3);
+ jets[0] = x0;
+ jets[1] = x1;
+ jets[2] = x2;
+ return EvaluateWithJets(jets.get(), residuals);
+ }
+
+ template <typename JetT>
+ bool operator()(const JetT* x0,
+ const JetT* x1,
+ const JetT* x2,
+ const JetT* x3,
+ JetT* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_EQ(N4, 0);
+ CHECK_EQ(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const JetT*> jets(4);
+ jets[0] = x0;
+ jets[1] = x1;
+ jets[2] = x2;
+ jets[3] = x3;
+ return EvaluateWithJets(jets.get(), residuals);
+ }
+
+ template <typename JetT>
+ bool operator()(const JetT* x0,
+ const JetT* x1,
+ const JetT* x2,
+ const JetT* x3,
+ const JetT* x4,
+ JetT* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_EQ(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const JetT*> jets(5);
+ jets[0] = x0;
+ jets[1] = x1;
+ jets[2] = x2;
+ jets[3] = x3;
+ jets[4] = x4;
+ return EvaluateWithJets(jets.get(), residuals);
+ }
+
+ template <typename JetT>
+ bool operator()(const JetT* x0,
+ const JetT* x1,
+ const JetT* x2,
+ const JetT* x3,
+ const JetT* x4,
+ const JetT* x5,
+ JetT* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_NE(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const JetT*> jets(6);
+ jets[0] = x0;
+ jets[1] = x1;
+ jets[2] = x2;
+ jets[3] = x3;
+ jets[4] = x4;
+ jets[5] = x5;
+ return EvaluateWithJets(jets.get(), residuals);
+ }
+
+ template <typename JetT>
+ bool operator()(const JetT* x0,
+ const JetT* x1,
+ const JetT* x2,
+ const JetT* x3,
+ const JetT* x4,
+ const JetT* x5,
+ const JetT* x6,
+ JetT* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_NE(N5, 0);
+ CHECK_NE(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const JetT*> jets(7);
+ jets[0] = x0;
+ jets[1] = x1;
+ jets[2] = x2;
+ jets[3] = x3;
+ jets[4] = x4;
+ jets[5] = x5;
+ jets[6] = x6;
+ return EvaluateWithJets(jets.get(), residuals);
+ }
+
+ template <typename JetT>
+ bool operator()(const JetT* x0,
+ const JetT* x1,
+ const JetT* x2,
+ const JetT* x3,
+ const JetT* x4,
+ const JetT* x5,
+ const JetT* x6,
+ const JetT* x7,
+ JetT* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_NE(N5, 0);
+ CHECK_NE(N6, 0);
+ CHECK_NE(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const JetT*> jets(8);
+ jets[0] = x0;
+ jets[1] = x1;
+ jets[2] = x2;
+ jets[3] = x3;
+ jets[4] = x4;
+ jets[5] = x5;
+ jets[6] = x6;
+ jets[7] = x7;
+ return EvaluateWithJets(jets.get(), residuals);
+ }
+
+ template <typename JetT>
+ bool operator()(const JetT* x0,
+ const JetT* x1,
+ const JetT* x2,
+ const JetT* x3,
+ const JetT* x4,
+ const JetT* x5,
+ const JetT* x6,
+ const JetT* x7,
+ const JetT* x8,
+ JetT* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_NE(N5, 0);
+ CHECK_NE(N6, 0);
+ CHECK_NE(N7, 0);
+ CHECK_NE(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const JetT*> jets(9);
+ jets[0] = x0;
+ jets[1] = x1;
+ jets[2] = x2;
+ jets[3] = x3;
+ jets[4] = x4;
+ jets[5] = x5;
+ jets[6] = x6;
+ jets[7] = x7;
+ jets[8] = x8;
+ return EvaluateWithJets(jets.get(), residuals);
+ }
+
+ template <typename JetT>
+ bool operator()(const JetT* x0,
+ const JetT* x1,
+ const JetT* x2,
+ const JetT* x3,
+ const JetT* x4,
+ const JetT* x5,
+ const JetT* x6,
+ const JetT* x7,
+ const JetT* x8,
+ const JetT* x9,
+ JetT* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_NE(N5, 0);
+ CHECK_NE(N6, 0);
+ CHECK_NE(N7, 0);
+ CHECK_NE(N8, 0);
+ CHECK_NE(N9, 0);
+ internal::FixedArray<const JetT*> jets(10);
+ jets[0] = x0;
+ jets[1] = x1;
+ jets[2] = x2;
+ jets[3] = x3;
+ jets[4] = x4;
+ jets[5] = x5;
+ jets[6] = x6;
+ jets[7] = x7;
+ jets[8] = x8;
+ jets[9] = x9;
+ return EvaluateWithJets(jets.get(), residuals);
+ }
+
+ private:
+ template <typename JetT>
+ bool EvaluateWithJets(const JetT** inputs, JetT* output) const {
+ const int kNumParameters = N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9;
+ const vector<int16>& parameter_block_sizes =
+ cost_function_->parameter_block_sizes();
+ const int num_parameter_blocks = parameter_block_sizes.size();
+ const int num_residuals = cost_function_->num_residuals();
+
+ internal::FixedArray<double> parameters(kNumParameters);
+ internal::FixedArray<double*> parameter_blocks(num_parameter_blocks);
+ internal::FixedArray<double> jacobians(num_residuals * kNumParameters);
+ internal::FixedArray<double*> jacobian_blocks(num_parameter_blocks);
+ internal::FixedArray<double> residuals(num_residuals);
+
+ // Build a set of arrays to get the residuals and jacobians from
+ // the CostFunction wrapped by this functor.
+ double* parameter_ptr = parameters.get();
+ double* jacobian_ptr = jacobians.get();
+ for (int i = 0; i < num_parameter_blocks; ++i) {
+ parameter_blocks[i] = parameter_ptr;
+ jacobian_blocks[i] = jacobian_ptr;
+ for (int j = 0; j < parameter_block_sizes[i]; ++j) {
+ *parameter_ptr++ = inputs[i][j].a;
+ }
+ jacobian_ptr += num_residuals * parameter_block_sizes[i];
+ }
+
+ if (!cost_function_->Evaluate(parameter_blocks.get(),
+ residuals.get(),
+ jacobian_blocks.get())) {
+ return false;
+ }
+
+ // Now that we have the incoming Jets, which are carrying the
+ // partial derivatives of each of the inputs w.r.t to some other
+ // underlying parameters. The derivative of the outputs of the
+ // cost function w.r.t to the same underlying parameters can now
+ // be computed by applying the chain rule.
+ //
+ // d output[i] d output[i] d input[j]
+ // -------------- = sum_j ----------- * ------------
+ // d parameter[k] d input[j] d parameter[k]
+ //
+ // d input[j]
+ // -------------- = inputs[j], so
+ // d parameter[k]
+ //
+ // outputJet[i] = sum_k jacobian[i][k] * inputJet[k]
+ //
+ // The following loop, iterates over the residuals, computing one
+ // output jet at a time.
+ for (int i = 0; i < num_residuals; ++i) {
+ output[i].a = residuals[i];
+ output[i].v.setZero();
+
+ for (int j = 0; j < num_parameter_blocks; ++j) {
+ const int16 block_size = parameter_block_sizes[j];
+ for (int k = 0; k < parameter_block_sizes[j]; ++k) {
+ output[i].v +=
+ jacobian_blocks[j][i * block_size + k] * inputs[j][k].v;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private:
+ internal::scoped_ptr<CostFunction> cost_function_;
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/crs_matrix.h b/extern/libmv/third_party/ceres/include/ceres/crs_matrix.h
index c9fe8f78b7c..8c470cd33f2 100644
--- a/extern/libmv/third_party/ceres/include/ceres/crs_matrix.h
+++ b/extern/libmv/third_party/ceres/include/ceres/crs_matrix.h
@@ -44,17 +44,35 @@ struct CRSMatrix {
int num_rows;
int num_cols;
- // A compressed row matrix stores its contents in three arrays.
- // The non-zero pattern of the i^th row is given by
+ // A compressed row matrix stores its contents in three arrays,
+ // rows, cols and values.
//
- // rows[cols[i] ... cols[i + 1]]
+ // rows is a num_rows + 1 sized array that points into the cols and
+ // values array. For each row i:
//
- // and the corresponding values by
+ // cols[rows[i]] ... cols[rows[i + 1] - 1] are the indices of the
+ // non-zero columns of row i.
//
- // values[cols[i] ... cols[i + 1]]
+ // values[rows[i]] .. values[rows[i + 1] - 1] are the values of the
+ // corresponding entries.
//
- // Thus, cols is a vector of size num_cols + 1, and rows and values
- // have as many entries as number of non-zeros in the matrix.
+ // cols and values contain as many entries as there are non-zeros in
+ // the matrix.
+ //
+ // e.g, consider the 3x4 sparse matrix
+ //
+ // [ 0 10 0 4 ]
+ // [ 0 2 -3 2 ]
+ // [ 1 2 0 0 ]
+ //
+ // The three arrays will be:
+ //
+ //
+ // -row0- ---row1--- -row2-
+ // rows = [ 0, 2, 5, 7]
+ // cols = [ 1, 3, 1, 2, 3, 0, 1]
+ // values = [10, 4, 2, -3, 2, 1, 2]
+
vector<int> cols;
vector<int> rows;
vector<double> values;
diff --git a/extern/libmv/third_party/ceres/include/ceres/dynamic_autodiff_cost_function.h b/extern/libmv/third_party/ceres/include/ceres/dynamic_autodiff_cost_function.h
new file mode 100644
index 00000000000..861164a8253
--- /dev/null
+++ b/extern/libmv/third_party/ceres/include/ceres/dynamic_autodiff_cost_function.h
@@ -0,0 +1,215 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 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: mierle@gmail.com (Keir Mierle)
+// sameeragarwal@google.com (Sameer Agarwal)
+// thadh@gmail.com (Thad Hughes)
+//
+// This autodiff implementation differs from the one found in
+// autodiff_cost_function.h by supporting autodiff on cost functions with
+// variable numbers of parameters with variable sizes. With the other
+// implementation, all the sizes (both the number of parameter blocks and the
+// size of each block) must be fixed at compile time.
+//
+// The functor API differs slightly from the API for fixed size autodiff; the
+// expected interface for the cost functors is:
+//
+// struct MyCostFunctor {
+// template<typename T>
+// bool operator()(T const* const* parameters, T* residuals) const {
+// // Use parameters[i] to access the i'th parameter block.
+// }
+// }
+//
+// Since the sizing of the parameters is done at runtime, you must also specify
+// the sizes after creating the dynamic autodiff cost function. For example:
+//
+// DynamicAutoDiffCostFunction<MyCostFunctor, 3> cost_function(
+// new MyCostFunctor());
+// cost_function.AddParameterBlock(5);
+// cost_function.AddParameterBlock(10);
+// cost_function.SetNumResiduals(21);
+//
+// Under the hood, the implementation evaluates the cost function multiple
+// times, computing a small set of the derivatives (four by default, controlled
+// by the Stride template parameter) with each pass. There is a tradeoff with
+// the size of the passes; you may want to experiment with the stride.
+
+#ifndef CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
+#define CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
+
+#include <cmath>
+#include <numeric>
+#include <vector>
+
+#include "ceres/cost_function.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/jet.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+template <typename CostFunctor, int Stride = 4>
+class DynamicAutoDiffCostFunction : public CostFunction {
+ public:
+ explicit DynamicAutoDiffCostFunction(CostFunctor* functor)
+ : functor_(functor) {}
+
+ virtual ~DynamicAutoDiffCostFunction() {}
+
+ void AddParameterBlock(int size) {
+ mutable_parameter_block_sizes()->push_back(size);
+ }
+
+ void SetNumResiduals(int num_residuals) {
+ set_num_residuals(num_residuals);
+ }
+
+ virtual bool Evaluate(double const* const* parameters,
+ double* residuals,
+ double** jacobians) const {
+ CHECK_GT(num_residuals(), 0)
+ << "You must call DynamicAutoDiffCostFunction::SetNumResiduals() "
+ << "before DynamicAutoDiffCostFunction::Evaluate().";
+
+ if (jacobians == NULL) {
+ return (*functor_)(parameters, residuals);
+ }
+
+ // The difficulty with Jets, as implemented in Ceres, is that they were
+ // originally designed for strictly compile-sized use. At this point, there
+ // is a large body of code that assumes inside a cost functor it is
+ // acceptable to do e.g. T(1.5) and get an appropriately sized jet back.
+ //
+ // Unfortunately, it is impossible to communicate the expected size of a
+ // dynamically sized jet to the static instantiations that existing code
+ // depends on.
+ //
+ // To work around this issue, the solution here is to evaluate the
+ // jacobians in a series of passes, each one computing Stripe *
+ // num_residuals() derivatives. This is done with small, fixed-size jets.
+ const int num_parameter_blocks = parameter_block_sizes().size();
+ const int num_parameters = std::accumulate(parameter_block_sizes().begin(),
+ parameter_block_sizes().end(),
+ 0);
+
+ // Allocate scratch space for the strided evaluation.
+ vector<Jet<double, Stride> > input_jets(num_parameters);
+ vector<Jet<double, Stride> > output_jets(num_residuals());
+
+ // Make the parameter pack that is sent to the functor (reused).
+ vector<Jet<double, Stride>* > jet_parameters(num_parameter_blocks, NULL);
+ int num_active_parameters = 0;
+ int start_derivative_section = -1;
+ for (int i = 0, parameter_cursor = 0; i < num_parameter_blocks; ++i) {
+ jet_parameters[i] = &input_jets[parameter_cursor];
+
+ const int parameter_block_size = parameter_block_sizes()[i];
+ if (jacobians[i] != NULL) {
+ start_derivative_section =
+ (start_derivative_section == -1)
+ ? parameter_cursor
+ : start_derivative_section;
+ num_active_parameters += parameter_block_size;
+ }
+
+ for (int j = 0; j < parameter_block_size; ++j, parameter_cursor++) {
+ input_jets[parameter_cursor].a = parameters[i][j];
+ }
+ }
+
+ // Evaluate all of the strides. Each stride is a chunk of the derivative to
+ // evaluate, typically some size proportional to the size of the SIMD
+ // registers of the CPU.
+ int num_strides = static_cast<int>(ceil(num_active_parameters /
+ static_cast<float>(Stride)));
+
+ for (int pass = 0; pass < num_strides; ++pass) {
+ // Set most of the jet components to zero, except for
+ // non-constant #Stride parameters.
+ int active_parameter_count = 0;
+ int end_derivative_section = start_derivative_section;
+ for (int i = 0, parameter_cursor = 0; i < num_parameter_blocks; ++i) {
+ for (int j = 0; j < parameter_block_sizes()[i];
+ ++j, parameter_cursor++) {
+ input_jets[parameter_cursor].v.setZero();
+ if (parameter_cursor >= start_derivative_section &&
+ active_parameter_count < Stride) {
+ if (jacobians[i] != NULL) {
+ input_jets[parameter_cursor]
+ .v[parameter_cursor - start_derivative_section] = 1.0;
+ ++active_parameter_count;
+ }
+ ++end_derivative_section;
+ }
+ }
+ }
+
+ if (!(*functor_)(&jet_parameters[0], &output_jets[0])) {
+ return false;
+ }
+
+ // Copy the pieces of the jacobians into their final place.
+ active_parameter_count = 0;
+ for (int i = 0, parameter_cursor = 0; i < num_parameter_blocks; ++i) {
+ for (int j = 0; j < parameter_block_sizes()[i];
+ ++j, parameter_cursor++) {
+ if (parameter_cursor >= start_derivative_section &&
+ active_parameter_count < Stride) {
+ if (jacobians[i] != NULL) {
+ for (int k = 0; k < num_residuals(); ++k) {
+ jacobians[i][k * parameter_block_sizes()[i] + j] =
+ output_jets[k].v[parameter_cursor -
+ start_derivative_section];
+ }
+ ++active_parameter_count;
+ }
+ }
+ }
+ }
+
+ // Only copy the residuals over once (even though we compute them on
+ // every loop).
+ if (pass == num_strides - 1) {
+ for (int k = 0; k < num_residuals(); ++k) {
+ residuals[k] = output_jets[k].a;
+ }
+ }
+
+ start_derivative_section = end_derivative_section;
+ }
+ return true;
+ }
+
+ private:
+ internal::scoped_ptr<CostFunctor> functor_;
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/fpclassify.h b/extern/libmv/third_party/ceres/include/ceres/fpclassify.h
index 5a9ea1599d2..b730832fd4b 100644
--- a/extern/libmv/third_party/ceres/include/ceres/fpclassify.h
+++ b/extern/libmv/third_party/ceres/include/ceres/fpclassify.h
@@ -41,6 +41,8 @@
#include <float.h>
#endif
+#include <limits>
+
namespace ceres {
#if defined(_MSC_VER)
diff --git a/extern/libmv/third_party/ceres/include/ceres/gradient_checker.h b/extern/libmv/third_party/ceres/include/ceres/gradient_checker.h
new file mode 100644
index 00000000000..3ec8056a02d
--- /dev/null
+++ b/extern/libmv/third_party/ceres/include/ceres/gradient_checker.h
@@ -0,0 +1,222 @@
+// 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.
+// Copyright 2007 Google Inc. All Rights Reserved.
+//
+// Author: wjr@google.com (William Rucklidge)
+//
+// This file contains a class that exercises a cost function, to make sure
+// that it is computing reasonable derivatives. It compares the Jacobians
+// computed by the cost function with those obtained by finite
+// differences.
+
+#ifndef CERES_PUBLIC_GRADIENT_CHECKER_H_
+#define CERES_PUBLIC_GRADIENT_CHECKER_H_
+
+#include <cstddef>
+#include <algorithm>
+#include <vector>
+
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/fixed_array.h"
+#include "ceres/internal/macros.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/numeric_diff_cost_function.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+// An object that exercises a cost function, to compare the answers that it
+// gives with derivatives estimated using finite differencing.
+//
+// The only likely usage of this is for testing.
+//
+// How to use: Fill in an array of pointers to parameter blocks for your
+// CostFunction, and then call Probe(). Check that the return value is
+// 'true'. See prober_test.cc for an example.
+//
+// This is templated similarly to NumericDiffCostFunction, as it internally
+// uses that.
+template <typename CostFunctionToProbe,
+ int M = 0, int N0 = 0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0>
+class GradientChecker {
+ public:
+ // Here we stash some results from the probe, for later
+ // inspection.
+ struct GradientCheckResults {
+ // Computed cost.
+ Vector cost;
+
+ // The sizes of these matrices are dictated by the cost function's
+ // parameter and residual block sizes. Each vector's length will
+ // term->parameter_block_sizes().size(), and each matrix is the
+ // Jacobian of the residual with respect to the corresponding parameter
+ // block.
+
+ // Derivatives as computed by the cost function.
+ vector<Matrix> term_jacobians;
+
+ // Derivatives as computed by finite differencing.
+ vector<Matrix> finite_difference_jacobians;
+
+ // Infinity-norm of term_jacobians - finite_difference_jacobians.
+ double error_jacobians;
+ };
+
+ // Checks the Jacobian computed by a cost function.
+ //
+ // probe_point: The parameter values at which to probe.
+ // error_tolerance: A threshold for the infinity-norm difference
+ // between the Jacobians. If the Jacobians differ by more than
+ // this amount, then the probe fails.
+ //
+ // term: The cost function to test. Not retained after this call returns.
+ //
+ // results: On return, the two Jacobians (and other information)
+ // will be stored here. May be NULL.
+ //
+ // Returns true if no problems are detected and the difference between the
+ // Jacobians is less than error_tolerance.
+ static bool Probe(double const* const* probe_point,
+ double error_tolerance,
+ CostFunctionToProbe *term,
+ GradientCheckResults* results) {
+ CHECK_NOTNULL(probe_point);
+ CHECK_NOTNULL(term);
+ LOG(INFO) << "-------------------- Starting Probe() --------------------";
+
+ // We need a GradientCheckeresults, whether or not they supplied one.
+ internal::scoped_ptr<GradientCheckResults> owned_results;
+ if (results == NULL) {
+ owned_results.reset(new GradientCheckResults);
+ results = owned_results.get();
+ }
+
+ // Do a consistency check between the term and the template parameters.
+ CHECK_EQ(M, term->num_residuals());
+ const int num_residuals = M;
+ const vector<int16>& block_sizes = term->parameter_block_sizes();
+ const int num_blocks = block_sizes.size();
+
+ CHECK_LE(num_blocks, 5) << "Unable to test functions that take more "
+ << "than 5 parameter blocks";
+ if (N0) {
+ CHECK_EQ(N0, block_sizes[0]);
+ CHECK_GE(num_blocks, 1);
+ } else {
+ CHECK_LT(num_blocks, 1);
+ }
+ if (N1) {
+ CHECK_EQ(N1, block_sizes[1]);
+ CHECK_GE(num_blocks, 2);
+ } else {
+ CHECK_LT(num_blocks, 2);
+ }
+ if (N2) {
+ CHECK_EQ(N2, block_sizes[2]);
+ CHECK_GE(num_blocks, 3);
+ } else {
+ CHECK_LT(num_blocks, 3);
+ }
+ if (N3) {
+ CHECK_EQ(N3, block_sizes[3]);
+ CHECK_GE(num_blocks, 4);
+ } else {
+ CHECK_LT(num_blocks, 4);
+ }
+ if (N4) {
+ CHECK_EQ(N4, block_sizes[4]);
+ CHECK_GE(num_blocks, 5);
+ } else {
+ CHECK_LT(num_blocks, 5);
+ }
+
+ results->term_jacobians.clear();
+ results->term_jacobians.resize(num_blocks);
+ results->finite_difference_jacobians.clear();
+ results->finite_difference_jacobians.resize(num_blocks);
+
+ internal::FixedArray<double*> term_jacobian_pointers(num_blocks);
+ internal::FixedArray<double*>
+ finite_difference_jacobian_pointers(num_blocks);
+ for (int i = 0; i < num_blocks; i++) {
+ results->term_jacobians[i].resize(num_residuals, block_sizes[i]);
+ term_jacobian_pointers[i] = results->term_jacobians[i].data();
+ results->finite_difference_jacobians[i].resize(
+ num_residuals, block_sizes[i]);
+ finite_difference_jacobian_pointers[i] =
+ results->finite_difference_jacobians[i].data();
+ }
+ results->cost.resize(num_residuals, 1);
+
+ CHECK(term->Evaluate(probe_point, results->cost.data(),
+ term_jacobian_pointers.get()));
+ NumericDiffCostFunction<CostFunctionToProbe, CENTRAL, M, N0, N1, N2, N3, N4>
+ numeric_term(term, DO_NOT_TAKE_OWNERSHIP);
+ CHECK(numeric_term.Evaluate(probe_point, results->cost.data(),
+ finite_difference_jacobian_pointers.get()));
+
+ results->error_jacobians = 0;
+ for (int i = 0; i < num_blocks; i++) {
+ Matrix jacobian_difference = results->term_jacobians[i] -
+ results->finite_difference_jacobians[i];
+ results->error_jacobians =
+ std::max(results->error_jacobians,
+ jacobian_difference.lpNorm<Eigen::Infinity>());
+ }
+
+ LOG(INFO) << "========== term-computed derivatives ==========";
+ for (int i = 0; i < num_blocks; i++) {
+ LOG(INFO) << "term_computed block " << i;
+ LOG(INFO) << "\n" << results->term_jacobians[i];
+ }
+
+ LOG(INFO) << "========== finite-difference derivatives ==========";
+ for (int i = 0; i < num_blocks; i++) {
+ LOG(INFO) << "finite_difference block " << i;
+ LOG(INFO) << "\n" << results->finite_difference_jacobians[i];
+ }
+
+ LOG(INFO) << "========== difference ==========";
+ for (int i = 0; i < num_blocks; i++) {
+ LOG(INFO) << "difference block " << i;
+ LOG(INFO) << (results->term_jacobians[i] -
+ results->finite_difference_jacobians[i]);
+ }
+
+ LOG(INFO) << "||difference|| = " << results->error_jacobians;
+
+ return results->error_jacobians < error_tolerance;
+ }
+
+ private:
+ CERES_DISALLOW_IMPLICIT_CONSTRUCTORS(GradientChecker);
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_GRADIENT_CHECKER_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/autodiff.h b/extern/libmv/third_party/ceres/include/ceres/internal/autodiff.h
index 4f5081f8f66..011f2a05b65 100644
--- a/extern/libmv/third_party/ceres/include/ceres/internal/autodiff.h
+++ b/extern/libmv/third_party/ceres/include/ceres/internal/autodiff.h
@@ -146,6 +146,7 @@
#include "ceres/jet.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/fixed_array.h"
+#include "ceres/internal/variadic_evaluate.h"
namespace ceres {
namespace internal {
@@ -191,134 +192,71 @@ inline void Take1stOrderPart(const int M, const JetT *src, T *dst) {
DCHECK(src);
DCHECK(dst);
for (int i = 0; i < M; ++i) {
- Eigen::Map<Eigen::Matrix<T, N, 1> >(dst + N * i, N) = src[i].v.template segment<N>(N0);
+ Eigen::Map<Eigen::Matrix<T, N, 1> >(dst + N * i, N) =
+ src[i].v.template segment<N>(N0);
}
}
-// This block of quasi-repeated code calls the user-supplied functor, which may
-// take a variable number of arguments. This is accomplished by specializing the
-// struct based on the size of the trailing parameters; parameters with 0 size
-// are assumed missing.
-//
-// Supporting variadic functions is the primary source of complexity in the
-// autodiff implementation.
-
-template<typename Functor, typename T,
- int N0, int N1, int N2, int N3, int N4, int N5>
-struct VariadicEvaluate {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- input[2],
- input[3],
- input[4],
- input[5],
- output);
- }
-};
-
-template<typename Functor, typename T,
- int N0, int N1, int N2, int N3, int N4>
-struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- input[2],
- input[3],
- input[4],
- output);
- }
-};
-
-template<typename Functor, typename T,
- int N0, int N1, int N2, int N3>
-struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, 0, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- input[2],
- input[3],
- output);
- }
-};
-
-template<typename Functor, typename T,
- int N0, int N1, int N2>
-struct VariadicEvaluate<Functor, T, N0, N1, N2, 0, 0, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- input[2],
- output);
- }
-};
-
-template<typename Functor, typename T,
- int N0, int N1>
-struct VariadicEvaluate<Functor, T, N0, N1, 0, 0, 0, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- output);
- }
-};
-
-template<typename Functor, typename T, int N0>
-struct VariadicEvaluate<Functor, T, N0, 0, 0, 0, 0, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- output);
- }
-};
-
-// This is in a struct because default template parameters on a function are not
-// supported in C++03 (though it is available in C++0x). N0 through N5 are the
-// dimension of the input arguments to the user supplied functor.
+// This is in a struct because default template parameters on a
+// function are not supported in C++03 (though it is available in
+// C++0x). N0 through N5 are the dimension of the input arguments to
+// the user supplied functor.
template <typename Functor, typename T,
- int N0 = 0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0, int N5=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>
struct AutoDiff {
static bool Differentiate(const Functor& functor,
T const *const *parameters,
int num_outputs,
T *function_value,
T **jacobians) {
- typedef Jet<T, N0 + N1 + N2 + N3 + N4 + N5> JetT;
-
- DCHECK_GT(N0, 0)
- << "Cost functions must have at least one parameter block.";
- DCHECK((!N1 && !N2 && !N3 && !N4 && !N5) ||
- ((N1 > 0) && !N2 && !N3 && !N4 && !N5) ||
- ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0)))
+ // This block breaks the 80 column rule to keep it somewhat readable.
+ DCHECK_GT(num_outputs, 0);
+ CHECK((!N1 && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && (N9 > 0)))
<< "Zero block cannot precede a non-zero block. Block sizes are "
<< "(ignore trailing 0s): " << N0 << ", " << N1 << ", " << N2 << ", "
- << N3 << ", " << N4 << ", " << N5;
-
- DCHECK_GT(num_outputs, 0);
+ << N3 << ", " << N4 << ", " << N5 << ", " << N6 << ", " << N7 << ", "
+ << N8 << ", " << N9;
+ typedef Jet<T, N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9> JetT;
FixedArray<JetT, (256 * 7) / sizeof(JetT)> x(
- N0 + N1 + N2 + N3 + N4 + N5 + num_outputs);
+ N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9 + num_outputs);
- // It's ugly, but it works.
- const int jet0 = 0;
- const int jet1 = N0;
- const int jet2 = N0 + N1;
- const int jet3 = N0 + N1 + N2;
- const int jet4 = N0 + N1 + N2 + N3;
- const int jet5 = N0 + N1 + N2 + N3 + N4;
- const int jet6 = N0 + N1 + N2 + N3 + N4 + N5;
+ // These are the positions of the respective jets in the fixed array x.
+ const int jet0 = 0;
+ const int jet1 = N0;
+ const int jet2 = N0 + N1;
+ const int jet3 = N0 + N1 + N2;
+ const int jet4 = N0 + N1 + N2 + N3;
+ const int jet5 = N0 + N1 + N2 + N3 + N4;
+ const int jet6 = N0 + N1 + N2 + N3 + N4 + N5;
+ const int jet7 = N0 + N1 + N2 + N3 + N4 + N5 + N6;
+ const int jet8 = N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7;
+ const int jet9 = N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8;
- const JetT *unpacked_parameters[6] = {
+ const JetT *unpacked_parameters[10] = {
x.get() + jet0,
x.get() + jet1,
x.get() + jet2,
x.get() + jet3,
x.get() + jet4,
x.get() + jet5,
+ x.get() + jet6,
+ x.get() + jet7,
+ x.get() + jet8,
+ x.get() + jet9,
};
- JetT *output = x.get() + jet6;
+
+ JetT* output = x.get() + N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9;
#define CERES_MAKE_1ST_ORDER_PERTURBATION(i) \
if (N ## i) { \
@@ -333,10 +271,14 @@ struct AutoDiff {
CERES_MAKE_1ST_ORDER_PERTURBATION(3);
CERES_MAKE_1ST_ORDER_PERTURBATION(4);
CERES_MAKE_1ST_ORDER_PERTURBATION(5);
+ CERES_MAKE_1ST_ORDER_PERTURBATION(6);
+ CERES_MAKE_1ST_ORDER_PERTURBATION(7);
+ CERES_MAKE_1ST_ORDER_PERTURBATION(8);
+ CERES_MAKE_1ST_ORDER_PERTURBATION(9);
#undef CERES_MAKE_1ST_ORDER_PERTURBATION
if (!VariadicEvaluate<Functor, JetT,
- N0, N1, N2, N3, N4, N5>::Call(
+ N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>::Call(
functor, unpacked_parameters, output)) {
return false;
}
@@ -359,6 +301,10 @@ struct AutoDiff {
CERES_TAKE_1ST_ORDER_PERTURBATION(3);
CERES_TAKE_1ST_ORDER_PERTURBATION(4);
CERES_TAKE_1ST_ORDER_PERTURBATION(5);
+ CERES_TAKE_1ST_ORDER_PERTURBATION(6);
+ CERES_TAKE_1ST_ORDER_PERTURBATION(7);
+ CERES_TAKE_1ST_ORDER_PERTURBATION(8);
+ CERES_TAKE_1ST_ORDER_PERTURBATION(9);
#undef CERES_TAKE_1ST_ORDER_PERTURBATION
return true;
}
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/fixed_array.h b/extern/libmv/third_party/ceres/include/ceres/internal/fixed_array.h
index ce777d22dc7..fa4a339d757 100644
--- a/extern/libmv/third_party/ceres/include/ceres/internal/fixed_array.h
+++ b/extern/libmv/third_party/ceres/include/ceres/internal/fixed_array.h
@@ -168,11 +168,11 @@ inline FixedArray<T, S>::FixedArray(typename FixedArray<T, S>::size_type n)
array_((n <= kInlineElements
? reinterpret_cast<InnerContainer*>(inline_space_)
: new InnerContainer[n])) {
- DCHECK_GE(n, 0);
+ DCHECK_GE(n, size_t(0));
// Construct only the elements actually used.
if (array_ == reinterpret_cast<InnerContainer*>(inline_space_)) {
- for (int i = 0; i != size_; ++i) {
+ for (size_t i = 0; i != size_; ++i) {
inline_space_[i].Init();
}
}
@@ -183,7 +183,7 @@ inline FixedArray<T, S>::~FixedArray() {
if (array_ != reinterpret_cast<InnerContainer*>(inline_space_)) {
delete[] array_;
} else {
- for (int i = 0; i != size_; ++i) {
+ for (size_t i = 0; i != size_; ++i) {
inline_space_[i].Destroy();
}
}
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/macros.h b/extern/libmv/third_party/ceres/include/ceres/internal/macros.h
index 83ec31193e7..388cf30fe70 100644
--- a/extern/libmv/third_party/ceres/include/ceres/internal/macros.h
+++ b/extern/libmv/third_party/ceres/include/ceres/internal/macros.h
@@ -132,16 +132,16 @@ char (&ArraySizeHelper(const T (&array)[N]))[N];
// - wan 2005-11-16
//
// Starting with Visual C++ 2005, WinNT.h includes ARRAYSIZE. However,
-// the definition comes from the over-broad windows.h header that
+// the definition comes from the over-broad windows.h header that
// introduces a macro, ERROR, that conflicts with the logging framework
// that Ceres uses. Instead, rename ARRAYSIZE to CERES_ARRAYSIZE.
-#define CERES_ARRAYSIZE(a) \
- ((sizeof(a) / sizeof(*(a))) / \
+#define CERES_ARRAYSIZE(a) \
+ ((sizeof(a) / sizeof(*(a))) / \
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
-// Tell the compiler to warn about unused return values for functions declared
-// with this macro. The macro should be used on function declarations
-// following the argument list:
+// Tell the compiler to warn about unused return values for functions
+// declared with this macro. The macro should be used on function
+// declarations following the argument list:
//
// Sprocket* AllocateSprocket() MUST_USE_RESULT;
//
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/manual_constructor.h b/extern/libmv/third_party/ceres/include/ceres/internal/manual_constructor.h
index 174d35ee2bd..7ea723d2a83 100644
--- a/extern/libmv/third_party/ceres/include/ceres/internal/manual_constructor.h
+++ b/extern/libmv/third_party/ceres/include/ceres/internal/manual_constructor.h
@@ -110,56 +110,61 @@ class ManualConstructor {
inline Type& operator*() { return *get(); }
inline const Type& operator*() const { return *get(); }
+ // This is needed to get around the strict aliasing warning GCC generates.
+ inline void* space() {
+ return reinterpret_cast<void*>(space_);
+ }
+
// You can pass up to four constructor arguments as arguments of Init().
inline void Init() {
- new(space_) Type;
+ new(space()) Type;
}
template <typename T1>
inline void Init(const T1& p1) {
- new(space_) Type(p1);
+ new(space()) Type(p1);
}
template <typename T1, typename T2>
inline void Init(const T1& p1, const T2& p2) {
- new(space_) Type(p1, p2);
+ new(space()) Type(p1, p2);
}
template <typename T1, typename T2, typename T3>
inline void Init(const T1& p1, const T2& p2, const T3& p3) {
- new(space_) Type(p1, p2, p3);
+ new(space()) Type(p1, p2, p3);
}
template <typename T1, typename T2, typename T3, typename T4>
inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4) {
- new(space_) Type(p1, p2, p3, p4);
+ new(space()) Type(p1, p2, p3, p4);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
const T5& p5) {
- new(space_) Type(p1, p2, p3, p4, p5);
+ new(space()) Type(p1, p2, p3, p4, p5);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6>
inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
const T5& p5, const T6& p6) {
- new(space_) Type(p1, p2, p3, p4, p5, p6);
+ new(space()) Type(p1, p2, p3, p4, p5, p6);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7>
inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
const T5& p5, const T6& p6, const T7& p7) {
- new(space_) Type(p1, p2, p3, p4, p5, p6, p7);
+ new(space()) Type(p1, p2, p3, p4, p5, p6, p7);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8>
inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
const T5& p5, const T6& p6, const T7& p7, const T8& p8) {
- new(space_) Type(p1, p2, p3, p4, p5, p6, p7, p8);
+ new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
@@ -167,7 +172,7 @@ class ManualConstructor {
inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
const T5& p5, const T6& p6, const T7& p7, const T8& p8,
const T9& p9) {
- new(space_) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9);
+ new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
@@ -175,7 +180,7 @@ class ManualConstructor {
inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
const T5& p5, const T6& p6, const T7& p7, const T8& p8,
const T9& p9, const T10& p10) {
- new(space_) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
+ new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
@@ -184,7 +189,7 @@ class ManualConstructor {
inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
const T5& p5, const T6& p6, const T7& p7, const T8& p8,
const T9& p9, const T10& p10, const T11& p11) {
- new(space_) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11);
+ new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11);
}
inline void Destroy() {
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/numeric_diff.h b/extern/libmv/third_party/ceres/include/ceres/internal/numeric_diff.h
new file mode 100644
index 00000000000..4058366c4a1
--- /dev/null
+++ b/extern/libmv/third_party/ceres/include/ceres/internal/numeric_diff.h
@@ -0,0 +1,199 @@
+// 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)
+// mierle@gmail.com (Keir Mierle)
+//
+// Finite differencing routine used by NumericDiffCostFunction.
+
+#ifndef CERES_PUBLIC_INTERNAL_NUMERIC_DIFF_H_
+#define CERES_PUBLIC_INTERNAL_NUMERIC_DIFF_H_
+
+#include <cstring>
+
+#include "Eigen/Dense"
+#include "ceres/cost_function.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/internal/variadic_evaluate.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+
+namespace ceres {
+namespace internal {
+
+// Helper templates that allow evaluation of a variadic functor or a
+// CostFunction object.
+template <typename CostFunctor,
+ int N0, int N1, int N2, int N3, int N4,
+ int N5, int N6, int N7, int N8, int N9 >
+bool EvaluateImpl(const CostFunctor* functor,
+ double const* const* parameters,
+ double* residuals,
+ const void* /* NOT USED */) {
+ return VariadicEvaluate<CostFunctor,
+ double,
+ N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>::Call(
+ *functor,
+ parameters,
+ residuals);
+}
+
+template <typename CostFunctor,
+ int N0, int N1, int N2, int N3, int N4,
+ int N5, int N6, int N7, int N8, int N9 >
+bool EvaluateImpl(const CostFunctor* functor,
+ double const* const* parameters,
+ double* residuals,
+ const CostFunction* /* NOT USED */) {
+ return functor->Evaluate(parameters, residuals, NULL);
+}
+
+// This is split from the main class because C++ doesn't allow partial template
+// specializations for member functions. The alternative is to repeat the main
+// class for differing numbers of parameters, which is also unfortunate.
+template <typename CostFunctor,
+ NumericDiffMethod kMethod,
+ int kNumResiduals,
+ int N0, int N1, int N2, int N3, int N4,
+ int N5, int N6, int N7, int N8, int N9,
+ int kParameterBlock,
+ int kParameterBlockSize>
+struct NumericDiff {
+ // Mutates parameters but must restore them before return.
+ static bool EvaluateJacobianForParameterBlock(
+ const CostFunctor* functor,
+ double const* residuals_at_eval_point,
+ const double relative_step_size,
+ double **parameters,
+ double *jacobian) {
+ using Eigen::Map;
+ using Eigen::Matrix;
+ using Eigen::RowMajor;
+ using Eigen::ColMajor;
+
+ typedef Matrix<double, kNumResiduals, 1> ResidualVector;
+ typedef Matrix<double, kParameterBlockSize, 1> ParameterVector;
+ typedef Matrix<double, kNumResiduals, kParameterBlockSize,
+ (kParameterBlockSize == 1 &&
+ kNumResiduals > 1) ? ColMajor : RowMajor> JacobianMatrix;
+
+
+ Map<JacobianMatrix> parameter_jacobian(jacobian,
+ kNumResiduals,
+ kParameterBlockSize);
+
+ // Mutate 1 element at a time and then restore.
+ Map<ParameterVector> x_plus_delta(parameters[kParameterBlock],
+ kParameterBlockSize);
+ ParameterVector x(x_plus_delta);
+ ParameterVector step_size = x.array().abs() * relative_step_size;
+
+ // To handle cases where a parameter is exactly zero, instead use
+ // the mean step_size for the other dimensions. If all the
+ // parameters are zero, there's no good answer. Take
+ // relative_step_size as a guess and hope for the best.
+ const double fallback_step_size =
+ (step_size.sum() == 0)
+ ? relative_step_size
+ : step_size.sum() / step_size.rows();
+
+ // For each parameter in the parameter block, use finite differences to
+ // compute the derivative for that parameter.
+ for (int j = 0; j < kParameterBlockSize; ++j) {
+ const double delta =
+ (step_size(j) == 0.0) ? fallback_step_size : step_size(j);
+
+ x_plus_delta(j) = x(j) + delta;
+
+ double residuals[kNumResiduals]; // NOLINT
+
+ if (!EvaluateImpl<CostFunctor, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>(
+ functor, parameters, residuals, functor)) {
+ return false;
+ }
+
+ // Compute this column of the jacobian in 3 steps:
+ // 1. Store residuals for the forward part.
+ // 2. Subtract residuals for the backward (or 0) part.
+ // 3. Divide out the run.
+ parameter_jacobian.col(j) =
+ Map<const ResidualVector>(residuals, kNumResiduals);
+
+ double one_over_delta = 1.0 / delta;
+ if (kMethod == CENTRAL) {
+ // Compute the function on the other side of x(j).
+ x_plus_delta(j) = x(j) - delta;
+
+ if (!EvaluateImpl<CostFunctor, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>(
+ functor, parameters, residuals, functor)) {
+ return false;
+ }
+
+ parameter_jacobian.col(j) -=
+ Map<ResidualVector>(residuals, kNumResiduals, 1);
+ one_over_delta /= 2;
+ } else {
+ // Forward difference only; reuse existing residuals evaluation.
+ parameter_jacobian.col(j) -=
+ Map<const ResidualVector>(residuals_at_eval_point, kNumResiduals);
+ }
+ x_plus_delta(j) = x(j); // Restore x_plus_delta.
+
+ // Divide out the run to get slope.
+ parameter_jacobian.col(j) *= one_over_delta;
+ }
+ return true;
+ }
+};
+
+template <typename CostFunctor,
+ NumericDiffMethod kMethod,
+ int kNumResiduals,
+ int N0, int N1, int N2, int N3, int N4,
+ int N5, int N6, int N7, int N8, int N9,
+ int kParameterBlock>
+struct NumericDiff<CostFunctor, kMethod, kNumResiduals,
+ N0, N1, N2, N3, N4, N5, N6, N7, N8, N9,
+ kParameterBlock, 0> {
+ // Mutates parameters but must restore them before return.
+ static bool EvaluateJacobianForParameterBlock(
+ const CostFunctor* functor,
+ double const* residuals_at_eval_point,
+ const double relative_step_size,
+ double **parameters,
+ double *jacobian) {
+ LOG(FATAL) << "Control should never reach here.";
+ return true;
+ }
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_PUBLIC_INTERNAL_NUMERIC_DIFF_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/scoped_ptr.h b/extern/libmv/third_party/ceres/include/ceres/internal/scoped_ptr.h
index 44f198b339d..5dfb551243c 100644
--- a/extern/libmv/third_party/ceres/include/ceres/internal/scoped_ptr.h
+++ b/extern/libmv/third_party/ceres/include/ceres/internal/scoped_ptr.h
@@ -38,6 +38,7 @@
#include <assert.h>
#include <stdlib.h>
#include <cstddef>
+#include <algorithm>
namespace ceres {
namespace internal {
@@ -49,18 +50,17 @@ template <class C> class scoped_array;
template <class C>
scoped_ptr<C> make_scoped_ptr(C *);
-// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>
-// automatically deletes the pointer it holds (if any). That is, scoped_ptr<T>
-// owns the T object that it points to. Like a T*, a scoped_ptr<T> may hold
-// either NULL or a pointer to a T object. Also like T*, scoped_ptr<T> is
-// thread-compatible, and once you dereference it, you get the threadsafety
-// guarantees of T.
+// A scoped_ptr<T> is like a T*, except that the destructor of
+// scoped_ptr<T> automatically deletes the pointer it holds (if
+// any). That is, scoped_ptr<T> owns the T object that it points
+// to. Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to
+// a T object. Also like T*, scoped_ptr<T> is thread-compatible, and
+// once you dereference it, you get the threadsafety guarantees of T.
//
// The size of a scoped_ptr is small: sizeof(scoped_ptr<C>) == sizeof(C*)
template <class C>
class scoped_ptr {
public:
-
// The element type
typedef C element_type;
@@ -193,7 +193,6 @@ scoped_ptr<C> make_scoped_ptr(C *p) {
template <class C>
class scoped_array {
public:
-
// The element type
typedef C element_type;
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/variadic_evaluate.h b/extern/libmv/third_party/ceres/include/ceres/internal/variadic_evaluate.h
new file mode 100644
index 00000000000..4b1e4bdc65a
--- /dev/null
+++ b/extern/libmv/third_party/ceres/include/ceres/internal/variadic_evaluate.h
@@ -0,0 +1,182 @@
+// 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)
+// mierle@gmail.com (Keir Mierle)
+
+#ifndef CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_
+#define CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_
+
+#include <stddef.h>
+
+#include <glog/logging.h>
+#include "ceres/jet.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/fixed_array.h"
+
+namespace ceres {
+namespace internal {
+
+// This block of quasi-repeated code calls the user-supplied functor, which may
+// take a variable number of arguments. This is accomplished by specializing the
+// struct based on the size of the trailing parameters; parameters with 0 size
+// are assumed missing.
+template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4,
+ int N5, int N6, int N7, int N8, int N9>
+struct VariadicEvaluate {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input[0],
+ input[1],
+ input[2],
+ input[3],
+ input[4],
+ input[5],
+ input[6],
+ input[7],
+ input[8],
+ input[9],
+ output);
+ }
+};
+
+template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4,
+ int N5, int N6, int N7, int N8>
+struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, N5, N6, N7, N8, 0> {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input[0],
+ input[1],
+ input[2],
+ input[3],
+ input[4],
+ input[5],
+ input[6],
+ input[7],
+ input[8],
+ output);
+ }
+};
+
+template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4,
+ int N5, int N6, int N7>
+struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, N5, N6, N7, 0, 0> {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input[0],
+ input[1],
+ input[2],
+ input[3],
+ input[4],
+ input[5],
+ input[6],
+ input[7],
+ output);
+ }
+};
+
+template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4,
+ int N5, int N6>
+struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, N5, N6, 0, 0, 0> {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input[0],
+ input[1],
+ input[2],
+ input[3],
+ input[4],
+ input[5],
+ input[6],
+ output);
+ }
+};
+
+template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4,
+ int N5>
+struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, N5, 0, 0, 0, 0> {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input[0],
+ input[1],
+ input[2],
+ input[3],
+ input[4],
+ input[5],
+ output);
+ }
+};
+
+template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4>
+struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, 0, 0, 0, 0, 0> {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input[0],
+ input[1],
+ input[2],
+ input[3],
+ input[4],
+ output);
+ }
+};
+
+template<typename Functor, typename T, int N0, int N1, int N2, int N3>
+struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, 0, 0, 0, 0, 0, 0> {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input[0],
+ input[1],
+ input[2],
+ input[3],
+ output);
+ }
+};
+
+template<typename Functor, typename T, int N0, int N1, int N2>
+struct VariadicEvaluate<Functor, T, N0, N1, N2, 0, 0, 0, 0, 0, 0, 0> {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input[0],
+ input[1],
+ input[2],
+ output);
+ }
+};
+
+template<typename Functor, typename T, int N0, int N1>
+struct VariadicEvaluate<Functor, T, N0, N1, 0, 0, 0, 0, 0, 0, 0, 0> {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input[0],
+ input[1],
+ output);
+ }
+};
+
+template<typename Functor, typename T, int N0>
+struct VariadicEvaluate<Functor, T, N0, 0, 0, 0, 0, 0, 0, 0, 0, 0> {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input[0],
+ output);
+ }
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/iteration_callback.h b/extern/libmv/third_party/ceres/include/ceres/iteration_callback.h
index 29157d380f2..0dc4c96b441 100644
--- a/extern/libmv/third_party/ceres/include/ceres/iteration_callback.h
+++ b/extern/libmv/third_party/ceres/include/ceres/iteration_callback.h
@@ -42,6 +42,23 @@ namespace ceres {
// This struct describes the state of the optimizer after each
// iteration of the minimization.
struct IterationSummary {
+ IterationSummary()
+ : iteration(0),
+ step_is_valid(false),
+ step_is_nonmonotonic(false),
+ step_is_successful(false),
+ cost(0.0),
+ cost_change(0.0),
+ gradient_max_norm(0.0),
+ step_norm(0.0),
+ eta(0.0),
+ step_size(0.0),
+ line_search_function_evaluations(0),
+ linear_solver_iterations(0),
+ iteration_time_in_seconds(0.0),
+ step_solver_time_in_seconds(0.0),
+ cumulative_time_in_seconds(0.0) {}
+
// Current iteration number.
int32 iteration;
@@ -51,7 +68,22 @@ struct IterationSummary {
// Note: step_is_valid is false when iteration = 0.
bool step_is_valid;
- // Whether or not the algorithm made progress in this iteration.
+ // Step did not reduce the value of the objective function
+ // sufficiently, but it was accepted because of the relaxed
+ // acceptance criterion used by the non-monotonic trust region
+ // algorithm.
+ //
+ // Note: step_is_nonmonotonic is false when iteration = 0;
+ bool step_is_nonmonotonic;
+
+ // Whether or not the minimizer accepted this step or not. If the
+ // ordinary trust region algorithm is used, this means that the
+ // relative reduction in the objective function value was greater
+ // than Solver::Options::min_relative_decrease. However, if the
+ // non-monotonic trust region algorithm is used
+ // (Solver::Options:use_nonmonotonic_steps = true), then even if the
+ // relative decrease is not sufficient, the algorithm may accept the
+ // step and the step is declared successful.
//
// Note: step_is_successful is false when iteration = 0.
bool step_is_successful;
@@ -60,8 +92,7 @@ struct IterationSummary {
double cost;
// Change in the value of the objective function in this
- // iteration. This can be positive or negative. Negative change
- // means that the step was not successful.
+ // iteration. This can be positive or negative.
double cost_change;
// Infinity norm of the gradient vector.
@@ -87,6 +118,12 @@ struct IterationSummary {
// ignore it.
double eta;
+ // Step sized computed by the line search algorithm.
+ double step_size;
+
+ // Number of function evaluations used by the line search algorithm.
+ int line_search_function_evaluations;
+
// Number of iterations taken by the linear solver to solve for the
// Newton step.
int linear_solver_iterations;
diff --git a/extern/libmv/third_party/ceres/include/ceres/numeric_diff_cost_function.h b/extern/libmv/third_party/ceres/include/ceres/numeric_diff_cost_function.h
index 8544e44d0bc..555bc3d073f 100644
--- a/extern/libmv/third_party/ceres/include/ceres/numeric_diff_cost_function.h
+++ b/extern/libmv/third_party/ceres/include/ceres/numeric_diff_cost_function.h
@@ -27,19 +27,109 @@
// POSSIBILITY OF SUCH DAMAGE.
//
// Author: keir@google.com (Keir Mierle)
+// sameeragarwal@google.com (Sameer Agarwal)
//
// Create CostFunctions as needed by the least squares framework with jacobians
// computed via numeric (a.k.a. finite) differentiation. For more details see
// http://en.wikipedia.org/wiki/Numerical_differentiation.
//
-// To get a numerically differentiated cost function, define a subclass of
-// CostFunction such that the Evaluate() function ignores the jacobian
-// parameter. The numeric differentiation wrapper will fill in the jacobian
-// parameter if nececssary by repeatedly calling the Evaluate() function with
-// small changes to the appropriate parameters, and computing the slope. For
-// performance, the numeric differentiation wrapper class is templated on the
-// concrete cost function, even though it could be implemented only in terms of
-// the virtual CostFunction interface.
+// To get an numerically differentiated cost function, you must define
+// a class with a operator() (a functor) that computes the residuals.
+//
+// The function must write the computed value in the last argument (the only
+// non-const one) and return true to indicate success.
+//
+// For example, consider a scalar error e = k - x'y, where both x and y are
+// two-dimensional column vector parameters, the prime sign indicates
+// transposition, and k is a constant. The form of this error, which is the
+// difference between a constant and an expression, is a common pattern in least
+// squares problems. For example, the value x'y might be the model expectation
+// for a series of measurements, where there is an instance of the cost function
+// for each measurement k.
+//
+// The actual cost added to the total problem is e^2, or (k - x'k)^2; however,
+// the squaring is implicitly done by the optimization framework.
+//
+// To write an numerically-differentiable cost function for the above model, first
+// define the object
+//
+// class MyScalarCostFunctor {
+// MyScalarCostFunctor(double k): k_(k) {}
+//
+// bool operator()(const double* const x,
+// const double* const y,
+// double* residuals) const {
+// residuals[0] = k_ - x[0] * y[0] + x[1] * y[1];
+// return true;
+// }
+//
+// private:
+// double k_;
+// };
+//
+// Note that in the declaration of operator() the input parameters x
+// and y come first, and are passed as const pointers to arrays of
+// doubles. If there were three input parameters, then the third input
+// parameter would come after y. The output is always the last
+// parameter, and is also a pointer to an array. In the example above,
+// the residual is a scalar, so only residuals[0] is set.
+//
+// Then given this class definition, the numerically differentiated
+// cost function with central differences used for computing the
+// derivative can be constructed as follows.
+//
+// CostFunction* cost_function
+// = new NumericDiffCostFunction<MyScalarCostFunctor, CENTRAL, 1, 2, 2>(
+// new MyScalarCostFunctor(1.0)); ^ ^ ^
+// | | | |
+// Finite Differencing Scheme -+ | | |
+// Dimension of residual ----------+ | |
+// Dimension of x --------------------+ |
+// Dimension of y -----------------------+
+//
+// In this example, there is usually an instance for each measumerent of k.
+//
+// In the instantiation above, the template parameters following
+// "MyScalarCostFunctor", "1, 2, 2", describe the functor as computing
+// a 1-dimensional output from two arguments, both 2-dimensional.
+//
+// The framework can currently accommodate cost functions of up to 10
+// independent variables, and there is no limit on the dimensionality
+// of each of them.
+//
+// The central difference method is considerably more accurate at the cost of
+// twice as many function evaluations than forward difference. Consider using
+// central differences begin with, and only after that works, trying forward
+// difference to improve performance.
+//
+// TODO(sameeragarwal): Add support for dynamic number of residuals.
+//
+// WARNING #1: A common beginner's error when first using
+// NumericDiffCostFunction is to get the sizing wrong. In particular,
+// there is a tendency to set the template parameters to (dimension of
+// residual, number of parameters) instead of passing a dimension
+// parameter for *every parameter*. In the example above, that would
+// be <MyScalarCostFunctor, 1, 2>, which is missing the last '2'
+// argument. Please be careful when setting the size parameters.
+//
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+//
+// ALTERNATE INTERFACE
+//
+// For a variety of reason, including compatibility with legacy code,
+// NumericDiffCostFunction can also take CostFunction objects as
+// input. The following describes how.
+//
+// To get a numerically differentiated cost function, define a
+// subclass of CostFunction such that the Evaluate() function ignores
+// the jacobian parameter. The numeric differentiation wrapper will
+// fill in the jacobian parameter if nececssary by repeatedly calling
+// the Evaluate() function with small changes to the appropriate
+// parameters, and computing the slope. For performance, the numeric
+// differentiation wrapper class is templated on the concrete cost
+// function, even though it could be implemented only in terms of the
+// virtual CostFunction interface.
//
// The numerically differentiated version of a cost function for a cost function
// can be constructed as follows:
@@ -51,233 +141,153 @@
// where MyCostFunction has 1 residual and 2 parameter blocks with sizes 4 and 8
// respectively. Look at the tests for a more detailed example.
//
-// The central difference method is considerably more accurate at the cost of
-// twice as many function evaluations than forward difference. Consider using
-// central differences begin with, and only after that works, trying forward
-// difference to improve performance.
-//
// TODO(keir): Characterize accuracy; mention pitfalls; provide alternatives.
#ifndef CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_
#define CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_
-#include <cstring>
#include <glog/logging.h>
#include "Eigen/Dense"
+#include "ceres/cost_function.h"
+#include "ceres/internal/numeric_diff.h"
#include "ceres/internal/scoped_ptr.h"
#include "ceres/sized_cost_function.h"
#include "ceres/types.h"
namespace ceres {
-enum NumericDiffMethod {
- CENTRAL,
- FORWARD
-};
-
-// This is split from the main class because C++ doesn't allow partial template
-// specializations for member functions. The alternative is to repeat the main
-// class for differing numbers of parameters, which is also unfortunate.
-template <typename CostFunctionNoJacobian,
- int num_residuals,
- int parameter_block_size,
- int parameter_block,
- NumericDiffMethod method>
-struct Differencer {
- // Mutates parameters but must restore them before return.
- static bool EvaluateJacobianForParameterBlock(
- const CostFunctionNoJacobian *function,
- double const* residuals_at_eval_point,
- double **parameters,
- double **jacobians) {
- using Eigen::Map;
- using Eigen::Matrix;
- using Eigen::RowMajor;
- using Eigen::ColMajor;
-
- typedef Matrix<double, num_residuals, 1> ResidualVector;
- typedef Matrix<double, parameter_block_size, 1> ParameterVector;
- typedef Matrix<double, num_residuals, parameter_block_size,
- (parameter_block_size == 1 &&
- num_residuals > 1) ? ColMajor : RowMajor> JacobianMatrix;
-
- Map<JacobianMatrix> parameter_jacobian(jacobians[parameter_block],
- num_residuals,
- parameter_block_size);
-
- // Mutate 1 element at a time and then restore.
- Map<ParameterVector> x_plus_delta(parameters[parameter_block],
- parameter_block_size);
- ParameterVector x(x_plus_delta);
-
- // TODO(keir): Pick a smarter number! In theory a good choice is sqrt(eps) *
- // x, which for doubles means about 1e-8 * x. However, I have found this
- // number too optimistic. This number should be exposed for users to change.
- const double kRelativeStepSize = 1e-6;
-
- ParameterVector step_size = x.array().abs() * kRelativeStepSize;
-
- // To handle cases where a parameter is exactly zero, instead use the mean
- // step_size for the other dimensions.
- double fallback_step_size = step_size.sum() / step_size.rows();
- if (fallback_step_size == 0.0) {
- // If all the parameters are zero, there's no good answer. Take
- // kRelativeStepSize as a guess and hope for the best.
- fallback_step_size = kRelativeStepSize;
- }
-
- // For each parameter in the parameter block, use finite differences to
- // compute the derivative for that parameter.
- for (int j = 0; j < parameter_block_size; ++j) {
- if (step_size(j) == 0.0) {
- // The parameter is exactly zero, so compromise and use the mean
- // step_size from the other parameters. This can break in many cases,
- // but it's hard to pick a good number without problem specific
- // knowledge.
- step_size(j) = fallback_step_size;
- }
- x_plus_delta(j) = x(j) + step_size(j);
-
- double residuals[num_residuals]; // NOLINT
- if (!function->Evaluate(parameters, residuals, NULL)) {
- // Something went wrong; bail.
- return false;
- }
-
- // Compute this column of the jacobian in 3 steps:
- // 1. Store residuals for the forward part.
- // 2. Subtract residuals for the backward (or 0) part.
- // 3. Divide out the run.
- parameter_jacobian.col(j) =
- Map<const ResidualVector>(residuals, num_residuals);
-
- double one_over_h = 1 / step_size(j);
- if (method == CENTRAL) {
- // Compute the function on the other side of x(j).
- x_plus_delta(j) = x(j) - step_size(j);
-
- if (!function->Evaluate(parameters, residuals, NULL)) {
- // Something went wrong; bail.
- return false;
- }
- parameter_jacobian.col(j) -=
- Map<ResidualVector>(residuals, num_residuals, 1);
- one_over_h /= 2;
- } else {
- // Forward difference only; reuse existing residuals evaluation.
- parameter_jacobian.col(j) -=
- Map<const ResidualVector>(residuals_at_eval_point, num_residuals);
- }
- x_plus_delta(j) = x(j); // Restore x_plus_delta.
-
- // Divide out the run to get slope.
- parameter_jacobian.col(j) *= one_over_h;
- }
- return true;
- }
-};
-
-// Prevent invalid instantiations.
-template <typename CostFunctionNoJacobian,
- int num_residuals,
- int parameter_block,
- NumericDiffMethod method>
-struct Differencer<CostFunctionNoJacobian,
- num_residuals,
- 0 /* parameter_block_size */,
- parameter_block,
- method> {
- static bool EvaluateJacobianForParameterBlock(
- const CostFunctionNoJacobian *function,
- double const* residuals_at_eval_point,
- double **parameters,
- double **jacobians) {
- LOG(FATAL) << "Shouldn't get here.";
- return true;
- }
-};
-
-template <typename CostFunctionNoJacobian,
- NumericDiffMethod method = CENTRAL, int M = 0,
- int N0 = 0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0, int N5 = 0>
+template <typename CostFunctor,
+ NumericDiffMethod method = CENTRAL,
+ int kNumResiduals = 0, // Number of residuals, or ceres::DYNAMIC
+ int N0 = 0, // Number of parameters in block 0.
+ int N1 = 0, // Number of parameters in block 1.
+ int N2 = 0, // Number of parameters in block 2.
+ int N3 = 0, // Number of parameters in block 3.
+ int N4 = 0, // Number of parameters in block 4.
+ int N5 = 0, // Number of parameters in block 5.
+ int N6 = 0, // Number of parameters in block 6.
+ int N7 = 0, // Number of parameters in block 7.
+ int N8 = 0, // Number of parameters in block 8.
+ int N9 = 0> // Number of parameters in block 9.
class NumericDiffCostFunction
- : public SizedCostFunction<M, N0, N1, N2, N3, N4, N5> {
+ : public SizedCostFunction<kNumResiduals,
+ N0, N1, N2, N3, N4,
+ N5, N6, N7, N8, N9> {
public:
- NumericDiffCostFunction(CostFunctionNoJacobian* function,
- Ownership ownership)
- : function_(function), ownership_(ownership) {}
+ NumericDiffCostFunction(CostFunctor* functor,
+ const double relative_step_size = 1e-6)
+ :functor_(functor),
+ ownership_(TAKE_OWNERSHIP),
+ relative_step_size_(relative_step_size) {}
- virtual ~NumericDiffCostFunction() {
+ NumericDiffCostFunction(CostFunctor* functor,
+ Ownership ownership,
+ const double relative_step_size = 1e-6)
+ : functor_(functor),
+ ownership_(ownership),
+ relative_step_size_(relative_step_size) {}
+
+ ~NumericDiffCostFunction() {
if (ownership_ != TAKE_OWNERSHIP) {
- function_.release();
+ functor_.release();
}
}
virtual bool Evaluate(double const* const* parameters,
double* residuals,
double** jacobians) const {
+ using internal::FixedArray;
+ using internal::NumericDiff;
+
+ const int kNumParameters = N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9;
+ const int kNumParameterBlocks =
+ (N0 > 0) + (N1 > 0) + (N2 > 0) + (N3 > 0) + (N4 > 0) +
+ (N5 > 0) + (N6 > 0) + (N7 > 0) + (N8 > 0) + (N9 > 0);
+
// Get the function value (residuals) at the the point to evaluate.
- bool success = function_->Evaluate(parameters, residuals, NULL);
- if (!success) {
- // Something went wrong; ignore the jacobian.
+ if (!internal::EvaluateImpl<CostFunctor,
+ N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>(
+ functor_.get(),
+ parameters,
+ residuals,
+ functor_.get())) {
return false;
}
+
if (!jacobians) {
- // Nothing to do; just forward.
return true;
}
// Create a copy of the parameters which will get mutated.
- const int kParametersSize = N0 + N1 + N2 + N3 + N4 + N5;
- double parameters_copy[kParametersSize];
- double *parameters_references_copy[6];
- parameters_references_copy[0] = &parameters_copy[0];
- parameters_references_copy[1] = &parameters_copy[0] + N0;
- parameters_references_copy[2] = &parameters_copy[0] + N0 + N1;
- parameters_references_copy[3] = &parameters_copy[0] + N0 + N1 + N2;
- parameters_references_copy[4] = &parameters_copy[0] + N0 + N1 + N2 + N3;
- parameters_references_copy[5] =
- &parameters_copy[0] + N0 + N1 + N2 + N3 + N4;
+ FixedArray<double> parameters_copy(kNumParameters);
+ FixedArray<double*> parameters_reference_copy(kNumParameterBlocks);
+
+ parameters_reference_copy[0] = parameters_copy.get();
+ if (N1) parameters_reference_copy[1] = parameters_reference_copy[0] + N0;
+ if (N2) parameters_reference_copy[2] = parameters_reference_copy[1] + N1;
+ if (N3) parameters_reference_copy[3] = parameters_reference_copy[2] + N2;
+ if (N4) parameters_reference_copy[4] = parameters_reference_copy[3] + N3;
+ if (N5) parameters_reference_copy[5] = parameters_reference_copy[4] + N4;
+ if (N6) parameters_reference_copy[6] = parameters_reference_copy[5] + N5;
+ if (N7) parameters_reference_copy[7] = parameters_reference_copy[6] + N6;
+ if (N7) parameters_reference_copy[8] = parameters_reference_copy[7] + N7;
+ if (N8) parameters_reference_copy[9] = parameters_reference_copy[8] + N8;
+
+#define COPY_PARAMETER_BLOCK(block) \
+ if (N ## block) memcpy(parameters_reference_copy[block], \
+ parameters[block], \
+ sizeof(double) * N ## block); // NOLINT
-#define COPY_PARAMETER_BLOCK(block) \
- if (N ## block) memcpy(parameters_references_copy[block], \
- parameters[block], \
- sizeof(double) * N ## block); // NOLINT
COPY_PARAMETER_BLOCK(0);
COPY_PARAMETER_BLOCK(1);
COPY_PARAMETER_BLOCK(2);
COPY_PARAMETER_BLOCK(3);
COPY_PARAMETER_BLOCK(4);
COPY_PARAMETER_BLOCK(5);
+ COPY_PARAMETER_BLOCK(6);
+ COPY_PARAMETER_BLOCK(7);
+ COPY_PARAMETER_BLOCK(8);
+ COPY_PARAMETER_BLOCK(9);
+
#undef COPY_PARAMETER_BLOCK
-#define EVALUATE_JACOBIAN_FOR_BLOCK(block) \
- if (N ## block && jacobians[block]) { \
- if (!Differencer<CostFunctionNoJacobian, /* NOLINT */ \
- M, \
- N ## block, \
- block, \
- method>::EvaluateJacobianForParameterBlock( \
- function_.get(), \
- residuals, \
- parameters_references_copy, \
- jacobians)) { \
- return false; \
- } \
+#define EVALUATE_JACOBIAN_FOR_BLOCK(block) \
+ if (N ## block && jacobians[block] != NULL) { \
+ if (!NumericDiff<CostFunctor, \
+ method, \
+ kNumResiduals, \
+ N0, N1, N2, N3, N4, N5, N6, N7, N8, N9, \
+ block, \
+ N ## block >::EvaluateJacobianForParameterBlock( \
+ functor_.get(), \
+ residuals, \
+ relative_step_size_, \
+ parameters_reference_copy.get(), \
+ jacobians[block])) { \
+ return false; \
+ } \
}
+
EVALUATE_JACOBIAN_FOR_BLOCK(0);
EVALUATE_JACOBIAN_FOR_BLOCK(1);
EVALUATE_JACOBIAN_FOR_BLOCK(2);
EVALUATE_JACOBIAN_FOR_BLOCK(3);
EVALUATE_JACOBIAN_FOR_BLOCK(4);
EVALUATE_JACOBIAN_FOR_BLOCK(5);
+ EVALUATE_JACOBIAN_FOR_BLOCK(6);
+ EVALUATE_JACOBIAN_FOR_BLOCK(7);
+ EVALUATE_JACOBIAN_FOR_BLOCK(8);
+ EVALUATE_JACOBIAN_FOR_BLOCK(9);
+
#undef EVALUATE_JACOBIAN_FOR_BLOCK
+
return true;
}
private:
- internal::scoped_ptr<CostFunctionNoJacobian> function_;
+ internal::scoped_ptr<CostFunctor> functor_;
Ownership ownership_;
+ const double relative_step_size_;
};
} // namespace ceres
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
new file mode 100644
index 00000000000..593c3718bf5
--- /dev/null
+++ b/extern/libmv/third_party/ceres/include/ceres/numeric_diff_functor.h
@@ -0,0 +1,346 @@
+// 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,
+ 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, 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_
diff --git a/extern/libmv/third_party/ceres/include/ceres/ordered_groups.h b/extern/libmv/third_party/ceres/include/ceres/ordered_groups.h
new file mode 100644
index 00000000000..e373d35b9d7
--- /dev/null
+++ b/extern/libmv/third_party/ceres/include/ceres/ordered_groups.h
@@ -0,0 +1,176 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 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: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_PUBLIC_ORDERED_GROUPS_H_
+#define CERES_PUBLIC_ORDERED_GROUPS_H_
+
+#include <map>
+#include <set>
+#include "ceres/internal/port.h"
+
+namespace ceres {
+
+// A class for storing and manipulating an ordered collection of
+// groups/sets with the following semantics:
+//
+// Group ids are non-negative integer values. Elements are any type
+// that can serve as a key in a map or an element of a set.
+//
+// An element can only belong to one group at a time. A group may
+// contain an arbitrary number of elements.
+//
+// Groups are ordered by their group id.
+template <typename T>
+class OrderedGroups {
+ public:
+ // Add an element to a group. If a group with this id does not
+ // exist, one is created. This method can be called any number of
+ // times for the same element. Group ids should be non-negative
+ // numbers.
+ //
+ // Return value indicates if adding the element was a success.
+ bool AddElementToGroup(const T element, const int group) {
+ if (group < 0) {
+ return false;
+ }
+
+ typename map<T, int>::const_iterator it = element_to_group_.find(element);
+ if (it != element_to_group_.end()) {
+ if (it->second == group) {
+ // Element is already in the right group, nothing to do.
+ return true;
+ }
+
+ group_to_elements_[it->second].erase(element);
+ if (group_to_elements_[it->second].size() == 0) {
+ group_to_elements_.erase(it->second);
+ }
+ }
+
+ element_to_group_[element] = group;
+ group_to_elements_[group].insert(element);
+ return true;
+ }
+
+ void Clear() {
+ group_to_elements_.clear();
+ element_to_group_.clear();
+ }
+
+ // Remove the element, no matter what group it is in. If the element
+ // is not a member of any group, calling this method will result in
+ // a crash.
+ //
+ // Return value indicates if the element was actually removed.
+ bool Remove(const T element) {
+ const int current_group = GroupId(element);
+ if (current_group < 0) {
+ return false;
+ }
+
+ group_to_elements_[current_group].erase(element);
+
+ if (group_to_elements_[current_group].size() == 0) {
+ // If the group is empty, then get rid of it.
+ group_to_elements_.erase(current_group);
+ }
+
+ element_to_group_.erase(element);
+ return true;
+ }
+
+ // Reverse the order of the groups in place.
+ void Reverse() {
+ typename map<int, set<T> >::reverse_iterator it =
+ group_to_elements_.rbegin();
+ map<int, set<T> > new_group_to_elements;
+ new_group_to_elements[it->first] = it->second;
+
+ int new_group_id = it->first + 1;
+ for (++it; it != group_to_elements_.rend(); ++it) {
+ for (typename set<T>::const_iterator element_it = it->second.begin();
+ element_it != it->second.end();
+ ++element_it) {
+ element_to_group_[*element_it] = new_group_id;
+ }
+ new_group_to_elements[new_group_id] = it->second;
+ new_group_id++;
+ }
+
+ group_to_elements_.swap(new_group_to_elements);
+ }
+
+ // Return the group id for the element. If the element is not a
+ // member of any group, return -1.
+ int GroupId(const T element) const {
+ typename map<T, int>::const_iterator it = element_to_group_.find(element);
+ if (it == element_to_group_.end()) {
+ return -1;
+ }
+ return it->second;
+ }
+
+ bool IsMember(const T element) const {
+ typename map<T, int>::const_iterator it = element_to_group_.find(element);
+ return (it != element_to_group_.end());
+ }
+
+ // This function always succeeds, i.e., implicitly there exists a
+ // group for every integer.
+ int GroupSize(const int group) const {
+ typename map<int, set<T> >::const_iterator it =
+ group_to_elements_.find(group);
+ return (it == group_to_elements_.end()) ? 0 : it->second.size();
+ }
+
+ int NumElements() const {
+ return element_to_group_.size();
+ }
+
+ // Number of groups with one or more elements.
+ int NumGroups() const {
+ return group_to_elements_.size();
+ }
+
+ const map<int, set<T> >& group_to_elements() const {
+ return group_to_elements_;
+ }
+
+ private:
+ map<int, set<T> > group_to_elements_;
+ map<T, int> element_to_group_;
+};
+
+// Typedef for the most commonly used version of OrderedGroups.
+typedef OrderedGroups<double*> ParameterBlockOrdering;
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_ORDERED_GROUP_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/problem.h b/extern/libmv/third_party/ceres/include/ceres/problem.h
index 2b08c6723e8..bccb329dc55 100644
--- a/extern/libmv/third_party/ceres/include/ceres/problem.h
+++ b/extern/libmv/third_party/ceres/include/ceres/problem.h
@@ -39,11 +39,12 @@
#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"
+
namespace ceres {
@@ -51,6 +52,7 @@ class CostFunction;
class LossFunction;
class LocalParameterization;
class Solver;
+struct CRSMatrix;
namespace internal {
class Preprocessor;
@@ -59,10 +61,9 @@ class ParameterBlock;
class ResidualBlock;
} // namespace internal
-// A ResidualBlockId is a handle clients can use to delete residual
-// blocks after creating them. They are opaque for any purposes other
-// than that.
-typedef const internal::ResidualBlock* ResidualBlockId;
+// A ResidualBlockId is an opaque handle clients can use to remove residual
+// blocks from a Problem after adding them.
+typedef internal::ResidualBlock* ResidualBlockId;
// A class to represent non-linear least squares problems. Such
// problems have a cost function that is a sum of error terms (known
@@ -122,7 +123,9 @@ class Problem {
Options()
: cost_function_ownership(TAKE_OWNERSHIP),
loss_function_ownership(TAKE_OWNERSHIP),
- local_parameterization_ownership(TAKE_OWNERSHIP) {}
+ local_parameterization_ownership(TAKE_OWNERSHIP),
+ enable_fast_parameter_block_removal(false),
+ disable_all_safety_checks(false) {}
// These flags control whether the Problem object owns the cost
// functions, loss functions, and parameterizations passed into
@@ -134,6 +137,29 @@ class Problem {
Ownership cost_function_ownership;
Ownership loss_function_ownership;
Ownership local_parameterization_ownership;
+
+ // If true, trades memory for a faster RemoveParameterBlock() operation.
+ //
+ // RemoveParameterBlock() takes time proportional to the size of the entire
+ // Problem. If you only remove parameter blocks from the Problem
+ // occassionaly, this may be acceptable. However, if you are modifying the
+ // Problem frequently, and have memory to spare, then flip this switch to
+ // make RemoveParameterBlock() take time proportional to the number of
+ // residual blocks that depend on it. The increase in memory usage is an
+ // additonal hash set per parameter block containing all the residuals that
+ // depend on the parameter block.
+ bool enable_fast_parameter_block_removal;
+
+ // By default, Ceres performs a variety of safety checks when constructing
+ // the problem. There is a small but measurable performance penalty to
+ // these checks, typically around 5% of construction time. If you are sure
+ // your problem construction is correct, and 5% of the problem construction
+ // time is truly an overhead you want to avoid, then you can set
+ // disable_all_safety_checks to true.
+ //
+ // WARNING: Do not set this to true, unless you are absolutely sure of what
+ // you are doing.
+ bool disable_all_safety_checks;
};
// The default constructor is equivalent to the
@@ -208,6 +234,27 @@ class Problem {
LossFunction* loss_function,
double* x0, double* x1, double* x2,
double* x3, double* x4, double* x5);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3, double* x4, double* x5,
+ double* x6);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3, double* x4, double* x5,
+ double* x6, double* x7);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3, double* x4, double* x5,
+ double* x6, double* x7, double* x8);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3, double* x4, double* x5,
+ double* x6, double* x7, double* x8,
+ double* x9);
// Add a parameter block with appropriate size to the problem.
// Repeated calls with the same arguments are ignored. Repeated
@@ -223,6 +270,33 @@ class Problem {
int size,
LocalParameterization* local_parameterization);
+ // Remove a parameter block from the problem. The parameterization of the
+ // parameter block, if it exists, will persist until the deletion of the
+ // problem (similar to cost/loss functions in residual block removal). Any
+ // residual blocks that depend on the parameter are also removed, as
+ // described above in RemoveResidualBlock().
+ //
+ // If Problem::Options::enable_fast_parameter_block_removal is true, then the
+ // removal is fast (almost constant time). Otherwise, removing a parameter
+ // block will incur a scan of the entire Problem object.
+ //
+ // WARNING: Removing a residual or parameter block will destroy the implicit
+ // ordering, rendering the jacobian or residuals returned from the solver
+ // uninterpretable. If you depend on the evaluated jacobian, do not use
+ // remove! This may change in a future release.
+ void RemoveParameterBlock(double* values);
+
+ // Remove a residual block from the problem. Any parameters that the residual
+ // block depends on are not removed. The cost and loss functions for the
+ // residual block will not get deleted immediately; won't happen until the
+ // problem itself is deleted.
+ //
+ // WARNING: Removing a residual or parameter block will destroy the implicit
+ // ordering, rendering the jacobian or residuals returned from the solver
+ // uninterpretable. If you depend on the evaluated jacobian, do not use
+ // remove! This may change in a future release.
+ void RemoveResidualBlock(ResidualBlockId residual_block);
+
// Hold the indicated parameter block constant during optimization.
void SetParameterBlockConstant(double* values);
@@ -254,6 +328,76 @@ class Problem {
// sizes of all of the residual blocks.
int NumResiduals() const;
+ // Options struct to control Problem::Evaluate.
+ struct EvaluateOptions {
+ EvaluateOptions()
+ : num_threads(1) {
+ }
+
+ // The set of parameter blocks for which evaluation should be
+ // performed. This vector determines the order that parameter
+ // blocks occur in the gradient vector and in the columns of the
+ // jacobian matrix. If parameter_blocks is empty, then it is
+ // assumed to be equal to vector containing ALL the parameter
+ // blocks. Generally speaking the parameter blocks will occur in
+ // the order in which they were added to the problem. But, this
+ // may change if the user removes any parameter blocks from the
+ // problem.
+ //
+ // NOTE: This vector should contain the same pointers as the ones
+ // used to add parameter blocks to the Problem. These parmeter
+ // block should NOT point to new memory locations. Bad things will
+ // happen otherwise.
+ vector<double*> parameter_blocks;
+
+ // The set of residual blocks to evaluate. This vector determines
+ // the order in which the residuals occur, and how the rows of the
+ // jacobian are ordered. If residual_blocks is empty, then it is
+ // assumed to be equal to the vector containing all the residual
+ // blocks. If this vector is empty, then it is assumed to be equal
+ // to a vector containing ALL the residual blocks. Generally
+ // speaking the residual blocks will occur in the order in which
+ // they were added to the problem. But, this may change if the
+ // user removes any residual blocks from the problem.
+ vector<ResidualBlockId> residual_blocks;
+ int num_threads;
+ };
+
+ // Evaluate Problem. Any of the output pointers can be NULL. Which
+ // residual blocks and parameter blocks are used is controlled by
+ // the EvaluateOptions struct above.
+ //
+ // Note 1: The evaluation will use the values stored in the memory
+ // locations pointed to by the parameter block pointers used at the
+ // time of the construction of the problem. i.e.,
+ //
+ // Problem problem;
+ // double x = 1;
+ // problem.Add(new MyCostFunction, NULL, &x);
+ //
+ // double cost = 0.0;
+ // problem.Evaluate(Problem::EvaluateOptions(), &cost, NULL, NULL, NULL);
+ //
+ // The cost is evaluated at x = 1. If you wish to evaluate the
+ // problem at x = 2, then
+ //
+ // x = 2;
+ // problem.Evaluate(Problem::EvaluateOptions(), &cost, NULL, NULL, NULL);
+ //
+ // is the way to do so.
+ //
+ // Note 2: If no local parameterizations are used, then the size of
+ // the gradient vector (and the number of columns in the jacobian)
+ // is the sum of the sizes of all the parameter blocks. If a
+ // parameter block has a local parameterization, then it contributes
+ // "LocalSize" entries to the gradient vecto (and the number of
+ // columns in the jacobian).
+ bool Evaluate(const EvaluateOptions& options,
+ double* cost,
+ vector<double>* residuals,
+ vector<double>* gradient,
+ CRSMatrix* jacobian);
+
private:
friend class Solver;
internal::scoped_ptr<internal::ProblemImpl> problem_impl_;
diff --git a/extern/libmv/third_party/ceres/include/ceres/rotation.h b/extern/libmv/third_party/ceres/include/ceres/rotation.h
index 0d8a390d5d1..ffac4f1dc0c 100644
--- a/extern/libmv/third_party/ceres/include/ceres/rotation.h
+++ b/extern/libmv/third_party/ceres/include/ceres/rotation.h
@@ -51,6 +51,31 @@
namespace ceres {
+// Trivial wrapper to index linear arrays as matrices, given a fixed
+// column and row stride. When an array "T* array" is wrapped by a
+//
+// (const) MatrixAdapter<T, row_stride, col_stride> M"
+//
+// the expression M(i, j) is equivalent to
+//
+// arrary[i * row_stride + j * col_stride]
+//
+// Conversion functions to and from rotation matrices accept
+// MatrixAdapters to permit using row-major and column-major layouts,
+// and rotation matrices embedded in larger matrices (such as a 3x4
+// projection matrix).
+template <typename T, int row_stride, int col_stride>
+struct MatrixAdapter;
+
+// Convenience functions to create a MatrixAdapter that treats the
+// array pointed to by "pointer" as a 3x3 (contiguous) column-major or
+// row-major matrix.
+template <typename T>
+MatrixAdapter<T, 1, 3> ColumnMajorAdapter3x3(T* pointer);
+
+template <typename T>
+MatrixAdapter<T, 3, 1> RowMajorAdapter3x3(T* pointer);
+
// Convert a value in combined axis-angle representation to a quaternion.
// The value angle_axis is a triple whose norm is an angle in radians,
// and whose direction is aligned with the axis of rotation,
@@ -73,9 +98,20 @@ void QuaternionToAngleAxis(T const* quaternion, T* angle_axis);
// axis-angle rotation representations. Templated for use with
// autodifferentiation.
template <typename T>
-void RotationMatrixToAngleAxis(T const * R, T * angle_axis);
+void RotationMatrixToAngleAxis(T const* R, T* angle_axis);
+
+template <typename T, int row_stride, int col_stride>
+void RotationMatrixToAngleAxis(
+ const MatrixAdapter<const T, row_stride, col_stride>& R,
+ T* angle_axis);
+
template <typename T>
-void AngleAxisToRotationMatrix(T const * angle_axis, T * R);
+void AngleAxisToRotationMatrix(T const* angle_axis, T* R);
+
+template <typename T, int row_stride, int col_stride>
+void AngleAxisToRotationMatrix(
+ T const* angle_axis,
+ const MatrixAdapter<T, row_stride, col_stride>& R);
// Conversions between 3x3 rotation matrix (in row major order) and
// Euler angle (in degrees) rotation representations.
@@ -86,6 +122,11 @@ void AngleAxisToRotationMatrix(T const * angle_axis, T * R);
template <typename T>
void EulerAnglesToRotationMatrix(const T* euler, int row_stride, T* R);
+template <typename T, int row_stride, int col_stride>
+void EulerAnglesToRotationMatrix(
+ const T* euler,
+ const MatrixAdapter<T, row_stride, col_stride>& R);
+
// Convert a 4-vector to a 3x3 scaled rotation matrix.
//
// The choice of rotation is such that the quaternion [1 0 0 0] goes to an
@@ -108,11 +149,21 @@ void EulerAnglesToRotationMatrix(const T* euler, int row_stride, T* R);
template <typename T> inline
void QuaternionToScaledRotation(const T q[4], T R[3 * 3]);
+template <typename T, int row_stride, int col_stride> inline
+void QuaternionToScaledRotation(
+ const T q[4],
+ const MatrixAdapter<T, row_stride, col_stride>& R);
+
// Same as above except that the rotation matrix is normalized by the
// Frobenius norm, so that R * R' = I (and det(R) = 1).
template <typename T> inline
void QuaternionToRotation(const T q[4], T R[3 * 3]);
+template <typename T, int row_stride, int col_stride> inline
+void QuaternionToRotation(
+ const T q[4],
+ const MatrixAdapter<T, row_stride, col_stride>& R);
+
// Rotates a point pt by a quaternion q:
//
// result = R(q) * pt
@@ -146,6 +197,28 @@ void AngleAxisRotatePoint(const T angle_axis[3], const T pt[3], T result[3]);
// --- IMPLEMENTATION
+template<typename T, int row_stride, int col_stride>
+struct MatrixAdapter {
+ T* pointer_;
+ explicit MatrixAdapter(T* pointer)
+ : pointer_(pointer)
+ {}
+
+ T& operator()(int r, int c) const {
+ return pointer_[r * row_stride + c * col_stride];
+ }
+};
+
+template <typename T>
+MatrixAdapter<T, 1, 3> ColumnMajorAdapter3x3(T* pointer) {
+ return MatrixAdapter<T, 1, 3>(pointer);
+}
+
+template <typename T>
+MatrixAdapter<T, 3, 1> RowMajorAdapter3x3(T* pointer) {
+ return MatrixAdapter<T, 3, 1>(pointer);
+}
+
template<typename T>
inline void AngleAxisToQuaternion(const T* angle_axis, T* quaternion) {
const T& a0 = angle_axis[0];
@@ -228,17 +301,24 @@ inline void QuaternionToAngleAxis(const T* quaternion, T* angle_axis) {
// to not perform division by a small number.
template <typename T>
inline void RotationMatrixToAngleAxis(const T * R, T * angle_axis) {
+ RotationMatrixToAngleAxis(ColumnMajorAdapter3x3(R), angle_axis);
+}
+
+template <typename T, int row_stride, int col_stride>
+void RotationMatrixToAngleAxis(
+ const MatrixAdapter<const T, row_stride, col_stride>& R,
+ T * angle_axis) {
// x = k * 2 * sin(theta), where k is the axis of rotation.
- angle_axis[0] = R[5] - R[7];
- angle_axis[1] = R[6] - R[2];
- angle_axis[2] = R[1] - R[3];
+ angle_axis[0] = R(2, 1) - R(1, 2);
+ angle_axis[1] = R(0, 2) - R(2, 0);
+ angle_axis[2] = R(1, 0) - R(0, 1);
static const T kOne = T(1.0);
static const T kTwo = T(2.0);
// Since the right hand side may give numbers just above 1.0 or
// below -1.0 leading to atan misbehaving, we threshold.
- T costheta = std::min(std::max((R[0] + R[4] + R[8] - kOne) / kTwo,
+ T costheta = std::min(std::max((R(0, 0) + R(1, 1) + R(2, 2) - kOne) / kTwo,
T(-1.0)),
kOne);
@@ -296,7 +376,7 @@ inline void RotationMatrixToAngleAxis(const T * R, T * angle_axis) {
// with the sign of sin(theta). If they are the same, then
// angle_axis[i] should be positive, otherwise negative.
for (int i = 0; i < 3; ++i) {
- angle_axis[i] = theta * sqrt((R[i*4] - costheta) * inv_one_minus_costheta);
+ angle_axis[i] = theta * sqrt((R(i, i) - costheta) * inv_one_minus_costheta);
if (((sintheta < 0.0) && (angle_axis[i] > 0.0)) ||
((sintheta > 0.0) && (angle_axis[i] < 0.0))) {
angle_axis[i] = -angle_axis[i];
@@ -306,6 +386,13 @@ inline void RotationMatrixToAngleAxis(const T * R, T * angle_axis) {
template <typename T>
inline void AngleAxisToRotationMatrix(const T * angle_axis, T * R) {
+ AngleAxisToRotationMatrix(angle_axis, ColumnMajorAdapter3x3(R));
+}
+
+template <typename T, int row_stride, int col_stride>
+void AngleAxisToRotationMatrix(
+ const T * angle_axis,
+ const MatrixAdapter<T, row_stride, col_stride>& R) {
static const T kOne = T(1.0);
const T theta2 = DotProduct(angle_axis, angle_axis);
if (theta2 > 0.0) {
@@ -320,33 +407,41 @@ inline void AngleAxisToRotationMatrix(const T * angle_axis, T * R) {
const T costheta = cos(theta);
const T sintheta = sin(theta);
- R[0] = costheta + wx*wx*(kOne - costheta);
- R[1] = wz*sintheta + wx*wy*(kOne - costheta);
- R[2] = -wy*sintheta + wx*wz*(kOne - costheta);
- R[3] = wx*wy*(kOne - costheta) - wz*sintheta;
- R[4] = costheta + wy*wy*(kOne - costheta);
- R[5] = wx*sintheta + wy*wz*(kOne - costheta);
- R[6] = wy*sintheta + wx*wz*(kOne - costheta);
- R[7] = -wx*sintheta + wy*wz*(kOne - costheta);
- R[8] = costheta + wz*wz*(kOne - costheta);
+ R(0, 0) = costheta + wx*wx*(kOne - costheta);
+ R(1, 0) = wz*sintheta + wx*wy*(kOne - costheta);
+ R(2, 0) = -wy*sintheta + wx*wz*(kOne - costheta);
+ R(0, 1) = wx*wy*(kOne - costheta) - wz*sintheta;
+ R(1, 1) = costheta + wy*wy*(kOne - costheta);
+ R(2, 1) = wx*sintheta + wy*wz*(kOne - costheta);
+ R(0, 2) = wy*sintheta + wx*wz*(kOne - costheta);
+ R(1, 2) = -wx*sintheta + wy*wz*(kOne - costheta);
+ R(2, 2) = costheta + wz*wz*(kOne - costheta);
} else {
// At zero, we switch to using the first order Taylor expansion.
- R[0] = kOne;
- R[1] = -angle_axis[2];
- R[2] = angle_axis[1];
- R[3] = angle_axis[2];
- R[4] = kOne;
- R[5] = -angle_axis[0];
- R[6] = -angle_axis[1];
- R[7] = angle_axis[0];
- R[8] = kOne;
+ R(0, 0) = kOne;
+ R(1, 0) = -angle_axis[2];
+ R(2, 0) = angle_axis[1];
+ R(0, 1) = angle_axis[2];
+ R(1, 1) = kOne;
+ R(2, 1) = -angle_axis[0];
+ R(0, 2) = -angle_axis[1];
+ R(1, 2) = angle_axis[0];
+ R(2, 2) = kOne;
}
}
template <typename T>
inline void EulerAnglesToRotationMatrix(const T* euler,
- const int row_stride,
+ const int row_stride_parameter,
T* R) {
+ CHECK_EQ(row_stride_parameter, 3);
+ EulerAnglesToRotationMatrix(euler, RowMajorAdapter3x3(R));
+}
+
+template <typename T, int row_stride, int col_stride>
+void EulerAnglesToRotationMatrix(
+ const T* euler,
+ const MatrixAdapter<T, row_stride, col_stride>& R) {
const double kPi = 3.14159265358979323846;
const T degrees_to_radians(kPi / 180.0);
@@ -361,26 +456,28 @@ inline void EulerAnglesToRotationMatrix(const T* euler,
const T c3 = cos(pitch);
const T s3 = sin(pitch);
- // Rows of the rotation matrix.
- T* R1 = R;
- T* R2 = R1 + row_stride;
- T* R3 = R2 + row_stride;
-
- R1[0] = c1*c2;
- R1[1] = -s1*c3 + c1*s2*s3;
- R1[2] = s1*s3 + c1*s2*c3;
+ R(0, 0) = c1*c2;
+ R(0, 1) = -s1*c3 + c1*s2*s3;
+ R(0, 2) = s1*s3 + c1*s2*c3;
- R2[0] = s1*c2;
- R2[1] = c1*c3 + s1*s2*s3;
- R2[2] = -c1*s3 + s1*s2*c3;
+ R(1, 0) = s1*c2;
+ R(1, 1) = c1*c3 + s1*s2*s3;
+ R(1, 2) = -c1*s3 + s1*s2*c3;
- R3[0] = -s2;
- R3[1] = c2*s3;
- R3[2] = c2*c3;
+ R(2, 0) = -s2;
+ R(2, 1) = c2*s3;
+ R(2, 2) = c2*c3;
}
template <typename T> inline
void QuaternionToScaledRotation(const T q[4], T R[3 * 3]) {
+ QuaternionToScaledRotation(q, RowMajorAdapter3x3(R));
+}
+
+template <typename T, int row_stride, int col_stride> inline
+void QuaternionToScaledRotation(
+ const T q[4],
+ const MatrixAdapter<T, row_stride, col_stride>& R) {
// Make convenient names for elements of q.
T a = q[0];
T b = q[1];
@@ -399,21 +496,29 @@ void QuaternionToScaledRotation(const T q[4], T R[3 * 3]) {
T cd = c * d;
T dd = d * d;
- R[0] = aa + bb - cc - dd; R[1] = T(2) * (bc - ad); R[2] = T(2) * (ac + bd); // NOLINT
- R[3] = T(2) * (ad + bc); R[4] = aa - bb + cc - dd; R[5] = T(2) * (cd - ab); // NOLINT
- R[6] = T(2) * (bd - ac); R[7] = T(2) * (ab + cd); R[8] = aa - bb - cc + dd; // NOLINT
+ R(0, 0) = aa + bb - cc - dd; R(0, 1) = T(2) * (bc - ad); R(0, 2) = T(2) * (ac + bd); // NOLINT
+ R(1, 0) = T(2) * (ad + bc); R(1, 1) = aa - bb + cc - dd; R(1, 2) = T(2) * (cd - ab); // NOLINT
+ R(2, 0) = T(2) * (bd - ac); R(2, 1) = T(2) * (ab + cd); R(2, 2) = aa - bb - cc + dd; // NOLINT
}
template <typename T> inline
void QuaternionToRotation(const T q[4], T R[3 * 3]) {
+ QuaternionToRotation(q, RowMajorAdapter3x3(R));
+}
+
+template <typename T, int row_stride, int col_stride> inline
+void QuaternionToRotation(const T q[4],
+ const MatrixAdapter<T, row_stride, col_stride>& R) {
QuaternionToScaledRotation(q, R);
T normalizer = q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3];
CHECK_NE(normalizer, T(0));
normalizer = T(1) / normalizer;
- for (int i = 0; i < 9; ++i) {
- R[i] *= normalizer;
+ for (int i = 0; i < 3; ++i) {
+ for (int j = 0; j < 3; ++j) {
+ R(i, j) *= normalizer;
+ }
}
}
@@ -433,7 +538,6 @@ void UnitQuaternionRotatePoint(const T q[4], const T pt[3], T result[3]) {
result[2] = T(2) * ((t7 - t3) * pt[0] + (t2 + t9) * pt[1] + (t5 + t8) * pt[2]) + pt[2]; // NOLINT
}
-
template <typename T> inline
void QuaternionRotatePoint(const T q[4], const T pt[3], T result[3]) {
// 'scale' is 1 / norm(q).
diff --git a/extern/libmv/third_party/ceres/include/ceres/sized_cost_function.h b/extern/libmv/third_party/ceres/include/ceres/sized_cost_function.h
index 2894a9fba5c..6bfc1af31a2 100644
--- a/extern/libmv/third_party/ceres/include/ceres/sized_cost_function.h
+++ b/extern/libmv/third_party/ceres/include/ceres/sized_cost_function.h
@@ -45,25 +45,29 @@
namespace ceres {
template<int kNumResiduals,
- int N0 = 0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0, int N5 = 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 SizedCostFunction : public CostFunction {
public:
SizedCostFunction() {
- // Sanity checking.
CHECK(kNumResiduals > 0 || kNumResiduals == DYNAMIC)
<< "Cost functions must have at least one residual block.";
- CHECK_GT(N0, 0)
- << "Cost functions must have at least one parameter block.";
- CHECK((!N1 && !N2 && !N3 && !N4 && !N5) ||
- ((N1 > 0) && !N2 && !N3 && !N4 && !N5) ||
- ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0)))
+ // This block breaks the 80 column rule to keep it somewhat readable.
+ CHECK((!N1 && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && !N9) ||
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && (N9 > 0)))
<< "Zero block cannot precede a non-zero block. Block sizes are "
<< "(ignore trailing 0s): " << N0 << ", " << N1 << ", " << N2 << ", "
- << N3 << ", " << N4 << ", " << N5;
+ << N3 << ", " << N4 << ", " << N5 << ", " << N6 << ", " << N7 << ", "
+ << N8 << ", " << N9;
set_num_residuals(kNumResiduals);
@@ -75,6 +79,10 @@ class SizedCostFunction : public CostFunction {
ADD_PARAMETER_BLOCK(N3);
ADD_PARAMETER_BLOCK(N4);
ADD_PARAMETER_BLOCK(N5);
+ ADD_PARAMETER_BLOCK(N6);
+ ADD_PARAMETER_BLOCK(N7);
+ ADD_PARAMETER_BLOCK(N8);
+ ADD_PARAMETER_BLOCK(N9);
#undef ADD_PARAMETER_BLOCK
}
diff --git a/extern/libmv/third_party/ceres/include/ceres/solver.h b/extern/libmv/third_party/ceres/include/ceres/solver.h
index 31d5e8d7987..122870c86c8 100644
--- a/extern/libmv/third_party/ceres/include/ceres/solver.h
+++ b/extern/libmv/third_party/ceres/include/ceres/solver.h
@@ -38,6 +38,7 @@
#include "ceres/internal/macros.h"
#include "ceres/internal/port.h"
#include "ceres/iteration_callback.h"
+#include "ceres/ordered_groups.h"
#include "ceres/types.h"
namespace ceres {
@@ -57,6 +58,11 @@ class Solver {
struct Options {
// Default constructor that sets up a generic sparse problem.
Options() {
+ minimizer_type = TRUST_REGION;
+ line_search_direction_type = LBFGS;
+ line_search_type = ARMIJO;
+ nonlinear_conjugate_gradient_type = FLETCHER_REEVES;
+ max_lbfgs_rank = 20;
trust_region_strategy_type = LEVENBERG_MARQUARDT;
dogleg_type = TRADITIONAL_DOGLEG;
use_nonmonotonic_steps = false;
@@ -89,27 +95,21 @@ class Solver {
#endif
num_linear_solver_threads = 1;
- num_eliminate_blocks = 0;
- ordering_type = NATURAL;
#if defined(CERES_NO_SUITESPARSE)
use_block_amd = false;
#else
use_block_amd = true;
#endif
-
+ linear_solver_ordering = NULL;
+ use_inner_iterations = false;
+ inner_iteration_ordering = NULL;
linear_solver_min_num_iterations = 1;
linear_solver_max_num_iterations = 500;
eta = 1e-1;
jacobi_scaling = true;
logging_type = PER_MINIMIZER_ITERATION;
minimizer_progress_to_stdout = false;
- return_initial_residuals = false;
- return_initial_gradient = false;
- return_initial_jacobian = false;
- return_final_residuals = false;
- return_final_gradient = false;
- return_final_jacobian = false;
lsqp_dump_directory = "/tmp";
lsqp_dump_format_type = TEXTFILE;
check_gradients = false;
@@ -118,8 +118,64 @@ class Solver {
update_state_every_iteration = false;
}
+ ~Options();
// Minimizer options ----------------------------------------
+ // Ceres supports the two major families of optimization strategies -
+ // Trust Region and Line Search.
+ //
+ // 1. The line search approach first finds a descent direction
+ // along which the objective function will be reduced and then
+ // computes a step size that decides how far should move along
+ // that direction. The descent direction can be computed by
+ // various methods, such as gradient descent, Newton's method and
+ // Quasi-Newton method. The step size can be determined either
+ // exactly or inexactly.
+ //
+ // 2. The trust region approach approximates the objective
+ // function using using a model function (often a quadratic) over
+ // a subset of the search space known as the trust region. If the
+ // model function succeeds in minimizing the true objective
+ // function the trust region is expanded; conversely, otherwise it
+ // is contracted and the model optimization problem is solved
+ // again.
+ //
+ // Trust region methods are in some sense dual to line search methods:
+ // trust region methods first choose a step size (the size of the
+ // trust region) and then a step direction while line search methods
+ // first choose a step direction and then a step size.
+ MinimizerType minimizer_type;
+
+ 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;
+
TrustRegionStrategyType trust_region_strategy_type;
// Type of dogleg strategy to use.
@@ -229,29 +285,76 @@ class Solver {
// using this setting.
int num_linear_solver_threads;
- // For Schur reduction based methods, the first 0 to num blocks are
- // eliminated using the Schur reduction. For example, when solving
- // traditional structure from motion problems where the parameters are in
- // two classes (cameras and points) then num_eliminate_blocks would be the
- // number of points.
- //
- // This parameter is used in conjunction with the ordering.
- // Applies to: Preprocessor and linear least squares solver.
- int num_eliminate_blocks;
-
- // Internally Ceres reorders the parameter blocks to help the
- // various linear solvers. This parameter allows the user to
- // influence the re-ordering strategy used. For structure from
- // motion problems use SCHUR, for other problems NATURAL (default)
- // is a good choice. In case you wish to specify your own ordering
- // scheme, for example in conjunction with num_eliminate_blocks,
- // use USER.
- OrderingType ordering_type;
-
- // The ordering of the parameter blocks. The solver pays attention
- // to it if the ordering_type is set to USER and the vector is
- // non-empty.
- vector<double*> ordering;
+ // The order in which variables are eliminated in a linear solver
+ // can have a significant of impact on the efficiency and accuracy
+ // of the method. e.g., when doing sparse Cholesky factorization,
+ // there are matrices for which a good ordering will give a
+ // Cholesky factor with O(n) storage, where as a bad ordering will
+ // result in an completely dense factor.
+ //
+ // Ceres allows the user to provide varying amounts of hints to
+ // the solver about the variable elimination ordering to use. This
+ // can range from no hints, where the solver is free to decide the
+ // best possible ordering based on the user's choices like the
+ // linear solver being used, to an exact order in which the
+ // variables should be eliminated, and a variety of possibilities
+ // in between.
+ //
+ // Instances of the ParameterBlockOrdering class are used to
+ // communicate this information to Ceres.
+ //
+ // Formally an ordering is an ordered partitioning of the
+ // parameter blocks, i.e, each parameter block belongs to exactly
+ // one group, and each group has a unique non-negative integer
+ // associated with it, that determines its order in the set of
+ // groups.
+ //
+ // Given such an ordering, Ceres ensures that the parameter blocks in
+ // the lowest numbered group are eliminated first, and then the
+ // parmeter blocks in the next lowest numbered group and so on. Within
+ // each group, Ceres is free to order the parameter blocks as it
+ // chooses.
+ //
+ // If NULL, then all parameter blocks are assumed to be in the
+ // same group and the solver is free to decide the best
+ // ordering.
+ //
+ // e.g. Consider the linear system
+ //
+ // x + y = 3
+ // 2x + 3y = 7
+ //
+ // There are two ways in which it can be solved. First eliminating x
+ // from the two equations, solving for y and then back substituting
+ // for x, or first eliminating y, solving for x and back substituting
+ // for y. The user can construct three orderings here.
+ //
+ // {0: x}, {1: y} - eliminate x first.
+ // {0: y}, {1: x} - eliminate y first.
+ // {0: x, y} - Solver gets to decide the elimination order.
+ //
+ // Thus, to have Ceres determine the ordering automatically using
+ // heuristics, put all the variables in group 0 and to control the
+ // ordering for every variable, create groups 0..N-1, one per
+ // variable, in the desired order.
+ //
+ // Bundle Adjustment
+ // -----------------
+ //
+ // A particular case of interest is bundle adjustment, where the user
+ // has two options. The default is to not specify an ordering at all,
+ // the solver will see that the user wants to use a Schur type solver
+ // and figure out the right elimination ordering.
+ //
+ // But if the user already knows what parameter blocks are points and
+ // what are cameras, they can save preprocessing time by partitioning
+ // the parameter blocks into two groups, one for the points and one
+ // for the cameras, where the group containing the points has an id
+ // smaller than the group containing cameras.
+ //
+ // Once assigned, Solver::Options owns this pointer and will
+ // deallocate the memory when destroyed.
+ ParameterBlockOrdering* linear_solver_ordering;
// By virtue of the modeling layer in Ceres being block oriented,
// all the matrices used by Ceres are also block oriented. When
@@ -267,6 +370,77 @@ class Solver {
// sparse_linear_algebra_library = SUITE_SPARSE.
bool use_block_amd;
+ // Some non-linear least squares problems have additional
+ // structure in the way the parameter blocks interact that it is
+ // beneficial to modify the way the trust region step is computed.
+ //
+ // e.g., consider the following regression problem
+ //
+ // y = a_1 exp(b_1 x) + a_2 exp(b_3 x^2 + c_1)
+ //
+ // Given a set of pairs{(x_i, y_i)}, the user wishes to estimate
+ // a_1, a_2, b_1, b_2, and c_1.
+ //
+ // Notice here that the expression on the left is linear in a_1
+ // and a_2, and given any value for b_1, b_2 and c_1, it is
+ // possible to use linear regression to estimate the optimal
+ // values of a_1 and a_2. Indeed, its possible to analytically
+ // eliminate the variables a_1 and a_2 from the problem all
+ // together. Problems like these are known as separable least
+ // squares problem and the most famous algorithm for solving them
+ // is the Variable Projection algorithm invented by Golub &
+ // Pereyra.
+ //
+ // Similar structure can be found in the matrix factorization with
+ // missing data problem. There the corresponding algorithm is
+ // known as Wiberg's algorithm.
+ //
+ // Ruhe & Wedin (Algorithms for Separable Nonlinear Least Squares
+ // Problems, SIAM Reviews, 22(3), 1980) present an analyis of
+ // various algorithms for solving separable non-linear least
+ // squares problems and refer to "Variable Projection" as
+ // Algorithm I in their paper.
+ //
+ // Implementing Variable Projection is tedious and expensive, and
+ // they present a simpler algorithm, which they refer to as
+ // Algorithm II, where once the Newton/Trust Region step has been
+ // computed for the whole problem (a_1, a_2, b_1, b_2, c_1) and
+ // additional optimization step is performed to estimate a_1 and
+ // a_2 exactly.
+ //
+ // This idea can be generalized to cases where the residual is not
+ // linear in a_1 and a_2, i.e., Solve for the trust region step
+ // for the full problem, and then use it as the starting point to
+ // further optimize just a_1 and a_2. For the linear case, this
+ // amounts to doing a single linear least squares solve. For
+ // non-linear problems, any method for solving the a_1 and a_2
+ // optimization problems will do. The only constraint on a_1 and
+ // a_2 is that they do not co-occur in any residual block.
+ //
+ // This idea can be further generalized, by not just optimizing
+ // (a_1, a_2), but decomposing the graph corresponding to the
+ // Hessian matrix's sparsity structure in a collection of
+ // non-overlapping independent sets and optimizing each of them.
+ //
+ // Setting "use_inner_iterations" to true enables the use of this
+ // non-linear generalization of Ruhe & Wedin's Algorithm II. This
+ // version of Ceres has a higher iteration complexity, but also
+ // displays better convergence behaviour per iteration. Setting
+ // Solver::Options::num_threads to the maximum number possible is
+ // highly recommended.
+ bool use_inner_iterations;
+
+ // If inner_iterations is true, then the user has two choices.
+ //
+ // 1. Let the solver heuristically decide which parameter blocks
+ // to optimize in each inner iteration. To do this leave
+ // Solver::Options::inner_iteration_ordering untouched.
+ //
+ // 2. Specify a collection of of ordered independent sets. Where
+ // the lower numbered groups are optimized before the higher
+ // number groups. Each group must be an independent set.
+ ParameterBlockOrdering* inner_iteration_ordering;
+
// Minimum number of iterations for which the linear solver should
// run, even if the convergence criterion is satisfied.
int linear_solver_min_num_iterations;
@@ -301,14 +475,6 @@ class Solver {
// is sent to STDOUT.
bool minimizer_progress_to_stdout;
- bool return_initial_residuals;
- bool return_initial_gradient;
- bool return_initial_jacobian;
-
- bool return_final_residuals;
- bool return_final_gradient;
- bool return_final_jacobian;
-
// List of iterations at which the optimizer should dump the
// linear least squares problem to disk. Useful for testing and
// benchmarking. If empty (default), no problems are dumped.
@@ -398,6 +564,8 @@ class Solver {
string FullReport() const;
// Minimizer summary -------------------------------------------------
+ MinimizerType minimizer_type;
+
SolverTerminationType termination_type;
// If the solver did not run, or there was a failure, a
@@ -414,54 +582,6 @@ class Solver {
// blocks that they depend on were fixed.
double fixed_cost;
- // Vectors of residuals before and after the optimization. The
- // entries of these vectors are in the order in which
- // ResidualBlocks were added to the Problem object.
- //
- // Whether the residual vectors are populated with values is
- // controlled by Solver::Options::return_initial_residuals and
- // Solver::Options::return_final_residuals respectively.
- vector<double> initial_residuals;
- vector<double> final_residuals;
-
- // Gradient vectors, before and after the optimization. The rows
- // are in the same order in which the ParameterBlocks were added
- // to the Problem object.
- //
- // NOTE: Since AddResidualBlock adds ParameterBlocks to the
- // Problem automatically if they do not already exist, if you wish
- // to have explicit control over the ordering of the vectors, then
- // use Problem::AddParameterBlock to explicitly add the
- // ParameterBlocks in the order desired.
- //
- // Whether the vectors are populated with values is controlled by
- // Solver::Options::return_initial_gradient and
- // Solver::Options::return_final_gradient respectively.
- vector<double> initial_gradient;
- vector<double> final_gradient;
-
- // Jacobian matrices before and after the optimization. The rows
- // of these matrices are in the same order in which the
- // ResidualBlocks were added to the Problem object. The columns
- // are in the same order in which the ParameterBlocks were added
- // to the Problem object.
- //
- // NOTE: Since AddResidualBlock adds ParameterBlocks to the
- // Problem automatically if they do not already exist, if you wish
- // to have explicit control over the column ordering of the
- // matrix, then use Problem::AddParameterBlock to explicitly add
- // the ParameterBlocks in the order desired.
- //
- // The Jacobian matrices are stored as compressed row sparse
- // matrices. Please see ceres/crs_matrix.h for more details of the
- // format.
- //
- // Whether the Jacboan matrices are populated with values is
- // controlled by Solver::Options::return_initial_jacobian and
- // Solver::Options::return_final_jacobian respectively.
- CRSMatrix initial_jacobian;
- CRSMatrix final_jacobian;
-
vector<IterationSummary> iterations;
int num_successful_steps;
@@ -484,6 +604,10 @@ class Solver {
// Some total of all time spent inside Ceres when Solve is called.
double total_time_in_seconds;
+ double linear_solver_time_in_seconds;
+ double residual_evaluation_time_in_seconds;
+ double jacobian_evaluation_time_in_seconds;
+
// Preprocessor summary.
int num_parameter_blocks;
int num_parameters;
@@ -507,12 +631,23 @@ class Solver {
LinearSolverType linear_solver_type_given;
LinearSolverType linear_solver_type_used;
+ vector<int> linear_solver_ordering_given;
+ vector<int> linear_solver_ordering_used;
+
PreconditionerType preconditioner_type;
- OrderingType ordering_type;
TrustRegionStrategyType trust_region_strategy_type;
DoglegType dogleg_type;
+ bool inner_iterations;
+
SparseLinearAlgebraLibraryType sparse_linear_algebra_library;
+
+ LineSearchDirectionType line_search_direction_type;
+ LineSearchType line_search_type;
+ int max_lbfgs_rank;
+
+ vector<int> inner_iteration_ordering_given;
+ vector<int> inner_iteration_ordering_used;
};
// Once a least squares problem has been built, this function takes
diff --git a/extern/libmv/third_party/ceres/include/ceres/types.h b/extern/libmv/third_party/ceres/include/ceres/types.h
index 3980885b53c..5512340f7b3 100644
--- a/extern/libmv/third_party/ceres/include/ceres/types.h
+++ b/extern/libmv/third_party/ceres/include/ceres/types.h
@@ -37,6 +37,8 @@
#ifndef CERES_PUBLIC_TYPES_H_
#define CERES_PUBLIC_TYPES_H_
+#include "ceres/internal/port.h"
+
namespace ceres {
// Basic integer types. These typedefs are in the Ceres namespace to avoid
@@ -99,8 +101,7 @@ enum PreconditionerType {
JACOBI,
// Block diagonal of the Schur complement. This preconditioner may
- // only be used with the ITERATIVE_SCHUR solver. Requires
- // SuiteSparse/CHOLMOD.
+ // only be used with the ITERATIVE_SCHUR solver.
SCHUR_JACOBI,
// Visibility clustering based preconditioners.
@@ -143,18 +144,6 @@ enum LinearSolverTerminationType {
FAILURE
};
-enum OrderingType {
- // The order in which the parameter blocks were defined.
- NATURAL,
-
- // Use the ordering specificed in the vector ordering.
- USER,
-
- // Automatically figure out the best ordering to use the schur
- // complement based solver.
- SCHUR
-};
-
// Logging options
// The options get progressively noisier.
enum LoggingType {
@@ -162,6 +151,55 @@ enum LoggingType {
PER_MINIMIZER_ITERATION
};
+enum MinimizerType {
+ LINE_SEARCH,
+ TRUST_REGION
+};
+
+enum LineSearchDirectionType {
+ // Negative of the gradient.
+ STEEPEST_DESCENT,
+
+ // A generalization of the Conjugate Gradient method to non-linear
+ // functions. The generalization can be performed in a number of
+ // different ways, resulting in a variety of search directions. The
+ // precise choice of the non-linear conjugate gradient algorithm
+ // used is determined by NonlinerConjuateGradientType.
+ NONLINEAR_CONJUGATE_GRADIENT,
+
+ // A limited memory approximation to the inverse Hessian is
+ // maintained and used to compute a quasi-Newton step.
+ //
+ // For more details see
+ //
+ // Nocedal, J. (1980). "Updating Quasi-Newton Matrices with Limited
+ // Storage". Mathematics of Computation 35 (151): 773–782.
+ //
+ // Byrd, R. H.; Nocedal, J.; Schnabel, R. B. (1994).
+ // "Representations of Quasi-Newton Matrices and their use in
+ // Limited Memory Methods". Mathematical Programming 63 (4):
+ // 129–156.
+ LBFGS,
+};
+
+// Nonliner conjugate gradient methods are a generalization of the
+// method of Conjugate Gradients for linear systems. The
+// generalization can be carried out in a number of different ways
+// leading to number of different rules for computing the search
+// direction. Ceres provides a number of different variants. For more
+// details see Numerical Optimization by Nocedal & Wright.
+enum NonlinearConjugateGradientType {
+ FLETCHER_REEVES,
+ POLAK_RIBIRERE,
+ HESTENES_STIEFEL,
+};
+
+enum LineSearchType {
+ // Backtracking line search with polynomial interpolation or
+ // bisection.
+ ARMIJO,
+};
+
// Ceres supports different strategies for computing the trust region
// step.
enum TrustRegionStrategyType {
@@ -296,18 +334,54 @@ enum DimensionType {
DYNAMIC = -1
};
+enum NumericDiffMethod {
+ CENTRAL,
+ FORWARD
+};
+
const char* LinearSolverTypeToString(LinearSolverType type);
+bool StringToLinearSolverType(string value, LinearSolverType* type);
+
const char* PreconditionerTypeToString(PreconditionerType type);
+bool StringToPreconditionerType(string value, PreconditionerType* type);
+
const char* SparseLinearAlgebraLibraryTypeToString(
SparseLinearAlgebraLibraryType type);
+bool StringToSparseLinearAlgebraLibraryType(
+ string value,
+ SparseLinearAlgebraLibraryType* type);
+
+const char* TrustRegionStrategyTypeToString(TrustRegionStrategyType type);
+bool StringToTrustRegionStrategyType(string value,
+ TrustRegionStrategyType* type);
+
+const char* DoglegTypeToString(DoglegType type);
+bool StringToDoglegType(string value, DoglegType* type);
+
+const char* MinimizerTypeToString(MinimizerType type);
+bool StringToMinimizerType(string value, MinimizerType* type);
+
+const char* LineSearchDirectionTypeToString(LineSearchDirectionType type);
+bool StringToLineSearchDirectionType(string value,
+ LineSearchDirectionType* type);
+
+const char* LineSearchTypeToString(LineSearchType type);
+bool StringToLineSearchType(string value, LineSearchType* type);
+
+const char* NonlinearConjugateGradientTypeToString(
+ NonlinearConjugateGradientType type);
+bool StringToNonlinearConjugateGradientType(
+ string value, NonlinearConjugateGradientType* type);
+
const char* LinearSolverTerminationTypeToString(
LinearSolverTerminationType type);
-const char* OrderingTypeToString(OrderingType type);
+
const char* SolverTerminationTypeToString(SolverTerminationType type);
-const char* SparseLinearAlgebraLibraryTypeToString(
- SparseLinearAlgebraLibraryType type);
-const char* TrustRegionStrategyTypeToString( TrustRegionStrategyType type);
+
bool IsSchurType(LinearSolverType type);
+bool IsSparseLinearAlgebraLibraryTypeAvailable(
+ SparseLinearAlgebraLibraryType type);
+
} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/array_utils.h b/extern/libmv/third_party/ceres/internal/ceres/array_utils.h
index 99cc8d8ebbf..742f439d886 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/array_utils.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/array_utils.h
@@ -28,7 +28,7 @@
//
// Author: sameeragarwal@google.com (Sameer Agarwal)
//
-// Utility routines for validating arrays.
+// Utility routines for validating arrays.
//
// These are useful for detecting two common class of errors.
//
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc b/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc
index 474c37f7ca4..1d5f9d77ab0 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc
@@ -40,10 +40,10 @@
namespace ceres {
namespace internal {
-BlockJacobiPreconditioner::BlockJacobiPreconditioner(const LinearOperator& A)
+BlockJacobiPreconditioner::BlockJacobiPreconditioner(
+ const BlockSparseMatrixBase& A)
: num_rows_(A.num_rows()),
- block_structure_(
- *(down_cast<const BlockSparseMatrix*>(&A)->block_structure())) {
+ block_structure_(*A.block_structure()) {
// Calculate the amount of storage needed.
int storage_needed = 0;
for (int c = 0; c < block_structure_.cols.size(); ++c) {
@@ -64,11 +64,10 @@ BlockJacobiPreconditioner::BlockJacobiPreconditioner(const LinearOperator& A)
}
}
-BlockJacobiPreconditioner::~BlockJacobiPreconditioner() {
-}
+BlockJacobiPreconditioner::~BlockJacobiPreconditioner() {}
-void BlockJacobiPreconditioner::Update(const LinearOperator& matrix, const double* D) {
- const BlockSparseMatrix& A = *(down_cast<const BlockSparseMatrix*>(&matrix));
+bool BlockJacobiPreconditioner::Update(const BlockSparseMatrixBase& A,
+ const double* D) {
const CompressedRowBlockStructure* bs = A.block_structure();
// Compute the diagonal blocks by block inner products.
@@ -107,16 +106,19 @@ void BlockJacobiPreconditioner::Update(const LinearOperator& matrix, const doubl
MatrixRef block(blocks_[c], size, size);
if (D != NULL) {
- block.diagonal() += ConstVectorRef(D + position, size).array().square().matrix();
+ block.diagonal() +=
+ ConstVectorRef(D + position, size).array().square().matrix();
}
block = block.selfadjointView<Eigen::Upper>()
.ldlt()
.solve(Matrix::Identity(size, size));
}
+ return true;
}
-void BlockJacobiPreconditioner::RightMultiply(const double* x, double* y) const {
+void BlockJacobiPreconditioner::RightMultiply(const double* x,
+ double* y) const {
for (int c = 0; c < block_structure_.cols.size(); ++c) {
const int size = block_structure_.cols[c].size;
const int position = block_structure_.cols[c].position;
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.h b/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.h
index 91cfeddb688..ed5eebc8dc6 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.h
@@ -32,38 +32,33 @@
#define CERES_INTERNAL_BLOCK_JACOBI_PRECONDITIONER_H_
#include <vector>
-#include "ceres/linear_operator.h"
+#include "ceres/preconditioner.h"
namespace ceres {
namespace internal {
-class CompressedRowBlockStructure;
+class BlockSparseMatrixBase;
+struct CompressedRowBlockStructure;
class LinearOperator;
-class SparseMatrix;
-// A block Jacobi preconditioner. This is intended for use with conjugate
-// gradients, or other iterative symmetric solvers. To use the preconditioner,
-// create one by passing a BlockSparseMatrix as the linear operator "A" to the
-// constructor. This fixes the sparsity pattern to the pattern of the matrix
-// A^TA.
+// A block Jacobi preconditioner. This is intended for use with
+// conjugate gradients, or other iterative symmetric solvers. To use
+// the preconditioner, create one by passing a BlockSparseMatrix "A"
+// to the constructor. This fixes the sparsity pattern to the pattern
+// of the matrix A^TA.
//
// Before each use of the preconditioner in a solve with conjugate gradients,
// update the matrix by running Update(A, D). The values of the matrix A are
// inspected to construct the preconditioner. The vector D is applied as the
// D^TD diagonal term.
-class BlockJacobiPreconditioner : public LinearOperator {
+class BlockJacobiPreconditioner : public Preconditioner {
public:
// A must remain valid while the BlockJacobiPreconditioner is.
- BlockJacobiPreconditioner(const LinearOperator& A);
+ explicit BlockJacobiPreconditioner(const BlockSparseMatrixBase& A);
virtual ~BlockJacobiPreconditioner();
- // Update the preconditioner with the values found in A. The sparsity pattern
- // must match that of the A passed to the constructor. D is a vector that
- // must have the same number of rows as A, and is applied as a diagonal in
- // addition to the block diagonals of A.
- void Update(const LinearOperator& A, const double* D);
-
- // LinearOperator interface.
+ // Preconditioner interface
+ virtual bool Update(const BlockSparseMatrixBase& A, const double* D);
virtual void RightMultiply(const double* x, double* y) const;
virtual void LeftMultiply(const double* x, double* y) const;
virtual int num_rows() const { return num_rows_; }
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc
index 0f95e8932b8..aedfc745f22 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc
@@ -28,12 +28,12 @@
//
// Author: sameeragarwal@google.com (Sameer Agarwal)
-#include "glog/logging.h"
#include "ceres/block_random_access_dense_matrix.h"
#include <vector>
#include "ceres/internal/eigen.h"
#include "ceres/internal/scoped_ptr.h"
+#include "glog/logging.h"
namespace ceres {
namespace internal {
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc
index 9ed62ce948b..f789436364a 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc
@@ -28,7 +28,6 @@
//
// Author: sameeragarwal@google.com (Sameer Agarwal)
-#include "glog/logging.h"
#include "ceres/block_random_access_sparse_matrix.h"
#include <algorithm>
@@ -40,6 +39,7 @@
#include "ceres/mutex.h"
#include "ceres/triplet_sparse_matrix.h"
#include "ceres/types.h"
+#include "glog/logging.h"
namespace ceres {
namespace internal {
diff --git a/extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.h b/extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.h
index 2d1eb403995..5f8e4e3e5dd 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.h
@@ -43,16 +43,16 @@
#include <vector>
-#include <glog/logging.h>
#include "ceres/collections_port.h"
#include "ceres/graph.h"
-#include "ceres/map_util.h"
#include "ceres/internal/macros.h"
+#include "ceres/map_util.h"
+#include "glog/logging.h"
namespace ceres {
namespace internal {
-class CanonicalViewsClusteringOptions;
+struct CanonicalViewsClusteringOptions;
// Compute a partitioning of the vertices of the graph using the
// canonical views clustering algorithm.
diff --git a/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.cc
index ccc8026f9f7..e2e799fe607 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.cc
@@ -30,25 +30,28 @@
#include "ceres/cgnr_solver.h"
-#include "glog/logging.h"
-#include "ceres/linear_solver.h"
+#include "ceres/block_jacobi_preconditioner.h"
#include "ceres/cgnr_linear_operator.h"
#include "ceres/conjugate_gradients_solver.h"
-#include "ceres/block_jacobi_preconditioner.h"
+#include "ceres/linear_solver.h"
+#include "ceres/wall_time.h"
+#include "glog/logging.h"
namespace ceres {
namespace internal {
CgnrSolver::CgnrSolver(const LinearSolver::Options& options)
: options_(options),
- jacobi_preconditioner_(NULL) {
+ preconditioner_(NULL) {
}
-LinearSolver::Summary CgnrSolver::Solve(
- LinearOperator* A,
+LinearSolver::Summary CgnrSolver::SolveImpl(
+ BlockSparseMatrixBase* A,
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
double* x) {
+ EventLogger event_logger("CgnrSolver::Solve");
+
// Form z = Atb.
scoped_array<double> z(new double[A->num_cols()]);
std::fill(z.get(), z.get() + A->num_cols(), 0.0);
@@ -57,11 +60,11 @@ LinearSolver::Summary CgnrSolver::Solve(
// Precondition if necessary.
LinearSolver::PerSolveOptions cg_per_solve_options = per_solve_options;
if (options_.preconditioner_type == JACOBI) {
- if (jacobi_preconditioner_.get() == NULL) {
- jacobi_preconditioner_.reset(new BlockJacobiPreconditioner(*A));
+ if (preconditioner_.get() == NULL) {
+ preconditioner_.reset(new BlockJacobiPreconditioner(*A));
}
- jacobi_preconditioner_->Update(*A, per_solve_options.D);
- cg_per_solve_options.preconditioner = jacobi_preconditioner_.get();
+ preconditioner_->Update(*A, per_solve_options.D);
+ cg_per_solve_options.preconditioner = preconditioner_.get();
} else if (options_.preconditioner_type != IDENTITY) {
LOG(FATAL) << "CGNR only supports IDENTITY and JACOBI preconditioners.";
}
@@ -69,11 +72,14 @@ LinearSolver::Summary CgnrSolver::Solve(
// Solve (AtA + DtD)x = z (= Atb).
std::fill(x, x + A->num_cols(), 0.0);
CgnrLinearOperator lhs(*A, per_solve_options.D);
+ event_logger.AddEvent("Setup");
+
ConjugateGradientsSolver conjugate_gradient_solver(options_);
- return conjugate_gradient_solver.Solve(&lhs,
- z.get(),
- cg_per_solve_options,
- x);
+ LinearSolver::Summary summary =
+ conjugate_gradient_solver.Solve(&lhs, z.get(), cg_per_solve_options, x);
+ event_logger.AddEvent("Solve");
+
+ return summary;
}
} // namespace internal
diff --git a/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h b/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h
index 877b4c4ceea..d560a9de58d 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h
@@ -37,6 +37,8 @@
namespace ceres {
namespace internal {
+class Preconditioner;
+
class BlockJacobiPreconditioner;
// A conjugate gradients on the normal equations solver. This directly solves
@@ -46,17 +48,18 @@ class BlockJacobiPreconditioner;
//
// as required for solving for x in the least squares sense. Currently only
// block diagonal preconditioning is supported.
-class CgnrSolver : public LinearSolver {
+class CgnrSolver : public BlockSparseMatrixBaseSolver {
public:
explicit CgnrSolver(const LinearSolver::Options& options);
- virtual Summary Solve(LinearOperator* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x);
+ virtual Summary SolveImpl(
+ BlockSparseMatrixBase* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x);
private:
const LinearSolver::Options options_;
- scoped_ptr<BlockJacobiPreconditioner> jacobi_preconditioner_;
+ scoped_ptr<Preconditioner> preconditioner_;
CERES_DISALLOW_COPY_AND_ASSIGN(CgnrSolver);
};
diff --git a/extern/libmv/third_party/ceres/internal/ceres/collections_port.h b/extern/libmv/third_party/ceres/internal/ceres/collections_port.h
index c2fce9033cd..715c975e00e 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/collections_port.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/collections_port.h
@@ -37,7 +37,7 @@
# include <map>
# include <set>
#else
-# if defined(_MSC_VER) && _MSC_VER <= 1600
+# if defined(_MSC_VER)
# include <unordered_map>
# include <unordered_set>
# else
diff --git a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc b/extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc
index 912c4845441..bbadb772805 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc
@@ -135,7 +135,8 @@ SparseMatrix* CompressedRowJacobianWriter::CreateJacobian() const {
// Populate the row and column block vectors for use by block
// oriented ordering algorithms. This is useful when
// Solver::Options::use_block_amd = true.
- const vector<ParameterBlock*>& parameter_blocks = program_->parameter_blocks();
+ const vector<ParameterBlock*>& parameter_blocks =
+ program_->parameter_blocks();
vector<int>& col_blocks = *(jacobian->mutable_col_blocks());
col_blocks.resize(parameter_blocks.size());
for (int i = 0; i < parameter_blocks.size(); ++i) {
diff --git a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h
index 6a9d82842e5..c9c904bf63c 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h
@@ -32,17 +32,18 @@
#define CERES_INTERNAL_COMPRESSED_ROW_SPARSE_MATRIX_H_
#include <vector>
-#include <glog/logging.h>
-#include "ceres/sparse_matrix.h"
-#include "ceres/triplet_sparse_matrix.h"
+
#include "ceres/internal/eigen.h"
#include "ceres/internal/macros.h"
#include "ceres/internal/port.h"
+#include "ceres/sparse_matrix.h"
+#include "ceres/triplet_sparse_matrix.h"
#include "ceres/types.h"
+#include "glog/logging.h"
namespace ceres {
-class CRSMatrix;
+struct CRSMatrix;
namespace internal {
diff --git a/extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.cc b/extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.cc
new file mode 100644
index 00000000000..c4da987919a
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.cc
@@ -0,0 +1,236 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 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: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/coordinate_descent_minimizer.h"
+
+#ifdef CERES_USE_OPENMP
+#include <omp.h>
+#endif
+
+#include <iterator>
+#include <numeric>
+#include <vector>
+#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/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"
+
+namespace ceres {
+namespace internal {
+
+CoordinateDescentMinimizer::~CoordinateDescentMinimizer() {
+}
+
+bool CoordinateDescentMinimizer::Init(
+ const Program& program,
+ const ProblemImpl::ParameterMap& parameter_map,
+ const ParameterBlockOrdering& ordering,
+ string* error) {
+ parameter_blocks_.clear();
+ independent_set_offsets_.clear();
+ independent_set_offsets_.push_back(0);
+
+ // Serialize the OrderedGroups into a vector of parameter block
+ // offsets for parallel access.
+ map<ParameterBlock*, int> parameter_block_index;
+ 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) {
+ for (set<double*>::const_iterator ptr_it = it->second.begin();
+ ptr_it != it->second.end();
+ ++ptr_it) {
+ parameter_blocks_.push_back(parameter_map.find(*ptr_it)->second);
+ parameter_block_index[parameter_blocks_.back()] =
+ parameter_blocks_.size() - 1;
+ }
+ independent_set_offsets_.push_back(
+ independent_set_offsets_.back() + it->second.size());
+ }
+
+ // The ordering does not have to contain all parameter blocks, so
+ // assign zero offsets/empty independent sets to these parameter
+ // blocks.
+ const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
+ for (int i = 0; i < parameter_blocks.size(); ++i) {
+ if (!ordering.IsMember(parameter_blocks[i]->mutable_user_state())) {
+ parameter_blocks_.push_back(parameter_blocks[i]);
+ independent_set_offsets_.push_back(independent_set_offsets_.back());
+ }
+ }
+
+ // Compute the set of residual blocks that depend on each parameter
+ // block.
+ residual_blocks_.resize(parameter_block_index.size());
+ const vector<ResidualBlock*>& residual_blocks = program.residual_blocks();
+ for (int i = 0; i < residual_blocks.size(); ++i) {
+ ResidualBlock* residual_block = residual_blocks[i];
+ const int num_parameter_blocks = residual_block->NumParameterBlocks();
+ for (int j = 0; j < num_parameter_blocks; ++j) {
+ ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
+ const map<ParameterBlock*, int>::const_iterator it =
+ parameter_block_index.find(parameter_block);
+ if (it != parameter_block_index.end()) {
+ residual_blocks_[it->second].push_back(residual_block);
+ }
+ }
+ }
+
+ evaluator_options_.linear_solver_type = DENSE_QR;
+ evaluator_options_.num_eliminate_blocks = 0;
+ evaluator_options_.num_threads = 1;
+
+ return true;
+}
+
+void CoordinateDescentMinimizer::Minimize(
+ const Minimizer::Options& options,
+ double* parameters,
+ Solver::Summary* summary) {
+ // Set the state and mark all parameter blocks constant.
+ for (int i = 0; i < parameter_blocks_.size(); ++i) {
+ ParameterBlock* parameter_block = parameter_blocks_[i];
+ parameter_block->SetState(parameters + parameter_block->state_offset());
+ parameter_block->SetConstant();
+ }
+
+ scoped_array<LinearSolver*> linear_solvers(
+ new LinearSolver*[options.num_threads]);
+
+ LinearSolver::Options linear_solver_options;
+ linear_solver_options.type = DENSE_QR;
+
+ for (int i = 0; i < options.num_threads; ++i) {
+ linear_solvers[i] = LinearSolver::Create(linear_solver_options);
+ }
+
+ for (int i = 0; i < independent_set_offsets_.size() - 1; ++i) {
+ // No point paying the price for an OpemMP call if the set if of
+ // size zero.
+ if (independent_set_offsets_[i] == independent_set_offsets_[i + 1]) {
+ continue;
+ }
+
+ // The parameter blocks in each independent set can be optimized
+ // in parallel, since they do not co-occur in any residual block.
+#pragma omp parallel for num_threads(options.num_threads)
+ for (int j = independent_set_offsets_[i];
+ j < independent_set_offsets_[i + 1];
+ ++j) {
+#ifdef CERES_USE_OPENMP
+ int thread_id = omp_get_thread_num();
+#else
+ int thread_id = 0;
+#endif
+
+ ParameterBlock* parameter_block = parameter_blocks_[j];
+ const int old_index = parameter_block->index();
+ const int old_delta_offset = parameter_block->delta_offset();
+ parameter_block->SetVarying();
+ parameter_block->set_index(0);
+ parameter_block->set_delta_offset(0);
+
+ Program inner_program;
+ inner_program.mutable_parameter_blocks()->push_back(parameter_block);
+ *inner_program.mutable_residual_blocks() = residual_blocks_[j];
+
+ // TODO(sameeragarwal): Better error handling. Right now we
+ // assume that this is not going to lead to problems of any
+ // sort. Basically we should be checking for numerical failure
+ // of some sort.
+ //
+ // On the other hand, if the optimization is a failure, that in
+ // some ways is fine, since it won't change the parameters and
+ // we are fine.
+ Solver::Summary inner_summary;
+ Solve(&inner_program,
+ linear_solvers[thread_id],
+ parameters + parameter_block->state_offset(),
+ &inner_summary);
+
+ parameter_block->set_index(old_index);
+ parameter_block->set_delta_offset(old_delta_offset);
+ parameter_block->SetState(parameters + parameter_block->state_offset());
+ parameter_block->SetConstant();
+ }
+ }
+
+ for (int i = 0; i < parameter_blocks_.size(); ++i) {
+ parameter_blocks_[i]->SetVarying();
+ }
+
+ for (int i = 0; i < options.num_threads; ++i) {
+ delete linear_solvers[i];
+ }
+}
+
+// Solve the optimization problem for one parameter block.
+void CoordinateDescentMinimizer::Solve(Program* program,
+ LinearSolver* linear_solver,
+ double* parameter,
+ Solver::Summary* summary) {
+ *summary = Solver::Summary();
+ summary->initial_cost = 0.0;
+ summary->fixed_cost = 0.0;
+ 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());
+
+ TrustRegionStrategy::Options trs_options;
+ trs_options.linear_solver = linear_solver;
+
+ scoped_ptr<TrustRegionStrategy>trust_region_strategy(
+ 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();
+
+ TrustRegionMinimizer minimizer;
+ minimizer.Minimize(minimizer_options, parameter, summary);
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.h b/extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.h
new file mode 100644
index 00000000000..3dcf8faee59
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.h
@@ -0,0 +1,88 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 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: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_COORDINATE_DESCENT_MINIMIZER_H_
+#define CERES_INTERNAL_COORDINATE_DESCENT_MINIMIZER_H_
+
+#include <vector>
+
+#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 {
+
+// 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
+// ordering. The independent set structure allows for all parameter
+// blocks in the same independent set to be optimized in parallel, and
+// the order of the independent set determines the order in which the
+// parameter block groups are optimized.
+//
+// The minimizer assumes that none of the parameter blocks in the
+// program are constant.
+class CoordinateDescentMinimizer : public Minimizer {
+ public:
+ bool Init(const Program& program,
+ const ProblemImpl::ParameterMap& parameter_map,
+ const ParameterBlockOrdering& ordering,
+ string* error);
+
+ // Minimizer interface.
+ virtual ~CoordinateDescentMinimizer();
+ virtual void Minimize(const Minimizer::Options& options,
+ double* parameters,
+ Solver::Summary* summary);
+
+ private:
+ void Solve(Program* program,
+ LinearSolver* linear_solver,
+ double* parameters,
+ Solver::Summary* summary);
+
+ vector<ParameterBlock*> parameter_blocks_;
+ vector<vector<ResidualBlock*> > residual_blocks_;
+ // The optimization is performed in rounds. In each round all the
+ // parameter blocks that form one independent set are optimized in
+ // parallel. This array, marks the boundaries of the independent
+ // sets in parameter_blocks_.
+ vector<int> independent_set_offsets_;
+
+ Evaluator::Options evaluator_options_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_COORDINATE_DESCENT_MINIMIZER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/corrector.cc b/extern/libmv/third_party/ceres/internal/ceres/corrector.cc
index eff4dff8566..c3858abd2f4 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/corrector.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/corrector.cc
@@ -113,12 +113,19 @@ void Corrector::CorrectJacobian(int nrow, int ncol,
double* residuals, double* jacobian) {
DCHECK(residuals != NULL);
DCHECK(jacobian != NULL);
- ConstVectorRef r_ref(residuals, nrow);
- MatrixRef j_ref(jacobian, nrow, ncol);
- // Equation 11 in BANS.
- j_ref = sqrt_rho1_ * (j_ref - alpha_sq_norm_ *
- r_ref * (r_ref.transpose() * j_ref));
+ if (nrow == 1) {
+ // Specialization for the case where the residual is a scalar.
+ VectorRef j_ref(jacobian, ncol);
+ j_ref *= sqrt_rho1_ * (1.0 - alpha_sq_norm_ * pow(*residuals, 2));
+ } else {
+ ConstVectorRef r_ref(residuals, nrow);
+ MatrixRef j_ref(jacobian, nrow, ncol);
+
+ // Equation 11 in BANS.
+ j_ref = sqrt_rho1_ * (j_ref - alpha_sq_norm_ *
+ r_ref * (r_ref.transpose() * j_ref));
+ }
}
} // namespace internal
diff --git a/extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc b/extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc
index ca36ce07614..19fa17cc37d 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc
@@ -39,7 +39,7 @@
namespace ceres {
namespace internal {
-CXSparse::CXSparse() : scratch_size_(0), scratch_(NULL) {
+CXSparse::CXSparse() : scratch_(NULL), scratch_size_(0) {
}
CXSparse::~CXSparse() {
@@ -116,12 +116,12 @@ cs_di* CXSparse::CreateSparseMatrix(TripletSparseMatrix* tsm) {
return cs_compress(&tsm_wrapper);
}
-void CXSparse::Free(cs_di* factor) {
- cs_free(factor);
+void CXSparse::Free(cs_di* sparse_matrix) {
+ cs_di_spfree(sparse_matrix);
}
-void CXSparse::Free(cs_dis* factor) {
- cs_sfree(factor);
+void CXSparse::Free(cs_dis* symbolic_factorization) {
+ cs_di_sfree(symbolic_factorization);
}
} // namespace internal
diff --git a/extern/libmv/third_party/ceres/internal/ceres/cxsparse.h b/extern/libmv/third_party/ceres/internal/ceres/cxsparse.h
index d3b64fcd1a5..dd5eadc8da8 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/cxsparse.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/cxsparse.h
@@ -72,9 +72,8 @@ class CXSparse {
// The returned matrix should be deallocated with Free when not used anymore.
cs_dis* AnalyzeCholesky(cs_di* A);
- // Deallocates the memory of a matrix obtained from AnalyzeCholesky.
- void Free(cs_di* factor);
- void Free(cs_dis* factor);
+ void Free(cs_di* sparse_matrix);
+ void Free(cs_dis* symbolic_factorization);
private:
// Cached scratch space
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_jacobian_writer.h b/extern/libmv/third_party/ceres/internal/ceres/dense_jacobian_writer.h
index 1177b83a556..be743a8591c 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/dense_jacobian_writer.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/dense_jacobian_writer.h
@@ -62,7 +62,8 @@ class DenseJacobianWriter {
SparseMatrix* CreateJacobian() const {
return new DenseSparseMatrix(program_->NumResiduals(),
- program_->NumEffectiveParameters());
+ program_->NumEffectiveParameters(),
+ true);
}
void Write(int residual_id,
@@ -87,10 +88,10 @@ class DenseJacobianWriter {
continue;
}
- int parameter_block_size = parameter_block->LocalSize();
- MatrixRef parameter_jacobian(jacobians[j],
- num_residuals,
- parameter_block_size);
+ const int parameter_block_size = parameter_block->LocalSize();
+ ConstMatrixRef parameter_jacobian(jacobians[j],
+ num_residuals,
+ parameter_block_size);
dense_jacobian->mutable_matrix().block(
residual_offset,
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc
index f6bb99abf63..a340e1664f0 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc
@@ -34,10 +34,11 @@
#include "Eigen/Dense"
#include "ceres/dense_sparse_matrix.h"
-#include "ceres/linear_solver.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/scoped_ptr.h"
+#include "ceres/linear_solver.h"
#include "ceres/types.h"
+#include "ceres/wall_time.h"
namespace ceres {
namespace internal {
@@ -51,6 +52,8 @@ LinearSolver::Summary DenseNormalCholeskySolver::SolveImpl(
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
double* x) {
+ EventLogger event_logger("DenseNormalCholeskySolver::Solve");
+
const int num_rows = A->num_rows();
const int num_cols = A->num_cols();
@@ -58,6 +61,7 @@ LinearSolver::Summary DenseNormalCholeskySolver::SolveImpl(
Matrix lhs(num_cols, num_cols);
lhs.setZero();
+ event_logger.AddEvent("Setup");
// lhs += A'A
//
// Using rankUpdate instead of GEMM, exposes the fact that its the
@@ -73,12 +77,13 @@ LinearSolver::Summary DenseNormalCholeskySolver::SolveImpl(
lhs += D.array().square().matrix().asDiagonal();
}
- VectorRef(x, num_cols) =
- lhs.selfadjointView<Eigen::Upper>().ldlt().solve(rhs);
-
LinearSolver::Summary summary;
summary.num_iterations = 1;
summary.termination_type = TOLERANCE;
+ VectorRef(x, num_cols) =
+ lhs.selfadjointView<Eigen::Upper>().ldlt().solve(rhs);
+ event_logger.AddEvent("Solve");
+
return summary;
}
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.cc
index 2b329ee0e9c..1fb9709b42a 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.cc
@@ -34,10 +34,11 @@
#include "Eigen/Dense"
#include "ceres/dense_sparse_matrix.h"
-#include "ceres/linear_solver.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/scoped_ptr.h"
+#include "ceres/linear_solver.h"
#include "ceres/types.h"
+#include "ceres/wall_time.h"
namespace ceres {
namespace internal {
@@ -50,10 +51,10 @@ LinearSolver::Summary DenseQRSolver::SolveImpl(
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
double* x) {
+ EventLogger event_logger("DenseQRSolver::Solve");
+
const int num_rows = A->num_rows();
const int num_cols = A->num_cols();
- VLOG(2) << "DenseQRSolver: "
- << num_rows << " x " << num_cols << " system.";
if (per_solve_options.D != NULL) {
// Temporarily append a diagonal block to the A matrix, but undo
@@ -62,18 +63,18 @@ LinearSolver::Summary DenseQRSolver::SolveImpl(
}
// rhs = [b;0] to account for the additional rows in the lhs.
- Vector rhs(num_rows + ((per_solve_options.D != NULL) ? num_cols : 0));
- rhs.setZero();
- rhs.head(num_rows) = ConstVectorRef(b, num_rows);
+ const int augmented_num_rows =
+ num_rows + ((per_solve_options.D != NULL) ? num_cols : 0);
+ if (rhs_.rows() != augmented_num_rows) {
+ rhs_.resize(augmented_num_rows);
+ rhs_.setZero();
+ }
+ rhs_.head(num_rows) = ConstVectorRef(b, num_rows);
+ event_logger.AddEvent("Setup");
// Solve the system.
- VectorRef(x, num_cols) = A->matrix().colPivHouseholderQr().solve(rhs);
-
- VLOG(3) << "A:\n" << A->matrix();
- VLOG(3) << "x:\n" << VectorRef(x, num_cols);
- VLOG(3) << "b:\n" << rhs;
- VLOG(3) << "error: " << (A->matrix() * VectorRef(x, num_cols) - rhs).norm();
-
+ VectorRef(x, num_cols) = A->matrix().colPivHouseholderQr().solve(rhs_);
+ event_logger.AddEvent("Solve");
if (per_solve_options.D != NULL) {
// Undo the modifications to the matrix A.
@@ -86,6 +87,8 @@ LinearSolver::Summary DenseQRSolver::SolveImpl(
LinearSolver::Summary summary;
summary.num_iterations = 1;
summary.termination_type = TOLERANCE;
+
+ event_logger.AddEvent("TearDown");
return summary;
}
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.h b/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.h
index dd683a8c4ea..f78fa72c5f3 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.h
@@ -33,6 +33,7 @@
#define CERES_INTERNAL_DENSE_QR_SOLVER_H_
#include "ceres/linear_solver.h"
+#include "ceres/internal/eigen.h"
#include "ceres/internal/macros.h"
namespace ceres {
@@ -90,6 +91,7 @@ class DenseQRSolver: public DenseSparseMatrixSolver {
double* x);
const LinearSolver::Options options_;
+ Vector rhs_;
CERES_DISALLOW_COPY_AND_ASSIGN(DenseQRSolver);
};
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.cc
index 86730cc101b..978ac6abe15 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.cc
@@ -47,6 +47,20 @@ DenseSparseMatrix::DenseSparseMatrix(int num_rows, int num_cols)
m_.setZero();
}
+DenseSparseMatrix::DenseSparseMatrix(int num_rows,
+ int num_cols,
+ bool reserve_diagonal)
+ : has_diagonal_appended_(false),
+ has_diagonal_reserved_(reserve_diagonal) {
+ // Allocate enough space for the diagonal.
+ if (reserve_diagonal) {
+ m_.resize(num_rows + num_cols, num_cols);
+ } else {
+ m_.resize(num_rows, num_cols);
+ }
+ m_.setZero();
+}
+
DenseSparseMatrix::DenseSparseMatrix(const TripletSparseMatrix& m)
: m_(Eigen::MatrixXd::Zero(m.num_rows(), m.num_cols())),
has_diagonal_appended_(false),
@@ -105,7 +119,7 @@ void DenseSparseMatrix::ScaleColumns(const double* scale) {
}
void DenseSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const {
- *dense_matrix = m_;
+ *dense_matrix = m_.block(0, 0, num_rows(), num_cols());
}
#ifndef CERES_NO_PROTOCOL_BUFFERS
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.h
index e7ad14d0ee6..1e4d499b631 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.h
@@ -57,6 +57,7 @@ class DenseSparseMatrix : public SparseMatrix {
#endif
DenseSparseMatrix(int num_rows, int num_cols);
+ DenseSparseMatrix(int num_rows, int num_cols, bool reserve_diagonal);
virtual ~DenseSparseMatrix() {}
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc b/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc
index 668fa54b8b8..a330ad2c7a2 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc
@@ -35,7 +35,7 @@
#include "ceres/array_utils.h"
#include "ceres/internal/eigen.h"
#include "ceres/linear_solver.h"
-#include "ceres/polynomial_solver.h"
+#include "ceres/polynomial.h"
#include "ceres/sparse_matrix.h"
#include "ceres/trust_region_strategy.h"
#include "ceres/types.h"
@@ -87,7 +87,7 @@ TrustRegionStrategy::Summary DoglegStrategy::ComputeStep(
// Gauss-Newton and gradient vectors are always available, only a
// new interpolant need to be computed. For the subspace case,
// the subspace and the two-dimensional model are also still valid.
- switch(dogleg_type_) {
+ switch (dogleg_type_) {
case TRADITIONAL_DOGLEG:
ComputeTraditionalDoglegStep(step);
break;
@@ -135,7 +135,7 @@ TrustRegionStrategy::Summary DoglegStrategy::ComputeStep(
summary.termination_type = linear_solver_summary.termination_type;
if (linear_solver_summary.termination_type != FAILURE) {
- switch(dogleg_type_) {
+ switch (dogleg_type_) {
// Interpolate the Cauchy point and the Gauss-Newton step.
case TRADITIONAL_DOGLEG:
ComputeTraditionalDoglegStep(step);
@@ -415,15 +415,15 @@ Vector DoglegStrategy::MakePolynomialForBoundaryConstrainedProblem() const {
const double trB = subspace_B_.trace();
const double r2 = radius_ * radius_;
Matrix2d B_adj;
- B_adj << subspace_B_(1,1) , -subspace_B_(0,1),
- -subspace_B_(1,0) , subspace_B_(0,0);
+ B_adj << subspace_B_(1, 1) , -subspace_B_(0, 1),
+ -subspace_B_(1, 0) , subspace_B_(0, 0);
Vector polynomial(5);
polynomial(0) = r2;
polynomial(1) = 2.0 * r2 * trB;
- polynomial(2) = r2 * ( trB * trB + 2.0 * detB ) - subspace_g_.squaredNorm();
- polynomial(3) = -2.0 * ( subspace_g_.transpose() * B_adj * subspace_g_
- - r2 * detB * trB );
+ polynomial(2) = r2 * (trB * trB + 2.0 * detB) - subspace_g_.squaredNorm();
+ polynomial(3) = -2.0 * (subspace_g_.transpose() * B_adj * subspace_g_
+ - r2 * detB * trB);
polynomial(4) = r2 * detB * detB - (B_adj * subspace_g_).squaredNorm();
return polynomial;
@@ -598,7 +598,7 @@ void DoglegStrategy::StepAccepted(double step_quality) {
// Reduce the regularization multiplier, in the hope that whatever
// was causing the rank deficiency has gone away and we can return
// to doing a pure Gauss-Newton solve.
- mu_ = max(min_mu_, 2.0 * mu_ / mu_increase_factor_ );
+ mu_ = max(min_mu_, 2.0 * mu_ / mu_increase_factor_);
reuse_ = false;
}
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h b/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h
index bff1689aa4a..7131467d6ce 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h
@@ -53,8 +53,8 @@ namespace internal {
// This finds the exact optimum over the two-dimensional subspace
// spanned by the two Dogleg vectors.
class DoglegStrategy : public TrustRegionStrategy {
-public:
- DoglegStrategy(const TrustRegionStrategy::Options& options);
+ public:
+ explicit DoglegStrategy(const TrustRegionStrategy::Options& options);
virtual ~DoglegStrategy() {}
// TrustRegionStrategy interface
diff --git a/extern/libmv/third_party/ceres/internal/ceres/evaluator.h b/extern/libmv/third_party/ceres/internal/ceres/evaluator.h
index 6aa30d7b739..14a88188145 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/evaluator.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/evaluator.h
@@ -32,14 +32,17 @@
#ifndef CERES_INTERNAL_EVALUATOR_H_
#define CERES_INTERNAL_EVALUATOR_H_
+#include <map>
#include <string>
#include <vector>
+
+#include "ceres/execution_summary.h"
#include "ceres/internal/port.h"
#include "ceres/types.h"
namespace ceres {
-class CRSMatrix;
+struct CRSMatrix;
namespace internal {
@@ -152,6 +155,18 @@ class Evaluator {
// The number of residuals in the optimization problem.
virtual int NumResiduals() const = 0;
+
+ // The following two methods return copies instead of references so
+ // that the base class implementation does not have to worry about
+ // life time issues. Further, these calls are not expected to be
+ // frequent or performance sensitive.
+ virtual map<string, int> CallStatistics() const {
+ return map<string, int>();
+ }
+
+ virtual map<string, double> TimeStatistics() const {
+ return map<string, double>();
+ }
};
} // namespace internal
diff --git a/extern/libmv/third_party/ceres/internal/ceres/execution_summary.h b/extern/libmv/third_party/ceres/internal/ceres/execution_summary.h
new file mode 100644
index 00000000000..29bdc69ecd7
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/execution_summary.h
@@ -0,0 +1,90 @@
+// 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_EXECUTION_SUMMARY_H_
+#define CERES_INTERNAL_EXECUTION_SUMMARY_H_
+
+#include <map>
+#include <string>
+
+#include "ceres/internal/port.h"
+#include "ceres/wall_time.h"
+#include "ceres/mutex.h"
+
+namespace ceres {
+namespace internal {
+
+// Struct used by various objects to report statistics and other
+// information about their execution. e.g., ExecutionSummary::times
+// can be used for reporting times associated with various activities.
+class ExecutionSummary {
+ public:
+ void IncrementTimeBy(const string& name, const double value) {
+ CeresMutexLock l(&times_mutex_);
+ times_[name] += value;
+ }
+
+ void IncrementCall(const string& name) {
+ CeresMutexLock l(&calls_mutex_);
+ calls_[name] += 1;
+ }
+
+ const map<string, double>& times() const { return times_; }
+ const map<string, int>& calls() const { return calls_; }
+
+ private:
+ Mutex times_mutex_;
+ map<string, double> times_;
+
+ Mutex calls_mutex_;
+ map<string, int> calls_;
+};
+
+class ScopedExecutionTimer {
+ public:
+ ScopedExecutionTimer(const string& name, ExecutionSummary* summary)
+ : start_time_(WallTimeInSeconds()),
+ name_(name),
+ summary_(summary) {}
+
+ ~ScopedExecutionTimer() {
+ summary_->IncrementTimeBy(name_, WallTimeInSeconds() - start_time_);
+ }
+
+ private:
+ const double start_time_;
+ const string name_;
+ ExecutionSummary* summary_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_EXECUTION_SUMMARY_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/file.cc b/extern/libmv/third_party/ceres/internal/ceres/file.cc
index 6fe7557246d..5226c85e6ee 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/file.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/file.cc
@@ -30,8 +30,9 @@
//
// Really simple file IO.
+#include "ceres/file.h"
+
#include <cstdio>
-#include "file.h"
#include "glog/logging.h"
namespace ceres {
diff --git a/extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc b/extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc
index 7fb3ed7b3a8..3edf95da6e0 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc
@@ -154,8 +154,8 @@ class GradientCheckingCostFunction : public CostFunction {
"Jacobian for " "block %d: (%ld by %ld)) "
"==========\n",
k,
- term_jacobians[k].rows(),
- term_jacobians[k].cols());
+ static_cast<long>(term_jacobians[k].rows()),
+ static_cast<long>(term_jacobians[k].cols()));
// The funny spacing creates appropriately aligned column headers.
m += " block row col user dx/dy num diff dx/dy "
"abs error relative error parameter residual\n";
diff --git a/extern/libmv/third_party/ceres/internal/ceres/graph.h b/extern/libmv/third_party/ceres/internal/ceres/graph.h
index 2c0f6d28e54..5f92d4d4df2 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/graph.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/graph.h
@@ -32,12 +32,13 @@
#define CERES_INTERNAL_GRAPH_H_
#include <limits>
-#include <glog/logging.h>
+#include <utility>
#include "ceres/integral_types.h"
#include "ceres/map_util.h"
#include "ceres/collections_port.h"
#include "ceres/internal/macros.h"
#include "ceres/types.h"
+#include "glog/logging.h"
namespace ceres {
namespace internal {
@@ -65,6 +66,28 @@ class Graph {
AddVertex(vertex, 1.0);
}
+ bool RemoveVertex(const Vertex& vertex) {
+ if (vertices_.find(vertex) == vertices_.end()) {
+ return false;
+ }
+
+ vertices_.erase(vertex);
+ vertex_weights_.erase(vertex);
+ const HashSet<Vertex>& sinks = edges_[vertex];
+ for (typename HashSet<Vertex>::const_iterator it = sinks.begin();
+ it != sinks.end(); ++it) {
+ if (vertex < *it) {
+ edge_weights_.erase(make_pair(vertex, *it));
+ } else {
+ edge_weights_.erase(make_pair(*it, vertex));
+ }
+ edges_[*it].erase(vertex);
+ }
+
+ edges_.erase(vertex);
+ return true;
+ }
+
// Add a weighted 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.
diff --git a/extern/libmv/third_party/ceres/internal/ceres/graph_algorithms.h b/extern/libmv/third_party/ceres/internal/ceres/graph_algorithms.h
index 3b42d936336..2e6eec0e6d8 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/graph_algorithms.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/graph_algorithms.h
@@ -33,10 +33,12 @@
#ifndef CERES_INTERNAL_GRAPH_ALGORITHMS_H_
#define CERES_INTERNAL_GRAPH_ALGORITHMS_H_
+#include <algorithm>
#include <vector>
-#include <glog/logging.h>
+#include <utility>
#include "ceres/collections_port.h"
#include "ceres/graph.h"
+#include "glog/logging.h"
namespace ceres {
namespace internal {
diff --git a/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc
index 679c41f2431..cf5562ac771 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc
@@ -33,6 +33,7 @@
#include <algorithm>
#include <cstring>
#include <vector>
+
#include "Eigen/Dense"
#include "ceres/block_sparse_matrix.h"
#include "ceres/block_structure.h"
@@ -41,9 +42,12 @@
#include "ceres/internal/eigen.h"
#include "ceres/internal/scoped_ptr.h"
#include "ceres/linear_solver.h"
+#include "ceres/preconditioner.h"
+#include "ceres/schur_jacobi_preconditioner.h"
#include "ceres/triplet_sparse_matrix.h"
#include "ceres/types.h"
#include "ceres/visibility_based_preconditioner.h"
+#include "ceres/wall_time.h"
#include "glog/logging.h"
namespace ceres {
@@ -62,12 +66,14 @@ LinearSolver::Summary IterativeSchurComplementSolver::SolveImpl(
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
double* x) {
+ EventLogger event_logger("IterativeSchurComplementSolver::Solve");
+
CHECK_NOTNULL(A->block_structure());
// Initialize a ImplicitSchurComplement object.
if (schur_complement_ == NULL) {
schur_complement_.reset(
- new ImplicitSchurComplement(options_.num_eliminate_blocks,
+ new ImplicitSchurComplement(options_.elimination_groups[0],
options_.preconditioner_type == JACOBI));
}
schur_complement_->Init(*A, per_solve_options.D, b);
@@ -89,44 +95,58 @@ LinearSolver::Summary IterativeSchurComplementSolver::SolveImpl(
cg_per_solve_options.r_tolerance = per_solve_options.r_tolerance;
cg_per_solve_options.q_tolerance = per_solve_options.q_tolerance;
- bool is_preconditioner_good = false;
+ Preconditioner::Options preconditioner_options;
+ preconditioner_options.type = options_.preconditioner_type;
+ preconditioner_options.sparse_linear_algebra_library =
+ options_.sparse_linear_algebra_library;
+ preconditioner_options.use_block_amd = options_.use_block_amd;
+ preconditioner_options.num_threads = options_.num_threads;
+ preconditioner_options.row_block_size = options_.row_block_size;
+ preconditioner_options.e_block_size = options_.e_block_size;
+ preconditioner_options.f_block_size = options_.f_block_size;
+ preconditioner_options.elimination_groups = options_.elimination_groups;
+
switch (options_.preconditioner_type) {
case IDENTITY:
- is_preconditioner_good = true;
break;
case JACOBI:
- // We need to strip the constness of the block_diagonal_FtF_inverse
- // matrix here because the only other way to initialize the struct
- // cg_solve_options would be to add a constructor to it. We know
- // that the only method ever called on the preconditioner is the
- // RightMultiply which is a const method so we don't need to worry
- // about the object getting modified.
- cg_per_solve_options.preconditioner =
- const_cast<BlockSparseMatrix*>(
- schur_complement_->block_diagonal_FtF_inverse());
- is_preconditioner_good = true;
+ preconditioner_.reset(
+ new SparseMatrixPreconditionerWrapper(
+ schur_complement_->block_diagonal_FtF_inverse()));
break;
case SCHUR_JACOBI:
+ if (preconditioner_.get() == NULL) {
+ preconditioner_.reset(
+ new SchurJacobiPreconditioner(
+ *A->block_structure(), preconditioner_options));
+ }
+ break;
case CLUSTER_JACOBI:
case CLUSTER_TRIDIAGONAL:
- if (visibility_based_preconditioner_.get() == NULL) {
- visibility_based_preconditioner_.reset(
- new VisibilityBasedPreconditioner(*A->block_structure(), options_));
+ if (preconditioner_.get() == NULL) {
+ preconditioner_.reset(
+ new VisibilityBasedPreconditioner(
+ *A->block_structure(), preconditioner_options));
}
- is_preconditioner_good =
- visibility_based_preconditioner_->Update(*A, per_solve_options.D);
- cg_per_solve_options.preconditioner =
- visibility_based_preconditioner_.get();
break;
default:
LOG(FATAL) << "Unknown Preconditioner Type";
}
+ bool preconditioner_update_was_successful = true;
+ if (preconditioner_.get() != NULL) {
+ preconditioner_update_was_successful =
+ preconditioner_->Update(*A, per_solve_options.D);
+ cg_per_solve_options.preconditioner = preconditioner_.get();
+ }
+
+ event_logger.AddEvent("Setup");
+
LinearSolver::Summary cg_summary;
cg_summary.num_iterations = 0;
cg_summary.termination_type = FAILURE;
- if (is_preconditioner_good) {
+ if (preconditioner_update_was_successful) {
cg_summary = cg_solver.Solve(schur_complement_.get(),
schur_complement_->rhs().data(),
cg_per_solve_options,
@@ -138,6 +158,8 @@ LinearSolver::Summary IterativeSchurComplementSolver::SolveImpl(
}
VLOG(2) << "CG Iterations : " << cg_summary.num_iterations;
+
+ event_logger.AddEvent("Solve");
return cg_summary;
}
diff --git a/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.h b/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.h
index cfeb65e1eec..f8abe04c142 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.h
@@ -39,13 +39,12 @@
namespace ceres {
namespace internal {
-class BlockSparseMatrix;
class BlockSparseMatrixBase;
class ImplicitSchurComplement;
-class VisibilityBasedPreconditioner;
+class Preconditioner;
// This class implements an iterative solver for the linear least
-// squares problems that have a bi-partitte sparsity structure common
+// squares problems that have a bi-partite sparsity structure common
// to Structure from Motion problems.
//
// The algorithm used by this solver was developed in a series of
@@ -70,9 +69,7 @@ class VisibilityBasedPreconditioner;
// "Iterative Methods for Sparse Linear Systems".
class IterativeSchurComplementSolver : public BlockSparseMatrixBaseSolver {
public:
- explicit IterativeSchurComplementSolver(
- const LinearSolver::Options& options);
-
+ explicit IterativeSchurComplementSolver(const LinearSolver::Options& options);
virtual ~IterativeSchurComplementSolver();
private:
@@ -84,8 +81,9 @@ class IterativeSchurComplementSolver : public BlockSparseMatrixBaseSolver {
LinearSolver::Options options_;
scoped_ptr<internal::ImplicitSchurComplement> schur_complement_;
- scoped_ptr<VisibilityBasedPreconditioner> visibility_based_preconditioner_;
+ scoped_ptr<Preconditioner> preconditioner_;
Vector reduced_linear_system_solution_;
+ CERES_DISALLOW_COPY_AND_ASSIGN(IterativeSchurComplementSolver);
};
} // namespace internal
diff --git a/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h b/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h
index 90c21789797..344e3285422 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h
@@ -43,8 +43,9 @@ namespace internal {
//
// http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/3215/pdf/imm3215.pdf
class LevenbergMarquardtStrategy : public TrustRegionStrategy {
-public:
- LevenbergMarquardtStrategy(const TrustRegionStrategy::Options& options);
+ public:
+ explicit LevenbergMarquardtStrategy(
+ const TrustRegionStrategy::Options& options);
virtual ~LevenbergMarquardtStrategy();
// TrustRegionStrategy interface
diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search.cc b/extern/libmv/third_party/ceres/internal/ceres/line_search.cc
new file mode 100644
index 00000000000..e7508caec56
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/line_search.cc
@@ -0,0 +1,211 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 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: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/line_search.h"
+
+#include <glog/logging.h>
+#include "ceres/fpclassify.h"
+#include "ceres/evaluator.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/polynomial.h"
+
+
+namespace ceres {
+namespace internal {
+namespace {
+
+FunctionSample ValueSample(const double x, const double value) {
+ FunctionSample sample;
+ sample.x = x;
+ sample.value = value;
+ sample.value_is_valid = true;
+ return sample;
+};
+
+FunctionSample ValueAndGradientSample(const double x,
+ const double value,
+ const double gradient) {
+ FunctionSample sample;
+ sample.x = x;
+ sample.value = value;
+ sample.gradient = gradient;
+ sample.value_is_valid = true;
+ sample.gradient_is_valid = true;
+ return sample;
+};
+
+} // namespace
+
+LineSearchFunction::LineSearchFunction(Evaluator* evaluator)
+ : evaluator_(evaluator),
+ position_(evaluator->NumParameters()),
+ direction_(evaluator->NumEffectiveParameters()),
+ evaluation_point_(evaluator->NumParameters()),
+ scaled_direction_(evaluator->NumEffectiveParameters()),
+ gradient_(evaluator->NumEffectiveParameters()) {
+}
+
+void LineSearchFunction::Init(const Vector& position,
+ const Vector& direction) {
+ position_ = position;
+ direction_ = direction;
+}
+
+bool LineSearchFunction::Evaluate(const double x, double* f, double* g) {
+ scaled_direction_ = x * direction_;
+ if (!evaluator_->Plus(position_.data(),
+ scaled_direction_.data(),
+ evaluation_point_.data())) {
+ return false;
+ }
+
+ if (g == NULL) {
+ return (evaluator_->Evaluate(evaluation_point_.data(),
+ f, NULL, NULL, NULL) &&
+ IsFinite(*f));
+ }
+
+ if (!evaluator_->Evaluate(evaluation_point_.data(),
+ f,
+ NULL,
+ gradient_.data(), NULL)) {
+ return false;
+ }
+
+ *g = direction_.dot(gradient_);
+ return IsFinite(*f) && IsFinite(*g);
+}
+
+void ArmijoLineSearch::Search(const LineSearch::Options& options,
+ const double initial_step_size,
+ const double initial_cost,
+ const double initial_gradient,
+ Summary* summary) {
+ *CHECK_NOTNULL(summary) = LineSearch::Summary();
+ Function* function = options.function;
+
+ double previous_step_size = 0.0;
+ double previous_cost = 0.0;
+ double previous_gradient = 0.0;
+ bool previous_step_size_is_valid = false;
+
+ double step_size = initial_step_size;
+ double cost = 0.0;
+ double gradient = 0.0;
+ bool step_size_is_valid = false;
+
+ ++summary->num_evaluations;
+ step_size_is_valid =
+ function->Evaluate(step_size,
+ &cost,
+ options.interpolation_degree < 2 ? NULL : &gradient);
+ while (!step_size_is_valid || cost > (initial_cost
+ + options.sufficient_decrease
+ * initial_gradient
+ * step_size)) {
+ // If step_size_is_valid is not true we treat it as if the cost at
+ // that point is not large enough to satisfy the sufficient
+ // decrease condition.
+
+ const double current_step_size = step_size;
+ // Backtracking search. Each iteration of this loop finds a new point
+
+ if ((options.interpolation_degree == 0) || !step_size_is_valid) {
+ // Backtrack by halving the step_size;
+ step_size *= 0.5;
+ } else {
+ // Backtrack by interpolating the function and gradient values
+ // and minimizing the corresponding polynomial.
+
+ vector<FunctionSample> samples;
+ samples.push_back(ValueAndGradientSample(0.0,
+ initial_cost,
+ initial_gradient));
+
+ if (options.interpolation_degree == 1) {
+ // Two point interpolation using function values and the
+ // initial gradient.
+ samples.push_back(ValueSample(step_size, cost));
+
+ if (options.use_higher_degree_interpolation_when_possible &&
+ summary->num_evaluations > 1 &&
+ previous_step_size_is_valid) {
+ // Three point interpolation, using function values and the
+ // initial gradient.
+ samples.push_back(ValueSample(previous_step_size, previous_cost));
+ }
+ } else {
+ // Two point interpolation using the function values and the gradients.
+ samples.push_back(ValueAndGradientSample(step_size,
+ cost,
+ gradient));
+
+ if (options.use_higher_degree_interpolation_when_possible &&
+ summary->num_evaluations > 1 &&
+ previous_step_size_is_valid) {
+ // Three point interpolation using the function values and
+ // the gradients.
+ samples.push_back(ValueAndGradientSample(previous_step_size,
+ previous_cost,
+ previous_gradient));
+ }
+ }
+
+ double min_value;
+ MinimizeInterpolatingPolynomial(samples, 0.0, current_step_size,
+ &step_size, &min_value);
+ step_size =
+ min(max(step_size,
+ options.min_relative_step_size_change * current_step_size),
+ options.max_relative_step_size_change * current_step_size);
+ }
+
+ previous_step_size = current_step_size;
+ previous_cost = cost;
+ previous_gradient = gradient;
+
+ if (fabs(initial_gradient) * step_size < options.step_size_threshold) {
+ LOG(WARNING) << "Line search failed: step_size too small: " << step_size;
+ return;
+ }
+
+ ++summary->num_evaluations;
+ step_size_is_valid =
+ function->Evaluate(step_size,
+ &cost,
+ options.interpolation_degree < 2 ? NULL : &gradient);
+ }
+
+ summary->optimal_step_size = step_size;
+ summary->success = true;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search.h b/extern/libmv/third_party/ceres/internal/ceres/line_search.h
new file mode 100644
index 00000000000..fccf63b598a
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/line_search.h
@@ -0,0 +1,212 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 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: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Interface for and implementation of various Line search algorithms.
+
+#ifndef CERES_INTERNAL_LINE_SEARCH_H_
+#define CERES_INTERNAL_LINE_SEARCH_H_
+
+#include <glog/logging.h>
+#include <vector>
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/port.h"
+
+namespace ceres {
+namespace internal {
+
+class Evaluator;
+
+// Line search is another name for a one dimensional optimization
+// algorithm. The name "line search" comes from the fact one
+// dimensional optimization problems that arise as subproblems of
+// general multidimensional optimization problems.
+//
+// While finding the exact minimum of a one dimensionl function is
+// hard, instances of LineSearch find a point that satisfies a
+// sufficient decrease condition. Depending on the particular
+// condition used, we get a variety of different line search
+// algorithms, e.g., Armijo, Wolfe etc.
+class LineSearch {
+ public:
+ class Function;
+
+ struct Options {
+ Options()
+ : interpolation_degree(1),
+ use_higher_degree_interpolation_when_possible(false),
+ sufficient_decrease(1e-4),
+ min_relative_step_size_change(1e-3),
+ max_relative_step_size_change(0.6),
+ step_size_threshold(1e-9),
+ function(NULL) {}
+
+ // TODO(sameeragarwal): Replace this with enums which are common
+ // across various line searches.
+ //
+ // Degree of the polynomial used to approximate the objective
+ // function. Valid values are {0, 1, 2}.
+ //
+ // For Armijo line search
+ //
+ // 0: Bisection based backtracking search.
+ // 1: Quadratic interpolation.
+ // 2: Cubic interpolation.
+ int interpolation_degree;
+
+ // Usually its possible to increase the degree of the
+ // interpolation polynomial by storing and using an extra point.
+ bool use_higher_degree_interpolation_when_possible;
+
+ // Armijo 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 sufficient_decrease;
+
+ // In each iteration of the Armijo line search,
+ //
+ // new_step_size >= min_relative_step_size_change * step_size
+ double min_relative_step_size_change;
+
+ // In each iteration of the Armijo line search,
+ //
+ // new_step_size <= max_relative_step_size_change * step_size
+ double max_relative_step_size_change;
+
+ // If during the line search, the step_size falls below this
+ // value, it is truncated to zero.
+ double step_size_threshold;
+
+ // The one dimensional function that the line search algorithm
+ // minimizes.
+ Function* function;
+ };
+
+ // An object used by the line search to access the function values
+ // and gradient of the one dimensional function being optimized.
+ //
+ // In practice, this object will provide access to the objective
+ // function value and the directional derivative of the underlying
+ // optimization problem along a specific search direction.
+ //
+ // See LineSearchFunction for an example implementation.
+ class Function {
+ public:
+ virtual ~Function() {}
+ // Evaluate the line search objective
+ //
+ // f(x) = p(position + x * direction)
+ //
+ // Where, p is the objective function of the general optimization
+ // problem.
+ //
+ // g is the gradient f'(x) at x.
+ //
+ // f must not be null. The gradient is computed only if g is not null.
+ virtual bool Evaluate(double x, double* f, double* g) = 0;
+ };
+
+ // Result of the line search.
+ struct Summary {
+ Summary()
+ : success(false),
+ optimal_step_size(0.0),
+ num_evaluations(0) {}
+
+ bool success;
+ double optimal_step_size;
+ int num_evaluations;
+ };
+
+ virtual ~LineSearch() {}
+
+ // Perform the line search.
+ //
+ // initial_step_size must be a positive number.
+ //
+ // initial_cost and initial_gradient are the values and gradient of
+ // the function at zero.
+ // summary must not be null and will contain the result of the line
+ // search.
+ //
+ // Summary::success is true if a non-zero step size is found.
+ virtual void Search(const LineSearch::Options& options,
+ double initial_step_size,
+ double initial_cost,
+ double initial_gradient,
+ Summary* summary) = 0;
+};
+
+class LineSearchFunction : public LineSearch::Function {
+ public:
+ explicit LineSearchFunction(Evaluator* evaluator);
+ virtual ~LineSearchFunction() {}
+ void Init(const Vector& position, const Vector& direction);
+ virtual bool Evaluate(const double x, double* f, double* g);
+
+ private:
+ Evaluator* evaluator_;
+ Vector position_;
+ Vector direction_;
+
+ // evaluation_point = Evaluator::Plus(position_, x * direction_);
+ Vector evaluation_point_;
+
+ // scaled_direction = x * direction_;
+ Vector scaled_direction_;
+ Vector gradient_;
+};
+
+// Backtracking and interpolation based Armijo line search. This
+// implementation is based on the Armijo line search that ships in the
+// minFunc package by Mark Schmidt.
+//
+// For more details: http://www.di.ens.fr/~mschmidt/Software/minFunc.html
+class ArmijoLineSearch : public LineSearch {
+ public:
+ virtual ~ArmijoLineSearch() {}
+ virtual void Search(const LineSearch::Options& options,
+ double initial_step_size,
+ double initial_cost,
+ double initial_gradient,
+ Summary* summary);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_LINE_SEARCH_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search_direction.cc b/extern/libmv/third_party/ceres/internal/ceres/line_search_direction.cc
new file mode 100644
index 00000000000..2f27a78301a
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/line_search_direction.cc
@@ -0,0 +1,145 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 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: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/line_search_direction.h"
+#include "ceres/line_search_minimizer.h"
+#include "ceres/low_rank_inverse_hessian.h"
+#include "ceres/internal/eigen.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+class SteepestDescent : public LineSearchDirection {
+ public:
+ virtual ~SteepestDescent() {}
+ bool NextDirection(const LineSearchMinimizer::State& previous,
+ const LineSearchMinimizer::State& current,
+ Vector* search_direction) {
+ *search_direction = -current.gradient;
+ return true;
+ }
+};
+
+class NonlinearConjugateGradient : public LineSearchDirection {
+ public:
+ NonlinearConjugateGradient(const NonlinearConjugateGradientType type,
+ const double function_tolerance)
+ : type_(type),
+ function_tolerance_(function_tolerance) {
+ }
+
+ bool NextDirection(const LineSearchMinimizer::State& previous,
+ const LineSearchMinimizer::State& current,
+ Vector* search_direction) {
+ double beta = 0.0;
+ Vector gradient_change;
+ switch (type_) {
+ case FLETCHER_REEVES:
+ beta = current.gradient_squared_norm / previous.gradient_squared_norm;
+ break;
+ case POLAK_RIBIRERE:
+ gradient_change = current.gradient - previous.gradient;
+ beta = (current.gradient.dot(gradient_change) /
+ previous.gradient_squared_norm);
+ break;
+ case HESTENES_STIEFEL:
+ gradient_change = current.gradient - previous.gradient;
+ beta = (current.gradient.dot(gradient_change) /
+ previous.search_direction.dot(gradient_change));
+ break;
+ default:
+ LOG(FATAL) << "Unknown nonlinear conjugate gradient type: " << type_;
+ }
+
+ *search_direction = -current.gradient + beta * previous.search_direction;
+ const double directional_derivative =
+ current. gradient.dot(*search_direction);
+ if (directional_derivative > -function_tolerance_) {
+ LOG(WARNING) << "Restarting non-linear conjugate gradients: "
+ << directional_derivative;
+ *search_direction = -current.gradient;
+ };
+
+ return true;
+ }
+
+ private:
+ const NonlinearConjugateGradientType type_;
+ const double function_tolerance_;
+};
+
+class LBFGS : public LineSearchDirection {
+ public:
+ LBFGS(const int num_parameters, const int max_lbfgs_rank)
+ : low_rank_inverse_hessian_(num_parameters, max_lbfgs_rank) {}
+
+ virtual ~LBFGS() {}
+
+ bool NextDirection(const LineSearchMinimizer::State& previous,
+ const LineSearchMinimizer::State& current,
+ Vector* search_direction) {
+ low_rank_inverse_hessian_.Update(
+ previous.search_direction * previous.step_size,
+ current.gradient - previous.gradient);
+ search_direction->setZero();
+ low_rank_inverse_hessian_.RightMultiply(current.gradient.data(),
+ search_direction->data());
+ *search_direction *= -1.0;
+ return true;
+ }
+
+ private:
+ LowRankInverseHessian low_rank_inverse_hessian_;
+};
+
+LineSearchDirection*
+LineSearchDirection::Create(const LineSearchDirection::Options& options) {
+ if (options.type == STEEPEST_DESCENT) {
+ return new SteepestDescent;
+ }
+
+ if (options.type == NONLINEAR_CONJUGATE_GRADIENT) {
+ return new NonlinearConjugateGradient(
+ options.nonlinear_conjugate_gradient_type,
+ options.function_tolerance);
+ }
+
+ if (options.type == ceres::LBFGS) {
+ return new ceres::internal::LBFGS(options.num_parameters,
+ options.max_lbfgs_rank);
+ }
+
+ LOG(ERROR) << "Unknown line search direction type: " << options.type;
+ return NULL;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.h b/extern/libmv/third_party/ceres/internal/ceres/line_search_direction.h
index 1cf07ddb549..71063ab8414 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/line_search_direction.h
@@ -26,40 +26,45 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
-// Author: moll.markus@arcor.de (Markus Moll)
+// Author: sameeragarwal@google.com (Sameer Agarwal)
-#ifndef CERES_INTERNAL_POLYNOMIAL_SOLVER_H_
-#define CERES_INTERNAL_POLYNOMIAL_SOLVER_H_
+#ifndef CERES_INTERNAL_LINE_SEARCH_DIRECTION_H_
+#define CERES_INTERNAL_LINE_SEARCH_DIRECTION_H_
#include "ceres/internal/eigen.h"
+#include "ceres/line_search_minimizer.h"
+#include "ceres/types.h"
namespace ceres {
namespace internal {
-// Use the companion matrix eigenvalues to determine the roots of the polynomial
-//
-// sum_{i=0}^N polynomial(i) x^{N-i}.
-//
-// This function returns true on success, false otherwise.
-// Failure indicates that the polynomial is invalid (of size 0) or
-// that the eigenvalues of the companion matrix could not be computed.
-// On failure, a more detailed message will be written to LOG(ERROR).
-// If real is not NULL, the real parts of the roots will be returned in it.
-// Likewise, if imaginary is not NULL, imaginary parts will be returned in it.
-bool FindPolynomialRoots(const Vector& polynomial,
- Vector* real,
- Vector* imaginary);
+class LineSearchDirection {
+ public:
+ struct Options {
+ Options()
+ : num_parameters(0),
+ type(LBFGS),
+ nonlinear_conjugate_gradient_type(FLETCHER_REEVES),
+ function_tolerance(1e-12),
+ max_lbfgs_rank(20) {
+ }
+
+ int num_parameters;
+ LineSearchDirectionType type;
+ NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
+ double function_tolerance;
+ int max_lbfgs_rank;
+ };
+
+ static LineSearchDirection* Create(const Options& options);
-// Evaluate the polynomial at x using the Horner scheme.
-inline double EvaluatePolynomial(const Vector& polynomial, double x) {
- double v = 0.0;
- for (int i = 0; i < polynomial.size(); ++i) {
- v = v * x + polynomial(i);
- }
- return v;
-}
+ virtual ~LineSearchDirection() {}
+ virtual bool NextDirection(const LineSearchMinimizer::State& previous,
+ const LineSearchMinimizer::State& current,
+ Vector* search_direction) = 0;
+};
} // namespace internal
} // namespace ceres
-#endif // CERES_INTERNAL_POLYNOMIAL_SOLVER_H_
+#endif // CERES_INTERNAL_LINE_SEARCH_DIRECTION_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.cc b/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.cc
new file mode 100644
index 00000000000..ca7d639c5ef
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.cc
@@ -0,0 +1,283 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 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: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Generic loop for line search based optimization algorithms.
+//
+// This is primarily inpsired by the minFunc packaged written by Mark
+// Schmidt.
+//
+// http://www.di.ens.fr/~mschmidt/Software/minFunc.html
+//
+// For details on the theory and implementation see "Numerical
+// Optimization" by Nocedal & Wright.
+
+#include "ceres/line_search_minimizer.h"
+
+#include <algorithm>
+#include <cstdlib>
+#include <cmath>
+#include <string>
+#include <vector>
+
+#include "Eigen/Dense"
+#include "ceres/array_utils.h"
+#include "ceres/evaluator.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/line_search.h"
+#include "ceres/line_search_direction.h"
+#include "ceres/stringprintf.h"
+#include "ceres/types.h"
+#include "ceres/wall_time.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+namespace {
+// Small constant for various floating point issues.
+// TODO(sameeragarwal): Change to a better name if this has only one
+// use.
+const double kEpsilon = 1e-12;
+
+bool Evaluate(Evaluator* evaluator,
+ const Vector& x,
+ LineSearchMinimizer::State* state) {
+ const bool status = evaluator->Evaluate(x.data(),
+ &(state->cost),
+ NULL,
+ state->gradient.data(),
+ NULL);
+ if (status) {
+ state->gradient_squared_norm = state->gradient.squaredNorm();
+ state->gradient_max_norm = state->gradient.lpNorm<Eigen::Infinity>();
+ }
+
+ return status;
+}
+
+} // namespace
+
+void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
+ double* parameters,
+ Solver::Summary* summary) {
+ double start_time = WallTimeInSeconds();
+ double iteration_start_time = start_time;
+
+ Evaluator* evaluator = CHECK_NOTNULL(options.evaluator);
+ const int num_parameters = evaluator->NumParameters();
+ const int num_effective_parameters = evaluator->NumEffectiveParameters();
+
+ summary->termination_type = NO_CONVERGENCE;
+ summary->num_successful_steps = 0;
+ summary->num_unsuccessful_steps = 0;
+
+ VectorRef x(parameters, num_parameters);
+
+ State current_state(num_parameters, num_effective_parameters);
+ State previous_state(num_parameters, num_effective_parameters);
+
+ Vector delta(num_effective_parameters);
+ Vector x_plus_delta(num_parameters);
+
+ IterationSummary iteration_summary;
+ iteration_summary.iteration = 0;
+ iteration_summary.step_is_valid = false;
+ iteration_summary.step_is_successful = false;
+ iteration_summary.cost_change = 0.0;
+ iteration_summary.gradient_max_norm = 0.0;
+ iteration_summary.step_norm = 0.0;
+ iteration_summary.linear_solver_iterations = 0;
+ iteration_summary.step_solver_time_in_seconds = 0;
+
+ // Do initial cost and Jacobian evaluation.
+ if (!Evaluate(evaluator, x, &current_state)) {
+ LOG(WARNING) << "Terminating: Cost and gradient evaluation failed.";
+ summary->termination_type = NUMERICAL_FAILURE;
+ return;
+ }
+
+ summary->initial_cost = current_state.cost + summary->fixed_cost;
+ iteration_summary.cost = current_state.cost + summary->fixed_cost;
+
+ iteration_summary.gradient_max_norm = current_state.gradient_max_norm;
+
+ // The initial gradient max_norm is bounded from below so that we do
+ // not divide by zero.
+ const double initial_gradient_max_norm =
+ max(iteration_summary.gradient_max_norm, kEpsilon);
+ const double absolute_gradient_tolerance =
+ options.gradient_tolerance * initial_gradient_max_norm;
+
+ if (iteration_summary.gradient_max_norm <= absolute_gradient_tolerance) {
+ summary->termination_type = GRADIENT_TOLERANCE;
+ VLOG(1) << "Terminating: Gradient tolerance reached."
+ << "Relative gradient max norm: "
+ << iteration_summary.gradient_max_norm / initial_gradient_max_norm
+ << " <= " << options.gradient_tolerance;
+ return;
+ }
+
+ iteration_summary.iteration_time_in_seconds =
+ WallTimeInSeconds() - iteration_start_time;
+ iteration_summary.cumulative_time_in_seconds =
+ WallTimeInSeconds() - start_time
+ + summary->preprocessor_time_in_seconds;
+ summary->iterations.push_back(iteration_summary);
+
+ LineSearchDirection::Options line_search_direction_options;
+ line_search_direction_options.num_parameters = num_effective_parameters;
+ line_search_direction_options.type = options.line_search_direction_type;
+ line_search_direction_options.nonlinear_conjugate_gradient_type =
+ options.nonlinear_conjugate_gradient_type;
+ line_search_direction_options.max_lbfgs_rank = options.max_lbfgs_rank;
+ scoped_ptr<LineSearchDirection> line_search_direction(
+ LineSearchDirection::Create(line_search_direction_options));
+
+ LineSearchFunction line_search_function(evaluator);
+ LineSearch::Options line_search_options;
+ line_search_options.function = &line_search_function;
+
+ // TODO(sameeragarwal): Make this parameterizable over different
+ // line searches.
+ ArmijoLineSearch line_search;
+ LineSearch::Summary line_search_summary;
+
+ while (true) {
+ if (!RunCallbacks(options.callbacks, iteration_summary, summary)) {
+ return;
+ }
+
+ iteration_start_time = WallTimeInSeconds();
+ if (iteration_summary.iteration >= options.max_num_iterations) {
+ summary->termination_type = NO_CONVERGENCE;
+ VLOG(1) << "Terminating: Maximum number of iterations reached.";
+ break;
+ }
+
+ const double total_solver_time = iteration_start_time - start_time +
+ summary->preprocessor_time_in_seconds;
+ if (total_solver_time >= options.max_solver_time_in_seconds) {
+ summary->termination_type = NO_CONVERGENCE;
+ VLOG(1) << "Terminating: Maximum solver time reached.";
+ break;
+ }
+
+ iteration_summary = IterationSummary();
+ iteration_summary.iteration = summary->iterations.back().iteration + 1;
+
+ bool line_search_status = true;
+ if (iteration_summary.iteration == 1) {
+ current_state.search_direction = -current_state.gradient;
+ } else {
+ line_search_status = line_search_direction->NextDirection(
+ previous_state,
+ current_state,
+ &current_state.search_direction);
+ }
+
+ if (!line_search_status) {
+ LOG(WARNING) << "Line search direction computation failed. "
+ "Resorting to steepest descent.";
+ current_state.search_direction = -current_state.gradient;
+ }
+
+ line_search_function.Init(x, current_state.search_direction);
+ current_state.directional_derivative =
+ current_state.gradient.dot(current_state.search_direction);
+
+ // TODO(sameeragarwal): Refactor this into its own object and add
+ // explanations for the various choices.
+ const double initial_step_size = (iteration_summary.iteration == 1)
+ ? min(1.0, 1.0 / current_state.gradient_max_norm)
+ : min(1.0, 2.0 * (current_state.cost - previous_state.cost) /
+ current_state.directional_derivative);
+
+ line_search.Search(line_search_options,
+ initial_step_size,
+ current_state.cost,
+ current_state.directional_derivative,
+ &line_search_summary);
+
+ current_state.step_size = line_search_summary.optimal_step_size;
+ delta = current_state.step_size * current_state.search_direction;
+
+ previous_state = current_state;
+
+ // TODO(sameeragarwal): Collect stats.
+ if (!evaluator->Plus(x.data(), delta.data(), x_plus_delta.data()) ||
+ !Evaluate(evaluator, x_plus_delta, &current_state)) {
+ LOG(WARNING) << "Evaluation failed.";
+ } else {
+ x = x_plus_delta;
+ }
+
+ iteration_summary.gradient_max_norm = current_state.gradient_max_norm;
+ if (iteration_summary.gradient_max_norm <= absolute_gradient_tolerance) {
+ summary->termination_type = GRADIENT_TOLERANCE;
+ VLOG(1) << "Terminating: Gradient tolerance reached."
+ << "Relative gradient max norm: "
+ << iteration_summary.gradient_max_norm / initial_gradient_max_norm
+ << " <= " << options.gradient_tolerance;
+ break;
+ }
+
+ iteration_summary.cost_change = previous_state.cost - current_state.cost;
+ const double absolute_function_tolerance =
+ options.function_tolerance * previous_state.cost;
+ if (fabs(iteration_summary.cost_change) < absolute_function_tolerance) {
+ VLOG(1) << "Terminating. Function tolerance reached. "
+ << "|cost_change|/cost: "
+ << fabs(iteration_summary.cost_change) / previous_state.cost
+ << " <= " << options.function_tolerance;
+ summary->termination_type = FUNCTION_TOLERANCE;
+ return;
+ }
+
+ iteration_summary.cost = current_state.cost + summary->fixed_cost;
+ iteration_summary.step_norm = delta.norm();
+ iteration_summary.step_is_valid = true;
+ iteration_summary.step_is_successful = true;
+ iteration_summary.step_norm = delta.norm();
+ iteration_summary.step_size = current_state.step_size;
+ iteration_summary.line_search_function_evaluations =
+ line_search_summary.num_evaluations;
+ iteration_summary.iteration_time_in_seconds =
+ WallTimeInSeconds() - iteration_start_time;
+ iteration_summary.cumulative_time_in_seconds =
+ WallTimeInSeconds() - start_time
+ + summary->preprocessor_time_in_seconds;
+
+ summary->iterations.push_back(iteration_summary);
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.h b/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.h
new file mode 100644
index 00000000000..f82f13984a8
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.h
@@ -0,0 +1,77 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 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: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_LINE_SEARCH_MINIMIZER_H_
+#define CERES_INTERNAL_LINE_SEARCH_MINIMIZER_H_
+
+#include "ceres/minimizer.h"
+#include "ceres/solver.h"
+#include "ceres/types.h"
+#include "ceres/internal/eigen.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+// Generic line search minimization algorithm.
+//
+// For example usage, see SolverImpl::Minimize.
+class LineSearchMinimizer : public Minimizer {
+ public:
+ struct State {
+ State(int num_parameters,
+ int num_effective_parameters)
+ : cost(0.0),
+ gradient(num_effective_parameters),
+ gradient_squared_norm(0.0),
+ search_direction(num_effective_parameters),
+ directional_derivative(0.0),
+ step_size(0.0) {
+ }
+
+ double cost;
+ Vector gradient;
+ double gradient_squared_norm;
+ double gradient_max_norm;
+ Vector search_direction;
+ double directional_derivative;
+ double step_size;
+ };
+
+ ~LineSearchMinimizer() {}
+ virtual void Minimize(const Minimizer::Options& options,
+ double* parameters,
+ Solver::Summary* summary);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_LINE_SEARCH_MINIMIZER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.cc b/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.cc
index a91e254a663..6c886a1be38 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.cc
@@ -573,13 +573,14 @@ LinearLeastSquaresProblem* LinearLeastSquaresProblem3() {
return problem;
}
-static bool DumpLinearLeastSquaresProblemToConsole(const string& directory,
- int iteration,
- const SparseMatrix* A,
- const double* D,
- const double* b,
- const double* x,
- int num_eliminate_blocks) {
+namespace {
+bool DumpLinearLeastSquaresProblemToConsole(const string& directory,
+ int iteration,
+ const SparseMatrix* A,
+ const double* D,
+ const double* b,
+ const double* x,
+ int num_eliminate_blocks) {
CHECK_NOTNULL(A);
Matrix AA;
A->ToDenseMatrix(&AA);
@@ -601,13 +602,13 @@ static bool DumpLinearLeastSquaresProblemToConsole(const string& directory,
};
#ifndef CERES_NO_PROTOCOL_BUFFERS
-static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
- int iteration,
- const SparseMatrix* A,
- const double* D,
- const double* b,
- const double* x,
- int num_eliminate_blocks) {
+bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
+ int iteration,
+ const SparseMatrix* A,
+ const double* D,
+ const double* b,
+ const double* x,
+ int num_eliminate_blocks) {
CHECK_NOTNULL(A);
LinearLeastSquaresProblemProto lsqp;
A->ToProto(lsqp.mutable_a());
@@ -641,13 +642,13 @@ static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& director
return true;
}
#else
-static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
- int iteration,
- const SparseMatrix* A,
- const double* D,
- const double* b,
- const double* x,
- int num_eliminate_blocks) {
+bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
+ int iteration,
+ const SparseMatrix* A,
+ const double* D,
+ const double* b,
+ const double* x,
+ int num_eliminate_blocks) {
LOG(ERROR) << "Dumping least squares problems is only "
<< "supported when Ceres is compiled with "
<< "protocol buffer support.";
@@ -655,9 +656,9 @@ static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& director
}
#endif
-static void WriteArrayToFileOrDie(const string& filename,
- const double* x,
- const int size) {
+void WriteArrayToFileOrDie(const string& filename,
+ const double* x,
+ const int size) {
CHECK_NOTNULL(x);
VLOG(2) << "Writing array to: " << filename;
FILE* fptr = fopen(filename.c_str(), "w");
@@ -668,13 +669,13 @@ static void WriteArrayToFileOrDie(const string& filename,
fclose(fptr);
}
-static bool DumpLinearLeastSquaresProblemToTextFile(const string& directory,
- int iteration,
- const SparseMatrix* A,
- const double* D,
- const double* b,
- const double* x,
- int num_eliminate_blocks) {
+bool DumpLinearLeastSquaresProblemToTextFile(const string& directory,
+ int iteration,
+ const SparseMatrix* A,
+ const double* D,
+ const double* b,
+ const double* x,
+ int num_eliminate_blocks) {
CHECK_NOTNULL(A);
string format_string = JoinPath(directory,
"lm_iteration_%03d");
@@ -732,9 +733,10 @@ static bool DumpLinearLeastSquaresProblemToTextFile(const string& directory,
WriteStringToFileOrDie(matlab_script, matlab_filename);
return true;
}
+} // namespace
bool DumpLinearLeastSquaresProblem(const string& directory,
- int iteration,
+ int iteration,
DumpFormatType dump_format_type,
const SparseMatrix* A,
const double* D,
@@ -742,18 +744,18 @@ bool DumpLinearLeastSquaresProblem(const string& directory,
const double* x,
int num_eliminate_blocks) {
switch (dump_format_type) {
- case (CONSOLE):
+ case CONSOLE:
return DumpLinearLeastSquaresProblemToConsole(directory,
iteration,
A, D, b, x,
num_eliminate_blocks);
- case (PROTOBUF):
+ case PROTOBUF:
return DumpLinearLeastSquaresProblemToProtocolBuffer(
directory,
iteration,
A, D, b, x,
num_eliminate_blocks);
- case (TEXTFILE):
+ case TEXTFILE:
return DumpLinearLeastSquaresProblemToTextFile(directory,
iteration,
A, D, b, x,
diff --git a/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.h b/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.h
index 553cc0d3db3..c76ae91c7d8 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.h
@@ -74,7 +74,7 @@ LinearLeastSquaresProblem* LinearLeastSquaresProblem3();
// Write the linear least squares problem to disk. The exact format
// depends on dump_format_type.
bool DumpLinearLeastSquaresProblem(const string& directory,
- int iteration,
+ int iteration,
DumpFormatType dump_format_type,
const SparseMatrix* A,
const double* D,
diff --git a/extern/libmv/third_party/ceres/internal/ceres/linear_solver.h b/extern/libmv/third_party/ceres/internal/ceres/linear_solver.h
index 31f88740b9f..a98051468e7 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/linear_solver.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/linear_solver.h
@@ -35,14 +35,16 @@
#define CERES_INTERNAL_LINEAR_SOLVER_H_
#include <cstddef>
-
-#include <glog/logging.h>
+#include <map>
+#include <vector>
#include "ceres/block_sparse_matrix.h"
#include "ceres/casts.h"
#include "ceres/compressed_row_sparse_matrix.h"
#include "ceres/dense_sparse_matrix.h"
+#include "ceres/execution_summary.h"
#include "ceres/triplet_sparse_matrix.h"
#include "ceres/types.h"
+#include "glog/logging.h"
namespace ceres {
namespace internal {
@@ -76,7 +78,6 @@ class LinearSolver {
min_num_iterations(1),
max_num_iterations(1),
num_threads(1),
- num_eliminate_blocks(0),
residual_reset_period(10),
row_block_size(Dynamic),
e_block_size(Dynamic),
@@ -100,15 +101,23 @@ class LinearSolver {
// If possible, how many threads can the solver use.
int num_threads;
- // Eliminate 0 to num_eliminate_blocks - 1 from the Normal
- // equations to form a schur complement. Only used by the Schur
- // complement based solver. The most common use for this parameter
- // is in the case of structure from motion problems where we have
- // camera blocks and point blocks. Then setting the
- // num_eliminate_blocks to the number of points allows the solver
- // to use the Schur complement trick. For more details see the
- // description of this parameter in solver.h.
- int num_eliminate_blocks;
+ // Hints about the order in which the parameter blocks should be
+ // eliminated by the linear solver.
+ //
+ // For example if elimination_groups is a vector of size k, then
+ // the linear solver is informed that it should eliminate the
+ // parameter blocks 0 - elimination_groups[0] - 1 first, and then
+ // elimination_groups[0] - elimination_groups[1] and so on. Within
+ // each elimination group, the linear solver is free to choose how
+ // the parameter blocks are ordered. Different linear solvers have
+ // differing requirements on elimination_groups.
+ //
+ // The most common use is for Schur type solvers, where there
+ // should be at least two elimination groups and the first
+ // elimination group must form an independent set in the normal
+ // equations. The first elimination group corresponds to the
+ // num_eliminate_blocks in the Schur type solvers.
+ vector<int> elimination_groups;
// Iterative solvers, e.g. Preconditioned Conjugate Gradients
// maintain a cheap estimate of the residual which may become
@@ -247,6 +256,18 @@ class LinearSolver {
const PerSolveOptions& per_solve_options,
double* x) = 0;
+ // The following two methods return copies instead of references so
+ // that the base class implementation does not have to worry about
+ // life time issues. Further, these calls are not expected to be
+ // frequent or performance sensitive.
+ virtual map<string, int> CallStatistics() const {
+ return map<string, int>();
+ }
+
+ virtual map<string, double> TimeStatistics() const {
+ return map<string, double>();
+ }
+
// Factory
static LinearSolver* Create(const Options& options);
};
@@ -267,18 +288,29 @@ class TypedLinearSolver : public LinearSolver {
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
double* x) {
+ ScopedExecutionTimer total_time("LinearSolver::Solve", &execution_summary_);
CHECK_NOTNULL(A);
CHECK_NOTNULL(b);
CHECK_NOTNULL(x);
return SolveImpl(down_cast<MatrixType*>(A), b, per_solve_options, x);
}
+ virtual map<string, int> CallStatistics() const {
+ return execution_summary_.calls();
+ }
+
+ virtual map<string, double> TimeStatistics() const {
+ return execution_summary_.times();
+ }
+
private:
virtual LinearSolver::Summary SolveImpl(
MatrixType* A,
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
double* x) = 0;
+
+ ExecutionSummary execution_summary_;
};
// Linear solvers that depend on acccess to the low level structure of
diff --git a/extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.cc b/extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.cc
new file mode 100644
index 00000000000..3fe113f1afb
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.cc
@@ -0,0 +1,109 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 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: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/internal/eigen.h"
+#include "ceres/low_rank_inverse_hessian.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+LowRankInverseHessian::LowRankInverseHessian(int num_parameters,
+ int max_num_corrections)
+ : num_parameters_(num_parameters),
+ max_num_corrections_(max_num_corrections),
+ num_corrections_(0),
+ diagonal_(1.0),
+ delta_x_history_(num_parameters, max_num_corrections),
+ delta_gradient_history_(num_parameters, max_num_corrections),
+ delta_x_dot_delta_gradient_(max_num_corrections) {
+}
+
+bool LowRankInverseHessian::Update(const Vector& delta_x,
+ const Vector& delta_gradient) {
+ const double delta_x_dot_delta_gradient = delta_x.dot(delta_gradient);
+ if (delta_x_dot_delta_gradient <= 1e-10) {
+ VLOG(2) << "Skipping LBFGS Update. " << delta_x_dot_delta_gradient;
+ return false;
+ }
+
+ if (num_corrections_ == max_num_corrections_) {
+ // TODO(sameeragarwal): This can be done more efficiently using
+ // a circular buffer/indexing scheme, but for simplicity we will
+ // do the expensive copy for now.
+ delta_x_history_.block(0, 0, num_parameters_, max_num_corrections_ - 2) =
+ delta_x_history_
+ .block(0, 1, num_parameters_, max_num_corrections_ - 1);
+
+ delta_gradient_history_
+ .block(0, 0, num_parameters_, max_num_corrections_ - 2) =
+ delta_gradient_history_
+ .block(0, 1, num_parameters_, max_num_corrections_ - 1);
+
+ delta_x_dot_delta_gradient_.head(num_corrections_ - 2) =
+ delta_x_dot_delta_gradient_.tail(num_corrections_ - 1);
+ } else {
+ ++num_corrections_;
+ }
+
+ delta_x_history_.col(num_corrections_ - 1) = delta_x;
+ delta_gradient_history_.col(num_corrections_ - 1) = delta_gradient;
+ delta_x_dot_delta_gradient_(num_corrections_ - 1) =
+ delta_x_dot_delta_gradient;
+ diagonal_ = delta_x_dot_delta_gradient / delta_gradient.squaredNorm();
+ return true;
+}
+
+void LowRankInverseHessian::RightMultiply(const double* x_ptr,
+ double* y_ptr) const {
+ ConstVectorRef gradient(x_ptr, num_parameters_);
+ VectorRef search_direction(y_ptr, num_parameters_);
+
+ search_direction = gradient;
+
+ Vector alpha(num_corrections_);
+
+ for (int i = num_corrections_ - 1; i >= 0; --i) {
+ alpha(i) = delta_x_history_.col(i).dot(search_direction) /
+ delta_x_dot_delta_gradient_(i);
+ search_direction -= alpha(i) * delta_gradient_history_.col(i);
+ }
+
+ search_direction *= diagonal_;
+
+ for (int i = 0; i < num_corrections_; ++i) {
+ const double beta = delta_gradient_history_.col(i).dot(search_direction) /
+ delta_x_dot_delta_gradient_(i);
+ search_direction += delta_x_history_.col(i) * (alpha(i) - beta);
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.h b/extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.h
new file mode 100644
index 00000000000..6f3fc0c9d00
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.h
@@ -0,0 +1,99 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 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: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Limited memory positive definite approximation to the inverse
+// Hessian, using the LBFGS algorithm
+
+#ifndef CERES_INTERNAL_LOW_RANK_INVERSE_HESSIAN_H_
+#define CERES_INTERNAL_LOW_RANK_INVERSE_HESSIAN_H_
+
+#include "ceres/internal/eigen.h"
+#include "ceres/linear_operator.h"
+
+namespace ceres {
+namespace internal {
+
+// LowRankInverseHessian is a positive definite approximation to the
+// Hessian using the limited memory variant of the
+// Broyden-Fletcher-Goldfarb-Shanno (BFGS)secant formula for
+// approximating the Hessian.
+//
+// Other update rules like the Davidon-Fletcher-Powell (DFP) are
+// possible, but the BFGS rule is considered the best performing one.
+//
+// The limited memory variant was developed by Nocedal and further
+// enhanced with scaling rule by Byrd, Nocedal and Schanbel.
+//
+// Nocedal, J. (1980). "Updating Quasi-Newton Matrices with Limited
+// Storage". Mathematics of Computation 35 (151): 773–782.
+//
+// Byrd, R. H.; Nocedal, J.; Schnabel, R. B. (1994).
+// "Representations of Quasi-Newton Matrices and their use in
+// Limited Memory Methods". Mathematical Programming 63 (4):
+class LowRankInverseHessian : public LinearOperator {
+ public:
+ // num_parameters is the row/column size of the Hessian.
+ // max_num_corrections is the rank of the Hessian approximation.
+ // The approximation uses:
+ // 2 * max_num_corrections * num_parameters + max_num_corrections
+ // doubles.
+ LowRankInverseHessian(int num_parameters, int max_num_corrections);
+ virtual ~LowRankInverseHessian() {}
+
+ // Update the low rank approximation. delta_x is the change in the
+ // domain of Hessian, and delta_gradient is the change in the
+ // gradient. The update copies the delta_x and delta_gradient
+ // vectors, and gets rid of the oldest delta_x and delta_gradient
+ // vectors if the number of corrections is already equal to
+ // max_num_corrections.
+ bool Update(const Vector& delta_x, const Vector& delta_gradient);
+
+ // LinearOperator interface
+ virtual void RightMultiply(const double* x, double* y) const;
+ virtual void LeftMultiply(const double* x, double* y) const {
+ RightMultiply(x, y);
+ }
+ virtual int num_rows() const { return num_parameters_; }
+ virtual int num_cols() const { return num_parameters_; }
+
+ private:
+ const int num_parameters_;
+ const int max_num_corrections_;
+ int num_corrections_;
+ double diagonal_;
+ Matrix delta_x_history_;
+ Matrix delta_gradient_history_;
+ Vector delta_x_dot_delta_gradient_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_LOW_RANK_INVERSE_HESSIAN_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/map_util.h b/extern/libmv/third_party/ceres/internal/ceres/map_util.h
index ddf1252f674..929c6b36982 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/map_util.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/map_util.h
@@ -35,6 +35,7 @@
#include <utility>
#include "ceres/internal/port.h"
+#include "glog/logging.h"
namespace ceres {
diff --git a/extern/libmv/third_party/ceres/internal/ceres/minimizer.cc b/extern/libmv/third_party/ceres/internal/ceres/minimizer.cc
new file mode 100644
index 00000000000..2e2c15ac612
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/minimizer.cc
@@ -0,0 +1,67 @@
+// 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: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/minimizer.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+Minimizer::~Minimizer() {}
+
+bool Minimizer::RunCallbacks(const vector<IterationCallback*> callbacks,
+ const IterationSummary& iteration_summary,
+ Solver::Summary* summary) {
+ CallbackReturnType status = SOLVER_CONTINUE;
+ int i = 0;
+ while (status == SOLVER_CONTINUE && i < callbacks.size()) {
+ status = (*callbacks[i])(iteration_summary);
+ ++i;
+ }
+ switch (status) {
+ case SOLVER_CONTINUE:
+ return true;
+ case SOLVER_TERMINATE_SUCCESSFULLY:
+ summary->termination_type = USER_SUCCESS;
+ VLOG(1) << "Terminating: User callback returned USER_SUCCESS.";
+ return false;
+ case SOLVER_ABORT:
+ summary->termination_type = USER_ABORT;
+ VLOG(1) << "Terminating: User callback returned USER_ABORT.";
+ return false;
+ default:
+ LOG(FATAL) << "Unknown type of user callback status";
+ }
+ return false;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/minimizer.h b/extern/libmv/third_party/ceres/internal/ceres/minimizer.h
index cfc98a3ebd0..708974d63c2 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/minimizer.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/minimizer.h
@@ -32,8 +32,9 @@
#define CERES_INTERNAL_MINIMIZER_H_
#include <vector>
-#include "ceres/solver.h"
+#include "ceres/internal/port.h"
#include "ceres/iteration_callback.h"
+#include "ceres/solver.h"
namespace ceres {
namespace internal {
@@ -59,6 +60,7 @@ class Minimizer {
}
void Init(const Solver::Options& options) {
+ num_threads = options.num_threads;
max_num_iterations = options.max_num_iterations;
max_solver_time_in_seconds = options.max_solver_time_in_seconds;
max_step_solver_retries = 5;
@@ -74,18 +76,24 @@ class Minimizer {
lsqp_dump_directory = options.lsqp_dump_directory;
lsqp_iterations_to_dump = options.lsqp_iterations_to_dump;
lsqp_dump_format_type = options.lsqp_dump_format_type;
- num_eliminate_blocks = options.num_eliminate_blocks;
max_num_consecutive_invalid_steps =
options.max_num_consecutive_invalid_steps;
min_trust_region_radius = options.min_trust_region_radius;
+ line_search_direction_type = options.line_search_direction_type;
+ line_search_type = options.line_search_type;
+ nonlinear_conjugate_gradient_type =
+ options.nonlinear_conjugate_gradient_type;
+ max_lbfgs_rank = options.max_lbfgs_rank;
evaluator = NULL;
trust_region_strategy = NULL;
jacobian = NULL;
callbacks = options.callbacks;
+ inner_iteration_minimizer = NULL;
}
int max_num_iterations;
double max_solver_time_in_seconds;
+ int num_threads;
// Number of times the linear solver should be retried in case of
// numerical failure. The retries are done by exponentially scaling up
@@ -104,9 +112,12 @@ class Minimizer {
vector<int> lsqp_iterations_to_dump;
DumpFormatType lsqp_dump_format_type;
string lsqp_dump_directory;
- int num_eliminate_blocks;
int max_num_consecutive_invalid_steps;
int min_trust_region_radius;
+ LineSearchDirectionType line_search_direction_type;
+ LineSearchType line_search_type;
+ NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
+ int max_lbfgs_rank;
// List of callbacks that are executed by the Minimizer at the end
// of each iteration.
@@ -128,10 +139,15 @@ class Minimizer {
// and will remain constant for the life time of the
// optimization. The Options struct does not own this pointer.
SparseMatrix* jacobian;
+
+ Minimizer* inner_iteration_minimizer;
};
- virtual ~Minimizer() {}
+ static bool RunCallbacks(const vector<IterationCallback*> callbacks,
+ const IterationSummary& iteration_summary,
+ Solver::Summary* summary);
+ virtual ~Minimizer();
// Note: The minimizer is expected to update the state of the
// parameters array every iteration. This is required for the
// StateUpdatingCallback to work.
diff --git a/extern/libmv/third_party/ceres/internal/ceres/mutex.h b/extern/libmv/third_party/ceres/internal/ceres/mutex.h
index 5090a71b78d..410748ff0ab 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/mutex.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/mutex.h
@@ -107,10 +107,12 @@
# define _WIN32_WINNT 0x0400
# endif
# endif
+// Unfortunately, windows.h defines a bunch of macros with common
+// names. Two in particular need avoiding: ERROR and min/max.
// To avoid macro definition of ERROR.
-# define CERES_NOGDI
+# define NOGDI
// To avoid macro definition of min/max.
-# define CERES_NOMINMAX
+# define NOMINMAX
# include <windows.h>
typedef CRITICAL_SECTION MutexType;
#elif defined(CERES_HAVE_PTHREAD) && defined(CERES_HAVE_RWLOCK)
diff --git a/extern/libmv/third_party/ceres/internal/ceres/parameter_block.h b/extern/libmv/third_party/ceres/internal/ceres/parameter_block.h
index f20805ca873..b1e8d938b8a 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/parameter_block.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/parameter_block.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
+// Copyright 2010, 2011, 2012, 2013 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 <cstdlib>
#include <string>
#include "ceres/array_utils.h"
+#include "ceres/collections_port.h"
#include "ceres/integral_types.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/port.h"
@@ -46,6 +47,7 @@ namespace ceres {
namespace internal {
class ProblemImpl;
+class ResidualBlock;
// The parameter block encodes the location of the user's original value, and
// also the "current state" of the parameter. The evaluator uses whatever is in
@@ -58,13 +60,29 @@ class ProblemImpl;
// responsible for the proper disposal of the local parameterization.
class ParameterBlock {
public:
- ParameterBlock(double* user_state, int size) {
- Init(user_state, size, NULL);
+ // TODO(keir): Decide what data structure is best here. Should this be a set?
+ // Probably not, because sets are memory inefficient. However, if it's a
+ // vector, you can get into pathological linear performance when removing a
+ // residual block from a problem where all the residual blocks depend on one
+ // parameter; for example, shared focal length in a bundle adjustment
+ // problem. It might be worth making a custom structure that is just an array
+ // when it is small, but transitions to a hash set when it has more elements.
+ //
+ // For now, use a hash set.
+ typedef HashSet<ResidualBlock*> ResidualBlockSet;
+
+ // Create a parameter block with the user state, size, and index specified.
+ // The size is the size of the parameter block and the index is the position
+ // of the parameter block inside a Program (if any).
+ ParameterBlock(double* user_state, int size, int index) {
+ Init(user_state, size, index, NULL);
}
+
ParameterBlock(double* user_state,
int size,
+ int index,
LocalParameterization* local_parameterization) {
- Init(user_state, size, local_parameterization);
+ Init(user_state, size, index, local_parameterization);
}
// The size of the parameter block.
@@ -187,12 +205,43 @@ class ParameterBlock {
delta_offset_);
}
+ void EnableResidualBlockDependencies() {
+ CHECK(residual_blocks_.get() == NULL)
+ << "Ceres bug: There is already a residual block collection "
+ << "for parameter block: " << ToString();
+ residual_blocks_.reset(new ResidualBlockSet);
+ }
+
+ void AddResidualBlock(ResidualBlock* residual_block) {
+ CHECK(residual_blocks_.get() != NULL)
+ << "Ceres bug: The residual block collection is null for parameter "
+ << "block: " << ToString();
+ residual_blocks_->insert(residual_block);
+ }
+
+ void RemoveResidualBlock(ResidualBlock* residual_block) {
+ CHECK(residual_blocks_.get() != NULL)
+ << "Ceres bug: The residual block collection is null for parameter "
+ << "block: " << ToString();
+ CHECK(residual_blocks_->find(residual_block) != residual_blocks_->end())
+ << "Ceres bug: Missing residual for parameter block: " << ToString();
+ residual_blocks_->erase(residual_block);
+ }
+
+ // This is only intended for iterating; perhaps this should only expose
+ // .begin() and .end().
+ ResidualBlockSet* mutable_residual_blocks() {
+ return residual_blocks_.get();
+ }
+
private:
void Init(double* user_state,
int size,
+ int index,
LocalParameterization* local_parameterization) {
user_state_ = user_state;
size_ = size;
+ index_ = index;
is_constant_ = false;
state_ = user_state_;
@@ -201,7 +250,6 @@ class ParameterBlock {
SetParameterization(local_parameterization);
}
- index_ = -1;
state_offset_ = -1;
delta_offset_ = -1;
}
@@ -261,6 +309,9 @@ class ParameterBlock {
// The offset of this parameter block inside a larger delta vector.
int32 delta_offset_;
+ // If non-null, contains the residual blocks this parameter block is in.
+ scoped_ptr<ResidualBlockSet> residual_blocks_;
+
// Necessary so ProblemImpl can clean up the parameterizations.
friend class ProblemImpl;
};
diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_ordering.cc b/extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.cc
index 1cdff4e6dec..e8f626f8e80 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/schur_ordering.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.cc
@@ -28,7 +28,7 @@
//
// Author: sameeragarwal@google.com (Sameer Agarwal)
-#include "ceres/schur_ordering.h"
+#include "ceres/parameter_block_ordering.h"
#include "ceres/graph.h"
#include "ceres/graph_algorithms.h"
@@ -46,8 +46,7 @@ int ComputeSchurOrdering(const Program& program,
vector<ParameterBlock*>* ordering) {
CHECK_NOTNULL(ordering)->clear();
- scoped_ptr<Graph< ParameterBlock*> > graph(
- CHECK_NOTNULL(CreateHessianGraph(program)));
+ scoped_ptr<Graph< ParameterBlock*> > graph(CreateHessianGraph(program));
int independent_set_size = IndependentSetOrdering(*graph, ordering);
const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
@@ -62,9 +61,31 @@ int ComputeSchurOrdering(const Program& program,
return independent_set_size;
}
+void ComputeRecursiveIndependentSetOrdering(const Program& program,
+ ParameterBlockOrdering* ordering) {
+ CHECK_NOTNULL(ordering)->Clear();
+ const vector<ParameterBlock*> parameter_blocks = program.parameter_blocks();
+ scoped_ptr<Graph< ParameterBlock*> > graph(CreateHessianGraph(program));
+
+ int num_covered = 0;
+ int round = 0;
+ while (num_covered < parameter_blocks.size()) {
+ vector<ParameterBlock*> independent_set_ordering;
+ const int independent_set_size =
+ IndependentSetOrdering(*graph, &independent_set_ordering);
+ for (int i = 0; i < independent_set_size; ++i) {
+ ParameterBlock* parameter_block = independent_set_ordering[i];
+ ordering->AddElementToGroup(parameter_block->mutable_user_state(), round);
+ graph->RemoveVertex(parameter_block);
+ }
+ num_covered += independent_set_size;
+ ++round;
+ }
+}
+
Graph<ParameterBlock*>*
CreateHessianGraph(const Program& program) {
- Graph<ParameterBlock*>* graph = new Graph<ParameterBlock*>;
+ 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) {
ParameterBlock* parameter_block = parameter_blocks[i];
diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_ordering.h b/extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.h
index 1f9a4ff354f..a5277a44c70 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/schur_ordering.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.h
@@ -27,14 +27,12 @@
// POSSIBILITY OF SUCH DAMAGE.
//
// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Compute a parameter block ordering for use with the Schur
-// complement based algorithms.
-#ifndef CERES_INTERNAL_SCHUR_ORDERING_H_
-#define CERES_INTERNAL_SCHUR_ORDERING_H_
+#ifndef CERES_INTERNAL_PARAMETER_BLOCK_ORDERING_H_
+#define CERES_INTERNAL_PARAMETER_BLOCK_ORDERING_H_
#include <vector>
+#include "ceres/ordered_groups.h"
#include "ceres/graph.h"
#include "ceres/types.h"
@@ -60,6 +58,12 @@ class ParameterBlock;
int ComputeSchurOrdering(const Program& program,
vector<ParameterBlock* >* ordering);
+// Use an approximate independent set ordering to decompose the
+// parameter blocks of a problem in a sequence of independent
+// sets. The ordering covers all the non-constant parameter blocks in
+// the program.
+void ComputeRecursiveIndependentSetOrdering(const Program& program,
+ ParameterBlockOrdering* ordering);
// Builds a graph on the parameter blocks of a Problem, whose
// structure reflects the sparsity structure of the Hessian. Each
@@ -71,4 +75,4 @@ Graph<ParameterBlock*>* CreateHessianGraph(const Program& program);
} // namespace internal
} // namespace ceres
-#endif // CERES_INTERNAL_SCHUR_ORDERING_H_
+#endif // CERES_INTERNAL_PARAMETER_BLOCK_ORDERING_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/polynomial.cc
index 20c01566a89..3238b89670e 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/polynomial.cc
@@ -27,11 +27,14 @@
// POSSIBILITY OF SUCH DAMAGE.
//
// Author: moll.markus@arcor.de (Markus Moll)
+// sameeragarwal@google.com (Sameer Agarwal)
-#include "ceres/polynomial_solver.h"
+#include "ceres/polynomial.h"
#include <cmath>
#include <cstddef>
+#include <vector>
+
#include "Eigen/Dense"
#include "ceres/internal/port.h"
#include "glog/logging.h"
@@ -159,8 +162,7 @@ bool FindPolynomialRoots(const Vector& polynomial_in,
BalanceCompanionMatrix(&companion_matrix);
// Find its (complex) eigenvalues.
- Eigen::EigenSolver<Matrix> solver(companion_matrix,
- Eigen::EigenvaluesOnly);
+ Eigen::EigenSolver<Matrix> solver(companion_matrix, false);
if (solver.info() != Eigen::Success) {
LOG(ERROR) << "Failed to extract eigenvalues from companion matrix.";
return false;
@@ -180,5 +182,138 @@ bool FindPolynomialRoots(const Vector& polynomial_in,
return true;
}
+Vector DifferentiatePolynomial(const Vector& polynomial) {
+ const int degree = polynomial.rows() - 1;
+ CHECK_GE(degree, 0);
+
+ // Degree zero polynomials are constants, and their derivative does
+ // not result in a smaller degree polynomial, just a degree zero
+ // polynomial with value zero.
+ if (degree == 0) {
+ return Eigen::VectorXd::Zero(1);
+ }
+
+ Vector derivative(degree);
+ for (int i = 0; i < degree; ++i) {
+ derivative(i) = (degree - i) * polynomial(i);
+ }
+
+ return derivative;
+}
+
+void MinimizePolynomial(const Vector& polynomial,
+ const double x_min,
+ const double x_max,
+ double* optimal_x,
+ double* optimal_value) {
+ // Find the minimum of the polynomial at the two ends.
+ //
+ // We start by inspecting the middle of the interval. Technically
+ // this is not needed, but we do this to make this code as close to
+ // the minFunc package as possible.
+ *optimal_x = (x_min + x_max) / 2.0;
+ *optimal_value = EvaluatePolynomial(polynomial, *optimal_x);
+
+ const double x_min_value = EvaluatePolynomial(polynomial, x_min);
+ if (x_min_value < *optimal_value) {
+ *optimal_value = x_min_value;
+ *optimal_x = x_min;
+ }
+
+ const double x_max_value = EvaluatePolynomial(polynomial, x_max);
+ if (x_max_value < *optimal_value) {
+ *optimal_value = x_max_value;
+ *optimal_x = x_max;
+ }
+
+ // If the polynomial is linear or constant, we are done.
+ if (polynomial.rows() <= 2) {
+ return;
+ }
+
+ const Vector derivative = DifferentiatePolynomial(polynomial);
+ Vector roots_real;
+ if (!FindPolynomialRoots(derivative, &roots_real, NULL)) {
+ LOG(WARNING) << "Unable to find the critical points of "
+ << "the interpolating polynomial.";
+ return;
+ }
+
+ // This is a bit of an overkill, as some of the roots may actually
+ // have a complex part, but its simpler to just check these values.
+ for (int i = 0; i < roots_real.rows(); ++i) {
+ const double root = roots_real(i);
+ if ((root < x_min) || (root > x_max)) {
+ continue;
+ }
+
+ const double value = EvaluatePolynomial(polynomial, root);
+ if (value < *optimal_value) {
+ *optimal_value = value;
+ *optimal_x = root;
+ }
+ }
+}
+
+Vector FindInterpolatingPolynomial(const vector<FunctionSample>& samples) {
+ const int num_samples = samples.size();
+ int num_constraints = 0;
+ for (int i = 0; i < num_samples; ++i) {
+ if (samples[i].value_is_valid) {
+ ++num_constraints;
+ }
+ if (samples[i].gradient_is_valid) {
+ ++num_constraints;
+ }
+ }
+
+ const int degree = num_constraints - 1;
+ Matrix lhs = Matrix::Zero(num_constraints, num_constraints);
+ Vector rhs = Vector::Zero(num_constraints);
+
+ int row = 0;
+ for (int i = 0; i < num_samples; ++i) {
+ const FunctionSample& sample = samples[i];
+ if (sample.value_is_valid) {
+ for (int j = 0; j <= degree; ++j) {
+ lhs(row, j) = pow(sample.x, degree - j);
+ }
+ rhs(row) = sample.value;
+ ++row;
+ }
+
+ if (sample.gradient_is_valid) {
+ for (int j = 0; j < degree; ++j) {
+ lhs(row, j) = (degree - j) * pow(sample.x, degree - j - 1);
+ }
+ rhs(row) = sample.gradient;
+ ++row;
+ }
+ }
+
+ return lhs.fullPivLu().solve(rhs);
+}
+
+void MinimizeInterpolatingPolynomial(const vector<FunctionSample>& samples,
+ double x_min,
+ double x_max,
+ double* optimal_x,
+ double* optimal_value) {
+ const Vector polynomial = FindInterpolatingPolynomial(samples);
+ MinimizePolynomial(polynomial, x_min, x_max, optimal_x, optimal_value);
+ for (int i = 0; i < samples.size(); ++i) {
+ const FunctionSample& sample = samples[i];
+ if ((sample.x < x_min) || (sample.x > x_max)) {
+ continue;
+ }
+
+ const double value = EvaluatePolynomial(polynomial, sample.x);
+ if (value < *optimal_value) {
+ *optimal_x = sample.x;
+ *optimal_value = value;
+ }
+ }
+}
+
} // namespace internal
} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/polynomial.h b/extern/libmv/third_party/ceres/internal/ceres/polynomial.h
new file mode 100644
index 00000000000..42ffdcb13c5
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/polynomial.h
@@ -0,0 +1,134 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 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: moll.markus@arcor.de (Markus Moll)
+// sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_POLYNOMIAL_SOLVER_H_
+#define CERES_INTERNAL_POLYNOMIAL_SOLVER_H_
+
+#include <vector>
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/port.h"
+
+namespace ceres {
+namespace internal {
+
+// All polynomials are assumed to be the form
+//
+// sum_{i=0}^N polynomial(i) x^{N-i}.
+//
+// and are given by a vector of coefficients of size N + 1.
+
+// Evaluate the polynomial at x using the Horner scheme.
+inline double EvaluatePolynomial(const Vector& polynomial, double x) {
+ double v = 0.0;
+ for (int i = 0; i < polynomial.size(); ++i) {
+ v = v * x + polynomial(i);
+ }
+ return v;
+}
+
+// Use the companion matrix eigenvalues to determine the roots of the
+// polynomial.
+//
+// This function returns true on success, false otherwise.
+// Failure indicates that the polynomial is invalid (of size 0) or
+// that the eigenvalues of the companion matrix could not be computed.
+// On failure, a more detailed message will be written to LOG(ERROR).
+// If real is not NULL, the real parts of the roots will be returned in it.
+// Likewise, if imaginary is not NULL, imaginary parts will be returned in it.
+bool FindPolynomialRoots(const Vector& polynomial,
+ Vector* real,
+ Vector* imaginary);
+
+// Return the derivative of the given polynomial. It is assumed that
+// the input polynomial is at least of degree zero.
+Vector DifferentiatePolynomial(const Vector& polynomial);
+
+// Find the minimum value of the polynomial in the interval [x_min,
+// x_max]. The minimum is obtained by computing all the roots of the
+// derivative of the input polynomial. All real roots within the
+// interval [x_min, x_max] are considered as well as the end points
+// x_min and x_max. Since polynomials are differentiable functions,
+// this ensures that the true minimum is found.
+void MinimizePolynomial(const Vector& polynomial,
+ double x_min,
+ double x_max,
+ double* optimal_x,
+ double* optimal_value);
+
+// Structure for storing sample values of a function.
+//
+// Clients can use this struct to communicate the value of the
+// function and or its gradient at a given point x.
+struct FunctionSample {
+ FunctionSample()
+ : x(0.0),
+ value(0.0),
+ value_is_valid(false),
+ gradient(0.0),
+ gradient_is_valid(false) {
+ }
+
+ double x;
+ double value; // value = f(x)
+ bool value_is_valid;
+ double gradient; // gradient = f'(x)
+ bool gradient_is_valid;
+};
+
+// Given a set of function value and/or gradient samples, find a
+// polynomial whose value and gradients are exactly equal to the ones
+// in samples.
+//
+// Generally speaking,
+//
+// degree = # values + # gradients - 1
+//
+// Of course its possible to sample a polynomial any number of times,
+// in which case, generally speaking the spurious higher order
+// coefficients will be zero.
+Vector FindInterpolatingPolynomial(const vector<FunctionSample>& samples);
+
+// Interpolate the function described by samples with a polynomial,
+// and minimize it on the interval [x_min, x_max]. Depending on the
+// input samples, it is possible that the interpolation or the root
+// finding algorithms may fail due to numerical difficulties. But the
+// function is guaranteed to return its best guess of an answer, by
+// considering the samples and the end points as possible solutions.
+void MinimizeInterpolatingPolynomial(const vector<FunctionSample>& samples,
+ double x_min,
+ double x_max,
+ double* optimal_x,
+ double* optimal_value);
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_POLYNOMIAL_SOLVER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/preconditioner.cc b/extern/libmv/third_party/ceres/internal/ceres/preconditioner.cc
new file mode 100644
index 00000000000..05e539f9fb1
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/preconditioner.cc
@@ -0,0 +1,63 @@
+// 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)
+
+#include "ceres/preconditioner.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+Preconditioner::~Preconditioner() {
+}
+
+SparseMatrixPreconditionerWrapper::SparseMatrixPreconditionerWrapper(
+ const SparseMatrix* matrix)
+ : matrix_(CHECK_NOTNULL(matrix)) {
+}
+
+SparseMatrixPreconditionerWrapper::~SparseMatrixPreconditionerWrapper() {
+}
+
+bool SparseMatrixPreconditionerWrapper::Update(const BlockSparseMatrixBase& A,
+ const double* D) {
+ return true;
+}
+
+void SparseMatrixPreconditionerWrapper::RightMultiply(const double* x,
+ double* y) const {
+ matrix_->RightMultiply(x, y);
+}
+
+int SparseMatrixPreconditionerWrapper::num_rows() const {
+ return matrix_->num_rows();
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/preconditioner.h b/extern/libmv/third_party/ceres/internal/ceres/preconditioner.h
new file mode 100644
index 00000000000..5bb077e0e33
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/preconditioner.h
@@ -0,0 +1,148 @@
+// 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_PRECONDITIONER_H_
+#define CERES_INTERNAL_PRECONDITIONER_H_
+
+#include <vector>
+#include "ceres/linear_operator.h"
+#include "ceres/sparse_matrix.h"
+
+namespace ceres {
+namespace internal {
+
+class BlockSparseMatrixBase;
+class SparseMatrix;
+
+class Preconditioner : public LinearOperator {
+ public:
+ struct Options {
+ Options()
+ : type(JACOBI),
+ sparse_linear_algebra_library(SUITE_SPARSE),
+ use_block_amd(true),
+ num_threads(1),
+ row_block_size(Dynamic),
+ e_block_size(Dynamic),
+ f_block_size(Dynamic) {
+ }
+
+ PreconditionerType type;
+
+ SparseLinearAlgebraLibraryType sparse_linear_algebra_library;
+
+ // See solver.h for explanation of this option.
+ bool use_block_amd;
+
+ // If possible, how many threads the preconditioner can use.
+ int num_threads;
+
+ // Hints about the order in which the parameter blocks should be
+ // eliminated by the linear solver.
+ //
+ // For example if elimination_groups is a vector of size k, then
+ // the linear solver is informed that it should eliminate the
+ // parameter blocks 0 ... elimination_groups[0] - 1 first, and
+ // then elimination_groups[0] ... elimination_groups[1] and so
+ // on. Within each elimination group, the linear solver is free to
+ // choose how the parameter blocks are ordered. Different linear
+ // solvers have differing requirements on elimination_groups.
+ //
+ // The most common use is for Schur type solvers, where there
+ // should be at least two elimination groups and the first
+ // elimination group must form an independent set in the normal
+ // equations. The first elimination group corresponds to the
+ // num_eliminate_blocks in the Schur type solvers.
+ vector<int> elimination_groups;
+
+ // If the block sizes in a BlockSparseMatrix are fixed, then in
+ // some cases the Schur complement based solvers can detect and
+ // specialize on them.
+ //
+ // It is expected that these parameters are set programmatically
+ // rather than manually.
+ //
+ // Please see schur_complement_solver.h and schur_eliminator.h for
+ // more details.
+ int row_block_size;
+ int e_block_size;
+ int f_block_size;
+ };
+
+ virtual ~Preconditioner();
+
+ // Update the numerical value of the preconditioner for the linear
+ // system:
+ //
+ // | A | x = |b|
+ // |diag(D)| |0|
+ //
+ // for some vector b. It is important that the matrix A have the
+ // same block structure as the one used to construct this object.
+ //
+ // D can be NULL, in which case its interpreted as a diagonal matrix
+ // of size zero.
+ virtual bool Update(const BlockSparseMatrixBase& A, const double* D) = 0;
+
+ // LinearOperator interface. Since the operator is symmetric,
+ // LeftMultiply and num_cols are just calls to RightMultiply and
+ // num_rows respectively. Update() must be called before
+ // RightMultiply can be called.
+ virtual void RightMultiply(const double* x, double* y) const = 0;
+ virtual void LeftMultiply(const double* x, double* y) const {
+ return RightMultiply(x, y);
+ }
+
+ virtual int num_rows() const = 0;
+ virtual int num_cols() const {
+ return num_rows();
+ }
+};
+
+// Wrap a SparseMatrix object as a preconditioner.
+class SparseMatrixPreconditionerWrapper : public Preconditioner {
+ public:
+ // Wrapper does NOT take ownership of the matrix pointer.
+ explicit SparseMatrixPreconditionerWrapper(const SparseMatrix* matrix);
+ virtual ~SparseMatrixPreconditionerWrapper();
+
+ // Preconditioner interface
+ virtual bool Update(const BlockSparseMatrixBase& A, const double* D);
+ virtual void RightMultiply(const double* x, double* y) const;
+ virtual int num_rows() const;
+
+ private:
+ const SparseMatrix* matrix_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_PRECONDITIONER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/problem.cc b/extern/libmv/third_party/ceres/internal/ceres/problem.cc
index b8c25d9db84..43e78835b15 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/problem.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/problem.cc
@@ -32,12 +32,11 @@
#include "ceres/problem.h"
#include <vector>
+#include "ceres/crs_matrix.h"
#include "ceres/problem_impl.h"
namespace ceres {
-class ResidualBlock;
-
Problem::Problem() : problem_impl_(new internal::ProblemImpl) {}
Problem::Problem(const Problem::Options& options)
: problem_impl_(new internal::ProblemImpl(options)) {}
@@ -106,6 +105,47 @@ ResidualBlockId Problem::AddResidualBlock(
x0, x1, x2, x3, x4, x5);
}
+ResidualBlockId Problem::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
+ double* x6) {
+ return problem_impl_->AddResidualBlock(cost_function,
+ loss_function,
+ x0, x1, x2, x3, x4, x5, x6);
+}
+
+ResidualBlockId Problem::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
+ double* x6, double* x7) {
+ return problem_impl_->AddResidualBlock(cost_function,
+ loss_function,
+ x0, x1, x2, x3, x4, x5, x6, x7);
+}
+
+ResidualBlockId Problem::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
+ double* x6, double* x7, double* x8) {
+ return problem_impl_->AddResidualBlock(cost_function,
+ loss_function,
+ x0, x1, x2, x3, x4, x5, x6, x7, x8);
+}
+
+ResidualBlockId Problem::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
+ double* x6, double* x7, double* x8, double* x9) {
+ return problem_impl_->AddResidualBlock(
+ cost_function,
+ loss_function,
+ x0, x1, x2, x3, x4, x5, x6, x7, x8, x9);
+}
+
void Problem::AddParameterBlock(double* values, int size) {
problem_impl_->AddParameterBlock(values, size);
}
@@ -116,6 +156,14 @@ void Problem::AddParameterBlock(double* values,
problem_impl_->AddParameterBlock(values, size, local_parameterization);
}
+void Problem::RemoveResidualBlock(ResidualBlockId residual_block) {
+ problem_impl_->RemoveResidualBlock(residual_block);
+}
+
+void Problem::RemoveParameterBlock(double* values) {
+ problem_impl_->RemoveParameterBlock(values);
+}
+
void Problem::SetParameterBlockConstant(double* values) {
problem_impl_->SetParameterBlockConstant(values);
}
@@ -130,6 +178,18 @@ void Problem::SetParameterization(
problem_impl_->SetParameterization(values, local_parameterization);
}
+bool Problem::Evaluate(const EvaluateOptions& evaluate_options,
+ double* cost,
+ vector<double>* residuals,
+ vector<double>* gradient,
+ CRSMatrix* jacobian) {
+ return problem_impl_->Evaluate(evaluate_options,
+ cost,
+ residuals,
+ gradient,
+ jacobian);
+}
+
int Problem::NumParameterBlocks() const {
return problem_impl_->NumParameterBlocks();
}
diff --git a/extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc b/extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc
index c186f527be8..bc378aaafff 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc
@@ -37,7 +37,11 @@
#include <string>
#include <utility>
#include <vector>
+#include "ceres/casts.h"
+#include "ceres/compressed_row_sparse_matrix.h"
#include "ceres/cost_function.h"
+#include "ceres/crs_matrix.h"
+#include "ceres/evaluator.h"
#include "ceres/loss_function.h"
#include "ceres/map_util.h"
#include "ceres/parameter_block.h"
@@ -73,54 +77,103 @@ static void CheckForNoAliasing(double* existing_block,
<< "size " << new_block_size << ".";
}
-static ParameterBlock* InternalAddParameterBlock(
- double* values,
- int size,
- ParameterMap* parameter_map,
- vector<ParameterBlock*>* parameter_blocks) {
- CHECK(values) << "Null pointer passed to AddParameterBlock for a parameter "
- << "with size " << size;
+ParameterBlock* ProblemImpl::InternalAddParameterBlock(double* values,
+ int size) {
+ CHECK(values != NULL) << "Null pointer passed to AddParameterBlock "
+ << "for a parameter with size " << size;
// Ignore the request if there is a block for the given pointer already.
- ParameterMap::iterator it = parameter_map->find(values);
- if (it != parameter_map->end()) {
- int existing_size = it->second->Size();
- CHECK(size == existing_size)
- << "Tried adding a parameter block with the same double pointer, "
- << values << ", twice, but with different block sizes. Original "
- << "size was " << existing_size << " but new size is "
- << size;
+ ParameterMap::iterator it = parameter_block_map_.find(values);
+ if (it != parameter_block_map_.end()) {
+ if (!options_.disable_all_safety_checks) {
+ int existing_size = it->second->Size();
+ CHECK(size == existing_size)
+ << "Tried adding a parameter block with the same double pointer, "
+ << values << ", twice, but with different block sizes. Original "
+ << "size was " << existing_size << " but new size is "
+ << size;
+ }
return it->second;
}
- // Before adding the parameter block, also check that it doesn't alias any
- // other parameter blocks.
- if (!parameter_map->empty()) {
- ParameterMap::iterator lb = parameter_map->lower_bound(values);
-
- // If lb is not the first block, check the previous block for aliasing.
- if (lb != parameter_map->begin()) {
- ParameterMap::iterator previous = lb;
- --previous;
- CheckForNoAliasing(previous->first,
- previous->second->Size(),
- values,
- size);
- }
- // If lb is not off the end, check lb for aliasing.
- if (lb != parameter_map->end()) {
- CheckForNoAliasing(lb->first,
- lb->second->Size(),
- values,
- size);
+ if (!options_.disable_all_safety_checks) {
+ // Before adding the parameter block, also check that it doesn't alias any
+ // other parameter blocks.
+ if (!parameter_block_map_.empty()) {
+ ParameterMap::iterator lb = parameter_block_map_.lower_bound(values);
+
+ // If lb is not the first block, check the previous block for aliasing.
+ if (lb != parameter_block_map_.begin()) {
+ ParameterMap::iterator previous = lb;
+ --previous;
+ CheckForNoAliasing(previous->first,
+ previous->second->Size(),
+ values,
+ size);
+ }
+
+ // If lb is not off the end, check lb for aliasing.
+ if (lb != parameter_block_map_.end()) {
+ CheckForNoAliasing(lb->first,
+ lb->second->Size(),
+ values,
+ size);
+ }
}
}
- ParameterBlock* new_parameter_block = new ParameterBlock(values, size);
- (*parameter_map)[values] = new_parameter_block;
- parameter_blocks->push_back(new_parameter_block);
+
+ // Pass the index of the new parameter block as well to keep the index in
+ // sync with the position of the parameter in the program's parameter vector.
+ ParameterBlock* new_parameter_block =
+ new ParameterBlock(values, size, program_->parameter_blocks_.size());
+
+ // For dynamic problems, add the list of dependent residual blocks, which is
+ // empty to start.
+ if (options_.enable_fast_parameter_block_removal) {
+ new_parameter_block->EnableResidualBlockDependencies();
+ }
+ parameter_block_map_[values] = new_parameter_block;
+ program_->parameter_blocks_.push_back(new_parameter_block);
return new_parameter_block;
}
+// Deletes the residual block in question, assuming there are no other
+// references to it inside the problem (e.g. by another parameter). Referenced
+// cost and loss functions are tucked away for future deletion, since it is not
+// possible to know whether other parts of the problem depend on them without
+// doing a full scan.
+void ProblemImpl::DeleteBlock(ResidualBlock* residual_block) {
+ // The const casts here are legit, since ResidualBlock holds these
+ // pointers as const pointers but we have ownership of them and
+ // have the right to destroy them when the destructor is called.
+ if (options_.cost_function_ownership == TAKE_OWNERSHIP &&
+ residual_block->cost_function() != NULL) {
+ cost_functions_to_delete_.push_back(
+ const_cast<CostFunction*>(residual_block->cost_function()));
+ }
+ if (options_.loss_function_ownership == TAKE_OWNERSHIP &&
+ residual_block->loss_function() != NULL) {
+ loss_functions_to_delete_.push_back(
+ const_cast<LossFunction*>(residual_block->loss_function()));
+ }
+ delete residual_block;
+}
+
+// Deletes the parameter block in question, assuming there are no other
+// references to it inside the problem (e.g. by any residual blocks).
+// Referenced parameterizations are tucked away for future deletion, since it
+// is not possible to know whether other parts of the problem depend on them
+// without doing a full scan.
+void ProblemImpl::DeleteBlock(ParameterBlock* parameter_block) {
+ if (options_.local_parameterization_ownership == TAKE_OWNERSHIP &&
+ parameter_block->local_parameterization() != NULL) {
+ local_parameterizations_to_delete_.push_back(
+ parameter_block->mutable_local_parameterization());
+ }
+ parameter_block_map_.erase(parameter_block->mutable_user_state());
+ delete parameter_block;
+}
+
ProblemImpl::ProblemImpl() : program_(new internal::Program) {}
ProblemImpl::ProblemImpl(const Problem::Options& options)
: options_(options),
@@ -128,48 +181,28 @@ ProblemImpl::ProblemImpl(const Problem::Options& options)
ProblemImpl::~ProblemImpl() {
// Collect the unique cost/loss functions and delete the residuals.
- set<CostFunction*> cost_functions;
- set<LossFunction*> loss_functions;
+ const int num_residual_blocks = program_->residual_blocks_.size();
+ cost_functions_to_delete_.reserve(num_residual_blocks);
+ loss_functions_to_delete_.reserve(num_residual_blocks);
for (int i = 0; i < program_->residual_blocks_.size(); ++i) {
- ResidualBlock* residual_block = program_->residual_blocks_[i];
-
- // The const casts here are legit, since ResidualBlock holds these
- // pointers as const pointers but we have ownership of them and
- // have the right to destroy them when the destructor is called.
- if (options_.cost_function_ownership == TAKE_OWNERSHIP) {
- cost_functions.insert(
- const_cast<CostFunction*>(residual_block->cost_function()));
- }
- if (options_.loss_function_ownership == TAKE_OWNERSHIP) {
- loss_functions.insert(
- const_cast<LossFunction*>(residual_block->loss_function()));
- }
-
- delete residual_block;
+ DeleteBlock(program_->residual_blocks_[i]);
}
// Collect the unique parameterizations and delete the parameters.
- set<LocalParameterization*> local_parameterizations;
for (int i = 0; i < program_->parameter_blocks_.size(); ++i) {
- ParameterBlock* parameter_block = program_->parameter_blocks_[i];
-
- if (options_.local_parameterization_ownership == TAKE_OWNERSHIP) {
- local_parameterizations.insert(parameter_block->local_parameterization_);
- }
-
- delete parameter_block;
+ DeleteBlock(program_->parameter_blocks_[i]);
}
// Delete the owned cost/loss functions and parameterizations.
- STLDeleteContainerPointers(local_parameterizations.begin(),
- local_parameterizations.end());
- STLDeleteContainerPointers(cost_functions.begin(),
- cost_functions.end());
- STLDeleteContainerPointers(loss_functions.begin(),
- loss_functions.end());
+ STLDeleteUniqueContainerPointers(local_parameterizations_to_delete_.begin(),
+ local_parameterizations_to_delete_.end());
+ STLDeleteUniqueContainerPointers(cost_functions_to_delete_.begin(),
+ cost_functions_to_delete_.end());
+ STLDeleteUniqueContainerPointers(loss_functions_to_delete_.begin(),
+ loss_functions_to_delete_.end());
}
-const ResidualBlock* ProblemImpl::AddResidualBlock(
+ResidualBlock* ProblemImpl::AddResidualBlock(
CostFunction* cost_function,
LossFunction* loss_function,
const vector<double*>& parameter_blocks) {
@@ -180,25 +213,28 @@ const ResidualBlock* ProblemImpl::AddResidualBlock(
// Check the sizes match.
const vector<int16>& parameter_block_sizes =
cost_function->parameter_block_sizes();
- CHECK_EQ(parameter_block_sizes.size(), parameter_blocks.size())
- << "Number of blocks input is different than the number of blocks "
- << "that the cost function expects.";
-
- // Check for duplicate parameter blocks.
- vector<double*> sorted_parameter_blocks(parameter_blocks);
- sort(sorted_parameter_blocks.begin(), sorted_parameter_blocks.end());
- vector<double*>::const_iterator duplicate_items =
- unique(sorted_parameter_blocks.begin(),
- sorted_parameter_blocks.end());
- if (duplicate_items != sorted_parameter_blocks.end()) {
- string blocks;
- for (int i = 0; i < parameter_blocks.size(); ++i) {
- blocks += internal::StringPrintf(" %p ", parameter_blocks[i]);
- }
- LOG(FATAL) << "Duplicate parameter blocks in a residual parameter "
- << "are not allowed. Parameter block pointers: ["
- << blocks << "]";
+ if (!options_.disable_all_safety_checks) {
+ CHECK_EQ(parameter_block_sizes.size(), parameter_blocks.size())
+ << "Number of blocks input is different than the number of blocks "
+ << "that the cost function expects.";
+
+ // Check for duplicate parameter blocks.
+ vector<double*> sorted_parameter_blocks(parameter_blocks);
+ sort(sorted_parameter_blocks.begin(), sorted_parameter_blocks.end());
+ vector<double*>::const_iterator duplicate_items =
+ unique(sorted_parameter_blocks.begin(),
+ sorted_parameter_blocks.end());
+ if (duplicate_items != sorted_parameter_blocks.end()) {
+ string blocks;
+ for (int i = 0; i < parameter_blocks.size(); ++i) {
+ blocks += StringPrintf(" %p ", parameter_blocks[i]);
+ }
+
+ LOG(FATAL) << "Duplicate parameter blocks in a residual parameter "
+ << "are not allowed. Parameter block pointers: ["
+ << blocks << "]";
+ }
}
// Add parameter blocks and convert the double*'s to parameter blocks.
@@ -206,33 +242,42 @@ const ResidualBlock* ProblemImpl::AddResidualBlock(
for (int i = 0; i < parameter_blocks.size(); ++i) {
parameter_block_ptrs[i] =
InternalAddParameterBlock(parameter_blocks[i],
- parameter_block_sizes[i],
- &parameter_block_map_,
- &program_->parameter_blocks_);
+ parameter_block_sizes[i]);
}
- // Check that the block sizes match the block sizes expected by the
- // cost_function.
- for (int i = 0; i < parameter_block_ptrs.size(); ++i) {
- CHECK_EQ(cost_function->parameter_block_sizes()[i],
- parameter_block_ptrs[i]->Size())
- << "The cost function expects parameter block " << i
- << " of size " << cost_function->parameter_block_sizes()[i]
- << " but was given a block of size "
- << parameter_block_ptrs[i]->Size();
+ if (!options_.disable_all_safety_checks) {
+ // Check that the block sizes match the block sizes expected by the
+ // cost_function.
+ for (int i = 0; i < parameter_block_ptrs.size(); ++i) {
+ CHECK_EQ(cost_function->parameter_block_sizes()[i],
+ parameter_block_ptrs[i]->Size())
+ << "The cost function expects parameter block " << i
+ << " of size " << cost_function->parameter_block_sizes()[i]
+ << " but was given a block of size "
+ << parameter_block_ptrs[i]->Size();
+ }
}
ResidualBlock* new_residual_block =
new ResidualBlock(cost_function,
loss_function,
- parameter_block_ptrs);
+ parameter_block_ptrs,
+ program_->residual_blocks_.size());
+
+ // Add dependencies on the residual to the parameter blocks.
+ if (options_.enable_fast_parameter_block_removal) {
+ for (int i = 0; i < parameter_blocks.size(); ++i) {
+ parameter_block_ptrs[i]->AddResidualBlock(new_residual_block);
+ }
+ }
+
program_->residual_blocks_.push_back(new_residual_block);
return new_residual_block;
}
// Unfortunately, macros don't help much to reduce this code, and var args don't
// work because of the ambiguous case that there is no loss function.
-const ResidualBlock* ProblemImpl::AddResidualBlock(
+ResidualBlock* ProblemImpl::AddResidualBlock(
CostFunction* cost_function,
LossFunction* loss_function,
double* x0) {
@@ -241,7 +286,7 @@ const ResidualBlock* ProblemImpl::AddResidualBlock(
return AddResidualBlock(cost_function, loss_function, residual_parameters);
}
-const ResidualBlock* ProblemImpl::AddResidualBlock(
+ResidualBlock* ProblemImpl::AddResidualBlock(
CostFunction* cost_function,
LossFunction* loss_function,
double* x0, double* x1) {
@@ -251,7 +296,7 @@ const ResidualBlock* ProblemImpl::AddResidualBlock(
return AddResidualBlock(cost_function, loss_function, residual_parameters);
}
-const ResidualBlock* ProblemImpl::AddResidualBlock(
+ResidualBlock* ProblemImpl::AddResidualBlock(
CostFunction* cost_function,
LossFunction* loss_function,
double* x0, double* x1, double* x2) {
@@ -262,7 +307,7 @@ const ResidualBlock* ProblemImpl::AddResidualBlock(
return AddResidualBlock(cost_function, loss_function, residual_parameters);
}
-const ResidualBlock* ProblemImpl::AddResidualBlock(
+ResidualBlock* ProblemImpl::AddResidualBlock(
CostFunction* cost_function,
LossFunction* loss_function,
double* x0, double* x1, double* x2, double* x3) {
@@ -274,7 +319,7 @@ const ResidualBlock* ProblemImpl::AddResidualBlock(
return AddResidualBlock(cost_function, loss_function, residual_parameters);
}
-const ResidualBlock* ProblemImpl::AddResidualBlock(
+ResidualBlock* ProblemImpl::AddResidualBlock(
CostFunction* cost_function,
LossFunction* loss_function,
double* x0, double* x1, double* x2, double* x3, double* x4) {
@@ -287,7 +332,7 @@ const ResidualBlock* ProblemImpl::AddResidualBlock(
return AddResidualBlock(cost_function, loss_function, residual_parameters);
}
-const ResidualBlock* ProblemImpl::AddResidualBlock(
+ResidualBlock* ProblemImpl::AddResidualBlock(
CostFunction* cost_function,
LossFunction* loss_function,
double* x0, double* x1, double* x2, double* x3, double* x4, double* x5) {
@@ -301,12 +346,78 @@ const ResidualBlock* ProblemImpl::AddResidualBlock(
return AddResidualBlock(cost_function, loss_function, residual_parameters);
}
+ResidualBlock* ProblemImpl::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
+ double* x6) {
+ vector<double*> residual_parameters;
+ residual_parameters.push_back(x0);
+ residual_parameters.push_back(x1);
+ residual_parameters.push_back(x2);
+ residual_parameters.push_back(x3);
+ residual_parameters.push_back(x4);
+ residual_parameters.push_back(x5);
+ residual_parameters.push_back(x6);
+ return AddResidualBlock(cost_function, loss_function, residual_parameters);
+}
+
+ResidualBlock* ProblemImpl::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
+ double* x6, double* x7) {
+ vector<double*> residual_parameters;
+ residual_parameters.push_back(x0);
+ residual_parameters.push_back(x1);
+ residual_parameters.push_back(x2);
+ residual_parameters.push_back(x3);
+ residual_parameters.push_back(x4);
+ residual_parameters.push_back(x5);
+ residual_parameters.push_back(x6);
+ residual_parameters.push_back(x7);
+ return AddResidualBlock(cost_function, loss_function, residual_parameters);
+}
+
+ResidualBlock* ProblemImpl::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
+ double* x6, double* x7, double* x8) {
+ vector<double*> residual_parameters;
+ residual_parameters.push_back(x0);
+ residual_parameters.push_back(x1);
+ residual_parameters.push_back(x2);
+ residual_parameters.push_back(x3);
+ residual_parameters.push_back(x4);
+ residual_parameters.push_back(x5);
+ residual_parameters.push_back(x6);
+ residual_parameters.push_back(x7);
+ residual_parameters.push_back(x8);
+ return AddResidualBlock(cost_function, loss_function, residual_parameters);
+}
+
+ResidualBlock* ProblemImpl::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
+ double* x6, double* x7, double* x8, double* x9) {
+ vector<double*> residual_parameters;
+ residual_parameters.push_back(x0);
+ residual_parameters.push_back(x1);
+ residual_parameters.push_back(x2);
+ residual_parameters.push_back(x3);
+ residual_parameters.push_back(x4);
+ residual_parameters.push_back(x5);
+ residual_parameters.push_back(x6);
+ residual_parameters.push_back(x7);
+ residual_parameters.push_back(x8);
+ residual_parameters.push_back(x9);
+ return AddResidualBlock(cost_function, loss_function, residual_parameters);
+}
void ProblemImpl::AddParameterBlock(double* values, int size) {
- InternalAddParameterBlock(values,
- size,
- &parameter_block_map_,
- &program_->parameter_blocks_);
+ InternalAddParameterBlock(values, size);
}
void ProblemImpl::AddParameterBlock(
@@ -314,15 +425,83 @@ void ProblemImpl::AddParameterBlock(
int size,
LocalParameterization* local_parameterization) {
ParameterBlock* parameter_block =
- InternalAddParameterBlock(values,
- size,
- &parameter_block_map_,
- &program_->parameter_blocks_);
+ InternalAddParameterBlock(values, size);
if (local_parameterization != NULL) {
parameter_block->SetParameterization(local_parameterization);
}
}
+// Delete a block from a vector of blocks, maintaining the indexing invariant.
+// This is done in constant time by moving an element from the end of the
+// vector over the element to remove, then popping the last element. It
+// destroys the ordering in the interest of speed.
+template<typename Block>
+void ProblemImpl::DeleteBlockInVector(vector<Block*>* mutable_blocks,
+ Block* block_to_remove) {
+ CHECK_EQ((*mutable_blocks)[block_to_remove->index()], block_to_remove)
+ << "You found a Ceres bug! Block: " << block_to_remove->ToString();
+
+ // Prepare the to-be-moved block for the new, lower-in-index position by
+ // setting the index to the blocks final location.
+ Block* tmp = mutable_blocks->back();
+ tmp->set_index(block_to_remove->index());
+
+ // Overwrite the to-be-deleted residual block with the one at the end.
+ (*mutable_blocks)[block_to_remove->index()] = tmp;
+
+ DeleteBlock(block_to_remove);
+
+ // The block is gone so shrink the vector of blocks accordingly.
+ mutable_blocks->pop_back();
+}
+
+void ProblemImpl::RemoveResidualBlock(ResidualBlock* residual_block) {
+ CHECK_NOTNULL(residual_block);
+
+ // If needed, remove the parameter dependencies on this residual block.
+ if (options_.enable_fast_parameter_block_removal) {
+ const int num_parameter_blocks_for_residual =
+ residual_block->NumParameterBlocks();
+ for (int i = 0; i < num_parameter_blocks_for_residual; ++i) {
+ residual_block->parameter_blocks()[i]
+ ->RemoveResidualBlock(residual_block);
+ }
+ }
+ DeleteBlockInVector(program_->mutable_residual_blocks(), residual_block);
+}
+
+void ProblemImpl::RemoveParameterBlock(double* values) {
+ ParameterBlock* parameter_block = FindOrDie(parameter_block_map_, values);
+
+ if (options_.enable_fast_parameter_block_removal) {
+ // Copy the dependent residuals from the parameter block because the set of
+ // dependents will change after each call to RemoveResidualBlock().
+ vector<ResidualBlock*> residual_blocks_to_remove(
+ parameter_block->mutable_residual_blocks()->begin(),
+ parameter_block->mutable_residual_blocks()->end());
+ for (int i = 0; i < residual_blocks_to_remove.size(); ++i) {
+ RemoveResidualBlock(residual_blocks_to_remove[i]);
+ }
+ } else {
+ // Scan all the residual blocks to remove ones that depend on the parameter
+ // block. Do the scan backwards since the vector changes while iterating.
+ const int num_residual_blocks = NumResidualBlocks();
+ for (int i = num_residual_blocks - 1; i >= 0; --i) {
+ ResidualBlock* residual_block =
+ (*(program_->mutable_residual_blocks()))[i];
+ const int num_parameter_blocks = residual_block->NumParameterBlocks();
+ for (int j = 0; j < num_parameter_blocks; ++j) {
+ if (residual_block->parameter_blocks()[j] == parameter_block) {
+ RemoveResidualBlock(residual_block);
+ // The parameter blocks are guaranteed unique.
+ break;
+ }
+ }
+ }
+ }
+ DeleteBlockInVector(program_->mutable_parameter_blocks(), parameter_block);
+}
+
void ProblemImpl::SetParameterBlockConstant(double* values) {
FindOrDie(parameter_block_map_, values)->SetConstant();
}
@@ -338,6 +517,164 @@ void ProblemImpl::SetParameterization(
->SetParameterization(local_parameterization);
}
+bool ProblemImpl::Evaluate(const Problem::EvaluateOptions& evaluate_options,
+ double* cost,
+ vector<double>* residuals,
+ vector<double>* gradient,
+ CRSMatrix* jacobian) {
+ if (cost == NULL &&
+ residuals == NULL &&
+ gradient == NULL &&
+ jacobian == NULL) {
+ LOG(INFO) << "Nothing to do.";
+ return true;
+ }
+
+ // If the user supplied residual blocks, then use them, otherwise
+ // take the residual blocks from the underlying program.
+ Program program;
+ *program.mutable_residual_blocks() =
+ ((evaluate_options.residual_blocks.size() > 0)
+ ? evaluate_options.residual_blocks : program_->residual_blocks());
+
+ const vector<double*>& parameter_block_ptrs =
+ evaluate_options.parameter_blocks;
+
+ vector<ParameterBlock*> variable_parameter_blocks;
+ vector<ParameterBlock*>& parameter_blocks =
+ *program.mutable_parameter_blocks();
+
+ if (parameter_block_ptrs.size() == 0) {
+ // The user did not provide any parameter blocks, so default to
+ // using all the parameter blocks in the order that they are in
+ // the underlying program object.
+ parameter_blocks = program_->parameter_blocks();
+ } else {
+ // The user supplied a vector of parameter blocks. Using this list
+ // requires a number of steps.
+
+ // 1. Convert double* into ParameterBlock*
+ parameter_blocks.resize(parameter_block_ptrs.size());
+ for (int i = 0; i < parameter_block_ptrs.size(); ++i) {
+ parameter_blocks[i] =
+ FindOrDie(parameter_block_map_, parameter_block_ptrs[i]);
+ }
+
+ // 2. The user may have only supplied a subset of parameter
+ // blocks, so identify the ones that are not supplied by the user
+ // and are NOT constant. These parameter blocks are stored in
+ // variable_parameter_blocks.
+ //
+ // To ensure that the parameter blocks are not included in the
+ // columns of the jacobian, we need to make sure that they are
+ // constant during evaluation and then make them variable again
+ // after we are done.
+ vector<ParameterBlock*> all_parameter_blocks(program_->parameter_blocks());
+ vector<ParameterBlock*> included_parameter_blocks(
+ program.parameter_blocks());
+
+ vector<ParameterBlock*> excluded_parameter_blocks;
+ sort(all_parameter_blocks.begin(), all_parameter_blocks.end());
+ sort(included_parameter_blocks.begin(), included_parameter_blocks.end());
+ set_difference(all_parameter_blocks.begin(),
+ all_parameter_blocks.end(),
+ included_parameter_blocks.begin(),
+ included_parameter_blocks.end(),
+ back_inserter(excluded_parameter_blocks));
+
+ variable_parameter_blocks.reserve(excluded_parameter_blocks.size());
+ for (int i = 0; i < excluded_parameter_blocks.size(); ++i) {
+ ParameterBlock* parameter_block = excluded_parameter_blocks[i];
+ if (!parameter_block->IsConstant()) {
+ variable_parameter_blocks.push_back(parameter_block);
+ parameter_block->SetConstant();
+ }
+ }
+ }
+
+ // Setup the Parameter indices and offsets before an evaluator can
+ // be constructed and used.
+ program.SetParameterOffsetsAndIndex();
+
+ Evaluator::Options evaluator_options;
+
+ // Even though using SPARSE_NORMAL_CHOLESKY requires SuiteSparse or
+ // CXSparse, here it just being used for telling the evaluator to
+ // use a SparseRowCompressedMatrix for the jacobian. This is because
+ // the Evaluator decides the storage for the Jacobian based on the
+ // type of linear solver being used.
+ evaluator_options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+ evaluator_options.num_threads = evaluate_options.num_threads;
+
+ string error;
+ scoped_ptr<Evaluator> evaluator(
+ Evaluator::Create(evaluator_options, &program, &error));
+ if (evaluator.get() == NULL) {
+ LOG(ERROR) << "Unable to create an Evaluator object. "
+ << "Error: " << error
+ << "This is a Ceres bug; please contact the developers!";
+
+ // Make the parameter blocks that were temporarily marked
+ // constant, variable again.
+ for (int i = 0; i < variable_parameter_blocks.size(); ++i) {
+ variable_parameter_blocks[i]->SetVarying();
+ }
+ return false;
+ }
+
+ if (residuals !=NULL) {
+ residuals->resize(evaluator->NumResiduals());
+ }
+
+ if (gradient != NULL) {
+ gradient->resize(evaluator->NumEffectiveParameters());
+ }
+
+ scoped_ptr<CompressedRowSparseMatrix> tmp_jacobian;
+ if (jacobian != NULL) {
+ tmp_jacobian.reset(
+ down_cast<CompressedRowSparseMatrix*>(evaluator->CreateJacobian()));
+ }
+
+ // Point the state pointers to the user state pointers. This is
+ // needed so that we can extract a parameter vector which is then
+ // passed to Evaluator::Evaluate.
+ program.SetParameterBlockStatePtrsToUserStatePtrs();
+
+ // Copy the value of the parameter blocks into a vector, since the
+ // Evaluate::Evaluate method needs its input as such. The previous
+ // call to SetParameterBlockStatePtrsToUserStatePtrs ensures that
+ // these values are the ones corresponding to the actual state of
+ // the parameter blocks, rather than the temporary state pointer
+ // used for evaluation.
+ Vector parameters(program.NumParameters());
+ program.ParameterBlocksToStateVector(parameters.data());
+
+ double tmp_cost = 0;
+ bool status = evaluator->Evaluate(parameters.data(),
+ &tmp_cost,
+ residuals != NULL ? &(*residuals)[0] : NULL,
+ gradient != NULL ? &(*gradient)[0] : NULL,
+ tmp_jacobian.get());
+
+ // Make the parameter blocks that were temporarirly marked
+ // constant, variable again.
+ for (int i = 0; i < variable_parameter_blocks.size(); ++i) {
+ variable_parameter_blocks[i]->SetVarying();
+ }
+
+ if (status) {
+ if (cost != NULL) {
+ *cost = tmp_cost;
+ }
+ if (jacobian != NULL) {
+ tmp_jacobian->ToCRSMatrix(jacobian);
+ }
+ }
+
+ return status;
+}
+
int ProblemImpl::NumParameterBlocks() const {
return program_->NumParameterBlocks();
}
diff --git a/extern/libmv/third_party/ceres/internal/ceres/problem_impl.h b/extern/libmv/third_party/ceres/internal/ceres/problem_impl.h
index 2ca055448c3..ccc315de6b6 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/problem_impl.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/problem_impl.h
@@ -53,6 +53,7 @@ namespace ceres {
class CostFunction;
class LossFunction;
class LocalParameterization;
+struct CRSMatrix;
namespace internal {
@@ -93,14 +94,46 @@ class ProblemImpl {
LossFunction* loss_function,
double* x0, double* x1, double* x2,
double* x3, double* x4, double* x5);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3, double* x4, double* x5,
+ double* x6);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3, double* x4, double* x5,
+ double* x6, double* x7);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3, double* x4, double* x5,
+ double* x6, double* x7, double* x8);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3, double* x4, double* x5,
+ double* x6, double* x7, double* x8,
+ double* x9);
void AddParameterBlock(double* values, int size);
void AddParameterBlock(double* values,
int size,
LocalParameterization* local_parameterization);
+
+ void RemoveResidualBlock(ResidualBlock* residual_block);
+ void RemoveParameterBlock(double* values);
+
void SetParameterBlockConstant(double* values);
void SetParameterBlockVariable(double* values);
void SetParameterization(double* values,
LocalParameterization* local_parameterization);
+
+ bool Evaluate(const Problem::EvaluateOptions& options,
+ double* cost,
+ vector<double>* residuals,
+ vector<double>* gradient,
+ CRSMatrix* jacobian);
+
int NumParameterBlocks() const;
int NumParameters() const;
int NumResidualBlocks() const;
@@ -112,12 +145,41 @@ class ProblemImpl {
const ParameterMap& parameter_map() const { return parameter_block_map_; }
private:
+ ParameterBlock* InternalAddParameterBlock(double* values, int size);
+
+ bool InternalEvaluate(Program* program,
+ double* cost,
+ vector<double>* residuals,
+ vector<double>* gradient,
+ CRSMatrix* jacobian);
+
+ // Delete the arguments in question. These differ from the Remove* functions
+ // in that they do not clean up references to the block to delete; they
+ // merely delete them.
+ template<typename Block>
+ void DeleteBlockInVector(vector<Block*>* mutable_blocks,
+ Block* block_to_remove);
+ void DeleteBlock(ResidualBlock* residual_block);
+ void DeleteBlock(ParameterBlock* parameter_block);
+
const Problem::Options options_;
// The mapping from user pointers to parameter blocks.
map<double*, ParameterBlock*> parameter_block_map_;
+ // The actual parameter and residual blocks.
internal::scoped_ptr<internal::Program> program_;
+
+ // When removing residual and parameter blocks, cost/loss functions and
+ // parameterizations have ambiguous ownership. Instead of scanning the entire
+ // problem to see if the cost/loss/parameterization is shared with other
+ // residual or parameter blocks, buffer them until destruction.
+ //
+ // TODO(keir): See if it makes sense to use sets instead.
+ vector<CostFunction*> cost_functions_to_delete_;
+ vector<LossFunction*> loss_functions_to_delete_;
+ vector<LocalParameterization*> local_parameterizations_to_delete_;
+
CERES_DISALLOW_COPY_AND_ASSIGN(ProblemImpl);
};
diff --git a/extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h b/extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h
index 6c48e7d7643..a19cdf8a86a 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h
@@ -83,11 +83,14 @@
#include <omp.h>
#endif
+#include <map>
+#include <vector>
+#include "ceres/execution_summary.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/scoped_ptr.h"
#include "ceres/parameter_block.h"
#include "ceres/program.h"
#include "ceres/residual_block.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
namespace ceres {
namespace internal {
@@ -122,6 +125,12 @@ class ProgramEvaluator : public Evaluator {
double* residuals,
double* gradient,
SparseMatrix* jacobian) {
+ ScopedExecutionTimer total_timer("Evaluator::Total", &execution_summary_);
+ ScopedExecutionTimer call_type_timer(gradient == NULL && jacobian == NULL
+ ? "Evaluator::Residual"
+ : "Evaluator::Jacobian",
+ &execution_summary_);
+
// The parameters are stateful, so set the state before evaluating.
if (!program_->StateVectorToParameterBlocks(state)) {
return false;
@@ -129,7 +138,7 @@ class ProgramEvaluator : public Evaluator {
if (residuals != NULL) {
VectorRef(residuals, program_->NumResiduals()).setZero();
- }
+ }
if (jacobian != NULL) {
jacobian->SetZero();
@@ -138,6 +147,10 @@ class ProgramEvaluator : public Evaluator {
// Each thread gets it's own cost and evaluate scratch space.
for (int i = 0; i < options_.num_threads; ++i) {
evaluate_scratch_[i].cost = 0.0;
+ if (gradient != NULL) {
+ VectorRef(evaluate_scratch_[i].gradient.get(),
+ program_->NumEffectiveParameters()).setZero();
+ }
}
// This bool is used to disable the loop if an error is encountered
@@ -262,6 +275,14 @@ class ProgramEvaluator : public Evaluator {
return program_->NumResiduals();
}
+ virtual map<string, int> CallStatistics() const {
+ return execution_summary_.calls();
+ }
+
+ virtual map<string, double> TimeStatistics() const {
+ return execution_summary_.times();
+ }
+
private:
// Per-thread scratch space needed to evaluate and store each residual block.
struct EvaluateScratch {
@@ -327,6 +348,7 @@ class ProgramEvaluator : public Evaluator {
scoped_array<EvaluatePreparer> evaluate_preparers_;
scoped_array<EvaluateScratch> evaluate_scratch_;
vector<int> residual_layout_;
+ ::ceres::internal::ExecutionSummary execution_summary_;
};
} // namespace internal
diff --git a/extern/libmv/third_party/ceres/internal/ceres/residual_block.cc b/extern/libmv/third_party/ceres/internal/ceres/residual_block.cc
index bdb88b1dd97..7f789605e5f 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/residual_block.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/residual_block.cc
@@ -49,12 +49,14 @@ namespace internal {
ResidualBlock::ResidualBlock(const CostFunction* cost_function,
const LossFunction* loss_function,
- const vector<ParameterBlock*>& parameter_blocks)
+ const vector<ParameterBlock*>& parameter_blocks,
+ int index)
: cost_function_(cost_function),
loss_function_(loss_function),
parameter_blocks_(
new ParameterBlock* [
- cost_function->parameter_block_sizes().size()]) {
+ cost_function->parameter_block_sizes().size()]),
+ index_(index) {
std::copy(parameter_blocks.begin(),
parameter_blocks.end(),
parameter_blocks_.get());
diff --git a/extern/libmv/third_party/ceres/internal/ceres/residual_block.h b/extern/libmv/third_party/ceres/internal/ceres/residual_block.h
index e0a06e78958..3921d1d4678 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/residual_block.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/residual_block.h
@@ -34,11 +34,13 @@
#ifndef CERES_INTERNAL_RESIDUAL_BLOCK_H_
#define CERES_INTERNAL_RESIDUAL_BLOCK_H_
+#include <string>
#include <vector>
#include "ceres/cost_function.h"
#include "ceres/internal/port.h"
#include "ceres/internal/scoped_ptr.h"
+#include "ceres/stringprintf.h"
#include "ceres/types.h"
namespace ceres {
@@ -64,9 +66,13 @@ class ParameterBlock;
// loss functions, and parameter blocks.
class ResidualBlock {
public:
+ // Construct the residual block with the given cost/loss functions. Loss may
+ // be null. The index is the index of the residual block in the Program's
+ // residual_blocks array.
ResidualBlock(const CostFunction* cost_function,
const LossFunction* loss_function,
- const vector<ParameterBlock*>& parameter_blocks);
+ const vector<ParameterBlock*>& parameter_blocks,
+ int index);
// Evaluates the residual term, storing the scalar cost in *cost, the residual
// components in *residuals, and the jacobians between the parameters and
@@ -112,10 +118,23 @@ class ResidualBlock {
// The minimum amount of scratch space needed to pass to Evaluate().
int NumScratchDoublesForEvaluate() const;
+ // This residual block's index in an array.
+ int index() const { return index_; }
+ void set_index(int index) { index_ = index; }
+
+ string ToString() {
+ return StringPrintf("{residual block; index=%d}", index_);
+ }
+
private:
const CostFunction* cost_function_;
const LossFunction* loss_function_;
scoped_array<ParameterBlock*> parameter_blocks_;
+
+ // The index of the residual, typically in a Program. This is only to permit
+ // switching from a ResidualBlock* to an index in the Program's array, needed
+ // to do efficient removals.
+ int32 index_;
};
} // namespace internal
diff --git a/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.cc b/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.cc
index 9442bb2a1c1..4d88a9f4f8a 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.cc
@@ -63,7 +63,8 @@ void InvalidateEvaluation(const ResidualBlock& block,
// Utility routine to print an array of doubles to a string. If the
// array pointer is NULL, it is treated as an array of zeros.
-static void AppendArrayToString(const int size, const double* x, string* result) {
+namespace {
+void AppendArrayToString(const int size, const double* x, string* result) {
for (int i = 0; i < size; ++i) {
if (x == NULL) {
StringAppendF(result, "Not Computed ");
@@ -76,6 +77,7 @@ static void AppendArrayToString(const int size, const double* x, string* result)
}
}
}
+} // namespace
string EvaluationToString(const ResidualBlock& block,
double const* const* parameters,
diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc
index 2cbe78d133a..17537596c75 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc
@@ -38,22 +38,21 @@
#endif // CERES_NO_CXSPARSE
#include "Eigen/Dense"
-#include "glog/logging.h"
#include "ceres/block_random_access_dense_matrix.h"
#include "ceres/block_random_access_matrix.h"
#include "ceres/block_random_access_sparse_matrix.h"
#include "ceres/block_sparse_matrix.h"
#include "ceres/block_structure.h"
#include "ceres/detect_structure.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
#include "ceres/linear_solver.h"
#include "ceres/schur_complement_solver.h"
#include "ceres/suitesparse.h"
#include "ceres/triplet_sparse_matrix.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/types.h"
-
+#include "ceres/wall_time.h"
namespace ceres {
namespace internal {
@@ -63,43 +62,39 @@ LinearSolver::Summary SchurComplementSolver::SolveImpl(
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
double* x) {
- const time_t start_time = time(NULL);
+ EventLogger event_logger("SchurComplementSolver::Solve");
+
if (eliminator_.get() == NULL) {
InitStorage(A->block_structure());
DetectStructure(*A->block_structure(),
- options_.num_eliminate_blocks,
+ options_.elimination_groups[0],
&options_.row_block_size,
&options_.e_block_size,
&options_.f_block_size);
eliminator_.reset(CHECK_NOTNULL(SchurEliminatorBase::Create(options_)));
- eliminator_->Init(options_.num_eliminate_blocks, A->block_structure());
+ eliminator_->Init(options_.elimination_groups[0], A->block_structure());
};
- const time_t init_time = time(NULL);
fill(x, x + A->num_cols(), 0.0);
+ event_logger.AddEvent("Setup");
LinearSolver::Summary summary;
summary.num_iterations = 1;
summary.termination_type = FAILURE;
eliminator_->Eliminate(A, b, per_solve_options.D, lhs_.get(), rhs_.get());
- const time_t eliminate_time = time(NULL);
+ event_logger.AddEvent("Eliminate");
double* reduced_solution = x + A->num_cols() - lhs_->num_cols();
const bool status = SolveReducedLinearSystem(reduced_solution);
- const time_t solve_time = time(NULL);
+ event_logger.AddEvent("ReducedSolve");
if (!status) {
return summary;
}
eliminator_->BackSubstitute(A, b, per_solve_options.D, reduced_solution, x);
- const time_t backsubstitute_time = time(NULL);
summary.termination_type = TOLERANCE;
- VLOG(2) << "time (sec) total: " << (backsubstitute_time - start_time)
- << " init: " << (init_time - start_time)
- << " eliminate: " << (eliminate_time - init_time)
- << " solve: " << (solve_time - eliminate_time)
- << " backsubstitute: " << (backsubstitute_time - solve_time);
+ event_logger.AddEvent("BackSubstitute");
return summary;
}
@@ -107,7 +102,7 @@ LinearSolver::Summary SchurComplementSolver::SolveImpl(
// complement.
void DenseSchurComplementSolver::InitStorage(
const CompressedRowBlockStructure* bs) {
- const int num_eliminate_blocks = options().num_eliminate_blocks;
+ const int num_eliminate_blocks = options().elimination_groups[0];
const int num_col_blocks = bs->cols.size();
vector<int> blocks(num_col_blocks - num_eliminate_blocks, 0);
@@ -179,7 +174,7 @@ SparseSchurComplementSolver::~SparseSchurComplementSolver() {
// initialize a BlockRandomAccessSparseMatrix object.
void SparseSchurComplementSolver::InitStorage(
const CompressedRowBlockStructure* bs) {
- const int num_eliminate_blocks = options().num_eliminate_blocks;
+ const int num_eliminate_blocks = options().elimination_groups[0];
const int num_col_blocks = bs->cols.size();
const int num_row_blocks = bs->rows.size();
@@ -268,8 +263,6 @@ bool SparseSchurComplementSolver::SolveReducedLinearSystem(double* solution) {
// CHOLMOD's sparse cholesky factorization routines.
bool SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse(
double* solution) {
- const time_t start_time = time(NULL);
-
TripletSparseMatrix* tsm =
const_cast<TripletSparseMatrix*>(
down_cast<const BlockRandomAccessSparseMatrix*>(lhs())->matrix());
@@ -286,11 +279,9 @@ bool SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse(
// The matrix is symmetric, and the upper triangular part of the
// matrix contains the values.
cholmod_lhs->stype = 1;
- const time_t lhs_time = time(NULL);
cholmod_dense* cholmod_rhs =
ss_.CreateDenseVector(const_cast<double*>(rhs()), num_rows, num_rows);
- const time_t rhs_time = time(NULL);
// Symbolic factorization is computed if we don't already have one handy.
if (factor_ == NULL) {
@@ -307,32 +298,22 @@ bool SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse(
CHECK_NOTNULL(factor_);
- const time_t symbolic_time = time(NULL);
cholmod_dense* cholmod_solution =
ss_.SolveCholesky(cholmod_lhs, factor_, cholmod_rhs);
- const time_t solve_time = time(NULL);
-
ss_.Free(cholmod_lhs);
cholmod_lhs = NULL;
ss_.Free(cholmod_rhs);
cholmod_rhs = NULL;
if (cholmod_solution == NULL) {
- LOG(ERROR) << "CHOLMOD solve failed.";
+ LOG(WARNING) << "CHOLMOD solve failed.";
return false;
}
VectorRef(solution, num_rows)
= VectorRef(static_cast<double*>(cholmod_solution->x), num_rows);
ss_.Free(cholmod_solution);
- const time_t final_time = time(NULL);
- VLOG(2) << "time: " << (final_time - start_time)
- << " lhs : " << (lhs_time - start_time)
- << " rhs: " << (rhs_time - lhs_time)
- << " analyze: " << (symbolic_time - rhs_time)
- << " factor_and_solve: " << (solve_time - symbolic_time)
- << " cleanup: " << (final_time - solve_time);
return true;
}
#else
diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h b/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h
index ea1b3184c33..7e98f316255 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h
@@ -33,6 +33,7 @@
#include <set>
#include <utility>
+#include <vector>
#include "ceres/block_random_access_matrix.h"
#include "ceres/block_sparse_matrix.h"
@@ -97,13 +98,14 @@ class BlockSparseMatrixBase;
// The two solvers can be instantiated by calling
// LinearSolver::CreateLinearSolver with LinearSolver::Options::type
// set to DENSE_SCHUR and SPARSE_SCHUR
-// respectively. LinearSolver::Options::num_eliminate_blocks should be
+// respectively. LinearSolver::Options::elimination_groups[0] should be
// at least 1.
class SchurComplementSolver : public BlockSparseMatrixBaseSolver {
public:
explicit SchurComplementSolver(const LinearSolver::Options& options)
: options_(options) {
- CHECK_GT(options.num_eliminate_blocks, 0);
+ CHECK_GT(options.elimination_groups.size(), 1);
+ CHECK_GT(options.elimination_groups[0], 0);
}
// LinearSolver methods
diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator_impl.h b/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator_impl.h
index 6120db9b009..339c44bc41c 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator_impl.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator_impl.h
@@ -50,7 +50,6 @@
#include <algorithm>
#include <map>
-#include <glog/logging.h>
#include "Eigen/Dense"
#include "ceres/block_random_access_matrix.h"
#include "ceres/block_sparse_matrix.h"
@@ -60,6 +59,7 @@
#include "ceres/stl_util.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/scoped_ptr.h"
+#include "glog/logging.h"
namespace ceres {
namespace internal {
diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.cc b/extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.cc
new file mode 100644
index 00000000000..33a666ed037
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.cc
@@ -0,0 +1,145 @@
+// 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)
+
+#include "ceres/schur_jacobi_preconditioner.h"
+
+#include <utility>
+#include <vector>
+#include "Eigen/Dense"
+#include "ceres/block_random_access_sparse_matrix.h"
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/collections_port.h"
+#include "ceres/detect_structure.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/linear_solver.h"
+#include "ceres/schur_eliminator.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+SchurJacobiPreconditioner::SchurJacobiPreconditioner(
+ const CompressedRowBlockStructure& bs,
+ const Preconditioner::Options& options)
+ : options_(options) {
+ CHECK_GT(options_.elimination_groups.size(), 1);
+ CHECK_GT(options_.elimination_groups[0], 0);
+ const int num_blocks = bs.cols.size() - options_.elimination_groups[0];
+ CHECK_GT(num_blocks, 0)
+ << "Jacobian should have atleast 1 f_block for "
+ << "SCHUR_JACOBI preconditioner.";
+
+ block_size_.resize(num_blocks);
+ set<pair<int, int> > block_pairs;
+
+ int num_block_diagonal_entries = 0;
+ for (int i = 0; i < num_blocks; ++i) {
+ block_size_[i] = bs.cols[i + options_.elimination_groups[0]].size;
+ block_pairs.insert(make_pair(i, i));
+ num_block_diagonal_entries += block_size_[i] * block_size_[i];
+ }
+
+ m_.reset(new BlockRandomAccessSparseMatrix(block_size_, block_pairs));
+ InitEliminator(bs);
+}
+
+SchurJacobiPreconditioner::~SchurJacobiPreconditioner() {
+}
+
+// Initialize the SchurEliminator.
+void SchurJacobiPreconditioner::InitEliminator(
+ const CompressedRowBlockStructure& bs) {
+ LinearSolver::Options eliminator_options;
+
+ eliminator_options.elimination_groups = options_.elimination_groups;
+ eliminator_options.num_threads = options_.num_threads;
+
+ DetectStructure(bs, options_.elimination_groups[0],
+ &eliminator_options.row_block_size,
+ &eliminator_options.e_block_size,
+ &eliminator_options.f_block_size);
+
+ eliminator_.reset(SchurEliminatorBase::Create(eliminator_options));
+ eliminator_->Init(options_.elimination_groups[0], &bs);
+}
+
+// Update the values of the preconditioner matrix and factorize it.
+bool SchurJacobiPreconditioner::Update(const BlockSparseMatrixBase& A,
+ const double* D) {
+ const int num_rows = m_->num_rows();
+ CHECK_GT(num_rows, 0);
+
+ // We need a dummy rhs vector and a dummy b vector since the Schur
+ // eliminator combines the computation of the reduced camera matrix
+ // with the computation of the right hand side of that linear
+ // system.
+ //
+ // TODO(sameeragarwal): Perhaps its worth refactoring the
+ // SchurEliminator::Eliminate function to allow NULL for the rhs. As
+ // of now it does not seem to be worth the effort.
+ Vector rhs = Vector::Zero(m_->num_rows());
+ Vector b = Vector::Zero(A.num_rows());
+
+ // Compute a subset of the entries of the Schur complement.
+ eliminator_->Eliminate(&A, b.data(), D, m_.get(), rhs.data());
+ return true;
+}
+
+void SchurJacobiPreconditioner::RightMultiply(const double* x,
+ double* y) const {
+ CHECK_NOTNULL(x);
+ CHECK_NOTNULL(y);
+
+ const double* lhs_values =
+ down_cast<BlockRandomAccessSparseMatrix*>(m_.get())->matrix()->values();
+
+ // This loop can be easily multi-threaded with OpenMP if need be.
+ for (int i = 0; i < block_size_.size(); ++i) {
+ const int block_size = block_size_[i];
+ ConstMatrixRef block(lhs_values, block_size, block_size);
+
+ VectorRef(y, block_size) =
+ block
+ .selfadjointView<Eigen::Upper>()
+ .ldlt()
+ .solve(ConstVectorRef(x, block_size));
+
+ x += block_size;
+ y += block_size;
+ lhs_values += block_size * block_size;
+ }
+}
+
+int SchurJacobiPreconditioner::num_rows() const {
+ return m_->num_rows();
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.h b/extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.h
new file mode 100644
index 00000000000..3addd73abd2
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.h
@@ -0,0 +1,110 @@
+// 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)
+//
+// Detailed descriptions of these preconditions beyond what is
+// documented here can be found in
+//
+// Bundle Adjustment in the Large
+// S. Agarwal, N. Snavely, S. Seitz & R. Szeliski, ECCV 2010
+// http://www.cs.washington.edu/homes/sagarwal/bal.pdf
+
+#ifndef CERES_INTERNAL_SCHUR_JACOBI_PRECONDITIONER_H_
+#define CERES_INTERNAL_SCHUR_JACOBI_PRECONDITIONER_H_
+
+#include <set>
+#include <vector>
+#include <utility>
+#include "ceres/collections_port.h"
+#include "ceres/internal/macros.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/preconditioner.h"
+
+namespace ceres {
+namespace internal {
+
+class BlockRandomAccessSparseMatrix;
+class BlockSparseMatrixBase;
+struct CompressedRowBlockStructure;
+class SchurEliminatorBase;
+
+// This class implements the SCHUR_JACOBI preconditioner for Structure
+// from Motion/Bundle Adjustment problems. Full mathematical details
+// can be found in
+//
+// Bundle Adjustment in the Large
+// S. Agarwal, N. Snavely, S. Seitz & R. Szeliski, ECCV 2010
+// http://www.cs.washington.edu/homes/sagarwal/bal.pdf
+//
+// Example usage:
+//
+// Preconditioner::Options options;
+// options.preconditioner_type = SCHUR_JACOBI;
+// options.elimination_groups.push_back(num_points);
+// options.elimination_groups.push_back(num_cameras);
+// SchurJacobiPreconditioner preconditioner(
+// *A.block_structure(), options);
+// preconditioner.Update(A, NULL);
+// preconditioner.RightMultiply(x, y);
+//
+class SchurJacobiPreconditioner : public Preconditioner {
+ public:
+ // Initialize the symbolic structure of the preconditioner. bs is
+ // the block structure of the linear system to be solved. It is used
+ // to determine the sparsity structure of the preconditioner matrix.
+ //
+ // It has the same structural requirement as other Schur complement
+ // based solvers. Please see schur_eliminator.h for more details.
+ SchurJacobiPreconditioner(const CompressedRowBlockStructure& bs,
+ const Preconditioner::Options& options);
+ virtual ~SchurJacobiPreconditioner();
+
+ // Preconditioner interface.
+ virtual bool Update(const BlockSparseMatrixBase& A, const double* D);
+ virtual void RightMultiply(const double* x, double* y) const;
+ virtual int num_rows() const;
+
+ private:
+ void InitEliminator(const CompressedRowBlockStructure& bs);
+
+ Preconditioner::Options options_;
+
+ // Sizes of the blocks in the schur complement.
+ vector<int> block_size_;
+ scoped_ptr<SchurEliminatorBase> eliminator_;
+
+ // Preconditioner matrix.
+ scoped_ptr<BlockRandomAccessSparseMatrix> m_;
+ CERES_DISALLOW_COPY_AND_ASSIGN(SchurJacobiPreconditioner);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_SCHUR_JACOBI_PRECONDITIONER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/solver.cc b/extern/libmv/third_party/ceres/internal/ceres/solver.cc
index 66ca93283a1..6436d2df2a7 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/solver.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/solver.cc
@@ -37,20 +37,41 @@
#include "ceres/program.h"
#include "ceres/solver_impl.h"
#include "ceres/stringprintf.h"
+#include "ceres/wall_time.h"
namespace ceres {
+namespace {
+
+void StringifyOrdering(const vector<int>& ordering, string* report) {
+ if (ordering.size() == 0) {
+ internal::StringAppendF(report, "AUTOMATIC");
+ return;
+ }
+
+ for (int i = 0; i < ordering.size() - 1; ++i) {
+ internal::StringAppendF(report, "%d, ", ordering[i]);
+ }
+ internal::StringAppendF(report, "%d", ordering.back());
+}
+
+} // namespace
+
+Solver::Options::~Options() {
+ delete linear_solver_ordering;
+ delete inner_iteration_ordering;
+}
Solver::~Solver() {}
-// TODO(sameeragarwal): Use subsecond timers.
void Solver::Solve(const Solver::Options& options,
Problem* problem,
Solver::Summary* summary) {
- time_t start_time_seconds = time(NULL);
+ double start_time_seconds = internal::WallTimeInSeconds();
internal::ProblemImpl* problem_impl =
CHECK_NOTNULL(problem)->problem_impl_.get();
internal::SolverImpl::Solve(options, problem_impl, summary);
- summary->total_time_in_seconds = time(NULL) - start_time_seconds;
+ summary->total_time_in_seconds =
+ internal::WallTimeInSeconds() - start_time_seconds;
}
void Solve(const Solver::Options& options,
@@ -63,7 +84,8 @@ void Solve(const Solver::Options& options,
Solver::Summary::Summary()
// Invalid values for most fields, to ensure that we are not
// accidentally reporting default values.
- : termination_type(DID_NOT_RUN),
+ : minimizer_type(TRUST_REGION),
+ termination_type(DID_NOT_RUN),
initial_cost(-1.0),
final_cost(-1.0),
fixed_cost(-1.0),
@@ -73,6 +95,9 @@ Solver::Summary::Summary()
minimizer_time_in_seconds(-1.0),
postprocessor_time_in_seconds(-1.0),
total_time_in_seconds(-1.0),
+ linear_solver_time_in_seconds(-1.0),
+ residual_evaluation_time_in_seconds(-1.0),
+ jacobian_evaluation_time_in_seconds(-1.0),
num_parameter_blocks(-1),
num_parameters(-1),
num_residual_blocks(-1),
@@ -81,8 +106,6 @@ Solver::Summary::Summary()
num_parameters_reduced(-1),
num_residual_blocks_reduced(-1),
num_residuals_reduced(-1),
- num_eliminate_blocks_given(-1),
- num_eliminate_blocks_used(-1),
num_threads_given(-1),
num_threads_used(-1),
num_linear_solver_threads_given(-1),
@@ -90,9 +113,11 @@ Solver::Summary::Summary()
linear_solver_type_given(SPARSE_NORMAL_CHOLESKY),
linear_solver_type_used(SPARSE_NORMAL_CHOLESKY),
preconditioner_type(IDENTITY),
- ordering_type(NATURAL),
trust_region_strategy_type(LEVENBERG_MARQUARDT),
- sparse_linear_algebra_library(SUITE_SPARSE) {
+ inner_iterations(false),
+ sparse_linear_algebra_library(SUITE_SPARSE),
+ line_search_direction_type(LBFGS),
+ line_search_type(ARMIJO) {
}
string Solver::Summary::BriefReport() const {
@@ -121,6 +146,8 @@ string Solver::Summary::BriefReport() const {
return report;
};
+using internal::StringAppendF;
+
string Solver::Summary::FullReport() const {
string report =
"\n"
@@ -128,124 +155,210 @@ string Solver::Summary::FullReport() const {
"-------------------\n";
if (termination_type == DID_NOT_RUN) {
- internal::StringAppendF(&report, " Original\n");
- internal::StringAppendF(&report, "Parameter blocks % 10d\n",
- num_parameter_blocks);
- internal::StringAppendF(&report, "Parameters % 10d\n",
- num_parameters);
- internal::StringAppendF(&report, "Residual blocks % 10d\n",
- num_residual_blocks);
- internal::StringAppendF(&report, "Residuals % 10d\n\n",
- num_residuals);
+ StringAppendF(&report, " Original\n");
+ StringAppendF(&report, "Parameter blocks % 10d\n",
+ num_parameter_blocks);
+ StringAppendF(&report, "Parameters % 10d\n",
+ num_parameters);
+ StringAppendF(&report, "Residual blocks % 10d\n",
+ num_residual_blocks);
+ StringAppendF(&report, "Residuals % 10d\n\n",
+ num_residuals);
} else {
- internal::StringAppendF(&report, "%45s %21s\n", "Original", "Reduced");
- internal::StringAppendF(&report, "Parameter blocks % 25d% 25d\n",
- num_parameter_blocks, num_parameter_blocks_reduced);
- internal::StringAppendF(&report, "Parameters % 25d% 25d\n",
- num_parameters, num_parameters_reduced);
- internal::StringAppendF(&report, "Residual blocks % 25d% 25d\n",
- num_residual_blocks, num_residual_blocks_reduced);
- internal::StringAppendF(&report, "Residual % 25d% 25d\n\n",
- num_residuals, num_residuals_reduced);
+ StringAppendF(&report, "%45s %21s\n", "Original", "Reduced");
+ StringAppendF(&report, "Parameter blocks % 25d% 25d\n",
+ num_parameter_blocks, num_parameter_blocks_reduced);
+ StringAppendF(&report, "Parameters % 25d% 25d\n",
+ num_parameters, num_parameters_reduced);
+ StringAppendF(&report, "Residual blocks % 25d% 25d\n",
+ num_residual_blocks, num_residual_blocks_reduced);
+ StringAppendF(&report, "Residual % 25d% 25d\n",
+ num_residuals, num_residuals_reduced);
}
- internal::StringAppendF(&report, "%45s %21s\n", "Given", "Used");
- internal::StringAppendF(&report, "Linear solver %25s%25s\n",
- LinearSolverTypeToString(linear_solver_type_given),
- LinearSolverTypeToString(linear_solver_type_used));
+ // TODO(sameeragarwal): Refactor this into separate functions.
- if (linear_solver_type_given == CGNR ||
- linear_solver_type_given == ITERATIVE_SCHUR) {
- internal::StringAppendF(&report, "Preconditioner %25s%25s\n",
- PreconditionerTypeToString(preconditioner_type),
- PreconditionerTypeToString(preconditioner_type));
- } else {
- internal::StringAppendF(&report, "Preconditioner %25s%25s\n",
- "N/A", "N/A");
- }
+ if (minimizer_type == TRUST_REGION) {
+ StringAppendF(&report, "\nMinimizer %19s\n",
+ "TRUST_REGION");
+ if (linear_solver_type_used == SPARSE_NORMAL_CHOLESKY ||
+ linear_solver_type_used == SPARSE_SCHUR ||
+ (linear_solver_type_used == ITERATIVE_SCHUR &&
+ (preconditioner_type == CLUSTER_JACOBI ||
+ preconditioner_type == CLUSTER_TRIDIAGONAL))) {
+ StringAppendF(&report, "\nSparse Linear Algebra Library %15s\n",
+ SparseLinearAlgebraLibraryTypeToString(
+ sparse_linear_algebra_library));
+ }
- internal::StringAppendF(&report, "Ordering %25s%25s\n",
- OrderingTypeToString(ordering_type),
- OrderingTypeToString(ordering_type));
+ StringAppendF(&report, "Trust Region Strategy %19s",
+ TrustRegionStrategyTypeToString(
+ trust_region_strategy_type));
+ if (trust_region_strategy_type == DOGLEG) {
+ if (dogleg_type == TRADITIONAL_DOGLEG) {
+ StringAppendF(&report, " (TRADITIONAL)");
+ } else {
+ StringAppendF(&report, " (SUBSPACE)");
+ }
+ }
+ StringAppendF(&report, "\n");
+ StringAppendF(&report, "\n");
+
+ StringAppendF(&report, "%45s %21s\n", "Given", "Used");
+ StringAppendF(&report, "Linear solver %25s%25s\n",
+ LinearSolverTypeToString(linear_solver_type_given),
+ LinearSolverTypeToString(linear_solver_type_used));
- if (IsSchurType(linear_solver_type_given)) {
- if (ordering_type == SCHUR) {
- internal::StringAppendF(&report, "num_eliminate_blocks%25s% 25d\n",
- "N/A",
- num_eliminate_blocks_used);
+ if (linear_solver_type_given == CGNR ||
+ linear_solver_type_given == ITERATIVE_SCHUR) {
+ StringAppendF(&report, "Preconditioner %25s%25s\n",
+ PreconditionerTypeToString(preconditioner_type),
+ PreconditionerTypeToString(preconditioner_type));
} else {
- internal::StringAppendF(&report, "num_eliminate_blocks% 25d% 25d\n",
- num_eliminate_blocks_given,
- num_eliminate_blocks_used);
+ StringAppendF(&report, "Preconditioner %25s%25s\n",
+ "N/A", "N/A");
}
- }
- internal::StringAppendF(&report, "Threads: % 25d% 25d\n",
- num_threads_given, num_threads_used);
- internal::StringAppendF(&report, "Linear solver threads % 23d% 25d\n",
- num_linear_solver_threads_given,
- num_linear_solver_threads_used);
-
- if (linear_solver_type_used == SPARSE_NORMAL_CHOLESKY ||
- linear_solver_type_used == SPARSE_SCHUR ||
- (linear_solver_type_used == ITERATIVE_SCHUR &&
- (preconditioner_type == SCHUR_JACOBI ||
- preconditioner_type == CLUSTER_JACOBI ||
- preconditioner_type == CLUSTER_TRIDIAGONAL))) {
- internal::StringAppendF(&report, "\nSparse Linear Algebra Library %15s\n",
- SparseLinearAlgebraLibraryTypeToString(
- sparse_linear_algebra_library));
- }
+ StringAppendF(&report, "Threads: % 25d% 25d\n",
+ num_threads_given, num_threads_used);
+ StringAppendF(&report, "Linear solver threads % 23d% 25d\n",
+ num_linear_solver_threads_given,
+ num_linear_solver_threads_used);
+
+ if (IsSchurType(linear_solver_type_used)) {
+ string given;
+ StringifyOrdering(linear_solver_ordering_given, &given);
+ string used;
+ StringifyOrdering(linear_solver_ordering_used, &used);
+ StringAppendF(&report,
+ "Linear solver ordering %22s %24s\n",
+ given.c_str(),
+ used.c_str());
+ }
+
+ if (inner_iterations) {
+ string given;
+ StringifyOrdering(inner_iteration_ordering_given, &given);
+ string used;
+ StringifyOrdering(inner_iteration_ordering_used, &used);
+ StringAppendF(&report,
+ "Inner iteration ordering %20s %24s\n",
+ given.c_str(),
+ used.c_str());
+ }
+
+ if (termination_type == DID_NOT_RUN) {
+ CHECK(!error.empty())
+ << "Solver terminated with DID_NOT_RUN but the solver did not "
+ << "return a reason. This is a Ceres error. Please report this "
+ << "to the Ceres team";
+ StringAppendF(&report, "Termination: %20s\n",
+ "DID_NOT_RUN");
+ StringAppendF(&report, "Reason: %s\n", error.c_str());
+ return report;
+ }
+
+ StringAppendF(&report, "\nCost:\n");
+ StringAppendF(&report, "Initial % 30e\n", initial_cost);
+ if (termination_type != NUMERICAL_FAILURE &&
+ termination_type != USER_ABORT) {
+ StringAppendF(&report, "Final % 30e\n", final_cost);
+ StringAppendF(&report, "Change % 30e\n",
+ initial_cost - final_cost);
+ }
+
+ StringAppendF(&report, "\nNumber of iterations:\n");
+ StringAppendF(&report, "Successful % 20d\n",
+ num_successful_steps);
+ StringAppendF(&report, "Unsuccessful % 20d\n",
+ num_unsuccessful_steps);
+ StringAppendF(&report, "Total % 20d\n",
+ num_successful_steps + num_unsuccessful_steps);
+
+ StringAppendF(&report, "\nTime (in seconds):\n");
+ StringAppendF(&report, "Preprocessor %25.3f\n",
+ preprocessor_time_in_seconds);
+ StringAppendF(&report, "\n Residual Evaluations %22.3f\n",
+ residual_evaluation_time_in_seconds);
+ StringAppendF(&report, " Jacobian Evaluations %22.3f\n",
+ jacobian_evaluation_time_in_seconds);
+ StringAppendF(&report, " Linear Solver %23.3f\n",
+ linear_solver_time_in_seconds);
+ StringAppendF(&report, "Minimizer %25.3f\n\n",
+ minimizer_time_in_seconds);
+
+ StringAppendF(&report, "Postprocessor %24.3f\n",
+ postprocessor_time_in_seconds);
- internal::StringAppendF(&report, "Trust Region Strategy %19s",
- TrustRegionStrategyTypeToString(
- trust_region_strategy_type));
- if (trust_region_strategy_type == DOGLEG) {
- if (dogleg_type == TRADITIONAL_DOGLEG) {
- internal::StringAppendF(&report, " (TRADITIONAL)");
+ StringAppendF(&report, "Total %25.3f\n\n",
+ total_time_in_seconds);
+
+ StringAppendF(&report, "Termination: %25s\n",
+ SolverTerminationTypeToString(termination_type));
+ } else {
+ // LINE_SEARCH
+ StringAppendF(&report, "\nMinimizer %19s\n", "LINE_SEARCH");
+ if (line_search_direction_type == LBFGS) {
+ StringAppendF(&report, "Line search direction %19s(%d)\n",
+ LineSearchDirectionTypeToString(line_search_direction_type),
+ max_lbfgs_rank);
} else {
- internal::StringAppendF(&report, " (SUBSPACE)");
+ StringAppendF(&report, "Line search direction %19s\n",
+ LineSearchDirectionTypeToString(
+ line_search_direction_type));
}
- }
- internal::StringAppendF(&report, "\n");
+ StringAppendF(&report, "Line search type %19s\n",
+ LineSearchTypeToString(line_search_type));
+ StringAppendF(&report, "\n");
- if (termination_type == DID_NOT_RUN) {
- CHECK(!error.empty())
- << "Solver terminated with DID_NOT_RUN but the solver did not "
- << "return a reason. This is a Ceres error. Please report this "
- << "to the Ceres team";
- internal::StringAppendF(&report, "Termination: %20s\n",
- "DID_NOT_RUN");
- internal::StringAppendF(&report, "Reason: %s\n", error.c_str());
- return report;
- }
+ StringAppendF(&report, "%45s %21s\n", "Given", "Used");
+ StringAppendF(&report, "Threads: % 25d% 25d\n",
+ num_threads_given, num_threads_used);
- internal::StringAppendF(&report, "\nCost:\n");
- internal::StringAppendF(&report, "Initial % 30e\n", initial_cost);
- if (termination_type != NUMERICAL_FAILURE && termination_type != USER_ABORT) {
- internal::StringAppendF(&report, "Final % 30e\n", final_cost);
- internal::StringAppendF(&report, "Change % 30e\n",
- initial_cost - final_cost);
+ if (termination_type == DID_NOT_RUN) {
+ CHECK(!error.empty())
+ << "Solver terminated with DID_NOT_RUN but the solver did not "
+ << "return a reason. This is a Ceres error. Please report this "
+ << "to the Ceres team";
+ StringAppendF(&report, "Termination: %20s\n",
+ "DID_NOT_RUN");
+ StringAppendF(&report, "Reason: %s\n", error.c_str());
+ return report;
+ }
+
+ StringAppendF(&report, "\nCost:\n");
+ StringAppendF(&report, "Initial % 30e\n", initial_cost);
+ if (termination_type != NUMERICAL_FAILURE &&
+ termination_type != USER_ABORT) {
+ StringAppendF(&report, "Final % 30e\n", final_cost);
+ StringAppendF(&report, "Change % 30e\n",
+ initial_cost - final_cost);
+ }
+
+ StringAppendF(&report, "\nNumber of iterations: % 20ld\n",
+ iterations.size() - 1);
+
+ StringAppendF(&report, "\nTime (in seconds):\n");
+ StringAppendF(&report, "Preprocessor %25.3f\n",
+ preprocessor_time_in_seconds);
+ StringAppendF(&report, "\n Residual Evaluations %22.3f\n",
+ residual_evaluation_time_in_seconds);
+ StringAppendF(&report, " Jacobian Evaluations %22.3f\n",
+ jacobian_evaluation_time_in_seconds);
+ StringAppendF(&report, "Minimizer %25.3f\n\n",
+ minimizer_time_in_seconds);
+
+ StringAppendF(&report, "Postprocessor %24.3f\n",
+ postprocessor_time_in_seconds);
+
+ StringAppendF(&report, "Total %25.3f\n\n",
+ total_time_in_seconds);
+
+ StringAppendF(&report, "Termination: %25s\n",
+ SolverTerminationTypeToString(termination_type));
}
- internal::StringAppendF(&report, "\nNumber of iterations:\n");
- internal::StringAppendF(&report, "Successful % 20d\n",
- num_successful_steps);
- internal::StringAppendF(&report, "Unsuccessful % 20d\n",
- num_unsuccessful_steps);
- internal::StringAppendF(&report, "Total % 20d\n",
- num_successful_steps + num_unsuccessful_steps);
- internal::StringAppendF(&report, "\nTime (in seconds):\n");
- internal::StringAppendF(&report, "Preprocessor % 25e\n",
- preprocessor_time_in_seconds);
- internal::StringAppendF(&report, "Minimizer % 25e\n",
- minimizer_time_in_seconds);
- internal::StringAppendF(&report, "Total % 25e\n",
- total_time_in_seconds);
-
- internal::StringAppendF(&report, "Termination: %25s\n",
- SolverTerminationTypeToString(termination_type));
return report;
};
diff --git a/extern/libmv/third_party/ceres/internal/ceres/solver_impl.cc b/extern/libmv/third_party/ceres/internal/ceres/solver_impl.cc
index 8ef5b98e35f..5bcfdc6312f 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/solver_impl.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/solver_impl.cc
@@ -33,21 +33,25 @@
#include <cstdio>
#include <iostream> // NOLINT
#include <numeric>
+#include "ceres/coordinate_descent_minimizer.h"
#include "ceres/evaluator.h"
#include "ceres/gradient_checking_cost_function.h"
#include "ceres/iteration_callback.h"
#include "ceres/levenberg_marquardt_strategy.h"
#include "ceres/linear_solver.h"
+#include "ceres/line_search_minimizer.h"
#include "ceres/map_util.h"
#include "ceres/minimizer.h"
+#include "ceres/ordered_groups.h"
#include "ceres/parameter_block.h"
+#include "ceres/parameter_block_ordering.h"
#include "ceres/problem.h"
#include "ceres/problem_impl.h"
#include "ceres/program.h"
#include "ceres/residual_block.h"
-#include "ceres/schur_ordering.h"
#include "ceres/stringprintf.h"
#include "ceres/trust_region_minimizer.h"
+#include "ceres/wall_time.h"
namespace ceres {
namespace internal {
@@ -73,14 +77,24 @@ class StateUpdatingCallback : public IterationCallback {
double* parameters_;
};
+void SetSummaryFinalCost(Solver::Summary* summary) {
+ summary->final_cost = summary->initial_cost;
+ // We need the loop here, instead of just looking at the last
+ // iteration because the minimizer maybe making non-monotonic steps.
+ for (int i = 0; i < summary->iterations.size(); ++i) {
+ const IterationSummary& iteration_summary = summary->iterations[i];
+ summary->final_cost = min(iteration_summary.cost, summary->final_cost);
+ }
+}
+
// 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 {
+class TrustRegionLoggingCallback : public IterationCallback {
public:
- explicit LoggingCallback(bool log_to_stdout)
+ explicit TrustRegionLoggingCallback(bool log_to_stdout)
: log_to_stdout_(log_to_stdout) {}
- ~LoggingCallback() {}
+ ~TrustRegionLoggingCallback() {}
CallbackReturnType operator()(const IterationSummary& summary) {
const char* kReportRowFormat =
@@ -109,6 +123,42 @@ class LoggingCallback : public IterationCallback {
const bool log_to_stdout_;
};
+// Callback for logging the state of the minimizer to STDERR or STDOUT
+// depending on the user's preferences and logging level.
+class LineSearchLoggingCallback : public IterationCallback {
+ public:
+ explicit LineSearchLoggingCallback(bool log_to_stdout)
+ : log_to_stdout_(log_to_stdout) {}
+
+ ~LineSearchLoggingCallback() {}
+
+ CallbackReturnType operator()(const IterationSummary& summary) {
+ 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";
+ string 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);
+ if (log_to_stdout_) {
+ cout << output << endl;
+ } else {
+ VLOG(1) << output;
+ }
+ return SOLVER_CONTINUE;
+ }
+
+ private:
+ const bool log_to_stdout_;
+};
+
+
// Basic callback to record the execution of the solver to a file for
// offline analysis.
class FileLoggingCallback : public IterationCallback {
@@ -137,14 +187,34 @@ class FileLoggingCallback : public IterationCallback {
FILE* fptr_;
};
+// Iterate over each of the groups in order of their priority and fill
+// summary with their sizes.
+void SummarizeOrdering(ParameterBlockOrdering* ordering,
+ vector<int>* summary) {
+ CHECK_NOTNULL(summary)->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) {
+ summary->push_back(it->second.size());
+ }
+}
+
} // namespace
-void SolverImpl::Minimize(const Solver::Options& options,
- Program* program,
- Evaluator* evaluator,
- LinearSolver* linear_solver,
- double* parameters,
- Solver::Summary* summary) {
+void SolverImpl::TrustRegionMinimize(
+ const Solver::Options& options,
+ Program* program,
+ CoordinateDescentMinimizer* inner_iteration_minimizer,
+ Evaluator* evaluator,
+ LinearSolver* linear_solver,
+ double* parameters,
+ Solver::Summary* summary) {
Minimizer::Options minimizer_options(options);
// TODO(sameeragarwal): Add support for logging the configuration
@@ -156,7 +226,8 @@ void SolverImpl::Minimize(const Solver::Options& options,
file_logging_callback.get());
}
- LoggingCallback logging_callback(options.minimizer_progress_to_stdout);
+ TrustRegionLoggingCallback logging_callback(
+ options.minimizer_progress_to_stdout);
if (options.logging_type != SILENT) {
minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
&logging_callback);
@@ -172,7 +243,9 @@ void SolverImpl::Minimize(const Solver::Options& options,
minimizer_options.evaluator = evaluator;
scoped_ptr<SparseMatrix> jacobian(evaluator->CreateJacobian());
+
minimizer_options.jacobian = jacobian.get();
+ minimizer_options.inner_iteration_minimizer = inner_iteration_minimizer;
TrustRegionStrategy::Options trust_region_strategy_options;
trust_region_strategy_options.linear_solver = linear_solver;
@@ -189,78 +262,140 @@ void SolverImpl::Minimize(const Solver::Options& options,
minimizer_options.trust_region_strategy = strategy.get();
TrustRegionMinimizer minimizer;
- time_t minimizer_start_time = time(NULL);
+ double minimizer_start_time = WallTimeInSeconds();
minimizer.Minimize(minimizer_options, parameters, summary);
- summary->minimizer_time_in_seconds = time(NULL) - minimizer_start_time;
+ summary->minimizer_time_in_seconds =
+ WallTimeInSeconds() - minimizer_start_time;
}
-void SolverImpl::Solve(const Solver::Options& original_options,
- ProblemImpl* original_problem_impl,
+
+void SolverImpl::LineSearchMinimize(
+ const Solver::Options& options,
+ Program* program,
+ Evaluator* evaluator,
+ double* parameters,
+ Solver::Summary* summary) {
+ Minimizer::Options minimizer_options(options);
+
+ // TODO(sameeragarwal): Add support for logging the configuration
+ // and more detailed stats.
+ scoped_ptr<IterationCallback> file_logging_callback;
+ if (!options.solver_log.empty()) {
+ file_logging_callback.reset(new FileLoggingCallback(options.solver_log));
+ minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
+ file_logging_callback.get());
+ }
+
+ LineSearchLoggingCallback logging_callback(
+ options.minimizer_progress_to_stdout);
+ if (options.logging_type != SILENT) {
+ minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
+ &logging_callback);
+ }
+
+ StateUpdatingCallback updating_callback(program, parameters);
+ if (options.update_state_every_iteration) {
+ // 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(),
+ &updating_callback);
+ }
+
+ minimizer_options.evaluator = evaluator;
+
+ LineSearchMinimizer minimizer;
+ double minimizer_start_time = WallTimeInSeconds();
+ minimizer.Minimize(minimizer_options, parameters, summary);
+ summary->minimizer_time_in_seconds =
+ WallTimeInSeconds() - minimizer_start_time;
+}
+
+void SolverImpl::Solve(const Solver::Options& options,
+ ProblemImpl* problem_impl,
Solver::Summary* summary) {
- time_t solver_start_time = time(NULL);
- Solver::Options options(original_options);
+ if (options.minimizer_type == TRUST_REGION) {
+ TrustRegionSolve(options, problem_impl, summary);
+ } else {
+ LineSearchSolve(options, problem_impl, summary);
+ }
+}
+
+void SolverImpl::TrustRegionSolve(const Solver::Options& original_options,
+ ProblemImpl* original_problem_impl,
+ Solver::Summary* summary) {
+ EventLogger event_logger("TrustRegionSolve");
+ double solver_start_time = WallTimeInSeconds();
+
Program* original_program = original_problem_impl->mutable_program();
ProblemImpl* problem_impl = original_problem_impl;
+
// Reset the summary object to its default values.
*CHECK_NOTNULL(summary) = Solver::Summary();
+ summary->minimizer_type = TRUST_REGION;
+ summary->num_parameter_blocks = problem_impl->NumParameterBlocks();
+ summary->num_parameters = problem_impl->NumParameters();
+ summary->num_residual_blocks = problem_impl->NumResidualBlocks();
+ summary->num_residuals = problem_impl->NumResiduals();
+
+ // Empty programs are usually a user error.
+ if (summary->num_parameter_blocks == 0) {
+ summary->error = "Problem contains no parameter blocks.";
+ LOG(ERROR) << summary->error;
+ return;
+ }
+
+ if (summary->num_residual_blocks == 0) {
+ summary->error = "Problem contains no residual blocks.";
+ LOG(ERROR) << summary->error;
+ return;
+ }
+
+ SummarizeOrdering(original_options.linear_solver_ordering,
+ &(summary->linear_solver_ordering_given));
+
+ SummarizeOrdering(original_options.inner_iteration_ordering,
+ &(summary->inner_iteration_ordering_given));
+
+ Solver::Options options(original_options);
+ options.linear_solver_ordering = NULL;
+ options.inner_iteration_ordering = NULL;
#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"
+ << "only options.num_threads=1 is supported. Switching "
<< "to single threaded mode.";
options.num_threads = 1;
}
if (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"
+ << "only options.num_linear_solver_threads=1 is supported. Switching "
<< "to single threaded mode.";
options.num_linear_solver_threads = 1;
}
#endif
- summary->linear_solver_type_given = options.linear_solver_type;
- summary->num_eliminate_blocks_given = original_options.num_eliminate_blocks;
summary->num_threads_given = original_options.num_threads;
- summary->num_linear_solver_threads_given =
- original_options.num_linear_solver_threads;
- summary->ordering_type = original_options.ordering_type;
+ summary->num_threads_used = options.num_threads;
- summary->num_parameter_blocks = problem_impl->NumParameterBlocks();
- summary->num_parameters = problem_impl->NumParameters();
- summary->num_residual_blocks = problem_impl->NumResidualBlocks();
- summary->num_residuals = problem_impl->NumResiduals();
+ if (options.lsqp_iterations_to_dump.size() > 0) {
+ LOG(WARNING) << "Dumping linear least squares problems to disk is"
+ " currently broken. Ignoring Solver::Options::lsqp_iterations_to_dump";
+ }
- summary->num_threads_used = options.num_threads;
- summary->sparse_linear_algebra_library =
- options.sparse_linear_algebra_library;
- summary->trust_region_strategy_type = options.trust_region_strategy_type;
- summary->dogleg_type = options.dogleg_type;
+ event_logger.AddEvent("Init");
- // Evaluate the initial cost, residual vector and the jacobian
- // matrix if requested by the user. The initial cost needs to be
- // computed on the original unpreprocessed problem, as it is used to
- // determine the value of the "fixed" part of the objective function
- // after the problem has undergone reduction.
- Evaluator::Evaluate(
- original_program,
- options.num_threads,
- &(summary->initial_cost),
- options.return_initial_residuals ? &summary->initial_residuals : NULL,
- options.return_initial_gradient ? &summary->initial_gradient : NULL,
- options.return_initial_jacobian ? &summary->initial_jacobian : NULL);
- original_program->SetParameterBlockStatePtrsToUserStatePtrs();
+ original_program->SetParameterBlockStatePtrsToUserStatePtrs();
+ event_logger.AddEvent("SetParameterBlockPtrs");
// If the user requests gradient checking, construct a new
// ProblemImpl by wrapping the CostFunctions of problem_impl inside
// GradientCheckingCostFunction and replacing problem_impl with
// gradient_checking_problem_impl.
scoped_ptr<ProblemImpl> gradient_checking_problem_impl;
- // Save the original problem impl so we don't use the gradient
- // checking one when computing the residuals.
if (options.check_gradients) {
VLOG(1) << "Checking Gradients";
gradient_checking_problem_impl.reset(
@@ -269,45 +404,344 @@ void SolverImpl::Solve(const Solver::Options& original_options,
options.numeric_derivative_relative_step_size,
options.gradient_check_relative_precision));
- // From here on, problem_impl will point to the GradientChecking version.
+ // From here on, problem_impl will point to the gradient checking
+ // version.
problem_impl = gradient_checking_problem_impl.get();
}
+ if (original_options.linear_solver_ordering != NULL) {
+ if (!IsOrderingValid(original_options, problem_impl, &summary->error)) {
+ LOG(ERROR) << summary->error;
+ return;
+ }
+ event_logger.AddEvent("CheckOrdering");
+ options.linear_solver_ordering =
+ new ParameterBlockOrdering(*original_options.linear_solver_ordering);
+ event_logger.AddEvent("CopyOrdering");
+ } else {
+ options.linear_solver_ordering = new ParameterBlockOrdering;
+ const ProblemImpl::ParameterMap& parameter_map =
+ problem_impl->parameter_map();
+ for (ProblemImpl::ParameterMap::const_iterator it = parameter_map.begin();
+ it != parameter_map.end();
+ ++it) {
+ options.linear_solver_ordering->AddElementToGroup(it->first, 0);
+ }
+ event_logger.AddEvent("ConstructOrdering");
+ }
+
// Create the three objects needed to minimize: the transformed program, the
// evaluator, and the linear solver.
-
scoped_ptr<Program> reduced_program(CreateReducedProgram(&options,
problem_impl,
&summary->fixed_cost,
&summary->error));
+
+ event_logger.AddEvent("CreateReducedProgram");
if (reduced_program == NULL) {
return;
}
+ SummarizeOrdering(options.linear_solver_ordering,
+ &(summary->linear_solver_ordering_used));
+
summary->num_parameter_blocks_reduced = reduced_program->NumParameterBlocks();
summary->num_parameters_reduced = reduced_program->NumParameters();
summary->num_residual_blocks_reduced = reduced_program->NumResidualBlocks();
summary->num_residuals_reduced = reduced_program->NumResiduals();
+ if (summary->num_parameter_blocks_reduced == 0) {
+ summary->preprocessor_time_in_seconds =
+ WallTimeInSeconds() - solver_start_time;
+
+ double post_process_start_time = WallTimeInSeconds();
+ LOG(INFO) << "Terminating: FUNCTION_TOLERANCE reached. "
+ << "No non-constant parameter blocks found.";
+
+ summary->initial_cost = summary->fixed_cost;
+ summary->final_cost = summary->fixed_cost;
+
+ // FUNCTION_TOLERANCE is the right convergence here, as we know
+ // that the objective function is constant and cannot be changed
+ // any further.
+ summary->termination_type = FUNCTION_TOLERANCE;
+
+ // Ensure the program state is set to the user parameters on the way out.
+ original_program->SetParameterBlockStatePtrsToUserStatePtrs();
+
+ summary->postprocessor_time_in_seconds =
+ WallTimeInSeconds() - post_process_start_time;
+ return;
+ }
+
scoped_ptr<LinearSolver>
linear_solver(CreateLinearSolver(&options, &summary->error));
+ event_logger.AddEvent("CreateLinearSolver");
+ if (linear_solver == NULL) {
+ return;
+ }
+
+ summary->linear_solver_type_given = original_options.linear_solver_type;
summary->linear_solver_type_used = options.linear_solver_type;
+
summary->preconditioner_type = options.preconditioner_type;
- summary->num_eliminate_blocks_used = options.num_eliminate_blocks;
+
+ summary->num_linear_solver_threads_given =
+ original_options.num_linear_solver_threads;
summary->num_linear_solver_threads_used = options.num_linear_solver_threads;
- if (linear_solver == NULL) {
+ summary->sparse_linear_algebra_library =
+ options.sparse_linear_algebra_library;
+
+ summary->trust_region_strategy_type = options.trust_region_strategy_type;
+ summary->dogleg_type = options.dogleg_type;
+
+ // Only Schur types require the lexicographic reordering.
+ if (IsSchurType(options.linear_solver_type)) {
+ const int num_eliminate_blocks =
+ options.linear_solver_ordering
+ ->group_to_elements().begin()
+ ->second.size();
+ if (!LexicographicallyOrderResidualBlocks(num_eliminate_blocks,
+ reduced_program.get(),
+ &summary->error)) {
+ return;
+ }
+ }
+
+ scoped_ptr<Evaluator> evaluator(CreateEvaluator(options,
+ problem_impl->parameter_map(),
+ reduced_program.get(),
+ &summary->error));
+
+ event_logger.AddEvent("CreateEvaluator");
+
+ if (evaluator == NULL) {
+ return;
+ }
+
+ scoped_ptr<CoordinateDescentMinimizer> inner_iteration_minimizer;
+ if (options.use_inner_iterations) {
+ if (reduced_program->parameter_blocks().size() < 2) {
+ LOG(WARNING) << "Reduced problem only contains one parameter block."
+ << "Disabling inner iterations.";
+ } else {
+ inner_iteration_minimizer.reset(
+ CreateInnerIterationMinimizer(original_options,
+ *reduced_program,
+ problem_impl->parameter_map(),
+ summary));
+ if (inner_iteration_minimizer == NULL) {
+ LOG(ERROR) << summary->error;
+ return;
+ }
+ }
+ }
+
+ event_logger.AddEvent("CreateIIM");
+
+ // The optimizer works on contiguous parameter vectors; allocate some.
+ Vector parameters(reduced_program->NumParameters());
+
+ // Collect the discontiguous parameters into a contiguous state vector.
+ reduced_program->ParameterBlocksToStateVector(parameters.data());
+
+ Vector original_parameters = parameters;
+
+ double minimizer_start_time = WallTimeInSeconds();
+ summary->preprocessor_time_in_seconds =
+ minimizer_start_time - solver_start_time;
+
+ // Run the optimization.
+ TrustRegionMinimize(options,
+ reduced_program.get(),
+ inner_iteration_minimizer.get(),
+ evaluator.get(),
+ linear_solver.get(),
+ parameters.data(),
+ summary);
+ event_logger.AddEvent("Minimize");
+
+ SetSummaryFinalCost(summary);
+
+ // If the user aborted mid-optimization or the optimization
+ // terminated because of a numerical failure, then return without
+ // updating user state.
+ if (summary->termination_type == USER_ABORT ||
+ summary->termination_type == NUMERICAL_FAILURE) {
return;
}
- if (!MaybeReorderResidualBlocks(options,
- reduced_program.get(),
- &summary->error)) {
+ double post_process_start_time = WallTimeInSeconds();
+
+ // Push the contiguous optimized parameters back to the user's
+ // parameters.
+ reduced_program->StateVectorToParameterBlocks(parameters.data());
+ reduced_program->CopyParameterBlockStateToUserState();
+
+ // Ensure the program state is set to the user parameters on the way
+ // out.
+ original_program->SetParameterBlockStatePtrsToUserStatePtrs();
+
+ const map<string, double>& linear_solver_time_statistics =
+ linear_solver->TimeStatistics();
+ summary->linear_solver_time_in_seconds =
+ FindWithDefault(linear_solver_time_statistics,
+ "LinearSolver::Solve",
+ 0.0);
+
+ const map<string, double>& evaluator_time_statistics =
+ evaluator->TimeStatistics();
+
+ summary->residual_evaluation_time_in_seconds =
+ FindWithDefault(evaluator_time_statistics, "Evaluator::Residual", 0.0);
+ summary->jacobian_evaluation_time_in_seconds =
+ FindWithDefault(evaluator_time_statistics, "Evaluator::Jacobian", 0.0);
+
+ // Stick a fork in it, we're done.
+ summary->postprocessor_time_in_seconds =
+ WallTimeInSeconds() - post_process_start_time;
+ event_logger.AddEvent("PostProcess");
+}
+
+void SolverImpl::LineSearchSolve(const Solver::Options& original_options,
+ ProblemImpl* original_problem_impl,
+ Solver::Summary* summary) {
+ double solver_start_time = WallTimeInSeconds();
+
+ Program* original_program = original_problem_impl->mutable_program();
+ ProblemImpl* problem_impl = original_problem_impl;
+
+ // Reset the summary object to its default values.
+ *CHECK_NOTNULL(summary) = Solver::Summary();
+
+ summary->minimizer_type = LINE_SEARCH;
+ summary->line_search_direction_type =
+ original_options.line_search_direction_type;
+ summary->max_lbfgs_rank = original_options.max_lbfgs_rank;
+ summary->line_search_type = original_options.line_search_type;
+ summary->num_parameter_blocks = problem_impl->NumParameterBlocks();
+ summary->num_parameters = problem_impl->NumParameters();
+ summary->num_residual_blocks = problem_impl->NumResidualBlocks();
+ summary->num_residuals = problem_impl->NumResiduals();
+
+ // Empty programs are usually a user error.
+ if (summary->num_parameter_blocks == 0) {
+ summary->error = "Problem contains no parameter blocks.";
+ LOG(ERROR) << summary->error;
return;
}
- scoped_ptr<Evaluator> evaluator(
- CreateEvaluator(options, reduced_program.get(), &summary->error));
+ if (summary->num_residual_blocks == 0) {
+ summary->error = "Problem contains no residual blocks.";
+ LOG(ERROR) << summary->error;
+ return;
+ }
+
+ Solver::Options options(original_options);
+
+ // This ensures that we get a Block Jacobian Evaluator along with
+ // none of the Schur nonsense. This file will have to be extensively
+ // refactored to deal with the various bits of cleanups related to
+ // line search.
+ options.linear_solver_type = CGNR;
+
+ options.linear_solver_ordering = NULL;
+ options.inner_iteration_ordering = NULL;
+
+#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
+
+ summary->num_threads_given = original_options.num_threads;
+ summary->num_threads_used = options.num_threads;
+
+ if (original_options.linear_solver_ordering != NULL) {
+ if (!IsOrderingValid(original_options, problem_impl, &summary->error)) {
+ LOG(ERROR) << summary->error;
+ return;
+ }
+ options.linear_solver_ordering =
+ new ParameterBlockOrdering(*original_options.linear_solver_ordering);
+ } else {
+ options.linear_solver_ordering = new ParameterBlockOrdering;
+ const ProblemImpl::ParameterMap& parameter_map =
+ problem_impl->parameter_map();
+ for (ProblemImpl::ParameterMap::const_iterator it = parameter_map.begin();
+ it != parameter_map.end();
+ ++it) {
+ options.linear_solver_ordering->AddElementToGroup(it->first, 0);
+ }
+ }
+
+ original_program->SetParameterBlockStatePtrsToUserStatePtrs();
+
+ // If the user requests gradient checking, construct a new
+ // ProblemImpl by wrapping the CostFunctions of problem_impl inside
+ // GradientCheckingCostFunction and replacing problem_impl with
+ // gradient_checking_problem_impl.
+ scoped_ptr<ProblemImpl> gradient_checking_problem_impl;
+ if (options.check_gradients) {
+ VLOG(1) << "Checking Gradients";
+ gradient_checking_problem_impl.reset(
+ CreateGradientCheckingProblemImpl(
+ problem_impl,
+ options.numeric_derivative_relative_step_size,
+ options.gradient_check_relative_precision));
+
+ // From here on, problem_impl will point to the gradient checking
+ // version.
+ problem_impl = gradient_checking_problem_impl.get();
+ }
+
+ // Create the three objects needed to minimize: the transformed program, the
+ // evaluator, and the linear solver.
+ scoped_ptr<Program> reduced_program(CreateReducedProgram(&options,
+ problem_impl,
+ &summary->fixed_cost,
+ &summary->error));
+ if (reduced_program == NULL) {
+ return;
+ }
+
+ summary->num_parameter_blocks_reduced = reduced_program->NumParameterBlocks();
+ summary->num_parameters_reduced = reduced_program->NumParameters();
+ summary->num_residual_blocks_reduced = reduced_program->NumResidualBlocks();
+ summary->num_residuals_reduced = reduced_program->NumResiduals();
+
+ if (summary->num_parameter_blocks_reduced == 0) {
+ summary->preprocessor_time_in_seconds =
+ WallTimeInSeconds() - solver_start_time;
+
+ LOG(INFO) << "Terminating: FUNCTION_TOLERANCE reached. "
+ << "No non-constant parameter blocks found.";
+
+ // FUNCTION_TOLERANCE is the right convergence here, as we know
+ // that the objective function is constant and cannot be changed
+ // any further.
+ summary->termination_type = FUNCTION_TOLERANCE;
+
+ const double post_process_start_time = WallTimeInSeconds();
+
+ SetSummaryFinalCost(summary);
+
+ // Ensure the program state is set to the user parameters on the way out.
+ original_program->SetParameterBlockStatePtrsToUserStatePtrs();
+ summary->postprocessor_time_in_seconds =
+ WallTimeInSeconds() - post_process_start_time;
+ return;
+ }
+
+ scoped_ptr<Evaluator> evaluator(CreateEvaluator(options,
+ problem_impl->parameter_map(),
+ reduced_program.get(),
+ &summary->error));
if (evaluator == NULL) {
return;
}
@@ -318,17 +752,18 @@ void SolverImpl::Solve(const Solver::Options& original_options,
// Collect the discontiguous parameters into a contiguous state vector.
reduced_program->ParameterBlocksToStateVector(parameters.data());
- time_t minimizer_start_time = time(NULL);
+ Vector original_parameters = parameters;
+
+ const double minimizer_start_time = WallTimeInSeconds();
summary->preprocessor_time_in_seconds =
minimizer_start_time - solver_start_time;
// Run the optimization.
- Minimize(options,
- reduced_program.get(),
- evaluator.get(),
- linear_solver.get(),
- parameters.data(),
- summary);
+ LineSearchMinimize(options,
+ reduced_program.get(),
+ evaluator.get(),
+ parameters.data(),
+ summary);
// If the user aborted mid-optimization or the optimization
// terminated because of a numerical failure, then return without
@@ -338,35 +773,100 @@ void SolverImpl::Solve(const Solver::Options& original_options,
return;
}
- time_t post_process_start_time = time(NULL);
+ const double post_process_start_time = WallTimeInSeconds();
// Push the contiguous optimized parameters back to the user's parameters.
reduced_program->StateVectorToParameterBlocks(parameters.data());
reduced_program->CopyParameterBlockStateToUserState();
- // Evaluate the final cost, residual vector and the jacobian
- // matrix if requested by the user.
- Evaluator::Evaluate(
- original_program,
- options.num_threads,
- &summary->final_cost,
- options.return_final_residuals ? &summary->final_residuals : NULL,
- options.return_final_gradient ? &summary->final_gradient : NULL,
- options.return_final_jacobian ? &summary->final_jacobian : NULL);
+ SetSummaryFinalCost(summary);
// Ensure the program state is set to the user parameters on the way out.
original_program->SetParameterBlockStatePtrsToUserStatePtrs();
+
+ const map<string, double>& evaluator_time_statistics =
+ evaluator->TimeStatistics();
+
+ summary->residual_evaluation_time_in_seconds =
+ FindWithDefault(evaluator_time_statistics, "Evaluator::Residual", 0.0);
+ summary->jacobian_evaluation_time_in_seconds =
+ FindWithDefault(evaluator_time_statistics, "Evaluator::Jacobian", 0.0);
+
// Stick a fork in it, we're done.
- summary->postprocessor_time_in_seconds = time(NULL) - post_process_start_time;
+ summary->postprocessor_time_in_seconds =
+ WallTimeInSeconds() - post_process_start_time;
+}
+
+
+bool SolverImpl::IsOrderingValid(const Solver::Options& options,
+ const ProblemImpl* problem_impl,
+ string* error) {
+ if (options.linear_solver_ordering->NumElements() !=
+ problem_impl->NumParameterBlocks()) {
+ *error = "Number of parameter blocks in user supplied ordering "
+ "does not match the number of parameter blocks in the problem";
+ return false;
+ }
+
+ const Program& program = problem_impl->program();
+ const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
+ for (vector<ParameterBlock*>::const_iterator it = parameter_blocks.begin();
+ it != parameter_blocks.end();
+ ++it) {
+ if (!options.linear_solver_ordering
+ ->IsMember(const_cast<double*>((*it)->user_state()))) {
+ *error = "Problem contains a parameter block that is not in "
+ "the user specified ordering.";
+ return false;
+ }
+ }
+
+ if (IsSchurType(options.linear_solver_type) &&
+ options.linear_solver_ordering->NumGroups() > 1) {
+ const vector<ResidualBlock*>& residual_blocks = program.residual_blocks();
+ const set<double*>& e_blocks =
+ options.linear_solver_ordering->group_to_elements().begin()->second;
+ if (!IsParameterBlockSetIndependent(e_blocks, residual_blocks)) {
+ *error = "The user requested the use of a Schur type solver. "
+ "But the first elimination group in the ordering is not an "
+ "independent set.";
+ return false;
+ }
+ }
+ return true;
+}
+
+bool SolverImpl::IsParameterBlockSetIndependent(
+ const set<double*>& parameter_block_ptrs,
+ const vector<ResidualBlock*>& residual_blocks) {
+ // 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 += parameter_block_ptrs.count(
+ parameter_blocks[i]->mutable_user_state());
+ }
+ if (count > 1) {
+ return false;
+ }
+ }
+ return true;
}
+
// Strips varying parameters and residuals, maintaining order, and updating
// num_eliminate_blocks.
bool SolverImpl::RemoveFixedBlocksFromProgram(Program* program,
- int* num_eliminate_blocks,
+ ParameterBlockOrdering* ordering,
double* fixed_cost,
string* error) {
- int original_num_eliminate_blocks = *num_eliminate_blocks;
vector<ParameterBlock*>* parameter_blocks =
program->mutable_parameter_blocks();
@@ -423,7 +923,7 @@ bool SolverImpl::RemoveFixedBlocksFromProgram(Program* program,
}
// Filter out unused or fixed parameter blocks, and update
- // num_eliminate_blocks as necessary.
+ // the ordering.
{
vector<ParameterBlock*>* parameter_blocks =
program->mutable_parameter_blocks();
@@ -432,8 +932,8 @@ bool SolverImpl::RemoveFixedBlocksFromProgram(Program* program,
ParameterBlock* parameter_block = (*parameter_blocks)[i];
if (parameter_block->index() == 1) {
(*parameter_blocks)[j++] = parameter_block;
- } else if (i < original_num_eliminate_blocks) {
- (*num_eliminate_blocks)--;
+ } else {
+ ordering->Remove(parameter_block->mutable_user_state());
}
}
parameter_blocks->resize(j);
@@ -451,70 +951,127 @@ Program* SolverImpl::CreateReducedProgram(Solver::Options* options,
ProblemImpl* problem_impl,
double* fixed_cost,
string* error) {
+ EventLogger event_logger("CreateReducedProgram");
+
+ CHECK_NOTNULL(options->linear_solver_ordering);
Program* original_program = problem_impl->mutable_program();
scoped_ptr<Program> transformed_program(new Program(*original_program));
+ event_logger.AddEvent("TransformedProgram");
- if (options->ordering_type == USER &&
- !ApplyUserOrdering(*problem_impl,
- options->ordering,
- transformed_program.get(),
- error)) {
- return NULL;
- }
-
- if (options->ordering_type == SCHUR && options->num_eliminate_blocks != 0) {
- *error = "Can't specify SCHUR ordering and num_eliminate_blocks "
- "at the same time; SCHUR ordering determines "
- "num_eliminate_blocks automatically.";
- return NULL;
- }
-
- if (options->ordering_type == SCHUR && options->ordering.size() != 0) {
- *error = "Can't specify SCHUR ordering type and the ordering "
- "vector at the same time; SCHUR ordering determines "
- "a suitable parameter ordering automatically.";
- return NULL;
- }
+ ParameterBlockOrdering* linear_solver_ordering =
+ options->linear_solver_ordering;
- int num_eliminate_blocks = options->num_eliminate_blocks;
+ const int min_group_id =
+ linear_solver_ordering->group_to_elements().begin()->first;
+ const int original_num_groups = linear_solver_ordering->NumGroups();
if (!RemoveFixedBlocksFromProgram(transformed_program.get(),
- &num_eliminate_blocks,
+ linear_solver_ordering,
fixed_cost,
error)) {
return NULL;
}
+ event_logger.AddEvent("RemoveFixedBlocks");
+
if (transformed_program->NumParameterBlocks() == 0) {
+ if (transformed_program->NumResidualBlocks() > 0) {
+ *error = "Zero parameter blocks but non-zero residual blocks"
+ " in the reduced program. Congratulations, you found a "
+ "Ceres bug! Please report this error to the developers.";
+ return NULL;
+ }
+
LOG(WARNING) << "No varying parameter blocks to optimize; "
<< "bailing early.";
return transformed_program.release();
}
- if (options->ordering_type == SCHUR) {
+ // If the user supplied an linear_solver_ordering with just one
+ // group, it is equivalent to the user supplying NULL as
+ // 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.
+ if (original_num_groups == 1 && IsSchurType(options->linear_solver_type)) {
vector<ParameterBlock*> schur_ordering;
- num_eliminate_blocks = ComputeSchurOrdering(*transformed_program,
- &schur_ordering);
+ const int num_eliminate_blocks = ComputeSchurOrdering(*transformed_program,
+ &schur_ordering);
CHECK_EQ(schur_ordering.size(), transformed_program->NumParameterBlocks())
<< "Congratulations, you found a Ceres bug! Please report this error "
<< "to the developers.";
- // Replace the transformed program's ordering with the schur ordering.
- swap(*transformed_program->mutable_parameter_blocks(), schur_ordering);
+ for (int i = 0; i < schur_ordering.size(); ++i) {
+ linear_solver_ordering->AddElementToGroup(
+ schur_ordering[i]->mutable_user_state(),
+ (i < num_eliminate_blocks) ? 0 : 1);
+ }
}
- options->num_eliminate_blocks = num_eliminate_blocks;
- CHECK_GE(options->num_eliminate_blocks, 0)
- << "Congratulations, you found a Ceres bug! Please report this error "
- << "to the developers.";
+ event_logger.AddEvent("SchurOrdering");
+
+ if (!ApplyUserOrdering(problem_impl->parameter_map(),
+ linear_solver_ordering,
+ transformed_program.get(),
+ error)) {
+ return NULL;
+ }
+ event_logger.AddEvent("ApplyOrdering");
+
+ // If the user requested the use of a Schur type solver, and
+ // supplied a non-NULL linear_solver_ordering object with more than
+ // one elimination group, then it can happen that after all the
+ // parameter blocks which are fixed or unused have been removed from
+ // the program and the ordering, there are no more parameter blocks
+ // in the first elimination group.
+ //
+ // In such a case, the use of a Schur type solver is not possible,
+ // as they assume there is at least one e_block. Thus, we
+ // automatically switch to one of the other solvers, depending on
+ // the user's indicated preferences.
+ if (IsSchurType(options->linear_solver_type) &&
+ original_num_groups > 1 &&
+ linear_solver_ordering->GroupSize(min_group_id) == 0) {
+ string msg = "No e_blocks remaining. Switching from ";
+ if (options->linear_solver_type == SPARSE_SCHUR) {
+ options->linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+ msg += "SPARSE_SCHUR to SPARSE_NORMAL_CHOLESKY.";
+ } else if (options->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.
+ options->linear_solver_type = DENSE_QR;
+ msg += "DENSE_SCHUR to DENSE_QR.";
+ } else if (options->linear_solver_type == ITERATIVE_SCHUR) {
+ msg += StringPrintf("ITERATIVE_SCHUR with %s preconditioner "
+ "to CGNR with JACOBI preconditioner.",
+ PreconditionerTypeToString(
+ options->preconditioner_type));
+ options->linear_solver_type = CGNR;
+ if (options->preconditioner_type != IDENTITY) {
+ // CGNR currently only supports the JACOBI preconditioner.
+ options->preconditioner_type = JACOBI;
+ }
+ }
- // Since the transformed program is the "active" program, and it is mutated,
- // update the parameter offsets and indices.
+ LOG(WARNING) << msg;
+ }
+
+ event_logger.AddEvent("AlternateSolver");
+
+ // Since the transformed program is the "active" program, and it is
+ // mutated, update the parameter offsets and indices.
transformed_program->SetParameterOffsetsAndIndex();
+
+ event_logger.AddEvent("SetOffsets");
return transformed_program.release();
}
LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options,
string* error) {
+ CHECK_NOTNULL(options);
+ CHECK_NOTNULL(options->linear_solver_ordering);
+ CHECK_NOTNULL(error);
+
if (options->trust_region_strategy_type == DOGLEG) {
if (options->linear_solver_type == ITERATIVE_SCHUR ||
options->linear_solver_type == CGNR) {
@@ -532,6 +1089,18 @@ LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options,
"SuiteSparse was not enabled when Ceres was built.";
return NULL;
}
+
+ if (options->preconditioner_type == CLUSTER_JACOBI) {
+ *error = "CLUSTER_JACOBI preconditioner not suppored. Please build Ceres "
+ "with SuiteSparse support.";
+ return NULL;
+ }
+
+ if (options->preconditioner_type == CLUSTER_TRIDIAGONAL) {
+ *error = "CLUSTER_TRIDIAGONAL preconditioner not suppored. Please build "
+ "Ceres with SuiteSparse support.";
+ return NULL;
+ }
#endif
#ifdef CERES_NO_CXSPARSE
@@ -543,6 +1112,13 @@ LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options,
}
#endif
+#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE)
+ if (options->linear_solver_type == SPARSE_SCHUR) {
+ *error = "Can't use SPARSE_SCHUR because neither SuiteSparse nor"
+ "CXSparse was enabled when Ceres was compiled.";
+ return NULL;
+ }
+#endif
if (options->linear_solver_max_num_iterations <= 0) {
*error = "Solver::Options::linear_solver_max_num_iterations is 0.";
@@ -568,52 +1144,8 @@ LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options,
linear_solver_options.preconditioner_type = options->preconditioner_type;
linear_solver_options.sparse_linear_algebra_library =
options->sparse_linear_algebra_library;
- linear_solver_options.use_block_amd = options->use_block_amd;
-
-#ifdef CERES_NO_SUITESPARSE
- if (linear_solver_options.preconditioner_type == SCHUR_JACOBI) {
- *error = "SCHUR_JACOBI preconditioner not suppored. Please build Ceres "
- "with SuiteSparse support.";
- return NULL;
- }
-
- if (linear_solver_options.preconditioner_type == CLUSTER_JACOBI) {
- *error = "CLUSTER_JACOBI preconditioner not suppored. Please build Ceres "
- "with SuiteSparse support.";
- return NULL;
- }
-
- if (linear_solver_options.preconditioner_type == CLUSTER_TRIDIAGONAL) {
- *error = "CLUSTER_TRIDIAGONAL preconditioner not suppored. Please build "
- "Ceres with SuiteSparse support.";
- return NULL;
- }
-#endif
linear_solver_options.num_threads = options->num_linear_solver_threads;
- linear_solver_options.num_eliminate_blocks =
- options->num_eliminate_blocks;
-
- if ((linear_solver_options.num_eliminate_blocks == 0) &&
- IsSchurType(linear_solver_options.type)) {
-#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE)
- LOG(INFO) << "No elimination block remaining switching to DENSE_QR.";
- linear_solver_options.type = DENSE_QR;
-#else
- LOG(INFO) << "No elimination block remaining "
- << "switching to SPARSE_NORMAL_CHOLESKY.";
- linear_solver_options.type = SPARSE_NORMAL_CHOLESKY;
-#endif
- }
-
-#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE)
- if (linear_solver_options.type == SPARSE_SCHUR) {
- *error = "Can't use SPARSE_SCHUR because neither SuiteSparse nor"
- "CXSparse was enabled when Ceres was compiled.";
- return NULL;
- }
-#endif
-
// The matrix used for storing the dense Schur complement has a
// single lock guarding the whole matrix. Running the
// SchurComplementSolver with multiple threads leads to maximum
@@ -628,56 +1160,67 @@ LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options,
<< "switching to single-threaded.";
linear_solver_options.num_threads = 1;
}
-
- options->linear_solver_type = linear_solver_options.type;
options->num_linear_solver_threads = linear_solver_options.num_threads;
+ linear_solver_options.use_block_amd = options->use_block_amd;
+ const map<int, set<double*> >& groups =
+ options->linear_solver_ordering->group_to_elements();
+ for (map<int, set<double*> >::const_iterator it = groups.begin();
+ it != groups.end();
+ ++it) {
+ linear_solver_options.elimination_groups.push_back(it->second.size());
+ }
+ // Schur type solvers, expect at least two elimination groups. If
+ // there is only one elimination group, then CreateReducedProgram
+ // guarantees that this group only contains e_blocks. Thus we add a
+ // dummy elimination group with zero blocks in it.
+ if (IsSchurType(linear_solver_options.type) &&
+ linear_solver_options.elimination_groups.size() == 1) {
+ linear_solver_options.elimination_groups.push_back(0);
+ }
+
return LinearSolver::Create(linear_solver_options);
}
-bool SolverImpl::ApplyUserOrdering(const ProblemImpl& problem_impl,
- vector<double*>& ordering,
- Program* program,
- string* error) {
- if (ordering.size() != program->NumParameterBlocks()) {
+bool SolverImpl::ApplyUserOrdering(
+ const ProblemImpl::ParameterMap& parameter_map,
+ const ParameterBlockOrdering* ordering,
+ Program* program,
+ string* error) {
+ if (ordering->NumElements() != program->NumParameterBlocks()) {
*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 %ld blocks.",
+ "has %d blocks while the ordering has %d blocks.",
program->NumParameterBlocks(),
- ordering.size());
+ ordering->NumElements());
return false;
}
- // Ensure that there are no duplicates in the user's ordering.
- {
- vector<double*> ordering_copy(ordering);
- sort(ordering_copy.begin(), ordering_copy.end());
- if (unique(ordering_copy.begin(), ordering_copy.end())
- != ordering_copy.end()) {
- *error = "User specified ordering contains duplicates.";
- return false;
- }
- }
-
vector<ParameterBlock*>* parameter_blocks =
program->mutable_parameter_blocks();
-
- fill(parameter_blocks->begin(),
- parameter_blocks->end(),
- static_cast<ParameterBlock*>(NULL));
-
- const ProblemImpl::ParameterMap& parameter_map = problem_impl.parameter_map();
- for (int i = 0; i < ordering.size(); ++i) {
- ProblemImpl::ParameterMap::const_iterator it =
- parameter_map.find(ordering[i]);
- if (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 at position %d "
- " in options.ordering.", i);
- return false;
+ 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);
}
- (*parameter_blocks)[i] = it->second;
}
return true;
}
@@ -704,36 +1247,31 @@ static int MinParameterBlock(const ResidualBlock* residual_block,
// 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 SolverImpl::MaybeReorderResidualBlocks(const Solver::Options& options,
- Program* program,
- string* error) {
- // Only Schur types require the lexicographic reordering.
- if (!IsSchurType(options.linear_solver_type)) {
- return true;
- }
-
- CHECK_NE(0, options.num_eliminate_blocks)
- << "Congratulations, you found a Ceres bug! Please report this error "
- << "to the developers.";
+bool SolverImpl::LexicographicallyOrderResidualBlocks(
+ const int num_eliminate_blocks,
+ Program* program,
+ string* error) {
+ CHECK_GE(num_eliminate_blocks, 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(options.num_eliminate_blocks + 1);
+ vector<int> residual_blocks_per_e_block(num_eliminate_blocks + 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,
- options.num_eliminate_blocks);
+ int position = MinParameterBlock(residual_block, num_eliminate_blocks);
min_position_per_residual[i] = position;
- DCHECK_LE(position, options.num_eliminate_blocks);
+ DCHECK_LE(position, num_eliminate_blocks);
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(options.num_eliminate_blocks + 1);
+ vector<int> offsets(num_eliminate_blocks + 1);
std::partial_sum(residual_blocks_per_e_block.begin(),
residual_blocks_per_e_block.end(),
offsets.begin());
@@ -772,7 +1310,7 @@ bool SolverImpl::MaybeReorderResidualBlocks(const Solver::Options& options,
// Sanity check #1: The difference in bucket offsets should match the
// histogram sizes.
- for (int i = 0; i < options.num_eliminate_blocks; ++i) {
+ for (int i = 0; i < num_eliminate_blocks; ++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.";
@@ -789,15 +1327,76 @@ bool SolverImpl::MaybeReorderResidualBlocks(const Solver::Options& options,
return true;
}
-Evaluator* SolverImpl::CreateEvaluator(const Solver::Options& options,
- Program* program,
- string* error) {
+Evaluator* SolverImpl::CreateEvaluator(
+ const Solver::Options& options,
+ const ProblemImpl::ParameterMap& parameter_map,
+ Program* program,
+ string* error) {
Evaluator::Options evaluator_options;
evaluator_options.linear_solver_type = options.linear_solver_type;
- evaluator_options.num_eliminate_blocks = options.num_eliminate_blocks;
+ evaluator_options.num_eliminate_blocks =
+ (options.linear_solver_ordering->NumGroups() > 0 &&
+ IsSchurType(options.linear_solver_type))
+ ? (options.linear_solver_ordering
+ ->group_to_elements().begin()
+ ->second.size())
+ : 0;
evaluator_options.num_threads = options.num_threads;
return Evaluator::Create(evaluator_options, program, error);
}
+CoordinateDescentMinimizer* SolverImpl::CreateInnerIterationMinimizer(
+ const Solver::Options& options,
+ const Program& program,
+ const ProblemImpl::ParameterMap& parameter_map,
+ Solver::Summary* summary) {
+ scoped_ptr<CoordinateDescentMinimizer> inner_iteration_minimizer(
+ new CoordinateDescentMinimizer);
+ scoped_ptr<ParameterBlockOrdering> inner_iteration_ordering;
+ ParameterBlockOrdering* ordering_ptr = NULL;
+
+ if (options.inner_iteration_ordering == NULL) {
+ // 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.
+ inner_iteration_ordering.reset(new ParameterBlockOrdering);
+ ComputeRecursiveIndependentSetOrdering(program,
+ inner_iteration_ordering.get());
+ inner_iteration_ordering->Reverse();
+ ordering_ptr = inner_iteration_ordering.get();
+ } else {
+ const map<int, set<double*> >& group_to_elements =
+ options.inner_iteration_ordering->group_to_elements();
+
+ // Iterate over each group and verify that it is an independent
+ // set.
+ map<int, set<double*> >::const_iterator it = group_to_elements.begin();
+ for ( ; it != group_to_elements.end(); ++it) {
+ if (!IsParameterBlockSetIndependent(it->second,
+ program.residual_blocks())) {
+ summary->error =
+ StringPrintf("The user-provided "
+ "parameter_blocks_for_inner_iterations does not "
+ "form an independent set. Group Id: %d", it->first);
+ return NULL;
+ }
+ }
+ ordering_ptr = options.inner_iteration_ordering;
+ }
+
+ if (!inner_iteration_minimizer->Init(program,
+ parameter_map,
+ *ordering_ptr,
+ &summary->error)) {
+ return NULL;
+ }
+
+ summary->inner_iterations = true;
+ SummarizeOrdering(ordering_ptr, &(summary->inner_iteration_ordering_used));
+
+ return inner_iteration_minimizer.release();
+}
+
} // namespace internal
} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/solver_impl.h b/extern/libmv/third_party/ceres/internal/ceres/solver_impl.h
index 11b44de6f42..c5f5efad3d7 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/solver_impl.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/solver_impl.h
@@ -31,17 +31,20 @@
#ifndef CERES_INTERNAL_SOLVER_IMPL_H_
#define CERES_INTERNAL_SOLVER_IMPL_H_
+#include <set>
#include <string>
#include <vector>
#include "ceres/internal/port.h"
+#include "ceres/ordered_groups.h"
+#include "ceres/problem_impl.h"
#include "ceres/solver.h"
namespace ceres {
namespace internal {
+class CoordinateDescentMinimizer;
class Evaluator;
class LinearSolver;
-class ProblemImpl;
class Program;
class SolverImpl {
@@ -52,10 +55,19 @@ class SolverImpl {
ProblemImpl* problem_impl,
Solver::Summary* summary);
+ static void TrustRegionSolve(const Solver::Options& options,
+ ProblemImpl* problem_impl,
+ Solver::Summary* summary);
+
+ static void LineSearchSolve(const Solver::Options& options,
+ ProblemImpl* problem_impl,
+ Solver::Summary* summary);
+
// Create the transformed Program, which has all the fixed blocks
// and residuals eliminated, and in the case of automatic schur
// ordering, has the E blocks first in the resulting program, with
// options.num_eliminate_blocks set appropriately.
+ //
// If fixed_cost is not NULL, the residual blocks that are removed
// are evaluated and the sum of their cost is returned in fixed_cost.
static Program* CreateReducedProgram(Solver::Options* options,
@@ -71,46 +83,73 @@ class SolverImpl {
static LinearSolver* CreateLinearSolver(Solver::Options* options,
string* error);
- // Reorder the parameter blocks in program using the vector
- // ordering. A return value of true indicates success and false
- // indicates an error was encountered whose cause is logged to
- // LOG(ERROR).
- static bool ApplyUserOrdering(const ProblemImpl& problem_impl,
- vector<double*>& ordering,
+ // Reorder the parameter blocks in program using the ordering. A
+ // return value of true indicates success and false indicates an
+ // error was encountered whose cause is logged to LOG(ERROR).
+ static bool ApplyUserOrdering(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.
- static bool MaybeReorderResidualBlocks(const Solver::Options& options,
- Program* program,
- string* error);
+ // residuals involving e block (i.e., the first num_eliminate_block
+ // parameter blocks) occur together. This is a necessary condition
+ // for the Schur eliminator.
+ static bool LexicographicallyOrderResidualBlocks(
+ const int num_eliminate_blocks,
+ Program* program,
+ string* error);
// Create the appropriate evaluator for the transformed program.
- static Evaluator* CreateEvaluator(const Solver::Options& options,
- Program* program,
- string* error);
-
- // Run the minimization for the given evaluator and configuration.
- static void Minimize(const Solver::Options &options,
- Program* program,
- Evaluator* evaluator,
- LinearSolver* linear_solver,
- double* parameters,
- Solver::Summary* summary);
+ static Evaluator* CreateEvaluator(
+ const Solver::Options& options,
+ const ProblemImpl::ParameterMap& parameter_map,
+ Program* program,
+ string* error);
+
+ // Run the TrustRegionMinimizer for the given evaluator and configuration.
+ static void TrustRegionMinimize(
+ const Solver::Options &options,
+ Program* program,
+ CoordinateDescentMinimizer* inner_iteration_minimizer,
+ Evaluator* evaluator,
+ LinearSolver* linear_solver,
+ double* parameters,
+ Solver::Summary* summary);
+
+ // Run the LineSearchMinimizer for the given evaluator and configuration.
+ static void LineSearchMinimize(
+ const Solver::Options &options,
+ Program* program,
+ Evaluator* evaluator,
+ double* parameters,
+ Solver::Summary* summary);
// Remove the fixed or unused parameter blocks and residuals
// depending only on fixed parameters from the problem. Also updates
// num_eliminate_blocks, since removed parameters changes the point
- // at which the eliminated blocks is valid.
- // If fixed_cost is not NULL, the residual blocks that are removed
- // are evaluated and the sum of their cost is returned in fixed_cost.
+ // at which the eliminated blocks is valid. If fixed_cost is not
+ // NULL, the residual blocks that are removed are evaluated and the
+ // sum of their cost is returned in fixed_cost.
static bool RemoveFixedBlocksFromProgram(Program* program,
- int* num_eliminate_blocks,
+ ParameterBlockOrdering* ordering,
double* fixed_cost,
string* error);
+
+ static bool IsOrderingValid(const Solver::Options& options,
+ const ProblemImpl* problem_impl,
+ string* error);
+
+ static bool IsParameterBlockSetIndependent(
+ const set<double*>& parameter_block_ptrs,
+ const vector<ResidualBlock*>& residual_blocks);
+
+ static CoordinateDescentMinimizer* CreateInnerIterationMinimizer(
+ const Solver::Options& options,
+ const Program& program,
+ const ProblemImpl::ParameterMap& parameter_map,
+ Solver::Summary* summary);
};
} // namespace internal
diff --git a/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc
index 9e00b4402dc..dd05f0c6f41 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc
@@ -39,12 +39,13 @@
#endif
#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/scoped_ptr.h"
#include "ceres/linear_solver.h"
#include "ceres/suitesparse.h"
#include "ceres/triplet_sparse_matrix.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/types.h"
+#include "ceres/wall_time.h"
namespace ceres {
namespace internal {
@@ -103,6 +104,8 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingCXSparse(
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
double * x) {
+ EventLogger event_logger("SparseNormalCholeskySolver::CXSparse::Solve");
+
LinearSolver::Summary summary;
summary.num_iterations = 1;
const int num_cols = A->num_cols();
@@ -129,25 +132,34 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingCXSparse(
// off of Jt to compute the Cholesky factorization of the normal
// equations.
cs_di* A2 = cs_transpose(&At, 1);
- cs_di* AtA = cs_multiply(&At,A2);
+ cs_di* AtA = cs_multiply(&At, A2);
cxsparse_.Free(A2);
if (per_solve_options.D != NULL) {
A->DeleteRows(num_cols);
}
+ event_logger.AddEvent("Setup");
+
// Compute symbolic factorization if not available.
if (cxsparse_factor_ == NULL) {
cxsparse_factor_ = CHECK_NOTNULL(cxsparse_.AnalyzeCholesky(AtA));
}
+ event_logger.AddEvent("Analysis");
+
+
// Solve the linear system.
if (cxsparse_.SolveCholesky(AtA, cxsparse_factor_, Atb.data())) {
VectorRef(x, Atb.rows()) = Atb;
summary.termination_type = TOLERANCE;
}
+ event_logger.AddEvent("Solve");
+
cxsparse_.Free(AtA);
+
+ event_logger.AddEvent("Teardown");
return summary;
}
#else
@@ -169,9 +181,9 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingSuiteSparse(
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
double * x) {
- const time_t start_time = time(NULL);
- const int num_cols = A->num_cols();
+ EventLogger event_logger("SparseNormalCholeskySolver::SuiteSparse::Solve");
+ const int num_cols = A->num_cols();
LinearSolver::Summary summary;
Vector Atb = Vector::Zero(num_cols);
A->LeftMultiply(b, Atb.data());
@@ -189,7 +201,7 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingSuiteSparse(
CHECK_NOTNULL(lhs.get());
cholmod_dense* rhs = ss_.CreateDenseVector(Atb.data(), num_cols, num_cols);
- const time_t init_time = time(NULL);
+ event_logger.AddEvent("Setup");
if (factor_ == NULL) {
if (options_.use_block_amd) {
@@ -206,11 +218,10 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingSuiteSparse(
}
CHECK_NOTNULL(factor_);
-
- const time_t symbolic_time = time(NULL);
+ event_logger.AddEvent("Analysis");
cholmod_dense* sol = ss_.SolveCholesky(lhs.get(), factor_, rhs);
- const time_t solve_time = time(NULL);
+ event_logger.AddEvent("Solve");
ss_.Free(rhs);
rhs = NULL;
@@ -228,12 +239,7 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingSuiteSparse(
summary.termination_type = TOLERANCE;
}
- const time_t cleanup_time = time(NULL);
- VLOG(2) << "time (sec) total: " << (cleanup_time - start_time)
- << " init: " << (init_time - start_time)
- << " symbolic: " << (symbolic_time - init_time)
- << " solve: " << (solve_time - symbolic_time)
- << " cleanup: " << (cleanup_time - solve_time);
+ event_logger.AddEvent("Teardown");
return summary;
}
#else
diff --git a/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h b/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h
index 40d9e0a0327..8d48096d4c6 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h
@@ -35,8 +35,8 @@
#define CERES_INTERNAL_SPARSE_NORMAL_CHOLESKY_SOLVER_H_
#include "ceres/cxsparse.h"
-#include "ceres/linear_solver.h"
#include "ceres/internal/macros.h"
+#include "ceres/linear_solver.h"
#include "ceres/suitesparse.h"
namespace ceres {
diff --git a/extern/libmv/third_party/ceres/internal/ceres/split.cc b/extern/libmv/third_party/ceres/internal/ceres/split.cc
index c65c8a5bb5d..3edbc281340 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/split.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/split.cc
@@ -28,10 +28,11 @@
//
// Author: keir@google.com (Keir Mierle)
+#include "ceres/split.h"
+
#include <string>
#include <vector>
#include <iterator>
-#include "ceres/split.h"
#include "ceres/internal/port.h"
namespace ceres {
diff --git a/extern/libmv/third_party/ceres/internal/ceres/split.h b/extern/libmv/third_party/ceres/internal/ceres/split.h
index ec579e974da..4df48c3a7cd 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/split.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/split.h
@@ -2,7 +2,7 @@
// Author: keir@google.com (Keir Mierle)
#ifndef CERES_INTERNAL_SPLIT_H_
-#define VISION_OPTIMIZATION_LEAST_SQUARES_INTERNAL_SPLIT_H_
+#define CERES_INTERNAL_SPLIT_H_
#include <string>
#include <vector>
diff --git a/extern/libmv/third_party/ceres/internal/ceres/stl_util.h b/extern/libmv/third_party/ceres/internal/ceres/stl_util.h
index a1a19e8b3ce..08f15ec8398 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/stl_util.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/stl_util.h
@@ -31,6 +31,8 @@
#ifndef CERES_INTERNAL_STL_UTIL_H_
#define CERES_INTERNAL_STL_UTIL_H_
+#include <algorithm>
+
namespace ceres {
// STLDeleteContainerPointers()
@@ -53,6 +55,20 @@ void STLDeleteContainerPointers(ForwardIterator begin,
}
}
+// Variant of STLDeleteContainerPointers which allows the container to
+// contain duplicates.
+template <class ForwardIterator>
+void STLDeleteUniqueContainerPointers(ForwardIterator begin,
+ ForwardIterator end) {
+ sort(begin, end);
+ ForwardIterator new_end = unique(begin, end);
+ while (begin != new_end) {
+ ForwardIterator temp = begin;
+ ++begin;
+ delete *temp;
+ }
+}
+
// STLDeleteElements() deletes all the elements in an STL container and clears
// the container. This function is suitable for use with a vector, set,
// hash_set, or any other STL container which defines sensible begin(), end(),
diff --git a/extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc b/extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc
index 396a48b7d97..ce204674dce 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc
@@ -28,13 +28,14 @@
//
// Author: Sanjay Ghemawat
+#include "ceres/stringprintf.h"
+
#include <cerrno>
#include <cstdarg> // For va_list and related operations
#include <cstdio> // MSVC requires this for _vsnprintf
#include <string>
#include <vector>
-#include "ceres/stringprintf.h"
#include "ceres/internal/port.h"
namespace ceres {
diff --git a/extern/libmv/third_party/ceres/internal/ceres/stringprintf.h b/extern/libmv/third_party/ceres/internal/ceres/stringprintf.h
index f2f907ab32d..cd1be142aed 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/stringprintf.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/stringprintf.h
@@ -65,17 +65,17 @@ namespace internal {
// Return a C++ string.
extern string StringPrintf(const char* format, ...)
// Tell the compiler to do printf format string checking.
- CERES_PRINTF_ATTRIBUTE(1,2);
+ CERES_PRINTF_ATTRIBUTE(1, 2);
// Store result into a supplied string and return it.
extern const string& SStringPrintf(string* dst, const char* format, ...)
// Tell the compiler to do printf format string checking.
- CERES_PRINTF_ATTRIBUTE(2,3);
+ CERES_PRINTF_ATTRIBUTE(2, 3);
// Append result to a supplied string.
extern void StringAppendF(string* dst, const char* format, ...)
// Tell the compiler to do printf format string checking.
- CERES_PRINTF_ATTRIBUTE(2,3);
+ CERES_PRINTF_ATTRIBUTE(2, 3);
// Lower-level routine that takes a va_list and appends to a specified string.
// All other routines are just convenience wrappers around it.
diff --git a/extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc b/extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc
index cf3c48f84e6..d200aeb82f3 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc
@@ -135,10 +135,11 @@ cholmod_factor* SuiteSparse::BlockAnalyzeCholesky(
return AnalyzeCholeskyWithUserOrdering(A, ordering);
}
-cholmod_factor* SuiteSparse::AnalyzeCholeskyWithUserOrdering(cholmod_sparse* A,
- const vector<int>& ordering) {
+cholmod_factor* SuiteSparse::AnalyzeCholeskyWithUserOrdering(
+ cholmod_sparse* A,
+ const vector<int>& ordering) {
CHECK_EQ(ordering.size(), A->nrow);
- cc_.nmethods = 1 ;
+ cc_.nmethods = 1;
cc_.method[0].ordering = CHOLMOD_GIVEN;
cholmod_factor* factor =
cholmod_analyze_p(A, const_cast<int*>(&ordering[0]), NULL, 0, &cc_);
diff --git a/extern/libmv/third_party/ceres/internal/ceres/suitesparse.h b/extern/libmv/third_party/ceres/internal/ceres/suitesparse.h
index eb691c0c0ed..3fe79080d5d 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/suitesparse.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/suitesparse.h
@@ -39,9 +39,9 @@
#include <string>
#include <vector>
-#include <glog/logging.h>
-#include "cholmod.h"
#include "ceres/internal/port.h"
+#include "cholmod.h"
+#include "glog/logging.h"
namespace ceres {
namespace internal {
diff --git a/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc
index ed8677ea18a..a09f38ee24e 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc
@@ -71,7 +71,8 @@ TripletSparseMatrix::TripletSparseMatrix(int num_rows,
}
TripletSparseMatrix::TripletSparseMatrix(const TripletSparseMatrix& orig)
- : num_rows_(orig.num_rows_),
+ : SparseMatrix(),
+ num_rows_(orig.num_rows_),
num_cols_(orig.num_cols_),
max_num_nonzeros_(orig.max_num_nonzeros_),
num_nonzeros_(orig.num_nonzeros_),
diff --git a/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc b/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc
index 76c4f8a7580..981c60a12e7 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc
@@ -45,8 +45,10 @@
#include "ceres/internal/scoped_ptr.h"
#include "ceres/linear_least_squares_problems.h"
#include "ceres/sparse_matrix.h"
+#include "ceres/stringprintf.h"
#include "ceres/trust_region_strategy.h"
#include "ceres/types.h"
+#include "ceres/wall_time.h"
#include "glog/logging.h"
namespace ceres {
@@ -56,28 +58,13 @@ namespace {
const double kEpsilon = 1e-12;
} // namespace
-// Execute the list of IterationCallbacks sequentially. If any one of
-// the callbacks does not return SOLVER_CONTINUE, then stop and return
-// its status.
-CallbackReturnType TrustRegionMinimizer::RunCallbacks(
- const IterationSummary& iteration_summary) {
- for (int i = 0; i < options_.callbacks.size(); ++i) {
- const CallbackReturnType status =
- (*options_.callbacks[i])(iteration_summary);
- if (status != SOLVER_CONTINUE) {
- return status;
- }
- }
- return SOLVER_CONTINUE;
-}
-
// Compute a scaling vector that is used to improve the conditioning
// of the Jacobian.
void TrustRegionMinimizer::EstimateScale(const SparseMatrix& jacobian,
double* scale) const {
jacobian.SquaredColumnNorm(scale);
for (int i = 0; i < jacobian.num_cols(); ++i) {
- scale[i] = 1.0 / (kEpsilon + sqrt(scale[i]));
+ scale[i] = 1.0 / (1.0 + sqrt(scale[i]));
}
}
@@ -96,29 +83,19 @@ bool TrustRegionMinimizer::MaybeDumpLinearLeastSquaresProblem(
// moved inside TrustRegionStrategy, its not clear how we dump the
// regularization vector/matrix anymore.
//
- // Doing this right requires either an API change to the
- // TrustRegionStrategy and/or how LinearLeastSquares problems are
- // stored on disk.
+ // Also num_eliminate_blocks is not visible to the trust region
+ // minimizer either.
//
- // For now, we will just not dump the regularizer.
- return (!binary_search(options_.lsqp_iterations_to_dump.begin(),
- options_.lsqp_iterations_to_dump.end(),
- iteration) ||
- DumpLinearLeastSquaresProblem(options_.lsqp_dump_directory,
- iteration,
- options_.lsqp_dump_format_type,
- jacobian,
- NULL,
- residuals,
- step,
- options_.num_eliminate_blocks));
+ // Both of these indicate that this is the wrong place for this
+ // code, and going forward this should needs fixing/refactoring.
+ return true;
}
void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
double* parameters,
Solver::Summary* summary) {
- time_t start_time = time(NULL);
- time_t iteration_start_time = start_time;
+ double start_time = WallTimeInSeconds();
+ double iteration_start_time = start_time;
Init(options);
summary->termination_type = NO_CONVERGENCE;
@@ -149,7 +126,6 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
iteration_summary.iteration = 0;
iteration_summary.step_is_valid = false;
iteration_summary.step_is_successful = false;
- iteration_summary.cost = summary->initial_cost;
iteration_summary.cost_change = 0.0;
iteration_summary.gradient_max_norm = 0.0;
iteration_summary.step_norm = 0.0;
@@ -169,6 +145,9 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
return;
}
+ summary->initial_cost = cost + summary->fixed_cost;
+ iteration_summary.cost = cost + summary->fixed_cost;
+
int num_consecutive_nonmonotonic_steps = 0;
double minimum_cost = cost;
double reference_cost = cost;
@@ -189,45 +168,34 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
// The initial gradient max_norm is bounded from below so that we do
// not divide by zero.
- const double gradient_max_norm_0 =
+ const double initial_gradient_max_norm =
max(iteration_summary.gradient_max_norm, kEpsilon);
const double absolute_gradient_tolerance =
- options_.gradient_tolerance * gradient_max_norm_0;
+ options_.gradient_tolerance * initial_gradient_max_norm;
if (iteration_summary.gradient_max_norm <= absolute_gradient_tolerance) {
summary->termination_type = GRADIENT_TOLERANCE;
VLOG(1) << "Terminating: Gradient tolerance reached."
<< "Relative gradient max norm: "
- << iteration_summary.gradient_max_norm / gradient_max_norm_0
+ << iteration_summary.gradient_max_norm / initial_gradient_max_norm
<< " <= " << options_.gradient_tolerance;
return;
}
iteration_summary.iteration_time_in_seconds =
- time(NULL) - iteration_start_time;
- iteration_summary.cumulative_time_in_seconds = time(NULL) - start_time +
- summary->preprocessor_time_in_seconds;
+ WallTimeInSeconds() - iteration_start_time;
+ iteration_summary.cumulative_time_in_seconds =
+ WallTimeInSeconds() - start_time
+ + summary->preprocessor_time_in_seconds;
summary->iterations.push_back(iteration_summary);
- // Call the various callbacks.
- switch (RunCallbacks(iteration_summary)) {
- case SOLVER_TERMINATE_SUCCESSFULLY:
- summary->termination_type = USER_SUCCESS;
- VLOG(1) << "Terminating: User callback returned USER_SUCCESS.";
- return;
- case SOLVER_ABORT:
- summary->termination_type = USER_ABORT;
- VLOG(1) << "Terminating: User callback returned USER_ABORT.";
- return;
- case SOLVER_CONTINUE:
- break;
- default:
- LOG(FATAL) << "Unknown type of user callback status";
- }
-
int num_consecutive_invalid_steps = 0;
while (true) {
- iteration_start_time = time(NULL);
+ if (!RunCallbacks(options.callbacks, iteration_summary, summary)) {
+ return;
+ }
+
+ iteration_start_time = WallTimeInSeconds();
if (iteration_summary.iteration >= options_.max_num_iterations) {
summary->termination_type = NO_CONVERGENCE;
VLOG(1) << "Terminating: Maximum number of iterations reached.";
@@ -248,7 +216,7 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
iteration_summary.step_is_valid = false;
iteration_summary.step_is_successful = false;
- const time_t strategy_start_time = time(NULL);
+ const double strategy_start_time = WallTimeInSeconds();
TrustRegionStrategy::PerSolveOptions per_solve_options;
per_solve_options.eta = options_.eta;
TrustRegionStrategy::Summary strategy_summary =
@@ -258,7 +226,7 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
trust_region_step.data());
iteration_summary.step_solver_time_in_seconds =
- time(NULL) - strategy_start_time;
+ WallTimeInSeconds() - strategy_start_time;
iteration_summary.linear_solver_iterations =
strategy_summary.num_iterations;
@@ -270,23 +238,24 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
<< options.lsqp_dump_directory << "but failed.";
}
- double new_model_cost = 0.0;
+ double model_cost_change = 0.0;
if (strategy_summary.termination_type != FAILURE) {
- // new_model_cost = 1/2 |f + J * step|^2
- model_residuals = residuals;
+ // new_model_cost
+ // = 1/2 [f + J * step]^2
+ // = 1/2 [ f'f + 2f'J * step + step' * J' * J * step ]
+ // model_cost_change
+ // = cost - new_model_cost
+ // = f'f/2 - 1/2 [ f'f + 2f'J * step + step' * J' * J * step]
+ // = -f'J * step - step' * J' * J * step / 2
+ model_residuals.setZero();
jacobian->RightMultiply(trust_region_step.data(), model_residuals.data());
- new_model_cost = model_residuals.squaredNorm() / 2.0;
-
- // In exact arithmetic, this would never be the case. But poorly
- // conditioned matrices can give rise to situations where the
- // new_model_cost can actually be larger than half the squared
- // norm of the residual vector. We allow for small tolerance
- // around cost and beyond that declare the step to be invalid.
- if ((1.0 - new_model_cost / cost) < -kEpsilon) {
+ model_cost_change = -(residuals.dot(model_residuals) +
+ model_residuals.squaredNorm() / 2.0);
+
+ if (model_cost_change < 0.0) {
VLOG(1) << "Invalid step: current_cost: " << cost
- << " new_model_cost " << new_model_cost
- << " absolute difference " << (cost - new_model_cost)
- << " relative difference " << (1.0 - new_model_cost/cost);
+ << " absolute difference " << model_cost_change
+ << " relative difference " << (model_cost_change / cost);
} else {
iteration_summary.step_is_valid = true;
}
@@ -299,10 +268,12 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
if (++num_consecutive_invalid_steps >=
options_.max_num_consecutive_invalid_steps) {
summary->termination_type = NUMERICAL_FAILURE;
- LOG(WARNING) << "Terminating. Number of successive invalid steps more "
- << "than "
- << "Solver::Options::max_num_consecutive_invalid_steps: "
- << options_.max_num_consecutive_invalid_steps;
+ summary->error = StringPrintf(
+ "Terminating. Number of successive invalid steps more "
+ "than Solver::Options::max_num_consecutive_invalid_steps: %d",
+ options_.max_num_consecutive_invalid_steps);
+
+ LOG(WARNING) << summary->error;
return;
}
@@ -311,7 +282,7 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
// as an unsuccessful iteration. Since the various callbacks are
// still executed, we are going to fill the iteration summary
// with data that assumes a step of length zero and no progress.
- iteration_summary.cost = cost;
+ iteration_summary.cost = cost + summary->fixed_cost;
iteration_summary.cost_change = 0.0;
iteration_summary.gradient_max_norm =
summary->iterations.back().gradient_max_norm;
@@ -322,51 +293,19 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
// The step is numerically valid, so now we can judge its quality.
num_consecutive_invalid_steps = 0;
- // We allow some slop around 0, and clamp the model_cost_change
- // at kEpsilon * min(1.0, cost) from below.
- //
- // In exact arithmetic this should never be needed, as we are
- // guaranteed to new_model_cost <= cost. However, due to various
- // numerical issues, it is possible that new_model_cost is
- // nearly equal to cost, and the difference is a small negative
- // number. To make sure that the relative_decrease computation
- // remains sane, as clamp the difference (cost - new_model_cost)
- // from below at a small positive number.
- //
- // This number is the minimum of kEpsilon * (cost, 1.0), which
- // ensures that it will never get too large in absolute value,
- // while scaling down proportionally with the magnitude of the
- // cost. This is important for problems where the minimum of the
- // objective function is near zero.
- const double model_cost_change =
- max(kEpsilon * min(1.0, cost), cost - new_model_cost);
-
// Undo the Jacobian column scaling.
delta = (trust_region_step.array() * scale.array()).matrix();
- iteration_summary.step_norm = delta.norm();
-
- // Convergence based on parameter_tolerance.
- const double step_size_tolerance = options_.parameter_tolerance *
- (x_norm + options_.parameter_tolerance);
- if (iteration_summary.step_norm <= step_size_tolerance) {
- VLOG(1) << "Terminating. Parameter tolerance reached. "
- << "relative step_norm: "
- << iteration_summary.step_norm /
- (x_norm + options_.parameter_tolerance)
- << " <= " << options_.parameter_tolerance;
- summary->termination_type = PARAMETER_TOLERANCE;
- return;
- }
-
if (!evaluator->Plus(x.data(), delta.data(), x_plus_delta.data())) {
summary->termination_type = NUMERICAL_FAILURE;
- LOG(WARNING) << "Terminating. Failed to compute "
- << "Plus(x, delta, x_plus_delta).";
+ summary->error =
+ "Terminating. Failed to compute Plus(x, delta, x_plus_delta).";
+
+ LOG(WARNING) << summary->error;
return;
}
// Try this step.
- double new_cost;
+ double new_cost = numeric_limits<double>::max();
if (!evaluator->Evaluate(x_plus_delta.data(),
&new_cost,
NULL, NULL, NULL)) {
@@ -375,6 +314,45 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
LOG(WARNING) << "Step failed to evaluate. "
<< "Treating it as step with infinite cost";
new_cost = numeric_limits<double>::max();
+ } else {
+ // Check if performing an inner iteration will make it better.
+ if (options.inner_iteration_minimizer != NULL) {
+ const double x_plus_delta_cost = new_cost;
+ Vector inner_iteration_x = x_plus_delta;
+ Solver::Summary inner_iteration_summary;
+ options.inner_iteration_minimizer->Minimize(options,
+ inner_iteration_x.data(),
+ &inner_iteration_summary);
+ if (!evaluator->Evaluate(inner_iteration_x.data(),
+ &new_cost,
+ NULL, NULL, NULL)) {
+ VLOG(2) << "Inner iteration failed.";
+ new_cost = x_plus_delta_cost;
+ } else {
+ x_plus_delta = inner_iteration_x;
+ // Boost the model_cost_change, since the inner iteration
+ // improvements are not accounted for by the trust region.
+ model_cost_change += x_plus_delta_cost - new_cost;
+ VLOG(2) << "Inner iteration succeeded; current cost: " << cost
+ << " x_plus_delta_cost: " << x_plus_delta_cost
+ << " new_cost: " << new_cost;
+ }
+ }
+ }
+
+ iteration_summary.step_norm = (x - x_plus_delta).norm();
+
+ // Convergence based on parameter_tolerance.
+ const double step_size_tolerance = options_.parameter_tolerance *
+ (x_norm + options_.parameter_tolerance);
+ if (iteration_summary.step_norm <= step_size_tolerance) {
+ VLOG(1) << "Terminating. Parameter tolerance reached. "
+ << "relative step_norm: "
+ << iteration_summary.step_norm /
+ (x_norm + options_.parameter_tolerance)
+ << " <= " << options_.parameter_tolerance;
+ summary->termination_type = PARAMETER_TOLERANCE;
+ return;
}
VLOG(2) << "old cost: " << cost << " new cost: " << new_cost;
@@ -421,6 +399,7 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
accumulated_candidate_model_cost_change += model_cost_change;
accumulated_reference_model_cost_change += model_cost_change;
if (relative_decrease <= options_.min_relative_decrease) {
+ iteration_summary.step_is_nonmonotonic = true;
VLOG(2) << "Non-monotonic step! "
<< " relative_decrease: " << relative_decrease
<< " historical_relative_decrease: "
@@ -443,7 +422,9 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
NULL,
jacobian)) {
summary->termination_type = NUMERICAL_FAILURE;
- LOG(WARNING) << "Terminating: Residual and Jacobian evaluation failed.";
+ summary->error =
+ "Terminating: Residual and Jacobian evaluation failed.";
+ LOG(WARNING) << summary->error;
return;
}
@@ -455,7 +436,8 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
summary->termination_type = GRADIENT_TOLERANCE;
VLOG(1) << "Terminating: Gradient tolerance reached."
<< "Relative gradient max norm: "
- << iteration_summary.gradient_max_norm / gradient_max_norm_0
+ << (iteration_summary.gradient_max_norm /
+ initial_gradient_max_norm)
<< " <= " << options_.gradient_tolerance;
return;
}
@@ -523,25 +505,11 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
}
iteration_summary.iteration_time_in_seconds =
- time(NULL) - iteration_start_time;
- iteration_summary.cumulative_time_in_seconds = time(NULL) - start_time +
- summary->preprocessor_time_in_seconds;
+ WallTimeInSeconds() - iteration_start_time;
+ iteration_summary.cumulative_time_in_seconds =
+ WallTimeInSeconds() - start_time
+ + summary->preprocessor_time_in_seconds;
summary->iterations.push_back(iteration_summary);
-
- switch (RunCallbacks(iteration_summary)) {
- case SOLVER_TERMINATE_SUCCESSFULLY:
- summary->termination_type = USER_SUCCESS;
- VLOG(1) << "Terminating: User callback returned USER_SUCCESS.";
- return;
- case SOLVER_ABORT:
- summary->termination_type = USER_ABORT;
- VLOG(1) << "Terminating: User callback returned USER_ABORT.";
- return;
- case SOLVER_CONTINUE:
- break;
- default:
- LOG(FATAL) << "Unknown type of user callback status";
- }
}
}
diff --git a/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.h b/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.h
index a4f5ba3674d..9a022843233 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.h
@@ -39,8 +39,7 @@ namespace ceres {
namespace internal {
// Generic trust region minimization algorithm. The heavy lifting is
-// done by a TrustRegionStrategy object passed in as one of the
-// arguments to the Minimize method.
+// done by a TrustRegionStrategy object passed in as part of options.
//
// For example usage, see SolverImpl::Minimize.
class TrustRegionMinimizer : public Minimizer {
@@ -53,11 +52,10 @@ class TrustRegionMinimizer : public Minimizer {
private:
void Init(const Minimizer::Options& options);
void EstimateScale(const SparseMatrix& jacobian, double* scale) const;
- CallbackReturnType RunCallbacks(const IterationSummary& iteration_summary);
- bool MaybeDumpLinearLeastSquaresProblem( const int iteration,
- const SparseMatrix* jacobian,
- const double* residuals,
- const double* step) const;
+ bool MaybeDumpLinearLeastSquaresProblem(const int iteration,
+ const SparseMatrix* jacobian,
+ const double* residuals,
+ const double* step) const;
Minimizer::Options options_;
};
diff --git a/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.cc b/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.cc
index 89bc19d084b..c68269d0449 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.cc
@@ -1,3 +1,35 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2012, 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)
+// keir@google.com (Keir Mierle)
+
#include "ceres/trust_region_strategy.h"
#include "ceres/dogleg_strategy.h"
#include "ceres/levenberg_marquardt_strategy.h"
diff --git a/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.h b/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.h
index 391da97d5eb..f150594bbd2 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.h
@@ -52,7 +52,7 @@ class SparseMatrix;
// radius to scale the damping term, which controls the step size, but
// does not set a hard limit on its size.
class TrustRegionStrategy {
-public:
+ public:
struct Options {
Options()
: trust_region_strategy_type(LEVENBERG_MARQUARDT),
diff --git a/extern/libmv/third_party/ceres/internal/ceres/types.cc b/extern/libmv/third_party/ceres/internal/ceres/types.cc
index 05e573ff6d5..2e19322cc76 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/types.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/types.cc
@@ -28,15 +28,23 @@
//
// Author: sameeragarwal@google.com (Sameer Agarwal)
+#include <algorithm>
+#include <cctype>
#include <string>
#include "ceres/types.h"
+#include "glog/logging.h"
namespace ceres {
#define CASESTR(x) case x: return #x
+#define STRENUM(x) if (value == #x) { *type = x; return true;}
-const char* LinearSolverTypeToString(LinearSolverType solver_type) {
- switch (solver_type) {
+static void UpperCase(string* input) {
+ std::transform(input->begin(), input->end(), input->begin(), ::toupper);
+}
+
+const char* LinearSolverTypeToString(LinearSolverType type) {
+ switch (type) {
CASESTR(DENSE_NORMAL_CHOLESKY);
CASESTR(DENSE_QR);
CASESTR(SPARSE_NORMAL_CHOLESKY);
@@ -49,9 +57,20 @@ const char* LinearSolverTypeToString(LinearSolverType solver_type) {
}
}
-const char* PreconditionerTypeToString(
- PreconditionerType preconditioner_type) {
- switch (preconditioner_type) {
+bool StringToLinearSolverType(string value, LinearSolverType* type) {
+ UpperCase(&value);
+ STRENUM(DENSE_NORMAL_CHOLESKY);
+ STRENUM(DENSE_QR);
+ STRENUM(SPARSE_NORMAL_CHOLESKY);
+ STRENUM(DENSE_SCHUR);
+ STRENUM(SPARSE_SCHUR);
+ STRENUM(ITERATIVE_SCHUR);
+ STRENUM(CGNR);
+ return false;
+}
+
+const char* PreconditionerTypeToString(PreconditionerType type) {
+ switch (type) {
CASESTR(IDENTITY);
CASESTR(JACOBI);
CASESTR(SCHUR_JACOBI);
@@ -62,9 +81,19 @@ const char* PreconditionerTypeToString(
}
}
+bool StringToPreconditionerType(string value, PreconditionerType* type) {
+ UpperCase(&value);
+ STRENUM(IDENTITY);
+ STRENUM(JACOBI);
+ STRENUM(SCHUR_JACOBI);
+ STRENUM(CLUSTER_JACOBI);
+ STRENUM(CLUSTER_TRIDIAGONAL);
+ return false;
+}
+
const char* SparseLinearAlgebraLibraryTypeToString(
- SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type) {
- switch (sparse_linear_algebra_library_type) {
+ SparseLinearAlgebraLibraryType type) {
+ switch (type) {
CASESTR(SUITE_SPARSE);
CASESTR(CX_SPARSE);
default:
@@ -72,19 +101,121 @@ const char* SparseLinearAlgebraLibraryTypeToString(
}
}
-const char* OrderingTypeToString(OrderingType ordering_type) {
- switch (ordering_type) {
- CASESTR(NATURAL);
- CASESTR(USER);
- CASESTR(SCHUR);
+
+bool StringToSparseLinearAlgebraLibraryType(
+ string value,
+ SparseLinearAlgebraLibraryType* type) {
+ UpperCase(&value);
+ STRENUM(SUITE_SPARSE);
+ STRENUM(CX_SPARSE);
+ return false;
+}
+
+const char* TrustRegionStrategyTypeToString(TrustRegionStrategyType type) {
+ switch (type) {
+ CASESTR(LEVENBERG_MARQUARDT);
+ CASESTR(DOGLEG);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToTrustRegionStrategyType(string value,
+ TrustRegionStrategyType* type) {
+ UpperCase(&value);
+ STRENUM(LEVENBERG_MARQUARDT);
+ STRENUM(DOGLEG);
+ return false;
+}
+
+const char* DoglegTypeToString(DoglegType type) {
+ switch (type) {
+ CASESTR(TRADITIONAL_DOGLEG);
+ CASESTR(SUBSPACE_DOGLEG);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToDoglegType(string value, DoglegType* type) {
+ UpperCase(&value);
+ STRENUM(TRADITIONAL_DOGLEG);
+ STRENUM(SUBSPACE_DOGLEG);
+ return false;
+}
+
+const char* MinimizerTypeToString(MinimizerType type) {
+ switch (type) {
+ CASESTR(TRUST_REGION);
+ CASESTR(LINE_SEARCH);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToMinimizerType(string value, MinimizerType* type) {
+ UpperCase(&value);
+ STRENUM(TRUST_REGION);
+ STRENUM(LINE_SEARCH);
+ return false;
+}
+
+const char* LineSearchDirectionTypeToString(LineSearchDirectionType type) {
+ switch (type) {
+ CASESTR(STEEPEST_DESCENT);
+ CASESTR(NONLINEAR_CONJUGATE_GRADIENT);
+ CASESTR(LBFGS);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToLineSearchDirectionType(string value,
+ LineSearchDirectionType* type) {
+ UpperCase(&value);
+ STRENUM(STEEPEST_DESCENT);
+ STRENUM(NONLINEAR_CONJUGATE_GRADIENT);
+ STRENUM(LBFGS);
+ return false;
+}
+
+const char* LineSearchTypeToString(LineSearchType type) {
+ switch (type) {
+ CASESTR(ARMIJO);
default:
return "UNKNOWN";
}
}
-const char* SolverTerminationTypeToString(
- SolverTerminationType termination_type) {
- switch (termination_type) {
+bool StringToLineSearchType(string value, LineSearchType* type) {
+ UpperCase(&value);
+ STRENUM(ARMIJO);
+ return false;
+}
+
+const char* NonlinearConjugateGradientTypeToString(
+ NonlinearConjugateGradientType type) {
+ switch (type) {
+ CASESTR(FLETCHER_REEVES);
+ CASESTR(POLAK_RIBIRERE);
+ CASESTR(HESTENES_STIEFEL);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToNonlinearConjugateGradientType(
+ string value,
+ NonlinearConjugateGradientType* type) {
+ UpperCase(&value);
+ STRENUM(FLETCHER_REEVES);
+ STRENUM(POLAK_RIBIRERE);
+ STRENUM(HESTENES_STIEFEL);
+ return false;
+}
+
+const char* SolverTerminationTypeToString(SolverTerminationType type) {
+ switch (type) {
CASESTR(NO_CONVERGENCE);
CASESTR(FUNCTION_TOLERANCE);
CASESTR(GRADIENT_TOLERANCE);
@@ -98,29 +229,20 @@ const char* SolverTerminationTypeToString(
}
}
-#if 0 /* UNUSED */
-static const char* SparseLinearAlgebraTypeToString(
- SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type) {
- switch (sparse_linear_algebra_library_type) {
- CASESTR(CX_SPARSE);
- CASESTR(SUITE_SPARSE);
- default:
- return "UNKNOWN";
- }
-}
-#endif
-
-const char* TrustRegionStrategyTypeToString(
- TrustRegionStrategyType trust_region_strategy_type) {
- switch (trust_region_strategy_type) {
- CASESTR(LEVENBERG_MARQUARDT);
- CASESTR(DOGLEG);
+const char* LinearSolverTerminationTypeToString(
+ LinearSolverTerminationType type) {
+ switch (type) {
+ CASESTR(TOLERANCE);
+ CASESTR(MAX_ITERATIONS);
+ CASESTR(STAGNATION);
+ CASESTR(FAILURE);
default:
return "UNKNOWN";
}
}
#undef CASESTR
+#undef STRENUM
bool IsSchurType(LinearSolverType type) {
return ((type == SPARSE_SCHUR) ||
@@ -128,4 +250,26 @@ bool IsSchurType(LinearSolverType type) {
(type == ITERATIVE_SCHUR));
}
+bool IsSparseLinearAlgebraLibraryTypeAvailable(
+ SparseLinearAlgebraLibraryType type) {
+ if (type == SUITE_SPARSE) {
+#ifdef CERES_NO_SUITESPARSE
+ return false;
+#else
+ return true;
+#endif
+ }
+
+ if (type == CX_SPARSE) {
+#ifdef CERES_NO_CXSPARSE
+ return false;
+#else
+ return true;
+#endif
+ }
+
+ LOG(WARNING) << "Unknown sparse linear algebra library " << type;
+ return false;
+}
+
} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/visibility.cc b/extern/libmv/third_party/ceres/internal/ceres/visibility.cc
index 564cc54493e..8e80fd121bb 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/visibility.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/visibility.cc
@@ -28,6 +28,8 @@
//
// Author: kushalav@google.com (Avanish Kushal)
+#include "ceres/visibility.h"
+
#include <cmath>
#include <ctime>
#include <algorithm>
@@ -36,7 +38,6 @@
#include <utility>
#include "ceres/block_structure.h"
#include "ceres/collections_port.h"
-#include "ceres/visibility.h"
#include "ceres/graph.h"
#include "glog/logging.h"
diff --git a/extern/libmv/third_party/ceres/internal/ceres/visibility.h b/extern/libmv/third_party/ceres/internal/ceres/visibility.h
index 692dd87201e..f29e3c6a0a8 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/visibility.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/visibility.h
@@ -42,7 +42,7 @@
namespace ceres {
namespace internal {
-class CompressedRowBlockStructure;
+struct CompressedRowBlockStructure;
// Given a compressed row block structure, computes the set of
// e_blocks "visible" to each f_block. If an e_block co-occurs with an
diff --git a/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc b/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc
index 4caad03d7a1..a75d6f0c17e 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc
@@ -65,17 +65,17 @@ static const double kSimilarityPenaltyWeight = 0.0;
#ifndef CERES_NO_SUITESPARSE
VisibilityBasedPreconditioner::VisibilityBasedPreconditioner(
const CompressedRowBlockStructure& bs,
- const LinearSolver::Options& options)
+ const Preconditioner::Options& options)
: options_(options),
num_blocks_(0),
num_clusters_(0),
factor_(NULL) {
- CHECK_GT(options_.num_eliminate_blocks, 0);
- CHECK(options_.preconditioner_type == SCHUR_JACOBI ||
- options_.preconditioner_type == CLUSTER_JACOBI ||
- options_.preconditioner_type == CLUSTER_TRIDIAGONAL)
- << "Unknown preconditioner type: " << options_.preconditioner_type;
- num_blocks_ = bs.cols.size() - options_.num_eliminate_blocks;
+ CHECK_GT(options_.elimination_groups.size(), 1);
+ CHECK_GT(options_.elimination_groups[0], 0);
+ CHECK(options_.type == CLUSTER_JACOBI ||
+ options_.type == CLUSTER_TRIDIAGONAL)
+ << "Unknown preconditioner type: " << options_.type;
+ num_blocks_ = bs.cols.size() - options_.elimination_groups[0];
CHECK_GT(num_blocks_, 0)
<< "Jacobian should have atleast 1 f_block for "
<< "visibility based preconditioning.";
@@ -83,14 +83,11 @@ VisibilityBasedPreconditioner::VisibilityBasedPreconditioner(
// Vector of camera block sizes
block_size_.resize(num_blocks_);
for (int i = 0; i < num_blocks_; ++i) {
- block_size_[i] = bs.cols[i + options_.num_eliminate_blocks].size;
+ block_size_[i] = bs.cols[i + options_.elimination_groups[0]].size;
}
const time_t start_time = time(NULL);
- switch (options_.preconditioner_type) {
- case SCHUR_JACOBI:
- ComputeSchurJacobiSparsity(bs);
- break;
+ switch (options_.type) {
case CLUSTER_JACOBI:
ComputeClusterJacobiSparsity(bs);
break;
@@ -130,24 +127,6 @@ VisibilityBasedPreconditioner::~VisibilityBasedPreconditioner() {
}
}
-// Determine the sparsity structure of the SCHUR_JACOBI
-// preconditioner. SCHUR_JACOBI is an extreme case of a visibility
-// based preconditioner where each camera block corresponds to a
-// cluster and there is no interaction between clusters.
-void VisibilityBasedPreconditioner::ComputeSchurJacobiSparsity(
- const CompressedRowBlockStructure& bs) {
- num_clusters_ = num_blocks_;
- cluster_membership_.resize(num_blocks_);
- cluster_pairs_.clear();
-
- // Each camea block is a member of its own cluster and the only
- // cluster pairs are the self edges (i,i).
- for (int i = 0; i < num_clusters_; ++i) {
- cluster_membership_[i] = i;
- cluster_pairs_.insert(make_pair(i, i));
- }
-}
-
// Determine the sparsity structure of the CLUSTER_JACOBI
// preconditioner. It clusters cameras using their scene
// visibility. The clusters form the diagonal blocks of the
@@ -155,7 +134,7 @@ void VisibilityBasedPreconditioner::ComputeSchurJacobiSparsity(
void VisibilityBasedPreconditioner::ComputeClusterJacobiSparsity(
const CompressedRowBlockStructure& bs) {
vector<set<int> > visibility;
- ComputeVisibility(bs, options_.num_eliminate_blocks, &visibility);
+ ComputeVisibility(bs, options_.elimination_groups[0], &visibility);
CHECK_EQ(num_blocks_, visibility.size());
ClusterCameras(visibility);
cluster_pairs_.clear();
@@ -173,7 +152,7 @@ void VisibilityBasedPreconditioner::ComputeClusterJacobiSparsity(
void VisibilityBasedPreconditioner::ComputeClusterTridiagonalSparsity(
const CompressedRowBlockStructure& bs) {
vector<set<int> > visibility;
- ComputeVisibility(bs, options_.num_eliminate_blocks, &visibility);
+ ComputeVisibility(bs, options_.elimination_groups[0], &visibility);
CHECK_EQ(num_blocks_, visibility.size());
ClusterCameras(visibility);
@@ -253,7 +232,7 @@ void VisibilityBasedPreconditioner::ComputeBlockPairsInPreconditioner(
int r = 0;
const int num_row_blocks = bs.rows.size();
- const int num_eliminate_blocks = options_.num_eliminate_blocks;
+ const int num_eliminate_blocks = options_.elimination_groups[0];
// Iterate over each row of the matrix. The block structure of the
// matrix is assumed to be sorted in order of the e_blocks/point
@@ -331,16 +310,16 @@ void VisibilityBasedPreconditioner::ComputeBlockPairsInPreconditioner(
void VisibilityBasedPreconditioner::InitEliminator(
const CompressedRowBlockStructure& bs) {
LinearSolver::Options eliminator_options;
- eliminator_options.num_eliminate_blocks = options_.num_eliminate_blocks;
+ eliminator_options.elimination_groups = options_.elimination_groups;
eliminator_options.num_threads = options_.num_threads;
- DetectStructure(bs, options_.num_eliminate_blocks,
+ DetectStructure(bs, options_.elimination_groups[0],
&eliminator_options.row_block_size,
&eliminator_options.e_block_size,
&eliminator_options.f_block_size);
eliminator_.reset(SchurEliminatorBase::Create(eliminator_options));
- eliminator_->Init(options_.num_eliminate_blocks, &bs);
+ eliminator_->Init(options_.elimination_groups[0], &bs);
}
// Update the values of the preconditioner matrix and factorize it.
@@ -364,13 +343,13 @@ bool VisibilityBasedPreconditioner::Update(const BlockSparseMatrixBase& A,
// Compute a subset of the entries of the Schur complement.
eliminator_->Eliminate(&A, b.data(), D, m_.get(), rhs.data());
- // Try factorizing the matrix. For SCHUR_JACOBI and CLUSTER_JACOBI,
- // this should always succeed modulo some numerical/conditioning
- // problems. For CLUSTER_TRIDIAGONAL, in general the preconditioner
- // matrix as constructed is not positive definite. However, we will
- // go ahead and try factorizing it. If it works, great, otherwise we
- // scale all the cells in the preconditioner corresponding to the
- // edges in the degree-2 forest and that guarantees positive
+ // Try factorizing the matrix. For CLUSTER_JACOBI, this should
+ // always succeed modulo some numerical/conditioning problems. For
+ // CLUSTER_TRIDIAGONAL, in general the preconditioner matrix as
+ // constructed is not positive definite. However, we will go ahead
+ // and try factorizing it. If it works, great, otherwise we scale
+ // all the cells in the preconditioner corresponding to the edges in
+ // the degree-2 forest and that guarantees positive
// definiteness. The proof of this fact can be found in Lemma 1 in
// "Visibility Based Preconditioning for Bundle Adjustment".
//
@@ -380,10 +359,10 @@ bool VisibilityBasedPreconditioner::Update(const BlockSparseMatrixBase& A,
// The scaling only affects the tri-diagonal case, since
// ScaleOffDiagonalBlocks only pays attenion to the cells that
- // belong to the edges of the degree-2 forest. In the SCHUR_JACOBI
- // and the CLUSTER_JACOBI cases, the preconditioner is guaranteed to
- // be positive semidefinite.
- if (!status && options_.preconditioner_type == CLUSTER_TRIDIAGONAL) {
+ // belong to the edges of the degree-2 forest. In the CLUSTER_JACOBI
+ // case, the preconditioner is guaranteed to be positive
+ // semidefinite.
+ if (!status && options_.type == CLUSTER_TRIDIAGONAL) {
VLOG(1) << "Unscaled factorization failed. Retrying with off-diagonal "
<< "scaling";
ScaleOffDiagonalCells();
diff --git a/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h b/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h
index 888c65eba3a..8a09c78d36a 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h
@@ -29,25 +29,19 @@
// Author: sameeragarwal@google.com (Sameer Agarwal)
//
// Preconditioners for linear systems that arise in Structure from
-// Motion problems. VisibilityBasedPreconditioner implements three
-// preconditioners:
+// Motion problems. VisibilityBasedPreconditioner implements:
//
-// SCHUR_JACOBI
// CLUSTER_JACOBI
// CLUSTER_TRIDIAGONAL
//
// Detailed descriptions of these preconditions beyond what is
// documented here can be found in
//
-// Bundle Adjustment in the Large
-// S. Agarwal, N. Snavely, S. Seitz & R. Szeliski, ECCV 2010
-// http://www.cs.washington.edu/homes/sagarwal/bal.pdf
-//
// Visibility Based Preconditioning for Bundle Adjustment
// A. Kushal & S. Agarwal, submitted to CVPR 2012
// http://www.cs.washington.edu/homes/sagarwal/vbp.pdf
//
-// The three preconditioners share enough code that its most efficient
+// The two preconditioners share enough code that its most efficient
// to implement them as part of the same code base.
#ifndef CERES_INTERNAL_VISIBILITY_BASED_PRECONDITIONER_H_
@@ -58,36 +52,26 @@
#include <utility>
#include "ceres/collections_port.h"
#include "ceres/graph.h"
-#include "ceres/linear_solver.h"
-#include "ceres/linear_operator.h"
-#include "ceres/suitesparse.h"
#include "ceres/internal/macros.h"
#include "ceres/internal/scoped_ptr.h"
+#include "ceres/preconditioner.h"
+#include "ceres/suitesparse.h"
namespace ceres {
namespace internal {
class BlockRandomAccessSparseMatrix;
class BlockSparseMatrixBase;
-class CompressedRowBlockStructure;
+struct CompressedRowBlockStructure;
class SchurEliminatorBase;
-// This class implements three preconditioners for Structure from
-// Motion/Bundle Adjustment problems. The name
+// This class implements visibility based preconditioners for
+// Structure from Motion/Bundle Adjustment problems. The name
// VisibilityBasedPreconditioner comes from the fact that the sparsity
// structure of the preconditioner matrix is determined by analyzing
// the visibility structure of the scene, i.e. which cameras see which
// points.
//
-// Strictly speaking, SCHUR_JACOBI is not a visibility based
-// preconditioner but it is an extreme case of CLUSTER_JACOBI, where
-// every cluster contains exactly one camera block. Treating it as a
-// special case of CLUSTER_JACOBI makes it easy to implement as part
-// of the same code base with no significant loss of performance.
-//
-// In the following, we will only discuss CLUSTER_JACOBI and
-// CLUSTER_TRIDIAGONAL.
-//
// The key idea of visibility based preconditioning is to identify
// cameras that we expect have strong interactions, and then using the
// entries in the Schur complement matrix corresponding to these
@@ -130,15 +114,15 @@ class SchurEliminatorBase;
//
// LinearSolver::Options options;
// options.preconditioner_type = CLUSTER_JACOBI;
-// options.num_eliminate_blocks = num_points;
+// options.elimination_groups.push_back(num_points);
+// options.elimination_groups.push_back(num_cameras);
// VisibilityBasedPreconditioner preconditioner(
// *A.block_structure(), options);
// preconditioner.Update(A, NULL);
// preconditioner.RightMultiply(x, y);
//
-
#ifndef CERES_NO_SUITESPARSE
-class VisibilityBasedPreconditioner : public LinearOperator {
+class VisibilityBasedPreconditioner : public Preconditioner {
public:
// Initialize the symbolic structure of the preconditioner. bs is
// the block structure of the linear system to be solved. It is used
@@ -146,48 +130,17 @@ class VisibilityBasedPreconditioner : public LinearOperator {
//
// It has the same structural requirement as other Schur complement
// based solvers. Please see schur_eliminator.h for more details.
- //
- // LinearSolver::Options::num_eliminate_blocks should be set to the
- // number of e_blocks in the block structure.
- //
- // TODO(sameeragarwal): The use of LinearSolver::Options should
- // ultimately be replaced with Preconditioner::Options and some sort
- // of preconditioner factory along the lines of
- // LinearSolver::CreateLinearSolver. I will wait to do this till I
- // create a general purpose block Jacobi preconditioner for general
- // sparse problems along with a CGLS solver.
VisibilityBasedPreconditioner(const CompressedRowBlockStructure& bs,
- const LinearSolver::Options& options);
+ const Preconditioner::Options& options);
virtual ~VisibilityBasedPreconditioner();
- // Update the numerical value of the preconditioner for the linear
- // system:
- //
- // | A | x = |b|
- // |diag(D)| |0|
- //
- // for some vector b. It is important that the matrix A have the
- // same block structure as the one used to construct this object.
- //
- // D can be NULL, in which case its interpreted as a diagonal matrix
- // of size zero.
- bool Update(const BlockSparseMatrixBase& A, const double* D);
-
-
- // LinearOperator interface. Since the operator is symmetric,
- // LeftMultiply and num_cols are just calls to RightMultiply and
- // num_rows respectively. Update() must be called before
- // RightMultiply can be called.
+ // Preconditioner interface
+ virtual bool Update(const BlockSparseMatrixBase& A, const double* D);
virtual void RightMultiply(const double* x, double* y) const;
- virtual void LeftMultiply(const double* x, double* y) const {
- RightMultiply(x, y);
- }
virtual int num_rows() const;
- virtual int num_cols() const { return num_rows(); }
friend class VisibilityBasedPreconditionerTest;
private:
- void ComputeSchurJacobiSparsity(const CompressedRowBlockStructure& bs);
void ComputeClusterJacobiSparsity(const CompressedRowBlockStructure& bs);
void ComputeClusterTridiagonalSparsity(const CompressedRowBlockStructure& bs);
void InitStorage(const CompressedRowBlockStructure& bs);
@@ -207,7 +160,7 @@ class VisibilityBasedPreconditioner : public LinearOperator {
bool IsBlockPairInPreconditioner(int block1, int block2) const;
bool IsBlockPairOffDiagonal(int block1, int block2) const;
- LinearSolver::Options options_;
+ Preconditioner::Options options_;
// Number of parameter blocks in the schur complement.
int num_blocks_;
@@ -249,10 +202,10 @@ class VisibilityBasedPreconditioner : public LinearOperator {
#else // SuiteSparse
// If SuiteSparse is not compiled in, the preconditioner is not
// available.
-class VisibilityBasedPreconditioner : public LinearOperator {
+class VisibilityBasedPreconditioner : public Preconditioner {
public:
VisibilityBasedPreconditioner(const CompressedRowBlockStructure& bs,
- const LinearSolver::Options& options) {
+ const Preconditioner::Options& options) {
LOG(FATAL) << "Visibility based preconditioning is not available. Please "
"build Ceres with SuiteSparse.";
}
diff --git a/extern/libmv/third_party/ceres/internal/ceres/wall_time.cc b/extern/libmv/third_party/ceres/internal/ceres/wall_time.cc
new file mode 100644
index 00000000000..e63d20c0ab1
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/wall_time.cc
@@ -0,0 +1,96 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 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: strandmark@google.com (Petter Strandmark)
+
+#include "ceres/wall_time.h"
+
+#ifdef CERES_USE_OPENMP
+#include <omp.h>
+#else
+#include <ctime>
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sys/time.h>
+#endif
+
+namespace ceres {
+namespace internal {
+
+double WallTimeInSeconds() {
+#ifdef CERES_USE_OPENMP
+ return omp_get_wtime();
+#else
+#ifdef _WIN32
+ return static_cast<double>(std::time(NULL));
+#else
+ timeval time_val;
+ gettimeofday(&time_val, NULL);
+ return (time_val.tv_sec + time_val.tv_usec * 1e-6);
+#endif
+#endif
+}
+
+EventLogger::EventLogger(const string& logger_name)
+ : start_time_(WallTimeInSeconds()),
+ last_event_time_(start_time_),
+ events_("") {
+ StringAppendF(&events_,
+ "\n%s\n Delta Cumulative\n",
+ logger_name.c_str());
+}
+
+EventLogger::~EventLogger() {
+ if (VLOG_IS_ON(3)) {
+ AddEvent("Total");
+ VLOG(2) << "\n" << events_ << "\n";
+ }
+}
+
+void EventLogger::AddEvent(const string& event_name) {
+ if (!VLOG_IS_ON(3)) {
+ return;
+ }
+
+ const double current_time = WallTimeInSeconds();
+ const double relative_time_delta = current_time - last_event_time_;
+ const double absolute_time_delta = current_time - start_time_;
+ last_event_time_ = current_time;
+
+ StringAppendF(&events_,
+ " %25s : %10.5f %10.5f\n",
+ event_name.c_str(),
+ relative_time_delta,
+ absolute_time_delta);
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/wall_time.h b/extern/libmv/third_party/ceres/internal/ceres/wall_time.h
new file mode 100644
index 00000000000..45f65ca1aa5
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/wall_time.h
@@ -0,0 +1,88 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 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: strandmark@google.com (Petter Strandmark)
+
+#ifndef CERES_INTERNAL_WALL_TIME_H_
+#define CERES_INTERNAL_WALL_TIME_H_
+
+#include <map>
+
+#include "ceres/internal/port.h"
+#include "ceres/stringprintf.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+// Returns time, in seconds, from some arbitrary starting point. If
+// OpenMP is available then the high precision openmp_get_wtime()
+// function is used. Otherwise on unixes, gettimeofday is used. The
+// granularity is in seconds on windows systems.
+double WallTimeInSeconds();
+
+// Log a series of events, recording for each event the time elapsed
+// since the last event and since the creation of the object.
+//
+// The information is output to VLOG(3) upon destruction. A
+// name::Total event is added as the final event right before
+// destruction.
+//
+// Example usage:
+//
+// void Foo() {
+// EventLogger event_logger("Foo");
+// Bar1();
+// event_logger.AddEvent("Bar1")
+// Bar2();
+// event_logger.AddEvent("Bar2")
+// Bar3();
+// }
+//
+// Will produce output that looks like
+//
+// Foo
+// Bar1: time1 time1
+// Bar2: time2 time1 + time2;
+// Total: time3 time1 + time2 + time3;
+class EventLogger {
+ public:
+ explicit EventLogger(const string& logger_name);
+ ~EventLogger();
+ void AddEvent(const string& event_name);
+
+ private:
+ const double start_time_;
+ double last_event_time_;
+ string events_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_WALL_TIME_H_
diff --git a/extern/libmv/third_party/ceres/patches/collections_port.h.mingw.patch b/extern/libmv/third_party/ceres/patches/collections_port.h.mingw.patch
deleted file mode 100644
index c01a17c7992..00000000000
--- a/extern/libmv/third_party/ceres/patches/collections_port.h.mingw.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/internal/ceres/collections_port.h b/internal/ceres/collections_port.h
-index a356cc0..c2fce90 100644
---- a/internal/ceres/collections_port.h
-+++ b/internal/ceres/collections_port.h
-@@ -77,7 +77,7 @@ struct HashMap : std::tr1::unordered_map<K, V> {};
- template<typename K>
- struct HashSet : std::tr1::unordered_set<K> {};
-
--#ifdef _WIN32
-+#if defined(_WIN32) && !defined(__MINGW64__) && !defined(__MINGW32__)
- #define GG_LONGLONG(x) x##I64
- #define GG_ULONGLONG(x) x##UI64
- #else
diff --git a/extern/libmv/third_party/ceres/patches/msvc_glog_fix.patch b/extern/libmv/third_party/ceres/patches/msvc_glog_fix.patch
deleted file mode 100644
index f3200fb8e0a..00000000000
--- a/extern/libmv/third_party/ceres/patches/msvc_glog_fix.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-diff --git a/internal/ceres/block_random_access_dense_matrix.cc b/internal/ceres/block_random_access_dense_matrix.cc
-index aedfc74..0f95e89 100644
---- a/internal/ceres/block_random_access_dense_matrix.cc
-+++ b/internal/ceres/block_random_access_dense_matrix.cc
-@@ -28,12 +28,12 @@
- //
- // Author: sameeragarwal@google.com (Sameer Agarwal)
-
-+#include "glog/logging.h"
- #include "ceres/block_random_access_dense_matrix.h"
-
- #include <vector>
- #include "ceres/internal/eigen.h"
- #include "ceres/internal/scoped_ptr.h"
--#include "glog/logging.h"
-
- namespace ceres {
- namespace internal {
-diff --git a/internal/ceres/block_random_access_sparse_matrix.cc b/internal/ceres/block_random_access_sparse_matrix.cc
-index f789436..9ed62ce 100644
---- a/internal/ceres/block_random_access_sparse_matrix.cc
-+++ b/internal/ceres/block_random_access_sparse_matrix.cc
-@@ -28,6 +28,7 @@
- //
- // Author: sameeragarwal@google.com (Sameer Agarwal)
-
-+#include "glog/logging.h"
- #include "ceres/block_random_access_sparse_matrix.h"
-
- #include <algorithm>
-@@ -39,7 +40,6 @@
- #include "ceres/mutex.h"
- #include "ceres/triplet_sparse_matrix.h"
- #include "ceres/types.h"
--#include "glog/logging.h"
-
- namespace ceres {
- namespace internal {
-diff --git a/internal/ceres/schur_complement_solver.cc b/internal/ceres/schur_complement_solver.cc
-index b9224d8..2cbe78d 100644
---- a/internal/ceres/schur_complement_solver.cc
-+++ b/internal/ceres/schur_complement_solver.cc
-@@ -38,6 +38,7 @@
- #endif // CERES_NO_CXSPARSE
-
- #include "Eigen/Dense"
-+#include "glog/logging.h"
- #include "ceres/block_random_access_dense_matrix.h"
- #include "ceres/block_random_access_matrix.h"
- #include "ceres/block_random_access_sparse_matrix.h"
diff --git a/extern/libmv/third_party/ceres/patches/no_previous_declaration_fix.patch b/extern/libmv/third_party/ceres/patches/no_previous_declaration_fix.patch
deleted file mode 100644
index 03f1c500d9a..00000000000
--- a/extern/libmv/third_party/ceres/patches/no_previous_declaration_fix.patch
+++ /dev/null
@@ -1,199 +0,0 @@
-diff --git a/internal/ceres/file.cc b/internal/ceres/file.cc
-index 387f359..6fe7557 100644
---- a/internal/ceres/file.cc
-+++ b/internal/ceres/file.cc
-@@ -31,6 +31,7 @@
- // Really simple file IO.
-
- #include <cstdio>
-+#include "file.h"
- #include "glog/logging.h"
-
- namespace ceres {
-diff --git a/internal/ceres/linear_least_squares_problems.cc b/internal/ceres/linear_least_squares_problems.cc
-index 3e3bcd0..a91e254 100644
---- a/internal/ceres/linear_least_squares_problems.cc
-+++ b/internal/ceres/linear_least_squares_problems.cc
-@@ -573,13 +573,13 @@ LinearLeastSquaresProblem* LinearLeastSquaresProblem3() {
- return problem;
- }
-
--bool DumpLinearLeastSquaresProblemToConsole(const string& directory,
-- int iteration,
-- const SparseMatrix* A,
-- const double* D,
-- const double* b,
-- const double* x,
-- int num_eliminate_blocks) {
-+static bool DumpLinearLeastSquaresProblemToConsole(const string& directory,
-+ int iteration,
-+ const SparseMatrix* A,
-+ const double* D,
-+ const double* b,
-+ const double* x,
-+ int num_eliminate_blocks) {
- CHECK_NOTNULL(A);
- Matrix AA;
- A->ToDenseMatrix(&AA);
-@@ -601,13 +601,13 @@ bool DumpLinearLeastSquaresProblemToConsole(const string& directory,
- };
-
- #ifndef CERES_NO_PROTOCOL_BUFFERS
--bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
-- int iteration,
-- const SparseMatrix* A,
-- const double* D,
-- const double* b,
-- const double* x,
-- int num_eliminate_blocks) {
-+static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
-+ int iteration,
-+ const SparseMatrix* A,
-+ const double* D,
-+ const double* b,
-+ const double* x,
-+ int num_eliminate_blocks) {
- CHECK_NOTNULL(A);
- LinearLeastSquaresProblemProto lsqp;
- A->ToProto(lsqp.mutable_a());
-@@ -641,13 +641,13 @@ bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
- return true;
- }
- #else
--bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
-- int iteration,
-- const SparseMatrix* A,
-- const double* D,
-- const double* b,
-- const double* x,
-- int num_eliminate_blocks) {
-+static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
-+ int iteration,
-+ const SparseMatrix* A,
-+ const double* D,
-+ const double* b,
-+ const double* x,
-+ int num_eliminate_blocks) {
- LOG(ERROR) << "Dumping least squares problems is only "
- << "supported when Ceres is compiled with "
- << "protocol buffer support.";
-@@ -655,9 +655,9 @@ bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
- }
- #endif
-
--void WriteArrayToFileOrDie(const string& filename,
-- const double* x,
-- const int size) {
-+static void WriteArrayToFileOrDie(const string& filename,
-+ const double* x,
-+ const int size) {
- CHECK_NOTNULL(x);
- VLOG(2) << "Writing array to: " << filename;
- FILE* fptr = fopen(filename.c_str(), "w");
-@@ -668,13 +668,13 @@ void WriteArrayToFileOrDie(const string& filename,
- fclose(fptr);
- }
-
--bool DumpLinearLeastSquaresProblemToTextFile(const string& directory,
-- int iteration,
-- const SparseMatrix* A,
-- const double* D,
-- const double* b,
-- const double* x,
-- int num_eliminate_blocks) {
-+static bool DumpLinearLeastSquaresProblemToTextFile(const string& directory,
-+ int iteration,
-+ const SparseMatrix* A,
-+ const double* D,
-+ const double* b,
-+ const double* x,
-+ int num_eliminate_blocks) {
- CHECK_NOTNULL(A);
- string format_string = JoinPath(directory,
- "lm_iteration_%03d");
-diff --git a/internal/ceres/residual_block_utils.cc b/internal/ceres/residual_block_utils.cc
-index ff18e21..9442bb2 100644
---- a/internal/ceres/residual_block_utils.cc
-+++ b/internal/ceres/residual_block_utils.cc
-@@ -63,7 +63,7 @@ void InvalidateEvaluation(const ResidualBlock& block,
-
- // Utility routine to print an array of doubles to a string. If the
- // array pointer is NULL, it is treated as an array of zeros.
--void AppendArrayToString(const int size, const double* x, string* result) {
-+static void AppendArrayToString(const int size, const double* x, string* result) {
- for (int i = 0; i < size; ++i) {
- if (x == NULL) {
- StringAppendF(result, "Not Computed ");
-diff --git a/internal/ceres/solver_impl.cc b/internal/ceres/solver_impl.cc
-index 2802a75..8ef5b98 100644
---- a/internal/ceres/solver_impl.cc
-+++ b/internal/ceres/solver_impl.cc
-@@ -685,8 +685,8 @@ bool SolverImpl::ApplyUserOrdering(const ProblemImpl& problem_impl,
- // Find the minimum index of any parameter block to the given residual.
- // Parameter blocks that have indices greater than num_eliminate_blocks are
- // considered to have an index equal to num_eliminate_blocks.
--int MinParameterBlock(const ResidualBlock* residual_block,
-- int num_eliminate_blocks) {
-+static int MinParameterBlock(const ResidualBlock* residual_block,
-+ int num_eliminate_blocks) {
- int min_parameter_block_position = num_eliminate_blocks;
- for (int i = 0; i < residual_block->NumParameterBlocks(); ++i) {
- ParameterBlock* parameter_block = residual_block->parameter_blocks()[i];
-diff --git a/internal/ceres/split.cc b/internal/ceres/split.cc
-index 4fa1bd4..c65c8a5 100644
---- a/internal/ceres/split.cc
-+++ b/internal/ceres/split.cc
-@@ -31,6 +31,7 @@
- #include <string>
- #include <vector>
- #include <iterator>
-+#include "ceres/split.h"
- #include "ceres/internal/port.h"
-
- namespace ceres {
-diff --git a/internal/ceres/stringprintf.cc b/internal/ceres/stringprintf.cc
-index c0f3522..396a48b 100644
---- a/internal/ceres/stringprintf.cc
-+++ b/internal/ceres/stringprintf.cc
-@@ -34,6 +34,7 @@
- #include <string>
- #include <vector>
-
-+#include "ceres/stringprintf.h"
- #include "ceres/internal/port.h"
-
- namespace ceres {
-diff --git a/internal/ceres/types.cc b/internal/ceres/types.cc
-index 2e950c5..05e573f 100644
---- a/internal/ceres/types.cc
-+++ b/internal/ceres/types.cc
-@@ -98,7 +98,8 @@ const char* SolverTerminationTypeToString(
- }
- }
-
--const char* SparseLinearAlgebraTypeToString(
-+#if 0 /* UNUSED */
-+static const char* SparseLinearAlgebraTypeToString(
- SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type) {
- switch (sparse_linear_algebra_library_type) {
- CASESTR(CX_SPARSE);
-@@ -107,6 +108,7 @@ const char* SparseLinearAlgebraTypeToString(
- return "UNKNOWN";
- }
- }
-+#endif
-
- const char* TrustRegionStrategyTypeToString(
- TrustRegionStrategyType trust_region_strategy_type) {
-diff --git a/internal/ceres/visibility.cc b/internal/ceres/visibility.cc
-index 9d80654..564cc54 100644
---- a/internal/ceres/visibility.cc
-+++ b/internal/ceres/visibility.cc
-@@ -36,6 +36,7 @@
- #include <utility>
- #include "ceres/block_structure.h"
- #include "ceres/collections_port.h"
-+#include "ceres/visibility.h"
- #include "ceres/graph.h"
- #include "glog/logging.h"
-
diff --git a/extern/libmv/third_party/ceres/patches/series b/extern/libmv/third_party/ceres/patches/series
index a6874318923..e69de29bb2d 100644
--- a/extern/libmv/third_party/ceres/patches/series
+++ b/extern/libmv/third_party/ceres/patches/series
@@ -1,3 +0,0 @@
-collections_port.h.mingw.patch
-msvc_glog_fix.patch
-no_previous_declaration_fix.patch \ No newline at end of file
diff --git a/extern/libmv/third_party/ldl/CMakeLists.txt b/extern/libmv/third_party/ldl/CMakeLists.txt
deleted file mode 100644
index db2d40e2612..00000000000
--- a/extern/libmv/third_party/ldl/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-include_directories(../ufconfig)
-include_directories(Include)
-add_library(ldl Source/ldl.c)
-
-LIBMV_INSTALL_THIRD_PARTY_LIB(ldl)
diff --git a/extern/libmv/third_party/ldl/Doc/ChangeLog b/extern/libmv/third_party/ldl/Doc/ChangeLog
deleted file mode 100644
index 48c322d3e77..00000000000
--- a/extern/libmv/third_party/ldl/Doc/ChangeLog
+++ /dev/null
@@ -1,39 +0,0 @@
-May 31, 2007: version 2.0.0
-
- * C-callable 64-bit version added
-
- * ported to 64-bit MATLAB
-
- * subdirectories added (Source/, Include/, Lib/, Demo/, Doc/, MATLAB/)
-
-Dec 12, 2006: version 1.3.4
-
- * minor MATLAB cleanup
-
-Sept 11, 2006: version 1.3.1
-
- * The ldl m-file renamed to ldlsparse, to avoid name conflict with the
- new MATLAB ldl function (in MATLAB 7.3).
-
-Apr 30, 2006: version 1.3
-
- * requires AMD v2.0. ldlmain.c demo program modified, since AMD can now
- handle jumbled matrices. Minor change to Makefile.
-
-Aug 30, 2005:
-
- * Makefile changed to use ../UFconfig/UFconfig.mk. License changed to
- GNU LGPL.
-
-July 4, 2005:
-
- * user guide added. Since no changes to the code were made,
- the version number (1.1) and code release date (Apr 22, 2005)
- were left unchanged.
-
-Apr. 22, 2005: LDL v1.1 released.
-
- * No real changes were made. The code was revised so
- that each routine fits on a single page in the documentation.
-
-Dec 31, 2003: LDL v1.0 released.
diff --git a/extern/libmv/third_party/ldl/Doc/lesser.txt b/extern/libmv/third_party/ldl/Doc/lesser.txt
deleted file mode 100644
index 8add30ad590..00000000000
--- a/extern/libmv/third_party/ldl/Doc/lesser.txt
+++ /dev/null
@@ -1,504 +0,0 @@
- GNU LESSER GENERAL PUBLIC LICENSE
- Version 2.1, February 1999
-
- Copyright (C) 1991, 1999 Free Software Foundation, Inc.
- 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-[This is the first released version of the Lesser GPL. It also counts
- as the successor of the GNU Library Public License, version 2, hence
- the version number 2.1.]
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-
- This license, the Lesser General Public License, applies to some
-specially designated software packages--typically libraries--of the
-Free Software Foundation and other authors who decide to use it. You
-can use it too, but we suggest you first think carefully about whether
-this license or the ordinary General Public License is the better
-strategy to use in any particular case, based on the explanations below.
-
- When we speak of free software, we are referring to freedom of use,
-not price. Our General Public Licenses are designed to make sure that
-you have the freedom to distribute copies of free software (and charge
-for this service if you wish); that you receive source code or can get
-it if you want it; that you can change the software and use pieces of
-it in new free programs; and that you are informed that you can do
-these things.
-
- To protect your rights, we need to make restrictions that forbid
-distributors to deny you these rights or to ask you to surrender these
-rights. These restrictions translate to certain responsibilities for
-you if you distribute copies of the library or if you modify it.
-
- For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you. You must make sure that they, too, receive or can get the source
-code. If you link other code with the library, you must provide
-complete object files to the recipients, so that they can relink them
-with the library after making changes to the library and recompiling
-it. And you must show them these terms so they know their rights.
-
- We protect your rights with a two-step method: (1) we copyright the
-library, and (2) we offer you this license, which gives you legal
-permission to copy, distribute and/or modify the library.
-
- To protect each distributor, we want to make it very clear that
-there is no warranty for the free library. Also, if the library is
-modified by someone else and passed on, the recipients should know
-that what they have is not the original version, so that the original
-author's reputation will not be affected by problems that might be
-introduced by others.
-
- Finally, software patents pose a constant threat to the existence of
-any free program. We wish to make sure that a company cannot
-effectively restrict the users of a free program by obtaining a
-restrictive license from a patent holder. Therefore, we insist that
-any patent license obtained for a version of the library must be
-consistent with the full freedom of use specified in this license.
-
- Most GNU software, including some libraries, is covered by the
-ordinary GNU General Public License. This license, the GNU Lesser
-General Public License, applies to certain designated libraries, and
-is quite different from the ordinary General Public License. We use
-this license for certain libraries in order to permit linking those
-libraries into non-free programs.
-
- When a program is linked with a library, whether statically or using
-a shared library, the combination of the two is legally speaking a
-combined work, a derivative of the original library. The ordinary
-General Public License therefore permits such linking only if the
-entire combination fits its criteria of freedom. The Lesser General
-Public License permits more lax criteria for linking other code with
-the library.
-
- We call this license the "Lesser" General Public License because it
-does Less to protect the user's freedom than the ordinary General
-Public License. It also provides other free software developers Less
-of an advantage over competing non-free programs. These disadvantages
-are the reason we use the ordinary General Public License for many
-libraries. However, the Lesser license provides advantages in certain
-special circumstances.
-
- For example, on rare occasions, there may be a special need to
-encourage the widest possible use of a certain library, so that it becomes
-a de-facto standard. To achieve this, non-free programs must be
-allowed to use the library. A more frequent case is that a free
-library does the same job as widely used non-free libraries. In this
-case, there is little to gain by limiting the free library to free
-software only, so we use the Lesser General Public License.
-
- In other cases, permission to use a particular library in non-free
-programs enables a greater number of people to use a large body of
-free software. For example, permission to use the GNU C Library in
-non-free programs enables many more people to use the whole GNU
-operating system, as well as its variant, the GNU/Linux operating
-system.
-
- Although the Lesser General Public License is Less protective of the
-users' freedom, it does ensure that the user of a program that is
-linked with the Library has the freedom and the wherewithal to run
-that program using a modified version of the Library.
-
- The precise terms and conditions for copying, distribution and
-modification follow. Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library". The
-former contains code derived from the library, whereas the latter must
-be combined with the library in order to run.
-
- GNU LESSER GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License Agreement applies to any software library or other
-program which contains a notice placed by the copyright holder or
-other authorized party saying it may be distributed under the terms of
-this Lesser General Public License (also called "this License").
-Each licensee is addressed as "you".
-
- A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-
- The "Library", below, refers to any such software library or work
-which has been distributed under these terms. A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language. (Hereinafter, translation is
-included without limitation in the term "modification".)
-
- "Source code" for a work means the preferred form of the work for
-making modifications to it. For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation
-and installation of the library.
-
- Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it). Whether that is true depends on what the Library does
-and what the program that uses the Library does.
-
- 1. You may copy and distribute verbatim copies of the Library's
-complete source code as you receive it, in any medium, provided that
-you conspicuously and appropriately publish on each copy an
-appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the
-Library.
-
- You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-
- 2. You may modify your copy or copies of the Library or any portion
-of it, thus forming a work based on the Library, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) The modified work must itself be a software library.
-
- b) You must cause the files modified to carry prominent notices
- stating that you changed the files and the date of any change.
-
- c) You must cause the whole of the work to be licensed at no
- charge to all third parties under the terms of this License.
-
- d) If a facility in the modified Library refers to a function or a
- table of data to be supplied by an application program that uses
- the facility, other than as an argument passed when the facility
- is invoked, then you must make a good faith effort to ensure that,
- in the event an application does not supply such function or
- table, the facility still operates, and performs whatever part of
- its purpose remains meaningful.
-
- (For example, a function in a library to compute square roots has
- a purpose that is entirely well-defined independent of the
- application. Therefore, Subsection 2d requires that any
- application-supplied function or table used by this function must
- be optional: if the application does not supply it, the square
- root function must still compute square roots.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Library.
-
-In addition, mere aggregation of another work not based on the Library
-with the Library (or with a work based on the Library) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may opt to apply the terms of the ordinary GNU General Public
-License instead of this License to a given copy of the Library. To do
-this, you must alter all the notices that refer to this License, so
-that they refer to the ordinary GNU General Public License, version 2,
-instead of to this License. (If a newer version than version 2 of the
-ordinary GNU General Public License has appeared, then you can specify
-that version instead if you wish.) Do not make any other change in
-these notices.
-
- Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-
- This option is useful when you wish to copy part of the code of
-the Library into a program that is not a library.
-
- 4. You may copy and distribute the Library (or a portion or
-derivative of it, under Section 2) in object code or executable form
-under the terms of Sections 1 and 2 above provided that you accompany
-it with the complete corresponding machine-readable source code, which
-must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange.
-
- If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to
-distribute the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 5. A program that contains no derivative of any portion of the
-Library, but is designed to work with the Library by being compiled or
-linked with it, is called a "work that uses the Library". Such a
-work, in isolation, is not a derivative work of the Library, and
-therefore falls outside the scope of this License.
-
- However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library". The executable is therefore covered by this License.
-Section 6 states terms for distribution of such executables.
-
- When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library. The
-threshold for this to be true is not precisely defined by law.
-
- If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work. (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-
- Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6,
-whether or not they are linked directly with the Library itself.
-
- 6. As an exception to the Sections above, you may also combine or
-link a "work that uses the Library" with the Library to produce a
-work containing portions of the Library, and distribute that work
-under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-
- You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License. You must supply a copy of this License. If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License. Also, you must do one
-of these things:
-
- a) Accompany the work with the complete corresponding
- machine-readable source code for the Library including whatever
- changes were used in the work (which must be distributed under
- Sections 1 and 2 above); and, if the work is an executable linked
- with the Library, with the complete machine-readable "work that
- uses the Library", as object code and/or source code, so that the
- user can modify the Library and then relink to produce a modified
- executable containing the modified Library. (It is understood
- that the user who changes the contents of definitions files in the
- Library will not necessarily be able to recompile the application
- to use the modified definitions.)
-
- b) Use a suitable shared library mechanism for linking with the
- Library. A suitable mechanism is one that (1) uses at run time a
- copy of the library already present on the user's computer system,
- rather than copying library functions into the executable, and (2)
- will operate properly with a modified version of the library, if
- the user installs one, as long as the modified version is
- interface-compatible with the version that the work was made with.
-
- c) Accompany the work with a written offer, valid for at
- least three years, to give the same user the materials
- specified in Subsection 6a, above, for a charge no more
- than the cost of performing this distribution.
-
- d) If distribution of the work is made by offering access to copy
- from a designated place, offer equivalent access to copy the above
- specified materials from the same place.
-
- e) Verify that the user has already received a copy of these
- materials or that you have already sent this user a copy.
-
- For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it. However, as a special exception,
-the materials to be distributed need not include anything that is
-normally distributed (in either source or binary form) with the major
-components (compiler, kernel, and so on) of the operating system on
-which the executable runs, unless that component itself accompanies
-the executable.
-
- It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system. Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-
- 7. You may place library facilities that are a work based on the
-Library side-by-side in a single library together with other library
-facilities not covered by this License, and distribute such a combined
-library, provided that the separate distribution of the work based on
-the Library and of the other library facilities is otherwise
-permitted, and provided that you do these two things:
-
- a) Accompany the combined library with a copy of the same work
- based on the Library, uncombined with any other library
- facilities. This must be distributed under the terms of the
- Sections above.
-
- b) Give prominent notice with the combined library of the fact
- that part of it is a work based on the Library, and explaining
- where to find the accompanying uncombined form of the same work.
-
- 8. You may not copy, modify, sublicense, link with, or distribute
-the Library except as expressly provided under this License. Any
-attempt otherwise to copy, modify, sublicense, link with, or
-distribute the Library is void, and will automatically terminate your
-rights under this License. However, parties who have received copies,
-or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
- 9. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Library or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Library (or any work based on the
-Library), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-
- 10. Each time you redistribute the Library (or any work based on the
-Library), the recipient automatically receives a license from the
-original licensor to copy, distribute, link with or modify the Library
-subject to these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties with
-this License.
-
- 11. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Library at all. For example, if a patent
-license would not permit royalty-free redistribution of the Library by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Library.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply,
-and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 12. If the distribution and/or use of the Library is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Library under this License may add
-an explicit geographical distribution limitation excluding those countries,
-so that distribution is permitted only in or among countries not thus
-excluded. In such case, this License incorporates the limitation as if
-written in the body of this License.
-
- 13. The Free Software Foundation may publish revised and/or new
-versions of the Lesser General Public License from time to time.
-Such new versions will be similar in spirit to the present version,
-but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Library
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation. If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-
- 14. If you wish to incorporate parts of the Library into other free
-programs whose distribution conditions are incompatible with these,
-write to the author to ask for permission. For software which is
-copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this. Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
-
- NO WARRANTY
-
- 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Libraries
-
- If you develop a new library, and you want it to be of the greatest
-possible use to the public, we recommend making it free software that
-everyone can redistribute and change. You can do so by permitting
-redistribution under these terms (or, alternatively, under the terms of the
-ordinary General Public License).
-
- To apply these terms, attach the following notices to the library. It is
-safest to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least the
-"copyright" line and a pointer to where the full notice is found.
-
- <one line to give the library's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-Also add information on how to contact you by electronic and paper mail.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the library, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the
- library `Frob' (a library for tweaking knobs) written by James Random Hacker.
-
- <signature of Ty Coon>, 1 April 1990
- Ty Coon, President of Vice
-
-That's all there is to it!
-
-
diff --git a/extern/libmv/third_party/ldl/Include/ldl.h b/extern/libmv/third_party/ldl/Include/ldl.h
deleted file mode 100644
index 5840be322f7..00000000000
--- a/extern/libmv/third_party/ldl/Include/ldl.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/* ========================================================================== */
-/* === ldl.h: include file for the LDL package ============================= */
-/* ========================================================================== */
-
-/* LDL Copyright (c) Timothy A Davis,
- * University of Florida. All Rights Reserved. See README for the License.
- */
-
-#include "UFconfig.h"
-
-#ifdef LDL_LONG
-#define LDL_int UF_long
-#define LDL_ID UF_long_id
-
-#define LDL_symbolic ldl_l_symbolic
-#define LDL_numeric ldl_l_numeric
-#define LDL_lsolve ldl_l_lsolve
-#define LDL_dsolve ldl_l_dsolve
-#define LDL_ltsolve ldl_l_ltsolve
-#define LDL_perm ldl_l_perm
-#define LDL_permt ldl_l_permt
-#define LDL_valid_perm ldl_l_valid_perm
-#define LDL_valid_matrix ldl_l_valid_matrix
-
-#else
-#define LDL_int int
-#define LDL_ID "%d"
-
-#define LDL_symbolic ldl_symbolic
-#define LDL_numeric ldl_numeric
-#define LDL_lsolve ldl_lsolve
-#define LDL_dsolve ldl_dsolve
-#define LDL_ltsolve ldl_ltsolve
-#define LDL_perm ldl_perm
-#define LDL_permt ldl_permt
-#define LDL_valid_perm ldl_valid_perm
-#define LDL_valid_matrix ldl_valid_matrix
-
-#endif
-
-/* ========================================================================== */
-/* === int version ========================================================== */
-/* ========================================================================== */
-
-void ldl_symbolic (int n, int Ap [ ], int Ai [ ], int Lp [ ],
- int Parent [ ], int Lnz [ ], int Flag [ ], int P [ ], int Pinv [ ]) ;
-
-int ldl_numeric (int n, int Ap [ ], int Ai [ ], double Ax [ ],
- int Lp [ ], int Parent [ ], int Lnz [ ], int Li [ ], double Lx [ ],
- double D [ ], double Y [ ], int Pattern [ ], int Flag [ ],
- int P [ ], int Pinv [ ]) ;
-
-void ldl_lsolve (int n, double X [ ], int Lp [ ], int Li [ ],
- double Lx [ ]) ;
-
-void ldl_dsolve (int n, double X [ ], double D [ ]) ;
-
-void ldl_ltsolve (int n, double X [ ], int Lp [ ], int Li [ ],
- double Lx [ ]) ;
-
-void ldl_perm (int n, double X [ ], double B [ ], int P [ ]) ;
-void ldl_permt (int n, double X [ ], double B [ ], int P [ ]) ;
-
-int ldl_valid_perm (int n, int P [ ], int Flag [ ]) ;
-int ldl_valid_matrix ( int n, int Ap [ ], int Ai [ ]) ;
-
-/* ========================================================================== */
-/* === long version ========================================================= */
-/* ========================================================================== */
-
-void ldl_l_symbolic (UF_long n, UF_long Ap [ ], UF_long Ai [ ], UF_long Lp [ ],
- UF_long Parent [ ], UF_long Lnz [ ], UF_long Flag [ ], UF_long P [ ],
- UF_long Pinv [ ]) ;
-
-UF_long ldl_l_numeric (UF_long n, UF_long Ap [ ], UF_long Ai [ ], double Ax [ ],
- UF_long Lp [ ], UF_long Parent [ ], UF_long Lnz [ ], UF_long Li [ ],
- double Lx [ ], double D [ ], double Y [ ], UF_long Pattern [ ],
- UF_long Flag [ ], UF_long P [ ], UF_long Pinv [ ]) ;
-
-void ldl_l_lsolve (UF_long n, double X [ ], UF_long Lp [ ], UF_long Li [ ],
- double Lx [ ]) ;
-
-void ldl_l_dsolve (UF_long n, double X [ ], double D [ ]) ;
-
-void ldl_l_ltsolve (UF_long n, double X [ ], UF_long Lp [ ], UF_long Li [ ],
- double Lx [ ]) ;
-
-void ldl_l_perm (UF_long n, double X [ ], double B [ ], UF_long P [ ]) ;
-void ldl_l_permt (UF_long n, double X [ ], double B [ ], UF_long P [ ]) ;
-
-UF_long ldl_l_valid_perm (UF_long n, UF_long P [ ], UF_long Flag [ ]) ;
-UF_long ldl_l_valid_matrix ( UF_long n, UF_long Ap [ ], UF_long Ai [ ]) ;
-
-/* ========================================================================== */
-/* === LDL version ========================================================== */
-/* ========================================================================== */
-
-#define LDL_DATE "Nov 1, 2007"
-#define LDL_VERSION_CODE(main,sub) ((main) * 1000 + (sub))
-#define LDL_MAIN_VERSION 2
-#define LDL_SUB_VERSION 0
-#define LDL_SUBSUB_VERSION 1
-#define LDL_VERSION LDL_VERSION_CODE(LDL_MAIN_VERSION,LDL_SUB_VERSION)
-
diff --git a/extern/libmv/third_party/ldl/README.libmv b/extern/libmv/third_party/ldl/README.libmv
deleted file mode 100644
index 64ece48a390..00000000000
--- a/extern/libmv/third_party/ldl/README.libmv
+++ /dev/null
@@ -1,10 +0,0 @@
-Project: LDL
-URL: http://www.cise.ufl.edu/research/sparse/ldl/
-License: LGPL2.1
-Upstream version: 2.0.1 (despite the ChangeLog saying 2.0.0)
-
-Local modifications:
-
- * Deleted everything except ldl.c, ldl.h, the license, the ChangeLog, and the
- README.
-
diff --git a/extern/libmv/third_party/ldl/README.txt b/extern/libmv/third_party/ldl/README.txt
deleted file mode 100644
index 7be8dd1f001..00000000000
--- a/extern/libmv/third_party/ldl/README.txt
+++ /dev/null
@@ -1,136 +0,0 @@
-LDL Version 2.0: a sparse LDL' factorization and solve package.
- Written in C, with both a C and MATLAB mexFunction interface.
-
-These routines are not terrifically fast (they do not use dense matrix kernels),
-but the code is very short and concise. The purpose is to illustrate the
-algorithms in a very concise and readable manner, primarily for educational
-purposes. Although the code is very concise, this package is slightly faster
-than the built-in sparse Cholesky factorization in MATLAB 6.5 (chol), when
-using the same input permutation.
-
-Requires UFconfig, in the ../UFconfig directory relative to this directory.
-
-Quick start (Unix, or Windows with Cygwin):
-
- To compile, test, and install LDL, you may wish to first obtain a copy of
- AMD v2.0 from http://www.cise.ufl.edu/research/sparse, and place it in the
- ../AMD directory, relative to this directory. Next, type "make", which
- will compile the LDL library and three demo main programs (one of which
- requires AMD). It will also compile the LDL MATLAB mexFunction (if you
- have MATLAB). Typing "make clean" will remove non-essential files.
- AMD v2.0 or later is required. Its use is optional.
-
-Quick start (for MATLAB users);
-
- To compile, test, and install the LDL mexFunctions (ldlsparse and
- ldlsymbol), start MATLAB in this directory and type ldl_install.
- This works on any system supported by MATLAB.
-
---------------------------------------------------------------------------------
-
-LDL Copyright (c) 2005 by Timothy A. Davis. All Rights Reserved.
-
-LDL License:
-
- Your use or distribution of LDL or any modified version of
- LDL implies that you agree to this License.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
- USA
-
- Permission is hereby granted to use or copy this program under the
- terms of the GNU LGPL, provided that the Copyright, this License,
- and the Availability of the original version is retained on all copies.
- User documentation of any code that uses this code or any modified
- version of this code must cite the Copyright, this License, the
- Availability note, and "Used by permission." Permission to modify
- the code and to distribute modified code is granted, provided the
- Copyright, this License, and the Availability note are retained,
- and a notice that the code was modified is included.
-
-Availability:
-
- http://www.cise.ufl.edu/research/sparse/ldl
-
-Acknowledgements:
-
- This work was supported by the National Science Foundation, under
- grant CCR-0203270.
-
- Portions of this work were done while on sabbatical at Stanford University
- and Lawrence Berkeley National Laboratory (with funding from the SciDAC
- program). I would like to thank Gene Golub, Esmond Ng, and Horst Simon
- for making this sabbatical possible. I would like to thank Pete Stewart
- for his comments on a draft of this software and paper.
-
---------------------------------------------------------------------------------
-Files and directories in this distribution:
---------------------------------------------------------------------------------
-
- Documentation, and compiling:
-
- README.txt this file
- Makefile for compiling LDL
- ChangeLog changes since V1.0 (Dec 31, 2003)
- License license
- lesser.txt the GNU LGPL license
-
- ldl_userguide.pdf user guide in PDF
- ldl_userguide.ps user guide in postscript
- ldl_userguide.tex user guide in Latex
- ldl.bib bibliography for user guide
-
- The LDL library itself:
-
- ldl.c the C-callable routines
- ldl.h include file for any code that calls LDL
-
- A simple C main program that demonstrates how to use LDL:
-
- ldlsimple.c a stand-alone C program, uses the basic features of LDL
- ldlsimple.out output of ldlsimple
-
- ldllsimple.c long integer version of ldlsimple.c
-
- Demo C program, for testing LDL and providing an example of its use
-
- ldlmain.c a stand-alone C main program that uses and tests LDL
- Matrix a directory containing matrices used by ldlmain.c
- ldlmain.out output of ldlmain
- ldlamd.out output of ldlamd (ldlmain.c compiled with AMD)
- ldllamd.out output of ldllamd (ldlmain.c compiled with AMD, long)
-
- MATLAB-related, not required for use in a regular C program
-
- Contents.m a list of the MATLAB-callable routines
- ldl.m MATLAB help file for the LDL mexFunction
- ldldemo.m MATLAB demo of how to use the LDL mexFunction
- ldldemo.out diary output of ldldemo
- ldltest.m to test the LDL mexFunction
- ldltest.out diary output of ldltest
- ldlmex.c the LDL mexFunction for MATLAB
- ldlrow.m the numerical algorithm that LDL is based on
- ldlmain2.m compiles and runs ldlmain.c as a MATLAB mexFunction
- ldlmain2.out output of ldlmain2.m
- ldlsymbolmex.c symbolic factorization using LDL (see SYMBFACT, ETREE)
- ldlsymbol.m help file for the LDLSYMBOL mexFunction
-
- ldl_install.m compile, install, and test LDL functions
- ldl_make.m compile LDL (ldlsparse and ldlsymbol)
-
- ldlsparse.m help for ldlsparse
-
-See ldl.c for a description of how to use the code from a C program. Type
-"help ldl" in MATLAB for information on how to use LDL in a MATLAB program.
diff --git a/extern/libmv/third_party/ldl/Source/ldl.c b/extern/libmv/third_party/ldl/Source/ldl.c
deleted file mode 100644
index a9b35c846ef..00000000000
--- a/extern/libmv/third_party/ldl/Source/ldl.c
+++ /dev/null
@@ -1,507 +0,0 @@
-/* ========================================================================== */
-/* === ldl.c: sparse LDL' factorization and solve package =================== */
-/* ========================================================================== */
-
-/* LDL: a simple set of routines for sparse LDL' factorization. These routines
- * are not terrifically fast (they do not use dense matrix kernels), but the
- * code is very short. The purpose is to illustrate the algorithms in a very
- * concise manner, primarily for educational purposes. Although the code is
- * very concise, this package is slightly faster than the built-in sparse
- * Cholesky factorization in MATLAB 7.0 (chol), when using the same input
- * permutation.
- *
- * The routines compute the LDL' factorization of a real sparse symmetric
- * matrix A (or PAP' if a permutation P is supplied), and solve upper
- * and lower triangular systems with the resulting L and D factors. If A is
- * positive definite then the factorization will be accurate. A can be
- * indefinite (with negative values on the diagonal D), but in this case no
- * guarantee of accuracy is provided, since no numeric pivoting is performed.
- *
- * The n-by-n sparse matrix A is in compressed-column form. The nonzero values
- * in column j are stored in Ax [Ap [j] ... Ap [j+1]-1], with corresponding row
- * indices in Ai [Ap [j] ... Ap [j+1]-1]. Ap [0] = 0 is required, and thus
- * nz = Ap [n] is the number of nonzeros in A. Ap is an int array of size n+1.
- * The int array Ai and the double array Ax are of size nz. This data structure
- * is identical to the one used by MATLAB, except for the following
- * generalizations. The row indices in each column of A need not be in any
- * particular order, although they must be in the range 0 to n-1. Duplicate
- * entries can be present; any duplicates are summed. That is, if row index i
- * appears twice in a column j, then the value of A (i,j) is the sum of the two
- * entries. The data structure used here for the input matrix A is more
- * flexible than MATLAB's, which requires sorted columns with no duplicate
- * entries.
- *
- * Only the diagonal and upper triangular part of A (or PAP' if a permutation
- * P is provided) is accessed. The lower triangular parts of the matrix A or
- * PAP' can be present, but they are ignored.
- *
- * The optional input permutation is provided as an array P of length n. If
- * P [k] = j, the row and column j of A is the kth row and column of PAP'.
- * If P is present then the factorization is LDL' = PAP' or L*D*L' = A(P,P) in
- * 0-based MATLAB notation. If P is not present (a null pointer) then no
- * permutation is performed, and the factorization is LDL' = A.
- *
- * The lower triangular matrix L is stored in the same compressed-column
- * form (an int Lp array of size n+1, an int Li array of size Lp [n], and a
- * double array Lx of the same size as Li). It has a unit diagonal, which is
- * not stored. The row indices in each column of L are always returned in
- * ascending order, with no duplicate entries. This format is compatible with
- * MATLAB, except that it would be more convenient for MATLAB to include the
- * unit diagonal of L. Doing so here would add additional complexity to the
- * code, and is thus omitted in the interest of keeping this code short and
- * readable.
- *
- * The elimination tree is held in the Parent [0..n-1] array. It is normally
- * not required by the user, but it is required by ldl_numeric. The diagonal
- * matrix D is held as an array D [0..n-1] of size n.
- *
- * --------------------
- * C-callable routines:
- * --------------------
- *
- * ldl_symbolic: Given the pattern of A, computes the Lp and Parent arrays
- * required by ldl_numeric. Takes time proportional to the number of
- * nonzeros in L. Computes the inverse Pinv of P if P is provided.
- * Also returns Lnz, the count of nonzeros in each column of L below
- * the diagonal (this is not required by ldl_numeric).
- * ldl_numeric: Given the pattern and numerical values of A, the Lp array,
- * the Parent array, and P and Pinv if applicable, computes the
- * pattern and numerical values of L and D.
- * ldl_lsolve: Solves Lx=b for a dense vector b.
- * ldl_dsolve: Solves Dx=b for a dense vector b.
- * ldl_ltsolve: Solves L'x=b for a dense vector b.
- * ldl_perm: Computes x=Pb for a dense vector b.
- * ldl_permt: Computes x=P'b for a dense vector b.
- * ldl_valid_perm: checks the validity of a permutation vector
- * ldl_valid_matrix: checks the validity of the sparse matrix A
- *
- * ----------------------------
- * Limitations of this package:
- * ----------------------------
- *
- * In the interest of keeping this code simple and readable, ldl_symbolic and
- * ldl_numeric assume their inputs are valid. You can check your own inputs
- * prior to calling these routines with the ldl_valid_perm and ldl_valid_matrix
- * routines. Except for the two ldl_valid_* routines, no routine checks to see
- * if the array arguments are present (non-NULL). Like all C routines, no
- * routine can determine if the arrays are long enough and don't overlap.
- *
- * The ldl_numeric does check the numerical factorization, however. It returns
- * n if the factorization is successful. If D (k,k) is zero, then k is
- * returned, and L is only partially computed.
- *
- * No pivoting to control fill-in is performed, which is often critical for
- * obtaining good performance. I recommend that you compute the permutation P
- * using AMD or SYMAMD (approximate minimum degree ordering routines), or an
- * appropriate graph-partitioning based ordering. See the ldldemo.m routine for
- * an example in MATLAB, and the ldlmain.c stand-alone C program for examples of
- * how to find P. Routines for manipulating compressed-column matrices are
- * available in UMFPACK. AMD, SYMAMD, UMFPACK, and this LDL package are all
- * available at http://www.cise.ufl.edu/research/sparse.
- *
- * -------------------------
- * Possible simplifications:
- * -------------------------
- *
- * These routines could be made even simpler with a few additional assumptions.
- * If no input permutation were performed, the caller would have to permute the
- * matrix first, but the computation of Pinv, and the use of P and Pinv could be
- * removed. If only the diagonal and upper triangular part of A or PAP' are
- * present, then the tests in the "if (i < k)" statement in ldl_symbolic and
- * "if (i <= k)" in ldl_numeric, are always true, and could be removed (i can
- * equal k in ldl_symbolic, but then the body of the if statement would
- * correctly do no work since Flag [k] == k). If we could assume that no
- * duplicate entries are present, then the statement Y [i] += Ax [p] could be
- * replaced with Y [i] = Ax [p] in ldl_numeric.
- *
- * --------------------------
- * Description of the method:
- * --------------------------
- *
- * LDL computes the symbolic factorization by finding the pattern of L one row
- * at a time. It does this based on the following theory. Consider a sparse
- * system Lx=b, where L, x, and b, are all sparse, and where L comes from a
- * Cholesky (or LDL') factorization. The elimination tree (etree) of L is
- * defined as follows. The parent of node j is the smallest k > j such that
- * L (k,j) is nonzero. Node j has no parent if column j of L is completely zero
- * below the diagonal (j is a root of the etree in this case). The nonzero
- * pattern of x is the union of the paths from each node i to the root, for
- * each nonzero b (i). To compute the numerical solution to Lx=b, we can
- * traverse the columns of L corresponding to nonzero values of x. This
- * traversal does not need to be done in the order 0 to n-1. It can be done in
- * any "topological" order, such that x (i) is computed before x (j) if i is a
- * descendant of j in the elimination tree.
- *
- * The row-form of the LDL' factorization is shown in the MATLAB function
- * ldlrow.m in this LDL package. Note that row k of L is found via a sparse
- * triangular solve of L (1:k-1, 1:k-1) \ A (1:k-1, k), to use 1-based MATLAB
- * notation. Thus, we can start with the nonzero pattern of the kth column of
- * A (above the diagonal), follow the paths up to the root of the etree of the
- * (k-1)-by-(k-1) leading submatrix of L, and obtain the pattern of the kth row
- * of L. Note that we only need the leading (k-1)-by-(k-1) submatrix of L to
- * do this. The elimination tree can be constructed as we go.
- *
- * The symbolic factorization does the same thing, except that it discards the
- * pattern of L as it is computed. It simply counts the number of nonzeros in
- * each column of L and then constructs the Lp index array when it's done. The
- * symbolic factorization does not need to do this in topological order.
- * Compare ldl_symbolic with the first part of ldl_numeric, and note that the
- * while (len > 0) loop is not present in ldl_symbolic.
- *
- * LDL Version 1.3, Copyright (c) 2006 by Timothy A Davis,
- * University of Florida. All Rights Reserved. Developed while on sabbatical
- * at Stanford University and Lawrence Berkeley National Laboratory. Refer to
- * the README file for the License. Available at
- * http://www.cise.ufl.edu/research/sparse.
- */
-
-#include "ldl.h"
-
-/* ========================================================================== */
-/* === ldl_symbolic ========================================================= */
-/* ========================================================================== */
-
-/* The input to this routine is a sparse matrix A, stored in column form, and
- * an optional permutation P. The output is the elimination tree
- * and the number of nonzeros in each column of L. Parent [i] = k if k is the
- * parent of i in the tree. The Parent array is required by ldl_numeric.
- * Lnz [k] gives the number of nonzeros in the kth column of L, excluding the
- * diagonal.
- *
- * One workspace vector (Flag) of size n is required.
- *
- * If P is NULL, then it is ignored. The factorization will be LDL' = A.
- * Pinv is not computed. In this case, neither P nor Pinv are required by
- * ldl_numeric.
- *
- * If P is not NULL, then it is assumed to be a valid permutation. If
- * row and column j of A is the kth pivot, the P [k] = j. The factorization
- * will be LDL' = PAP', or A (p,p) in MATLAB notation. The inverse permutation
- * Pinv is computed, where Pinv [j] = k if P [k] = j. In this case, both P
- * and Pinv are required as inputs to ldl_numeric.
- *
- * The floating-point operation count of the subsequent call to ldl_numeric
- * is not returned, but could be computed after ldl_symbolic is done. It is
- * the sum of (Lnz [k]) * (Lnz [k] + 2) for k = 0 to n-1.
- */
-
-void LDL_symbolic
-(
- LDL_int n, /* A and L are n-by-n, where n >= 0 */
- LDL_int Ap [ ], /* input of size n+1, not modified */
- LDL_int Ai [ ], /* input of size nz=Ap[n], not modified */
- LDL_int Lp [ ], /* output of size n+1, not defined on input */
- LDL_int Parent [ ], /* output of size n, not defined on input */
- LDL_int Lnz [ ], /* output of size n, not defined on input */
- LDL_int Flag [ ], /* workspace of size n, not defn. on input or output */
- LDL_int P [ ], /* optional input of size n */
- LDL_int Pinv [ ] /* optional output of size n (used if P is not NULL) */
-)
-{
- LDL_int i, k, p, kk, p2 ;
- if (P)
- {
- /* If P is present then compute Pinv, the inverse of P */
- for (k = 0 ; k < n ; k++)
- {
- Pinv [P [k]] = k ;
- }
- }
- for (k = 0 ; k < n ; k++)
- {
- /* L(k,:) pattern: all nodes reachable in etree from nz in A(0:k-1,k) */
- Parent [k] = -1 ; /* parent of k is not yet known */
- Flag [k] = k ; /* mark node k as visited */
- Lnz [k] = 0 ; /* count of nonzeros in column k of L */
- kk = (P) ? (P [k]) : (k) ; /* kth original, or permuted, column */
- p2 = Ap [kk+1] ;
- for (p = Ap [kk] ; p < p2 ; p++)
- {
- /* A (i,k) is nonzero (original or permuted A) */
- i = (Pinv) ? (Pinv [Ai [p]]) : (Ai [p]) ;
- if (i < k)
- {
- /* follow path from i to root of etree, stop at flagged node */
- for ( ; Flag [i] != k ; i = Parent [i])
- {
- /* find parent of i if not yet determined */
- if (Parent [i] == -1) Parent [i] = k ;
- Lnz [i]++ ; /* L (k,i) is nonzero */
- Flag [i] = k ; /* mark i as visited */
- }
- }
- }
- }
- /* construct Lp index array from Lnz column counts */
- Lp [0] = 0 ;
- for (k = 0 ; k < n ; k++)
- {
- Lp [k+1] = Lp [k] + Lnz [k] ;
- }
-}
-
-
-/* ========================================================================== */
-/* === ldl_numeric ========================================================== */
-/* ========================================================================== */
-
-/* Given a sparse matrix A (the arguments n, Ap, Ai, and Ax) and its symbolic
- * analysis (Lp and Parent, and optionally P and Pinv), compute the numeric LDL'
- * factorization of A or PAP'. The outputs of this routine are arguments Li,
- * Lx, and D. It also requires three size-n workspaces (Y, Pattern, and Flag).
- */
-
-LDL_int LDL_numeric /* returns n if successful, k if D (k,k) is zero */
-(
- LDL_int n, /* A and L are n-by-n, where n >= 0 */
- LDL_int Ap [ ], /* input of size n+1, not modified */
- LDL_int Ai [ ], /* input of size nz=Ap[n], not modified */
- double Ax [ ], /* input of size nz=Ap[n], not modified */
- LDL_int Lp [ ], /* input of size n+1, not modified */
- LDL_int Parent [ ], /* input of size n, not modified */
- LDL_int Lnz [ ], /* output of size n, not defn. on input */
- LDL_int Li [ ], /* output of size lnz=Lp[n], not defined on input */
- double Lx [ ], /* output of size lnz=Lp[n], not defined on input */
- double D [ ], /* output of size n, not defined on input */
- double Y [ ], /* workspace of size n, not defn. on input or output */
- LDL_int Pattern [ ],/* workspace of size n, not defn. on input or output */
- LDL_int Flag [ ], /* workspace of size n, not defn. on input or output */
- LDL_int P [ ], /* optional input of size n */
- LDL_int Pinv [ ] /* optional input of size n */
-)
-{
- double yi, l_ki ;
- LDL_int i, k, p, kk, p2, len, top ;
- for (k = 0 ; k < n ; k++)
- {
- /* compute nonzero Pattern of kth row of L, in topological order */
- Y [k] = 0.0 ; /* Y(0:k) is now all zero */
- top = n ; /* stack for pattern is empty */
- Flag [k] = k ; /* mark node k as visited */
- Lnz [k] = 0 ; /* count of nonzeros in column k of L */
- kk = (P) ? (P [k]) : (k) ; /* kth original, or permuted, column */
- p2 = Ap [kk+1] ;
- for (p = Ap [kk] ; p < p2 ; p++)
- {
- i = (Pinv) ? (Pinv [Ai [p]]) : (Ai [p]) ; /* get A(i,k) */
- if (i <= k)
- {
- Y [i] += Ax [p] ; /* scatter A(i,k) into Y (sum duplicates) */
- for (len = 0 ; Flag [i] != k ; i = Parent [i])
- {
- Pattern [len++] = i ; /* L(k,i) is nonzero */
- Flag [i] = k ; /* mark i as visited */
- }
- while (len > 0) Pattern [--top] = Pattern [--len] ;
- }
- }
- /* compute numerical values kth row of L (a sparse triangular solve) */
- D [k] = Y [k] ; /* get D(k,k) and clear Y(k) */
- Y [k] = 0.0 ;
- for ( ; top < n ; top++)
- {
- i = Pattern [top] ; /* Pattern [top:n-1] is pattern of L(:,k) */
- yi = Y [i] ; /* get and clear Y(i) */
- Y [i] = 0.0 ;
- p2 = Lp [i] + Lnz [i] ;
- for (p = Lp [i] ; p < p2 ; p++)
- {
- Y [Li [p]] -= Lx [p] * yi ;
- }
- l_ki = yi / D [i] ; /* the nonzero entry L(k,i) */
- D [k] -= l_ki * yi ;
- Li [p] = k ; /* store L(k,i) in column form of L */
- Lx [p] = l_ki ;
- Lnz [i]++ ; /* increment count of nonzeros in col i */
- }
- if (D [k] == 0.0) return (k) ; /* failure, D(k,k) is zero */
- }
- return (n) ; /* success, diagonal of D is all nonzero */
-}
-
-
-/* ========================================================================== */
-/* === ldl_lsolve: solve Lx=b ============================================== */
-/* ========================================================================== */
-
-void LDL_lsolve
-(
- LDL_int n, /* L is n-by-n, where n >= 0 */
- double X [ ], /* size n. right-hand-side on input, soln. on output */
- LDL_int Lp [ ], /* input of size n+1, not modified */
- LDL_int Li [ ], /* input of size lnz=Lp[n], not modified */
- double Lx [ ] /* input of size lnz=Lp[n], not modified */
-)
-{
- LDL_int j, p, p2 ;
- for (j = 0 ; j < n ; j++)
- {
- p2 = Lp [j+1] ;
- for (p = Lp [j] ; p < p2 ; p++)
- {
- X [Li [p]] -= Lx [p] * X [j] ;
- }
- }
-}
-
-
-/* ========================================================================== */
-/* === ldl_dsolve: solve Dx=b ============================================== */
-/* ========================================================================== */
-
-void LDL_dsolve
-(
- LDL_int n, /* D is n-by-n, where n >= 0 */
- double X [ ], /* size n. right-hand-side on input, soln. on output */
- double D [ ] /* input of size n, not modified */
-)
-{
- LDL_int j ;
- for (j = 0 ; j < n ; j++)
- {
- X [j] /= D [j] ;
- }
-}
-
-
-/* ========================================================================== */
-/* === ldl_ltsolve: solve L'x=b ============================================ */
-/* ========================================================================== */
-
-void LDL_ltsolve
-(
- LDL_int n, /* L is n-by-n, where n >= 0 */
- double X [ ], /* size n. right-hand-side on input, soln. on output */
- LDL_int Lp [ ], /* input of size n+1, not modified */
- LDL_int Li [ ], /* input of size lnz=Lp[n], not modified */
- double Lx [ ] /* input of size lnz=Lp[n], not modified */
-)
-{
- int j, p, p2 ;
- for (j = n-1 ; j >= 0 ; j--)
- {
- p2 = Lp [j+1] ;
- for (p = Lp [j] ; p < p2 ; p++)
- {
- X [j] -= Lx [p] * X [Li [p]] ;
- }
- }
-}
-
-
-/* ========================================================================== */
-/* === ldl_perm: permute a vector, x=Pb ===================================== */
-/* ========================================================================== */
-
-void LDL_perm
-(
- LDL_int n, /* size of X, B, and P */
- double X [ ], /* output of size n. */
- double B [ ], /* input of size n. */
- LDL_int P [ ] /* input permutation array of size n. */
-)
-{
- LDL_int j ;
- for (j = 0 ; j < n ; j++)
- {
- X [j] = B [P [j]] ;
- }
-}
-
-
-/* ========================================================================== */
-/* === ldl_permt: permute a vector, x=P'b =================================== */
-/* ========================================================================== */
-
-void LDL_permt
-(
- LDL_int n, /* size of X, B, and P */
- double X [ ], /* output of size n. */
- double B [ ], /* input of size n. */
- LDL_int P [ ] /* input permutation array of size n. */
-)
-{
- LDL_int j ;
- for (j = 0 ; j < n ; j++)
- {
- X [P [j]] = B [j] ;
- }
-}
-
-
-/* ========================================================================== */
-/* === ldl_valid_perm: check if a permutation vector is valid =============== */
-/* ========================================================================== */
-
-LDL_int LDL_valid_perm /* returns 1 if valid, 0 otherwise */
-(
- LDL_int n,
- LDL_int P [ ], /* input of size n, a permutation of 0:n-1 */
- LDL_int Flag [ ] /* workspace of size n */
-)
-{
- LDL_int j, k ;
- if (n < 0 || !Flag)
- {
- return (0) ; /* n must be >= 0, and Flag must be present */
- }
- if (!P)
- {
- return (1) ; /* If NULL, P is assumed to be the identity perm. */
- }
- for (j = 0 ; j < n ; j++)
- {
- Flag [j] = 0 ; /* clear the Flag array */
- }
- for (k = 0 ; k < n ; k++)
- {
- j = P [k] ;
- if (j < 0 || j >= n || Flag [j] != 0)
- {
- return (0) ; /* P is not valid */
- }
- Flag [j] = 1 ;
- }
- return (1) ; /* P is valid */
-}
-
-
-/* ========================================================================== */
-/* === ldl_valid_matrix: check if a sparse matrix is valid ================== */
-/* ========================================================================== */
-
-/* This routine checks to see if a sparse matrix A is valid for input to
- * ldl_symbolic and ldl_numeric. It returns 1 if the matrix is valid, 0
- * otherwise. A is in sparse column form. The numerical values in column j
- * are stored in Ax [Ap [j] ... Ap [j+1]-1], with row indices in
- * Ai [Ap [j] ... Ap [j+1]-1]. The Ax array is not checked.
- */
-
-LDL_int LDL_valid_matrix
-(
- LDL_int n,
- LDL_int Ap [ ],
- LDL_int Ai [ ]
-)
-{
- LDL_int j, p ;
- if (n < 0 || !Ap || !Ai || Ap [0] != 0)
- {
- return (0) ; /* n must be >= 0, and Ap and Ai must be present */
- }
- for (j = 0 ; j < n ; j++)
- {
- if (Ap [j] > Ap [j+1])
- {
- return (0) ; /* Ap must be monotonically nondecreasing */
- }
- }
- for (p = 0 ; p < Ap [n] ; p++)
- {
- if (Ai [p] < 0 || Ai [p] >= n)
- {
- return (0) ; /* row indices must be in the range 0 to n-1 */
- }
- }
- return (1) ; /* matrix is valid */
-}
diff --git a/extern/libmv/third_party/ssba/COPYING.TXT b/extern/libmv/third_party/ssba/COPYING.TXT
deleted file mode 100644
index fc8a5de7edf..00000000000
--- a/extern/libmv/third_party/ssba/COPYING.TXT
+++ /dev/null
@@ -1,165 +0,0 @@
- GNU LESSER GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-
- This version of the GNU Lesser General Public License incorporates
-the terms and conditions of version 3 of the GNU General Public
-License, supplemented by the additional permissions listed below.
-
- 0. Additional Definitions.
-
- As used herein, "this License" refers to version 3 of the GNU Lesser
-General Public License, and the "GNU GPL" refers to version 3 of the GNU
-General Public License.
-
- "The Library" refers to a covered work governed by this License,
-other than an Application or a Combined Work as defined below.
-
- An "Application" is any work that makes use of an interface provided
-by the Library, but which is not otherwise based on the Library.
-Defining a subclass of a class defined by the Library is deemed a mode
-of using an interface provided by the Library.
-
- A "Combined Work" is a work produced by combining or linking an
-Application with the Library. The particular version of the Library
-with which the Combined Work was made is also called the "Linked
-Version".
-
- The "Minimal Corresponding Source" for a Combined Work means the
-Corresponding Source for the Combined Work, excluding any source code
-for portions of the Combined Work that, considered in isolation, are
-based on the Application, and not on the Linked Version.
-
- The "Corresponding Application Code" for a Combined Work means the
-object code and/or source code for the Application, including any data
-and utility programs needed for reproducing the Combined Work from the
-Application, but excluding the System Libraries of the Combined Work.
-
- 1. Exception to Section 3 of the GNU GPL.
-
- You may convey a covered work under sections 3 and 4 of this License
-without being bound by section 3 of the GNU GPL.
-
- 2. Conveying Modified Versions.
-
- If you modify a copy of the Library, and, in your modifications, a
-facility refers to a function or data to be supplied by an Application
-that uses the facility (other than as an argument passed when the
-facility is invoked), then you may convey a copy of the modified
-version:
-
- a) under this License, provided that you make a good faith effort to
- ensure that, in the event an Application does not supply the
- function or data, the facility still operates, and performs
- whatever part of its purpose remains meaningful, or
-
- b) under the GNU GPL, with none of the additional permissions of
- this License applicable to that copy.
-
- 3. Object Code Incorporating Material from Library Header Files.
-
- The object code form of an Application may incorporate material from
-a header file that is part of the Library. You may convey such object
-code under terms of your choice, provided that, if the incorporated
-material is not limited to numerical parameters, data structure
-layouts and accessors, or small macros, inline functions and templates
-(ten or fewer lines in length), you do both of the following:
-
- a) Give prominent notice with each copy of the object code that the
- Library is used in it and that the Library and its use are
- covered by this License.
-
- b) Accompany the object code with a copy of the GNU GPL and this license
- document.
-
- 4. Combined Works.
-
- You may convey a Combined Work under terms of your choice that,
-taken together, effectively do not restrict modification of the
-portions of the Library contained in the Combined Work and reverse
-engineering for debugging such modifications, if you also do each of
-the following:
-
- a) Give prominent notice with each copy of the Combined Work that
- the Library is used in it and that the Library and its use are
- covered by this License.
-
- b) Accompany the Combined Work with a copy of the GNU GPL and this license
- document.
-
- c) For a Combined Work that displays copyright notices during
- execution, include the copyright notice for the Library among
- these notices, as well as a reference directing the user to the
- copies of the GNU GPL and this license document.
-
- d) Do one of the following:
-
- 0) Convey the Minimal Corresponding Source under the terms of this
- License, and the Corresponding Application Code in a form
- suitable for, and under terms that permit, the user to
- recombine or relink the Application with a modified version of
- the Linked Version to produce a modified Combined Work, in the
- manner specified by section 6 of the GNU GPL for conveying
- Corresponding Source.
-
- 1) Use a suitable shared library mechanism for linking with the
- Library. A suitable mechanism is one that (a) uses at run time
- a copy of the Library already present on the user's computer
- system, and (b) will operate properly with a modified version
- of the Library that is interface-compatible with the Linked
- Version.
-
- e) Provide Installation Information, but only if you would otherwise
- be required to provide such information under section 6 of the
- GNU GPL, and only to the extent that such information is
- necessary to install and execute a modified version of the
- Combined Work produced by recombining or relinking the
- Application with a modified version of the Linked Version. (If
- you use option 4d0, the Installation Information must accompany
- the Minimal Corresponding Source and Corresponding Application
- Code. If you use option 4d1, you must provide the Installation
- Information in the manner specified by section 6 of the GNU GPL
- for conveying Corresponding Source.)
-
- 5. Combined Libraries.
-
- You may place library facilities that are a work based on the
-Library side by side in a single library together with other library
-facilities that are not Applications and are not covered by this
-License, and convey such a combined library under terms of your
-choice, if you do both of the following:
-
- a) Accompany the combined library with a copy of the same work based
- on the Library, uncombined with any other library facilities,
- conveyed under the terms of this License.
-
- b) Give prominent notice with the combined library that part of it
- is a work based on the Library, and explaining where to find the
- accompanying uncombined form of the same work.
-
- 6. Revised Versions of the GNU Lesser General Public License.
-
- The Free Software Foundation may publish revised and/or new versions
-of the GNU Lesser General Public License from time to time. Such new
-versions will be similar in spirit to the present version, but may
-differ in detail to address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Library as you received it specifies that a certain numbered version
-of the GNU Lesser General Public License "or any later version"
-applies to it, you have the option of following the terms and
-conditions either of that published version or of any later version
-published by the Free Software Foundation. If the Library as you
-received it does not specify a version number of the GNU Lesser
-General Public License, you may choose any version of the GNU Lesser
-General Public License ever published by the Free Software Foundation.
-
- If the Library as you received it specifies that a proxy can decide
-whether future versions of the GNU Lesser General Public License shall
-apply, that proxy's public statement of acceptance of any version is
-permanent authorization for you to choose that version for the
-Library.
diff --git a/extern/libmv/third_party/ssba/Geometry/v3d_cameramatrix.h b/extern/libmv/third_party/ssba/Geometry/v3d_cameramatrix.h
deleted file mode 100644
index 448ae9714e5..00000000000
--- a/extern/libmv/third_party/ssba/Geometry/v3d_cameramatrix.h
+++ /dev/null
@@ -1,204 +0,0 @@
-// -*- C++ -*-
-/*
-Copyright (c) 2008 University of North Carolina at Chapel Hill
-
-This file is part of SSBA (Simple Sparse Bundle Adjustment).
-
-SSBA is free software: you can redistribute it and/or modify it under the
-terms of the GNU Lesser General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option) any
-later version.
-
-SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with SSBA. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef V3D_CAMERA_MATRIX_H
-#define V3D_CAMERA_MATRIX_H
-
-#include "Math/v3d_linear.h"
-#include "Geometry/v3d_distortion.h"
-
-namespace V3D
-{
-
- struct CameraMatrix
- {
- CameraMatrix()
- {
- makeIdentityMatrix(_K);
- makeIdentityMatrix(_R);
- makeZeroVector(_T);
- this->updateCachedValues(true, true);
- }
-
- CameraMatrix(double f, double cx, double cy)
- {
- makeIdentityMatrix(_K);
- _K[0][0] = f;
- _K[1][1] = f;
- _K[0][2] = cx;
- _K[1][2] = cy;
- makeIdentityMatrix(_R);
- makeZeroVector(_T);
- this->updateCachedValues(true, true);
- }
-
- CameraMatrix(Matrix3x3d const& K,
- Matrix3x3d const& R,
- Vector3d const& T)
- : _K(K), _R(R), _T(T)
- {
- this->updateCachedValues(true, true);
- }
-
- void setIntrinsic(Matrix3x3d const& K) { _K = K; this->updateCachedValues(true, false); }
- void setRotation(Matrix3x3d const& R) { _R = R; this->updateCachedValues(false, true); }
- void setTranslation(Vector3d const& T) { _T = T; this->updateCachedValues(false, true); }
-
- template <typename Mat>
- void setOrientation(Mat const& RT)
- {
- _R[0][0] = RT[0][0]; _R[0][1] = RT[0][1]; _R[0][2] = RT[0][2];
- _R[1][0] = RT[1][0]; _R[1][1] = RT[1][1]; _R[1][2] = RT[1][2];
- _R[2][0] = RT[2][0]; _R[2][1] = RT[2][1]; _R[2][2] = RT[2][2];
- _T[0] = RT[0][3]; _T[1] = RT[1][3]; _T[2] = RT[2][3];
- this->updateCachedValues(false, true);
- }
-
- Matrix3x3d const& getIntrinsic() const { return _K; }
- Matrix3x3d const& getRotation() const { return _R; }
- Vector3d const& getTranslation() const { return _T; }
-
- Matrix3x4d getOrientation() const
- {
- Matrix3x4d RT;
- RT[0][0] = _R[0][0]; RT[0][1] = _R[0][1]; RT[0][2] = _R[0][2];
- RT[1][0] = _R[1][0]; RT[1][1] = _R[1][1]; RT[1][2] = _R[1][2];
- RT[2][0] = _R[2][0]; RT[2][1] = _R[2][1]; RT[2][2] = _R[2][2];
- RT[0][3] = _T[0]; RT[1][3] = _T[1]; RT[2][3] = _T[2];
- return RT;
- }
-
- Matrix3x4d getProjection() const
- {
- Matrix3x4d const RT = this->getOrientation();
- return _K * RT;
- }
-
- double getFocalLength() const { return _K[0][0]; }
- double getAspectRatio() const { return _K[1][1] / _K[0][0]; }
-
- Vector2d getPrincipalPoint() const
- {
- Vector2d pp;
- pp[0] = _K[0][2];
- pp[1] = _K[1][2];
- return pp;
- }
-
- Vector2d projectPoint(Vector3d const& X) const
- {
- Vector3d q = _K*(_R*X + _T);
- Vector2d res;
- res[0] = q[0]/q[2]; res[1] = q[1]/q[2];
- return res;
- }
-
- template <typename Distortion>
- Vector2d projectPoint(Distortion const& distortion, Vector3d const& X) const
- {
- Vector3d XX = _R*X + _T;
- Vector2d p;
- p[0] = XX[0] / XX[2];
- p[1] = XX[1] / XX[2];
- p = distortion(p);
-
- Vector2d res;
- res[0] = _K[0][0] * p[0] + _K[0][1] * p[1] + _K[0][2];
- res[1] = _K[1][1] * p[1] + _K[1][2];
- return res;
- }
-
- Vector3d unprojectPixel(Vector2d const &p, double depth = 1) const
- {
- Vector3d pp;
- pp[0] = p[0]; pp[1] = p[1]; pp[2] = 1.0;
- Vector3d ray = _invK * pp;
- ray[0] *= depth/ray[2];
- ray[1] *= depth/ray[2];
- ray[2] = depth;
- ray = _Rt * ray;
- return _center + ray;
- }
-
- Vector3d transformPointIntoCameraSpace(Vector3d const& p) const
- {
- return _R*p + _T;
- }
-
- Vector3d transformPointFromCameraSpace(Vector3d const& p) const
- {
- return _Rt*(p-_T);
- }
-
- Vector3d transformDirectionFromCameraSpace(Vector3d const& dir) const
- {
- return _Rt*dir;
- }
-
- Vector3d const& cameraCenter() const
- {
- return _center;
- }
-
- Vector3d opticalAxis() const
- {
- return this->transformDirectionFromCameraSpace(makeVector3(0.0, 0.0, 1.0));
- }
-
- Vector3d upVector() const
- {
- return this->transformDirectionFromCameraSpace(makeVector3(0.0, 1.0, 0.0));
- }
-
- Vector3d rightVector() const
- {
- return this->transformDirectionFromCameraSpace(makeVector3(1.0, 0.0, 0.0));
- }
-
- Vector3d getRay(Vector2d const& p) const
- {
- Vector3d pp = makeVector3(p[0], p[1], 1.0);
- Vector3d ray = _invK * pp;
- ray = _Rt * ray;
- normalizeVector(ray);
- return ray;
- }
-
- protected:
- void updateCachedValues(bool intrinsic, bool orientation)
- {
- if (intrinsic) _invK = invertedMatrix(_K);
-
- if (orientation)
- {
- makeTransposedMatrix(_R, _Rt);
- _center = _Rt * (-1.0 * _T);
- }
- }
-
- Matrix3x3d _K, _R;
- Vector3d _T;
- Matrix3x3d _invK, _Rt;
- Vector3d _center;
- }; // end struct CameraMatrix
-
-} // end namespace V3D
-
-#endif
diff --git a/extern/libmv/third_party/ssba/Geometry/v3d_distortion.h b/extern/libmv/third_party/ssba/Geometry/v3d_distortion.h
deleted file mode 100644
index d0816558314..00000000000
--- a/extern/libmv/third_party/ssba/Geometry/v3d_distortion.h
+++ /dev/null
@@ -1,97 +0,0 @@
-// -*- C++ -*-
-/*
-Copyright (c) 2008 University of North Carolina at Chapel Hill
-
-This file is part of SSBA (Simple Sparse Bundle Adjustment).
-
-SSBA is free software: you can redistribute it and/or modify it under the
-terms of the GNU Lesser General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option) any
-later version.
-
-SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with SSBA. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef V3D_DISTORTION_H
-#define V3D_DISTORTION_H
-
-#include "Math/v3d_linear.h"
-#include "Math/v3d_linear_utils.h"
-
-namespace V3D
-{
-
- struct StdDistortionFunction
- {
- double k1, k2, p1, p2;
-
- StdDistortionFunction()
- : k1(0), k2(0), p1(0), p2(0)
- { }
-
- Vector2d operator()(Vector2d const& xu) const
- {
- double const r2 = xu[0]*xu[0] + xu[1]*xu[1];
- double const r4 = r2*r2;
- double const kr = 1 + k1*r2 + k2*r4;
-
- Vector2d xd;
- xd[0] = kr * xu[0] + 2*p1*xu[0]*xu[1] + p2*(r2 + 2*xu[0]*xu[0]);
- xd[1] = kr * xu[1] + 2*p2*xu[0]*xu[1] + p1*(r2 + 2*xu[1]*xu[1]);
- return xd;
- }
-
- Matrix2x2d derivativeWrtRadialParameters(Vector2d const& xu) const
- {
- double const r2 = xu[0]*xu[0] + xu[1]*xu[1];
- double const r4 = r2*r2;
- //double const kr = 1 + k1*r2 + k2*r4;
-
- Matrix2x2d deriv;
-
- deriv[0][0] = xu[0] * r2; // d xd/d k1
- deriv[0][1] = xu[0] * r4; // d xd/d k2
- deriv[1][0] = xu[1] * r2; // d yd/d k1
- deriv[1][1] = xu[1] * r4; // d yd/d k2
- return deriv;
- }
-
- Matrix2x2d derivativeWrtTangentialParameters(Vector2d const& xu) const
- {
- double const r2 = xu[0]*xu[0] + xu[1]*xu[1];
- //double const r4 = r2*r2;
- //double const kr = 1 + k1*r2 + k2*r4;
-
- Matrix2x2d deriv;
- deriv[0][0] = 2*xu[0]*xu[1]; // d xd/d p1
- deriv[0][1] = r2 + 2*xu[0]*xu[0]; // d xd/d p2
- deriv[1][0] = r2 + 2*xu[1]*xu[1]; // d yd/d p1
- deriv[1][1] = deriv[0][0]; // d yd/d p2
- return deriv;
- }
-
- Matrix2x2d derivativeWrtUndistortedPoint(Vector2d const& xu) const
- {
- double const r2 = xu[0]*xu[0] + xu[1]*xu[1];
- double const r4 = r2*r2;
- double const kr = 1 + k1*r2 + k2*r4;
- double const dkr = 2*k1 + 4*k2*r2;
-
- Matrix2x2d deriv;
- deriv[0][0] = kr + xu[0] * xu[0] * dkr + 2*p1*xu[1] + 6*p2*xu[0]; // d xd/d xu
- deriv[0][1] = xu[0] * xu[1] * dkr + 2*p1*xu[0] + 2*p2*xu[1]; // d xd/d yu
- deriv[1][0] = deriv[0][1]; // d yd/d xu
- deriv[1][1] = kr + xu[1] * xu[1] * dkr + 6*p1*xu[1] + 2*p2*xu[0]; // d yd/d yu
- return deriv;
- }
- }; // end struct StdDistortionFunction
-
-} // end namespace V3D
-
-#endif
diff --git a/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.cpp b/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.cpp
deleted file mode 100644
index 7eb2dfac5d9..00000000000
--- a/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.cpp
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
-Copyright (c) 2008 University of North Carolina at Chapel Hill
-
-This file is part of SSBA (Simple Sparse Bundle Adjustment).
-
-SSBA is free software: you can redistribute it and/or modify it under the
-terms of the GNU Lesser General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option) any
-later version.
-
-SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with SSBA. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "Geometry/v3d_metricbundle.h"
-
-#if defined(V3DLIB_ENABLE_SUITESPARSE)
-
-namespace
-{
-
- typedef V3D::InlineMatrix<double, 2, 4> Matrix2x4d;
- typedef V3D::InlineMatrix<double, 4, 2> Matrix4x2d;
- typedef V3D::InlineMatrix<double, 2, 6> Matrix2x6d;
-
-} // end namespace <>
-
-namespace V3D
-{
-
- void
- MetricBundleOptimizerBase::updateParametersA(VectorArray<double> const& deltaAi)
- {
- Vector3d T, omega;
- Matrix3x3d R0, dR;
-
- for (int i = _nNonvaryingA; i < _nParametersA; ++i)
- {
- T = _cams[i].getTranslation();
- T[0] += deltaAi[i][0];
- T[1] += deltaAi[i][1];
- T[2] += deltaAi[i][2];
- _cams[i].setTranslation(T);
-
- // Create incremental rotation using Rodriguez formula.
- R0 = _cams[i].getRotation();
- omega[0] = deltaAi[i][3];
- omega[1] = deltaAi[i][4];
- omega[2] = deltaAi[i][5];
- createRotationMatrixRodriguez(omega, dR);
- _cams[i].setRotation(dR * R0);
- } // end for (i)
- } // end MetricBundleOptimizerBase::updateParametersA()
-
- void
- MetricBundleOptimizerBase::updateParametersB(VectorArray<double> const& deltaBj)
- {
- for (int j = _nNonvaryingB; j < _nParametersB; ++j)
- {
- _Xs[j][0] += deltaBj[j][0];
- _Xs[j][1] += deltaBj[j][1];
- _Xs[j][2] += deltaBj[j][2];
- }
- } // end MetricBundleOptimizerBase::updateParametersB()
-
- void
- MetricBundleOptimizerBase::poseDerivatives(int i, int j, Vector3d& XX,
- Matrix3x6d& d_dRT, Matrix3x3d& d_dX) const
- {
- XX = _cams[i].transformPointIntoCameraSpace(_Xs[j]);
-
- // See Frank Dellaerts bundle adjustment tutorial.
- // d(dR * R0 * X + t)/d omega = -[R0 * X]_x
- Matrix3x3d J;
- makeCrossProductMatrix(XX - _cams[i].getTranslation(), J);
- scaleMatrixIP(-1.0, J);
-
- // Now the transformation from world coords into camera space is xx = Rx + T
- // Hence the derivative of x wrt. T is just the identity matrix.
- makeIdentityMatrix(d_dRT);
- copyMatrixSlice(J, 0, 0, 3, 3, d_dRT, 0, 3);
-
- // The derivative of Rx+T wrt x is just R.
- copyMatrix(_cams[i].getRotation(), d_dX);
- } // end MetricBundleOptimizerBase::poseDerivatives()
-
-
-//----------------------------------------------------------------------
-
- void
- StdMetricBundleOptimizer::fillJacobians(Matrix<double>& Ak,
- Matrix<double>& Bk,
- Matrix<double>& Ck,
- int i, int j, int k)
- {
- Vector3d XX;
- Matrix3x6d d_dRT;
- Matrix3x3d d_dX;
- this->poseDerivatives(i, j, XX, d_dRT, d_dX);
-
- double const f = _cams[i].getFocalLength();
- double const ar = _cams[i].getAspectRatio();
-
- Matrix2x3d dp_dX;
- double const bx = f / (XX[2] * XX[2]);
- double const by = ar * bx;
- dp_dX[0][0] = bx * XX[2]; dp_dX[0][1] = 0; dp_dX[0][2] = -bx * XX[0];
- dp_dX[1][0] = 0; dp_dX[1][1] = by * XX[2]; dp_dX[1][2] = -by * XX[1];
-
- multiply_A_B(dp_dX, d_dRT, Ak);
- multiply_A_B(dp_dX, d_dX, Bk);
- } // end StdMetricBundleOptimizer::fillJacobians()
-
- //----------------------------------------------------------------------
-
- void
- CommonInternalsMetricBundleOptimizer::fillJacobians(Matrix<double>& Ak,
- Matrix<double>& Bk,
- Matrix<double>& Ck,
- int i, int j, int k)
- {
- double const focalLength = _K[0][0];
-
- Vector3d XX;
- Matrix3x6d dXX_dRT;
- Matrix3x3d dXX_dX;
- this->poseDerivatives(i, j, XX, dXX_dRT, dXX_dX);
-
- Vector2d xu; // undistorted image point
- xu[0] = XX[0] / XX[2];
- xu[1] = XX[1] / XX[2];
-
- Vector2d const xd = _distortion(xu); // distorted image point
-
- Matrix2x2d dp_dxd;
- dp_dxd[0][0] = focalLength; dp_dxd[0][1] = 0;
- dp_dxd[1][0] = 0; dp_dxd[1][1] = _cachedAspectRatio * focalLength;
-
- {
- // First, lets do the derivative wrt the structure and motion parameters.
- Matrix2x3d dxu_dXX;
- dxu_dXX[0][0] = 1.0f / XX[2]; dxu_dXX[0][1] = 0; dxu_dXX[0][2] = -XX[0]/(XX[2]*XX[2]);
- dxu_dXX[1][0] = 0; dxu_dXX[1][1] = 1.0f / XX[2]; dxu_dXX[1][2] = -XX[1]/(XX[2]*XX[2]);
-
- Matrix2x2d dxd_dxu = _distortion.derivativeWrtUndistortedPoint(xu);
-
- Matrix2x2d dp_dxu = dp_dxd * dxd_dxu;
- Matrix2x3d dp_dXX = dp_dxu * dxu_dXX;
-
- multiply_A_B(dp_dXX, dXX_dRT, Ak);
- multiply_A_B(dp_dXX, dXX_dX, Bk);
- } // end scope
-
- switch (_mode)
- {
- case FULL_BUNDLE_FOCAL_AND_RADIAL_K1:
- {
- // Focal length.
- Ck[0][0] = xd[0];
- Ck[1][0] = xd[1];
-
- // For radial, k1 only.
- Matrix2x2d dxd_dk1k2 = _distortion.derivativeWrtRadialParameters(xu);
- Matrix2x2d d_dk1k2 = dp_dxd * dxd_dk1k2;
- Ck[0][1] = d_dk1k2[0][0];
- Ck[1][1] = d_dk1k2[1][0];
- break;
- }
- case FULL_BUNDLE_FOCAL_AND_RADIAL:
- {
- // Focal length.
- Ck[0][0] = xd[0];
- Ck[1][0] = xd[1];
-
- // Radial k1 and k2.
- Matrix2x2d dxd_dk1k2 = _distortion.derivativeWrtRadialParameters(xu);
- Matrix2x2d d_dk1k2 = dp_dxd * dxd_dk1k2;
- copyMatrixSlice(d_dk1k2, 0, 0, 2, 2, Ck, 0, 1);
- break;
- }
- case FULL_BUNDLE_RADIAL_TANGENTIAL:
- {
- Matrix2x2d dxd_dp1p2 = _distortion.derivativeWrtTangentialParameters(xu);
- Matrix2x2d d_dp1p2 = dp_dxd * dxd_dp1p2;
- copyMatrixSlice(d_dp1p2, 0, 0, 2, 2, Ck, 0, 5);
- // No break here!
- }
- case FULL_BUNDLE_RADIAL:
- {
- Matrix2x2d dxd_dk1k2 = _distortion.derivativeWrtRadialParameters(xu);
- Matrix2x2d d_dk1k2 = dp_dxd * dxd_dk1k2;
- copyMatrixSlice(d_dk1k2, 0, 0, 2, 2, Ck, 0, 3);
- // No break here!
- }
- case FULL_BUNDLE_FOCAL_LENGTH_PP:
- {
- Ck[0][1] = 1; Ck[0][2] = 0;
- Ck[1][1] = 0; Ck[1][2] = 1;
- // No break here!
- }
- case FULL_BUNDLE_FOCAL_LENGTH:
- {
- Ck[0][0] = xd[0];
- Ck[1][0] = xd[1];
- }
- case FULL_BUNDLE_METRIC:
- {
- }
- } // end switch
- } // end CommonInternalsMetricBundleOptimizer::fillJacobians()
-
- void
- CommonInternalsMetricBundleOptimizer::updateParametersC(Vector<double> const& deltaC)
- {
- switch (_mode)
- {
- case FULL_BUNDLE_FOCAL_AND_RADIAL_K1:
- {
- _K[0][0] += deltaC[0];
- _K[1][1] = _cachedAspectRatio * _K[0][0];
- _distortion.k1 += deltaC[1];
- break;
- }
- case FULL_BUNDLE_FOCAL_AND_RADIAL:
- {
- _K[0][0] += deltaC[0];
- _K[1][1] = _cachedAspectRatio * _K[0][0];
- _distortion.k1 += deltaC[1];
- _distortion.k2 += deltaC[2];
- break;
- }
- case FULL_BUNDLE_RADIAL_TANGENTIAL:
- {
- _distortion.p1 += deltaC[5];
- _distortion.p2 += deltaC[6];
- // No break here!
- }
- case FULL_BUNDLE_RADIAL:
- {
- _distortion.k1 += deltaC[3];
- _distortion.k2 += deltaC[4];
- // No break here!
- }
- case FULL_BUNDLE_FOCAL_LENGTH_PP:
- {
- _K[0][2] += deltaC[1];
- _K[1][2] += deltaC[2];
- // No break here!
- }
- case FULL_BUNDLE_FOCAL_LENGTH:
- {
- _K[0][0] += deltaC[0];
- _K[1][1] = _cachedAspectRatio * _K[0][0];
- }
- case FULL_BUNDLE_METRIC:
- {
- }
- } // end switch
- } // end CommonInternalsMetricBundleOptimizer::updateParametersC()
-
- //----------------------------------------------------------------------
-
- void
- VaryingInternalsMetricBundleOptimizer::fillJacobians(Matrix<double>& Ak,
- Matrix<double>& Bk,
- Matrix<double>& Ck,
- int i, int j, int k)
- {
- Vector3d XX;
- Matrix3x6d dXX_dRT;
- Matrix3x3d dXX_dX;
- this->poseDerivatives(i, j, XX, dXX_dRT, dXX_dX);
-
- Vector2d xu; // undistorted image point
- xu[0] = XX[0] / XX[2];
- xu[1] = XX[1] / XX[2];
-
- Vector2d const xd = _distortions[i](xu); // distorted image point
-
- double const focalLength = _cams[i].getFocalLength();
- double const aspectRatio = _cams[i].getAspectRatio();
-
- Matrix2x2d dp_dxd;
- dp_dxd[0][0] = focalLength; dp_dxd[0][1] = 0;
- dp_dxd[1][0] = 0; dp_dxd[1][1] = aspectRatio * focalLength;
-
- {
- // First, lets do the derivative wrt the structure and motion parameters.
- Matrix2x3d dxu_dXX;
- dxu_dXX[0][0] = 1.0f / XX[2]; dxu_dXX[0][1] = 0; dxu_dXX[0][2] = -XX[0]/(XX[2]*XX[2]);
- dxu_dXX[1][0] = 0; dxu_dXX[1][1] = 1.0f / XX[2]; dxu_dXX[1][2] = -XX[1]/(XX[2]*XX[2]);
-
- Matrix2x2d dxd_dxu = _distortions[i].derivativeWrtUndistortedPoint(xu);
-
- Matrix2x2d dp_dxu = dp_dxd * dxd_dxu;
- Matrix2x3d dp_dXX = dp_dxu * dxu_dXX;
-
- Matrix2x6d dp_dRT;
-
- multiply_A_B(dp_dXX, dXX_dRT, dp_dRT);
- copyMatrixSlice(dp_dRT, 0, 0, 2, 6, Ak, 0, 0);
- multiply_A_B(dp_dXX, dXX_dX, Bk);
- } // end scope
-
- switch (_mode)
- {
- case FULL_BUNDLE_RADIAL_TANGENTIAL:
- {
- Matrix2x2d dxd_dp1p2 = _distortions[i].derivativeWrtTangentialParameters(xu);
- Matrix2x2d d_dp1p2 = dp_dxd * dxd_dp1p2;
- copyMatrixSlice(d_dp1p2, 0, 0, 2, 2, Ak, 0, 11);
- // No break here!
- }
- case FULL_BUNDLE_RADIAL:
- {
- Matrix2x2d dxd_dk1k2 = _distortions[i].derivativeWrtRadialParameters(xu);
- Matrix2x2d d_dk1k2 = dp_dxd * dxd_dk1k2;
- copyMatrixSlice(d_dk1k2, 0, 0, 2, 2, Ak, 0, 9);
- // No break here!
- }
- case FULL_BUNDLE_FOCAL_LENGTH_PP:
- {
- Ak[0][7] = 1; Ak[0][8] = 0;
- Ak[1][7] = 0; Ak[1][8] = 1;
- // No break here!
- }
- case FULL_BUNDLE_FOCAL_LENGTH:
- {
- Ak[0][6] = xd[0];
- Ak[1][6] = xd[1];
- }
- case FULL_BUNDLE_METRIC:
- {
- }
- } // end switch
- } // end VaryingInternalsMetricBundleOptimizer::fillJacobians()
-
- void
- VaryingInternalsMetricBundleOptimizer::updateParametersA(VectorArray<double> const& deltaAi)
- {
- Vector3d T, omega;
- Matrix3x3d R0, dR, K;
-
- for (int i = _nNonvaryingA; i < _nParametersA; ++i)
- {
- Vector<double> const& deltaA = deltaAi[i];
-
- T = _cams[i].getTranslation();
- T[0] += deltaA[0];
- T[1] += deltaA[1];
- T[2] += deltaA[2];
- _cams[i].setTranslation(T);
-
- // Create incremental rotation using Rodriguez formula.
- R0 = _cams[i].getRotation();
- omega[0] = deltaA[3];
- omega[1] = deltaA[4];
- omega[2] = deltaA[5];
- createRotationMatrixRodriguez(omega, dR);
- _cams[i].setRotation(dR * R0);
-
- K = _cams[i].getIntrinsic();
-
- switch (_mode)
- {
- case FULL_BUNDLE_RADIAL_TANGENTIAL:
- {
- _distortions[i].p1 += deltaA[11];
- _distortions[i].p2 += deltaA[12];
- // No break here!
- }
- case FULL_BUNDLE_RADIAL:
- {
- _distortions[i].k1 += deltaA[9];
- _distortions[i].k2 += deltaA[10];
- // No break here!
- }
- case FULL_BUNDLE_FOCAL_LENGTH_PP:
- {
- K[0][2] += deltaA[7];
- K[1][2] += deltaA[8];
- // No break here!
- }
- case FULL_BUNDLE_FOCAL_LENGTH:
- {
- double const ar = K[1][1] / K[0][0];
- K[0][0] += deltaA[6];
- K[1][1] = ar * K[0][0];
- }
- case FULL_BUNDLE_METRIC:
- {
- }
- } // end switch
- _cams[i].setIntrinsic(K);
- } // end for (i)
- } // end VaryingInternalsMetricBundleOptimizer::updateParametersC()
-
-} // end namespace V3D
-
-#endif // defined(V3DLIB_ENABLE_SUITESPARSE)
diff --git a/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.h b/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.h
deleted file mode 100644
index 339e174ed9e..00000000000
--- a/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.h
+++ /dev/null
@@ -1,352 +0,0 @@
-// -*- C++ -*-
-/*
-Copyright (c) 2008 University of North Carolina at Chapel Hill
-
-This file is part of SSBA (Simple Sparse Bundle Adjustment).
-
-SSBA is free software: you can redistribute it and/or modify it under the
-terms of the GNU Lesser General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option) any
-later version.
-
-SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with SSBA. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef V3D_METRICBUNDLE_H
-#define V3D_METRICBUNDLE_H
-
-# if defined(V3DLIB_ENABLE_SUITESPARSE)
-
-#include "Math/v3d_optimization.h"
-#include "Math/v3d_linear.h"
-#include "Math/v3d_linear_utils.h"
-#include "Geometry/v3d_cameramatrix.h"
-#include "Geometry/v3d_distortion.h"
-
-namespace V3D
-{
-
- // This structure provides some helper functions common to all metric BAs
- struct MetricBundleOptimizerBase : public SparseLevenbergOptimizer
- {
- typedef SparseLevenbergOptimizer Base;
-
- MetricBundleOptimizerBase(double inlierThreshold,
- vector<CameraMatrix>& cams,
- vector<Vector3d >& Xs,
- vector<Vector2d > const& measurements,
- vector<int> const& corrspondingView,
- vector<int> const& corrspondingPoint,
- int nAddParamsA, int nParamsC)
- : SparseLevenbergOptimizer(2, cams.size(), 6+nAddParamsA, Xs.size(), 3, nParamsC,
- corrspondingView, corrspondingPoint),
- _cams(cams), _Xs(Xs), _measurements(measurements),
- _savedTranslations(cams.size()), _savedRotations(cams.size()),
- _savedXs(Xs.size()),
- _inlierThreshold(inlierThreshold), _cachedParamLength(0.0)
- {
- // Since we assume that BA does not alter the inputs too much,
- // we compute the overall length of the parameter vector in advance
- // and return that value as the result of getParameterLength().
- for (int i = _nNonvaryingA; i < _nParametersA; ++i)
- {
- _cachedParamLength += sqrNorm_L2(_cams[i].getTranslation());
- _cachedParamLength += 3.0; // Assume eye(3) for R.
- }
- for (int j = _nNonvaryingB; j < _nParametersB; ++j)
- _cachedParamLength += sqrNorm_L2(_Xs[j]);
-
- _cachedParamLength = sqrt(_cachedParamLength);
- }
-
- // Huber robust cost function.
- virtual void fillWeights(VectorArray<double> const& residual, Vector<double>& w)
- {
- for (unsigned int k = 0; k < w.size(); ++k)
- {
- Vector<double> const& r = residual[k];
- double const e = norm_L2(r);
- w[k] = (e < _inlierThreshold) ? 1.0 : sqrt(_inlierThreshold / e);
- } // end for (k)
- }
-
- virtual double getParameterLength() const
- {
- return _cachedParamLength;
- }
-
- virtual void updateParametersA(VectorArray<double> const& deltaAi);
- virtual void updateParametersB(VectorArray<double> const& deltaBj);
- virtual void updateParametersC(Vector<double> const& deltaC)
- {
- (void)deltaC;
- }
-
- virtual void saveAllParameters()
- {
- for (int i = _nNonvaryingA; i < _nParametersA; ++i)
- {
- _savedTranslations[i] = _cams[i].getTranslation();
- _savedRotations[i] = _cams[i].getRotation();
- }
- _savedXs = _Xs;
- }
-
- virtual void restoreAllParameters()
- {
- for (int i = _nNonvaryingA; i < _nParametersA; ++i)
- {
- _cams[i].setTranslation(_savedTranslations[i]);
- _cams[i].setRotation(_savedRotations[i]);
- }
- _Xs = _savedXs;
- }
-
- protected:
- typedef InlineMatrix<double, 3, 6> Matrix3x6d;
-
- void poseDerivatives(int i, int j, Vector3d& XX,
- Matrix3x6d& d_dRT, Matrix3x3d& d_dX) const;
-
- vector<CameraMatrix>& _cams;
- vector<Vector3d>& _Xs;
-
- vector<Vector2d> const& _measurements;
-
- vector<Vector3d> _savedTranslations;
- vector<Matrix3x3d> _savedRotations;
- vector<Vector3d> _savedXs;
-
- double const _inlierThreshold;
- double _cachedParamLength;
- }; // end struct MetricBundleOptimizerBase
-
- struct StdMetricBundleOptimizer : public MetricBundleOptimizerBase
- {
- typedef MetricBundleOptimizerBase Base;
-
- StdMetricBundleOptimizer(double inlierThreshold,
- vector<CameraMatrix>& cams,
- vector<Vector3d >& Xs,
- vector<Vector2d > const& measurements,
- vector<int> const& corrspondingView,
- vector<int> const& corrspondingPoint)
- : MetricBundleOptimizerBase(inlierThreshold, cams, Xs, measurements,
- corrspondingView, corrspondingPoint, 0, 0)
- { }
-
- virtual void evalResidual(VectorArray<double>& e)
- {
- for (unsigned int k = 0; k < e.count(); ++k)
- {
- int const i = _correspondingParamA[k];
- int const j = _correspondingParamB[k];
-
- Vector2d const q = _cams[i].projectPoint(_Xs[j]);
- e[k][0] = q[0] - _measurements[k][0];
- e[k][1] = q[1] - _measurements[k][1];
- }
- }
-
- virtual void fillJacobians(Matrix<double>& Ak, Matrix<double>& Bk, Matrix<double>& Ck,
- int i, int j, int k);
- }; // end struct StdMetricBundleOptimizer
-
-//----------------------------------------------------------------------
-
- enum
- {
- FULL_BUNDLE_METRIC = 0,
- FULL_BUNDLE_FOCAL_LENGTH = 1, // f
- FULL_BUNDLE_FOCAL_LENGTH_PP = 2, // f, cx, cy
- FULL_BUNDLE_RADIAL = 3, // f, cx, cy, k1, k2
- FULL_BUNDLE_RADIAL_TANGENTIAL = 4, // f, cx, cy, k1, k2, p1, p2
- FULL_BUNDLE_FOCAL_AND_RADIAL_K1 = 5, // f, k1
- FULL_BUNDLE_FOCAL_AND_RADIAL = 6, // f, k1, k2
- };
-
- struct CommonInternalsMetricBundleOptimizer : public MetricBundleOptimizerBase
- {
- static int globalParamDimensionFromMode(int mode)
- {
- switch (mode)
- {
- case FULL_BUNDLE_METRIC: return 0;
- case FULL_BUNDLE_FOCAL_LENGTH: return 1;
- case FULL_BUNDLE_FOCAL_LENGTH_PP: return 3;
- case FULL_BUNDLE_RADIAL: return 5;
- case FULL_BUNDLE_RADIAL_TANGENTIAL: return 7;
- case FULL_BUNDLE_FOCAL_AND_RADIAL_K1: return 2;
- case FULL_BUNDLE_FOCAL_AND_RADIAL: return 3;
- }
- return 0;
- }
-
- typedef MetricBundleOptimizerBase Base;
-
- CommonInternalsMetricBundleOptimizer(int mode,
- double inlierThreshold,
- Matrix3x3d& K,
- StdDistortionFunction& distortion,
- vector<CameraMatrix>& cams,
- vector<Vector3d >& Xs,
- vector<Vector2d > const& measurements,
- vector<int> const& corrspondingView,
- vector<int> const& corrspondingPoint)
- : MetricBundleOptimizerBase(inlierThreshold, cams, Xs, measurements,
- corrspondingView, corrspondingPoint,
- 0, globalParamDimensionFromMode(mode)),
- _mode(mode), _K(K), _distortion(distortion)
- {
- _cachedAspectRatio = K[1][1] / K[0][0];
- }
-
- Vector2d projectPoint(Vector3d const& X, int i) const
- {
- Vector3d const XX = _cams[i].transformPointIntoCameraSpace(X);
- Vector2d p;
- p[0] = XX[0] / XX[2];
- p[1] = XX[1] / XX[2];
- p = _distortion(p);
- Vector2d res;
- res[0] = _K[0][0] * p[0] + _K[0][1] * p[1] + _K[0][2];
- res[1] = _K[1][1] * p[1] + _K[1][2];
- return res;
- }
-
- virtual void evalResidual(VectorArray<double>& e)
- {
- for (unsigned int k = 0; k < e.count(); ++k)
- {
- int const i = _correspondingParamA[k];
- int const j = _correspondingParamB[k];
-
- Vector2d const q = this->projectPoint(_Xs[j], i);
- e[k][0] = q[0] - _measurements[k][0];
- e[k][1] = q[1] - _measurements[k][1];
- }
- }
-
- virtual void fillJacobians(Matrix<double>& Ak, Matrix<double>& Bk, Matrix<double>& Ck,
- int i, int j, int k);
-
- virtual void updateParametersC(Vector<double> const& deltaC);
-
- virtual void saveAllParameters()
- {
- Base::saveAllParameters();
- _savedK = _K;
- _savedDistortion = _distortion;
- }
-
- virtual void restoreAllParameters()
- {
- Base::restoreAllParameters();
- _K = _savedK;
- _distortion = _savedDistortion;
- }
-
- protected:
- int _mode;
- Matrix3x3d& _K;
- StdDistortionFunction& _distortion;
-
- Matrix3x3d _savedK;
- StdDistortionFunction _savedDistortion;
- double _cachedAspectRatio;
- }; // end struct CommonInternalsMetricBundleOptimizer
-
-//----------------------------------------------------------------------
-
- struct VaryingInternalsMetricBundleOptimizer : public MetricBundleOptimizerBase
- {
- static int extParamDimensionFromMode(int mode)
- {
- switch (mode)
- {
- case FULL_BUNDLE_METRIC: return 0;
- case FULL_BUNDLE_FOCAL_LENGTH: return 1;
- case FULL_BUNDLE_FOCAL_LENGTH_PP: return 3;
- case FULL_BUNDLE_RADIAL: return 5;
- case FULL_BUNDLE_RADIAL_TANGENTIAL: return 7;
- case FULL_BUNDLE_FOCAL_AND_RADIAL_K1: return 2;
- case FULL_BUNDLE_FOCAL_AND_RADIAL: return 3;
- }
- return 0;
- }
-
- typedef MetricBundleOptimizerBase Base;
-
- VaryingInternalsMetricBundleOptimizer(int mode,
- double inlierThreshold,
- std::vector<StdDistortionFunction>& distortions,
- vector<CameraMatrix>& cams,
- vector<Vector3d >& Xs,
- vector<Vector2d > const& measurements,
- vector<int> const& corrspondingView,
- vector<int> const& corrspondingPoint)
- : MetricBundleOptimizerBase(inlierThreshold, cams, Xs, measurements,
- corrspondingView, corrspondingPoint,
- extParamDimensionFromMode(mode), 0),
- _mode(mode), _distortions(distortions),
- _savedKs(cams.size()), _savedDistortions(cams.size())
- { }
-
- Vector2d projectPoint(Vector3d const& X, int i) const
- {
- return _cams[i].projectPoint(_distortions[i], X);
- }
-
- virtual void evalResidual(VectorArray<double>& e)
- {
- for (unsigned int k = 0; k < e.count(); ++k)
- {
- int const i = _correspondingParamA[k];
- int const j = _correspondingParamB[k];
-
- Vector2d const q = this->projectPoint(_Xs[j], i);
- e[k][0] = q[0] - _measurements[k][0];
- e[k][1] = q[1] - _measurements[k][1];
- }
- }
-
- virtual void fillJacobians(Matrix<double>& Ak, Matrix<double>& Bk, Matrix<double>& Ck,
- int i, int j, int k);
-
- virtual void updateParametersA(VectorArray<double> const& deltaAi);
-
- virtual void saveAllParameters()
- {
- Base::saveAllParameters();
- for (int i = _nNonvaryingA; i < _nParametersA; ++i)
- _savedKs[i] = _cams[i].getIntrinsic();
- std::copy(_distortions.begin(), _distortions.end(), _savedDistortions.begin());
- }
-
- virtual void restoreAllParameters()
- {
- Base::restoreAllParameters();
- for (int i = _nNonvaryingA; i < _nParametersA; ++i)
- _cams[i].setIntrinsic(_savedKs[i]);
- std::copy(_savedDistortions.begin(), _savedDistortions.end(), _distortions.begin());
- }
-
- protected:
- int _mode;
- std::vector<StdDistortionFunction>& _distortions;
-
- std::vector<Matrix3x3d> _savedKs;
- std::vector<StdDistortionFunction> _savedDistortions;
- }; // end struct VaryingInternalsMetricBundleOptimizer
-
-} // end namespace V3D
-
-# endif
-
-#endif
diff --git a/extern/libmv/third_party/ssba/Math/v3d_linear.h b/extern/libmv/third_party/ssba/Math/v3d_linear.h
deleted file mode 100644
index 7d6e898169c..00000000000
--- a/extern/libmv/third_party/ssba/Math/v3d_linear.h
+++ /dev/null
@@ -1,923 +0,0 @@
-// -*- C++ -*-
-/*
-Copyright (c) 2008 University of North Carolina at Chapel Hill
-
-This file is part of SSBA (Simple Sparse Bundle Adjustment).
-
-SSBA is free software: you can redistribute it and/or modify it under the
-terms of the GNU Lesser General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option) any
-later version.
-
-SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with SSBA. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef V3D_LINEAR_H
-#define V3D_LINEAR_H
-
-#include <cassert>
-#include <algorithm>
-#include <vector>
-#include <cmath>
-
-namespace V3D
-{
- using namespace std;
-
- //! Unboxed vector type
- template <typename Elem, int Size>
- struct InlineVectorBase
- {
- typedef Elem value_type;
- typedef Elem element_type;
-
- typedef Elem const * const_iterator;
- typedef Elem * iterator;
-
- static unsigned int size() { return Size; }
-
- Elem& operator[](unsigned int i) { return _vec[i]; }
- Elem operator[](unsigned int i) const { return _vec[i]; }
-
- Elem& operator()(unsigned int i) { return _vec[i-1]; }
- Elem operator()(unsigned int i) const { return _vec[i-1]; }
-
- const_iterator begin() const { return _vec; }
- iterator begin() { return _vec; }
- const_iterator end() const { return _vec + Size; }
- iterator end() { return _vec + Size; }
-
- void newsize(unsigned int sz) const
- {
- assert(sz == Size);
- }
-
- protected:
- Elem _vec[Size];
- };
-
- //! Boxed (heap allocated) vector.
- template <typename Elem>
- struct VectorBase
- {
- typedef Elem value_type;
- typedef Elem element_type;
-
- typedef Elem const * const_iterator;
- typedef Elem * iterator;
-
- VectorBase()
- : _size(0), _ownsVec(true), _vec(0)
- { }
-
- VectorBase(unsigned int size)
- : _size(size), _ownsVec(true), _vec(0)
- {
- if (size > 0) _vec = new Elem[size];
- }
-
- VectorBase(unsigned int size, Elem * values)
- : _size(size), _ownsVec(false), _vec(values)
- { }
-
- VectorBase(VectorBase<Elem> const& a)
- : _size(0), _ownsVec(true), _vec(0)
- {
- _size = a._size;
- if (_size == 0) return;
- _vec = new Elem[_size];
- std::copy(a._vec, a._vec + _size, _vec);
- }
-
- ~VectorBase() { if (_ownsVec && _vec != 0) delete [] _vec; }
-
- VectorBase& operator=(VectorBase<Elem> const& a)
- {
- if (this == &a) return *this;
-
- this->newsize(a._size);
- std::copy(a._vec, a._vec + _size, _vec);
- return *this;
- }
-
- unsigned int size() const { return _size; }
-
- VectorBase<Elem>& newsize(unsigned int sz)
- {
- if (sz == _size) return *this;
- assert(_ownsVec);
-
- __destroy();
- _size = sz;
- if (_size > 0) _vec = new Elem[_size];
-
- return *this;
- }
-
-
- Elem& operator[](unsigned int i) { return _vec[i]; }
- Elem operator[](unsigned int i) const { return _vec[i]; }
-
- Elem& operator()(unsigned int i) { return _vec[i-1]; }
- Elem operator()(unsigned int i) const { return _vec[i-1]; }
-
- const_iterator begin() const { return _vec; }
- iterator begin() { return _vec; }
- const_iterator end() const { return _vec + _size; }
- iterator end() { return _vec + _size; }
-
- protected:
- void __destroy()
- {
- assert(_ownsVec);
-
- if (_vec != 0) delete [] _vec;
- _size = 0;
- _vec = 0;
- }
-
- unsigned int _size;
- bool _ownsVec;
- Elem * _vec;
- };
-
- template <typename Elem, int Rows, int Cols>
- struct InlineMatrixBase
- {
- typedef Elem value_type;
- typedef Elem element_type;
-
- typedef Elem * iterator;
- typedef Elem const * const_iterator;
-
- static unsigned int num_rows() { return Rows; }
- static unsigned int num_cols() { return Cols; }
-
- Elem * operator[](unsigned int row) { return _m[row]; }
- Elem const * operator[](unsigned int row) const { return _m[row]; }
-
- Elem& operator()(unsigned int row, unsigned int col) { return _m[row-1][col-1]; }
- Elem operator()(unsigned int row, unsigned int col) const { return _m[row-1][col-1]; }
-
- template <typename Vec>
- void getRowSlice(unsigned int row, unsigned int first, unsigned int last, Vec& dst) const
- {
- for (unsigned int c = first; c < last; ++c) dst[c-first] = _m[row][c];
- }
-
- template <typename Vec>
- void getColumnSlice(unsigned int first, unsigned int len, unsigned int col, Vec& dst) const
- {
- for (unsigned int r = 0; r < len; ++r) dst[r] = _m[r+first][col];
- }
-
- void newsize(unsigned int rows, unsigned int cols) const
- {
- assert(rows == Rows && cols == Cols);
- }
-
- const_iterator begin() const { return &_m[0][0]; }
- iterator begin() { return &_m[0][0]; }
- const_iterator end() const { return &_m[0][0] + Rows*Cols; }
- iterator end() { return &_m[0][0] + Rows*Cols; }
-
- protected:
- Elem _m[Rows][Cols];
- };
-
- template <typename Elem>
- struct MatrixBase
- {
- typedef Elem value_type;
- typedef Elem element_type;
-
- typedef Elem const * const_iterator;
- typedef Elem * iterator;
-
- MatrixBase()
- : _rows(0), _cols(0), _ownsData(true), _m(0)
- { }
-
- MatrixBase(unsigned int rows, unsigned int cols)
- : _rows(rows), _cols(cols), _ownsData(true), _m(0)
- {
- if (_rows * _cols == 0) return;
- _m = new Elem[rows*cols];
- }
-
- MatrixBase(unsigned int rows, unsigned int cols, Elem * values)
- : _rows(rows), _cols(cols), _ownsData(false), _m(values)
- { }
-
- MatrixBase(MatrixBase<Elem> const& a)
- : _ownsData(true), _m(0)
- {
- _rows = a._rows; _cols = a._cols;
- if (_rows * _cols == 0) return;
- _m = new Elem[_rows*_cols];
- std::copy(a._m, a._m+_rows*_cols, _m);
- }
-
- ~MatrixBase()
- {
- if (_ownsData && _m != 0) delete [] _m;
- }
-
- MatrixBase& operator=(MatrixBase<Elem> const& a)
- {
- if (this == &a) return *this;
-
- this->newsize(a.num_rows(), a.num_cols());
-
- std::copy(a._m, a._m+_rows*_cols, _m);
- return *this;
- }
-
- void newsize(unsigned int rows, unsigned int cols)
- {
- if (rows == _rows && cols == _cols) return;
-
- assert(_ownsData);
-
- __destroy();
-
- _rows = rows;
- _cols = cols;
- if (_rows * _cols == 0) return;
- _m = new Elem[rows*cols];
- }
-
- unsigned int num_rows() const { return _rows; }
- unsigned int num_cols() const { return _cols; }
-
- Elem * operator[](unsigned int row) { return _m + row*_cols; }
- Elem const * operator[](unsigned int row) const { return _m + row*_cols; }
-
- Elem& operator()(unsigned int row, unsigned int col) { return _m[(row-1)*_cols + col-1]; }
- Elem operator()(unsigned int row, unsigned int col) const { return _m[(row-1)*_cols + col-1]; }
-
- const_iterator begin() const { return _m; }
- iterator begin() { return _m; }
- const_iterator end() const { return _m + _rows*_cols; }
- iterator end() { return _m + _rows*_cols; }
-
- template <typename Vec>
- void getRowSlice(unsigned int row, unsigned int first, unsigned int last, Vec& dst) const
- {
- Elem const * v = (*this)[row];
- for (unsigned int c = first; c < last; ++c) dst[c-first] = v[c];
- }
-
- template <typename Vec>
- void getColumnSlice(unsigned int first, unsigned int len, unsigned int col, Vec& dst) const
- {
- for (unsigned int r = 0; r < len; ++r) dst[r] = _m[r+first][col];
- }
-
- protected:
- void __destroy()
- {
- assert(_ownsData);
- if (_m != 0) delete [] _m;
- _m = 0;
- _rows = _cols = 0;
- }
-
- unsigned int _rows, _cols;
- bool _ownsData;
- Elem * _m;
- };
-
- template <typename T>
- struct CCS_Matrix
- {
- CCS_Matrix()
- : _rows(0), _cols(0)
- { }
-
- CCS_Matrix(int const rows, int const cols, vector<pair<int, int> > const& nonZeros)
- : _rows(rows), _cols(cols)
- {
- this->initialize(nonZeros);
- }
-
- CCS_Matrix(CCS_Matrix const& b)
- : _rows(b._rows), _cols(b._cols),
- _colStarts(b._colStarts), _rowIdxs(b._rowIdxs), _destIdxs(b._destIdxs), _values(b._values)
- { }
-
- CCS_Matrix& operator=(CCS_Matrix const& b)
- {
- if (this == &b) return *this;
- _rows = b._rows;
- _cols = b._cols;
- _colStarts = b._colStarts;
- _rowIdxs = b._rowIdxs;
- _destIdxs = b._destIdxs;
- _values = b._values;
- return *this;
- }
-
- void create(int const rows, int const cols, vector<pair<int, int> > const& nonZeros)
- {
- _rows = rows;
- _cols = cols;
- this->initialize(nonZeros);
- }
-
- unsigned int num_rows() const { return _rows; }
- unsigned int num_cols() const { return _cols; }
-
- int getNonzeroCount() const { return _values.size(); }
-
- T const * getValues() const { return &_values[0]; }
- T * getValues() { return &_values[0]; }
-
- int const * getDestIndices() const { return &_destIdxs[0]; }
- int const * getColumnStarts() const { return &_colStarts[0]; }
- int const * getRowIndices() const { return &_rowIdxs[0]; }
-
- void getRowRange(unsigned int col, unsigned int& firstRow, unsigned int& lastRow) const
- {
- firstRow = _rowIdxs[_colStarts[col]];
- lastRow = _rowIdxs[_colStarts[col+1]-1]+1;
- }
-
- template <typename Vec>
- void getColumnSlice(unsigned int first, unsigned int len, unsigned int col, Vec& dst) const
- {
- unsigned int const last = first + len;
-
- for (int r = 0; r < len; ++r) dst[r] = 0; // Fill vector with zeros
-
- int const colStart = _colStarts[col];
- int const colEnd = _colStarts[col+1];
-
- int i = colStart;
- int r;
- // Skip rows less than the given start row
- while (i < colEnd && (r = _rowIdxs[i]) < first) ++i;
-
- // Copy elements until the final row
- while (i < colEnd && (r = _rowIdxs[i]) < last)
- {
- dst[r-first] = _values[i];
- ++i;
- }
- } // end getColumnSlice()
-
- int getColumnNonzeroCount(unsigned int col) const
- {
- int const colStart = _colStarts[col];
- int const colEnd = _colStarts[col+1];
- return colEnd - colStart;
- }
-
- template <typename VecA, typename VecB>
- void getSparseColumn(unsigned int col, VecA& rows, VecB& values) const
- {
- int const colStart = _colStarts[col];
- int const colEnd = _colStarts[col+1];
- int const nnz = colEnd - colStart;
-
- for (int i = 0; i < nnz; ++i)
- {
- rows[i] = _rowIdxs[colStart + i];
- values[i] = _values[colStart + i];
- }
- }
-
- protected:
- struct NonzeroInfo
- {
- int row, col, serial;
-
- // Sort wrt the column first
- bool operator<(NonzeroInfo const& rhs) const
- {
- if (col < rhs.col) return true;
- if (col > rhs.col) return false;
- return row < rhs.row;
- }
- };
-
- void initialize(std::vector<std::pair<int, int> > const& nonZeros)
- {
- using namespace std;
-
- int const nnz = nonZeros.size();
-
- _colStarts.resize(_cols + 1);
- _rowIdxs.resize(nnz);
-
- vector<NonzeroInfo> nz(nnz);
- for (int k = 0; k < nnz; ++k)
- {
- nz[k].row = nonZeros[k].first;
- nz[k].col = nonZeros[k].second;
- nz[k].serial = k;
- }
-
- // Sort in column major order
- std::sort(nz.begin(), nz.end());
-
- for (size_t k = 0; k < nnz; ++k) _rowIdxs[k] = nz[k].row;
-
- int curCol = -1;
- for (int k = 0; k < nnz; ++k)
- {
- NonzeroInfo const& el = nz[k];
- if (el.col != curCol)
- {
- // Update empty cols between
- for (int c = curCol+1; c < el.col; ++c) _colStarts[c] = k;
-
- curCol = el.col;
- _colStarts[curCol] = k;
- } // end if
- } // end for (k)
-
- // Update remaining columns
- for (int c = curCol+1; c <= _cols; ++c) _colStarts[c] = nnz;
-
- _destIdxs.resize(nnz);
- for (int k = 0; k < nnz; ++k) _destIdxs[nz[k].serial] = k;
-
- _values.resize(nnz);
- } // end initialize()
-
- int _rows, _cols;
- std::vector<int> _colStarts;
- std::vector<int> _rowIdxs;
- std::vector<int> _destIdxs;
- std::vector<T> _values;
- }; // end struct CCS_Matrix
-
-//----------------------------------------------------------------------
-
- template <typename Vec, typename Elem>
- inline void
- fillVector(Vec& v, Elem val)
- {
- // We do not use std::fill since we rely only on size() and operator[] member functions.
- for (unsigned int i = 0; i < v.size(); ++i) v[i] = val;
- }
-
- template <typename Vec>
- inline void
- makeZeroVector(Vec& v)
- {
- fillVector(v, 0);
- }
-
- template <typename VecA, typename VecB>
- inline void
- copyVector(VecA const& src, VecB& dst)
- {
- assert(src.size() == dst.size());
- // We do not use std::fill since we rely only on size() and operator[] member functions.
- for (unsigned int i = 0; i < src.size(); ++i) dst[i] = src[i];
- }
-
- template <typename VecA, typename VecB>
- inline void
- copyVectorSlice(VecA const& src, unsigned int srcStart, unsigned int srcLen,
- VecB& dst, unsigned int dstStart)
- {
- unsigned int const end = std::min(srcStart + srcLen, src.size());
- unsigned int const sz = dst.size();
- unsigned int i0, i1;
- for (i0 = srcStart, i1 = dstStart; i0 < end && i1 < sz; ++i0, ++i1) dst[i1] = src[i0];
- }
-
- template <typename Vec>
- inline typename Vec::value_type
- norm_L1(Vec const& v)
- {
- typename Vec::value_type res(0);
- for (unsigned int i = 0; i < v.size(); ++i) res += fabs(v[i]);
- return res;
- }
-
- template <typename Vec>
- inline typename Vec::value_type
- norm_Linf(Vec const& v)
- {
- typename Vec::value_type res(0);
- for (unsigned int i = 0; i < v.size(); ++i) res = std::max(res, fabs(v[i]));
- return res;
- }
-
- template <typename Vec>
- inline typename Vec::value_type
- norm_L2(Vec const& v)
- {
- typename Vec::value_type res(0);
- for (unsigned int i = 0; i < v.size(); ++i) res += v[i]*v[i];
- return sqrt((double)res);
- }
-
- template <typename Vec>
- inline typename Vec::value_type
- sqrNorm_L2(Vec const& v)
- {
- typename Vec::value_type res(0);
- for (unsigned int i = 0; i < v.size(); ++i) res += v[i]*v[i];
- return res;
- }
-
- template <typename Vec>
- inline void
- normalizeVector(Vec& v)
- {
- typename Vec::value_type norm(norm_L2(v));
- for (unsigned int i = 0; i < v.size(); ++i) v[i] /= norm;
- }
-
- template<typename VecA, typename VecB>
- inline typename VecA::value_type
- innerProduct(VecA const& a, VecB const& b)
- {
- assert(a.size() == b.size());
- typename VecA::value_type res(0);
- for (unsigned int i = 0; i < a.size(); ++i) res += a[i] * b[i];
- return res;
- }
-
- template <typename Elem, typename VecA, typename VecB>
- inline void
- scaleVector(Elem s, VecA const& v, VecB& dst)
- {
- for (unsigned int i = 0; i < v.size(); ++i) dst[i] = s * v[i];
- }
-
- template <typename Elem, typename Vec>
- inline void
- scaleVectorIP(Elem s, Vec& v)
- {
- typedef typename Vec::value_type Elem2;
- for (unsigned int i = 0; i < v.size(); ++i)
- v[i] = (Elem2)(v[i] * s);
- }
-
- template <typename VecA, typename VecB, typename VecC>
- inline void
- makeCrossProductVector(VecA const& v, VecB const& w, VecC& dst)
- {
- assert(v.size() == 3);
- assert(w.size() == 3);
- assert(dst.size() == 3);
- dst[0] = v[1]*w[2] - v[2]*w[1];
- dst[1] = v[2]*w[0] - v[0]*w[2];
- dst[2] = v[0]*w[1] - v[1]*w[0];
- }
-
- template <typename VecA, typename VecB, typename VecC>
- inline void
- addVectors(VecA const& v, VecB const& w, VecC& dst)
- {
- assert(v.size() == w.size());
- assert(v.size() == dst.size());
- for (unsigned int i = 0; i < v.size(); ++i) dst[i] = v[i] + w[i];
- }
-
- template <typename VecA, typename VecB, typename VecC>
- inline void
- subtractVectors(VecA const& v, VecB const& w, VecC& dst)
- {
- assert(v.size() == w.size());
- assert(v.size() == dst.size());
- for (unsigned int i = 0; i < v.size(); ++i) dst[i] = v[i] - w[i];
- }
-
- template <typename MatA, typename MatB>
- inline void
- copyMatrix(MatA const& src, MatB& dst)
- {
- unsigned int const rows = src.num_rows();
- unsigned int const cols = src.num_cols();
- assert(dst.num_rows() == rows);
- assert(dst.num_cols() == cols);
- for (unsigned int c = 0; c < cols; ++c)
- for (unsigned int r = 0; r < rows; ++r) dst[r][c] = src[r][c];
- }
-
- template <typename MatA, typename MatB>
- inline void
- copyMatrixSlice(MatA const& src, unsigned int rowStart, unsigned int colStart, unsigned int rowLen, unsigned int colLen,
- MatB& dst, unsigned int dstRow, unsigned int dstCol)
- {
- unsigned int const rows = dst.num_rows();
- unsigned int const cols = dst.num_cols();
-
- unsigned int const rowEnd = std::min(rowStart + rowLen, src.num_rows());
- unsigned int const colEnd = std::min(colStart + colLen, src.num_cols());
-
- unsigned int c0, c1, r0, r1;
-
- for (c0 = colStart, c1 = dstCol; c0 < colEnd && c1 < cols; ++c0, ++c1)
- for (r0 = rowStart, r1 = dstRow; r0 < rowEnd && r1 < rows; ++r0, ++r1)
- dst[r1][c1] = src[r0][c0];
- }
-
- template <typename MatA, typename MatB>
- inline void
- makeTransposedMatrix(MatA const& src, MatB& dst)
- {
- unsigned int const rows = src.num_rows();
- unsigned int const cols = src.num_cols();
- assert(dst.num_cols() == rows);
- assert(dst.num_rows() == cols);
- for (unsigned int c = 0; c < cols; ++c)
- for (unsigned int r = 0; r < rows; ++r) dst[c][r] = src[r][c];
- }
-
- template <typename Mat>
- inline void
- fillMatrix(Mat& m, typename Mat::value_type val)
- {
- unsigned int const rows = m.num_rows();
- unsigned int const cols = m.num_cols();
- for (unsigned int c = 0; c < cols; ++c)
- for (unsigned int r = 0; r < rows; ++r) m[r][c] = val;
- }
-
- template <typename Mat>
- inline void
- makeZeroMatrix(Mat& m)
- {
- fillMatrix(m, 0);
- }
-
- template <typename Mat>
- inline void
- makeIdentityMatrix(Mat& m)
- {
- makeZeroMatrix(m);
- unsigned int const rows = m.num_rows();
- unsigned int const cols = m.num_cols();
- unsigned int n = std::min(rows, cols);
- for (unsigned int i = 0; i < n; ++i)
- m[i][i] = 1;
- }
-
- template <typename Mat, typename Vec>
- inline void
- makeCrossProductMatrix(Vec const& v, Mat& m)
- {
- assert(v.size() == 3);
- assert(m.num_rows() == 3);
- assert(m.num_cols() == 3);
- m[0][0] = 0; m[0][1] = -v[2]; m[0][2] = v[1];
- m[1][0] = v[2]; m[1][1] = 0; m[1][2] = -v[0];
- m[2][0] = -v[1]; m[2][1] = v[0]; m[2][2] = 0;
- }
-
- template <typename Mat, typename Vec>
- inline void
- makeOuterProductMatrix(Vec const& v, Mat& m)
- {
- assert(m.num_cols() == m.num_rows());
- assert(v.size() == m.num_cols());
- unsigned const sz = v.size();
- for (unsigned r = 0; r < sz; ++r)
- for (unsigned c = 0; c < sz; ++c) m[r][c] = v[r]*v[c];
- }
-
- template <typename Mat, typename VecA, typename VecB>
- inline void
- makeOuterProductMatrix(VecA const& u, VecB const& v, Mat& m)
- {
- assert(m.num_cols() == m.num_rows());
- assert(u.size() == m.num_cols());
- assert(v.size() == m.num_cols());
- unsigned const sz = u.size();
- for (unsigned r = 0; r < sz; ++r)
- for (unsigned c = 0; c < sz; ++c) m[r][c] = u[r]*v[c];
- }
-
- template <typename MatA, typename MatB, typename MatC>
- void addMatrices(MatA const& a, MatB const& b, MatC& dst)
- {
- assert(a.num_cols() == b.num_cols());
- assert(a.num_rows() == b.num_rows());
- assert(dst.num_cols() == a.num_cols());
- assert(dst.num_rows() == a.num_rows());
-
- unsigned int const rows = a.num_rows();
- unsigned int const cols = a.num_cols();
-
- for (unsigned r = 0; r < rows; ++r)
- for (unsigned c = 0; c < cols; ++c) dst[r][c] = a[r][c] + b[r][c];
- }
-
- template <typename MatA, typename MatB>
- void addMatricesIP(MatA const& a, MatB& dst)
- {
- assert(dst.num_cols() == a.num_cols());
- assert(dst.num_rows() == a.num_rows());
-
- unsigned int const rows = a.num_rows();
- unsigned int const cols = a.num_cols();
-
- for (unsigned r = 0; r < rows; ++r)
- for (unsigned c = 0; c < cols; ++c) dst[r][c] += a[r][c];
- }
-
- template <typename MatA, typename MatB, typename MatC>
- void subtractMatrices(MatA const& a, MatB const& b, MatC& dst)
- {
- assert(a.num_cols() == b.num_cols());
- assert(a.num_rows() == b.num_rows());
- assert(dst.num_cols() == a.num_cols());
- assert(dst.num_rows() == a.num_rows());
-
- unsigned int const rows = a.num_rows();
- unsigned int const cols = a.num_cols();
-
- for (unsigned r = 0; r < rows; ++r)
- for (unsigned c = 0; c < cols; ++c) dst[r][c] = a[r][c] - b[r][c];
- }
-
- template <typename MatA, typename Elem, typename MatB>
- inline void
- makeScaledMatrix(MatA const& m, Elem scale, MatB& dst)
- {
- unsigned int const rows = m.num_rows();
- unsigned int const cols = m.num_cols();
- for (unsigned int c = 0; c < cols; ++c)
- for (unsigned int r = 0; r < rows; ++r) dst[r][c] = m[r][c] * scale;
- }
-
- template <typename Mat, typename Elem>
- inline void
- scaleMatrixIP(Elem scale, Mat& m)
- {
- unsigned int const rows = m.num_rows();
- unsigned int const cols = m.num_cols();
- for (unsigned int c = 0; c < cols; ++c)
- for (unsigned int r = 0; r < rows; ++r) m[r][c] *= scale;
- }
-
- template <typename Mat, typename VecA, typename VecB>
- inline void
- multiply_A_v(Mat const& m, VecA const& in, VecB& dst)
- {
- unsigned int const rows = m.num_rows();
- unsigned int const cols = m.num_cols();
- assert(in.size() == cols);
- assert(dst.size() == rows);
-
- makeZeroVector(dst);
-
- for (unsigned int r = 0; r < rows; ++r)
- for (unsigned int c = 0; c < cols; ++c) dst[r] += m[r][c] * in[c];
- }
-
- template <typename Mat, typename VecA, typename VecB>
- inline void
- multiply_A_v_projective(Mat const& m, VecA const& in, VecB& dst)
- {
- unsigned int const rows = m.num_rows();
- unsigned int const cols = m.num_cols();
- assert(in.size() == cols-1);
- assert(dst.size() == rows-1);
-
- typename VecB::value_type w = m(rows-1, cols-1);
- unsigned int r, i;
- for (i = 0; i < cols-1; ++i) w += m(rows-1, i) * in[i];
- for (r = 0; r < rows-1; ++r) dst[r] = m(r, cols-1);
- for (r = 0; r < rows-1; ++r)
- for (unsigned int c = 0; c < cols-1; ++c) dst[r] += m[r][c] * in[c];
- for (i = 0; i < rows-1; ++i) dst[i] /= w;
- }
-
- template <typename Mat, typename VecA, typename VecB>
- inline void
- multiply_A_v_affine(Mat const& m, VecA const& in, VecB& dst)
- {
- unsigned int const rows = m.num_rows();
- unsigned int const cols = m.num_cols();
- assert(in.size() == cols-1);
- assert(dst.size() == rows);
-
- unsigned int r;
-
- for (r = 0; r < rows; ++r) dst[r] = m(r, cols-1);
- for (r = 0; r < rows; ++r)
- for (unsigned int c = 0; c < cols-1; ++c) dst[r] += m[r][c] * in[c];
- }
-
- template <typename Mat, typename VecA, typename VecB>
- inline void
- multiply_At_v(Mat const& m, VecA const& in, VecB& dst)
- {
- unsigned int const rows = m.num_rows();
- unsigned int const cols = m.num_cols();
- assert(in.size() == rows);
- assert(dst.size() == cols);
-
- makeZeroVector(dst);
- for (unsigned int c = 0; c < cols; ++c)
- for (unsigned int r = 0; r < rows; ++r) dst[c] += m[r][c] * in[r];
- }
-
- template <typename MatA, typename MatB>
- inline void
- multiply_At_A(MatA const& a, MatB& dst)
- {
- assert(dst.num_rows() == a.num_cols());
- assert(dst.num_cols() == a.num_cols());
-
- typedef typename MatB::value_type Elem;
-
- Elem accum;
- for (unsigned int r = 0; r < a.num_cols(); ++r)
- for (unsigned int c = 0; c < a.num_cols(); ++c)
- {
- accum = 0;
- for (unsigned int k = 0; k < a.num_rows(); ++k) accum += a[k][r] * a[k][c];
- dst[r][c] = accum;
- }
- }
-
- template <typename MatA, typename MatB, typename MatC>
- inline void
- multiply_A_B(MatA const& a, MatB const& b, MatC& dst)
- {
- assert(a.num_cols() == b.num_rows());
- assert(dst.num_rows() == a.num_rows());
- assert(dst.num_cols() == b.num_cols());
-
- typedef typename MatC::value_type Elem;
-
- Elem accum;
- for (unsigned int r = 0; r < a.num_rows(); ++r)
- for (unsigned int c = 0; c < b.num_cols(); ++c)
- {
- accum = 0;
- for (unsigned int k = 0; k < a.num_cols(); ++k) accum += a[r][k] * b[k][c];
- dst[r][c] = accum;
- }
- }
-
- template <typename MatA, typename MatB, typename MatC>
- inline void
- multiply_At_B(MatA const& a, MatB const& b, MatC& dst)
- {
- assert(a.num_rows() == b.num_rows());
- assert(dst.num_rows() == a.num_cols());
- assert(dst.num_cols() == b.num_cols());
-
- typedef typename MatC::value_type Elem;
-
- Elem accum;
- for (unsigned int r = 0; r < a.num_cols(); ++r)
- for (unsigned int c = 0; c < b.num_cols(); ++c)
- {
- accum = 0;
- for (unsigned int k = 0; k < a.num_rows(); ++k) accum += a[k][r] * b[k][c];
- dst[r][c] = accum;
- }
- }
-
- template <typename MatA, typename MatB, typename MatC>
- inline void
- multiply_A_Bt(MatA const& a, MatB const& b, MatC& dst)
- {
- assert(a.num_cols() == b.num_cols());
- assert(dst.num_rows() == a.num_rows());
- assert(dst.num_cols() == b.num_rows());
-
- typedef typename MatC::value_type Elem;
-
- Elem accum;
- for (unsigned int r = 0; r < a.num_rows(); ++r)
- for (unsigned int c = 0; c < b.num_rows(); ++c)
- {
- accum = 0;
- for (unsigned int k = 0; k < a.num_cols(); ++k) accum += a[r][k] * b[c][k];
- dst[r][c] = accum;
- }
- }
-
- template <typename Mat>
- inline void
- transposeMatrixIP(Mat& a)
- {
- assert(a.num_rows() == a.num_cols());
-
- for (unsigned int r = 0; r < a.num_rows(); ++r)
- for (unsigned int c = 0; c < r; ++c)
- std::swap(a[r][c], a[c][r]);
- }
-
-} // end namespace V3D
-
-#endif
diff --git a/extern/libmv/third_party/ssba/Math/v3d_linear_utils.h b/extern/libmv/third_party/ssba/Math/v3d_linear_utils.h
deleted file mode 100644
index 969ec99694f..00000000000
--- a/extern/libmv/third_party/ssba/Math/v3d_linear_utils.h
+++ /dev/null
@@ -1,391 +0,0 @@
-// -*- C++ -*-
-/*
-Copyright (c) 2008 University of North Carolina at Chapel Hill
-
-This file is part of SSBA (Simple Sparse Bundle Adjustment).
-
-SSBA is free software: you can redistribute it and/or modify it under the
-terms of the GNU Lesser General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option) any
-later version.
-
-SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with SSBA. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef V3D_LINEAR_UTILS_H
-#define V3D_LINEAR_UTILS_H
-
-#include "Math/v3d_linear.h"
-
-#include <iostream>
-
-namespace V3D
-{
-
- template <typename Elem, int Size>
- struct InlineVector : public InlineVectorBase<Elem, Size>
- {
- }; // end struct InlineVector
-
- template <typename Elem>
- struct Vector : public VectorBase<Elem>
- {
- Vector()
- : VectorBase<Elem>()
- { }
-
- Vector(unsigned int size)
- : VectorBase<Elem>(size)
- { }
-
- Vector(unsigned int size, Elem * values)
- : VectorBase<Elem>(size, values)
- { }
-
- Vector(Vector<Elem> const& a)
- : VectorBase<Elem>(a)
- { }
-
- Vector<Elem>& operator=(Vector<Elem> const& a)
- {
- (VectorBase<Elem>::operator=)(a);
- return *this;
- }
-
- Vector<Elem>& operator+=(Vector<Elem> const& rhs)
- {
- addVectorsIP(rhs, *this);
- return *this;
- }
-
- Vector<Elem>& operator*=(Elem scale)
- {
- scaleVectorsIP(scale, *this);
- return *this;
- }
-
- Vector<Elem> operator+(Vector<Elem> const& rhs) const
- {
- Vector<Elem> res(this->size());
- addVectors(*this, rhs, res);
- return res;
- }
-
- Vector<Elem> operator-(Vector<Elem> const& rhs) const
- {
- Vector<Elem> res(this->size());
- subtractVectors(*this, rhs, res);
- return res;
- }
-
- Elem operator*(Vector<Elem> const& rhs) const
- {
- return innerProduct(*this, rhs);
- }
-
- }; // end struct Vector
-
- template <typename Elem, int Rows, int Cols>
- struct InlineMatrix : public InlineMatrixBase<Elem, Rows, Cols>
- {
- }; // end struct InlineMatrix
-
- template <typename Elem>
- struct Matrix : public MatrixBase<Elem>
- {
- Matrix()
- : MatrixBase<Elem>()
- { }
-
- Matrix(unsigned int rows, unsigned int cols)
- : MatrixBase<Elem>(rows, cols)
- { }
-
- Matrix(unsigned int rows, unsigned int cols, Elem * values)
- : MatrixBase<Elem>(rows, cols, values)
- { }
-
- Matrix(Matrix<Elem> const& a)
- : MatrixBase<Elem>(a)
- { }
-
- Matrix<Elem>& operator=(Matrix<Elem> const& a)
- {
- (MatrixBase<Elem>::operator=)(a);
- return *this;
- }
-
- Matrix<Elem>& operator+=(Matrix<Elem> const& rhs)
- {
- addMatricesIP(rhs, *this);
- return *this;
- }
-
- Matrix<Elem>& operator*=(Elem scale)
- {
- scaleMatrixIP(scale, *this);
- return *this;
- }
-
- Matrix<Elem> operator+(Matrix<Elem> const& rhs) const
- {
- Matrix<Elem> res(this->num_rows(), this->num_cols());
- addMatrices(*this, rhs, res);
- return res;
- }
-
- Matrix<Elem> operator-(Matrix<Elem> const& rhs) const
- {
- Matrix<Elem> res(this->num_rows(), this->num_cols());
- subtractMatrices(*this, rhs, res);
- return res;
- }
-
- }; // end struct Matrix
-
-//----------------------------------------------------------------------
-
- typedef InlineVector<float, 2> Vector2f;
- typedef InlineVector<double, 2> Vector2d;
- typedef InlineVector<float, 3> Vector3f;
- typedef InlineVector<double, 3> Vector3d;
- typedef InlineVector<float, 4> Vector4f;
- typedef InlineVector<double, 4> Vector4d;
-
- typedef InlineMatrix<float, 2, 2> Matrix2x2f;
- typedef InlineMatrix<double, 2, 2> Matrix2x2d;
- typedef InlineMatrix<float, 3, 3> Matrix3x3f;
- typedef InlineMatrix<double, 3, 3> Matrix3x3d;
- typedef InlineMatrix<float, 4, 4> Matrix4x4f;
- typedef InlineMatrix<double, 4, 4> Matrix4x4d;
-
- typedef InlineMatrix<float, 2, 3> Matrix2x3f;
- typedef InlineMatrix<double, 2, 3> Matrix2x3d;
- typedef InlineMatrix<float, 3, 4> Matrix3x4f;
- typedef InlineMatrix<double, 3, 4> Matrix3x4d;
-
- template <typename Elem>
- struct VectorArray
- {
- VectorArray(unsigned count, unsigned size)
- : _count(count), _size(size), _values(0), _vectors(0)
- {
- unsigned const nTotal = _count * _size;
- if (count > 0) _vectors = new Vector<Elem>[count];
- if (nTotal > 0) _values = new Elem[nTotal];
- for (unsigned i = 0; i < _count; ++i) new (&_vectors[i]) Vector<Elem>(_size, _values + i*_size);
- }
-
- VectorArray(unsigned count, unsigned size, Elem initVal)
- : _count(count), _size(size), _values(0), _vectors(0)
- {
- unsigned const nTotal = _count * _size;
- if (count > 0) _vectors = new Vector<Elem>[count];
- if (nTotal > 0) _values = new Elem[nTotal];
- for (unsigned i = 0; i < _count; ++i) new (&_vectors[i]) Vector<Elem>(_size, _values + i*_size);
- std::fill(_values, _values + nTotal, initVal);
- }
-
- ~VectorArray()
- {
- delete [] _values;
- delete [] _vectors;
- }
-
- unsigned count() const { return _count; }
- unsigned size() const { return _size; }
-
- //! Get the submatrix at position ix
- Vector<Elem> const& operator[](unsigned ix) const
- {
- return _vectors[ix];
- }
-
- //! Get the submatrix at position ix
- Vector<Elem>& operator[](unsigned ix)
- {
- return _vectors[ix];
- }
-
- protected:
- unsigned _count, _size;
- Elem * _values;
- Vector<Elem> * _vectors;
-
- private:
- VectorArray(VectorArray const&);
- void operator=(VectorArray const&);
- };
-
- template <typename Elem>
- struct MatrixArray
- {
- MatrixArray(unsigned count, unsigned nRows, unsigned nCols)
- : _count(count), _rows(nRows), _columns(nCols), _values(0), _matrices(0)
- {
- unsigned const nTotal = _count * _rows * _columns;
- if (count > 0) _matrices = new Matrix<Elem>[count];
- if (nTotal > 0) _values = new double[nTotal];
- for (unsigned i = 0; i < _count; ++i)
- new (&_matrices[i]) Matrix<Elem>(_rows, _columns, _values + i*(_rows*_columns));
- }
-
- ~MatrixArray()
- {
- delete [] _matrices;
- delete [] _values;
- }
-
- //! Get the submatrix at position ix
- Matrix<Elem> const& operator[](unsigned ix) const
- {
- return _matrices[ix];
- }
-
- //! Get the submatrix at position ix
- Matrix<Elem>& operator[](unsigned ix)
- {
- return _matrices[ix];
- }
-
- unsigned count() const { return _count; }
- unsigned num_rows() const { return _rows; }
- unsigned num_cols() const { return _columns; }
-
- protected:
- unsigned _count, _rows, _columns;
- double * _values;
- Matrix<Elem> * _matrices;
-
- private:
- MatrixArray(MatrixArray const&);
- void operator=(MatrixArray const&);
- };
-
-//----------------------------------------------------------------------
-
- template <typename Elem, int Size>
- inline InlineVector<Elem, Size>
- operator+(InlineVector<Elem, Size> const& v, InlineVector<Elem, Size> const& w)
- {
- InlineVector<Elem, Size> res;
- addVectors(v, w, res);
- return res;
- }
-
- template <typename Elem, int Size>
- inline InlineVector<Elem, Size>
- operator-(InlineVector<Elem, Size> const& v, InlineVector<Elem, Size> const& w)
- {
- InlineVector<Elem, Size> res;
- subtractVectors(v, w, res);
- return res;
- }
-
- template <typename Elem, int Size>
- inline InlineVector<Elem, Size>
- operator*(Elem scale, InlineVector<Elem, Size> const& v)
- {
- InlineVector<Elem, Size> res;
- scaleVector(scale, v, res);
- return res;
- }
-
- template <typename Elem, int Rows, int Cols>
- inline InlineVector<Elem, Rows>
- operator*(InlineMatrix<Elem, Rows, Cols> const& A, InlineVector<Elem, Cols> const& v)
- {
- InlineVector<Elem, Rows> res;
- multiply_A_v(A, v, res);
- return res;
- }
-
- template <typename Elem, int RowsA, int ColsA, int ColsB>
- inline InlineMatrix<Elem, RowsA, ColsB>
- operator*(InlineMatrix<Elem, RowsA, ColsA> const& A, InlineMatrix<Elem, ColsA, ColsB> const& B)
- {
- InlineMatrix<Elem, RowsA, ColsB> res;
- multiply_A_B(A, B, res);
- return res;
- }
-
- template <typename Elem, int Rows, int Cols>
- inline InlineMatrix<Elem, Cols, Rows>
- transposedMatrix(InlineMatrix<Elem, Rows, Cols> const& A)
- {
- InlineMatrix<Elem, Cols, Rows> At;
- makeTransposedMatrix(A, At);
- return At;
- }
-
- template <typename Elem>
- inline InlineMatrix<Elem, 3, 3>
- invertedMatrix(InlineMatrix<Elem, 3, 3> const& A)
- {
- Elem a = A[0][0], b = A[0][1], c = A[0][2];
- Elem d = A[1][0], e = A[1][1], f = A[1][2];
- Elem g = A[2][0], h = A[2][1], i = A[2][2];
-
- Elem const det = a*e*i + b*f*g + c*d*h - c*e*g - b*d*i - a*f*h;
-
- InlineMatrix<Elem, 3, 3> res;
- res[0][0] = e*i-f*h; res[0][1] = c*h-b*i; res[0][2] = b*f-c*e;
- res[1][0] = f*g-d*i; res[1][1] = a*i-c*g; res[1][2] = c*d-a*f;
- res[2][0] = d*h-e*g; res[2][1] = b*g-a*h; res[2][2] = a*e-b*d;
-
- scaleMatrixIP(1.0/det, res);
- return res;
- }
-
- template <typename Elem>
- inline InlineVector<Elem, 2>
- makeVector2(Elem a, Elem b)
- {
- InlineVector<Elem, 2> res;
- res[0] = a; res[1] = b;
- return res;
- }
-
- template <typename Elem>
- inline InlineVector<Elem, 3>
- makeVector3(Elem a, Elem b, Elem c)
- {
- InlineVector<Elem, 3> res;
- res[0] = a; res[1] = b; res[2] = c;
- return res;
- }
-
- template <typename Vec>
- inline void
- displayVector(Vec const& v)
- {
- using namespace std;
-
- for (int r = 0; r < v.size(); ++r)
- cout << v[r] << " ";
- cout << endl;
- }
-
- template <typename Mat>
- inline void
- displayMatrix(Mat const& A)
- {
- using namespace std;
-
- for (int r = 0; r < A.num_rows(); ++r)
- {
- for (int c = 0; c < A.num_cols(); ++c)
- cout << A[r][c] << " ";
- cout << endl;
- }
- }
-
-} // end namespace V3D
-
-#endif
diff --git a/extern/libmv/third_party/ssba/Math/v3d_mathutilities.h b/extern/libmv/third_party/ssba/Math/v3d_mathutilities.h
deleted file mode 100644
index 9e38b92a94b..00000000000
--- a/extern/libmv/third_party/ssba/Math/v3d_mathutilities.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// -*- C++ -*-
-/*
-Copyright (c) 2008 University of North Carolina at Chapel Hill
-
-This file is part of SSBA (Simple Sparse Bundle Adjustment).
-
-SSBA is free software: you can redistribute it and/or modify it under the
-terms of the GNU Lesser General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option) any
-later version.
-
-SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with SSBA. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef V3D_MATH_UTILITIES_H
-#define V3D_MATH_UTILITIES_H
-
-#include "Math/v3d_linear.h"
-#include "Math/v3d_linear_utils.h"
-
-#include <vector>
-
-namespace V3D
-{
-
- template <typename Vec, typename Mat>
- inline void
- createRotationMatrixRodriguez(Vec const& omega, Mat& R)
- {
- assert(omega.size() == 3);
- assert(R.num_rows() == 3);
- assert(R.num_cols() == 3);
-
- double const theta = norm_L2(omega);
- makeIdentityMatrix(R);
- if (fabs(theta) > 1e-6)
- {
- Matrix3x3d J, J2;
- makeCrossProductMatrix(omega, J);
- multiply_A_B(J, J, J2);
- double const c1 = sin(theta)/theta;
- double const c2 = (1-cos(theta))/(theta*theta);
- for (int i = 0; i < 3; ++i)
- for (int j = 0; j < 3; ++j)
- R[i][j] += c1*J[i][j] + c2*J2[i][j];
- }
- } // end createRotationMatrixRodriguez()
-
- template <typename T> inline double sqr(T x) { return x*x; }
-
-} // namespace V3D
-
-#endif
diff --git a/extern/libmv/third_party/ssba/Math/v3d_optimization.cpp b/extern/libmv/third_party/ssba/Math/v3d_optimization.cpp
deleted file mode 100644
index 234815fcd1f..00000000000
--- a/extern/libmv/third_party/ssba/Math/v3d_optimization.cpp
+++ /dev/null
@@ -1,955 +0,0 @@
-/*
-Copyright (c) 2008 University of North Carolina at Chapel Hill
-
-This file is part of SSBA (Simple Sparse Bundle Adjustment).
-
-SSBA is free software: you can redistribute it and/or modify it under the
-terms of the GNU Lesser General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option) any
-later version.
-
-SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with SSBA. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "Math/v3d_optimization.h"
-
-#if defined(V3DLIB_ENABLE_SUITESPARSE)
-//# include "COLAMD/Include/colamd.h"
-# include "colamd.h"
-extern "C"
-{
-//# include "LDL/Include/ldl.h"
-# include "ldl.h"
-}
-#endif
-
-#include <iostream>
-#include <map>
-
-#define USE_BLOCK_REORDERING 1
-#define USE_MULTIPLICATIVE_UPDATE 1
-
-using namespace std;
-
-namespace
-{
-
- using namespace V3D;
-
- inline double
- squaredResidual(VectorArray<double> const& e)
- {
- int const N = e.count();
- int const M = e.size();
-
- double res = 0.0;
-
- for (int n = 0; n < N; ++n)
- for (int m = 0; m < M; ++m)
- res += e[n][m] * e[n][m];
-
- return res;
- } // end squaredResidual()
-
-} // end namespace <>
-
-namespace V3D
-{
-
- int optimizerVerbosenessLevel = 0;
-
-#if defined(V3DLIB_ENABLE_SUITESPARSE)
-
- void
- SparseLevenbergOptimizer::setupSparseJtJ()
- {
- int const nVaryingA = _nParametersA - _nNonvaryingA;
- int const nVaryingB = _nParametersB - _nNonvaryingB;
- int const nVaryingC = _paramDimensionC - _nNonvaryingC;
-
- int const bColumnStart = nVaryingA*_paramDimensionA;
- int const cColumnStart = bColumnStart + nVaryingB*_paramDimensionB;
- int const nColumns = cColumnStart + nVaryingC;
-
- _jointNonzerosW.clear();
- _jointIndexW.resize(_nMeasurements);
-#if 1
- {
- map<pair<int, int>, int> jointNonzeroMap;
- for (size_t k = 0; k < _nMeasurements; ++k)
- {
- int const i = _correspondingParamA[k] - _nNonvaryingA;
- int const j = _correspondingParamB[k] - _nNonvaryingB;
- if (i >= 0 && j >= 0)
- {
- map<pair<int, int>, int>::const_iterator p = jointNonzeroMap.find(make_pair(i, j));
- if (p == jointNonzeroMap.end())
- {
- jointNonzeroMap.insert(make_pair(make_pair(i, j), _jointNonzerosW.size()));
- _jointIndexW[k] = _jointNonzerosW.size();
- _jointNonzerosW.push_back(make_pair(i, j));
- }
- else
- {
- _jointIndexW[k] = (*p).second;
- } // end if
- } // end if
- } // end for (k)
- } // end scope
-#else
- for (size_t k = 0; k < _nMeasurements; ++k)
- {
- int const i = _correspondingParamA[k] - _nNonvaryingA;
- int const j = _correspondingParamB[k] - _nNonvaryingB;
- if (i >= 0 && j >= 0)
- {
- _jointIndexW[k] = _jointNonzerosW.size();
- _jointNonzerosW.push_back(make_pair(i, j));
- }
- } // end for (k)
-#endif
-
-#if defined(USE_BLOCK_REORDERING)
- int const bBlockColumnStart = nVaryingA;
- int const cBlockColumnStart = bBlockColumnStart + nVaryingB;
-
- int const nBlockColumns = cBlockColumnStart + ((nVaryingC > 0) ? 1 : 0);
-
- //cout << "nBlockColumns = " << nBlockColumns << endl;
-
- // For the column reordering we treat the columns belonging to one set
- // of parameters as one (logical) column.
-
- // Determine non-zeros of JtJ (we forget about the non-zero diagonal for now)
- // Only consider nonzeros of Ai^t * Bj induced by the measurements.
- vector<pair<int, int> > nz_blockJtJ(_jointNonzerosW.size());
- for (int k = 0; k < _jointNonzerosW.size(); ++k)
- {
- nz_blockJtJ[k].first = _jointNonzerosW[k].second + bBlockColumnStart;
- nz_blockJtJ[k].second = _jointNonzerosW[k].first;
- }
-
- if (nVaryingC > 0)
- {
- // We assume, that the global unknowns are linked to every other variable.
- for (int i = 0; i < nVaryingA; ++i)
- nz_blockJtJ.push_back(make_pair(cBlockColumnStart, i));
- for (int j = 0; j < nVaryingB; ++j)
- nz_blockJtJ.push_back(make_pair(cBlockColumnStart, j + bBlockColumnStart));
- } // end if
-
- int const nnzBlock = nz_blockJtJ.size();
-
- vector<int> permBlockJtJ(nBlockColumns + 1);
-
- if (nnzBlock > 0)
- {
-// cout << "nnzBlock = " << nnzBlock << endl;
-
- CCS_Matrix<int> blockJtJ(nBlockColumns, nBlockColumns, nz_blockJtJ);
-
-// cout << " nz_blockJtJ: " << endl;
-// for (size_t k = 0; k < nz_blockJtJ.size(); ++k)
-// cout << " " << nz_blockJtJ[k].first << ":" << nz_blockJtJ[k].second << endl;
-// cout << endl;
-
- int * colStarts = (int *)blockJtJ.getColumnStarts();
- int * rowIdxs = (int *)blockJtJ.getRowIndices();
-
-// cout << "blockJtJ_colStarts = ";
-// for (int k = 0; k <= nBlockColumns; ++k) cout << colStarts[k] << " ";
-// cout << endl;
-
-// cout << "blockJtJ_rowIdxs = ";
-// for (int k = 0; k < nnzBlock; ++k) cout << rowIdxs[k] << " ";
-// cout << endl;
-
- int stats[COLAMD_STATS];
- symamd(nBlockColumns, rowIdxs, colStarts, &permBlockJtJ[0], (double *) NULL, stats, &calloc, &free);
- if (optimizerVerbosenessLevel >= 2) symamd_report(stats);
- }
- else
- {
- for (int k = 0; k < permBlockJtJ.size(); ++k) permBlockJtJ[k] = k;
- } // end if
-
-// cout << "permBlockJtJ = ";
-// for (int k = 0; k < permBlockJtJ.size(); ++k)
-// cout << permBlockJtJ[k] << " ";
-// cout << endl;
-
- // From the determined symbolic permutation with logical variables, determine the actual ordering
- _perm_JtJ.resize(nVaryingA*_paramDimensionA + nVaryingB*_paramDimensionB + nVaryingC + 1);
-
- int curDstCol = 0;
- for (int k = 0; k < permBlockJtJ.size()-1; ++k)
- {
- int const srcCol = permBlockJtJ[k];
- if (srcCol < nVaryingA)
- {
- for (int n = 0; n < _paramDimensionA; ++n)
- _perm_JtJ[curDstCol + n] = srcCol*_paramDimensionA + n;
- curDstCol += _paramDimensionA;
- }
- else if (srcCol >= bBlockColumnStart && srcCol < cBlockColumnStart)
- {
- int const bStart = nVaryingA*_paramDimensionA;
- int const j = srcCol - bBlockColumnStart;
-
- for (int n = 0; n < _paramDimensionB; ++n)
- _perm_JtJ[curDstCol + n] = bStart + j*_paramDimensionB + n;
- curDstCol += _paramDimensionB;
- }
- else if (srcCol == cBlockColumnStart)
- {
- int const cStart = nVaryingA*_paramDimensionA + nVaryingB*_paramDimensionB;
-
- for (int n = 0; n < nVaryingC; ++n)
- _perm_JtJ[curDstCol + n] = cStart + n;
- curDstCol += nVaryingC;
- }
- else
- {
- cerr << "Should not reach " << __LINE__ << ":" << __LINE__ << "!" << endl;
- assert(false);
- }
- }
-#else
- vector<pair<int, int> > nz, nzL;
- this->serializeNonZerosJtJ(nz);
-
- for (int k = 0; k < nz.size(); ++k)
- {
- // Swap rows and columns, since serializeNonZerosJtJ() generates the
- // upper triangular part but symamd wants the lower triangle.
- nzL.push_back(make_pair(nz[k].second, nz[k].first));
- }
-
- _perm_JtJ.resize(nColumns+1);
-
- if (nzL.size() > 0)
- {
- CCS_Matrix<int> symbJtJ(nColumns, nColumns, nzL);
-
- int * colStarts = (int *)symbJtJ.getColumnStarts();
- int * rowIdxs = (int *)symbJtJ.getRowIndices();
-
-// cout << "symbJtJ_colStarts = ";
-// for (int k = 0; k <= nColumns; ++k) cout << colStarts[k] << " ";
-// cout << endl;
-
-// cout << "symbJtJ_rowIdxs = ";
-// for (int k = 0; k < nzL.size(); ++k) cout << rowIdxs[k] << " ";
-// cout << endl;
-
- int stats[COLAMD_STATS];
- symamd(nColumns, rowIdxs, colStarts, &_perm_JtJ[0], (double *) NULL, stats, &calloc, &free);
- if (optimizerVerbosenessLevel >= 2) symamd_report(stats);
- }
- else
- {
- for (int k = 0; k < _perm_JtJ.size(); ++k) _perm_JtJ[k] = k;
- } //// end if
-#endif
- _perm_JtJ.back() = _perm_JtJ.size() - 1;
-
-// cout << "_perm_JtJ = ";
-// for (int k = 0; k < _perm_JtJ.size(); ++k) cout << _perm_JtJ[k] << " ";
-// cout << endl;
-
- // Finally, compute the inverse of the full permutation.
- _invPerm_JtJ.resize(_perm_JtJ.size());
- for (size_t k = 0; k < _perm_JtJ.size(); ++k)
- _invPerm_JtJ[_perm_JtJ[k]] = k;
-
- vector<pair<int, int> > nz_JtJ;
- this->serializeNonZerosJtJ(nz_JtJ);
-
- for (int k = 0; k < nz_JtJ.size(); ++k)
- {
- int const i = nz_JtJ[k].first;
- int const j = nz_JtJ[k].second;
-
- int pi = _invPerm_JtJ[i];
- int pj = _invPerm_JtJ[j];
- // Swap values if in lower triangular part
- if (pi > pj) std::swap(pi, pj);
- nz_JtJ[k].first = pi;
- nz_JtJ[k].second = pj;
- }
-
- int const nnz = nz_JtJ.size();
-
-// cout << "nz_JtJ = ";
-// for (int k = 0; k < nnz; ++k) cout << nz_JtJ[k].first << ":" << nz_JtJ[k].second << " ";
-// cout << endl;
-
- _JtJ.create(nColumns, nColumns, nz_JtJ);
-
-// cout << "_colStart_JtJ = ";
-// for (int k = 0; k < _JtJ.num_cols(); ++k) cout << _JtJ.getColumnStarts()[k] << " ";
-// cout << endl;
-
-// cout << "_rowIdxs_JtJ = ";
-// for (int k = 0; k < nnz; ++k) cout << _JtJ.getRowIndices()[k] << " ";
-// cout << endl;
-
- vector<int> workFlags(nColumns);
-
- _JtJ_Lp.resize(nColumns+1);
- _JtJ_Parent.resize(nColumns);
- _JtJ_Lnz.resize(nColumns);
-
- ldl_symbolic(nColumns, (int *)_JtJ.getColumnStarts(), (int *)_JtJ.getRowIndices(),
- &_JtJ_Lp[0], &_JtJ_Parent[0], &_JtJ_Lnz[0],
- &workFlags[0], NULL, NULL);
-
- if (optimizerVerbosenessLevel >= 1)
- cout << "SparseLevenbergOptimizer: Nonzeros in LDL decomposition: " << _JtJ_Lp[nColumns] << endl;
-
- } // end SparseLevenbergOptimizer::setupSparseJtJ()
-
- void
- SparseLevenbergOptimizer::serializeNonZerosJtJ(vector<pair<int, int> >& dst) const
- {
- int const nVaryingA = _nParametersA - _nNonvaryingA;
- int const nVaryingB = _nParametersB - _nNonvaryingB;
- int const nVaryingC = _paramDimensionC - _nNonvaryingC;
-
- int const bColumnStart = nVaryingA*_paramDimensionA;
- int const cColumnStart = bColumnStart + nVaryingB*_paramDimensionB;
-
- dst.clear();
-
- // Add the diagonal block matrices (only the upper triangular part).
-
- // Ui submatrices of JtJ
- for (int i = 0; i < nVaryingA; ++i)
- {
- int const i0 = i * _paramDimensionA;
-
- for (int c = 0; c < _paramDimensionA; ++c)
- for (int r = 0; r <= c; ++r)
- dst.push_back(make_pair(i0 + r, i0 + c));
- }
-
- // Vj submatrices of JtJ
- for (int j = 0; j < nVaryingB; ++j)
- {
- int const j0 = j*_paramDimensionB + bColumnStart;
-
- for (int c = 0; c < _paramDimensionB; ++c)
- for (int r = 0; r <= c; ++r)
- dst.push_back(make_pair(j0 + r, j0 + c));
- }
-
- // Z submatrix of JtJ
- for (int c = 0; c < nVaryingC; ++c)
- for (int r = 0; r <= c; ++r)
- dst.push_back(make_pair(cColumnStart + r, cColumnStart + c));
-
- // Add the elements i and j linked by an observation k
- // W submatrix of JtJ
- for (size_t n = 0; n < _jointNonzerosW.size(); ++n)
- {
- int const i0 = _jointNonzerosW[n].first;
- int const j0 = _jointNonzerosW[n].second;
- int const r0 = i0*_paramDimensionA;
- int const c0 = j0*_paramDimensionB + bColumnStart;
-
- for (int r = 0; r < _paramDimensionA; ++r)
- for (int c = 0; c < _paramDimensionB; ++c)
- dst.push_back(make_pair(r0 + r, c0 + c));
- } // end for (n)
-
- if (nVaryingC > 0)
- {
- // Finally, add the dense columns linking i (resp. j) with the global parameters.
- // X submatrix of JtJ
- for (int i = 0; i < nVaryingA; ++i)
- {
- int const i0 = i*_paramDimensionA;
-
- for (int r = 0; r < _paramDimensionA; ++r)
- for (int c = 0; c < nVaryingC; ++c)
- dst.push_back(make_pair(i0 + r, cColumnStart + c));
- }
-
- // Y submatrix of JtJ
- for (int j = 0; j < nVaryingB; ++j)
- {
- int const j0 = j*_paramDimensionB + bColumnStart;
-
- for (int r = 0; r < _paramDimensionB; ++r)
- for (int c = 0; c < nVaryingC; ++c)
- dst.push_back(make_pair(j0 + r, cColumnStart + c));
- }
- } // end if
- } // end SparseLevenbergOptimizer::serializeNonZerosJtJ()
-
- void
- SparseLevenbergOptimizer::fillSparseJtJ(MatrixArray<double> const& Ui,
- MatrixArray<double> const& Vj,
- MatrixArray<double> const& Wn,
- Matrix<double> const& Z,
- Matrix<double> const& X,
- Matrix<double> const& Y)
- {
- int const nVaryingA = _nParametersA - _nNonvaryingA;
- int const nVaryingB = _nParametersB - _nNonvaryingB;
- int const nVaryingC = _paramDimensionC - _nNonvaryingC;
-
- int const bColumnStart = nVaryingA*_paramDimensionA;
- int const cColumnStart = bColumnStart + nVaryingB*_paramDimensionB;
-
- int const nCols = _JtJ.num_cols();
- int const nnz = _JtJ.getNonzeroCount();
-
- // The following has to replicate the procedure as in serializeNonZerosJtJ()
-
- int serial = 0;
-
- double * values = _JtJ.getValues();
- int const * destIdxs = _JtJ.getDestIndices();
-
- // Add the diagonal block matrices (only the upper triangular part).
-
- // Ui submatrices of JtJ
- for (int i = 0; i < nVaryingA; ++i)
- {
- int const i0 = i * _paramDimensionA;
-
- for (int c = 0; c < _paramDimensionA; ++c)
- for (int r = 0; r <= c; ++r, ++serial)
- values[destIdxs[serial]] = Ui[i][r][c];
- }
-
- // Vj submatrices of JtJ
- for (int j = 0; j < nVaryingB; ++j)
- {
- int const j0 = j*_paramDimensionB + bColumnStart;
-
- for (int c = 0; c < _paramDimensionB; ++c)
- for (int r = 0; r <= c; ++r, ++serial)
- values[destIdxs[serial]] = Vj[j][r][c];
- }
-
- // Z submatrix of JtJ
- for (int c = 0; c < nVaryingC; ++c)
- for (int r = 0; r <= c; ++r, ++serial)
- values[destIdxs[serial]] = Z[r][c];
-
- // Add the elements i and j linked by an observation k
- // W submatrix of JtJ
- for (size_t n = 0; n < _jointNonzerosW.size(); ++n)
- {
- for (int r = 0; r < _paramDimensionA; ++r)
- for (int c = 0; c < _paramDimensionB; ++c, ++serial)
- values[destIdxs[serial]] = Wn[n][r][c];
- } // end for (k)
-
- if (nVaryingC > 0)
- {
- // Finally, add the dense columns linking i (resp. j) with the global parameters.
- // X submatrix of JtJ
- for (int i = 0; i < nVaryingA; ++i)
- {
- int const r0 = i * _paramDimensionA;
- for (int r = 0; r < _paramDimensionA; ++r)
- for (int c = 0; c < nVaryingC; ++c, ++serial)
- values[destIdxs[serial]] = X[r0+r][c];
- }
-
- // Y submatrix of JtJ
- for (int j = 0; j < nVaryingB; ++j)
- {
- int const r0 = j * _paramDimensionB;
- for (int r = 0; r < _paramDimensionB; ++r)
- for (int c = 0; c < nVaryingC; ++c, ++serial)
- values[destIdxs[serial]] = Y[r0+r][c];
- }
- } // end if
- } // end SparseLevenbergOptimizer::fillSparseJtJ()
-
- void
- SparseLevenbergOptimizer::minimize()
- {
- status = LEVENBERG_OPTIMIZER_TIMEOUT;
- bool computeDerivatives = true;
-
- int const nVaryingA = _nParametersA - _nNonvaryingA;
- int const nVaryingB = _nParametersB - _nNonvaryingB;
- int const nVaryingC = _paramDimensionC - _nNonvaryingC;
-
- if (nVaryingA == 0 && nVaryingB == 0 && nVaryingC == 0)
- {
- // No degrees of freedom, nothing to optimize.
- status = LEVENBERG_OPTIMIZER_CONVERGED;
- return;
- }
-
- this->setupSparseJtJ();
-
- Vector<double> weights(_nMeasurements);
-
- MatrixArray<double> Ak(_nMeasurements, _measurementDimension, _paramDimensionA);
- MatrixArray<double> Bk(_nMeasurements, _measurementDimension, _paramDimensionB);
- MatrixArray<double> Ck(_nMeasurements, _measurementDimension, _paramDimensionC);
-
- MatrixArray<double> Ui(nVaryingA, _paramDimensionA, _paramDimensionA);
- MatrixArray<double> Vj(nVaryingB, _paramDimensionB, _paramDimensionB);
-
- // Wn = Ak^t*Bk
- MatrixArray<double> Wn(_jointNonzerosW.size(), _paramDimensionA, _paramDimensionB);
-
- Matrix<double> Z(nVaryingC, nVaryingC);
-
- // X = A^t*C
- Matrix<double> X(nVaryingA*_paramDimensionA, nVaryingC);
- // Y = B^t*C
- Matrix<double> Y(nVaryingB*_paramDimensionB, nVaryingC);
-
- VectorArray<double> residuals(_nMeasurements, _measurementDimension);
- VectorArray<double> residuals2(_nMeasurements, _measurementDimension);
-
- VectorArray<double> diagUi(nVaryingA, _paramDimensionA);
- VectorArray<double> diagVj(nVaryingB, _paramDimensionB);
- Vector<double> diagZ(nVaryingC);
-
- VectorArray<double> At_e(nVaryingA, _paramDimensionA);
- VectorArray<double> Bt_e(nVaryingB, _paramDimensionB);
- Vector<double> Ct_e(nVaryingC);
-
- Vector<double> Jt_e(nVaryingA*_paramDimensionA + nVaryingB*_paramDimensionB + nVaryingC);
-
- Vector<double> delta(nVaryingA*_paramDimensionA + nVaryingB*_paramDimensionB + nVaryingC);
- Vector<double> deltaPerm(nVaryingA*_paramDimensionA + nVaryingB*_paramDimensionB + nVaryingC);
-
- VectorArray<double> deltaAi(_nParametersA, _paramDimensionA);
- VectorArray<double> deltaBj(_nParametersB, _paramDimensionB);
- Vector<double> deltaC(_paramDimensionC);
-
- double err = 0.0;
-
- for (currentIteration = 0; currentIteration < maxIterations; ++currentIteration)
- {
- if (optimizerVerbosenessLevel >= 2)
- cout << "SparseLevenbergOptimizer: currentIteration: " << currentIteration << endl;
- if (computeDerivatives)
- {
- this->evalResidual(residuals);
- this->fillWeights(residuals, weights);
- for (int k = 0; k < _nMeasurements; ++k)
- scaleVectorIP(weights[k], residuals[k]);
-
- err = squaredResidual(residuals);
-
- if (optimizerVerbosenessLevel >= 1) cout << "SparseLevenbergOptimizer: |residual|^2 = " << err << endl;
- if (optimizerVerbosenessLevel >= 2) cout << "SparseLevenbergOptimizer: lambda = " << lambda << endl;
-
- for (int k = 0; k < residuals.count(); ++k) scaleVectorIP(-1.0, residuals[k]);
-
- this->setupJacobianGathering();
- this->fillAllJacobians(weights, Ak, Bk, Ck);
-
- // Compute the different parts of J^t*e
- if (nVaryingA > 0)
- {
- for (int i = 0; i < nVaryingA; ++i) makeZeroVector(At_e[i]);
-
- Vector<double> tmp(_paramDimensionA);
-
- for (int k = 0; k < _nMeasurements; ++k)
- {
- int const i = _correspondingParamA[k] - _nNonvaryingA;
- if (i < 0) continue;
- multiply_At_v(Ak[k], residuals[k], tmp);
- addVectors(tmp, At_e[i], At_e[i]);
- } // end for (k)
- } // end if
-
- if (nVaryingB > 0)
- {
- for (int j = 0; j < nVaryingB; ++j) makeZeroVector(Bt_e[j]);
-
- Vector<double> tmp(_paramDimensionB);
-
- for (int k = 0; k < _nMeasurements; ++k)
- {
- int const j = _correspondingParamB[k] - _nNonvaryingB;
- if (j < 0) continue;
- multiply_At_v(Bk[k], residuals[k], tmp);
- addVectors(tmp, Bt_e[j], Bt_e[j]);
- } // end for (k)
- } // end if
-
- if (nVaryingC > 0)
- {
- makeZeroVector(Ct_e);
-
- Vector<double> tmp(_paramDimensionC);
-
- for (int k = 0; k < _nMeasurements; ++k)
- {
- multiply_At_v(Ck[k], residuals[k], tmp);
- for (int l = 0; l < nVaryingC; ++l) Ct_e[l] += tmp[_nNonvaryingC + l];
- }
- } // end if
-
- int pos = 0;
- for (int i = 0; i < nVaryingA; ++i)
- for (int l = 0; l < _paramDimensionA; ++l, ++pos)
- Jt_e[pos] = At_e[i][l];
- for (int j = 0; j < nVaryingB; ++j)
- for (int l = 0; l < _paramDimensionB; ++l, ++pos)
- Jt_e[pos] = Bt_e[j][l];
- for (int l = 0; l < nVaryingC; ++l, ++pos)
- Jt_e[pos] = Ct_e[l];
-
-// cout << "Jt_e = ";
-// for (int k = 0; k < Jt_e.size(); ++k) cout << Jt_e[k] << " ";
-// cout << endl;
-
- if (this->applyGradientStoppingCriteria(norm_Linf(Jt_e)))
- {
- status = LEVENBERG_OPTIMIZER_CONVERGED;
- goto end;
- }
-
- // The lhs J^t*J consists of several parts:
- // [ U W X ]
- // J^t*J = [ W^t V Y ]
- // [ X^t Y^t Z ],
- // where U, V and W are block-sparse matrices (due to the sparsity of A and B).
- // X, Y and Z contain only a few columns (the number of global parameters).
-
- if (nVaryingA > 0)
- {
- // Compute Ui
- Matrix<double> U(_paramDimensionA, _paramDimensionA);
-
- for (int i = 0; i < nVaryingA; ++i) makeZeroMatrix(Ui[i]);
-
- for (int k = 0; k < _nMeasurements; ++k)
- {
- int const i = _correspondingParamA[k] - _nNonvaryingA;
- if (i < 0) continue;
- multiply_At_A(Ak[k], U);
- addMatricesIP(U, Ui[i]);
- } // end for (k)
- } // end if
-
- if (nVaryingB > 0)
- {
- // Compute Vj
- Matrix<double> V(_paramDimensionB, _paramDimensionB);
-
- for (int j = 0; j < nVaryingB; ++j) makeZeroMatrix(Vj[j]);
-
- for (int k = 0; k < _nMeasurements; ++k)
- {
- int const j = _correspondingParamB[k] - _nNonvaryingB;
- if (j < 0) continue;
- multiply_At_A(Bk[k], V);
- addMatricesIP(V, Vj[j]);
- } // end for (k)
- } // end if
-
- if (nVaryingC > 0)
- {
- Matrix<double> ZZ(_paramDimensionC, _paramDimensionC);
- Matrix<double> Zsum(_paramDimensionC, _paramDimensionC);
-
- makeZeroMatrix(Zsum);
-
- for (int k = 0; k < _nMeasurements; ++k)
- {
- multiply_At_A(Ck[k], ZZ);
- addMatricesIP(ZZ, Zsum);
- } // end for (k)
-
- // Ignore the non-varying parameters
- for (int i = 0; i < nVaryingC; ++i)
- for (int j = 0; j < nVaryingC; ++j)
- Z[i][j] = Zsum[i+_nNonvaryingC][j+_nNonvaryingC];
- } // end if
-
- if (nVaryingA > 0 && nVaryingB > 0)
- {
- for (int n = 0; n < Wn.count(); ++n) makeZeroMatrix(Wn[n]);
-
- Matrix<double> W(_paramDimensionA, _paramDimensionB);
-
- for (int k = 0; k < _nMeasurements; ++k)
- {
- int const n = _jointIndexW[k];
- if (n >= 0)
- {
- int const i0 = _jointNonzerosW[n].first;
- int const j0 = _jointNonzerosW[n].second;
-
- multiply_At_B(Ak[k], Bk[k], W);
- addMatricesIP(W, Wn[n]);
- } // end if
- } // end for (k)
- } // end if
-
- if (nVaryingA > 0 && nVaryingC > 0)
- {
- Matrix<double> XX(_paramDimensionA, _paramDimensionC);
-
- makeZeroMatrix(X);
-
- for (int k = 0; k < _nMeasurements; ++k)
- {
- int const i = _correspondingParamA[k] - _nNonvaryingA;
- // Ignore the non-varying parameters
- if (i < 0) continue;
-
- multiply_At_B(Ak[k], Ck[k], XX);
-
- for (int r = 0; r < _paramDimensionA; ++r)
- for (int c = 0; c < nVaryingC; ++c)
- X[r+i*_paramDimensionA][c] += XX[r][c+_nNonvaryingC];
- } // end for (k)
- } // end if
-
- if (nVaryingB > 0 && nVaryingC > 0)
- {
- Matrix<double> YY(_paramDimensionB, _paramDimensionC);
-
- makeZeroMatrix(Y);
-
- for (int k = 0; k < _nMeasurements; ++k)
- {
- int const j = _correspondingParamB[k] - _nNonvaryingB;
- // Ignore the non-varying parameters
- if (j < 0) continue;
-
- multiply_At_B(Bk[k], Ck[k], YY);
-
- for (int r = 0; r < _paramDimensionB; ++r)
- for (int c = 0; c < nVaryingC; ++c)
- Y[r+j*_paramDimensionB][c] += YY[r][c+_nNonvaryingC];
- } // end for (k)
- } // end if
-
- if (currentIteration == 0)
- {
- // Initialize lambda as tau*max(JtJ[i][i])
- double maxEl = -1e30;
- if (nVaryingA > 0)
- {
- for (int i = 0; i < nVaryingA; ++i)
- for (int l = 0; l < _paramDimensionA; ++l)
- maxEl = std::max(maxEl, Ui[i][l][l]);
- }
- if (nVaryingB > 0)
- {
- for (int j = 0; j < nVaryingB; ++j)
- for (int l = 0; l < _paramDimensionB; ++l)
- maxEl = std::max(maxEl, Vj[j][l][l]);
- }
- if (nVaryingC > 0)
- {
- for (int l = 0; l < nVaryingC; ++l)
- maxEl = std::max(maxEl, Z[l][l]);
- }
-
- lambda = tau * maxEl;
- if (optimizerVerbosenessLevel >= 2)
- cout << "SparseLevenbergOptimizer: initial lambda = " << lambda << endl;
- } // end if (currentIteration == 0)
- } // end if (computeDerivatives)
-
- for (int i = 0; i < nVaryingA; ++i)
- {
- for (int l = 0; l < _paramDimensionA; ++l) diagUi[i][l] = Ui[i][l][l];
- } // end for (i)
-
- for (int j = 0; j < nVaryingB; ++j)
- {
- for (int l = 0; l < _paramDimensionB; ++l) diagVj[j][l] = Vj[j][l][l];
- } // end for (j)
-
- for (int l = 0; l < nVaryingC; ++l) diagZ[l] = Z[l][l];
-
- // Augment the diagonals with lambda (either by the standard additive update or by multiplication).
-#if !defined(USE_MULTIPLICATIVE_UPDATE)
- for (int i = 0; i < nVaryingA; ++i)
- for (unsigned l = 0; l < _paramDimensionA; ++l)
- Ui[i][l][l] += lambda;
-
- for (int j = 0; j < nVaryingB; ++j)
- for (unsigned l = 0; l < _paramDimensionB; ++l)
- Vj[j][l][l] += lambda;
-
- for (unsigned l = 0; l < nVaryingC; ++l)
- Z[l][l] += lambda;
-#else
- for (int i = 0; i < nVaryingA; ++i)
- for (unsigned l = 0; l < _paramDimensionA; ++l)
- Ui[i][l][l] = std::max(Ui[i][l][l] * (1.0 + lambda), 1e-15);
-
- for (int j = 0; j < nVaryingB; ++j)
- for (unsigned l = 0; l < _paramDimensionB; ++l)
- Vj[j][l][l] = std::max(Vj[j][l][l] * (1.0 + lambda), 1e-15);
-
- for (unsigned l = 0; l < nVaryingC; ++l)
- Z[l][l] = std::max(Z[l][l] * (1.0 + lambda), 1e-15);
-#endif
-
- this->fillSparseJtJ(Ui, Vj, Wn, Z, X, Y);
-
- bool success = true;
- double rho = 0.0;
- {
- int const nCols = _JtJ_Parent.size();
- int const nnz = _JtJ.getNonzeroCount();
- int const lnz = _JtJ_Lp.back();
-
- vector<int> Li(lnz);
- vector<double> Lx(lnz);
- vector<double> D(nCols), Y(nCols);
- vector<int> workPattern(nCols), workFlag(nCols);
-
- int * colStarts = (int *)_JtJ.getColumnStarts();
- int * rowIdxs = (int *)_JtJ.getRowIndices();
- double * values = _JtJ.getValues();
-
- int const d = ldl_numeric(nCols, colStarts, rowIdxs, values,
- &_JtJ_Lp[0], &_JtJ_Parent[0], &_JtJ_Lnz[0],
- &Li[0], &Lx[0], &D[0],
- &Y[0], &workPattern[0], &workFlag[0],
- NULL, NULL);
-
- if (d == nCols)
- {
- ldl_perm(nCols, &deltaPerm[0], &Jt_e[0], &_perm_JtJ[0]);
- ldl_lsolve(nCols, &deltaPerm[0], &_JtJ_Lp[0], &Li[0], &Lx[0]);
- ldl_dsolve(nCols, &deltaPerm[0], &D[0]);
- ldl_ltsolve(nCols, &deltaPerm[0], &_JtJ_Lp[0], &Li[0], &Lx[0]);
- ldl_permt(nCols, &delta[0], &deltaPerm[0], &_perm_JtJ[0]);
- }
- else
- {
- if (optimizerVerbosenessLevel >= 2)
- cout << "SparseLevenbergOptimizer: LDL decomposition failed. Increasing lambda." << endl;
- success = false;
- }
- }
-
- if (success)
- {
- double const deltaSqrLength = sqrNorm_L2(delta);
-
- if (optimizerVerbosenessLevel >= 2)
- cout << "SparseLevenbergOptimizer: ||delta||^2 = " << deltaSqrLength << endl;
-
- double const paramLength = this->getParameterLength();
- if (this->applyUpdateStoppingCriteria(paramLength, sqrt(deltaSqrLength)))
- {
- status = LEVENBERG_OPTIMIZER_SMALL_UPDATE;
- goto end;
- }
-
- // Copy the updates from delta to the respective arrays
- int pos = 0;
-
- for (int i = 0; i < _nNonvaryingA; ++i) makeZeroVector(deltaAi[i]);
- for (int i = _nNonvaryingA; i < _nParametersA; ++i)
- for (int l = 0; l < _paramDimensionA; ++l, ++pos)
- deltaAi[i][l] = delta[pos];
-
- for (int j = 0; j < _nNonvaryingB; ++j) makeZeroVector(deltaBj[j]);
- for (int j = _nNonvaryingB; j < _nParametersB; ++j)
- for (int l = 0; l < _paramDimensionB; ++l, ++pos)
- deltaBj[j][l] = delta[pos];
-
- makeZeroVector(deltaC);
- for (int l = _nNonvaryingC; l < _paramDimensionC; ++l, ++pos)
- deltaC[l] = delta[pos];
-
- saveAllParameters();
- if (nVaryingA > 0) updateParametersA(deltaAi);
- if (nVaryingB > 0) updateParametersB(deltaBj);
- if (nVaryingC > 0) updateParametersC(deltaC);
-
- this->evalResidual(residuals2);
- for (int k = 0; k < _nMeasurements; ++k)
- scaleVectorIP(weights[k], residuals2[k]);
-
- double const newErr = squaredResidual(residuals2);
- rho = err - newErr;
- if (optimizerVerbosenessLevel >= 2)
- cout << "SparseLevenbergOptimizer: |new residual|^2 = " << newErr << endl;
-
-#if !defined(USE_MULTIPLICATIVE_UPDATE)
- double const denom1 = lambda * deltaSqrLength;
-#else
- double denom1 = 0.0f;
- for (int i = _nNonvaryingA; i < _nParametersA; ++i)
- for (int l = 0; l < _paramDimensionA; ++l)
- denom1 += deltaAi[i][l] * deltaAi[i][l] * diagUi[i-_nNonvaryingA][l];
-
- for (int j = _nNonvaryingB; j < _nParametersB; ++j)
- for (int l = 0; l < _paramDimensionB; ++l)
- denom1 += deltaBj[j][l] * deltaBj[j][l] * diagVj[j-_nNonvaryingB][l];
-
- for (int l = _nNonvaryingC; l < _paramDimensionC; ++l)
- denom1 += deltaC[l] * deltaC[l] * diagZ[l-_nNonvaryingC];
-
- denom1 *= lambda;
-#endif
- double const denom2 = innerProduct(delta, Jt_e);
- rho = rho / (denom1 + denom2);
- if (optimizerVerbosenessLevel >= 2)
- cout << "SparseLevenbergOptimizer: rho = " << rho
- << " denom1 = " << denom1 << " denom2 = " << denom2 << endl;
- } // end if (success)
-
- if (success && rho > 0)
- {
- if (optimizerVerbosenessLevel >= 2)
- cout << "SparseLevenbergOptimizer: Improved solution - decreasing lambda." << endl;
- // Improvement in the new solution
- decreaseLambda(rho);
- computeDerivatives = true;
- }
- else
- {
- if (optimizerVerbosenessLevel >= 2)
- cout << "SparseLevenbergOptimizer: Inferior solution - increasing lambda." << endl;
- restoreAllParameters();
- increaseLambda();
- computeDerivatives = false;
-
- // Restore diagonal elements in Ui, Vj and Z.
- for (int i = 0; i < nVaryingA; ++i)
- {
- for (int l = 0; l < _paramDimensionA; ++l) Ui[i][l][l] = diagUi[i][l];
- } // end for (i)
-
- for (int j = 0; j < nVaryingB; ++j)
- {
- for (int l = 0; l < _paramDimensionB; ++l) Vj[j][l][l] = diagVj[j][l];
- } // end for (j)
-
- for (int l = 0; l < nVaryingC; ++l) Z[l][l] = diagZ[l];
- } // end if
- } // end for
-
- end:;
- if (optimizerVerbosenessLevel >= 2)
- cout << "Leaving SparseLevenbergOptimizer::minimize()." << endl;
- } // end SparseLevenbergOptimizer::minimize()
-
-#endif // defined(V3DLIB_ENABLE_SUITESPARSE)
-
-} // end namespace V3D
diff --git a/extern/libmv/third_party/ssba/Math/v3d_optimization.h b/extern/libmv/third_party/ssba/Math/v3d_optimization.h
deleted file mode 100644
index 27d2e12287f..00000000000
--- a/extern/libmv/third_party/ssba/Math/v3d_optimization.h
+++ /dev/null
@@ -1,273 +0,0 @@
-// -*- C++ -*-
-/*
-Copyright (c) 2008 University of North Carolina at Chapel Hill
-
-This file is part of SSBA (Simple Sparse Bundle Adjustment).
-
-SSBA is free software: you can redistribute it and/or modify it under the
-terms of the GNU Lesser General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option) any
-later version.
-
-SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with SSBA. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef V3D_OPTIMIZATION_H
-#define V3D_OPTIMIZATION_H
-
-#include "Math/v3d_linear.h"
-#include "Math/v3d_mathutilities.h"
-
-#include <vector>
-#include <iostream>
-
-namespace V3D
-{
-
- enum
- {
- LEVENBERG_OPTIMIZER_TIMEOUT = 0,
- LEVENBERG_OPTIMIZER_SMALL_UPDATE = 1,
- LEVENBERG_OPTIMIZER_CONVERGED = 2
- };
-
- extern int optimizerVerbosenessLevel;
-
- struct LevenbergOptimizerCommon
- {
- LevenbergOptimizerCommon()
- : status(LEVENBERG_OPTIMIZER_TIMEOUT), currentIteration(0), maxIterations(50),
- tau(1e-3), lambda(1e-3),
- gradientThreshold(1e-10), updateThreshold(1e-10),
- _nu(2.0)
- { }
- virtual ~LevenbergOptimizerCommon() {}
-
- // See Madsen et al., "Methods for non-linear least squares problems."
- virtual void increaseLambda()
- {
- lambda *= _nu; _nu *= 2.0;
- }
-
- virtual void decreaseLambda(double const rho)
- {
- double const r = 2*rho - 1.0;
- lambda *= std::max(1.0/3.0, 1 - r*r*r);
- if (lambda < 1e-10) lambda = 1e-10;
- _nu = 2;
- }
-
- bool applyGradientStoppingCriteria(double maxGradient) const
- {
- return maxGradient < gradientThreshold;
- }
-
- bool applyUpdateStoppingCriteria(double paramLength, double updateLength) const
- {
- return updateLength < updateThreshold * (paramLength + updateThreshold);
- }
-
- int status;
- int currentIteration, maxIterations;
- double tau, lambda;
- double gradientThreshold, updateThreshold;
-
- protected:
- double _nu;
- }; // end struct LevenbergOptimizerCommon
-
-# if defined(V3DLIB_ENABLE_SUITESPARSE)
-
- struct SparseLevenbergOptimizer : public LevenbergOptimizerCommon
- {
- SparseLevenbergOptimizer(int measurementDimension,
- int nParametersA, int paramDimensionA,
- int nParametersB, int paramDimensionB,
- int paramDimensionC,
- std::vector<int> const& correspondingParamA,
- std::vector<int> const& correspondingParamB)
- : LevenbergOptimizerCommon(),
- _nMeasurements(correspondingParamA.size()),
- _measurementDimension(measurementDimension),
- _nParametersA(nParametersA), _paramDimensionA(paramDimensionA),
- _nParametersB(nParametersB), _paramDimensionB(paramDimensionB),
- _paramDimensionC(paramDimensionC),
- _nNonvaryingA(0), _nNonvaryingB(0), _nNonvaryingC(0),
- _correspondingParamA(correspondingParamA),
- _correspondingParamB(correspondingParamB)
- {
- assert(correspondingParamA.size() == correspondingParamB.size());
- }
-
- ~SparseLevenbergOptimizer() { }
-
- void setNonvaryingCounts(int nNonvaryingA, int nNonvaryingB, int nNonvaryingC)
- {
- _nNonvaryingA = nNonvaryingA;
- _nNonvaryingB = nNonvaryingB;
- _nNonvaryingC = nNonvaryingC;
- }
-
- void getNonvaryingCounts(int& nNonvaryingA, int& nNonvaryingB, int& nNonvaryingC) const
- {
- nNonvaryingA = _nNonvaryingA;
- nNonvaryingB = _nNonvaryingB;
- nNonvaryingC = _nNonvaryingC;
- }
-
- void minimize();
-
- virtual void evalResidual(VectorArray<double>& residuals) = 0;
-
- virtual void fillWeights(VectorArray<double> const& residuals, Vector<double>& w)
- {
- (void)residuals;
- std::fill(w.begin(), w.end(), 1.0);
- }
-
- void fillAllJacobians(Vector<double> const& w,
- MatrixArray<double>& Ak,
- MatrixArray<double>& Bk,
- MatrixArray<double>& Ck)
- {
- int const nVaryingA = _nParametersA - _nNonvaryingA;
- int const nVaryingB = _nParametersB - _nNonvaryingB;
- int const nVaryingC = _paramDimensionC - _nNonvaryingC;
-
- for (unsigned k = 0; k < _nMeasurements; ++k)
- {
- int const i = _correspondingParamA[k];
- int const j = _correspondingParamB[k];
-
- if (i < _nNonvaryingA && j < _nNonvaryingB) continue;
-
- fillJacobians(Ak[k], Bk[k], Ck[k], i, j, k);
- } // end for (k)
-
- if (nVaryingA > 0)
- {
- for (unsigned k = 0; k < _nMeasurements; ++k)
- scaleMatrixIP(w[k], Ak[k]);
- }
- if (nVaryingB > 0)
- {
- for (unsigned k = 0; k < _nMeasurements; ++k)
- scaleMatrixIP(w[k], Bk[k]);
- }
- if (nVaryingC > 0)
- {
- for (unsigned k = 0; k < _nMeasurements; ++k)
- scaleMatrixIP(w[k], Ck[k]);
- }
- } // end fillAllJacobians()
-
- virtual void setupJacobianGathering() { }
-
- virtual void fillJacobians(Matrix<double>& Ak, Matrix<double>& Bk, Matrix<double>& Ck,
- int i, int j, int k) = 0;
-
- virtual double getParameterLength() const = 0;
-
- virtual void updateParametersA(VectorArray<double> const& deltaAi) = 0;
- virtual void updateParametersB(VectorArray<double> const& deltaBj) = 0;
- virtual void updateParametersC(Vector<double> const& deltaC) = 0;
- virtual void saveAllParameters() = 0;
- virtual void restoreAllParameters() = 0;
-
- int currentIteration, maxIterations;
-
- protected:
- void serializeNonZerosJtJ(std::vector<std::pair<int, int> >& dst) const;
- void setupSparseJtJ();
- void fillSparseJtJ(MatrixArray<double> const& Ui, MatrixArray<double> const& Vj, MatrixArray<double> const& Wk,
- Matrix<double> const& Z, Matrix<double> const& X, Matrix<double> const& Y);
-
- int const _nMeasurements, _measurementDimension;
- int const _nParametersA, _paramDimensionA;
- int const _nParametersB, _paramDimensionB;
- int const _paramDimensionC;
-
- int _nNonvaryingA, _nNonvaryingB, _nNonvaryingC;
-
- std::vector<int> const& _correspondingParamA;
- std::vector<int> const& _correspondingParamB;
-
- std::vector<pair<int, int> > _jointNonzerosW;
- std::vector<int> _jointIndexW;
-
- std::vector<int> _JtJ_Lp, _JtJ_Parent, _JtJ_Lnz;
- std::vector<int> _perm_JtJ, _invPerm_JtJ;
-
- CCS_Matrix<double> _JtJ;
- }; // end struct SparseLevenbergOptimizer
-
- struct StdSparseLevenbergOptimizer : public SparseLevenbergOptimizer
- {
- StdSparseLevenbergOptimizer(int measurementDimension,
- int nParametersA, int paramDimensionA,
- int nParametersB, int paramDimensionB,
- int paramDimensionC,
- std::vector<int> const& correspondingParamA,
- std::vector<int> const& correspondingParamB)
- : SparseLevenbergOptimizer(measurementDimension, nParametersA, paramDimensionA,
- nParametersB, paramDimensionB, paramDimensionC,
- correspondingParamA, correspondingParamB),
- curParametersA(nParametersA, paramDimensionA), savedParametersA(nParametersA, paramDimensionA),
- curParametersB(nParametersB, paramDimensionB), savedParametersB(nParametersB, paramDimensionB),
- curParametersC(paramDimensionC), savedParametersC(paramDimensionC)
- { }
-
- virtual double getParameterLength() const
- {
- double res = 0.0;
- for (int i = 0; i < _nParametersA; ++i) res += sqrNorm_L2(curParametersA[i]);
- for (int j = 0; j < _nParametersB; ++j) res += sqrNorm_L2(curParametersB[j]);
- res += sqrNorm_L2(curParametersC);
- return sqrt(res);
- }
-
- virtual void updateParametersA(VectorArray<double> const& deltaAi)
- {
- for (int i = 0; i < _nParametersA; ++i) addVectors(deltaAi[i], curParametersA[i], curParametersA[i]);
- }
-
- virtual void updateParametersB(VectorArray<double> const& deltaBj)
- {
- for (int j = 0; j < _nParametersB; ++j) addVectors(deltaBj[j], curParametersB[j], curParametersB[j]);
- }
-
- virtual void updateParametersC(Vector<double> const& deltaC)
- {
- addVectors(deltaC, curParametersC, curParametersC);
- }
-
- virtual void saveAllParameters()
- {
- for (int i = 0; i < _nParametersA; ++i) savedParametersA[i] = curParametersA[i];
- for (int j = 0; j < _nParametersB; ++j) savedParametersB[j] = curParametersB[j];
- savedParametersC = curParametersC;
- }
-
- virtual void restoreAllParameters()
- {
- for (int i = 0; i < _nParametersA; ++i) curParametersA[i] = savedParametersA[i];
- for (int j = 0; j < _nParametersB; ++j) curParametersB[j] = savedParametersB[j];
- curParametersC = savedParametersC;
- }
-
- VectorArray<double> curParametersA, savedParametersA;
- VectorArray<double> curParametersB, savedParametersB;
- Vector<double> curParametersC, savedParametersC;
- }; // end struct StdSparseLevenbergOptimizer
-
-# endif
-
-} // end namespace V3D
-
-#endif
diff --git a/extern/libmv/third_party/ssba/README.TXT b/extern/libmv/third_party/ssba/README.TXT
deleted file mode 100644
index 734962b1df8..00000000000
--- a/extern/libmv/third_party/ssba/README.TXT
+++ /dev/null
@@ -1,92 +0,0 @@
-Description
-
-This is an implementation of a sparse Levenberg-Marquardt optimization
-procedure and several bundle adjustment modules based on it. There are three
-versions of bundle adjustment:
-1) Pure metric adjustment. Camera poses have 6 dof and 3D points have 3 dof.
-2) Common, but adjustable intrinsic and distortion parameters. This is useful,
- if the set of images are taken with the same camera under constant zoom
- settings.
-3) Variable intrinsics and distortion parameters for each view. This addresses
- the "community photo collection" setting, where each image is captured with
- a different camera and/or with varying zoom setting.
-
-There are two demo applications in the Apps directory, bundle_common and
-bundle_varying, which correspond to item 2) and 3) above.
-
-The input data file for both applications is a text file with the following
-numerical values:
-
-First, the number of 3D points, views and 2D measurements:
-<M> <N> <K>
-Then, the values of the intrinsic matrix
- [ fx skew cx ]
-K = [ 0 fy cy ]
- [ 0 0 1 ],
-and the distortion parameters according to the convention of the Bouget
-toolbox:
-
- <fx> <skew> <cx> <fy> <cy> <k1> <k2> <p1> <p2>
-
-For the bundle_varying application this is given <N> times, one for each
-camera/view.
-Then the <M> 3D point positions are given:
-
- <point-id> <X> <Y> <Z>
-
-Note: the point-ids need not to be exactly from 0 to M-1, any (unique) ids
-will do.
-The camera poses are given subsequently:
-
- <view-id> <12 entries of the RT matrix>
-
-There is a lot of confusion how to specify the orientation of cameras. We use
-projection matrix notation, i.e. P = K [R|T], and a 3D point X in world
-coordinates is transformed into the camera coordinate system by XX=R*X+T.
-
-Finally, the <K> 2d image measurements (given in pixels) are provided:
-
- <view-id> <point-id> <x> <y> 1
-
-See the example in the Dataset folder.
-
-
-Performance
-
-This software is able to perform successful loop closing for a video sequence
-containing 1745 views, 37920 3D points and 627228 image measurements in about
-16min on a 2.2 GHz Core 2. The footprint in memory was <700MB.
-
-
-Requirements
-
-Solving the augmented normal equation in the LM optimizer is done with LDL, a
-Cholsky like decomposition method for sparse matrices (see
-http://www.cise.ufl.edu/research/sparse/ldl). The appropriate column
-reordering is done with COLAMD (see
-http://www.cise.ufl.edu/research/sparse/colamd). Both packages are licensed
-under the GNU LGPL.
-
-This software was developed under Linux, but should compile equally well on
-other operating systems.
-
--Christopher Zach (cmzach@cs.unc.edu)
-
-/*
-Copyright (c) 2008 University of North Carolina at Chapel Hill
-
-This file is part of SSBA (Simple Sparse Bundle Adjustment).
-
-SSBA is free software: you can redistribute it and/or modify it under the
-terms of the GNU Lesser General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option) any
-later version.
-
-SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with SSBA. If not, see <http://www.gnu.org/licenses/>.
-*/
diff --git a/extern/libmv/third_party/ssba/README.libmv b/extern/libmv/third_party/ssba/README.libmv
deleted file mode 100644
index 45e0a31f6fc..00000000000
--- a/extern/libmv/third_party/ssba/README.libmv
+++ /dev/null
@@ -1,23 +0,0 @@
-Project: SSBA
-URL: http://www.cs.unc.edu/~cmzach/opensource.html
-License: LGPL3
-Upstream version: 1.0
-
-Local modifications:
-
- * Added
- SET(CMAKE_CXX_FLAGS "")
- to CMakeLists.txt to prevent warnings from being treated as errors.
- * Fixed "unused variable" in the header files. Warnings in the cpps files
- are still there.
- * Fixed a bug in CameraMatrix::opticalAxis() in file
- Geometry/v3d_cameramatrix.h
- * Deleted the Dataset directory.
- * Added '#include <string>' to ssba/Apps/bundle_common.cpp and
- ssba/Apps/bundle_varying.cpp to stop undefined references to strcmp
- * Removed unnecessary elements from the CMakeLists.txt file, including the
- obsoleted local_config.cmake and friends.
- * Added a virtual destructor to V3D::LevenbergOptimizerCommon in
- Math/v3d_optimization.h
- * Added /EHsc WIN32-specific flag to CMakeLists.txt
- * Remove unused variable Vector3d np in bundle_common.cpp and bundle_varying (in main() function).
diff --git a/extern/lzo/minilzo/COPYING b/extern/lzo/minilzo/COPYING
index 5ee49f42e91..d159169d105 100644
--- a/extern/lzo/minilzo/COPYING
+++ b/extern/lzo/minilzo/COPYING
@@ -1,8 +1,8 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
+the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
@@ -55,7 +55,7 @@ patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
-
+
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
@@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
-
+
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
@@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
-
+
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
@@ -225,7 +225,7 @@ impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
-
+
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
@@ -278,7 +278,7 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
-
+
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
@@ -291,7 +291,7 @@ convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
- Copyright (C) 19yy <name of author>
+ Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -303,17 +303,16 @@ the "copyright" line and a pointer to where the full notice is found.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
- Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
@@ -336,5 +335,5 @@ necessary. Here is a sample; alter the names:
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
+library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
diff --git a/extern/lzo/minilzo/README.LZO b/extern/lzo/minilzo/README.LZO
index 3700f28e310..058eace70a0 100644
--- a/extern/lzo/minilzo/README.LZO
+++ b/extern/lzo/minilzo/README.LZO
@@ -6,8 +6,8 @@
Author : Markus Franz Xaver Johannes Oberhumer
<markus@oberhumer.com>
http://www.oberhumer.com/opensource/lzo/
- Version : 2.03
- Date : 30 Apr 2008
+ Version : 2.06
+ Date : 12 Aug 2011
I've created miniLZO for projects where it is inconvenient to
include (or require) the full LZO source code just because you
@@ -24,10 +24,10 @@
To use miniLZO just copy these files into your source directory, add
minilzo.c to your Makefile and #include minilzo.h from your program.
- Note: you also must distribute this file (`README.LZO') with your project.
+ Note: you also must distribute this file ('README.LZO') with your project.
- minilzo.o compiles to about 6 kB (using gcc or Visual C on a i386), and
- the sources are about 30 kB when packed with zip - so there's no more
+ minilzo.o compiles to about 6 KiB (using gcc or Visual C on an i386), and
+ the sources are about 30 KiB when packed with zip - so there's no more
excuse that your application doesn't support data compression :-)
For more information, documentation, example programs and other support
@@ -49,15 +49,15 @@
out-of-the-box on most machines.
If you are running on a very unusual architecture and lzo_init() fails then
- you should first recompile with `-DLZO_DEBUG' to see what causes the failure.
- The most probable case is something like `sizeof(char *) != sizeof(long)'.
+ you should first recompile with '-DLZO_DEBUG' to see what causes the failure.
+ The most probable case is something like 'sizeof(void *) != sizeof(size_t)'.
After identifying the problem you can compile by adding some defines
- like `-DSIZEOF_CHAR_P=8' to your Makefile.
+ like '-DSIZEOF_VOID_P=8' to your Makefile.
The best solution is (of course) using Autoconf - if your project uses
- Autoconf anyway just add `-DMINILZO_HAVE_CONFIG_H' to your compiler
+ Autoconf anyway just add '-DMINILZO_HAVE_CONFIG_H' to your compiler
flags when compiling minilzo.c. See the LZO distribution for an example
- how to set up configure.in.
+ how to set up configure.ac.
Appendix B: list of public functions available in miniLZO
@@ -87,7 +87,7 @@
lzo_memset()
- Appendix C: suggested macros for `configure.in' when using Autoconf
+ Appendix C: suggested macros for 'configure.ac' when using Autoconf
-------------------------------------------------------------------
Checks for typedefs and structures
AC_CHECK_TYPE(ptrdiff_t,long)
@@ -110,8 +110,9 @@
Appendix D: Copyright
---------------------
- LZO and miniLZO are Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007, 2008 Markus Franz Xaver Johannes Oberhumer
+ LZO and miniLZO are Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001,
+ 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+ Markus Franz Xaver Oberhumer <markus@oberhumer.com>.
LZO and miniLZO are distributed under the terms of the GNU General
Public License (GPL). See the file COPYING.
diff --git a/extern/lzo/minilzo/lzoconf.h b/extern/lzo/minilzo/lzoconf.h
index cc437f1ebfe..23c6ca93fcc 100644
--- a/extern/lzo/minilzo/lzoconf.h
+++ b/extern/lzo/minilzo/lzoconf.h
@@ -1,7 +1,10 @@
-/* lzoconf.h -- configuration for the LZO real-time data compression library
+/* lzoconf.h -- configuration of the LZO data compression library
This file is part of the LZO real-time data compression library.
+ Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
@@ -39,11 +42,11 @@
#ifndef __LZOCONF_H_INCLUDED
-#define __LZOCONF_H_INCLUDED
+#define __LZOCONF_H_INCLUDED 1
-#define LZO_VERSION 0x2030
-#define LZO_VERSION_STRING "2.03"
-#define LZO_VERSION_DATE "Apr 30 2008"
+#define LZO_VERSION 0x2060
+#define LZO_VERSION_STRING "2.06"
+#define LZO_VERSION_DATE "Aug 12 2011"
/* internal Autoconf configuration file - only used when building LZO */
#if defined(LZO_HAVE_CONFIG_H)
@@ -157,6 +160,27 @@ extern "C" {
# endif
#endif
+/* Integral types with exactly 64 bits. */
+#if !defined(LZO_UINT64_MAX)
+# if (LZO_UINT_MAX >= LZO_0xffffffffL)
+# if ((((LZO_UINT_MAX) >> 31) >> 31) == 3)
+# define lzo_uint64 lzo_uint
+# define lzo_int64 lzo_int
+# define LZO_UINT64_MAX LZO_UINT_MAX
+# define LZO_INT64_MAX LZO_INT_MAX
+# define LZO_INT64_MIN LZO_INT_MIN
+# endif
+# elif (ULONG_MAX >= LZO_0xffffffffL)
+# if ((((ULONG_MAX) >> 31) >> 31) == 3)
+ typedef unsigned long lzo_uint64;
+ typedef long lzo_int64;
+# define LZO_UINT64_MAX ULONG_MAX
+# define LZO_INT64_MAX LONG_MAX
+# define LZO_INT64_MIN LONG_MIN
+# endif
+# endif
+#endif
+
/* The larger type of lzo_uint and lzo_uint32. */
#if (LZO_UINT_MAX >= LZO_UINT32_MAX)
# define lzo_xint lzo_uint
@@ -167,12 +191,12 @@ extern "C" {
/* Memory model that allows to access memory at offsets of lzo_uint. */
#if !defined(__LZO_MMODEL)
# if (LZO_UINT_MAX <= UINT_MAX)
-# define __LZO_MMODEL
+# define __LZO_MMODEL /*empty*/
# elif defined(LZO_HAVE_MM_HUGE_PTR)
# define __LZO_MMODEL_HUGE 1
# define __LZO_MMODEL __huge
# else
-# define __LZO_MMODEL
+# define __LZO_MMODEL /*empty*/
# endif
#endif
@@ -184,12 +208,16 @@ extern "C" {
#define lzo_ushortp unsigned short __LZO_MMODEL *
#define lzo_uint32p lzo_uint32 __LZO_MMODEL *
#define lzo_int32p lzo_int32 __LZO_MMODEL *
+#if defined(LZO_UINT64_MAX)
+#define lzo_uint64p lzo_uint64 __LZO_MMODEL *
+#define lzo_int64p lzo_int64 __LZO_MMODEL *
+#endif
#define lzo_uintp lzo_uint __LZO_MMODEL *
#define lzo_intp lzo_int __LZO_MMODEL *
#define lzo_xintp lzo_xint __LZO_MMODEL *
#define lzo_voidpp lzo_voidp __LZO_MMODEL *
#define lzo_bytepp lzo_bytep __LZO_MMODEL *
-/* deprecated - use `lzo_bytep' instead of `lzo_byte *' */
+/* deprecated - use 'lzo_bytep' instead of 'lzo_byte *' */
#define lzo_byte unsigned char __LZO_MMODEL
typedef int lzo_bool;
@@ -215,10 +243,10 @@ typedef int lzo_bool;
/* DLL export information */
#if !defined(__LZO_EXPORT1)
-# define __LZO_EXPORT1
+# define __LZO_EXPORT1 /*empty*/
#endif
#if !defined(__LZO_EXPORT2)
-# define __LZO_EXPORT2
+# define __LZO_EXPORT2 /*empty*/
#endif
/* __cdecl calling convention for public C and assembly functions */
@@ -306,7 +334,7 @@ struct lzo_callback_t
*/
#define LZO_E_OK 0
#define LZO_E_ERROR (-1)
-#define LZO_E_OUT_OF_MEMORY (-2) /* [not used right now] */
+#define LZO_E_OUT_OF_MEMORY (-2) /* [lzo_alloc_func_t failure] */
#define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */
#define LZO_E_INPUT_OVERRUN (-4)
#define LZO_E_OUTPUT_OVERRUN (-5)
@@ -314,6 +342,7 @@ struct lzo_callback_t
#define LZO_E_EOF_NOT_FOUND (-7)
#define LZO_E_INPUT_NOT_CONSUMED (-8)
#define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */
+#define LZO_E_INVALID_ARGUMENT (-10)
#ifndef lzo_sizeof_dict_t
@@ -341,32 +370,32 @@ LZO_EXTERN(const lzo_charp) _lzo_version_date(void);
/* string functions */
LZO_EXTERN(int)
-lzo_memcmp(const lzo_voidp _s1, const lzo_voidp _s2, lzo_uint _len);
+ lzo_memcmp(const lzo_voidp a, const lzo_voidp b, lzo_uint len);
LZO_EXTERN(lzo_voidp)
-lzo_memcpy(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len);
+ lzo_memcpy(lzo_voidp dst, const lzo_voidp src, lzo_uint len);
LZO_EXTERN(lzo_voidp)
-lzo_memmove(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len);
+ lzo_memmove(lzo_voidp dst, const lzo_voidp src, lzo_uint len);
LZO_EXTERN(lzo_voidp)
-lzo_memset(lzo_voidp _s, int _c, lzo_uint _len);
+ lzo_memset(lzo_voidp buf, int c, lzo_uint len);
/* checksum functions */
LZO_EXTERN(lzo_uint32)
-lzo_adler32(lzo_uint32 _adler, const lzo_bytep _buf, lzo_uint _len);
+ lzo_adler32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len);
LZO_EXTERN(lzo_uint32)
-lzo_crc32(lzo_uint32 _c, const lzo_bytep _buf, lzo_uint _len);
+ lzo_crc32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len);
LZO_EXTERN(const lzo_uint32p)
-lzo_get_crc32_table(void);
+ lzo_get_crc32_table(void);
/* misc. */
LZO_EXTERN(int) _lzo_config_check(void);
typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u;
typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u;
-typedef union { void *vp; lzo_bytep bp; lzo_uint32 u32; long l; } lzo_align_t;
+typedef union { void *vp; lzo_bytep bp; lzo_uint u; lzo_uint32 u32; unsigned long l; } lzo_align_t;
-/* align a char pointer on a boundary that is a multiple of `size' */
-LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size);
-#define LZO_PTR_ALIGN_UP(_ptr,_size) \
- ((_ptr) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(_ptr),(lzo_uint)(_size)))
+/* align a char pointer on a boundary that is a multiple of 'size' */
+LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp p, lzo_uint size);
+#define LZO_PTR_ALIGN_UP(p,size) \
+ ((p) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(p),(lzo_uint)(size)))
/***********************************************************************
@@ -395,8 +424,8 @@ LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size);
# define __LZO_WIN 1
#endif
-#define __LZO_CMODEL
-#define __LZO_DMODEL
+#define __LZO_CMODEL /*empty*/
+#define __LZO_DMODEL /*empty*/
#define __LZO_ENTRY __LZO_CDECL
#define LZO_EXTERN_CDECL LZO_EXTERN
#define LZO_ALIGN LZO_PTR_ALIGN_UP
diff --git a/extern/lzo/minilzo/lzodefs.h b/extern/lzo/minilzo/lzodefs.h
index 180563723e5..0e40e332a8d 100644
--- a/extern/lzo/minilzo/lzodefs.h
+++ b/extern/lzo/minilzo/lzodefs.h
@@ -2,6 +2,9 @@
This file is part of the LZO real-time data compression library.
+ Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
@@ -121,7 +124,7 @@
#endif
#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL)
# define ptrdiff_t long
-# define _PTRDIFF_T_DEFINED
+# define _PTRDIFF_T_DEFINED 1
#endif
#if (UINT_MAX == LZO_0xffffL)
# undef __LZO_RENAME_A
@@ -265,9 +268,9 @@
# define LZO_EXTERN_C extern
#endif
#if !defined(__LZO_OS_OVERRIDE)
-#if defined(LZO_OS_FREESTANDING)
+#if (LZO_OS_FREESTANDING)
# define LZO_INFO_OS "freestanding"
-#elif defined(LZO_OS_EMBEDDED)
+#elif (LZO_OS_EMBEDDED)
# define LZO_INFO_OS "embedded"
#elif 1 && defined(__IAR_SYSTEMS_ICC__)
# define LZO_OS_EMBEDDED 1
@@ -476,12 +479,27 @@
# define LZO_CC_PELLESC 1
# define LZO_INFO_CC "Pelles C"
# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__POCC__)
-#elif defined(__llvm__) && defined(__GNUC__) && defined(__VERSION__)
-# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
-# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+#elif defined(__clang__) && defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
+# if defined(__GNUC_PATCHLEVEL__)
+# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+# else
+# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+# endif
+# if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__)
+# define LZO_CC_CLANG_CLANG (__clang_major__ * 0x10000L + __clang_minor__ * 0x100 + __clang_patchlevel__)
+# else
+# define LZO_CC_CLANG_CLANG 0x010000L
+# endif
+# define LZO_CC_CLANG LZO_CC_CLANG_GNUC
+# define LZO_INFO_CC "clang"
+# define LZO_INFO_CCVER __VERSION__
+#elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
+# if defined(__GNUC_PATCHLEVEL__)
+# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
# else
-# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
# endif
+# define LZO_CC_LLVM LZO_CC_LLVM_GNUC
# define LZO_INFO_CC "llvm-gcc"
# define LZO_INFO_CCVER __VERSION__
#elif defined(__GNUC__) && defined(__VERSION__)
@@ -502,6 +520,10 @@
# define LZO_CC_AZTECC 1
# define LZO_INFO_CC "Aztec C"
# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__AZTEC_C__)
+#elif defined(__CODEGEARC__)
+# define LZO_CC_CODEGEARC 1
+# define LZO_INFO_CC "CodeGear C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CODEGEARC__)
#elif defined(__BORLANDC__)
# define LZO_CC_BORLANDC 1
# define LZO_INFO_CC "Borland C"
@@ -632,7 +654,7 @@
#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER)
# error "LZO_CC_MSC: _MSC_FULL_VER is not defined"
#endif
-#if !defined(__LZO_ARCH_OVERRIDE) && !defined(LZO_ARCH_GENERIC) && defined(_CRAY)
+#if !defined(__LZO_ARCH_OVERRIDE) && !(LZO_ARCH_GENERIC) && defined(_CRAY)
# if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY)
# if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E)
# define LZO_ARCH_CRAY_MPP 1
@@ -642,7 +664,7 @@
# endif
#endif
#if !defined(__LZO_ARCH_OVERRIDE)
-#if defined(LZO_ARCH_GENERIC)
+#if (LZO_ARCH_GENERIC)
# define LZO_INFO_ARCH "generic"
#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
# define LZO_ARCH_I086 1
@@ -677,6 +699,9 @@
#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__)
# define LZO_ARCH_AVR 1
# define LZO_INFO_ARCH "avr"
+#elif defined(__avr32__) || defined(__AVR32__)
+# define LZO_ARCH_AVR32 1
+# define LZO_INFO_ARCH "avr32"
#elif defined(__bfin__)
# define LZO_ARCH_BLACKFIN 1
# define LZO_INFO_ARCH "blackfin"
@@ -799,10 +824,10 @@
# define LZO_ARCH_I086PM 1
# define LZO_ARCH_IA16PM 1
#endif
-#if defined(LZO_ARCH_ARM_THUMB) && !defined(LZO_ARCH_ARM)
+#if (LZO_ARCH_ARM_THUMB) && !(LZO_ARCH_ARM)
# error "this should not happen"
#endif
-#if defined(LZO_ARCH_I086PM) && !defined(LZO_ARCH_I086)
+#if (LZO_ARCH_I086PM) && !(LZO_ARCH_I086)
# error "this should not happen"
#endif
#if (LZO_ARCH_I086)
@@ -875,7 +900,7 @@
#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295))
# undef LZO_HAVE_MM_HUGE_ARRAY
#endif
-#if (LZO_ARCH_I086PM) && !defined(LZO_HAVE_MM_HUGE_PTR)
+#if (LZO_ARCH_I086PM) && !(LZO_HAVE_MM_HUGE_PTR)
# if (LZO_OS_DOS16)
# error "this should not happen"
# elif (LZO_CC_ZORTECHC)
@@ -1091,7 +1116,7 @@ extern "C" {
#if (LZO_ARCH_I086 && LZO_CC_DMC)
#elif (LZO_CC_CILLY) && defined(__GNUC__)
# define LZO_SIZEOF_LONG_LONG 8
-#elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define LZO_SIZEOF_LONG_LONG 8
#elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400))
# define LZO_SIZEOF_LONG_LONG 8
@@ -1125,12 +1150,12 @@ extern "C" {
#endif
#endif
#endif
-#if defined(__cplusplus) && defined(LZO_CC_GNUC)
+#if defined(__cplusplus) && (LZO_CC_GNUC)
# if (LZO_CC_GNUC < 0x020800ul)
# undef LZO_SIZEOF_LONG_LONG
# endif
#endif
-#if defined(LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG)
+#if (LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG)
# undef LZO_SIZEOF_LONG_LONG
#endif
#if !defined(LZO_SIZEOF_VOID_P)
@@ -1229,15 +1254,17 @@ extern "C" {
# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T
#endif
#endif
-#if defined(LZO_ABI_NEUTRAL_ENDIAN)
+#if (LZO_ABI_NEUTRAL_ENDIAN)
# undef LZO_ABI_BIG_ENDIAN
# undef LZO_ABI_LITTLE_ENDIAN
-#elif !defined(LZO_ABI_BIG_ENDIAN) && !defined(LZO_ABI_LITTLE_ENDIAN)
+#elif !(LZO_ABI_BIG_ENDIAN) && !(LZO_ABI_LITTLE_ENDIAN)
#if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP)
# define LZO_ABI_BIG_ENDIAN 1
+#elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64)
+# define LZO_ABI_LITTLE_ENDIAN 1
#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430)
# define LZO_ABI_LITTLE_ENDIAN 1
-#elif (LZO_ARCH_M68K || LZO_ARCH_S390)
+#elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390)
# define LZO_ABI_BIG_ENDIAN 1
#elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__)
# if (__LITTLE_ENDIAN__ == 1)
@@ -1259,14 +1286,14 @@ extern "C" {
# define LZO_ABI_LITTLE_ENDIAN 1
#endif
#endif
-#if defined(LZO_ABI_BIG_ENDIAN) && defined(LZO_ABI_LITTLE_ENDIAN)
+#if (LZO_ABI_BIG_ENDIAN) && (LZO_ABI_LITTLE_ENDIAN)
# error "this should not happen"
#endif
-#if defined(LZO_ABI_BIG_ENDIAN)
+#if (LZO_ABI_BIG_ENDIAN)
# define LZO_INFO_ABI_ENDIAN "be"
-#elif defined(LZO_ABI_LITTLE_ENDIAN)
+#elif (LZO_ABI_LITTLE_ENDIAN)
# define LZO_INFO_ABI_ENDIAN "le"
-#elif defined(LZO_ABI_NEUTRAL_ENDIAN)
+#elif (LZO_ABI_NEUTRAL_ENDIAN)
# define LZO_INFO_ABI_ENDIAN "neutral"
#endif
#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2)
@@ -1292,15 +1319,15 @@ extern "C" {
# define LZO_INFO_ABI_PM "ip32l64"
#endif
#if !defined(__LZO_LIBC_OVERRIDE)
-#if defined(LZO_LIBC_NAKED)
+#if (LZO_LIBC_NAKED)
# define LZO_INFO_LIBC "naked"
-#elif defined(LZO_LIBC_FREESTANDING)
+#elif (LZO_LIBC_FREESTANDING)
# define LZO_INFO_LIBC "freestanding"
-#elif defined(LZO_LIBC_MOSTLY_FREESTANDING)
+#elif (LZO_LIBC_MOSTLY_FREESTANDING)
# define LZO_INFO_LIBC "mfreestanding"
-#elif defined(LZO_LIBC_ISOC90)
+#elif (LZO_LIBC_ISOC90)
# define LZO_INFO_LIBC "isoc90"
-#elif defined(LZO_LIBC_ISOC99)
+#elif (LZO_LIBC_ISOC99)
# define LZO_INFO_LIBC "isoc99"
#elif defined(__dietlibc__)
# define LZO_LIBC_DIETLIBC 1
@@ -1332,22 +1359,24 @@ extern "C" {
#if !defined(__lzo_gnuc_extension__)
#if (LZO_CC_GNUC >= 0x020800ul)
# define __lzo_gnuc_extension__ __extension__
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_gnuc_extension__ __extension__
#else
-# define __lzo_gnuc_extension__
+# define __lzo_gnuc_extension__ /*empty*/
#endif
#endif
#if !defined(__lzo_ua_volatile)
# define __lzo_ua_volatile volatile
#endif
#if !defined(__lzo_alignof)
-#if (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+#if (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
# define __lzo_alignof(e) __alignof__(e)
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700))
# define __lzo_alignof(e) __alignof__(e)
#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
# define __lzo_alignof(e) __alignof(e)
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+# define __lzo_alignof(e) __alignof__(e)
#endif
#endif
#if defined(__lzo_alignof)
@@ -1358,7 +1387,7 @@ extern "C" {
# define __lzo_constructor __attribute__((__constructor__,__used__))
#elif (LZO_CC_GNUC >= 0x020700ul)
# define __lzo_constructor __attribute__((__constructor__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_constructor __attribute__((__constructor__))
#endif
#endif
@@ -1370,14 +1399,14 @@ extern "C" {
# define __lzo_destructor __attribute__((__destructor__,__used__))
#elif (LZO_CC_GNUC >= 0x020700ul)
# define __lzo_destructor __attribute__((__destructor__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_destructor __attribute__((__destructor__))
#endif
#endif
#if defined(__lzo_destructor)
# define __lzo_HAVE_destructor 1
#endif
-#if defined(__lzo_HAVE_destructor) && !defined(__lzo_HAVE_constructor)
+#if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor)
# error "this should not happen"
#endif
#if !defined(__lzo_inline)
@@ -1386,7 +1415,7 @@ extern "C" {
# define __lzo_inline inline
#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550))
# define __lzo_inline __inline
-#elif (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+#elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
# define __lzo_inline __inline__
#elif (LZO_CC_DMC)
# define __lzo_inline __inline
@@ -1396,6 +1425,8 @@ extern "C" {
# define __lzo_inline __inline
#elif (LZO_CC_MSC && (_MSC_VER >= 900))
# define __lzo_inline __inline
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+# define __lzo_inline __inline__
#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
# define __lzo_inline inline
#endif
@@ -1403,7 +1434,7 @@ extern "C" {
#if defined(__lzo_inline)
# define __lzo_HAVE_inline 1
#else
-# define __lzo_inline
+# define __lzo_inline /*empty*/
#endif
#if !defined(__lzo_forceinline)
#if (LZO_CC_GNUC >= 0x030200ul)
@@ -1412,16 +1443,18 @@ extern "C" {
# define __lzo_forceinline __forceinline
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
# define __lzo_forceinline __inline__ __attribute__((__always_inline__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_forceinline __inline__ __attribute__((__always_inline__))
#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
# define __lzo_forceinline __forceinline
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+# define __lzo_forceinline __inline__ __attribute__((__always_inline__))
#endif
#endif
#if defined(__lzo_forceinline)
# define __lzo_HAVE_forceinline 1
#else
-# define __lzo_forceinline
+# define __lzo_forceinline /*empty*/
#endif
#if !defined(__lzo_noinline)
#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul)
@@ -1432,7 +1465,7 @@ extern "C" {
# define __lzo_noinline __declspec(noinline)
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
# define __lzo_noinline __attribute__((__noinline__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_noinline __attribute__((__noinline__))
#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
# define __lzo_noinline __declspec(noinline)
@@ -1441,14 +1474,16 @@ extern "C" {
# else
# define __lzo_noinline __declspec(noinline)
# endif
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+# define __lzo_noinline __attribute__((__noinline__))
#endif
#endif
#if defined(__lzo_noinline)
# define __lzo_HAVE_noinline 1
#else
-# define __lzo_noinline
+# define __lzo_noinline /*empty*/
#endif
-#if (defined(__lzo_HAVE_forceinline) || defined(__lzo_HAVE_noinline)) && !defined(__lzo_HAVE_inline)
+#if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline)
# error "this should not happen"
#endif
#if !defined(__lzo_noreturn)
@@ -1458,7 +1493,7 @@ extern "C" {
# define __lzo_noreturn __declspec(noreturn)
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC)
# define __lzo_noreturn __attribute__((__noreturn__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_noreturn __attribute__((__noreturn__))
#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
# define __lzo_noreturn __declspec(noreturn)
@@ -1467,16 +1502,16 @@ extern "C" {
#if defined(__lzo_noreturn)
# define __lzo_HAVE_noreturn 1
#else
-# define __lzo_noreturn
+# define __lzo_noreturn /*empty*/
#endif
#if !defined(__lzo_nothrow)
#if (LZO_CC_GNUC >= 0x030300ul)
# define __lzo_nothrow __attribute__((__nothrow__))
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus)
# define __lzo_nothrow __declspec(nothrow)
-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 900) && LZO_CC_SYNTAX_GNUC)
# define __lzo_nothrow __attribute__((__nothrow__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_nothrow __attribute__((__nothrow__))
#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus)
# define __lzo_nothrow __declspec(nothrow)
@@ -1485,14 +1520,14 @@ extern "C" {
#if defined(__lzo_nothrow)
# define __lzo_HAVE_nothrow 1
#else
-# define __lzo_nothrow
+# define __lzo_nothrow /*empty*/
#endif
#if !defined(__lzo_restrict)
#if (LZO_CC_GNUC >= 0x030400ul)
# define __lzo_restrict __restrict__
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC)
# define __lzo_restrict __restrict__
-#elif (LZO_CC_LLVM)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM)
# define __lzo_restrict __restrict__
#elif (LZO_CC_MSC && (_MSC_VER >= 1400))
# define __lzo_restrict __restrict
@@ -1501,7 +1536,7 @@ extern "C" {
#if defined(__lzo_restrict)
# define __lzo_HAVE_restrict 1
#else
-# define __lzo_restrict
+# define __lzo_restrict /*empty*/
#endif
#if !defined(__lzo_likely) && !defined(__lzo_unlikely)
#if (LZO_CC_GNUC >= 0x030200ul)
@@ -1510,7 +1545,7 @@ extern "C" {
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800))
# define __lzo_likely(e) (__builtin_expect(!!(e),1))
# define __lzo_unlikely(e) (__builtin_expect(!!(e),0))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_likely(e) (__builtin_expect(!!(e),1))
# define __lzo_unlikely(e) (__builtin_expect(!!(e),0))
#endif
@@ -1530,7 +1565,7 @@ extern "C" {
# define LZO_UNUSED(var) ((void) &var)
# elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC)
# define LZO_UNUSED(var) if (&var) ; else
-# elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define LZO_UNUSED(var) ((void) var)
# elif (LZO_CC_MSC && (_MSC_VER < 900))
# define LZO_UNUSED(var) if (&var) ; else
@@ -1549,7 +1584,7 @@ extern "C" {
# define LZO_UNUSED_FUNC(func) ((void) func)
# elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC)
# define LZO_UNUSED_FUNC(func) if (func) ; else
-# elif (LZO_CC_LLVM)
+# elif (LZO_CC_CLANG || LZO_CC_LLVM)
# define LZO_UNUSED_FUNC(func) ((void) &func)
# elif (LZO_CC_MSC && (_MSC_VER < 900))
# define LZO_UNUSED_FUNC(func) if (func) ; else
@@ -1564,7 +1599,7 @@ extern "C" {
#if !defined(LZO_UNUSED_LABEL)
# if (LZO_CC_WATCOMC) && defined(__cplusplus)
# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l
-# elif (LZO_CC_INTELC || LZO_CC_WATCOMC)
+# elif (LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC)
# define LZO_UNUSED_LABEL(l) if (0) goto l
# else
# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l
@@ -1579,6 +1614,15 @@ extern "C" {
# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init
# endif
#endif
+#if !defined(LZO_UNCONST_CAST)
+# if 0 && defined(__cplusplus)
+# define LZO_UNCONST_CAST(t,e) (const_cast<t> (e))
+# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((lzo_uintptr_t) ((const void *) (e))))))
+# else
+# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((const void *) (e)))))
+# endif
+#endif
#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER)
# if (LZO_CC_AZTECC || LZO_CC_ZORTECHC)
# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)];
@@ -1607,7 +1651,7 @@ extern "C" {
# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC)
# elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
# define __lzo_cdecl __cdecl
-# define __lzo_cdecl_atexit
+# define __lzo_cdecl_atexit /*empty*/
# define __lzo_cdecl_main __cdecl
# if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))
# define __lzo_cdecl_qsort __pascal
@@ -1648,24 +1692,24 @@ extern "C" {
# define __lzo_cdecl cdecl
#endif
#if !defined(__lzo_cdecl)
-# define __lzo_cdecl
+# define __lzo_cdecl /*empty*/
#endif
#if !defined(__lzo_cdecl_atexit)
-# define __lzo_cdecl_atexit
+# define __lzo_cdecl_atexit /*empty*/
#endif
#if !defined(__lzo_cdecl_main)
-# define __lzo_cdecl_main
+# define __lzo_cdecl_main /*empty*/
#endif
#if !defined(__lzo_cdecl_qsort)
-# define __lzo_cdecl_qsort
+# define __lzo_cdecl_qsort /*empty*/
#endif
#if !defined(__lzo_cdecl_sighandler)
-# define __lzo_cdecl_sighandler
+# define __lzo_cdecl_sighandler /*empty*/
#endif
#if !defined(__lzo_cdecl_va)
# define __lzo_cdecl_va __lzo_cdecl
#endif
-#if !defined(LZO_CFG_NO_WINDOWS_H)
+#if !(LZO_CFG_NO_WINDOWS_H)
#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64)
# if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000))
# elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__)
@@ -1711,7 +1755,7 @@ extern "C" {
#elif (LZO_ARCH_POWERPC)
# define LZO_OPT_PREFER_PREINC 1
# define LZO_OPT_PREFER_PREDEC 1
-# if defined(LZO_ABI_BIG_ENDIAN)
+# if (LZO_ABI_BIG_ENDIAN)
# define LZO_OPT_UNALIGNED16 1
# define LZO_OPT_UNALIGNED32 1
# endif
@@ -1725,28 +1769,29 @@ extern "C" {
# define LZO_OPT_PREFER_POSTINC 1
# define LZO_OPT_PREFER_PREDEC 1
#endif
-#if !defined(LZO_CFG_NO_INLINE_ASM)
-#if defined(LZO_CC_LLVM)
+#ifndef LZO_CFG_NO_INLINE_ASM
+#if (LZO_CC_LLVM)
# define LZO_CFG_NO_INLINE_ASM 1
#endif
#endif
-#if !defined(LZO_CFG_NO_UNALIGNED)
-#if defined(LZO_ABI_NEUTRAL_ENDIAN) || defined(LZO_ARCH_GENERIC)
+#ifndef LZO_CFG_NO_UNALIGNED
+#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC)
# define LZO_CFG_NO_UNALIGNED 1
#endif
#endif
-#if defined(LZO_CFG_NO_UNALIGNED)
+#if (LZO_CFG_NO_UNALIGNED)
# undef LZO_OPT_UNALIGNED16
# undef LZO_OPT_UNALIGNED32
# undef LZO_OPT_UNALIGNED64
#endif
-#if defined(LZO_CFG_NO_INLINE_ASM)
+#if (LZO_CFG_NO_INLINE_ASM)
#elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
# define LZO_ASM_SYNTAX_MSC 1
#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
-#elif (LZO_ARCH_I386 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
+#elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul))
+#elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
# define LZO_ASM_SYNTAX_GNUC 1
-#elif (LZO_ARCH_AMD64 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
+#elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
# define LZO_ASM_SYNTAX_GNUC 1
#endif
#if (LZO_ASM_SYNTAX_GNUC)
diff --git a/extern/lzo/minilzo/minilzo.c b/extern/lzo/minilzo/minilzo.c
index 6a62b31b94a..34ce0f090bd 100644
--- a/extern/lzo/minilzo/minilzo.c
+++ b/extern/lzo/minilzo/minilzo.c
@@ -2,6 +2,9 @@
This file is part of the LZO real-time data compression library.
+ Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
@@ -43,8 +46,7 @@
* http://www.oberhumer.com/opensource/lzo/
*/
-#define __LZO_IN_MINILZO
-#define LZO_BUILD
+#define __LZO_IN_MINILZO 1
#if defined(LZO_CFG_FREESTANDING)
# undef MINILZO_HAVE_CONFIG_H
@@ -142,7 +144,7 @@
#endif
#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL)
# define ptrdiff_t long
-# define _PTRDIFF_T_DEFINED
+# define _PTRDIFF_T_DEFINED 1
#endif
#if (UINT_MAX == LZO_0xffffL)
# undef __LZO_RENAME_A
@@ -286,9 +288,9 @@
# define LZO_EXTERN_C extern
#endif
#if !defined(__LZO_OS_OVERRIDE)
-#if defined(LZO_OS_FREESTANDING)
+#if (LZO_OS_FREESTANDING)
# define LZO_INFO_OS "freestanding"
-#elif defined(LZO_OS_EMBEDDED)
+#elif (LZO_OS_EMBEDDED)
# define LZO_INFO_OS "embedded"
#elif 1 && defined(__IAR_SYSTEMS_ICC__)
# define LZO_OS_EMBEDDED 1
@@ -497,12 +499,27 @@
# define LZO_CC_PELLESC 1
# define LZO_INFO_CC "Pelles C"
# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__POCC__)
-#elif defined(__llvm__) && defined(__GNUC__) && defined(__VERSION__)
-# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
-# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+#elif defined(__clang__) && defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
+# if defined(__GNUC_PATCHLEVEL__)
+# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+# else
+# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+# endif
+# if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__)
+# define LZO_CC_CLANG_CLANG (__clang_major__ * 0x10000L + __clang_minor__ * 0x100 + __clang_patchlevel__)
# else
-# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+# define LZO_CC_CLANG_CLANG 0x010000L
# endif
+# define LZO_CC_CLANG LZO_CC_CLANG_GNUC
+# define LZO_INFO_CC "clang"
+# define LZO_INFO_CCVER __VERSION__
+#elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
+# if defined(__GNUC_PATCHLEVEL__)
+# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+# else
+# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+# endif
+# define LZO_CC_LLVM LZO_CC_LLVM_GNUC
# define LZO_INFO_CC "llvm-gcc"
# define LZO_INFO_CCVER __VERSION__
#elif defined(__GNUC__) && defined(__VERSION__)
@@ -523,6 +540,10 @@
# define LZO_CC_AZTECC 1
# define LZO_INFO_CC "Aztec C"
# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__AZTEC_C__)
+#elif defined(__CODEGEARC__)
+# define LZO_CC_CODEGEARC 1
+# define LZO_INFO_CC "CodeGear C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CODEGEARC__)
#elif defined(__BORLANDC__)
# define LZO_CC_BORLANDC 1
# define LZO_INFO_CC "Borland C"
@@ -653,7 +674,7 @@
#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER)
# error "LZO_CC_MSC: _MSC_FULL_VER is not defined"
#endif
-#if !defined(__LZO_ARCH_OVERRIDE) && !defined(LZO_ARCH_GENERIC) && defined(_CRAY)
+#if !defined(__LZO_ARCH_OVERRIDE) && !(LZO_ARCH_GENERIC) && defined(_CRAY)
# if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY)
# if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E)
# define LZO_ARCH_CRAY_MPP 1
@@ -663,7 +684,7 @@
# endif
#endif
#if !defined(__LZO_ARCH_OVERRIDE)
-#if defined(LZO_ARCH_GENERIC)
+#if (LZO_ARCH_GENERIC)
# define LZO_INFO_ARCH "generic"
#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
# define LZO_ARCH_I086 1
@@ -698,6 +719,9 @@
#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__)
# define LZO_ARCH_AVR 1
# define LZO_INFO_ARCH "avr"
+#elif defined(__avr32__) || defined(__AVR32__)
+# define LZO_ARCH_AVR32 1
+# define LZO_INFO_ARCH "avr32"
#elif defined(__bfin__)
# define LZO_ARCH_BLACKFIN 1
# define LZO_INFO_ARCH "blackfin"
@@ -820,10 +844,10 @@
# define LZO_ARCH_I086PM 1
# define LZO_ARCH_IA16PM 1
#endif
-#if defined(LZO_ARCH_ARM_THUMB) && !defined(LZO_ARCH_ARM)
+#if (LZO_ARCH_ARM_THUMB) && !(LZO_ARCH_ARM)
# error "this should not happen"
#endif
-#if defined(LZO_ARCH_I086PM) && !defined(LZO_ARCH_I086)
+#if (LZO_ARCH_I086PM) && !(LZO_ARCH_I086)
# error "this should not happen"
#endif
#if (LZO_ARCH_I086)
@@ -896,7 +920,7 @@
#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295))
# undef LZO_HAVE_MM_HUGE_ARRAY
#endif
-#if (LZO_ARCH_I086PM) && !defined(LZO_HAVE_MM_HUGE_PTR)
+#if (LZO_ARCH_I086PM) && !(LZO_HAVE_MM_HUGE_PTR)
# if (LZO_OS_DOS16)
# error "this should not happen"
# elif (LZO_CC_ZORTECHC)
@@ -1112,7 +1136,7 @@ extern "C" {
#if (LZO_ARCH_I086 && LZO_CC_DMC)
#elif (LZO_CC_CILLY) && defined(__GNUC__)
# define LZO_SIZEOF_LONG_LONG 8
-#elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define LZO_SIZEOF_LONG_LONG 8
#elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400))
# define LZO_SIZEOF_LONG_LONG 8
@@ -1146,12 +1170,12 @@ extern "C" {
#endif
#endif
#endif
-#if defined(__cplusplus) && defined(LZO_CC_GNUC)
+#if defined(__cplusplus) && (LZO_CC_GNUC)
# if (LZO_CC_GNUC < 0x020800ul)
# undef LZO_SIZEOF_LONG_LONG
# endif
#endif
-#if defined(LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG)
+#if (LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG)
# undef LZO_SIZEOF_LONG_LONG
#endif
#if !defined(LZO_SIZEOF_VOID_P)
@@ -1250,15 +1274,17 @@ extern "C" {
# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T
#endif
#endif
-#if defined(LZO_ABI_NEUTRAL_ENDIAN)
+#if (LZO_ABI_NEUTRAL_ENDIAN)
# undef LZO_ABI_BIG_ENDIAN
# undef LZO_ABI_LITTLE_ENDIAN
-#elif !defined(LZO_ABI_BIG_ENDIAN) && !defined(LZO_ABI_LITTLE_ENDIAN)
+#elif !(LZO_ABI_BIG_ENDIAN) && !(LZO_ABI_LITTLE_ENDIAN)
#if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP)
# define LZO_ABI_BIG_ENDIAN 1
+#elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64)
+# define LZO_ABI_LITTLE_ENDIAN 1
#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430)
# define LZO_ABI_LITTLE_ENDIAN 1
-#elif (LZO_ARCH_M68K || LZO_ARCH_S390)
+#elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390)
# define LZO_ABI_BIG_ENDIAN 1
#elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__)
# if (__LITTLE_ENDIAN__ == 1)
@@ -1280,14 +1306,14 @@ extern "C" {
# define LZO_ABI_LITTLE_ENDIAN 1
#endif
#endif
-#if defined(LZO_ABI_BIG_ENDIAN) && defined(LZO_ABI_LITTLE_ENDIAN)
+#if (LZO_ABI_BIG_ENDIAN) && (LZO_ABI_LITTLE_ENDIAN)
# error "this should not happen"
#endif
-#if defined(LZO_ABI_BIG_ENDIAN)
+#if (LZO_ABI_BIG_ENDIAN)
# define LZO_INFO_ABI_ENDIAN "be"
-#elif defined(LZO_ABI_LITTLE_ENDIAN)
+#elif (LZO_ABI_LITTLE_ENDIAN)
# define LZO_INFO_ABI_ENDIAN "le"
-#elif defined(LZO_ABI_NEUTRAL_ENDIAN)
+#elif (LZO_ABI_NEUTRAL_ENDIAN)
# define LZO_INFO_ABI_ENDIAN "neutral"
#endif
#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2)
@@ -1313,15 +1339,15 @@ extern "C" {
# define LZO_INFO_ABI_PM "ip32l64"
#endif
#if !defined(__LZO_LIBC_OVERRIDE)
-#if defined(LZO_LIBC_NAKED)
+#if (LZO_LIBC_NAKED)
# define LZO_INFO_LIBC "naked"
-#elif defined(LZO_LIBC_FREESTANDING)
+#elif (LZO_LIBC_FREESTANDING)
# define LZO_INFO_LIBC "freestanding"
-#elif defined(LZO_LIBC_MOSTLY_FREESTANDING)
+#elif (LZO_LIBC_MOSTLY_FREESTANDING)
# define LZO_INFO_LIBC "mfreestanding"
-#elif defined(LZO_LIBC_ISOC90)
+#elif (LZO_LIBC_ISOC90)
# define LZO_INFO_LIBC "isoc90"
-#elif defined(LZO_LIBC_ISOC99)
+#elif (LZO_LIBC_ISOC99)
# define LZO_INFO_LIBC "isoc99"
#elif defined(__dietlibc__)
# define LZO_LIBC_DIETLIBC 1
@@ -1353,22 +1379,24 @@ extern "C" {
#if !defined(__lzo_gnuc_extension__)
#if (LZO_CC_GNUC >= 0x020800ul)
# define __lzo_gnuc_extension__ __extension__
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_gnuc_extension__ __extension__
#else
-# define __lzo_gnuc_extension__
+# define __lzo_gnuc_extension__ /*empty*/
#endif
#endif
#if !defined(__lzo_ua_volatile)
# define __lzo_ua_volatile volatile
#endif
#if !defined(__lzo_alignof)
-#if (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+#if (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
# define __lzo_alignof(e) __alignof__(e)
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700))
# define __lzo_alignof(e) __alignof__(e)
#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
# define __lzo_alignof(e) __alignof(e)
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+# define __lzo_alignof(e) __alignof__(e)
#endif
#endif
#if defined(__lzo_alignof)
@@ -1379,7 +1407,7 @@ extern "C" {
# define __lzo_constructor __attribute__((__constructor__,__used__))
#elif (LZO_CC_GNUC >= 0x020700ul)
# define __lzo_constructor __attribute__((__constructor__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_constructor __attribute__((__constructor__))
#endif
#endif
@@ -1391,14 +1419,14 @@ extern "C" {
# define __lzo_destructor __attribute__((__destructor__,__used__))
#elif (LZO_CC_GNUC >= 0x020700ul)
# define __lzo_destructor __attribute__((__destructor__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_destructor __attribute__((__destructor__))
#endif
#endif
#if defined(__lzo_destructor)
# define __lzo_HAVE_destructor 1
#endif
-#if defined(__lzo_HAVE_destructor) && !defined(__lzo_HAVE_constructor)
+#if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor)
# error "this should not happen"
#endif
#if !defined(__lzo_inline)
@@ -1407,7 +1435,7 @@ extern "C" {
# define __lzo_inline inline
#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550))
# define __lzo_inline __inline
-#elif (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+#elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
# define __lzo_inline __inline__
#elif (LZO_CC_DMC)
# define __lzo_inline __inline
@@ -1417,6 +1445,8 @@ extern "C" {
# define __lzo_inline __inline
#elif (LZO_CC_MSC && (_MSC_VER >= 900))
# define __lzo_inline __inline
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+# define __lzo_inline __inline__
#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
# define __lzo_inline inline
#endif
@@ -1424,7 +1454,7 @@ extern "C" {
#if defined(__lzo_inline)
# define __lzo_HAVE_inline 1
#else
-# define __lzo_inline
+# define __lzo_inline /*empty*/
#endif
#if !defined(__lzo_forceinline)
#if (LZO_CC_GNUC >= 0x030200ul)
@@ -1433,16 +1463,18 @@ extern "C" {
# define __lzo_forceinline __forceinline
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
# define __lzo_forceinline __inline__ __attribute__((__always_inline__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_forceinline __inline__ __attribute__((__always_inline__))
#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
# define __lzo_forceinline __forceinline
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+# define __lzo_forceinline __inline__ __attribute__((__always_inline__))
#endif
#endif
#if defined(__lzo_forceinline)
# define __lzo_HAVE_forceinline 1
#else
-# define __lzo_forceinline
+# define __lzo_forceinline /*empty*/
#endif
#if !defined(__lzo_noinline)
#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul)
@@ -1453,7 +1485,7 @@ extern "C" {
# define __lzo_noinline __declspec(noinline)
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
# define __lzo_noinline __attribute__((__noinline__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_noinline __attribute__((__noinline__))
#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
# define __lzo_noinline __declspec(noinline)
@@ -1462,14 +1494,16 @@ extern "C" {
# else
# define __lzo_noinline __declspec(noinline)
# endif
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+# define __lzo_noinline __attribute__((__noinline__))
#endif
#endif
#if defined(__lzo_noinline)
# define __lzo_HAVE_noinline 1
#else
-# define __lzo_noinline
+# define __lzo_noinline /*empty*/
#endif
-#if (defined(__lzo_HAVE_forceinline) || defined(__lzo_HAVE_noinline)) && !defined(__lzo_HAVE_inline)
+#if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline)
# error "this should not happen"
#endif
#if !defined(__lzo_noreturn)
@@ -1479,7 +1513,7 @@ extern "C" {
# define __lzo_noreturn __declspec(noreturn)
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC)
# define __lzo_noreturn __attribute__((__noreturn__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_noreturn __attribute__((__noreturn__))
#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
# define __lzo_noreturn __declspec(noreturn)
@@ -1488,16 +1522,16 @@ extern "C" {
#if defined(__lzo_noreturn)
# define __lzo_HAVE_noreturn 1
#else
-# define __lzo_noreturn
+# define __lzo_noreturn /*empty*/
#endif
#if !defined(__lzo_nothrow)
#if (LZO_CC_GNUC >= 0x030300ul)
# define __lzo_nothrow __attribute__((__nothrow__))
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus)
# define __lzo_nothrow __declspec(nothrow)
-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 900) && LZO_CC_SYNTAX_GNUC)
# define __lzo_nothrow __attribute__((__nothrow__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_nothrow __attribute__((__nothrow__))
#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus)
# define __lzo_nothrow __declspec(nothrow)
@@ -1506,14 +1540,14 @@ extern "C" {
#if defined(__lzo_nothrow)
# define __lzo_HAVE_nothrow 1
#else
-# define __lzo_nothrow
+# define __lzo_nothrow /*empty*/
#endif
#if !defined(__lzo_restrict)
#if (LZO_CC_GNUC >= 0x030400ul)
# define __lzo_restrict __restrict__
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC)
# define __lzo_restrict __restrict__
-#elif (LZO_CC_LLVM)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM)
# define __lzo_restrict __restrict__
#elif (LZO_CC_MSC && (_MSC_VER >= 1400))
# define __lzo_restrict __restrict
@@ -1522,7 +1556,7 @@ extern "C" {
#if defined(__lzo_restrict)
# define __lzo_HAVE_restrict 1
#else
-# define __lzo_restrict
+# define __lzo_restrict /*empty*/
#endif
#if !defined(__lzo_likely) && !defined(__lzo_unlikely)
#if (LZO_CC_GNUC >= 0x030200ul)
@@ -1531,7 +1565,7 @@ extern "C" {
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800))
# define __lzo_likely(e) (__builtin_expect(!!(e),1))
# define __lzo_unlikely(e) (__builtin_expect(!!(e),0))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_likely(e) (__builtin_expect(!!(e),1))
# define __lzo_unlikely(e) (__builtin_expect(!!(e),0))
#endif
@@ -1551,7 +1585,7 @@ extern "C" {
# define LZO_UNUSED(var) ((void) &var)
# elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC)
# define LZO_UNUSED(var) if (&var) ; else
-# elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define LZO_UNUSED(var) ((void) var)
# elif (LZO_CC_MSC && (_MSC_VER < 900))
# define LZO_UNUSED(var) if (&var) ; else
@@ -1570,7 +1604,7 @@ extern "C" {
# define LZO_UNUSED_FUNC(func) ((void) func)
# elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC)
# define LZO_UNUSED_FUNC(func) if (func) ; else
-# elif (LZO_CC_LLVM)
+# elif (LZO_CC_CLANG || LZO_CC_LLVM)
# define LZO_UNUSED_FUNC(func) ((void) &func)
# elif (LZO_CC_MSC && (_MSC_VER < 900))
# define LZO_UNUSED_FUNC(func) if (func) ; else
@@ -1585,7 +1619,7 @@ extern "C" {
#if !defined(LZO_UNUSED_LABEL)
# if (LZO_CC_WATCOMC) && defined(__cplusplus)
# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l
-# elif (LZO_CC_INTELC || LZO_CC_WATCOMC)
+# elif (LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC)
# define LZO_UNUSED_LABEL(l) if (0) goto l
# else
# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l
@@ -1600,6 +1634,15 @@ extern "C" {
# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init
# endif
#endif
+#if !defined(LZO_UNCONST_CAST)
+# if 0 && defined(__cplusplus)
+# define LZO_UNCONST_CAST(t,e) (const_cast<t> (e))
+# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((lzo_uintptr_t) ((const void *) (e))))))
+# else
+# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((const void *) (e)))))
+# endif
+#endif
#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER)
# if (LZO_CC_AZTECC || LZO_CC_ZORTECHC)
# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)];
@@ -1628,7 +1671,7 @@ extern "C" {
# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC)
# elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
# define __lzo_cdecl __cdecl
-# define __lzo_cdecl_atexit
+# define __lzo_cdecl_atexit /*empty*/
# define __lzo_cdecl_main __cdecl
# if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))
# define __lzo_cdecl_qsort __pascal
@@ -1669,24 +1712,24 @@ extern "C" {
# define __lzo_cdecl cdecl
#endif
#if !defined(__lzo_cdecl)
-# define __lzo_cdecl
+# define __lzo_cdecl /*empty*/
#endif
#if !defined(__lzo_cdecl_atexit)
-# define __lzo_cdecl_atexit
+# define __lzo_cdecl_atexit /*empty*/
#endif
#if !defined(__lzo_cdecl_main)
-# define __lzo_cdecl_main
+# define __lzo_cdecl_main /*empty*/
#endif
#if !defined(__lzo_cdecl_qsort)
-# define __lzo_cdecl_qsort
+# define __lzo_cdecl_qsort /*empty*/
#endif
#if !defined(__lzo_cdecl_sighandler)
-# define __lzo_cdecl_sighandler
+# define __lzo_cdecl_sighandler /*empty*/
#endif
#if !defined(__lzo_cdecl_va)
# define __lzo_cdecl_va __lzo_cdecl
#endif
-#if !defined(LZO_CFG_NO_WINDOWS_H)
+#if !(LZO_CFG_NO_WINDOWS_H)
#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64)
# if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000))
# elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__)
@@ -1732,7 +1775,7 @@ extern "C" {
#elif (LZO_ARCH_POWERPC)
# define LZO_OPT_PREFER_PREINC 1
# define LZO_OPT_PREFER_PREDEC 1
-# if defined(LZO_ABI_BIG_ENDIAN)
+# if (LZO_ABI_BIG_ENDIAN)
# define LZO_OPT_UNALIGNED16 1
# define LZO_OPT_UNALIGNED32 1
# endif
@@ -1746,28 +1789,29 @@ extern "C" {
# define LZO_OPT_PREFER_POSTINC 1
# define LZO_OPT_PREFER_PREDEC 1
#endif
-#if !defined(LZO_CFG_NO_INLINE_ASM)
-#if defined(LZO_CC_LLVM)
+#ifndef LZO_CFG_NO_INLINE_ASM
+#if (LZO_CC_LLVM)
# define LZO_CFG_NO_INLINE_ASM 1
#endif
#endif
-#if !defined(LZO_CFG_NO_UNALIGNED)
-#if defined(LZO_ABI_NEUTRAL_ENDIAN) || defined(LZO_ARCH_GENERIC)
+#ifndef LZO_CFG_NO_UNALIGNED
+#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC)
# define LZO_CFG_NO_UNALIGNED 1
#endif
#endif
-#if defined(LZO_CFG_NO_UNALIGNED)
+#if (LZO_CFG_NO_UNALIGNED)
# undef LZO_OPT_UNALIGNED16
# undef LZO_OPT_UNALIGNED32
# undef LZO_OPT_UNALIGNED64
#endif
-#if defined(LZO_CFG_NO_INLINE_ASM)
+#if (LZO_CFG_NO_INLINE_ASM)
#elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
# define LZO_ASM_SYNTAX_MSC 1
#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
-#elif (LZO_ARCH_I386 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
+#elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul))
+#elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
# define LZO_ASM_SYNTAX_GNUC 1
-#elif (LZO_ARCH_AMD64 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
+#elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
# define LZO_ASM_SYNTAX_GNUC 1
#endif
#if (LZO_ASM_SYNTAX_GNUC)
@@ -1830,34 +1874,34 @@ extern "C" {
#undef LZO_HAVE_CONFIG_H
#include "minilzo.h"
-#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x2030)
+#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x2060)
# error "version mismatch in miniLZO source files"
#endif
#ifdef MINILZO_HAVE_CONFIG_H
-# define LZO_HAVE_CONFIG_H
+# define LZO_HAVE_CONFIG_H 1
#endif
#ifndef __LZO_CONF_H
-#define __LZO_CONF_H
+#define __LZO_CONF_H 1
#if !defined(__LZO_IN_MINILZO)
-#if defined(LZO_CFG_FREESTANDING)
+#if (LZO_CFG_FREESTANDING)
# define LZO_LIBC_FREESTANDING 1
# define LZO_OS_FREESTANDING 1
# define ACC_LIBC_FREESTANDING 1
# define ACC_OS_FREESTANDING 1
#endif
-#if defined(LZO_CFG_NO_UNALIGNED)
+#if (LZO_CFG_NO_UNALIGNED)
# define ACC_CFG_NO_UNALIGNED 1
#endif
-#if defined(LZO_ARCH_GENERIC)
+#if (LZO_ARCH_GENERIC)
# define ACC_ARCH_GENERIC 1
#endif
-#if defined(LZO_ABI_NEUTRAL_ENDIAN)
+#if (LZO_ABI_NEUTRAL_ENDIAN)
# define ACC_ABI_NEUTRAL_ENDIAN 1
#endif
-#if defined(LZO_HAVE_CONFIG_H)
+#if (LZO_HAVE_CONFIG_H)
# define ACC_CONFIG_NO_HEADER 1
#endif
#if defined(LZO_CFG_EXTRA_CONFIG_HEADER)
@@ -1886,11 +1930,14 @@ extern "C" {
#endif
#if (LZO_CC_SUNPROC)
+#if !defined(__cplusplus)
# pragma error_messages(off,E_END_OF_LOOP_CODE_NOT_REACHED)
# pragma error_messages(off,E_LOOP_NOT_ENTERED_AT_TOP)
+# pragma error_messages(off,E_STATEMENT_NOT_REACHED)
+#endif
#endif
-#if defined(__LZO_MMODEL_HUGE) && (!LZO_HAVE_MM_HUGE_PTR)
+#if (__LZO_MMODEL_HUGE) && !(LZO_HAVE_MM_HUGE_PTR)
# error "this should not happen - check defines for __huge"
#endif
@@ -1955,40 +2002,44 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp))
#include <string.h>
#endif
-#if defined(LZO_CFG_FREESTANDING)
+#if (LZO_CFG_FREESTANDING)
# undef HAVE_MEMCMP
# undef HAVE_MEMCPY
# undef HAVE_MEMMOVE
# undef HAVE_MEMSET
#endif
-#if !defined(HAVE_MEMCMP)
+#if !(HAVE_MEMCMP)
# undef memcmp
# define memcmp(a,b,c) lzo_memcmp(a,b,c)
-#elif !defined(__LZO_MMODEL_HUGE)
+#elif !(__LZO_MMODEL_HUGE)
+# undef lzo_memcmp
# define lzo_memcmp(a,b,c) memcmp(a,b,c)
#endif
-#if !defined(HAVE_MEMCPY)
+#if !(HAVE_MEMCPY)
# undef memcpy
# define memcpy(a,b,c) lzo_memcpy(a,b,c)
-#elif !defined(__LZO_MMODEL_HUGE)
+#elif !(__LZO_MMODEL_HUGE)
+# undef lzo_memcpy
# define lzo_memcpy(a,b,c) memcpy(a,b,c)
#endif
-#if !defined(HAVE_MEMMOVE)
+#if !(HAVE_MEMMOVE)
# undef memmove
# define memmove(a,b,c) lzo_memmove(a,b,c)
-#elif !defined(__LZO_MMODEL_HUGE)
+#elif !(__LZO_MMODEL_HUGE)
+# undef lzo_memmove
# define lzo_memmove(a,b,c) memmove(a,b,c)
#endif
-#if !defined(HAVE_MEMSET)
+#if !(HAVE_MEMSET)
# undef memset
# define memset(a,b,c) lzo_memset(a,b,c)
-#elif !defined(__LZO_MMODEL_HUGE)
+#elif !(__LZO_MMODEL_HUGE)
+# undef lzo_memset
# define lzo_memset(a,b,c) memset(a,b,c)
#endif
#undef NDEBUG
-#if defined(LZO_CFG_FREESTANDING)
+#if (LZO_CFG_FREESTANDING)
# undef LZO_DEBUG
# define NDEBUG 1
# undef assert
@@ -2008,13 +2059,24 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp))
#endif
#if !defined(__lzo_inline)
-# define __lzo_inline
+# define __lzo_inline /*empty*/
#endif
#if !defined(__lzo_forceinline)
-# define __lzo_forceinline
+# define __lzo_forceinline /*empty*/
#endif
#if !defined(__lzo_noinline)
-# define __lzo_noinline
+# define __lzo_noinline /*empty*/
+#endif
+
+#if (LZO_CFG_PGO)
+# undef __acc_likely
+# undef __acc_unlikely
+# undef __lzo_likely
+# undef __lzo_unlikely
+# define __acc_likely(e) (e)
+# define __acc_unlikely(e) (e)
+# define __lzo_likely(e) (e)
+# define __lzo_unlikely(e) (e)
#endif
#if 1
@@ -2050,24 +2112,69 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp))
#endif
#endif
-#if 1 && !defined(LZO_CFG_NO_UNALIGNED)
-#if 1 && (LZO_ARCH_AMD64 || LZO_ARCH_I386)
+#if 1 && (LZO_ARCH_AMD64 || LZO_ARCH_I386 || LZO_ARCH_POWERPC)
# if (LZO_SIZEOF_SHORT == 2)
-# define LZO_UNALIGNED_OK_2
+# define LZO_UNALIGNED_OK_2 1
# endif
# if (LZO_SIZEOF_INT == 4)
-# define LZO_UNALIGNED_OK_4
+# define LZO_UNALIGNED_OK_4 1
# endif
#endif
+#if 1 && (LZO_ARCH_AMD64)
+# if defined(LZO_UINT64_MAX)
+# define LZO_UNALIGNED_OK_8 1
+# endif
#endif
-
+#if (LZO_CFG_NO_UNALIGNED)
+# undef LZO_UNALIGNED_OK_2
+# undef LZO_UNALIGNED_OK_4
+# undef LZO_UNALIGNED_OK_8
+#endif
+
+#undef UA_GET16
+#undef UA_SET16
+#undef UA_COPY16
+#undef UA_GET32
+#undef UA_SET32
+#undef UA_COPY32
+#undef UA_GET64
+#undef UA_SET64
+#undef UA_COPY64
#if defined(LZO_UNALIGNED_OK_2)
- LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(short) == 2)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(unsigned short) == 2)
+# if 1 && defined(ACC_UA_COPY16)
+# define UA_GET16 ACC_UA_GET16
+# define UA_SET16 ACC_UA_SET16
+# define UA_COPY16 ACC_UA_COPY16
+# else
+# define UA_GET16(p) (* (__lzo_ua_volatile const lzo_ushortp) (__lzo_ua_volatile const lzo_voidp) (p))
+# define UA_SET16(p,v) ((* (__lzo_ua_volatile lzo_ushortp) (__lzo_ua_volatile lzo_voidp) (p)) = (unsigned short) (v))
+# define UA_COPY16(d,s) UA_SET16(d, UA_GET16(s))
+# endif
#endif
-#if defined(LZO_UNALIGNED_OK_4)
- LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32) == 4)
-#elif defined(LZO_ALIGNED_OK_4)
- LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32) == 4)
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32) == 4)
+# if 1 && defined(ACC_UA_COPY32)
+# define UA_GET32 ACC_UA_GET32
+# define UA_SET32 ACC_UA_SET32
+# define UA_COPY32 ACC_UA_COPY32
+# else
+# define UA_GET32(p) (* (__lzo_ua_volatile const lzo_uint32p) (__lzo_ua_volatile const lzo_voidp) (p))
+# define UA_SET32(p,v) ((* (__lzo_ua_volatile lzo_uint32p) (__lzo_ua_volatile lzo_voidp) (p)) = (lzo_uint32) (v))
+# define UA_COPY32(d,s) UA_SET32(d, UA_GET32(s))
+# endif
+#endif
+#if defined(LZO_UNALIGNED_OK_8)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint64) == 8)
+# if 1 && defined(ACC_UA_COPY64)
+# define UA_GET64 ACC_UA_GET64
+# define UA_SET64 ACC_UA_SET64
+# define UA_COPY64 ACC_UA_COPY64
+# else
+# define UA_GET64(p) (* (__lzo_ua_volatile const lzo_uint64p) (__lzo_ua_volatile const lzo_voidp) (p))
+# define UA_SET64(p,v) ((* (__lzo_ua_volatile lzo_uint64p) (__lzo_ua_volatile lzo_voidp) (p)) = (lzo_uint64) (v))
+# define UA_COPY64(d,s) UA_SET64(d, UA_GET64(s))
+# endif
#endif
#define MEMCPY8_DS(dest,src,len) \
@@ -2079,19 +2186,17 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp))
#define MEMCPY_DS(dest,src,len) \
do *dest++ = *src++; while (--len > 0)
-__LZO_EXTERN_C int __lzo_init_done;
-__LZO_EXTERN_C const char __lzo_copyright[];
LZO_EXTERN(const lzo_bytep) lzo_copyright(void);
#ifndef __LZO_PTR_H
-#define __LZO_PTR_H
+#define __LZO_PTR_H 1
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(lzo_uintptr_t)
-# if defined(__LZO_MMODEL_HUGE)
+# if (__LZO_MMODEL_HUGE)
# define lzo_uintptr_t unsigned long
# else
# define lzo_uintptr_t acc_uintptr_t
@@ -2140,6 +2245,10 @@ typedef union
lzo_uint a_lzo_uint;
lzo_int32 a_lzo_int32;
lzo_uint32 a_lzo_uint32;
+#if defined(LZO_UINT64_MAX)
+ lzo_int64 a_lzo_int64;
+ lzo_uint64 a_lzo_uint64;
+#endif
ptrdiff_t a_ptrdiff_t;
lzo_uintptr_t a_lzo_uintptr_t;
lzo_voidp a_lzo_voidp;
@@ -2161,14 +2270,19 @@ lzo_full_align_t;
#endif
-#define LZO_DETERMINISTIC
+#ifndef LZO_DETERMINISTIC
+#define LZO_DETERMINISTIC 1
+#endif
-#define LZO_DICT_USE_PTR
+#ifndef LZO_DICT_USE_PTR
+#define LZO_DICT_USE_PTR 1
#if 0 && (LZO_ARCH_I086)
# undef LZO_DICT_USE_PTR
+# define LZO_DICT_USE_PTR 0
+#endif
#endif
-#if defined(LZO_DICT_USE_PTR)
+#if (LZO_DICT_USE_PTR)
# define lzo_dict_t const lzo_bytep
# define lzo_dict_p lzo_dict_t __LZO_MMODEL *
#else
@@ -2216,22 +2330,22 @@ __lzo_align_gap(const lzo_voidp ptr, lzo_uint size)
}
#endif
+#if !defined(MINILZO_CFG_SKIP_LZO_UTIL)
/* If you use the LZO library in a product, I would appreciate that you
* keep this copyright string in the executable of your product.
*/
-const char __lzo_copyright[] =
+static const char __lzo_copyright[] =
#if !defined(__LZO_IN_MINLZO)
LZO_VERSION_STRING;
#else
"\r\n\n"
"LZO data compression library.\n"
- "$Copyright: LZO (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Markus Franz Xaver Johannes Oberhumer\n"
+ "$Copyright: LZO Copyright (C) 1996-2011 Markus Franz Xaver Johannes Oberhumer\n"
"<markus@oberhumer.com>\n"
"http://www.oberhumer.com $\n\n"
"$Id: LZO version: v" LZO_VERSION_STRING ", " LZO_VERSION_DATE " $\n"
- "$Built: " __DATE__ " " __TIME__ " $\n"
"$Info: " LZO_INFO_STRING " $\n";
#endif
@@ -2321,6 +2435,7 @@ lzo_adler32(lzo_uint32 adler, const lzo_bytep buf, lzo_uint len)
#undef LZO_DO8
#undef LZO_DO16
+#endif
#if !defined(MINILZO_CFG_SKIP_LZO_STRING)
#undef lzo_memcmp
#undef lzo_memcpy
@@ -2343,7 +2458,7 @@ lzo_adler32(lzo_uint32 adler, const lzo_bytep buf, lzo_uint len)
#endif
LZOLIB_PUBLIC(int, lzo_hmemcmp) (const lzo_hvoid_p s1, const lzo_hvoid_p s2, lzo_hsize_t len)
{
-#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMCMP)
+#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMCMP)
const lzo_hbyte_p p1 = (const lzo_hbyte_p) s1;
const lzo_hbyte_p p2 = (const lzo_hbyte_p) s2;
if __lzo_likely(len > 0) do
@@ -2360,7 +2475,7 @@ LZOLIB_PUBLIC(int, lzo_hmemcmp) (const lzo_hvoid_p s1, const lzo_hvoid_p s2, lzo
}
LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemcpy) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len)
{
-#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMCPY)
+#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMCPY)
lzo_hbyte_p p1 = (lzo_hbyte_p) dest;
const lzo_hbyte_p p2 = (const lzo_hbyte_p) src;
if (!(len > 0) || p1 == p2)
@@ -2375,7 +2490,7 @@ LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemcpy) (lzo_hvoid_p dest, const lzo_hvoid_p src
}
LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemmove) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len)
{
-#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMMOVE)
+#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMMOVE)
lzo_hbyte_p p1 = (lzo_hbyte_p) dest;
const lzo_hbyte_p p2 = (const lzo_hbyte_p) src;
if (!(len > 0) || p1 == p2)
@@ -2401,7 +2516,7 @@ LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemmove) (lzo_hvoid_p dest, const lzo_hvoid_p sr
}
LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len)
{
-#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMSET)
+#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMSET)
lzo_hbyte_p p = (lzo_hbyte_p) s;
if __lzo_likely(len > 0) do
*p++ = (unsigned char) c;
@@ -2413,6 +2528,7 @@ LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len)
}
#undef LZOLIB_PUBLIC
#endif
+#if !defined(MINILZO_CFG_SKIP_LZO_INIT)
#if !defined(__LZO_IN_MINILZO)
@@ -2426,6 +2542,11 @@ LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len)
ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint32)
ACCCHK_ASSERT((LZO_UINT32_C(1) << (int)(8*sizeof(LZO_UINT32_C(1))-1)) > 0)
ACCCHK_ASSERT(sizeof(lzo_uint32) >= 4)
+#if defined(LZO_UINT64_MAX)
+ ACCCHK_ASSERT(sizeof(lzo_uint64) == 8)
+ ACCCHK_ASSERT_IS_SIGNED_T(lzo_int64)
+ ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint64)
+#endif
#if !defined(__LZO_UINTPTR_T_IS_POINTER)
ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uintptr_t)
@@ -2440,40 +2561,158 @@ LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len)
#endif
#undef ACCCHK_ASSERT
+#define WANT_lzo_bitops_clz32 1
+#define WANT_lzo_bitops_clz64 1
+#define WANT_lzo_bitops_ctz32 1
+#define WANT_lzo_bitops_ctz64 1
+
+#if (defined(_WIN32) || defined(_WIN64)) && ((LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_MSC && (_MSC_VER >= 1400)))
+#include <intrin.h>
+#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) && 0
+#pragma intrinsic(_BitScanReverse)
+static __lzo_inline unsigned lzo_bitops_clz32(lzo_uint32 v)
+{
+ unsigned long r;
+ (void) _BitScanReverse(&r, v);
+ return (unsigned) r;
+}
+#define lzo_bitops_clz32 lzo_bitops_clz32
+#endif
+#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) && 0
+#pragma intrinsic(_BitScanReverse64)
+static __lzo_inline unsigned lzo_bitops_clz64(lzo_uint64 v)
+{
+ unsigned long r;
+ (void) _BitScanReverse64(&r, v);
+ return (unsigned) r;
+}
+#define lzo_bitops_clz64 lzo_bitops_clz64
+#endif
+#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32)
+#pragma intrinsic(_BitScanForward)
+static __lzo_inline unsigned lzo_bitops_ctz32(lzo_uint32 v)
+{
+ unsigned long r;
+ (void) _BitScanForward(&r, v);
+ return (unsigned) r;
+}
+#define lzo_bitops_ctz32 lzo_bitops_ctz32
+#endif
+#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX)
+#pragma intrinsic(_BitScanForward64)
+static __lzo_inline unsigned lzo_bitops_ctz64(lzo_uint64 v)
+{
+ unsigned long r;
+ (void) _BitScanForward64(&r, v);
+ return (unsigned) r;
+}
+#define lzo_bitops_ctz64 lzo_bitops_ctz64
+#endif
+
+#elif (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x030400ul) || (LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_LLVM && (!defined(__llvm_tools_version__) || (__llvm_tools_version__+0 >= 0x010500ul))))
+#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32)
+#define lzo_bitops_clz32(v) ((unsigned) __builtin_clz(v))
+#endif
+#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX)
+#define lzo_bitops_clz64(v) ((unsigned) __builtin_clzll(v))
+#endif
+#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32)
+#define lzo_bitops_ctz32(v) ((unsigned) __builtin_ctz(v))
+#endif
+#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX)
+#define lzo_bitops_ctz64(v) ((unsigned) __builtin_ctzll(v))
+#endif
+#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount32)
+#define lzo_bitops_popcount32(v) ((unsigned) __builtin_popcount(v))
+#endif
+#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount64) && defined(LZO_UINT64_MAX)
+#define lzo_bitops_popcount64(v) ((unsigned) __builtin_popcountll(v))
+#endif
+#endif
+
+#if 0
+#define u2p(ptr,off) ((lzo_voidp) (((lzo_bytep)(lzo_voidp)(ptr)) + (off)))
+#else
+static __lzo_noinline lzo_voidp u2p(lzo_voidp ptr, lzo_uint off)
+{
+ return (lzo_voidp) ((lzo_bytep) ptr + off);
+}
+#endif
+
LZO_PUBLIC(int)
_lzo_config_check(void)
{
lzo_bool r = 1;
- union { unsigned char c[2*sizeof(lzo_xint)]; lzo_xint l[2]; } u;
- lzo_uintptr_t p;
-
+ union {
+ lzo_xint a[2]; unsigned char b[2*LZO_MAX(8,sizeof(lzo_xint))];
+#if defined(LZO_UNALIGNED_OK_8)
+ lzo_uint64 c[2];
+#endif
+ unsigned short x[2]; lzo_uint32 y[2]; lzo_uint z[2];
+ } u;
+ lzo_voidp p;
+
+ u.a[0] = u.a[1] = 0;
+ p = u2p(&u, 0);
+ r &= ((* (lzo_bytep) p) == 0);
#if !defined(LZO_CFG_NO_CONFIG_CHECK)
#if defined(LZO_ABI_BIG_ENDIAN)
- u.l[0] = u.l[1] = 0; u.c[sizeof(lzo_xint) - 1] = 128;
- r &= (u.l[0] == 128);
+ u.a[0] = u.a[1] = 0; u.b[sizeof(lzo_uint) - 1] = 128;
+ p = u2p(&u, 0);
+ r &= ((* (lzo_uintp) p) == 128);
#endif
#if defined(LZO_ABI_LITTLE_ENDIAN)
- u.l[0] = u.l[1] = 0; u.c[0] = 128;
- r &= (u.l[0] == 128);
+ u.a[0] = u.a[1] = 0; u.b[0] = 128;
+ p = u2p(&u, 0);
+ r &= ((* (lzo_uintp) p) == 128);
#endif
#if defined(LZO_UNALIGNED_OK_2)
- p = (lzo_uintptr_t) (const lzo_voidp) &u.c[0];
- u.l[0] = u.l[1] = 0;
- r &= ((* (const lzo_ushortp) (p+1)) == 0);
+ u.a[0] = u.a[1] = 0;
+ u.b[0] = 1; u.b[sizeof(unsigned short) + 1] = 2;
+ p = u2p(&u, 1);
+ r &= ((* (lzo_ushortp) p) == 0);
#endif
#if defined(LZO_UNALIGNED_OK_4)
- p = (lzo_uintptr_t) (const lzo_voidp) &u.c[0];
- u.l[0] = u.l[1] = 0;
- r &= ((* (const lzo_uint32p) (p+1)) == 0);
+ u.a[0] = u.a[1] = 0;
+ u.b[0] = 3; u.b[sizeof(lzo_uint32) + 1] = 4;
+ p = u2p(&u, 1);
+ r &= ((* (lzo_uint32p) p) == 0);
+#endif
+#if defined(LZO_UNALIGNED_OK_8)
+ u.c[0] = u.c[1] = 0;
+ u.b[0] = 5; u.b[sizeof(lzo_uint64) + 1] = 6;
+ p = u2p(&u, 1);
+ r &= ((* (lzo_uint64p) p) == 0);
+#endif
+#if defined(lzo_bitops_clz32)
+ { unsigned i; lzo_uint32 v = 1;
+ for (i = 0; i < 32; i++, v <<= 1)
+ r &= lzo_bitops_clz32(v) == 31 - i;
+ }
+#endif
+#if defined(lzo_bitops_clz64)
+ { unsigned i; lzo_uint64 v = 1;
+ for (i = 0; i < 64; i++, v <<= 1)
+ r &= lzo_bitops_clz64(v) == 63 - i;
+ }
+#endif
+#if defined(lzo_bitops_ctz32)
+ { unsigned i; lzo_uint32 v = 1;
+ for (i = 0; i < 32; i++, v <<= 1)
+ r &= lzo_bitops_ctz32(v) == i;
+ }
+#endif
+#if defined(lzo_bitops_ctz64)
+ { unsigned i; lzo_uint64 v = 1;
+ for (i = 0; i < 64; i++, v <<= 1)
+ r &= lzo_bitops_ctz64(v) == i;
+ }
#endif
#endif
- LZO_UNUSED(u); LZO_UNUSED(p);
return r == 1 ? LZO_E_OK : LZO_E_ERROR;
}
-int __lzo_init_done = 0;
-
LZO_PUBLIC(int)
__lzo_init_v2(unsigned v, int s1, int s2, int s3, int s4, int s5,
int s6, int s7, int s8, int s9)
@@ -2489,8 +2728,6 @@ __lzo_init_v2(unsigned v, int s1, int s2, int s3, int s4, int s5,
#endif
#undef ACCCHK_ASSERT
- __lzo_init_done = 1;
-
if (v == 0)
return LZO_E_ERROR;
@@ -2532,27 +2769,47 @@ int __far __pascal LibMain ( int a, short b, short c, long d )
#endif
-#define do_compress _lzo1x_1_do_compress
+#endif
+
+#define LZO1X 1
+#define LZO_EOF_CODE 1
+#define M2_MAX_OFFSET 0x0800
#if !defined(MINILZO_CFG_SKIP_LZO1X_1_COMPRESS)
-#define LZO_NEED_DICT_H
+#if 1 && defined(UA_GET32)
+#undef LZO_DICT_USE_PTR
+#define LZO_DICT_USE_PTR 0
+#undef lzo_dict_t
+#define lzo_dict_t unsigned short
+#endif
+
+#define LZO_NEED_DICT_H 1
+#ifndef D_BITS
#define D_BITS 14
+#endif
#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5)
#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)
+#if 1
+#define DINDEX(dv,p) DM(((DMUL(0x1824429d,dv)) >> (32-D_BITS)))
+#else
+#define DINDEX(dv,p) DM((dv) + ((dv) >> (32-D_BITS)))
+#endif
#ifndef __LZO_CONFIG1X_H
-#define __LZO_CONFIG1X_H
+#define __LZO_CONFIG1X_H 1
#if !defined(LZO1X) && !defined(LZO1Y) && !defined(LZO1Z)
-# define LZO1X
+# define LZO1X 1
#endif
#if !defined(__LZO_IN_MINILZO)
#include "lzo/lzo1x.h"
#endif
-#define LZO_EOF_CODE
+#ifndef LZO_EOF_CODE
+#define LZO_EOF_CODE 1
+#endif
#undef LZO_DETERMINISTIC
#define M1_MAX_OFFSET 0x0400
@@ -2592,7 +2849,7 @@ int __far __pascal LibMain ( int a, short b, short c, long d )
#define DL_MIN_LEN M2_MIN_LEN
#ifndef __LZO_DICT_H
-#define __LZO_DICT_H
+#define __LZO_DICT_H 1
#ifdef __cplusplus
extern "C" {
@@ -2633,10 +2890,10 @@ extern "C" {
#if (D_BITS != DL_BITS + DD_BITS)
# error "D_BITS does not match"
#endif
-#if (D_BITS < 8 || D_BITS > 18)
+#if (D_BITS < 6 || D_BITS > 18)
# error "invalid D_BITS"
#endif
-#if (DL_BITS < 8 || DL_BITS > 20)
+#if (DL_BITS < 6 || DL_BITS > 20)
# error "invalid DL_BITS"
#endif
#if (DD_BITS < 0 || DD_BITS > 6)
@@ -2695,14 +2952,14 @@ extern "C" {
# define _DINDEX(dv,p) (_DV_A((p),DL_SHIFT))
#elif (LZO_HASH == LZO_HASH_GZIP_INCREMENTAL)
-# define __LZO_HASH_INCREMENTAL
+# define __LZO_HASH_INCREMENTAL 1
# define DVAL_FIRST(dv,p) dv = _DV_A((p),DL_SHIFT)
# define DVAL_NEXT(dv,p) dv = (((dv) << DL_SHIFT) ^ p[2])
# define _DINDEX(dv,p) (dv)
# define DVAL_LOOKAHEAD DL_MIN_LEN
#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_A)
-# define __LZO_HASH_INCREMENTAL
+# define __LZO_HASH_INCREMENTAL 1
# define DVAL_FIRST(dv,p) dv = _DV_A((p),5)
# define DVAL_NEXT(dv,p) \
dv ^= (lzo_xint)(p[-1]) << (2*5); dv = (((dv) << 5) ^ p[2])
@@ -2710,7 +2967,7 @@ extern "C" {
# define DVAL_LOOKAHEAD DL_MIN_LEN
#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_B)
-# define __LZO_HASH_INCREMENTAL
+# define __LZO_HASH_INCREMENTAL 1
# define DVAL_FIRST(dv,p) dv = _DV_B((p),5)
# define DVAL_NEXT(dv,p) \
dv ^= p[-1]; dv = (((dv) >> 5) ^ ((lzo_xint)(p[2]) << (2*5)))
@@ -2739,7 +2996,12 @@ extern "C" {
#if !defined(DVAL_ASSERT)
#if defined(__LZO_HASH_INCREMENTAL) && !defined(NDEBUG)
-static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p)
+#if (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_LLVM)
+static void __attribute__((__unused__))
+#else
+static void
+#endif
+DVAL_ASSERT(lzo_xint dv, const lzo_bytep p)
{
lzo_xint df;
DVAL_FIRST(df,(p));
@@ -2750,11 +3012,11 @@ static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p)
#endif
#endif
-#if defined(LZO_DICT_USE_PTR)
+#if (LZO_DICT_USE_PTR)
# define DENTRY(p,in) (p)
# define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex]
#else
-# define DENTRY(p,in) ((lzo_uint) ((p)-(in)))
+# define DENTRY(p,in) ((lzo_dict_t) pd(p, in))
# define GINDEX(m_pos,m_off,dict,dindex,in) m_off = dict[dindex]
#endif
@@ -2775,7 +3037,7 @@ static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p)
#endif
-#if defined(LZO_DICT_USE_PTR)
+#if (LZO_DICT_USE_PTR)
#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \
(m_pos == NULL || (m_off = pd(ip, m_pos)) > max_offset)
@@ -2784,7 +3046,7 @@ static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p)
(BOUNDS_CHECKING_OFF_IN_EXPR(( \
m_pos = ip - (lzo_uint) PTR_DIFF(ip,m_pos), \
PTR_LT(m_pos,in) || \
- (m_off = (lzo_uint) PTR_DIFF(ip,m_pos)) <= 0 || \
+ (m_off = (lzo_uint) PTR_DIFF(ip,m_pos)) == 0 || \
m_off > max_offset )))
#else
@@ -2801,7 +3063,7 @@ static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p)
#endif
-#if defined(LZO_DETERMINISTIC)
+#if (LZO_DETERMINISTIC)
# define LZO_CHECK_MPOS LZO_CHECK_MPOS_DET
#else
# define LZO_CHECK_MPOS LZO_CHECK_MPOS_NON_DET
@@ -2817,17 +3079,99 @@ static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p)
#endif
+#define LZO_DETERMINISTIC !(LZO_DICT_USE_PTR)
+
+#ifndef DO_COMPRESS
#define DO_COMPRESS lzo1x_1_compress
+#endif
+
+#if 1 && defined(DO_COMPRESS) && !defined(do_compress)
+# define do_compress LZO_CPP_ECONCAT2(DO_COMPRESS,_core)
+#endif
+
+#if defined(UA_GET64) && (LZO_ABI_BIG_ENDIAN)
+# define WANT_lzo_bitops_clz64 1
+#elif defined(UA_GET64) && (LZO_ABI_LITTLE_ENDIAN)
+# define WANT_lzo_bitops_ctz64 1
+#elif defined(UA_GET32) && (LZO_ABI_BIG_ENDIAN)
+# define WANT_lzo_bitops_clz32 1
+#elif defined(UA_GET32) && (LZO_ABI_LITTLE_ENDIAN)
+# define WANT_lzo_bitops_ctz32 1
+#endif
+
+#if (defined(_WIN32) || defined(_WIN64)) && ((LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_MSC && (_MSC_VER >= 1400)))
+#include <intrin.h>
+#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) && 0
+#pragma intrinsic(_BitScanReverse)
+static __lzo_inline unsigned lzo_bitops_clz32(lzo_uint32 v)
+{
+ unsigned long r;
+ (void) _BitScanReverse(&r, v);
+ return (unsigned) r;
+}
+#define lzo_bitops_clz32 lzo_bitops_clz32
+#endif
+#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) && 0
+#pragma intrinsic(_BitScanReverse64)
+static __lzo_inline unsigned lzo_bitops_clz64(lzo_uint64 v)
+{
+ unsigned long r;
+ (void) _BitScanReverse64(&r, v);
+ return (unsigned) r;
+}
+#define lzo_bitops_clz64 lzo_bitops_clz64
+#endif
+#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32)
+#pragma intrinsic(_BitScanForward)
+static __lzo_inline unsigned lzo_bitops_ctz32(lzo_uint32 v)
+{
+ unsigned long r;
+ (void) _BitScanForward(&r, v);
+ return (unsigned) r;
+}
+#define lzo_bitops_ctz32 lzo_bitops_ctz32
+#endif
+#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX)
+#pragma intrinsic(_BitScanForward64)
+static __lzo_inline unsigned lzo_bitops_ctz64(lzo_uint64 v)
+{
+ unsigned long r;
+ (void) _BitScanForward64(&r, v);
+ return (unsigned) r;
+}
+#define lzo_bitops_ctz64 lzo_bitops_ctz64
+#endif
+
+#elif (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x030400ul) || (LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_LLVM && (!defined(__llvm_tools_version__) || (__llvm_tools_version__+0 >= 0x010500ul))))
+#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32)
+#define lzo_bitops_clz32(v) ((unsigned) __builtin_clz(v))
+#endif
+#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX)
+#define lzo_bitops_clz64(v) ((unsigned) __builtin_clzll(v))
+#endif
+#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32)
+#define lzo_bitops_ctz32(v) ((unsigned) __builtin_ctz(v))
+#endif
+#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX)
+#define lzo_bitops_ctz64(v) ((unsigned) __builtin_ctzll(v))
+#endif
+#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount32)
+#define lzo_bitops_popcount32(v) ((unsigned) __builtin_popcount(v))
+#endif
+#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount64) && defined(LZO_UINT64_MAX)
+#define lzo_bitops_popcount64(v) ((unsigned) __builtin_popcountll(v))
+#endif
+#endif
static __lzo_noinline lzo_uint
do_compress ( const lzo_bytep in , lzo_uint in_len,
lzo_bytep out, lzo_uintp out_len,
- lzo_voidp wrkmem )
+ lzo_uint ti, lzo_voidp wrkmem)
{
register const lzo_bytep ip;
lzo_bytep op;
const lzo_bytep const in_end = in + in_len;
- const lzo_bytep const ip_end = in + in_len - M2_MAX_LEN - 5;
+ const lzo_bytep const ip_end = in + in_len - 20;
const lzo_bytep ii;
lzo_dict_p const dict = (lzo_dict_p) wrkmem;
@@ -2835,14 +3179,17 @@ do_compress ( const lzo_bytep in , lzo_uint in_len,
ip = in;
ii = ip;
- ip += 4;
+ ip += ti < 4 ? 4 - ti : 0;
for (;;)
{
- register const lzo_bytep m_pos;
- lzo_uint m_off;
+ const lzo_bytep m_pos;
+#if !(LZO_DETERMINISTIC)
+ LZO_DEFINE_UNINITIALIZED_VAR(lzo_uint, m_off, 0);
lzo_uint m_len;
lzo_uint dindex;
-
+next:
+ if __lzo_unlikely(ip >= ip_end)
+ break;
DINDEX1(dindex,ip);
GINDEX(m_pos,m_off,dict,dindex,in);
if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
@@ -2860,200 +3207,245 @@ do_compress ( const lzo_bytep in , lzo_uint in_len,
goto literal;
try_match:
-#if 1 && defined(LZO_UNALIGNED_OK_2)
- if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip)
+#if defined(UA_GET32)
+ if (UA_GET32(m_pos) != UA_GET32(ip))
#else
- if (m_pos[0] != ip[0] || m_pos[1] != ip[1])
+ if (m_pos[0] != ip[0] || m_pos[1] != ip[1] || m_pos[2] != ip[2] || m_pos[3] != ip[3])
#endif
{
+literal:
+ UPDATE_I(dict,0,dindex,ip,in);
+ ip += 1 + ((ip - ii) >> 5);
+ continue;
}
- else
- {
- if __lzo_likely(m_pos[2] == ip[2])
- {
-#if 0
- if (m_off <= M2_MAX_OFFSET)
- goto match;
- if (lit <= 3)
- goto match;
- if (lit == 3)
- {
- assert(op - 2 > out); op[-2] |= LZO_BYTE(3);
- *op++ = *ii++; *op++ = *ii++; *op++ = *ii++;
- goto code_match;
- }
- if (m_pos[3] == ip[3])
-#endif
- goto match;
- }
- else
- {
-#if 0
-#if 0
- if (m_off <= M1_MAX_OFFSET && lit > 0 && lit <= 3)
+ UPDATE_I(dict,0,dindex,ip,in);
#else
- if (m_off <= M1_MAX_OFFSET && lit == 3)
-#endif
- {
- register lzo_uint t;
-
- t = lit;
- assert(op - 2 > out); op[-2] |= LZO_BYTE(t);
- do *op++ = *ii++; while (--t > 0);
- assert(ii == ip);
- m_off -= 1;
- *op++ = LZO_BYTE(M1_MARKER | ((m_off & 3) << 2));
- *op++ = LZO_BYTE(m_off >> 2);
- ip += 2;
- goto match_done;
- }
-#endif
- }
- }
-
+ lzo_uint m_off;
+ lzo_uint m_len;
+ {
+ lzo_uint32 dv;
+ lzo_uint dindex;
literal:
- UPDATE_I(dict,0,dindex,ip,in);
- ++ip;
+ ip += 1 + ((ip - ii) >> 5);
+next:
if __lzo_unlikely(ip >= ip_end)
break;
- continue;
-
-match:
+ dv = UA_GET32(ip);
+ dindex = DINDEX(dv,ip);
+ GINDEX(m_off,m_pos,in+dict,dindex,in);
UPDATE_I(dict,0,dindex,ip,in);
- if (pd(ip,ii) > 0)
- {
- register lzo_uint t = pd(ip,ii);
+ if __lzo_unlikely(dv != UA_GET32(m_pos))
+ goto literal;
+ }
+#endif
+ ii -= ti; ti = 0;
+ {
+ register lzo_uint t = pd(ip,ii);
+ if (t != 0)
+ {
if (t <= 3)
{
- assert(op - 2 > out);
op[-2] |= LZO_BYTE(t);
+#if defined(UA_COPY32)
+ UA_COPY32(op, ii);
+ op += t;
+#else
+ { do *op++ = *ii++; while (--t > 0); }
+#endif
}
- else if (t <= 18)
+#if defined(UA_COPY32) || defined(UA_COPY64)
+ else if (t <= 16)
+ {
*op++ = LZO_BYTE(t - 3);
+#if defined(UA_COPY64)
+ UA_COPY64(op, ii);
+ UA_COPY64(op+8, ii+8);
+#else
+ UA_COPY32(op, ii);
+ UA_COPY32(op+4, ii+4);
+ UA_COPY32(op+8, ii+8);
+ UA_COPY32(op+12, ii+12);
+#endif
+ op += t;
+ }
+#endif
else
{
- register lzo_uint tt = t - 18;
-
- *op++ = 0;
- while (tt > 255)
+ if (t <= 18)
+ *op++ = LZO_BYTE(t - 3);
+ else
{
- tt -= 255;
+ register lzo_uint tt = t - 18;
*op++ = 0;
+ while __lzo_unlikely(tt > 255)
+ {
+ tt -= 255;
+#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400))
+ * (volatile unsigned char *) op++ = 0;
+#else
+ *op++ = 0;
+#endif
+ }
+ assert(tt > 0);
+ *op++ = LZO_BYTE(tt);
}
- assert(tt > 0);
- *op++ = LZO_BYTE(tt);
+#if defined(UA_COPY32) || defined(UA_COPY64)
+ do {
+#if defined(UA_COPY64)
+ UA_COPY64(op, ii);
+ UA_COPY64(op+8, ii+8);
+#else
+ UA_COPY32(op, ii);
+ UA_COPY32(op+4, ii+4);
+ UA_COPY32(op+8, ii+8);
+ UA_COPY32(op+12, ii+12);
+#endif
+ op += 16; ii += 16; t -= 16;
+ } while (t >= 16); if (t > 0)
+#endif
+ { do *op++ = *ii++; while (--t > 0); }
}
- do *op++ = *ii++; while (--t > 0);
}
-
- assert(ii == ip);
- ip += 3;
- if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++ ||
- m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++
-#ifdef LZO1Y
- || m_pos[ 9] != *ip++ || m_pos[10] != *ip++ || m_pos[11] != *ip++
- || m_pos[12] != *ip++ || m_pos[13] != *ip++ || m_pos[14] != *ip++
+ }
+ m_len = 4;
+ {
+#if defined(UA_GET64)
+ lzo_uint64 v;
+ v = UA_GET64(ip + m_len) ^ UA_GET64(m_pos + m_len);
+ if __lzo_unlikely(v == 0) {
+ do {
+ m_len += 8;
+ v = UA_GET64(ip + m_len) ^ UA_GET64(m_pos + m_len);
+ if __lzo_unlikely(ip + m_len >= ip_end)
+ goto m_len_done;
+ } while (v == 0);
+ }
+#if (LZO_ABI_BIG_ENDIAN) && defined(lzo_bitops_clz64)
+ m_len += lzo_bitops_clz64(v) / CHAR_BIT;
+#elif (LZO_ABI_BIG_ENDIAN)
+ if ((v >> (64 - CHAR_BIT)) == 0) do {
+ v <<= CHAR_BIT;
+ m_len += 1;
+ } while ((v >> (64 - CHAR_BIT)) == 0);
+#elif (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_ctz64)
+ m_len += lzo_bitops_ctz64(v) / CHAR_BIT;
+#elif (LZO_ABI_LITTLE_ENDIAN)
+ if ((v & UCHAR_MAX) == 0) do {
+ v >>= CHAR_BIT;
+ m_len += 1;
+ } while ((v & UCHAR_MAX) == 0);
+#else
+ if (ip[m_len] == m_pos[m_len]) do {
+ m_len += 1;
+ } while (ip[m_len] == m_pos[m_len]);
+#endif
+#elif defined(UA_GET32)
+ lzo_uint32 v;
+ v = UA_GET32(ip + m_len) ^ UA_GET32(m_pos + m_len);
+ if __lzo_unlikely(v == 0) {
+ do {
+ m_len += 4;
+ v = UA_GET32(ip + m_len) ^ UA_GET32(m_pos + m_len);
+ if __lzo_unlikely(ip + m_len >= ip_end)
+ goto m_len_done;
+ } while (v == 0);
+ }
+#if (LZO_ABI_BIG_ENDIAN) && defined(lzo_bitops_clz32)
+ m_len += lzo_bitops_clz32(v) / CHAR_BIT;
+#elif (LZO_ABI_BIG_ENDIAN)
+ if ((v >> (32 - CHAR_BIT)) == 0) do {
+ v <<= CHAR_BIT;
+ m_len += 1;
+ } while ((v >> (32 - CHAR_BIT)) == 0);
+#elif (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_ctz32)
+ m_len += lzo_bitops_ctz32(v) / CHAR_BIT;
+#elif (LZO_ABI_LITTLE_ENDIAN)
+ if ((v & UCHAR_MAX) == 0) do {
+ v >>= CHAR_BIT;
+ m_len += 1;
+ } while ((v & UCHAR_MAX) == 0);
+#else
+ if (ip[m_len] == m_pos[m_len]) do {
+ m_len += 1;
+ } while (ip[m_len] == m_pos[m_len]);
+#endif
+#else
+ if __lzo_unlikely(ip[m_len] == m_pos[m_len]) {
+ do {
+ m_len += 1;
+ if __lzo_unlikely(ip + m_len >= ip_end)
+ goto m_len_done;
+ } while (ip[m_len] == m_pos[m_len]);
+ }
#endif
- )
+ }
+m_len_done:
+ m_off = pd(ip,m_pos);
+ ip += m_len;
+ ii = ip;
+ if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET)
{
- --ip;
- m_len = pd(ip, ii);
- assert(m_len >= 3); assert(m_len <= M2_MAX_LEN);
-
- if (m_off <= M2_MAX_OFFSET)
- {
- m_off -= 1;
+ m_off -= 1;
#if defined(LZO1X)
- *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2));
- *op++ = LZO_BYTE(m_off >> 3);
+ *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2));
+ *op++ = LZO_BYTE(m_off >> 3);
#elif defined(LZO1Y)
- *op++ = LZO_BYTE(((m_len + 1) << 4) | ((m_off & 3) << 2));
- *op++ = LZO_BYTE(m_off >> 2);
+ *op++ = LZO_BYTE(((m_len + 1) << 4) | ((m_off & 3) << 2));
+ *op++ = LZO_BYTE(m_off >> 2);
#endif
- }
- else if (m_off <= M3_MAX_OFFSET)
- {
- m_off -= 1;
+ }
+ else if (m_off <= M3_MAX_OFFSET)
+ {
+ m_off -= 1;
+ if (m_len <= M3_MAX_LEN)
*op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
- goto m3_m4_offset;
- }
else
-#if defined(LZO1X)
{
- m_off -= 0x4000;
- assert(m_off > 0); assert(m_off <= 0x7fff);
- *op++ = LZO_BYTE(M4_MARKER |
- ((m_off & 0x4000) >> 11) | (m_len - 2));
- goto m3_m4_offset;
- }
-#elif defined(LZO1Y)
- goto m4_match;
+ m_len -= M3_MAX_LEN;
+ *op++ = M3_MARKER | 0;
+ while __lzo_unlikely(m_len > 255)
+ {
+ m_len -= 255;
+#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400))
+ * (volatile unsigned char *) op++ = 0;
+#else
+ *op++ = 0;
#endif
+ }
+ *op++ = LZO_BYTE(m_len);
+ }
+ *op++ = LZO_BYTE(m_off << 2);
+ *op++ = LZO_BYTE(m_off >> 6);
}
else
{
- {
- const lzo_bytep end = in_end;
- const lzo_bytep m = m_pos + M2_MAX_LEN + 1;
- while (ip < end && *m == *ip)
- m++, ip++;
- m_len = pd(ip, ii);
- }
- assert(m_len > M2_MAX_LEN);
-
- if (m_off <= M3_MAX_OFFSET)
- {
- m_off -= 1;
- if (m_len <= 33)
- *op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
- else
- {
- m_len -= 33;
- *op++ = M3_MARKER | 0;
- goto m3_m4_len;
- }
- }
+ m_off -= 0x4000;
+ if (m_len <= M4_MAX_LEN)
+ *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8) | (m_len - 2));
else
{
-#if defined(LZO1Y)
-m4_match:
-#endif
- m_off -= 0x4000;
- assert(m_off > 0); assert(m_off <= 0x7fff);
- if (m_len <= M4_MAX_LEN)
- *op++ = LZO_BYTE(M4_MARKER |
- ((m_off & 0x4000) >> 11) | (m_len - 2));
- else
+ m_len -= M4_MAX_LEN;
+ *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8));
+ while __lzo_unlikely(m_len > 255)
{
- m_len -= M4_MAX_LEN;
- *op++ = LZO_BYTE(M4_MARKER | ((m_off & 0x4000) >> 11));
-m3_m4_len:
- while (m_len > 255)
- {
- m_len -= 255;
- *op++ = 0;
- }
- assert(m_len > 0);
- *op++ = LZO_BYTE(m_len);
+ m_len -= 255;
+#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400))
+ * (volatile unsigned char *) op++ = 0;
+#else
+ *op++ = 0;
+#endif
}
+ *op++ = LZO_BYTE(m_len);
}
-
-m3_m4_offset:
- *op++ = LZO_BYTE((m_off & 63) << 2);
+ *op++ = LZO_BYTE(m_off << 2);
*op++ = LZO_BYTE(m_off >> 6);
}
-
-#if 0
-match_done:
-#endif
- ii = ip;
- if __lzo_unlikely(ip >= ip_end)
- break;
+ goto next;
}
*out_len = pd(op, out);
- return pd(in_end,ii);
+ return pd(in_end,ii-ti);
}
LZO_PUBLIC(int)
@@ -3061,16 +3453,30 @@ DO_COMPRESS ( const lzo_bytep in , lzo_uint in_len,
lzo_bytep out, lzo_uintp out_len,
lzo_voidp wrkmem )
{
+ const lzo_bytep ip = in;
lzo_bytep op = out;
- lzo_uint t;
+ lzo_uint l = in_len;
+ lzo_uint t = 0;
- if __lzo_unlikely(in_len <= M2_MAX_LEN + 5)
- t = in_len;
- else
+ while (l > 20)
{
- t = do_compress(in,in_len,op,out_len,wrkmem);
+ lzo_uint ll = l;
+ lzo_uintptr_t ll_end;
+#if 0 || (LZO_DETERMINISTIC)
+ ll = LZO_MIN(ll, 49152);
+#endif
+ ll_end = (lzo_uintptr_t)ip + ll;
+ if ((ll_end + ((t + ll) >> 5)) <= ll_end || (const lzo_bytep)(ll_end + ((t + ll) >> 5)) <= ip + ll)
+ break;
+#if (LZO_DETERMINISTIC)
+ lzo_memset(wrkmem, 0, ((lzo_uint)1 << D_BITS) * sizeof(lzo_dict_t));
+#endif
+ t = do_compress(ip,ll,op,out_len,t,wrkmem);
+ ip += ll;
op += *out_len;
+ l -= ll;
}
+ t += l;
if (t > 0)
{
@@ -3090,7 +3496,12 @@ DO_COMPRESS ( const lzo_bytep in , lzo_uint in_len,
while (tt > 255)
{
tt -= 255;
+#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400))
+
+ * (volatile unsigned char *) op++ = 0;
+#else
*op++ = 0;
+#endif
}
assert(tt > 0);
*op++ = LZO_BYTE(tt);
@@ -3126,7 +3537,7 @@ DO_COMPRESS ( const lzo_bytep in , lzo_uint in_len,
# define LZO_TEST_OVERRUN_OUTPUT 2
# endif
# if !defined(LZO_TEST_OVERRUN_LOOKBEHIND)
-# define LZO_TEST_OVERRUN_LOOKBEHIND
+# define LZO_TEST_OVERRUN_LOOKBEHIND 1
# endif
#endif
@@ -3177,42 +3588,32 @@ DO_COMPRESS ( const lzo_bytep in , lzo_uint in_len,
#endif
#if defined(TEST_IP)
-# define HAVE_TEST_IP
+# define HAVE_TEST_IP 1
#else
# define TEST_IP 1
#endif
#if defined(TEST_OP)
-# define HAVE_TEST_OP
+# define HAVE_TEST_OP 1
#else
# define TEST_OP 1
#endif
#if defined(NEED_IP)
-# define HAVE_NEED_IP
+# define HAVE_NEED_IP 1
#else
# define NEED_IP(x) ((void) 0)
#endif
#if defined(NEED_OP)
-# define HAVE_NEED_OP
+# define HAVE_NEED_OP 1
#else
# define NEED_OP(x) ((void) 0)
#endif
#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)
-# define HAVE_ANY_IP
+# define HAVE_ANY_IP 1
#endif
#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP)
-# define HAVE_ANY_OP
-#endif
-
-#undef __COPY4
-#define __COPY4(dst,src) * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src)
-
-#undef COPY4
-#if defined(LZO_UNALIGNED_OK_4)
-# define COPY4(dst,src) __COPY4(dst,src)
-#elif defined(LZO_ALIGNED_OK_4)
-# define COPY4(dst,src) __COPY4((lzo_uintptr_t)(dst),(lzo_uintptr_t)(src))
+# define HAVE_ANY_OP 1
#endif
#if defined(DO_DECOMPRESS)
@@ -3291,19 +3692,36 @@ DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len,
t += 15 + *ip++;
}
assert(t > 0); NEED_OP(t+3); NEED_IP(t+4);
-#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4)
+ t += 3;
+ if (t >= 8) do
+ {
+ UA_COPY64(op,ip);
+ op += 8; ip += 8; t -= 8;
+ } while (t >= 8);
+ if (t >= 4)
+ {
+ UA_COPY32(op,ip);
+ op += 4; ip += 4; t -= 4;
+ }
+ if (t > 0)
+ {
+ *op++ = *ip++;
+ if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }
+ }
+#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
#if !defined(LZO_UNALIGNED_OK_4)
if (PTR_ALIGNED2_4(op,ip))
{
#endif
- COPY4(op,ip);
+ UA_COPY32(op,ip);
op += 4; ip += 4;
if (--t > 0)
{
if (t >= 4)
{
do {
- COPY4(op,ip);
+ UA_COPY32(op,ip);
op += 4; ip += 4; t -= 4;
} while (t >= 4);
if (t > 0) do *op++ = *ip++; while (--t > 0);
@@ -3316,7 +3734,7 @@ DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len,
else
#endif
#endif
-#if !defined(LZO_UNALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4) && !defined(LZO_UNALIGNED_OK_8)
{
*op++ = *ip++; *op++ = *ip++; *op++ = *ip++;
do *op++ = *ip++; while (--t > 0);
@@ -3437,7 +3855,7 @@ match:
}
#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
m_pos = op - 1;
- m_pos -= (* (const lzo_ushortp) ip) >> 2;
+ m_pos -= UA_GET16(ip) >> 2;
#else
m_pos = op - 1;
m_pos -= (ip[0] >> 2) + (ip[1] << 6);
@@ -3482,7 +3900,7 @@ match:
#if defined(LZO1Z)
m_pos -= (ip[0] << 6) + (ip[1] >> 2);
#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
- m_pos -= (* (const lzo_ushortp) ip) >> 2;
+ m_pos -= UA_GET16(ip) >> 2;
#else
m_pos -= (ip[0] >> 2) + (ip[1] << 6);
#endif
@@ -3530,7 +3948,28 @@ match:
#else
TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
-#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4)
+ if (op - m_pos >= 8)
+ {
+ t += (3 - 1);
+ if (t >= 8) do
+ {
+ UA_COPY64(op,m_pos);
+ op += 8; m_pos += 8; t -= 8;
+ } while (t >= 8);
+ if (t >= 4)
+ {
+ UA_COPY32(op,m_pos);
+ op += 4; m_pos += 4; t -= 4;
+ }
+ if (t > 0)
+ {
+ *op++ = m_pos[0];
+ if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } }
+ }
+ }
+ else
+#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
#if !defined(LZO_UNALIGNED_OK_4)
if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos))
{
@@ -3539,10 +3978,10 @@ match:
if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
{
#endif
- COPY4(op,m_pos);
+ UA_COPY32(op,m_pos);
op += 4; m_pos += 4; t -= 4 - (3 - 1);
do {
- COPY4(op,m_pos);
+ UA_COPY32(op,m_pos);
op += 4; m_pos += 4; t -= 4;
} while (t >= 4);
if (t > 0) do *op++ = *m_pos++; while (--t > 0);
@@ -3610,7 +4049,7 @@ lookbehind_overrun:
#endif
-#define LZO_TEST_OVERRUN
+#define LZO_TEST_OVERRUN 1
#undef DO_DECOMPRESS
#define DO_DECOMPRESS lzo1x_decompress_safe
@@ -3624,7 +4063,7 @@ lookbehind_overrun:
# define LZO_TEST_OVERRUN_OUTPUT 2
# endif
# if !defined(LZO_TEST_OVERRUN_LOOKBEHIND)
-# define LZO_TEST_OVERRUN_LOOKBEHIND
+# define LZO_TEST_OVERRUN_LOOKBEHIND 1
# endif
#endif
@@ -3675,42 +4114,32 @@ lookbehind_overrun:
#endif
#if defined(TEST_IP)
-# define HAVE_TEST_IP
+# define HAVE_TEST_IP 1
#else
# define TEST_IP 1
#endif
#if defined(TEST_OP)
-# define HAVE_TEST_OP
+# define HAVE_TEST_OP 1
#else
# define TEST_OP 1
#endif
#if defined(NEED_IP)
-# define HAVE_NEED_IP
+# define HAVE_NEED_IP 1
#else
# define NEED_IP(x) ((void) 0)
#endif
#if defined(NEED_OP)
-# define HAVE_NEED_OP
+# define HAVE_NEED_OP 1
#else
# define NEED_OP(x) ((void) 0)
#endif
#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)
-# define HAVE_ANY_IP
+# define HAVE_ANY_IP 1
#endif
#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP)
-# define HAVE_ANY_OP
-#endif
-
-#undef __COPY4
-#define __COPY4(dst,src) * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src)
-
-#undef COPY4
-#if defined(LZO_UNALIGNED_OK_4)
-# define COPY4(dst,src) __COPY4(dst,src)
-#elif defined(LZO_ALIGNED_OK_4)
-# define COPY4(dst,src) __COPY4((lzo_uintptr_t)(dst),(lzo_uintptr_t)(src))
+# define HAVE_ANY_OP 1
#endif
#if defined(DO_DECOMPRESS)
@@ -3789,19 +4218,36 @@ DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len,
t += 15 + *ip++;
}
assert(t > 0); NEED_OP(t+3); NEED_IP(t+4);
-#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4)
+ t += 3;
+ if (t >= 8) do
+ {
+ UA_COPY64(op,ip);
+ op += 8; ip += 8; t -= 8;
+ } while (t >= 8);
+ if (t >= 4)
+ {
+ UA_COPY32(op,ip);
+ op += 4; ip += 4; t -= 4;
+ }
+ if (t > 0)
+ {
+ *op++ = *ip++;
+ if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }
+ }
+#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
#if !defined(LZO_UNALIGNED_OK_4)
if (PTR_ALIGNED2_4(op,ip))
{
#endif
- COPY4(op,ip);
+ UA_COPY32(op,ip);
op += 4; ip += 4;
if (--t > 0)
{
if (t >= 4)
{
do {
- COPY4(op,ip);
+ UA_COPY32(op,ip);
op += 4; ip += 4; t -= 4;
} while (t >= 4);
if (t > 0) do *op++ = *ip++; while (--t > 0);
@@ -3814,7 +4260,7 @@ DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len,
else
#endif
#endif
-#if !defined(LZO_UNALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4) && !defined(LZO_UNALIGNED_OK_8)
{
*op++ = *ip++; *op++ = *ip++; *op++ = *ip++;
do *op++ = *ip++; while (--t > 0);
@@ -3935,7 +4381,7 @@ match:
}
#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
m_pos = op - 1;
- m_pos -= (* (const lzo_ushortp) ip) >> 2;
+ m_pos -= UA_GET16(ip) >> 2;
#else
m_pos = op - 1;
m_pos -= (ip[0] >> 2) + (ip[1] << 6);
@@ -3980,7 +4426,7 @@ match:
#if defined(LZO1Z)
m_pos -= (ip[0] << 6) + (ip[1] >> 2);
#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
- m_pos -= (* (const lzo_ushortp) ip) >> 2;
+ m_pos -= UA_GET16(ip) >> 2;
#else
m_pos -= (ip[0] >> 2) + (ip[1] << 6);
#endif
@@ -4028,7 +4474,28 @@ match:
#else
TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
-#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4)
+ if (op - m_pos >= 8)
+ {
+ t += (3 - 1);
+ if (t >= 8) do
+ {
+ UA_COPY64(op,m_pos);
+ op += 8; m_pos += 8; t -= 8;
+ } while (t >= 8);
+ if (t >= 4)
+ {
+ UA_COPY32(op,m_pos);
+ op += 4; m_pos += 4; t -= 4;
+ }
+ if (t > 0)
+ {
+ *op++ = m_pos[0];
+ if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } }
+ }
+ }
+ else
+#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
#if !defined(LZO_UNALIGNED_OK_4)
if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos))
{
@@ -4037,10 +4504,10 @@ match:
if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
{
#endif
- COPY4(op,m_pos);
+ UA_COPY32(op,m_pos);
op += 4; m_pos += 4; t -= 4 - (3 - 1);
do {
- COPY4(op,m_pos);
+ UA_COPY32(op,m_pos);
op += 4; m_pos += 4; t -= 4;
} while (t >= 4);
if (t > 0) do *op++ = *m_pos++; while (--t > 0);
diff --git a/extern/lzo/minilzo/minilzo.h b/extern/lzo/minilzo/minilzo.h
index 93916bc89b2..f2c104856e3 100644
--- a/extern/lzo/minilzo/minilzo.h
+++ b/extern/lzo/minilzo/minilzo.h
@@ -2,6 +2,9 @@
This file is part of the LZO real-time data compression library.
+ Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
@@ -45,9 +48,9 @@
#ifndef __MINILZO_H
-#define __MINILZO_H
+#define __MINILZO_H 1
-#define MINILZO_VERSION 0x2030
+#define MINILZO_VERSION 0x2060
#ifdef __LZOCONF_H
# error "you cannot use both LZO and miniLZO"
@@ -103,7 +106,6 @@ lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len,
#define LZO_HEAP_ALLOC(var,size) \
lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ]
-
#ifdef __cplusplus
} /* extern "C" */
#endif