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.
230 lines
12 KiB
230 lines
12 KiB
#include "storm/parser/DeterministicSparseTransitionParser.h"
|
|
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <cstdint>
|
|
#include <clocale>
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
#include "storm/utility/constants.h"
|
|
#include "storm/utility/cstring.h"
|
|
#include "storm/parser/MappedFile.h"
|
|
#include "storm/exceptions/FileIoException.h"
|
|
#include "storm/exceptions/WrongFormatException.h"
|
|
#include "storm/exceptions/InvalidArgumentException.h"
|
|
#include "storm/settings/SettingsManager.h"
|
|
#include "storm/settings/modules/CoreSettings.h"
|
|
|
|
#include "storm/adapters/CarlAdapter.h"
|
|
#include "storm/utility/macros.h"
|
|
namespace storm {
|
|
namespace parser {
|
|
|
|
using namespace storm::utility::cstring;
|
|
|
|
template<typename ValueType>
|
|
storm::storage::SparseMatrix<ValueType> DeterministicSparseTransitionParser<ValueType>::parseDeterministicTransitions(std::string const& filename) {
|
|
storm::storage::SparseMatrix<ValueType> emptyMatrix;
|
|
return DeterministicSparseTransitionParser<ValueType>::parse(filename, false, emptyMatrix);
|
|
}
|
|
|
|
template<typename ValueType>
|
|
template<typename MatrixValueType>
|
|
storm::storage::SparseMatrix<ValueType> DeterministicSparseTransitionParser<ValueType>::parseDeterministicTransitionRewards(std::string const& filename, storm::storage::SparseMatrix<MatrixValueType> const& transitionMatrix) {
|
|
return DeterministicSparseTransitionParser<ValueType>::parse(filename, true, transitionMatrix);
|
|
}
|
|
|
|
template<typename ValueType>
|
|
template<typename MatrixValueType>
|
|
storm::storage::SparseMatrix<ValueType> DeterministicSparseTransitionParser<ValueType>::parse(std::string const& filename, bool isRewardFile, storm::storage::SparseMatrix<MatrixValueType> const& transitionMatrix) {
|
|
// Enforce locale where decimal point is '.'.
|
|
setlocale(LC_NUMERIC, "C");
|
|
|
|
// Open file.
|
|
MappedFile file(filename.c_str());
|
|
char const* buf = file.getData();
|
|
|
|
// Perform first pass, i.e. count entries that are not zero.
|
|
DeterministicSparseTransitionParser<ValueType>::FirstPassResult firstPass = DeterministicSparseTransitionParser<ValueType>::firstPass(file.getData());
|
|
|
|
STORM_LOG_TRACE("First pass on " << filename << " shows " << firstPass.numberOfNonzeroEntries << " non-zeros.");
|
|
|
|
// If first pass returned zero, the file format was wrong.
|
|
if (firstPass.numberOfNonzeroEntries == 0) {
|
|
STORM_LOG_ERROR("Error while parsing " << filename << ": empty or erroneous file format.");
|
|
throw storm::exceptions::WrongFormatException();
|
|
}
|
|
|
|
// Perform second pass.
|
|
|
|
// Skip the format hint if it is there.
|
|
buf = trimWhitespaces(buf);
|
|
if (buf[0] < '0' || buf[0] > '9') {
|
|
buf = forwardToLineEnd(buf);
|
|
buf = trimWhitespaces(buf);
|
|
}
|
|
|
|
if (isRewardFile) {
|
|
// The reward matrix should match the size of the transition matrix.
|
|
if (firstPass.highestStateIndex + 1 > transitionMatrix.getRowCount() || firstPass.highestStateIndex + 1 > transitionMatrix.getColumnCount()) {
|
|
STORM_LOG_ERROR("Reward matrix has more rows or columns than transition matrix.");
|
|
throw storm::exceptions::WrongFormatException() << "Reward matrix has more rows or columns than transition matrix.";
|
|
} else {
|
|
// If we found the right number of states or less, we set it to the number of states represented by the transition matrix.
|
|
firstPass.highestStateIndex = transitionMatrix.getRowCount() - 1;
|
|
}
|
|
}
|
|
|
|
// Creating matrix builder here.
|
|
// The actual matrix will be build once all contents are inserted.
|
|
storm::storage::SparseMatrixBuilder<ValueType> resultMatrix(firstPass.highestStateIndex + 1, firstPass.highestStateIndex + 1, firstPass.numberOfNonzeroEntries);
|
|
|
|
uint_fast64_t row, col, lastRow = 0;
|
|
double val;
|
|
bool dontFixDeadlocks = storm::settings::getModule<storm::settings::modules::CoreSettings>().isDontFixDeadlocksSet();
|
|
bool hadDeadlocks = false;
|
|
|
|
// Read all transitions from file. Note that we assume that the
|
|
// transitions are listed in canonical order, otherwise this will not
|
|
// work, i.e. the values in the matrix will be at wrong places.
|
|
|
|
// Different parsing routines for transition systems and transition rewards.
|
|
if (isRewardFile) {
|
|
while (buf[0] != '\0') {
|
|
|
|
// Read next transition.
|
|
row = checked_strtol(buf, &buf);
|
|
col = checked_strtol(buf, &buf);
|
|
val = checked_strtod(buf, &buf);
|
|
|
|
resultMatrix.addNextValue(row, col, val);
|
|
buf = trimWhitespaces(buf);
|
|
}
|
|
} else {
|
|
// Read first row and add self-loops if necessary.
|
|
char const* tmp;
|
|
row = checked_strtol(buf, &tmp);
|
|
|
|
if (row > 0) {
|
|
for (uint_fast64_t skippedRow = 0; skippedRow < row; ++skippedRow) {
|
|
hadDeadlocks = true;
|
|
if (!dontFixDeadlocks) {
|
|
resultMatrix.addNextValue(skippedRow, skippedRow, storm::utility::one<ValueType>());
|
|
STORM_LOG_WARN("Warning while parsing " << filename << ": state " << skippedRow << " has no outgoing transitions. A self-loop was inserted.");
|
|
} else {
|
|
STORM_LOG_ERROR("Error while parsing " << filename << ": state " << skippedRow << " has no outgoing transitions.");
|
|
// Before throwing the appropriate exception we will give notice of all deadlock states.
|
|
}
|
|
}
|
|
}
|
|
|
|
while (buf[0] != '\0') {
|
|
|
|
// Read next transition.
|
|
row = checked_strtol(buf, &buf);
|
|
col = checked_strtol(buf, &buf);
|
|
val = checked_strtod(buf, &buf);
|
|
|
|
// Test if we moved to a new row.
|
|
// Handle all incomplete or skipped rows.
|
|
if (lastRow != row) {
|
|
for (uint_fast64_t skippedRow = lastRow + 1; skippedRow < row; ++skippedRow) {
|
|
hadDeadlocks = true;
|
|
if (!dontFixDeadlocks) {
|
|
resultMatrix.addNextValue(skippedRow, skippedRow, storm::utility::one<ValueType>());
|
|
STORM_LOG_WARN("Warning while parsing " << filename << ": state " << skippedRow << " has no outgoing transitions. A self-loop was inserted.");
|
|
} else {
|
|
STORM_LOG_ERROR("Error while parsing " << filename << ": state " << skippedRow << " has no outgoing transitions.");
|
|
// Before throwing the appropriate exception we will give notice of all deadlock states.
|
|
}
|
|
}
|
|
lastRow = row;
|
|
}
|
|
|
|
resultMatrix.addNextValue(row, col, val);
|
|
buf = trimWhitespaces(buf);
|
|
}
|
|
|
|
// If we encountered deadlock and did not fix them, now is the time to throw the exception.
|
|
if (dontFixDeadlocks && hadDeadlocks) throw storm::exceptions::WrongFormatException() << "Some of the states do not have outgoing transitions.";
|
|
}
|
|
|
|
// Finally, build the actual matrix, test and return it.
|
|
storm::storage::SparseMatrix<ValueType> result = resultMatrix.build();
|
|
|
|
// Since we cannot check if each transition for which there is a reward in the reward file also exists in the transition matrix during parsing, we have to do it afterwards.
|
|
if (isRewardFile && !result.isSubmatrixOf(transitionMatrix)) {
|
|
STORM_LOG_ERROR("There are rewards for non existent transitions given in the reward file.");
|
|
throw storm::exceptions::WrongFormatException() << "There are rewards for non existent transitions given in the reward file.";
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
template<typename ValueType>
|
|
typename DeterministicSparseTransitionParser<ValueType>::FirstPassResult DeterministicSparseTransitionParser<ValueType>::firstPass(char const* buf) {
|
|
|
|
DeterministicSparseTransitionParser<ValueType>::FirstPassResult result;
|
|
|
|
// Skip the format hint if it is there.
|
|
buf = trimWhitespaces(buf);
|
|
if (buf[0] < '0' || buf[0] > '9') {
|
|
buf = forwardToLineEnd(buf);
|
|
buf = trimWhitespaces(buf);
|
|
}
|
|
|
|
// Check all transitions for non-zero diagonal entries and deadlock states.
|
|
uint_fast64_t row, col, lastRow = 0, lastCol = -1;
|
|
bool rowHadDiagonalEntry = false;
|
|
|
|
// Read first row and reserve space for self-loops if necessary.
|
|
char const* tmp;
|
|
row = checked_strtol(buf, &tmp);
|
|
if (row > 0) {
|
|
for (uint_fast64_t skippedRow = 0; skippedRow < row; ++skippedRow) {
|
|
++result.numberOfNonzeroEntries;
|
|
}
|
|
}
|
|
|
|
while (buf[0] != '\0') {
|
|
|
|
// Read the transition.
|
|
row = checked_strtol(buf, &buf);
|
|
col = checked_strtol(buf, &buf);
|
|
// The actual read value is not needed here.
|
|
checked_strtod(buf, &buf);
|
|
|
|
// Check if a higher state id was found.
|
|
if (row > result.highestStateIndex) result.highestStateIndex = row;
|
|
if (col > result.highestStateIndex) result.highestStateIndex = col;
|
|
|
|
++result.numberOfNonzeroEntries;
|
|
|
|
// Have we already seen this transition?
|
|
if (row == lastRow && col == lastCol) {
|
|
STORM_LOG_ERROR("The same transition (" << row << ", " << col << ") is given twice.");
|
|
throw storm::exceptions::InvalidArgumentException() << "The same transition (" << row << ", " << col << ") is given twice.";
|
|
}
|
|
|
|
lastRow = row;
|
|
lastCol = col;
|
|
|
|
buf = trimWhitespaces(buf);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
template class DeterministicSparseTransitionParser<double>;
|
|
template storm::storage::SparseMatrix<double> DeterministicSparseTransitionParser<double>::parseDeterministicTransitionRewards(std::string const& filename, storm::storage::SparseMatrix<double> const& transitionMatrix);
|
|
template storm::storage::SparseMatrix<double> DeterministicSparseTransitionParser<double>::parse(std::string const& filename, bool isRewardFile, storm::storage::SparseMatrix<double> const& transitionMatrix);
|
|
|
|
#ifdef STORM_HAVE_CARL
|
|
template class DeterministicSparseTransitionParser<storm::Interval>;
|
|
|
|
template storm::storage::SparseMatrix<storm::Interval> DeterministicSparseTransitionParser<storm::Interval>::parseDeterministicTransitionRewards(std::string const& filename, storm::storage::SparseMatrix<double> const& transitionMatrix);
|
|
template storm::storage::SparseMatrix<storm::Interval> DeterministicSparseTransitionParser<storm::Interval>::parse(std::string const& filename, bool isRewardFile, storm::storage::SparseMatrix<double> const& transitionMatrix);
|
|
#endif
|
|
} // namespace parser
|
|
} // namespace storm
|