Browse Source

Merge branch 'master' into parametricSystems

Former-commit-id: 0c71b31069
main
sjunges 11 years ago
parent
commit
3387e288f8
  1. 3
      CMakeLists.txt
  2. 9
      resources/3rdparty/cudd-2.5.0/CMakeLists.txt
  3. 1
      resources/3rdparty/cudd-2.5.0/src/cudd/cudd.h
  4. 19
      resources/3rdparty/cudd-2.5.0/src/cudd/cuddExport.c
  5. 65
      resources/3rdparty/cudd-2.5.0/src/cudd/cuddSat.c
  6. 16
      resources/3rdparty/cudd-2.5.0/src/obj/cuddObj.cc
  7. 5
      resources/3rdparty/cudd-2.5.0/src/obj/cuddObj.hh
  8. 2
      resources/3rdparty/ltl2dstar-0.5.1/src/parsers/nba-parser-lbtt.lex.cpp
  9. 2
      resources/3rdparty/ltl2dstar-0.5.1/src/parsers/nba-parser-promela.lex.cpp
  10. 2
      src/modelchecker/prctl/SparseDtmcPrctlModelChecker.h
  11. 2
      src/modelchecker/prctl/SparseMdpPrctlModelChecker.h
  12. 2
      src/parser/PrctlParser.cpp
  13. 42
      src/parser/PrismParser.cpp
  14. 9
      src/parser/PrismParser.h
  15. 75
      src/storage/dd/CuddDd.cpp
  16. 68
      src/storage/dd/CuddDd.h
  17. 161
      src/storage/dd/CuddDdForwardIterator.cpp
  18. 130
      src/storage/dd/CuddDdForwardIterator.h
  19. 39
      src/storage/dd/CuddDdManager.cpp
  20. 21
      src/storage/dd/CuddDdManager.h
  21. 13
      src/storage/dd/DdForwardIterator.h
  22. 15
      src/storage/dd/DdMetaVariable.cpp
  23. 25
      src/storage/dd/DdMetaVariable.h
  24. 5
      src/storage/expressions/BinaryBooleanFunctionExpression.cpp
  25. 2
      src/storage/expressions/BinaryBooleanFunctionExpression.h
  26. 28
      src/storage/expressions/Expression.cpp
  27. 29
      src/storage/expressions/Expression.h
  28. 37
      src/storage/expressions/IdentifierSubstitutionVisitor.cpp
  29. 6
      src/storage/expressions/IdentifierSubstitutionVisitor.h
  30. 11
      src/storage/expressions/SimpleValuation.cpp
  31. 5
      src/storage/expressions/SimpleValuation.h
  32. 37
      src/storage/expressions/SubstitutionVisitor.cpp
  33. 6
      src/storage/expressions/SubstitutionVisitor.h
  34. 2
      src/storage/prism/Assignment.cpp
  35. 2
      src/storage/prism/BooleanVariable.cpp
  36. 2
      src/storage/prism/Command.cpp
  37. 5
      src/storage/prism/Constant.cpp
  38. 2
      src/storage/prism/Formula.cpp
  39. 2
      src/storage/prism/IntegerVariable.cpp
  40. 2
      src/storage/prism/Label.cpp
  41. 1
      src/storage/prism/LocatedInformation.h
  42. 4
      src/storage/prism/Program.cpp
  43. 2
      src/storage/prism/StateReward.cpp
  44. 2
      src/storage/prism/TransitionReward.cpp
  45. 2
      src/storage/prism/Update.cpp
  46. 2
      src/storage/prism/Variable.cpp
  47. 2
      test/functional/parser/PrismParserTest.cpp
  48. 60
      test/functional/parser/prism/coin2.nm
  49. 69
      test/functional/parser/prism/crowds5_5.pm
  50. 130
      test/functional/parser/prism/csma2_2.nm
  51. 24
      test/functional/parser/prism/die.pm
  52. 170
      test/functional/parser/prism/firewire.nm
  53. 96
      test/functional/parser/prism/leader3.nm
  54. 85
      test/functional/parser/prism/leader3_5.pm
  55. 40
      test/functional/parser/prism/two_dice.nm
  56. 219
      test/functional/parser/prism/wlan0_collide.nm
  57. 2
      test/functional/solver/GmmxxLinearEquationSolverTest.cpp
  58. 39
      test/functional/storage/CuddDdTest.cpp
  59. 9
      test/functional/storage/ExpressionTest.cpp

3
CMakeLists.txt

@ -129,6 +129,9 @@ elseif(MSVC)
# Windows.h breaks GMM in gmm_except.h because of its macro definition for min and max
add_definitions(/DNOMINMAX)
# since nobody cares at the moment
add_definitions(/wd4250)
if(ENABLE_Z3)
set(Z3_LIB_NAME "libz3")
endif()

9
resources/3rdparty/cudd-2.5.0/CMakeLists.txt

@ -25,5 +25,14 @@ if(MSVC)
add_definitions(/D_SCL_SECURE_NO_DEPRECATE /D_CRT_SECURE_NO_WARNINGS)
endif()
# Since we do not target Alphas, this symbol is always set
add_definitions(-DHAVE_IEEE_754)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
message(STATUS "CUDD: Targeting 64bit architecture")
add_definitions(-DSIZEOF_VOID_P=8)
add_definitions(-DSIZEOF_LONG=8)
endif()
# Add the library
add_library(cudd ${CUDD_SOURCES} ${CUDD_HEADERS} ${CUDD_HEADERS_CXX} ${CUDD_SOURCES_CXX})

1
resources/3rdparty/cudd-2.5.0/src/cudd/cudd.h

@ -964,6 +964,7 @@ extern DdNode * Cudd_Increasing (DdManager *dd, DdNode *f, int i);
extern int Cudd_EquivDC (DdManager *dd, DdNode *F, DdNode *G, DdNode *D);
extern int Cudd_bddLeqUnless (DdManager *dd, DdNode *f, DdNode *g, DdNode *D);
extern int Cudd_EqualSupNorm (DdManager *dd, DdNode *f, DdNode *g, CUDD_VALUE_TYPE tolerance, int pr);
extern int Cudd_EqualSupNormRel (DdManager *dd, DdNode *f, DdNode *g, CUDD_VALUE_TYPE tolerance, int pr);
extern DdNode * Cudd_bddMakePrime (DdManager *dd, DdNode *cube, DdNode *f);
extern DdNode * Cudd_bddMaximallyExpand(DdManager *dd, DdNode *lb, DdNode *ub, DdNode *f);
extern DdNode * Cudd_bddLargestPrimeUnate(DdManager *dd , DdNode *f, DdNode *phaseBdd);

19
resources/3rdparty/cudd-2.5.0/src/cudd/cuddExport.c

@ -502,9 +502,11 @@ Cudd_DumpDot(
scan = nodelist[j];
while (scan != NULL) {
if (st_is_member(visited,(char *) scan)) {
retval = fprintf(fp,"\"%p\";\n",
(void *) ((mask & (ptrint) scan) / sizeof(DdNode)));
if (retval == EOF) goto failure;
if (scan != Cudd_ReadZero(dd)) {
retval = fprintf(fp,"\"%p\";\n",
(void *) ((mask & (ptrint) scan) / sizeof(DdNode)));
if (retval == EOF) goto failure;
}
}
scan = scan->next;
}
@ -541,6 +543,12 @@ Cudd_DumpDot(
scan = nodelist[j];
while (scan != NULL) {
if (st_is_member(visited,(char *) scan)) {
retval = fprintf(fp,
"\"%p\" [label = \"%s\"];\n",
(void *) ((mask & (ptrint) scan) /
sizeof(DdNode)), inames[dd->invperm[i]]);
if (retval == EOF) goto failure;
if (cuddT(scan) != Cudd_ReadZero(dd)) {
retval = fprintf(fp,
"\"%p\" -> \"%p\";\n",
(void *) ((mask & (ptrint) scan) /
@ -548,6 +556,8 @@ Cudd_DumpDot(
(void *) ((mask & (ptrint) cuddT(scan)) /
sizeof(DdNode)));
if (retval == EOF) goto failure;
}
if (cuddE(scan) != Cudd_ReadZero(dd)) {
if (Cudd_IsComplement(cuddE(scan))) {
retval = fprintf(fp,
"\"%p\" -> \"%p\" [style = dotted];\n",
@ -565,6 +575,7 @@ Cudd_DumpDot(
}
if (retval == EOF) goto failure;
}
}
scan = scan->next;
}
}
@ -578,11 +589,13 @@ Cudd_DumpDot(
scan = nodelist[j];
while (scan != NULL) {
if (st_is_member(visited,(char *) scan)) {
if (scan != Cudd_ReadZero(dd)) {
retval = fprintf(fp,"\"%p\" [label = \"%g\"];\n",
(void *) ((mask & (ptrint) scan) / sizeof(DdNode)),
cuddV(scan));
if (retval == EOF) goto failure;
}
}
scan = scan->next;
}
}

65
resources/3rdparty/cudd-2.5.0/src/cudd/cuddSat.c

@ -853,6 +853,71 @@ Cudd_EqualSupNorm(
} /* end of Cudd_EqualSupNorm */
/**Function********************************************************************
Synopsis [Compares two ADDs for equality within tolerance.]
Description [Same as Cudd_EqualSupNorm but tests for max _relative_ difference
i.e. (f-g/f)<e instead of (f-g)<e ]
SideEffects [None]
SeeAlso []
******************************************************************************/
int
Cudd_EqualSupNormRel(
DdManager * dd /* manager */,
DdNode * f /* first ADD */,
DdNode * g /* second ADD */,
CUDD_VALUE_TYPE tolerance /* maximum allowed difference */,
int pr /* verbosity level */)
{
DdNode *fv, *fvn, *gv, *gvn, *r;
unsigned int topf, topg;
statLine(dd);
/* Check terminal cases. */
if (f == g) return(1);
if (Cudd_IsConstant(f) && Cudd_IsConstant(g)) {
if (ddAbs((cuddV(f) - cuddV(g))/cuddV(f)) < tolerance) {
return(1);
} else {
if (pr>0) {
(void) fprintf(dd->out,"Offending nodes:\n");
(void) fprintf(dd->out,
"f: address = %p\t value = %40.30f\n",
(void *) f, cuddV(f));
(void) fprintf(dd->out,
"g: address = %p\t value = %40.30f\n",
(void *) g, cuddV(g));
}
return(0);
}
}
/* We only insert the result in the cache if the comparison is
** successful. Therefore, if we hit we return 1. */
r = cuddCacheLookup2(dd,(DD_CTFP)Cudd_EqualSupNormRel,f,g);
if (r != NULL) {
return(1);
}
/* Compute the cofactors and solve the recursive subproblems. */
topf = cuddI(dd,f->index);
topg = cuddI(dd,g->index);
if (topf <= topg) {fv = cuddT(f); fvn = cuddE(f);} else {fv = fvn = f;}
if (topg <= topf) {gv = cuddT(g); gvn = cuddE(g);} else {gv = gvn = g;}
if (!Cudd_EqualSupNormRel(dd,fv,gv,tolerance,pr)) return(0);
if (!Cudd_EqualSupNormRel(dd,fvn,gvn,tolerance,pr)) return(0);
cuddCacheInsert2(dd,(DD_CTFP)Cudd_EqualSupNormRel,f,g,DD_ONE(dd));
return(1);
} /* end of Cudd_EqualSupNormRel */
/**Function********************************************************************

16
resources/3rdparty/cudd-2.5.0/src/obj/cuddObj.cc

@ -4747,6 +4747,16 @@ ADD::EqualSupNorm(
} // ADD::EqualSupNorm
bool
ADD::EqualSupNormRel(
const ADD& g,
CUDD_VALUE_TYPE tolerance,
int pr) const
{
DdManager *mgr = checkSameManager(g);
return Cudd_EqualSupNormRel(mgr, node, g.node, tolerance, pr) != 0;
} // ADD::EqualSupNormRel
BDD
BDD::MakePrime(
@ -5267,14 +5277,14 @@ ABDD::FirstCube(
int
NextCube(
ABDD::NextCube(
DdGen * gen,
int ** cube,
CUDD_VALUE_TYPE * value)
CUDD_VALUE_TYPE * value)
{
return Cudd_NextCube(gen, cube, value);
} // NextCube
} // ABDD::NextCube
BDD

5
resources/3rdparty/cudd-2.5.0/src/obj/cuddObj.hh

@ -192,6 +192,7 @@ public:
const;
int CountLeaves() const;
DdGen * FirstCube(int ** cube, CUDD_VALUE_TYPE * value) const;
static int NextCube(DdGen * gen, int ** cube, CUDD_VALUE_TYPE * value);
double Density(int nvars) const;
}; // ABDD
@ -426,8 +427,8 @@ public:
ADD TimesPlus(const ADD& B, std::vector<ADD> z) const;
ADD Triangle(const ADD& g, std::vector<ADD> z) const;
ADD Eval(int * inputs) const;
bool EqualSupNorm(const ADD& g, CUDD_VALUE_TYPE tolerance, int pr) const;
bool EqualSupNorm(const ADD& g, CUDD_VALUE_TYPE tolerance, int pr = 0) const;
bool EqualSupNormRel(const ADD& g, CUDD_VALUE_TYPE tolerance, int pr = 0) const;
}; // ADD

2
resources/3rdparty/ltl2dstar-0.5.1/src/parsers/nba-parser-lbtt.lex.cpp

@ -31,7 +31,7 @@
/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) || defined _WIN32
#include <inttypes.h>
typedef int8_t flex_int8_t;
typedef uint8_t flex_uint8_t;

2
resources/3rdparty/ltl2dstar-0.5.1/src/parsers/nba-parser-promela.lex.cpp

@ -31,7 +31,7 @@
/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) || defined _WIN32
#include <inttypes.h>
typedef int8_t flex_int8_t;
typedef uint8_t flex_uint8_t;

2
src/modelchecker/prctl/SparseDtmcPrctlModelChecker.h

@ -393,7 +393,7 @@ public:
// Perform the actual matrix-vector multiplication as long as the bound of the formula is met.
if (linearEquationSolver != nullptr) {
this->linearEquationSolver->performMatrixVectorMultiplication(this->getModel().getTransitionMatrix(), result, &totalRewardVector, formula.getBound());
this->linearEquationSolver->performMatrixVectorMultiplication(this->getModel().getTransitionMatrix(), result, &totalRewardVector, static_cast<uint_fast64_t>(formula.getBound()));
} else {
throw storm::exceptions::InvalidStateException() << "No valid linear equation solver available.";
}

2
src/modelchecker/prctl/SparseMdpPrctlModelChecker.h

@ -410,7 +410,7 @@ namespace storm {
result.resize(this->getModel().getNumberOfStates());
}
this->nondeterministicLinearEquationSolver->performMatrixVectorMultiplication(this->minimumOperatorStack.top(), this->getModel().getTransitionMatrix(), result, &totalRewardVector, formula.getBound());
this->nondeterministicLinearEquationSolver->performMatrixVectorMultiplication(this->minimumOperatorStack.top(), this->getModel().getTransitionMatrix(), result, &totalRewardVector, static_cast<uint_fast64_t>(formula.getBound()));
return result;
}

2
src/parser/PrctlParser.cpp

@ -140,7 +140,7 @@ struct PrctlParser::PrctlGrammar : qi::grammar<Iterator, storm::property::prctl:
reachabilityReward = (qi::lit("F") > stateFormula)[qi::_val =
phoenix::new_<storm::property::prctl::ReachabilityReward<double>>(qi::_1)];
reachabilityReward.name("path formula (for reward operator)");
instantaneousReward = (qi::lit("I") > qi::lit("=") > qi::double_)
instantaneousReward = (qi::lit("I") > qi::lit("=") > qi::uint_)
[qi::_val = phoenix::new_<storm::property::prctl::InstantaneousReward<double>>(qi::_1)];
instantaneousReward.name("path formula (for reward operator)");
steadyStateReward = (qi::lit("S"))[qi::_val = phoenix::new_<storm::property::prctl::SteadyStateReward<double>>()];

42
src/parser/PrismParser.cpp

@ -88,13 +88,16 @@ namespace storm {
plusExpression = multiplicationExpression[qi::_val = qi::_1] >> *((qi::lit("+")[qi::_a = true] | qi::lit("-")[qi::_a = false]) >> multiplicationExpression)[phoenix::if_(qi::_a) [qi::_val = phoenix::bind(&PrismParser::createPlusExpression, phoenix::ref(*this), qi::_val, qi::_1)] .else_ [qi::_val = phoenix::bind(&PrismParser::createMinusExpression, phoenix::ref(*this), qi::_val, qi::_1)]];
plusExpression.name("plus expression");
relativeExpression = (plusExpression >> qi::lit(">=") >> plusExpression)[qi::_val = phoenix::bind(&PrismParser::createGreaterOrEqualExpression, phoenix::ref(*this), qi::_1, qi::_2)] | (plusExpression >> qi::lit(">") >> plusExpression)[qi::_val = phoenix::bind(&PrismParser::createGreaterExpression, phoenix::ref(*this), qi::_1, qi::_2)] | (plusExpression >> qi::lit("<=") >> plusExpression)[qi::_val = phoenix::bind(&PrismParser::createLessOrEqualExpression, phoenix::ref(*this), qi::_1, qi::_2)] | (plusExpression >> qi::lit("<") >> plusExpression)[qi::_val = phoenix::bind(&PrismParser::createLessExpression, phoenix::ref(*this), qi::_1, qi::_2)] | (plusExpression >> qi::lit("=") >> plusExpression)[qi::_val = phoenix::bind(&PrismParser::createEqualsExpression, phoenix::ref(*this), qi::_1, qi::_2)] | (plusExpression >> qi::lit("!=") >> plusExpression)[qi::_val = phoenix::bind(&PrismParser::createNotEqualsExpression, phoenix::ref(*this), qi::_1, qi::_2)] | plusExpression[qi::_val = qi::_1];
relativeExpression = (plusExpression >> qi::lit(">=") >> plusExpression)[qi::_val = phoenix::bind(&PrismParser::createGreaterOrEqualExpression, phoenix::ref(*this), qi::_1, qi::_2)] | (plusExpression >> qi::lit(">") >> plusExpression)[qi::_val = phoenix::bind(&PrismParser::createGreaterExpression, phoenix::ref(*this), qi::_1, qi::_2)] | (plusExpression >> qi::lit("<=") >> plusExpression)[qi::_val = phoenix::bind(&PrismParser::createLessOrEqualExpression, phoenix::ref(*this), qi::_1, qi::_2)] | (plusExpression >> qi::lit("<") >> plusExpression)[qi::_val = phoenix::bind(&PrismParser::createLessExpression, phoenix::ref(*this), qi::_1, qi::_2)] | plusExpression[qi::_val = qi::_1];
relativeExpression.name("relative expression");
andExpression = relativeExpression[qi::_val = qi::_1] >> *(qi::lit("&") >> relativeExpression)[qi::_val = phoenix::bind(&PrismParser::createAndExpression, phoenix::ref(*this), qi::_val, qi::_1)];
equalityExpression = relativeExpression[qi::_val = qi::_1] >> *((qi::lit("=")[qi::_a = true] | qi::lit("!=")[qi::_a = false]) >> relativeExpression)[phoenix::if_(qi::_a) [ qi::_val = phoenix::bind(&PrismParser::createEqualsExpression, phoenix::ref(*this), qi::_val, qi::_1) ] .else_ [ qi::_val = phoenix::bind(&PrismParser::createNotEqualsExpression, phoenix::ref(*this), qi::_val, qi::_1) ] ];
equalityExpression.name("equality expression");
andExpression = equalityExpression[qi::_val = qi::_1] >> *(qi::lit("&") >> equalityExpression)[qi::_val = phoenix::bind(&PrismParser::createAndExpression, phoenix::ref(*this), qi::_val, qi::_1)];
andExpression.name("and expression");
orExpression = andExpression[qi::_val = qi::_1] >> *(qi::lit("|") >> andExpression)[qi::_val = phoenix::bind(&PrismParser::createOrExpression, phoenix::ref(*this), qi::_val, qi::_1)];
orExpression = andExpression[qi::_val = qi::_1] >> *((qi::lit("|")[qi::_a = true] | qi::lit("=>")[qi::_a = false]) >> andExpression)[phoenix::if_(qi::_a) [qi::_val = phoenix::bind(&PrismParser::createOrExpression, phoenix::ref(*this), qi::_val, qi::_1)] .else_ [qi::_val = phoenix::bind(&PrismParser::createImpliesExpression, phoenix::ref(*this), qi::_val, qi::_1)] ];
orExpression.name("or expression");
iteExpression = orExpression[qi::_val = qi::_1] >> -(qi::lit("?") > orExpression > qi::lit(":") > orExpression)[qi::_val = phoenix::bind(&PrismParser::createIteExpression, phoenix::ref(*this), qi::_val, qi::_1, qi::_2)];
@ -204,6 +207,7 @@ namespace storm {
qi::on_error<qi::fail>(iteExpression, handler(qi::_1, qi::_2, qi::_3, qi::_4));
qi::on_error<qi::fail>(orExpression, handler(qi::_1, qi::_2, qi::_3, qi::_4));
qi::on_error<qi::fail>(andExpression, handler(qi::_1, qi::_2, qi::_3, qi::_4));
qi::on_error<qi::fail>(equalityExpression, handler(qi::_1, qi::_2, qi::_3, qi::_4));
qi::on_error<qi::fail>(relativeExpression, handler(qi::_1, qi::_2, qi::_3, qi::_4));
qi::on_error<qi::fail>(plusExpression, handler(qi::_1, qi::_2, qi::_3, qi::_4));
qi::on_error<qi::fail>(multiplicationExpression, handler(qi::_1, qi::_2, qi::_3, qi::_4));
@ -271,6 +275,14 @@ namespace storm {
}
}
storm::expressions::Expression PrismParser::createImpliesExpression(storm::expressions::Expression e1, storm::expressions::Expression e2) const {
if (!this->secondRun) {
return storm::expressions::Expression::createFalse();
} else {
return e1.implies(e2);
}
}
storm::expressions::Expression PrismParser::createOrExpression(storm::expressions::Expression e1, storm::expressions::Expression e2) const {
if (!this->secondRun) {
return storm::expressions::Expression::createFalse();
@ -323,7 +335,11 @@ namespace storm {
if (!this->secondRun) {
return storm::expressions::Expression::createFalse();
} else {
return e1 == e2;
if (e1.hasBooleanReturnType() && e2.hasBooleanReturnType()) {
return e1.iff(e2);
} else {
return e1 == e2;
}
}
}
@ -331,7 +347,11 @@ namespace storm {
if (!this->secondRun) {
return storm::expressions::Expression::createFalse();
} else {
return e1 != e2;
if (e1.hasBooleanReturnType() && e2.hasBooleanReturnType()) {
return e1 ^ e2;
} else {
return e1 != e2;
}
}
}
@ -585,7 +605,7 @@ namespace storm {
auto const& renamingPair = renaming.find(variable.getName());
LOG_THROW(renamingPair != renaming.end(), storm::exceptions::WrongFormatException, "Boolean variable '" << variable.getName() << " was not renamed.");
booleanVariables.push_back(storm::prism::BooleanVariable(renamingPair->second, variable.getInitialValueExpression().substitute<std::map>(expressionRenaming), this->getFilename(), get_line(qi::_1)));
booleanVariables.push_back(storm::prism::BooleanVariable(renamingPair->second, variable.getInitialValueExpression().substitute(expressionRenaming), this->getFilename(), get_line(qi::_1)));
}
// Rename the integer variables.
@ -594,7 +614,7 @@ namespace storm {
auto const& renamingPair = renaming.find(variable.getName());
LOG_THROW(renamingPair != renaming.end(), storm::exceptions::WrongFormatException, "Integer variable '" << variable.getName() << " was not renamed.");
integerVariables.push_back(storm::prism::IntegerVariable(renamingPair->second, variable.getLowerBoundExpression().substitute<std::map>(expressionRenaming), variable.getUpperBoundExpression().substitute<std::map>(expressionRenaming), variable.getInitialValueExpression().substitute<std::map>(expressionRenaming), this->getFilename(), get_line(qi::_1)));
integerVariables.push_back(storm::prism::IntegerVariable(renamingPair->second, variable.getLowerBoundExpression().substitute(expressionRenaming), variable.getUpperBoundExpression().substitute(expressionRenaming), variable.getInitialValueExpression().substitute(expressionRenaming), this->getFilename(), get_line(qi::_1)));
}
// Rename commands.
@ -606,12 +626,12 @@ namespace storm {
for (auto const& assignment : update.getAssignments()) {
auto const& renamingPair = renaming.find(assignment.getVariableName());
if (renamingPair != renaming.end()) {
assignments.emplace_back(renamingPair->second, assignment.getExpression().substitute<std::map>(expressionRenaming), this->getFilename(), get_line(qi::_1));
assignments.emplace_back(renamingPair->second, assignment.getExpression().substitute(expressionRenaming), this->getFilename(), get_line(qi::_1));
} else {
assignments.emplace_back(assignment.getVariableName(), assignment.getExpression().substitute<std::map>(expressionRenaming), this->getFilename(), get_line(qi::_1));
assignments.emplace_back(assignment.getVariableName(), assignment.getExpression().substitute(expressionRenaming), this->getFilename(), get_line(qi::_1));
}
}
updates.emplace_back(globalProgramInformation.currentUpdateIndex, update.getLikelihoodExpression().substitute<std::map>(expressionRenaming), assignments, this->getFilename(), get_line(qi::_1));
updates.emplace_back(globalProgramInformation.currentUpdateIndex, update.getLikelihoodExpression().substitute(expressionRenaming), assignments, this->getFilename(), get_line(qi::_1));
++globalProgramInformation.currentUpdateIndex;
}
@ -621,7 +641,7 @@ namespace storm {
newActionName = renamingPair->second;
}
commands.emplace_back(globalProgramInformation.currentCommandIndex, newActionName, command.getGuardExpression().substitute<std::map>(expressionRenaming), updates, this->getFilename(), get_line(qi::_1));
commands.emplace_back(globalProgramInformation.currentCommandIndex, newActionName, command.getGuardExpression().substitute(expressionRenaming), updates, this->getFilename(), get_line(qi::_1));
++globalProgramInformation.currentCommandIndex;
}

9
src/parser/PrismParser.h

@ -25,6 +25,7 @@ typedef BOOST_TYPEOF(qi::lit("//") >> *(qi::char_ - qi::eol) >> qi::eol | boost:
#include "src/storage/prism/Program.h"
#include "src/storage/expressions/Expression.h"
#include "src/storage/expressions/Expressions.h"
#include "src/exceptions/ExceptionMacros.h"
namespace storm {
@ -32,7 +33,7 @@ namespace storm {
class GlobalProgramInformation {
public:
// Default construct the header information.
GlobalProgramInformation() = default;
GlobalProgramInformation() : hasInitialStatesExpression(false), currentCommandIndex(0), currentUpdateIndex(0) {}
// Members for all essential information that needs to be collected.
storm::prism::Program::ModelType modelType;
@ -85,7 +86,7 @@ namespace storm {
}
};
struct keywordsStruct : qi::symbols<char, bool> {
struct keywordsStruct : qi::symbols<char, uint_fast64_t> {
keywordsStruct() {
add
("dtmc", 1)
@ -244,9 +245,10 @@ namespace storm {
// Rules for parsing a composed expression.
qi::rule<Iterator, storm::expressions::Expression(), Skipper> expression;
qi::rule<Iterator, storm::expressions::Expression(), Skipper> iteExpression;
qi::rule<Iterator, storm::expressions::Expression(), Skipper> orExpression;
qi::rule<Iterator, storm::expressions::Expression(), qi::locals<bool>, Skipper> orExpression;
qi::rule<Iterator, storm::expressions::Expression(), Skipper> andExpression;
qi::rule<Iterator, storm::expressions::Expression(), Skipper> relativeExpression;
qi::rule<Iterator, storm::expressions::Expression(), qi::locals<bool>, Skipper> equalityExpression;
qi::rule<Iterator, storm::expressions::Expression(), qi::locals<bool>, Skipper> plusExpression;
qi::rule<Iterator, storm::expressions::Expression(), qi::locals<bool>, Skipper> multiplicationExpression;
qi::rule<Iterator, storm::expressions::Expression(), Skipper> unaryExpression;
@ -269,6 +271,7 @@ namespace storm {
bool addInitialStatesExpression(storm::expressions::Expression initialStatesExpression, GlobalProgramInformation& globalProgramInformation);
storm::expressions::Expression createIteExpression(storm::expressions::Expression e1, storm::expressions::Expression e2, storm::expressions::Expression e3) const;
storm::expressions::Expression createImpliesExpression(storm::expressions::Expression e1, storm::expressions::Expression e2) const;
storm::expressions::Expression createOrExpression(storm::expressions::Expression e1, storm::expressions::Expression e2) const;
storm::expressions::Expression createAndExpression(storm::expressions::Expression e1, storm::expressions::Expression e2) const;
storm::expressions::Expression createGreaterExpression(storm::expressions::Expression e1, storm::expressions::Expression e2) const;

75
src/storage/dd/CuddDd.cpp

@ -1,3 +1,4 @@
#include <cstring>
#include <algorithm>
#include "src/storage/dd/CuddDd.h"
@ -19,6 +20,14 @@ namespace storm {
return this->cuddAdd != other.getCuddAdd();
}
Dd<DdType::CUDD> Dd<DdType::CUDD>::ite(Dd<DdType::CUDD> const& thenDd, Dd<DdType::CUDD> const& elseDd) const {
std::set<std::string> metaVariableNames(this->getContainedMetaVariableNames());
metaVariableNames.insert(thenDd.getContainedMetaVariableNames().begin(), thenDd.getContainedMetaVariableNames().end());
metaVariableNames.insert(elseDd.getContainedMetaVariableNames().begin(), elseDd.getContainedMetaVariableNames().end());
return Dd<DdType::CUDD>(this->getDdManager(), this->getCuddAdd().Ite(thenDd.getCuddAdd(), elseDd.getCuddAdd()));
}
Dd<DdType::CUDD> Dd<DdType::CUDD>::operator+(Dd<DdType::CUDD> const& other) const {
Dd<DdType::CUDD> result(*this);
result += other;
@ -55,6 +64,10 @@ namespace storm {
return result;
}
Dd<DdType::CUDD> Dd<DdType::CUDD>::operator-() const {
return this->getDdManager()->getZero() - *this;
}
Dd<DdType::CUDD>& Dd<DdType::CUDD>::operator-=(Dd<DdType::CUDD> const& other) {
this->cuddAdd -= other.getCuddAdd();
@ -79,11 +92,25 @@ namespace storm {
return *this;
}
Dd<DdType::CUDD> Dd<DdType::CUDD>::operator~() const {
Dd<DdType::CUDD> Dd<DdType::CUDD>::operator!() const {
Dd<DdType::CUDD> result(*this);
result.complement();
return result;
}
Dd<DdType::CUDD> Dd<DdType::CUDD>::operator&&(Dd<DdType::CUDD> const& other) const {
std::set<std::string> metaVariableNames(this->getContainedMetaVariableNames());
metaVariableNames.insert(other.getContainedMetaVariableNames().begin(), other.getContainedMetaVariableNames().end());
// Rewrite a and b to not((not a) or (not b)).
return Dd<DdType::CUDD>(this->getDdManager(), ~(~this->getCuddAdd()).Or(~other.getCuddAdd()), metaVariableNames);
}
Dd<DdType::CUDD> Dd<DdType::CUDD>::operator||(Dd<DdType::CUDD> const& other) const {
std::set<std::string> metaVariableNames(this->getContainedMetaVariableNames());
metaVariableNames.insert(other.getContainedMetaVariableNames().begin(), other.getContainedMetaVariableNames().end());
return Dd<DdType::CUDD>(this->getDdManager(), this->getCuddAdd().Or(other.getCuddAdd()), metaVariableNames);
}
Dd<DdType::CUDD>& Dd<DdType::CUDD>::complement() {
this->cuddAdd = ~this->cuddAdd;
@ -194,6 +221,14 @@ namespace storm {
this->cuddAdd = this->cuddAdd.MaxAbstract(cubeDd.getCuddAdd());
}
bool Dd<DdType::CUDD>::equalModuloPrecision(Dd<DdType::CUDD> const& other, double precision, bool relative) const {
if (relative) {
return this->getCuddAdd().EqualSupNormRel(other.getCuddAdd(), precision);
} else {
return this->getCuddAdd().EqualSupNorm(other.getCuddAdd(), precision);
}
}
void Dd<DdType::CUDD>::swapVariables(std::vector<std::pair<std::string, std::string>> const& metaVariablePairs) {
std::vector<ADD> from;
std::vector<ADD> to;
@ -230,7 +265,7 @@ namespace storm {
this->cuddAdd = this->cuddAdd.SwapVariables(from, to);
}
Dd<DdType::CUDD> Dd<DdType::CUDD>::multiplyMatrix(Dd<DdType::CUDD> const& otherMatrix, std::set<std::string> const& summationMetaVariableNames) {
Dd<DdType::CUDD> Dd<DdType::CUDD>::multiplyMatrix(Dd<DdType::CUDD> const& otherMatrix, std::set<std::string> const& summationMetaVariableNames) const {
std::vector<ADD> summationDdVariables;
// Create the CUDD summation variables.
@ -358,9 +393,32 @@ namespace storm {
if (filename.empty()) {
this->getDdManager()->getCuddManager().DumpDot(cuddAddVector);
} else {
// Build the name input of the DD.
std::vector<char*> ddNames;
std::string ddName("f");
ddNames.push_back(new char[ddName.size() + 1]);
std::copy(ddName.c_str(), ddName.c_str() + 2, ddNames.back());
// Now build the variables names.
std::vector<std::string> ddVariableNamesAsStrings = this->getDdManager()->getDdVariableNames();
std::vector<char*> ddVariableNames;
for (auto const& element : ddVariableNamesAsStrings) {
ddVariableNames.push_back(new char[element.size() + 1]);
std::copy(element.c_str(), element.c_str() + element.size() + 1, ddVariableNames.back());
}
// Open the file, dump the DD and close it again.
FILE* filePointer = fopen(filename.c_str() , "w");
this->getDdManager()->getCuddManager().DumpDot(cuddAddVector, nullptr, nullptr, filePointer);
this->getDdManager()->getCuddManager().DumpDot(cuddAddVector, &ddVariableNames[0], &ddNames[0], filePointer);
fclose(filePointer);
// Finally, delete the names.
for (char* element : ddNames) {
delete element;
}
for (char* element : ddVariableNames) {
delete element;
}
}
}
@ -384,6 +442,17 @@ namespace storm {
return this->ddManager;
}
DdForwardIterator<DdType::CUDD> Dd<DdType::CUDD>::begin() const {
int* cube;
double value;
DdGen* generator = this->getCuddAdd().FirstCube(&cube, &value);
return DdForwardIterator<DdType::CUDD>(this->getDdManager(), generator, cube, value, Cudd_IsGenEmpty(generator), &this->getContainedMetaVariableNames());
}
DdForwardIterator<DdType::CUDD> Dd<DdType::CUDD>::end() const {
return DdForwardIterator<DdType::CUDD>(this->getDdManager(), nullptr, nullptr, 0, true, nullptr);
}
std::ostream & operator<<(std::ostream& out, const Dd<DdType::CUDD>& dd) {
dd.exportToDot();
return out;

68
src/storage/dd/CuddDd.h

@ -7,6 +7,7 @@
#include <iostream>
#include "src/storage/dd/Dd.h"
#include "src/storage/dd/CuddDdForwardIterator.h"
#include "src/utility/OsDetection.h"
// Include the C++-interface of CUDD.
@ -20,8 +21,9 @@ namespace storm {
template<>
class Dd<DdType::CUDD> {
public:
// Declare the DdManager class as friend so it can access the internals of a DD.
// Declare the DdManager and DdIterator class as friend so it can access the internals of a DD.
friend class DdManager<DdType::CUDD>;
friend class DdForwardIterator<DdType::CUDD>;
// Instantiate all copy/move constructors/assignments with the default implementation.
Dd() = default;
@ -48,6 +50,27 @@ namespace storm {
*/
bool operator!=(Dd<DdType::CUDD> const& other) const;
/*!
* Performs an if-then-else with the given operands, i.e. maps all valuations that are mapped to a non-zero
* function value to the function values specified by the first DD and all others to the function values
* specified by the second DD.
*/
Dd<DdType::CUDD> ite(Dd<DdType::CUDD> const& thenDd, Dd<DdType::CUDD> const& elseDd) const;
/*!
* Performs a logical or of the current and the given DD.
*
* @return The logical or of the operands.
*/
Dd<DdType::CUDD> operator||(Dd<DdType::CUDD> const& other) const;
/*!
* Performs a logical and of the current and the given DD.
*
* @return The logical and of the operands.
*/
Dd<DdType::CUDD> operator&&(Dd<DdType::CUDD> const& other) const;
/*!
* Adds the two DDs.
*
@ -88,6 +111,13 @@ namespace storm {
*/
Dd<DdType::CUDD> operator-(Dd<DdType::CUDD> const& other) const;
/*!
* Subtracts the DD from the constant zero function.
*
* @return The resulting function represented as a DD.
*/
Dd<DdType::CUDD> operator-() const;
/*!
* Subtracts the given DD from the current one and assigns the result to the current DD.
*
@ -112,20 +142,13 @@ namespace storm {
*/
Dd<DdType::CUDD>& operator/=(Dd<DdType::CUDD> const& other);
/*!
* Subtracts the DD from the constant zero function.
*
* @return The resulting function represented as a DD.
*/
Dd<DdType::CUDD> minus() const;
/*!
* Retrieves the logical complement of the current DD. The result will map all encodings with a value
* unequal to zero to false and all others to true.
*
* @return The logical complement of the current DD.
*/
Dd<DdType::CUDD> operator~() const;
Dd<DdType::CUDD> operator!() const;
/*!
* Logically complements the current DD. The result will map all encodings with a value
@ -215,6 +238,17 @@ namespace storm {
*/
void maxAbstract(std::set<std::string> const& metaVariableNames);
/*!
* Checks whether the current and the given DD represent the same function modulo some given precision.
*
* @param other The DD with which to compare.
* @param precision An upper bound on the maximal difference between any two function values that is to be
* tolerated.
* @param relative If set to true, not the absolute values have to be within the precision, but the relative
* values.
*/
bool equalModuloPrecision(Dd<DdType::CUDD> const& other, double precision, bool relative = true) const;
/*!
* Swaps the given pairs of meta variables in the DD. The pairs of meta variables must be guaranteed to have
* the same number of underlying DD variables.
@ -232,7 +266,7 @@ namespace storm {
* matrix multiplication.
* @return A DD representing the result of the matrix-matrix multiplication.
*/
Dd<DdType::CUDD> multiplyMatrix(Dd<DdType::CUDD> const& otherMatrix, std::set<std::string> const& summationMetaVariableNames);
Dd<DdType::CUDD> multiplyMatrix(Dd<DdType::CUDD> const& otherMatrix, std::set<std::string> const& summationMetaVariableNames) const;
/*!
* Retrieves the number of encodings that are mapped to a non-zero value.
@ -380,6 +414,20 @@ namespace storm {
*/
std::shared_ptr<DdManager<DdType::CUDD>> getDdManager() const;
/*!
* Retrieves an iterator that points to the first meta variable assignment with a non-zero function value.
*
* @return An iterator that points to the first meta variable assignment with a non-zero function value.
*/
DdForwardIterator<DdType::CUDD> begin() const;
/*!
* Retrieves an iterator that points past the end of the container.
*
* @return An iterator that points past the end of the container.
*/
DdForwardIterator<DdType::CUDD> end() const;
friend std::ostream & operator<<(std::ostream& out, const Dd<DdType::CUDD>& dd);
private:
/*!

161
src/storage/dd/CuddDdForwardIterator.cpp

@ -0,0 +1,161 @@
#include "src/storage/dd/CuddDdForwardIterator.h"
#include "src/storage/dd/CuddDdManager.h"
#include "src/storage/dd/DdMetaVariable.h"
#include "src/exceptions/ExceptionMacros.h"
namespace storm {
namespace dd {
DdForwardIterator<DdType::CUDD>::DdForwardIterator(std::shared_ptr<DdManager<DdType::CUDD>> ddManager, DdGen* generator, int* cube, double value, bool isAtEnd, std::set<std::string> const* metaVariables) : ddManager(ddManager), generator(generator), cube(cube), value(value), isAtEnd(isAtEnd), metaVariables(metaVariables), cubeCounter(), relevantDontCareDdVariables(), currentValuation() {
// If the given generator is not yet at its end, we need to create the current valuation from the cube from
// scratch.
if (!this->isAtEnd) {
// Start by registering all meta variables in the valuation with the appropriate type.
for (auto const& metaVariableName : *this->metaVariables) {
auto const& metaVariable = this->ddManager->getMetaVariable(metaVariableName);
switch (metaVariable.getType()) {
case DdMetaVariable<DdType::CUDD>::MetaVariableType::Bool: currentValuation.addBooleanIdentifier(metaVariableName); break;
case DdMetaVariable<DdType::CUDD>::MetaVariableType::Int: currentValuation.addIntegerIdentifier(metaVariableName); break;
}
}
// And then get ready for treating the first cube.
this->treatNewCube();
}
}
DdForwardIterator<DdType::CUDD>::DdForwardIterator(DdForwardIterator<DdType::CUDD>&& other) : ddManager(other.ddManager), generator(other.generator), cube(other.cube), value(other.value), isAtEnd(other.isAtEnd), metaVariables(other.metaVariables), cubeCounter(other.cubeCounter), relevantDontCareDdVariables(other.relevantDontCareDdVariables), currentValuation(other.currentValuation) {
// Null-out the pointers of which we took possession.
other.cube = nullptr;
other.generator = nullptr;
}
DdForwardIterator<DdType::CUDD>& DdForwardIterator<DdType::CUDD>::operator=(DdForwardIterator<DdType::CUDD>&& other) {
if (this != &other) {
this->ddManager = other.ddManager;
this->generator = other.generator;
this->cube = other.cube;
this->value = other.value;
this->isAtEnd = other.isAtEnd;
this->metaVariables = other.metaVariables;
this->cubeCounter = other.cubeCounter;
this->relevantDontCareDdVariables = other.relevantDontCareDdVariables;
this->currentValuation = other.currentValuation;
// Null-out the pointers of which we took possession.
other.cube = nullptr;
other.generator = nullptr;
}
return *this;
}
DdForwardIterator<DdType::CUDD>::~DdForwardIterator() {
if (this->cube != nullptr) {
free(this->cube);
}
if (this->generator != nullptr) {
free(this->generator);
}
}
DdForwardIterator<DdType::CUDD>& DdForwardIterator<DdType::CUDD>::operator++() {
LOG_ASSERT(!this->isAtEnd, "Illegally incrementing iterator that is already at its end.");
// If there were no (relevant) don't cares or we have enumerated all combination, we need to eliminate the
// found solutions and get the next "first" cube.
if (this->relevantDontCareDdVariables.empty() || this->cubeCounter >= std::pow(2, this->relevantDontCareDdVariables.size()) - 1) {
// Get the next cube and check for emptiness.
ABDD::NextCube(generator, &cube, &value);
this->isAtEnd = Cudd_IsGenEmpty(generator);
// In case we are not done yet, we get ready to treat the next cube.
if (!this->isAtEnd) {
this->treatNewCube();
}
} else {
// Treat the next solution of the cube.
this->treatNextInCube();
}
return *this;
}
void DdForwardIterator<DdType::CUDD>::treatNextInCube() {
// Start by increasing the counter and check which bits we need to set/unset in the new valuation.
++this->cubeCounter;
for (uint_fast64_t index = 0; index < this->relevantDontCareDdVariables.size(); ++index) {
auto const& metaVariable = this->ddManager->getMetaVariable(std::get<1>(this->relevantDontCareDdVariables[index]));
if (metaVariable.getType() == DdMetaVariable<DdType::CUDD>::MetaVariableType::Bool) {
if ((this->cubeCounter & (1ull << index)) != 0) {
currentValuation.setBooleanValue(metaVariable.getName(), true);
} else {
currentValuation.setBooleanValue(metaVariable.getName(), false);
}
} else {
if ((this->cubeCounter & (1ull << index)) != 0) {
currentValuation.setIntegerValue(metaVariable.getName(), ((currentValuation.getIntegerValue(metaVariable.getName()) - metaVariable.getLow()) | (1ull << std::get<2>(this->relevantDontCareDdVariables[index]))) + metaVariable.getLow());
} else {
currentValuation.setIntegerValue(metaVariable.getName(), ((currentValuation.getIntegerValue(metaVariable.getName()) - metaVariable.getLow()) & ~(1ull << std::get<2>(this->relevantDontCareDdVariables[index]))) + metaVariable.getLow());
}
}
}
}
void DdForwardIterator<DdType::CUDD>::treatNewCube() {
this->relevantDontCareDdVariables.clear();
// Now loop through the bits of all meta variables and check whether they need to be set, not set or are
// don't cares. In the latter case, we add them to a special list, so we can iterate over their concrete
// valuations later.
for (auto const& metaVariableName : *this->metaVariables) {
auto const& metaVariable = this->ddManager->getMetaVariable(metaVariableName);
if (metaVariable.getType() == DdMetaVariable<DdType::CUDD>::MetaVariableType::Bool) {
if (this->cube[metaVariable.getDdVariables()[0].getCuddAdd().NodeReadIndex()] == 0) {
currentValuation.setBooleanValue(metaVariableName, false);
} else if (this->cube[metaVariable.getDdVariables()[0].getCuddAdd().NodeReadIndex()] == 1) {
currentValuation.setBooleanValue(metaVariableName, true);
} else {
relevantDontCareDdVariables.push_back(std::make_tuple(metaVariable.getDdVariables()[0].getCuddAdd(), metaVariableName, 0));
}
} else {
int_fast64_t intValue = 0;
for (uint_fast64_t bitIndex = 0; bitIndex < metaVariable.getNumberOfDdVariables(); ++bitIndex) {
if (cube[metaVariable.getDdVariables()[bitIndex].getCuddAdd().NodeReadIndex()] == 0) {
// Leave bit unset.
} else if (cube[metaVariable.getDdVariables()[bitIndex].getCuddAdd().NodeReadIndex()] == 1) {
intValue |= 1ull << (metaVariable.getNumberOfDdVariables() - bitIndex - 1);
} else {
// Temporarily leave bit unset so we can iterate trough the other option later.
// Add the bit to the relevant don't care bits.
this->relevantDontCareDdVariables.push_back(std::make_tuple(metaVariable.getDdVariables()[bitIndex].getCuddAdd(), metaVariableName, metaVariable.getNumberOfDdVariables() - bitIndex - 1));
}
}
currentValuation.setIntegerValue(metaVariableName, intValue + metaVariable.getLow());
}
}
// Finally, reset the cube counter.
this->cubeCounter = 0;
}
bool DdForwardIterator<DdType::CUDD>::operator==(DdForwardIterator<DdType::CUDD> const& other) const {
if (this->isAtEnd && other.isAtEnd) {
return true;
} else {
return this->ddManager.get() == other.ddManager.get() && this->generator == other.generator
&& this->cube == other.cube && this->value == other.value && this->isAtEnd == other.isAtEnd
&& this->metaVariables == other.metaVariables && this->cubeCounter == other.cubeCounter
&& this->relevantDontCareDdVariables == other.relevantDontCareDdVariables
&& this->currentValuation == other.currentValuation;
}
}
bool DdForwardIterator<DdType::CUDD>::operator!=(DdForwardIterator<DdType::CUDD> const& other) const {
return !(*this == other);
}
std::pair<storm::expressions::SimpleValuation, double> DdForwardIterator<DdType::CUDD>::operator*() const {
return std::make_pair(currentValuation, value);
}
}
}

130
src/storage/dd/CuddDdForwardIterator.h

@ -0,0 +1,130 @@
#ifndef STORM_STORAGE_DD_CUDDDDFORWARDITERATOR_H_
#define STORM_STORAGE_DD_CUDDDDFORWARDITERATOR_H_
#include <memory>
#include <cstdint>
#include <set>
#include <tuple>
#include <utility>
#include "src/storage/dd/DdForwardIterator.h"
#include "src/storage/expressions/SimpleValuation.h"
// Include the C++-interface of CUDD.
#include "cuddObj.hh"
namespace storm {
namespace dd {
// Forward-declare the DdManager class.
template<DdType Type> class DdManager;
template<DdType Type> class Dd;
template<>
class DdForwardIterator<DdType::CUDD> {
public:
friend class Dd<DdType::CUDD>;
// Default-instantiate the constructor.
DdForwardIterator() = default;
// Forbid copy-construction and copy assignment, because ownership of the internal pointer is unclear then.
DdForwardIterator(DdForwardIterator<DdType::CUDD> const& other) = delete;
DdForwardIterator& operator=(DdForwardIterator<DdType::CUDD> const& other) = delete;
// Provide move-construction and move-assignment, though.
DdForwardIterator(DdForwardIterator<DdType::CUDD>&& other);
DdForwardIterator& operator=(DdForwardIterator<DdType::CUDD>&& other);
/*!
* Destroys the forward iterator and frees the generator as well as the cube if they are not the nullptr.
*/
~DdForwardIterator();
/*!
* Moves the iterator one position forward.
*/
DdForwardIterator<DdType::CUDD>& operator++();
/*!
* Returns a pair consisting of a valuation of meta variables and the value to which this valuation is
* mapped. Note that the result is returned by value.
*
* @return A pair of a valuation and the function value.
*/
std::pair<storm::expressions::SimpleValuation, double> operator*() const;
/*!
* Compares the iterator with the given one. Two iterators are considered equal when all their underlying
* data members are the same or they both are at their end.
*
* @param other The iterator with which to compare.
* @return True if the two iterators are considered equal.
*/
bool operator==(DdForwardIterator<DdType::CUDD> const& other) const;
/*!
* Compares the iterator with the given one. Two iterators are considered unequal iff they are not
* considered equal.
*
* @param other The iterator with which to compare.
* @return True if the two iterators are considered unequal.
*/
bool operator!=(DdForwardIterator<DdType::CUDD> const& other) const;
private:
/*!
* Constructs a forward iterator using the given generator with the given set of relevant meta variables.
*
* @param ddManager The manager responsible for the DD over which to iterate.
* @param generator The generator used to enumerate the cubes of the DD.
* @param cube The cube as represented by CUDD.
* @param value The value the cube is mapped to.
* @param isAtEnd A flag that indicates whether the iterator is at its end and may not be moved forward any
* more.
* @param metaVariables The meta variables that appear in the DD.
*/
DdForwardIterator(std::shared_ptr<DdManager<DdType::CUDD>> ddManager, DdGen* generator, int* cube, double value, bool isAtEnd, std::set<std::string> const* metaVariables = nullptr);
/*!
* Recreates the internal information when a new cube needs to be treated.
*/
void treatNewCube();
/*!
* Updates the internal information when the next solution of the current cube needs to be treated.
*/
void treatNextInCube();
// The manager responsible for the meta variables (and therefore the underlying DD).
std::shared_ptr<DdManager<DdType::CUDD>> ddManager;
// The CUDD generator used to enumerate the cubes of the DD.
DdGen* generator;
// The currently considered cube of the DD.
int* cube;
// The function value of the current cube.
double value;
// A flag that indicates whether the iterator is at its end and may not be moved further. This is also used
// for the check against the end iterator.
bool isAtEnd;
// The set of meta variables appearing in the DD.
std::set<std::string> const* metaVariables;
// A number that represents how many assignments of the current cube have already been returned previously.
// This is needed, because cubes may represent many assignments (if they have don't care variables).
uint_fast64_t cubeCounter;
// A vector of tuples of the form <variable, metaVariableName, bitIndex>.
std::vector<std::tuple<ADD, std::string, uint_fast64_t>> relevantDontCareDdVariables;
// The current valuation of meta variables.
storm::expressions::SimpleValuation currentValuation;
};
}
}
#endif /* STORM_STORAGE_DD_CUDDDDFORWARDITERATOR_H_ */

39
src/storage/dd/CuddDdManager.cpp

@ -1,4 +1,5 @@
#include <cmath>
#include <string>
#include <algorithm>
#include "src/storage/dd/CuddDdManager.h"
@ -44,14 +45,14 @@ namespace storm {
if (value & (1ull << (ddVariables.size() - 1))) {
result = ddVariables[0];
} else {
result = ~ddVariables[0];
result = !ddVariables[0];
}
for (std::size_t i = 1; i < ddVariables.size(); ++i) {
if (value & (1ull << (ddVariables.size() - i - 1))) {
result *= ddVariables[i];
} else {
result *= ~ddVariables[i];
result *= !ddVariables[i];
}
}
@ -110,6 +111,18 @@ namespace storm {
metaVariableMap.emplace(name, DdMetaVariable<DdType::CUDD>(name, low, high, variables, this->shared_from_this()));
}
void DdManager<DdType::CUDD>::addMetaVariable(std::string const& name) {
// Check whether a meta variable already exists.
if (this->hasMetaVariable(name)) {
throw storm::exceptions::InvalidArgumentException() << "A meta variable '" << name << "' already exists.";
}
std::vector<Dd<DdType::CUDD>> variables;
variables.emplace_back(Dd<DdType::CUDD>(this->shared_from_this(), cuddManager.addVar(), {name}));
metaVariableMap.emplace(name, DdMetaVariable<DdType::CUDD>(name, variables, this->shared_from_this()));
}
void DdManager<DdType::CUDD>::addMetaVariablesInterleaved(std::vector<std::string> const& names, int_fast64_t low, int_fast64_t high) {
// Make sure that at least one meta variable is added.
if (names.size() == 0) {
@ -179,5 +192,27 @@ namespace storm {
Cudd& DdManager<DdType::CUDD>::getCuddManager() {
return this->cuddManager;
}
std::vector<std::string> DdManager<DdType::CUDD>::getDdVariableNames() const {
// First, we initialize a list DD variables and their names.
std::vector<std::pair<ADD, std::string>> variableNamePairs;
for (auto const& nameMetaVariablePair : this->metaVariableMap) {
DdMetaVariable<DdType::CUDD> const& metaVariable = nameMetaVariablePair.second;
for (uint_fast64_t variableIndex = 0; variableIndex < metaVariable.getNumberOfDdVariables(); ++variableIndex) {
variableNamePairs.emplace_back(metaVariable.getDdVariables()[variableIndex].getCuddAdd(), metaVariable.getName() + "." + std::to_string(variableIndex));
}
}
// Then, we sort this list according to the indices of the ADDs.
std::sort(variableNamePairs.begin(), variableNamePairs.end(), [](std::pair<ADD, std::string> const& a, std::pair<ADD, std::string> const& b) { return a.first.NodeReadIndex() < b.first.NodeReadIndex(); });
// Now, we project the sorted vector to its second component.
std::vector<std::string> result;
for (auto const& element : variableNamePairs) {
result.push_back(element.second);
}
return result;
}
}
}

21
src/storage/dd/CuddDdManager.h

@ -5,7 +5,6 @@
#include "src/storage/dd/DdManager.h"
#include "src/storage/dd/DdMetaVariable.h"
#include "src/storage/dd/CuddDd.h"
#include "src/utility/OsDetection.h"
// Include the C++-interface of CUDD.
@ -16,7 +15,6 @@ namespace storm {
template<>
class DdManager<DdType::CUDD> : public std::enable_shared_from_this<DdManager<DdType::CUDD>> {
public:
// To break the cylic dependencies, we need to forward-declare the other DD-related classes.
friend class Dd<DdType::CUDD>;
/*!
@ -83,7 +81,7 @@ namespace storm {
Dd<DdType::CUDD> getIdentity(std::string const& metaVariableName);
/*!
* Adds a meta variable with the given name and range.
* Adds an integer meta variable with the given name and range.
*
* @param name The name of the meta variable.
* @param low The lowest value of the range of the variable.
@ -92,7 +90,15 @@ namespace storm {
void addMetaVariable(std::string const& name, int_fast64_t low, int_fast64_t high);
/*!
* Adds meta variables with the given names and (equal) range and arranges the DD variables in an interleaved order.
* Adds a boolean meta variable with the given name.
*
* @param name The name of the meta variable.
*/
void addMetaVariable(std::string const& name);
/*!
* Adds integer meta variables with the given names and (equal) range and arranges the DD variables in an
* interleaved order.
*
* @param names The names of the variables.
* @param low The lowest value of the ranges of the variables.
@ -131,6 +137,13 @@ namespace storm {
bool hasMetaVariable(std::string const& metaVariableName) const;
private:
/*!
* Retrieves a list of names of the DD variables in the order of their index.
*
* @return A list of DD variable names.
*/
std::vector<std::string> getDdVariableNames() const;
/*!
* Retrieves the underlying CUDD manager.
*

13
src/storage/dd/DdForwardIterator.h

@ -0,0 +1,13 @@
#ifndef STORM_STORAGE_DD_DDFORWARDITERATOR_H_
#define STORM_STORAGE_DD_DDFORWARDITERATOR_H_
#include "src/storage/dd/DdType.h"
namespace storm {
namespace dd {
// Declare DdIterator class so we can then specialize it for the different DD types.
template<DdType Type> class DdForwardIterator;
}
}
#endif /* STORM_STORAGE_DD_DDFORWARDITERATOR_H_ */

15
src/storage/dd/DdMetaVariable.cpp

@ -4,7 +4,15 @@
namespace storm {
namespace dd {
template<DdType Type>
DdMetaVariable<Type>::DdMetaVariable(std::string const& name, int_fast64_t low, int_fast64_t high, std::vector<Dd<Type>> const& ddVariables, std::shared_ptr<DdManager<Type>> manager) : name(name), low(low), high(high), ddVariables(ddVariables), cube(manager->getOne()), manager(manager) {
DdMetaVariable<Type>::DdMetaVariable(std::string const& name, int_fast64_t low, int_fast64_t high, std::vector<Dd<Type>> const& ddVariables, std::shared_ptr<DdManager<Type>> manager) : name(name), type(MetaVariableType::Int), low(low), high(high), ddVariables(ddVariables), cube(manager->getOne()), manager(manager) {
// Create the cube of all variables of this meta variable.
for (auto const& ddVariable : this->ddVariables) {
this->cube *= ddVariable;
}
}
template<DdType Type>
DdMetaVariable<Type>::DdMetaVariable(std::string const& name, std::vector<Dd<Type>> const& ddVariables, std::shared_ptr<DdManager<Type>> manager) : name(name), type(MetaVariableType::Bool), ddVariables(ddVariables), cube(manager->getOne()), manager(manager) {
// Create the cube of all variables of this meta variable.
for (auto const& ddVariable : this->ddVariables) {
this->cube *= ddVariable;
@ -16,6 +24,11 @@ namespace storm {
return this->name;
}
template<DdType Type>
typename DdMetaVariable<Type>::MetaVariableType DdMetaVariable<Type>::getType() const {
return this->type;
}
template<DdType Type>
int_fast64_t DdMetaVariable<Type>::getLow() const {
return this->low;

25
src/storage/dd/DdMetaVariable.h

@ -8,6 +8,7 @@
#include "utility/OsDetection.h"
#include "src/storage/dd/CuddDd.h"
#include "src/storage/expressions/Expression.h"
namespace storm {
namespace dd {
@ -20,9 +21,13 @@ namespace storm {
// Declare the DdManager class as friend so it can access the internals of a meta variable.
friend class DdManager<Type>;
friend class Dd<Type>;
friend class DdForwardIterator<Type>;
// An enumeration for all legal types of meta variables.
enum class MetaVariableType { Bool, Int };
/*!
* Creates a meta variable with the given name, range bounds.
* Creates an integer meta variable with the given name and range bounds.
*
* @param name The name of the meta variable.
* @param low The lowest value of the range of the variable.
@ -32,6 +37,14 @@ namespace storm {
*/
DdMetaVariable(std::string const& name, int_fast64_t low, int_fast64_t high, std::vector<Dd<Type>> const& ddVariables, std::shared_ptr<DdManager<Type>> manager);
/*!
* Creates a boolean meta variable with the given name.
* @param name The name of the meta variable.
* @param ddVariables The vector of variables used to encode this variable.
* @param manager A pointer to the manager that is responsible for this meta variable.
*/
DdMetaVariable(std::string const& name, std::vector<Dd<Type>> const& ddVariables, std::shared_ptr<DdManager<Type>> manager);
// Explictly generate all default versions of copy/move constructors/assignments.
DdMetaVariable(DdMetaVariable const& other) = default;
DdMetaVariable& operator=(DdMetaVariable const& other) = default;
@ -47,6 +60,13 @@ namespace storm {
*/
std::string const& getName() const;
/*!
* Retrieves the type of the meta variable.
*
* @return The type of the meta variable.
*/
MetaVariableType getType() const;
/*!
* Retrieves the lowest value of the range of the variable.
*
@ -93,6 +113,9 @@ namespace storm {
// The name of the meta variable.
std::string name;
// The type of the variable.
MetaVariableType type;
// The lowest value of the range of the variable.
int_fast64_t low;

5
src/storage/expressions/BinaryBooleanFunctionExpression.cpp

@ -23,6 +23,7 @@ namespace storm {
switch (this->getOperatorType()) {
case OperatorType::And: result = firstOperandEvaluation && secondOperandEvaluation; break;
case OperatorType::Or: result = firstOperandEvaluation || secondOperandEvaluation; break;
case OperatorType::Xor: result = firstOperandEvaluation ^ secondOperandEvaluation; break;
case OperatorType::Implies: result = !firstOperandEvaluation || secondOperandEvaluation; break;
case OperatorType::Iff: result = (firstOperandEvaluation && secondOperandEvaluation) || (!firstOperandEvaluation && !secondOperandEvaluation); break;
}
@ -55,6 +56,7 @@ namespace storm {
return firstOperandSimplified;
}
break;
case OperatorType::Xor: break;
case OperatorType::Implies: if (firstOperandSimplified->isTrue()) {
return secondOperandSimplified;
} else if (firstOperandSimplified->isFalse()) {
@ -88,8 +90,9 @@ namespace storm {
switch (this->getOperatorType()) {
case OperatorType::And: stream << " & "; break;
case OperatorType::Or: stream << " | "; break;
case OperatorType::Xor: stream << " != "; break;
case OperatorType::Implies: stream << " => "; break;
case OperatorType::Iff: stream << " <=> "; break;
case OperatorType::Iff: stream << " = "; break;
}
stream << *this->getSecondOperand() << ")";
}

2
src/storage/expressions/BinaryBooleanFunctionExpression.h

@ -11,7 +11,7 @@ namespace storm {
/*!
* An enum type specifying the different operators applicable.
*/
enum class OperatorType {And, Or, Implies, Iff};
enum class OperatorType {And, Or, Xor, Implies, Iff};
/*!
* Creates a binary boolean function expression with the given return type, operands and operator.

28
src/storage/expressions/Expression.cpp

@ -27,15 +27,21 @@ namespace storm {
// Intentionally left empty.
}
template<template<typename... Arguments> class MapType>
Expression Expression::substitute(MapType<std::string, Expression> const& identifierToExpressionMap) const {
return SubstitutionVisitor<MapType>(identifierToExpressionMap).substitute(this->getBaseExpressionPointer().get());
Expression Expression::substitute(std::map<std::string, Expression> const& identifierToExpressionMap) const {
return SubstitutionVisitor< std::map<std::string, Expression> >(identifierToExpressionMap).substitute(this->getBaseExpressionPointer().get());
}
Expression Expression::substitute(std::unordered_map<std::string, Expression> const& identifierToExpressionMap) const {
return SubstitutionVisitor< std::unordered_map<std::string, Expression> >(identifierToExpressionMap).substitute(this->getBaseExpressionPointer().get());
}
template<template<typename... Arguments> class MapType>
Expression Expression::substitute(MapType<std::string, std::string> const& identifierToIdentifierMap) const {
return IdentifierSubstitutionVisitor<MapType>(identifierToIdentifierMap).substitute(this->getBaseExpressionPointer().get());
Expression Expression::substitute(std::map<std::string, std::string> const& identifierToIdentifierMap) const {
return IdentifierSubstitutionVisitor< std::map<std::string, std::string> >(identifierToIdentifierMap).substitute(this->getBaseExpressionPointer().get());
}
Expression Expression::substitute(std::unordered_map<std::string, std::string> const& identifierToIdentifierMap) const {
return IdentifierSubstitutionVisitor< std::unordered_map<std::string, std::string> >(identifierToIdentifierMap).substitute(this->getBaseExpressionPointer().get());
}
bool Expression::evaluateAsBool(Valuation const* valuation) const {
return this->getBaseExpression().evaluateAsBool(valuation);
@ -166,6 +172,11 @@ namespace storm {
return Expression(std::shared_ptr<BaseExpression>(new BinaryNumericalFunctionExpression(this->getReturnType() == ExpressionReturnType::Int && other.getReturnType() == ExpressionReturnType::Int ? ExpressionReturnType::Int : ExpressionReturnType::Double, this->getBaseExpressionPointer(), other.getBaseExpressionPointer(), BinaryNumericalFunctionExpression::OperatorType::Divide)));
}
Expression Expression::operator^(Expression const& other) const {
LOG_THROW(this->hasBooleanReturnType() && other.hasBooleanReturnType(), storm::exceptions::InvalidTypeException, "Operator '^' requires boolean operands.");
return Expression(std::shared_ptr<BaseExpression>(new BinaryBooleanFunctionExpression(ExpressionReturnType::Bool, this->getBaseExpressionPointer(), other.getBaseExpressionPointer(), BinaryBooleanFunctionExpression::OperatorType::Xor)));
}
Expression Expression::operator&&(Expression const& other) const {
LOG_THROW(this->hasBooleanReturnType() && other.hasBooleanReturnType(), storm::exceptions::InvalidTypeException, "Operator '&&' requires boolean operands.");
return Expression(std::shared_ptr<BaseExpression>(new BinaryBooleanFunctionExpression(ExpressionReturnType::Bool, this->getBaseExpressionPointer(), other.getBaseExpressionPointer(), BinaryBooleanFunctionExpression::OperatorType::And)));
@ -247,11 +258,6 @@ namespace storm {
return Expression(std::shared_ptr<BaseExpression>(new UnaryNumericalFunctionExpression(ExpressionReturnType::Int, this->getBaseExpressionPointer(), UnaryNumericalFunctionExpression::OperatorType::Ceil)));
}
template Expression Expression::substitute<std::map>(std::map<std::string, storm::expressions::Expression> const&) const;
template Expression Expression::substitute<std::unordered_map>(std::unordered_map<std::string, storm::expressions::Expression> const&) const;
template Expression Expression::substitute<std::map>(std::map<std::string, std::string> const&) const;
template Expression Expression::substitute<std::unordered_map>(std::unordered_map<std::string, std::string> const&) const;
std::ostream& operator<<(std::ostream& stream, Expression const& expression) {
stream << expression.getBaseExpression();
return stream;

29
src/storage/expressions/Expression.h

@ -2,6 +2,8 @@
#define STORM_STORAGE_EXPRESSIONS_EXPRESSION_H_
#include <memory>
#include <map>
#include <unordered_map>
#include "src/storage/expressions/BaseExpression.h"
#include "src/utility/OsDetection.h"
@ -47,6 +49,7 @@ namespace storm {
Expression operator-() const;
Expression operator*(Expression const& other) const;
Expression operator/(Expression const& other) const;
Expression operator^(Expression const& other) const;
Expression operator&&(Expression const& other) const;
Expression operator||(Expression const& other) const;
Expression operator!() const;
@ -76,8 +79,18 @@ namespace storm {
* @return An expression in which all identifiers in the key set of the mapping are replaced by the
* expression they are mapped to.
*/
template<template<typename... Arguments> class MapType>
Expression substitute(MapType<std::string, Expression> const& identifierToExpressionMap) const;
Expression substitute(std::map<std::string, Expression> const& identifierToExpressionMap) const;
/*!
* Substitutes all occurrences of identifiers according to the given map. Note that this substitution is
* done simultaneously, i.e., identifiers appearing in the expressions that were "plugged in" are not
* substituted.
*
* @param identifierToExpressionMap A mapping from identifiers to the expression they are substituted with.
* @return An expression in which all identifiers in the key set of the mapping are replaced by the
* expression they are mapped to.
*/
Expression substitute(std::unordered_map<std::string, Expression> const& identifierToExpressionMap) const;
/*!
* Substitutes all occurrences of identifiers with different names given by a mapping.
@ -86,8 +99,16 @@ namespace storm {
* @return An expression in which all identifiers in the key set of the mapping are replaced by the
* identifiers they are mapped to.
*/
template<template<typename... Arguments> class MapType>
Expression substitute(MapType<std::string, std::string> const& identifierToIdentifierMap) const;
Expression substitute(std::map<std::string, std::string> const& identifierToIdentifierMap) const;
/*!
* Substitutes all occurrences of identifiers with different names given by a mapping.
*
* @param identifierToIdentifierMap A mapping from identifiers to identifiers they are substituted with.
* @return An expression in which all identifiers in the key set of the mapping are replaced by the
* identifiers they are mapped to.
*/
Expression substitute(std::unordered_map<std::string, std::string> const& identifierToIdentifierMap) const;
/*!
* Evaluates the expression under the valuation of unknowns (variables and constants) given by the

37
src/storage/expressions/IdentifierSubstitutionVisitor.cpp

@ -1,5 +1,6 @@
#include <map>
#include <unordered_map>
#include <string>
#include "src/storage/expressions/IdentifierSubstitutionVisitor.h"
@ -19,18 +20,18 @@
namespace storm {
namespace expressions {
template<template<typename... Arguments> class MapType>
IdentifierSubstitutionVisitor<MapType>::IdentifierSubstitutionVisitor(MapType<std::string, std::string> const& identifierToIdentifierMap) : identifierToIdentifierMap(identifierToIdentifierMap) {
template<typename MapType>
IdentifierSubstitutionVisitor<MapType>::IdentifierSubstitutionVisitor(MapType const& identifierToIdentifierMap) : identifierToIdentifierMap(identifierToIdentifierMap) {
// Intentionally left empty.
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
Expression IdentifierSubstitutionVisitor<MapType>::substitute(BaseExpression const* expression) {
expression->accept(this);
return Expression(this->expressionStack.top());
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void IdentifierSubstitutionVisitor<MapType>::visit(IfThenElseExpression const* expression) {
expression->getCondition()->accept(this);
std::shared_ptr<BaseExpression const> conditionExpression = expressionStack.top();
@ -52,7 +53,7 @@ namespace storm {
}
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void IdentifierSubstitutionVisitor<MapType>::visit(BinaryBooleanFunctionExpression const* expression) {
expression->getFirstOperand()->accept(this);
std::shared_ptr<BaseExpression const> firstExpression = expressionStack.top();
@ -70,7 +71,7 @@ namespace storm {
}
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void IdentifierSubstitutionVisitor<MapType>::visit(BinaryNumericalFunctionExpression const* expression) {
expression->getFirstOperand()->accept(this);
std::shared_ptr<BaseExpression const> firstExpression = expressionStack.top();
@ -88,7 +89,7 @@ namespace storm {
}
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void IdentifierSubstitutionVisitor<MapType>::visit(BinaryRelationExpression const* expression) {
expression->getFirstOperand()->accept(this);
std::shared_ptr<BaseExpression const> firstExpression = expressionStack.top();
@ -106,7 +107,7 @@ namespace storm {
}
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void IdentifierSubstitutionVisitor<MapType>::visit(BooleanConstantExpression const* expression) {
// If the boolean constant is in the key set of the substitution, we need to replace it.
auto const& namePair = this->identifierToIdentifierMap.find(expression->getConstantName());
@ -117,7 +118,7 @@ namespace storm {
}
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void IdentifierSubstitutionVisitor<MapType>::visit(DoubleConstantExpression const* expression) {
// If the double constant is in the key set of the substitution, we need to replace it.
auto const& namePair = this->identifierToIdentifierMap.find(expression->getConstantName());
@ -128,7 +129,7 @@ namespace storm {
}
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void IdentifierSubstitutionVisitor<MapType>::visit(IntegerConstantExpression const* expression) {
// If the integer constant is in the key set of the substitution, we need to replace it.
auto const& namePair = this->identifierToIdentifierMap.find(expression->getConstantName());
@ -139,7 +140,7 @@ namespace storm {
}
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void IdentifierSubstitutionVisitor<MapType>::visit(VariableExpression const* expression) {
// If the variable is in the key set of the substitution, we need to replace it.
auto const& namePair = this->identifierToIdentifierMap.find(expression->getVariableName());
@ -150,7 +151,7 @@ namespace storm {
}
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void IdentifierSubstitutionVisitor<MapType>::visit(UnaryBooleanFunctionExpression const* expression) {
expression->getOperand()->accept(this);
std::shared_ptr<BaseExpression const> operandExpression = expressionStack.top();
@ -164,7 +165,7 @@ namespace storm {
}
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void IdentifierSubstitutionVisitor<MapType>::visit(UnaryNumericalFunctionExpression const* expression) {
expression->getOperand()->accept(this);
std::shared_ptr<BaseExpression const> operandExpression = expressionStack.top();
@ -178,23 +179,23 @@ namespace storm {
}
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void IdentifierSubstitutionVisitor<MapType>::visit(BooleanLiteralExpression const* expression) {
this->expressionStack.push(expression->getSharedPointer());
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void IdentifierSubstitutionVisitor<MapType>::visit(IntegerLiteralExpression const* expression) {
this->expressionStack.push(expression->getSharedPointer());
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void IdentifierSubstitutionVisitor<MapType>::visit(DoubleLiteralExpression const* expression) {
this->expressionStack.push(expression->getSharedPointer());
}
// Explicitly instantiate the class with map and unordered_map.
template class IdentifierSubstitutionVisitor<std::map>;
template class IdentifierSubstitutionVisitor<std::unordered_map>;
template class IdentifierSubstitutionVisitor< std::map<std::string, std::string> >;
template class IdentifierSubstitutionVisitor< std::unordered_map<std::string, std::string> >;
}
}

6
src/storage/expressions/IdentifierSubstitutionVisitor.h

@ -8,7 +8,7 @@
namespace storm {
namespace expressions {
template<template<typename... Arguments> class MapType>
template<typename MapType>
class IdentifierSubstitutionVisitor : public ExpressionVisitor {
public:
/*!
@ -16,7 +16,7 @@ namespace storm {
*
* @param identifierToExpressionMap A mapping from identifiers to expressions.
*/
IdentifierSubstitutionVisitor(MapType<std::string, std::string> const& identifierToExpressionMap);
IdentifierSubstitutionVisitor(MapType const& identifierToExpressionMap);
/*!
* Substitutes the identifiers in the given expression according to the previously given map and returns the
@ -47,7 +47,7 @@ namespace storm {
std::stack<std::shared_ptr<BaseExpression const>> expressionStack;
// A mapping of identifier names to expressions with which they shall be replaced.
MapType<std::string, std::string> const& identifierToIdentifierMap;
MapType const& identifierToIdentifierMap;
};
}
}

11
src/storage/expressions/SimpleValuation.cpp

@ -1,6 +1,7 @@
#include "src/storage/expressions/SimpleValuation.h"
#include <boost/functional/hash.hpp>
#include "src/storage/expressions/SimpleValuation.h"
#include "src/exceptions/ExceptionMacros.h"
#include "src/exceptions/InvalidArgumentException.h"
namespace storm {
namespace expressions {
@ -13,16 +14,22 @@ namespace storm {
}
void SimpleValuation::addBooleanIdentifier(std::string const& name, bool initialValue) {
LOG_THROW(this->booleanIdentifierToIndexMap->find(name) == this->booleanIdentifierToIndexMap->end(), storm::exceptions::InvalidArgumentException, "Boolean identifier '" << name << "' already registered.");
this->booleanIdentifierToIndexMap->emplace(name, this->booleanValues.size());
this->booleanValues.push_back(initialValue);
}
void SimpleValuation::addIntegerIdentifier(std::string const& name, int_fast64_t initialValue) {
LOG_THROW(this->booleanIdentifierToIndexMap->find(name) == this->booleanIdentifierToIndexMap->end(), storm::exceptions::InvalidArgumentException, "Integer identifier '" << name << "' already registered.");
this->integerIdentifierToIndexMap->emplace(name, this->integerValues.size());
this->integerValues.push_back(initialValue);
}
void SimpleValuation::addDoubleIdentifier(std::string const& name, double initialValue) {
LOG_THROW(this->booleanIdentifierToIndexMap->find(name) == this->booleanIdentifierToIndexMap->end(), storm::exceptions::InvalidArgumentException, "Double identifier '" << name << "' already registered.");
this->doubleIdentifierToIndexMap->emplace(name, this->doubleValues.size());
this->doubleValues.push_back(initialValue);
}

5
src/storage/expressions/SimpleValuation.h

@ -7,6 +7,7 @@
#include <iostream>
#include "src/storage/expressions/Valuation.h"
#include "src/utility/OsDetection.h"
namespace storm {
namespace expressions {
@ -23,8 +24,10 @@ namespace storm {
// Instantiate some constructors and assignments with their default implementations.
SimpleValuation(SimpleValuation const&) = default;
SimpleValuation& operator=(SimpleValuation const&) = default;
SimpleValuation(SimpleValuation&&) = default;
#ifndef WINDOWS
SimpleValuation(SimpleValuation&&) = default;
SimpleValuation& operator=(SimpleValuation&&) = default;
#endif
virtual ~SimpleValuation() = default;
/*!

37
src/storage/expressions/SubstitutionVisitor.cpp

@ -1,5 +1,6 @@
#include <map>
#include <unordered_map>
#include <string>
#include "src/storage/expressions/SubstitutionVisitor.h"
@ -19,18 +20,18 @@
namespace storm {
namespace expressions {
template<template<typename... Arguments> class MapType>
SubstitutionVisitor<MapType>::SubstitutionVisitor(MapType<std::string, Expression> const& identifierToExpressionMap) : identifierToExpressionMap(identifierToExpressionMap) {
template<typename MapType>
SubstitutionVisitor<MapType>::SubstitutionVisitor(MapType const& identifierToExpressionMap) : identifierToExpressionMap(identifierToExpressionMap) {
// Intentionally left empty.
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
Expression SubstitutionVisitor<MapType>::substitute(BaseExpression const* expression) {
expression->accept(this);
return Expression(this->expressionStack.top());
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void SubstitutionVisitor<MapType>::visit(IfThenElseExpression const* expression) {
expression->getCondition()->accept(this);
std::shared_ptr<BaseExpression const> conditionExpression = expressionStack.top();
@ -52,7 +53,7 @@ namespace storm {
}
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void SubstitutionVisitor<MapType>::visit(BinaryBooleanFunctionExpression const* expression) {
expression->getFirstOperand()->accept(this);
std::shared_ptr<BaseExpression const> firstExpression = expressionStack.top();
@ -70,7 +71,7 @@ namespace storm {
}
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void SubstitutionVisitor<MapType>::visit(BinaryNumericalFunctionExpression const* expression) {
expression->getFirstOperand()->accept(this);
std::shared_ptr<BaseExpression const> firstExpression = expressionStack.top();
@ -88,7 +89,7 @@ namespace storm {
}
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void SubstitutionVisitor<MapType>::visit(BinaryRelationExpression const* expression) {
expression->getFirstOperand()->accept(this);
std::shared_ptr<BaseExpression const> firstExpression = expressionStack.top();
@ -106,7 +107,7 @@ namespace storm {
}
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void SubstitutionVisitor<MapType>::visit(BooleanConstantExpression const* expression) {
// If the boolean constant is in the key set of the substitution, we need to replace it.
auto const& nameExpressionPair = this->identifierToExpressionMap.find(expression->getConstantName());
@ -117,7 +118,7 @@ namespace storm {
}
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void SubstitutionVisitor<MapType>::visit(DoubleConstantExpression const* expression) {
// If the double constant is in the key set of the substitution, we need to replace it.
auto const& nameExpressionPair = this->identifierToExpressionMap.find(expression->getConstantName());
@ -128,7 +129,7 @@ namespace storm {
}
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void SubstitutionVisitor<MapType>::visit(IntegerConstantExpression const* expression) {
// If the integer constant is in the key set of the substitution, we need to replace it.
auto const& nameExpressionPair = this->identifierToExpressionMap.find(expression->getConstantName());
@ -139,7 +140,7 @@ namespace storm {
}
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void SubstitutionVisitor<MapType>::visit(VariableExpression const* expression) {
// If the variable is in the key set of the substitution, we need to replace it.
auto const& nameExpressionPair = this->identifierToExpressionMap.find(expression->getVariableName());
@ -150,7 +151,7 @@ namespace storm {
}
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void SubstitutionVisitor<MapType>::visit(UnaryBooleanFunctionExpression const* expression) {
expression->getOperand()->accept(this);
std::shared_ptr<BaseExpression const> operandExpression = expressionStack.top();
@ -164,7 +165,7 @@ namespace storm {
}
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void SubstitutionVisitor<MapType>::visit(UnaryNumericalFunctionExpression const* expression) {
expression->getOperand()->accept(this);
std::shared_ptr<BaseExpression const> operandExpression = expressionStack.top();
@ -178,23 +179,23 @@ namespace storm {
}
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void SubstitutionVisitor<MapType>::visit(BooleanLiteralExpression const* expression) {
this->expressionStack.push(expression->getSharedPointer());
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void SubstitutionVisitor<MapType>::visit(IntegerLiteralExpression const* expression) {
this->expressionStack.push(expression->getSharedPointer());
}
template<template<typename... Arguments> class MapType>
template<typename MapType>
void SubstitutionVisitor<MapType>::visit(DoubleLiteralExpression const* expression) {
this->expressionStack.push(expression->getSharedPointer());
}
// Explicitly instantiate the class with map and unordered_map.
template class SubstitutionVisitor<std::map>;
template class SubstitutionVisitor<std::unordered_map>;
template class SubstitutionVisitor< std::map<std::string, Expression> >;
template class SubstitutionVisitor< std::unordered_map<std::string, Expression> >;
}
}

6
src/storage/expressions/SubstitutionVisitor.h

@ -8,7 +8,7 @@
namespace storm {
namespace expressions {
template<template<typename... Arguments> class MapType>
template<typename MapType>
class SubstitutionVisitor : public ExpressionVisitor {
public:
/*!
@ -16,7 +16,7 @@ namespace storm {
*
* @param identifierToExpressionMap A mapping from identifiers to expressions.
*/
SubstitutionVisitor(MapType<std::string, Expression> const& identifierToExpressionMap);
SubstitutionVisitor(MapType const& identifierToExpressionMap);
/*!
* Substitutes the identifiers in the given expression according to the previously given map and returns the
@ -47,7 +47,7 @@ namespace storm {
std::stack<std::shared_ptr<BaseExpression const>> expressionStack;
// A mapping of identifier names to expressions with which they shall be replaced.
MapType<std::string, Expression> const& identifierToExpressionMap;
MapType const& identifierToExpressionMap;
};
}
}

2
src/storage/prism/Assignment.cpp

@ -15,7 +15,7 @@ namespace storm {
}
Assignment Assignment::substitute(std::map<std::string, storm::expressions::Expression> const& substitution) const {
return Assignment(this->getVariableName(), this->getExpression().substitute<std::map>(substitution), this->getFilename(), this->getLineNumber());
return Assignment(this->getVariableName(), this->getExpression().substitute(substitution), this->getFilename(), this->getLineNumber());
}
std::ostream& operator<<(std::ostream& stream, Assignment const& assignment) {

2
src/storage/prism/BooleanVariable.cpp

@ -11,7 +11,7 @@ namespace storm {
}
BooleanVariable BooleanVariable::substitute(std::map<std::string, storm::expressions::Expression> const& substitution) const {
return BooleanVariable(this->getName(), this->getInitialValueExpression().substitute<std::map>(substitution), this->getFilename(), this->getLineNumber());
return BooleanVariable(this->getName(), this->getInitialValueExpression().substitute(substitution), this->getFilename(), this->getLineNumber());
}
std::ostream& operator<<(std::ostream& stream, BooleanVariable const& variable) {

2
src/storage/prism/Command.cpp

@ -37,7 +37,7 @@ namespace storm {
newUpdates.emplace_back(update.substitute(substitution));
}
return Command(this->getGlobalIndex(), this->getActionName(), this->getGuardExpression().substitute<std::map>(substitution), newUpdates, this->getFilename(), this->getLineNumber());
return Command(this->getGlobalIndex(), this->getActionName(), this->getGuardExpression().substitute(substitution), newUpdates, this->getFilename(), this->getLineNumber());
}
std::ostream& operator<<(std::ostream& stream, Command const& command) {

5
src/storage/prism/Constant.cpp

@ -1,4 +1,6 @@
#include "src/storage/prism/Constant.h"
#include "src/exceptions/ExceptionMacros.h"
#include "src/exceptions/IllegalFunctionCallException.h"
namespace storm {
namespace prism {
@ -23,11 +25,12 @@ namespace storm {
}
storm::expressions::Expression const& Constant::getExpression() const {
LOG_THROW(this->isDefined(), storm::exceptions::IllegalFunctionCallException, "Unable to retrieve defining expression for undefined constant.");
return this->expression;
}
Constant Constant::substitute(std::map<std::string, storm::expressions::Expression> const& substitution) const {
return Constant(this->getType(), this->getName(), this->getExpression().substitute<std::map>(substitution), this->getFilename(), this->getLineNumber());
return Constant(this->getType(), this->getName(), this->getExpression().substitute(substitution), this->getFilename(), this->getLineNumber());
}
std::ostream& operator<<(std::ostream& stream, Constant const& constant) {

2
src/storage/prism/Formula.cpp

@ -19,7 +19,7 @@ namespace storm {
}
Formula Formula::substitute(std::map<std::string, storm::expressions::Expression> const& substitution) const {
return Formula(this->getName(), this->getExpression().substitute<std::map>(substitution), this->getFilename(), this->getLineNumber());
return Formula(this->getName(), this->getExpression().substitute(substitution), this->getFilename(), this->getLineNumber());
}
std::ostream& operator<<(std::ostream& stream, Formula const& formula) {

2
src/storage/prism/IntegerVariable.cpp

@ -19,7 +19,7 @@ namespace storm {
}
IntegerVariable IntegerVariable::substitute(std::map<std::string, storm::expressions::Expression> const& substitution) const {
return IntegerVariable(this->getName(), this->getLowerBoundExpression().substitute<std::map>(substitution), this->getUpperBoundExpression().substitute<std::map>(substitution), this->getInitialValueExpression().substitute<std::map>(substitution), this->getFilename(), this->getLineNumber());
return IntegerVariable(this->getName(), this->getLowerBoundExpression().substitute(substitution), this->getUpperBoundExpression().substitute(substitution), this->getInitialValueExpression().substitute(substitution), this->getFilename(), this->getLineNumber());
}
std::ostream& operator<<(std::ostream& stream, IntegerVariable const& variable) {

2
src/storage/prism/Label.cpp

@ -15,7 +15,7 @@ namespace storm {
}
Label Label::substitute(std::map<std::string, storm::expressions::Expression> const& substitution) const {
return Label(this->getName(), this->getStatePredicateExpression().substitute<std::map>(substitution), this->getFilename(), this->getLineNumber());
return Label(this->getName(), this->getStatePredicateExpression().substitute(substitution), this->getFilename(), this->getLineNumber());
}
std::ostream& operator<<(std::ostream& stream, Label const& label) {

1
src/storage/prism/LocatedInformation.h

@ -2,6 +2,7 @@
#define STORM_STORAGE_PRISM_LOCATEDINFORMATION_H_
#include <string>
#include <cstdint>
#include "src/utility/OsDetection.h"

4
src/storage/prism/Program.cpp

@ -229,7 +229,7 @@ namespace storm {
LOG_THROW(constantDefinitions.find(constant.getName()) == constantDefinitions.end(), storm::exceptions::InvalidArgumentException, "Illegally defining already defined constant '" << constant.getName() << "'.");
// Now replace the occurrences of undefined constants in its defining expression.
newConstants.emplace_back(constant.getType(), constant.getName(), constant.getExpression().substitute<std::map>(constantDefinitions), constant.getFilename(), constant.getLineNumber());
newConstants.emplace_back(constant.getType(), constant.getName(), constant.getExpression().substitute(constantDefinitions), constant.getFilename(), constant.getLineNumber());
} else {
auto const& variableExpressionPair = constantDefinitions.find(constant.getName());
@ -310,7 +310,7 @@ namespace storm {
newRewardModels.emplace_back(rewardModel.substitute(constantSubstitution));
}
storm::expressions::Expression newInitialStateExpression = this->getInitialStatesExpression().substitute<std::map>(constantSubstitution);
storm::expressions::Expression newInitialStateExpression = this->getInitialStatesExpression().substitute(constantSubstitution);
std::vector<Label> newLabels;
newLabels.reserve(this->getNumberOfLabels());

2
src/storage/prism/StateReward.cpp

@ -15,7 +15,7 @@ namespace storm {
}
StateReward StateReward::substitute(std::map<std::string, storm::expressions::Expression> const& substitution) const {
return StateReward(this->getStatePredicateExpression().substitute<std::map>(substitution), this->getRewardValueExpression().substitute<std::map>(substitution), this->getFilename(), this->getLineNumber());
return StateReward(this->getStatePredicateExpression().substitute(substitution), this->getRewardValueExpression().substitute(substitution), this->getFilename(), this->getLineNumber());
}
std::ostream& operator<<(std::ostream& stream, StateReward const& stateReward) {

2
src/storage/prism/TransitionReward.cpp

@ -19,7 +19,7 @@ namespace storm {
}
TransitionReward TransitionReward::substitute(std::map<std::string, storm::expressions::Expression> const& substitution) const {
return TransitionReward(this->getActionName(), this->getStatePredicateExpression().substitute<std::map>(substitution), this->getRewardValueExpression().substitute<std::map>(substitution), this->getFilename(), this->getLineNumber());
return TransitionReward(this->getActionName(), this->getStatePredicateExpression().substitute(substitution), this->getRewardValueExpression().substitute(substitution), this->getFilename(), this->getLineNumber());
}
std::ostream& operator<<(std::ostream& stream, TransitionReward const& transitionReward) {

2
src/storage/prism/Update.cpp

@ -44,7 +44,7 @@ namespace storm {
newAssignments.emplace_back(assignment.substitute(substitution));
}
return Update(this->getGlobalIndex(), this->getLikelihoodExpression().substitute<std::map>(substitution), newAssignments, this->getFilename(), this->getLineNumber());
return Update(this->getGlobalIndex(), this->getLikelihoodExpression().substitute(substitution), newAssignments, this->getFilename(), this->getLineNumber());
}
std::ostream& operator<<(std::ostream& stream, Update const& update) {

2
src/storage/prism/Variable.cpp

@ -8,7 +8,7 @@ namespace storm {
// Nothing to do here.
}
Variable::Variable(Variable const& oldVariable, std::string const& newName, std::map<std::string, std::string> const& renaming, std::string const& filename, uint_fast64_t lineNumber) : LocatedInformation(filename, lineNumber), name(newName), initialValueExpression(oldVariable.getInitialValueExpression().substitute<std::map>(renaming)), defaultInitialValue(oldVariable.hasDefaultInitialValue()) {
Variable::Variable(Variable const& oldVariable, std::string const& newName, std::map<std::string, std::string> const& renaming, std::string const& filename, uint_fast64_t lineNumber) : LocatedInformation(filename, lineNumber), name(newName), initialValueExpression(oldVariable.getInitialValueExpression().substitute(renaming)), defaultInitialValue(oldVariable.hasDefaultInitialValue()) {
// Intentionally left empty.
}

2
test/functional/parser/PrismParserTest.cpp

@ -47,7 +47,7 @@ TEST(PrismParser, SimpleFullTest) {
R"(dtmc
module mod1
b : bool;
[a] true -> 1: (b'=true);
[a] true -> 1: (b'=true != false = b => false);
endmodule)";
storm::prism::Program result;

60
test/functional/parser/prism/coin2.nm

@ -0,0 +1,60 @@
// COIN FLIPPING PROTOCOL FOR POLYNOMIAL RANDOMIZED CONSENSUS [AH90]
// gxn/dxp 20/11/00
mdp
// constants
const int N=2;
const int K;
const int range = 2*(K+1)*N;
const int counter_init = (K+1)*N;
const int left = N;
const int right = 2*(K+1)*N - N;
// shared coin
global counter : [0..range] init counter_init;
module process1
// program counter
pc1 : [0..3];
// 0 - flip
// 1 - write
// 2 - check
// 3 - finished
// local coin
coin1 : [0..1];
// flip coin
[] (pc1=0) -> 0.5 : (coin1'=0) & (pc1'=1) + 0.5 : (coin1'=1) & (pc1'=1);
// write tails -1 (reset coin to add regularity)
[] (pc1=1) & (coin1=0) & (counter>0) -> 1 : (counter'=counter-1) & (pc1'=2) & (coin1'=0);
// write heads +1 (reset coin to add regularity)
[] (pc1=1) & (coin1=1) & (counter<range) -> 1 : (counter'=counter+1) & (pc1'=2) & (coin1'=0);
// check
// decide tails
[] (pc1=2) & (counter<=left) -> 1 : (pc1'=3) & (coin1'=0);
// decide heads
[] (pc1=2) & (counter>=right) -> 1 : (pc1'=3) & (coin1'=1);
// flip again
[] (pc1=2) & (counter>left) & (counter<right) -> 1 : (pc1'=0);
// loop (all loop together when done)
[done] (pc1=3) -> 1 : (pc1'=3);
endmodule
// construct remaining processes through renaming
module process2 = process1[pc1=pc2,coin1=coin2] endmodule
// labels
label "finished" = pc1=3 & pc2=3 ;
label "all_coins_equal_0" = coin1=0 & coin2=0 ;
label "all_coins_equal_1" = coin1=1 & coin2=1 ;
label "agree" = coin1=coin2 ;
// rewards
rewards "steps"
true : 1;
endrewards

69
test/functional/parser/prism/crowds5_5.pm

@ -0,0 +1,69 @@
dtmc
// probability of forwarding
const double PF = 0.8;
const double notPF = .2; // must be 1-PF
// probability that a crowd member is bad
const double badC = .167;
// probability that a crowd member is good
const double goodC = 0.833;
// Total number of protocol runs to analyze
const int TotalRuns = 5;
// size of the crowd
const int CrowdSize = 5;
module crowds
// protocol phase
phase: [0..4] init 0;
// crowd member good (or bad)
good: bool init false;
// number of protocol runs
runCount: [0..TotalRuns] init 0;
// observe_i is the number of times the attacker observed crowd member i
observe0: [0..TotalRuns] init 0;
observe1: [0..TotalRuns] init 0;
observe2: [0..TotalRuns] init 0;
observe3: [0..TotalRuns] init 0;
observe4: [0..TotalRuns] init 0;
// the last seen crowd member
lastSeen: [0..CrowdSize - 1] init 0;
// get the protocol started
[] phase=0 & runCount<TotalRuns -> 1: (phase'=1) & (runCount'=runCount+1) & (lastSeen'=0);
// decide whether crowd member is good or bad according to given probabilities
[] phase=1 -> goodC : (phase'=2) & (good'=true) + badC : (phase'=2) & (good'=false);
// if the current member is a good member, update the last seen index (chosen uniformly)
[] phase=2 & good -> 1/5 : (lastSeen'=0) & (phase'=3) + 1/5 : (lastSeen'=1) & (phase'=3) + 1/5 : (lastSeen'=2) & (phase'=3) + 1/5 : (lastSeen'=3) & (phase'=3) + 1/5 : (lastSeen'=4) & (phase'=3);
// if the current member is a bad member, record the most recently seen index
[] phase=2 & !good & lastSeen=0 & observe0 < TotalRuns -> 1: (observe0'=observe0+1) & (phase'=4);
[] phase=2 & !good & lastSeen=1 & observe1 < TotalRuns -> 1: (observe1'=observe1+1) & (phase'=4);
[] phase=2 & !good & lastSeen=2 & observe2 < TotalRuns -> 1: (observe2'=observe2+1) & (phase'=4);
[] phase=2 & !good & lastSeen=3 & observe3 < TotalRuns -> 1: (observe3'=observe3+1) & (phase'=4);
[] phase=2 & !good & lastSeen=4 & observe4 < TotalRuns -> 1: (observe4'=observe4+1) & (phase'=4);
// good crowd members forward with probability PF and deliver otherwise
[] phase=3 -> PF : (phase'=1) + notPF : (phase'=4);
// deliver the message and start over
[] phase=4 -> 1: (phase'=0);
endmodule
label "observe0Greater1" = observe0>1;
label "observe1Greater1" = observe1>1;
label "observe2Greater1" = observe2>1;
label "observe3Greater1" = observe3>1;
label "observe4Greater1" = observe4>1;
label "observeIGreater1" = observe1>1|observe2>1|observe3>1|observe4>1;
label "observeOnlyTrueSender" = observe0>1&observe1<=1 & observe2<=1 & observe3<=1 & observe4<=1;

130
test/functional/parser/prism/csma2_2.nm

@ -0,0 +1,130 @@
// CSMA/CD protocol - probabilistic version of kronos model (3 stations)
// gxn/dxp 04/12/01
mdp
// note made changes since cannot have strict inequalities
// in digital clocks approach and suppose a station only sends one message
// simplified parameters scaled
const int sigma=1; // time for messages to propagate along the bus
const int lambda=30; // time to send a message
// actual parameters
const int N = 2; // number of processes
const int K = 2; // exponential backoff limit
const int slot = 2*sigma; // length of slot
// const int M = floor(pow(2, K))-1 ; // max number of slots to wait
const int M = 3 ; // max number of slots to wait
//const int lambda=782;
//const int sigma=26;
// formula min_backoff_after_success = min(s1=4?cd1:K+1,s2=4?cd2:K+1);
// formula min_collisions = min(cd1,cd2);
// formula max_collisions = max(cd1,cd2);
//----------------------------------------------------------------------------------------------------------------------------
// the bus
module bus
b : [0..2];
// b=0 - idle
// b=1 - active
// b=2 - collision
// clocks of bus
y1 : [0..sigma+1]; // time since first send (used find time until channel sensed busy)
y2 : [0..sigma+1]; // time since second send (used to find time until collision detected)
// a sender sends (ok - no other message being sent)
[send1] (b=0) -> (b'=1);
[send2] (b=0) -> (b'=1);
// a sender sends (bus busy - collision)
[send1] (b=1|b=2) & (y1<sigma) -> (b'=2);
[send2] (b=1|b=2) & (y1<sigma) -> (b'=2);
// finish sending
[end1] (b=1) -> (b'=0) & (y1'=0);
[end2] (b=1) -> (b'=0) & (y1'=0);
// bus busy
[busy1] (b=1|b=2) & (y1>=sigma) -> (b'=b);
[busy2] (b=1|b=2) & (y1>=sigma) -> (b'=b);
// collision detected
[cd] (b=2) & (y2<=sigma) -> (b'=0) & (y1'=0) & (y2'=0);
// time passage
[time] (b=0) -> (y1'=0); // value of y1/y2 does not matter in state 0
[time] (b=1) -> (y1'=min(y1+1,sigma+1)); // no invariant in state 1
[time] (b=2) & (y2<sigma) -> (y1'=min(y1+1,sigma+1)) & (y2'=min(y2+1,sigma+1)); // invariant in state 2 (time until collision detected)
endmodule
//----------------------------------------------------------------------------------------------------------------------------
// model of first sender
module station1
// LOCAL STATE
s1 : [0..5];
// s1=0 - initial state
// s1=1 - transmit
// s1=2 - collision (set backoff)
// s1=3 - wait (bus busy)
// s1=4 - successfully sent
// LOCAL CLOCK
x1 : [0..max(lambda,slot)];
// BACKOFF COUNTER (number of slots to wait)
bc1 : [0..M];
// COLLISION COUNTER
cd1 : [0..K];
// start sending
[send1] (s1=0) -> (s1'=1) & (x1'=0); // start sending
[busy1] (s1=0) -> (s1'=2) & (x1'=0) & (cd1'=min(K,cd1+1)); // detects channel is busy so go into backoff
// transmitting
[time] (s1=1) & (x1<lambda) -> (x1'=min(x1+1,lambda)); // let time pass
[end1] (s1=1) & (x1=lambda) -> (s1'=4) & (x1'=0); // finished
[cd] (s1=1) -> (s1'=2) & (x1'=0) & (cd1'=min(K,cd1+1)); // collision detected (increment backoff counter)
[cd] !(s1=1) -> (s1'=s1); // add loop for collision detection when not important
// set backoff (no time can pass in this state)
// probability depends on which transmission this is (cd1)
[] s1=2 & cd1=1 -> 1/2 : (s1'=3) & (bc1'=0) + 1/2 : (s1'=3) & (bc1'=1) ;
[] s1=2 & cd1=2 -> 1/4 : (s1'=3) & (bc1'=0) + 1/4 : (s1'=3) & (bc1'=1) + 1/4 : (s1'=3) & (bc1'=2) + 1/4 : (s1'=3) & (bc1'=3) ;
// wait until backoff counter reaches 0 then send again
[time] (s1=3) & (x1<slot) -> (x1'=x1+1); // let time pass (in slot)
[time] (s1=3) & (x1=slot) & (bc1>0) -> (x1'=1) & (bc1'=bc1-1); // let time pass (move slots)
[send1] (s1=3) & (x1=slot) & (bc1=0) -> (s1'=1) & (x1'=0); // finished backoff (bus appears free)
[busy1] (s1=3) & (x1=slot) & (bc1=0) -> (s1'=2) & (x1'=0) & (cd1'=min(K,cd1+1)); // finished backoff (bus busy)
// once finished nothing matters
[time] (s1>=4) -> (x1'=0);
endmodule
//----------------------------------------------------------------------------------------------------------------------------
// construct further stations through renaming
module station2=station1[s1=s2,x1=x2,cd1=cd2,bc1=bc2,send1=send2,busy1=busy2,end1=end2] endmodule
//----------------------------------------------------------------------------------------------------------------------------
// reward structure for expected time
rewards "time"
[time] true : 1;
endrewards
//----------------------------------------------------------------------------------------------------------------------------
// labels/formulae
label "all_delivered" = s1=4&s2=4;
label "one_delivered" = s1=4|s2=4;
label "collision_max_backoff" = (cd1=K & s1=1 & b=2)|(cd2=K & s2=1 & b=2);

24
test/functional/parser/prism/die.pm

@ -0,0 +1,24 @@
// Knuth's model of a fair die using only fair coins
dtmc
module die
// local state
s : [0..7] init 0;
// value of the dice
d : [0..6] init 0;
[] s=0 -> 0.5 : (s'=1) + 0.5 : (s'=2);
[] s=1 -> 0.5 : (s'=3) + 0.5 : (s'=4);
[] s=2 -> 0.5 : (s'=5) + 0.5 : (s'=6);
[] s=3 -> 0.5 : (s'=1) + 0.5 : (s'=7) & (d'=1);
[] s=4 -> 0.5 : (s'=7) & (d'=2) + 0.5 : (s'=7) & (d'=3);
[] s=5 -> 0.5 : (s'=7) & (d'=4) + 0.5 : (s'=7) & (d'=5);
[] s=6 -> 0.5 : (s'=2) + 0.5 : (s'=7) & (d'=6);
[] s=7 -> 1: (s'=7);
endmodule
rewards "coin_flips"
[] s<7 : 1;
endrewards

170
test/functional/parser/prism/firewire.nm

@ -0,0 +1,170 @@
// firewire protocol with integer semantics
// dxp/gxn 14/06/01
// CLOCKS
// x1 (x2) clock for node1 (node2)
// y1 and y2 (z1 and z2) clocks for wire12 (wire21)
mdp
// maximum and minimum delays
// fast
const int rc_fast_max = 85;
const int rc_fast_min = 76;
// slow
const int rc_slow_max = 167;
const int rc_slow_min = 159;
// delay caused by the wire length
const int delay;
// probability of choosing fast
const double fast;
const double slow=1-fast;
module wire12
// local state
w12 : [0..9];
// 0 - empty
// 1 - rec_req
// 2 - rec_req_ack
// 3 - rec_ack
// 4 - rec_ack_idle
// 5 - rec_idle
// 6 - rec_idle_req
// 7 - rec_ack_req
// 8 - rec_req_idle
// 9 - rec_idle_ack
// clock for wire12
y1 : [0..delay+1];
y2 : [0..delay+1];
// empty
// do not need y1 and y2 to increase as always reset when this state is left
// similarly can reset y1 and y2 when we re-enter this state
[snd_req12] w12=0 -> (w12'=1) & (y1'=0) & (y2'=0);
[snd_ack12] w12=0 -> (w12'=3) & (y1'=0) & (y2'=0);
[snd_idle12] w12=0 -> (w12'=5) & (y1'=0) & (y2'=0);
[time] w12=0 -> (w12'=w12);
// rec_req
[snd_req12] w12=1 -> (w12'=1);
[rec_req12] w12=1 -> (w12'=0) & (y1'=0) & (y2'=0);
[snd_ack12] w12=1 -> (w12'=2) & (y2'=0);
[snd_idle12] w12=1 -> (w12'=8) & (y2'=0);
[time] w12=1 & y2<delay -> (y1'=min(y1+1,delay+1)) & (y2'=min(y2+1,delay+1));
// rec_req_ack
[snd_ack12] w12=2 -> (w12'=2);
[rec_req12] w12=2 -> (w12'=3);
[time] w12=2 & y1<delay -> (y1'=min(y1+1,delay+1)) & (y2'=min(y2+1,delay+1));
// rec_ack
[snd_ack12] w12=3 -> (w12'=3);
[rec_ack12] w12=3 -> (w12'=0) & (y1'=0) & (y2'=0);
[snd_idle12] w12=3 -> (w12'=4) & (y2'=0);
[snd_req12] w12=3 -> (w12'=7) & (y2'=0);
[time] w12=3 & y2<delay -> (y1'=min(y1+1,delay+1)) & (y2'=min(y2+1,delay+1));
// rec_ack_idle
[snd_idle12] w12=4 -> (w12'=4);
[rec_ack12] w12=4 -> (w12'=5);
[time] w12=4 & y1<delay -> (y1'=min(y1+1,delay+1)) & (y2'=min(y2+1,delay+1));
// rec_idle
[snd_idle12] w12=5 -> (w12'=5);
[rec_idle12] w12=5 -> (w12'=0) & (y1'=0) & (y2'=0);
[snd_req12] w12=5 -> (w12'=6) & (y2'=0);
[snd_ack12] w12=5 -> (w12'=9) & (y2'=0);
[time] w12=5 & y2<delay -> (y1'=min(y1+1,delay+1)) & (y2'=min(y2+1,delay+1));
// rec_idle_req
[snd_req12] w12=6 -> (w12'=6);
[rec_idle12] w12=6 -> (w12'=1);
[time] w12=6 & y1<delay -> (y1'=min(y1+1,delay+1)) & (y2'=min(y2+1,delay+1));
// rec_ack_req
[snd_req12] w12=7 -> (w12'=7);
[rec_ack12] w12=7 -> (w12'=1);
[time] w12=7 & y1<delay -> (y1'=min(y1+1,delay+1)) & (y2'=min(y2+1,delay+1));
// rec_req_idle
[snd_idle12] w12=8 -> (w12'=8);
[rec_req12] w12=8 -> (w12'=5);
[time] w12=8 & y1<delay -> (y1'=min(y1+1,delay+1)) & (y2'=min(y2+1,delay+1));
// rec_idle_ack
[snd_ack12] w12=9 -> (w12'=9);
[rec_idle12] w12=9 -> (w12'=3);
[time] w12=9 & y1<delay -> (y1'=min(y1+1,delay+1)) & (y2'=min(y2+1,delay+1));
endmodule
module node1
// clock for node1
x1 : [0..168];
// local state
s1 : [0..8];
// 0 - root contention
// 1 - rec_idle
// 2 - rec_req_fast
// 3 - rec_req_slow
// 4 - rec_idle_fast
// 5 - rec_idle_slow
// 6 - snd_req
// 7- almost_root
// 8 - almost_child
// added resets to x1 when not considered again until after rest
// removed root and child (using almost root and almost child)
// root contention immediate state)
[snd_idle12] s1=0 -> fast : (s1'=2) & (x1'=0) + slow : (s1'=3) & (x1'=0);
[rec_idle21] s1=0 -> (s1'=1);
// rec_idle immediate state)
[snd_idle12] s1=1 -> fast : (s1'=4) & (x1'=0) + slow : (s1'=5) & (x1'=0);
[rec_req21] s1=1 -> (s1'=0);
// rec_req_fast
[rec_idle21] s1=2 -> (s1'=4);
[snd_ack12] s1=2 & x1>=rc_fast_min -> (s1'=7) & (x1'=0);
[time] s1=2 & x1<rc_fast_max -> (x1'=min(x1+1,168));
// rec_req_slow
[rec_idle21] s1=3 -> (s1'=5);
[snd_ack12] s1=3 & x1>=rc_slow_min -> (s1'=7) & (x1'=0);
[time] s1=3 & x1<rc_slow_max -> (x1'=min(x1+1,168));
// rec_idle_fast
[rec_req21] s1=4 -> (s1'=2);
[snd_req12] s1=4 & x1>=rc_fast_min -> (s1'=6) & (x1'=0);
[time] s1=4 & x1<rc_fast_max -> (x1'=min(x1+1,168));
// rec_idle_slow
[rec_req21] s1=5 -> (s1'=3);
[snd_req12] s1=5 & x1>=rc_slow_min -> (s1'=6) & (x1'=0);
[time] s1=5 & x1<rc_slow_max -> (x1'=min(x1+1,168));
// snd_req
// do not use x1 until reset (in state 0 or in state 1) so do not need to increase x1
// also can set x1 to 0 upon entering this state
[rec_req21] s1=6 -> (s1'=0);
[rec_ack21] s1=6 -> (s1'=8);
[time] s1=6 -> (s1'=s1);
// almost root (immediate)
// loop in final states to remove deadlock
[] s1=7 & s2=8 -> (s1'=s1);
[] s1=8 & s2=7 -> (s1'=s1);
[time] s1=7 -> (s1'=s1);
[time] s1=8 -> (s1'=s1);
endmodule
// construct remaining automata through renaming
module wire21=wire12[w12=w21, y1=z1, y2=z2,
snd_req12=snd_req21, snd_idle12=snd_idle21, snd_ack12=snd_ack21,
rec_req12=rec_req21, rec_idle12=rec_idle21, rec_ack12=rec_ack21]
endmodule
module node2=node1[s1=s2, s2=s1, x1=x2,
rec_req21=rec_req12, rec_idle21=rec_idle12, rec_ack21=rec_ack12,
snd_req12=snd_req21, snd_idle12=snd_idle21, snd_ack12=snd_ack21]
endmodule
// reward structures
// time
rewards "time"
[time] true : 1;
endrewards
// time nodes sending
rewards "time_sending"
[time] (w12>0 | w21>0) : 1;
endrewards
label "elected" = ((s1=8) & (s2=7)) | ((s1=7) & (s2=8));

96
test/functional/parser/prism/leader3.nm

@ -0,0 +1,96 @@
// asynchronous leader election
// 4 processes
// gxn/dxp 29/01/01
mdp
const int N = 3; // number of processes
//----------------------------------------------------------------------------------------------------------------------------
module process1
// COUNTER
c1 : [0..3-1];
// STATES
s1 : [0..4];
// 0 make choice
// 1 have not received neighbours choice
// 2 active
// 3 inactive
// 4 leader
// PREFERENCE
p1 : [0..1];
// VARIABLES FOR SENDING AND RECEIVING
receive1 : [0..2];
// not received anything
// received choice
// received counter
sent1 : [0..2];
// not send anything
// sent choice
// sent counter
// pick value
[] (s1=0) -> 0.5 : (s1'=1) & (p1'=0) + 0.5 : (s1'=1) & (p1'=1);
// send preference
[p12] (s1=1) & (sent1=0) -> (sent1'=1);
// receive preference
// stay active
[p31] (s1=1) & (receive1=0) & !( (p1=0) & (p3=1) ) -> (s1'=2) & (receive1'=1);
// become inactive
[p31] (s1=1) & (receive1=0) & (p1=0) & (p3=1) -> (s1'=3) & (receive1'=1);
// send preference (can now reset preference)
[p12] (s1=2) & (sent1=0) -> (sent1'=1) & (p1'=0);
// send counter (already sent preference)
// not received counter yet
[c12] (s1=2) & (sent1=1) & (receive1=1) -> (sent1'=2);
// received counter (pick again)
[c12] (s1=2) & (sent1=1) & (receive1=2) -> (s1'=0) & (p1'=0) & (c1'=0) & (sent1'=0) & (receive1'=0);
// receive counter and not sent yet (note in this case do not pass it on as will send own counter)
[c31] (s1=2) & (receive1=1) & (sent1<2) -> (receive1'=2);
// receive counter and sent counter
// only active process (decide)
[c31] (s1=2) & (receive1=1) & (sent1=2) & (c3=N-1) -> (s1'=4) & (p1'=0) & (c1'=0) & (sent1'=0) & (receive1'=0);
// other active process (pick again)
[c31] (s1=2) & (receive1=1) & (sent1=2) & (c3<N-1) -> (s1'=0) & (p1'=0) & (c1'=0) & (sent1'=0) & (receive1'=0);
// send preference (must have received preference) and can now reset
[p12] (s1=3) & (receive1>0) & (sent1=0) -> (sent1'=1) & (p1'=0);
// send counter (must have received counter first) and can now reset
[c12] (s1=3) & (receive1=2) & (sent1=1) -> (s1'=3) & (p1'=0) & (c1'=0) & (sent1'=0) & (receive1'=0);
// receive preference
[p31] (s1=3) & (receive1=0) -> (p1'=p3) & (receive1'=1);
// receive counter
[c31] (s1=3) & (receive1=1) & (c3<N-1) -> (c1'=c3+1) & (receive1'=2);
// done
[done] (s1=4) -> (s1'=s1);
// add loop for processes who are inactive
[done] (s1=3) -> (s1'=s1);
endmodule
//----------------------------------------------------------------------------------------------------------------------------
// construct further stations through renaming
module process2=process1[s1=s2,p1=p2,c1=c2,sent1=sent2,receive1=receive2,p12=p23,p31=p12,c12=c23,c31=c12,p3=p1,c3=c1] endmodule
module process3=process1[s1=s3,p1=p3,c1=c3,sent1=sent3,receive1=receive3,p12=p31,p31=p23,c12=c31,c31=c23,p3=p2,c3=c2] endmodule
//----------------------------------------------------------------------------------------------------------------------------
// reward - expected number of rounds (equals the number of times a process receives a counter)
rewards "name"
[c12] true : 1;
endrewards
//----------------------------------------------------------------------------------------------------------------------------
formula leaders = (s1=4?1:0)+(s2=4?1:0)+(s3=4?1:0);
label "elected" = s1=4|s2=4|s3=4;

85
test/functional/parser/prism/leader3_5.pm

@ -0,0 +1,85 @@
// synchronous leader election protocol (itai & Rodeh)
// dxp/gxn 25/01/01
dtmc
// CONSTANTS
const int N = 3; // number of processes
const int K = 5; // range of probabilistic choice
// counter module used to count the number of processes that have been read
// and to know when a process has decided
module counter
// counter (c=i means process j reading process (i-1)+j next)
c : [1..N-1];
// reading
[read] c<N-1 -> 1:(c'=c+1);
// finished reading
[read] c=N-1 -> 1:(c'=c);
//decide
[done] u1|u2|u3 -> 1:(c'=c);
// pick again reset counter
[retry] !(u1|u2|u3) -> 1:(c'=1);
// loop (when finished to avoid deadlocks)
[loop] s1=3 -> 1:(c'=c);
endmodule
// processes form a ring and suppose:
// process 1 reads process 2
// process 2 reads process 3
// process 3 reads process 1
module process1
// local state
s1 : [0..3];
// s1=0 make random choice
// s1=1 reading
// s1=2 deciding
// s1=3 finished
// has a unique id so far (initially true)
u1 : bool;
// value to be sent to next process in the ring (initially sets this to its own value)
v1 : [0..K-1];
// random choice
p1 : [0..K-1];
// pick value
[pick] s1=0 -> 1/K : (s1'=1) & (p1'=0) & (v1'=0) & (u1'=true)
+ 1/K : (s1'=1) & (p1'=1) & (v1'=1) & (u1'=true)
+ 1/K : (s1'=1) & (p1'=2) & (v1'=2) & (u1'=true)
+ 1/K : (s1'=1) & (p1'=3) & (v1'=3) & (u1'=true)
+ 1/K : (s1'=1) & (p1'=4) & (v1'=4) & (u1'=true);
// read
[read] s1=1 & u1 & c<N-1 -> 1:(u1'=(p1!=v2)) & (v1'=v2);
[read] s1=1 & !u1 & c<N-1 -> 1:(u1'=false) & (v1'=v2) & (p1'=0);
// read and move to decide
[read] s1=1 & u1 & c=N-1 -> 1:(s1'=2) & (u1'=(p1!=v2)) & (v1'=0) & (p1'=0);
[read] s1=1 & !u1 & c=N-1 -> 1:(s1'=2) & (u1'=false) & (v1'=0);
// deciding
// done
[done] s1=2 -> 1:(s1'=3) & (u1'=false) & (v1'=0) & (p1'=0);
//retry
[retry] s1=2 -> 1:(s1'=0) & (u1'=false) & (v1'=0) & (p1'=0);
// loop (when finished to avoid deadlocks)
[loop] s1=3 -> 1:(s1'=3);
endmodule
// construct remaining processes through renaming
module process2 = process1 [ s1=s2,p1=p2,v1=v2,u1=u2,v2=v3 ] endmodule
module process3 = process1 [ s1=s3,p1=p3,v1=v3,u1=u3,v2=v1 ] endmodule
// expected number of rounds
rewards "num_rounds"
[pick] true : 1;
endrewards
// labels
label "elected" = s1=3&s2=3&s3=3;

40
test/functional/parser/prism/two_dice.nm

@ -0,0 +1,40 @@
// sum of two dice as the asynchronous parallel composition of
// two copies of Knuth's model of a fair die using only fair coins
mdp
module die1
// local state
s1 : [0..7] init 0;
// value of the dice
d1 : [0..6] init 0;
[] s1=0 -> 0.5 : (s1'=1) + 0.5 : (s1'=2);
[] s1=1 -> 0.5 : (s1'=3) + 0.5 : (s1'=4);
[] s1=2 -> 0.5 : (s1'=5) + 0.5 : (s1'=6);
[] s1=3 -> 0.5 : (s1'=1) + 0.5 : (s1'=7) & (d1'=1);
[] s1=4 -> 0.5 : (s1'=7) & (d1'=2) + 0.5 : (s1'=7) & (d1'=3);
[] s1=5 -> 0.5 : (s1'=7) & (d1'=4) + 0.5 : (s1'=7) & (d1'=5);
[] s1=6 -> 0.5 : (s1'=2) + 0.5 : (s1'=7) & (d1'=6);
[] s1=7 & s2=7 -> 1: (s1'=7);
endmodule
module die2 = die1 [ s1=s2, s2=s1, d1=d2 ] endmodule
rewards "coinflips"
[] s1<7 | s2<7 : 1;
endrewards
label "done" = s1=7 & s2=7;
label "two" = s1=7 & s2=7 & d1+d2=2;
label "three" = s1=7 & s2=7 & d1+d2=3;
label "four" = s1=7 & s2=7 & d1+d2=4;
label "five" = s1=7 & s2=7 & d1+d2=5;
label "six" = s1=7 & s2=7 & d1+d2=6;
label "seven" = s1=7 & s2=7 & d1+d2=7;
label "eight" = s1=7 & s2=7 & d1+d2=8;
label "nine" = s1=7 & s2=7 & d1+d2=9;
label "ten" = s1=7 & s2=7 & d1+d2=10;
label "eleven" = s1=7 & s2=7 & d1+d2=11;
label "twelve" = s1=7 & s2=7 & d1+d2=12;

219
test/functional/parser/prism/wlan0_collide.nm

@ -0,0 +1,219 @@
// WLAN PROTOCOL (two stations)
// discrete time model
// gxn/jzs 20/02/02
mdp
// COLLISIONS
const int COL; // maximum number of collisions
// TIMING CONSTRAINTS
// we have used the FHSS parameters
// then scaled by the value of ASLOTTIME
const int ASLOTTIME = 1;
const int DIFS = 3; // due to scaling can be either 2 or 3 which is modelled by a non-deterministic choice
const int VULN = 1; // due to scaling can be either 0 or 1 which is modelled by a non-deterministic choice
const int TRANS_TIME_MAX; // scaling up
const int TRANS_TIME_MIN = 4; // scaling down
const int ACK_TO = 6;
const int ACK = 4; // due to scaling can be either 3 or 4 which is modelled by a non-deterministic choice
const int SIFS = 1; // due to scaling can be either 0 or 1 which is modelled by a non-deterministic choice
// maximum constant used in timing constraints + 1
const int TIME_MAX = max(ACK_TO,TRANS_TIME_MAX)+1;
// CONTENTION WINDOW
// CWMIN =15 & CWMAX =16
// this means that MAX_BACKOFF IS 2
const int MAX_BACKOFF = 0;
//-----------------------------------------------------------------//
// THE MEDIUM/CHANNEL
// FORMULAE FOR THE CHANNEL
// channel is busy
formula busy = c1>0 | c2>0;
// channel is free
formula free = c1=0 & c2=0;
module medium
// number of collisions
col : [0..COL];
// medium status
c1 : [0..2];
c2 : [0..2];
// ci corresponds to messages associated with station i
// 0 nothing being sent
// 1 being sent correctly
// 2 being sent garbled
// begin sending message and nothing else currently being sent
[send1] c1=0 & c2=0 -> (c1'=1);
[send2] c2=0 & c1=0 -> (c2'=1);
// begin sending message and something is already being sent
// in this case both messages become garbled
[send1] c1=0 & c2>0 -> (c1'=2) & (c2'=2) & (col'=min(col+1,COL));
[send2] c2=0 & c1>0 -> (c1'=2) & (c2'=2) & (col'=min(col+1,COL));
// finish sending message
[finish1] c1>0 -> (c1'=0);
[finish2] c2>0 -> (c2'=0);
endmodule
//-----------------------------------------------------------------//
// STATION 1
module station1
// clock for station 1
x1 : [0..TIME_MAX];
// local state
s1 : [1..12];
// 1 sense
// 2 wait until free before setting backoff
// 3 wait for DIFS then set slot
// 4 set backoff
// 5 backoff
// 6 wait until free in backoff
// 7 wait for DIFS then resume backoff
// 8 vulnerable
// 9 transmit
// 11 wait for SIFS and then ACK
// 10 wait for ACT_TO
// 12 done
// BACKOFF
// separate into slots
slot1 : [0..1];
backoff1 : [0..15];
// BACKOFF COUNTER
bc1 : [0..1];
// SENSE
// let time pass
[time] s1=1 & x1<DIFS & free -> (x1'=min(x1+1,TIME_MAX));
// ready to transmit
[] s1=1 & (x1=DIFS | x1=DIFS-1) -> (s1'=8) & (x1'=0);
// found channel busy so wait until free
[] s1=1 & busy -> (s1'=2) & (x1'=0);
// WAIT UNTIL FREE BEFORE SETTING BACKOFF
// let time pass (no need for the clock x1 to change)
[time] s1=2 & busy -> (s1'=2);
// find that channel is free so check its free for DIFS before setting backoff
[] s1=2 & free -> (s1'=3);
// WAIT FOR DIFS THEN SET BACKOFF
// let time pass
[time] s1=3 & x1<DIFS & free -> (x1'=min(x1+1,TIME_MAX));
// found channel busy so wait until free
[] s1=3 & busy -> (s1'=2) & (x1'=0);
// start backoff first uniformly choose slot
// backoff counter 0
[] s1=3 & (x1=DIFS | x1=DIFS-1) & bc1=0 -> (s1'=4) & (x1'=0) & (slot1'=0) & (bc1'=min(bc1+1,MAX_BACKOFF));
// SET BACKOFF (no time can pass)
// chosen slot now set backoff
[] s1=4 -> 1/16 : (s1'=5) & (backoff1'=0 )
+ 1/16 : (s1'=5) & (backoff1'=1 )
+ 1/16 : (s1'=5) & (backoff1'=2 )
+ 1/16 : (s1'=5) & (backoff1'=3 )
+ 1/16 : (s1'=5) & (backoff1'=4 )
+ 1/16 : (s1'=5) & (backoff1'=5 )
+ 1/16 : (s1'=5) & (backoff1'=6 )
+ 1/16 : (s1'=5) & (backoff1'=7 )
+ 1/16 : (s1'=5) & (backoff1'=8 )
+ 1/16 : (s1'=5) & (backoff1'=9 )
+ 1/16 : (s1'=5) & (backoff1'=10)
+ 1/16 : (s1'=5) & (backoff1'=11)
+ 1/16 : (s1'=5) & (backoff1'=12)
+ 1/16 : (s1'=5) & (backoff1'=13)
+ 1/16 : (s1'=5) & (backoff1'=14)
+ 1/16 : (s1'=5) & (backoff1'=15);
// BACKOFF
// let time pass
[time] s1=5 & x1<ASLOTTIME & free -> (x1'=min(x1+1,TIME_MAX));
// decrement backoff
[] s1=5 & x1=ASLOTTIME & backoff1>0 -> (s1'=5) & (x1'=0) & (backoff1'=backoff1-1);
[] s1=5 & x1=ASLOTTIME & backoff1=0 & slot1>0 -> (s1'=5) & (x1'=0) & (backoff1'=15) & (slot1'=slot1-1);
// finish backoff
[] s1=5 & x1=ASLOTTIME & backoff1=0 & slot1=0 -> (s1'=8) & (x1'=0);
// found channel busy
[] s1=5 & busy -> (s1'=6) & (x1'=0);
// WAIT UNTIL FREE IN BACKOFF
// let time pass (no need for the clock x1 to change)
[time] s1=6 & busy -> (s1'=6);
// find that channel is free
[] s1=6 & free -> (s1'=7);
// WAIT FOR DIFS THEN RESUME BACKOFF
// let time pass
[time] s1=7 & x1<DIFS & free -> (x1'=min(x1+1,TIME_MAX));
// resume backoff (start again from previous backoff)
[] s1=7 & (x1=DIFS | x1=DIFS-1) -> (s1'=5) & (x1'=0);
// found channel busy
[] s1=7 & busy -> (s1'=6) & (x1'=0);
// VULNERABLE
// let time pass
[time] s1=8 & x1<VULN -> (x1'=min(x1+1,TIME_MAX));
// move to transmit
[send1] s1=8 & (x1=VULN | x1=VULN-1) -> (s1'=9) & (x1'=0);
// TRANSMIT
// let time pass
[time] s1=9 & x1<TRANS_TIME_MAX -> (x1'=min(x1+1,TIME_MAX));
// finish transmission successful
[finish1] s1=9 & x1>=TRANS_TIME_MIN & c1=1 -> (s1'=10) & (x1'=0);
// finish transmission garbled
[finish1] s1=9 & x1>=TRANS_TIME_MIN & c1=2 -> (s1'=11) & (x1'=0);
// WAIT FOR SIFS THEN WAIT FOR ACK
// WAIT FOR SIFS i.e. c1=0
// check channel and busy: go into backoff
[] s1=10 & c1=0 & x1=0 & busy -> (s1'=2);
// check channel and free: let time pass
[time] s1=10 & c1=0 & x1=0 & free -> (x1'=min(x1+1,TIME_MAX));
// let time pass
// following guard is always false as SIFS=1
// [time] s1=10 & c1=0 & x1>0 & x1<SIFS -> (x1'=min(x1+1,TIME_MAX));
// ack is sent after SIFS (since SIFS-1=0 add condition that channel is free)
[send1] s1=10 & c1=0 & (x1=SIFS | (x1=SIFS-1 & free)) -> (s1'=10) & (x1'=0);
// WAIT FOR ACK i.e. c1=1
// let time pass
[time] s1=10 & c1=1 & x1<ACK -> (x1'=min(x1+1,TIME_MAX));
// get acknowledgement so packet sent correctly and move to done
[finish1] s1=10 & c1=1 & (x1=ACK | x1=ACK-1) -> (s1'=12) & (x1'=0) & (bc1'=0);
// WAIT FOR ACK_TO
// check channel and busy: go into backoff
[] s1=11 & x1=0 & busy -> (s1'=2);
// check channel and free: let time pass
[time] s1=11 & x1=0 & free -> (x1'=min(x1+1,TIME_MAX));
// let time pass
[time] s1=11 & x1>0 & x1<ACK_TO -> (x1'=min(x1+1,TIME_MAX));
// no acknowledgement (go to backoff waiting DIFS first)
[] s1=11 & x1=ACK_TO -> (s1'=3) & (x1'=0);
// DONE
[time] s1=12 -> (s1'=12);
endmodule
// ---------------------------------------------------------------------------- //
// STATION 2 (rename STATION 1)
module
station2=station1[x1=x2,
s1=s2,
s2=s1,
c1=c2,
c2=c1,
slot1=slot2,
backoff1=backoff2,
bc1=bc2,
send1=send2,
finish1=finish2]
endmodule
// ---------------------------------------------------------------------------- //
label "twoCollisions" = col=2;
label "fourCollisions" = col=4;
label "sixCollisions" = col=6;

2
test/functional/solver/GmmxxLinearEquationSolverTest.cpp

@ -81,7 +81,7 @@ TEST(GmmxxLinearEquationSolver, qmr) {
ASSERT_NO_THROW(storm::solver::GmmxxLinearEquationSolver<double> solver(storm::solver::GmmxxLinearEquationSolver<double>::QMR, 1e-6, 10000, storm::solver::GmmxxLinearEquationSolver<double>::NONE));
storm::solver::GmmxxLinearEquationSolver<double> solver(storm::solver::GmmxxLinearEquationSolver<double>::QMR, 1e-6, 10000, storm::solver::GmmxxLinearEquationSolver<double>::NONE, 50);
storm::solver::GmmxxLinearEquationSolver<double> solver(storm::solver::GmmxxLinearEquationSolver<double>::QMR, 1e-6, 10000, storm::solver::GmmxxLinearEquationSolver<double>::NONE, true, 50);
ASSERT_NO_THROW(solver.solveEquationSystem(A, x, b));
ASSERT_LT(std::abs(x[0] - 1), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble());
ASSERT_LT(std::abs(x[1] - 3), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble());

39
test/functional/storage/CuddDdTest.cpp

@ -130,9 +130,12 @@ TEST(CuddDd, OperatorTest) {
dd3 += manager->getZero();
EXPECT_TRUE(dd3 == manager->getConstant(2));
dd3 = dd1 && manager->getConstant(3);
EXPECT_TRUE(dd1 == manager->getOne());
dd3 = dd1 * manager->getConstant(3);
EXPECT_TRUE(dd3 == manager->getConstant(3));
dd3 *= manager->getConstant(2);
EXPECT_TRUE(dd3 == manager->getConstant(6));
@ -148,8 +151,11 @@ TEST(CuddDd, OperatorTest) {
dd3.complement();
EXPECT_TRUE(dd3 == manager->getZero());
dd1 = ~dd3;
dd1 = !dd3;
EXPECT_TRUE(dd1 == manager->getOne());
dd3 = dd1 || dd2;
EXPECT_TRUE(dd3 == manager->getOne());
dd1 = manager->getIdentity("x");
dd2 = manager->getConstant(5);
@ -158,7 +164,7 @@ TEST(CuddDd, OperatorTest) {
EXPECT_EQ(1, dd3.getNonZeroCount());
storm::dd::Dd<storm::dd::DdType::CUDD> dd4 = dd1.notEquals(dd2);
EXPECT_TRUE(dd4 == ~dd3);
EXPECT_TRUE(dd4 == !dd3);
dd3 = dd1.less(dd2);
EXPECT_EQ(11, dd3.getNonZeroCount());
@ -171,6 +177,11 @@ TEST(CuddDd, OperatorTest) {
dd3 = dd1.greaterOrEqual(dd2);
EXPECT_EQ(5, dd3.getNonZeroCount());
dd1 = manager->getConstant(0.01);
dd2 = manager->getConstant(0.01 + 1e-6);
EXPECT_TRUE(dd1.equalModuloPrecision(dd2, 1e-6, false));
EXPECT_FALSE(dd1.equalModuloPrecision(dd2, 1e-6));
}
TEST(CuddDd, AbstractionTest) {
@ -253,7 +264,6 @@ TEST(CuddDd, GetSetValueTest) {
storm::dd::Dd<storm::dd::DdType::CUDD> dd1 = manager->getOne();
ASSERT_NO_THROW(dd1.setValue("x", 4, 2));
EXPECT_EQ(2, dd1.getLeafCount());
dd1.exportToDot("dd1.dot");
std::map<std::string, int_fast64_t> metaVariableToValueMap;
metaVariableToValueMap.emplace("x", 1);
@ -263,3 +273,24 @@ TEST(CuddDd, GetSetValueTest) {
metaVariableToValueMap.emplace("x", 4);
EXPECT_EQ(2, dd1.getValue(metaVariableToValueMap));
}
TEST(CuddDd, ForwardIteratorTest) {
std::shared_ptr<storm::dd::DdManager<storm::dd::DdType::CUDD>> manager(new storm::dd::DdManager<storm::dd::DdType::CUDD>());
manager->addMetaVariable("x", 1, 9);
manager->addMetaVariable("y", 0, 3);
storm::dd::Dd<storm::dd::DdType::CUDD> dd;
ASSERT_NO_THROW(dd = manager->getRange("x"));
storm::dd::DdForwardIterator<storm::dd::DdType::CUDD> it, ite;
ASSERT_NO_THROW(it = dd.begin());
ASSERT_NO_THROW(ite = dd.end());
std::pair<storm::expressions::SimpleValuation, double> valuationValuePair;
uint_fast64_t numberOfValuations = 0;
while (it != ite) {
ASSERT_NO_THROW(valuationValuePair = *it);
ASSERT_NO_THROW(++it);
++numberOfValuations;
}
EXPECT_EQ(9, numberOfValuations);
}

9
test/functional/storage/ExpressionTest.cpp

@ -1,4 +1,5 @@
#include <map>
#include <string>
#include "gtest/gtest.h"
#include "src/storage/expressions/Expression.h"
@ -264,6 +265,12 @@ TEST(Expression, OperatorTest) {
ASSERT_NO_THROW(tempExpression = boolVarExpression.iff(boolConstExpression));
EXPECT_TRUE(tempExpression.getReturnType() == storm::expressions::ExpressionReturnType::Bool);
ASSERT_THROW(tempExpression = trueExpression ^ piExpression, storm::exceptions::InvalidTypeException);
ASSERT_NO_THROW(tempExpression = trueExpression ^ falseExpression);
EXPECT_TRUE(tempExpression.getReturnType() == storm::expressions::ExpressionReturnType::Bool);
ASSERT_NO_THROW(tempExpression = boolVarExpression ^ boolConstExpression);
EXPECT_TRUE(tempExpression.getReturnType() == storm::expressions::ExpressionReturnType::Bool);
ASSERT_THROW(tempExpression = trueExpression.floor(), storm::exceptions::InvalidTypeException);
ASSERT_NO_THROW(tempExpression = threeExpression.floor());
EXPECT_TRUE(tempExpression.getReturnType() == storm::expressions::ExpressionReturnType::Int);
@ -305,7 +312,7 @@ TEST(Expression, SubstitutionTest) {
std::map<std::string, storm::expressions::Expression> substution = { std::make_pair("y", doubleConstExpression), std::make_pair("x", storm::expressions::Expression::createTrue()), std::make_pair("a", storm::expressions::Expression::createTrue()) };
storm::expressions::Expression substitutedExpression;
ASSERT_NO_THROW(substitutedExpression = tempExpression.substitute<std::map>(substution));
ASSERT_NO_THROW(substitutedExpression = tempExpression.substitute(substution));
EXPECT_TRUE(substitutedExpression.simplify().isTrue());
}

Loading…
Cancel
Save