Browse Source

Merge branch master into PrctlParser

main
Lanchid 13 years ago
parent
commit
5b57728d7e
  1. 3109
      resources/cmake/cotire.cmake
  2. 2
      src/formula/AbstractFormula.h
  3. 4
      src/formula/AbstractPathFormula.h
  4. 2
      src/formula/AbstractStateFormula.h
  5. 2
      src/formula/And.h
  6. 2
      src/formula/Ap.h
  7. 8
      src/formula/BoundedEventually.h
  8. 9
      src/formula/BoundedNaryUntil.h
  9. 9
      src/formula/BoundedUntil.h
  10. 6
      src/formula/CumulativeReward.h
  11. 8
      src/formula/Eventually.h
  12. 10
      src/formula/Formulas.h
  13. 7
      src/formula/Globally.h
  14. 6
      src/formula/InstantaneousReward.h
  15. 6
      src/formula/Next.h
  16. 59
      src/formula/NoBoundOperator.h
  17. 2
      src/formula/Not.h
  18. 36
      src/formula/PathBoundOperator.h
  19. 11
      src/formula/PrctlFormulaChecker.h
  20. 27
      src/formula/ProbabilisticBoundOperator.h
  21. 14
      src/formula/ProbabilisticNoBoundOperator.h
  22. 7
      src/formula/ReachabilityReward.h
  23. 27
      src/formula/RewardBoundOperator.h
  24. 14
      src/formula/RewardNoBoundOperator.h
  25. 6
      src/formula/Until.h
  26. 139
      src/modelchecker/AbstractModelChecker.h
  27. 182
      src/modelchecker/DtmcPrctlModelChecker.h
  28. 21
      src/modelchecker/EigenDtmcPrctlModelChecker.h
  29. 3
      src/modelchecker/ForwardDeclarations.h
  30. 96
      src/modelchecker/GmmxxDtmcPrctlModelChecker.h
  31. 434
      src/modelchecker/GmmxxMdpPrctlModelChecker.h
  32. 286
      src/modelchecker/MdpPrctlModelChecker.h
  33. 54
      src/models/AbstractDeterministicModel.h
  34. 176
      src/models/AbstractModel.h
  35. 82
      src/models/AbstractNondeterministicModel.h
  36. 15
      src/models/AtomicPropositionsLabeling.h
  37. 149
      src/models/Ctmc.h
  38. 175
      src/models/Ctmdp.h
  39. 173
      src/models/Dtmc.h
  40. 104
      src/models/GraphTransitions.h
  41. 175
      src/models/Mdp.h
  42. 79
      src/parser/AutoParser.cpp
  43. 76
      src/parser/AutoParser.h
  44. 10
      src/parser/NondeterministicModelParser.cpp
  45. 7
      src/parser/NondeterministicModelParser.h
  46. 146
      src/parser/NondeterministicSparseTransitionParser.cpp
  47. 4
      src/parser/NondeterministicSparseTransitionParser.h
  48. 79
      src/reward/RewardModel.h
  49. 155
      src/solver/GraphAnalyzer.h
  50. 39
      src/storage/BitVector.h
  51. 220
      src/storage/SparseMatrix.h
  52. 71
      src/storm.cpp
  53. 8
      src/utility/ConstTemplates.h
  54. 421
      src/utility/GraphAnalyzer.h
  55. 2
      src/utility/IoUtility.cpp
  56. 63
      src/utility/Vector.h
  57. 183
      src/vector/dense_vector.h
  58. 8
      test/parser/ParseMdpTest.cpp
  59. 23
      test/reward/RewardModelTest.cpp
  60. 8
      test/storage/SparseMatrixTest.cpp

3109
resources/cmake/cotire.cmake
File diff suppressed because it is too large
View File

2
src/formula/AbstractFormula.h

@ -14,7 +14,7 @@ namespace storm { namespace formula {
template <class T> class AbstractFormula;
}}
#include "src/modelchecker/AbstractModelChecker.h"
#include "src/modelchecker/ForwardDeclarations.h"
#include "src/formula/AbstractFormulaChecker.h"
namespace storm {

4
src/formula/AbstractPathFormula.h

@ -13,7 +13,7 @@ template <class T> class AbstractPathFormula;
}}
#include "src/formula/AbstractFormula.h"
#include "src/modelchecker/AbstractModelChecker.h"
#include "src/modelchecker/ForwardDeclarations.h"
#include <vector>
#include <iostream>
@ -61,7 +61,7 @@ public:
*
* @returns A vector indicating the probability that the formula holds for each state.
*/
virtual std::vector<T>* check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker) const = 0;
virtual std::vector<T>* check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker, bool qualitative) const = 0;
};
} //namespace formula

2
src/formula/AbstractStateFormula.h

@ -14,7 +14,7 @@ template <class T> class AbstractStateFormula;
#include "src/formula/AbstractFormula.h"
#include "src/storage/BitVector.h"
#include "src/modelchecker/AbstractModelChecker.h"
#include "src/modelchecker/ForwardDeclarations.h"
namespace storm {
namespace formula {

2
src/formula/And.h

@ -10,7 +10,7 @@
#include "src/formula/AbstractStateFormula.h"
#include "src/formula/AbstractFormulaChecker.h"
#include "src/modelchecker/AbstractModelChecker.h"
#include "src/modelchecker/ForwardDeclarations.h"
#include <string>
namespace storm {

2
src/formula/Ap.h

@ -10,7 +10,7 @@
#include "src/formula/AbstractStateFormula.h"
#include "src/formula/AbstractFormulaChecker.h"
#include "src/modelchecker/AbstractModelChecker.h"
#include "src/modelchecker/ForwardDeclarations.h"
namespace storm {
namespace formula {

8
src/formula/BoundedEventually.h

@ -13,7 +13,7 @@
#include "src/formula/AbstractFormulaChecker.h"
#include "boost/integer/integer_mask.hpp"
#include <string>
#include "src/modelchecker/AbstractModelChecker.h"
#include "src/modelchecker/ForwardDeclarations.h"
namespace storm {
@ -36,7 +36,7 @@ class IBoundedEventuallyModelChecker {
* @param obj Formula object with subformulas.
* @return Result of the formula for every node.
*/
virtual std::vector<T>* checkBoundedEventually(const BoundedEventually<T>& obj) const = 0;
virtual std::vector<T>* checkBoundedEventually(const BoundedEventually<T>& obj, bool qualitative) const = 0;
};
/*!
@ -157,8 +157,8 @@ public:
*
* @returns A vector indicating the probability that the formula holds for each state.
*/
virtual std::vector<T> *check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker) const {
return modelChecker.template as<IBoundedEventuallyModelChecker>()->checkBoundedEventually(*this);
virtual std::vector<T>* check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker, bool qualitative) const {
return modelChecker.template as<IBoundedEventuallyModelChecker>()->checkBoundedEventually(*this, qualitative);
}
/*!

9
src/formula/BoundedNaryUntil.h

@ -10,13 +10,12 @@
#include "src/formula/AbstractPathFormula.h"
#include "src/formula/AbstractStateFormula.h"
#include "src/modelchecker/AbstractModelChecker.h"
#include "boost/integer/integer_mask.hpp"
#include <string>
#include <vector>
#include <tuple>
#include <sstream>
#include "src/formula/AbstractFormulaChecker.h"
#include "src/modelchecker/ForwardDeclarations.h"
namespace storm {
namespace formula {
@ -38,7 +37,7 @@ class IBoundedNaryUntilModelChecker {
* @param obj Formula object with subformulas.
* @return Result of the formula for every node.
*/
virtual std::vector<T>* checkBoundedNaryUntil(const BoundedNaryUntil<T>& obj) const = 0;
virtual std::vector<T>* checkBoundedNaryUntil(const BoundedNaryUntil<T>& obj, bool qualitative) const = 0;
};
/*!
@ -180,8 +179,8 @@ public:
*
* @returns A vector indicating the probability that the formula holds for each state.
*/
virtual std::vector<T> *check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker) const {
return modelChecker.template as<IBoundedNaryUntilModelChecker>()->checkBoundedNaryUntil(*this);
virtual std::vector<T> *check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker, bool qualitative) const {
return modelChecker.template as<IBoundedNaryUntilModelChecker>()->checkBoundedNaryUntil(*this, qualitative);
}
/*!

9
src/formula/BoundedUntil.h

@ -10,10 +10,9 @@
#include "src/formula/AbstractPathFormula.h"
#include "src/formula/AbstractStateFormula.h"
#include "src/modelchecker/AbstractModelChecker.h"
#include "boost/integer/integer_mask.hpp"
#include <string>
#include "src/formula/AbstractFormulaChecker.h"
#include "src/modelchecker/ForwardDeclarations.h"
namespace storm {
namespace formula {
@ -35,7 +34,7 @@ class IBoundedUntilModelChecker {
* @param obj Formula object with subformulas.
* @return Result of the formula for every node.
*/
virtual std::vector<T>* checkBoundedUntil(const BoundedUntil<T>& obj) const = 0;
virtual std::vector<T>* checkBoundedUntil(const BoundedUntil<T>& obj, bool qualitative) const = 0;
};
/*!
@ -185,8 +184,8 @@ public:
*
* @returns A vector indicating the probability that the formula holds for each state.
*/
virtual std::vector<T> *check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker) const {
return modelChecker.template as<IBoundedUntilModelChecker>()->checkBoundedUntil(*this);
virtual std::vector<T> *check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker, bool qualitative) const {
return modelChecker.template as<IBoundedUntilModelChecker>()->checkBoundedUntil(*this, qualitative);
}
/*!

6
src/formula/CumulativeReward.h

@ -35,7 +35,7 @@ class ICumulativeRewardModelChecker {
* @param obj Formula object with subformulas.
* @return Result of the formula for every node.
*/
virtual std::vector<T>* checkCumulativeReward(const CumulativeReward<T>& obj) const = 0;
virtual std::vector<T>* checkCumulativeReward(const CumulativeReward<T>& obj, bool qualitative) const = 0;
};
/*!
@ -121,8 +121,8 @@ public:
*
* @returns A vector indicating the probability that the formula holds for each state.
*/
virtual std::vector<T> *check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker) const {
return modelChecker.template as<ICumulativeRewardModelChecker>()->checkCumulativeReward(*this);
virtual std::vector<T> *check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker, bool qualitative) const {
return modelChecker.template as<ICumulativeRewardModelChecker>()->checkCumulativeReward(*this, qualitative);
}
/*!

8
src/formula/Eventually.h

@ -10,7 +10,7 @@
#include "src/formula/AbstractPathFormula.h"
#include "src/formula/AbstractStateFormula.h"
#include "src/modelchecker/AbstractModelChecker.h"
#include "src/modelchecker/ForwardDeclarations.h"
namespace storm {
@ -33,7 +33,7 @@ class IEventuallyModelChecker {
* @param obj Formula object with subformulas.
* @return Result of the formula for every node.
*/
virtual std::vector<T>* checkEventually(const Eventually<T>& obj) const = 0;
virtual std::vector<T>* checkEventually(const Eventually<T>& obj, bool qualitative) const = 0;
};
/*!
@ -131,8 +131,8 @@ public:
*
* @returns A vector indicating the probability that the formula holds for each state.
*/
virtual std::vector<T> *check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker) const {
return modelChecker.template as<IEventuallyModelChecker>()->checkEventually(*this);
virtual std::vector<T> *check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker, bool qualitative) const {
return modelChecker.template as<IEventuallyModelChecker>()->checkEventually(*this, qualitative);
}
/*!

10
src/formula/Formulas.h

@ -10,11 +10,6 @@
#include "modelchecker/ForwardDeclarations.h"
#include "AbstractFormula.h"
#include "AbstractPathFormula.h"
#include "AbstractStateFormula.h"
#include "And.h"
#include "Ap.h"
#include "BoundedUntil.h"
@ -36,6 +31,11 @@
#include "RewardNoBoundOperator.h"
#include "SteadyStateOperator.h"
#include "AbstractFormula.h"
#include "AbstractPathFormula.h"
#include "AbstractStateFormula.h"
// FIXME: Why is this needed? To me this makes no sense.
#include "modelchecker/DtmcPrctlModelChecker.h"
#endif /* STORM_FORMULA_FORMULAS_H_ */

7
src/formula/Globally.h

@ -11,6 +11,7 @@
#include "AbstractPathFormula.h"
#include "AbstractStateFormula.h"
#include "src/formula/AbstractFormulaChecker.h"
#include "src/modelchecker/ForwardDeclarations.h"
namespace storm {
@ -33,7 +34,7 @@ class IGloballyModelChecker {
* @param obj Formula object with subformulas.
* @return Result of the formula for every node.
*/
virtual std::vector<T>* checkGlobally(const Globally<T>& obj) const = 0;
virtual std::vector<T>* checkGlobally(const Globally<T>& obj, bool qualitative) const = 0;
};
/*!
@ -131,8 +132,8 @@ public:
*
* @returns A vector indicating the probability that the formula holds for each state.
*/
virtual std::vector<T> *check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker) const {
return modelChecker.template as<IGloballyModelChecker>()->checkGlobally(*this);
virtual std::vector<T> *check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker, bool qualitative) const {
return modelChecker.template as<IGloballyModelChecker>()->checkGlobally(*this, qualitative);
}
/*!

6
src/formula/InstantaneousReward.h

@ -35,7 +35,7 @@ class IInstantaneousRewardModelChecker {
* @param obj Formula object with subformulas.
* @return Result of the formula for every node.
*/
virtual std::vector<T>* checkInstantaneousReward(const InstantaneousReward<T>& obj) const = 0;
virtual std::vector<T>* checkInstantaneousReward(const InstantaneousReward<T>& obj, bool qualitative) const = 0;
};
/*!
@ -121,8 +121,8 @@ public:
*
* @returns A vector indicating the probability that the formula holds for each state.
*/
virtual std::vector<T> *check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker) const {
return modelChecker.template as<IInstantaneousRewardModelChecker>()->checkInstantaneousReward(*this);
virtual std::vector<T> *check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker, bool qualitative) const {
return modelChecker.template as<IInstantaneousRewardModelChecker>()->checkInstantaneousReward(*this, qualitative);
}
/*!

6
src/formula/Next.h

@ -33,7 +33,7 @@ class INextModelChecker {
* @param obj Formula object with subformulas.
* @return Result of the formula for every node.
*/
virtual std::vector<T>* checkNext(const Next<T>& obj) const = 0;
virtual std::vector<T>* checkNext(const Next<T>& obj, bool qualitative) const = 0;
};
/*!
@ -133,8 +133,8 @@ public:
*
* @returns A vector indicating the probability that the formula holds for each state.
*/
virtual std::vector<T> *check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker) const {
return modelChecker.template as<INextModelChecker>()->checkNext(*this);
virtual std::vector<T> *check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker, bool qualitative) const {
return modelChecker.template as<INextModelChecker>()->checkNext(*this, qualitative);
}
/*!

59
src/formula/NoBoundOperator.h

@ -74,8 +74,8 @@ public:
/*!
* Empty constructor
*/
NoBoundOperator() {
this->pathFormula = NULL;
NoBoundOperator() : optimalityOperator(false), minimumOperator(false) {
this->pathFormula = nullptr;
}
/*!
@ -83,7 +83,19 @@ public:
*
* @param pathFormula The child node.
*/
NoBoundOperator(AbstractPathFormula<T>* pathFormula) {
NoBoundOperator(AbstractPathFormula<T>* pathFormula) : optimalityOperator(false), minimumOperator(false) {
this->pathFormula = pathFormula;
}
/*!
* Constructor
*
* @param pathFormula The child node.
* @param minimumOperator A flag indicating whether this operator is a minimizing or a
* maximizing operator.
*/
NoBoundOperator(AbstractPathFormula<T>* pathFormula, bool minimumOperator)
: optimalityOperator(true), minimumOperator(minimumOperator) {
this->pathFormula = pathFormula;
}
@ -130,7 +142,20 @@ public:
/*!
* @returns a string representation of the formula
*/
virtual std::string toString() const = 0;
virtual std::string toString() const {
std::string result;
if (this->isOptimalityOperator()) {
if (this->isMinimumOperator()) {
result += "min";
} else {
result += "max";
}
}
result += " = ? [";
result += this->getPathFormula().toString();
result += "]";
return result;
}
/*!
* @brief Checks if the subtree conforms to some logic.
@ -142,8 +167,34 @@ public:
return checker.conforms(this->pathFormula);
}
/*!
* Retrieves whether the operator is to be interpreted as an optimizing (i.e. min/max) operator.
* @returns True if the operator is an optimizing operator.
*/
bool isOptimalityOperator() const {
return optimalityOperator;
}
/*!
* Retrieves whether the operator is a minimizing operator given that it is an optimality
* operator.
* @returns True if the operator is an optimizing operator and it is a minimizing operator and
* false otherwise, i.e. if it is either not an optimizing operator or not a minimizing operator.
*/
bool isMinimumOperator() const {
return optimalityOperator && minimumOperator;
}
private:
AbstractPathFormula<T>* pathFormula;
// A flag that indicates whether this operator is meant as an optimizing (i.e. min/max) operator
// over a nondeterministic model.
bool optimalityOperator;
// In the case this operator is an optimizing operator, this flag indicates whether it is
// looking for the minimum or the maximum value.
bool minimumOperator;
};
} /* namespace formula */

2
src/formula/Not.h

@ -10,7 +10,7 @@
#include "AbstractStateFormula.h"
#include "src/formula/AbstractFormulaChecker.h"
#include "src/modelchecker/AbstractModelChecker.h"
#include "src/modelchecker/ForwardDeclarations.h"
namespace storm {

36
src/formula/PathBoundOperator.h

@ -11,7 +11,7 @@
#include "src/formula/AbstractStateFormula.h"
#include "src/formula/AbstractPathFormula.h"
#include "src/formula/AbstractFormulaChecker.h"
#include "src/modelchecker/AbstractModelChecker.h"
#include "src/modelchecker/ForwardDeclarations.h"
#include "src/utility/ConstTemplates.h"
namespace storm {
@ -20,18 +20,6 @@ namespace formula {
template <class T> class PathBoundOperator;
/*!
* @brief Interface class for model checkers that support PathBoundOperator.
*
* All model checkers that support the formula class PathBoundOperator must inherit
* this pure virtual class.
*/
template <class T>
class IPathBoundOperatorModelChecker {
public:
virtual storm::storage::BitVector* checkPathBoundOperator(const PathBoundOperator<T>& obj) const = 0;
};
/*!
* @brief
* Class for a Abstract formula tree with a P (probablistic) operator node over a probability interval
@ -132,11 +120,12 @@ public:
virtual std::string toString() const {
std::string result = "";
switch (comparisonOperator) {
case LESS: result += "< "; break;
case LESS_EQUAL: result += "<= "; break;
case GREATER: result += "> "; break;
case GREATER_EQUAL: result += ">= "; break;
case LESS: result += "<"; break;
case LESS_EQUAL: result += "<="; break;
case GREATER: result += ">"; break;
case GREATER_EQUAL: result += ">="; break;
}
result += " ";
result += std::to_string(bound);
result += " [";
result += pathFormula->toString();
@ -163,19 +152,6 @@ public:
*/
virtual AbstractStateFormula<T>* clone() const = 0;
/*!
* Calls the model checker to check this formula.
* Needed to infer the correct type of formula class.
*
* @note This function should only be called in a generic check function of a model checker class. For other uses,
* the methods of the model checker should be used.
*
* @returns A bit vector indicating all states that satisfy the formula represented by the called object.
*/
virtual storm::storage::BitVector *check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker) const {
return modelChecker.template as<IPathBoundOperatorModelChecker>()->checkPathBoundOperator(*this);
}
/*!
* @brief Checks if the subtree conforms to some logic.
*

11
src/formula/PrctlFormulaChecker.h

@ -21,18 +21,21 @@ class PrctlFormulaChecker : public AbstractFormulaChecker<T> {
/*!
* Implementation of AbstractFormulaChecker::conforms() using code
* looking exactly like the sample code given there.
*
* We currently allow And, Ap, Eventually, Not, Or,
* ProbabilisticNoBoundOperator.
*/
virtual bool conforms(const AbstractFormula<T>* formula) const {
// What to support: Principles of Model Checking Def. 10.76 + syntactic sugar
if (
dynamic_cast<const And<T>*>(formula) ||
dynamic_cast<const Ap<T>*>(formula) ||
dynamic_cast<const BoundedUntil<T>*>(formula) ||
dynamic_cast<const Eventually<T>*>(formula) ||
dynamic_cast<const Globally<T>*>(formula) ||
dynamic_cast<const Next<T>*>(formula) ||
dynamic_cast<const Not<T>*>(formula) ||
dynamic_cast<const Or<T>*>(formula) ||
dynamic_cast<const ProbabilisticNoBoundOperator<T>*>(formula)
dynamic_cast<const ProbabilisticNoBoundOperator<T>*>(formula) ||
dynamic_cast<const ProbabilisticBoundOperator<T>*>(formula) ||
dynamic_cast<const Until<T>*>(formula)
) {
return formula->conforms(*this);
}

27
src/formula/ProbabilisticBoundOperator.h

@ -16,6 +16,20 @@
namespace storm {
namespace formula {
template <class T> class ProbabilisticBoundOperator;
/*!
* @brief Interface class for model checkers that support ProbabilisticBoundOperator.
*
* All model checkers that support the formula class PathBoundOperator must inherit
* this pure virtual class.
*/
template <class T>
class IProbabilisticBoundOperatorModelChecker {
public:
virtual storm::storage::BitVector* checkProbabilisticBoundOperator(const ProbabilisticBoundOperator<T>& obj) const = 0;
};
/*!
* @brief
* Class for a Abstract formula tree with a P (probablistic) operator node over a probability interval
@ -86,6 +100,19 @@ public:
result->setPathFormula(this->getPathFormula().clone());
return result;
}
/*!
* Calls the model checker to check this formula.
* Needed to infer the correct type of formula class.
*
* @note This function should only be called in a generic check function of a model checker class. For other uses,
* the methods of the model checker should be used.
*
* @returns A bit vector indicating all states that satisfy the formula represented by the called object.
*/
virtual storm::storage::BitVector* check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker) const {
return modelChecker.template as<IProbabilisticBoundOperatorModelChecker>()->checkProbabilisticBoundOperator(*this);
}
};
} //namespace formula

14
src/formula/ProbabilisticNoBoundOperator.h

@ -64,13 +64,21 @@ public:
// Intentionally left empty
}
/*!
* Constructor
*
* @param pathFormula The child node.
*/
ProbabilisticNoBoundOperator(AbstractPathFormula<T>* pathFormula, bool minimumOperator) : NoBoundOperator<T>(pathFormula, minimumOperator) {
// Intentionally left empty
}
/*!
* @returns a string representation of the formula
*/
virtual std::string toString() const {
std::string result = "P = ? [";
result += this->getPathFormula().toString();
result += "]";
std::string result = "P";
result += NoBoundOperator<T>::toString();
return result;
}
};

7
src/formula/ReachabilityReward.h

@ -11,7 +11,6 @@
#include "src/formula/AbstractPathFormula.h"
#include "src/formula/AbstractStateFormula.h"
#include "src/formula/AbstractFormulaChecker.h"
#include "src/modelchecker/AbstractModelChecker.h"
namespace storm {
namespace formula {
@ -33,7 +32,7 @@ class IReachabilityRewardModelChecker {
* @param obj Formula object with subformulas.
* @return Result of the formula for every node.
*/
virtual std::vector<T>* checkReachabilityReward(const ReachabilityReward<T>& obj) const = 0;
virtual std::vector<T>* checkReachabilityReward(const ReachabilityReward<T>& obj, bool qualitative) const = 0;
};
/*!
@ -128,8 +127,8 @@ public:
*
* @returns A vector indicating the probability that the formula holds for each state.
*/
virtual std::vector<T> *check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker) const {
return modelChecker.template as<IReachabilityRewardModelChecker>()->checkReachabilityReward(*this);
virtual std::vector<T> *check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker, bool qualitative) const {
return modelChecker.template as<IReachabilityRewardModelChecker>()->checkReachabilityReward(*this, qualitative);
}
/*!

27
src/formula/RewardBoundOperator.h

@ -16,6 +16,20 @@
namespace storm {
namespace formula {
template <class T> class RewardBoundOperator;
/*!
* @brief Interface class for model checkers that support RewardBoundOperator.
*
* All model checkers that support the formula class PathBoundOperator must inherit
* this pure virtual class.
*/
template <class T>
class IRewardBoundOperatorModelChecker {
public:
virtual storm::storage::BitVector* checkRewardBoundOperator(const RewardBoundOperator<T>& obj) const = 0;
};
/*!
* @brief
* Class for a Abstract formula tree with a R (reward) operator node over a reward interval as root.
@ -83,6 +97,19 @@ public:
result->setPathFormula(this->getPathFormula().clone());
return result;
}
/*!
* Calls the model checker to check this formula.
* Needed to infer the correct type of formula class.
*
* @note This function should only be called in a generic check function of a model checker class. For other uses,
* the methods of the model checker should be used.
*
* @returns A bit vector indicating all states that satisfy the formula represented by the called object.
*/
virtual storm::storage::BitVector* check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker) const {
return modelChecker.template as<IRewardBoundOperatorModelChecker>()->checkRewardBoundOperator(*this);
}
};
} //namespace formula

14
src/formula/RewardNoBoundOperator.h

@ -64,13 +64,21 @@ public:
// Intentionally left empty
}
/*!
* Constructor
*
* @param pathFormula The child node.
*/
RewardNoBoundOperator(AbstractPathFormula<T>* pathFormula, bool minimumOperator) : NoBoundOperator<T>(pathFormula, minimumOperator) {
// Intentionally left empty
}
/*!
* @returns a string representation of the formula
*/
virtual std::string toString() const {
std::string result = "R = ? [";
result += this->getPathFormula().toString();
result += "]";
std::string result = "R";
result += NoBoundOperator<T>::toString();
return result;
}
};

6
src/formula/Until.h

@ -32,7 +32,7 @@ class IUntilModelChecker {
* @param obj Formula object with subformulas.
* @return Result of the formula for every node.
*/
virtual std::vector<T>* checkUntil(const Until<T>& obj) const = 0;
virtual std::vector<T>* checkUntil(const Until<T>& obj, bool qualitative) const = 0;
};
/*!
@ -158,8 +158,8 @@ public:
*
* @returns A vector indicating the probability that the formula holds for each state.
*/
virtual std::vector<T> *check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker) const {
return modelChecker.template as<IUntilModelChecker>()->checkUntil(*this);
virtual std::vector<T> *check(const storm::modelChecker::AbstractModelChecker<T>& modelChecker, bool qualitative) const {
return modelChecker.template as<IUntilModelChecker>()->checkUntil(*this, qualitative);
}
/*!

139
src/modelchecker/AbstractModelChecker.h

@ -12,10 +12,10 @@ namespace storm { namespace modelChecker {
template <class Type> class AbstractModelChecker;
}}
//#include "src/formula/Formulas.h"
#include "src/formula/Or.h"
#include "src/formula/Ap.h"
#include "src/exceptions/InvalidPropertyException.h"
#include "src/formula/Formulas.h"
#include "src/storage/BitVector.h"
#include "src/models/AbstractModel.h"
#include <iostream>
@ -33,11 +33,33 @@ namespace modelChecker {
*/
template<class Type>
class AbstractModelChecker :
public virtual storm::formula::IApModelChecker<Type>,
public virtual storm::formula::IAndModelChecker<Type>,
public virtual storm::formula::IOrModelChecker<Type>,
public virtual storm::formula::IApModelChecker<Type>
{
public virtual storm::formula::INotModelChecker<Type>,
public virtual storm::formula::IUntilModelChecker<Type>,
public virtual storm::formula::IEventuallyModelChecker<Type>,
public virtual storm::formula::IGloballyModelChecker<Type>,
public virtual storm::formula::INextModelChecker<Type>,
public virtual storm::formula::IBoundedUntilModelChecker<Type>,
public virtual storm::formula::IBoundedEventuallyModelChecker<Type>,
public virtual storm::formula::INoBoundOperatorModelChecker<Type>,
public virtual storm::formula::IProbabilisticBoundOperatorModelChecker<Type>,
public virtual storm::formula::IRewardBoundOperatorModelChecker<Type>,
public virtual storm::formula::IReachabilityRewardModelChecker<Type>,
public virtual storm::formula::ICumulativeRewardModelChecker<Type>,
public virtual storm::formula::IInstantaneousRewardModelChecker<Type> {
public:
explicit AbstractModelChecker(storm::models::AbstractModel<Type>& model)
: model(model) {
// Nothing to do here...
}
explicit AbstractModelChecker(AbstractModelChecker<Type>* modelChecker)
: model(modelChecker->model) {
}
template <template <class T> class Target>
const Target<Type>* as() const {
try {
@ -48,6 +70,113 @@ public:
}
return nullptr;
}
/*!
* The check method for a state formula with an And node as root in its formula tree
*
* @param formula The And formula to check
* @returns The set of states satisfying the formula, represented by a bit vector
*/
storm::storage::BitVector* checkAnd(const storm::formula::And<Type>& formula) const {
storm::storage::BitVector* result = formula.getLeft().check(*this);
storm::storage::BitVector* right = formula.getRight().check(*this);
(*result) &= (*right);
delete right;
return result;
}
/*!
* The check method for a formula with a Not node as root in its formula tree
*
* @param formula The Not state formula to check
* @returns The set of states satisfying the formula, represented by a bit vector
*/
storm::storage::BitVector* checkNot(const storm::formula::Not<Type>& formula) const {
storm::storage::BitVector* result = formula.getChild().check(*this);
result->complement();
return result;
}
/*!
* The check method for a state formula with an Or node as root in its formula tree
*
* @param formula The Or state formula to check
* @returns The set of states satisfying the formula, represented by a bit vector
*/
virtual storm::storage::BitVector* checkOr(const storm::formula::Or<Type>& formula) const {
storm::storage::BitVector* result = formula.getLeft().check(*this);
storm::storage::BitVector* right = formula.getRight().check(*this);
(*result) |= (*right);
delete right;
return result;
}
/*!
* The check method for a state formula with a bound operator node as root in
* its formula tree
*
* @param formula The state formula to check
* @returns The set of states satisfying the formula, represented by a bit vector
*/
storm::storage::BitVector* checkProbabilisticBoundOperator(const storm::formula::ProbabilisticBoundOperator<Type>& formula) const {
// First, we need to compute the probability for satisfying the path formula for each state.
std::vector<Type>* quantitativeResult = formula.getPathFormula().check(*this, false);
// Create resulting bit vector, which will hold the yes/no-answer for every state.
storm::storage::BitVector* result = new storm::storage::BitVector(quantitativeResult->size());
// Now, we can compute which states meet the bound specified in this operator and set the
// corresponding bits to true in the resulting vector.
for (uint_fast64_t i = 0; i < quantitativeResult->size(); ++i) {
if (formula.meetsBound((*quantitativeResult)[i])) {
result->set(i, true);
}
}
// Delete the probabilities computed for the states and return result.
delete quantitativeResult;
return result;
}
/*!
* The check method for a state formula with a bound operator node as root in
* its formula tree
*
* @param formula The state formula to check
* @returns The set of states satisfying the formula, represented by a bit vector
*/
storm::storage::BitVector* checkRewardBoundOperator(const storm::formula::RewardBoundOperator<Type>& formula) const {
// First, we need to compute the probability for satisfying the path formula for each state.
std::vector<Type>* quantitativeResult = formula.getPathFormula().check(*this, false);
// Create resulting bit vector, which will hold the yes/no-answer for every state.
storm::storage::BitVector* result = new storm::storage::BitVector(quantitativeResult->size());
// Now, we can compute which states meet the bound specified in this operator and set the
// corresponding bits to true in the resulting vector.
for (uint_fast64_t i = 0; i < quantitativeResult->size(); ++i) {
if (formula.meetsBound((*quantitativeResult)[i])) {
result->set(i, true);
}
}
// Delete the probabilities computed for the states and return result.
delete quantitativeResult;
return result;
}
void setModel(storm::models::AbstractModel<Type>& model) {
this->model = model;
}
template <class Model>
Model& getModel() const {
return *dynamic_cast<Model*>(&this->model);
}
private:
storm::models::AbstractModel<Type>& model;
};
} //namespace modelChecker

182
src/modelchecker/DtmcPrctlModelChecker.h

@ -39,19 +39,17 @@ namespace modelChecker {
*/
template<class Type>
class DtmcPrctlModelChecker :
public virtual AbstractModelChecker<Type>,
public virtual storm::formula::INoBoundOperatorModelChecker<Type>,
public virtual storm::formula::IReachabilityRewardModelChecker<Type>,
public virtual storm::formula::IEventuallyModelChecker<Type>
{
public AbstractModelChecker<Type> {
public:
/*!
* Constructor
*
* @param model The dtmc model which is checked.
*/
explicit DtmcPrctlModelChecker(storm::models::Dtmc<Type>& model) : model(model) {
explicit DtmcPrctlModelChecker(storm::models::Dtmc<Type>& model)
: AbstractModelChecker<Type>(model) {
// Intentionally left empty.
}
/*!
@ -59,8 +57,7 @@ public:
*
* @param modelChecker The model checker that is copied.
*/
explicit DtmcPrctlModelChecker(const storm::modelChecker::DtmcPrctlModelChecker<Type>* modelChecker) {
this->model = new storm::models::Dtmc<Type>(modelChecker->getModel());
explicit DtmcPrctlModelChecker(const storm::modelChecker::DtmcPrctlModelChecker<Type>* modelChecker) : AbstractModelChecker<Type>(modelChecker) {
}
/*!
@ -74,7 +71,7 @@ public:
* @returns A reference to the dtmc of the model checker.
*/
storm::models::Dtmc<Type>& getModel() const {
return this->model;
return AbstractModelChecker<Type>::template getModel<storm::models::Dtmc<Type>>();
}
/*!
@ -82,7 +79,28 @@ public:
* @param model
*/
void setModel(storm::models::Dtmc<Type>& model) {
this->model = &model;
AbstractModelChecker<Type>::setModel(model);
}
/*!
* The check method for a formula with an AP node as root in its formula tree
*
* @param formula The Ap state formula to check
* @returns The set of states satisfying the formula, represented by a bit vector
*/
storm::storage::BitVector* checkAp(const storm::formula::Ap<Type>& formula) const {
if (formula.getAp().compare("true") == 0) {
return new storm::storage::BitVector(this->getModel().getNumberOfStates(), true);
} else if (formula.getAp().compare("false") == 0) {
return new storm::storage::BitVector(this->getModel().getNumberOfStates());
}
if (!this->getModel().hasAtomicProposition(formula.getAp())) {
LOG4CPLUS_ERROR(logger, "Atomic proposition '" << formula.getAp() << "' is invalid.");
throw storm::exceptions::InvalidPropertyException() << "Atomic proposition '" << formula.getAp() << "' is invalid.";
}
return new storm::storage::BitVector(*this->getModel().getLabeledStates(formula.getAp()));
}
/*!
@ -143,105 +161,6 @@ public:
storm::utility::printSeparationLine(std::cout);
}
/*!
* The check method for a state formula; Will infer the actual type of formula and delegate it
* to the specialized method
*
* @param formula The state formula to check
* @returns The set of states satisfying the formula, represented by a bit vector
*/
storm::storage::BitVector* checkStateFormula(const storm::formula::AbstractStateFormula<Type>& formula) const {
return formula.check(*this);
}
/*!
* The check method for a state formula with an And node as root in its formula tree
*
* @param formula The And formula to check
* @returns The set of states satisfying the formula, represented by a bit vector
*/
storm::storage::BitVector* checkAnd(const storm::formula::And<Type>& formula) const {
storm::storage::BitVector* result = checkStateFormula(formula.getLeft());
storm::storage::BitVector* right = checkStateFormula(formula.getRight());
(*result) &= (*right);
delete right;
return result;
}
/*!
* The check method for a formula with an AP node as root in its formula tree
*
* @param formula The Ap state formula to check
* @returns The set of states satisfying the formula, represented by a bit vector
*/
storm::storage::BitVector* checkAp(const storm::formula::Ap<Type>& formula) const {
if (formula.getAp().compare("true") == 0) {
return new storm::storage::BitVector(this->getModel().getNumberOfStates(), true);
} else if (formula.getAp().compare("false") == 0) {
return new storm::storage::BitVector(this->getModel().getNumberOfStates());
}
if (!this->getModel().hasAtomicProposition(formula.getAp())) {
throw storm::exceptions::InvalidPropertyException() << "Atomic proposition '" << formula.getAp() << "' is invalid.";
return nullptr;
}
return new storm::storage::BitVector(*this->getModel().getLabeledStates(formula.getAp()));
}
/*!
* The check method for a formula with a Not node as root in its formula tree
*
* @param formula The Not state formula to check
* @returns The set of states satisfying the formula, represented by a bit vector
*/
storm::storage::BitVector* checkNot(const storm::formula::Not<Type>& formula) const {
storm::storage::BitVector* result = checkStateFormula(formula.getChild());
result->complement();
return result;
}
/*!
* The check method for a state formula with an Or node as root in its formula tree
*
* @param formula The Or state formula to check
* @returns The set of states satisfying the formula, represented by a bit vector
*/
virtual storm::storage::BitVector* checkOr(const storm::formula::Or<Type>& formula) const {
storm::storage::BitVector* result = checkStateFormula(formula.getLeft());
storm::storage::BitVector* right = checkStateFormula(formula.getRight());
(*result) |= (*right);
delete right;
return result;
}
/*!
* The check method for a state formula with a bound operator node as root in
* its formula tree
*
* @param formula The state formula to check
* @returns The set of states satisfying the formula, represented by a bit vector
*/
storm::storage::BitVector* checkPathBoundOperator(const storm::formula::PathBoundOperator<Type>& formula) const {
// First, we need to compute the probability for satisfying the path formula for each state.
std::vector<Type>* quantitativeResult = this->checkPathFormula(formula.getPathFormula());
// Create resulting bit vector, which will hold the yes/no-answer for every state.
storm::storage::BitVector* result = new storm::storage::BitVector(this->getModel().getNumberOfStates());
// Now, we can compute which states meet the bound specified in this operator and set the
// corresponding bits to true in the resulting vector.
for (uint_fast64_t i = 0; i < this->getModel().getNumberOfStates(); ++i) {
if (formula.meetsBound((*quantitativeResult)[i])) {
result->set(i, true);
}
}
// Delete the probabilities computed for the states and return result.
delete quantitativeResult;
return result;
}
/*!
* The check method for a state formula with a probabilistic operator node without bounds as root
* in its formula tree
@ -250,18 +169,11 @@ public:
* @returns The set of states satisfying the formula, represented by a bit vector
*/
std::vector<Type>* checkNoBoundOperator(const storm::formula::NoBoundOperator<Type>& formula) const {
return formula.getPathFormula().check(*this);
}
/*!
* The check method for a path formula; Will infer the actual type of formula and delegate it
* to the specialized method
*
* @param formula The path formula to check
* @returns for each state the probability that the path formula holds.
*/
std::vector<Type>* checkPathFormula(const storm::formula::AbstractPathFormula<Type>& formula) const {
return formula.check(*this);
// Check if the operator was an optimality operator and report a warning in that case.
if (formula.isOptimalityOperator()) {
LOG4CPLUS_WARN(logger, "Formula contains min/max operator which is not meaningful over deterministic models.");
}
return formula.getPathFormula().check(*this, false);
}
/*!
@ -270,7 +182,7 @@ public:
* @param formula The Bounded Until path formula to check
* @returns for each state the probability that the path formula holds.
*/
virtual std::vector<Type>* checkBoundedUntil(const storm::formula::BoundedUntil<Type>& formula) const = 0;
virtual std::vector<Type>* checkBoundedUntil(const storm::formula::BoundedUntil<Type>& formula, bool qualitative) const = 0;
/*!
* The check method for a path formula with a Next operator node as root in its formula tree
@ -278,7 +190,7 @@ public:
* @param formula The Next path formula to check
* @returns for each state the probability that the path formula holds.
*/
virtual std::vector<Type>* checkNext(const storm::formula::Next<Type>& formula) const = 0;
virtual std::vector<Type>* checkNext(const storm::formula::Next<Type>& formula, bool qualitative) const = 0;
/*!
* The check method for a path formula with a Bounded Eventually operator node as root in its
@ -287,10 +199,10 @@ public:
* @param formula The Bounded Eventually path formula to check
* @returns for each state the probability that the path formula holds
*/
virtual std::vector<Type>* checkBoundedEventually(const storm::formula::BoundedEventually<Type>& formula) const {
virtual std::vector<Type>* checkBoundedEventually(const storm::formula::BoundedEventually<Type>& formula, bool qualitative) const {
// Create equivalent temporary bounded until formula and check it.
storm::formula::BoundedUntil<Type> temporaryBoundedUntilFormula(new storm::formula::Ap<Type>("true"), formula.getChild().clone(), formula.getBound());
return this->checkBoundedUntil(temporaryBoundedUntilFormula);
return this->checkBoundedUntil(temporaryBoundedUntilFormula, qualitative);
}
/*!
@ -299,10 +211,10 @@ public:
* @param formula The Eventually path formula to check
* @returns for each state the probability that the path formula holds
*/
virtual std::vector<Type>* checkEventually(const storm::formula::Eventually<Type>& formula) const {
virtual std::vector<Type>* checkEventually(const storm::formula::Eventually<Type>& formula, bool qualitative) const {
// Create equivalent temporary until formula and check it.
storm::formula::Until<Type> temporaryUntilFormula(new storm::formula::Ap<Type>("true"), formula.getChild().clone());
return this->checkUntil(temporaryUntilFormula);
return this->checkUntil(temporaryUntilFormula, qualitative);
}
/*!
@ -311,10 +223,10 @@ public:
* @param formula The Globally path formula to check
* @returns for each state the probability that the path formula holds
*/
virtual std::vector<Type>* checkGlobally(const storm::formula::Globally<Type>& formula) const {
virtual std::vector<Type>* checkGlobally(const storm::formula::Globally<Type>& formula, bool qualitative) const {
// Create "equivalent" temporary eventually formula and check it.
storm::formula::Eventually<Type> temporaryEventuallyFormula(new storm::formula::Not<Type>(formula.getChild().clone()));
std::vector<Type>* result = this->checkEventually(temporaryEventuallyFormula);
std::vector<Type>* result = this->checkEventually(temporaryEventuallyFormula, qualitative);
// Now subtract the resulting vector from the constant one vector to obtain final result.
storm::utility::subtractFromConstantOneVector(result);
@ -327,7 +239,7 @@ public:
* @param formula The Until path formula to check
* @returns for each state the probability that the path formula holds.
*/
virtual std::vector<Type>* checkUntil(const storm::formula::Until<Type>& formula) const = 0;
virtual std::vector<Type>* checkUntil(const storm::formula::Until<Type>& formula, bool qualitative) const = 0;
/*!
* The check method for a path formula with an Instantaneous Reward operator node as root in its
@ -336,7 +248,7 @@ public:
* @param formula The Instantaneous Reward formula to check
* @returns for each state the reward that the instantaneous reward yields
*/
virtual std::vector<Type>* checkInstantaneousReward(const storm::formula::InstantaneousReward<Type>& formula) const = 0;
virtual std::vector<Type>* checkInstantaneousReward(const storm::formula::InstantaneousReward<Type>& formula, bool qualitative) const = 0;
/*!
* The check method for a path formula with a Cumulative Reward operator node as root in its
@ -345,7 +257,7 @@ public:
* @param formula The Cumulative Reward formula to check
* @returns for each state the reward that the cumulative reward yields
*/
virtual std::vector<Type>* checkCumulativeReward(const storm::formula::CumulativeReward<Type>& formula) const = 0;
virtual std::vector<Type>* checkCumulativeReward(const storm::formula::CumulativeReward<Type>& formula, bool qualitative) const = 0;
/*!
* The check method for a path formula with a Reachability Reward operator node as root in its
@ -354,10 +266,10 @@ public:
* @param formula The Reachbility Reward formula to check
* @returns for each state the reward that the reachability reward yields
*/
virtual std::vector<Type>* checkReachabilityReward(const storm::formula::ReachabilityReward<Type>& formula) const = 0;
virtual std::vector<Type>* checkReachabilityReward(const storm::formula::ReachabilityReward<Type>& formula, bool qualitative) const = 0;
private:
storm::models::Dtmc<Type>& model;
// storm::models::Dtmc<Type>& model;
};
} //namespace modelChecker

21
src/modelchecker/EigenDtmcPrctlModelChecker.h

@ -12,7 +12,7 @@
#include "src/models/Dtmc.h"
#include "src/modelchecker/DtmcPrctlModelChecker.h"
#include "src/solver/GraphAnalyzer.h"
#include "src/utility/GraphAnalyzer.h"
#include "src/utility/ConstTemplates.h"
#include "src/exceptions/NoConvergenceException.h"
@ -126,17 +126,16 @@ public:
// Then, we need to identify the states which have to be taken out of the matrix, i.e.
// all states that have probability 0 and 1 of satisfying the until-formula.
storm::storage::BitVector notExistsPhiUntilPsiStates(this->getModel().getNumberOfStates());
storm::storage::BitVector alwaysPhiUntilPsiStates(this->getModel().getNumberOfStates());
storm::solver::GraphAnalyzer::getPhiUntilPsiStates<double>(this->getModel(), *leftStates, *rightStates, &notExistsPhiUntilPsiStates, &alwaysPhiUntilPsiStates);
notExistsPhiUntilPsiStates.complement();
storm::storage::BitVector statesWithProbability0(this->getModel().getNumberOfStates());
storm::storage::BitVector statesWithProbability1(this->getModel().getNumberOfStates());
storm::utility::GraphAnalyzer::performProb01(this->getModel(), *leftStates, *rightStates, &statesWithProbability0, &statesWithProbability1);
delete leftStates;
delete rightStates;
LOG4CPLUS_INFO(logger, "Found " << notExistsPhiUntilPsiStates.getNumberOfSetBits() << " 'no' states.");
LOG4CPLUS_INFO(logger, "Found " << alwaysPhiUntilPsiStates.getNumberOfSetBits() << " 'yes' states.");
storm::storage::BitVector maybeStates = ~(notExistsPhiUntilPsiStates | alwaysPhiUntilPsiStates);
LOG4CPLUS_INFO(logger, "Found " << statesWithProbability0.getNumberOfSetBits() << " 'no' states.");
LOG4CPLUS_INFO(logger, "Found " << statesWithProbability1.getNumberOfSetBits() << " 'yes' states.");
storm::storage::BitVector maybeStates = ~(statesWithProbability0 | statesWithProbability1);
LOG4CPLUS_INFO(logger, "Found " << maybeStates.getNumberOfSetBits() << " 'maybe' states.");
// Create resulting vector and set values accordingly.
@ -175,7 +174,7 @@ public:
Type *pb = &(b[0]); // get the address storing the data for b
MapType vectorB(pb, b.size()); // vectorB shares data
this->getModel().getTransitionProbabilityMatrix()->getConstrainedRowCountVector(maybeStates, alwaysPhiUntilPsiStates, &x);
this->getModel().getTransitionProbabilityMatrix()->getConstrainedRowCountVector(maybeStates, statesWithProbability1, &x);
Eigen::BiCGSTAB<Eigen::SparseMatrix<Type, 1, int_fast32_t>> solver;
solver.compute(*eigenSubMatrix);
@ -212,8 +211,8 @@ public:
delete eigenSubMatrix;
}
storm::utility::setVectorValues<Type>(result, notExistsPhiUntilPsiStates, storm::utility::constGetZero<Type>());
storm::utility::setVectorValues<Type>(result, alwaysPhiUntilPsiStates, storm::utility::constGetOne<Type>());
storm::utility::setVectorValues<Type>(result, statesWithProbability0, storm::utility::constGetZero<Type>());
storm::utility::setVectorValues<Type>(result, statesWithProbability1, storm::utility::constGetOne<Type>());
return result;
}

3
src/modelchecker/ForwardDeclarations.h

@ -13,6 +13,9 @@ namespace storm {
namespace modelChecker {
template <class Type>
class AbstractModelChecker;
template <class Type>
class DtmcPrctlModelChecker;

96
src/modelchecker/GmmxxDtmcPrctlModelChecker.h

@ -12,7 +12,7 @@
#include "src/models/Dtmc.h"
#include "src/modelchecker/DtmcPrctlModelChecker.h"
#include "src/solver/GraphAnalyzer.h"
#include "src/utility/GraphAnalyzer.h"
#include "src/utility/Vector.h"
#include "src/utility/ConstTemplates.h"
#include "src/utility/Settings.h"
@ -36,20 +36,24 @@ namespace modelChecker {
* A model checking engine that makes use of the gmm++ backend.
*/
template <class Type>
class GmmxxDtmcPrctlModelChecker : public DtmcPrctlModelChecker<Type> {
class GmmxxDtmcPrctlModelChecker
: public DtmcPrctlModelChecker<Type> {
public:
explicit GmmxxDtmcPrctlModelChecker(storm::models::Dtmc<Type>& dtmc) : DtmcPrctlModelChecker<Type>(dtmc) { }
explicit GmmxxDtmcPrctlModelChecker(storm::models::Dtmc<Type>& dtmc)
: DtmcPrctlModelChecker<Type>(dtmc) {
// Intentionally left empty.
}
virtual ~GmmxxDtmcPrctlModelChecker() { }
virtual std::vector<Type>* checkBoundedUntil(const storm::formula::BoundedUntil<Type>& formula) const {
virtual std::vector<Type>* checkBoundedUntil(const storm::formula::BoundedUntil<Type>& formula, bool qualitative) const {
// First, we need to compute the states that satisfy the sub-formulas of the until-formula.
storm::storage::BitVector* leftStates = this->checkStateFormula(formula.getLeft());
storm::storage::BitVector* rightStates = this->checkStateFormula(formula.getRight());
storm::storage::BitVector* leftStates = formula.getLeft().check(*this);
storm::storage::BitVector* rightStates = formula.getRight().check(*this);
// Copy the matrix before we make any changes.
storm::storage::SparseMatrix<Type> tmpMatrix(*this->getModel().getTransitionProbabilityMatrix());
storm::storage::SparseMatrix<Type> tmpMatrix(*this->getModel().getTransitionMatrix());
// Make all rows absorbing that violate both sub-formulas or satisfy the second sub-formula.
tmpMatrix.makeRowsAbsorbing(~(*leftStates | *rightStates) | *rightStates);
@ -79,12 +83,12 @@ public:
return result;
}
virtual std::vector<Type>* checkNext(const storm::formula::Next<Type>& formula) const {
virtual std::vector<Type>* checkNext(const storm::formula::Next<Type>& formula, bool qualitative) const {
// First, we need to compute the states that satisfy the sub-formula of the next-formula.
storm::storage::BitVector* nextStates = this->checkStateFormula(formula.getChild());
storm::storage::BitVector* nextStates = formula.getChild().check(*this);
// Transform the transition probability matrix to the gmm++ format to use its arithmetic.
gmm::csr_matrix<Type>* gmmxxMatrix = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(*this->getModel().getTransitionProbabilityMatrix());
gmm::csr_matrix<Type>* gmmxxMatrix = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(*this->getModel().getTransitionMatrix());
// Create the vector with which to multiply and initialize it correctly.
std::vector<Type> x(this->getModel().getNumberOfStates());
@ -104,25 +108,24 @@ public:
return result;
}
virtual std::vector<Type>* checkUntil(const storm::formula::Until<Type>& formula) const {
virtual std::vector<Type>* checkUntil(const storm::formula::Until<Type>& formula, bool qualitative) const {
// First, we need to compute the states that satisfy the sub-formulas of the until-formula.
storm::storage::BitVector* leftStates = this->checkStateFormula(formula.getLeft());
storm::storage::BitVector* rightStates = this->checkStateFormula(formula.getRight());
storm::storage::BitVector* leftStates = formula.getLeft().check(*this);
storm::storage::BitVector* rightStates = formula.getRight().check(*this);
// Then, we need to identify the states which have to be taken out of the matrix, i.e.
// all states that have probability 0 and 1 of satisfying the until-formula.
storm::storage::BitVector notExistsPhiUntilPsiStates(this->getModel().getNumberOfStates());
storm::storage::BitVector alwaysPhiUntilPsiStates(this->getModel().getNumberOfStates());
storm::solver::GraphAnalyzer::getPhiUntilPsiStates(this->getModel(), *leftStates, *rightStates, &notExistsPhiUntilPsiStates, &alwaysPhiUntilPsiStates);
notExistsPhiUntilPsiStates.complement();
storm::storage::BitVector statesWithProbability0(this->getModel().getNumberOfStates());
storm::storage::BitVector statesWithProbability1(this->getModel().getNumberOfStates());
storm::utility::GraphAnalyzer::performProb01(this->getModel(), *leftStates, *rightStates, &statesWithProbability0, &statesWithProbability1);
// Delete sub-results that are obsolete now.
delete leftStates;
delete rightStates;
LOG4CPLUS_INFO(logger, "Found " << notExistsPhiUntilPsiStates.getNumberOfSetBits() << " 'no' states.");
LOG4CPLUS_INFO(logger, "Found " << alwaysPhiUntilPsiStates.getNumberOfSetBits() << " 'yes' states.");
storm::storage::BitVector maybeStates = ~(notExistsPhiUntilPsiStates | alwaysPhiUntilPsiStates);
LOG4CPLUS_INFO(logger, "Found " << statesWithProbability0.getNumberOfSetBits() << " 'no' states.");
LOG4CPLUS_INFO(logger, "Found " << statesWithProbability1.getNumberOfSetBits() << " 'yes' states.");
storm::storage::BitVector maybeStates = ~(statesWithProbability0 | statesWithProbability1);
LOG4CPLUS_INFO(logger, "Found " << maybeStates.getNumberOfSetBits() << " 'maybe' states.");
// Create resulting vector.
@ -130,9 +133,9 @@ public:
// Only try to solve system if there are states for which the probability is unknown.
uint_fast64_t mayBeStatesSetBitCount = maybeStates.getNumberOfSetBits();
if (mayBeStatesSetBitCount > 0) {
if (mayBeStatesSetBitCount > 0 && !qualitative) {
// Now we can eliminate the rows and columns from the original transition probability matrix.
storm::storage::SparseMatrix<Type>* submatrix = this->getModel().getTransitionProbabilityMatrix()->getSubmatrix(maybeStates);
storm::storage::SparseMatrix<Type>* submatrix = this->getModel().getTransitionMatrix()->getSubmatrix(maybeStates);
// Converting the matrix from the fixpoint notation to the form needed for the equation
// system. That is, we go from x = A*x + b to (I-A)x = b.
submatrix->convertToEquationSystem();
@ -149,7 +152,7 @@ public:
// Prepare the right-hand side of the equation system. For entry i this corresponds to
// the accumulated probability of going from state i to some 'yes' state.
std::vector<Type> b(mayBeStatesSetBitCount);
this->getModel().getTransitionProbabilityMatrix()->getConstrainedRowCountVector(maybeStates, alwaysPhiUntilPsiStates, &b);
this->getModel().getTransitionMatrix()->getConstrainedRowSumVector(maybeStates, statesWithProbability1, &b);
// Solve the corresponding system of linear equations.
this->solveLinearEquationSystem(*gmmxxMatrix, x, b);
@ -159,16 +162,20 @@ public:
// Delete temporary matrix.
delete gmmxxMatrix;
} else if (qualitative) {
// If we only need a qualitative result, we can safely assume that the results will only be compared to
// bounds which are either 0 or 1. Setting the value to 0.5 is thus safe.
storm::utility::setVectorValues<Type>(result, maybeStates, Type(0.5));
}
// Set values of resulting vector that are known exactly.
storm::utility::setVectorValues<Type>(result, notExistsPhiUntilPsiStates, storm::utility::constGetZero<Type>());
storm::utility::setVectorValues<Type>(result, alwaysPhiUntilPsiStates, storm::utility::constGetOne<Type>());
storm::utility::setVectorValues<Type>(result, statesWithProbability0, storm::utility::constGetZero<Type>());
storm::utility::setVectorValues<Type>(result, statesWithProbability1, storm::utility::constGetOne<Type>());
return result;
}
virtual std::vector<Type>* checkInstantaneousReward(const storm::formula::InstantaneousReward<Type>& formula) const {
virtual std::vector<Type>* checkInstantaneousReward(const storm::formula::InstantaneousReward<Type>& formula, bool qualitative) const {
// Only compute the result if the model has a state-based reward model.
if (!this->getModel().hasStateRewards()) {
LOG4CPLUS_ERROR(logger, "Missing (state-based) reward model for formula.");
@ -176,10 +183,10 @@ public:
}
// Transform the transition probability matrix to the gmm++ format to use its arithmetic.
gmm::csr_matrix<Type>* gmmxxMatrix = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(*this->getModel().getTransitionProbabilityMatrix());
gmm::csr_matrix<Type>* gmmxxMatrix = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(*this->getModel().getTransitionMatrix());
// Initialize result to state rewards of the model.
std::vector<Type>* result = new std::vector<Type>(*this->getModel().getStateRewards());
std::vector<Type>* result = new std::vector<Type>(*this->getModel().getStateRewardVector());
// Now perform matrix-vector multiplication as long as we meet the bound of the formula.
std::vector<Type>* swap = nullptr;
@ -197,7 +204,7 @@ public:
return result;
}
virtual std::vector<Type>* checkCumulativeReward(const storm::formula::CumulativeReward<Type>& formula) const {
virtual std::vector<Type>* checkCumulativeReward(const storm::formula::CumulativeReward<Type>& formula, bool qualitative) const {
// Only compute the result if the model has at least one reward model.
if (!this->getModel().hasStateRewards() && !this->getModel().hasTransitionRewards()) {
LOG4CPLUS_ERROR(logger, "Missing reward model for formula.");
@ -205,17 +212,17 @@ public:
}
// Transform the transition probability matrix to the gmm++ format to use its arithmetic.
gmm::csr_matrix<Type>* gmmxxMatrix = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(*this->getModel().getTransitionProbabilityMatrix());
gmm::csr_matrix<Type>* gmmxxMatrix = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(*this->getModel().getTransitionMatrix());
// Compute the reward vector to add in each step based on the available reward models.
std::vector<Type>* totalRewardVector = nullptr;
if (this->getModel().hasTransitionRewards()) {
totalRewardVector = this->getModel().getTransitionProbabilityMatrix()->getPointwiseProductRowSumVector(*this->getModel().getTransitionRewardMatrix());
totalRewardVector = this->getModel().getTransitionMatrix()->getPointwiseProductRowSumVector(*this->getModel().getTransitionRewardMatrix());
if (this->getModel().hasStateRewards()) {
gmm::add(*this->getModel().getStateRewards(), *totalRewardVector);
gmm::add(*this->getModel().getStateRewardVector(), *totalRewardVector);
}
} else {
totalRewardVector = new std::vector<Type>(*this->getModel().getStateRewards());
totalRewardVector = new std::vector<Type>(*this->getModel().getStateRewardVector());
}
std::vector<Type>* result = new std::vector<Type>(this->getModel().getNumberOfStates());
@ -240,7 +247,7 @@ public:
return result;
}
virtual std::vector<Type>* checkReachabilityReward(const storm::formula::ReachabilityReward<Type>& formula) const {
virtual std::vector<Type>* checkReachabilityReward(const storm::formula::ReachabilityReward<Type>& formula, bool qualitative) const {
// Only compute the result if the model has at least one reward model.
if (!this->getModel().hasStateRewards() && !this->getModel().hasTransitionRewards()) {
LOG4CPLUS_ERROR(logger, "Missing reward model for formula. Skipping formula");
@ -248,12 +255,12 @@ public:
}
// Determine the states for which the target predicate holds.
storm::storage::BitVector* targetStates = this->checkStateFormula(formula.getChild());
storm::storage::BitVector* targetStates = formula.getChild().check(*this);
// Determine which states have a reward of infinity by definition.
storm::storage::BitVector infinityStates(this->getModel().getNumberOfStates());
storm::storage::BitVector trueStates(this->getModel().getNumberOfStates(), true);
storm::solver::GraphAnalyzer::getAlwaysPhiUntilPsiStates(this->getModel(), trueStates, *targetStates, &infinityStates);
storm::utility::GraphAnalyzer::performProb1(this->getModel(), trueStates, *targetStates, &infinityStates);
infinityStates.complement();
// Create resulting vector.
@ -264,7 +271,7 @@ public:
const int maybeStatesSetBitCount = maybeStates.getNumberOfSetBits();
if (maybeStatesSetBitCount > 0) {
// Now we can eliminate the rows and columns from the original transition probability matrix.
storm::storage::SparseMatrix<Type>* submatrix = this->getModel().getTransitionProbabilityMatrix()->getSubmatrix(maybeStates);
storm::storage::SparseMatrix<Type>* submatrix = this->getModel().getTransitionMatrix()->getSubmatrix(maybeStates);
// Converting the matrix from the fixpoint notation to the form needed for the equation
// system. That is, we go from x = A*x + b to (I-A)x = b.
submatrix->convertToEquationSystem();
@ -283,7 +290,7 @@ public:
// If a transition-based reward model is available, we initialize the right-hand
// side to the vector resulting from summing the rows of the pointwise product
// of the transition probability matrix and the transition reward matrix.
std::vector<Type>* pointwiseProductRowSumVector = this->getModel().getTransitionProbabilityMatrix()->getPointwiseProductRowSumVector(*this->getModel().getTransitionRewardMatrix());
std::vector<Type>* pointwiseProductRowSumVector = this->getModel().getTransitionMatrix()->getPointwiseProductRowSumVector(*this->getModel().getTransitionRewardMatrix());
storm::utility::selectVectorValues(b, maybeStates, *pointwiseProductRowSumVector);
delete pointwiseProductRowSumVector;
@ -293,7 +300,7 @@ public:
// that we still consider (i.e. maybeStates), we need to extract these values
// first.
std::vector<Type>* subStateRewards = new std::vector<Type>(maybeStatesSetBitCount);
storm::utility::setVectorValues(subStateRewards, maybeStates, *this->getModel().getStateRewards());
storm::utility::setVectorValues(subStateRewards, maybeStates, *this->getModel().getStateRewardVector());
gmm::add(*subStateRewards, *b);
delete subStateRewards;
}
@ -302,7 +309,7 @@ public:
// right-hand side. As the state reward vector contains entries not just for the
// states that we still consider (i.e. maybeStates), we need to extract these values
// first.
storm::utility::setVectorValues(b, maybeStates, *this->getModel().getStateRewards());
storm::utility::setVectorValues(b, maybeStates, *this->getModel().getStateRewardVector());
}
// Solve the corresponding system of linear equations.
@ -330,7 +337,7 @@ public:
* @return The name of this module.
*/
static std::string getModuleName() {
return "gmm++";
return "gmm++det";
}
/*!
@ -347,9 +354,10 @@ public:
*/
static void putOptions(boost::program_options::options_description* desc) {
desc->add_options()("lemethod", boost::program_options::value<std::string>()->default_value("bicgstab")->notifier(&validateLeMethod), "Sets the method used for linear equation solving. Must be in {bicgstab, qmr}.");
desc->add_options()("lemaxiter", boost::program_options::value<unsigned>()->default_value(10000), "Sets the maximal number of iterations for iterative linear equation solving.");
desc->add_options()("precision", boost::program_options::value<double>()->default_value(10e-6), "Sets the precision for iterative linear equation solving.");
desc->add_options()("maxiter", boost::program_options::value<unsigned>()->default_value(10000), "Sets the maximal number of iterations for iterative equation solving.");
desc->add_options()("precision", boost::program_options::value<double>()->default_value(1e-6), "Sets the precision for iterative equation solving.");
desc->add_options()("precond", boost::program_options::value<std::string>()->default_value("ilu")->notifier(&validatePreconditioner), "Sets the preconditioning technique for linear equation solving. Must be in {ilu, diagonal, ildlt, none}.");
desc->add_options()("relative", boost::program_options::value<bool>()->default_value(true), "Sets whether the relative or absolute error is considered for detecting convergence.");
}
/*!
@ -389,7 +397,7 @@ private:
// Prepare an iteration object that determines the accuracy, maximum number of iterations
// and the like.
gmm::iteration iter(s->get<double>("precision"), 0, s->get<unsigned>("lemaxiter"));
gmm::iteration iter(s->get<double>("precision"), 0, s->get<unsigned>("maxiter"));
// Now do the actual solving.
LOG4CPLUS_INFO(logger, "Starting iterative solver.");

434
src/modelchecker/GmmxxMdpPrctlModelChecker.h

@ -0,0 +1,434 @@
/*
* GmmxxDtmcPrctlModelChecker.h
*
* Created on: 06.12.2012
* Author: Christian Dehnert
*/
#ifndef STORM_MODELCHECKER_GMMXXMDPPRCTLMODELCHECKER_H_
#define STORM_MODELCHECKER_GMMXXMDPPRCTLMODELCHECKER_H_
#include <cmath>
#include "src/models/Mdp.h"
#include "src/modelchecker/MdpPrctlModelChecker.h"
#include "src/utility/GraphAnalyzer.h"
#include "src/utility/Vector.h"
#include "src/utility/ConstTemplates.h"
#include "src/utility/Settings.h"
#include "src/adapters/GmmxxAdapter.h"
#include "src/exceptions/InvalidPropertyException.h"
#include "src/storage/JacobiDecomposition.h"
#include "gmm/gmm_matrix.h"
#include "gmm/gmm_iter_solvers.h"
#include "log4cplus/logger.h"
#include "log4cplus/loggingmacros.h"
extern log4cplus::Logger logger;
namespace storm {
namespace modelChecker {
/*
* A model checking engine that makes use of the gmm++ backend.
*/
template <class Type>
class GmmxxMdpPrctlModelChecker : public MdpPrctlModelChecker<Type> {
public:
explicit GmmxxMdpPrctlModelChecker(storm::models::Mdp<Type>& mdp) : MdpPrctlModelChecker<Type>(mdp) { }
virtual ~GmmxxMdpPrctlModelChecker() { }
virtual std::vector<Type>* checkBoundedUntil(const storm::formula::BoundedUntil<Type>& formula, bool qualitative) const {
// First, we need to compute the states that satisfy the sub-formulas of the until-formula.
storm::storage::BitVector* leftStates = formula.getLeft().check(*this);
storm::storage::BitVector* rightStates = formula.getRight().check(*this);
// Copy the matrix before we make any changes.
storm::storage::SparseMatrix<Type> tmpMatrix(*this->getModel().getTransitionMatrix());
// Get the starting row indices for the non-deterministic choices to reduce the resulting
// vector properly.
std::shared_ptr<std::vector<uint_fast64_t>> nondeterministicChoiceIndices = this->getModel().getNondeterministicChoiceIndices();
// Make all rows absorbing that violate both sub-formulas or satisfy the second sub-formula.
tmpMatrix.makeRowsAbsorbing(~(*leftStates | *rightStates) | *rightStates, *nondeterministicChoiceIndices);
// Transform the transition probability matrix to the gmm++ format to use its arithmetic.
gmm::csr_matrix<Type>* gmmxxMatrix = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(tmpMatrix);
// Create the vector with which to multiply.
std::vector<Type>* result = new std::vector<Type>(this->getModel().getNumberOfStates());
storm::utility::setVectorValues(result, *rightStates, storm::utility::constGetOne<Type>());
// Create vector for result of multiplication, which is reduced to the result vector after
// each multiplication.
std::vector<Type>* multiplyResult = new std::vector<Type>(this->getModel().getTransitionMatrix()->getRowCount(), 0);
// Now perform matrix-vector multiplication as long as we meet the bound of the formula.
for (uint_fast64_t i = 0; i < formula.getBound(); ++i) {
gmm::mult(*gmmxxMatrix, *result, *multiplyResult);
if (this->minimumOperatorStack.top()) {
storm::utility::reduceVectorMin(*multiplyResult, result, *nondeterministicChoiceIndices);
} else {
storm::utility::reduceVectorMax(*multiplyResult, result, *nondeterministicChoiceIndices);
}
}
delete multiplyResult;
// Delete intermediate results and return result.
delete gmmxxMatrix;
delete leftStates;
delete rightStates;
return result;
}
virtual std::vector<Type>* checkNext(const storm::formula::Next<Type>& formula, bool qualitative) const {
// First, we need to compute the states that satisfy the sub-formula of the next-formula.
storm::storage::BitVector* nextStates = formula.getChild().check(*this);
// Transform the transition probability matrix to the gmm++ format to use its arithmetic.
gmm::csr_matrix<Type>* gmmxxMatrix = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(*this->getModel().getTransitionMatrix());
// Create the vector with which to multiply and initialize it correctly.
std::vector<Type>* result = new std::vector<Type>(this->getModel().getNumberOfStates());
storm::utility::setVectorValues(result, *nextStates, storm::utility::constGetOne<Type>());
// Delete obsolete sub-result.
delete nextStates;
// Create resulting vector.
std::vector<Type>* temporaryResult = new std::vector<Type>(this->getModel().getTransitionMatrix()->getRowCount());
// Perform the actual computation, namely matrix-vector multiplication.
gmm::mult(*gmmxxMatrix, *result, *temporaryResult);
// Get the starting row indices for the non-deterministic choices to reduce the resulting
// vector properly.
std::shared_ptr<std::vector<uint_fast64_t>> nondeterministicChoiceIndices = this->getModel().getNondeterministicChoiceIndices();
if (this->minimumOperatorStack.top()) {
storm::utility::reduceVectorMin(*temporaryResult, result, *nondeterministicChoiceIndices);
} else {
storm::utility::reduceVectorMax(*temporaryResult, result, *nondeterministicChoiceIndices);
}
// Delete temporary matrix plus temporary result and return result.
delete gmmxxMatrix;
delete temporaryResult;
return result;
}
virtual std::vector<Type>* checkUntil(const storm::formula::Until<Type>& formula, bool qualitative) const {
// First, we need to compute the states that satisfy the sub-formulas of the until-formula.
storm::storage::BitVector* leftStates = formula.getLeft().check(*this);
storm::storage::BitVector* rightStates = formula.getRight().check(*this);
// Then, we need to identify the states which have to be taken out of the matrix, i.e.
// all states that have probability 0 and 1 of satisfying the until-formula.
storm::storage::BitVector statesWithProbability0(this->getModel().getNumberOfStates());
storm::storage::BitVector statesWithProbability1(this->getModel().getNumberOfStates());
if (this->minimumOperatorStack.top()) {
storm::utility::GraphAnalyzer::performProb01Min(this->getModel(), *leftStates, *rightStates, &statesWithProbability0, &statesWithProbability1);
} else {
storm::utility::GraphAnalyzer::performProb01Max(this->getModel(), *leftStates, *rightStates, &statesWithProbability0, &statesWithProbability1);
}
// Delete sub-results that are obsolete now.
delete leftStates;
delete rightStates;
LOG4CPLUS_INFO(logger, "Found " << statesWithProbability0.getNumberOfSetBits() << " 'no' states.");
LOG4CPLUS_INFO(logger, "Found " << statesWithProbability1.getNumberOfSetBits() << " 'yes' states.");
storm::storage::BitVector maybeStates = ~(statesWithProbability0 | statesWithProbability1);
LOG4CPLUS_INFO(logger, "Found " << maybeStates.getNumberOfSetBits() << " 'maybe' states.");
// Create resulting vector.
std::vector<Type>* result = new std::vector<Type>(this->getModel().getNumberOfStates());
// Only try to solve system if there are states for which the probability is unknown.
uint_fast64_t maybeStatesSetBitCount = maybeStates.getNumberOfSetBits();
if (maybeStatesSetBitCount > 0) {
// First, we can eliminate the rows and columns from the original transition probability matrix for states
// whose probabilities are already known.
storm::storage::SparseMatrix<Type>* submatrix = this->getModel().getTransitionMatrix()->getSubmatrix(maybeStates, *this->getModel().getNondeterministicChoiceIndices());
// Get the "new" nondeterministic choice indices for the submatrix.
std::shared_ptr<std::vector<uint_fast64_t>> subNondeterministicChoiceIndices = this->computeNondeterministicChoiceIndicesForConstraint(maybeStates);
// Transform the submatrix to the gmm++ format to use its capabilities.
gmm::csr_matrix<Type>* gmmxxMatrix = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(*submatrix);
// Create vector for results for maybe states.
std::vector<Type>* x = new std::vector<Type>(maybeStatesSetBitCount);
// Prepare the right-hand side of the equation system. For entry i this corresponds to
// the accumulated probability of going from state i to some 'yes' state.
std::vector<Type> b(submatrix->getRowCount());
this->getModel().getTransitionMatrix()->getConstrainedRowSumVector(maybeStates, *this->getModel().getNondeterministicChoiceIndices(), statesWithProbability1, &b);
delete submatrix;
// Solve the corresponding system of equations.
this->solveEquationSystem(*gmmxxMatrix, x, b, *subNondeterministicChoiceIndices);
// Set values of resulting vector according to result.
storm::utility::setVectorValues<Type>(result, maybeStates, *x);
// Delete temporary matrix and vector.
delete gmmxxMatrix;
delete x;
}
// Set values of resulting vector that are known exactly.
storm::utility::setVectorValues<Type>(result, statesWithProbability0, storm::utility::constGetZero<Type>());
storm::utility::setVectorValues<Type>(result, statesWithProbability1, storm::utility::constGetOne<Type>());
return result;
}
virtual std::vector<Type>* checkInstantaneousReward(const storm::formula::InstantaneousReward<Type>& formula, bool qualitative) const {
// Only compute the result if the model has a state-based reward model.
if (!this->getModel().hasStateRewards()) {
LOG4CPLUS_ERROR(logger, "Missing (state-based) reward model for formula.");
throw storm::exceptions::InvalidPropertyException() << "Missing (state-based) reward model for formula.";
}
// Transform the transition probability matrix to the gmm++ format to use its arithmetic.
gmm::csr_matrix<Type>* gmmxxMatrix = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(*this->getModel().getTransitionMatrix());
// Initialize result to state rewards of the model.
std::vector<Type>* result = new std::vector<Type>(*this->getModel().getStateRewardVector());
// Now perform matrix-vector multiplication as long as we meet the bound of the formula.
std::vector<Type>* swap = nullptr;
std::vector<Type>* tmpResult = new std::vector<Type>(this->getModel().getNumberOfStates());
for (uint_fast64_t i = 0; i < formula.getBound(); ++i) {
gmm::mult(*gmmxxMatrix, *result, *tmpResult);
swap = tmpResult;
tmpResult = result;
result = swap;
}
// Delete temporary variables and return result.
delete tmpResult;
delete gmmxxMatrix;
return result;
}
virtual std::vector<Type>* checkCumulativeReward(const storm::formula::CumulativeReward<Type>& formula, bool qualitative) const {
// Only compute the result if the model has at least one reward model.
if (!this->getModel().hasStateRewards() && !this->getModel().hasTransitionRewards()) {
LOG4CPLUS_ERROR(logger, "Missing reward model for formula.");
throw storm::exceptions::InvalidPropertyException() << "Missing reward model for formula.";
}
// Transform the transition probability matrix to the gmm++ format to use its arithmetic.
gmm::csr_matrix<Type>* gmmxxMatrix = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(*this->getModel().getTransitionMatrix());
// Compute the reward vector to add in each step based on the available reward models.
std::vector<Type>* totalRewardVector = nullptr;
if (this->getModel().hasTransitionRewards()) {
totalRewardVector = this->getModel().getTransitionMatrix()->getPointwiseProductRowSumVector(*this->getModel().getTransitionRewardMatrix());
if (this->getModel().hasStateRewards()) {
gmm::add(*this->getModel().getStateRewardVector(), *totalRewardVector);
}
} else {
totalRewardVector = new std::vector<Type>(*this->getModel().getStateRewardVector());
}
std::vector<Type>* result = new std::vector<Type>(this->getModel().getNumberOfStates());
// Now perform matrix-vector multiplication as long as we meet the bound of the formula.
std::vector<Type>* swap = nullptr;
std::vector<Type>* tmpResult = new std::vector<Type>(this->getModel().getNumberOfStates());
for (uint_fast64_t i = 0; i < formula.getBound(); ++i) {
gmm::mult(*gmmxxMatrix, *result, *tmpResult);
swap = tmpResult;
tmpResult = result;
result = swap;
// Add the reward vector to the result.
gmm::add(*totalRewardVector, *result);
}
// Delete temporary variables and return result.
delete tmpResult;
delete gmmxxMatrix;
delete totalRewardVector;
return result;
}
virtual std::vector<Type>* checkReachabilityReward(const storm::formula::ReachabilityReward<Type>& formula, bool qualitative) const {
// Only compute the result if the model has at least one reward model.
if (!this->getModel().hasStateRewards() && !this->getModel().hasTransitionRewards()) {
LOG4CPLUS_ERROR(logger, "Missing reward model for formula. Skipping formula");
throw storm::exceptions::InvalidPropertyException() << "Missing reward model for formula.";
}
// Determine the states for which the target predicate holds.
storm::storage::BitVector* targetStates = formula.getChild().check(*this);
// Determine which states have a reward of infinity by definition.
storm::storage::BitVector infinityStates(this->getModel().getNumberOfStates());
storm::storage::BitVector trueStates(this->getModel().getNumberOfStates(), true);
// TODO: just commented out to make it compile
//storm::utility::GraphAnalyzer::performProb1(this->getModel(), trueStates, *targetStates, &infinityStates);
infinityStates.complement();
// Create resulting vector.
std::vector<Type>* result = new std::vector<Type>(this->getModel().getNumberOfStates());
// Check whether there are states for which we have to compute the result.
storm::storage::BitVector maybeStates = ~(*targetStates) & ~infinityStates;
const int maybeStatesSetBitCount = maybeStates.getNumberOfSetBits();
if (maybeStatesSetBitCount > 0) {
// Now we can eliminate the rows and columns from the original transition probability matrix.
storm::storage::SparseMatrix<Type>* submatrix = this->getModel().getTransitionMatrix()->getSubmatrix(maybeStates);
// Converting the matrix from the fixpoint notation to the form needed for the equation
// system. That is, we go from x = A*x + b to (I-A)x = b.
submatrix->convertToEquationSystem();
// Transform the submatrix to the gmm++ format to use its solvers.
gmm::csr_matrix<Type>* gmmxxMatrix = storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix<Type>(*submatrix);
delete submatrix;
// Initialize the x vector with 1 for each element. This is the initial guess for
// the iterative solvers.
std::vector<Type> x(maybeStatesSetBitCount, storm::utility::constGetOne<Type>());
// Prepare the right-hand side of the equation system.
std::vector<Type>* b = new std::vector<Type>(maybeStatesSetBitCount);
if (this->getModel().hasTransitionRewards()) {
// If a transition-based reward model is available, we initialize the right-hand
// side to the vector resulting from summing the rows of the pointwise product
// of the transition probability matrix and the transition reward matrix.
std::vector<Type>* pointwiseProductRowSumVector = this->getModel().getTransitionMatrix()->getPointwiseProductRowSumVector(*this->getModel().getTransitionRewardMatrix());
storm::utility::selectVectorValues(b, maybeStates, *pointwiseProductRowSumVector);
delete pointwiseProductRowSumVector;
if (this->getModel().hasStateRewards()) {
// If a state-based reward model is also available, we need to add this vector
// as well. As the state reward vector contains entries not just for the states
// that we still consider (i.e. maybeStates), we need to extract these values
// first.
std::vector<Type>* subStateRewards = new std::vector<Type>(maybeStatesSetBitCount);
storm::utility::setVectorValues(subStateRewards, maybeStates, *this->getModel().getStateRewardVector());
gmm::add(*subStateRewards, *b);
delete subStateRewards;
}
} else {
// If only a state-based reward model is available, we take this vector as the
// right-hand side. As the state reward vector contains entries not just for the
// states that we still consider (i.e. maybeStates), we need to extract these values
// first.
storm::utility::setVectorValues(b, maybeStates, *this->getModel().getStateRewardVector());
}
// Solve the corresponding system of linear equations.
// TODO: just commented out to make it compile
// this->solveEquationSystem(*gmmxxMatrix, x, *b);
// Set values of resulting vector according to result.
storm::utility::setVectorValues<Type>(result, maybeStates, x);
// Delete temporary matrix and right-hand side.
delete gmmxxMatrix;
delete b;
}
// Set values of resulting vector that are known exactly.
storm::utility::setVectorValues(result, *targetStates, storm::utility::constGetZero<Type>());
storm::utility::setVectorValues(result, infinityStates, storm::utility::constGetInfinity<Type>());
// Delete temporary storages and return result.
delete targetStates;
return result;
}
private:
/*!
* Solves the given equation system under the given parameters using the power method.
*
* @param A The matrix A specifying the coefficients of the equations.
* @param x The vector x for which to solve the equations. The initial value of the elements of
* this vector are used as the initial guess and might thus influence performance and convergence.
* @param b The vector b specifying the values on the right-hand-sides of the equations.
* @return The solution of the system of linear equations in form of the elements of the vector
* x.
*/
void solveEquationSystem(gmm::csr_matrix<Type> const& A, std::vector<Type>* x, std::vector<Type> const& b, std::vector<uint_fast64_t> const& nondeterministicChoiceIndices) const {
// Get the settings object to customize solving.
storm::settings::Settings* s = storm::settings::instance();
// Get relevant user-defined settings for solving the equations.
double precision = s->get<double>("precision");
unsigned maxIterations = s->get<unsigned>("maxiter");
bool relative = s->get<bool>("relative");
// Set up the environment for the power method.
std::vector<Type>* temporaryResult = new std::vector<Type>(b.size());
std::vector<Type>* newX = new std::vector<Type>(x->size());
std::vector<Type>* swap = nullptr;
bool converged = false;
uint_fast64_t iterations = 0;
// Proceed with the iterations as long as the method did not converge or reach the
// user-specified maximum number of iterations.
while (!converged && iterations < maxIterations) {
// Compute x' = A*x + b.
gmm::mult(A, *x, *temporaryResult);
gmm::add(b, *temporaryResult);
// Reduce the vector x' by applying min/max for all non-deterministic choices.
if (this->minimumOperatorStack.top()) {
storm::utility::reduceVectorMin(*temporaryResult, newX, nondeterministicChoiceIndices);
} else {
storm::utility::reduceVectorMax(*temporaryResult, newX, nondeterministicChoiceIndices);
}
// Determine whether the method converged.
converged = storm::utility::equalModuloPrecision(*x, *newX, precision, relative);
// Update environment variables.
swap = x;
x = newX;
newX = swap;
++iterations;
}
delete temporaryResult;
// Check if the solver converged and issue a warning otherwise.
if (converged) {
LOG4CPLUS_INFO(logger, "Iterative solver converged after " << iterations << " iterations.");
} else {
LOG4CPLUS_WARN(logger, "Iterative solver did not converge.");
}
}
std::shared_ptr<std::vector<uint_fast64_t>> computeNondeterministicChoiceIndicesForConstraint(storm::storage::BitVector constraint) const {
std::shared_ptr<std::vector<uint_fast64_t>> nondeterministicChoiceIndices = this->getModel().getNondeterministicChoiceIndices();
std::shared_ptr<std::vector<uint_fast64_t>> subNondeterministicChoiceIndices(new std::vector<uint_fast64_t>(constraint.getNumberOfSetBits() + 1));
uint_fast64_t currentRowCount = 0;
uint_fast64_t currentIndexCount = 1;
(*subNondeterministicChoiceIndices)[0] = 0;
for (auto index : constraint) {
(*subNondeterministicChoiceIndices)[currentIndexCount] = currentRowCount + (*nondeterministicChoiceIndices)[index + 1] - (*nondeterministicChoiceIndices)[index];
currentRowCount += (*nondeterministicChoiceIndices)[index + 1] - (*nondeterministicChoiceIndices)[index];
++currentIndexCount;
}
(*subNondeterministicChoiceIndices)[constraint.getNumberOfSetBits()] = currentRowCount;
return subNondeterministicChoiceIndices;
}
};
} //namespace modelChecker
} //namespace storm
#endif /* STORM_MODELCHECKER_GMMXXMDPPRCTLMODELCHECKER_H_ */

286
src/modelchecker/MdpPrctlModelChecker.h

@ -0,0 +1,286 @@
/*
* MdpPrctlModelChecker.h
*
* Created on: 15.02.2013
* Author: Christian Dehnert
*/
#ifndef STORM_MODELCHECKER_MDPPRCTLMODELCHECKER_H_
#define STORM_MODELCHECKER_MDPPRCTLMODELCHECKER_H_
#include "src/formula/Formulas.h"
#include "src/utility/Vector.h"
#include "src/storage/SparseMatrix.h"
#include "src/models/Mdp.h"
#include "src/storage/BitVector.h"
#include "src/exceptions/InvalidPropertyException.h"
#include "src/utility/Vector.h"
#include "src/modelchecker/AbstractModelChecker.h"
#include <vector>
#include <stack>
#include "log4cplus/logger.h"
#include "log4cplus/loggingmacros.h"
extern log4cplus::Logger logger;
namespace storm {
namespace modelChecker {
/*!
* @brief
* Interface for model checker classes.
*
* This class provides basic functions that are the same for all subclasses, but mainly only declares
* abstract methods that are to be implemented in concrete instances.
*
* @attention This class is abstract.
*/
template<class Type>
class MdpPrctlModelChecker :
public AbstractModelChecker<Type> {
public:
/*!
* Constructor
*
* @param model The dtmc model which is checked.
*/
explicit MdpPrctlModelChecker(storm::models::Mdp<Type>& model)
: AbstractModelChecker<Type>(model), minimumOperatorStack() {
}
/*!
* Copy constructor
*
* @param modelChecker The model checker that is copied.
*/
explicit MdpPrctlModelChecker(const storm::modelChecker::MdpPrctlModelChecker<Type>* modelChecker)
: AbstractModelChecker<Type>(modelChecker), minimumOperatorStack() {
}
/*!
* Destructor
*/
virtual ~MdpPrctlModelChecker() {
// Intentionally left empty.
}
/*!
* @returns A reference to the dtmc of the model checker.
*/
storm::models::Mdp<Type>& getModel() const {
return AbstractModelChecker<Type>::template getModel<storm::models::Mdp<Type>>();
}
/*!
* Sets the DTMC model which is checked
* @param model
*/
void setModel(storm::models::Mdp<Type>& model) {
AbstractModelChecker<Type>::setModel(model);
}
/*!
* Checks the given state formula on the DTMC and prints the result (true/false) for all initial
* states.
* @param stateFormula The formula to be checked.
*/
void check(const storm::formula::AbstractStateFormula<Type>& stateFormula) const {
std::cout << std::endl;
LOG4CPLUS_INFO(logger, "Model checking formula\t" << stateFormula.toString());
std::cout << "Model checking formula:\t" << stateFormula.toString() << std::endl;
storm::storage::BitVector* result = nullptr;
try {
result = stateFormula.check(*this);
LOG4CPLUS_INFO(logger, "Result for initial states:");
std::cout << "Result for initial states:" << std::endl;
for (auto initialState : *this->getModel().getLabeledStates("init")) {
LOG4CPLUS_INFO(logger, "\t" << initialState << ": " << (result->get(initialState) ? "satisfied" : "not satisfied"));
std::cout << "\t" << initialState << ": " << (*result)[initialState] << std::endl;
}
delete result;
} catch (std::exception& e) {
std::cout << "Error during computation: " << e.what() << "Skipping property." << std::endl;
if (result != nullptr) {
delete result;
}
}
std::cout << std::endl;
storm::utility::printSeparationLine(std::cout);
}
/*!
* Checks the given operator (with no bound) on the DTMC and prints the result
* (probability/rewards) for all initial states.
* @param noBoundFormula The formula to be checked.
*/
void check(const storm::formula::NoBoundOperator<Type>& noBoundFormula) const {
std::cout << std::endl;
LOG4CPLUS_INFO(logger, "Model checking formula\t" << noBoundFormula.toString());
std::cout << "Model checking formula:\t" << noBoundFormula.toString() << std::endl;
std::vector<Type>* result = nullptr;
try {
result = noBoundFormula.check(*this);
LOG4CPLUS_INFO(logger, "Result for initial states:");
std::cout << "Result for initial states:" << std::endl;
for (auto initialState : *this->getModel().getLabeledStates("init")) {
LOG4CPLUS_INFO(logger, "\t" << initialState << ": " << (*result)[initialState]);
std::cout << "\t" << initialState << ": " << (*result)[initialState] << std::endl;
}
delete result;
} catch (std::exception& e) {
std::cout << "Error during computation: " << e.what() << " Skipping property." << std::endl;
if (result != nullptr) {
delete result;
}
}
std::cout << std::endl;
storm::utility::printSeparationLine(std::cout);
}
/*!
* The check method for a formula with an AP node as root in its formula tree
*
* @param formula The Ap state formula to check
* @returns The set of states satisfying the formula, represented by a bit vector
*/
storm::storage::BitVector* checkAp(const storm::formula::Ap<Type>& formula) const {
if (formula.getAp().compare("true") == 0) {
return new storm::storage::BitVector(this->getModel().getNumberOfStates(), true);
} else if (formula.getAp().compare("false") == 0) {
return new storm::storage::BitVector(this->getModel().getNumberOfStates());
}
if (!this->getModel().hasAtomicProposition(formula.getAp())) {
LOG4CPLUS_ERROR(logger, "Atomic proposition '" << formula.getAp() << "' is invalid.");
throw storm::exceptions::InvalidPropertyException() << "Atomic proposition '" << formula.getAp() << "' is invalid.";
return nullptr;
}
return new storm::storage::BitVector(*this->getModel().getLabeledStates(formula.getAp()));
}
/*!
* The check method for a state formula with a probabilistic operator node without bounds as root
* in its formula tree
*
* @param formula The state formula to check
* @returns The set of states satisfying the formula, represented by a bit vector
*/
std::vector<Type>* checkNoBoundOperator(const storm::formula::NoBoundOperator<Type>& formula) const {
// Check if the operator was an non-optimality operator and report an error in that case.
if (!formula.isOptimalityOperator()) {
LOG4CPLUS_ERROR(logger, "Formula does not specify neither min nor max optimality, which is not meaningful over nondeterministic models.");
throw storm::exceptions::InvalidArgumentException() << "Formula does not specify neither min nor max optimality, which is not meaningful over nondeterministic models.";
}
minimumOperatorStack.push(formula.isMinimumOperator());
std::vector<Type>* result = formula.getPathFormula().check(*this, false);
minimumOperatorStack.pop();
return result;
}
/*!
* The check method for a path formula with a Bounded Until operator node as root in its formula tree
*
* @param formula The Bounded Until path formula to check
* @returns for each state the probability that the path formula holds.
*/
virtual std::vector<Type>* checkBoundedUntil(const storm::formula::BoundedUntil<Type>& formula, bool qualitative) const = 0;
/*!
* The check method for a path formula with a Next operator node as root in its formula tree
*
* @param formula The Next path formula to check
* @returns for each state the probability that the path formula holds.
*/
virtual std::vector<Type>* checkNext(const storm::formula::Next<Type>& formula, bool qualitative) const = 0;
/*!
* The check method for a path formula with a Bounded Eventually operator node as root in its
* formula tree
*
* @param formula The Bounded Eventually path formula to check
* @returns for each state the probability that the path formula holds
*/
virtual std::vector<Type>* checkBoundedEventually(const storm::formula::BoundedEventually<Type>& formula, bool qualitative) const {
// Create equivalent temporary bounded until formula and check it.
storm::formula::BoundedUntil<Type> temporaryBoundedUntilFormula(new storm::formula::Ap<Type>("true"), formula.getChild().clone(), formula.getBound());
return this->checkBoundedUntil(temporaryBoundedUntilFormula, qualitative);
}
/*!
* The check method for a path formula with an Eventually operator node as root in its formula tree
*
* @param formula The Eventually path formula to check
* @returns for each state the probability that the path formula holds
*/
virtual std::vector<Type>* checkEventually(const storm::formula::Eventually<Type>& formula, bool qualitative) const {
// Create equivalent temporary until formula and check it.
storm::formula::Until<Type> temporaryUntilFormula(new storm::formula::Ap<Type>("true"), formula.getChild().clone());
return this->checkUntil(temporaryUntilFormula, qualitative);
}
/*!
* The check method for a path formula with a Globally operator node as root in its formula tree
*
* @param formula The Globally path formula to check
* @returns for each state the probability that the path formula holds
*/
virtual std::vector<Type>* checkGlobally(const storm::formula::Globally<Type>& formula, bool qualitative) const {
// Create "equivalent" temporary eventually formula and check it.
storm::formula::Eventually<Type> temporaryEventuallyFormula(new storm::formula::Not<Type>(formula.getChild().clone()));
std::vector<Type>* result = this->checkEventually(temporaryEventuallyFormula, qualitative);
// Now subtract the resulting vector from the constant one vector to obtain final result.
storm::utility::subtractFromConstantOneVector(result);
return result;
}
/*!
* The check method for a path formula with an Until operator node as root in its formula tree
*
* @param formula The Until path formula to check
* @returns for each state the probability that the path formula holds.
*/
virtual std::vector<Type>* checkUntil(const storm::formula::Until<Type>& formula, bool qualitative) const = 0;
/*!
* The check method for a path formula with an Instantaneous Reward operator node as root in its
* formula tree
*
* @param formula The Instantaneous Reward formula to check
* @returns for each state the reward that the instantaneous reward yields
*/
virtual std::vector<Type>* checkInstantaneousReward(const storm::formula::InstantaneousReward<Type>& formula, bool qualitative) const = 0;
/*!
* The check method for a path formula with a Cumulative Reward operator node as root in its
* formula tree
*
* @param formula The Cumulative Reward formula to check
* @returns for each state the reward that the cumulative reward yields
*/
virtual std::vector<Type>* checkCumulativeReward(const storm::formula::CumulativeReward<Type>& formula, bool qualitative) const = 0;
/*!
* The check method for a path formula with a Reachability Reward operator node as root in its
* formula tree
*
* @param formula The Reachbility Reward formula to check
* @returns for each state the reward that the reachability reward yields
*/
virtual std::vector<Type>* checkReachabilityReward(const storm::formula::ReachabilityReward<Type>& formula, bool qualitative) const = 0;
protected:
mutable std::stack<bool> minimumOperatorStack;
};
} //namespace modelChecker
} //namespace storm
#endif /* STORM_MODELCHECKER_DTMCPRCTLMODELCHECKER_H_ */

54
src/models/AbstractDeterministicModel.h

@ -0,0 +1,54 @@
#ifndef STORM_MODELS_ABSTRACTDETERMINISTICMODEL_H_
#define STORM_MODELS_ABSTRACTDETERMINISTICMODEL_H_
#include "AbstractModel.h"
#include "GraphTransitions.h"
#include <memory>
namespace storm {
namespace models {
/*!
* @brief Base class for all deterministic model classes.
*
* This is base class defines a common interface for all deterministic models.
*/
template<class T>
class AbstractDeterministicModel: public AbstractModel<T> {
public:
/*! Constructs an abstract determinstic model from the given parameters.
* @param transitionMatrix The matrix representing the transitions in the model.
* @param stateLabeling The labeling that assigns a set of atomic
* propositions to each state.
* @param stateRewardVector The reward values associated with the states.
* @param transitionRewardMatrix The reward values associated with the transitions of the model.
*/
AbstractDeterministicModel(std::shared_ptr<storm::storage::SparseMatrix<T>> transitionMatrix,
std::shared_ptr<storm::models::AtomicPropositionsLabeling> stateLabeling,
std::shared_ptr<std::vector<T>> stateRewardVector, std::shared_ptr<storm::storage::SparseMatrix<T>> transitionRewardMatrix)
: AbstractModel<T>(transitionMatrix, stateLabeling, stateRewardVector, transitionRewardMatrix) {
}
/*!
* Destructor.
*/
virtual ~AbstractDeterministicModel() {
// Intentionally left empty.
}
/*!
* Copy Constructor.
*/
AbstractDeterministicModel(AbstractDeterministicModel const& other) : AbstractModel<T>(other) {
// Intentionally left empty.
}
};
} // namespace models
} // namespace storm
#endif /* STORM_MODELS_ABSTRACTDETERMINISTICMODEL_H_ */

176
src/models/AbstractModel.h

@ -1,7 +1,13 @@
#ifndef STORM_MODELS_ABSTRACTMODEL_H_
#define STORM_MODELS_ABSTRACTMODEL_H_
#include "src/models/AtomicPropositionsLabeling.h"
#include "src/storage/BitVector.h"
#include "src/storage/SparseMatrix.h"
#include "src/utility/CommandLine.h"
#include <memory>
#include <vector>
namespace storm {
namespace models {
@ -24,9 +30,32 @@ std::ostream& operator<<(std::ostream& os, ModelType const type);
* This is base class defines a common interface for all models to identify
* their type and obtain the special model.
*/
class AbstractModel: public std::enable_shared_from_this<AbstractModel> {
template<class T>
class AbstractModel: public std::enable_shared_from_this<AbstractModel<T>> {
public:
/*! Constructs an abstract model from the given transition matrix and
* the given labeling of the states.
* @param transitionMatrix The matrix representing the transitions in the model.
* @param stateLabeling The labeling that assigns a set of atomic
* propositions to each state.
* @param stateRewardVector The reward values associated with the states.
* @param transitionRewardMatrix The reward values associated with the transitions of the model.
*/
AbstractModel(std::shared_ptr<storm::storage::SparseMatrix<T>> transitionMatrix,
std::shared_ptr<storm::models::AtomicPropositionsLabeling> stateLabeling,
std::shared_ptr<std::vector<T>> stateRewardVector, std::shared_ptr<storm::storage::SparseMatrix<T>> transitionRewardMatrix)
: transitionMatrix(transitionMatrix), stateLabeling(stateLabeling), stateRewardVector(stateRewardVector), transitionRewardMatrix(transitionRewardMatrix) {
// Intentionally left empty.
}
/*!
* Destructor.
*/
virtual ~AbstractModel() {
// Intentionally left empty.
}
/*!
* @brief Casts the model to the model type that was actually
* created.
@ -44,7 +73,7 @@ class AbstractModel: public std::enable_shared_from_this<AbstractModel> {
*/
template <typename Model>
std::shared_ptr<Model> as() {
return std::dynamic_pointer_cast<Model>(shared_from_this());
return std::dynamic_pointer_cast<Model>(this->shared_from_this());
}
/*!
@ -54,8 +83,147 @@ class AbstractModel: public std::enable_shared_from_this<AbstractModel> {
*
* @return Type of the model.
*/
virtual ModelType getType() = 0;
virtual ModelType getType() const = 0;
/*!
* Returns the state space size of the model.
* @return The size of the state space of the model.
*/
virtual uint_fast64_t getNumberOfStates() const {
return this->getTransitionMatrix()->getColumnCount();
}
/*!
* Returns the number of (non-zero) transitions of the model.
* @return The number of (non-zero) transitions of the model.
*/
virtual uint_fast64_t getNumberOfTransitions() const {
return this->getTransitionMatrix()->getNonZeroEntryCount();
}
/*!
* Returns a bit vector in which exactly those bits are set to true that
* correspond to a state labeled with the given atomic proposition.
* @param ap The atomic proposition for which to get the bit vector.
* @return A bit vector in which exactly those bits are set to true that
* correspond to a state labeled with the given atomic proposition.
*/
storm::storage::BitVector* getLabeledStates(std::string ap) const {
return stateLabeling->getAtomicProposition(ap);
}
/*!
* Retrieves whether the given atomic proposition is a valid atomic proposition in this model.
* @param atomicProposition The atomic proposition to be checked for validity.
* @return True if the given atomic proposition is valid in this model.
*/
bool hasAtomicProposition(std::string const& atomicProposition) const {
return stateLabeling->containsAtomicProposition(atomicProposition);
}
/*!
* Returns a pointer to the matrix representing the transition probability
* function.
* @return A pointer to the matrix representing the transition probability
* function.
*/
std::shared_ptr<storm::storage::SparseMatrix<T>> getTransitionMatrix() const {
return transitionMatrix;
}
/*!
* Returns a pointer to the matrix representing the transition rewards.
* @return A pointer to the matrix representing the transition rewards.
*/
std::shared_ptr<storm::storage::SparseMatrix<T>> getTransitionRewardMatrix() const {
return transitionRewardMatrix;
}
/*!
* Returns a pointer to the vector representing the state rewards.
* @return A pointer to the vector representing the state rewards.
*/
std::shared_ptr<std::vector<T>> getStateRewardVector() const {
return stateRewardVector;
}
/*!
* Returns the set of states with which the given state is labeled.
* @return The set of states with which the given state is labeled.
*/
std::set<std::string> const getPropositionsForState(uint_fast64_t const &state) const {
return stateLabeling->getPropositionsForState(state);
}
/*!
* Returns the state labeling associated with this model.
* @return The state labeling associated with this model.
*/
std::shared_ptr<storm::models::AtomicPropositionsLabeling> getStateLabeling() const {
return stateLabeling;
}
/*!
* Retrieves whether this model has a state reward model.
* @return True if this model has a state reward model.
*/
bool hasStateRewards() const {
return stateRewardVector != nullptr;
}
/*!
* Retrieves whether this model has a transition reward model.
* @return True if this model has a transition reward model.
*/
bool hasTransitionRewards() const {
return transitionRewardMatrix != nullptr;
}
/*!
* Retrieves the size of the internal representation of the model in memory.
* @return the size of the internal representation of the model in memory
* measured in bytes.
*/
virtual uint_fast64_t getSizeInMemory() const {
uint_fast64_t result = transitionMatrix->getSizeInMemory() + stateLabeling->getSizeInMemory();
if (stateRewardVector != nullptr) {
result += stateRewardVector->size() * sizeof(T);
}
if (transitionRewardMatrix != nullptr) {
result += transitionRewardMatrix->getSizeInMemory();
}
return result;
}
/*!
* Prints information about the model to the specified stream.
* @param out The stream the information is to be printed to.
*/
void printModelInformationToStream(std::ostream& out) const {
out << "-------------------------------------------------------------- "
<< std::endl;
out << "Model type: \t\t" << this->getType() << std::endl;
out << "States: \t\t" << this->getNumberOfStates() << std::endl;
out << "Transitions: \t\t" << this->getNumberOfTransitions() << std::endl;
this->getStateLabeling()->printAtomicPropositionsInformationToStream(out);
out << "Size in memory: \t"
<< (this->getSizeInMemory())/1024 << " kbytes" << std::endl;
out << "-------------------------------------------------------------- "
<< std::endl;
}
private:
/*! A matrix representing the likelihoods of moving between states. */
std::shared_ptr<storm::storage::SparseMatrix<T>> transitionMatrix;
/*! The labeling of the states of the model. */
std::shared_ptr<storm::models::AtomicPropositionsLabeling> stateLabeling;
/*! The state-based rewards of the model. */
std::shared_ptr<std::vector<T>> stateRewardVector;
/*! The transition-based rewards of the model. */
std::shared_ptr<storm::storage::SparseMatrix<T>> transitionRewardMatrix;
};
} // namespace models

82
src/models/AbstractNondeterministicModel.h

@ -0,0 +1,82 @@
#ifndef STORM_MODELS_ABSTRACTNONDETERMINISTICMODEL_H_
#define STORM_MODELS_ABSTRACTNONDETERMINISTICMODEL_H_
#include "AbstractModel.h"
#include "GraphTransitions.h"
#include <memory>
namespace storm {
namespace models {
/*!
* @brief Base class for all non-deterministic model classes.
*
* This is base class defines a common interface for all non-deterministic models.
*/
template<class T>
class AbstractNondeterministicModel: public AbstractModel<T> {
public:
/*! Constructs an abstract non-determinstic model from the given parameters.
* @param transitionMatrix The matrix representing the transitions in the model.
* @param stateLabeling The labeling that assigns a set of atomic
* propositions to each state.
* @param choiceIndices A mapping from states to rows in the transition matrix.
* @param stateRewardVector The reward values associated with the states.
* @param transitionRewardMatrix The reward values associated with the transitions of the model.
*/
AbstractNondeterministicModel(std::shared_ptr<storm::storage::SparseMatrix<T>> transitionMatrix,
std::shared_ptr<storm::models::AtomicPropositionsLabeling> stateLabeling,
std::shared_ptr<std::vector<uint_fast64_t>> nondeterministicChoiceIndices,
std::shared_ptr<std::vector<T>> stateRewardVector,
std::shared_ptr<storm::storage::SparseMatrix<T>> transitionRewardMatrix)
: AbstractModel<T>(transitionMatrix, stateLabeling, stateRewardVector, transitionRewardMatrix),
nondeterministicChoiceIndices(nondeterministicChoiceIndices) {
}
/*!
* Destructor.
*/
virtual ~AbstractNondeterministicModel() {
// Intentionally left empty.
}
/*!
* Copy Constructor.
*/
AbstractNondeterministicModel(AbstractNondeterministicModel const& other) : AbstractModel<T>(other),
nondeterministicChoiceIndices(other.nondeterministicChoiceIndices) {
// Intentionally left empty.
}
/*!
* Retrieves the size of the internal representation of the model in memory.
* @return the size of the internal representation of the model in memory
* measured in bytes.
*/
virtual uint_fast64_t getSizeInMemory() const {
return AbstractModel<T>::getSizeInMemory() + nondeterministicChoiceIndices->size() * sizeof(uint_fast64_t);
}
/*!
* Retrieves the vector indicating which matrix rows represent non-deterministic choices
* of a certain state.
* @param the vector indicating which matrix rows represent non-deterministic choices
* of a certain state.
*/
std::shared_ptr<std::vector<uint_fast64_t>> getNondeterministicChoiceIndices() const {
return nondeterministicChoiceIndices;
}
private:
/*! A vector of indices mapping states to the choices (rows) in the transition matrix. */
std::shared_ptr<std::vector<uint_fast64_t>> nondeterministicChoiceIndices;
};
} // namespace models
} // namespace storm
#endif /* STORM_MODELS_ABSTRACTDETERMINISTICMODEL_H_ */

15
src/models/AtomicPropositionsLabeling.h

@ -15,6 +15,11 @@
#include <unordered_map>
#include <set>
#include "log4cplus/logger.h"
#include "log4cplus/loggingmacros.h"
extern log4cplus::Logger logger;
namespace storm {
namespace models {
@ -82,9 +87,11 @@ public:
*/
uint_fast64_t addAtomicProposition(std::string ap) {
if (nameToLabelingMap.count(ap) != 0) {
LOG4CPLUS_ERROR(logger, "Atomic Proposition already exists.");
throw storm::exceptions::OutOfRangeException("Atomic Proposition already exists.");
}
if (apsCurrent >= apCountMax) {
LOG4CPLUS_ERROR(logger, "Added more atomic propositions than previously declared.");
throw storm::exceptions::OutOfRangeException("Added more atomic propositions than"
"previously declared.");
}
@ -110,9 +117,11 @@ public:
*/
void addAtomicPropositionToState(std::string ap, const uint_fast64_t state) {
if (nameToLabelingMap.count(ap) == 0) {
LOG4CPLUS_ERROR(logger, "Atomic Proposition '" << ap << "' unknown.");
throw storm::exceptions::OutOfRangeException() << "Atomic Proposition '" << ap << "' unknown.";
}
if (state >= stateCount) {
LOG4CPLUS_ERROR(logger, "State index out of range.");
throw storm::exceptions::OutOfRangeException("State index out of range.");
}
this->singleLabelings[nameToLabelingMap[ap]]->set(state, true);
@ -125,6 +134,7 @@ public:
*/
std::set<std::string> getPropositionsForState(uint_fast64_t state) {
if (state >= stateCount) {
LOG4CPLUS_ERROR(logger, "State index out of range.");
throw storm::exceptions::OutOfRangeException("State index out of range.");
}
std::set<std::string> result;
@ -165,6 +175,11 @@ public:
* represents the labeling of the states with the given atomic proposition.
*/
storm::storage::BitVector* getAtomicProposition(std::string ap) {
if (!this->containsAtomicProposition(ap)) {
LOG4CPLUS_ERROR(logger, "The atomic proposition " << ap << " is invalid for the labeling of the model.");
throw storm::exceptions::InvalidArgumentException() << "The atomic proposition " << ap
<< " is invalid for the labeling of the model.";
}
return (this->singleLabelings[nameToLabelingMap[ap]]);
}

149
src/models/Ctmc.h

@ -8,28 +8,23 @@
#ifndef STORM_MODELS_CTMC_H_
#define STORM_MODELS_CTMC_H_
#include <ostream>
#include <iostream>
#include <memory>
#include <cstdlib>
#include <vector>
#include "AbstractDeterministicModel.h"
#include "AtomicPropositionsLabeling.h"
#include "GraphTransitions.h"
#include "src/storage/SparseMatrix.h"
#include "src/exceptions/InvalidArgumentException.h"
#include "src/models/AbstractModel.h"
namespace storm {
namespace models {
/*!
* This class represents a discrete-time Markov chain (DTMC) whose states are
* This class represents a continuous-time Markov chain (CTMC) whose states are
* labeled with atomic propositions.
*/
template <class T>
class Ctmc : public storm::models::AbstractModel {
class Ctmc : public storm::models::AbstractDeterministicModel<T> {
public:
//! Constructor
@ -43,11 +38,9 @@ public:
*/
Ctmc(std::shared_ptr<storm::storage::SparseMatrix<T>> rateMatrix,
std::shared_ptr<storm::models::AtomicPropositionsLabeling> stateLabeling,
std::shared_ptr<std::vector<T>> stateRewards = nullptr,
std::shared_ptr<std::vector<T>> stateRewardVector = nullptr,
std::shared_ptr<storm::storage::SparseMatrix<T>> transitionRewardMatrix = nullptr)
: rateMatrix(rateMatrix), stateLabeling(stateLabeling),
stateRewards(stateRewards), transitionRewardMatrix(transitionRewardMatrix),
backwardTransitions(nullptr) {
: AbstractDeterministicModel<T>(rateMatrix, stateLabeling, stateRewardVector, transitionRewardMatrix) {
}
//! Copy Constructor
@ -55,137 +48,13 @@ public:
* Copy Constructor. Performs a deep copy of the given CTMC.
* @param ctmc A reference to the CTMC that is to be copied.
*/
Ctmc(const Ctmc<T> &ctmc) : rateMatrix(ctmc.rateMatrix),
stateLabeling(ctmc.stateLabeling), stateRewards(ctmc.stateRewards),
transitionRewardMatrix(ctmc.transitionRewardMatrix) {
if (ctmc.backwardTransitions != nullptr) {
this->backwardTransitions = new storm::models::GraphTransitions<T>(*ctmc.backwardTransitions);
}
}
//! Destructor
/*!
* Destructor. Frees the matrix and labeling associated with this CTMC.
*/
~Ctmc() {
if (this->backwardTransitions != nullptr) {
delete this->backwardTransitions;
}
}
/*!
* Returns the state space size of the CTMC.
* @return The size of the state space of the CTMC.
*/
uint_fast64_t getNumberOfStates() const {
return this->rateMatrix->getRowCount();
}
/*!
* Returns the number of (non-zero) transitions of the CTMC.
* @return The number of (non-zero) transitions of the CTMC.
*/
uint_fast64_t getNumberOfTransitions() const {
return this->rateMatrix->getNonZeroEntryCount();
}
/*!
* Returns a bit vector in which exactly those bits are set to true that
* correspond to a state labeled with the given atomic proposition.
* @param ap The atomic proposition for which to get the bit vector.
* @return A bit vector in which exactly those bits are set to true that
* correspond to a state labeled with the given atomic proposition.
*/
storm::storage::BitVector* getLabeledStates(std::string ap) const {
return this->stateLabeling->getAtomicProposition(ap);
}
/*!
* Returns a pointer to the matrix representing the transition probability
* function.
* @return A pointer to the matrix representing the transition probability
* function.
*/
std::shared_ptr<storm::storage::SparseMatrix<T>> getTransitionRateMatrix() const {
return this->rateMatrix;
}
/*!
* Returns a pointer to the matrix representing the transition rewards.
* @return A pointer to the matrix representing the transition rewards.
*/
std::shared_ptr<storm::storage::SparseMatrix<T>> getTransitionRewardMatrix() const {
return this->transitionRewardMatrix;
Ctmc(const Ctmc<T> &ctmc) : AbstractDeterministicModel<T>(ctmc) {
// Intentionally left empty.
}
/*!
* Returns a pointer to the vector representing the state rewards.
* @return A pointer to the vector representing the state rewards.
*/
std::shared_ptr<std::vector<T>> getStateRewards() const {
return this->stateRewards;
}
/*!
*
*/
std::set<std::string> const getPropositionsForState(uint_fast64_t const &state) const {
return stateLabeling->getPropositionsForState(state);
}
/*!
* Retrieves a reference to the backwards transition relation.
* @return A reference to the backwards transition relation.
*/
storm::models::GraphTransitions<T>& getBackwardTransitions() {
if (this->backwardTransitions == nullptr) {
this->backwardTransitions = new storm::models::GraphTransitions<T>(this->probabilityMatrix, false);
}
return *this->backwardTransitions;
}
/*!
* Prints information about the model to the specified stream.
* @param out The stream the information is to be printed to.
*/
void printModelInformationToStream(std::ostream& out) const {
out << "-------------------------------------------------------------- "
<< std::endl;
out << "Model type: \t\tCTMC" << std::endl;
out << "States: \t\t" << this->getNumberOfStates() << std::endl;
out << "Transitions: \t\t" << this->getNumberOfTransitions() << std::endl;
this->stateLabeling->printAtomicPropositionsInformationToStream(out);
out << "Size in memory: \t"
<< (this->rateMatrix->getSizeInMemory() +
this->stateLabeling->getSizeInMemory() +
sizeof(*this))/1024 << " kbytes" << std::endl;
out << "-------------------------------------------------------------- "
<< std::endl;
}
storm::models::ModelType getType() {
storm::models::ModelType getType() const {
return CTMC;
}
private:
/*! A matrix representing the transition rate function of the CTMC. */
std::shared_ptr<storm::storage::SparseMatrix<T>> rateMatrix;
/*! The labeling of the states of the CTMC. */
std::shared_ptr<storm::models::AtomicPropositionsLabeling> stateLabeling;
/*! The state-based rewards of the CTMC. */
std::shared_ptr<std::vector<T>> stateRewards;
/*! The transition-based rewards of the CTMC. */
std::shared_ptr<storm::storage::SparseMatrix<T>> transitionRewardMatrix;
/*!
* A data structure that stores the predecessors for all states. This is
* needed for backwards directed searches.
*/
storm::models::GraphTransitions<T>* backwardTransitions;
};
} // namespace models

175
src/models/Ctmdp.h

@ -8,19 +8,13 @@
#ifndef STORM_MODELS_CTMDP_H_
#define STORM_MODELS_CTMDP_H_
#include <ostream>
#include <iostream>
#include <memory>
#include <cstdlib>
#include <vector>
#include "AtomicPropositionsLabeling.h"
#include "GraphTransitions.h"
#include "AbstractNondeterministicModel.h"
#include "src/storage/SparseMatrix.h"
#include "src/exceptions/InvalidArgumentException.h"
#include "src/utility/CommandLine.h"
#include "src/utility/Settings.h"
#include "src/models/AbstractModel.h"
#include "src/parser/NonDeterministicSparseTransitionParser.h"
namespace storm {
@ -31,7 +25,7 @@ namespace models {
* labeled with atomic propositions.
*/
template <class T>
class Ctmdp : public storm::models::AbstractModel {
class Ctmdp : public storm::models::AbstractNondeterministicModel<T> {
public:
//! Constructor
@ -45,12 +39,10 @@ public:
*/
Ctmdp(std::shared_ptr<storm::storage::SparseMatrix<T>> probabilityMatrix,
std::shared_ptr<storm::models::AtomicPropositionsLabeling> stateLabeling,
std::shared_ptr<std::vector<uint_fast64_t>> rowMapping,
std::shared_ptr<std::vector<T>> stateRewards = nullptr,
std::shared_ptr<std::vector<uint_fast64_t>> choiceIndices,
std::shared_ptr<std::vector<T>> stateRewardVector = nullptr,
std::shared_ptr<storm::storage::SparseMatrix<T>> transitionRewardMatrix = nullptr)
: probabilityMatrix(probabilityMatrix), stateLabeling(stateLabeling), rowMapping(rowMapping),
stateRewards(stateRewards), transitionRewardMatrix(transitionRewardMatrix),
backwardTransitions(nullptr) {
: AbstractNondeterministicModel<T>(probabilityMatrix, stateLabeling, choiceIndices, stateRewardVector, transitionRewardMatrix) {
if (!this->checkValidityOfProbabilityMatrix()) {
LOG4CPLUS_ERROR(logger, "Probability matrix is invalid.");
throw storm::exceptions::InvalidArgumentException() << "Probability matrix is invalid.";
@ -62,12 +54,7 @@ public:
* Copy Constructor. Performs a deep copy of the given CTMDP.
* @param ctmdp A reference to the CTMDP that is to be copied.
*/
Ctmdp(const Ctmdp<T> &ctmdp) : probabilityMatrix(ctmdp.probabilityMatrix),
stateLabeling(ctmdp.stateLabeling), rowMapping(ctmdp.rowMapping), stateRewards(ctmdp.stateRewards),
transitionRewardMatrix(ctmdp.transitionRewardMatrix) {
if (ctmdp.backwardTransitions != nullptr) {
this->backwardTransitions = new storm::models::GraphTransitions<T>(*ctmdp.backwardTransitions);
}
Ctmdp(const Ctmdp<T> &ctmdp) : AbstractNondeterministicModel<T>(ctmdp) {
if (!this->checkValidityOfProbabilityMatrix()) {
LOG4CPLUS_ERROR(logger, "Probability matrix is invalid.");
throw storm::exceptions::InvalidArgumentException() << "Probability matrix is invalid.";
@ -76,130 +63,13 @@ public:
//! Destructor
/*!
* Destructor. Frees the matrix and labeling associated with this CTMDP.
* Destructor.
*/
~Ctmdp() {
if (this->backwardTransitions != nullptr) {
delete this->backwardTransitions;
}
}
/*!
* Returns the state space size of the CTMDP.
* @return The size of the state space of the CTMDP.
*/
uint_fast64_t getNumberOfStates() const {
return this->probabilityMatrix->getColumnCount();
// Intentionally left empty.
}
/*!
* Returns the number of (non-zero) transitions of the CTMDP.
* @return The number of (non-zero) transitions of the CTMDP.
*/
uint_fast64_t getNumberOfTransitions() const {
return this->probabilityMatrix->getNonZeroEntryCount();
}
/*!
* Returns a bit vector in which exactly those bits are set to true that
* correspond to a state labeled with the given atomic proposition.
* @param ap The atomic proposition for which to get the bit vector.
* @return A bit vector in which exactly those bits are set to true that
* correspond to a state labeled with the given atomic proposition.
*/
storm::storage::BitVector* getLabeledStates(std::string ap) const {
return this->stateLabeling->getAtomicProposition(ap);
}
/*!
* Returns a pointer to the matrix representing the transition probability
* function.
* @return A pointer to the matrix representing the transition probability
* function.
*/
std::shared_ptr<storm::storage::SparseMatrix<T>> getTransitionProbabilityMatrix() const {
return this->probabilityMatrix;
}
/*!
* Returns a pointer to the matrix representing the transition rewards.
* @return A pointer to the matrix representing the transition rewards.
*/
std::shared_ptr<storm::storage::SparseMatrix<T>> getTransitionRewardMatrix() const {
return this->transitionRewardMatrix;
}
/*!
* Returns a pointer to the vector representing the state rewards.
* @return A pointer to the vector representing the state rewards.
*/
std::shared_ptr<std::vector<T>> getStateRewards() const {
return this->stateRewards;
}
/*!
*
*/
std::set<std::string> const getPropositionsForState(uint_fast64_t const &state) const {
return stateLabeling->getPropositionsForState(state);
}
/*!
* Retrieves a reference to the backwards transition relation.
* @return A reference to the backwards transition relation.
*/
storm::models::GraphTransitions<T>& getBackwardTransitions() {
if (this->backwardTransitions == nullptr) {
this->backwardTransitions = new storm::models::GraphTransitions<T>(this->probabilityMatrix, false);
}
return *this->backwardTransitions;
}
/*!
* Retrieves whether this CTMDP has a state reward model.
* @return True if this CTMDP has a state reward model.
*/
bool hasStateRewards() {
return this->stateRewards != nullptr;
}
/*!
* Retrieves whether this CTMDP has a transition reward model.
* @return True if this CTMDP has a transition reward model.
*/
bool hasTransitionRewards() {
return this->transitionRewardMatrix != nullptr;
}
/*!
* Retrieves whether the given atomic proposition is a valid atomic proposition in this model.
* @param atomicProposition The atomic proposition to be checked for validity.
* @return True if the given atomic proposition is valid in this model.
*/
bool hasAtomicProposition(std::string const& atomicProposition) {
return this->stateLabeling->containsAtomicProposition(atomicProposition);
}
/*!
* Prints information about the model to the specified stream.
* @param out The stream the information is to be printed to.
*/
void printModelInformationToStream(std::ostream& out) const {
storm::utility::printSeparationLine(out);
out << std::endl;
out << "Model type: \t\tCTMDP" << std::endl;
out << "States: \t\t" << this->getNumberOfStates() << std::endl;
out << "Transitions: \t\t" << this->getNumberOfTransitions() << std::endl;
this->stateLabeling->printAtomicPropositionsInformationToStream(out);
out << "Size in memory: \t"
<< (this->probabilityMatrix->getSizeInMemory() +
this->stateLabeling->getSizeInMemory() +
sizeof(*this))/1024 << " kbytes" << std::endl;
out << std::endl;
storm::utility::printSeparationLine(out);
}
storm::models::ModelType getType() {
storm::models::ModelType getType() const {
return CTMDP;
}
@ -214,34 +84,13 @@ private:
// Get the settings object to customize linear solving.
storm::settings::Settings* s = storm::settings::instance();
double precision = s->get<double>("precision");
for (uint_fast64_t row = 0; row < this->probabilityMatrix->getRowCount(); row++) {
T sum = this->probabilityMatrix->getRowSum(row);
for (uint_fast64_t row = 0; row < this->getTransitionMatrix()->getRowCount(); row++) {
T sum = this->getTransitionMatrix()->getRowSum(row);
if (sum == 0) continue;
if (std::abs(sum - 1) > precision) return false;
}
return true;
}
/*! A matrix representing the transition probability function of the CTMDP. */
std::shared_ptr<storm::storage::SparseMatrix<T>> probabilityMatrix;
/*! The labeling of the states of the CTMDP. */
std::shared_ptr<storm::models::AtomicPropositionsLabeling> stateLabeling;
/*! The mapping from states to rows. */
std::shared_ptr<std::vector<uint_fast64_t>> rowMapping;
/*! The state-based rewards of the CTMDP. */
std::shared_ptr<std::vector<T>> stateRewards;
/*! The transition-based rewards of the CTMDP. */
std::shared_ptr<storm::storage::SparseMatrix<T>> transitionRewardMatrix;
/*!
* A data structure that stores the predecessors for all states. This is
* needed for backwards directed searches.
*/
storm::models::GraphTransitions<T>* backwardTransitions;
};
} // namespace models

173
src/models/Dtmc.h

@ -13,13 +13,11 @@
#include <memory>
#include <cstdlib>
#include "AbstractDeterministicModel.h"
#include "AtomicPropositionsLabeling.h"
#include "GraphTransitions.h"
#include "src/storage/SparseMatrix.h"
#include "src/exceptions/InvalidArgumentException.h"
#include "src/utility/CommandLine.h"
#include "src/utility/Settings.h"
#include "src/models/AbstractModel.h"
namespace storm {
@ -30,7 +28,7 @@ namespace models {
* labeled with atomic propositions.
*/
template <class T>
class Dtmc : public storm::models::AbstractModel {
class Dtmc : public storm::models::AbstractDeterministicModel<T> {
public:
//! Constructor
@ -44,17 +42,15 @@ public:
*/
Dtmc(std::shared_ptr<storm::storage::SparseMatrix<T>> probabilityMatrix,
std::shared_ptr<storm::models::AtomicPropositionsLabeling> stateLabeling,
std::shared_ptr<std::vector<T>> stateRewards = nullptr,
std::shared_ptr<std::vector<T>> stateRewardVector = nullptr,
std::shared_ptr<storm::storage::SparseMatrix<T>> transitionRewardMatrix = nullptr)
: probabilityMatrix(probabilityMatrix), stateLabeling(stateLabeling),
stateRewards(stateRewards), transitionRewardMatrix(transitionRewardMatrix),
backwardTransitions(nullptr) {
: AbstractDeterministicModel<T>(probabilityMatrix, stateLabeling, stateRewardVector, transitionRewardMatrix) {
if (!this->checkValidityOfProbabilityMatrix()) {
LOG4CPLUS_ERROR(logger, "Probability matrix is invalid.");
throw storm::exceptions::InvalidArgumentException() << "Probability matrix is invalid.";
}
if (this->transitionRewardMatrix != nullptr) {
if (!this->transitionRewardMatrix->isSubmatrixOf(*(this->probabilityMatrix))) {
if (this->getTransitionRewardMatrix() != nullptr) {
if (!this->getTransitionRewardMatrix()->isSubmatrixOf(*(this->getTransitionMatrix()))) {
LOG4CPLUS_ERROR(logger, "Transition reward matrix is not a submatrix of the transition matrix, i.e. there are rewards for transitions that do not exist.");
throw storm::exceptions::InvalidArgumentException() << "There are transition rewards for nonexistent transitions.";
}
@ -66,146 +62,23 @@ public:
* Copy Constructor. Performs a deep copy of the given DTMC.
* @param dtmc A reference to the DTMC that is to be copied.
*/
Dtmc(const Dtmc<T> &dtmc) : probabilityMatrix(dtmc.probabilityMatrix),
stateLabeling(dtmc.stateLabeling), stateRewards(dtmc.stateRewards),
transitionRewardMatrix(dtmc.transitionRewardMatrix) {
if (dtmc.backwardTransitions != nullptr) {
this->backwardTransitions = new storm::models::GraphTransitions<T>(*dtmc.backwardTransitions);
}
// no checks here, as they have already been performed for dtmc.
Dtmc(const Dtmc<T> &dtmc) : AbstractDeterministicModel<T>(dtmc) {
// Intentionally left empty.
}
//! Destructor
/*!
* Destructor. Frees the matrix and labeling associated with this DTMC.
* Destructor.
*/
~Dtmc() {
if (this->backwardTransitions != nullptr) {
delete this->backwardTransitions;
}
}
/*!
* Returns the state space size of the DTMC.
* @return The size of the state space of the DTMC.
*/
uint_fast64_t getNumberOfStates() const {
return this->probabilityMatrix->getRowCount();
}
/*!
* Returns the number of (non-zero) transitions of the DTMC.
* @return The number of (non-zero) transitions of the DTMC.
*/
uint_fast64_t getNumberOfTransitions() const {
return this->probabilityMatrix->getNonZeroEntryCount();
}
/*!
* Returns a bit vector in which exactly those bits are set to true that
* correspond to a state labeled with the given atomic proposition.
* @param ap The atomic proposition for which to get the bit vector.
* @return A bit vector in which exactly those bits are set to true that
* correspond to a state labeled with the given atomic proposition.
*/
storm::storage::BitVector* getLabeledStates(std::string ap) const {
return this->stateLabeling->getAtomicProposition(ap);
}
/*!
* Returns a pointer to the matrix representing the transition probability
* function.
* @return A pointer to the matrix representing the transition probability
* function.
*/
std::shared_ptr<storm::storage::SparseMatrix<T>> getTransitionProbabilityMatrix() const {
return this->probabilityMatrix;
}
/*!
* Returns a pointer to the matrix representing the transition rewards.
* @return A pointer to the matrix representing the transition rewards.
*/
std::shared_ptr<storm::storage::SparseMatrix<T>> getTransitionRewardMatrix() const {
return this->transitionRewardMatrix;
}
/*!
* Returns a pointer to the vector representing the state rewards.
* @return A pointer to the vector representing the state rewards.
*/
std::shared_ptr<std::vector<T>> getStateRewards() const {
return this->stateRewards;
}
/*!
*
*/
std::set<std::string> const getPropositionsForState(uint_fast64_t const &state) const {
return stateLabeling->getPropositionsForState(state);
}
/*!
* Retrieves a reference to the backwards transition relation.
* @return A reference to the backwards transition relation.
*/
storm::models::GraphTransitions<T>& getBackwardTransitions() {
if (this->backwardTransitions == nullptr) {
this->backwardTransitions = new storm::models::GraphTransitions<T>(this->probabilityMatrix, false);
}
return *this->backwardTransitions;
}
/*!
* Retrieves whether this DTMC has a state reward model.
* @return True if this DTMC has a state reward model.
*/
bool hasStateRewards() {
return this->stateRewards != nullptr;
}
/*!
* Retrieves whether this DTMC has a transition reward model.
* @return True if this DTMC has a transition reward model.
*/
bool hasTransitionRewards() {
return this->transitionRewardMatrix != nullptr;
}
/*!
* Retrieves whether the given atomic proposition is a valid atomic proposition in this model.
* @param atomicProposition The atomic proposition to be checked for validity.
* @return True if the given atomic proposition is valid in this model.
*/
bool hasAtomicProposition(std::string const& atomicProposition) {
return this->stateLabeling->containsAtomicProposition(atomicProposition);
}
/*!
* Prints information about the model to the specified stream.
* @param out The stream the information is to be printed to.
*/
void printModelInformationToStream(std::ostream& out) const {
storm::utility::printSeparationLine(out);
out << std::endl;
out << "Model type: \t\tDTMC" << std::endl;
out << "States: \t\t" << this->getNumberOfStates() << std::endl;
out << "Transitions: \t\t" << this->getNumberOfTransitions() << std::endl;
this->stateLabeling->printAtomicPropositionsInformationToStream(out);
out << "Size in memory: \t"
<< (this->probabilityMatrix->getSizeInMemory() +
this->stateLabeling->getSizeInMemory() +
sizeof(*this))/1024 << " kbytes" << std::endl;
out << std::endl;
storm::utility::printSeparationLine(out);
// Intentionally left empty.
}
storm::models::ModelType getType() {
storm::models::ModelType getType() const {
return DTMC;
}
private:
/*!
* @brief Perform some sanity checks.
*
@ -216,14 +89,14 @@ private:
storm::settings::Settings* s = storm::settings::instance();
double precision = s->get<double>("precision");
if (this->probabilityMatrix->getRowCount() != this->probabilityMatrix->getColumnCount()) {
if (this->getTransitionMatrix()->getRowCount() != this->getTransitionMatrix()->getColumnCount()) {
// not square
LOG4CPLUS_ERROR(logger, "Probability matrix is not square.");
return false;
}
for (uint_fast64_t row = 0; row < this->probabilityMatrix->getRowCount(); row++) {
T sum = this->probabilityMatrix->getRowSum(row);
for (uint_fast64_t row = 0; row < this->getTransitionMatrix()->getRowCount(); row++) {
T sum = this->getTransitionMatrix()->getRowSum(row);
if (sum == 0) {
LOG4CPLUS_ERROR(logger, "Row " << row << " has sum 0");
return false;
@ -235,24 +108,6 @@ private:
}
return true;
}
/*! A matrix representing the transition probability function of the DTMC. */
std::shared_ptr<storm::storage::SparseMatrix<T>> probabilityMatrix;
/*! The labeling of the states of the DTMC. */
std::shared_ptr<storm::models::AtomicPropositionsLabeling> stateLabeling;
/*! The state-based rewards of the DTMC. */
std::shared_ptr<std::vector<T>> stateRewards;
/*! The transition-based rewards of the DTMC. */
std::shared_ptr<storm::storage::SparseMatrix<T>> transitionRewardMatrix;
/*!
* A data structure that stores the predecessors for all states. This is
* needed for backwards directed searches.
*/
storm::models::GraphTransitions<T>* backwardTransitions;
};
} // namespace models

104
src/models/GraphTransitions.h

@ -40,7 +40,7 @@ public:
* of the backwards transition relation.
*/
GraphTransitions(std::shared_ptr<storm::storage::SparseMatrix<T>> transitionMatrix, bool forward)
: successorList(nullptr), stateIndications(nullptr), numberOfStates(transitionMatrix->getRowCount()), numberOfNonZeroTransitions(transitionMatrix->getNonZeroEntryCount()) {
: successorList(nullptr), stateIndications(nullptr), numberOfStates(transitionMatrix->getColumnCount()), numberOfTransitions(transitionMatrix->getNonZeroEntryCount()) {
if (forward) {
this->initializeForward(transitionMatrix);
} else {
@ -48,6 +48,15 @@ public:
}
}
GraphTransitions(std::shared_ptr<storm::storage::SparseMatrix<T>> transitionMatrix, std::shared_ptr<std::vector<uint_fast64_t>> choiceIndices, bool forward)
: successorList(nullptr), stateIndications(nullptr), numberOfStates(transitionMatrix->getColumnCount()), numberOfTransitions(transitionMatrix->getNonZeroEntryCount()) {
if (forward) {
this->initializeForward(transitionMatrix, choiceIndices);
} else {
this->initializeBackward(transitionMatrix, choiceIndices);
}
}
//! Destructor
/*!
* Destructor. Frees the internal storage.
@ -61,6 +70,16 @@ public:
}
}
/*!
* Retrieves the size of the internal representation of the graph transitions in memory.
* @return the size of the internal representation of the graph transitions in memory
* measured in bytes.
*/
virtual uint_fast64_t getSizeInMemory() const {
uint_fast64_t result = sizeof(this) + (numberOfStates + numberOfTransitions + 1) * sizeof(uint_fast64_t);
return result;
}
/*!
* Returns an iterator to the successors of the given state.
* @param state The state for which to get the successor iterator.
@ -88,18 +107,37 @@ private:
* relation given by means of a sparse matrix.
*/
void initializeForward(std::shared_ptr<storm::storage::SparseMatrix<T>> transitionMatrix) {
this->successorList = new uint_fast64_t[numberOfNonZeroTransitions];
this->successorList = new uint_fast64_t[numberOfTransitions];
this->stateIndications = new uint_fast64_t[numberOfStates + 1];
// First, we copy the index list from the sparse matrix as this will
// stay the same.
std::copy(transitionMatrix->getRowIndicationsPointer().begin(), transitionMatrix->getRowIndicationsPointer().end(), this->stateIndications);
std::copy(transitionMatrix->getRowIndications().begin(), transitionMatrix->getRowIndications().end(), this->stateIndications);
// Now we can iterate over all rows of the transition matrix and record
// the target state.
for (uint_fast64_t i = 0, currentNonZeroElement = 0; i < numberOfStates; i++) {
for (auto rowIt = transitionMatrix->beginConstColumnIterator(i); rowIt != transitionMatrix->endConstColumnIterator(i); ++rowIt) {
this->stateIndications[currentNonZeroElement++] = *rowIt;
this->successorList[currentNonZeroElement++] = *rowIt;
}
}
}
void initializeForward(std::shared_ptr<storm::storage::SparseMatrix<T>> transitionMatrix, std::shared_ptr<std::vector<uint_fast64_t>> choiceIndices) {
this->successorList = new uint_fast64_t[numberOfTransitions];
this->stateIndications = new uint_fast64_t[numberOfStates + 1];
for (uint_fast64_t i = 0; i < numberOfStates; ++i) {
this->stateIndications[i] = transitionMatrix->getRowIndications().at(choiceIndices->at(i));
}
// Now we can iterate over all rows of the transition matrix and record
// the target state.
for (uint_fast64_t i = 0, currentNonZeroElement = 0; i < numberOfStates; i++) {
for (uint_fast64_t j = choiceIndices->at(i); j < choiceIndices->at(i + 1); ++j) {
for (auto rowIt = transitionMatrix->beginConstColumnIterator(j); rowIt != transitionMatrix->endConstColumnIterator(j); ++rowIt) {
this->successorList[currentNonZeroElement++] = *rowIt;
}
}
}
}
@ -110,27 +148,25 @@ private:
* matrix.
*/
void initializeBackward(std::shared_ptr<storm::storage::SparseMatrix<T>> transitionMatrix) {
this->successorList = new uint_fast64_t[numberOfNonZeroTransitions];
this->stateIndications = new uint_fast64_t[numberOfStates + 1];
this->successorList = new uint_fast64_t[numberOfTransitions];
this->stateIndications = new uint_fast64_t[numberOfStates + 1]();
// First, we need to count how many backward transitions each state has.
// NOTE: We disregard the diagonal here, as we only consider "true"
// predecessors.
for (uint_fast64_t i = 0; i < numberOfStates; i++) {
for (uint_fast64_t i = 0; i < numberOfStates; ++i) {
for (auto rowIt = transitionMatrix->beginConstColumnIterator(i); rowIt != transitionMatrix->endConstColumnIterator(i); ++rowIt) {
this->stateIndications[*rowIt + 1]++;
}
}
// Now compute the accumulated offsets.
for (uint_fast64_t i = 1; i < numberOfStates; i++) {
for (uint_fast64_t i = 1; i < numberOfStates; ++i) {
this->stateIndications[i] = this->stateIndications[i - 1] + this->stateIndications[i];
}
// Put a sentinel element at the end of the indices list. This way,
// for each state i the range of indices can be read off between
// state_indices_list[i] and state_indices_list[i + 1].
this->stateIndications[numberOfStates] = numberOfNonZeroTransitions;
this->stateIndications[numberOfStates] = numberOfTransitions;
// Create an array that stores the next index for each state. Initially
// this corresponds to the previously computed accumulated offsets.
@ -139,7 +175,7 @@ private:
// Now we are ready to actually fill in the list of predecessors for
// every state. Again, we start by considering all but the last row.
for (uint_fast64_t i = 0; i < numberOfStates; i++) {
for (uint_fast64_t i = 0; i < numberOfStates; ++i) {
for (auto rowIt = transitionMatrix->beginConstColumnIterator(i); rowIt != transitionMatrix->endConstColumnIterator(i); ++rowIt) {
this->successorList[nextIndicesList[*rowIt]++] = i;
}
@ -149,6 +185,48 @@ private:
delete[] nextIndicesList;
}
void initializeBackward(std::shared_ptr<storm::storage::SparseMatrix<T>> transitionMatrix, std::shared_ptr<std::vector<uint_fast64_t>> choiceIndices) {
this->successorList = new uint_fast64_t[numberOfTransitions];
this->stateIndications = new uint_fast64_t[numberOfStates + 1]();
// First, we need to count how many backward transitions each state has.
for (uint_fast64_t i = 0; i < numberOfStates; ++i) {
for (uint_fast64_t j = choiceIndices->at(i); j < choiceIndices->at(i + 1); ++j) {
for (auto rowIt = transitionMatrix->beginConstColumnIterator(j); rowIt != transitionMatrix->endConstColumnIterator(j); ++rowIt) {
this->stateIndications[*rowIt + 1]++;
}
}
}
// Now compute the accumulated offsets.
for (uint_fast64_t i = 1; i < numberOfStates; i++) {
this->stateIndications[i] = this->stateIndications[i - 1] + this->stateIndications[i];
}
// Put a sentinel element at the end of the indices list. This way,
// for each state i the range of indices can be read off between
// state_indices_list[i] and state_indices_list[i + 1].
this->stateIndications[numberOfStates] = numberOfTransitions;
// Create an array that stores the next index for each state. Initially
// this corresponds to the previously computed accumulated offsets.
uint_fast64_t* nextIndicesList = new uint_fast64_t[numberOfStates];
std::copy(stateIndications, stateIndications + numberOfStates, nextIndicesList);
// Now we are ready to actually fill in the list of predecessors for
// every state. Again, we start by considering all but the last row.
for (uint_fast64_t i = 0; i < numberOfStates; i++) {
for (uint_fast64_t j = (*choiceIndices)[i]; j < (*choiceIndices)[i + 1]; ++j) {
for (auto rowIt = transitionMatrix->beginConstColumnIterator(j); rowIt != transitionMatrix->endConstColumnIterator(j); ++rowIt) {
this->successorList[nextIndicesList[*rowIt]++] = i;
}
}
}
// Now we can dispose of the auxiliary array.
delete[] nextIndicesList;
}
/*! A list of successors for *all* states. */
uint_fast64_t* successorList;
@ -168,7 +246,7 @@ private:
* Store the number of non-zero transition entries to determine the highest
* index at which the predecessor_list may be accessed.
*/
uint_fast64_t numberOfNonZeroTransitions;
uint_fast64_t numberOfTransitions;
};
} // namespace models

175
src/models/Mdp.h

@ -14,13 +14,9 @@
#include <cstdlib>
#include "AtomicPropositionsLabeling.h"
#include "GraphTransitions.h"
#include "src/storage/SparseMatrix.h"
#include "src/exceptions/InvalidArgumentException.h"
#include "src/utility/CommandLine.h"
#include "src/utility/Settings.h"
#include "src/models/AbstractModel.h"
#include "src/parser/NonDeterministicSparseTransitionParser.h"
#include "src/models/AbstractNondeterministicModel.h"
namespace storm {
@ -31,7 +27,7 @@ namespace models {
* labeled with atomic propositions.
*/
template <class T>
class Mdp : public storm::models::AbstractModel {
class Mdp : public storm::models::AbstractNondeterministicModel<T> {
public:
//! Constructor
@ -45,12 +41,10 @@ public:
*/
Mdp(std::shared_ptr<storm::storage::SparseMatrix<T>> probabilityMatrix,
std::shared_ptr<storm::models::AtomicPropositionsLabeling> stateLabeling,
std::shared_ptr<std::vector<uint_fast64_t>> rowMapping,
std::shared_ptr<std::vector<T>> stateRewards = nullptr,
std::shared_ptr<std::vector<uint_fast64_t>> choiceIndices,
std::shared_ptr<std::vector<T>> stateRewardVector = nullptr,
std::shared_ptr<storm::storage::SparseMatrix<T>> transitionRewardMatrix = nullptr)
: probabilityMatrix(probabilityMatrix), stateLabeling(stateLabeling), rowMapping(rowMapping),
stateRewards(stateRewards), transitionRewardMatrix(transitionRewardMatrix),
backwardTransitions(nullptr) {
: AbstractNondeterministicModel<T>(probabilityMatrix, stateLabeling, choiceIndices, stateRewardVector, transitionRewardMatrix) {
if (!this->checkValidityOfProbabilityMatrix()) {
LOG4CPLUS_ERROR(logger, "Probability matrix is invalid.");
throw storm::exceptions::InvalidArgumentException() << "Probability matrix is invalid.";
@ -62,12 +56,7 @@ public:
* Copy Constructor. Performs a deep copy of the given MDP.
* @param mdp A reference to the MDP that is to be copied.
*/
Mdp(const Mdp<T> &mdp) : probabilityMatrix(mdp.probabilityMatrix),
stateLabeling(mdp.stateLabeling), rowMapping(mdp.rowMapping), stateRewards(mdp.stateRewards),
transitionRewardMatrix(mdp.transitionRewardMatrix) {
if (mdp.backwardTransitions != nullptr) {
this->backwardTransitions = new storm::models::GraphTransitions<T>(*mdp.backwardTransitions);
}
Mdp(const Mdp<T> &mdp) : AbstractNondeterministicModel<T>(mdp) {
if (!this->checkValidityOfProbabilityMatrix()) {
LOG4CPLUS_ERROR(logger, "Probability matrix is invalid.");
throw storm::exceptions::InvalidArgumentException() << "Probability matrix is invalid.";
@ -76,130 +65,13 @@ public:
//! Destructor
/*!
* Destructor. Frees the matrix and labeling associated with this MDP.
* Destructor.
*/
~Mdp() {
if (this->backwardTransitions != nullptr) {
delete this->backwardTransitions;
}
}
/*!
* Returns the state space size of the MDP.
* @return The size of the state space of the MDP.
*/
uint_fast64_t getNumberOfStates() const {
return this->probabilityMatrix->getColumnCount();
// Intentionally left empty.
}
/*!
* Returns the number of (non-zero) transitions of the MDP.
* @return The number of (non-zero) transitions of the MDP.
*/
uint_fast64_t getNumberOfTransitions() const {
return this->probabilityMatrix->getNonZeroEntryCount();
}
/*!
* Returns a bit vector in which exactly those bits are set to true that
* correspond to a state labeled with the given atomic proposition.
* @param ap The atomic proposition for which to get the bit vector.
* @return A bit vector in which exactly those bits are set to true that
* correspond to a state labeled with the given atomic proposition.
*/
storm::storage::BitVector* getLabeledStates(std::string ap) const {
return this->stateLabeling->getAtomicProposition(ap);
}
/*!
* Returns a pointer to the matrix representing the transition probability
* function.
* @return A pointer to the matrix representing the transition probability
* function.
*/
std::shared_ptr<storm::storage::SparseMatrix<T>> getTransitionProbabilityMatrix() const {
return this->probabilityMatrix;
}
/*!
* Returns a pointer to the matrix representing the transition rewards.
* @return A pointer to the matrix representing the transition rewards.
*/
std::shared_ptr<storm::storage::SparseMatrix<T>> getTransitionRewardMatrix() const {
return this->transitionRewardMatrix;
}
/*!
* Returns a pointer to the vector representing the state rewards.
* @return A pointer to the vector representing the state rewards.
*/
std::shared_ptr<std::vector<T>> getStateRewards() const {
return this->stateRewards;
}
/*!
*
*/
std::set<std::string> const getPropositionsForState(uint_fast64_t const &state) const {
return stateLabeling->getPropositionsForState(state);
}
/*!
* Retrieves a reference to the backwards transition relation.
* @return A reference to the backwards transition relation.
*/
storm::models::GraphTransitions<T>& getBackwardTransitions() {
if (this->backwardTransitions == nullptr) {
this->backwardTransitions = new storm::models::GraphTransitions<T>(this->probabilityMatrix, false);
}
return *this->backwardTransitions;
}
/*!
* Retrieves whether this MDP has a state reward model.
* @return True if this MDP has a state reward model.
*/
bool hasStateRewards() {
return this->stateRewards != nullptr;
}
/*!
* Retrieves whether this MDP has a transition reward model.
* @return True if this MDP has a transition reward model.
*/
bool hasTransitionRewards() {
return this->transitionRewardMatrix != nullptr;
}
/*!
* Retrieves whether the given atomic proposition is a valid atomic proposition in this model.
* @param atomicProposition The atomic proposition to be checked for validity.
* @return True if the given atomic proposition is valid in this model.
*/
bool hasAtomicProposition(std::string const& atomicProposition) {
return this->stateLabeling->containsAtomicProposition(atomicProposition);
}
/*!
* Prints information about the model to the specified stream.
* @param out The stream the information is to be printed to.
*/
void printModelInformationToStream(std::ostream& out) const {
storm::utility::printSeparationLine(out);
out << std::endl;
out << "Model type: \t\tMDP" << std::endl;
out << "States: \t\t" << this->getNumberOfStates() << std::endl;
out << "Transitions: \t\t" << this->getNumberOfTransitions() << std::endl;
this->stateLabeling->printAtomicPropositionsInformationToStream(out);
out << "Size in memory: \t"
<< (this->probabilityMatrix->getSizeInMemory() +
this->stateLabeling->getSizeInMemory() +
sizeof(*this))/1024 << " kbytes" << std::endl;
out << std::endl;
storm::utility::printSeparationLine(out);
}
storm::models::ModelType getType() {
storm::models::ModelType getType() const {
return MDP;
}
@ -214,34 +86,15 @@ private:
// Get the settings object to customize linear solving.
storm::settings::Settings* s = storm::settings::instance();
double precision = s->get<double>("precision");
for (uint_fast64_t row = 0; row < this->probabilityMatrix->getRowCount(); row++) {
T sum = this->probabilityMatrix->getRowSum(row);
for (uint_fast64_t row = 0; row < this->getTransitionMatrix()->getRowCount(); row++) {
T sum = this->getTransitionMatrix()->getRowSum(row);
if (sum == 0) continue;
if (std::abs(sum - 1) > precision) return false;
if (std::abs(sum - 1) > precision) {
return false;
}
}
return true;
}
/*! A matrix representing the transition probability function of the MDP. */
std::shared_ptr<storm::storage::SparseMatrix<T>> probabilityMatrix;
/*! The labeling of the states of the MDP. */
std::shared_ptr<storm::models::AtomicPropositionsLabeling> stateLabeling;
/*! The mapping from states to rows. */
std::shared_ptr<std::vector<uint_fast64_t>> rowMapping;
/*! The state-based rewards of the MDP. */
std::shared_ptr<std::vector<T>> stateRewards;
/*! The transition-based rewards of the MDP. */
std::shared_ptr<storm::storage::SparseMatrix<T>> transitionRewardMatrix;
/*!
* A data structure that stores the predecessors for all states. This is
* needed for backwards directed searches.
*/
storm::models::GraphTransitions<T>* backwardTransitions;
};
} // namespace models

79
src/parser/AutoParser.cpp

@ -1,79 +0,0 @@
#include "src/parser/AutoParser.h"
#include <string>
#include <cctype>
#include "src/exceptions/WrongFormatException.h"
#include "src/models/AbstractModel.h"
#include "src/parser/DeterministicModelParser.h"
#include "src/parser/NonDeterministicModelParser.h"
namespace storm {
namespace parser {
AutoParser::AutoParser(std::string const & transitionSystemFile, std::string const & labelingFile,
std::string const & stateRewardFile, std::string const & transitionRewardFile)
: model(nullptr) {
storm::models::ModelType type = this->analyzeHint(transitionSystemFile);
if (type == storm::models::Unknown) {
LOG4CPLUS_ERROR(logger, "Could not determine file type of " << transitionSystemFile << ".");
LOG4CPLUS_ERROR(logger, "The first line of the file should contain a format hint. Please fix your file and try again.");
throw storm::exceptions::WrongFormatException() << "Could not determine type of file " << transitionSystemFile;
} else {
LOG4CPLUS_INFO(logger, "Model type seems to be " << type);
}
// Do actual parsing
switch (type) {
case storm::models::DTMC: {
DeterministicModelParser parser(transitionSystemFile, labelingFile, stateRewardFile, transitionRewardFile);
this->model = parser.getDtmc();
break;
}
case storm::models::CTMC: {
DeterministicModelParser parser(transitionSystemFile, labelingFile, stateRewardFile, transitionRewardFile);
this->model = parser.getCtmc();
break;
}
case storm::models::MDP: {
NonDeterministicModelParser parser(transitionSystemFile, labelingFile, stateRewardFile, transitionRewardFile);
this->model = parser.getMdp();
break;
}
case storm::models::CTMDP: {
NonDeterministicModelParser parser(transitionSystemFile, labelingFile, stateRewardFile, transitionRewardFile);
this->model = parser.getCtmdp();
break;
}
default: ; // Unknown
}
if (!this->model) {
LOG4CPLUS_WARN(logger, "Model is still null.");
}
}
storm::models::ModelType AutoParser::analyzeHint(const std::string& filename) {
storm::models::ModelType hintType = storm::models::Unknown;
// Open file
MappedFile file(filename.c_str());
char* buf = file.data;
// parse hint
char hint[128];
sscanf(buf, "%s\n", hint);
for (char* c = hint; *c != '\0'; c++) *c = toupper(*c);
// check hint
if (strncmp(hint, "DTMC", sizeof(hint)) == 0) hintType = storm::models::DTMC;
else if (strncmp(hint, "CTMC", sizeof(hint)) == 0) hintType = storm::models::CTMC;
else if (strncmp(hint, "MDP", sizeof(hint)) == 0) hintType = storm::models::MDP;
else if (strncmp(hint, "CTMDP", sizeof(hint)) == 0) hintType = storm::models::CTMDP;
return hintType;
}
} // namespace parser
} // namespace storm

76
src/parser/AutoParser.h

@ -4,11 +4,19 @@
#include "src/parser/Parser.h"
#include "src/models/AbstractModel.h"
#include "src/exceptions/WrongFormatException.h"
#include "src/models/AbstractModel.h"
#include "src/parser/DeterministicModelParser.h"
#include "src/parser/NondeterministicModelParser.h"
#include <memory>
#include <iostream>
#include <utility>
#include <string>
#include <cctype>
namespace storm {
namespace parser {
/*!
@ -21,10 +29,51 @@ namespace parser {
* When the files are parsed successfully, the parsed ModelType and Model
* can be obtained via getType() and getModel<ModelClass>().
*/
template<class T>
class AutoParser : Parser {
public:
AutoParser(std::string const & transitionSystemFile, std::string const & labelingFile,
std::string const & stateRewardFile = "", std::string const & transitionRewardFile = "");
std::string const & stateRewardFile = "", std::string const & transitionRewardFile = "") : model(nullptr) {
storm::models::ModelType type = this->analyzeHint(transitionSystemFile);
if (type == storm::models::Unknown) {
LOG4CPLUS_ERROR(logger, "Could not determine file type of " << transitionSystemFile << ".");
LOG4CPLUS_ERROR(logger, "The first line of the file should contain a format hint. Please fix your file and try again.");
throw storm::exceptions::WrongFormatException() << "Could not determine type of file " << transitionSystemFile;
} else {
LOG4CPLUS_INFO(logger, "Model type seems to be " << type);
}
// Do actual parsing
switch (type) {
case storm::models::DTMC: {
DeterministicModelParser parser(transitionSystemFile, labelingFile, stateRewardFile, transitionRewardFile);
this->model = parser.getDtmc();
break;
}
case storm::models::CTMC: {
DeterministicModelParser parser(transitionSystemFile, labelingFile, stateRewardFile, transitionRewardFile);
this->model = parser.getCtmc();
break;
}
case storm::models::MDP: {
NondeterministicModelParser parser(transitionSystemFile, labelingFile, stateRewardFile, transitionRewardFile);
this->model = parser.getMdp();
break;
}
case storm::models::CTMDP: {
NondeterministicModelParser parser(transitionSystemFile, labelingFile, stateRewardFile, transitionRewardFile);
this->model = parser.getCtmdp();
break;
}
default: ; // Unknown
}
if (!this->model) {
LOG4CPLUS_WARN(logger, "Model is still null.");
}
}
/*!
* @brief Returns the type of model that was parsed.
@ -39,7 +88,7 @@ class AutoParser : Parser {
*/
template <typename Model>
std::shared_ptr<Model> getModel() {
return this->model->as<Model>();
return this->model->template as<Model>();
}
private:
@ -47,15 +96,34 @@ class AutoParser : Parser {
/*!
* @brief Open file and read file format hint.
*/
storm::models::ModelType analyzeHint(const std::string& filename);
storm::models::ModelType analyzeHint(const std::string& filename) {
storm::models::ModelType hintType = storm::models::Unknown;
// Open file
MappedFile file(filename.c_str());
char* buf = file.data;
// parse hint
char hint[128];
sscanf(buf, "%s\n", hint);
for (char* c = hint; *c != '\0'; c++) *c = toupper(*c);
// check hint
if (strncmp(hint, "DTMC", sizeof(hint)) == 0) hintType = storm::models::DTMC;
else if (strncmp(hint, "CTMC", sizeof(hint)) == 0) hintType = storm::models::CTMC;
else if (strncmp(hint, "MDP", sizeof(hint)) == 0) hintType = storm::models::MDP;
else if (strncmp(hint, "CTMDP", sizeof(hint)) == 0) hintType = storm::models::CTMDP;
return hintType;
}
/*!
* @brief Pointer to a parser that has parsed the given transition system.
*/
std::shared_ptr<storm::models::AbstractModel> model;
std::shared_ptr<storm::models::AbstractModel<T>> model;
};
} // namespace parser
} // namespace storm
#endif /* STORM_PARSER_AUTOPARSER_H_ */

10
src/parser/NonDeterministicModelParser.cpp → src/parser/NondeterministicModelParser.cpp

@ -5,12 +5,12 @@
* Author: Philipp Berger
*/
#include "src/parser/NonDeterministicModelParser.h"
#include "src/parser/NondeterministicModelParser.h"
#include <string>
#include <vector>
#include "src/parser/NonDeterministicSparseTransitionParser.h"
#include "src/parser/NondeterministicSparseTransitionParser.h"
#include "src/parser/AtomicPropositionLabelingParser.h"
#include "src/parser/SparseStateRewardParser.h"
@ -27,9 +27,9 @@ namespace parser {
* @param stateRewardFile String containing the location of the state reward file (...srew)
* @param transitionRewardFile String containing the location of the transition reward file (...trew)
*/
NonDeterministicModelParser::NonDeterministicModelParser(std::string const & transitionSystemFile, std::string const & labelingFile,
NondeterministicModelParser::NondeterministicModelParser(std::string const & transitionSystemFile, std::string const & labelingFile,
std::string const & stateRewardFile, std::string const & transitionRewardFile) {
storm::parser::NonDeterministicSparseTransitionParser tp(transitionSystemFile);
storm::parser::NondeterministicSparseTransitionParser tp(transitionSystemFile);
uint_fast64_t stateCount = tp.getMatrix()->getRowCount();
storm::parser::AtomicPropositionLabelingParser lp(stateCount, labelingFile);
@ -38,7 +38,7 @@ NonDeterministicModelParser::NonDeterministicModelParser(std::string const & tra
this->stateRewards = srp.getStateRewards();
}
if (transitionRewardFile != "") {
storm::parser::NonDeterministicSparseTransitionParser trp(transitionRewardFile);
storm::parser::NondeterministicSparseTransitionParser trp(transitionRewardFile);
this->transitionRewardMatrix = trp.getMatrix();
}

7
src/parser/NonDeterministicModelParser.h → src/parser/NondeterministicModelParser.h

@ -13,6 +13,7 @@
#include "src/models/Ctmdp.h"
namespace storm {
namespace parser {
/*!
@ -23,9 +24,9 @@ namespace parser {
*
* @note The labeling representation in the file may use at most as much nodes as are specified in the mdp.
*/
class NonDeterministicModelParser: public storm::parser::Parser {
class NondeterministicModelParser: public storm::parser::Parser {
public:
NonDeterministicModelParser(std::string const & transitionSystemFile, std::string const & labelingFile,
NondeterministicModelParser(std::string const & transitionSystemFile, std::string const & labelingFile,
std::string const & stateRewardFile = "", std::string const & transitionRewardFile = "");
std::shared_ptr<storm::models::Mdp<double>> getMdp() {
@ -58,5 +59,7 @@ private:
};
} /* namespace parser */
} /* namespace storm */
#endif /* STORM_PARSER_NONDETERMINISTICMODELPARSER_H_ */

146
src/parser/NonDeterministicSparseTransitionParser.cpp → src/parser/NondeterministicSparseTransitionParser.cpp

@ -5,7 +5,7 @@
* Author: Gereon Kremer
*/
#include "src/parser/NonDeterministicSparseTransitionParser.h"
#include "src/parser/NondeterministicSparseTransitionParser.h"
#include <errno.h>
#include <time.h>
@ -49,7 +49,7 @@ namespace parser {
* @param maxnode Is set to highest id of all nodes.
* @return The number of non-zero elements.
*/
uint_fast64_t NonDeterministicSparseTransitionParser::firstPass(char* buf, uint_fast64_t& choices, int_fast64_t& maxnode) {
uint_fast64_t NondeterministicSparseTransitionParser::firstPass(char* buf, uint_fast64_t& choices, int_fast64_t& maxnode) {
/*
* Check file header and extract number of transitions.
*/
@ -70,14 +70,14 @@ uint_fast64_t NonDeterministicSparseTransitionParser::firstPass(char* buf, uint_
* Parse number of transitions.
* We will not actually use this value, but we will compare it to the
* number of transitions we count and issue a warning if this parsed
* vlaue is wrong.
* value is wrong.
*/
uint_fast64_t parsed_nonzero = strtol(buf, &buf, 10);
/*
* Read all transitions.
*/
int_fast64_t source, target;
int_fast64_t source, target, choice, lastchoice = -1;
int_fast64_t lastsource = -1;
uint_fast64_t nonzero = 0;
double val;
@ -85,54 +85,66 @@ uint_fast64_t NonDeterministicSparseTransitionParser::firstPass(char* buf, uint_
maxnode = 0;
while (buf[0] != '\0') {
/*
* Read source node.
* Check if current source node is larger than current maximum node id.
* Increase number of choices.
* Check if we have skipped any source node, i.e. if any node has no
* outgoing transitions. If so, increase nonzero (and
* parsed_nonzero).
* Read source state and choice.
*/
source = checked_strtol(buf, &buf);
if (source > maxnode) maxnode = source;
choices++;
// Read the name of the nondeterministic choice.
choice = checked_strtol(buf, &buf);
// Check if we encountered a state index that is bigger than all previously seen.
if (source > maxnode) {
maxnode = source;
}
// If we have skipped some states, we need to reserve the space for the self-loop insertion
// in the second pass.
if (source > lastsource + 1) {
nonzero += source - lastsource - 1;
choices += source - lastsource - 1;
parsed_nonzero += source - lastsource - 1;
} else if (source != lastsource || choice != lastchoice) {
// If we have switched the source state or the nondeterministic choice, we need to
// reserve one row more.
++choices;
}
// Read target and check if we encountered a state index that is bigger than all previously
// seen.
target = checked_strtol(buf, &buf);
if (target > maxnode) {
maxnode = target;
}
// Read value and check whether it's positive.
val = checked_strtod(buf, &buf);
if ((val < 0.0) || (val > 1.0)) {
LOG4CPLUS_ERROR(logger, "Expected a positive probability but got \"" << std::string(buf, 0, 16) << "\".");
return 0;
}
lastchoice = choice;
lastsource = source;
buf = trimWhitespaces(buf); // Skip to name of choice
buf += strcspn(buf, " \t\n\r"); // Skip name of choice.
/*
* Read all targets for this choice.
* Increase number of non-zero values.
*/
buf = trimWhitespaces(buf);
while (buf[0] == '*') {
buf++;
/*
* Read target node and transition value.
* Check if current target node is larger than current maximum node id.
* Check if the transition value is a valid probability.
*/
target = checked_strtol(buf, &buf);
if (target > maxnode) maxnode = target;
val = checked_strtod(buf, &buf);
if ((val < 0.0) || (val > 1.0)) {
LOG4CPLUS_ERROR(logger, "Expected a positive probability but got \"" << std::string(buf, 0, 16) << "\".");
return 0;
}
/*
* Increase number of non-zero values.
*/
nonzero++;
nonzero++;
/*
* Proceed to beginning of next line.
*/
buf = trimWhitespaces(buf);
// The PRISM output format lists the name of the transition in the fourth column,
// but omits the fourth column if it is an internal action. In either case, however, the third column
// is followed by a space. We need to skip over that space first (instead of trimming whitespaces),
// before we can skip to the line end, because trimming the white spaces will proceed to the next line
// in case there is no action label in the fourth column.
if (buf[0] == ' ') {
++buf;
}
/*
* Proceed to beginning of next line.
*/
buf += strcspn(buf, " \t\n\r");
buf = trimWhitespaces(buf);
}
/*
@ -154,7 +166,7 @@ uint_fast64_t NonDeterministicSparseTransitionParser::firstPass(char* buf, uint_
* @return a pointer to the created sparse matrix.
*/
NonDeterministicSparseTransitionParser::NonDeterministicSparseTransitionParser(std::string const &filename)
NondeterministicSparseTransitionParser::NondeterministicSparseTransitionParser(std::string const &filename)
: matrix(nullptr) {
/*
* Enforce locale where decimal point is '.'.
@ -214,14 +226,13 @@ NonDeterministicSparseTransitionParser::NonDeterministicSparseTransitionParser(s
/*
* Create row mapping.
*/
this->rowMapping = std::shared_ptr<std::vector<uint_fast64_t>>(new std::vector<uint_fast64_t>(maxnode+1,0));
this->rowMapping = std::shared_ptr<std::vector<uint_fast64_t>>(new std::vector<uint_fast64_t>(maxnode+2,0));
/*
* Parse file content.
*/
int_fast64_t source, target, lastsource = -1;
uint_fast64_t curRow = 0;
std::string choice;
int_fast64_t source, target, lastsource = -1, choice, lastchoice = -1;
uint_fast64_t curRow = -1;
double val;
bool fixDeadlocks = storm::settings::instance()->isSet("fix-deadlocks");
bool hadDeadlocks = false;
@ -231,11 +242,16 @@ NonDeterministicSparseTransitionParser::NonDeterministicSparseTransitionParser(s
*/
while (buf[0] != '\0') {
/*
* Read source node and choice name.
* Read source state and choice.
*/
source = checked_strtol(buf, &buf);
buf = trimWhitespaces(buf); // Skip to name of choice
choice = std::string(buf, strcspn(buf, " \t\n\r"));
choice = checked_strtol(buf, &buf);
// Increase line count if we have either finished reading the transitions of a certain state
// or we have finished reading one nondeterministic choice of a state.
if ((source != lastsource || choice != lastchoice)) {
++curRow;
}
/*
* Check if we have skipped any source node, i.e. if any node has no
@ -247,7 +263,7 @@ NonDeterministicSparseTransitionParser::NonDeterministicSparseTransitionParser(s
if (fixDeadlocks) {
this->rowMapping->at(node) = curRow;
this->matrix->addNextValue(curRow, node, 1);
curRow++;
++curRow;
LOG4CPLUS_WARN(logger, "Warning while parsing " << filename << ": node " << node << " has no outgoing transitions. A self-loop was inserted.");
} else {
LOG4CPLUS_ERROR(logger, "Error while parsing " << filename << ": node " << node << " has no outgoing transitions.");
@ -259,35 +275,27 @@ NonDeterministicSparseTransitionParser::NonDeterministicSparseTransitionParser(s
*/
this->rowMapping->at(source) = curRow;
}
// Read target and value and write it to the matrix.
target = checked_strtol(buf, &buf);
val = checked_strtod(buf, &buf);
this->matrix->addNextValue(curRow, target, val);
lastsource = source;
lastchoice = choice;
/*
* Skip name of choice.
* Proceed to beginning of next line in file and next row in matrix.
*/
if (buf[0] == ' ') {
++buf;
}
buf += strcspn(buf, " \t\n\r");
/*
* Read all targets for this choice.
*/
buf = trimWhitespaces(buf);
while (buf[0] == '*') {
buf++;
/*
* Read target node and transition value.
* Put it into the matrix.
*/
target = checked_strtol(buf, &buf);
val = checked_strtod(buf, &buf);
this->matrix->addNextValue(curRow, target, val);
/*
* Proceed to beginning of next line in file and next row in matrix.
*/
buf = trimWhitespaces(buf);
}
curRow++;
}
this->rowMapping->at(maxnode+1) = curRow + 1;
if (!fixDeadlocks && hadDeadlocks) throw storm::exceptions::WrongFormatException() << "Some of the nodes had deadlocks. You can use --fix-deadlocks to insert self-loops on the fly.";
/*

4
src/parser/NonDeterministicSparseTransitionParser.h → src/parser/NondeterministicSparseTransitionParser.h

@ -17,9 +17,9 @@ namespace parser {
* @brief Load a nondeterministic transition system from file and create a
* sparse adjacency matrix whose entries represent the weights of the edges
*/
class NonDeterministicSparseTransitionParser : public Parser {
class NondeterministicSparseTransitionParser : public Parser {
public:
NonDeterministicSparseTransitionParser(std::string const &filename);
NondeterministicSparseTransitionParser(std::string const &filename);
inline std::shared_ptr<storm::storage::SparseMatrix<double>> getMatrix() const {
return this->matrix;

79
src/reward/RewardModel.h

@ -1,79 +0,0 @@
/*
* RewardModel.h
*
* Created on: 25.10.2012
* Author: Philipp Berger
*/
#ifndef STORM_REWARD_REWARDMODEL_H_
#define STORM_REWARD_REWARDMODEL_H_
#include <stdexcept>
#include "boost/integer/integer_mask.hpp"
namespace storm {
namespace reward {
/*! This class represents a single reward model with a type DataClass value for each state contained in a Vector of type VectorImpl
*/
template<template<class, class> class VectorImpl, class DataClass>
class RewardModel {
//! Shorthand for a constant reference to the DataClass type
typedef const DataClass& crDataClass;
public:
RewardModel(const uint_fast32_t state_count, const DataClass& null_value) : state_count(state_count), null_value(null_value) {
this->reward_vector = new VectorImpl<DataClass, std::allocator<DataClass>>(this->state_count);
// init everything to zero
for (uint_fast32_t i = 0; i < this->state_count; ++i) {
this->setReward(i, this->null_value);
}
}
virtual ~RewardModel() {
delete reward_vector;
}
bool setReward(const uint_fast32_t state_index, crDataClass reward) {
if (state_index < this->state_count) {
this->reward_vector->at(state_index) = reward;
// [state_index] = reward;
return true;
}
return false;
}
crDataClass getReward(const uint_fast32_t state_index) {
if (state_index < this->state_count) {
return this->reward_vector->at(state_index);
}
return this->null_value;
}
bool resetReward(const uint_fast32_t state_index) {
if (state_index < this->state_count) {
this->reward_vector[state_index] = this->null_value;
return true;
}
return false;
}
uint_fast32_t getSize() const {
return this->state_count;
}
private:
uint_fast32_t state_count;
VectorImpl<DataClass, std::allocator<DataClass>>* reward_vector;
const DataClass& null_value;
};
} //namespace reward
} //namespace storm
#endif /* STORM_REWARD_REWARDMODEL_H_ */

155
src/solver/GraphAnalyzer.h

@ -1,155 +0,0 @@
/*
* GraphAnalyzer.h
*
* Created on: 28.11.2012
* Author: Christian Dehnert
*/
#ifndef STORM_SOLVER_GRAPHANALYZER_H_
#define STORM_SOLVER_GRAPHANALYZER_H_
#include "src/models/Dtmc.h"
#include "src/exceptions/InvalidArgumentException.h"
#include "log4cplus/logger.h"
#include "log4cplus/loggingmacros.h"
extern log4cplus::Logger logger;
namespace storm {
namespace solver {
class GraphAnalyzer {
public:
/*!
* Performs a backwards depth-first search trough the underlying graph structure
* of the given model to determine which states of the model can reach one
* of the given target states whilst always staying in the set of filter states
* before. The resulting states are written to the given bit vector.
* @param model The model whose graph structure to search.
* @param phiStates A bit vector of all states satisfying phi.
* @param psiStates A bit vector of all states satisfying psi.
* @param existsPhiUntilPsiStates A pointer to the result of the search for states that possess
* a paths satisfying phi until psi.
*/
template <class T>
static void getExistsPhiUntilPsiStates(storm::models::Dtmc<T>& model, const storm::storage::BitVector& phiStates, const storm::storage::BitVector& psiStates, storm::storage::BitVector* existsPhiUntilPsiStates) {
// Check for valid parameter.
if (existsPhiUntilPsiStates == nullptr) {
LOG4CPLUS_ERROR(logger, "Parameter 'existsPhiUntilPhiStates' must not be null.");
throw storm::exceptions::InvalidArgumentException("Parameter 'existsPhiUntilPhiStates' must not be null.");
}
// Get the backwards transition relation from the model to ease the search.
storm::models::GraphTransitions<T>& backwardTransitions = model.getBackwardTransitions();
// Add all psi states as the already satisfy the condition.
*existsPhiUntilPsiStates |= psiStates;
// Initialize the stack used for the DFS with the states
std::vector<uint_fast64_t> stack;
stack.reserve(model.getNumberOfStates());
psiStates.getList(stack);
// Perform the actual DFS.
while(!stack.empty()) {
uint_fast64_t currentState = stack.back();
stack.pop_back();
for(auto it = backwardTransitions.beginStateSuccessorsIterator(currentState); it != backwardTransitions.endStateSuccessorsIterator(currentState); ++it) {
if (phiStates.get(*it) && !existsPhiUntilPsiStates->get(*it)) {
existsPhiUntilPsiStates->set(*it, true);
stack.push_back(*it);
}
}
}
}
/*!
* Computes the set of states of the given model for which all paths lead to
* the given set of target states and only visit states from the filter set
* before. In order to do this, it uses the given set of states that
* characterizes the states that possess at least one path to a target state.
* The results are written to the given bit vector.
* @param model The model whose graph structure to search.
* @param phiStates A bit vector of all states satisfying phi.
* @param psiStates A bit vector of all states satisfying psi.
* @param existsPhiUntilPsiStates A reference to a bit vector of states that possess a path
* satisfying phi until psi.
* @param alwaysPhiUntilPsiStates A pointer to the result of the search for states that only
* have paths satisfying phi until psi.
*/
template <class T>
static void getAlwaysPhiUntilPsiStates(storm::models::Dtmc<T>& model, const storm::storage::BitVector& phiStates, const storm::storage::BitVector& psiStates, const storm::storage::BitVector& existsPhiUntilPsiStates, storm::storage::BitVector* alwaysPhiUntilPsiStates) {
// Check for valid parameter.
if (alwaysPhiUntilPsiStates == nullptr) {
LOG4CPLUS_ERROR(logger, "Parameter 'alwaysPhiUntilPhiStates' must not be null.");
throw storm::exceptions::InvalidArgumentException("Parameter 'alwaysPhiUntilPhiStates' must not be null.");
}
GraphAnalyzer::getExistsPhiUntilPsiStates(model, ~psiStates, ~existsPhiUntilPsiStates, alwaysPhiUntilPsiStates);
alwaysPhiUntilPsiStates->complement();
}
/*!
* Computes the set of states of the given model for which all paths lead to
* the given set of target states and only visit states from the filter set
* before. The results are written to the given bit vector.
* @param model The model whose graph structure to search.
* @param phiStates A bit vector of all states satisfying phi.
* @param psiStates A bit vector of all states satisfying psi.
* @param alwaysPhiUntilPsiStates A pointer to the result of the search for states that only
* have paths satisfying phi until psi.
*/
template <class T>
static void getAlwaysPhiUntilPsiStates(storm::models::Dtmc<T>& model, const storm::storage::BitVector& phiStates, const storm::storage::BitVector& psiStates, storm::storage::BitVector* alwaysPhiUntilPsiStates) {
// Check for valid parameter.
if (alwaysPhiUntilPsiStates == nullptr) {
LOG4CPLUS_ERROR(logger, "Parameter 'alwaysPhiUntilPhiStates' must not be null.");
throw storm::exceptions::InvalidArgumentException("Parameter 'alwaysPhiUntilPhiStates' must not be null.");
}
storm::storage::BitVector existsPhiUntilPsiStates(model.getNumberOfStates());
GraphAnalyzer::getExistsPhiUntilPsiStates(model, phiStates, psiStates, &existsPhiUntilPsiStates);
GraphAnalyzer::getExistsPhiUntilPsiStates(model, ~psiStates, ~existsPhiUntilPsiStates, alwaysPhiUntilPsiStates);
alwaysPhiUntilPsiStates->complement();
}
/*!
* Computes the set of states of the given model for which all paths lead to
* the given set of target states and only visit states from the filter set
* before.
* @param model The model whose graph structure to search.
* @param phiStates A bit vector of all states satisfying phi.
* @param psiStates A bit vector of all states satisfying psi.
* @param existsPhiUntilPsiStates A pointer to the result of the search for states that possess
* a path satisfying phi until psi.
* @param alwaysPhiUntilPsiStates A pointer to the result of the search for states that only
* have paths satisfying phi until psi.
*/
template <class T>
static void getPhiUntilPsiStates(storm::models::Dtmc<T>& model, const storm::storage::BitVector& phiStates, const storm::storage::BitVector& psiStates, storm::storage::BitVector* existsPhiUntilPsiStates, storm::storage::BitVector* alwaysPhiUntilPsiStates) {
// Check for valid parameters.
if (existsPhiUntilPsiStates == nullptr) {
LOG4CPLUS_ERROR(logger, "Parameter 'existsPhiUntilPhiStates' must not be null.");
throw storm::exceptions::InvalidArgumentException("Parameter 'existsPhiUntilPhiStates' must not be null.");
}
if (alwaysPhiUntilPsiStates == nullptr) {
LOG4CPLUS_ERROR(logger, "Parameter 'alwaysPhiUntilPhiStates' must not be null.");
throw storm::exceptions::InvalidArgumentException("Parameter 'alwaysPhiUntilPhiStates' must not be null.");
}
// Perform search.
GraphAnalyzer::getExistsPhiUntilPsiStates(model, phiStates, psiStates, existsPhiUntilPsiStates);
GraphAnalyzer::getAlwaysPhiUntilPsiStates(model, phiStates, psiStates, *existsPhiUntilPsiStates, alwaysPhiUntilPsiStates);
}
};
} // namespace solver
} // namespace storm
#endif /* STORM_SOLVER_GRAPHANALYZER_H_ */

39
src/storage/BitVector.h

@ -136,7 +136,7 @@ public:
* Copy Constructor. Performs a deep copy of the given bit vector.
* @param bv A reference to the bit vector to be copied.
*/
BitVector(const BitVector &bv) : bucketCount(bv.bucketCount), bitCount(bv.bitCount), endIterator(*this, bitCount, bitCount, false), truncateMask((1ll << (bitCount & mod64mask)) - 1ll) {
BitVector(BitVector const& bv) : bucketCount(bv.bucketCount), bitCount(bv.bitCount), endIterator(*this, bitCount, bitCount, false), truncateMask((1ll << (bitCount & mod64mask)) - 1ll) {
LOG4CPLUS_WARN(logger, "Invoking copy constructor.");
bucketArray = new uint64_t[bucketCount];
std::copy(bv.bucketArray, bv.bucketArray + this->bucketCount, this->bucketArray);
@ -152,6 +152,25 @@ public:
}
}
// Equality Operator
/*!
* Compares the given bit vector with the current one.
*/
bool operator==(BitVector const& bv) {
// If the lengths of the vectors do not match, they are considered unequal.
if (this->bitCount != bv.bitCount) return false;
// If the lengths match, we compare the buckets one by one.
for (uint_fast64_t index = 0; index < this->bucketCount; ++index) {
if (this->bucketArray[index] != bv.bucketArray[index]) {
return false;
}
}
// All buckets were equal, so the bit vectors are equal.
return true;
}
//! Assignment Operator
/*!
* Assigns the given bit vector to the current bit vector by a deep copy.
@ -159,7 +178,7 @@ public:
* @return A reference to this bit vector after it has been assigned the
* given bit vector by means of a deep copy.
*/
BitVector& operator=(const BitVector& bv) {
BitVector& operator=(BitVector const& bv) {
if (this->bucketArray != nullptr) {
delete[] this->bucketArray;
}
@ -239,7 +258,7 @@ public:
* @param bv A reference to the bit vector to use for the operation.
* @return A bit vector corresponding to the logical "and" of the two bit vectors.
*/
BitVector operator &(const BitVector &bv) const {
BitVector operator&(BitVector const& bv) const {
uint_fast64_t minSize = (bv.bitCount < this->bitCount) ? bv.bitCount : this->bitCount;
// Create resulting bit vector and perform the operation on the individual elements.
@ -259,7 +278,7 @@ public:
* @return A reference to the current bit vector corresponding to the logical "and"
* of the two bit vectors.
*/
BitVector operator &=(const BitVector bv) {
BitVector operator&=(BitVector const& bv) {
uint_fast64_t minSize = (bv.bucketCount < this->bucketCount) ? bv.bucketCount : this->bucketCount;
for (uint_fast64_t i = 0; i < minSize; ++i) {
@ -276,7 +295,7 @@ public:
* @param bv A reference to the bit vector to use for the operation.
* @return A bit vector corresponding to the logical "or" of the two bit vectors.
*/
BitVector operator |(const BitVector &bv) const {
BitVector operator|(BitVector const& bv) const {
uint_fast64_t minSize = (bv.bitCount < this->bitCount) ? bv.bitCount : this->bitCount;
// Create resulting bit vector and perform the operation on the individual elements.
@ -297,7 +316,7 @@ public:
* @return A reference to the current bit vector corresponding to the logical "or"
* of the two bit vectors.
*/
BitVector& operator |=(const BitVector bv) {
BitVector& operator|=(BitVector const& bv) {
uint_fast64_t minSize = (bv.bucketCount < this->bucketCount) ? bv.bucketCount : this->bucketCount;
for (uint_fast64_t i = 0; i < minSize; ++i) {
@ -315,7 +334,7 @@ public:
* @param bv A reference to the bit vector to use for the operation.
* @return A bit vector corresponding to the logical "xor" of the two bit vectors.
*/
BitVector operator ^(const BitVector &bv) const {
BitVector operator^(BitVector const& bv) const {
uint_fast64_t minSize = (bv.bitCount < this->bitCount) ? bv.bitCount : this->bitCount;
// Create resulting bit vector and perform the operation on the individual elements.
@ -332,7 +351,7 @@ public:
* Performs a logical "not" on the bit vector.
* @return A bit vector corresponding to the logical "not" of the bit vector.
*/
BitVector operator ~() const {
BitVector operator~() const {
// Create resulting bit vector and perform the operation on the individual elements.
BitVector result(this->bitCount);
for (uint_fast64_t i = 0; i < this->bucketCount; ++i) {
@ -360,7 +379,7 @@ public:
* @param bv A reference to the bit vector to use for the operation.
* @return A bit vector corresponding to the logical "implies" of the two bit vectors.
*/
BitVector implies(const BitVector& bv) const {
BitVector implies(BitVector const& bv) const {
uint_fast64_t minSize = (bv.bitCount < this->bitCount) ? bv.bitCount : this->bitCount;
// Create resulting bit vector and perform the operation on the individual elements.
@ -377,7 +396,7 @@ public:
* Adds all indices of bits set to one to the provided list.
* @param list The list to which to append the indices.
*/
void getList(std::vector<uint_fast64_t>& list) const {
void addSetIndicesToList(std::vector<uint_fast64_t>& list) const {
for (auto index : *this) {
list.push_back(index);
}

220
src/storage/SparseMatrix.h

@ -476,7 +476,7 @@ public:
* Returns a pointer to the value storage of the matrix.
* @return A pointer to the value storage of the matrix.
*/
std::vector<T> const & getStoragePointer() const {
std::vector<T> const& getStorage() const {
return valueStorage;
}
@ -486,7 +486,7 @@ public:
* @return A pointer to the array that stores the start indices of non-zero
* entries in the value storage for each row.
*/
std::vector<uint_fast64_t> const & getRowIndicationsPointer() const {
std::vector<uint_fast64_t> const& getRowIndications() const {
return rowIndications;
}
@ -496,7 +496,7 @@ public:
* @return A pointer to an array that stores the column of each non-zero
* element.
*/
std::vector<uint_fast64_t> const & getColumnIndicationsPointer() const {
std::vector<uint_fast64_t> const& getColumnIndications() const {
return columnIndications;
}
@ -641,12 +641,29 @@ public:
bool makeRowsAbsorbing(const storm::storage::BitVector rows) {
bool result = true;
for (auto row : rows) {
result &= makeRowAbsorbing(row);
result &= makeRowAbsorbing(row, row);
}
return result;
}
/*!
* This function makes the groups of rows given by the bit vector absorbing.
* @param rows A bit vector indicating which row groups to make absorbing.
* @return True iff the operation was successful.
*/
bool makeRowsAbsorbing(const storm::storage::BitVector rows, std::vector<uint_fast64_t> const& nondeterministicChoices) {
bool result = true;
for (auto index : rows) {
for (uint_fast64_t row = nondeterministicChoices[index]; row < nondeterministicChoices[index + 1]; ++row) {
result &= makeRowAbsorbing(row, index);
}
}
return result;
}
/*!
* This function makes the given row absorbing. This means that all
* entries in will be set to 0 and the value 1 will be written
@ -654,7 +671,7 @@ public:
* @param row The row to be made absorbing.
* @returns True iff the operation was successful.
*/
bool makeRowAbsorbing(const uint_fast64_t row) {
bool makeRowAbsorbing(const uint_fast64_t row, const uint_fast64_t column) {
// Check whether the accessed state exists.
if (row > rowCount) {
LOG4CPLUS_ERROR(logger, "Trying to make an illegal row " << row << " absorbing.");
@ -668,29 +685,16 @@ public:
uint_fast64_t rowEnd = rowIndications[row + 1];
if (rowStart >= rowEnd) {
this->print();
LOG4CPLUS_ERROR(logger, "Cannot make row absorbing, because there is no entry in this row.");
throw storm::exceptions::InvalidStateException("Cannot make row absorbing, because there is no entry in this row.");
LOG4CPLUS_ERROR(logger, "Cannot make row " << row << " absorbing, because there is no entry in this row.");
throw storm::exceptions::InvalidStateException() << "Cannot make row " << row << " absorbing, because there is no entry in this row.";
}
uint_fast64_t pseudoDiagonal = row % colCount;
bool foundDiagonal = false;
while (rowStart < rowEnd) {
if (!foundDiagonal && columnIndications[rowStart] >= pseudoDiagonal) {
foundDiagonal = true;
// insert/replace the diagonal entry
columnIndications[rowStart] = pseudoDiagonal;
valueStorage[rowStart] = storm::utility::constGetOne<T>();
} else {
valueStorage[rowStart] = storm::utility::constGetZero<T>();
}
++rowStart;
}
valueStorage[rowStart] = storm::utility::constGetOne<T>();
columnIndications[rowStart] = column;
if (!foundDiagonal) {
--rowStart;
columnIndications[rowStart] = pseudoDiagonal;
valueStorage[rowStart] = storm::utility::constGetOne<T>();
for (uint_fast64_t index = rowStart + 1; index < rowEnd; ++index) {
valueStorage[index] = storm::utility::constGetZero<T>();
columnIndications[index] = 0;
}
return true;
@ -722,13 +726,30 @@ public:
* @param resultVector A pointer to the resulting vector that has at least
* as many elements as there are bits set to true in the constraint.
*/
void getConstrainedRowCountVector(const storm::storage::BitVector& rowConstraint, const storm::storage::BitVector& columnConstraint, std::vector<T>* resultVector) const {
void getConstrainedRowSumVector(const storm::storage::BitVector& rowConstraint, const storm::storage::BitVector& columnConstraint, std::vector<T>* resultVector) const {
uint_fast64_t currentRowCount = 0;
for (auto row : rowConstraint) {
(*resultVector)[currentRowCount++] = getConstrainedRowSum(row, columnConstraint);
}
}
/*!
* Computes a vector in which each element is the sum of those elements in the
* corresponding row whose column bits are set to one in the given constraint.
* @param rowConstraint A bit vector that indicates for which rows to perform summation.
* @param columnConstraint A bit vector that indicates which columns to add.
* @param resultVector A pointer to the resulting vector that has at least
* as many elements as there are bits set to true in the constraint.
*/
void getConstrainedRowSumVector(const storm::storage::BitVector& rowConstraint, std::vector<uint_fast64_t> const& nondeterministicChoiceIndices, const storm::storage::BitVector& columnConstraint, std::vector<T>* resultVector) const {
uint_fast64_t currentRowCount = 0;
for (auto index : rowConstraint) {
for (uint_fast64_t row = nondeterministicChoiceIndices[index]; row < nondeterministicChoiceIndices[index + 1]; ++row) {
(*resultVector)[currentRowCount++] = getConstrainedRowSum(row, columnConstraint);
}
}
}
/*!
* Creates a sub-matrix of the current matrix by dropping all rows and
* columns whose bits are not set to one in the given bit vector.
@ -761,7 +782,7 @@ public:
// Create a temporary array that stores for each index whose bit is set
// to true the number of bits that were set before that particular index.
uint_fast64_t* bitsSetBeforeIndex = new uint_fast64_t[rowCount];
uint_fast64_t* bitsSetBeforeIndex = new uint_fast64_t[colCount];
uint_fast64_t lastIndex = 0;
uint_fast64_t currentNumberOfSetBits = 0;
for (auto index : constraint) {
@ -792,6 +813,70 @@ public:
return result;
}
SparseMatrix* getSubmatrix(storm::storage::BitVector& constraint, std::vector<uint_fast64_t> const& rowIndices) const {
LOG4CPLUS_DEBUG(logger, "Creating a sub-matrix (of unknown size).");
// Check for valid constraint.
if (constraint.getNumberOfSetBits() == 0) {
LOG4CPLUS_ERROR(logger, "Trying to create a sub-matrix of size 0.");
throw storm::exceptions::InvalidArgumentException("Trying to create a sub-matrix of size 0.");
}
// First, we need to determine the number of non-zero entries and the number of rows of the
// sub-matrix.
uint_fast64_t subNonZeroEntries = 0;
uint_fast64_t subRowCount = 0;
for (auto index : constraint) {
subRowCount += rowIndices[index + 1] - rowIndices[index];
for (uint_fast64_t i = rowIndices[index]; i < rowIndices[index + 1]; ++i) {
for (uint_fast64_t j = rowIndications[i]; j < rowIndications[i + 1]; ++j) {
if (constraint.get(columnIndications[j])) {
++subNonZeroEntries;
}
}
}
}
LOG4CPLUS_DEBUG(logger, "Determined size of submatrix to be " << subRowCount << "x" << constraint.getNumberOfSetBits() << ".");
// Create and initialize resulting matrix.
SparseMatrix* result = new SparseMatrix(subRowCount, constraint.getNumberOfSetBits());
result->initialize(subNonZeroEntries);
// Create a temporary array that stores for each index whose bit is set
// to true the number of bits that were set before that particular index.
uint_fast64_t* bitsSetBeforeIndex = new uint_fast64_t[colCount];
uint_fast64_t lastIndex = 0;
uint_fast64_t currentNumberOfSetBits = 0;
for (auto index : constraint) {
while (lastIndex <= index) {
bitsSetBeforeIndex[lastIndex++] = currentNumberOfSetBits;
}
++currentNumberOfSetBits;
}
// Copy over selected entries.
uint_fast64_t rowCount = 0;
for (auto index : constraint) {
for (uint_fast64_t i = rowIndices[index]; i < rowIndices[index + 1]; ++i) {
for (uint_fast64_t j = rowIndications[i]; j < rowIndications[i + 1]; ++j) {
if (constraint.get(columnIndications[j])) {
result->addNextValue(rowCount, bitsSetBeforeIndex[columnIndications[j]], valueStorage[j]);
}
}
++rowCount;
}
}
// Dispose of the temporary array.
delete[] bitsSetBeforeIndex;
// Finalize sub-matrix and return result.
result->finalize();
LOG4CPLUS_DEBUG(logger, "Done creating sub-matrix.");
return result;
}
void convertToEquationSystem() {
invertDiagonal();
negateAllNonDiagonalElements();
@ -1005,11 +1090,82 @@ public:
return true;
}
void print() const {
std::cout << "entries in (" << rowCount << "x" << colCount << " matrix):" << std::endl;
std::cout << rowIndications << std::endl;
std::cout << columnIndications << std::endl;
std::cout << valueStorage << std::endl;
/*!
* Retrieves a compressed string representation of the matrix.
* @return a compressed string representation of the matrix.
*/
std::string toStringCompressed() const {
std::stringstream result;
result << rowIndications << std::endl;
result << columnIndications << std::endl;
result << valueStorage << std::endl;
return result.str();
}
/*!
* Retrieves a (non-compressed) string representation of the matrix.
* Note: the matrix is presented densely. That is, all zeros are filled in and are part of the string
* representation.
* @param nondeterministicChoiceIndices A vector indicating which rows belong together. If given, rows belonging
* to separate groups will be separated by a dashed line.
* @return a (non-compressed) string representation of the matrix.
*/
std::string toString(std::shared_ptr<std::vector<std::uint_fast64_t>> nondeterministicChoiceIndices) const {
std::stringstream result;
uint_fast64_t currentNondeterministicChoiceIndex = 0;
// Print column numbers in header.
result << "\t\t";
for (uint_fast64_t i = 0; i < colCount; ++i) {
result << i << "\t";
}
result << std::endl;
// Iterate over all rows.
for (uint_fast64_t i = 0; i < rowCount; ++i) {
uint_fast64_t nextIndex = rowIndications[i];
// If we need to group of rows, print a dashed line in case we have moved to the next group of rows.
if (nondeterministicChoiceIndices != nullptr) {
if (i == (*nondeterministicChoiceIndices)[currentNondeterministicChoiceIndex]) {
if (i != 0) {
result << "\t(\t";
for (uint_fast64_t j = 0; j < colCount - 2; ++j) {
result << "----";
if (j == 1) {
result << "\t" << currentNondeterministicChoiceIndex << "\t";
}
}
result << "\t)" << std::endl;
}
++currentNondeterministicChoiceIndex;
}
}
// Print the actual row.
result << i << "\t(\t";
uint_fast64_t currentRealIndex = 0;
while (currentRealIndex < colCount) {
if (currentRealIndex == columnIndications[nextIndex] && nextIndex < rowIndications[i + 1]) {
result << valueStorage[nextIndex] << "\t";
++nextIndex;
} else {
result << "0\t";
}
++currentRealIndex;
}
result << "\t)\t" << i << std::endl;
}
// Print column numbers in footer.
result << "\t\t";
for (uint_fast64_t i = 0; i < colCount; ++i) {
result << i << "\t";
}
result << std::endl;
// Return final result.
return result.str();
}
private:

71
src/storm.cpp

@ -24,9 +24,9 @@
#include "src/models/AtomicPropositionsLabeling.h"
#include "src/modelchecker/EigenDtmcPrctlModelChecker.h"
#include "src/modelchecker/GmmxxDtmcPrctlModelChecker.h"
#include "src/modelchecker/GmmxxMdpPrctlModelChecker.h"
#include "src/parser/AutoParser.h"
#include "src/parser/PrctlParser.h"
#include "src/solver/GraphAnalyzer.h"
#include "src/utility/Settings.h"
#include "src/formula/Formulas.h"
@ -126,6 +126,10 @@ bool parseOptions(const int argc, const char* argv[]) {
return true;
}
void setUp() {
std::cout.precision(10);
}
/*!
* Function to perform some cleanup.
*/
@ -206,12 +210,59 @@ void testCheckingSynchronousLeader(storm::models::Dtmc<double>& dtmc, uint_fast6
delete mc;
}
void testCheckingDice(storm::models::Mdp<double>& mdp) {
storm::formula::Ap<double>* threeFormula = new storm::formula::Ap<double>("three");
storm::formula::Eventually<double>* eventuallyFormula = new storm::formula::Eventually<double>(threeFormula);
storm::formula::ProbabilisticNoBoundOperator<double>* probFormula = new storm::formula::ProbabilisticNoBoundOperator<double>(eventuallyFormula, false);
storm::modelChecker::GmmxxMdpPrctlModelChecker<double>* mc = new storm::modelChecker::GmmxxMdpPrctlModelChecker<double>(mdp);
mc->check(*probFormula);
delete probFormula;
delete mc;
}
void testCheckingAsynchLeader(storm::models::Mdp<double>& mdp) {
storm::formula::Ap<double>* electedFormula = new storm::formula::Ap<double>("elected");
storm::formula::Eventually<double>* eventuallyFormula = new storm::formula::Eventually<double>(electedFormula);
storm::formula::ProbabilisticNoBoundOperator<double>* probMinFormula = new storm::formula::ProbabilisticNoBoundOperator<double>(eventuallyFormula, true);
storm::modelChecker::GmmxxMdpPrctlModelChecker<double>* mc = new storm::modelChecker::GmmxxMdpPrctlModelChecker<double>(mdp);
mc->check(*probMinFormula);
delete probMinFormula;
electedFormula = new storm::formula::Ap<double>("elected");
eventuallyFormula = new storm::formula::Eventually<double>(electedFormula);
storm::formula::ProbabilisticNoBoundOperator<double>* probMaxFormula = new storm::formula::ProbabilisticNoBoundOperator<double>(eventuallyFormula, false);
mc->check(*probMaxFormula);
delete probMaxFormula;
electedFormula = new storm::formula::Ap<double>("elected");
storm::formula::BoundedEventually<double>* boundedEventuallyFormula = new storm::formula::BoundedEventually<double>(electedFormula, 50);
probMinFormula = new storm::formula::ProbabilisticNoBoundOperator<double>(boundedEventuallyFormula, true);
mc->check(*probMinFormula);
delete probMinFormula;
electedFormula = new storm::formula::Ap<double>("elected");
boundedEventuallyFormula = new storm::formula::BoundedEventually<double>(electedFormula, 50);
probMaxFormula = new storm::formula::ProbabilisticNoBoundOperator<double>(boundedEventuallyFormula, false);
mc->check(*probMaxFormula);
delete probMaxFormula;
delete mc;
}
/*!
* Simple testing procedure.
*/
void testChecking() {
storm::settings::Settings* s = storm::settings::instance();
storm::parser::AutoParser parser(s->getString("trafile"), s->getString("labfile"), s->getString("staterew"), s->getString("transrew"));
storm::parser::AutoParser<double> parser(s->getString("trafile"), s->getString("labfile"), s->getString("staterew"), s->getString("transrew"));
if (parser.getType() == storm::models::DTMC) {
std::shared_ptr<storm::models::Dtmc<double>> dtmc = parser.getModel<storm::models::Dtmc<double>>();
@ -221,7 +272,15 @@ void testChecking() {
// testCheckingCrowds(*dtmc);
// testCheckingSynchronousLeader(*dtmc, 4);
}
else std::cout << "Input is not DTMC" << std::endl;
else if (parser.getType() == storm::models::MDP) {
std::shared_ptr<storm::models::Mdp<double>> mdp = parser.getModel<storm::models::Mdp<double>>();
mdp->printModelInformationToStream(std::cout);
// testCheckingDice(*mdp);
// testCheckingAsynchLeader(*mdp);
} else {
std::cout << "Input is neither a DTMC nor an MDP." << std::endl;
}
}
/*!
@ -232,10 +291,16 @@ int main(const int argc, const char* argv[]) {
if (!parseOptions(argc, argv)) {
return 0;
}
setUp();
LOG4CPLUS_INFO(logger, "StoRM was invoked.");
printHeader(argc, argv);
testChecking();
cleanUp();
LOG4CPLUS_INFO(logger, "StoRM quit.");
return 0;
}

8
src/utility/ConstTemplates.h

@ -8,6 +8,14 @@
#ifndef STORM_UTILITY_CONSTTEMPLATES_H_
#define STORM_UTILITY_CONSTTEMPLATES_H_
#ifdef max
# undef max
#endif
#ifdef min
# undef min
#endif
#include <limits>
namespace storm {

421
src/utility/GraphAnalyzer.h

@ -0,0 +1,421 @@
/*
* GraphAnalyzer.h
*
* Created on: 28.11.2012
* Author: Christian Dehnert
*/
#ifndef STORM_UTILITY_GRAPHANALYZER_H_
#define STORM_UTILITY_GRAPHANALYZER_H_
#include "src/models/AbstractDeterministicModel.h"
#include "src/models/AbstractNondeterministicModel.h"
#include "src/exceptions/InvalidArgumentException.h"
#include "log4cplus/logger.h"
#include "log4cplus/loggingmacros.h"
extern log4cplus::Logger logger;
namespace storm {
namespace utility {
class GraphAnalyzer {
public:
/*!
* Computes the sets of states that have probability 0 or 1, respectively, of satisfying phi until psi in a
* deterministic model.
* @param model The model whose graph structure to search.
* @param phiStates The set of all states satisfying phi.
* @param psiStates The set of all states satisfying psi.
* @param statesWithProbability0 A pointer to a bit vector that is initially empty and will contain all states with
* probability 0 after the invocation of the function.
* @param statesWithProbability1 A pointer to a bit vector that is initially empty and will contain all states with
* probability 1 after the invocation of the function.
*/
template <class T>
static void performProb01(storm::models::AbstractDeterministicModel<T>& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::BitVector* statesWithProbability0, storm::storage::BitVector* statesWithProbability1) {
// Check for valid parameters.
if (statesWithProbability0 == nullptr) {
LOG4CPLUS_ERROR(logger, "Parameter 'statesWithProbability0' must not be null.");
throw storm::exceptions::InvalidArgumentException("Parameter 'statesWithProbability0' must not be null.");
}
if (statesWithProbability1 == nullptr) {
LOG4CPLUS_ERROR(logger, "Parameter 'statesWithProbability1' must not be null.");
throw storm::exceptions::InvalidArgumentException("Parameter 'statesWithProbability1' must not be null.");
}
// Perform the actual search.
GraphAnalyzer::performProbGreater0(model, phiStates, psiStates, statesWithProbability0);
GraphAnalyzer::performProb1(model, phiStates, psiStates, *statesWithProbability0, statesWithProbability1);
statesWithProbability0->complement();
}
/*!
* Performs a backwards depth-first search trough the underlying graph structure
* of the given model to determine which states of the model have a positive probability
* of satisfying phi until psi. The resulting states are written to the given bit vector.
* @param model The model whose graph structure to search.
* @param phiStates A bit vector of all states satisfying phi.
* @param psiStates A bit vector of all states satisfying psi.
* @param statesWithProbabilityGreater0 A pointer to the result of the search for states that possess
* a positive probability of satisfying phi until psi.
*/
template <class T>
static void performProbGreater0(storm::models::AbstractDeterministicModel<T>& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::BitVector* statesWithProbabilityGreater0) {
// Check for valid parameter.
if (statesWithProbabilityGreater0 == nullptr) {
LOG4CPLUS_ERROR(logger, "Parameter 'statesWithProbabilityGreater0' must not be null.");
throw storm::exceptions::InvalidArgumentException("Parameter 'statesWithProbabilityGreater0' must not be null.");
}
// Get the backwards transition relation from the model to ease the search.
storm::models::GraphTransitions<T> backwardTransitions(model.getTransitionMatrix(), false);
// Add all psi states as the already satisfy the condition.
*statesWithProbabilityGreater0 |= psiStates;
// Initialize the stack used for the DFS with the states
std::vector<uint_fast64_t> stack;
stack.reserve(model.getNumberOfStates());
psiStates.addSetIndicesToList(stack);
// Perform the actual DFS.
while(!stack.empty()) {
uint_fast64_t currentState = stack.back();
stack.pop_back();
for(auto it = backwardTransitions.beginStateSuccessorsIterator(currentState); it != backwardTransitions.endStateSuccessorsIterator(currentState); ++it) {
if (phiStates.get(*it) && !statesWithProbabilityGreater0->get(*it)) {
statesWithProbabilityGreater0->set(*it, true);
stack.push_back(*it);
}
}
}
}
/*!
* Computes the set of states of the given model for which all paths lead to
* the given set of target states and only visit states from the filter set
* before. In order to do this, it uses the given set of states that
* characterizes the states that possess at least one path to a target state.
* The results are written to the given bit vector.
* @param model The model whose graph structure to search.
* @param phiStates A bit vector of all states satisfying phi.
* @param psiStates A bit vector of all states satisfying psi.
* @param statesWithProbabilityGreater0 A reference to a bit vector of states that possess a positive
* probability mass of satisfying phi until psi.
* @param alwaysPhiUntilPsiStates A pointer to the result of the search for states that only
* have paths satisfying phi until psi.
*/
template <class T>
static void performProb1(storm::models::AbstractDeterministicModel<T>& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::BitVector const& statesWithProbabilityGreater0, storm::storage::BitVector* statesWithProbability1) {
// Check for valid parameter.
if (statesWithProbability1 == nullptr) {
LOG4CPLUS_ERROR(logger, "Parameter 'statesWithProbability1' must not be null.");
throw storm::exceptions::InvalidArgumentException("Parameter 'statesWithProbability1' must not be null.");
}
GraphAnalyzer::performProbGreater0(model, ~psiStates, ~statesWithProbabilityGreater0, statesWithProbability1);
statesWithProbability1->complement();
}
/*!
* Computes the set of states of the given model for which all paths lead to
* the given set of target states and only visit states from the filter set
* before. In order to do this, it uses the given set of states that
* characterizes the states that possess at least one path to a target state.
* The results are written to the given bit vector.
* @param model The model whose graph structure to search.
* @param phiStates A bit vector of all states satisfying phi.
* @param psiStates A bit vector of all states satisfying psi.
* @param alwaysPhiUntilPsiStates A pointer to the result of the search for states that only
* have paths satisfying phi until psi.
*/
template <class T>
static void performProb1(storm::models::AbstractDeterministicModel<T>& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::BitVector* statesWithProbability1) {
// Check for valid parameter.
if (statesWithProbability1 == nullptr) {
LOG4CPLUS_ERROR(logger, "Parameter 'statesWithProbability1' must not be null.");
throw storm::exceptions::InvalidArgumentException("Parameter 'statesWithProbability1' must not be null.");
}
storm::storage::BitVector* statesWithProbabilityGreater0 = new storm::storage::BitVector(model.getNumberOfStates());
GraphAnalyzer::performProbGreater0(model, phiStates, psiStates, statesWithProbabilityGreater0);
GraphAnalyzer::performProbGreater0(model, ~psiStates, ~(*statesWithProbabilityGreater0), statesWithProbability1);
delete statesWithProbabilityGreater0;
statesWithProbability1->complement();
}
template <class T>
static void performProb01Max(storm::models::AbstractNondeterministicModel<T>& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::BitVector* statesWithProbability0, storm::storage::BitVector* statesWithProbability1) {
// Check for valid parameters.
if (statesWithProbability0 == nullptr) {
LOG4CPLUS_ERROR(logger, "Parameter 'statesWithProbability0' must not be null.");
throw storm::exceptions::InvalidArgumentException("Parameter 'statesWithProbability0' must not be null.");
}
if (statesWithProbability1 == nullptr) {
LOG4CPLUS_ERROR(logger, "Parameter 'statesWithProbability1' must not be null.");
throw storm::exceptions::InvalidArgumentException("Parameter 'statesWithProbability1' must not be null.");
}
// Perform the actual search.
GraphAnalyzer::performProb0A(model, phiStates, psiStates, statesWithProbability0);
GraphAnalyzer::performProb1E(model, phiStates, psiStates, statesWithProbability1);
}
template <class T>
static void performProb0A(storm::models::AbstractNondeterministicModel<T>& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::BitVector* statesWithProbability0) {
// Check for valid parameter.
if (statesWithProbability0 == nullptr) {
LOG4CPLUS_ERROR(logger, "Parameter 'statesWithProbability0' must not be null.");
throw storm::exceptions::InvalidArgumentException("Parameter 'statesWithProbability0' must not be null.");
}
// Get the backwards transition relation from the model to ease the search.
storm::models::GraphTransitions<T> backwardTransitions(model.getTransitionMatrix(), model.getNondeterministicChoiceIndices(), false);
// Add all psi states as the already satisfy the condition.
*statesWithProbability0 |= psiStates;
// Initialize the stack used for the DFS with the states
std::vector<uint_fast64_t> stack;
stack.reserve(model.getNumberOfStates());
psiStates.addSetIndicesToList(stack);
// Perform the actual DFS.
while(!stack.empty()) {
uint_fast64_t currentState = stack.back();
stack.pop_back();
for(auto it = backwardTransitions.beginStateSuccessorsIterator(currentState); it != backwardTransitions.endStateSuccessorsIterator(currentState); ++it) {
if (phiStates.get(*it) && !statesWithProbability0->get(*it)) {
statesWithProbability0->set(*it, true);
stack.push_back(*it);
}
}
}
statesWithProbability0->complement();
}
template <class T>
static void performProb1E(storm::models::AbstractNondeterministicModel<T>& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::BitVector* statesWithProbability1) {
// Check for valid parameters.
if (statesWithProbability1 == nullptr) {
LOG4CPLUS_ERROR(logger, "Parameter 'statesWithProbability1' must not be null.");
throw storm::exceptions::InvalidArgumentException("Parameter 'statesWithProbability1' must not be null.");
}
// Get some temporaries for convenience.
std::shared_ptr<storm::storage::SparseMatrix<T>> transitionMatrix = model.getTransitionMatrix();
std::shared_ptr<std::vector<uint_fast64_t>> nondeterministicChoiceIndices = model.getNondeterministicChoiceIndices();
// Get the backwards transition relation from the model to ease the search.
storm::models::GraphTransitions<T> backwardTransitions(model.getTransitionMatrix(), model.getNondeterministicChoiceIndices(), false);
storm::storage::BitVector* currentStates = new storm::storage::BitVector(model.getNumberOfStates(), true);
std::vector<uint_fast64_t> stack;
stack.reserve(model.getNumberOfStates());
bool done = false;
while (!done) {
stack.clear();
storm::storage::BitVector* nextStates = new storm::storage::BitVector(psiStates);
psiStates.addSetIndicesToList(stack);
while (!stack.empty()) {
uint_fast64_t currentState = stack.back();
stack.pop_back();
for(auto it = backwardTransitions.beginStateSuccessorsIterator(currentState); it != backwardTransitions.endStateSuccessorsIterator(currentState); ++it) {
if (phiStates.get(*it) && !nextStates->get(*it)) {
// Check whether the predecessor has only successors in the current state set for one of the
// nondeterminstic choices.
for (uint_fast64_t row = (*nondeterministicChoiceIndices)[*it]; row < (*nondeterministicChoiceIndices)[*it + 1]; ++row) {
bool allSuccessorsInCurrentStates = true;
for (auto colIt = transitionMatrix->beginConstColumnIterator(row); colIt != transitionMatrix->endConstColumnIterator(row); ++colIt) {
if (!currentStates->get(*colIt)) {
allSuccessorsInCurrentStates = false;
break;
}
}
// If all successors for a given nondeterministic choice are in the current state set, we
// add it to the set of states for the next iteration and perform a backward search from
// that state.
if (allSuccessorsInCurrentStates) {
nextStates->set(*it, true);
stack.push_back(*it);
break;
}
}
}
}
}
// Check whether we need to perform an additional iteration.
if (*currentStates == *nextStates) {
done = true;
} else {
*currentStates = *nextStates;
}
}
*statesWithProbability1 = *currentStates;
delete currentStates;
}
template <class T>
static void performProb01Min(storm::models::AbstractNondeterministicModel<T>& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::BitVector* statesWithProbability0, storm::storage::BitVector* statesWithProbability1) {
// Check for valid parameters.
if (statesWithProbability0 == nullptr) {
LOG4CPLUS_ERROR(logger, "Parameter 'statesWithProbability0' must not be null.");
throw storm::exceptions::InvalidArgumentException("Parameter 'statesWithProbability0' must not be null.");
}
if (statesWithProbability1 == nullptr) {
LOG4CPLUS_ERROR(logger, "Parameter 'statesWithProbability1' must not be null.");
throw storm::exceptions::InvalidArgumentException("Parameter 'statesWithProbability1' must not be null.");
}
// Perform the actual search.
GraphAnalyzer::performProb0E(model, phiStates, psiStates, statesWithProbability0);
GraphAnalyzer::performProb1A(model, phiStates, psiStates, statesWithProbability1);
}
template <class T>
static void performProb0E(storm::models::AbstractNondeterministicModel<T>& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::BitVector* statesWithProbability0) {
// Check for valid parameter.
if (statesWithProbability0 == nullptr) {
LOG4CPLUS_ERROR(logger, "Parameter 'statesWithProbability0' must not be null.");
throw storm::exceptions::InvalidArgumentException("Parameter 'statesWithProbability0' must not be null.");
}
// Get some temporaries for convenience.
std::shared_ptr<storm::storage::SparseMatrix<T>> transitionMatrix = model.getTransitionMatrix();
std::shared_ptr<std::vector<uint_fast64_t>> nondeterministicChoiceIndices = model.getNondeterministicChoiceIndices();
// Get the backwards transition relation from the model to ease the search.
storm::models::GraphTransitions<T> backwardTransitions(transitionMatrix, nondeterministicChoiceIndices, false);
// Add all psi states as the already satisfy the condition.
*statesWithProbability0 |= psiStates;
// Initialize the stack used for the DFS with the states
std::vector<uint_fast64_t> stack;
stack.reserve(model.getNumberOfStates());
psiStates.addSetIndicesToList(stack);
// Perform the actual DFS.
while(!stack.empty()) {
uint_fast64_t currentState = stack.back();
stack.pop_back();
for(auto it = backwardTransitions.beginStateSuccessorsIterator(currentState); it != backwardTransitions.endStateSuccessorsIterator(currentState); ++it) {
if (phiStates.get(*it) && !statesWithProbability0->get(*it)) {
// Check whether the predecessor has at least one successor in the current state
// set for every nondeterministic choice.
bool addToStatesWithProbability0 = true;
for (auto rowIt = nondeterministicChoiceIndices->begin() + *it; rowIt != nondeterministicChoiceIndices->begin() + *it + 1; ++rowIt) {
bool hasAtLeastOneSuccessorWithProbabilityGreater0 = false;
for (auto colIt = transitionMatrix->beginConstColumnIterator(*rowIt); colIt != transitionMatrix->endConstColumnIterator(*rowIt); ++colIt) {
if (statesWithProbability0->get(*colIt)) {
hasAtLeastOneSuccessorWithProbabilityGreater0 = true;
break;
}
}
if (!hasAtLeastOneSuccessorWithProbabilityGreater0) {
addToStatesWithProbability0 = false;
break;
}
}
// If we need to add the state, then actually add it and perform further search
// from the state.
if (addToStatesWithProbability0) {
statesWithProbability0->set(*it, true);
stack.push_back(*it);
}
}
}
}
statesWithProbability0->complement();
}
template <class T>
static void performProb1A(storm::models::AbstractNondeterministicModel<T>& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::BitVector* statesWithProbability1) {
// Check for valid parameters.
if (statesWithProbability1 == nullptr) {
LOG4CPLUS_ERROR(logger, "Parameter 'statesWithProbability1' must not be null.");
throw storm::exceptions::InvalidArgumentException("Parameter 'statesWithProbability1' must not be null.");
}
// Get some temporaries for convenience.
std::shared_ptr<storm::storage::SparseMatrix<T>> transitionMatrix = model.getTransitionMatrix();
std::shared_ptr<std::vector<uint_fast64_t>> nondeterministicChoiceIndices = model.getNondeterministicChoiceIndices();
// Get the backwards transition relation from the model to ease the search.
storm::models::GraphTransitions<T> backwardTransitions(model.getTransitionMatrix(), model.getNondeterministicChoiceIndices(), false);
storm::storage::BitVector* currentStates = new storm::storage::BitVector(model.getNumberOfStates(), true);
std::vector<uint_fast64_t> stack;
stack.reserve(model.getNumberOfStates());
bool done = false;
while (!done) {
stack.clear();
storm::storage::BitVector* nextStates = new storm::storage::BitVector(psiStates);
psiStates.addSetIndicesToList(stack);
while (!stack.empty()) {
uint_fast64_t currentState = stack.back();
stack.pop_back();
for(auto it = backwardTransitions.beginStateSuccessorsIterator(currentState); it != backwardTransitions.endStateSuccessorsIterator(currentState); ++it) {
if (phiStates.get(*it) && !nextStates->get(*it)) {
// Check whether the predecessor has only successors in the current state set for all of the
// nondeterminstic choices.
bool allSuccessorsInCurrentStatesForAllChoices = true;
for (uint_fast64_t row = (*nondeterministicChoiceIndices)[*it]; row < (*nondeterministicChoiceIndices)[*it + 1]; ++row) {
for (auto colIt = transitionMatrix->beginConstColumnIterator(row); colIt != transitionMatrix->endConstColumnIterator(row); ++colIt) {
if (!currentStates->get(*colIt)) {
allSuccessorsInCurrentStatesForAllChoices = false;
goto afterCheckLoop;
}
}
}
afterCheckLoop:
// If all successors for all nondeterministic choices are in the current state set, we
// add it to the set of states for the next iteration and perform a backward search from
// that state.
if (allSuccessorsInCurrentStatesForAllChoices) {
nextStates->set(*it, true);
stack.push_back(*it);
}
}
}
}
// Check whether we need to perform an additional iteration.
if (*currentStates == *nextStates) {
done = true;
} else {
*currentStates = *nextStates;
}
}
*statesWithProbability1 = *currentStates;
delete currentStates;
}
};
} // namespace utility
} // namespace storm
#endif /* STORM_UTILITY_GRAPHANALYZER_H_ */

2
src/utility/IoUtility.cpp

@ -17,7 +17,7 @@ namespace storm {
namespace utility {
void dtmcToDot(storm::models::Dtmc<double> const &dtmc, std::string filename) {
std::shared_ptr<storm::storage::SparseMatrix<double>> matrix(dtmc.getTransitionProbabilityMatrix());
std::shared_ptr<storm::storage::SparseMatrix<double>> matrix(dtmc.getTransitionMatrix());
std::ofstream file;
file.open(filename);

63
src/utility/Vector.h

@ -12,6 +12,11 @@
#include "ConstTemplates.h"
#include <iostream>
#include "log4cplus/logger.h"
#include "log4cplus/loggingmacros.h"
extern log4cplus::Logger logger;
namespace storm {
namespace utility {
@ -53,6 +58,64 @@ void subtractFromConstantOneVector(std::vector<T>* vector) {
}
}
template<class T>
void reduceVectorMin(std::vector<T> const& source, std::vector<T>* target, std::vector<uint_fast64_t> const& filter) {
uint_fast64_t currentSourceRow = 0;
uint_fast64_t currentTargetRow = -1;
for (auto it = source.cbegin(); it != source.cend(); ++it, ++currentSourceRow) {
// Check whether we have considered all source rows for the current target row.
if (filter[currentTargetRow + 1] <= currentSourceRow || currentSourceRow == 0) {
++currentTargetRow;
(*target)[currentTargetRow] = source[currentSourceRow];
continue;
}
// We have to minimize the value, so only overwrite the current value if the
// value is actually lower.
if (*it < (*target)[currentTargetRow]) {
(*target)[currentTargetRow] = *it;
}
}
}
template<class T>
void reduceVectorMax(std::vector<T> const& source, std::vector<T>* target, std::vector<uint_fast64_t> const& filter) {
uint_fast64_t currentSourceRow = 0;
uint_fast64_t currentTargetRow = -1;
for (auto it = source.cbegin(); it != source.cend(); ++it, ++currentSourceRow) {
// Check whether we have considered all source rows for the current target row.
if (filter[currentTargetRow + 1] <= currentSourceRow || currentSourceRow == 0) {
++currentTargetRow;
(*target)[currentTargetRow] = source[currentSourceRow];
continue;
}
// We have to maximize the value, so only overwrite the current value if the
// value is actually greater.
if (*it > (*target)[currentTargetRow]) {
(*target)[currentTargetRow] = *it;
}
}
}
template<class T>
bool equalModuloPrecision(std::vector<T> const& vectorLeft, std::vector<T> const& vectorRight, T precision, bool relativeError) {
if (vectorLeft.size() != vectorRight.size()) {
LOG4CPLUS_ERROR(logger, "Length of vectors does not match and makes comparison impossible.");
throw storm::exceptions::InvalidArgumentException() << "Length of vectors does not match and makes comparison impossible.";
}
for (uint_fast64_t i = 0; i < vectorLeft.size(); ++i) {
if (relativeError) {
if (std::abs(vectorLeft[i] - vectorRight[i])/vectorRight[i] > precision) return false;
} else {
if (std::abs(vectorLeft[i] - vectorRight[i]) > precision) return false;
}
}
return true;
}
} //namespace utility
} //namespace storm

183
src/vector/dense_vector.h

@ -1,183 +0,0 @@
#ifndef MRMC_VECTOR_BITVECTOR_H_
#define MRMC_VECTOR_BITVECTOR_H_
#include <exception>
#include <new>
#include <cmath>
#include "boost/integer/integer_mask.hpp"
#include <pantheios/pantheios.hpp>
#include <pantheios/inserters/integer.hpp>
#include "src/exceptions/invalid_state.h"
#include "src/exceptions/invalid_argument.h"
#include "src/exceptions/out_of_range.h"
namespace mrmc {
namespace vector {
//! A Vector
/*!
A bit vector for boolean fields or quick selection schemas on Matrix entries.
Does NOT perform index bound checks!
*/
template <class T>
class DenseVector {
public:
//! Constructor
/*!
\param initial_length The initial size of the boolean Array. Can be changed later on via BitVector::resize()
*/
BitVector(uint_fast64_t initial_length) {
bucket_count = initial_length / 64;
if (initial_length % 64 != 0) {
++bucket_count;
}
bucket_array = new uint_fast64_t[bucket_count]();
// init all 0
for (uint_fast64_t i = 0; i < bucket_count; ++i) {
bucket_array[i] = 0;
}
}
//! Copy Constructor
/*!
Copy Constructor. Creates an exact copy of the source bit vector bv. Modification of either bit vector does not affect the other.
@param bv A reference to the bit vector that should be copied from
*/
BitVector(const BitVector &bv) : bucket_count(bv.bucket_count)
{
pantheios::log_DEBUG("BitVector::CopyCTor: Using Copy() Ctor.");
bucket_array = new uint_fast64_t[bucket_count]();
memcpy(bucket_array, bv.bucket_array, sizeof(uint_fast64_t) * bucket_count);
}
~BitVector() {
if (bucket_array != NULL) {
delete[] bucket_array;
}
}
void resize(uint_fast64_t new_length) {
uint_fast64_t* tempArray = new uint_fast64_t[new_length]();
// 64 bit/entries per uint_fast64_t
uint_fast64_t copySize = (new_length <= (bucket_count * 64)) ? (new_length/64) : (bucket_count);
memcpy(tempArray, bucket_array, sizeof(uint_fast64_t) * copySize);
bucket_count = new_length / 64;
if (new_length % 64 != 0) {
++bucket_count;
}
delete[] bucket_array;
bucket_array = tempArray;
}
void set(const uint_fast64_t index, const bool value) {
uint_fast64_t bucket = index / 64;
// Taking the step with mask is crucial as we NEED a 64bit shift, not a 32bit one.
// MSVC: C4334, use 1i64 or cast to __int64.
// result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
uint_fast64_t mask = 1;
mask = mask << (index % 64);
if (value) {
bucket_array[bucket] |= mask;
} else {
bucket_array[bucket] &= ~mask;
}
}
bool get(const uint_fast64_t index) {
uint_fast64_t bucket = index / 64;
// Taking the step with mask is crucial as we NEED a 64bit shift, not a 32bit one.
// MSVC: C4334, use 1i64 or cast to __int64.
// result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
uint_fast64_t mask = 1;
mask = mask << (index % 64);
return ((bucket_array[bucket] & mask) == mask);
}
// Operators
BitVector operator &(BitVector const &bv) {
uint_fast64_t minSize = (bv.bucket_count < this->bucket_count) ? bv.bucket_count : this->bucket_count;
BitVector result(minSize * 64);
for (uint_fast64_t i = 0; i < minSize; ++i) {
result.bucket_array[i] = this->bucket_array[i] & bv.bucket_array[i];
}
return result;
}
BitVector operator |(BitVector const &bv) {
uint_fast64_t minSize = (bv.bucket_count < this->bucket_count) ? bv.bucket_count : this->bucket_count;
BitVector result(minSize * 64);
for (uint_fast64_t i = 0; i < minSize; ++i) {
result.bucket_array[i] = this->bucket_array[i] | bv.bucket_array[i];
}
return result;
}
BitVector operator ^(BitVector const &bv) {
uint_fast64_t minSize = (bv.bucket_count < this->bucket_count) ? bv.bucket_count : this->bucket_count;
BitVector result(minSize * 64);
for (uint_fast64_t i = 0; i < minSize; ++i) {
result.bucket_array[i] = this->bucket_array[i] ^ bv.bucket_array[i];
}
return result;
}
BitVector operator ~() {
BitVector result(this->bucket_count * 64);
for (uint_fast64_t i = 0; i < this->bucket_count; ++i) {
result.bucket_array[i] = ~this->bucket_array[i];
}
return result;
}
/*!
* Returns the number of bits that are set (to one) in this bit vector.
* @return The number of bits that are set (to one) in this bit vector.
*/
uint_fast64_t getNumberOfSetBits() {
uint_fast64_t set_bits = 0;
for (uint_fast64_t i = 0; i < bucket_count; i++) {
#ifdef __GNUG__ // check if we are using g++ and use built-in function if available
set_bits += __builtin_popcount (this->bucket_array[i]);
#else
uint_fast32_t cnt;
uint_fast64_t bitset = this->bucket_array[i];
for (cnt = 0; bitset; cnt++) {
bitset &= bitset - 1;
}
set_bits += cnt;
#endif
}
return set_bits;
}
/*!
* Returns the size of the bit vector in memory measured in bytes.
* @return The size of the bit vector in memory measured in bytes.
*/
uint_fast64_t getSizeInMemory() {
return sizeof(*this) + sizeof(uint_fast64_t) * bucket_count;
}
private:
uint_fast64_t bucket_count;
/*! Array containing the boolean bits for each node, 64bits/64nodes per element */
uint_fast64_t* bucket_array;
};
} // namespace vector
} // namespace mrmc
#endif // MRMC_SPARSE_STATIC_SPARSE_MATRIX_H_

8
test/parser/ParseMdpTest.cpp

@ -8,17 +8,17 @@
#include "gtest/gtest.h"
#include "storm-config.h"
#include "src/parser/NonDeterministicModelParser.h"
#include "src/parser/NondeterministicModelParser.h"
#include "src/utility/IoUtility.h"
TEST(ParseMdpTest, parseAndOutput) {
storm::parser::NonDeterministicModelParser* mdpParser = nullptr;
ASSERT_NO_THROW(mdpParser = new storm::parser::NonDeterministicModelParser(
storm::parser::NondeterministicModelParser* mdpParser = nullptr;
ASSERT_NO_THROW(mdpParser = new storm::parser::NondeterministicModelParser(
STORM_CPP_TESTS_BASE_PATH "/parser/tra_files/mdp_general_input_01.tra",
STORM_CPP_TESTS_BASE_PATH "/parser/lab_files/pctl_general_input_01.lab"));
std::shared_ptr<storm::models::Mdp<double>> mdp = mdpParser->getMdp();
std::shared_ptr<storm::storage::SparseMatrix<double>> matrix = mdp->getTransitionProbabilityMatrix();
std::shared_ptr<storm::storage::SparseMatrix<double>> matrix = mdp->getTransitionMatrix();
ASSERT_EQ(mdp->getNumberOfStates(), (uint_fast64_t)3);
ASSERT_EQ(mdp->getNumberOfTransitions(), (uint_fast64_t)11);

23
test/reward/RewardModelTest.cpp

@ -1,23 +0,0 @@
#include "gtest/gtest.h"
#include "Eigen/Sparse"
#include "src/exceptions/InvalidArgumentException.h"
#include "boost/integer/integer_mask.hpp"
#include <vector>
#include "reward/RewardModel.h"
TEST(RewardModelTest, ReadWriteTest) {
// 50 entries
storm::reward::RewardModel<std::vector, double> rm(50, 0.0);
double values[50];
for (int i = 0; i < 50; ++i) {
values[i] = 1.0 + i;
ASSERT_TRUE(rm.setReward(i, values[i]));
ASSERT_EQ(rm.getReward(i), values[i]);
}
}

8
test/storage/SparseMatrixTest.cpp

@ -80,7 +80,7 @@ TEST(SparseMatrixTest, Test) {
int position_row[50] = {
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, /* first row empty, one full row ��������� 25 minus the diagonal entry */
2, 2, 2, 2, /* first row empty, one full row 25 minus the diagonal entry */
4, 4, /* one empty row, then first and last column */
13, 13, 13, 13, /* a few empty rows, middle columns */
24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
@ -288,9 +288,9 @@ TEST(SparseMatrixTest, ConversionFromSparseEigen_RowMajor_SparseMatrixTest) {
ASSERT_EQ(ssm->getState(), storm::storage::SparseMatrix<int>::MatrixStatus::ReadReady);
const std::vector<uint_fast64_t> rowP = ssm->getRowIndicationsPointer();
const std::vector<uint_fast64_t> colP = ssm->getColumnIndicationsPointer();
const std::vector<int> valP = ssm->getStoragePointer();
const std::vector<uint_fast64_t> rowP = ssm->getRowIndications();
const std::vector<uint_fast64_t> colP = ssm->getColumnIndications();
const std::vector<int> valP = ssm->getStorage();
int target = -1;
for (auto &coeff: tripletList) {

Loading…
Cancel
Save