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
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_
|