roadrunner  2.6.0
Fast simulator for SBML models
Matrix.h
1 //
2 // Created by Ciaran on 08/07/2021.
3 //
4 
5 #ifndef ROADRUNNER_MATRIX_H
6 #define ROADRUNNER_MATRIX_H
7 
8 #include "rr-libstruct/lsMatrix.h"
9 #include <algorithm>
10 
11 namespace rr {
12 
17  template<typename T>
18  class Matrix : public ls::Matrix<T> {
19  public:
20  using ls::Matrix<T>::Matrix;
21  using ls::Matrix<T>::numCols;
22  using ls::Matrix<T>::numRows;
23  using ls::Matrix<T>::operator();
24  using ls::Matrix<T>::operator[];
25  using ls::Matrix<T>::resize;
26  using ls::Matrix<T>::getArray;
27  using ls::Matrix<T>::getValues;
28  using ls::Matrix<T>::setColNames;
29  using ls::Matrix<T>::setRowNames;
30  using ls::Matrix<T>::rowNames;
31  using ls::Matrix<T>::colNames;
32  using ls::Matrix<T>::swapCols;
33  using ls::Matrix<T>::swapRows;
34 
39  explicit Matrix<T>(ls::Matrix<T> &matrix);
40 
45  explicit Matrix<T>(ls::Matrix<T> *matrix);
46 
52  bool operator==(Matrix<T> &other);
53 
57  bool operator!=(Matrix<T> &other);
58 
63  bool almostEquals(Matrix<double> &other, const double &tolerance);
64 
68  Matrix<T> mult(Matrix<T> matrix);
69 
74  bool empty();
75 
80  void sortRowsByLabels();
81 
86  void sortColsByLabels();
87 
97  void deleteRow(int which);
98 
108  void deleteRow(const std::string& which);
109 
119  void deleteCol(int which);
120 
130  void deleteCol(const std::string& which);
131  };
132 
137  template<typename T>
138  Matrix<T>::Matrix(ls::Matrix<T> &matrix) {
139  resize(matrix.numRows(), matrix.numCols());
140  for (int i = 0; i < numRows(); i++) {
141  for (int j = 0; j < numCols(); j++) {
142  operator()(i, j) = matrix(i, j);
143  }
144  }
145  // row and col names are references, so we make a copy
146  colNames = std::vector<std::string>(matrix.getColNames().begin(), matrix.getColNames().end());
147  rowNames = std::vector<std::string>(matrix.getRowNames().begin(), matrix.getRowNames().end());
148  }
149 
150  template<typename T>
151  Matrix<T>::Matrix(ls::Matrix<T> *matrix)
152  : Matrix<T>(*matrix) {}
153 
159  template<typename T>
161  // if both are empty, result is true
162  if (empty() && other.empty()) {
163  return true;
164  }
165  if (numRows() != other.numRows()) {
166  return false;
167  }
168  if (numCols() != other.numCols()) {
169  return false;
170  }
171 
172  bool equals = true;
173  for (int i = 0; i < numRows(); i++) {
174  for (int j = 0; j < numCols(); j++) {
175  if (this->operator()(i, j) != other(i, j)) {
176  equals = false;
177  break;
178  }
179  }
180  }
181  return equals;
182  }
183 
187  template<typename T>
189  return !(*this == other);
190  }
191 
197  template<typename T>
198  bool Matrix<T>::almostEquals(Matrix<double> &other, const double &tolerance) {
199  // when both matrices are empty, they are equal
200  if (empty() && other.empty()) {
201  return true;
202  }
203  if (numRows() != other.numRows()) {
204  return false;
205  }
206  if (numCols() != other.numCols()) {
207  return false;
208  }
209  bool equals = true;
210  for (int i = 0; i < numRows(); i++) {
211  for (int j = 0; j < numCols(); j++) {
212  if ((this->operator()(i, j) - other(i, j)) > tolerance) {
213  equals = false;
214  break;
215  }
216  }
217  }
218  return equals;
219  }
220 
221  template<typename T>
223  ls::Matrix<T> mat = ls::mult(*this, matrix);
224  return Matrix<T>(mat);
225  }
226 
231  template<typename T>
233  if (getArray() == nullptr)
234  return true;
235  return false;
236  }
237 
242  template<typename T>
244  if (rowNames.empty()) {
245  // don't sort unlabelled matrices
246  return;
247  }
248 
249  // dont sort 0 and 1 length row labels
250  if (numRows() < 2) {
251  return;
252  }
253 
254  std::vector<std::string> rowLabels = rowNames; // make copy
255 
256  // now a cheeky bubble sort algorithm
257  // poor performance, but easy to implement
258  bool swapped = false;
259  for (int i = 0; i < rowLabels.size() - 1; i++) {
260  for (int j = 0; j < rowLabels.size() - 1; j++) {
261  if (rowLabels[j] > rowLabels[j + 1]) {
262  swapRows(j, j + 1);
263  std::swap(rowLabels[j], rowLabels[j + 1]);
264  swapped = true;
265  }
266  }
267  // little optimization
268  if (!swapped) {
269  break;
270  }
271  }
272  setRowNames(rowLabels);
273  }
274 
279  template<typename T>
281  if (colNames.empty()) {
282  // don't sort unlabelled matrices
283  return;
284  }
285 
286  // dont sort 0 and 1 length col labels
287  if (numCols() < 2) {
288  return;
289  }
290 
291  std::vector<std::string> colLabels = colNames; // make copy
292 
293  // now a cheeky bubble sort algorithm
294  // poor performance, but easy to implement
295  bool swapped = false;
296  for (int i = 0; i < colLabels.size() - 1; i++) {
297  for (int j = 0; j < colLabels.size() - 1; j++) {
298  if (colLabels[j] > colLabels[j + 1]) {
299  swapCols(j, j + 1);
300  std::swap(colLabels[j], colLabels[j + 1]);
301  swapped = true;
302  }
303  }
304  // little optimization
305  if (!swapped) {
306  break;
307  }
308  }
309  setColNames(colLabels);
310  }
311 
312 
313  template<typename T>
314  void Matrix<T>::deleteRow(int which) {
315  if (which > numRows() - 1) {
316  throw std::invalid_argument("Cannot delete row " + std::to_string(which));
317  }
318  // get the underlying array
319  auto *arr = getArray();
320  // store original size for later
321  int originalSize = this->_Rows * this->_Cols;
322 
323  // reduce the number of rows
324  this->_Rows--;
325  rowNames.erase(rowNames.begin() + which);
326 
327  if (which == this->_Rows) {
336  return;
337  }
338 
339  // figure out which elements
340  // in the underlying array to remove
341  int firstIdx = which * this->_Cols;
342  int secondIdx = which * this->_Cols + this->_Cols;
343  while (secondIdx != originalSize) {
344  // shift all items right of removed elements
345  // to the left. We don't actually delete or
346  // deallocate, but hide
347  std::swap(arr[firstIdx], arr[secondIdx]);
348  secondIdx++;
349  firstIdx++;
350  }
351  }
352 
353  template<typename T>
354  void Matrix<T>::deleteRow(const std::string& which){
355  auto it = std::find(rowNames.begin(), rowNames.end(), which);
356  if (it != rowNames.end()){
357  // item has been found. Find its index
358  int idx = std::distance(rowNames.begin(), it);
359  deleteRow(idx);
360  }
361  }
362 
363  template<typename T>
364  void Matrix<T>::deleteCol(int which) {
365  if (which > numCols() - 1) {
366  throw std::invalid_argument("Cannot delete col " + std::to_string(which));
367  }
368  // get the underlying array
369  auto *arr = getArray();
370  // store original size for later
371  int originalSize = this->_Rows * this->_Cols;
372 
373  // start at the last index that we need to move
374  // logic of this computation:
375  // start on the last row at "(numRows - 1) * numCols"
376  // then add the idx of column we want (which).
377  int idx = which + ((this->_Rows - 1) * this->_Cols);
378 
379  while (idx >= which) {
380  // if we are deleting the last column, then the item at
381  // the last index (Row*Col) should not be swapped.
382  // In this case, we just leave the item inplace. Reducing
383  // number of columns hides the extra data from the user.
384  if (idx == originalSize - 1) {
385  // aaand remember to increment the idx
386  idx -= this->_Rows + (this->_Cols - this->_Rows);
387  continue;
388  }
389 
390  for (int i = idx; i < originalSize - 1; i++) {
391  std::swap(arr[i], arr[i + 1]);
392  }
393 
394  // when num cols > num rows
395  idx -= this->_Rows + (this->_Cols - this->_Rows);
396  }
397 
398  // reduce the number of columns
399  this->_Cols--;
400  colNames.erase(colNames.begin() + which);
401  }
402 
403 
404  template<typename T>
405  void Matrix<T>::deleteCol(const std::string& which){
406  auto it = std::find(colNames.begin(), colNames.end(), which);
407  if (it != colNames.end()){
408  // item has been found. Find its index
409  int idx = std::distance(colNames.begin(), it);
410  deleteCol(idx);
411  }
412  }
413 
414 } // namespace rr
415 
416 
417 #endif //ROADRUNNER_MATRIX_H
A basic local matrix class, based on the libstruct version.
Definition: Matrix.h:18
void deleteCol(int which)
delete col
Definition: Matrix.h:364
bool operator==(Matrix< T > &other)
Element-wise equality operator to compare a Matrix<T> with another Matrix<T>
Definition: Matrix.h:160
bool empty()
indicator method for empty Matrix.
Definition: Matrix.h:232
bool operator!=(Matrix< T > &other)
inequality operators
Definition: Matrix.h:188
Matrix(ls::Matrix< T > &matrix)
Constructor for creating a Matrix<T> from a ls::Matrix<T>
Definition: Matrix.h:138
bool almostEquals(Matrix< double > &other, const double &tolerance)
Element-wise comparison between this Matrix<double> with another.
Definition: Matrix.h:198
void deleteRow(int which)
delete row
Definition: Matrix.h:314
void sortRowsByLabels()
Reorder Matrix rows such that row names are in alphabetical order.
Definition: Matrix.h:243
Matrix< T > mult(Matrix< T > matrix)
matrix multiplication operator
Definition: Matrix.h:222
void sortColsByLabels()
Reorder Matrix cols such that col names are in alphabetical order.
Definition: Matrix.h:280