ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
CutPursuit_Linear.h
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #pragma once
9 
10 #include "CutPursuit.h"
11 
12 namespace CP {
13 template <typename T>
14 struct CutPursuit_Linear : public CutPursuit<T> {
15  std::vector<std::vector<T>> componentVector;
16 
17  // only used with backward step - the sum of all observation in the
18  // component
19  CutPursuit_Linear(uint32_t nbVertex = 1) : CutPursuit<T>(nbVertex) {
20  this->componentVector = std::vector<std::vector<T>>(1);
21  }
22 
23  std::pair<T, T> compute_energy() override {
24  VertexAttributeMap<T> vertex_attribute_map =
25  boost::get(boost::vertex_bundle, this->main_graph);
26  EdgeAttributeMap<T> edge_attribute_map =
27  boost::get(boost::edge_bundle, this->main_graph);
28  std::pair<T, T> pair_energy;
29  T energy = 0;
30  VertexIterator<T> i_ver;
31  // #pragma omp parallel for private(i_ver) if (this->parameter.parallel)
32  for (i_ver = boost::vertices(this->main_graph).first;
33  i_ver != this->lastIterator; ++i_ver) {
34  for (uint32_t i_dim = 0; i_dim < this->dim; i_dim++) {
35  energy -= vertex_attribute_map(*i_ver).weight *
36  vertex_attribute_map(*i_ver).observation[i_dim] *
37  vertex_attribute_map(*i_ver).value[i_dim];
38  }
39  }
40  pair_energy.first = energy;
41  energy = 0;
42  EdgeIterator<T> i_edg,
43  i_edg_end = boost::edges(this->main_graph).second;
44  for (i_edg = boost::edges(this->main_graph).first; i_edg != i_edg_end;
45  ++i_edg) {
46  if (!edge_attribute_map(*i_edg).realEdge) {
47  continue;
48  }
49  energy += .5 * edge_attribute_map(*i_edg).isActive *
50  this->parameter.reg_strenth *
51  edge_attribute_map(*i_edg).weight;
52  }
53  pair_energy.second = energy;
54  return pair_energy;
55  }
56 
57  //=============================================================================================
58  //============================= SPLIT
59  //===========================================
60  //=============================================================================================
61  size_t split()
62  override { // split the graph by trying to find the best binary
63  // partition each components is split into B and notB
64  // initialize h_1 and h_2 with kmeans
65  //--------initilializing
66  // labels------------------------------------------------------------
67  // corner contains the two most likely class for each component
68  std::vector<std::vector<uint32_t>> corners =
69  std::vector<std::vector<uint32_t>>(this->components.size(),
70  std::vector<uint32_t>(2, 0));
71  this->compute_corners(corners);
72  this->set_capacities(corners);
73  // compute flow
74  boost::boykov_kolmogorov_max_flow(
75  this->main_graph,
80  get(boost::vertex_index, this->main_graph), this->source,
81  this->sink);
82  size_t saturation = this->activate_edges();
83  return saturation;
84  }
85 
86  //=============================================================================================
87  //============================= COMPUTE CORNERS
88  //===================================
89  //=============================================================================================
90  inline void compute_corners(
91  std::vector<std::vector<uint32_t>>&
92  corners) { //-----compute the 2 most populous
93  // labels------------------------------ #pragma
94  // omp parallel for if
95  // (this->parameter.parallel) schedule(dynamic)
96  for (uint32_t i_com = 0; i_com < this->components.size(); i_com++) {
97  if (this->saturated_components[i_com]) {
98  continue;
99  }
100  std::pair<uint32_t, uint32_t> corners_pair = find_corner(i_com);
101  corners[i_com][0] = corners_pair.first;
102  corners[i_com][1] = corners_pair.second;
103  }
104  }
105 
106  //=============================================================================================
107  //============================= find_corner
108  //=======================================
109  //=============================================================================================
110  std::pair<uint32_t, uint32_t> find_corner(const uint32_t& i_com) {
111  // given a component will output the pairs of the two most likely labels
112  VertexAttributeMap<T> vertex_attribute_map =
113  boost::get(boost::vertex_bundle, this->main_graph);
114  std::vector<T> average_vector(this->dim, 0);
115  for (uint32_t i_ver = 0; i_ver < this->components[i_com].size();
116  i_ver++) {
117  for (uint32_t i_dim = 0; i_dim < this->dim; i_dim++) {
118  average_vector.at(i_dim) +=
119  vertex_attribute_map[this->components[i_com][i_ver]]
120  .observation[i_dim] *
121  vertex_attribute_map[this->components[i_com][i_ver]]
122  .weight;
123  }
124  }
125  uint32_t indexOfMax = 0;
126  for (uint32_t i_dim = 1; i_dim < this->dim; i_dim++) {
127  if (average_vector.at(indexOfMax) < average_vector.at(i_dim)) {
128  indexOfMax = i_dim;
129  }
130  }
131  average_vector[indexOfMax] = -1;
132  uint32_t indexOfSndMax = 0;
133  for (uint32_t i_dim = 1; i_dim < this->dim; i_dim++) {
134  if (average_vector[indexOfSndMax] < average_vector[i_dim]) {
135  indexOfSndMax = i_dim;
136  }
137  }
138  return std::pair<uint32_t, uint32_t>(indexOfMax, indexOfSndMax);
139  }
140 
141  //=============================================================================================
142  //============================= SET_CAPACITIES
143  //=======================================
144  //=============================================================================================
145  inline void set_capacities(
146  const std::vector<std::vector<uint32_t>>& corners) {
147  VertexDescriptor<T> desc_v;
148  EdgeDescriptor desc_source2v, desc_v2sink, desc_v2source;
149  VertexAttributeMap<T> vertex_attribute_map =
150  boost::get(boost::vertex_bundle, this->main_graph);
151  EdgeAttributeMap<T> edge_attribute_map =
152  boost::get(boost::edge_bundle, this->main_graph);
153  T cost_B, cost_notB; // the cost of being in B or not B, local for each
154  // component
155  //----first compute the capacity in sink/node
156  // edges------------------------------------ #pragma omp parallel for if
157  //(this->parameter.parallel) schedule(dynamic)
158  for (uint32_t i_com = 0; i_com < this->components.size(); i_com++) {
159  if (this->saturated_components[i_com]) {
160  continue;
161  }
162  for (uint32_t i_ver = 0; i_ver < this->components[i_com].size();
163  i_ver++) {
164  desc_v = this->components[i_com][i_ver];
165  // because of the adjacency structure NEVER access edge
166  // (source,v) directly!
167  desc_v2source =
168  boost::edge(desc_v, this->source, this->main_graph)
169  .first;
170  desc_source2v =
171  edge_attribute_map(desc_v2source)
172  .edge_reverse; // use edge_reverse instead
173  desc_v2sink =
174  boost::edge(desc_v, this->sink, this->main_graph).first;
175  cost_B = 0;
176  cost_notB = 0;
177  if (vertex_attribute_map(desc_v).weight == 0) {
178  edge_attribute_map(desc_source2v).capacity = 0;
179  edge_attribute_map(desc_v2sink).capacity = 0;
180  continue;
181  }
182  cost_B += vertex_attribute_map(desc_v)
183  .observation[corners[i_com][0]];
184  cost_notB += vertex_attribute_map(desc_v)
185  .observation[corners[i_com][1]];
186  if (cost_B > cost_notB) {
187  edge_attribute_map(desc_source2v).capacity =
188  cost_B - cost_notB;
189  edge_attribute_map(desc_v2sink).capacity = 0.;
190  } else {
191  edge_attribute_map(desc_source2v).capacity = 0.;
192  edge_attribute_map(desc_v2sink).capacity =
193  cost_notB - cost_B;
194  }
195  }
196  }
197  //----then set the vertex to vertex edges
198  //---------------------------------------------
199  EdgeIterator<T> i_edg, i_edg_end;
200  for (boost::tie(i_edg, i_edg_end) = boost::edges(this->main_graph);
201  i_edg != i_edg_end; ++i_edg) {
202  if (!edge_attribute_map(*i_edg).realEdge) {
203  continue;
204  }
205  if (!edge_attribute_map(*i_edg).isActive) {
206  edge_attribute_map(*i_edg).capacity =
207  edge_attribute_map(*i_edg).weight *
208  this->parameter.reg_strenth;
209  } else {
210  edge_attribute_map(*i_edg).capacity = 0;
211  }
212  }
213  }
214 
215  //=============================================================================================
216  //================================= COMPUTE_VALUE
217  //=========================================
218  //=============================================================================================
219  std::pair<std::vector<T>, T> compute_value(const uint32_t& i_com) override {
220  VertexAttributeMap<T> vertex_attribute_map =
221  boost::get(boost::vertex_bundle, this->main_graph);
222  if (i_com == 0) { // we allocate the space necessary for the component
223  // vector at the first read of the component
224  this->componentVector =
225  std::vector<std::vector<T>>(this->components.size());
226  }
227  std::vector<T> average_vector(this->dim), component_value(this->dim);
228  T total_weight = 0;
229  for (uint32_t i_dim = 0; i_dim < this->dim; i_dim++) {
230  average_vector[i_dim] = 0;
231  }
232  for (uint32_t ind_ver = 0; ind_ver < this->components[i_com].size();
233  ++ind_ver) {
234  for (uint32_t i_dim = 0; i_dim < this->dim; i_dim++) {
235  average_vector[i_dim] +=
236  vertex_attribute_map[this->components[i_com][ind_ver]]
237  .observation[i_dim] *
238  vertex_attribute_map[this->components[i_com][ind_ver]]
239  .weight;
240  }
241  total_weight +=
242  vertex_attribute_map[this->components[i_com][ind_ver]]
243  .weight;
244  vertex_attribute_map(this->components[i_com][ind_ver])
245  .in_component = i_com;
246  }
247  this->componentVector[i_com] = average_vector;
248  uint32_t indexOfMax = 0;
249  for (uint32_t i_dim = 1; i_dim < this->dim; i_dim++) {
250  if (average_vector[indexOfMax] < average_vector[i_dim]) {
251  indexOfMax = i_dim;
252  }
253  }
254  for (uint32_t ind_ver = 0; ind_ver < this->components[i_com].size();
255  ++ind_ver) {
256  for (uint32_t i_dim = 0; i_dim < this->dim; i_dim++) {
257  if (i_dim == indexOfMax) {
258  component_value[i_dim] = 1;
259  vertex_attribute_map(this->components[i_com][ind_ver])
260  .value[i_dim] = 1;
261  } else {
262  component_value[i_dim] = 0;
263  vertex_attribute_map(this->components[i_com][ind_ver])
264  .value[i_dim] = 0;
265  }
266  }
267  }
268  return std::pair<std::vector<T>, T>(component_value, total_weight);
269  }
270 
271  //=============================================================================================
272  //================================= COMPUTE_MERGE_GAIN
273  //=========================================
274  //=============================================================================================
275  std::pair<std::vector<T>, T> compute_merge_gain(
276  const VertexDescriptor<T>& comp1,
277  const VertexDescriptor<T>& comp2) override {
278  VertexAttributeMap<T> reduced_vertex_attribute_map =
279  boost::get(boost::vertex_bundle, this->reduced_graph);
280  VertexIndexMap<T> reduced_vertex_vertex_index_map =
282  std::vector<T> merge_value(this->dim), mergedVector(this->dim);
283  T gain = 0;
284  // compute the value obtained by mergeing the two connected components
285  for (uint32_t i_dim = 0; i_dim < this->dim; i_dim++) {
286  mergedVector[i_dim] =
287  this->componentVector[reduced_vertex_vertex_index_map(
288  comp1)][i_dim] +
289  this->componentVector[reduced_vertex_vertex_index_map(
290  comp2)][i_dim];
291  }
292  uint32_t indexOfMax = 0;
293  for (uint32_t i_dim = 1; i_dim < this->dim; i_dim++) {
294  if (mergedVector[indexOfMax] < mergedVector[i_dim]) {
295  indexOfMax = i_dim;
296  }
297  }
298  for (uint32_t i_dim = 0; i_dim < this->dim; i_dim++) {
299  if (i_dim == indexOfMax) {
300  merge_value[i_dim] = 1;
301  } else {
302  merge_value[i_dim] = 0;
303  }
304  gain += mergedVector[i_dim] * merge_value[i_dim] -
305  this->componentVector[reduced_vertex_vertex_index_map(
306  comp1)][i_dim] *
307  reduced_vertex_attribute_map(comp1).value[i_dim] -
308  this->componentVector[reduced_vertex_vertex_index_map(
309  comp2)][i_dim] *
310  reduced_vertex_attribute_map(comp2).value[i_dim];
311  }
312 
313  return std::pair<std::vector<T>, T>(merge_value, gain);
314  }
315 };
316 } // namespace CP
long vertex_index
Definition: API.h:123
boost::vec_adj_list_vertex_property_map< Graph< T >, Graph< T > *, VertexAttribute< T >, VertexAttribute< T > &, boost::vertex_bundle_t > VertexAttributeMap
Definition: Graph.h:92
typename boost::graph_traits< Graph< T > >::edge_iterator EdgeIterator
Definition: Graph.h:84
typename boost::graph_traits< Graph< T > >::vertex_iterator VertexIterator
Definition: Graph.h:82
boost::graph_traits< boost::adjacency_list< boost::vecS, boost::vecS, boost::directedS > >::edge_descriptor EdgeDescriptor
Definition: Graph.h:22
typename boost::graph_traits< CP::Graph< T > >::vertex_descriptor VertexDescriptor
Definition: Graph.h:75
typename boost::property_map< Graph< T >, boost::vertex_index_t >::type VertexIndexMap
Definition: Graph.h:103
boost::adj_list_edge_property_map< boost::directed_tag, EdgeAttribute< T >, EdgeAttribute< T > &, uint64_t, CP::EdgeAttribute< T >, boost::edge_bundle_t > EdgeAttributeMap
Definition: Graph.h:100
std::pair< uint32_t, uint32_t > find_corner(const uint32_t &i_com)
std::pair< std::vector< T >, T > compute_value(const uint32_t &i_com) override
CutPursuit_Linear(uint32_t nbVertex=1)
std::pair< T, T > compute_energy() override
void compute_corners(std::vector< std::vector< uint32_t >> &corners)
void set_capacities(const std::vector< std::vector< uint32_t >> &corners)
std::pair< std::vector< T >, T > compute_merge_gain(const VertexDescriptor< T > &comp1, const VertexDescriptor< T > &comp2) override
size_t split() override
std::vector< std::vector< T > > componentVector
Graph< T > main_graph
Definition: CutPursuit.h:45
CP::VertexIterator< T > lastIterator
Definition: CutPursuit.h:63
std::vector< std::vector< VertexDescriptor< T > > > components
Definition: CutPursuit.h:49
VertexDescriptor< T > sink
Definition: CutPursuit.h:58
VertexDescriptor< T > source
Definition: CutPursuit.h:57
size_t activate_edges(bool allows_saturation=true)
Definition: CutPursuit.h:298
uint32_t dim
Definition: CutPursuit.h:59
std::vector< bool > saturated_components
Definition: CutPursuit.h:53
Graph< T > reduced_graph
Definition: CutPursuit.h:46