#ifndef MATRIXMATH_H #define MATRIXMATH_H #include "CoolPropTools.h" #include "Exceptions.h" #include #include #include // inner_product #include #include "float.h" #include "Eigen/Core" /// A wrapper around std::vector /** This wrapper makes the standard vector multi-dimensional. * A useful thing even though we might not need it that * much. However, it makes the code look better and the * polynomial class really is a mess... * Source: http://stackoverflow.com/questions/13105514/n-dimensional-vector */ template struct VectorNd { typedef std::vector< typename VectorNd::type > type; }; template struct VectorNd<0,T> { typedef T type; }; namespace CoolProp{ /// Some shortcuts and regularly needed operations template std::size_t num_rows ( std::vector const& in){ return in.size(); } template std::size_t num_rows (std::vector > const& in){ return in.size(); } template std::size_t max_cols (std::vector > const& in){ std::size_t cols = 0; std::size_t col = 0; for (std::size_t i = 0; i < in.size(); i++) { col = in[i].size(); if (cols bool is_squared(std::vector > const& in){ std::size_t cols = max_cols(in); if (cols!=num_rows(in)) { return false;} else { for (std::size_t i = 0; i < in.size(); i++) { if (cols!=in[i].size()) {return false; } } } return true; }; template std::size_t num_cols ( std::vector const& in){ return 1; } template std::size_t num_cols (std::vector > const& in){ if (num_rows(in)>0) { if (is_squared(in)) { return in[0].size(); } else { return max_cols(in); } } else { return 0; } }; /// Convert vectors and matrices /** Conversion functions for the different kinds of object-like * parameters. This might be obsolete at a later stage, but now * it is still needed. * @param coefficients matrix containing the ordered coefficients * @param axis axis along which to extract */ template std::vector eigen_to_vec1D(const Eigen::Matrix &coefficients, int axis = 0){ std::vector result; size_t r = coefficients.rows(), c = coefficients.cols(); if (axis==0) { if (c!=1) throw ValueError(format("Your matrix has the wrong dimensions: %d,%d",r,c)); result.resize(r); for (size_t i = 0; i < r; ++i) { result[i] = coefficients(i,0); } } else if (axis==1) { if (r!=1) throw ValueError(format("Your matrix has the wrong dimensions: %d,%d",r,c)); result.resize(c); for (size_t i = 0; i < c; ++i) { result[i] = coefficients(0,i); } } else { throw ValueError(format("You have to provide axis information: %d is not valid. ",axis)); } return result; } /// @param coefficients matrix containing the ordered coefficients template std::vector > eigen_to_vec(const Eigen::Matrix &coefficients){ // Eigen uses columns as major axis, this might be faster than the row iteration. // However, the 2D vector stores things differently, no idea what is faster... std::vector > result; size_t r = coefficients.rows(), c = coefficients.cols(); result.resize(r, std::vector(c, 0)); // extends vector if necessary for (size_t i = 0; i < r; ++i) { result[i].resize(c, 0); for (size_t j = 0; j < c; ++j) { result[i][j] = coefficients(i,j); } } return result; } /// @param coefficients matrix containing the ordered coefficients template Eigen::Matrix vec_to_eigen(const std::vector > &coefficients){ size_t nRows = num_rows(coefficients), nCols = num_cols(coefficients); Eigen::Matrix result(nRows,nCols); for (size_t i = 0; i < nCols; ++i) { for (size_t j = 0; j < nRows; ++j) { result(j,i) = coefficients[j][i]; } } return result; } /** * @param coefficients matrix containing the ordered coefficients * @param axis axis along which to extract data */ template Eigen::Matrix vec_to_eigen(const std::vector &coefficients, int axis = 0){ size_t nRows = num_rows(coefficients); Eigen::Matrix result; if (axis==0) result.resize(nRows,1); else if (axis==1) result.resize(1,nRows); else throw ValueError(format("You have to provide axis information: %d is not valid. ",axis)); for (size_t i = 0; i < nRows; ++i) { if (axis==0) result(i,0) = coefficients[i]; if (axis==1) result(0,i) = coefficients[i]; } return result; } /// @param coefficient template Eigen::Matrix vec_to_eigen(const T &coefficient){ Eigen::Matrix result = Eigen::Matrix(1,1); result(0,0) = coefficient; return result; } /// Convert 1D matrix to vector /** Returns either a row- or a column-based * vector. By default, Eigen prefers column * major ordering, just like Fortran. */ template< class T> Eigen::Matrix makeColVector(const Eigen::Matrix &matrix){ std::size_t r = matrix.rows(); std::size_t c = matrix.cols(); Eigen::Matrix vector; if (r==1&&c>=1) { // Check passed, matrix can be transformed vector = matrix.transpose().block(0,0,c,r); } else if ( r>=1&&c==1) { // Check passed, matrix can be transformed vector = matrix.block(0,0,r,c); } else { // Check failed, throw error throw ValueError(format("Your matrix (%d,%d) cannot be converted into a vector (x,1).",r,c)); } return vector; } template< class T> Eigen::Matrix makeVector(const Eigen::Matrix &matrix) { return makeColVector(matrix); } template< class T> Eigen::Matrix makeRowVector(const Eigen::Matrix &matrix){ std::size_t r = matrix.rows(); std::size_t c = matrix.cols(); Eigen::Matrix vector; if (r==1&&c>=1) { // Check passed, matrix can be transformed vector = matrix.block(0,0,r,c); } else if ( r>=1&&c==1) { // Check passed, matrix can be transformed vector = matrix.transpose().block(0,0,c,r); } else { // Check failed, throw error throw ValueError(format("Your matrix (%d,%d) cannot be converted into a vector (1,x).",r,c)); } return vector; } /// Remove rows and columns from matrices /** A set of convenience functions inspired by http://stackoverflow.com/questions/13290395/how-to-remove-a-certain-row-or-column-while-using-eigen-library-c * but altered to respect templates. */ template< class T> void removeRow(Eigen::Matrix &matrix, std::size_t rowToRemove){ //template void removeRow(Eigen::MatrixXd& matrix, std::size_t rowToRemove){ //void removeRow(Eigen::MatrixXd& matrix, unsigned int rowToRemove){ //template void removeRow(Eigen::MatrixBase &matrix, std::size_t rowToRemove){ std::size_t numRows = matrix.rows()-1; std::size_t numCols = matrix.cols(); if( rowToRemove < numRows ){ matrix.block(rowToRemove,0,numRows-rowToRemove,numCols) = matrix.block(rowToRemove+1,0,numRows-rowToRemove,numCols); } else { if( rowToRemove > numRows ){ throw ValueError(format("Your matrix does not have enough rows, %d is not greater or equal to %d.",numRows,rowToRemove)); } // Do nothing, resize removes the last row } matrix.conservativeResize(numRows,numCols); } template void removeColumn(Eigen::Matrix &matrix, std::size_t colToRemove){ //template void removeColumn(Eigen::MatrixXd& matrix, std::size_t colToRemove){ //void removeColumn(Eigen::MatrixXd& matrix, unsigned int colToRemove){ //template void removeColumn(Eigen::MatrixBase &matrix, std::size_t colToRemove){ std::size_t numRows = matrix.rows(); std::size_t numCols = matrix.cols()-1; if( colToRemove < numCols ) { matrix.block(0,colToRemove,numRows,numCols-colToRemove) = matrix.block(0,colToRemove+1,numRows,numCols-colToRemove); } else { if( colToRemove > numCols ) { throw ValueError(format("Your matrix does not have enough columns, %d is not greater or equal to %d.",numCols,colToRemove)); } // Do nothing, resize removes the last column } matrix.conservativeResize(numRows,numCols); } ///// @param coefficients matrix containing the ordered coefficients //template Eigen::Matrix convert(const std::vector > &coefficients){ // size_t nRows = num_rows(coefficients), nCols = num_cols(coefficients); // Eigen::MatrixBase result(nRows,nCols); // for (size_t i = 0; i < nCols; ++i) { // for (size_t j = 0; j < nRows; ++j) { // result(j,i) = coefficients[j][i]; // } // } // return result; //} // ///// @param coefficients matrix containing the ordered coefficients //template void convert(const std::vector > &coefficients, Eigen::Matrix &result){ // size_t nRows = num_rows(coefficients), nCols = num_cols(coefficients); // //Eigen::MatrixBase result(nRows,nCols); // for (size_t i = 0; i < nCols; ++i) { // for (size_t j = 0; j < nRows; ++j) { // result(j,i) = coefficients[j][i]; // } // } // //return result; //} // //template void convert(const std::vector > &coefficients, Eigen::MatrixBase &result){ // size_t nRows = num_rows(coefficients), nCols = num_cols(coefficients); // //Eigen::MatrixBase result; // //if ((R!=nRows) || (C!=nCols)) // result.resize(nRows,nCols); // for (size_t i = 0; i < nCols; ++i) { // for (size_t j = 0; j < nRows; ++j) { // result(j,i) = coefficients[j][i]; // } // } // //return result; //} //template //inline void func1(MatrixBase &out_mat ){ // // Do something then return a matrix // out_mat = ... //} //template //Eigen::Matrix //Multiply(const Eigen::MatrixBase& p1, // const Eigen::MatrixBase& p2) //{ // return (p1 * p2); //} // // //template //Eigen::Matrix //Multiply(const Eigen::MatrixBase& p1, // const Eigen::MatrixBase& p2) //{ // return (p1 * p2); //} /// Templates for printing numbers, vectors and matrices static const char* stdFmt = "%8.3f"; ///Templates for turning vectors (1D-matrices) into strings template std::string vec_to_string(const std::vector &a, const char *fmt) { if (a.size()<1) return std::string(""); std::stringstream out; out << "[ " << format(fmt,a[0]); for (size_t j = 1; j < a.size(); j++) { out << ", " << format(fmt, a[j]); } out << " ]"; return out.str(); }; template std::string vec_to_string(const std::vector &a) { return vec_to_string(std::vector(a.begin(), a.end()), stdFmt); }; ///Templates for turning vectors (1D-matrices) into strings inline std::string stringvec_to_string(const std::vector &a) { if (a.size()<1) return std::string(""); std::stringstream out; out << "[ " << format("%s", a[0].c_str()); for (size_t j = 1; j < a.size(); j++) { out << ", " << format("%s", a[j].c_str()); } out << " ]"; return out.str(); }; /// Templates for turning numbers (0D-matrices) into strings template std::string vec_to_string(const T &a, const char *fmt) { std::vector vec; vec.push_back(a); return vec_to_string(vec, fmt); }; template std::string vec_to_string(const T &a) { return vec_to_string((double) a, stdFmt); }; ///Templates for turning 2D-matrices into strings template std::string vec_to_string(const std::vector > &A, const char *fmt) { if (A.size()<1) return std::string(""); std::stringstream out; out << "[ " << vec_to_string(A[0], fmt); for (size_t j = 1; j < A.size(); j++) { out << ", " << std::endl << " " << vec_to_string(A[j], fmt); } out << " ]"; return out.str(); }; template std::string vec_to_string(const std::vector > &A) { return vec_to_string(A, stdFmt); }; ///Templates for turning Eigen matrices into strings template std::string mat_to_string(const Eigen::Matrix &A, const char *fmt) { //std::string mat_to_string(const Eigen::MatrixXd &A, const char *fmt) { std::size_t r = A.rows(); std::size_t c = A.cols(); if ((r<1)||(c<1)) return std::string(""); std::stringstream out; out << "[ "; if (r==1) { out << format(fmt, A(0,0)); for (size_t j = 1; j < c; j++) { out << ", " << format(fmt, A(0,j)); } } else { out << mat_to_string(Eigen::Matrix(A.row(0)), fmt); for (size_t i = 1; i < r; i++) { out << ", " << std::endl << " " << mat_to_string(Eigen::Matrix(A.row(i)), fmt); } } out << " ]"; return out.str(); }; template std::string mat_to_string(const Eigen::Matrix &A) { //std::string vec_to_string(const Eigen::MatrixXd &A) { return mat_to_string(A, stdFmt); }; ///// Templates for printing numbers, vectors and matrices //static const char* stdFmt = "%8.3f"; // /////Templates for turning vectors (1D-matrices) into strings //template std::string vec_to_string(const std::vector &a, const char *fmt) { // if (a.size()<1) return std::string(""); // std::stringstream out; // out << "[ " << format(fmt,a[0]); // for (size_t j = 1; j < a.size(); j++) { // out << ", " << format(fmt, a[j]); // } // out << " ]"; // return out.str(); //}; //template std::string vec_to_string(const std::vector &a) { // return vec_to_string(a, stdFmt); //}; // ///// Templates for turning numbers (0D-matrices) into strings //template std::string vec_to_string(const T &a, const char *fmt) { // std::vector vec; // vec.push_back(a); // return vec_to_string(vec, fmt); //}; //template std::string vec_to_string(const T &a) { // return vec_to_string(a, stdFmt); //}; // /////Templates for turning 2D-matrices into strings //template std::string vec_to_string(const std::vector > &A, const char *fmt) { // if (A.size()<1) return std::string(""); // std::stringstream out; // out << "[ " << vec_to_string(A[0], fmt); // for (size_t j = 1; j < A.size(); j++) { // out << ", " << std::endl << " " << vec_to_string(A[j], fmt); // } // out << " ]"; // return out.str(); //}; //template std::string vec_to_string(const std::vector > &A) { // return vec_to_string(A, stdFmt); //}; // /////Templates for turning Eigen matrices into strings //template std::string mat_to_string(const Eigen::Matrix &A, const char *fmt) { ////std::string mat_to_string(const Eigen::MatrixXd &A, const char *fmt) { // std::size_t r = A.rows(); // std::size_t c = A.cols(); // if ((r<1)||(c<1)) return std::string(""); // std::stringstream out; // out << "[ "; // if (r==1) { // out << format(fmt, A(0,0)); // for (size_t j = 1; j < c; j++) { // out << ", " << format(fmt, A(0,j)); // } // } else { // out << mat_to_string(Eigen::Matrix(A.row(0)), fmt); // for (size_t i = 1; i < r; i++) { // out << ", " << std::endl << " " << mat_to_string(Eigen::Matrix(A.row(i)), fmt); // } // } // out << " ]"; // return out.str(); //}; //template std::string mat_to_string(const Eigen::Matrix &A) { ////std::string vec_to_string(const Eigen::MatrixXd &A) { // return mat_to_string(A, stdFmt); //}; /// Template class for turning numbers (0D-matrices) into strings //template std::string vec_to_string(const T &a){ // return vec_to_string(a, stdFmt); // std::stringstream out; // out << format("[ %7.3f ]",a); // return out.str(); //}; //template std::string vec_to_string(const VectorNd<0, T> &a){ // return vec_to_string(a, stdFmt); //}; //template std::string vec_to_string(const VectorNd<0, T> &a, const char *fmt) { // VectorNd<1, T> vec; // vec.push_back(a); // return vec_to_string(vec, fmt); //}; // /////Template classes for turning vectors (1D-matrices) into strings //template std::string vec_to_string(const VectorNd<1, T> &a) { // return vec_to_string(a, stdFmt); //}; //template std::string vec_to_string(const VectorNd<1, T> &a, const char *fmt) { // if (a.size()<1) { // return std::string(""); // } else { // std::stringstream out; // out << "[ "; // out << format(fmt,a[0]); // for (size_t j = 1; j < a.size(); j++) { // out << ", "; // out << format(fmt,a[j]); // } // out << " ]"; // return out.str(); // } //}; // /////Template classes for turning 2D-matrices into strings //template std::string vec_to_string(const VectorNd<2, T> &A) { // return vec_to_string(A, stdFmt); //} //template std::string vec_to_string(const VectorNd<2, T> &A, const char *fmt) { // if (A.size()<1) return std::string(""); // std::stringstream out; // out << "[ " << format(fmt,A[0]); // for (size_t j = 1; j < A.size(); j++) { // out << ", " << std::endl << " " << vec_to_string(A[j], fmt); // } // out << " ]"; // return out.str(); //} ///// Publish the linear algebra solver //template std::vector linsolve(std::vector > const& A, std::vector const& b); //template std::vector > linsolve(std::vector > const& A, std::vector > const& B); // ///// Some shortcuts and regularly needed operations //template std::size_t num_rows (std::vector > const& in); //template std::size_t num_cols (std::vector > const& in); //template std::size_t max_cols (std::vector > const& in); //template std::vector get_row (std::vector > const& in, size_t row); //template std::vector get_col (std::vector > const& in, size_t col); //template bool is_squared(std::vector > const& in); //template std::vector > make_squared(std::vector > const& in); // ///// Define some basic math operations for vectors //template T multiply( std::vector const& A, std::vector const& B); //template std::vector multiply(std::vector > const& A, std::vector const& B); //template std::vector > multiply(std::vector > const& A, std::vector > const& B); // //template T dot_product(std::vector const& a, std::vector const& b); //template std::vector cross_product(std::vector const& a, std::vector const& b); // //template std::vector > transpose(std::vector > const& in); //template std::vector > invert(std::vector > const& in); // //template std::string vec_to_string( T const& a); //template std::string vec_to_string( std::vector const& a); //template std::string vec_to_string(std::vector > const& A); // //template std::string vec_to_string( std::vector const& a, const char *fmt); //template std::string vec_to_string(std::vector > const& A, const char *fmt); /* Owe a debt of gratitude to http://sole.ooz.ie/en - very clear treatment of GJ */ template void swap_rows(std::vector > *A, size_t row1, size_t row2) { for (size_t col = 0; col < (*A)[0].size(); col++){ std::swap((*A)[row1][col],(*A)[row2][col]); } }; template void subtract_row_multiple(std::vector > *A, size_t row, T multiple, size_t pivot_row) { for (size_t col = 0; col < (*A)[0].size(); col++){ (*A)[row][col] -= multiple*(*A)[pivot_row][col]; } }; template void divide_row_by(std::vector > *A, size_t row, T value) { for (size_t col = 0; col < (*A)[0].size(); col++){ (*A)[row][col] /= value; } }; template size_t get_pivot_row(std::vector > *A, size_t col) { std::size_t index = col; T max = 0, val; for (size_t row = col; row < (*A).size(); row++) { val = (*A)[row][col]; if (std::abs(val) > max) { max = std::abs(val); index = row; } } return index; }; template std::vector > linsolve_Gauss_Jordan(std::vector > const& A, std::vector > const& B) { std::vector > AB; std::vector > X; size_t pivot_row; T pivot_element; size_t NrowA = num_rows(A); size_t NrowB = num_rows(B); size_t NcolA = num_cols(A); size_t NcolB = num_cols(B); if (NrowA!=NrowB) throw ValueError(format("You have to provide matrices with the same number of rows: %d is not %d. ",NrowA,NrowB)); AB.resize(NrowA, std::vector(NcolA+NcolB, 0)); X.resize(NrowA, std::vector(NcolB, 0)); // Build the augmented matrix for (size_t row = 0; row < NrowA; row++){ for (size_t col = 0; col < NcolA; col++){ AB[row][col] = A[row][col]; } for (size_t col = NcolA; col < NcolA+NcolB; col++){ AB[row][col] = B[row][col-NcolA]; } } for (size_t col = 0; col < NcolA; col++){ // Find the pivot value pivot_row = get_pivot_row(&AB, col); if (std::abs(AB[pivot_row][col]) < 10*DBL_EPSILON){ throw ValueError(format("Zero occurred in row %d, the matrix is singular. ",pivot_row));} if (pivot_row>=col){ // Swap pivot row and current row swap_rows(&AB, col, pivot_row); } // Get the pivot element pivot_element = AB[col][col]; // Divide the pivot row by the pivot element divide_row_by(&AB,col,pivot_element); if (col < NrowA-1) { // All the rest of the rows, subtract the value of the [r][c] combination for (size_t row = col + 1; row < NrowA; row++) { subtract_row_multiple(&AB,row,AB[row][col],col); } } } for (std::size_t col = NcolA - 1; col > 0; col--) { for (int row = static_cast(col) - 1; row >=0; row--) { subtract_row_multiple(&AB,row,AB[row][col],col); } } // Set the output value for (size_t row = 0; row < NrowA; row++){ for (size_t col = 0; col < NcolB; col++){ X[row][col] = AB[row][NcolA+col]; } } return X; }; //std::vector > linsolve_Gauss_Jordan_reimpl(std::vector > const& A, std::vector > const& B) { // std::vector > AB; // std::vector > X; // size_t pivot_row; // double pivot_element; // double tmp_element; // // size_t NrowA = num_rows(A); // size_t NrowB = num_rows(B); // size_t NcolA = num_cols(A); // size_t NcolB = num_cols(B); // // if (NrowA!=NrowB) throw ValueError(format("You have to provide matrices with the same number of rows: %d is not %d. ",NrowA,NrowB)); // // AB.resize(NrowA, std::vector(NcolA+NcolB, 0)); // X.resize(NrowA, std::vector(NcolB, 0)); // // // Build the augmented matrix // for (size_t row = 0; row < NrowA; row++){ // for (size_t col = 0; col < NcolA; col++){ // AB[row][col] = A[row][col]; // } // for (size_t col = NcolA; col < NcolA+NcolB; col++){ // AB[row][col] = B[row][col-NcolA]; // } // } // // for (size_t col = 0; col < NcolA; col++){ // // Find the pivot row // pivot_row = 0; // pivot_element = 0.0; // for (size_t row = col; row < NrowA; row++){ // tmp_element = std::abs(AB[row][col]); // if (tmp_element>pivot_element) { // pivot_element = tmp_element; // pivot_row = row; // } // } // // Check for errors // if (AB[pivot_row][col]<1./_HUGE) throw ValueError(format("Zero occurred in row %d, the matrix is singular. ",pivot_row)); // // Swap the rows // if (pivot_row>col) { // for (size_t colInt = 0; colInt < NcolA; colInt++){ // std::swap(AB[pivot_row][colInt],AB[pivot_row][colInt]); // } // } // // Process the entries below current element // for (size_t row = col; row < NrowA; row++){ // // Entries to the right of current element (until end of A) // for (size_t colInt = col+1; colInt < NcolA; colInt++){ // // All entries in augmented matrix // for (size_t colFull = col; colFull < NcolA+NcolB; colFull++){ // AB[colInt][colFull] -= AB[col][colFull] * AB[colInt][col] / AB[col][col]; // } // AB[colInt][col] = 0.0; // } // } // } // return AB; //} template std::vector > linsolve(std::vector > const& A, std::vector > const& B){ return linsolve_Gauss_Jordan(A, B); }; template std::vector linsolve(std::vector > const& A, std::vector const& b){ std::vector > B; for (size_t i = 0; i < b.size(); i++){ B.push_back(std::vector(1,b[i])); } B = linsolve(A, B); B[0].resize(B.size(),0.0); for (size_t i = 1; i < B.size(); i++){ B[0][i] = B[i][0]; } return B[0]; }; template std::vector get_row(std::vector< std::vector > const& in, size_t row) { return in[row]; }; template std::vector get_col(std::vector< std::vector > const& in, size_t col) { std::size_t sizeX = in.size(); if (sizeX<1) throw ValueError(format("You have to provide values, a vector length of %d is not valid. ",sizeX)); size_t sizeY = in[0].size(); if (sizeY<1) throw ValueError(format("You have to provide values, a vector length of %d is not valid. ",sizeY)); std::vector out; for (std::size_t i = 0; i < sizeX; i++) { sizeY = in[i].size(); if (sizeY-1 std::vector > make_squared(std::vector > const& in){ std::size_t cols = max_cols(in); std::size_t rows = num_rows(in); std::size_t maxVal = 0; std::vector > out; std::vector tmp; if (cols>rows) {maxVal = cols; } else {maxVal = rows; } out.clear(); for (std::size_t i = 0; i < in.size(); i++) { tmp.clear(); for (std::size_t j = 0; j < in[i].size(); j++) { tmp.push_back(in[i][j]); } while (maxVal>tmp.size()) { tmp.push_back(0.0); } out.push_back(tmp); } // Check rows tmp.clear(); tmp.resize(maxVal,0.0); while (maxVal>out.size()) { out.push_back(tmp); } return out; }; template T multiply( std::vector const& a, std::vector const& b){ return dot_product(a,b); }; template std::vector multiply(std::vector > const& A, std::vector const& b){ std::vector > B; for (size_t i = 0; i < b.size(); i++){ B.push_back(std::vector(1,b[i])); } B = multiply(A, B); B[0].resize(B.size(),0.0); for (size_t i = 1; i < B.size(); i++){ B[0][i] = B[i][0]; } return B[0]; } template std::vector > multiply(std::vector > const& A, std::vector > const& B){ if (num_cols(A) != num_rows(B)){ 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))); } size_t rows = num_rows(A); size_t cols = num_cols(B); T tmp; std::vector > outVec; std::vector tmpVec; outVec.clear(); for (size_t i = 0; i < rows; i++){ tmpVec.clear(); for (size_t j = 0; j < cols; j++){ tmp = 0.0; for (size_t k = 0; k < num_cols(A); k++){ tmp += A[i][k] * B[k][j]; } tmpVec.push_back(tmp); } outVec.push_back(tmpVec); } return outVec; }; template T dot_product(std::vector const& a, std::vector const& b){ if (a.size()==b.size()){ return std::inner_product(a.begin(), a.end(), b.begin(), 0.0); } throw ValueError(format("You have to provide vectors with the same length: %d is not equal to %d. ",a.size(),b.size())); }; template std::vector cross_product(std::vector const& a, std::vector const& b){ throw NotImplementedError("The cross product function has not been implemented, yet"); }; template std::vector< std::vector > transpose(std::vector > const& in){ size_t sizeX = in.size(); if (sizeX<1) throw ValueError(format("You have to provide values, a vector length of %d is not a valid. ",sizeX)); size_t sizeY = in[0].size(); size_t sizeYOld = sizeY; if (sizeY<1) throw ValueError(format("You have to provide values, a vector length of %d is not a valid. ",sizeY)); std::vector< std::vector > out(sizeY,std::vector(sizeX)); for (size_t i = 0; i < sizeX; ++i){ sizeY = in[i].size(); if (sizeY!=sizeYOld) throw ValueError(format("You have to provide a rectangular matrix: %d is not equal to %d. ",sizeY,sizeYOld)); for (size_t j = 0; j < sizeY; ++j){ out[j][i] = in[i][j]; } } return out; }; template std::vector< std::vector > invert(std::vector > const& in){ 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))); std::vector > identity; // Build the identity matrix size_t dim = num_rows(in); identity.resize(dim, std::vector(dim, 0)); for (size_t row = 0; row < dim; row++){ identity[row][row] = 1.0; } return linsolve(in,identity); }; inline void removeRow(Eigen::MatrixXd& matrix, unsigned int rowToRemove) { unsigned int numRows = static_cast(matrix.rows())- 1; unsigned int numCols = static_cast(matrix.cols()); if (rowToRemove <= numRows) matrix.block(rowToRemove, 0, numRows-rowToRemove, numCols) = matrix.block(rowToRemove+1, 0, numRows-rowToRemove, numCols); else{ throw ValueError(format("Trying to remove row index [%d] greater than max index [%d] ", rowToRemove, numRows)); } matrix.conservativeResize(numRows, numCols); }; inline void removeColumn(Eigen::MatrixXd& matrix, unsigned int colToRemove) { unsigned int numRows = static_cast(matrix.rows()); unsigned int numCols = static_cast(matrix.cols())-1; if (colToRemove <= numCols) matrix.block(0, colToRemove, numRows, numCols-colToRemove) = matrix.block(0, colToRemove+1, numRows, numCols-colToRemove); else{ throw ValueError(format("Trying to remove column index [%d] greater than max index [%d] ", colToRemove, numCols)); } matrix.conservativeResize(numRows, numCols); }; template inline Eigen::MatrixXd minor_matrix(const Eigen::MatrixBase& A, std::size_t i, std::size_t j) { Eigen::MatrixXd Am = A; removeRow(Am, static_cast(i)); removeColumn(Am, static_cast(j)); return Am; }; template static Eigen::MatrixXd adjugate(const Eigen::MatrixBase& A) { std::size_t N = A.rows(); if (N==1){ Eigen::MatrixXd Aadj(1,1); Aadj << 1; return Aadj; } Eigen::MatrixXd Aadj(N, N); for (std::size_t i = 0; i < N; ++i){ for (std::size_t j = 0; j < N; ++j){ int negative_1_to_the_i_plus_j = ((i+j)%2==0) ? 1 : -1; Aadj(i, j) = negative_1_to_the_i_plus_j*minor_matrix(A, j, i).determinant(); } } return Aadj; } template static Eigen::MatrixXd adjugate_derivative(const Eigen::MatrixBase &A, const Eigen::MatrixBase& dAdt) { std::size_t N = A.rows(); Eigen::MatrixXd Aadj(N, N); for (std::size_t i = 0; i < N; ++i){ for (std::size_t j = 0; j < N; ++j){ int negative_1_to_the_i_plus_j = ((i+j)%2==0) ? 1 : -1; Eigen::MatrixXd mm = minor_matrix(A, j, i); Aadj(i, j) = negative_1_to_the_i_plus_j*(adjugate(minor_matrix(A, j, i))*minor_matrix(dAdt,j,i)).trace(); } } return Aadj; } }; /* namespace CoolProp */ #endif