ceres-solver and colmap
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +9 -0
- bin/colmap +3 -0
- cmake/Ceres/CeresConfig.cmake +340 -0
- cmake/Ceres/CeresConfigVersion.cmake +70 -0
- cmake/Ceres/CeresTargets-release.cmake +19 -0
- cmake/Ceres/CeresTargets.cmake +100 -0
- cmake/Ceres/FindCXSparse.cmake +240 -0
- cmake/Ceres/FindGlog.cmake +379 -0
- cmake/Ceres/FindMETIS.cmake +110 -0
- cmake/Ceres/FindSuiteSparse.cmake +488 -0
- include/ceres/autodiff_cost_function.h +228 -0
- include/ceres/autodiff_first_order_function.h +151 -0
- include/ceres/autodiff_local_parameterization.h +158 -0
- include/ceres/autodiff_manifold.h +259 -0
- include/ceres/c_api.h +148 -0
- include/ceres/ceres.h +74 -0
- include/ceres/conditioned_cost_function.h +101 -0
- include/ceres/context.h +58 -0
- include/ceres/cost_function.h +144 -0
- include/ceres/cost_function_to_functor.h +171 -0
- include/ceres/covariance.h +459 -0
- include/ceres/crs_matrix.h +87 -0
- include/ceres/cubic_interpolation.h +436 -0
- include/ceres/dynamic_autodiff_cost_function.h +274 -0
- include/ceres/dynamic_cost_function.h +57 -0
- include/ceres/dynamic_cost_function_to_functor.h +194 -0
- include/ceres/dynamic_numeric_diff_cost_function.h +164 -0
- include/ceres/evaluation_callback.h +80 -0
- include/ceres/first_order_function.h +54 -0
- include/ceres/gradient_checker.h +189 -0
- include/ceres/gradient_problem.h +185 -0
- include/ceres/gradient_problem_solver.h +357 -0
- include/ceres/internal/array_selector.h +97 -0
- include/ceres/internal/autodiff.h +365 -0
- include/ceres/internal/config.h +123 -0
- include/ceres/internal/disable_warnings.h +44 -0
- include/ceres/internal/eigen.h +75 -0
- include/ceres/internal/export.h +42 -0
- include/ceres/internal/fixed_array.h +467 -0
- include/ceres/internal/householder_vector.h +96 -0
- include/ceres/internal/integer_sequence_algorithm.h +291 -0
- include/ceres/internal/jet_traits.h +223 -0
- include/ceres/internal/line_parameterization.h +183 -0
- include/ceres/internal/memory.h +90 -0
- include/ceres/internal/numeric_diff.h +508 -0
- include/ceres/internal/parameter_dims.h +124 -0
- include/ceres/internal/port.h +88 -0
- include/ceres/internal/reenable_warnings.h +38 -0
- include/ceres/internal/sphere_manifold_functions.h +162 -0
- include/ceres/internal/variadic_evaluate.h +113 -0
.gitattributes
CHANGED
|
@@ -32,3 +32,12 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 32 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 33 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 33 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 35 |
+
bin/colmap filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
lib/libceres.a filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
lib/colmap/libcolmap_cuda.a filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
lib/colmap/libflann.a filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
lib/colmap/libpoisson_recon.a filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
lib/colmap/libcolmap.a filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
lib/colmap/libpba.a filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
lib/colmap/libsqlite3.a filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
lib/colmap/libsift_gpu.a filter=lfs diff=lfs merge=lfs -text
|
bin/colmap
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5256130472c6f6e7e82c04b2bcd08ca11628cc8da83f65e011f5a5c3ff260796
|
| 3 |
+
size 30940856
|
cmake/Ceres/CeresConfig.cmake
ADDED
|
@@ -0,0 +1,340 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
# Copyright 2015 Google Inc. All rights reserved.
|
| 3 |
+
# http://ceres-solver.org/
|
| 4 |
+
#
|
| 5 |
+
# Redistribution and use in source and binary forms, with or without
|
| 6 |
+
# modification, are permitted provided that the following conditions are met:
|
| 7 |
+
#
|
| 8 |
+
# * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
# this list of conditions and the following disclaimer.
|
| 10 |
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
# this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
# and/or other materials provided with the distribution.
|
| 13 |
+
# * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
# used to endorse or promote products derived from this software without
|
| 15 |
+
# specific prior written permission.
|
| 16 |
+
#
|
| 17 |
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
# POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
#
|
| 29 |
+
# Authors: pablo.speciale@gmail.com (Pablo Speciale)
|
| 30 |
+
# alexs.mac@gmail.com (Alex Stewart)
|
| 31 |
+
#
|
| 32 |
+
|
| 33 |
+
# Config file for Ceres Solver - Find Ceres & dependencies.
|
| 34 |
+
#
|
| 35 |
+
# This file is used by CMake when find_package(Ceres) is invoked and either
|
| 36 |
+
# the directory containing this file either is present in CMAKE_MODULE_PATH
|
| 37 |
+
# (if Ceres was installed), or exists in the local CMake package registry if
|
| 38 |
+
# the Ceres build directory was exported.
|
| 39 |
+
#
|
| 40 |
+
# This module defines the following variables:
|
| 41 |
+
#
|
| 42 |
+
# Ceres_FOUND / CERES_FOUND: True if Ceres has been successfully
|
| 43 |
+
# found. Both variables are set as although
|
| 44 |
+
# FindPackage() only references Ceres_FOUND
|
| 45 |
+
# in Config mode, given the conventions for
|
| 46 |
+
# <package>_FOUND when FindPackage() is
|
| 47 |
+
# called in Module mode, users could
|
| 48 |
+
# reasonably expect to use CERES_FOUND
|
| 49 |
+
# instead.
|
| 50 |
+
#
|
| 51 |
+
# CERES_VERSION: Version of Ceres found.
|
| 52 |
+
#
|
| 53 |
+
# CERES_LIBRARIES: Libraries for Ceres and all
|
| 54 |
+
# dependencies against which Ceres was
|
| 55 |
+
# compiled. This will not include any optional
|
| 56 |
+
# dependencies that were disabled when Ceres was
|
| 57 |
+
# compiled.
|
| 58 |
+
#
|
| 59 |
+
# NOTE: There is no equivalent of CERES_INCLUDE_DIRS as the exported
|
| 60 |
+
# CMake target already includes the definition of its public
|
| 61 |
+
# include directories.
|
| 62 |
+
|
| 63 |
+
include(CMakeFindDependencyMacro)
|
| 64 |
+
|
| 65 |
+
# Called if we failed to find Ceres or any of its required dependencies,
|
| 66 |
+
# unsets all public (designed to be used externally) variables and reports
|
| 67 |
+
# error message at priority depending upon [REQUIRED/QUIET/<NONE>] argument.
|
| 68 |
+
macro(CERES_REPORT_NOT_FOUND REASON_MSG)
|
| 69 |
+
# FindPackage() only references Ceres_FOUND, and requires it to be
|
| 70 |
+
# explicitly set FALSE to denote not found (not merely undefined).
|
| 71 |
+
set(Ceres_FOUND FALSE)
|
| 72 |
+
set(CERES_FOUND FALSE)
|
| 73 |
+
unset(CERES_INCLUDE_DIR)
|
| 74 |
+
unset(CERES_INCLUDE_DIRS)
|
| 75 |
+
unset(CERES_LIBRARIES)
|
| 76 |
+
|
| 77 |
+
# Reset the CMake module path to its state when this script was called.
|
| 78 |
+
set(CMAKE_MODULE_PATH ${CALLERS_CMAKE_MODULE_PATH})
|
| 79 |
+
|
| 80 |
+
# Note <package>_FIND_[REQUIRED/QUIETLY] variables defined by
|
| 81 |
+
# FindPackage() use the camelcase library name, not uppercase.
|
| 82 |
+
if (Ceres_FIND_QUIETLY)
|
| 83 |
+
message(STATUS "Failed to find Ceres - " ${REASON_MSG} ${ARGN})
|
| 84 |
+
elseif (Ceres_FIND_REQUIRED)
|
| 85 |
+
message(FATAL_ERROR "Failed to find Ceres - " ${REASON_MSG} ${ARGN})
|
| 86 |
+
else()
|
| 87 |
+
# Neither QUIETLY nor REQUIRED, use SEND_ERROR which emits an error
|
| 88 |
+
# that prevents generation, but continues configuration.
|
| 89 |
+
message(SEND_ERROR "Failed to find Ceres - " ${REASON_MSG} ${ARGN})
|
| 90 |
+
endif ()
|
| 91 |
+
return()
|
| 92 |
+
endmacro(CERES_REPORT_NOT_FOUND)
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
# ceres_message([mode] "message text")
|
| 96 |
+
#
|
| 97 |
+
# Wraps the standard cmake 'message' command, but suppresses output
|
| 98 |
+
# if the QUIET flag was passed to the find_package(Ceres ...) call.
|
| 99 |
+
function(ceres_message)
|
| 100 |
+
if (NOT Ceres_FIND_QUIETLY)
|
| 101 |
+
message(${ARGN})
|
| 102 |
+
endif()
|
| 103 |
+
endfunction()
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
# ceres_pretty_print_cmake_list( OUTPUT_VAR [item1 [item2 ... ]] )
|
| 107 |
+
#
|
| 108 |
+
# Sets ${OUTPUT_VAR} in the caller's scope to a human-readable string
|
| 109 |
+
# representation of the list passed as the remaining arguments formed
|
| 110 |
+
# as: "[item1, item2, ..., itemN]".
|
| 111 |
+
function(ceres_pretty_print_cmake_list OUTPUT_VAR)
|
| 112 |
+
string(REPLACE ";" ", " PRETTY_LIST_STRING "[${ARGN}]")
|
| 113 |
+
set(${OUTPUT_VAR} "${PRETTY_LIST_STRING}" PARENT_SCOPE)
|
| 114 |
+
endfunction()
|
| 115 |
+
|
| 116 |
+
# The list of (optional) components this version of Ceres was compiled with.
|
| 117 |
+
set(CERES_COMPILED_COMPONENTS "EigenSparse;SparseLinearAlgebraLibrary;LAPACK;SuiteSparse;CXSparse;SchurSpecializations;Multithreading")
|
| 118 |
+
|
| 119 |
+
# If Ceres was not installed, then by definition it was exported
|
| 120 |
+
# from a build directory.
|
| 121 |
+
set(CERES_WAS_INSTALLED TRUE)
|
| 122 |
+
|
| 123 |
+
# Record the state of the CMake module path when this script was
|
| 124 |
+
# called so that we can ensure that we leave it in the same state on
|
| 125 |
+
# exit as it was on entry, but modify it locally.
|
| 126 |
+
set(CALLERS_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH})
|
| 127 |
+
|
| 128 |
+
# Get the (current, i.e. installed) directory containing this file.
|
| 129 |
+
get_filename_component(CERES_CURRENT_CONFIG_DIR
|
| 130 |
+
"${CMAKE_CURRENT_LIST_FILE}" PATH)
|
| 131 |
+
|
| 132 |
+
if (CERES_WAS_INSTALLED)
|
| 133 |
+
# Reset CMake module path to the installation directory of this
|
| 134 |
+
# script, thus we will use the FindPackage() scripts shipped with
|
| 135 |
+
# Ceres to find Ceres' dependencies, even if the user has equivalently
|
| 136 |
+
# named FindPackage() scripts in their project.
|
| 137 |
+
set(CMAKE_MODULE_PATH ${CERES_CURRENT_CONFIG_DIR})
|
| 138 |
+
|
| 139 |
+
# Build the absolute root install directory as a relative path
|
| 140 |
+
# (determined when Ceres was configured & built) from the current
|
| 141 |
+
# install directory for this this file. This allows for the install
|
| 142 |
+
# tree to be relocated, after Ceres was built, outside of CMake.
|
| 143 |
+
get_filename_component(CURRENT_ROOT_INSTALL_DIR
|
| 144 |
+
"${CERES_CURRENT_CONFIG_DIR}/../../../"
|
| 145 |
+
ABSOLUTE)
|
| 146 |
+
if (NOT EXISTS ${CURRENT_ROOT_INSTALL_DIR})
|
| 147 |
+
ceres_report_not_found(
|
| 148 |
+
"Ceres install root: ${CURRENT_ROOT_INSTALL_DIR}, "
|
| 149 |
+
"determined from relative path from CeresConfig.cmake install location: "
|
| 150 |
+
"${CERES_CURRENT_CONFIG_DIR}, does not exist. Either the install "
|
| 151 |
+
"directory was deleted, or the install tree was only partially relocated "
|
| 152 |
+
"outside of CMake after Ceres was built.")
|
| 153 |
+
endif (NOT EXISTS ${CURRENT_ROOT_INSTALL_DIR})
|
| 154 |
+
|
| 155 |
+
else(CERES_WAS_INSTALLED)
|
| 156 |
+
# Ceres was exported from the build tree.
|
| 157 |
+
set(CERES_EXPORTED_BUILD_DIR ${CERES_CURRENT_CONFIG_DIR})
|
| 158 |
+
get_filename_component(CERES_EXPORTED_SOURCE_DIR
|
| 159 |
+
"${CERES_EXPORTED_BUILD_DIR}/../../../"
|
| 160 |
+
ABSOLUTE)
|
| 161 |
+
if (NOT EXISTS ${CERES_EXPORTED_SOURCE_DIR})
|
| 162 |
+
ceres_report_not_found(
|
| 163 |
+
"Ceres exported source directory: ${CERES_EXPORTED_SOURCE_DIR}, "
|
| 164 |
+
"determined from relative path from CeresConfig.cmake exported build "
|
| 165 |
+
"directory: ${CERES_EXPORTED_BUILD_DIR} does not exist.")
|
| 166 |
+
endif()
|
| 167 |
+
|
| 168 |
+
# Reset CMake module path to the cmake directory in the Ceres source
|
| 169 |
+
# tree which was exported, thus we will use the FindPackage() scripts shipped
|
| 170 |
+
# with Ceres to find Ceres' dependencies, even if the user has equivalently
|
| 171 |
+
# named FindPackage() scripts in their project.
|
| 172 |
+
set(CMAKE_MODULE_PATH ${CERES_EXPORTED_SOURCE_DIR}/cmake)
|
| 173 |
+
endif(CERES_WAS_INSTALLED)
|
| 174 |
+
|
| 175 |
+
# Set the version.
|
| 176 |
+
set(CERES_VERSION 2.1.0)
|
| 177 |
+
|
| 178 |
+
include(CMakeFindDependencyMacro)
|
| 179 |
+
find_dependency(Threads)
|
| 180 |
+
|
| 181 |
+
# Optional dependencies
|
| 182 |
+
find_dependency(CXSparse 3.1.9)
|
| 183 |
+
find_dependency(SuiteSparse 5.1.2)
|
| 184 |
+
|
| 185 |
+
# As imported CMake targets are not re-exported when a dependent target is
|
| 186 |
+
# exported, we must invoke find_package(XXX) here to reload the definition
|
| 187 |
+
# of their targets. Without this, the dependency target names (e.g.
|
| 188 |
+
# 'gflags-shared') which will be present in the ceres target would not be
|
| 189 |
+
# defined, and so CMake will assume that they refer to a library name and
|
| 190 |
+
# fail to link correctly.
|
| 191 |
+
|
| 192 |
+
# Eigen.
|
| 193 |
+
# Flag set during configuration and build of Ceres.
|
| 194 |
+
set(CERES_EIGEN_VERSION 3.3.4)
|
| 195 |
+
# Search quietly to control the timing of the error message if not found. The
|
| 196 |
+
# search should be for an exact match, but for usability reasons do a soft
|
| 197 |
+
# match and reject with an explanation below.
|
| 198 |
+
find_package(Eigen3 ${CERES_EIGEN_VERSION} QUIET)
|
| 199 |
+
if (Eigen3_FOUND)
|
| 200 |
+
if (NOT Eigen3_VERSION VERSION_EQUAL CERES_EIGEN_VERSION)
|
| 201 |
+
# CMake's VERSION check in FIND_PACKAGE() will accept any version >= the
|
| 202 |
+
# specified version. However, only version = is supported. Improve
|
| 203 |
+
# usability by explaining why we don't accept non-exact version matching.
|
| 204 |
+
ceres_report_not_found("Found Eigen dependency, but the version of Eigen "
|
| 205 |
+
"found (${Eigen3_VERSION}) does not exactly match the version of Eigen "
|
| 206 |
+
"Ceres was compiled with (${CERES_EIGEN_VERSION}). This can cause subtle "
|
| 207 |
+
"bugs by triggering violations of the One Definition Rule. See the "
|
| 208 |
+
"Wikipedia article http://en.wikipedia.org/wiki/One_Definition_Rule "
|
| 209 |
+
"for more details")
|
| 210 |
+
endif ()
|
| 211 |
+
ceres_message(STATUS "Found required Ceres dependency: "
|
| 212 |
+
"Eigen version ${CERES_EIGEN_VERSION} in ${Eigen3_DIR}")
|
| 213 |
+
else (Eigen3_FOUND)
|
| 214 |
+
ceres_report_not_found("Missing required Ceres "
|
| 215 |
+
"dependency: Eigen version ${CERES_EIGEN_VERSION}, please set "
|
| 216 |
+
"Eigen3_DIR.")
|
| 217 |
+
endif (Eigen3_FOUND)
|
| 218 |
+
|
| 219 |
+
# glog (and maybe gflags).
|
| 220 |
+
#
|
| 221 |
+
# Flags set during configuration and build of Ceres.
|
| 222 |
+
set(CERES_USES_MINIGLOG OFF)
|
| 223 |
+
set(CERES_GLOG_VERSION )
|
| 224 |
+
set(CERES_GLOG_WAS_BUILT_WITH_CMAKE 0)
|
| 225 |
+
|
| 226 |
+
set(CERES_USES_GFLAGS ON)
|
| 227 |
+
set(CERES_GFLAGS_VERSION 2.2.1)
|
| 228 |
+
|
| 229 |
+
if (CERES_USES_MINIGLOG)
|
| 230 |
+
# Output message at standard log level (not the lower STATUS) so that
|
| 231 |
+
# the message is output in GUI during configuration to warn user.
|
| 232 |
+
ceres_message("-- Found Ceres compiled with miniglog substitute "
|
| 233 |
+
"for glog, beware this will likely cause problems if glog is later linked.")
|
| 234 |
+
else(CERES_USES_MINIGLOG)
|
| 235 |
+
if (CERES_GLOG_WAS_BUILT_WITH_CMAKE)
|
| 236 |
+
find_package(glog ${CERES_GLOG_VERSION} CONFIG QUIET)
|
| 237 |
+
set(GLOG_FOUND ${glog_FOUND})
|
| 238 |
+
else()
|
| 239 |
+
# Version of glog against which Ceres was built was not built with CMake,
|
| 240 |
+
# use the exported glog find_package() module from Ceres to find it again.
|
| 241 |
+
# Append the locations of glog when Ceres was built to the search path hints.
|
| 242 |
+
list(APPEND GLOG_INCLUDE_DIR_HINTS "/usr/include")
|
| 243 |
+
get_filename_component(CERES_BUILD_GLOG_LIBRARY_DIR "/usr/lib/x86_64-linux-gnu/libglog.so" PATH)
|
| 244 |
+
list(APPEND GLOG_LIBRARY_DIR_HINTS ${CERES_BUILD_GLOG_LIBRARY_DIR})
|
| 245 |
+
|
| 246 |
+
# Search quietly s/t we control the timing of the error message if not found.
|
| 247 |
+
find_package(Glog QUIET)
|
| 248 |
+
endif()
|
| 249 |
+
|
| 250 |
+
if (GLOG_FOUND)
|
| 251 |
+
ceres_message(STATUS "Found required Ceres dependency: glog")
|
| 252 |
+
else()
|
| 253 |
+
ceres_report_not_found("Missing required Ceres dependency: glog.")
|
| 254 |
+
endif()
|
| 255 |
+
|
| 256 |
+
# gflags is only a public dependency of Ceres via glog, thus is not required
|
| 257 |
+
# if Ceres was built with MINIGLOG.
|
| 258 |
+
if (CERES_USES_GFLAGS)
|
| 259 |
+
# Search quietly s/t we control the timing of the error message if not found.
|
| 260 |
+
find_package(gflags ${CERES_GFLAGS_VERSION} QUIET)
|
| 261 |
+
if (gflags_FOUND AND TARGET gflags)
|
| 262 |
+
ceres_message(STATUS "Found required Ceres dependency: gflags")
|
| 263 |
+
else()
|
| 264 |
+
ceres_report_not_found("Missing required Ceres "
|
| 265 |
+
"dependency: gflags (not found, or not found as exported CMake target).")
|
| 266 |
+
endif()
|
| 267 |
+
endif()
|
| 268 |
+
endif(CERES_USES_MINIGLOG)
|
| 269 |
+
|
| 270 |
+
# Import exported Ceres targets, if they have not already been imported.
|
| 271 |
+
if (NOT TARGET ceres AND NOT Ceres_BINARY_DIR)
|
| 272 |
+
include(${CERES_CURRENT_CONFIG_DIR}/CeresTargets.cmake)
|
| 273 |
+
endif (NOT TARGET ceres AND NOT Ceres_BINARY_DIR)
|
| 274 |
+
# Set the expected XX_LIBRARIES variable for FindPackage().
|
| 275 |
+
set(CERES_LIBRARIES Ceres::ceres)
|
| 276 |
+
|
| 277 |
+
# Reset CMake module path to its state when this script was called.
|
| 278 |
+
set(CMAKE_MODULE_PATH ${CALLERS_CMAKE_MODULE_PATH})
|
| 279 |
+
|
| 280 |
+
# Build the detected Ceres version string to correctly capture whether it
|
| 281 |
+
# was installed, or exported.
|
| 282 |
+
ceres_pretty_print_cmake_list(CERES_COMPILED_COMPONENTS_STRING
|
| 283 |
+
${CERES_COMPILED_COMPONENTS})
|
| 284 |
+
if (CERES_WAS_INSTALLED)
|
| 285 |
+
set(CERES_DETECTED_VERSION_STRING "Ceres version: ${CERES_VERSION} "
|
| 286 |
+
"installed in: ${CURRENT_ROOT_INSTALL_DIR} with components: "
|
| 287 |
+
"${CERES_COMPILED_COMPONENTS_STRING}")
|
| 288 |
+
else (CERES_WAS_INSTALLED)
|
| 289 |
+
set(CERES_DETECTED_VERSION_STRING "Ceres version: ${CERES_VERSION} "
|
| 290 |
+
"exported from build directory: ${CERES_EXPORTED_BUILD_DIR} with "
|
| 291 |
+
"components: ${CERES_COMPILED_COMPONENTS_STRING}")
|
| 292 |
+
endif()
|
| 293 |
+
|
| 294 |
+
# If the user called this script through find_package() whilst specifying
|
| 295 |
+
# particular Ceres components that should be found via:
|
| 296 |
+
# find_package(Ceres COMPONENTS XXX YYY), check the requested components against
|
| 297 |
+
# those with which Ceres was compiled. In this case, we should only report
|
| 298 |
+
# Ceres as found if all the requested components have been found.
|
| 299 |
+
if (Ceres_FIND_COMPONENTS)
|
| 300 |
+
foreach (REQUESTED_COMPONENT ${Ceres_FIND_COMPONENTS})
|
| 301 |
+
list(FIND CERES_COMPILED_COMPONENTS ${REQUESTED_COMPONENT} HAVE_REQUESTED_COMPONENT)
|
| 302 |
+
# list(FIND ..) returns -1 if the element was not in the list, but CMake
|
| 303 |
+
# interprets if (VAR) to be true if VAR is any non-zero number, even
|
| 304 |
+
# negative ones, hence we have to explicitly check for >= 0.
|
| 305 |
+
if (HAVE_REQUESTED_COMPONENT EQUAL -1)
|
| 306 |
+
# Check for the presence of all requested components before reporting
|
| 307 |
+
# not found, such that we report all of the missing components rather
|
| 308 |
+
# than just the first.
|
| 309 |
+
list(APPEND MISSING_CERES_COMPONENTS ${REQUESTED_COMPONENT})
|
| 310 |
+
endif()
|
| 311 |
+
endforeach()
|
| 312 |
+
if (MISSING_CERES_COMPONENTS)
|
| 313 |
+
ceres_pretty_print_cmake_list(REQUESTED_CERES_COMPONENTS_STRING
|
| 314 |
+
${Ceres_FIND_COMPONENTS})
|
| 315 |
+
ceres_pretty_print_cmake_list(MISSING_CERES_COMPONENTS_STRING
|
| 316 |
+
${MISSING_CERES_COMPONENTS})
|
| 317 |
+
ceres_report_not_found("Missing requested Ceres components: "
|
| 318 |
+
"${MISSING_CERES_COMPONENTS_STRING} (components requested: "
|
| 319 |
+
"${REQUESTED_CERES_COMPONENTS_STRING}). Detected "
|
| 320 |
+
"${CERES_DETECTED_VERSION_STRING}.")
|
| 321 |
+
endif()
|
| 322 |
+
endif()
|
| 323 |
+
|
| 324 |
+
# As we use CERES_REPORT_NOT_FOUND() to abort, if we reach this point we have
|
| 325 |
+
# found Ceres and all required dependencies.
|
| 326 |
+
ceres_message(STATUS "Found " ${CERES_DETECTED_VERSION_STRING})
|
| 327 |
+
|
| 328 |
+
# Set CERES_FOUND to be equivalent to Ceres_FOUND, which is set to
|
| 329 |
+
# TRUE by FindPackage() if this file is found and run, and after which
|
| 330 |
+
# Ceres_FOUND is not (explicitly, i.e. undefined does not count) set
|
| 331 |
+
# to FALSE.
|
| 332 |
+
set(CERES_FOUND TRUE)
|
| 333 |
+
|
| 334 |
+
if (NOT TARGET ceres)
|
| 335 |
+
# For backwards compatibility, create a local 'alias' target with the
|
| 336 |
+
# non-namespace-qualified Ceres target name. Note that this is not a
|
| 337 |
+
# true ALIAS library in CMake terms as they cannot point to imported targets.
|
| 338 |
+
add_library(ceres INTERFACE IMPORTED)
|
| 339 |
+
set_target_properties(ceres PROPERTIES INTERFACE_LINK_LIBRARIES Ceres::ceres)
|
| 340 |
+
endif()
|
cmake/Ceres/CeresConfigVersion.cmake
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This is a basic version file for the Config-mode of find_package().
|
| 2 |
+
# It is used by write_basic_package_version_file() as input file for configure_file()
|
| 3 |
+
# to create a version-file which can be installed along a config.cmake file.
|
| 4 |
+
#
|
| 5 |
+
# The created file sets PACKAGE_VERSION_EXACT if the current version string and
|
| 6 |
+
# the requested version string are exactly the same and it sets
|
| 7 |
+
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version,
|
| 8 |
+
# but only if the requested major version is the same as the current one.
|
| 9 |
+
# The variable CVF_VERSION must be set before calling configure_file().
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
set(PACKAGE_VERSION "2.1.0")
|
| 13 |
+
|
| 14 |
+
if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
|
| 15 |
+
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
| 16 |
+
else()
|
| 17 |
+
|
| 18 |
+
if("2.1.0" MATCHES "^([0-9]+)\\.")
|
| 19 |
+
set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}")
|
| 20 |
+
if(NOT CVF_VERSION_MAJOR VERSION_EQUAL 0)
|
| 21 |
+
string(REGEX REPLACE "^0+" "" CVF_VERSION_MAJOR "${CVF_VERSION_MAJOR}")
|
| 22 |
+
endif()
|
| 23 |
+
else()
|
| 24 |
+
set(CVF_VERSION_MAJOR "2.1.0")
|
| 25 |
+
endif()
|
| 26 |
+
|
| 27 |
+
if(PACKAGE_FIND_VERSION_RANGE)
|
| 28 |
+
# both endpoints of the range must have the expected major version
|
| 29 |
+
math (EXPR CVF_VERSION_MAJOR_NEXT "${CVF_VERSION_MAJOR} + 1")
|
| 30 |
+
if (NOT PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR
|
| 31 |
+
OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX_MAJOR STREQUAL CVF_VERSION_MAJOR)
|
| 32 |
+
OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX VERSION_LESS_EQUAL CVF_VERSION_MAJOR_NEXT)))
|
| 33 |
+
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
| 34 |
+
elseif(PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR
|
| 35 |
+
AND ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS_EQUAL PACKAGE_FIND_VERSION_MAX)
|
| 36 |
+
OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MAX)))
|
| 37 |
+
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
| 38 |
+
else()
|
| 39 |
+
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
| 40 |
+
endif()
|
| 41 |
+
else()
|
| 42 |
+
if(PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR)
|
| 43 |
+
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
| 44 |
+
else()
|
| 45 |
+
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
| 46 |
+
endif()
|
| 47 |
+
|
| 48 |
+
if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
|
| 49 |
+
set(PACKAGE_VERSION_EXACT TRUE)
|
| 50 |
+
endif()
|
| 51 |
+
endif()
|
| 52 |
+
endif()
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
# if the installed project requested no architecture check, don't perform the check
|
| 56 |
+
if("FALSE")
|
| 57 |
+
return()
|
| 58 |
+
endif()
|
| 59 |
+
|
| 60 |
+
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
|
| 61 |
+
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "")
|
| 62 |
+
return()
|
| 63 |
+
endif()
|
| 64 |
+
|
| 65 |
+
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
|
| 66 |
+
if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8")
|
| 67 |
+
math(EXPR installedBits "8 * 8")
|
| 68 |
+
set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
|
| 69 |
+
set(PACKAGE_VERSION_UNSUITABLE TRUE)
|
| 70 |
+
endif()
|
cmake/Ceres/CeresTargets-release.cmake
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#----------------------------------------------------------------
|
| 2 |
+
# Generated CMake target import file for configuration "Release".
|
| 3 |
+
#----------------------------------------------------------------
|
| 4 |
+
|
| 5 |
+
# Commands may need to know the format version.
|
| 6 |
+
set(CMAKE_IMPORT_FILE_VERSION 1)
|
| 7 |
+
|
| 8 |
+
# Import target "Ceres::ceres" for configuration "Release"
|
| 9 |
+
set_property(TARGET Ceres::ceres APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
|
| 10 |
+
set_target_properties(Ceres::ceres PROPERTIES
|
| 11 |
+
IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
|
| 12 |
+
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libceres.a"
|
| 13 |
+
)
|
| 14 |
+
|
| 15 |
+
list(APPEND _IMPORT_CHECK_TARGETS Ceres::ceres )
|
| 16 |
+
list(APPEND _IMPORT_CHECK_FILES_FOR_Ceres::ceres "${_IMPORT_PREFIX}/lib/libceres.a" )
|
| 17 |
+
|
| 18 |
+
# Commands beyond this point should not need to know the version.
|
| 19 |
+
set(CMAKE_IMPORT_FILE_VERSION)
|
cmake/Ceres/CeresTargets.cmake
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Generated by CMake
|
| 2 |
+
|
| 3 |
+
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.6)
|
| 4 |
+
message(FATAL_ERROR "CMake >= 2.6.0 required")
|
| 5 |
+
endif()
|
| 6 |
+
cmake_policy(PUSH)
|
| 7 |
+
cmake_policy(VERSION 2.6...3.20)
|
| 8 |
+
#----------------------------------------------------------------
|
| 9 |
+
# Generated CMake target import file.
|
| 10 |
+
#----------------------------------------------------------------
|
| 11 |
+
|
| 12 |
+
# Commands may need to know the format version.
|
| 13 |
+
set(CMAKE_IMPORT_FILE_VERSION 1)
|
| 14 |
+
|
| 15 |
+
# Protect against multiple inclusion, which would fail when already imported targets are added once more.
|
| 16 |
+
set(_targetsDefined)
|
| 17 |
+
set(_targetsNotDefined)
|
| 18 |
+
set(_expectedTargets)
|
| 19 |
+
foreach(_expectedTarget Ceres::ceres)
|
| 20 |
+
list(APPEND _expectedTargets ${_expectedTarget})
|
| 21 |
+
if(NOT TARGET ${_expectedTarget})
|
| 22 |
+
list(APPEND _targetsNotDefined ${_expectedTarget})
|
| 23 |
+
endif()
|
| 24 |
+
if(TARGET ${_expectedTarget})
|
| 25 |
+
list(APPEND _targetsDefined ${_expectedTarget})
|
| 26 |
+
endif()
|
| 27 |
+
endforeach()
|
| 28 |
+
if("${_targetsDefined}" STREQUAL "${_expectedTargets}")
|
| 29 |
+
unset(_targetsDefined)
|
| 30 |
+
unset(_targetsNotDefined)
|
| 31 |
+
unset(_expectedTargets)
|
| 32 |
+
set(CMAKE_IMPORT_FILE_VERSION)
|
| 33 |
+
cmake_policy(POP)
|
| 34 |
+
return()
|
| 35 |
+
endif()
|
| 36 |
+
if(NOT "${_targetsDefined}" STREQUAL "")
|
| 37 |
+
message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n")
|
| 38 |
+
endif()
|
| 39 |
+
unset(_targetsDefined)
|
| 40 |
+
unset(_targetsNotDefined)
|
| 41 |
+
unset(_expectedTargets)
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
# Compute the installation prefix relative to this file.
|
| 45 |
+
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
| 46 |
+
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
| 47 |
+
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
| 48 |
+
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
| 49 |
+
if(_IMPORT_PREFIX STREQUAL "/")
|
| 50 |
+
set(_IMPORT_PREFIX "")
|
| 51 |
+
endif()
|
| 52 |
+
|
| 53 |
+
# Create imported target Ceres::ceres
|
| 54 |
+
add_library(Ceres::ceres STATIC IMPORTED)
|
| 55 |
+
|
| 56 |
+
set_target_properties(Ceres::ceres PROPERTIES
|
| 57 |
+
INTERFACE_COMPILE_FEATURES "cxx_std_14"
|
| 58 |
+
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include;/usr/include"
|
| 59 |
+
INTERFACE_LINK_LIBRARIES "Threads::Threads;/usr/lib/x86_64-linux-gnu/libglog.so;gflags;\$<LINK_ONLY:SuiteSparse::CHOLMOD>;\$<LINK_ONLY:SuiteSparse::SPQR>;\$<LINK_ONLY:CXSparse::CXSparse>;/usr/local/cuda/lib64/libcudart_static.a;\$<LINK_ONLY:Threads::Threads>;\$<LINK_ONLY:dl>;/usr/lib/x86_64-linux-gnu/librt.so;/usr/local/cuda/lib64/libcublas.so;/usr/local/cuda/lib64/libcusolver.so;/usr/local/cuda/lib64/libcusparse.so;/usr/local/lib/libmkl_intel_lp64.so;/usr/local/lib/libmkl_intel_thread.so;/usr/local/lib/libmkl_core.so;/usr/local/lib/libiomp5.so;\$<LINK_ONLY:-lpthread>;\$<LINK_ONLY:-lm>;\$<LINK_ONLY:-ldl>;\$<LINK_ONLY:-lpthread>;\$<LINK_ONLY:-lm>;\$<LINK_ONLY:-ldl>;Eigen3::Eigen"
|
| 60 |
+
)
|
| 61 |
+
|
| 62 |
+
if(CMAKE_VERSION VERSION_LESS 2.8.12)
|
| 63 |
+
message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.")
|
| 64 |
+
endif()
|
| 65 |
+
|
| 66 |
+
# Load information for each installed configuration.
|
| 67 |
+
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
| 68 |
+
file(GLOB CONFIG_FILES "${_DIR}/CeresTargets-*.cmake")
|
| 69 |
+
foreach(f ${CONFIG_FILES})
|
| 70 |
+
include(${f})
|
| 71 |
+
endforeach()
|
| 72 |
+
|
| 73 |
+
# Cleanup temporary variables.
|
| 74 |
+
set(_IMPORT_PREFIX)
|
| 75 |
+
|
| 76 |
+
# Loop over all imported files and verify that they actually exist
|
| 77 |
+
foreach(target ${_IMPORT_CHECK_TARGETS} )
|
| 78 |
+
foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )
|
| 79 |
+
if(NOT EXISTS "${file}" )
|
| 80 |
+
message(FATAL_ERROR "The imported target \"${target}\" references the file
|
| 81 |
+
\"${file}\"
|
| 82 |
+
but this file does not exist. Possible reasons include:
|
| 83 |
+
* The file was deleted, renamed, or moved to another location.
|
| 84 |
+
* An install or uninstall procedure did not complete successfully.
|
| 85 |
+
* The installation package was faulty and contained
|
| 86 |
+
\"${CMAKE_CURRENT_LIST_FILE}\"
|
| 87 |
+
but not all the files it references.
|
| 88 |
+
")
|
| 89 |
+
endif()
|
| 90 |
+
endforeach()
|
| 91 |
+
unset(_IMPORT_CHECK_FILES_FOR_${target})
|
| 92 |
+
endforeach()
|
| 93 |
+
unset(_IMPORT_CHECK_TARGETS)
|
| 94 |
+
|
| 95 |
+
# This file does not depend on other imported targets which have
|
| 96 |
+
# been exported from the same project but in a separate export set.
|
| 97 |
+
|
| 98 |
+
# Commands beyond this point should not need to know the version.
|
| 99 |
+
set(CMAKE_IMPORT_FILE_VERSION)
|
| 100 |
+
cmake_policy(POP)
|
cmake/Ceres/FindCXSparse.cmake
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
# Copyright 2022 Google Inc. All rights reserved.
|
| 3 |
+
# http://ceres-solver.org/
|
| 4 |
+
#
|
| 5 |
+
# Redistribution and use in source and binary forms, with or without
|
| 6 |
+
# modification, are permitted provided that the following conditions are met:
|
| 7 |
+
#
|
| 8 |
+
# * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
# this list of conditions and the following disclaimer.
|
| 10 |
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
# this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
# and/or other materials provided with the distribution.
|
| 13 |
+
# * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
# used to endorse or promote products derived from this software without
|
| 15 |
+
# specific prior written permission.
|
| 16 |
+
#
|
| 17 |
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
# POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
#
|
| 29 |
+
# Author: alexs.mac@gmail.com (Alex Stewart)
|
| 30 |
+
#
|
| 31 |
+
|
| 32 |
+
#[=======================================================================[.rst:
|
| 33 |
+
FindCXSparse
|
| 34 |
+
============
|
| 35 |
+
|
| 36 |
+
Find CXSparse and its dependencies.
|
| 37 |
+
|
| 38 |
+
This module defines the following variables which should be referenced by the
|
| 39 |
+
caller to use the library.
|
| 40 |
+
|
| 41 |
+
``CXSparse_FOUND``
|
| 42 |
+
``TRUE`` iff CXSparse and all dependencies have been found.
|
| 43 |
+
|
| 44 |
+
``CXSparse_VERSION``
|
| 45 |
+
Extracted from ``cs.h``.
|
| 46 |
+
|
| 47 |
+
``CXSparse_VERSION_MAJOR``
|
| 48 |
+
Equal to 3 if ``CXSparse_VERSION`` = 3.1.2
|
| 49 |
+
|
| 50 |
+
``CXSparse_VERSION_MINOR``
|
| 51 |
+
Equal to 1 if ``CXSparse_VERSION`` = 3.1.2
|
| 52 |
+
|
| 53 |
+
``CXSparse_VERSION_PATCH``
|
| 54 |
+
Equal to 2 if ``CXSparse_VERSION`` = 3.1.2
|
| 55 |
+
|
| 56 |
+
The following variables control the behaviour of this module:
|
| 57 |
+
|
| 58 |
+
``CXSparse_NO_CMAKE``
|
| 59 |
+
Do not attempt to use the native CXSparse CMake package configuration.
|
| 60 |
+
|
| 61 |
+
Targets
|
| 62 |
+
-------
|
| 63 |
+
|
| 64 |
+
The following target defines CXSparse.
|
| 65 |
+
|
| 66 |
+
``CXSparse::CXSparse``
|
| 67 |
+
The main CXSparse to be linked against.
|
| 68 |
+
|
| 69 |
+
The following variables are also defined by this module, but in line with CMake
|
| 70 |
+
recommended ``find_package`` module style should NOT be referenced directly by
|
| 71 |
+
callers (use the plural variables detailed above instead). These variables do
|
| 72 |
+
however affect the behaviour of the module via ``find_[path/library]()`` which
|
| 73 |
+
are NOT re-called (i.e., search for library is not repeated) if these variables
|
| 74 |
+
are set with valid values *in the CMake cache*. This means that if these
|
| 75 |
+
variables are set directly in the cache, either by the user in the CMake GUI, or
|
| 76 |
+
by the user passing ``-DVAR=VALUE`` directives to CMake when called (which
|
| 77 |
+
explicitly defines a cache variable), then they will be used verbatim, bypassing
|
| 78 |
+
the ``HINTS`` variables and other hard-coded search locations.
|
| 79 |
+
|
| 80 |
+
``CXSparse_INCLUDE_DIR``
|
| 81 |
+
Include directory for CXSparse, not including the include directory of any
|
| 82 |
+
dependencies.
|
| 83 |
+
|
| 84 |
+
``CXSparse_LIBRARY``
|
| 85 |
+
CXSparse library, not including the libraries of any dependencies.
|
| 86 |
+
]=======================================================================]
|
| 87 |
+
|
| 88 |
+
if (NOT CXSparse_NO_CMAKE)
|
| 89 |
+
find_package (CXSparse NO_MODULE QUIET)
|
| 90 |
+
endif (NOT CXSparse_NO_CMAKE)
|
| 91 |
+
|
| 92 |
+
if (CXSparse_FOUND)
|
| 93 |
+
return ()
|
| 94 |
+
endif (CXSparse_FOUND)
|
| 95 |
+
|
| 96 |
+
# Reset CALLERS_CMAKE_FIND_LIBRARY_PREFIXES to its value when
|
| 97 |
+
# FindCXSparse was invoked.
|
| 98 |
+
macro(CXSparse_RESET_FIND_LIBRARY_PREFIX)
|
| 99 |
+
if (MSVC)
|
| 100 |
+
set(CMAKE_FIND_LIBRARY_PREFIXES "${CALLERS_CMAKE_FIND_LIBRARY_PREFIXES}")
|
| 101 |
+
endif (MSVC)
|
| 102 |
+
endmacro(CXSparse_RESET_FIND_LIBRARY_PREFIX)
|
| 103 |
+
|
| 104 |
+
# Called if we failed to find CXSparse or any of it's required dependencies,
|
| 105 |
+
# unsets all public (designed to be used externally) variables and reports
|
| 106 |
+
# error message at priority depending upon [REQUIRED/QUIET/<NONE>] argument.
|
| 107 |
+
macro(CXSparse_REPORT_NOT_FOUND REASON_MSG)
|
| 108 |
+
# Make results of search visible in the CMake GUI if CXSparse has not
|
| 109 |
+
# been found so that user does not have to toggle to advanced view.
|
| 110 |
+
mark_as_advanced(CLEAR CXSparse_INCLUDE_DIR
|
| 111 |
+
CXSparse_LIBRARY)
|
| 112 |
+
|
| 113 |
+
cxsparse_reset_find_library_prefix()
|
| 114 |
+
|
| 115 |
+
# Note <package>_FIND_[REQUIRED/QUIETLY] variables defined by FindPackage()
|
| 116 |
+
# use the camelcase library name, not uppercase.
|
| 117 |
+
if (CXSparse_FIND_QUIETLY)
|
| 118 |
+
message(STATUS "Failed to find CXSparse - " ${REASON_MSG} ${ARGN})
|
| 119 |
+
elseif (CXSparse_FIND_REQUIRED)
|
| 120 |
+
message(FATAL_ERROR "Failed to find CXSparse - " ${REASON_MSG} ${ARGN})
|
| 121 |
+
else()
|
| 122 |
+
# Neither QUIETLY nor REQUIRED, use no priority which emits a message
|
| 123 |
+
# but continues configuration and allows generation.
|
| 124 |
+
message("-- Failed to find CXSparse - " ${REASON_MSG} ${ARGN})
|
| 125 |
+
endif ()
|
| 126 |
+
return()
|
| 127 |
+
endmacro(CXSparse_REPORT_NOT_FOUND)
|
| 128 |
+
|
| 129 |
+
# Handle possible presence of lib prefix for libraries on MSVC, see
|
| 130 |
+
# also CXSparse_RESET_FIND_LIBRARY_PREFIX().
|
| 131 |
+
if (MSVC)
|
| 132 |
+
# Preserve the caller's original values for CMAKE_FIND_LIBRARY_PREFIXES
|
| 133 |
+
# s/t we can set it back before returning.
|
| 134 |
+
set(CALLERS_CMAKE_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}")
|
| 135 |
+
# The empty string in this list is important, it represents the case when
|
| 136 |
+
# the libraries have no prefix (shared libraries / DLLs).
|
| 137 |
+
set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "" "${CMAKE_FIND_LIBRARY_PREFIXES}")
|
| 138 |
+
endif (MSVC)
|
| 139 |
+
|
| 140 |
+
# Additional suffixes to try appending to each search path.
|
| 141 |
+
list(APPEND CXSparse_CHECK_PATH_SUFFIXES
|
| 142 |
+
suitesparse) # Linux/Windows
|
| 143 |
+
|
| 144 |
+
# Search supplied hint directories first if supplied.
|
| 145 |
+
find_path(CXSparse_INCLUDE_DIR
|
| 146 |
+
NAMES cs.h
|
| 147 |
+
PATH_SUFFIXES ${CXSparse_CHECK_PATH_SUFFIXES})
|
| 148 |
+
if (NOT CXSparse_INCLUDE_DIR OR
|
| 149 |
+
NOT EXISTS ${CXSparse_INCLUDE_DIR})
|
| 150 |
+
cxsparse_report_not_found(
|
| 151 |
+
"Could not find CXSparse include directory, set CXSparse_INCLUDE_DIR "
|
| 152 |
+
"to directory containing cs.h")
|
| 153 |
+
endif (NOT CXSparse_INCLUDE_DIR OR
|
| 154 |
+
NOT EXISTS ${CXSparse_INCLUDE_DIR})
|
| 155 |
+
|
| 156 |
+
find_library(CXSparse_LIBRARY NAMES cxsparse
|
| 157 |
+
PATH_SUFFIXES ${CXSparse_CHECK_PATH_SUFFIXES})
|
| 158 |
+
|
| 159 |
+
if (NOT CXSparse_LIBRARY OR
|
| 160 |
+
NOT EXISTS ${CXSparse_LIBRARY})
|
| 161 |
+
cxsparse_report_not_found(
|
| 162 |
+
"Could not find CXSparse library, set CXSparse_LIBRARY "
|
| 163 |
+
"to full path to libcxsparse.")
|
| 164 |
+
endif (NOT CXSparse_LIBRARY OR
|
| 165 |
+
NOT EXISTS ${CXSparse_LIBRARY})
|
| 166 |
+
|
| 167 |
+
# Mark internally as found, then verify. CXSparse_REPORT_NOT_FOUND() unsets
|
| 168 |
+
# if called.
|
| 169 |
+
set(CXSparse_FOUND TRUE)
|
| 170 |
+
|
| 171 |
+
# Extract CXSparse version from cs.h
|
| 172 |
+
if (CXSparse_INCLUDE_DIR)
|
| 173 |
+
set(CXSparse_VERSION_FILE ${CXSparse_INCLUDE_DIR}/cs.h)
|
| 174 |
+
if (NOT EXISTS ${CXSparse_VERSION_FILE})
|
| 175 |
+
cxsparse_report_not_found(
|
| 176 |
+
"Could not find file: ${CXSparse_VERSION_FILE} "
|
| 177 |
+
"containing version information in CXSparse install located at: "
|
| 178 |
+
"${CXSparse_INCLUDE_DIR}.")
|
| 179 |
+
else (NOT EXISTS ${CXSparse_VERSION_FILE})
|
| 180 |
+
file(READ ${CXSparse_INCLUDE_DIR}/cs.h CXSparse_VERSION_FILE_CONTENTS)
|
| 181 |
+
|
| 182 |
+
string(REGEX MATCH "#define CS_VER [0-9]+"
|
| 183 |
+
CXSparse_VERSION_MAJOR "${CXSparse_VERSION_FILE_CONTENTS}")
|
| 184 |
+
string(REGEX REPLACE "#define CS_VER ([0-9]+)" "\\1"
|
| 185 |
+
CXSparse_VERSION_MAJOR "${CXSparse_VERSION_MAJOR}")
|
| 186 |
+
|
| 187 |
+
string(REGEX MATCH "#define CS_SUBVER [0-9]+"
|
| 188 |
+
CXSparse_VERSION_MINOR "${CXSparse_VERSION_FILE_CONTENTS}")
|
| 189 |
+
string(REGEX REPLACE "#define CS_SUBVER ([0-9]+)" "\\1"
|
| 190 |
+
CXSparse_VERSION_MINOR "${CXSparse_VERSION_MINOR}")
|
| 191 |
+
|
| 192 |
+
string(REGEX MATCH "#define CS_SUBSUB [0-9]+"
|
| 193 |
+
CXSparse_VERSION_PATCH "${CXSparse_VERSION_FILE_CONTENTS}")
|
| 194 |
+
string(REGEX REPLACE "#define CS_SUBSUB ([0-9]+)" "\\1"
|
| 195 |
+
CXSparse_VERSION_PATCH "${CXSparse_VERSION_PATCH}")
|
| 196 |
+
|
| 197 |
+
# This is on a single line s/t CMake does not interpret it as a list of
|
| 198 |
+
# elements and insert ';' separators which would result in 3.;1.;2 nonsense.
|
| 199 |
+
set(CXSparse_VERSION "${CXSparse_VERSION_MAJOR}.${CXSparse_VERSION_MINOR}.${CXSparse_VERSION_PATCH}")
|
| 200 |
+
set(CXSparse_VERSION_COMPONENTS 3)
|
| 201 |
+
endif (NOT EXISTS ${CXSparse_VERSION_FILE})
|
| 202 |
+
endif (CXSparse_INCLUDE_DIR)
|
| 203 |
+
|
| 204 |
+
# Catch the case when the caller has set CXSparse_LIBRARY in the cache / GUI and
|
| 205 |
+
# thus FIND_LIBRARY was not called, but specified library is invalid, otherwise
|
| 206 |
+
# we would report CXSparse as found.
|
| 207 |
+
# TODO: This regex for CXSparse library is pretty primitive, we use lowercase
|
| 208 |
+
# for comparison to handle Windows using CamelCase library names, could
|
| 209 |
+
# this check be better?
|
| 210 |
+
string(TOLOWER "${CXSparse_LIBRARY}" LOWERCASE_CXSparse_LIBRARY)
|
| 211 |
+
if (CXSparse_LIBRARY AND
|
| 212 |
+
EXISTS ${CXSparse_LIBRARY} AND
|
| 213 |
+
NOT "${LOWERCASE_CXSparse_LIBRARY}" MATCHES ".*cxsparse[^/]*")
|
| 214 |
+
cxsparse_report_not_found(
|
| 215 |
+
"Caller defined CXSparse_LIBRARY: "
|
| 216 |
+
"${CXSparse_LIBRARY} does not match CXSparse.")
|
| 217 |
+
endif (CXSparse_LIBRARY AND
|
| 218 |
+
EXISTS ${CXSparse_LIBRARY} AND
|
| 219 |
+
NOT "${LOWERCASE_CXSparse_LIBRARY}" MATCHES ".*cxsparse[^/]*")
|
| 220 |
+
|
| 221 |
+
cxsparse_reset_find_library_prefix()
|
| 222 |
+
|
| 223 |
+
mark_as_advanced(CXSparse_INCLUDE_DIR CXSparse_LIBRARY)
|
| 224 |
+
|
| 225 |
+
# Handle REQUIRED / QUIET optional arguments and version.
|
| 226 |
+
include(FindPackageHandleStandardArgs)
|
| 227 |
+
find_package_handle_standard_args(CXSparse
|
| 228 |
+
REQUIRED_VARS CXSparse_INCLUDE_DIR CXSparse_LIBRARY
|
| 229 |
+
VERSION_VAR CXSparse_VERSION)
|
| 230 |
+
|
| 231 |
+
if (CXSparse_INCLUDE_DIR AND CXSparse_LIBRARY)
|
| 232 |
+
if (NOT TARGET CXSparse::CXSparse)
|
| 233 |
+
add_library (CXSparse::CXSparse IMPORTED UNKNOWN)
|
| 234 |
+
endif (NOT TARGET CXSparse::CXSparse)
|
| 235 |
+
|
| 236 |
+
set_property (TARGET CXSparse::CXSparse PROPERTY
|
| 237 |
+
IMPORTED_LOCATION ${CXSparse_LIBRARY})
|
| 238 |
+
set_property (TARGET CXSparse::CXSparse PROPERTY
|
| 239 |
+
INTERFACE_INCLUDE_DIRECTORIES ${CXSparse_INCLUDE_DIR})
|
| 240 |
+
endif (CXSparse_INCLUDE_DIR AND CXSparse_LIBRARY)
|
cmake/Ceres/FindGlog.cmake
ADDED
|
@@ -0,0 +1,379 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
# Copyright 2015 Google Inc. All rights reserved.
|
| 3 |
+
# http://ceres-solver.org/
|
| 4 |
+
#
|
| 5 |
+
# Redistribution and use in source and binary forms, with or without
|
| 6 |
+
# modification, are permitted provided that the following conditions are met:
|
| 7 |
+
#
|
| 8 |
+
# * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
# this list of conditions and the following disclaimer.
|
| 10 |
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
# this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
# and/or other materials provided with the distribution.
|
| 13 |
+
# * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
# used to endorse or promote products derived from this software without
|
| 15 |
+
# specific prior written permission.
|
| 16 |
+
#
|
| 17 |
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
# POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
#
|
| 29 |
+
# Author: alexs.mac@gmail.com (Alex Stewart)
|
| 30 |
+
#
|
| 31 |
+
|
| 32 |
+
# FindGlog.cmake - Find Google glog logging library.
|
| 33 |
+
#
|
| 34 |
+
# This module defines the following variables:
|
| 35 |
+
#
|
| 36 |
+
# GLOG_FOUND: TRUE iff glog is found.
|
| 37 |
+
# GLOG_INCLUDE_DIRS: Include directories for glog.
|
| 38 |
+
# GLOG_LIBRARIES: Libraries required to link glog.
|
| 39 |
+
# FOUND_INSTALLED_GLOG_CMAKE_CONFIGURATION: True iff the version of glog found
|
| 40 |
+
# was built & installed / exported
|
| 41 |
+
# as a CMake package.
|
| 42 |
+
#
|
| 43 |
+
# The following variables control the behaviour of this module:
|
| 44 |
+
#
|
| 45 |
+
# GLOG_PREFER_EXPORTED_GLOG_CMAKE_CONFIGURATION: TRUE/FALSE, iff TRUE then
|
| 46 |
+
# then prefer using an exported CMake configuration
|
| 47 |
+
# generated by glog > 0.3.4 over searching for the
|
| 48 |
+
# glog components manually. Otherwise (FALSE)
|
| 49 |
+
# ignore any exported glog CMake configurations and
|
| 50 |
+
# always perform a manual search for the components.
|
| 51 |
+
# Default: TRUE iff user does not define this variable
|
| 52 |
+
# before we are called, and does NOT specify either
|
| 53 |
+
# GLOG_INCLUDE_DIR_HINTS or GLOG_LIBRARY_DIR_HINTS
|
| 54 |
+
# otherwise FALSE.
|
| 55 |
+
# GLOG_INCLUDE_DIR_HINTS: List of additional directories in which to
|
| 56 |
+
# search for glog includes, e.g: /timbuktu/include.
|
| 57 |
+
# GLOG_LIBRARY_DIR_HINTS: List of additional directories in which to
|
| 58 |
+
# search for glog libraries, e.g: /timbuktu/lib.
|
| 59 |
+
#
|
| 60 |
+
# The following variables are also defined by this module, but in line with
|
| 61 |
+
# CMake recommended FindPackage() module style should NOT be referenced directly
|
| 62 |
+
# by callers (use the plural variables detailed above instead). These variables
|
| 63 |
+
# do however affect the behaviour of the module via FIND_[PATH/LIBRARY]() which
|
| 64 |
+
# are NOT re-called (i.e. search for library is not repeated) if these variables
|
| 65 |
+
# are set with valid values _in the CMake cache_. This means that if these
|
| 66 |
+
# variables are set directly in the cache, either by the user in the CMake GUI,
|
| 67 |
+
# or by the user passing -DVAR=VALUE directives to CMake when called (which
|
| 68 |
+
# explicitly defines a cache variable), then they will be used verbatim,
|
| 69 |
+
# bypassing the HINTS variables and other hard-coded search locations.
|
| 70 |
+
#
|
| 71 |
+
# GLOG_INCLUDE_DIR: Include directory for glog, not including the
|
| 72 |
+
# include directory of any dependencies.
|
| 73 |
+
# GLOG_LIBRARY: glog library, not including the libraries of any
|
| 74 |
+
# dependencies.
|
| 75 |
+
|
| 76 |
+
# Reset CALLERS_CMAKE_FIND_LIBRARY_PREFIXES to its value when
|
| 77 |
+
# FindGlog was invoked.
|
| 78 |
+
macro(GLOG_RESET_FIND_LIBRARY_PREFIX)
|
| 79 |
+
if (MSVC AND CALLERS_CMAKE_FIND_LIBRARY_PREFIXES)
|
| 80 |
+
set(CMAKE_FIND_LIBRARY_PREFIXES "${CALLERS_CMAKE_FIND_LIBRARY_PREFIXES}")
|
| 81 |
+
endif()
|
| 82 |
+
endmacro(GLOG_RESET_FIND_LIBRARY_PREFIX)
|
| 83 |
+
|
| 84 |
+
# Called if we failed to find glog or any of it's required dependencies,
|
| 85 |
+
# unsets all public (designed to be used externally) variables and reports
|
| 86 |
+
# error message at priority depending upon [REQUIRED/QUIET/<NONE>] argument.
|
| 87 |
+
macro(GLOG_REPORT_NOT_FOUND REASON_MSG)
|
| 88 |
+
unset(GLOG_FOUND)
|
| 89 |
+
unset(GLOG_INCLUDE_DIRS)
|
| 90 |
+
unset(GLOG_LIBRARIES)
|
| 91 |
+
# Make results of search visible in the CMake GUI if glog has not
|
| 92 |
+
# been found so that user does not have to toggle to advanced view.
|
| 93 |
+
mark_as_advanced(CLEAR GLOG_INCLUDE_DIR
|
| 94 |
+
GLOG_LIBRARY)
|
| 95 |
+
|
| 96 |
+
glog_reset_find_library_prefix()
|
| 97 |
+
|
| 98 |
+
# Note <package>_FIND_[REQUIRED/QUIETLY] variables defined by FindPackage()
|
| 99 |
+
# use the camelcase library name, not uppercase.
|
| 100 |
+
if (Glog_FIND_QUIETLY)
|
| 101 |
+
message(STATUS "Failed to find glog - " ${REASON_MSG} ${ARGN})
|
| 102 |
+
elseif (Glog_FIND_REQUIRED)
|
| 103 |
+
message(FATAL_ERROR "Failed to find glog - " ${REASON_MSG} ${ARGN})
|
| 104 |
+
else()
|
| 105 |
+
# Neither QUIETLY nor REQUIRED, use no priority which emits a message
|
| 106 |
+
# but continues configuration and allows generation.
|
| 107 |
+
message("-- Failed to find glog - " ${REASON_MSG} ${ARGN})
|
| 108 |
+
endif ()
|
| 109 |
+
return()
|
| 110 |
+
endmacro(GLOG_REPORT_NOT_FOUND)
|
| 111 |
+
|
| 112 |
+
# glog_message([mode] "message text")
|
| 113 |
+
#
|
| 114 |
+
# Wraps the standard cmake 'message' command, but suppresses output
|
| 115 |
+
# if the QUIET flag was passed to the find_package(Glog ...) call.
|
| 116 |
+
function(GLOG_MESSAGE)
|
| 117 |
+
if (NOT Glog_FIND_QUIETLY)
|
| 118 |
+
message(${ARGN})
|
| 119 |
+
endif()
|
| 120 |
+
endfunction()
|
| 121 |
+
|
| 122 |
+
# Protect against any alternative find_package scripts for this library having
|
| 123 |
+
# been called previously (in a client project) which set GLOG_FOUND, but not
|
| 124 |
+
# the other variables we require / set here which could cause the search logic
|
| 125 |
+
# here to fail.
|
| 126 |
+
unset(GLOG_FOUND)
|
| 127 |
+
|
| 128 |
+
# -----------------------------------------------------------------
|
| 129 |
+
# By default, if the user has expressed no preference for using an exported
|
| 130 |
+
# glog CMake configuration over performing a search for the installed
|
| 131 |
+
# components, and has not specified any hints for the search locations, then
|
| 132 |
+
# prefer a glog exported configuration if available.
|
| 133 |
+
if (NOT DEFINED GLOG_PREFER_EXPORTED_GLOG_CMAKE_CONFIGURATION
|
| 134 |
+
AND NOT GLOG_INCLUDE_DIR_HINTS
|
| 135 |
+
AND NOT GLOG_LIBRARY_DIR_HINTS)
|
| 136 |
+
glog_message(STATUS "No preference for use of exported glog CMake "
|
| 137 |
+
"configuration set, and no hints for include/library directories provided. "
|
| 138 |
+
"Defaulting to preferring an installed/exported glog CMake configuration "
|
| 139 |
+
"if available.")
|
| 140 |
+
set(GLOG_PREFER_EXPORTED_GLOG_CMAKE_CONFIGURATION TRUE)
|
| 141 |
+
endif()
|
| 142 |
+
|
| 143 |
+
# On macOS, add the Homebrew prefix (with appropriate suffixes) to the
|
| 144 |
+
# respective HINTS directories (after any user-specified locations). This
|
| 145 |
+
# handles Homebrew installations into non-standard locations (not /usr/local).
|
| 146 |
+
# We do not use CMAKE_PREFIX_PATH for this as given the search ordering of
|
| 147 |
+
# find_xxx(), doing so would override any user-specified HINTS locations with
|
| 148 |
+
# the Homebrew version if it exists.
|
| 149 |
+
if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
| 150 |
+
find_program(HOMEBREW_EXECUTABLE brew)
|
| 151 |
+
mark_as_advanced(FORCE HOMEBREW_EXECUTABLE)
|
| 152 |
+
if (HOMEBREW_EXECUTABLE)
|
| 153 |
+
# Detected a Homebrew install, query for its install prefix.
|
| 154 |
+
execute_process(COMMAND ${HOMEBREW_EXECUTABLE} --prefix
|
| 155 |
+
OUTPUT_VARIABLE HOMEBREW_INSTALL_PREFIX
|
| 156 |
+
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
| 157 |
+
glog_message(STATUS "Detected Homebrew with install prefix: "
|
| 158 |
+
"${HOMEBREW_INSTALL_PREFIX}, adding to CMake search paths.")
|
| 159 |
+
list(APPEND GLOG_INCLUDE_DIR_HINTS "${HOMEBREW_INSTALL_PREFIX}/include")
|
| 160 |
+
list(APPEND GLOG_LIBRARY_DIR_HINTS "${HOMEBREW_INSTALL_PREFIX}/lib")
|
| 161 |
+
endif()
|
| 162 |
+
endif()
|
| 163 |
+
|
| 164 |
+
if (GLOG_PREFER_EXPORTED_GLOG_CMAKE_CONFIGURATION)
|
| 165 |
+
# Try to find an exported CMake configuration for glog, as generated by
|
| 166 |
+
# glog versions > 0.3.4
|
| 167 |
+
#
|
| 168 |
+
# We search twice, s/t we can invert the ordering of precedence used by
|
| 169 |
+
# find_package() for exported package build directories, and installed
|
| 170 |
+
# packages (found via CMAKE_SYSTEM_PREFIX_PATH), listed as items 6) and 7)
|
| 171 |
+
# respectively in [1].
|
| 172 |
+
#
|
| 173 |
+
# By default, exported build directories are (in theory) detected first, and
|
| 174 |
+
# this is usually the case on Windows. However, on OS X & Linux, the install
|
| 175 |
+
# path (/usr/local) is typically present in the PATH environment variable
|
| 176 |
+
# which is checked in item 4) in [1] (i.e. before both of the above, unless
|
| 177 |
+
# NO_SYSTEM_ENVIRONMENT_PATH is passed). As such on those OSs installed
|
| 178 |
+
# packages are usually detected in preference to exported package build
|
| 179 |
+
# directories.
|
| 180 |
+
#
|
| 181 |
+
# To ensure a more consistent response across all OSs, and as users usually
|
| 182 |
+
# want to prefer an installed version of a package over a locally built one
|
| 183 |
+
# where both exist (esp. as the exported build directory might be removed
|
| 184 |
+
# after installation), we first search with NO_CMAKE_PACKAGE_REGISTRY which
|
| 185 |
+
# means any build directories exported by the user are ignored, and thus
|
| 186 |
+
# installed directories are preferred. If this fails to find the package
|
| 187 |
+
# we then research again, but without NO_CMAKE_PACKAGE_REGISTRY, so any
|
| 188 |
+
# exported build directories will now be detected.
|
| 189 |
+
#
|
| 190 |
+
# To prevent confusion on Windows, we also pass NO_CMAKE_BUILDS_PATH (which
|
| 191 |
+
# is item 5) in [1]), to not preferentially use projects that were built
|
| 192 |
+
# recently with the CMake GUI to ensure that we always prefer an installed
|
| 193 |
+
# version if available.
|
| 194 |
+
#
|
| 195 |
+
# NOTE: We use the NAMES option as glog erroneously uses 'google-glog' as its
|
| 196 |
+
# project name when built with CMake, but exports itself as just 'glog'.
|
| 197 |
+
# On Linux/OS X this does not break detection as the project name is
|
| 198 |
+
# not used as part of the install path for the CMake package files,
|
| 199 |
+
# e.g. /usr/local/lib/cmake/glog, where the <glog> suffix is hardcoded
|
| 200 |
+
# in glog's CMakeLists. However, on Windows the project name *is*
|
| 201 |
+
# part of the install prefix: C:/Program Files/google-glog/[include,lib].
|
| 202 |
+
# However, by default CMake checks:
|
| 203 |
+
# C:/Program Files/<FIND_PACKAGE_ARGUMENT_NAME='glog'> which does not
|
| 204 |
+
# exist and thus detection fails. Thus we use the NAMES to force the
|
| 205 |
+
# search to use both google-glog & glog.
|
| 206 |
+
#
|
| 207 |
+
# [1] http://www.cmake.org/cmake/help/v2.8.11/cmake.html#command:find_package
|
| 208 |
+
find_package(glog QUIET
|
| 209 |
+
NAMES google-glog glog
|
| 210 |
+
HINTS ${glog_DIR} ${HOMEBREW_INSTALL_PREFIX}
|
| 211 |
+
NO_MODULE
|
| 212 |
+
NO_CMAKE_PACKAGE_REGISTRY
|
| 213 |
+
NO_CMAKE_BUILDS_PATH)
|
| 214 |
+
if (glog_FOUND)
|
| 215 |
+
glog_message(STATUS "Found installed version of glog: ${glog_DIR}")
|
| 216 |
+
else()
|
| 217 |
+
# Failed to find an installed version of glog, repeat search allowing
|
| 218 |
+
# exported build directories.
|
| 219 |
+
glog_message(STATUS "Failed to find installed glog CMake configuration, "
|
| 220 |
+
"searching for glog build directories exported with CMake.")
|
| 221 |
+
# Again pass NO_CMAKE_BUILDS_PATH, as we know that glog is exported and
|
| 222 |
+
# do not want to treat projects built with the CMake GUI preferentially.
|
| 223 |
+
find_package(glog QUIET
|
| 224 |
+
NAMES google-glog glog
|
| 225 |
+
NO_MODULE
|
| 226 |
+
NO_CMAKE_BUILDS_PATH)
|
| 227 |
+
if (glog_FOUND)
|
| 228 |
+
glog_message(STATUS "Found exported glog build directory: ${glog_DIR}")
|
| 229 |
+
endif(glog_FOUND)
|
| 230 |
+
endif(glog_FOUND)
|
| 231 |
+
|
| 232 |
+
set(FOUND_INSTALLED_GLOG_CMAKE_CONFIGURATION ${glog_FOUND})
|
| 233 |
+
|
| 234 |
+
if (FOUND_INSTALLED_GLOG_CMAKE_CONFIGURATION)
|
| 235 |
+
glog_message(STATUS "Detected glog version: ${glog_VERSION}")
|
| 236 |
+
set(GLOG_FOUND ${glog_FOUND})
|
| 237 |
+
# glog wraps the include directories into the exported glog::glog target.
|
| 238 |
+
set(GLOG_INCLUDE_DIR "")
|
| 239 |
+
set(GLOG_LIBRARY glog::glog)
|
| 240 |
+
else (FOUND_INSTALLED_GLOG_CMAKE_CONFIGURATION)
|
| 241 |
+
glog_message(STATUS "Failed to find an installed/exported CMake "
|
| 242 |
+
"configuration for glog, will perform search for installed glog "
|
| 243 |
+
"components.")
|
| 244 |
+
endif (FOUND_INSTALLED_GLOG_CMAKE_CONFIGURATION)
|
| 245 |
+
endif(GLOG_PREFER_EXPORTED_GLOG_CMAKE_CONFIGURATION)
|
| 246 |
+
|
| 247 |
+
if (NOT GLOG_FOUND)
|
| 248 |
+
# Either failed to find an exported glog CMake configuration, or user
|
| 249 |
+
# told us not to use one. Perform a manual search for all glog components.
|
| 250 |
+
|
| 251 |
+
# Handle possible presence of lib prefix for libraries on MSVC, see
|
| 252 |
+
# also GLOG_RESET_FIND_LIBRARY_PREFIX().
|
| 253 |
+
if (MSVC)
|
| 254 |
+
# Preserve the caller's original values for CMAKE_FIND_LIBRARY_PREFIXES
|
| 255 |
+
# s/t we can set it back before returning.
|
| 256 |
+
set(CALLERS_CMAKE_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}")
|
| 257 |
+
# The empty string in this list is important, it represents the case when
|
| 258 |
+
# the libraries have no prefix (shared libraries / DLLs).
|
| 259 |
+
set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "" "${CMAKE_FIND_LIBRARY_PREFIXES}")
|
| 260 |
+
endif (MSVC)
|
| 261 |
+
|
| 262 |
+
# Search user-installed locations first, so that we prefer user installs
|
| 263 |
+
# to system installs where both exist.
|
| 264 |
+
list(APPEND GLOG_CHECK_INCLUDE_DIRS
|
| 265 |
+
/usr/local/include
|
| 266 |
+
/usr/local/homebrew/include # Mac OS X
|
| 267 |
+
/opt/local/var/macports/software # Mac OS X.
|
| 268 |
+
/opt/local/include
|
| 269 |
+
/usr/include)
|
| 270 |
+
# Windows (for C:/Program Files prefix).
|
| 271 |
+
list(APPEND GLOG_CHECK_PATH_SUFFIXES
|
| 272 |
+
glog/include
|
| 273 |
+
glog/Include
|
| 274 |
+
Glog/include
|
| 275 |
+
Glog/Include
|
| 276 |
+
google-glog/include # CMake installs with project name prefix.
|
| 277 |
+
google-glog/Include)
|
| 278 |
+
|
| 279 |
+
list(APPEND GLOG_CHECK_LIBRARY_DIRS
|
| 280 |
+
/usr/local/lib
|
| 281 |
+
/usr/local/homebrew/lib # Mac OS X.
|
| 282 |
+
/opt/local/lib
|
| 283 |
+
/usr/lib)
|
| 284 |
+
# Windows (for C:/Program Files prefix).
|
| 285 |
+
list(APPEND GLOG_CHECK_LIBRARY_SUFFIXES
|
| 286 |
+
glog/lib
|
| 287 |
+
glog/Lib
|
| 288 |
+
Glog/lib
|
| 289 |
+
Glog/Lib
|
| 290 |
+
google-glog/lib # CMake installs with project name prefix.
|
| 291 |
+
google-glog/Lib)
|
| 292 |
+
|
| 293 |
+
# Search supplied hint directories first if supplied.
|
| 294 |
+
find_path(GLOG_INCLUDE_DIR
|
| 295 |
+
NAMES glog/logging.h
|
| 296 |
+
HINTS ${GLOG_INCLUDE_DIR_HINTS}
|
| 297 |
+
PATHS ${GLOG_CHECK_INCLUDE_DIRS}
|
| 298 |
+
PATH_SUFFIXES ${GLOG_CHECK_PATH_SUFFIXES})
|
| 299 |
+
if (NOT GLOG_INCLUDE_DIR OR
|
| 300 |
+
NOT EXISTS ${GLOG_INCLUDE_DIR})
|
| 301 |
+
glog_report_not_found(
|
| 302 |
+
"Could not find glog include directory, set GLOG_INCLUDE_DIR "
|
| 303 |
+
"to directory containing glog/logging.h")
|
| 304 |
+
endif (NOT GLOG_INCLUDE_DIR OR
|
| 305 |
+
NOT EXISTS ${GLOG_INCLUDE_DIR})
|
| 306 |
+
|
| 307 |
+
find_library(GLOG_LIBRARY NAMES glog
|
| 308 |
+
HINTS ${GLOG_LIBRARY_DIR_HINTS}
|
| 309 |
+
PATHS ${GLOG_CHECK_LIBRARY_DIRS}
|
| 310 |
+
PATH_SUFFIXES ${GLOG_CHECK_LIBRARY_SUFFIXES})
|
| 311 |
+
if (NOT GLOG_LIBRARY OR
|
| 312 |
+
NOT EXISTS ${GLOG_LIBRARY})
|
| 313 |
+
glog_report_not_found(
|
| 314 |
+
"Could not find glog library, set GLOG_LIBRARY "
|
| 315 |
+
"to full path to libglog.")
|
| 316 |
+
endif (NOT GLOG_LIBRARY OR
|
| 317 |
+
NOT EXISTS ${GLOG_LIBRARY})
|
| 318 |
+
|
| 319 |
+
# Mark internally as found, then verify. GLOG_REPORT_NOT_FOUND() unsets
|
| 320 |
+
# if called.
|
| 321 |
+
set(GLOG_FOUND TRUE)
|
| 322 |
+
|
| 323 |
+
# Glog does not seem to provide any record of the version in its
|
| 324 |
+
# source tree, thus cannot extract version.
|
| 325 |
+
|
| 326 |
+
# Catch case when caller has set GLOG_INCLUDE_DIR in the cache / GUI and
|
| 327 |
+
# thus FIND_[PATH/LIBRARY] are not called, but specified locations are
|
| 328 |
+
# invalid, otherwise we would report the library as found.
|
| 329 |
+
if (GLOG_INCLUDE_DIR AND
|
| 330 |
+
NOT EXISTS ${GLOG_INCLUDE_DIR}/glog/logging.h)
|
| 331 |
+
glog_report_not_found(
|
| 332 |
+
"Caller defined GLOG_INCLUDE_DIR:"
|
| 333 |
+
" ${GLOG_INCLUDE_DIR} does not contain glog/logging.h header.")
|
| 334 |
+
endif (GLOG_INCLUDE_DIR AND
|
| 335 |
+
NOT EXISTS ${GLOG_INCLUDE_DIR}/glog/logging.h)
|
| 336 |
+
# TODO: This regex for glog library is pretty primitive, we use lowercase
|
| 337 |
+
# for comparison to handle Windows using CamelCase library names, could
|
| 338 |
+
# this check be better?
|
| 339 |
+
string(TOLOWER "${GLOG_LIBRARY}" LOWERCASE_GLOG_LIBRARY)
|
| 340 |
+
if (GLOG_LIBRARY AND
|
| 341 |
+
NOT "${LOWERCASE_GLOG_LIBRARY}" MATCHES ".*glog[^/]*")
|
| 342 |
+
glog_report_not_found(
|
| 343 |
+
"Caller defined GLOG_LIBRARY: "
|
| 344 |
+
"${GLOG_LIBRARY} does not match glog.")
|
| 345 |
+
endif (GLOG_LIBRARY AND
|
| 346 |
+
NOT "${LOWERCASE_GLOG_LIBRARY}" MATCHES ".*glog[^/]*")
|
| 347 |
+
|
| 348 |
+
glog_reset_find_library_prefix()
|
| 349 |
+
|
| 350 |
+
endif(NOT GLOG_FOUND)
|
| 351 |
+
|
| 352 |
+
# Set standard CMake FindPackage variables if found.
|
| 353 |
+
if (GLOG_FOUND)
|
| 354 |
+
set(GLOG_INCLUDE_DIRS ${GLOG_INCLUDE_DIR})
|
| 355 |
+
set(GLOG_LIBRARIES ${GLOG_LIBRARY})
|
| 356 |
+
endif (GLOG_FOUND)
|
| 357 |
+
|
| 358 |
+
# If we are using an exported CMake glog target, the include directories are
|
| 359 |
+
# wrapped into the target itself, and do not have to be (and are not)
|
| 360 |
+
# separately specified. In which case, we should not add GLOG_INCLUDE_DIRS
|
| 361 |
+
# to the list of required variables in order that glog be reported as found.
|
| 362 |
+
if (FOUND_INSTALLED_GLOG_CMAKE_CONFIGURATION)
|
| 363 |
+
set(GLOG_REQUIRED_VARIABLES GLOG_LIBRARIES)
|
| 364 |
+
else()
|
| 365 |
+
set(GLOG_REQUIRED_VARIABLES GLOG_INCLUDE_DIRS GLOG_LIBRARIES)
|
| 366 |
+
endif()
|
| 367 |
+
|
| 368 |
+
# Handle REQUIRED / QUIET optional arguments.
|
| 369 |
+
include(FindPackageHandleStandardArgs)
|
| 370 |
+
find_package_handle_standard_args(Glog DEFAULT_MSG
|
| 371 |
+
${GLOG_REQUIRED_VARIABLES})
|
| 372 |
+
|
| 373 |
+
# Only mark internal variables as advanced if we found glog, otherwise
|
| 374 |
+
# leave them visible in the standard GUI for the user to set manually.
|
| 375 |
+
if (GLOG_FOUND)
|
| 376 |
+
mark_as_advanced(FORCE GLOG_INCLUDE_DIR
|
| 377 |
+
GLOG_LIBRARY
|
| 378 |
+
glog_DIR) # Autogenerated by find_package(glog)
|
| 379 |
+
endif (GLOG_FOUND)
|
cmake/Ceres/FindMETIS.cmake
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#
|
| 2 |
+
# Copyright (c) 2022 Sergiu Deitsch
|
| 3 |
+
#
|
| 4 |
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 5 |
+
# of this software and associated documentation files (the "Software"), to deal
|
| 6 |
+
# in the Software without restriction, including without limitation the rights
|
| 7 |
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 8 |
+
# copies of the Software, and to permit persons to whom the Software is
|
| 9 |
+
# furnished to do so, subject to the following conditions:
|
| 10 |
+
#
|
| 11 |
+
# The above copyright notice and this permission notice shall be included in all
|
| 12 |
+
# copies or substantial portions of the Software.
|
| 13 |
+
#
|
| 14 |
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 15 |
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 16 |
+
# FITNESS FOR A PARTMETISLAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 17 |
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 18 |
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 19 |
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 20 |
+
# SOFTWARE.
|
| 21 |
+
#
|
| 22 |
+
#[=======================================================================[.rst:
|
| 23 |
+
Module for locating METIS
|
| 24 |
+
=========================
|
| 25 |
+
|
| 26 |
+
Read-only variables:
|
| 27 |
+
|
| 28 |
+
``METIS_FOUND``
|
| 29 |
+
Indicates whether the library has been found.
|
| 30 |
+
|
| 31 |
+
``METIS_VERSION``
|
| 32 |
+
Indicates library version.
|
| 33 |
+
|
| 34 |
+
Targets
|
| 35 |
+
-------
|
| 36 |
+
|
| 37 |
+
``METIS::METIS``
|
| 38 |
+
Specifies targets that should be passed to target_link_libararies.
|
| 39 |
+
]=======================================================================]
|
| 40 |
+
|
| 41 |
+
include (FindPackageHandleStandardArgs)
|
| 42 |
+
|
| 43 |
+
find_path (METIS_INCLUDE_DIR NAMES metis.h
|
| 44 |
+
PATH_SUFFIXES include
|
| 45 |
+
DOC "METIS include directory")
|
| 46 |
+
find_library (METIS_LIBRARY_DEBUG NAMES metis
|
| 47 |
+
PATH_SUFFIXES Debug
|
| 48 |
+
DOC "METIS debug library")
|
| 49 |
+
find_library (METIS_LIBRARY_RELEASE NAMES metis
|
| 50 |
+
PATH_SUFFIXES Release
|
| 51 |
+
DOC "METIS release library")
|
| 52 |
+
|
| 53 |
+
if (METIS_LIBRARY_RELEASE)
|
| 54 |
+
if (METIS_LIBRARY_DEBUG)
|
| 55 |
+
set (METIS_LIBRARY debug ${METIS_LIBRARY_DEBUG} optimized
|
| 56 |
+
${METIS_LIBRARY_RELEASE} CACHE STRING "METIS library")
|
| 57 |
+
else (METIS_LIBRARY_DEBUG)
|
| 58 |
+
set (METIS_LIBRARY ${METIS_LIBRARY_RELEASE} CACHE FILEPATH "METIS library")
|
| 59 |
+
endif (METIS_LIBRARY_DEBUG)
|
| 60 |
+
elseif (METIS_LIBRARY_DEBUG)
|
| 61 |
+
set (METIS_LIBRARY ${METIS_LIBRARY_DEBUG} CACHE FILEPATH "METIS library")
|
| 62 |
+
endif (METIS_LIBRARY_RELEASE)
|
| 63 |
+
|
| 64 |
+
set (_METIS_VERSION_HEADER ${METIS_INCLUDE_DIR}/metis.h)
|
| 65 |
+
|
| 66 |
+
if (EXISTS ${_METIS_VERSION_HEADER})
|
| 67 |
+
file (READ ${_METIS_VERSION_HEADER} _METIS_VERSION_CONTENTS)
|
| 68 |
+
|
| 69 |
+
string (REGEX REPLACE ".*#define METIS_VER_MAJOR[ \t]+([0-9]+).*" "\\1"
|
| 70 |
+
METIS_VERSION_MAJOR "${_METIS_VERSION_CONTENTS}")
|
| 71 |
+
string (REGEX REPLACE ".*#define METIS_VER_MINOR[ \t]+([0-9]+).*" "\\1"
|
| 72 |
+
METIS_VERSION_MINOR "${_METIS_VERSION_CONTENTS}")
|
| 73 |
+
string (REGEX REPLACE ".*#define METIS_VER_SUBMINOR[ \t]+([0-9]+).*" "\\1"
|
| 74 |
+
METIS_VERSION_PATCH "${_METIS_VERSION_CONTENTS}")
|
| 75 |
+
|
| 76 |
+
set (METIS_VERSION
|
| 77 |
+
${METIS_VERSION_MAJOR}.${METIS_VERSION_MINOR}.${METIS_VERSION_PATCH})
|
| 78 |
+
set (METIS_VERSION_COMPONENTS 3)
|
| 79 |
+
endif (EXISTS ${_METIS_VERSION_HEADER})
|
| 80 |
+
|
| 81 |
+
mark_as_advanced (METIS_INCLUDE_DIR METIS_LIBRARY_DEBUG METIS_LIBRARY_RELEASE
|
| 82 |
+
METIS_LIBRARY)
|
| 83 |
+
|
| 84 |
+
if (NOT TARGET METIS::METIS)
|
| 85 |
+
if (METIS_INCLUDE_DIR OR METIS_LIBRARY)
|
| 86 |
+
add_library (METIS::METIS IMPORTED UNKNOWN)
|
| 87 |
+
endif (METIS_INCLUDE_DIR OR METIS_LIBRARY)
|
| 88 |
+
endif (NOT TARGET METIS::METIS)
|
| 89 |
+
|
| 90 |
+
if (METIS_INCLUDE_DIR)
|
| 91 |
+
set_property (TARGET METIS::METIS PROPERTY INTERFACE_INCLUDE_DIRECTORIES
|
| 92 |
+
${METIS_INCLUDE_DIR})
|
| 93 |
+
endif (METIS_INCLUDE_DIR)
|
| 94 |
+
|
| 95 |
+
if (METIS_LIBRARY_RELEASE)
|
| 96 |
+
set_property (TARGET METIS::METIS PROPERTY IMPORTED_LOCATION_RELEASE
|
| 97 |
+
${METIS_LIBRARY_RELEASE})
|
| 98 |
+
set_property (TARGET METIS::METIS APPEND PROPERTY IMPORTED_CONFIGURATIONS
|
| 99 |
+
RELEASE)
|
| 100 |
+
endif (METIS_LIBRARY_RELEASE)
|
| 101 |
+
|
| 102 |
+
if (METIS_LIBRARY_DEBUG)
|
| 103 |
+
set_property (TARGET METIS::METIS PROPERTY IMPORTED_LOCATION_DEBUG
|
| 104 |
+
${METIS_LIBRARY_DEBUG})
|
| 105 |
+
set_property (TARGET METIS::METIS APPEND PROPERTY IMPORTED_CONFIGURATIONS
|
| 106 |
+
DEBUG)
|
| 107 |
+
endif (METIS_LIBRARY_DEBUG)
|
| 108 |
+
|
| 109 |
+
find_package_handle_standard_args (METIS REQUIRED_VARS
|
| 110 |
+
METIS_INCLUDE_DIR METIS_LIBRARY VERSION_VAR METIS_VERSION)
|
cmake/Ceres/FindSuiteSparse.cmake
ADDED
|
@@ -0,0 +1,488 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
# Copyright 2022 Google Inc. All rights reserved.
|
| 3 |
+
# http://ceres-solver.org/
|
| 4 |
+
#
|
| 5 |
+
# Redistribution and use in source and binary forms, with or without
|
| 6 |
+
# modification, are permitted provided that the following conditions are met:
|
| 7 |
+
#
|
| 8 |
+
# * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
# this list of conditions and the following disclaimer.
|
| 10 |
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
# this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
# and/or other materials provided with the distribution.
|
| 13 |
+
# * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
# used to endorse or promote products derived from this software without
|
| 15 |
+
# specific prior written permission.
|
| 16 |
+
#
|
| 17 |
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
# POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
#
|
| 29 |
+
# Author: alexs.mac@gmail.com (Alex Stewart)
|
| 30 |
+
#
|
| 31 |
+
|
| 32 |
+
#[=======================================================================[.rst:
|
| 33 |
+
FindSuiteSparse
|
| 34 |
+
===============
|
| 35 |
+
|
| 36 |
+
Module for locating SuiteSparse libraries and its dependencies.
|
| 37 |
+
|
| 38 |
+
This module defines the following variables:
|
| 39 |
+
|
| 40 |
+
``SuiteSparse_FOUND``
|
| 41 |
+
``TRUE`` iff SuiteSparse and all dependencies have been found.
|
| 42 |
+
|
| 43 |
+
``SuiteSparse_VERSION``
|
| 44 |
+
Extracted from ``SuiteSparse_config.h`` (>= v4).
|
| 45 |
+
|
| 46 |
+
``SuiteSparse_VERSION_MAJOR``
|
| 47 |
+
Equal to 4 if ``SuiteSparse_VERSION`` = 4.2.1
|
| 48 |
+
|
| 49 |
+
``SuiteSparse_VERSION_MINOR``
|
| 50 |
+
Equal to 2 if ``SuiteSparse_VERSION`` = 4.2.1
|
| 51 |
+
|
| 52 |
+
``SuiteSparse_VERSION_PATCH``
|
| 53 |
+
Equal to 1 if ``SuiteSparse_VERSION`` = 4.2.1
|
| 54 |
+
|
| 55 |
+
The following variables control the behaviour of this module:
|
| 56 |
+
|
| 57 |
+
``SuiteSparse_NO_CMAKE``
|
| 58 |
+
Do not attempt to use the native SuiteSparse CMake package configuration.
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
Targets
|
| 62 |
+
-------
|
| 63 |
+
|
| 64 |
+
The following targets define the SuiteSparse components searched for.
|
| 65 |
+
|
| 66 |
+
``SuiteSparse::AMD``
|
| 67 |
+
Symmetric Approximate Minimum Degree (AMD)
|
| 68 |
+
|
| 69 |
+
``SuiteSparse::CAMD``
|
| 70 |
+
Constrained Approximate Minimum Degree (CAMD)
|
| 71 |
+
|
| 72 |
+
``SuiteSparse::COLAMD``
|
| 73 |
+
Column Approximate Minimum Degree (COLAMD)
|
| 74 |
+
|
| 75 |
+
``SuiteSparse::CCOLAMD``
|
| 76 |
+
Constrained Column Approximate Minimum Degree (CCOLAMD)
|
| 77 |
+
|
| 78 |
+
``SuiteSparse::CHOLMOD``
|
| 79 |
+
Sparse Supernodal Cholesky Factorization and Update/Downdate (CHOLMOD)
|
| 80 |
+
|
| 81 |
+
``SuiteSparse::SPQR``
|
| 82 |
+
Multifrontal Sparse QR (SuiteSparseQR)
|
| 83 |
+
|
| 84 |
+
``SuiteSparse::Config``
|
| 85 |
+
Common configuration for all but CSparse (SuiteSparse version >= 4).
|
| 86 |
+
|
| 87 |
+
Optional SuiteSparse dependencies:
|
| 88 |
+
|
| 89 |
+
``METIS::METIS``
|
| 90 |
+
Serial Graph Partitioning and Fill-reducing Matrix Ordering (METIS)
|
| 91 |
+
]=======================================================================]
|
| 92 |
+
|
| 93 |
+
if (NOT SuiteSparse_NO_CMAKE)
|
| 94 |
+
find_package (SuiteSparse NO_MODULE QUIET)
|
| 95 |
+
endif (NOT SuiteSparse_NO_CMAKE)
|
| 96 |
+
|
| 97 |
+
if (SuiteSparse_FOUND)
|
| 98 |
+
return ()
|
| 99 |
+
endif (SuiteSparse_FOUND)
|
| 100 |
+
|
| 101 |
+
# Push CMP0057 to enable support for IN_LIST, when cmake_minimum_required is
|
| 102 |
+
# set to <3.3.
|
| 103 |
+
cmake_policy (PUSH)
|
| 104 |
+
cmake_policy (SET CMP0057 NEW)
|
| 105 |
+
|
| 106 |
+
if (NOT SuiteSparse_FIND_COMPONENTS)
|
| 107 |
+
set (SuiteSparse_FIND_COMPONENTS
|
| 108 |
+
AMD
|
| 109 |
+
CAMD
|
| 110 |
+
CCOLAMD
|
| 111 |
+
CHOLMOD
|
| 112 |
+
COLAMD
|
| 113 |
+
SPQR
|
| 114 |
+
)
|
| 115 |
+
|
| 116 |
+
foreach (component IN LISTS SuiteSparse_FIND_COMPONENTS)
|
| 117 |
+
set (SuiteSparse_FIND_REQUIRED_${component} TRUE)
|
| 118 |
+
endforeach (component IN LISTS SuiteSparse_FIND_COMPONENTS)
|
| 119 |
+
endif (NOT SuiteSparse_FIND_COMPONENTS)
|
| 120 |
+
|
| 121 |
+
# Assume SuiteSparse was found and set it to false only if third-party
|
| 122 |
+
# dependencies could not be located. SuiteSparse components are handled by
|
| 123 |
+
# FindPackageHandleStandardArgs HANDLE_COMPONENTS option.
|
| 124 |
+
set (SuiteSparse_FOUND TRUE)
|
| 125 |
+
|
| 126 |
+
include (CheckLibraryExists)
|
| 127 |
+
|
| 128 |
+
# Config is a base component and thus always required
|
| 129 |
+
set (SuiteSparse_IMPLICIT_COMPONENTS Config)
|
| 130 |
+
|
| 131 |
+
# CHOLMOD depends on AMD, CAMD, CCOLAMD, and COLAMD.
|
| 132 |
+
if (CHOLMOD IN_LIST SuiteSparse_FIND_COMPONENTS)
|
| 133 |
+
list (APPEND SuiteSparse_IMPLICIT_COMPONENTS AMD CAMD CCOLAMD COLAMD)
|
| 134 |
+
endif (CHOLMOD IN_LIST SuiteSparse_FIND_COMPONENTS)
|
| 135 |
+
|
| 136 |
+
# SPQR depends on CHOLMOD.
|
| 137 |
+
if (SPQR IN_LIST SuiteSparse_FIND_COMPONENTS)
|
| 138 |
+
list (APPEND SuiteSparse_IMPLICIT_COMPONENTS CHOLMOD)
|
| 139 |
+
endif (SPQR IN_LIST SuiteSparse_FIND_COMPONENTS)
|
| 140 |
+
|
| 141 |
+
# Implicit components are always required
|
| 142 |
+
foreach (component IN LISTS SuiteSparse_IMPLICIT_COMPONENTS)
|
| 143 |
+
set (SuiteSparse_FIND_REQUIRED_${component} TRUE)
|
| 144 |
+
endforeach (component IN LISTS SuiteSparse_IMPLICIT_COMPONENTS)
|
| 145 |
+
|
| 146 |
+
list (APPEND SuiteSparse_FIND_COMPONENTS ${SuiteSparse_IMPLICIT_COMPONENTS})
|
| 147 |
+
|
| 148 |
+
# Do not list components multiple times.
|
| 149 |
+
list (REMOVE_DUPLICATES SuiteSparse_FIND_COMPONENTS)
|
| 150 |
+
|
| 151 |
+
# Reset CALLERS_CMAKE_FIND_LIBRARY_PREFIXES to its value when
|
| 152 |
+
# FindSuiteSparse was invoked.
|
| 153 |
+
macro(SuiteSparse_RESET_FIND_LIBRARY_PREFIX)
|
| 154 |
+
if (MSVC)
|
| 155 |
+
set(CMAKE_FIND_LIBRARY_PREFIXES "${CALLERS_CMAKE_FIND_LIBRARY_PREFIXES}")
|
| 156 |
+
endif (MSVC)
|
| 157 |
+
endmacro(SuiteSparse_RESET_FIND_LIBRARY_PREFIX)
|
| 158 |
+
|
| 159 |
+
# Called if we failed to find SuiteSparse or any of it's required dependencies,
|
| 160 |
+
# unsets all public (designed to be used externally) variables and reports
|
| 161 |
+
# error message at priority depending upon [REQUIRED/QUIET/<NONE>] argument.
|
| 162 |
+
macro(SuiteSparse_REPORT_NOT_FOUND REASON_MSG)
|
| 163 |
+
# Will be set to FALSE by find_package_handle_standard_args
|
| 164 |
+
unset (SuiteSparse_FOUND)
|
| 165 |
+
|
| 166 |
+
# Do NOT unset SuiteSparse_REQUIRED_VARS here, as it is used by
|
| 167 |
+
# FindPackageHandleStandardArgs() to generate the automatic error message on
|
| 168 |
+
# failure which highlights which components are missing.
|
| 169 |
+
|
| 170 |
+
suitesparse_reset_find_library_prefix()
|
| 171 |
+
|
| 172 |
+
# Note <package>_FIND_[REQUIRED/QUIETLY] variables defined by FindPackage()
|
| 173 |
+
# use the camelcase library name, not uppercase.
|
| 174 |
+
if (SuiteSparse_FIND_QUIETLY)
|
| 175 |
+
message(STATUS "Failed to find SuiteSparse - " ${REASON_MSG} ${ARGN})
|
| 176 |
+
elseif (SuiteSparse_FIND_REQUIRED)
|
| 177 |
+
message(FATAL_ERROR "Failed to find SuiteSparse - " ${REASON_MSG} ${ARGN})
|
| 178 |
+
else()
|
| 179 |
+
# Neither QUIETLY nor REQUIRED, use no priority which emits a message
|
| 180 |
+
# but continues configuration and allows generation.
|
| 181 |
+
message("-- Failed to find SuiteSparse - " ${REASON_MSG} ${ARGN})
|
| 182 |
+
endif (SuiteSparse_FIND_QUIETLY)
|
| 183 |
+
|
| 184 |
+
# Do not call return(), s/t we keep processing if not called with REQUIRED
|
| 185 |
+
# and report all missing components, rather than bailing after failing to find
|
| 186 |
+
# the first.
|
| 187 |
+
endmacro(SuiteSparse_REPORT_NOT_FOUND)
|
| 188 |
+
|
| 189 |
+
# Handle possible presence of lib prefix for libraries on MSVC, see
|
| 190 |
+
# also SuiteSparse_RESET_FIND_LIBRARY_PREFIX().
|
| 191 |
+
if (MSVC)
|
| 192 |
+
# Preserve the caller's original values for CMAKE_FIND_LIBRARY_PREFIXES
|
| 193 |
+
# s/t we can set it back before returning.
|
| 194 |
+
set(CALLERS_CMAKE_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}")
|
| 195 |
+
# The empty string in this list is important, it represents the case when
|
| 196 |
+
# the libraries have no prefix (shared libraries / DLLs).
|
| 197 |
+
set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "" "${CMAKE_FIND_LIBRARY_PREFIXES}")
|
| 198 |
+
endif (MSVC)
|
| 199 |
+
|
| 200 |
+
# Additional suffixes to try appending to each search path.
|
| 201 |
+
list(APPEND SuiteSparse_CHECK_PATH_SUFFIXES
|
| 202 |
+
suitesparse) # Windows/Ubuntu
|
| 203 |
+
|
| 204 |
+
# Wrappers to find_path/library that pass the SuiteSparse search hints/paths.
|
| 205 |
+
#
|
| 206 |
+
# suitesparse_find_component(<component> [FILES name1 [name2 ...]]
|
| 207 |
+
# [LIBRARIES name1 [name2 ...]])
|
| 208 |
+
macro(suitesparse_find_component COMPONENT)
|
| 209 |
+
include(CMakeParseArguments)
|
| 210 |
+
set(MULTI_VALUE_ARGS FILES LIBRARIES)
|
| 211 |
+
cmake_parse_arguments(SuiteSparse_FIND_COMPONENT_${COMPONENT}
|
| 212 |
+
"" "" "${MULTI_VALUE_ARGS}" ${ARGN})
|
| 213 |
+
|
| 214 |
+
set(SuiteSparse_${COMPONENT}_FOUND TRUE)
|
| 215 |
+
if (SuiteSparse_FIND_COMPONENT_${COMPONENT}_FILES)
|
| 216 |
+
find_path(SuiteSparse_${COMPONENT}_INCLUDE_DIR
|
| 217 |
+
NAMES ${SuiteSparse_FIND_COMPONENT_${COMPONENT}_FILES}
|
| 218 |
+
PATH_SUFFIXES ${SuiteSparse_CHECK_PATH_SUFFIXES})
|
| 219 |
+
if (SuiteSparse_${COMPONENT}_INCLUDE_DIR)
|
| 220 |
+
message(STATUS "Found ${COMPONENT} headers in: "
|
| 221 |
+
"${SuiteSparse_${COMPONENT}_INCLUDE_DIR}")
|
| 222 |
+
mark_as_advanced(SuiteSparse_${COMPONENT}_INCLUDE_DIR)
|
| 223 |
+
else()
|
| 224 |
+
# Specified headers not found.
|
| 225 |
+
set(SuiteSparse_${COMPONENT}_FOUND FALSE)
|
| 226 |
+
if (SuiteSparse_FIND_REQUIRED_${COMPONENT})
|
| 227 |
+
suitesparse_report_not_found(
|
| 228 |
+
"Did not find ${COMPONENT} header (required SuiteSparse component).")
|
| 229 |
+
else()
|
| 230 |
+
message(STATUS "Did not find ${COMPONENT} header (optional "
|
| 231 |
+
"SuiteSparse component).")
|
| 232 |
+
# Hide optional vars from CMake GUI even if not found.
|
| 233 |
+
mark_as_advanced(SuiteSparse_${COMPONENT}_INCLUDE_DIR)
|
| 234 |
+
endif()
|
| 235 |
+
endif()
|
| 236 |
+
endif()
|
| 237 |
+
|
| 238 |
+
if (SuiteSparse_FIND_COMPONENT_${COMPONENT}_LIBRARIES)
|
| 239 |
+
find_library(SuiteSparse_${COMPONENT}_LIBRARY
|
| 240 |
+
NAMES ${SuiteSparse_FIND_COMPONENT_${COMPONENT}_LIBRARIES}
|
| 241 |
+
PATH_SUFFIXES ${SuiteSparse_CHECK_PATH_SUFFIXES})
|
| 242 |
+
if (SuiteSparse_${COMPONENT}_LIBRARY)
|
| 243 |
+
message(STATUS "Found ${COMPONENT} library: ${SuiteSparse_${COMPONENT}_LIBRARY}")
|
| 244 |
+
mark_as_advanced(SuiteSparse_${COMPONENT}_LIBRARY)
|
| 245 |
+
else ()
|
| 246 |
+
# Specified libraries not found.
|
| 247 |
+
set(SuiteSparse_${COMPONENT}_FOUND FALSE)
|
| 248 |
+
if (SuiteSparse_FIND_REQUIRED_${COMPONENT})
|
| 249 |
+
suitesparse_report_not_found(
|
| 250 |
+
"Did not find ${COMPONENT} library (required SuiteSparse component).")
|
| 251 |
+
else()
|
| 252 |
+
message(STATUS "Did not find ${COMPONENT} library (optional SuiteSparse "
|
| 253 |
+
"dependency)")
|
| 254 |
+
# Hide optional vars from CMake GUI even if not found.
|
| 255 |
+
mark_as_advanced(SuiteSparse_${COMPONENT}_LIBRARY)
|
| 256 |
+
endif()
|
| 257 |
+
endif()
|
| 258 |
+
endif()
|
| 259 |
+
|
| 260 |
+
# A component can be optional (given to OPTIONAL_COMPONENTS). However, if the
|
| 261 |
+
# component is implicit (must be always present, such as the Config component)
|
| 262 |
+
# assume it be required as well.
|
| 263 |
+
if (SuiteSparse_FIND_REQUIRED_${COMPONENT})
|
| 264 |
+
list (APPEND SuiteSparse_REQUIRED_VARS SuiteSparse_${COMPONENT}_INCLUDE_DIR)
|
| 265 |
+
list (APPEND SuiteSparse_REQUIRED_VARS SuiteSparse_${COMPONENT}_LIBRARY)
|
| 266 |
+
endif (SuiteSparse_FIND_REQUIRED_${COMPONENT})
|
| 267 |
+
|
| 268 |
+
# Define the target only if the include directory and the library were found
|
| 269 |
+
if (SuiteSparse_${COMPONENT}_INCLUDE_DIR AND SuiteSparse_${COMPONENT}_LIBRARY)
|
| 270 |
+
if (NOT TARGET SuiteSparse::${COMPONENT})
|
| 271 |
+
add_library(SuiteSparse::${COMPONENT} IMPORTED UNKNOWN)
|
| 272 |
+
endif (NOT TARGET SuiteSparse::${COMPONENT})
|
| 273 |
+
|
| 274 |
+
set_property(TARGET SuiteSparse::${COMPONENT} PROPERTY
|
| 275 |
+
INTERFACE_INCLUDE_DIRECTORIES ${SuiteSparse_${COMPONENT}_INCLUDE_DIR})
|
| 276 |
+
set_property(TARGET SuiteSparse::${COMPONENT} PROPERTY
|
| 277 |
+
IMPORTED_LOCATION ${SuiteSparse_${COMPONENT}_LIBRARY})
|
| 278 |
+
endif (SuiteSparse_${COMPONENT}_INCLUDE_DIR AND SuiteSparse_${COMPONENT}_LIBRARY)
|
| 279 |
+
endmacro()
|
| 280 |
+
|
| 281 |
+
# Given the number of components of SuiteSparse, and to ensure that the
|
| 282 |
+
# automatic failure message generated by FindPackageHandleStandardArgs()
|
| 283 |
+
# when not all required components are found is helpful, we maintain a list
|
| 284 |
+
# of all variables that must be defined for SuiteSparse to be considered found.
|
| 285 |
+
unset(SuiteSparse_REQUIRED_VARS)
|
| 286 |
+
|
| 287 |
+
# BLAS.
|
| 288 |
+
find_package(BLAS QUIET)
|
| 289 |
+
if (NOT BLAS_FOUND)
|
| 290 |
+
suitesparse_report_not_found(
|
| 291 |
+
"Did not find BLAS library (required for SuiteSparse).")
|
| 292 |
+
endif (NOT BLAS_FOUND)
|
| 293 |
+
|
| 294 |
+
# LAPACK.
|
| 295 |
+
find_package(LAPACK QUIET)
|
| 296 |
+
if (NOT LAPACK_FOUND)
|
| 297 |
+
suitesparse_report_not_found(
|
| 298 |
+
"Did not find LAPACK library (required for SuiteSparse).")
|
| 299 |
+
endif (NOT LAPACK_FOUND)
|
| 300 |
+
|
| 301 |
+
foreach (component IN LISTS SuiteSparse_FIND_COMPONENTS)
|
| 302 |
+
string (TOLOWER ${component} component_library)
|
| 303 |
+
|
| 304 |
+
if (component STREQUAL "Config")
|
| 305 |
+
set (component_header SuiteSparse_config.h)
|
| 306 |
+
set (component_library suitesparseconfig)
|
| 307 |
+
elseif (component STREQUAL "SPQR")
|
| 308 |
+
set (component_header SuiteSparseQR.hpp)
|
| 309 |
+
else (component STREQUAL "SPQR")
|
| 310 |
+
set (component_header ${component_library}.h)
|
| 311 |
+
endif (component STREQUAL "Config")
|
| 312 |
+
|
| 313 |
+
suitesparse_find_component(${component}
|
| 314 |
+
FILES ${component_header}
|
| 315 |
+
LIBRARIES ${component_library})
|
| 316 |
+
endforeach (component IN LISTS SuiteSparse_FIND_COMPONENTS)
|
| 317 |
+
|
| 318 |
+
if (TARGET SuiteSparse::SPQR)
|
| 319 |
+
# SuiteSparseQR may be compiled with Intel Threading Building Blocks,
|
| 320 |
+
# we assume that if TBB is installed, SuiteSparseQR was compiled with
|
| 321 |
+
# support for it, this will do no harm if it wasn't.
|
| 322 |
+
find_package(TBB QUIET)
|
| 323 |
+
if (TBB_FOUND)
|
| 324 |
+
message(STATUS "Found Intel Thread Building Blocks (TBB) library "
|
| 325 |
+
"(${TBB_VERSION_MAJOR}.${TBB_VERSION_MINOR} / ${TBB_INTERFACE_VERSION}) "
|
| 326 |
+
"include location: ${TBB_INCLUDE_DIRS}. Assuming SuiteSparseQR was "
|
| 327 |
+
"compiled with TBB.")
|
| 328 |
+
# Add the TBB libraries to the SuiteSparseQR libraries (the only
|
| 329 |
+
# libraries to optionally depend on TBB).
|
| 330 |
+
if (TARGET TBB::tbb)
|
| 331 |
+
# Native TBB package configuration provides an imported target. Use it if
|
| 332 |
+
# available.
|
| 333 |
+
set_property (TARGET SuiteSparse::SPQR APPEND PROPERTY
|
| 334 |
+
INTERFACE_LINK_LIBRARIES TBB::tbb)
|
| 335 |
+
else (TARGET TBB::tbb)
|
| 336 |
+
set_property (TARGET SuiteSparse::SPQR APPEND PROPERTY
|
| 337 |
+
INTERFACE_INCLUDE_DIRECTORIES ${TBB_INCLUDE_DIRS})
|
| 338 |
+
set_property (TARGET SuiteSparse::SPQR APPEND PROPERTY
|
| 339 |
+
INTERFACE_LINK_LIBRARIES ${TBB_LIBRARIES})
|
| 340 |
+
endif (TARGET TBB::tbb)
|
| 341 |
+
else (TBB_FOUND)
|
| 342 |
+
message(STATUS "Did not find Intel TBB library, assuming SuiteSparseQR was "
|
| 343 |
+
"not compiled with TBB.")
|
| 344 |
+
endif (TBB_FOUND)
|
| 345 |
+
endif (TARGET SuiteSparse::SPQR)
|
| 346 |
+
|
| 347 |
+
check_library_exists(rt shm_open "" HAVE_LIBRT)
|
| 348 |
+
|
| 349 |
+
if (TARGET SuiteSparse::Config)
|
| 350 |
+
# SuiteSparse_config (SuiteSparse version >= 4) requires librt library for
|
| 351 |
+
# timing by default when compiled on Linux or Unix, but not on OSX (which
|
| 352 |
+
# does not have librt).
|
| 353 |
+
if (HAVE_LIBRT)
|
| 354 |
+
message(STATUS "Adding librt to "
|
| 355 |
+
"SuiteSparse_config libraries (required on Linux & Unix [not OSX] if "
|
| 356 |
+
"SuiteSparse is compiled with timing).")
|
| 357 |
+
set_property (TARGET SuiteSparse::Config APPEND PROPERTY
|
| 358 |
+
INTERFACE_LINK_LIBRARIES $<LINK_ONLY:rt>)
|
| 359 |
+
else (HAVE_LIBRT)
|
| 360 |
+
message(STATUS "Could not find librt, but found SuiteSparse_config, "
|
| 361 |
+
"assuming that SuiteSparse was compiled without timing.")
|
| 362 |
+
endif (HAVE_LIBRT)
|
| 363 |
+
|
| 364 |
+
# Add BLAS and LAPACK as dependencies of SuiteSparse::Config for convenience
|
| 365 |
+
# given that all components depend on it.
|
| 366 |
+
if (BLAS_FOUND)
|
| 367 |
+
if (TARGET BLAS::BLAS)
|
| 368 |
+
set_property (TARGET SuiteSparse::Config APPEND PROPERTY
|
| 369 |
+
INTERFACE_LINK_LIBRARIES $<LINK_ONLY:BLAS::BLAS>)
|
| 370 |
+
else (TARGET BLAS::BLAS)
|
| 371 |
+
set_property (TARGET SuiteSparse::Config APPEND PROPERTY
|
| 372 |
+
INTERFACE_LINK_LIBRARIES ${BLAS_LIBRARIES})
|
| 373 |
+
endif (TARGET BLAS::BLAS)
|
| 374 |
+
endif (BLAS_FOUND)
|
| 375 |
+
|
| 376 |
+
if (LAPACK_FOUND)
|
| 377 |
+
if (TARGET LAPACK::LAPACK)
|
| 378 |
+
set_property (TARGET SuiteSparse::Config APPEND PROPERTY
|
| 379 |
+
INTERFACE_LINK_LIBRARIES $<LINK_ONLY:LAPACK::LAPACK>)
|
| 380 |
+
else (TARGET LAPACK::LAPACK)
|
| 381 |
+
set_property (TARGET SuiteSparse::Config APPEND PROPERTY
|
| 382 |
+
INTERFACE_LINK_LIBRARIES ${LAPACK_LIBRARIES})
|
| 383 |
+
endif (TARGET LAPACK::LAPACK)
|
| 384 |
+
endif (LAPACK_FOUND)
|
| 385 |
+
|
| 386 |
+
# SuiteSparse version >= 4.
|
| 387 |
+
set(SuiteSparse_VERSION_FILE
|
| 388 |
+
${SuiteSparse_Config_INCLUDE_DIR}/SuiteSparse_config.h)
|
| 389 |
+
if (NOT EXISTS ${SuiteSparse_VERSION_FILE})
|
| 390 |
+
suitesparse_report_not_found(
|
| 391 |
+
"Could not find file: ${SuiteSparse_VERSION_FILE} containing version "
|
| 392 |
+
"information for >= v4 SuiteSparse installs, but SuiteSparse_config was "
|
| 393 |
+
"found (only present in >= v4 installs).")
|
| 394 |
+
else (NOT EXISTS ${SuiteSparse_VERSION_FILE})
|
| 395 |
+
file(READ ${SuiteSparse_VERSION_FILE} Config_CONTENTS)
|
| 396 |
+
|
| 397 |
+
string(REGEX MATCH "#define SUITESPARSE_MAIN_VERSION [0-9]+"
|
| 398 |
+
SuiteSparse_VERSION_MAJOR "${Config_CONTENTS}")
|
| 399 |
+
string(REGEX REPLACE "#define SUITESPARSE_MAIN_VERSION ([0-9]+)" "\\1"
|
| 400 |
+
SuiteSparse_VERSION_MAJOR "${SuiteSparse_VERSION_MAJOR}")
|
| 401 |
+
|
| 402 |
+
string(REGEX MATCH "#define SUITESPARSE_SUB_VERSION [0-9]+"
|
| 403 |
+
SuiteSparse_VERSION_MINOR "${Config_CONTENTS}")
|
| 404 |
+
string(REGEX REPLACE "#define SUITESPARSE_SUB_VERSION ([0-9]+)" "\\1"
|
| 405 |
+
SuiteSparse_VERSION_MINOR "${SuiteSparse_VERSION_MINOR}")
|
| 406 |
+
|
| 407 |
+
string(REGEX MATCH "#define SUITESPARSE_SUBSUB_VERSION [0-9]+"
|
| 408 |
+
SuiteSparse_VERSION_PATCH "${Config_CONTENTS}")
|
| 409 |
+
string(REGEX REPLACE "#define SUITESPARSE_SUBSUB_VERSION ([0-9]+)" "\\1"
|
| 410 |
+
SuiteSparse_VERSION_PATCH "${SuiteSparse_VERSION_PATCH}")
|
| 411 |
+
|
| 412 |
+
# This is on a single line s/t CMake does not interpret it as a list of
|
| 413 |
+
# elements and insert ';' separators which would result in 4.;2.;1 nonsense.
|
| 414 |
+
set(SuiteSparse_VERSION
|
| 415 |
+
"${SuiteSparse_VERSION_MAJOR}.${SuiteSparse_VERSION_MINOR}.${SuiteSparse_VERSION_PATCH}")
|
| 416 |
+
set(SuiteSparse_VERSION_COMPONENTS 3)
|
| 417 |
+
endif (NOT EXISTS ${SuiteSparse_VERSION_FILE})
|
| 418 |
+
endif (TARGET SuiteSparse::Config)
|
| 419 |
+
|
| 420 |
+
# METIS (Optional dependency).
|
| 421 |
+
find_package (METIS)
|
| 422 |
+
|
| 423 |
+
# CHOLMOD requires AMD CAMD CCOLAMD COLAMD
|
| 424 |
+
if (TARGET SuiteSparse::CHOLMOD)
|
| 425 |
+
# METIS is optional
|
| 426 |
+
if (TARGET METIS::METIS)
|
| 427 |
+
set_property (TARGET SuiteSparse::CHOLMOD APPEND PROPERTY
|
| 428 |
+
INTERFACE_LINK_LIBRARIES METIS::METIS)
|
| 429 |
+
endif (TARGET METIS::METIS)
|
| 430 |
+
|
| 431 |
+
foreach (component IN ITEMS AMD CAMD CCOLAMD COLAMD)
|
| 432 |
+
if (TARGET SuiteSparse::${component})
|
| 433 |
+
set_property (TARGET SuiteSparse::CHOLMOD APPEND PROPERTY
|
| 434 |
+
INTERFACE_LINK_LIBRARIES SuiteSparse::${component})
|
| 435 |
+
else (TARGET SuiteSparse::${component})
|
| 436 |
+
# Consider CHOLMOD not found if COLAMD cannot be found
|
| 437 |
+
set (SuiteSparse_CHOLMOD_FOUND FALSE)
|
| 438 |
+
endif (TARGET SuiteSparse::${component})
|
| 439 |
+
endforeach (component IN ITEMS AMD CAMD CCOLAMD COLAMD)
|
| 440 |
+
endif (TARGET SuiteSparse::CHOLMOD)
|
| 441 |
+
|
| 442 |
+
# SPQR requires CHOLMOD
|
| 443 |
+
if (TARGET SuiteSparse::SPQR)
|
| 444 |
+
if (TARGET SuiteSparse::CHOLMOD)
|
| 445 |
+
set_property (TARGET SuiteSparse::SPQR APPEND PROPERTY
|
| 446 |
+
INTERFACE_LINK_LIBRARIES SuiteSparse::CHOLMOD)
|
| 447 |
+
else (TARGET SuiteSparse::CHOLMOD)
|
| 448 |
+
# Consider SPQR not found if CHOLMOD cannot be found
|
| 449 |
+
set (SuiteSparse_SQPR_FOUND FALSE)
|
| 450 |
+
endif (TARGET SuiteSparse::CHOLMOD)
|
| 451 |
+
endif (TARGET SuiteSparse::SPQR)
|
| 452 |
+
|
| 453 |
+
# Add SuiteSparse::Config as dependency to all components
|
| 454 |
+
if (TARGET SuiteSparse::Config)
|
| 455 |
+
foreach (component IN LISTS SuiteSparse_FIND_COMPONENTS)
|
| 456 |
+
if (component STREQUAL Config)
|
| 457 |
+
continue ()
|
| 458 |
+
endif (component STREQUAL Config)
|
| 459 |
+
|
| 460 |
+
if (TARGET SuiteSparse::${component})
|
| 461 |
+
set_property (TARGET SuiteSparse::${component} APPEND PROPERTY
|
| 462 |
+
INTERFACE_LINK_LIBRARIES SuiteSparse::Config)
|
| 463 |
+
endif (TARGET SuiteSparse::${component})
|
| 464 |
+
endforeach (component IN LISTS SuiteSparse_FIND_COMPONENTS)
|
| 465 |
+
endif (TARGET SuiteSparse::Config)
|
| 466 |
+
|
| 467 |
+
suitesparse_reset_find_library_prefix()
|
| 468 |
+
|
| 469 |
+
# Handle REQUIRED and QUIET arguments to FIND_PACKAGE
|
| 470 |
+
include(FindPackageHandleStandardArgs)
|
| 471 |
+
if (SuiteSparse_FOUND)
|
| 472 |
+
find_package_handle_standard_args(SuiteSparse
|
| 473 |
+
REQUIRED_VARS ${SuiteSparse_REQUIRED_VARS}
|
| 474 |
+
VERSION_VAR SuiteSparse_VERSION
|
| 475 |
+
FAIL_MESSAGE "Failed to find some/all required components of SuiteSparse."
|
| 476 |
+
HANDLE_COMPONENTS)
|
| 477 |
+
else (SuiteSparse_FOUND)
|
| 478 |
+
# Do not pass VERSION_VAR to FindPackageHandleStandardArgs() if we failed to
|
| 479 |
+
# find SuiteSparse to avoid a confusing autogenerated failure message
|
| 480 |
+
# that states 'not found (missing: FOO) (found version: x.y.z)'.
|
| 481 |
+
find_package_handle_standard_args(SuiteSparse
|
| 482 |
+
REQUIRED_VARS ${SuiteSparse_REQUIRED_VARS}
|
| 483 |
+
FAIL_MESSAGE "Failed to find some/all required components of SuiteSparse."
|
| 484 |
+
HANDLE_COMPONENTS)
|
| 485 |
+
endif (SuiteSparse_FOUND)
|
| 486 |
+
|
| 487 |
+
# Pop CMP0057.
|
| 488 |
+
cmake_policy (POP)
|
include/ceres/autodiff_cost_function.h
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: sameeragarwal@google.com (Sameer Agarwal)
|
| 30 |
+
//
|
| 31 |
+
// Create CostFunctions as needed by the least squares framework, with
|
| 32 |
+
// Jacobians computed via automatic differentiation. For more
|
| 33 |
+
// information on automatic differentiation, see the wikipedia article
|
| 34 |
+
// at http://en.wikipedia.org/wiki/Automatic_differentiation
|
| 35 |
+
//
|
| 36 |
+
// To get an auto differentiated cost function, you must define a class with a
|
| 37 |
+
// templated operator() (a functor) that computes the cost function in terms of
|
| 38 |
+
// the template parameter T. The autodiff framework substitutes appropriate
|
| 39 |
+
// "jet" objects for T in order to compute the derivative when necessary, but
|
| 40 |
+
// this is hidden, and you should write the function as if T were a scalar type
|
| 41 |
+
// (e.g. a double-precision floating point number).
|
| 42 |
+
//
|
| 43 |
+
// The function must write the computed value in the last argument
|
| 44 |
+
// (the only non-const one) and return true to indicate
|
| 45 |
+
// success. Please see cost_function.h for details on how the return
|
| 46 |
+
// value maybe used to impose simple constraints on the parameter
|
| 47 |
+
// block.
|
| 48 |
+
//
|
| 49 |
+
// For example, consider a scalar error e = k - x'y, where both x and y are
|
| 50 |
+
// two-dimensional column vector parameters, the prime sign indicates
|
| 51 |
+
// transposition, and k is a constant. The form of this error, which is the
|
| 52 |
+
// difference between a constant and an expression, is a common pattern in least
|
| 53 |
+
// squares problems. For example, the value x'y might be the model expectation
|
| 54 |
+
// for a series of measurements, where there is an instance of the cost function
|
| 55 |
+
// for each measurement k.
|
| 56 |
+
//
|
| 57 |
+
// The actual cost added to the total problem is e^2, or (k - x'y)^2; however,
|
| 58 |
+
// the squaring is implicitly done by the optimization framework.
|
| 59 |
+
//
|
| 60 |
+
// To write an auto-differentiable cost function for the above model, first
|
| 61 |
+
// define the object
|
| 62 |
+
//
|
| 63 |
+
// class MyScalarCostFunctor {
|
| 64 |
+
// MyScalarCostFunctor(double k): k_(k) {}
|
| 65 |
+
//
|
| 66 |
+
// template <typename T>
|
| 67 |
+
// bool operator()(const T* const x , const T* const y, T* e) const {
|
| 68 |
+
// e[0] = T(k_) - x[0] * y[0] + x[1] * y[1];
|
| 69 |
+
// return true;
|
| 70 |
+
// }
|
| 71 |
+
//
|
| 72 |
+
// private:
|
| 73 |
+
// double k_;
|
| 74 |
+
// };
|
| 75 |
+
//
|
| 76 |
+
// Note that in the declaration of operator() the input parameters x and y come
|
| 77 |
+
// first, and are passed as const pointers to arrays of T. If there were three
|
| 78 |
+
// input parameters, then the third input parameter would come after y. The
|
| 79 |
+
// output is always the last parameter, and is also a pointer to an array. In
|
| 80 |
+
// the example above, e is a scalar, so only e[0] is set.
|
| 81 |
+
//
|
| 82 |
+
// Then given this class definition, the auto differentiated cost function for
|
| 83 |
+
// it can be constructed as follows.
|
| 84 |
+
//
|
| 85 |
+
// CostFunction* cost_function
|
| 86 |
+
// = new AutoDiffCostFunction<MyScalarCostFunctor, 1, 2, 2>(
|
| 87 |
+
// new MyScalarCostFunctor(1.0)); ^ ^ ^
|
| 88 |
+
// | | |
|
| 89 |
+
// Dimension of residual -----+ | |
|
| 90 |
+
// Dimension of x ---------------+ |
|
| 91 |
+
// Dimension of y ------------------+
|
| 92 |
+
//
|
| 93 |
+
// In this example, there is usually an instance for each measurement of k.
|
| 94 |
+
//
|
| 95 |
+
// In the instantiation above, the template parameters following
|
| 96 |
+
// "MyScalarCostFunctor", "1, 2, 2", describe the functor as computing a
|
| 97 |
+
// 1-dimensional output from two arguments, both 2-dimensional.
|
| 98 |
+
//
|
| 99 |
+
// AutoDiffCostFunction also supports cost functions with a
|
| 100 |
+
// runtime-determined number of residuals. For example:
|
| 101 |
+
//
|
| 102 |
+
// CostFunction* cost_function
|
| 103 |
+
// = new AutoDiffCostFunction<MyScalarCostFunctor, DYNAMIC, 2, 2>(
|
| 104 |
+
// new CostFunctorWithDynamicNumResiduals(1.0), ^ ^ ^
|
| 105 |
+
// runtime_number_of_residuals); <----+ | | |
|
| 106 |
+
// | | | |
|
| 107 |
+
// | | | |
|
| 108 |
+
// Actual number of residuals ------+ | | |
|
| 109 |
+
// Indicate dynamic number of residuals --------+ | |
|
| 110 |
+
// Dimension of x ------------------------------------+ |
|
| 111 |
+
// Dimension of y ---------------------------------------+
|
| 112 |
+
//
|
| 113 |
+
// WARNING #1: Since the functor will get instantiated with different types for
|
| 114 |
+
// T, you must convert from other numeric types to T before mixing
|
| 115 |
+
// computations with other variables of type T. In the example above, this is
|
| 116 |
+
// seen where instead of using k_ directly, k_ is wrapped with T(k_).
|
| 117 |
+
//
|
| 118 |
+
// WARNING #2: A common beginner's error when first using autodiff cost
|
| 119 |
+
// functions is to get the sizing wrong. In particular, there is a tendency to
|
| 120 |
+
// set the template parameters to (dimension of residual, number of parameters)
|
| 121 |
+
// instead of passing a dimension parameter for *every parameter*. In the
|
| 122 |
+
// example above, that would be <MyScalarCostFunctor, 1, 2>, which is missing
|
| 123 |
+
// the last '2' argument. Please be careful when setting the size parameters.
|
| 124 |
+
|
| 125 |
+
#ifndef CERES_PUBLIC_AUTODIFF_COST_FUNCTION_H_
|
| 126 |
+
#define CERES_PUBLIC_AUTODIFF_COST_FUNCTION_H_
|
| 127 |
+
|
| 128 |
+
#include <memory>
|
| 129 |
+
|
| 130 |
+
#include "ceres/internal/autodiff.h"
|
| 131 |
+
#include "ceres/sized_cost_function.h"
|
| 132 |
+
#include "ceres/types.h"
|
| 133 |
+
#include "glog/logging.h"
|
| 134 |
+
|
| 135 |
+
namespace ceres {
|
| 136 |
+
|
| 137 |
+
// A cost function which computes the derivative of the cost with respect to
|
| 138 |
+
// the parameters (a.k.a. the jacobian) using an auto differentiation framework.
|
| 139 |
+
// The first template argument is the functor object, described in the header
|
| 140 |
+
// comment. The second argument is the dimension of the residual (or
|
| 141 |
+
// ceres::DYNAMIC to indicate it will be set at runtime), and subsequent
|
| 142 |
+
// arguments describe the size of the Nth parameter, one per parameter.
|
| 143 |
+
//
|
| 144 |
+
// The constructors take ownership of the cost functor.
|
| 145 |
+
//
|
| 146 |
+
// If the number of residuals (argument kNumResiduals below) is
|
| 147 |
+
// ceres::DYNAMIC, then the two-argument constructor must be used. The
|
| 148 |
+
// second constructor takes a number of residuals (in addition to the
|
| 149 |
+
// templated number of residuals). This allows for varying the number
|
| 150 |
+
// of residuals for a single autodiff cost function at runtime.
|
| 151 |
+
template <typename CostFunctor,
|
| 152 |
+
int kNumResiduals, // Number of residuals, or ceres::DYNAMIC.
|
| 153 |
+
int... Ns> // Number of parameters in each parameter block.
|
| 154 |
+
class AutoDiffCostFunction final
|
| 155 |
+
: public SizedCostFunction<kNumResiduals, Ns...> {
|
| 156 |
+
public:
|
| 157 |
+
// Takes ownership of functor by default. Uses the template-provided
|
| 158 |
+
// value for the number of residuals ("kNumResiduals").
|
| 159 |
+
explicit AutoDiffCostFunction(CostFunctor* functor,
|
| 160 |
+
Ownership ownership = TAKE_OWNERSHIP)
|
| 161 |
+
: functor_(functor), ownership_(ownership) {
|
| 162 |
+
static_assert(kNumResiduals != DYNAMIC,
|
| 163 |
+
"Can't run the fixed-size constructor if the number of "
|
| 164 |
+
"residuals is set to ceres::DYNAMIC.");
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
// Takes ownership of functor by default. Ignores the template-provided
|
| 168 |
+
// kNumResiduals in favor of the "num_residuals" argument provided.
|
| 169 |
+
//
|
| 170 |
+
// This allows for having autodiff cost functions which return varying
|
| 171 |
+
// numbers of residuals at runtime.
|
| 172 |
+
AutoDiffCostFunction(CostFunctor* functor,
|
| 173 |
+
int num_residuals,
|
| 174 |
+
Ownership ownership = TAKE_OWNERSHIP)
|
| 175 |
+
: functor_(functor), ownership_(ownership) {
|
| 176 |
+
static_assert(kNumResiduals == DYNAMIC,
|
| 177 |
+
"Can't run the dynamic-size constructor if the number of "
|
| 178 |
+
"residuals is not ceres::DYNAMIC.");
|
| 179 |
+
SizedCostFunction<kNumResiduals, Ns...>::set_num_residuals(num_residuals);
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
AutoDiffCostFunction(AutoDiffCostFunction&& other)
|
| 183 |
+
: functor_(std::move(other.functor_)), ownership_(other.ownership_) {}
|
| 184 |
+
|
| 185 |
+
virtual ~AutoDiffCostFunction() {
|
| 186 |
+
// Manually release pointer if configured to not take ownership rather than
|
| 187 |
+
// deleting only if ownership is taken.
|
| 188 |
+
// This is to stay maximally compatible to old user code which may have
|
| 189 |
+
// forgotten to implement a virtual destructor, from when the
|
| 190 |
+
// AutoDiffCostFunction always took ownership.
|
| 191 |
+
if (ownership_ == DO_NOT_TAKE_OWNERSHIP) {
|
| 192 |
+
functor_.release();
|
| 193 |
+
}
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
// Implementation details follow; clients of the autodiff cost function should
|
| 197 |
+
// not have to examine below here.
|
| 198 |
+
//
|
| 199 |
+
// To handle variadic cost functions, some template magic is needed. It's
|
| 200 |
+
// mostly hidden inside autodiff.h.
|
| 201 |
+
bool Evaluate(double const* const* parameters,
|
| 202 |
+
double* residuals,
|
| 203 |
+
double** jacobians) const override {
|
| 204 |
+
using ParameterDims =
|
| 205 |
+
typename SizedCostFunction<kNumResiduals, Ns...>::ParameterDims;
|
| 206 |
+
|
| 207 |
+
if (!jacobians) {
|
| 208 |
+
return internal::VariadicEvaluate<ParameterDims>(
|
| 209 |
+
*functor_, parameters, residuals);
|
| 210 |
+
}
|
| 211 |
+
return internal::AutoDifferentiate<kNumResiduals, ParameterDims>(
|
| 212 |
+
*functor_,
|
| 213 |
+
parameters,
|
| 214 |
+
SizedCostFunction<kNumResiduals, Ns...>::num_residuals(),
|
| 215 |
+
residuals,
|
| 216 |
+
jacobians);
|
| 217 |
+
};
|
| 218 |
+
|
| 219 |
+
const CostFunctor& functor() const { return *functor_; }
|
| 220 |
+
|
| 221 |
+
private:
|
| 222 |
+
std::unique_ptr<CostFunctor> functor_;
|
| 223 |
+
Ownership ownership_;
|
| 224 |
+
};
|
| 225 |
+
|
| 226 |
+
} // namespace ceres
|
| 227 |
+
|
| 228 |
+
#endif // CERES_PUBLIC_AUTODIFF_COST_FUNCTION_H_
|
include/ceres/autodiff_first_order_function.h
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: sameeragarwal@google.com (Sameer Agarwal)
|
| 30 |
+
|
| 31 |
+
#ifndef CERES_PUBLIC_AUTODIFF_FIRST_ORDER_FUNCTION_H_
|
| 32 |
+
#define CERES_PUBLIC_AUTODIFF_FIRST_ORDER_FUNCTION_H_
|
| 33 |
+
|
| 34 |
+
#include <memory>
|
| 35 |
+
|
| 36 |
+
#include "ceres/first_order_function.h"
|
| 37 |
+
#include "ceres/internal/eigen.h"
|
| 38 |
+
#include "ceres/internal/fixed_array.h"
|
| 39 |
+
#include "ceres/jet.h"
|
| 40 |
+
#include "ceres/types.h"
|
| 41 |
+
|
| 42 |
+
namespace ceres {
|
| 43 |
+
|
| 44 |
+
// Create FirstOrderFunctions as needed by the GradientProblem
|
| 45 |
+
// framework, with gradients computed via automatic
|
| 46 |
+
// differentiation. For more information on automatic differentiation,
|
| 47 |
+
// see the wikipedia article at
|
| 48 |
+
// http://en.wikipedia.org/wiki/Automatic_differentiation
|
| 49 |
+
//
|
| 50 |
+
// To get an auto differentiated function, you must define a class
|
| 51 |
+
// with a templated operator() (a functor) that computes the cost
|
| 52 |
+
// function in terms of the template parameter T. The autodiff
|
| 53 |
+
// framework substitutes appropriate "jet" objects for T in order to
|
| 54 |
+
// compute the derivative when necessary, but this is hidden, and you
|
| 55 |
+
// should write the function as if T were a scalar type (e.g. a
|
| 56 |
+
// double-precision floating point number).
|
| 57 |
+
//
|
| 58 |
+
// The function must write the computed value in the last argument
|
| 59 |
+
// (the only non-const one) and return true to indicate
|
| 60 |
+
// success.
|
| 61 |
+
//
|
| 62 |
+
// For example, consider a scalar error e = x'y - a, where both x and y are
|
| 63 |
+
// two-dimensional column vector parameters, the prime sign indicates
|
| 64 |
+
// transposition, and a is a constant.
|
| 65 |
+
//
|
| 66 |
+
// To write an auto-differentiable FirstOrderFunction for the above model, first
|
| 67 |
+
// define the object
|
| 68 |
+
//
|
| 69 |
+
// class QuadraticCostFunctor {
|
| 70 |
+
// public:
|
| 71 |
+
// explicit QuadraticCostFunctor(double a) : a_(a) {}
|
| 72 |
+
// template <typename T>
|
| 73 |
+
// bool operator()(const T* const xy, T* cost) const {
|
| 74 |
+
// const T* const x = xy;
|
| 75 |
+
// const T* const y = xy + 2;
|
| 76 |
+
// *cost = x[0] * y[0] + x[1] * y[1] - T(a_);
|
| 77 |
+
// return true;
|
| 78 |
+
// }
|
| 79 |
+
//
|
| 80 |
+
// private:
|
| 81 |
+
// double a_;
|
| 82 |
+
// };
|
| 83 |
+
//
|
| 84 |
+
// Note that in the declaration of operator() the input parameters xy come
|
| 85 |
+
// first, and are passed as const pointers to arrays of T. The
|
| 86 |
+
// output is the last parameter.
|
| 87 |
+
//
|
| 88 |
+
// Then given this class definition, the auto differentiated FirstOrderFunction
|
| 89 |
+
// for it can be constructed as follows.
|
| 90 |
+
//
|
| 91 |
+
// FirstOrderFunction* function =
|
| 92 |
+
// new AutoDiffFirstOrderFunction<QuadraticCostFunctor, 4>(
|
| 93 |
+
// new QuadraticCostFunctor(1.0)));
|
| 94 |
+
//
|
| 95 |
+
// In the instantiation above, the template parameters following
|
| 96 |
+
// "QuadraticCostFunctor", "4", describe the functor as computing a
|
| 97 |
+
// 1-dimensional output from a four dimensional vector.
|
| 98 |
+
//
|
| 99 |
+
// WARNING: Since the functor will get instantiated with different types for
|
| 100 |
+
// T, you must convert from other numeric types to T before mixing
|
| 101 |
+
// computations with other variables of type T. In the example above, this is
|
| 102 |
+
// seen where instead of using a_ directly, a_ is wrapped with T(a_).
|
| 103 |
+
|
| 104 |
+
template <typename FirstOrderFunctor, int kNumParameters>
|
| 105 |
+
class AutoDiffFirstOrderFunction final : public FirstOrderFunction {
|
| 106 |
+
public:
|
| 107 |
+
// Takes ownership of functor.
|
| 108 |
+
explicit AutoDiffFirstOrderFunction(FirstOrderFunctor* functor)
|
| 109 |
+
: functor_(functor) {
|
| 110 |
+
static_assert(kNumParameters > 0, "kNumParameters must be positive");
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
bool Evaluate(const double* const parameters,
|
| 114 |
+
double* cost,
|
| 115 |
+
double* gradient) const override {
|
| 116 |
+
if (gradient == nullptr) {
|
| 117 |
+
return (*functor_)(parameters, cost);
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
using JetT = Jet<double, kNumParameters>;
|
| 121 |
+
internal::FixedArray<JetT, (256 * 7) / sizeof(JetT)> x(kNumParameters);
|
| 122 |
+
for (int i = 0; i < kNumParameters; ++i) {
|
| 123 |
+
x[i].a = parameters[i];
|
| 124 |
+
x[i].v.setZero();
|
| 125 |
+
x[i].v[i] = 1.0;
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
JetT output;
|
| 129 |
+
output.a = kImpossibleValue;
|
| 130 |
+
output.v.setConstant(kImpossibleValue);
|
| 131 |
+
|
| 132 |
+
if (!(*functor_)(x.data(), &output)) {
|
| 133 |
+
return false;
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
*cost = output.a;
|
| 137 |
+
VectorRef(gradient, kNumParameters) = output.v;
|
| 138 |
+
return true;
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
int NumParameters() const override { return kNumParameters; }
|
| 142 |
+
|
| 143 |
+
const FirstOrderFunctor& functor() const { return *functor_; }
|
| 144 |
+
|
| 145 |
+
private:
|
| 146 |
+
std::unique_ptr<FirstOrderFunctor> functor_;
|
| 147 |
+
};
|
| 148 |
+
|
| 149 |
+
} // namespace ceres
|
| 150 |
+
|
| 151 |
+
#endif // CERES_PUBLIC_AUTODIFF_FIRST_ORDER_FUNCTION_H_
|
include/ceres/autodiff_local_parameterization.h
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: sergey.vfx@gmail.com (Sergey Sharybin)
|
| 30 |
+
// mierle@gmail.com (Keir Mierle)
|
| 31 |
+
// sameeragarwal@google.com (Sameer Agarwal)
|
| 32 |
+
|
| 33 |
+
#ifndef CERES_PUBLIC_AUTODIFF_LOCAL_PARAMETERIZATION_H_
|
| 34 |
+
#define CERES_PUBLIC_AUTODIFF_LOCAL_PARAMETERIZATION_H_
|
| 35 |
+
|
| 36 |
+
#include <memory>
|
| 37 |
+
|
| 38 |
+
#include "ceres/internal/autodiff.h"
|
| 39 |
+
#include "ceres/local_parameterization.h"
|
| 40 |
+
|
| 41 |
+
namespace ceres {
|
| 42 |
+
|
| 43 |
+
// WARNING: LocalParameterizations are deprecated, so is
|
| 44 |
+
// AutoDiffLocalParameterization. They will be removed from Ceres Solver in
|
| 45 |
+
// version 2.2.0. Please use Manifolds and AutoDiffManifold instead.
|
| 46 |
+
|
| 47 |
+
// Create local parameterization with Jacobians computed via automatic
|
| 48 |
+
// differentiation. For more information on local parameterizations,
|
| 49 |
+
// see include/ceres/local_parameterization.h
|
| 50 |
+
//
|
| 51 |
+
// To get an auto differentiated local parameterization, you must define
|
| 52 |
+
// a class with a templated operator() (a functor) that computes
|
| 53 |
+
//
|
| 54 |
+
// x_plus_delta = Plus(x, delta);
|
| 55 |
+
//
|
| 56 |
+
// the template parameter T. The autodiff framework substitutes appropriate
|
| 57 |
+
// "Jet" objects for T in order to compute the derivative when necessary, but
|
| 58 |
+
// this is hidden, and you should write the function as if T were a scalar type
|
| 59 |
+
// (e.g. a double-precision floating point number).
|
| 60 |
+
//
|
| 61 |
+
// The function must write the computed value in the last argument (the only
|
| 62 |
+
// non-const one) and return true to indicate success.
|
| 63 |
+
//
|
| 64 |
+
// For example, Quaternions have a three dimensional local
|
| 65 |
+
// parameterization. It's plus operation can be implemented as (taken
|
| 66 |
+
// from internal/ceres/auto_diff_local_parameterization_test.cc)
|
| 67 |
+
//
|
| 68 |
+
// struct QuaternionPlus {
|
| 69 |
+
// template<typename T>
|
| 70 |
+
// bool operator()(const T* x, const T* delta, T* x_plus_delta) const {
|
| 71 |
+
// const T squared_norm_delta =
|
| 72 |
+
// delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2];
|
| 73 |
+
//
|
| 74 |
+
// T q_delta[4];
|
| 75 |
+
// if (squared_norm_delta > T(0.0)) {
|
| 76 |
+
// T norm_delta = sqrt(squared_norm_delta);
|
| 77 |
+
// const T sin_delta_by_delta = sin(norm_delta) / norm_delta;
|
| 78 |
+
// q_delta[0] = cos(norm_delta);
|
| 79 |
+
// q_delta[1] = sin_delta_by_delta * delta[0];
|
| 80 |
+
// q_delta[2] = sin_delta_by_delta * delta[1];
|
| 81 |
+
// q_delta[3] = sin_delta_by_delta * delta[2];
|
| 82 |
+
// } else {
|
| 83 |
+
// // We do not just use q_delta = [1,0,0,0] here because that is a
|
| 84 |
+
// // constant and when used for automatic differentiation will
|
| 85 |
+
// // lead to a zero derivative. Instead we take a first order
|
| 86 |
+
// // approximation and evaluate it at zero.
|
| 87 |
+
// q_delta[0] = T(1.0);
|
| 88 |
+
// q_delta[1] = delta[0];
|
| 89 |
+
// q_delta[2] = delta[1];
|
| 90 |
+
// q_delta[3] = delta[2];
|
| 91 |
+
// }
|
| 92 |
+
//
|
| 93 |
+
// QuaternionProduct(q_delta, x, x_plus_delta);
|
| 94 |
+
// return true;
|
| 95 |
+
// }
|
| 96 |
+
// };
|
| 97 |
+
//
|
| 98 |
+
// Then given this struct, the auto differentiated local
|
| 99 |
+
// parameterization can now be constructed as
|
| 100 |
+
//
|
| 101 |
+
// LocalParameterization* local_parameterization =
|
| 102 |
+
// new AutoDiffLocalParameterization<QuaternionPlus, 4, 3>;
|
| 103 |
+
// | |
|
| 104 |
+
// Global Size ---------------+ |
|
| 105 |
+
// Local Size -------------------+
|
| 106 |
+
//
|
| 107 |
+
// WARNING: Since the functor will get instantiated with different types for
|
| 108 |
+
// T, you must to convert from other numeric types to T before mixing
|
| 109 |
+
// computations with other variables of type T. In the example above, this is
|
| 110 |
+
// seen where instead of using k_ directly, k_ is wrapped with T(k_).
|
| 111 |
+
|
| 112 |
+
template <typename Functor, int kGlobalSize, int kLocalSize>
|
| 113 |
+
class CERES_DEPRECATED_WITH_MSG("Use AutoDiffManifold instead.")
|
| 114 |
+
AutoDiffLocalParameterization : public LocalParameterization {
|
| 115 |
+
public:
|
| 116 |
+
AutoDiffLocalParameterization() : functor_(new Functor()) {}
|
| 117 |
+
|
| 118 |
+
// Takes ownership of functor.
|
| 119 |
+
explicit AutoDiffLocalParameterization(Functor* functor)
|
| 120 |
+
: functor_(functor) {}
|
| 121 |
+
|
| 122 |
+
bool Plus(const double* x,
|
| 123 |
+
const double* delta,
|
| 124 |
+
double* x_plus_delta) const override {
|
| 125 |
+
return (*functor_)(x, delta, x_plus_delta);
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
bool ComputeJacobian(const double* x, double* jacobian) const override {
|
| 129 |
+
double zero_delta[kLocalSize];
|
| 130 |
+
for (int i = 0; i < kLocalSize; ++i) {
|
| 131 |
+
zero_delta[i] = 0.0;
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
double x_plus_delta[kGlobalSize];
|
| 135 |
+
for (int i = 0; i < kGlobalSize; ++i) {
|
| 136 |
+
x_plus_delta[i] = 0.0;
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
const double* parameter_ptrs[2] = {x, zero_delta};
|
| 140 |
+
double* jacobian_ptrs[2] = {nullptr, jacobian};
|
| 141 |
+
return internal::AutoDifferentiate<
|
| 142 |
+
kGlobalSize,
|
| 143 |
+
internal::StaticParameterDims<kGlobalSize, kLocalSize>>(
|
| 144 |
+
*functor_, parameter_ptrs, kGlobalSize, x_plus_delta, jacobian_ptrs);
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
int GlobalSize() const override { return kGlobalSize; }
|
| 148 |
+
int LocalSize() const override { return kLocalSize; }
|
| 149 |
+
|
| 150 |
+
const Functor& functor() const { return *functor_; }
|
| 151 |
+
|
| 152 |
+
private:
|
| 153 |
+
std::unique_ptr<Functor> functor_;
|
| 154 |
+
};
|
| 155 |
+
|
| 156 |
+
} // namespace ceres
|
| 157 |
+
|
| 158 |
+
#endif // CERES_PUBLIC_AUTODIFF_LOCAL_PARAMETERIZATION_H_
|
include/ceres/autodiff_manifold.h
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2022 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: sameeragarwal@google.com (Sameer Agarwal)
|
| 30 |
+
|
| 31 |
+
#ifndef CERES_PUBLIC_AUTODIFF_MANIFOLD_H_
|
| 32 |
+
#define CERES_PUBLIC_AUTODIFF_MANIFOLD_H_
|
| 33 |
+
|
| 34 |
+
#include <memory>
|
| 35 |
+
|
| 36 |
+
#include "ceres/internal/autodiff.h"
|
| 37 |
+
#include "ceres/manifold.h"
|
| 38 |
+
|
| 39 |
+
namespace ceres {
|
| 40 |
+
|
| 41 |
+
// Create a Manifold with Jacobians computed via automatic differentiation. For
|
| 42 |
+
// more information on manifolds, see include/ceres/manifold.h
|
| 43 |
+
//
|
| 44 |
+
// To get an auto differentiated manifold, you must define a class/struct with
|
| 45 |
+
// templated Plus and Minus functions that compute
|
| 46 |
+
//
|
| 47 |
+
// x_plus_delta = Plus(x, delta);
|
| 48 |
+
// y_minus_x = Minus(y, x);
|
| 49 |
+
//
|
| 50 |
+
// Where, x, y and x_plus_y are vectors on the manifold in the ambient space (so
|
| 51 |
+
// they are kAmbientSize vectors) and delta, y_minus_x are vectors in the
|
| 52 |
+
// tangent space (so they are kTangentSize vectors).
|
| 53 |
+
//
|
| 54 |
+
// The Functor should have the signature:
|
| 55 |
+
//
|
| 56 |
+
// struct Functor {
|
| 57 |
+
// template <typename T>
|
| 58 |
+
// bool Plus(const T* x, const T* delta, T* x_plus_delta) const;
|
| 59 |
+
//
|
| 60 |
+
// template <typename T>
|
| 61 |
+
// bool Minus(const T* y, const T* x, T* y_minus_x) const;
|
| 62 |
+
// };
|
| 63 |
+
//
|
| 64 |
+
// Observe that the Plus and Minus operations are templated on the parameter T.
|
| 65 |
+
// The autodiff framework substitutes appropriate "Jet" objects for T in order
|
| 66 |
+
// to compute the derivative when necessary. This is the same mechanism that is
|
| 67 |
+
// used to compute derivatives when using AutoDiffCostFunction.
|
| 68 |
+
//
|
| 69 |
+
// Plus and Minus should return true if the computation is successful and false
|
| 70 |
+
// otherwise, in which case the result will not be used.
|
| 71 |
+
//
|
| 72 |
+
// Given this Functor, the corresponding Manifold can be constructed as:
|
| 73 |
+
//
|
| 74 |
+
// AutoDiffManifold<Functor, kAmbientSize, kTangentSize> manifold;
|
| 75 |
+
//
|
| 76 |
+
// As a concrete example consider the case of Quaternions. Quaternions form a
|
| 77 |
+
// three dimensional manifold embedded in R^4, i.e. they have an ambient
|
| 78 |
+
// dimension of 4 and their tangent space has dimension 3. The following Functor
|
| 79 |
+
// (taken from autodiff_manifold_test.cc) defines the Plus and Minus operations
|
| 80 |
+
// on the Quaternion manifold:
|
| 81 |
+
//
|
| 82 |
+
// NOTE: The following is only used for illustration purposes. Ceres Solver
|
| 83 |
+
// ships with optimized production grade QuaternionManifold implementation. See
|
| 84 |
+
// manifold.h.
|
| 85 |
+
//
|
| 86 |
+
// This functor assumes that the quaternions are laid out as [w,x,y,z] in
|
| 87 |
+
// memory, i.e. the real or scalar part is the first coordinate.
|
| 88 |
+
//
|
| 89 |
+
// struct QuaternionFunctor {
|
| 90 |
+
// template <typename T>
|
| 91 |
+
// bool Plus(const T* x, const T* delta, T* x_plus_delta) const {
|
| 92 |
+
// const T squared_norm_delta =
|
| 93 |
+
// delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2];
|
| 94 |
+
//
|
| 95 |
+
// T q_delta[4];
|
| 96 |
+
// if (squared_norm_delta > T(0.0)) {
|
| 97 |
+
// T norm_delta = sqrt(squared_norm_delta);
|
| 98 |
+
// const T sin_delta_by_delta = sin(norm_delta) / norm_delta;
|
| 99 |
+
// q_delta[0] = cos(norm_delta);
|
| 100 |
+
// q_delta[1] = sin_delta_by_delta * delta[0];
|
| 101 |
+
// q_delta[2] = sin_delta_by_delta * delta[1];
|
| 102 |
+
// q_delta[3] = sin_delta_by_delta * delta[2];
|
| 103 |
+
// } else {
|
| 104 |
+
// // We do not just use q_delta = [1,0,0,0] here because that is a
|
| 105 |
+
// // constant and when used for automatic differentiation will
|
| 106 |
+
// // lead to a zero derivative. Instead we take a first order
|
| 107 |
+
// // approximation and evaluate it at zero.
|
| 108 |
+
// q_delta[0] = T(1.0);
|
| 109 |
+
// q_delta[1] = delta[0];
|
| 110 |
+
// q_delta[2] = delta[1];
|
| 111 |
+
// q_delta[3] = delta[2];
|
| 112 |
+
// }
|
| 113 |
+
//
|
| 114 |
+
// QuaternionProduct(q_delta, x, x_plus_delta);
|
| 115 |
+
// return true;
|
| 116 |
+
// }
|
| 117 |
+
//
|
| 118 |
+
// template <typename T>
|
| 119 |
+
// bool Minus(const T* y, const T* x, T* y_minus_x) const {
|
| 120 |
+
// T minus_x[4] = {x[0], -x[1], -x[2], -x[3]};
|
| 121 |
+
// T ambient_y_minus_x[4];
|
| 122 |
+
// QuaternionProduct(y, minus_x, ambient_y_minus_x);
|
| 123 |
+
// T u_norm = sqrt(ambient_y_minus_x[1] * ambient_y_minus_x[1] +
|
| 124 |
+
// ambient_y_minus_x[2] * ambient_y_minus_x[2] +
|
| 125 |
+
// ambient_y_minus_x[3] * ambient_y_minus_x[3]);
|
| 126 |
+
// if (u_norm > 0.0) {
|
| 127 |
+
// T theta = atan2(u_norm, ambient_y_minus_x[0]);
|
| 128 |
+
// y_minus_x[0] = theta * ambient_y_minus_x[1] / u_norm;
|
| 129 |
+
// y_minus_x[1] = theta * ambient_y_minus_x[2] / u_norm;
|
| 130 |
+
// y_minus_x[2] = theta * ambient_y_minus_x[3] / u_norm;
|
| 131 |
+
// } else {
|
| 132 |
+
// // We do not use [0,0,0] here because even though the value part is
|
| 133 |
+
// // a constant, the derivative part is not.
|
| 134 |
+
// y_minus_x[0] = ambient_y_minus_x[1];
|
| 135 |
+
// y_minus_x[1] = ambient_y_minus_x[2];
|
| 136 |
+
// y_minus_x[2] = ambient_y_minus_x[3];
|
| 137 |
+
// }
|
| 138 |
+
// return true;
|
| 139 |
+
// }
|
| 140 |
+
// };
|
| 141 |
+
//
|
| 142 |
+
// Then given this struct, the auto differentiated Quaternion Manifold can now
|
| 143 |
+
// be constructed as
|
| 144 |
+
//
|
| 145 |
+
// Manifold* manifold = new AutoDiffManifold<QuaternionFunctor, 4, 3>;
|
| 146 |
+
|
| 147 |
+
template <typename Functor, int kAmbientSize, int kTangentSize>
|
| 148 |
+
class AutoDiffManifold final : public Manifold {
|
| 149 |
+
public:
|
| 150 |
+
AutoDiffManifold() : functor_(std::make_unique<Functor>()) {}
|
| 151 |
+
|
| 152 |
+
// Takes ownership of functor.
|
| 153 |
+
explicit AutoDiffManifold(Functor* functor) : functor_(functor) {}
|
| 154 |
+
|
| 155 |
+
int AmbientSize() const override { return kAmbientSize; }
|
| 156 |
+
int TangentSize() const override { return kTangentSize; }
|
| 157 |
+
|
| 158 |
+
bool Plus(const double* x,
|
| 159 |
+
const double* delta,
|
| 160 |
+
double* x_plus_delta) const override {
|
| 161 |
+
return functor_->Plus(x, delta, x_plus_delta);
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
bool PlusJacobian(const double* x, double* jacobian) const override;
|
| 165 |
+
|
| 166 |
+
bool Minus(const double* y,
|
| 167 |
+
const double* x,
|
| 168 |
+
double* y_minus_x) const override {
|
| 169 |
+
return functor_->Minus(y, x, y_minus_x);
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
bool MinusJacobian(const double* x, double* jacobian) const override;
|
| 173 |
+
|
| 174 |
+
const Functor& functor() const { return *functor_; }
|
| 175 |
+
|
| 176 |
+
private:
|
| 177 |
+
std::unique_ptr<Functor> functor_;
|
| 178 |
+
};
|
| 179 |
+
|
| 180 |
+
namespace internal {
|
| 181 |
+
|
| 182 |
+
// The following two helper structs are needed to interface the Plus and Minus
|
| 183 |
+
// methods of the ManifoldFunctor with the automatic differentiation which
|
| 184 |
+
// expects a Functor with operator().
|
| 185 |
+
template <typename Functor>
|
| 186 |
+
struct PlusWrapper {
|
| 187 |
+
explicit PlusWrapper(const Functor& functor) : functor(functor) {}
|
| 188 |
+
template <typename T>
|
| 189 |
+
bool operator()(const T* x, const T* delta, T* x_plus_delta) const {
|
| 190 |
+
return functor.Plus(x, delta, x_plus_delta);
|
| 191 |
+
}
|
| 192 |
+
const Functor& functor;
|
| 193 |
+
};
|
| 194 |
+
|
| 195 |
+
template <typename Functor>
|
| 196 |
+
struct MinusWrapper {
|
| 197 |
+
explicit MinusWrapper(const Functor& functor) : functor(functor) {}
|
| 198 |
+
template <typename T>
|
| 199 |
+
bool operator()(const T* y, const T* x, T* y_minus_x) const {
|
| 200 |
+
return functor.Minus(y, x, y_minus_x);
|
| 201 |
+
}
|
| 202 |
+
const Functor& functor;
|
| 203 |
+
};
|
| 204 |
+
} // namespace internal
|
| 205 |
+
|
| 206 |
+
template <typename Functor, int kAmbientSize, int kTangentSize>
|
| 207 |
+
bool AutoDiffManifold<Functor, kAmbientSize, kTangentSize>::PlusJacobian(
|
| 208 |
+
const double* x, double* jacobian) const {
|
| 209 |
+
double zero_delta[kTangentSize];
|
| 210 |
+
for (int i = 0; i < kTangentSize; ++i) {
|
| 211 |
+
zero_delta[i] = 0.0;
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
double x_plus_delta[kAmbientSize];
|
| 215 |
+
for (int i = 0; i < kAmbientSize; ++i) {
|
| 216 |
+
x_plus_delta[i] = 0.0;
|
| 217 |
+
}
|
| 218 |
+
|
| 219 |
+
const double* parameter_ptrs[2] = {x, zero_delta};
|
| 220 |
+
|
| 221 |
+
// PlusJacobian is D_2 Plus(x,0) so we only need to compute the Jacobian
|
| 222 |
+
// w.r.t. the second argument.
|
| 223 |
+
double* jacobian_ptrs[2] = {nullptr, jacobian};
|
| 224 |
+
return internal::AutoDifferentiate<
|
| 225 |
+
kAmbientSize,
|
| 226 |
+
internal::StaticParameterDims<kAmbientSize, kTangentSize>>(
|
| 227 |
+
internal::PlusWrapper<Functor>(*functor_),
|
| 228 |
+
parameter_ptrs,
|
| 229 |
+
kAmbientSize,
|
| 230 |
+
x_plus_delta,
|
| 231 |
+
jacobian_ptrs);
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
template <typename Functor, int kAmbientSize, int kTangentSize>
|
| 235 |
+
bool AutoDiffManifold<Functor, kAmbientSize, kTangentSize>::MinusJacobian(
|
| 236 |
+
const double* x, double* jacobian) const {
|
| 237 |
+
double y_minus_x[kTangentSize];
|
| 238 |
+
for (int i = 0; i < kTangentSize; ++i) {
|
| 239 |
+
y_minus_x[i] = 0.0;
|
| 240 |
+
}
|
| 241 |
+
|
| 242 |
+
const double* parameter_ptrs[2] = {x, x};
|
| 243 |
+
|
| 244 |
+
// MinusJacobian is D_1 Minus(x,x), so we only need to compute the Jacobian
|
| 245 |
+
// w.r.t. the first argument.
|
| 246 |
+
double* jacobian_ptrs[2] = {jacobian, nullptr};
|
| 247 |
+
return internal::AutoDifferentiate<
|
| 248 |
+
kTangentSize,
|
| 249 |
+
internal::StaticParameterDims<kAmbientSize, kAmbientSize>>(
|
| 250 |
+
internal::MinusWrapper<Functor>(*functor_),
|
| 251 |
+
parameter_ptrs,
|
| 252 |
+
kTangentSize,
|
| 253 |
+
y_minus_x,
|
| 254 |
+
jacobian_ptrs);
|
| 255 |
+
}
|
| 256 |
+
|
| 257 |
+
} // namespace ceres
|
| 258 |
+
|
| 259 |
+
#endif // CERES_PUBLIC_AUTODIFF_MANIFOLD_H_
|
include/ceres/c_api.h
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
* Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
* http://ceres-solver.org/
|
| 4 |
+
*
|
| 5 |
+
* Redistribution and use in source and binary forms, with or without
|
| 6 |
+
* modification, are permitted provided that the following conditions are met:
|
| 7 |
+
*
|
| 8 |
+
* - Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
* this list of conditions and the following disclaimer.
|
| 10 |
+
* - Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
* and/or other materials provided with the distribution.
|
| 13 |
+
* - Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
* used to endorse or promote products derived from this software without
|
| 15 |
+
* specific prior written permission.
|
| 16 |
+
*
|
| 17 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
* POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
*
|
| 29 |
+
* Author: mierle@gmail.com (Keir Mierle)
|
| 30 |
+
*
|
| 31 |
+
* A minimal C API for Ceres. Not all functionality is included. This API is
|
| 32 |
+
* not intended for clients of Ceres, but is instead intended for easing the
|
| 33 |
+
* process of binding Ceres to other languages.
|
| 34 |
+
*
|
| 35 |
+
* Currently this is a work in progress.
|
| 36 |
+
*/
|
| 37 |
+
|
| 38 |
+
#ifndef CERES_PUBLIC_C_API_H_
|
| 39 |
+
#define CERES_PUBLIC_C_API_H_
|
| 40 |
+
|
| 41 |
+
// clang-format off
|
| 42 |
+
#include "ceres/internal/export.h"
|
| 43 |
+
#include "ceres/internal/disable_warnings.h"
|
| 44 |
+
// clang-format on
|
| 45 |
+
|
| 46 |
+
#ifdef __cplusplus
|
| 47 |
+
extern "C" {
|
| 48 |
+
#endif
|
| 49 |
+
|
| 50 |
+
/* Init the Ceres private data. Must be called before anything else. */
|
| 51 |
+
CERES_EXPORT void ceres_init();
|
| 52 |
+
|
| 53 |
+
/* Equivalent to CostFunction::Evaluate() in the C++ API.
|
| 54 |
+
*
|
| 55 |
+
* The user may keep private information inside the opaque user_data object.
|
| 56 |
+
* The pointer here is the same one passed in the ceres_add_residual_block().
|
| 57 |
+
*/
|
| 58 |
+
typedef int (*ceres_cost_function_t)(void* user_data,
|
| 59 |
+
double** parameters,
|
| 60 |
+
double* residuals,
|
| 61 |
+
double** jacobians);
|
| 62 |
+
|
| 63 |
+
/* Equivalent to LossFunction::Evaluate() from the C++ API. */
|
| 64 |
+
typedef void (*ceres_loss_function_t)(void* user_data,
|
| 65 |
+
double squared_norm,
|
| 66 |
+
double out[3]);
|
| 67 |
+
|
| 68 |
+
/* Create callback data for Ceres' stock loss functions.
|
| 69 |
+
*
|
| 70 |
+
* Ceres has several loss functions available by default, and these functions
|
| 71 |
+
* expose those to the C API. To use the stock loss functions, call
|
| 72 |
+
* ceres_create_*_loss_data(), which internally creates an instance of one of
|
| 73 |
+
* the stock loss functions (for example ceres::CauchyLoss), and pass the
|
| 74 |
+
* returned "loss_function_data" along with the ceres_stock_loss_function to
|
| 75 |
+
* ceres_add_residual_block().
|
| 76 |
+
*
|
| 77 |
+
* For example:
|
| 78 |
+
*
|
| 79 |
+
* void* cauchy_loss_function_data =
|
| 80 |
+
* ceres_create_cauchy_loss_function_data(1.2, 0.0);
|
| 81 |
+
* ceres_problem_add_residual_block(
|
| 82 |
+
* problem,
|
| 83 |
+
* my_cost_function,
|
| 84 |
+
* my_cost_function_data,
|
| 85 |
+
* ceres_stock_loss_function,
|
| 86 |
+
* cauchy_loss_function_data,
|
| 87 |
+
* 1,
|
| 88 |
+
* 2,
|
| 89 |
+
* parameter_sizes,
|
| 90 |
+
* parameter_pointers);
|
| 91 |
+
* ...
|
| 92 |
+
* ceres_free_stock_loss_function_data(cauchy_loss_function_data);
|
| 93 |
+
*
|
| 94 |
+
* See loss_function.h for the details of each loss function.
|
| 95 |
+
*/
|
| 96 |
+
CERES_EXPORT void* ceres_create_huber_loss_function_data(double a);
|
| 97 |
+
CERES_EXPORT void* ceres_create_softl1_loss_function_data(double a);
|
| 98 |
+
CERES_EXPORT void* ceres_create_cauchy_loss_function_data(double a);
|
| 99 |
+
CERES_EXPORT void* ceres_create_arctan_loss_function_data(double a);
|
| 100 |
+
CERES_EXPORT void* ceres_create_tolerant_loss_function_data(double a, double b);
|
| 101 |
+
|
| 102 |
+
/* Free the given stock loss function data. */
|
| 103 |
+
CERES_EXPORT void ceres_free_stock_loss_function_data(void* loss_function_data);
|
| 104 |
+
|
| 105 |
+
/* This is an implementation of ceres_loss_function_t contained within Ceres
|
| 106 |
+
* itself, intended as a way to access the various stock Ceres loss functions
|
| 107 |
+
* from the C API. This should be passed to ceres_add_residual() below, in
|
| 108 |
+
* combination with a user_data pointer generated by
|
| 109 |
+
* ceres_create_stock_loss_function() above. */
|
| 110 |
+
CERES_EXPORT void ceres_stock_loss_function(void* user_data,
|
| 111 |
+
double squared_norm,
|
| 112 |
+
double out[3]);
|
| 113 |
+
|
| 114 |
+
/* Equivalent to Problem from the C++ API. */
|
| 115 |
+
struct ceres_problem_s;
|
| 116 |
+
typedef struct ceres_problem_s ceres_problem_t;
|
| 117 |
+
|
| 118 |
+
struct ceres_residual_block_id_s;
|
| 119 |
+
typedef struct ceres_residual_block_id_s ceres_residual_block_id_t;
|
| 120 |
+
|
| 121 |
+
/* Create and destroy a problem */
|
| 122 |
+
/* TODO(keir): Add options for the problem. */
|
| 123 |
+
CERES_EXPORT ceres_problem_t* ceres_create_problem();
|
| 124 |
+
CERES_EXPORT void ceres_free_problem(ceres_problem_t* problem);
|
| 125 |
+
|
| 126 |
+
/* Add a residual block. */
|
| 127 |
+
CERES_EXPORT ceres_residual_block_id_t* ceres_problem_add_residual_block(
|
| 128 |
+
ceres_problem_t* problem,
|
| 129 |
+
ceres_cost_function_t cost_function,
|
| 130 |
+
void* cost_function_data,
|
| 131 |
+
ceres_loss_function_t loss_function,
|
| 132 |
+
void* loss_function_data,
|
| 133 |
+
int num_residuals,
|
| 134 |
+
int num_parameter_blocks,
|
| 135 |
+
int* parameter_block_sizes,
|
| 136 |
+
double** parameters);
|
| 137 |
+
|
| 138 |
+
CERES_EXPORT void ceres_solve(ceres_problem_t* problem);
|
| 139 |
+
|
| 140 |
+
/* TODO(keir): Figure out a way to pass a config in. */
|
| 141 |
+
|
| 142 |
+
#ifdef __cplusplus
|
| 143 |
+
}
|
| 144 |
+
#endif
|
| 145 |
+
|
| 146 |
+
#include "ceres/internal/reenable_warnings.h"
|
| 147 |
+
|
| 148 |
+
#endif /* CERES_PUBLIC_C_API_H_ */
|
include/ceres/ceres.h
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2022 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: keir@google.com (Keir Mierle)
|
| 30 |
+
//
|
| 31 |
+
// This is a forwarding header containing the public symbols exported from
|
| 32 |
+
// Ceres. Anything in the "ceres" namespace is available for use.
|
| 33 |
+
|
| 34 |
+
#ifndef CERES_PUBLIC_CERES_H_
|
| 35 |
+
#define CERES_PUBLIC_CERES_H_
|
| 36 |
+
|
| 37 |
+
#include "ceres/autodiff_cost_function.h"
|
| 38 |
+
#include "ceres/autodiff_first_order_function.h"
|
| 39 |
+
#include "ceres/autodiff_local_parameterization.h"
|
| 40 |
+
#include "ceres/autodiff_manifold.h"
|
| 41 |
+
#include "ceres/conditioned_cost_function.h"
|
| 42 |
+
#include "ceres/context.h"
|
| 43 |
+
#include "ceres/cost_function.h"
|
| 44 |
+
#include "ceres/cost_function_to_functor.h"
|
| 45 |
+
#include "ceres/covariance.h"
|
| 46 |
+
#include "ceres/crs_matrix.h"
|
| 47 |
+
#include "ceres/dynamic_autodiff_cost_function.h"
|
| 48 |
+
#include "ceres/dynamic_cost_function.h"
|
| 49 |
+
#include "ceres/dynamic_cost_function_to_functor.h"
|
| 50 |
+
#include "ceres/dynamic_numeric_diff_cost_function.h"
|
| 51 |
+
#include "ceres/evaluation_callback.h"
|
| 52 |
+
#include "ceres/first_order_function.h"
|
| 53 |
+
#include "ceres/gradient_checker.h"
|
| 54 |
+
#include "ceres/gradient_problem.h"
|
| 55 |
+
#include "ceres/gradient_problem_solver.h"
|
| 56 |
+
#include "ceres/iteration_callback.h"
|
| 57 |
+
#include "ceres/jet.h"
|
| 58 |
+
#include "ceres/line_manifold.h"
|
| 59 |
+
#include "ceres/local_parameterization.h"
|
| 60 |
+
#include "ceres/loss_function.h"
|
| 61 |
+
#include "ceres/manifold.h"
|
| 62 |
+
#include "ceres/numeric_diff_cost_function.h"
|
| 63 |
+
#include "ceres/numeric_diff_first_order_function.h"
|
| 64 |
+
#include "ceres/numeric_diff_options.h"
|
| 65 |
+
#include "ceres/ordered_groups.h"
|
| 66 |
+
#include "ceres/problem.h"
|
| 67 |
+
#include "ceres/product_manifold.h"
|
| 68 |
+
#include "ceres/sized_cost_function.h"
|
| 69 |
+
#include "ceres/solver.h"
|
| 70 |
+
#include "ceres/sphere_manifold.h"
|
| 71 |
+
#include "ceres/types.h"
|
| 72 |
+
#include "ceres/version.h"
|
| 73 |
+
|
| 74 |
+
#endif // CERES_PUBLIC_CERES_H_
|
include/ceres/conditioned_cost_function.h
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: wjr@google.com (William Rucklidge)
|
| 30 |
+
//
|
| 31 |
+
// This file contains a cost function that can apply a transformation to
|
| 32 |
+
// each residual value before they are square-summed.
|
| 33 |
+
|
| 34 |
+
#ifndef CERES_PUBLIC_CONDITIONED_COST_FUNCTION_H_
|
| 35 |
+
#define CERES_PUBLIC_CONDITIONED_COST_FUNCTION_H_
|
| 36 |
+
|
| 37 |
+
#include <memory>
|
| 38 |
+
#include <vector>
|
| 39 |
+
|
| 40 |
+
#include "ceres/cost_function.h"
|
| 41 |
+
#include "ceres/internal/disable_warnings.h"
|
| 42 |
+
#include "ceres/types.h"
|
| 43 |
+
|
| 44 |
+
namespace ceres {
|
| 45 |
+
|
| 46 |
+
// This class allows you to apply different conditioning to the residual
|
| 47 |
+
// values of a wrapped cost function. An example where this is useful is
|
| 48 |
+
// where you have an existing cost function that produces N values, but you
|
| 49 |
+
// want the total cost to be something other than just the sum of these
|
| 50 |
+
// squared values - maybe you want to apply a different scaling to some
|
| 51 |
+
// values, to change their contribution to the cost.
|
| 52 |
+
//
|
| 53 |
+
// Usage:
|
| 54 |
+
//
|
| 55 |
+
// // my_cost_function produces N residuals
|
| 56 |
+
// CostFunction* my_cost_function = ...
|
| 57 |
+
// CHECK_EQ(N, my_cost_function->num_residuals());
|
| 58 |
+
// vector<CostFunction*> conditioners;
|
| 59 |
+
//
|
| 60 |
+
// // Make N 1x1 cost functions (1 parameter, 1 residual)
|
| 61 |
+
// CostFunction* f_1 = ...
|
| 62 |
+
// conditioners.push_back(f_1);
|
| 63 |
+
// ...
|
| 64 |
+
// CostFunction* f_N = ...
|
| 65 |
+
// conditioners.push_back(f_N);
|
| 66 |
+
// ConditionedCostFunction* ccf =
|
| 67 |
+
// new ConditionedCostFunction(my_cost_function, conditioners);
|
| 68 |
+
//
|
| 69 |
+
// Now ccf's residual i (i=0..N-1) will be passed though the i'th conditioner.
|
| 70 |
+
//
|
| 71 |
+
// ccf_residual[i] = f_i(my_cost_function_residual[i])
|
| 72 |
+
//
|
| 73 |
+
// and the Jacobian will be affected appropriately.
|
| 74 |
+
class CERES_EXPORT ConditionedCostFunction final : public CostFunction {
|
| 75 |
+
public:
|
| 76 |
+
// Builds a cost function based on a wrapped cost function, and a
|
| 77 |
+
// per-residual conditioner. Takes ownership of all of the wrapped cost
|
| 78 |
+
// functions, or not, depending on the ownership parameter. Conditioners
|
| 79 |
+
// may be nullptr, in which case the corresponding residual is not modified.
|
| 80 |
+
//
|
| 81 |
+
// The conditioners can repeat.
|
| 82 |
+
ConditionedCostFunction(CostFunction* wrapped_cost_function,
|
| 83 |
+
const std::vector<CostFunction*>& conditioners,
|
| 84 |
+
Ownership ownership);
|
| 85 |
+
~ConditionedCostFunction() override;
|
| 86 |
+
|
| 87 |
+
bool Evaluate(double const* const* parameters,
|
| 88 |
+
double* residuals,
|
| 89 |
+
double** jacobians) const override;
|
| 90 |
+
|
| 91 |
+
private:
|
| 92 |
+
std::unique_ptr<CostFunction> wrapped_cost_function_;
|
| 93 |
+
std::vector<CostFunction*> conditioners_;
|
| 94 |
+
Ownership ownership_;
|
| 95 |
+
};
|
| 96 |
+
|
| 97 |
+
} // namespace ceres
|
| 98 |
+
|
| 99 |
+
#include "ceres/internal/reenable_warnings.h"
|
| 100 |
+
|
| 101 |
+
#endif // CERES_PUBLIC_CONDITIONED_COST_FUNCTION_H_
|
include/ceres/context.h
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: vitus@google.com (Michael Vitus)
|
| 30 |
+
|
| 31 |
+
#ifndef CERES_PUBLIC_CONTEXT_H_
|
| 32 |
+
#define CERES_PUBLIC_CONTEXT_H_
|
| 33 |
+
|
| 34 |
+
#include "ceres/internal/export.h"
|
| 35 |
+
|
| 36 |
+
namespace ceres {
|
| 37 |
+
|
| 38 |
+
// A global context for processing data in Ceres. This provides a mechanism to
|
| 39 |
+
// allow Ceres to reuse items that are expensive to create between multiple
|
| 40 |
+
// calls; for example, thread pools. The same Context can be used on multiple
|
| 41 |
+
// Problems, either serially or in parallel. When using it with multiple
|
| 42 |
+
// Problems at the same time, they may end up contending for resources
|
| 43 |
+
// (e.g. threads) managed by the Context.
|
| 44 |
+
class CERES_EXPORT Context {
|
| 45 |
+
public:
|
| 46 |
+
Context();
|
| 47 |
+
Context(const Context&) = delete;
|
| 48 |
+
void operator=(const Context&) = delete;
|
| 49 |
+
|
| 50 |
+
virtual ~Context();
|
| 51 |
+
|
| 52 |
+
// Creates a context object and the caller takes ownership.
|
| 53 |
+
static Context* Create();
|
| 54 |
+
};
|
| 55 |
+
|
| 56 |
+
} // namespace ceres
|
| 57 |
+
|
| 58 |
+
#endif // CERES_PUBLIC_CONTEXT_H_
|
include/ceres/cost_function.h
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: sameeragarwal@google.com (Sameer Agarwal)
|
| 30 |
+
// keir@google.m (Keir Mierle)
|
| 31 |
+
//
|
| 32 |
+
// This is the interface through which the least squares solver accesses the
|
| 33 |
+
// residual and Jacobian of the least squares problem. Users are expected to
|
| 34 |
+
// subclass CostFunction to define their own terms in the least squares problem.
|
| 35 |
+
//
|
| 36 |
+
// It is recommended that users define templated residual functors for use as
|
| 37 |
+
// arguments for AutoDiffCostFunction (see autodiff_cost_function.h), instead of
|
| 38 |
+
// directly implementing the CostFunction interface. This often results in both
|
| 39 |
+
// shorter code and faster execution than hand-coded derivatives. However,
|
| 40 |
+
// specialized cases may demand direct implementation of the lower-level
|
| 41 |
+
// CostFunction interface; for example, this is true when calling legacy code
|
| 42 |
+
// which is not templated on numeric types.
|
| 43 |
+
|
| 44 |
+
#ifndef CERES_PUBLIC_COST_FUNCTION_H_
|
| 45 |
+
#define CERES_PUBLIC_COST_FUNCTION_H_
|
| 46 |
+
|
| 47 |
+
#include <cstdint>
|
| 48 |
+
#include <vector>
|
| 49 |
+
|
| 50 |
+
#include "ceres/internal/disable_warnings.h"
|
| 51 |
+
#include "ceres/internal/export.h"
|
| 52 |
+
|
| 53 |
+
namespace ceres {
|
| 54 |
+
|
| 55 |
+
// This class implements the computation of the cost (a.k.a. residual) terms as
|
| 56 |
+
// a function of the input (control) variables, and is the interface for users
|
| 57 |
+
// to describe their least squares problem to Ceres. In other words, this is the
|
| 58 |
+
// modeling layer between users and the Ceres optimizer. The signature of the
|
| 59 |
+
// function (number and sizes of input parameter blocks and number of outputs)
|
| 60 |
+
// is stored in parameter_block_sizes_ and num_residuals_ respectively. User
|
| 61 |
+
// code inheriting from this class is expected to set these two members with the
|
| 62 |
+
// corresponding accessors. This information will be verified by the Problem
|
| 63 |
+
// when added with AddResidualBlock().
|
| 64 |
+
class CERES_EXPORT CostFunction {
|
| 65 |
+
public:
|
| 66 |
+
CostFunction();
|
| 67 |
+
CostFunction(const CostFunction&) = delete;
|
| 68 |
+
void operator=(const CostFunction&) = delete;
|
| 69 |
+
|
| 70 |
+
virtual ~CostFunction();
|
| 71 |
+
|
| 72 |
+
// Inputs:
|
| 73 |
+
//
|
| 74 |
+
// parameters is an array of pointers to arrays containing the
|
| 75 |
+
// various parameter blocks. parameters has the same number of
|
| 76 |
+
// elements as parameter_block_sizes_. Parameter blocks are in the
|
| 77 |
+
// same order as parameter_block_sizes_.i.e.,
|
| 78 |
+
//
|
| 79 |
+
// parameters_[i] = double[parameter_block_sizes_[i]]
|
| 80 |
+
//
|
| 81 |
+
// Outputs:
|
| 82 |
+
//
|
| 83 |
+
// residuals is an array of size num_residuals_.
|
| 84 |
+
//
|
| 85 |
+
// jacobians is an array of size parameter_block_sizes_ containing
|
| 86 |
+
// pointers to storage for jacobian blocks corresponding to each
|
| 87 |
+
// parameter block. Jacobian blocks are in the same order as
|
| 88 |
+
// parameter_block_sizes, i.e. jacobians[i], is an
|
| 89 |
+
// array that contains num_residuals_* parameter_block_sizes_[i]
|
| 90 |
+
// elements. Each jacobian block is stored in row-major order, i.e.,
|
| 91 |
+
//
|
| 92 |
+
// jacobians[i][r*parameter_block_size_[i] + c] =
|
| 93 |
+
// d residual[r] / d parameters[i][c]
|
| 94 |
+
//
|
| 95 |
+
// If jacobians is nullptr, then no derivatives are returned; this is
|
| 96 |
+
// the case when computing cost only. If jacobians[i] is nullptr, then
|
| 97 |
+
// the jacobian block corresponding to the i'th parameter block must
|
| 98 |
+
// not to be returned.
|
| 99 |
+
//
|
| 100 |
+
// The return value indicates whether the computation of the
|
| 101 |
+
// residuals and/or jacobians was successful or not.
|
| 102 |
+
//
|
| 103 |
+
// This can be used to communicate numerical failures in jacobian
|
| 104 |
+
// computations for instance.
|
| 105 |
+
//
|
| 106 |
+
// A more interesting and common use is to impose constraints on the
|
| 107 |
+
// parameters. If the initial values of the parameter blocks satisfy
|
| 108 |
+
// the constraints, then returning false whenever the constraints
|
| 109 |
+
// are not satisfied will prevent the solver from moving into the
|
| 110 |
+
// infeasible region. This is not a very sophisticated mechanism for
|
| 111 |
+
// enforcing constraints, but is often good enough.
|
| 112 |
+
//
|
| 113 |
+
// Note that it is important that the initial values of the
|
| 114 |
+
// parameter block must be feasible, otherwise the solver will
|
| 115 |
+
// declare a numerical problem at iteration 0.
|
| 116 |
+
virtual bool Evaluate(double const* const* parameters,
|
| 117 |
+
double* residuals,
|
| 118 |
+
double** jacobians) const = 0;
|
| 119 |
+
|
| 120 |
+
const std::vector<int32_t>& parameter_block_sizes() const {
|
| 121 |
+
return parameter_block_sizes_;
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
int num_residuals() const { return num_residuals_; }
|
| 125 |
+
|
| 126 |
+
protected:
|
| 127 |
+
std::vector<int32_t>* mutable_parameter_block_sizes() {
|
| 128 |
+
return ¶meter_block_sizes_;
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
void set_num_residuals(int num_residuals) { num_residuals_ = num_residuals; }
|
| 132 |
+
|
| 133 |
+
private:
|
| 134 |
+
// Cost function signature metadata: number of inputs & their sizes,
|
| 135 |
+
// number of outputs (residuals).
|
| 136 |
+
std::vector<int32_t> parameter_block_sizes_;
|
| 137 |
+
int num_residuals_;
|
| 138 |
+
};
|
| 139 |
+
|
| 140 |
+
} // namespace ceres
|
| 141 |
+
|
| 142 |
+
#include "ceres/internal/reenable_warnings.h"
|
| 143 |
+
|
| 144 |
+
#endif // CERES_PUBLIC_COST_FUNCTION_H_
|
include/ceres/cost_function_to_functor.h
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: sameeragarwal@google.com (Sameer Agarwal)
|
| 30 |
+
//
|
| 31 |
+
// CostFunctionToFunctor is an adapter class that allows users to use
|
| 32 |
+
// SizedCostFunction objects in templated functors which are to be used for
|
| 33 |
+
// automatic differentiation. This allows the user to seamlessly mix
|
| 34 |
+
// analytic, numeric and automatic differentiation.
|
| 35 |
+
//
|
| 36 |
+
// For example, let us assume that
|
| 37 |
+
//
|
| 38 |
+
// class IntrinsicProjection : public SizedCostFunction<2, 5, 3> {
|
| 39 |
+
// public:
|
| 40 |
+
// IntrinsicProjection(const double* observation);
|
| 41 |
+
// bool Evaluate(double const* const* parameters,
|
| 42 |
+
// double* residuals,
|
| 43 |
+
// double** jacobians) const override;
|
| 44 |
+
// };
|
| 45 |
+
//
|
| 46 |
+
// is a cost function that implements the projection of a point in its
|
| 47 |
+
// local coordinate system onto its image plane and subtracts it from
|
| 48 |
+
// the observed point projection. It can compute its residual and
|
| 49 |
+
// jacobians either via analytic or numerical differentiation.
|
| 50 |
+
//
|
| 51 |
+
// Now we would like to compose the action of this CostFunction with
|
| 52 |
+
// the action of camera extrinsics, i.e., rotation and
|
| 53 |
+
// translation. Say we have a templated function
|
| 54 |
+
//
|
| 55 |
+
// template<typename T>
|
| 56 |
+
// void RotateAndTranslatePoint(const T* rotation,
|
| 57 |
+
// const T* translation,
|
| 58 |
+
// const T* point,
|
| 59 |
+
// T* result);
|
| 60 |
+
//
|
| 61 |
+
// Then we can now do the following,
|
| 62 |
+
//
|
| 63 |
+
// struct CameraProjection {
|
| 64 |
+
// CameraProjection(const double* observation)
|
| 65 |
+
// : intrinsic_projection_(new IntrinsicProjection(observation)) {
|
| 66 |
+
// }
|
| 67 |
+
// template <typename T>
|
| 68 |
+
// bool operator()(const T* rotation,
|
| 69 |
+
// const T* translation,
|
| 70 |
+
// const T* intrinsics,
|
| 71 |
+
// const T* point,
|
| 72 |
+
// T* residual) const {
|
| 73 |
+
// T transformed_point[3];
|
| 74 |
+
// RotateAndTranslatePoint(rotation, translation, point, transformed_point);
|
| 75 |
+
//
|
| 76 |
+
// // Note that we call intrinsic_projection_, just like it was
|
| 77 |
+
// // any other templated functor.
|
| 78 |
+
//
|
| 79 |
+
// return intrinsic_projection_(intrinsics, transformed_point, residual);
|
| 80 |
+
// }
|
| 81 |
+
//
|
| 82 |
+
// private:
|
| 83 |
+
// CostFunctionToFunctor<2,5,3> intrinsic_projection_;
|
| 84 |
+
// };
|
| 85 |
+
|
| 86 |
+
#ifndef CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_
|
| 87 |
+
#define CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_
|
| 88 |
+
|
| 89 |
+
#include <cstdint>
|
| 90 |
+
#include <numeric>
|
| 91 |
+
#include <tuple>
|
| 92 |
+
#include <utility>
|
| 93 |
+
#include <vector>
|
| 94 |
+
|
| 95 |
+
#include "ceres/cost_function.h"
|
| 96 |
+
#include "ceres/dynamic_cost_function_to_functor.h"
|
| 97 |
+
#include "ceres/internal/export.h"
|
| 98 |
+
#include "ceres/internal/fixed_array.h"
|
| 99 |
+
#include "ceres/internal/parameter_dims.h"
|
| 100 |
+
#include "ceres/types.h"
|
| 101 |
+
#include "glog/logging.h"
|
| 102 |
+
|
| 103 |
+
namespace ceres {
|
| 104 |
+
|
| 105 |
+
template <int kNumResiduals, int... Ns>
|
| 106 |
+
class CostFunctionToFunctor {
|
| 107 |
+
public:
|
| 108 |
+
// Takes ownership of cost_function.
|
| 109 |
+
explicit CostFunctionToFunctor(CostFunction* cost_function)
|
| 110 |
+
: cost_functor_(cost_function) {
|
| 111 |
+
CHECK(cost_function != nullptr);
|
| 112 |
+
CHECK(kNumResiduals > 0 || kNumResiduals == DYNAMIC);
|
| 113 |
+
|
| 114 |
+
const std::vector<int32_t>& parameter_block_sizes =
|
| 115 |
+
cost_function->parameter_block_sizes();
|
| 116 |
+
const int num_parameter_blocks = ParameterDims::kNumParameterBlocks;
|
| 117 |
+
CHECK_EQ(static_cast<int>(parameter_block_sizes.size()),
|
| 118 |
+
num_parameter_blocks);
|
| 119 |
+
|
| 120 |
+
if (parameter_block_sizes.size() == num_parameter_blocks) {
|
| 121 |
+
for (int block = 0; block < num_parameter_blocks; ++block) {
|
| 122 |
+
CHECK_EQ(ParameterDims::GetDim(block), parameter_block_sizes[block])
|
| 123 |
+
<< "Parameter block size missmatch. The specified static parameter "
|
| 124 |
+
"block dimension does not match the one from the cost function.";
|
| 125 |
+
}
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
CHECK_EQ(accumulate(
|
| 129 |
+
parameter_block_sizes.begin(), parameter_block_sizes.end(), 0),
|
| 130 |
+
ParameterDims::kNumParameters);
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
template <typename T, typename... Ts>
|
| 134 |
+
bool operator()(const T* p1, Ts*... ps) const {
|
| 135 |
+
// Add one because of residual block.
|
| 136 |
+
static_assert(sizeof...(Ts) + 1 == ParameterDims::kNumParameterBlocks + 1,
|
| 137 |
+
"Invalid number of parameter blocks specified.");
|
| 138 |
+
|
| 139 |
+
auto params = std::make_tuple(p1, ps...);
|
| 140 |
+
|
| 141 |
+
// Extract residual pointer from params. The residual pointer is the
|
| 142 |
+
// last pointer.
|
| 143 |
+
constexpr int kResidualIndex = ParameterDims::kNumParameterBlocks;
|
| 144 |
+
T* residuals = std::get<kResidualIndex>(params);
|
| 145 |
+
|
| 146 |
+
// Extract parameter block pointers from params.
|
| 147 |
+
using Indices =
|
| 148 |
+
std::make_integer_sequence<int, ParameterDims::kNumParameterBlocks>;
|
| 149 |
+
std::array<const T*, ParameterDims::kNumParameterBlocks> parameter_blocks =
|
| 150 |
+
GetParameterPointers<T>(params, Indices());
|
| 151 |
+
|
| 152 |
+
return cost_functor_(parameter_blocks.data(), residuals);
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
private:
|
| 156 |
+
using ParameterDims = internal::StaticParameterDims<Ns...>;
|
| 157 |
+
|
| 158 |
+
template <typename T, typename Tuple, int... Indices>
|
| 159 |
+
static std::array<const T*, ParameterDims::kNumParameterBlocks>
|
| 160 |
+
GetParameterPointers(const Tuple& paramPointers,
|
| 161 |
+
std::integer_sequence<int, Indices...>) {
|
| 162 |
+
return std::array<const T*, ParameterDims::kNumParameterBlocks>{
|
| 163 |
+
{std::get<Indices>(paramPointers)...}};
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
DynamicCostFunctionToFunctor cost_functor_;
|
| 167 |
+
};
|
| 168 |
+
|
| 169 |
+
} // namespace ceres
|
| 170 |
+
|
| 171 |
+
#endif // CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_
|
include/ceres/covariance.h
ADDED
|
@@ -0,0 +1,459 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: sameeragarwal@google.com (Sameer Agarwal)
|
| 30 |
+
|
| 31 |
+
#ifndef CERES_PUBLIC_COVARIANCE_H_
|
| 32 |
+
#define CERES_PUBLIC_COVARIANCE_H_
|
| 33 |
+
|
| 34 |
+
#include <memory>
|
| 35 |
+
#include <utility>
|
| 36 |
+
#include <vector>
|
| 37 |
+
|
| 38 |
+
#include "ceres/internal/config.h"
|
| 39 |
+
#include "ceres/internal/disable_warnings.h"
|
| 40 |
+
#include "ceres/internal/export.h"
|
| 41 |
+
#include "ceres/types.h"
|
| 42 |
+
|
| 43 |
+
namespace ceres {
|
| 44 |
+
|
| 45 |
+
class Problem;
|
| 46 |
+
|
| 47 |
+
namespace internal {
|
| 48 |
+
class CovarianceImpl;
|
| 49 |
+
} // namespace internal
|
| 50 |
+
|
| 51 |
+
// WARNING
|
| 52 |
+
// =======
|
| 53 |
+
// It is very easy to use this class incorrectly without understanding
|
| 54 |
+
// the underlying mathematics. Please read and understand the
|
| 55 |
+
// documentation completely before attempting to use it.
|
| 56 |
+
//
|
| 57 |
+
//
|
| 58 |
+
// This class allows the user to evaluate the covariance for a
|
| 59 |
+
// non-linear least squares problem and provides random access to its
|
| 60 |
+
// blocks
|
| 61 |
+
//
|
| 62 |
+
// Background
|
| 63 |
+
// ==========
|
| 64 |
+
// One way to assess the quality of the solution returned by a
|
| 65 |
+
// non-linear least squares solver is to analyze the covariance of the
|
| 66 |
+
// solution.
|
| 67 |
+
//
|
| 68 |
+
// Let us consider the non-linear regression problem
|
| 69 |
+
//
|
| 70 |
+
// y = f(x) + N(0, I)
|
| 71 |
+
//
|
| 72 |
+
// i.e., the observation y is a random non-linear function of the
|
| 73 |
+
// independent variable x with mean f(x) and identity covariance. Then
|
| 74 |
+
// the maximum likelihood estimate of x given observations y is the
|
| 75 |
+
// solution to the non-linear least squares problem:
|
| 76 |
+
//
|
| 77 |
+
// x* = arg min_x |f(x) - y|^2
|
| 78 |
+
//
|
| 79 |
+
// And the covariance of x* is given by
|
| 80 |
+
//
|
| 81 |
+
// C(x*) = inverse[J'(x*)J(x*)]
|
| 82 |
+
//
|
| 83 |
+
// Here J(x*) is the Jacobian of f at x*. The above formula assumes
|
| 84 |
+
// that J(x*) has full column rank.
|
| 85 |
+
//
|
| 86 |
+
// If J(x*) is rank deficient, then the covariance matrix C(x*) is
|
| 87 |
+
// also rank deficient and is given by
|
| 88 |
+
//
|
| 89 |
+
// C(x*) = pseudoinverse[J'(x*)J(x*)]
|
| 90 |
+
//
|
| 91 |
+
// Note that in the above, we assumed that the covariance
|
| 92 |
+
// matrix for y was identity. This is an important assumption. If this
|
| 93 |
+
// is not the case and we have
|
| 94 |
+
//
|
| 95 |
+
// y = f(x) + N(0, S)
|
| 96 |
+
//
|
| 97 |
+
// Where S is a positive semi-definite matrix denoting the covariance
|
| 98 |
+
// of y, then the maximum likelihood problem to be solved is
|
| 99 |
+
//
|
| 100 |
+
// x* = arg min_x f'(x) inverse[S] f(x)
|
| 101 |
+
//
|
| 102 |
+
// and the corresponding covariance estimate of x* is given by
|
| 103 |
+
//
|
| 104 |
+
// C(x*) = inverse[J'(x*) inverse[S] J(x*)]
|
| 105 |
+
//
|
| 106 |
+
// So, if it is the case that the observations being fitted to have a
|
| 107 |
+
// covariance matrix not equal to identity, then it is the user's
|
| 108 |
+
// responsibility that the corresponding cost functions are correctly
|
| 109 |
+
// scaled, e.g. in the above case the cost function for this problem
|
| 110 |
+
// should evaluate S^{-1/2} f(x) instead of just f(x), where S^{-1/2}
|
| 111 |
+
// is the inverse square root of the covariance matrix S.
|
| 112 |
+
//
|
| 113 |
+
// This class allows the user to evaluate the covariance for a
|
| 114 |
+
// non-linear least squares problem and provides random access to its
|
| 115 |
+
// blocks. The computation assumes that the CostFunctions compute
|
| 116 |
+
// residuals such that their covariance is identity.
|
| 117 |
+
//
|
| 118 |
+
// Since the computation of the covariance matrix requires computing
|
| 119 |
+
// the inverse of a potentially large matrix, this can involve a
|
| 120 |
+
// rather large amount of time and memory. However, it is usually the
|
| 121 |
+
// case that the user is only interested in a small part of the
|
| 122 |
+
// covariance matrix. Quite often just the block diagonal. This class
|
| 123 |
+
// allows the user to specify the parts of the covariance matrix that
|
| 124 |
+
// she is interested in and then uses this information to only compute
|
| 125 |
+
// and store those parts of the covariance matrix.
|
| 126 |
+
//
|
| 127 |
+
// Rank of the Jacobian
|
| 128 |
+
// --------------------
|
| 129 |
+
// As we noted above, if the jacobian is rank deficient, then the
|
| 130 |
+
// inverse of J'J is not defined and instead a pseudo inverse needs to
|
| 131 |
+
// be computed.
|
| 132 |
+
//
|
| 133 |
+
// The rank deficiency in J can be structural -- columns which are
|
| 134 |
+
// always known to be zero or numerical -- depending on the exact
|
| 135 |
+
// values in the Jacobian.
|
| 136 |
+
//
|
| 137 |
+
// Structural rank deficiency occurs when the problem contains
|
| 138 |
+
// parameter blocks that are constant. This class correctly handles
|
| 139 |
+
// structural rank deficiency like that.
|
| 140 |
+
//
|
| 141 |
+
// Numerical rank deficiency, where the rank of the matrix cannot be
|
| 142 |
+
// predicted by its sparsity structure and requires looking at its
|
| 143 |
+
// numerical values is more complicated. Here again there are two
|
| 144 |
+
// cases.
|
| 145 |
+
//
|
| 146 |
+
// a. The rank deficiency arises from overparameterization. e.g., a
|
| 147 |
+
// four dimensional quaternion used to parameterize SO(3), which is
|
| 148 |
+
// a three dimensional manifold. In cases like this, the user should
|
| 149 |
+
// use an appropriate LocalParameterization/Manifold. Not only will this lead
|
| 150 |
+
// to better numerical behaviour of the Solver, it will also expose
|
| 151 |
+
// the rank deficiency to the Covariance object so that it can
|
| 152 |
+
// handle it correctly.
|
| 153 |
+
//
|
| 154 |
+
// b. More general numerical rank deficiency in the Jacobian
|
| 155 |
+
// requires the computation of the so called Singular Value
|
| 156 |
+
// Decomposition (SVD) of J'J. We do not know how to do this for
|
| 157 |
+
// large sparse matrices efficiently. For small and moderate sized
|
| 158 |
+
// problems this is done using dense linear algebra.
|
| 159 |
+
//
|
| 160 |
+
// Gauge Invariance
|
| 161 |
+
// ----------------
|
| 162 |
+
// In structure from motion (3D reconstruction) problems, the
|
| 163 |
+
// reconstruction is ambiguous up to a similarity transform. This is
|
| 164 |
+
// known as a Gauge Ambiguity. Handling Gauges correctly requires the
|
| 165 |
+
// use of SVD or custom inversion algorithms. For small problems the
|
| 166 |
+
// user can use the dense algorithm. For more details see
|
| 167 |
+
//
|
| 168 |
+
// Ken-ichi Kanatani, Daniel D. Morris: Gauges and gauge
|
| 169 |
+
// transformations for uncertainty description of geometric structure
|
| 170 |
+
// with indeterminacy. IEEE Transactions on Information Theory 47(5):
|
| 171 |
+
// 2017-2028 (2001)
|
| 172 |
+
//
|
| 173 |
+
// Example Usage
|
| 174 |
+
// =============
|
| 175 |
+
//
|
| 176 |
+
// double x[3];
|
| 177 |
+
// double y[2];
|
| 178 |
+
//
|
| 179 |
+
// Problem problem;
|
| 180 |
+
// problem.AddParameterBlock(x, 3);
|
| 181 |
+
// problem.AddParameterBlock(y, 2);
|
| 182 |
+
// <Build Problem>
|
| 183 |
+
// <Solve Problem>
|
| 184 |
+
//
|
| 185 |
+
// Covariance::Options options;
|
| 186 |
+
// Covariance covariance(options);
|
| 187 |
+
//
|
| 188 |
+
// std::vector<std::pair<const double*, const double*>> covariance_blocks;
|
| 189 |
+
// covariance_blocks.push_back(make_pair(x, x));
|
| 190 |
+
// covariance_blocks.push_back(make_pair(y, y));
|
| 191 |
+
// covariance_blocks.push_back(make_pair(x, y));
|
| 192 |
+
//
|
| 193 |
+
// CHECK(covariance.Compute(covariance_blocks, &problem));
|
| 194 |
+
//
|
| 195 |
+
// double covariance_xx[3 * 3];
|
| 196 |
+
// double covariance_yy[2 * 2];
|
| 197 |
+
// double covariance_xy[3 * 2];
|
| 198 |
+
// covariance.GetCovarianceBlock(x, x, covariance_xx)
|
| 199 |
+
// covariance.GetCovarianceBlock(y, y, covariance_yy)
|
| 200 |
+
// covariance.GetCovarianceBlock(x, y, covariance_xy)
|
| 201 |
+
//
|
| 202 |
+
class CERES_EXPORT Covariance {
|
| 203 |
+
public:
|
| 204 |
+
struct CERES_EXPORT Options {
|
| 205 |
+
// Sparse linear algebra library to use when a sparse matrix
|
| 206 |
+
// factorization is being used to compute the covariance matrix.
|
| 207 |
+
//
|
| 208 |
+
// Currently this only applies to SPARSE_QR.
|
| 209 |
+
SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type =
|
| 210 |
+
#if !defined(CERES_NO_SUITESPARSE)
|
| 211 |
+
SUITE_SPARSE;
|
| 212 |
+
#else
|
| 213 |
+
// Eigen's QR factorization is always available.
|
| 214 |
+
EIGEN_SPARSE;
|
| 215 |
+
#endif
|
| 216 |
+
|
| 217 |
+
// Ceres supports two different algorithms for covariance
|
| 218 |
+
// estimation, which represent different tradeoffs in speed,
|
| 219 |
+
// accuracy and reliability.
|
| 220 |
+
//
|
| 221 |
+
// 1. DENSE_SVD uses Eigen's JacobiSVD to perform the
|
| 222 |
+
// computations. It computes the singular value decomposition
|
| 223 |
+
//
|
| 224 |
+
// U * D * V' = J
|
| 225 |
+
//
|
| 226 |
+
// and then uses it to compute the pseudo inverse of J'J as
|
| 227 |
+
//
|
| 228 |
+
// pseudoinverse[J'J] = V * pseudoinverse[D^2] * V'
|
| 229 |
+
//
|
| 230 |
+
// It is an accurate but slow method and should only be used
|
| 231 |
+
// for small to moderate sized problems. It can handle
|
| 232 |
+
// full-rank as well as rank deficient Jacobians.
|
| 233 |
+
//
|
| 234 |
+
// 2. SPARSE_QR uses the sparse QR factorization algorithm
|
| 235 |
+
// to compute the decomposition
|
| 236 |
+
//
|
| 237 |
+
// Q * R = J
|
| 238 |
+
//
|
| 239 |
+
// [J'J]^-1 = [R'*R]^-1
|
| 240 |
+
//
|
| 241 |
+
// SPARSE_QR is not capable of computing the covariance if the
|
| 242 |
+
// Jacobian is rank deficient. Depending on the value of
|
| 243 |
+
// Covariance::Options::sparse_linear_algebra_library_type, either
|
| 244 |
+
// Eigen's Sparse QR factorization algorithm will be used or
|
| 245 |
+
// SuiteSparse's high performance SuiteSparseQR algorithm will be
|
| 246 |
+
// used.
|
| 247 |
+
CovarianceAlgorithmType algorithm_type = SPARSE_QR;
|
| 248 |
+
|
| 249 |
+
// If the Jacobian matrix is near singular, then inverting J'J
|
| 250 |
+
// will result in unreliable results, e.g, if
|
| 251 |
+
//
|
| 252 |
+
// J = [1.0 1.0 ]
|
| 253 |
+
// [1.0 1.0000001 ]
|
| 254 |
+
//
|
| 255 |
+
// which is essentially a rank deficient matrix, we have
|
| 256 |
+
//
|
| 257 |
+
// inv(J'J) = [ 2.0471e+14 -2.0471e+14]
|
| 258 |
+
// [-2.0471e+14 2.0471e+14]
|
| 259 |
+
//
|
| 260 |
+
// This is not a useful result. Therefore, by default
|
| 261 |
+
// Covariance::Compute will return false if a rank deficient
|
| 262 |
+
// Jacobian is encountered. How rank deficiency is detected
|
| 263 |
+
// depends on the algorithm being used.
|
| 264 |
+
//
|
| 265 |
+
// 1. DENSE_SVD
|
| 266 |
+
//
|
| 267 |
+
// min_sigma / max_sigma < sqrt(min_reciprocal_condition_number)
|
| 268 |
+
//
|
| 269 |
+
// where min_sigma and max_sigma are the minimum and maxiumum
|
| 270 |
+
// singular values of J respectively.
|
| 271 |
+
//
|
| 272 |
+
// 2. SPARSE_QR
|
| 273 |
+
//
|
| 274 |
+
// rank(J) < num_col(J)
|
| 275 |
+
//
|
| 276 |
+
// Here rank(J) is the estimate of the rank of J returned by the
|
| 277 |
+
// sparse QR factorization algorithm. It is a fairly reliable
|
| 278 |
+
// indication of rank deficiency.
|
| 279 |
+
//
|
| 280 |
+
double min_reciprocal_condition_number = 1e-14;
|
| 281 |
+
|
| 282 |
+
// When using DENSE_SVD, the user has more control in dealing with
|
| 283 |
+
// singular and near singular covariance matrices.
|
| 284 |
+
//
|
| 285 |
+
// As mentioned above, when the covariance matrix is near
|
| 286 |
+
// singular, instead of computing the inverse of J'J, the
|
| 287 |
+
// Moore-Penrose pseudoinverse of J'J should be computed.
|
| 288 |
+
//
|
| 289 |
+
// If J'J has the eigen decomposition (lambda_i, e_i), where
|
| 290 |
+
// lambda_i is the i^th eigenvalue and e_i is the corresponding
|
| 291 |
+
// eigenvector, then the inverse of J'J is
|
| 292 |
+
//
|
| 293 |
+
// inverse[J'J] = sum_i e_i e_i' / lambda_i
|
| 294 |
+
//
|
| 295 |
+
// and computing the pseudo inverse involves dropping terms from
|
| 296 |
+
// this sum that correspond to small eigenvalues.
|
| 297 |
+
//
|
| 298 |
+
// How terms are dropped is controlled by
|
| 299 |
+
// min_reciprocal_condition_number and null_space_rank.
|
| 300 |
+
//
|
| 301 |
+
// If null_space_rank is non-negative, then the smallest
|
| 302 |
+
// null_space_rank eigenvalue/eigenvectors are dropped
|
| 303 |
+
// irrespective of the magnitude of lambda_i. If the ratio of the
|
| 304 |
+
// smallest non-zero eigenvalue to the largest eigenvalue in the
|
| 305 |
+
// truncated matrix is still below
|
| 306 |
+
// min_reciprocal_condition_number, then the Covariance::Compute()
|
| 307 |
+
// will fail and return false.
|
| 308 |
+
//
|
| 309 |
+
// Setting null_space_rank = -1 drops all terms for which
|
| 310 |
+
//
|
| 311 |
+
// lambda_i / lambda_max < min_reciprocal_condition_number.
|
| 312 |
+
//
|
| 313 |
+
// This option has no effect on the SUITE_SPARSE_QR and
|
| 314 |
+
// EIGEN_SPARSE_QR algorithms.
|
| 315 |
+
int null_space_rank = 0;
|
| 316 |
+
|
| 317 |
+
int num_threads = 1;
|
| 318 |
+
|
| 319 |
+
// Even though the residual blocks in the problem may contain loss
|
| 320 |
+
// functions, setting apply_loss_function to false will turn off
|
| 321 |
+
// the application of the loss function to the output of the cost
|
| 322 |
+
// function and in turn its effect on the covariance.
|
| 323 |
+
//
|
| 324 |
+
// TODO(sameergaarwal): Expand this based on Jim's experiments.
|
| 325 |
+
bool apply_loss_function = true;
|
| 326 |
+
};
|
| 327 |
+
|
| 328 |
+
explicit Covariance(const Options& options);
|
| 329 |
+
~Covariance();
|
| 330 |
+
|
| 331 |
+
// Compute a part of the covariance matrix.
|
| 332 |
+
//
|
| 333 |
+
// The vector covariance_blocks, indexes into the covariance matrix
|
| 334 |
+
// block-wise using pairs of parameter blocks. This allows the
|
| 335 |
+
// covariance estimation algorithm to only compute and store these
|
| 336 |
+
// blocks.
|
| 337 |
+
//
|
| 338 |
+
// Since the covariance matrix is symmetric, if the user passes
|
| 339 |
+
// (block1, block2), then GetCovarianceBlock can be called with
|
| 340 |
+
// block1, block2 as well as block2, block1.
|
| 341 |
+
//
|
| 342 |
+
// covariance_blocks cannot contain duplicates. Bad things will
|
| 343 |
+
// happen if they do.
|
| 344 |
+
//
|
| 345 |
+
// Note that the list of covariance_blocks is only used to determine
|
| 346 |
+
// what parts of the covariance matrix are computed. The full
|
| 347 |
+
// Jacobian is used to do the computation, i.e. they do not have an
|
| 348 |
+
// impact on what part of the Jacobian is used for computation.
|
| 349 |
+
//
|
| 350 |
+
// The return value indicates the success or failure of the
|
| 351 |
+
// covariance computation. Please see the documentation for
|
| 352 |
+
// Covariance::Options for more on the conditions under which this
|
| 353 |
+
// function returns false.
|
| 354 |
+
bool Compute(const std::vector<std::pair<const double*, const double*>>&
|
| 355 |
+
covariance_blocks,
|
| 356 |
+
Problem* problem);
|
| 357 |
+
|
| 358 |
+
// Compute a part of the covariance matrix.
|
| 359 |
+
//
|
| 360 |
+
// The vector parameter_blocks contains the parameter blocks that
|
| 361 |
+
// are used for computing the covariance matrix. From this vector
|
| 362 |
+
// all covariance pairs are generated. This allows the covariance
|
| 363 |
+
// estimation algorithm to only compute and store these blocks.
|
| 364 |
+
//
|
| 365 |
+
// parameter_blocks cannot contain duplicates. Bad things will
|
| 366 |
+
// happen if they do.
|
| 367 |
+
//
|
| 368 |
+
// Note that the list of covariance_blocks is only used to determine
|
| 369 |
+
// what parts of the covariance matrix are computed. The full
|
| 370 |
+
// Jacobian is used to do the computation, i.e. they do not have an
|
| 371 |
+
// impact on what part of the Jacobian is used for computation.
|
| 372 |
+
//
|
| 373 |
+
// The return value indicates the success or failure of the
|
| 374 |
+
// covariance computation. Please see the documentation for
|
| 375 |
+
// Covariance::Options for more on the conditions under which this
|
| 376 |
+
// function returns false.
|
| 377 |
+
bool Compute(const std::vector<const double*>& parameter_blocks,
|
| 378 |
+
Problem* problem);
|
| 379 |
+
|
| 380 |
+
// Return the block of the cross-covariance matrix corresponding to
|
| 381 |
+
// parameter_block1 and parameter_block2.
|
| 382 |
+
//
|
| 383 |
+
// Compute must be called before the first call to
|
| 384 |
+
// GetCovarianceBlock and the pair <parameter_block1,
|
| 385 |
+
// parameter_block2> OR the pair <parameter_block2,
|
| 386 |
+
// parameter_block1> must have been present in the vector
|
| 387 |
+
// covariance_blocks when Compute was called. Otherwise
|
| 388 |
+
// GetCovarianceBlock will return false.
|
| 389 |
+
//
|
| 390 |
+
// covariance_block must point to a memory location that can store a
|
| 391 |
+
// parameter_block1_size x parameter_block2_size matrix. The
|
| 392 |
+
// returned covariance will be a row-major matrix.
|
| 393 |
+
bool GetCovarianceBlock(const double* parameter_block1,
|
| 394 |
+
const double* parameter_block2,
|
| 395 |
+
double* covariance_block) const;
|
| 396 |
+
|
| 397 |
+
// Return the block of the cross-covariance matrix corresponding to
|
| 398 |
+
// parameter_block1 and parameter_block2.
|
| 399 |
+
// Returns cross-covariance in the tangent space if a local
|
| 400 |
+
// parameterization is associated with either parameter block;
|
| 401 |
+
// else returns cross-covariance in the ambient space.
|
| 402 |
+
//
|
| 403 |
+
// Compute must be called before the first call to
|
| 404 |
+
// GetCovarianceBlock and the pair <parameter_block1,
|
| 405 |
+
// parameter_block2> OR the pair <parameter_block2,
|
| 406 |
+
// parameter_block1> must have been present in the vector
|
| 407 |
+
// covariance_blocks when Compute was called. Otherwise
|
| 408 |
+
// GetCovarianceBlock will return false.
|
| 409 |
+
//
|
| 410 |
+
// covariance_block must point to a memory location that can store a
|
| 411 |
+
// parameter_block1_local_size x parameter_block2_local_size matrix. The
|
| 412 |
+
// returned covariance will be a row-major matrix.
|
| 413 |
+
bool GetCovarianceBlockInTangentSpace(const double* parameter_block1,
|
| 414 |
+
const double* parameter_block2,
|
| 415 |
+
double* covariance_block) const;
|
| 416 |
+
|
| 417 |
+
// Return the covariance matrix corresponding to all parameter_blocks.
|
| 418 |
+
//
|
| 419 |
+
// Compute must be called before calling GetCovarianceMatrix and all
|
| 420 |
+
// parameter_blocks must have been present in the vector
|
| 421 |
+
// parameter_blocks when Compute was called. Otherwise
|
| 422 |
+
// GetCovarianceMatrix returns false.
|
| 423 |
+
//
|
| 424 |
+
// covariance_matrix must point to a memory location that can store
|
| 425 |
+
// the size of the covariance matrix. The covariance matrix will be
|
| 426 |
+
// a square matrix whose row and column count is equal to the sum of
|
| 427 |
+
// the sizes of the individual parameter blocks. The covariance
|
| 428 |
+
// matrix will be a row-major matrix.
|
| 429 |
+
bool GetCovarianceMatrix(const std::vector<const double*>& parameter_blocks,
|
| 430 |
+
double* covariance_matrix) const;
|
| 431 |
+
|
| 432 |
+
// Return the covariance matrix corresponding to parameter_blocks
|
| 433 |
+
// in the tangent space if a local parameterization is associated
|
| 434 |
+
// with one of the parameter blocks else returns the covariance
|
| 435 |
+
// matrix in the ambient space.
|
| 436 |
+
//
|
| 437 |
+
// Compute must be called before calling GetCovarianceMatrix and all
|
| 438 |
+
// parameter_blocks must have been present in the vector
|
| 439 |
+
// parameters_blocks when Compute was called. Otherwise
|
| 440 |
+
// GetCovarianceMatrix returns false.
|
| 441 |
+
//
|
| 442 |
+
// covariance_matrix must point to a memory location that can store
|
| 443 |
+
// the size of the covariance matrix. The covariance matrix will be
|
| 444 |
+
// a square matrix whose row and column count is equal to the sum of
|
| 445 |
+
// the sizes of the tangent spaces of the individual parameter
|
| 446 |
+
// blocks. The covariance matrix will be a row-major matrix.
|
| 447 |
+
bool GetCovarianceMatrixInTangentSpace(
|
| 448 |
+
const std::vector<const double*>& parameter_blocks,
|
| 449 |
+
double* covariance_matrix) const;
|
| 450 |
+
|
| 451 |
+
private:
|
| 452 |
+
std::unique_ptr<internal::CovarianceImpl> impl_;
|
| 453 |
+
};
|
| 454 |
+
|
| 455 |
+
} // namespace ceres
|
| 456 |
+
|
| 457 |
+
#include "ceres/internal/reenable_warnings.h"
|
| 458 |
+
|
| 459 |
+
#endif // CERES_PUBLIC_COVARIANCE_H_
|
include/ceres/crs_matrix.h
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: sameeragarwal@google.com (Sameer Agarwal)
|
| 30 |
+
|
| 31 |
+
#ifndef CERES_PUBLIC_CRS_MATRIX_H_
|
| 32 |
+
#define CERES_PUBLIC_CRS_MATRIX_H_
|
| 33 |
+
|
| 34 |
+
#include <vector>
|
| 35 |
+
|
| 36 |
+
#include "ceres/internal/disable_warnings.h"
|
| 37 |
+
#include "ceres/internal/export.h"
|
| 38 |
+
|
| 39 |
+
namespace ceres {
|
| 40 |
+
|
| 41 |
+
// A compressed row sparse matrix used primarily for communicating the
|
| 42 |
+
// Jacobian matrix to the user.
|
| 43 |
+
struct CERES_EXPORT CRSMatrix {
|
| 44 |
+
CRSMatrix() = default;
|
| 45 |
+
|
| 46 |
+
int num_rows{0};
|
| 47 |
+
int num_cols{0};
|
| 48 |
+
|
| 49 |
+
// A compressed row matrix stores its contents in three arrays,
|
| 50 |
+
// rows, cols and values.
|
| 51 |
+
//
|
| 52 |
+
// rows is a num_rows + 1 sized array that points into the cols and
|
| 53 |
+
// values array. For each row i:
|
| 54 |
+
//
|
| 55 |
+
// cols[rows[i]] ... cols[rows[i + 1] - 1] are the indices of the
|
| 56 |
+
// non-zero columns of row i.
|
| 57 |
+
//
|
| 58 |
+
// values[rows[i]] .. values[rows[i + 1] - 1] are the values of the
|
| 59 |
+
// corresponding entries.
|
| 60 |
+
//
|
| 61 |
+
// cols and values contain as many entries as there are non-zeros in
|
| 62 |
+
// the matrix.
|
| 63 |
+
//
|
| 64 |
+
// e.g, consider the 3x4 sparse matrix
|
| 65 |
+
//
|
| 66 |
+
// [ 0 10 0 4 ]
|
| 67 |
+
// [ 0 2 -3 2 ]
|
| 68 |
+
// [ 1 2 0 0 ]
|
| 69 |
+
//
|
| 70 |
+
// The three arrays will be:
|
| 71 |
+
//
|
| 72 |
+
//
|
| 73 |
+
// -row0- ---row1--- -row2-
|
| 74 |
+
// rows = [ 0, 2, 5, 7]
|
| 75 |
+
// cols = [ 1, 3, 1, 2, 3, 0, 1]
|
| 76 |
+
// values = [10, 4, 2, -3, 2, 1, 2]
|
| 77 |
+
|
| 78 |
+
std::vector<int> cols;
|
| 79 |
+
std::vector<int> rows;
|
| 80 |
+
std::vector<double> values;
|
| 81 |
+
};
|
| 82 |
+
|
| 83 |
+
} // namespace ceres
|
| 84 |
+
|
| 85 |
+
#include "ceres/internal/reenable_warnings.h"
|
| 86 |
+
|
| 87 |
+
#endif // CERES_PUBLIC_CRS_MATRIX_H_
|
include/ceres/cubic_interpolation.h
ADDED
|
@@ -0,0 +1,436 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: sameeragarwal@google.com (Sameer Agarwal)
|
| 30 |
+
|
| 31 |
+
#ifndef CERES_PUBLIC_CUBIC_INTERPOLATION_H_
|
| 32 |
+
#define CERES_PUBLIC_CUBIC_INTERPOLATION_H_
|
| 33 |
+
|
| 34 |
+
#include "Eigen/Core"
|
| 35 |
+
#include "ceres/internal/export.h"
|
| 36 |
+
#include "glog/logging.h"
|
| 37 |
+
|
| 38 |
+
namespace ceres {
|
| 39 |
+
|
| 40 |
+
// Given samples from a function sampled at four equally spaced points,
|
| 41 |
+
//
|
| 42 |
+
// p0 = f(-1)
|
| 43 |
+
// p1 = f(0)
|
| 44 |
+
// p2 = f(1)
|
| 45 |
+
// p3 = f(2)
|
| 46 |
+
//
|
| 47 |
+
// Evaluate the cubic Hermite spline (also known as the Catmull-Rom
|
| 48 |
+
// spline) at a point x that lies in the interval [0, 1].
|
| 49 |
+
//
|
| 50 |
+
// This is also the interpolation kernel (for the case of a = 0.5) as
|
| 51 |
+
// proposed by R. Keys, in:
|
| 52 |
+
//
|
| 53 |
+
// "Cubic convolution interpolation for digital image processing".
|
| 54 |
+
// IEEE Transactions on Acoustics, Speech, and Signal Processing
|
| 55 |
+
// 29 (6): 1153-1160.
|
| 56 |
+
//
|
| 57 |
+
// For more details see
|
| 58 |
+
//
|
| 59 |
+
// http://en.wikipedia.org/wiki/Cubic_Hermite_spline
|
| 60 |
+
// http://en.wikipedia.org/wiki/Bicubic_interpolation
|
| 61 |
+
//
|
| 62 |
+
// f if not nullptr will contain the interpolated function values.
|
| 63 |
+
// dfdx if not nullptr will contain the interpolated derivative values.
|
| 64 |
+
template <int kDataDimension>
|
| 65 |
+
void CubicHermiteSpline(const Eigen::Matrix<double, kDataDimension, 1>& p0,
|
| 66 |
+
const Eigen::Matrix<double, kDataDimension, 1>& p1,
|
| 67 |
+
const Eigen::Matrix<double, kDataDimension, 1>& p2,
|
| 68 |
+
const Eigen::Matrix<double, kDataDimension, 1>& p3,
|
| 69 |
+
const double x,
|
| 70 |
+
double* f,
|
| 71 |
+
double* dfdx) {
|
| 72 |
+
using VType = Eigen::Matrix<double, kDataDimension, 1>;
|
| 73 |
+
const VType a = 0.5 * (-p0 + 3.0 * p1 - 3.0 * p2 + p3);
|
| 74 |
+
const VType b = 0.5 * (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3);
|
| 75 |
+
const VType c = 0.5 * (-p0 + p2);
|
| 76 |
+
const VType d = p1;
|
| 77 |
+
|
| 78 |
+
// Use Horner's rule to evaluate the function value and its
|
| 79 |
+
// derivative.
|
| 80 |
+
|
| 81 |
+
// f = ax^3 + bx^2 + cx + d
|
| 82 |
+
if (f != nullptr) {
|
| 83 |
+
Eigen::Map<VType>(f, kDataDimension) = d + x * (c + x * (b + x * a));
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
// dfdx = 3ax^2 + 2bx + c
|
| 87 |
+
if (dfdx != nullptr) {
|
| 88 |
+
Eigen::Map<VType>(dfdx, kDataDimension) = c + x * (2.0 * b + 3.0 * a * x);
|
| 89 |
+
}
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
// Given as input an infinite one dimensional grid, which provides the
|
| 93 |
+
// following interface.
|
| 94 |
+
//
|
| 95 |
+
// class Grid {
|
| 96 |
+
// public:
|
| 97 |
+
// enum { DATA_DIMENSION = 2; };
|
| 98 |
+
// void GetValue(int n, double* f) const;
|
| 99 |
+
// };
|
| 100 |
+
//
|
| 101 |
+
// Here, GetValue gives the value of a function f (possibly vector
|
| 102 |
+
// valued) for any integer n.
|
| 103 |
+
//
|
| 104 |
+
// The enum DATA_DIMENSION indicates the dimensionality of the
|
| 105 |
+
// function being interpolated. For example if you are interpolating
|
| 106 |
+
// rotations in axis-angle format over time, then DATA_DIMENSION = 3.
|
| 107 |
+
//
|
| 108 |
+
// CubicInterpolator uses cubic Hermite splines to produce a smooth
|
| 109 |
+
// approximation to it that can be used to evaluate the f(x) and f'(x)
|
| 110 |
+
// at any point on the real number line.
|
| 111 |
+
//
|
| 112 |
+
// For more details on cubic interpolation see
|
| 113 |
+
//
|
| 114 |
+
// http://en.wikipedia.org/wiki/Cubic_Hermite_spline
|
| 115 |
+
//
|
| 116 |
+
// Example usage:
|
| 117 |
+
//
|
| 118 |
+
// const double data[] = {1.0, 2.0, 5.0, 6.0};
|
| 119 |
+
// Grid1D<double, 1> grid(data, 0, 4);
|
| 120 |
+
// CubicInterpolator<Grid1D<double, 1>> interpolator(grid);
|
| 121 |
+
// double f, dfdx;
|
| 122 |
+
// interpolator.Evaluator(1.5, &f, &dfdx);
|
| 123 |
+
template <typename Grid>
|
| 124 |
+
class CubicInterpolator {
|
| 125 |
+
public:
|
| 126 |
+
explicit CubicInterpolator(const Grid& grid) : grid_(grid) {
|
| 127 |
+
// The + casts the enum into an int before doing the
|
| 128 |
+
// comparison. It is needed to prevent
|
| 129 |
+
// "-Wunnamed-type-template-args" related errors.
|
| 130 |
+
CHECK_GE(+Grid::DATA_DIMENSION, 1);
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
void Evaluate(double x, double* f, double* dfdx) const {
|
| 134 |
+
const int n = std::floor(x);
|
| 135 |
+
Eigen::Matrix<double, Grid::DATA_DIMENSION, 1> p0, p1, p2, p3;
|
| 136 |
+
grid_.GetValue(n - 1, p0.data());
|
| 137 |
+
grid_.GetValue(n, p1.data());
|
| 138 |
+
grid_.GetValue(n + 1, p2.data());
|
| 139 |
+
grid_.GetValue(n + 2, p3.data());
|
| 140 |
+
CubicHermiteSpline<Grid::DATA_DIMENSION>(p0, p1, p2, p3, x - n, f, dfdx);
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
// The following two Evaluate overloads are needed for interfacing
|
| 144 |
+
// with automatic differentiation. The first is for when a scalar
|
| 145 |
+
// evaluation is done, and the second one is for when Jets are used.
|
| 146 |
+
void Evaluate(const double& x, double* f) const { Evaluate(x, f, nullptr); }
|
| 147 |
+
|
| 148 |
+
template <typename JetT>
|
| 149 |
+
void Evaluate(const JetT& x, JetT* f) const {
|
| 150 |
+
double fx[Grid::DATA_DIMENSION], dfdx[Grid::DATA_DIMENSION];
|
| 151 |
+
Evaluate(x.a, fx, dfdx);
|
| 152 |
+
for (int i = 0; i < Grid::DATA_DIMENSION; ++i) {
|
| 153 |
+
f[i].a = fx[i];
|
| 154 |
+
f[i].v = dfdx[i] * x.v;
|
| 155 |
+
}
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
private:
|
| 159 |
+
const Grid& grid_;
|
| 160 |
+
};
|
| 161 |
+
|
| 162 |
+
// An object that implements an infinite one dimensional grid needed
|
| 163 |
+
// by the CubicInterpolator where the source of the function values is
|
| 164 |
+
// an array of type T on the interval
|
| 165 |
+
//
|
| 166 |
+
// [begin, ..., end - 1]
|
| 167 |
+
//
|
| 168 |
+
// Since the input array is finite and the grid is infinite, values
|
| 169 |
+
// outside this interval needs to be computed. Grid1D uses the value
|
| 170 |
+
// from the nearest edge.
|
| 171 |
+
//
|
| 172 |
+
// The function being provided can be vector valued, in which case
|
| 173 |
+
// kDataDimension > 1. The dimensional slices of the function maybe
|
| 174 |
+
// interleaved, or they maybe stacked, i.e, if the function has
|
| 175 |
+
// kDataDimension = 2, if kInterleaved = true, then it is stored as
|
| 176 |
+
//
|
| 177 |
+
// f01, f02, f11, f12 ....
|
| 178 |
+
//
|
| 179 |
+
// and if kInterleaved = false, then it is stored as
|
| 180 |
+
//
|
| 181 |
+
// f01, f11, .. fn1, f02, f12, .. , fn2
|
| 182 |
+
//
|
| 183 |
+
template <typename T, int kDataDimension = 1, bool kInterleaved = true>
|
| 184 |
+
struct Grid1D {
|
| 185 |
+
public:
|
| 186 |
+
enum { DATA_DIMENSION = kDataDimension };
|
| 187 |
+
|
| 188 |
+
Grid1D(const T* data, const int begin, const int end)
|
| 189 |
+
: data_(data), begin_(begin), end_(end), num_values_(end - begin) {
|
| 190 |
+
CHECK_LT(begin, end);
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
EIGEN_STRONG_INLINE void GetValue(const int n, double* f) const {
|
| 194 |
+
const int idx = (std::min)((std::max)(begin_, n), end_ - 1) - begin_;
|
| 195 |
+
if (kInterleaved) {
|
| 196 |
+
for (int i = 0; i < kDataDimension; ++i) {
|
| 197 |
+
f[i] = static_cast<double>(data_[kDataDimension * idx + i]);
|
| 198 |
+
}
|
| 199 |
+
} else {
|
| 200 |
+
for (int i = 0; i < kDataDimension; ++i) {
|
| 201 |
+
f[i] = static_cast<double>(data_[i * num_values_ + idx]);
|
| 202 |
+
}
|
| 203 |
+
}
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
private:
|
| 207 |
+
const T* data_;
|
| 208 |
+
const int begin_;
|
| 209 |
+
const int end_;
|
| 210 |
+
const int num_values_;
|
| 211 |
+
};
|
| 212 |
+
|
| 213 |
+
// Given as input an infinite two dimensional grid like object, which
|
| 214 |
+
// provides the following interface:
|
| 215 |
+
//
|
| 216 |
+
// struct Grid {
|
| 217 |
+
// enum { DATA_DIMENSION = 1 };
|
| 218 |
+
// void GetValue(int row, int col, double* f) const;
|
| 219 |
+
// };
|
| 220 |
+
//
|
| 221 |
+
// Where, GetValue gives us the value of a function f (possibly vector
|
| 222 |
+
// valued) for any pairs of integers (row, col), and the enum
|
| 223 |
+
// DATA_DIMENSION indicates the dimensionality of the function being
|
| 224 |
+
// interpolated. For example if you are interpolating a color image
|
| 225 |
+
// with three channels (Red, Green & Blue), then DATA_DIMENSION = 3.
|
| 226 |
+
//
|
| 227 |
+
// BiCubicInterpolator uses the cubic convolution interpolation
|
| 228 |
+
// algorithm of R. Keys, to produce a smooth approximation to it that
|
| 229 |
+
// can be used to evaluate the f(r,c), df(r, c)/dr and df(r,c)/dc at
|
| 230 |
+
// any point in the real plane.
|
| 231 |
+
//
|
| 232 |
+
// For more details on the algorithm used here see:
|
| 233 |
+
//
|
| 234 |
+
// "Cubic convolution interpolation for digital image processing".
|
| 235 |
+
// Robert G. Keys, IEEE Trans. on Acoustics, Speech, and Signal
|
| 236 |
+
// Processing 29 (6): 1153-1160, 1981.
|
| 237 |
+
//
|
| 238 |
+
// http://en.wikipedia.org/wiki/Cubic_Hermite_spline
|
| 239 |
+
// http://en.wikipedia.org/wiki/Bicubic_interpolation
|
| 240 |
+
//
|
| 241 |
+
// Example usage:
|
| 242 |
+
//
|
| 243 |
+
// const double data[] = {1.0, 3.0, -1.0, 4.0,
|
| 244 |
+
// 3.6, 2.1, 4.2, 2.0,
|
| 245 |
+
// 2.0, 1.0, 3.1, 5.2};
|
| 246 |
+
// Grid2D<double, 1> grid(data, 3, 4);
|
| 247 |
+
// BiCubicInterpolator<Grid2D<double, 1>> interpolator(grid);
|
| 248 |
+
// double f, dfdr, dfdc;
|
| 249 |
+
// interpolator.Evaluate(1.2, 2.5, &f, &dfdr, &dfdc);
|
| 250 |
+
|
| 251 |
+
template <typename Grid>
|
| 252 |
+
class BiCubicInterpolator {
|
| 253 |
+
public:
|
| 254 |
+
explicit BiCubicInterpolator(const Grid& grid) : grid_(grid) {
|
| 255 |
+
// The + casts the enum into an int before doing the
|
| 256 |
+
// comparison. It is needed to prevent
|
| 257 |
+
// "-Wunnamed-type-template-args" related errors.
|
| 258 |
+
CHECK_GE(+Grid::DATA_DIMENSION, 1);
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
// Evaluate the interpolated function value and/or its
|
| 262 |
+
// derivative. Uses the nearest point on the grid boundary if r or
|
| 263 |
+
// c is out of bounds.
|
| 264 |
+
void Evaluate(
|
| 265 |
+
double r, double c, double* f, double* dfdr, double* dfdc) const {
|
| 266 |
+
// BiCubic interpolation requires 16 values around the point being
|
| 267 |
+
// evaluated. We will use pij, to indicate the elements of the
|
| 268 |
+
// 4x4 grid of values.
|
| 269 |
+
//
|
| 270 |
+
// col
|
| 271 |
+
// p00 p01 p02 p03
|
| 272 |
+
// row p10 p11 p12 p13
|
| 273 |
+
// p20 p21 p22 p23
|
| 274 |
+
// p30 p31 p32 p33
|
| 275 |
+
//
|
| 276 |
+
// The point (r,c) being evaluated is assumed to lie in the square
|
| 277 |
+
// defined by p11, p12, p22 and p21.
|
| 278 |
+
|
| 279 |
+
const int row = std::floor(r);
|
| 280 |
+
const int col = std::floor(c);
|
| 281 |
+
|
| 282 |
+
Eigen::Matrix<double, Grid::DATA_DIMENSION, 1> p0, p1, p2, p3;
|
| 283 |
+
|
| 284 |
+
// Interpolate along each of the four rows, evaluating the function
|
| 285 |
+
// value and the horizontal derivative in each row.
|
| 286 |
+
Eigen::Matrix<double, Grid::DATA_DIMENSION, 1> f0, f1, f2, f3;
|
| 287 |
+
Eigen::Matrix<double, Grid::DATA_DIMENSION, 1> df0dc, df1dc, df2dc, df3dc;
|
| 288 |
+
|
| 289 |
+
grid_.GetValue(row - 1, col - 1, p0.data());
|
| 290 |
+
grid_.GetValue(row - 1, col, p1.data());
|
| 291 |
+
grid_.GetValue(row - 1, col + 1, p2.data());
|
| 292 |
+
grid_.GetValue(row - 1, col + 2, p3.data());
|
| 293 |
+
CubicHermiteSpline<Grid::DATA_DIMENSION>(
|
| 294 |
+
p0, p1, p2, p3, c - col, f0.data(), df0dc.data());
|
| 295 |
+
|
| 296 |
+
grid_.GetValue(row, col - 1, p0.data());
|
| 297 |
+
grid_.GetValue(row, col, p1.data());
|
| 298 |
+
grid_.GetValue(row, col + 1, p2.data());
|
| 299 |
+
grid_.GetValue(row, col + 2, p3.data());
|
| 300 |
+
CubicHermiteSpline<Grid::DATA_DIMENSION>(
|
| 301 |
+
p0, p1, p2, p3, c - col, f1.data(), df1dc.data());
|
| 302 |
+
|
| 303 |
+
grid_.GetValue(row + 1, col - 1, p0.data());
|
| 304 |
+
grid_.GetValue(row + 1, col, p1.data());
|
| 305 |
+
grid_.GetValue(row + 1, col + 1, p2.data());
|
| 306 |
+
grid_.GetValue(row + 1, col + 2, p3.data());
|
| 307 |
+
CubicHermiteSpline<Grid::DATA_DIMENSION>(
|
| 308 |
+
p0, p1, p2, p3, c - col, f2.data(), df2dc.data());
|
| 309 |
+
|
| 310 |
+
grid_.GetValue(row + 2, col - 1, p0.data());
|
| 311 |
+
grid_.GetValue(row + 2, col, p1.data());
|
| 312 |
+
grid_.GetValue(row + 2, col + 1, p2.data());
|
| 313 |
+
grid_.GetValue(row + 2, col + 2, p3.data());
|
| 314 |
+
CubicHermiteSpline<Grid::DATA_DIMENSION>(
|
| 315 |
+
p0, p1, p2, p3, c - col, f3.data(), df3dc.data());
|
| 316 |
+
|
| 317 |
+
// Interpolate vertically the interpolated value from each row and
|
| 318 |
+
// compute the derivative along the columns.
|
| 319 |
+
CubicHermiteSpline<Grid::DATA_DIMENSION>(f0, f1, f2, f3, r - row, f, dfdr);
|
| 320 |
+
if (dfdc != nullptr) {
|
| 321 |
+
// Interpolate vertically the derivative along the columns.
|
| 322 |
+
CubicHermiteSpline<Grid::DATA_DIMENSION>(
|
| 323 |
+
df0dc, df1dc, df2dc, df3dc, r - row, dfdc, nullptr);
|
| 324 |
+
}
|
| 325 |
+
}
|
| 326 |
+
|
| 327 |
+
// The following two Evaluate overloads are needed for interfacing
|
| 328 |
+
// with automatic differentiation. The first is for when a scalar
|
| 329 |
+
// evaluation is done, and the second one is for when Jets are used.
|
| 330 |
+
void Evaluate(const double& r, const double& c, double* f) const {
|
| 331 |
+
Evaluate(r, c, f, nullptr, nullptr);
|
| 332 |
+
}
|
| 333 |
+
|
| 334 |
+
template <typename JetT>
|
| 335 |
+
void Evaluate(const JetT& r, const JetT& c, JetT* f) const {
|
| 336 |
+
double frc[Grid::DATA_DIMENSION];
|
| 337 |
+
double dfdr[Grid::DATA_DIMENSION];
|
| 338 |
+
double dfdc[Grid::DATA_DIMENSION];
|
| 339 |
+
Evaluate(r.a, c.a, frc, dfdr, dfdc);
|
| 340 |
+
for (int i = 0; i < Grid::DATA_DIMENSION; ++i) {
|
| 341 |
+
f[i].a = frc[i];
|
| 342 |
+
f[i].v = dfdr[i] * r.v + dfdc[i] * c.v;
|
| 343 |
+
}
|
| 344 |
+
}
|
| 345 |
+
|
| 346 |
+
private:
|
| 347 |
+
const Grid& grid_;
|
| 348 |
+
};
|
| 349 |
+
|
| 350 |
+
// An object that implements an infinite two dimensional grid needed
|
| 351 |
+
// by the BiCubicInterpolator where the source of the function values
|
| 352 |
+
// is an grid of type T on the grid
|
| 353 |
+
//
|
| 354 |
+
// [(row_start, col_start), ..., (row_start, col_end - 1)]
|
| 355 |
+
// [ ... ]
|
| 356 |
+
// [(row_end - 1, col_start), ..., (row_end - 1, col_end - 1)]
|
| 357 |
+
//
|
| 358 |
+
// Since the input grid is finite and the grid is infinite, values
|
| 359 |
+
// outside this interval needs to be computed. Grid2D uses the value
|
| 360 |
+
// from the nearest edge.
|
| 361 |
+
//
|
| 362 |
+
// The function being provided can be vector valued, in which case
|
| 363 |
+
// kDataDimension > 1. The data maybe stored in row or column major
|
| 364 |
+
// format and the various dimensional slices of the function maybe
|
| 365 |
+
// interleaved, or they maybe stacked, i.e, if the function has
|
| 366 |
+
// kDataDimension = 2, is stored in row-major format and if
|
| 367 |
+
// kInterleaved = true, then it is stored as
|
| 368 |
+
//
|
| 369 |
+
// f001, f002, f011, f012, ...
|
| 370 |
+
//
|
| 371 |
+
// A commonly occuring example are color images (RGB) where the three
|
| 372 |
+
// channels are stored interleaved.
|
| 373 |
+
//
|
| 374 |
+
// If kInterleaved = false, then it is stored as
|
| 375 |
+
//
|
| 376 |
+
// f001, f011, ..., fnm1, f002, f012, ...
|
| 377 |
+
template <typename T,
|
| 378 |
+
int kDataDimension = 1,
|
| 379 |
+
bool kRowMajor = true,
|
| 380 |
+
bool kInterleaved = true>
|
| 381 |
+
struct Grid2D {
|
| 382 |
+
public:
|
| 383 |
+
enum { DATA_DIMENSION = kDataDimension };
|
| 384 |
+
|
| 385 |
+
Grid2D(const T* data,
|
| 386 |
+
const int row_begin,
|
| 387 |
+
const int row_end,
|
| 388 |
+
const int col_begin,
|
| 389 |
+
const int col_end)
|
| 390 |
+
: data_(data),
|
| 391 |
+
row_begin_(row_begin),
|
| 392 |
+
row_end_(row_end),
|
| 393 |
+
col_begin_(col_begin),
|
| 394 |
+
col_end_(col_end),
|
| 395 |
+
num_rows_(row_end - row_begin),
|
| 396 |
+
num_cols_(col_end - col_begin),
|
| 397 |
+
num_values_(num_rows_ * num_cols_) {
|
| 398 |
+
CHECK_GE(kDataDimension, 1);
|
| 399 |
+
CHECK_LT(row_begin, row_end);
|
| 400 |
+
CHECK_LT(col_begin, col_end);
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
EIGEN_STRONG_INLINE void GetValue(const int r, const int c, double* f) const {
|
| 404 |
+
const int row_idx =
|
| 405 |
+
(std::min)((std::max)(row_begin_, r), row_end_ - 1) - row_begin_;
|
| 406 |
+
const int col_idx =
|
| 407 |
+
(std::min)((std::max)(col_begin_, c), col_end_ - 1) - col_begin_;
|
| 408 |
+
|
| 409 |
+
const int n = (kRowMajor) ? num_cols_ * row_idx + col_idx
|
| 410 |
+
: num_rows_ * col_idx + row_idx;
|
| 411 |
+
|
| 412 |
+
if (kInterleaved) {
|
| 413 |
+
for (int i = 0; i < kDataDimension; ++i) {
|
| 414 |
+
f[i] = static_cast<double>(data_[kDataDimension * n + i]);
|
| 415 |
+
}
|
| 416 |
+
} else {
|
| 417 |
+
for (int i = 0; i < kDataDimension; ++i) {
|
| 418 |
+
f[i] = static_cast<double>(data_[i * num_values_ + n]);
|
| 419 |
+
}
|
| 420 |
+
}
|
| 421 |
+
}
|
| 422 |
+
|
| 423 |
+
private:
|
| 424 |
+
const T* data_;
|
| 425 |
+
const int row_begin_;
|
| 426 |
+
const int row_end_;
|
| 427 |
+
const int col_begin_;
|
| 428 |
+
const int col_end_;
|
| 429 |
+
const int num_rows_;
|
| 430 |
+
const int num_cols_;
|
| 431 |
+
const int num_values_;
|
| 432 |
+
};
|
| 433 |
+
|
| 434 |
+
} // namespace ceres
|
| 435 |
+
|
| 436 |
+
#endif // CERES_PUBLIC_CUBIC_INTERPOLATOR_H_
|
include/ceres/dynamic_autodiff_cost_function.h
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: sameeragarwal@google.com (Sameer Agarwal)
|
| 30 |
+
// mierle@gmail.com (Keir Mierle)
|
| 31 |
+
|
| 32 |
+
#ifndef CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
|
| 33 |
+
#define CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
|
| 34 |
+
|
| 35 |
+
#include <cmath>
|
| 36 |
+
#include <memory>
|
| 37 |
+
#include <numeric>
|
| 38 |
+
#include <vector>
|
| 39 |
+
|
| 40 |
+
#include "ceres/dynamic_cost_function.h"
|
| 41 |
+
#include "ceres/internal/fixed_array.h"
|
| 42 |
+
#include "ceres/jet.h"
|
| 43 |
+
#include "ceres/types.h"
|
| 44 |
+
#include "glog/logging.h"
|
| 45 |
+
|
| 46 |
+
namespace ceres {
|
| 47 |
+
|
| 48 |
+
// This autodiff implementation differs from the one found in
|
| 49 |
+
// autodiff_cost_function.h by supporting autodiff on cost functions
|
| 50 |
+
// with variable numbers of parameters with variable sizes. With the
|
| 51 |
+
// other implementation, all the sizes (both the number of parameter
|
| 52 |
+
// blocks and the size of each block) must be fixed at compile time.
|
| 53 |
+
//
|
| 54 |
+
// The functor API differs slightly from the API for fixed size
|
| 55 |
+
// autodiff; the expected interface for the cost functors is:
|
| 56 |
+
//
|
| 57 |
+
// struct MyCostFunctor {
|
| 58 |
+
// template<typename T>
|
| 59 |
+
// bool operator()(T const* const* parameters, T* residuals) const {
|
| 60 |
+
// // Use parameters[i] to access the i'th parameter block.
|
| 61 |
+
// }
|
| 62 |
+
// };
|
| 63 |
+
//
|
| 64 |
+
// Since the sizing of the parameters is done at runtime, you must
|
| 65 |
+
// also specify the sizes after creating the dynamic autodiff cost
|
| 66 |
+
// function. For example:
|
| 67 |
+
//
|
| 68 |
+
// DynamicAutoDiffCostFunction<MyCostFunctor, 3> cost_function(
|
| 69 |
+
// new MyCostFunctor());
|
| 70 |
+
// cost_function.AddParameterBlock(5);
|
| 71 |
+
// cost_function.AddParameterBlock(10);
|
| 72 |
+
// cost_function.SetNumResiduals(21);
|
| 73 |
+
//
|
| 74 |
+
// Under the hood, the implementation evaluates the cost function
|
| 75 |
+
// multiple times, computing a small set of the derivatives (four by
|
| 76 |
+
// default, controlled by the Stride template parameter) with each
|
| 77 |
+
// pass. There is a tradeoff with the size of the passes; you may want
|
| 78 |
+
// to experiment with the stride.
|
| 79 |
+
template <typename CostFunctor, int Stride = 4>
|
| 80 |
+
class DynamicAutoDiffCostFunction final : public DynamicCostFunction {
|
| 81 |
+
public:
|
| 82 |
+
// Takes ownership by default.
|
| 83 |
+
explicit DynamicAutoDiffCostFunction(CostFunctor* functor,
|
| 84 |
+
Ownership ownership = TAKE_OWNERSHIP)
|
| 85 |
+
: functor_(functor), ownership_(ownership) {}
|
| 86 |
+
|
| 87 |
+
DynamicAutoDiffCostFunction(DynamicAutoDiffCostFunction&& other)
|
| 88 |
+
: functor_(std::move(other.functor_)), ownership_(other.ownership_) {}
|
| 89 |
+
|
| 90 |
+
~DynamicAutoDiffCostFunction() override {
|
| 91 |
+
// Manually release pointer if configured to not take ownership
|
| 92 |
+
// rather than deleting only if ownership is taken. This is to
|
| 93 |
+
// stay maximally compatible to old user code which may have
|
| 94 |
+
// forgotten to implement a virtual destructor, from when the
|
| 95 |
+
// AutoDiffCostFunction always took ownership.
|
| 96 |
+
if (ownership_ == DO_NOT_TAKE_OWNERSHIP) {
|
| 97 |
+
functor_.release();
|
| 98 |
+
}
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
bool Evaluate(double const* const* parameters,
|
| 102 |
+
double* residuals,
|
| 103 |
+
double** jacobians) const override {
|
| 104 |
+
CHECK_GT(num_residuals(), 0)
|
| 105 |
+
<< "You must call DynamicAutoDiffCostFunction::SetNumResiduals() "
|
| 106 |
+
<< "before DynamicAutoDiffCostFunction::Evaluate().";
|
| 107 |
+
|
| 108 |
+
if (jacobians == nullptr) {
|
| 109 |
+
return (*functor_)(parameters, residuals);
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
// The difficulty with Jets, as implemented in Ceres, is that they were
|
| 113 |
+
// originally designed for strictly compile-sized use. At this point, there
|
| 114 |
+
// is a large body of code that assumes inside a cost functor it is
|
| 115 |
+
// acceptable to do e.g. T(1.5) and get an appropriately sized jet back.
|
| 116 |
+
//
|
| 117 |
+
// Unfortunately, it is impossible to communicate the expected size of a
|
| 118 |
+
// dynamically sized jet to the static instantiations that existing code
|
| 119 |
+
// depends on.
|
| 120 |
+
//
|
| 121 |
+
// To work around this issue, the solution here is to evaluate the
|
| 122 |
+
// jacobians in a series of passes, each one computing Stride *
|
| 123 |
+
// num_residuals() derivatives. This is done with small, fixed-size jets.
|
| 124 |
+
const int num_parameter_blocks =
|
| 125 |
+
static_cast<int>(parameter_block_sizes().size());
|
| 126 |
+
const int num_parameters = std::accumulate(
|
| 127 |
+
parameter_block_sizes().begin(), parameter_block_sizes().end(), 0);
|
| 128 |
+
|
| 129 |
+
// Allocate scratch space for the strided evaluation.
|
| 130 |
+
using JetT = Jet<double, Stride>;
|
| 131 |
+
internal::FixedArray<JetT, (256 * 7) / sizeof(JetT)> input_jets(
|
| 132 |
+
num_parameters);
|
| 133 |
+
internal::FixedArray<JetT, (256 * 7) / sizeof(JetT)> output_jets(
|
| 134 |
+
num_residuals());
|
| 135 |
+
|
| 136 |
+
// Make the parameter pack that is sent to the functor (reused).
|
| 137 |
+
internal::FixedArray<Jet<double, Stride>*> jet_parameters(
|
| 138 |
+
num_parameter_blocks, nullptr);
|
| 139 |
+
int num_active_parameters = 0;
|
| 140 |
+
|
| 141 |
+
// To handle constant parameters between non-constant parameter blocks, the
|
| 142 |
+
// start position --- a raw parameter index --- of each contiguous block of
|
| 143 |
+
// non-constant parameters is recorded in start_derivative_section.
|
| 144 |
+
std::vector<int> start_derivative_section;
|
| 145 |
+
bool in_derivative_section = false;
|
| 146 |
+
int parameter_cursor = 0;
|
| 147 |
+
|
| 148 |
+
// Discover the derivative sections and set the parameter values.
|
| 149 |
+
for (int i = 0; i < num_parameter_blocks; ++i) {
|
| 150 |
+
jet_parameters[i] = &input_jets[parameter_cursor];
|
| 151 |
+
|
| 152 |
+
const int parameter_block_size = parameter_block_sizes()[i];
|
| 153 |
+
if (jacobians[i] != nullptr) {
|
| 154 |
+
if (!in_derivative_section) {
|
| 155 |
+
start_derivative_section.push_back(parameter_cursor);
|
| 156 |
+
in_derivative_section = true;
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
num_active_parameters += parameter_block_size;
|
| 160 |
+
} else {
|
| 161 |
+
in_derivative_section = false;
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
for (int j = 0; j < parameter_block_size; ++j, parameter_cursor++) {
|
| 165 |
+
input_jets[parameter_cursor].a = parameters[i][j];
|
| 166 |
+
}
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
if (num_active_parameters == 0) {
|
| 170 |
+
return (*functor_)(parameters, residuals);
|
| 171 |
+
}
|
| 172 |
+
// When `num_active_parameters % Stride != 0` then it can be the case
|
| 173 |
+
// that `active_parameter_count < Stride` while parameter_cursor is less
|
| 174 |
+
// than the total number of parameters and with no remaining non-constant
|
| 175 |
+
// parameter blocks. Pushing parameter_cursor (the total number of
|
| 176 |
+
// parameters) as a final entry to start_derivative_section is required
|
| 177 |
+
// because if a constant parameter block is encountered after the
|
| 178 |
+
// last non-constant block then current_derivative_section is incremented
|
| 179 |
+
// and would otherwise index an invalid position in
|
| 180 |
+
// start_derivative_section. Setting the final element to the total number
|
| 181 |
+
// of parameters means that this can only happen at most once in the loop
|
| 182 |
+
// below.
|
| 183 |
+
start_derivative_section.push_back(parameter_cursor);
|
| 184 |
+
|
| 185 |
+
// Evaluate all of the strides. Each stride is a chunk of the derivative to
|
| 186 |
+
// evaluate, typically some size proportional to the size of the SIMD
|
| 187 |
+
// registers of the CPU.
|
| 188 |
+
int num_strides = static_cast<int>(
|
| 189 |
+
ceil(num_active_parameters / static_cast<float>(Stride)));
|
| 190 |
+
|
| 191 |
+
int current_derivative_section = 0;
|
| 192 |
+
int current_derivative_section_cursor = 0;
|
| 193 |
+
|
| 194 |
+
for (int pass = 0; pass < num_strides; ++pass) {
|
| 195 |
+
// Set most of the jet components to zero, except for
|
| 196 |
+
// non-constant #Stride parameters.
|
| 197 |
+
const int initial_derivative_section = current_derivative_section;
|
| 198 |
+
const int initial_derivative_section_cursor =
|
| 199 |
+
current_derivative_section_cursor;
|
| 200 |
+
|
| 201 |
+
int active_parameter_count = 0;
|
| 202 |
+
parameter_cursor = 0;
|
| 203 |
+
|
| 204 |
+
for (int i = 0; i < num_parameter_blocks; ++i) {
|
| 205 |
+
for (int j = 0; j < parameter_block_sizes()[i];
|
| 206 |
+
++j, parameter_cursor++) {
|
| 207 |
+
input_jets[parameter_cursor].v.setZero();
|
| 208 |
+
if (active_parameter_count < Stride &&
|
| 209 |
+
parameter_cursor >=
|
| 210 |
+
(start_derivative_section[current_derivative_section] +
|
| 211 |
+
current_derivative_section_cursor)) {
|
| 212 |
+
if (jacobians[i] != nullptr) {
|
| 213 |
+
input_jets[parameter_cursor].v[active_parameter_count] = 1.0;
|
| 214 |
+
++active_parameter_count;
|
| 215 |
+
++current_derivative_section_cursor;
|
| 216 |
+
} else {
|
| 217 |
+
++current_derivative_section;
|
| 218 |
+
current_derivative_section_cursor = 0;
|
| 219 |
+
}
|
| 220 |
+
}
|
| 221 |
+
}
|
| 222 |
+
}
|
| 223 |
+
|
| 224 |
+
if (!(*functor_)(&jet_parameters[0], &output_jets[0])) {
|
| 225 |
+
return false;
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
// Copy the pieces of the jacobians into their final place.
|
| 229 |
+
active_parameter_count = 0;
|
| 230 |
+
|
| 231 |
+
current_derivative_section = initial_derivative_section;
|
| 232 |
+
current_derivative_section_cursor = initial_derivative_section_cursor;
|
| 233 |
+
|
| 234 |
+
for (int i = 0, parameter_cursor = 0; i < num_parameter_blocks; ++i) {
|
| 235 |
+
for (int j = 0; j < parameter_block_sizes()[i];
|
| 236 |
+
++j, parameter_cursor++) {
|
| 237 |
+
if (active_parameter_count < Stride &&
|
| 238 |
+
parameter_cursor >=
|
| 239 |
+
(start_derivative_section[current_derivative_section] +
|
| 240 |
+
current_derivative_section_cursor)) {
|
| 241 |
+
if (jacobians[i] != nullptr) {
|
| 242 |
+
for (int k = 0; k < num_residuals(); ++k) {
|
| 243 |
+
jacobians[i][k * parameter_block_sizes()[i] + j] =
|
| 244 |
+
output_jets[k].v[active_parameter_count];
|
| 245 |
+
}
|
| 246 |
+
++active_parameter_count;
|
| 247 |
+
++current_derivative_section_cursor;
|
| 248 |
+
} else {
|
| 249 |
+
++current_derivative_section;
|
| 250 |
+
current_derivative_section_cursor = 0;
|
| 251 |
+
}
|
| 252 |
+
}
|
| 253 |
+
}
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
// Only copy the residuals over once (even though we compute them on
|
| 257 |
+
// every loop).
|
| 258 |
+
if (pass == num_strides - 1) {
|
| 259 |
+
for (int k = 0; k < num_residuals(); ++k) {
|
| 260 |
+
residuals[k] = output_jets[k].a;
|
| 261 |
+
}
|
| 262 |
+
}
|
| 263 |
+
}
|
| 264 |
+
return true;
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
private:
|
| 268 |
+
std::unique_ptr<CostFunctor> functor_;
|
| 269 |
+
Ownership ownership_;
|
| 270 |
+
};
|
| 271 |
+
|
| 272 |
+
} // namespace ceres
|
| 273 |
+
|
| 274 |
+
#endif // CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
|
include/ceres/dynamic_cost_function.h
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: sameeragarwal@google.com (Sameer Agarwal)
|
| 30 |
+
|
| 31 |
+
#ifndef CERES_PUBLIC_DYNAMIC_COST_FUNCTION_H_
|
| 32 |
+
#define CERES_PUBLIC_DYNAMIC_COST_FUNCTION_H_
|
| 33 |
+
|
| 34 |
+
#include "ceres/cost_function.h"
|
| 35 |
+
#include "ceres/internal/disable_warnings.h"
|
| 36 |
+
|
| 37 |
+
namespace ceres {
|
| 38 |
+
|
| 39 |
+
// A common base class for DynamicAutoDiffCostFunction and
|
| 40 |
+
// DynamicNumericDiffCostFunction which depend on methods that can add
|
| 41 |
+
// parameter blocks and set the number of residuals at run time.
|
| 42 |
+
class CERES_EXPORT DynamicCostFunction : public CostFunction {
|
| 43 |
+
public:
|
| 44 |
+
virtual void AddParameterBlock(int size) {
|
| 45 |
+
mutable_parameter_block_sizes()->push_back(size);
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
virtual void SetNumResiduals(int num_residuals) {
|
| 49 |
+
set_num_residuals(num_residuals);
|
| 50 |
+
}
|
| 51 |
+
};
|
| 52 |
+
|
| 53 |
+
} // namespace ceres
|
| 54 |
+
|
| 55 |
+
#include "ceres/internal/reenable_warnings.h"
|
| 56 |
+
|
| 57 |
+
#endif // CERES_PUBLIC_DYNAMIC_COST_FUNCTION_H_
|
include/ceres/dynamic_cost_function_to_functor.h
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: sameeragarwal@google.com (Sameer Agarwal)
|
| 30 |
+
// dgossow@google.com (David Gossow)
|
| 31 |
+
|
| 32 |
+
#ifndef CERES_PUBLIC_DYNAMIC_COST_FUNCTION_TO_FUNCTOR_H_
|
| 33 |
+
#define CERES_PUBLIC_DYNAMIC_COST_FUNCTION_TO_FUNCTOR_H_
|
| 34 |
+
|
| 35 |
+
#include <memory>
|
| 36 |
+
#include <numeric>
|
| 37 |
+
#include <vector>
|
| 38 |
+
|
| 39 |
+
#include "ceres/dynamic_cost_function.h"
|
| 40 |
+
#include "ceres/internal/disable_warnings.h"
|
| 41 |
+
#include "ceres/internal/export.h"
|
| 42 |
+
#include "ceres/internal/fixed_array.h"
|
| 43 |
+
#include "glog/logging.h"
|
| 44 |
+
|
| 45 |
+
namespace ceres {
|
| 46 |
+
|
| 47 |
+
// DynamicCostFunctionToFunctor allows users to use CostFunction
|
| 48 |
+
// objects in templated functors which are to be used for automatic
|
| 49 |
+
// differentiation. It works similar to CostFunctionToFunctor, with the
|
| 50 |
+
// difference that it allows you to wrap a cost function with dynamic numbers
|
| 51 |
+
// of parameters and residuals.
|
| 52 |
+
//
|
| 53 |
+
// For example, let us assume that
|
| 54 |
+
//
|
| 55 |
+
// class IntrinsicProjection : public CostFunction {
|
| 56 |
+
// public:
|
| 57 |
+
// IntrinsicProjection(const double* observation);
|
| 58 |
+
// bool Evaluate(double const* const* parameters,
|
| 59 |
+
// double* residuals,
|
| 60 |
+
// double** jacobians) const override;
|
| 61 |
+
// };
|
| 62 |
+
//
|
| 63 |
+
// is a cost function that implements the projection of a point in its
|
| 64 |
+
// local coordinate system onto its image plane and subtracts it from
|
| 65 |
+
// the observed point projection. It can compute its residual and
|
| 66 |
+
// either via analytic or numerical differentiation can compute its
|
| 67 |
+
// jacobians. The intrinsics are passed in as parameters[0] and the point as
|
| 68 |
+
// parameters[1].
|
| 69 |
+
//
|
| 70 |
+
// Now we would like to compose the action of this CostFunction with
|
| 71 |
+
// the action of camera extrinsics, i.e., rotation and
|
| 72 |
+
// translation. Say we have a templated function
|
| 73 |
+
//
|
| 74 |
+
// template<typename T>
|
| 75 |
+
// void RotateAndTranslatePoint(double const* const* parameters,
|
| 76 |
+
// double* residuals);
|
| 77 |
+
//
|
| 78 |
+
// Then we can now do the following,
|
| 79 |
+
//
|
| 80 |
+
// struct CameraProjection {
|
| 81 |
+
// CameraProjection(const double* observation)
|
| 82 |
+
// : intrinsic_projection_.(new IntrinsicProjection(observation)) {
|
| 83 |
+
// }
|
| 84 |
+
// template <typename T>
|
| 85 |
+
// bool operator()(T const* const* parameters,
|
| 86 |
+
// T* residual) const {
|
| 87 |
+
// const T* rotation = parameters[0];
|
| 88 |
+
// const T* translation = parameters[1];
|
| 89 |
+
// const T* intrinsics = parameters[2];
|
| 90 |
+
// const T* point = parameters[3];
|
| 91 |
+
// T transformed_point[3];
|
| 92 |
+
// RotateAndTranslatePoint(rotation, translation, point, transformed_point);
|
| 93 |
+
//
|
| 94 |
+
// // Note that we call intrinsic_projection_, just like it was
|
| 95 |
+
// // any other templated functor.
|
| 96 |
+
// const T* projection_parameters[2];
|
| 97 |
+
// projection_parameters[0] = intrinsics;
|
| 98 |
+
// projection_parameters[1] = transformed_point;
|
| 99 |
+
// return intrinsic_projection_(projection_parameters, residual);
|
| 100 |
+
// }
|
| 101 |
+
//
|
| 102 |
+
// private:
|
| 103 |
+
// DynamicCostFunctionToFunctor intrinsic_projection_;
|
| 104 |
+
// };
|
| 105 |
+
class CERES_EXPORT DynamicCostFunctionToFunctor {
|
| 106 |
+
public:
|
| 107 |
+
// Takes ownership of cost_function.
|
| 108 |
+
explicit DynamicCostFunctionToFunctor(CostFunction* cost_function)
|
| 109 |
+
: cost_function_(cost_function) {
|
| 110 |
+
CHECK(cost_function != nullptr);
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
bool operator()(double const* const* parameters, double* residuals) const {
|
| 114 |
+
return cost_function_->Evaluate(parameters, residuals, nullptr);
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
template <typename JetT>
|
| 118 |
+
bool operator()(JetT const* const* inputs, JetT* output) const {
|
| 119 |
+
const std::vector<int32_t>& parameter_block_sizes =
|
| 120 |
+
cost_function_->parameter_block_sizes();
|
| 121 |
+
const int num_parameter_blocks =
|
| 122 |
+
static_cast<int>(parameter_block_sizes.size());
|
| 123 |
+
const int num_residuals = cost_function_->num_residuals();
|
| 124 |
+
const int num_parameters = std::accumulate(
|
| 125 |
+
parameter_block_sizes.begin(), parameter_block_sizes.end(), 0);
|
| 126 |
+
|
| 127 |
+
internal::FixedArray<double> parameters(num_parameters);
|
| 128 |
+
internal::FixedArray<double*> parameter_blocks(num_parameter_blocks);
|
| 129 |
+
internal::FixedArray<double> jacobians(num_residuals * num_parameters);
|
| 130 |
+
internal::FixedArray<double*> jacobian_blocks(num_parameter_blocks);
|
| 131 |
+
internal::FixedArray<double> residuals(num_residuals);
|
| 132 |
+
|
| 133 |
+
// Build a set of arrays to get the residuals and jacobians from
|
| 134 |
+
// the CostFunction wrapped by this functor.
|
| 135 |
+
double* parameter_ptr = parameters.data();
|
| 136 |
+
double* jacobian_ptr = jacobians.data();
|
| 137 |
+
for (int i = 0; i < num_parameter_blocks; ++i) {
|
| 138 |
+
parameter_blocks[i] = parameter_ptr;
|
| 139 |
+
jacobian_blocks[i] = jacobian_ptr;
|
| 140 |
+
for (int j = 0; j < parameter_block_sizes[i]; ++j) {
|
| 141 |
+
*parameter_ptr++ = inputs[i][j].a;
|
| 142 |
+
}
|
| 143 |
+
jacobian_ptr += num_residuals * parameter_block_sizes[i];
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
if (!cost_function_->Evaluate(parameter_blocks.data(),
|
| 147 |
+
residuals.data(),
|
| 148 |
+
jacobian_blocks.data())) {
|
| 149 |
+
return false;
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
// Now that we have the incoming Jets, which are carrying the
|
| 153 |
+
// partial derivatives of each of the inputs w.r.t to some other
|
| 154 |
+
// underlying parameters. The derivative of the outputs of the
|
| 155 |
+
// cost function w.r.t to the same underlying parameters can now
|
| 156 |
+
// be computed by applying the chain rule.
|
| 157 |
+
//
|
| 158 |
+
// d output[i] d output[i] d input[j]
|
| 159 |
+
// -------------- = sum_j ----------- * ------------
|
| 160 |
+
// d parameter[k] d input[j] d parameter[k]
|
| 161 |
+
//
|
| 162 |
+
// d input[j]
|
| 163 |
+
// -------------- = inputs[j], so
|
| 164 |
+
// d parameter[k]
|
| 165 |
+
//
|
| 166 |
+
// outputJet[i] = sum_k jacobian[i][k] * inputJet[k]
|
| 167 |
+
//
|
| 168 |
+
// The following loop, iterates over the residuals, computing one
|
| 169 |
+
// output jet at a time.
|
| 170 |
+
for (int i = 0; i < num_residuals; ++i) {
|
| 171 |
+
output[i].a = residuals[i];
|
| 172 |
+
output[i].v.setZero();
|
| 173 |
+
|
| 174 |
+
for (int j = 0; j < num_parameter_blocks; ++j) {
|
| 175 |
+
const int32_t block_size = parameter_block_sizes[j];
|
| 176 |
+
for (int k = 0; k < parameter_block_sizes[j]; ++k) {
|
| 177 |
+
output[i].v +=
|
| 178 |
+
jacobian_blocks[j][i * block_size + k] * inputs[j][k].v;
|
| 179 |
+
}
|
| 180 |
+
}
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
return true;
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
private:
|
| 187 |
+
std::unique_ptr<CostFunction> cost_function_;
|
| 188 |
+
};
|
| 189 |
+
|
| 190 |
+
} // namespace ceres
|
| 191 |
+
|
| 192 |
+
#include "ceres/internal/reenable_warnings.h"
|
| 193 |
+
|
| 194 |
+
#endif // CERES_PUBLIC_DYNAMIC_COST_FUNCTION_TO_FUNCTOR_H_
|
include/ceres/dynamic_numeric_diff_cost_function.h
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: mierle@gmail.com (Keir Mierle)
|
| 30 |
+
// sameeragarwal@google.com (Sameer Agarwal)
|
| 31 |
+
// thadh@gmail.com (Thad Hughes)
|
| 32 |
+
// tbennun@gmail.com (Tal Ben-Nun)
|
| 33 |
+
|
| 34 |
+
#ifndef CERES_PUBLIC_DYNAMIC_NUMERIC_DIFF_COST_FUNCTION_H_
|
| 35 |
+
#define CERES_PUBLIC_DYNAMIC_NUMERIC_DIFF_COST_FUNCTION_H_
|
| 36 |
+
|
| 37 |
+
#include <cmath>
|
| 38 |
+
#include <memory>
|
| 39 |
+
#include <numeric>
|
| 40 |
+
#include <vector>
|
| 41 |
+
|
| 42 |
+
#include "ceres/dynamic_cost_function.h"
|
| 43 |
+
#include "ceres/internal/eigen.h"
|
| 44 |
+
#include "ceres/internal/numeric_diff.h"
|
| 45 |
+
#include "ceres/internal/parameter_dims.h"
|
| 46 |
+
#include "ceres/numeric_diff_options.h"
|
| 47 |
+
#include "ceres/types.h"
|
| 48 |
+
#include "glog/logging.h"
|
| 49 |
+
|
| 50 |
+
namespace ceres {
|
| 51 |
+
|
| 52 |
+
// This numeric diff implementation differs from the one found in
|
| 53 |
+
// numeric_diff_cost_function.h by supporting numericdiff on cost
|
| 54 |
+
// functions with variable numbers of parameters with variable
|
| 55 |
+
// sizes. With the other implementation, all the sizes (both the
|
| 56 |
+
// number of parameter blocks and the size of each block) must be
|
| 57 |
+
// fixed at compile time.
|
| 58 |
+
//
|
| 59 |
+
// The functor API differs slightly from the API for fixed size
|
| 60 |
+
// numeric diff; the expected interface for the cost functors is:
|
| 61 |
+
//
|
| 62 |
+
// struct MyCostFunctor {
|
| 63 |
+
// bool operator()(double const*
|
| 64 |
+
// const* parameters,
|
| 65 |
+
// double* residuals) const {
|
| 66 |
+
// // Use parameters[i] to access the i'th parameter block.
|
| 67 |
+
// }
|
| 68 |
+
// }
|
| 69 |
+
//
|
| 70 |
+
// Since the sizing of the parameters is done at runtime, you must
|
| 71 |
+
// also specify the sizes after creating the
|
| 72 |
+
// DynamicNumericDiffCostFunction. For example:
|
| 73 |
+
//
|
| 74 |
+
// DynamicAutoDiffCostFunction<MyCostFunctor, CENTRAL> cost_function(
|
| 75 |
+
// new MyCostFunctor());
|
| 76 |
+
// cost_function.AddParameterBlock(5);
|
| 77 |
+
// cost_function.AddParameterBlock(10);
|
| 78 |
+
// cost_function.SetNumResiduals(21);
|
| 79 |
+
template <typename CostFunctor, NumericDiffMethodType method = CENTRAL>
|
| 80 |
+
class DynamicNumericDiffCostFunction final : public DynamicCostFunction {
|
| 81 |
+
public:
|
| 82 |
+
explicit DynamicNumericDiffCostFunction(
|
| 83 |
+
const CostFunctor* functor,
|
| 84 |
+
Ownership ownership = TAKE_OWNERSHIP,
|
| 85 |
+
const NumericDiffOptions& options = NumericDiffOptions())
|
| 86 |
+
: functor_(functor), ownership_(ownership), options_(options) {}
|
| 87 |
+
|
| 88 |
+
DynamicNumericDiffCostFunction(DynamicNumericDiffCostFunction&& other)
|
| 89 |
+
: functor_(std::move(other.functor_)), ownership_(other.ownership_) {}
|
| 90 |
+
|
| 91 |
+
~DynamicNumericDiffCostFunction() override {
|
| 92 |
+
if (ownership_ != TAKE_OWNERSHIP) {
|
| 93 |
+
functor_.release();
|
| 94 |
+
}
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
bool Evaluate(double const* const* parameters,
|
| 98 |
+
double* residuals,
|
| 99 |
+
double** jacobians) const override {
|
| 100 |
+
using internal::NumericDiff;
|
| 101 |
+
CHECK_GT(num_residuals(), 0)
|
| 102 |
+
<< "You must call DynamicNumericDiffCostFunction::SetNumResiduals() "
|
| 103 |
+
<< "before DynamicNumericDiffCostFunction::Evaluate().";
|
| 104 |
+
|
| 105 |
+
const std::vector<int32_t>& block_sizes = parameter_block_sizes();
|
| 106 |
+
CHECK(!block_sizes.empty())
|
| 107 |
+
<< "You must call DynamicNumericDiffCostFunction::AddParameterBlock() "
|
| 108 |
+
<< "before DynamicNumericDiffCostFunction::Evaluate().";
|
| 109 |
+
|
| 110 |
+
const bool status =
|
| 111 |
+
internal::VariadicEvaluate<internal::DynamicParameterDims>(
|
| 112 |
+
*functor_.get(), parameters, residuals);
|
| 113 |
+
if (jacobians == nullptr || !status) {
|
| 114 |
+
return status;
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
// Create local space for a copy of the parameters which will get mutated.
|
| 118 |
+
int parameters_size = accumulate(block_sizes.begin(), block_sizes.end(), 0);
|
| 119 |
+
std::vector<double> parameters_copy(parameters_size);
|
| 120 |
+
std::vector<double*> parameters_references_copy(block_sizes.size());
|
| 121 |
+
parameters_references_copy[0] = ¶meters_copy[0];
|
| 122 |
+
for (size_t block = 1; block < block_sizes.size(); ++block) {
|
| 123 |
+
parameters_references_copy[block] =
|
| 124 |
+
parameters_references_copy[block - 1] + block_sizes[block - 1];
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
// Copy the parameters into the local temp space.
|
| 128 |
+
for (size_t block = 0; block < block_sizes.size(); ++block) {
|
| 129 |
+
memcpy(parameters_references_copy[block],
|
| 130 |
+
parameters[block],
|
| 131 |
+
block_sizes[block] * sizeof(*parameters[block]));
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
for (size_t block = 0; block < block_sizes.size(); ++block) {
|
| 135 |
+
if (jacobians[block] != nullptr &&
|
| 136 |
+
!NumericDiff<CostFunctor,
|
| 137 |
+
method,
|
| 138 |
+
ceres::DYNAMIC,
|
| 139 |
+
internal::DynamicParameterDims,
|
| 140 |
+
ceres::DYNAMIC,
|
| 141 |
+
ceres::DYNAMIC>::
|
| 142 |
+
EvaluateJacobianForParameterBlock(functor_.get(),
|
| 143 |
+
residuals,
|
| 144 |
+
options_,
|
| 145 |
+
this->num_residuals(),
|
| 146 |
+
block,
|
| 147 |
+
block_sizes[block],
|
| 148 |
+
¶meters_references_copy[0],
|
| 149 |
+
jacobians[block])) {
|
| 150 |
+
return false;
|
| 151 |
+
}
|
| 152 |
+
}
|
| 153 |
+
return true;
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
private:
|
| 157 |
+
std::unique_ptr<const CostFunctor> functor_;
|
| 158 |
+
Ownership ownership_;
|
| 159 |
+
NumericDiffOptions options_;
|
| 160 |
+
};
|
| 161 |
+
|
| 162 |
+
} // namespace ceres
|
| 163 |
+
|
| 164 |
+
#endif // CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
|
include/ceres/evaluation_callback.h
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: mierle@gmail.com (Keir Mierle)
|
| 30 |
+
|
| 31 |
+
#ifndef CERES_PUBLIC_EVALUATION_CALLBACK_H_
|
| 32 |
+
#define CERES_PUBLIC_EVALUATION_CALLBACK_H_
|
| 33 |
+
|
| 34 |
+
#include "ceres/internal/export.h"
|
| 35 |
+
|
| 36 |
+
namespace ceres {
|
| 37 |
+
|
| 38 |
+
// Using this callback interface, Ceres can notify you when it is
|
| 39 |
+
// about to evaluate the residuals or jacobians. With the callback,
|
| 40 |
+
// you can share computation between residual blocks by doing the
|
| 41 |
+
// shared computation in PrepareForEvaluation() before Ceres calls
|
| 42 |
+
// CostFunction::Evaluate(). It also enables caching results between a
|
| 43 |
+
// pure residual evaluation and a residual & jacobian evaluation, via
|
| 44 |
+
// the new_evaluation_point argument.
|
| 45 |
+
//
|
| 46 |
+
// One use case for this callback is if the cost function compute is
|
| 47 |
+
// moved to the GPU. In that case, the prepare call does the actual
|
| 48 |
+
// cost function evaluation, and subsequent calls from Ceres to the
|
| 49 |
+
// actual cost functions merely copy the results from the GPU onto the
|
| 50 |
+
// corresponding blocks for Ceres to plug into the solver.
|
| 51 |
+
//
|
| 52 |
+
// NOTE: Ceres provides no mechanism to share data other than the
|
| 53 |
+
// notification from the callback. Users must provide access to
|
| 54 |
+
// pre-computed shared data to their cost functions behind the scenes;
|
| 55 |
+
// this all happens without Ceres knowing.
|
| 56 |
+
//
|
| 57 |
+
// One approach is to put a pointer to the shared data in each cost
|
| 58 |
+
// function (recommended) or to use a global shared variable
|
| 59 |
+
// (discouraged; bug-prone). As far as Ceres is concerned, it is
|
| 60 |
+
// evaluating cost functions like any other; it just so happens that
|
| 61 |
+
// behind the scenes the cost functions reuse pre-computed data to
|
| 62 |
+
// execute faster.
|
| 63 |
+
class CERES_EXPORT EvaluationCallback {
|
| 64 |
+
public:
|
| 65 |
+
virtual ~EvaluationCallback();
|
| 66 |
+
|
| 67 |
+
// Called before Ceres requests residuals or jacobians for a given setting of
|
| 68 |
+
// the parameters. User parameters (the double* values provided to the cost
|
| 69 |
+
// functions) are fixed until the next call to PrepareForEvaluation(). If
|
| 70 |
+
// new_evaluation_point == true, then this is a new point that is different
|
| 71 |
+
// from the last evaluated point. Otherwise, it is the same point that was
|
| 72 |
+
// evaluated previously (either jacobian or residual) and the user can use
|
| 73 |
+
// cached results from previous evaluations.
|
| 74 |
+
virtual void PrepareForEvaluation(bool evaluate_jacobians,
|
| 75 |
+
bool new_evaluation_point) = 0;
|
| 76 |
+
};
|
| 77 |
+
|
| 78 |
+
} // namespace ceres
|
| 79 |
+
|
| 80 |
+
#endif // CERES_PUBLIC_EVALUATION_CALLBACK_H_
|
include/ceres/first_order_function.h
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: sameeragarwal@google.com (Sameer Agarwal)
|
| 30 |
+
|
| 31 |
+
#ifndef CERES_PUBLIC_FIRST_ORDER_FUNCTION_H_
|
| 32 |
+
#define CERES_PUBLIC_FIRST_ORDER_FUNCTION_H_
|
| 33 |
+
|
| 34 |
+
#include "ceres/internal/export.h"
|
| 35 |
+
|
| 36 |
+
namespace ceres {
|
| 37 |
+
|
| 38 |
+
// A FirstOrderFunction object implements the evaluation of a function
|
| 39 |
+
// and its gradient.
|
| 40 |
+
class CERES_EXPORT FirstOrderFunction {
|
| 41 |
+
public:
|
| 42 |
+
virtual ~FirstOrderFunction();
|
| 43 |
+
|
| 44 |
+
// cost is never null. gradient may be null. The return value
|
| 45 |
+
// indicates whether the evaluation was successful or not.
|
| 46 |
+
virtual bool Evaluate(const double* const parameters,
|
| 47 |
+
double* cost,
|
| 48 |
+
double* gradient) const = 0;
|
| 49 |
+
virtual int NumParameters() const = 0;
|
| 50 |
+
};
|
| 51 |
+
|
| 52 |
+
} // namespace ceres
|
| 53 |
+
|
| 54 |
+
#endif // CERES_PUBLIC_FIRST_ORDER_FUNCTION_H_
|
include/ceres/gradient_checker.h
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
// Copyright 2007 Google Inc. All Rights Reserved.
|
| 29 |
+
//
|
| 30 |
+
// Authors: wjr@google.com (William Rucklidge),
|
| 31 |
+
// keir@google.com (Keir Mierle),
|
| 32 |
+
// dgossow@google.com (David Gossow)
|
| 33 |
+
|
| 34 |
+
#ifndef CERES_PUBLIC_GRADIENT_CHECKER_H_
|
| 35 |
+
#define CERES_PUBLIC_GRADIENT_CHECKER_H_
|
| 36 |
+
|
| 37 |
+
#include <memory>
|
| 38 |
+
#include <string>
|
| 39 |
+
#include <vector>
|
| 40 |
+
|
| 41 |
+
#include "ceres/cost_function.h"
|
| 42 |
+
#include "ceres/dynamic_numeric_diff_cost_function.h"
|
| 43 |
+
#include "ceres/internal/disable_warnings.h"
|
| 44 |
+
#include "ceres/internal/eigen.h"
|
| 45 |
+
#include "ceres/internal/export.h"
|
| 46 |
+
#include "ceres/internal/fixed_array.h"
|
| 47 |
+
#include "ceres/local_parameterization.h"
|
| 48 |
+
#include "ceres/manifold.h"
|
| 49 |
+
#include "glog/logging.h"
|
| 50 |
+
|
| 51 |
+
namespace ceres {
|
| 52 |
+
|
| 53 |
+
// GradientChecker compares the Jacobians returned by a cost function against
|
| 54 |
+
// derivatives estimated using finite differencing.
|
| 55 |
+
//
|
| 56 |
+
// The condition enforced is that
|
| 57 |
+
//
|
| 58 |
+
// (J_actual(i, j) - J_numeric(i, j))
|
| 59 |
+
// ------------------------------------ < relative_precision
|
| 60 |
+
// max(J_actual(i, j), J_numeric(i, j))
|
| 61 |
+
//
|
| 62 |
+
// where J_actual(i, j) is the jacobian as computed by the supplied cost
|
| 63 |
+
// function (by the user) multiplied by the local parameterization Jacobian
|
| 64 |
+
// and J_numeric is the jacobian as computed by finite differences, multiplied
|
| 65 |
+
// by the local parameterization Jacobian as well.
|
| 66 |
+
//
|
| 67 |
+
// How to use: Fill in an array of pointers to parameter blocks for your
|
| 68 |
+
// CostFunction, and then call Probe(). Check that the return value is 'true'.
|
| 69 |
+
class CERES_EXPORT GradientChecker {
|
| 70 |
+
public:
|
| 71 |
+
// This constructor will not take ownership of the cost function or local
|
| 72 |
+
// parameterizations.
|
| 73 |
+
//
|
| 74 |
+
// function: The cost function to probe.
|
| 75 |
+
//
|
| 76 |
+
// local_parameterizations: A vector of local parameterizations, one for each
|
| 77 |
+
// parameter block. May be nullptr or contain nullptrs to indicate that the
|
| 78 |
+
// respective parameter does not have a local parameterization.
|
| 79 |
+
//
|
| 80 |
+
// options: Options to use for numerical differentiation.
|
| 81 |
+
//
|
| 82 |
+
// NOTE: This constructor is deprecated and will be removed in the next public
|
| 83 |
+
// release of Ceres Solver. Please transition to using the Manifold based
|
| 84 |
+
// version.
|
| 85 |
+
CERES_DEPRECATED_WITH_MSG(
|
| 86 |
+
"Local Parameterizations are deprecated. Use the constructor that uses "
|
| 87 |
+
"Manifolds instead.")
|
| 88 |
+
GradientChecker(
|
| 89 |
+
const CostFunction* function,
|
| 90 |
+
const std::vector<const LocalParameterization*>* local_parameterizations,
|
| 91 |
+
const NumericDiffOptions& options);
|
| 92 |
+
|
| 93 |
+
// This will not take ownership of the cost function or manifolds.
|
| 94 |
+
//
|
| 95 |
+
// function: The cost function to probe.
|
| 96 |
+
//
|
| 97 |
+
// manifolds: A vector of manifolds for each parameter. May be nullptr or
|
| 98 |
+
// contain nullptrs to indicate that the respective parameter blocks are
|
| 99 |
+
// Euclidean.
|
| 100 |
+
//
|
| 101 |
+
// options: Options to use for numerical differentiation.
|
| 102 |
+
GradientChecker(const CostFunction* function,
|
| 103 |
+
const std::vector<const Manifold*>* manifolds,
|
| 104 |
+
const NumericDiffOptions& options);
|
| 105 |
+
~GradientChecker();
|
| 106 |
+
|
| 107 |
+
// Contains results from a call to Probe for later inspection.
|
| 108 |
+
struct CERES_EXPORT ProbeResults {
|
| 109 |
+
// The return value of the cost function.
|
| 110 |
+
bool return_value;
|
| 111 |
+
|
| 112 |
+
// Computed residual vector.
|
| 113 |
+
Vector residuals;
|
| 114 |
+
|
| 115 |
+
// The sizes of the Jacobians below are dictated by the cost function's
|
| 116 |
+
// parameter block size and residual block sizes. If a parameter block has a
|
| 117 |
+
// manifold associated with it, the size of the "local" Jacobian will be
|
| 118 |
+
// determined by the dimension of the manifold (which is the same as the
|
| 119 |
+
// dimension of the tangent space) and residual block size, otherwise it
|
| 120 |
+
// will be identical to the regular Jacobian.
|
| 121 |
+
|
| 122 |
+
// Derivatives as computed by the cost function.
|
| 123 |
+
std::vector<Matrix> jacobians;
|
| 124 |
+
|
| 125 |
+
// Derivatives as computed by the cost function in local space.
|
| 126 |
+
std::vector<Matrix> local_jacobians;
|
| 127 |
+
|
| 128 |
+
// Derivatives as computed by numerical differentiation in local space.
|
| 129 |
+
std::vector<Matrix> numeric_jacobians;
|
| 130 |
+
|
| 131 |
+
// Derivatives as computed by numerical differentiation in local space.
|
| 132 |
+
std::vector<Matrix> local_numeric_jacobians;
|
| 133 |
+
|
| 134 |
+
// Contains the maximum relative error found in the local Jacobians.
|
| 135 |
+
double maximum_relative_error;
|
| 136 |
+
|
| 137 |
+
// If an error was detected, this will contain a detailed description of
|
| 138 |
+
// that error.
|
| 139 |
+
std::string error_log;
|
| 140 |
+
};
|
| 141 |
+
|
| 142 |
+
// Call the cost function, compute alternative Jacobians using finite
|
| 143 |
+
// differencing and compare results. If manifolds are given, the Jacobians
|
| 144 |
+
// will be multiplied by the manifold Jacobians before performing the check,
|
| 145 |
+
// which effectively means that all errors along the null space of the
|
| 146 |
+
// manifold will be ignored. Returns false if the Jacobians don't match, the
|
| 147 |
+
// cost function return false, or if a cost function returns a different
|
| 148 |
+
// residual when called with a Jacobian output argument vs. calling it
|
| 149 |
+
// without. Otherwise returns true.
|
| 150 |
+
//
|
| 151 |
+
// parameters: The parameter values at which to probe.
|
| 152 |
+
// relative_precision: A threshold for the relative difference between the
|
| 153 |
+
// Jacobians. If the Jacobians differ by more than this amount, then the
|
| 154 |
+
// probe fails.
|
| 155 |
+
// results: On return, the Jacobians (and other information) will be stored
|
| 156 |
+
// here. May be nullptr.
|
| 157 |
+
//
|
| 158 |
+
// Returns true if no problems are detected and the difference between the
|
| 159 |
+
// Jacobians is less than error_tolerance.
|
| 160 |
+
bool Probe(double const* const* parameters,
|
| 161 |
+
double relative_precision,
|
| 162 |
+
ProbeResults* results) const;
|
| 163 |
+
|
| 164 |
+
private:
|
| 165 |
+
GradientChecker() = delete;
|
| 166 |
+
GradientChecker(const GradientChecker&) = delete;
|
| 167 |
+
void operator=(const GradientChecker&) = delete;
|
| 168 |
+
|
| 169 |
+
// This bool is used to determine whether the constructor with the
|
| 170 |
+
// LocalParameterizations is called or the one with Manifolds is called. If
|
| 171 |
+
// the former, then the vector of manifolds is a vector of ManifoldAdapter
|
| 172 |
+
// objects which we own and should be deleted. If the latter then they are
|
| 173 |
+
// real Manifold objects owned by the caller and will not be deleted.
|
| 174 |
+
//
|
| 175 |
+
// This bool is only needed during the LocalParameterization to Manifold
|
| 176 |
+
// transition, once this transition is complete the LocalParameterization
|
| 177 |
+
// based constructor and this bool will be removed.
|
| 178 |
+
const bool delete_manifolds_ = false;
|
| 179 |
+
|
| 180 |
+
std::vector<const Manifold*> manifolds_;
|
| 181 |
+
const CostFunction* function_;
|
| 182 |
+
std::unique_ptr<CostFunction> finite_diff_cost_function_;
|
| 183 |
+
};
|
| 184 |
+
|
| 185 |
+
} // namespace ceres
|
| 186 |
+
|
| 187 |
+
#include "ceres/internal/reenable_warnings.h"
|
| 188 |
+
|
| 189 |
+
#endif // CERES_PUBLIC_GRADIENT_CHECKER_H_
|
include/ceres/gradient_problem.h
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: sameeragarwal@google.com (Sameer Agarwal)
|
| 30 |
+
|
| 31 |
+
#ifndef CERES_PUBLIC_GRADIENT_PROBLEM_H_
|
| 32 |
+
#define CERES_PUBLIC_GRADIENT_PROBLEM_H_
|
| 33 |
+
|
| 34 |
+
#include <memory>
|
| 35 |
+
|
| 36 |
+
#include "ceres/first_order_function.h"
|
| 37 |
+
#include "ceres/internal/disable_warnings.h"
|
| 38 |
+
#include "ceres/internal/export.h"
|
| 39 |
+
#include "ceres/local_parameterization.h"
|
| 40 |
+
#include "ceres/manifold.h"
|
| 41 |
+
|
| 42 |
+
namespace ceres {
|
| 43 |
+
|
| 44 |
+
class FirstOrderFunction;
|
| 45 |
+
|
| 46 |
+
// Instances of GradientProblem represent general non-linear
|
| 47 |
+
// optimization problems that must be solved using just the value of
|
| 48 |
+
// the objective function and its gradient.
|
| 49 |
+
|
| 50 |
+
// Unlike the Problem class, which can only be used to model non-linear least
|
| 51 |
+
// squares problems, instances of GradientProblem are not restricted in the form
|
| 52 |
+
// of the objective function.
|
| 53 |
+
//
|
| 54 |
+
// Structurally GradientProblem is a composition of a FirstOrderFunction and
|
| 55 |
+
// optionally a Manifold.
|
| 56 |
+
//
|
| 57 |
+
// The FirstOrderFunction is responsible for evaluating the cost and gradient of
|
| 58 |
+
// the objective function.
|
| 59 |
+
//
|
| 60 |
+
// The Manifold is responsible for going back and forth between the ambient
|
| 61 |
+
// space and the local tangent space. (See manifold.h for more details). When a
|
| 62 |
+
// Manifold is not provided, then the tangent space is assumed to coincide with
|
| 63 |
+
// the ambient Euclidean space that the gradient vector lives in.
|
| 64 |
+
//
|
| 65 |
+
// Example usage:
|
| 66 |
+
//
|
| 67 |
+
// The following demonstrate the problem construction for Rosenbrock's function
|
| 68 |
+
//
|
| 69 |
+
// f(x,y) = (1-x)^2 + 100(y - x^2)^2;
|
| 70 |
+
//
|
| 71 |
+
// class Rosenbrock : public ceres::FirstOrderFunction {
|
| 72 |
+
// public:
|
| 73 |
+
// virtual ~Rosenbrock() {}
|
| 74 |
+
//
|
| 75 |
+
// virtual bool Evaluate(const double* parameters,
|
| 76 |
+
// double* cost,
|
| 77 |
+
// double* gradient) const {
|
| 78 |
+
// const double x = parameters[0];
|
| 79 |
+
// const double y = parameters[1];
|
| 80 |
+
//
|
| 81 |
+
// cost[0] = (1.0 - x) * (1.0 - x) + 100.0 * (y - x * x) * (y - x * x);
|
| 82 |
+
// if (gradient != nullptr) {
|
| 83 |
+
// gradient[0] = -2.0 * (1.0 - x) - 200.0 * (y - x * x) * 2.0 * x;
|
| 84 |
+
// gradient[1] = 200.0 * (y - x * x);
|
| 85 |
+
// }
|
| 86 |
+
// return true;
|
| 87 |
+
// };
|
| 88 |
+
//
|
| 89 |
+
// virtual int NumParameters() const { return 2; };
|
| 90 |
+
// };
|
| 91 |
+
//
|
| 92 |
+
// ceres::GradientProblem problem(new Rosenbrock());
|
| 93 |
+
//
|
| 94 |
+
// NOTE: We are currently in the process of transitioning from
|
| 95 |
+
// LocalParameterization to Manifolds in the Ceres API. During this period,
|
| 96 |
+
// GradientProblem will support using both Manifold and LocalParameterization
|
| 97 |
+
// objects interchangably. For methods in the API affected by this change, see
|
| 98 |
+
// their documentation below.
|
| 99 |
+
class CERES_EXPORT GradientProblem {
|
| 100 |
+
public:
|
| 101 |
+
// Takes ownership of the function.
|
| 102 |
+
explicit GradientProblem(FirstOrderFunction* function);
|
| 103 |
+
|
| 104 |
+
// Takes ownership of the function and the parameterization.
|
| 105 |
+
//
|
| 106 |
+
// NOTE: This constructor is deprecated and will be removed in the next public
|
| 107 |
+
// release of Ceres Solver. Please move to using the Manifold based
|
| 108 |
+
// constructor.
|
| 109 |
+
CERES_DEPRECATED_WITH_MSG(
|
| 110 |
+
"LocalParameterizations are deprecated. Please use the constructor that "
|
| 111 |
+
"uses Manifold instead.")
|
| 112 |
+
GradientProblem(FirstOrderFunction* function,
|
| 113 |
+
LocalParameterization* parameterization);
|
| 114 |
+
|
| 115 |
+
// Takes ownership of the function and the manifold.
|
| 116 |
+
GradientProblem(FirstOrderFunction* function, Manifold* manifold);
|
| 117 |
+
|
| 118 |
+
int NumParameters() const;
|
| 119 |
+
|
| 120 |
+
// Dimension of the manifold (and its tangent space).
|
| 121 |
+
//
|
| 122 |
+
// During the transition from LocalParameterization to Manifold, this method
|
| 123 |
+
// reports the LocalSize of the LocalParameterization or the TangentSize of
|
| 124 |
+
// the Manifold object associated with this problem.
|
| 125 |
+
int NumTangentParameters() const;
|
| 126 |
+
|
| 127 |
+
// Dimension of the manifold (and its tangent space).
|
| 128 |
+
//
|
| 129 |
+
// NOTE: This method is deprecated and will be removed in the next public
|
| 130 |
+
// release of Ceres Solver. Please move to using NumTangentParameters()
|
| 131 |
+
// instead.
|
| 132 |
+
int NumLocalParameters() const { return NumTangentParameters(); }
|
| 133 |
+
|
| 134 |
+
// This call is not thread safe.
|
| 135 |
+
bool Evaluate(const double* parameters, double* cost, double* gradient) const;
|
| 136 |
+
bool Plus(const double* x, const double* delta, double* x_plus_delta) const;
|
| 137 |
+
|
| 138 |
+
const FirstOrderFunction* function() const { return function_.get(); }
|
| 139 |
+
FirstOrderFunction* mutable_function() { return function_.get(); }
|
| 140 |
+
|
| 141 |
+
// NOTE: During the transition from LocalParameterization to Manifold we need
|
| 142 |
+
// to support both The LocalParameterization and Manifold based constructors.
|
| 143 |
+
//
|
| 144 |
+
// When the user uses the LocalParameterization, internally the solver will
|
| 145 |
+
// wrap it in a ManifoldAdapter object and return it when manifold or
|
| 146 |
+
// mutable_manifold are called.
|
| 147 |
+
//
|
| 148 |
+
// As a result this method will return a non-nullptr result if a Manifold or a
|
| 149 |
+
// LocalParameterization was used when constructing the GradientProblem.
|
| 150 |
+
const Manifold* manifold() const { return manifold_.get(); }
|
| 151 |
+
Manifold* mutable_manifold() { return manifold_.get(); }
|
| 152 |
+
|
| 153 |
+
// If the problem is constructed without a LocalParameterization or with a
|
| 154 |
+
// Manifold this method will return a nullptr.
|
| 155 |
+
//
|
| 156 |
+
// NOTE: This method is deprecated and will be removed in the next public
|
| 157 |
+
// release of Ceres Solver.
|
| 158 |
+
CERES_DEPRECATED_WITH_MSG("Use Manifolds instead.")
|
| 159 |
+
const LocalParameterization* parameterization() const {
|
| 160 |
+
return parameterization_.get();
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
// If the problem is constructed without a LocalParameterization or with a
|
| 164 |
+
// Manifold this method will return a nullptr.
|
| 165 |
+
//
|
| 166 |
+
// NOTE: This method is deprecated and will be removed in the next public
|
| 167 |
+
// release of Ceres Solver.
|
| 168 |
+
CERES_DEPRECATED_WITH_MSG("Use Manifolds instead.")
|
| 169 |
+
LocalParameterization* mutable_parameterization() {
|
| 170 |
+
return parameterization_.get();
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
private:
|
| 174 |
+
std::unique_ptr<FirstOrderFunction> function_;
|
| 175 |
+
CERES_DEPRECATED_WITH_MSG("")
|
| 176 |
+
std::unique_ptr<LocalParameterization> parameterization_;
|
| 177 |
+
std::unique_ptr<Manifold> manifold_;
|
| 178 |
+
std::unique_ptr<double[]> scratch_;
|
| 179 |
+
};
|
| 180 |
+
|
| 181 |
+
} // namespace ceres
|
| 182 |
+
|
| 183 |
+
#include "ceres/internal/reenable_warnings.h"
|
| 184 |
+
|
| 185 |
+
#endif // CERES_PUBLIC_GRADIENT_PROBLEM_H_
|
include/ceres/gradient_problem_solver.h
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: sameeragarwal@google.com (Sameer Agarwal)
|
| 30 |
+
|
| 31 |
+
#ifndef CERES_PUBLIC_GRADIENT_PROBLEM_SOLVER_H_
|
| 32 |
+
#define CERES_PUBLIC_GRADIENT_PROBLEM_SOLVER_H_
|
| 33 |
+
|
| 34 |
+
#include <cmath>
|
| 35 |
+
#include <string>
|
| 36 |
+
#include <vector>
|
| 37 |
+
|
| 38 |
+
#include "ceres/internal/disable_warnings.h"
|
| 39 |
+
#include "ceres/internal/export.h"
|
| 40 |
+
#include "ceres/internal/port.h"
|
| 41 |
+
#include "ceres/iteration_callback.h"
|
| 42 |
+
#include "ceres/types.h"
|
| 43 |
+
|
| 44 |
+
namespace ceres {
|
| 45 |
+
|
| 46 |
+
class GradientProblem;
|
| 47 |
+
|
| 48 |
+
class CERES_EXPORT GradientProblemSolver {
|
| 49 |
+
public:
|
| 50 |
+
virtual ~GradientProblemSolver();
|
| 51 |
+
|
| 52 |
+
// The options structure contains, not surprisingly, options that control how
|
| 53 |
+
// the solver operates. The defaults should be suitable for a wide range of
|
| 54 |
+
// problems; however, better performance is often obtainable with tweaking.
|
| 55 |
+
//
|
| 56 |
+
// The constants are defined inside types.h
|
| 57 |
+
struct CERES_EXPORT Options {
|
| 58 |
+
// Returns true if the options struct has a valid
|
| 59 |
+
// configuration. Returns false otherwise, and fills in *error
|
| 60 |
+
// with a message describing the problem.
|
| 61 |
+
bool IsValid(std::string* error) const;
|
| 62 |
+
|
| 63 |
+
// Minimizer options ----------------------------------------
|
| 64 |
+
LineSearchDirectionType line_search_direction_type = LBFGS;
|
| 65 |
+
LineSearchType line_search_type = WOLFE;
|
| 66 |
+
NonlinearConjugateGradientType nonlinear_conjugate_gradient_type =
|
| 67 |
+
FLETCHER_REEVES;
|
| 68 |
+
|
| 69 |
+
// The LBFGS hessian approximation is a low rank approximation to
|
| 70 |
+
// the inverse of the Hessian matrix. The rank of the
|
| 71 |
+
// approximation determines (linearly) the space and time
|
| 72 |
+
// complexity of using the approximation. Higher the rank, the
|
| 73 |
+
// better is the quality of the approximation. The increase in
|
| 74 |
+
// quality is however is bounded for a number of reasons.
|
| 75 |
+
//
|
| 76 |
+
// 1. The method only uses secant information and not actual
|
| 77 |
+
// derivatives.
|
| 78 |
+
//
|
| 79 |
+
// 2. The Hessian approximation is constrained to be positive
|
| 80 |
+
// definite.
|
| 81 |
+
//
|
| 82 |
+
// So increasing this rank to a large number will cost time and
|
| 83 |
+
// space complexity without the corresponding increase in solution
|
| 84 |
+
// quality. There are no hard and fast rules for choosing the
|
| 85 |
+
// maximum rank. The best choice usually requires some problem
|
| 86 |
+
// specific experimentation.
|
| 87 |
+
//
|
| 88 |
+
// For more theoretical and implementation details of the LBFGS
|
| 89 |
+
// method, please see:
|
| 90 |
+
//
|
| 91 |
+
// Nocedal, J. (1980). "Updating Quasi-Newton Matrices with
|
| 92 |
+
// Limited Storage". Mathematics of Computation 35 (151): 773-782.
|
| 93 |
+
int max_lbfgs_rank = 20;
|
| 94 |
+
|
| 95 |
+
// As part of the (L)BFGS update step (BFGS) / right-multiply step (L-BFGS),
|
| 96 |
+
// the initial inverse Hessian approximation is taken to be the Identity.
|
| 97 |
+
// However, Oren showed that using instead I * \gamma, where \gamma is
|
| 98 |
+
// chosen to approximate an eigenvalue of the true inverse Hessian can
|
| 99 |
+
// result in improved convergence in a wide variety of cases. Setting
|
| 100 |
+
// use_approximate_eigenvalue_bfgs_scaling to true enables this scaling.
|
| 101 |
+
//
|
| 102 |
+
// It is important to note that approximate eigenvalue scaling does not
|
| 103 |
+
// always improve convergence, and that it can in fact significantly degrade
|
| 104 |
+
// performance for certain classes of problem, which is why it is disabled
|
| 105 |
+
// by default. In particular it can degrade performance when the
|
| 106 |
+
// sensitivity of the problem to different parameters varies significantly,
|
| 107 |
+
// as in this case a single scalar factor fails to capture this variation
|
| 108 |
+
// and detrimentally downscales parts of the jacobian approximation which
|
| 109 |
+
// correspond to low-sensitivity parameters. It can also reduce the
|
| 110 |
+
// robustness of the solution to errors in the jacobians.
|
| 111 |
+
//
|
| 112 |
+
// Oren S.S., Self-scaling variable metric (SSVM) algorithms
|
| 113 |
+
// Part II: Implementation and experiments, Management Science,
|
| 114 |
+
// 20(5), 863-874, 1974.
|
| 115 |
+
bool use_approximate_eigenvalue_bfgs_scaling = false;
|
| 116 |
+
|
| 117 |
+
// Degree of the polynomial used to approximate the objective
|
| 118 |
+
// function. Valid values are BISECTION, QUADRATIC and CUBIC.
|
| 119 |
+
//
|
| 120 |
+
// BISECTION corresponds to pure backtracking search with no
|
| 121 |
+
// interpolation.
|
| 122 |
+
LineSearchInterpolationType line_search_interpolation_type = CUBIC;
|
| 123 |
+
|
| 124 |
+
// If during the line search, the step_size falls below this
|
| 125 |
+
// value, it is truncated to zero.
|
| 126 |
+
double min_line_search_step_size = 1e-9;
|
| 127 |
+
|
| 128 |
+
// Line search parameters.
|
| 129 |
+
|
| 130 |
+
// Solving the line search problem exactly is computationally
|
| 131 |
+
// prohibitive. Fortunately, line search based optimization
|
| 132 |
+
// algorithms can still guarantee convergence if instead of an
|
| 133 |
+
// exact solution, the line search algorithm returns a solution
|
| 134 |
+
// which decreases the value of the objective function
|
| 135 |
+
// sufficiently. More precisely, we are looking for a step_size
|
| 136 |
+
// s.t.
|
| 137 |
+
//
|
| 138 |
+
// f(step_size) <= f(0) + sufficient_decrease * f'(0) * step_size
|
| 139 |
+
//
|
| 140 |
+
double line_search_sufficient_function_decrease = 1e-4;
|
| 141 |
+
|
| 142 |
+
// In each iteration of the line search,
|
| 143 |
+
//
|
| 144 |
+
// new_step_size >= max_line_search_step_contraction * step_size
|
| 145 |
+
//
|
| 146 |
+
// Note that by definition, for contraction:
|
| 147 |
+
//
|
| 148 |
+
// 0 < max_step_contraction < min_step_contraction < 1
|
| 149 |
+
//
|
| 150 |
+
double max_line_search_step_contraction = 1e-3;
|
| 151 |
+
|
| 152 |
+
// In each iteration of the line search,
|
| 153 |
+
//
|
| 154 |
+
// new_step_size <= min_line_search_step_contraction * step_size
|
| 155 |
+
//
|
| 156 |
+
// Note that by definition, for contraction:
|
| 157 |
+
//
|
| 158 |
+
// 0 < max_step_contraction < min_step_contraction < 1
|
| 159 |
+
//
|
| 160 |
+
double min_line_search_step_contraction = 0.6;
|
| 161 |
+
|
| 162 |
+
// Maximum number of trial step size iterations during each line search,
|
| 163 |
+
// if a step size satisfying the search conditions cannot be found within
|
| 164 |
+
// this number of trials, the line search will terminate.
|
| 165 |
+
int max_num_line_search_step_size_iterations = 20;
|
| 166 |
+
|
| 167 |
+
// Maximum number of restarts of the line search direction algorithm before
|
| 168 |
+
// terminating the optimization. Restarts of the line search direction
|
| 169 |
+
// algorithm occur when the current algorithm fails to produce a new descent
|
| 170 |
+
// direction. This typically indicates a numerical failure, or a breakdown
|
| 171 |
+
// in the validity of the approximations used.
|
| 172 |
+
int max_num_line_search_direction_restarts = 5;
|
| 173 |
+
|
| 174 |
+
// The strong Wolfe conditions consist of the Armijo sufficient
|
| 175 |
+
// decrease condition, and an additional requirement that the
|
| 176 |
+
// step-size be chosen s.t. the _magnitude_ ('strong' Wolfe
|
| 177 |
+
// conditions) of the gradient along the search direction
|
| 178 |
+
// decreases sufficiently. Precisely, this second condition
|
| 179 |
+
// is that we seek a step_size s.t.
|
| 180 |
+
//
|
| 181 |
+
// |f'(step_size)| <= sufficient_curvature_decrease * |f'(0)|
|
| 182 |
+
//
|
| 183 |
+
// Where f() is the line search objective and f'() is the derivative
|
| 184 |
+
// of f w.r.t step_size (d f / d step_size).
|
| 185 |
+
double line_search_sufficient_curvature_decrease = 0.9;
|
| 186 |
+
|
| 187 |
+
// During the bracketing phase of the Wolfe search, the step size is
|
| 188 |
+
// increased until either a point satisfying the Wolfe conditions is
|
| 189 |
+
// found, or an upper bound for a bracket containing a point satisfying
|
| 190 |
+
// the conditions is found. Precisely, at each iteration of the
|
| 191 |
+
// expansion:
|
| 192 |
+
//
|
| 193 |
+
// new_step_size <= max_step_expansion * step_size.
|
| 194 |
+
//
|
| 195 |
+
// By definition for expansion, max_step_expansion > 1.0.
|
| 196 |
+
double max_line_search_step_expansion = 10.0;
|
| 197 |
+
|
| 198 |
+
// Maximum number of iterations for the minimizer to run for.
|
| 199 |
+
int max_num_iterations = 50;
|
| 200 |
+
|
| 201 |
+
// Maximum time for which the minimizer should run for.
|
| 202 |
+
double max_solver_time_in_seconds = 1e9;
|
| 203 |
+
|
| 204 |
+
// Minimizer terminates when
|
| 205 |
+
//
|
| 206 |
+
// (new_cost - old_cost) < function_tolerance * old_cost;
|
| 207 |
+
//
|
| 208 |
+
double function_tolerance = 1e-6;
|
| 209 |
+
|
| 210 |
+
// Minimizer terminates when
|
| 211 |
+
//
|
| 212 |
+
// max_i |x - Project(Plus(x, -g(x))| < gradient_tolerance
|
| 213 |
+
//
|
| 214 |
+
// This value should typically be 1e-4 * function_tolerance.
|
| 215 |
+
double gradient_tolerance = 1e-10;
|
| 216 |
+
|
| 217 |
+
// Minimizer terminates when
|
| 218 |
+
//
|
| 219 |
+
// |step|_2 <= parameter_tolerance * ( |x|_2 + parameter_tolerance)
|
| 220 |
+
//
|
| 221 |
+
double parameter_tolerance = 1e-8;
|
| 222 |
+
|
| 223 |
+
// Logging options ---------------------------------------------------------
|
| 224 |
+
|
| 225 |
+
LoggingType logging_type = PER_MINIMIZER_ITERATION;
|
| 226 |
+
|
| 227 |
+
// By default the Minimizer progress is logged to VLOG(1), which
|
| 228 |
+
// is sent to STDERR depending on the vlog level. If this flag is
|
| 229 |
+
// set to true, and logging_type is not SILENT, the logging output
|
| 230 |
+
// is sent to STDOUT.
|
| 231 |
+
bool minimizer_progress_to_stdout = false;
|
| 232 |
+
|
| 233 |
+
// If true, the user's parameter blocks are updated at the end of
|
| 234 |
+
// every Minimizer iteration, otherwise they are updated when the
|
| 235 |
+
// Minimizer terminates. This is useful if, for example, the user
|
| 236 |
+
// wishes to visualize the state of the optimization every
|
| 237 |
+
// iteration.
|
| 238 |
+
bool update_state_every_iteration = false;
|
| 239 |
+
|
| 240 |
+
// Callbacks that are executed at the end of each iteration of the
|
| 241 |
+
// Minimizer. An iteration may terminate midway, either due to
|
| 242 |
+
// numerical failures or because one of the convergence tests has
|
| 243 |
+
// been satisfied. In this case none of the callbacks are
|
| 244 |
+
// executed.
|
| 245 |
+
|
| 246 |
+
// Callbacks are executed in the order that they are specified in
|
| 247 |
+
// this vector. By default, parameter blocks are updated only at
|
| 248 |
+
// the end of the optimization, i.e when the Minimizer
|
| 249 |
+
// terminates. This behaviour is controlled by
|
| 250 |
+
// update_state_every_variable. If the user wishes to have access
|
| 251 |
+
// to the update parameter blocks when his/her callbacks are
|
| 252 |
+
// executed, then set update_state_every_iteration to true.
|
| 253 |
+
//
|
| 254 |
+
// The solver does NOT take ownership of these pointers.
|
| 255 |
+
std::vector<IterationCallback*> callbacks;
|
| 256 |
+
};
|
| 257 |
+
|
| 258 |
+
struct CERES_EXPORT Summary {
|
| 259 |
+
// A brief one line description of the state of the solver after
|
| 260 |
+
// termination.
|
| 261 |
+
std::string BriefReport() const;
|
| 262 |
+
|
| 263 |
+
// A full multiline description of the state of the solver after
|
| 264 |
+
// termination.
|
| 265 |
+
std::string FullReport() const;
|
| 266 |
+
|
| 267 |
+
bool IsSolutionUsable() const;
|
| 268 |
+
|
| 269 |
+
// Minimizer summary -------------------------------------------------
|
| 270 |
+
TerminationType termination_type = FAILURE;
|
| 271 |
+
|
| 272 |
+
// Reason why the solver terminated.
|
| 273 |
+
std::string message = "ceres::GradientProblemSolve was not called.";
|
| 274 |
+
|
| 275 |
+
// Cost of the problem (value of the objective function) before
|
| 276 |
+
// the optimization.
|
| 277 |
+
double initial_cost = -1.0;
|
| 278 |
+
|
| 279 |
+
// Cost of the problem (value of the objective function) after the
|
| 280 |
+
// optimization.
|
| 281 |
+
double final_cost = -1.0;
|
| 282 |
+
|
| 283 |
+
// IterationSummary for each minimizer iteration in order.
|
| 284 |
+
std::vector<IterationSummary> iterations;
|
| 285 |
+
|
| 286 |
+
// Number of times the cost (and not the gradient) was evaluated.
|
| 287 |
+
int num_cost_evaluations = -1;
|
| 288 |
+
|
| 289 |
+
// Number of times the gradient (and the cost) were evaluated.
|
| 290 |
+
int num_gradient_evaluations = -1;
|
| 291 |
+
|
| 292 |
+
// Sum total of all time spent inside Ceres when Solve is called.
|
| 293 |
+
double total_time_in_seconds = -1.0;
|
| 294 |
+
|
| 295 |
+
// Time (in seconds) spent evaluating the cost.
|
| 296 |
+
double cost_evaluation_time_in_seconds = -1.0;
|
| 297 |
+
|
| 298 |
+
// Time (in seconds) spent evaluating the gradient.
|
| 299 |
+
double gradient_evaluation_time_in_seconds = -1.0;
|
| 300 |
+
|
| 301 |
+
// Time (in seconds) spent minimizing the interpolating polynomial
|
| 302 |
+
// to compute the next candidate step size as part of a line search.
|
| 303 |
+
double line_search_polynomial_minimization_time_in_seconds = -1.0;
|
| 304 |
+
|
| 305 |
+
// Number of parameters in the problem.
|
| 306 |
+
int num_parameters = -1;
|
| 307 |
+
|
| 308 |
+
// Dimension of the tangent space of the problem.
|
| 309 |
+
CERES_DEPRECATED_WITH_MSG("Use num_tangent_parameters.")
|
| 310 |
+
int num_local_parameters = -1;
|
| 311 |
+
|
| 312 |
+
// Dimension of the tangent space of the problem.
|
| 313 |
+
int num_tangent_parameters = -1;
|
| 314 |
+
|
| 315 |
+
// Type of line search direction used.
|
| 316 |
+
LineSearchDirectionType line_search_direction_type = LBFGS;
|
| 317 |
+
|
| 318 |
+
// Type of the line search algorithm used.
|
| 319 |
+
LineSearchType line_search_type = WOLFE;
|
| 320 |
+
|
| 321 |
+
// When performing line search, the degree of the polynomial used
|
| 322 |
+
// to approximate the objective function.
|
| 323 |
+
LineSearchInterpolationType line_search_interpolation_type = CUBIC;
|
| 324 |
+
|
| 325 |
+
// If the line search direction is NONLINEAR_CONJUGATE_GRADIENT,
|
| 326 |
+
// then this indicates the particular variant of non-linear
|
| 327 |
+
// conjugate gradient used.
|
| 328 |
+
NonlinearConjugateGradientType nonlinear_conjugate_gradient_type =
|
| 329 |
+
FLETCHER_REEVES;
|
| 330 |
+
|
| 331 |
+
// If the type of the line search direction is LBFGS, then this
|
| 332 |
+
// indicates the rank of the Hessian approximation.
|
| 333 |
+
int max_lbfgs_rank = -1;
|
| 334 |
+
};
|
| 335 |
+
|
| 336 |
+
// Once a least squares problem has been built, this function takes
|
| 337 |
+
// the problem and optimizes it based on the values of the options
|
| 338 |
+
// parameters. Upon return, a detailed summary of the work performed
|
| 339 |
+
// by the preprocessor, the non-linear minimizer and the linear
|
| 340 |
+
// solver are reported in the summary object.
|
| 341 |
+
virtual void Solve(const GradientProblemSolver::Options& options,
|
| 342 |
+
const GradientProblem& problem,
|
| 343 |
+
double* parameters,
|
| 344 |
+
GradientProblemSolver::Summary* summary);
|
| 345 |
+
};
|
| 346 |
+
|
| 347 |
+
// Helper function which avoids going through the interface.
|
| 348 |
+
CERES_EXPORT void Solve(const GradientProblemSolver::Options& options,
|
| 349 |
+
const GradientProblem& problem,
|
| 350 |
+
double* parameters,
|
| 351 |
+
GradientProblemSolver::Summary* summary);
|
| 352 |
+
|
| 353 |
+
} // namespace ceres
|
| 354 |
+
|
| 355 |
+
#include "ceres/internal/reenable_warnings.h"
|
| 356 |
+
|
| 357 |
+
#endif // CERES_PUBLIC_GRADIENT_PROBLEM_SOLVER_H_
|
include/ceres/internal/array_selector.h
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2020 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: darius.rueckert@fau.de (Darius Rueckert)
|
| 30 |
+
//
|
| 31 |
+
|
| 32 |
+
#ifndef CERES_PUBLIC_INTERNAL_ARRAY_SELECTOR_H_
|
| 33 |
+
#define CERES_PUBLIC_INTERNAL_ARRAY_SELECTOR_H_
|
| 34 |
+
|
| 35 |
+
#include <array>
|
| 36 |
+
#include <vector>
|
| 37 |
+
|
| 38 |
+
#include "ceres/internal/fixed_array.h"
|
| 39 |
+
#include "ceres/types.h"
|
| 40 |
+
|
| 41 |
+
namespace ceres {
|
| 42 |
+
namespace internal {
|
| 43 |
+
|
| 44 |
+
// StaticFixedArray selects the best array implementation based on template
|
| 45 |
+
// arguments. If the size is not known at compile-time, pass
|
| 46 |
+
// ceres::DYNAMIC as a size-template argument.
|
| 47 |
+
//
|
| 48 |
+
// Three different containers are selected in different scenarios:
|
| 49 |
+
//
|
| 50 |
+
// num_elements == DYNAMIC:
|
| 51 |
+
// -> ceres::internal::FixedArray<T, max_stack_size>(size)
|
| 52 |
+
|
| 53 |
+
// num_elements != DYNAMIC && num_elements <= max_stack_size
|
| 54 |
+
// -> std::array<T,num_elements>
|
| 55 |
+
|
| 56 |
+
// num_elements != DYNAMIC && num_elements > max_stack_size
|
| 57 |
+
// -> std::vector<T>(num_elements)
|
| 58 |
+
//
|
| 59 |
+
template <typename T,
|
| 60 |
+
int num_elements,
|
| 61 |
+
int max_num_elements_on_stack,
|
| 62 |
+
bool dynamic = (num_elements == DYNAMIC),
|
| 63 |
+
bool fits_on_stack = (num_elements <= max_num_elements_on_stack)>
|
| 64 |
+
struct ArraySelector {};
|
| 65 |
+
|
| 66 |
+
template <typename T,
|
| 67 |
+
int num_elements,
|
| 68 |
+
int max_num_elements_on_stack,
|
| 69 |
+
bool fits_on_stack>
|
| 70 |
+
struct ArraySelector<T,
|
| 71 |
+
num_elements,
|
| 72 |
+
max_num_elements_on_stack,
|
| 73 |
+
true,
|
| 74 |
+
fits_on_stack>
|
| 75 |
+
: ceres::internal::FixedArray<T, max_num_elements_on_stack> {
|
| 76 |
+
explicit ArraySelector(int s)
|
| 77 |
+
: ceres::internal::FixedArray<T, max_num_elements_on_stack>(s) {}
|
| 78 |
+
};
|
| 79 |
+
|
| 80 |
+
template <typename T, int num_elements, int max_num_elements_on_stack>
|
| 81 |
+
struct ArraySelector<T, num_elements, max_num_elements_on_stack, false, true>
|
| 82 |
+
: std::array<T, num_elements> {
|
| 83 |
+
explicit ArraySelector(int s) { CHECK_EQ(s, num_elements); }
|
| 84 |
+
};
|
| 85 |
+
|
| 86 |
+
template <typename T, int num_elements, int max_num_elements_on_stack>
|
| 87 |
+
struct ArraySelector<T, num_elements, max_num_elements_on_stack, false, false>
|
| 88 |
+
: std::vector<T> {
|
| 89 |
+
explicit ArraySelector(int s) : std::vector<T>(s) {
|
| 90 |
+
CHECK_EQ(s, num_elements);
|
| 91 |
+
}
|
| 92 |
+
};
|
| 93 |
+
|
| 94 |
+
} // namespace internal
|
| 95 |
+
} // namespace ceres
|
| 96 |
+
|
| 97 |
+
#endif // CERES_PUBLIC_INTERNAL_ARRAY_SELECTOR_H_
|
include/ceres/internal/autodiff.h
ADDED
|
@@ -0,0 +1,365 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2019 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: keir@google.com (Keir Mierle)
|
| 30 |
+
//
|
| 31 |
+
// Computation of the Jacobian matrix for vector-valued functions of multiple
|
| 32 |
+
// variables, using automatic differentiation based on the implementation of
|
| 33 |
+
// dual numbers in jet.h. Before reading the rest of this file, it is advisable
|
| 34 |
+
// to read jet.h's header comment in detail.
|
| 35 |
+
//
|
| 36 |
+
// The helper wrapper AutoDifferentiate() computes the jacobian of
|
| 37 |
+
// functors with templated operator() taking this form:
|
| 38 |
+
//
|
| 39 |
+
// struct F {
|
| 40 |
+
// template<typename T>
|
| 41 |
+
// bool operator()(const T *x, const T *y, ..., T *z) {
|
| 42 |
+
// // Compute z[] based on x[], y[], ...
|
| 43 |
+
// // return true if computation succeeded, false otherwise.
|
| 44 |
+
// }
|
| 45 |
+
// };
|
| 46 |
+
//
|
| 47 |
+
// All inputs and outputs may be vector-valued.
|
| 48 |
+
//
|
| 49 |
+
// To understand how jets are used to compute the jacobian, a
|
| 50 |
+
// picture may help. Consider a vector-valued function, F, returning 3
|
| 51 |
+
// dimensions and taking a vector-valued parameter of 4 dimensions:
|
| 52 |
+
//
|
| 53 |
+
// y x
|
| 54 |
+
// [ * ] F [ * ]
|
| 55 |
+
// [ * ] <--- [ * ]
|
| 56 |
+
// [ * ] [ * ]
|
| 57 |
+
// [ * ]
|
| 58 |
+
//
|
| 59 |
+
// Similar to the 2-parameter example for f described in jet.h, computing the
|
| 60 |
+
// jacobian dy/dx is done by substituting a suitable jet object for x and all
|
| 61 |
+
// intermediate steps of the computation of F. Since x is has 4 dimensions, use
|
| 62 |
+
// a Jet<double, 4>.
|
| 63 |
+
//
|
| 64 |
+
// Before substituting a jet object for x, the dual components are set
|
| 65 |
+
// appropriately for each dimension of x:
|
| 66 |
+
//
|
| 67 |
+
// y x
|
| 68 |
+
// [ * | * * * * ] f [ * | 1 0 0 0 ] x0
|
| 69 |
+
// [ * | * * * * ] <--- [ * | 0 1 0 0 ] x1
|
| 70 |
+
// [ * | * * * * ] [ * | 0 0 1 0 ] x2
|
| 71 |
+
// ---+--- [ * | 0 0 0 1 ] x3
|
| 72 |
+
// | ^ ^ ^ ^
|
| 73 |
+
// dy/dx | | | +----- infinitesimal for x3
|
| 74 |
+
// | | +------- infinitesimal for x2
|
| 75 |
+
// | +--------- infinitesimal for x1
|
| 76 |
+
// +----------- infinitesimal for x0
|
| 77 |
+
//
|
| 78 |
+
// The reason to set the internal 4x4 submatrix to the identity is that we wish
|
| 79 |
+
// to take the derivative of y separately with respect to each dimension of x.
|
| 80 |
+
// Each column of the 4x4 identity is therefore for a single component of the
|
| 81 |
+
// independent variable x.
|
| 82 |
+
//
|
| 83 |
+
// Then the jacobian of the mapping, dy/dx, is the 3x4 sub-matrix of the
|
| 84 |
+
// extended y vector, indicated in the above diagram.
|
| 85 |
+
//
|
| 86 |
+
// Functors with multiple parameters
|
| 87 |
+
// ---------------------------------
|
| 88 |
+
// In practice, it is often convenient to use a function f of two or more
|
| 89 |
+
// vector-valued parameters, for example, x[3] and z[6]. Unfortunately, the jet
|
| 90 |
+
// framework is designed for a single-parameter vector-valued input. The wrapper
|
| 91 |
+
// in this file addresses this issue adding support for functions with one or
|
| 92 |
+
// more parameter vectors.
|
| 93 |
+
//
|
| 94 |
+
// To support multiple parameters, all the parameter vectors are concatenated
|
| 95 |
+
// into one and treated as a single parameter vector, except that since the
|
| 96 |
+
// functor expects different inputs, we need to construct the jets as if they
|
| 97 |
+
// were part of a single parameter vector. The extended jets are passed
|
| 98 |
+
// separately for each parameter.
|
| 99 |
+
//
|
| 100 |
+
// For example, consider a functor F taking two vector parameters, p[2] and
|
| 101 |
+
// q[3], and producing an output y[4]:
|
| 102 |
+
//
|
| 103 |
+
// struct F {
|
| 104 |
+
// template<typename T>
|
| 105 |
+
// bool operator()(const T *p, const T *q, T *z) {
|
| 106 |
+
// // ...
|
| 107 |
+
// }
|
| 108 |
+
// };
|
| 109 |
+
//
|
| 110 |
+
// In this case, the necessary jet type is Jet<double, 5>. Here is a
|
| 111 |
+
// visualization of the jet objects in this case:
|
| 112 |
+
//
|
| 113 |
+
// Dual components for p ----+
|
| 114 |
+
// |
|
| 115 |
+
// -+-
|
| 116 |
+
// y [ * | 1 0 | 0 0 0 ] --- p[0]
|
| 117 |
+
// [ * | 0 1 | 0 0 0 ] --- p[1]
|
| 118 |
+
// [ * | . . | + + + ] |
|
| 119 |
+
// [ * | . . | + + + ] v
|
| 120 |
+
// [ * | . . | + + + ] <--- F(p, q)
|
| 121 |
+
// [ * | . . | + + + ] ^
|
| 122 |
+
// ^^^ ^^^^^ |
|
| 123 |
+
// dy/dp dy/dq [ * | 0 0 | 1 0 0 ] --- q[0]
|
| 124 |
+
// [ * | 0 0 | 0 1 0 ] --- q[1]
|
| 125 |
+
// [ * | 0 0 | 0 0 1 ] --- q[2]
|
| 126 |
+
// --+--
|
| 127 |
+
// |
|
| 128 |
+
// Dual components for q --------------+
|
| 129 |
+
//
|
| 130 |
+
// where the 4x2 submatrix (marked with ".") and 4x3 submatrix (marked with "+"
|
| 131 |
+
// of y in the above diagram are the derivatives of y with respect to p and q
|
| 132 |
+
// respectively. This is how autodiff works for functors taking multiple vector
|
| 133 |
+
// valued arguments (up to 6).
|
| 134 |
+
//
|
| 135 |
+
// Jacobian null pointers (nullptr)
|
| 136 |
+
// --------------------------------
|
| 137 |
+
// In general, the functions below will accept nullptr for all or some of the
|
| 138 |
+
// Jacobian parameters, meaning that those Jacobians will not be computed.
|
| 139 |
+
|
| 140 |
+
#ifndef CERES_PUBLIC_INTERNAL_AUTODIFF_H_
|
| 141 |
+
#define CERES_PUBLIC_INTERNAL_AUTODIFF_H_
|
| 142 |
+
|
| 143 |
+
#include <array>
|
| 144 |
+
#include <cstddef>
|
| 145 |
+
#include <utility>
|
| 146 |
+
|
| 147 |
+
#include "ceres/internal/array_selector.h"
|
| 148 |
+
#include "ceres/internal/eigen.h"
|
| 149 |
+
#include "ceres/internal/fixed_array.h"
|
| 150 |
+
#include "ceres/internal/parameter_dims.h"
|
| 151 |
+
#include "ceres/internal/variadic_evaluate.h"
|
| 152 |
+
#include "ceres/jet.h"
|
| 153 |
+
#include "ceres/types.h"
|
| 154 |
+
#include "glog/logging.h"
|
| 155 |
+
|
| 156 |
+
// If the number of parameters exceeds this values, the corresponding jets are
|
| 157 |
+
// placed on the heap. This will reduce performance by a factor of 2-5 on
|
| 158 |
+
// current compilers.
|
| 159 |
+
#ifndef CERES_AUTODIFF_MAX_PARAMETERS_ON_STACK
|
| 160 |
+
#define CERES_AUTODIFF_MAX_PARAMETERS_ON_STACK 50
|
| 161 |
+
#endif
|
| 162 |
+
|
| 163 |
+
#ifndef CERES_AUTODIFF_MAX_RESIDUALS_ON_STACK
|
| 164 |
+
#define CERES_AUTODIFF_MAX_RESIDUALS_ON_STACK 20
|
| 165 |
+
#endif
|
| 166 |
+
|
| 167 |
+
namespace ceres {
|
| 168 |
+
namespace internal {
|
| 169 |
+
|
| 170 |
+
// Extends src by a 1st order perturbation for every dimension and puts it in
|
| 171 |
+
// dst. The size of src is N. Since this is also used for perturbations in
|
| 172 |
+
// blocked arrays, offset is used to shift which part of the jet the
|
| 173 |
+
// perturbation occurs. This is used to set up the extended x augmented by an
|
| 174 |
+
// identity matrix. The JetT type should be a Jet type, and T should be a
|
| 175 |
+
// numeric type (e.g. double). For example,
|
| 176 |
+
//
|
| 177 |
+
// 0 1 2 3 4 5 6 7 8
|
| 178 |
+
// dst[0] [ * | . . | 1 0 0 | . . . ]
|
| 179 |
+
// dst[1] [ * | . . | 0 1 0 | . . . ]
|
| 180 |
+
// dst[2] [ * | . . | 0 0 1 | . . . ]
|
| 181 |
+
//
|
| 182 |
+
// is what would get put in dst if N was 3, offset was 3, and the jet type JetT
|
| 183 |
+
// was 8-dimensional.
|
| 184 |
+
template <int j, int N, int Offset, typename T, typename JetT>
|
| 185 |
+
struct Make1stOrderPerturbation {
|
| 186 |
+
public:
|
| 187 |
+
inline static void Apply(const T* src, JetT* dst) {
|
| 188 |
+
if (j == 0) {
|
| 189 |
+
DCHECK(src);
|
| 190 |
+
DCHECK(dst);
|
| 191 |
+
}
|
| 192 |
+
dst[j] = JetT(src[j], j + Offset);
|
| 193 |
+
Make1stOrderPerturbation<j + 1, N, Offset, T, JetT>::Apply(src, dst);
|
| 194 |
+
}
|
| 195 |
+
};
|
| 196 |
+
|
| 197 |
+
template <int N, int Offset, typename T, typename JetT>
|
| 198 |
+
struct Make1stOrderPerturbation<N, N, Offset, T, JetT> {
|
| 199 |
+
public:
|
| 200 |
+
static void Apply(const T* /* NOT USED */, JetT* /* NOT USED */) {}
|
| 201 |
+
};
|
| 202 |
+
|
| 203 |
+
// Calls Make1stOrderPerturbation for every parameter block.
|
| 204 |
+
//
|
| 205 |
+
// Example:
|
| 206 |
+
// If one having three parameter blocks with dimensions (3, 2, 4), the call
|
| 207 |
+
// Make1stOrderPerturbations<integer_sequence<3, 2, 4>::Apply(params, x);
|
| 208 |
+
// will result in the following calls to Make1stOrderPerturbation:
|
| 209 |
+
// Make1stOrderPerturbation<0, 3, 0>::Apply(params[0], x + 0);
|
| 210 |
+
// Make1stOrderPerturbation<0, 2, 3>::Apply(params[1], x + 3);
|
| 211 |
+
// Make1stOrderPerturbation<0, 4, 5>::Apply(params[2], x + 5);
|
| 212 |
+
template <typename Seq, int ParameterIdx = 0, int Offset = 0>
|
| 213 |
+
struct Make1stOrderPerturbations;
|
| 214 |
+
|
| 215 |
+
template <int N, int... Ns, int ParameterIdx, int Offset>
|
| 216 |
+
struct Make1stOrderPerturbations<std::integer_sequence<int, N, Ns...>,
|
| 217 |
+
ParameterIdx,
|
| 218 |
+
Offset> {
|
| 219 |
+
template <typename T, typename JetT>
|
| 220 |
+
inline static void Apply(T const* const* parameters, JetT* x) {
|
| 221 |
+
Make1stOrderPerturbation<0, N, Offset, T, JetT>::Apply(
|
| 222 |
+
parameters[ParameterIdx], x + Offset);
|
| 223 |
+
Make1stOrderPerturbations<std::integer_sequence<int, Ns...>,
|
| 224 |
+
ParameterIdx + 1,
|
| 225 |
+
Offset + N>::Apply(parameters, x);
|
| 226 |
+
}
|
| 227 |
+
};
|
| 228 |
+
|
| 229 |
+
// End of 'recursion'. Nothing more to do.
|
| 230 |
+
template <int ParameterIdx, int Total>
|
| 231 |
+
struct Make1stOrderPerturbations<std::integer_sequence<int>,
|
| 232 |
+
ParameterIdx,
|
| 233 |
+
Total> {
|
| 234 |
+
template <typename T, typename JetT>
|
| 235 |
+
static void Apply(T const* const* /* NOT USED */, JetT* /* NOT USED */) {}
|
| 236 |
+
};
|
| 237 |
+
|
| 238 |
+
// Takes the 0th order part of src, assumed to be a Jet type, and puts it in
|
| 239 |
+
// dst. This is used to pick out the "vector" part of the extended y.
|
| 240 |
+
template <typename JetT, typename T>
|
| 241 |
+
inline void Take0thOrderPart(int M, const JetT* src, T dst) {
|
| 242 |
+
DCHECK(src);
|
| 243 |
+
for (int i = 0; i < M; ++i) {
|
| 244 |
+
dst[i] = src[i].a;
|
| 245 |
+
}
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
// Takes N 1st order parts, starting at index N0, and puts them in the M x N
|
| 249 |
+
// matrix 'dst'. This is used to pick out the "matrix" parts of the extended y.
|
| 250 |
+
template <int N0, int N, typename JetT, typename T>
|
| 251 |
+
inline void Take1stOrderPart(const int M, const JetT* src, T* dst) {
|
| 252 |
+
DCHECK(src);
|
| 253 |
+
DCHECK(dst);
|
| 254 |
+
for (int i = 0; i < M; ++i) {
|
| 255 |
+
Eigen::Map<Eigen::Matrix<T, N, 1>>(dst + N * i, N) =
|
| 256 |
+
src[i].v.template segment<N>(N0);
|
| 257 |
+
}
|
| 258 |
+
}
|
| 259 |
+
|
| 260 |
+
// Calls Take1stOrderPart for every parameter block.
|
| 261 |
+
//
|
| 262 |
+
// Example:
|
| 263 |
+
// If one having three parameter blocks with dimensions (3, 2, 4), the call
|
| 264 |
+
// Take1stOrderParts<integer_sequence<3, 2, 4>::Apply(num_outputs,
|
| 265 |
+
// output,
|
| 266 |
+
// jacobians);
|
| 267 |
+
// will result in the following calls to Take1stOrderPart:
|
| 268 |
+
// if (jacobians[0]) {
|
| 269 |
+
// Take1stOrderPart<0, 3>(num_outputs, output, jacobians[0]);
|
| 270 |
+
// }
|
| 271 |
+
// if (jacobians[1]) {
|
| 272 |
+
// Take1stOrderPart<3, 2>(num_outputs, output, jacobians[1]);
|
| 273 |
+
// }
|
| 274 |
+
// if (jacobians[2]) {
|
| 275 |
+
// Take1stOrderPart<5, 4>(num_outputs, output, jacobians[2]);
|
| 276 |
+
// }
|
| 277 |
+
template <typename Seq, int ParameterIdx = 0, int Offset = 0>
|
| 278 |
+
struct Take1stOrderParts;
|
| 279 |
+
|
| 280 |
+
template <int N, int... Ns, int ParameterIdx, int Offset>
|
| 281 |
+
struct Take1stOrderParts<std::integer_sequence<int, N, Ns...>,
|
| 282 |
+
ParameterIdx,
|
| 283 |
+
Offset> {
|
| 284 |
+
template <typename JetT, typename T>
|
| 285 |
+
inline static void Apply(int num_outputs, JetT* output, T** jacobians) {
|
| 286 |
+
if (jacobians[ParameterIdx]) {
|
| 287 |
+
Take1stOrderPart<Offset, N>(num_outputs, output, jacobians[ParameterIdx]);
|
| 288 |
+
}
|
| 289 |
+
Take1stOrderParts<std::integer_sequence<int, Ns...>,
|
| 290 |
+
ParameterIdx + 1,
|
| 291 |
+
Offset + N>::Apply(num_outputs, output, jacobians);
|
| 292 |
+
}
|
| 293 |
+
};
|
| 294 |
+
|
| 295 |
+
// End of 'recursion'. Nothing more to do.
|
| 296 |
+
template <int ParameterIdx, int Offset>
|
| 297 |
+
struct Take1stOrderParts<std::integer_sequence<int>, ParameterIdx, Offset> {
|
| 298 |
+
template <typename T, typename JetT>
|
| 299 |
+
static void Apply(int /* NOT USED*/,
|
| 300 |
+
JetT* /* NOT USED*/,
|
| 301 |
+
T** /* NOT USED */) {}
|
| 302 |
+
};
|
| 303 |
+
|
| 304 |
+
template <int kNumResiduals,
|
| 305 |
+
typename ParameterDims,
|
| 306 |
+
typename Functor,
|
| 307 |
+
typename T>
|
| 308 |
+
inline bool AutoDifferentiate(const Functor& functor,
|
| 309 |
+
T const* const* parameters,
|
| 310 |
+
int dynamic_num_outputs,
|
| 311 |
+
T* function_value,
|
| 312 |
+
T** jacobians) {
|
| 313 |
+
using JetT = Jet<T, ParameterDims::kNumParameters>;
|
| 314 |
+
using Parameters = typename ParameterDims::Parameters;
|
| 315 |
+
|
| 316 |
+
if (kNumResiduals != DYNAMIC) {
|
| 317 |
+
DCHECK_EQ(kNumResiduals, dynamic_num_outputs);
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
ArraySelector<JetT,
|
| 321 |
+
ParameterDims::kNumParameters,
|
| 322 |
+
CERES_AUTODIFF_MAX_PARAMETERS_ON_STACK>
|
| 323 |
+
parameters_as_jets(ParameterDims::kNumParameters);
|
| 324 |
+
|
| 325 |
+
// Pointers to the beginning of each parameter block
|
| 326 |
+
std::array<JetT*, ParameterDims::kNumParameterBlocks> unpacked_parameters =
|
| 327 |
+
ParameterDims::GetUnpackedParameters(parameters_as_jets.data());
|
| 328 |
+
|
| 329 |
+
// If the number of residuals is fixed, we use the template argument as the
|
| 330 |
+
// number of outputs. Otherwise we use the num_outputs parameter. Note: The
|
| 331 |
+
// ?-operator here is compile-time evaluated, therefore num_outputs is also
|
| 332 |
+
// a compile-time constant for functors with fixed residuals.
|
| 333 |
+
const int num_outputs =
|
| 334 |
+
kNumResiduals == DYNAMIC ? dynamic_num_outputs : kNumResiduals;
|
| 335 |
+
DCHECK_GT(num_outputs, 0);
|
| 336 |
+
|
| 337 |
+
ArraySelector<JetT, kNumResiduals, CERES_AUTODIFF_MAX_RESIDUALS_ON_STACK>
|
| 338 |
+
residuals_as_jets(num_outputs);
|
| 339 |
+
|
| 340 |
+
// Invalidate the output Jets, so that we can detect if the user
|
| 341 |
+
// did not assign values to all of them.
|
| 342 |
+
for (int i = 0; i < num_outputs; ++i) {
|
| 343 |
+
residuals_as_jets[i].a = kImpossibleValue;
|
| 344 |
+
residuals_as_jets[i].v.setConstant(kImpossibleValue);
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
Make1stOrderPerturbations<Parameters>::Apply(parameters,
|
| 348 |
+
parameters_as_jets.data());
|
| 349 |
+
|
| 350 |
+
if (!VariadicEvaluate<ParameterDims>(
|
| 351 |
+
functor, unpacked_parameters.data(), residuals_as_jets.data())) {
|
| 352 |
+
return false;
|
| 353 |
+
}
|
| 354 |
+
|
| 355 |
+
Take0thOrderPart(num_outputs, residuals_as_jets.data(), function_value);
|
| 356 |
+
Take1stOrderParts<Parameters>::Apply(
|
| 357 |
+
num_outputs, residuals_as_jets.data(), jacobians);
|
| 358 |
+
|
| 359 |
+
return true;
|
| 360 |
+
}
|
| 361 |
+
|
| 362 |
+
} // namespace internal
|
| 363 |
+
} // namespace ceres
|
| 364 |
+
|
| 365 |
+
#endif // CERES_PUBLIC_INTERNAL_AUTODIFF_H_
|
include/ceres/internal/config.h
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2022 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: alexs.mac@gmail.com (Alex Stewart)
|
| 30 |
+
|
| 31 |
+
// Configuration options for Ceres.
|
| 32 |
+
//
|
| 33 |
+
// Do not edit this file, it was automatically configured by CMake when
|
| 34 |
+
// Ceres was compiled with the relevant configuration for the machine
|
| 35 |
+
// on which Ceres was compiled.
|
| 36 |
+
//
|
| 37 |
+
// Ceres Developers: All options should have the same name as their mapped
|
| 38 |
+
// CMake options, in the preconfigured version of this file
|
| 39 |
+
// all options should be enclosed in '@'.
|
| 40 |
+
|
| 41 |
+
#ifndef CERES_PUBLIC_INTERNAL_CONFIG_H_
|
| 42 |
+
#define CERES_PUBLIC_INTERNAL_CONFIG_H_
|
| 43 |
+
|
| 44 |
+
// If defined, use the LGPL code in Eigen.
|
| 45 |
+
#define CERES_USE_EIGEN_SPARSE
|
| 46 |
+
|
| 47 |
+
// If defined, Ceres was compiled without LAPACK.
|
| 48 |
+
// #define CERES_NO_LAPACK
|
| 49 |
+
|
| 50 |
+
// If defined, Ceres was compiled without SuiteSparse.
|
| 51 |
+
// #define CERES_NO_SUITESPARSE
|
| 52 |
+
|
| 53 |
+
// If defined, Ceres was compiled without CXSparse.
|
| 54 |
+
// #define CERES_NO_CXSPARSE
|
| 55 |
+
|
| 56 |
+
// If defined, Ceres was compiled without CUDA.
|
| 57 |
+
// #define CERES_NO_CUDA
|
| 58 |
+
|
| 59 |
+
// If defined, Ceres was compiled without Apple's Accelerate framework solvers.
|
| 60 |
+
#define CERES_NO_ACCELERATE_SPARSE
|
| 61 |
+
|
| 62 |
+
#if defined(CERES_NO_SUITESPARSE) && \
|
| 63 |
+
defined(CERES_NO_ACCELERATE_SPARSE) && \
|
| 64 |
+
defined(CERES_NO_CXSPARSE) && \
|
| 65 |
+
!defined(CERES_USE_EIGEN_SPARSE) // NOLINT
|
| 66 |
+
// If defined Ceres was compiled without any sparse linear algebra support.
|
| 67 |
+
#define CERES_NO_SPARSE
|
| 68 |
+
#endif
|
| 69 |
+
|
| 70 |
+
// If defined, Ceres was compiled without Schur specializations.
|
| 71 |
+
// #define CERES_RESTRICT_SCHUR_SPECIALIZATION
|
| 72 |
+
|
| 73 |
+
// If defined, Ceres was compiled to use Eigen instead of hardcoded BLAS
|
| 74 |
+
// routines.
|
| 75 |
+
// #define CERES_NO_CUSTOM_BLAS
|
| 76 |
+
|
| 77 |
+
// If defined, Ceres was compiled without multithreading support.
|
| 78 |
+
// #define CERES_NO_THREADS
|
| 79 |
+
// If defined Ceres was compiled with OpenMP multithreading.
|
| 80 |
+
// #define CERES_USE_OPENMP
|
| 81 |
+
// If defined Ceres was compiled with modern C++ multithreading.
|
| 82 |
+
#define CERES_USE_CXX_THREADS
|
| 83 |
+
|
| 84 |
+
// If defined, Ceres was compiled with a version MSVC >= 2005 which
|
| 85 |
+
// deprecated the standard POSIX names for bessel functions, replacing them
|
| 86 |
+
// with underscore prefixed versions (e.g. j0() -> _j0()).
|
| 87 |
+
// #define CERES_MSVC_USE_UNDERSCORE_PREFIXED_BESSEL_FUNCTIONS
|
| 88 |
+
|
| 89 |
+
#if defined(CERES_USE_OPENMP)
|
| 90 |
+
#if defined(CERES_USE_CXX_THREADS) || defined(CERES_NO_THREADS)
|
| 91 |
+
#error CERES_USE_OPENMP is mutually exclusive to CERES_USE_CXX_THREADS and CERES_NO_THREADS
|
| 92 |
+
#endif
|
| 93 |
+
#elif defined(CERES_USE_CXX_THREADS)
|
| 94 |
+
#if defined(CERES_USE_OPENMP) || defined(CERES_NO_THREADS)
|
| 95 |
+
#error CERES_USE_CXX_THREADS is mutually exclusive to CERES_USE_OPENMP, CERES_USE_CXX_THREADS and CERES_NO_THREADS
|
| 96 |
+
#endif
|
| 97 |
+
#elif defined(CERES_NO_THREADS)
|
| 98 |
+
#if defined(CERES_USE_OPENMP) || defined(CERES_USE_CXX_THREADS)
|
| 99 |
+
#error CERES_NO_THREADS is mutually exclusive to CERES_USE_OPENMP and CERES_USE_CXX_THREADS
|
| 100 |
+
#endif
|
| 101 |
+
#else
|
| 102 |
+
# error One of CERES_USE_OPENMP, CERES_USE_CXX_THREADS or CERES_NO_THREADS must be defined.
|
| 103 |
+
#endif
|
| 104 |
+
|
| 105 |
+
// CERES_NO_SPARSE should be automatically defined by config.h if Ceres was
|
| 106 |
+
// compiled without any sparse back-end. Verify that it has not subsequently
|
| 107 |
+
// been inconsistently redefined.
|
| 108 |
+
#if defined(CERES_NO_SPARSE)
|
| 109 |
+
#if !defined(CERES_NO_SUITESPARSE)
|
| 110 |
+
#error CERES_NO_SPARSE requires CERES_NO_SUITESPARSE.
|
| 111 |
+
#endif
|
| 112 |
+
#if !defined(CERES_NO_CXSPARSE)
|
| 113 |
+
#error CERES_NO_SPARSE requires CERES_NO_CXSPARSE
|
| 114 |
+
#endif
|
| 115 |
+
#if !defined(CERES_NO_ACCELERATE_SPARSE)
|
| 116 |
+
#error CERES_NO_SPARSE requires CERES_NO_ACCELERATE_SPARSE
|
| 117 |
+
#endif
|
| 118 |
+
#if defined(CERES_USE_EIGEN_SPARSE)
|
| 119 |
+
#error CERES_NO_SPARSE requires !CERES_USE_EIGEN_SPARSE
|
| 120 |
+
#endif
|
| 121 |
+
#endif
|
| 122 |
+
|
| 123 |
+
#endif // CERES_PUBLIC_INTERNAL_CONFIG_H_
|
include/ceres/internal/disable_warnings.h
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2015 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// This file has the sole purpose to silence warnings when including Ceres.
|
| 30 |
+
|
| 31 |
+
// This is not your usual header guard. The macro CERES_WARNINGS_DISABLED
|
| 32 |
+
// shows up again in reenable_warnings.h.
|
| 33 |
+
#ifndef CERES_WARNINGS_DISABLED
|
| 34 |
+
#define CERES_WARNINGS_DISABLED
|
| 35 |
+
|
| 36 |
+
#ifdef _MSC_VER
|
| 37 |
+
#pragma warning(push)
|
| 38 |
+
// Disable the warning C4251 which is triggered by stl classes in
|
| 39 |
+
// Ceres' public interface. To quote MSDN: "C4251 can be ignored "
|
| 40 |
+
// "if you are deriving from a type in the Standard C++ Library"
|
| 41 |
+
#pragma warning(disable : 4251)
|
| 42 |
+
#endif
|
| 43 |
+
|
| 44 |
+
#endif // CERES_WARNINGS_DISABLED
|
include/ceres/internal/eigen.h
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2015 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: sameeragarwal@google.com (Sameer Agarwal)
|
| 30 |
+
|
| 31 |
+
#ifndef CERES_INTERNAL_EIGEN_H_
|
| 32 |
+
#define CERES_INTERNAL_EIGEN_H_
|
| 33 |
+
|
| 34 |
+
#include "Eigen/Core"
|
| 35 |
+
|
| 36 |
+
namespace ceres {
|
| 37 |
+
|
| 38 |
+
using Vector = Eigen::Matrix<double, Eigen::Dynamic, 1>;
|
| 39 |
+
using Matrix =
|
| 40 |
+
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
|
| 41 |
+
using VectorRef = Eigen::Map<Vector>;
|
| 42 |
+
using MatrixRef = Eigen::Map<Matrix>;
|
| 43 |
+
using ConstVectorRef = Eigen::Map<const Vector>;
|
| 44 |
+
using ConstMatrixRef = Eigen::Map<const Matrix>;
|
| 45 |
+
|
| 46 |
+
// Column major matrices for DenseSparseMatrix/DenseQRSolver
|
| 47 |
+
using ColMajorMatrix =
|
| 48 |
+
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>;
|
| 49 |
+
|
| 50 |
+
using ColMajorMatrixRef =
|
| 51 |
+
Eigen::Map<ColMajorMatrix, 0, Eigen::Stride<Eigen::Dynamic, 1>>;
|
| 52 |
+
|
| 53 |
+
using ConstColMajorMatrixRef =
|
| 54 |
+
Eigen::Map<const ColMajorMatrix, 0, Eigen::Stride<Eigen::Dynamic, 1>>;
|
| 55 |
+
|
| 56 |
+
// C++ does not support templated typdefs, thus the need for this
|
| 57 |
+
// struct so that we can support statically sized Matrix and Maps.
|
| 58 |
+
template <int num_rows = Eigen::Dynamic, int num_cols = Eigen::Dynamic>
|
| 59 |
+
struct EigenTypes {
|
| 60 |
+
using Matrix =
|
| 61 |
+
Eigen::Matrix<double,
|
| 62 |
+
num_rows,
|
| 63 |
+
num_cols,
|
| 64 |
+
num_cols == 1 ? Eigen::ColMajor : Eigen::RowMajor>;
|
| 65 |
+
|
| 66 |
+
using MatrixRef = Eigen::Map<Matrix>;
|
| 67 |
+
using ConstMatrixRef = Eigen::Map<const Matrix>;
|
| 68 |
+
using Vector = Eigen::Matrix<double, num_rows, 1>;
|
| 69 |
+
using VectorRef = Eigen::Map<Eigen::Matrix<double, num_rows, 1>>;
|
| 70 |
+
using ConstVectorRef = Eigen::Map<const Eigen::Matrix<double, num_rows, 1>>;
|
| 71 |
+
};
|
| 72 |
+
|
| 73 |
+
} // namespace ceres
|
| 74 |
+
|
| 75 |
+
#endif // CERES_INTERNAL_EIGEN_H_
|
include/ceres/internal/export.h
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
#ifndef CERES_EXPORT_H
|
| 3 |
+
#define CERES_EXPORT_H
|
| 4 |
+
|
| 5 |
+
#ifdef CERES_STATIC_DEFINE
|
| 6 |
+
# define CERES_EXPORT
|
| 7 |
+
# define CERES_NO_EXPORT
|
| 8 |
+
#else
|
| 9 |
+
# ifndef CERES_EXPORT
|
| 10 |
+
# ifdef ceres_EXPORTS
|
| 11 |
+
/* We are building this library */
|
| 12 |
+
# define CERES_EXPORT
|
| 13 |
+
# else
|
| 14 |
+
/* We are using this library */
|
| 15 |
+
# define CERES_EXPORT
|
| 16 |
+
# endif
|
| 17 |
+
# endif
|
| 18 |
+
|
| 19 |
+
# ifndef CERES_NO_EXPORT
|
| 20 |
+
# define CERES_NO_EXPORT
|
| 21 |
+
# endif
|
| 22 |
+
#endif
|
| 23 |
+
|
| 24 |
+
#ifndef CERES_DEPRECATED
|
| 25 |
+
# define CERES_DEPRECATED __attribute__ ((__deprecated__))
|
| 26 |
+
#endif
|
| 27 |
+
|
| 28 |
+
#ifndef CERES_DEPRECATED_EXPORT
|
| 29 |
+
# define CERES_DEPRECATED_EXPORT CERES_EXPORT CERES_DEPRECATED
|
| 30 |
+
#endif
|
| 31 |
+
|
| 32 |
+
#ifndef CERES_DEPRECATED_NO_EXPORT
|
| 33 |
+
# define CERES_DEPRECATED_NO_EXPORT CERES_NO_EXPORT CERES_DEPRECATED
|
| 34 |
+
#endif
|
| 35 |
+
|
| 36 |
+
#if 0 /* DEFINE_NO_DEPRECATED */
|
| 37 |
+
# ifndef CERES_NO_DEPRECATED
|
| 38 |
+
# define CERES_NO_DEPRECATED
|
| 39 |
+
# endif
|
| 40 |
+
#endif
|
| 41 |
+
|
| 42 |
+
#endif /* CERES_EXPORT_H */
|
include/ceres/internal/fixed_array.h
ADDED
|
@@ -0,0 +1,467 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2018 The Abseil Authors.
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
//
|
| 15 |
+
// -----------------------------------------------------------------------------
|
| 16 |
+
// File: fixed_array.h
|
| 17 |
+
// -----------------------------------------------------------------------------
|
| 18 |
+
//
|
| 19 |
+
// A `FixedArray<T>` represents a non-resizable array of `T` where the length of
|
| 20 |
+
// the array can be determined at run-time. It is a good replacement for
|
| 21 |
+
// non-standard and deprecated uses of `alloca()` and variable length arrays
|
| 22 |
+
// within the GCC extension. (See
|
| 23 |
+
// https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html).
|
| 24 |
+
//
|
| 25 |
+
// `FixedArray` allocates small arrays inline, keeping performance fast by
|
| 26 |
+
// avoiding heap operations. It also helps reduce the chances of
|
| 27 |
+
// accidentally overflowing your stack if large input is passed to
|
| 28 |
+
// your function.
|
| 29 |
+
|
| 30 |
+
#ifndef CERES_PUBLIC_INTERNAL_FIXED_ARRAY_H_
|
| 31 |
+
#define CERES_PUBLIC_INTERNAL_FIXED_ARRAY_H_
|
| 32 |
+
|
| 33 |
+
#include <Eigen/Core> // For Eigen::aligned_allocator
|
| 34 |
+
#include <algorithm>
|
| 35 |
+
#include <array>
|
| 36 |
+
#include <cstddef>
|
| 37 |
+
#include <memory>
|
| 38 |
+
#include <tuple>
|
| 39 |
+
#include <type_traits>
|
| 40 |
+
|
| 41 |
+
#include "ceres/internal/memory.h"
|
| 42 |
+
#include "glog/logging.h"
|
| 43 |
+
|
| 44 |
+
namespace ceres {
|
| 45 |
+
namespace internal {
|
| 46 |
+
|
| 47 |
+
constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1);
|
| 48 |
+
|
| 49 |
+
// The default fixed array allocator.
|
| 50 |
+
//
|
| 51 |
+
// As one can not easily detect if a struct contains or inherits from a fixed
|
| 52 |
+
// size Eigen type, to be safe the Eigen::aligned_allocator is used by default.
|
| 53 |
+
// But trivial types can never contain Eigen types, so std::allocator is used to
|
| 54 |
+
// safe some heap memory.
|
| 55 |
+
template <typename T>
|
| 56 |
+
using FixedArrayDefaultAllocator =
|
| 57 |
+
typename std::conditional<std::is_trivial<T>::value,
|
| 58 |
+
std::allocator<T>,
|
| 59 |
+
Eigen::aligned_allocator<T>>::type;
|
| 60 |
+
|
| 61 |
+
// -----------------------------------------------------------------------------
|
| 62 |
+
// FixedArray
|
| 63 |
+
// -----------------------------------------------------------------------------
|
| 64 |
+
//
|
| 65 |
+
// A `FixedArray` provides a run-time fixed-size array, allocating a small array
|
| 66 |
+
// inline for efficiency.
|
| 67 |
+
//
|
| 68 |
+
// Most users should not specify an `inline_elements` argument and let
|
| 69 |
+
// `FixedArray` automatically determine the number of elements
|
| 70 |
+
// to store inline based on `sizeof(T)`. If `inline_elements` is specified, the
|
| 71 |
+
// `FixedArray` implementation will use inline storage for arrays with a
|
| 72 |
+
// length <= `inline_elements`.
|
| 73 |
+
//
|
| 74 |
+
// Note that a `FixedArray` constructed with a `size_type` argument will
|
| 75 |
+
// default-initialize its values by leaving trivially constructible types
|
| 76 |
+
// uninitialized (e.g. int, int[4], double), and others default-constructed.
|
| 77 |
+
// This matches the behavior of c-style arrays and `std::array`, but not
|
| 78 |
+
// `std::vector`.
|
| 79 |
+
//
|
| 80 |
+
// Note that `FixedArray` does not provide a public allocator; if it requires a
|
| 81 |
+
// heap allocation, it will do so with global `::operator new[]()` and
|
| 82 |
+
// `::operator delete[]()`, even if T provides class-scope overrides for these
|
| 83 |
+
// operators.
|
| 84 |
+
template <typename T,
|
| 85 |
+
size_t N = kFixedArrayUseDefault,
|
| 86 |
+
typename A = FixedArrayDefaultAllocator<T>>
|
| 87 |
+
class FixedArray {
|
| 88 |
+
static_assert(!std::is_array<T>::value || std::extent<T>::value > 0,
|
| 89 |
+
"Arrays with unknown bounds cannot be used with FixedArray.");
|
| 90 |
+
|
| 91 |
+
static constexpr size_t kInlineBytesDefault = 256;
|
| 92 |
+
|
| 93 |
+
using AllocatorTraits = std::allocator_traits<A>;
|
| 94 |
+
// std::iterator_traits isn't guaranteed to be SFINAE-friendly until C++17,
|
| 95 |
+
// but this seems to be mostly pedantic.
|
| 96 |
+
template <typename Iterator>
|
| 97 |
+
using EnableIfForwardIterator = typename std::enable_if<std::is_convertible<
|
| 98 |
+
typename std::iterator_traits<Iterator>::iterator_category,
|
| 99 |
+
std::forward_iterator_tag>::value>::type;
|
| 100 |
+
static constexpr bool DefaultConstructorIsNonTrivial() {
|
| 101 |
+
return !std::is_trivially_default_constructible<StorageElement>::value;
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
public:
|
| 105 |
+
using allocator_type = typename AllocatorTraits::allocator_type;
|
| 106 |
+
using value_type = typename AllocatorTraits::value_type;
|
| 107 |
+
using pointer = typename AllocatorTraits::pointer;
|
| 108 |
+
using const_pointer = typename AllocatorTraits::const_pointer;
|
| 109 |
+
using reference = value_type&;
|
| 110 |
+
using const_reference = const value_type&;
|
| 111 |
+
using size_type = typename AllocatorTraits::size_type;
|
| 112 |
+
using difference_type = typename AllocatorTraits::difference_type;
|
| 113 |
+
using iterator = pointer;
|
| 114 |
+
using const_iterator = const_pointer;
|
| 115 |
+
using reverse_iterator = std::reverse_iterator<iterator>;
|
| 116 |
+
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
| 117 |
+
|
| 118 |
+
static constexpr size_type inline_elements =
|
| 119 |
+
(N == kFixedArrayUseDefault ? kInlineBytesDefault / sizeof(value_type)
|
| 120 |
+
: static_cast<size_type>(N));
|
| 121 |
+
|
| 122 |
+
FixedArray(const FixedArray& other,
|
| 123 |
+
const allocator_type& a = allocator_type())
|
| 124 |
+
: FixedArray(other.begin(), other.end(), a) {}
|
| 125 |
+
|
| 126 |
+
FixedArray(FixedArray&& other, const allocator_type& a = allocator_type())
|
| 127 |
+
: FixedArray(std::make_move_iterator(other.begin()),
|
| 128 |
+
std::make_move_iterator(other.end()),
|
| 129 |
+
a) {}
|
| 130 |
+
|
| 131 |
+
// Creates an array object that can store `n` elements.
|
| 132 |
+
// Note that trivially constructible elements will be uninitialized.
|
| 133 |
+
explicit FixedArray(size_type n, const allocator_type& a = allocator_type())
|
| 134 |
+
: storage_(n, a) {
|
| 135 |
+
if (DefaultConstructorIsNonTrivial()) {
|
| 136 |
+
ConstructRange(storage_.alloc(), storage_.begin(), storage_.end());
|
| 137 |
+
}
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
// Creates an array initialized with `n` copies of `val`.
|
| 141 |
+
FixedArray(size_type n,
|
| 142 |
+
const value_type& val,
|
| 143 |
+
const allocator_type& a = allocator_type())
|
| 144 |
+
: storage_(n, a) {
|
| 145 |
+
ConstructRange(storage_.alloc(), storage_.begin(), storage_.end(), val);
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
// Creates an array initialized with the size and contents of `init_list`.
|
| 149 |
+
FixedArray(std::initializer_list<value_type> init_list,
|
| 150 |
+
const allocator_type& a = allocator_type())
|
| 151 |
+
: FixedArray(init_list.begin(), init_list.end(), a) {}
|
| 152 |
+
|
| 153 |
+
// Creates an array initialized with the elements from the input
|
| 154 |
+
// range. The array's size will always be `std::distance(first, last)`.
|
| 155 |
+
// REQUIRES: Iterator must be a forward_iterator or better.
|
| 156 |
+
template <typename Iterator, EnableIfForwardIterator<Iterator>* = nullptr>
|
| 157 |
+
FixedArray(Iterator first,
|
| 158 |
+
Iterator last,
|
| 159 |
+
const allocator_type& a = allocator_type())
|
| 160 |
+
: storage_(std::distance(first, last), a) {
|
| 161 |
+
CopyRange(storage_.alloc(), storage_.begin(), first, last);
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
~FixedArray() noexcept {
|
| 165 |
+
for (auto* cur = storage_.begin(); cur != storage_.end(); ++cur) {
|
| 166 |
+
AllocatorTraits::destroy(storage_.alloc(), cur);
|
| 167 |
+
}
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
// Assignments are deleted because they break the invariant that the size of a
|
| 171 |
+
// `FixedArray` never changes.
|
| 172 |
+
void operator=(FixedArray&&) = delete;
|
| 173 |
+
void operator=(const FixedArray&) = delete;
|
| 174 |
+
|
| 175 |
+
// FixedArray::size()
|
| 176 |
+
//
|
| 177 |
+
// Returns the length of the fixed array.
|
| 178 |
+
size_type size() const { return storage_.size(); }
|
| 179 |
+
|
| 180 |
+
// FixedArray::max_size()
|
| 181 |
+
//
|
| 182 |
+
// Returns the largest possible value of `std::distance(begin(), end())` for a
|
| 183 |
+
// `FixedArray<T>`. This is equivalent to the most possible addressable bytes
|
| 184 |
+
// over the number of bytes taken by T.
|
| 185 |
+
constexpr size_type max_size() const {
|
| 186 |
+
return (std::numeric_limits<difference_type>::max)() / sizeof(value_type);
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
// FixedArray::empty()
|
| 190 |
+
//
|
| 191 |
+
// Returns whether or not the fixed array is empty.
|
| 192 |
+
bool empty() const { return size() == 0; }
|
| 193 |
+
|
| 194 |
+
// FixedArray::memsize()
|
| 195 |
+
//
|
| 196 |
+
// Returns the memory size of the fixed array in bytes.
|
| 197 |
+
size_t memsize() const { return size() * sizeof(value_type); }
|
| 198 |
+
|
| 199 |
+
// FixedArray::data()
|
| 200 |
+
//
|
| 201 |
+
// Returns a const T* pointer to elements of the `FixedArray`. This pointer
|
| 202 |
+
// can be used to access (but not modify) the contained elements.
|
| 203 |
+
const_pointer data() const { return AsValueType(storage_.begin()); }
|
| 204 |
+
|
| 205 |
+
// Overload of FixedArray::data() to return a T* pointer to elements of the
|
| 206 |
+
// fixed array. This pointer can be used to access and modify the contained
|
| 207 |
+
// elements.
|
| 208 |
+
pointer data() { return AsValueType(storage_.begin()); }
|
| 209 |
+
|
| 210 |
+
// FixedArray::operator[]
|
| 211 |
+
//
|
| 212 |
+
// Returns a reference the ith element of the fixed array.
|
| 213 |
+
// REQUIRES: 0 <= i < size()
|
| 214 |
+
reference operator[](size_type i) {
|
| 215 |
+
DCHECK_LT(i, size());
|
| 216 |
+
return data()[i];
|
| 217 |
+
}
|
| 218 |
+
|
| 219 |
+
// Overload of FixedArray::operator()[] to return a const reference to the
|
| 220 |
+
// ith element of the fixed array.
|
| 221 |
+
// REQUIRES: 0 <= i < size()
|
| 222 |
+
const_reference operator[](size_type i) const {
|
| 223 |
+
DCHECK_LT(i, size());
|
| 224 |
+
return data()[i];
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
// FixedArray::front()
|
| 228 |
+
//
|
| 229 |
+
// Returns a reference to the first element of the fixed array.
|
| 230 |
+
reference front() { return *begin(); }
|
| 231 |
+
|
| 232 |
+
// Overload of FixedArray::front() to return a reference to the first element
|
| 233 |
+
// of a fixed array of const values.
|
| 234 |
+
const_reference front() const { return *begin(); }
|
| 235 |
+
|
| 236 |
+
// FixedArray::back()
|
| 237 |
+
//
|
| 238 |
+
// Returns a reference to the last element of the fixed array.
|
| 239 |
+
reference back() { return *(end() - 1); }
|
| 240 |
+
|
| 241 |
+
// Overload of FixedArray::back() to return a reference to the last element
|
| 242 |
+
// of a fixed array of const values.
|
| 243 |
+
const_reference back() const { return *(end() - 1); }
|
| 244 |
+
|
| 245 |
+
// FixedArray::begin()
|
| 246 |
+
//
|
| 247 |
+
// Returns an iterator to the beginning of the fixed array.
|
| 248 |
+
iterator begin() { return data(); }
|
| 249 |
+
|
| 250 |
+
// Overload of FixedArray::begin() to return a const iterator to the
|
| 251 |
+
// beginning of the fixed array.
|
| 252 |
+
const_iterator begin() const { return data(); }
|
| 253 |
+
|
| 254 |
+
// FixedArray::cbegin()
|
| 255 |
+
//
|
| 256 |
+
// Returns a const iterator to the beginning of the fixed array.
|
| 257 |
+
const_iterator cbegin() const { return begin(); }
|
| 258 |
+
|
| 259 |
+
// FixedArray::end()
|
| 260 |
+
//
|
| 261 |
+
// Returns an iterator to the end of the fixed array.
|
| 262 |
+
iterator end() { return data() + size(); }
|
| 263 |
+
|
| 264 |
+
// Overload of FixedArray::end() to return a const iterator to the end of the
|
| 265 |
+
// fixed array.
|
| 266 |
+
const_iterator end() const { return data() + size(); }
|
| 267 |
+
|
| 268 |
+
// FixedArray::cend()
|
| 269 |
+
//
|
| 270 |
+
// Returns a const iterator to the end of the fixed array.
|
| 271 |
+
const_iterator cend() const { return end(); }
|
| 272 |
+
|
| 273 |
+
// FixedArray::rbegin()
|
| 274 |
+
//
|
| 275 |
+
// Returns a reverse iterator from the end of the fixed array.
|
| 276 |
+
reverse_iterator rbegin() { return reverse_iterator(end()); }
|
| 277 |
+
|
| 278 |
+
// Overload of FixedArray::rbegin() to return a const reverse iterator from
|
| 279 |
+
// the end of the fixed array.
|
| 280 |
+
const_reverse_iterator rbegin() const {
|
| 281 |
+
return const_reverse_iterator(end());
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
// FixedArray::crbegin()
|
| 285 |
+
//
|
| 286 |
+
// Returns a const reverse iterator from the end of the fixed array.
|
| 287 |
+
const_reverse_iterator crbegin() const { return rbegin(); }
|
| 288 |
+
|
| 289 |
+
// FixedArray::rend()
|
| 290 |
+
//
|
| 291 |
+
// Returns a reverse iterator from the beginning of the fixed array.
|
| 292 |
+
reverse_iterator rend() { return reverse_iterator(begin()); }
|
| 293 |
+
|
| 294 |
+
// Overload of FixedArray::rend() for returning a const reverse iterator
|
| 295 |
+
// from the beginning of the fixed array.
|
| 296 |
+
const_reverse_iterator rend() const {
|
| 297 |
+
return const_reverse_iterator(begin());
|
| 298 |
+
}
|
| 299 |
+
|
| 300 |
+
// FixedArray::crend()
|
| 301 |
+
//
|
| 302 |
+
// Returns a reverse iterator from the beginning of the fixed array.
|
| 303 |
+
const_reverse_iterator crend() const { return rend(); }
|
| 304 |
+
|
| 305 |
+
// FixedArray::fill()
|
| 306 |
+
//
|
| 307 |
+
// Assigns the given `value` to all elements in the fixed array.
|
| 308 |
+
void fill(const value_type& val) { std::fill(begin(), end(), val); }
|
| 309 |
+
|
| 310 |
+
// Relational operators. Equality operators are elementwise using
|
| 311 |
+
// `operator==`, while order operators order FixedArrays lexicographically.
|
| 312 |
+
friend bool operator==(const FixedArray& lhs, const FixedArray& rhs) {
|
| 313 |
+
return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
|
| 314 |
+
}
|
| 315 |
+
|
| 316 |
+
friend bool operator!=(const FixedArray& lhs, const FixedArray& rhs) {
|
| 317 |
+
return !(lhs == rhs);
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
friend bool operator<(const FixedArray& lhs, const FixedArray& rhs) {
|
| 321 |
+
return std::lexicographical_compare(
|
| 322 |
+
lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
|
| 323 |
+
}
|
| 324 |
+
|
| 325 |
+
friend bool operator>(const FixedArray& lhs, const FixedArray& rhs) {
|
| 326 |
+
return rhs < lhs;
|
| 327 |
+
}
|
| 328 |
+
|
| 329 |
+
friend bool operator<=(const FixedArray& lhs, const FixedArray& rhs) {
|
| 330 |
+
return !(rhs < lhs);
|
| 331 |
+
}
|
| 332 |
+
|
| 333 |
+
friend bool operator>=(const FixedArray& lhs, const FixedArray& rhs) {
|
| 334 |
+
return !(lhs < rhs);
|
| 335 |
+
}
|
| 336 |
+
|
| 337 |
+
private:
|
| 338 |
+
// StorageElement
|
| 339 |
+
//
|
| 340 |
+
// For FixedArrays with a C-style-array value_type, StorageElement is a POD
|
| 341 |
+
// wrapper struct called StorageElementWrapper that holds the value_type
|
| 342 |
+
// instance inside. This is needed for construction and destruction of the
|
| 343 |
+
// entire array regardless of how many dimensions it has. For all other cases,
|
| 344 |
+
// StorageElement is just an alias of value_type.
|
| 345 |
+
//
|
| 346 |
+
// Maintainer's Note: The simpler solution would be to simply wrap value_type
|
| 347 |
+
// in a struct whether it's an array or not. That causes some paranoid
|
| 348 |
+
// diagnostics to misfire, believing that 'data()' returns a pointer to a
|
| 349 |
+
// single element, rather than the packed array that it really is.
|
| 350 |
+
// e.g.:
|
| 351 |
+
//
|
| 352 |
+
// FixedArray<char> buf(1);
|
| 353 |
+
// sprintf(buf.data(), "foo");
|
| 354 |
+
//
|
| 355 |
+
// error: call to int __builtin___sprintf_chk(etc...)
|
| 356 |
+
// will always overflow destination buffer [-Werror]
|
| 357 |
+
//
|
| 358 |
+
template <typename OuterT,
|
| 359 |
+
typename InnerT = typename std::remove_extent<OuterT>::type,
|
| 360 |
+
size_t InnerN = std::extent<OuterT>::value>
|
| 361 |
+
struct StorageElementWrapper {
|
| 362 |
+
InnerT array[InnerN];
|
| 363 |
+
};
|
| 364 |
+
|
| 365 |
+
using StorageElement =
|
| 366 |
+
typename std::conditional<std::is_array<value_type>::value,
|
| 367 |
+
StorageElementWrapper<value_type>,
|
| 368 |
+
value_type>::type;
|
| 369 |
+
|
| 370 |
+
static pointer AsValueType(pointer ptr) { return ptr; }
|
| 371 |
+
static pointer AsValueType(StorageElementWrapper<value_type>* ptr) {
|
| 372 |
+
return std::addressof(ptr->array);
|
| 373 |
+
}
|
| 374 |
+
|
| 375 |
+
static_assert(sizeof(StorageElement) == sizeof(value_type), "");
|
| 376 |
+
static_assert(alignof(StorageElement) == alignof(value_type), "");
|
| 377 |
+
|
| 378 |
+
class NonEmptyInlinedStorage {
|
| 379 |
+
public:
|
| 380 |
+
StorageElement* data() { return reinterpret_cast<StorageElement*>(buff_); }
|
| 381 |
+
void AnnotateConstruct(size_type) {}
|
| 382 |
+
void AnnotateDestruct(size_type) {}
|
| 383 |
+
|
| 384 |
+
// #ifdef ADDRESS_SANITIZER
|
| 385 |
+
// void* RedzoneBegin() { return &redzone_begin_; }
|
| 386 |
+
// void* RedzoneEnd() { return &redzone_end_ + 1; }
|
| 387 |
+
// #endif // ADDRESS_SANITIZER
|
| 388 |
+
|
| 389 |
+
private:
|
| 390 |
+
// ADDRESS_SANITIZER_REDZONE(redzone_begin_);
|
| 391 |
+
alignas(StorageElement) char buff_[sizeof(StorageElement[inline_elements])];
|
| 392 |
+
// ADDRESS_SANITIZER_REDZONE(redzone_end_);
|
| 393 |
+
};
|
| 394 |
+
|
| 395 |
+
class EmptyInlinedStorage {
|
| 396 |
+
public:
|
| 397 |
+
StorageElement* data() { return nullptr; }
|
| 398 |
+
void AnnotateConstruct(size_type) {}
|
| 399 |
+
void AnnotateDestruct(size_type) {}
|
| 400 |
+
};
|
| 401 |
+
|
| 402 |
+
using InlinedStorage =
|
| 403 |
+
typename std::conditional<inline_elements == 0,
|
| 404 |
+
EmptyInlinedStorage,
|
| 405 |
+
NonEmptyInlinedStorage>::type;
|
| 406 |
+
|
| 407 |
+
// Storage
|
| 408 |
+
//
|
| 409 |
+
// An instance of Storage manages the inline and out-of-line memory for
|
| 410 |
+
// instances of FixedArray. This guarantees that even when construction of
|
| 411 |
+
// individual elements fails in the FixedArray constructor body, the
|
| 412 |
+
// destructor for Storage will still be called and out-of-line memory will be
|
| 413 |
+
// properly deallocated.
|
| 414 |
+
//
|
| 415 |
+
class Storage : public InlinedStorage {
|
| 416 |
+
public:
|
| 417 |
+
Storage(size_type n, const allocator_type& a)
|
| 418 |
+
: size_alloc_(n, a), data_(InitializeData()) {}
|
| 419 |
+
|
| 420 |
+
~Storage() noexcept {
|
| 421 |
+
if (UsingInlinedStorage(size())) {
|
| 422 |
+
InlinedStorage::AnnotateDestruct(size());
|
| 423 |
+
} else {
|
| 424 |
+
AllocatorTraits::deallocate(alloc(), AsValueType(begin()), size());
|
| 425 |
+
}
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
size_type size() const { return std::get<0>(size_alloc_); }
|
| 429 |
+
StorageElement* begin() const { return data_; }
|
| 430 |
+
StorageElement* end() const { return begin() + size(); }
|
| 431 |
+
allocator_type& alloc() { return std::get<1>(size_alloc_); }
|
| 432 |
+
|
| 433 |
+
private:
|
| 434 |
+
static bool UsingInlinedStorage(size_type n) {
|
| 435 |
+
return n <= inline_elements;
|
| 436 |
+
}
|
| 437 |
+
|
| 438 |
+
StorageElement* InitializeData() {
|
| 439 |
+
if (UsingInlinedStorage(size())) {
|
| 440 |
+
InlinedStorage::AnnotateConstruct(size());
|
| 441 |
+
return InlinedStorage::data();
|
| 442 |
+
} else {
|
| 443 |
+
return reinterpret_cast<StorageElement*>(
|
| 444 |
+
AllocatorTraits::allocate(alloc(), size()));
|
| 445 |
+
}
|
| 446 |
+
}
|
| 447 |
+
|
| 448 |
+
// Using std::tuple and not absl::CompressedTuple, as it has a lot of
|
| 449 |
+
// dependencies to other absl headers.
|
| 450 |
+
std::tuple<size_type, allocator_type> size_alloc_;
|
| 451 |
+
StorageElement* data_;
|
| 452 |
+
};
|
| 453 |
+
|
| 454 |
+
Storage storage_;
|
| 455 |
+
};
|
| 456 |
+
|
| 457 |
+
template <typename T, size_t N, typename A>
|
| 458 |
+
constexpr size_t FixedArray<T, N, A>::kInlineBytesDefault;
|
| 459 |
+
|
| 460 |
+
template <typename T, size_t N, typename A>
|
| 461 |
+
constexpr typename FixedArray<T, N, A>::size_type
|
| 462 |
+
FixedArray<T, N, A>::inline_elements;
|
| 463 |
+
|
| 464 |
+
} // namespace internal
|
| 465 |
+
} // namespace ceres
|
| 466 |
+
|
| 467 |
+
#endif // CERES_PUBLIC_INTERNAL_FIXED_ARRAY_H_
|
include/ceres/internal/householder_vector.h
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2015 Google Inc. All rights reserved.
|
| 3 |
+
// http://code.google.com/p/ceres-solver/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: vitus@google.com (Michael Vitus)
|
| 30 |
+
|
| 31 |
+
#ifndef CERES_PUBLIC_INTERNAL_HOUSEHOLDER_VECTOR_H_
|
| 32 |
+
#define CERES_PUBLIC_INTERNAL_HOUSEHOLDER_VECTOR_H_
|
| 33 |
+
|
| 34 |
+
#include "Eigen/Core"
|
| 35 |
+
#include "glog/logging.h"
|
| 36 |
+
|
| 37 |
+
namespace ceres {
|
| 38 |
+
namespace internal {
|
| 39 |
+
|
| 40 |
+
// Algorithm 5.1.1 from 'Matrix Computations' by Golub et al. (Johns Hopkins
|
| 41 |
+
// Studies in Mathematical Sciences) but using the nth element of the input
|
| 42 |
+
// vector as pivot instead of first. This computes the vector v with v(n) = 1
|
| 43 |
+
// and beta such that H = I - beta * v * v^T is orthogonal and
|
| 44 |
+
// H * x = ||x||_2 * e_n.
|
| 45 |
+
//
|
| 46 |
+
// NOTE: Some versions of MSVC have trouble deducing the type of v if
|
| 47 |
+
// you do not specify all the template arguments explicitly.
|
| 48 |
+
template <typename XVectorType, typename Scalar, int N>
|
| 49 |
+
void ComputeHouseholderVector(const XVectorType& x,
|
| 50 |
+
Eigen::Matrix<Scalar, N, 1>* v,
|
| 51 |
+
Scalar* beta) {
|
| 52 |
+
CHECK(beta != nullptr);
|
| 53 |
+
CHECK(v != nullptr);
|
| 54 |
+
CHECK_GT(x.rows(), 1);
|
| 55 |
+
CHECK_EQ(x.rows(), v->rows());
|
| 56 |
+
|
| 57 |
+
Scalar sigma = x.head(x.rows() - 1).squaredNorm();
|
| 58 |
+
*v = x;
|
| 59 |
+
(*v)(v->rows() - 1) = Scalar(1.0);
|
| 60 |
+
|
| 61 |
+
*beta = Scalar(0.0);
|
| 62 |
+
const Scalar& x_pivot = x(x.rows() - 1);
|
| 63 |
+
|
| 64 |
+
if (sigma <= Scalar(std::numeric_limits<double>::epsilon())) {
|
| 65 |
+
if (x_pivot < Scalar(0.0)) {
|
| 66 |
+
*beta = Scalar(2.0);
|
| 67 |
+
}
|
| 68 |
+
return;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
const Scalar mu = sqrt(x_pivot * x_pivot + sigma);
|
| 72 |
+
Scalar v_pivot = Scalar(1.0);
|
| 73 |
+
|
| 74 |
+
if (x_pivot <= Scalar(0.0)) {
|
| 75 |
+
v_pivot = x_pivot - mu;
|
| 76 |
+
} else {
|
| 77 |
+
v_pivot = -sigma / (x_pivot + mu);
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
*beta = Scalar(2.0) * v_pivot * v_pivot / (sigma + v_pivot * v_pivot);
|
| 81 |
+
|
| 82 |
+
v->head(v->rows() - 1) /= v_pivot;
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
template <typename XVectorType, typename Derived>
|
| 86 |
+
typename Derived::PlainObject ApplyHouseholderVector(
|
| 87 |
+
const XVectorType& y,
|
| 88 |
+
const Eigen::MatrixBase<Derived>& v,
|
| 89 |
+
const typename Derived::Scalar& beta) {
|
| 90 |
+
return (y - v * (beta * (v.transpose() * y)));
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
} // namespace internal
|
| 94 |
+
} // namespace ceres
|
| 95 |
+
|
| 96 |
+
#endif // CERES_PUBLIC_INTERNAL_HOUSEHOLDER_VECTOR_H_
|
include/ceres/internal/integer_sequence_algorithm.h
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2022 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: jodebo_beck@gmx.de (Johannes Beck)
|
| 30 |
+
// sergiu.deitsch@gmail.com (Sergiu Deitsch)
|
| 31 |
+
//
|
| 32 |
+
// Algorithms to be used together with integer_sequence, like computing the sum
|
| 33 |
+
// or the exclusive scan (sometimes called exclusive prefix sum) at compile
|
| 34 |
+
// time.
|
| 35 |
+
|
| 36 |
+
#ifndef CERES_PUBLIC_INTERNAL_INTEGER_SEQUENCE_ALGORITHM_H_
|
| 37 |
+
#define CERES_PUBLIC_INTERNAL_INTEGER_SEQUENCE_ALGORITHM_H_
|
| 38 |
+
|
| 39 |
+
#include <utility>
|
| 40 |
+
|
| 41 |
+
#include "ceres/jet_fwd.h"
|
| 42 |
+
|
| 43 |
+
namespace ceres {
|
| 44 |
+
namespace internal {
|
| 45 |
+
|
| 46 |
+
// Implementation of calculating the sum of an integer sequence.
|
| 47 |
+
// Recursively instantiate SumImpl and calculate the sum of the N first
|
| 48 |
+
// numbers. This reduces the number of instantiations and speeds up
|
| 49 |
+
// compilation.
|
| 50 |
+
//
|
| 51 |
+
// Examples:
|
| 52 |
+
// 1) integer_sequence<int, 5>:
|
| 53 |
+
// Value = 5
|
| 54 |
+
//
|
| 55 |
+
// 2) integer_sequence<int, 4, 2>:
|
| 56 |
+
// Value = 4 + 2 + SumImpl<integer_sequence<int>>::Value
|
| 57 |
+
// Value = 4 + 2 + 0
|
| 58 |
+
//
|
| 59 |
+
// 3) integer_sequence<int, 2, 1, 4>:
|
| 60 |
+
// Value = 2 + 1 + SumImpl<integer_sequence<int, 4>>::Value
|
| 61 |
+
// Value = 2 + 1 + 4
|
| 62 |
+
template <typename Seq>
|
| 63 |
+
struct SumImpl;
|
| 64 |
+
|
| 65 |
+
// Strip of and sum the first number.
|
| 66 |
+
template <typename T, T N, T... Ns>
|
| 67 |
+
struct SumImpl<std::integer_sequence<T, N, Ns...>> {
|
| 68 |
+
static constexpr T Value =
|
| 69 |
+
N + SumImpl<std::integer_sequence<T, Ns...>>::Value;
|
| 70 |
+
};
|
| 71 |
+
|
| 72 |
+
// Strip of and sum the first two numbers.
|
| 73 |
+
template <typename T, T N1, T N2, T... Ns>
|
| 74 |
+
struct SumImpl<std::integer_sequence<T, N1, N2, Ns...>> {
|
| 75 |
+
static constexpr T Value =
|
| 76 |
+
N1 + N2 + SumImpl<std::integer_sequence<T, Ns...>>::Value;
|
| 77 |
+
};
|
| 78 |
+
|
| 79 |
+
// Strip of and sum the first four numbers.
|
| 80 |
+
template <typename T, T N1, T N2, T N3, T N4, T... Ns>
|
| 81 |
+
struct SumImpl<std::integer_sequence<T, N1, N2, N3, N4, Ns...>> {
|
| 82 |
+
static constexpr T Value =
|
| 83 |
+
N1 + N2 + N3 + N4 + SumImpl<std::integer_sequence<T, Ns...>>::Value;
|
| 84 |
+
};
|
| 85 |
+
|
| 86 |
+
// Only one number is left. 'Value' is just that number ('recursion' ends).
|
| 87 |
+
template <typename T, T N>
|
| 88 |
+
struct SumImpl<std::integer_sequence<T, N>> {
|
| 89 |
+
static constexpr T Value = N;
|
| 90 |
+
};
|
| 91 |
+
|
| 92 |
+
// No number is left. 'Value' is the identity element (for sum this is zero).
|
| 93 |
+
template <typename T>
|
| 94 |
+
struct SumImpl<std::integer_sequence<T>> {
|
| 95 |
+
static constexpr T Value = T(0);
|
| 96 |
+
};
|
| 97 |
+
|
| 98 |
+
// Calculate the sum of an integer sequence. The resulting sum will be stored in
|
| 99 |
+
// 'Value'.
|
| 100 |
+
template <typename Seq>
|
| 101 |
+
class Sum {
|
| 102 |
+
using T = typename Seq::value_type;
|
| 103 |
+
|
| 104 |
+
public:
|
| 105 |
+
static constexpr T Value = SumImpl<Seq>::Value;
|
| 106 |
+
};
|
| 107 |
+
|
| 108 |
+
// Implementation of calculating an exclusive scan (exclusive prefix sum) of an
|
| 109 |
+
// integer sequence. Exclusive means that the i-th input element is not included
|
| 110 |
+
// in the i-th sum. Calculating the exclusive scan for an input array I results
|
| 111 |
+
// in the following output R:
|
| 112 |
+
//
|
| 113 |
+
// R[0] = 0
|
| 114 |
+
// R[1] = I[0];
|
| 115 |
+
// R[2] = I[0] + I[1];
|
| 116 |
+
// R[3] = I[0] + I[1] + I[2];
|
| 117 |
+
// ...
|
| 118 |
+
//
|
| 119 |
+
// In C++17 std::exclusive_scan does the same operation at runtime (but
|
| 120 |
+
// cannot be used to calculate the prefix sum at compile time). See
|
| 121 |
+
// https://en.cppreference.com/w/cpp/algorithm/exclusive_scan for a more
|
| 122 |
+
// detailed description.
|
| 123 |
+
//
|
| 124 |
+
// Example for integer_sequence<int, 1, 4, 3> (seq := integer_sequence):
|
| 125 |
+
// T , Sum, Ns... , Rs...
|
| 126 |
+
// ExclusiveScanImpl<int, 0, seq<int, 1, 4, 3>, seq<int >>
|
| 127 |
+
// ExclusiveScanImpl<int, 1, seq<int, 4, 3>, seq<int, 0 >>
|
| 128 |
+
// ExclusiveScanImpl<int, 5, seq<int, 3>, seq<int, 0, 1 >>
|
| 129 |
+
// ExclusiveScanImpl<int, 8, seq<int >, seq<int, 0, 1, 5>>
|
| 130 |
+
// ^^^^^^^^^^^^^^^^^
|
| 131 |
+
// resulting sequence
|
| 132 |
+
template <typename T, T Sum, typename SeqIn, typename SeqOut>
|
| 133 |
+
struct ExclusiveScanImpl;
|
| 134 |
+
|
| 135 |
+
template <typename T, T Sum, T N, T... Ns, T... Rs>
|
| 136 |
+
struct ExclusiveScanImpl<T,
|
| 137 |
+
Sum,
|
| 138 |
+
std::integer_sequence<T, N, Ns...>,
|
| 139 |
+
std::integer_sequence<T, Rs...>> {
|
| 140 |
+
using Type =
|
| 141 |
+
typename ExclusiveScanImpl<T,
|
| 142 |
+
Sum + N,
|
| 143 |
+
std::integer_sequence<T, Ns...>,
|
| 144 |
+
std::integer_sequence<T, Rs..., Sum>>::Type;
|
| 145 |
+
};
|
| 146 |
+
|
| 147 |
+
// End of 'recursion'. The resulting type is SeqOut.
|
| 148 |
+
template <typename T, T Sum, typename SeqOut>
|
| 149 |
+
struct ExclusiveScanImpl<T, Sum, std::integer_sequence<T>, SeqOut> {
|
| 150 |
+
using Type = SeqOut;
|
| 151 |
+
};
|
| 152 |
+
|
| 153 |
+
// Calculates the exclusive scan of the specified integer sequence. The last
|
| 154 |
+
// element (the total) is not included in the resulting sequence so they have
|
| 155 |
+
// same length. This means the exclusive scan of integer_sequence<int, 1, 2, 3>
|
| 156 |
+
// will be integer_sequence<int, 0, 1, 3>.
|
| 157 |
+
template <typename Seq>
|
| 158 |
+
class ExclusiveScanT {
|
| 159 |
+
using T = typename Seq::value_type;
|
| 160 |
+
|
| 161 |
+
public:
|
| 162 |
+
using Type =
|
| 163 |
+
typename ExclusiveScanImpl<T, T(0), Seq, std::integer_sequence<T>>::Type;
|
| 164 |
+
};
|
| 165 |
+
|
| 166 |
+
// Helper to use exclusive scan without typename.
|
| 167 |
+
template <typename Seq>
|
| 168 |
+
using ExclusiveScan = typename ExclusiveScanT<Seq>::Type;
|
| 169 |
+
|
| 170 |
+
// Removes all elements from a integer sequence corresponding to specified
|
| 171 |
+
// ValueToRemove.
|
| 172 |
+
//
|
| 173 |
+
// This type should not be used directly but instead RemoveValue.
|
| 174 |
+
template <typename T, T ValueToRemove, typename... Sequence>
|
| 175 |
+
struct RemoveValueImpl;
|
| 176 |
+
|
| 177 |
+
// Final filtered sequence
|
| 178 |
+
template <typename T, T ValueToRemove, T... Values>
|
| 179 |
+
struct RemoveValueImpl<T,
|
| 180 |
+
ValueToRemove,
|
| 181 |
+
std::integer_sequence<T, Values...>,
|
| 182 |
+
std::integer_sequence<T>> {
|
| 183 |
+
using type = std::integer_sequence<T, Values...>;
|
| 184 |
+
};
|
| 185 |
+
|
| 186 |
+
// Found a matching value
|
| 187 |
+
template <typename T, T ValueToRemove, T... Head, T... Tail>
|
| 188 |
+
struct RemoveValueImpl<T,
|
| 189 |
+
ValueToRemove,
|
| 190 |
+
std::integer_sequence<T, Head...>,
|
| 191 |
+
std::integer_sequence<T, ValueToRemove, Tail...>>
|
| 192 |
+
: RemoveValueImpl<T,
|
| 193 |
+
ValueToRemove,
|
| 194 |
+
std::integer_sequence<T, Head...>,
|
| 195 |
+
std::integer_sequence<T, Tail...>> {};
|
| 196 |
+
|
| 197 |
+
// Move one element from the tail to the head
|
| 198 |
+
template <typename T, T ValueToRemove, T... Head, T MiddleValue, T... Tail>
|
| 199 |
+
struct RemoveValueImpl<T,
|
| 200 |
+
ValueToRemove,
|
| 201 |
+
std::integer_sequence<T, Head...>,
|
| 202 |
+
std::integer_sequence<T, MiddleValue, Tail...>>
|
| 203 |
+
: RemoveValueImpl<T,
|
| 204 |
+
ValueToRemove,
|
| 205 |
+
std::integer_sequence<T, Head..., MiddleValue>,
|
| 206 |
+
std::integer_sequence<T, Tail...>> {};
|
| 207 |
+
|
| 208 |
+
// Start recursion by splitting the integer sequence into two separate ones
|
| 209 |
+
template <typename T, T ValueToRemove, T... Tail>
|
| 210 |
+
struct RemoveValueImpl<T, ValueToRemove, std::integer_sequence<T, Tail...>>
|
| 211 |
+
: RemoveValueImpl<T,
|
| 212 |
+
ValueToRemove,
|
| 213 |
+
std::integer_sequence<T>,
|
| 214 |
+
std::integer_sequence<T, Tail...>> {};
|
| 215 |
+
|
| 216 |
+
// RemoveValue takes an integer Sequence of arbitrary type and removes all
|
| 217 |
+
// elements matching ValueToRemove.
|
| 218 |
+
//
|
| 219 |
+
// In contrast to RemoveValueImpl, this implementation deduces the value type
|
| 220 |
+
// eliminating the need to specify it explicitly.
|
| 221 |
+
//
|
| 222 |
+
// As an example, RemoveValue<std::integer_sequence<int, 1, 2, 3>, 4>::type will
|
| 223 |
+
// not transform the type of the original sequence. However,
|
| 224 |
+
// RemoveValue<std::integer_sequence<int, 0, 0, 2>, 2>::type will generate a new
|
| 225 |
+
// sequence of type std::integer_sequence<int, 0, 0> by removing the value 2.
|
| 226 |
+
template <typename Sequence, typename Sequence::value_type ValueToRemove>
|
| 227 |
+
struct RemoveValue
|
| 228 |
+
: RemoveValueImpl<typename Sequence::value_type, ValueToRemove, Sequence> {
|
| 229 |
+
};
|
| 230 |
+
|
| 231 |
+
// Convenience template alias for RemoveValue.
|
| 232 |
+
template <typename Sequence, typename Sequence::value_type ValueToRemove>
|
| 233 |
+
using RemoveValue_t = typename RemoveValue<Sequence, ValueToRemove>::type;
|
| 234 |
+
|
| 235 |
+
// Determines whether the values of an integer sequence are all the same.
|
| 236 |
+
//
|
| 237 |
+
// The integer sequence must contain at least one value. The predicate is
|
| 238 |
+
// undefined for empty sequences. The evaluation result of the predicate for a
|
| 239 |
+
// sequence containing only one value is defined to be true.
|
| 240 |
+
template <typename... Sequence>
|
| 241 |
+
struct AreAllEqual;
|
| 242 |
+
|
| 243 |
+
// The predicate result for a sequence containing one element is defined to be
|
| 244 |
+
// true.
|
| 245 |
+
template <typename T, T Value>
|
| 246 |
+
struct AreAllEqual<std::integer_sequence<T, Value>> : std::true_type {};
|
| 247 |
+
|
| 248 |
+
// Recursion end.
|
| 249 |
+
template <typename T, T Value1, T Value2>
|
| 250 |
+
struct AreAllEqual<std::integer_sequence<T, Value1, Value2>>
|
| 251 |
+
: std::integral_constant<bool, Value1 == Value2> {};
|
| 252 |
+
|
| 253 |
+
// Recursion for sequences containing at least two elements.
|
| 254 |
+
template <typename T, T Value1, T Value2, T... Values>
|
| 255 |
+
// clang-format off
|
| 256 |
+
struct AreAllEqual<std::integer_sequence<T, Value1, Value2, Values...> >
|
| 257 |
+
: std::integral_constant
|
| 258 |
+
<
|
| 259 |
+
bool,
|
| 260 |
+
AreAllEqual<std::integer_sequence<T, Value1, Value2> >::value &&
|
| 261 |
+
AreAllEqual<std::integer_sequence<T, Value2, Values...> >::value
|
| 262 |
+
>
|
| 263 |
+
// clang-format on
|
| 264 |
+
{};
|
| 265 |
+
|
| 266 |
+
// Convenience variable template for AreAllEqual.
|
| 267 |
+
template <class Sequence>
|
| 268 |
+
constexpr bool AreAllEqual_v = AreAllEqual<Sequence>::value;
|
| 269 |
+
|
| 270 |
+
// Predicate determining whether an integer sequence is either empty or all
|
| 271 |
+
// values are equal.
|
| 272 |
+
template <typename Sequence>
|
| 273 |
+
struct IsEmptyOrAreAllEqual;
|
| 274 |
+
|
| 275 |
+
// Empty case.
|
| 276 |
+
template <typename T>
|
| 277 |
+
struct IsEmptyOrAreAllEqual<std::integer_sequence<T>> : std::true_type {};
|
| 278 |
+
|
| 279 |
+
// General case for sequences containing at least one value.
|
| 280 |
+
template <typename T, T HeadValue, T... Values>
|
| 281 |
+
struct IsEmptyOrAreAllEqual<std::integer_sequence<T, HeadValue, Values...>>
|
| 282 |
+
: AreAllEqual<std::integer_sequence<T, HeadValue, Values...>> {};
|
| 283 |
+
|
| 284 |
+
// Convenience variable template for IsEmptyOrAreAllEqual.
|
| 285 |
+
template <class Sequence>
|
| 286 |
+
constexpr bool IsEmptyOrAreAllEqual_v = IsEmptyOrAreAllEqual<Sequence>::value;
|
| 287 |
+
|
| 288 |
+
} // namespace internal
|
| 289 |
+
} // namespace ceres
|
| 290 |
+
|
| 291 |
+
#endif // CERES_PUBLIC_INTERNAL_INTEGER_SEQUENCE_ALGORITHM_H_
|
include/ceres/internal/jet_traits.h
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2022 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: sergiu.deitsch@gmail.com (Sergiu Deitsch)
|
| 30 |
+
//
|
| 31 |
+
|
| 32 |
+
#ifndef CERES_PUBLIC_INTERNAL_JET_TRAITS_H_
|
| 33 |
+
#define CERES_PUBLIC_INTERNAL_JET_TRAITS_H_
|
| 34 |
+
|
| 35 |
+
#include <tuple>
|
| 36 |
+
#include <type_traits>
|
| 37 |
+
#include <utility>
|
| 38 |
+
|
| 39 |
+
#include "ceres/internal/integer_sequence_algorithm.h"
|
| 40 |
+
#include "ceres/jet_fwd.h"
|
| 41 |
+
|
| 42 |
+
namespace ceres {
|
| 43 |
+
namespace internal {
|
| 44 |
+
|
| 45 |
+
// Predicate that determines whether T is a Jet.
|
| 46 |
+
template <typename T, typename E = void>
|
| 47 |
+
struct IsJet : std::false_type {};
|
| 48 |
+
|
| 49 |
+
template <typename T, int N>
|
| 50 |
+
struct IsJet<Jet<T, N>> : std::true_type {};
|
| 51 |
+
|
| 52 |
+
// Convenience variable template for IsJet.
|
| 53 |
+
template <typename T>
|
| 54 |
+
constexpr bool IsJet_v = IsJet<T>::value;
|
| 55 |
+
|
| 56 |
+
// Predicate that determines whether any of the Types is a Jet.
|
| 57 |
+
template <typename... Types>
|
| 58 |
+
struct AreAnyJet : std::false_type {};
|
| 59 |
+
|
| 60 |
+
template <typename T, typename... Types>
|
| 61 |
+
struct AreAnyJet<T, Types...> : AreAnyJet<Types...> {};
|
| 62 |
+
|
| 63 |
+
template <typename T, int N, typename... Types>
|
| 64 |
+
struct AreAnyJet<Jet<T, N>, Types...> : std::true_type {};
|
| 65 |
+
|
| 66 |
+
// Convenience variable template for AreAnyJet.
|
| 67 |
+
template <typename... Types>
|
| 68 |
+
constexpr bool AreAnyJet_v = AreAnyJet<Types...>::value;
|
| 69 |
+
|
| 70 |
+
// Extracts the underlying floating-point from a type T.
|
| 71 |
+
template <typename T, typename E = void>
|
| 72 |
+
struct UnderlyingScalar {
|
| 73 |
+
using type = T;
|
| 74 |
+
};
|
| 75 |
+
|
| 76 |
+
template <typename T, int N>
|
| 77 |
+
struct UnderlyingScalar<Jet<T, N>> : UnderlyingScalar<T> {};
|
| 78 |
+
|
| 79 |
+
// Convenience template alias for UnderlyingScalar type trait.
|
| 80 |
+
template <typename T>
|
| 81 |
+
using UnderlyingScalar_t = typename UnderlyingScalar<T>::type;
|
| 82 |
+
|
| 83 |
+
// Predicate determining whether all Types in the pack are the same.
|
| 84 |
+
//
|
| 85 |
+
// Specifically, the predicate applies std::is_same recursively to pairs of
|
| 86 |
+
// Types in the pack.
|
| 87 |
+
//
|
| 88 |
+
// The predicate is defined only for template packs containing at least two
|
| 89 |
+
// types.
|
| 90 |
+
template <typename T1, typename T2, typename... Types>
|
| 91 |
+
// clang-format off
|
| 92 |
+
struct AreAllSame : std::integral_constant
|
| 93 |
+
<
|
| 94 |
+
bool,
|
| 95 |
+
AreAllSame<T1, T2>::value &&
|
| 96 |
+
AreAllSame<T2, Types...>::value
|
| 97 |
+
>
|
| 98 |
+
// clang-format on
|
| 99 |
+
{};
|
| 100 |
+
|
| 101 |
+
// AreAllSame pairwise test.
|
| 102 |
+
template <typename T1, typename T2>
|
| 103 |
+
struct AreAllSame<T1, T2> : std::is_same<T1, T2> {};
|
| 104 |
+
|
| 105 |
+
// Convenience variable template for AreAllSame.
|
| 106 |
+
template <typename... Types>
|
| 107 |
+
constexpr bool AreAllSame_v = AreAllSame<Types...>::value;
|
| 108 |
+
|
| 109 |
+
// Determines the rank of a type. This allows to ensure that types passed as
|
| 110 |
+
// arguments are compatible to each other. The rank of Jet is determined by the
|
| 111 |
+
// dimensions of the dual part. The rank of a scalar is always 0.
|
| 112 |
+
// Non-specialized types default to a rank of -1.
|
| 113 |
+
template <typename T, typename E = void>
|
| 114 |
+
struct Rank : std::integral_constant<int, -1> {};
|
| 115 |
+
|
| 116 |
+
// The rank of a scalar is 0.
|
| 117 |
+
template <typename T>
|
| 118 |
+
struct Rank<T, std::enable_if_t<std::is_scalar<T>::value>>
|
| 119 |
+
: std::integral_constant<int, 0> {};
|
| 120 |
+
|
| 121 |
+
// The rank of a Jet is given by its dimensionality.
|
| 122 |
+
template <typename T, int N>
|
| 123 |
+
struct Rank<Jet<T, N>> : std::integral_constant<int, N> {};
|
| 124 |
+
|
| 125 |
+
// Convenience variable template for Rank.
|
| 126 |
+
template <typename T>
|
| 127 |
+
constexpr int Rank_v = Rank<T>::value;
|
| 128 |
+
|
| 129 |
+
// Constructs an integer sequence of ranks for each of the Types in the pack.
|
| 130 |
+
template <typename... Types>
|
| 131 |
+
using Ranks_t = std::integer_sequence<int, Rank_v<Types>...>;
|
| 132 |
+
|
| 133 |
+
// Returns the scalar part of a type. This overload acts as an identity.
|
| 134 |
+
template <typename T>
|
| 135 |
+
constexpr decltype(auto) AsScalar(T&& value) noexcept {
|
| 136 |
+
return std::forward<T>(value);
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
// Recursively unwraps the scalar part of a Jet until a non-Jet scalar type is
|
| 140 |
+
// encountered.
|
| 141 |
+
template <typename T, int N>
|
| 142 |
+
constexpr decltype(auto) AsScalar(const Jet<T, N>& value) noexcept(
|
| 143 |
+
noexcept(AsScalar(value.a))) {
|
| 144 |
+
return AsScalar(value.a);
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
} // namespace internal
|
| 148 |
+
|
| 149 |
+
// Type trait ensuring at least one of the types is a Jet,
|
| 150 |
+
// the underlying scalar types are the same and Jet dimensions match.
|
| 151 |
+
//
|
| 152 |
+
// The type trait can be further specialized if necessary.
|
| 153 |
+
//
|
| 154 |
+
// This trait is a candidate for a concept definition once C++20 features can
|
| 155 |
+
// be used.
|
| 156 |
+
template <typename... Types>
|
| 157 |
+
// clang-format off
|
| 158 |
+
struct CompatibleJetOperands : std::integral_constant
|
| 159 |
+
<
|
| 160 |
+
bool,
|
| 161 |
+
// At least one of the types is a Jet
|
| 162 |
+
internal::AreAnyJet_v<Types...> &&
|
| 163 |
+
// The underlying floating-point types are exactly the same
|
| 164 |
+
internal::AreAllSame_v<internal::UnderlyingScalar_t<Types>...> &&
|
| 165 |
+
// Non-zero ranks of types are equal
|
| 166 |
+
internal::IsEmptyOrAreAllEqual_v<internal::RemoveValue_t<internal::Ranks_t<Types...>, 0>>
|
| 167 |
+
>
|
| 168 |
+
// clang-format on
|
| 169 |
+
{};
|
| 170 |
+
|
| 171 |
+
// Single Jet operand is always compatible.
|
| 172 |
+
template <typename T, int N>
|
| 173 |
+
struct CompatibleJetOperands<Jet<T, N>> : std::true_type {};
|
| 174 |
+
|
| 175 |
+
// Single non-Jet operand is always incompatible.
|
| 176 |
+
template <typename T>
|
| 177 |
+
struct CompatibleJetOperands<T> : std::false_type {};
|
| 178 |
+
|
| 179 |
+
// Empty operands are always incompatible.
|
| 180 |
+
template <>
|
| 181 |
+
struct CompatibleJetOperands<> : std::false_type {};
|
| 182 |
+
|
| 183 |
+
// Convenience variable template ensuring at least one of the types is a Jet,
|
| 184 |
+
// the underlying scalar types are the same and Jet dimensions match.
|
| 185 |
+
//
|
| 186 |
+
// This trait is a candidate for a concept definition once C++20 features can
|
| 187 |
+
// be used.
|
| 188 |
+
template <typename... Types>
|
| 189 |
+
constexpr bool CompatibleJetOperands_v = CompatibleJetOperands<Types...>::value;
|
| 190 |
+
|
| 191 |
+
// Type trait ensuring at least one of the types is a Jet,
|
| 192 |
+
// the underlying scalar types are compatible among each other and Jet
|
| 193 |
+
// dimensions match.
|
| 194 |
+
//
|
| 195 |
+
// The type trait can be further specialized if necessary.
|
| 196 |
+
//
|
| 197 |
+
// This trait is a candidate for a concept definition once C++20 features can
|
| 198 |
+
// be used.
|
| 199 |
+
template <typename... Types>
|
| 200 |
+
// clang-format off
|
| 201 |
+
struct PromotableJetOperands : std::integral_constant
|
| 202 |
+
<
|
| 203 |
+
bool,
|
| 204 |
+
// Types can be compatible among each other
|
| 205 |
+
internal::AreAnyJet_v<Types...> &&
|
| 206 |
+
// Non-zero ranks of types are equal
|
| 207 |
+
internal::IsEmptyOrAreAllEqual_v<internal::RemoveValue_t<internal::Ranks_t<Types...>, 0>>
|
| 208 |
+
>
|
| 209 |
+
// clang-format on
|
| 210 |
+
{};
|
| 211 |
+
|
| 212 |
+
// Convenience variable template ensuring at least one of the types is a Jet,
|
| 213 |
+
// the underlying scalar types are compatible among each other and Jet
|
| 214 |
+
// dimensions match.
|
| 215 |
+
//
|
| 216 |
+
// This trait is a candidate for a concept definition once C++20 features can
|
| 217 |
+
// be used.
|
| 218 |
+
template <typename... Types>
|
| 219 |
+
constexpr bool PromotableJetOperands_v = PromotableJetOperands<Types...>::value;
|
| 220 |
+
|
| 221 |
+
} // namespace ceres
|
| 222 |
+
|
| 223 |
+
#endif // CERES_PUBLIC_INTERNAL_JET_TRAITS_H_
|
include/ceres/internal/line_parameterization.h
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2020 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: jodebo_beck@gmx.de (Johannes Beck)
|
| 30 |
+
//
|
| 31 |
+
|
| 32 |
+
#ifndef CERES_PUBLIC_INTERNAL_LINE_PARAMETERIZATION_H_
|
| 33 |
+
#define CERES_PUBLIC_INTERNAL_LINE_PARAMETERIZATION_H_
|
| 34 |
+
|
| 35 |
+
#include "householder_vector.h"
|
| 36 |
+
|
| 37 |
+
namespace ceres {
|
| 38 |
+
|
| 39 |
+
template <int AmbientSpaceDimension>
|
| 40 |
+
bool LineParameterization<AmbientSpaceDimension>::Plus(
|
| 41 |
+
const double* x_ptr,
|
| 42 |
+
const double* delta_ptr,
|
| 43 |
+
double* x_plus_delta_ptr) const {
|
| 44 |
+
// We seek a box plus operator of the form
|
| 45 |
+
//
|
| 46 |
+
// [o*, d*] = Plus([o, d], [delta_o, delta_d])
|
| 47 |
+
//
|
| 48 |
+
// where o is the origin point, d is the direction vector, delta_o is
|
| 49 |
+
// the delta of the origin point and delta_d the delta of the direction and
|
| 50 |
+
// o* and d* is the updated origin point and direction.
|
| 51 |
+
//
|
| 52 |
+
// We separate the Plus operator into the origin point and directional part
|
| 53 |
+
// d* = Plus_d(d, delta_d)
|
| 54 |
+
// o* = Plus_o(o, d, delta_o)
|
| 55 |
+
//
|
| 56 |
+
// The direction update function Plus_d is the same as for the homogeneous
|
| 57 |
+
// vector parameterization:
|
| 58 |
+
//
|
| 59 |
+
// d* = H_{v(d)} [0.5 sinc(0.5 |delta_d|) delta_d, cos(0.5 |delta_d|)]^T
|
| 60 |
+
//
|
| 61 |
+
// where H is the householder matrix
|
| 62 |
+
// H_{v} = I - (2 / |v|^2) v v^T
|
| 63 |
+
// and
|
| 64 |
+
// v(d) = d - sign(d_n) |d| e_n.
|
| 65 |
+
//
|
| 66 |
+
// The origin point update function Plus_o is defined as
|
| 67 |
+
//
|
| 68 |
+
// o* = o + H_{v(d)} [0.5 delta_o, 0]^T.
|
| 69 |
+
|
| 70 |
+
static constexpr int kDim = AmbientSpaceDimension;
|
| 71 |
+
using AmbientVector = Eigen::Matrix<double, kDim, 1>;
|
| 72 |
+
using AmbientVectorRef = Eigen::Map<Eigen::Matrix<double, kDim, 1>>;
|
| 73 |
+
using ConstAmbientVectorRef =
|
| 74 |
+
Eigen::Map<const Eigen::Matrix<double, kDim, 1>>;
|
| 75 |
+
using ConstTangentVectorRef =
|
| 76 |
+
Eigen::Map<const Eigen::Matrix<double, kDim - 1, 1>>;
|
| 77 |
+
|
| 78 |
+
ConstAmbientVectorRef o(x_ptr);
|
| 79 |
+
ConstAmbientVectorRef d(x_ptr + kDim);
|
| 80 |
+
|
| 81 |
+
ConstTangentVectorRef delta_o(delta_ptr);
|
| 82 |
+
ConstTangentVectorRef delta_d(delta_ptr + kDim - 1);
|
| 83 |
+
AmbientVectorRef o_plus_delta(x_plus_delta_ptr);
|
| 84 |
+
AmbientVectorRef d_plus_delta(x_plus_delta_ptr + kDim);
|
| 85 |
+
|
| 86 |
+
const double norm_delta_d = delta_d.norm();
|
| 87 |
+
|
| 88 |
+
o_plus_delta = o;
|
| 89 |
+
|
| 90 |
+
// Shortcut for zero delta direction.
|
| 91 |
+
if (norm_delta_d == 0.0) {
|
| 92 |
+
d_plus_delta = d;
|
| 93 |
+
|
| 94 |
+
if (delta_o.isZero(0.0)) {
|
| 95 |
+
return true;
|
| 96 |
+
}
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
// Calculate the householder transformation which is needed for f_d and f_o.
|
| 100 |
+
AmbientVector v;
|
| 101 |
+
double beta;
|
| 102 |
+
|
| 103 |
+
// NOTE: The explicit template arguments are needed here because
|
| 104 |
+
// ComputeHouseholderVector is templated and some versions of MSVC
|
| 105 |
+
// have trouble deducing the type of v automatically.
|
| 106 |
+
internal::ComputeHouseholderVector<ConstAmbientVectorRef, double, kDim>(
|
| 107 |
+
d, &v, &beta);
|
| 108 |
+
|
| 109 |
+
if (norm_delta_d != 0.0) {
|
| 110 |
+
// Map the delta from the minimum representation to the over parameterized
|
| 111 |
+
// homogeneous vector. See section A6.9.2 on page 624 of Hartley & Zisserman
|
| 112 |
+
// (2nd Edition) for a detailed description. Note there is a typo on Page
|
| 113 |
+
// 625, line 4 so check the book errata.
|
| 114 |
+
const double norm_delta_div_2 = 0.5 * norm_delta_d;
|
| 115 |
+
const double sin_delta_by_delta =
|
| 116 |
+
std::sin(norm_delta_div_2) / norm_delta_div_2;
|
| 117 |
+
|
| 118 |
+
// Apply the delta update to remain on the unit sphere. See section A6.9.3
|
| 119 |
+
// on page 625 of Hartley & Zisserman (2nd Edition) for a detailed
|
| 120 |
+
// description.
|
| 121 |
+
AmbientVector y;
|
| 122 |
+
y.template head<kDim - 1>() = 0.5 * sin_delta_by_delta * delta_d;
|
| 123 |
+
y[kDim - 1] = std::cos(norm_delta_div_2);
|
| 124 |
+
|
| 125 |
+
d_plus_delta = d.norm() * (y - v * (beta * (v.transpose() * y)));
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
// The null space is in the direction of the line, so the tangent space is
|
| 129 |
+
// perpendicular to the line direction. This is achieved by using the
|
| 130 |
+
// householder matrix of the direction and allow only movements
|
| 131 |
+
// perpendicular to e_n.
|
| 132 |
+
//
|
| 133 |
+
// The factor of 0.5 is used to be consistent with the line direction
|
| 134 |
+
// update.
|
| 135 |
+
AmbientVector y;
|
| 136 |
+
y << 0.5 * delta_o, 0;
|
| 137 |
+
o_plus_delta += y - v * (beta * (v.transpose() * y));
|
| 138 |
+
|
| 139 |
+
return true;
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
template <int AmbientSpaceDimension>
|
| 143 |
+
bool LineParameterization<AmbientSpaceDimension>::ComputeJacobian(
|
| 144 |
+
const double* x_ptr, double* jacobian_ptr) const {
|
| 145 |
+
static constexpr int kDim = AmbientSpaceDimension;
|
| 146 |
+
using AmbientVector = Eigen::Matrix<double, kDim, 1>;
|
| 147 |
+
using ConstAmbientVectorRef =
|
| 148 |
+
Eigen::Map<const Eigen::Matrix<double, kDim, 1>>;
|
| 149 |
+
using MatrixRef = Eigen::Map<
|
| 150 |
+
Eigen::Matrix<double, 2 * kDim, 2 * (kDim - 1), Eigen::RowMajor>>;
|
| 151 |
+
|
| 152 |
+
ConstAmbientVectorRef d(x_ptr + kDim);
|
| 153 |
+
MatrixRef jacobian(jacobian_ptr);
|
| 154 |
+
|
| 155 |
+
// Clear the Jacobian as only half of the matrix is not zero.
|
| 156 |
+
jacobian.setZero();
|
| 157 |
+
|
| 158 |
+
AmbientVector v;
|
| 159 |
+
double beta;
|
| 160 |
+
|
| 161 |
+
// NOTE: The explicit template arguments are needed here because
|
| 162 |
+
// ComputeHouseholderVector is templated and some versions of MSVC
|
| 163 |
+
// have trouble deducing the type of v automatically.
|
| 164 |
+
internal::ComputeHouseholderVector<ConstAmbientVectorRef, double, kDim>(
|
| 165 |
+
d, &v, &beta);
|
| 166 |
+
|
| 167 |
+
// The Jacobian is equal to J = 0.5 * H.leftCols(kDim - 1) where H is
|
| 168 |
+
// the Householder matrix (H = I - beta * v * v') for the origin point. For
|
| 169 |
+
// the line direction part the Jacobian is scaled by the norm of the
|
| 170 |
+
// direction.
|
| 171 |
+
for (int i = 0; i < kDim - 1; ++i) {
|
| 172 |
+
jacobian.block(0, i, kDim, 1) = -0.5 * beta * v(i) * v;
|
| 173 |
+
jacobian.col(i)(i) += 0.5;
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
jacobian.template block<kDim, kDim - 1>(kDim, kDim - 1) =
|
| 177 |
+
jacobian.template block<kDim, kDim - 1>(0, 0) * d.norm();
|
| 178 |
+
return true;
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
} // namespace ceres
|
| 182 |
+
|
| 183 |
+
#endif // CERES_PUBLIC_INTERNAL_LINE_PARAMETERIZATION_H_
|
include/ceres/internal/memory.h
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2017 The Abseil Authors.
|
| 2 |
+
//
|
| 3 |
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
// you may not use this file except in compliance with the License.
|
| 5 |
+
// You may obtain a copy of the License at
|
| 6 |
+
//
|
| 7 |
+
// https://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
//
|
| 9 |
+
// Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
// See the License for the specific language governing permissions and
|
| 13 |
+
// limitations under the License.
|
| 14 |
+
//
|
| 15 |
+
// -----------------------------------------------------------------------------
|
| 16 |
+
// File: memory.h
|
| 17 |
+
// -----------------------------------------------------------------------------
|
| 18 |
+
//
|
| 19 |
+
// This header file contains utility functions for managing the creation and
|
| 20 |
+
// conversion of smart pointers. This file is an extension to the C++
|
| 21 |
+
// standard <memory> library header file.
|
| 22 |
+
|
| 23 |
+
#ifndef CERES_PUBLIC_INTERNAL_MEMORY_H_
|
| 24 |
+
#define CERES_PUBLIC_INTERNAL_MEMORY_H_
|
| 25 |
+
|
| 26 |
+
#include <memory>
|
| 27 |
+
|
| 28 |
+
#ifdef CERES_HAVE_EXCEPTIONS
|
| 29 |
+
#define CERES_INTERNAL_TRY try
|
| 30 |
+
#define CERES_INTERNAL_CATCH_ANY catch (...)
|
| 31 |
+
#define CERES_INTERNAL_RETHROW \
|
| 32 |
+
do { \
|
| 33 |
+
throw; \
|
| 34 |
+
} while (false)
|
| 35 |
+
#else // CERES_HAVE_EXCEPTIONS
|
| 36 |
+
#define CERES_INTERNAL_TRY if (true)
|
| 37 |
+
#define CERES_INTERNAL_CATCH_ANY else if (false)
|
| 38 |
+
#define CERES_INTERNAL_RETHROW \
|
| 39 |
+
do { \
|
| 40 |
+
} while (false)
|
| 41 |
+
#endif // CERES_HAVE_EXCEPTIONS
|
| 42 |
+
|
| 43 |
+
namespace ceres {
|
| 44 |
+
namespace internal {
|
| 45 |
+
|
| 46 |
+
template <typename Allocator, typename Iterator, typename... Args>
|
| 47 |
+
void ConstructRange(Allocator& alloc,
|
| 48 |
+
Iterator first,
|
| 49 |
+
Iterator last,
|
| 50 |
+
const Args&... args) {
|
| 51 |
+
for (Iterator cur = first; cur != last; ++cur) {
|
| 52 |
+
CERES_INTERNAL_TRY {
|
| 53 |
+
std::allocator_traits<Allocator>::construct(
|
| 54 |
+
alloc, std::addressof(*cur), args...);
|
| 55 |
+
}
|
| 56 |
+
CERES_INTERNAL_CATCH_ANY {
|
| 57 |
+
while (cur != first) {
|
| 58 |
+
--cur;
|
| 59 |
+
std::allocator_traits<Allocator>::destroy(alloc, std::addressof(*cur));
|
| 60 |
+
}
|
| 61 |
+
CERES_INTERNAL_RETHROW;
|
| 62 |
+
}
|
| 63 |
+
}
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
template <typename Allocator, typename Iterator, typename InputIterator>
|
| 67 |
+
void CopyRange(Allocator& alloc,
|
| 68 |
+
Iterator destination,
|
| 69 |
+
InputIterator first,
|
| 70 |
+
InputIterator last) {
|
| 71 |
+
for (Iterator cur = destination; first != last;
|
| 72 |
+
static_cast<void>(++cur), static_cast<void>(++first)) {
|
| 73 |
+
CERES_INTERNAL_TRY {
|
| 74 |
+
std::allocator_traits<Allocator>::construct(
|
| 75 |
+
alloc, std::addressof(*cur), *first);
|
| 76 |
+
}
|
| 77 |
+
CERES_INTERNAL_CATCH_ANY {
|
| 78 |
+
while (cur != destination) {
|
| 79 |
+
--cur;
|
| 80 |
+
std::allocator_traits<Allocator>::destroy(alloc, std::addressof(*cur));
|
| 81 |
+
}
|
| 82 |
+
CERES_INTERNAL_RETHROW;
|
| 83 |
+
}
|
| 84 |
+
}
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
} // namespace internal
|
| 88 |
+
} // namespace ceres
|
| 89 |
+
|
| 90 |
+
#endif // CERES_PUBLIC_INTERNAL_MEMORY_H_
|
include/ceres/internal/numeric_diff.h
ADDED
|
@@ -0,0 +1,508 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2015 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: sameeragarwal@google.com (Sameer Agarwal)
|
| 30 |
+
// mierle@gmail.com (Keir Mierle)
|
| 31 |
+
// tbennun@gmail.com (Tal Ben-Nun)
|
| 32 |
+
//
|
| 33 |
+
// Finite differencing routines used by NumericDiffCostFunction.
|
| 34 |
+
|
| 35 |
+
#ifndef CERES_PUBLIC_INTERNAL_NUMERIC_DIFF_H_
|
| 36 |
+
#define CERES_PUBLIC_INTERNAL_NUMERIC_DIFF_H_
|
| 37 |
+
|
| 38 |
+
#include <cstring>
|
| 39 |
+
#include <utility>
|
| 40 |
+
|
| 41 |
+
#include "Eigen/Dense"
|
| 42 |
+
#include "Eigen/StdVector"
|
| 43 |
+
#include "ceres/cost_function.h"
|
| 44 |
+
#include "ceres/internal/fixed_array.h"
|
| 45 |
+
#include "ceres/internal/variadic_evaluate.h"
|
| 46 |
+
#include "ceres/numeric_diff_options.h"
|
| 47 |
+
#include "ceres/types.h"
|
| 48 |
+
#include "glog/logging.h"
|
| 49 |
+
|
| 50 |
+
namespace ceres {
|
| 51 |
+
namespace internal {
|
| 52 |
+
|
| 53 |
+
// This is split from the main class because C++ doesn't allow partial template
|
| 54 |
+
// specializations for member functions. The alternative is to repeat the main
|
| 55 |
+
// class for differing numbers of parameters, which is also unfortunate.
|
| 56 |
+
template <typename CostFunctor,
|
| 57 |
+
NumericDiffMethodType kMethod,
|
| 58 |
+
int kNumResiduals,
|
| 59 |
+
typename ParameterDims,
|
| 60 |
+
int kParameterBlock,
|
| 61 |
+
int kParameterBlockSize>
|
| 62 |
+
struct NumericDiff {
|
| 63 |
+
// Mutates parameters but must restore them before return.
|
| 64 |
+
static bool EvaluateJacobianForParameterBlock(
|
| 65 |
+
const CostFunctor* functor,
|
| 66 |
+
const double* residuals_at_eval_point,
|
| 67 |
+
const NumericDiffOptions& options,
|
| 68 |
+
int num_residuals,
|
| 69 |
+
int parameter_block_index,
|
| 70 |
+
int parameter_block_size,
|
| 71 |
+
double** parameters,
|
| 72 |
+
double* jacobian) {
|
| 73 |
+
using Eigen::ColMajor;
|
| 74 |
+
using Eigen::Map;
|
| 75 |
+
using Eigen::Matrix;
|
| 76 |
+
using Eigen::RowMajor;
|
| 77 |
+
|
| 78 |
+
DCHECK(jacobian);
|
| 79 |
+
|
| 80 |
+
const int num_residuals_internal =
|
| 81 |
+
(kNumResiduals != ceres::DYNAMIC ? kNumResiduals : num_residuals);
|
| 82 |
+
const int parameter_block_index_internal =
|
| 83 |
+
(kParameterBlock != ceres::DYNAMIC ? kParameterBlock
|
| 84 |
+
: parameter_block_index);
|
| 85 |
+
const int parameter_block_size_internal =
|
| 86 |
+
(kParameterBlockSize != ceres::DYNAMIC ? kParameterBlockSize
|
| 87 |
+
: parameter_block_size);
|
| 88 |
+
|
| 89 |
+
using ResidualVector = Matrix<double, kNumResiduals, 1>;
|
| 90 |
+
using ParameterVector = Matrix<double, kParameterBlockSize, 1>;
|
| 91 |
+
|
| 92 |
+
// The convoluted reasoning for choosing the Row/Column major
|
| 93 |
+
// ordering of the matrix is an artifact of the restrictions in
|
| 94 |
+
// Eigen that prevent it from creating RowMajor matrices with a
|
| 95 |
+
// single column. In these cases, we ask for a ColMajor matrix.
|
| 96 |
+
using JacobianMatrix =
|
| 97 |
+
Matrix<double,
|
| 98 |
+
kNumResiduals,
|
| 99 |
+
kParameterBlockSize,
|
| 100 |
+
(kParameterBlockSize == 1) ? ColMajor : RowMajor>;
|
| 101 |
+
|
| 102 |
+
Map<JacobianMatrix> parameter_jacobian(
|
| 103 |
+
jacobian, num_residuals_internal, parameter_block_size_internal);
|
| 104 |
+
|
| 105 |
+
Map<ParameterVector> x_plus_delta(
|
| 106 |
+
parameters[parameter_block_index_internal],
|
| 107 |
+
parameter_block_size_internal);
|
| 108 |
+
ParameterVector x(x_plus_delta);
|
| 109 |
+
ParameterVector step_size =
|
| 110 |
+
x.array().abs() * ((kMethod == RIDDERS)
|
| 111 |
+
? options.ridders_relative_initial_step_size
|
| 112 |
+
: options.relative_step_size);
|
| 113 |
+
|
| 114 |
+
// It is not a good idea to make the step size arbitrarily
|
| 115 |
+
// small. This will lead to problems with round off and numerical
|
| 116 |
+
// instability when dividing by the step size. The general
|
| 117 |
+
// recommendation is to not go down below sqrt(epsilon).
|
| 118 |
+
double min_step_size = std::sqrt(std::numeric_limits<double>::epsilon());
|
| 119 |
+
|
| 120 |
+
// For Ridders' method, the initial step size is required to be large,
|
| 121 |
+
// thus ridders_relative_initial_step_size is used.
|
| 122 |
+
if (kMethod == RIDDERS) {
|
| 123 |
+
min_step_size =
|
| 124 |
+
(std::max)(min_step_size, options.ridders_relative_initial_step_size);
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
// For each parameter in the parameter block, use finite differences to
|
| 128 |
+
// compute the derivative for that parameter.
|
| 129 |
+
FixedArray<double> temp_residual_array(num_residuals_internal);
|
| 130 |
+
FixedArray<double> residual_array(num_residuals_internal);
|
| 131 |
+
Map<ResidualVector> residuals(residual_array.data(),
|
| 132 |
+
num_residuals_internal);
|
| 133 |
+
|
| 134 |
+
for (int j = 0; j < parameter_block_size_internal; ++j) {
|
| 135 |
+
const double delta = (std::max)(min_step_size, step_size(j));
|
| 136 |
+
|
| 137 |
+
if (kMethod == RIDDERS) {
|
| 138 |
+
if (!EvaluateRiddersJacobianColumn(functor,
|
| 139 |
+
j,
|
| 140 |
+
delta,
|
| 141 |
+
options,
|
| 142 |
+
num_residuals_internal,
|
| 143 |
+
parameter_block_size_internal,
|
| 144 |
+
x.data(),
|
| 145 |
+
residuals_at_eval_point,
|
| 146 |
+
parameters,
|
| 147 |
+
x_plus_delta.data(),
|
| 148 |
+
temp_residual_array.data(),
|
| 149 |
+
residual_array.data())) {
|
| 150 |
+
return false;
|
| 151 |
+
}
|
| 152 |
+
} else {
|
| 153 |
+
if (!EvaluateJacobianColumn(functor,
|
| 154 |
+
j,
|
| 155 |
+
delta,
|
| 156 |
+
num_residuals_internal,
|
| 157 |
+
parameter_block_size_internal,
|
| 158 |
+
x.data(),
|
| 159 |
+
residuals_at_eval_point,
|
| 160 |
+
parameters,
|
| 161 |
+
x_plus_delta.data(),
|
| 162 |
+
temp_residual_array.data(),
|
| 163 |
+
residual_array.data())) {
|
| 164 |
+
return false;
|
| 165 |
+
}
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
parameter_jacobian.col(j).matrix() = residuals;
|
| 169 |
+
}
|
| 170 |
+
return true;
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
static bool EvaluateJacobianColumn(const CostFunctor* functor,
|
| 174 |
+
int parameter_index,
|
| 175 |
+
double delta,
|
| 176 |
+
int num_residuals,
|
| 177 |
+
int parameter_block_size,
|
| 178 |
+
const double* x_ptr,
|
| 179 |
+
const double* residuals_at_eval_point,
|
| 180 |
+
double** parameters,
|
| 181 |
+
double* x_plus_delta_ptr,
|
| 182 |
+
double* temp_residuals_ptr,
|
| 183 |
+
double* residuals_ptr) {
|
| 184 |
+
using Eigen::Map;
|
| 185 |
+
using Eigen::Matrix;
|
| 186 |
+
|
| 187 |
+
using ResidualVector = Matrix<double, kNumResiduals, 1>;
|
| 188 |
+
using ParameterVector = Matrix<double, kParameterBlockSize, 1>;
|
| 189 |
+
|
| 190 |
+
Map<const ParameterVector> x(x_ptr, parameter_block_size);
|
| 191 |
+
Map<ParameterVector> x_plus_delta(x_plus_delta_ptr, parameter_block_size);
|
| 192 |
+
|
| 193 |
+
Map<ResidualVector> residuals(residuals_ptr, num_residuals);
|
| 194 |
+
Map<ResidualVector> temp_residuals(temp_residuals_ptr, num_residuals);
|
| 195 |
+
|
| 196 |
+
// Mutate 1 element at a time and then restore.
|
| 197 |
+
x_plus_delta(parameter_index) = x(parameter_index) + delta;
|
| 198 |
+
|
| 199 |
+
if (!VariadicEvaluate<ParameterDims>(
|
| 200 |
+
*functor, parameters, residuals.data())) {
|
| 201 |
+
return false;
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
// Compute this column of the jacobian in 3 steps:
|
| 205 |
+
// 1. Store residuals for the forward part.
|
| 206 |
+
// 2. Subtract residuals for the backward (or 0) part.
|
| 207 |
+
// 3. Divide out the run.
|
| 208 |
+
double one_over_delta = 1.0 / delta;
|
| 209 |
+
if (kMethod == CENTRAL || kMethod == RIDDERS) {
|
| 210 |
+
// Compute the function on the other side of x(parameter_index).
|
| 211 |
+
x_plus_delta(parameter_index) = x(parameter_index) - delta;
|
| 212 |
+
|
| 213 |
+
if (!VariadicEvaluate<ParameterDims>(
|
| 214 |
+
*functor, parameters, temp_residuals.data())) {
|
| 215 |
+
return false;
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
residuals -= temp_residuals;
|
| 219 |
+
one_over_delta /= 2;
|
| 220 |
+
} else {
|
| 221 |
+
// Forward difference only; reuse existing residuals evaluation.
|
| 222 |
+
residuals -=
|
| 223 |
+
Map<const ResidualVector>(residuals_at_eval_point, num_residuals);
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
// Restore x_plus_delta.
|
| 227 |
+
x_plus_delta(parameter_index) = x(parameter_index);
|
| 228 |
+
|
| 229 |
+
// Divide out the run to get slope.
|
| 230 |
+
residuals *= one_over_delta;
|
| 231 |
+
|
| 232 |
+
return true;
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
// This numeric difference implementation uses adaptive differentiation
|
| 236 |
+
// on the parameters to obtain the Jacobian matrix. The adaptive algorithm
|
| 237 |
+
// is based on Ridders' method for adaptive differentiation, which creates
|
| 238 |
+
// a Romberg tableau from varying step sizes and extrapolates the
|
| 239 |
+
// intermediate results to obtain the current computational error.
|
| 240 |
+
//
|
| 241 |
+
// References:
|
| 242 |
+
// C.J.F. Ridders, Accurate computation of F'(x) and F'(x) F"(x), Advances
|
| 243 |
+
// in Engineering Software (1978), Volume 4, Issue 2, April 1982,
|
| 244 |
+
// Pages 75-76, ISSN 0141-1195,
|
| 245 |
+
// http://dx.doi.org/10.1016/S0141-1195(82)80057-0.
|
| 246 |
+
static bool EvaluateRiddersJacobianColumn(
|
| 247 |
+
const CostFunctor* functor,
|
| 248 |
+
int parameter_index,
|
| 249 |
+
double delta,
|
| 250 |
+
const NumericDiffOptions& options,
|
| 251 |
+
int num_residuals,
|
| 252 |
+
int parameter_block_size,
|
| 253 |
+
const double* x_ptr,
|
| 254 |
+
const double* residuals_at_eval_point,
|
| 255 |
+
double** parameters,
|
| 256 |
+
double* x_plus_delta_ptr,
|
| 257 |
+
double* temp_residuals_ptr,
|
| 258 |
+
double* residuals_ptr) {
|
| 259 |
+
using Eigen::aligned_allocator;
|
| 260 |
+
using Eigen::Map;
|
| 261 |
+
using Eigen::Matrix;
|
| 262 |
+
|
| 263 |
+
using ResidualVector = Matrix<double, kNumResiduals, 1>;
|
| 264 |
+
using ResidualCandidateMatrix =
|
| 265 |
+
Matrix<double, kNumResiduals, Eigen::Dynamic>;
|
| 266 |
+
using ParameterVector = Matrix<double, kParameterBlockSize, 1>;
|
| 267 |
+
|
| 268 |
+
Map<const ParameterVector> x(x_ptr, parameter_block_size);
|
| 269 |
+
Map<ParameterVector> x_plus_delta(x_plus_delta_ptr, parameter_block_size);
|
| 270 |
+
|
| 271 |
+
Map<ResidualVector> residuals(residuals_ptr, num_residuals);
|
| 272 |
+
Map<ResidualVector> temp_residuals(temp_residuals_ptr, num_residuals);
|
| 273 |
+
|
| 274 |
+
// In order for the algorithm to converge, the step size should be
|
| 275 |
+
// initialized to a value that is large enough to produce a significant
|
| 276 |
+
// change in the function.
|
| 277 |
+
// As the derivative is estimated, the step size decreases.
|
| 278 |
+
// By default, the step sizes are chosen so that the middle column
|
| 279 |
+
// of the Romberg tableau uses the input delta.
|
| 280 |
+
double current_step_size =
|
| 281 |
+
delta * pow(options.ridders_step_shrink_factor,
|
| 282 |
+
options.max_num_ridders_extrapolations / 2);
|
| 283 |
+
|
| 284 |
+
// Double-buffering temporary differential candidate vectors
|
| 285 |
+
// from previous step size.
|
| 286 |
+
ResidualCandidateMatrix stepsize_candidates_a(
|
| 287 |
+
num_residuals, options.max_num_ridders_extrapolations);
|
| 288 |
+
ResidualCandidateMatrix stepsize_candidates_b(
|
| 289 |
+
num_residuals, options.max_num_ridders_extrapolations);
|
| 290 |
+
ResidualCandidateMatrix* current_candidates = &stepsize_candidates_a;
|
| 291 |
+
ResidualCandidateMatrix* previous_candidates = &stepsize_candidates_b;
|
| 292 |
+
|
| 293 |
+
// Represents the computational error of the derivative. This variable is
|
| 294 |
+
// initially set to a large value, and is set to the difference between
|
| 295 |
+
// current and previous finite difference extrapolations.
|
| 296 |
+
// norm_error is supposed to decrease as the finite difference tableau
|
| 297 |
+
// generation progresses, serving both as an estimate for differentiation
|
| 298 |
+
// error and as a measure of differentiation numerical stability.
|
| 299 |
+
double norm_error = (std::numeric_limits<double>::max)();
|
| 300 |
+
|
| 301 |
+
// Loop over decreasing step sizes until:
|
| 302 |
+
// 1. Error is smaller than a given value (ridders_epsilon),
|
| 303 |
+
// 2. Maximal order of extrapolation reached, or
|
| 304 |
+
// 3. Extrapolation becomes numerically unstable.
|
| 305 |
+
for (int i = 0; i < options.max_num_ridders_extrapolations; ++i) {
|
| 306 |
+
// Compute the numerical derivative at this step size.
|
| 307 |
+
if (!EvaluateJacobianColumn(functor,
|
| 308 |
+
parameter_index,
|
| 309 |
+
current_step_size,
|
| 310 |
+
num_residuals,
|
| 311 |
+
parameter_block_size,
|
| 312 |
+
x.data(),
|
| 313 |
+
residuals_at_eval_point,
|
| 314 |
+
parameters,
|
| 315 |
+
x_plus_delta.data(),
|
| 316 |
+
temp_residuals.data(),
|
| 317 |
+
current_candidates->col(0).data())) {
|
| 318 |
+
// Something went wrong; bail.
|
| 319 |
+
return false;
|
| 320 |
+
}
|
| 321 |
+
|
| 322 |
+
// Store initial results.
|
| 323 |
+
if (i == 0) {
|
| 324 |
+
residuals = current_candidates->col(0);
|
| 325 |
+
}
|
| 326 |
+
|
| 327 |
+
// Shrink differentiation step size.
|
| 328 |
+
current_step_size /= options.ridders_step_shrink_factor;
|
| 329 |
+
|
| 330 |
+
// Extrapolation factor for Richardson acceleration method (see below).
|
| 331 |
+
double richardson_factor = options.ridders_step_shrink_factor *
|
| 332 |
+
options.ridders_step_shrink_factor;
|
| 333 |
+
for (int k = 1; k <= i; ++k) {
|
| 334 |
+
// Extrapolate the various orders of finite differences using
|
| 335 |
+
// the Richardson acceleration method.
|
| 336 |
+
current_candidates->col(k) =
|
| 337 |
+
(richardson_factor * current_candidates->col(k - 1) -
|
| 338 |
+
previous_candidates->col(k - 1)) /
|
| 339 |
+
(richardson_factor - 1.0);
|
| 340 |
+
|
| 341 |
+
richardson_factor *= options.ridders_step_shrink_factor *
|
| 342 |
+
options.ridders_step_shrink_factor;
|
| 343 |
+
|
| 344 |
+
// Compute the difference between the previous value and the current.
|
| 345 |
+
double candidate_error = (std::max)(
|
| 346 |
+
(current_candidates->col(k) - current_candidates->col(k - 1))
|
| 347 |
+
.norm(),
|
| 348 |
+
(current_candidates->col(k) - previous_candidates->col(k - 1))
|
| 349 |
+
.norm());
|
| 350 |
+
|
| 351 |
+
// If the error has decreased, update results.
|
| 352 |
+
if (candidate_error <= norm_error) {
|
| 353 |
+
norm_error = candidate_error;
|
| 354 |
+
residuals = current_candidates->col(k);
|
| 355 |
+
|
| 356 |
+
// If the error is small enough, stop.
|
| 357 |
+
if (norm_error < options.ridders_epsilon) {
|
| 358 |
+
break;
|
| 359 |
+
}
|
| 360 |
+
}
|
| 361 |
+
}
|
| 362 |
+
|
| 363 |
+
// After breaking out of the inner loop, declare convergence.
|
| 364 |
+
if (norm_error < options.ridders_epsilon) {
|
| 365 |
+
break;
|
| 366 |
+
}
|
| 367 |
+
|
| 368 |
+
// Check to see if the current gradient estimate is numerically unstable.
|
| 369 |
+
// If so, bail out and return the last stable result.
|
| 370 |
+
if (i > 0) {
|
| 371 |
+
double tableau_error =
|
| 372 |
+
(current_candidates->col(i) - previous_candidates->col(i - 1))
|
| 373 |
+
.norm();
|
| 374 |
+
|
| 375 |
+
// Compare current error to the chosen candidate's error.
|
| 376 |
+
if (tableau_error >= 2 * norm_error) {
|
| 377 |
+
break;
|
| 378 |
+
}
|
| 379 |
+
}
|
| 380 |
+
|
| 381 |
+
std::swap(current_candidates, previous_candidates);
|
| 382 |
+
}
|
| 383 |
+
return true;
|
| 384 |
+
}
|
| 385 |
+
};
|
| 386 |
+
|
| 387 |
+
// This function calls NumericDiff<...>::EvaluateJacobianForParameterBlock for
|
| 388 |
+
// each parameter block.
|
| 389 |
+
//
|
| 390 |
+
// Example:
|
| 391 |
+
// A call to
|
| 392 |
+
// EvaluateJacobianForParameterBlocks<StaticParameterDims<2, 3>>(
|
| 393 |
+
// functor,
|
| 394 |
+
// residuals_at_eval_point,
|
| 395 |
+
// options,
|
| 396 |
+
// num_residuals,
|
| 397 |
+
// parameters,
|
| 398 |
+
// jacobians);
|
| 399 |
+
// will result in the following calls to
|
| 400 |
+
// NumericDiff<...>::EvaluateJacobianForParameterBlock:
|
| 401 |
+
//
|
| 402 |
+
// if (jacobians[0] != nullptr) {
|
| 403 |
+
// if (!NumericDiff<
|
| 404 |
+
// CostFunctor,
|
| 405 |
+
// method,
|
| 406 |
+
// kNumResiduals,
|
| 407 |
+
// StaticParameterDims<2, 3>,
|
| 408 |
+
// 0,
|
| 409 |
+
// 2>::EvaluateJacobianForParameterBlock(functor,
|
| 410 |
+
// residuals_at_eval_point,
|
| 411 |
+
// options,
|
| 412 |
+
// num_residuals,
|
| 413 |
+
// 0,
|
| 414 |
+
// 2,
|
| 415 |
+
// parameters,
|
| 416 |
+
// jacobians[0])) {
|
| 417 |
+
// return false;
|
| 418 |
+
// }
|
| 419 |
+
// }
|
| 420 |
+
// if (jacobians[1] != nullptr) {
|
| 421 |
+
// if (!NumericDiff<
|
| 422 |
+
// CostFunctor,
|
| 423 |
+
// method,
|
| 424 |
+
// kNumResiduals,
|
| 425 |
+
// StaticParameterDims<2, 3>,
|
| 426 |
+
// 1,
|
| 427 |
+
// 3>::EvaluateJacobianForParameterBlock(functor,
|
| 428 |
+
// residuals_at_eval_point,
|
| 429 |
+
// options,
|
| 430 |
+
// num_residuals,
|
| 431 |
+
// 1,
|
| 432 |
+
// 3,
|
| 433 |
+
// parameters,
|
| 434 |
+
// jacobians[1])) {
|
| 435 |
+
// return false;
|
| 436 |
+
// }
|
| 437 |
+
// }
|
| 438 |
+
template <typename ParameterDims,
|
| 439 |
+
typename Parameters = typename ParameterDims::Parameters,
|
| 440 |
+
int ParameterIdx = 0>
|
| 441 |
+
struct EvaluateJacobianForParameterBlocks;
|
| 442 |
+
|
| 443 |
+
template <typename ParameterDims, int N, int... Ns, int ParameterIdx>
|
| 444 |
+
struct EvaluateJacobianForParameterBlocks<ParameterDims,
|
| 445 |
+
std::integer_sequence<int, N, Ns...>,
|
| 446 |
+
ParameterIdx> {
|
| 447 |
+
template <NumericDiffMethodType method,
|
| 448 |
+
int kNumResiduals,
|
| 449 |
+
typename CostFunctor>
|
| 450 |
+
static bool Apply(const CostFunctor* functor,
|
| 451 |
+
const double* residuals_at_eval_point,
|
| 452 |
+
const NumericDiffOptions& options,
|
| 453 |
+
int num_residuals,
|
| 454 |
+
double** parameters,
|
| 455 |
+
double** jacobians) {
|
| 456 |
+
if (jacobians[ParameterIdx] != nullptr) {
|
| 457 |
+
if (!NumericDiff<
|
| 458 |
+
CostFunctor,
|
| 459 |
+
method,
|
| 460 |
+
kNumResiduals,
|
| 461 |
+
ParameterDims,
|
| 462 |
+
ParameterIdx,
|
| 463 |
+
N>::EvaluateJacobianForParameterBlock(functor,
|
| 464 |
+
residuals_at_eval_point,
|
| 465 |
+
options,
|
| 466 |
+
num_residuals,
|
| 467 |
+
ParameterIdx,
|
| 468 |
+
N,
|
| 469 |
+
parameters,
|
| 470 |
+
jacobians[ParameterIdx])) {
|
| 471 |
+
return false;
|
| 472 |
+
}
|
| 473 |
+
}
|
| 474 |
+
|
| 475 |
+
return EvaluateJacobianForParameterBlocks<ParameterDims,
|
| 476 |
+
std::integer_sequence<int, Ns...>,
|
| 477 |
+
ParameterIdx + 1>::
|
| 478 |
+
template Apply<method, kNumResiduals>(functor,
|
| 479 |
+
residuals_at_eval_point,
|
| 480 |
+
options,
|
| 481 |
+
num_residuals,
|
| 482 |
+
parameters,
|
| 483 |
+
jacobians);
|
| 484 |
+
}
|
| 485 |
+
};
|
| 486 |
+
|
| 487 |
+
// End of 'recursion'. Nothing more to do.
|
| 488 |
+
template <typename ParameterDims, int ParameterIdx>
|
| 489 |
+
struct EvaluateJacobianForParameterBlocks<ParameterDims,
|
| 490 |
+
std::integer_sequence<int>,
|
| 491 |
+
ParameterIdx> {
|
| 492 |
+
template <NumericDiffMethodType method,
|
| 493 |
+
int kNumResiduals,
|
| 494 |
+
typename CostFunctor>
|
| 495 |
+
static bool Apply(const CostFunctor* /* NOT USED*/,
|
| 496 |
+
const double* /* NOT USED*/,
|
| 497 |
+
const NumericDiffOptions& /* NOT USED*/,
|
| 498 |
+
int /* NOT USED*/,
|
| 499 |
+
double** /* NOT USED*/,
|
| 500 |
+
double** /* NOT USED*/) {
|
| 501 |
+
return true;
|
| 502 |
+
}
|
| 503 |
+
};
|
| 504 |
+
|
| 505 |
+
} // namespace internal
|
| 506 |
+
} // namespace ceres
|
| 507 |
+
|
| 508 |
+
#endif // CERES_PUBLIC_INTERNAL_NUMERIC_DIFF_H_
|
include/ceres/internal/parameter_dims.h
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2018 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: jodebo_beck@gmx.de (Johannes Beck)
|
| 30 |
+
|
| 31 |
+
#ifndef CERES_PUBLIC_INTERNAL_PARAMETER_DIMS_H_
|
| 32 |
+
#define CERES_PUBLIC_INTERNAL_PARAMETER_DIMS_H_
|
| 33 |
+
|
| 34 |
+
#include <array>
|
| 35 |
+
#include <utility>
|
| 36 |
+
|
| 37 |
+
#include "ceres/internal/integer_sequence_algorithm.h"
|
| 38 |
+
|
| 39 |
+
namespace ceres {
|
| 40 |
+
namespace internal {
|
| 41 |
+
|
| 42 |
+
// Checks, whether the given parameter block sizes are valid. Valid means every
|
| 43 |
+
// dimension is bigger than zero.
|
| 44 |
+
constexpr bool IsValidParameterDimensionSequence(std::integer_sequence<int>) {
|
| 45 |
+
return true;
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
template <int N, int... Ts>
|
| 49 |
+
constexpr bool IsValidParameterDimensionSequence(
|
| 50 |
+
std::integer_sequence<int, N, Ts...>) {
|
| 51 |
+
return (N <= 0) ? false
|
| 52 |
+
: IsValidParameterDimensionSequence(
|
| 53 |
+
std::integer_sequence<int, Ts...>());
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
// Helper class that represents the parameter dimensions. The parameter
|
| 57 |
+
// dimensions are either dynamic or the sizes are known at compile time. It is
|
| 58 |
+
// used to pass parameter block dimensions around (e.g. between functions or
|
| 59 |
+
// classes).
|
| 60 |
+
//
|
| 61 |
+
// As an example if one have three parameter blocks with dimensions (2, 4, 1),
|
| 62 |
+
// one would use 'StaticParameterDims<2, 4, 1>' which is a synonym for
|
| 63 |
+
// 'ParameterDims<false, 2, 4, 1>'.
|
| 64 |
+
// For dynamic parameter dims, one would just use 'DynamicParameterDims', which
|
| 65 |
+
// is a synonym for 'ParameterDims<true>'.
|
| 66 |
+
template <bool IsDynamic, int... Ns>
|
| 67 |
+
class ParameterDims {
|
| 68 |
+
public:
|
| 69 |
+
using Parameters = std::integer_sequence<int, Ns...>;
|
| 70 |
+
|
| 71 |
+
// The parameter dimensions are only valid if all parameter block dimensions
|
| 72 |
+
// are greater than zero.
|
| 73 |
+
static constexpr bool kIsValid =
|
| 74 |
+
IsValidParameterDimensionSequence(Parameters());
|
| 75 |
+
static_assert(kIsValid,
|
| 76 |
+
"Invalid parameter block dimension detected. Each parameter "
|
| 77 |
+
"block dimension must be bigger than zero.");
|
| 78 |
+
|
| 79 |
+
static constexpr bool kIsDynamic = IsDynamic;
|
| 80 |
+
static constexpr int kNumParameterBlocks = sizeof...(Ns);
|
| 81 |
+
static_assert(kIsDynamic || kNumParameterBlocks > 0,
|
| 82 |
+
"At least one parameter block must be specified.");
|
| 83 |
+
|
| 84 |
+
static constexpr int kNumParameters =
|
| 85 |
+
Sum<std::integer_sequence<int, Ns...>>::Value;
|
| 86 |
+
|
| 87 |
+
static constexpr int GetDim(int dim) { return params_[dim]; }
|
| 88 |
+
|
| 89 |
+
// If one has all parameters packed into a single array this function unpacks
|
| 90 |
+
// the parameters.
|
| 91 |
+
template <typename T>
|
| 92 |
+
static inline std::array<T*, kNumParameterBlocks> GetUnpackedParameters(
|
| 93 |
+
T* ptr) {
|
| 94 |
+
using Offsets = ExclusiveScan<Parameters>;
|
| 95 |
+
return GetUnpackedParameters(ptr, Offsets());
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
private:
|
| 99 |
+
template <typename T, int... Indices>
|
| 100 |
+
static inline std::array<T*, kNumParameterBlocks> GetUnpackedParameters(
|
| 101 |
+
T* ptr, std::integer_sequence<int, Indices...>) {
|
| 102 |
+
return std::array<T*, kNumParameterBlocks>{{ptr + Indices...}};
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
static constexpr std::array<int, kNumParameterBlocks> params_{Ns...};
|
| 106 |
+
};
|
| 107 |
+
|
| 108 |
+
// Even static constexpr member variables needs to be defined (not only
|
| 109 |
+
// declared). As the ParameterDims class is tempalted this definition must
|
| 110 |
+
// be in the header file.
|
| 111 |
+
template <bool IsDynamic, int... Ns>
|
| 112 |
+
constexpr std::array<int, ParameterDims<IsDynamic, Ns...>::kNumParameterBlocks>
|
| 113 |
+
ParameterDims<IsDynamic, Ns...>::params_;
|
| 114 |
+
|
| 115 |
+
// Using declarations for static and dynamic parameter dims. This makes client
|
| 116 |
+
// code easier to read.
|
| 117 |
+
template <int... Ns>
|
| 118 |
+
using StaticParameterDims = ParameterDims<false, Ns...>;
|
| 119 |
+
using DynamicParameterDims = ParameterDims<true>;
|
| 120 |
+
|
| 121 |
+
} // namespace internal
|
| 122 |
+
} // namespace ceres
|
| 123 |
+
|
| 124 |
+
#endif // CERES_PUBLIC_INTERNAL_PARAMETER_DIMS_H_
|
include/ceres/internal/port.h
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2022 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: keir@google.com (Keir Mierle)
|
| 30 |
+
|
| 31 |
+
#ifndef CERES_PUBLIC_INTERNAL_PORT_H_
|
| 32 |
+
#define CERES_PUBLIC_INTERNAL_PORT_H_
|
| 33 |
+
|
| 34 |
+
// A macro to mark a function/variable/class as deprecated.
|
| 35 |
+
// We use compiler specific attributes rather than the c++
|
| 36 |
+
// attribute because they do not mix well with each other.
|
| 37 |
+
#if defined(_MSC_VER)
|
| 38 |
+
#define CERES_DEPRECATED_WITH_MSG(message) __declspec(deprecated(message))
|
| 39 |
+
#elif defined(__GNUC__)
|
| 40 |
+
#define CERES_DEPRECATED_WITH_MSG(message) __attribute__((deprecated(message)))
|
| 41 |
+
#else
|
| 42 |
+
// In the worst case fall back to c++ attribute.
|
| 43 |
+
#define CERES_DEPRECATED_WITH_MSG(message) [[deprecated(message)]]
|
| 44 |
+
#endif
|
| 45 |
+
|
| 46 |
+
#ifndef CERES_GET_FLAG
|
| 47 |
+
#define CERES_GET_FLAG(X) X
|
| 48 |
+
#endif
|
| 49 |
+
|
| 50 |
+
// Indicates whether C++17 is currently active
|
| 51 |
+
#ifndef CERES_HAS_CPP17
|
| 52 |
+
#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
|
| 53 |
+
#define CERES_HAS_CPP17
|
| 54 |
+
#endif // __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >=
|
| 55 |
+
// 201703L)
|
| 56 |
+
#endif // !defined(CERES_HAS_CPP17)
|
| 57 |
+
|
| 58 |
+
// Indicates whether C++20 is currently active
|
| 59 |
+
#ifndef CERES_HAS_CPP20
|
| 60 |
+
#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
|
| 61 |
+
#define CERES_HAS_CPP20
|
| 62 |
+
#endif // __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >=
|
| 63 |
+
// 202002L)
|
| 64 |
+
#endif // !defined(CERES_HAS_CPP20)
|
| 65 |
+
|
| 66 |
+
// Prevents symbols from being substituted by the corresponding macro definition
|
| 67 |
+
// under the same name. For instance, min and max are defined as macros on
|
| 68 |
+
// Windows (unless NOMINMAX is defined) which causes compilation errors when
|
| 69 |
+
// defining or referencing symbols under the same name.
|
| 70 |
+
//
|
| 71 |
+
// To be robust in all cases particularly when NOMINMAX cannot be used, use this
|
| 72 |
+
// macro to annotate min/max declarations/definitions. Examples:
|
| 73 |
+
//
|
| 74 |
+
// int max CERES_PREVENT_MACRO_SUBSTITUTION();
|
| 75 |
+
// min CERES_PREVENT_MACRO_SUBSTITUTION(a, b);
|
| 76 |
+
// max CERES_PREVENT_MACRO_SUBSTITUTION(a, b);
|
| 77 |
+
//
|
| 78 |
+
// NOTE: In case the symbols for which the substitution must be prevented are
|
| 79 |
+
// used within another macro, the substitution must be inhibited using parens as
|
| 80 |
+
//
|
| 81 |
+
// (std::numerical_limits<double>::max)()
|
| 82 |
+
//
|
| 83 |
+
// since the helper macro will not work here. Do not use this technique in
|
| 84 |
+
// general case, because it will prevent argument-dependent lookup (ADL).
|
| 85 |
+
//
|
| 86 |
+
#define CERES_PREVENT_MACRO_SUBSTITUTION // Yes, it's empty
|
| 87 |
+
|
| 88 |
+
#endif // CERES_PUBLIC_INTERNAL_PORT_H_
|
include/ceres/internal/reenable_warnings.h
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2015 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
|
| 30 |
+
// This is not your usual header guard. See disable_warnings.h
|
| 31 |
+
#ifdef CERES_WARNINGS_DISABLED
|
| 32 |
+
#undef CERES_WARNINGS_DISABLED
|
| 33 |
+
|
| 34 |
+
#ifdef _MSC_VER
|
| 35 |
+
#pragma warning(pop)
|
| 36 |
+
#endif
|
| 37 |
+
|
| 38 |
+
#endif // CERES_WARNINGS_DISABLED
|
include/ceres/internal/sphere_manifold_functions.h
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2022 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: vitus@google.com (Mike Vitus)
|
| 30 |
+
// jodebo_beck@gmx.de (Johannes Beck)
|
| 31 |
+
|
| 32 |
+
#ifndef CERES_PUBLIC_INTERNAL_SPHERE_MANIFOLD_HELPERS_H_
|
| 33 |
+
#define CERES_PUBLIC_INTERNAL_SPHERE_MANIFOLD_HELPERS_H_
|
| 34 |
+
|
| 35 |
+
#include "ceres/internal/householder_vector.h"
|
| 36 |
+
|
| 37 |
+
// This module contains functions to compute the SphereManifold plus and minus
|
| 38 |
+
// operator and their Jacobians.
|
| 39 |
+
//
|
| 40 |
+
// As the parameters to these functions are shared between them, they are
|
| 41 |
+
// described here: The following variable names are used:
|
| 42 |
+
// Plus(x, delta) = x + delta = x_plus_delta,
|
| 43 |
+
// Minus(y, x) = y - x = y_minus_x.
|
| 44 |
+
//
|
| 45 |
+
// The remaining ones are v and beta which describe the Householder
|
| 46 |
+
// transformation of x, and norm_delta which is the norm of delta.
|
| 47 |
+
//
|
| 48 |
+
// The types of x, y, x_plus_delta and y_minus_x need to be equivalent to
|
| 49 |
+
// Eigen::Matrix<double, AmbientSpaceDimension, 1> and the type of delta needs
|
| 50 |
+
// to be equivalent to Eigen::Matrix<double, TangentSpaceDimension, 1>.
|
| 51 |
+
//
|
| 52 |
+
// The type of Jacobian plus needs to be equivalent to Eigen::Matrix<double,
|
| 53 |
+
// AmbientSpaceDimension, TangentSpaceDimension, Eigen::RowMajor> and for
|
| 54 |
+
// Jacobian minus Eigen::Matrix<double, TangentSpaceDimension,
|
| 55 |
+
// AmbientSpaceDimension, Eigen::RowMajor>.
|
| 56 |
+
//
|
| 57 |
+
// For all vector / matrix inputs and outputs, template parameters are
|
| 58 |
+
// used in order to allow also Eigen::Ref and Eigen block expressions to
|
| 59 |
+
// be passed to the function.
|
| 60 |
+
|
| 61 |
+
namespace ceres {
|
| 62 |
+
namespace internal {
|
| 63 |
+
|
| 64 |
+
template <typename VT, typename XT, typename DeltaT, typename XPlusDeltaT>
|
| 65 |
+
inline void ComputeSphereManifoldPlus(const VT& v,
|
| 66 |
+
double beta,
|
| 67 |
+
const XT& x,
|
| 68 |
+
const DeltaT& delta,
|
| 69 |
+
double norm_delta,
|
| 70 |
+
XPlusDeltaT* x_plus_delta) {
|
| 71 |
+
constexpr int AmbientDim = VT::RowsAtCompileTime;
|
| 72 |
+
|
| 73 |
+
// Map the delta from the minimum representation to the over parameterized
|
| 74 |
+
// homogeneous vector. See B.2 p.25 equation (106) - (107) for more details.
|
| 75 |
+
const double norm_delta_div_2 = 0.5 * norm_delta;
|
| 76 |
+
const double sin_delta_by_delta =
|
| 77 |
+
std::sin(norm_delta_div_2) / norm_delta_div_2;
|
| 78 |
+
|
| 79 |
+
Eigen::Matrix<double, AmbientDim, 1> y(v.size());
|
| 80 |
+
y << 0.5 * sin_delta_by_delta * delta, std::cos(norm_delta_div_2);
|
| 81 |
+
|
| 82 |
+
// Apply the delta update to remain on the sphere.
|
| 83 |
+
*x_plus_delta = x.norm() * ApplyHouseholderVector(y, v, beta);
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
template <typename VT, typename JacobianT>
|
| 87 |
+
inline void ComputeSphereManifoldPlusJacobian(const VT& x,
|
| 88 |
+
JacobianT* jacobian) {
|
| 89 |
+
constexpr int AmbientSpaceDim = VT::RowsAtCompileTime;
|
| 90 |
+
using AmbientVector = Eigen::Matrix<double, AmbientSpaceDim, 1>;
|
| 91 |
+
const int ambient_size = x.size();
|
| 92 |
+
const int tangent_size = x.size() - 1;
|
| 93 |
+
|
| 94 |
+
AmbientVector v(ambient_size);
|
| 95 |
+
double beta;
|
| 96 |
+
|
| 97 |
+
// NOTE: The explicit template arguments are needed here because
|
| 98 |
+
// ComputeHouseholderVector is templated and some versions of MSVC
|
| 99 |
+
// have trouble deducing the type of v automatically.
|
| 100 |
+
ComputeHouseholderVector<VT, double, AmbientSpaceDim>(x, &v, &beta);
|
| 101 |
+
|
| 102 |
+
// The Jacobian is equal to J = 0.5 * H.leftCols(size_ - 1) where H is the
|
| 103 |
+
// Householder matrix (H = I - beta * v * v').
|
| 104 |
+
for (int i = 0; i < tangent_size; ++i) {
|
| 105 |
+
(*jacobian).col(i) = -0.5 * beta * v(i) * v;
|
| 106 |
+
(*jacobian)(i, i) += 0.5;
|
| 107 |
+
}
|
| 108 |
+
(*jacobian) *= x.norm();
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
template <typename VT, typename XT, typename YT, typename YMinusXT>
|
| 112 |
+
inline void ComputeSphereManifoldMinus(
|
| 113 |
+
const VT& v, double beta, const XT& x, const YT& y, YMinusXT* y_minus_x) {
|
| 114 |
+
constexpr int AmbientSpaceDim = VT::RowsAtCompileTime;
|
| 115 |
+
constexpr int TangentSpaceDim =
|
| 116 |
+
AmbientSpaceDim == Eigen::Dynamic ? Eigen::Dynamic : AmbientSpaceDim - 1;
|
| 117 |
+
using AmbientVector = Eigen::Matrix<double, AmbientSpaceDim, 1>;
|
| 118 |
+
|
| 119 |
+
const int tanget_size = v.size() - 1;
|
| 120 |
+
|
| 121 |
+
const AmbientVector hy = ApplyHouseholderVector(y, v, beta) / x.norm();
|
| 122 |
+
|
| 123 |
+
// Calculate y - x. See B.2 p.25 equation (108).
|
| 124 |
+
double y_last = hy[tanget_size];
|
| 125 |
+
double hy_norm = hy.template head<TangentSpaceDim>(tanget_size).norm();
|
| 126 |
+
if (hy_norm == 0.0) {
|
| 127 |
+
y_minus_x->setZero();
|
| 128 |
+
} else {
|
| 129 |
+
*y_minus_x = 2.0 * std::atan2(hy_norm, y_last) / hy_norm *
|
| 130 |
+
hy.template head<TangentSpaceDim>(tanget_size);
|
| 131 |
+
}
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
template <typename VT, typename JacobianT>
|
| 135 |
+
inline void ComputeSphereManifoldMinusJacobian(const VT& x,
|
| 136 |
+
JacobianT* jacobian) {
|
| 137 |
+
constexpr int AmbientSpaceDim = VT::RowsAtCompileTime;
|
| 138 |
+
using AmbientVector = Eigen::Matrix<double, AmbientSpaceDim, 1>;
|
| 139 |
+
const int ambient_size = x.size();
|
| 140 |
+
const int tangent_size = x.size() - 1;
|
| 141 |
+
|
| 142 |
+
AmbientVector v(ambient_size);
|
| 143 |
+
double beta;
|
| 144 |
+
|
| 145 |
+
// NOTE: The explicit template arguments are needed here because
|
| 146 |
+
// ComputeHouseholderVector is templated and some versions of MSVC
|
| 147 |
+
// have trouble deducing the type of v automatically.
|
| 148 |
+
ComputeHouseholderVector<VT, double, AmbientSpaceDim>(x, &v, &beta);
|
| 149 |
+
|
| 150 |
+
// The Jacobian is equal to J = 2.0 * H.leftCols(size_ - 1) where H is the
|
| 151 |
+
// Householder matrix (H = I - beta * v * v').
|
| 152 |
+
for (int i = 0; i < tangent_size; ++i) {
|
| 153 |
+
(*jacobian).row(i) = -2.0 * beta * v(i) * v;
|
| 154 |
+
(*jacobian)(i, i) += 2.0;
|
| 155 |
+
}
|
| 156 |
+
(*jacobian) /= x.norm();
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
} // namespace internal
|
| 160 |
+
} // namespace ceres
|
| 161 |
+
|
| 162 |
+
#endif
|
include/ceres/internal/variadic_evaluate.h
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Ceres Solver - A fast non-linear least squares minimizer
|
| 2 |
+
// Copyright 2015 Google Inc. All rights reserved.
|
| 3 |
+
// http://ceres-solver.org/
|
| 4 |
+
//
|
| 5 |
+
// Redistribution and use in source and binary forms, with or without
|
| 6 |
+
// modification, are permitted provided that the following conditions are met:
|
| 7 |
+
//
|
| 8 |
+
// * Redistributions of source code must retain the above copyright notice,
|
| 9 |
+
// this list of conditions and the following disclaimer.
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright notice,
|
| 11 |
+
// this list of conditions and the following disclaimer in the documentation
|
| 12 |
+
// and/or other materials provided with the distribution.
|
| 13 |
+
// * Neither the name of Google Inc. nor the names of its contributors may be
|
| 14 |
+
// used to endorse or promote products derived from this software without
|
| 15 |
+
// specific prior written permission.
|
| 16 |
+
//
|
| 17 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 18 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 19 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 20 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 21 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 22 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 23 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 24 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 25 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 26 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 27 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 28 |
+
//
|
| 29 |
+
// Author: sameeragarwal@google.com (Sameer Agarwal)
|
| 30 |
+
// mierle@gmail.com (Keir Mierle)
|
| 31 |
+
// jodebo_beck@gmx.de (Johannes Beck)
|
| 32 |
+
|
| 33 |
+
#ifndef CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_
|
| 34 |
+
#define CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_
|
| 35 |
+
|
| 36 |
+
#include <cstddef>
|
| 37 |
+
#include <type_traits>
|
| 38 |
+
#include <utility>
|
| 39 |
+
|
| 40 |
+
#include "ceres/cost_function.h"
|
| 41 |
+
#include "ceres/internal/parameter_dims.h"
|
| 42 |
+
|
| 43 |
+
namespace ceres {
|
| 44 |
+
namespace internal {
|
| 45 |
+
|
| 46 |
+
// For fixed size cost functors
|
| 47 |
+
template <typename Functor, typename T, int... Indices>
|
| 48 |
+
inline bool VariadicEvaluateImpl(const Functor& functor,
|
| 49 |
+
T const* const* input,
|
| 50 |
+
T* output,
|
| 51 |
+
std::false_type /*is_dynamic*/,
|
| 52 |
+
std::integer_sequence<int, Indices...>) {
|
| 53 |
+
static_assert(sizeof...(Indices),
|
| 54 |
+
"Invalid number of parameter blocks. At least one parameter "
|
| 55 |
+
"block must be specified.");
|
| 56 |
+
return functor(input[Indices]..., output);
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
// For dynamic sized cost functors
|
| 60 |
+
template <typename Functor, typename T>
|
| 61 |
+
inline bool VariadicEvaluateImpl(const Functor& functor,
|
| 62 |
+
T const* const* input,
|
| 63 |
+
T* output,
|
| 64 |
+
std::true_type /*is_dynamic*/,
|
| 65 |
+
std::integer_sequence<int>) {
|
| 66 |
+
return functor(input, output);
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
// For ceres cost functors (not ceres::CostFunction)
|
| 70 |
+
template <typename ParameterDims, typename Functor, typename T>
|
| 71 |
+
inline bool VariadicEvaluateImpl(const Functor& functor,
|
| 72 |
+
T const* const* input,
|
| 73 |
+
T* output,
|
| 74 |
+
const void* /* NOT USED */) {
|
| 75 |
+
using ParameterBlockIndices =
|
| 76 |
+
std::make_integer_sequence<int, ParameterDims::kNumParameterBlocks>;
|
| 77 |
+
using IsDynamic = std::integral_constant<bool, ParameterDims::kIsDynamic>;
|
| 78 |
+
return VariadicEvaluateImpl(
|
| 79 |
+
functor, input, output, IsDynamic(), ParameterBlockIndices());
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
// For ceres::CostFunction
|
| 83 |
+
template <typename ParameterDims, typename Functor, typename T>
|
| 84 |
+
inline bool VariadicEvaluateImpl(const Functor& functor,
|
| 85 |
+
T const* const* input,
|
| 86 |
+
T* output,
|
| 87 |
+
const CostFunction* /* NOT USED */) {
|
| 88 |
+
return functor.Evaluate(input, output, nullptr);
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
// Variadic evaluate is a helper function to evaluate ceres cost function or
|
| 92 |
+
// functors using an input, output and the parameter dimensions. There are
|
| 93 |
+
// several ways different possibilities:
|
| 94 |
+
// 1) If the passed functor is a 'ceres::CostFunction' its evaluate method is
|
| 95 |
+
// called.
|
| 96 |
+
// 2) If the functor is not a 'ceres::CostFunction' and the specified parameter
|
| 97 |
+
// dims is dynamic, the functor must have the following signature
|
| 98 |
+
// 'bool(T const* const* input, T* output)'.
|
| 99 |
+
// 3) If the functor is not a 'ceres::CostFunction' and the specified parameter
|
| 100 |
+
// dims is not dynamic, the input is expanded by using the number of parameter
|
| 101 |
+
// blocks. The signature of the functor must have the following signature
|
| 102 |
+
// 'bool()(const T* i_1, const T* i_2, ... const T* i_n, T* output)'.
|
| 103 |
+
template <typename ParameterDims, typename Functor, typename T>
|
| 104 |
+
inline bool VariadicEvaluate(const Functor& functor,
|
| 105 |
+
T const* const* input,
|
| 106 |
+
T* output) {
|
| 107 |
+
return VariadicEvaluateImpl<ParameterDims>(functor, input, output, &functor);
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
} // namespace internal
|
| 111 |
+
} // namespace ceres
|
| 112 |
+
|
| 113 |
+
#endif // CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_
|