Austin Schuh | 3de38b0 | 2024-06-25 18:25:10 -0700 | [diff] [blame^] | 1 | // Ceres Solver - A fast non-linear least squares minimizer |
| 2 | // Copyright 2023 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/constants.h" |
| 36 | #include "ceres/internal/householder_vector.h" |
| 37 | |
| 38 | // This module contains functions to compute the SphereManifold plus and minus |
| 39 | // operator and their Jacobians. |
| 40 | // |
| 41 | // As the parameters to these functions are shared between them, they are |
| 42 | // described here: The following variable names are used: |
| 43 | // Plus(x, delta) = x + delta = x_plus_delta, |
| 44 | // Minus(y, x) = y - x = y_minus_x. |
| 45 | // |
| 46 | // The remaining ones are v and beta which describe the Householder |
| 47 | // transformation of x, and norm_delta which is the norm of delta. |
| 48 | // |
| 49 | // The types of x, y, x_plus_delta and y_minus_x need to be equivalent to |
| 50 | // Eigen::Matrix<double, AmbientSpaceDimension, 1> and the type of delta needs |
| 51 | // to be equivalent to Eigen::Matrix<double, TangentSpaceDimension, 1>. |
| 52 | // |
| 53 | // The type of Jacobian plus needs to be equivalent to Eigen::Matrix<double, |
| 54 | // AmbientSpaceDimension, TangentSpaceDimension, Eigen::RowMajor> and for |
| 55 | // Jacobian minus Eigen::Matrix<double, TangentSpaceDimension, |
| 56 | // AmbientSpaceDimension, Eigen::RowMajor>. |
| 57 | // |
| 58 | // For all vector / matrix inputs and outputs, template parameters are |
| 59 | // used in order to allow also Eigen::Ref and Eigen block expressions to |
| 60 | // be passed to the function. |
| 61 | |
| 62 | namespace ceres::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 | const 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 sin_delta_by_delta = std::sin(norm_delta) / norm_delta; |
| 76 | |
| 77 | Eigen::Matrix<double, AmbientDim, 1> y(v.size()); |
| 78 | y << sin_delta_by_delta * delta, std::cos(norm_delta); |
| 79 | |
| 80 | // Apply the delta update to remain on the sphere. |
| 81 | *x_plus_delta = x.norm() * ApplyHouseholderVector(y, v, beta); |
| 82 | } |
| 83 | |
| 84 | template <typename VT, typename JacobianT> |
| 85 | inline void ComputeSphereManifoldPlusJacobian(const VT& x, |
| 86 | JacobianT* jacobian) { |
| 87 | constexpr int AmbientSpaceDim = VT::RowsAtCompileTime; |
| 88 | using AmbientVector = Eigen::Matrix<double, AmbientSpaceDim, 1>; |
| 89 | const int ambient_size = x.size(); |
| 90 | const int tangent_size = x.size() - 1; |
| 91 | |
| 92 | AmbientVector v(ambient_size); |
| 93 | double beta; |
| 94 | |
| 95 | // NOTE: The explicit template arguments are needed here because |
| 96 | // ComputeHouseholderVector is templated and some versions of MSVC |
| 97 | // have trouble deducing the type of v automatically. |
| 98 | ComputeHouseholderVector<VT, double, AmbientSpaceDim>(x, &v, &beta); |
| 99 | |
| 100 | // The Jacobian is equal to J = H.leftCols(size_ - 1) where H is the |
| 101 | // Householder matrix (H = I - beta * v * v'). |
| 102 | for (int i = 0; i < tangent_size; ++i) { |
| 103 | (*jacobian).col(i) = -beta * v(i) * v; |
| 104 | (*jacobian)(i, i) += 1.0; |
| 105 | } |
| 106 | (*jacobian) *= x.norm(); |
| 107 | } |
| 108 | |
| 109 | template <typename VT, typename XT, typename YT, typename YMinusXT> |
| 110 | inline void ComputeSphereManifoldMinus( |
| 111 | const VT& v, double beta, const XT& x, const YT& y, YMinusXT* y_minus_x) { |
| 112 | constexpr int AmbientSpaceDim = VT::RowsAtCompileTime; |
| 113 | constexpr int TangentSpaceDim = |
| 114 | AmbientSpaceDim == Eigen::Dynamic ? Eigen::Dynamic : AmbientSpaceDim - 1; |
| 115 | using AmbientVector = Eigen::Matrix<double, AmbientSpaceDim, 1>; |
| 116 | |
| 117 | const int tangent_size = v.size() - 1; |
| 118 | |
| 119 | const AmbientVector hy = ApplyHouseholderVector(y, v, beta) / x.norm(); |
| 120 | |
| 121 | // Calculate y - x. See B.2 p.25 equation (108). |
| 122 | const double y_last = hy[tangent_size]; |
| 123 | const double hy_norm = hy.template head<TangentSpaceDim>(tangent_size).norm(); |
| 124 | if (hy_norm == 0.0) { |
| 125 | y_minus_x->setZero(); |
| 126 | y_minus_x->data()[tangent_size - 1] = y_last >= 0 ? 0.0 : constants::pi; |
| 127 | } else { |
| 128 | *y_minus_x = std::atan2(hy_norm, y_last) / hy_norm * |
| 129 | hy.template head<TangentSpaceDim>(tangent_size); |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | template <typename VT, typename JacobianT> |
| 134 | inline void ComputeSphereManifoldMinusJacobian(const VT& x, |
| 135 | JacobianT* jacobian) { |
| 136 | constexpr int AmbientSpaceDim = VT::RowsAtCompileTime; |
| 137 | using AmbientVector = Eigen::Matrix<double, AmbientSpaceDim, 1>; |
| 138 | const int ambient_size = x.size(); |
| 139 | const int tangent_size = x.size() - 1; |
| 140 | |
| 141 | AmbientVector v(ambient_size); |
| 142 | double beta; |
| 143 | |
| 144 | // NOTE: The explicit template arguments are needed here because |
| 145 | // ComputeHouseholderVector is templated and some versions of MSVC |
| 146 | // have trouble deducing the type of v automatically. |
| 147 | ComputeHouseholderVector<VT, double, AmbientSpaceDim>(x, &v, &beta); |
| 148 | |
| 149 | // The Jacobian is equal to J = H.leftCols(size_ - 1) where H is the |
| 150 | // Householder matrix (H = I - beta * v * v'). |
| 151 | for (int i = 0; i < tangent_size; ++i) { |
| 152 | // NOTE: The transpose is used for correctness (the product is expected to |
| 153 | // be a row vector), although here there seems to be no difference between |
| 154 | // transposing or not for Eigen (possibly a compile-time auto fix). |
| 155 | (*jacobian).row(i) = -beta * v(i) * v.transpose(); |
| 156 | (*jacobian)(i, i) += 1.0; |
| 157 | } |
| 158 | (*jacobian) /= x.norm(); |
| 159 | } |
| 160 | |
| 161 | } // namespace ceres::internal |
| 162 | |
| 163 | #endif |