You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

199 lines
6.4 KiB

#ifndef MRMC_SPARSE_STATIC_SPARSE_MATRIX_H_
#define MRMC_SPARSE_STATIC_SPARSE_MATRIX_H_
#include <exception>
#include "boost/integer/integer_mask.hpp"
#include <pantheios/pantheios.hpp>
#include <pantheios/inserters/integer.hpp>
#include "src/exceptions/invalid_state.h"
#include "src/exceptions/invalid_argument.h"
#include "src/exceptions/out_of_range.h"
namespace mrmc {
namespace sparse {
//! A sparse Matrix for DTMCs with a constant number of non-zero entries on the non-diagonal fields.
/*!
The sparse matrix used for calculation on the DTMCs.
Adressing is NOT zero-based! The valid range for getValue and addNextValue is 1 to rows (first argument to constructor).
*/
template <class T>
class StaticSparseMatrix {
public:
//! Constructor
/*!
\param rows Row-Count and therefor column-count of the symetric matrix
\param non_zero_entries The exact count of entries that will be submitted through addNextValue *excluding* those on the diagonal (A_{i,j} with i = j)
*/
StaticSparseMatrix(uint_fast32_t rows, uint_fast32_t non_zero_entries) {
current_size = 0;
storage_size = 0;
row_count = rows;
non_zero_entry_count = non_zero_entries;
//initialize(rows, non_zero_entries);
}
~StaticSparseMatrix() {
if (value_storage != NULL) {
free(value_storage);
}
if (column_indications != NULL) {
free(column_indications);
}
if (row_indications != NULL) {
free(row_indications);
}
if (diagonal_storage != NULL) {
free(diagonal_storage);
}
}
//! Getter for saving matrix entry A_{row,col} to target
/*!
Getter function for the matrix.
\param row 1-based index of the requested row
\param col 1-based index of the requested column
\param target pointer to where the result will be stored
\return True iff the value was set, false otherwise. On false, 0 will be written to *target.
*/
inline bool getValue(uint_fast32_t row, uint_fast32_t col, T* const target) {
if (row == col) {
// storage is row_count + 1 large for direct access without the -1
*target = diagonal_storage[row];
return true;
}
if ((row > row_count) || (col > row_count) || (row == 0) || (col == 0)) {
throw new mrmc::exceptions::out_of_range("mrmc::StaticSparseMatrix::getValue: row or col not in 1 .. rows");
}
uint_fast32_t row_start = row_indications[row - 1];
uint_fast32_t row_end = row_indications[row];
while (row_start < row_end) {
if (column_indications[row_start] == col) {
*target = value_storage[row_start];
return true;
}
if (column_indications[row_start] > col) {
break;
}
row_start++;
}
*target = 0;
return false;
}
//! Mandatory initialization of the matrix
/*!
Mandatory initialization of the matrix, must be called before using any other member function.
*/
void initialize() {
if (row_count == 0) {
pantheios::log_ERROR("StaticSparseMatrix::initialize: Throwing invalid_argument for row_count = 0");
throw new mrmc::exceptions::invalid_argument("mrmc::StaticSparseMatrix::initialize: Matrix with 0 rows is not reasonable");
}
if (((row_count * row_count) - row_count) < non_zero_entry_count) {
pantheios::log_ERROR("StaticSparseMatrix::initialize: Throwing invalid_argument: More non-zero entries than entries in target matrix");
throw new mrmc::exceptions::invalid_argument("mrmc::StaticSparseMatrix::initialize: More non-zero entries than entries in target matrix");
}
storage_size = non_zero_entry_count;
last_row = 0;
value_storage = static_cast<T*>(calloc(storage_size, sizeof(*value_storage)));
column_indications = static_cast<uint_fast32_t*>(calloc(storage_size, sizeof(*column_indications)));
row_indications = static_cast<uint_fast32_t*>(calloc(row_count + 1, sizeof(*row_indications)));
// row_count + 1 so that access with 1-based indices can be direct without the overhead of a -1 each time
diagonal_storage = static_cast<T*>(calloc(row_count + 1, sizeof(*diagonal_storage)));
if ((value_storage == NULL) || (column_indications == NULL) || (row_indications == NULL) || (diagonal_storage == NULL)) {
pantheios::log_ERROR("StaticSparseMatrix::initialize: Throwing bad_alloc: memory allocation failed");
#ifdef __linux__
throw new std::bad_alloc();
#else
throw new std::bad_alloc("mrmc::StaticSparseMatrix::initialize: memory allocation failed");
#endif
}
}
//! Linear Setter for matrix entry A_{row, col} to value
/*!
Linear Setter function for matrix entry A_{row, col} to value. Must be called consecutively for each element in a row in ascending order of columns AND in ascending order of rows.
Diagonal entries may be set at any time.
*/
void addNextValue(const uint_fast32_t row, const uint_fast32_t col, const T value) {
if ((row > row_count) || (col > row_count) || (row == 0) || (col == 0)) {
pantheios::log_ERROR("StaticSparseMatrix::addNextValue: Throwing out_of_range: row or col not in 1 .. rows");
throw new mrmc::exceptions::out_of_range("mrmc::StaticSparseMatrix::addNextValue: row or col not in 1 .. rows");
}
if (row == col) {
diagonal_storage[row] = value;
} else {
if (row != last_row) {
for (uint_fast32_t i = last_row; i < row; ++i) {
row_indications[i] = current_size;
}
last_row = row;
}
value_storage[current_size] = value;
column_indications[current_size] = col;
// Increment counter for stored elements
current_size++;
}
}
void finalize() {
if (storage_size != current_size) {
pantheios::log_ERROR("StaticSparseMatrix::finalize: Throwing invalid_state: Wrong call count for addNextValue");
throw new mrmc::exceptions::invalid_state("mrmc::StaticSparseMatrix::finalize: Wrong call count for addNextValue");
}
if (last_row != row_count) {
for (uint_fast32_t i = last_row; i < row_count; ++i) {
row_indications[i] = current_size;
}
}
row_indications[row_count] = storage_size;
}
private:
uint_fast32_t storage_size;
uint_fast32_t current_size;
uint_fast32_t row_count;
uint_fast32_t non_zero_entry_count;
uint_fast32_t last_row;
/*! Array containing all non-zero values, apart from the diagonal entries */
T* value_storage;
/*! Array containing all diagonal values */
T* diagonal_storage;
/*! Array containing the column number of the corresponding value_storage entry */
uint_fast32_t* column_indications;
/*! Array containing the row boundarys of valueStorage */
uint_fast32_t* row_indications;
};
} // namespace sparse
} // namespace mrmc
#endif // MRMC_SPARSE_STATIC_SPARSE_MATRIX_H_