MCL
A C++ library mirroring some of the most common Matlab functions.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
matrixop.h
Go to the documentation of this file.
1 /*
2  MCL
3  Copyright (c) 2012-18, Enzo De Sena
4  All rights reserved.
5 
6  Authors: Enzo De Sena, enzodesena@gmail.com
7  */
8 
9 // This file contains definitions of matrix operations and classes
10 
11 #ifndef MCL_MATRIXOP_H
12 #define MCL_MATRIXOP_H
13 
14 #include <fstream>
15 #include <iostream>
16 #include <iomanip>
17 #include "mcltypes.h"
18 #include "comparisonop.h"
19 #include "basicop.h"
20 #include "elementaryop.h"
21 
22 #if MCL_LOAD_EIGEN
23  #include <Eigen/Dense>
24 #endif
25 
26 namespace mcl {
27 
28 // Forward declaration
29 std::vector<std::string> Split(const std::string& string,
30  char delim) noexcept;
31 
33 template<class T>
34 class Matrix {
35 public:
37  Matrix() noexcept : num_rows_(0), num_columns_(0) {}
38 
42  Matrix(Int num_rows, Int num_columns) noexcept : num_rows_(num_rows),
43  num_columns_(num_columns) {
44  for (Int i=0; i<num_rows; ++i) {
45  data_.push_back(std::vector<T>(num_columns));
46  }
47  }
48 
52  Matrix(const std::vector<std::vector<T> > vectors) noexcept {
53  num_rows_ = vectors.size();
54  if (num_rows_ > 0) {
55  num_columns_ = vectors[0].size();
56  for (Int i=1; i<num_rows_; ++i) {
57  // Check that all rows have the same number of columns
58  if ((Int)vectors[i].size() != num_columns_) {
59  ASSERT_WITH_MESSAGE(false, "One or more rows do not have the same number of columns");
60  }
61  }
62  data_ = vectors;
63  }
64  else {
65  num_columns_ = 0;
66  }
67  }
68 
70  void SetElement(const Int& index_row, const Int& index_column,
71  const T& element) noexcept {
72  ASSERT_WITH_MESSAGE(index_row < num_rows_ && index_column < num_columns_,
73  "Out-of-bounds index in setting matrix element");
74  data_[index_row][index_column] = element;
75  }
76 
78  void SetColumn(Int index_column, std::vector<T> column) noexcept {
79  ASSERT((Int)column.size() == num_rows_);
80  ASSERT(index_column < num_columns_);
81  for (Int i=0; i<num_rows_; ++i) {
82  SetElement(i, index_column, column[i]);
83  }
84  }
85 
87  void SetRow(Int index_row, std::vector<T> row) noexcept {
88  ASSERT((Int)row.size() == num_columns_);
89  ASSERT(index_row < num_rows_);
90  data_[index_row] = row;
91  }
92 
94  T GetElement(const Int& index_row, const Int& index_column) const noexcept {
95  ASSERT(index_row < num_rows_);
96  ASSERT(index_column < num_columns_);
97  return data_[index_row][index_column];
98  }
99 
101  std::vector<T> GetRow(Int index_row) const noexcept {
102  ASSERT(index_row < num_rows_);
103  return data_[index_row];
104  }
105 
107  std::vector<T> GetColumn(Int index_column) const noexcept {
108  ASSERT(index_column < num_columns_);
109  std::vector<T> output(num_rows_);
110  for (Int i=0; i<num_rows_; ++i) { output[i] = data_[i][index_column]; }
111  return output;
112  }
113 
115  std::vector<T> Serial() const noexcept {
116  std::vector<T> serial(num_columns()*num_rows());
117 
118  Int k=0;
119  for (Int j=0; j<num_columns(); ++j) {
120  for (Int i=0; i<num_rows(); ++i) {
121  serial[k++] = GetElement(i, j);
122  }
123  }
124  return serial;
125  }
126 
128  Int num_rows() const noexcept { return num_rows_; }
129 
131  Int num_columns() const noexcept { return num_columns_; }
132 
135  void Save(std::string file_name, mcl::Int precision = 5) {
136  std::ofstream output_file;
137  output_file.open(file_name.c_str());
138  output_file<<std::fixed;
139  output_file<<std::setprecision((int)precision);
140  for (Int i=0; i<num_rows_; ++i) {
141  for (Int j=0; j<num_columns_; ++j) {
142  output_file<<data_.at(i).at(j)<<" ";
143  }
144  output_file<<std::endl;
145  }
146  output_file.close();
147  }
148 
150  std::vector<std::vector<T> > data() noexcept { return data_; }
151 
156  static Matrix Load(std::string file_name) {
157  std::string line;
158  std::ifstream in_file (file_name.c_str());
159  ASSERT(in_file.is_open());
160 
161  // First: lets count the number of rows
162  Int number_of_rows = 0;
163  Int number_of_columns = 0;
164  while (std::getline(in_file, line)) {
165  std::vector<std::string> elements = Split(line, '\t');
166  if (number_of_columns == 0) { number_of_columns = (Int) elements.size(); }
167  else {
168  ASSERT(number_of_columns == (Int)elements.size());
169  }
170 
171  ++number_of_rows;
172  }
173 
174  // Reset pointer
175  in_file.clear();
176  in_file.seekg(0,std::ios::beg);
177 
178  // Create new matrix
179  // TODO: recognize complex matrix
180  Matrix<T> matrix(number_of_rows, number_of_columns);
181  for(Int row=0; row<number_of_rows; ++row) {
182  std::getline(in_file, line);
183  std::vector<std::string> elements = Split(line, '\t');
184  for (Int column=0; column<(Int)elements.size(); ++column) {
185  matrix.SetElement(row, column, (T) StringToDouble(elements[column]));
186  }
187  }
188 
189  in_file.close();
190  return matrix;
191  }
192 
196  static Matrix Ones(Int number_of_rows, Int number_of_columns) noexcept {
197  Matrix<T> matrix(number_of_rows, number_of_columns);
198  for(Int row=0; row<number_of_rows; ++row) {
199  for (Int column=0; column<number_of_columns; ++column) {
200  matrix.SetElement(row, column, (T) 1.0);
201  }
202  }
203  return matrix;
204  }
205 
209  static Matrix Ones(Int matrix_dimension) noexcept {
210  return Matrix<T>::Ones(matrix_dimension, matrix_dimension);
211  }
212 
213 private:
214  // Outer is rows, inner is columns. Hence, data_[0] is the first column.
215  std::vector<std::vector<T> > data_;
216  Int num_rows_;
217  Int num_columns_;
218 };
219 
220 template<class T>
221 void Print(const Matrix<T>& matrix) noexcept {
222  for (Int i=0; i<matrix.num_rows(); ++i) {
223  for (Int j=0; j<matrix.num_columns(); ++j) {
224  std::cout<<matrix.GetElement(i,j)<<"\t";
225  }
226  std::cout<<std::endl;
227  }
228 }
229 
231 template<class T>
232 Matrix<T> Transpose(const Matrix<T>& matrix) noexcept {
233  Matrix<T> output(matrix.num_columns(), matrix.num_rows());
234 
235  for (Int i=0; i<output.num_rows(); ++i) {
236  for (Int j=0; j<output.num_columns(); ++j) {
237  output.SetElement(i, j, matrix.GetElement(j, i));
238  }
239  }
240  return output;
241 }
242 
247 template<class T>
248 Matrix<T> Multiply(const Matrix<T>& matrix, T value) noexcept {
249  Matrix<T> output(matrix.num_rows(), matrix.num_columns());
250  for (Int i=0; i<output.num_rows(); ++i) {
251  for (Int j=0; j<output.num_columns(); ++j) {
252  output.SetElement(i, j, matrix.GetElement(i, j)*value);
253  }
254  }
255  return output;
256 }
257 
258 
260 template<class T>
261 Matrix<T> Multiply(const Matrix<T>& matrix_a,
262  const Matrix<T>& matrix_b) noexcept {
263  ASSERT(matrix_a.num_columns() == matrix_b.num_rows());
264 
265  Matrix<T> output(matrix_a.num_rows(), matrix_b.num_columns());
266  for (Int i=0; i<output.num_rows(); ++i) {
267  for (Int j=0; j<output.num_columns(); ++j) {
268  T output_value = (T) 0.0;
269  for (Int k=0; k<matrix_a.num_columns(); ++k) {
270  output_value += matrix_a.GetElement(i, k) * matrix_b.GetElement(k, j);
271  }
272  output.SetElement(i, j, output_value);
273  }
274  }
275  return output;
276 }
277 
278 template<class T>
279 std::vector<T> Multiply(const Matrix<T>& matrix_a,
280  const std::vector<T>& vector) noexcept {
281  ASSERT(matrix_a.num_columns() == (Int)vector.size());
282  Matrix<T> temp_input((Int) vector.size(), 1);
283  temp_input.SetColumn(0, vector);
284  Matrix<T> temp_output = Multiply(matrix_a, temp_input);
285  ASSERT(temp_output.num_columns() == 1);
286  ASSERT(temp_output.num_rows() == (Int)vector.size());
287 
288  return temp_output.GetColumn(0);
289 }
290 
291 
296 template<class T>
297 T Max(const Matrix<T>& matrix) noexcept {
298  return Max<T>(matrix.Serial());
299 }
300 
301 
303 struct EigOutput {
304  std::vector<Complex> eigen_values;
305  std::vector<std::vector<Complex> > eigen_vectors;
306 };
307 
308 EigOutput Eig(const Matrix<Real>& matrix) noexcept;
309 
310 Matrix<Real> RealPart(const Matrix<Complex>& input) noexcept;
311 
312 #if MCL_LOAD_EIGEN
313 Eigen::MatrixXd ConvertToEigen(const Matrix<Real>& input);
314 #endif
315 
316 template<class T>
317 bool IsEqual(const Matrix<T>& matrix_a, const Matrix<T>& matrix_b) noexcept {
318  if (matrix_a.num_rows() != matrix_b.num_rows() |
319  matrix_a.num_columns() != matrix_b.num_columns()) { return false; }
320 
321  for (Int i=0; i<matrix_a.num_rows(); ++i) {
322  for (Int j=0; j<matrix_a.num_columns(); ++j) {
323  if (!IsEqual(matrix_a.GetElement(i, j), matrix_b.GetElement(i, j))) {
324  return false;
325  }
326  }
327  }
328  return true;
329 }
330 
331 bool MatrixOpTest();
332 
333 
334 } // namespace mcl
335 
336 #endif