Browse Source

Refactored NondeterministicSparseTransitionParser.h/.cpp.

-Changed structure to conform to common parser structure: static class with two passes and structs to handle value passing.
-Killed all warnings (signed unsigned interger compare)
-Made parser more flexible: Is now able to ignore arbitrarily many columns after the value column (instead of only one).
-Threw out a number of unnecessary includes.
-more...

Next up: Refactor NondeterministicModelParser.h/.cpp


Former-commit-id: fd2fdb7fdf
main
masawei 11 years ago
parent
commit
cc71a002f4
  1. 18
      src/parser/DeterministicSparseTransitionParser.cpp
  2. 4
      src/parser/DeterministicSparseTransitionParser.h
  3. 2
      src/parser/MarkovAutomatonSparseTransitionParser.cpp
  4. 18
      src/parser/NondeterministicModelParser.cpp
  5. 565
      src/parser/NondeterministicSparseTransitionParser.cpp
  6. 113
      src/parser/NondeterministicSparseTransitionParser.h
  7. 23
      src/parser/Parser.cpp
  8. 5
      src/parser/Parser.h

18
src/parser/DeterministicSparseTransitionParser.cpp

@ -30,12 +30,14 @@ namespace parser {
storm::storage::SparseMatrix<double> DeterministicSparseTransitionParser::parseDeterministicTransitions(std::string const& filename, bool insertDiagonalEntriesIfMissing) {
return DeterministicSparseTransitionParser::parse(filename, false, insertDiagonalEntriesIfMissing);
RewardMatrixInformationStruct nullInformation;
return DeterministicSparseTransitionParser::parse(filename, false, nullInformation, insertDiagonalEntriesIfMissing);
}
storm::storage::SparseMatrix<double> DeterministicSparseTransitionParser::parseDeterministicTransitionRewards(std::string const& filename, RewardMatrixInformationStruct const& rewardMatrixInformation) {
return DeterministicSparseTransitionParser::parse(filename, true, false, rewardMatrixInformation);
return DeterministicSparseTransitionParser::parse(filename, true, rewardMatrixInformation);
}
DeterministicSparseTransitionParser::FirstPassResult DeterministicSparseTransitionParser::firstPass(char* buf, SupportedLineEndingsEnum lineEndings, bool insertDiagonalEntriesIfMissing) {
@ -44,7 +46,7 @@ DeterministicSparseTransitionParser::FirstPassResult DeterministicSparseTransiti
// Skip the format hint if it is there.
buf = trimWhitespaces(buf);
if(buf[0] != '0') {
if(buf[0] < '0' || buf[0] > '9') {
buf = storm::parser::forwardToNextLine(buf, lineEndings);
}
@ -53,7 +55,7 @@ DeterministicSparseTransitionParser::FirstPassResult DeterministicSparseTransiti
bool rowHadDiagonalEntry = false;
while (buf[0] != '\0') {
// Read the transition..
// Read the transition.
row = checked_strtol(buf, &buf);
col = checked_strtol(buf, &buf);
// The actual read value is not needed here.
@ -106,7 +108,7 @@ DeterministicSparseTransitionParser::FirstPassResult DeterministicSparseTransiti
return result;
}
storm::storage::SparseMatrix<double> DeterministicSparseTransitionParser::parse(std::string const& filename, bool rewardFile, bool insertDiagonalEntriesIfMissing, RewardMatrixInformationStruct const& rewardMatrixInformation) {
storm::storage::SparseMatrix<double> DeterministicSparseTransitionParser::parse(std::string const& filename, bool isRewardFile, RewardMatrixInformationStruct const& rewardMatrixInformation, bool insertDiagonalEntriesIfMissing) {
// Enforce locale where decimal point is '.'.
setlocale(LC_NUMERIC, "C");
@ -138,11 +140,11 @@ storm::storage::SparseMatrix<double> DeterministicSparseTransitionParser::parse(
// Skip the format hint if it is there.
buf = trimWhitespaces(buf);
if(buf[0] != '0') {
if(buf[0] < '0' || buf[0] > '9') {
buf = storm::parser::forwardToNextLine(buf, lineEndings);
}
if(rewardFile) {
if(isRewardFile) {
// The reward matrix should match the size of the transition matrix.
if (firstPass.highestStateIndex + 1 > rewardMatrixInformation.rowCount || firstPass.highestStateIndex + 1 > rewardMatrixInformation.columnCount) {
LOG4CPLUS_ERROR(logger, "Reward matrix has more rows or columns than transition matrix.");
@ -169,7 +171,7 @@ storm::storage::SparseMatrix<double> DeterministicSparseTransitionParser::parse(
// work, i.e. the values in the matrix will be at wrong places.
// Different parsing routines for transition systems and transition rewards.
if(rewardFile) {
if(isRewardFile) {
while (buf[0] != '\0') {
// Read next transition.

4
src/parser/DeterministicSparseTransitionParser.h

@ -59,7 +59,7 @@ private:
*
* @param buffer The buffer that cointains the input.
* @param lineEndings The line endings that are to be used while parsing.
* @param insertDiagonalEntriesIfMissing Flag determining whether
* @param insertDiagonalEntriesIfMissing A flag set iff entries on the primary diagonal of the matrix should be added in case they are missing in the parsed file.
* @return A structure representing the result of the first pass.
*/
static FirstPassResult firstPass(char* buffer, SupportedLineEndingsEnum lineEndings, bool insertDiagonalEntriesIfMissing = true);
@ -74,7 +74,7 @@ private:
* @param rewardMatrixInformation A struct containing information that is used to check if the transition reward matrix fits to the rest of the model.
* @return A SparseMatrix containing the parsed file contents.
*/
static storm::storage::SparseMatrix<double> parse(std::string const& filename, bool rewardFile, bool insertDiagonalEntriesIfMissing = false, RewardMatrixInformationStruct const& rewardMatrixInformation = nullptr);
static storm::storage::SparseMatrix<double> parse(std::string const& filename, bool isRewardFile, RewardMatrixInformationStruct const& rewardMatrixInformation, bool insertDiagonalEntriesIfMissing = false);
};

2
src/parser/MarkovAutomatonSparseTransitionParser.cpp

@ -14,7 +14,7 @@ MarkovAutomatonSparseTransitionParser::FirstPassResult MarkovAutomatonSparseTran
// Skip the format hint if it is there.
buf = trimWhitespaces(buf);
if(buf[0] != '0') {
if(buf[0] < '0' || buf[0] > '9') {
buf = storm::parser::forwardToNextLine(buf, lineEndings);
}

18
src/parser/NondeterministicModelParser.cpp

@ -29,23 +29,23 @@ namespace parser {
NondeterministicModelParserResultContainer<double> parseNondeterministicModel(std::string const & transitionSystemFile, std::string const & labelingFile,
std::string const & stateRewardFile, std::string const & transitionRewardFile) {
NondeterministicSparseTransitionParserResult_t nondeterministicSparseTransitionParserResult(std::move(storm::parser::NondeterministicSparseTransitionParser(transitionSystemFile)));
storm::storage::SparseMatrix<double> resultTransitionSystem(std::move(nondeterministicSparseTransitionParserResult.first));
NondeterministicSparseTransitionParser::Result transitionParserResult(std::move(storm::parser::NondeterministicSparseTransitionParser::parseNondeterministicTransitions(transitionSystemFile)));
storm::storage::SparseMatrix<double> transitions(std::move(transitionParserResult.transitionMatrix));
uint_fast64_t stateCount = resultTransitionSystem.getColumnCount();
uint_fast64_t rowCount = resultTransitionSystem.getRowCount();
uint_fast64_t stateCount = transitions.getColumnCount();
uint_fast64_t rowCount = transitions.getRowCount();
storm::models::AtomicPropositionsLabeling resultLabeling(std::move(storm::parser::AtomicPropositionLabelingParser(stateCount, labelingFile)));
storm::models::AtomicPropositionsLabeling labeling(std::move(storm::parser::AtomicPropositionLabelingParser(stateCount, labelingFile)));
NondeterministicModelParserResultContainer<double> result(std::move(resultTransitionSystem), std::move(nondeterministicSparseTransitionParserResult.second), std::move(resultLabeling));
NondeterministicModelParserResultContainer<double> result(std::move(transitions), std::move(transitionParserResult.rowMapping), std::move(labeling));
if (stateRewardFile != "") {
result.stateRewards.reset(storm::parser::SparseStateRewardParser::parseSparseStateReward(stateCount, stateRewardFile));
}
if (transitionRewardFile != "") {
RewardMatrixInformationStruct* rewardMatrixInfo = new RewardMatrixInformationStruct(rowCount, stateCount, &result.rowMapping);
result.transitionRewards.reset(storm::parser::NondeterministicSparseTransitionParser(transitionRewardFile, rewardMatrixInfo).first);
delete rewardMatrixInfo;
RewardMatrixInformationStruct rewardMatrixInfo(rowCount, stateCount, &result.rowMapping);
result.transitionRewards.reset(storm::parser::NondeterministicSparseTransitionParser::parseNondeterministicTransitionRewards(transitionRewardFile, rewardMatrixInfo).transitionMatrix);
}
return result;
}

565
src/parser/NondeterministicSparseTransitionParser.cpp

@ -1,5 +1,5 @@
/*!
* TraParser.cpp
* NondeterministicSparseTransitionParser.cpp
*
* Created on: 20.11.2012
* Author: Gereon Kremer
@ -7,380 +7,277 @@
#include "src/parser/NondeterministicSparseTransitionParser.h"
#include <errno.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <locale.h>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <clocale>
#include <iostream>
#include <utility>
#include <string>
#include "src/settings/Settings.h"
#include "src/exceptions/FileIoException.h"
#include "src/exceptions/WrongFormatException.h"
#include <cstdint>
#include "log4cplus/logger.h"
#include "log4cplus/loggingmacros.h"
extern log4cplus::Logger logger;
namespace storm {
namespace parser {
namespace parser {
/*!
* @brief Perform first pass through the file and obtain overall number of
* choices, number of non-zero cells and maximum node id.
*
* This method does the first pass through the transition file.
*
* It computes the overall number of nondeterministic choices, i.e. the
* number of rows in the matrix that should be created.
* It also calculates the overall number of non-zero cells, i.e. the number
* of elements the matrix has to hold, and the maximum node id, i.e. the
* number of columns of the matrix.
*
* @param buf Data to scan. Is expected to be some char array.
* @param choices Overall number of choices.
* @param maxnode Is set to highest id of all nodes.
* @return The number of non-zero elements.
*/
uint_fast64_t firstPass(char* buf, SupportedLineEndingsEnum lineEndings, uint_fast64_t& choices, int_fast64_t& maxnode, RewardMatrixInformationStruct* rewardMatrixInformation) {
bool isRewardFile = rewardMatrixInformation != nullptr;
/*
* Check file header and extract number of transitions.
*/
if (!isRewardFile) {
// skip format hint
buf = storm::parser::forwardToNextLine(buf, lineEndings);
}
/*
* Read all transitions.
*/
int_fast64_t source, target, choice, lastchoice = -1;
int_fast64_t lastsource = -1;
uint_fast64_t nonzero = 0;
double val;
choices = 0;
maxnode = 0;
while (buf[0] != '\0') {
/*
* Read source state and choice.
*/
source = checked_strtol(buf, &buf);
// Read the name of the nondeterministic choice.
choice = checked_strtol(buf, &buf);
// Check if we encountered a state index that is bigger than all previously seen.
if (source > maxnode) {
maxnode = source;
NondeterministicSparseTransitionParser::Result NondeterministicSparseTransitionParser::parseNondeterministicTransitions(std::string const& filename) {
RewardMatrixInformationStruct nullInformation;
return NondeterministicSparseTransitionParser::parse(filename, false, nullInformation);
}
if (isRewardFile) {
// If we have switched the source state, we possibly need to insert the rows of the last
// last source state.
if (source != lastsource && lastsource != -1) {
choices += lastchoice - ((*rewardMatrixInformation->nondeterministicChoiceIndices)[lastsource + 1] - (*rewardMatrixInformation->nondeterministicChoiceIndices)[lastsource] - 1);
}
NondeterministicSparseTransitionParser::Result NondeterministicSparseTransitionParser::parseNondeterministicTransitionRewards(std::string const& filename, RewardMatrixInformationStruct const& rewardMatrixInformation) {
// If we skipped some states, we need to reserve empty rows for all their nondeterministic
// choices.
for (int_fast64_t i = lastsource + 1; i < source; ++i) {
choices += ((*rewardMatrixInformation->nondeterministicChoiceIndices)[i + 1] - (*rewardMatrixInformation->nondeterministicChoiceIndices)[i]);
}
return NondeterministicSparseTransitionParser::parse(filename, true, rewardMatrixInformation);
}
// If we advanced to the next state, but skipped some choices, we have to reserve rows
// for them
if (source != lastsource) {
choices += choice + 1;
} else if (choice != lastchoice) {
choices += choice - lastchoice;
}
} else {
// If we have skipped some states, we need to reserve the space for the self-loop insertion
// in the second pass.
if (source > lastsource + 1) {
nonzero += source - lastsource - 1;
choices += source - lastsource - 1;
} else if (source != lastsource || choice != lastchoice) {
// If we have switched the source state or the nondeterministic choice, we need to
// reserve one row more.
++choices;
NondeterministicSparseTransitionParser::FirstPassResult NondeterministicSparseTransitionParser::firstPass(char* buf, SupportedLineEndingsEnum lineEndings, bool isRewardFile, RewardMatrixInformationStruct const& rewardMatrixInformation) {
// Check file header and extract number of transitions.
// Skip the format hint if it is there.
buf = trimWhitespaces(buf);
if(buf[0] < '0' || buf[0] > '9') {
buf = storm::parser::forwardToNextLine(buf, lineEndings);
}
}
// Read target and check if we encountered a state index that is bigger than all previously
// seen.
target = checked_strtol(buf, &buf);
if (target > maxnode) {
maxnode = target;
}
// Read all transitions.
uint_fast64_t source = 0, target = 0, choice = 0, lastchoice = 0, lastsource = 0;
double val = 0.0;
NondeterministicSparseTransitionParser::FirstPassResult result;
// Read value and check whether it's positive.
val = checked_strtod(buf, &buf);
if ((val < 0.0) || (val > 1.0)) {
LOG4CPLUS_ERROR(logger, "Expected a positive probability but got \"" << std::string(buf, 0, 16) << "\".");
return 0;
}
// Since the first line is already a new choice but is not covered below, that has to be covered here.
result.choices = 1;
lastchoice = choice;
lastsource = source;
/*
* Increase number of non-zero values.
*/
nonzero++;
// The PRISM output format lists the name of the transition in the fourth column,
// but omits the fourth column if it is an internal action. In either case, however, the third column
// is followed by a space. We need to skip over that space first (instead of trimming whitespaces),
// before we can skip to the line end, because trimming the white spaces will proceed to the next line
// in case there is no action label in the fourth column.
if (buf[0] == ' ') {
++buf;
}
while (buf[0] != '\0') {
/*
* Proceed to beginning of next line.
*/
switch (lineEndings) {
case SupportedLineEndingsEnum::SlashN:
buf += strcspn(buf, " \t\n");
break;
case SupportedLineEndingsEnum::SlashR:
buf += strcspn(buf, " \t\r");
break;
case SupportedLineEndingsEnum::SlashRN:
buf += strcspn(buf, " \t\r\n");
break;
default:
case storm::parser::SupportedLineEndingsEnum::Unsupported:
// This Line will never be reached as the Parser would have thrown already.
throw;
break;
}
buf = trimWhitespaces(buf);
}
// Read source state and choice.
source = checked_strtol(buf, &buf);
if (isRewardFile) {
// If not all rows were filled for the last state, we need to insert them.
choices += lastchoice - ((*rewardMatrixInformation->nondeterministicChoiceIndices)[lastsource + 1] - (*rewardMatrixInformation->nondeterministicChoiceIndices)[lastsource] - 1);
// Read the name of the nondeterministic choice.
choice = checked_strtol(buf, &buf);
// If we skipped some states, we need to reserve empty rows for all their nondeterministic
// choices.
for (uint_fast64_t i = lastsource + 1; i < rewardMatrixInformation->nondeterministicChoiceIndices->size() - 1; ++i) {
choices += ((*rewardMatrixInformation->nondeterministicChoiceIndices)[i + 1] - (*rewardMatrixInformation->nondeterministicChoiceIndices)[i]);
}
}
// Check if we encountered a state index that is bigger than all previously seen.
if (source > result.highestStateIndex) {
result.highestStateIndex = source;
}
return nonzero;
}
if (isRewardFile) {
// If we have switched the source state, we possibly need to insert rows for skipped choices of the last
// source state.
if (source != lastsource) {
// number of choices skipped = number of choices of last state - number of choices read
result.choices += ((*rewardMatrixInformation.nondeterministicChoiceIndices)[lastsource + 1] - (*rewardMatrixInformation.nondeterministicChoiceIndices)[lastsource]) - (lastchoice + 1);
}
// If we skipped some states, we need to reserve empty rows for all their nondeterministic
// choices.
for (uint_fast64_t i = lastsource + 1; i < source; ++i) {
result.choices += ((*rewardMatrixInformation.nondeterministicChoiceIndices)[i + 1] - (*rewardMatrixInformation.nondeterministicChoiceIndices)[i]);
}
// If we advanced to the next state, but skipped some choices, we have to reserve rows
// for them.
if (source != lastsource) {
result.choices += choice + 1;
} else if (choice != lastchoice) {
result.choices += choice - lastchoice;
}
} else {
// If we have skipped some states, we need to reserve the space for the self-loop insertion
// in the second pass.
if (source > lastsource + 1) {
result.numberOfNonzeroEntries += source - lastsource - 1;
result.choices += source - lastsource - 1;
} else if (source != lastsource || choice != lastchoice) {
// If we have switched the source state or the nondeterministic choice, we need to
// reserve one row more.
++result.choices;
}
}
// Read target and check if we encountered a state index that is bigger than all previously
// seen.
target = checked_strtol(buf, &buf);
if (target > result.highestStateIndex) {
result.highestStateIndex = target;
}
/*!
* Reads a .tra file and produces a sparse matrix representing the described Markov Chain.
*
* Matrices created with this method have to be freed with the delete operator.
* @param filename input .tra file's name.
* @return a pointer to the created sparse matrix.
*/
// Read value and check whether it's positive.
val = checked_strtod(buf, &buf);
if ((val < 0.0) || (val > 1.0)) {
LOG4CPLUS_ERROR(logger, "Expected a positive probability but got \"" << std::string(buf, 0, 16) << "\".");
NondeterministicSparseTransitionParser::FirstPassResult nullResult;
return nullResult;
}
NondeterministicSparseTransitionParserResult_t NondeterministicSparseTransitionParser(std::string const &filename, RewardMatrixInformationStruct* rewardMatrixInformation) {
/*
* Enforce locale where decimal point is '.'.
*/
setlocale(LC_NUMERIC, "C");
if (!fileExistsAndIsReadable(filename.c_str())) {
LOG4CPLUS_ERROR(logger, "Error while parsing " << filename << ": File does not exist or is not readable.");
throw storm::exceptions::WrongFormatException();
}
bool isRewardFile = rewardMatrixInformation != nullptr;
/*
* Find out about the used line endings.
*/
SupportedLineEndingsEnum lineEndings = findUsedLineEndings(filename, true);
/*
* Open file.
*/
MappedFile file(filename.c_str());
char* buf = file.data;
/*
* Perform first pass, i.e. obtain number of columns, rows and non-zero elements.
*/
int_fast64_t maxnode;
uint_fast64_t choices;
uint_fast64_t nonzero = firstPass(file.data, lineEndings, choices, maxnode, rewardMatrixInformation);
/*
* If first pass returned zero, the file format was wrong.
*/
if (nonzero == 0) {
LOG4CPLUS_ERROR(logger, "Error while parsing " << filename << ": erroneous file format.");
throw storm::exceptions::WrongFormatException();
}
/*
* Perform second pass.
*
* From here on, we already know that the file header is correct.
*/
/*
* Skip file header.
*/
if (!isRewardFile) {
// skip format hint
buf = storm::parser::forwardToNextLine(buf, lineEndings);
}
if (isRewardFile) {
if (choices > rewardMatrixInformation->rowCount || (uint_fast64_t)(maxnode + 1) > rewardMatrixInformation->columnCount) {
LOG4CPLUS_ERROR(logger, "Reward matrix size exceeds transition matrix size.");
throw storm::exceptions::WrongFormatException() << "Reward matrix size exceeds transition matrix size.";
} else if (choices != rewardMatrixInformation->rowCount) {
LOG4CPLUS_ERROR(logger, "Reward matrix row count does not match transition matrix row count.");
throw storm::exceptions::WrongFormatException() << "Reward matrix row count does not match transition matrix row count.";
} else {
maxnode = rewardMatrixInformation->columnCount - 1;
}
}
/*
* Create and initialize matrix.
* The matrix should have as many columns as we have nodes and as many rows as we have choices.
* Those two values, as well as the number of nonzero elements, was been calculated in the first run.
*/
LOG4CPLUS_INFO(logger, "Attempting to create matrix of size " << choices << " x " << (maxnode+1) << " with " << nonzero << " entries.");
storm::storage::SparseMatrixBuilder<double> matrixBuilder(choices, maxnode + 1, nonzero);
/*
* Create row mapping.
*/
std::vector<uint_fast64_t> rowMapping(maxnode + 2, 0);
/*
* Parse file content.
*/
int_fast64_t source, target, lastsource = -1, choice, lastchoice = -1;
uint_fast64_t curRow = -1;
double val;
bool fixDeadlocks = storm::settings::Settings::getInstance()->isSet("fixDeadlocks");
bool hadDeadlocks = false;
/*
* Read all transitions from file.
*/
while (buf[0] != '\0') {
/*
* Read source state and choice.
*/
source = checked_strtol(buf, &buf);
choice = checked_strtol(buf, &buf);
if (isRewardFile) {
// If we have switched the source state, we possibly need to insert the rows of the last
// last source state.
if (source != lastsource && lastsource != -1) {
curRow += lastchoice - ((*rewardMatrixInformation->nondeterministicChoiceIndices)[lastsource + 1] - (*rewardMatrixInformation->nondeterministicChoiceIndices)[lastsource] - 1);
lastchoice = choice;
lastsource = source;
// Increase number of non-zero values.
result.numberOfNonzeroEntries++;
// The PRISM output format lists the name of the transition in the fourth column,
// but omits the fourth column if it is an internal action. In either case we can skip to the end of the line.
buf = forwardToLineEnd(buf, lineEndings);
buf = trimWhitespaces(buf);
}
// If we skipped some states, we need to reserve empty rows for all their nondeterministic
// choices.
for (int_fast64_t i = lastsource + 1; i < source; ++i) {
curRow += ((*rewardMatrixInformation->nondeterministicChoiceIndices)[i + 1] - (*rewardMatrixInformation->nondeterministicChoiceIndices)[i]);
if (isRewardFile) {
// If not all rows were filled for the last state, we need to insert them.
result.choices += ((*rewardMatrixInformation.nondeterministicChoiceIndices)[lastsource + 1] - (*rewardMatrixInformation.nondeterministicChoiceIndices)[lastsource] ) - (lastchoice + 1);
// If we skipped some states, we need to reserve empty rows for all their nondeterministic
// choices.
for (uint_fast64_t i = lastsource + 1; i < rewardMatrixInformation.nondeterministicChoiceIndices->size() - 1; ++i) {
result.choices += ((*rewardMatrixInformation.nondeterministicChoiceIndices)[i + 1] - (*rewardMatrixInformation.nondeterministicChoiceIndices)[i]);
}
}
// If we advanced to the next state, but skipped some choices, we have to reserve rows
// for them
if (source != lastsource) {
curRow += choice + 1;
} else if (choice != lastchoice) {
curRow += choice - lastchoice;
return result;
}
NondeterministicSparseTransitionParser::Result NondeterministicSparseTransitionParser::parse(std::string const &filename, bool isRewardFile, RewardMatrixInformationStruct const& rewardMatrixInformation) {
// Enforce locale where decimal point is '.'.
setlocale(LC_NUMERIC, "C");
if (!fileExistsAndIsReadable(filename.c_str())) {
LOG4CPLUS_ERROR(logger, "Error while parsing " << filename << ": File does not exist or is not readable.");
throw storm::exceptions::WrongFormatException();
}
} else {
// Increase line count if we have either finished reading the transitions of a certain state
// or we have finished reading one nondeterministic choice of a state.
if ((source != lastsource || choice != lastchoice)) {
++curRow;
// Find out about the used line endings.
SupportedLineEndingsEnum lineEndings = findUsedLineEndings(filename, true);
// Open file.
MappedFile file(filename.c_str());
char* buf = file.data;
// Perform first pass, i.e. obtain number of columns, rows and non-zero elements.
NondeterministicSparseTransitionParser::FirstPassResult firstPass = NondeterministicSparseTransitionParser::firstPass(file.data, lineEndings, isRewardFile, rewardMatrixInformation);
// If first pass returned zero, the file format was wrong.
if (firstPass.numberOfNonzeroEntries == 0) {
LOG4CPLUS_ERROR(logger, "Error while parsing " << filename << ": erroneous file format.");
throw storm::exceptions::WrongFormatException();
}
/*
* Check if we have skipped any source node, i.e. if any node has no
* outgoing transitions. If so, insert a self-loop.
* Also add self-loops to rowMapping.
*/
for (int_fast64_t node = lastsource + 1; node < source; node++) {
hadDeadlocks = true;
if (fixDeadlocks) {
rowMapping.at(node) = curRow;
matrixBuilder.addNextValue(curRow, node, 1);
++curRow;
LOG4CPLUS_WARN(logger, "Warning while parsing " << filename << ": node " << node << " has no outgoing transitions. A self-loop was inserted.");
// Perform second pass.
// Skip the format hint if it is there.
buf = trimWhitespaces(buf);
if(buf[0] < '0' || buf[0] > '9') {
buf = storm::parser::forwardToNextLine(buf, lineEndings);
}
if (isRewardFile) {
// The reward matrix should match the size of the transition matrix.
if (firstPass.choices > rewardMatrixInformation.rowCount || (uint_fast64_t)(firstPass.highestStateIndex + 1) > rewardMatrixInformation.columnCount) {
LOG4CPLUS_ERROR(logger, "Reward matrix size exceeds transition matrix size.");
throw storm::exceptions::WrongFormatException() << "Reward matrix size exceeds transition matrix size.";
} else if (firstPass.choices != rewardMatrixInformation.rowCount) {
LOG4CPLUS_ERROR(logger, "Reward matrix row count does not match transition matrix row count.");
throw storm::exceptions::WrongFormatException() << "Reward matrix row count does not match transition matrix row count.";
} else {
LOG4CPLUS_ERROR(logger, "Error while parsing " << filename << ": node " << node << " has no outgoing transitions.");
firstPass.highestStateIndex = rewardMatrixInformation.columnCount - 1;
}
}
if (source != lastsource) {
/*
* Add this source to rowMapping, if this is the first choice we encounter for this state.
*/
rowMapping.at(source) = curRow;
}
}
// Read target and value and write it to the matrix.
target = checked_strtol(buf, &buf);
val = checked_strtod(buf, &buf);
matrixBuilder.addNextValue(curRow, target, val);
lastsource = source;
lastchoice = choice;
// Create the matrix builder.
// The matrix to be build should have as many columns as we have nodes and as many rows as we have choices.
// Those two values, as well as the number of nonzero elements, was been calculated in the first run.
LOG4CPLUS_INFO(logger, "Attempting to create matrix of size " << firstPass.choices << " x " << (firstPass.highestStateIndex+1) << " with " << firstPass.numberOfNonzeroEntries << " entries.");
storm::storage::SparseMatrixBuilder<double> matrixBuilder(firstPass.choices, firstPass.highestStateIndex + 1, firstPass.numberOfNonzeroEntries);
// Create row mapping.
std::vector<uint_fast64_t> rowMapping(firstPass.highestStateIndex + 2, 0);
// Initialize variables for the parsing run.
uint_fast64_t source = 0, target = 0, lastsource = 0, choice = 0, lastchoice = 0, curRow = 0;
double val = 0.0;
bool fixDeadlocks = storm::settings::Settings::getInstance()->isSet("fixDeadlocks");
bool hadDeadlocks = false;
// Read all transitions from file.
while (buf[0] != '\0') {
// Read source state and choice.
source = checked_strtol(buf, &buf);
choice = checked_strtol(buf, &buf);
if (isRewardFile) {
// If we have switched the source state, we possibly need to insert the rows of the last
// source state.
if (source != lastsource) {
curRow += ((*rewardMatrixInformation.nondeterministicChoiceIndices)[lastsource + 1] - (*rewardMatrixInformation.nondeterministicChoiceIndices)[lastsource]) -(lastchoice + 1);
}
// If we skipped some states, we need to reserve empty rows for all their nondeterministic
// choices.
for (uint_fast64_t i = lastsource + 1; i < source; ++i) {
curRow += ((*rewardMatrixInformation.nondeterministicChoiceIndices)[i + 1] - (*rewardMatrixInformation.nondeterministicChoiceIndices)[i]);
}
// If we advanced to the next state, but skipped some choices, we have to reserve rows
// for them
if (source != lastsource) {
curRow += choice + 1;
} else if (choice != lastchoice) {
curRow += choice - lastchoice;
}
} else {
// Increase line count if we have either finished reading the transitions of a certain state
// or we have finished reading one nondeterministic choice of a state.
if ((source != lastsource || choice != lastchoice)) {
++curRow;
}
// Check if we have skipped any source node, i.e. if any node has no
// outgoing transitions. If so, insert a self-loop.
// Also add self-loops to rowMapping.
for (uint_fast64_t node = lastsource + 1; node < source; node++) {
hadDeadlocks = true;
if (fixDeadlocks) {
rowMapping.at(node) = curRow;
matrixBuilder.addNextValue(curRow, node, 1);
++curRow;
LOG4CPLUS_WARN(logger, "Warning while parsing " << filename << ": node " << node << " has no outgoing transitions. A self-loop was inserted.");
} else {
LOG4CPLUS_ERROR(logger, "Error while parsing " << filename << ": node " << node << " has no outgoing transitions.");
}
}
if (source != lastsource) {
// Add this source to rowMapping, if this is the first choice we encounter for this state.
rowMapping.at(source) = curRow;
}
}
/*
* Proceed to beginning of next line in file and next row in matrix.
*/
if (buf[0] == ' ') {
++buf;
}
switch (lineEndings) {
case SupportedLineEndingsEnum::SlashN:
buf += strcspn(buf, " \t\n");
break;
case SupportedLineEndingsEnum::SlashR:
buf += strcspn(buf, " \t\r");
break;
case SupportedLineEndingsEnum::SlashRN:
buf += strcspn(buf, " \t\r\n");
break;
default:
case storm::parser::SupportedLineEndingsEnum::Unsupported:
// This Line will never be reached as the Parser would have thrown already.
throw;
break;
}
buf = trimWhitespaces(buf);
}
// Read target and value and write it to the matrix.
target = checked_strtol(buf, &buf);
val = checked_strtod(buf, &buf);
matrixBuilder.addNextValue(curRow, target, val);
lastsource = source;
lastchoice = choice;
for (int_fast64_t node = lastsource + 1; node <= maxnode + 1; node++) {
rowMapping.at(node) = curRow + 1;
}
// Proceed to beginning of next line in file and next row in matrix.
buf = forwardToLineEnd(buf, lineEndings);
if (!fixDeadlocks && hadDeadlocks && !isRewardFile) throw storm::exceptions::WrongFormatException() << "Some of the nodes had deadlocks. You can use --fixDeadlocks to insert self-loops on the fly.";
buf = trimWhitespaces(buf);
}
return std::make_pair(matrixBuilder.build(), std::move(rowMapping));
}
for (uint_fast64_t node = lastsource + 1; node <= firstPass.highestStateIndex + 1; node++) {
rowMapping.at(node) = curRow + 1;
}
if (!fixDeadlocks && hadDeadlocks && !isRewardFile) throw storm::exceptions::WrongFormatException() << "Some of the nodes had deadlocks. You can use --fixDeadlocks to insert self-loops on the fly.";
return NondeterministicSparseTransitionParser::Result(matrixBuilder.build(), rowMapping);
}
} // namespace parser
} // namespace parser
} // namespace storm

113
src/parser/NondeterministicSparseTransitionParser.h

@ -1,30 +1,101 @@
#ifndef STORM_PARSER_NONDETTRAPARSER_H_
#define STORM_PARSER_NONDETTRAPARSER_H_
#include "src/storage/SparseMatrix.h"
#ifndef STORM_PARSER_NONDETERMINISTICSPARSETRANSITIONPARSER_H_
#define STORM_PARSER_NONDETERMINISTICSPARSETRANSITIONPARSER_H_
#include "src/parser/Parser.h"
#include "src/utility/OsDetection.h"
#include "src/storage/SparseMatrix.h"
#include <utility>
#include <memory>
#include <vector>
namespace storm {
namespace parser {
namespace parser {
class NondeterministicSparseTransitionParser {
public:
/*
* A structure representing the result of the first pass of this parser.
* It contains the number of non-zero entries in the model, the highest state index and the total number if nondeterministic choices.
*/
struct FirstPassResult {
FirstPassResult() : numberOfNonzeroEntries(0), highestStateIndex(0), choices(0) {
// Intentionally left empty.
}
// The total number of non-zero entries of the model.
uint_fast64_t numberOfNonzeroEntries;
// The highest state index that appears in the model.
uint_fast64_t highestStateIndex;
// The total number of nondeterministic choices within the transition system.
uint_fast64_t choices;
};
/*!
* A structure representing the result of the parser.
* It contains the resulting matrix as well as the row mapping.
*/
struct Result {
Result(storm::storage::SparseMatrix<double> transitionMatrix, std::vector<uint_fast64_t> rowMapping) : transitionMatrix(transitionMatrix), rowMapping(rowMapping) {
// Intentionally left empty.
}
// The matrix containing the parsed transition system.
storm::storage::SparseMatrix<double> transitionMatrix;
// A mapping from rows of the matrix to states of the model.
// This resolves the nondeterministic choices inside the transition system.
std::vector<uint_fast64_t> rowMapping;
};
/*!
* @brief Load a nondeterministic transition system from file and create a
* sparse adjacency matrix whose entries represent the weights of the edges
*/
static Result parseNondeterministicTransitions(std::string const &filename);
/*!
* @brief Load a nondeterministic transition system from file and create a
* sparse adjacency matrix whose entries represent the weights of the edges
*/
static Result parseNondeterministicTransitionRewards(std::string const &filename, RewardMatrixInformationStruct const& rewardMatrixInformation);
private:
/*!
* This method does the first pass through the buffer containing the content of some transition file.
*
* It computes the overall number of nondeterministic choices, i.e. the
* number of rows in the matrix that should be created.
* It also calculates the overall number of non-zero cells, i.e. the number
* of elements the matrix has to hold, and the maximum node id, i.e. the
* number of columns of the matrix.
*
* @param buffer Buffer containing the data to scan. This is expected to be some char array.
* @param lineEndings The line endings that are to be used while parsing.
* @param insertDiagonalEntriesIfMissing A flag set iff entries on the primary diagonal of the matrix should be added in case they are missing in the parsed file.
* @return A structure representing the result of the first pass.
*/
static FirstPassResult firstPass(char* buffer, SupportedLineEndingsEnum lineEndings, bool isRewardFile, RewardMatrixInformationStruct const& rewardMatrixInformation);
/*!
* The main parsing routine.
* Opens the given file, calls the first pass and performs the second pass, parsing the content of the file into a SparseMatrix.
*
* @param filename The path of file to be parsed.
* @param rewardFile A flag set iff the file to be parsed contains transition rewards.
* @param insertDiagonalEntriesIfMissing A flag set iff entries on the primary diagonal of the matrix should be added in case they are missing in the parsed file.
* @param rewardMatrixInformation A struct containing information that is used to check if the transition reward matrix fits to the rest of the model.
* @return A SparseMatrix containing the parsed file contents.
*/
static Result parse(std::string const& filename, bool isRewardFile, RewardMatrixInformationStruct const& rewardMatrixInformation);
};
/*!
* @brief Contains the Result of a call to the NondeterministicSparseTransitionParser function. The first part is the resulting matrix. The second part is the row mapping.
*/
typedef std::pair<storm::storage::SparseMatrix<double>, std::vector<uint_fast64_t>> NondeterministicSparseTransitionParserResult_t;
/*!
* @brief Load a nondeterministic transition system from file and create a
* sparse adjacency matrix whose entries represent the weights of the edges
*/
NondeterministicSparseTransitionParserResult_t NondeterministicSparseTransitionParser(std::string const &filename, RewardMatrixInformationStruct* rewardMatrixInformation = nullptr);
} // namespace parser
} // namespace parser
} // namespace storm
#endif /* STORM_PARSER_NONDETTRAPARSER_H_ */
#endif /* STORM_PARSER_NONDETERMINISTICSPARSETRANSITIONPARSER_H__H_ */

23
src/parser/Parser.cpp

@ -117,6 +117,29 @@ SupportedLineEndingsEnum findUsedLineEndings(std::string const& fileName, bool t
return SupportedLineEndingsEnum::Unsupported;
}
/*!
* @brief Encapsulates the usage of function @strcspn to forward to the end of the line (next char is the newline character).
*/
char* forwardToLineEnd(char* buffer, SupportedLineEndingsEnum lineEndings) {
switch (lineEndings) {
case SupportedLineEndingsEnum::SlashN:
return buffer + strcspn(buffer, "\n\0");
break;
case SupportedLineEndingsEnum::SlashR:
return buffer + strcspn(buffer, "\r\0");
break;
case SupportedLineEndingsEnum::SlashRN:
return buffer + strcspn(buffer, "\r\0");
break;
default:
case SupportedLineEndingsEnum::Unsupported:
// This Line will never be reached as the Parser would have thrown already.
throw;
break;
}
return nullptr;
}
/*!
* @brief Encapsulates the usage of function @strchr to forward to the next line
*/

5
src/parser/Parser.h

@ -146,6 +146,11 @@ enum class SupportedLineEndingsEnum : unsigned short {
*/
storm::parser::SupportedLineEndingsEnum findUsedLineEndings(std::string const& fileName, bool throwOnUnsupported = false);
/*!
* @brief Encapsulates the usage of function @strcspn to forward to the end of the line (next char is the newline character).
*/
char* forwardToLineEnd(char* buffer, storm::parser::SupportedLineEndingsEnum lineEndings);
/*!
* @brief Encapsulates the usage of function @strchr to forward to the next line
*/

Loading…
Cancel
Save