Browse Source

Initial version of reward model checking for DTMCs. Added two convenience operators to PCTL (Eventually and Globally) and added missing reward formulas.

tempestpy_adaptions
dehnert 12 years ago
parent
commit
58cf8118fe
  1. 2
      src/formula/BoundedUntil.h
  2. 115
      src/formula/CumulativeReward.h
  3. 125
      src/formula/Eventually.h
  4. 9
      src/formula/Formulas.h
  5. 125
      src/formula/Globally.h
  6. 115
      src/formula/InstantaneousReward.h
  7. 4
      src/formula/ProbabilisticIntervalOperator.h
  8. 158
      src/formula/ProbabilisticOperator.h
  9. 122
      src/formula/ReachabilityReward.h
  10. 171
      src/formula/RewardIntervalOperator.h
  11. 110
      src/formula/RewardNoBoundsOperator.h
  12. 145
      src/modelChecker/DtmcPrctlModelChecker.h
  13. 290
      src/modelChecker/GmmxxDtmcPrctlModelChecker.h
  14. 25
      src/models/Dtmc.h
  15. 25
      src/solver/GraphAnalyzer.h
  16. 32
      src/storage/SquareSparseMatrix.h
  17. 22
      src/storm.cpp
  18. 20
      src/utility/CommandLine.cpp
  19. 24
      src/utility/CommandLine.h
  20. 53
      src/utility/ConstTemplates.h
  21. 19
      src/utility/Vector.h

2
src/formula/BoundedUntil.h

@ -56,7 +56,7 @@ public:
BoundedUntil(PctlStateFormula<T>* left, PctlStateFormula<T>* right,
uint_fast64_t bound) {
this->left = left;
this->right = right;;
this->right = right;
this->bound = bound;
}

115
src/formula/CumulativeReward.h

@ -0,0 +1,115 @@
/*
* InstantaneousReward.h
*
* Created on: 26.12.2012
* Author: Christian Dehnert
*/
#ifndef STORM_FORMULA_CUMULATIVEREWARD_H_
#define STORM_FORMULA_CUMULATIVEREWARD_H_
#include "PctlPathFormula.h"
#include "PctlStateFormula.h"
#include "boost/integer/integer_mask.hpp"
#include <string>
namespace storm {
namespace formula {
/*!
* @brief
* Class for a PCTL (path) formula tree with a Cumulative Reward node as root.
*
* The subtrees are seen as part of the object and deleted with the object
* (this behavior can be prevented by setting them to NULL before deletion)
*
* @see PctlPathFormula
* @see PctlFormula
*/
template <class T>
class CumulativeReward : public PctlPathFormula<T> {
public:
/*!
* Empty constructor
*/
CumulativeReward() {
bound = 0;
}
/*!
* Constructor
*
* @param bound The time bound of the reward formula
*/
CumulativeReward(uint_fast64_t bound) {
this->bound = bound;
}
/*!
* Empty destructor.
*/
virtual ~CumulativeReward() {
// Intentionally left empty.
}
/*!
* @returns the time instance for the instantaneous reward operator
*/
uint_fast64_t getBound() const {
return bound;
}
/*!
* Sets the the time instance for the instantaneous reward operator
*
* @param bound the new bound.
*/
void setBound(uint_fast64_t bound) {
this->bound = bound;
}
/*!
* @returns a string representation of the formula
*/
virtual std::string toString() const {
std::string result = "C<=";
result += std::to_string(bound);
return result;
}
/*!
* Clones the called object.
*
* Performs a "deep copy", i.e. the subtrees of the new object are clones of the original ones
*
* @returns a new BoundedUntil-object that is identical the called object.
*/
virtual PctlPathFormula<T>* clone() const {
return new CumulativeReward(bound);
}
/*!
* 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 vector indicating the probability that the formula holds for each state.
*/
virtual std::vector<T> *check(const storm::modelChecker::DtmcPrctlModelChecker<T>& modelChecker) const {
return modelChecker.checkCumulativeReward(*this);
}
private:
uint_fast64_t bound;
};
} //namespace formula
} //namespace storm
#endif /* STORM_FORMULA_INSTANTANEOUSREWARD_H_ */

125
src/formula/Eventually.h

@ -0,0 +1,125 @@
/*
* Next.h
*
* Created on: 26.12.2012
* Author: Christian Dehnert
*/
#ifndef STORM_FORMULA_EVENTUALLY_H_
#define STORM_FORMULA_EVENTUALLY_H_
#include "PctlPathFormula.h"
#include "PctlStateFormula.h"
namespace storm {
namespace formula {
/*!
* @brief
* Class for a PCTL (path) formula tree with an Eventually node as root.
*
* Has one PCTL state formula as sub formula/tree.
*
* @par Semantics
* The formula holds iff eventually \e child holds.
*
* The subtree is seen as part of the object and deleted with the object
* (this behavior can be prevented by setting them to nullptr before deletion)
*
* @see PctlPathFormula
* @see PctlFormula
*/
template <class T>
class Eventually : public PctlPathFormula<T> {
public:
/*!
* Empty constructor
*/
Eventually() {
this->child = nullptr;
}
/*!
* Constructor
*
* @param child The child node
*/
Eventually(PctlStateFormula<T>* child) {
this->child = child;
}
/*!
* Constructor.
*
* Also deletes the subtree.
* (this behaviour can be prevented by setting the subtrees to nullptr before deletion)
*/
virtual ~Eventually() {
if (child != nullptr) {
delete child;
}
}
/*!
* @returns the child node
*/
const PctlStateFormula<T>& getChild() const {
return *child;
}
/*!
* Sets the subtree
* @param child the new child node
*/
void setChild(PctlStateFormula<T>* child) {
this->child = child;
}
/*!
* @returns a string representation of the formula
*/
virtual std::string toString() const {
std::string result = "F ";
result += child->toString();
return result;
}
/*!
* Clones the called object.
*
* Performs a "deep copy", i.e. the subtrees of the new object are clones of the original ones
*
* @returns a new BoundedUntil-object that is identical the called object.
*/
virtual PctlPathFormula<T>* clone() const {
Eventually<T>* result = new Eventually<T>();
if (child != nullptr) {
result->setChild(child);
}
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 vector indicating the probability that the formula holds for each state.
*/
virtual std::vector<T> *check(const storm::modelChecker::DtmcPrctlModelChecker<T>& modelChecker) const {
return modelChecker.checkEventually(*this);
}
private:
PctlStateFormula<T>* child;
};
} //namespace formula
} //namespace storm
#endif /* STORM_FORMULA_EVENTUALLY_H_ */

9
src/formula/Formulas.h

@ -17,9 +17,16 @@
#include "PctlFormula.h"
#include "PctlPathFormula.h"
#include "PctlStateFormula.h"
#include "ProbabilisticOperator.h"
#include "ProbabilisticNoBoundsOperator.h"
#include "ProbabilisticIntervalOperator.h"
#include "Until.h"
#include "Eventually.h"
#include "Globally.h"
#include "InstantaneousReward.h"
#include "CumulativeReward.h"
#include "ReachabilityReward.h"
#include "RewardIntervalOperator.h"
#include "RewardNoBoundsOperator.h"
#endif /* STORM_FORMULA_FORMULAS_H_ */

125
src/formula/Globally.h

@ -0,0 +1,125 @@
/*
* Next.h
*
* Created on: 26.12.2012
* Author: Christian Dehnert
*/
#ifndef STORM_FORMULA_GLOBALLY_H_
#define STORM_FORMULA_GLOBALLY_H_
#include "PctlPathFormula.h"
#include "PctlStateFormula.h"
namespace storm {
namespace formula {
/*!
* @brief
* Class for a PCTL (path) formula tree with a Globally node as root.
*
* Has one PCTL state formula as sub formula/tree.
*
* @par Semantics
* The formula holds iff globally \e child holds.
*
* The subtree is seen as part of the object and deleted with the object
* (this behavior can be prevented by setting them to nullptr before deletion)
*
* @see PctlPathFormula
* @see PctlFormula
*/
template <class T>
class Globally : public PctlPathFormula<T> {
public:
/*!
* Empty constructor
*/
Globally() {
this->child = nullptr;
}
/*!
* Constructor
*
* @param child The child node
*/
Globally(PctlStateFormula<T>* child) {
this->child = child;
}
/*!
* Constructor.
*
* Also deletes the subtree.
* (this behaviour can be prevented by setting the subtrees to nullptr before deletion)
*/
virtual ~Globally() {
if (child != nullptr) {
delete child;
}
}
/*!
* @returns the child node
*/
const PctlStateFormula<T>& getChild() const {
return *child;
}
/*!
* Sets the subtree
* @param child the new child node
*/
void setChild(PctlStateFormula<T>* child) {
this->child = child;
}
/*!
* @returns a string representation of the formula
*/
virtual std::string toString() const {
std::string result = "G ";
result += child->toString();
return result;
}
/*!
* Clones the called object.
*
* Performs a "deep copy", i.e. the subtrees of the new object are clones of the original ones
*
* @returns a new BoundedUntil-object that is identical the called object.
*/
virtual PctlPathFormula<T>* clone() const {
Next<T>* result = new Next<T>();
if (child != nullptr) {
result->setChild(child);
}
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 vector indicating the probability that the formula holds for each state.
*/
virtual std::vector<T> *check(const storm::modelChecker::DtmcPrctlModelChecker<T>& modelChecker) const {
return modelChecker.checkGlobally(*this);
}
private:
PctlStateFormula<T>* child;
};
} //namespace formula
} //namespace storm
#endif /* STORM_FORMULA_GLOBALLY_H_ */

115
src/formula/InstantaneousReward.h

@ -0,0 +1,115 @@
/*
* InstantaneousReward.h
*
* Created on: 26.12.2012
* Author: Christian Dehnert
*/
#ifndef STORM_FORMULA_INSTANTANEOUSREWARD_H_
#define STORM_FORMULA_INSTANTANEOUSREWARD_H_
#include "PctlPathFormula.h"
#include "PctlStateFormula.h"
#include "boost/integer/integer_mask.hpp"
#include <string>
namespace storm {
namespace formula {
/*!
* @brief
* Class for a PCTL (path) formula tree with a Instantaneous Reward node as root.
*
* The subtrees are seen as part of the object and deleted with the object
* (this behavior can be prevented by setting them to NULL before deletion)
*
* @see PctlPathFormula
* @see PctlFormula
*/
template <class T>
class InstantaneousReward : public PctlPathFormula<T> {
public:
/*!
* Empty constructor
*/
InstantaneousReward() {
bound = 0;
}
/*!
* Constructor
*
* @param bound The time instance of the reward formula
*/
InstantaneousReward(uint_fast64_t bound) {
this->bound = bound;
}
/*!
* Empty destructor.
*/
virtual ~InstantaneousReward() {
// Intentionally left empty.
}
/*!
* @returns the time instance for the instantaneous reward operator
*/
uint_fast64_t getBound() const {
return bound;
}
/*!
* Sets the the time instance for the instantaneous reward operator
*
* @param bound the new bound.
*/
void setBound(uint_fast64_t bound) {
this->bound = bound;
}
/*!
* @returns a string representation of the formula
*/
virtual std::string toString() const {
std::string result = "I=";
result += std::to_string(bound);
return result;
}
/*!
* Clones the called object.
*
* Performs a "deep copy", i.e. the subtrees of the new object are clones of the original ones
*
* @returns a new BoundedUntil-object that is identical the called object.
*/
virtual PctlPathFormula<T>* clone() const {
return new InstantaneousReward(bound);
}
/*!
* 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 vector indicating the probability that the formula holds for each state.
*/
virtual std::vector<T> *check(const storm::modelChecker::DtmcPrctlModelChecker<T>& modelChecker) const {
return modelChecker.checkInstantaneousReward(*this);
}
private:
uint_fast64_t bound;
};
} //namespace formula
} //namespace storm
#endif /* STORM_FORMULA_INSTANTANEOUSREWARD_H_ */

4
src/formula/ProbabilisticIntervalOperator.h

@ -21,10 +21,6 @@ namespace formula {
* Class for a PCTL formula tree with a P (probablistic) operator node over a probability interval
* as root.
*
* If the probability interval consist just of one single value (i.e. it is [x,x] for some
* real number x), the class ProbabilisticOperator should be used instead.
*
*
* Has one PCTL path formula as sub formula/tree.
*
* @par Semantics

158
src/formula/ProbabilisticOperator.h

@ -1,158 +0,0 @@
/*
* ProbabilisticOperator.h
*
* Created on: 07.12.2012
* Author: Thomas Heinemann
*/
#ifndef STORM_FORMULA_PROBABILISTICOPERATOR_H_
#define STORM_FORMULA_PROBABILISTICOPERATOR_H_
#include "PctlStateFormula.h"
namespace storm {
namespace formula {
/*!
* @brief
* Class for a PCTL formula tree with a P (probablistic) operator node over a single real valued
* probability as root.
*
* If the probability interval consist just of one single value (i.e. it is [x,x] for some
* real number x), the class ProbabilisticOperator should be used instead.
*
*
* Has one PCTL path formula as sub formula/tree.
*
* @par Semantics
* The formula holds iff the probability that the path formula holds is equal to the probablility
* specified in this operator
*
* The subtree is seen as part of the object and deleted with it
* (this behavior can be prevented by setting them to NULL before deletion)
*
*
* @see PctlStateFormula
* @see PctlPathFormula
* @see ProbabilisticIntervalOperator
* @see ProbabilisticNoBoundsOperator
* @see PctlFormula
*/
template<class T>
class ProbabilisticOperator : public storm::formula::PctlStateFormula<T> {
public:
/*!
* Empty constructor
*/
ProbabilisticOperator() {
this->pathFormula = NULL;
}
/*!
* Constructor
*
* @param bound The expected value for path formulas
* @param pathFormula The child node
*/
ProbabilisticOperator(T bound, PctlPathFormula<T>* pathFormula) {
this->bound = bound;
this->pathFormula = *pathFormula;
}
/*!
* Destructor
*
* The subtree is deleted with the object
* (this behavior can be prevented by setting them to NULL before deletion)
*/
virtual ~ProbabilisticOperator() {
if (pathFormula != NULL) {
delete pathFormula;
}
}
/*!
* @returns the child node (representation of a PCTL path formula)
*/
const PctlPathFormula<T>& getPathFormula () const {
return *pathFormula;
}
/*!
* @returns the bound for the probability
*/
const T& getBound() const {
return bound;
}
/*!
* Sets the child node
*
* @param pathFormula the path formula that becomes the new child node
*/
void setPathFormula(PctlPathFormula<T>* pathFormula) {
this->pathFormula = pathFormula;
}
/*!
* Sets the expected probability that the path formula holds.
*
* @param bound The bound for the probability
*/
void setBound(T bound) {
this->bound = bound;
}
/*!
* Clones the called object.
*
* Performs a "deep copy", i.e. the subtrees of the new object are clones of the original ones
*
* @returns a new ProbabilisticOperator-object that is identical to the called object.
*/
virtual PctlStateFormula<T>* clone() const {
ProbabilisticOperator<T>* result = new ProbabilisticOperator<T>();
result->setBound(bound);
if (pathFormula != NULL) {
result->setPathFormula(pathFormula->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::DtmcPrctlModelChecker<T>& modelChecker) const {
return modelChecker.checkProbabilisticOperator(*this);
}
/*!
* Returns a string representation of this PctlStateFormula
*
* @returns a string representation of this PctlStateFormula
*/
virtual std::string toString() const {
std::string result = " P=";
result += std::to_string(bound);
result += " (";
result += pathFormula->toString();
result += ")";
return result;
}
private:
T bound;
PctlPathFormula<T>* pathFormula;
};
} /* namespace formula */
} /* namespace storm */
#endif /* STORM_FORMULA_PROBABILISTICOPERATOR_H_ */

122
src/formula/ReachabilityReward.h

@ -0,0 +1,122 @@
/*
* Next.h
*
* Created on: 26.12.2012
* Author: Christian Dehnert
*/
#ifndef STORM_FORMULA_REACHABILITYREWARD_H_
#define STORM_FORMULA_REACHABILITYREWARD_H_
#include "PctlPathFormula.h"
#include "PctlStateFormula.h"
namespace storm {
namespace formula {
/*!
* @brief
* Class for a PCTL (path) formula tree with an Reachability Reward node as root.
*
* Has one PCTL state formula as sub formula/tree.
*
* The subtree is seen as part of the object and deleted with the object
* (this behavior can be prevented by setting them to nullptr before deletion)
*
* @see PctlPathFormula
* @see PctlFormula
*/
template <class T>
class ReachabilityReward : public PctlPathFormula<T> {
public:
/*!
* Empty constructor
*/
ReachabilityReward() {
this->child = nullptr;
}
/*!
* Constructor
*
* @param child The child node
*/
ReachabilityReward(PctlStateFormula<T>* child) {
this->child = child;
}
/*!
* Constructor.
*
* Also deletes the subtree.
* (this behaviour can be prevented by setting the subtrees to nullptr before deletion)
*/
virtual ~ReachabilityReward() {
if (child != nullptr) {
delete child;
}
}
/*!
* @returns the child node
*/
const PctlStateFormula<T>& getChild() const {
return *child;
}
/*!
* Sets the subtree
* @param child the new child node
*/
void setChild(PctlStateFormula<T>* child) {
this->child = child;
}
/*!
* @returns a string representation of the formula
*/
virtual std::string toString() const {
std::string result = "F ";
result += child->toString();
return result;
}
/*!
* Clones the called object.
*
* Performs a "deep copy", i.e. the subtrees of the new object are clones of the original ones
*
* @returns a new BoundedUntil-object that is identical the called object.
*/
virtual PctlPathFormula<T>* clone() const {
ReachabilityReward<T>* result = new ReachabilityReward<T>();
if (child != nullptr) {
result->setChild(child);
}
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 vector indicating the probability that the formula holds for each state.
*/
virtual std::vector<T> *check(const storm::modelChecker::DtmcPrctlModelChecker<T>& modelChecker) const {
return modelChecker.checkReachabilityReward(*this);
}
private:
PctlStateFormula<T>* child;
};
} //namespace formula
} //namespace storm
#endif /* STORM_FORMULA_REACHABILITYREWARD_H_ */

171
src/formula/RewardIntervalOperator.h

@ -0,0 +1,171 @@
/*
* ProbabilisticOperator.h
*
* Created on: 19.10.2012
* Author: Thomas Heinemann
*/
#ifndef STORM_FORMULA_REWARDINTERVALOPERATOR_H_
#define STORM_FORMULA_REWARDINTERVALOPERATOR_H_
#include "PctlStateFormula.h"
#include "PctlPathFormula.h"
#include "utility/ConstTemplates.h"
namespace storm {
namespace formula {
/*!
* @brief
* Class for a PCTL formula tree with a R (reward) operator node over a reward interval as root.
*
* Has a reward path formula as sub formula/tree.
*
* @par Semantics
* The formula holds iff the reward of the reward path formula is inside the bounds
* specified in this operator
*
* The subtree is seen as part of the object and deleted with it
* (this behavior can be prevented by setting them to NULL before deletion)
*
*
* @see PctlStateFormula
* @see PctlPathFormula
* @see ProbabilisticOperator
* @see ProbabilisticNoBoundsOperator
* @see PctlFormula
*/
template<class T>
class RewardIntervalOperator : public PctlStateFormula<T> {
public:
/*!
* Empty constructor
*/
RewardIntervalOperator() {
upper = storm::utility::constGetZero<T>();
lower = storm::utility::constGetZero<T>();
pathFormula = nullptr;
}
/*!
* Constructor
*
* @param lowerBound The lower bound for the probability
* @param upperBound The upper bound for the probability
* @param pathFormula The child node
*/
RewardIntervalOperator(T lowerBound, T upperBound, PctlPathFormula<T>& pathFormula) {
this->lower = lowerBound;
this->upper = upperBound;
this->pathFormula = &pathFormula;
}
/*!
* Destructor
*
* The subtree is deleted with the object
* (this behavior can be prevented by setting them to NULL before deletion)
*/
virtual ~RewardIntervalOperator() {
if (pathFormula != nullptr) {
delete pathFormula;
}
}
/*!
* @returns the child node (representation of a PCTL path formula)
*/
const PctlPathFormula<T>& getPathFormula () const {
return *pathFormula;
}
/*!
* @returns the lower bound for the probability
*/
const T& getLowerBound() const {
return lower;
}
/*!
* @returns the upper bound for the probability
*/
const T& getUpperBound() const {
return upper;
}
/*!
* Sets the child node
*
* @param pathFormula the path formula that becomes the new child node
*/
void setPathFormula(PctlPathFormula<T>* pathFormula) {
this->pathFormula = pathFormula;
}
/*!
* Sets the interval in which the probability that the path formula holds may lie in.
*
* @param lowerBound The lower bound for the probability
* @param upperBound The upper bound for the probability
*/
void setInterval(T lowerBound, T upperBound) {
this->lower = lowerBound;
this->upper = upperBound;
}
/*!
* @returns a string representation of the formula
*/
virtual std::string toString() const {
std::string result = "R [";
result += std::to_string(lower);
result += ", ";
result += std::to_string(upper);
result += "] [";
result += pathFormula->toString();
result += "]";
return result;
}
/*!
* Clones the called object.
*
* Performs a "deep copy", i.e. the subtrees of the new object are clones of the original ones
*
* @returns a new AND-object that is identical the called object.
*/
virtual PctlStateFormula<T>* clone() const {
RewardIntervalOperator<T>* result = new RewardIntervalOperator<T>();
result->setInterval(lower, upper);
if (pathFormula != nullptr) {
result->setPathFormula(pathFormula->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::DtmcPrctlModelChecker<T>& modelChecker) const {
return modelChecker.checkRewardIntervalOperator(*this);
}
private:
T lower;
T upper;
PctlPathFormula<T>* pathFormula;
};
} //namespace formula
} //namespace storm
#endif /* STORM_FORMULA_REWARDINTERVALOPERATOR_H_ */

110
src/formula/RewardNoBoundsOperator.h

@ -0,0 +1,110 @@
/*
* RewardNoBoundsOperator.h
*
* Created on: 12.12.2012
* Author: thomas
*/
#ifndef STORM_FORMULA_REWARDNOBOUNDSOPERATOR_H_
#define STORM_FORMULA_REWARDNOBOUNDSOPERATOR_H_
#include "PctlFormula.h"
#include "PctlPathFormula.h"
namespace storm {
namespace formula {
/*!
* @brief
* Class for a PCTL formula tree with a R (reward) operator without declaration of reward values
* as root.
*
* Checking a formula with this operator as root returns the reward for the reward path formula for
* each state
*
* Has one PCTL path formula as sub formula/tree.
*
* @note
* This class is a hybrid of a state and path formula, and may only appear as the outermost operator.
* Hence, it is seen as neither a state nor a path formula, but is directly derived from PctlFormula.
*
* @note
* This class does not contain a check() method like the other formula classes.
* The check method should only be called by the model checker to infer the correct check function for sub
* formulas. As this operator can only appear at the root, the method is not useful here.
* Use the checkRewardNoBoundsOperator method from the DtmcPrctlModelChecker class instead.
*
* The subtree is seen as part of the object and deleted with it
* (this behavior can be prevented by setting them to NULL before deletion)
*
*
* @see PctlStateFormula
* @see PctlPathFormula
* @see ProbabilisticOperator
* @see ProbabilisticIntervalOperator
* @see PctlFormula
*/
template <class T>
class RewardNoBoundsOperator: public storm::formula::PctlFormula<T> {
public:
/*!
* Empty constructor
*/
RewardNoBoundsOperator() {
this->pathFormula = nullptr;
}
/*!
* Constructor
*
* @param pathFormula The child node.
*/
RewardNoBoundsOperator(PctlPathFormula<T>* pathFormula) {
this->pathFormula = pathFormula;
}
/*!
* Destructor
*/
virtual ~RewardNoBoundsOperator() {
if (pathFormula != nullptr) {
delete pathFormula;
}
}
/*!
* @returns the child node (representation of a PCTL path formula)
*/
const PctlPathFormula<T>& getPathFormula () const {
return *pathFormula;
}
/*!
* Sets the child node
*
* @param pathFormula the path formula that becomes the new child node
*/
void setPathFormula(PctlPathFormula<T>* pathFormula) {
this->pathFormula = pathFormula;
}
/*!
* @returns a string representation of the formula
*/
virtual std::string toString() const {
std::string result = " R=? [";
result += pathFormula->toString();
result += "]";
return result;
}
private:
PctlPathFormula<T>* pathFormula;
};
} /* namespace formula */
} /* namespace storm */
#endif /* STORM_FORMULA_REWARDNOBOUNDSOPERATOR_H_ */

145
src/modelChecker/DtmcPrctlModelChecker.h

@ -98,13 +98,19 @@ public:
* states.
* @param stateFormula The formula to be checked.
*/
void check(const storm::formula::PctlStateFormula<Type>& stateFormula) {
LOG4CPLUS_INFO(logger, "Model checking formula " << stateFormula.toString());
void check(const storm::formula::PctlStateFormula<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 = 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;
}
std::cout << std::endl;
storm::utility::printSeparationLine(std::cout);
delete result;
}
@ -113,9 +119,10 @@ public:
* (probability) for all initial states.
* @param probabilisticNoBoundsFormula The formula to be checked.
*/
void check(const storm::formula::ProbabilisticNoBoundsOperator<Type>& probabilisticNoBoundsFormula) {
LOG4CPLUS_INFO(logger, "Model checking formula " << probabilisticNoBoundsFormula.toString());
std::cout << "Model checking formula: " << probabilisticNoBoundsFormula.toString() << std::endl;
void check(const storm::formula::ProbabilisticNoBoundsOperator<Type>& probabilisticNoBoundsFormula) const {
std::cout << std::endl;
LOG4CPLUS_INFO(logger, "Model checking formula\t" << probabilisticNoBoundsFormula.toString());
std::cout << "Model checking formula:\t" << probabilisticNoBoundsFormula.toString() << std::endl;
std::vector<Type>* result = checkProbabilisticNoBoundsOperator(probabilisticNoBoundsFormula);
LOG4CPLUS_INFO(logger, "Result for initial states:");
std::cout << "Result for initial states:" << std::endl;
@ -123,6 +130,29 @@ public:
LOG4CPLUS_INFO(logger, "\t" << initialState << ": " << (*result)[initialState]);
std::cout << "\t" << initialState << ": " << (*result)[initialState] << std::endl;
}
std::cout << std::endl;
storm::utility::printSeparationLine(std::cout);
delete result;
}
/*!
* Checks the given reward operator (with no bound) on the DTMC and prints the result
* (reward values) for all initial states.
* @param rewardNoBoundsFormula The formula to be checked.
*/
void check(const storm::formula::RewardNoBoundsOperator<Type>& rewardNoBoundsFormula) {
std::cout << std::endl;
LOG4CPLUS_INFO(logger, "Model checking formula\t" << rewardNoBoundsFormula.toString());
std::cout << "Model checking formula:\t" << rewardNoBoundsFormula.toString() << std::endl;
std::vector<Type>* result = checkRewardNoBoundsOperator(rewardNoBoundsFormula);
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;
}
std::cout << std::endl;
storm::utility::printSeparationLine(std::cout);
delete result;
}
@ -193,38 +223,45 @@ public:
}
/*!
* The check method for a state formula with a probabilistic operator node as root in its
* formula tree
* The check method for a state formula with a probabilistic interval 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* checkProbabilisticOperator(
const storm::formula::ProbabilisticOperator<Type>& formula) const {
storm::storage::BitVector* checkProbabilisticIntervalOperator(
const storm::formula::ProbabilisticIntervalOperator<Type>& formula) const {
// First, we need to compute the probability for satisfying the path formula for each state.
std::vector<Type>* probabilisticResult = 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());
Type bound = formula.getBound();
// Now, we can compute which states meet the bound specified in this operator, i.e.
// lie in the interval that was given along with this operator, and set the corresponding bits
// to true in the resulting vector.
Type lower = formula.getLowerBound();
Type upper = formula.getUpperBound();
for (uint_fast64_t i = 0; i < this->getModel().getNumberOfStates(); ++i) {
if ((*probabilisticResult)[i] == bound) result->set(i, true);
if ((*probabilisticResult)[i] >= lower && (*probabilisticResult)[i] <= upper) result->set(i, true);
}
// Delete the probabilities computed for the states and return result.
delete probabilisticResult;
return result;
}
/*!
* The check method for a state formula with a probabilistic interval operator node as root in
* The check method for a state formula with a reward interval 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* checkProbabilisticIntervalOperator(
const storm::formula::ProbabilisticIntervalOperator<Type>& formula) const {
storm::storage::BitVector* checkRewardIntervalOperator(
const storm::formula::RewardIntervalOperator<Type>& formula) const {
// First, we need to compute the probability for satisfying the path formula for each state.
std::vector<Type>* probabilisticResult = this->checkPathFormula(formula.getPathFormula());
std::vector<Type>* rewardResult = 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());
@ -235,15 +272,14 @@ public:
Type lower = formula.getLowerBound();
Type upper = formula.getUpperBound();
for (uint_fast64_t i = 0; i < this->getModel().getNumberOfStates(); ++i) {
if ((*probabilisticResult)[i] >= lower && (*probabilisticResult)[i] <= upper) result->set(i, true);
if ((*rewardResult)[i] >= lower && (*rewardResult)[i] <= upper) result->set(i, true);
}
// Delete the probabilities computed for the states and return result.
delete probabilisticResult;
// Delete the reward values computed for the states and return result.
delete rewardResult;
return result;
}
/*!
* The check method for a state formula with a probabilistic operator node without bounds as root
* in its formula tree
@ -256,6 +292,18 @@ public:
return formula.getPathFormula().check(*this);
}
/*!
* The check method for a state formula with a reward 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>* checkRewardNoBoundsOperator(
const storm::formula::RewardNoBoundsOperator<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
@ -283,6 +331,36 @@ public:
*/
virtual std::vector<Type>* checkNext(const storm::formula::Next<Type>& formula) const = 0;
/*!
* 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) const {
// Create equivalent temporary until formula and check it.
storm::formula::Until<Type> temporaryUntilFormula(new storm::formula::Ap<Type>("true"), formula.getChild().clone());
std::vector<Type>* result = this->checkUntil(temporaryUntilFormula);
return result;
}
/*!
* 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) 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);
// 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
*
@ -291,6 +369,33 @@ public:
*/
virtual std::vector<Type>* checkUntil(const storm::formula::Until<Type>& formula) 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) 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) 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) const = 0;
private:
storm::models::Dtmc<Type>& model;
};

290
src/modelChecker/GmmxxDtmcPrctlModelChecker.h

@ -17,6 +17,7 @@
#include "src/utility/ConstTemplates.h"
#include "src/utility/Settings.h"
#include "src/adapters/GmmxxAdapter.h"
#include "src/exceptions/InvalidArgumentException.h"
#include "gmm/gmm_matrix.h"
#include "gmm/gmm_iter_solvers.h"
@ -71,6 +72,7 @@ public:
delete tmpResult;
// Delete intermediate results and return result.
delete gmmxxMatrix;
delete leftStates;
delete rightStates;
return result;
@ -122,7 +124,7 @@ public:
storm::storage::BitVector maybeStates = ~(notExistsPhiUntilPsiStates | alwaysPhiUntilPsiStates);
LOG4CPLUS_INFO(logger, "Found " << maybeStates.getNumberOfSetBits() << " 'maybe' states.");
// Create resulting vector and set values accordingly.
// 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.
@ -147,84 +149,176 @@ public:
std::vector<Type> b(maybeStates.getNumberOfSetBits());
this->getModel().getTransitionProbabilityMatrix()->getConstrainedRowCountVector(maybeStates, alwaysPhiUntilPsiStates, &b);
// Get the settings object to customize linear solving.
storm::settings::Settings* s = storm::settings::instance();
// Solve the corresponding system of linear equations.
this->solveLinearEquationSystem(*gmmxxMatrix, x, b);
// 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"));
// Set values of resulting vector according to result.
storm::utility::setVectorValues<Type>(result, maybeStates, x);
// Now do the actual solving.
LOG4CPLUS_INFO(logger, "Starting iterative solver.");
const std::string& precond = s->getString("precond");
if (precond == "ilu") {
LOG4CPLUS_INFO(logger, "Using ILU preconditioner.");
} else if (precond == "diagonal") {
LOG4CPLUS_INFO(logger, "Using diagonal preconditioner.");
} else if (precond == "ildlt") {
LOG4CPLUS_INFO(logger, "Using ILDLT preconditioner.");
} else if (precond == "none") {
LOG4CPLUS_INFO(logger, "Using no preconditioner.");
// Delete temporary matrix.
delete gmmxxMatrix;
}
if (s->getString("lemethod") == "bicgstab") {
LOG4CPLUS_INFO(logger, "Using BiCGStab method.");
if (precond == "ilu") {
gmm::bicgstab(*gmmxxMatrix, x, b, gmm::ilu_precond<gmm::csr_matrix<Type>>(*gmmxxMatrix), iter);
} else if (precond == "diagonal") {
gmm::bicgstab(*gmmxxMatrix, x, b, gmm::diagonal_precond<gmm::csr_matrix<Type>>(*gmmxxMatrix), iter);
} else if (precond == "ildlt") {
gmm::bicgstab(*gmmxxMatrix, x, b, gmm::ildlt_precond<gmm::csr_matrix<Type>>(*gmmxxMatrix), iter);
} else if (precond == "none") {
gmm::bicgstab(*gmmxxMatrix, x, b, gmm::identity_matrix(), iter);
// 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>());
return result;
}
// FIXME: gmres has been disabled, because it triggers gmm++ compilation errors
/* } else if (s->getString("lemethod").compare("gmres") == 0) {
LOG4CPLUS_INFO(logger, "Using GMRES method.");
if (precond.compare("ilu")) {
gmm::gmres(*gmmxxMatrix, x, b, gmm::ilu_precond<gmm::csr_matrix<Type>>(*gmmxxMatrix), s->get<unsigned>("restart"), iter);
} else if (precond == "diagonal") {
gmm::gmres(*gmmxxMatrix, x, b, gmm::diagonal_precond<gmm::csr_matrix<Type>>(*gmmxxMatrix), s->get<unsigned>("restart"), iter);
} else if (precond == "ildlt") {
gmm::gmres(*gmmxxMatrix, x, b, gmm::ildlt_precond<gmm::csr_matrix<Type>>(*gmmxxMatrix), s->get<unsigned>("restart"), iter);
} else if (precond == "none") {
gmm::gmres(*gmmxxMatrix, x, b, gmm::identity_matrix(), s->get<unsigned>("restart"), iter);
} */
} else if (s->getString("lemethod") == "qmr") {
LOG4CPLUS_INFO(logger, "Using QMR method.");
if (precond == "ilu") {
gmm::qmr(*gmmxxMatrix, x, b, gmm::ilu_precond<gmm::csr_matrix<Type>>(*gmmxxMatrix), iter);
} /* FIXME: The following line throws a warning as there should be brackets around such a construction
* TBH, I don't understand it completely (why the comparison with 0?), so I don't know how to fix it
* (Thomas Heinemann, 2012-12-21)
*/
else if (precond == "diagonal") {
gmm::qmr(*gmmxxMatrix, x, b, gmm::diagonal_precond<gmm::csr_matrix<Type>>(*gmmxxMatrix), iter);
} else if (precond == "ildlt") {
gmm::qmr(*gmmxxMatrix, x, b, gmm::ildlt_precond<gmm::csr_matrix<Type>>(*gmmxxMatrix), iter);
} else if (precond == "none") {
gmm::qmr(*gmmxxMatrix, x, b, gmm::identity_matrix(), iter);
virtual std::vector<Type>* checkInstantaneousReward(const storm::formula::InstantaneousReward<Type>& formula) 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::InvalidArgumentException() << "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().getTransitionProbabilityMatrix());
// Initialize result to state rewards of the model.
std::vector<Type>* result = new std::vector<Type>(*this->getModel().getStateRewards());
// 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;
}
// Check if the solver converged and issue a warning otherwise.
if (iter.converged()) {
LOG4CPLUS_INFO(logger, "Iterative solver converged after " << iter.get_iteration() << " iterations.");
// Delete temporary variables and return result.
delete tmpResult;
delete gmmxxMatrix;
return result;
}
virtual std::vector<Type>* checkCumulativeReward(const storm::formula::CumulativeReward<Type>& formula) 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::InvalidArgumentException() << "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().getTransitionProbabilityMatrix());
// 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());
if (this->getModel().hasStateRewards()) {
gmm::add(*this->getModel().getStateRewards(), *totalRewardVector);
}
} else {
LOG4CPLUS_WARN(logger, "Iterative solver did not converge.");
totalRewardVector = new std::vector<Type>(*this->getModel().getStateRewards());
}
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) 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::InvalidArgumentException() << "Missing reward model for formula.";
}
// Determine the states for which the target predicate holds.
storm::storage::BitVector* targetStates = this->checkStateFormula(formula.getChild());
// 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);
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;
if (maybeStates.getNumberOfSetBits() > 0) {
// Now we can eliminate the rows and columns from the original transition probability matrix.
storm::storage::SquareSparseMatrix<Type>* submatrix = this->getModel().getTransitionProbabilityMatrix()->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(maybeStates.getNumberOfSetBits(), storm::utility::constGetOne<Type>());
// Prepare the right-hand side of the equation system.
std::vector<Type>* b = new std::vector<Type>(maybeStates.getNumberOfSetBits());
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().getTransitionProbabilityMatrix()->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>(maybeStates.getNumberOfSetBits());
storm::utility::setVectorValues(subStateRewards, maybeStates, *this->getModel().getStateRewards());
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().getStateRewards());
}
// Solve the corresponding system of linear equations.
this->solveLinearEquationSystem(*gmmxxMatrix, x, *b);
// Set values of resulting vector according to result.
storm::utility::setVectorValues<Type>(result, maybeStates, x);
// Delete temporary matrix.
// Delete temporary matrix and right-hand side.
delete gmmxxMatrix;
delete b;
}
// 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(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;
}
@ -274,6 +368,82 @@ public:
throw exceptions::InvalidSettingsException() << "Argument " << preconditioner << " for option 'precond' is invalid.";
}
}
private:
/*!
* Solves the linear equation system Ax=b with the given parameters.
*
* @param A The matrix A specifying the coefficients of the linear 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 solveLinearEquationSystem(gmm::csr_matrix<Type> const& A, std::vector<Type>& x, std::vector<Type> const& b) const {
// Get the settings object to customize linear solving.
storm::settings::Settings* s = storm::settings::instance();
// 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"));
// Now do the actual solving.
LOG4CPLUS_INFO(logger, "Starting iterative solver.");
const std::string& precond = s->getString("precond");
if (precond == "ilu") {
LOG4CPLUS_INFO(logger, "Using ILU preconditioner.");
} else if (precond == "diagonal") {
LOG4CPLUS_INFO(logger, "Using diagonal preconditioner.");
} else if (precond == "ildlt") {
LOG4CPLUS_INFO(logger, "Using ILDLT preconditioner.");
} else if (precond == "none") {
LOG4CPLUS_INFO(logger, "Using no preconditioner.");
}
if (s->getString("lemethod") == "bicgstab") {
LOG4CPLUS_INFO(logger, "Using BiCGStab method.");
if (precond == "ilu") {
gmm::bicgstab(A, x, b, gmm::ilu_precond<gmm::csr_matrix<Type>>(A), iter);
} else if (precond == "diagonal") {
gmm::bicgstab(A, x, b, gmm::diagonal_precond<gmm::csr_matrix<Type>>(A), iter);
} else if (precond == "ildlt") {
gmm::bicgstab(A, x, b, gmm::ildlt_precond<gmm::csr_matrix<Type>>(A), iter);
} else if (precond == "none") {
gmm::bicgstab(A, x, b, gmm::identity_matrix(), iter);
}
// FIXME: gmres has been disabled, because it triggers gmm++ compilation errors
/* } else if (s->getString("lemethod").compare("gmres") == 0) {
LOG4CPLUS_INFO(logger, "Using GMRES method.");
if (precond.compare("ilu")) {
gmm::gmres(A, x, b, gmm::ilu_precond<gmm::csr_matrix<Type>>(A), s->get<unsigned>("restart"), iter);
} else if (precond == "diagonal") {
gmm::gmres(A, x, b, gmm::diagonal_precond<gmm::csr_matrix<Type>>(A), s->get<unsigned>("restart"), iter);
} else if (precond == "ildlt") {
gmm::gmres(A, x, b, gmm::ildlt_precond<gmm::csr_matrix<Type>>(A), s->get<unsigned>("restart"), iter);
} else if (precond == "none") {
gmm::gmres(A, x, b, gmm::identity_matrix(), s->get<unsigned>("restart"), iter);
} */
} else if (s->getString("lemethod") == "qmr") {
LOG4CPLUS_INFO(logger, "Using QMR method.");
if (precond == "ilu") {
gmm::qmr(A, x, b, gmm::ilu_precond<gmm::csr_matrix<Type>>(A), iter);
} else if (precond == "diagonal") {
gmm::qmr(A, x, b, gmm::diagonal_precond<gmm::csr_matrix<Type>>(A), iter);
} else if (precond == "ildlt") {
gmm::qmr(A, x, b, gmm::ildlt_precond<gmm::csr_matrix<Type>>(A), iter);
} else if (precond == "none") {
gmm::qmr(A, x, b, gmm::identity_matrix(), iter);
}
}
// Check if the solver converged and issue a warning otherwise.
if (iter.converged()) {
LOG4CPLUS_INFO(logger, "Iterative solver converged after " << iter.get_iteration() << " iterations.");
} else {
LOG4CPLUS_WARN(logger, "Iterative solver did not converge.");
}
}
};
} //namespace modelChecker

25
src/models/Dtmc.h

@ -17,6 +17,7 @@
#include "GraphTransitions.h"
#include "src/storage/SquareSparseMatrix.h"
#include "src/exceptions/InvalidArgumentException.h"
#include "src/utility/CommandLine.h"
namespace storm {
@ -148,13 +149,29 @@ public:
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;
}
/*!
* 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;
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;
@ -163,8 +180,8 @@ public:
<< (this->probabilityMatrix->getSizeInMemory() +
this->stateLabeling->getSizeInMemory() +
sizeof(*this))/1024 << " kbytes" << std::endl;
out << "-------------------------------------------------------------- "
<< std::endl;
out << std::endl;
storm::utility::printSeparationLine(out);
}
private:

25
src/solver/GraphAnalyzer.h

@ -92,6 +92,31 @@ public:
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

32
src/storage/SquareSparseMatrix.h

@ -827,6 +827,38 @@ public:
return new storm::storage::JacobiDecomposition<T>(resultLU, resultDinv);
}
/*!
* Performs a pointwise matrix multiplication of the matrix with the given matrix and returns a
* vector containing the sum of the elements in each row of the resulting matrix.
* @param otherMatrix A reference to the matrix with which to perform the pointwise multiplication.
* This matrix must be a submatrix of the current matrix in the sense that it may not have
* non-zero entries at indices where there is a zero in the current matrix.
* @return A vector containing the sum of the elements in each row of the matrix resulting from
* pointwise multiplication of the current matrix with the given matrix.
*/
std::vector<T>* getPointwiseProductRowSumVector(storm::storage::SquareSparseMatrix<T> const& otherMatrix) {
// Prepare result.
std::vector<T>* result = new std::vector<T>(rowCount);
// Iterate over all elements of the current matrix and either continue with the next element
// in case the given matrix does not have a non-zero element at this column position, or
// multiply the two entries and add the result to the corresponding position in the vector.
uint_fast64_t otherRow = 0;
for (uint_fast64_t row = 0; row < rowCount; ++row) {
(*result)[row] += diagonalStorage[row] * otherMatrix.diagonalStorage[row];
for (uint_fast64_t element = otherMatrix.rowIndications[row], nextElement = rowIndications[row]; element < otherMatrix.rowIndications[row + 1]; ++element) {
if (otherMatrix.columnIndications[element] < columnIndications[nextElement]) {
continue;
} else {
(*result)[row] += otherMatrix.valueStorage[element] * valueStorage[nextElement];
++nextElement;
}
}
}
return result;
}
/*!
* Returns the size of the matrix in memory measured in bytes.
* @return The size of the matrix in memory measured in bytes.

22
src/storm.cpp

@ -66,10 +66,10 @@ void setUpFileLogging() {
* Prints the header.
*/
void printHeader(const int argc, const char* argv[]) {
std::cout << "STORM" << std::endl;
std::cout << "StoRM" << std::endl;
std::cout << "====" << std::endl << std::endl;
std::cout << "Version: 1.0" << std::endl;
std::cout << "Version: 1.0 Alpha" << std::endl;
// "Compute" the command line argument string with which STORM was invoked.
std::stringstream commandStream;
for (int i = 0; i < argc; ++i) {
@ -143,20 +143,26 @@ void cleanUp() {
*/
void testChecking() {
storm::settings::Settings* s = storm::settings::instance();
storm::parser::DtmcParser dtmcParser(s->getString("trafile"), s->getString("labfile"));
storm::parser::DtmcParser dtmcParser(s->getString("trafile"), s->getString("labfile"), s->getString("staterew"), s->getString("transrew"));
std::shared_ptr<storm::models::Dtmc<double>> dtmc = dtmcParser.getDtmc();
dtmc->printModelInformationToStream(std::cout);
storm::formula::Ap<double>* trueFormula = new storm::formula::Ap<double>("true");
storm::formula::Ap<double>* observe0Greater1Formula = new storm::formula::Ap<double>("observe0Greater1");
storm::formula::Until<double>* untilFormula = new storm::formula::Until<double>(trueFormula, observe0Greater1Formula);
storm::formula::ProbabilisticNoBoundsOperator<double>* probFormula = new storm::formula::ProbabilisticNoBoundsOperator<double>(untilFormula);
storm::formula::Ap<double>* observe0Greater1Formula = new storm::formula::Ap<double>("one");
storm::formula::Eventually<double>* eventuallyFormula = new storm::formula::Eventually<double>(observe0Greater1Formula);
storm::formula::ProbabilisticNoBoundsOperator<double>* probFormula = new storm::formula::ProbabilisticNoBoundsOperator<double>(eventuallyFormula);
storm::formula::Ap<double>* done = new storm::formula::Ap<double>("done");
storm::formula::ReachabilityReward<double>* reachabilityRewardFormula = new storm::formula::ReachabilityReward<double>(done);
storm::formula::RewardNoBoundsOperator<double>* rewardFormula = new storm::formula::RewardNoBoundsOperator<double>(reachabilityRewardFormula);
storm::modelChecker::GmmxxDtmcPrctlModelChecker<double>* mc = new storm::modelChecker::GmmxxDtmcPrctlModelChecker<double>(*dtmc);
mc->check(*probFormula);
mc->check(*rewardFormula);
delete mc;
delete probFormula;
delete rewardFormula;
}
/*!
@ -169,7 +175,7 @@ int main(const int argc, const char* argv[]) {
}
printHeader(argc, argv);
testChecking();
// testChecking();
cleanUp();
return 0;

20
src/utility/CommandLine.cpp

@ -0,0 +1,20 @@
/*
* CommandLine.cpp
*
* Created on: 26.12.2012
* Author: Christian Dehnert
*/
#include <ostream>
namespace storm {
namespace utility {
void printSeparationLine(std::ostream& out) {
out << "------------------------------------------------------" << std::endl;
}
} // namespace utility
} // namespace storm

24
src/utility/CommandLine.h

@ -0,0 +1,24 @@
/*
* CommandLine.h
*
* Created on: 26.12.2012
* Author: Christian Dehnert
*/
#ifndef STORM_UTILITY_COMMANDLINE_H_
#define STORM_UTILITY_COMMANDLINE_H_
namespace storm {
namespace utility {
/*!
* Prints a separation line on the command line.
*/
void printSeparationLine(std::ostream& out);
} //namespace utility
} //namespace storm
#endif /* STORM_UTILITY_COMMANDLINE_H_ */

53
src/utility/ConstTemplates.h

@ -8,6 +8,8 @@
#ifndef STORM_UTILITY_CONSTTEMPLATES_H_
#define STORM_UTILITY_CONSTTEMPLATES_H_
#include <limits>
namespace storm {
namespace utility {
@ -110,6 +112,57 @@ inline double constGetOne() {
/*! @endcond */
/*!
* Returns a constant value of infinity that is fit to the type it is being written to.
* As (at least) gcc has problems to use the correct template by the return value
* only, the function gets a pointer as a parameter to infer the return type.
*
* @note
* The template parameter is just inferred by the return type; GCC is not able to infer this
* automatically, hence the type should always be stated explicitly (e.g. @c constGetOne<int>();)
*
* @return Value Infinity, fit to the return type
*/
template<typename _Scalar>
static inline _Scalar constGetInfinity() {
return std::numeric_limits<_Scalar>::infinity();
}
/*! @cond TEMPLATE_SPECIALIZATION
* (By default, the template specifications are not included in the documentation)
*/
/*!
* Template specification for int_fast32_t
* @return Value Infinity, fit to the type uint_fast32_t
*/
template<>
inline int_fast32_t constGetInfinity() {
throw storm::exceptions::InvalidArgumentException() << "Integer has no infinity.";
return std::numeric_limits<int_fast32_t>::max();
}
/*!
* Template specification for uint_fast64_t
* @return Value Infinity, fit to the type uint_fast64_t
*/
template<>
inline uint_fast64_t constGetInfinity() {
throw storm::exceptions::InvalidArgumentException() << "Integer has no infinity.";
return std::numeric_limits<int_fast64_t>::max();
}
/*!
* Template specification for double
* @return Value Infinity, fit to the type double
*/
template<>
inline double constGetInfinity() {
return std::numeric_limits<double>::infinity();
}
/*! @endcond */
} //namespace utility
} //namespace storm

19
src/utility/Vector.h

@ -10,12 +10,14 @@
#include "Eigen/src/Core/Matrix.h"
#include <iostream>
namespace storm {
namespace utility {
template<class T>
void setVectorValues(std::vector<T>* vector, const storm::storage::BitVector& positions, const std::vector<T> values) {
void setVectorValues(std::vector<T>* vector, const storm::storage::BitVector& positions, std::vector<T> const& values) {
uint_fast64_t oldPosition = 0;
for (auto position : positions) {
(*vector)[position] = values[oldPosition++];
@ -36,6 +38,21 @@ void setVectorValues(Eigen::Matrix<T, -1, 1, 0, -1, 1>* eigenVector, const storm
}
}
template<class T>
void selectVectorValues(std::vector<T>* vector, const storm::storage::BitVector& positions, std::vector<T> const& values) {
uint_fast64_t oldPosition = 0;
for (auto position : positions) {
(*vector)[oldPosition++] = values[position];
}
}
template<class T>
void subtractFromConstantOneVector(std::vector<T>* vector) {
for (auto it = vector->begin(); it != vector->end(); ++it) {
*it = storm::utility::constGetOne<T>() - *it;
}
}
} //namespace utility
} //namespace storm

Loading…
Cancel
Save