RandomSetter.h
Go to the documentation of this file.
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 #include "./InternalHeaderCheck.h"
20 
21 namespace Eigen {
22 
27 template<typename Scalar> struct StdMapTraits
28 {
29  typedef int KeyType;
30  typedef std::map<KeyType,Scalar> Type;
31  enum {
32  IsSorted = 1
33  };
34 
35  static void setInvalidKey(Type&, const KeyType&) {}
36 };
37 
38 
42 template<typename Scalar> struct StdUnorderedMapTraits
43 {
44  typedef int KeyType;
45  typedef std::unordered_map<KeyType,Scalar> Type;
46  enum {
47  IsSorted = 0
48  };
49 
50  static void setInvalidKey(Type&, const KeyType&) {}
51 };
52 
53 #if defined(EIGEN_GOOGLEHASH_SUPPORT)
54 
55 namespace google {
56 
57 // Namespace work-around, since sometimes dense_hash_map and sparse_hash_map
58 // are in the global namespace, and other times they are under ::google.
59 using namespace ::google;
60 
61 template<typename KeyType, typename Scalar>
62 struct DenseHashMap {
63  typedef dense_hash_map<KeyType, Scalar> type;
64 };
65 
66 template<typename KeyType, typename Scalar>
67 struct SparseHashMap {
68  typedef sparse_hash_map<KeyType, Scalar> type;
69 };
70 
71 } // namespace google
72 
77 template<typename Scalar> struct GoogleDenseHashMapTraits
78 {
79  typedef int KeyType;
80  typedef typename google::DenseHashMap<KeyType,Scalar>::type Type;
81  enum {
82  IsSorted = 0
83  };
84 
85  static void setInvalidKey(Type& map, const KeyType& k)
86  { map.set_empty_key(k); }
87 };
88 
93 template<typename Scalar> struct GoogleSparseHashMapTraits
94 {
95  typedef int KeyType;
96  typedef typename google::SparseHashMap<KeyType,Scalar>::type Type;
97  enum {
98  IsSorted = 0
99  };
100 
101  static void setInvalidKey(Type&, const KeyType&) {}
102 };
103 #endif
104 
154 template<typename SparseMatrixType,
155  template <typename T> class MapTraits =
156 #if defined(EIGEN_GOOGLEHASH_SUPPORT)
157  GoogleDenseHashMapTraits
158 #else
159  StdUnorderedMapTraits
160 #endif
161  ,int OuterPacketBits = 6>
163 {
164  typedef typename SparseMatrixType::Scalar Scalar;
165  typedef typename SparseMatrixType::StorageIndex StorageIndex;
166 
168  {
171  };
172  typedef typename MapTraits<ScalarWrapper>::KeyType KeyType;
173  typedef typename MapTraits<ScalarWrapper>::Type HashMapType;
174  static constexpr int OuterPacketMask = (1 << OuterPacketBits) - 1;
175  enum {
176  SwapStorage = 1 - MapTraits<ScalarWrapper>::IsSorted,
177  TargetRowMajor = (SparseMatrixType::Flags & RowMajorBit) ? 1 : 0,
179  };
180 
181  public:
182 
189  inline RandomSetter(SparseMatrixType& target)
190  : mp_target(&target)
191  {
192  const Index outerSize = SwapStorage ? target.innerSize() : target.outerSize();
193  const Index innerSize = SwapStorage ? target.outerSize() : target.innerSize();
194  m_outerPackets = outerSize >> OuterPacketBits;
195  if (outerSize&OuterPacketMask)
196  m_outerPackets += 1;
198  // compute number of bits needed to store inner indices
199  Index aux = innerSize - 1;
200  m_keyBitsOffset = 0;
201  while (aux)
202  {
203  ++m_keyBitsOffset;
204  aux = aux >> 1;
205  }
206  KeyType ik = (1<<(OuterPacketBits+m_keyBitsOffset));
207  for (Index k=0; k<m_outerPackets; ++k)
208  MapTraits<ScalarWrapper>::setInvalidKey(m_hashmaps[k],ik);
209 
210  // insert current coeffs
211  for (Index j=0; j<mp_target->outerSize(); ++j)
212  for (typename SparseMatrixType::InnerIterator it(*mp_target,j); it; ++it)
213  (*this)(TargetRowMajor?j:it.index(), TargetRowMajor?it.index():j) = it.value();
214  }
215 
218  {
219  KeyType keyBitsMask = (1<<m_keyBitsOffset)-1;
220  if (!SwapStorage) // also means the map is sorted
221  {
222  mp_target->setZero();
223  mp_target->makeCompressed();
224  mp_target->reserve(nonZeros());
225  Index prevOuter = -1;
226  for (Index k=0; k<m_outerPackets; ++k)
227  {
228  const Index outerOffset = (1<<OuterPacketBits) * k;
229  typename HashMapType::iterator end = m_hashmaps[k].end();
230  for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it!=end; ++it)
231  {
232  const Index outer = (it->first >> m_keyBitsOffset) + outerOffset;
233  const Index inner = it->first & keyBitsMask;
234  if (prevOuter!=outer)
235  {
236  for (Index j=prevOuter+1;j<=outer;++j)
237  mp_target->startVec(j);
238  prevOuter = outer;
239  }
240  mp_target->insertBackByOuterInner(outer, inner) = it->second.value;
241  }
242  }
243  mp_target->finalize();
244  }
245  else
246  {
247  VectorXi positions(mp_target->outerSize());
248  positions.setZero();
249  // pass 1
250  for (Index k=0; k<m_outerPackets; ++k)
251  {
252  typename HashMapType::iterator end = m_hashmaps[k].end();
253  for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it!=end; ++it)
254  {
255  const Index outer = it->first & keyBitsMask;
256  ++positions[outer];
257  }
258  }
259  // prefix sum
260  StorageIndex count = 0;
261  for (Index j=0; j<mp_target->outerSize(); ++j)
262  {
263  StorageIndex tmp = positions[j];
264  mp_target->outerIndexPtr()[j] = count;
265  positions[j] = count;
266  count += tmp;
267  }
268  mp_target->makeCompressed();
269  mp_target->outerIndexPtr()[mp_target->outerSize()] = count;
270  mp_target->resizeNonZeros(count);
271  // pass 2
272  for (Index k=0; k<m_outerPackets; ++k)
273  {
274  const Index outerOffset = (1<<OuterPacketBits) * k;
275  typename HashMapType::iterator end = m_hashmaps[k].end();
276  for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it!=end; ++it)
277  {
278  const Index inner = (it->first >> m_keyBitsOffset) + outerOffset;
279  const Index outer = it->first & keyBitsMask;
280  // sorted insertion
281  // Note that we have to deal with at most 2^OuterPacketBits unsorted coefficients,
282  // moreover those 2^OuterPacketBits coeffs are likely to be sparse, an so only a
283  // small fraction of them have to be sorted, whence the following simple procedure:
284  Index posStart = mp_target->outerIndexPtr()[outer];
285  Index i = (positions[outer]++) - 1;
286  while ( (i >= posStart) && (mp_target->innerIndexPtr()[i] > inner) )
287  {
288  mp_target->valuePtr()[i+1] = mp_target->valuePtr()[i];
289  mp_target->innerIndexPtr()[i+1] = mp_target->innerIndexPtr()[i];
290  --i;
291  }
292  mp_target->innerIndexPtr()[i+1] = internal::convert_index<StorageIndex>(inner);
293  mp_target->valuePtr()[i+1] = it->second.value;
294  }
295  }
296  }
297  delete[] m_hashmaps;
298  }
299 
302  {
303  const Index outer = SetterRowMajor ? row : col;
304  const Index inner = SetterRowMajor ? col : row;
305  const Index outerMajor = outer >> OuterPacketBits; // index of the packet/map
306  const Index outerMinor = outer & OuterPacketMask; // index of the inner vector in the packet
307  const KeyType key = internal::convert_index<KeyType>((outerMinor<<m_keyBitsOffset) | inner);
308  return m_hashmaps[outerMajor][key].value;
309  }
310 
316  Index nonZeros() const
317  {
318  Index nz = 0;
319  for (Index k=0; k<m_outerPackets; ++k)
320  nz += static_cast<Index>(m_hashmaps[k].size());
321  return nz;
322  }
323 
324 
325  protected:
326 
328  SparseMatrixType* mp_target;
330  unsigned char m_keyBitsOffset;
331 };
332 
333 } // end namespace Eigen
334 
335 #endif // EIGEN_RANDOMSETTER_H
int i
RowXpr row(Index i) const
ColXpr col(Index i) const
Matrix< Scalar_, Rows_, Cols_, Options_, MaxRows_, MaxCols_ > & setZero(Index rows, Index cols)
The RandomSetter is a wrapper object allowing to set/update a sparse matrix with random access.
Definition: RandomSetter.h:163
MapTraits< ScalarWrapper >::KeyType KeyType
Definition: RandomSetter.h:172
RandomSetter(SparseMatrixType &target)
Definition: RandomSetter.h:189
Scalar & operator()(Index row, Index col)
Definition: RandomSetter.h:301
unsigned char m_keyBitsOffset
Definition: RandomSetter.h:330
MapTraits< ScalarWrapper >::Type HashMapType
Definition: RandomSetter.h:173
HashMapType * m_hashmaps
Definition: RandomSetter.h:327
SparseMatrixType::StorageIndex StorageIndex
Definition: RandomSetter.h:165
SparseMatrixType::Scalar Scalar
Definition: RandomSetter.h:164
Index nonZeros() const
Definition: RandomSetter.h:316
static constexpr int OuterPacketMask
Definition: RandomSetter.h:174
SparseMatrixType * mp_target
Definition: RandomSetter.h:328
static const lastp1_t end
const unsigned int RowMajorBit
Type
: TensorContractionSycl.h, provides various tensor contraction kernel for SYCL backend
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
SparseMat::Index size
std::map< KeyType, Scalar > Type
Definition: RandomSetter.h:30
static void setInvalidKey(Type &, const KeyType &)
Definition: RandomSetter.h:35
static void setInvalidKey(Type &, const KeyType &)
Definition: RandomSetter.h:50
std::unordered_map< KeyType, Scalar > Type
Definition: RandomSetter.h:45
std::ptrdiff_t j