gtsam_points
Loading...
Searching...
No Matches
jacobian_test.hpp
1// SPDX-FileCopyrightText: Copyright 2024 Kenji Koide
2// SPDX-License-Identifier: MIT
3#pragma once
4
5#include <random>
6#include <vector>
7#include <gtsam/linear/VectorValues.h>
8#include <gtsam/nonlinear/NonlinearFactor.h>
9
10namespace gtsam_points {
11
43template <typename GenerateFactor, typename GenerateValues>
44bool test_factor_jacobian(std::mt19937& mt, const GenerateFactor& generate_factor, const GenerateValues& generate_values) {
45 auto factor = generate_factor(mt);
46 gtsam::Values values = generate_values(mt);
47
48 std::vector<gtsam::Matrix> Hs_a(factor->keys().size());
49 std::vector<gtsam::Matrix> Hs_d(factor->keys().size());
50 gtsam::Vector x0 = factor->unwhitenedError(values, Hs_a);
51
52 const double eps = 1e-6;
53
54 for (int i = 0; i < factor->keys().size(); i++) {
55 const auto key = factor->keys()[i];
56 gtsam::VectorValues delta = values.zeroVectors();
57 const int D = delta[key].size();
58
59 gtsam::Matrix Hd(x0.size(), D);
60 for (int j = 0; j < D; j++) {
61 delta[key].setZero();
62 delta[key][j] = eps;
63
64 gtsam::Vector xi = factor->unwhitenedError(values.retract(delta));
65 Hd.col(j) = (xi - x0) / eps;
66 }
67
68 Hs_d[i] = Hd;
69 }
70
71 bool ok = true;
72 for (int i = 0; i < factor->keys().size(); i++) {
73 ok &= ((Hs_a[i] - Hs_d[i]).array().abs() < 1e-3).all();
74 }
75
76 if (ok) {
77 std::cout << "OK (x0=" << x0.transpose() << ")" << std::endl;
78 } else {
79 std::cout << "Failed (x0=" << x0.transpose() << ")" << std::endl;
80
81 for (int i = 0; i < factor->keys().size(); i++) {
82 std::cout << "*** key " << i << " ***" << std::endl;
83 std::cerr << "--- Ha ---" << std::endl << Hs_a[i] << std::endl;
84 std::cerr << "--- Hd ---" << std::endl << Hs_d[i] << std::endl;
85 std::cerr << "--- err ---" << std::endl << Hs_a[i] - Hs_d[i] << std::endl;
86 }
87 }
88
89 return ok;
90}
91
92} // namespace gtsam_points