Program Listing for File mtx_reader.cc
↰ Return to documentation for file (src/sparsebase/io/mtx_reader.cc
)
#include "sparsebase/io/mtx_reader.h"
#include <sstream>
#include <string>
#include "sparsebase/config.h"
namespace sparsebase::io {
template <typename IDType, typename NNZType, typename ValueType>
MTXReader<IDType, NNZType, ValueType>::MTXReader(std::string filename,
bool convert_to_zero_index)
: filename_(filename), convert_to_zero_index_(convert_to_zero_index) {
std::ifstream fin(filename_);
if (fin.is_open()) {
std::string header_line;
std::getline(fin, header_line);
// parse first line
options_ = ParseHeader(header_line);
} else {
throw utils::ReaderException("Wrong matrix market file name\n");
}
}
template <typename IDType, typename NNZType, typename ValueType>
typename MTXReader<IDType, NNZType, ValueType>::MTXOptions
MTXReader<IDType, NNZType, ValueType>::ParseHeader(
std::string header_line) const {
std::stringstream line_ss(header_line);
MTXOptions options;
std::string prefix, object, format, field, symmetry;
line_ss >> prefix >> object >> format >> field >> symmetry;
if (prefix != MMX_PREFIX)
throw utils::ReaderException("Wrong prefix in a matrix market file");
// parsing Object option
if (object == "matrix") {
options.object =
MTXReader<IDType, NNZType, ValueType>::MTXObjectOptions::matrix;
} else if (object == "vector") {
options.object =
MTXReader<IDType, NNZType, ValueType>::MTXObjectOptions::matrix;
throw utils::ReaderException(
"Matrix market reader does not currently support reading vectors.");
} else {
throw utils::ReaderException(
"Illegal value for the 'object' option in matrix market header");
}
// parsing format option
if (format == "array") {
options.format =
MTXReader<IDType, NNZType, ValueType>::MTXFormatOptions::array;
} else if (format == "coordinate") {
options.format =
MTXReader<IDType, NNZType, ValueType>::MTXFormatOptions::coordinate;
} else {
throw utils::ReaderException(
"Illegal value for the 'format' option in matrix market header");
}
// parsing field option
if (field == "real") {
options.field =
MTXReader<IDType, NNZType, ValueType>::MTXFieldOptions::real;
if constexpr (std::is_same<void, ValueType>::value)
throw utils::ReaderException(
"You are reading the values of the matrix market file into a void "
"array");
} else if (field == "double") {
options.field =
MTXReader<IDType, NNZType, ValueType>::MTXFieldOptions::double_field;
if constexpr (std::is_same<void, ValueType>::value)
throw utils::ReaderException(
"You are reading the values of the matrix market file into a void "
"array");
} else if (field == "complex") {
options.field =
MTXReader<IDType, NNZType, ValueType>::MTXFieldOptions::complex;
if constexpr (std::is_same<void, ValueType>::value)
throw utils::ReaderException(
"You are reading the values of the matrix market file into a void "
"array");
} else if (field == "integer") {
options.field =
MTXReader<IDType, NNZType, ValueType>::MTXFieldOptions::integer;
if constexpr (std::is_same<void, ValueType>::value)
throw utils::ReaderException(
"You are reading the values of the matrix market file into a void "
"array");
} else if (field == "pattern") {
options.field =
MTXReader<IDType, NNZType, ValueType>::MTXFieldOptions::pattern;
} else {
throw utils::ReaderException(
"Illegal value for the 'field' option in matrix market header");
}
// parsing symmetry
if (symmetry == "general") {
options.symmetry =
MTXReader<IDType, NNZType, ValueType>::MTXSymmetryOptions::general;
} else if (symmetry == "symmetric") {
options.symmetry =
MTXReader<IDType, NNZType, ValueType>::MTXSymmetryOptions::symmetric;
} else if (symmetry == "skew-symmetric") {
options.symmetry = MTXReader<IDType, NNZType,
ValueType>::MTXSymmetryOptions::skew_symmetric;
} else if (symmetry == "hermitian") {
options.symmetry =
MTXReader<IDType, NNZType, ValueType>::MTXSymmetryOptions::hermitian;
throw utils::ReaderException(
"Matrix market reader does not currently support hermitian symmetry.");
} else {
throw utils::ReaderException(
"Illegal value for the 'symmetry' option in matrix market header");
}
return options;
}
template <typename IDType, typename NNZType, typename ValueType>
template <bool weighted>
format::COO<IDType, NNZType, ValueType>
*MTXReader<IDType, NNZType, ValueType>::ReadArrayIntoCOO() const {
std::ifstream fin(filename_);
// Ignore headers and comments:
while (fin.peek() == '%')
fin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Declare variables: (check the types here)
format::DimensionType M, N;
fin >> M >> N;
format::DimensionType total_values = M * N;
IDType *long_rows = new IDType[total_values];
IDType *long_cols = new IDType[total_values];
ValueType *long_vals = nullptr;
if constexpr (weighted) long_vals = new ValueType[total_values];
NNZType num_nnz = 0;
for (format::DimensionType l = 0; l < total_values; l++) {
ValueType w;
fin >> w;
if (w != 0) {
long_cols[num_nnz] = l / N;
long_rows[num_nnz] = l % N;
if constexpr (weighted) long_vals[num_nnz] = w;
num_nnz++;
}
// nnz_counter += w != 0;
}
IDType *row = new IDType[num_nnz];
IDType *col = new IDType[num_nnz];
std::copy(long_rows, long_rows + num_nnz, row);
std::copy(long_cols, long_cols + num_nnz, col);
ValueType *vals = nullptr;
if constexpr (weighted) {
vals = new ValueType[num_nnz];
std::copy(long_vals, long_vals + num_nnz, vals);
}
return new format::COO<IDType, NNZType, ValueType>(N, M, num_nnz, row, col,
vals, format::kOwned);
}
template <typename IDType, typename NNZType, typename ValueType>
format::COO<IDType, NNZType, ValueType>
*MTXReader<IDType, NNZType, ValueType>::ReadCOO() const {
bool weighted = options_.field != MTXFieldOptions::pattern;
if (options_.format == MTXFormatOptions::array) {
if (weighted) {
if constexpr (!std::is_same_v<ValueType, void>) {
return this->ReadArrayIntoCOO<true>();
} else {
throw utils::ReaderException(
"Weight type for weighted graphs can not be void");
}
} else
throw utils::ReaderException(
"Matrix market files with array format cannot have the field "
"'pattern' ");
} else if (options_.format == MTXFormatOptions::coordinate) {
if (weighted) {
if (options_.symmetry == MTXSymmetryOptions::general)
if (this->convert_to_zero_index_)
return this->ReadCoordinateIntoCOO<
true, (int)MTXSymmetryOptions::general, true>();
else
return this->ReadCoordinateIntoCOO<
true, (int)MTXSymmetryOptions::general, false>();
else if (options_.symmetry == MTXSymmetryOptions::symmetric)
if (this->convert_to_zero_index_)
return this->ReadCoordinateIntoCOO<
true, (int)MTXSymmetryOptions::symmetric, true>();
else
return this->ReadCoordinateIntoCOO<
true, (int)MTXSymmetryOptions::symmetric, false>();
else if (options_.symmetry == MTXSymmetryOptions::skew_symmetric)
if (this->convert_to_zero_index_)
return this->ReadCoordinateIntoCOO<
true, (int)MTXSymmetryOptions::skew_symmetric, true>();
else
return this->ReadCoordinateIntoCOO<
true, (int)MTXSymmetryOptions::skew_symmetric, false>();
else
throw utils::ReaderException(
"Can't read matrix market symmetry options besides general, "
"symmetric, and skew_symmetric");
} else {
if (options_.symmetry == MTXSymmetryOptions::general)
if (this->convert_to_zero_index_)
return this->ReadCoordinateIntoCOO<
false, (int)MTXSymmetryOptions::general, true>();
else
return this->ReadCoordinateIntoCOO<
false, (int)MTXSymmetryOptions::general, false>();
else if (options_.symmetry == MTXSymmetryOptions::symmetric)
if (this->convert_to_zero_index_)
return this->ReadCoordinateIntoCOO<
false, (int)MTXSymmetryOptions::symmetric, true>();
else
return this->ReadCoordinateIntoCOO<
false, (int)MTXSymmetryOptions::symmetric, false>();
else if (options_.symmetry == MTXSymmetryOptions::skew_symmetric)
if (this->convert_to_zero_index_)
return this->ReadCoordinateIntoCOO<
false, (int)MTXSymmetryOptions::skew_symmetric, true>();
else
return this->ReadCoordinateIntoCOO<
false, (int)MTXSymmetryOptions::skew_symmetric, false>();
else
throw utils::ReaderException(
"Can't read matrix market symmetry options besides general, "
"symmetric, and skew_symmetric");
}
} else {
throw utils::ReaderException(
"Can't read matrix market formats besides array and coordinate");
}
}
template <typename IDType, typename NNZType, typename ValueType>
format::Array<ValueType>
*MTXReader<IDType, NNZType, ValueType>::ReadCoordinateIntoArray() const {
if constexpr (std::is_same_v<ValueType, void>)
throw utils::ReaderException(
"Cannot read a matrix market file into an Array with void ValueType");
else {
std::ifstream fin(filename_);
// Ignore headers and comments:
while (fin.peek() == '%')
fin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Declare variables: (check the types here)
// check that it has 1 row/column
format::DimensionType M, N, L;
fin >> M >> N >> L;
if (M != 1 && N != 1) {
throw utils::ReaderException(
"Trying to read a 2D matrix with multiple rows "
"and multiple columns into dense array");
}
fin.close();
auto coo = ReadCOO();
auto n = coo->get_dimensions()[0];
auto m = coo->get_dimensions()[1];
auto coo_col = coo->get_col();
auto coo_row = coo->get_row();
auto coo_vals = coo->get_vals();
auto num_nnz = coo->get_num_nnz();
ValueType *vals = new ValueType[std::max<IDType>(n, m)]();
IDType curr_row = 0;
IDType curr_col = 0;
for (IDType nnz = 0; nnz < num_nnz; nnz++) {
vals[coo_col[nnz] + coo_row[nnz]] = coo_vals[nnz];
}
return new format::Array<ValueType>(std::max(n, m), vals,
sparsebase::format::kOwned);
}
}
template <typename IDType, typename NNZType, typename ValueType>
template <bool weighted, int symm, bool conv_to_zero>
format::COO<IDType, NNZType, ValueType>
*MTXReader<IDType, NNZType, ValueType>::ReadCoordinateIntoCOO() const {
// Open the file:
std::ifstream fin(filename_);
if (fin.is_open()) {
// Declare variables: (check the types here)
format::DimensionType M, N, L;
// Ignore headers and comments:
while (fin.peek() == '%')
fin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
fin >> M >> N >> L;
ValueType *vals = nullptr;
if constexpr (symm == (int)MTXSymmetryOptions::general) {
IDType *row = new IDType[L];
IDType *col = new IDType[L];
if constexpr (weighted) {
if constexpr (!std::is_same_v<void, ValueType>) {
vals = new ValueType[L];
for (NNZType l = 0; l < L; l++) {
IDType m, n;
ValueType w;
fin >> m >> n >> w;
if constexpr (conv_to_zero) {
n--;
m--;
}
row[l] = m;
col[l] = n;
vals[l] = w;
}
auto coo = new format::COO<IDType, NNZType, ValueType>(
M, N, L, row, col, vals, format::kOwned);
return coo;
} else {
// TODO: Add an exception class for this
throw utils::ReaderException(
"Weight type for weighted graphs can not be void");
}
} else {
for (NNZType l = 0; l < L; l++) {
IDType m, n;
fin >> m >> n;
if constexpr (conv_to_zero) {
n--;
m--;
}
row[l] = m;
col[l] = n;
}
auto coo = new format::COO<IDType, NNZType, ValueType>(
M, N, L, row, col, nullptr, format::kOwned);
return coo;
}
} else if constexpr (symm == (int)MTXSymmetryOptions::symmetric ||
symm == (int)MTXSymmetryOptions::skew_symmetric) {
IDType *row = new IDType[L * 2];
IDType *col = new IDType[L * 2];
NNZType actual_nnzs = 0;
IDType m, n;
if constexpr (weighted) {
if constexpr (!std::is_same_v<void, ValueType>) {
vals = new ValueType[L * 2];
} else {
throw utils::ReaderException(
"Weight type for weighted graphs can not be void");
}
}
for (NNZType l = 0; l < L; l++) {
fin >> m >> n;
if constexpr (conv_to_zero) {
n--;
m--;
}
row[actual_nnzs] = m;
col[actual_nnzs] = n;
if constexpr (weighted && !std::is_same_v<void, ValueType>) {
fin >> vals[actual_nnzs];
}
actual_nnzs++;
bool check_diagonal;
if constexpr (symm == (int)MTXSymmetryOptions::skew_symmetric)
check_diagonal = false;
else
check_diagonal = true;
if (check_diagonal && m != n) {
row[actual_nnzs] = n;
col[actual_nnzs] = m;
if constexpr (weighted && !std::is_same_v<void, ValueType> &&
weighted)
vals[actual_nnzs] = vals[actual_nnzs - 1];
actual_nnzs++;
}
}
IDType *actual_rows = row;
IDType *actual_cols = col;
ValueType *actual_vals = vals;
if (symm == (int)MTXSymmetryOptions::symmetric && actual_nnzs != L * 2) {
actual_rows = new IDType[actual_nnzs];
actual_cols = new IDType[actual_nnzs];
std::copy(row, row + actual_nnzs, actual_rows);
std::copy(col, col + actual_nnzs, actual_cols);
delete[] row;
delete[] col;
if constexpr (weighted && !std::is_same_v<void, ValueType>) {
actual_vals = new ValueType[actual_nnzs];
std::copy(vals, vals + actual_nnzs, actual_vals);
delete[] vals;
}
}
auto coo = new format::COO<IDType, NNZType, ValueType>(
M, N, actual_nnzs, actual_rows, actual_cols, actual_vals,
format::kOwned);
return coo;
} else {
throw utils::ReaderException(
"Reader only supports general, symmetric, and skew-symmetric "
"symmetry options");
}
} else {
throw utils::ReaderException("file does not exists!!");
}
}
template <typename IDType, typename NNZType, typename ValueType>
format::Array<ValueType>
*MTXReader<IDType, NNZType, ValueType>::ReadArrayIntoArray() const {
if constexpr (!std::is_same_v<void, ValueType>) {
std::ifstream fin(filename_);
// Ignore headers and comments:
while (fin.peek() == '%')
fin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Declare variables: (check the types here)
// check that it has 1 row/column
format::DimensionType M, N;
fin >> M >> N;
if (M != 1 && N != 1) {
throw utils::ReaderException(
"Trying to read a 2D matrix with multiple rows "
"and multiple columns into dense array");
}
format::DimensionType total_values = M * N;
// T ODO
// Currently num_nnz is defined all wrong. Once it's fixed add back
// nnz_counter
// NNZType nnz_counter = 0;
ValueType *vals = new ValueType[total_values];
for (format::DimensionType l = 0; l < total_values; l++) {
ValueType w;
fin >> w;
vals[l] = w;
// nnz_counter += w != 0;
}
auto array = new format::Array<ValueType>(/*nnz_counter*/ total_values,
vals, format::kOwned);
return array;
} else {
throw utils::ReaderException(
"Cannot read a matrix market file into an Array whose ValueType is "
"void");
}
}
template <typename IDType, typename NNZType, typename ValueType>
format::Array<ValueType> *MTXReader<IDType, NNZType, ValueType>::ReadArray()
const {
// check object
if constexpr (std::is_same_v<ValueType, void>) {
throw utils::ReaderException(
"Cannot read a matrix market file into an Array whose ValueType is "
"void");
} else {
bool weighted = options_.field != MTXFieldOptions::pattern;
if (!weighted) {
throw utils::ReaderException(
"Cannot read a matrix market file into an Array if it is in pattern "
"format");
}
if (options_.format == MTXFormatOptions::coordinate) {
if constexpr (!std::is_same_v<ValueType, void>) {
return ReadCoordinateIntoArray();
}
} else if (options_.format == MTXFormatOptions::array) {
if constexpr (!std::is_same_v<ValueType, void>) {
return ReadArrayIntoArray();
}
} else {
throw utils::ReaderException(
"Wrong format value while reading matrix market file\n");
}
}
}
template <typename IDType, typename NNZType, typename ValueType>
format::CSR<IDType, NNZType, ValueType>
*MTXReader<IDType, NNZType, ValueType>::ReadCSR() const {
auto coo = ReadCOO();
converter::ConverterOrderTwo<IDType, NNZType, ValueType> converterObj;
context::CPUContext cpu_context;
return converterObj.template Convert<format::CSR<IDType, NNZType, ValueType>>(
coo, &cpu_context);
}
template <typename IDType, typename NNZType, typename ValueType>
MTXReader<IDType, NNZType, ValueType>::~MTXReader(){};
#ifndef _HEADER_ONLY
#include "init/mtx_reader.inc"
#endif
} // namespace sparsebase::io