Program Listing for File Matrix.h¶
↰ Return to documentation for file (necsim/Matrix.h
)
//This file is part of necsim project which is released under MIT license.
//See file **LICENSE.txt** or visit https://opensource.org/licenses/MIT) for full license details.
#ifndef MATRIX
#define MATRIX
#define null 0
#include <cstdio>
#include <iostream>
#include <sstream>
#include <fstream>
#include <cstdlib>
#include <cstring>
#include <stdexcept>
#include <vector>
#ifdef use_csv
#include<cmath>
#include <stdexcept>
#include "fast-cpp-csv-parser/csv.h"
#endif
#include <cstdint>
#include "Logging.h"
using namespace std;
namespace necsim
{
// Array of data sizes for importing tif files.
const int gdal_data_sizes[] = {0, 8, 16, 16, 32, 32, 32, 64};
template<class T>
class Matrix
{
protected:
// number of rows and columns
unsigned long num_cols{};
unsigned long num_rows{};
// a matrix is an array of rows
vector<T> matrix;
public:
explicit Matrix(unsigned long rows = 0, unsigned long cols = 0) : matrix(rows * cols, T())
{
}
Matrix(const Matrix &m) : matrix()
{
this = m;
}
virtual ~Matrix()
{
}
void setSize(unsigned long rows, unsigned long cols)
{
if(!matrix.empty())
{
matrix.clear();
}
matrix.resize(rows * cols);
num_cols = cols;
num_rows = rows;
}
unsigned long getCols() const
{
return num_cols;
}
unsigned long getRows() const
{
return num_rows;
}
void fill(T val)
{
std::fill(matrix.begin(), matrix.end(), val);
}
unsigned long index(const unsigned long &row, const unsigned long &col) const
{
#ifdef DEBUG
if(num_cols == 0 || num_rows == 0)
{
throw out_of_range("Matrix has 0 rows and columns for indexing from.");
}
if(col + num_cols * row > matrix.size())
{
stringstream ss;
ss << "Index of " << col + num_cols * row << ", (" << row << ", " << col << ")";
ss << " is out of range of matrix vector with size " << matrix.size() << endl;
throw out_of_range(ss.str());
}
#endif // DEBUG
return col + num_cols * row;
}
T &get(const unsigned long &row, const unsigned long &col)
{
#ifdef DEBUG
if(row < 0 || row >= num_rows || col < 0 || col >= num_cols)
{
stringstream ss;
ss << "Index of " << row << ", " << col << " is out of range of matrix with size " << num_rows;
ss << ", " << num_cols << endl;
throw out_of_range(ss.str());
}
#endif
return matrix[index(row, col)];
}
const T &get(const unsigned long &row, const unsigned long &col) const
{
#ifdef DEBUG
if(row < 0 || row >= num_rows || col < 0 || col >= num_cols)
{
stringstream ss;
ss << "Index of " << row << ", " << col << " is out of range of matrix with size " << num_rows;
ss << ", " << num_cols << endl;
throw out_of_range(ss.str());
}
#endif
return matrix[index(row, col)];
}
T getCopy(const unsigned long &row, const unsigned long &col) const
{
#ifdef DEBUG
if(row < 0 || row >= num_rows || col < 0 || col >= num_cols)
{
stringstream ss;
ss << "Index of " << row << ", " << col << " is out of range of matrix with size " << num_rows;
ss << ", " << num_cols << endl;
throw out_of_range(ss.str());
}
#endif
return matrix[index(row, col)];
}
typename vector<T>::iterator begin()
{
return matrix.begin();
}
typename vector<T>::iterator end()
{
return matrix.end();
}
typename vector<T>::const_iterator begin() const
{
return matrix.begin();
}
typename vector<T>::const_iterator end() const
{
return matrix.end();
}
double getMean() const
{
if(matrix.empty())
{
return 0.0;
}
T total = sum();
return double(total)/matrix.size();
}
T sum() const
{
if(matrix.empty())
{
return T();
}
else
{
T total = 0;
for(const auto &item : matrix)
{
total += item;
}
return total;
}
}
Matrix &operator=(const Matrix &m)
{
this->matrix = m.matrix;
this->num_cols = m.num_cols;
this->num_rows = m.num_rows;
return *this;
}
Matrix operator+(const Matrix &m) const
{
//Since addition creates a new matrix, we don't want to return a reference, but an actual matrix object.
unsigned long new_num_cols = findMinCols(this, m);
unsigned long new_num_rows = findMinRows(this, m);
Matrix result(new_num_rows, new_num_cols);
for(unsigned long r = 0; r < new_num_rows; r++)
{
for(unsigned long c = 0; c < new_num_cols; c++)
{
result.get(r, c) = get(r, c) + m.get(r, c);
}
}
return result;
}
Matrix operator-(const Matrix &m) const
{
unsigned long new_num_cols = findMinCols(this, m);
unsigned long new_num_rows = findMinRows(this, m);
Matrix result(new_num_rows, new_num_cols);
for(unsigned long r = 0; r < new_num_rows; r++)
{
for(unsigned long c = 0; c < new_num_cols; c++)
{
result.get(r, c) = get(r, c) - m.get(r, c);
}
}
return result;
}
Matrix &operator+=(const Matrix &m)
{
unsigned long new_num_cols = findMinCols(this, m);
unsigned long new_num_rows = findMinRows(this, m);
for(unsigned long r = 0; r < new_num_rows; r++)
{
for(unsigned long c = 0; c < new_num_cols; c++)
{
get(r, c) += m.get(r, c);
}
}
return *this;
}
Matrix &operator-=(const Matrix &m)
{
unsigned long new_num_cols = findMinCols(this, m);
unsigned long new_num_rows = findMinRows(this, m);
for(unsigned long r = 0; r < new_num_rows; r++)
{
for(unsigned long c = 0; c < new_num_cols; c++)
{
matrix.get(r, c) -= m.get(r, c);
}
}
return *this;
}
Matrix operator*(const double s) const
{
Matrix result(num_rows, num_cols);
for(unsigned long r = 0; r < num_rows; r++)
{
for(unsigned long c = 0; c < num_cols; c++)
{
result.get(r, c) = get(r, c) * s;
}
}
return result;
}
Matrix operator*(Matrix &m) const
{
unsigned long new_num_cols = findMinCols(this, m);
unsigned long new_num_rows = findMinRows(this, m);
Matrix result(num_rows, m.num_cols);
for(unsigned long r = 0; r < new_num_rows; r++)
{
for(unsigned long c = 0; c < new_num_cols; c++)
{
result.get(r, c) = get(r, c) * m.get(r, c);
}
}
return result;
}
Matrix &operator*=(const double s)
{
for(unsigned long r = 0; r < num_rows; r++)
{
for(unsigned long c = 0; c < num_cols; c++)
{
get(r, c) *= s;
}
}
return *this;
}
Matrix &operator*=(const Matrix &m)
{
unsigned long new_num_cols = findMinCols(this, m);
unsigned long new_num_rows = findMinRows(this, m);
for(unsigned long r = 0; r < new_num_rows; r++)
{
for(unsigned long c = 0; c < new_num_cols; c++)
{
get(r, c) *= m.get(r, c);
}
}
return *this;
}
Matrix operator/(const double s) const
{
Matrix result(num_rows, num_cols);
for(unsigned long r = 0; r < num_rows; r++)
{
for(unsigned long c = 0; c < num_cols; c++)
{
result.get(r, c) = get(r, c) / s;
}
}
return result;
}
Matrix &operator/=(const double s)
{
for(unsigned long r = 0; r < num_rows; r++)
{
for(unsigned long c = 0; c < num_cols; c++)
{
get(r, c) /= s;
}
}
return *this;
}
Matrix &operator/=(const Matrix &m)
{
unsigned long new_num_cols = findMinCols(this, m);
unsigned long new_num_rows = findMinRows(this, m);
for(unsigned long r = 0; r < new_num_rows; r++)
{
for(unsigned long c = 0; c < new_num_cols; c++)
{
get(r, c) /= m.get(r, c);
}
}
return *this;
}
friend ostream &writeOut(ostream &os, const Matrix &m)
{
for(unsigned long r = 0; r < m.num_rows; r++)
{
for(unsigned long c = 0; c < m.num_cols; c++)
{
os << m.getCopy(r, c) << ",";
}
os << "\n";
}
return os;
}
friend istream &readIn(istream &is, Matrix &m)
{
char delim;
for(unsigned long r = 0; r < m.num_rows; r++)
{
for(unsigned long c = 0; c < m.num_cols; c++)
{
is >> m.get(r, c);
is >> delim;
}
}
return is;
}
friend ostream &operator<<(ostream &os, const Matrix &m)
{
return writeOut(os, m);
}
friend istream &operator>>(istream &is, Matrix &m)
{
return readIn(is, m);
}
void setValue(const unsigned long &row, const unsigned long &col, const char* value)
{
matrix[index(row, col)] = static_cast<T>(*value);
}
void setValue(const unsigned long &row, const unsigned long &col, const T &value)
{
matrix[index(row, col)] = value;
}
virtual void import(const string &filename)
{
if(!importCsv(filename))
{
string s = "Type detection failed for " + filename + ". Check file_name is correct.";
throw runtime_error(s);
}
}
#ifdef use_csv
bool importCsv(const string &file_name)
{
if(file_name.find(".csv") != string::npos)
{
stringstream os;
os << "Importing " << file_name << " " << flush;
writeInfo(os.str());
// LineReader option
io::LineReader in(file_name);
// Keep track of whether we've printed to terminal or not.
bool bPrint = false;
// Initialies empty variable so that the setValue operator overloading works properly.
unsigned int number_printed = 0;
for(unsigned long i =0; i<num_rows; i++)
{
char* line = in.next_line();
if(line == nullptr)
{
if(!bPrint)
{
writeError("Input dimensions incorrect - read past end of file.");
bPrint = true;
}
break;
}
else
{
char *dToken;
dToken = strtok(line,",");
for(unsigned long j = 0; j<num_cols; j++)
{
if(dToken == nullptr)
{
if(!bPrint)
{
writeError("Input dimensions incorrect - read past end of file.");
bPrint = true;
}
break;
}
else
{
// This function is overloaded to correctly determine the type of the template
setValue(i,j,dToken);
dToken = strtok(NULL,",");
}
}
// output the percentage complete
double dComplete = ((double)i/(double)num_rows)*20;
if( number_printed < dComplete)
{
stringstream os;
os << "\rImporting " << file_name << " ";
number_printed = 0;
while(number_printed < dComplete)
{
os << ".";
number_printed ++;
}
os << flush;
writeInfo(os.str());
}
}
}
writeInfo("done.\n");
return true;
}
return false;
}
#endif
#ifndef use_csv
bool importCsv(const string &filename)
{
if(filename.find(".csv") != string::npos)
{
stringstream os;
os << "Importing" << filename << " " << flush;
ifstream inputstream;
inputstream.open(filename.c_str());
unsigned long number_printed = 0;
for(uint32_t j = 0; j < num_rows; j++)
{
string line;
getline(inputstream, line);
istringstream iss(line);
for(uint32_t i = 0; i < num_cols; i++)
{
char delim;
T val;
iss >> val >> delim;
this->setValue(j, i, val);
}
double dComplete = ((double) j / (double) num_rows) * 5;
if(number_printed < dComplete)
{
os << "\rImporting " << filename << " " << flush;
while(number_printed < dComplete)
{
os << ".";
number_printed++;
}
os << flush;
writeInfo(os.str());
}
}
stringstream os2;
os2 << "\rImporting" << filename << "..." << "done." << " " << endl;
inputstream.close();
writeInfo(os2.str());
return true;
}
return false;
}
#endif // use_csv
};
template<typename T> const unsigned long findMinCols(const Matrix<T> &matrix1, const Matrix<T> &matrix2)
{
if(matrix1.getCols() < matrix2.getCols())
{
return matrix1.getCols();
}
return matrix2.getCols();
}
template<typename T> const unsigned long findMinRows(const Matrix<T> &matrix1, const Matrix<T> &matrix2)
{
if(matrix1.getRows() < matrix2.getRows())
{
return matrix1.getRows();
}
return matrix2.getRows();
}
}
#endif // MATRIX