Factor_GenericPrior.cpp
Go to the documentation of this file.
1 /*
2  * OpenVINS: An Open Platform for Visual-Inertial Research
3  * Copyright (C) 2018-2023 Patrick Geneva
4  * Copyright (C) 2018-2023 Guoquan Huang
5  * Copyright (C) 2018-2023 OpenVINS Contributors
6  * Copyright (C) 2018-2019 Kevin Eckenhoff
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include "Factor_GenericPrior.h"
23 
24 #include "utils/quat_ops.h"
25 
26 using namespace ov_init;
27 
28 Factor_GenericPrior::Factor_GenericPrior(const Eigen::MatrixXd &x_lin_, const std::vector<std::string> &x_type_,
29  const Eigen::MatrixXd &prior_Info, const Eigen::MatrixXd &prior_grad)
30  : x_lin(x_lin_), x_type(x_type_) {
31 
32  // First assert that our state and variables are of the correct size
33  int state_size = 0;
34  int state_error_size = 0;
35  for (auto const &str : x_type_) {
36  if (str == "quat") {
37  state_size += 4;
38  state_error_size += 3;
39  } else if (str == "quat_yaw") {
40  state_size += 4;
41  state_error_size += 1;
42  } else if (str == "vec1") {
43  state_size += 1;
44  state_error_size += 1;
45  } else if (str == "vec3") {
46  state_size += 3;
47  state_error_size += 3;
48  } else if (str == "vec8") {
49  state_size += 8;
50  state_error_size += 8;
51  } else {
52  std::cerr << "type - " << str << " not implemented in prior" << std::endl;
53  std::exit(EXIT_FAILURE);
54  }
55  }
56  assert(x_lin.rows() == state_size);
57  assert(x_lin.cols() == 1);
58  assert(prior_Info.rows() == state_error_size);
59  assert(prior_Info.cols() == state_error_size);
60  assert(prior_grad.rows() == state_error_size);
61  assert(prior_grad.cols() == 1);
62 
63  // Now lets base-compute the square-root information and constant term b
64  // Comes from the form: cost = A * (x - x_lin) + b
65  Eigen::LLT<Eigen::MatrixXd> lltOfI(prior_Info);
66  sqrtI = lltOfI.matrixL().transpose();
67  Eigen::MatrixXd I = Eigen::MatrixXd::Identity(prior_Info.rows(), prior_Info.rows());
68  b = sqrtI.triangularView<Eigen::Upper>().solve(I) * prior_grad;
69 
70  // Check that we have a valid matrix that we can get the information of
71  if (std::isnan(prior_Info.norm()) || std::isnan(sqrtI.norm()) || std::isnan(b.norm())) {
72  std::cerr << "prior_Info - " << std::endl << prior_Info << std::endl << std::endl;
73  std::cerr << "prior_Info_inv - " << std::endl << prior_Info.inverse() << std::endl << std::endl;
74  std::cerr << "b - " << std::endl << b << std::endl << std::endl;
75  std::exit(EXIT_FAILURE);
76  }
77 
78  // Set the number of measurements, and the block sized
79  set_num_residuals(state_error_size);
80  for (auto const &str : x_type_) {
81  if (str == "quat")
82  mutable_parameter_block_sizes()->push_back(4);
83  if (str == "quat_yaw")
84  mutable_parameter_block_sizes()->push_back(4);
85  if (str == "vec1")
86  mutable_parameter_block_sizes()->push_back(1);
87  if (str == "vec3")
88  mutable_parameter_block_sizes()->push_back(3);
89  if (str == "vec8")
90  mutable_parameter_block_sizes()->push_back(8);
91  }
92 }
93 
94 bool Factor_GenericPrior::Evaluate(double const *const *parameters, double *residuals, double **jacobians) const {
95 
96  // Location in our state and output residual
97  int local_it = 0;
98  int global_it = 0;
99  Eigen::MatrixXd res = Eigen::MatrixXd::Zero(num_residuals(), 1);
100 
101  // Loop through each state and calculate its residual and Jacobian
102  for (size_t i = 0; i < x_type.size(); i++) {
103  if (x_type[i] == "quat") {
104  Eigen::Vector4d q_i = Eigen::Map<const Eigen::Vector4d>(parameters[i]);
105  Eigen::Matrix3d R_i = ov_core::quat_2_Rot(q_i);
106  Eigen::Matrix3d R_lin = ov_core::quat_2_Rot(x_lin.block(global_it, 0, 4, 1));
107  Eigen::Vector3d theta_err = ov_core::log_so3(R_i.transpose() * R_lin);
108  res.block(local_it, 0, 3, 1) = -theta_err;
109  if (jacobians && jacobians[i]) {
110  Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> jacobian(jacobians[i], num_residuals(), 4);
111  jacobian.setZero();
112  Eigen::Matrix3d Jr_inv = ov_core::Jr_so3(theta_err).inverse();
113  Eigen::Matrix3d H_theta = -Jr_inv * R_lin.transpose();
114  jacobian.block(0, 0, num_residuals(), 3) = sqrtI.block(0, local_it, num_residuals(), 3) * H_theta;
115  }
116  global_it += 4;
117  local_it += 3;
118  } else if (x_type[i] == "quat_yaw") {
119  Eigen::Vector3d ez = Eigen::Vector3d(0.0, 0.0, 1.0);
120  Eigen::Vector4d q_i = Eigen::Map<const Eigen::Vector4d>(parameters[i]);
121  Eigen::Matrix3d R_i = ov_core::quat_2_Rot(q_i);
122  Eigen::Matrix3d R_lin = ov_core::quat_2_Rot(x_lin.block(global_it, 0, 4, 1));
123  Eigen::Vector3d theta_err = ov_core::log_so3(R_i.transpose() * R_lin);
124  res(local_it, 0) = -(ez.transpose() * theta_err)(0, 0);
125  if (jacobians && jacobians[i]) {
126  Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> jacobian(jacobians[i], num_residuals(), 4);
127  jacobian.setZero();
128  Eigen::Matrix3d Jr_inv = ov_core::Jr_so3(theta_err).inverse();
129  Eigen::Matrix<double, 1, 3> H_theta = -ez.transpose() * (Jr_inv * R_lin.transpose());
130  jacobian.block(0, 0, num_residuals(), 3) = sqrtI.block(0, local_it, num_residuals(), 1) * H_theta;
131  }
132  global_it += 4;
133  local_it += 1;
134  } else if (x_type[i] == "vec1") {
135  double x = parameters[i][0];
136  res(local_it, 0) = x - x_lin(global_it, 0);
137  if (jacobians && jacobians[i]) {
138  Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> J_vi(jacobians[i], num_residuals(), 1);
139  J_vi.block(0, 0, num_residuals(), 1) = sqrtI.block(0, local_it, num_residuals(), 1);
140  }
141  global_it += 1;
142  local_it += 1;
143  } else if (x_type[i] == "vec3") {
144  Eigen::Matrix<double, 3, 1> p_i = Eigen::Map<const Eigen::Matrix<double, 3, 1>>(parameters[i]);
145  res.block(local_it, 0, 3, 1) = p_i - x_lin.block(global_it, 0, 3, 1);
146  if (jacobians && jacobians[i]) {
147  Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> jacobian(jacobians[i], num_residuals(), 3);
148  jacobian.block(0, 0, num_residuals(), 3) = sqrtI.block(0, local_it, num_residuals(), 3);
149  }
150  global_it += 3;
151  local_it += 3;
152  } else if (x_type[i] == "vec8") {
153  Eigen::Matrix<double, 8, 1> p_i = Eigen::Map<const Eigen::Matrix<double, 8, 1>>(parameters[i]);
154  res.block(local_it, 0, 8, 1) = p_i - x_lin.block(global_it, 0, 8, 1);
155  if (jacobians && jacobians[i]) {
156  Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> jacobian(jacobians[i], num_residuals(), 8);
157  jacobian.block(0, 0, num_residuals(), 8) = sqrtI.block(0, local_it, num_residuals(), 8);
158  }
159  global_it += 8;
160  local_it += 8;
161  } else {
162  std::cerr << "type - " << x_type[i] << " not implemented in prior" << std::endl;
163  std::exit(EXIT_FAILURE);
164  }
165  }
166 
167  // Now that we have done x - x_lin we need to multiply by sqrtI and add b to get full cost
168  // Jacobians will already have sqrtI applied to them...
169  res = sqrtI * res;
170  res += b;
171 
172  // Store the residuals into ceres
173  for (int i = 0; i < res.rows(); i++) {
174  residuals[i] = res(i, 0);
175  }
176  return true;
177 }
ov_core::Jr_so3
Eigen::Matrix< double, 3, 3 > Jr_so3(const Eigen::Matrix< double, 3, 1 > &w)
quat_ops.h
ov_init::Factor_GenericPrior::Evaluate
bool Evaluate(double const *const *parameters, double *residuals, double **jacobians) const override
Error residual and Jacobian calculation.
Definition: Factor_GenericPrior.cpp:94
ov_init::Factor_GenericPrior::sqrtI
Eigen::MatrixXd sqrtI
The square-root of the information s.t. sqrtI^T * sqrtI = marginal information.
Definition: Factor_GenericPrior.h:81
ov_init::Factor_GenericPrior::x_lin
Eigen::MatrixXd x_lin
State estimates at the time of marginalization to linearize the problem.
Definition: Factor_GenericPrior.h:75
ov_init
State initialization code.
Definition: Factor_GenericPrior.h:27
ov_core::quat_2_Rot
Eigen::Matrix< double, 3, 3 > quat_2_Rot(const Eigen::Matrix< double, 4, 1 > &q)
Factor_GenericPrior.h
ov_init::Factor_GenericPrior::Factor_GenericPrior
Factor_GenericPrior(const Eigen::MatrixXd &x_lin_, const std::vector< std::string > &x_type_, const Eigen::MatrixXd &prior_Info, const Eigen::MatrixXd &prior_grad)
Default constructor.
Definition: Factor_GenericPrior.cpp:28
ov_init::Factor_GenericPrior::b
Eigen::MatrixXd b
Constant term inside the cost s.t. sqrtI^T * b = marginal gradient (can be zero)
Definition: Factor_GenericPrior.h:84
ov_core::log_so3
Eigen::Matrix< double, 3, 1 > log_so3(const Eigen::Matrix< double, 3, 3 > &R)
ov_init::Factor_GenericPrior::x_type
std::vector< std::string > x_type
State type for each variable in x_lin. Can be [quat, quat_yaw, vec3, vec8].
Definition: Factor_GenericPrior.h:78


ov_init
Author(s): Patrick Geneva , Kevin Eckenhoff , Guoquan Huang
autogenerated on Mon Dec 16 2024 03:06:51