IVSparse  v1.0
A sparse matrix compression library.
VCSC_Methods.hpp
Go to the documentation of this file.
1 
9 #pragma once
10 
11 namespace IVSparse {
12 
13 //* Getters *//
14 
15 // Gets the element stored at the given row and column
16 template <typename T, typename indexT, bool columnMajor>
17 T SparseMatrix<T, indexT, 2, columnMajor>::coeff(uint32_t row, uint32_t col) {
18  return (*this)(row, col);
19 }
20 
21 // Check for Column Major
22 template <typename T, typename indexT, bool columnMajor>
24  return columnMajor;
25 }
26 
27 // get the values vector
28 template <typename T, typename indexT, bool columnMajor>
30  return values[vec];
31 }
32 
33 // get the counts vector
34 template <typename T, typename indexT, bool columnMajor>
36  return counts[vec];
37 }
38 
39 // get the indices vector
40 template <typename T, typename indexT, bool columnMajor>
42  uint32_t vec) const {
43  return indices[vec];
44 }
45 
46 // get the number of unique values in a vector
47 template <typename T, typename indexT, bool columnMajor>
49  uint32_t vec) const {
50  if (valueSizes == nullptr) {
51  return 0;
52  }
53  return valueSizes[vec];
54 }
55 
56 // get the number of indices in a vector
57 template <typename T, typename indexT, bool columnMajor>
59  uint32_t vec) const {
60  if (indexSizes == nullptr) {
61  return 0;
62  }
63  return indexSizes[vec];
64 }
65 
66 // get the vector at the given index
67 template <typename T, typename indexT, bool columnMajor>
70  return (*this)[vec];
71 }
72 
73 //* Utility Methods *//
74 
75 // Writes the matrix to file
76 template <typename T, typename indexT, bool columnMajor>
78  // Open the file
79  FILE *fp = fopen(filename, "wb");
80 
81  // Write the metadata
82  fwrite(metadata, 1, NUM_META_DATA * sizeof(uint32_t), fp);
83 
84  // write the lengths of the vectors
85  for (uint32_t i = 0; i < outerDim; ++i) {
86  fwrite(&valueSizes[i], 1, sizeof(indexT), fp);
87  }
88  for (uint32_t i = 0; i < outerDim; ++i) {
89  fwrite(&indexSizes[i], 1, sizeof(indexT), fp);
90  }
91 
92  // write the values
93  for (uint32_t i = 0; i < outerDim; ++i) {
94  fwrite(values[i], 1, valueSizes[i] * sizeof(T), fp);
95  }
96 
97  // write the counts
98  for (uint32_t i = 0; i < outerDim; ++i) {
99  fwrite(counts[i], 1, valueSizes[i] * sizeof(indexT), fp);
100  }
101 
102  // write the indices
103  for (uint32_t i = 0; i < outerDim; ++i) {
104  fwrite(indices[i], 1, indexSizes[i] * sizeof(indexT), fp);
105  }
106 
107  // close the file
108  fclose(fp);
109 }
110 
111 // Prints the matrix dense to console
112 template <typename T, typename indexT, bool columnMajor>
114  std::cout << std::endl;
115  std::cout << "IVSparse Matrix" << std::endl;
116 
117  // if the matrix is less than 100 rows and columns print the whole thing
118  if (numRows < 100 && numCols < 100) {
119  // print the matrix
120  for (uint32_t i = 0; i < numRows; i++) {
121  for (uint32_t j = 0; j < numCols; j++) {
122  std::cout << coeff(i, j) << " ";
123  }
124  std::cout << std::endl;
125  }
126  } else if (numRows > 100 && numCols > 100) {
127  // print the first 100 rows and columns
128  for (uint32_t i = 0; i < 100; i++) {
129  for (uint32_t j = 0; j < 100; j++) {
130  std::cout << coeff(i, j) << " ";
131  }
132  std::cout << std::endl;
133  }
134  }
135 
136  std::cout << std::endl;
137 }
138 
139 // Convert a IVCSC matrix to CSC
140 template <typename T, typename indexT, bool columnMajor>
142  // create a new sparse matrix
143  Eigen::SparseMatrix<T, columnMajor ? Eigen::ColMajor : Eigen::RowMajor>
144  eigenMatrix(numRows, numCols);
145 
146  // iterate over the matrix
147  for (uint32_t i = 0; i < outerDim; ++i) {
148  for (typename SparseMatrix<T, indexT, 2>::InnerIterator it(*this, i); it;
149  ++it) {
150  // add the value to the matrix
151  eigenMatrix.insert(it.row(), it.col()) = it.value();
152  }
153  }
154 
155  // finalize the matrix
156  eigenMatrix.makeCompressed();
157 
158  // make a CSC matrix
160 
161  // return the matrix
162  return CSCMatrix;
163 }
164 
165 // Convert a IVCSC matrix to a VCSC matrix
166 template <typename T, typename indexT, bool columnMajor>
168  // make a pointer for the CSC pointers
169  T *values = (T *)malloc(nnz * sizeof(T));
170  indexT *indices = (indexT *)malloc(nnz * sizeof(indexT));
171  indexT *colPtrs = (indexT *)malloc((outerDim + 1) * sizeof(indexT));
172 
173  colPtrs[0] = 0;
174 
175  // make an array of ordered maps to hold the data
176  std::map<indexT, T> dict[outerDim];
177 
178  // iterate through the data using the iterator
179  for (uint32_t i = 0; i < outerDim; ++i) {
180  size_t count = 0;
181 
182  for (typename SparseMatrix<T, indexT, 2>::InnerIterator it(*this, i); it; ++it) {
183  dict[i][it.getIndex()] = it.value();
184  count++;
185  }
186  colPtrs[i + 1] = colPtrs[i] + count;
187  }
188  size_t count = 0;
189 
190  // loop through the dictionary and populate values and indices
191  for (uint32_t i = 0; i < outerDim; ++i) {
192  for (auto &pair : dict[i]) {
193  values[count] = pair.second;
194  indices[count] = pair.first;
195  count++;
196  }
197  }
198 
199  // return a IVCSC matrix from the CSC vectors
200  IVSparse::SparseMatrix<T, indexT, 3, columnMajor> mat(values, indices, colPtrs, numRows, numCols, nnz);
201 
202  // free the CSC vectors
203  free(values);
204  free(indices);
205  free(colPtrs);
206 
207  return mat;
208 }
209 
210 // converts the ivsparse matrix to an eigen one and returns it
211 template <typename T, typename indexT, bool columnMajor>
212 Eigen::SparseMatrix<T, columnMajor ? Eigen::ColMajor : Eigen::RowMajor> SparseMatrix<T, indexT, 2, columnMajor>::toEigen() {
213 
214  #ifdef IVSPARSE_DEBUG
215  // assert that the matrix is not empty
216  assert(outerDim > 0 && "Cannot convert an empty matrix to an Eigen matrix!");
217  #endif
218 
219  // create a new sparse matrix
220  Eigen::SparseMatrix<T, columnMajor ? Eigen::ColMajor : Eigen::RowMajor> eigenMatrix(numRows, numCols);
221 
222  // iterate over the matrix
223  for (uint32_t i = 0; i < outerDim; ++i) {
224  for (typename SparseMatrix<T, indexT, 2>::InnerIterator it(*this, i); it; ++it) {
225  // add the value to the matrix
226  eigenMatrix.insert(it.row(), it.col()) = it.value();
227  }
228  }
229 
230  // finalize the matrix
231  eigenMatrix.makeCompressed();
232 
233  // return the matrix
234  return eigenMatrix;
235 }
236 
237 //* Conversion/Transformation Methods *//
238 
239 // appends a vector to the back of the storage order of the matrix
240 template <typename T, typename indexT, bool columnMajor>
242 
243  #ifdef IVSPARSE_DEBUG
244  // check that the vector is the correct size
245  assert((vec.getLength() == innerDim) &&
246  "The vector must be the same size as the outer dimension of the "
247  "matrix!");
248  #endif
249 
250  // check if the matrix is empty
251  if (numRows < 1 && numCols < 1) [[unlikely]] {
253  } else {
254  // check if the vector is empty, if so change the implementation details
255  if (vec.nonZeros() == 0) {
256  if (columnMajor) {
257  numCols++;
258  } else {
259  numRows++;
260  }
261  outerDim++;
262 
263  // update metadata
264  metadata[2] = outerDim;
265 
266  // realloc the vectors
267  try {
268  values = (T **)realloc(values, outerDim * sizeof(T *));
269  counts = (indexT **)realloc(counts, outerDim * sizeof(indexT *));
270  indices = (indexT **)realloc(indices, outerDim * sizeof(indexT *));
271  valueSizes = (indexT *)realloc(valueSizes, outerDim * sizeof(indexT));
272  indexSizes = (indexT *)realloc(indexSizes, outerDim * sizeof(indexT));
273  } catch (std::bad_alloc &e) {
274  std::cerr << "Error: " << e.what() << std::endl;
275  exit(1);
276  }
277 
278  // set the last vector to be empty
279  values[outerDim - 1] = nullptr;
280  counts[outerDim - 1] = nullptr;
281  indices[outerDim - 1] = nullptr;
282  valueSizes[outerDim - 1] = 0;
283  indexSizes[outerDim - 1] = 0;
284 
285  calculateCompSize();
286  return;
287  } else {
288  #ifdef IVSPARSE_DEBUG
289  // check that the vector is the correct size
290  if ((vec.getLength() != innerDim))
291  throw std::invalid_argument(
292  "The vector must be the same size as the outer dimension of the "
293  "matrix!");
294  #endif
295 
296  outerDim++;
297  nnz += vec.nonZeros();
298 
299  if (columnMajor) {
300  numCols++;
301  } else {
302  numRows++;
303  }
304 
305  // update metadata
306  metadata[2] = outerDim;
307  metadata[3] = nnz;
308 
309  // realloc the vectors
310  try {
311  values = (T **)realloc(values, outerDim * sizeof(T *));
312  counts = (indexT **)realloc(counts, outerDim * sizeof(indexT *));
313  indices = (indexT **)realloc(indices, outerDim * sizeof(indexT *));
314  valueSizes = (indexT *)realloc(valueSizes, outerDim * sizeof(indexT));
315  indexSizes = (indexT *)realloc(indexSizes, outerDim * sizeof(indexT));
316  } catch (std::bad_alloc &e) {
317  std::cerr << "Error: " << e.what() << std::endl;
318  exit(1);
319  }
320 
321  // set the sizes of the new vector
322  valueSizes[outerDim - 1] = vec.uniqueVals();
323  indexSizes[outerDim - 1] = vec.nonZeros();
324 
325  // allocate the new vectors
326  try {
327  values[outerDim - 1] =
328  (T *)malloc(valueSizes[outerDim - 1] * sizeof(T));
329  counts[outerDim - 1] =
330  (indexT *)malloc(sizeof(indexT) * valueSizes[outerDim - 1]);
331  indices[outerDim - 1] =
332  (indexT *)malloc(indexSizes[outerDim - 1] * sizeof(indexT));
333  } catch (std::bad_alloc &e) {
334  std::cerr << "Error: " << e.what() << std::endl;
335  exit(1);
336  }
337 
338  // copy the data from the vector to the new vectors
339  memcpy(values[outerDim - 1], vec.getValues(),
340  valueSizes[outerDim - 1] * sizeof(T));
341  memcpy(counts[outerDim - 1], vec.getCounts(),
342  valueSizes[outerDim - 1] * sizeof(indexT));
343  memcpy(indices[outerDim - 1], vec.getIndices(),
344  indexSizes[outerDim - 1] * sizeof(indexT));
345 
346  // update the compressed size
347  calculateCompSize();
348  }
349  }
350 
351 } // end append
352 
353 // tranposes the ivsparse matrix
354 template <typename T, typename indexT, bool columnMajor>
356  // make a data structure to store the tranpose
357  std::unordered_map<T, std::vector<indexT>> mapsT[innerDim];
358 
359  // populate the transpose data structure
360  for (uint32_t i = 0; i < outerDim; ++i) {
361  for (typename SparseMatrix<T, indexT, 2>::InnerIterator it(*this, i); it;
362  ++it) {
363  // add the value to the map
364  if constexpr (columnMajor) {
365  mapsT[it.row()][it.value()].push_back(it.col());
366  } else {
367  mapsT[it.col()][it.value()].push_back(it.row());
368  }
369  }
370  }
371 
372  // create a new matrix passing in transposedMap
373  IVSparse::SparseMatrix<T, indexT, 2, columnMajor> temp(mapsT, numRows, numCols);
374 
375  // return the new matrix
376  return temp;
377 }
378 
379 // Transpose In Place Method
380 template <typename T, typename indexT, bool columnMajor>
382  // make a data structure to store the tranpose
383  std::unordered_map<T, std::vector<indexT>> mapsT[innerDim];
384 
385  // populate the transpose data structure
386  for (uint32_t i = 0; i < outerDim; ++i) {
387  for (typename SparseMatrix<T, indexT, 2>::InnerIterator it(*this, i); it;
388  ++it) {
389  // add the value to the map
390  if constexpr (columnMajor) {
391  mapsT[it.row()][it.value()].push_back(it.col());
392  } else {
393  mapsT[it.col()][it.value()].push_back(it.row());
394  }
395  }
396  }
397 
398  // set this to the transposed matrix
400  numCols);
401 }
402 
403 // slice method that returns a vector of IVSparse vectors
404 template <typename T, typename indexT, bool columnMajor>
405 std::vector<typename IVSparse::SparseMatrix<T, indexT, 2, columnMajor>::Vector>
406 SparseMatrix<T, indexT, 2, columnMajor>::slice(uint32_t start, uint32_t end) {
407 
408  #ifdef IVSPARSE_DEBUG
409  assert(start < outerDim && end <= outerDim && start < end &&
410  "Invalid start and end values!");
411  #endif
412 
413  // make a vector of IVSparse vectors
414  std::vector<
416  vecs(end - start);
417 
418  // grab the vectors and add them to vecs
419  for (uint32_t i = start; i < end; ++i) {
420  // make a temp vector
422 
423  // add the vector to vecs
424  vecs[i - start] = temp;
425  }
426 
427  // return the vector
428  return vecs;
429 }
430 
431 } // end namespace IVSparse
Definition: IVCSC_Iterator.hpp:25
Definition: CSC_SparseMatrix.hpp:24
Definition: VCSC_SparseMatrix.hpp:21
uint32_t nonZeros() const
Definition: IVSparse_Base_Methods.hpp:39
Definition: IVCSC_SparseMatrix.hpp:29
IVSparse::SparseMatrix< T, indexT, compressionLevel, columnMajor >::Vector getVector(uint32_t vec)
Definition: IVCSC_Methods.hpp:47
IVSparse::SparseMatrix< T, indexT, compressionLevel, columnMajor > transpose()
Definition: IVCSC_Methods.hpp:329
void append(typename SparseMatrix< T, indexT, compressionLevel, columnMajor >::Vector &vec)
Definition: IVCSC_Methods.hpp:245
IVSparse::SparseMatrix< T, indexT, 1, columnMajor > toCSC()
Definition: IVCSC_Methods.hpp:126
T coeff(uint32_t row, uint32_t col)
Definition: IVCSC_Methods.hpp:17
void write(const char *filename)
Definition: IVCSC_Methods.hpp:72
void print()
Definition: IVCSC_Methods.hpp:97
Eigen::SparseMatrix< T, columnMajor ? Eigen::ColMajor :Eigen::RowMajor > toEigen()
Definition: IVCSC_Methods.hpp:210
bool isColumnMajor() const
Definition: IVCSC_Methods.hpp:30
std::vector< typename IVSparse::SparseMatrix< T, indexT, compressionLevel, columnMajor >::Vector > slice(uint32_t start, uint32_t end)
Definition: IVCSC_Methods.hpp:416
void inPlaceTranspose()
Definition: IVCSC_Methods.hpp:374