45template <
typename T,
typename S>
class Hessian {
48 std::vector<BlockCoordinates> get_block_coordinates(Graph<T, S> *graph) {
53 thrust::device_vector<BlockCoordinates> block_coords;
54 auto &f_desc = graph->get_factor_descriptors();
55 for (
auto &f : f_desc) {
56 f->get_hessian_block_coordinates(block_coords);
60 thrust::device, block_coords.begin(), block_coords.end(),
71 auto end_it = thrust::unique(
72 thrust::device, block_coords.begin(), block_coords.end(),
74 return (a.row == b.row) && (a.col == b.col);
78 block_coords.resize(end_it - block_coords.begin());
81 std::vector<BlockCoordinates> host_block_coords(block_coords.size());
82 thrust::copy(block_coords.begin(), block_coords.end(),
83 host_block_coords.begin());
84 return host_block_coords;
92 void build_indices(Graph<T, S> *graph,
93 const std::vector<BlockCoordinates> &block_coords) {
94 const auto num_columns = graph->get_num_block_columns();
95 csc::build_block_csc_indices(num_columns, block_indices, block_coords,
96 d_col_pointers, d_row_indices, d_offsets);
97 d_hessian_offsets = graph->get_offset_vector();
98 csc::build_scalar_to_block_map(d_hessian_offsets, num_columns,
102 void backup_diagonal(Graph<T, S> *graph,
StreamPool &streams) {
103 d_prev_diagonal.resize(graph->get_hessian_dimension());
105 auto diag = d_prev_diagonal.data().get();
106 const auto h_offsets = d_hessian_offsets.data().get();
107 const auto p_col = d_col_pointers.data().get();
108 const auto r_idx = d_row_indices.data().get();
109 const auto block_locations = d_offsets.data().get();
110 const auto h = d_hessian.data().get();
113 thrust::device, thrust::make_counting_iterator<size_t>(0),
114 thrust::make_counting_iterator<size_t>(graph->get_num_block_columns()),
115 [=] __device__(
size_t block_col) {
116 const size_t hessian_col = h_offsets[block_col];
117 const size_t dim = h_offsets[block_col + 1] - hessian_col;
121 const auto end = p_col[block_col + 1];
123 const auto b = end - 1;
126 if (r_idx[b] == block_col) {
128 const auto block = h + block_locations[b];
129 for (
size_t i = 0; i < dim; i++) {
130 diag[hessian_col + i] = block[i * dim + i];
136 void apply_damping(Graph<T, S> *graph, T damping_factor,
137 const bool use_identity,
StreamPool &streams) {
139 auto diag = d_prev_diagonal.data().get();
140 const auto h_offsets = d_hessian_offsets.data().get();
141 const auto p_col = d_col_pointers.data().get();
142 const auto r_idx = d_row_indices.data().get();
143 auto block_locations = d_offsets.data().get();
144 auto h = d_hessian.data().get();
147 thrust::device, thrust::make_counting_iterator<size_t>(0),
148 thrust::make_counting_iterator<size_t>(graph->get_num_block_columns()),
149 [=] __device__(
size_t block_col) {
150 const size_t hessian_col = h_offsets[block_col];
151 const size_t dim = h_offsets[block_col + 1] - hessian_col;
155 const auto end = p_col[block_col + 1];
156 const auto b = end - 1;
159 if (r_idx[b] == block_col) {
161 auto block = h + block_locations[b];
162 for (
size_t i = 0; i < dim; i++) {
163 const auto h_diag = diag[hessian_col + i];
166 (S)((
double)h_diag + (
double)damping_factor);
171 std::clamp((
double)h_diag, 1.0e-6, 1.0e32));
178 void setup_hessian_computation(Graph<T, S> *graph,
StreamPool &streams) {
185 const auto &factors = graph->get_factor_descriptors();
186 size_t mul_count = 0;
187 for (
auto &f : factors) {
188 const size_t num_vertices = f->get_num_descriptors();
189 for (
size_t i = 0; i < num_vertices; i++) {
190 for (
size_t j = i; j < num_vertices; j++) {
191 mul_count += f->active_count();
196 h_block_offsets.resize(mul_count);
200 for (
auto &f : factors) {
201 mul_count += f->setup_hessian_computation(
202 block_indices, d_hessian, h_block_offsets.data() + mul_count,
207 d_block_offsets = h_block_offsets;
210 void execute_hessian_computation(Graph<T, S> *graph,
StreamPool &streams) {
211 thrust::fill(thrust::device, d_hessian.begin(), d_hessian.end(),
212 static_cast<S
>(0.0));
213 size_t mul_count = 0;
214 const auto &factors = graph->get_factor_descriptors();
215 for (
auto &f : factors) {
216 mul_count += f->execute_hessian_computation(
217 block_indices, d_hessian, d_block_offsets.data().get() + mul_count,
223 std::unordered_map<BlockCoordinates, size_t> block_indices;
224 thrust::device_vector<S> d_hessian;
225 thrust::device_vector<size_t> d_col_pointers;
226 thrust::device_vector<size_t> d_row_indices;
227 thrust::device_vector<size_t> d_offsets;
228 thrust::device_vector<S> d_prev_diagonal;
229 thrust::device_vector<size_t> d_hessian_offsets;
230 thrust::device_vector<size_t> scalar_to_block_map;
233 thrust::host_vector<size_t> h_block_offsets;
234 thrust::device_vector<size_t> d_block_offsets;
239 const thrust::device_vector<size_t> &get_block_col_pointers()
const {
240 return d_col_pointers;
243 const thrust::device_vector<size_t> &get_block_row_indices()
const {
244 return d_row_indices;
247 const thrust::device_vector<size_t> &get_block_value_offsets()
const {
251 const thrust::device_vector<S> &get_values()
const {
return d_hessian; }
253 S *get_values_ptr() {
return d_hessian.data().get(); }
255 const S *get_values_ptr()
const {
return d_hessian.data().get(); }
257 void build_structure(Graph<T, S> *graph,
StreamPool &streams) {
264 const auto block_coords = get_block_coordinates(graph);
270 size_t num_values = 0;
271 block_indices.clear();
272 block_indices.reserve(block_coords.size());
273 for (
const auto &coord : block_coords) {
274 block_indices[coord] = num_values;
275 num_values += graph->get_variable_dimension(coord.row) *
276 graph->get_variable_dimension(coord.col);
278 d_hessian.resize(num_values);
284 build_indices(graph, block_coords);
287 setup_hessian_computation(graph, streams);
290 void update_values(Graph<T, S> *graph,
StreamPool &streams) {
295 execute_hessian_computation(graph, streams);
306 backup_diagonal(graph, streams);
309 template <
typename I>
310 void build_csc_structure(Graph<T, S> *graph, CSCMatrix<S, I> &matrix) {
311 const auto hessian_dim = graph->get_hessian_dimension();
312 csc::build_scalar_csc_structure<S, I>(hessian_dim, d_col_pointers,
313 d_row_indices, d_hessian_offsets,
314 scalar_to_block_map, matrix);
317 template <
typename I>
318 void update_csc_values(Graph<T, S> *graph, CSCMatrix<S, I> &matrix) {
319 const auto hessian_dim = graph->get_hessian_dimension();
320 csc::update_scalar_csc_values<S, I>(
321 hessian_dim, d_hessian, d_col_pointers, d_row_indices, d_offsets,
322 d_hessian_offsets, scalar_to_block_map, matrix);