Ocean
SuccessionSubset.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  */
7 
8 #ifndef META_OCEAN_MATH_SUCCESSION_SUBSET_H
9 #define META_OCEAN_MATH_SUCCESSION_SUBSET_H
10 
11 #include "ocean/math/Math.h"
12 #include "ocean/math/Variance.h"
13 
15 
16 #include <limits>
17 
18 namespace Ocean
19 {
20 
21 /**
22  * This class implements a data container for abstract data objects with several dimensions.
23  * The container allows to extract a subset of the data objects with largest distance to the remaining objects in the container.<br>
24  * The distance between two objects is determined by the Euclidean distance while each dimension is normalized by the object's standard deviation of all data objects.<br>
25  * Each object has the same dimension and each element of the objects has the same data type.<br>
26  * Use this class to find a subset of e.g. camera poses, matrices or vectors so that each object of the subset has the largest distance to all objects of the entire set.<br>
27  * The set of objects should be set during the construction of a SuccessionSubset object or by application of SuccessionSubset::setObjects().<br>
28  * Beware: Set the entire set of objects before determine the subset.<br>
29  * @tparam T Data type of the individual objects of each object
30  * @tparam tDimensions Number of dimension that each object has
31  * @ingroup math
32  */
33 template <typename T, size_t tDimensions>
35 {
36  public:
37 
38  /**
39  * The definition of an abstract object of this constainer.
40  */
42 
43  /**
44  * Definition of a vector holding indices.
45  */
46  typedef std::vector<size_t> Indices;
47 
48  protected:
49 
50  /**
51  * Definition of a vector holding abstract objects.
52  */
53  typedef std::vector<Object> Objects;
54 
55  /**
56  * Definition of a vector holding flags.
57  */
58  typedef std::vector<unsigned char> Flags;
59 
60  public:
61 
62  /**
63  * Creates an empty container object.
64  */
66 
67  /**
68  * Creates a new container and provides a set of objects that will be managed by this container.
69  * @param objects Objects that will be copied
70  * @param size Number of given objects
71  */
72  SuccessionSubset(const Object* objects, const size_t size);
73 
74  /**
75  * Returns the dimension of each object of this container.
76  * @return Dimensions of each object, tDimension is returned
77  */
78  static inline size_t dimensions();
79 
80  /**
81  * Returns the number of objects that are managed by this container
82  * @return Object number
83  */
84  inline size_t size() const;
85 
86  /**
87  * Determines the next object of this container that has the largest distance to all remaining objects that are stored by this container.
88  * The determined object is added to the internal subset, further the index of the object will be returned.<br>
89  * @return Index of the object with largest distance, returns -1 if the subset holds already all objects
90  */
91  size_t incrementSubset();
92 
93  /**
94  * Explicitly selects one object of this container so that is will be added to the internal subset.
95  * Use this function only if one specific object should be part of the final subset.<br>
96  * The object must not be part of the current subset.<br>
97  * @param object Index of the object that is selected explicitly, with range [0, size())
98  * @return True, if succeeded
99  */
100  bool incrementSubset(const size_t object);
101 
102  /**
103  * Returns one object of this container.
104  * @param index The index of the requested object, with range [0, size())
105  * @return The requested object
106  */
107  inline const Object& object(const size_t index);
108 
109  /**
110  * Returns the current object subset of this container.
111  * @return Indices of the objects that belong to the subset of this container
112  */
113  inline const Indices& subset() const;
114 
115  /**
116  * Returns a subset of the stored elements with specified size.
117  * If the internal subset is larger than the requested size, the entire subset is returned.<br>
118  * If the internal subset is smaller than the requested size, the internal subset will be incremented until the requested size is reached.<br>
119  * @param size Size of the requested subset, with range [1, size())
120  * @return Indices of the elements of the requested subset
121  */
122  const Indices& subset(const size_t size);
123 
124  /**
125  * Overwrites all objects of this container and resets the current subset of the previous object to zero.
126  * @param objects New object to be copied into this container
127  * @param size Number of given objects
128  */
129  void setObjects(const Object* objects, const size_t size);
130 
131  /**
132  * Returns whether this container is empty and thus does not store any object.
133  * @return True, if so
134  */
135  inline bool isEmpty() const;
136 
137  /**
138  * Returns whether this container holds at least one object.
139  * @return True, if so
140  */
141  explicit inline operator bool() const;
142 
143  /**
144  * Converts the indices of this object to 32 bit indices.
145  * @param indices Indices to convert
146  * @return The converted indices
147  */
148  static inline Indices32 indices2indices32(const Indices& indices);
149 
150  protected:
151 
152  /**
153  * Returns the elements of this container that is not part of the subset and that has the smallest maximal distance to all remaining objects in the container.
154  * @return Index of the resulting object
155  */
156  size_t smallestMaximalDistance() const;
157 
158  /**
159  * Returns the elements of this container that is not part of the subset and that has the largest minimal distance to all subset objects in the container.
160  * @return Index of the resulting object
161  */
162  size_t largestMinimalDistanceWithSubset() const;
163 
164  /**
165  * Determines the distance between two objects of this container.
166  * @param a Index of the first object, with range [0, size())
167  * @param b Index of the second object
168  * @return Resulting distance between both objects
169  */
170  T distance(const size_t a, const size_t b) const;
171 
172  /**
173  * Returns the maximal distance between a specified object of this container and all remaining objects of this container.
174  * @param index Index of the object for that the minimal distance will be determined, with range [0, size())
175  * @return Resulting smallest distance
176  */
177  T maximalDistance(const size_t index) const;
178 
179  /**
180  * Returns the smallest distance between a specified object of this container and all subset objects of this container.
181  * @param index Index of the object for that the minimal distance will be determined, with range [0, size())
182  * @return Resulting smallest distance
183  */
184  T minimalDistanceWithSubset(const size_t index) const;
185 
186  protected:
187 
188  /// All objects of this container.
190 
191  /// Objects flags, for a fast check whether an objects is part of the internal subset.
193 
194  /// The indices of all objects inside the subset.
196 };
197 
198 template <typename T, size_t tDimensions>
200 {
201  // nothing to do here
202 }
203 
204 template <typename T, size_t tDimensions>
206 {
207  setObjects(objects, size);
208 }
209 
210 template <typename T, size_t tDimensions>
212 {
213  return tDimensions;
214 }
215 
216 template <typename T, size_t tDimensions>
218 {
219  return successionObjects.size();
220 }
221 
222 template <typename T, size_t tDimensions>
224 {
225  ocean_assert(successionObjects.size() == successionFlags.size());
226 
227  size_t index = size_t(-1);
228 
229  if (successionSubset.size() == successionObjects.size())
230  {
231  return size_t(-1);
232  }
233 
234  ocean_assert(successionSubset.size() < successionObjects.size());
235 
236  if (successionSubset.size() == 0)
237  {
238  index = smallestMaximalDistance();
239  }
240  else
241  {
242  index = largestMinimalDistanceWithSubset();
243  }
244 
245  if (index == size_t(-1))
246  {
247  return size_t(-1);
248  }
249 
250  ocean_assert(index < successionFlags.size());
251  successionFlags[index] = 1;
252  successionSubset.push_back(index);
253 
254  return index;
255 }
256 
257 template <typename T, size_t tDimensions>
259 {
260  ocean_assert(successionObjects.size() == successionFlags.size());
261 
262  if (object >= successionObjects.size() || successionFlags[object] != 0)
263  {
264  return false;
265  }
266 
267  successionFlags[object] = 1;
268  successionSubset.push_back(object);
269 
270  return true;
271 }
272 
273 template <typename T, size_t tDimensions>
275 {
276  ocean_assert(index < successionObjects.size());
277  return successionObjects[index];
278 }
279 
280 template <typename T, size_t tDimensions>
282 {
283  return successionSubset;
284 }
285 
286 template <typename T, size_t tDimensions>
288 {
289  while (successionSubset.size() < objects && successionSubset.size() < successionObjects.size())
290  {
291  const size_t index = incrementSubset();
292  ocean_assert_and_suppress_unused(index < successionObjects.size(), index);
293  }
294 
295  return successionSubset;
296 }
297 
298 template <typename T, size_t tDimensions>
299 void SuccessionSubset<T, tDimensions>::setObjects(const Object* objects, const size_t size)
300 {
301  StaticBuffer<VarianceT<T>, tDimensions> variances;
302 
303  for (size_t n = 0; n < size; ++n)
304  {
305  for (size_t i = 0; i < tDimensions; ++i)
306  {
307  variances[i].add(objects[n][i]);
308  }
309  }
310 
311  // copy normalized objects
312  successionObjects.resize(size);
313  successionFlags = Flags(size, 0u);
314  successionSubset.clear();
315 
316  if (size == 0)
317  {
318  return;
319  }
320 
321  StaticBuffer<T, tDimensions> normalizationFactors;
322  for (size_t i = 0; i < tDimensions; ++i)
323  {
324  normalizationFactors[i] = variances[i].deviation() > 0 ? (T(1) / variances[i].deviation()) : T(1);
325  }
326 
327  for (size_t n = 0; n < size; ++n)
328  {
329  for (size_t i = 0; i < tDimensions; ++i)
330  {
331  successionObjects[n][i] = objects[n][i] * normalizationFactors[i];
332  }
333  }
334 }
335 
336 template <typename T, size_t tDimensions>
338 {
339  return successionObjects.empty();
340 }
341 
342 template <typename T, size_t tDimensions>
344 {
345  ocean_assert(successionObjects.size() == successionFlags.size());
346  return successionSubset.size() < successionObjects.size();
347 }
348 
349 template <typename T, size_t tDimensions>
351 {
352  Indices32 result(indices.size());
353 
354  for (size_t n = 0; n < indices.size(); ++n)
355  {
356  ocean_assert(indices[n] <= NumericT<Index32>::maxValue());
357  result[n] = Index32(indices[n]);
358  }
359 
360  return result;
361 }
362 
363 template <typename T, size_t tDimensions>
365 {
366  ocean_assert(successionSubset.size() < successionObjects.size());
367 
368  size_t smallestIndex = size_t(-1);
369 
370  for (size_t n = 0; n < successionObjects.size(); ++n)
371  {
372  if (successionFlags[n] == 0)
373  {
374  smallestIndex = n;
375  break;
376  }
377  }
378 
379  // determine the distance for the selected object
380  T smallestDistance = maximalDistance(smallestIndex);
381 
382  // now check the distance for all remaining objects
383  for (size_t n = smallestIndex + 1; n < successionObjects.size(); ++n)
384  {
385  if (successionFlags[n] == 0)
386  {
387  const T localDistance = maximalDistance(n);
388 
389  if (localDistance < smallestDistance)
390  {
391  smallestDistance = localDistance;
392  smallestIndex = n;
393  }
394  }
395  }
396 
397  return smallestIndex;
398 }
399 
400 template <typename T, size_t tDimensions>
402 {
403  ocean_assert(successionSubset.size() < successionObjects.size());
404 
405  size_t largestIndex = size_t(-1);
406 
407  for (size_t n = 0; n < successionObjects.size(); ++n)
408  {
409  if (successionFlags[n] == 0)
410  {
411  largestIndex = n;
412  break;
413  }
414  }
415 
416  // determine the distance for the selected object
417  T largestDistance = minimalDistanceWithSubset(largestIndex);
418 
419  // now check the distance for all remaining objects
420  for (size_t n = largestIndex + 1; n < successionObjects.size(); ++n)
421  {
422  if (successionFlags[n] == 0)
423  {
424  const T localDistance = minimalDistanceWithSubset(n);
425 
426  if (localDistance > largestDistance)
427  {
428  largestDistance = localDistance;
429  largestIndex = n;
430  }
431  }
432  }
433 
434  return largestIndex;
435 }
436 
437 template <typename T, size_t tDimensions>
438 T SuccessionSubset<T, tDimensions>::distance(const size_t a, const size_t b) const
439 {
440  ocean_assert(a < successionObjects.size());
441  ocean_assert(b < successionObjects.size());
442 
443  T result = 0;
444 
445  for (size_t i = 0; i < tDimensions; ++i)
446  {
447  result += NumericT<T>::sqr(successionObjects[a][i] - successionObjects[b][i]);
448  }
449 
450  return result;
451 }
452 
453 template <typename T, size_t tDimensions>
455 {
456  ocean_assert(index < successionObjects.size());
457  ocean_assert(successionObjects.size() >= 2);
458 
459  T maxDistance = NumericT<T>::minValue();
460 
461  // determine the distance for the selected object
462  for (size_t n = 0; n < successionObjects.size(); ++n)
463  {
464  if (n != index)
465  {
466  const T localDistance = distance(n, index);
467 
468  if (localDistance > maxDistance)
469  maxDistance = localDistance;
470  }
471  }
472 
473  ocean_assert(maxDistance != NumericT<T>::minValue());
474  return maxDistance;
475 }
476 
477 template <typename T, size_t tDimensions>
479 {
480  ocean_assert(index < successionObjects.size());
481  ocean_assert(successionSubset.size() >= 1);
482 
483  T minDistance = NumericT<T>::maxValue();
484 
485  // determine the distance for the selected object
486  for (size_t n = 0; n < successionSubset.size(); ++n)
487  {
488  ocean_assert(index != successionSubset[n]);
489  const T localDistance = distance(successionSubset[n], index);
490 
491  if (localDistance < minDistance)
492  {
493  minDistance = localDistance;
494  }
495  }
496 
497  ocean_assert(minDistance != NumericT<T>::maxValue());
498  return minDistance;
499 }
500 
501 }
502 
503 #endif // META_OCEAN_MATH_SUCCESSION_SUBSET_H
This class provides basic numeric functionalities.
Definition: Numeric.h:57
static constexpr T minValue()
Returns the min scalar value.
Definition: Numeric.h:3250
static constexpr T sqr(const T value)
Returns the square of a given value.
Definition: Numeric.h:1495
static constexpr T maxValue()
Returns the max scalar value.
Definition: Numeric.h:3244
This class implements a static buffer that has a fixed capacity.
Definition: StaticBuffer.h:24
This class implements a data container for abstract data objects with several dimensions.
Definition: SuccessionSubset.h:35
SuccessionSubset()
Creates an empty container object.
Definition: SuccessionSubset.h:199
size_t largestMinimalDistanceWithSubset() const
Returns the elements of this container that is not part of the subset and that has the largest minima...
Definition: SuccessionSubset.h:401
T distance(const size_t a, const size_t b) const
Determines the distance between two objects of this container.
Definition: SuccessionSubset.h:438
T maximalDistance(const size_t index) const
Returns the maximal distance between a specified object of this container and all remaining objects o...
Definition: SuccessionSubset.h:454
std::vector< Object > Objects
Definition of a vector holding abstract objects.
Definition: SuccessionSubset.h:53
Indices successionSubset
The indices of all objects inside the subset.
Definition: SuccessionSubset.h:195
static size_t dimensions()
Returns the dimension of each object of this container.
Definition: SuccessionSubset.h:211
void setObjects(const Object *objects, const size_t size)
Overwrites all objects of this container and resets the current subset of the previous object to zero...
Definition: SuccessionSubset.h:299
size_t smallestMaximalDistance() const
Returns the elements of this container that is not part of the subset and that has the smallest maxim...
Definition: SuccessionSubset.h:364
Flags successionFlags
Objects flags, for a fast check whether an objects is part of the internal subset.
Definition: SuccessionSubset.h:192
const Object & object(const size_t index)
Returns one object of this container.
Definition: SuccessionSubset.h:274
size_t size() const
Returns the number of objects that are managed by this container.
Definition: SuccessionSubset.h:217
bool isEmpty() const
Returns whether this container is empty and thus does not store any object.
Definition: SuccessionSubset.h:337
size_t incrementSubset()
Determines the next object of this container that has the largest distance to all remaining objects t...
Definition: SuccessionSubset.h:223
StaticBuffer< T, tDimensions > Object
The definition of an abstract object of this constainer.
Definition: SuccessionSubset.h:41
std::vector< unsigned char > Flags
Definition of a vector holding flags.
Definition: SuccessionSubset.h:58
T minimalDistanceWithSubset(const size_t index) const
Returns the smallest distance between a specified object of this container and all subset objects of ...
Definition: SuccessionSubset.h:478
static Indices32 indices2indices32(const Indices &indices)
Converts the indices of this object to 32 bit indices.
Definition: SuccessionSubset.h:350
Objects successionObjects
All objects of this container.
Definition: SuccessionSubset.h:189
std::vector< size_t > Indices
Definition of a vector holding indices.
Definition: SuccessionSubset.h:46
const Indices & subset() const
Returns the current object subset of this container.
Definition: SuccessionSubset.h:281
std::vector< Index32 > Indices32
Definition of a vector holding 32 bit index values.
Definition: Base.h:96
uint32_t Index32
Definition of a 32 bit index value.
Definition: Base.h:84
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15