GemaCoreLib
The GeMA Core library
gmSparseMatrixLayout.h
Go to the documentation of this file.
1 /************************************************************************
2 **
3 ** Copyright (C) 2014 by Carlos Augusto Teixera Mendes
4 ** All rights reserved.
5 **
6 ** This file is part of the "GeMA" software. It's use should respect
7 ** the terms in the license agreement that can be found together
8 ** with this source code.
9 ** It is provided AS IS, with NO WARRANTY OF ANY KIND,
10 ** INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR
11 ** A PARTICULAR PURPOSE.
12 **
13 ************************************************************************/
14 
25 #ifndef _GEMA_SPARSE_MATRIX_LAYOUT_H_
26 #define _GEMA_SPARSE_MATRIX_LAYOUT_H_
27 
28 #include "gmCoreConfig.h"
29 
30 #include <armadillo>
31 #include <QObject>
32 
33 #if 0
34 #define ENABLE_MATRIX_LAYOUT_INDEX_CACHE 1
35 #endif
36 
37 #ifdef ENABLE_MATRIX_LAYOUT_INDEX_CACHE
38 #include "gmThreadLocalStorage.h"
39 #endif
40 
41 
42 class GmLogCategory;
43 
46 {
49 };
50 
51 
66 {
67  Q_OBJECT
68 
69 public:
71  GmSparseMatrixLayout(GmSparseMatrixLayoutTypes type) : _type(type), _shared(false) {}
72 
74  virtual ~GmSparseMatrixLayout() {}
75 
77  virtual bool empty() const = 0;
78 
80  virtual void clear() = 0;
81 
83  virtual int index(int row, int col) const = 0;
84 
90  virtual int dindex(int n) const = 0;
91 
93  virtual void printStatistics(const GmLogCategory& logger) const = 0;
94 
96  void emitLayoutCompleted() { emit layoutCompleted(); }
97 
99  mutable bool _shared;
100 
101 #ifdef ENABLE_TESTS
102  virtual void checkLayoutData() const = 0;
103 #endif
104 
105 signals:
110  void layoutCompleted();
111 
112 private:
113  Q_DISABLE_COPY(GmSparseMatrixLayout)
114 };
115 
116 
122 template <class IndexType, GmSparseMatrixLayoutTypes T>
124 {
125 public:
132  {
133  _ptr = _index = NULL;
134  _n = _nnz = 0;
135  _arma = arma;
136 
137 #ifdef ENABLE_MATRIX_LAYOUT_INDEX_CACHE
138  _lastIndex.init(-1);
139 #endif
140  }
141 
144  {
145  delete[] _ptr;
146  delete[] _index;
147  }
148 
149  // See comments on the base class
150  virtual bool empty() const { return _n == 0; }
151 
152  // See comments on the base class
153  virtual void clear()
154  {
155  delete[] _ptr;
156  delete[] _index;
157  _ptr = _index = NULL;
158  _n = _nnz = 0;
159 
160 #ifdef ENABLE_MATRIX_LAYOUT_INDEX_CACHE
161  _lastIndex.init(-1);
162 #endif
163  }
164 
165  // Index implementation is specialized explicitly in the cpp file to avoid the need of an 'if' checking
166  // the layout type. Although this is static and the compiler should be able to optimize the if, looking
167  // at the generated optimized code does not clarify if the compiler is really doing that :(.
168  virtual int index(int row, int col) const;
169 
170  // See comments on the base class. TODO: Should we try to optimize searching first in the center values?
171  virtual int dindex(int n) const { return indexWorker(_ptr[n], _ptr[n+1], n); }
172 
173  virtual void printStatistics(const GmLogCategory& logger) const;
174 
175 #ifdef ENABLE_TESTS
176  virtual void checkLayoutData() const;
177 #endif
178 
179  IndexType* _ptr;
180  IndexType* _index;
181  int _n;
182  int _nnz;
183  int _arma;
184 
185 #ifdef ENABLE_MATRIX_LAYOUT_INDEX_CACHE
186  mutable GmTLS<int, true> _lastIndex;
187 #endif
188 
189 protected:
190  int indexWorker(int start, int end, int ind) const
191  {
192  // Simple linear search. Number of non zeros should be small!
193  // Should we change for a binary search if the array length gets past a limit?
194  // Should we unroll part of the loop? Should we try to use vector instructions?
195  // Should we remember the last search and begin from there?
196  // TODO: Optimize.
197  // Interesting links:
198  // - https://dirtyhandscoding.wordpress.com/2017/08/25/performance-comparison-linear-search-vs-binary-search/
199  // - https://schani.wordpress.com/2010/04/30/linear-vs-binary-search/
200  // - https://blog.demofox.org/2017/06/20/simd-gpu-friendly-branchless-binary-search/
201  // - https://www.agner.org/optimize/
202 #if 1
203  // Standard
204  int i = start;
205  for(; i < end; ++i)
206  {
207  if(_index[i] >= ind)
208  return (_index[i] == ind) ? i : -1;
209  }
210  return -1;
211 #endif
212 #if 0
213  // Cache
214  int& li = _lastIndex.localData();
215  int i = (li > start && li < end && _index[li] <= ind) ? li : start;
216  for(; i < end; ++i)
217  {
218  if(_index[i] >= ind)
219  {
220  li = i;
221  return (_index[i] == ind) ? i : -1;
222  }
223  }
224  li = -1;
225  return -1;
226 #endif
227 #if 0
228  // Cache unroll
229  int& li = _lastIndex.localData();
230  int i = (li > start && li < end && _index[li] <= ind) ? li : start;
231  while(i+3 < end)
232  {
233  if(_index[i + 0] >= ind) { li = i + 0; return (_index[i + 0] == ind) ? i + 0 : -1; }
234  if(_index[i + 1] >= ind) { li = i + 1; return (_index[i + 1] == ind) ? i + 1 : -1; }
235  if(_index[i + 2] >= ind) { li = i + 2; return (_index[i + 2] == ind) ? i + 2 : -1; }
236  if(_index[i + 3] >= ind) { li = i + 3; return (_index[i + 3] == ind) ? i + 3 : -1; }
237  i += 4;
238  }
239  for(; i < end; ++i)
240  {
241  if(_index[i] >= ind)
242  {
243  li = i;
244  return (_index[i] == ind) ? i : -1;
245  }
246  }
247  li = -1;
248  return -1;
249 #endif
250 #if 0
251  // Bin search
252  IndexType* pos = std::lower_bound(_index+start, _index+end, ind);
253  return (pos < _index+end && *pos == ind) ? pos - _index : -1;
254 #endif
255 #if 0
256  // Unroll
257  int i = start;
258  while(i+3 < end)
259  {
260  if(_index[i + 0] >= ind) return (_index[i + 0] == ind) ? i + 0 : -1;
261  if(_index[i + 1] >= ind) return (_index[i + 1] == ind) ? i + 1 : -1;
262  if(_index[i + 2] >= ind) return (_index[i + 2] == ind) ? i + 2 : -1;
263  if(_index[i + 3] >= ind) return (_index[i + 3] == ind) ? i + 3 : -1;
264  i += 4;
265  }
266  for(; i < end; ++i)
267  {
268  if(_index[i] >= ind)
269  return (_index[i] == ind) ? i : -1;
270  }
271  return -1;
272 #endif
273 #if 0
274  // Count
275  int cnt = start;
276  for(int i = start; i<end; i++)
277  cnt += (_index[i] < ind);
278  return (cnt < end && _index[cnt] == ind) ? cnt : -1;
279 #endif
280  }
281 };
282 
283 
284 
287 
296 
297 // Currently, the <int, CSC> and <uword, CSR> configurations are used only during unit tests
298 #ifdef ENABLE_TESTS
299 typedef GmCSxSparseMatrixLayout<arma::uword, GM_CSR_SPARSE_FORMAT> GmCSRArmadilloSparseMatrixLayout;
300 typedef GmCSxSparseMatrixLayout<int, GM_CSC_SPARSE_FORMAT> GmCSCSparseMatrixLayout;
301 #endif
302 
303 
304 #endif
305 
GmCSxSparseMatrixLayout< arma::uword, GM_CSC_SPARSE_FORMAT > GmCSCArmadilloSparseMatrixLayout
CSC layout with 64 bits integer index.
Definition: gmSparseMatrixLayout.h:295
GmCSxSparseMatrixLayout(bool arma)
Constructor.
Definition: gmSparseMatrixLayout.h:131
GmSparseMatrixLayoutTypes _type
The stored sparse matrix type.
Definition: gmSparseMatrixLayout.h:98
virtual int dindex(int n) const
Returns the index for the value in the diagonal of the given matrix row (column). Returns -1 if the v...
Definition: gmSparseMatrixLayout.h:171
Declaration of the GmTLS class.
virtual ~GmSparseMatrixLayout()
Virtual destructor.
Definition: gmSparseMatrixLayout.h:74
virtual void clear()
Clears the layout releasing memory and making the matrix a zero matrix.
Definition: gmSparseMatrixLayout.h:153
Declaration of usefull configuration definitions for the Core library.
Data is stored in "Compressed Sparse Column" format.
Definition: gmSparseMatrixLayout.h:47
A class that works together with GmThreadManager to provide thread local storage.
Definition: gmThreadLocalStorage.h:131
GmCSxSparseMatrixLayout< int, GM_CSR_SPARSE_FORMAT > GmCSRSparseMatrixLayout
CSR layout with 32 bits integer index.
Definition: gmSparseMatrixLayout.h:286
int _nnz
The number of elements stored in the matrix (in some cases zero values can be stored,...
Definition: gmSparseMatrixLayout.h:182
Data is stored in "Compressed Sparse Row" (or old Yale) format.
Definition: gmSparseMatrixLayout.h:48
GmSparseMatrixLayoutTypes
Supported sparse matrix types by GmSparseMatrixLayout sub-classes.
Definition: gmSparseMatrixLayout.h:45
GmSparseMatrixLayout(GmSparseMatrixLayoutTypes type)
Constructor.
Definition: gmSparseMatrixLayout.h:71
T & localData(int tid)
Returns the given thread local data as a modifiable reference.
Definition: gmThreadLocalStorage.h:163
virtual int index(int row, int col) const =0
Returns the index for the value in the given matrix row, col. Returns -1 if the value is not part of ...
int _n
The number of rows(CSR)/columns(CSC) in the matrix.
Definition: gmSparseMatrixLayout.h:181
virtual bool empty() const
Returns true if the layout is empty.
Definition: gmSparseMatrixLayout.h:150
A structure for storing a matrix layout in either CSR or CSC format. The template type defines the ty...
Definition: gmSparseMatrixLayout.h:123
#define GMC_API_EXPORT
Macro for controling if the class is being exported (GEMA_CORE_LIB defined) or imported (GEMA_CORE_LI...
Definition: gmCoreConfig.h:35
virtual void printStatistics(const GmLogCategory &logger) const =0
Print layout statistics to the given logger.
Class representing a category with multiple logging levels.
Definition: gmLog.h:58
IndexType * _ptr
Vector storing the index of the first non zero element of each matrix row(CSR)/column(CSC)....
Definition: gmSparseMatrixLayout.h:179
A base structure for storing layout data for sparse marices (fill structure or non zero positions)....
Definition: gmSparseMatrixLayout.h:65
int _arma
Stores 1 if the layout should store 1 extra space per vector to be compatible with Armadillo requirem...
Definition: gmSparseMatrixLayout.h:183
virtual ~GmCSxSparseMatrixLayout()
Destuctor.
Definition: gmSparseMatrixLayout.h:143
IndexType * _index
Vector storing the column(CSR)/row(CSC) index for each non zero value. Size = _nnz.
Definition: gmSparseMatrixLayout.h:180
bool _shared
Is this layout shared? Mutable to enable matrices sharing a layout to specify so.
Definition: gmSparseMatrixLayout.h:99
void emitLayoutCompleted()
Emits the layoutCompleted signal.
Definition: gmSparseMatrixLayout.h:96