From 0e811b0881f1f21df0ae04fd745ae4ba5189cac1 Mon Sep 17 00:00:00 2001 From: Sameer Agarwal Date: Thu, 1 May 2014 07:54:12 -0700 Subject: [PATCH 01/10] Fix a bug in Minimizer::RunCallbacks. Solver::Summary::message was not being updated when the solver terminated because of a user's iteration callback indicating success or failure. Thanks to Sergey Sharybin for reporting this. Change-Id: I27e6e5eed086920ddf765461b0159417ac79d7b3 --- internal/ceres/line_search_minimizer.cc | 2 +- internal/ceres/minimizer.cc | 13 +++++--- internal/ceres/minimizer.h | 2 +- internal/ceres/minimizer_test.cc | 39 +++++++++++++++++++++++- internal/ceres/trust_region_minimizer.cc | 2 +- 5 files changed, 49 insertions(+), 9 deletions(-) diff --git a/internal/ceres/line_search_minimizer.cc b/internal/ceres/line_search_minimizer.cc index 3e8d18a..ae77a73 100644 --- a/internal/ceres/line_search_minimizer.cc +++ b/internal/ceres/line_search_minimizer.cc @@ -207,7 +207,7 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options, int num_line_search_direction_restarts = 0; while (true) { - if (!RunCallbacks(options.callbacks, iteration_summary, summary)) { + if (!RunCallbacks(options, iteration_summary, summary)) { break; } diff --git a/internal/ceres/minimizer.cc b/internal/ceres/minimizer.cc index bdb6a11..a20eed5 100644 --- a/internal/ceres/minimizer.cc +++ b/internal/ceres/minimizer.cc @@ -37,13 +37,14 @@ namespace internal { Minimizer::~Minimizer() {} -bool Minimizer::RunCallbacks(const vector callbacks, +bool Minimizer::RunCallbacks(const Minimizer::Options& options, const IterationSummary& iteration_summary, Solver::Summary* summary) { + const bool is_not_silent = !options.is_silent; CallbackReturnType status = SOLVER_CONTINUE; int i = 0; - while (status == SOLVER_CONTINUE && i < callbacks.size()) { - status = (*callbacks[i])(iteration_summary); + while (status == SOLVER_CONTINUE && i < options.callbacks.size()) { + status = (*options.callbacks[i])(iteration_summary); ++i; } switch (status) { @@ -51,11 +52,13 @@ bool Minimizer::RunCallbacks(const vector callbacks, return true; case SOLVER_TERMINATE_SUCCESSFULLY: summary->termination_type = USER_SUCCESS; - VLOG(1) << "Terminating: User callback returned USER_SUCCESS."; + summary->message = "User callback returned SOLVER_TERMINATE_SUCCESSFULLY."; + VLOG_IF(is_not_silent, 1) << "Terminating: " << summary->message; return false; case SOLVER_ABORT: summary->termination_type = USER_FAILURE; - VLOG(1) << "Terminating: User callback returned USER_ABORT."; + summary->message = "User callback returned SOLVER_ABORT."; + VLOG_IF(is_not_silent, 1) << "Terminating: " << summary->message; return false; default: LOG(FATAL) << "Unknown type of user callback status"; diff --git a/internal/ceres/minimizer.h b/internal/ceres/minimizer.h index f9f2b51..f1da3f7 100644 --- a/internal/ceres/minimizer.h +++ b/internal/ceres/minimizer.h @@ -186,7 +186,7 @@ class Minimizer { bool is_constrained; }; - static bool RunCallbacks(const vector callbacks, + static bool RunCallbacks(const Options& options, const IterationSummary& iteration_summary, Solver::Summary* summary); diff --git a/internal/ceres/minimizer_test.cc b/internal/ceres/minimizer_test.cc index 1058036..0d8b617 100644 --- a/internal/ceres/minimizer_test.cc +++ b/internal/ceres/minimizer_test.cc @@ -44,7 +44,7 @@ class FakeIterationCallback : public IterationCallback { } }; -TEST(MinimizerTest, InitializationCopiesCallbacks) { +TEST(Minimizer, InitializationCopiesCallbacks) { FakeIterationCallback callback0; FakeIterationCallback callback1; @@ -59,5 +59,42 @@ TEST(MinimizerTest, InitializationCopiesCallbacks) { EXPECT_EQ(minimizer_options.callbacks[1], &callback1); } +class AbortingIterationCallback : public IterationCallback { + public: + virtual ~AbortingIterationCallback() {} + virtual CallbackReturnType operator()(const IterationSummary& summary) { + return SOLVER_ABORT; + } +}; + +TEST(Minimizer, UserAbortUpdatesSummaryMessage) { + AbortingIterationCallback callback; + Solver::Options solver_options; + solver_options.callbacks.push_back(&callback); + Minimizer::Options minimizer_options(solver_options); + Solver::Summary summary; + Minimizer::RunCallbacks(minimizer_options, IterationSummary(), &summary); + EXPECT_EQ(summary.message, "User callback returned SOLVER_ABORT."); +} + +class SucceedingIterationCallback : public IterationCallback { + public: + virtual ~SucceedingIterationCallback() {} + virtual CallbackReturnType operator()(const IterationSummary& summary) { + return SOLVER_TERMINATE_SUCCESSFULLY; + } +}; + +TEST(Minimizer, UserSuccessUpdatesSummaryMessage) { + SucceedingIterationCallback callback; + Solver::Options solver_options; + solver_options.callbacks.push_back(&callback); + Minimizer::Options minimizer_options(solver_options); + Solver::Summary summary; + Minimizer::RunCallbacks(minimizer_options, IterationSummary(), &summary); + EXPECT_EQ(summary.message, + "User callback returned SOLVER_TERMINATE_SUCCESSFULLY."); +} + } // namespace internal } // namespace ceres diff --git a/internal/ceres/trust_region_minimizer.cc b/internal/ceres/trust_region_minimizer.cc index 8f8ec98..4be5619 100644 --- a/internal/ceres/trust_region_minimizer.cc +++ b/internal/ceres/trust_region_minimizer.cc @@ -256,7 +256,7 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options, bool inner_iterations_are_enabled = options.inner_iteration_minimizer != NULL; while (true) { bool inner_iterations_were_useful = false; - if (!RunCallbacks(options.callbacks, iteration_summary, summary)) { + if (!RunCallbacks(options, iteration_summary, summary)) { return; } From 5ffe06019a6c741ee7edc940ffeeceaaeabfa05d Mon Sep 17 00:00:00 2001 From: Alex Stewart Date: Thu, 1 May 2014 12:06:46 +0100 Subject: [PATCH 02/10] Export Ceres compile definitions to targets compiled against Ceres. - Previously all Ceres compile definitions were private to Ceres, that is they were not exported to users via the CMake export mechanism. - Now that we use compile definitions in public (installed) Ceres headers, we need to export the Ceres compile definitions. - If we did not do this, then the client's code 'see's' a different version of the Ceres headers to those which were in fact compiled, or in the case of shared_ptr, may not find the required header. - This patch makes use of the new, in CMake 2.8.11, function: target_compile_definitions() to export all of the Ceres compile definitions using CMake's export functionality. - For CMake versions < 2.8.11, we have to use the blunter instrument of calling add_definitions() in CeresConfig.cmake (invoked by a call to find_package(Ceres)). This is messy because it ends up adding the Ceres compile definitions to any target declared in the user's code after the call to find_package(Ceres). Although this should do no harm as all of our defines are prefaced with CERES_, so any unintentional name clashes are unlikely. Change-Id: I5dea80949190eaf4fb08ea4ac568ce28c32dd4e0 --- CMakeLists.txt | 17 +++++++++++++++++ cmake/CeresConfig.cmake.in | 28 ++++++++++++++++++++++++++++ internal/ceres/CMakeLists.txt | 16 ++++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5110d26..d959669 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -647,6 +647,23 @@ IF (APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang") CLANG_VERSION VERSION_LESS 4.2) ENDIF (APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang") +# Get the complete list of any added compile definitions so that we can +# export them. Currently we export all Ceres compile definitions to users +# of Ceres via FindPackage() except CERES_BUILDING_SHARED_LIBRARY (if present) +# which controls the behaviour of the CERES_EXPORT macro for MSVC, which +# we substitute for CERES_USING_SHARED_LIBRARY, which is what users of +# Ceres should call in MSVC. +GET_DIRECTORY_PROPERTY(CERES_INTERFACE_COMPILE_DEFINITIONS + DIRECTORY ${CMAKE_SOURCE_DIR} COMPILE_DEFINITIONS) +# Substitute CERES_BUILDING_SHARED_LIBRARY with CERES_USING_SHARED_LIBRARY +# if building Ceres as a shared library. +IF (BUILD_SHARED_LIBS) + LIST(REMOVE_ITEM CERES_INTERFACE_COMPILE_DEFINITIONS + CERES_BUILDING_SHARED_LIBRARY) + LIST(APPEND CERES_INTERFACE_COMPILE_DEFINITIONS + CERES_USING_SHARED_LIBRARY) +ENDIF() + ADD_SUBDIRECTORY(internal/ceres) IF (BUILD_DOCUMENTATION) diff --git a/cmake/CeresConfig.cmake.in b/cmake/CeresConfig.cmake.in index 02da766..56a2194 100644 --- a/cmake/CeresConfig.cmake.in +++ b/cmake/CeresConfig.cmake.in @@ -51,6 +51,15 @@ # was compiled. This will not include any optional dependencies # that were disabled when Ceres was compiled. # +# CERES_INTERFACE_COMPILE_DEFINITIONS: List of compile definitions which should be +# used when compiling a target that uses Ceres +# Note that these variables will NOT have a -D +# prefix appended. +# IMPORTANT: The contents of CERES_INTERFACE_COMPILE_DEFINITIONS will be +# AUTOMATICALLY added for you, either via the CMake function +# target_compile_definitions() in CMake >= 2.8.11, or via a call to +# add_definitions() in CMake < 2.8.11. +# # The following variables are also defined for legacy compatibility only. # Any new code should not use them as they do not conform to the standard CMake # FindPackage naming conventions. @@ -67,6 +76,7 @@ MACRO(CERES_REPORT_NOT_FOUND REASON_MSG) SET(CERES_FOUND FALSE) UNSET(CERES_INCLUDE_DIRS) UNSET(CERES_LIBRARIES) + UNSET(CERES_INTERFACE_COMPILE_DEFINITIONS) # Reset the CMake module path to its state when this script was called. SET(CMAKE_MODULE_PATH ${CALLERS_CMAKE_MODULE_PATH}) @@ -190,6 +200,24 @@ ENDIF (NOT TARGET ceres AND NOT Ceres_BINARY_DIR) # Set the expected XX_LIBRARIES variable for FindPackage(). SET(CERES_LIBRARIES ceres) +# If Ceres was compiled with CMake < 2.8.11, we were not able to use the +# new (in 2.8.11) target_compile_definitions() function to append the +# required compile definitions to use when compiling a target that uses +# Ceres to the Ceres library target. As such, we need to use add_definitions() +# to ensure that they will be present. This is a blunt instrument, as it +# will add the Ceres definitions to _all_ targets declared from this point +# on in the caller's project. Hoever, without requiring the user to +# explicitly set the flags themselves, this is the only way in CMake +# versions < 2.8.11. +SET (CERES_COMPILED_CMAKE_VERSION @CMAKE_VERSION@) +SET (CERES_INTERFACE_COMPILE_DEFINITIONS @CERES_INTERFACE_COMPILE_DEFINITIONS@) +IF (CERES_COMPILED_CMAKE_VERSION VERSION_LESS 2.8.11) + # The definitions will have been stripped of -D, add it back. + FOREACH(DEF ${CERES_INTERFACE_COMPILE_DEFINITIONS}) + ADD_DEFINITIONS("-D${DEF}") + ENDFOREACH() +ENDIF() + # Set legacy include directories variable for backwards compatibility. SET(CERES_INCLUDES ${CERES_INCLUDE_DIRS}) diff --git a/internal/ceres/CMakeLists.txt b/internal/ceres/CMakeLists.txt index b959768..7b7f21d 100644 --- a/internal/ceres/CMakeLists.txt +++ b/internal/ceres/CMakeLists.txt @@ -177,6 +177,22 @@ SET_TARGET_PROPERTIES(ceres PROPERTIES VERSION ${CERES_VERSION} SOVERSION ${CERES_VERSION_MAJOR} ) + +# If we are using CMake >= 2.8.11, make use of the target_compile_definitions() +# function to append the compile definitions to the exported ceres target, thus +# any library that finds Ceres via CMake, then adds Ceres to one of its own +# targets will be compiled with the Ceres compile definitions defined. This +# is important for any defines that appear in the installed Ceres header files +# e.g those related to shared_ptr. +# +# If we are using CMake < 2.8.11, then we will have added an add_definitions() +# call in the CeresConfig.cmake file, which whilst achieving a similar effect, +# is more of a blunt instrument, as the Ceres definitions will also be added +# to targets in the users project that do not use Ceres. +IF (CMAKE_VERSION VERSION_EQUAL 2.8.11 OR + CMAKE_VERSION VERSION_GREATER 2.8.11) + TARGET_COMPILE_DEFINITIONS(ceres INTERFACE ${CERES_INTERFACE_COMPILE_DEFINITIONS}) +ENDIF() TARGET_LINK_LIBRARIES(ceres ${CERES_LIBRARY_DEPENDENCIES}) INSTALL(TARGETS ceres From 633b50b7af9841607c07133f585e131fba7de177 Mon Sep 17 00:00:00 2001 From: Sameer Agarwal Date: Fri, 2 May 2014 22:46:20 -0700 Subject: [PATCH 03/10] Add the (2,4,8) template specialization. Change-Id: I058bcebdd1725031d573404133b184d6f27dc005 --- .../generate_eliminator_specialization.py | 1 + ...partitioned_matrix_view_specializations.py | 1 + .../partitioned_matrix_view_2_4_8.cc | 56 +++++++++++++++++++ .../ceres/generated/schur_eliminator_2_4_8.cc | 56 +++++++++++++++++++ internal/ceres/partitioned_matrix_view.cc | 6 ++ internal/ceres/schur_eliminator.cc | 5 ++ 6 files changed, 125 insertions(+) create mode 100644 internal/ceres/generated/partitioned_matrix_view_2_4_8.cc create mode 100644 internal/ceres/generated/schur_eliminator_2_4_8.cc diff --git a/internal/ceres/generate_eliminator_specialization.py b/internal/ceres/generate_eliminator_specialization.py index 5b5a866..37b1fd7 100644 --- a/internal/ceres/generate_eliminator_specialization.py +++ b/internal/ceres/generate_eliminator_specialization.py @@ -59,6 +59,7 @@ (2, 3, "Eigen::Dynamic"), (2, 4, 3), (2, 4, 4), + (2, 4, 8), (2, 4, 9), (2, 4, "Eigen::Dynamic"), (2, "Eigen::Dynamic", "Eigen::Dynamic"), diff --git a/internal/ceres/generate_partitioned_matrix_view_specializations.py b/internal/ceres/generate_partitioned_matrix_view_specializations.py index 34a65cb..d447262 100644 --- a/internal/ceres/generate_partitioned_matrix_view_specializations.py +++ b/internal/ceres/generate_partitioned_matrix_view_specializations.py @@ -57,6 +57,7 @@ (2, 3, "Eigen::Dynamic"), (2, 4, 3), (2, 4, 4), + (2, 4, 8), (2, 4, 9), (2, 4, "Eigen::Dynamic"), (2, "Eigen::Dynamic", "Eigen::Dynamic"), diff --git a/internal/ceres/generated/partitioned_matrix_view_2_4_8.cc b/internal/ceres/generated/partitioned_matrix_view_2_4_8.cc new file mode 100644 index 0000000..aef7048 --- /dev/null +++ b/internal/ceres/generated/partitioned_matrix_view_2_4_8.cc @@ -0,0 +1,56 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2013 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) +// +// Template specialization of PartitionedMatrixView. +// +// ======================================== +// THIS FILE IS AUTOGENERATED. DO NOT EDIT. +// THIS FILE IS AUTOGENERATED. DO NOT EDIT. +// THIS FILE IS AUTOGENERATED. DO NOT EDIT. +// THIS FILE IS AUTOGENERATED. DO NOT EDIT. +//========================================= +// +// This file is generated using generate_partitioned_matrix_view_specializations.py. +// Editing it manually is not recommended. + +#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION + +#include "ceres/partitioned_matrix_view_impl.h" +#include "ceres/internal/eigen.h" + +namespace ceres { +namespace internal { + +template class PartitionedMatrixView<2, 4, 8>; + +} // namespace internal +} // namespace ceres + +#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION diff --git a/internal/ceres/generated/schur_eliminator_2_4_8.cc b/internal/ceres/generated/schur_eliminator_2_4_8.cc new file mode 100644 index 0000000..81e6bd6 --- /dev/null +++ b/internal/ceres/generated/schur_eliminator_2_4_8.cc @@ -0,0 +1,56 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved. +// http://code.google.com/p/ceres-solver/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) +// +// Template specialization of SchurEliminator. +// +// ======================================== +// THIS FILE IS AUTOGENERATED. DO NOT EDIT. +// THIS FILE IS AUTOGENERATED. DO NOT EDIT. +// THIS FILE IS AUTOGENERATED. DO NOT EDIT. +// THIS FILE IS AUTOGENERATED. DO NOT EDIT. +//========================================= +// +// This file is generated using generate_eliminator_specialization.py. +// Editing it manually is not recommended. + +#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION + +#include "ceres/schur_eliminator_impl.h" +#include "ceres/internal/eigen.h" + +namespace ceres { +namespace internal { + +template class SchurEliminator<2, 4, 8>; + +} // namespace internal +} // namespace ceres + +#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION diff --git a/internal/ceres/partitioned_matrix_view.cc b/internal/ceres/partitioned_matrix_view.cc index e6c0fe4..d745a9b 100644 --- a/internal/ceres/partitioned_matrix_view.cc +++ b/internal/ceres/partitioned_matrix_view.cc @@ -111,6 +111,12 @@ PartitionedMatrixViewBase::Create(const LinearSolver::Options& options, return new PartitionedMatrixView<2, 4, 4>( matrix, options.elimination_groups[0]); } + if ((options.row_block_size == 2) && + (options.e_block_size == 4) && + (options.f_block_size == 8)) { + return new PartitionedMatrixView<2, 4, 8>( + matrix, options.elimination_groups[0]); + } if ((options.row_block_size == 2) && (options.e_block_size == 4) && (options.f_block_size == 9)) { diff --git a/internal/ceres/schur_eliminator.cc b/internal/ceres/schur_eliminator.cc index 2701683..4d9b175 100644 --- a/internal/ceres/schur_eliminator.cc +++ b/internal/ceres/schur_eliminator.cc @@ -100,6 +100,11 @@ SchurEliminatorBase::Create(const LinearSolver::Options& options) { (options.f_block_size == 4)) { return new SchurEliminator<2, 4, 4>(options); } + if ((options.row_block_size == 2) && + (options.e_block_size == 4) && + (options.f_block_size == 8)) { + return new SchurEliminator<2, 4, 8>(options); + } if ((options.row_block_size == 2) && (options.e_block_size == 4) && (options.f_block_size == 9)) { From a536ae76dfa2dbe2bc487900b98cf6c15276c649 Mon Sep 17 00:00:00 2001 From: Sameer Agarwal Date: Sun, 4 May 2014 21:18:42 -0700 Subject: [PATCH 04/10] Lazily initialize the bounds arrays in ParameterBlock. Problems that do not use bounds do not have to pay the price of storing bounds constraints. Also replace the raw pointer access to the upper and lower bounds arrays with accessors which hides the lazy initialization from the user. Change-Id: I0325a35de9c29f853559f891e32e7c777686e537 --- internal/ceres/parameter_block.h | 66 ++++++++++++++++++-------- internal/ceres/parameter_block_test.cc | 29 ++++++----- internal/ceres/solver_impl.cc | 39 ++++++++------- 3 files changed, 84 insertions(+), 50 deletions(-) diff --git a/internal/ceres/parameter_block.h b/internal/ceres/parameter_block.h index a978eb5..7bc823d 100644 --- a/internal/ceres/parameter_block.h +++ b/internal/ceres/parameter_block.h @@ -184,11 +184,27 @@ class ParameterBlock { void SetUpperBound(int index, double upper_bound) { CHECK_LT(index, size_); + + if (upper_bounds_.get() == NULL) { + upper_bounds_.reset(new double[size_]); + std::fill(upper_bounds_.get(), + upper_bounds_.get() + size_, + std::numeric_limits::max()); + } + upper_bounds_[index] = upper_bound; }; void SetLowerBound(int index, double lower_bound) { CHECK_LT(index, size_); + + if (lower_bounds_.get() == NULL) { + lower_bounds_.reset(new double[size_]); + std::fill(lower_bounds_.get(), + lower_bounds_.get() + size_, + -std::numeric_limits::max()); + } + lower_bounds_[index] = lower_bound; } @@ -206,10 +222,16 @@ class ParameterBlock { } // Project onto the box constraints. - for (int i = 0; i < size_; ++i) { - x_plus_delta[i] = std::min(std::max(x_plus_delta[i], - lower_bounds_[i]), - upper_bounds_[i]); + if (lower_bounds_.get() != NULL) { + for (int i = 0; i < size_; ++i) { + x_plus_delta[i] = std::max(x_plus_delta[i], lower_bounds_[i]); + } + } + + if (upper_bounds_.get() != NULL) { + for (int i = 0; i < size_; ++i) { + x_plus_delta[i] = std::min(x_plus_delta[i], upper_bounds_[i]); + } } return true; @@ -257,12 +279,20 @@ class ParameterBlock { return residual_blocks_.get(); } - const double* upper_bounds() const { - return upper_bounds_.get(); + double LowerBoundForParameter(int index) const { + if (lower_bounds_.get() == NULL) { + return -std::numeric_limits::max(); + } else { + return lower_bounds_[index]; + } } - const double* lower_bounds() const { - return lower_bounds_.get(); + double UpperBoundForParameter(int index) const { + if (upper_bounds_.get() == NULL) { + return std::numeric_limits::max(); + } else { + return upper_bounds_[index]; + } } private: @@ -281,15 +311,6 @@ class ParameterBlock { SetParameterization(local_parameterization); } - upper_bounds_.reset(new double[size_]); - std::fill(upper_bounds_.get(), - upper_bounds_.get() + size_, - std::numeric_limits::max()); - lower_bounds_.reset(new double[size_]); - std::fill(lower_bounds_.get(), - lower_bounds_.get() + size_, - -std::numeric_limits::max()); - state_offset_ = -1; delta_offset_ = -1; } @@ -352,8 +373,15 @@ class ParameterBlock { // If non-null, contains the residual blocks this parameter block is in. scoped_ptr residual_blocks_; - // Upper and lower bounds for the parameter block. These arrays are - // initialized to std::numeric_limits::max() and + // Upper and lower bounds for the parameter block. SetUpperBound + // and SetLowerBound lazily initialize the upper_bounds_ and + // lower_bounds_ arrays. If they are never called, then memory for + // these arrays is never allocated. Thus for problems where there + // are no bounds, or only one sided bounds we do not pay the cost of + // allocating memory for the inactive bounds constraints. + // + // Upon initialization these arrays are initialized to + // std::numeric_limits::max() and // -std::numeric_limits::max() respectively which correspond // to the parameter block being unconstrained. scoped_array upper_bounds_; diff --git a/internal/ceres/parameter_block_test.cc b/internal/ceres/parameter_block_test.cc index a76c408..5a2db3c 100644 --- a/internal/ceres/parameter_block_test.cc +++ b/internal/ceres/parameter_block_test.cc @@ -172,26 +172,29 @@ TEST(ParameterBlock, DetectBadLocalParameterization) { TEST(ParameterBlock, DefaultBounds) { double x[2]; ParameterBlock parameter_block(x, 2, -1, NULL); - const double* upper_bounds = parameter_block.upper_bounds(); - EXPECT_EQ(upper_bounds[0], std::numeric_limits::max()); - EXPECT_EQ(upper_bounds[1], std::numeric_limits::max()); - const double* lower_bounds = parameter_block.lower_bounds(); - EXPECT_EQ(lower_bounds[0], -std::numeric_limits::max()); - EXPECT_EQ(lower_bounds[1], -std::numeric_limits::max()); + EXPECT_EQ(parameter_block.UpperBoundForParameter(0), + std::numeric_limits::max()); + EXPECT_EQ(parameter_block.UpperBoundForParameter(1), + std::numeric_limits::max()); + EXPECT_EQ(parameter_block.LowerBoundForParameter(0), + -std::numeric_limits::max()); + EXPECT_EQ(parameter_block.LowerBoundForParameter(1), + -std::numeric_limits::max()); } TEST(ParameterBlock, SetBounds) { double x[2]; ParameterBlock parameter_block(x, 2, -1, NULL); - parameter_block.SetUpperBound(1, 1); parameter_block.SetLowerBound(0, 1); + parameter_block.SetUpperBound(1, 1); + + EXPECT_EQ(parameter_block.LowerBoundForParameter(0), 1.0); + EXPECT_EQ(parameter_block.LowerBoundForParameter(1), + -std::numeric_limits::max()); - const double* upper_bounds = parameter_block.upper_bounds(); - EXPECT_EQ(upper_bounds[0], std::numeric_limits::max()); - EXPECT_EQ(upper_bounds[1], 1.0); - const double* lower_bounds = parameter_block.lower_bounds(); - EXPECT_EQ(lower_bounds[0], 1.0); - EXPECT_EQ(lower_bounds[1], -std::numeric_limits::max()); + EXPECT_EQ(parameter_block.UpperBoundForParameter(0), + std::numeric_limits::max()); + EXPECT_EQ(parameter_block.UpperBoundForParameter(1), 1.0); } TEST(ParameterBlock, PlusWithBoundsConstraints) { diff --git a/internal/ceres/solver_impl.cc b/internal/ceres/solver_impl.cc index 6ae2c90..2bf6cd2 100644 --- a/internal/ceres/solver_impl.cc +++ b/internal/ceres/solver_impl.cc @@ -328,16 +328,16 @@ bool LineSearchOptionsAreValid(const Solver::Options& options, bool IsBoundsConstrained(const Program& program) { const vector& parameter_blocks = program.parameter_blocks(); for (int i = 0; i < parameter_blocks.size(); ++i) { - if (parameter_blocks[i]->IsConstant()) { + const ParameterBlock* parameter_block = parameter_blocks[i]; + if (parameter_block->IsConstant()) { continue; } - - const double* lower_bounds = parameter_blocks[i]->lower_bounds(); - const double* upper_bounds = parameter_blocks[i]->upper_bounds(); - const int size = parameter_blocks[i]->Size(); + const int size = parameter_block->Size(); for (int j = 0; j < size; ++j) { - if (lower_bounds[j] > -std::numeric_limits::max() || - upper_bounds[j] < std::numeric_limits::max()) { + const double lower_bound = parameter_block->LowerBoundForParameter(j); + const double upper_bound = parameter_block->UpperBoundForParameter(j); + if (lower_bound > -std::numeric_limits::max() || + upper_bound < std::numeric_limits::max()) { return true; } } @@ -353,24 +353,25 @@ bool ParameterBlocksAreFeasible(const ProblemImpl* problem, string* message) { const Program& program = problem->program(); const vector& parameter_blocks = program.parameter_blocks(); for (int i = 0; i < parameter_blocks.size(); ++i) { - const double* array = parameter_blocks[i]->user_state(); - const double* lower_bounds = parameter_blocks[i]->lower_bounds(); - const double* upper_bounds = parameter_blocks[i]->upper_bounds(); - const int size = parameter_blocks[i]->Size(); - if (parameter_blocks[i]->IsConstant()) { + const ParameterBlock* parameter_block = parameter_blocks[i]; + const double* parameters = parameter_block->user_state(); + const int size = parameter_block->Size(); + if (parameter_block->IsConstant()) { // Constant parameter blocks must start in the feasible region // to ultimately produce a feasible solution, since Ceres cannot // change them. for (int j = 0; j < size; ++j) { - if (array[j] < lower_bounds[j] || array[j] > upper_bounds[j]) { + const double lower_bound = parameter_block->LowerBoundForParameter(j); + const double upper_bound = parameter_block->UpperBoundForParameter(j); + if (parameters[j] < lower_bound || parameters[j] > upper_bound) { *message = StringPrintf( "ParameterBlock: %p with size %d has at least one infeasible " "value." "\nFirst infeasible value is at index: %d." "\nLower bound: %e, value: %e, upper bound: %e" "\nParameter block values: ", - array, size, j, lower_bounds[j], array[j], upper_bounds[j]); - AppendArrayToString(size, array, message); + parameters, size, j, lower_bound, parameters[j], upper_bound); + AppendArrayToString(size, parameters, message); return false; } } @@ -379,15 +380,17 @@ bool ParameterBlocksAreFeasible(const ProblemImpl* problem, string* message) { // regions, otherwise there is no way to produce a feasible // solution. for (int j = 0; j < size; ++j) { - if (lower_bounds[j] >= upper_bounds[j]) { + const double lower_bound = parameter_block->LowerBoundForParameter(j); + const double upper_bound = parameter_block->UpperBoundForParameter(j); + if (lower_bound >= upper_bound) { *message = StringPrintf( "ParameterBlock: %p with size %d has at least one infeasible " "bound." "\nFirst infeasible bound is at index: %d." "\nLower bound: %e, upper bound: %e" "\nParameter block values: ", - array, size, j, lower_bounds[j], upper_bounds[j]); - AppendArrayToString(size, array, message); + parameters, size, j, lower_bound, upper_bound); + AppendArrayToString(size, parameters, message); return false; } } From 95cce0834d5a2d72568e6d2be968a51c244c2787 Mon Sep 17 00:00:00 2001 From: Sameer Agarwal Date: Mon, 5 May 2014 08:54:50 -0700 Subject: [PATCH 05/10] Remove some errant tabs. Change-Id: Ie1f7051e99bcb15ad068711b68a9d8f317b12ed7 --- .../ceres/generate_partitioned_matrix_view_specializations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ceres/generate_partitioned_matrix_view_specializations.py b/internal/ceres/generate_partitioned_matrix_view_specializations.py index d447262..a352d29 100644 --- a/internal/ceres/generate_partitioned_matrix_view_specializations.py +++ b/internal/ceres/generate_partitioned_matrix_view_specializations.py @@ -57,7 +57,7 @@ (2, 3, "Eigen::Dynamic"), (2, 4, 3), (2, 4, 4), - (2, 4, 8), + (2, 4, 8), (2, 4, 9), (2, 4, "Eigen::Dynamic"), (2, "Eigen::Dynamic", "Eigen::Dynamic"), From 7088a08f5d9e04e75a5a4c3823ef7927e13ff0e4 Mon Sep 17 00:00:00 2001 From: Sameer Agarwal Date: Mon, 5 May 2014 09:02:05 -0700 Subject: [PATCH 06/10] Fix some 80col violations and reflow the comments in cmake.in file. Change-Id: I4c65c89b794845aeef69159a03350c727e2ee812 --- cmake/CeresConfig.cmake.in | 117 ++++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 53 deletions(-) diff --git a/cmake/CeresConfig.cmake.in b/cmake/CeresConfig.cmake.in index 56a2194..5550fd0 100644 --- a/cmake/CeresConfig.cmake.in +++ b/cmake/CeresConfig.cmake.in @@ -37,32 +37,40 @@ # # This module defines the following variables: # -# Ceres_FOUND / CERES_FOUND: True iff Ceres has been successfully found. Both -# variables are set as although FindPackage() only -# references Ceres_FOUND in Config mode, given the -# conventions for _FOUND when FindPackage() -# is called in Module mode, users could reasonably -# expect to use CERES_FOUND instead. +# Ceres_FOUND / CERES_FOUND: True iff Ceres has been successfully +# found. Both variables are set as although +# FindPackage() only references Ceres_FOUND +# in Config mode, given the conventions for +# _FOUND when FindPackage() is +# called in Module mode, users could +# reasonably expect to use CERES_FOUND +# instead. +# # CERES_VERSION: Version of Ceres found. -# CERES_INCLUDE_DIRS: Include directories for Ceres and the dependencies which -# appear in the Ceres public API and are thus required to -# use Ceres. -# CERES_LIBRARIES: Libraries for Ceres and all dependencies against which Ceres -# was compiled. This will not include any optional dependencies -# that were disabled when Ceres was compiled. # -# CERES_INTERFACE_COMPILE_DEFINITIONS: List of compile definitions which should be -# used when compiling a target that uses Ceres -# Note that these variables will NOT have a -D -# prefix appended. -# IMPORTANT: The contents of CERES_INTERFACE_COMPILE_DEFINITIONS will be -# AUTOMATICALLY added for you, either via the CMake function -# target_compile_definitions() in CMake >= 2.8.11, or via a call to -# add_definitions() in CMake < 2.8.11. +# CERES_INCLUDE_DIRS: Include directories for Ceres and the +# dependencies which appear in the Ceres public +# API and are thus required to use Ceres. +# CERES_LIBRARIES: Libraries for Ceres and all +# dependencies against which Ceres was +# compiled. This will not include any optional +# dependencies that were disabled when Ceres was +# compiled. +# +# CERES_INTERFACE_COMPILE_DEFINITIONS: List of compile definitions +# which should be used when +# compiling a target that uses Ceres +# Note that these variables will NOT +# have a -D prefix appended. # -# The following variables are also defined for legacy compatibility only. -# Any new code should not use them as they do not conform to the standard CMake -# FindPackage naming conventions. +# IMPORTANT: The contents of CERES_INTERFACE_COMPILE_DEFINITIONS will +# be AUTOMATICALLY added for you, either via the CMake +# function target_compile_definitions() in CMake >= 2.8.11, +# or via a call to add_definitions() in CMake < 2.8.11. +# +# The following variables are also defined for legacy compatibility +# only. Any new code should not use them as they do not conform to +# the standard CMake FindPackage naming conventions. # # CERES_INCLUDES = ${CERES_INCLUDE_DIRS}. @@ -70,8 +78,8 @@ # unsets all public (designed to be used externally) variables and reports # error message at priority depending upon [REQUIRED/QUIET/] argument. MACRO(CERES_REPORT_NOT_FOUND REASON_MSG) - # FindPackage() only references Ceres_FOUND, and requires it to be explicitly - # set FALSE to denote not found (not merely undefined). + # FindPackage() only references Ceres_FOUND, and requires it to be + # explicitly set FALSE to denote not found (not merely undefined). SET(Ceres_FOUND FALSE) SET(CERES_FOUND FALSE) UNSET(CERES_INCLUDE_DIRS) @@ -81,8 +89,8 @@ MACRO(CERES_REPORT_NOT_FOUND REASON_MSG) # Reset the CMake module path to its state when this script was called. SET(CMAKE_MODULE_PATH ${CALLERS_CMAKE_MODULE_PATH}) - # Note _FIND_[REQUIRED/QUIETLY] variables defined by FindPackage() - # use the camelcase library name, not uppercase. + # Note _FIND_[REQUIRED/QUIETLY] variables defined by + # FindPackage() use the camelcase library name, not uppercase. IF (Ceres_FIND_QUIETLY) MESSAGE(STATUS "Failed to find Ceres - " ${REASON_MSG} ${ARGN}) ELSE (Ceres_FIND_REQUIRED) @@ -99,20 +107,20 @@ ENDMACRO(CERES_REPORT_NOT_FOUND) GET_FILENAME_COMPONENT(CURRENT_CONFIG_INSTALL_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) -# Record the state of the CMake module path when this script was called so -# that we can ensure that we leave it in the same state on exit as it was -# on entry, but modify it locally. +# Record the state of the CMake module path when this script was +# called so that we can ensure that we leave it in the same state on +# exit as it was on entry, but modify it locally. SET(CALLERS_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}) -# Reset CMake module path to the installation directory of this script, -# thus we will use the FindPackage() scripts shipped with Ceres to find -# Ceres' dependencies, even if the user has equivalently named FindPackage() -# scripts in their project. +# Reset CMake module path to the installation directory of this +# script, thus we will use the FindPackage() scripts shipped with +# Ceres to find Ceres' dependencies, even if the user has equivalently +# named FindPackage() scripts in their project. SET(CMAKE_MODULE_PATH ${CURRENT_CONFIG_INSTALL_DIR}) -# Build the absolute root install directory as a relative path (determined when -# Ceres was configured & built) from the current install directory for this -# this file. This allows for the install tree to be relocated, after Ceres was -# built, outside of CMake. +# Build the absolute root install directory as a relative path +# (determined when Ceres was configured & built) from the current +# install directory for this this file. This allows for the install +# tree to be relocated, after Ceres was built, outside of CMake. GET_FILENAME_COMPONENT(CURRENT_ROOT_INSTALL_DIR ${CURRENT_CONFIG_INSTALL_DIR}/@INSTALL_ROOT_REL_CONFIG_INSTALL_DIR@ ABSOLUTE) IF (NOT EXISTS ${CURRENT_ROOT_INSTALL_DIR}) @@ -138,9 +146,10 @@ IF (NOT EXISTS ${CERES_INCLUDE_DIR}/ceres/ceres.h) "partially relocated outside of CMake after Ceres was built.") ENDIF (NOT EXISTS ${CERES_INCLUDE_DIR}/ceres/ceres.h) -# Append the include directories for all (potentially optional) dependencies -# with which Ceres was compiled, the libraries themselves come in via -# CeresTargets-.cmake as link libraries for Ceres target. +# Append the include directories for all (potentially optional) +# dependencies with which Ceres was compiled, the libraries themselves +# come in via CeresTargets-.cmake as link libraries for +# Ceres target. SET(CERES_INCLUDE_DIRS ${CERES_INCLUDE_DIR}) # Eigen. @@ -200,15 +209,15 @@ ENDIF (NOT TARGET ceres AND NOT Ceres_BINARY_DIR) # Set the expected XX_LIBRARIES variable for FindPackage(). SET(CERES_LIBRARIES ceres) -# If Ceres was compiled with CMake < 2.8.11, we were not able to use the -# new (in 2.8.11) target_compile_definitions() function to append the -# required compile definitions to use when compiling a target that uses -# Ceres to the Ceres library target. As such, we need to use add_definitions() -# to ensure that they will be present. This is a blunt instrument, as it -# will add the Ceres definitions to _all_ targets declared from this point -# on in the caller's project. Hoever, without requiring the user to -# explicitly set the flags themselves, this is the only way in CMake -# versions < 2.8.11. +# If Ceres was compiled with CMake < 2.8.11, we were not able to use +# the new (in 2.8.11) target_compile_definitions() function to append +# the required compile definitions to use when compiling a target that +# uses Ceres to the Ceres library target. As such, we need to use +# add_definitions() to ensure that they will be present. This is a +# blunt instrument, as it will add the Ceres definitions to _all_ +# targets declared from this point on in the caller's project. +# Hoever, without requiring the user to explicitly set the flags +# themselves, this is the only way in CMake versions < 2.8.11. SET (CERES_COMPILED_CMAKE_VERSION @CMAKE_VERSION@) SET (CERES_INTERFACE_COMPILE_DEFINITIONS @CERES_INTERFACE_COMPILE_DEFINITIONS@) IF (CERES_COMPILED_CMAKE_VERSION VERSION_LESS 2.8.11) @@ -228,7 +237,9 @@ SET(CMAKE_MODULE_PATH ${CALLERS_CMAKE_MODULE_PATH}) # found Ceres and all required dependencies. MESSAGE(STATUS "Found Ceres version: ${CERES_VERSION} " "installed in: ${CURRENT_ROOT_INSTALL_DIR}") -# Set CERES_FOUND to be equivalent to Ceres_FOUND, which is set to TRUE by -# FindPackage() if this file is found and run, and after which Ceres_FOUND -# is not (explicitly, i.e. undefined does not count) set to FALSE. + +# Set CERES_FOUND to be equivalent to Ceres_FOUND, which is set to +# TRUE by FindPackage() if this file is found and run, and after which +# Ceres_FOUND is not (explicitly, i.e. undefined does not count) set +# to FALSE. SET(CERES_FOUND TRUE) From eca7e1c635581834c858794e09c1e876323b7775 Mon Sep 17 00:00:00 2001 From: Sameer Agarwal Date: Tue, 6 May 2014 10:16:19 -0700 Subject: [PATCH 07/10] Remove BlockRandomAccessCRSMatrix. It is not used anywhere. Change-Id: I2a8ebbdacf788582f21266825ead3f76646da29e --- internal/ceres/CMakeLists.txt | 2 - .../ceres/block_random_access_crs_matrix.cc | 170 ------------------ .../ceres/block_random_access_crs_matrix.h | 108 ----------- .../block_random_access_crs_matrix_test.cc | 148 --------------- 4 files changed, 428 deletions(-) delete mode 100644 internal/ceres/block_random_access_crs_matrix.cc delete mode 100644 internal/ceres/block_random_access_crs_matrix.h delete mode 100644 internal/ceres/block_random_access_crs_matrix_test.cc diff --git a/internal/ceres/CMakeLists.txt b/internal/ceres/CMakeLists.txt index 7b7f21d..f077547 100644 --- a/internal/ceres/CMakeLists.txt +++ b/internal/ceres/CMakeLists.txt @@ -34,7 +34,6 @@ SET(CERES_INTERNAL_SRC block_evaluate_preparer.cc block_jacobi_preconditioner.cc block_jacobian_writer.cc - block_random_access_crs_matrix.cc block_random_access_dense_matrix.cc block_random_access_diagonal_matrix.cc block_random_access_matrix.cc @@ -224,7 +223,6 @@ IF (BUILD_TESTING AND GFLAGS) CERES_TEST(autodiff) CERES_TEST(autodiff_cost_function) CERES_TEST(autodiff_local_parameterization) - CERES_TEST(block_random_access_crs_matrix) CERES_TEST(block_random_access_dense_matrix) CERES_TEST(block_random_access_diagonal_matrix) CERES_TEST(block_random_access_sparse_matrix) diff --git a/internal/ceres/block_random_access_crs_matrix.cc b/internal/ceres/block_random_access_crs_matrix.cc deleted file mode 100644 index 5b008e2..0000000 --- a/internal/ceres/block_random_access_crs_matrix.cc +++ /dev/null @@ -1,170 +0,0 @@ -// Ceres Solver - A fast non-linear least squares minimizer -// Copyright 2013 Google Inc. All rights reserved. -// http://code.google.com/p/ceres-solver/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of Google Inc. nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Author: sameeragarwal@google.com (Sameer Agarwal) - -#include "ceres/block_random_access_crs_matrix.h" - -#include -#include -#include -#include -#include "ceres/compressed_row_sparse_matrix.h" -#include "ceres/internal/port.h" -#include "ceres/internal/scoped_ptr.h" -#include "ceres/mutex.h" -#include "ceres/triplet_sparse_matrix.h" -#include "ceres/types.h" -#include "glog/logging.h" - -namespace ceres { -namespace internal { - -BlockRandomAccessCRSMatrix::BlockRandomAccessCRSMatrix( - const vector& blocks, - const set >& block_pairs) - : kMaxRowBlocks(10 * 1000 * 1000), - blocks_(blocks) { - CHECK_LT(blocks.size(), kMaxRowBlocks); - - col_layout_.resize(blocks_.size(), 0); - row_strides_.resize(blocks_.size(), 0); - - // Build the row/column layout vector and count the number of scalar - // rows/columns. - int num_cols = 0; - for (int i = 0; i < blocks_.size(); ++i) { - col_layout_[i] = num_cols; - num_cols += blocks_[i]; - } - - // Walk the sparsity pattern and count the number of non-zeros. - int num_nonzeros = 0; - for (set >::const_iterator it = block_pairs.begin(); - it != block_pairs.end(); - ++it) { - const int row_block_size = blocks_[it->first]; - const int col_block_size = blocks_[it->second]; - num_nonzeros += row_block_size * col_block_size; - } - - VLOG(2) << "Matrix Size [" << num_cols - << "," << num_cols - << "] " << num_nonzeros; - - crsm_.reset(new CompressedRowSparseMatrix(num_cols, num_cols, num_nonzeros)); - int* rows = crsm_->mutable_rows(); - int* cols = crsm_->mutable_cols(); - double* values = crsm_->mutable_values(); - - // Iterate over the sparsity pattern and fill the scalar sparsity - // pattern of the underlying compressed sparse row matrix. Along the - // way also fill out the Layout object which will allow random - // access into the CRS Matrix. - set >::const_iterator it = block_pairs.begin(); - vector col_blocks; - int row_pos = 0; - rows[0] = 0; - while (it != block_pairs.end()) { - // Add entries to layout_ for all the blocks for this row. - col_blocks.clear(); - const int row_block_id = it->first; - const int row_block_size = blocks_[row_block_id]; - int num_cols = 0; - while ((it != block_pairs.end()) && (it->first == row_block_id)) { - layout_[IntPairToLong(it->first, it->second)] = - new CellInfo(values + num_cols); - col_blocks.push_back(it->second); - num_cols += blocks_[it->second]; - ++it; - }; - - // Count the number of non-zeros in the row block. - for (int j = 0; j < row_block_size; ++j) { - rows[row_pos + j + 1] = rows[row_pos + j] + num_cols; - } - - // Fill out the sparsity pattern for each row. - int col_pos = 0; - for (int j = 0; j < col_blocks.size(); ++j) { - const int col_block_id = col_blocks[j]; - const int col_block_size = blocks_[col_block_id]; - for (int r = 0; r < row_block_size; ++r) { - const int column_block_begin = rows[row_pos + r] + col_pos; - for (int c = 0; c < col_block_size; ++c) { - cols[column_block_begin + c] = col_layout_[col_block_id] + c; - } - } - col_pos += col_block_size; - } - - row_pos += row_block_size; - values += row_block_size * num_cols; - row_strides_[row_block_id] = num_cols; - } -} - -// Assume that the user does not hold any locks on any cell blocks -// when they are calling SetZero. -BlockRandomAccessCRSMatrix::~BlockRandomAccessCRSMatrix() { - // TODO(sameeragarwal) this should be rationalized going forward and - // perhaps moved into BlockRandomAccessMatrix. - for (LayoutType::iterator it = layout_.begin(); - it != layout_.end(); - ++it) { - delete it->second; - } -} - -CellInfo* BlockRandomAccessCRSMatrix::GetCell(int row_block_id, - int col_block_id, - int* row, - int* col, - int* row_stride, - int* col_stride) { - const LayoutType::iterator it = - layout_.find(IntPairToLong(row_block_id, col_block_id)); - if (it == layout_.end()) { - return NULL; - } - - *row = 0; - *col = 0; - *row_stride = blocks_[row_block_id]; - *col_stride = row_strides_[row_block_id]; - return it->second; -} - -// Assume that the user does not hold any locks on any cell blocks -// when they are calling SetZero. -void BlockRandomAccessCRSMatrix::SetZero() { - crsm_->SetZero(); -} - -} // namespace internal -} // namespace ceres diff --git a/internal/ceres/block_random_access_crs_matrix.h b/internal/ceres/block_random_access_crs_matrix.h deleted file mode 100644 index 11a203b..0000000 --- a/internal/ceres/block_random_access_crs_matrix.h +++ /dev/null @@ -1,108 +0,0 @@ -// Ceres Solver - A fast non-linear least squares minimizer -// Copyright 2013 Google Inc. All rights reserved. -// http://code.google.com/p/ceres-solver/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of Google Inc. nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Author: sameeragarwal@google.com (Sameer Agarwal) - -#ifndef CERES_INTERNAL_BLOCK_RANDOM_ACCESS_CRS_MATRIX_H_ -#define CERES_INTERNAL_BLOCK_RANDOM_ACCESS_CRS_MATRIX_H_ - -#include -#include -#include -#include "ceres/mutex.h" -#include "ceres/block_random_access_matrix.h" -#include "ceres/compressed_row_sparse_matrix.h" -#include "ceres/collections_port.h" -#include "ceres/integral_types.h" -#include "ceres/internal/macros.h" -#include "ceres/internal/port.h" -#include "ceres/internal/scoped_ptr.h" -#include "ceres/types.h" - -namespace ceres { -namespace internal { - -// A square BlockRandomAccessMatrix where the underlying storage is a -// compressed row sparse matrix. The matrix need not be symmetric. -class BlockRandomAccessCRSMatrix : public BlockRandomAccessMatrix { - public: - // blocks is an array of block sizes. block_pairs is a set of - // pairs to identify the non-zero cells - // of this matrix. - BlockRandomAccessCRSMatrix(const vector& blocks, - const set >& block_pairs); - - // The destructor is not thread safe. It assumes that no one is - // modifying any cells when the matrix is being destroyed. - virtual ~BlockRandomAccessCRSMatrix(); - - // BlockRandomAccessMatrix Interface. - virtual CellInfo* GetCell(int row_block_id, - int col_block_id, - int* row, - int* col, - int* row_stride, - int* col_stride); - - // This is not a thread safe method, it assumes that no cell is - // locked. - virtual void SetZero(); - - // Since the matrix is square, num_rows() == num_cols(). - virtual int num_rows() const { return crsm_->num_rows(); } - virtual int num_cols() const { return crsm_->num_cols(); } - - // Access to the underlying matrix object. - const CompressedRowSparseMatrix* matrix() const { return crsm_.get(); } - CompressedRowSparseMatrix* mutable_matrix() { return crsm_.get(); } - - private: - int64 IntPairToLong(int a, int b) { - return a * kMaxRowBlocks + b; - } - - const int64 kMaxRowBlocks; - // row/column block sizes. - const vector blocks_; - vector col_layout_; - vector row_strides_; - - // A mapping from to the position in - // the values array of tsm_ where the block is stored. - typedef HashMap LayoutType; - LayoutType layout_; - - scoped_ptr crsm_; - friend class BlockRandomAccessCRSMatrixTest; - CERES_DISALLOW_COPY_AND_ASSIGN(BlockRandomAccessCRSMatrix); -}; - -} // namespace internal -} // namespace ceres - -#endif // CERES_INTERNAL_BLOCK_RANDOM_ACCESS_CRS_MATRIX_H_ diff --git a/internal/ceres/block_random_access_crs_matrix_test.cc b/internal/ceres/block_random_access_crs_matrix_test.cc deleted file mode 100644 index 1266c4f..0000000 --- a/internal/ceres/block_random_access_crs_matrix_test.cc +++ /dev/null @@ -1,148 +0,0 @@ -// Ceres Solver - A fast non-linear least squares minimizer -// Copyright 2013 Google Inc. All rights reserved. -// http://code.google.com/p/ceres-solver/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of Google Inc. nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Author: sameeragarwal@google.com (Sameer Agarwal) - -#include -#include -#include "ceres/block_random_access_crs_matrix.h" -#include "ceres/internal/eigen.h" -#include "glog/logging.h" -#include "gtest/gtest.h" - -namespace ceres { -namespace internal { - -TEST(BlockRandomAccessCRSMatrix, GetCell) { - vector blocks; - blocks.push_back(3); - blocks.push_back(4); - blocks.push_back(5); - const int num_rows = 3 + 4 + 5; - - set< pair > block_pairs; - int num_nonzeros = 0; - block_pairs.insert(make_pair(0, 0)); - num_nonzeros += blocks[0] * blocks[0]; - - block_pairs.insert(make_pair(1, 1)); - num_nonzeros += blocks[1] * blocks[1]; - - block_pairs.insert(make_pair(1, 2)); - num_nonzeros += blocks[1] * blocks[2]; - - block_pairs.insert(make_pair(2, 0)); - num_nonzeros += blocks[2] * blocks[0]; - - BlockRandomAccessCRSMatrix m(blocks, block_pairs); - EXPECT_EQ(m.num_rows(), num_rows); - EXPECT_EQ(m.num_cols(), num_rows); - - for (set >::const_iterator it = block_pairs.begin(); - it != block_pairs.end(); - ++it) { - const int row_block_id = it->first; - const int col_block_id = it->second; - int row; - int col; - int row_stride; - int col_stride; - CellInfo* cell = m.GetCell(row_block_id, col_block_id, - &row, &col, - &row_stride, &col_stride); - EXPECT_TRUE(cell != NULL); - EXPECT_EQ(row, 0); - EXPECT_EQ(col, 0); - - // Write into the block. - MatrixRef(cell->values, row_stride, col_stride).block( - row, col, blocks[row_block_id], blocks[col_block_id]) = - (row_block_id + 1) * (col_block_id +1) * - Matrix::Ones(blocks[row_block_id], blocks[col_block_id]); - } - - const CompressedRowSparseMatrix* crsm = m.matrix(); - EXPECT_EQ(crsm->num_nonzeros(), num_nonzeros); - - Matrix dense; - crsm->ToDenseMatrix(&dense); - - double kTolerance = 1e-14; - - // (0,0) - EXPECT_NEAR((dense.block(0, 0, 3, 3) - Matrix::Ones(3, 3)).norm(), - 0.0, - kTolerance); - // (1,1) - EXPECT_NEAR((dense.block(3, 3, 4, 4) - 2 * 2 * Matrix::Ones(4, 4)).norm(), - 0.0, - kTolerance); - // (1,2) - EXPECT_NEAR((dense.block(3, 3 + 4, 4, 5) - 2 * 3 * Matrix::Ones(4, 5)).norm(), - 0.0, - kTolerance); - // (2,0) - EXPECT_NEAR((dense.block(3 + 4, 0, 5, 3) - 3 * 1 * Matrix::Ones(5, 3)).norm(), - 0.0, - kTolerance); - - // There is nothing else in the matrix besides these four blocks. - EXPECT_NEAR(dense.norm(), sqrt(9. + 16. * 16. + 36. * 20. + 9. * 15.), - kTolerance); -} - -// IntPairToLong is private, thus this fixture is needed to access and -// test it. -class BlockRandomAccessCRSMatrixTest : public ::testing::Test { - public: - virtual void SetUp() { - vector blocks; - blocks.push_back(1); - set< pair > block_pairs; - block_pairs.insert(make_pair(0, 0)); - m_.reset(new BlockRandomAccessCRSMatrix(blocks, block_pairs)); - } - - void CheckIntPair(int a, int b) { - int64 value = m_->IntPairToLong(a, b); - EXPECT_GT(value, 0) << "Overflow a = " << a << " b = " << b; - EXPECT_GT(value, a) << "Overflow a = " << a << " b = " << b; - EXPECT_GT(value, b) << "Overflow a = " << a << " b = " << b; - } - - private: - scoped_ptr m_; -}; - -TEST_F(BlockRandomAccessCRSMatrixTest, IntPairToLongOverflow) { - CheckIntPair(numeric_limits::max(), numeric_limits::max()); -} - - -} // namespace internal -} // namespace ceres From 1df2f0f5d704f0cc458cf707e2602d495979e3c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Piltz?= Date: Wed, 7 May 2014 11:10:30 +0200 Subject: [PATCH 08/10] Removed MSVC warnings These are warnings which show up when using Ceres. Change-Id: Id1f382f46b8a60743f0b12535b5b3cdf46f988e0 --- include/ceres/fpclassify.h | 6 +++--- include/ceres/local_parameterization.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/ceres/fpclassify.h b/include/ceres/fpclassify.h index e7f0d7c..da8a4d0 100644 --- a/include/ceres/fpclassify.h +++ b/include/ceres/fpclassify.h @@ -47,9 +47,9 @@ namespace ceres { #if defined(_MSC_VER) -inline bool IsFinite (double x) { return _finite(x); } -inline bool IsInfinite(double x) { return !_finite(x) && !_isnan(x); } -inline bool IsNaN (double x) { return _isnan(x); } +inline bool IsFinite (double x) { return _finite(x) != 0; } +inline bool IsInfinite(double x) { return _finite(x) == 0 && _isnan(x) == 0; } +inline bool IsNaN (double x) { return _isnan(x) != 0; } inline bool IsNormal (double x) { int classification = _fpclass(x); return classification == _FPCLASS_NN || diff --git a/include/ceres/local_parameterization.h b/include/ceres/local_parameterization.h index 3ecd959..0d74087 100644 --- a/include/ceres/local_parameterization.h +++ b/include/ceres/local_parameterization.h @@ -160,7 +160,7 @@ class CERES_EXPORT SubsetParameterization : public LocalParameterization { double* x_plus_delta) const; virtual bool ComputeJacobian(const double* x, double* jacobian) const; - virtual int GlobalSize() const { return constancy_mask_.size(); } + virtual int GlobalSize() const { return static_cast(constancy_mask_.size()); } virtual int LocalSize() const { return local_size_; } private: From 3209b045744ea31f38d74bd9e9c8f88e605e7f76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Piltz?= Date: Wed, 7 May 2014 17:02:27 +0200 Subject: [PATCH 09/10] Fixed warning : 'va_copy' : macro redefinition MSVC 2013 has got va_copy Compare http://msdn.microsoft.com/en-us/library/kb57fad8(v=vs.110).aspx and http://msdn.microsoft.com/en-us/library/kb57fad8.aspx. Change-Id: If0937c76e8d250cde4b343844f3d35c980bf0921 --- internal/ceres/stringprintf.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/ceres/stringprintf.cc b/internal/ceres/stringprintf.cc index eabdcb6..0f85f05 100644 --- a/internal/ceres/stringprintf.cc +++ b/internal/ceres/stringprintf.cc @@ -43,7 +43,9 @@ namespace internal { #ifdef _MSC_VER enum { IS_COMPILER_MSVC = 1 }; +#if _MSC_VER < 1800 #define va_copy(d, s) ((d) = (s)) +#endif #else enum { IS_COMPILER_MSVC = 0 }; #endif From cbf955474acf8f275b272da6ff5acd3a629cc806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Piltz?= Date: Wed, 7 May 2014 17:10:15 +0200 Subject: [PATCH 10/10] Fixes swapped verboselevel and condition. Change-Id: I296d86e6bbf415be4bfd19d6a0fe0963e3d36d74 --- internal/ceres/minimizer.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/ceres/minimizer.cc b/internal/ceres/minimizer.cc index a20eed5..6c3b68d 100644 --- a/internal/ceres/minimizer.cc +++ b/internal/ceres/minimizer.cc @@ -53,12 +53,12 @@ bool Minimizer::RunCallbacks(const Minimizer::Options& options, case SOLVER_TERMINATE_SUCCESSFULLY: summary->termination_type = USER_SUCCESS; summary->message = "User callback returned SOLVER_TERMINATE_SUCCESSFULLY."; - VLOG_IF(is_not_silent, 1) << "Terminating: " << summary->message; + VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message; return false; case SOLVER_ABORT: summary->termination_type = USER_FAILURE; summary->message = "User callback returned SOLVER_ABORT."; - VLOG_IF(is_not_silent, 1) << "Terminating: " << summary->message; + VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message; return false; default: LOG(FATAL) << "Unknown type of user callback status";