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 // 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;
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;
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>
158  typedef typename SparseMatrixType::StorageIndex StorageIndex;
159 
160  struct ScalarWrapper {
163  };
164  typedef typename MapTraits<ScalarWrapper>::KeyType KeyType;
166  static constexpr int OuterPacketMask = (1 << OuterPacketBits) - 1;
167  enum {
168  SwapStorage = 1 - MapTraits<ScalarWrapper>::IsSorted,
169  TargetRowMajor = (SparseMatrixType::Flags & RowMajorBit) ? 1 : 0,
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;
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 
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:
296  SparseMatrixType* mp_target;
298  unsigned char m_keyBitsOffset;
299 };
300 
301 } // end namespace Eigen
302 
303 #endif // EIGEN_RANDOMSETTER_H
int i
Definition: BiCGSTAB_step_by_step.cpp:9
m col(1)
m row(1)
Scalar Scalar int size
Definition: benchVecAdd.cpp:17
SCALAR Scalar
Definition: bench_gemm.cpp:45
The RandomSetter is a wrapper object allowing to set/update a sparse matrix with random access.
Definition: RandomSetter.h:156
Index m_outerPackets
Definition: RandomSetter.h:297
MapTraits< ScalarWrapper >::KeyType KeyType
Definition: RandomSetter.h:164
~RandomSetter()
Definition: RandomSetter.h:203
RandomSetter(SparseMatrixType &target)
Definition: RandomSetter.h:180
Scalar & operator()(Index row, Index col)
Definition: RandomSetter.h:274
@ SwapStorage
Definition: RandomSetter.h:168
@ SetterRowMajor
Definition: RandomSetter.h:170
@ TargetRowMajor
Definition: RandomSetter.h:169
unsigned char m_keyBitsOffset
Definition: RandomSetter.h:298
MapTraits< ScalarWrapper >::Type HashMapType
Definition: RandomSetter.h:165
HashMapType * m_hashmaps
Definition: RandomSetter.h:295
SparseMatrixType::StorageIndex StorageIndex
Definition: RandomSetter.h:158
SparseMatrixType::Scalar Scalar
Definition: RandomSetter.h:157
Index nonZeros() const
Definition: RandomSetter.h:288
static constexpr int OuterPacketMask
Definition: RandomSetter.h:166
SparseMatrixType * mp_target
Definition: RandomSetter.h:296
static constexpr lastp1_t end
Definition: IndexedViewHelper.h:79
const unsigned int RowMajorBit
Definition: Constants.h:70
char char char int int * k
Definition: level2_impl.h:374
Eigen::Matrix< Scalar, Dynamic, Dynamic, ColMajor > tmp
Definition: level3_impl.h:365
Namespace containing all symbols from the Eigen library.
Definition: bench_norm.cpp:70
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:83
const unsigned nz
Definition: ConstraintElementsUnitTest.cpp:32
type
Definition: compute_granudrum_aor.py:141
Type
Type of JSON value.
Definition: rapidjson.h:513
Definition: RandomSetter.h:160
Scalar value
Definition: RandomSetter.h:162
ScalarWrapper()
Definition: RandomSetter.h:161
Definition: RandomSetter.h:29
std::map< KeyType, Scalar > Type
Definition: RandomSetter.h:31
int KeyType
Definition: RandomSetter.h:30
@ IsSorted
Definition: RandomSetter.h:32
static void setInvalidKey(Type &, const KeyType &)
Definition: RandomSetter.h:34
Definition: RandomSetter.h:41
static void setInvalidKey(Type &, const KeyType &)
Definition: RandomSetter.h:46
int KeyType
Definition: RandomSetter.h:42
std::unordered_map< KeyType, Scalar > Type
Definition: RandomSetter.h:43
@ IsSorted
Definition: RandomSetter.h:44
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2