30template <
typename T,
typename S>
class Graph {
33 std::vector<BaseVertexDescriptor<T, S> *> vertex_descriptors;
34 std::vector<BaseFactorDescriptor<T, S> *> factor_descriptors;
35 thrust::host_vector<GlobalToLocalEntry> global_to_local_combined;
36 thrust::device_vector<GlobalToLocalEntry> d_global_to_local_combined;
37 thrust::device_vector<T> b;
38 thrust::device_vector<T> jacobian_scales;
39 size_t hessian_column;
40 std::vector<size_t> hessian_offsets;
42 size_t elimination_block;
45 Graph() : scale_jacobians(
true) {}
47 size_t get_hessian_dimension()
const {
return hessian_column; }
48 size_t get_variable_dimension(
const size_t block_index)
const {
49 return hessian_offsets[block_index + 1] - hessian_offsets[block_index];
51 size_t get_num_block_columns()
const {
return hessian_offsets.size() - 1; }
53 const std::vector<size_t> &get_offset_vector()
const {
54 return hessian_offsets;
57 thrust::device_vector<T> &get_b() {
return b; }
59 std::vector<BaseVertexDescriptor<T, S> *> &get_vertex_descriptors() {
60 return vertex_descriptors;
63 std::vector<BaseFactorDescriptor<T, S> *> &get_factor_descriptors() {
64 return factor_descriptors;
67 thrust::device_vector<T> &get_jacobian_scales() {
return jacobian_scales; }
69 template <
typename V>
void add_vertex_descriptor(V *descriptor) {
70 vertex_descriptors.push_back(descriptor);
73 template <
typename F>
void add_factor_descriptor(F *factor) {
74 factor_descriptors.push_back(factor);
77 template <
typename D>
void add_descriptor(D *descriptor) {
78 if constexpr (std::is_base_of<BaseVertexDescriptor<T, S>, D>::value) {
79 add_vertex_descriptor(descriptor);
80 }
else if constexpr (std::is_base_of<BaseFactorDescriptor<T, S>,
82 add_factor_descriptor(descriptor);
84 static_assert(std::is_base_of<BaseVertexDescriptor<T, S>, D>::value ||
85 std::is_base_of<BaseFactorDescriptor<T, S>, D>::value,
86 "You tried to add something strange to the graph.");
90 size_t get_elimination_block_column()
const {
return elimination_block; }
92 bool initialize_optimization(
const uint8_t level) {
97 global_to_local_combined.clear();
98 d_global_to_local_combined.clear();
100 for (
size_t i = 0; i < vertex_descriptors.size(); ++i) {
101 const auto &map = vertex_descriptors[i]->get_global_map();
102 const bool eliminated = vertex_descriptors[i]->get_eliminate();
103 for (
const auto &entry : map) {
104 global_to_local_combined.push_back(
110 d_global_to_local_combined = global_to_local_combined;
112 thrust::sort(thrust::device, d_global_to_local_combined.begin(),
113 d_global_to_local_combined.end(),
116 if (a.eliminated != b.eliminated) {
117 return !a.eliminated;
119 return a.global_id < b.global_id;
122 global_to_local_combined = d_global_to_local_combined;
125 for (
auto &desc : factor_descriptors) {
126 desc->initialize_device_ids(level);
128 deactivate_unused_vertices(level);
132 size_t hessian_block_index = 0;
133 hessian_offsets.clear();
134 elimination_block = std::numeric_limits<size_t>::max();
135 for (
const auto &entry : global_to_local_combined) {
136 if (vertex_descriptors[entry.descriptor_index]->is_active(
138 if (vertex_descriptors[entry.descriptor_index]->get_eliminate()) {
139 elimination_block = std::min(elimination_block, hessian_block_index);
141 vertex_descriptors[entry.descriptor_index]->set_hessian_column(
142 entry.global_id, hessian_column, hessian_block_index);
143 hessian_offsets.push_back(hessian_column);
145 vertex_descriptors[entry.descriptor_index]->dimension();
146 hessian_block_index++;
149 hessian_offsets.push_back(hessian_column);
152 for (
auto &desc : vertex_descriptors) {
157 for (
auto &desc : factor_descriptors) {
162 for (
auto &f : factor_descriptors) {
163 f->initialize_jacobian_storage();
171 void deactivate_unused_vertices(
const uint8_t level) {
174 for (
size_t i = 0; i < vertex_descriptors.size(); ++i) {
175 if (vertex_descriptors[i]->count() == 0) {
176 std::cerr <<
"Error: Vertex descriptor " << i <<
" has no entries."
181 for (
size_t i = 0; i < factor_descriptors.size(); ++i) {
182 if (factor_descriptors[i]->active_count() == 0) {
183 std::cerr <<
"Error: Factor descriptor " << i <<
" has no entries."
189 for (
auto &desc : vertex_descriptors) {
191 thrust::cuda::par_nosync.on(0), desc->get_active_state(),
192 desc->get_active_state() + desc->count(), desc->get_active_state(),
193 [] __device__(uint8_t state) {
return state & 0x7F; });
198 for (
auto &desc : factor_descriptors) {
199 desc->flag_active_vertices_async(level);
203 for (
auto &desc : vertex_descriptors) {
205 thrust::cuda::par_nosync.on(0), desc->get_active_state(),
206 desc->get_active_state() + desc->count(), desc->get_active_state(),
207 [] __device__(uint8_t state) {
return state ^ 0x80; });
209 cudaStreamSynchronize(0);
212 bool build_structure() {
214 const auto size_x = get_hessian_dimension();
216 jacobian_scales.resize(size_x);
221 void compute_error() {
222 for (
auto &factor : factor_descriptors) {
223 factor->compute_error();
225 cudaStreamSynchronize(0);
229 T chi2 =
static_cast<T
>(0);
230 for (
auto &factor : factor_descriptors) {
231 chi2 += factor->chi2();
238 for (
auto &factor : factor_descriptors) {
240 if (factor->use_autodiff() && (factor->store_jacobians() ||
241 !factor->supports_dynamic_jacobians())) {
242 factor->compute_error_autodiff(streams);
244 factor->compute_error();
245 factor->compute_jacobians(streams);
248 cudaStreamSynchronize(0);
254 if (scale_jacobians) {
255 thrust::fill(jacobian_scales.begin(), jacobian_scales.end(), 0);
256 for (
auto &factor : factor_descriptors) {
257 factor->compute_hessian_scalar_diagonal_async(
258 jacobian_scales.data().get(),
nullptr);
260 cudaStreamSynchronize(0);
263 thrust::device, jacobian_scales.begin(), jacobian_scales.end(),
264 jacobian_scales.begin(), [] __device__(T value) {
266 const double denom = std::numeric_limits<double>::epsilon() +
267 sqrt(
static_cast<double>(value));
269 return static_cast<T
>(1.0 / denom);
272 thrust::fill(jacobian_scales.begin(), jacobian_scales.end(), 1.0);
276 if (scale_jacobians) {
277 for (
auto &factor : factor_descriptors) {
278 factor->scale_jacobians_async(jacobian_scales.data().get());
280 cudaStreamSynchronize(0);
284 thrust::fill(thrust::cuda::par_nosync.on(0), b.begin(), b.end(), 0);
285 for (
auto &fd : factor_descriptors) {
286 fd->compute_b_async(b.data().get(), jacobian_scales.data().get());
289 cudaStreamSynchronize(0);
292 void apply_update(
const T *delta_x,
StreamPool &streams) {
294 for (
auto &desc : vertex_descriptors) {
295 desc->apply_update_async(delta_x, jacobian_scales.data().get(),
302 void backup_parameters() {
304 for (
const auto &desc : vertex_descriptors) {
305 desc->backup_parameters_async();
308 cudaStreamSynchronize(0);
311 void revert_parameters() {
313 for (
auto &desc : vertex_descriptors) {
314 desc->restore_parameters_async();
317 cudaStreamSynchronize(0);
321 vertex_descriptors.clear();
322 factor_descriptors.clear();
323 global_to_local_combined.clear();
324 d_global_to_local_combined.clear();
326 jacobian_scales.clear();
328 hessian_offsets.clear();
331 void scale_system(
const bool enable_scaling) {
332 scale_jacobians = enable_scaling;