$darkmode
Eigen-unsupported  5.0.1-dev
RandomSetter.h
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
5 //
6 // This Source Code Form is subject to the terms of the Mozilla
7 // Public License v. 2.0. If a copy of the MPL was not distributed
8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 
10 #ifndef EIGEN_RANDOMSETTER_H
11 #define EIGEN_RANDOMSETTER_H
12 
13 #if defined(EIGEN_GOOGLEHASH_SUPPORT)
14 // Ensure the ::google namespace exists, required for checking existence of
15 // ::google::dense_hash_map and ::google::sparse_hash_map.
16 namespace google {}
17 #endif
18 
19 // IWYU pragma: private
20 #include "./InternalHeaderCheck.h"
21 
22 namespace Eigen {
23 
28 template <typename Scalar>
29 struct StdMapTraits {
30  typedef int KeyType;
31  typedef std::map<KeyType, Scalar> Type;
32  enum { IsSorted = 1 };
33 
34  static void setInvalidKey(Type&, const KeyType&) {}
35 };
36 
40 template <typename Scalar>
42  typedef int KeyType;
43  typedef std::unordered_map<KeyType, Scalar> Type;
44  enum { IsSorted = 0 };
45 
46  static void setInvalidKey(Type&, const KeyType&) {}
47 };
48 
49 #if defined(EIGEN_GOOGLEHASH_SUPPORT)
50 
51 namespace google {
52 
53 // Namespace work-around, since sometimes dense_hash_map and sparse_hash_map
54 // are in the global namespace, and other times they are under ::google.
55 using namespace ::google;
56 
57 template <typename KeyType, typename Scalar>
58 struct DenseHashMap {
59  typedef dense_hash_map<KeyType, Scalar> type;
60 };
61 
62 template <typename KeyType, typename Scalar>
63 struct SparseHashMap {
64  typedef sparse_hash_map<KeyType, Scalar> type;
65 };
66 
67 } // namespace google
68 
73 template <typename Scalar>
74 struct GoogleDenseHashMapTraits {
75  typedef int KeyType;
76  typedef typename google::DenseHashMap<KeyType, Scalar>::type Type;
77  enum { IsSorted = 0 };
78 
79  static void setInvalidKey(Type& map, const KeyType& k) { map.set_empty_key(k); }
80 };
81 
86 template <typename Scalar>
87 struct GoogleSparseHashMapTraits {
88  typedef int KeyType;
89  typedef typename google::SparseHashMap<KeyType, Scalar>::type Type;
90  enum { IsSorted = 0 };
91 
92  static void setInvalidKey(Type&, const KeyType&) {}
93 };
94 #endif
95 
147 template <typename SparseMatrixType,
148  template <typename T> class MapTraits =
149 #if defined(EIGEN_GOOGLEHASH_SUPPORT)
150  GoogleDenseHashMapTraits
151 #else
152  StdUnorderedMapTraits
153 #endif
154  ,
155  int OuterPacketBits = 6>
157  typedef typename SparseMatrixType::Scalar Scalar;
158  typedef typename SparseMatrixType::StorageIndex StorageIndex;
159 
160  struct ScalarWrapper {
161  ScalarWrapper() : value(0) {}
162  Scalar value;
163  };
164  typedef typename MapTraits<ScalarWrapper>::KeyType KeyType;
165  typedef typename MapTraits<ScalarWrapper>::Type HashMapType;
166  static constexpr int OuterPacketMask = (1 << OuterPacketBits) - 1;
167  enum {
168  SwapStorage = 1 - MapTraits<ScalarWrapper>::IsSorted,
169  TargetRowMajor = (SparseMatrixType::Flags & RowMajorBit) ? 1 : 0,
170  SetterRowMajor = SwapStorage ? 1 - TargetRowMajor : TargetRowMajor
171  };
172 
173  public:
180  inline RandomSetter(SparseMatrixType& target) : mp_target(&target) {
181  const Index outerSize = SwapStorage ? target.innerSize() : target.outerSize();
182  const Index innerSize = SwapStorage ? target.outerSize() : target.innerSize();
183  m_outerPackets = outerSize >> OuterPacketBits;
184  if (outerSize & OuterPacketMask) m_outerPackets += 1;
185  m_hashmaps = new HashMapType[m_outerPackets];
186  // compute number of bits needed to store inner indices
187  Index aux = innerSize - 1;
188  m_keyBitsOffset = 0;
189  while (aux) {
190  ++m_keyBitsOffset;
191  aux = aux >> 1;
192  }
193  KeyType ik = (1 << (OuterPacketBits + m_keyBitsOffset));
194  for (Index k = 0; k < m_outerPackets; ++k) MapTraits<ScalarWrapper>::setInvalidKey(m_hashmaps[k], ik);
195 
196  // insert current coeffs
197  for (Index j = 0; j < mp_target->outerSize(); ++j)
198  for (typename SparseMatrixType::InnerIterator it(*mp_target, j); it; ++it)
199  (*this)(TargetRowMajor ? j : it.index(), TargetRowMajor ? it.index() : j) = it.value();
200  }
201 
204  KeyType keyBitsMask = (1 << m_keyBitsOffset) - 1;
205  if (!SwapStorage) // also means the map is sorted
206  {
207  mp_target->setZero();
208  mp_target->makeCompressed();
209  mp_target->reserve(nonZeros());
210  Index prevOuter = -1;
211  for (Index k = 0; k < m_outerPackets; ++k) {
212  const Index outerOffset = (1 << OuterPacketBits) * k;
213  typename HashMapType::iterator end = m_hashmaps[k].end();
214  for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it != end; ++it) {
215  const Index outer = (it->first >> m_keyBitsOffset) + outerOffset;
216  const Index inner = it->first & keyBitsMask;
217  if (prevOuter != outer) {
218  for (Index j = prevOuter + 1; j <= outer; ++j) mp_target->startVec(j);
219  prevOuter = outer;
220  }
221  mp_target->insertBackByOuterInner(outer, inner) = it->second.value;
222  }
223  }
224  mp_target->finalize();
225  } else {
226  VectorXi positions(mp_target->outerSize());
227  positions.setZero();
228  // pass 1
229  for (Index k = 0; k < m_outerPackets; ++k) {
230  typename HashMapType::iterator end = m_hashmaps[k].end();
231  for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it != end; ++it) {
232  const Index outer = it->first & keyBitsMask;
233  ++positions[outer];
234  }
235  }
236  // prefix sum
237  StorageIndex count = 0;
238  for (Index j = 0; j < mp_target->outerSize(); ++j) {
239  StorageIndex tmp = positions[j];
240  mp_target->outerIndexPtr()[j] = count;
241  positions[j] = count;
242  count += tmp;
243  }
244  mp_target->makeCompressed();
245  mp_target->outerIndexPtr()[mp_target->outerSize()] = count;
246  mp_target->resizeNonZeros(count);
247  // pass 2
248  for (Index k = 0; k < m_outerPackets; ++k) {
249  const Index outerOffset = (1 << OuterPacketBits) * k;
250  typename HashMapType::iterator end = m_hashmaps[k].end();
251  for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it != end; ++it) {
252  const Index inner = (it->first >> m_keyBitsOffset) + outerOffset;
253  const Index outer = it->first & keyBitsMask;
254  // sorted insertion
255  // Note that we have to deal with at most 2^OuterPacketBits unsorted coefficients,
256  // moreover those 2^OuterPacketBits coeffs are likely to be sparse, an so only a
257  // small fraction of them have to be sorted, whence the following simple procedure:
258  Index posStart = mp_target->outerIndexPtr()[outer];
259  Index i = (positions[outer]++) - 1;
260  while ((i >= posStart) && (mp_target->innerIndexPtr()[i] > inner)) {
261  mp_target->valuePtr()[i + 1] = mp_target->valuePtr()[i];
262  mp_target->innerIndexPtr()[i + 1] = mp_target->innerIndexPtr()[i];
263  --i;
264  }
265  mp_target->innerIndexPtr()[i + 1] = internal::convert_index<StorageIndex>(inner);
266  mp_target->valuePtr()[i + 1] = it->second.value;
267  }
268  }
269  }
270  delete[] m_hashmaps;
271  }
272 
274  Scalar& operator()(Index row, Index col) {
275  const Index outer = SetterRowMajor ? row : col;
276  const Index inner = SetterRowMajor ? col : row;
277  const Index outerMajor = outer >> OuterPacketBits; // index of the packet/map
278  const Index outerMinor = outer & OuterPacketMask; // index of the inner vector in the packet
279  const KeyType key = internal::convert_index<KeyType>((outerMinor << m_keyBitsOffset) | inner);
280  return m_hashmaps[outerMajor][key].value;
281  }
282 
288  Index nonZeros() const {
289  Index nz = 0;
290  for (Index k = 0; k < m_outerPackets; ++k) nz += static_cast<Index>(m_hashmaps[k].size());
291  return nz;
292  }
293 
294  protected:
295  HashMapType* m_hashmaps;
296  SparseMatrixType* mp_target;
297  Index m_outerPackets;
298  unsigned char m_keyBitsOffset;
299 };
300 
301 } // end namespace Eigen
302 
303 #endif // EIGEN_RANDOMSETTER_H
static constexpr lastp1_t end
Scalar & operator()(Index row, Index col)
Definition: RandomSetter.h:274
RandomSetter(SparseMatrixType &target)
Definition: RandomSetter.h:180
Definition: RandomSetter.h:29
Namespace containing all symbols from the Eigen library.
Index nonZeros() const
Definition: RandomSetter.h:288
const unsigned int RowMajorBit
Matrix< Scalar_, Rows_, Cols_, Options_, MaxRows_, MaxCols_ > & setZero(Index size)
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The RandomSetter is a wrapper object allowing to set/update a sparse matrix with random access...
Definition: RandomSetter.h:156
~RandomSetter()
Definition: RandomSetter.h:203
Definition: RandomSetter.h:41