Traffic Flow Dynamics Model
SparseMatrix.hpp
1 
5 
6 #ifndef SparseMatrix_hpp
7 #define SparseMatrix_hpp
8 
9 #include <fstream>
10 #include <iostream>
11 #include <random>
12 #include <stdexcept>
13 #include <string>
14 #include <typeinfo>
15 #include <unordered_map>
16 #include <vector>
17 
18 template <typename T> class SparseMatrix {
19  std::unordered_map<int, T> _matrix = {};
20  int _rows = 0, _cols = 0;
21  static constexpr T _defaultReturn = 0;
22  bool _setSeed = false;
23  int _seed;
24  uint _randomGeneratedNumbers;
25 
26 public:
27  SparseMatrix() = default;
32  SparseMatrix(int rows, int cols) {
33  rows < 0 || cols < 0
34  ? throw std::invalid_argument("SparseMatrix: rows and cols must be > 0")
35  : _rows = rows,
36  _cols = cols;
37  };
41  SparseMatrix(int index) {
42  index < 0 ? throw std::invalid_argument("SparseMatrix: index must be > 0")
43  : _rows = index,
44  _cols = 1;
45  };
49  static void encode(std::string const &filename) {
50  std::fstream file;
51  int rows, cols;
52  std::unordered_map<int, T> matrix = {};
53  file.open(filename, std::ios::in);
54  file >> rows >> cols;
55  T value;
56  int i = 0;
57  while (file >> value) {
58  if (value != 0) {
59  matrix.emplace(std::make_pair(i, value));
60  }
61  ++i;
62  }
63  file.close();
64  file.open(filename, std::ios::out);
65  file << rows << '\t' << cols << '\n';
66  for (auto const &[key, value] : matrix) {
67  file << key << '\t' << value << '\n';
68  }
69  file.close();
70  }
74  static void decode(std::string const &filename) {
75  std::fstream file(filename);
76  int rows, cols, index;
77  std::unordered_map<int, T> matrix = {};
78  file >> rows >> cols;
79  T value;
80  while (file >> index >> value) {
81  matrix.emplace(std::make_pair(index, value));
82  }
83  file.close();
84  file.open(filename, std::ios::out);
85  file << rows << '\t' << cols << '\n';
86  for (int i = 0; i < rows * cols; ++i) {
87  if (matrix.find(i) != matrix.end()) {
88  file << matrix[i] << '\t';
89  } else {
90  file << 0 << '\t';
91  }
92  if ((i + 1) % cols == 0) {
93  file << '\n';
94  }
95  }
96  }
99  void setSeed(int seed) noexcept {
100  _seed = seed;
101  _randomGeneratedNumbers = 0;
102  _setSeed = true;
103  }
109  void insert(int i, int j, T value) {
110  if (i >= _rows || j >= _cols || i < 0 || j < 0) {
111  throw std::out_of_range("Index out of range");
112  }
113  _matrix.emplace(std::make_pair(i * _cols + j, value));
114  };
119  void insert(int i, T value) {
120  if (i >= _rows * _cols || i < 0) {
121  throw std::out_of_range("Index out of range");
122  }
123  _matrix.emplace(std::make_pair(i, value));
124  };
131  void insert_or_assign(int i, int j, T value) {
132  if (i >= _rows || j >= _cols || i < 0 || j < 0) {
133  throw std::out_of_range("Index out of range");
134  }
135  _matrix.insert_or_assign(i * _cols + j, value);
136  };
142  void insert_or_assign(int index, T value) {
143  if (index < 0 || index > _rows * _cols - 1) {
144  throw std::out_of_range("Index out of range");
145  }
146  _matrix.insert_or_assign(index, value);
147  };
153  void erase(int i, int j) {
154  if (i >= _rows || j >= _cols || i < 0 || j < 0) {
155  throw std::out_of_range("Index out of range");
156  }
157  _matrix.find(i * _cols + j) != _matrix.end()
158  ? _matrix.erase(i * _cols + j)
159  : throw std::runtime_error("SparseMatrix: element not found");
160  };
164  void eraseRow(int index) {
165  if (index < 0 || index > _rows - 1) {
166  throw std::out_of_range("Index out of range");
167  }
168  for (int i = 0; i < _cols; ++i) {
169  _matrix.erase(index * _cols + i);
170  }
171  std::unordered_map<int, T> new_matrix = {};
172  for (auto const &[key, value] : _matrix) {
173  if (key / _cols < index) {
174  new_matrix.emplace(std::make_pair(key, value));
175  } else {
176  new_matrix.emplace(std::make_pair(key - _cols, value));
177  }
178  }
179  --_rows;
180  _matrix = new_matrix;
181  };
185  void eraseColumn(int index) {
186  if (index < 0 || index > _cols - 1) {
187  throw std::out_of_range("Index out of range");
188  }
189  for (int i = 0; i < _rows; ++i) {
190  _matrix.erase(i * _cols + index);
191  }
192  std::unordered_map<int, T> new_matrix = {};
193  for (auto const &[key, value] : _matrix) {
194  if (key % _cols < index) {
195  new_matrix.emplace(std::make_pair(key - key / _cols, value));
196  } else {
197  new_matrix.emplace(
198  std::make_pair(key / _cols * (_cols - 1) + key % _cols - 1, value));
199  }
200  }
201  --_cols;
202  _matrix = new_matrix;
203  };
204  void clear() noexcept {
205  _matrix.clear();
206  _rows = 0;
207  _cols = 0;
208  };
214  bool contains(int i, int j) const {
215  if (i >= _rows || j >= _cols || i < 0 || j < 0) {
216  throw std::out_of_range("Index out of range");
217  }
218  return _matrix.contains(i * _cols + j);
219  };
224  bool contains(int const index) const {
225  if (index < 0 || index > _rows * _cols - 1) {
226  throw std::out_of_range("Index out of range");
227  }
228  return _matrix.contains(index);
229  };
234  if (_rows != _cols) {
235  throw std::runtime_error(
236  "SparseMatrix: getDegreeVector only works on square matrices");
237  }
238  auto degreeVector = SparseMatrix<int>(_rows, 1);
239  for (auto &i : _matrix) {
240  degreeVector.insert_or_assign(i.first / _cols, 0,
241  degreeVector.at(i.first / _cols, 0) + 1);
242  }
243  return degreeVector;
244  };
249  if (_rows != _cols) {
250  throw std::runtime_error(
251  "SparseMatrix: getStrengthVector only works on square matrices");
252  }
253  auto strengthVector = SparseMatrix<double>(_rows, 1);
254  for (auto &i : _matrix) {
255  strengthVector.insert_or_assign(
256  i.first / _cols, 0, strengthVector.at(i.first / _cols, 0) + i.second);
257  }
258  return strengthVector;
259  };
264  if (_rows != _cols) {
265  throw std::runtime_error(
266  "SparseMatrix: getLaplacian only works on square matrices");
267  }
268  auto laplacian = SparseMatrix<int>(_rows, _cols);
269  for (auto &i : _matrix) {
270  laplacian.insert_or_assign(i.first / _cols, i.first % _cols, -1);
271  }
272  auto degreeVector = this->getDegreeVector();
273  for (int i = 0; i < _rows; i++) {
274  laplacian.insert_or_assign(i, i, degreeVector.at(i, 0));
275  }
276  return laplacian;
277  };
278 
283  SparseMatrix getRow(int index) const {
284  if (index >= _rows || index < 0) {
285  throw std::out_of_range("Index out of range");
286  }
287  SparseMatrix row(1, _cols);
288  for (auto &it : _matrix) {
289  if (it.first / _cols == index) {
290  row.insert(it.first % _cols, it.second);
291  }
292  }
293  return row;
294  }
299  SparseMatrix getCol(int index) const {
300  if (index >= _cols || index < 0) {
301  throw std::out_of_range("Index out of range");
302  }
303  SparseMatrix col(_rows, 1);
304  for (auto &it : _matrix) {
305  if (it.first % _cols == index) {
306  col.insert(it.first / _cols, it.second);
307  }
308  }
309  return col;
310  }
315  std::pair<int, T> getRndRowElement(int index) {
316  if (index >= _rows || index < 0)
317  throw std::out_of_range("Index out of range");
318  auto row = this->getRow(index);
319  if (row.size() == 0)
320  throw std::runtime_error("SparseMatrix: row is empty");
321  std::pair<int, T> res = row.getRndElement();
322  res.first += index * _cols;
323  return res;
324  }
329  std::pair<int, T> getRndColElement(int index) {
330  if (index >= _cols || index < 0)
331  throw std::out_of_range("Index out of range");
332  auto col = this->getCol(index);
333  if (col.size() == 0)
334  throw std::runtime_error("SparseMatrix: col is empty");
335  std::pair<int, T> res = col.getRndElement();
336  res.first *= _cols;
337  res.first += index;
338  return res;
339  }
343  std::pair<int, T> getRndElement() {
344  if (this->size() == 0)
345  throw std::runtime_error("SparseMatrix: matrix is empty");
346  auto it = _matrix.begin();
347  std::mt19937 rng(std::random_device{}());
348  if (_setSeed) {
349  rng.seed(_seed);
350  rng.discard(
351  _randomGeneratedNumbers); // maybe not that smart, but it works
352  }
353  auto dist = std::uniform_int_distribution<int>(0, this->size() - 1);
354  std::advance(it, dist(rng));
355  std::pair<int, T> res = *it;
356  ++_randomGeneratedNumbers;
357  return res;
358  }
362  SparseMatrix<double> normRows(_rows, _cols);
363  for (int index = 0; index < _rows; index++) {
364  auto row = this->getRow(index);
365  double sum = 0.;
366  for (auto &it : row) {
367  sum += std::abs(it.second);
368  }
369  sum < std::numeric_limits<double>::epsilon() ? sum = 1. : sum = sum;
370  for (auto &it : row) {
371  normRows.insert(it.first + index * _cols, it.second / sum);
372  }
373  }
374  return normRows;
375  }
379  SparseMatrix<double> normCols(_rows, _cols);
380  for (int index = 0; index < _cols; index++) {
381  auto col = this->getCol(index);
382  double sum = 0.;
383  for (auto &it : col) {
384  sum += std::abs(it.second);
385  }
386  sum < std::numeric_limits<double>::epsilon() ? sum = 1. : sum = sum;
387  for (auto &it : col) {
388  normCols.insert(it.first * _cols + index, it.second / sum);
389  }
390  }
391  return normCols;
392  }
395  int getRowDim() const noexcept { return this->_rows; }
398  int getColDim() const noexcept { return this->_cols; }
401  int size() const noexcept { return _matrix.size(); };
404  int max_size() const noexcept { return this->_rows * this->_cols; }
410  T at(int i, int j) const {
411  if (i >= _rows || j >= _cols || i < 0 || j < 0) {
412  throw std::out_of_range("Index out of range");
413  }
414  auto const &it = _matrix.find(i * _cols + j);
415  return it != _matrix.end() ? it->second : _defaultReturn;
416  }
421  T at(int index) const {
422  if (index >= _rows * _cols || index < 0) {
423  throw std::out_of_range("Index out of range");
424  }
425  auto const &it = _matrix.find(index);
426  return it != _matrix.end() ? it->second : _defaultReturn;
427  }
429  void symmetrize() { *this += this->operator++(); }
430 
432  void print() const noexcept {
433  for (int i = 0; i < _rows; ++i) {
434  for (int j = 0; j < _cols; ++j) {
435  auto const &it = _matrix.find(i * _cols + j);
436  it != _matrix.end() ? std::cout << it->second : std::cout << 0;
437  std::cout << '\t';
438  }
439  std::cout << '\n';
440  }
441  }
444  void fprint(std::string const &filename) const noexcept {
445  std::ofstream file(filename);
446  file << _rows << '\t' << _cols << '\n';
447  // move buffer on file
448  auto const rdbufBackup = std::cout.rdbuf();
449  std::cout.rdbuf(file.rdbuf());
450  this->print();
451  std::cout.rdbuf(rdbufBackup);
452  file.close();
453  }
456  typename std::unordered_map<int, T>::const_iterator begin() const noexcept {
457  return _matrix.begin();
458  }
461  typename std::unordered_map<int, T>::const_iterator end() const noexcept {
462  return _matrix.end();
463  }
469  T const &operator()(int i, int j) {
470  if (i >= _rows || j >= _cols || i < 0 || j < 0) {
471  throw std::out_of_range("Index out of range");
472  }
473  auto const &it = _matrix.find(i * _cols + j);
474  return it != _matrix.end() ? it->second : _defaultReturn;
475  }
480  T const &operator()(int index) {
481  if (index >= _rows * _cols || index < 0) {
482  throw std::out_of_range("Index out of range");
483  }
484  auto const &it = _matrix.find(index);
485  return it != _matrix.end() ? it->second : _defaultReturn;
486  }
488  friend std::ostream &operator<<(std::ostream &os, const SparseMatrix &m) {
489  os << m._rows << '\t' << m._cols << '\n';
490  for (auto &it : m._matrix) {
491  os << it.first << '\t' << it.second << '\n';
492  }
493  return os;
494  }
496  friend std::istream &operator>>(std::istream &is, SparseMatrix &m) {
497  is >> m._rows >> m._cols;
498  int index;
499  T value;
500  while (is >> index >> value) {
501  m._matrix.emplace(std::make_pair(index, value));
502  }
503  return is;
504  }
509  template <typename U>
510  SparseMatrix operator+(const SparseMatrix<U> &other) const {
511  if (this->_rows != other._rows || this->_cols != other._cols) {
512  throw std::runtime_error("SparseMatrix: dimensions do not match");
513  }
514  auto result = SparseMatrix(this->_rows, this->_cols);
515  std::unordered_map<int, bool> unique;
516  for (auto &it : this->_matrix) {
517  unique.insert_or_assign(it.first, true);
518  }
519  for (auto &it : other._matrix) {
520  unique.insert_or_assign(it.first, true);
521  }
522  for (auto &it : unique) {
523  result.insert(it.first / this->_cols, it.first % this->_cols,
524  this->at(it.first) + other.at(it.first));
525  }
526  return result;
527  }
532  template <typename U>
533  SparseMatrix operator-(const SparseMatrix<U> &other) const {
534  if (this->_rows != other._rows || this->_cols != other._cols) {
535  throw std::runtime_error("SparseMatrix: dimensions do not match");
536  }
537  auto result = SparseMatrix(this->_rows, this->_cols);
538  std::unordered_map<int, bool> unique;
539  for (auto &it : this->_matrix) {
540  unique.insert_or_assign(it.first, true);
541  }
542  for (auto &it : other._matrix) {
543  unique.insert_or_assign(it.first, true);
544  }
545  for (auto &it : unique) {
546  result.insert(it.first / this->_cols, it.first % this->_cols,
547  this->at(it.first) - other.at(it.first));
548  }
549  return result;
550  }
551  // template <typename U>
552  // SparseMatrix operator*(const SparseMatrix<U> &other) const {
553  // if (this->_cols != other._rows) {
554  // throw std::runtime_error("SparseMatrix: dimensions do not match");
555  // }
556  // auto result = SparseMatrix(this->_rows, other._cols);
557  // for (int i = 0; i < this->_rows; ++i) {
558  // for (int j = 0; j < other._cols; ++j) {
559  // T sum = 0;
560  // for (int k = 0; k < this->_cols; ++k) {
561  // sum += this->at(i, k) * other.at(k, j);
562  // }
563  // if (sum != 0) {
564  // result.insert(i, j, sum);
565  // }
566  // }
567  // }
568  // return result;
569  // }
573  auto transpost = SparseMatrix(this->_cols, this->_rows);
574  for (auto &it : _matrix) {
575  transpost.insert(it.first % _cols, it.first / _cols, it.second);
576  }
577  return transpost;
578  }
583  template <typename U> SparseMatrix &operator+=(const SparseMatrix<U> &other) {
584  if (this->_rows != other._rows || this->_cols != other._cols) {
585  throw std::runtime_error("SparseMatrix: dimensions do not match");
586  }
587  for (auto &it : other._matrix) {
588  this->contains(it.first)
589  ? this->insert_or_assign(it.first,
590  this->operator()(it.first) + it.second)
591  : this->insert(it.first, it.second);
592  }
593  return *this;
594  }
599  template <typename U> SparseMatrix &operator-=(const SparseMatrix<U> &other) {
600  if (this->_rows != other._rows || this->_cols != other._cols) {
601  throw std::runtime_error("SparseMatrix: dimensions do not match");
602  }
603  for (auto &it : other._matrix) {
604  this->contains(it.first)
605  ? this->insert_or_assign(it.first,
606  this->operator()(it.first) - it.second)
607  : this->insert(it.first, -it.second);
608  }
609  return *this;
610  }
611  // template <typename U> SparseMatrix &operator*=(const SparseMatrix<U>
612  // &other) {
613  // if (this->_cols != other._rows) {
614  // throw std::runtime_error("SparseMatrix: dimensions do not match");
615  // }
616  // auto result = SparseMatrix(this->_rows, other._cols);
617  // for (int i = 0; i < this->_rows; ++i) {
618  // for (int j = 0; j < other._cols; ++j) {
619  // T sum = 0;
620  // for (int k = 0; k < this->_cols; ++k) {
621  // sum += this->at(i, k) * other.at(k, j);
622  // }
623  // if (sum != 0) {
624  // result.insert(i, j, sum);
625  // }
626  // }
627  // }
628  // *this = result;
629  // return *this;
630  // }
631 };
632 
633 #endif
SparseMatrix class v1.7.0 by Grufoony.
Definition: SparseMatrix.hpp:18
SparseMatrix< double > getNormRows() const
get a matrix of double with every row normalized to 1
Definition: SparseMatrix.hpp:361
int getRowDim() const noexcept
get the number of rows
Definition: SparseMatrix.hpp:395
T at(int i, int j) const
access an element of the matrix
Definition: SparseMatrix.hpp:410
std::unordered_map< int, T >::const_iterator begin() const noexcept
return the begin iterator of the matrix
Definition: SparseMatrix.hpp:456
SparseMatrix< int > getLaplacian()
get the laplacian matrix
Definition: SparseMatrix.hpp:263
void insert_or_assign(int i, int j, T value)
insert a value in the matrix. If the element already exist, it overwrites it
Definition: SparseMatrix.hpp:131
SparseMatrix getCol(int index) const
get a column as a column vector
Definition: SparseMatrix.hpp:299
void insert(int i, int j, T value)
insert a value in the matrix
Definition: SparseMatrix.hpp:109
void setSeed(int seed) noexcept
Set random seed.
Definition: SparseMatrix.hpp:99
bool contains(int i, int j) const
check if the element is non zero
Definition: SparseMatrix.hpp:214
std::pair< int, T > getRndRowElement(int index)
get a random non-zero element from a row
Definition: SparseMatrix.hpp:315
static void encode(std::string const &filename)
Function to read a matrix from a file and rewrite it in a listed way.
Definition: SparseMatrix.hpp:49
SparseMatrix & operator+=(const SparseMatrix< U > &other)
sum of two matrices
Definition: SparseMatrix.hpp:583
SparseMatrix(int rows, int cols)
SparseMatrix constructor.
Definition: SparseMatrix.hpp:32
friend std::istream & operator>>(std::istream &is, SparseMatrix &m)
read the matrix from a stream
Definition: SparseMatrix.hpp:496
void symmetrize()
symmetrize the matrix
Definition: SparseMatrix.hpp:429
SparseMatrix & operator-=(const SparseMatrix< U > &other)
difference of two matrices
Definition: SparseMatrix.hpp:599
SparseMatrix< double > getStrengthVector()
get the strength of all nodes
Definition: SparseMatrix.hpp:248
std::unordered_map< int, T >::const_iterator end() const noexcept
return the end iterator of the matrix
Definition: SparseMatrix.hpp:461
SparseMatrix operator++()
transpose the matrix
Definition: SparseMatrix.hpp:572
std::pair< int, T > getRndElement()
get a random non-zero element from the matrix
Definition: SparseMatrix.hpp:343
SparseMatrix(int index)
SparseMatrix constructor - colum.
Definition: SparseMatrix.hpp:41
void print() const noexcept
print the matrix in standard output
Definition: SparseMatrix.hpp:432
std::pair< int, T > getRndColElement(int index)
get a random non-zero element from a column
Definition: SparseMatrix.hpp:329
friend std::ostream & operator<<(std::ostream &os, const SparseMatrix &m)
print the matrix on a stream
Definition: SparseMatrix.hpp:488
void insert(int i, T value)
insert a value in the matrix
Definition: SparseMatrix.hpp:119
T const & operator()(int index)
access an element of the matrix
Definition: SparseMatrix.hpp:480
int max_size() const noexcept
get the maximum number of elements in the matrix
Definition: SparseMatrix.hpp:404
SparseMatrix getRow(int index) const
get a row as a row vector
Definition: SparseMatrix.hpp:283
T const & operator()(int i, int j)
access an element of the matrix
Definition: SparseMatrix.hpp:469
SparseMatrix operator-(const SparseMatrix< U > &other) const
difference of two matrices
Definition: SparseMatrix.hpp:533
void eraseRow(int index)
remove a row from the matrix
Definition: SparseMatrix.hpp:164
static void decode(std::string const &filename)
Function to read a matrix from a file and rewrite it as a full matrix.
Definition: SparseMatrix.hpp:74
void erase(int i, int j)
remove a value from the matrix
Definition: SparseMatrix.hpp:153
int getColDim() const noexcept
get the number of columns
Definition: SparseMatrix.hpp:398
void insert_or_assign(int index, T value)
insert a value in the matrix. If the element already exist, it overwrites it
Definition: SparseMatrix.hpp:142
T at(int index) const
access an element of the matrix
Definition: SparseMatrix.hpp:421
int size() const noexcept
get the number of non zero elements in the matrix
Definition: SparseMatrix.hpp:401
SparseMatrix operator+(const SparseMatrix< U > &other) const
sum of two matrices
Definition: SparseMatrix.hpp:510
bool contains(int const index) const
check if the element is non zero
Definition: SparseMatrix.hpp:224
SparseMatrix< double > getNormCols() const
get a matrix of double with every column normalized to 1
Definition: SparseMatrix.hpp:378
SparseMatrix< int > getDegreeVector()
get the input degree of all nodes
Definition: SparseMatrix.hpp:233
void eraseColumn(int index)
remove a column from the matrix
Definition: SparseMatrix.hpp:185
void fprint(std::string const &filename) const noexcept
print the matrix on a file
Definition: SparseMatrix.hpp:444