|
| 1 | +/** |
| 2 | + * @file SL4.cpp |
| 3 | + * @brief Projective Special Linear Group (PSL(4, R)) Pose |
| 4 | + * @author: Hyungtae Lim |
| 5 | + */ |
| 6 | + |
| 7 | +#include <gtsam/geometry/SL4.h> |
| 8 | + |
| 9 | +// To use exp(), log() |
| 10 | +#include <unsupported/Eigen/MatrixFunctions> |
| 11 | + |
| 12 | +using namespace std; |
| 13 | + |
| 14 | +namespace { |
| 15 | +Eigen::Matrix<double, 15, 15> I_15x15 = |
| 16 | + Eigen::Matrix<double, 15, 15>::Identity(); |
| 17 | + |
| 18 | +Eigen::Matrix<double, 16, 15> setVecToAlgMatrix() { |
| 19 | + Eigen::Matrix<double, 16, 15> alg = Eigen::Matrix<double, 16, 15>::Zero(); |
| 20 | + |
| 21 | + // 12 Off-diagonal E_ij generators |
| 22 | + int k = 0; |
| 23 | + for (int i = 0; i < 4; ++i) { |
| 24 | + for (int j = 0; j < 4; ++j) { |
| 25 | + if (i != j) { |
| 26 | + alg(i * 4 + j, k++) = 1.0; |
| 27 | + } |
| 28 | + } |
| 29 | + } |
| 30 | + |
| 31 | + // For Diagonal generators B1 = diag(1, -1, 0, 0) |
| 32 | + alg(0, 12) = 1.0; |
| 33 | + alg(5, 12) = -1.0; |
| 34 | + |
| 35 | + // For B2 = diag(0, 1, -1, 0) |
| 36 | + alg(5, 13) = 1.0; |
| 37 | + alg(10, 13) = -1.0; |
| 38 | + |
| 39 | + // For B3 = diag(0, 0, 1, -1) |
| 40 | + alg(10, 14) = 1.0; |
| 41 | + alg(15, 14) = -1.0; |
| 42 | + |
| 43 | + return alg; |
| 44 | +} |
| 45 | + |
| 46 | +Eigen::Matrix<double, 15, 16> setAlgtoVecMatrix() { |
| 47 | + Eigen::Matrix<double, 15, 16> mat; |
| 48 | + mat << 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., |
| 49 | + 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., |
| 50 | + 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., |
| 51 | + 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., |
| 52 | + 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., |
| 53 | + 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., |
| 54 | + 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., |
| 55 | + 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., |
| 56 | + 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., |
| 57 | + 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., |
| 58 | + 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 1., 0., 0., 0., 0., 0., |
| 59 | + 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1., 0., 0., |
| 60 | + 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., |
| 61 | + 0., 0., 0., 0., 0., -1.; |
| 62 | + return mat; |
| 63 | +} |
| 64 | + |
| 65 | +// ALG_TO_VEC * VEC_TO_ALG is equals to I_15x15 |
| 66 | +const Eigen::Matrix<double, 16, 15> VEC_TO_ALG = setVecToAlgMatrix(); |
| 67 | +const Eigen::Matrix<double, 15, 16> ALG_TO_VEC = setAlgtoVecMatrix(); |
| 68 | +} // namespace |
| 69 | +namespace gtsam { |
| 70 | + |
| 71 | +SL4::SL4(const Matrix44& pose) { |
| 72 | + double det = pose.determinant(); |
| 73 | + if (det <= 0.0) { |
| 74 | + throw std::runtime_error( |
| 75 | + "Matrix determinant must be positive for SL(4) normalization. Got det " |
| 76 | + "= " + |
| 77 | + std::to_string(det)); |
| 78 | + } |
| 79 | + |
| 80 | + T_ = pose / std::pow(det, 1.0 / 4.0); |
| 81 | +} |
| 82 | + |
| 83 | +/* ************************************************************************* */ |
| 84 | +void SL4::print(const std::string& s) const { cout << s << T_ << "\n"; } |
| 85 | + |
| 86 | +/* ************************************************************************* */ |
| 87 | +bool SL4::equals(const SL4& sl4, double tol) const { |
| 88 | + return T_.isApprox(sl4.T_, tol); |
| 89 | +} |
| 90 | +/* ************************************************************************* */ |
| 91 | +SL4 SL4::ChartAtOrigin::Retract(const Vector15& v, ChartJacobian H) { |
| 92 | + assert(v.size() == 15); |
| 93 | + SL4 retracted(I_4x4 + Hat(v)); |
| 94 | + if (H) throw std::runtime_error("SL4::Retract: Jacobian not implemented."); |
| 95 | + return retracted; |
| 96 | +} |
| 97 | + |
| 98 | +/* ************************************************************************* */ |
| 99 | +Vector15 SL4::ChartAtOrigin::Local(const SL4& sl4, ChartJacobian H) { |
| 100 | + Vector xi = Vee(sl4.T_ - I_4x4); |
| 101 | + if (H) throw std::runtime_error("SL4::Local: Jacobian not implemented."); |
| 102 | + return xi; |
| 103 | +} |
| 104 | + |
| 105 | +/* ************************************************************************* */ |
| 106 | +SL4 SL4::Expmap(const Vector& xi, SL4Jacobian H) { |
| 107 | + assert(xi.size() == 15); |
| 108 | + const auto& A = Hat(xi); |
| 109 | + |
| 110 | + if (H) throw std::runtime_error("SL4::Expmap: Jacobian not implemented."); |
| 111 | + |
| 112 | + // NOTE(hlim): |
| 113 | + // The cost of the computation is approximately 20n^3 for matrices of size n. |
| 114 | + // The number 20 depends weakly on the norm of the matrix. |
| 115 | + // See |
| 116 | + // https://eigen.tuxfamily.org/dox/unsupported/group__MatrixFunctions__Module.html |
| 117 | + |
| 118 | + return SL4(A.exp()); |
| 119 | +} |
| 120 | + |
| 121 | +/* ************************************************************************* */ |
| 122 | +Vector SL4::Logmap(const SL4& p, SL4Jacobian H) { |
| 123 | + if (H) throw std::runtime_error("SL4::Logmap: Jacobian not implemented."); |
| 124 | + return Vee(p.T_.log()); |
| 125 | +} |
| 126 | + |
| 127 | +/* ************************************************************************* */ |
| 128 | +Matrix15x15 SL4::AdjointMap() const { |
| 129 | + Matrix44 H_inv_T = T_.inverse().transpose(); |
| 130 | + Matrix16x16 C_H; |
| 131 | + |
| 132 | + // Kronecker product H ⊗ H^{-T} |
| 133 | + for (int i = 0; i < 4; ++i) |
| 134 | + for (int j = 0; j < 4; ++j) |
| 135 | + C_H.block<4, 4>(i * 4, j * 4) = T_(i, j) * H_inv_T; |
| 136 | + |
| 137 | + return ALG_TO_VEC * C_H * VEC_TO_ALG; |
| 138 | +} |
| 139 | + |
| 140 | +/* ************************************************************************* */ |
| 141 | +Matrix44 SL4::Hat(const Vector& xi) { |
| 142 | + assert(xi.size() == 15); |
| 143 | + Matrix44 A; |
| 144 | + const double d11 = xi(12); |
| 145 | + const double d22 = -xi(12) + xi(13); |
| 146 | + const double d33 = -xi(13) + xi(14); |
| 147 | + const double d44 = -xi(14); |
| 148 | + |
| 149 | + A << d11, xi(0), xi(1), xi(2), xi(3), d22, xi(4), xi(5), xi(6), xi(7), d33, |
| 150 | + xi(8), xi(9), xi(10), xi(11), d44; |
| 151 | + |
| 152 | + return A; |
| 153 | +} |
| 154 | + |
| 155 | +/* ************************************************************************* */ |
| 156 | +// NOTE(hlim): Why 'X'? - I just follow the convention of GTSAM |
| 157 | +Vector SL4::Vee(const Matrix44& X) { |
| 158 | + Vector vec(15); |
| 159 | + const double x12 = X(0, 0); |
| 160 | + const double x13 = X(1, 1) + x12; |
| 161 | + const double x14 = -X(3, 3); |
| 162 | + vec << X(0, 1), X(0, 2), X(0, 3), X(1, 0), X(1, 2), X(1, 3), X(2, 0), X(2, 1), |
| 163 | + X(2, 3), X(3, 0), X(3, 1), X(3, 2), x12, x13, x14; |
| 164 | + return vec; |
| 165 | +} |
| 166 | + |
| 167 | +} // namespace gtsam |
0 commit comments