/*! read_tra_file.cpp * Provides functions for reading a *.tra file describing the transition * system of a Markov chain (DTMC) and saving it into a corresponding * matrix. * * Reuses code from the file "read_tra_file.c" from the old MRMC project. * * Created on: 15.08.2012 * Author: Thomas Heinemann */ #include "src/parser/read_tra_file.h" #include "src/exceptions/file_IO_exception.h" #include "src/exceptions/wrong_file_format.h" #include "boost/integer/integer_mask.hpp" #include #include #include #include #include namespace mrmc { namespace parser{ // Disable C4996 - This function or variable may be unsafe. #pragma warning(disable:4996) /*! * This method does the first pass through the .tra file and computes * the number of non zero elements that are not diagonal elements, * which correspondents to the number of transitions that are not * self-loops. * (Diagonal elements are treated in a special way). * * @return The number of non-zero elements that are not on the diagonal * @param p File stream to scan. Is expected to be opened, a NULL pointer will * be rejected! */ static uint_fast32_t make_first_pass(FILE* p) { if(p==NULL) { pantheios::log_ERROR("make_first_pass was called with NULL! (SHOULD NEVER HAPPEN)"); throw exceptions::file_IO_exception ("make_first_pass: File not readable (this should be checked before calling this function!)"); } char s[1024]; //String buffer uint_fast32_t rows=0, non_zero=0; //Reading No. of states if (fgets(s, 1024, p) != NULL) { if (sscanf( s, "STATES %d", &rows) == 0) { pantheios::log_WARNING(pantheios::integer(rows)); throw mrmc::exceptions::wrong_file_format(); } } //Reading No. of transitions if (fgets(s, 1024, p) != NULL) { if (sscanf( s, "TRANSITIONS %d", &non_zero) == 0) { throw mrmc::exceptions::wrong_file_format(); } } //Reading transitions (one per line) //And increase number of transitions while (NULL != fgets( s, 1024, p )) { uint_fast32_t row=0, col=0; double val=0.0; if (sscanf( s, "%d%d%lf", &row, &col, &val ) != 3) { throw mrmc::exceptions::wrong_file_format(); } //Diagonal elements are not counted into the result! if(row == col) { --non_zero; } } return non_zero; } /*!Reads a .tra file and produces a sparse matrix representing the described Markov Chain. * @param *filename input .tra file's name. * @return a pointer to a sparse matrix. */ sparse::StaticSparseMatrix * read_tra_file(const char * filename) { FILE *p; char s[1024]; uint_fast32_t rows, non_zero; sparse::StaticSparseMatrix *sp = NULL; p = fopen(filename, "r"); if(p==NULL) { pantheios::log_ERROR("File ", filename, " was not readable (Does it exist?)"); throw exceptions::file_IO_exception("mrmc::read_tra_file: Error opening file! (Does it exist?)"); } non_zero = make_first_pass(p); //Set file reader back to the beginning rewind(p); //Reading No. of states if (fgets(s, 1024, p) != NULL) { if (sscanf( s, "STATES %d", &rows) == 0) { pantheios::log_WARNING(pantheios::integer(rows)); throw mrmc::exceptions::wrong_file_format(); } } /* Reading No. of transitions * Note that the result is not used in this function as make_first_pass() * computes the relevant number (non_zero) */ if (fgets(s, 1024, p) != NULL) { uint_fast32_t nnz=0; if (sscanf( s, "TRANSITIONS %d", &nnz) == 0) { throw mrmc::exceptions::wrong_file_format(); } } pantheios::log_DEBUG("Creating matrix with ", pantheios::integer(rows), " rows and ", pantheios::integer(non_zero), " Non-Zero-Elements"); /* Creating matrix * Variable non_zero does NOT count any diagonal element, * But all diagonal elements are allocated, so the number of allocated * elements is non_zero */ sp = new sparse::StaticSparseMatrix(rows,non_zero); sp->initialize(); if ( NULL == sp ) { throw std::bad_alloc(); return NULL; } //Reading transitions (one per line) and saving the results in the matrix while (NULL != fgets( s, 1024, p )) { uint_fast32_t row=0, col=0; double val = 0.0; if (sscanf( s, "%d%d%lf", &row, &col, &val) != 3) { throw mrmc::exceptions::wrong_file_format(); } pantheios::log_DEBUG("Write value ", pantheios::real(val), " to position ", pantheios::integer(row), " x ", pantheios::integer(col)); sp->addNextValue(row,col,val); } (void)fclose(p); pantheios::log_DEBUG("Finalizing Matrix"); sp->finalize(); return sp; } } //namespace parser } //namespace mrmc