CoolProp  4.2.5
An open-source fluid property and humid air property database
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
MatrixMath.cpp
Go to the documentation of this file.
1 
2 #include <string>
3 #include <sstream>
4 #include <vector>
5 #include <numeric>
6 #include <math.h>
7 #include "CoolPropTools.h"
8 #include "CPExceptions.h"
9 
10 #include "MatrixMath.h"
11 
12 /*
13 Owe a debt of gratitude to http://sole.ooz.ie/en - very clear treatment of GJ
14 */
15 void swap_rows(std::vector<std::vector<double> > *A, size_t row1, size_t row2)
16 {
17  for (size_t col = 0; col < (*A)[0].size(); col++){
18  std::swap((*A)[row1][col],(*A)[row2][col]);
19  }
20 }
21 void subtract_row_multiple(std::vector<std::vector<double> > *A, size_t row, double multiple, size_t pivot_row)
22 {
23  for (size_t col = 0; col < (*A)[0].size(); col++){
24  (*A)[row][col] -= multiple*(*A)[pivot_row][col];
25  }
26 }
27 void divide_row_by(std::vector<std::vector<double> > *A, size_t row, double value)
28 {
29  for (size_t col = 0; col < (*A)[0].size(); col++){
30  (*A)[row][col] /= value;
31  }
32 }
33 
34 size_t get_pivot_row(std::vector<std::vector<double> > *A, size_t col)
35 {
36  int index = col;
37  double max = 0, val;
38 
39  for (size_t row = col; row < (*A).size(); row++)
40  {
41  val = (*A)[row][col];
42  if (fabs(val) > max)
43  {
44  max = fabs(val);
45  index = row;
46  }
47  }
48  return index;
49 }
50 
51 
52 std::vector<std::vector<double> > linsolve_Gauss_Jordan(std::vector<std::vector<double> > const& A, std::vector<std::vector<double> > const& B) {
53  std::vector<std::vector<double> > AB;
54  std::vector<std::vector<double> > X;
55  size_t pivot_row;
56  double pivot_element;
57 
58  size_t NrowA = num_rows(A);
59  size_t NrowB = num_rows(B);
60  size_t NcolA = num_cols(A);
61  size_t NcolB = num_cols(B);
62 
63  if (NrowA!=NrowB) throw ValueError(format("You have to provide matrices with the same number of rows: %d is not %d. ",NrowA,NrowB));
64 
65  AB.resize(NrowA, std::vector<double>(NcolA+NcolB, 0));
66  X.resize(NrowA, std::vector<double>(NcolB, 0));
67 
68  // Build the augmented matrix
69  for (size_t row = 0; row < NrowA; row++){
70  for (size_t col = 0; col < NcolA; col++){
71  AB[row][col] = A[row][col];
72  }
73  for (size_t col = NcolA; col < NcolA+NcolB; col++){
74  AB[row][col] = B[row][col-NcolA];
75  }
76  }
77 
78  for (size_t col = 0; col < NcolA; col++){
79  // Find the pivot value
80  pivot_row = get_pivot_row(&AB, col);
81 
82  if (fabs(AB[pivot_row][col]) < 10*DBL_EPSILON){ throw ValueError(format("Zero occurred in row %d, the matrix is singular. ",pivot_row));}
83 
84  if (pivot_row>=col){
85  // Swap pivot row and current row
86  swap_rows(&AB, col, pivot_row);
87  }
88  // Get the pivot element
89  pivot_element = AB[col][col];
90  // Divide the pivot row by the pivot element
91  divide_row_by(&AB,col,pivot_element);
92 
93  if (col < NrowA-1)
94  {
95  // All the rest of the rows, subtract the value of the [r][c] combination
96  for (size_t row = col + 1; row < NrowA; row++)
97  {
98  subtract_row_multiple(&AB,row,AB[row][col],col);
99  }
100  }
101  }
102  for (int col = NcolA - 1; col > 0; col--)
103  {
104  for (int row = col - 1; row >=0; row--)
105  {
106  subtract_row_multiple(&AB,row,AB[row][col],col);
107  }
108  }
109  // Set the output value
110  for (size_t row = 0; row < NrowA; row++){
111  for (size_t col = 0; col < NcolB; col++){
112  X[row][col] = AB[row][NcolA+col];
113  }
114  }
115  return X;
116 }
117 
118 
119 //std::vector<std::vector<double> > linsolve_Gauss_Jordan_reimpl(std::vector<std::vector<double> > const& A, std::vector<std::vector<double> > const& B) {
120 // std::vector<std::vector<double> > AB;
121 // std::vector<std::vector<double> > X;
122 // size_t pivot_row;
123 // double pivot_element;
124 // double tmp_element;
125 //
126 // size_t NrowA = num_rows(A);
127 // size_t NrowB = num_rows(B);
128 // size_t NcolA = num_cols(A);
129 // size_t NcolB = num_cols(B);
130 //
131 // if (NrowA!=NrowB) throw ValueError(format("You have to provide matrices with the same number of rows: %d is not %d. ",NrowA,NrowB));
132 //
133 // AB.resize(NrowA, std::vector<double>(NcolA+NcolB, 0));
134 // X.resize(NrowA, std::vector<double>(NcolB, 0));
135 //
136 // // Build the augmented matrix
137 // for (size_t row = 0; row < NrowA; row++){
138 // for (size_t col = 0; col < NcolA; col++){
139 // AB[row][col] = A[row][col];
140 // }
141 // for (size_t col = NcolA; col < NcolA+NcolB; col++){
142 // AB[row][col] = B[row][col-NcolA];
143 // }
144 // }
145 //
146 // for (size_t col = 0; col < NcolA; col++){
147 // // Find the pivot row
148 // pivot_row = 0;
149 // pivot_element = 0.0;
150 // for (size_t row = col; row < NrowA; row++){
151 // tmp_element = fabs(AB[row][col]);
152 // if (tmp_element>pivot_element) {
153 // pivot_element = tmp_element;
154 // pivot_row = row;
155 // }
156 // }
157 // // Check for errors
158 // if (AB[pivot_row][col]<1./_HUGE) throw ValueError(format("Zero occurred in row %d, the matrix is singular. ",pivot_row));
159 // // Swap the rows
160 // if (pivot_row>col) {
161 // for (size_t colInt = 0; colInt < NcolA; colInt++){
162 // std::swap(AB[pivot_row][colInt],AB[pivot_row][colInt]);
163 // }
164 // }
165 // // Process the entries below current element
166 // for (size_t row = col; row < NrowA; row++){
167 // // Entries to the right of current element (until end of A)
168 // for (size_t colInt = col+1; colInt < NcolA; colInt++){
169 // // All entries in augmented matrix
170 // for (size_t colFull = col; colFull < NcolA+NcolB; colFull++){
171 // AB[colInt][colFull] -= AB[col][colFull] * AB[colInt][col] / AB[col][col];
172 // }
173 // AB[colInt][col] = 0.0;
174 // }
175 // }
176 // }
177 // return AB;
178 //}
179 
180 
181 
182 
183 
184 
185 std::vector<std::vector<double> > linsolve(std::vector<std::vector<double> > const& A, std::vector<std::vector<double> > const& B){
186  return linsolve_Gauss_Jordan(A, B);
187 }
188 
189 std::vector<double> linsolve(std::vector<std::vector<double> > const& A, std::vector<double> const& b){
190  std::vector<std::vector<double> > B;
191  for (size_t i = 0; i < b.size(); i++){
192  B.push_back(std::vector<double>(1,b[i]));
193  }
194  B = linsolve(A, B);
195  B[0].resize(B.size(),0.0);
196  for (size_t i = 1; i < B.size(); i++){
197  B[0][i] = B[i][0];
198  }
199  return B[0];
200 }
201 
202 
204 std::size_t num_rows (std::vector<std::vector<double> > const& in){ return in.size(); }
205 std::size_t num_cols (std::vector<std::vector<double> > const& in){
206  if (num_rows(in)>0) {
207  if (is_squared(in)) {
208  return in[0].size();
209  } else {
210  return max_cols(in);
211  }
212  } else {
213  return 0;
214  }
215 }
216 std::size_t max_cols (std::vector<std::vector<double> > const& in){
217  std::size_t cols = 0;
218  std::size_t col = 0;
219  for (std::size_t i = 0; i < in.size(); i++) {
220  col = in[i].size();
221  if (cols<col) {cols = col;}
222  }
223  return cols;
224 }
225 std::vector<double> get_row(std::vector< std::vector<double> > const& in, size_t row) { return in[row]; }
226 std::vector<double> get_col(std::vector< std::vector<double> > const& in, size_t col) {
227  std::size_t sizeX = in.size();
228  if (sizeX<1) throw ValueError(format("You have to provide values, a vector length of %d is not valid. ",sizeX));
229  size_t sizeY = in[0].size();
230  if (sizeY<1) throw ValueError(format("You have to provide values, a vector length of %d is not valid. ",sizeY));
231  std::vector<double> out;
232  for (std::size_t i = 0; i < sizeX; i++) {
233  sizeY = in[i].size();
234  if (sizeY-1<col) throw ValueError(format("Your matrix does not have enough entries in row %d, last index %d is less than %d. ",i,sizeY-1,col));
235  out.push_back(in[i][col]);
236  }
237  return out;
238 }
239 bool is_squared(std::vector<std::vector<double> > const& in){
240  std::size_t cols = max_cols(in);
241  if (cols!=num_rows(in)) { return false;}
242  else {
243  for (std::size_t i = 0; i < in.size(); i++) {
244  if (cols!=in[i].size()) {return false; }
245  }
246  }
247  return true;
248 }
249 std::vector<std::vector<double> > make_squared(std::vector<std::vector<double> > const& in){
250  std::size_t cols = max_cols(in);
251  std::size_t rows = num_rows(in);
252  std::size_t maxVal = 0;
253  std::vector<std::vector<double> > out;
254  std::vector<double> tmp;
255 
256  if (cols>rows) {maxVal = cols; }
257  else {maxVal = rows; }
258  out.clear();
259  for (std::size_t i = 0; i < in.size(); i++) {
260  tmp.clear();
261  for (std::size_t j = 0; j < in[i].size(); j++) {
262  tmp.push_back(in[i][j]);
263  }
264  while (maxVal>tmp.size()) {
265  tmp.push_back(0.0);
266  }
267  out.push_back(tmp);
268  }
269  // Check rows
270  tmp.clear();
271  tmp.resize(maxVal,0.0);
272  while (maxVal>out.size()) {
273  out.push_back(tmp);
274  }
275  return out;
276 }
277 
278  double multiply( std::vector<double> const& a, std::vector<double> const& b){
279  return dot_product(a,b);
280 
281 }
282  std::vector<double> multiply(std::vector<std::vector<double> > const& A, std::vector<double> const& b){
283  std::vector<std::vector<double> > B;
284  for (size_t i = 0; i < b.size(); i++){
285  B.push_back(std::vector<double>(1,b[i]));
286  }
287  B = multiply(A, B);
288  B[0].resize(B.size(),0.0);
289  for (size_t i = 1; i < B.size(); i++){
290  B[0][i] = B[i][0];
291  }
292  return B[0];
293 }
294 
295 std::vector<std::vector<double> > multiply(std::vector<std::vector<double> > const& A, std::vector<std::vector<double> > const& B){
296  if (num_cols(A) != num_rows(B)){
297  throw ValueError(format("You have to provide matrices with the same columns and rows: %d is not equal to %d. ",num_cols(A),num_rows(B)));
298  }
299  size_t rows = num_rows(A);
300  size_t cols = num_cols(B);
301  double tmp;
302  std::vector<std::vector<double> > outVec;
303  std::vector<double> tmpVec;
304  outVec.clear();
305  for (size_t i = 0; i < rows; i++){
306  tmpVec.clear();
307  for (size_t j = 0; j < cols; j++){
308  tmp = 0.0;
309  for (size_t k = 0; k < num_cols(A); k++){
310  tmp += A[i][k] * B[k][j];
311  }
312  tmpVec.push_back(tmp);
313  }
314  outVec.push_back(tmpVec);
315  }
316  return outVec;
317 }
318 
319 double dot_product(std::vector<double> const& a, std::vector<double> const& b){
320  if (a.size()==b.size()){
321  return std::inner_product(a.begin(), a.end(), b.begin(), 0.0);
322  }
323  throw ValueError(format("You have to provide vectors with the same length: %d is not equal to %d. ",a.size(),b.size()));
324 }
325 
326 std::vector<double> cross_product(std::vector<double> const& a, std::vector<double> const& b){
327  throw NotImplementedError("The cross product function has not been implemented, yet");
328 }
329 
330 std::vector< std::vector<double> > transpose(std::vector<std::vector<double> > const& in){
331  size_t sizeX = in.size();
332  if (sizeX<1) throw ValueError(format("You have to provide values, a vector length of %d is not a valid. ",sizeX));
333  size_t sizeY = in[0].size();
334  size_t sizeYOld = sizeY;
335  if (sizeY<1) throw ValueError(format("You have to provide values, a vector length of %d is not a valid. ",sizeY));
336  std::vector< std::vector<double> > out(sizeY,std::vector<double>(sizeX));
337  for (size_t i = 0; i < sizeX; ++i){
338  sizeY = in[i].size();
339  if (sizeY!=sizeYOld) throw ValueError(format("You have to provide a rectangular matrix: %d is not equal to %d. ",sizeY,sizeYOld));
340  for (size_t j = 0; j < sizeY; ++j){
341  out[j][i] = in[i][j];
342  }
343  }
344  return out;
345 }
346 
347 std::vector< std::vector<double> > invert(std::vector<std::vector<double> > const& in){
348  if (!is_squared(in)) throw ValueError(format("Only square matrices can be inverted: %d is not equal to %d. ",num_rows(in),num_cols(in)));
349  std::vector<std::vector<double> > identity;
350  // Build the identity matrix
351  size_t dim = num_rows(in);
352  identity.resize(dim, std::vector<double>(dim, 0));
353  for (size_t row = 0; row < dim; row++){
354  identity[row][row] = 1.0;
355  }
356  return linsolve(in,identity);
357 }
358 
359 std::string vec_to_string( double const& a){
360  std::stringstream out;
361  out << format("[ %7.3f ]",a);
362  return out.str();
363 }
364 
365 std::string vec_to_string( std::vector<double> const& a) {
366  return vec_to_string(a,"%7.3g");
367 }
368 std::string vec_to_string( std::vector<double> const& a, const char *fmt) {
369  if (a.size()<1) {
370  return std::string("");
371  } else {
372  std::stringstream out;
373  out << format("[ ");
374  out << format(fmt,a[0]);
375  for (size_t j = 1; j < a.size(); j++) {
376  out << ", ";
377  out << format(fmt,a[j]);
378  }
379  out << " ]";
380  return out.str();
381  }
382 }
383 
384 std::string vec_to_string(std::vector<std::vector<double> > const& A) {
385  return vec_to_string(A, "%7.3g");
386 }
387 
388 std::string vec_to_string(std::vector<std::vector<double> > const& A, const char *fmt) {
389  std::stringstream out;
390  for (size_t j = 0; j < A.size(); j++) {
391  out << vec_to_string(A[j], fmt);
392  }
393  return out.str();
394 }
395 
std::vector< std::vector< double > > transpose(std::vector< std::vector< double > > const &in)
Definition: MatrixMath.cpp:330
double multiply(std::vector< double > const &a, std::vector< double > const &b)
Define some basic math operations for vectors.
Definition: MatrixMath.cpp:278
std::size_t num_cols(std::vector< std::vector< double > > const &in)
Definition: MatrixMath.cpp:205
double dot_product(std::vector< double > const &a, std::vector< double > const &b)
Definition: MatrixMath.cpp:319
size_t get_pivot_row(std::vector< std::vector< double > > *A, size_t col)
Definition: MatrixMath.cpp:34
std::vector< std::vector< double > > linsolve_Gauss_Jordan(std::vector< std::vector< double > > const &A, std::vector< std::vector< double > > const &B)
Definition: MatrixMath.cpp:52
std::vector< std::vector< double > > make_squared(std::vector< std::vector< double > > const &in)
Definition: MatrixMath.cpp:249
std::size_t num_rows(std::vector< std::vector< double > > const &in)
Some shortcuts and regularly needed operations.
Definition: MatrixMath.cpp:204
std::vector< double > cross_product(std::vector< double > const &a, std::vector< double > const &b)
Definition: MatrixMath.cpp:326
#define DBL_EPSILON
Definition: Helmholtz.cpp:10
std::string format(const char *fmt,...)
void subtract_row_multiple(std::vector< std::vector< double > > *A, size_t row, double multiple, size_t pivot_row)
Definition: MatrixMath.cpp:21
std::vector< std::vector< double > > linsolve(std::vector< std::vector< double > > const &A, std::vector< std::vector< double > > const &B)
Definition: MatrixMath.cpp:185
bool is_squared(std::vector< std::vector< double > > const &in)
Definition: MatrixMath.cpp:239
std::string vec_to_string(double const &a)
Definition: MatrixMath.cpp:359
void divide_row_by(std::vector< std::vector< double > > *A, size_t row, double value)
Definition: MatrixMath.cpp:27
void swap_rows(std::vector< std::vector< double > > *A, size_t row1, size_t row2)
Definition: MatrixMath.cpp:15
std::vector< double > get_col(std::vector< std::vector< double > > const &in, size_t col)
Definition: MatrixMath.cpp:226
std::vector< std::vector< double > > invert(std::vector< std::vector< double > > const &in)
Definition: MatrixMath.cpp:347
std::vector< double > get_row(std::vector< std::vector< double > > const &in, size_t row)
Definition: MatrixMath.cpp:225
std::size_t max_cols(std::vector< std::vector< double > > const &in)
Definition: MatrixMath.cpp:216