Turi Create  4.0
index_mapper.hpp
1 /* Copyright © 2017 Apple Inc. All rights reserved.
2  *
3  * Use of this source code is governed by a BSD-3-clause license that can
4  * be found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause
5  */
6 #ifndef TURI_UNITY_VECTOR_INDEX_MAPPER_H_
7 #define TURI_UNITY_VECTOR_INDEX_MAPPER_H_
8 
9 #include <vector>
10 #include <core/util/dense_bitset.hpp>
11 
12 namespace turi {
13 
14 /** Index Mapping. Just a simple utility to allow mapping indices to
15  * a subset of them based on a bitmask. Upon construction, the index
16  * mapping is the identity; after an index mapping is applied,
17  * vectors of the original indices can be remapped to other
18  */
20  private:
21 
22  bool _index_mapping_enabled = false;
23  std::vector<size_t> data_to_internal_index_mapping;
24  std::vector<size_t> internal_to_data_index_mapping;
25 
26  public:
27 
28  /** Is the current mapping the identity?
29  */
30  inline bool is_identity() const {
31  return !_index_mapping_enabled;
32  }
33 
34  /** Applies a mapping to the vertices so that only a subset of them
35  * are active, and each of these are mapped to a contiguous set of
36  * indices, 0, ..., n_active-1.
37  */
38  size_t set_index_mapping_from_mask(const dense_bitset& is_active_entry) {
39 
40  size_t num_items = is_active_entry.size();
41  size_t new_size = is_active_entry.popcount();
42 
43  // Nothing to do if they are all active still
44  if(new_size == num_items) {
45  _index_mapping_enabled = false;
46  internal_to_data_index_mapping.clear();
47  data_to_internal_index_mapping.clear();
48  return new_size;
49  }
50 
51  // Build the index mappings
52  internal_to_data_index_mapping.resize(new_size);
53  data_to_internal_index_mapping.resize(num_items);
54 
55  size_t map_idx = 0;
56  for(size_t src_idx = 0; src_idx < num_items; ++src_idx) {
57  bool entry_active = is_active_entry.get(src_idx);
58 
59  if(entry_active) {
60  internal_to_data_index_mapping[map_idx] = src_idx;
61  data_to_internal_index_mapping[src_idx] = map_idx;
62  ++map_idx;
63  } else {
64  data_to_internal_index_mapping[src_idx] = size_t(-1);
65  }
66  }
67 
68  _index_mapping_enabled = true;
69  return new_size;
70  }
71 
72  /** Remaps a vector inplace such that only active indices are kept,
73  * and the rest are discarded. Effectively, this applies the mask
74  * given to set_index_mapping_from_mask to this vector. In the
75  * new vector, entry i in the original will then be entry
76  * map_data_index_to_internal_index(i) in the remapped vector.
77  *
78  * The vector is unchanged if is_identity() is true.
79  */
80  template <typename T>
82  void remap_vector(std::vector<T>& data_vect) const {
83 
84  if(!_index_mapping_enabled) {
85  return;
86  }
87 
88  DASSERT_EQ(data_vect.size(), data_to_internal_index_mapping.size());
89 
90  // Go through and filter all the index data to be the internal
91  // indices.
92  for(size_t i = 0; i < internal_to_data_index_mapping.size(); ++i) {
93  size_t src_idx = internal_to_data_index_mapping[i];
94  size_t dest_idx = i;
95 
96  data_vect[dest_idx] = std::move(data_vect[src_idx]);
97  }
98 
99  data_vect.resize(internal_to_data_index_mapping.size());
100  }
101 
102  /** Remaps a sparse vector of (index, value) pairs inplace such
103  * that only active indices are kept and the rest are discarded.
104  * Active indices are remapped.
105  *
106  * The vector is unchanged if is_identity() is true.
107  */
108  template <typename T>
110  void remap_sparse_vector(std::vector<std::pair<size_t, T> >& data_vect) const {
111 
112  if(!_index_mapping_enabled) {
113  return;
114  }
115 
116  DASSERT_TRUE(std::is_sorted(data_vect.begin(), data_vect.end(),
117  [](const std::pair<size_t, T>& p1,
118  const std::pair<size_t, T>& p2) {
119  DASSERT_NE(p1.first, p2.first);
120  return p1.first < p2.first; }));
121 
122  size_t dest_idx = 0;
123  for(size_t src_idx = 0; src_idx < data_vect.size(); ++src_idx) {
124  auto& p = data_vect[src_idx];
125  size_t mapped_index = map_data_index_to_internal_index(p.first);
126  if(mapped_index != size_t(-1)) {
127  data_vect[dest_idx] = {mapped_index, std::move(p.second)};
128  ++dest_idx;
129  }
130  }
131  data_vect.resize(dest_idx);
132 
133  DASSERT_TRUE(std::is_sorted(data_vect.begin(), data_vect.end(),
134  [](const std::pair<size_t, T>& p1,
135  const std::pair<size_t, T>& p2) {
136  DASSERT_NE(p1.first, p2.first);
137  return p1.first < p2.first; }));
138  }
139 
140  /** Is a given entry still active?
141  */
142  inline bool is_active(size_t data_idx) const GL_HOT_INLINE_FLATTEN {
143  return _index_mapping_enabled || (data_to_internal_index_mapping[data_idx] != size_t(-1));
144  }
145 
146  /** What's the internal mapped index for the given entry?
147  */
148  inline size_t map_data_index_to_internal_index(size_t data_idx) const GL_HOT_INLINE_FLATTEN {
149  DASSERT_LT(data_idx, data_to_internal_index_mapping.size());
150  if(_index_mapping_enabled) {
151  return data_to_internal_index_mapping[data_idx];
152  } else {
153  return data_idx;
154  }
155  }
156 
157  /** What's the external index here?
158  */
159  inline size_t map_internal_index_to_data_index(size_t internal_idx) const GL_HOT_INLINE_FLATTEN {
160  if(_index_mapping_enabled) {
161  DASSERT_LT(internal_idx, internal_to_data_index_mapping.size());
162  return internal_to_data_index_mapping[internal_idx];
163  } else {
164  return internal_idx;
165  }
166  }
167 
168 };
169 
170 }
171 
172 #endif
#define GL_HOT_FLATTEN
GL_HOT_FLATTEN void remap_sparse_vector(std::vector< std::pair< size_t, T > > &data_vect) const
size_t map_internal_index_to_data_index(size_t internal_idx) const GL_HOT_INLINE_FLATTEN
bool get(size_t b) const
Returns the value of the bit b.
bool is_active(size_t data_idx) const GL_HOT_INLINE_FLATTEN
size_t set_index_mapping_from_mask(const dense_bitset &is_active_entry)
#define GL_HOT_INLINE_FLATTEN
size_t map_data_index_to_internal_index(size_t data_idx) const GL_HOT_INLINE_FLATTEN
size_t size() const
Returns the number of bits in this bitset.
GL_HOT_FLATTEN void remap_vector(std::vector< T > &data_vect) const
#define DASSERT_TRUE(cond)
Definition: assertions.hpp:364